mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
add AppActions view/route
This commit is contained in:
parent
b1b9e65b7b
commit
a12dc45229
5 changed files with 174 additions and 20 deletions
|
@ -1,7 +1,7 @@
|
||||||
import i18n from '@/i18n'
|
import i18n from '@/i18n'
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
|
|
||||||
function formatI18nField (field) {
|
export function formatI18nField (field) {
|
||||||
if (typeof field === 'string') return field
|
if (typeof field === 'string') return field
|
||||||
const { locale, fallbackLocale } = store.state
|
const { locale, fallbackLocale } = store.state
|
||||||
return field[locale] || field[fallbackLocale] || field.en
|
return field[locale] || field[fallbackLocale] || field.en
|
||||||
|
|
|
@ -165,18 +165,6 @@ const routes = [
|
||||||
component: () => import(/* webpackChunkName: "views/apps" */ '@/views/app/AppList'),
|
component: () => import(/* webpackChunkName: "views/apps" */ '@/views/app/AppList'),
|
||||||
meta: { breadcrumb: [{ name: 'app-list', trad: 'applications' }] }
|
meta: { breadcrumb: [{ name: 'app-list', trad: 'applications' }] }
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'app-info',
|
|
||||||
path: '/apps/info/:id',
|
|
||||||
component: () => import(/* webpackChunkName: "views/apps" */ '@/views/app/AppInfo'),
|
|
||||||
props: true,
|
|
||||||
meta: {
|
|
||||||
breadcrumb: [
|
|
||||||
{ name: 'app-list', trad: 'applications' },
|
|
||||||
{ name: 'app-info', param: 'id' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'app-catalog',
|
name: 'app-catalog',
|
||||||
path: '/apps/catalog',
|
path: '/apps/catalog',
|
||||||
|
@ -214,6 +202,31 @@ const routes = [
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'app-info',
|
||||||
|
path: '/apps/:id',
|
||||||
|
component: () => import(/* webpackChunkName: "views/apps" */ '@/views/app/AppInfo'),
|
||||||
|
props: true,
|
||||||
|
meta: {
|
||||||
|
breadcrumb: [
|
||||||
|
{ name: 'app-list', trad: 'applications' },
|
||||||
|
{ name: 'app-info', param: 'id' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'app-actions',
|
||||||
|
path: '/apps/:id/actions',
|
||||||
|
component: () => import(/* webpackChunkName: "views/apps" */ '@/views/app/AppActions'),
|
||||||
|
props: true,
|
||||||
|
meta: {
|
||||||
|
breadcrumb: [
|
||||||
|
{ name: 'app-list', trad: 'applications' },
|
||||||
|
{ name: 'app-info', param: 'id' },
|
||||||
|
{ name: 'app-actions', trad: 'action' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/* ────────────────╮
|
/* ────────────────╮
|
||||||
│ SYSTEM UPDATE │
|
│ SYSTEM UPDATE │
|
||||||
|
|
|
@ -76,15 +76,24 @@ body {
|
||||||
.card + .card {
|
.card + .card {
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
}
|
}
|
||||||
.card-header h2 {
|
.card-header {
|
||||||
margin: 0;
|
h2, h4 {
|
||||||
font-size: 1.75rem;
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-body {
|
.card-body {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-footer {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
// collapse icon
|
// collapse icon
|
||||||
.not-collapsed > .icon {
|
.not-collapsed > .icon {
|
||||||
transform: rotate(-90deg);
|
transform: rotate(-90deg);
|
||||||
|
|
131
app/src/views/app/AppActions.vue
Normal file
131
app/src/views/app/AppActions.vue
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
<template>
|
||||||
|
<div class="app-actions">
|
||||||
|
<div v-if="actions">
|
||||||
|
<b-alert variant="warning" show class="mb-4">
|
||||||
|
<icon iname="exclamation-triangle" /> {{ $t('experimental_warning') }}
|
||||||
|
</b-alert>
|
||||||
|
|
||||||
|
<!-- BASIC INFOS -->
|
||||||
|
<b-card v-for="(action, i) in actions" :key="i">
|
||||||
|
<template v-slot:header>
|
||||||
|
<h4>{{ action.name }}</h4>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<b-card-text v-if="action.description" v-html="action.description" />
|
||||||
|
|
||||||
|
<b-form v-if="action.args" :id="action.id + '-form'" @submit.prevent="performAction(action)">
|
||||||
|
<form-item-helper v-for="arg in action.args" :key="arg.name" v-bind="arg" />
|
||||||
|
|
||||||
|
<b-form-invalid-feedback :id="action.id + '-feedback'" :state="action.isValid">
|
||||||
|
{{ action.error }}
|
||||||
|
</b-form-invalid-feedback>
|
||||||
|
</b-form>
|
||||||
|
|
||||||
|
<template v-slot:footer>
|
||||||
|
<b-button
|
||||||
|
v-if="action.args" type="submit" :form="action.id + '-form'"
|
||||||
|
variant="success" class="ml-auto" v-t="'perform'"
|
||||||
|
/>
|
||||||
|
<b-button
|
||||||
|
v-else @click="performAction(action)"
|
||||||
|
variant="success" class="ml-auto" v-t="'perform'"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</b-card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- In case of a custom url with no manifest found -->
|
||||||
|
<b-alert v-else-if="actions === null" variant="warning" show>
|
||||||
|
<icon iname="exclamation-triangle" /> {{ $t('app_no_actions') }}
|
||||||
|
</b-alert>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import api, { objectToParams } from '@/helpers/api'
|
||||||
|
import { formatI18nField, formatYunoHostArgument } from '@/helpers/yunohostArguments'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'AppActions',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
actions: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
fetchData () {
|
||||||
|
Promise.all([
|
||||||
|
api.get(`apps/${this.id}/actions`),
|
||||||
|
this.$store.dispatch('FETCH_ALL', [
|
||||||
|
{ uri: 'domains' },
|
||||||
|
{ uri: 'domains/main', storeKey: 'main_domain' },
|
||||||
|
{ uri: 'users' }
|
||||||
|
])
|
||||||
|
]).then((responses) => this.setupForm(responses[0]))
|
||||||
|
},
|
||||||
|
|
||||||
|
setupForm (data) {
|
||||||
|
if (!data.actions) {
|
||||||
|
this.actions = null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const actions = []
|
||||||
|
for (const { name, id, description, arguments: arguments_ } of data.actions) {
|
||||||
|
const action = { name, id, isValid: null, error: '' }
|
||||||
|
if (description) {
|
||||||
|
action.description = formatI18nField(description)
|
||||||
|
}
|
||||||
|
if (arguments_ && arguments_.length) {
|
||||||
|
action.args = arguments_.map(arg => formatYunoHostArgument(arg))
|
||||||
|
}
|
||||||
|
actions.push(action)
|
||||||
|
}
|
||||||
|
this.actions = actions
|
||||||
|
},
|
||||||
|
|
||||||
|
performAction (action) {
|
||||||
|
const data = {}
|
||||||
|
|
||||||
|
if (action.args) {
|
||||||
|
const args = {}
|
||||||
|
for (const arg of action.args) {
|
||||||
|
if (arg.component === 'CheckboxItem') {
|
||||||
|
args[arg.props.id] = arg.props.value ? 1 : 0
|
||||||
|
} else {
|
||||||
|
args[arg.props.id] = arg.props.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data.args = objectToParams(args)
|
||||||
|
// FIXME api expect at least one argument ?!
|
||||||
|
} else {
|
||||||
|
data.args = objectToParams({ wut: undefined })
|
||||||
|
}
|
||||||
|
|
||||||
|
api.put(`apps/${this.id}/actions/${action.id}`, data).then(response => {
|
||||||
|
this.fetchData()
|
||||||
|
}).catch(err => {
|
||||||
|
action.isValid = false
|
||||||
|
action.error = err.message
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created () {
|
||||||
|
this.fetchData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
|
@ -32,12 +32,13 @@
|
||||||
<form-item-helper v-for="arg in form.args" :key="arg.name" v-bind="arg" />
|
<form-item-helper v-for="arg in form.args" :key="arg.name" v-bind="arg" />
|
||||||
|
|
||||||
<b-form-invalid-feedback id="global-feedback" :state="server.isValid">
|
<b-form-invalid-feedback id="global-feedback" :state="server.isValid">
|
||||||
{{ this.server.error }}
|
{{ server.error }}
|
||||||
</b-form-invalid-feedback>
|
</b-form-invalid-feedback>
|
||||||
</b-form>
|
</b-form>
|
||||||
|
|
||||||
<template v-slot:footer>
|
<template v-slot:footer>
|
||||||
<b-button
|
<b-button
|
||||||
|
class="ml-auto"
|
||||||
type="submit" form="install-form"
|
type="submit" form="install-form"
|
||||||
variant="success" v-t="'install'"
|
variant="success" v-t="'install'"
|
||||||
/>
|
/>
|
||||||
|
@ -48,7 +49,7 @@
|
||||||
<b-modal
|
<b-modal
|
||||||
id="confirm-domain-root-modal" ref="confirm-domain-root-modal" centered
|
id="confirm-domain-root-modal" ref="confirm-domain-root-modal" centered
|
||||||
body-bg-variant="danger" body-text-variant="light"
|
body-bg-variant="danger" body-text-variant="light"
|
||||||
@ok="runInstall" hide-header
|
@ok="performInstall" hide-header
|
||||||
:ok-title="$t('install')"
|
:ok-title="$t('install')"
|
||||||
>
|
>
|
||||||
{{ $t('confirm_install_domain_root', { domain: confirmDomain }) }}
|
{{ $t('confirm_install_domain_root', { domain: confirmDomain }) }}
|
||||||
|
@ -152,11 +153,11 @@ export default {
|
||||||
this.confirmDomain = this.form.args.find(arg => arg.props.id === 'domain').props.value
|
this.confirmDomain = this.form.args.find(arg => arg.props.id === 'domain').props.value
|
||||||
this.$refs['confirm-domain-root-modal'].show()
|
this.$refs['confirm-domain-root-modal'].show()
|
||||||
} else {
|
} else {
|
||||||
this.runInstall()
|
this.performInstall()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
runInstall () {
|
performInstall () {
|
||||||
const args = {}
|
const args = {}
|
||||||
for (const arg of this.form.args) {
|
for (const arg of this.form.args) {
|
||||||
if (arg.component === 'CheckboxItem') {
|
if (arg.component === 'CheckboxItem') {
|
||||||
|
|
Loading…
Add table
Reference in a new issue