@dxos/plugin-kanban 0.8.4-main.5ad4a44 → 0.8.4-main.66e292d

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 (54) hide show
  1. package/dist/lib/browser/{chunk-K7KYFJ3P.mjs → chunk-B7EZTXV2.mjs} +32 -11
  2. package/dist/lib/browser/chunk-B7EZTXV2.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +23 -24
  4. package/dist/lib/browser/index.mjs.map +3 -3
  5. package/dist/lib/browser/{intent-resolver-LR3SDMKQ.mjs → intent-resolver-ANBDVEJ2.mjs} +11 -8
  6. package/dist/lib/browser/intent-resolver-ANBDVEJ2.mjs.map +7 -0
  7. package/dist/lib/browser/meta.json +1 -1
  8. package/dist/lib/browser/{react-surface-R2ORFB43.mjs → react-surface-7ONRKYBB.mjs} +60 -73
  9. package/dist/lib/browser/react-surface-7ONRKYBB.mjs.map +7 -0
  10. package/dist/lib/browser/types/index.mjs +5 -3
  11. package/dist/lib/node-esm/{chunk-VDWYSHP4.mjs → chunk-WBN5YQGD.mjs} +32 -11
  12. package/dist/lib/node-esm/chunk-WBN5YQGD.mjs.map +7 -0
  13. package/dist/lib/node-esm/index.mjs +23 -24
  14. package/dist/lib/node-esm/index.mjs.map +3 -3
  15. package/dist/lib/node-esm/{intent-resolver-CKDNVLND.mjs → intent-resolver-X4UZDRI7.mjs} +11 -8
  16. package/dist/lib/node-esm/intent-resolver-X4UZDRI7.mjs.map +7 -0
  17. package/dist/lib/node-esm/meta.json +1 -1
  18. package/dist/lib/node-esm/{react-surface-RMRLHCOY.mjs → react-surface-D7XTGTZL.mjs} +60 -73
  19. package/dist/lib/node-esm/react-surface-D7XTGTZL.mjs.map +7 -0
  20. package/dist/lib/node-esm/types/index.mjs +5 -3
  21. package/dist/types/src/KanbanPlugin.d.ts.map +1 -1
  22. package/dist/types/src/capabilities/artifact-definition.d.ts.map +1 -1
  23. package/dist/types/src/capabilities/blueprint-definition.d.ts +1 -1
  24. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  25. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  26. package/dist/types/src/components/KanbanContainer.d.ts +3 -3
  27. package/dist/types/src/components/KanbanContainer.d.ts.map +1 -1
  28. package/dist/types/src/components/KanbanContainer.stories.d.ts +21 -8
  29. package/dist/types/src/components/KanbanContainer.stories.d.ts.map +1 -1
  30. package/dist/types/src/components/KanbanViewEditor.d.ts +3 -3
  31. package/dist/types/src/components/KanbanViewEditor.d.ts.map +1 -1
  32. package/dist/types/src/meta.d.ts.map +1 -1
  33. package/dist/types/src/translations.d.ts +21 -9
  34. package/dist/types/src/translations.d.ts.map +1 -1
  35. package/dist/types/src/types/schema.d.ts +7 -3
  36. package/dist/types/src/types/schema.d.ts.map +1 -1
  37. package/dist/types/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +33 -32
  39. package/src/KanbanPlugin.tsx +10 -15
  40. package/src/capabilities/artifact-definition.ts +6 -6
  41. package/src/capabilities/intent-resolver.ts +4 -9
  42. package/src/capabilities/react-surface.tsx +18 -19
  43. package/src/components/KanbanContainer.stories.tsx +25 -41
  44. package/src/components/KanbanContainer.tsx +13 -26
  45. package/src/components/KanbanViewEditor.tsx +18 -21
  46. package/src/meta.ts +6 -2
  47. package/src/translations.ts +5 -5
  48. package/src/types/schema.ts +19 -7
  49. package/dist/lib/browser/chunk-K7KYFJ3P.mjs.map +0 -7
  50. package/dist/lib/browser/intent-resolver-LR3SDMKQ.mjs.map +0 -7
  51. package/dist/lib/browser/react-surface-R2ORFB43.mjs.map +0 -7
  52. package/dist/lib/node-esm/chunk-VDWYSHP4.mjs.map +0 -7
  53. package/dist/lib/node-esm/intent-resolver-CKDNVLND.mjs.map +0 -7
  54. package/dist/lib/node-esm/react-surface-RMRLHCOY.mjs.map +0 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-kanban",
3
- "version": "0.8.4-main.5ad4a44",
3
+ "version": "0.8.4-main.66e292d",
4
4
  "description": "Kanban DXOS Surface plugin",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -38,48 +38,49 @@
38
38
  "@preact-signals/safe-react": "^0.9.0",
39
39
  "@preact/signals-core": "^1.12.1",
40
40
  "effect": "3.18.3",
41
- "@dxos/ai": "0.8.4-main.5ad4a44",
42
- "@dxos/app-framework": "0.8.4-main.5ad4a44",
43
- "@dxos/assistant": "0.8.4-main.5ad4a44",
44
- "@dxos/async": "0.8.4-main.5ad4a44",
45
- "@dxos/echo": "0.8.4-main.5ad4a44",
46
- "@dxos/functions": "0.8.4-main.5ad4a44",
47
- "@dxos/invariant": "0.8.4-main.5ad4a44",
48
- "@dxos/log": "0.8.4-main.5ad4a44",
49
- "@dxos/plugin-client": "0.8.4-main.5ad4a44",
50
- "@dxos/effect": "0.8.4-main.5ad4a44",
51
- "@dxos/plugin-graph": "0.8.4-main.5ad4a44",
52
- "@dxos/plugin-search": "0.8.4-main.5ad4a44",
53
- "@dxos/plugin-space": "0.8.4-main.5ad4a44",
54
- "@dxos/blueprints": "0.8.4-main.5ad4a44",
55
- "@dxos/react-ui": "0.8.4-main.5ad4a44",
56
- "@dxos/react-ui-form": "0.8.4-main.5ad4a44",
57
- "@dxos/react-ui-kanban": "0.8.4-main.5ad4a44",
58
- "@dxos/random": "0.8.4-main.5ad4a44",
59
- "@dxos/util": "0.8.4-main.5ad4a44",
60
- "@dxos/schema": "0.8.4-main.5ad4a44",
61
- "@dxos/react-ui-stack": "0.8.4-main.5ad4a44",
62
- "@dxos/react-client": "0.8.4-main.5ad4a44"
41
+ "@dxos/app-framework": "0.8.4-main.66e292d",
42
+ "@dxos/assistant": "0.8.4-main.66e292d",
43
+ "@dxos/blueprints": "0.8.4-main.66e292d",
44
+ "@dxos/echo": "0.8.4-main.66e292d",
45
+ "@dxos/effect": "0.8.4-main.66e292d",
46
+ "@dxos/invariant": "0.8.4-main.66e292d",
47
+ "@dxos/functions": "0.8.4-main.66e292d",
48
+ "@dxos/async": "0.8.4-main.66e292d",
49
+ "@dxos/ai": "0.8.4-main.66e292d",
50
+ "@dxos/log": "0.8.4-main.66e292d",
51
+ "@dxos/plugin-client": "0.8.4-main.66e292d",
52
+ "@dxos/plugin-search": "0.8.4-main.66e292d",
53
+ "@dxos/plugin-graph": "0.8.4-main.66e292d",
54
+ "@dxos/random": "0.8.4-main.66e292d",
55
+ "@dxos/react-client": "0.8.4-main.66e292d",
56
+ "@dxos/react-ui": "0.8.4-main.66e292d",
57
+ "@dxos/react-ui-form": "0.8.4-main.66e292d",
58
+ "@dxos/react-ui-kanban": "0.8.4-main.66e292d",
59
+ "@dxos/react-ui-stack": "0.8.4-main.66e292d",
60
+ "@dxos/schema": "0.8.4-main.66e292d",
61
+ "@dxos/plugin-space": "0.8.4-main.66e292d",
62
+ "@dxos/types": "0.8.4-main.66e292d",
63
+ "@dxos/util": "0.8.4-main.66e292d"
63
64
  },
64
65
  "devDependencies": {
65
66
  "@types/react": "~19.2.2",
66
- "@types/react-dom": "~19.2.1",
67
+ "@types/react-dom": "~19.2.2",
67
68
  "react": "~19.2.0",
68
69
  "react-dom": "~19.2.0",
69
70
  "vite": "7.1.9",
70
- "@dxos/plugin-preview": "0.8.4-main.5ad4a44",
71
- "@dxos/react-ui-syntax-highlighter": "0.8.4-main.5ad4a44",
72
- "@dxos/react-ui-theme": "0.8.4-main.5ad4a44",
73
- "@dxos/plugin-theme": "0.8.4-main.5ad4a44",
74
- "@dxos/test-utils": "0.8.4-main.5ad4a44",
75
- "@dxos/storybook-utils": "0.8.4-main.5ad4a44"
71
+ "@dxos/plugin-preview": "0.8.4-main.66e292d",
72
+ "@dxos/plugin-theme": "0.8.4-main.66e292d",
73
+ "@dxos/react-ui-syntax-highlighter": "0.8.4-main.66e292d",
74
+ "@dxos/react-ui-theme": "0.8.4-main.66e292d",
75
+ "@dxos/storybook-utils": "0.8.4-main.66e292d",
76
+ "@dxos/test-utils": "0.8.4-main.66e292d"
76
77
  },
77
78
  "peerDependencies": {
78
79
  "effect": "^3.13.3",
79
80
  "react": "^19.0.0",
80
81
  "react-dom": "^19.0.0",
81
- "@dxos/react-ui": "0.8.4-main.5ad4a44",
82
- "@dxos/react-ui-theme": "0.8.4-main.5ad4a44"
82
+ "@dxos/react-ui": "0.8.4-main.66e292d",
83
+ "@dxos/react-ui-theme": "0.8.4-main.66e292d"
83
84
  },
84
85
  "publishConfig": {
85
86
  "access": "public"
@@ -3,9 +3,9 @@
3
3
  //
4
4
 
5
5
  import { Capabilities, Events, contributes, createIntent, defineModule, definePlugin } from '@dxos/app-framework';
6
- import { ClientEvents } from '@dxos/plugin-client';
7
- import { SpaceCapabilities } from '@dxos/plugin-space';
8
- import { defineObjectForm } from '@dxos/plugin-space/types';
6
+ import { Type } from '@dxos/echo';
7
+ import { ClientCapabilities, ClientEvents } from '@dxos/plugin-client';
8
+ import { type CreateObjectIntent } from '@dxos/plugin-space/types';
9
9
  import { translations as kanbanTranslations } from '@dxos/react-ui-kanban';
10
10
  import { Kanban } from '@dxos/react-ui-kanban/types';
11
11
 
@@ -25,25 +25,20 @@ export const KanbanPlugin = definePlugin(meta, () => [
25
25
  activatesOn: Events.SetupMetadata,
26
26
  activate: () =>
27
27
  contributes(Capabilities.Metadata, {
28
- id: Kanban.Kanban.typename,
28
+ id: Type.getTypename(Kanban.Kanban),
29
29
  metadata: {
30
30
  icon: 'ph--kanban--regular',
31
+ iconHue: 'green',
32
+ inputSchema: CreateKanbanSchema,
33
+ createObjectIntent: ((props, options) =>
34
+ createIntent(KanbanAction.Create, { ...props, space: options.space })) satisfies CreateObjectIntent,
31
35
  },
32
36
  }),
33
37
  }),
34
38
  defineModule({
35
- id: `${meta.id}/module/object-form`,
39
+ id: `${meta.id}/module/schema`,
36
40
  activatesOn: ClientEvents.SetupSchema,
37
- activate: () =>
38
- contributes(
39
- SpaceCapabilities.ObjectForm,
40
- defineObjectForm({
41
- objectSchema: Kanban.Kanban,
42
- formSchema: CreateKanbanSchema,
43
- hidden: true,
44
- getIntent: (props, options) => createIntent(KanbanAction.Create, { ...props, space: options.space }),
45
- }),
46
- ),
41
+ activate: () => contributes(ClientCapabilities.Schema, [Kanban.Kanban]),
47
42
  }),
48
43
  defineModule({
49
44
  id: `${meta.id}/module/react-surface`,
@@ -15,9 +15,9 @@ import { defineArtifact } from '@dxos/blueprints';
15
15
  import { Obj, Query } from '@dxos/echo';
16
16
  import { invariant } from '@dxos/invariant';
17
17
  import { SpaceAction } from '@dxos/plugin-space/types';
18
- import { Filter, type Space, fullyQualifiedId } from '@dxos/react-client/echo';
18
+ import { Filter, type Space } from '@dxos/react-client/echo';
19
19
  import { KanbanView } from '@dxos/react-ui-kanban';
20
- import { DataType } from '@dxos/schema';
20
+ import { View } from '@dxos/schema';
21
21
  import { isNonNullable } from '@dxos/util';
22
22
 
23
23
  import { meta } from '../meta';
@@ -94,7 +94,7 @@ export default () => {
94
94
  execute: async (_input, { extensions }) => {
95
95
  invariant(extensions?.space, 'No space');
96
96
  const space = extensions.space;
97
- const { objects } = await space.db.query(Filter.type(DataType.View)).run();
97
+ const { objects } = await space.db.query(Filter.type(View.View)).run();
98
98
 
99
99
  const boardInfo = await Promise.all(
100
100
  objects.map(async (view) => {
@@ -104,7 +104,7 @@ export default () => {
104
104
  }
105
105
 
106
106
  return {
107
- id: fullyQualifiedId(view),
107
+ id: Obj.getDXN(view).toString(),
108
108
  name: view.name ?? 'Unnamed Kanban',
109
109
  typename: view.query.typename,
110
110
  };
@@ -124,8 +124,8 @@ export default () => {
124
124
  const space = extensions.space;
125
125
  const view = (await space.db
126
126
  // TODO(wittjosiah): Filter.and should aggregate type
127
- .query(Query.select(Filter.and(Filter.type(DataType.View), Filter.ids(id))))
128
- .first()) as DataType.View;
127
+ .query(Query.select(Filter.and(Filter.type(View.View), Filter.ids(id))))
128
+ .first()) as View.View;
129
129
 
130
130
  const kanban = await view.presentation.load();
131
131
  invariant(Obj.instanceOf(KanbanView, kanban));
@@ -7,7 +7,7 @@ import { invariant } from '@dxos/invariant';
7
7
  import { ClientCapabilities } from '@dxos/plugin-client';
8
8
  import { getSpace } from '@dxos/react-client/echo';
9
9
  import { Kanban } from '@dxos/react-ui-kanban/types';
10
- import { ProjectionModel, getTypenameFromQuery } from '@dxos/schema';
10
+ import { ProjectionModel, View, getTypenameFromQuery } from '@dxos/schema';
11
11
 
12
12
  import { meta } from '../meta';
13
13
  import { KanbanAction } from '../types';
@@ -18,14 +18,9 @@ export default (context: PluginContext) =>
18
18
  intent: KanbanAction.Create,
19
19
  resolve: async ({ space, name, typename, initialPivotColumn }) => {
20
20
  const client = context.getCapability(ClientCapabilities.Client);
21
- const { view } = await Kanban.makeView({
22
- client,
23
- space,
24
- name,
25
- typename,
26
- pivotFieldName: initialPivotColumn,
27
- });
28
- return { data: { object: view } };
21
+ const { view } = await View.makeFromSpace({ client, space, typename, pivotFieldName: initialPivotColumn });
22
+ const kanban = Kanban.make({ name, view });
23
+ return { data: { object: kanban } };
29
24
  },
30
25
  }),
31
26
  createResolver({
@@ -5,14 +5,13 @@
5
5
  import type * as Schema from 'effect/Schema';
6
6
  import React, { useMemo } from 'react';
7
7
 
8
- import { Capabilities, contributes, createSurface, useCapabilities } from '@dxos/app-framework';
8
+ import { Capabilities, contributes, createSurface } from '@dxos/app-framework';
9
9
  import { Obj, Type } from '@dxos/echo';
10
10
  import { findAnnotation } from '@dxos/effect';
11
- import { ClientCapabilities } from '@dxos/plugin-client';
12
11
  import { type Space, getSpace, isSpace } from '@dxos/react-client/echo';
13
12
  import { type InputProps, SelectInput, useFormValues } from '@dxos/react-ui-form';
14
13
  import { Kanban } from '@dxos/react-ui-kanban/types';
15
- import { DataType } from '@dxos/schema';
14
+ import { type Collection } from '@dxos/schema';
16
15
 
17
16
  import { KanbanContainer, KanbanViewEditor } from '../components';
18
17
  import { meta } from '../meta';
@@ -23,24 +22,26 @@ export default () =>
23
22
  createSurface({
24
23
  id: meta.id,
25
24
  role: ['article', 'section'],
26
- filter: (data): data is { subject: DataType.View } =>
27
- Obj.instanceOf(DataType.View, data.subject) && Obj.instanceOf(Kanban.Kanban, data.subject.presentation.target),
28
- component: ({ data, role }) => <KanbanContainer view={data.subject} role={role} />,
25
+ filter: (data): data is { subject: Kanban.Kanban } => Obj.instanceOf(Kanban.Kanban, data.subject),
26
+ component: ({ data, role }) => <KanbanContainer object={data.subject} role={role} />,
29
27
  }),
30
28
  createSurface({
31
29
  id: `${meta.id}/object-settings`,
32
30
  role: 'object-settings',
33
31
  position: 'hoist',
34
- filter: (data): data is { subject: DataType.View } =>
35
- Obj.instanceOf(DataType.View, data.subject) && Obj.instanceOf(Kanban.Kanban, data.subject.presentation.target),
36
- component: ({ data }) => <KanbanViewEditor view={data.subject} />,
32
+ filter: (data): data is { subject: Kanban.Kanban } => Obj.instanceOf(Kanban.Kanban, data.subject),
33
+ component: ({ data }) => <KanbanViewEditor object={data.subject} />,
37
34
  }),
38
35
  createSurface({
39
36
  id: `${meta.id}/create-initial-schema-form-[pivot-column]`,
40
37
  role: 'form-input',
41
38
  filter: (
42
39
  data,
43
- ): data is { prop: string; schema: Schema.Schema<any>; target: Space | DataType.Collection | undefined } => {
40
+ ): data is {
41
+ prop: string;
42
+ schema: Schema.Schema<any>;
43
+ target: Space | Collection.Collection | undefined;
44
+ } => {
44
45
  const annotation = findAnnotation<boolean>((data.schema as Schema.Schema.All).ast, PivotColumnAnnotationId);
45
46
  return !!annotation;
46
47
  },
@@ -50,16 +51,14 @@ export default () =>
50
51
  if (!space) {
51
52
  return null;
52
53
  }
53
- const { typename } = useFormValues();
54
- // TODO(wittjosiah): Unify this schema lookup.
55
- const schemaWhitelists = useCapabilities(ClientCapabilities.SchemaWhiteList);
56
- const staticSchema = schemaWhitelists.flat().find((schema) => Type.getTypename(schema) === typename);
57
- const [selectedSchema] = space?.db.schemaRegistry.query({ typename }).runSync();
58
54
 
55
+ const { typename } = useFormValues();
56
+ const [selectedSchema] = useMemo(
57
+ () => space?.db.schemaRegistry.query({ location: ['database', 'runtime'], typename }).runSync(),
58
+ [space, typename],
59
+ );
59
60
  const singleSelectColumns = useMemo(() => {
60
- const properties = staticSchema
61
- ? Type.toJsonSchema(staticSchema).properties
62
- : selectedSchema?.jsonSchema?.properties;
61
+ const properties = Type.toJsonSchema(selectedSchema).properties;
63
62
  if (!properties) {
64
63
  return [];
65
64
  }
@@ -72,7 +71,7 @@ export default () =>
72
71
  }, []);
73
72
 
74
73
  return columns;
75
- }, [selectedSchema?.jsonSchema, staticSchema]);
74
+ }, [selectedSchema]);
76
75
 
77
76
  if (!typename) {
78
77
  return null;
@@ -3,11 +3,11 @@
3
3
  //
4
4
 
5
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
6
- import React, { useCallback, useEffect, useState } from 'react';
6
+ import React, { useCallback } from 'react';
7
7
 
8
8
  import { IntentPlugin, SettingsPlugin } from '@dxos/app-framework';
9
9
  import { withPluginManager } from '@dxos/app-framework/testing';
10
- import { Obj, Query, Type } from '@dxos/echo';
10
+ import { Obj, type QueryAST, Type } from '@dxos/echo';
11
11
  import { invariant } from '@dxos/invariant';
12
12
  import { ClientPlugin } from '@dxos/plugin-client';
13
13
  import { PreviewPlugin } from '@dxos/plugin-preview';
@@ -20,11 +20,12 @@ import { useClient } from '@dxos/react-client';
20
20
  import { Filter, useQuery, useSchema, useSpaces } from '@dxos/react-client/echo';
21
21
  import { withTheme } from '@dxos/react-ui/testing';
22
22
  import { ViewEditor } from '@dxos/react-ui-form';
23
- import { Kanban as KanbanComponent, useKanbanModel } from '@dxos/react-ui-kanban';
23
+ import { Kanban as KanbanComponent, useKanbanModel, useProjectionModel } from '@dxos/react-ui-kanban';
24
24
  import { Kanban } from '@dxos/react-ui-kanban/types';
25
25
  import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
26
26
  import { defaultTx } from '@dxos/react-ui-theme';
27
- import { DataType, ProjectionModel, getTypenameFromQuery } from '@dxos/schema';
27
+ import { View, getTypenameFromQuery } from '@dxos/schema';
28
+ import { Organization, Person } from '@dxos/types';
28
29
 
29
30
  import { translations } from '../translations';
30
31
 
@@ -39,41 +40,23 @@ const rollOrg = () => ({
39
40
  description: faker.lorem.paragraph(),
40
41
  image: faker.image.url(),
41
42
  website: faker.internet.url(),
42
- status: faker.helpers.arrayElement(DataType.OrganizationStatusOptions).id as DataType.Organization['status'],
43
+ status: faker.helpers.arrayElement(Organization.StatusOptions).id as Organization.Organization['status'],
43
44
  });
44
45
 
45
46
  const StorybookKanban = () => {
46
47
  const client = useClient();
47
48
  const spaces = useSpaces();
48
49
  const space = spaces[spaces.length - 1];
49
- const views = useQuery(space, Filter.type(DataType.View));
50
- const [view, setView] = useState<DataType.View>();
51
- const [projection, setProjection] = useState<ProjectionModel>();
52
- const typename = view?.query ? getTypenameFromQuery(view.query.ast) : undefined;
50
+ const [object] = useQuery(space, Filter.type(Kanban.Kanban));
51
+ const typename = object?.view.target?.query ? getTypenameFromQuery(object.view.target.query.ast) : undefined;
53
52
  const schema = useSchema(client, space, typename);
54
53
 
55
- useEffect(() => {
56
- if (views.length && !view) {
57
- const view = views[0];
58
- setView(view);
59
- }
60
- }, [views]);
61
-
62
- useEffect(() => {
63
- if (view?.projection && schema) {
64
- const jsonSchema = Type.toJsonSchema(schema);
65
- setProjection(new ProjectionModel(jsonSchema, view.projection));
66
- }
67
- // TODO(ZaymonFC): Is there a better way to get notified about deep changes in the json schema?
68
- // @dmaretskyi? Once resolved, update in multiple places (e.g., storybooks).
69
- }, [view?.projection, schema, JSON.stringify(schema ? Type.toJsonSchema(schema) : {})]);
70
-
71
54
  const objects = useQuery(space, schema ? Filter.type(schema) : Filter.nothing());
72
55
  const filteredObjects = useGlobalFilteredObjects(objects);
73
56
 
57
+ const projection = useProjectionModel(schema, object);
74
58
  const model = useKanbanModel({
75
- view,
76
- schema,
59
+ object,
77
60
  projection,
78
61
  items: filteredObjects,
79
62
  });
@@ -94,21 +77,21 @@ const StorybookKanban = () => {
94
77
  [space, schema, model],
95
78
  );
96
79
 
97
- const handleRemoveCard = useCallback((card: { id: string }) => space.db.remove(card), [space]);
80
+ const handleRemoveCard = useCallback((card: { id: string }) => Obj.isObject(card) && space?.db.remove(card), [space]);
98
81
 
99
82
  const handleUpdateQuery = useCallback(
100
- (typename: string) => {
83
+ (newQuery: QueryAST.Query) => {
101
84
  invariant(schema);
102
85
  invariant(Type.isMutable(schema));
103
- invariant(view);
86
+ invariant(object.view.target);
104
87
 
105
- schema.updateTypename(typename);
106
- view.query.ast = Query.select(Filter.typename(typename)).ast;
88
+ schema.updateTypename(getTypenameFromQuery(newQuery));
89
+ object.view.target.query.ast = newQuery;
107
90
  },
108
- [view, schema],
91
+ [object, schema],
109
92
  );
110
93
 
111
- if (!schema || !view) {
94
+ if (!schema || !object.view.target) {
112
95
  return null;
113
96
  }
114
97
 
@@ -119,14 +102,14 @@ const StorybookKanban = () => {
119
102
  <ViewEditor
120
103
  registry={space?.db.schemaRegistry}
121
104
  schema={schema}
122
- view={view}
105
+ view={object.view.target}
123
106
  onQueryChanged={handleUpdateQuery}
124
107
  onDelete={(fieldId: string) => {
125
108
  console.log('[ViewEditor]', 'onDelete', fieldId);
126
109
  }}
127
110
  />
128
111
  <SyntaxHighlighter language='json' className='text-xs'>
129
- {JSON.stringify({ view, schema }, null, 2)}
112
+ {JSON.stringify({ view: object.view.target, schema }, null, 2)}
130
113
  </SyntaxHighlighter>
131
114
  </div>
132
115
  </div>
@@ -150,22 +133,23 @@ const meta = {
150
133
  withPluginManager({
151
134
  plugins: [
152
135
  ClientPlugin({
153
- types: [DataType.Organization, DataType.Person, DataType.View, Kanban.Kanban],
136
+ types: [Organization.Organization, Person.Person, View.View, Kanban.Kanban],
154
137
  onClientInitialized: async ({ client }) => {
155
138
  await client.halo.createIdentity();
156
139
  const space = await client.spaces.create();
157
140
  await space.waitUntilReady();
158
- const { view } = await Kanban.makeView({
141
+ const { view } = await View.makeFromSpace({
159
142
  client,
160
143
  space,
161
- typename: DataType.Organization.typename,
144
+ typename: Organization.Organization.typename,
162
145
  pivotFieldName: 'status',
163
146
  });
164
- space.db.add(view);
147
+ const kanban = Kanban.make({ view });
148
+ space.db.add(kanban);
165
149
 
166
150
  // TODO(burdon): Replace with sdk/schema/testing.
167
151
  Array.from({ length: 80 }).map(() => {
168
- return space.db.add(Obj.make(DataType.Organization, rollOrg()));
152
+ return space.db.add(Obj.make(Organization.Organization, rollOrg()));
169
153
  });
170
154
  },
171
155
  }),
@@ -2,34 +2,28 @@
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 { useIntentDispatcher } from '@dxos/app-framework/react';
8
9
  import { Filter, Obj, Type } from '@dxos/echo';
9
- import { EchoSchema, type TypedObject } from '@dxos/echo/internal';
10
+ import { type TypedObject } from '@dxos/echo/internal';
10
11
  import { useGlobalFilteredObjects } from '@dxos/plugin-search';
11
12
  import { useClient } from '@dxos/react-client';
12
13
  import { getSpace, useQuery } from '@dxos/react-client/echo';
13
- import { Kanban, useKanbanModel } from '@dxos/react-ui-kanban';
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 { type DataType, ProjectionModel, getTypenameFromQuery } 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 }) => {
21
+ export const KanbanContainer = ({ object }: { object: Kanban.Kanban; role: string }) => {
20
22
  const client = useClient();
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
- const typename = view.query ? getTypenameFromQuery(view.query.ast) : undefined;
26
-
27
- const jsonSchema = useMemo(() => {
28
- if (!cardSchema) {
29
- return undefined;
30
- }
31
- return cardSchema instanceof EchoSchema ? cardSchema.jsonSchema : Type.toJsonSchema(cardSchema);
32
- }, [cardSchema]);
26
+ const typename = object.view.target?.query ? getTypenameFromQuery(object.view.target.query.ast) : undefined;
33
27
 
34
28
  useEffect(() => {
35
29
  const staticSchema = client.graph.schemaRegistry.schemas.find((schema) => Type.getTypename(schema) === typename);
@@ -51,19 +45,12 @@ export const KanbanContainer = ({ view }: { view: DataType.View; role: string })
51
45
  }
52
46
  }, [typename, space]);
53
47
 
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)]);
60
-
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,46 +4,43 @@
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/internal';
7
+ import { Format } from '@dxos/echo/internal';
8
+ import { invariant } from '@dxos/invariant';
9
9
  import { useClient } from '@dxos/react-client';
10
10
  import { getSpace, useSchema } from '@dxos/react-client/echo';
11
11
  import { type CustomInputMap, Form, SelectInput } from '@dxos/react-ui-form';
12
- import { Kanban } from '@dxos/react-ui-kanban/types';
13
- import { type DataType, ProjectionModel, getTypenameFromQuery } from '@dxos/schema';
12
+ import { useProjectionModel } from '@dxos/react-ui-kanban';
13
+ import { type Kanban } from '@dxos/react-ui-kanban/types';
14
+ import { getTypenameFromQuery } from '@dxos/schema';
14
15
 
15
- type KanbanViewEditorProps = { view: DataType.View };
16
+ import { SettingsSchema } from '../types';
16
17
 
17
- export const KanbanViewEditor = ({ view }: KanbanViewEditorProps) => {
18
+ type KanbanViewEditorProps = { object: Kanban.Kanban };
19
+
20
+ export const KanbanViewEditor = ({ object }: KanbanViewEditorProps) => {
18
21
  const client = useClient();
19
- const space = getSpace(view);
20
- const currentTypename = view.query ? getTypenameFromQuery(view.query.ast) : undefined;
22
+ const space = getSpace(object);
23
+ const view = object.view.target;
24
+ const currentTypename = view?.query ? getTypenameFromQuery(view.query.ast) : undefined;
21
25
  const schema = useSchema(client, space, currentTypename);
22
-
23
- const projection = useMemo(() => {
24
- if (schema) {
25
- const jsonSchema = schema instanceof EchoSchema ? schema.jsonSchema : Type.toJsonSchema(schema);
26
- const projection = new ProjectionModel(jsonSchema, view.projection);
27
- projection.normalizeView();
28
- return projection;
29
- }
30
- }, [view.projection, JSON.stringify(schema)]);
26
+ const projection = useProjectionModel(schema, object);
31
27
 
32
28
  const fieldProjections = projection?.getFieldProjections() || [];
33
29
  const selectFields = fieldProjections
34
- .filter((field) => field.props.format === FormatEnum.SingleSelect)
30
+ .filter((field) => field.props.format === Format.TypeFormat.SingleSelect)
35
31
  .map(({ field }) => ({ value: field.id, label: field.path }));
36
32
 
37
33
  const handleSave = useCallback(
38
34
  (values: Partial<{ columnFieldId: string }>) => {
35
+ invariant(view);
39
36
  view.projection.pivotFieldId = values.columnFieldId;
40
37
  },
41
38
  [view],
42
39
  );
43
40
 
44
41
  const initialValues = useMemo(
45
- () => ({ columnFieldId: view.projection.pivotFieldId }),
46
- [view.projection.pivotFieldId],
42
+ () => ({ columnFieldId: view?.projection.pivotFieldId }),
43
+ [view?.projection.pivotFieldId],
47
44
  );
48
45
  const custom: CustomInputMap = useMemo(
49
46
  () => ({ columnFieldId: (props) => <SelectInput {...props} options={selectFields} /> }),
@@ -53,7 +50,7 @@ export const KanbanViewEditor = ({ view }: KanbanViewEditorProps) => {
53
50
  return (
54
51
  <Form
55
52
  Custom={custom}
56
- schema={Kanban.SettingsSchema}
53
+ schema={SettingsSchema}
57
54
  values={initialValues}
58
55
  onSave={handleSave}
59
56
  autoSave
package/src/meta.ts CHANGED
@@ -3,13 +3,17 @@
3
3
  //
4
4
 
5
5
  import { type PluginMeta } from '@dxos/app-framework';
6
+ import { trim } from '@dxos/util';
6
7
 
7
8
  export const meta: PluginMeta = {
8
9
  id: 'dxos.org/plugin/kanban',
9
10
  name: 'Kanban',
10
- description:
11
- '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
+ `,
12
15
  icon: 'ph--kanban--regular',
16
+ iconHue: 'green',
13
17
  source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-kanban',
14
18
  screenshots: ['https://dxos.network/plugin-details-kanban-dark.png'],
15
19
  };
@@ -2,6 +2,7 @@
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
7
  import { Kanban } from '@dxos/react-ui-kanban/types';
7
8
 
@@ -10,24 +11,23 @@ import { meta } from './meta';
10
11
  export const translations = [
11
12
  {
12
13
  'en-US': {
13
- [Kanban.Kanban.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
  },