@dxos/plugin-kanban 0.8.4-main.fcfe5033a5 → 0.8.4-staging.60fe92afc8

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 (256) hide show
  1. package/LICENSE +102 -5
  2. package/PLUGIN.mdl +398 -0
  3. package/README.md +1 -1
  4. package/dist/lib/neutral/KanbanArticle-T4CPKAZH.mjs +132 -0
  5. package/dist/lib/neutral/KanbanArticle-T4CPKAZH.mjs.map +7 -0
  6. package/dist/lib/neutral/KanbanPlugin.mjs +44 -0
  7. package/dist/lib/neutral/KanbanPlugin.mjs.map +7 -0
  8. package/dist/lib/neutral/KanbanPlugin.node.mjs +27 -0
  9. package/dist/lib/neutral/KanbanPlugin.node.mjs.map +7 -0
  10. package/dist/lib/neutral/KanbanPlugin.workerd.mjs +21 -0
  11. package/dist/lib/neutral/KanbanPlugin.workerd.mjs.map +7 -0
  12. package/dist/lib/neutral/KanbanSettings-5WOS4CUE.mjs +83 -0
  13. package/dist/lib/neutral/KanbanSettings-5WOS4CUE.mjs.map +7 -0
  14. package/dist/lib/neutral/blueprint-definition-6DV3Q5MC.mjs +15 -0
  15. package/dist/lib/neutral/blueprint-definition-6DV3Q5MC.mjs.map +7 -0
  16. package/dist/lib/neutral/blueprints/index.mjs +8 -0
  17. package/dist/lib/neutral/capabilities/index.mjs +17 -0
  18. package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
  19. package/dist/lib/neutral/chunk-6ZHHQWO5.mjs +39 -0
  20. package/dist/lib/neutral/chunk-6ZHHQWO5.mjs.map +7 -0
  21. package/dist/lib/neutral/chunk-DAKIZO46.mjs +246 -0
  22. package/dist/lib/neutral/chunk-DAKIZO46.mjs.map +7 -0
  23. package/dist/lib/neutral/chunk-M5ISZWZU.mjs +8 -0
  24. package/dist/lib/neutral/chunk-M5ISZWZU.mjs.map +7 -0
  25. package/dist/lib/{browser/blueprints/index.mjs → neutral/chunk-ZTQW5KQS.mjs} +4 -5
  26. package/dist/lib/neutral/chunk-ZTQW5KQS.mjs.map +7 -0
  27. package/dist/lib/neutral/components/index.mjs +243 -0
  28. package/dist/lib/neutral/components/index.mjs.map +7 -0
  29. package/dist/lib/neutral/containers/index.mjs +11 -0
  30. package/dist/lib/neutral/containers/index.mjs.map +7 -0
  31. package/dist/lib/neutral/create-object-DKBSI46K.mjs +40 -0
  32. package/dist/lib/neutral/create-object-DKBSI46K.mjs.map +7 -0
  33. package/dist/lib/{browser/delete-card-VPNVIWOA.mjs → neutral/delete-card-VNAV3CZV.mjs} +6 -14
  34. package/dist/lib/neutral/delete-card-VNAV3CZV.mjs.map +7 -0
  35. package/dist/lib/neutral/delete-card-field-XHOLGS6L.mjs +39 -0
  36. package/dist/lib/neutral/delete-card-field-XHOLGS6L.mjs.map +7 -0
  37. package/dist/lib/neutral/hooks/index.mjs +431 -0
  38. package/dist/lib/neutral/hooks/index.mjs.map +7 -0
  39. package/dist/lib/neutral/index.mjs +34 -0
  40. package/dist/lib/neutral/index.mjs.map +7 -0
  41. package/dist/lib/neutral/meta.json +1 -0
  42. package/dist/lib/neutral/meta.mjs +8 -0
  43. package/dist/lib/neutral/meta.mjs.map +7 -0
  44. package/dist/lib/neutral/operation-handler-B7IW6MXU.mjs +13 -0
  45. package/dist/lib/neutral/operation-handler-B7IW6MXU.mjs.map +7 -0
  46. package/dist/lib/neutral/operations/index.mjs +8 -0
  47. package/dist/lib/neutral/operations/index.mjs.map +7 -0
  48. package/dist/lib/neutral/plugin.mjs +16 -0
  49. package/dist/lib/neutral/plugin.mjs.map +7 -0
  50. package/dist/lib/neutral/react-surface-VZEVEJL5.mjs +91 -0
  51. package/dist/lib/neutral/react-surface-VZEVEJL5.mjs.map +7 -0
  52. package/dist/lib/{browser/restore-card-4GG2RYKR.mjs → neutral/restore-card-EKVEPATL.mjs} +6 -14
  53. package/dist/lib/neutral/restore-card-EKVEPATL.mjs.map +7 -0
  54. package/dist/lib/neutral/restore-card-field-TQCTGGNO.mjs +37 -0
  55. package/dist/lib/neutral/restore-card-field-TQCTGGNO.mjs.map +7 -0
  56. package/dist/lib/neutral/testing/index.mjs +62 -0
  57. package/dist/lib/neutral/testing/index.mjs.map +7 -0
  58. package/dist/lib/neutral/translations.mjs +44 -0
  59. package/dist/lib/neutral/translations.mjs.map +7 -0
  60. package/dist/lib/neutral/types/index.mjs +22 -0
  61. package/dist/lib/neutral/types/index.mjs.map +7 -0
  62. package/dist/lib/neutral/undo-mappings-6CHW6BOF.mjs +42 -0
  63. package/dist/lib/neutral/undo-mappings-6CHW6BOF.mjs.map +7 -0
  64. package/dist/types/src/KanbanPlugin.d.ts +1 -0
  65. package/dist/types/src/KanbanPlugin.d.ts.map +1 -1
  66. package/dist/types/src/KanbanPlugin.node.d.ts +4 -0
  67. package/dist/types/src/KanbanPlugin.node.d.ts.map +1 -0
  68. package/dist/types/src/KanbanPlugin.test.d.ts +2 -0
  69. package/dist/types/src/KanbanPlugin.test.d.ts.map +1 -0
  70. package/dist/types/src/KanbanPlugin.workerd.d.ts +4 -0
  71. package/dist/types/src/KanbanPlugin.workerd.d.ts.map +1 -0
  72. package/dist/types/src/blueprints/kanban-blueprint.d.ts +2 -2
  73. package/dist/types/src/blueprints/kanban-blueprint.d.ts.map +1 -1
  74. package/dist/types/src/capabilities/artifact-definition.d.ts.map +1 -1
  75. package/dist/types/src/capabilities/blueprint-definition.d.ts +1 -1
  76. package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -1
  77. package/dist/types/src/capabilities/create-object.d.ts +11 -0
  78. package/dist/types/src/capabilities/create-object.d.ts.map +1 -0
  79. package/dist/types/src/capabilities/index.d.ts +9 -2
  80. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  81. package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
  82. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -1
  83. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  84. package/dist/types/src/capabilities/undo-mappings.d.ts.map +1 -1
  85. package/dist/types/src/components/KanbanBoard/KanbanBoard.d.ts +9 -29
  86. package/dist/types/src/components/KanbanBoard/KanbanBoard.d.ts.map +1 -1
  87. package/dist/types/src/components/KanbanBoard/KanbanBoard.stories.d.ts +24 -24
  88. package/dist/types/src/components/KanbanBoard/KanbanBoard.stories.d.ts.map +1 -1
  89. package/dist/types/src/components/KanbanBoard/KanbanCard.d.ts +2 -3
  90. package/dist/types/src/components/KanbanBoard/KanbanCard.d.ts.map +1 -1
  91. package/dist/types/src/components/KanbanBoard/KanbanColumn.d.ts +2 -3
  92. package/dist/types/src/components/KanbanBoard/KanbanColumn.d.ts.map +1 -1
  93. package/dist/types/src/components/KanbanBoard/context.d.ts +38 -0
  94. package/dist/types/src/components/KanbanBoard/context.d.ts.map +1 -0
  95. package/dist/types/src/containers/KanbanArticle/KanbanArticle.d.ts +6 -0
  96. package/dist/types/src/containers/KanbanArticle/KanbanArticle.d.ts.map +1 -0
  97. package/dist/types/src/containers/{KanbanContainer/KanbanContainer.stories.d.ts → KanbanArticle/KanbanArticle.stories.d.ts} +26 -26
  98. package/dist/types/src/containers/KanbanArticle/KanbanArticle.stories.d.ts.map +1 -0
  99. package/dist/types/src/containers/KanbanArticle/index.d.ts +2 -0
  100. package/dist/types/src/containers/KanbanArticle/index.d.ts.map +1 -0
  101. package/dist/types/src/containers/KanbanSettings/KanbanSettings.d.ts +13 -0
  102. package/dist/types/src/containers/KanbanSettings/KanbanSettings.d.ts.map +1 -0
  103. package/dist/types/src/containers/KanbanSettings/index.d.ts +2 -0
  104. package/dist/types/src/containers/KanbanSettings/index.d.ts.map +1 -0
  105. package/dist/types/src/containers/index.d.ts +2 -2
  106. package/dist/types/src/containers/index.d.ts.map +1 -1
  107. package/dist/types/src/hooks/index.d.ts +1 -0
  108. package/dist/types/src/hooks/index.d.ts.map +1 -1
  109. package/dist/types/src/hooks/useEchoChangeCallback.d.ts.map +1 -1
  110. package/dist/types/src/hooks/useItemsProjection.d.ts +10 -0
  111. package/dist/types/src/hooks/useItemsProjection.d.ts.map +1 -0
  112. package/dist/types/src/hooks/useKanbanBoardModel.browser.test.d.ts +2 -0
  113. package/dist/types/src/hooks/useKanbanBoardModel.browser.test.d.ts.map +1 -0
  114. package/dist/types/src/hooks/useKanbanBoardModel.d.ts.map +1 -1
  115. package/dist/types/src/hooks/useKanbanColumnEventHandler.d.ts +1 -1
  116. package/dist/types/src/hooks/useKanbanColumnEventHandler.d.ts.map +1 -1
  117. package/dist/types/src/hooks/useKanbanItemEventHandler.d.ts +1 -1
  118. package/dist/types/src/hooks/useKanbanItemEventHandler.d.ts.map +1 -1
  119. package/dist/types/src/hooks/useProjectionModel.d.ts.map +1 -1
  120. package/dist/types/src/index.d.ts +3 -1
  121. package/dist/types/src/index.d.ts.map +1 -1
  122. package/dist/types/src/meta.d.ts +1 -1
  123. package/dist/types/src/meta.d.ts.map +1 -1
  124. package/dist/types/src/operations/delete-card-field.d.ts +3 -3
  125. package/dist/types/src/operations/delete-card-field.d.ts.map +1 -1
  126. package/dist/types/src/operations/delete-card.d.ts +3 -3
  127. package/dist/types/src/operations/delete-card.d.ts.map +1 -1
  128. package/dist/types/src/operations/index.d.ts +1 -2
  129. package/dist/types/src/operations/index.d.ts.map +1 -1
  130. package/dist/types/src/operations/restore-card-field.d.ts +3 -3
  131. package/dist/types/src/operations/restore-card-field.d.ts.map +1 -1
  132. package/dist/types/src/operations/restore-card.d.ts +3 -3
  133. package/dist/types/src/operations/restore-card.d.ts.map +1 -1
  134. package/dist/types/src/playwright/board-manager.d.ts.map +1 -1
  135. package/dist/types/src/playwright/playwright.config.d.ts.map +1 -1
  136. package/dist/types/src/plugin.d.ts +4 -0
  137. package/dist/types/src/plugin.d.ts.map +1 -0
  138. package/dist/types/src/translations.d.ts +24 -24
  139. package/dist/types/src/translations.d.ts.map +1 -1
  140. package/dist/types/src/types/Kanban.d.ts +66 -9
  141. package/dist/types/src/types/Kanban.d.ts.map +1 -1
  142. package/dist/types/src/{operations/definitions.d.ts → types/KanbanOperation.d.ts} +4 -4
  143. package/dist/types/src/types/KanbanOperation.d.ts.map +1 -0
  144. package/dist/types/src/types/constants.d.ts +3 -3
  145. package/dist/types/src/types/constants.d.ts.map +1 -1
  146. package/dist/types/src/types/index.d.ts +2 -1
  147. package/dist/types/src/types/index.d.ts.map +1 -1
  148. package/dist/types/src/types/schema.d.ts +15 -1
  149. package/dist/types/src/types/schema.d.ts.map +1 -1
  150. package/dist/types/src/types/types.d.ts +2 -2
  151. package/dist/types/src/util/arrangement.d.ts +8 -4
  152. package/dist/types/src/util/arrangement.d.ts.map +1 -1
  153. package/dist/types/tsconfig.tsbuildinfo +1 -1
  154. package/package.json +110 -76
  155. package/src/KanbanPlugin.node.ts +21 -0
  156. package/src/KanbanPlugin.test.ts +31 -0
  157. package/src/KanbanPlugin.tsx +12 -39
  158. package/src/KanbanPlugin.workerd.ts +18 -0
  159. package/src/blueprints/kanban-blueprint.ts +2 -3
  160. package/src/capabilities/artifact-definition.ts +10 -9
  161. package/src/capabilities/blueprint-definition.ts +6 -4
  162. package/src/capabilities/create-object.ts +40 -0
  163. package/src/capabilities/index.ts +9 -2
  164. package/src/capabilities/operation-handler.ts +1 -1
  165. package/src/capabilities/react-surface.tsx +31 -14
  166. package/src/capabilities/undo-mappings.ts +1 -1
  167. package/src/components/KanbanBoard/KanbanBoard.stories.tsx +9 -6
  168. package/src/components/KanbanBoard/KanbanBoard.tsx +22 -51
  169. package/src/components/KanbanBoard/KanbanCard.tsx +75 -60
  170. package/src/components/KanbanBoard/KanbanColumn.tsx +16 -13
  171. package/src/components/KanbanBoard/context.ts +54 -0
  172. package/src/containers/{KanbanContainer/KanbanContainer.stories.tsx → KanbanArticle/KanbanArticle.stories.tsx} +48 -42
  173. package/src/containers/KanbanArticle/KanbanArticle.tsx +179 -0
  174. package/src/containers/KanbanArticle/index.ts +5 -0
  175. package/src/containers/KanbanSettings/KanbanSettings.tsx +94 -0
  176. package/src/containers/KanbanSettings/index.ts +5 -0
  177. package/src/containers/index.ts +2 -2
  178. package/src/hooks/index.ts +1 -0
  179. package/src/hooks/useEchoChangeCallback.ts +2 -2
  180. package/src/hooks/useItemsProjection.ts +44 -0
  181. package/src/hooks/{useKanbanBoardModel.test.ts → useKanbanBoardModel.browser.test.ts} +14 -19
  182. package/src/hooks/useKanbanBoardModel.ts +19 -7
  183. package/src/hooks/useProjectionModel.ts +4 -4
  184. package/src/index.ts +3 -2
  185. package/src/meta.ts +22 -5
  186. package/src/operations/delete-card-field.ts +11 -16
  187. package/src/operations/delete-card.ts +3 -3
  188. package/src/operations/index.ts +1 -3
  189. package/src/operations/restore-card-field.ts +11 -16
  190. package/src/operations/restore-card.ts +3 -3
  191. package/src/playwright/smoke.spec.ts +3 -3
  192. package/src/plugin.ts +11 -0
  193. package/src/testing/KanbanCardTileSimple.tsx +6 -6
  194. package/src/types/Kanban.ts +86 -23
  195. package/src/{operations/definitions.ts → types/KanbanOperation.ts} +25 -9
  196. package/src/types/index.ts +3 -1
  197. package/src/types/schema.ts +20 -2
  198. package/src/types/types.ts +2 -2
  199. package/src/util/arrangement.test.ts +22 -13
  200. package/src/util/arrangement.ts +25 -15
  201. package/src/vite-env.d.ts +10 -0
  202. package/dist/lib/browser/blueprints/index.mjs.map +0 -7
  203. package/dist/lib/browser/chunk-A3PBV3S5.mjs +0 -105
  204. package/dist/lib/browser/chunk-A3PBV3S5.mjs.map +0 -7
  205. package/dist/lib/browser/delete-card-VPNVIWOA.mjs.map +0 -7
  206. package/dist/lib/browser/delete-card-field-4HHF2GYX.mjs +0 -50
  207. package/dist/lib/browser/delete-card-field-4HHF2GYX.mjs.map +0 -7
  208. package/dist/lib/browser/index.mjs +0 -121
  209. package/dist/lib/browser/index.mjs.map +0 -7
  210. package/dist/lib/browser/meta.json +0 -1
  211. package/dist/lib/browser/operations/index.mjs +0 -13
  212. package/dist/lib/browser/operations/index.mjs.map +0 -7
  213. package/dist/lib/browser/restore-card-4GG2RYKR.mjs.map +0 -7
  214. package/dist/lib/browser/restore-card-field-3T26ACYX.mjs +0 -48
  215. package/dist/lib/browser/restore-card-field-3T26ACYX.mjs.map +0 -7
  216. package/dist/lib/browser/types/index.mjs +0 -100
  217. package/dist/lib/browser/types/index.mjs.map +0 -7
  218. package/dist/lib/node-esm/blueprints/index.mjs +0 -28
  219. package/dist/lib/node-esm/blueprints/index.mjs.map +0 -7
  220. package/dist/lib/node-esm/chunk-6LELYA2G.mjs +0 -106
  221. package/dist/lib/node-esm/chunk-6LELYA2G.mjs.map +0 -7
  222. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
  223. package/dist/lib/node-esm/delete-card-5PW5OMFN.mjs +0 -33
  224. package/dist/lib/node-esm/delete-card-5PW5OMFN.mjs.map +0 -7
  225. package/dist/lib/node-esm/delete-card-field-KPJU2AQ3.mjs +0 -51
  226. package/dist/lib/node-esm/delete-card-field-KPJU2AQ3.mjs.map +0 -7
  227. package/dist/lib/node-esm/index.mjs +0 -122
  228. package/dist/lib/node-esm/index.mjs.map +0 -7
  229. package/dist/lib/node-esm/meta.json +0 -1
  230. package/dist/lib/node-esm/operations/index.mjs +0 -14
  231. package/dist/lib/node-esm/operations/index.mjs.map +0 -7
  232. package/dist/lib/node-esm/restore-card-X2TKMU5A.mjs +0 -30
  233. package/dist/lib/node-esm/restore-card-X2TKMU5A.mjs.map +0 -7
  234. package/dist/lib/node-esm/restore-card-field-IUTL4RTR.mjs +0 -49
  235. package/dist/lib/node-esm/restore-card-field-IUTL4RTR.mjs.map +0 -7
  236. package/dist/lib/node-esm/types/index.mjs +0 -101
  237. package/dist/lib/node-esm/types/index.mjs.map +0 -7
  238. package/dist/types/src/containers/KanbanContainer/KanbanContainer.d.ts +0 -6
  239. package/dist/types/src/containers/KanbanContainer/KanbanContainer.d.ts.map +0 -1
  240. package/dist/types/src/containers/KanbanContainer/KanbanContainer.stories.d.ts.map +0 -1
  241. package/dist/types/src/containers/KanbanContainer/index.d.ts +0 -2
  242. package/dist/types/src/containers/KanbanContainer/index.d.ts.map +0 -1
  243. package/dist/types/src/containers/KanbanViewEditor/KanbanViewEditor.d.ts +0 -6
  244. package/dist/types/src/containers/KanbanViewEditor/KanbanViewEditor.d.ts.map +0 -1
  245. package/dist/types/src/containers/KanbanViewEditor/index.d.ts +0 -2
  246. package/dist/types/src/containers/KanbanViewEditor/index.d.ts.map +0 -1
  247. package/dist/types/src/hooks/useKanbanBoardModel.test.d.ts +0 -2
  248. package/dist/types/src/hooks/useKanbanBoardModel.test.d.ts.map +0 -1
  249. package/dist/types/src/operations/definitions.d.ts.map +0 -1
  250. package/src/containers/KanbanContainer/KanbanContainer.tsx +0 -96
  251. package/src/containers/KanbanContainer/index.ts +0 -5
  252. package/src/containers/KanbanViewEditor/KanbanViewEditor.tsx +0 -63
  253. package/src/containers/KanbanViewEditor/index.ts +0 -5
  254. /package/dist/lib/{browser/chunk-J5LGTIGS.mjs.map → neutral/blueprints/index.mjs.map} +0 -0
  255. /package/dist/lib/{browser → neutral}/chunk-J5LGTIGS.mjs +0 -0
  256. /package/dist/lib/{node-esm/chunk-HSLMI22Q.mjs.map → neutral/chunk-J5LGTIGS.mjs.map} +0 -0
@@ -6,8 +6,7 @@ import { Atom, RegistryContext } from '@effect-atom/atom-react';
6
6
  import { type Meta, type StoryObj } from '@storybook/react-vite';
7
7
  import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
8
8
 
9
- import { Filter, JsonSchema, Obj, Query } from '@dxos/echo';
10
- import { type View } from '@dxos/echo';
9
+ import { Filter, JsonSchema, Obj, Query, type View } from '@dxos/echo';
11
10
  import { random } from '@dxos/random';
12
11
  import { withMosaic } from '@dxos/react-ui-mosaic/testing';
13
12
  import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
@@ -17,9 +16,9 @@ import { Organization } from '@dxos/types';
17
16
 
18
17
  import { createEchoChangeCallback as createKanbanChangeCallback } from '#hooks';
19
18
  import { KanbanCardTileSimple } from '#testing';
19
+ import { translations } from '#translations';
20
20
  import { Kanban } from '#types';
21
21
 
22
- import { translations } from '../../translations';
23
22
  import { KanbanBoard } from './KanbanBoard';
24
23
 
25
24
  random.seed(1);
@@ -48,7 +47,7 @@ const DefaultStory = () => {
48
47
 
49
48
  useEffect(() => {
50
49
  const view = ViewModel.make({
51
- query: Query.select(Filter.typename(Organization.Organization.typename)),
50
+ query: Query.select(Filter.type(Organization.Organization)),
52
51
  jsonSchema: JsonSchema.toJsonSchema(Organization.Organization),
53
52
  pivotFieldName: 'status',
54
53
  });
@@ -79,7 +78,9 @@ const DefaultStory = () => {
79
78
 
80
79
  const handleCardAdd = useCallback(
81
80
  (columnValue: string | undefined) => {
82
- if (!state || !columnFieldPath || !registry) return undefined;
81
+ if (!state || !columnFieldPath || !registry) {
82
+ return undefined;
83
+ }
83
84
  const card = Obj.make(Organization.Organization, {
84
85
  ...createOrg(),
85
86
  ...(columnFieldPath ? { [columnFieldPath]: columnValue } : {}),
@@ -93,7 +94,9 @@ const DefaultStory = () => {
93
94
 
94
95
  const handleCardRemove = useCallback(
95
96
  (card: Obj.Unknown) => {
96
- if (!registry) return;
97
+ if (!registry) {
98
+ return;
99
+ }
97
100
  const current = registry.get(items) ?? [];
98
101
  registry.set(
99
102
  items,
@@ -3,64 +3,30 @@
3
3
  //
4
4
 
5
5
  import { type Atom, RegistryContext } from '@effect-atom/atom-react';
6
- import { createContext } from '@radix-ui/react-context';
7
- import React, {
8
- type ComponentPropsWithoutRef,
9
- type ComponentType,
10
- type PropsWithChildren,
11
- useCallback,
12
- useContext,
13
- useMemo,
14
- } from 'react';
6
+ import React, { type ComponentPropsWithoutRef, type PropsWithChildren, useCallback, useContext, useMemo } from 'react';
15
7
 
16
8
  import { Obj } from '@dxos/echo';
17
9
  import { useTranslation } from '@dxos/react-ui';
10
+ import { composable, composableProps } from '@dxos/react-ui';
18
11
  import { Board, useBoard } from '@dxos/react-ui-mosaic';
19
12
  import type { ProjectionModel } from '@dxos/schema';
20
- import { composable, composableProps } from '@dxos/ui-theme';
21
13
 
22
14
  import { useKanbanBoardModel, useKanbanColumnEventHandler } from '#hooks';
23
15
  import { meta } from '#meta';
24
- import { type Kanban, type KanbanChangeCallback, UNCATEGORIZED_ATTRIBUTES, UNCATEGORIZED_VALUE } from '#types';
25
-
26
- import { KanbanCard, type KanbanCardProps } from './KanbanCard';
27
- import { KanbanColumn, type KanbanColumnProps } from './KanbanColumn';
16
+ import { type Kanban, UNCATEGORIZED_ATTRIBUTES, UNCATEGORIZED_VALUE } from '#types';
17
+
18
+ import {
19
+ KanbanBoardContext,
20
+ type KanbanBoardContextValue,
21
+ type KanbanCardProps,
22
+ type KanbanColumnProps,
23
+ useKanbanBoard,
24
+ } from './context';
25
+ import { KanbanCard } from './KanbanCard';
26
+ import { KanbanColumn } from './KanbanColumn';
28
27
 
29
28
  // TODO(burdon): Rename Kanban.
30
29
 
31
- //
32
- // Context
33
- //
34
-
35
- const KANBAN_BOARD_NAME = 'KanbanBoard.Context';
36
-
37
- /**
38
- * Context value for the Kanban board.
39
- * Items are Echo objects (Obj.Unknown).
40
- */
41
- type KanbanBoardContextValue = {
42
- kanbanId: string;
43
- projection: ProjectionModel | undefined;
44
- columnFieldPath: string | undefined;
45
- change: KanbanChangeCallback<Obj.Unknown>;
46
- pivotFieldId: string | undefined;
47
- getPivotAttributes: (columnValue: string) => { title: string; color: string };
48
- itemTile?: ComponentType<KanbanCardProps>; // TODO(burdon): Prop.
49
- onCardAdd?: (columnValue: string | undefined) => string | undefined;
50
- onCardRemove?: (card: Obj.Unknown) => void;
51
- };
52
-
53
- const [KanbanBoardContext, useKanbanBoard] = createContext<KanbanBoardContextValue>(KANBAN_BOARD_NAME, {
54
- kanbanId: 'never',
55
- projection: undefined,
56
- columnFieldPath: undefined,
57
- change: { kanban: () => {}, setItemField: () => {} },
58
- pivotFieldId: undefined,
59
- getPivotAttributes: (id: string) =>
60
- id === UNCATEGORIZED_VALUE ? UNCATEGORIZED_ATTRIBUTES : { title: id, color: 'neutral' },
61
- itemTile: (() => null) as ComponentType<KanbanCardProps>,
62
- });
63
-
64
30
  //
65
31
  // Root
66
32
  //
@@ -94,15 +60,20 @@ export const KanbanBoardRoot = ({
94
60
  const { t } = useTranslation(meta.id);
95
61
  const model = useKanbanBoardModel(kanban, projection, items, registry);
96
62
  const columns = model?.getColumns?.() ?? [];
97
- const view = kanban?.view?.target;
63
+ const view = kanban?.spec.kind === 'view' ? kanban.spec.view.target : undefined;
98
64
  const pivotFieldId = view?.projection?.pivotFieldId;
99
65
  const columnFieldPath = useMemo(() => {
66
+ // Items-variant kanbans use the property name itself as the pivot field
67
+ // (no view/projection translation layer).
68
+ if (kanban?.spec.kind === 'items') {
69
+ return kanban.spec.pivotField;
70
+ }
100
71
  if (pivotFieldId === undefined || !projection) {
101
72
  return undefined;
102
73
  }
103
74
 
104
75
  return projection.tryGetFieldProjection(pivotFieldId)?.props.property;
105
- }, [projection, pivotFieldId]);
76
+ }, [kanban?.spec, projection, pivotFieldId]);
106
77
 
107
78
  const getPivotAttributes = useCallback<KanbanBoardContextValue['getPivotAttributes']>(
108
79
  (columnValue) => {
@@ -119,7 +90,7 @@ export const KanbanBoardRoot = ({
119
90
 
120
91
  if (columns.length === 0) {
121
92
  return (
122
- <div role='none' className='flex flex-1 items-center justify-center p-8 text-center text-description'>
93
+ <div className='flex flex-1 items-center justify-center p-8 text-center text-description'>
123
94
  {t('select-pivot.placeholder')}
124
95
  </div>
125
96
  );
@@ -127,7 +98,7 @@ export const KanbanBoardRoot = ({
127
98
 
128
99
  return (
129
100
  <KanbanBoardContext
130
- kanbanId={Obj.getDXN(kanban).toString()}
101
+ kanbanId={Obj.getURI(kanban)}
131
102
  projection={projection}
132
103
  columnFieldPath={columnFieldPath}
133
104
  pivotFieldId={pivotFieldId}
@@ -9,78 +9,93 @@ import { AppSurface, useObjectMenuItems } from '@dxos/app-toolkit/ui';
9
9
  import { Obj } from '@dxos/echo';
10
10
  import { Card, Toolbar, useTranslation } from '@dxos/react-ui';
11
11
  import { Menu, createMenuAction } from '@dxos/react-ui-menu';
12
- import { Focus, Mosaic, type MosaicTileProps, useBoard } from '@dxos/react-ui-mosaic';
12
+ import { Focus, Mosaic, useBoard } from '@dxos/react-ui-mosaic';
13
13
 
14
14
  import { meta } from '#meta';
15
15
 
16
- import { useKanbanBoard } from './KanbanBoard';
16
+ import { type KanbanCardProps, useKanbanBoard } from './context';
17
17
 
18
- const KANBAN_CARD_TILE_NAME = 'KanbanBoard.Card';
18
+ export { type KanbanCardProps };
19
19
 
20
- export type KanbanCardProps = Pick<MosaicTileProps<Obj.Unknown>, 'location' | 'data' | 'debug'>;
20
+ const KANBAN_CARD_TILE_NAME = 'KanbanBoard.Card';
21
21
 
22
22
  /**
23
23
  * Mosaic Tile for Kanban card.
24
24
  * Uses Surface for content; requires plugin manager context.
25
25
  */
26
- export const KanbanCard = forwardRef<HTMLDivElement, KanbanCardProps>(({ data, location, debug }, forwardedRef) => {
27
- const { t } = useTranslation(meta.id);
28
- const { model } = useBoard(KANBAN_CARD_TILE_NAME);
29
- const { projection, onCardRemove } = useKanbanBoard(KANBAN_CARD_TILE_NAME);
30
- const [dragHandle, setDragHandle] = useState<HTMLButtonElement | null>(null);
31
- const dragHandleRef = useCallback((el: HTMLButtonElement | null) => setDragHandle(el), []);
26
+ export const KanbanCard = forwardRef<HTMLDivElement, KanbanCardProps>(
27
+ ({ data, location, debug, draggable }, forwardedRef) => {
28
+ const { t } = useTranslation(meta.id);
29
+ const { model } = useBoard(KANBAN_CARD_TILE_NAME);
30
+ const { projection, columnFieldPath, onCardRemove } = useKanbanBoard(KANBAN_CARD_TILE_NAME);
31
+ const [dragHandle, setDragHandle] = useState<HTMLButtonElement | null>(null);
32
+ const dragHandleRef = useCallback((el: HTMLButtonElement | null) => setDragHandle(el), []);
32
33
 
33
- const objectMenuItems = useObjectMenuItems(data);
34
+ const objectMenuItems = useObjectMenuItems(data);
34
35
 
35
- const menuItems = useMemo(
36
- () => [
37
- ...objectMenuItems,
38
- ...(onCardRemove
39
- ? [
40
- createMenuAction('remove', () => onCardRemove(data), {
41
- label: t('remove-card.label'),
42
- icon: 'ph--trash--regular',
43
- }),
44
- ]
45
- : []),
46
- ],
47
- [objectMenuItems, onCardRemove, data, t],
48
- );
36
+ const menuItems = useMemo(
37
+ () => [
38
+ ...objectMenuItems,
39
+ ...(onCardRemove
40
+ ? [
41
+ createMenuAction('remove', () => onCardRemove(data), {
42
+ label: t('remove-card.label'),
43
+ icon: 'ph--trash--regular',
44
+ }),
45
+ ]
46
+ : []),
47
+ ],
48
+ [objectMenuItems, onCardRemove, data, t],
49
+ );
49
50
 
50
- return (
51
- <Menu.Root>
52
- <Mosaic.Tile
53
- asChild
54
- id={model.getItemId(data)}
55
- data={data}
56
- location={location}
57
- debug={debug}
58
- dragHandle={dragHandle}
59
- >
60
- <Focus.Item asChild>
61
- <Card.Root ref={forwardedRef} data-testid='board-item'>
62
- <Card.Toolbar>
63
- <Card.DragHandle ref={dragHandleRef} testId='mosaicBoard.cardDragHandle' />
64
- <Card.Title data-testid='mosaicBoard.cardTitle'>{Obj.getLabel(data)}</Card.Title>
65
- {/* TODO(wittjosiah): Reconcile with Card.Menu. */}
66
- <Menu.Trigger asChild disabled={!menuItems?.length}>
67
- <Toolbar.IconButton
68
- iconOnly
69
- variant='ghost'
70
- icon='ph--dots-three-vertical--regular'
71
- label={t('action-menu.label')}
72
- />
73
- </Menu.Trigger>
74
- <Menu.Content items={menuItems} />
75
- </Card.Toolbar>
76
- <Card.Content>
77
- {projection && <Surface.Surface type={AppSurface.Card} limit={1} data={{ subject: data, projection }} />}
78
- </Card.Content>
79
- </Card.Root>
80
- </Focus.Item>
81
- </Mosaic.Tile>
82
- </Menu.Root>
83
- );
84
- });
51
+ return (
52
+ <Menu.Root>
53
+ <Mosaic.Tile
54
+ asChild
55
+ id={model.getItemId(data)}
56
+ data={data}
57
+ location={location}
58
+ debug={debug}
59
+ draggable={draggable}
60
+ dragHandle={dragHandle}
61
+ >
62
+ <Focus.Item asChild>
63
+ <Card.Root ref={forwardedRef} data-testid='board-item'>
64
+ <Card.Header>
65
+ <Card.DragHandle ref={dragHandleRef} testId='mosaicBoard.cardDragHandle' />
66
+ <Card.Title data-testid='mosaicBoard.cardTitle'>{Obj.getLabel(data)}</Card.Title>
67
+ {/* TODO(wittjosiah): Reconcile with Card.Menu. */}
68
+ <Menu.Trigger asChild disabled={!menuItems?.length}>
69
+ <Toolbar.IconButton
70
+ iconOnly
71
+ variant='ghost'
72
+ icon='ph--dots-three-vertical--regular'
73
+ label={t('action-menu.label')}
74
+ />
75
+ </Menu.Trigger>
76
+ <Menu.Content items={menuItems} />
77
+ </Card.Header>
78
+ <Card.Body>
79
+ {projection && (
80
+ <Surface.Surface
81
+ type={AppSurface.Card}
82
+ limit={1}
83
+ data={{
84
+ subject: data,
85
+ projection,
86
+ // Hide the pivot field: its value is already conveyed by
87
+ // which column the card sits in.
88
+ ignorePaths: columnFieldPath ? [columnFieldPath] : undefined,
89
+ }}
90
+ />
91
+ )}
92
+ </Card.Body>
93
+ </Card.Root>
94
+ </Focus.Item>
95
+ </Mosaic.Tile>
96
+ </Menu.Root>
97
+ );
98
+ },
99
+ );
85
100
 
86
101
  KanbanCard.displayName = KANBAN_CARD_TILE_NAME;
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import React, { FC, forwardRef, RefObject, useRef } from 'react';
5
+ import React, { FC, forwardRef, useState } from 'react';
6
6
 
7
7
  import type { Obj } from '@dxos/echo';
8
8
  import { Board, type MosaicTileProps, useBoard } from '@dxos/react-ui-mosaic';
@@ -10,23 +10,23 @@ import { Board, type MosaicTileProps, useBoard } from '@dxos/react-ui-mosaic';
10
10
  import { useKanbanItemEventHandler } from '#hooks';
11
11
  import { type ColumnStructure, UNCATEGORIZED_VALUE } from '#types';
12
12
 
13
- import { useKanbanBoard } from './KanbanBoard';
13
+ import { type KanbanColumnProps, useKanbanBoard } from './context';
14
14
 
15
- const KANBAN_COLUMN_NAME = 'KanbanBoard.Column';
15
+ export { type KanbanColumnProps };
16
16
 
17
- export type KanbanColumnProps = Pick<MosaicTileProps<ColumnStructure>, 'location' | 'data' | 'debug'>;
17
+ const KANBAN_COLUMN_NAME = 'KanbanBoard.Column';
18
18
 
19
19
  /**
20
20
  * Mosaic Tile for Kanban column.
21
21
  */
22
22
  export const KanbanColumn = forwardRef<HTMLDivElement, KanbanColumnProps>(
23
- ({ data: column, location, debug }, forwardedRef) => {
23
+ ({ data: column, location, debug, draggable }, forwardedRef) => {
24
24
  const { model } = useBoard<ColumnStructure, Obj.Unknown>(KANBAN_COLUMN_NAME);
25
25
  const { columnFieldPath, change, onCardAdd, getPivotAttributes, itemTile } = useKanbanBoard(KANBAN_COLUMN_NAME);
26
26
 
27
27
  const { title } = getPivotAttributes(column.columnValue);
28
28
  const uncategorized = column.columnValue === UNCATEGORIZED_VALUE;
29
- const dragHandleRef = useRef<HTMLButtonElement | null>(null);
29
+ const [dragHandle, setDragHandle] = useState<HTMLButtonElement | null>(null);
30
30
 
31
31
  const eventHandler = useKanbanItemEventHandler({
32
32
  column,
@@ -41,7 +41,8 @@ export const KanbanColumn = forwardRef<HTMLDivElement, KanbanColumnProps>(
41
41
  location={location}
42
42
  classNames='grid grid-rows-[var(--dx-rail-action)_1fr_var(--dx-rail-action)]'
43
43
  debug={debug}
44
- dragHandleRef={dragHandleRef}
44
+ draggable={draggable}
45
+ dragHandle={dragHandle}
45
46
  ref={forwardedRef}
46
47
  >
47
48
  {uncategorized ? (
@@ -49,18 +50,20 @@ export const KanbanColumn = forwardRef<HTMLDivElement, KanbanColumnProps>(
49
50
  <span className='font-medium'>{title}</span>
50
51
  </div>
51
52
  ) : (
52
- <Board.Column.Header label={title} dragHandleRef={dragHandleRef as RefObject<HTMLButtonElement>} />
53
+ <Board.Column.Header label={title} dragHandleRef={setDragHandle} />
53
54
  )}
54
55
  <Board.Column.Body
55
56
  data={column}
56
57
  eventHandler={eventHandler}
57
58
  Tile={itemTile as FC<MosaicTileProps<Obj.Unknown>>}
58
59
  />
59
- {onCardAdd && (
60
- <Board.Column.Footer
61
- onAdd={() => onCardAdd(column.columnValue === UNCATEGORIZED_VALUE ? undefined : column.columnValue)}
62
- />
63
- )}
60
+ <Board.Column.Footer
61
+ onAdd={
62
+ onCardAdd
63
+ ? () => onCardAdd(column.columnValue === UNCATEGORIZED_VALUE ? undefined : column.columnValue)
64
+ : undefined
65
+ }
66
+ />
64
67
  </Board.Column.Root>
65
68
  );
66
69
  },
@@ -0,0 +1,54 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { createContext } from '@radix-ui/react-context';
6
+ import { type ComponentType } from 'react';
7
+
8
+ import { type Obj } from '@dxos/echo';
9
+ import { type MosaicTileProps } from '@dxos/react-ui-mosaic';
10
+ import { type ProjectionModel } from '@dxos/schema';
11
+
12
+ import { type ColumnStructure, type KanbanChangeCallback, UNCATEGORIZED_ATTRIBUTES, UNCATEGORIZED_VALUE } from '#types';
13
+
14
+ const KANBAN_BOARD_NAME = 'KanbanBoard.Context';
15
+
16
+ /**
17
+ * Card tile props. Defined here (rather than in `KanbanCard.tsx`) so the
18
+ * context type can reference it without forming a cycle through that
19
+ * module's runtime exports — webkit treats the resulting TDZ as a hard
20
+ * error while other engines are lenient.
21
+ */
22
+ export type KanbanCardProps = Pick<MosaicTileProps<Obj.Unknown>, 'location' | 'data' | 'debug' | 'draggable'>;
23
+
24
+ /**
25
+ * Column tile props. See note on {@link KanbanCardProps}.
26
+ */
27
+ export type KanbanColumnProps = Pick<MosaicTileProps<ColumnStructure>, 'location' | 'data' | 'debug' | 'draggable'>;
28
+
29
+ /**
30
+ * Context value for the Kanban board.
31
+ * Items are Echo objects (Obj.Unknown).
32
+ */
33
+ export type KanbanBoardContextValue = {
34
+ kanbanId: string;
35
+ projection: ProjectionModel | undefined;
36
+ columnFieldPath: string | undefined;
37
+ change: KanbanChangeCallback<Obj.Unknown>;
38
+ pivotFieldId: string | undefined;
39
+ getPivotAttributes: (columnValue: string) => { title: string; color: string };
40
+ itemTile?: ComponentType<KanbanCardProps>; // TODO(burdon): Prop.
41
+ onCardAdd?: (columnValue: string | undefined) => string | undefined;
42
+ onCardRemove?: (card: Obj.Unknown) => void;
43
+ };
44
+
45
+ export const [KanbanBoardContext, useKanbanBoard] = createContext<KanbanBoardContextValue>(KANBAN_BOARD_NAME, {
46
+ kanbanId: 'never',
47
+ projection: undefined,
48
+ columnFieldPath: undefined,
49
+ change: { kanban: () => {}, setItemField: () => {} },
50
+ pivotFieldId: undefined,
51
+ getPivotAttributes: (id: string) =>
52
+ id === UNCATEGORIZED_VALUE ? UNCATEGORIZED_ATTRIBUTES : { title: id, color: 'neutral' },
53
+ itemTile: (() => null) as ComponentType<KanbanCardProps>,
54
+ });
@@ -11,29 +11,30 @@ import { expect, waitFor, within } from 'storybook/test';
11
11
  import { withPluginManager } from '@dxos/app-framework/testing';
12
12
  import { Surface } from '@dxos/app-framework/ui';
13
13
  import { AppSurface } from '@dxos/app-toolkit/ui';
14
- import { Obj, type QueryAST, Type } from '@dxos/echo';
15
- import { View } from '@dxos/echo';
16
- import { type Mutable } from '@dxos/echo/internal';
14
+ import { Filter, Obj, type QueryAST, Type, View } from '@dxos/echo';
15
+ import { type Mutable } from '@dxos/echo/Obj';
17
16
  import { invariant } from '@dxos/invariant';
18
- import { ClientPlugin } from '@dxos/plugin-client';
17
+ // `/plugin` entrypoints used here for the same reason as `corePlugins()` —
18
+ // see `@dxos/plugin-testing/src/core.ts` for the rationale.
19
+ import { ClientPlugin } from '@dxos/plugin-client/testing';
19
20
  import { initializeIdentity } from '@dxos/plugin-client/testing';
20
- import { PreviewPlugin } from '@dxos/plugin-preview';
21
- import { SpacePlugin } from '@dxos/plugin-space';
21
+ import { PreviewPlugin } from '@dxos/plugin-preview/testing';
22
+ import { SpacePlugin } from '@dxos/plugin-space/testing';
22
23
  import { StorybookPlugin, corePlugins } from '@dxos/plugin-testing';
23
24
  import { random } from '@dxos/random';
24
- import { Filter, type Space, useQuery, useSchema, useSpaces } from '@dxos/react-client/echo';
25
+ import { type Space, useQuery, useType, useSpaces } from '@dxos/react-client/echo';
25
26
  import { ViewEditor } from '@dxos/react-ui-form';
26
- import { Json } from '@dxos/react-ui-syntax-highlighter';
27
+ import { Syntax } from '@dxos/react-ui-syntax-highlighter';
27
28
  import { withLayout } from '@dxos/react-ui/testing';
28
- import { ViewModel, getTypenameFromQuery } from '@dxos/schema';
29
+ import { ViewModel, getTypeURIFromQuery } from '@dxos/schema';
29
30
  // TODO(wittjosiah): Replace with echo/testing.
30
31
  import { Organization, Person } from '@dxos/types';
31
32
 
32
33
  import { useProjectionModel } from '#hooks';
34
+ import { translations } from '#translations';
33
35
  import { Kanban } from '#types';
34
36
 
35
37
  import { KanbanPlugin } from '../../KanbanPlugin';
36
- import { translations } from '../../translations';
37
38
 
38
39
  random.seed(0);
39
40
 
@@ -56,7 +57,7 @@ type ClientSetupOptions = {
56
57
 
57
58
  /**
58
59
  * Creates the standard plugin manager decorator with client configuration.
59
- * Includes KanbanPlugin so the Surface resolves to KanbanContainer.
60
+ * Includes KanbanPlugin so the Surface resolves to KanbanArticle.
60
61
  */
61
62
  const withKanbanPlugins = ({ types = [], onSpaceCreated }: ClientSetupOptions): Decorator =>
62
63
  withPluginManager({
@@ -80,7 +81,7 @@ const withKanbanPlugins = ({ types = [], onSpaceCreated }: ClientSetupOptions):
80
81
  });
81
82
 
82
83
  /**
83
- * Renders the first Kanban in the space via Surface (resolves to KanbanContainer),
84
+ * Renders the first Kanban in the space via Surface (resolves to KanbanArticle),
84
85
  * with a sidebar containing ViewEditor and Json filter.
85
86
  */
86
87
  const DefaultComponent = () => {
@@ -88,36 +89,37 @@ const DefaultComponent = () => {
88
89
  const spaces = useSpaces();
89
90
  const space = spaces[spaces.length - 1];
90
91
  const [kanban] = useQuery(space?.db, Filter.type(Kanban.Kanban));
91
- const typename = kanban?.view.target?.query ? getTypenameFromQuery(kanban.view.target.query.ast) : undefined;
92
- const schema = useSchema(space?.db, typename);
93
- const projection = useProjectionModel(schema, kanban, registry);
92
+ const viewRef = kanban && kanban.spec.kind === 'view' ? kanban.spec.view : undefined;
93
+ const view = viewRef?.target;
94
+ const typeUri = view?.query ? getTypeURIFromQuery(view.query.ast) : undefined;
95
+ const type = useType(space?.db, typeUri);
96
+ const projection = useProjectionModel(type, kanban, registry);
94
97
 
95
98
  const data = useMemo(() => (kanban ? { subject: kanban, attendableId: 'story' } : undefined), [kanban]);
96
99
 
97
100
  const handleUpdateQuery = useCallback(
98
101
  (newQuery: QueryAST.Query) => {
99
- invariant(schema);
100
- invariant(kanban?.view.target);
101
- if (Type.isMutable(schema)) {
102
- schema.updateTypename(getTypenameFromQuery(newQuery));
103
- }
104
- Obj.change(kanban.view.target, (view) => {
102
+ invariant(type);
103
+ invariant(view);
104
+ // NOTE: persisted Type.Type typename is immutable; only the view's
105
+ // query is updated here.
106
+ Obj.update(view, (view) => {
105
107
  view.query.ast = newQuery as Mutable<QueryAST.Query>;
106
108
  });
107
109
  },
108
- [kanban, schema],
110
+ [view, type],
109
111
  );
110
112
 
111
113
  const handleDeleteField = useCallback(
112
114
  (fieldId: string) => {
113
- if (schema && Type.isMutable(schema) && projection) {
115
+ if (type && Type.getDatabase(type) != null && projection) {
114
116
  projection.deleteFieldProjection(fieldId);
115
117
  }
116
118
  },
117
- [schema, projection],
119
+ [type, projection],
118
120
  );
119
121
 
120
- if (!schema || !kanban?.view.target) {
122
+ if (!type || !view) {
121
123
  return null;
122
124
  }
123
125
 
@@ -126,18 +128,20 @@ const DefaultComponent = () => {
126
128
  <Surface.Surface type={AppSurface.Article} data={data} limit={1} />
127
129
  <div className='flex flex-col h-full overflow-hidden border-l border-separator'>
128
130
  <ViewEditor
129
- registry={space?.db.schemaRegistry}
130
- schema={schema}
131
- view={kanban.view.target}
131
+ registry={space?.db.graph.registry}
132
+ type={type}
133
+ view={view}
132
134
  onQueryChanged={handleUpdateQuery}
133
- onDelete={schema && Type.isMutable(schema) ? handleDeleteField : undefined}
135
+ onDelete={type && Type.getDatabase(type) != null ? handleDeleteField : undefined}
134
136
  />
135
- <Json.Root data={{ view: kanban.view.target, schema }}>
136
- <Json.Content>
137
- <Json.Filter />
138
- <Json.Data classNames='text-xs' />
139
- </Json.Content>
140
- </Json.Root>
137
+ <Syntax.Root data={{ view, schema: Type.getSchema(type) }}>
138
+ <Syntax.Content>
139
+ <Syntax.Filter />
140
+ <Syntax.Viewport>
141
+ <Syntax.Code classNames='text-xs' />
142
+ </Syntax.Viewport>
143
+ </Syntax.Content>
144
+ </Syntax.Root>
141
145
  </div>
142
146
  </div>
143
147
  );
@@ -173,7 +177,7 @@ export const Default: Story = {
173
177
  onSpaceCreated: async (space) => {
174
178
  const { view } = await ViewModel.makeFromDatabase({
175
179
  db: space.db,
176
- typename: Organization.Organization.typename,
180
+ typename: Type.getTypename(Organization.Organization),
177
181
  pivotFieldName: 'status',
178
182
  });
179
183
  const kanban = Kanban.make({ view });
@@ -217,7 +221,7 @@ export const Default: Story = {
217
221
  await expect(activeCards.length).toBeGreaterThan(0);
218
222
  await expect(prospectCards.length).toBeGreaterThan(0);
219
223
 
220
- // Verify cards have drag handles (Card.Toolbar includes drag handle).
224
+ // Verify cards have drag handles (Card.Header includes drag handle).
221
225
  const firstActiveCard = activeCards[0];
222
226
  const buttons = firstActiveCard.querySelectorAll('button');
223
227
  await expect(buttons.length).toBeGreaterThan(0);
@@ -234,7 +238,7 @@ export const Default: Story = {
234
238
  };
235
239
 
236
240
  /**
237
- * Story variant that uses a mutable database schema (EchoSchema).
241
+ * Story variant that uses a database-stored Type.Type entity (mutable schema).
238
242
  * This allows testing schema mutations like adding/removing fields.
239
243
  */
240
244
  // TODO(wittjosiah): Card previews (e.g., OrganizationCard) are type-specific and hard-coded.
@@ -245,12 +249,14 @@ export const MutableSchema: Story = {
245
249
  decorators: [
246
250
  withKanbanPlugins({
247
251
  onSpaceCreated: async (space) => {
248
- // Register schema in the database to make it mutable (EchoSchema).
249
- const [schema] = await space.db.schemaRegistry.register([Organization.Organization]);
252
+ // Persist the schema in the database to make it mutable (stored Type.Type).
253
+ const type = await space.db.addType(Organization.Organization);
250
254
 
251
255
  const { view } = await ViewModel.makeFromDatabase({
252
256
  db: space.db,
253
- typename: schema.typename,
257
+ // `db.addType` returns a persisted `Type.Type` entity; its typename lives in the
258
+ // type metadata, so read it via `Type.getTypename` rather than a `.typename` prop.
259
+ typename: Type.getTypename(type),
254
260
  pivotFieldName: 'status',
255
261
  });
256
262
  const kanban = Kanban.make({ view });
@@ -264,7 +270,7 @@ export const MutableSchema: Story = {
264
270
  ...Array.from({ length: 1 }, () => createOrg('commit')),
265
271
  ...Array.from({ length: 1 }, () => createOrg('reject')),
266
272
  ];
267
- requiredOrgs.forEach((org) => space.db.add(Obj.make(schema, org)));
273
+ requiredOrgs.forEach((org) => space.db.add(Obj.make(type, org)));
268
274
  },
269
275
  }),
270
276
  ],