add AppActions view/route

This commit is contained in:
Axolotle 2020-10-07 20:44:11 +02:00
parent b1b9e65b7b
commit a12dc45229
5 changed files with 174 additions and 20 deletions

View file

@ -1,7 +1,7 @@
import i18n from '@/i18n'
import store from '@/store'
function formatI18nField (field) {
export function formatI18nField (field) {
if (typeof field === 'string') return field
const { locale, fallbackLocale } = store.state
return field[locale] || field[fallbackLocale] || field.en

View file

@ -165,18 +165,6 @@ const routes = [
component: () => import(/* webpackChunkName: "views/apps" */ '@/views/app/AppList'),
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',
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

View file

@ -76,15 +76,24 @@ body {
.card + .card {
margin-top: 2rem;
}
.card-header h2 {
margin: 0;
font-size: 1.75rem;
.card-header {
h2, h4 {
margin: 0;
}
h2 {
font-size: 1.75rem;
}
}
.card-body {
padding: 1rem;
}
.card-footer {
display: flex;
}
// collapse icon
.not-collapsed > .icon {
transform: rotate(-90deg);

View 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>

View file

@ -32,12 +32,13 @@
<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">
{{ this.server.error }}
{{ server.error }}
</b-form-invalid-feedback>
</b-form>
<template v-slot:footer>
<b-button
class="ml-auto"
type="submit" form="install-form"
variant="success" v-t="'install'"
/>
@ -48,7 +49,7 @@
<b-modal
id="confirm-domain-root-modal" ref="confirm-domain-root-modal" centered
body-bg-variant="danger" body-text-variant="light"
@ok="runInstall" hide-header
@ok="performInstall" hide-header
:ok-title="$t('install')"
>
{{ $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.$refs['confirm-domain-root-modal'].show()
} else {
this.runInstall()
this.performInstall()
}
},
runInstall () {
performInstall () {
const args = {}
for (const arg of this.form.args) {
if (arg.component === 'CheckboxItem') {