From c4a516ccb37e838038011ba39d198e65a1ca2c79 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 4 Oct 2023 09:25:35 +0100 Subject: [PATCH] Ensure grid schema structure is predictable and prevent copying IDs for query datasources --- .../components/grid/cells/HeaderCell.svelte | 7 +-- .../grid/overlays/MenuOverlay.svelte | 4 +- .../src/components/grid/stores/columns.js | 33 +++++++------ .../src/components/grid/stores/datasource.js | 48 +++++++++++-------- .../src/components/grid/stores/rows.js | 2 +- .../src/components/grid/stores/sort.js | 15 +++--- 6 files changed, 61 insertions(+), 48 deletions(-) diff --git a/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte b/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte index a58b4c8fe4..5ac70c93c8 100644 --- a/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte @@ -22,6 +22,7 @@ columns, definition, datasource, + schema, } = getContext("grid") const bannedDisplayColumnTypes = [ @@ -126,16 +127,16 @@ // Generate new name let newName = `${column.name} copy` let attempts = 2 - while ($definition.schema[newName]) { + while ($schema[newName]) { newName = `${column.name} copy ${attempts++}` } // Save schema with new column - const existingColumnDefinition = $definition.schema[column.name] + const existingColumnDefinition = $schema[column.name] await datasource.actions.saveDefinition({ ...$definition, schema: { - ...$definition.schema, + ...$schema, [newName]: { ...existingColumnDefinition, name: newName, diff --git a/packages/frontend-core/src/components/grid/overlays/MenuOverlay.svelte b/packages/frontend-core/src/components/grid/overlays/MenuOverlay.svelte index cbf2c6ee4e..7fb2bb138d 100644 --- a/packages/frontend-core/src/components/grid/overlays/MenuOverlay.svelte +++ b/packages/frontend-core/src/components/grid/overlays/MenuOverlay.svelte @@ -75,7 +75,9 @@ copyToClipboard($focusedRow?._id)} on:click={menu.actions.close} > diff --git a/packages/frontend-core/src/components/grid/stores/columns.js b/packages/frontend-core/src/components/grid/stores/columns.js index 629d5dd893..c36afea7a1 100644 --- a/packages/frontend-core/src/components/grid/stores/columns.js +++ b/packages/frontend-core/src/components/grid/stores/columns.js @@ -69,7 +69,7 @@ export const deriveStores = context => { } export const createActions = context => { - const { columns, stickyColumn, datasource, definition } = context + const { columns, stickyColumn, datasource, definition, schema } = context // Updates the datasources primary display column const changePrimaryDisplay = async column => { @@ -101,7 +101,7 @@ export const createActions = context => { const $columns = get(columns) const $definition = get(definition) const $stickyColumn = get(stickyColumn) - const newSchema = cloneDeep($definition.schema) + let newSchema = cloneDeep(get(schema)) || {} // Build new updated datasource schema Object.keys(newSchema).forEach(column => { @@ -142,11 +142,11 @@ export const createActions = context => { } export const initialise = context => { - const { definition, columns, stickyColumn, schema } = context + const { definition, columns, stickyColumn, enrichedSchema } = context // Merge new schema fields with existing schema in order to preserve widths - schema.subscribe($schema => { - if (!$schema) { + enrichedSchema.subscribe($enrichedSchema => { + if (!$enrichedSchema) { columns.set([]) stickyColumn.set(null) return @@ -155,13 +155,16 @@ export const initialise = context => { // Find primary display let primaryDisplay - if ($definition.primaryDisplay && $schema[$definition.primaryDisplay]) { + if ( + $definition.primaryDisplay && + $enrichedSchema[$definition.primaryDisplay] + ) { primaryDisplay = $definition.primaryDisplay } // Get field list let fields = [] - Object.keys($schema).forEach(field => { + Object.keys($enrichedSchema).forEach(field => { if (field !== primaryDisplay) { fields.push(field) } @@ -172,11 +175,11 @@ export const initialise = context => { fields .map(field => ({ name: field, - label: $schema[field].displayName || field, - schema: $schema[field], - width: $schema[field].width || DefaultColumnWidth, - visible: $schema[field].visible ?? true, - order: $schema[field].order, + label: $enrichedSchema[field].displayName || field, + schema: $enrichedSchema[field], + width: $enrichedSchema[field].width || DefaultColumnWidth, + visible: $enrichedSchema[field].visible ?? true, + order: $enrichedSchema[field].order, })) .sort((a, b) => { // Sort by order first @@ -207,9 +210,9 @@ export const initialise = context => { } stickyColumn.set({ name: primaryDisplay, - label: $schema[primaryDisplay].displayName || primaryDisplay, - schema: $schema[primaryDisplay], - width: $schema[primaryDisplay].width || DefaultColumnWidth, + label: $enrichedSchema[primaryDisplay].displayName || primaryDisplay, + schema: $enrichedSchema[primaryDisplay], + width: $enrichedSchema[primaryDisplay].width || DefaultColumnWidth, visible: true, order: 0, left: GutterWidth, diff --git a/packages/frontend-core/src/components/grid/stores/datasource.js b/packages/frontend-core/src/components/grid/stores/datasource.js index e56b37a5f3..0d70424550 100644 --- a/packages/frontend-core/src/components/grid/stores/datasource.js +++ b/packages/frontend-core/src/components/grid/stores/datasource.js @@ -12,27 +12,36 @@ export const createStores = () => { export const deriveStores = context => { const { definition, schemaOverrides, columnWhitelist } = context - const schema = derived( - [definition, schemaOverrides, columnWhitelist], - ([$definition, $schemaOverrides, $columnWhitelist]) => { - if (!$definition?.schema) { + const schema = derived(definition, $definition => { + let schema = $definition?.schema + if (!schema) { + return null + } + + // Ensure schema is configured as objects. + // Certain datasources like queries use primitives. + Object.keys(schema || {}).forEach(key => { + if (typeof schema[key] !== "object") { + schema[key] = { type: schema[key] } + } + }) + + return schema + }) + + const enrichedSchema = derived( + [schema, schemaOverrides, columnWhitelist], + ([$schema, $schemaOverrides, $columnWhitelist]) => { + if (!$schema) { return null } - let newSchema = { ...$definition?.schema } - - // Ensure schema is configured as objects. - // Certain datasources like queries use primitives. - Object.keys(newSchema).forEach(key => { - if (typeof newSchema[key] !== "object") { - newSchema[key] = { type: newSchema[key] } - } - }) + let enrichedSchema = { ...$schema } // Apply schema overrides Object.keys($schemaOverrides || {}).forEach(field => { - if (newSchema[field]) { - newSchema[field] = { - ...newSchema[field], + if (enrichedSchema[field]) { + enrichedSchema[field] = { + ...enrichedSchema[field], ...$schemaOverrides[field], } } @@ -40,19 +49,20 @@ export const deriveStores = context => { // Apply whitelist if specified if ($columnWhitelist?.length) { - Object.keys(newSchema).forEach(key => { + Object.keys(enrichedSchema).forEach(key => { if (!$columnWhitelist.includes(key)) { - delete newSchema[key] + delete enrichedSchema[key] } }) } - return newSchema + return enrichedSchema } ) return { schema, + enrichedSchema, } } diff --git a/packages/frontend-core/src/components/grid/stores/rows.js b/packages/frontend-core/src/components/grid/stores/rows.js index 2e2832f209..1eafb20756 100644 --- a/packages/frontend-core/src/components/grid/stores/rows.js +++ b/packages/frontend-core/src/components/grid/stores/rows.js @@ -418,7 +418,7 @@ export const createActions = context => { // Ensure we have a unique _id. // This means generating one for non DS+. if (!newRow._id) { - newRow._id = Helpers.hashString(JSON.stringify(newRow)) + newRow._id = `fake-${Helpers.hashString(JSON.stringify(newRow))}` } if (!rowCacheMap[newRow._id]) { diff --git a/packages/frontend-core/src/components/grid/stores/sort.js b/packages/frontend-core/src/components/grid/stores/sort.js index 734a876eed..336570d012 100644 --- a/packages/frontend-core/src/components/grid/stores/sort.js +++ b/packages/frontend-core/src/components/grid/stores/sort.js @@ -17,7 +17,7 @@ export const createStores = context => { } export const initialise = context => { - const { sort, initialSortColumn, initialSortOrder, definition } = context + const { sort, initialSortColumn, initialSortOrder, schema } = context // Reset sort when initial sort props change initialSortColumn.subscribe(newSortColumn => { @@ -28,15 +28,12 @@ export const initialise = context => { }) // Derive if the current sort column exists in the schema - const sortColumnExists = derived( - [sort, definition], - ([$sort, $definition]) => { - if (!$sort?.column || !$definition) { - return true - } - return $definition.schema?.[$sort.column] != null + const sortColumnExists = derived([sort, schema], ([$sort, $schema]) => { + if (!$sort?.column || !$schema) { + return true } - ) + return $schema[$sort.column] != null + }) // Clear sort state if our sort column does not exist sortColumnExists.subscribe(exists => {