diff --git a/dashboard/src/components/DockerRegistryDialog.vue b/dashboard/src/components/DockerRegistryDialog.vue new file mode 100644 index 000000000..398185afd --- /dev/null +++ b/dashboard/src/components/DockerRegistryDialog.vue @@ -0,0 +1,122 @@ + + + diff --git a/dashboard/src/components/PrivateRegistry.vue b/dashboard/src/components/PrivateRegistry.vue index b16a72f34..94e254579 100644 --- a/dashboard/src/components/PrivateRegistry.vue +++ b/dashboard/src/components/PrivateRegistry.vue @@ -4,103 +4,43 @@ import { useI18n } from 'vue-i18n'; const i18n = useI18n(); const t = i18n.t; -import { ref, useTemplateRef, onMounted, computed } from 'vue'; -import { Button, Dialog, FormGroup, PasswordInput, TextInput, SingleSelect } from 'pankow'; -import { isValidDomainOrURL } from 'pankow/utils'; +import { ref, onMounted, useTemplateRef, inject } from 'vue'; +import { Button, TableView } from 'pankow'; import Section from '../components/Section.vue'; -import CloudronModel from '../models/CloudronModel.js'; +import DockerRegistryDialog from '../components/DockerRegistryDialog.vue'; +import DockerRegistriesModel from '../models/DockerRegistriesModel.js'; -const cloudronModel = CloudronModel.create(); +const dockerRegistriesModel = DockerRegistriesModel.create(); -const providers = [ - { name: 'AWS', value: 'aws' }, - { name: 'Cloudron', value: 'cloudron' }, - { name: 'Digital Ocean', value: 'digitalocean' }, - { name: 'DockerHub', value: 'dockerhub' }, - { name: 'Google Cloud', value: 'google-cloud' }, - { name: 'Linode', value: 'linode' }, - { name: 'Quay', value: 'quay' }, - { name: 'Treescale', value: 'treescale' }, - { name: t('settings.registryConfig.providerOther') || 'Other', value: 'other' }, - { name: t('settings.registryConfig.providerDisabled') || 'Disabled', value: 'noop' } -]; +const registries = ref([]); -const provider = ref(''); -const serverAddress = ref(''); -const username = ref(''); -const email = ref(''); -const password = ref(''); +const columns = { + serverAddress: { + label: t('settings.privateDockerRegistry.server'), + sort: true + }, + username: { + label: t('settings.privateDockerRegistry.username'), + sort: true + }, + actions: {} +}; + +const features = inject('features'); +const subscriptionRequiredDialog = inject('subscriptionRequiredDialog'); -// configure const dialog = useTemplateRef('dialog'); -const configureBusy = ref(false); -const configureError = ref(''); -const configureProvider = ref(''); -const configureServerAddress = ref(''); -const configureUsername = ref(''); -const configureEmail = ref(''); -const configurePassword = ref(''); -const isValid = computed(() => { - if (configureProvider.value === 'noop') return true; - if (!configureServerAddress.value) return false; - if (!configureUsername.value) return false; - if (!configurePassword.value) return false; - if (!isValidDomainOrURL(configureServerAddress.value)) return false; - - return true; -}); - -function onShowConfigure() { - configureBusy.value = false; - configureError.value = ''; - configureProvider.value = provider.value; - configureServerAddress.value = serverAddress.value; - configureUsername.value = username.value; - configureEmail.value = email.value; - configurePassword.value = password.value; - - dialog.value.open(); -} - -async function onSubmitConfigure() { - if (!isValid.value) return; - - configureBusy.value = true; - configureError.value = ''; - - const data = { - provider: configureProvider.value - }; - - if (configureProvider.value !== 'noop') { - data.serverAddress = configureServerAddress.value; - data.username = configureUsername.value; - data.email = configureEmail.value; - data.password = configurePassword.value; - }; - - const [error] = await cloudronModel.setRegistryConfig(data); - if (error) { - configureError.value = error.body ? error.body.message : 'Internal error'; - configureBusy.value = false; - return console.error(error); - } - - await refresh(); - dialog.value.close(); - configureBusy.value = false; +function onEditOrAdd(registry = null) { + if (registry || features.value.privateDockerRegistry) dialog.value.open(registry); + else subscriptionRequiredDialog.value.open(); } async function refresh() { - const [error, result] = await cloudronModel.getRegistryConfig(); + const [error, result] = await dockerRegistriesModel.list(); if (error) return console.error(error); - provider.value = result.provider; - serverAddress.value = result.serverAddress; - email.value = result.email; - username.value = result.username; - password.value = result.password; + registries.value = result; } onMounted(async () => { @@ -111,60 +51,22 @@ onMounted(async () => { diff --git a/dashboard/src/models/DockerRegistriesModel.js b/dashboard/src/models/DockerRegistriesModel.js new file mode 100644 index 000000000..0c9107c5a --- /dev/null +++ b/dashboard/src/models/DockerRegistriesModel.js @@ -0,0 +1,69 @@ + +import { fetcher } from 'pankow'; +import { API_ORIGIN } from '../constants.js'; + +function create() { + const accessToken = localStorage.token; + + return { + async list() { + let error, result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/docker/registries`, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 200) return [error || result]; + return [null, result.body.registries]; + }, + 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 }); + } catch (e) { + error = e; + } + + if (error || result.status !== 201) return [error || result]; + return [null, result.body.id]; + }, + async get(id) { + let error, result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/docker/registries/${id}`, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 200) return [error || result]; + return [null, result.body]; + }, + 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 }); + } catch (e) { + error = e; + } + + if (error || result.status !== 204) return [error || result]; + return [null]; + }, + async remove(id) { + let error, result; + try { + result = await fetcher.del(`${API_ORIGIN}/api/v1/docker/registries/${id}`, {}, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 204) return [error || result]; + return [null]; + }, + }; +} + +export default { + create, +};