Merge pull request #13610 from Budibase/table-width-setting
Table column initial width setting
This commit is contained in:
commit
39f59c076a
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import EditComponentPopover from "../EditComponentPopover/EditComponentPopover.svelte"
|
||||
import EditComponentPopover from "../EditComponentPopover.svelte"
|
||||
import { Icon } from "@budibase/bbui"
|
||||
import { runtimeToReadableBinding } from "dataBinding"
|
||||
import { isJSBinding } from "@budibase/string-templates"
|
||||
|
|
|
@ -100,9 +100,6 @@
|
|||
on:click={() => {
|
||||
get(store).actions.select(draggableItem.id)
|
||||
}}
|
||||
on:mousedown={() => {
|
||||
get(store).actions.select()
|
||||
}}
|
||||
bind:this={anchors[draggableItem.id]}
|
||||
class:highlighted={draggableItem.id === $store.selected}
|
||||
>
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import { componentStore } from "stores/builder"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import { createEventDispatcher, getContext } from "svelte"
|
||||
import { customPositionHandler } from "."
|
||||
import ComponentSettingsSection from "pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte"
|
||||
|
||||
export let anchor
|
||||
|
@ -18,76 +17,74 @@
|
|||
|
||||
let popover
|
||||
let drawers = []
|
||||
let open = false
|
||||
let isOpen = false
|
||||
|
||||
// Auto hide the component when another item is selected
|
||||
$: if (open && $draggable.selected !== componentInstance._id) {
|
||||
popover.hide()
|
||||
close()
|
||||
}
|
||||
|
||||
// Open automatically if the component is marked as selected
|
||||
$: if (!open && $draggable.selected === componentInstance._id && popover) {
|
||||
popover.show()
|
||||
open = true
|
||||
open()
|
||||
}
|
||||
|
||||
$: componentDef = componentStore.getDefinition(componentInstance._component)
|
||||
$: 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 => {
|
||||
if (!componentDef) {
|
||||
return {}
|
||||
}
|
||||
const clone = cloneDeep(componentDef)
|
||||
|
||||
if (typeof parseSettings === "function") {
|
||||
clone.settings = parseSettings(clone.settings)
|
||||
}
|
||||
|
||||
return clone
|
||||
}
|
||||
|
||||
const updateSetting = async (setting, value) => {
|
||||
const nestedComponentInstance = cloneDeep(componentInstance)
|
||||
|
||||
const patchFn = componentStore.updateComponentSetting(setting.key, value)
|
||||
patchFn(nestedComponentInstance)
|
||||
|
||||
dispatch("change", nestedComponentInstance)
|
||||
}
|
||||
</script>
|
||||
|
||||
<Icon
|
||||
name="Settings"
|
||||
hoverable
|
||||
size="S"
|
||||
on:click={() => {
|
||||
if (!open) {
|
||||
popover.show()
|
||||
open = true
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Icon name="Settings" hoverable size="S" on:click={toggleOpen} />
|
||||
|
||||
<Popover
|
||||
bind:this={popover}
|
||||
on:open={() => {
|
||||
drawers = []
|
||||
$draggable.actions.select(componentInstance._id)
|
||||
}}
|
||||
on:close={() => {
|
||||
open = false
|
||||
if ($draggable.selected === componentInstance._id) {
|
||||
$draggable.actions.select()
|
||||
}
|
||||
}}
|
||||
open={isOpen}
|
||||
on:close={close}
|
||||
{anchor}
|
||||
align="left-outside"
|
||||
showPopover={drawers.length === 0}
|
||||
clickOutsideOverride={drawers.length > 0}
|
||||
maxHeight={600}
|
||||
offset={18}
|
||||
handlePostionUpdate={customPositionHandler}
|
||||
>
|
||||
<span class="popover-wrap">
|
||||
<Layout noPadding noGap>
|
|
@ -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 }
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import EditComponentPopover from "../EditComponentPopover/EditComponentPopover.svelte"
|
||||
import EditComponentPopover from "../EditComponentPopover.svelte"
|
||||
import { Toggle, Icon } from "@budibase/bbui"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import EditComponentPopover from "../EditComponentPopover/EditComponentPopover.svelte"
|
||||
import EditComponentPopover from "../EditComponentPopover.svelte"
|
||||
import { Toggle, Icon } from "@budibase/bbui"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import EditComponentPopover from "../EditComponentPopover/EditComponentPopover.svelte"
|
||||
import EditComponentPopover from "../EditComponentPopover.svelte"
|
||||
import { Icon } from "@budibase/bbui"
|
||||
import { setContext } from "svelte"
|
||||
import { writable } from "svelte/store"
|
||||
|
|
|
@ -67,6 +67,7 @@ const toGridFormat = draggableListColumns => {
|
|||
label: entry.label,
|
||||
field: entry.field,
|
||||
active: entry.active,
|
||||
width: entry.width,
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -81,6 +82,7 @@ const toDraggableListFormat = (gridFormatColumns, createComponent, schema) => {
|
|||
field: column.field,
|
||||
label: column.label,
|
||||
columnType: schema[column.field].type,
|
||||
width: column.width,
|
||||
},
|
||||
{}
|
||||
)
|
||||
|
|
|
@ -10,7 +10,6 @@ import {
|
|||
NewFormSteps,
|
||||
} from "./steps"
|
||||
import { API } from "api"
|
||||
import { customPositionHandler } from "components/design/settings/controls/EditComponentPopover"
|
||||
|
||||
const ONBOARDING_EVENT_PREFIX = "onboarding"
|
||||
|
||||
|
@ -187,7 +186,6 @@ const getTours = () => {
|
|||
tourEvent(TOUR_STEP_KEYS.BUILDER_FORM_CREATE_STEPS)
|
||||
builderStore.highlightSetting("steps", "info")
|
||||
},
|
||||
positionHandler: customPositionHandler,
|
||||
align: "left-outside",
|
||||
},
|
||||
],
|
||||
|
@ -203,7 +201,6 @@ const getTours = () => {
|
|||
tourEvent(TOUR_STEP_KEYS.BUILDER_FORM_ROW_ID)
|
||||
builderStore.highlightSetting("rowId", "info")
|
||||
},
|
||||
positionHandler: customPositionHandler,
|
||||
align: "left-outside",
|
||||
},
|
||||
{
|
||||
|
@ -219,7 +216,6 @@ const getTours = () => {
|
|||
tourEvent(TOUR_STEP_KEYS.BUILDER_FORM_VIEW_UPDATE_STEPS)
|
||||
builderStore.highlightSetting("steps", "info")
|
||||
},
|
||||
positionHandler: customPositionHandler,
|
||||
align: "left-outside",
|
||||
scrollIntoView: true,
|
||||
},
|
||||
|
|
|
@ -2746,6 +2746,14 @@
|
|||
"type": "plainText",
|
||||
"label": "Label",
|
||||
"key": "label"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"label": "Initial width",
|
||||
"key": "width",
|
||||
"placeholder": "Auto",
|
||||
"min": 80,
|
||||
"max": 9999
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
$: schemaOverrides = getSchemaOverrides(parsedColumns)
|
||||
$: enrichedButtons = enrichButtons(buttons)
|
||||
$: selectedRows = deriveSelectedRows(gridContext)
|
||||
$: styles = patchStyles($component.styles, minHeight)
|
||||
$: data = { selectedRows: $selectedRows }
|
||||
$: actions = [
|
||||
{
|
||||
|
@ -84,9 +85,11 @@
|
|||
|
||||
const getSchemaOverrides = columns => {
|
||||
let overrides = {}
|
||||
columns.forEach(column => {
|
||||
columns.forEach((column, idx) => {
|
||||
overrides[column.field] = {
|
||||
displayName: column.label,
|
||||
width: column.width,
|
||||
order: idx,
|
||||
}
|
||||
})
|
||||
return overrides
|
||||
|
@ -128,52 +131,54 @@
|
|||
)
|
||||
}
|
||||
|
||||
const patchStyles = (styles, minHeight) => {
|
||||
return {
|
||||
...styles,
|
||||
normal: {
|
||||
...styles?.normal,
|
||||
"min-height": `${minHeight}px`,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
gridContext = grid.getContext()
|
||||
gridContext.minHeight.subscribe($height => (minHeight = $height))
|
||||
})
|
||||
</script>
|
||||
|
||||
<span style="--min-height:{minHeight}px">
|
||||
<div
|
||||
use:styleable={$component.styles}
|
||||
class:in-builder={$builderStore.inBuilder}
|
||||
>
|
||||
<Grid
|
||||
bind:this={grid}
|
||||
datasource={table}
|
||||
{API}
|
||||
{stripeRows}
|
||||
{quiet}
|
||||
{initialFilter}
|
||||
{initialSortColumn}
|
||||
{initialSortOrder}
|
||||
{fixedRowHeight}
|
||||
{columnWhitelist}
|
||||
{schemaOverrides}
|
||||
canAddRows={allowAddRows}
|
||||
canEditRows={allowEditRows}
|
||||
canDeleteRows={allowDeleteRows}
|
||||
canEditColumns={false}
|
||||
canExpandRows={false}
|
||||
canSaveSchema={false}
|
||||
canSelectRows={true}
|
||||
showControls={false}
|
||||
notifySuccess={notificationStore.actions.success}
|
||||
notifyError={notificationStore.actions.error}
|
||||
buttons={enrichedButtons}
|
||||
isCloud={$environmentStore.cloud}
|
||||
on:rowclick={e => onRowClick?.({ row: e.detail })}
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
<div use:styleable={styles} class:in-builder={$builderStore.inBuilder}>
|
||||
<Grid
|
||||
bind:this={grid}
|
||||
datasource={table}
|
||||
{API}
|
||||
{stripeRows}
|
||||
{quiet}
|
||||
{initialFilter}
|
||||
{initialSortColumn}
|
||||
{initialSortOrder}
|
||||
{fixedRowHeight}
|
||||
{columnWhitelist}
|
||||
{schemaOverrides}
|
||||
canAddRows={allowAddRows}
|
||||
canEditRows={allowEditRows}
|
||||
canDeleteRows={allowDeleteRows}
|
||||
canEditColumns={false}
|
||||
canExpandRows={false}
|
||||
canSaveSchema={false}
|
||||
canSelectRows={true}
|
||||
showControls={false}
|
||||
notifySuccess={notificationStore.actions.success}
|
||||
notifyError={notificationStore.actions.error}
|
||||
buttons={enrichedButtons}
|
||||
isCloud={$environmentStore.cloud}
|
||||
on:rowclick={e => onRowClick?.({ row: e.detail })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Provider {data} {actions} />
|
||||
|
||||
<style>
|
||||
span {
|
||||
display: contents;
|
||||
}
|
||||
div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -182,7 +187,6 @@
|
|||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
height: 410px;
|
||||
min-height: var(--min-height);
|
||||
}
|
||||
div.in-builder :global(*) {
|
||||
pointer-events: none;
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
subscribe,
|
||||
config,
|
||||
ui,
|
||||
columns,
|
||||
definition,
|
||||
datasource,
|
||||
schema,
|
||||
|
@ -158,17 +157,13 @@
|
|||
}
|
||||
|
||||
const makeDisplayColumn = () => {
|
||||
columns.actions.changePrimaryDisplay(column.name)
|
||||
datasource.actions.changePrimaryDisplay(column.name)
|
||||
open = false
|
||||
}
|
||||
|
||||
const hideColumn = () => {
|
||||
columns.update(state => {
|
||||
const index = state.findIndex(col => col.name === column.name)
|
||||
state[index].visible = false
|
||||
return state.slice()
|
||||
})
|
||||
columns.actions.saveChanges()
|
||||
datasource.actions.addSchemaMutation(column.name, { visible: false })
|
||||
datasource.actions.saveSchemaMutations()
|
||||
open = false
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import { ActionButton, Popover, Toggle, Icon } from "@budibase/bbui"
|
||||
import { getColumnIcon } from "../lib/utils"
|
||||
|
||||
const { columns, stickyColumn, dispatch } = getContext("grid")
|
||||
const { columns, datasource, stickyColumn, dispatch } = getContext("grid")
|
||||
|
||||
let open = false
|
||||
let anchor
|
||||
|
@ -11,36 +11,20 @@
|
|||
$: anyHidden = $columns.some(col => !col.visible)
|
||||
$: text = getText($columns)
|
||||
|
||||
const toggleVisibility = async (column, visible) => {
|
||||
columns.update(state => {
|
||||
const index = state.findIndex(col => col.name === column.name)
|
||||
state[index].visible = visible
|
||||
return state.slice()
|
||||
})
|
||||
await columns.actions.saveChanges()
|
||||
const toggleColumn = async (column, visible) => {
|
||||
datasource.actions.addSchemaMutation(column.name, { visible })
|
||||
await datasource.actions.saveSchemaMutations()
|
||||
dispatch(visible ? "show-column" : "hide-column")
|
||||
}
|
||||
|
||||
const showAll = async () => {
|
||||
columns.update(state => {
|
||||
return state.map(col => ({
|
||||
...col,
|
||||
visible: true,
|
||||
}))
|
||||
const toggleAll = async visible => {
|
||||
let mutations = {}
|
||||
$columns.forEach(column => {
|
||||
mutations[column.name] = { visible }
|
||||
})
|
||||
await columns.actions.saveChanges()
|
||||
dispatch("show-column")
|
||||
}
|
||||
|
||||
const hideAll = async () => {
|
||||
columns.update(state => {
|
||||
return state.map(col => ({
|
||||
...col,
|
||||
visible: false,
|
||||
}))
|
||||
})
|
||||
await columns.actions.saveChanges()
|
||||
dispatch("hide-column")
|
||||
datasource.actions.addSchemaMutations(mutations)
|
||||
await datasource.actions.saveSchemaMutations()
|
||||
dispatch(visible ? "show-column" : "hide-column")
|
||||
}
|
||||
|
||||
const getText = columns => {
|
||||
|
@ -80,14 +64,14 @@
|
|||
<Toggle
|
||||
size="S"
|
||||
value={column.visible}
|
||||
on:change={e => toggleVisibility(column, e.detail)}
|
||||
on:change={e => toggleColumn(column, e.detail)}
|
||||
disabled={column.primaryDisplay}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<ActionButton on:click={showAll}>Show all</ActionButton>
|
||||
<ActionButton on:click={hideAll}>Hide all</ActionButton>
|
||||
<ActionButton on:click={() => toggleAll(true)}>Show all</ActionButton>
|
||||
<ActionButton on:click={() => toggleAll(false)}>Hide all</ActionButton>
|
||||
</div>
|
||||
</div>
|
||||
</Popover>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { derived, get, writable } from "svelte/store"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import { GutterWidth, DefaultColumnWidth } from "../lib/constants"
|
||||
|
||||
export const createStores = () => {
|
||||
|
@ -75,72 +74,23 @@ export const deriveStores = context => {
|
|||
}
|
||||
|
||||
export const createActions = context => {
|
||||
const { columns, stickyColumn, datasource, definition, schema } = context
|
||||
|
||||
// Updates the datasources primary display column
|
||||
const changePrimaryDisplay = async column => {
|
||||
return await datasource.actions.saveDefinition({
|
||||
...get(definition),
|
||||
primaryDisplay: column,
|
||||
})
|
||||
}
|
||||
const { columns, datasource, schema } = 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 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,
|
||||
const $schema = get(schema)
|
||||
let mutations = {}
|
||||
Object.keys($schema).forEach(field => {
|
||||
mutations[field] = { width }
|
||||
})
|
||||
datasource.actions.addSchemaMutations(mutations)
|
||||
await datasource.actions.saveSchemaMutations()
|
||||
}
|
||||
|
||||
return {
|
||||
columns: {
|
||||
...columns,
|
||||
actions: {
|
||||
saveChanges,
|
||||
changePrimaryDisplay,
|
||||
changeAllColumnWidths,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -4,15 +4,23 @@ import { memo } from "../../../utils"
|
|||
|
||||
export const createStores = () => {
|
||||
const definition = memo(null)
|
||||
const schemaMutations = memo({})
|
||||
|
||||
return {
|
||||
definition,
|
||||
schemaMutations,
|
||||
}
|
||||
}
|
||||
|
||||
export const deriveStores = context => {
|
||||
const { API, definition, schemaOverrides, columnWhitelist, datasource } =
|
||||
context
|
||||
const {
|
||||
API,
|
||||
definition,
|
||||
schemaOverrides,
|
||||
columnWhitelist,
|
||||
datasource,
|
||||
schemaMutations,
|
||||
} = context
|
||||
|
||||
const schema = derived(definition, $definition => {
|
||||
let schema = getDatasourceSchema({
|
||||
|
@ -35,42 +43,26 @@ export const deriveStores = context => {
|
|||
return schema
|
||||
})
|
||||
|
||||
// Derives the total enriched schema, made up of the saved schema and any
|
||||
// prop and user overrides
|
||||
const enrichedSchema = derived(
|
||||
[schema, schemaOverrides, columnWhitelist],
|
||||
([$schema, $schemaOverrides, $columnWhitelist]) => {
|
||||
[schema, schemaOverrides, schemaMutations, columnWhitelist],
|
||||
([$schema, $schemaOverrides, $schemaMutations, $columnWhitelist]) => {
|
||||
if (!$schema) {
|
||||
return null
|
||||
}
|
||||
let enrichedSchema = { ...$schema }
|
||||
|
||||
// Apply schema overrides
|
||||
Object.keys($schemaOverrides || {}).forEach(field => {
|
||||
if (enrichedSchema[field]) {
|
||||
enrichedSchema[field] = {
|
||||
...enrichedSchema[field],
|
||||
...$schemaOverrides[field],
|
||||
}
|
||||
let enrichedSchema = {}
|
||||
Object.keys($schema).forEach(field => {
|
||||
// Apply whitelist if provided
|
||||
if ($columnWhitelist?.length && !$columnWhitelist.includes(field)) {
|
||||
return
|
||||
}
|
||||
enrichedSchema[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
|
||||
}
|
||||
)
|
||||
|
@ -100,6 +92,8 @@ export const createActions = context => {
|
|||
table,
|
||||
viewV2,
|
||||
nonPlus,
|
||||
schemaMutations,
|
||||
schema,
|
||||
} = context
|
||||
|
||||
// Gets the appropriate API for the configured datasource type
|
||||
|
@ -136,11 +130,81 @@ export const createActions = context => {
|
|||
// Update server
|
||||
if (get(config).canSaveSchema) {
|
||||
await getAPI()?.actions.saveDefinition(newDefinition)
|
||||
}
|
||||
|
||||
// Broadcast change to external state can be updated, as this change
|
||||
// will not be received by the builder websocket because we caused it ourselves
|
||||
dispatch("updatedatasource", newDefinition)
|
||||
// Broadcast change so external state can be updated, as this change
|
||||
// will not be received by the builder websocket because we caused it
|
||||
// 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
|
||||
|
@ -185,6 +249,10 @@ export const createActions = context => {
|
|||
getRow,
|
||||
isDatasourceValid,
|
||||
canUseColumn,
|
||||
changePrimaryDisplay,
|
||||
addSchemaMutation,
|
||||
addSchemaMutations,
|
||||
saveSchemaMutations,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ export const createActions = context => {
|
|||
stickyColumn,
|
||||
maxScrollLeft,
|
||||
width,
|
||||
datasource,
|
||||
} = context
|
||||
|
||||
let autoScrollInterval
|
||||
|
@ -173,20 +174,17 @@ export const createActions = context => {
|
|||
document.removeEventListener("touchend", stopReordering)
|
||||
document.removeEventListener("touchcancel", stopReordering)
|
||||
|
||||
// Ensure there's actually a change
|
||||
let { sourceColumn, targetColumn } = get(reorder)
|
||||
if (sourceColumn !== targetColumn) {
|
||||
moveColumn(sourceColumn, targetColumn)
|
||||
await columns.actions.saveChanges()
|
||||
}
|
||||
|
||||
// Reset state
|
||||
// Ensure there's actually a change before saving
|
||||
const { sourceColumn, targetColumn } = get(reorder)
|
||||
reorder.set(reorderInitialState)
|
||||
if (sourceColumn !== targetColumn) {
|
||||
await moveColumn(sourceColumn, targetColumn)
|
||||
}
|
||||
}
|
||||
|
||||
// Moves a column after another columns.
|
||||
// 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 sourceIdx = $columns.findIndex(x => x.name === sourceColumn)
|
||||
let targetIdx = $columns.findIndex(x => x.name === targetColumn)
|
||||
|
@ -198,14 +196,21 @@ export const createActions = context => {
|
|||
}
|
||||
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)
|
||||
const moveColumnLeft = async column => {
|
||||
const $visibleColumns = get(visibleColumns)
|
||||
const sourceIdx = $visibleColumns.findIndex(x => x.name === column)
|
||||
moveColumn(column, $visibleColumns[sourceIdx - 2]?.name)
|
||||
await columns.actions.saveChanges()
|
||||
await moveColumn(column, $visibleColumns[sourceIdx - 2]?.name)
|
||||
}
|
||||
|
||||
// Moves a column one place right (as appears visually)
|
||||
|
@ -215,8 +220,7 @@ export const createActions = context => {
|
|||
if (sourceIdx === $visibleColumns.length - 1) {
|
||||
return
|
||||
}
|
||||
moveColumn(column, $visibleColumns[sourceIdx + 1]?.name)
|
||||
await columns.actions.saveChanges()
|
||||
await moveColumn(column, $visibleColumns[sourceIdx + 1]?.name)
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -6,7 +6,6 @@ const initialState = {
|
|||
initialMouseX: null,
|
||||
initialWidth: null,
|
||||
column: null,
|
||||
columnIdx: null,
|
||||
width: 0,
|
||||
left: 0,
|
||||
}
|
||||
|
@ -21,7 +20,7 @@ export const createStores = () => {
|
|||
}
|
||||
|
||||
export const createActions = context => {
|
||||
const { resize, columns, stickyColumn, ui } = context
|
||||
const { resize, ui, datasource } = context
|
||||
|
||||
// Starts resizing a certain column
|
||||
const startResizing = (column, e) => {
|
||||
|
@ -32,12 +31,6 @@ export const createActions = context => {
|
|||
e.preventDefault()
|
||||
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
|
||||
resize.set({
|
||||
width: column.width,
|
||||
|
@ -45,7 +38,6 @@ export const createActions = context => {
|
|||
initialWidth: column.width,
|
||||
initialMouseX: x,
|
||||
column: column.name,
|
||||
columnIdx,
|
||||
})
|
||||
|
||||
// Add mouse event listeners to handle resizing
|
||||
|
@ -58,7 +50,7 @@ export const createActions = context => {
|
|||
|
||||
// Handler for moving the mouse to resize columns
|
||||
const onResizeMouseMove = e => {
|
||||
const { initialMouseX, initialWidth, width, columnIdx } = get(resize)
|
||||
const { initialMouseX, initialWidth, width, column } = get(resize)
|
||||
const { x } = parseEventLocation(e)
|
||||
const dx = x - initialMouseX
|
||||
const newWidth = Math.round(Math.max(MinColumnWidth, initialWidth + dx))
|
||||
|
@ -69,17 +61,7 @@ export const createActions = context => {
|
|||
}
|
||||
|
||||
// Update column state
|
||||
if (columnIdx === "sticky") {
|
||||
stickyColumn.update(state => ({
|
||||
...state,
|
||||
width: newWidth,
|
||||
}))
|
||||
} else {
|
||||
columns.update(state => {
|
||||
state[columnIdx].width = newWidth
|
||||
return [...state]
|
||||
})
|
||||
}
|
||||
datasource.actions.addSchemaMutation(column, { width })
|
||||
|
||||
// Update state
|
||||
resize.update(state => ({
|
||||
|
@ -101,26 +83,16 @@ export const createActions = context => {
|
|||
|
||||
// Persist width if it changed
|
||||
if ($resize.width !== $resize.initialWidth) {
|
||||
await columns.actions.saveChanges()
|
||||
await datasource.actions.saveSchemaMutations()
|
||||
}
|
||||
}
|
||||
|
||||
// Resets a column size back to default
|
||||
const resetSize = async column => {
|
||||
const $stickyColumn = get(stickyColumn)
|
||||
if (column.name === $stickyColumn?.name) {
|
||||
stickyColumn.update(state => ({
|
||||
...state,
|
||||
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()
|
||||
datasource.actions.addSchemaMutation(column.name, {
|
||||
width: DefaultColumnWidth,
|
||||
})
|
||||
await datasource.actions.saveSchemaMutations()
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
Loading…
Reference in New Issue