diff --git a/dashboard/src/components/DockerRegistryDialog.vue b/dashboard/src/components/DockerRegistryDialog.vue index 2399d7907..4c5912b92 100644 --- a/dashboard/src/components/DockerRegistryDialog.vue +++ b/dashboard/src/components/DockerRegistryDialog.vue @@ -4,9 +4,8 @@ import { useI18n } from 'vue-i18n'; const i18n = useI18n(); const t = i18n.t; -import { ref, useTemplateRef, computed } from 'vue'; -import { Dialog, TextInput, FormGroup, SingleSelect } from '@cloudron/pankow'; -import { isValidDomainOrURL } from '@cloudron/pankow/utils'; +import { ref, useTemplateRef } from 'vue'; +import { Dialog, TextInput, FormGroup, SingleSelect, MaskedInput } from '@cloudron/pankow'; import DockerRegistriesModel from '../models/DockerRegistriesModel.js'; const dockerRegistriesModel = DockerRegistriesModel.create(); @@ -36,17 +35,15 @@ const username = ref(''); const email = ref(''); const password = ref(''); -const isValid = computed(() => { - if (!provider.value) return false; - if (!serverAddress.value) return false; - if (!username.value) return false; - if (!password.value) return false; - if (!isValidDomainOrURL(serverAddress.value)) return false; - - return true; -}); +const form = useTemplateRef('form'); +const isFormValid = ref(false); +function checkValidity() { + isFormValid.value = form.value.checkValidity(); +} async function onSubmit() { + if (!form.value.reportValidity()) return; + busy.value = true; formError.value = {}; @@ -77,6 +74,8 @@ defineExpose({ password.value = r ? r.password : ''; dialog.value.open(); + + setTimeout(checkValidity, 100); // update state of the confirm button } }); @@ -87,20 +86,20 @@ defineExpose({ :title="$t('dockerRegistries.dialog.title')" :confirm-label="$t('main.dialog.save')" :confirm-busy="busy" - :confirm-active="!busy && isValid" + :confirm-active="!busy && isFormValid" :reject-label="$t('main.dialog.cancel')" reject-style="secondary" @confirm="onSubmit()" > -
+
- +
{{ formError.generic }}
- + @@ -120,7 +119,7 @@ defineExpose({ - +
diff --git a/dashboard/src/components/DomainDialog.vue b/dashboard/src/components/DomainDialog.vue index 5c4d00c62..765f6d871 100644 --- a/dashboard/src/components/DomainDialog.vue +++ b/dashboard/src/components/DomainDialog.vue @@ -23,12 +23,12 @@ const customNameservers = ref(false); const dnsConfig = ref(DomainsModel.createEmptyConfig()); +const form = useTemplateRef('form'); const isFormValid = ref(false); function checkValidity() { isFormValid.value = form.value.checkValidity(); } -const form = useTemplateRef('form'); async function onSubmit() { if (!form.value.reportValidity()) return; @@ -84,8 +84,7 @@ defineExpose({ dialog.value.open(); - // ensure we trigger this once - setTimeout(checkValidity, 100); + setTimeout(checkValidity, 100); // update state of the confirm button } }); diff --git a/dashboard/src/models/DockerRegistriesModel.js b/dashboard/src/models/DockerRegistriesModel.js index dbc2ee627..a5f0eef2f 100644 --- a/dashboard/src/models/DockerRegistriesModel.js +++ b/dashboard/src/models/DockerRegistriesModel.js @@ -17,7 +17,7 @@ function create() { if (error || result.status !== 200) return [error || result]; return [null, result.body.registries]; }, - async add(provider, serverAddress, username = '', email = '', password = '') { + async add(provider, serverAddress, username, email, password) { let error, result; try { result = await fetcher.post(`${API_ORIGIN}/api/v1/docker/registries`, { provider, serverAddress, username, email, password }, { access_token: accessToken }); @@ -39,7 +39,7 @@ function create() { if (error || result.status !== 200) return [error || result]; return [null, result.body]; }, - async update(id, provider, serverAddress, username = '', email = '', password = '') { + async update(id, provider, serverAddress, username, email, password) { let error, result; try { result = await fetcher.post(`${API_ORIGIN}/api/v1/docker/registries/${id}`, { provider, serverAddress, username, email, password }, { access_token: accessToken }); diff --git a/src/dockerregistries.js b/src/dockerregistries.js index 201e17e93..98d6e4e37 100644 --- a/src/dockerregistries.js +++ b/src/dockerregistries.js @@ -1,15 +1,5 @@ 'use strict'; -exports = module.exports = { - removePrivateFields, - - list, - add, - get, - del, - update, -}; - const assert = require('node:assert'), BoxError = require('./boxerror.js'), constants = require('./constants.js'), @@ -26,11 +16,14 @@ const REGISTRY_FIELDS = [ 'id', 'provider', 'serverAddress', 'username', 'email' function removePrivateFields(registryConfig) { assert.strictEqual(typeof registryConfig, 'object'); - if (registryConfig.password) registryConfig.password = constants.SECRET_PLACEHOLDER; - + delete registryConfig.password; return registryConfig; } +function injectPrivateFields(newConfig, currentConfig) { + if (!Object.hasOwn(newConfig, 'password')) newConfig.password = currentConfig.password; +} + async function get(id) { assert.strictEqual(typeof id, 'string'); @@ -65,10 +58,6 @@ async function testRegistryConfig(config) { if (error) throw new BoxError(BoxError.BAD_FIELD, `Invalid serverAddress: ${error.message}`); } -function injectPrivateFields(newConfig, currentConfig) { - if (newConfig.password === constants.SECRET_PLACEHOLDER) newConfig.password = currentConfig.password; -} - async function add(registry, auditSource) { assert.strictEqual(typeof registry, 'object'); assert(auditSource && typeof auditSource === 'object'); @@ -121,3 +110,13 @@ async function del(registry, auditSource) { await eventlog.add(eventlog.ACTION_REGISTRY_DEL, auditSource, { registry: removePrivateFields(registry) }); } + +exports = module.exports = { + removePrivateFields, + + list, + add, + get, + del, + update, +};