From 8f8f0e5c122daa462bbab3233ecebfd27b206135 Mon Sep 17 00:00:00 2001 From: Harikrushna Date: Sat, 11 Dec 2021 01:39:36 +0530 Subject: [PATCH] Relations: fix M2M related primary key (#10368) * correction in m2m relation filed name * prevent m2m reload on form change * rely on junction PK instead of relation PK When relation PK is a manually entered string, we cannot rely on relation PK. * prevent m2a reload on form change Co-authored-by: Jose Varela Co-authored-by: rijkvanzanten --- app/src/interfaces/list-m2a/list-m2a.vue | 6 ++++-- app/src/interfaces/list-m2m/use-actions.ts | 20 ++++++++++++-------- app/src/interfaces/list-m2m/use-preview.ts | 8 +++++--- app/src/interfaces/list-m2m/use-selection.ts | 12 ++++++------ 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/app/src/interfaces/list-m2a/list-m2a.vue b/app/src/interfaces/list-m2a/list-m2a.vue index dd12fe3de4..57fdf796fd 100644 --- a/app/src/interfaces/list-m2a/list-m2a.vue +++ b/app/src/interfaces/list-m2a/list-m2a.vue @@ -148,7 +148,7 @@ import DrawerItem from '@/views/private/components/drawer-item/'; import api from '@/api'; import { unexpectedError } from '@/utils/unexpected-error'; import { getFieldsFromTemplate } from '@directus/shared/utils'; -import { isPlainObject, cloneDeep } from 'lodash'; +import { isPlainObject, cloneDeep, isEqual } from 'lodash'; import { getEndpoint } from '@/utils/get-endpoint'; import { hideDragImage } from '@/utils/hide-drag-image'; import Draggable from 'vuedraggable'; @@ -378,9 +378,11 @@ export default defineComponent({ relatedItemValues, }; - async function fetchValues() { + async function fetchValues(newVal: any, oldVal: any) { if (props.value === null) return; + if (isEqual(newVal, oldVal)) return; + loading.value = true; try { diff --git a/app/src/interfaces/list-m2m/use-actions.ts b/app/src/interfaces/list-m2m/use-actions.ts index d620087dd0..07b182b1ac 100644 --- a/app/src/interfaces/list-m2m/use-actions.ts +++ b/app/src/interfaces/list-m2m/use-actions.ts @@ -44,22 +44,26 @@ export default function useActions( // Returns all items that do not have an existing junction and related item. function getNewItems() { - const { junctionField, relationPkField } = relation.value; + const { junctionPkField } = relation.value; - if (value.value === null || junctionField === null) return []; + if (value.value === null || junctionPkField === null) return []; - return value.value.filter( - (item) => typeof get(item, junctionField) === 'object' && has(item, [junctionField, relationPkField]) === false - ) as Record[]; + return value.value.filter((item: any) => typeof item === 'object' && !item?.[junctionPkField]) as Record< + string, + any + >[]; } // Returns a list of items which related or junction item does exist but had changes. function getUpdatedItems() { - const { junctionField, relationPkField } = relation.value; + const { junctionPkField } = relation.value; - if (value.value === null || junctionField === null) return []; + if (value.value === null || junctionPkField === null) return []; - return value.value.filter((item) => has(item, [junctionField, relationPkField])) as Record[]; + return value.value.filter((item: any) => typeof item === 'object' && item?.[junctionPkField]) as Record< + string, + any + >[]; } // Returns only items that do not have any changes what so ever. diff --git a/app/src/interfaces/list-m2m/use-preview.ts b/app/src/interfaces/list-m2m/use-preview.ts index 88ef05e238..96b1278e97 100644 --- a/app/src/interfaces/list-m2m/use-preview.ts +++ b/app/src/interfaces/list-m2m/use-preview.ts @@ -3,7 +3,7 @@ import { Header } from '@/components/v-table/types'; import { useFieldsStore } from '@/stores/'; import { Field } from '@directus/shared/types'; import { addRelatedPrimaryKeyToFields } from '@/utils/add-related-primary-key-to-fields'; -import { cloneDeep, get, merge } from 'lodash'; +import { cloneDeep, get, merge, isEqual } from 'lodash'; import { Ref, ref, watch } from 'vue'; import { RelationInfo } from '@/composables/use-m2m'; import { getEndpoint } from '@/utils/get-endpoint'; @@ -37,12 +37,14 @@ export default function usePreview( watch( () => value.value, - async (newVal) => { + async (newVal, oldVal) => { if (newVal === null) { items.value = []; return; } + if (isEqual(newVal, oldVal)) return; + loading.value = true; const { junctionField, relationPkField, junctionPkField, relationCollection } = relation.value; if (junctionField === null) return; @@ -87,7 +89,7 @@ export default function usePreview( .map((item) => { const updatedItem = updatedItems.find( (updated) => - get(updated, [junctionField, junctionPkField]) === get(item, [junctionField, junctionPkField]) + get(updated, [junctionField, relationPkField]) === get(item, [junctionField, relationPkField]) ); if (updatedItem !== undefined) return merge(item, updatedItem); return item; diff --git a/app/src/interfaces/list-m2m/use-selection.ts b/app/src/interfaces/list-m2m/use-selection.ts index 3b1a39e99e..7854d2693e 100644 --- a/app/src/interfaces/list-m2m/use-selection.ts +++ b/app/src/interfaces/list-m2m/use-selection.ts @@ -31,19 +31,19 @@ export default function useSelection( }); function stageSelection(newSelection: (number | string)[]) { - const { junctionField, junctionPkField } = relation.value; + const { junctionField, relationPkField } = relation.value; const selection = newSelection.map((item) => { - const initial = initialItems.value.find((existent) => existent[junctionField][junctionPkField] === item); - const draft = items.value.find((draft) => draft[junctionField][junctionPkField] === item); + const initial = initialItems.value.find((existent) => existent[junctionField][relationPkField] === item); + const draft = items.value.find((draft) => draft[junctionField][relationPkField] === item); return { ...initial, ...draft, [junctionField]: { - ...initial?.[junctionPkField], - ...draft?.[junctionPkField], - [junctionPkField]: item, + ...initial?.[relationPkField], + ...draft?.[relationPkField], + [relationPkField]: item, }, }; });