diff --git a/dashboard/public/translation/en.json b/dashboard/public/translation/en.json index 3b20e92fb..d698e8d2b 100644 --- a/dashboard/public/translation/en.json +++ b/dashboard/public/translation/en.json @@ -680,7 +680,7 @@ } }, "branding": { - "title": "Branding", + "title": "Appearance", "cloudronName": "Cloudron Name", "logo": "Logo", "footer": { @@ -888,7 +888,7 @@ "refresh": "Refresh" }, "settings": { - "title": "Settings", + "title": "System", "appstoreAccount": { "title": "Cloudron.io Account", "description": "A Cloudron.io account is used to access the App Store and manage your subscription.", @@ -1000,7 +1000,7 @@ } }, "system": { - "title": "System Info", + "title": "Metrics", "diskUsage": { "title": "Disk Usage", "mountedAt": "{{ filesystem }} mounted at {{ mountpoint }}", diff --git a/dashboard/src/Index.vue b/dashboard/src/Index.vue index 0b8405630..dd38e6b7f 100644 --- a/dashboard/src/Index.vue +++ b/dashboard/src/Index.vue @@ -15,7 +15,7 @@ import AppsView from './views/AppsView.vue'; import AppConfigureView from './views/AppConfigureView.vue'; import AppstoreView from './views/AppstoreView.vue'; import BackupsView from './views/BackupsView.vue'; -import BrandingView from './views/BrandingView.vue'; +import AppearanceView from './views/AppearanceView.vue'; import DomainsView from './views/DomainsView.vue'; import EmailDomainView from './views/EmailDomainView.vue'; import EmailMailboxesView from './views/EmailMailboxesView.vue'; @@ -27,9 +27,9 @@ import EventlogView from './views/EventlogView.vue'; import NetworkView from './views/NetworkView.vue'; import ProfileView from './views/ProfileView.vue'; import ServicesView from './views/ServicesView.vue'; -import SettingsView from './views/SettingsView.vue'; import SupportView from './views/SupportView.vue'; import SystemView from './views/SystemView.vue'; +import MetricsView from './views/MetricsView.vue'; import UserDirectorySettingsView from './views/UserDirectorySettingsView.vue'; import UserDirectoryLdapProviderView from './views/UserDirectoryLdapProviderView.vue'; import UserDirectoryOpenIdProviderView from './views/UserDirectoryOpenIdProviderView.vue'; @@ -37,11 +37,11 @@ import UsersView from './views/UsersView.vue'; import VolumesView from './views/VolumesView.vue'; const VIEWS = { - APPS: 'apps', APP: 'app', + APPEARANCE: 'appearance', + APPS: 'apps', APPSTORE: 'appstore', BACKUPS: 'backups', - BRANDING: 'branding', DOMAINS: 'domains', EMAIL_DOMAIN: 'email-domain', EMAIL_MAILBOXES: 'email-mailboxes', @@ -50,10 +50,10 @@ const VIEWS = { EMAIL_EVENTLOG: 'email-eventlog', EMAIL_STATUS: 'email-status', EVENTLOG: 'eventlog', + METRICS: 'metrics', NETWORK: 'network', PROFILE: 'profile', SERVICES: 'services', - SETTINGS: 'settings', SUPPORT: 'support', SYSTEM: 'system', USER_DIRECTORY_SETTINGS: 'user-directory-settings', @@ -137,8 +137,8 @@ function onHashChange() { view.value = VIEWS.APP; } else if (v === VIEWS.BACKUPS && profile.value.isAtLeastAdmin) { view.value = VIEWS.BACKUPS; - } else if (v === VIEWS.BRANDING && profile.value.isAtLeastAdmin) { - view.value = VIEWS.BRANDING; + } else if (v === VIEWS.APPEARANCE && profile.value.isAtLeastAdmin) { + view.value = VIEWS.APPEARANCE; } else if (v === VIEWS.DOMAINS && profile.value.isAtLeastAdmin) { view.value = VIEWS.DOMAINS; } else if (v === VIEWS.EMAIL_DOMAIN && profile.value.isAtLeastMailManager) { @@ -155,14 +155,14 @@ function onHashChange() { view.value = VIEWS.EMAIL_STATUS; } else if (v === VIEWS.EVENTLOG && profile.value.isAtLeastAdmin) { view.value = VIEWS.EVENTLOG; + } else if (v === VIEWS.METRICS && profile.value.isAtLeastAdmin) { + view.value = VIEWS.METRICS; } else if (v === VIEWS.NETWORK && profile.value.isAtLeastAdmin) { view.value = VIEWS.NETWORK; } else if (v.indexOf(VIEWS.PROFILE) === 0) { view.value = VIEWS.PROFILE; } else if (v === VIEWS.SERVICES && profile.value.isAtLeastAdmin) { view.value = VIEWS.SERVICES; - } else if (v === VIEWS.SETTINGS && profile.value.isAtLeastAdmin) { - view.value = VIEWS.SETTINGS; } else if (v === VIEWS.SUPPORT && profile.value.isAtLeastOwner) { view.value = VIEWS.SUPPORT; } else if (v === VIEWS.SYSTEM && profile.value.isAtLeastAdmin) { @@ -256,7 +256,7 @@ onMounted(async () => { {{ $t('appstore.title') }} {{ $t('main.navbar.users') }} {{ $t('backups.title') }} - {{ $t('branding.title') }} + {{ $t('branding.title') }} {{ $t('domains.title') }} @@ -272,7 +272,7 @@ onMounted(async () => { {{ $t('eventlog.title') }} {{ $t('network.title') }} {{ $t('services.title') }} - {{ $t('settings.title') }} + {{ $t('settings.title') }} {{ $t('volumes.title') }} - {{ $t('system.title') }} + {{ $t('system.title') }} @@ -294,7 +294,7 @@ onMounted(async () => { - + @@ -303,10 +303,10 @@ onMounted(async () => { + - diff --git a/dashboard/src/views/BrandingView.vue b/dashboard/src/views/AppearanceView.vue similarity index 100% rename from dashboard/src/views/BrandingView.vue rename to dashboard/src/views/AppearanceView.vue diff --git a/dashboard/src/views/MetricsView.vue b/dashboard/src/views/MetricsView.vue new file mode 100644 index 000000000..4791575ec --- /dev/null +++ b/dashboard/src/views/MetricsView.vue @@ -0,0 +1,116 @@ + + + diff --git a/dashboard/src/views/SettingsView.vue b/dashboard/src/views/SettingsView.vue deleted file mode 100644 index 51c30c102..000000000 --- a/dashboard/src/views/SettingsView.vue +++ /dev/null @@ -1,97 +0,0 @@ - - - diff --git a/dashboard/src/views/SystemView.vue b/dashboard/src/views/SystemView.vue index 4791575ec..51c30c102 100644 --- a/dashboard/src/views/SystemView.vue +++ b/dashboard/src/views/SystemView.vue @@ -4,113 +4,94 @@ import { useI18n } from 'vue-i18n'; const i18n = useI18n(); const t = i18n.t; -import { ref, useTemplateRef, onMounted } from 'vue'; -import { Button, InputDialog } from 'pankow'; +import { ref, onMounted } from 'vue'; +import { SingleSelect } from 'pankow'; import moment from 'moment-timezone'; -import { prettyDecimalSize, sleep } from 'pankow/utils'; +import SettingsItem from '../components/SettingsItem.vue'; import Section from '../components/Section.vue'; -import SystemMetrics from '../components/SystemMetrics.vue'; -import DiskUsage from '../components/DiskUsage.vue'; -import SystemModel from '../models/SystemModel.js'; -import DashboardModel from '../models/DashboardModel.js'; +import CloudronAccount from '../components/CloudronAccount.vue'; +import SystemUpdate from '../components/SystemUpdate.vue'; +import PrivateRegistry from '../components/PrivateRegistry.vue'; +import CloudronModel from '../models/CloudronModel.js'; -const systemModel = SystemModel.create(); -const dashboardModel = DashboardModel.create(); +const cloudronModel = CloudronModel.create(); -const config = ref({}); -const info = ref({}); -const memory = ref({}); -const cpus = ref({}); -const uptime = ref(''); -const activeSince = ref(''); +// Timezone +const allTimezones = moment.tz.names().map(t => { return { id: t }; }); +const timeZone = ref(''); +const currentTimeZone = ref(''); -const inputDialog = useTemplateRef('inputDialog'); -async function onReboot() { - const confirmed = await inputDialog.value.confirm({ - title: t('main.rebootDialog.title'), - message: t('main.rebootDialog.description'), - confirmLabel: t('main.rebootDialog.rebootAction'), - confirmStyle: 'danger', - rejectLabel: t('main.dialog.cancel'), - }); +async function onTimeZoneChange(value) { + const [error] = await cloudronModel.setTimeZone(value); + if (error) return console.error(error); - if (!confirmed) return; + currentTimeZone.value = value; +} - await systemModel.reboot(); +// Language +const allLanguages = ref([]); +const language = ref(''); +const currentLanguage = ref(''); - // now poll until the backend does not respond anymore to trigger the unreachable overlay - while (true) { - const [error] = await dashboardModel.config(); - if (error) break; - await sleep(1000); - } +async function onLanguageChange(value) { + const [error] = await cloudronModel.setLanguage(value); + if (error) return console.error(error); + + currentLanguage.value = value; } onMounted(async () => { - let [error, result] = await systemModel.memory(); + let [error, result] = await cloudronModel.getTimeZone(); if (error) return console.error(error); - memory.value = result; - [error, result] = await systemModel.cpus(); + timeZone.value = result; + currentTimeZone.value = result; + + [error, result] = await cloudronModel.languages(); if (error) return console.error(error); - cpus.value = result; - [error, result] = await systemModel.info(); + allLanguages.value = result.map(l => { + return { + id: l, + display: t(`lang.${l}`) + }; + }); + + [error, result] = await cloudronModel.getLanguage(); if (error) return console.error(error); - info.value = result; - uptime.value = moment.duration(info.value.uptimeSecs, 'seconds').locale(navigator.language).humanize(); - activeSince.value = info.value.activationTime ? moment(info.value.activationTime).fromNow() : 'unknown'; - - [error, result] = await dashboardModel.config(); - if (error) return console.error(error); - config.value = result; + language.value = result; + currentLanguage.value = result; });