v3.0.0/src/site/components/settings/JoiObject.vue

152 lines
3.3 KiB
Vue

<template>
<div v-if="settings">
<div v-for="[key, field] in Object.entries(settings)" :key="key">
<b-field
:label="field.flags.label"
:message="getErrorMessage(key) || field.flags.description"
:type="getValidationType(key)"
class="field"
horizontal>
<b-input
v-if="getDisplayType(field) === 'string'"
v-model="values[key]"
class="chibisafe-input"
expanded />
<b-input
v-else-if="getDisplayType(field) === 'number'"
v-model="values[key]"
type="number"
class="chibisafe-input"
:min="getMin(field)"
:max="getMax(field)"
expanded />
<b-switch
v-else-if="getDisplayType(field) === 'boolean'"
v-model="values[key]"
:rounded="false"
:true-value="true"
:false-value="false" />
<!-- TODO: If array and has allowed items, limit input to those items only -->
<b-taginput
v-else-if="getDisplayType(field) === 'array' || getDisplayType(field) === 'tagInput'"
v-model="values[key]"
ellipsis
icon="label"
:placeholder="field.flags.label"
class="taginp" />
<div v-else-if="getDisplayType(field) === 'checkbox'">
<b-checkbox v-for="item in getAllowedItems(field)" :key="item"
v-model="values[key]"
:native-value="item">
{{ item }}
</b-checkbox>
</div>
</b-field>
<!--
TODO: Add asterisk to required fields
-->
</div>
</div>
</template>
<script>
export default {
name: 'JoiObject',
props: {
settings: {
type: Object,
required: true
},
errors: {
'type': Object,
'default': () => ({})
}
},
data() {
return {
values: {}
};
},
created() {
for (const [k, v] of Object.entries(this.settings)) {
this.$set(this.values, k, v.value);
}
},
methods: {
getMin(field) {
if (field.type !== 'number') return;
for (const rule of field.rules) {
if (rule.name === 'greater') return rule.args.limit + 1;
if (rule.name === 'min') return rule.args.limit;
}
},
getMax(field) {
if (field.type !== 'number') return;
for (const rule of field.rules) {
if (rule.name === 'less') return rule.args.limit - 1;
if (rule.name === 'max') return rule.args.limit;
}
},
getDisplayType(field) {
if (!field.metas) return field.type;
const foundMeta = field.metas.find(e => e.displayType);
if (foundMeta) return foundMeta.displayType;
return field.type;
},
getAllowedItems(field) {
if (!field.items) return [];
return field.items.reduce((acc, item) => {
if (!item.allow) return acc;
return [...acc, ...item.allow];
}, []);
},
getValidationType(fieldName) {
if (Array.isArray(this.errors[fieldName])) return 'is-danger';
return null;
},
getErrorMessage(fieldName) {
if (Array.isArray(this.errors[fieldName])) return this.errors[fieldName].join('\n');
return null;
},
getValues() {
return this.values;
}
}
};
</script>
<style lang="scss" scoped>
@import '~/assets/styles/_colors.scss';
.field {
margin-bottom: 1em;
::v-deep .help.is-danger {
white-space: pre-line;
}
}
.taginp {
::v-deep {
.taginput-container {
border-color: #585858;
}
.input::placeholder {
color: $textColor;
}
.taginput-container, .control, .input {
background-color: transparent;
}
}
}
</style>