add row selection functionality to tables

This commit is contained in:
Peter Clement 2022-02-11 11:55:35 +00:00
parent 0829723d99
commit 350edc2aec
11 changed files with 153 additions and 54 deletions

View File

@ -3,6 +3,7 @@
import "@spectrum-css/table/dist/index-vars.css" import "@spectrum-css/table/dist/index-vars.css"
import CellRenderer from "./CellRenderer.svelte" import CellRenderer from "./CellRenderer.svelte"
import SelectEditRenderer from "./SelectEditRenderer.svelte" import SelectEditRenderer from "./SelectEditRenderer.svelte"
import Checkbox from "../Form/Checkbox.svelte"
import { cloneDeep } from "lodash" import { cloneDeep } from "lodash"
import { deepGet } from "../utils/helpers" import { deepGet } from "../utils/helpers"
@ -29,7 +30,7 @@
export let editColumnTitle = "Edit" export let editColumnTitle = "Edit"
export let customRenderers = [] export let customRenderers = []
export let disableSorting = false export let disableSorting = false
export let allowSelectAllRows = false
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
// Config // Config
@ -204,12 +205,27 @@
dispatch("editrow", cloneDeep(row)) dispatch("editrow", cloneDeep(row))
} }
const toggleSelectAll = e => {
if (!allowSelectAllRows) {
return
}
if (e.detail) {
selectedRows = rows
} else {
selectedRows = []
}
}
const toggleSelectRow = row => { const toggleSelectRow = row => {
if (!allowSelectRows) { if (!allowSelectRows) {
return return
} }
if (selectedRows.includes(row)) { if (
selectedRows = selectedRows.filter(selectedRow => selectedRow !== row) selectedRows.findIndex(selectedRow => selectedRow._id === row._id) === 0
) {
selectedRows = selectedRows.filter(
selectedRow => selectedRow._id !== row._id
)
} else { } else {
selectedRows = [...selectedRows, row] selectedRows = [...selectedRows, row]
} }
@ -234,7 +250,11 @@
{#if showEditColumn} {#if showEditColumn}
<th class="spectrum-Table-headCell"> <th class="spectrum-Table-headCell">
<div class="spectrum-Table-headCell-content"> <div class="spectrum-Table-headCell-content">
{#if allowSelectAllRows}
<Checkbox on:change={toggleSelectAll} />
{:else}
{editColumnTitle || ""} {editColumnTitle || ""}
{/if}
</div> </div>
</th> </th>
{/if} {/if}
@ -299,7 +319,9 @@
<div class="spectrum-Table-cell-content"> <div class="spectrum-Table-cell-content">
<SelectEditRenderer <SelectEditRenderer
data={row} data={row}
selected={selectedRows.includes(row)} selected={selectedRows.findIndex(
selectedRow => selectedRow._id === row._id
) !== -1}
onToggleSelection={() => toggleSelectRow(row)} onToggleSelection={() => toggleSelectRow(row)}
onEdit={e => editRow(e, row)} onEdit={e => editRow(e, row)}
{allowSelectRows} {allowSelectRows}
@ -364,6 +386,7 @@
overflow: hidden; overflow: hidden;
position: relative; position: relative;
z-index: 0; z-index: 0;
cursor: pointer;
} }
.container { .container {

View File

@ -35,12 +35,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 rowBindings = getRowBindings()
return [ return [
...contextBindings, ...contextBindings,
...urlBindings, ...urlBindings,
...stateBindings, ...stateBindings,
...userBindings, ...userBindings,
...deviceBindings, ...deviceBindings,
...rowBindings,
] ]
} }
@ -321,13 +323,33 @@ const getDeviceBindings = () => {
return bindings 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. * Gets all state bindings that are globally available.
*/ */
const getStateBindings = () => { const getStateBindings = () => {
let bindings = [] let bindings = []
if (get(store).clientFeatures?.state) { if (get(store).clientFeatures?.rowSelection) {
const safeState = makePropSafe("state") const safeState = makePropSafe("rowSelection")
bindings = getAllStateVariables().map(key => ({ bindings = getAllStateVariables().map(key => ({
type: "context", type: "context",
runtimeBinding: `${safeState}.${makePropSafe(key)}`, runtimeBinding: `${safeState}.${makePropSafe(key)}`,

View File

@ -42,6 +42,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,

View File

@ -66,7 +66,6 @@ export function createAppStore() {
} }
async function update(appId, value) { async function update(appId, value) {
console.log({ value })
const response = await api.put(`/api/applications/${appId}`, { ...value }) const response = await api.put(`/api/applications/${appId}`, { ...value })
if (response.status === 200) { if (response.status === 200) {
store.update(state => { store.update(state => {

View File

@ -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",
@ -2707,6 +2708,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",
@ -2961,6 +2969,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",

View File

@ -19,6 +19,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,6 +91,7 @@
<UserBindingsProvider> <UserBindingsProvider>
<DeviceBindingsProvider> <DeviceBindingsProvider>
<StateBindingsProvider> <StateBindingsProvider>
<RowSelectionProvider>
<!-- Settings bar can be rendered outside of device preview --> <!-- Settings bar can be rendered outside of device preview -->
<!-- Key block needs to be outside the if statement or it breaks --> <!-- Key block needs to be outside the if statement or it breaks -->
{#key $builderStore.selectedComponentId} {#key $builderStore.selectedComponentId}
@ -143,6 +145,7 @@
<DNDHandler /> <DNDHandler />
{/if} {/if}
</div> </div>
</RowSelectionProvider>
</StateBindingsProvider> </StateBindingsProvider>
</DeviceBindingsProvider> </DeviceBindingsProvider>
</UserBindingsProvider> </UserBindingsProvider>

View File

@ -14,9 +14,11 @@
export let linkURL export let linkURL
export let linkColumn export let linkColumn
export let linkPeek export let linkPeek
export let allowSelectRows
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 = [
{ {
@ -24,7 +26,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 +38,9 @@
ActionTypes.SetDataProviderSorting ActionTypes.SetDataProviderSorting
) )
$: {
rowSelectionStore.actions.update(selectedRows)
}
const getFields = (schema, customColumns, showAutoColumns) => { const getFields = (schema, customColumns, showAutoColumns) => {
// Check for an invalid column selection // Check for an invalid column selection
let invalid = false let invalid = false
@ -112,7 +117,9 @@
{rowCount} {rowCount}
{quiet} {quiet}
{customRenderers} {customRenderers}
allowSelectRows={false} {allowSelectRows}
bind:selectedRows
allowSelectAllRows={true}
allowEditRows={false} allowEditRows={false}
allowEditColumns={false} allowEditColumns={false}
showAutoColumns={true} showAutoColumns={true}

View File

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

View File

@ -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,

View File

@ -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"

View File

@ -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()