From d34a9e12e235f3c0051aed28e1d9d5f5cea4216f Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 25 Feb 2021 09:41:04 +0000 Subject: [PATCH 01/10] Having the server send out _id and primaryDisplay in an object for relationships, also accepting objects and coercing them on way in. --- packages/server/src/api/routes/tests/row.spec.js | 5 +++-- packages/server/src/db/linkedRows/index.js | 9 +++++---- packages/server/src/utilities/rowProcessor.js | 3 +++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.js b/packages/server/src/api/routes/tests/row.spec.js index 1c11369ae5..777a99b091 100644 --- a/packages/server/src/api/routes/tests/row.spec.js +++ b/packages/server/src/api/routes/tests/row.spec.js @@ -282,12 +282,13 @@ describe("/rows", () => { const secondRow = (await createRow({ name: "Test 2", description: "og desc", - link: [firstRow._id], + link: [{_id: firstRow._id}], tableId: table._id, })).body const enriched = await outputProcessing(appId, table, [secondRow]) expect(enriched[0].link.length).toBe(1) - expect(enriched[0].link[0]).toBe("Test Contact") + expect(enriched[0].link[0]._id).toBe(firstRow._id) + expect(enriched[0].link[0].primaryDisplay).toBe("Test Contact") }) }) diff --git a/packages/server/src/db/linkedRows/index.js b/packages/server/src/db/linkedRows/index.js index f60c4c7f26..052386ba86 100644 --- a/packages/server/src/db/linkedRows/index.js +++ b/packages/server/src/db/linkedRows/index.js @@ -175,11 +175,12 @@ exports.attachLinkedPrimaryDisplay = async (appId, table, rows) => { if (!linkedRow || !linkedTable) { continue } - // need to handle an edge case where relationship just wasn't found - const value = linkedRow[linkedTable.primaryDisplay] || linkedRow._id - if (value) { - row[link.fieldName].push(value) + const obj = { _id: linkedRow._id } + // if we know the display column, add it + if (linkedRow[linkedTable.primaryDisplay] != null) { + obj.primaryDisplay = linkedRow[linkedTable.primaryDisplay] } + row[link.fieldName].push(obj) } } return rows diff --git a/packages/server/src/utilities/rowProcessor.js b/packages/server/src/utilities/rowProcessor.js index 32c488aed7..eea34efc30 100644 --- a/packages/server/src/utilities/rowProcessor.js +++ b/packages/server/src/utilities/rowProcessor.js @@ -15,6 +15,9 @@ const TYPE_TRANSFORM_MAP = { [null]: [], [undefined]: undefined, parse: link => { + if (Array.isArray(link) && typeof link[0] === "object") { + return link.map(el => (el && el._id ? el._id : el)) + } if (typeof link === "string") { return [link] } From 73d19f53d1456d41582fa23fe67d7acbffb70cb0 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 25 Feb 2021 11:05:46 +0000 Subject: [PATCH 02/10] Add support for new relationship object in backend table --- .../components/backend/DataTable/cells/RelationshipCell.svelte | 2 +- .../{RelationshipCount.svelte => RelationshipLabel.svelte} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename packages/standard-components/src/grid/Relationship/{RelationshipCount.svelte => RelationshipLabel.svelte} (91%) diff --git a/packages/builder/src/components/backend/DataTable/cells/RelationshipCell.svelte b/packages/builder/src/components/backend/DataTable/cells/RelationshipCell.svelte index 2d85a184d9..0aae16f3db 100644 --- a/packages/builder/src/components/backend/DataTable/cells/RelationshipCell.svelte +++ b/packages/builder/src/components/backend/DataTable/cells/RelationshipCell.svelte @@ -11,7 +11,7 @@ class:link={!!items.length} on:click={() => selectRelationship(row, columnName)}> {#each items as item} -
{item}
+
{item?.primaryDisplay ?? ''}
{/each} diff --git a/packages/standard-components/src/grid/Relationship/RelationshipCount.svelte b/packages/standard-components/src/grid/Relationship/RelationshipLabel.svelte similarity index 91% rename from packages/standard-components/src/grid/Relationship/RelationshipCount.svelte rename to packages/standard-components/src/grid/Relationship/RelationshipLabel.svelte index 6a96a0b90b..550dedc419 100644 --- a/packages/standard-components/src/grid/Relationship/RelationshipCount.svelte +++ b/packages/standard-components/src/grid/Relationship/RelationshipLabel.svelte @@ -7,7 +7,7 @@
{#each items as item} -
{item}
+
{item?.primaryDisplay}
{/each}
From 6d9c5cdf46971b0d13c312be2608314eb0b6ac2b Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 25 Feb 2021 11:06:16 +0000 Subject: [PATCH 03/10] Add support for new relationship objects in client apps --- .../standard-components/src/forms/Form.svelte | 2 +- .../src/forms/Picker.svelte | 2 +- .../src/forms/RelationshipField.svelte | 21 +++++++++++-------- .../Relationship/RelationshipLabel.svelte | 2 +- .../src/grid/customRenderer.js | 4 ++-- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/standard-components/src/forms/Form.svelte b/packages/standard-components/src/forms/Form.svelte index e51a31955e..92002ed4a5 100644 --- a/packages/standard-components/src/forms/Form.svelte +++ b/packages/standard-components/src/forms/Form.svelte @@ -35,7 +35,7 @@ // Form API contains functions to control the form const formApi = { - registerField: (field, defaultValue = null, fieldDisabled = false) => { + registerField: (field, defaultValue = undefined, fieldDisabled = false) => { if (!field) { return } diff --git a/packages/standard-components/src/forms/Picker.svelte b/packages/standard-components/src/forms/Picker.svelte index 894a070070..e633f7439e 100644 --- a/packages/standard-components/src/forms/Picker.svelte +++ b/packages/standard-components/src/forms/Picker.svelte @@ -57,7 +57,7 @@ role="option" aria-selected="true" tabindex="0" - on:click={() => onSelectOption(null)}> + on:click={() => onSelectOption(undefined)}> {placeholderOption} { if (fieldSchema?.relationshipType === "one-to-many") { if (value?.length && options?.length) { - const row = options.find(row => row._id === value[0]) + const row = options.find(row => row._id === value[0]?._id) return getDisplayName(row) } else { return placeholder || "Choose an option" @@ -60,27 +60,30 @@ } const getDisplayName = row => { - return row[tableDefinition?.primaryDisplay || "_id"] + return row?.[tableDefinition?.primaryDisplay || "_id"] || "-" } const getValueLookupMap = value => { let map = {} if (value?.length) { value.forEach(option => { - map[option] = true + if (option?._id) { + map[option._id] = true + } }) } return map } - const toggleOption = option => { - if (fieldSchema.type === "one-to-many") { - fieldApi.setValue([option]) + const toggleOption = id => { + if (fieldSchema.relationshipType === "one-to-many") { + fieldApi.setValue([{ _id: id }]) } else { - if ($fieldState.value.includes(option)) { - fieldApi.setValue($fieldState.value.filter(x => x !== option)) + if ($fieldState.value.find(option => option?._id === id)) { + const filtered = $fieldState.value.filter(option => option?._id !== id) + fieldApi.setValue(filtered) } else { - fieldApi.setValue([...$fieldState.value, option]) + fieldApi.setValue([...$fieldState.value, { _id: id }]) } } } diff --git a/packages/standard-components/src/grid/Relationship/RelationshipLabel.svelte b/packages/standard-components/src/grid/Relationship/RelationshipLabel.svelte index 550dedc419..ec64255855 100644 --- a/packages/standard-components/src/grid/Relationship/RelationshipLabel.svelte +++ b/packages/standard-components/src/grid/Relationship/RelationshipLabel.svelte @@ -7,7 +7,7 @@
{#each items as item} -
{item?.primaryDisplay}
+
{item?.primaryDisplay ?? ''}
{/each}
diff --git a/packages/standard-components/src/grid/customRenderer.js b/packages/standard-components/src/grid/customRenderer.js index acb72639a6..fd558baa98 100644 --- a/packages/standard-components/src/grid/customRenderer.js +++ b/packages/standard-components/src/grid/customRenderer.js @@ -5,7 +5,7 @@ import AttachmentCell from "./AttachmentCell/Button.svelte" import ViewDetails from "./ViewDetails/Cell.svelte" import Select from "./Select/Wrapper.svelte" import DatePicker from "./DateTime/Wrapper.svelte" -import RelationshipCount from "./Relationship/RelationshipCount.svelte" +import RelationshipLabel from "./Relationship/RelationshipLabel.svelte" const renderers = new Map([ ["boolean", booleanRenderer], @@ -127,7 +127,7 @@ function linkedRowRenderer(options, constraints, editable, SDK) { container.style.placeItems = "center" container.style.height = "100%" - new RelationshipCount({ + new RelationshipLabel({ target: container, props: { row: params.data, From 69fcaebc4de88b890011f93eaa069efaccbf71c9 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 25 Feb 2021 11:06:46 +0000 Subject: [PATCH 04/10] Add support for new relationship objects in client app bindings --- packages/client/src/api/rows.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/client/src/api/rows.js b/packages/client/src/api/rows.js index 54c0179cc8..639516f0f6 100644 --- a/packages/client/src/api/rows.js +++ b/packages/client/src/api/rows.js @@ -120,7 +120,11 @@ export const enrichRows = async (rows, tableId) => { const type = schema[key].type if (type === "link") { // Enrich row a string join of relationship fields - row[`${key}_text`] = row[key]?.join(", ") || "" + row[`${key}_text`] = + row[key] + ?.map(option => option?.primaryDisplay) + .filter(option => !!option) + .join(", ") || "" } else if (type === "attachment") { // Enrich row with the first image URL for any attachment fields let url = null From 63db4edbbe562599ec673d0e20cfd45162cd7b14 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 25 Feb 2021 11:09:00 +0000 Subject: [PATCH 05/10] Fixing an issue with option fields not being unselectable. --- packages/server/src/api/controllers/row.js | 14 ++++++++++---- packages/server/src/utilities/rowProcessor.js | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/server/src/api/controllers/row.js b/packages/server/src/api/controllers/row.js index 4ce664413e..413fedc6cd 100644 --- a/packages/server/src/api/controllers/row.js +++ b/packages/server/src/api/controllers/row.js @@ -15,6 +15,7 @@ const { } = require("../../utilities/rowProcessor") const { FieldTypes } = require("../../constants") const { isEqual } = require("lodash") +const { cloneDeep } = require("lodash/fp") const TABLE_VIEW_BEGINS_WITH = `all${SEPARATOR}${DocumentTypes.TABLE}${SEPARATOR}` @@ -351,10 +352,15 @@ async function validate({ appId, tableId, row, table }) { } const errors = {} for (let fieldName of Object.keys(table.schema)) { - const res = validateJs.single( - row[fieldName], - table.schema[fieldName].constraints - ) + const constraints = cloneDeep(table.schema[fieldName].constraints) + // special case for options, need to always allow unselected (null) + if ( + table.schema[fieldName].type === FieldTypes.OPTIONS && + constraints.inclusion + ) { + constraints.inclusion.push(null) + } + const res = validateJs.single(row[fieldName], constraints) if (res) errors[fieldName] = res } return { valid: Object.keys(errors).length === 0, errors } diff --git a/packages/server/src/utilities/rowProcessor.js b/packages/server/src/utilities/rowProcessor.js index eea34efc30..ee2a05f856 100644 --- a/packages/server/src/utilities/rowProcessor.js +++ b/packages/server/src/utilities/rowProcessor.js @@ -25,7 +25,7 @@ const TYPE_TRANSFORM_MAP = { }, }, [FieldTypes.OPTIONS]: { - "": "", + "": null, [null]: "", [undefined]: undefined, }, From f134724ed6c33e7740178096ac2e70870dad154f Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 25 Feb 2021 11:26:28 +0000 Subject: [PATCH 06/10] Fixing coercion of null to empty string for options fields. --- packages/server/src/utilities/rowProcessor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/utilities/rowProcessor.js b/packages/server/src/utilities/rowProcessor.js index ee2a05f856..b76177865b 100644 --- a/packages/server/src/utilities/rowProcessor.js +++ b/packages/server/src/utilities/rowProcessor.js @@ -26,7 +26,7 @@ const TYPE_TRANSFORM_MAP = { }, [FieldTypes.OPTIONS]: { "": null, - [null]: "", + [null]: null, [undefined]: undefined, }, [FieldTypes.STRING]: { From 45d9845806e25035c3a9aff713c742e14b295529 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 25 Feb 2021 11:34:11 +0000 Subject: [PATCH 07/10] Update picker to use null as default placeholder value --- packages/standard-components/src/forms/Form.svelte | 2 +- packages/standard-components/src/forms/Picker.svelte | 2 +- packages/standard-components/src/forms/RelationshipField.svelte | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/standard-components/src/forms/Form.svelte b/packages/standard-components/src/forms/Form.svelte index 92002ed4a5..e51a31955e 100644 --- a/packages/standard-components/src/forms/Form.svelte +++ b/packages/standard-components/src/forms/Form.svelte @@ -35,7 +35,7 @@ // Form API contains functions to control the form const formApi = { - registerField: (field, defaultValue = undefined, fieldDisabled = false) => { + registerField: (field, defaultValue = null, fieldDisabled = false) => { if (!field) { return } diff --git a/packages/standard-components/src/forms/Picker.svelte b/packages/standard-components/src/forms/Picker.svelte index e633f7439e..894a070070 100644 --- a/packages/standard-components/src/forms/Picker.svelte +++ b/packages/standard-components/src/forms/Picker.svelte @@ -57,7 +57,7 @@ role="option" aria-selected="true" tabindex="0" - on:click={() => onSelectOption(undefined)}> + on:click={() => onSelectOption(null)}> {placeholderOption} { if (fieldSchema.relationshipType === "one-to-many") { - fieldApi.setValue([{ _id: id }]) + fieldApi.setValue(id ? [{ _id: id }] : []) } else { if ($fieldState.value.find(option => option?._id === id)) { const filtered = $fieldState.value.filter(option => option?._id !== id) From 559b4d8314ae0a9cb29c445fcb72578b9d5a8d32 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 25 Feb 2021 11:34:35 +0000 Subject: [PATCH 08/10] Update backend linked row selector to support new relationship object --- .../src/components/common/LinkedRowSelector.svelte | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/builder/src/components/common/LinkedRowSelector.svelte b/packages/builder/src/components/common/LinkedRowSelector.svelte index ac660d4a71..5ac1efbc54 100644 --- a/packages/builder/src/components/common/LinkedRowSelector.svelte +++ b/packages/builder/src/components/common/LinkedRowSelector.svelte @@ -1,5 +1,4 @@