diff --git a/packages/frontend-core/src/components/grid/cells/RelationshipCell.svelte b/packages/frontend-core/src/components/grid/cells/RelationshipCell.svelte index 462d53445d..d91655a715 100644 --- a/packages/frontend-core/src/components/grid/cells/RelationshipCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/RelationshipCell.svelte @@ -7,7 +7,7 @@ const { API, cache } = getContext("grid") - export let value + export let value = [] export let api export let readonly export let focused @@ -29,10 +29,12 @@ let searching = false let container let anchor + let cacheStr + $: fieldValue = parseValue(value) $: oneRowOnly = schema?.relationshipType === "one-to-many" $: editable = focused && !readonly - $: lookupMap = buildLookupMap(value, isOpen) + $: lookupMap = buildLookupMap(fieldValue, isOpen) $: debouncedSearch(searchString) $: { if (!focused && isOpen) { @@ -40,6 +42,22 @@ } } + const parseValue = value => { + // Is it unset or a valid array? 1+ + const isValid = val => + !val || + (Array.isArray(val) && + (val.length === 0 || + val.some(relEntry => Object.hasOwn(relEntry, "_id")))) + + const stf = JSON.stringify(value) + if (!cacheStr || cacheStr !== stf) { + cacheStr = stf + return isValid(value) ? [...(value || [])] : [] + } + return [...(value || [])] + } + // Builds a lookup map to quickly check which rows are selected const buildLookupMap = (value, isOpen) => { let map = {} @@ -177,13 +195,13 @@ // Toggles whether a row is included in the relationship or not const toggleRow = async row => { - if (value?.some(x => x._id === row._id)) { + if (fieldValue?.some(x => x._id === row._id)) { // If the row is already included, remove it and update the candidate // row to be the same position if possible if (oneRowOnly) { await onChange([]) } else { - const newValue = value.filter(x => x._id !== row._id) + const newValue = fieldValue.filter(x => x._id !== row._id) if (!newValue.length) { candidateIndex = null } else { @@ -196,7 +214,7 @@ if (oneRowOnly) { await onChange([row]) } else { - await onChange(sortRows([...(value || []), row])) + await onChange(sortRows([...(fieldValue || []), row])) } candidateIndex = null } @@ -238,7 +256,7 @@ class:wrap={editable || contentLines > 1} on:wheel={e => (focused ? e.stopPropagation() : null)} > - {#each value || [] as relationship} + {#each fieldValue || [] as relationship} {#if relationship[primaryDisplay] || relationship.primaryDisplay}
@@ -263,9 +281,9 @@
{/if} - {#if !hideCounter && value?.length} + {#if !hideCounter && fieldValue?.length}
- {value?.length || 0} + {fieldValue?.length || 0}
{/if} diff --git a/packages/server/src/db/linkedRows/LinkController.ts b/packages/server/src/db/linkedRows/LinkController.ts index ffc9e32fde..4de5506e05 100644 --- a/packages/server/src/db/linkedRows/LinkController.ts +++ b/packages/server/src/db/linkedRows/LinkController.ts @@ -172,6 +172,11 @@ class LinkController { const rowField = row[fieldName] const field = table.schema[fieldName] if (field.type === FieldType.LINK && rowField != null) { + // Expects an array of docs with at least their _id + if (!Array.isArray(rowField)) { + throw new Error("Relationship Error: Invalid request") + } + // check which links actual pertain to the update in this row const thisFieldLinkDocs = linkDocs.filter( linkDoc =>