diff --git a/packages/client/manifest.json b/packages/client/manifest.json
index 3f36f2f666..3186c40259 100644
--- a/packages/client/manifest.json
+++ b/packages/client/manifest.json
@@ -5230,9 +5230,7 @@
"block": true,
"name": "Grid block",
"icon": "Table",
- "styles": [
- "size"
- ],
+ "styles": ["size"],
"size": {
"width": 600,
"height": 400
@@ -5245,23 +5243,49 @@
"key": "table",
"required": true
},
+ {
+ "type": "columns",
+ "label": "Columns",
+ "key": "columns",
+ "dependsOn": "table"
+ },
{
"type": "filter",
"label": "Filtering",
- "key": "filter"
+ "key": "initialFilter"
},
{
"type": "field/sortable",
"label": "Sort column",
- "key": "sortColumn"
+ "key": "initialSortColumn"
},
{
"type": "select",
"label": "Sort order",
- "key": "sortOrder",
+ "key": "initialSortOrder",
"options": ["Ascending", "Descending"],
"defaultValue": "Ascending"
},
+ {
+ "type": "select",
+ "label": "Row height",
+ "key": "initialRowHeight",
+ "placeholder": "Default",
+ "options": [
+ {
+ "label": "Small",
+ "value": 36
+ },
+ {
+ "label": "Medium",
+ "value": 64
+ },
+ {
+ "label": "Large",
+ "value": 92
+ }
+ ]
+ },
{
"type": "boolean",
"label": "Add rows",
diff --git a/packages/client/src/components/app/GridBlock.svelte b/packages/client/src/components/app/GridBlock.svelte
index 5267582bc8..bfc3a15d1c 100644
--- a/packages/client/src/components/app/GridBlock.svelte
+++ b/packages/client/src/components/app/GridBlock.svelte
@@ -9,9 +9,10 @@
export let allowEditRows = true
export let allowDeleteRows = true
export let stripeRows = false
- export let filter = null
- export let sortColumn = null
- export let sortOrder = null
+ export let initialFilter = null
+ export let initialSortColumn = null
+ export let initialSortOrder = null
+ export let initialRowHeight = null
const component = getContext("component")
const { styleable, API, builderStore } = getContext("sdk")
@@ -28,9 +29,10 @@
{allowEditRows}
{allowDeleteRows}
{stripeRows}
- {filter}
- {sortColumn}
- {sortOrder}
+ {initialFilter}
+ {initialSortColumn}
+ {initialSortOrder}
+ {initialRowHeight}
showControls={false}
allowExpandRows={false}
allowSchemaChanges={false}
diff --git a/packages/frontend-core/src/components/grid/controls/ColumnWidthButton.svelte b/packages/frontend-core/src/components/grid/controls/ColumnWidthButton.svelte
index 5ffd968d30..fb20cc50e5 100644
--- a/packages/frontend-core/src/components/grid/controls/ColumnWidthButton.svelte
+++ b/packages/frontend-core/src/components/grid/controls/ColumnWidthButton.svelte
@@ -33,22 +33,6 @@
selected: allLarge,
},
]
-
- const changeColumnWidth = async width => {
- columns.update(state => {
- state.forEach(column => {
- column.width = width
- })
- return state
- })
- if ($stickyColumn) {
- stickyColumn.update(state => ({
- ...state,
- width,
- }))
- }
- await columns.actions.saveChanges()
- }
@@ -70,7 +54,7 @@
{#each sizeOptions as option}
changeColumnWidth(option.size)}
+ on:click={() => columns.actions.changeAllColumnWidths(option.size)}
selected={option.selected}
>
{option.label}
diff --git a/packages/frontend-core/src/components/grid/layout/Grid.svelte b/packages/frontend-core/src/components/grid/layout/Grid.svelte
index 9edd69d09d..211bb15917 100644
--- a/packages/frontend-core/src/components/grid/layout/Grid.svelte
+++ b/packages/frontend-core/src/components/grid/layout/Grid.svelte
@@ -29,7 +29,6 @@
GutterWidth,
DefaultRowHeight,
} from "../lib/constants"
- import { memo } from "../../../utils"
export let API = null
export let tableId = null
@@ -43,48 +42,26 @@
export let collaboration = true
export let showAvatars = true
export let showControls = true
- export let filter = null
- export let sortColumn = null
- export let sortOrder = null
+ export let initialFilter = null
+ export let initialSortColumn = null
+ export let initialSortOrder = null
+ export let initialRowHeight = null
// Unique identifier for DOM nodes inside this instance
const rand = Math.random()
- // Stores derived from props.
- // We use memo here to ensure redundant store reactions don't fire and cause
- // wasted API calls.
- const tableIdStore = memo(tableId)
- const schemaOverridesStore = memo(schemaOverrides)
- const filterStore = memo(filter)
- const sortStore = memo({
- column: sortColumn,
- order: sortOrder,
- })
- const config = memo({
- allowAddRows,
- allowExpandRows,
- allowEditRows,
- allowDeleteRows,
- allowSchemaChanges,
- stripeRows,
- showControls,
- })
-
// Build up context
let context = {
API: API || createAPIClient(),
rand,
- config,
- tableId: tableIdStore,
- schemaOverrides: schemaOverridesStore,
- filter: filterStore,
- sort: sortStore,
+ props: $$props,
}
context = { ...context, ...createEventManagers() }
context = attachStores(context)
// Reference some stores for local use
const {
+ config,
isResizing,
isReordering,
ui,
@@ -95,22 +72,23 @@
gridFocused,
} = context
- // Keep prop-derived stores up to date
- $: tableIdStore.set(tableId)
- $: schemaOverridesStore.set(schemaOverrides)
- $: filterStore.set(filter)
- $: sortStore.set({
- column: sortColumn,
- order: sortOrder,
- })
+ // Keep config store up to date with props
$: config.set({
+ tableId,
+ schemaOverrides,
allowAddRows,
- allowSchemaChanges,
allowExpandRows,
allowEditRows,
allowDeleteRows,
+ allowSchemaChanges,
stripeRows,
+ collaboration,
+ showAvatars,
showControls,
+ initialFilter,
+ initialSortColumn,
+ initialSortOrder,
+ initialRowHeight,
})
// Set context for children to consume
diff --git a/packages/frontend-core/src/components/grid/stores/columns.js b/packages/frontend-core/src/components/grid/stores/columns.js
index a0820e77bb..5f34de1434 100644
--- a/packages/frontend-core/src/components/grid/stores/columns.js
+++ b/packages/frontend-core/src/components/grid/stores/columns.js
@@ -56,6 +56,23 @@ export const deriveStores = context => {
})
}
+ // Updates the width of all columns
+ const changeAllColumnWidths = async width => {
+ columns.update(state => {
+ return state.map(col => ({
+ ...col,
+ width,
+ }))
+ })
+ if (get(stickyColumn)) {
+ stickyColumn.update(state => ({
+ ...state,
+ width,
+ }))
+ }
+ await saveChanges()
+ }
+
// Persists column changes by saving metadata against table schema
const saveChanges = async () => {
const $columns = get(columns)
@@ -107,6 +124,7 @@ export const deriveStores = context => {
saveChanges,
saveTable,
changePrimaryDisplay,
+ changeAllColumnWidths,
},
},
}
diff --git a/packages/frontend-core/src/components/grid/stores/config.js b/packages/frontend-core/src/components/grid/stores/config.js
new file mode 100644
index 0000000000..3e8da81e2e
--- /dev/null
+++ b/packages/frontend-core/src/components/grid/stores/config.js
@@ -0,0 +1,23 @@
+import { writable } from "svelte/store"
+import { derivedMemo } from "../../../utils"
+
+export const createStores = context => {
+ const config = writable(context.props)
+ const getProp = prop => derivedMemo(config, $config => $config[prop])
+
+ // Derive and memoize some props so that we can react to them in isolation
+ const tableId = getProp("tableId")
+ const initialSortColumn = getProp("initialSortColumn")
+ const initialSortOrder = getProp("initialSortOrder")
+ const initialFilter = getProp("initialFilter")
+ const initialRowHeight = getProp("initialRowHeight")
+
+ return {
+ config,
+ tableId,
+ initialSortColumn,
+ initialSortOrder,
+ initialFilter,
+ initialRowHeight,
+ }
+}
diff --git a/packages/frontend-core/src/components/grid/stores/filter.js b/packages/frontend-core/src/components/grid/stores/filter.js
new file mode 100644
index 0000000000..1f01aaec40
--- /dev/null
+++ b/packages/frontend-core/src/components/grid/stores/filter.js
@@ -0,0 +1,20 @@
+import { writable } from "svelte/store"
+import { derivedMemo } from "../../../utils"
+
+export const createStores = context => {
+ const { props } = context
+
+ // Initialise to default props
+ const filter = writable(props.initialFilter)
+
+ return {
+ filter,
+ }
+}
+
+export const initialise = context => {
+ const { filter, initialFilter } = context
+
+ // Reset filter when initial filter prop changes
+ initialFilter.subscribe(filter.set)
+}
diff --git a/packages/frontend-core/src/components/grid/stores/index.js b/packages/frontend-core/src/components/grid/stores/index.js
index aa552a9ffe..588b568c8e 100644
--- a/packages/frontend-core/src/components/grid/stores/index.js
+++ b/packages/frontend-core/src/components/grid/stores/index.js
@@ -11,8 +11,14 @@ import * as Users from "./users"
import * as Validation from "./validation"
import * as Viewport from "./viewport"
import * as Clipboard from "./clipboard"
+import * as Config from "./config"
+import * as Sort from "./sort"
+import * as Filter from "./filter"
const DependencyOrderedStores = [
+ Config,
+ Sort,
+ Filter,
Bounds,
Scroll,
Rows,
diff --git a/packages/frontend-core/src/components/grid/stores/sort.js b/packages/frontend-core/src/components/grid/stores/sort.js
new file mode 100644
index 0000000000..211124f640
--- /dev/null
+++ b/packages/frontend-core/src/components/grid/stores/sort.js
@@ -0,0 +1,27 @@
+import { writable } from "svelte/store"
+
+export const createStores = context => {
+ const { props } = context
+
+ // Initialise to default props
+ const sort = writable({
+ column: props.initialSortColumn,
+ order: props.initialSortOrder || "ascending",
+ })
+
+ return {
+ sort,
+ }
+}
+
+export const initialise = context => {
+ const { sort, initialSortColumn, initialSortOrder } = context
+
+ // Reset sort when initial sort props change
+ initialSortColumn.subscribe(newSortColumn => {
+ sort.update(state => ({ ...state, column: newSortColumn }))
+ })
+ initialSortOrder.subscribe(newSortOrder => {
+ sort.update(state => ({ ...state, order: newSortOrder }))
+ })
+}
diff --git a/packages/frontend-core/src/components/grid/stores/ui.js b/packages/frontend-core/src/components/grid/stores/ui.js
index f5c0905320..168b0c8184 100644
--- a/packages/frontend-core/src/components/grid/stores/ui.js
+++ b/packages/frontend-core/src/components/grid/stores/ui.js
@@ -8,12 +8,13 @@ import {
NewRowID,
} from "../lib/constants"
-export const createStores = () => {
+export const createStores = context => {
+ const { props } = context
const focusedCellId = writable(null)
const focusedCellAPI = writable(null)
const selectedRows = writable({})
const hoveredRowId = writable(null)
- const rowHeight = writable(DefaultRowHeight)
+ const rowHeight = writable(props.initialRowHeight || DefaultRowHeight)
const previousFocusedRowId = writable(null)
const gridFocused = writable(false)
const isDragging = writable(false)
@@ -98,9 +99,9 @@ export const deriveStores = context => {
// Derive the amount of content lines to show in cells depending on row height
const contentLines = derived(rowHeight, $rowHeight => {
- if ($rowHeight === LargeRowHeight) {
+ if ($rowHeight >= LargeRowHeight) {
return 3
- } else if ($rowHeight === MediumRowHeight) {
+ } else if ($rowHeight >= MediumRowHeight) {
return 2
}
return 1
@@ -133,6 +134,7 @@ export const initialise = context => {
hoveredRowId,
table,
rowHeight,
+ initialRowHeight,
} = context
// Ensure we clear invalid rows from state if they disappear
@@ -189,4 +191,7 @@ export const initialise = context => {
table.subscribe($table => {
rowHeight.set($table?.rowHeight || DefaultRowHeight)
})
+
+ // Reset row height when initial row height prop changes
+ initialRowHeight.subscribe(rowHeight.set)
}
diff --git a/packages/frontend-core/src/utils/index.js b/packages/frontend-core/src/utils/index.js
index e3ec87a5e9..26e44410ba 100644
--- a/packages/frontend-core/src/utils/index.js
+++ b/packages/frontend-core/src/utils/index.js
@@ -3,5 +3,5 @@ export * as JSONUtils from "./json"
export * as CookieUtils from "./cookies"
export * as RoleUtils from "./roles"
export * as Utils from "./utils"
-export { memo } from "./memo"
+export { memo, derivedMemo } from "./memo"
export { createWebsocket } from "./websocket"
diff --git a/packages/frontend-core/src/utils/memo.js b/packages/frontend-core/src/utils/memo.js
index d46b264d1b..ba0e3f3490 100644
--- a/packages/frontend-core/src/utils/memo.js
+++ b/packages/frontend-core/src/utils/memo.js
@@ -1,4 +1,4 @@
-import { writable, get } from "svelte/store"
+import { writable, get, derived } from "svelte/store"
// A simple svelte store which deeply compares all changes and ensures that
// subscribed children will only fire when a new value is actually set
@@ -33,3 +33,11 @@ export const memo = initialValue => {
},
}
}
+
+// Enriched version of svelte's derived store which returns a memo
+export const derivedMemo = (store, derivation) => {
+ const derivedStore = derived(store, derivation)
+ const memoStore = memo(get(derivedStore))
+ derivedStore.subscribe(memoStore.set)
+ return memoStore
+}