Merge pull request #13610 from Budibase/table-width-setting

Table column initial width setting
This commit is contained in:
Andrew Kingston 2024-05-20 11:05:02 +01:00 committed by GitHub
commit 39f59c076a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 240 additions and 281 deletions

View File

@ -1,5 +1,5 @@
<script> <script>
import EditComponentPopover from "../EditComponentPopover/EditComponentPopover.svelte" import EditComponentPopover from "../EditComponentPopover.svelte"
import { Icon } from "@budibase/bbui" import { Icon } from "@budibase/bbui"
import { runtimeToReadableBinding } from "dataBinding" import { runtimeToReadableBinding } from "dataBinding"
import { isJSBinding } from "@budibase/string-templates" import { isJSBinding } from "@budibase/string-templates"

View File

@ -100,9 +100,6 @@
on:click={() => { on:click={() => {
get(store).actions.select(draggableItem.id) get(store).actions.select(draggableItem.id)
}} }}
on:mousedown={() => {
get(store).actions.select()
}}
bind:this={anchors[draggableItem.id]} bind:this={anchors[draggableItem.id]}
class:highlighted={draggableItem.id === $store.selected} class:highlighted={draggableItem.id === $store.selected}
> >

View File

@ -3,7 +3,6 @@
import { componentStore } from "stores/builder" import { componentStore } from "stores/builder"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import { createEventDispatcher, getContext } from "svelte" import { createEventDispatcher, getContext } from "svelte"
import { customPositionHandler } from "."
import ComponentSettingsSection from "pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte" import ComponentSettingsSection from "pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte"
export let anchor export let anchor
@ -18,76 +17,74 @@
let popover let popover
let drawers = [] let drawers = []
let open = false let isOpen = false
// Auto hide the component when another item is selected // Auto hide the component when another item is selected
$: if (open && $draggable.selected !== componentInstance._id) { $: if (open && $draggable.selected !== componentInstance._id) {
popover.hide() close()
} }
// Open automatically if the component is marked as selected // Open automatically if the component is marked as selected
$: if (!open && $draggable.selected === componentInstance._id && popover) { $: if (!open && $draggable.selected === componentInstance._id && popover) {
popover.show() open()
open = true
} }
$: componentDef = componentStore.getDefinition(componentInstance._component) $: componentDef = componentStore.getDefinition(componentInstance._component)
$: parsedComponentDef = processComponentDefinitionSettings(componentDef) $: parsedComponentDef = processComponentDefinitionSettings(componentDef)
const open = () => {
isOpen = true
drawers = []
$draggable.actions.select(componentInstance._id)
}
const close = () => {
// Slight delay allows us to be able to properly toggle open/close state by
// clicking again on the settings icon
setTimeout(() => {
isOpen = false
if ($draggable.selected === componentInstance._id) {
$draggable.actions.select()
}
}, 10)
}
const toggleOpen = () => {
if (isOpen) {
close()
} else {
open()
}
}
const processComponentDefinitionSettings = componentDef => { const processComponentDefinitionSettings = componentDef => {
if (!componentDef) { if (!componentDef) {
return {} return {}
} }
const clone = cloneDeep(componentDef) const clone = cloneDeep(componentDef)
if (typeof parseSettings === "function") { if (typeof parseSettings === "function") {
clone.settings = parseSettings(clone.settings) clone.settings = parseSettings(clone.settings)
} }
return clone return clone
} }
const updateSetting = async (setting, value) => { const updateSetting = async (setting, value) => {
const nestedComponentInstance = cloneDeep(componentInstance) const nestedComponentInstance = cloneDeep(componentInstance)
const patchFn = componentStore.updateComponentSetting(setting.key, value) const patchFn = componentStore.updateComponentSetting(setting.key, value)
patchFn(nestedComponentInstance) patchFn(nestedComponentInstance)
dispatch("change", nestedComponentInstance) dispatch("change", nestedComponentInstance)
} }
</script> </script>
<Icon <Icon name="Settings" hoverable size="S" on:click={toggleOpen} />
name="Settings"
hoverable
size="S"
on:click={() => {
if (!open) {
popover.show()
open = true
}
}}
/>
<Popover <Popover
bind:this={popover} open={isOpen}
on:open={() => { on:close={close}
drawers = []
$draggable.actions.select(componentInstance._id)
}}
on:close={() => {
open = false
if ($draggable.selected === componentInstance._id) {
$draggable.actions.select()
}
}}
{anchor} {anchor}
align="left-outside" align="left-outside"
showPopover={drawers.length === 0} showPopover={drawers.length === 0}
clickOutsideOverride={drawers.length > 0} clickOutsideOverride={drawers.length > 0}
maxHeight={600} maxHeight={600}
offset={18} offset={18}
handlePostionUpdate={customPositionHandler}
> >
<span class="popover-wrap"> <span class="popover-wrap">
<Layout noPadding noGap> <Layout noPadding noGap>

View File

@ -1,18 +0,0 @@
export const customPositionHandler = (anchorBounds, eleBounds, cfg) => {
let { left, top, offset } = cfg
let percentageOffset = 30
// left-outside
left = anchorBounds.left - eleBounds.width - (offset || 5)
// shift up from the anchor, if space allows
let offsetPos = Math.floor(eleBounds.height / 100) * percentageOffset
let defaultTop = anchorBounds.top - offsetPos
if (window.innerHeight - defaultTop < eleBounds.height) {
top = window.innerHeight - eleBounds.height - 5
} else {
top = anchorBounds.top - offsetPos
}
return { ...cfg, left, top }
}

View File

@ -1,5 +1,5 @@
<script> <script>
import EditComponentPopover from "../EditComponentPopover/EditComponentPopover.svelte" import EditComponentPopover from "../EditComponentPopover.svelte"
import { Toggle, Icon } from "@budibase/bbui" import { Toggle, Icon } from "@budibase/bbui"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"

View File

@ -1,5 +1,5 @@
<script> <script>
import EditComponentPopover from "../EditComponentPopover/EditComponentPopover.svelte" import EditComponentPopover from "../EditComponentPopover.svelte"
import { Toggle, Icon } from "@budibase/bbui" import { Toggle, Icon } from "@budibase/bbui"
import { createEventDispatcher } from "svelte" import { createEventDispatcher } from "svelte"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"

View File

@ -1,5 +1,5 @@
<script> <script>
import EditComponentPopover from "../EditComponentPopover/EditComponentPopover.svelte" import EditComponentPopover from "../EditComponentPopover.svelte"
import { Icon } from "@budibase/bbui" import { Icon } from "@budibase/bbui"
import { setContext } from "svelte" import { setContext } from "svelte"
import { writable } from "svelte/store" import { writable } from "svelte/store"

View File

@ -67,6 +67,7 @@ const toGridFormat = draggableListColumns => {
label: entry.label, label: entry.label,
field: entry.field, field: entry.field,
active: entry.active, active: entry.active,
width: entry.width,
})) }))
} }
@ -81,6 +82,7 @@ const toDraggableListFormat = (gridFormatColumns, createComponent, schema) => {
field: column.field, field: column.field,
label: column.label, label: column.label,
columnType: schema[column.field].type, columnType: schema[column.field].type,
width: column.width,
}, },
{} {}
) )

View File

@ -10,7 +10,6 @@ import {
NewFormSteps, NewFormSteps,
} from "./steps" } from "./steps"
import { API } from "api" import { API } from "api"
import { customPositionHandler } from "components/design/settings/controls/EditComponentPopover"
const ONBOARDING_EVENT_PREFIX = "onboarding" const ONBOARDING_EVENT_PREFIX = "onboarding"
@ -187,7 +186,6 @@ const getTours = () => {
tourEvent(TOUR_STEP_KEYS.BUILDER_FORM_CREATE_STEPS) tourEvent(TOUR_STEP_KEYS.BUILDER_FORM_CREATE_STEPS)
builderStore.highlightSetting("steps", "info") builderStore.highlightSetting("steps", "info")
}, },
positionHandler: customPositionHandler,
align: "left-outside", align: "left-outside",
}, },
], ],
@ -203,7 +201,6 @@ const getTours = () => {
tourEvent(TOUR_STEP_KEYS.BUILDER_FORM_ROW_ID) tourEvent(TOUR_STEP_KEYS.BUILDER_FORM_ROW_ID)
builderStore.highlightSetting("rowId", "info") builderStore.highlightSetting("rowId", "info")
}, },
positionHandler: customPositionHandler,
align: "left-outside", align: "left-outside",
}, },
{ {
@ -219,7 +216,6 @@ const getTours = () => {
tourEvent(TOUR_STEP_KEYS.BUILDER_FORM_VIEW_UPDATE_STEPS) tourEvent(TOUR_STEP_KEYS.BUILDER_FORM_VIEW_UPDATE_STEPS)
builderStore.highlightSetting("steps", "info") builderStore.highlightSetting("steps", "info")
}, },
positionHandler: customPositionHandler,
align: "left-outside", align: "left-outside",
scrollIntoView: true, scrollIntoView: true,
}, },

View File

@ -2746,6 +2746,14 @@
"type": "plainText", "type": "plainText",
"label": "Label", "label": "Label",
"key": "label" "key": "label"
},
{
"type": "number",
"label": "Initial width",
"key": "width",
"placeholder": "Auto",
"min": 80,
"max": 9999
} }
] ]
}, },

View File

@ -44,6 +44,7 @@
$: schemaOverrides = getSchemaOverrides(parsedColumns) $: schemaOverrides = getSchemaOverrides(parsedColumns)
$: enrichedButtons = enrichButtons(buttons) $: enrichedButtons = enrichButtons(buttons)
$: selectedRows = deriveSelectedRows(gridContext) $: selectedRows = deriveSelectedRows(gridContext)
$: styles = patchStyles($component.styles, minHeight)
$: data = { selectedRows: $selectedRows } $: data = { selectedRows: $selectedRows }
$: actions = [ $: actions = [
{ {
@ -84,9 +85,11 @@
const getSchemaOverrides = columns => { const getSchemaOverrides = columns => {
let overrides = {} let overrides = {}
columns.forEach(column => { columns.forEach((column, idx) => {
overrides[column.field] = { overrides[column.field] = {
displayName: column.label, displayName: column.label,
width: column.width,
order: idx,
} }
}) })
return overrides return overrides
@ -128,52 +131,54 @@
) )
} }
const patchStyles = (styles, minHeight) => {
return {
...styles,
normal: {
...styles?.normal,
"min-height": `${minHeight}px`,
},
}
}
onMount(() => { onMount(() => {
gridContext = grid.getContext() gridContext = grid.getContext()
gridContext.minHeight.subscribe($height => (minHeight = $height)) gridContext.minHeight.subscribe($height => (minHeight = $height))
}) })
</script> </script>
<span style="--min-height:{minHeight}px"> <div use:styleable={styles} class:in-builder={$builderStore.inBuilder}>
<div <Grid
use:styleable={$component.styles} bind:this={grid}
class:in-builder={$builderStore.inBuilder} datasource={table}
> {API}
<Grid {stripeRows}
bind:this={grid} {quiet}
datasource={table} {initialFilter}
{API} {initialSortColumn}
{stripeRows} {initialSortOrder}
{quiet} {fixedRowHeight}
{initialFilter} {columnWhitelist}
{initialSortColumn} {schemaOverrides}
{initialSortOrder} canAddRows={allowAddRows}
{fixedRowHeight} canEditRows={allowEditRows}
{columnWhitelist} canDeleteRows={allowDeleteRows}
{schemaOverrides} canEditColumns={false}
canAddRows={allowAddRows} canExpandRows={false}
canEditRows={allowEditRows} canSaveSchema={false}
canDeleteRows={allowDeleteRows} canSelectRows={true}
canEditColumns={false} showControls={false}
canExpandRows={false} notifySuccess={notificationStore.actions.success}
canSaveSchema={false} notifyError={notificationStore.actions.error}
canSelectRows={true} buttons={enrichedButtons}
showControls={false} isCloud={$environmentStore.cloud}
notifySuccess={notificationStore.actions.success} on:rowclick={e => onRowClick?.({ row: e.detail })}
notifyError={notificationStore.actions.error} />
buttons={enrichedButtons} </div>
isCloud={$environmentStore.cloud}
on:rowclick={e => onRowClick?.({ row: e.detail })}
/>
</div>
</span>
<Provider {data} {actions} /> <Provider {data} {actions} />
<style> <style>
span {
display: contents;
}
div { div {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -182,7 +187,6 @@
border-radius: 4px; border-radius: 4px;
overflow: hidden; overflow: hidden;
height: 410px; height: 410px;
min-height: var(--min-height);
} }
div.in-builder :global(*) { div.in-builder :global(*) {
pointer-events: none; pointer-events: none;

View File

@ -23,7 +23,6 @@
subscribe, subscribe,
config, config,
ui, ui,
columns,
definition, definition,
datasource, datasource,
schema, schema,
@ -158,17 +157,13 @@
} }
const makeDisplayColumn = () => { const makeDisplayColumn = () => {
columns.actions.changePrimaryDisplay(column.name) datasource.actions.changePrimaryDisplay(column.name)
open = false open = false
} }
const hideColumn = () => { const hideColumn = () => {
columns.update(state => { datasource.actions.addSchemaMutation(column.name, { visible: false })
const index = state.findIndex(col => col.name === column.name) datasource.actions.saveSchemaMutations()
state[index].visible = false
return state.slice()
})
columns.actions.saveChanges()
open = false open = false
} }

View File

@ -3,7 +3,7 @@
import { ActionButton, Popover, Toggle, Icon } from "@budibase/bbui" import { ActionButton, Popover, Toggle, Icon } from "@budibase/bbui"
import { getColumnIcon } from "../lib/utils" import { getColumnIcon } from "../lib/utils"
const { columns, stickyColumn, dispatch } = getContext("grid") const { columns, datasource, stickyColumn, dispatch } = getContext("grid")
let open = false let open = false
let anchor let anchor
@ -11,36 +11,20 @@
$: anyHidden = $columns.some(col => !col.visible) $: anyHidden = $columns.some(col => !col.visible)
$: text = getText($columns) $: text = getText($columns)
const toggleVisibility = async (column, visible) => { const toggleColumn = async (column, visible) => {
columns.update(state => { datasource.actions.addSchemaMutation(column.name, { visible })
const index = state.findIndex(col => col.name === column.name) await datasource.actions.saveSchemaMutations()
state[index].visible = visible
return state.slice()
})
await columns.actions.saveChanges()
dispatch(visible ? "show-column" : "hide-column") dispatch(visible ? "show-column" : "hide-column")
} }
const showAll = async () => { const toggleAll = async visible => {
columns.update(state => { let mutations = {}
return state.map(col => ({ $columns.forEach(column => {
...col, mutations[column.name] = { visible }
visible: true,
}))
}) })
await columns.actions.saveChanges() datasource.actions.addSchemaMutations(mutations)
dispatch("show-column") await datasource.actions.saveSchemaMutations()
} dispatch(visible ? "show-column" : "hide-column")
const hideAll = async () => {
columns.update(state => {
return state.map(col => ({
...col,
visible: false,
}))
})
await columns.actions.saveChanges()
dispatch("hide-column")
} }
const getText = columns => { const getText = columns => {
@ -80,14 +64,14 @@
<Toggle <Toggle
size="S" size="S"
value={column.visible} value={column.visible}
on:change={e => toggleVisibility(column, e.detail)} on:change={e => toggleColumn(column, e.detail)}
disabled={column.primaryDisplay} disabled={column.primaryDisplay}
/> />
{/each} {/each}
</div> </div>
<div class="buttons"> <div class="buttons">
<ActionButton on:click={showAll}>Show all</ActionButton> <ActionButton on:click={() => toggleAll(true)}>Show all</ActionButton>
<ActionButton on:click={hideAll}>Hide all</ActionButton> <ActionButton on:click={() => toggleAll(false)}>Hide all</ActionButton>
</div> </div>
</div> </div>
</Popover> </Popover>

View File

@ -1,5 +1,4 @@
import { derived, get, writable } from "svelte/store" import { derived, get, writable } from "svelte/store"
import { cloneDeep } from "lodash/fp"
import { GutterWidth, DefaultColumnWidth } from "../lib/constants" import { GutterWidth, DefaultColumnWidth } from "../lib/constants"
export const createStores = () => { export const createStores = () => {
@ -75,72 +74,23 @@ export const deriveStores = context => {
} }
export const createActions = context => { export const createActions = context => {
const { columns, stickyColumn, datasource, definition, schema } = context const { columns, datasource, schema } = context
// Updates the datasources primary display column
const changePrimaryDisplay = async column => {
return await datasource.actions.saveDefinition({
...get(definition),
primaryDisplay: column,
})
}
// Updates the width of all columns // Updates the width of all columns
const changeAllColumnWidths = async width => { const changeAllColumnWidths = async width => {
columns.update(state => { const $schema = get(schema)
return state.map(col => ({ let mutations = {}
...col, Object.keys($schema).forEach(field => {
width, mutations[field] = { width }
}))
})
if (get(stickyColumn)) {
stickyColumn.update(state => ({
...state,
width,
}))
}
await saveChanges()
}
// Persists column changes by saving metadata against datasource schema
const saveChanges = async () => {
const $columns = get(columns)
const $definition = get(definition)
const $stickyColumn = get(stickyColumn)
let newSchema = cloneDeep(get(schema)) || {}
// Build new updated datasource schema
Object.keys(newSchema).forEach(column => {
// Respect order specified by columns
const index = $columns.findIndex(x => x.name === column)
if (index !== -1) {
newSchema[column].order = index
} else {
delete newSchema[column].order
}
// Copy over metadata
if (column === $stickyColumn?.name) {
newSchema[column].visible = true
newSchema[column].width = $stickyColumn.width || DefaultColumnWidth
} else {
newSchema[column].visible = $columns[index]?.visible ?? true
newSchema[column].width = $columns[index]?.width || DefaultColumnWidth
}
})
await datasource.actions.saveDefinition({
...$definition,
schema: newSchema,
}) })
datasource.actions.addSchemaMutations(mutations)
await datasource.actions.saveSchemaMutations()
} }
return { return {
columns: { columns: {
...columns, ...columns,
actions: { actions: {
saveChanges,
changePrimaryDisplay,
changeAllColumnWidths, changeAllColumnWidths,
}, },
}, },

View File

@ -4,15 +4,23 @@ import { memo } from "../../../utils"
export const createStores = () => { export const createStores = () => {
const definition = memo(null) const definition = memo(null)
const schemaMutations = memo({})
return { return {
definition, definition,
schemaMutations,
} }
} }
export const deriveStores = context => { export const deriveStores = context => {
const { API, definition, schemaOverrides, columnWhitelist, datasource } = const {
context API,
definition,
schemaOverrides,
columnWhitelist,
datasource,
schemaMutations,
} = context
const schema = derived(definition, $definition => { const schema = derived(definition, $definition => {
let schema = getDatasourceSchema({ let schema = getDatasourceSchema({
@ -35,42 +43,26 @@ export const deriveStores = context => {
return schema return schema
}) })
// Derives the total enriched schema, made up of the saved schema and any
// prop and user overrides
const enrichedSchema = derived( const enrichedSchema = derived(
[schema, schemaOverrides, columnWhitelist], [schema, schemaOverrides, schemaMutations, columnWhitelist],
([$schema, $schemaOverrides, $columnWhitelist]) => { ([$schema, $schemaOverrides, $schemaMutations, $columnWhitelist]) => {
if (!$schema) { if (!$schema) {
return null return null
} }
let enrichedSchema = { ...$schema } let enrichedSchema = {}
Object.keys($schema).forEach(field => {
// Apply schema overrides // Apply whitelist if provided
Object.keys($schemaOverrides || {}).forEach(field => { if ($columnWhitelist?.length && !$columnWhitelist.includes(field)) {
if (enrichedSchema[field]) { return
enrichedSchema[field] = { }
...enrichedSchema[field], enrichedSchema[field] = {
...$schemaOverrides[field], ...$schema[field],
} ...$schemaOverrides?.[field],
...$schemaMutations[field],
} }
}) })
// Apply whitelist if specified
if ($columnWhitelist?.length) {
const sortedColumns = {}
$columnWhitelist.forEach((columnKey, idx) => {
const enrichedColumn = enrichedSchema[columnKey]
if (enrichedColumn) {
sortedColumns[columnKey] = {
...enrichedColumn,
order: idx,
visible: true,
}
}
})
return sortedColumns
}
return enrichedSchema return enrichedSchema
} }
) )
@ -100,6 +92,8 @@ export const createActions = context => {
table, table,
viewV2, viewV2,
nonPlus, nonPlus,
schemaMutations,
schema,
} = context } = context
// Gets the appropriate API for the configured datasource type // Gets the appropriate API for the configured datasource type
@ -136,11 +130,81 @@ export const createActions = context => {
// Update server // Update server
if (get(config).canSaveSchema) { if (get(config).canSaveSchema) {
await getAPI()?.actions.saveDefinition(newDefinition) await getAPI()?.actions.saveDefinition(newDefinition)
}
// Broadcast change to external state can be updated, as this change // Broadcast change so external state can be updated, as this change
// will not be received by the builder websocket because we caused it ourselves // will not be received by the builder websocket because we caused it
dispatch("updatedatasource", newDefinition) // ourselves
dispatch("updatedatasource", newDefinition)
}
}
// Updates the datasources primary display column
const changePrimaryDisplay = async column => {
return await saveDefinition({
...get(definition),
primaryDisplay: column,
})
}
// Adds a schema mutation for a single field
const addSchemaMutation = (field, mutation) => {
if (!field || !mutation) {
return
}
schemaMutations.update($schemaMutations => {
return {
...$schemaMutations,
[field]: {
...$schemaMutations[field],
...mutation,
},
}
})
}
// Adds schema mutations for multiple fields at once
const addSchemaMutations = mutations => {
const fields = Object.keys(mutations || {})
if (!fields.length) {
return
}
schemaMutations.update($schemaMutations => {
let newSchemaMutations = { ...$schemaMutations }
fields.forEach(field => {
newSchemaMutations[field] = {
...newSchemaMutations[field],
...mutations[field],
}
})
return newSchemaMutations
})
}
// Saves schema changes to the server, if possible
const saveSchemaMutations = async () => {
// If we can't save schema changes then we just want to keep this in memory
if (!get(config).canSaveSchema) {
return
}
const $definition = get(definition)
const $schemaMutations = get(schemaMutations)
const $schema = get(schema)
let newSchema = {}
// Build new updated datasource schema
Object.keys($schema).forEach(column => {
newSchema[column] = {
...$schema[column],
...$schemaMutations[column],
}
})
// Save the changes, then reset our local mutations
await saveDefinition({
...$definition,
schema: newSchema,
})
schemaMutations.set({})
} }
// Adds a row to the datasource // Adds a row to the datasource
@ -185,6 +249,10 @@ export const createActions = context => {
getRow, getRow,
isDatasourceValid, isDatasourceValid,
canUseColumn, canUseColumn,
changePrimaryDisplay,
addSchemaMutation,
addSchemaMutations,
saveSchemaMutations,
}, },
}, },
} }

View File

@ -34,6 +34,7 @@ export const createActions = context => {
stickyColumn, stickyColumn,
maxScrollLeft, maxScrollLeft,
width, width,
datasource,
} = context } = context
let autoScrollInterval let autoScrollInterval
@ -173,20 +174,17 @@ export const createActions = context => {
document.removeEventListener("touchend", stopReordering) document.removeEventListener("touchend", stopReordering)
document.removeEventListener("touchcancel", stopReordering) document.removeEventListener("touchcancel", stopReordering)
// Ensure there's actually a change // Ensure there's actually a change before saving
let { sourceColumn, targetColumn } = get(reorder) const { sourceColumn, targetColumn } = get(reorder)
if (sourceColumn !== targetColumn) {
moveColumn(sourceColumn, targetColumn)
await columns.actions.saveChanges()
}
// Reset state
reorder.set(reorderInitialState) reorder.set(reorderInitialState)
if (sourceColumn !== targetColumn) {
await moveColumn(sourceColumn, targetColumn)
}
} }
// Moves a column after another columns. // Moves a column after another columns.
// An undefined target column will move the source to index 0. // An undefined target column will move the source to index 0.
const moveColumn = (sourceColumn, targetColumn) => { const moveColumn = async (sourceColumn, targetColumn) => {
let $columns = get(columns) let $columns = get(columns)
let sourceIdx = $columns.findIndex(x => x.name === sourceColumn) let sourceIdx = $columns.findIndex(x => x.name === sourceColumn)
let targetIdx = $columns.findIndex(x => x.name === targetColumn) let targetIdx = $columns.findIndex(x => x.name === targetColumn)
@ -198,14 +196,21 @@ export const createActions = context => {
} }
return state.toSpliced(targetIdx, 0, removed[0]) return state.toSpliced(targetIdx, 0, removed[0])
}) })
// Extract new orders as schema mutations
let mutations = {}
get(columns).forEach((column, idx) => {
mutations[column.name] = { order: idx }
})
datasource.actions.addSchemaMutations(mutations)
await datasource.actions.saveSchemaMutations()
} }
// Moves a column one place left (as appears visually) // Moves a column one place left (as appears visually)
const moveColumnLeft = async column => { const moveColumnLeft = async column => {
const $visibleColumns = get(visibleColumns) const $visibleColumns = get(visibleColumns)
const sourceIdx = $visibleColumns.findIndex(x => x.name === column) const sourceIdx = $visibleColumns.findIndex(x => x.name === column)
moveColumn(column, $visibleColumns[sourceIdx - 2]?.name) await moveColumn(column, $visibleColumns[sourceIdx - 2]?.name)
await columns.actions.saveChanges()
} }
// Moves a column one place right (as appears visually) // Moves a column one place right (as appears visually)
@ -215,8 +220,7 @@ export const createActions = context => {
if (sourceIdx === $visibleColumns.length - 1) { if (sourceIdx === $visibleColumns.length - 1) {
return return
} }
moveColumn(column, $visibleColumns[sourceIdx + 1]?.name) await moveColumn(column, $visibleColumns[sourceIdx + 1]?.name)
await columns.actions.saveChanges()
} }
return { return {

View File

@ -6,7 +6,6 @@ const initialState = {
initialMouseX: null, initialMouseX: null,
initialWidth: null, initialWidth: null,
column: null, column: null,
columnIdx: null,
width: 0, width: 0,
left: 0, left: 0,
} }
@ -21,7 +20,7 @@ export const createStores = () => {
} }
export const createActions = context => { export const createActions = context => {
const { resize, columns, stickyColumn, ui } = context const { resize, ui, datasource } = context
// Starts resizing a certain column // Starts resizing a certain column
const startResizing = (column, e) => { const startResizing = (column, e) => {
@ -32,12 +31,6 @@ export const createActions = context => {
e.preventDefault() e.preventDefault()
ui.actions.blur() ui.actions.blur()
// Find and cache index
let columnIdx = get(columns).findIndex(col => col.name === column.name)
if (columnIdx === -1) {
columnIdx = "sticky"
}
// Set initial store state // Set initial store state
resize.set({ resize.set({
width: column.width, width: column.width,
@ -45,7 +38,6 @@ export const createActions = context => {
initialWidth: column.width, initialWidth: column.width,
initialMouseX: x, initialMouseX: x,
column: column.name, column: column.name,
columnIdx,
}) })
// Add mouse event listeners to handle resizing // Add mouse event listeners to handle resizing
@ -58,7 +50,7 @@ export const createActions = context => {
// Handler for moving the mouse to resize columns // Handler for moving the mouse to resize columns
const onResizeMouseMove = e => { const onResizeMouseMove = e => {
const { initialMouseX, initialWidth, width, columnIdx } = get(resize) const { initialMouseX, initialWidth, width, column } = get(resize)
const { x } = parseEventLocation(e) const { x } = parseEventLocation(e)
const dx = x - initialMouseX const dx = x - initialMouseX
const newWidth = Math.round(Math.max(MinColumnWidth, initialWidth + dx)) const newWidth = Math.round(Math.max(MinColumnWidth, initialWidth + dx))
@ -69,17 +61,7 @@ export const createActions = context => {
} }
// Update column state // Update column state
if (columnIdx === "sticky") { datasource.actions.addSchemaMutation(column, { width })
stickyColumn.update(state => ({
...state,
width: newWidth,
}))
} else {
columns.update(state => {
state[columnIdx].width = newWidth
return [...state]
})
}
// Update state // Update state
resize.update(state => ({ resize.update(state => ({
@ -101,26 +83,16 @@ export const createActions = context => {
// Persist width if it changed // Persist width if it changed
if ($resize.width !== $resize.initialWidth) { if ($resize.width !== $resize.initialWidth) {
await columns.actions.saveChanges() await datasource.actions.saveSchemaMutations()
} }
} }
// Resets a column size back to default // Resets a column size back to default
const resetSize = async column => { const resetSize = async column => {
const $stickyColumn = get(stickyColumn) datasource.actions.addSchemaMutation(column.name, {
if (column.name === $stickyColumn?.name) { width: DefaultColumnWidth,
stickyColumn.update(state => ({ })
...state, await datasource.actions.saveSchemaMutations()
width: DefaultColumnWidth,
}))
} else {
columns.update(state => {
const columnIdx = state.findIndex(x => x.name === column.name)
state[columnIdx].width = DefaultColumnWidth
return [...state]
})
}
await columns.actions.saveChanges()
} }
return { return {