diff --git a/dashboard/public/translation/de.json b/dashboard/public/translation/de.json index d69f283aa..02ba650f4 100644 --- a/dashboard/public/translation/de.json +++ b/dashboard/public/translation/de.json @@ -906,7 +906,7 @@ "memoryLimit": "Speicherlimit", "advancedSettings": "Erweiterte Einstellungen…", "encryptionDescription": "Vorsicht: Passphrase an einem sicheren Ort aufbewahren. Cloudron speichert dieses Passwort nicht. Backups können ohne die Passphrase nicht entschlüsselt werden", - "encryptionPassword": "Verschlüsselungspasswort (optional)", + "encryptionPassword": "Verschlüsselungspasswort", "s3LikeNote": "Bitte alle object expiration lifecycle Regeln entfernen, da dadurch rsync-Backups beschädigt werden.", "formatChangeNote": "Frühere Backups, die das alte Speicherformat verwenden, müssen manuell entfernt werden.", "format": "Speicherformat", diff --git a/dashboard/public/translation/en.json b/dashboard/public/translation/en.json index b649aa12f..75bcab57e 100644 --- a/dashboard/public/translation/en.json +++ b/dashboard/public/translation/en.json @@ -613,7 +613,7 @@ "format": "Storage Format", "formatChangeNote": "Previous backups using the old storage format have to be removed manually.", "s3LikeNote": "Please remove any object expiration lifecycle rules since it will corrupt rsync backups.", - "encryptionPassword": "Encryption Password (optional)", + "encryptionPassword": "Encryption Password", "encryptionDescription": "Save this passphrase in a safe place. Cloudron does not store this password. Backups cannot be decrypted without the passphrase", "advancedSettings": "Advanced settings…", "memoryLimit": "Memory Limit", diff --git a/dashboard/public/translation/fr.json b/dashboard/public/translation/fr.json index bc647a75a..5d668500f 100644 --- a/dashboard/public/translation/fr.json +++ b/dashboard/public/translation/fr.json @@ -461,7 +461,7 @@ }, "configureBackupStorage": { "memoryLimit": "Limite de la mémoire allouée", - "encryptionPassword": "Clé de chiffrement (optionnel)", + "encryptionPassword": "Clé de chiffrement", "copyConcurrency": "Simultanéité des copies", "encryptionPasswordRepeat": "Répéter le mot de passe", "hardlinksLabel": "Utiliser des liens durs", diff --git a/dashboard/public/translation/it.json b/dashboard/public/translation/it.json index db942c500..579f348f2 100644 --- a/dashboard/public/translation/it.json +++ b/dashboard/public/translation/it.json @@ -660,7 +660,7 @@ "memoryLimit": "Limite di memoria", "advancedSettings": "Impostazioni avanzate…", "encryptionDescription": "Salva questa passphrase in un luogo sicuro. Cloudron non memorizza questa password. I backup non possono essere decrittografati senza la passphrase", - "encryptionPassword": "Password di crittografia (opzionale)", + "encryptionPassword": "Password di crittografia", "s3LikeNote": "Rimuovere qualsiasi regola del ciclo di vita di scadenza degli oggetti poiché danneggerà i backup rsync.", "formatChangeNote": "I backup precedenti che utilizzano il vecchio formato di archiviazione devono essere rimossi manualmente.", "format": "Formato Archiviazione", diff --git a/dashboard/public/translation/nl.json b/dashboard/public/translation/nl.json index 98280fc4b..c6d406b4b 100644 --- a/dashboard/public/translation/nl.json +++ b/dashboard/public/translation/nl.json @@ -606,7 +606,7 @@ "gcsServiceKey": "Serviceaccountsleutel", "format": "Opslagformaat", "s3LikeNote": "Verwijder alle 'object expiration lifecycle'-regels omdat anders rsync backups beschadigt worden.", - "encryptionPassword": "Versleutel wachtwoord (optioneel)", + "encryptionPassword": "Versleutel wachtwoord", "advancedSettings": "Geavanceerde instellingen…", "memoryLimit": "Geheugen limiet", "uploadPartSize": "Upload onderdeelgrootte", @@ -1133,7 +1133,7 @@ "taskError": { "title": "Taak fout", "retryAction": "Probeer taak {{ task }} opnieuw", - "description": "Indien een configuratie, update, herstel of backup resulteert in een fout, probeer de taak dan opnieuw." + "description": "Indien een installatie, configuratie, update, herstel of backup resulteert in een fout, probeer de taak dan opnieuw." }, "appIsBusyTooltip": "App is bezet" }, diff --git a/dashboard/public/translation/pt.json b/dashboard/public/translation/pt.json index 7d5bba497..7274e46dc 100644 --- a/dashboard/public/translation/pt.json +++ b/dashboard/public/translation/pt.json @@ -2,8 +2,8 @@ "apps": { "title": "As Minhas Aplicações", "noApps": { - "description": "Que tal instalar algumas? Veja na Loja de Aplicações", - "title": "Sem aplicações instaladas!" + "description": "E que tal instalar algumas? Veja na Loja de Aplicações", + "title": "Ainda sem aplicações instaladas!" }, "groupsFilterHeader": "Todos os Grupos", "addApplinkAction": "Adicionar Hiperligação da Aplicação", @@ -127,10 +127,10 @@ "federated": "Federados" }, "installDialog": { - "lastUpdated": "Última atualização a {{ date }}", + "lastUpdated": "Última atualização em {{ date }}", "locationPlaceholder": "Deixe em branco para utilizar o domínio de raiz", "userManagementNone": "Esta aplicação tem a sua própria gestão de utilizadores. Esta definição determina se a aplicação está ou não visível no painel do utilizador.", - "memoryRequirement": "Requere pelo menos {{ size }} de memória", + "memoryRequirement": "Requer pelo menos {{ size }} de memória", "location": "Localização", "manualWarning": "Configure manualmente os registos A (IPv4) e AAA (IPv6) para {{ location }} apontando para este servidor", "userManagement": "Gestão de utilizadores", @@ -249,7 +249,8 @@ "description": "Novo código de API:", "generateToken": "Gerar Código de API", "access": "Acesso de API", - "copyNow": "Por favor, copie o código da API agora. Este não será mostrado novamente por motivos de segurança." + "copyNow": "Por favor, copie o código da API agora. Este não será mostrado novamente por motivos de segurança.", + "allowedIpRanges": "Intervalo(s) de IP Permitido(s)" }, "passwordResetNotification": { "title": "Redefinição da palavra-passe bem-sucedida", @@ -425,7 +426,8 @@ "bindPassword": "Vincular Palavra-passe (opcional)", "disableWarning": "A fonte de autenticação de todos os utilizadores existentes será reiniciada para se autenticar na base de dados da palavra-passe atual.", "baseDn": "Base DN", - "bindUsername": "Vincular Base DN/Nome de utilizador (opcional)" + "bindUsername": "Vincular Base DN/Nome de utilizador (opcional)", + "groupFilter": "Filtro de Grupo" }, "deleteUserDialog": { "title": "Eliminar utilizador {{ username }}", @@ -686,7 +688,12 @@ "user": "Utilizador", "privateKey": "Código Privado", "diskPath": "Caminho do Disco", - "downloadConcurrencyDescription": "Número de ficheiros para transferir em paralelo quando restaurar" + "downloadConcurrencyDescription": "Número de ficheiros para transferir em paralelo quando restaurar", + "downloadConcurrency": "Transferir Moeda", + "uploadConcurrency": "Enviar Moeda", + "uploadConcurrencyDescription": "Número de ficheiros para enviar em paralelo quando realizar a cópia de segurança", + "copyConcurrency": "Copiar Moeda", + "copyConcurrencyDescription": "Número de cópias de ficheiros em paralelo quando realizar a cópia de segurança." }, "schedule": { "schedule": "Agendar", @@ -705,7 +712,8 @@ "title": "Restaurar do Arquivo" }, "archives": { - "info": "Informação" + "info": "Informação", + "title": "Arquivo de Aplicações" }, "deleteArchive": { "deleteAction": "Eliminar" @@ -753,6 +761,9 @@ "date": "Data", "version": "Versão", "format": "Formato" + }, + "archive": { + "description": "Os arquivos eliminados são limpos de acordo com a política da cópia de segurança." } }, "passwordReset": { @@ -1083,8 +1094,62 @@ "backups": { "backups": { "downloadConfigTooltip": "Transferir Configuração da Cópia de Segurança", - "downloadBackupTooltip": "Transferir Cópia de Segurança" + "downloadBackupTooltip": "Transferir Cópia de Segurança", + "restoreTooltip": "Restaurar para esta Cópia de Segurança", + "cloneTooltip": "Clonar desta Cópia de Segurança", + "createBackupAction": "Criar Cópia de Segurança", + "importAction": "Importar Cópia de Segurança", + "title": "Cópias de Segurança" + }, + "auto": { + "enabled": "Atualmente, a 'Cópias de Segurança Automáticas' estão ativadas.", + "disabled": "Atualmente, as 'Cópias de Segurança Automáticas' estão desativadas.", + "disableAction": "Desativar Cópias de Segurança Automáticas", + "enableAction": "Ativar Cópias de Segurança Automáticas" + }, + "import": { + "title": "Importar da Cópia de Segurança Externa" } + }, + "repair": { + "taskError": { + "description": "Se uma instalação, configuração, atualização, restauração ou cópia de segurança resultou num erro, pode tentar novamente a tarefa.", + "retryAction": "Repetir tarefa {{ task }}" + }, + "appIsBusyTooltip": "Aplicação ocupada", + "recovery": { + "title": "Recuperação de Crache" + } + }, + "updates": { + "auto": { + "disableAction": "Desative as Atualizações Automáticas", + "description": "Verifique o Cloudron periodicamente para atualizações na App Store .", + "disabled": "Atualmente, as 'Atualizações Automáticas' estão desativadas.", + "enableAction": "Ative as Atualizações Automáticas", + "title": "Atualizações Automáticas", + "enabled": "Atualmente, as 'Atualizações Automáticas' estão ativadas." + }, + "info": { + "customAppUpdateInfo": "A atualização automática não está disponível para as aplicações personalizadas.", + "installedAt": "Instalado às", + "lastUpdated": "Última Atualização", + "packageVersion": "Versão do Pacote", + "checkForUpdatesAction": "Procurar por Atualizações", + "updateAvailableAction": "Disponível Atualização", + "repository": "Repositório de Pacotes", + "title": "Informação da Aplicação", + "description": "Título e Versão da Aplicação" + }, + "noUpdates": "Sem atualizações disponíveis" + }, + "uninstall": { + "startStop": { + "title": "Iniciar/Parar" + } + }, + "security": { + "hstsPreload": "Ativar pré-carregamento de HSTS para este site e todos os subdomínios" } }, "logs": { diff --git a/dashboard/public/translation/ru.json b/dashboard/public/translation/ru.json index 25c4ef357..88a818a53 100644 --- a/dashboard/public/translation/ru.json +++ b/dashboard/public/translation/ru.json @@ -781,7 +781,7 @@ }, "taskError": { "title": "Ошибка задачи", - "description": "Если настройка, обновление, восстановление или создание резервной копии вызвало ошибку, вы можете перезапустить задачу.", + "description": "Если установка, обновление, восстановление или создание резервной копии вызвало ошибку, вы можете перезапустить задачу.", "retryAction": "Перезапустить задачу {{ task }}" }, "appIsBusyTooltip": "Приложение занято" diff --git a/dashboard/src/components/BackupProviderForm.vue b/dashboard/src/components/BackupProviderForm.vue index da6ea1a4f..e7c1f3b90 100644 --- a/dashboard/src/components/BackupProviderForm.vue +++ b/dashboard/src/components/BackupProviderForm.vue @@ -10,8 +10,6 @@ import { mountlike, s3like } from '../utils.js'; const provider = defineModel('provider'); const providerConfig = defineModel('providerConfig'); const format = defineModel('format'); -const encryptionPassword = defineModel('encryptionPassword'); -const encryptedFilenames = defineModel('encryptedFilenames'); const props = defineProps({ formError: {}, @@ -197,7 +195,7 @@ onMounted(async () => { - + @@ -282,12 +280,5 @@ onMounted(async () => {
{{ $t('backups.configureBackupStorage.s3LikeNote') }}
- - - - - -
{{ $t('backups.configureBackupStorage.encryptionDescription') }}
- diff --git a/dashboard/src/components/BackupTargetDialog.vue b/dashboard/src/components/BackupTargetDialog.vue index 22d50598d..1fc092711 100644 --- a/dashboard/src/components/BackupTargetDialog.vue +++ b/dashboard/src/components/BackupTargetDialog.vue @@ -1,7 +1,7 @@ diff --git a/dashboard/src/models/BackupTargetsModel.js b/dashboard/src/models/BackupTargetsModel.js index daa0722aa..daf3d9072 100644 --- a/dashboard/src/models/BackupTargetsModel.js +++ b/dashboard/src/models/BackupTargetsModel.js @@ -20,12 +20,10 @@ function create() { if (error || result.status !== 200) return [error || result]; return [null, result.body.backupTargets]; }, - async add(name, format, provider, config, schedule, retention, limits = null, encryptionPassword = null, encryptedFilenames = null) { + async add(name, format, provider, config, schedule, retention, limits = null) { const data = { name, format, provider, config, schedule, retention }; if (limits !== null) data.limits = limits; - if (encryptionPassword !== null) data.encryptionPassword = encryptionPassword; - if (encryptedFilenames !== null) data.encryptedFilenames = encryptedFilenames; let error, result; try { @@ -126,6 +124,17 @@ function create() { if (error || result.status !== 200) return [error || result]; return [null]; }, + async setEncryption(id, encryptionPassword, encryptedFilenames, encryptionPasswordHint = '') { + let error, result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/backup_targets/${id}/configure/encryption`, { encryptionPassword, encryptedFilenames, encryptionPasswordHint }, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 200) return [error || result]; + return [null]; + }, async setConfig(id, config) { let error, result; try { diff --git a/dashboard/src/views/BackupTargetsView.vue b/dashboard/src/views/BackupTargetsView.vue index e95d4d43f..8100c9e8e 100644 --- a/dashboard/src/views/BackupTargetsView.vue +++ b/dashboard/src/views/BackupTargetsView.vue @@ -23,9 +23,6 @@ const targets = ref([]); const busy = ref(false); const columns = { - primary: { - width: '30px', - }, status: { width: '30px', }, @@ -194,11 +191,6 @@ onMounted(async () => {

TODO Explain what backup targets are and what primary/secondary is

- - - diff --git a/src/backuptargets.js b/src/backuptargets.js index 1b06efee3..7ab33db78 100644 --- a/src/backuptargets.js +++ b/src/backuptargets.js @@ -284,8 +284,8 @@ async function setEncryption(backupTarget, data, auditSource) { } const queries = [ - { query: 'DELETE FROM FROM backups WHERE targetId=?', args: [ backupTarget.id ] }, - { query: 'UPDATE backupTargets SET encryptionJson=?', args: [ encryption ? JSON.stringify(encryption) : null ] }, + { query: 'DELETE FROM backups WHERE targetId=?', args: [ backupTarget.id ] }, + { query: 'UPDATE backupTargets SET encryptionJson=? WHERE id=?', args: [ encryption ? JSON.stringify(encryption) : null, backupTarget.id ] }, ]; const [error, result] = await safe(database.transaction(queries));