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:
Nitwel
2023-02-24 15:01:57 +01:00
committed by GitHub
parent da9c3fed3c
commit 21bb26988e
4 changed files with 88 additions and 2 deletions

View File

@@ -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 {

View File

@@ -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 [];
},
},
});

View File

@@ -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']);
});

View File

@@ -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);