@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.
Files changed (267) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +172 -2
  3. package/cordis.patch.yml +7 -0
  4. package/lib/client.js +16766 -0
  5. package/lib/contract-envelope.d.ts +91 -0
  6. package/lib/contract-envelope.js +106 -0
  7. package/lib/contract-layout.d.ts +130 -0
  8. package/lib/contract-layout.js +138 -0
  9. package/lib/contract-refs.d.ts +39 -0
  10. package/lib/contract-refs.js +9 -0
  11. package/lib/contract-version.d.ts +311 -0
  12. package/lib/contract-version.js +270 -0
  13. package/lib/contract-wire.d.ts +147 -0
  14. package/lib/contract-wire.js +99 -0
  15. package/lib/contracts.d.ts +12 -0
  16. package/lib/contracts.js +12 -0
  17. package/lib/types/audit.d.ts +42 -0
  18. package/lib/types/audit.js +39 -0
  19. package/lib/types/client/ProjectImportMenu.d.ts +30 -0
  20. package/lib/types/client/ProjectImportMenu.js +70 -0
  21. package/lib/types/client/SheetPanel.d.ts +33 -0
  22. package/lib/types/client/SheetPanel.js +1766 -0
  23. package/lib/types/client/SheetToggle.d.ts +18 -0
  24. package/lib/types/client/SheetToggle.js +26 -0
  25. package/lib/types/client/index.d.ts +15 -0
  26. package/lib/types/client/index.js +110 -0
  27. package/lib/types/client/persistence/changes.d.ts +15 -0
  28. package/lib/types/client/persistence/changes.js +51 -0
  29. package/lib/types/client/persistence/ids.d.ts +34 -0
  30. package/lib/types/client/persistence/ids.js +48 -0
  31. package/lib/types/client/persistence/merge.d.ts +35 -0
  32. package/lib/types/client/persistence/merge.js +362 -0
  33. package/lib/types/client/store.d.ts +61 -0
  34. package/lib/types/client/store.js +152 -0
  35. package/lib/types/client/surface-context.d.ts +27 -0
  36. package/lib/types/client/surface-context.js +104 -0
  37. package/lib/types/client/surface-control.d.ts +2 -0
  38. package/lib/types/client/surface-control.js +12 -0
  39. package/lib/types/client/transport/workbookApi.d.ts +159 -0
  40. package/lib/types/client/transport/workbookApi.js +246 -0
  41. package/lib/types/client/univer/StandaloneWorkbookPage.d.ts +5 -0
  42. package/lib/types/client/univer/StandaloneWorkbookPage.js +7 -0
  43. package/lib/types/client/univer/WorkbookCanvas.d.ts +40 -0
  44. package/lib/types/client/univer/WorkbookCanvas.js +87 -0
  45. package/lib/types/client/univer/WorkbookView.d.ts +3 -0
  46. package/lib/types/client/univer/WorkbookView.js +2 -0
  47. package/lib/types/client/univer/loader.d.ts +18 -0
  48. package/lib/types/client/univer/loader.js +81 -0
  49. package/lib/types/client/univer/standalone-entry.d.ts +1 -0
  50. package/lib/types/client/univer/standalone-entry.js +19 -0
  51. package/lib/types/client/versions/VersionChrome.d.ts +33 -0
  52. package/lib/types/client/versions/VersionChrome.js +21 -0
  53. package/lib/types/client/versions/inspect.d.ts +70 -0
  54. package/lib/types/client/versions/inspect.js +88 -0
  55. package/lib/types/client/versions/preview-decoration.d.ts +11 -0
  56. package/lib/types/client/versions/preview-decoration.js +54 -0
  57. package/lib/types/client/versions/records.d.ts +19 -0
  58. package/lib/types/client/versions/records.js +70 -0
  59. package/lib/types/client/workspace-host.d.ts +61 -0
  60. package/lib/types/client/workspace-host.js +124 -0
  61. package/lib/types/collaboration-hub.d.ts +31 -0
  62. package/lib/types/collaboration-hub.js +69 -0
  63. package/lib/types/contract/ids.d.ts +24 -0
  64. package/lib/types/contract/ids.js +46 -0
  65. package/lib/types/contract/mutations.d.ts +25 -0
  66. package/lib/types/contract/mutations.js +782 -0
  67. package/lib/types/contract/operations.d.ts +54 -0
  68. package/lib/types/contract/operations.js +203 -0
  69. package/lib/types/contract/snapshots.d.ts +176 -0
  70. package/lib/types/contract/snapshots.js +351 -0
  71. package/lib/types/contract/univer-api-catalog.d.ts +29 -0
  72. package/lib/types/contract/univer-api-catalog.js +264 -0
  73. package/lib/types/errors.d.ts +8 -0
  74. package/lib/types/errors.js +12 -0
  75. package/lib/types/http/assets-routes.d.ts +3 -0
  76. package/lib/types/http/assets-routes.js +169 -0
  77. package/lib/types/http/collaboration.d.ts +10 -0
  78. package/lib/types/http/collaboration.js +154 -0
  79. package/lib/types/http/history.d.ts +15 -0
  80. package/lib/types/http/history.js +134 -0
  81. package/lib/types/http/project-files.d.ts +79 -0
  82. package/lib/types/http/project-files.js +206 -0
  83. package/lib/types/http/project-scope.d.ts +50 -0
  84. package/lib/types/http/project-scope.js +52 -0
  85. package/lib/types/http/routes.d.ts +98 -0
  86. package/lib/types/http/routes.js +323 -0
  87. package/lib/types/http/standalone.d.ts +9 -0
  88. package/lib/types/http/standalone.js +31 -0
  89. package/lib/types/http/trunk.d.ts +10 -0
  90. package/lib/types/http/trunk.js +322 -0
  91. package/lib/types/http/worktree.d.ts +9 -0
  92. package/lib/types/http/worktree.js +145 -0
  93. package/lib/types/index.d.ts +18 -0
  94. package/lib/types/index.js +156 -0
  95. package/lib/types/invariant.d.ts +15 -0
  96. package/lib/types/invariant.js +15 -0
  97. package/lib/types/request-params.d.ts +21 -0
  98. package/lib/types/request-params.js +76 -0
  99. package/lib/types/store/paths.d.ts +68 -0
  100. package/lib/types/store/paths.js +148 -0
  101. package/lib/types/store/project.d.ts +88 -0
  102. package/lib/types/store/project.js +120 -0
  103. package/lib/types/store/read.d.ts +110 -0
  104. package/lib/types/store/read.js +404 -0
  105. package/lib/types/store/retention.d.ts +27 -0
  106. package/lib/types/store/retention.js +111 -0
  107. package/lib/types/store/write.d.ts +22 -0
  108. package/lib/types/store/write.js +210 -0
  109. package/lib/types/tools/arguments.d.ts +40 -0
  110. package/lib/types/tools/arguments.js +130 -0
  111. package/lib/types/tools/cells.d.ts +50 -0
  112. package/lib/types/tools/cells.js +298 -0
  113. package/lib/types/tools/index.d.ts +2 -0
  114. package/lib/types/tools/index.js +250 -0
  115. package/lib/types/tools/render.d.ts +47 -0
  116. package/lib/types/tools/render.js +290 -0
  117. package/lib/types/tools/univer-api.d.ts +18 -0
  118. package/lib/types/tools/univer-api.js +198 -0
  119. package/lib/types/tools/workbook-catalog.d.ts +3 -0
  120. package/lib/types/tools/workbook-catalog.js +83 -0
  121. package/lib/types/tools/workbook-edit.d.ts +192 -0
  122. package/lib/types/tools/workbook-edit.js +912 -0
  123. package/lib/types/tools/workbook-find.d.ts +11 -0
  124. package/lib/types/tools/workbook-find.js +89 -0
  125. package/lib/types/tools/workbook-history.d.ts +2 -0
  126. package/lib/types/tools/workbook-history.js +59 -0
  127. package/lib/types/tools/workbook-read.d.ts +21 -0
  128. package/lib/types/tools/workbook-read.js +204 -0
  129. package/lib/types/types.d.ts +377 -0
  130. package/lib/types/types.js +34 -0
  131. package/lib/types/univer/apply-operation.d.ts +14 -0
  132. package/lib/types/univer/apply-operation.js +398 -0
  133. package/lib/types/univer/chunk.d.ts +68 -0
  134. package/lib/types/univer/chunk.js +16 -0
  135. package/lib/types/univer/decoration.d.ts +34 -0
  136. package/lib/types/univer/decoration.js +88 -0
  137. package/lib/types/univer/diagnostics.d.ts +31 -0
  138. package/lib/types/univer/diagnostics.js +141 -0
  139. package/lib/types/univer/engine.d.ts +33 -0
  140. package/lib/types/univer/engine.js +338 -0
  141. package/lib/types/univer/entry.d.ts +8 -0
  142. package/lib/types/univer/entry.js +11 -0
  143. package/lib/types/univer/facade.d.ts +107 -0
  144. package/lib/types/univer/facade.js +1 -0
  145. package/lib/types/univer/fonts.d.ts +202 -0
  146. package/lib/types/univer/fonts.js +140 -0
  147. package/lib/types/univer/plugins/collaboration.d.ts +23 -0
  148. package/lib/types/univer/plugins/collaboration.js +47 -0
  149. package/lib/types/univer/plugins/export.d.ts +39 -0
  150. package/lib/types/univer/plugins/export.js +246 -0
  151. package/lib/types/univer/plugins/history.d.ts +24 -0
  152. package/lib/types/univer/plugins/history.js +50 -0
  153. package/lib/types/univer/plugins/version.d.ts +13 -0
  154. package/lib/types/univer/plugins/version.js +13 -0
  155. package/lib/types/version/diff.d.ts +36 -0
  156. package/lib/types/version/diff.js +156 -0
  157. package/lib/types/version/grouping.d.ts +7 -0
  158. package/lib/types/version/grouping.js +94 -0
  159. package/lib/types/version/records.d.ts +17 -0
  160. package/lib/types/version/records.js +102 -0
  161. package/lib/types/version/session.d.ts +36 -0
  162. package/lib/types/version/session.js +89 -0
  163. package/lib/types/version/summary.d.ts +24 -0
  164. package/lib/types/version/summary.js +111 -0
  165. package/lib/types/workbook-manager.d.ts +191 -0
  166. package/lib/types/workbook-manager.js +935 -0
  167. package/lib/types/xlsx-export-worker.d.ts +5 -0
  168. package/lib/types/xlsx-export-worker.js +24 -0
  169. package/lib/types/xlsx-export.d.ts +21 -0
  170. package/lib/types/xlsx-export.js +371 -0
  171. package/lib/types/xlsx-import-worker.d.ts +1 -0
  172. package/lib/types/xlsx-import-worker.js +19 -0
  173. package/lib/univer-client.js +690 -0
  174. package/lib/workbook-page.js +23826 -0
  175. package/lib/xlsx-export-worker.js +104 -0
  176. package/lib/xlsx-import-worker.js +46 -0
  177. package/package.json +106 -3
  178. package/src/audit.ts +58 -0
  179. package/src/client/ProjectImportMenu.tsx +100 -0
  180. package/src/client/SheetPanel.module.css +1578 -0
  181. package/src/client/SheetPanel.tsx +1934 -0
  182. package/src/client/SheetToggle.module.css +73 -0
  183. package/src/client/SheetToggle.tsx +65 -0
  184. package/src/client/contract.d.ts +19 -0
  185. package/src/client/index.ts +131 -0
  186. package/src/client/persistence/changes.ts +58 -0
  187. package/src/client/persistence/ids.ts +60 -0
  188. package/src/client/persistence/merge.ts +392 -0
  189. package/src/client/store.ts +188 -0
  190. package/src/client/surface-context.ts +123 -0
  191. package/src/client/surface-control.ts +13 -0
  192. package/src/client/transport/workbookApi.ts +355 -0
  193. package/src/client/univer/SheetView.module.css +110 -0
  194. package/src/client/univer/StandaloneWorkbookPage.module.css +8 -0
  195. package/src/client/univer/StandaloneWorkbookPage.tsx +15 -0
  196. package/src/client/univer/WorkbookCanvas.tsx +128 -0
  197. package/src/client/univer/WorkbookView.module.css +30 -0
  198. package/src/client/univer/WorkbookView.tsx +3 -0
  199. package/src/client/univer/loader.ts +90 -0
  200. package/src/client/univer/react-dom-client.d.ts +10 -0
  201. package/src/client/univer/standalone-entry.tsx +19 -0
  202. package/src/client/univer/standalone.css +12 -0
  203. package/src/client/univer/univer-locales.d.ts +89 -0
  204. package/src/client/univer/univer-modules.d.ts +26 -0
  205. package/src/client/versions/VersionChrome.tsx +114 -0
  206. package/src/client/versions/inspect.ts +138 -0
  207. package/src/client/versions/preview-decoration.ts +54 -0
  208. package/src/client/versions/records.ts +78 -0
  209. package/src/client/workspace-host.ts +147 -0
  210. package/src/collaboration-hub.ts +83 -0
  211. package/src/contract/ids.ts +50 -0
  212. package/src/contract/mutations.ts +791 -0
  213. package/src/contract/operations.ts +221 -0
  214. package/src/contract/snapshots.ts +383 -0
  215. package/src/contract/univer-api-catalog.ts +289 -0
  216. package/src/css-modules.d.ts +6 -0
  217. package/src/errors.ts +25 -0
  218. package/src/http/assets-routes.ts +177 -0
  219. package/src/http/collaboration.ts +144 -0
  220. package/src/http/history.ts +151 -0
  221. package/src/http/project-files.ts +227 -0
  222. package/src/http/project-scope.ts +77 -0
  223. package/src/http/routes.ts +364 -0
  224. package/src/http/standalone.ts +32 -0
  225. package/src/http/trunk.ts +322 -0
  226. package/src/http/worktree.ts +119 -0
  227. package/src/index.ts +165 -0
  228. package/src/invariant.ts +17 -0
  229. package/src/request-params.ts +92 -0
  230. package/src/store/paths.ts +165 -0
  231. package/src/store/project.ts +137 -0
  232. package/src/store/read.ts +454 -0
  233. package/src/store/retention.ts +106 -0
  234. package/src/store/write.ts +230 -0
  235. package/src/tools/arguments.ts +128 -0
  236. package/src/tools/cells.ts +298 -0
  237. package/src/tools/index.ts +274 -0
  238. package/src/tools/render.ts +301 -0
  239. package/src/tools/univer-api.ts +243 -0
  240. package/src/tools/workbook-catalog.ts +94 -0
  241. package/src/tools/workbook-edit.ts +987 -0
  242. package/src/tools/workbook-find.ts +80 -0
  243. package/src/tools/workbook-history.ts +63 -0
  244. package/src/tools/workbook-read.ts +210 -0
  245. package/src/types.ts +432 -0
  246. package/src/univer/apply-operation.ts +369 -0
  247. package/src/univer/chunk.ts +77 -0
  248. package/src/univer/decoration.ts +111 -0
  249. package/src/univer/diagnostics.ts +136 -0
  250. package/src/univer/engine.ts +370 -0
  251. package/src/univer/entry.ts +14 -0
  252. package/src/univer/facade.ts +91 -0
  253. package/src/univer/fonts.ts +148 -0
  254. package/src/univer/overrides.css +33 -0
  255. package/src/univer/plugins/collaboration.ts +47 -0
  256. package/src/univer/plugins/export.ts +236 -0
  257. package/src/univer/plugins/history.ts +49 -0
  258. package/src/univer/plugins/version.ts +13 -0
  259. package/src/version/diff.ts +169 -0
  260. package/src/version/grouping.ts +96 -0
  261. package/src/version/records.ts +113 -0
  262. package/src/version/session.ts +90 -0
  263. package/src/version/summary.ts +117 -0
  264. package/src/workbook-manager.ts +1111 -0
  265. package/src/xlsx-export-worker.ts +34 -0
  266. package/src/xlsx-export.ts +373 -0
  267. package/src/xlsx-import-worker.ts +30 -0
@@ -0,0 +1,73 @@
1
+ .toggle {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ justify-content: center;
5
+ gap: 7px;
6
+ min-width: 96px;
7
+ height: 32px;
8
+ padding: 0 9px;
9
+ border: 1px solid var(--dsw-alias-border-l2);
10
+ border-radius: 6px;
11
+ color: var(--dsw-alias-label-primary);
12
+ background: transparent;
13
+ font-family: var(--dsw-font-family);
14
+ font-size: 12px;
15
+ font-weight: 600;
16
+ line-height: 20px;
17
+ cursor: pointer;
18
+ transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
19
+ }
20
+
21
+ .toggle:hover {
22
+ background: color-mix(in srgb, var(--dsw-alias-state-business-primary) 6%, transparent);
23
+ border-color: color-mix(in srgb, var(--dsw-alias-state-business-primary) 38%, var(--dsw-alias-border-l2));
24
+ }
25
+
26
+ .toggle:focus-visible {
27
+ outline: none;
28
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-business-primary) 18%, transparent);
29
+ }
30
+
31
+ .toggle[data-open='true'] {
32
+ border-color: color-mix(in srgb, var(--dsw-alias-state-business-primary) 38%, var(--dsw-alias-border-l2));
33
+ color: var(--dsw-alias-state-business-primary);
34
+ background: color-mix(in srgb, var(--dsw-alias-state-business-primary) 10%, transparent);
35
+ }
36
+
37
+ .toggle[data-open='true']:hover {
38
+ background: color-mix(in srgb, var(--dsw-alias-state-business-primary) 16%, transparent);
39
+ }
40
+
41
+ .icon,
42
+ .label {
43
+ flex: none;
44
+ }
45
+
46
+ .icon {
47
+ display: grid;
48
+ width: 18px;
49
+ height: 18px;
50
+ place-items: center;
51
+ color: var(--dsw-alias-state-business-primary);
52
+ }
53
+
54
+ .icon svg {
55
+ display: block;
56
+ width: 15px;
57
+ height: 15px;
58
+ }
59
+
60
+ .label {
61
+ white-space: nowrap;
62
+ }
63
+
64
+ @media (max-width: 640px) {
65
+ .toggle {
66
+ min-width: 32px;
67
+ padding: 0 8px;
68
+ }
69
+
70
+ .label {
71
+ display: none;
72
+ }
73
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Session-header toggle for dsh-data-table: the top-right entry
3
+ * button flipping the right sheet column (AppFrame `details`).
4
+ * @module dsh-data-table/client/SheetToggle
5
+ */
6
+
7
+ import { useEffect } from 'react'
8
+ import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
9
+ import { useSheetOpen } from './store.ts'
10
+ import styles from './SheetToggle.module.css'
11
+
12
+ type ToggleProps = PropsRuntime<'conversation.session.header.utilities'> & {
13
+ /** Bound toggle action (registration inject). */
14
+ toggleSheet: () => void
15
+ /** Reopens the layout column after a session switch when the feature was open. */
16
+ ensureSheetOpen: () => void
17
+ }
18
+
19
+ /** Small spreadsheet glyph: a header row plus a quiet 2×3 cell grid. */
20
+ function SheetIcon() {
21
+ return (
22
+ <svg
23
+ width="14"
24
+ height="14"
25
+ viewBox="0 0 16 16"
26
+ fill="none"
27
+ xmlns="http://www.w3.org/2000/svg"
28
+ focusable="false"
29
+ >
30
+ <rect x="1.75" y="2.25" width="12.5" height="11.5" rx="2" stroke="currentColor" strokeWidth="1.25" />
31
+ <path d="M2.25 5.75H13.75" stroke="currentColor" strokeWidth="1.25" />
32
+ <path d="M5.75 5.75V13.25M10.25 5.75V13.25" stroke="currentColor" strokeWidth="1.1" />
33
+ <path d="M3.5 3.65H12" stroke="currentColor" strokeWidth="1.1" strokeLinecap="round" opacity="0.55" />
34
+ </svg>
35
+ )
36
+ }
37
+
38
+ /**
39
+ * Header utility button: opens/closes the sheet column (top-right corner).
40
+ * @param props - standard session header utility share.
41
+ */
42
+ export function SheetToggle({ toggleSheet, ensureSheetOpen }: ToggleProps) {
43
+ const open = useSheetOpen()
44
+ const label = open ? '关闭 Table' : '打开 Table'
45
+ useEffect(() => {
46
+ if (open) ensureSheetOpen()
47
+ }, [open, ensureSheetOpen])
48
+
49
+ return (
50
+ <button
51
+ type="button"
52
+ className={styles.toggle}
53
+ data-open={open}
54
+ aria-label={label}
55
+ aria-pressed={open}
56
+ title={label}
57
+ onClick={toggleSheet}
58
+ >
59
+ <span className={styles.icon} aria-hidden="true">
60
+ <SheetIcon />
61
+ </span>
62
+ <span className={styles.label}>{open ? '关闭' : 'Table'}</span>
63
+ </button>
64
+ )
65
+ }
@@ -0,0 +1,19 @@
1
+ export {}
2
+
3
+ /**
4
+ * Local slot contract for dsh-data-table.
5
+ *
6
+ * The published DSH client packages ship `lib/` only, so the SlotMap merges
7
+ * declared by ui-layout (`details` — AppFrame's right grid column) is not
8
+ * visible to this standalone compilation. The details slot is re-declared
9
+ * here with a structurally
10
+ * compatible owner type (the runtime passes exactly these owner fields).
11
+ * @module dsh-data-table/client/contract
12
+ */
13
+
14
+ declare module '@deepseek-ai/dsh-client-ui-slots' {
15
+ interface SlotMap {
16
+ /** AppFrame's right grid column (declared by ui-layout); hosts the sheet. */
17
+ 'details': { kind: 'single'; scope: 'session' }
18
+ }
19
+ }
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Browser half of dsh-data-table.
3
+ *
4
+ * The workbook is a first-class extension of DSH's official right Sidebar:
5
+ * the tab type is registered in `sidebarRightTabs`, while the body is mounted
6
+ * through the keyed `sidebar.right.pane.tab` seat. Keeping those two steps
7
+ * separate means the plugin never reaches into the Sidebar's layout store and
8
+ * can be published to the upstream datastudio/dsh extension surface.
9
+ * @module dsh-data-table/client
10
+ */
11
+
12
+ import type { Context as ClientContext } from '@deepseek-ai/cordis'
13
+ import type { SurfaceBridgeService } from '@tita-agent/dsh-surface-bridge'
14
+ import { startSurfaceOperationLoop } from '@tita-agent/dsh-surface-bridge/client/loop'
15
+ import type {} from '@deepseek-ai/dsh-client-ui-conversation/client'
16
+ import type {} from '@deepseek-ai/dsh-client-ui-layout/client'
17
+ import type { InjectFace, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
18
+ import type { SidebarRightTabDefinition } from '@deepseek-ai/dsh-client-ui-sidebar-right/client'
19
+ import type {} from '@deepseek-ai/dsh-client-ui-sidebar-right/client'
20
+ import type {} from '@deepseek-ai/dsh-client-ui-renderer/client'
21
+ import { Table2 } from '@tita-agent/ui/icons'
22
+ import { createElement, useEffect, useLayoutEffect, useRef, type ReactNode } from 'react'
23
+ import { createRoot } from 'react-dom/client'
24
+ import { WorkbookWorkspace } from './SheetPanel.tsx'
25
+ import { setSheetVisible, useSheetVisible } from './store.ts'
26
+ import { adoptWorkspaceHost, parkWorkspaceHost } from './workspace-host.ts'
27
+ import { setDshSessionId } from './transport/workbookApi.ts'
28
+ import { DATA_SHEET_SURFACE_ID } from './surface-context.ts'
29
+ import { focusDataSheetItem } from './surface-control.ts'
30
+ import styles from './SheetPanel.module.css'
31
+
32
+ /** This package's identity in the official right-Sidebar registry. */
33
+ const DATA_SHEET_ID = 'dsh-data-table'
34
+ const DATA_SHEET_KIND = 'data-sheet'
35
+
36
+ /** Stage one: describe the page type and its entry in the official guide. */
37
+ function dataSheetDefinition(): SidebarRightTabDefinition {
38
+ return {
39
+ id: DATA_SHEET_ID,
40
+ kind: DATA_SHEET_KIND,
41
+ priority: 'extension',
42
+ title: () => 'Table',
43
+ guide: [{ id: `${DATA_SHEET_ID}-guide`, order: 45, title: () => 'Table', icon: Table2 }],
44
+ }
45
+ }
46
+
47
+ /**
48
+ * The resident workspace: one React tree for the whole page life.
49
+ *
50
+ * `open` is true because the workspace stays live while parked off-screen;
51
+ * `visible` carries the pane's real visibility to the few behaviours that must
52
+ * be tied to it (the window-level save shortcut).
53
+ */
54
+ function ResidentWorkspace({ bridge }: { readonly bridge: SurfaceBridgeService }): ReactNode {
55
+ const visible = useSheetVisible()
56
+ return createElement(WorkbookWorkspace, { open: true, visible, bridge })
57
+ }
58
+
59
+ /**
60
+ * Create the workspace root; called once per workspace lifetime.
61
+ * @returns the disposer that releases the React tree again.
62
+ */
63
+ function mountResidentWorkspace(container: HTMLElement, bridge: SurfaceBridgeService): () => void {
64
+ const root = createRoot(container)
65
+ root.render(createElement(ResidentWorkspace, { bridge }))
66
+ return () => { root.unmount() }
67
+ }
68
+
69
+ /**
70
+ * Stage two: render the workbook for the active right-Sidebar tab.
71
+ *
72
+ * The pane body is only a frame: the dock unmounts it whenever another tab
73
+ * becomes active, so the workspace itself is adopted from a resident container
74
+ * instead of being rendered here. That is what stops a tab switch from
75
+ * disposing the Univer engine and reloading the workbook.
76
+ */
77
+ function DataSheetTab({ sessionId, useTabInfo, bridge }: PropsRuntime<'sidebar.right.pane.tab'> & InjectFace<{ readonly bridge: SurfaceBridgeService }>): ReactNode {
78
+ const { tab } = useTabInfo()
79
+ const frameRef = useRef<HTMLDivElement | null>(null)
80
+
81
+ // Bind the transport to this Session's project for as long as the tab exists:
82
+ // every workbook read and write resolves to `<project>/storages/data-table`.
83
+ useEffect(() => {
84
+ setDshSessionId(sessionId)
85
+ return () => { setDshSessionId(undefined) }
86
+ }, [sessionId])
87
+
88
+ // Layout effect: its cleanup runs while the pane DOM is still connected, so
89
+ // the workspace can be moved out before the browser reports a 0x0 resize.
90
+ useLayoutEffect(() => {
91
+ const frame = frameRef.current
92
+ if (frame === null) return
93
+ adoptWorkspaceHost(frame, container => mountResidentWorkspace(container, bridge))
94
+ return () => { parkWorkspaceHost() }
95
+ }, [bridge])
96
+
97
+ useEffect(() => {
98
+ setSheetVisible(tab.visible)
99
+ bridge.setVisible(DATA_SHEET_SURFACE_ID, tab.visible)
100
+ if (!tab.visible) return
101
+ const stop = startSurfaceOperationLoop(sessionId, DATA_SHEET_SURFACE_ID, bridge)
102
+ return () => {
103
+ stop()
104
+ bridge.setVisible(DATA_SHEET_SURFACE_ID, false)
105
+ setSheetVisible(false)
106
+ }
107
+ }, [bridge, sessionId, tab.visible])
108
+
109
+ return createElement('div', { ref: frameRef, className: styles.sidebarTab, 'data-data-table-frame': '' })
110
+ }
111
+
112
+ /** Required services for the official two-stage Sidebar extension path. */
113
+ export const inject = ['slots', 'sidebarRightTabs', 'sidebarRight', 'surfaceBridge'] as const
114
+
115
+ /** Register the type and its keyed body; both registrations are disposable. */
116
+ export function apply(ctx: ClientContext): void {
117
+ const bridge = ctx.surfaceBridge
118
+ ctx.effect(() => ctx.sidebarRightTabs.register(dataSheetDefinition()), 'data-sheet: right Sidebar type')
119
+ ctx.effect(() => bridge.registerContext({
120
+ id: DATA_SHEET_SURFACE_ID,
121
+ label: 'Table',
122
+ icon: Table2,
123
+ order: 20,
124
+ reveal: () => { ctx.sidebarRight.openTab(DATA_SHEET_KIND) },
125
+ focusItem: focusDataSheetItem,
126
+ }), 'data-sheet: composer context source')
127
+ ctx.effect(() => ctx.slots.inject('sidebar.right.pane.tab', () => ctx.slots.register(
128
+ { name: 'sidebar.right.pane.tab', key: DATA_SHEET_ID, inject: () => ({ bridge }) },
129
+ DataSheetTab,
130
+ )), 'data-sheet: right Sidebar body')
131
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Deciding what may be applied from elsewhere (docs/issue/0022 P5).
3
+ *
4
+ * A remote operation arriving while the user has unsaved local edits is the one
5
+ * genuinely concurrent case in this plugin: either the operation touches
6
+ * different cells and can be applied on top, or it overlaps and the pane has to
7
+ * fall back to a snapshot reload. These are the predicates that decide.
8
+ */
9
+ import type { WorkbookCellUpdate, WorkbookLocalChange, WorkbookOperation } from '../../types.ts'
10
+
11
+ /** Return cell coordinates for the subset that can be safely rebased live. */
12
+ export function operationCellKeys(operation: WorkbookOperation, target = new Set<string>()): Set<string> | null {
13
+ if (operation.type === 'update_cells') {
14
+ const sheetId = operation.payload.sheetId ?? operation.payload.sheetName
15
+ if (sheetId === undefined || operation.payload.cells === undefined || operation.payload.cells.length === 0) return null
16
+ for (const cell of operation.payload.cells) target.add(`${sheetId}:${cell.row}:${cell.column}`)
17
+ return target
18
+ }
19
+ if (operation.type === 'batch') {
20
+ const children = operation.payload.operations ?? []
21
+ if (children.length === 0) return null
22
+ for (const child of children) {
23
+ const childKeys = operationCellKeys({ ...operation, type: child.type, payload: child.payload }, target)
24
+ if (childKeys === null) return null
25
+ }
26
+ return target
27
+ }
28
+ return null
29
+ }
30
+
31
+ export function canApplyRemoteWhileEditing(operation: WorkbookOperation, snapshotFallback: boolean): boolean {
32
+ // The Host already serializes cell operations and applies the later
33
+ // revision to the latest snapshot. Keep all cell-only operations visible in
34
+ // the canvas; the pending local changes are replayed immediately after the
35
+ // remote projection and are then submitted as the later revision — which is
36
+ // why this needs no view of them. It used to take them and `void` them.
37
+ if (snapshotFallback) return false
38
+ return operationCellKeys(operation) !== null
39
+ }
40
+
41
+ export function coalesceLocalChanges(changes: WorkbookLocalChange[]): WorkbookLocalChange[] {
42
+ const sheets = new Map<string, Map<string, WorkbookCellUpdate>>()
43
+ for (const change of changes) {
44
+ const cells = sheets.get(change.payload.sheetId) ?? new Map<string, WorkbookCellUpdate>()
45
+ for (const cell of change.payload.cells) cells.set(`${cell.row}:${cell.column}`, cell)
46
+ sheets.set(change.payload.sheetId, cells)
47
+ }
48
+ return [...sheets.entries()].map(([sheetId, cells]) => ({
49
+ type: 'update_cells',
50
+ payload: { sheetId, cells: [...cells.values()] },
51
+ }))
52
+ }
53
+
54
+ /** Keep the Univer snapshot name aligned with the Datasheet workbook name. */
55
+ export function withWorkbookName(snapshot: object, name: string): object {
56
+ const root = snapshot as Record<string, unknown>
57
+ return { ...root, name: name.trim() || root.name || 'workbook' }
58
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Ids the browser mints for its own writes (docs/issue/0022 P5).
3
+ *
4
+ * An opId makes a retried save idempotent and a versionId keeps one editing
5
+ * session together across requests; both are the client's to name because the
6
+ * Host cannot tell a retry from a new edit.
7
+ */
8
+ export function nextUserOpId(workbookId: string): string {
9
+ const suffix = typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function' ? crypto.randomUUID() : `${Date.now()}-${Math.random().toString(36).slice(2)}`
10
+ return `user:${workbookId}:${suffix}`
11
+ }
12
+
13
+ export function nextUserVersionId(workbookId: string): string {
14
+ const suffix = typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function' ? crypto.randomUUID() : `${Date.now()}-${Math.random().toString(36).slice(2)}`
15
+ return `user-version:${workbookId}:${suffix}`
16
+ }
17
+
18
+ /** How many unclaimed op ids one page remembers before the oldest is dropped. */
19
+ const OWN_OP_LIMIT = 64
20
+
21
+ export interface OwnOpLog {
22
+ /** Mint the op id for a write this browser is about to make, and remember it. */
23
+ next: (workbookId: string) => string
24
+ /**
25
+ * Claim an op id that came back. True when this browser minted it — i.e. the
26
+ * operation is this client's own write being echoed, not a peer's edit.
27
+ */
28
+ take: (opId: string) => boolean
29
+ }
30
+
31
+ /**
32
+ * The op ids this browser has sent and not yet seen come back (GUI feedback
33
+ * 2026-09-20).
34
+ *
35
+ * The collaboration stream echoes a write to **every** client on the workbook,
36
+ * the one that made it included, and the echo can arrive before the POST's own
37
+ * response — the Host publishes as soon as it has written. Without this log the
38
+ * Table panel read its own `snapshot_replace` as a foreign one and answered it
39
+ * the only way that operation can be answered, by re-downloading the snapshot
40
+ * and remounting the canvas: 「保存版本」 flashed the grid on every save, even
41
+ * though the canvas was already showing exactly the revision just stored.
42
+ *
43
+ * Bounded, because a save whose answer never comes back — a dropped connection —
44
+ * must not grow this for the life of the page.
45
+ */
46
+ export function createOwnOpLog(limit = OWN_OP_LIMIT): OwnOpLog {
47
+ const ids = new Set<string>()
48
+ return {
49
+ next: (workbookId: string): string => {
50
+ const opId = nextUserOpId(workbookId)
51
+ ids.add(opId)
52
+ if (ids.size > limit) {
53
+ const oldest = ids.values().next().value
54
+ if (oldest !== undefined) ids.delete(oldest)
55
+ }
56
+ return opId
57
+ },
58
+ take: (opId: string): boolean => ids.delete(opId),
59
+ }
60
+ }