@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.
- package/dist/lib/browser/blueprint-definition-UYVX622Q.mjs +28 -0
- package/dist/lib/browser/blueprint-definition-UYVX622Q.mjs.map +7 -0
- package/dist/lib/browser/{chunk-X44RHBZK.mjs → chunk-PEQVHFOX.mjs} +35 -42
- package/dist/lib/browser/chunk-PEQVHFOX.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +31 -33
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{intent-resolver-E6O3LBAB.mjs → intent-resolver-NHCWHMPW.mjs} +20 -20
- package/dist/lib/browser/intent-resolver-NHCWHMPW.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{react-surface-MWNNZYMN.mjs → react-surface-NSCKM4QW.mjs} +81 -98
- package/dist/lib/browser/react-surface-NSCKM4QW.mjs.map +7 -0
- package/dist/lib/browser/types/index.mjs +3 -3
- package/dist/lib/node-esm/blueprint-definition-42P47FUY.mjs +30 -0
- package/dist/lib/node-esm/blueprint-definition-42P47FUY.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-6WK5CGYY.mjs → chunk-LTCOYU73.mjs} +35 -42
- package/dist/lib/node-esm/chunk-LTCOYU73.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +31 -33
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/{intent-resolver-LPASDELU.mjs → intent-resolver-L2OEBOJW.mjs} +20 -20
- package/dist/lib/node-esm/intent-resolver-L2OEBOJW.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/{react-surface-T52BBG45.mjs → react-surface-WXYTWOY2.mjs} +81 -98
- package/dist/lib/node-esm/react-surface-WXYTWOY2.mjs.map +7 -0
- package/dist/lib/node-esm/types/index.mjs +3 -3
- package/dist/types/src/KanbanPlugin.d.ts +1 -1
- package/dist/types/src/KanbanPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/artifact-definition.d.ts +1 -1
- package/dist/types/src/capabilities/artifact-definition.d.ts.map +1 -1
- package/dist/types/src/capabilities/blueprint-definition.d.ts +5 -0
- package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +3 -3
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/components/KanbanContainer.d.ts +3 -3
- package/dist/types/src/components/KanbanContainer.d.ts.map +1 -1
- package/dist/types/src/components/KanbanContainer.stories.d.ts +50 -6
- package/dist/types/src/components/KanbanContainer.stories.d.ts.map +1 -1
- package/dist/types/src/components/KanbanViewEditor.d.ts +3 -3
- package/dist/types/src/components/KanbanViewEditor.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +0 -1
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +21 -9
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/index.d.ts +0 -1
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/src/types/schema.d.ts +15 -54
- package/dist/types/src/types/schema.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +43 -40
- package/src/KanbanPlugin.tsx +49 -54
- package/src/capabilities/artifact-definition.ts +15 -11
- package/src/capabilities/blueprint-definition.ts +30 -0
- package/src/capabilities/index.ts +1 -1
- package/src/capabilities/intent-resolver.ts +11 -17
- package/src/capabilities/react-surface.tsx +24 -25
- package/src/components/KanbanContainer.stories.tsx +52 -73
- package/src/components/KanbanContainer.tsx +18 -31
- package/src/components/KanbanViewEditor.tsx +31 -37
- package/src/meta.ts +7 -5
- package/src/translations.ts +6 -6
- package/src/types/index.ts +0 -1
- package/src/types/schema.ts +22 -10
- package/dist/lib/browser/artifact-definition-WMSZK3RW.mjs +0 -174
- package/dist/lib/browser/artifact-definition-WMSZK3RW.mjs.map +0 -7
- package/dist/lib/browser/chunk-X44RHBZK.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-E6O3LBAB.mjs.map +0 -7
- package/dist/lib/browser/react-surface-MWNNZYMN.mjs.map +0 -7
- package/dist/lib/node-esm/artifact-definition-QVZXPDXK.mjs +0 -175
- package/dist/lib/node-esm/artifact-definition-QVZXPDXK.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-6WK5CGYY.mjs.map +0 -7
- package/dist/lib/node-esm/intent-resolver-LPASDELU.mjs.map +0 -7
- package/dist/lib/node-esm/react-surface-T52BBG45.mjs.map +0 -7
- package/dist/types/src/types/kanban.d.ts +0 -11
- package/dist/types/src/types/kanban.d.ts.map +0 -1
- package/src/types/kanban.ts +0 -29
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@
|
|
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 {
|
|
22
|
-
import {
|
|
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
|
|
25
|
-
import {
|
|
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 {
|
|
28
|
-
import {
|
|
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(
|
|
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
|
|
52
|
-
const
|
|
53
|
-
const
|
|
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
|
-
|
|
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
|
|
78
|
+
const handleRemoveCard = useCallback((card: { id: string }) => Obj.isObject(card) && space?.db.remove(card), [space]);
|
|
99
79
|
|
|
100
|
-
const
|
|
101
|
-
(
|
|
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(
|
|
107
|
-
view.query.
|
|
86
|
+
schema.updateTypename(getTypenameFromQuery(newQuery));
|
|
87
|
+
object.view.target.query.ast = newQuery;
|
|
108
88
|
},
|
|
109
|
-
[
|
|
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 ? <
|
|
119
|
-
<div className='flex flex-col bs-full
|
|
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
|
-
|
|
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
|
-
<
|
|
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
|
|
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
|
-
|
|
124
|
+
withTheme,
|
|
152
125
|
withPluginManager({
|
|
153
126
|
plugins: [
|
|
154
|
-
ThemePlugin({ tx: defaultTx }),
|
|
155
127
|
ClientPlugin({
|
|
156
|
-
types: [
|
|
157
|
-
onClientInitialized: async (
|
|
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
|
|
162
|
-
client,
|
|
133
|
+
const { view } = await View.makeFromSpace({
|
|
163
134
|
space,
|
|
164
|
-
typename:
|
|
165
|
-
|
|
135
|
+
typename: Organization.Organization.typename,
|
|
136
|
+
pivotFieldName: 'status',
|
|
166
137
|
});
|
|
167
|
-
|
|
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(
|
|
143
|
+
return space.db.add(Obj.make(Organization.Organization, rollOrg()));
|
|
172
144
|
});
|
|
173
145
|
},
|
|
174
146
|
}),
|
|
175
|
-
|
|
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<
|
|
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,
|
|
5
|
+
import React, { useCallback, useEffect, useState } from 'react';
|
|
6
6
|
|
|
7
|
-
import { createIntent
|
|
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 {
|
|
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 {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
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 {
|
|
17
|
+
import { getTypenameFromQuery } from '@dxos/schema';
|
|
16
18
|
|
|
17
19
|
import { KanbanAction } from '../types';
|
|
18
20
|
|
|
19
|
-
export const KanbanContainer = ({
|
|
20
|
-
const
|
|
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
|
|
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
|
|
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
|
-
}, [
|
|
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
|
-
|
|
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 && <
|
|
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 {
|
|
8
|
-
import {
|
|
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,
|
|
12
|
-
import {
|
|
13
|
-
import { type
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
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 ===
|
|
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
|
-
|
|
33
|
+
invariant(view);
|
|
34
|
+
view.projection.pivotFieldId = values.columnFieldId;
|
|
39
35
|
},
|
|
40
|
-
[
|
|
36
|
+
[view],
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const initialValues = useMemo(
|
|
40
|
+
() => ({ columnFieldId: view?.projection.pivotFieldId }),
|
|
41
|
+
[view?.projection.pivotFieldId],
|
|
41
42
|
);
|
|
42
43
|
|
|
43
|
-
const
|
|
44
|
-
|
|
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
|
-
|
|
52
|
-
|
|
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:
|
|
9
|
+
id: 'dxos.org/plugin/kanban',
|
|
11
10
|
name: 'Kanban',
|
|
12
|
-
description:
|
|
13
|
-
|
|
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
|
};
|
package/src/translations.ts
CHANGED
|
@@ -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 {
|
|
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
|
-
[
|
|
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
|
},
|
package/src/types/index.ts
CHANGED
package/src/types/schema.ts
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
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 {
|
|
9
|
+
import { Kanban } from '@dxos/react-ui-kanban/types';
|
|
10
|
+
import { FieldSchema, View } from '@dxos/schema';
|
|
9
11
|
|
|
10
|
-
import {
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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 = `${
|
|
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:
|
|
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:
|
|
64
|
+
view: View.View,
|
|
53
65
|
fieldId: Schema.String,
|
|
54
66
|
// TODO(wittjosiah): Separate fields for undo data?
|
|
55
67
|
deletionData: Schema.optional(
|