Fixup all toplevel views to only have one child node and test with basic animation

This commit is contained in:
Johannes Zellner
2025-03-26 18:36:04 +01:00
parent ae68cc95bb
commit 830db36928
10 changed files with 254 additions and 236 deletions
+42 -42
View File
@@ -240,49 +240,49 @@ onMounted(async () => {
</script>
<template>
<InputDialog ref="inputDialog"/>
<Dialog ref="restoreDialog"
:title="$t('backups.restoreArchiveDialog.title')"
reject-style="secondary"
:reject-label="restoreBusy ? '' : $t('main.dialog.cancel')"
:confirm-label="$t(restoreNeedsOverwrite ? 'backups.restoreArchiveDialog.restoreActionOverwrite' : 'backups.restoreArchiveDialog.restoreAction')"
:confirm-busy="restoreBusy"
:confirm-active="!restoreBusy"
@confirm="onRestoreSubmit()"
>
<p v-html="$t('backups.restoreArchiveDialog.description', { appId: restoreManifest.id, fqdn: restoreFqdn, creationTime: prettyLongDate(restoreArchive.creationTime) })"></p>
<div class="text-danger" v-show="restoreError.generic">{{ restoreError.generic }}</div>
<div class="text-danger" v-show="restoreError.dnsInUse">{{ restoreError.dnsInUse }}</div>
<!-- <div ng-show="archiveRestore.error.location.fqdn === archiveRestore.subdomain + '.' + archiveRestore.domain.domain"><small>{{ archiveRestore.error.location.message }}</small></div> -->
<form @submit.prevent="onRestoreSubmit()" autocomplete="off">
<fieldset>
<FormGroup>
<label for="locationInput">{{ $t('app.cloneDialog.location') }}</label>
<InputGroup>
<TextInput id="locationInput" ref="locationInput" v-model="restoreLocation" style="flex-grow: 1;" />
<Dropdown v-model="restoreDomain" :options="domains" option-label="domain" option-key="domain" />
</InputGroup>
</FormGroup>
<FormGroup v-for="(domain, key) in restoreSecondaryDomains" :key="key">
<label :for="'secondaryDomainInput-' + key">{{ domain.title }}</label>
<small>{{ domain.description }}</small>
<InputGroup>
<TextInput :id="'secondaryDomainInput-' + key" v-model="domain.subdomain" :placeholder="$t('appstore.installDialog.locationPlaceholder')" style="flex-grow: 1;" />
<Dropdown v-model="domain.domain" :options="domains" option-label="domain" option-key="domain" />
</InputGroup>
</FormGroup>
<!-- <p class="text-small text-warning" ng-show="archiveRestore.domain.provider === 'noop' || archiveRestore.domain.provider === 'manual'" ng-bind-html="'appstore.installDialog.manualWarning' | tr:{ location: ((archiveRestore.subdomain ? archiveRestore.subdomain + '.' : '') + archiveRestore.domain.domain) }"></p> -->
<!-- <div class="has-error text-center" ng-show="archiveRestore.error.port">{{ archiveRestore.error.port }}</div> -->
<PortBindings v-model:tcp-ports="restoreTcpPorts" v-model:udp-ports="restoreUdpPorts" :error="restoreError"/>
</fieldset>
</form>
</Dialog>
<Section :title="$t('backups.archives.title')">
<InputDialog ref="inputDialog"/>
<Dialog ref="restoreDialog"
:title="$t('backups.restoreArchiveDialog.title')"
reject-style="secondary"
:reject-label="restoreBusy ? '' : $t('main.dialog.cancel')"
:confirm-label="$t(restoreNeedsOverwrite ? 'backups.restoreArchiveDialog.restoreActionOverwrite' : 'backups.restoreArchiveDialog.restoreAction')"
:confirm-busy="restoreBusy"
:confirm-active="!restoreBusy"
@confirm="onRestoreSubmit()"
>
<p v-html="$t('backups.restoreArchiveDialog.description', { appId: restoreManifest.id, fqdn: restoreFqdn, creationTime: prettyLongDate(restoreArchive.creationTime) })"></p>
<div class="text-danger" v-show="restoreError.generic">{{ restoreError.generic }}</div>
<div class="text-danger" v-show="restoreError.dnsInUse">{{ restoreError.dnsInUse }}</div>
<!-- <div ng-show="archiveRestore.error.location.fqdn === archiveRestore.subdomain + '.' + archiveRestore.domain.domain"><small>{{ archiveRestore.error.location.message }}</small></div> -->
<form @submit.prevent="onRestoreSubmit()" autocomplete="off">
<fieldset>
<FormGroup>
<label for="locationInput">{{ $t('app.cloneDialog.location') }}</label>
<InputGroup>
<TextInput id="locationInput" ref="locationInput" v-model="restoreLocation" style="flex-grow: 1;" />
<Dropdown v-model="restoreDomain" :options="domains" option-label="domain" option-key="domain" />
</InputGroup>
</FormGroup>
<FormGroup v-for="(domain, key) in restoreSecondaryDomains" :key="key">
<label :for="'secondaryDomainInput-' + key">{{ domain.title }}</label>
<small>{{ domain.description }}</small>
<InputGroup>
<TextInput :id="'secondaryDomainInput-' + key" v-model="domain.subdomain" :placeholder="$t('appstore.installDialog.locationPlaceholder')" style="flex-grow: 1;" />
<Dropdown v-model="domain.domain" :options="domains" option-label="domain" option-key="domain" />
</InputGroup>
</FormGroup>
<!-- <p class="text-small text-warning" ng-show="archiveRestore.domain.provider === 'noop' || archiveRestore.domain.provider === 'manual'" ng-bind-html="'appstore.installDialog.manualWarning' | tr:{ location: ((archiveRestore.subdomain ? archiveRestore.subdomain + '.' : '') + archiveRestore.domain.domain) }"></p> -->
<!-- <div class="has-error text-center" ng-show="archiveRestore.error.port">{{ archiveRestore.error.port }}</div> -->
<PortBindings v-model:tcp-ports="restoreTcpPorts" v-model:udp-ports="restoreUdpPorts" :error="restoreError"/>
</fieldset>
</form>
</Dialog>
<p v-html="$t('backups.archive.description')"></p>
<TableView :columns="columns" :model="archives" :busy="busy" @row-click="onInfo">
+62 -62
View File
@@ -25,7 +25,6 @@ const tasksModel = TasksModel.create();
const dashboardModel = DashboardModel.create();
const columns = {
preserveSecs: {}, // archived
packageVersion: {
label: t('backups.listing.version'),
sort: true,
@@ -35,6 +34,7 @@ const columns = {
label: t('main.table.date'),
sort: true
},
preserveSecs: {}, // archived
content: {
label: t('backups.listing.contents'),
sort: false,
@@ -211,68 +211,68 @@ onMounted(async () => {
</script>
<template>
<Dialog ref="infoDialog"
:title="$t('backups.backupDetails.title')"
:reject-label="$t('main.dialog.cancel')"
>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupDetails.id') }}</div>
<div class="info-value">{{ infoBackup.id }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupEdit.label') }}</div>
<div class="info-value">{{ infoBackup.label }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupEdit.remotePath') }}</div>
<div class="info-value">{{ infoBackup.remotePath }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupDetails.date') }}</div>
<div class="info-value">{{ prettyLongDate(infoBackup.creationTime) }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupDetails.version') }}</div>
<div class="info-value">{{ infoBackup.packageVersion }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupDetails.format') }}</div>
<div class="info-value">{{ infoBackup.format }}</div>
</div>
<br/>
<p class="text-muted">{{ $t('backups.backupDetails.list', { appCount: infoBackup.contents.length }) }}:</p>
<div v-for="content in infoBackup.contents" :key="content.id">
<a v-if="content.fqdn" :href="`/#/app/${content.id}/backups`">{{ content.label || content.fqdn }}</a>
<a v-else :href="`/#/eventlog?search=${content.id}`">{{ content.id }}</a>
</div>
</Dialog>
<Dialog ref="editDialog"
:title="$t('backups.backupEdit.title')"
:reject-label="editBackupBusy ? '' : $t('main.dialog.cancel')"
reject-style="secondary"
:confirm-label="$t('main.dialog.save')"
:confirm-busy="editBackupBusy"
@confirm="onEditSubmit()"
>
<p class="has-error text-center" v-show="editBackupError">{{ editBackupError }}</p>
<form @submit.prevent="onEditSubmit()" autocomplete="off">
<fieldset>
<FormGroup>
<label for="backupLabelInput">{{ $t('backups.backupEdit.label') }}</label>
<TextInput id="backupLabelInput" v-model="editBackupLabel" />
</FormGroup>
<Checkbox v-model="editBackupPersist" :label="$t('backups.backupEdit.preserved.description')" />
<!-- <sup><a popover-placement="top-right" popover-trigger="outsideClick" uib-popover="{{ 'backups.backupEdit.preserved.tooltip' | tr: { appsLength: editBackup.backup.contents.length} }}"><i class="fa fa-question-circle"></i></a></sup> -->
</fieldset>
</form>
</Dialog>
<Section :title="$t('backups.listing.title')">
<Dialog ref="infoDialog"
:title="$t('backups.backupDetails.title')"
:reject-label="$t('main.dialog.cancel')"
>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupDetails.id') }}</div>
<div class="info-value">{{ infoBackup.id }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupEdit.label') }}</div>
<div class="info-value">{{ infoBackup.label }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupEdit.remotePath') }}</div>
<div class="info-value">{{ infoBackup.remotePath }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupDetails.date') }}</div>
<div class="info-value">{{ prettyLongDate(infoBackup.creationTime) }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupDetails.version') }}</div>
<div class="info-value">{{ infoBackup.packageVersion }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupDetails.format') }}</div>
<div class="info-value">{{ infoBackup.format }}</div>
</div>
<br/>
<p class="text-muted">{{ $t('backups.backupDetails.list', { appCount: infoBackup.contents.length }) }}:</p>
<div v-for="content in infoBackup.contents" :key="content.id">
<a v-if="content.fqdn" :href="`/#/app/${content.id}/backups`">{{ content.label || content.fqdn }}</a>
<a v-else :href="`/#/eventlog?search=${content.id}`">{{ content.id }}</a>
</div>
</Dialog>
<Dialog ref="editDialog"
:title="$t('backups.backupEdit.title')"
:reject-label="editBackupBusy ? '' : $t('main.dialog.cancel')"
reject-style="secondary"
:confirm-label="$t('main.dialog.save')"
:confirm-busy="editBackupBusy"
@confirm="onEditSubmit()"
>
<p class="has-error text-center" v-show="editBackupError">{{ editBackupError }}</p>
<form @submit.prevent="onEditSubmit()" autocomplete="off">
<fieldset>
<FormGroup>
<label for="backupLabelInput">{{ $t('backups.backupEdit.label') }}</label>
<TextInput id="backupLabelInput" v-model="editBackupLabel" />
</FormGroup>
<Checkbox v-model="editBackupPersist" :label="$t('backups.backupEdit.preserved.description')" />
<!-- <sup><a popover-placement="top-right" popover-trigger="outsideClick" uib-popover="{{ 'backups.backupEdit.preserved.tooltip' | tr: { appsLength: editBackup.backup.contents.length} }}"><i class="fa fa-question-circle"></i></a></sup> -->
</fieldset>
</form>
</Dialog>
<template #header-buttons>
<Button tool icon="fas fa-align-left" v-tooltip="$t('settings.updates.showLogsAction')" :menu="taskLogsMenu" :disabled="!taskLogsMenu.length"/>
</template>
+34 -34
View File
@@ -204,41 +204,41 @@ onMounted(async () => {
</script>
<template>
<InputDialog ref="inputDialog" />
<Dialog ref="configureDialog"
:title="$t('backups.configureBackupSchedule.title')"
reject-style="secondary"
:reject-label="configureBusy ? null : $t('main.dialog.cancel')"
:confirm-label="$t('main.dialog.save')"
:confirm-busy="configureBusy"
:confirm-active="isConfigureValid"
@confirm="onSubmitConfigure()"
>
<p class="has-error text-center" v-show="configureError">{{ configureError }}</p>
<form @submit.prevent="onSubmitConfigure()" autocomplete="off">
<fieldset>
<FormGroup>
<label for="daysInput">{{ $t('backups.configureBackupSchedule.schedule') }}</label>
<p v-html="$t('backups.configureBackupSchedule.scheduleDescription')"></p>
<div style="display: flex; gap: 10px;">
<div>{{ $t('backups.configureBackupSchedule.days') }}: <MultiSelect id="daysInput" v-model="configureDays" :options="cronDays" option-key="id" option-label="name"></MultiSelect></div>
<div>{{ $t('backups.configureBackupSchedule.hours') }}: <MultiSelect v-model="configureHours" :options="cronHours" option-key="id" option-label="name"></MultiSelect></div>
</div>
</FormGroup>
<FormGroup>
<label for="retentionInput">{{ $t('backups.configureBackupSchedule.retentionPolicy') }}</label>
<select id="retentionInput" v-model="configureRetention">
<option v-for="elem in backupRetentions" :key="elem.id" :value="elem.id">{{ elem.name }}</option>
</select>
</FormGroup>
</fieldset>
</form>
</Dialog>
<Section :title="$t('backups.schedule.title')">
<InputDialog ref="inputDialog" />
<Dialog ref="configureDialog"
:title="$t('backups.configureBackupSchedule.title')"
reject-style="secondary"
:reject-label="configureBusy ? null : $t('main.dialog.cancel')"
:confirm-label="$t('main.dialog.save')"
:confirm-busy="configureBusy"
:confirm-active="isConfigureValid"
@confirm="onSubmitConfigure()"
>
<p class="has-error text-center" v-show="configureError">{{ configureError }}</p>
<form @submit.prevent="onSubmitConfigure()" autocomplete="off">
<fieldset>
<FormGroup>
<label for="daysInput">{{ $t('backups.configureBackupSchedule.schedule') }}</label>
<p v-html="$t('backups.configureBackupSchedule.scheduleDescription')"></p>
<div style="display: flex; gap: 10px;">
<div>{{ $t('backups.configureBackupSchedule.days') }}: <MultiSelect id="daysInput" v-model="configureDays" :options="cronDays" option-key="id" option-label="name"></MultiSelect></div>
<div>{{ $t('backups.configureBackupSchedule.hours') }}: <MultiSelect v-model="configureHours" :options="cronHours" option-key="id" option-label="name"></MultiSelect></div>
</div>
</FormGroup>
<FormGroup>
<label for="retentionInput">{{ $t('backups.configureBackupSchedule.retentionPolicy') }}</label>
<select id="retentionInput" v-model="configureRetention">
<option v-for="elem in backupRetentions" :key="elem.id" :value="elem.id">{{ elem.name }}</option>
</select>
</FormGroup>
</fieldset>
</form>
</Dialog>
<template #header-buttons>
<Button tool icon="fas fa-align-left" v-tooltip="$t('settings.updates.showLogsAction')" :menu="taskLogsMenu" :disabled="!taskLogsMenu.length"/>
</template>
+43 -43
View File
@@ -110,50 +110,50 @@ onMounted(async () => {
</script>
<template>
<Dialog ref="dialog"
:title="$t('settings.privateDockerRegistryDialog.title')"
:confirm-label="$t('main.dialog.save')"
:confirm-busy="configureBusy"
:confirm-active="!configureBusy && isValid"
:reject-label="$t('main.dialog.cancel')"
reject-style="secondary"
@confirm="onSubmitConfigure()"
>
<p class="has-error text-center" v-show="configureError">{{ configureError }}</p>
<form novalidate @submit.prevent="onSubmitConfigure()" autocomplete="off">
<fieldset :disabled="configureBusy">
<input style="display: none" type="submit" :disabled="!isValid"/>
<FormGroup>
<label for="providerInput">{{ $t('settings.registryConfig.provider') }} <sup><a href="https://docs.cloudron.io/settings/#private-docker-registry" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
<Dropdown id="providerInput" v-model="configureProvider" :options="providers" option-key="value" option-label="name" />
</FormGroup>
<FormGroup v-if="configureProvider !== 'noop'">
<label for="serverAddressInput">{{ $t('settings.privateDockerRegistry.server') }}</label>
<TextInput id="serverAddressInput" v-model="configureServerAddress" placeholder="docker.io" required />
</FormGroup>
<FormGroup v-if="configureProvider !== 'noop'">
<label for="usernameInput">{{ $t('settings.privateDockerRegistry.username') }}</label>
<TextInput id="usernameInput" v-model="configureUsername" required />
</FormGroup>
<FormGroup v-if="configureProvider !== 'noop'">
<label for="emailInput">{{ $t('settings.privateDockerRegistryDialog.email') }}</label>
<TextInput id="emailInput" v-model="configureEmail" />
</FormGroup>
<FormGroup v-if="configureProvider !== 'noop'">
<label for="passwordInput">{{ $t('settings.privateDockerRegistryDialog.passwordToken') }}</label>
<PasswordInput id="passwordInput" v-model="configurePassword" required />
</FormGroup>
</fieldset>
</form>
</Dialog>
<Section :title="$t('settings.privateDockerRegistry.title')">
<Dialog ref="dialog"
:title="$t('settings.privateDockerRegistryDialog.title')"
:confirm-label="$t('main.dialog.save')"
:confirm-busy="configureBusy"
:confirm-active="!configureBusy && isValid"
:reject-label="$t('main.dialog.cancel')"
reject-style="secondary"
@confirm="onSubmitConfigure()"
>
<p class="has-error text-center" v-show="configureError">{{ configureError }}</p>
<form novalidate @submit.prevent="onSubmitConfigure()" autocomplete="off">
<fieldset :disabled="configureBusy">
<input style="display: none" type="submit" :disabled="!isValid"/>
<FormGroup>
<label for="providerInput">{{ $t('settings.registryConfig.provider') }} <sup><a href="https://docs.cloudron.io/settings/#private-docker-registry" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
<Dropdown id="providerInput" v-model="configureProvider" :options="providers" option-key="value" option-label="name" />
</FormGroup>
<FormGroup v-if="configureProvider !== 'noop'">
<label for="serverAddressInput">{{ $t('settings.privateDockerRegistry.server') }}</label>
<TextInput id="serverAddressInput" v-model="configureServerAddress" placeholder="docker.io" required />
</FormGroup>
<FormGroup v-if="configureProvider !== 'noop'">
<label for="usernameInput">{{ $t('settings.privateDockerRegistry.username') }}</label>
<TextInput id="usernameInput" v-model="configureUsername" required />
</FormGroup>
<FormGroup v-if="configureProvider !== 'noop'">
<label for="emailInput">{{ $t('settings.privateDockerRegistryDialog.email') }}</label>
<TextInput id="emailInput" v-model="configureEmail" />
</FormGroup>
<FormGroup v-if="configureProvider !== 'noop'">
<label for="passwordInput">{{ $t('settings.privateDockerRegistryDialog.passwordToken') }}</label>
<PasswordInput id="passwordInput" v-model="configurePassword" required />
</FormGroup>
</fieldset>
</form>
</Dialog>
<p v-html="$t('settings.privateDockerRegistry.description', { customAppsLink: 'https://docs.cloudron.io/custom-apps/tutorial/' })"></p>
<div class="info-row">