diff --git a/app/src/i18n/locales/en.json b/app/src/i18n/locales/en.json index 11052ad2..98cc0ec3 100644 --- a/app/src/i18n/locales/en.json +++ b/app/src/i18n/locales/en.json @@ -327,6 +327,82 @@ "rerun_diagnosis": "Rerun diagnosis", "restore": "Restore", "restart": "Restart", + "human_routes": { + "adminpw": "Change admin password", + "apps": { + "change_label": "Change label of '{prevName}' for '{nextName}'", + "change_url": "Change access url of '{name}'", + "install": "Install app '{name}'", + "set_default": "Redirect '{domain}' domain root to '{name}'", + "perform_action": "Perform action '{action}' of app '{name}'", + "uninstall": "Uninstall app '{name}'", + "update_config": "Update app '{name}' configuration" + }, + "backups": { + "create": "Create a backup", + "delete": "Delete backup '{name}'", + "restore": "Restore backup '{name}'" + }, + "diagnosis": { + "ignore": { + "error": "Ignore an error", + "warning": "Ignore a warning" + }, + "run": "Run the diagnosis", + "run_specific": "Run '{description}' diagnosis", + "unignore": { + "error": "Unignore an error", + "warning": "Unignore a warning" + } + }, + "domains": { + "add": "Add domain '{name}'", + "delete": "Delete domain '{name}'", + "install_LE": "Install certificate for '{name}'", + "manual_renew_LE": "Renew certificate for '{name}'", + "regen_selfsigned": "Renew self-signed certificate for '{name}'", + "revert_to_selfsigned": "Revert to self-signed certificate for '{name}'", + "set_default": "Set '{name}' as default domain" + }, + "firewall": { + "ports": "{action} port {port} ({protocol}, {connection})", + "upnp": "{action} UPnP" + }, + "groups": { + "create": "Create group '{name}'", + "delete": "Delete group '{name}'", + "add": "Add '{user}' to group '{name}'", + "remove": "Remove '{user}' from group '{name}'" + }, + "migrations": { + "run": "Run migrations", + "skip": "Skip migrations" + }, + "permissions": { + "add": "Allow '{name}' to access '{perm}'", + "remove": "Remove '{name}' access to '{perm}'" + }, + "postinstall": "Run the post-install", + "reboot": "Reboot the server", + "services": { + "restart": "Restart the service '{name}'", + "start": "Start the service '{name}'", + "stop": "Stop the service '{name}'" + }, + "share_logs": "Generate link for log '{name}'", + "shutdown": "Shutdown the server", + "update": "Check for updates", + "upgrade": { + "system": "Upgrade the system", + "apps": "Upgrade all apps", + "app": "Upgrade '{app}' app" + }, + "users": { + "create": "Create user '{name}'", + "delete": "Delete user '{name}'", + "update": "Update user '{name}'" + } + }, "run": "Run", "running": "Running", "save": "Save", diff --git a/app/src/store/info.js b/app/src/store/info.js index 9cf2426b..280720b7 100644 --- a/app/src/store/info.js +++ b/app/src/store/info.js @@ -108,7 +108,7 @@ export default { }, 'LOGIN' ({ dispatch }, password) { - return api.post('login', { password }, { websocket: false }).then(() => { + return api.post('login', { password }, null, { websocket: false }).then(() => { dispatch('CONNECT') }) }, diff --git a/app/src/views/PostInstall.vue b/app/src/views/PostInstall.vue index 8edcae6a..3e4d5ea4 100644 --- a/app/src/views/PostInstall.vue +++ b/app/src/views/PostInstall.vue @@ -92,7 +92,8 @@ export default { performPostInstall () { // FIXME does the api will throw an error for bad passwords ? - api.post('postinstall', { domain: this.domain, password: this.password }).then(data => { + const { domain, password } = this + api.post('postinstall', { domain, password }, 'postinstall').then(() => { // Display success message and allow the user to login this.step = 'login' }) diff --git a/app/src/views/app/AppActions.vue b/app/src/views/app/AppActions.vue index 117a1325..638e132e 100644 --- a/app/src/views/app/AppActions.vue +++ b/app/src/views/app/AppActions.vue @@ -99,7 +99,11 @@ export default { // FIXME api expects at least one argument ?! (fake one given with { dontmindthis } ) const args = objectToParams(action.form ? formatFormData(action.form) : { dontmindthis: undefined }) - api.put(`apps/${this.id}/actions/${action.id}`, { args }).then(() => { + api.put( + `apps/${this.id}/actions/${action.id}`, + { args }, + { key: 'apps.perform_action', action: action.id, name: this.id } + ).then(() => { this.$refs.view.fetchQueries() }).catch(err => { if (err.name !== 'APIBadRequestError') throw err diff --git a/app/src/views/app/AppConfigPanel.vue b/app/src/views/app/AppConfigPanel.vue index bffb00be..3d4e43be 100644 --- a/app/src/views/app/AppConfigPanel.vue +++ b/app/src/views/app/AppConfigPanel.vue @@ -102,7 +102,9 @@ export default { applyConfig (id_) { const args = objectToParams(formatFormData(this.forms[id_])) - api.put(`apps/${this.id}/config`, { args }).then(response => { + api.put( + `apps/${this.id}/config`, { args }, { key: 'apps.update_config', name: this.id } + ).then(response => { console.log('SUCCESS', response) }).catch(err => { if (err.name !== 'APIBadRequestError') throw err diff --git a/app/src/views/app/AppInfo.vue b/app/src/views/app/AppInfo.vue index f173f27a..aa05220a 100644 --- a/app/src/views/app/AppInfo.vue +++ b/app/src/views/app/AppInfo.vue @@ -252,7 +252,11 @@ export default { changeLabel (permName, data) { data.show_tile = data.show_tile ? 'True' : 'False' - api.put('users/permissions/' + permName, data).then(this.$refs.view.fetchQueries) + api.put( + 'users/permissions/' + permName, + data, + { key: 'apps.change_label', prevName: this.infos.label, nextName: data.label } + ).then(this.$refs.view.fetchQueries) }, async changeUrl () { @@ -262,7 +266,8 @@ export default { const { domain, path } = this.form.url api.put( `apps/${this.id}/changeurl`, - { domain, path: '/' + path } + { domain, path: '/' + path }, + { key: 'apps.change_url', name: this.infos.label } ).then(this.$refs.view.fetchQueries) }, @@ -270,7 +275,11 @@ export default { const confirmed = await this.$askConfirmation(this.$i18n.t('confirm_app_default')) if (!confirmed) return - api.put(`apps/${this.id}/default`).then(this.$refs.view.fetchQueries) + api.put( + `apps/${this.id}/default`, + {}, + { key: 'apps.set_default', name: this.infos.label, domain: this.app.domain } + ).then(this.$refs.view.fetchQueries) }, async uninstall () { @@ -279,7 +288,7 @@ export default { ) if (!confirmed) return - api.delete('apps/' + this.id).then(() => { + api.delete('apps/' + this.id, {}, { key: 'apps.uninstall', name: this.infos.label }).then(() => { this.$router.push({ name: 'app-list' }) }) } diff --git a/app/src/views/app/AppInstall.vue b/app/src/views/app/AppInstall.vue index 780c1a06..e6c9c42c 100644 --- a/app/src/views/app/AppInstall.vue +++ b/app/src/views/app/AppInstall.vue @@ -92,7 +92,7 @@ export default { }, getApiManifest () { - return api.get('appscatalog?full').then(response => response.apps[this.id].manifest) + return api.get('apps/catalog?full').then(response => response.apps[this.id].manifest) }, formatManifestData (manifest) { @@ -128,7 +128,7 @@ export default { const { data: args, label } = formatFormData(this.form, { extract: ['label'] }) const data = { app: this.id, label, args: objectToParams(args) } - api.post('apps', data).then(response => { + api.post('apps', data, { key: 'apps.install', name: this.name }).then(() => { this.$router.push({ name: 'app-list' }) }).catch(err => { if (err.name !== 'APIBadRequestError') throw err diff --git a/app/src/views/backup/BackupCreate.vue b/app/src/views/backup/BackupCreate.vue index 1088bc83..7ac84154 100644 --- a/app/src/views/backup/BackupCreate.vue +++ b/app/src/views/backup/BackupCreate.vue @@ -164,7 +164,7 @@ export default { } } - api.post('backups', data).then(response => { + api.post('backups', data, 'backups.create').then(() => { this.$router.push({ name: 'backup-list', params: { id: this.id } }) }) } diff --git a/app/src/views/backup/BackupInfo.vue b/app/src/views/backup/BackupInfo.vue index c472357d..86ba2acd 100644 --- a/app/src/views/backup/BackupInfo.vue +++ b/app/src/views/backup/BackupInfo.vue @@ -210,7 +210,9 @@ export default { } } - api.put(`backups/${this.name}/restore`, data).then(response => { + api.put( + `backups/${this.name}/restore`, data, { key: 'backups.restore', name: this.name } + ).then(() => { this.isValid = null }).catch(err => { if (err.name !== 'APIBadRequestError') throw err @@ -223,7 +225,9 @@ export default { const confirmed = await this.$askConfirmation(this.$i18n.t('confirm_delete', { name: this.name })) if (!confirmed) return - api.delete('backups/' + this.name).then(() => { + api.delete( + 'backups/' + this.name, {}, { key: 'backups.delete', name: this.name } + ).then(() => { this.$router.push({ name: 'backup-list', params: { id: this.id } }) }) }, diff --git a/app/src/views/diagnosis/Diagnosis.vue b/app/src/views/diagnosis/Diagnosis.vue index b3708e50..5b1d5dc8 100644 --- a/app/src/views/diagnosis/Diagnosis.vue +++ b/app/src/views/diagnosis/Diagnosis.vue @@ -42,7 +42,7 @@ @@ -115,7 +115,7 @@ export default { data () { return { queries: [ - ['PUT', 'diagnosis/run?except_if_never_ran_yet'], + ['PUT', 'diagnosis/run?except_if_never_ran_yet', {}, 'diagnosis.run'], ['GET', 'diagnosis?full'] ], reports: undefined @@ -171,10 +171,15 @@ export default { this.reports = reports }, - runDiagnosis (id = null) { + runDiagnosis ({ id = null, description } = {}) { const param = id !== null ? '?force' : '' const data = id !== null ? { categories: [id] } : {} - api.post('diagnosis/run' + param, data).then(this.$refs.view.fetchQueries) + + api.put( + 'diagnosis/run' + param, + data, + { key: 'diagnosis.run' + (id !== null ? '_specific' : ''), description } + ).then(this.$refs.view.fetchQueries) }, toggleIgnoreIssue (action, report, item) { @@ -183,7 +188,11 @@ export default { return filterArgs }, [report.id]) - api.put('diagnosis/' + action, { filter: filterArgs }).then(() => { + api.put( + 'diagnosis/' + action, + { filter: filterArgs }, + `diagnosis.${action}.${item.status.toLowerCase()}` + ).then(() => { item.ignored = action === 'ignore' if (item.ignored) { report[item.status.toLowerCase() + 's']-- diff --git a/app/src/views/domain/DomainAdd.vue b/app/src/views/domain/DomainAdd.vue index 6213d38f..6b9cfee1 100644 --- a/app/src/views/domain/DomainAdd.vue +++ b/app/src/views/domain/DomainAdd.vue @@ -27,8 +27,7 @@ export default { onSubmit ({ domain, domainType }) { const uri = 'domains' + (domainType === 'dynDomain' ? '?dyndns' : '') api.post( - { uri, storeKey: 'domains' }, - { domain } + { uri, storeKey: 'domains' }, { domain }, { key: 'domains.add', name: domain } ).then(() => { this.$router.push({ name: 'domain-list' }) }).catch(err => { diff --git a/app/src/views/domain/DomainCert.vue b/app/src/views/domain/DomainCert.vue index cb3d248a..e8e0c523 100644 --- a/app/src/views/domain/DomainCert.vue +++ b/app/src/views/domain/DomainCert.vue @@ -151,7 +151,9 @@ export default { if (action === 'regen_selfsigned') uri += '?self_signed' else if (action === 'manual_renew_LE') uri += '?force' else if (action === 'revert_to_selfsigned') uri += '?self_signed&force' - api.put(uri).then(this.$refs.view.fetchQueries) + api.put( + uri, {}, { key: 'domains.' + action, name: this.name } + ).then(this.$refs.view.fetchQueries) } } } diff --git a/app/src/views/domain/DomainInfo.vue b/app/src/views/domain/DomainInfo.vue index 64a76b47..44837eee 100644 --- a/app/src/views/domain/DomainInfo.vue +++ b/app/src/views/domain/DomainInfo.vue @@ -83,7 +83,7 @@ export default { if (!confirmed) return api.delete( - { uri: 'domains', param: this.name } + { uri: 'domains', param: this.name }, {}, { key: 'domains.delete', name: this.name } ).then(() => { this.$router.push({ name: 'domain-list' }) }) @@ -94,7 +94,9 @@ export default { if (!confirmed) return api.put( - { uri: `domains/${this.name}/main`, storeKey: 'main_domain' } + { uri: `domains/${this.name}/main`, storeKey: 'main_domain' }, + {}, + { key: 'domains.set_default', name: this.name } ).then(() => { // FIXME Have to commit by hand here since the response is empty (should return the given name) this.$store.commit('UPDATE_MAIN_DOMAIN', this.name) diff --git a/app/src/views/group/GroupCreate.vue b/app/src/views/group/GroupCreate.vue index 0dc6332e..ab311566 100644 --- a/app/src/views/group/GroupCreate.vue +++ b/app/src/views/group/GroupCreate.vue @@ -45,7 +45,8 @@ export default { onSubmit () { api.post( { uri: 'users/groups', storeKey: 'groups' }, - this.form + this.form, + { key: 'groups.create', name: this.form.groupname } ).then(() => { this.$router.push({ name: 'group-list' }) }).catch(err => { diff --git a/app/src/views/group/GroupList.vue b/app/src/views/group/GroupList.vue index da1606ab..4587cbe7 100644 --- a/app/src/views/group/GroupList.vue +++ b/app/src/views/group/GroupList.vue @@ -220,7 +220,11 @@ export default { // const data = { [action]: name } const from = action === 'add' ? 'availablePermissions' : 'permissions' const to = action === 'add' ? 'permissions' : 'availablePermissions' - api.put(`users/permissions/${item}/${action}/${name}`).then(() => { + api.put( + `users/permissions/${item}/${action}/${name}`, + {}, + { key: 'permissions.' + action, perm: item.replace('.main', ''), name } + ).then(() => { this[groupType + 'Groups'][name][from].splice(index, 1) this[groupType + 'Groups'][name][to].push(item) }) @@ -229,7 +233,11 @@ export default { onUserChanged ({ item, index, name, action }) { const from = action === 'add' ? 'availableMembers' : 'members' const to = action === 'add' ? 'members' : 'availableMembers' - api.put(`users/groups/${name}/${action}/${item}`).then(() => { + api.put( + `users/groups/${name}/${action}/${item}`, + {}, + { key: 'groups.' + action, user: item, name } + ).then(() => { this.normalGroups[name][from].splice(index, 1) this.normalGroups[name][to].push(item) }) @@ -253,7 +261,7 @@ export default { if (!confirmed) return api.delete( - { uri: 'users/groups', param: name, storeKey: 'groups' } + { uri: 'users/groups', param: name, storeKey: 'groups' }, {}, { key: 'groups.delete', name } ).then(() => { Vue.delete(this.normalGroups, name) }) diff --git a/app/src/views/service/ServiceInfo.vue b/app/src/views/service/ServiceInfo.vue index 273307bd..8af84ab8 100644 --- a/app/src/views/service/ServiceInfo.vue +++ b/app/src/views/service/ServiceInfo.vue @@ -120,7 +120,11 @@ export default { ) if (!confirmed) return - api.put(`services/${this.name}/${action}`).then(this.$refs.view.fetchQueries) + api.put( + `services/${this.name}/${action}`, + {}, + { key: 'services.' + action, name: this.name } + ).then(this.$refs.view.fetchQueries) }, shareLogs () { diff --git a/app/src/views/tool/ToolAdminpw.vue b/app/src/views/tool/ToolAdminpw.vue index 538846a0..8ff3f6cf 100644 --- a/app/src/views/tool/ToolAdminpw.vue +++ b/app/src/views/tool/ToolAdminpw.vue @@ -44,8 +44,8 @@ export default { this.serverError = '' api.fetchAll( - [['POST', 'login', { password: currentPassword }, { websocket: false }], - ['PUT', 'adminpw', { new_password: password }]], + [['POST', 'login', { password: currentPassword }, null, { websocket: false }], + ['PUT', 'adminpw', { new_password: password }, 'adminpw']], { wait: true } ).then(() => { this.$store.dispatch('DISCONNECT') diff --git a/app/src/views/tool/ToolFirewall.vue b/app/src/views/tool/ToolFirewall.vue index 7829a7ab..cd0592a2 100644 --- a/app/src/views/tool/ToolFirewall.vue +++ b/app/src/views/tool/ToolFirewall.vue @@ -183,8 +183,12 @@ export default { if (!confirmed) { return Promise.resolve(confirmed) } + + const actionTrad = this.$i18n.t({ allow: 'open', disallow: 'close' }[action]) return api.put( `firewall/${protocol}/${action}/${port}?${connection}_only`, + {}, + { key: 'firewall.ports', protocol, action: actionTrad, port, connection }, { wait: false } ).then(() => confirmed) }, @@ -194,7 +198,11 @@ export default { const confirmed = await this.$askConfirmation(this.$i18n.t('confirm_upnp_' + action)) if (!confirmed) return - api.put('firewall/upnp/' + action).then(() => { + api.put( + 'firewall/upnp/' + action, + {}, + { key: 'firewall.upnp', action: this.$i18n.t(action) } + ).then(() => { // FIXME Couldn't test when it works. this.$refs.view.fetchQueries() }).catch(err => { diff --git a/app/src/views/tool/ToolLog.vue b/app/src/views/tool/ToolLog.vue index a280176f..7ca3ba4f 100644 --- a/app/src/views/tool/ToolLog.vue +++ b/app/src/views/tool/ToolLog.vue @@ -127,7 +127,12 @@ export default { }, shareLogs () { - api.get(`logs/${this.name}/share`, null, { websocket: true }).then(({ url }) => { + api.get( + `logs/${this.name}/share`, + null, + { key: 'share_logs', name: this.name }, + { websocket: true } + ).then(({ url }) => { window.open(url, '_blank') }) } diff --git a/app/src/views/tool/ToolMigrations.vue b/app/src/views/tool/ToolMigrations.vue index 83d77550..df01dfc2 100644 --- a/app/src/views/tool/ToolMigrations.vue +++ b/app/src/views/tool/ToolMigrations.vue @@ -121,7 +121,7 @@ export default { } // Check that every migration's disclaimer has been checked. if (Object.values(this.checked).every(value => value === true)) { - api.put('migrations', { accept_disclaimer: true }).then(() => { + api.put('migrations', { accept_disclaimer: true }, 'migrations.run').then(() => { this.$refs.view.fetchQueries() }) } @@ -131,7 +131,7 @@ export default { const confirmed = await this.$askConfirmation(this.$i18n.t('confirm_migrations_skip')) if (!confirmed) return - api.put('migrations/' + id, { skip: '' }).then(() => { + api.put('migrations/' + id, { skip: '' }, 'migration.skip').then(() => { this.$refs.view.fetchQueries() }) } diff --git a/app/src/views/tool/ToolPower.vue b/app/src/views/tool/ToolPower.vue index ff496bf7..cd2df63d 100644 --- a/app/src/views/tool/ToolPower.vue +++ b/app/src/views/tool/ToolPower.vue @@ -66,7 +66,7 @@ export default { if (!confirmed) return this.action = action - api.put(action + '?force').then(() => { + api.put(action + '?force', {}, action).then(() => { // Use 'RESET_CONNECTED' and not 'DISCONNECT' else user will be redirect to login this.$store.dispatch('RESET_CONNECTED') this.inProcess = true diff --git a/app/src/views/update/SystemUpdate.vue b/app/src/views/update/SystemUpdate.vue index 282e64a6..f7a0f156 100644 --- a/app/src/views/update/SystemUpdate.vue +++ b/app/src/views/update/SystemUpdate.vue @@ -74,7 +74,7 @@ export default { return { queries: [ ['GET', 'migrations?pending'], - ['PUT', 'update/all'] + ['PUT', 'update/all', {}, 'update'] ], // API data migrationsNotDone: undefined, @@ -96,7 +96,7 @@ export default { if (!confirmed) return const uri = id !== null ? `apps/${id}/upgrade` : 'upgrade/' + type - api.put(uri).then(() => { + api.put(uri, {}, { key: 'upgrade.' + (id ? 'app' : type), app: id }).then(() => { this.$router.push({ name: 'tool-logs' }) }) } diff --git a/app/src/views/user/UserCreate.vue b/app/src/views/user/UserCreate.vue index 13cfa5f8..fb8d7a89 100644 --- a/app/src/views/user/UserCreate.vue +++ b/app/src/views/user/UserCreate.vue @@ -175,7 +175,7 @@ export default { onSubmit () { const data = formatFormData(this.form, { flatten: true }) - api.post({ uri: 'users' }, data).then(() => { + api.post({ uri: 'users' }, data, { key: 'users.create', name: this.form.username }).then(() => { this.$router.push({ name: 'user-list' }) }).catch(err => { if (err.name !== 'APIBadRequestError') throw err diff --git a/app/src/views/user/UserEdit.vue b/app/src/views/user/UserEdit.vue index bf056574..63dc9141 100644 --- a/app/src/views/user/UserEdit.vue +++ b/app/src/views/user/UserEdit.vue @@ -296,7 +296,8 @@ export default { api.put( { uri: 'users', param: this.name, storeKey: 'users_details' }, - data + data, + { key: 'users.update', name: this.name } ).then(() => { this.$router.push({ name: 'user-info', param: { name: this.name } }) }).catch(err => { diff --git a/app/src/views/user/UserInfo.vue b/app/src/views/user/UserInfo.vue index 0fcf4505..662b242e 100644 --- a/app/src/views/user/UserInfo.vue +++ b/app/src/views/user/UserInfo.vue @@ -108,7 +108,8 @@ export default { const data = this.purge ? { purge: '' } : {} api.delete( { uri: 'users', param: this.name, storeKey: 'users_details' }, - data + data, + { key: 'users.delete', name: this.name } ).then(() => { this.$router.push({ name: 'user-list' }) })