mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
refactor: upgrade to vuelidate2
This commit is contained in:
parent
81707bb11a
commit
c5976dbd48
21 changed files with 246 additions and 177 deletions
|
@ -16,6 +16,8 @@
|
||||||
"@fontsource/fira-code": "^4.5.13",
|
"@fontsource/fira-code": "^4.5.13",
|
||||||
"@fontsource/firago": "^4.5.3",
|
"@fontsource/firago": "^4.5.3",
|
||||||
"@vue/compat": "3.3.4",
|
"@vue/compat": "3.3.4",
|
||||||
|
"@vuelidate/core": "^2.0.3",
|
||||||
|
"@vuelidate/validators": "^2.0.4",
|
||||||
"bootstrap-vue": "^2.22.0",
|
"bootstrap-vue": "^2.22.0",
|
||||||
"date-fns": "^2.29.3",
|
"date-fns": "^2.29.3",
|
||||||
"fork-awesome": "^1.2.0",
|
"fork-awesome": "^1.2.0",
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<RoutableTabs
|
<RoutableTabs
|
||||||
v-if="routes_.length > 1"
|
v-if="routes_.length > 1"
|
||||||
:routes="routes_"
|
:routes="routes_"
|
||||||
v-bind="{ panels, forms, v: $v, ...$attrs }"
|
v-bind="{ panels, forms, v: v$, ...$attrs }"
|
||||||
v-on="$listeners"
|
v-on="$listeners"
|
||||||
>
|
>
|
||||||
<template #tab-top>
|
<template #tab-top>
|
||||||
|
@ -26,7 +26,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { validationMixin } from 'vuelidate'
|
import { toRef } from 'vue'
|
||||||
|
import { useVuelidate } from '@vuelidate/core'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ConfigPanels',
|
name: 'ConfigPanels',
|
||||||
|
@ -37,8 +38,6 @@ export default {
|
||||||
RoutableTabs: () => import('@/components/RoutableTabs.vue'),
|
RoutableTabs: () => import('@/components/RoutableTabs.vue'),
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [validationMixin],
|
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
panels: { type: Array, default: undefined },
|
panels: { type: Array, default: undefined },
|
||||||
forms: { type: Object, default: undefined },
|
forms: { type: Object, default: undefined },
|
||||||
|
@ -46,6 +45,14 @@ export default {
|
||||||
errors: { type: Object, default: undefined }, // never used
|
errors: { type: Object, default: undefined }, // never used
|
||||||
routes: { type: Array, default: null },
|
routes: { type: Array, default: null },
|
||||||
noRedirect: { type: Boolean, default: false },
|
noRedirect: { type: Boolean, default: false },
|
||||||
|
externalResults: { type: Object, required: true },
|
||||||
|
},
|
||||||
|
|
||||||
|
setup(props) {
|
||||||
|
const externalResults = toRef(props, 'externalResults')
|
||||||
|
return {
|
||||||
|
v$: useVuelidate({ $externalResults: externalResults, $autoDirty: true }),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
|
|
@ -47,7 +47,7 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
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.$errors.length) {
|
||||||
return this.$i18n.t('form_errors.invalid_form')
|
return this.$i18n.t('form_errors.invalid_form')
|
||||||
} else return ''
|
} else return ''
|
||||||
},
|
},
|
||||||
|
@ -58,7 +58,7 @@ export default {
|
||||||
const v = this.validation
|
const v = this.validation
|
||||||
if (v) {
|
if (v) {
|
||||||
v.$touch()
|
v.$touch()
|
||||||
if (v.$pending || v.$invalid) return
|
if (v.$pending || v.$errors.length) return
|
||||||
}
|
}
|
||||||
this.$emit('submit', e)
|
this.$emit('submit', e)
|
||||||
},
|
},
|
||||||
|
|
|
@ -52,7 +52,7 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
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.$errors.length) {
|
||||||
return this.$i18n.t('form_errors.invalid_form')
|
return this.$i18n.t('form_errors.invalid_form')
|
||||||
} else return ''
|
} else return ''
|
||||||
},
|
},
|
||||||
|
|
|
@ -65,6 +65,7 @@ export default {
|
||||||
value: { type: null, default: null },
|
value: { type: null, default: null },
|
||||||
props: { type: Object, default: () => ({}) },
|
props: { type: Object, default: () => ({}) },
|
||||||
validation: { type: Object, default: null },
|
validation: { type: Object, default: null },
|
||||||
|
validationIndex: { type: Number, default: null },
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -93,19 +94,36 @@ export default {
|
||||||
return attrs
|
return attrs
|
||||||
},
|
},
|
||||||
|
|
||||||
state() {
|
error() {
|
||||||
// Need to set state as null if no error, else component turn green
|
|
||||||
if (this.validation) {
|
if (this.validation) {
|
||||||
return this.validation.$anyError === true ? false : null
|
if (this.validationIndex !== null) {
|
||||||
|
const errors =
|
||||||
|
this.validation.$each.$response.$errors[this.validationIndex]
|
||||||
|
const err = Object.values(errors).find((part) => {
|
||||||
|
return part.length
|
||||||
|
})
|
||||||
|
return err?.length ? err[0] : null
|
||||||
|
}
|
||||||
|
return this.validation.$errors.length
|
||||||
|
? { ...this.validation.$errors[0], $model: this.validation.$model }
|
||||||
|
: null
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
|
|
||||||
|
state() {
|
||||||
|
// Need to set state as null if no error, else component turn green
|
||||||
|
return this.error ? false : null
|
||||||
|
},
|
||||||
|
|
||||||
errorMessage() {
|
errorMessage() {
|
||||||
const validation = this.validation
|
const err = this.error
|
||||||
if (validation && validation.$anyError) {
|
if (err) {
|
||||||
const [type, errData] = this.findError(validation.$params, validation)
|
if (err.$message) return err.$message
|
||||||
return this.$i18n.t('form_errors.' + type, errData)
|
return this.$i18n.t('form_errors.' + err.$validator, {
|
||||||
|
value: err.$model,
|
||||||
|
...err.$params,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
},
|
},
|
||||||
|
@ -122,17 +140,6 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
findError(params, obj, parent = obj) {
|
|
||||||
for (const key in params) {
|
|
||||||
if (!obj[key]) {
|
|
||||||
return [key, obj.$params[key]]
|
|
||||||
}
|
|
||||||
if (obj[key].$anyError) {
|
|
||||||
return this.findError(obj[key].$params, obj[key], parent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,70 +1,61 @@
|
||||||
import { helpers } from 'vuelidate/lib/validators'
|
import { helpers } from '@vuelidate/validators'
|
||||||
|
|
||||||
// Unicode ranges are taken from https://stackoverflow.com/a/37668315
|
// Unicode ranges are taken from https://stackoverflow.com/a/37668315
|
||||||
const nonAsciiWordCharacters =
|
const nonAsciiWordCharacters =
|
||||||
'\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC'
|
'\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC'
|
||||||
|
|
||||||
const alphalownumdot_ = helpers.regex('alphalownumdot_', /^[a-z0-9_.]+$/)
|
const alphalownumdot_ = helpers.regex(/^[a-z0-9_.]+$/)
|
||||||
|
|
||||||
const domain = helpers.regex(
|
const domain = helpers.regex(
|
||||||
'domain',
|
|
||||||
new RegExp(
|
new RegExp(
|
||||||
`^(?:[\\da-z${nonAsciiWordCharacters}]+(?:-*[\\da-z${nonAsciiWordCharacters}]+)*\\.)+(?:(?:xn--)?[\\da-z${nonAsciiWordCharacters}]{2,})$`,
|
`^(?:[\\da-z${nonAsciiWordCharacters}]+(?:-*[\\da-z${nonAsciiWordCharacters}]+)*\\.)+(?:(?:xn--)?[\\da-z${nonAsciiWordCharacters}]{2,})$`,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
const dynDomain = helpers.regex(
|
const dynDomain = helpers.regex(
|
||||||
'dynDomain',
|
|
||||||
new RegExp(`^(?:xn--)?[\\da-z-${nonAsciiWordCharacters}]+$`),
|
new RegExp(`^(?:xn--)?[\\da-z-${nonAsciiWordCharacters}]+$`),
|
||||||
)
|
)
|
||||||
|
|
||||||
const emailLocalPart = helpers.regex('emailLocalPart', /^[\w.-]+$/)
|
const emailLocalPart = helpers.regex(/^[\w.-]+$/)
|
||||||
|
|
||||||
const emailForwardLocalPart = helpers.regex(
|
const emailForwardLocalPart = helpers.regex(/^[\w+.-]+$/)
|
||||||
'emailForwardLocalPart',
|
|
||||||
/^[\w+.-]+$/,
|
|
||||||
)
|
|
||||||
|
|
||||||
const email = (value) =>
|
const email = (value) => {
|
||||||
helpers.withParams({ type: 'email', value }, (value) => {
|
|
||||||
const [localPart, domainPart] = value.split('@')
|
const [localPart, domainPart] = value.split('@')
|
||||||
if (!domainPart) return !helpers.req(value) || false
|
if (!domainPart) return !helpers.req(value) || false
|
||||||
return (
|
return (
|
||||||
!helpers.req(value) || (emailLocalPart(localPart) && domain(domainPart))
|
!helpers.req(value) || (emailLocalPart(localPart) && domain(domainPart))
|
||||||
)
|
)
|
||||||
})(value)
|
}
|
||||||
|
|
||||||
// Same as email but with `+` allowed.
|
// Same as email but with `+` allowed.
|
||||||
const emailForward = (value) =>
|
const emailForward = (value) => {
|
||||||
helpers.withParams({ type: 'emailForward', value }, (value) => {
|
|
||||||
const [localPart, domainPart] = value.split('@')
|
const [localPart, domainPart] = value.split('@')
|
||||||
if (!domainPart) return !helpers.req(value) || false
|
if (!domainPart) return !helpers.req(value) || false
|
||||||
return (
|
return (
|
||||||
!helpers.req(value) ||
|
!helpers.req(value) ||
|
||||||
(emailForwardLocalPart(localPart) && domain(domainPart))
|
(emailForwardLocalPart(localPart) && domain(domainPart))
|
||||||
)
|
)
|
||||||
})(value)
|
}
|
||||||
|
|
||||||
const appRepoUrl = helpers.regex(
|
const appRepoUrl = helpers.regex(
|
||||||
'appRepoUrl',
|
|
||||||
/^https:\/\/[a-zA-Z0-9-_.]+\/[a-zA-Z0-9-_./~]+\/[a-zA-Z0-9-_.]+_ynh(\/?(-\/)?tree\/[a-zA-Z0-9-_.]+)?(\.git)?\/?$/,
|
/^https:\/\/[a-zA-Z0-9-_.]+\/[a-zA-Z0-9-_./~]+\/[a-zA-Z0-9-_.]+_ynh(\/?(-\/)?tree\/[a-zA-Z0-9-_.]+)?(\.git)?\/?$/,
|
||||||
)
|
)
|
||||||
|
|
||||||
const includes = (items) => (item) =>
|
const includes = (items) =>
|
||||||
helpers.withParams(
|
helpers.withParams(
|
||||||
{ type: 'includes', value: item },
|
{ type: 'includes' },
|
||||||
(item) => !helpers.req(item) || (items ? items.includes(item) : false),
|
(item) => !helpers.req(item) || (items ? items.includes(item) : false),
|
||||||
)(item)
|
)
|
||||||
|
|
||||||
const name = helpers.regex(
|
const name = helpers.regex(
|
||||||
'name',
|
|
||||||
new RegExp(`^(?:[A-Za-z${nonAsciiWordCharacters}]{1,30}[ ,.'-]{0,3})+$`),
|
new RegExp(`^(?:[A-Za-z${nonAsciiWordCharacters}]{1,30}[ ,.'-]{0,3})+$`),
|
||||||
)
|
)
|
||||||
|
|
||||||
const unique = (items) => (item) =>
|
const unique = (items) =>
|
||||||
helpers.withParams({ type: 'unique', arg: items, value: item }, (item) =>
|
helpers.withParams({ type: 'unique', arg: items }, (item) =>
|
||||||
items ? !helpers.req(item) || !items.includes(item) : true,
|
items ? !helpers.req(item) || !items.includes(item) : true,
|
||||||
)(item)
|
)
|
||||||
|
|
||||||
export {
|
export {
|
||||||
alphalownumdot_,
|
alphalownumdot_,
|
||||||
|
|
|
@ -9,4 +9,4 @@ export {
|
||||||
minValue,
|
minValue,
|
||||||
required,
|
required,
|
||||||
sameAs,
|
sameAs,
|
||||||
} from 'vuelidate/lib/validators'
|
} from '@vuelidate/validators'
|
||||||
|
|
|
@ -121,8 +121,7 @@ function addEvaluationGetter(prop, obj, expr, ctx, nested) {
|
||||||
*/
|
*/
|
||||||
export function formatYunoHostArgument(arg) {
|
export function formatYunoHostArgument(arg) {
|
||||||
let value = arg.value !== undefined ? arg.value : null
|
let value = arg.value !== undefined ? arg.value : null
|
||||||
const validation = {}
|
let validation = {}
|
||||||
const error = { message: null }
|
|
||||||
arg.ask = formatI18nField(arg.ask)
|
arg.ask = formatI18nField(arg.ask)
|
||||||
const field = {
|
const field = {
|
||||||
is: arg.readonly ? 'ReadOnlyField' : 'FormField',
|
is: arg.readonly ? 'ReadOnlyField' : 'FormField',
|
||||||
|
@ -272,6 +271,9 @@ export function formatYunoHostArgument(arg) {
|
||||||
]
|
]
|
||||||
|
|
||||||
// Default type management if no one is filled
|
// Default type management if no one is filled
|
||||||
|
if (arg.type !== 'tags' && arg.choices && arg.choices.length) {
|
||||||
|
arg.type = 'select'
|
||||||
|
}
|
||||||
if (arg.type === undefined) {
|
if (arg.type === undefined) {
|
||||||
if (arg.choices && arg.choices.length) {
|
if (arg.choices && arg.choices.length) {
|
||||||
arg.type = 'select'
|
arg.type = 'select'
|
||||||
|
@ -308,21 +310,12 @@ 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.regex(
|
validation.pattern = validators.helpers.withMessage(
|
||||||
formatI18nField(arg.pattern.error),
|
formatI18nField(arg.pattern.error),
|
||||||
new RegExp(arg.pattern.regexp),
|
validators.helpers.regex(new RegExp(arg.pattern.regexp)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!component.renderSelf && !arg.readonly) {
|
|
||||||
// Bind a validation with what the server may respond
|
|
||||||
validation.remote = validators.helpers.withParams(error, (v) => {
|
|
||||||
const result = !error.message
|
|
||||||
error.message = null
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default value if still `null`
|
// Default value if still `null`
|
||||||
if (value === null && arg.default) {
|
if (value === null && arg.default) {
|
||||||
value = arg.default
|
value = arg.default
|
||||||
|
@ -351,7 +344,6 @@ export function formatYunoHostArgument(arg) {
|
||||||
field,
|
field,
|
||||||
// Return null instead of empty object if there's no validation
|
// Return null instead of empty object if there's no validation
|
||||||
validation: Object.keys(validation).length === 0 ? null : validation,
|
validation: Object.keys(validation).length === 0 ? null : validation,
|
||||||
error,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,14 +359,12 @@ export function formatYunoHostArguments(args, forms) {
|
||||||
const form = {}
|
const form = {}
|
||||||
const fields = {}
|
const fields = {}
|
||||||
const validations = {}
|
const validations = {}
|
||||||
const errors = {}
|
|
||||||
|
|
||||||
for (const arg of args) {
|
for (const arg of args) {
|
||||||
const { value, field, validation, error } = formatYunoHostArgument(arg)
|
const { value, field, validation } = formatYunoHostArgument(arg)
|
||||||
fields[arg.id] = field
|
fields[arg.id] = field
|
||||||
form[arg.id] = value
|
form[arg.id] = value
|
||||||
if (validation) validations[arg.id] = validation
|
if (validation) validations[arg.id] = validation
|
||||||
errors[arg.id] = error
|
|
||||||
|
|
||||||
if ('visible' in arg && typeof arg.visible === 'string') {
|
if ('visible' in arg && typeof arg.visible === 'string') {
|
||||||
addEvaluationGetter(
|
addEvaluationGetter(
|
||||||
|
@ -397,7 +387,7 @@ export function formatYunoHostArguments(args, forms) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { form, fields, validations, errors }
|
return { form, fields, validations }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatYunoHostConfigPanels(data) {
|
export function formatYunoHostConfigPanels(data) {
|
||||||
|
@ -405,7 +395,6 @@ export function formatYunoHostConfigPanels(data) {
|
||||||
panels: [],
|
panels: [],
|
||||||
forms: {},
|
forms: {},
|
||||||
validations: {},
|
validations: {},
|
||||||
errors: {},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const { id: panelId, name, help, sections } of data.panels) {
|
for (const { id: panelId, name, help, sections } of data.panels) {
|
||||||
|
@ -417,7 +406,6 @@ export function formatYunoHostConfigPanels(data) {
|
||||||
}
|
}
|
||||||
result.forms[panelId] = {}
|
result.forms[panelId] = {}
|
||||||
result.validations[panelId] = {}
|
result.validations[panelId] = {}
|
||||||
result.errors[panelId] = {}
|
|
||||||
|
|
||||||
if (name) panel.name = formatI18nField(name)
|
if (name) panel.name = formatI18nField(name)
|
||||||
if (help) panel.help = formatI18nField(help)
|
if (help) panel.help = formatI18nField(help)
|
||||||
|
@ -434,14 +422,13 @@ export function formatYunoHostConfigPanels(data) {
|
||||||
addEvaluationGetter('visible', section, section.visible, result.forms)
|
addEvaluationGetter('visible', section, section.visible, result.forms)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { form, fields, validations, errors } = formatYunoHostArguments(
|
const { form, fields, validations } = formatYunoHostArguments(
|
||||||
_section.options,
|
_section.options,
|
||||||
result.forms,
|
result.forms,
|
||||||
)
|
)
|
||||||
// Merge all sections forms to the panel to get a unique form
|
// Merge all sections forms to the panel to get a unique form
|
||||||
Object.assign(result.forms[panelId], form)
|
Object.assign(result.forms[panelId], form)
|
||||||
Object.assign(result.validations[panelId], validations)
|
Object.assign(result.validations[panelId], validations)
|
||||||
Object.assign(result.errors[panelId], errors)
|
|
||||||
section.fields = fields
|
section.fields = fields
|
||||||
panel.sections.push(section)
|
panel.sections.push(section)
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<CardForm
|
<CardForm
|
||||||
:title="$t('login')"
|
:title="$t('login')"
|
||||||
icon="lock"
|
icon="lock"
|
||||||
:validation="$v"
|
:validation="v$"
|
||||||
:server-error="serverError"
|
:server-error="serverError"
|
||||||
@submit.prevent="login"
|
@submit.prevent="login"
|
||||||
>
|
>
|
||||||
|
@ -10,14 +10,14 @@
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.username"
|
v-bind="fields.username"
|
||||||
v-model="form.username"
|
v-model="form.username"
|
||||||
:validation="$v.form.username"
|
:validation="v$.form.username"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- ADMIN PASSWORD -->
|
<!-- ADMIN PASSWORD -->
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.password"
|
v-bind="fields.password"
|
||||||
v-model="form.password"
|
v-model="form.password"
|
||||||
:validation="$v.form.password"
|
:validation="v$.form.password"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<template #buttons>
|
<template #buttons>
|
||||||
|
@ -35,18 +35,22 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import { validationMixin } from 'vuelidate'
|
import { useVuelidate } from '@vuelidate/core'
|
||||||
import { alphalownumdot_, required, minLength } from '@/helpers/validators'
|
import { alphalownumdot_, required, minLength } from '@/helpers/validators'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'LoginView',
|
name: 'LoginView',
|
||||||
|
|
||||||
mixins: [validationMixin],
|
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
forceReload: { type: Boolean, default: false },
|
forceReload: { type: Boolean, default: false },
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
v$: useVuelidate(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
serverError: '',
|
serverError: '',
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
<CardForm
|
<CardForm
|
||||||
:title="$t('postinstall.user.title')"
|
:title="$t('postinstall.user.title')"
|
||||||
icon="user-plus"
|
icon="user-plus"
|
||||||
:validation="$v"
|
:validation="v$"
|
||||||
:server-error="serverError"
|
:server-error="serverError"
|
||||||
:submit-text="$t('next')"
|
:submit-text="$t('next')"
|
||||||
@submit.prevent="setUser"
|
@submit.prevent="setUser"
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
:key="name"
|
:key="name"
|
||||||
v-bind="field"
|
v-bind="field"
|
||||||
v-model="user[name]"
|
v-model="user[name]"
|
||||||
:validation="$v.user[name]"
|
:validation="v$.user[name]"
|
||||||
/>
|
/>
|
||||||
</CardForm>
|
</CardForm>
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { validationMixin } from 'vuelidate'
|
import { useVuelidate } from '@vuelidate/core'
|
||||||
|
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { DomainForm } from '@/views/_partials'
|
import { DomainForm } from '@/views/_partials'
|
||||||
|
@ -106,13 +106,17 @@ import {
|
||||||
export default {
|
export default {
|
||||||
name: 'PostInstall',
|
name: 'PostInstall',
|
||||||
|
|
||||||
mixins: [validationMixin],
|
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
DomainForm,
|
DomainForm,
|
||||||
LoginView,
|
LoginView,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
v$: useVuelidate(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
step: 'start',
|
step: 'start',
|
||||||
|
@ -224,7 +228,7 @@ export default {
|
||||||
username: { required, alphalownumdot_ },
|
username: { required, alphalownumdot_ },
|
||||||
fullname: { required, name },
|
fullname: { required, name },
|
||||||
password: { required, passwordLenght: minLength(8) },
|
password: { required, passwordLenght: minLength(8) },
|
||||||
confirmation: { required, passwordMatch: sameAs('password') },
|
confirmation: { required, passwordMatch: sameAs(this.user.password) },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
:title="title"
|
:title="title"
|
||||||
icon="globe"
|
icon="globe"
|
||||||
:submit-text="submitText"
|
:submit-text="submitText"
|
||||||
:validation="$v"
|
:validation="v$"
|
||||||
:server-error="serverError"
|
:server-error="serverError"
|
||||||
@submit.prevent="onSubmit"
|
@submit.prevent="onSubmit"
|
||||||
>
|
>
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.domain"
|
v-bind="fields.domain"
|
||||||
v-model="form.domain"
|
v-model="form.domain"
|
||||||
:validation="$v.form.domain"
|
:validation="v$.form.domain"
|
||||||
class="mt-3"
|
class="mt-3"
|
||||||
/>
|
/>
|
||||||
</BCollapse>
|
</BCollapse>
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.dynDomain"
|
v-bind="fields.dynDomain"
|
||||||
:validation="$v.form.dynDomain"
|
:validation="v$.form.dynDomain"
|
||||||
class="mt-3"
|
class="mt-3"
|
||||||
>
|
>
|
||||||
<template #default="{ self }">
|
<template #default="{ self }">
|
||||||
|
@ -68,13 +68,13 @@
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.dynDomainPassword"
|
v-bind="fields.dynDomainPassword"
|
||||||
:validation="$v.form.dynDomainPassword"
|
:validation="v$.form.dynDomainPassword"
|
||||||
v-model="form.dynDomainPassword"
|
v-model="form.dynDomainPassword"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.dynDomainPasswordConfirmation"
|
v-bind="fields.dynDomainPasswordConfirmation"
|
||||||
:validation="$v.form.dynDomainPasswordConfirmation"
|
:validation="v$.form.dynDomainPasswordConfirmation"
|
||||||
v-model="form.dynDomainPasswordConfirmation"
|
v-model="form.dynDomainPasswordConfirmation"
|
||||||
/>
|
/>
|
||||||
</BCollapse>
|
</BCollapse>
|
||||||
|
@ -103,7 +103,7 @@
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.localDomain"
|
v-bind="fields.localDomain"
|
||||||
:validation="$v.form.localDomain"
|
:validation="v$.form.localDomain"
|
||||||
class="mt-3"
|
class="mt-3"
|
||||||
>
|
>
|
||||||
<template #default="{ self }">
|
<template #default="{ self }">
|
||||||
|
@ -116,7 +116,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import { validationMixin } from 'vuelidate'
|
import { useVuelidate } from '@vuelidate/core'
|
||||||
|
|
||||||
import AdressInputSelect from '@/components/AdressInputSelect.vue'
|
import AdressInputSelect from '@/components/AdressInputSelect.vue'
|
||||||
import { formatFormData } from '@/helpers/yunohostArguments'
|
import { formatFormData } from '@/helpers/yunohostArguments'
|
||||||
|
@ -137,6 +137,12 @@ export default {
|
||||||
serverError: { type: String, default: '' },
|
serverError: { type: String, default: '' },
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
v$: useVuelidate(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selected: '',
|
selected: '',
|
||||||
|
@ -262,8 +268,6 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [validationMixin],
|
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
AdressInputSelect,
|
AdressInputSelect,
|
||||||
},
|
},
|
||||||
|
|
|
@ -171,7 +171,7 @@
|
||||||
icon="download"
|
icon="download"
|
||||||
@submit.prevent="onCustomInstallClick"
|
@submit.prevent="onCustomInstallClick"
|
||||||
:submit-text="$t('install')"
|
:submit-text="$t('install')"
|
||||||
:validation="$v"
|
:validation="v$"
|
||||||
class="mt-5"
|
class="mt-5"
|
||||||
>
|
>
|
||||||
<template #disclaimer>
|
<template #disclaimer>
|
||||||
|
@ -185,7 +185,7 @@
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="customInstall.field"
|
v-bind="customInstall.field"
|
||||||
v-model="customInstall.url"
|
v-model="customInstall.url"
|
||||||
:validation="$v.customInstall.url"
|
:validation="v$.customInstall.url"
|
||||||
/>
|
/>
|
||||||
</CardForm>
|
</CardForm>
|
||||||
</template>
|
</template>
|
||||||
|
@ -220,7 +220,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { validationMixin } from 'vuelidate'
|
import { useVuelidate } from '@vuelidate/core'
|
||||||
|
|
||||||
import CardDeckFeed from '@/components/CardDeckFeed.vue'
|
import CardDeckFeed from '@/components/CardDeckFeed.vue'
|
||||||
import { required, appRepoUrl } from '@/helpers/validators'
|
import { required, appRepoUrl } from '@/helpers/validators'
|
||||||
|
@ -240,6 +240,12 @@ export default {
|
||||||
subtag: { type: String, default: 'all' },
|
subtag: { type: String, default: 'all' },
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
v$: useVuelidate(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
queries: [['GET', 'apps/catalog?full&with_categories&with_antifeatures']],
|
queries: [['GET', 'apps/catalog?full&with_categories&with_antifeatures']],
|
||||||
|
@ -421,8 +427,6 @@ export default {
|
||||||
|
|
||||||
randint,
|
randint,
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [validationMixin],
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,11 @@
|
||||||
</YAlert>
|
</YAlert>
|
||||||
|
|
||||||
<!-- BASIC INFOS -->
|
<!-- BASIC INFOS -->
|
||||||
<ConfigPanels v-bind="config" @submit="onConfigSubmit">
|
<ConfigPanels
|
||||||
|
v-bind="config"
|
||||||
|
:external-results="externalResults"
|
||||||
|
@submit="onConfigSubmit"
|
||||||
|
>
|
||||||
<!-- OPERATIONS TAB -->
|
<!-- OPERATIONS TAB -->
|
||||||
<template v-if="currentTab === 'operations'" #tab-top>
|
<template v-if="currentTab === 'operations'" #tab-top>
|
||||||
<!-- CHANGE PERMISSIONS LABEL -->
|
<!-- CHANGE PERMISSIONS LABEL -->
|
||||||
|
@ -144,7 +148,7 @@
|
||||||
label-cols="0"
|
label-cols="0"
|
||||||
label-class=""
|
label-class=""
|
||||||
class="m-0"
|
class="m-0"
|
||||||
:validation="$v.form.labels.$each[i]"
|
:validation="v$.form.labels.$each[i]"
|
||||||
>
|
>
|
||||||
<template #default="{ self }">
|
<template #default="{ self }">
|
||||||
<BInputGroup>
|
<BInputGroup>
|
||||||
|
@ -361,11 +365,11 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import { validationMixin } from 'vuelidate'
|
import { useVuelidate } from '@vuelidate/core'
|
||||||
|
|
||||||
import api, { objectToParams } from '@/api'
|
import api, { objectToParams } from '@/api'
|
||||||
import { humanPermissionName } from '@/helpers/filters/human'
|
import { humanPermissionName } from '@/helpers/filters/human'
|
||||||
import { required } from '@/helpers/validators'
|
import { helpers, required } from '@/helpers/validators'
|
||||||
import { isEmptyValue } from '@/helpers/commons'
|
import { isEmptyValue } from '@/helpers/commons'
|
||||||
import {
|
import {
|
||||||
formatFormData,
|
formatFormData,
|
||||||
|
@ -385,6 +389,12 @@ export default {
|
||||||
id: { type: String, required: true },
|
id: { type: String, required: true },
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
v$: useVuelidate(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
queries: [
|
queries: [
|
||||||
|
@ -408,6 +418,7 @@ export default {
|
||||||
],
|
],
|
||||||
validations: {},
|
validations: {},
|
||||||
},
|
},
|
||||||
|
externalResults: {},
|
||||||
doc: undefined,
|
doc: undefined,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -429,7 +440,9 @@ export default {
|
||||||
return {
|
return {
|
||||||
form: {
|
form: {
|
||||||
labels: {
|
labels: {
|
||||||
$each: { label: { required } },
|
$each: helpers.forEach({
|
||||||
|
label: { required },
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
url: { path: { required } },
|
url: { path: { required } },
|
||||||
},
|
},
|
||||||
|
@ -614,7 +627,9 @@ export default {
|
||||||
if (err.name !== 'APIBadRequestError') throw err
|
if (err.name !== 'APIBadRequestError') throw err
|
||||||
const panel = this.config.panels.find((panel) => panel.id === id)
|
const panel = this.config.panels.find((panel) => panel.id === id)
|
||||||
if (err.data.name) {
|
if (err.data.name) {
|
||||||
this.config.errors[id][err.data.name].message = err.message
|
Object.assign(this.externalResults, {
|
||||||
|
forms: { [panel.id]: { [err.data.name]: [err.data.error] } },
|
||||||
|
})
|
||||||
} else this.$set(panel, 'serverError', err.message)
|
} else this.$set(panel, 'serverError', err.message)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -687,8 +702,6 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [validationMixin],
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -179,7 +179,7 @@
|
||||||
:title="$t('app_install_parameters')"
|
:title="$t('app_install_parameters')"
|
||||||
icon="cog"
|
icon="cog"
|
||||||
:submit-text="$t('install')"
|
:submit-text="$t('install')"
|
||||||
:validation="$v"
|
:validation="v$"
|
||||||
:server-error="serverError"
|
:server-error="serverError"
|
||||||
@submit.prevent="performInstall"
|
@submit.prevent="performInstall"
|
||||||
>
|
>
|
||||||
|
@ -189,7 +189,7 @@
|
||||||
:is="field.is"
|
:is="field.is"
|
||||||
v-bind="field.props"
|
v-bind="field.props"
|
||||||
v-model="form[fname]"
|
v-model="form[fname]"
|
||||||
:validation="$v.form[fname]"
|
:validation="v$.form[fname]"
|
||||||
:key="fname"
|
:key="fname"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
@ -210,7 +210,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { validationMixin } from 'vuelidate'
|
import { useVuelidate } from '@vuelidate/core'
|
||||||
|
|
||||||
import api, { objectToParams } from '@/api'
|
import api, { objectToParams } from '@/api'
|
||||||
import {
|
import {
|
||||||
|
@ -223,8 +223,6 @@ import CardCollapse from '@/components/CardCollapse.vue'
|
||||||
export default {
|
export default {
|
||||||
name: 'AppInstall',
|
name: 'AppInstall',
|
||||||
|
|
||||||
mixins: [validationMixin],
|
|
||||||
|
|
||||||
components: {
|
components: {
|
||||||
CardCollapse,
|
CardCollapse,
|
||||||
},
|
},
|
||||||
|
@ -233,6 +231,12 @@ export default {
|
||||||
id: { type: String, required: true },
|
id: { type: String, required: true },
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
v$: useVuelidate(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
queries: [
|
queries: [
|
||||||
|
|
|
@ -108,7 +108,12 @@
|
||||||
</DescriptionRow>
|
</DescriptionRow>
|
||||||
</YCard>
|
</YCard>
|
||||||
|
|
||||||
<ConfigPanels v-if="config.panels" v-bind="config" @submit="onConfigSubmit">
|
<ConfigPanels
|
||||||
|
v-if="config.panels"
|
||||||
|
v-bind="config"
|
||||||
|
:external-results="externalResults"
|
||||||
|
@submit="onConfigSubmit"
|
||||||
|
>
|
||||||
<template v-if="currentTab === 'dns'" #tab-after>
|
<template v-if="currentTab === 'dns'" #tab-after>
|
||||||
<DomainDns :name="name" />
|
<DomainDns :name="name" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -166,6 +171,7 @@ export default {
|
||||||
['GET', `domains/${this.name}/config?full`],
|
['GET', `domains/${this.name}/config?full`],
|
||||||
],
|
],
|
||||||
config: {},
|
config: {},
|
||||||
|
externalResults: {},
|
||||||
unsubscribeDomainFromDyndns: false,
|
unsubscribeDomainFromDyndns: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -247,7 +253,9 @@ export default {
|
||||||
if (err.name !== 'APIBadRequestError') throw err
|
if (err.name !== 'APIBadRequestError') throw err
|
||||||
const panel = this.config.panels.find((panel) => panel.id === id)
|
const panel = this.config.panels.find((panel) => panel.id === id)
|
||||||
if (err.data.name) {
|
if (err.data.name) {
|
||||||
this.config.errors[id][err.data.name].message = err.message
|
Object.assign(this.externalResults, {
|
||||||
|
forms: { [panel.id]: { [err.data.name]: [err.data.error] } },
|
||||||
|
})
|
||||||
} else this.$set(panel, 'serverError', err.message)
|
} else this.$set(panel, 'serverError', err.message)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<CardForm
|
<CardForm
|
||||||
:title="$t('group_new')"
|
:title="$t('group_new')"
|
||||||
icon="users"
|
icon="users"
|
||||||
:validation="$v"
|
:validation="v$"
|
||||||
:server-error="serverError"
|
:server-error="serverError"
|
||||||
@submit.prevent="onSubmit"
|
@submit.prevent="onSubmit"
|
||||||
>
|
>
|
||||||
|
@ -10,13 +10,13 @@
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="groupname"
|
v-bind="groupname"
|
||||||
v-model="form.groupname"
|
v-model="form.groupname"
|
||||||
:validation="$v.form.groupname"
|
:validation="v$.form.groupname"
|
||||||
/>
|
/>
|
||||||
</CardForm>
|
</CardForm>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { validationMixin } from 'vuelidate'
|
import { useVuelidate } from '@vuelidate/core'
|
||||||
|
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { required, alphalownumdot_ } from '@/helpers/validators'
|
import { required, alphalownumdot_ } from '@/helpers/validators'
|
||||||
|
@ -24,6 +24,12 @@ import { required, alphalownumdot_ } from '@/helpers/validators'
|
||||||
export default {
|
export default {
|
||||||
name: 'GroupCreate',
|
name: 'GroupCreate',
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
v$: useVuelidate(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
form: {
|
form: {
|
||||||
|
@ -63,7 +69,5 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [validationMixin],
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
<CardForm
|
<CardForm
|
||||||
:title="$t('operations')"
|
:title="$t('operations')"
|
||||||
icon="cogs"
|
icon="cogs"
|
||||||
:validation="$v"
|
:validation="v$"
|
||||||
:server-error="serverError"
|
:server-error="serverError"
|
||||||
@submit.prevent="onFormPortToggling"
|
@submit.prevent="onFormPortToggling"
|
||||||
inline
|
inline
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
<BFormSelect v-model="form.action" :options="actionChoices" />
|
<BFormSelect v-model="form.action" :options="actionChoices" />
|
||||||
</BInputGroup>
|
</BInputGroup>
|
||||||
|
|
||||||
<FormField :validation="$v.form.port">
|
<FormField :validation="v$.form.port">
|
||||||
<BInputGroup :prepend="$t('port')">
|
<BInputGroup :prepend="$t('port')">
|
||||||
<InputItem
|
<InputItem
|
||||||
id="input-port"
|
id="input-port"
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { validationMixin } from 'vuelidate'
|
import { useVuelidate } from '@vuelidate/core'
|
||||||
|
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { required, integer, between } from '@/helpers/validators'
|
import { required, integer, between } from '@/helpers/validators'
|
||||||
|
@ -127,6 +127,12 @@ import { required, integer, between } from '@/helpers/validators'
|
||||||
export default {
|
export default {
|
||||||
name: 'ToolFirewall',
|
name: 'ToolFirewall',
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
v$: useVuelidate(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
queries: [['GET', '/firewall?raw']],
|
queries: [['GET', '/firewall?raw']],
|
||||||
|
@ -281,8 +287,6 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [validationMixin],
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
<ConfigPanels
|
<ConfigPanels
|
||||||
v-if="config.panels"
|
v-if="config.panels"
|
||||||
v-bind="config"
|
v-bind="config"
|
||||||
|
:external-results="externalResults"
|
||||||
@submit="onConfigSubmit"
|
@submit="onConfigSubmit"
|
||||||
/>
|
/>
|
||||||
</ViewBase>
|
</ViewBase>
|
||||||
|
@ -34,6 +35,7 @@ export default {
|
||||||
return {
|
return {
|
||||||
queries: [['GET', 'settings?full']],
|
queries: [['GET', 'settings?full']],
|
||||||
config: {},
|
config: {},
|
||||||
|
externalResults: {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -62,7 +64,9 @@ export default {
|
||||||
if (err.name !== 'APIBadRequestError') throw err
|
if (err.name !== 'APIBadRequestError') throw err
|
||||||
const panel = this.config.panels.find((panel) => panel.id === id)
|
const panel = this.config.panels.find((panel) => panel.id === id)
|
||||||
if (err.data.name) {
|
if (err.data.name) {
|
||||||
this.config.errors[id][err.data.name].message = err.message
|
Object.assign(this.externalResults, {
|
||||||
|
forms: { [panel.id]: { [err.data.name]: [err.data.error] } },
|
||||||
|
})
|
||||||
} else this.$set(panel, 'serverError', err.message)
|
} else this.$set(panel, 'serverError', err.message)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<CardForm
|
<CardForm
|
||||||
:title="$t('users_new')"
|
:title="$t('users_new')"
|
||||||
icon="user-plus"
|
icon="user-plus"
|
||||||
:validation="$v"
|
:validation="v$"
|
||||||
:server-error="serverError"
|
:server-error="serverError"
|
||||||
@submit.prevent="onSubmit"
|
@submit.prevent="onSubmit"
|
||||||
>
|
>
|
||||||
|
@ -15,19 +15,19 @@
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.username"
|
v-bind="fields.username"
|
||||||
v-model="form.username"
|
v-model="form.username"
|
||||||
:validation="$v.form.username"
|
:validation="v$.form.username"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- USER FULLNAME -->
|
<!-- USER FULLNAME -->
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.fullname"
|
v-bind="fields.fullname"
|
||||||
:validation="$v.form.fullname"
|
:validation="v$.form.fullname"
|
||||||
v-model="form.fullname"
|
v-model="form.fullname"
|
||||||
/>
|
/>
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<!-- USER MAIL DOMAIN -->
|
<!-- USER MAIL DOMAIN -->
|
||||||
<FormField v-bind="fields.domain" :validation="$v.form.domain">
|
<FormField v-bind="fields.domain" :validation="v$.form.domain">
|
||||||
<template #default="{ self }">
|
<template #default="{ self }">
|
||||||
<BInputGroup>
|
<BInputGroup>
|
||||||
<BInputGroupAppend>
|
<BInputGroupAppend>
|
||||||
|
@ -55,14 +55,14 @@
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.password"
|
v-bind="fields.password"
|
||||||
v-model="form.password"
|
v-model="form.password"
|
||||||
:validation="$v.form.password"
|
:validation="v$.form.password"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- USER PASSWORD CONFIRMATION -->
|
<!-- USER PASSWORD CONFIRMATION -->
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.confirmation"
|
v-bind="fields.confirmation"
|
||||||
v-model="form.confirmation"
|
v-model="form.confirmation"
|
||||||
:validation="$v.form.confirmation"
|
:validation="v$.form.confirmation"
|
||||||
/>
|
/>
|
||||||
</CardForm>
|
</CardForm>
|
||||||
</ViewBase>
|
</ViewBase>
|
||||||
|
@ -71,7 +71,7 @@
|
||||||
<script>
|
<script>
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import { validationMixin } from 'vuelidate'
|
import { useVuelidate } from '@vuelidate/core'
|
||||||
|
|
||||||
import { formatFormData } from '@/helpers/yunohostArguments'
|
import { formatFormData } from '@/helpers/yunohostArguments'
|
||||||
import {
|
import {
|
||||||
|
@ -86,6 +86,12 @@ import {
|
||||||
export default {
|
export default {
|
||||||
name: 'UserCreate',
|
name: 'UserCreate',
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
v$: useVuelidate(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
queries: [
|
queries: [
|
||||||
|
@ -164,7 +170,7 @@ export default {
|
||||||
fullname: { required, name },
|
fullname: { required, name },
|
||||||
domain: { required },
|
domain: { required },
|
||||||
password: { required, passwordLenght: minLength(8) },
|
password: { required, passwordLenght: minLength(8) },
|
||||||
confirmation: { required, passwordMatch: sameAs('password') },
|
confirmation: { required, passwordMatch: sameAs(this.form.password) },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -191,8 +197,6 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [validationMixin],
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<CardForm
|
<CardForm
|
||||||
:title="$t('user_username_edit', { name })"
|
:title="$t('user_username_edit', { name })"
|
||||||
icon="user"
|
icon="user"
|
||||||
:validation="$v"
|
:validation="v$"
|
||||||
:server-error="serverError"
|
:server-error="serverError"
|
||||||
@submit.prevent="onSubmit"
|
@submit.prevent="onSubmit"
|
||||||
>
|
>
|
||||||
|
@ -18,13 +18,13 @@
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.fullname"
|
v-bind="fields.fullname"
|
||||||
v-model="form.fullname"
|
v-model="form.fullname"
|
||||||
:validation="$v.form.fullname"
|
:validation="v$.form.fullname"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<!-- USER EMAIL -->
|
<!-- USER EMAIL -->
|
||||||
<FormField v-bind="fields.mail" :validation="$v.form.mail">
|
<FormField v-bind="fields.mail" :validation="v$.form.mail">
|
||||||
<template #default="{ self }">
|
<template #default="{ self }">
|
||||||
<AdressInputSelect v-bind="self" v-model="form.mail" />
|
<AdressInputSelect v-bind="self" v-model="form.mail" />
|
||||||
</template>
|
</template>
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
<!-- MAILBOX QUOTA -->
|
<!-- MAILBOX QUOTA -->
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.mailbox_quota"
|
v-bind="fields.mailbox_quota"
|
||||||
:validation="$v.form.mailbox_quota"
|
:validation="v$.form.mailbox_quota"
|
||||||
>
|
>
|
||||||
<template #default="{ self }">
|
<template #default="{ self }">
|
||||||
<BInputGroup append="M">
|
<BInputGroup append="M">
|
||||||
|
@ -49,7 +49,8 @@
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.mail_aliases"
|
v-bind="fields.mail_aliases"
|
||||||
:id="'mail_aliases' + i"
|
:id="'mail_aliases' + i"
|
||||||
:validation="$v.form.mail_aliases.$each[i]"
|
:validation="v$.form.mail_aliases"
|
||||||
|
:validation-index="i"
|
||||||
>
|
>
|
||||||
<template #default="{ self }">
|
<template #default="{ self }">
|
||||||
<AdressInputSelect v-bind="self" v-model="form.mail_aliases[i]" />
|
<AdressInputSelect v-bind="self" v-model="form.mail_aliases[i]" />
|
||||||
|
@ -72,9 +73,10 @@
|
||||||
<div v-for="(mail, i) in form.mail_forward" :key="i" class="mail-list">
|
<div v-for="(mail, i) in form.mail_forward" :key="i" class="mail-list">
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.mail_forward"
|
v-bind="fields.mail_forward"
|
||||||
v-model="form.mail_forward[i]"
|
v-model="form.mail_forward[i].mail"
|
||||||
:id="'mail-forward' + i"
|
:id="'mail-forward' + i"
|
||||||
:validation="$v.form.mail_forward.$each[i]"
|
:validation="v$.form.mail_forward"
|
||||||
|
:validation-index="i"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<BButton variant="danger" @click="removeEmailField('forward', i)">
|
<BButton variant="danger" @click="removeEmailField('forward', i)">
|
||||||
|
@ -93,14 +95,14 @@
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.change_password"
|
v-bind="fields.change_password"
|
||||||
v-model="form.change_password"
|
v-model="form.change_password"
|
||||||
:validation="$v.form.change_password"
|
:validation="v$.form.change_password"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- USER PASSWORD CONFIRMATION -->
|
<!-- USER PASSWORD CONFIRMATION -->
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.confirmation"
|
v-bind="fields.confirmation"
|
||||||
v-model="form.confirmation"
|
v-model="form.confirmation"
|
||||||
:validation="$v.form.confirmation"
|
:validation="v$.form.confirmation"
|
||||||
/>
|
/>
|
||||||
</CardForm>
|
</CardForm>
|
||||||
</ViewBase>
|
</ViewBase>
|
||||||
|
@ -108,7 +110,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import { validationMixin } from 'vuelidate'
|
import { useVuelidate } from '@vuelidate/core'
|
||||||
|
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { arrayDiff } from '@/helpers/commons'
|
import { arrayDiff } from '@/helpers/commons'
|
||||||
|
@ -118,6 +120,7 @@ import {
|
||||||
formatFormData,
|
formatFormData,
|
||||||
} from '@/helpers/yunohostArguments'
|
} from '@/helpers/yunohostArguments'
|
||||||
import {
|
import {
|
||||||
|
helpers,
|
||||||
name,
|
name,
|
||||||
required,
|
required,
|
||||||
minLength,
|
minLength,
|
||||||
|
@ -137,6 +140,12 @@ export default {
|
||||||
name: { type: String, required: true },
|
name: { type: String, required: true },
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
v$: useVuelidate(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
queries: [
|
queries: [
|
||||||
|
@ -227,7 +236,8 @@ export default {
|
||||||
|
|
||||||
computed: mapGetters(['user', 'domainsAsChoices', 'mainDomain']),
|
computed: mapGetters(['user', 'domainsAsChoices', 'mainDomain']),
|
||||||
|
|
||||||
validations: {
|
validations() {
|
||||||
|
return {
|
||||||
form: {
|
form: {
|
||||||
fullname: { required, name },
|
fullname: { required, name },
|
||||||
mail: {
|
mail: {
|
||||||
|
@ -235,16 +245,19 @@ export default {
|
||||||
},
|
},
|
||||||
mailbox_quota: { integer, minValue: minValue(0) },
|
mailbox_quota: { integer, minValue: minValue(0) },
|
||||||
mail_aliases: {
|
mail_aliases: {
|
||||||
$each: {
|
$each: helpers.forEach({
|
||||||
localPart: { required, email: emailLocalPart },
|
localPart: { required, email: emailLocalPart },
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
mail_forward: {
|
mail_forward: {
|
||||||
$each: { required, emailForward },
|
$each: helpers.forEach({
|
||||||
|
mail: { required, emailForward },
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
change_password: { passwordLenght: minLength(8) },
|
change_password: { passwordLenght: minLength(8) },
|
||||||
confirmation: { passwordMatch: sameAs('change_password') },
|
confirmation: { passwordMatch: sameAs(this.form.change_password) },
|
||||||
},
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -260,7 +273,7 @@ export default {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (user['mail-forward']) {
|
if (user['mail-forward']) {
|
||||||
this.form.mail_forward = user['mail-forward'].slice() // Copy value
|
this.form.mail_forward = user['mail-forward'].map((mail) => ({ mail })) // Copy value
|
||||||
}
|
}
|
||||||
// mailbox-quota could be 'No quota' or 'Pas de quota'...
|
// mailbox-quota could be 'No quota' or 'Pas de quota'...
|
||||||
if (parseInt(user['mailbox-quota'].limit) > 0) {
|
if (parseInt(user['mailbox-quota'].limit) > 0) {
|
||||||
|
@ -278,6 +291,8 @@ export default {
|
||||||
formData.mailbox_quota = ''
|
formData.mailbox_quota = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
formData.mail_forward = formData.mail_forward?.map((v) => v.mail)
|
||||||
|
|
||||||
for (const key of ['mail_aliases', 'mail_forward']) {
|
for (const key of ['mail_aliases', 'mail_forward']) {
|
||||||
const dashedKey = key.replace('_', '-')
|
const dashedKey = key.replace('_', '-')
|
||||||
const newKey = key.replace('_', '').replace('es', '')
|
const newKey = key.replace('_', '').replace('es', '')
|
||||||
|
@ -323,7 +338,7 @@ export default {
|
||||||
this.form['mail_' + type].push(
|
this.form['mail_' + type].push(
|
||||||
type === 'aliases'
|
type === 'aliases'
|
||||||
? { localPart: '', separator: '@', domain: this.mainDomain }
|
? { localPart: '', separator: '@', domain: this.mainDomain }
|
||||||
: '',
|
: { mail: '' },
|
||||||
)
|
)
|
||||||
// Focus last input after rendering update
|
// Focus last input after rendering update
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
@ -337,7 +352,6 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [validationMixin],
|
|
||||||
components: { AdressInputSelect },
|
components: { AdressInputSelect },
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<CardForm
|
<CardForm
|
||||||
:title="$t('users_import')"
|
:title="$t('users_import')"
|
||||||
icon="user-plus"
|
icon="user-plus"
|
||||||
:validation="$v"
|
:validation="v$"
|
||||||
:server-error="serverError"
|
:server-error="serverError"
|
||||||
@submit.prevent="onSubmit"
|
@submit.prevent="onSubmit"
|
||||||
>
|
>
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
<FormField
|
<FormField
|
||||||
v-bind="fields.csvfile"
|
v-bind="fields.csvfile"
|
||||||
v-model="form.csvfile"
|
v-model="form.csvfile"
|
||||||
:validation="$v.form.csvfile"
|
:validation="v$.form.csvfile"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- UPDATE -->
|
<!-- UPDATE -->
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { validationMixin } from 'vuelidate'
|
import { useVuelidate } from '@vuelidate/core'
|
||||||
|
|
||||||
import { formatFormData } from '@/helpers/yunohostArguments'
|
import { formatFormData } from '@/helpers/yunohostArguments'
|
||||||
import { required } from '@/helpers/validators'
|
import { required } from '@/helpers/validators'
|
||||||
|
@ -31,6 +31,12 @@ import { required } from '@/helpers/validators'
|
||||||
export default {
|
export default {
|
||||||
name: 'UserImport',
|
name: 'UserImport',
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
v$: useVuelidate(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
form: {
|
form: {
|
||||||
|
@ -112,7 +118,5 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [validationMixin],
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in a new issue