From e1a9762d21c14a3994b46f5463dfc1fd23c0a7a8 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 8 Apr 2024 09:33:02 +0100 Subject: [PATCH 01/10] Always allow selecting rows in grids in apps, and add binding for grid selected rows --- packages/client/manifest.json | 20 ++++++++--- .../src/components/app/GridBlock.svelte | 34 ++++++++++++++++--- packages/client/src/utils/buttonActions.js | 1 + .../components/grid/cells/GutterCell.svelte | 20 ++++------- .../src/components/grid/layout/Grid.svelte | 2 ++ 5 files changed, 56 insertions(+), 21 deletions(-) diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 08d614391b..ec2f8f1597 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -6739,10 +6739,22 @@ ] } ], - "context": { - "type": "schema", - "scope": "local" - }, + "context": [ + { + "type": "schema", + "scope": "local" + }, + { + "type": "static", + "values": [ + { + "label": "Selected rows", + "key": "selectedRows", + "type": "array" + } + ] + } + ], "actions": ["RefreshDatasource"] }, "bbreferencefield": { diff --git a/packages/client/src/components/app/GridBlock.svelte b/packages/client/src/components/app/GridBlock.svelte index 46a507387d..52a8e963c7 100644 --- a/packages/client/src/components/app/GridBlock.svelte +++ b/packages/client/src/components/app/GridBlock.svelte @@ -1,8 +1,8 @@
- + { let selection = rowSelectionStore.actions.getSelection( action.parameters.tableComponentId ) + console.log(selection) if (selection.selectedRows && selection.selectedRows.length > 0) { try { const data = await API.exportRows({ diff --git a/packages/frontend-core/src/components/grid/cells/GutterCell.svelte b/packages/frontend-core/src/components/grid/cells/GutterCell.svelte index 377405786d..60b41a2b87 100644 --- a/packages/frontend-core/src/components/grid/cells/GutterCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/GutterCell.svelte @@ -16,6 +16,8 @@ const { config, dispatch, selectedRows } = getContext("grid") const svelteDispatch = createEventDispatcher() + $: selectionEnabled = $config.canSelectRows || $config.canDeleteRows + const select = e => { e.stopPropagation() svelteDispatch("select") @@ -52,7 +54,7 @@
@@ -60,7 +62,7 @@ {#if !disableNumber}
{row.__idx + 1} @@ -117,19 +119,11 @@ .expand { margin-right: 4px; } - .expand { + .expand:not(.visible), + .expand:not(.visible) :global(*) { opacity: 0; + pointer-events: none !important; } - .expand :global(.spectrum-Icon) { - pointer-events: none; - } - .expand.visible { - opacity: 1; - } - .expand.visible :global(.spectrum-Icon) { - pointer-events: all; - } - .delete:hover { cursor: pointer; } diff --git a/packages/frontend-core/src/components/grid/layout/Grid.svelte b/packages/frontend-core/src/components/grid/layout/Grid.svelte index 1d2220951c..bee86a21c8 100644 --- a/packages/frontend-core/src/components/grid/layout/Grid.svelte +++ b/packages/frontend-core/src/components/grid/layout/Grid.svelte @@ -38,6 +38,7 @@ export let canDeleteRows = true export let canEditColumns = true export let canSaveSchema = true + export let canSelectRows = false export let stripeRows = false export let collaboration = true export let showAvatars = true @@ -90,6 +91,7 @@ canDeleteRows, canEditColumns, canSaveSchema, + canSelectRows, stripeRows, collaboration, showAvatars, From 53bbaac7511fbded877ceecc912ede74d7d015a9 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 8 Apr 2024 16:17:22 +0100 Subject: [PATCH 02/10] Update export data action to work with new table component --- .../actions/ExportData.svelte | 32 +++++++---- .../src/components/app/GridBlock.svelte | 27 +++++---- packages/client/src/stores/rowSelection.js | 2 +- packages/client/src/utils/buttonActions.js | 56 ++++++++++++------- .../src/components/grid/stores/ui.js | 6 +- 5 files changed, 74 insertions(+), 49 deletions(-) diff --git a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExportData.svelte b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExportData.svelte index 096341783d..6ed0135844 100644 --- a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExportData.svelte +++ b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExportData.svelte @@ -49,26 +49,34 @@ }, ] - $: tables = findAllMatchingComponents($selectedScreen?.props, component => - component._component.endsWith("table") - ) - $: tableBlocks = findAllMatchingComponents( + $: components = findAllMatchingComponents( $selectedScreen?.props, - component => component._component.endsWith("tableblock") + component => { + const type = component._component + return ( + type.endsWith("/table") || + type.endsWith("/tableblock") || + type.endsWith("/gridblock") + ) + } ) - $: components = tables.concat(tableBlocks) - $: componentOptions = components.map(table => ({ - label: table._instanceName, - value: table._component.includes("tableblock") - ? `${table._id}-table` - : table._id, - })) + $: componentOptions = components.map(component => { + let value = component._id + if (component._component.endsWith("/tableblock")) { + value = `${component._id}-table` + } + return { + label: component._instanceName, + value, + } + }) $: selectedTableId = parameters.tableComponentId?.includes("-") ? parameters.tableComponentId.split("-")[0] : parameters.tableComponentId $: selectedTable = components.find( component => component._id === selectedTableId ) + $: parameters.rows = `{{ literal [${parameters.tableComponentId}].[selectedRows] }}` onMount(() => { if (!parameters.type) { diff --git a/packages/client/src/components/app/GridBlock.svelte b/packages/client/src/components/app/GridBlock.svelte index 52a8e963c7..e2d901cdb5 100644 --- a/packages/client/src/components/app/GridBlock.svelte +++ b/packages/client/src/components/app/GridBlock.svelte @@ -36,12 +36,10 @@ let grid let gridContext - $: columnWhitelist = parsedColumns - ?.filter(col => col.active) - ?.map(col => col.field) + $: parsedColumns = getParsedColumns(columns) + $: columnWhitelist = parsedColumns.filter(x => x.active).map(x => x.field) $: schemaOverrides = getSchemaOverrides(parsedColumns) $: enrichedButtons = enrichButtons(buttons) - $: parsedColumns = getParsedColumns(columns) $: selectedRows = deriveSelectedRows(gridContext) $: data = { selectedRows: $selectedRows } $: actions = [ @@ -67,12 +65,14 @@ // Parses columns to fix older formats const getParsedColumns = columns => { + if (!columns?.length) { + return [] + } // If the first element has an active key all elements should be in the new format - if (columns?.length && columns[0]?.active !== undefined) { + if (columns[0].active !== undefined) { return columns } - - return columns?.map(column => ({ + return columns.map(column => ({ label: column.displayName || column.name, field: column.name, active: true, @@ -81,7 +81,7 @@ const getSchemaOverrides = columns => { let overrides = {} - columns?.forEach(column => { + columns.forEach(column => { overrides[column.field] = { displayName: column.label, } @@ -115,13 +115,12 @@ return derived( [gridContext.selectedRows, gridContext.rowLookupMap, gridContext.rows], ([$selectedRows, $rowLookupMap, $rows]) => { - const rowIds = Object.entries($selectedRows || {}) + return Object.entries($selectedRows || {}) .filter(([_, selected]) => selected) - .map(([rowId]) => rowId) - return rowIds.map(id => { - const idx = $rowLookupMap[id] - return gridContext.rows.actions.cleanRow($rows[idx]) - }) + .map(([rowId]) => { + const idx = $rowLookupMap[rowId] + return gridContext.rows.actions.cleanRow($rows[idx]) + }) } ) } diff --git a/packages/client/src/stores/rowSelection.js b/packages/client/src/stores/rowSelection.js index 4c0a196678..554c3645f0 100644 --- a/packages/client/src/stores/rowSelection.js +++ b/packages/client/src/stores/rowSelection.js @@ -15,7 +15,7 @@ const createRowSelectionStore = () => { const componentId = Object.keys(selection).find( componentId => componentId === tableComponentId ) - return selection[componentId] || {} + return selection[componentId] } return { diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js index 710fac085d..1532a9c85b 100644 --- a/packages/client/src/utils/buttonActions.js +++ b/packages/client/src/utils/buttonActions.js @@ -332,31 +332,49 @@ const s3UploadHandler = async action => { } const exportDataHandler = async action => { - let selection = rowSelectionStore.actions.getSelection( - action.parameters.tableComponentId - ) - console.log(selection) - if (selection.selectedRows && selection.selectedRows.length > 0) { + let { tableComponentId, rows, type, columns, delimiter, customHeaders } = + action.parameters + + // Handle legacy configs using the row selection store + if (!rows?.length) { + const selection = rowSelectionStore.actions.getSelection(tableComponentId) + if (selection?.rows?.length) { + rows = selection.selectedRows + } + } + + // Get table ID from first row + const tableId = rows?.[0]?.tableId + + // Handle no rows selected + if (!rows?.length) { + notificationStore.actions.error("Please select at least one row") + } + // Handle case where we're not using a DS+ + else if (!tableId) { + notificationStore.actions.error( + "Exporting data only works for tables and views" + ) + } + // Happy path when we have both rows and table ID + else { try { + // Flatten rows if required + if (typeof rows[0] !== "string") { + rows = rows.map(row => row._id) + } const data = await API.exportRows({ - tableId: selection.tableId, - rows: selection.selectedRows, - format: action.parameters.type, - columns: action.parameters.columns?.map( - column => column.name || column - ), - delimiter: action.parameters.delimiter, - customHeaders: action.parameters.customHeaders, + tableId, + rows, + format: type, + columns: columns?.map(column => column.name || column), + delimiter, + customHeaders, }) - download( - new Blob([data], { type: "text/plain" }), - `${selection.tableId}.${action.parameters.type}` - ) + download(new Blob([data], { type: "text/plain" }), `${tableId}.${type}`) } catch (error) { notificationStore.actions.error("There was an error exporting the data") } - } else { - notificationStore.actions.error("Please select at least one row") } } diff --git a/packages/frontend-core/src/components/grid/stores/ui.js b/packages/frontend-core/src/components/grid/stores/ui.js index da0558bb5b..656db3627e 100644 --- a/packages/frontend-core/src/components/grid/stores/ui.js +++ b/packages/frontend-core/src/components/grid/stores/ui.js @@ -113,9 +113,9 @@ export const createActions = context => { // Callback when leaving the grid, deselecting all focussed or selected items const blur = () => { - focusedCellId.set(null) - selectedRows.set({}) - hoveredRowId.set(null) + // focusedCellId.set(null) + // selectedRows.set({}) + // hoveredRowId.set(null) } return { From 8e7e2ddb99895a258ee5278bfed1aa93f8c11d5c Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 8 Apr 2024 16:19:06 +0100 Subject: [PATCH 03/10] Clarify wording --- packages/client/src/utils/buttonActions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js index 1532a9c85b..2fa68ce424 100644 --- a/packages/client/src/utils/buttonActions.js +++ b/packages/client/src/utils/buttonActions.js @@ -353,7 +353,7 @@ const exportDataHandler = async action => { // Handle case where we're not using a DS+ else if (!tableId) { notificationStore.actions.error( - "Exporting data only works for tables and views" + "You can only export data from table datasources" ) } // Happy path when we have both rows and table ID From cfcda49c8038a3bbbce38666d585dc61c17cf2e0 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 8 Apr 2024 16:39:55 +0100 Subject: [PATCH 04/10] Fix data export for legacy configs --- packages/client/src/utils/buttonActions.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js index 2fa68ce424..c481fa5828 100644 --- a/packages/client/src/utils/buttonActions.js +++ b/packages/client/src/utils/buttonActions.js @@ -331,20 +331,29 @@ const s3UploadHandler = async action => { } } +/** + * For new configs, "rows" is defined and enriched to be the array of rows to + * export. For old configs it will be undefined and we need to use the legacy + * row selection store in combination with the tableComponentId parameter. + */ const exportDataHandler = async action => { let { tableComponentId, rows, type, columns, delimiter, customHeaders } = action.parameters + let tableId // Handle legacy configs using the row selection store if (!rows?.length) { const selection = rowSelectionStore.actions.getSelection(tableComponentId) - if (selection?.rows?.length) { + if (selection?.selectedRows?.length) { rows = selection.selectedRows + tableId = selection.tableId } } - // Get table ID from first row - const tableId = rows?.[0]?.tableId + // Get table ID from first row if needed + if (!tableId) { + tableId = rows?.[0]?.tableId + } // Handle no rows selected if (!rows?.length) { From 1ec9acc855f71d8509af66eb41609e6ebd8ec080 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 8 Apr 2024 16:46:05 +0100 Subject: [PATCH 05/10] Revert unnecessary changes --- .../ButtonActionEditor/actions/ExportData.svelte | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExportData.svelte b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExportData.svelte index 6ed0135844..a857bc7ede 100644 --- a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExportData.svelte +++ b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExportData.svelte @@ -60,16 +60,12 @@ ) } ) - $: componentOptions = components.map(component => { - let value = component._id - if (component._component.endsWith("/tableblock")) { - value = `${component._id}-table` - } - return { - label: component._instanceName, - value, - } - }) + $: componentOptions = components.map(table => ({ + label: table._instanceName, + value: table._component.endsWith("/tableblock") + ? `${table._id}-table` + : table._id, + })) $: selectedTableId = parameters.tableComponentId?.includes("-") ? parameters.tableComponentId.split("-")[0] : parameters.tableComponentId From 24d6bfcd0a8f0e68152cae4a6d7ee2abbe28119e Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 8 Apr 2024 16:49:37 +0100 Subject: [PATCH 06/10] Restore commented out code --- packages/frontend-core/src/components/grid/stores/ui.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/frontend-core/src/components/grid/stores/ui.js b/packages/frontend-core/src/components/grid/stores/ui.js index 656db3627e..8195abf446 100644 --- a/packages/frontend-core/src/components/grid/stores/ui.js +++ b/packages/frontend-core/src/components/grid/stores/ui.js @@ -109,13 +109,12 @@ export const deriveStores = context => { } export const createActions = context => { - const { focusedCellId, selectedRows, hoveredRowId } = context + const { focusedCellId, hoveredRowId } = context // Callback when leaving the grid, deselecting all focussed or selected items const blur = () => { - // focusedCellId.set(null) - // selectedRows.set({}) - // hoveredRowId.set(null) + focusedCellId.set(null) + hoveredRowId.set(null) } return { From 4516995ef5d2d67cca0b581c571695b864948e62 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 13 May 2024 13:44:50 +0100 Subject: [PATCH 07/10] Remove leftover repeat param in grids --- packages/client/src/components/app/GridBlock.svelte | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/client/src/components/app/GridBlock.svelte b/packages/client/src/components/app/GridBlock.svelte index 5b73019393..bf1dc5ede5 100644 --- a/packages/client/src/components/app/GridBlock.svelte +++ b/packages/client/src/components/app/GridBlock.svelte @@ -19,7 +19,6 @@ export let columns = null export let onRowClick = null export let buttons = null - export let repeat = null const context = getContext("context") const component = getContext("component") @@ -159,7 +158,6 @@ {fixedRowHeight} {columnWhitelist} {schemaOverrides} - {repeat} canAddRows={allowAddRows} canEditRows={allowEditRows} canDeleteRows={allowDeleteRows} From a5f627e320b01d395d1642c0c8315270a441d83d Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 13 May 2024 13:50:37 +0100 Subject: [PATCH 08/10] Move grid block provider top level since nesting doesn't matter --- .../src/components/app/GridBlock.svelte | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/packages/client/src/components/app/GridBlock.svelte b/packages/client/src/components/app/GridBlock.svelte index bf1dc5ede5..49b4d2127c 100644 --- a/packages/client/src/components/app/GridBlock.svelte +++ b/packages/client/src/components/app/GridBlock.svelte @@ -145,35 +145,35 @@
- - onRowClick?.({ row: e.detail })} - /> - + onRowClick?.({ row: e.detail })} + />
+ +