mirror of
https://github.com/directus/directus.git
synced 2026-02-07 12:55:18 -05:00
Conditions not working (partially) (#14488)
* changed way of storing the formfield data in v-form
* hacky translation implementation
* updated translations without bombing the performance
* removed debug code and refactored initial implementation
* removed redundant useFormFields in users route
* making proper use of useFormField results to not break the grid layout
* removed limitation for conditions
* Fix selection of foreign keys for value field in time series panel
* Revert "removed redundant useFormFields in users route"
This reverts commit c6f4f23cf8.
Co-authored-by: ian <licitdev@gmail.com>
Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com>
Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
This commit is contained in:
@@ -6,22 +6,22 @@
|
||||
:fields="fields ? fields : []"
|
||||
@scroll-to-field="scrollToField"
|
||||
/>
|
||||
<template v-for="(field, index) in formFields">
|
||||
<template v-for="(fieldName, index) in fieldNames">
|
||||
<component
|
||||
:is="`interface-${fieldsMeta[field.field]?.interface || 'group-standard'}`"
|
||||
v-if="fieldsMeta[field.field]?.special?.includes('group')"
|
||||
v-show="!fieldsMeta[field.field]?.hidden"
|
||||
:is="`interface-${fieldsMap[fieldName].meta?.interface || 'group-standard'}`"
|
||||
v-if="fieldsMap[fieldName].meta?.special?.includes('group')"
|
||||
v-show="!fieldsMap[fieldName].meta?.hidden"
|
||||
:ref="
|
||||
(el: Element) => {
|
||||
formFieldEls[field.field] = el;
|
||||
formFieldEls[fieldName] = el;
|
||||
}
|
||||
"
|
||||
:key="field.field + '_group'"
|
||||
:key="fieldName + '_group'"
|
||||
:class="[
|
||||
fieldsMeta[field.field]?.width || 'full',
|
||||
fieldsMap[fieldName].meta?.width || 'full',
|
||||
index === firstVisibleFieldIndex ? 'first-visible-field' : '',
|
||||
]"
|
||||
:field="field"
|
||||
:field="fieldsMap[fieldName]"
|
||||
:fields="fieldsForGroup[index] || []"
|
||||
:values="modelValue || {}"
|
||||
:initial-values="initialValues || {}"
|
||||
@@ -33,43 +33,43 @@
|
||||
:validation-errors="validationErrors"
|
||||
:badge="badge"
|
||||
:raw-editor-enabled="rawEditorEnabled"
|
||||
v-bind="fieldsMeta[field.field]?.options || {}"
|
||||
v-bind="fieldsMap[fieldName].meta?.options || {}"
|
||||
@apply="apply"
|
||||
/>
|
||||
|
||||
<form-field
|
||||
v-else-if="!fieldsMeta[field.field]?.hidden"
|
||||
v-else-if="!fieldsMap[fieldName].meta?.hidden"
|
||||
:ref="
|
||||
(el: Element) => {
|
||||
formFieldEls[field.field] = el;
|
||||
formFieldEls[fieldName] = el;
|
||||
}
|
||||
"
|
||||
:key="field.field + '_field'"
|
||||
:key="fieldName + '_field'"
|
||||
:class="index === firstVisibleFieldIndex ? 'first-visible-field' : ''"
|
||||
:field="field"
|
||||
:field="fieldsMap[fieldName]"
|
||||
:autofocus="index === firstEditableFieldIndex && autofocus"
|
||||
:model-value="(values || {})[field.field]"
|
||||
:initial-value="(initialValues || {})[field.field]"
|
||||
:disabled="isDisabled(field)"
|
||||
:model-value="(values || {})[fieldName]"
|
||||
:initial-value="(initialValues || {})[fieldName]"
|
||||
:disabled="isDisabled(fieldsMap[fieldName])"
|
||||
:batch-mode="batchMode"
|
||||
:batch-active="batchActiveFields.includes(field.field)"
|
||||
:batch-active="batchActiveFields.includes(fieldName)"
|
||||
:primary-key="primaryKey"
|
||||
:loading="loading"
|
||||
:validation-error="
|
||||
validationErrors.find(
|
||||
(err) =>
|
||||
err.collection === field?.collection &&
|
||||
(err.field === field.field || err.field.endsWith(`(${field.field})`))
|
||||
err.collection === fieldsMap[fieldName]?.collection &&
|
||||
(err.field === fieldName || err.field.endsWith(`(${fieldName})`))
|
||||
)
|
||||
"
|
||||
:badge="badge"
|
||||
:raw-editor-enabled="rawEditorEnabled"
|
||||
:raw-editor-active="rawActiveFields.has(field.field)"
|
||||
@update:model-value="setValue(field.field, $event)"
|
||||
:raw-editor-active="rawActiveFields.has(fieldName)"
|
||||
@update:model-value="setValue(fieldName, $event)"
|
||||
@set-field-value="setValue($event.field, $event.value, { force: true })"
|
||||
@unset="unsetValue(field)"
|
||||
@toggle-batch="toggleBatchField(field)"
|
||||
@toggle-raw="toggleRawField(field)"
|
||||
@unset="unsetValue(fieldsMap[fieldName])"
|
||||
@toggle-batch="toggleBatchField(fieldsMap[fieldName])"
|
||||
@toggle-raw="toggleRawField(fieldsMap[fieldName])"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
@@ -81,9 +81,9 @@ import useFormFields from '@/composables/use-form-fields';
|
||||
import { useFieldsStore } from '@/stores/';
|
||||
import { applyConditions } from '@/utils/apply-conditions';
|
||||
import { extractFieldFromFunction } from '@/utils/extract-field-from-function';
|
||||
import { Field, FieldMeta, ValidationError } from '@directus/shared/types';
|
||||
import { Field, ValidationError } from '@directus/shared/types';
|
||||
import { assign, cloneDeep, isEqual, isNil, omit, pick } from 'lodash';
|
||||
import { computed, defineComponent, onBeforeUpdate, PropType, provide, ref, watch, Ref } from 'vue';
|
||||
import { computed, defineComponent, onBeforeUpdate, PropType, provide, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import FormField from './form-field.vue';
|
||||
import ValidationErrors from './validation-errors.vue';
|
||||
@@ -158,8 +158,6 @@ export default defineComponent({
|
||||
setup(props, { emit }) {
|
||||
const { t } = useI18n();
|
||||
|
||||
const fields = useComputedFields();
|
||||
|
||||
const values = computed(() => {
|
||||
return Object.assign({}, props.initialValues, props.modelValue);
|
||||
});
|
||||
@@ -184,13 +182,14 @@ export default defineComponent({
|
||||
formFieldEls.value = {};
|
||||
});
|
||||
|
||||
const { formFields, getFieldsForGroup, fieldsForGroup, isDisabled, fieldsMeta } = useForm();
|
||||
const { fieldNames, fieldsMap, getFieldsForGroup, fieldsForGroup, isDisabled } = useForm();
|
||||
const { toggleBatchField, batchActiveFields } = useBatch();
|
||||
const { toggleRawField, rawActiveFields } = useRawEditor();
|
||||
|
||||
const firstEditableFieldIndex = computed(() => {
|
||||
for (let i = 0; i < formFields.value.length; i++) {
|
||||
if (formFields.value[i].meta && !formFields.value[i].meta?.readonly && !formFields.value[i].meta?.hidden) {
|
||||
for (let i = 0; i < fieldNames.value.length; i++) {
|
||||
const field = fieldsMap.value[fieldNames.value[i]];
|
||||
if (field.meta && !field.meta?.readonly && !field.meta?.hidden) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -198,8 +197,9 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
const firstVisibleFieldIndex = computed(() => {
|
||||
for (let i = 0; i < formFields.value.length; i++) {
|
||||
if (formFields.value[i].meta && !formFields.value[i].meta?.hidden) {
|
||||
for (let i = 0; i < fieldNames.value.length; i++) {
|
||||
const field = fieldsMap.value[fieldNames.value[i]];
|
||||
if (field.meta && !field.meta?.hidden) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -219,7 +219,6 @@ export default defineComponent({
|
||||
|
||||
return {
|
||||
t,
|
||||
formFields,
|
||||
values,
|
||||
setValue,
|
||||
batchActiveFields,
|
||||
@@ -239,10 +238,24 @@ export default defineComponent({
|
||||
isDisabled,
|
||||
scrollToField,
|
||||
formFieldEls,
|
||||
fieldsMeta,
|
||||
fieldNames,
|
||||
fieldsMap,
|
||||
};
|
||||
|
||||
function useForm() {
|
||||
const fieldsStore = useFieldsStore();
|
||||
const fields = ref<Field[]>(getFields());
|
||||
|
||||
watch(
|
||||
() => props.fields,
|
||||
() => {
|
||||
const newVal = getFields();
|
||||
if (!isEqual(fields.value, newVal)) {
|
||||
fields.value = newVal;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const defaultValues = computed(() => {
|
||||
return fields.value.reduce(function (acc, field) {
|
||||
if (
|
||||
@@ -260,28 +273,15 @@ export default defineComponent({
|
||||
}, {} as Record<string, any>);
|
||||
});
|
||||
|
||||
const fieldsMeta = computed(() => {
|
||||
const { formFields } = useFormFields(fields);
|
||||
|
||||
const fieldsMap = computed(() => {
|
||||
const valuesWithDefaults = Object.assign({}, defaultValues.value, values.value);
|
||||
|
||||
return fields.value.reduce((result: Record<string, FieldMeta>, field: Field) => {
|
||||
const { meta } = applyConditions(valuesWithDefaults, setPrimaryKeyReadonly(field));
|
||||
if (meta) result[meta.field] = meta;
|
||||
return formFields.value.reduce((result: Record<string, Field>, field: Field) => {
|
||||
const newField = applyConditions(valuesWithDefaults, setPrimaryKeyReadonly(field));
|
||||
if (newField.field) result[newField.field] = newField;
|
||||
return result;
|
||||
}, {} as Record<string, FieldMeta>);
|
||||
|
||||
function setPrimaryKeyReadonly(field: Field) {
|
||||
if (
|
||||
field.schema?.has_auto_increment === true ||
|
||||
(field.schema?.is_primary_key === true && props.primaryKey !== '+')
|
||||
) {
|
||||
const fieldClone = cloneDeep(field) as any;
|
||||
if (!fieldClone.meta) fieldClone.meta = {};
|
||||
fieldClone.meta.readonly = true;
|
||||
return fieldClone;
|
||||
}
|
||||
|
||||
return field;
|
||||
}
|
||||
}, {} as Record<string, Field>);
|
||||
});
|
||||
|
||||
const fieldsInGroup = computed(() =>
|
||||
@@ -289,17 +289,18 @@ export default defineComponent({
|
||||
(field: Field) => field.meta?.group === props.group || (props.group === null && isNil(field.meta?.group))
|
||||
)
|
||||
);
|
||||
|
||||
const { formFields } = useFormFields(fieldsInGroup);
|
||||
const fieldNames = computed(() => {
|
||||
return fieldsInGroup.value.map((f) => f.field);
|
||||
});
|
||||
|
||||
const fieldsForGroup = computed(() =>
|
||||
formFields.value.map((field: Field) => getFieldsForGroup(field.meta?.field || null))
|
||||
fieldNames.value.map((name: string) => getFieldsForGroup(fieldsMap.value[name]?.meta?.field || null))
|
||||
);
|
||||
|
||||
return { formFields, fieldsMeta, isDisabled, getFieldsForGroup, fieldsForGroup };
|
||||
return { fieldNames, fieldsMap, isDisabled, getFieldsForGroup, fieldsForGroup };
|
||||
|
||||
function isDisabled(field: Field) {
|
||||
const meta = fieldsMeta.value?.[field.field];
|
||||
const meta = fieldsMap.value?.[field.field].meta;
|
||||
return (
|
||||
props.loading ||
|
||||
props.disabled === true ||
|
||||
@@ -311,12 +312,12 @@ export default defineComponent({
|
||||
|
||||
function getFieldsForGroup(group: null | string, passed: string[] = []): Field[] {
|
||||
const fieldsInGroup: Field[] = fields.value.filter((field) => {
|
||||
const meta = fieldsMeta.value?.[field.field];
|
||||
const meta = fieldsMap.value?.[field.field].meta;
|
||||
return meta?.group === group || (group === null && isNil(meta));
|
||||
});
|
||||
|
||||
for (const field of fieldsInGroup) {
|
||||
const meta = fieldsMeta.value?.[field.field];
|
||||
const meta = fieldsMap.value?.[field.field].meta;
|
||||
if (meta?.special?.includes('group') && !passed.includes(meta!.field)) {
|
||||
passed.push(meta!.field);
|
||||
fieldsInGroup.push(...getFieldsForGroup(meta!.field, passed));
|
||||
@@ -325,24 +326,6 @@ export default defineComponent({
|
||||
|
||||
return fieldsInGroup;
|
||||
}
|
||||
}
|
||||
|
||||
function useComputedFields(): Ref<Field[]> {
|
||||
const fieldsStore = useFieldsStore();
|
||||
|
||||
const fields = ref<Field[]>(getFields());
|
||||
|
||||
watch(
|
||||
() => props.fields,
|
||||
() => {
|
||||
const newVal = getFields();
|
||||
if (!isEqual(fields.value, newVal)) {
|
||||
fields.value = newVal;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return fields;
|
||||
|
||||
function getFields(): Field[] {
|
||||
if (props.collection) {
|
||||
@@ -354,10 +337,24 @@ export default defineComponent({
|
||||
|
||||
throw new Error('[v-form]: You need to pass either the collection or fields prop.');
|
||||
}
|
||||
|
||||
function setPrimaryKeyReadonly(field: Field) {
|
||||
if (
|
||||
field.schema?.has_auto_increment === true ||
|
||||
(field.schema?.is_primary_key === true && props.primaryKey !== '+')
|
||||
) {
|
||||
const fieldClone = cloneDeep(field) as any;
|
||||
if (!fieldClone.meta) fieldClone.meta = {};
|
||||
fieldClone.meta.readonly = true;
|
||||
return fieldClone;
|
||||
}
|
||||
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
function setValue(fieldKey: string, value: any, opts?: { force?: boolean }) {
|
||||
const field = formFields.value?.find((field) => field.field === fieldKey);
|
||||
const field = fieldsMap.value[fieldKey];
|
||||
|
||||
if (opts?.force !== true && (!field || isDisabled(field))) return;
|
||||
|
||||
@@ -370,7 +367,7 @@ export default defineComponent({
|
||||
const updatableKeys = props.batchMode
|
||||
? Object.keys(updates)
|
||||
: Object.keys(updates).filter((key) => {
|
||||
const field = fields.value?.find((field) => field.field === key);
|
||||
const field = fieldsMap.value[key];
|
||||
if (!field) return false;
|
||||
return field.schema?.is_primary_key || !isDisabled(field);
|
||||
});
|
||||
|
||||
@@ -228,6 +228,7 @@ export default definePanel({
|
||||
interface: 'system-field',
|
||||
width: 'half',
|
||||
options: {
|
||||
allowForeignKeys: false,
|
||||
collectionField: 'collection',
|
||||
typeAllowList: ['integer', 'bigInteger', 'float', 'decimal'],
|
||||
},
|
||||
@@ -240,6 +241,7 @@ export default definePanel({
|
||||
},
|
||||
options: {
|
||||
allowPrimaryKey: true,
|
||||
allowForeignKeys: true,
|
||||
typeAllowList: ['integer', 'bigInteger', 'uuid', 'string'],
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user