mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
Merge pull request #339 from YunoHost/uniformize-actionmap-api
[enh] Uniformize actionmap api + human readable actions
This commit is contained in:
commit
c3d86065fa
35 changed files with 291 additions and 176 deletions
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
import { openWebSocket, getResponseData, handleError } from './handlers'
|
import { openWebSocket, getResponseData, handleError } from './handlers'
|
||||||
import { objectToParams } from '@/helpers/commons'
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,6 +30,31 @@ import { objectToParams } from '@/helpers/commons'
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an object literal into an `URLSearchParams` that can be turned into a
|
||||||
|
* query string or used as a body in a `fetch` call.
|
||||||
|
*
|
||||||
|
* @param {Object} obj - An object literal to convert.
|
||||||
|
* @param {Object} options
|
||||||
|
* @param {Boolean} [options.addLocale=false] - Option to append the locale to the query string.
|
||||||
|
* @return {URLSearchParams}
|
||||||
|
*/
|
||||||
|
export function objectToParams (obj, { addLocale = false } = {}) {
|
||||||
|
const urlParams = new URLSearchParams()
|
||||||
|
for (const [key, value] of Object.entries(obj)) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
value.forEach(v => urlParams.append(key, v))
|
||||||
|
} else {
|
||||||
|
urlParams.append(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (addLocale) {
|
||||||
|
urlParams.append('locale', store.getters.locale)
|
||||||
|
}
|
||||||
|
return urlParams
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
options: {
|
options: {
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
|
@ -55,9 +79,15 @@ export default {
|
||||||
* @param {Options} [options={ wait = true, websocket = true, initial = false, asFormData = false }]
|
* @param {Options} [options={ wait = true, websocket = true, initial = false, asFormData = false }]
|
||||||
* @return {Promise<Object|Error>} Promise that resolve the api response data or an error.
|
* @return {Promise<Object|Error>} Promise that resolve the api response data or an error.
|
||||||
*/
|
*/
|
||||||
async fetch (method, uri, data = {}, { wait = true, websocket = true, initial = false, asFormData = false } = {}) {
|
async fetch (
|
||||||
|
method,
|
||||||
|
uri,
|
||||||
|
data = {},
|
||||||
|
humanKey = null,
|
||||||
|
{ wait = true, websocket = true, initial = false, asFormData = false } = {}
|
||||||
|
) {
|
||||||
// `await` because Vuex actions returns promises by default.
|
// `await` because Vuex actions returns promises by default.
|
||||||
const request = await store.dispatch('INIT_REQUEST', { method, uri, initial, wait, websocket })
|
const request = await store.dispatch('INIT_REQUEST', { method, uri, humanKey, initial, wait, websocket })
|
||||||
|
|
||||||
if (websocket) {
|
if (websocket) {
|
||||||
await openWebSocket(request)
|
await openWebSocket(request)
|
||||||
|
@ -70,6 +100,10 @@ export default {
|
||||||
options = { ...options, method, body: objectToParams(data, { addLocale: true }) }
|
options = { ...options, method, body: objectToParams(data, { addLocale: true }) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (['upgrade', 'postinstall', 'reboot', 'shutdown', 'diagnsosis'].some(action => uri.includes(action))) {
|
||||||
|
store.dispatch('END_REQUEST', { request, success: true, wait })
|
||||||
|
return
|
||||||
|
}
|
||||||
const response = await fetch('/yunohost/api/' + uri, options)
|
const response = await fetch('/yunohost/api/' + uri, options)
|
||||||
const responseData = await getResponseData(response)
|
const responseData = await getResponseData(response)
|
||||||
store.dispatch('END_REQUEST', { request, success: response.ok, wait })
|
store.dispatch('END_REQUEST', { request, success: response.ok, wait })
|
||||||
|
@ -92,10 +126,10 @@ export default {
|
||||||
const results = []
|
const results = []
|
||||||
if (wait) store.commit('SET_WAITING', true)
|
if (wait) store.commit('SET_WAITING', true)
|
||||||
try {
|
try {
|
||||||
for (const [method, uri, data, options = {}] of queries) {
|
for (const [method, uri, data, humanKey, options = {}] of queries) {
|
||||||
if (wait) options.wait = false
|
if (wait) options.wait = false
|
||||||
if (initial) options.initial = true
|
if (initial) options.initial = true
|
||||||
results.push(await this[method.toLowerCase()](uri, data, options))
|
results.push(await this[method.toLowerCase()](uri, data, humanKey, options))
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// Stop waiting even if there is an error.
|
// Stop waiting even if there is an error.
|
||||||
|
@ -114,10 +148,10 @@ export default {
|
||||||
* @param {Options} [options={}] - options to apply to the call (default is `{ websocket: false, wait: false }`)
|
* @param {Options} [options={}] - options to apply to the call (default is `{ websocket: false, wait: false }`)
|
||||||
* @return {Promise<Object|Error>} Promise that resolve the api response data or an error.
|
* @return {Promise<Object|Error>} Promise that resolve the api response data or an error.
|
||||||
*/
|
*/
|
||||||
get (uri, data = null, options = {}) {
|
get (uri, data = null, humanKey = null, options = {}) {
|
||||||
options = { websocket: false, wait: false, ...options }
|
options = { websocket: false, wait: false, ...options }
|
||||||
if (typeof uri === 'string') return this.fetch('GET', uri, null, options)
|
if (typeof uri === 'string') return this.fetch('GET', uri, null, humanKey, options)
|
||||||
return store.dispatch('GET', { ...uri, options })
|
return store.dispatch('GET', { ...uri, humanKey, options })
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
@ -129,9 +163,9 @@ export default {
|
||||||
* @param {Options} [options={}] - options to apply to the call
|
* @param {Options} [options={}] - options to apply to the call
|
||||||
* @return {Promise<Object|Error>} Promise that resolve the api response data or an error.
|
* @return {Promise<Object|Error>} Promise that resolve the api response data or an error.
|
||||||
*/
|
*/
|
||||||
post (uri, data = {}, options = {}) {
|
post (uri, data = {}, humanKey = null, options = {}) {
|
||||||
if (typeof uri === 'string') return this.fetch('POST', uri, data, options)
|
if (typeof uri === 'string') return this.fetch('POST', uri, data, humanKey, options)
|
||||||
return store.dispatch('POST', { ...uri, data, options })
|
return store.dispatch('POST', { ...uri, data, humanKey, options })
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
@ -143,9 +177,9 @@ export default {
|
||||||
* @param {Options} [options={}] - options to apply to the call
|
* @param {Options} [options={}] - options to apply to the call
|
||||||
* @return {Promise<Object|Error>} Promise that resolve the api response data or an error.
|
* @return {Promise<Object|Error>} Promise that resolve the api response data or an error.
|
||||||
*/
|
*/
|
||||||
put (uri, data = {}, options = {}) {
|
put (uri, data = {}, humanKey = null, options = {}) {
|
||||||
if (typeof uri === 'string') return this.fetch('PUT', uri, data, options)
|
if (typeof uri === 'string') return this.fetch('PUT', uri, data, humanKey, options)
|
||||||
return store.dispatch('PUT', { ...uri, data, options })
|
return store.dispatch('PUT', { ...uri, data, humanKey, options })
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
@ -157,8 +191,8 @@ export default {
|
||||||
* @param {Options} [options={}] - options to apply to the call (default is `{ websocket: false, wait: false }`)
|
* @param {Options} [options={}] - options to apply to the call (default is `{ websocket: false, wait: false }`)
|
||||||
* @return {Promise<Object|Error>} Promise that resolve the api response data or an error.
|
* @return {Promise<Object|Error>} Promise that resolve the api response data or an error.
|
||||||
*/
|
*/
|
||||||
delete (uri, data = {}, options = {}) {
|
delete (uri, data = {}, humanKey = null, options = {}) {
|
||||||
if (typeof uri === 'string') return this.fetch('DELETE', uri, data, options)
|
if (typeof uri === 'string') return this.fetch('DELETE', uri, data, humanKey, options)
|
||||||
return store.dispatch('DELETE', { ...uri, data, options })
|
return store.dispatch('DELETE', { ...uri, data, humanKey, options })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { default } from './api'
|
export { default, objectToParams } from './api'
|
||||||
export { handleError, registerGlobalErrorHandlers } from './handlers'
|
export { handleError, registerGlobalErrorHandlers } from './handlers'
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
|
|
||||||
<!-- REQUEST DESCRIPTION -->
|
<!-- REQUEST DESCRIPTION -->
|
||||||
<strong class="request-desc">
|
<strong class="request-desc">
|
||||||
{{ request.uri | readableUri }}
|
{{ request.humanRoute }}
|
||||||
<small>({{ $t('history.methods.' + request.method) }})</small>
|
|
||||||
</strong>
|
</strong>
|
||||||
|
|
||||||
<div v-if="request.errors || request.warnings">
|
<div v-if="request.errors || request.warnings">
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
import store from '@/store'
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow to set a timeout on a `Promise` expected response.
|
* Allow to set a timeout on a `Promise` expected response.
|
||||||
* The returned Promise will be rejected if the original Promise is not resolved or
|
* The returned Promise will be rejected if the original Promise is not resolved or
|
||||||
|
@ -19,31 +16,6 @@ export function timeout (promise, delay) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts an object literal into an `URLSearchParams` that can be turned into a
|
|
||||||
* query string or used as a body in a `fetch` call.
|
|
||||||
*
|
|
||||||
* @param {Object} obj - An object literal to convert.
|
|
||||||
* @param {Object} options
|
|
||||||
* @param {Boolean} [options.addLocale=false] - Option to append the locale to the query string.
|
|
||||||
* @return {URLSearchParams}
|
|
||||||
*/
|
|
||||||
export function objectToParams (obj, { addLocale = false } = {}) {
|
|
||||||
const urlParams = new URLSearchParams()
|
|
||||||
for (const [key, value] of Object.entries(obj)) {
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
value.forEach(v => urlParams.append(key, v))
|
|
||||||
} else {
|
|
||||||
urlParams.append(key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (addLocale) {
|
|
||||||
urlParams.append('locale', store.getters.locale)
|
|
||||||
}
|
|
||||||
return urlParams
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if passed value is an object literal.
|
* Check if passed value is an object literal.
|
||||||
*
|
*
|
||||||
|
|
|
@ -91,8 +91,8 @@
|
||||||
"confirm_app_default": "Are you sure you want to make this app default?",
|
"confirm_app_default": "Are you sure you want to make this app default?",
|
||||||
"confirm_change_maindomain": "Are you sure you want to change the main domain?",
|
"confirm_change_maindomain": "Are you sure you want to change the main domain?",
|
||||||
"confirm_delete": "Are you sure you want to delete {name}?",
|
"confirm_delete": "Are you sure you want to delete {name}?",
|
||||||
"confirm_firewall_open": "Are you sure you want to open port {port} (protocol: {protocol}, connection: {connection})",
|
"confirm_firewall_allow": "Are you sure you want to open port {port} (protocol: {protocol}, connection: {connection})",
|
||||||
"confirm_firewall_close": "Are you sure you want to close port {port} (protocol: {protocol}, connection: {connection})",
|
"confirm_firewall_disallow": "Are you sure you want to close port {port} (protocol: {protocol}, connection: {connection})",
|
||||||
"confirm_install_custom_app": "WARNING! Installing 3rd party applications may compromise the integrity and security of your system. You should probably NOT install it unless you know what you are doing. Are you willing to take that risk?",
|
"confirm_install_custom_app": "WARNING! Installing 3rd party applications may compromise the integrity and security of your system. You should probably NOT install it unless you know what you are doing. Are you willing to take that risk?",
|
||||||
"confirm_install_domain_root": "Are you sure you want to install this application on '/'? You will not be able to install any other app on {domain}",
|
"confirm_install_domain_root": "Are you sure you want to install this application on '/'? You will not be able to install any other app on {domain}",
|
||||||
"confirm_app_install": "Are you sure you want to install this application?",
|
"confirm_app_install": "Are you sure you want to install this application?",
|
||||||
|
@ -201,6 +201,7 @@
|
||||||
"groups_and_permissions_manage": "Manage groups and permissions",
|
"groups_and_permissions_manage": "Manage groups and permissions",
|
||||||
"permissions": "Permissions",
|
"permissions": "Permissions",
|
||||||
"history": {
|
"history": {
|
||||||
|
"is_empty": "Nothing in history for now.",
|
||||||
"title": "History",
|
"title": "History",
|
||||||
"last_action": "Last action:",
|
"last_action": "Last action:",
|
||||||
"methods": {
|
"methods": {
|
||||||
|
@ -330,6 +331,82 @@
|
||||||
"rerun_diagnosis": "Rerun diagnosis",
|
"rerun_diagnosis": "Rerun diagnosis",
|
||||||
"restore": "Restore",
|
"restore": "Restore",
|
||||||
"restart": "Restart",
|
"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",
|
"run": "Run",
|
||||||
"running": "Running",
|
"running": "Running",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
|
|
|
@ -33,13 +33,11 @@ body {
|
||||||
min-height: 100vh
|
min-height: 100vh
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-list {
|
.menu-list .list-group-item {
|
||||||
.list-group-item {
|
|
||||||
padding: $list-group-item-padding-y 0;
|
padding: $list-group-item-padding-y 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Bootstrap overrides
|
// Bootstrap overrides
|
||||||
|
@ -114,10 +112,6 @@ body {
|
||||||
top: 2px;
|
top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-group-item .icon {
|
|
||||||
margin-left: 0.3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fork-awesome overrides
|
// Fork-awesome overrides
|
||||||
.fa-fw {
|
.fa-fw {
|
||||||
width: 1.25em !important;
|
width: 1.25em !important;
|
||||||
|
|
|
@ -90,21 +90,21 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
'GET' ({ state, commit, rootState }, { uri, param, storeKey = uri, options = {} }) {
|
'GET' ({ state, commit, rootState }, { uri, param, humanKey, storeKey = uri, options = {} }) {
|
||||||
const noCache = !rootState.cache || options.noCache || false
|
const noCache = !rootState.cache || options.noCache || false
|
||||||
const currentState = param ? state[storeKey][param] : state[storeKey]
|
const currentState = param ? state[storeKey][param] : state[storeKey]
|
||||||
// if data has already been queried, simply return
|
// if data has already been queried, simply return
|
||||||
if (currentState !== undefined && !noCache) return currentState
|
if (currentState !== undefined && !noCache) return currentState
|
||||||
|
|
||||||
return api.fetch('GET', param ? `${uri}/${param}` : uri, null, options).then(responseData => {
|
return api.fetch('GET', param ? `${uri}/${param}` : uri, null, humanKey, options).then(responseData => {
|
||||||
const data = responseData[storeKey] ? responseData[storeKey] : responseData
|
const data = responseData[storeKey] ? responseData[storeKey] : responseData
|
||||||
commit('SET_' + storeKey.toUpperCase(), param ? [param, data] : data)
|
commit('SET_' + storeKey.toUpperCase(), param ? [param, data] : data)
|
||||||
return param ? state[storeKey][param] : state[storeKey]
|
return param ? state[storeKey][param] : state[storeKey]
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
'POST' ({ state, commit }, { uri, storeKey = uri, data, options }) {
|
'POST' ({ state, commit }, { uri, storeKey = uri, data, humanKey, options }) {
|
||||||
return api.fetch('POST', uri, data, options).then(responseData => {
|
return api.fetch('POST', uri, data, humanKey, options).then(responseData => {
|
||||||
// FIXME api/domains returns null
|
// FIXME api/domains returns null
|
||||||
if (responseData === null) responseData = data
|
if (responseData === null) responseData = data
|
||||||
responseData = responseData[storeKey] ? responseData[storeKey] : responseData
|
responseData = responseData[storeKey] ? responseData[storeKey] : responseData
|
||||||
|
@ -113,16 +113,16 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
'PUT' ({ state, commit }, { uri, param, storeKey = uri, data, options }) {
|
'PUT' ({ state, commit }, { uri, param, storeKey = uri, data, humanKey, options }) {
|
||||||
return api.fetch('PUT', param ? `${uri}/${param}` : uri, data, options).then(responseData => {
|
return api.fetch('PUT', param ? `${uri}/${param}` : uri, data, humanKey, options).then(responseData => {
|
||||||
const data = responseData[storeKey] ? responseData[storeKey] : responseData
|
const data = responseData[storeKey] ? responseData[storeKey] : responseData
|
||||||
commit('UPDATE_' + storeKey.toUpperCase(), param ? [param, data] : data)
|
commit('UPDATE_' + storeKey.toUpperCase(), param ? [param, data] : data)
|
||||||
return param ? state[storeKey][param] : state[storeKey]
|
return param ? state[storeKey][param] : state[storeKey]
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
'DELETE' ({ commit }, { uri, param, storeKey = uri, data, options }) {
|
'DELETE' ({ commit }, { uri, param, storeKey = uri, data, humanKey, options }) {
|
||||||
return api.fetch('DELETE', param ? `${uri}/${param}` : uri, data, options).then(() => {
|
return api.fetch('DELETE', param ? `${uri}/${param}` : uri, data, humanKey, options).then(() => {
|
||||||
commit('DEL_' + storeKey.toUpperCase(), param)
|
commit('DEL_' + storeKey.toUpperCase(), param)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
import { timeout } from '@/helpers/commons'
|
import i18n from '@/i18n'
|
||||||
|
import { timeout, isObjectLiteral } from '@/helpers/commons'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
state: {
|
state: {
|
||||||
|
@ -107,7 +108,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
'LOGIN' ({ dispatch }, password) {
|
'LOGIN' ({ dispatch }, password) {
|
||||||
return api.post('login', { password }, { websocket: false }).then(() => {
|
return api.post('login', { password }, null, { websocket: false }).then(() => {
|
||||||
dispatch('CONNECT')
|
dispatch('CONNECT')
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -123,8 +124,12 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
'INIT_REQUEST' ({ commit }, { method, uri, initial, wait, websocket }) {
|
'INIT_REQUEST' ({ commit }, { method, uri, humanKey, initial, wait, websocket }) {
|
||||||
let request = { method, uri, initial, status: 'pending' }
|
// Try to find a description for an API route to display in history and modals
|
||||||
|
const { key, ...args } = isObjectLiteral(humanKey) ? humanKey : { key: humanKey }
|
||||||
|
const humanRoute = key ? i18n.t('human_routes.' + key, args) : `[${method}] /${uri}`
|
||||||
|
|
||||||
|
let request = { method, uri, humanRoute, initial, status: 'pending' }
|
||||||
if (websocket) {
|
if (websocket) {
|
||||||
request = { ...request, messages: [], date: Date.now(), warnings: 0, errors: 0 }
|
request = { ...request, messages: [], date: Date.now(), warnings: 0, errors: 0 }
|
||||||
commit('ADD_HISTORY_ACTION', request)
|
commit('ADD_HISTORY_ACTION', request)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
:key="item.routeName"
|
:key="item.routeName"
|
||||||
:to="{ name: item.routeName }"
|
:to="{ name: item.routeName }"
|
||||||
>
|
>
|
||||||
<icon :iname="item.icon" class="lg" />
|
<icon :iname="item.icon" class="lg ml-1" />
|
||||||
<h4>{{ $t(item.translation) }}</h4>
|
<h4>{{ $t(item.translation) }}</h4>
|
||||||
<icon iname="chevron-right" class="lg fs-sm ml-auto" />
|
<icon iname="chevron-right" class="lg fs-sm ml-auto" />
|
||||||
</b-list-group-item>
|
</b-list-group-item>
|
||||||
|
|
|
@ -33,6 +33,10 @@
|
||||||
class="accordion" role="tablist"
|
class="accordion" role="tablist"
|
||||||
id="history" ref="history"
|
id="history" ref="history"
|
||||||
>
|
>
|
||||||
|
<p v-if="history.length === 0" class="alert m-0 px-2 py-1">
|
||||||
|
{{ $t('history.is_empty') }}
|
||||||
|
</p>
|
||||||
|
|
||||||
<!-- ACTION LIST -->
|
<!-- ACTION LIST -->
|
||||||
<b-card
|
<b-card
|
||||||
v-for="(action, i) in history" :key="i"
|
v-for="(action, i) in history" :key="i"
|
||||||
|
|
|
@ -38,11 +38,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import api from '@/api'
|
import api, { objectToParams } from '@/api'
|
||||||
import { validationMixin } from 'vuelidate'
|
import { validationMixin } from 'vuelidate'
|
||||||
|
|
||||||
import { formatI18nField, formatYunoHostArguments, formatFormData } from '@/helpers/yunohostArguments'
|
import { formatI18nField, formatYunoHostArguments, formatFormData } from '@/helpers/yunohostArguments'
|
||||||
import { objectToParams } from '@/helpers/commons'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AppActions',
|
name: 'AppActions',
|
||||||
|
@ -100,7 +99,11 @@ export default {
|
||||||
// FIXME api expects at least one argument ?! (fake one given with { dontmindthis } )
|
// FIXME api expects at least one argument ?! (fake one given with { dontmindthis } )
|
||||||
const args = objectToParams(action.form ? formatFormData(action.form) : { dontmindthis: undefined })
|
const args = objectToParams(action.form ? formatFormData(action.form) : { dontmindthis: undefined })
|
||||||
|
|
||||||
api.put(`apps/${this.id}/actions/${action.id}`, { args }).then(response => {
|
api.put(
|
||||||
|
`apps/${this.id}/actions/${action.id}`,
|
||||||
|
{ args },
|
||||||
|
{ key: 'apps.perform_action', action: action.id, name: this.id }
|
||||||
|
).then(() => {
|
||||||
this.$refs.view.fetchQueries()
|
this.$refs.view.fetchQueries()
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
if (err.name !== 'APIBadRequestError') throw err
|
if (err.name !== 'APIBadRequestError') throw err
|
||||||
|
|
|
@ -164,7 +164,7 @@ export default {
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
queries: [
|
queries: [
|
||||||
['GET', 'appscatalog?full&with_categories']
|
['GET', 'apps/catalog?full&with_categories']
|
||||||
],
|
],
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
|
|
|
@ -38,9 +38,8 @@
|
||||||
import { validationMixin } from 'vuelidate'
|
import { validationMixin } from 'vuelidate'
|
||||||
|
|
||||||
// FIXME needs test and rework
|
// FIXME needs test and rework
|
||||||
import api from '@/api'
|
import api, { objectToParams } from '@/api'
|
||||||
import { formatI18nField, formatYunoHostArguments, formatFormData } from '@/helpers/yunohostArguments'
|
import { formatI18nField, formatYunoHostArguments, formatFormData } from '@/helpers/yunohostArguments'
|
||||||
import { objectToParams } from '@/helpers/commons'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AppConfigPanel',
|
name: 'AppConfigPanel',
|
||||||
|
@ -103,7 +102,9 @@ export default {
|
||||||
applyConfig (id_) {
|
applyConfig (id_) {
|
||||||
const args = objectToParams(formatFormData(this.forms[id_]))
|
const args = objectToParams(formatFormData(this.forms[id_]))
|
||||||
|
|
||||||
api.post(`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)
|
console.log('SUCCESS', response)
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
if (err.name !== 'APIBadRequestError') throw err
|
if (err.name !== 'APIBadRequestError') throw err
|
||||||
|
|
|
@ -252,7 +252,11 @@ export default {
|
||||||
|
|
||||||
changeLabel (permName, data) {
|
changeLabel (permName, data) {
|
||||||
data.show_tile = data.show_tile ? 'True' : 'False'
|
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 () {
|
async changeUrl () {
|
||||||
|
@ -262,7 +266,8 @@ export default {
|
||||||
const { domain, path } = this.form.url
|
const { domain, path } = this.form.url
|
||||||
api.put(
|
api.put(
|
||||||
`apps/${this.id}/changeurl`,
|
`apps/${this.id}/changeurl`,
|
||||||
{ domain, path: '/' + path }
|
{ domain, path: '/' + path },
|
||||||
|
{ key: 'apps.change_url', name: this.infos.label }
|
||||||
).then(this.$refs.view.fetchQueries)
|
).then(this.$refs.view.fetchQueries)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -270,7 +275,11 @@ export default {
|
||||||
const confirmed = await this.$askConfirmation(this.$i18n.t('confirm_app_default'))
|
const confirmed = await this.$askConfirmation(this.$i18n.t('confirm_app_default'))
|
||||||
if (!confirmed) return
|
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 () {
|
async uninstall () {
|
||||||
|
@ -279,7 +288,7 @@ export default {
|
||||||
)
|
)
|
||||||
if (!confirmed) return
|
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' })
|
this.$router.push({ name: 'app-list' })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,8 +49,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { validationMixin } from 'vuelidate'
|
import { validationMixin } from 'vuelidate'
|
||||||
|
|
||||||
import api from '@/api'
|
import api, { objectToParams } from '@/api'
|
||||||
import { objectToParams } from '@/helpers/commons'
|
|
||||||
import { formatYunoHostArguments, formatI18nField, formatFormData } from '@/helpers/yunohostArguments'
|
import { formatYunoHostArguments, formatI18nField, formatFormData } from '@/helpers/yunohostArguments'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -93,7 +92,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
getApiManifest () {
|
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) {
|
formatManifestData (manifest) {
|
||||||
|
@ -129,7 +128,7 @@ export default {
|
||||||
const { data: args, label } = formatFormData(this.form, { extract: ['label'] })
|
const { data: args, label } = formatFormData(this.form, { extract: ['label'] })
|
||||||
const data = { app: this.id, label, args: objectToParams(args) }
|
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' })
|
this.$router.push({ name: 'app-list' })
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
if (err.name !== 'APIBadRequestError') throw err
|
if (err.name !== 'APIBadRequestError') throw err
|
||||||
|
|
|
@ -164,7 +164,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
api.post('backup', data).then(response => {
|
api.post('backups', data, 'backups.create').then(() => {
|
||||||
this.$router.push({ name: 'backup-list', params: { id: this.id } })
|
this.$router.push({ name: 'backup-list', params: { id: this.id } })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,7 +132,7 @@ export default {
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
queries: [
|
queries: [
|
||||||
['GET', `backup/archives/${this.name}?with_details`]
|
['GET', `backups/${this.name}?with_details`]
|
||||||
],
|
],
|
||||||
selected: [],
|
selected: [],
|
||||||
error: '',
|
error: '',
|
||||||
|
@ -210,7 +210,9 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
api.post('backup/restore/' + this.name, data).then(response => {
|
api.put(
|
||||||
|
`backups/${this.name}/restore`, data, { key: 'backups.restore', name: this.name }
|
||||||
|
).then(() => {
|
||||||
this.isValid = null
|
this.isValid = null
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
if (err.name !== 'APIBadRequestError') throw err
|
if (err.name !== 'APIBadRequestError') throw err
|
||||||
|
@ -223,14 +225,16 @@ export default {
|
||||||
const confirmed = await this.$askConfirmation(this.$i18n.t('confirm_delete', { name: this.name }))
|
const confirmed = await this.$askConfirmation(this.$i18n.t('confirm_delete', { name: this.name }))
|
||||||
if (!confirmed) return
|
if (!confirmed) return
|
||||||
|
|
||||||
api.delete('backup/archives/' + 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 } })
|
this.$router.push({ name: 'backup-list', params: { id: this.id } })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
downloadBackup () {
|
downloadBackup () {
|
||||||
const host = this.$store.getters.host
|
const host = this.$store.getters.host
|
||||||
window.open(`https://${host}/yunohost/api/backup/download/${this.name}`, '_blank')
|
window.open(`https://${host}/yunohost/api/backups/${this.name}/download`, '_blank')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ export default {
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
queries: [
|
queries: [
|
||||||
['GET', 'backup/archives?with_info']
|
['GET', 'backups?with_info']
|
||||||
],
|
],
|
||||||
archives: undefined
|
archives: undefined
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #header-buttons>
|
<template #header-buttons>
|
||||||
<b-button size="sm" :variant="report.items ? 'info' : 'success'" @click="runDiagnosis(report.id)">
|
<b-button size="sm" :variant="report.items ? 'info' : 'success'" @click="runDiagnosis(report)">
|
||||||
<icon iname="refresh" /> {{ $t('rerun_diagnosis') }}
|
<icon iname="refresh" /> {{ $t('rerun_diagnosis') }}
|
||||||
</b-button>
|
</b-button>
|
||||||
</template>
|
</template>
|
||||||
|
@ -64,13 +64,13 @@
|
||||||
<div class="d-flex flex-column flex-lg-row ml-auto">
|
<div class="d-flex flex-column flex-lg-row ml-auto">
|
||||||
<b-button
|
<b-button
|
||||||
v-if="item.ignored" size="sm"
|
v-if="item.ignored" size="sm"
|
||||||
@click="toggleIgnoreIssue(false, report, item)"
|
@click="toggleIgnoreIssue('unignore', report, item)"
|
||||||
>
|
>
|
||||||
<icon iname="bell" /> {{ $t('unignore') }}
|
<icon iname="bell" /> {{ $t('unignore') }}
|
||||||
</b-button>
|
</b-button>
|
||||||
<b-button
|
<b-button
|
||||||
v-else-if="item.issue" variant="warning" size="sm"
|
v-else-if="item.issue" variant="warning" size="sm"
|
||||||
@click="toggleIgnoreIssue(true, report, item)"
|
@click="toggleIgnoreIssue('ignore', report, item)"
|
||||||
>
|
>
|
||||||
<icon iname="bell-slash" /> {{ $t('ignore') }}
|
<icon iname="bell-slash" /> {{ $t('ignore') }}
|
||||||
</b-button>
|
</b-button>
|
||||||
|
@ -115,8 +115,8 @@ export default {
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
queries: [
|
queries: [
|
||||||
['POST', 'diagnosis/run?except_if_never_ran_yet'],
|
['PUT', 'diagnosis/run?except_if_never_ran_yet', {}, 'diagnosis.run'],
|
||||||
['GET', 'diagnosis/show?full']
|
['GET', 'diagnosis?full']
|
||||||
],
|
],
|
||||||
reports: undefined
|
reports: undefined
|
||||||
}
|
}
|
||||||
|
@ -171,22 +171,30 @@ export default {
|
||||||
this.reports = reports
|
this.reports = reports
|
||||||
},
|
},
|
||||||
|
|
||||||
runDiagnosis (id = null) {
|
runDiagnosis ({ id = null, description } = {}) {
|
||||||
const param = id !== null ? '?force' : ''
|
const param = id !== null ? '?force' : ''
|
||||||
const data = id !== null ? { categories: [id] } : {}
|
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 (ignore, report, item) {
|
toggleIgnoreIssue (action, report, item) {
|
||||||
const key = (ignore ? 'add' : 'remove') + '_filter'
|
|
||||||
const filterArgs = Object.entries(item.meta).reduce((filterArgs, entries) => {
|
const filterArgs = Object.entries(item.meta).reduce((filterArgs, entries) => {
|
||||||
filterArgs.push(entries.join('='))
|
filterArgs.push(entries.join('='))
|
||||||
return filterArgs
|
return filterArgs
|
||||||
}, [report.id])
|
}, [report.id])
|
||||||
|
|
||||||
api.post('diagnosis/ignore', { [key]: filterArgs }).then(() => {
|
api.put(
|
||||||
item.ignored = ignore
|
'diagnosis/' + action,
|
||||||
if (ignore) {
|
{ filter: filterArgs },
|
||||||
|
`diagnosis.${action}.${item.status.toLowerCase()}`
|
||||||
|
).then(() => {
|
||||||
|
item.ignored = action === 'ignore'
|
||||||
|
if (item.ignored) {
|
||||||
report[item.status.toLowerCase() + 's']--
|
report[item.status.toLowerCase() + 's']--
|
||||||
} else {
|
} else {
|
||||||
report.ignoreds--
|
report.ignoreds--
|
||||||
|
|
|
@ -27,8 +27,7 @@ export default {
|
||||||
onSubmit ({ domain, domainType }) {
|
onSubmit ({ domain, domainType }) {
|
||||||
const uri = 'domains' + (domainType === 'dynDomain' ? '?dyndns' : '')
|
const uri = 'domains' + (domainType === 'dynDomain' ? '?dyndns' : '')
|
||||||
api.post(
|
api.post(
|
||||||
{ uri, storeKey: 'domains' },
|
{ uri, storeKey: 'domains' }, { domain }, { key: 'domains.add', name: domain }
|
||||||
{ domain }
|
|
||||||
).then(() => {
|
).then(() => {
|
||||||
this.$router.push({ name: 'domain-list' })
|
this.$router.push({ name: 'domain-list' })
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
|
|
|
@ -84,7 +84,7 @@ export default {
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
queries: [
|
queries: [
|
||||||
['GET', `domains/cert-status/${this.name}?full`]
|
['GET', `domains/${this.name}/cert?full`]
|
||||||
],
|
],
|
||||||
cert: undefined,
|
cert: undefined,
|
||||||
actionsEnabled: undefined
|
actionsEnabled: undefined
|
||||||
|
@ -147,13 +147,13 @@ export default {
|
||||||
const confirmed = await this.$askConfirmation(this.$i18n.t(`confirm_cert_${action}`))
|
const confirmed = await this.$askConfirmation(this.$i18n.t(`confirm_cert_${action}`))
|
||||||
if (!confirmed) return
|
if (!confirmed) return
|
||||||
|
|
||||||
let uri = 'domains/cert-install/' + this.name
|
let uri = `domains/${this.name}/cert`
|
||||||
if (action === 'regen_selfsigned') uri += '?self_signed'
|
if (action === 'regen_selfsigned') uri += '?self_signed'
|
||||||
else if (action === 'manual_renew_LE') uri += '?force'
|
else if (action === 'manual_renew_LE') uri += '?force'
|
||||||
else if (action === 'revert_to_selfsigned') uri += '?self_signed&force'
|
else if (action === 'revert_to_selfsigned') uri += '?self_signed&force'
|
||||||
// FIXME trigger loading ? while posting ? while getting ?
|
api.put(
|
||||||
// this.$refs.view.fallback_loading = true
|
uri, {}, { key: 'domains.' + action, name: this.name }
|
||||||
api.post(uri).then(this.$refs.view.fetchQueries)
|
).then(this.$refs.view.fetchQueries)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ export default {
|
||||||
if (!confirmed) return
|
if (!confirmed) return
|
||||||
|
|
||||||
api.delete(
|
api.delete(
|
||||||
{ uri: 'domains', param: this.name }
|
{ uri: 'domains', param: this.name }, {}, { key: 'domains.delete', name: this.name }
|
||||||
).then(() => {
|
).then(() => {
|
||||||
this.$router.push({ name: 'domain-list' })
|
this.$router.push({ name: 'domain-list' })
|
||||||
})
|
})
|
||||||
|
@ -94,8 +94,9 @@ export default {
|
||||||
if (!confirmed) return
|
if (!confirmed) return
|
||||||
|
|
||||||
api.put(
|
api.put(
|
||||||
{ uri: 'domains/main', storeKey: 'main_domain' },
|
{ uri: `domains/${this.name}/main`, storeKey: 'main_domain' },
|
||||||
{ new_main_domain: this.name }
|
{},
|
||||||
|
{ key: 'domains.set_default', name: this.name }
|
||||||
).then(() => {
|
).then(() => {
|
||||||
// FIXME Have to commit by hand here since the response is empty (should return the given name)
|
// 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)
|
this.$store.commit('UPDATE_MAIN_DOMAIN', this.name)
|
||||||
|
|
|
@ -45,7 +45,8 @@ export default {
|
||||||
onSubmit () {
|
onSubmit () {
|
||||||
api.post(
|
api.post(
|
||||||
{ uri: 'users/groups', storeKey: 'groups' },
|
{ uri: 'users/groups', storeKey: 'groups' },
|
||||||
this.form
|
this.form,
|
||||||
|
{ key: 'groups.create', name: this.form.groupname }
|
||||||
).then(() => {
|
).then(() => {
|
||||||
this.$router.push({ name: 'group-list' })
|
this.$router.push({ name: 'group-list' })
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
|
|
|
@ -216,22 +216,28 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
onPermissionChanged ({ item, index, name, groupType, action }) {
|
onPermissionChanged ({ item, index, name, groupType, action }) {
|
||||||
const uri = 'users/permissions/' + item
|
// const uri = 'users/permissions/' + item
|
||||||
const data = { [action]: name }
|
// const data = { [action]: name }
|
||||||
const from = action === 'add' ? 'availablePermissions' : 'permissions'
|
const from = action === 'add' ? 'availablePermissions' : 'permissions'
|
||||||
const to = action === 'add' ? 'permissions' : 'availablePermissions'
|
const to = action === 'add' ? 'permissions' : 'availablePermissions'
|
||||||
api.put(uri, data).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][from].splice(index, 1)
|
||||||
this[groupType + 'Groups'][name][to].push(item)
|
this[groupType + 'Groups'][name][to].push(item)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
onUserChanged ({ item, index, name, action }) {
|
onUserChanged ({ item, index, name, action }) {
|
||||||
const uri = 'users/groups/' + name
|
|
||||||
const data = { [action]: item }
|
|
||||||
const from = action === 'add' ? 'availableMembers' : 'members'
|
const from = action === 'add' ? 'availableMembers' : 'members'
|
||||||
const to = action === 'add' ? 'members' : 'availableMembers'
|
const to = action === 'add' ? 'members' : 'availableMembers'
|
||||||
api.put(uri, data).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][from].splice(index, 1)
|
||||||
this.normalGroups[name][to].push(item)
|
this.normalGroups[name][to].push(item)
|
||||||
})
|
})
|
||||||
|
@ -255,7 +261,7 @@ export default {
|
||||||
if (!confirmed) return
|
if (!confirmed) return
|
||||||
|
|
||||||
api.delete(
|
api.delete(
|
||||||
{ uri: 'users/groups', param: name, storeKey: 'groups' }
|
{ uri: 'users/groups', param: name, storeKey: 'groups' }, {}, { key: 'groups.delete', name }
|
||||||
).then(() => {
|
).then(() => {
|
||||||
Vue.delete(this.normalGroups, name)
|
Vue.delete(this.normalGroups, name)
|
||||||
})
|
})
|
||||||
|
|
|
@ -120,13 +120,11 @@ export default {
|
||||||
)
|
)
|
||||||
if (!confirmed) return
|
if (!confirmed) return
|
||||||
|
|
||||||
if (!['start', 'restart', 'stop'].includes(action)) return
|
api.put(
|
||||||
const method = action === 'stop' ? 'delete' : 'put'
|
`services/${this.name}/${action}`,
|
||||||
const uri = action === 'restart'
|
{},
|
||||||
? `services/${this.name}/restart`
|
{ key: 'services.' + action, name: this.name }
|
||||||
: 'services/' + this.name
|
).then(this.$refs.view.fetchQueries)
|
||||||
|
|
||||||
api[method](uri).then(this.$refs.view.fetchQueries)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
shareLogs () {
|
shareLogs () {
|
||||||
|
|
|
@ -44,8 +44,8 @@ export default {
|
||||||
this.serverError = ''
|
this.serverError = ''
|
||||||
|
|
||||||
api.fetchAll(
|
api.fetchAll(
|
||||||
[['POST', 'login', { password: currentPassword }, { websocket: false }],
|
[['POST', 'login', { password: currentPassword }, null, { websocket: false }],
|
||||||
['PUT', 'admisnpw', { new_password: password }]],
|
['PUT', 'adminpw', { new_password: password }, 'adminpw']],
|
||||||
{ wait: true }
|
{ wait: true }
|
||||||
).then(() => {
|
).then(() => {
|
||||||
this.$store.dispatch('DISCONNECT')
|
this.$store.dispatch('DISCONNECT')
|
||||||
|
|
|
@ -115,8 +115,8 @@ export default {
|
||||||
|
|
||||||
// Ports form data
|
// Ports form data
|
||||||
actionChoices: [
|
actionChoices: [
|
||||||
{ value: 'open', text: this.$i18n.t('open') },
|
{ value: 'allow', text: this.$i18n.t('open') },
|
||||||
{ value: 'close', text: this.$i18n.t('close') }
|
{ value: 'disallow', text: this.$i18n.t('close') }
|
||||||
],
|
],
|
||||||
connectionChoices: [
|
connectionChoices: [
|
||||||
{ value: 'ipv4', text: this.$i18n.t('ipv4') },
|
{ value: 'ipv4', text: this.$i18n.t('ipv4') },
|
||||||
|
@ -128,7 +128,7 @@ export default {
|
||||||
{ value: 'Both', text: this.$i18n.t('both') }
|
{ value: 'Both', text: this.$i18n.t('both') }
|
||||||
],
|
],
|
||||||
form: {
|
form: {
|
||||||
action: 'open',
|
action: 'allow',
|
||||||
port: undefined,
|
port: undefined,
|
||||||
connection: 'ipv4',
|
connection: 'ipv4',
|
||||||
protocol: 'TCP'
|
protocol: 'TCP'
|
||||||
|
@ -176,27 +176,21 @@ export default {
|
||||||
this.upnpEnabled = data.uPnP.enabled
|
this.upnpEnabled = data.uPnP.enabled
|
||||||
},
|
},
|
||||||
|
|
||||||
togglePort ({ action, port, protocol, connection }) {
|
async togglePort ({ action, port, protocol, connection }) {
|
||||||
return new Promise((resolve, reject) => {
|
const confirmed = await this.$askConfirmation(
|
||||||
this.$askConfirmation(
|
|
||||||
this.$i18n.t('confirm_firewall_' + action, { port, protocol, connection })
|
this.$i18n.t('confirm_firewall_' + action, { port, protocol, connection })
|
||||||
).then(confirmed => {
|
)
|
||||||
if (confirmed) {
|
if (!confirmed) {
|
||||||
const method = action === 'open' ? 'post' : 'delete'
|
return Promise.resolve(confirmed)
|
||||||
api[method](
|
|
||||||
`/firewall/port?${connection}_only`,
|
|
||||||
{ port, protocol },
|
|
||||||
{ wait: false }
|
|
||||||
).then(() => {
|
|
||||||
resolve(confirmed)
|
|
||||||
}).catch(error => {
|
|
||||||
reject(error)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
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)
|
||||||
},
|
},
|
||||||
|
|
||||||
async toggleUpnp (value) {
|
async toggleUpnp (value) {
|
||||||
|
@ -204,7 +198,11 @@ export default {
|
||||||
const confirmed = await this.$askConfirmation(this.$i18n.t('confirm_upnp_' + action))
|
const confirmed = await this.$askConfirmation(this.$i18n.t('confirm_upnp_' + action))
|
||||||
if (!confirmed) return
|
if (!confirmed) return
|
||||||
|
|
||||||
api.get('firewall/upnp?action=' + action, null, { websocket: true, wait: true }).then(() => {
|
api.put(
|
||||||
|
'firewall/upnp/' + action,
|
||||||
|
{},
|
||||||
|
{ key: 'firewall.upnp', action: this.$i18n.t(action) }
|
||||||
|
).then(() => {
|
||||||
// FIXME Couldn't test when it works.
|
// FIXME Couldn't test when it works.
|
||||||
this.$refs.view.fetchQueries()
|
this.$refs.view.fetchQueries()
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
|
@ -215,7 +213,7 @@ export default {
|
||||||
|
|
||||||
onTablePortToggling (port, protocol, connection, index, value) {
|
onTablePortToggling (port, protocol, connection, index, value) {
|
||||||
this.$set(this.protocols[protocol][index], connection, value)
|
this.$set(this.protocols[protocol][index], connection, value)
|
||||||
const action = value ? 'open' : 'close'
|
const action = value ? 'allow' : 'disallow'
|
||||||
this.togglePort({ action, port, protocol, connection }).then(toggled => {
|
this.togglePort({ action, port, protocol, connection }).then(toggled => {
|
||||||
// Revert change on cancel
|
// Revert change on cancel
|
||||||
if (!toggled) {
|
if (!toggled) {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
:key="item.routeName"
|
:key="item.routeName"
|
||||||
:to="{name: item.routeName}"
|
:to="{name: item.routeName}"
|
||||||
>
|
>
|
||||||
<icon :iname="item.icon" class="lg" />
|
<icon :iname="item.icon" class="lg ml-1" />
|
||||||
<h4>{{ $t(item.translation) }}</h4>
|
<h4>{{ $t(item.translation) }}</h4>
|
||||||
<icon iname="chevron-right" class="lg fs-sm ml-auto" />
|
<icon iname="chevron-right" class="lg fs-sm ml-auto" />
|
||||||
</b-list-group-item>
|
</b-list-group-item>
|
||||||
|
|
|
@ -60,8 +60,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import api from '@/api'
|
import api, { objectToParams } from '@/api'
|
||||||
import { objectToParams, escapeHtml } from '@/helpers/commons'
|
import { escapeHtml } from '@/helpers/commons'
|
||||||
import { readableDate } from '@/helpers/filters/date'
|
import { readableDate } from '@/helpers/filters/date'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -127,7 +127,12 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
shareLogs () {
|
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')
|
window.open(url, '_blank')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,7 @@ export default {
|
||||||
}
|
}
|
||||||
// Check that every migration's disclaimer has been checked.
|
// Check that every migration's disclaimer has been checked.
|
||||||
if (Object.values(this.checked).every(value => value === true)) {
|
if (Object.values(this.checked).every(value => value === true)) {
|
||||||
api.post('migrations/run?accept_disclaimer').then(() => {
|
api.post('migrations/run?accept_disclaimer', 'migrations.run').then(() => {
|
||||||
this.$refs.view.fetchQueries()
|
this.$refs.view.fetchQueries()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -130,8 +130,7 @@ export default {
|
||||||
async skipMigration (id) {
|
async skipMigration (id) {
|
||||||
const confirmed = await this.$askConfirmation(this.$i18n.t('confirm_migrations_skip'))
|
const confirmed = await this.$askConfirmation(this.$i18n.t('confirm_migrations_skip'))
|
||||||
if (!confirmed) return
|
if (!confirmed) return
|
||||||
|
api.post('/migrations/run', { skip: '', targets: id }, 'migration.skip').then(() => {
|
||||||
api.post('/migrations/run', { skip: '', targets: id }).then(() => {
|
|
||||||
this.$refs.view.fetchQueries()
|
this.$refs.view.fetchQueries()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ export default {
|
||||||
if (!confirmed) return
|
if (!confirmed) return
|
||||||
|
|
||||||
this.action = action
|
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
|
// Use 'RESET_CONNECTED' and not 'DISCONNECT' else user will be redirect to login
|
||||||
this.$store.dispatch('RESET_CONNECTED')
|
this.$store.dispatch('RESET_CONNECTED')
|
||||||
this.inProcess = true
|
this.inProcess = true
|
||||||
|
|
|
@ -74,7 +74,7 @@ export default {
|
||||||
return {
|
return {
|
||||||
queries: [
|
queries: [
|
||||||
['GET', 'migrations?pending'],
|
['GET', 'migrations?pending'],
|
||||||
['PUT', 'update']
|
['PUT', 'update/all', {}, 'update']
|
||||||
],
|
],
|
||||||
// API data
|
// API data
|
||||||
migrationsNotDone: undefined,
|
migrationsNotDone: undefined,
|
||||||
|
@ -95,11 +95,8 @@ export default {
|
||||||
const confirmed = await this.$askConfirmation(confirmMsg)
|
const confirmed = await this.$askConfirmation(confirmMsg)
|
||||||
if (!confirmed) return
|
if (!confirmed) return
|
||||||
|
|
||||||
const uri = type === 'specific_app'
|
const uri = id !== null ? `apps/${id}/upgrade` : 'upgrade/' + type
|
||||||
? 'upgrade/apps?app=' + id
|
api.put(uri, {}, { key: 'upgrade.' + (id ? 'app' : type), app: id }).then(() => {
|
||||||
: 'upgrade?' + type
|
|
||||||
|
|
||||||
api.put(uri).then(() => {
|
|
||||||
this.$router.push({ name: 'tool-logs' })
|
this.$router.push({ name: 'tool-logs' })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,7 +175,7 @@ export default {
|
||||||
|
|
||||||
onSubmit () {
|
onSubmit () {
|
||||||
const data = formatFormData(this.form, { flatten: true })
|
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' })
|
this.$router.push({ name: 'user-list' })
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
if (err.name !== 'APIBadRequestError') throw err
|
if (err.name !== 'APIBadRequestError') throw err
|
||||||
|
|
|
@ -296,7 +296,8 @@ export default {
|
||||||
|
|
||||||
api.put(
|
api.put(
|
||||||
{ uri: 'users', param: this.name, storeKey: 'users_details' },
|
{ uri: 'users', param: this.name, storeKey: 'users_details' },
|
||||||
data
|
data,
|
||||||
|
{ key: 'users.update', name: this.name }
|
||||||
).then(() => {
|
).then(() => {
|
||||||
this.$router.push({ name: 'user-info', param: { name: this.name } })
|
this.$router.push({ name: 'user-info', param: { name: this.name } })
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
|
|
|
@ -108,7 +108,8 @@ export default {
|
||||||
const data = this.purge ? { purge: '' } : {}
|
const data = this.purge ? { purge: '' } : {}
|
||||||
api.delete(
|
api.delete(
|
||||||
{ uri: 'users', param: this.name, storeKey: 'users_details' },
|
{ uri: 'users', param: this.name, storeKey: 'users_details' },
|
||||||
data
|
data,
|
||||||
|
{ key: 'users.delete', name: this.name }
|
||||||
).then(() => {
|
).then(() => {
|
||||||
this.$router.push({ name: 'user-list' })
|
this.$router.push({ name: 'user-list' })
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue