From 350edc2aecfc9bfd7cd44bf13ed00c66a6a1037f Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Fri, 11 Feb 2022 11:55:35 +0000 Subject: [PATCH] add row selection functionality to tables --- packages/bbui/src/Table/Table.svelte | 33 +++++-- .../builder/src/builderStore/dataBinding.js | 26 +++++- .../src/builderStore/store/frontend.js | 1 + packages/builder/src/stores/portal/apps.js | 1 - packages/client/manifest.json | 15 +++- .../client/src/components/ClientApp.svelte | 85 ++++++++++--------- .../src/components/app/table/Table.svelte | 13 ++- .../context/RowSelectionProvider.svelte | 8 ++ packages/client/src/sdk.js | 2 + packages/client/src/stores/index.js | 2 +- packages/client/src/stores/rowSelection.js | 21 +++++ 11 files changed, 153 insertions(+), 54 deletions(-) create mode 100644 packages/client/src/components/context/RowSelectionProvider.svelte create mode 100644 packages/client/src/stores/rowSelection.js diff --git a/packages/bbui/src/Table/Table.svelte b/packages/bbui/src/Table/Table.svelte index 09ade22627..64d39037fb 100644 --- a/packages/bbui/src/Table/Table.svelte +++ b/packages/bbui/src/Table/Table.svelte @@ -3,6 +3,7 @@ import "@spectrum-css/table/dist/index-vars.css" import CellRenderer from "./CellRenderer.svelte" import SelectEditRenderer from "./SelectEditRenderer.svelte" + import Checkbox from "../Form/Checkbox.svelte" import { cloneDeep } from "lodash" import { deepGet } from "../utils/helpers" @@ -29,7 +30,7 @@ export let editColumnTitle = "Edit" export let customRenderers = [] export let disableSorting = false - + export let allowSelectAllRows = false const dispatch = createEventDispatcher() // Config @@ -204,12 +205,27 @@ dispatch("editrow", cloneDeep(row)) } + const toggleSelectAll = e => { + if (!allowSelectAllRows) { + return + } + if (e.detail) { + selectedRows = rows + } else { + selectedRows = [] + } + } + const toggleSelectRow = row => { if (!allowSelectRows) { return } - if (selectedRows.includes(row)) { - selectedRows = selectedRows.filter(selectedRow => selectedRow !== row) + if ( + selectedRows.findIndex(selectedRow => selectedRow._id === row._id) === 0 + ) { + selectedRows = selectedRows.filter( + selectedRow => selectedRow._id !== row._id + ) } else { selectedRows = [...selectedRows, row] } @@ -234,7 +250,11 @@ {#if showEditColumn}
- {editColumnTitle || ""} + {#if allowSelectAllRows} + + {:else} + {editColumnTitle || ""} + {/if}
{/if} @@ -299,7 +319,9 @@
selectedRow._id === row._id + ) !== -1} onToggleSelection={() => toggleSelectRow(row)} onEdit={e => editRow(e, row)} {allowSelectRows} @@ -364,6 +386,7 @@ overflow: hidden; position: relative; z-index: 0; + cursor: pointer; } .container { diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js index 0f3cffc4fb..e8381aad1f 100644 --- a/packages/builder/src/builderStore/dataBinding.js +++ b/packages/builder/src/builderStore/dataBinding.js @@ -35,12 +35,14 @@ export const getBindableProperties = (asset, componentId) => { const urlBindings = getUrlBindings(asset) const deviceBindings = getDeviceBindings() const stateBindings = getStateBindings() + const rowBindings = getRowBindings() return [ ...contextBindings, ...urlBindings, ...stateBindings, ...userBindings, ...deviceBindings, + ...rowBindings, ] } @@ -321,13 +323,33 @@ const getDeviceBindings = () => { return bindings } +/** + * Gets all row bindings that are globally available. + */ +const getRowBindings = () => { + let bindings = [] + if (get(store).clientFeatures?.rowSelection) { + const safeState = makePropSafe("rowSelection") + bindings = [ + { + type: "context", + runtimeBinding: `${safeState}.${makePropSafe("row")}`, + readableBinding: "Rows", + }, + ] + + return bindings + } + return bindings +} + /** * Gets all state bindings that are globally available. */ const getStateBindings = () => { let bindings = [] - if (get(store).clientFeatures?.state) { - const safeState = makePropSafe("state") + if (get(store).clientFeatures?.rowSelection) { + const safeState = makePropSafe("rowSelection") bindings = getAllStateVariables().map(key => ({ type: "context", runtimeBinding: `${safeState}.${makePropSafe(key)}`, diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index d838150efc..c4935980be 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -42,6 +42,7 @@ const INITIAL_FRONTEND_STATE = { intelligentLoading: false, deviceAwareness: false, state: false, + rowSelection: false, customThemes: false, devicePreview: false, messagePassing: false, diff --git a/packages/builder/src/stores/portal/apps.js b/packages/builder/src/stores/portal/apps.js index de944c057d..21b01caf99 100644 --- a/packages/builder/src/stores/portal/apps.js +++ b/packages/builder/src/stores/portal/apps.js @@ -66,7 +66,6 @@ export function createAppStore() { } async function update(appId, value) { - console.log({ value }) const response = await api.put(`/api/applications/${appId}`, { ...value }) if (response.status === 200) { store.update(state => { diff --git a/packages/client/manifest.json b/packages/client/manifest.json index ab48142ad5..6ad752496e 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -6,7 +6,8 @@ "state": true, "customThemes": true, "devicePreview": true, - "messagePassing": true + "messagePassing": true, + "rowSelection": true }, "layout": { "name": "Layout", @@ -2707,6 +2708,13 @@ "key": "showAutoColumns", "defaultValue": false }, + { + "type": "boolean", + "label": "Allow row selection", + "key": "allowSelectRows", + "defaultValue": false + }, + { "type": "boolean", "label": "Link table rows", @@ -2961,6 +2969,11 @@ "label": "Show auto columns", "key": "showAutoColumns" }, + { + "type": "boolean", + "label": "Allow row selection", + "key": "allowSelectRows" + }, { "type": "boolean", "label": "Link table rows", diff --git a/packages/client/src/components/ClientApp.svelte b/packages/client/src/components/ClientApp.svelte index 7f5bed210e..649df0e377 100644 --- a/packages/client/src/components/ClientApp.svelte +++ b/packages/client/src/components/ClientApp.svelte @@ -19,6 +19,7 @@ import UserBindingsProvider from "components/context/UserBindingsProvider.svelte" import DeviceBindingsProvider from "components/context/DeviceBindingsProvider.svelte" import StateBindingsProvider from "components/context/StateBindingsProvider.svelte" + import RowSelectionProvider from "components/context/RowSelectionProvider.svelte" import SettingsBar from "components/preview/SettingsBar.svelte" import SelectionIndicator from "components/preview/SelectionIndicator.svelte" import HoverIndicator from "components/preview/HoverIndicator.svelte" @@ -90,59 +91,61 @@ - - - {#key $builderStore.selectedComponentId} - {#if $builderStore.inBuilder} - - {/if} - {/key} + + + + {#key $builderStore.selectedComponentId} + {#if $builderStore.inBuilder} + + {/if} + {/key} - -
- -
- - {#key $screenStore.activeLayout._id} - - {/key} + +
+ +
+ + {#key $screenStore.activeLayout._id} + + {/key} - -
+
- - - - + - {#if $builderStore.inBuilder} - - - - {/if} -
+ {#if $builderStore.inBuilder} + + + + {/if} +
+ diff --git a/packages/client/src/components/app/table/Table.svelte b/packages/client/src/components/app/table/Table.svelte index f462b93551..dfc27534ba 100644 --- a/packages/client/src/components/app/table/Table.svelte +++ b/packages/client/src/components/app/table/Table.svelte @@ -14,9 +14,11 @@ export let linkURL export let linkColumn export let linkPeek + export let allowSelectRows const component = getContext("component") - const { styleable, getAction, ActionTypes, routeStore } = getContext("sdk") + const { styleable, getAction, ActionTypes, routeStore, rowSelectionStore } = + getContext("sdk") const customColumnKey = `custom-${Math.random()}` const customRenderers = [ { @@ -24,7 +26,7 @@ component: SlotRenderer, }, ] - + let selectedRows = [] $: hasChildren = $component.children $: loading = dataProvider?.loading ?? false $: data = dataProvider?.rows || [] @@ -36,6 +38,9 @@ ActionTypes.SetDataProviderSorting ) + $: { + rowSelectionStore.actions.update(selectedRows) + } const getFields = (schema, customColumns, showAutoColumns) => { // Check for an invalid column selection let invalid = false @@ -112,7 +117,9 @@ {rowCount} {quiet} {customRenderers} - allowSelectRows={false} + {allowSelectRows} + bind:selectedRows + allowSelectAllRows={true} allowEditRows={false} allowEditColumns={false} showAutoColumns={true} diff --git a/packages/client/src/components/context/RowSelectionProvider.svelte b/packages/client/src/components/context/RowSelectionProvider.svelte new file mode 100644 index 0000000000..2c87a5fa00 --- /dev/null +++ b/packages/client/src/components/context/RowSelectionProvider.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/packages/client/src/sdk.js b/packages/client/src/sdk.js index 9803730541..c814294b55 100644 --- a/packages/client/src/sdk.js +++ b/packages/client/src/sdk.js @@ -6,6 +6,7 @@ import { screenStore, builderStore, uploadStore, + rowSelectionStore, } from "stores" import { styleable } from "utils/styleable" import { linkable } from "utils/linkable" @@ -19,6 +20,7 @@ export default { authStore, notificationStore, routeStore, + rowSelectionStore, screenStore, builderStore, uploadStore, diff --git a/packages/client/src/stores/index.js b/packages/client/src/stores/index.js index 9f6e5f6f50..ddd052fb4e 100644 --- a/packages/client/src/stores/index.js +++ b/packages/client/src/stores/index.js @@ -10,7 +10,7 @@ export { peekStore } from "./peek" export { stateStore } from "./state" export { themeStore } from "./theme" export { uploadStore } from "./uploads.js" - +export { rowSelectionStore } from "./rowSelection.js" // Context stores are layered and duplicated, so it is not a singleton export { createContextStore } from "./context" diff --git a/packages/client/src/stores/rowSelection.js b/packages/client/src/stores/rowSelection.js new file mode 100644 index 0000000000..40a86072f6 --- /dev/null +++ b/packages/client/src/stores/rowSelection.js @@ -0,0 +1,21 @@ +import { writable } from "svelte/store" + +const createRowSelectionStore = () => { + const store = writable([]) + + function update(rows) { + console.log(rows) + store.update(state => { + state = rows + return state + }) + } + return { + subscribe: store.subscribe, + actions: { + update, + }, + } +} + +export const rowSelectionStore = createRowSelectionStore()