script[setup]: interfaces/group-accordion (#18409)

This commit is contained in:
Rijk van Zanten
2023-05-02 17:30:09 -04:00
committed by GitHub
parent 290d783461
commit 6cd0ef3d3d
2 changed files with 181 additions and 263 deletions

View File

@@ -33,136 +33,97 @@
</v-item>
</template>
<script lang="ts">
import { defineComponent, PropType, computed } from 'vue';
import { merge, isNil } from 'lodash';
import { Field } from '@directus/types';
import { ValidationError } from '@directus/types';
<script setup lang="ts">
import { Field, ValidationError } from '@directus/types';
import { isNil, merge } from 'lodash';
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
export default defineComponent({
name: 'AccordionSection',
props: {
field: {
type: Object as PropType<Field>,
required: true,
},
fields: {
type: Array as PropType<Field[]>,
required: true,
},
values: {
type: Object as PropType<Record<string, unknown>>,
required: true,
},
initialValues: {
type: Object as PropType<Record<string, unknown>>,
required: true,
},
disabled: {
type: Boolean,
default: false,
},
batchMode: {
type: Boolean,
default: false,
},
batchActiveFields: {
type: Array as PropType<string[]>,
default: () => [],
},
primaryKey: {
type: [Number, String],
required: true,
},
loading: {
type: Boolean,
default: false,
},
validationErrors: {
type: Array as PropType<ValidationError[]>,
default: () => [],
},
badge: {
type: String,
default: null,
},
group: {
type: String,
required: true,
},
multiple: {
type: Boolean,
default: false,
},
direction: {
type: String,
default: undefined,
},
},
emits: ['apply', 'toggleAll'],
setup(props, { emit }) {
const { t } = useI18n();
const props = withDefaults(
defineProps<{
field: Field;
fields: Field[];
values: Record<string, unknown>;
initialValues: Record<string, unknown>;
disabled?: boolean;
batchMode?: boolean;
batchActiveFields?: string[];
primaryKey: number | string;
loading?: boolean;
validationErrors?: ValidationError[];
badge?: string;
group: string;
multiple?: boolean;
direction?: string;
}>(),
{
batchActiveFields: () => [],
validationErrors: () => [],
}
);
const fieldsInSection = computed(() => {
let fields: Field[] = [merge({}, props.field, { hideLabel: true })];
const emit = defineEmits<{
(e: 'apply', value: Record<string, unknown>): void;
(e: 'toggleAll'): void;
}>();
if (props.field.meta?.special?.includes('group')) {
fields.push(...getFieldsForGroup(props.field.meta?.field));
}
const { t } = useI18n();
return fields;
});
const fieldsInSection = computed(() => {
let fields: Field[] = [merge({}, props.field, { hideLabel: true })];
const edited = computed(() => {
if (!props.values) return false;
if (props.field.meta?.special?.includes('group')) {
fields.push(...getFieldsForGroup(props.field.meta?.field));
}
const editedFields = Object.keys(props.values);
return fieldsInSection.value.some((field) => editedFields.includes(field.field));
});
const validationMessage = computed(() => {
const validationError = props.validationErrors.find((error) => error.field === props.field.field);
if (validationError === undefined) return;
if (validationError.code === 'RECORD_NOT_UNIQUE') {
return t('validationError.unique');
} else {
return t(`validationError.${validationError.type}`, validationError);
}
});
return { t, fieldsInSection, edited, handleModifier, validationMessage };
function handleModifier(event: MouseEvent, toggle: () => void) {
if (props.multiple === false) {
toggle();
return;
}
if (event.shiftKey) {
emit('toggleAll');
} else {
toggle();
}
}
function getFieldsForGroup(group: null | string, passed: string[] = []): Field[] {
const fieldsInGroup: Field[] = props.fields.filter((field) => {
return field.meta?.group === group || (group === null && isNil(field.meta));
});
for (const field of fieldsInGroup) {
if (field.meta?.special?.includes('group') && !passed.includes(field.meta!.field)) {
passed.push(field.meta!.field);
fieldsInGroup.push(...getFieldsForGroup(field.meta!.field, passed));
}
}
return fieldsInGroup;
}
},
return fields;
});
const edited = computed(() => {
if (!props.values) return false;
const editedFields = Object.keys(props.values);
return fieldsInSection.value.some((field) => editedFields.includes(field.field));
});
const validationMessage = computed(() => {
const validationError = props.validationErrors.find((error) => error.field === props.field.field);
if (validationError === undefined) return;
if (validationError.code === 'RECORD_NOT_UNIQUE') {
return t('validationError.unique');
} else {
return t(`validationError.${validationError.type}`, validationError);
}
});
function handleModifier(event: MouseEvent, toggle: () => void) {
if (props.multiple === false) {
toggle();
return;
}
if (event.shiftKey) {
emit('toggleAll');
} else {
toggle();
}
}
function getFieldsForGroup(group: null | string, passed: string[] = []): Field[] {
const fieldsInGroup: Field[] = props.fields.filter((field) => {
return field.meta?.group === group || (group === null && isNil(field.meta));
});
for (const field of fieldsInGroup) {
if (field.meta?.special?.includes('group') && !passed.includes(field.meta!.field)) {
passed.push(field.meta!.field);
fieldsInGroup.push(...getFieldsForGroup(field.meta!.field, passed));
}
}
return fieldsInGroup;
}
</script>
<style lang="scss" scoped>

View File

@@ -24,154 +24,111 @@
</v-item-group>
</template>
<script lang="ts">
import { Field } from '@directus/types';
import { defineComponent, PropType, ref, watch } from 'vue';
import { ValidationError } from '@directus/types';
import AccordionSection from './accordion-section.vue';
<script setup lang="ts">
import { Field, ValidationError } from '@directus/types';
import { isEqual } from 'lodash';
import { ref, watch } from 'vue';
import AccordionSection from './accordion-section.vue';
export default defineComponent({
name: 'InterfaceGroupAccordion',
components: { AccordionSection },
props: {
field: {
type: Object as PropType<Field>,
required: true,
},
fields: {
type: Array as PropType<Field[]>,
required: true,
},
values: {
type: Object as PropType<Record<string, unknown>>,
required: true,
},
initialValues: {
type: Object as PropType<Record<string, unknown>>,
required: true,
},
disabled: {
type: Boolean,
default: false,
},
batchMode: {
type: Boolean,
default: false,
},
batchActiveFields: {
type: Array as PropType<string[]>,
default: () => [],
},
primaryKey: {
type: [Number, String],
required: true,
},
loading: {
type: Boolean,
default: false,
},
validationErrors: {
type: Array as PropType<ValidationError[]>,
default: () => [],
},
badge: {
type: String,
default: null,
},
rawEditorEnabled: {
type: Boolean,
default: false,
},
accordionMode: {
type: Boolean,
default: true,
},
start: {
type: String,
enum: ['opened', 'closed', 'first'],
default: 'closed',
},
direction: {
type: String,
default: undefined,
},
},
emits: ['apply'],
setup(props) {
const selection = ref<string[]>([]);
const { groupFields, groupValues } = useComputedGroup();
const props = withDefaults(
defineProps<{
field: Field;
fields: Field[];
values: Record<string, unknown>;
initialValues: Record<string, unknown>;
disabled?: boolean;
batchMode?: boolean;
batchActiveFields?: string[];
primaryKey: string | number;
loading?: boolean;
validationErrors?: ValidationError[];
badge?: string;
rawEditorEnabled?: boolean;
accordionMode?: boolean;
start?: 'opened' | 'closed' | 'first';
direction?: string;
}>(),
{
batchActiveFields: () => [],
validationErrors: () => [],
accordionMode: true,
start: 'closed',
}
);
watch(
() => props.start,
(start) => {
if (start === 'opened') {
selection.value = groupFields.value.map((field) => field.field);
}
defineEmits<{
(e: 'apply', value: Record<string, unknown>): void;
}>();
if (start === 'first') {
selection.value = [groupFields.value[0].field];
}
},
{ immediate: true }
);
const selection = ref<string[]>([]);
const { groupFields, groupValues } = useComputedGroup();
watch(
() => props.validationErrors,
(newVal, oldVal) => {
if (!props.validationErrors) return;
if (isEqual(newVal, oldVal)) return;
const includedFieldsWithErrors = props.validationErrors.filter((validationError) =>
groupFields.value.find((rootField) => rootField.field === validationError.field)
);
if (includedFieldsWithErrors.length > 0) selection.value = [includedFieldsWithErrors[0].field];
}
);
return { groupFields, groupValues, selection, toggleAll };
function toggleAll() {
if (props.accordionMode === true) return;
if (selection.value.length === groupFields.value.length) {
selection.value = [];
} else {
selection.value = groupFields.value.map((field) => field.field);
}
watch(
() => props.start,
(start) => {
if (start === 'opened') {
selection.value = groupFields.value.map((field) => field.field);
}
function useComputedGroup() {
const groupFields = ref<Field[]>(limitFields());
const groupValues = ref<Record<string, any>>({});
watch(
() => props.fields,
() => {
const newVal = limitFields();
if (!isEqual(groupFields.value, newVal)) {
groupFields.value = newVal;
}
}
);
watch(
() => props.values,
(newVal) => {
if (!isEqual(groupValues.value, newVal)) {
groupValues.value = newVal;
}
}
);
return { groupFields, groupValues };
function limitFields(): Field[] {
return props.fields.filter((field) => field.meta?.group === props.field.meta?.field);
}
if (start === 'first') {
selection.value = [groupFields.value[0].field];
}
},
});
{ immediate: true }
);
watch(
() => props.validationErrors,
(newVal, oldVal) => {
if (!props.validationErrors) return;
if (isEqual(newVal, oldVal)) return;
const includedFieldsWithErrors = props.validationErrors.filter((validationError) =>
groupFields.value.find((rootField) => rootField.field === validationError.field)
);
if (includedFieldsWithErrors.length > 0) selection.value = [includedFieldsWithErrors[0].field];
}
);
function toggleAll() {
if (props.accordionMode === true) return;
if (selection.value.length === groupFields.value.length) {
selection.value = [];
} else {
selection.value = groupFields.value.map((field) => field.field);
}
}
function useComputedGroup() {
const groupFields = ref<Field[]>(limitFields());
const groupValues = ref<Record<string, any>>({});
watch(
() => props.fields,
() => {
const newVal = limitFields();
if (!isEqual(groupFields.value, newVal)) {
groupFields.value = newVal;
}
}
);
watch(
() => props.values,
(newVal) => {
if (!isEqual(groupValues.value, newVal)) {
groupValues.value = newVal;
}
}
);
return { groupFields, groupValues };
function limitFields(): Field[] {
return props.fields.filter((field) => field.meta?.group === props.field.meta?.field);
}
}
</script>