mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
commit
218e544bbe
6 changed files with 129 additions and 53 deletions
|
@ -19,10 +19,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<slot v-if="!noFooter" name="buttons" slot="buttons">
|
<slot v-if="!noFooter" name="buttons" slot="buttons">
|
||||||
<b-button
|
<b-button type="submit" variant="success" :form="id">
|
||||||
type="submit" variant="success"
|
|
||||||
:form="id" :disabled="disabled"
|
|
||||||
>
|
|
||||||
{{ submitText ? submitText : $t('save') }}
|
{{ submitText ? submitText : $t('save') }}
|
||||||
</b-button>
|
</b-button>
|
||||||
</slot>
|
</slot>
|
||||||
|
@ -45,9 +42,6 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
disabled () {
|
|
||||||
return false // this.validation ? this.validation.$invalid : false
|
|
||||||
},
|
|
||||||
errorFeedback () {
|
errorFeedback () {
|
||||||
if (this.serverError) return this.serverError
|
if (this.serverError) return this.serverError
|
||||||
else if (this.validation && this.validation.$anyError) {
|
else if (this.validation && this.validation.$anyError) {
|
||||||
|
|
82
app/src/components/globals/TabForm.vue
Normal file
82
app/src/components/globals/TabForm.vue
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
<template>
|
||||||
|
<b-tab no-body>
|
||||||
|
<template #title>
|
||||||
|
<icon :iname="icon" /> {{ name }}
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<b-card-body>
|
||||||
|
<slot name="disclaimer" />
|
||||||
|
|
||||||
|
|
||||||
|
<b-form
|
||||||
|
:id="id" :inline="inline" :class="formClasses"
|
||||||
|
@submit.prevent="onSubmit" novalidate
|
||||||
|
>
|
||||||
|
<slot name="default" />
|
||||||
|
|
||||||
|
<slot name="server-error">
|
||||||
|
<b-alert
|
||||||
|
variant="danger" class="my-3" icon="ban"
|
||||||
|
:show="errorFeedback !== ''" v-html="errorFeedback"
|
||||||
|
/>
|
||||||
|
</slot>
|
||||||
|
</b-form>
|
||||||
|
</b-card-body>
|
||||||
|
|
||||||
|
<b-card-footer>
|
||||||
|
<b-button type="submit" variant="success" :form="id">
|
||||||
|
{{ submitText ? submitText : $t('save') }}
|
||||||
|
</b-button>
|
||||||
|
</b-card-footer>
|
||||||
|
</b-tab>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'TabForm',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
id: { type: String, default: 'ynh-form' },
|
||||||
|
submitText: { type: String, default: null },
|
||||||
|
validation: { type: Object, default: null },
|
||||||
|
serverError: { type: String, default: '' },
|
||||||
|
inline: { type: Boolean, default: false },
|
||||||
|
formClasses: { type: [Array, String, Object], default: null },
|
||||||
|
name: { type: String, required: true },
|
||||||
|
icon: { type: String, default: 'wrench' }
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
errorFeedback () {
|
||||||
|
if (this.serverError) return this.serverError
|
||||||
|
else if (this.validation && this.validation.$anyError) {
|
||||||
|
return this.$i18n.t('form_errors.invalid_form')
|
||||||
|
} else return ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onSubmit (e) {
|
||||||
|
const v = this.validation
|
||||||
|
if (v) {
|
||||||
|
v.$touch()
|
||||||
|
if (v.$pending || v.$invalid) return
|
||||||
|
}
|
||||||
|
this.$emit('submit', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.card-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
& > *:not(:first-child) {
|
||||||
|
margin-left: .5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -47,28 +47,29 @@ export default {
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
#top-bar {
|
#top-bar {
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 1rem;
|
||||||
flex-wrap: wrap-reverse;
|
flex-wrap: wrap-reverse;
|
||||||
|
|
||||||
.top-bar-group {
|
.top-bar-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-down(xs) {
|
@include media-breakpoint-down(xs) {
|
||||||
.top-bar-group {
|
.top-bar-group {
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep .btn:not(:first-of-type) {
|
|
||||||
margin-bottom: .25rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
@include media-breakpoint-down(sm) {
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
|
|
||||||
#top-bar-left ~ #top-bar-right {
|
#top-bar-right {
|
||||||
margin-bottom: 1rem;
|
margin-bottom: .75rem;
|
||||||
|
|
||||||
|
::v-deep > * {
|
||||||
|
margin-bottom: .25rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-bar-group {
|
.top-bar-group {
|
||||||
|
|
|
@ -63,3 +63,13 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
::v-deep .custom-file-label {
|
||||||
|
color: $input-placeholder-color;
|
||||||
|
|
||||||
|
.btn-danger + .b-form-file & {
|
||||||
|
color: $input-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -218,8 +218,7 @@ export function formatYunoHostArgument (arg) {
|
||||||
validation.required = validators.required
|
validation.required = validators.required
|
||||||
}
|
}
|
||||||
if (arg.pattern && arg.type !== 'tags') {
|
if (arg.pattern && arg.type !== 'tags') {
|
||||||
// validation.pattern = validators.helpers.withMessage(arg.pattern.error,
|
validation.pattern = validators.helpers.regex(formatI18nField(arg.pattern.error), new RegExp(arg.pattern.regexp))
|
||||||
validation.pattern = validators.helpers.regex(arg.pattern.error, new RegExp(arg.pattern.regexp))
|
|
||||||
}
|
}
|
||||||
validation.remote = validators.helpers.withParams(error, (v) => {
|
validation.remote = validators.helpers.withParams(error, (v) => {
|
||||||
const result = !error.message
|
const result = !error.message
|
||||||
|
|
|
@ -1,41 +1,32 @@
|
||||||
<template>
|
<template>
|
||||||
<view-base :queries="queries" @queries-response="onQueriesResponse" skeleton="card-form-skeleton">
|
<view-base :queries="queries" @queries-response="onQueriesResponse" skeleton="card-form-skeleton">
|
||||||
<template v-if="panels" #default>
|
<b-card v-if="panels" no-body>
|
||||||
<b-tabs pills card vertical>
|
<b-tabs fill pills card>
|
||||||
<b-tab v-for="{ name, id: id_, sections, help, serverError } in panels"
|
<tab-form
|
||||||
:key="id_"
|
v-for="{ name, id: id_, sections, help, serverError } in panels" :key="id_"
|
||||||
:title="name"
|
v-bind="{ name, id: id_ + '-form', validation: $v.forms[id_], serverError }"
|
||||||
>
|
|
||||||
<template #title>
|
|
||||||
<icon iname="wrench" /> {{ name }}
|
|
||||||
</template>
|
|
||||||
<card-form
|
|
||||||
:key="id_"
|
|
||||||
:title="name" icon="wrench" title-tag="h2"
|
|
||||||
:validation="$v.forms[id_]" :id="id_ + '-form'" :server-error="serverError"
|
|
||||||
@submit.prevent="applyConfig(id_)"
|
|
||||||
>
|
>
|
||||||
<template v-if="help" #disclaimer>
|
<template v-if="help" #disclaimer>
|
||||||
<div class="alert alert-info" v-html="help" />
|
<div class="alert alert-info" v-html="help" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-for="section in sections">
|
<template v-for="section in sections">
|
||||||
<div :key="section.id" class="mb-5" v-if="isVisible(section.visible, section)">
|
<div v-if="isVisible(section.visible, section)" :key="section.id" class="mb-5">
|
||||||
<b-card-title v-if="section.name" title-tag="h3">
|
<b-card-title v-if="section.name" title-tag="h3">
|
||||||
{{ section.name }} <small v-if="section.help">{{ section.help }}</small>
|
{{ section.name }} <small v-if="section.help">{{ section.help }}</small>
|
||||||
</b-card-title>
|
</b-card-title>
|
||||||
|
|
||||||
<template v-for="(field, fname) in section.fields">
|
<template v-for="(field, fname) in section.fields">
|
||||||
<form-field :key="fname" v-model="forms[id_][fname]"
|
<form-field
|
||||||
:validation="$v.forms[id_][fname]"
|
v-if="isVisible(field.visible, field)" :key="fname"
|
||||||
v-if="isVisible(field.visible, field)" v-bind="field"
|
v-model="forms[id_][fname]" v-bind="field" :validation="$v.forms[id_][fname]"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</card-form>
|
</tab-form>
|
||||||
</b-tab>
|
|
||||||
</b-tabs>
|
</b-tabs>
|
||||||
</template>
|
</b-card>
|
||||||
|
|
||||||
<!-- if no config panel -->
|
<!-- if no config panel -->
|
||||||
<b-alert v-else-if="panels === null" variant="warning">
|
<b-alert v-else-if="panels === null" variant="warning">
|
||||||
|
@ -117,6 +108,7 @@ export default {
|
||||||
// This value should be updated magically when vuejs will detect isVisible changed
|
// This value should be updated magically when vuejs will detect isVisible changed
|
||||||
return field.isVisible
|
return field.isVisible
|
||||||
},
|
},
|
||||||
|
|
||||||
onQueriesResponse (data) {
|
onQueriesResponse (data) {
|
||||||
if (!data.panels || data.panels.length === 0) {
|
if (!data.panels || data.panels.length === 0) {
|
||||||
this.panels = null
|
this.panels = null
|
||||||
|
@ -182,12 +174,10 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
|
||||||
h3.card-title {
|
<style lang="scss" scoped>
|
||||||
|
h3 {
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
border-bottom: solid 1px #aaa;
|
border-bottom: solid 1px #aaa;
|
||||||
}
|
}
|
||||||
.form-control::placeholder, .form-file-text {
|
|
||||||
color: #6d7780;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Add table
Reference in a new issue