@dxos/plugin-kanban 0.9.0 → 0.9.1-main.c7dcc2e112

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 (67) hide show
  1. package/dist/lib/neutral/KanbanPlugin.mjs +2 -2
  2. package/dist/lib/neutral/KanbanPlugin.mjs.map +4 -4
  3. package/dist/lib/neutral/{KanbanSettings-5WOS4CUE.mjs → KanbanSettings-FTIIR6PR.mjs} +3 -3
  4. package/dist/lib/neutral/{KanbanSettings-5WOS4CUE.mjs.map → KanbanSettings-FTIIR6PR.mjs.map} +3 -3
  5. package/dist/lib/neutral/capabilities/index.mjs +2 -2
  6. package/dist/lib/neutral/capabilities/index.mjs.map +2 -2
  7. package/dist/lib/neutral/chunk-2IGEE5J5.mjs +50 -0
  8. package/dist/lib/neutral/chunk-2IGEE5J5.mjs.map +7 -0
  9. package/dist/lib/neutral/chunk-NDJNHR4K.mjs +8 -0
  10. package/dist/lib/neutral/{chunk-DAKIZO46.mjs → chunk-Y2G24ZGD.mjs} +2 -2
  11. package/dist/lib/neutral/{chunk-DAKIZO46.mjs.map → chunk-Y2G24ZGD.mjs.map} +3 -3
  12. package/dist/lib/neutral/components/index.mjs +9 -7
  13. package/dist/lib/neutral/components/index.mjs.map +3 -3
  14. package/dist/lib/neutral/containers/index.mjs +1 -1
  15. package/dist/lib/neutral/{delete-card-VNAV3CZV.mjs → delete-card-NMULYEXS.mjs} +2 -2
  16. package/dist/lib/neutral/{delete-card-field-XHOLGS6L.mjs → delete-card-field-NGYNI6GL.mjs} +2 -2
  17. package/dist/lib/neutral/index.mjs +3 -3
  18. package/dist/lib/neutral/meta.json +1 -1
  19. package/dist/lib/neutral/meta.mjs +1 -1
  20. package/dist/lib/neutral/operations/index.mjs +1 -1
  21. package/dist/lib/neutral/plugin.mjs +2 -2
  22. package/dist/lib/neutral/{react-surface-VZEVEJL5.mjs → react-surface-5Y6IHGKR.mjs} +7 -10
  23. package/dist/lib/neutral/react-surface-5Y6IHGKR.mjs.map +7 -0
  24. package/dist/lib/neutral/{restore-card-EKVEPATL.mjs → restore-card-JQ5N7G6G.mjs} +2 -2
  25. package/dist/lib/neutral/{restore-card-field-TQCTGGNO.mjs → restore-card-field-4SU6IR4V.mjs} +2 -2
  26. package/dist/lib/neutral/testing/index.mjs +7 -5
  27. package/dist/lib/neutral/testing/index.mjs.map +3 -3
  28. package/dist/lib/neutral/translations.mjs +1 -1
  29. package/dist/lib/neutral/translations.mjs.map +3 -3
  30. package/dist/lib/neutral/types/index.mjs +1 -1
  31. package/dist/lib/neutral/{undo-mappings-6CHW6BOF.mjs → undo-mappings-EZTHO4UL.mjs} +3 -3
  32. package/dist/lib/neutral/{undo-mappings-6CHW6BOF.mjs.map → undo-mappings-EZTHO4UL.mjs.map} +3 -3
  33. package/dist/types/dx.config.d.ts +28 -0
  34. package/dist/types/dx.config.d.ts.map +1 -0
  35. package/dist/types/src/capabilities/index.d.ts +4 -10
  36. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  37. package/dist/types/src/capabilities/react-surface.d.ts +2 -2
  38. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  39. package/dist/types/src/components/KanbanBoard/KanbanCard.d.ts.map +1 -1
  40. package/dist/types/src/containers/KanbanSettings/KanbanSettings.d.ts.map +1 -1
  41. package/dist/types/src/meta.d.ts +28 -2
  42. package/dist/types/src/meta.d.ts.map +1 -1
  43. package/dist/types/src/testing/KanbanCardTileSimple.d.ts.map +1 -1
  44. package/dist/types/tsconfig.tsbuildinfo +1 -1
  45. package/dx.config.ts +36 -0
  46. package/package.json +33 -32
  47. package/src/KanbanPlugin.test.ts +1 -1
  48. package/src/KanbanPlugin.tsx +1 -1
  49. package/src/capabilities/index.ts +1 -7
  50. package/src/capabilities/react-surface.tsx +13 -24
  51. package/src/capabilities/undo-mappings.ts +2 -2
  52. package/src/components/KanbanBoard/KanbanBoard.tsx +1 -1
  53. package/src/components/KanbanBoard/KanbanCard.tsx +14 -12
  54. package/src/containers/KanbanSettings/KanbanSettings.tsx +10 -3
  55. package/src/meta.ts +2 -29
  56. package/src/testing/KanbanCardTileSimple.tsx +13 -11
  57. package/src/translations.ts +1 -1
  58. package/src/types/KanbanOperation.ts +1 -1
  59. package/dist/lib/neutral/chunk-6ZHHQWO5.mjs +0 -39
  60. package/dist/lib/neutral/chunk-6ZHHQWO5.mjs.map +0 -7
  61. package/dist/lib/neutral/chunk-M5ISZWZU.mjs +0 -8
  62. package/dist/lib/neutral/react-surface-VZEVEJL5.mjs.map +0 -7
  63. /package/dist/lib/neutral/{chunk-M5ISZWZU.mjs.map → chunk-NDJNHR4K.mjs.map} +0 -0
  64. /package/dist/lib/neutral/{delete-card-VNAV3CZV.mjs.map → delete-card-NMULYEXS.mjs.map} +0 -0
  65. /package/dist/lib/neutral/{delete-card-field-XHOLGS6L.mjs.map → delete-card-field-NGYNI6GL.mjs.map} +0 -0
  66. /package/dist/lib/neutral/{restore-card-EKVEPATL.mjs.map → restore-card-JQ5N7G6G.mjs.map} +0 -0
  67. /package/dist/lib/neutral/{restore-card-field-TQCTGGNO.mjs.map → restore-card-field-4SU6IR4V.mjs.map} +0 -0
package/dx.config.ts ADDED
@@ -0,0 +1,36 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Config2 } from '@dxos/app-framework/config';
6
+ import { trim } from '@dxos/util';
7
+
8
+ export default Config2.make({
9
+ plugin: {
10
+ key: 'org.dxos.plugin.kanban',
11
+ name: 'Kanban',
12
+ author: 'DXOS',
13
+ description: trim`
14
+ Visual project management using customizable kanban boards to track workflow progress.
15
+ Organize any ECHO type into drag-and-drop columns defined by a single-select field, move cards
16
+ between stages, and reorder both columns and cards — all changes are persisted to ECHO and
17
+ replicated to collaborators in real time.
18
+
19
+ Kanban boards come in two variants: view-variant boards source their cards through a linked
20
+ View query (any ECHO type can be pivoted on a single-select field), while items-variant boards
21
+ own their cards explicitly and are used by external sync integrations such as Linear or GitHub.
22
+ Both variants share the same arrangement storage and drag-and-drop mechanics.
23
+
24
+ Board settings let users choose which single-select field drives the column layout and
25
+ optionally hide the uncategorized column for items that have no pivot value.
26
+ Field-level undo support allows deleted card fields to be restored without data loss.
27
+
28
+ The plugin contributes a Kanban blueprint that exposes board creation and card management
29
+ to AI agents, enabling automated project tracking workflows.
30
+ `,
31
+ source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-kanban',
32
+ icon: { key: 'ph--kanban--regular', hue: 'green' },
33
+ spec: 'PLUGIN.mdl',
34
+ screenshots: [{ dark: 'https://dxos.network/plugin-details-kanban-dark.png' }],
35
+ },
36
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-kanban",
3
- "version": "0.9.0",
3
+ "version": "0.9.1-main.c7dcc2e112",
4
4
  "description": "Kanban DXOS Surface plugin",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -102,6 +102,7 @@
102
102
  "types": "dist/types/src/index.d.ts",
103
103
  "files": [
104
104
  "dist",
105
+ "dx.config.ts",
105
106
  "src",
106
107
  "PLUGIN.mdl"
107
108
  ],
@@ -109,26 +110,26 @@
109
110
  "@effect-atom/atom-react": "^0.5.0",
110
111
  "@radix-ui/react-context": "1.1.1",
111
112
  "effect": "3.21.3",
112
- "@dxos/ai": "0.9.0",
113
- "@dxos/app-framework": "0.9.0",
114
- "@dxos/app-toolkit": "0.9.0",
115
- "@dxos/assistant": "0.9.0",
116
- "@dxos/echo": "0.9.0",
117
- "@dxos/compute": "0.9.0",
118
- "@dxos/log": "0.9.0",
119
- "@dxos/effect": "0.9.0",
120
- "@dxos/plugin-space": "0.9.0",
121
- "@dxos/plugin-client": "0.9.0",
122
- "@dxos/invariant": "0.9.0",
123
- "@dxos/random": "0.9.0",
124
- "@dxos/react-client": "0.9.0",
125
- "@dxos/react-ui-form": "0.9.0",
126
- "@dxos/react-ui-menu": "0.9.0",
127
- "@dxos/schema": "0.9.0",
128
- "@dxos/react-ui": "0.9.0",
129
- "@dxos/react-ui-mosaic": "0.9.0",
130
- "@dxos/util": "0.9.0",
131
- "@dxos/types": "0.9.0"
113
+ "@dxos/ai": "0.9.1-main.c7dcc2e112",
114
+ "@dxos/app-framework": "0.9.1-main.c7dcc2e112",
115
+ "@dxos/app-toolkit": "0.9.1-main.c7dcc2e112",
116
+ "@dxos/assistant": "0.9.1-main.c7dcc2e112",
117
+ "@dxos/effect": "0.9.1-main.c7dcc2e112",
118
+ "@dxos/compute": "0.9.1-main.c7dcc2e112",
119
+ "@dxos/log": "0.9.1-main.c7dcc2e112",
120
+ "@dxos/invariant": "0.9.1-main.c7dcc2e112",
121
+ "@dxos/plugin-client": "0.9.1-main.c7dcc2e112",
122
+ "@dxos/echo": "0.9.1-main.c7dcc2e112",
123
+ "@dxos/plugin-space": "0.9.1-main.c7dcc2e112",
124
+ "@dxos/react-client": "0.9.1-main.c7dcc2e112",
125
+ "@dxos/random": "0.9.1-main.c7dcc2e112",
126
+ "@dxos/react-ui": "0.9.1-main.c7dcc2e112",
127
+ "@dxos/react-ui-menu": "0.9.1-main.c7dcc2e112",
128
+ "@dxos/react-ui-mosaic": "0.9.1-main.c7dcc2e112",
129
+ "@dxos/react-ui-form": "0.9.1-main.c7dcc2e112",
130
+ "@dxos/schema": "0.9.1-main.c7dcc2e112",
131
+ "@dxos/types": "0.9.1-main.c7dcc2e112",
132
+ "@dxos/util": "0.9.1-main.c7dcc2e112"
132
133
  },
133
134
  "devDependencies": {
134
135
  "@types/react": "~19.2.7",
@@ -136,22 +137,22 @@
136
137
  "react": "~19.2.3",
137
138
  "react-dom": "~19.2.3",
138
139
  "vite": "^8.0.16",
139
- "@dxos/keys": "0.9.0",
140
- "@dxos/echo-client": "0.9.0",
141
- "@dxos/plugin-preview": "0.9.0",
142
- "@dxos/plugin-testing": "0.9.0",
143
- "@dxos/plugin-theme": "0.9.0",
144
- "@dxos/test-utils": "0.9.0",
145
- "@dxos/ui-theme": "0.9.0",
146
- "@dxos/react-ui-syntax-highlighter": "0.9.0",
147
- "@dxos/storybook-utils": "0.9.0"
140
+ "@dxos/echo-client": "0.9.1-main.c7dcc2e112",
141
+ "@dxos/keys": "0.9.1-main.c7dcc2e112",
142
+ "@dxos/plugin-preview": "0.9.1-main.c7dcc2e112",
143
+ "@dxos/plugin-testing": "0.9.1-main.c7dcc2e112",
144
+ "@dxos/plugin-theme": "0.9.1-main.c7dcc2e112",
145
+ "@dxos/react-ui-syntax-highlighter": "0.9.1-main.c7dcc2e112",
146
+ "@dxos/storybook-utils": "0.9.1-main.c7dcc2e112",
147
+ "@dxos/test-utils": "0.9.1-main.c7dcc2e112",
148
+ "@dxos/ui-theme": "0.9.1-main.c7dcc2e112"
148
149
  },
149
150
  "peerDependencies": {
150
151
  "effect": "3.21.3",
151
152
  "react": "~19.2.3",
152
153
  "react-dom": "~19.2.3",
153
- "@dxos/react-ui": "0.9.0",
154
- "@dxos/ui-theme": "0.9.0"
154
+ "@dxos/react-ui": "0.9.1-main.c7dcc2e112",
155
+ "@dxos/ui-theme": "0.9.1-main.c7dcc2e112"
155
156
  },
156
157
  "publishConfig": {
157
158
  "access": "public"
@@ -11,7 +11,7 @@ import { KanbanPlugin } from '#plugin';
11
11
 
12
12
  import { meta } from './meta';
13
13
 
14
- const moduleId = (name: string) => `${meta.id}.module.${name}`;
14
+ const moduleId = (name: string) => `${meta.profile.key}.module.${name}`;
15
15
 
16
16
  describe('KanbanPlugin', () => {
17
17
  test('modules activate on the expected events', async ({ expect }) => {
@@ -22,7 +22,7 @@ export const KanbanPlugin = Plugin.define(meta).pipe(
22
22
  AppPlugin.addSurfaceModule({ activate: ReactSurface }),
23
23
  AppPlugin.addTranslationsModule({ translations }),
24
24
  AppPlugin.addPluginAssetModule({
25
- asset: { pluginId: meta.id, path: 'PLUGIN.mdl', content: pluginSpec, mimeType: 'application/x-mdl' },
25
+ asset: { pluginId: meta.profile.key, path: 'PLUGIN.mdl', content: pluginSpec, mimeType: 'application/x-mdl' },
26
26
  }),
27
27
  Plugin.make,
28
28
  );
@@ -3,15 +3,9 @@
3
3
  //
4
4
 
5
5
  import { Capability } from '@dxos/app-framework';
6
- import { type AppCapabilities } from '@dxos/app-toolkit';
7
6
  import type { OperationHandlerSet } from '@dxos/compute';
8
7
 
9
- // The contributed capability type references Blueprint types from @dxos/compute, so the lazy
10
- // wrapper needs an explicit annotation to keep the inferred type portable (TS2883).
11
- export const BlueprintDefinition: Capability.LazyCapability<
12
- void,
13
- Capability.Capability<typeof AppCapabilities.BlueprintDefinition>[]
14
- > = Capability.lazy('BlueprintDefinition', () => import('./blueprint-definition'));
8
+ export const BlueprintDefinition = Capability.lazy('BlueprintDefinition', () => import('./blueprint-definition'));
15
9
  export const CreateObject = Capability.lazy('CreateObject', () => import('./create-object'));
16
10
  export const OperationHandler = Capability.lazy<OperationHandlerSet.OperationHandlerSet>(
17
11
  'OperationHandler',
@@ -3,16 +3,14 @@
3
3
  //
4
4
 
5
5
  import * as Effect from 'effect/Effect';
6
- import type * as Schema from 'effect/Schema';
7
- import * as SchemaAST from 'effect/SchemaAST';
8
6
  import React, { useMemo } from 'react';
9
7
 
10
8
  import { Capabilities, Capability } from '@dxos/app-framework';
11
9
  import { Surface } from '@dxos/app-framework/ui';
12
10
  import { AppSurface } from '@dxos/app-toolkit/ui';
13
- import { type Collection, Database, Obj, Type } from '@dxos/echo';
11
+ import { Database, Obj, Type } from '@dxos/echo';
14
12
  import { SchemaEx } from '@dxos/effect';
15
- import { type FormFieldComponentProps, SelectField, useFormValues } from '@dxos/react-ui-form';
13
+ import { type FormFieldRendererProps, SelectField, useFormValues } from '@dxos/react-ui-form';
16
14
 
17
15
  import { KanbanArticle, KanbanSettings } from '#containers';
18
16
  import { Kanban, PivotColumnAnnotationId } from '#types';
@@ -37,29 +35,16 @@ export default Capability.makeModule(() =>
37
35
  }),
38
36
  Surface.create({
39
37
  id: 'createInitialSchemaForm',
40
- role: 'form-input',
41
- filter: (
42
- data,
43
- ): data is {
44
- prop: string;
45
- schema: Schema.Schema<any>;
46
- target: Database.Database | Collection.Collection | undefined;
47
- fieldPropertyAst?: SchemaAST.AST;
48
- } => {
49
- const annotation = SchemaEx.findAnnotation<boolean>(
50
- (data.schema as Schema.Schema.All).ast,
51
- PivotColumnAnnotationId,
52
- );
53
- return !!annotation;
54
- },
55
- component: ({ data: { target, fieldPropertyAst }, ...inputProps }) => {
56
- const ast = fieldPropertyAst;
38
+ filter: AppSurface.formInputBySchema((ast) => !!SchemaEx.findAnnotation<boolean>(ast, PivotColumnAnnotationId)),
39
+ component: ({ data, ...inputProps }) => {
40
+ const ast = data.fieldPropertyAst;
57
41
  if (!ast) {
58
42
  return null;
59
43
  }
60
44
 
61
- const props = { ...inputProps, type: ast } as any as FormFieldComponentProps;
62
- const db = Database.isDatabase(target) ? target : target && Obj.getDatabase(target);
45
+ const props = { ...inputProps, type: ast } as any as FormFieldRendererProps;
46
+ const target = data.target;
47
+ const db = Database.isDatabase(target) ? target : Obj.isObject(target) ? Obj.getDatabase(target) : undefined;
63
48
  if (!db) {
64
49
  return null;
65
50
  }
@@ -84,7 +69,11 @@ export default Capability.makeModule(() =>
84
69
  }
85
70
 
86
71
  const columns = Object.entries(properties).reduce<string[]>((acc, [key, value]) => {
87
- if (typeof value === 'object' && value?.format === 'single-select') {
72
+ if (
73
+ typeof value === 'object' &&
74
+ value !== null &&
75
+ (value as { format?: string }).format === 'single-select'
76
+ ) {
88
77
  acc.push(key);
89
78
  }
90
79
  return acc;
@@ -19,7 +19,7 @@ export default Capability.makeModule(() =>
19
19
  props: output.props,
20
20
  index: output.index,
21
21
  }),
22
- message: ['card-field-deleted.label', { ns: meta.id }],
22
+ message: ['card-field-deleted.label', { ns: meta.profile.key }],
23
23
  }),
24
24
  UndoMapping.make({
25
25
  operation: KanbanOperation.DeleteCard,
@@ -27,7 +27,7 @@ export default Capability.makeModule(() =>
27
27
  deriveContext: (_input, output) => ({
28
28
  card: output.card,
29
29
  }),
30
- message: ['card-deleted.label', { ns: meta.id }],
30
+ message: ['card-deleted.label', { ns: meta.profile.key }],
31
31
  }),
32
32
  ]),
33
33
  ),
@@ -57,7 +57,7 @@ export const KanbanBoardRoot = ({
57
57
  onCardRemove,
58
58
  }: KanbanBoardRootProps) => {
59
59
  const registry = useContext(RegistryContext);
60
- const { t } = useTranslation(meta.id);
60
+ const { t } = useTranslation(meta.profile.key);
61
61
  const model = useKanbanBoardModel(kanban, projection, items, registry);
62
62
  const columns = model?.getColumns?.() ?? [];
63
63
  const view = kanban?.spec.kind === 'view' ? kanban.spec.view.target : undefined;
@@ -7,7 +7,7 @@ import React, { forwardRef, useCallback, useMemo, useState } from 'react';
7
7
  import { Surface } from '@dxos/app-framework/ui';
8
8
  import { AppSurface, useObjectMenuItems } from '@dxos/app-toolkit/ui';
9
9
  import { Obj } from '@dxos/echo';
10
- import { Card, Toolbar, useTranslation } from '@dxos/react-ui';
10
+ import { Card, IconButton, useTranslation } from '@dxos/react-ui';
11
11
  import { Menu, createMenuAction } from '@dxos/react-ui-menu';
12
12
  import { Focus, Mosaic, useBoard } from '@dxos/react-ui-mosaic';
13
13
 
@@ -25,7 +25,7 @@ const KANBAN_CARD_TILE_NAME = 'KanbanBoard.Card';
25
25
  */
26
26
  export const KanbanCard = forwardRef<HTMLDivElement, KanbanCardProps>(
27
27
  ({ data, location, debug, draggable }, forwardedRef) => {
28
- const { t } = useTranslation(meta.id);
28
+ const { t } = useTranslation(meta.profile.key);
29
29
  const { model } = useBoard(KANBAN_CARD_TILE_NAME);
30
30
  const { projection, columnFieldPath, onCardRemove } = useKanbanBoard(KANBAN_CARD_TILE_NAME);
31
31
  const [dragHandle, setDragHandle] = useState<HTMLButtonElement | null>(null);
@@ -65,20 +65,22 @@ export const KanbanCard = forwardRef<HTMLDivElement, KanbanCardProps>(
65
65
  <Card.DragHandle ref={dragHandleRef} testId='mosaicBoard.cardDragHandle' />
66
66
  <Card.Title data-testid='mosaicBoard.cardTitle'>{Obj.getLabel(data)}</Card.Title>
67
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} />
68
+ <Card.Block end>
69
+ <Menu.Trigger asChild disabled={!menuItems?.length}>
70
+ <IconButton
71
+ iconOnly
72
+ variant='ghost'
73
+ icon='ph--dots-three-vertical--regular'
74
+ label={t('action-menu.label')}
75
+ />
76
+ </Menu.Trigger>
77
+ <Menu.Content items={menuItems} />
78
+ </Card.Block>
77
79
  </Card.Header>
78
80
  <Card.Body>
79
81
  {projection && (
80
82
  <Surface.Surface
81
- type={AppSurface.Card}
83
+ type={AppSurface.CardContent}
82
84
  limit={1}
83
85
  data={{
84
86
  subject: data,
@@ -87,8 +87,15 @@ export const KanbanSettings = ({ subject: object }: KanbanSettingsProps) => {
87
87
  const settingsSchema = (isView ? KanbanViewSettingsSchema : KanbanSettingsSchema) as any;
88
88
 
89
89
  return (
90
- <Form.Root schema={settingsSchema} values={initialValues} fieldMap={fieldMap} onValuesChanged={handleValuesChanged}>
91
- <Form.FieldSet />
92
- </Form.Root>
90
+ <Form.Section>
91
+ <Form.Root
92
+ schema={settingsSchema}
93
+ values={initialValues}
94
+ fieldMap={fieldMap}
95
+ onValuesChanged={handleValuesChanged}
96
+ >
97
+ <Form.FieldSet />
98
+ </Form.Root>
99
+ </Form.Section>
93
100
  );
94
101
  };
package/src/meta.ts CHANGED
@@ -3,34 +3,7 @@
3
3
  //
4
4
 
5
5
  import { Plugin } from '@dxos/app-framework';
6
- import { DXN } from '@dxos/echo';
7
- import { trim } from '@dxos/util';
8
6
 
9
- export const meta = Plugin.makeMeta({
10
- key: DXN.make('org.dxos.plugin.kanban'),
11
- name: 'Kanban',
12
- author: 'DXOS',
13
- description: trim`
14
- Visual project management using customizable kanban boards to track workflow progress.
15
- Organize any ECHO type into drag-and-drop columns defined by a single-select field, move cards
16
- between stages, and reorder both columns and cards — all changes are persisted to ECHO and
17
- replicated to collaborators in real time.
7
+ import config from '../dx.config';
18
8
 
19
- Kanban boards come in two variants: view-variant boards source their cards through a linked
20
- View query (any ECHO type can be pivoted on a single-select field), while items-variant boards
21
- own their cards explicitly and are used by external sync integrations such as Linear or GitHub.
22
- Both variants share the same arrangement storage and drag-and-drop mechanics.
23
-
24
- Board settings let users choose which single-select field drives the column layout and
25
- optionally hide the uncategorized column for items that have no pivot value.
26
- Field-level undo support allows deleted card fields to be restored without data loss.
27
-
28
- The plugin contributes a Kanban blueprint that exposes board creation and card management
29
- to AI agents, enabling automated project tracking workflows.
30
- `,
31
- icon: 'ph--kanban--regular',
32
- iconHue: 'green',
33
- source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-kanban',
34
- spec: 'PLUGIN.mdl',
35
- screenshots: ['https://dxos.network/plugin-details-kanban-dark.png'],
36
- });
9
+ export const meta = Plugin.getMetaFromConfig(config);
@@ -5,7 +5,7 @@
5
5
  import React, { forwardRef, useCallback, useMemo, useState } from 'react';
6
6
 
7
7
  import { Obj } from '@dxos/echo';
8
- import { Card, Toolbar, useTranslation } from '@dxos/react-ui';
8
+ import { Card, IconButton, useTranslation } from '@dxos/react-ui';
9
9
  import { Menu, createMenuAction } from '@dxos/react-ui-menu';
10
10
  import { Focus, Mosaic, useBoard } from '@dxos/react-ui-mosaic';
11
11
 
@@ -19,7 +19,7 @@ const KANBAN_CARD_TILE_SIMPLE_NAME = 'KanbanCardTileSimple';
19
19
  */
20
20
  export const KanbanCardTileSimple = forwardRef<HTMLDivElement, KanbanCardProps>(
21
21
  ({ data, location, debug }, forwardedRef) => {
22
- const { t } = useTranslation(meta.id);
22
+ const { t } = useTranslation(meta.profile.key);
23
23
  const { model } = useBoard(KANBAN_CARD_TILE_SIMPLE_NAME);
24
24
  const { onCardRemove } = useKanbanBoard(KANBAN_CARD_TILE_SIMPLE_NAME);
25
25
  const [dragHandle, setDragHandle] = useState<HTMLButtonElement | null>(null);
@@ -54,15 +54,17 @@ export const KanbanCardTileSimple = forwardRef<HTMLDivElement, KanbanCardProps>(
54
54
  <Card.DragHandle ref={dragHandleRef} />
55
55
  <Card.Title>{Obj.getLabel(data)}</Card.Title>
56
56
  {/* TODO(wittjosiah): Reconcile with Card.Menu. */}
57
- <Menu.Trigger asChild disabled={!menuItems?.length}>
58
- <Toolbar.IconButton
59
- iconOnly
60
- variant='ghost'
61
- icon='ph--dots-three-vertical--regular'
62
- label={t('action-menu.label')}
63
- />
64
- </Menu.Trigger>
65
- <Menu.Content items={menuItems} />
57
+ <Card.Block end>
58
+ <Menu.Trigger asChild disabled={!menuItems?.length}>
59
+ <IconButton
60
+ iconOnly
61
+ variant='ghost'
62
+ icon='ph--dots-three-vertical--regular'
63
+ label={t('action-menu.label')}
64
+ />
65
+ </Menu.Trigger>
66
+ <Menu.Content items={menuItems} />
67
+ </Card.Block>
66
68
  </Card.Header>
67
69
  <Card.Body>
68
70
  <Card.Row fullWidth>
@@ -22,7 +22,7 @@ export const translations = [
22
22
  'delete-object.label': 'Delete kanban',
23
23
  'object-deleted.label': 'Kanban deleted',
24
24
  },
25
- [meta.id]: {
25
+ [meta.profile.key]: {
26
26
  'action-menu.label': 'Actions',
27
27
  'plugin.name': 'Kanban',
28
28
  'kanban-title.label': 'Title',
@@ -12,7 +12,7 @@ import { Type, View, DXN } from '@dxos/echo';
12
12
 
13
13
  import { meta } from '#meta';
14
14
 
15
- const makeKey = (name: string) => DXN.make(`${meta.id}.operation.${name}`);
15
+ const makeKey = (name: string) => DXN.make(`${meta.profile.key}.operation.${name}`);
16
16
 
17
17
  export const DeleteCardFieldOutput = Schema.Struct({
18
18
  field: View.FieldSchema.annotations({ description: 'The deleted field schema.' }),
@@ -1,39 +0,0 @@
1
- // src/meta.ts
2
- import { Plugin } from "@dxos/app-framework";
3
- import { DXN } from "@dxos/echo";
4
- import { trim } from "@dxos/util";
5
- var meta = Plugin.makeMeta({
6
- key: DXN.make("org.dxos.plugin.kanban"),
7
- name: "Kanban",
8
- author: "DXOS",
9
- description: trim`
10
- Visual project management using customizable kanban boards to track workflow progress.
11
- Organize any ECHO type into drag-and-drop columns defined by a single-select field, move cards
12
- between stages, and reorder both columns and cards — all changes are persisted to ECHO and
13
- replicated to collaborators in real time.
14
-
15
- Kanban boards come in two variants: view-variant boards source their cards through a linked
16
- View query (any ECHO type can be pivoted on a single-select field), while items-variant boards
17
- own their cards explicitly and are used by external sync integrations such as Linear or GitHub.
18
- Both variants share the same arrangement storage and drag-and-drop mechanics.
19
-
20
- Board settings let users choose which single-select field drives the column layout and
21
- optionally hide the uncategorized column for items that have no pivot value.
22
- Field-level undo support allows deleted card fields to be restored without data loss.
23
-
24
- The plugin contributes a Kanban blueprint that exposes board creation and card management
25
- to AI agents, enabling automated project tracking workflows.
26
- `,
27
- icon: "ph--kanban--regular",
28
- iconHue: "green",
29
- source: "https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-kanban",
30
- spec: "PLUGIN.mdl",
31
- screenshots: [
32
- "https://dxos.network/plugin-details-kanban-dark.png"
33
- ]
34
- });
35
-
36
- export {
37
- meta
38
- };
39
- //# sourceMappingURL=chunk-6ZHHQWO5.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/meta.ts"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\nimport { DXN } from '@dxos/echo';\nimport { trim } from '@dxos/util';\n\nexport const meta = Plugin.makeMeta({\n key: DXN.make('org.dxos.plugin.kanban'),\n name: 'Kanban',\n author: 'DXOS',\n description: trim`\n Visual project management using customizable kanban boards to track workflow progress.\n Organize any ECHO type into drag-and-drop columns defined by a single-select field, move cards\n between stages, and reorder both columns and cards — all changes are persisted to ECHO and\n replicated to collaborators in real time.\n\n Kanban boards come in two variants: view-variant boards source their cards through a linked\n View query (any ECHO type can be pivoted on a single-select field), while items-variant boards\n own their cards explicitly and are used by external sync integrations such as Linear or GitHub.\n Both variants share the same arrangement storage and drag-and-drop mechanics.\n\n Board settings let users choose which single-select field drives the column layout and\n optionally hide the uncategorized column for items that have no pivot value.\n Field-level undo support allows deleted card fields to be restored without data loss.\n\n The plugin contributes a Kanban blueprint that exposes board creation and card management\n to AI agents, enabling automated project tracking workflows.\n `,\n icon: 'ph--kanban--regular',\n iconHue: 'green',\n source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-kanban',\n spec: 'PLUGIN.mdl',\n screenshots: ['https://dxos.network/plugin-details-kanban-dark.png'],\n});\n"],
5
- "mappings": ";AAIA,SAASA,cAAc;AACvB,SAASC,WAAW;AACpB,SAASC,YAAY;AAEd,IAAMC,OAAOH,OAAOI,SAAS;EAClCC,KAAKJ,IAAIK,KAAK,wBAAA;EACdC,MAAM;EACNC,QAAQ;EACRC,aAAaP;;;;;;;;;;;;;;;;;;EAkBbQ,MAAM;EACNC,SAAS;EACTC,QAAQ;EACRC,MAAM;EACNC,aAAa;IAAC;;AAChB,CAAA;",
6
- "names": ["Plugin", "DXN", "trim", "meta", "makeMeta", "key", "make", "name", "author", "description", "icon", "iconHue", "source", "spec", "screenshots"]
7
- }
@@ -1,8 +0,0 @@
1
- // src/operations/index.ts
2
- import { OperationHandlerSet } from "@dxos/compute";
3
- var KanbanOperationHandlerSet = OperationHandlerSet.lazy(() => import("./delete-card-VNAV3CZV.mjs"), () => import("./delete-card-field-XHOLGS6L.mjs"), () => import("./restore-card-EKVEPATL.mjs"), () => import("./restore-card-field-TQCTGGNO.mjs"));
4
-
5
- export {
6
- KanbanOperationHandlerSet
7
- };
8
- //# sourceMappingURL=chunk-M5ISZWZU.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/capabilities/react-surface.tsx"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport type * as Schema from 'effect/Schema';\nimport * as SchemaAST from 'effect/SchemaAST';\nimport React, { useMemo } from 'react';\n\nimport { Capabilities, Capability } from '@dxos/app-framework';\nimport { Surface } from '@dxos/app-framework/ui';\nimport { AppSurface } from '@dxos/app-toolkit/ui';\nimport { type Collection, Database, Obj, Type } from '@dxos/echo';\nimport { SchemaEx } from '@dxos/effect';\nimport { type FormFieldComponentProps, SelectField, useFormValues } from '@dxos/react-ui-form';\n\nimport { KanbanArticle, KanbanSettings } from '#containers';\nimport { Kanban, PivotColumnAnnotationId } from '#types';\n\nexport default Capability.makeModule(() =>\n Effect.succeed(\n Capability.contributes(Capabilities.ReactSurface, [\n Surface.create({\n id: 'root',\n // TODO(wittjosiah): Split into multiple surfaces if this filter proves too strict for non-article roles.\n filter: AppSurface.oneOf(\n AppSurface.object(AppSurface.Article, Kanban.Kanban),\n AppSurface.object(AppSurface.Section, Kanban.Kanban),\n ),\n component: ({ data, role }) => <KanbanArticle role={role} subject={data.subject} />,\n }),\n Surface.create({\n id: 'objectProperties',\n position: 'first',\n filter: AppSurface.object(AppSurface.ObjectProperties, Kanban.Kanban),\n component: ({ data }) => <KanbanSettings subject={data.subject} />,\n }),\n Surface.create({\n id: 'createInitialSchemaForm',\n role: 'form-input',\n filter: (\n data,\n ): data is {\n prop: string;\n schema: Schema.Schema<any>;\n target: Database.Database | Collection.Collection | undefined;\n fieldPropertyAst?: SchemaAST.AST;\n } => {\n const annotation = SchemaEx.findAnnotation<boolean>(\n (data.schema as Schema.Schema.All).ast,\n PivotColumnAnnotationId,\n );\n return !!annotation;\n },\n component: ({ data: { target, fieldPropertyAst }, ...inputProps }) => {\n const ast = fieldPropertyAst;\n if (!ast) {\n return null;\n }\n\n const props = { ...inputProps, type: ast } as any as FormFieldComponentProps;\n const db = Database.isDatabase(target) ? target : target && Obj.getDatabase(target);\n if (!db) {\n return null;\n }\n\n const { typename } = useFormValues('KanbanForm');\n const [selectedSchema] = useMemo(\n () =>\n db.graph.registry\n .list()\n .filter(Type.isType)\n .filter((t) => Type.getTypename(t) === typename),\n [db, typename],\n );\n const singleSelectColumns = useMemo(() => {\n if (!selectedSchema) {\n return [];\n }\n const jsonSchema = selectedSchema.jsonSchema;\n const properties = jsonSchema.properties;\n if (!properties) {\n return [];\n }\n\n const columns = Object.entries(properties).reduce<string[]>((acc, [key, value]) => {\n if (typeof value === 'object' && value?.format === 'single-select') {\n acc.push(key);\n }\n return acc;\n }, []);\n\n return columns;\n }, [selectedSchema]);\n\n if (!typename) {\n return null;\n }\n\n return <SelectField {...props} options={singleSelectColumns.map((column) => ({ value: column }))} />;\n },\n }),\n ]),\n ),\n);\n"],
5
- "mappings": ";;;AAIA,YAAYA,YAAY;AAGxB,OAAOC,SAASC,eAAe;AAE/B,SAASC,cAAcC,kBAAkB;AACzC,SAASC,eAAe;AACxB,SAASC,kBAAkB;AAC3B,SAA0BC,UAAUC,KAAKC,YAAY;AACrD,SAASC,gBAAgB;AACzB,SAAuCC,aAAaC,qBAAqB;AAEzE,SAASC,eAAeC,sBAAsB;AAC9C,SAASC,QAAQC,+BAA+B;AAEhD,IAAA,wBAAeZ,WAAWa,WAAW,MAC5BC,eACLd,WAAWe,YAAYhB,aAAaiB,cAAc;EAChDf,QAAQgB,OAAO;IACbC,IAAI;;IAEJC,QAAQjB,WAAWkB,MACjBlB,WAAWmB,OAAOnB,WAAWoB,SAASX,OAAOA,MAAM,GACnDT,WAAWmB,OAAOnB,WAAWqB,SAASZ,OAAOA,MAAM,CAAA;IAErDa,WAAW,CAAC,EAAEC,MAAMC,KAAI,MAAO,sBAAA,cAACjB,eAAAA;MAAciB;MAAYC,SAASF,KAAKE;;EAC1E,CAAA;EACA1B,QAAQgB,OAAO;IACbC,IAAI;IACJU,UAAU;IACVT,QAAQjB,WAAWmB,OAAOnB,WAAW2B,kBAAkBlB,OAAOA,MAAM;IACpEa,WAAW,CAAC,EAAEC,KAAI,MAAO,sBAAA,cAACf,gBAAAA;MAAeiB,SAASF,KAAKE;;EACzD,CAAA;EACA1B,QAAQgB,OAAO;IACbC,IAAI;IACJQ,MAAM;IACNP,QAAQ,CACNM,SAAAA;AAOA,YAAMK,aAAaxB,SAASyB,eACzBN,KAAKO,OAA6BC,KACnCrB,uBAAAA;AAEF,aAAO,CAAC,CAACkB;IACX;IACAN,WAAW,CAAC,EAAEC,MAAM,EAAES,QAAQC,iBAAgB,GAAI,GAAGC,WAAAA,MAAY;AAC/D,YAAMH,MAAME;AACZ,UAAI,CAACF,KAAK;AACR,eAAO;MACT;AAEA,YAAMI,QAAQ;QAAE,GAAGD;QAAYE,MAAML;MAAI;AACzC,YAAMM,KAAKpC,SAASqC,WAAWN,MAAAA,IAAUA,SAASA,UAAU9B,IAAIqC,YAAYP,MAAAA;AAC5E,UAAI,CAACK,IAAI;AACP,eAAO;MACT;AAEA,YAAM,EAAEG,SAAQ,IAAKlC,cAAc,YAAA;AACnC,YAAM,CAACmC,cAAAA,IAAkB7C,QACvB,MACEyC,GAAGK,MAAMC,SACNC,KAAI,EACJ3B,OAAOd,KAAK0C,MAAM,EAClB5B,OAAO,CAAC6B,MAAM3C,KAAK4C,YAAYD,CAAAA,MAAON,QAAAA,GAC3C;QAACH;QAAIG;OAAS;AAEhB,YAAMQ,sBAAsBpD,QAAQ,MAAA;AAClC,YAAI,CAAC6C,gBAAgB;AACnB,iBAAO,CAAA;QACT;AACA,cAAMQ,aAAaR,eAAeQ;AAClC,cAAMC,aAAaD,WAAWC;AAC9B,YAAI,CAACA,YAAY;AACf,iBAAO,CAAA;QACT;AAEA,cAAMC,UAAUC,OAAOC,QAAQH,UAAAA,EAAYI,OAAiB,CAACC,KAAK,CAACC,KAAKC,KAAAA,MAAM;AAC5E,cAAI,OAAOA,UAAU,YAAYA,OAAOC,WAAW,iBAAiB;AAClEH,gBAAII,KAAKH,GAAAA;UACX;AACA,iBAAOD;QACT,GAAG,CAAA,CAAE;AAEL,eAAOJ;MACT,GAAG;QAACV;OAAe;AAEnB,UAAI,CAACD,UAAU;AACb,eAAO;MACT;AAEA,aAAO,sBAAA,cAACnC,aAAAA;QAAa,GAAG8B;QAAOyB,SAASZ,oBAAoBa,IAAI,CAACC,YAAY;UAAEL,OAAOK;QAAO,EAAA;;IAC/F;EACF,CAAA;CACD,CAAA,CAAA;",
6
- "names": ["Effect", "React", "useMemo", "Capabilities", "Capability", "Surface", "AppSurface", "Database", "Obj", "Type", "SchemaEx", "SelectField", "useFormValues", "KanbanArticle", "KanbanSettings", "Kanban", "PivotColumnAnnotationId", "makeModule", "succeed", "contributes", "ReactSurface", "create", "id", "filter", "oneOf", "object", "Article", "Section", "component", "data", "role", "subject", "position", "ObjectProperties", "annotation", "findAnnotation", "schema", "ast", "target", "fieldPropertyAst", "inputProps", "props", "type", "db", "isDatabase", "getDatabase", "typename", "selectedSchema", "graph", "registry", "list", "isType", "t", "getTypename", "singleSelectColumns", "jsonSchema", "properties", "columns", "Object", "entries", "reduce", "acc", "key", "value", "format", "push", "options", "map", "column"]
7
- }