@tita-agent/dsh-data-table 0.0.0-stage → 0.2.0
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/LICENSE +21 -0
- package/README.md +172 -2
- package/cordis.patch.yml +7 -0
- package/lib/client.js +16766 -0
- package/lib/contract-envelope.d.ts +91 -0
- package/lib/contract-envelope.js +106 -0
- package/lib/contract-layout.d.ts +130 -0
- package/lib/contract-layout.js +138 -0
- package/lib/contract-refs.d.ts +39 -0
- package/lib/contract-refs.js +9 -0
- package/lib/contract-version.d.ts +311 -0
- package/lib/contract-version.js +270 -0
- package/lib/contract-wire.d.ts +147 -0
- package/lib/contract-wire.js +99 -0
- package/lib/contracts.d.ts +12 -0
- package/lib/contracts.js +12 -0
- package/lib/types/audit.d.ts +42 -0
- package/lib/types/audit.js +39 -0
- package/lib/types/client/ProjectImportMenu.d.ts +30 -0
- package/lib/types/client/ProjectImportMenu.js +70 -0
- package/lib/types/client/SheetPanel.d.ts +33 -0
- package/lib/types/client/SheetPanel.js +1766 -0
- package/lib/types/client/SheetToggle.d.ts +18 -0
- package/lib/types/client/SheetToggle.js +26 -0
- package/lib/types/client/index.d.ts +15 -0
- package/lib/types/client/index.js +110 -0
- package/lib/types/client/persistence/changes.d.ts +15 -0
- package/lib/types/client/persistence/changes.js +51 -0
- package/lib/types/client/persistence/ids.d.ts +34 -0
- package/lib/types/client/persistence/ids.js +48 -0
- package/lib/types/client/persistence/merge.d.ts +35 -0
- package/lib/types/client/persistence/merge.js +362 -0
- package/lib/types/client/store.d.ts +61 -0
- package/lib/types/client/store.js +152 -0
- package/lib/types/client/surface-context.d.ts +27 -0
- package/lib/types/client/surface-context.js +104 -0
- package/lib/types/client/surface-control.d.ts +2 -0
- package/lib/types/client/surface-control.js +12 -0
- package/lib/types/client/transport/workbookApi.d.ts +159 -0
- package/lib/types/client/transport/workbookApi.js +246 -0
- package/lib/types/client/univer/StandaloneWorkbookPage.d.ts +5 -0
- package/lib/types/client/univer/StandaloneWorkbookPage.js +7 -0
- package/lib/types/client/univer/WorkbookCanvas.d.ts +40 -0
- package/lib/types/client/univer/WorkbookCanvas.js +87 -0
- package/lib/types/client/univer/WorkbookView.d.ts +3 -0
- package/lib/types/client/univer/WorkbookView.js +2 -0
- package/lib/types/client/univer/loader.d.ts +18 -0
- package/lib/types/client/univer/loader.js +81 -0
- package/lib/types/client/univer/standalone-entry.d.ts +1 -0
- package/lib/types/client/univer/standalone-entry.js +19 -0
- package/lib/types/client/versions/VersionChrome.d.ts +33 -0
- package/lib/types/client/versions/VersionChrome.js +21 -0
- package/lib/types/client/versions/inspect.d.ts +70 -0
- package/lib/types/client/versions/inspect.js +88 -0
- package/lib/types/client/versions/preview-decoration.d.ts +11 -0
- package/lib/types/client/versions/preview-decoration.js +54 -0
- package/lib/types/client/versions/records.d.ts +19 -0
- package/lib/types/client/versions/records.js +70 -0
- package/lib/types/client/workspace-host.d.ts +61 -0
- package/lib/types/client/workspace-host.js +124 -0
- package/lib/types/collaboration-hub.d.ts +31 -0
- package/lib/types/collaboration-hub.js +69 -0
- package/lib/types/contract/ids.d.ts +24 -0
- package/lib/types/contract/ids.js +46 -0
- package/lib/types/contract/mutations.d.ts +25 -0
- package/lib/types/contract/mutations.js +782 -0
- package/lib/types/contract/operations.d.ts +54 -0
- package/lib/types/contract/operations.js +203 -0
- package/lib/types/contract/snapshots.d.ts +176 -0
- package/lib/types/contract/snapshots.js +351 -0
- package/lib/types/contract/univer-api-catalog.d.ts +29 -0
- package/lib/types/contract/univer-api-catalog.js +264 -0
- package/lib/types/errors.d.ts +8 -0
- package/lib/types/errors.js +12 -0
- package/lib/types/http/assets-routes.d.ts +3 -0
- package/lib/types/http/assets-routes.js +169 -0
- package/lib/types/http/collaboration.d.ts +10 -0
- package/lib/types/http/collaboration.js +154 -0
- package/lib/types/http/history.d.ts +15 -0
- package/lib/types/http/history.js +134 -0
- package/lib/types/http/project-files.d.ts +79 -0
- package/lib/types/http/project-files.js +206 -0
- package/lib/types/http/project-scope.d.ts +50 -0
- package/lib/types/http/project-scope.js +52 -0
- package/lib/types/http/routes.d.ts +98 -0
- package/lib/types/http/routes.js +323 -0
- package/lib/types/http/standalone.d.ts +9 -0
- package/lib/types/http/standalone.js +31 -0
- package/lib/types/http/trunk.d.ts +10 -0
- package/lib/types/http/trunk.js +322 -0
- package/lib/types/http/worktree.d.ts +9 -0
- package/lib/types/http/worktree.js +145 -0
- package/lib/types/index.d.ts +18 -0
- package/lib/types/index.js +156 -0
- package/lib/types/invariant.d.ts +15 -0
- package/lib/types/invariant.js +15 -0
- package/lib/types/request-params.d.ts +21 -0
- package/lib/types/request-params.js +76 -0
- package/lib/types/store/paths.d.ts +68 -0
- package/lib/types/store/paths.js +148 -0
- package/lib/types/store/project.d.ts +88 -0
- package/lib/types/store/project.js +120 -0
- package/lib/types/store/read.d.ts +110 -0
- package/lib/types/store/read.js +404 -0
- package/lib/types/store/retention.d.ts +27 -0
- package/lib/types/store/retention.js +111 -0
- package/lib/types/store/write.d.ts +22 -0
- package/lib/types/store/write.js +210 -0
- package/lib/types/tools/arguments.d.ts +40 -0
- package/lib/types/tools/arguments.js +130 -0
- package/lib/types/tools/cells.d.ts +50 -0
- package/lib/types/tools/cells.js +298 -0
- package/lib/types/tools/index.d.ts +2 -0
- package/lib/types/tools/index.js +250 -0
- package/lib/types/tools/render.d.ts +47 -0
- package/lib/types/tools/render.js +290 -0
- package/lib/types/tools/univer-api.d.ts +18 -0
- package/lib/types/tools/univer-api.js +198 -0
- package/lib/types/tools/workbook-catalog.d.ts +3 -0
- package/lib/types/tools/workbook-catalog.js +83 -0
- package/lib/types/tools/workbook-edit.d.ts +192 -0
- package/lib/types/tools/workbook-edit.js +912 -0
- package/lib/types/tools/workbook-find.d.ts +11 -0
- package/lib/types/tools/workbook-find.js +89 -0
- package/lib/types/tools/workbook-history.d.ts +2 -0
- package/lib/types/tools/workbook-history.js +59 -0
- package/lib/types/tools/workbook-read.d.ts +21 -0
- package/lib/types/tools/workbook-read.js +204 -0
- package/lib/types/types.d.ts +377 -0
- package/lib/types/types.js +34 -0
- package/lib/types/univer/apply-operation.d.ts +14 -0
- package/lib/types/univer/apply-operation.js +398 -0
- package/lib/types/univer/chunk.d.ts +68 -0
- package/lib/types/univer/chunk.js +16 -0
- package/lib/types/univer/decoration.d.ts +34 -0
- package/lib/types/univer/decoration.js +88 -0
- package/lib/types/univer/diagnostics.d.ts +31 -0
- package/lib/types/univer/diagnostics.js +141 -0
- package/lib/types/univer/engine.d.ts +33 -0
- package/lib/types/univer/engine.js +338 -0
- package/lib/types/univer/entry.d.ts +8 -0
- package/lib/types/univer/entry.js +11 -0
- package/lib/types/univer/facade.d.ts +107 -0
- package/lib/types/univer/facade.js +1 -0
- package/lib/types/univer/fonts.d.ts +202 -0
- package/lib/types/univer/fonts.js +140 -0
- package/lib/types/univer/plugins/collaboration.d.ts +23 -0
- package/lib/types/univer/plugins/collaboration.js +47 -0
- package/lib/types/univer/plugins/export.d.ts +39 -0
- package/lib/types/univer/plugins/export.js +246 -0
- package/lib/types/univer/plugins/history.d.ts +24 -0
- package/lib/types/univer/plugins/history.js +50 -0
- package/lib/types/univer/plugins/version.d.ts +13 -0
- package/lib/types/univer/plugins/version.js +13 -0
- package/lib/types/version/diff.d.ts +36 -0
- package/lib/types/version/diff.js +156 -0
- package/lib/types/version/grouping.d.ts +7 -0
- package/lib/types/version/grouping.js +94 -0
- package/lib/types/version/records.d.ts +17 -0
- package/lib/types/version/records.js +102 -0
- package/lib/types/version/session.d.ts +36 -0
- package/lib/types/version/session.js +89 -0
- package/lib/types/version/summary.d.ts +24 -0
- package/lib/types/version/summary.js +111 -0
- package/lib/types/workbook-manager.d.ts +191 -0
- package/lib/types/workbook-manager.js +935 -0
- package/lib/types/xlsx-export-worker.d.ts +5 -0
- package/lib/types/xlsx-export-worker.js +24 -0
- package/lib/types/xlsx-export.d.ts +21 -0
- package/lib/types/xlsx-export.js +371 -0
- package/lib/types/xlsx-import-worker.d.ts +1 -0
- package/lib/types/xlsx-import-worker.js +19 -0
- package/lib/univer-client.js +690 -0
- package/lib/workbook-page.js +23826 -0
- package/lib/xlsx-export-worker.js +104 -0
- package/lib/xlsx-import-worker.js +46 -0
- package/package.json +106 -3
- package/src/audit.ts +58 -0
- package/src/client/ProjectImportMenu.tsx +100 -0
- package/src/client/SheetPanel.module.css +1578 -0
- package/src/client/SheetPanel.tsx +1934 -0
- package/src/client/SheetToggle.module.css +73 -0
- package/src/client/SheetToggle.tsx +65 -0
- package/src/client/contract.d.ts +19 -0
- package/src/client/index.ts +131 -0
- package/src/client/persistence/changes.ts +58 -0
- package/src/client/persistence/ids.ts +60 -0
- package/src/client/persistence/merge.ts +392 -0
- package/src/client/store.ts +188 -0
- package/src/client/surface-context.ts +123 -0
- package/src/client/surface-control.ts +13 -0
- package/src/client/transport/workbookApi.ts +355 -0
- package/src/client/univer/SheetView.module.css +110 -0
- package/src/client/univer/StandaloneWorkbookPage.module.css +8 -0
- package/src/client/univer/StandaloneWorkbookPage.tsx +15 -0
- package/src/client/univer/WorkbookCanvas.tsx +128 -0
- package/src/client/univer/WorkbookView.module.css +30 -0
- package/src/client/univer/WorkbookView.tsx +3 -0
- package/src/client/univer/loader.ts +90 -0
- package/src/client/univer/react-dom-client.d.ts +10 -0
- package/src/client/univer/standalone-entry.tsx +19 -0
- package/src/client/univer/standalone.css +12 -0
- package/src/client/univer/univer-locales.d.ts +89 -0
- package/src/client/univer/univer-modules.d.ts +26 -0
- package/src/client/versions/VersionChrome.tsx +114 -0
- package/src/client/versions/inspect.ts +138 -0
- package/src/client/versions/preview-decoration.ts +54 -0
- package/src/client/versions/records.ts +78 -0
- package/src/client/workspace-host.ts +147 -0
- package/src/collaboration-hub.ts +83 -0
- package/src/contract/ids.ts +50 -0
- package/src/contract/mutations.ts +791 -0
- package/src/contract/operations.ts +221 -0
- package/src/contract/snapshots.ts +383 -0
- package/src/contract/univer-api-catalog.ts +289 -0
- package/src/css-modules.d.ts +6 -0
- package/src/errors.ts +25 -0
- package/src/http/assets-routes.ts +177 -0
- package/src/http/collaboration.ts +144 -0
- package/src/http/history.ts +151 -0
- package/src/http/project-files.ts +227 -0
- package/src/http/project-scope.ts +77 -0
- package/src/http/routes.ts +364 -0
- package/src/http/standalone.ts +32 -0
- package/src/http/trunk.ts +322 -0
- package/src/http/worktree.ts +119 -0
- package/src/index.ts +165 -0
- package/src/invariant.ts +17 -0
- package/src/request-params.ts +92 -0
- package/src/store/paths.ts +165 -0
- package/src/store/project.ts +137 -0
- package/src/store/read.ts +454 -0
- package/src/store/retention.ts +106 -0
- package/src/store/write.ts +230 -0
- package/src/tools/arguments.ts +128 -0
- package/src/tools/cells.ts +298 -0
- package/src/tools/index.ts +274 -0
- package/src/tools/render.ts +301 -0
- package/src/tools/univer-api.ts +243 -0
- package/src/tools/workbook-catalog.ts +94 -0
- package/src/tools/workbook-edit.ts +987 -0
- package/src/tools/workbook-find.ts +80 -0
- package/src/tools/workbook-history.ts +63 -0
- package/src/tools/workbook-read.ts +210 -0
- package/src/types.ts +432 -0
- package/src/univer/apply-operation.ts +369 -0
- package/src/univer/chunk.ts +77 -0
- package/src/univer/decoration.ts +111 -0
- package/src/univer/diagnostics.ts +136 -0
- package/src/univer/engine.ts +370 -0
- package/src/univer/entry.ts +14 -0
- package/src/univer/facade.ts +91 -0
- package/src/univer/fonts.ts +148 -0
- package/src/univer/overrides.css +33 -0
- package/src/univer/plugins/collaboration.ts +47 -0
- package/src/univer/plugins/export.ts +236 -0
- package/src/univer/plugins/history.ts +49 -0
- package/src/univer/plugins/version.ts +13 -0
- package/src/version/diff.ts +169 -0
- package/src/version/grouping.ts +96 -0
- package/src/version/records.ts +113 -0
- package/src/version/session.ts +90 -0
- package/src/version/summary.ts +117 -0
- package/src/workbook-manager.ts +1111 -0
- package/src/xlsx-export-worker.ts +34 -0
- package/src/xlsx-export.ts +373 -0
- package/src/xlsx-import-worker.ts +30 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Univer canvas used by the embedded Datasheet panel and the
|
|
3
|
+
* standalone workbook page. The workspace owns persistence and sync; this
|
|
4
|
+
* component owns only Univer residency and its imperative editing surface.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react'
|
|
8
|
+
import { mountWorkbook, type WorkbookDecoration } from './loader.ts'
|
|
9
|
+
import type { WorkbookFocusRange, WorkbookLocalChange, WorkbookOperation, WorkbookPresencePayload, WorkbookSelectionRange } from '../../types.ts'
|
|
10
|
+
import styles from './WorkbookView.module.css'
|
|
11
|
+
|
|
12
|
+
export interface WorkbookCanvasProps {
|
|
13
|
+
workbookData: object
|
|
14
|
+
/**
|
|
15
|
+
* Preview residency (docs/issue/0002 PRD v3.2 §7.2): the canvas is showing a past
|
|
16
|
+
* Version rather than live content, so it is mounted with Univer's editable
|
|
17
|
+
* permission off and its mutations are never reported as changes. The caller
|
|
18
|
+
* owns the preview state; this component only refuses to fork a Version.
|
|
19
|
+
*/
|
|
20
|
+
readOnly?: boolean
|
|
21
|
+
/**
|
|
22
|
+
* Diff overlay for a preview residency: the cells that differ from the
|
|
23
|
+
* baseline, painted by the engine at mount (PRD v3.3 §7.2). Part of the
|
|
24
|
+
* residency, not a live API — a Step jump remounts the canvas, so a stale
|
|
25
|
+
* highlight cannot survive it.
|
|
26
|
+
*/
|
|
27
|
+
decoration?: WorkbookDecoration
|
|
28
|
+
onDirty?: (change?: WorkbookLocalChange) => void
|
|
29
|
+
onPresence?: (presence: WorkbookPresencePayload) => void
|
|
30
|
+
onSelectionChange?: (ranges: readonly WorkbookSelectionRange[]) => void
|
|
31
|
+
onReady?: () => void
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface WorkbookCanvasHandle {
|
|
35
|
+
save(): unknown
|
|
36
|
+
applyOperation(operation: WorkbookOperation): Promise<void>
|
|
37
|
+
focusRange(range: WorkbookFocusRange): boolean
|
|
38
|
+
/**
|
|
39
|
+
* Show a different workbook in the same residency. Returns false when the
|
|
40
|
+
* engine could not swap, so the caller can fall back to a remount.
|
|
41
|
+
*/
|
|
42
|
+
swapWorkbook(next: object, decoration?: WorkbookDecoration): boolean
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Resident workbook canvas shared by embedded and standalone workspaces. */
|
|
46
|
+
export const WorkbookCanvas = forwardRef<WorkbookCanvasHandle, WorkbookCanvasProps>(
|
|
47
|
+
function WorkbookCanvas({ workbookData, readOnly = false, decoration, onDirty, onPresence, onSelectionChange, onReady }, ref) {
|
|
48
|
+
const containerRef = useRef<HTMLDivElement>(null)
|
|
49
|
+
const handleRef = useRef<WorkbookCanvasHandle | null>(null)
|
|
50
|
+
const [ready, setReady] = useState(false)
|
|
51
|
+
const [failed, setFailed] = useState(false)
|
|
52
|
+
// Read through a ref so the mount effect stays keyed on the residency
|
|
53
|
+
// itself: `workbookData`/`readOnly` are fixed for a residency's lifetime,
|
|
54
|
+
// and the caller switches residency by changing the React `key`.
|
|
55
|
+
const readOnlyRef = useRef(readOnly)
|
|
56
|
+
readOnlyRef.current = readOnly
|
|
57
|
+
const decorationRef = useRef(decoration)
|
|
58
|
+
decorationRef.current = decoration
|
|
59
|
+
const selectionChangeRef = useRef(onSelectionChange)
|
|
60
|
+
selectionChangeRef.current = onSelectionChange
|
|
61
|
+
const readyRef = useRef(onReady)
|
|
62
|
+
readyRef.current = onReady
|
|
63
|
+
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (handleRef.current !== null) return
|
|
66
|
+
const element = containerRef.current
|
|
67
|
+
if (element === null) return
|
|
68
|
+
let disposed = false
|
|
69
|
+
let mounted: Awaited<ReturnType<typeof mountWorkbook>> | null = null
|
|
70
|
+
const readOnlyMount = readOnlyRef.current
|
|
71
|
+
void (async () => {
|
|
72
|
+
await new Promise<void>(resolve => requestAnimationFrame(() => resolve()))
|
|
73
|
+
if (disposed) return
|
|
74
|
+
// Univer emits initialization/layout mutations while createUnit is
|
|
75
|
+
// still mounting. They describe the initial projection, not a user
|
|
76
|
+
// edit; forwarding them would mark the workbook dirty immediately and
|
|
77
|
+
// attempt a large snapshot save before the canvas is ready.
|
|
78
|
+
const mount = await mountWorkbook(element, workbookData, change => {
|
|
79
|
+
if (mounted !== null && !readOnlyMount) onDirty?.(change)
|
|
80
|
+
}, presence => {
|
|
81
|
+
if (mounted !== null && !readOnlyMount) onPresence?.(presence)
|
|
82
|
+
}, { readOnly: readOnlyMount, ...(decorationRef.current === undefined ? {} : { decoration: decorationRef.current }) }, ranges => {
|
|
83
|
+
if (mounted !== null && !readOnlyMount) selectionChangeRef.current?.(ranges)
|
|
84
|
+
})
|
|
85
|
+
mounted = mount
|
|
86
|
+
if (disposed) {
|
|
87
|
+
mount.dispose()
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
handleRef.current = {
|
|
91
|
+
save: () => mount.save(),
|
|
92
|
+
applyOperation: operation => mount.applyOperation(operation),
|
|
93
|
+
focusRange: range => mount.focusRange(range),
|
|
94
|
+
swapWorkbook: (next, nextDecoration) => mount.swapWorkbook(next, nextDecoration === undefined ? {} : { decoration: nextDecoration }),
|
|
95
|
+
}
|
|
96
|
+
setReady(true)
|
|
97
|
+
readyRef.current?.()
|
|
98
|
+
})().catch(() => {
|
|
99
|
+
if (!disposed) setFailed(true)
|
|
100
|
+
})
|
|
101
|
+
return () => {
|
|
102
|
+
disposed = true
|
|
103
|
+
mounted?.dispose()
|
|
104
|
+
mounted = null
|
|
105
|
+
handleRef.current = null
|
|
106
|
+
}
|
|
107
|
+
// Workbook data is fixed for the residency's lifetime.
|
|
108
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
109
|
+
}, [])
|
|
110
|
+
|
|
111
|
+
useImperativeHandle(ref, () => ({
|
|
112
|
+
save: () => (handleRef.current?.save() ?? null) as unknown,
|
|
113
|
+
applyOperation: async operation => { await handleRef.current?.applyOperation(operation) },
|
|
114
|
+
focusRange: range => handleRef.current?.focusRange(range) ?? false,
|
|
115
|
+
swapWorkbook: (next, nextDecoration) => handleRef.current?.swapWorkbook(next, nextDecoration) ?? false,
|
|
116
|
+
}))
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<div className={styles.view}>
|
|
120
|
+
<div className={styles.body}>
|
|
121
|
+
{!ready && !failed && <div className={styles.hint}>表格加载中…</div>}
|
|
122
|
+
{failed && <div className={styles.hint}>表格渲染失败</div>}
|
|
123
|
+
<div ref={containerRef} className={styles.univer} />
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
)
|
|
127
|
+
},
|
|
128
|
+
)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
.view {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
height: 100%;
|
|
5
|
+
min-height: 320px;
|
|
6
|
+
border: 0;
|
|
7
|
+
border-radius: 0;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
background: var(--tita-surface);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.body {
|
|
13
|
+
position: relative;
|
|
14
|
+
flex: 1;
|
|
15
|
+
min-height: 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.hint {
|
|
19
|
+
padding: 32px 20px;
|
|
20
|
+
font-size: 13px;
|
|
21
|
+
color: var(--tita-ink-muted);
|
|
22
|
+
text-align: center;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.univer {
|
|
26
|
+
position: absolute;
|
|
27
|
+
inset: 0;
|
|
28
|
+
height: 100%;
|
|
29
|
+
width: 100%;
|
|
30
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazy Univer half for dsh-data-table. The heavy Univer engine lives
|
|
3
|
+
* in a separate chunk (`lib/univer-client.js`, served by the node half at
|
|
4
|
+
* `/data-sheet/univer-client.js`); this module loads that chunk on the first
|
|
5
|
+
* sheet render so the ~16MB graph is never in the page's boot bundle.
|
|
6
|
+
* CSV export is engine-free and stays here.
|
|
7
|
+
* @module dsh-data-table/client/univer
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { WorkbookLocalChange, WorkbookPresencePayload, WorkbookSelectionRange } from '../../types.ts'
|
|
11
|
+
import type { UniverChunkApi, WorkbookDecoration, WorkbookMount, WorkbookMountOptions } from '../../univer/chunk.ts'
|
|
12
|
+
|
|
13
|
+
// The chunk contract (mount shape, mount options, and the `window` global) is
|
|
14
|
+
// declared once in `../../univer/chunk.ts`, so the loader and the ~16MB chunk it
|
|
15
|
+
// loads cannot drift apart. Re-exported here because the client half is that
|
|
16
|
+
// contract's public surface for the panel components.
|
|
17
|
+
export type { WorkbookDecoration, WorkbookDecorationCell, WorkbookMount, WorkbookMountOptions } from '../../univer/chunk.ts'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Engine-chunk candidates, tried in order: the node-half route is the durable
|
|
21
|
+
* source (registered when the dsh server runs the current plugin code); the
|
|
22
|
+
* dist asset is the stopgap for a server that was started before the route
|
|
23
|
+
* existed (each failed source is a dead end, not retried).
|
|
24
|
+
*/
|
|
25
|
+
function dataSheetAssetPath(path: string, keepQuery = false): string {
|
|
26
|
+
const transport = (globalThis as { __DSH_TRANSPORT__?: { ownsHost?: boolean } }).__DSH_TRANSPORT__
|
|
27
|
+
if (transport?.ownsHost === true) {
|
|
28
|
+
// The path travels as a query parameter, so a cache-busting query string
|
|
29
|
+
// would become part of the resolved file path; drop it in this mode.
|
|
30
|
+
const [withoutQuery] = keepQuery ? path.split('?') : [path]
|
|
31
|
+
return `/api/data-sheet?path=${encodeURIComponent(withoutQuery ?? path)}`
|
|
32
|
+
}
|
|
33
|
+
return path
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
declare const __DSH_DATA_SHEET_BUILD__: string | undefined
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Build tag appended to the engine chunk URL. The chunk is a plain script the
|
|
40
|
+
* browser caches by URL, so a rebuilt chunk used to keep running in an already
|
|
41
|
+
* open page; a unique query makes every build a different URL. The host
|
|
42
|
+
* transport mode passes the path as a query parameter, so the tag is only
|
|
43
|
+
* added on the direct route (which matches on `pathname` and ignores queries).
|
|
44
|
+
*/
|
|
45
|
+
const CHUNK_VERSION = typeof __DSH_DATA_SHEET_BUILD__ === 'string' ? __DSH_DATA_SHEET_BUILD__ : 'dev'
|
|
46
|
+
const chunkPath = `/data-sheet/univer-client.js?v=${encodeURIComponent(CHUNK_VERSION)}`
|
|
47
|
+
const CHUNK_SOURCES = [dataSheetAssetPath(chunkPath, true), '/assets/data-sheet-univer.js']
|
|
48
|
+
|
|
49
|
+
let chunkPromise: Promise<UniverChunkApi> | null = null
|
|
50
|
+
|
|
51
|
+
/** Load the engine chunk once (script tag; shared across concurrent callers). */
|
|
52
|
+
function loadChunk(): Promise<UniverChunkApi> {
|
|
53
|
+
if (window.__bestExcelUniver !== undefined) return Promise.resolve(window.__bestExcelUniver)
|
|
54
|
+
if (chunkPromise !== null) return chunkPromise
|
|
55
|
+
chunkPromise = (async () => {
|
|
56
|
+
for (const src of CHUNK_SOURCES) {
|
|
57
|
+
try {
|
|
58
|
+
await new Promise<void>((resolve, reject) => {
|
|
59
|
+
const el = document.createElement('script')
|
|
60
|
+
el.async = true
|
|
61
|
+
el.src = src
|
|
62
|
+
el.addEventListener('load', () => {
|
|
63
|
+
if (window.__bestExcelUniver === undefined) reject(new Error(`univer chunk loaded without its global: ${src}`))
|
|
64
|
+
else resolve()
|
|
65
|
+
}, { once: true })
|
|
66
|
+
el.addEventListener('error', () => reject(new Error(`univer chunk failed to load: ${src}`)))
|
|
67
|
+
document.head.append(el)
|
|
68
|
+
})
|
|
69
|
+
const api = window.__bestExcelUniver
|
|
70
|
+
if (api === undefined) throw new Error('univer chunk resolved without its global')
|
|
71
|
+
return api
|
|
72
|
+
} catch (error) {
|
|
73
|
+
if (src === CHUNK_SOURCES[CHUNK_SOURCES.length - 1]) throw error
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
throw new Error('unreachable')
|
|
77
|
+
})()
|
|
78
|
+
return chunkPromise
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Mount one resident Univer engine into a container with a workbook snapshot.
|
|
83
|
+
* Resolves after the engine chunk arrived (first call pays the fetch/parse).
|
|
84
|
+
* `options.readOnly` mounts a preview residency: the snapshot is a past
|
|
85
|
+
* Version, so no edit is reported and none can be made (PRD v3.2 §7.2).
|
|
86
|
+
*/
|
|
87
|
+
export async function mountWorkbook(container: HTMLElement, workbookData: object, onDirty?: (change?: WorkbookLocalChange) => void, onPresence?: (presence: WorkbookPresencePayload) => void, options?: WorkbookMountOptions, onSelection?: (ranges: readonly WorkbookSelectionRange[]) => void): Promise<WorkbookMount> {
|
|
88
|
+
const api = await loadChunk()
|
|
89
|
+
return api.mountWorkbook(container, workbookData, onDirty, onPresence, options, onSelection)
|
|
90
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createRoot } from 'react-dom/client'
|
|
2
|
+
import { setDshSessionId } from '../transport/workbookApi.ts'
|
|
3
|
+
import { StandaloneWorkbookPage } from './StandaloneWorkbookPage.tsx'
|
|
4
|
+
import './standalone.css'
|
|
5
|
+
|
|
6
|
+
const root = document.getElementById('data-sheet-workbook-root')
|
|
7
|
+
if (root !== null) {
|
|
8
|
+
const query = new URLSearchParams(window.location.search)
|
|
9
|
+
// The project this page reads: the address that opened it carries the Session id
|
|
10
|
+
// (see `standaloneWorkbookPath`), because a page in its own document — a new tab
|
|
11
|
+
// or the in-app full page — has no sidebar to ask.
|
|
12
|
+
setDshSessionId(query.get('sessionId') ?? undefined)
|
|
13
|
+
const pathMatch = /^\/data-sheet\/workbook\/([^/]+)\/view$/.exec(window.location.pathname)
|
|
14
|
+
const queryId = query.get('workbook')
|
|
15
|
+
const workbookId = pathMatch?.[1] === undefined
|
|
16
|
+
? (queryId ?? 'main')
|
|
17
|
+
: decodeURIComponent(pathMatch[1])
|
|
18
|
+
createRoot(root).render(<StandaloneWorkbookPage workbookId={workbookId} />)
|
|
19
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ambient declarations for the sheets preset family's `lib/es` runtime
|
|
3
|
+
* modules (index + locale packs): the published packages ship no sibling
|
|
4
|
+
* declarations next to the runtime files. Mirrors the typed counterparts —
|
|
5
|
+
* the preset factory signature (index modules) and the default locale object.
|
|
6
|
+
* @module dsh-data-table/client/univer-locales
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- ambient shim for the runtime-only subpath (IPreset is not exported).
|
|
10
|
+
type PresetFactory = (config?: unknown) => any
|
|
11
|
+
|
|
12
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-core/index.js' {
|
|
13
|
+
export const UniverSheetsCorePreset: PresetFactory
|
|
14
|
+
}
|
|
15
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-filter/index.js' {
|
|
16
|
+
export const UniverSheetsFilterPreset: PresetFactory
|
|
17
|
+
}
|
|
18
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-sort/index.js' {
|
|
19
|
+
export const UniverSheetsSortPreset: PresetFactory
|
|
20
|
+
}
|
|
21
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-find-replace/index.js' {
|
|
22
|
+
export const UniverSheetsFindReplacePreset: PresetFactory
|
|
23
|
+
}
|
|
24
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-conditional-formatting/index.js' {
|
|
25
|
+
export const UniverSheetsConditionalFormattingPreset: PresetFactory
|
|
26
|
+
}
|
|
27
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-data-validation/index.js' {
|
|
28
|
+
export const UniverSheetsDataValidationPreset: PresetFactory
|
|
29
|
+
}
|
|
30
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-drawing/index.js' {
|
|
31
|
+
export const UniverSheetsDrawingPreset: PresetFactory
|
|
32
|
+
}
|
|
33
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-hyper-link/index.js' {
|
|
34
|
+
export const UniverSheetsHyperLinkPreset: PresetFactory
|
|
35
|
+
}
|
|
36
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-note/index.js' {
|
|
37
|
+
export const UniverSheetsNotePreset: PresetFactory
|
|
38
|
+
}
|
|
39
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-thread-comment/index.js' {
|
|
40
|
+
export const UniverSheetsThreadCommentPreset: PresetFactory
|
|
41
|
+
}
|
|
42
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-table/index.js' {
|
|
43
|
+
export const UniverSheetsTablePreset: PresetFactory
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-core/locales/*.js' {
|
|
47
|
+
const locale: Record<string, unknown>
|
|
48
|
+
export default locale
|
|
49
|
+
}
|
|
50
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-filter/locales/*.js' {
|
|
51
|
+
const locale: Record<string, unknown>
|
|
52
|
+
export default locale
|
|
53
|
+
}
|
|
54
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-sort/locales/*.js' {
|
|
55
|
+
const locale: Record<string, unknown>
|
|
56
|
+
export default locale
|
|
57
|
+
}
|
|
58
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-find-replace/locales/*.js' {
|
|
59
|
+
const locale: Record<string, unknown>
|
|
60
|
+
export default locale
|
|
61
|
+
}
|
|
62
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-conditional-formatting/locales/*.js' {
|
|
63
|
+
const locale: Record<string, unknown>
|
|
64
|
+
export default locale
|
|
65
|
+
}
|
|
66
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-data-validation/locales/*.js' {
|
|
67
|
+
const locale: Record<string, unknown>
|
|
68
|
+
export default locale
|
|
69
|
+
}
|
|
70
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-drawing/locales/*.js' {
|
|
71
|
+
const locale: Record<string, unknown>
|
|
72
|
+
export default locale
|
|
73
|
+
}
|
|
74
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-hyper-link/locales/*.js' {
|
|
75
|
+
const locale: Record<string, unknown>
|
|
76
|
+
export default locale
|
|
77
|
+
}
|
|
78
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-note/locales/*.js' {
|
|
79
|
+
const locale: Record<string, unknown>
|
|
80
|
+
export default locale
|
|
81
|
+
}
|
|
82
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-thread-comment/locales/*.js' {
|
|
83
|
+
const locale: Record<string, unknown>
|
|
84
|
+
export default locale
|
|
85
|
+
}
|
|
86
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-table/locales/*.js' {
|
|
87
|
+
const locale: Record<string, unknown>
|
|
88
|
+
export default locale
|
|
89
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ambient types for the deep Univer preset entry. The preset factory is only
|
|
3
|
+
* exported from the es build subpath (the npm exports map types live at a
|
|
4
|
+
* different subpath), so this standalone declaration types the runtime import
|
|
5
|
+
* in `client/univer/loader.ts`. Must stay free of top-level imports to remain an ambient
|
|
6
|
+
* module declaration rather than an augmentation.
|
|
7
|
+
* @module dsh-data-table/client/univer-modules
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
declare module '@univerjs/presets/lib/es/preset-sheets-core/index.js' {
|
|
11
|
+
import type { Plugin, PluginCtor } from '@univerjs/core'
|
|
12
|
+
|
|
13
|
+
export interface UniverSheetsCorePresetOptions {
|
|
14
|
+
container?: HTMLElement
|
|
15
|
+
header?: boolean
|
|
16
|
+
toolbar?: boolean
|
|
17
|
+
formulaBar?: boolean
|
|
18
|
+
statusBarStatistic?: boolean
|
|
19
|
+
footer?: boolean
|
|
20
|
+
contextMenu?: boolean
|
|
21
|
+
disableAutoFocus?: boolean
|
|
22
|
+
}
|
|
23
|
+
export function UniverSheetsCorePreset(
|
|
24
|
+
config?: Partial<UniverSheetsCorePresetOptions>,
|
|
25
|
+
): { plugins: Array<PluginCtor<Plugin> | [PluginCtor<Plugin>, unknown]> }
|
|
26
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The version drawer and the two dialogs that answer from it (docs/issue/0022 P5).
|
|
3
|
+
*
|
|
4
|
+
* This is the chrome half of the history surface: `records.ts` turns a stored
|
|
5
|
+
* Version into the row the list draws, `inspect.ts` produces what the comparison
|
|
6
|
+
* bar needs, and this assembles the Drawer, the 保存版本 dialog and the
|
|
7
|
+
* 恢复/撤销 confirmation out of them. It was inline in `SheetPanel.tsx`, which is
|
|
8
|
+
* pinned at its size for a reason — the panel's job is the canvas and the wire,
|
|
9
|
+
* and the copy and structure of the history UI are not part of that.
|
|
10
|
+
*/
|
|
11
|
+
import { Button } from '@tita-agent/ui/components'
|
|
12
|
+
import {
|
|
13
|
+
Drawer,
|
|
14
|
+
DrawerBody,
|
|
15
|
+
DrawerContent,
|
|
16
|
+
DrawerDescription,
|
|
17
|
+
DrawerHeader,
|
|
18
|
+
DrawerTitle,
|
|
19
|
+
} from '@tita-agent/ui/overlays'
|
|
20
|
+
import { Save } from '@tita-agent/ui/icons'
|
|
21
|
+
import {
|
|
22
|
+
RestoreDialog,
|
|
23
|
+
SaveVersionDialog,
|
|
24
|
+
VersionManager,
|
|
25
|
+
type VersionManagerActions,
|
|
26
|
+
type VersionManagerGroup,
|
|
27
|
+
} from '@tita-agent/ui/versions'
|
|
28
|
+
import type { VersionRestoreRequest } from './inspect.ts'
|
|
29
|
+
|
|
30
|
+
export interface VersionChromeProps {
|
|
31
|
+
open: boolean
|
|
32
|
+
onOpenChange: (open: boolean) => void
|
|
33
|
+
/** Name of the artifact, for the drawer's header line. */
|
|
34
|
+
artifactName: string
|
|
35
|
+
/** How many Versions the list holds, and when the newest one landed. */
|
|
36
|
+
versionCount: number
|
|
37
|
+
headLabel: string | undefined
|
|
38
|
+
/** The Version the canvas would restore, or undo, to. */
|
|
39
|
+
restorableId: string | undefined
|
|
40
|
+
loading: boolean
|
|
41
|
+
groups: VersionManagerGroup[]
|
|
42
|
+
actions: VersionManagerActions
|
|
43
|
+
save: {
|
|
44
|
+
open: boolean
|
|
45
|
+
pending: boolean
|
|
46
|
+
/** True while no artifact is open: there is nothing to name. */
|
|
47
|
+
disabled: boolean
|
|
48
|
+
onOpenChange: (open: boolean) => void
|
|
49
|
+
onConfirm: (name: string) => void
|
|
50
|
+
}
|
|
51
|
+
restore: {
|
|
52
|
+
/** The pending confirmation, or null when the dialog is closed. */
|
|
53
|
+
request: VersionRestoreRequest | null
|
|
54
|
+
pending: boolean
|
|
55
|
+
onOpenChange: (open: boolean) => void
|
|
56
|
+
onConfirm: () => void
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Drawer, 保存版本 dialog and 恢复 confirmation, as one piece of chrome. */
|
|
61
|
+
export function VersionChrome({
|
|
62
|
+
open,
|
|
63
|
+
onOpenChange,
|
|
64
|
+
artifactName,
|
|
65
|
+
versionCount,
|
|
66
|
+
headLabel,
|
|
67
|
+
restorableId,
|
|
68
|
+
loading,
|
|
69
|
+
groups,
|
|
70
|
+
actions,
|
|
71
|
+
save,
|
|
72
|
+
restore,
|
|
73
|
+
}: VersionChromeProps): React.ReactElement {
|
|
74
|
+
return (
|
|
75
|
+
<>
|
|
76
|
+
<Drawer open={open} onOpenChange={onOpenChange}>
|
|
77
|
+
<DrawerContent aria-label="版本管理">
|
|
78
|
+
<DrawerHeader>
|
|
79
|
+
<div>
|
|
80
|
+
<DrawerTitle>版本管理</DrawerTitle>
|
|
81
|
+
<DrawerDescription>
|
|
82
|
+
{versionCount === 0
|
|
83
|
+
? `${artifactName} · 还没有版本`
|
|
84
|
+
: `${artifactName} · ${versionCount} 个版本 · 最近保存 ${headLabel ?? ''}`}
|
|
85
|
+
</DrawerDescription>
|
|
86
|
+
</div>
|
|
87
|
+
<Button variant="outline" size="sm" disabled={save.disabled} onClick={() => save.onOpenChange(true)}>
|
|
88
|
+
<Save size={14} aria-hidden="true" />保存版本
|
|
89
|
+
</Button>
|
|
90
|
+
</DrawerHeader>
|
|
91
|
+
<DrawerBody>
|
|
92
|
+
<VersionManager loading={loading} groups={groups} actions={{ ...actions, restorableId }} />
|
|
93
|
+
</DrawerBody>
|
|
94
|
+
</DrawerContent>
|
|
95
|
+
</Drawer>
|
|
96
|
+
<SaveVersionDialog
|
|
97
|
+
open={save.open}
|
|
98
|
+
onOpenChange={save.onOpenChange}
|
|
99
|
+
pending={save.pending}
|
|
100
|
+
onConfirm={save.onConfirm}
|
|
101
|
+
/>
|
|
102
|
+
<RestoreDialog
|
|
103
|
+
open={restore.request !== null}
|
|
104
|
+
onOpenChange={restore.onOpenChange}
|
|
105
|
+
targetLabel={restore.request?.label ?? ''}
|
|
106
|
+
{...(restore.request?.summary === undefined ? {} : { targetSummary: restore.request.summary })}
|
|
107
|
+
{...(restore.request === null ? {} : { mode: restore.request.mode })}
|
|
108
|
+
artifactLabel="工作簿内容"
|
|
109
|
+
pending={restore.pending}
|
|
110
|
+
onConfirm={restore.onConfirm}
|
|
111
|
+
/>
|
|
112
|
+
</>
|
|
113
|
+
)
|
|
114
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The read-only comparison surface, as view models (docs/issue/0022 P5).
|
|
3
|
+
*
|
|
4
|
+
* `records.ts` translates a stored Version into the row the drawer draws; this
|
|
5
|
+
* takes that row — or a fetched diff — and produces the things the *inspect*
|
|
6
|
+
* half needs: the two pickers' options, the canvas overlay, the counts in the
|
|
7
|
+
* bar, and the revision a baseline id addresses. All of it is pure, which is the
|
|
8
|
+
* point: the panel is 1800 lines of ref-mutating effects, and each of these was
|
|
9
|
+
* a `useMemo` body buried in the middle of it.
|
|
10
|
+
*/
|
|
11
|
+
import { versionChangeDirection } from '#contracts'
|
|
12
|
+
import {
|
|
13
|
+
versionOptionLabel,
|
|
14
|
+
versionStepOptionLabel,
|
|
15
|
+
type VersionInspectOption,
|
|
16
|
+
type VersionInspectorSummary,
|
|
17
|
+
type VersionManagerEntry,
|
|
18
|
+
} from '@tita-agent/ui/versions'
|
|
19
|
+
import type { WorkbookChange } from '../../types.ts'
|
|
20
|
+
import type { WorkbookDecoration } from '../univer/loader.ts'
|
|
21
|
+
import { toDecoration } from './preview-decoration.ts'
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* One preview residency (docs/issue/0002 PRD v3.2 §7.2). `step` is part of the
|
|
25
|
+
* canvas's React `key` so replaying a Step of the same Version remounts it;
|
|
26
|
+
* `snapshot` is the content the canvas renders read-only.
|
|
27
|
+
*/
|
|
28
|
+
export interface WorkbookPreviewState {
|
|
29
|
+
versionId: string
|
|
30
|
+
revision: number
|
|
31
|
+
/** Rebuilt content state; the canvas renders exactly this. */
|
|
32
|
+
snapshot: object
|
|
33
|
+
/** Step index when the preview is a Step replay rather than the Version end. */
|
|
34
|
+
step: number | null
|
|
35
|
+
/**
|
|
36
|
+
* What is on screen vs what it is compared against: a Step against the state
|
|
37
|
+
* before it, a Version against the newer one it followed. Drives the canvas
|
|
38
|
+
* overlay so the reader does not have to find the changed cells (v3.3 §7.2).
|
|
39
|
+
*/
|
|
40
|
+
changes: WorkbookChange[]
|
|
41
|
+
/**
|
|
42
|
+
* Which end of the measured range the canvas is showing, so only changes the
|
|
43
|
+
* reader can actually see get tinted.
|
|
44
|
+
*/
|
|
45
|
+
changesSide: 'before' | 'after'
|
|
46
|
+
/** True when the changes could not be rebuilt (compressed history). */
|
|
47
|
+
changesUnavailable?: boolean
|
|
48
|
+
/** True when the diff stopped at the server's limit, so the counts are a floor. */
|
|
49
|
+
changesTruncated?: boolean
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The overlay for a residency: identical to what an in-place swap painted, so a
|
|
54
|
+
* remount and a swap show exactly the same thing.
|
|
55
|
+
*/
|
|
56
|
+
export function previewDecorationOf(preview: WorkbookPreviewState | null): WorkbookDecoration | undefined {
|
|
57
|
+
return preview === null ? undefined : toDecoration(preview.changes, preview.changesSide)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Counts + legend for the bar, derived from the same list the canvas tints.
|
|
62
|
+
*
|
|
63
|
+
* The counts carry the same bucket names the engine paints with, so the legend
|
|
64
|
+
* and the grid are read as one thing; `truncated` is carried through because a
|
|
65
|
+
* capped list would otherwise read as the whole comparison.
|
|
66
|
+
*/
|
|
67
|
+
export function inspectorSummaryOf(preview: WorkbookPreviewState | null): VersionInspectorSummary {
|
|
68
|
+
const summary: VersionInspectorSummary = { total: 0, add: 0, remove: 0, modify: 0, structure: 0, style: 0 }
|
|
69
|
+
if (preview === null) return summary
|
|
70
|
+
summary.total = preview.changes.length
|
|
71
|
+
if (preview.changesUnavailable === true) summary.unavailable = true
|
|
72
|
+
if (preview.changesTruncated === true) summary.truncated = true
|
|
73
|
+
for (const change of preview.changes) {
|
|
74
|
+
summary[versionChangeDirection({
|
|
75
|
+
kind: change.kind,
|
|
76
|
+
target: '',
|
|
77
|
+
description: '',
|
|
78
|
+
...(change.row === undefined ? {} : { row: change.row }),
|
|
79
|
+
...(change.column === undefined ? {} : { column: change.column }),
|
|
80
|
+
...(change.before === undefined ? {} : { before: change.before }),
|
|
81
|
+
...(change.after === undefined ? {} : { after: change.after }),
|
|
82
|
+
...(change.styleOnly === true ? { styleOnly: true } : {}),
|
|
83
|
+
})] += 1
|
|
84
|
+
}
|
|
85
|
+
return summary
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Preview switcher options: every Version the artifact could be swapped onto,
|
|
90
|
+
* newest-first, labelled the way its row was. Built from the timeline so the
|
|
91
|
+
* selector can never offer a Version the list does not show.
|
|
92
|
+
*
|
|
93
|
+
* The Steps give the picker its second level; the shared helper budgets a Step's
|
|
94
|
+
* summary to one menu line.
|
|
95
|
+
*/
|
|
96
|
+
export function inspectOptionsOf(entries: readonly VersionManagerEntry[]): VersionInspectOption[] {
|
|
97
|
+
return entries
|
|
98
|
+
.filter(entry => entry.replayable)
|
|
99
|
+
.map(entry => ({
|
|
100
|
+
id: entry.id,
|
|
101
|
+
label: versionOptionLabel({ summary: entry.summary, ...(entry.timestamp === undefined ? { time: entry.time } : { timestamp: entry.timestamp }) }),
|
|
102
|
+
steps: (entry.steps ?? []).map(step => ({
|
|
103
|
+
index: step.index,
|
|
104
|
+
label: versionStepOptionLabel(step),
|
|
105
|
+
...(step.revision === undefined ? {} : { revision: step.revision }),
|
|
106
|
+
})),
|
|
107
|
+
}))
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Revision a baseline id measures against.
|
|
112
|
+
*
|
|
113
|
+
* A Step is measured at the revision it produced. Falling back to the Version
|
|
114
|
+
* rather than refusing keeps a record written before the field existed usable —
|
|
115
|
+
* it just compares the whole Version.
|
|
116
|
+
*/
|
|
117
|
+
export function baselineRevisionOf(
|
|
118
|
+
entry: VersionManagerEntry | undefined,
|
|
119
|
+
fallbackRevision: number,
|
|
120
|
+
step?: number,
|
|
121
|
+
): number {
|
|
122
|
+
if (entry === undefined) return fallbackRevision
|
|
123
|
+
if (step !== undefined) {
|
|
124
|
+
const found = entry.steps?.find(candidate => candidate.index === step)
|
|
125
|
+
if (found?.revision !== undefined) return found.revision
|
|
126
|
+
}
|
|
127
|
+
return entry.revision ?? fallbackRevision
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** What 「恢复」/「撤销这次改动」 posts, once the confirmation dialog is answered. */
|
|
131
|
+
export interface VersionRestoreRequest {
|
|
132
|
+
revision: number
|
|
133
|
+
/** Render-time label, for the dialog and the notice. */
|
|
134
|
+
label: string
|
|
135
|
+
/** Durable summary written into the new Version's record. */
|
|
136
|
+
summary: string
|
|
137
|
+
mode: 'restore' | 'undo'
|
|
138
|
+
}
|