This commit is contained in:
Andrew Kingston 2024-06-24 09:56:48 +01:00
parent 0d2cef20df
commit ada3367b49
No known key found for this signature in database
22 changed files with 173 additions and 262 deletions

View File

@ -270,7 +270,7 @@
on:touchcancel={onMouseUp} on:touchcancel={onMouseUp}
on:contextmenu={onContextMenu} on:contextmenu={onContextMenu}
width={column.width} width={column.width}
left={column.left} left={column.__left}
defaultHeight defaultHeight
center center
> >

View File

@ -7,14 +7,12 @@
export let allowViewReadonlyColumns = false export let allowViewReadonlyColumns = false
const { columns, datasource, stickyColumn, dispatch } = getContext("grid") const { columns, datasource, dispatch } = getContext("grid")
let open = false let open = false
let anchor let anchor
$: allColumns = $stickyColumn ? [$stickyColumn, ...$columns] : $columns $: restrictedColumns = $columns.filter(col => !col.visible || col.readonly)
$: restrictedColumns = allColumns.filter(col => !col.visible || col.readonly)
$: anyRestricted = restrictedColumns.length $: anyRestricted = restrictedColumns.length
$: text = anyRestricted ? `Columns (${anyRestricted} restricted)` : "Columns" $: text = anyRestricted ? `Columns (${anyRestricted} restricted)` : "Columns"
@ -43,12 +41,9 @@
HIDDEN: "hidden", HIDDEN: "hidden",
} }
$: displayColumns = allColumns.map(c => { $: displayColumns = $columns.map(c => {
const isRequired = helpers.schema.isRequired(c.schema.constraints) const isRequired = helpers.schema.isRequired(c.schema.constraints)
const isDisplayColumn = $stickyColumn === c
const requiredTooltip = isRequired && "Required columns must be writable" const requiredTooltip = isRequired && "Required columns must be writable"
const editEnabled = const editEnabled =
!isRequired || !isRequired ||
columnToPermissionOptions(c) !== PERMISSION_OPTIONS.WRITABLE columnToPermissionOptions(c) !== PERMISSION_OPTIONS.WRITABLE
@ -74,9 +69,9 @@
options.push({ options.push({
icon: "VisibilityOff", icon: "VisibilityOff",
value: PERMISSION_OPTIONS.HIDDEN, value: PERMISSION_OPTIONS.HIDDEN,
disabled: isDisplayColumn || isRequired, disabled: c.primaryDisplay || isRequired,
tooltip: tooltip:
(isDisplayColumn && "Display column cannot be hidden") || (c.primaryDisplay && "Display column cannot be hidden") ||
requiredTooltip || requiredTooltip ||
"Hidden", "Hidden",
}) })

View File

@ -8,14 +8,8 @@
SmallRowHeight, SmallRowHeight,
} from "../lib/constants" } from "../lib/constants"
const { const { columns, rowHeight, definition, fixedRowHeight, datasource } =
stickyColumn, getContext("grid")
columns,
rowHeight,
definition,
fixedRowHeight,
datasource,
} = getContext("grid")
// Some constants for column width options // Some constants for column width options
const smallColSize = 120 const smallColSize = 120
@ -42,10 +36,9 @@
let anchor let anchor
// Column width sizes // Column width sizes
$: allCols = $columns.concat($stickyColumn ? [$stickyColumn] : []) $: allSmall = $columns.every(col => col.width === smallColSize)
$: allSmall = allCols.every(col => col.width === smallColSize) $: allMedium = $columns.every(col => col.width === mediumColSize)
$: allMedium = allCols.every(col => col.width === mediumColSize) $: allLarge = $columns.every(col => col.width === largeColSize)
$: allLarge = allCols.every(col => col.width === largeColSize)
$: custom = !allSmall && !allMedium && !allLarge $: custom = !allSmall && !allMedium && !allLarge
$: columnSizeOptions = [ $: columnSizeOptions = [
{ {
@ -80,7 +73,7 @@
size="M" size="M"
on:click={() => (open = !open)} on:click={() => (open = !open)}
selected={open} selected={open}
disabled={!allCols.length} disabled={!$columns.length}
> >
Size Size
</ActionButton> </ActionButton>

View File

@ -3,34 +3,20 @@
import { ActionButton, Popover, Select } from "@budibase/bbui" import { ActionButton, Popover, Select } from "@budibase/bbui"
import { canBeSortColumn } from "@budibase/shared-core" import { canBeSortColumn } from "@budibase/shared-core"
const { sort, columns, stickyColumn } = getContext("grid") const { sort, columns } = getContext("grid")
let open = false let open = false
let anchor let anchor
$: columnOptions = getColumnOptions($stickyColumn, $columns) $: columnOptions = $columns
.map(col => ({
label: col.label || col.name,
value: col.name,
type: col.schema?.type,
}))
.filter(col => canBeSortColumn(col.type))
$: orderOptions = getOrderOptions($sort.column, columnOptions) $: orderOptions = getOrderOptions($sort.column, columnOptions)
const getColumnOptions = (stickyColumn, columns) => {
let options = []
if (stickyColumn) {
options.push({
label: stickyColumn.label || stickyColumn.name,
value: stickyColumn.name,
type: stickyColumn.schema?.type,
})
}
options = [
...options,
...columns.map(col => ({
label: col.label || col.name,
value: col.name,
type: col.schema?.type,
})),
]
return options.filter(col => canBeSortColumn(col.type))
}
const getOrderOptions = (column, columnOptions) => { const getOrderOptions = (column, columnOptions) => {
const type = columnOptions.find(col => col.value === column)?.type const type = columnOptions.find(col => col.value === column)?.type
return [ return [

View File

@ -8,7 +8,7 @@
const { const {
bounds, bounds,
renderedRows, renderedRows,
visibleColumns, scrollableColumns,
hoveredRowId, hoveredRowId,
dispatch, dispatch,
isDragging, isDragging,
@ -18,7 +18,7 @@
let body let body
$: columnsWidth = $visibleColumns.reduce( $: columnsWidth = $scrollableColumns.reduce(
(total, col) => (total += col.width), (total, col) => (total += col.width),
0 0
) )

View File

@ -10,7 +10,7 @@
focusedCellId, focusedCellId,
reorder, reorder,
selectedRows, selectedRows,
visibleColumns, scrollableColumns,
hoveredRowId, hoveredRowId,
focusedRow, focusedRow,
contentLines, contentLines,
@ -40,7 +40,7 @@
on:mouseleave={$isDragging ? null : () => ($hoveredRowId = null)} on:mouseleave={$isDragging ? null : () => ($hoveredRowId = null)}
on:click={() => dispatch("rowclick", rows.actions.cleanRow(row))} on:click={() => dispatch("rowclick", rows.actions.cleanRow(row))}
> >
{#each $visibleColumns as column} {#each $scrollableColumns as column}
{@const cellId = getCellID(row._id, column.name)} {@const cellId = getCellID(row._id, column.name)}
<DataCell <DataCell
{cellId} {cellId}

View File

@ -5,14 +5,14 @@
import HeaderCell from "../cells/HeaderCell.svelte" import HeaderCell from "../cells/HeaderCell.svelte"
import { TempTooltip, TooltipType } from "@budibase/bbui" import { TempTooltip, TooltipType } from "@budibase/bbui"
const { visibleColumns, config, hasNonAutoColumn, datasource, loading } = const { scrollableColumns, config, hasNonAutoColumn, datasource, loading } =
getContext("grid") getContext("grid")
</script> </script>
<div class="header"> <div class="header">
<GridScrollWrapper scrollHorizontally> <GridScrollWrapper scrollHorizontally>
<div class="row"> <div class="row">
{#each $visibleColumns as column, idx} {#each $scrollableColumns as column, idx}
<HeaderCell {column} {idx}> <HeaderCell {column} {idx}>
<slot name="edit-column" /> <slot name="edit-column" />
</HeaderCell> </HeaderCell>

View File

@ -12,7 +12,7 @@
const { const {
hoveredRowId, hoveredRowId,
focusedCellId, focusedCellId,
stickyColumn, displayColumn,
scroll, scroll,
dispatch, dispatch,
rows, rows,
@ -38,8 +38,8 @@
let newRow let newRow
let offset = 0 let offset = 0
$: firstColumn = $stickyColumn || $visibleColumns[0] $: firstColumn = $visibleColumns[0]
$: width = GutterWidth + ($stickyColumn?.width || 0) $: width = GutterWidth + ($displayColumn?.width || 0)
$: $datasource, (visible = false) $: $datasource, (visible = false)
$: selectedRowCount = Object.values($selectedRows).length $: selectedRowCount = Object.values($selectedRows).length
$: hasNoRows = !$rows.length $: hasNoRows = !$rows.length
@ -164,7 +164,7 @@
class="new-row-fab" class="new-row-fab"
on:click={() => dispatch("add-row-inline")} on:click={() => dispatch("add-row-inline")}
transition:fade|local={{ duration: 130 }} transition:fade|local={{ duration: 130 }}
class:offset={!$stickyColumn} class:offset={!$displayColumn}
> >
<Icon name="Add" size="S" /> <Icon name="Add" size="S" />
</div> </div>
@ -187,19 +187,19 @@
<div in:fade={{ duration: 130 }} class="loading-overlay" /> <div in:fade={{ duration: 130 }} class="loading-overlay" />
{/if} {/if}
</GutterCell> </GutterCell>
{#if $stickyColumn} {#if $displayColumn}
{@const cellId = getCellID(NewRowID, $stickyColumn.name)} {@const cellId = getCellID(NewRowID, $displayColumn.name)}
<DataCell <DataCell
{cellId} {cellId}
rowFocused rowFocused
column={$stickyColumn} column={$displayColumn}
row={newRow} row={newRow}
focused={$focusedCellId === cellId} focused={$focusedCellId === cellId}
width={$stickyColumn.width} width={$displayColumn.width}
{updateValue} {updateValue}
topRow={offset === 0} topRow={offset === 0}
> >
{#if $stickyColumn?.schema?.autocolumn} {#if $displayColumn?.schema?.autocolumn}
<div class="readonly-overlay">Can't edit auto column</div> <div class="readonly-overlay">Can't edit auto column</div>
{/if} {/if}
{#if isAdding} {#if isAdding}

View File

@ -13,7 +13,7 @@
const { const {
rows, rows,
selectedRows, selectedRows,
stickyColumn, displayColumn,
renderedRows, renderedRows,
focusedCellId, focusedCellId,
hoveredRowId, hoveredRowId,
@ -26,13 +26,12 @@
contentLines, contentLines,
isDragging, isDragging,
isSelectingCells, isSelectingCells,
selectedCells,
selectedCellCount, selectedCellCount,
} = getContext("grid") } = getContext("grid")
$: rowCount = $rows.length $: rowCount = $rows.length
$: selectedRowCount = Object.values($selectedRows).length $: selectedRowCount = Object.values($selectedRows).length
$: width = GutterWidth + ($stickyColumn?.width || 0) $: width = GutterWidth + ($displayColumn?.width || 0)
const selectAll = () => { const selectAll = () => {
const allSelected = selectedRowCount === rowCount const allSelected = selectedRowCount === rowCount
@ -61,8 +60,8 @@
rowSelected={selectedRowCount && selectedRowCount === rowCount} rowSelected={selectedRowCount && selectedRowCount === rowCount}
disabled={!$renderedRows.length} disabled={!$renderedRows.length}
/> />
{#if $stickyColumn} {#if $displayColumn}
<HeaderCell column={$stickyColumn} orderable={false} idx="sticky"> <HeaderCell column={$displayColumn} orderable={false} idx="sticky">
<slot name="edit-column" /> <slot name="edit-column" />
</HeaderCell> </HeaderCell>
{/if} {/if}
@ -78,7 +77,7 @@
$hoveredRowId === row._id && $hoveredRowId === row._id &&
(!$selectedCellCount || !$isSelectingCells)} (!$selectedCellCount || !$isSelectingCells)}
{@const rowFocused = $focusedRow?._id === row._id} {@const rowFocused = $focusedRow?._id === row._id}
{@const cellId = getCellID(row._id, $stickyColumn?.name)} {@const cellId = getCellID(row._id, $displayColumn?.name)}
<div <div
class="row" class="row"
on:mouseenter={$isDragging ? null : () => ($hoveredRowId = row._id)} on:mouseenter={$isDragging ? null : () => ($hoveredRowId = row._id)}
@ -86,7 +85,7 @@
on:click={() => dispatch("rowclick", rows.actions.cleanRow(row))} on:click={() => dispatch("rowclick", rows.actions.cleanRow(row))}
> >
<GutterCell {row} {rowFocused} {rowHovered} {rowSelected} /> <GutterCell {row} {rowFocused} {rowHovered} {rowSelected} />
{#if $stickyColumn} {#if $displayColumn}
<DataCell <DataCell
{row} {row}
{cellId} {cellId}
@ -98,8 +97,8 @@
topRow={idx === 0} topRow={idx === 0}
focused={$focusedCellId === cellId} focused={$focusedCellId === cellId}
selectedUser={$userCellMap[cellId]} selectedUser={$userCellMap[cellId]}
width={$stickyColumn.width} width={$displayColumn.width}
column={$stickyColumn} column={$displayColumn}
contentLines={$contentLines} contentLines={$contentLines}
isSelectingCells={$isSelectingCells} isSelectingCells={$isSelectingCells}
/> />
@ -118,9 +117,9 @@
<GutterCell rowHovered={$hoveredRowId === BlankRowID}> <GutterCell rowHovered={$hoveredRowId === BlankRowID}>
<Icon name="Add" color="var(--spectrum-global-color-gray-500)" /> <Icon name="Add" color="var(--spectrum-global-color-gray-500)" />
</GutterCell> </GutterCell>
{#if $stickyColumn} {#if $displayColumn}
<GridCell <GridCell
width={$stickyColumn.width} width={$displayColumn.width}
highlighted={$hoveredRowId === BlankRowID} highlighted={$hoveredRowId === BlankRowID}
> >
<KeyboardShortcut padded keybind="Ctrl+Enter" /> <KeyboardShortcut padded keybind="Ctrl+Enter" />

View File

@ -8,7 +8,6 @@
focusedCellId, focusedCellId,
visibleColumns, visibleColumns,
rowLookupMap, rowLookupMap,
stickyColumn,
focusedCellAPI, focusedCellAPI,
dispatch, dispatch,
selectedRowCount, selectedRowCount,
@ -168,7 +167,7 @@
if (!firstRow) { if (!firstRow) {
return return
} }
const firstColumn = $stickyColumn || $visibleColumns[0] const firstColumn = $visibleColumns[0]
if (!firstColumn) { if (!firstColumn) {
return return
} }

View File

@ -6,30 +6,30 @@
const { const {
isReordering, isReordering,
reorder, reorder,
visibleColumns, visibleColumnLookupMap,
stickyColumn, displayColumn,
rowHeight, rowHeight,
renderedRows, renderedRows,
scrollLeft, scrollLeft,
} = getContext("grid") } = getContext("grid")
$: targetColumn = $reorder.targetColumn $: targetColumn = $visibleColumnLookupMap[$reorder.targetColumn]
$: minLeft = GutterWidth + ($stickyColumn?.width || 0) $: console.log(targetColumn)
$: left = getLeft(targetColumn, $stickyColumn, $visibleColumns, $scrollLeft) $: minLeft = GutterWidth + ($displayColumn?.width || 0)
$: left = getLeft(targetColumn, $displayColumn, $scrollLeft)
$: height = $rowHeight * $renderedRows.length + DefaultRowHeight $: height = $rowHeight * $renderedRows.length + DefaultRowHeight
$: style = `left:${left}px; height:${height}px;` $: style = `left:${left}px; height:${height}px;`
$: visible = $isReordering && left >= minLeft $: visible = $isReordering && left >= minLeft
const getLeft = (targetColumn, stickyColumn, visibleColumns, scrollLeft) => { const getLeft = (targetColumn, displayColumn, scrollLeft) => {
let left = GutterWidth + (stickyColumn?.width || 0) - scrollLeft if (!targetColumn) {
return 0
}
let left = GutterWidth + (displayColumn?.width || 0) - scrollLeft
// If this is not the sticky column, add additional left space // If this is not the sticky column, add additional left space
if (targetColumn !== stickyColumn?.name) { if (!targetColumn.primaryDisplay) {
const column = visibleColumns.find(x => x.name === targetColumn) left += targetColumn.__left + targetColumn.width
if (!column) {
return left
}
left += column.left + column.width
} }
return left return left

View File

@ -2,28 +2,28 @@
import { getContext } from "svelte" import { getContext } from "svelte"
import { GutterWidth } from "../lib/constants" import { GutterWidth } from "../lib/constants"
const { resize, visibleColumns, stickyColumn, isReordering, scrollLeft } = const { resize, visibleColumns, displayColumn, isReordering, scrollLeft } =
getContext("grid") getContext("grid")
$: offset = GutterWidth + ($stickyColumn?.width || 0) $: offset = GutterWidth + ($displayColumn?.width || 0)
$: activeColumn = $resize.column $: activeColumn = $resize.column
const getStyle = (column, offset, scrollLeft) => { const getStyle = (column, offset, scrollLeft) => {
const left = offset + column.left + column.width - scrollLeft const left = offset + column.__left + column.width - scrollLeft
return `left:${left}px;` return `left:${left}px;`
} }
</script> </script>
<!-- svelte-ignore a11y-no-static-element-interactions --> <!-- svelte-ignore a11y-no-static-element-interactions -->
{#if !$isReordering} {#if !$isReordering}
{#if $stickyColumn} {#if $displayColumn}
<div <div
class="resize-slider" class="resize-slider"
class:visible={activeColumn === $stickyColumn.name} class:visible={activeColumn === $displayColumn.name}
on:mousedown={e => resize.actions.startResizing($stickyColumn, e)} on:mousedown={e => resize.actions.startResizing($displayColumn, e)}
on:touchstart={e => resize.actions.startResizing($stickyColumn, e)} on:touchstart={e => resize.actions.startResizing($displayColumn, e)}
on:dblclick={() => resize.actions.resetSize($stickyColumn)} on:dblclick={() => resize.actions.resetSize($displayColumn)}
style="left:{GutterWidth + $stickyColumn.width}px;" style="left:{GutterWidth + $displayColumn.width}px;"
> >
<div class="resize-indicator" /> <div class="resize-indicator" />
</div> </div>

View File

@ -63,7 +63,7 @@ export const createActions = context => {
rowChangeCache, rowChangeCache,
rows, rows,
focusedCellId, focusedCellId,
columnLookupMap, visibleColumnLookupMap,
allVisibleColumns, allVisibleColumns,
} = context } = context
@ -156,9 +156,9 @@ export const createActions = context => {
const $focusedCellId = get(focusedCellId) const $focusedCellId = get(focusedCellId)
const { rowId, field } = parseCellID($focusedCellId) const { rowId, field } = parseCellID($focusedCellId)
const $rowLookupMap = get(rowLookupMap) const $rowLookupMap = get(rowLookupMap)
const $columnLookupMap = get(columnLookupMap) const $visibleColumnLookupMap = get(visibleColumnLookupMap)
const rowIdx = $rowLookupMap[rowId].__idx const rowIdx = $rowLookupMap[rowId].__idx
const colIdx = $columnLookupMap[field] const colIdx = $visibleColumnLookupMap[field].__idx
// Get limits of how many rows and columns we're able to paste into // Get limits of how many rows and columns we're able to paste into
const $rows = get(rows) const $rows = get(rows)

View File

@ -1,98 +1,87 @@
import { derived, get, writable } from "svelte/store" import { derived, get, writable } from "svelte/store"
import { GutterWidth, DefaultColumnWidth } from "../lib/constants" import { DefaultColumnWidth } from "../lib/constants"
export const createStores = () => { export const createStores = () => {
const columns = writable([]) const columns = writable([])
const stickyColumn = writable(null)
// Derive an enriched version of columns with left offsets and indexes const enrichedColumns = derived(columns, $columns => {
// automatically calculated return $columns.map((col, idx) => ({
const enrichedColumns = derived( ...col,
columns, __idx: idx,
$columns => { }))
let offset = 0 })
return $columns.map(column => {
const enriched = {
...column,
left: offset,
}
if (column.visible) {
offset += column.width
}
return enriched
})
},
[]
)
// Derived list of columns which have not been explicitly hidden
const visibleColumns = derived(
enrichedColumns,
$columns => {
return $columns.filter(col => col.visible)
},
[]
)
return { return {
columns: { columns: {
...columns, ...columns,
subscribe: enrichedColumns.subscribe, subscribe: enrichedColumns.subscribe,
}, },
stickyColumn,
visibleColumns,
} }
} }
export const deriveStores = context => { export const deriveStores = context => {
const { columns, stickyColumn, visibleColumns } = context const { columns } = context
// Quick access to all columns // Derive the primary display column
const allColumns = derived( const displayColumn = derived(columns, $columns => {
[columns, stickyColumn], return $columns.find(col => col.primaryDisplay)
([$columns, $stickyColumn]) => { })
let allCols = $columns || []
if ($stickyColumn) {
allCols = [$stickyColumn, ...allCols]
}
return allCols
}
)
// Quick access to all visible columns // Derive a lookup map for all columns by name
const allVisibleColumns = derived( const columnLookupMap = derived(columns, $columns => {
[visibleColumns, stickyColumn], let map = {}
([$visibleColumns, $stickyColumn]) => { $columns.forEach(column => {
let allCols = $visibleColumns || [] map[column.name] = column
if ($stickyColumn) { })
allCols = [$stickyColumn, ...allCols] return map
} })
return allCols
} // Derived list of columns which have not been explicitly hidden, and enrich
) // with an index so we can easily select nearby columns
const visibleColumns = derived(columns, $columns => {
let offset = 0
return $columns
.filter(col => col.visible)
.map((column, idx) => {
const enriched = {
...column,
__left: offset,
__idx: idx,
}
offset += column.width
return enriched
})
})
// Derive a lookup map for visible columns by name
const visibleColumnLookupMap = derived(visibleColumns, $visibleColumns => {
let map = {}
$visibleColumns.forEach(column => {
map[column.name] = column
})
return map
})
// Derive scrollable columns
const scrollableColumns = derived(visibleColumns, $visibleColumns => {
return $visibleColumns.filter(col => !col.primaryDisplay)
})
// Derive if we have any normal columns // Derive if we have any normal columns
const hasNonAutoColumn = derived(allColumns, $allColumns => { const hasNonAutoColumn = derived(columns, $columns => {
const normalCols = $allColumns.filter(column => { const normalCols = $columns.filter(column => {
return !column.schema?.autocolumn return !column.schema?.autocolumn
}) })
return normalCols.length > 0 return normalCols.length > 0
}) })
// Derive a lookup map for column indices by name
const columnLookupMap = derived(allVisibleColumns, $allVisibleColumns => {
let map = {}
$allVisibleColumns.forEach((column, idx) => {
map[column.name] = idx
})
return map
})
return { return {
allColumns, displayColumn,
allVisibleColumns,
hasNonAutoColumn,
columnLookupMap, columnLookupMap,
visibleColumns,
visibleColumnLookupMap,
scrollableColumns,
hasNonAutoColumn,
} }
} }
@ -110,6 +99,7 @@ export const createActions = context => {
await datasource.actions.saveSchemaMutations() await datasource.actions.saveSchemaMutations()
} }
// Checks if a column is readonly
const isReadonly = column => { const isReadonly = column => {
if (!column?.schema) { if (!column?.schema) {
return false return false
@ -134,49 +124,32 @@ export const createActions = context => {
} }
export const initialise = context => { export const initialise = context => {
const { const { definition, columns, displayColumn, enrichedSchema } = context
definition,
columns,
stickyColumn,
allColumns,
enrichedSchema,
compact,
} = context
// Merge new schema fields with existing schema in order to preserve widths // Merge new schema fields with existing schema in order to preserve widths
const processColumns = $enrichedSchema => { const processColumns = $enrichedSchema => {
if (!$enrichedSchema) { if (!$enrichedSchema) {
columns.set([]) columns.set([])
stickyColumn.set(null)
return return
} }
const $definition = get(definition) const $definition = get(definition)
const $allColumns = get(allColumns) const $columns = get(columns)
const $stickyColumn = get(stickyColumn) const $displayColumn = get(displayColumn)
const $compact = get(compact)
// Find primary display // Find primary display
let primaryDisplay let primaryDisplay
const candidatePD = $definition.primaryDisplay || $stickyColumn?.name const candidatePD = $definition.primaryDisplay || $displayColumn?.name
if (candidatePD && $enrichedSchema[candidatePD]) { if (candidatePD && $enrichedSchema[candidatePD]) {
primaryDisplay = candidatePD primaryDisplay = candidatePD
} }
// Get field list
let fields = []
Object.keys($enrichedSchema).forEach(field => {
if ($compact || field !== primaryDisplay) {
fields.push(field)
}
})
// Update columns, removing extraneous columns and adding missing ones // Update columns, removing extraneous columns and adding missing ones
columns.set( columns.set(
fields Object.keys($enrichedSchema)
.map(field => { .map(field => {
const fieldSchema = $enrichedSchema[field] const fieldSchema = $enrichedSchema[field]
const oldColumn = $allColumns?.find(x => x.name === field) const oldColumn = $columns?.find(col => col.name === field)
return { let column = {
name: field, name: field,
label: fieldSchema.displayName || field, label: fieldSchema.displayName || field,
schema: fieldSchema, schema: fieldSchema,
@ -184,19 +157,24 @@ export const initialise = context => {
visible: fieldSchema.visible ?? true, visible: fieldSchema.visible ?? true,
readonly: fieldSchema.readonly, readonly: fieldSchema.readonly,
order: fieldSchema.order ?? oldColumn?.order, order: fieldSchema.order ?? oldColumn?.order,
primaryDisplay: field === primaryDisplay,
} }
// Override a few properties for primary display
if (field === primaryDisplay) {
column.visible = true
column.order = 0
column.primaryDisplay = true
}
return column
}) })
.sort((a, b) => { .sort((a, b) => {
// If we don't have a pinned column then primary display will be in // Display column should always come first
// the normal columns list, and should be first
if (a.name === primaryDisplay) { if (a.name === primaryDisplay) {
return -1 return -1
} else if (b.name === primaryDisplay) { } else if (b.name === primaryDisplay) {
return 1 return 1
} }
// Sort by order first // Then sort by order
const orderA = a.order const orderA = a.order
const orderB = b.order const orderB = b.order
if (orderA != null && orderB != null) { if (orderA != null && orderB != null) {
@ -216,29 +194,8 @@ export const initialise = context => {
return autoColA ? 1 : -1 return autoColA ? 1 : -1
}) })
) )
// Update sticky column
if ($compact || !primaryDisplay) {
stickyColumn.set(null)
return
}
const stickySchema = $enrichedSchema[primaryDisplay]
const oldStickyColumn = $allColumns?.find(x => x.name === primaryDisplay)
stickyColumn.set({
name: primaryDisplay,
label: stickySchema.displayName || primaryDisplay,
schema: stickySchema,
width: stickySchema.width || oldStickyColumn?.width || DefaultColumnWidth,
visible: true,
order: 0,
left: GutterWidth,
primaryDisplay: true,
})
} }
// Process columns when schema changes // Process columns when schema changes
enrichedSchema.subscribe(processColumns) enrichedSchema.subscribe(processColumns)
// Process columns when compact flag changes
compact.subscribe(() => processColumns(get(enrichedSchema)))
} }

View File

@ -1,7 +1,7 @@
import { get } from "svelte/store" import { get } from "svelte/store"
export const createActions = context => { export const createActions = context => {
const { columns, stickyColumn, table, viewV2 } = context const { columns, table, viewV2 } = context
const saveDefinition = async () => { const saveDefinition = async () => {
throw "This datasource does not support updating the definition" throw "This datasource does not support updating the definition"
@ -30,9 +30,7 @@ export const createActions = context => {
} }
const canUseColumn = name => { const canUseColumn = name => {
const $columns = get(columns) return get(columns).some(col => col.name === name)
const $sticky = get(stickyColumn)
return $columns.some(col => col.name === name) || $sticky?.name === name
} }
return { return {

View File

@ -3,7 +3,7 @@ import { get } from "svelte/store"
const SuppressErrors = true const SuppressErrors = true
export const createActions = context => { export const createActions = context => {
const { API, datasource, columns, stickyColumn } = context const { API, datasource, columns } = context
const saveDefinition = async newDefinition => { const saveDefinition = async newDefinition => {
await API.saveTable(newDefinition) await API.saveTable(newDefinition)
@ -43,9 +43,7 @@ export const createActions = context => {
} }
const canUseColumn = name => { const canUseColumn = name => {
const $columns = get(columns) return get(columns).some(col => col.name === name)
const $sticky = get(stickyColumn)
return $columns.some(col => col.name === name) || $sticky?.name === name
} }
return { return {

View File

@ -3,7 +3,7 @@ import { get } from "svelte/store"
const SuppressErrors = true const SuppressErrors = true
export const createActions = context => { export const createActions = context => {
const { API, datasource, columns, stickyColumn } = context const { API, datasource, columns } = context
const saveDefinition = async newDefinition => { const saveDefinition = async newDefinition => {
await API.viewV2.update(newDefinition) await API.viewV2.update(newDefinition)
@ -40,12 +40,7 @@ export const createActions = context => {
} }
const canUseColumn = name => { const canUseColumn = name => {
const $columns = get(columns) return get(columns).some(col => col.name === name && col.visible)
const $sticky = get(stickyColumn)
return (
$columns.some(col => col.name === name && col.visible) ||
$sticky?.name === name
)
} }
return { return {

View File

@ -25,12 +25,12 @@ const DependencyOrderedStores = [
Sort, Sort,
Filter, Filter,
Bounds, Bounds,
Scroll,
Table, Table,
ViewV2, ViewV2,
NonPlus, NonPlus,
Datasource, Datasource,
Columns, Columns,
Scroll,
Validation, Validation,
Rows, Rows,
UI, UI,

View File

@ -28,10 +28,12 @@ export const createActions = context => {
const { const {
reorder, reorder,
columns, columns,
visibleColumns, columnLookupMap,
scrollableColumns,
visibleColumnLookupMap,
scroll, scroll,
bounds, bounds,
stickyColumn, visibleColumns,
maxScrollLeft, maxScrollLeft,
width, width,
datasource, datasource,
@ -42,26 +44,14 @@ export const createActions = context => {
// Callback when dragging on a colum header and starting reordering // Callback when dragging on a colum header and starting reordering
const startReordering = (column, e) => { const startReordering = (column, e) => {
const $visibleColumns = get(visibleColumns) const $scrollableColumns = get(scrollableColumns)
const $bounds = get(bounds) const $bounds = get(bounds)
const $stickyColumn = get(stickyColumn)
// Generate new breakpoints for the current columns // Generate new breakpoints for the current columns
let breakpoints = $visibleColumns.map(col => ({ const breakpoints = $scrollableColumns.map(col => ({
x: col.left + col.width, x: col.__left + col.width,
column: col.name, column: col.name,
})) }))
if ($stickyColumn) {
breakpoints.unshift({
x: 0,
column: $stickyColumn.name,
})
} else if (!$visibleColumns[0].primaryDisplay) {
breakpoints.unshift({
x: 0,
column: null,
})
}
// Update state // Update state
reorder.set({ reorder.set({
@ -185,9 +175,9 @@ export const createActions = context => {
// 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 = async (sourceColumn, targetColumn) => { const moveColumn = async (sourceColumn, targetColumn) => {
let $columns = get(columns) const $columnLookupMap = get(columnLookupMap)
let sourceIdx = $columns.findIndex(x => x.name === sourceColumn) let sourceIdx = $columnLookupMap[sourceColumn]
let targetIdx = $columns.findIndex(x => x.name === targetColumn) let targetIdx = $columnLookupMap[targetColumn]
targetIdx++ targetIdx++
columns.update(state => { columns.update(state => {
const removed = state.splice(sourceIdx, 1) const removed = state.splice(sourceIdx, 1)
@ -209,14 +199,16 @@ export const createActions = context => {
// 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 $visibleColumnLookupMap = get(visibleColumnLookupMap)
const sourceIdx = $visibleColumnLookupMap[column]
await moveColumn(column, $visibleColumns[sourceIdx - 2]?.name) await moveColumn(column, $visibleColumns[sourceIdx - 2]?.name)
} }
// Moves a column one place right (as appears visually) // Moves a column one place right (as appears visually)
const moveColumnRight = async column => { const moveColumnRight = async column => {
const $visibleColumns = get(visibleColumns) const $visibleColumns = get(visibleColumns)
const sourceIdx = $visibleColumns.findIndex(x => x.name === column) const $visibleColumnLookupMap = get(visibleColumnLookupMap)
const sourceIdx = $visibleColumnLookupMap[column]
if (sourceIdx === $visibleColumns.length - 1) { if (sourceIdx === $visibleColumns.length - 1) {
return return
} }

View File

@ -34,7 +34,7 @@ export const createActions = context => {
// Set initial store state // Set initial store state
resize.set({ resize.set({
width: column.width, width: column.width,
left: column.left, left: column.__left,
initialWidth: column.width, initialWidth: column.width,
initialMouseX: x, initialMouseX: x,
column: column.name, column: column.name,

View File

@ -24,7 +24,7 @@ export const deriveStores = context => {
const { const {
rows, rows,
visibleColumns, visibleColumns,
stickyColumn, displayColumn,
rowHeight, rowHeight,
width, width,
height, height,
@ -32,7 +32,7 @@ export const deriveStores = context => {
} = context } = context
// Memoize store primitives // Memoize store primitives
const stickyColumnWidth = derived(stickyColumn, $col => $col?.width || 0, 0) const stickyColumnWidth = derived(displayColumn, $col => $col?.width || 0, 0)
// Derive vertical limits // Derive vertical limits
const contentHeight = derived( const contentHeight = derived(
@ -196,7 +196,7 @@ export const initialise = context => {
// Ensure column is not cutoff on right edge // Ensure column is not cutoff on right edge
else { else {
const $buttonColumnWidth = get(buttonColumnWidth) const $buttonColumnWidth = get(buttonColumnWidth)
const rightEdge = column.left + column.width const rightEdge = column.__left + column.width
const rightBound = const rightBound =
$bounds.width + $scroll.left - FocusedCellMinOffset - $buttonColumnWidth $bounds.width + $scroll.left - FocusedCellMinOffset - $buttonColumnWidth
delta = rightEdge - rightBound delta = rightEdge - rightBound

View File

@ -50,7 +50,6 @@ export const deriveStores = context => {
rows, rows,
rowLookupMap, rowLookupMap,
rowHeight, rowHeight,
stickyColumn,
width, width,
selectedRows, selectedRows,
cellSelection, cellSelection,
@ -85,8 +84,8 @@ export const deriveStores = context => {
}) })
// Derive whether we should use the compact UI, depending on width // Derive whether we should use the compact UI, depending on width
const compact = derived([stickyColumn, width], ([$stickyColumn, $width]) => { const compact = derived(width, $width => {
return ($stickyColumn?.width || 0) + $width + GutterWidth < 800 return $width < 600
}) })
// Derive we have any selected rows or not // Derive we have any selected rows or not