Fix tabular not properly dealiasing items (#18186)

* Fix tabular not properly dealiasing items

* run linter

* remove translations edgecase

* Fix linter warnings

* Remove unused var

---------

Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
This commit is contained in:
Nitwel
2023-04-21 21:13:25 +02:00
committed by GitHub
parent b69f380275
commit 6e707b7d1b
2 changed files with 18 additions and 58 deletions

View File

@@ -1,12 +1,12 @@
import { HeaderRaw, Item, Sort } from '@/components/v-table/types';
import { useFieldsStore } from '@/stores/fields';
import { useAliasFields } from '@/composables/use-alias-fields';
import { useFieldsStore } from '@/stores/fields';
import { adjustFieldsForDisplays } from '@/utils/adjust-fields-for-displays';
import { formatCollectionItemsCount } from '@/utils/format-collection-items-count';
import { getDefaultDisplayForType } from '@/utils/get-default-display-for-type';
import { hideDragImage } from '@/utils/hide-drag-image';
import { saveAsCSV } from '@/utils/save-as-csv';
import { syncRefProperty } from '@/utils/sync-ref-property';
import { formatCollectionItemsCount } from '@/utils/format-collection-items-count';
import { useCollection, useItems, useSync } from '@directus/composables';
import { Field } from '@directus/types';
import { defineLayout } from '@directus/utils';
@@ -17,7 +17,6 @@ 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',
@@ -34,7 +33,6 @@ 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);
@@ -46,7 +44,7 @@ export default defineLayout<LayoutOptions, LayoutQuery>({
const { sort, limit, page, fields } = useItemOptions();
const { aliasedFields, aliasQuery } = useAliasFields(fields, collection);
const { aliasedFields, aliasQuery, aliasedKeys } = useAliasFields(fields, collection);
const fieldsWithRelationalAliased = computed(() => {
return Object.values(aliasedFields.value).reduce<string[]>((acc, value) => {
@@ -124,6 +122,8 @@ export default defineLayout<LayoutOptions, LayoutQuery>({
search,
download,
fieldsWithRelationalAliased,
aliasedFields,
aliasedKeys,
};
async function resetPresetAndRefresh() {
@@ -218,52 +218,11 @@ export default defineLayout<LayoutOptions, LayoutQuery>({
const tableHeaders = computed<HeaderRaw[]>({
get() {
return activeFields.value.map((field) => {
let description: string | null = null;
const fieldParts = field.key.split('.');
if (fieldParts.length > 1) {
const fieldNames = fieldParts.map((fieldKey, index) => {
const pathPrefix = fieldParts.slice(0, index);
const field = fieldsStore.getField(collection.value!, [...pathPrefix, fieldKey].join('.'));
return field?.name ?? fieldKey;
});
description = fieldNames.join(' -> ');
const types = relationsStore.getRelationTypes(collection.value!, field.key);
const arrayField = fieldsStore.getField(collection.value!, fieldParts.slice(0, -1).join('.'));
// Special case for translations to render the nested data in the translations display instead of the default display
if (types.at(-1) === 'o2m' && arrayField?.meta?.special?.includes('translations')) {
if (arrayField)
return {
text: field.name,
value: field.key,
key: fieldParts.slice(0, -1).join('.'),
description,
width: localWidths.value[field.key] || layoutOptions.value?.widths?.[field.key] || null,
align: layoutOptions.value?.align?.[field.key] || 'left',
field: {
display: 'translations',
displayOptions: {
template: `{{${fieldParts.at(-1)}}}`,
},
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;
}
}
const description: string | null = null;
return {
text: field.name,
value: field.key,
key: field.key,
description,
width: localWidths.value[field.key] || layoutOptions.value?.widths?.[field.key] || null,
align: layoutOptions.value?.align?.[field.key] || 'left',

View File

@@ -25,7 +25,7 @@
>
<template v-for="header in tableHeaders" :key="header.value" #[`item.${header.value}`]="{ item }">
<render-display
:value="getDisplayValue(item, header.key)"
:value="getDisplayValue(item, header.value)"
:display="header.field.display"
:options="header.field.displayOptions"
:interface="header.field.interface"
@@ -185,7 +185,7 @@ import { Field, Filter, Item, ShowSelect } from '@directus/types';
import { ComponentPublicInstance, inject, ref, Ref, watch, computed, toRefs } from 'vue';
import { useI18n } from 'vue-i18n';
import { get } from '@directus/utils';
import { useAliasFields } from '@/composables/use-alias-fields';
import { AliasFields } from '@/composables/use-alias-fields';
import { usePermissionsStore } from '@/stores/permissions';
import { useUserStore } from '@/stores/user';
import { HeaderRaw } from '@/components/v-table/types';
@@ -216,6 +216,8 @@ interface Props {
selectAll: () => void;
filterUser?: Filter;
search?: string;
aliasedFields: Record<string, AliasFields>;
aliasedKeys: string[];
onSortChange: (newSort: { by: string; desc: boolean }) => void;
onAlignChange?: (field: 'string', align: 'left' | 'center' | 'right') => void;
}
@@ -237,7 +239,7 @@ const props = withDefaults(defineProps<Props>(), {
const emit = defineEmits(['update:selection', 'update:tableHeaders', 'update:limit', 'update:fields']);
const { t } = useI18n();
const { collection } = toRefs(props);
const { collection, aliasedFields, aliasedKeys } = toRefs(props);
const selectionWritable = useSync(props, 'selection', emit);
const tableHeadersWritable = useSync(props, 'tableHeaders', emit);
@@ -281,20 +283,19 @@ const showManualSort = computed(() => {
const fieldsWritable = useSync(props, 'fields', emit);
const { aliasedFields, aliasedKeys } = useAliasFields(fieldsWritable, collection);
function getDisplayValue(item: Item, key: string) {
const aliasInfo = Object.values(aliasedFields.value).find((field) => field.key === key);
if (!aliasInfo) return get(item, key);
const dealiasedItem = Object.keys(item).reduce<Item>((result, key) => {
if (aliasedKeys.value.includes(key)) {
if (key !== aliasInfo.fieldAlias) return result;
const name = aliasedFields.value[key].fieldName;
result[name] = item[key];
const dealiasedItem = Object.keys(item).reduce<Item>((result, itemKey) => {
if (aliasedKeys.value.includes(itemKey)) {
if (itemKey !== aliasInfo.fieldAlias) return result;
const name = aliasedFields.value[itemKey].fieldName;
result[name] = item[itemKey];
} else {
result[key] = item[key];
// Don't overwrite already dealiased keys
if (itemKey in result === false) result[itemKey] = item[itemKey];
}
return result;