@svgrid/grid 3.0.3 → 3.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/dist/GridMenus.svelte +44 -2
- package/dist/SvChartMenu.svelte +69 -0
- package/dist/SvChartMenu.svelte.d.ts +11 -0
- package/dist/SvChartPanes.svelte +113 -0
- package/dist/SvChartPanes.svelte.d.ts +20 -0
- package/dist/SvGrid.controller.svelte.d.ts +122 -41
- package/dist/SvGrid.controller.svelte.js +846 -207
- package/dist/SvGrid.css +178 -2
- package/dist/SvGrid.svelte +717 -720
- package/dist/SvGrid.types.d.ts +566 -12
- package/dist/SvGridCellEditor.svelte +17 -0
- package/dist/SvGridChart.svelte +2257 -329
- package/dist/SvGridChart.svelte.d.ts +6 -106
- package/dist/SvGridChart.types.d.ts +338 -0
- package/dist/SvGridChart.types.js +1 -0
- package/dist/SvGridChartBuilder.svelte +323 -0
- package/dist/SvGridChartBuilder.svelte.d.ts +34 -0
- package/dist/SvGridChartPanel.svelte +221 -275
- package/dist/SvGridChartPickers.svelte +417 -0
- package/dist/SvGridChartPickers.svelte.d.ts +70 -0
- package/dist/SvGridChartView.svelte +13 -14
- package/dist/SvModal.svelte +7 -1
- package/dist/SvModal.svelte.d.ts +5 -0
- package/dist/ai.d.ts +40 -8
- package/dist/ai.js +135 -24
- package/dist/aria.d.ts +11 -0
- package/dist/build-api.js +119 -28
- package/dist/cdn/GridMenus-CID62rlI.js +636 -0
- package/dist/cdn/GridMenus-DLL-qZeu.js +635 -0
- package/dist/cdn/SvChartMenu-Bl6PBbkT.js +58 -0
- package/dist/cdn/SvChartMenu-FBSMINA6.js +59 -0
- package/dist/cdn/{SvDateRangeInput-DMLKmGEc.js → SvDateRangeInput-BeU_TkbQ.js} +15 -14
- package/dist/cdn/{SvDateRangeInput-CaOuMs8O.js → SvDateRangeInput-yX8vzleW.js} +38 -37
- package/dist/cdn/{SvDateTimePicker-sonaH0oh.js → SvDateTimePicker-DQwt4UAs.js} +139 -180
- package/dist/cdn/SvDateTimePicker-vNU6bZ-q.js +775 -0
- package/dist/cdn/{SvGridCellEditor-CjEJMJKc.js → SvGridCellEditor-B1p-vCK5.js} +188 -178
- package/dist/cdn/{SvGridCellEditor-BWnTi2N7.js → SvGridCellEditor-D_0q4xAu.js} +98 -88
- package/dist/cdn/SvGridChart-C3EWAZaM.js +3574 -0
- package/dist/cdn/SvGridChart-DzLkSwCH.js +3572 -0
- package/dist/cdn/SvGridChartBuilder-BE2T1ykB.js +783 -0
- package/dist/cdn/SvGridChartBuilder-CfII62sZ.js +784 -0
- package/dist/cdn/SvGridChartPanel-CCX5_Wgd.js +675 -0
- package/dist/cdn/SvGridChartPanel-xf4sWVTo.js +699 -0
- package/dist/cdn/SvGridChartView-CfuXmY5I.js +48 -0
- package/dist/cdn/SvGridChartView-DYwabQWj.js +47 -0
- package/dist/cdn/SvMenuList-CLN8OuIK.js +452 -0
- package/dist/cdn/SvMenuList-DkGhNKjf.js +451 -0
- package/dist/cdn/SvModal-BAE-pjZX.js +396 -0
- package/dist/cdn/SvModal-CIZWCcad.js +397 -0
- package/dist/cdn/chart-Dz7SqMXH.js +4341 -0
- package/dist/cdn/chart-export-BXqueeWJ.js +135 -0
- package/dist/cdn/chart-export-pdf-DONFUnNY.js +110 -0
- package/dist/cdn/chart-panel-messages-CUbf2R4i.js +1052 -0
- package/dist/cdn/chart-panel-messages-CmNrMdsr.js +1053 -0
- package/dist/cdn/chart-summary-BJW_tg_X.js +138 -0
- package/dist/cdn/chart-trend-CaN9mDEV.js +50 -0
- package/dist/cdn/chart-validate-HcOVFAfJ.js +188 -0
- package/dist/cdn/{column-resize-DsfNXMom.js → column-resize-DpmOLfRp.js} +3 -3
- package/dist/cdn/{date-format-BnnHlqGw.js → date-format-CtquV-p3.js} +583 -603
- package/dist/cdn/{date-format-BNii4zeD.js → date-format-D6KFzU_W.js} +347 -367
- package/dist/cdn/dismissable-DAHetSNk.js +44 -0
- package/dist/cdn/editor-contract-LXgQJAgd.js +22 -0
- package/dist/cdn/focus-trap-BBOQYBma.js +65 -0
- package/dist/cdn/{row-resize-BRcimkUT.js → row-resize-niQCp040.js} +44 -36
- package/dist/cdn/server-block-cache-CGoWz-87.js +237 -0
- package/dist/cdn/{src-D6XvA1Ij.js → src-Bklofsad.js} +10615 -10155
- package/dist/cdn/{src-Bugf5XlI.js → src-jcFMkBnN.js} +7111 -6651
- package/dist/cdn/svgrid.js +27 -15
- package/dist/cdn/svgrid.svelte-external.js +27 -15
- package/dist/cdn/validate-C7Rn_Bns.js +76 -0
- package/dist/chart-axes.d.ts +53 -0
- package/dist/chart-axes.js +351 -0
- package/dist/chart-cartesian.d.ts +88 -0
- package/dist/chart-cartesian.js +1862 -0
- package/dist/chart-decimate.d.ts +51 -0
- package/dist/chart-decimate.js +199 -0
- package/dist/chart-export-pdf.d.ts +47 -0
- package/dist/chart-export-pdf.js +187 -0
- package/dist/chart-export.d.ts +2 -1
- package/dist/chart-export.js +18 -3
- package/dist/chart-financial.d.ts +91 -0
- package/dist/chart-financial.js +175 -0
- package/dist/chart-flow.d.ts +10 -0
- package/dist/chart-flow.js +298 -0
- package/dist/chart-format.d.ts +18 -0
- package/dist/chart-format.js +65 -0
- package/dist/chart-grid.d.ts +8 -0
- package/dist/chart-grid.js +190 -0
- package/dist/chart-hierarchy.d.ts +17 -0
- package/dist/chart-hierarchy.js +146 -0
- package/dist/chart-indicators.d.ts +115 -0
- package/dist/chart-indicators.js +389 -0
- package/dist/chart-messages.d.ts +95 -0
- package/dist/chart-messages.js +92 -0
- package/dist/chart-motion.d.ts +16 -0
- package/dist/chart-motion.js +141 -0
- package/dist/chart-panel-messages.d.ts +265 -0
- package/dist/chart-panel-messages.js +285 -0
- package/dist/chart-pivot.d.ts +87 -0
- package/dist/chart-pivot.js +156 -0
- package/dist/chart-polar.d.ts +25 -0
- package/dist/chart-polar.js +700 -0
- package/dist/chart-samples.d.ts +16 -0
- package/dist/chart-samples.js +153 -0
- package/dist/chart-scale.d.ts +113 -0
- package/dist/chart-scale.js +405 -0
- package/dist/chart-stats.d.ts +111 -0
- package/dist/chart-stats.js +419 -0
- package/dist/chart-stream.d.ts +45 -0
- package/dist/chart-stream.js +91 -0
- package/dist/chart-summary.d.ts +27 -0
- package/dist/chart-summary.js +205 -0
- package/dist/chart-sync.svelte.d.ts +32 -0
- package/dist/chart-sync.svelte.js +23 -0
- package/dist/chart-table.d.ts +35 -0
- package/dist/chart-table.js +165 -0
- package/dist/chart-trend.d.ts +19 -0
- package/dist/chart-trend.js +61 -0
- package/dist/chart-types.d.ts +1456 -0
- package/dist/chart-types.js +6 -0
- package/dist/chart-validate.d.ts +43 -0
- package/dist/chart-validate.js +272 -0
- package/dist/chart-zoom.d.ts +40 -0
- package/dist/chart-zoom.js +145 -0
- package/dist/chart.d.ts +186 -865
- package/dist/chart.js +460 -2204
- package/dist/clipboard.d.ts +1 -0
- package/dist/clipboard.js +137 -18
- package/dist/column-resize.d.ts +3 -0
- package/dist/column-resize.js +4 -1
- package/dist/columns.js +3 -0
- package/dist/command-context.d.ts +19 -0
- package/dist/command-context.js +116 -0
- package/dist/core.d.ts +7 -0
- package/dist/core.js +36 -13
- package/dist/createPopoverSelect.svelte.d.ts +2 -2
- package/dist/editing.d.ts +2 -8
- package/dist/editing.js +272 -33
- package/dist/fill-patterns.d.ts +0 -5
- package/dist/fill-patterns.js +56 -2
- package/dist/gantt-view.svelte.d.ts +24 -0
- package/dist/gantt-view.svelte.js +13 -0
- package/dist/grid-icons.d.ts +2 -2
- package/dist/grid-icons.js +2 -2
- package/dist/grid-messages.d.ts +16 -3
- package/dist/grid-messages.js +10 -0
- package/dist/history.d.ts +83 -0
- package/dist/history.js +133 -0
- package/dist/index.d.ts +29 -10
- package/dist/index.js +23 -5
- package/dist/keyboard-handlers.js +88 -31
- package/dist/keyboard.d.ts +55 -0
- package/dist/keyboard.js +132 -0
- package/dist/menus.d.ts +3 -1
- package/dist/menus.js +7 -2
- package/dist/merges.d.ts +97 -0
- package/dist/merges.js +147 -0
- package/dist/row-model.d.ts +133 -0
- package/dist/row-model.js +16 -0
- package/dist/row-resize.d.ts +3 -0
- package/dist/row-resize.js +14 -0
- package/dist/scroll-sync.d.ts +1 -0
- package/dist/scroll-sync.js +24 -0
- package/dist/selection.d.ts +18 -1
- package/dist/selection.js +138 -18
- package/dist/server-block-cache.d.ts +214 -0
- package/dist/server-block-cache.js +531 -0
- package/dist/server-data-source.d.ts +240 -6
- package/dist/server-data-source.js +220 -20
- package/dist/server.d.ts +13 -0
- package/dist/server.js +13 -0
- package/dist/shortcut-registry.d.ts +145 -0
- package/dist/shortcut-registry.js +44 -0
- package/dist/svgrid-wrapper.types.d.ts +213 -22
- package/dist/validate.d.ts +4 -0
- package/dist/validate.js +21 -3
- package/dist/virtualization/virtualizer.js +38 -17
- package/package.json +11 -1
- package/src/GridMenus.svelte +44 -2
- package/src/SvChartMenu.svelte +69 -0
- package/src/SvChartPanes.svelte +113 -0
- package/src/SvChartPanes.test.ts +66 -0
- package/src/SvGrid.controller.svelte.ts +819 -179
- package/src/SvGrid.css +178 -2
- package/src/SvGrid.svelte +717 -720
- package/src/SvGrid.types.ts +564 -11
- package/src/SvGridCellEditor.svelte +17 -0
- package/src/SvGridChart.svelte +2257 -329
- package/src/SvGridChart.test.ts +1419 -1
- package/src/SvGridChart.types.ts +336 -0
- package/src/SvGridChartBuilder.svelte +323 -0
- package/src/SvGridChartPanel.svelte +221 -275
- package/src/SvGridChartPickers.svelte +417 -0
- package/src/SvGridChartView.svelte +13 -14
- package/src/SvModal.svelte +7 -1
- package/src/SvModal.test.ts +9 -0
- package/src/ai.test.ts +57 -2
- package/src/ai.ts +166 -22
- package/src/aria.d.ts +11 -0
- package/src/build-api.coverage.test.ts +184 -0
- package/src/build-api.ts +118 -22
- package/src/chart-axes.test.ts +573 -0
- package/src/chart-axes.ts +342 -0
- package/src/chart-cartesian.ts +1863 -0
- package/src/chart-decimate.test.ts +249 -0
- package/src/chart-decimate.ts +186 -0
- package/src/chart-export-pdf.test.ts +91 -0
- package/src/chart-export-pdf.ts +207 -0
- package/src/chart-export.test.ts +14 -0
- package/src/chart-export.ts +13 -3
- package/src/chart-financial.ts +208 -0
- package/src/chart-flow.ts +286 -0
- package/src/chart-format.ts +67 -0
- package/src/chart-grid.ts +179 -0
- package/src/chart-hierarchy.ts +135 -0
- package/src/chart-indicators.test.ts +443 -0
- package/src/chart-indicators.ts +384 -0
- package/src/chart-messages.test.ts +21 -0
- package/src/chart-messages.ts +184 -0
- package/src/chart-motion.test.ts +71 -0
- package/src/chart-motion.ts +148 -0
- package/src/chart-panel-messages.test.ts +29 -0
- package/src/chart-panel-messages.ts +550 -0
- package/src/chart-pivot.test.ts +54 -0
- package/src/chart-pivot.ts +225 -0
- package/src/chart-polar.ts +674 -0
- package/src/chart-samples.ts +106 -0
- package/src/chart-scale.ts +394 -0
- package/src/chart-series-types.test.ts +714 -0
- package/src/chart-stats.ts +409 -0
- package/src/chart-stream.test.ts +75 -0
- package/src/chart-stream.ts +114 -0
- package/src/chart-summary.test.ts +90 -0
- package/src/chart-summary.ts +197 -0
- package/src/chart-sync.svelte.ts +41 -0
- package/src/chart-table.test.ts +76 -0
- package/src/chart-table.ts +178 -0
- package/src/chart-trend.ts +47 -0
- package/src/chart-types.ts +1309 -0
- package/src/chart-validate.test.ts +100 -0
- package/src/chart-validate.ts +247 -0
- package/src/chart-zoom.test.ts +137 -0
- package/src/chart-zoom.ts +124 -0
- package/src/chart.coverage.test.ts +81 -0
- package/src/chart.test.ts +56 -3
- package/src/chart.ts +557 -2784
- package/src/clipboard.test.ts +151 -0
- package/src/clipboard.ts +145 -16
- package/src/column-resize.ts +7 -1
- package/src/columns.ts +2 -0
- package/src/command-context.test.ts +200 -0
- package/src/command-context.ts +137 -0
- package/src/core.rowmodel-cache.test.ts +51 -0
- package/src/core.ts +40 -12
- package/src/editing.test.ts +281 -3
- package/src/editing.ts +264 -38
- package/src/fill-patterns.test.ts +35 -0
- package/src/fill-patterns.ts +56 -2
- package/src/gantt-stub.test.svelte +38 -0
- package/src/gantt-view.svelte.ts +35 -0
- package/src/grid-icons.ts +2 -2
- package/src/grid-messages.ts +28 -3
- package/src/history.test.ts +196 -0
- package/src/history.ts +162 -0
- package/src/icon-seam.test.ts +5 -6
- package/src/index.ts +186 -12
- package/src/keyboard-handlers.coverage.test.ts +126 -6
- package/src/keyboard-handlers.ts +91 -30
- package/src/keyboard-shortcuts.seam.test.ts +200 -0
- package/src/keyboard.test.ts +124 -1
- package/src/keyboard.ts +142 -0
- package/src/menus.test.ts +26 -0
- package/src/menus.ts +10 -3
- package/src/merges.test.ts +112 -0
- package/src/merges.ts +168 -0
- package/src/pivot.grid.test.ts +40 -5
- package/src/row-model.ts +146 -0
- package/src/row-resize.test.ts +44 -0
- package/src/row-resize.ts +17 -0
- package/src/scroll-sync.test.ts +42 -1
- package/src/scroll-sync.ts +25 -0
- package/src/selection.multi-range.test.ts +34 -0
- package/src/selection.test.ts +33 -2
- package/src/selection.ts +143 -21
- package/src/server-block-cache.test.ts +645 -0
- package/src/server-block-cache.ts +677 -0
- package/src/server-data-source.infinite.test.ts +343 -0
- package/src/server-data-source.ts +450 -27
- package/src/server.ts +47 -0
- package/src/shortcut-registry.test.ts +97 -0
- package/src/shortcut-registry.ts +181 -0
- package/src/svgrid-wrapper.types.ts +184 -13
- package/src/svgrid.behavior.test.ts +135 -0
- package/src/svgrid.charting.test.ts +513 -3
- package/src/svgrid.context-menu.test.ts +31 -0
- package/src/svgrid.gantt-seam.test.ts +199 -0
- package/src/svgrid.new-features.wrapper.test.ts +10 -3
- package/src/svgrid.row-model-prop.svelte.test.ts +352 -0
- package/src/svgrid.row-model-seam.svelte.test.ts +289 -0
- package/src/svgrid.upsell-license.test.ts +7 -4
- package/src/validate.test.ts +29 -0
- package/src/validate.ts +28 -3
- package/src/virtualization/virtualizer.ts +39 -17
- package/dist/SvGroupCell.svelte +0 -141
- package/dist/SvGroupCell.svelte.d.ts +0 -49
- package/dist/SvRowGroupPanel.svelte +0 -186
- package/dist/SvRowGroupPanel.svelte.d.ts +0 -25
- package/dist/cdn/GridMenus-CHOMnW-c.js +0 -602
- package/dist/cdn/GridMenus-DhdPF700.js +0 -603
- package/dist/cdn/SvDateTimePicker-CCbDZNZB.js +0 -816
- package/dist/cdn/SvGridChart-1PMSp2LZ.js +0 -1481
- package/dist/cdn/SvGridChart-D02avhyr.js +0 -1480
- package/dist/cdn/SvGridChartPanel-DJnViOv4.js +0 -834
- package/dist/cdn/SvGridChartPanel-vPTNerFZ.js +0 -810
- package/dist/cdn/SvGridChartView-C--HhdUo.js +0 -56
- package/dist/cdn/SvGridChartView-KyyFG-wY.js +0 -55
- package/dist/cdn/chart-DLg3_zTQ.js +0 -1652
- package/dist/cdn/validate-_CDJzgIo.js +0 -75
- package/dist/server-group-model.d.ts +0 -98
- package/dist/server-group-model.js +0 -263
- package/src/SvGroupCell.svelte +0 -141
- package/src/SvRowGroupPanel.svelte +0 -186
- package/src/server-group-model.test.ts +0 -294
- package/src/server-group-model.ts +0 -370
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `createServerDataSource({ mode: 'infinite' })` - the free infinite row model.
|
|
3
|
+
*
|
|
4
|
+
* Page mode hands the grid one page and a pager. Infinite mode hands it the
|
|
5
|
+
* whole result as one scrollable list, with placeholders where the data has
|
|
6
|
+
* not arrived. These tests are about that difference: what `state.rows` holds,
|
|
7
|
+
* when requests happen, and what the same controller methods mean once there
|
|
8
|
+
* are no pages to move between.
|
|
9
|
+
*
|
|
10
|
+
* The block mechanics themselves (eviction, concurrency, unknown counts) are
|
|
11
|
+
* covered in `server-block-cache.test.ts`; this file checks the wiring.
|
|
12
|
+
*/
|
|
13
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
14
|
+
import { createServerDataSource, type ServerDataSource, type ServerState } from './server-data-source'
|
|
15
|
+
import { rowPlaceholderState } from './server-block-cache'
|
|
16
|
+
|
|
17
|
+
type Row = { id: number; name: string }
|
|
18
|
+
|
|
19
|
+
/** A backend of `total` rows that honours startRow/endRow, sort and filter. */
|
|
20
|
+
function tableOf(total = 1000) {
|
|
21
|
+
const requests: Array<{ startRow: number; endRow: number; sort: string; global: string }> = []
|
|
22
|
+
const source: ServerDataSource<Row> = {
|
|
23
|
+
async getRows(req) {
|
|
24
|
+
requests.push({
|
|
25
|
+
startRow: req.startRow,
|
|
26
|
+
endRow: req.endRow,
|
|
27
|
+
sort: req.sortModel.map((s) => `${s.id}:${s.desc ? 'desc' : 'asc'}`).join(','),
|
|
28
|
+
global: req.filterModel.global ?? '',
|
|
29
|
+
})
|
|
30
|
+
const all: Row[] = []
|
|
31
|
+
for (let i = 0; i < total; i += 1) all.push({ id: i, name: `Row ${i}` })
|
|
32
|
+
const filtered = req.filterModel.global
|
|
33
|
+
? all.filter((r) => r.name.includes(req.filterModel.global!))
|
|
34
|
+
: all
|
|
35
|
+
const sorted = req.sortModel[0]?.desc ? [...filtered].reverse() : filtered
|
|
36
|
+
return { rows: sorted.slice(req.startRow, req.endRow), rowCount: sorted.length }
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
return { source, requests, starts: () => requests.map((r) => r.startRow) }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const settle = async () => {
|
|
43
|
+
for (let i = 0; i < 20; i += 1) await Promise.resolve()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
describe('createServerDataSource in infinite mode', () => {
|
|
47
|
+
it('spans the whole result, with placeholders where nothing is loaded', async () => {
|
|
48
|
+
const { source } = tableOf(1000)
|
|
49
|
+
let view!: ServerState<Row>
|
|
50
|
+
const ctl = createServerDataSource<Row>(source, {
|
|
51
|
+
mode: 'infinite',
|
|
52
|
+
blockSize: 100,
|
|
53
|
+
onChange: (s) => (view = s),
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
ctl.setViewport(0, 20)
|
|
57
|
+
await settle()
|
|
58
|
+
|
|
59
|
+
expect(view.rows).toHaveLength(1000)
|
|
60
|
+
expect(view.rows[0]).toEqual({ id: 0, name: 'Row 0' })
|
|
61
|
+
expect(rowPlaceholderState(view.rows[900])).toBe('loading')
|
|
62
|
+
expect(view.rowCount).toBe(1000)
|
|
63
|
+
expect(view.lastRowKnown).toBe(true)
|
|
64
|
+
ctl.dispose()
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('fetches a block only when the viewport reaches it', async () => {
|
|
68
|
+
const { source, starts } = tableOf(1000)
|
|
69
|
+
const ctl = createServerDataSource<Row>(source, {
|
|
70
|
+
mode: 'infinite',
|
|
71
|
+
blockSize: 100,
|
|
72
|
+
onChange: () => {},
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
ctl.setViewport(0, 20)
|
|
76
|
+
await settle()
|
|
77
|
+
expect(starts()).toEqual([0])
|
|
78
|
+
|
|
79
|
+
ctl.setViewport(640, 660)
|
|
80
|
+
await settle()
|
|
81
|
+
expect(starts()).toEqual([0, 600])
|
|
82
|
+
|
|
83
|
+
// Scrolling back to a block it still holds asks for nothing.
|
|
84
|
+
ctl.setViewport(0, 20)
|
|
85
|
+
await settle()
|
|
86
|
+
expect(starts()).toEqual([0, 600])
|
|
87
|
+
ctl.dispose()
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('reloads from the top when the sort or the filter changes', async () => {
|
|
91
|
+
const { source, requests, starts } = tableOf(1000)
|
|
92
|
+
let view!: ServerState<Row>
|
|
93
|
+
const ctl = createServerDataSource<Row>(source, {
|
|
94
|
+
mode: 'infinite',
|
|
95
|
+
blockSize: 100,
|
|
96
|
+
onChange: (s) => (view = s),
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
ctl.setViewport(0, 20)
|
|
100
|
+
await settle()
|
|
101
|
+
ctl.setViewport(300, 320)
|
|
102
|
+
await settle()
|
|
103
|
+
expect(starts()).toEqual([0, 300])
|
|
104
|
+
|
|
105
|
+
ctl.setSort([{ id: 'name', desc: true }])
|
|
106
|
+
await settle()
|
|
107
|
+
// The user is still looking at row 300, so that is what is re-requested -
|
|
108
|
+
// not row 0, which would be a wasted round trip nobody can see.
|
|
109
|
+
expect(starts()).toEqual([0, 300, 300])
|
|
110
|
+
expect(requests.at(-1)!.sort).toBe('name:desc')
|
|
111
|
+
expect(view.rows[300]).toEqual({ id: 699, name: 'Row 699' })
|
|
112
|
+
|
|
113
|
+
ctl.setFilter({ global: 'Row 1' })
|
|
114
|
+
await settle()
|
|
115
|
+
expect(requests.at(-1)!.global).toBe('Row 1')
|
|
116
|
+
ctl.dispose()
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
it('has no pages to move between', async () => {
|
|
120
|
+
const { source, starts } = tableOf(1000)
|
|
121
|
+
const ctl = createServerDataSource<Row>(source, {
|
|
122
|
+
mode: 'infinite',
|
|
123
|
+
blockSize: 100,
|
|
124
|
+
onChange: () => {},
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
ctl.setViewport(0, 20)
|
|
128
|
+
await settle()
|
|
129
|
+
const before = starts().length
|
|
130
|
+
|
|
131
|
+
ctl.setPage(4)
|
|
132
|
+
ctl.setPageSize(25)
|
|
133
|
+
await settle()
|
|
134
|
+
expect(starts()).toHaveLength(before)
|
|
135
|
+
ctl.dispose()
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
it('surfaces a failed block and recovers on retryLoads', async () => {
|
|
139
|
+
let failing = true
|
|
140
|
+
const source: ServerDataSource<Row> = {
|
|
141
|
+
async getRows(req) {
|
|
142
|
+
if (failing && req.startRow >= 100) throw new Error('backend down')
|
|
143
|
+
const rows: Row[] = []
|
|
144
|
+
for (let i = req.startRow; i < Math.min(req.endRow, 1000); i += 1) {
|
|
145
|
+
rows.push({ id: i, name: `Row ${i}` })
|
|
146
|
+
}
|
|
147
|
+
return { rows, rowCount: 1000 }
|
|
148
|
+
},
|
|
149
|
+
}
|
|
150
|
+
let view!: ServerState<Row>
|
|
151
|
+
const ctl = createServerDataSource<Row>(source, {
|
|
152
|
+
mode: 'infinite',
|
|
153
|
+
blockSize: 100,
|
|
154
|
+
onChange: (s) => (view = s),
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
ctl.setViewport(100, 150)
|
|
158
|
+
await settle()
|
|
159
|
+
expect(view.failedBlocks).toEqual([1])
|
|
160
|
+
expect(rowPlaceholderState(view.rows[120])).toBe('failed')
|
|
161
|
+
|
|
162
|
+
failing = false
|
|
163
|
+
ctl.retryLoads()
|
|
164
|
+
await settle()
|
|
165
|
+
expect(view.failedBlocks).toEqual([])
|
|
166
|
+
expect(view.rows[120]).toEqual({ id: 120, name: 'Row 120' })
|
|
167
|
+
ctl.dispose()
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
it('refresh keeps the count and the scroll position, purge does not', async () => {
|
|
171
|
+
const { source, starts } = tableOf(1000)
|
|
172
|
+
let view!: ServerState<Row>
|
|
173
|
+
const ctl = createServerDataSource<Row>(source, {
|
|
174
|
+
mode: 'infinite',
|
|
175
|
+
blockSize: 100,
|
|
176
|
+
onChange: (s) => (view = s),
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
ctl.setViewport(500, 520)
|
|
180
|
+
await settle()
|
|
181
|
+
expect(starts()).toEqual([500])
|
|
182
|
+
expect(view.rowCount).toBe(1000)
|
|
183
|
+
|
|
184
|
+
ctl.refresh()
|
|
185
|
+
await settle()
|
|
186
|
+
expect(starts()).toEqual([500, 500])
|
|
187
|
+
expect(view.rowCount).toBe(1000)
|
|
188
|
+
|
|
189
|
+
ctl.purge()
|
|
190
|
+
await settle()
|
|
191
|
+
expect(starts()).toEqual([500, 500, 500])
|
|
192
|
+
ctl.dispose()
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
it('keeps the whole list after a write, re-reading the held blocks in place', async () => {
|
|
196
|
+
const { source, starts } = tableOf(1000)
|
|
197
|
+
const writable: ServerDataSource<Row> = {
|
|
198
|
+
...source,
|
|
199
|
+
async updateRow(id, patch) {
|
|
200
|
+
return { id: Number(id), name: `Row ${id}`, ...patch }
|
|
201
|
+
},
|
|
202
|
+
}
|
|
203
|
+
let view!: ServerState<Row>
|
|
204
|
+
const ctl = createServerDataSource<Row>(writable, { mode: 'infinite', blockSize: 100, onChange: (s) => (view = s) })
|
|
205
|
+
ctl.setViewport(500, 520)
|
|
206
|
+
await settle()
|
|
207
|
+
expect(view.rows).toHaveLength(1000)
|
|
208
|
+
|
|
209
|
+
await ctl.updateRow('510', { name: 'Edited' })
|
|
210
|
+
await settle()
|
|
211
|
+
// Not one page of a hundred: the list is still the whole result, and the
|
|
212
|
+
// block the row sits in was asked for again rather than page 0.
|
|
213
|
+
expect(view.rows).toHaveLength(1000)
|
|
214
|
+
expect(starts()).toEqual([500, 500])
|
|
215
|
+
expect(view.rowCount).toBe(1000)
|
|
216
|
+
ctl.dispose()
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
it('patches the cached row on an optimistic update and removes it on delete', async () => {
|
|
220
|
+
const { source } = tableOf(1000)
|
|
221
|
+
let fail = false
|
|
222
|
+
const writable: ServerDataSource<Row> = {
|
|
223
|
+
...source,
|
|
224
|
+
async updateRow(id, patch) {
|
|
225
|
+
if (fail) throw new Error('nope')
|
|
226
|
+
return { id: Number(id), name: `Row ${id}`, ...patch }
|
|
227
|
+
},
|
|
228
|
+
async deleteRow() {
|
|
229
|
+
if (fail) throw new Error('nope')
|
|
230
|
+
},
|
|
231
|
+
}
|
|
232
|
+
let view!: ServerState<Row>
|
|
233
|
+
const ctl = createServerDataSource<Row>(writable, {
|
|
234
|
+
mode: 'infinite',
|
|
235
|
+
blockSize: 100,
|
|
236
|
+
optimistic: true,
|
|
237
|
+
getRowId: (r) => String(r.id),
|
|
238
|
+
onChange: (s) => (view = s),
|
|
239
|
+
})
|
|
240
|
+
ctl.setViewport(0, 20)
|
|
241
|
+
await settle()
|
|
242
|
+
const at = (i: number) => view.rows[i] as Row
|
|
243
|
+
|
|
244
|
+
await ctl.updateRow('5', { name: 'Edited' })
|
|
245
|
+
expect(at(5).name).toBe('Edited')
|
|
246
|
+
// A later block landing does not undo it: the cache itself was patched.
|
|
247
|
+
ctl.setViewport(200, 220)
|
|
248
|
+
await settle()
|
|
249
|
+
expect(at(5).name).toBe('Edited')
|
|
250
|
+
|
|
251
|
+
fail = true
|
|
252
|
+
await expect(ctl.updateRow('6', { name: 'Nope' })).rejects.toThrow('nope')
|
|
253
|
+
expect(at(6).name).toBe('Row 6')
|
|
254
|
+
|
|
255
|
+
fail = false
|
|
256
|
+
await ctl.deleteRow('7')
|
|
257
|
+
expect(at(7).id).toBe(8)
|
|
258
|
+
expect(view.rowCount).toBe(999)
|
|
259
|
+
|
|
260
|
+
fail = true
|
|
261
|
+
await expect(ctl.deleteRow('8')).rejects.toThrow('nope')
|
|
262
|
+
expect(at(7).id).toBe(8)
|
|
263
|
+
expect(view.rowCount).toBe(999)
|
|
264
|
+
ctl.dispose()
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
it('reports block state for debugging', async () => {
|
|
268
|
+
const { source } = tableOf(1000)
|
|
269
|
+
const ctl = createServerDataSource<Row>(source, {
|
|
270
|
+
mode: 'infinite',
|
|
271
|
+
blockSize: 100,
|
|
272
|
+
onChange: () => {},
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
ctl.setViewport(0, 120)
|
|
276
|
+
await settle()
|
|
277
|
+
expect(ctl.getCacheState()).toEqual([
|
|
278
|
+
{ blockIndex: 0, startRow: 0, endRow: 100, status: 'loaded', lastTouched: expect.any(Number) },
|
|
279
|
+
{ blockIndex: 1, startRow: 100, endRow: 200, status: 'loaded', lastTouched: expect.any(Number) },
|
|
280
|
+
])
|
|
281
|
+
ctl.dispose()
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
it('leaves page mode exactly as it was', async () => {
|
|
285
|
+
const { source, starts } = tableOf(1000)
|
|
286
|
+
let view!: ServerState<Row>
|
|
287
|
+
const ctl = createServerDataSource<Row>(source, {
|
|
288
|
+
pageSize: 25,
|
|
289
|
+
onChange: (s) => (view = s),
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
ctl.refresh()
|
|
293
|
+
await settle()
|
|
294
|
+
expect(view.rows).toHaveLength(25)
|
|
295
|
+
expect(view.total).toBe(1000)
|
|
296
|
+
expect(view.pageCount).toBe(40)
|
|
297
|
+
|
|
298
|
+
ctl.setPage(2)
|
|
299
|
+
await settle()
|
|
300
|
+
expect(starts()).toEqual([0, 50])
|
|
301
|
+
expect(view.rows[0]).toEqual({ id: 50, name: 'Row 50' })
|
|
302
|
+
|
|
303
|
+
// The infinite-only methods are inert rather than throwing, so one piece of
|
|
304
|
+
// calling code can drive either mode.
|
|
305
|
+
ctl.setViewport(0, 10)
|
|
306
|
+
ctl.retryLoads()
|
|
307
|
+
ctl.purge()
|
|
308
|
+
expect(ctl.getCacheState()).toEqual([])
|
|
309
|
+
await settle()
|
|
310
|
+
expect(starts()).toEqual([0, 50])
|
|
311
|
+
ctl.dispose()
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
it('warns once when an advanced filter is sent but not acknowledged', async () => {
|
|
315
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
316
|
+
const source: ServerDataSource<Row> = {
|
|
317
|
+
async getRows(req) {
|
|
318
|
+
const rows: Row[] = []
|
|
319
|
+
for (let i = req.startRow; i < Math.min(req.endRow, 500); i += 1) {
|
|
320
|
+
rows.push({ id: i, name: `Row ${i}` })
|
|
321
|
+
}
|
|
322
|
+
return { rows, rowCount: 500 } // never sets appliedExpression
|
|
323
|
+
},
|
|
324
|
+
}
|
|
325
|
+
let view!: ServerState<Row>
|
|
326
|
+
const ctl = createServerDataSource<Row>(source, {
|
|
327
|
+
mode: 'infinite',
|
|
328
|
+
blockSize: 100,
|
|
329
|
+
onChange: (s) => (view = s),
|
|
330
|
+
})
|
|
331
|
+
|
|
332
|
+
ctl.setFilter({ expression: { kind: 'cmp', column: 'name', op: 'contains', value: 'x' } })
|
|
333
|
+
ctl.setViewport(0, 20)
|
|
334
|
+
await settle()
|
|
335
|
+
ctl.setViewport(200, 220)
|
|
336
|
+
await settle()
|
|
337
|
+
|
|
338
|
+
expect(view.expressionUnapplied).toBe(true)
|
|
339
|
+
expect(warn).toHaveBeenCalledTimes(1) // once per controller, not per block
|
|
340
|
+
warn.mockRestore()
|
|
341
|
+
ctl.dispose()
|
|
342
|
+
})
|
|
343
|
+
})
|