@dxos/plugin-kanban 0.8.4-main.2e9d522 → 0.8.4-main.3c1ae3b

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 (78) hide show
  1. package/dist/lib/browser/blueprint-definition-UYVX622Q.mjs +28 -0
  2. package/dist/lib/browser/blueprint-definition-UYVX622Q.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-X44RHBZK.mjs → chunk-PEQVHFOX.mjs} +35 -42
  4. package/dist/lib/browser/chunk-PEQVHFOX.mjs.map +7 -0
  5. package/dist/lib/browser/index.mjs +31 -33
  6. package/dist/lib/browser/index.mjs.map +3 -3
  7. package/dist/lib/browser/{intent-resolver-E6O3LBAB.mjs → intent-resolver-NHCWHMPW.mjs} +20 -20
  8. package/dist/lib/browser/intent-resolver-NHCWHMPW.mjs.map +7 -0
  9. package/dist/lib/browser/meta.json +1 -1
  10. package/dist/lib/browser/{react-surface-MWNNZYMN.mjs → react-surface-NSCKM4QW.mjs} +81 -98
  11. package/dist/lib/browser/react-surface-NSCKM4QW.mjs.map +7 -0
  12. package/dist/lib/browser/types/index.mjs +3 -3
  13. package/dist/lib/node-esm/blueprint-definition-42P47FUY.mjs +30 -0
  14. package/dist/lib/node-esm/blueprint-definition-42P47FUY.mjs.map +7 -0
  15. package/dist/lib/node-esm/{chunk-6WK5CGYY.mjs → chunk-LTCOYU73.mjs} +35 -42
  16. package/dist/lib/node-esm/chunk-LTCOYU73.mjs.map +7 -0
  17. package/dist/lib/node-esm/index.mjs +31 -33
  18. package/dist/lib/node-esm/index.mjs.map +3 -3
  19. package/dist/lib/node-esm/{intent-resolver-LPASDELU.mjs → intent-resolver-L2OEBOJW.mjs} +20 -20
  20. package/dist/lib/node-esm/intent-resolver-L2OEBOJW.mjs.map +7 -0
  21. package/dist/lib/node-esm/meta.json +1 -1
  22. package/dist/lib/node-esm/{react-surface-T52BBG45.mjs → react-surface-WXYTWOY2.mjs} +81 -98
  23. package/dist/lib/node-esm/react-surface-WXYTWOY2.mjs.map +7 -0
  24. package/dist/lib/node-esm/types/index.mjs +3 -3
  25. package/dist/types/src/KanbanPlugin.d.ts +1 -1
  26. package/dist/types/src/KanbanPlugin.d.ts.map +1 -1
  27. package/dist/types/src/capabilities/artifact-definition.d.ts +1 -1
  28. package/dist/types/src/capabilities/artifact-definition.d.ts.map +1 -1
  29. package/dist/types/src/capabilities/blueprint-definition.d.ts +5 -0
  30. package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -0
  31. package/dist/types/src/capabilities/index.d.ts +3 -3
  32. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  33. package/dist/types/src/capabilities/intent-resolver.d.ts +1 -1
  34. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  35. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  36. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  37. package/dist/types/src/components/KanbanContainer.d.ts +3 -3
  38. package/dist/types/src/components/KanbanContainer.d.ts.map +1 -1
  39. package/dist/types/src/components/KanbanContainer.stories.d.ts +50 -6
  40. package/dist/types/src/components/KanbanContainer.stories.d.ts.map +1 -1
  41. package/dist/types/src/components/KanbanViewEditor.d.ts +3 -3
  42. package/dist/types/src/components/KanbanViewEditor.d.ts.map +1 -1
  43. package/dist/types/src/meta.d.ts +0 -1
  44. package/dist/types/src/meta.d.ts.map +1 -1
  45. package/dist/types/src/translations.d.ts +21 -9
  46. package/dist/types/src/translations.d.ts.map +1 -1
  47. package/dist/types/src/types/index.d.ts +0 -1
  48. package/dist/types/src/types/index.d.ts.map +1 -1
  49. package/dist/types/src/types/schema.d.ts +15 -54
  50. package/dist/types/src/types/schema.d.ts.map +1 -1
  51. package/dist/types/tsconfig.tsbuildinfo +1 -1
  52. package/package.json +43 -40
  53. package/src/KanbanPlugin.tsx +49 -54
  54. package/src/capabilities/artifact-definition.ts +15 -11
  55. package/src/capabilities/blueprint-definition.ts +30 -0
  56. package/src/capabilities/index.ts +1 -1
  57. package/src/capabilities/intent-resolver.ts +11 -17
  58. package/src/capabilities/react-surface.tsx +24 -25
  59. package/src/components/KanbanContainer.stories.tsx +52 -73
  60. package/src/components/KanbanContainer.tsx +18 -31
  61. package/src/components/KanbanViewEditor.tsx +31 -37
  62. package/src/meta.ts +7 -5
  63. package/src/translations.ts +6 -6
  64. package/src/types/index.ts +0 -1
  65. package/src/types/schema.ts +22 -10
  66. package/dist/lib/browser/artifact-definition-WMSZK3RW.mjs +0 -174
  67. package/dist/lib/browser/artifact-definition-WMSZK3RW.mjs.map +0 -7
  68. package/dist/lib/browser/chunk-X44RHBZK.mjs.map +0 -7
  69. package/dist/lib/browser/intent-resolver-E6O3LBAB.mjs.map +0 -7
  70. package/dist/lib/browser/react-surface-MWNNZYMN.mjs.map +0 -7
  71. package/dist/lib/node-esm/artifact-definition-QVZXPDXK.mjs +0 -175
  72. package/dist/lib/node-esm/artifact-definition-QVZXPDXK.mjs.map +0 -7
  73. package/dist/lib/node-esm/chunk-6WK5CGYY.mjs.map +0 -7
  74. package/dist/lib/node-esm/intent-resolver-LPASDELU.mjs.map +0 -7
  75. package/dist/lib/node-esm/react-surface-T52BBG45.mjs.map +0 -7
  76. package/dist/types/src/types/kanban.d.ts +0 -11
  77. package/dist/types/src/types/kanban.d.ts.map +0 -1
  78. package/src/types/kanban.ts +0 -29
@@ -2,14 +2,12 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
- import { type StoryObj, type Meta } from '@storybook/react-vite';
8
- import React, { useCallback, useEffect, useState } from 'react';
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import React, { useCallback } from 'react';
9
7
 
10
8
  import { IntentPlugin, SettingsPlugin } from '@dxos/app-framework';
11
9
  import { withPluginManager } from '@dxos/app-framework/testing';
12
- import { Obj, Type } from '@dxos/echo';
10
+ import { Obj, type QueryAST, Type } from '@dxos/echo';
13
11
  import { invariant } from '@dxos/invariant';
14
12
  import { ClientPlugin } from '@dxos/plugin-client';
15
13
  import { PreviewPlugin } from '@dxos/plugin-preview';
@@ -18,17 +16,17 @@ import { SpacePlugin } from '@dxos/plugin-space';
18
16
  import { StorybookLayoutPlugin } from '@dxos/plugin-storybook-layout';
19
17
  import { ThemePlugin } from '@dxos/plugin-theme';
20
18
  import { faker } from '@dxos/random';
21
- import { useClient } from '@dxos/react-client';
22
- import { Filter, useSpaces, useQuery, useSchema } from '@dxos/react-client/echo';
19
+ import { Filter, useQuery, useSchema, useSpaces } from '@dxos/react-client/echo';
20
+ import { withTheme } from '@dxos/react-ui/testing';
23
21
  import { ViewEditor } from '@dxos/react-ui-form';
24
- import { Kanban, KanbanView, useKanbanModel } from '@dxos/react-ui-kanban';
25
- import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
22
+ import { Kanban as KanbanComponent, useKanbanModel, useProjectionModel } from '@dxos/react-ui-kanban';
23
+ import { Kanban } from '@dxos/react-ui-kanban/types';
24
+ import { JsonFilter } from '@dxos/react-ui-syntax-highlighter';
26
25
  import { defaultTx } from '@dxos/react-ui-theme';
27
- import { DataType, ProjectionModel } from '@dxos/schema';
28
- import { withLayout } from '@dxos/storybook-utils';
26
+ import { View, getTypenameFromQuery } from '@dxos/schema';
27
+ import { Organization, Person } from '@dxos/types';
29
28
 
30
29
  import { translations } from '../translations';
31
- import { createKanban } from '../types';
32
30
 
33
31
  faker.seed(0);
34
32
 
@@ -41,40 +39,22 @@ const rollOrg = () => ({
41
39
  description: faker.lorem.paragraph(),
42
40
  image: faker.image.url(),
43
41
  website: faker.internet.url(),
44
- status: faker.helpers.arrayElement(DataType.OrganizationStatusOptions).id as DataType.Organization['status'],
42
+ status: faker.helpers.arrayElement(Organization.StatusOptions).id as Organization.Organization['status'],
45
43
  });
46
44
 
47
45
  const StorybookKanban = () => {
48
- const client = useClient();
49
46
  const spaces = useSpaces();
50
47
  const space = spaces[spaces.length - 1];
51
- const views = useQuery(space, Filter.type(DataType.View));
52
- const [view, setView] = useState<DataType.View>();
53
- const [projection, setProjection] = useState<ProjectionModel>();
54
- const schema = useSchema(client, space, view?.query.typename);
55
-
56
- useEffect(() => {
57
- if (views.length && !view) {
58
- const view = views[0];
59
- setView(view);
60
- }
61
- }, [views]);
62
-
63
- useEffect(() => {
64
- if (view?.projection && schema) {
65
- const jsonSchema = Type.toJsonSchema(schema);
66
- setProjection(new ProjectionModel(jsonSchema, view.projection));
67
- }
68
- // TODO(ZaymonFC): Is there a better way to get notified about deep changes in the json schema?
69
- // @dmaretskyi? Once resolved, update in multiple places (e.g., storybooks).
70
- }, [view?.projection, schema, JSON.stringify(schema ? Type.toJsonSchema(schema) : {})]);
48
+ const [object] = useQuery(space, Filter.type(Kanban.Kanban));
49
+ const typename = object?.view.target?.query ? getTypenameFromQuery(object.view.target.query.ast) : undefined;
50
+ const schema = useSchema(space, typename);
71
51
 
72
52
  const objects = useQuery(space, schema ? Filter.type(schema) : Filter.nothing());
73
53
  const filteredObjects = useGlobalFilteredObjects(objects);
74
54
 
55
+ const projection = useProjectionModel(schema, object);
75
56
  const model = useKanbanModel({
76
- view,
77
- schema,
57
+ object,
78
58
  projection,
79
59
  items: filteredObjects,
80
60
  });
@@ -95,95 +75,94 @@ const StorybookKanban = () => {
95
75
  [space, schema, model],
96
76
  );
97
77
 
98
- const handleRemoveCard = useCallback((card: { id: string }) => space.db.remove(card), [space]);
78
+ const handleRemoveCard = useCallback((card: { id: string }) => Obj.isObject(card) && space?.db.remove(card), [space]);
99
79
 
100
- const handleTypenameChanged = useCallback(
101
- (typename: string) => {
80
+ const handleUpdateQuery = useCallback(
81
+ (newQuery: QueryAST.Query) => {
102
82
  invariant(schema);
103
83
  invariant(Type.isMutable(schema));
104
- invariant(view);
84
+ invariant(object.view.target);
105
85
 
106
- schema.updateTypename(typename);
107
- view.query.typename = typename;
86
+ schema.updateTypename(getTypenameFromQuery(newQuery));
87
+ object.view.target.query.ast = newQuery;
108
88
  },
109
- [view, schema],
89
+ [object, schema],
110
90
  );
111
91
 
112
- if (!schema || !view) {
92
+ if (!schema || !object.view.target) {
113
93
  return null;
114
94
  }
115
95
 
116
96
  return (
117
- <div className='grow grid grid-cols-[1fr_350px]'>
118
- {model ? <Kanban model={model} onAddCard={handleAddCard} onRemoveCard={handleRemoveCard} /> : <div />}
119
- <div className='flex flex-col bs-full border-is border-separator overflow-y-auto'>
97
+ <div className='grow grid grid-cols-[1fr_350px] overflow-hidden'>
98
+ {model ? <KanbanComponent model={model} onAddCard={handleAddCard} onRemoveCard={handleRemoveCard} /> : <div />}
99
+ <div className='flex flex-col bs-full overflow-hidden'>
120
100
  <ViewEditor
121
101
  registry={space?.db.schemaRegistry}
122
102
  schema={schema}
123
- view={view}
124
- onTypenameChanged={handleTypenameChanged}
103
+ view={object.view.target}
104
+ onQueryChanged={handleUpdateQuery}
125
105
  onDelete={(fieldId: string) => {
126
106
  console.log('[ViewEditor]', 'onDelete', fieldId);
127
107
  }}
128
108
  />
129
- <SyntaxHighlighter language='json' className='w-full text-xs'>
130
- {JSON.stringify({ view, schema }, null, 2)}
131
- </SyntaxHighlighter>
109
+ <JsonFilter data={{ view: object.view.target, schema }} classNames='text-xs' />
132
110
  </div>
133
111
  </div>
134
112
  );
135
113
  };
136
114
 
137
- type StoryProps = {
138
- rows?: number;
139
- };
140
-
141
115
  //
142
116
  // Story definitions.
143
117
  //
144
118
 
145
- const meta: Meta<StoryProps> = {
119
+ const meta = {
146
120
  title: 'plugins/plugin-kanban/Kanban',
147
121
  component: StorybookKanban,
148
122
  render: () => <StorybookKanban />,
149
- parameters: { translations },
150
123
  decorators: [
151
- withLayout({ fullscreen: true }),
124
+ withTheme,
152
125
  withPluginManager({
153
126
  plugins: [
154
- ThemePlugin({ tx: defaultTx }),
155
127
  ClientPlugin({
156
- types: [DataType.Organization, DataType.Person, DataType.View, KanbanView],
157
- onClientInitialized: async (_, client) => {
128
+ types: [Organization.Organization, Person.Person, View.View, Kanban.Kanban],
129
+ onClientInitialized: async ({ client }) => {
158
130
  await client.halo.createIdentity();
159
131
  const space = await client.spaces.create();
160
132
  await space.waitUntilReady();
161
- const { view } = await createKanban({
162
- client,
133
+ const { view } = await View.makeFromSpace({
163
134
  space,
164
- typename: DataType.Organization.typename,
165
- initialPivotColumn: 'status',
135
+ typename: Organization.Organization.typename,
136
+ pivotFieldName: 'status',
166
137
  });
167
- space.db.add(view);
138
+ const kanban = Kanban.make({ view });
139
+ space.db.add(kanban);
168
140
 
169
141
  // TODO(burdon): Replace with sdk/schema/testing.
170
142
  Array.from({ length: 80 }).map(() => {
171
- return space.db.add(Obj.make(DataType.Organization, rollOrg()));
143
+ return space.db.add(Obj.make(Organization.Organization, rollOrg()));
172
144
  });
173
145
  },
174
146
  }),
175
- StorybookLayoutPlugin(),
176
- PreviewPlugin(),
177
- SpacePlugin(),
147
+ SpacePlugin({}),
178
148
  IntentPlugin(),
179
149
  SettingsPlugin(),
150
+
151
+ // UI
152
+ ThemePlugin({ tx: defaultTx }),
153
+ PreviewPlugin(),
154
+ StorybookLayoutPlugin({}),
180
155
  ],
181
156
  }),
182
157
  ],
183
- };
158
+ parameters: {
159
+ layout: 'fullscreen',
160
+ translations,
161
+ },
162
+ } satisfies Meta<typeof StorybookKanban>;
184
163
 
185
164
  export default meta;
186
165
 
187
- type Story = StoryObj<StoryProps>;
166
+ type Story = StoryObj<typeof meta>;
188
167
 
189
168
  export const Default: Story = {};
@@ -2,37 +2,31 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import React, { useCallback, useEffect, useMemo, useState } from 'react';
5
+ import React, { useCallback, useEffect, useState } from 'react';
6
6
 
7
- import { createIntent, useIntentDispatcher } from '@dxos/app-framework';
7
+ import { createIntent } from '@dxos/app-framework';
8
+ import { useCapabilities, useIntentDispatcher } from '@dxos/app-framework/react';
8
9
  import { Filter, Obj, Type } from '@dxos/echo';
9
- import { EchoSchema, type TypedObject } from '@dxos/echo-schema';
10
+ import { type TypedObject } from '@dxos/echo/internal';
11
+ import { ClientCapabilities } from '@dxos/plugin-client';
10
12
  import { useGlobalFilteredObjects } from '@dxos/plugin-search';
11
- import { useClient } from '@dxos/react-client';
12
- import { useQuery, getSpace } from '@dxos/react-client/echo';
13
- import { useKanbanModel, Kanban } from '@dxos/react-ui-kanban';
13
+ import { getSpace, useQuery } from '@dxos/react-client/echo';
14
+ import { Kanban as KanbanComponent, useKanbanModel, useProjectionModel } from '@dxos/react-ui-kanban';
15
+ import { type Kanban } from '@dxos/react-ui-kanban/types';
14
16
  import { StackItem } from '@dxos/react-ui-stack';
15
- import { ProjectionModel, type DataType } from '@dxos/schema';
17
+ import { getTypenameFromQuery } from '@dxos/schema';
16
18
 
17
19
  import { KanbanAction } from '../types';
18
20
 
19
- export const KanbanContainer = ({ view }: { view: DataType.View; role: string }) => {
20
- const client = useClient();
21
+ export const KanbanContainer = ({ object }: { object: Kanban.Kanban; role: string }) => {
22
+ const schemas = useCapabilities(ClientCapabilities.Schema);
21
23
  const [cardSchema, setCardSchema] = useState<TypedObject<any, any>>();
22
- const [projection, setProjection] = useState<ProjectionModel>();
23
- const space = getSpace(view);
24
+ const space = getSpace(object);
24
25
  const { dispatchPromise: dispatch } = useIntentDispatcher();
25
-
26
- const jsonSchema = useMemo(() => {
27
- if (!cardSchema) {
28
- return undefined;
29
- }
30
- return cardSchema instanceof EchoSchema ? cardSchema.jsonSchema : Type.toJsonSchema(cardSchema);
31
- }, [cardSchema]);
26
+ const typename = object.view.target?.query ? getTypenameFromQuery(object.view.target.query.ast) : undefined;
32
27
 
33
28
  useEffect(() => {
34
- const typename = view.query.typename;
35
- const staticSchema = client.graph.schemaRegistry.schemas.find((schema) => Type.getTypename(schema) === typename);
29
+ const staticSchema = schemas.flat().find((schema) => Type.getTypename(schema) === typename);
36
30
  if (staticSchema) {
37
31
  setCardSchema(() => staticSchema as TypedObject<any, any>);
38
32
  }
@@ -49,21 +43,14 @@ export const KanbanContainer = ({ view }: { view: DataType.View; role: string })
49
43
  );
50
44
  return unsubscribe;
51
45
  }
52
- }, [view.query.typename, space]);
53
-
54
- useEffect(() => {
55
- if (jsonSchema) {
56
- setProjection(new ProjectionModel(jsonSchema, view.projection));
57
- }
58
- // TODO(ZaymonFC): Is there a better way to get notified about deep changes in the json schema?
59
- }, [view.projection, JSON.stringify(jsonSchema)]);
46
+ }, [schemas, space, typename]);
60
47
 
61
48
  const objects = useQuery(space, cardSchema ? Filter.type(cardSchema) : Filter.nothing());
62
49
  const filteredObjects = useGlobalFilteredObjects(objects);
63
50
 
51
+ const projection = useProjectionModel(cardSchema, object);
64
52
  const model = useKanbanModel({
65
- view,
66
- schema: cardSchema,
53
+ object,
67
54
  projection,
68
55
  items: filteredObjects,
69
56
  });
@@ -89,7 +76,7 @@ export const KanbanContainer = ({ view }: { view: DataType.View; role: string })
89
76
 
90
77
  return (
91
78
  <StackItem.Content>
92
- {model && <Kanban model={model} onAddCard={handleAddCard} onRemoveCard={handleRemoveCard} />}
79
+ {model && <KanbanComponent model={model} onAddCard={handleAddCard} onRemoveCard={handleRemoveCard} />}
93
80
  </StackItem.Content>
94
81
  );
95
82
  };
@@ -4,57 +4,51 @@
4
4
 
5
5
  import React, { useCallback, useMemo } from 'react';
6
6
 
7
- import { Type } from '@dxos/echo';
8
- import { EchoSchema, FormatEnum } from '@dxos/echo-schema';
9
- import { useClient } from '@dxos/react-client';
7
+ import { Format } from '@dxos/echo/internal';
8
+ import { invariant } from '@dxos/invariant';
10
9
  import { getSpace, useSchema } from '@dxos/react-client/echo';
11
- import { Form, SelectInput, type CustomInputMap } from '@dxos/react-ui-form';
12
- import { KanbanSettingsSchema, type KanbanView } from '@dxos/react-ui-kanban';
13
- import { type DataType, ProjectionModel } from '@dxos/schema';
14
-
15
- type KanbanViewEditorProps = { view: DataType.View };
16
-
17
- export const KanbanViewEditor = ({ view }: KanbanViewEditorProps) => {
18
- const client = useClient();
19
- const space = getSpace(view);
20
- const kanban = view.presentation.target as KanbanView;
21
- const currentTypename = useMemo(() => view.query.typename, [view.query.typename]);
22
- const schema = useSchema(client, space, currentTypename);
23
-
24
- const projection = useMemo(() => {
25
- if (schema) {
26
- const jsonSchema = schema instanceof EchoSchema ? schema.jsonSchema : Type.toJsonSchema(schema);
27
- return new ProjectionModel(jsonSchema, view.projection);
28
- }
29
- }, [view.projection, JSON.stringify(schema)]);
10
+ import { Form, type FormFieldMap, SelectField } from '@dxos/react-ui-form';
11
+ import { useProjectionModel } from '@dxos/react-ui-kanban';
12
+ import { type Kanban } from '@dxos/react-ui-kanban/types';
13
+ import { getTypenameFromQuery } from '@dxos/schema';
14
+
15
+ import { SettingsSchema } from '../types';
16
+
17
+ type KanbanViewEditorProps = { object: Kanban.Kanban };
18
+
19
+ export const KanbanViewEditor = ({ object }: KanbanViewEditorProps) => {
20
+ const space = getSpace(object);
21
+ const view = object.view.target;
22
+ const currentTypename = view?.query ? getTypenameFromQuery(view.query.ast) : undefined;
23
+ const schema = useSchema(space, currentTypename);
24
+ const projection = useProjectionModel(schema, object);
30
25
 
31
26
  const fieldProjections = projection?.getFieldProjections() || [];
32
27
  const selectFields = fieldProjections
33
- .filter((field) => field.props.format === FormatEnum.SingleSelect)
28
+ .filter((field) => field.props.format === Format.TypeFormat.SingleSelect)
34
29
  .map(({ field }) => ({ value: field.id, label: field.path }));
35
30
 
36
31
  const handleSave = useCallback(
37
32
  (values: Partial<{ columnFieldId: string }>) => {
38
- kanban.columnFieldId = values.columnFieldId;
33
+ invariant(view);
34
+ view.projection.pivotFieldId = values.columnFieldId;
39
35
  },
40
- [kanban],
36
+ [view],
37
+ );
38
+
39
+ const initialValues = useMemo(
40
+ () => ({ columnFieldId: view?.projection.pivotFieldId }),
41
+ [view?.projection.pivotFieldId],
41
42
  );
42
43
 
43
- const initialValues = useMemo(() => ({ columnFieldId: kanban.columnFieldId }), [kanban.columnFieldId]);
44
- const custom: CustomInputMap = useMemo(
45
- () => ({ columnFieldId: (props) => <SelectInput {...props} options={selectFields} /> }),
44
+ const fieldMap: FormFieldMap = useMemo(
45
+ () => ({ columnFieldId: (props) => <SelectField {...props} options={selectFields} /> }),
46
46
  [selectFields],
47
47
  );
48
48
 
49
49
  return (
50
- <Form
51
- Custom={custom}
52
- schema={KanbanSettingsSchema}
53
- values={initialValues}
54
- onSave={handleSave}
55
- autoSave
56
- outerSpacing={false}
57
- classNames='pbs-inputSpacingBlock'
58
- />
50
+ <Form.Root schema={SettingsSchema} values={initialValues} fieldMap={fieldMap} autoSave onSave={handleSave}>
51
+ <Form.FieldSet />
52
+ </Form.Root>
59
53
  );
60
54
  };
package/src/meta.ts CHANGED
@@ -3,15 +3,17 @@
3
3
  //
4
4
 
5
5
  import { type PluginMeta } from '@dxos/app-framework';
6
-
7
- export const KANBAN_PLUGIN = 'dxos.org/plugin/kanban';
6
+ import { trim } from '@dxos/util';
8
7
 
9
8
  export const meta: PluginMeta = {
10
- id: KANBAN_PLUGIN,
9
+ id: 'dxos.org/plugin/kanban',
11
10
  name: 'Kanban',
12
- description:
13
- 'Kanban allows you to explore Table data in sorted columns defined by your custom schema. You can use Kanbans to track progress or trigger custom automations when cards are moved from one state to another.',
11
+ description: trim`
12
+ Visual project management using customizable kanban boards to track workflow progress.
13
+ Organize table data into columns, drag and drop items between stages, and trigger automations based on status changes.
14
+ `,
14
15
  icon: 'ph--kanban--regular',
16
+ iconHue: 'green',
15
17
  source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-kanban',
16
18
  screenshots: ['https://dxos.network/plugin-details-kanban-dark.png'],
17
19
  };
@@ -2,32 +2,32 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
+ import { Type } from '@dxos/echo';
5
6
  import { type Resource } from '@dxos/react-ui';
6
- import { KanbanView } from '@dxos/react-ui-kanban';
7
+ import { Kanban } from '@dxos/react-ui-kanban/types';
7
8
 
8
9
  import { meta } from './meta';
9
10
 
10
11
  export const translations = [
11
12
  {
12
13
  'en-US': {
13
- [KanbanView.typename]: {
14
+ [Type.getTypename(Kanban.Kanban)]: {
14
15
  'typename label': 'Kanban',
15
16
  'typename label_zero': 'Kanbans',
16
17
  'typename label_one': 'Kanban',
17
18
  'typename label_other': 'Kanbans',
18
19
  'object name placeholder': 'New kanban',
20
+ 'rename object label': 'Rename kanban',
21
+ 'delete object label': 'Delete kanban',
22
+ 'object deleted label': 'Kanban deleted',
19
23
  },
20
24
  [meta.id]: {
21
25
  'plugin name': 'Kanban',
22
26
  'kanban title label': 'Title',
23
27
  'column title label': 'Column title',
24
28
  'column title placeholder': 'New column',
25
- 'item title label': 'Item title',
26
- 'item title placeholder': 'New item',
27
29
  'add column label': 'Add column',
28
- 'add item label': 'Add card',
29
30
  'delete column label': 'Delete column',
30
- 'delete item label': 'Delete card',
31
31
  'card field deleted label': 'Card field deleted',
32
32
  'card deleted label': 'Card deleted',
33
33
  },
@@ -2,6 +2,5 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export * from './kanban';
6
5
  export * from './schema';
7
6
  export type * from './types';
@@ -2,12 +2,14 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
5
+ import * as Schema from 'effect/Schema';
6
6
 
7
+ import { TypeInputOptionsAnnotation } from '@dxos/plugin-space/types';
7
8
  import { SpaceSchema } from '@dxos/react-client/echo';
8
- import { DataType, FieldSchema, TypenameAnnotationId } from '@dxos/schema';
9
+ import { Kanban } from '@dxos/react-ui-kanban/types';
10
+ import { FieldSchema, View } from '@dxos/schema';
9
11
 
10
- import { KANBAN_PLUGIN } from '../meta';
12
+ import { meta } from '../meta';
11
13
 
12
14
  /**
13
15
  * Kanban data model.
@@ -21,13 +23,23 @@ import { KANBAN_PLUGIN } from '../meta';
21
23
  // TODO(wittjosiah): Factor out?
22
24
  export const PivotColumnAnnotationId = Symbol.for('@dxos/plugin-kanban/annotation/PivotColumn');
23
25
 
26
+ export const SettingsSchema = Schema.Struct({
27
+ columnFieldId: Schema.String.annotations({
28
+ title: 'Column field',
29
+ }),
30
+ });
31
+
24
32
  export const CreateKanbanSchema = Schema.Struct({
25
33
  name: Schema.optional(Schema.String),
26
- typename: Schema.optional(
27
- Schema.String.annotations({
28
- [TypenameAnnotationId]: ['limited-static', 'dynamic'],
29
- title: 'Select card schema (leave empty to start fresh)',
34
+ // TODO(wittjosiah): This should be a query input instead.
35
+ typename: Schema.String.pipe(
36
+ Schema.annotations({ title: 'Select card type' }),
37
+ TypeInputOptionsAnnotation.set({
38
+ location: ['database', 'runtime'],
39
+ kind: ['user'],
40
+ registered: ['registered'],
30
41
  }),
42
+ Schema.optional,
31
43
  ),
32
44
  initialPivotColumn: Schema.optional(
33
45
  Schema.String.annotations({
@@ -38,18 +50,18 @@ export const CreateKanbanSchema = Schema.Struct({
38
50
  });
39
51
 
40
52
  export namespace KanbanAction {
41
- const KANBAN_ACTION = `${KANBAN_PLUGIN}/action`;
53
+ const KANBAN_ACTION = `${meta.id}/action`;
42
54
 
43
55
  export class Create extends Schema.TaggedClass<Create>()(`${KANBAN_ACTION}/create`, {
44
56
  input: Schema.extend(Schema.Struct({ space: SpaceSchema }), CreateKanbanSchema),
45
57
  output: Schema.Struct({
46
- object: DataType.View,
58
+ object: Kanban.Kanban,
47
59
  }),
48
60
  }) {}
49
61
 
50
62
  export class DeleteCardField extends Schema.TaggedClass<DeleteCardField>()(`${KANBAN_ACTION}/delete-card-field`, {
51
63
  input: Schema.Struct({
52
- view: DataType.View,
64
+ view: View.View,
53
65
  fieldId: Schema.String,
54
66
  // TODO(wittjosiah): Separate fields for undo data?
55
67
  deletionData: Schema.optional(