Browse Source

Merge pull request #4638 from Budibase/feature/table-row-selection

Allow selection of rows from table component
master
Peter Clement 5 years ago
committed by GitHub
parent
commit
9931deceba
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      packages/bbui/src/Form/Core/Checkbox.svelte
  2. 24
      packages/bbui/src/Table/SelectEditRenderer.svelte
  3. 55
      packages/bbui/src/Table/Table.svelte
  4. 8
      packages/bbui/yarn.lock
  5. 5
      packages/builder/cypress/integration/createTable.spec.js
  6. 22
      packages/builder/cypress/support/commands.js
  7. 52
      packages/builder/src/builderStore/dataBinding.js
  8. 1
      packages/builder/src/builderStore/store/frontend.js
  9. 15
      packages/client/manifest.json
  10. 85
      packages/client/src/components/ClientApp.svelte
  11. 3
      packages/client/src/components/app/blocks/TableBlock.svelte
  12. 29
      packages/client/src/components/app/table/Table.svelte
  13. 8
      packages/client/src/components/context/RowSelectionProvider.svelte
  14. 2
      packages/client/src/sdk.js
  15. 2
      packages/client/src/stores/index.js
  16. 22
      packages/client/src/stores/rowSelection.js

4
packages/bbui/src/Form/Core/Checkbox.svelte

@ -47,7 +47,9 @@
<use xlink:href="#spectrum-css-icon-Dash100" /> <use xlink:href="#spectrum-css-icon-Dash100" />
</svg> </svg>
</span> </span>
<span class="spectrum-Checkbox-label">{text || ""}</span> {#if text}
<span class="spectrum-Checkbox-label">{text}</span>
{/if}
</label> </label>
<style> <style>

24
packages/bbui/src/Table/SelectEditRenderer.svelte

@ -8,9 +8,21 @@
export let allowEditRows = false export let allowEditRows = false
</script> </script>
{#if allowSelectRows} <div>
<Checkbox value={selected} /> {#if allowSelectRows}
{/if} <Checkbox value={selected} />
{#if allowEditRows} {/if}
<ActionButton size="S" on:click={onEdit}>Edit</ActionButton> {#if allowEditRows}
{/if} <ActionButton size="S" on:click={onEdit}>Edit</ActionButton>
{/if}
</div>
<style>
div {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
gap: var(--spacing-m);
}
</style>

55
packages/bbui/src/Table/Table.svelte

@ -5,6 +5,7 @@
import SelectEditRenderer from "./SelectEditRenderer.svelte" import SelectEditRenderer from "./SelectEditRenderer.svelte"
import { cloneDeep, deepGet } from "../helpers" import { cloneDeep, deepGet } from "../helpers"
import ProgressCircle from "../ProgressCircle/ProgressCircle.svelte" import ProgressCircle from "../ProgressCircle/ProgressCircle.svelte"
import Checkbox from "../Form/Checkbox.svelte"
/** /**
* The expected schema is our normal couch schemas for our tables. * The expected schema is our normal couch schemas for our tables.
@ -31,7 +32,6 @@
export let allowEditRows = true export let allowEditRows = true
export let allowEditColumns = true export let allowEditColumns = true
export let selectedRows = [] export let selectedRows = []
export let editColumnTitle = "Edit"
export let customRenderers = [] export let customRenderers = []
export let disableSorting = false export let disableSorting = false
export let autoSortColumns = true export let autoSortColumns = true
@ -50,6 +50,8 @@
// Table state // Table state
let height = 0 let height = 0
let loaded = false let loaded = false
let checkboxStatus = false
$: schema = fixSchema(schema) $: schema = fixSchema(schema)
$: if (!loading) loaded = true $: if (!loading) loaded = true
$: fields = getFields(schema, showAutoColumns, autoSortColumns) $: fields = getFields(schema, showAutoColumns, autoSortColumns)
@ -67,6 +69,16 @@
$: showEditColumn = allowEditRows || allowSelectRows $: showEditColumn = allowEditRows || allowSelectRows
$: cellStyles = computeCellStyles(schema) $: cellStyles = computeCellStyles(schema)
// Deselect the "select all" checkbox when the user navigates to a new page
$: {
let checkRowCount = rows.filter(o1 =>
selectedRows.some(o2 => o1._id === o2._id)
)
if (checkRowCount.length === 0) {
checkboxStatus = false
}
}
const fixSchema = schema => { const fixSchema = schema => {
let fixedSchema = {} let fixedSchema = {}
Object.entries(schema || {}).forEach(([fieldName, fieldSchema]) => { Object.entries(schema || {}).forEach(([fieldName, fieldSchema]) => {
@ -197,13 +209,32 @@
if (!allowSelectRows) { if (!allowSelectRows) {
return return
} }
if (selectedRows.includes(row)) { if (selectedRows.some(selectedRow => selectedRow._id === row._id)) {
selectedRows = selectedRows.filter(selectedRow => selectedRow !== row) selectedRows = selectedRows.filter(
selectedRow => selectedRow._id !== row._id
)
} else { } else {
selectedRows = [...selectedRows, row] selectedRows = [...selectedRows, row]
} }
} }
const toggleSelectAll = e => {
const select = !!e.detail
if (select) {
// Add any rows which are not already in selected rows
rows.forEach(row => {
if (selectedRows.findIndex(x => x._id === row._id) === -1) {
selectedRows.push(row)
}
})
} else {
// Remove any rows from selected rows that are in the current data set
selectedRows = selectedRows.filter(el =>
rows.every(f => f._id !== el._id)
)
}
}
const computeCellStyles = schema => { const computeCellStyles = schema => {
let styles = {} let styles = {}
Object.keys(schema || {}).forEach(field => { Object.keys(schema || {}).forEach(field => {
@ -244,7 +275,14 @@
<div <div
class="spectrum-Table-headCell spectrum-Table-headCell--divider spectrum-Table-headCell--edit" class="spectrum-Table-headCell spectrum-Table-headCell--divider spectrum-Table-headCell--edit"
> >
{editColumnTitle || ""} {#if allowSelectRows}
<Checkbox
bind:value={checkboxStatus}
on:change={toggleSelectAll}
/>
{:else}
Edit
{/if}
</div> </div>
{/if} {/if}
{#each fields as field} {#each fields as field}
@ -302,11 +340,16 @@
{#if showEditColumn} {#if showEditColumn}
<div <div
class="spectrum-Table-cell spectrum-Table-cell--divider spectrum-Table-cell--edit" class="spectrum-Table-cell spectrum-Table-cell--divider spectrum-Table-cell--edit"
on:click={e => {
toggleSelectRow(row)
e.stopPropagation()
}}
> >
<SelectEditRenderer <SelectEditRenderer
data={row} data={row}
selected={selectedRows.includes(row)} selected={selectedRows.findIndex(
onToggleSelection={() => toggleSelectRow(row)} selectedRow => selectedRow._id === row._id
) !== -1}
onEdit={e => editRow(e, row)} onEdit={e => editRow(e, row)}
{allowSelectRows} {allowSelectRows}
{allowEditRows} {allowEditRows}

8
packages/bbui/yarn.lock

@ -53,10 +53,10 @@
to-gfm-code-block "^0.1.1" to-gfm-code-block "^0.1.1"
year "^0.2.1" year "^0.2.1"
"@budibase/string-templates@^1.0.66-alpha.0": "@budibase/string-templates@^1.0.72-alpha.0":
version "1.0.72" version "1.0.75"
resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.72.tgz#acc154e402cce98ea30eedde9c6124183ee9b37c" resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.75.tgz#5b4061f1a626160ec092f32f036541376298100c"
integrity sha512-w715TjgO6NUHkZNqoOEo8lAKJ/PQ4b00ATWSX5VB523SAu7y/uOiqKqV1E3fgwxq1o8L+Ff7rn9FTkiYtjkV/g== integrity sha512-hPgr6n5cpSCGFEha5DS/P+rtRXOLc72M6y4J/scl59JvUi/ZUJkjRgJdpQPdBLu04CNKp89V59+rAqAuDjOC0g==
dependencies: dependencies:
"@budibase/handlebars-helpers" "^0.11.7" "@budibase/handlebars-helpers" "^0.11.7"
dayjs "^1.10.4" dayjs "^1.10.4"

5
packages/builder/cypress/integration/createTable.spec.js

@ -27,10 +27,13 @@ filterTests(["smoke", "all"], () => {
it("updates a column on the table", () => { it("updates a column on the table", () => {
cy.get(".title").click() cy.get(".title").click()
cy.get(".spectrum-Table-editIcon > use").click() cy.get(".spectrum-Table-editIcon > use").click()
cy.get("input").eq(1).type("updated", { force: true }) cy.get(".modal-inner-wrapper").within(() => {
cy.get("input").eq(0).type("updated", { force: true })
// Unset table display column // Unset table display column
cy.get(".spectrum-Switch-input").eq(1).click() cy.get(".spectrum-Switch-input").eq(1).click()
cy.contains("Save Column").click() cy.contains("Save Column").click()
})
cy.contains("nameupdated ").should("contain", "nameupdated") cy.contains("nameupdated ").should("contain", "nameupdated")
}) })

22
packages/builder/cypress/support/commands.js

@ -172,17 +172,19 @@ Cypress.Commands.add("addRow", values => {
Cypress.Commands.add("addRowMultiValue", values => { Cypress.Commands.add("addRowMultiValue", values => {
cy.contains("Create row").click() cy.contains("Create row").click()
cy.get(".spectrum-Form-itemField") cy.get(".spectrum-Modal").within(() => {
.click() cy.get(".spectrum-Form-itemField")
.then(() => { .click()
cy.get(".spectrum-Popover").within(() => { .then(() => {
for (let i = 0; i < values.length; i++) { cy.get(".spectrum-Popover").within(() => {
cy.get(".spectrum-Menu-item").eq(i).click() for (let i = 0; i < values.length; i++) {
} cy.get(".spectrum-Menu-item").eq(i).click()
}
})
cy.get(".spectrum-Dialog-grid").click("top")
cy.get(".spectrum-ButtonGroup").contains("Create").click()
}) })
cy.get(".spectrum-Dialog-grid").click("top") })
cy.get(".spectrum-ButtonGroup").contains("Create").click()
})
}) })
Cypress.Commands.add("createUser", email => { Cypress.Commands.add("createUser", email => {

52
packages/builder/src/builderStore/dataBinding.js

@ -32,12 +32,14 @@ export const getBindableProperties = (asset, componentId) => {
const urlBindings = getUrlBindings(asset) const urlBindings = getUrlBindings(asset)
const deviceBindings = getDeviceBindings() const deviceBindings = getDeviceBindings()
const stateBindings = getStateBindings() const stateBindings = getStateBindings()
const selectedRowsBindings = getSelectedRowsBindings(asset)
return [ return [
...contextBindings, ...contextBindings,
...urlBindings, ...urlBindings,
...stateBindings, ...stateBindings,
...userBindings, ...userBindings,
...deviceBindings, ...deviceBindings,
...selectedRowsBindings,
] ]
} }
@ -315,6 +317,40 @@ const getDeviceBindings = () => {
return bindings return bindings
} }
/**
* Gets all selected rows bindings for tables in the current asset.
*/
const getSelectedRowsBindings = asset => {
let bindings = []
if (get(store).clientFeatures?.rowSelection) {
// Add bindings for table components
let tables = findAllMatchingComponents(asset?.props, component =>
component._component.endsWith("table")
)
const safeState = makePropSafe("rowSelection")
bindings = bindings.concat(
tables.map(table => ({
type: "context",
runtimeBinding: `${safeState}.${makePropSafe(table._id)}`,
readableBinding: `${table._instanceName}.Selected rows`,
}))
)
// Add bindings for table blocks
let tableBlocks = findAllMatchingComponents(asset?.props, component =>
component._component.endsWith("tableblock")
)
bindings = bindings.concat(
tableBlocks.map(block => ({
type: "context",
runtimeBinding: `${safeState}.${makePropSafe(block._id + "-table")}`,
readableBinding: `${block._instanceName}.Selected rows`,
}))
)
}
return bindings
}
/** /**
* Gets all state bindings that are globally available. * Gets all state bindings that are globally available.
*/ */
@ -597,14 +633,9 @@ const buildFormSchema = component => {
* in the app. * in the app.
*/ */
export const getAllStateVariables = () => { export const getAllStateVariables = () => {
// Get all component containing assets
let allAssets = []
allAssets = allAssets.concat(get(store).layouts || [])
allAssets = allAssets.concat(get(store).screens || [])
// Find all button action settings in all components // Find all button action settings in all components
let eventSettings = [] let eventSettings = []
allAssets.forEach(asset => { getAllAssets().forEach(asset => {
findAllMatchingComponents(asset.props, component => { findAllMatchingComponents(asset.props, component => {
const settings = getComponentSettings(component._component) const settings = getComponentSettings(component._component)
settings settings
@ -635,6 +666,15 @@ export const getAllStateVariables = () => {
return Array.from(bindingSet) return Array.from(bindingSet)
} }
export const getAllAssets = () => {
// Get all component containing assets
let allAssets = []
allAssets = allAssets.concat(get(store).layouts || [])
allAssets = allAssets.concat(get(store).screens || [])
return allAssets
}
/** /**
* Recurses the input object to remove any instances of bindings. * Recurses the input object to remove any instances of bindings.
*/ */

1
packages/builder/src/builderStore/store/frontend.js

@ -41,6 +41,7 @@ const INITIAL_FRONTEND_STATE = {
intelligentLoading: false, intelligentLoading: false,
deviceAwareness: false, deviceAwareness: false,
state: false, state: false,
rowSelection: false,
customThemes: false, customThemes: false,
devicePreview: false, devicePreview: false,
messagePassing: false, messagePassing: false,

15
packages/client/manifest.json

@ -6,7 +6,8 @@
"state": true, "state": true,
"customThemes": true, "customThemes": true,
"devicePreview": true, "devicePreview": true,
"messagePassing": true "messagePassing": true,
"rowSelection": true
}, },
"layout": { "layout": {
"name": "Layout", "name": "Layout",
@ -2714,6 +2715,13 @@
"key": "showAutoColumns", "key": "showAutoColumns",
"defaultValue": false "defaultValue": false
}, },
{
"type": "boolean",
"label": "Allow row selection",
"key": "allowSelectRows",
"defaultValue": false
},
{ {
"type": "boolean", "type": "boolean",
"label": "Link table rows", "label": "Link table rows",
@ -2973,6 +2981,11 @@
"label": "Show auto columns", "label": "Show auto columns",
"key": "showAutoColumns" "key": "showAutoColumns"
}, },
{
"type": "boolean",
"label": "Allow row selection",
"key": "allowSelectRows"
},
{ {
"type": "boolean", "type": "boolean",
"label": "Link table rows", "label": "Link table rows",

85
packages/client/src/components/ClientApp.svelte

@ -21,6 +21,7 @@
import UserBindingsProvider from "components/context/UserBindingsProvider.svelte" import UserBindingsProvider from "components/context/UserBindingsProvider.svelte"
import DeviceBindingsProvider from "components/context/DeviceBindingsProvider.svelte" import DeviceBindingsProvider from "components/context/DeviceBindingsProvider.svelte"
import StateBindingsProvider from "components/context/StateBindingsProvider.svelte" import StateBindingsProvider from "components/context/StateBindingsProvider.svelte"
import RowSelectionProvider from "components/context/RowSelectionProvider.svelte"
import SettingsBar from "components/preview/SettingsBar.svelte" import SettingsBar from "components/preview/SettingsBar.svelte"
import SelectionIndicator from "components/preview/SelectionIndicator.svelte" import SelectionIndicator from "components/preview/SelectionIndicator.svelte"
import HoverIndicator from "components/preview/HoverIndicator.svelte" import HoverIndicator from "components/preview/HoverIndicator.svelte"
@ -90,59 +91,61 @@
<UserBindingsProvider> <UserBindingsProvider>
<DeviceBindingsProvider> <DeviceBindingsProvider>
<StateBindingsProvider> <StateBindingsProvider>
<!-- Settings bar can be rendered outside of device preview --> <RowSelectionProvider>
<!-- Key block needs to be outside the if statement or it breaks --> <!-- Settings bar can be rendered outside of device preview -->
{#key $builderStore.selectedComponentId} <!-- Key block needs to be outside the if statement or it breaks -->
{#if $builderStore.inBuilder} {#key $builderStore.selectedComponentId}
<SettingsBar /> {#if $builderStore.inBuilder}
{/if} <SettingsBar />
{/key} {/if}
{/key}
<!-- Clip boundary for selection indicators --> <!-- Clip boundary for selection indicators -->
<div <div
id="clip-root" id="clip-root"
class:preview={$builderStore.inBuilder} class:preview={$builderStore.inBuilder}
class:tablet-preview={$builderStore.previewDevice === "tablet"} class:tablet-preview={$builderStore.previewDevice === "tablet"}
class:mobile-preview={$builderStore.previewDevice === "mobile"} class:mobile-preview={$builderStore.previewDevice === "mobile"}
> >
<!-- Actual app --> <!-- Actual app -->
<div id="app-root"> <div id="app-root">
<CustomThemeWrapper> <CustomThemeWrapper>
{#key `${$screenStore.activeLayout._id}-${$builderStore.previewType}`} {#key `${$screenStore.activeLayout._id}-${$builderStore.previewType}`}
<Component <Component
isLayout isLayout
instance={$screenStore.activeLayout.props} instance={$screenStore.activeLayout.props}
/> />
{/key} {/key}
<!-- <!--
Flatpickr needs to be inside the theme wrapper. Flatpickr needs to be inside the theme wrapper.
It also needs its own container because otherwise it hijacks It also needs its own container because otherwise it hijacks
key events on the whole page. It is painful to work with. key events on the whole page. It is painful to work with.
--> -->
<div id="flatpickr-root" /> <div id="flatpickr-root" />
<!-- Modal container to ensure they sit on top --> <!-- Modal container to ensure they sit on top -->
<div class="modal-container" /> <div class="modal-container" />
<!-- Layers on top of app --> <!-- Layers on top of app -->
<NotificationDisplay /> <NotificationDisplay />
<ConfirmationDisplay /> <ConfirmationDisplay />
<PeekScreenDisplay /> <PeekScreenDisplay />
</CustomThemeWrapper> </CustomThemeWrapper>
</div> </div>
<!-- Selection indicators should be bounded by device --> <!-- Selection indicators should be bounded by device -->
<!-- <!--
We don't want to key these by componentID as they control their own We don't want to key these by componentID as they control their own
re-mounting to avoid flashes. re-mounting to avoid flashes.
--> -->
{#if $builderStore.inBuilder} {#if $builderStore.inBuilder}
<SelectionIndicator /> <SelectionIndicator />
<HoverIndicator /> <HoverIndicator />
<DNDHandler /> <DNDHandler />
{/if} {/if}
</div> </div>
</RowSelectionProvider>
</StateBindingsProvider> </StateBindingsProvider>
</DeviceBindingsProvider> </DeviceBindingsProvider>
</UserBindingsProvider> </UserBindingsProvider>

3
packages/client/src/components/app/blocks/TableBlock.svelte

@ -18,6 +18,7 @@
export let quiet export let quiet
export let compact export let compact
export let size export let size
export let allowSelectRows
export let linkRows export let linkRows
export let linkURL export let linkURL
export let linkColumn export let linkColumn
@ -157,6 +158,7 @@
> >
<BlockComponent <BlockComponent
type="table" type="table"
context="table"
props={{ props={{
dataProvider: `{{ literal ${safe(dataProviderId)} }}`, dataProvider: `{{ literal ${safe(dataProviderId)} }}`,
columns: tableColumns, columns: tableColumns,
@ -164,6 +166,7 @@
rowCount, rowCount,
quiet, quiet,
compact, compact,
allowSelectRows,
size, size,
linkRows, linkRows,
linkURL, linkURL,

29
packages/client/src/components/app/table/Table.svelte

@ -3,6 +3,7 @@
import { Table } from "@budibase/bbui" import { Table } from "@budibase/bbui"
import SlotRenderer from "./SlotRenderer.svelte" import SlotRenderer from "./SlotRenderer.svelte"
import { UnsortableTypes } from "../../../constants" import { UnsortableTypes } from "../../../constants"
import { onDestroy } from "svelte"
export let dataProvider export let dataProvider
export let columns export let columns
@ -14,10 +15,12 @@
export let linkURL export let linkURL
export let linkColumn export let linkColumn
export let linkPeek export let linkPeek
export let allowSelectRows
export let compact export let compact
const component = getContext("component") 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 customColumnKey = `custom-${Math.random()}`
const customRenderers = [ const customRenderers = [
{ {
@ -25,7 +28,7 @@
component: SlotRenderer, component: SlotRenderer,
}, },
] ]
let selectedRows = []
$: hasChildren = $component.children $: hasChildren = $component.children
$: loading = dataProvider?.loading ?? false $: loading = dataProvider?.loading ?? false
$: data = dataProvider?.rows || [] $: data = dataProvider?.rows || []
@ -36,6 +39,12 @@
dataProvider?.id, dataProvider?.id,
ActionTypes.SetDataProviderSorting ActionTypes.SetDataProviderSorting
) )
$: {
rowSelectionStore.actions.updateSelection(
$component.id,
selectedRows.map(row => row._id)
)
}
const getFields = (schema, customColumns, showAutoColumns) => { const getFields = (schema, customColumns, showAutoColumns) => {
// Check for an invalid column selection // Check for an invalid column selection
@ -117,6 +126,10 @@
const split = linkURL.split("/:") const split = linkURL.split("/:")
routeStore.actions.navigate(`${split[0]}/${id}`, linkPeek) routeStore.actions.navigate(`${split[0]}/${id}`, linkPeek)
} }
onDestroy(() => {
rowSelectionStore.actions.updateSelection($component.id, [])
})
</script> </script>
<div use:styleable={$component.styles} class={size}> <div use:styleable={$component.styles} class={size}>
@ -128,7 +141,8 @@
{quiet} {quiet}
{compact} {compact}
{customRenderers} {customRenderers}
allowSelectRows={false} allowSelectRows={!!allowSelectRows}
bind:selectedRows
allowEditRows={false} allowEditRows={false}
allowEditColumns={false} allowEditColumns={false}
showAutoColumns={true} showAutoColumns={true}
@ -139,10 +153,19 @@
> >
<slot /> <slot />
</Table> </Table>
{#if allowSelectRows && selectedRows.length}
<div class="row-count">
{selectedRows.length} row{selectedRows.length === 1 ? "" : "s"} selected
</div>
{/if}
</div> </div>
<style> <style>
div { div {
background-color: var(--spectrum-alias-background-color-secondary); background-color: var(--spectrum-alias-background-color-secondary);
} }
.row-count {
margin-top: var(--spacing-l);
}
</style> </style>

8
packages/client/src/components/context/RowSelectionProvider.svelte

@ -0,0 +1,8 @@
<script>
import Provider from "./Provider.svelte"
import { rowSelectionStore } from "stores"
</script>
<Provider key="rowSelection" data={$rowSelectionStore}>
<slot />
</Provider>

2
packages/client/src/sdk.js

@ -6,6 +6,7 @@ import {
screenStore, screenStore,
builderStore, builderStore,
uploadStore, uploadStore,
rowSelectionStore,
} from "stores" } from "stores"
import { styleable } from "utils/styleable" import { styleable } from "utils/styleable"
import { linkable } from "utils/linkable" import { linkable } from "utils/linkable"
@ -19,6 +20,7 @@ export default {
authStore, authStore,
notificationStore, notificationStore,
routeStore, routeStore,
rowSelectionStore,
screenStore, screenStore,
builderStore, builderStore,
uploadStore, uploadStore,

2
packages/client/src/stores/index.js

@ -10,7 +10,7 @@ export { peekStore } from "./peek"
export { stateStore } from "./state" export { stateStore } from "./state"
export { themeStore } from "./theme" export { themeStore } from "./theme"
export { uploadStore } from "./uploads.js" export { uploadStore } from "./uploads.js"
export { rowSelectionStore } from "./rowSelection.js"
// Context stores are layered and duplicated, so it is not a singleton // Context stores are layered and duplicated, so it is not a singleton
export { createContextStore } from "./context" export { createContextStore } from "./context"

22
packages/client/src/stores/rowSelection.js

@ -0,0 +1,22 @@
import { writable } from "svelte/store"
const createRowSelectionStore = () => {
const store = writable({})
function updateSelection(componentId, selectedRows) {
store.update(state => {
state[componentId] = [...selectedRows]
return state
})
}
return {
subscribe: store.subscribe,
set: store.set,
actions: {
updateSelection,
},
}
}
export const rowSelectionStore = createRowSelectionStore()
Loading…
Cancel
Save