Separate data fetching logic from main sheet and tidy up
This commit is contained in:
parent
30e1ecd67f
commit
b45ba0eba7
|
@ -0,0 +1,87 @@
|
||||||
|
<script>
|
||||||
|
import SheetCell from "./SheetCell.svelte"
|
||||||
|
import { getContext } from "svelte"
|
||||||
|
import { Icon } from "@budibase/bbui"
|
||||||
|
|
||||||
|
const { visibleColumns, reorder, selectedRows, rows } =
|
||||||
|
getContext("spreadsheet")
|
||||||
|
|
||||||
|
$: rowCount = $rows.length
|
||||||
|
$: selectedRowCount = Object.values($selectedRows).filter(x => !!x).length
|
||||||
|
|
||||||
|
const getIconForField = field => {
|
||||||
|
const type = field.schema.type
|
||||||
|
if (type === "options") {
|
||||||
|
return "ChevronDown"
|
||||||
|
} else if (type === "datetime") {
|
||||||
|
return "Date"
|
||||||
|
}
|
||||||
|
return "Text"
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectAll = () => {
|
||||||
|
const allSelected = selectedRowCount === rowCount
|
||||||
|
if (allSelected) {
|
||||||
|
$selectedRows = {}
|
||||||
|
} else {
|
||||||
|
selectedRows.update(state => {
|
||||||
|
$rows.forEach(row => {
|
||||||
|
state[row._id] = true
|
||||||
|
})
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<!-- Field headers -->
|
||||||
|
<SheetCell header label on:click={selectAll} width="40" left="0">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={rowCount && selectedRowCount === rowCount}
|
||||||
|
/>
|
||||||
|
</SheetCell>
|
||||||
|
{#each $visibleColumns as column}
|
||||||
|
<SheetCell
|
||||||
|
header
|
||||||
|
sticky={column.idx === 0}
|
||||||
|
reorderSource={$reorder.columnIdx === column.idx}
|
||||||
|
reorderTarget={$reorder.swapColumnIdx === column.idx}
|
||||||
|
on:mousedown={column.idx === 0
|
||||||
|
? null
|
||||||
|
: e => reorder.actions.startReordering(column.idx, e)}
|
||||||
|
width={column.width}
|
||||||
|
left={column.left}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
size="S"
|
||||||
|
name={getIconForField(column)}
|
||||||
|
color="var(--spectrum-global-color-gray-600)"
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
{column.name}
|
||||||
|
</span>
|
||||||
|
</SheetCell>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
width: inherit;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
.row.new {
|
||||||
|
position: absolute;
|
||||||
|
transform: translateY(var(--top));
|
||||||
|
}
|
||||||
|
.row :global(> :last-child) {
|
||||||
|
border-right-width: 1px;
|
||||||
|
}
|
||||||
|
input[type="checkbox"] {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,43 @@
|
||||||
|
<script>
|
||||||
|
import SheetCell from "./SheetCell.svelte"
|
||||||
|
import { Icon } from "@budibase/bbui"
|
||||||
|
import { getContext } from "svelte"
|
||||||
|
|
||||||
|
const { visibleColumns, cellHeight, rows, selectedCellId } =
|
||||||
|
getContext("spreadsheet")
|
||||||
|
|
||||||
|
const addRow = async field => {
|
||||||
|
const newRow = await rows.actions.addRow()
|
||||||
|
$selectedCellId = `${newRow._id}-${field.name}`
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="row new" style="--top:{($rows.length + 1) * cellHeight}px;">
|
||||||
|
<SheetCell label on:click={addRow} width="40" left="0">
|
||||||
|
<Icon hoverable name="Add" size="S" />
|
||||||
|
</SheetCell>
|
||||||
|
{#each $visibleColumns as column}
|
||||||
|
<SheetCell
|
||||||
|
sticky={column.idx === 0}
|
||||||
|
on:click={() => addRow(column)}
|
||||||
|
width={column.width}
|
||||||
|
left={column.left}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
top: var(--top);
|
||||||
|
width: inherit;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
.row:hover :global(.cell) {
|
||||||
|
background: var(--cell-background-hover);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.row :global(> :last-child) {
|
||||||
|
border-right-width: 1px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,16 +1,16 @@
|
||||||
<script>
|
<script>
|
||||||
import { setContext } from "svelte"
|
import { setContext } from "svelte"
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
import { fetchData } from "../../fetch/fetchData"
|
|
||||||
import { LuceneUtils } from "../../utils"
|
|
||||||
import { Icon } from "@budibase/bbui"
|
|
||||||
import { createReorderStores } from "./stores/reorder"
|
import { createReorderStores } from "./stores/reorder"
|
||||||
import { createViewportStores } from "./stores/viewport"
|
import { createViewportStores } from "./stores/viewport"
|
||||||
import SpreadsheetHeader from "./SheetHeader.svelte"
|
import { createRowsStore } from "./stores/rows"
|
||||||
import SpreadsheetBody from "./SheetBody.svelte"
|
import SheetHeader from "./SheetHeader.svelte"
|
||||||
import SpreadsheetCell from "./SheetCell.svelte"
|
import SheetBody from "./SheetBody.svelte"
|
||||||
import SpreadsheetRow from "./SheetRow.svelte"
|
import SheetRow from "./SheetRow.svelte"
|
||||||
import ResizeOverlay from "./ResizeOverlay.svelte"
|
import ResizeOverlay from "./ResizeOverlay.svelte"
|
||||||
|
import HeaderRow from "./HeaderRow.svelte"
|
||||||
|
import NewRow from "./NewRow.svelte"
|
||||||
|
import { createAPIClient } from "../../api"
|
||||||
|
|
||||||
export let tableId
|
export let tableId
|
||||||
export let filter
|
export let filter
|
||||||
|
@ -20,17 +20,14 @@
|
||||||
|
|
||||||
// Sheet constants
|
// Sheet constants
|
||||||
const cellHeight = 36
|
const cellHeight = 36
|
||||||
const limit = 100
|
|
||||||
const defaultWidth = 200
|
const defaultWidth = 200
|
||||||
const rand = Math.random()
|
const rand = Math.random()
|
||||||
|
|
||||||
// State stores
|
// State stores
|
||||||
const rows = writable([])
|
const tableIdStore = writable(tableId)
|
||||||
const columns = writable([])
|
const columns = writable([])
|
||||||
const selectedCellId = writable(null)
|
const selectedCellId = writable(null)
|
||||||
const selectedRows = writable({})
|
const selectedRows = writable({})
|
||||||
const changeCache = writable({})
|
|
||||||
const newRows = writable([])
|
|
||||||
const scroll = writable({
|
const scroll = writable({
|
||||||
left: 0,
|
left: 0,
|
||||||
top: 0,
|
top: 0,
|
||||||
|
@ -44,55 +41,28 @@
|
||||||
|
|
||||||
// Build up spreadsheet context and additional stores
|
// Build up spreadsheet context and additional stores
|
||||||
let context = {
|
let context = {
|
||||||
API,
|
API: API || createAPIClient(),
|
||||||
rand,
|
rand,
|
||||||
rows,
|
|
||||||
columns,
|
columns,
|
||||||
selectedCellId,
|
selectedCellId,
|
||||||
selectedRows,
|
selectedRows,
|
||||||
tableId,
|
|
||||||
changeCache,
|
|
||||||
newRows,
|
|
||||||
cellHeight,
|
cellHeight,
|
||||||
bounds,
|
bounds,
|
||||||
scroll,
|
scroll,
|
||||||
|
tableId: tableIdStore,
|
||||||
}
|
}
|
||||||
|
const { rows, schema, primaryDisplay } = createRowsStore(context)
|
||||||
|
context = { ...context, rows }
|
||||||
const { visibleRows, visibleColumns } = createViewportStores(context)
|
const { visibleRows, visibleColumns } = createViewportStores(context)
|
||||||
context = { ...context, visibleRows, visibleColumns }
|
context = { ...context, visibleRows, visibleColumns }
|
||||||
const { reorder } = createReorderStores(context)
|
const { reorder } = createReorderStores(context)
|
||||||
|
context = { ...context, reorder }
|
||||||
|
|
||||||
$: query = LuceneUtils.buildLuceneQuery(filter)
|
$: tableIdStore.set(tableId)
|
||||||
$: fetch = createFetch(tableId)
|
$: generateColumns($schema, $primaryDisplay)
|
||||||
$: fetch.update({
|
|
||||||
sortColumn,
|
|
||||||
sortOrder,
|
|
||||||
query,
|
|
||||||
limit,
|
|
||||||
})
|
|
||||||
$: generateColumns($fetch)
|
|
||||||
$: rowCount = $rows.length
|
|
||||||
$: selectedRowCount = Object.values($selectedRows).filter(x => !!x).length
|
|
||||||
$: updateSortedRows($fetch, $newRows)
|
|
||||||
|
|
||||||
const createFetch = tableId => {
|
|
||||||
return fetchData({
|
|
||||||
API,
|
|
||||||
datasource: {
|
|
||||||
type: "table",
|
|
||||||
tableId,
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
sortColumn,
|
|
||||||
sortOrder,
|
|
||||||
query,
|
|
||||||
limit,
|
|
||||||
paginate: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates the column array the first time the schema loads
|
// Generates the column array the first time the schema loads
|
||||||
const generateColumns = ({ schema, definition }) => {
|
const generateColumns = (schema, primaryDisplay) => {
|
||||||
if (!schema) {
|
if (!schema) {
|
||||||
$columns = []
|
$columns = []
|
||||||
return
|
return
|
||||||
|
@ -101,7 +71,6 @@
|
||||||
|
|
||||||
// Get fields in new schema
|
// Get fields in new schema
|
||||||
let fields = Object.keys(schema || {})
|
let fields = Object.keys(schema || {})
|
||||||
const primaryDisplay = definition?.primaryDisplay
|
|
||||||
if (primaryDisplay) {
|
if (primaryDisplay) {
|
||||||
fields = [primaryDisplay, ...fields.filter(x => x !== primaryDisplay)]
|
fields = [primaryDisplay, ...fields.filter(x => x !== primaryDisplay)]
|
||||||
}
|
}
|
||||||
|
@ -123,147 +92,19 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const getIconForField = field => {
|
|
||||||
const type = field.schema.type
|
|
||||||
if (type === "options") {
|
|
||||||
return "ChevronDown"
|
|
||||||
} else if (type === "datetime") {
|
|
||||||
return "Date"
|
|
||||||
}
|
|
||||||
return "Text"
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectAll = () => {
|
|
||||||
const allSelected = selectedRowCount === rowCount
|
|
||||||
if (allSelected) {
|
|
||||||
$selectedRows = {}
|
|
||||||
} else {
|
|
||||||
selectedRows.update(state => {
|
|
||||||
$rows.forEach(row => {
|
|
||||||
state[row._id] = true
|
|
||||||
})
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateValue = async (rowId, field, value) => {
|
|
||||||
let row = $rows.find(x => x._id === rowId)
|
|
||||||
if (!row) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (row[field.name] === value) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
changeCache.update(state => {
|
|
||||||
state[rowId] = { [field.name]: value }
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
await API.saveRow({
|
|
||||||
...row,
|
|
||||||
...$changeCache[rowId],
|
|
||||||
})
|
|
||||||
await fetch.refresh()
|
|
||||||
changeCache.update(state => {
|
|
||||||
delete state[rowId]
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const addRow = async field => {
|
|
||||||
const res = await API.saveRow({ tableId: table.tableId })
|
|
||||||
$selectedCellId = `${res._id}-${field.name}`
|
|
||||||
newRows.update(state => [...state, res._id])
|
|
||||||
await fetch.refresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateSortedRows = (unsortedRows, newRows) => {
|
|
||||||
let foo = unsortedRows.rows
|
|
||||||
for (let i = 0; i < 0; i++) {
|
|
||||||
foo = foo.concat(foo.map(x => ({ ...x, _id: x._id + "x" })))
|
|
||||||
}
|
|
||||||
let sortedRows = foo.slice()
|
|
||||||
sortedRows.sort((a, b) => {
|
|
||||||
const aIndex = newRows.indexOf(a._id)
|
|
||||||
const bIndex = newRows.indexOf(b._id)
|
|
||||||
return aIndex < bIndex ? -1 : 1
|
|
||||||
})
|
|
||||||
$rows = sortedRows.map((x, idx) => ({ ...x, __idx: idx }))
|
|
||||||
}
|
|
||||||
|
|
||||||
// API for children to consume
|
|
||||||
const spreadsheetAPI = {
|
|
||||||
refreshData: () => fetch?.refresh(),
|
|
||||||
updateValue,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set context for children to consume
|
// Set context for children to consume
|
||||||
setContext("spreadsheet", {
|
setContext("spreadsheet", context)
|
||||||
...context,
|
|
||||||
reorder,
|
|
||||||
visibleRows,
|
|
||||||
visibleColumns,
|
|
||||||
spreadsheetAPI,
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="sheet" style="--cell-height:{cellHeight}px;" id="sheet-{rand}">
|
<div class="sheet" style="--cell-height:{cellHeight}px;" id="sheet-{rand}">
|
||||||
<SpreadsheetHeader />
|
<SheetHeader />
|
||||||
<SpreadsheetBody>
|
<SheetBody>
|
||||||
<div class="row">
|
<HeaderRow />
|
||||||
<!-- Field headers -->
|
|
||||||
<SpreadsheetCell header label on:click={selectAll} width="40" left="0">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={rowCount && selectedRowCount === rowCount}
|
|
||||||
/>
|
|
||||||
</SpreadsheetCell>
|
|
||||||
{#each $visibleColumns as column}
|
|
||||||
<SpreadsheetCell
|
|
||||||
header
|
|
||||||
sticky={column.idx === 0}
|
|
||||||
reorderSource={$reorder.columnIdx === column.idx}
|
|
||||||
reorderTarget={$reorder.swapColumnIdx === column.idx}
|
|
||||||
on:mousedown={column.idx === 0
|
|
||||||
? null
|
|
||||||
: e => reorder.actions.startReordering(column.idx, e)}
|
|
||||||
width={column.width}
|
|
||||||
left={column.left}
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
size="S"
|
|
||||||
name={getIconForField(column)}
|
|
||||||
color="var(--spectrum-global-color-gray-600)"
|
|
||||||
/>
|
|
||||||
<span>
|
|
||||||
{column.name}
|
|
||||||
</span>
|
|
||||||
</SpreadsheetCell>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- All real rows -->
|
|
||||||
{#each $visibleRows as row (row._id)}
|
{#each $visibleRows as row (row._id)}
|
||||||
<SpreadsheetRow {row} />
|
<SheetRow {row} />
|
||||||
{/each}
|
{/each}
|
||||||
|
<NewRow />
|
||||||
<!-- New row placeholder -->
|
</SheetBody>
|
||||||
<div class="row new" style="--top:{($rows.length + 1) * cellHeight}px;">
|
|
||||||
<SpreadsheetCell label on:click={addRow} width="40" left="0">
|
|
||||||
<Icon hoverable name="Add" size="S" />
|
|
||||||
</SpreadsheetCell>
|
|
||||||
{#each $visibleColumns as column}
|
|
||||||
<SpreadsheetCell
|
|
||||||
sticky={column.idx === 0}
|
|
||||||
reorderSource={$reorder.columnIdx === column.idx}
|
|
||||||
reorderTarget={$reorder.swapColumnIdx === column.idx}
|
|
||||||
on:click={() => addRow(column)}
|
|
||||||
width={column.width}
|
|
||||||
left={column.left}
|
|
||||||
/>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</SpreadsheetBody>
|
|
||||||
<ResizeOverlay />
|
<ResizeOverlay />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -289,22 +130,4 @@
|
||||||
.sheet :global(*) {
|
.sheet :global(*) {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.row {
|
|
||||||
display: flex;
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
width: inherit;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
.row.new {
|
|
||||||
position: absolute;
|
|
||||||
transform: translateY(var(--top));
|
|
||||||
}
|
|
||||||
.row :global(> :last-child) {
|
|
||||||
border-right-width: 1px;
|
|
||||||
}
|
|
||||||
input[type="checkbox"] {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { getContext, onMount } from "svelte"
|
import { getContext, onMount } from "svelte"
|
||||||
import { Utils } from "../../utils"
|
import { Utils } from "../../utils"
|
||||||
|
|
||||||
const { columns, selectedCellId, rand, cellHeight, rows, bounds, scroll } =
|
const { columns, selectedCellId, cellHeight, rows, bounds, scroll } =
|
||||||
getContext("spreadsheet")
|
getContext("spreadsheet")
|
||||||
|
|
||||||
const padding = 180
|
const padding = 180
|
||||||
|
@ -45,7 +45,6 @@
|
||||||
class="sheet-body"
|
class="sheet-body"
|
||||||
class:horizontally-scrolled={$scroll.left > 0}
|
class:horizontally-scrolled={$scroll.left > 0}
|
||||||
on:click|self={() => ($selectedCellId = null)}
|
on:click|self={() => ($selectedCellId = null)}
|
||||||
id={`sheet-${rand}-body`}
|
|
||||||
on:scroll={handleScroll}
|
on:scroll={handleScroll}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -2,15 +2,7 @@
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
import { ActionButton, Modal, ModalContent } from "@budibase/bbui"
|
import { ActionButton, Modal, ModalContent } from "@budibase/bbui"
|
||||||
|
|
||||||
const {
|
const { selectedRows, rows, selectedCellId } = getContext("spreadsheet")
|
||||||
selectedRows,
|
|
||||||
rows,
|
|
||||||
selectedCellId,
|
|
||||||
hoveredRowId,
|
|
||||||
tableId,
|
|
||||||
spreadsheetAPI,
|
|
||||||
API,
|
|
||||||
} = getContext("spreadsheet")
|
|
||||||
|
|
||||||
let modal
|
let modal
|
||||||
|
|
||||||
|
@ -28,15 +20,10 @@
|
||||||
|
|
||||||
// Deletion callback when confirmed
|
// Deletion callback when confirmed
|
||||||
const performDeletion = async () => {
|
const performDeletion = async () => {
|
||||||
await API.deleteRows({
|
await rows.actions.deleteRows(rowsToDelete)
|
||||||
tableId,
|
|
||||||
rows: rowsToDelete,
|
|
||||||
})
|
|
||||||
await spreadsheetAPI.refreshData()
|
|
||||||
|
|
||||||
// Refresh state
|
// Refresh state
|
||||||
$selectedCellId = null
|
$selectedCellId = null
|
||||||
$hoveredRowId = null
|
|
||||||
$selectedRows = {}
|
$selectedRows = {}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -14,14 +14,12 @@
|
||||||
selectedCellId,
|
selectedCellId,
|
||||||
reorder,
|
reorder,
|
||||||
selectedRows,
|
selectedRows,
|
||||||
changeCache,
|
rows,
|
||||||
spreadsheetAPI,
|
|
||||||
visibleColumns,
|
visibleColumns,
|
||||||
cellHeight,
|
cellHeight,
|
||||||
} = getContext("spreadsheet")
|
} = getContext("spreadsheet")
|
||||||
|
|
||||||
$: rowSelected = !!$selectedRows[row._id]
|
$: rowSelected = !!$selectedRows[row._id]
|
||||||
$: data = { ...row, ...$changeCache[row._id] }
|
|
||||||
|
|
||||||
const getCellForField = field => {
|
const getCellForField = field => {
|
||||||
const type = field.schema.type
|
const type = field.schema.type
|
||||||
|
@ -71,10 +69,10 @@
|
||||||
>
|
>
|
||||||
<svelte:component
|
<svelte:component
|
||||||
this={getCellForField(column)}
|
this={getCellForField(column)}
|
||||||
value={data[column.name]}
|
value={row[column.name]}
|
||||||
schema={column.schema}
|
schema={column.schema}
|
||||||
selected={$selectedCellId === cellIdx}
|
selected={$selectedCellId === cellIdx}
|
||||||
onChange={val => spreadsheetAPI.updateValue(row._id, column, val)}
|
onChange={val => rows.actions.updateRow(row._id, column, val)}
|
||||||
readonly={column.schema.autocolumn}
|
readonly={column.schema.autocolumn}
|
||||||
/>
|
/>
|
||||||
</SpreadsheetCell>
|
</SpreadsheetCell>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { get, writable } from "svelte/store"
|
import { get, writable } from "svelte/store"
|
||||||
|
|
||||||
export const createReorderStores = context => {
|
export const createReorderStores = context => {
|
||||||
const { columns, visibleColumns, rand, scroll, bounds } = context
|
const { columns, rand, scroll, bounds } = context
|
||||||
const reorderInitialState = {
|
const reorderInitialState = {
|
||||||
columnIdx: null,
|
columnIdx: null,
|
||||||
swapColumnIdx: null,
|
swapColumnIdx: null,
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
import { writable, derived, get } from "svelte/store"
|
||||||
|
import { buildLuceneQuery } from "../../../utils/lucene"
|
||||||
|
import { fetchData } from "../../../fetch/fetchData"
|
||||||
|
|
||||||
|
export const createRowsStore = context => {
|
||||||
|
const { tableId, filter, API } = context
|
||||||
|
const rows = writable([])
|
||||||
|
const schema = writable({})
|
||||||
|
const primaryDisplay = writable(null)
|
||||||
|
const query = derived(filter, $filter => buildLuceneQuery($filter))
|
||||||
|
const fetch = derived(tableId, $tableId => {
|
||||||
|
return fetchData({
|
||||||
|
API,
|
||||||
|
datasource: {
|
||||||
|
type: "table",
|
||||||
|
tableId: $tableId,
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
sortColumn: null,
|
||||||
|
sortOrder: null,
|
||||||
|
query: get(query),
|
||||||
|
limit: 100,
|
||||||
|
paginate: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Update fetch when query changes
|
||||||
|
query.subscribe($query => {
|
||||||
|
get(fetch).update({
|
||||||
|
query: $query,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Observe each data fetch and extract some data
|
||||||
|
fetch.subscribe($fetch => {
|
||||||
|
$fetch.subscribe($$fetch => {
|
||||||
|
console.log("new fetch")
|
||||||
|
rows.set($$fetch.rows.map((row, idx) => ({ ...row, __idx: idx })))
|
||||||
|
schema.set($$fetch.schema)
|
||||||
|
primaryDisplay.set($$fetch.definition?.primaryDisplay)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Adds a new empty row
|
||||||
|
const addRow = async () => {
|
||||||
|
let newRow = await API.saveRow({ tableId: get(tableId) })
|
||||||
|
newRow.__idx = get(rows).length
|
||||||
|
rows.update(state => {
|
||||||
|
state.push(newRow)
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
return newRow
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates a value of a row
|
||||||
|
const updateRow = async (rowId, column, value) => {
|
||||||
|
const $rows = get(rows)
|
||||||
|
const index = $rows.findIndex(x => x._id === rowId)
|
||||||
|
const row = $rows[index]
|
||||||
|
if (index === -1 || row?.[column.name] === value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Immediately update state so that the change is reflected
|
||||||
|
let newRow = { ...row, [column.name]: value }
|
||||||
|
rows.update(state => {
|
||||||
|
state[index] = { ...newRow }
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
|
||||||
|
// Save change
|
||||||
|
delete newRow.__idx
|
||||||
|
await API.saveRow(newRow)
|
||||||
|
|
||||||
|
// Fetch row from the server again
|
||||||
|
newRow = await API.fetchRow({
|
||||||
|
tableId: get(tableId),
|
||||||
|
rowId: row._id,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Update state again with this row
|
||||||
|
newRow = { ...newRow, __idx: row.__idx }
|
||||||
|
rows.update(state => {
|
||||||
|
state[index] = newRow
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
|
||||||
|
return newRow
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletes an array of rows
|
||||||
|
const deleteRows = async rowsToDelete => {
|
||||||
|
const deletedIds = rowsToDelete.map(row => row._id)
|
||||||
|
|
||||||
|
// Actually delete rows
|
||||||
|
rowsToDelete.forEach(row => {
|
||||||
|
delete row.__idx
|
||||||
|
})
|
||||||
|
await API.deleteRows({
|
||||||
|
tableId: get(tableId),
|
||||||
|
rows: rowsToDelete,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Update state
|
||||||
|
rows.update(state => {
|
||||||
|
return state
|
||||||
|
.filter(row => !deletedIds.includes(row._id))
|
||||||
|
.map((row, idx) => ({ ...row, __idx: idx }))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
rows: {
|
||||||
|
...rows,
|
||||||
|
actions: {
|
||||||
|
addRow,
|
||||||
|
updateRow,
|
||||||
|
deleteRows,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
schema,
|
||||||
|
primaryDisplay,
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
import { writable, derived } from "svelte/store"
|
import { writable, derived } from "svelte/store"
|
||||||
import { Utils } from "../../../utils"
|
|
||||||
|
|
||||||
export const createViewportStores = context => {
|
export const createViewportStores = context => {
|
||||||
const { cellHeight, columns, rows, scroll, bounds } = context
|
const { cellHeight, columns, rows, scroll, bounds } = context
|
||||||
|
|
Loading…
Reference in New Issue