mirror of
https://github.com/directus/directus.git
synced 2026-01-23 23:18:10 -05:00
Improve preview of relational columns in tabular layout (#15269)
* improve preview of relational tabular columns * update pnpm-lock * Use the improved get method (#15548) * Update app/src/layouts/tabular/index.ts --------- Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com> Co-authored-by: Brainslug <br41nslug@users.noreply.github.com> Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com> Co-authored-by: Pascal Jufer <pascal-jufer@bluewin.ch>
This commit is contained in:
@@ -17,6 +17,7 @@ import TabularActions from './actions.vue';
|
||||
import TabularOptions from './options.vue';
|
||||
import TabularLayout from './tabular.vue';
|
||||
import { LayoutOptions, LayoutQuery } from './types';
|
||||
import { useRelationsStore } from '@/stores/relations';
|
||||
|
||||
export default defineLayout<LayoutOptions, LayoutQuery>({
|
||||
id: 'tabular',
|
||||
@@ -32,6 +33,7 @@ export default defineLayout<LayoutOptions, LayoutQuery>({
|
||||
const router = useRouter();
|
||||
|
||||
const fieldsStore = useFieldsStore();
|
||||
const relationsStore = useRelationsStore();
|
||||
|
||||
const selection = useSync(props, 'selection', emit);
|
||||
const layoutOptions = useSync(props, 'layoutOptions', emit);
|
||||
@@ -226,6 +228,43 @@ export default defineLayout<LayoutOptions, LayoutQuery>({
|
||||
});
|
||||
|
||||
description = fieldNames.join(' -> ');
|
||||
|
||||
const types = relationsStore.getRelationTypes(collection.value!, field.key);
|
||||
|
||||
if (types.at(-1) === 'o2m') {
|
||||
const arrayField = fieldsStore.getField(collection.value!, fieldParts.slice(0, -1).join('.'));
|
||||
let display;
|
||||
let displayOptions;
|
||||
|
||||
if (arrayField?.meta?.display) {
|
||||
display = arrayField.meta.display;
|
||||
displayOptions = arrayField.meta.display_options;
|
||||
} else {
|
||||
display = 'related-values';
|
||||
displayOptions = {
|
||||
template: `{{${fieldParts.at(-1)}}}`,
|
||||
};
|
||||
}
|
||||
|
||||
if (arrayField)
|
||||
return {
|
||||
text: field.name,
|
||||
value: arrayField.field,
|
||||
description,
|
||||
width: localWidths.value[field.key] || layoutOptions.value?.widths?.[field.key] || null,
|
||||
align: layoutOptions.value?.align?.[field.key] || 'left',
|
||||
field: {
|
||||
display,
|
||||
displayOptions,
|
||||
interface: arrayField.meta?.interface,
|
||||
interfaceOptions: arrayField.meta?.options,
|
||||
type: arrayField.type,
|
||||
field: arrayField.field,
|
||||
collection: arrayField.collection,
|
||||
},
|
||||
sortable: ['json', 'alias', 'presentation', 'translations'].includes(arrayField.type) === false,
|
||||
} as HeaderRaw;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -2,6 +2,7 @@ import api from '@/api';
|
||||
import { useFieldsStore } from '@/stores/fields';
|
||||
import { unexpectedError } from '@/utils/unexpected-error';
|
||||
import { Relation, DeepPartial } from '@directus/shared/types';
|
||||
import { getRelationType } from '@directus/shared/utils';
|
||||
import { isEqual } from 'lodash';
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
@@ -104,5 +105,43 @@ export const useRelationsStore = defineStore({
|
||||
|
||||
return relations.find((relation) => relation.collection === collection && relation.field === field) || null;
|
||||
},
|
||||
/**
|
||||
* Get a list of all relation types the path is made of
|
||||
* @param collection The starting collection
|
||||
* @param path The path to digest
|
||||
* @returns An array of types of the relations
|
||||
*/
|
||||
getRelationTypes(collection: string, path: string): ('m2a' | 'o2m' | 'm2o')[] {
|
||||
if (!path.includes('.')) return [];
|
||||
|
||||
const parts = path.split('.');
|
||||
|
||||
const currentField = parts[0].includes(':') ? parts[0].split(':')[0] : parts[0];
|
||||
|
||||
const relation = this.getRelationsForField(collection, currentField).find(
|
||||
(relation) => relation.collection === collection || relation.related_collection === collection
|
||||
);
|
||||
|
||||
if (!relation) return [];
|
||||
|
||||
const type = getRelationType({
|
||||
collection: collection,
|
||||
field: currentField,
|
||||
relation,
|
||||
});
|
||||
|
||||
switch (type) {
|
||||
case 'o2m':
|
||||
return ['o2m', ...this.getRelationTypes(relation.collection, parts.slice(1).join('.'))];
|
||||
case 'm2o':
|
||||
if (!relation.related_collection) return [];
|
||||
return ['m2o', ...this.getRelationTypes(relation.related_collection, parts.slice(1).join('.'))];
|
||||
case 'm2a':
|
||||
if (!relation.meta?.one_allowed_collections) return ['m2a'];
|
||||
return ['m2a', ...this.getRelationTypes(parts[0].split(':')[1], parts.slice(1).join('.'))];
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -16,3 +16,8 @@ test('Returns values in array path as flattened array', () => {
|
||||
const input = { test: [{ path: 'example' }, { path: 'another' }] };
|
||||
expect(get(input, 'test.path')).toEqual(['example', 'another']);
|
||||
});
|
||||
|
||||
test('Returns values in array path as flattened array', () => {
|
||||
const input = { test: [{ path: 'example' }, { falsePath: 'another' }] };
|
||||
expect(get(input, 'test:collection.path')).toEqual(['example']);
|
||||
});
|
||||
|
||||
@@ -9,9 +9,12 @@
|
||||
* ```
|
||||
*/
|
||||
export function get(object: Record<string, any> | any[], path: string, defaultValue?: unknown): any {
|
||||
const [key, ...follow] = path.split('.');
|
||||
let key = path.split('.')[0]!;
|
||||
const follow = path.split('.').slice(1);
|
||||
|
||||
const result = Array.isArray(object) ? object.map((entry) => entry?.[key!]) : object?.[key!];
|
||||
if (key.includes(':')) key = key.split(':')[0]!;
|
||||
|
||||
const result = Array.isArray(object) ? object.map((entry) => entry?.[key]).filter((entry) => entry) : object?.[key];
|
||||
|
||||
if (follow.length > 0) {
|
||||
return get(result, follow.join('.'), defaultValue);
|
||||
|
||||
Reference in New Issue
Block a user