@dxos/plugin-kanban 0.8.4-main.9735255 → 0.8.4-main.9be5663bfe
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/blueprints/index.mjs +23 -4
- package/dist/lib/browser/blueprints/index.mjs.map +4 -4
- package/dist/lib/browser/chunk-A3PBV3S5.mjs +105 -0
- package/dist/lib/browser/chunk-A3PBV3S5.mjs.map +7 -0
- package/dist/lib/browser/delete-card-VPNVIWOA.mjs +32 -0
- package/dist/lib/browser/delete-card-VPNVIWOA.mjs.map +7 -0
- package/dist/lib/browser/delete-card-field-4HHF2GYX.mjs +50 -0
- package/dist/lib/browser/delete-card-field-4HHF2GYX.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +84 -61
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/operations/index.mjs +13 -0
- package/dist/lib/browser/operations/index.mjs.map +7 -0
- package/dist/lib/browser/restore-card-4GG2RYKR.mjs +29 -0
- package/dist/lib/browser/restore-card-4GG2RYKR.mjs.map +7 -0
- package/dist/lib/browser/restore-card-field-3T26ACYX.mjs +48 -0
- package/dist/lib/browser/restore-card-field-3T26ACYX.mjs.map +7 -0
- package/dist/lib/browser/types/index.mjs +94 -8
- package/dist/lib/browser/types/index.mjs.map +4 -4
- package/dist/lib/node-esm/blueprints/index.mjs +23 -4
- package/dist/lib/node-esm/blueprints/index.mjs.map +4 -4
- package/dist/lib/node-esm/chunk-6LELYA2G.mjs +106 -0
- package/dist/lib/node-esm/chunk-6LELYA2G.mjs.map +7 -0
- package/dist/lib/node-esm/delete-card-5PW5OMFN.mjs +33 -0
- package/dist/lib/node-esm/delete-card-5PW5OMFN.mjs.map +7 -0
- package/dist/lib/node-esm/delete-card-field-KPJU2AQ3.mjs +51 -0
- package/dist/lib/node-esm/delete-card-field-KPJU2AQ3.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +84 -61
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/operations/index.mjs +14 -0
- package/dist/lib/node-esm/operations/index.mjs.map +7 -0
- package/dist/lib/node-esm/restore-card-X2TKMU5A.mjs +30 -0
- package/dist/lib/node-esm/restore-card-X2TKMU5A.mjs.map +7 -0
- package/dist/lib/node-esm/restore-card-field-IUTL4RTR.mjs +49 -0
- package/dist/lib/node-esm/restore-card-field-IUTL4RTR.mjs.map +7 -0
- package/dist/lib/node-esm/types/index.mjs +94 -8
- package/dist/lib/node-esm/types/index.mjs.map +4 -4
- package/dist/types/src/KanbanPlugin.d.ts.map +1 -1
- package/dist/types/src/blueprints/index.d.ts +1 -1
- package/dist/types/src/blueprints/index.d.ts.map +1 -1
- package/dist/types/src/blueprints/kanban-blueprint.d.ts +3 -21
- package/dist/types/src/blueprints/kanban-blueprint.d.ts.map +1 -1
- package/dist/types/src/capabilities/{artifact-definition/artifact-definition.d.ts → artifact-definition.d.ts} +1 -1
- package/dist/types/src/capabilities/artifact-definition.d.ts.map +1 -0
- package/dist/types/src/capabilities/blueprint-definition.d.ts +6 -0
- package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +6 -3
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
- package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface.d.ts +5 -0
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
- package/dist/types/src/capabilities/undo-mappings.d.ts +5 -0
- package/dist/types/src/capabilities/undo-mappings.d.ts.map +1 -0
- package/dist/types/src/components/KanbanBoard/KanbanBoard.d.ts +57 -0
- package/dist/types/src/components/KanbanBoard/KanbanBoard.d.ts.map +1 -0
- package/dist/types/src/components/KanbanBoard/KanbanBoard.stories.d.ts +72 -0
- package/dist/types/src/components/KanbanBoard/KanbanBoard.stories.d.ts.map +1 -0
- package/dist/types/src/components/KanbanBoard/KanbanCard.d.ts +10 -0
- package/dist/types/src/components/KanbanBoard/KanbanCard.d.ts.map +1 -0
- package/dist/types/src/components/KanbanBoard/KanbanColumn.d.ts +9 -0
- package/dist/types/src/components/KanbanBoard/KanbanColumn.d.ts.map +1 -0
- package/dist/types/src/components/KanbanBoard/index.d.ts +2 -0
- package/dist/types/src/components/KanbanBoard/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -2
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/KanbanContainer/KanbanContainer.d.ts +6 -0
- package/dist/types/src/containers/KanbanContainer/KanbanContainer.d.ts.map +1 -0
- package/dist/types/src/containers/KanbanContainer/KanbanContainer.stories.d.ts +79 -0
- package/dist/types/src/containers/KanbanContainer/KanbanContainer.stories.d.ts.map +1 -0
- package/dist/types/src/containers/KanbanContainer/index.d.ts +2 -0
- package/dist/types/src/containers/KanbanContainer/index.d.ts.map +1 -0
- package/dist/types/src/containers/KanbanViewEditor/KanbanViewEditor.d.ts +6 -0
- package/dist/types/src/containers/KanbanViewEditor/KanbanViewEditor.d.ts.map +1 -0
- package/dist/types/src/containers/KanbanViewEditor/index.d.ts +2 -0
- package/dist/types/src/containers/KanbanViewEditor/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +4 -0
- package/dist/types/src/containers/index.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +6 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -0
- package/dist/types/src/hooks/useEchoChangeCallback.d.ts +13 -0
- package/dist/types/src/hooks/useEchoChangeCallback.d.ts.map +1 -0
- package/dist/types/src/hooks/useKanbanBoardModel.d.ts +16 -0
- package/dist/types/src/hooks/useKanbanBoardModel.d.ts.map +1 -0
- package/dist/types/src/hooks/useKanbanBoardModel.test.d.ts +2 -0
- package/dist/types/src/hooks/useKanbanBoardModel.test.d.ts.map +1 -0
- package/dist/types/src/hooks/useKanbanColumnEventHandler.d.ts +22 -0
- package/dist/types/src/hooks/useKanbanColumnEventHandler.d.ts.map +1 -0
- package/dist/types/src/hooks/useKanbanItemEventHandler.d.ts +19 -0
- package/dist/types/src/hooks/useKanbanItemEventHandler.d.ts.map +1 -0
- package/dist/types/src/hooks/useProjectionModel.d.ts +15 -0
- package/dist/types/src/hooks/useProjectionModel.d.ts.map +1 -0
- package/dist/types/src/operations/definitions.d.ts +52 -0
- package/dist/types/src/operations/definitions.d.ts.map +1 -0
- package/dist/types/src/operations/delete-card-field.d.ts +5 -0
- package/dist/types/src/operations/delete-card-field.d.ts.map +1 -0
- package/dist/types/src/operations/delete-card.d.ts +5 -0
- package/dist/types/src/operations/delete-card.d.ts.map +1 -0
- package/dist/types/src/operations/index.d.ts +4 -0
- package/dist/types/src/operations/index.d.ts.map +1 -0
- package/dist/types/src/operations/restore-card-field.d.ts +5 -0
- package/dist/types/src/operations/restore-card-field.d.ts.map +1 -0
- package/dist/types/src/operations/restore-card.d.ts +5 -0
- package/dist/types/src/operations/restore-card.d.ts.map +1 -0
- package/dist/types/src/playwright/board-manager.d.ts +5 -0
- package/dist/types/src/playwright/board-manager.d.ts.map +1 -0
- package/dist/types/src/playwright/playwright.config.d.ts +3 -0
- package/dist/types/src/playwright/playwright.config.d.ts.map +1 -0
- package/dist/types/src/playwright/smoke.spec.d.ts +2 -0
- package/dist/types/src/playwright/smoke.spec.d.ts.map +1 -0
- package/dist/types/src/testing/KanbanCardTileSimple.d.ts +7 -0
- package/dist/types/src/testing/KanbanCardTileSimple.d.ts.map +1 -0
- package/dist/types/src/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +48 -32
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Kanban.d.ts +37 -0
- package/dist/types/src/types/Kanban.d.ts.map +1 -0
- package/dist/types/src/types/constants.d.ts +6 -0
- package/dist/types/src/types/constants.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +2 -0
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/src/types/schema.d.ts +0 -103
- package/dist/types/src/types/schema.d.ts.map +1 -1
- package/dist/types/src/types/types.d.ts +28 -0
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/dist/types/src/util/arrangement.d.ts +68 -0
- package/dist/types/src/util/arrangement.d.ts.map +1 -0
- package/dist/types/src/util/arrangement.test.d.ts +2 -0
- package/dist/types/src/util/arrangement.test.d.ts.map +1 -0
- package/dist/types/src/util/index.d.ts +2 -0
- package/dist/types/src/util/index.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +64 -42
- package/src/KanbanPlugin.tsx +35 -23
- package/src/blueprints/index.ts +1 -1
- package/src/blueprints/kanban-blueprint.ts +12 -8
- package/src/capabilities/{artifact-definition/artifact-definition.ts → artifact-definition.ts} +10 -9
- package/src/capabilities/blueprint-definition.ts +17 -0
- package/src/capabilities/index.ts +10 -3
- package/src/capabilities/operation-handler.ts +14 -0
- package/src/capabilities/{react-surface/react-surface.tsx → react-surface.tsx} +20 -19
- package/src/capabilities/undo-mappings.ts +34 -0
- package/src/components/KanbanBoard/KanbanBoard.stories.tsx +142 -0
- package/src/components/KanbanBoard/KanbanBoard.tsx +193 -0
- package/src/components/KanbanBoard/KanbanCard.tsx +86 -0
- package/src/components/KanbanBoard/KanbanColumn.tsx +69 -0
- package/src/components/KanbanBoard/index.ts +5 -0
- package/src/components/index.ts +1 -2
- package/src/{components → containers/KanbanContainer}/KanbanContainer.stories.tsx +80 -96
- package/src/containers/KanbanContainer/KanbanContainer.tsx +96 -0
- package/src/containers/KanbanContainer/index.ts +5 -0
- package/src/{components → containers/KanbanViewEditor}/KanbanViewEditor.tsx +23 -19
- package/src/containers/KanbanViewEditor/index.ts +5 -0
- package/src/containers/index.ts +8 -0
- package/src/hooks/index.ts +9 -0
- package/src/hooks/useEchoChangeCallback.ts +30 -0
- package/src/hooks/useKanbanBoardModel.test.ts +235 -0
- package/src/hooks/useKanbanBoardModel.ts +144 -0
- package/src/hooks/useKanbanColumnEventHandler.ts +106 -0
- package/src/hooks/useKanbanItemEventHandler.ts +133 -0
- package/src/hooks/useProjectionModel.ts +58 -0
- package/src/meta.ts +1 -1
- package/src/operations/definitions.ts +63 -0
- package/src/operations/delete-card-field.ts +47 -0
- package/src/operations/delete-card.ts +23 -0
- package/src/operations/index.ts +12 -0
- package/src/operations/restore-card-field.ts +41 -0
- package/src/operations/restore-card.ts +21 -0
- package/src/playwright/board-manager.ts +13 -0
- package/src/playwright/playwright.config.ts +19 -0
- package/src/playwright/smoke.spec.ts +107 -0
- package/src/testing/KanbanCardTileSimple.tsx +82 -0
- package/src/testing/index.ts +5 -0
- package/src/translations.ts +26 -18
- package/src/types/Kanban.ts +71 -0
- package/src/types/constants.ts +9 -0
- package/src/types/index.ts +2 -0
- package/src/types/schema.ts +0 -76
- package/src/types/types.ts +35 -0
- package/src/util/arrangement.test.ts +208 -0
- package/src/util/arrangement.ts +167 -0
- package/src/util/index.ts +5 -0
- package/dist/lib/browser/blueprint-definition-T2544VMJ.mjs +0 -17
- package/dist/lib/browser/blueprint-definition-T2544VMJ.mjs.map +0 -7
- package/dist/lib/browser/chunk-L6N4ZDZ7.mjs +0 -35
- package/dist/lib/browser/chunk-L6N4ZDZ7.mjs.map +0 -7
- package/dist/lib/browser/chunk-XYQO4VL7.mjs +0 -150
- package/dist/lib/browser/chunk-XYQO4VL7.mjs.map +0 -7
- package/dist/lib/browser/operation-resolver-UEJHX42A.mjs +0 -162
- package/dist/lib/browser/operation-resolver-UEJHX42A.mjs.map +0 -7
- package/dist/lib/browser/react-surface-LFUJAPRL.mjs +0 -236
- package/dist/lib/browser/react-surface-LFUJAPRL.mjs.map +0 -7
- package/dist/lib/node-esm/blueprint-definition-APJQFSHJ.mjs +0 -18
- package/dist/lib/node-esm/blueprint-definition-APJQFSHJ.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-NN6JMKIT.mjs +0 -152
- package/dist/lib/node-esm/chunk-NN6JMKIT.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-ZHRMUKTF.mjs +0 -36
- package/dist/lib/node-esm/chunk-ZHRMUKTF.mjs.map +0 -7
- package/dist/lib/node-esm/operation-resolver-5RPWHZCF.mjs +0 -163
- package/dist/lib/node-esm/operation-resolver-5RPWHZCF.mjs.map +0 -7
- package/dist/lib/node-esm/react-surface-7TSGBRJL.mjs +0 -237
- package/dist/lib/node-esm/react-surface-7TSGBRJL.mjs.map +0 -7
- package/dist/types/src/capabilities/artifact-definition/artifact-definition.d.ts.map +0 -1
- package/dist/types/src/capabilities/artifact-definition/index.d.ts +0 -3
- package/dist/types/src/capabilities/artifact-definition/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/blueprint-definition/blueprint-definition.d.ts +0 -9
- package/dist/types/src/capabilities/blueprint-definition/blueprint-definition.d.ts.map +0 -1
- package/dist/types/src/capabilities/blueprint-definition/index.d.ts +0 -3
- package/dist/types/src/capabilities/blueprint-definition/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/operation-resolver/index.d.ts +0 -3
- package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +0 -5
- package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +0 -1
- package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
- package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts +0 -5
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
- package/dist/types/src/components/KanbanContainer.d.ts +0 -6
- package/dist/types/src/components/KanbanContainer.d.ts.map +0 -1
- package/dist/types/src/components/KanbanContainer.stories.d.ts +0 -75
- package/dist/types/src/components/KanbanContainer.stories.d.ts.map +0 -1
- package/dist/types/src/components/KanbanViewEditor.d.ts +0 -8
- package/dist/types/src/components/KanbanViewEditor.d.ts.map +0 -1
- package/src/capabilities/artifact-definition/index.ts +0 -7
- package/src/capabilities/blueprint-definition/blueprint-definition.ts +0 -23
- package/src/capabilities/blueprint-definition/index.ts +0 -7
- package/src/capabilities/operation-resolver/index.ts +0 -7
- package/src/capabilities/operation-resolver/operation-resolver.ts +0 -133
- package/src/capabilities/react-surface/index.ts +0 -7
- package/src/components/KanbanContainer.tsx +0 -86
|
@@ -5,43 +5,43 @@
|
|
|
5
5
|
import { RegistryContext } from '@effect-atom/atom-react';
|
|
6
6
|
import { type Decorator, type Meta, type StoryObj } from '@storybook/react-vite';
|
|
7
7
|
import * as Effect from 'effect/Effect';
|
|
8
|
-
import React, { useCallback, useContext } from 'react';
|
|
8
|
+
import React, { useCallback, useContext, useMemo } from 'react';
|
|
9
9
|
import { expect, waitFor, within } from 'storybook/test';
|
|
10
10
|
|
|
11
11
|
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
12
|
+
import { Surface } from '@dxos/app-framework/ui';
|
|
12
13
|
import { Obj, type QueryAST, Type } from '@dxos/echo';
|
|
14
|
+
import { View } from '@dxos/echo';
|
|
13
15
|
import { type Mutable } from '@dxos/echo/internal';
|
|
14
16
|
import { invariant } from '@dxos/invariant';
|
|
15
17
|
import { ClientPlugin } from '@dxos/plugin-client';
|
|
18
|
+
import { initializeIdentity } from '@dxos/plugin-client/testing';
|
|
16
19
|
import { PreviewPlugin } from '@dxos/plugin-preview';
|
|
17
|
-
import { useGlobalFilteredObjects } from '@dxos/plugin-search';
|
|
18
20
|
import { SpacePlugin } from '@dxos/plugin-space';
|
|
19
21
|
import { StorybookPlugin, corePlugins } from '@dxos/plugin-testing';
|
|
20
|
-
import {
|
|
22
|
+
import { random } from '@dxos/random';
|
|
21
23
|
import { Filter, type Space, useQuery, useSchema, useSpaces } from '@dxos/react-client/echo';
|
|
22
|
-
import { withTheme } from '@dxos/react-ui/testing';
|
|
23
24
|
import { ViewEditor } from '@dxos/react-ui-form';
|
|
24
|
-
import {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
useProjectionModel,
|
|
29
|
-
} from '@dxos/react-ui-kanban';
|
|
30
|
-
import { Kanban } from '@dxos/react-ui-kanban/types';
|
|
31
|
-
import { JsonFilter } from '@dxos/react-ui-syntax-highlighter';
|
|
32
|
-
import { View, getTypenameFromQuery } from '@dxos/schema';
|
|
25
|
+
import { Json } from '@dxos/react-ui-syntax-highlighter';
|
|
26
|
+
import { withLayout } from '@dxos/react-ui/testing';
|
|
27
|
+
import { ViewModel, getTypenameFromQuery } from '@dxos/schema';
|
|
28
|
+
// TODO(wittjosiah): Replace with echo/testing.
|
|
33
29
|
import { Organization, Person } from '@dxos/types';
|
|
34
30
|
|
|
35
|
-
import {
|
|
31
|
+
import { useProjectionModel } from '#hooks';
|
|
32
|
+
import { Kanban } from '#types';
|
|
36
33
|
|
|
37
|
-
|
|
34
|
+
import { KanbanPlugin } from '../../KanbanPlugin';
|
|
35
|
+
import { translations } from '../../translations';
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
random.seed(0);
|
|
38
|
+
|
|
39
|
+
const createOrg = (status?: Organization.Organization['status']) => ({
|
|
40
|
+
name: random.commerce.productName(),
|
|
41
|
+
description: random.lorem.paragraph(),
|
|
42
|
+
image: random.image.url(),
|
|
43
|
+
website: random.internet.url(),
|
|
44
|
+
status: (status ?? random.helpers.arrayElement(Organization.StatusOptions).id) as Organization.Organization['status'],
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
//
|
|
@@ -49,12 +49,13 @@ const createOrg = () => ({
|
|
|
49
49
|
//
|
|
50
50
|
|
|
51
51
|
type ClientSetupOptions = {
|
|
52
|
-
types?: Type.
|
|
52
|
+
types?: Type.AnyEntity[];
|
|
53
53
|
onSpaceCreated?: (space: Space) => Promise<void>;
|
|
54
54
|
};
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* Creates the standard plugin manager decorator with client configuration.
|
|
58
|
+
* Includes KanbanPlugin so the Surface resolves to KanbanContainer.
|
|
58
59
|
*/
|
|
59
60
|
const withKanbanPlugins = ({ types = [], onSpaceCreated }: ClientSetupOptions): Decorator =>
|
|
60
61
|
withPluginManager({
|
|
@@ -64,7 +65,7 @@ const withKanbanPlugins = ({ types = [], onSpaceCreated }: ClientSetupOptions):
|
|
|
64
65
|
types: [...types, View.View, Kanban.Kanban],
|
|
65
66
|
onClientInitialized: ({ client }) =>
|
|
66
67
|
Effect.gen(function* () {
|
|
67
|
-
yield*
|
|
68
|
+
yield* initializeIdentity(client);
|
|
68
69
|
const space = yield* Effect.promise(() => client.spaces.create());
|
|
69
70
|
yield* Effect.promise(() => space.waitUntilReady());
|
|
70
71
|
yield* Effect.promise(() => onSpaceCreated?.(space) ?? Promise.resolve());
|
|
@@ -73,61 +74,37 @@ const withKanbanPlugins = ({ types = [], onSpaceCreated }: ClientSetupOptions):
|
|
|
73
74
|
PreviewPlugin(),
|
|
74
75
|
SpacePlugin({}),
|
|
75
76
|
StorybookPlugin({}),
|
|
77
|
+
KanbanPlugin(),
|
|
76
78
|
],
|
|
77
79
|
});
|
|
78
80
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Renders the first Kanban in the space via Surface (resolves to KanbanContainer),
|
|
83
|
+
* with a sidebar containing ViewEditor and Json filter.
|
|
84
|
+
*/
|
|
83
85
|
const DefaultComponent = () => {
|
|
84
86
|
const registry = useContext(RegistryContext);
|
|
85
87
|
const spaces = useSpaces();
|
|
86
88
|
const space = spaces[spaces.length - 1];
|
|
87
|
-
const [
|
|
88
|
-
const typename =
|
|
89
|
+
const [kanban] = useQuery(space?.db, Filter.type(Kanban.Kanban));
|
|
90
|
+
const typename = kanban?.view.target?.query ? getTypenameFromQuery(kanban.view.target.query.ast) : undefined;
|
|
89
91
|
const schema = useSchema(space?.db, typename);
|
|
92
|
+
const projection = useProjectionModel(schema, kanban, registry);
|
|
90
93
|
|
|
91
|
-
const
|
|
92
|
-
const filteredObjects = useGlobalFilteredObjects(objects);
|
|
93
|
-
|
|
94
|
-
const projection = useProjectionModel(schema, object, registry);
|
|
95
|
-
const model = useKanbanModel({
|
|
96
|
-
object,
|
|
97
|
-
projection,
|
|
98
|
-
items: filteredObjects,
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
const handleAddCard = useCallback(
|
|
102
|
-
(columnValue: string | undefined) => {
|
|
103
|
-
const path = model?.columnFieldPath;
|
|
104
|
-
if (space && schema && Type.isObjectSchema(schema) && path) {
|
|
105
|
-
const card = Obj.make(schema, {
|
|
106
|
-
...createOrg(),
|
|
107
|
-
[path]: columnValue,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
space.db.add(card);
|
|
111
|
-
return card.id;
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
[space, schema, model],
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
const handleRemoveCard = useCallback((card: { id: string }) => Obj.isObject(card) && space?.db.remove(card), [space]);
|
|
94
|
+
const data = useMemo(() => (kanban ? { subject: kanban, attendableId: 'story' } : {}), [kanban]);
|
|
118
95
|
|
|
119
96
|
const handleUpdateQuery = useCallback(
|
|
120
97
|
(newQuery: QueryAST.Query) => {
|
|
121
98
|
invariant(schema);
|
|
122
|
-
invariant(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
Obj.change(
|
|
127
|
-
|
|
99
|
+
invariant(kanban?.view.target);
|
|
100
|
+
if (Type.isMutable(schema)) {
|
|
101
|
+
schema.updateTypename(getTypenameFromQuery(newQuery));
|
|
102
|
+
}
|
|
103
|
+
Obj.change(kanban.view.target, (view) => {
|
|
104
|
+
view.query.ast = newQuery as Mutable<QueryAST.Query>;
|
|
128
105
|
});
|
|
129
106
|
},
|
|
130
|
-
[
|
|
107
|
+
[kanban, schema],
|
|
131
108
|
);
|
|
132
109
|
|
|
133
110
|
const handleDeleteField = useCallback(
|
|
@@ -139,23 +116,27 @@ const DefaultComponent = () => {
|
|
|
139
116
|
[schema, projection],
|
|
140
117
|
);
|
|
141
118
|
|
|
142
|
-
if (!schema || !
|
|
119
|
+
if (!schema || !kanban?.view.target) {
|
|
143
120
|
return null;
|
|
144
121
|
}
|
|
145
122
|
|
|
146
123
|
return (
|
|
147
|
-
<div className='grow grid grid-cols-[1fr_350px] overflow-hidden'>
|
|
148
|
-
|
|
149
|
-
<div className='flex flex-col
|
|
124
|
+
<div className='grow grid grid-cols-[1fr_350px] overflow-hidden h-full w-full'>
|
|
125
|
+
<Surface.Surface role='article' data={data} limit={1} />
|
|
126
|
+
<div className='flex flex-col h-full overflow-hidden border-l border-separator'>
|
|
150
127
|
<ViewEditor
|
|
151
|
-
classNames='p-2'
|
|
152
128
|
registry={space?.db.schemaRegistry}
|
|
153
129
|
schema={schema}
|
|
154
|
-
view={
|
|
130
|
+
view={kanban.view.target}
|
|
155
131
|
onQueryChanged={handleUpdateQuery}
|
|
156
|
-
onDelete={Type.isMutable(schema) ? handleDeleteField : undefined}
|
|
132
|
+
onDelete={schema && Type.isMutable(schema) ? handleDeleteField : undefined}
|
|
157
133
|
/>
|
|
158
|
-
<
|
|
134
|
+
<Json.Root data={{ view: kanban.view.target, schema }}>
|
|
135
|
+
<Json.Content>
|
|
136
|
+
<Json.Filter />
|
|
137
|
+
<Json.Data classNames='text-xs' />
|
|
138
|
+
</Json.Content>
|
|
139
|
+
</Json.Root>
|
|
159
140
|
</div>
|
|
160
141
|
</div>
|
|
161
142
|
);
|
|
@@ -166,13 +147,13 @@ const DefaultComponent = () => {
|
|
|
166
147
|
//
|
|
167
148
|
|
|
168
149
|
const meta = {
|
|
169
|
-
title: 'plugins/plugin-kanban/Kanban',
|
|
150
|
+
title: 'plugins/plugin-kanban/containers/Kanban',
|
|
170
151
|
component: DefaultComponent,
|
|
171
152
|
render: () => <DefaultComponent />,
|
|
172
|
-
decorators: [
|
|
153
|
+
decorators: [withLayout({ layout: 'fullscreen' })],
|
|
173
154
|
parameters: {
|
|
174
155
|
layout: 'fullscreen',
|
|
175
|
-
translations
|
|
156
|
+
translations,
|
|
176
157
|
},
|
|
177
158
|
} satisfies Meta<typeof DefaultComponent>;
|
|
178
159
|
|
|
@@ -189,7 +170,7 @@ export const Default: Story = {
|
|
|
189
170
|
withKanbanPlugins({
|
|
190
171
|
types: [Organization.Organization, Person.Person],
|
|
191
172
|
onSpaceCreated: async (space) => {
|
|
192
|
-
const { view } = await
|
|
173
|
+
const { view } = await ViewModel.makeFromDatabase({
|
|
193
174
|
db: space.db,
|
|
194
175
|
typename: Organization.Organization.typename,
|
|
195
176
|
pivotFieldName: 'status',
|
|
@@ -197,8 +178,7 @@ export const Default: Story = {
|
|
|
197
178
|
const kanban = Kanban.make({ view });
|
|
198
179
|
space.db.add(kanban);
|
|
199
180
|
|
|
200
|
-
|
|
201
|
-
Array.from({ length: 80 }).map(() => {
|
|
181
|
+
Array.from({ length: 10 }).map(() => {
|
|
202
182
|
return space.db.add(Obj.make(Organization.Organization, createOrg()));
|
|
203
183
|
});
|
|
204
184
|
},
|
|
@@ -209,25 +189,24 @@ export const Default: Story = {
|
|
|
209
189
|
|
|
210
190
|
// Wait for the kanban columns to render by finding the status tags.
|
|
211
191
|
// Organization.StatusOptions: prospect, qualified, active, commit, reject.
|
|
212
|
-
const activeTag = await canvas.findByText('Active', undefined, { timeout:
|
|
213
|
-
const prospectTag = await canvas.findByText('Prospect', undefined, { timeout:
|
|
214
|
-
const commitTag = await canvas.findByText('Commit', undefined, { timeout:
|
|
192
|
+
const activeTag = await canvas.findByText('Active', undefined, { timeout: 12_000 });
|
|
193
|
+
const prospectTag = await canvas.findByText('Prospect', undefined, { timeout: 12_000 });
|
|
194
|
+
const commitTag = await canvas.findByText('Commit', undefined, { timeout: 12_000 });
|
|
215
195
|
|
|
216
196
|
// Verify all expected columns are rendered.
|
|
217
197
|
await expect(activeTag).toBeTruthy();
|
|
218
198
|
await expect(prospectTag).toBeTruthy();
|
|
219
199
|
await expect(commitTag).toBeTruthy();
|
|
220
200
|
|
|
221
|
-
// Find the column containers.
|
|
222
|
-
const activeColumn = activeTag.closest('[data-
|
|
223
|
-
const prospectColumn = prospectTag.closest('[data-
|
|
201
|
+
// Find the column containers (Board uses data-testid="board-column").
|
|
202
|
+
const activeColumn = activeTag.closest('[data-testid="board-column"]') as HTMLElement;
|
|
203
|
+
const prospectColumn = prospectTag.closest('[data-testid="board-column"]') as HTMLElement;
|
|
224
204
|
await expect(activeColumn).toBeTruthy();
|
|
225
205
|
await expect(prospectColumn).toBeTruthy();
|
|
226
206
|
|
|
227
|
-
// Wait for cards to render in the columns.
|
|
228
|
-
// Cards have data-dx-item-id attribute from StackItem.Root.
|
|
207
|
+
// Wait for cards to render in the columns (Board items use data-testid="board-item").
|
|
229
208
|
const getColumnCards = (column: HTMLElement) =>
|
|
230
|
-
Array.from(column.querySelectorAll('[data-
|
|
209
|
+
Array.from(column.querySelectorAll('[data-testid="board-item"]')) as HTMLElement[];
|
|
231
210
|
|
|
232
211
|
await waitFor(() => expect(getColumnCards(activeColumn).length).toBeGreaterThan(0));
|
|
233
212
|
|
|
@@ -237,16 +216,16 @@ export const Default: Story = {
|
|
|
237
216
|
await expect(activeCards.length).toBeGreaterThan(0);
|
|
238
217
|
await expect(prospectCards.length).toBeGreaterThan(0);
|
|
239
218
|
|
|
240
|
-
// Verify cards have drag handles (
|
|
219
|
+
// Verify cards have drag handles (Card.Toolbar includes drag handle).
|
|
241
220
|
const firstActiveCard = activeCards[0];
|
|
242
221
|
const buttons = firstActiveCard.querySelectorAll('button');
|
|
243
222
|
await expect(buttons.length).toBeGreaterThan(0);
|
|
244
223
|
|
|
245
|
-
// Verify
|
|
246
|
-
const
|
|
247
|
-
const
|
|
248
|
-
await expect(
|
|
249
|
-
await expect(
|
|
224
|
+
// Verify add-card action exists in columns (optional footer).
|
|
225
|
+
const activeAddItem = activeColumn.querySelector('[data-testid="board-column-add-item"]');
|
|
226
|
+
const prospectAddItem = prospectColumn.querySelector('[data-testid="board-column-add-item"]');
|
|
227
|
+
await expect(activeAddItem).toBeTruthy();
|
|
228
|
+
await expect(prospectAddItem).toBeTruthy();
|
|
250
229
|
|
|
251
230
|
// TODO(wittjosiah): Get drag & drop tests working.
|
|
252
231
|
// See packages/apps/composer-app/src/playwright/stack.spec.ts for reference.
|
|
@@ -268,7 +247,7 @@ export const MutableSchema: Story = {
|
|
|
268
247
|
// Register schema in the database to make it mutable (EchoSchema).
|
|
269
248
|
const [schema] = await space.db.schemaRegistry.register([Organization.Organization]);
|
|
270
249
|
|
|
271
|
-
const { view } = await
|
|
250
|
+
const { view } = await ViewModel.makeFromDatabase({
|
|
272
251
|
db: space.db,
|
|
273
252
|
typename: schema.typename,
|
|
274
253
|
pivotFieldName: 'status',
|
|
@@ -277,9 +256,14 @@ export const MutableSchema: Story = {
|
|
|
277
256
|
space.db.add(kanban);
|
|
278
257
|
|
|
279
258
|
// Create test data using the registered schema.
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
259
|
+
const requiredOrgs = [
|
|
260
|
+
...Array.from({ length: 2 }, () => createOrg('prospect')),
|
|
261
|
+
...Array.from({ length: 5 }, () => createOrg('qualified')),
|
|
262
|
+
...Array.from({ length: 1 }, () => createOrg('active')),
|
|
263
|
+
...Array.from({ length: 1 }, () => createOrg('commit')),
|
|
264
|
+
...Array.from({ length: 1 }, () => createOrg('reject')),
|
|
265
|
+
];
|
|
266
|
+
requiredOrgs.forEach((org) => space.db.add(Obj.make(schema, org)));
|
|
283
267
|
},
|
|
284
268
|
}),
|
|
285
269
|
],
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { RegistryContext } from '@effect-atom/atom-react';
|
|
6
|
+
import React, { useCallback, useContext, useMemo } from 'react';
|
|
7
|
+
|
|
8
|
+
import { useCapabilities, useOperationInvoker } from '@dxos/app-framework/ui';
|
|
9
|
+
import { AppCapabilities } from '@dxos/app-toolkit';
|
|
10
|
+
import { type AppSurface } from '@dxos/app-toolkit/ui';
|
|
11
|
+
import { Filter, Obj, Query, Type } from '@dxos/echo';
|
|
12
|
+
import { AtomQuery } from '@dxos/echo-atom';
|
|
13
|
+
import { useObject, useSchema } from '@dxos/react-client/echo';
|
|
14
|
+
import { Panel, Toolbar } from '@dxos/react-ui';
|
|
15
|
+
import { getTagFromQuery, getTypenameFromQuery } from '@dxos/schema';
|
|
16
|
+
|
|
17
|
+
import { KanbanBoard } from '#components';
|
|
18
|
+
import { useEchoChangeCallback, useProjectionModel } from '#hooks';
|
|
19
|
+
import { KanbanOperation } from '#operations';
|
|
20
|
+
import { type Kanban } from '#types';
|
|
21
|
+
|
|
22
|
+
export type KanbanContainerProps = AppSurface.ObjectArticleProps<Kanban.Kanban>;
|
|
23
|
+
|
|
24
|
+
export const KanbanContainer = ({ role, subject: object }: KanbanContainerProps) => {
|
|
25
|
+
const registry = useContext(RegistryContext);
|
|
26
|
+
const schemas = useCapabilities(AppCapabilities.Schema);
|
|
27
|
+
const db = Obj.getDatabase(object);
|
|
28
|
+
const { invokePromise } = useOperationInvoker();
|
|
29
|
+
const [view] = useObject(object.view);
|
|
30
|
+
const typename = view?.query ? getTypenameFromQuery(view.query.ast) : undefined;
|
|
31
|
+
const tag = view?.query ? getTagFromQuery(view.query.ast) : undefined;
|
|
32
|
+
|
|
33
|
+
const schemaFromDb = useSchema(db, typename);
|
|
34
|
+
const cardSchema = useMemo(
|
|
35
|
+
() => schemaFromDb ?? schemas.flat().find((schema) => Type.getTypename(schema) === typename),
|
|
36
|
+
[schemaFromDb, schemas, typename],
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const items = useMemo(() => {
|
|
40
|
+
if (!db) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const baseFilter = cardSchema ? Filter.type(cardSchema) : Filter.nothing();
|
|
44
|
+
const query = tag ? Query.select(baseFilter).select(Filter.tag(tag)) : Query.select(baseFilter);
|
|
45
|
+
return AtomQuery.make(db, query);
|
|
46
|
+
}, [db, cardSchema, tag]);
|
|
47
|
+
|
|
48
|
+
const projection = useProjectionModel(cardSchema, object, registry);
|
|
49
|
+
const change = useEchoChangeCallback(object);
|
|
50
|
+
|
|
51
|
+
const pivotFieldId = view?.projection?.pivotFieldId;
|
|
52
|
+
const columnFieldPath =
|
|
53
|
+
projection && pivotFieldId ? projection.tryGetFieldProjection(pivotFieldId)?.props.property : undefined;
|
|
54
|
+
|
|
55
|
+
const handleCardAdd = useCallback(
|
|
56
|
+
(columnValue: string | undefined) => {
|
|
57
|
+
if (db && cardSchema && columnFieldPath) {
|
|
58
|
+
const card = Obj.make(cardSchema, { [columnFieldPath]: columnValue });
|
|
59
|
+
db.add(card);
|
|
60
|
+
return card.id;
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
[db, cardSchema, columnFieldPath],
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const handleCardRemove = useCallback(
|
|
67
|
+
(card: { id: string }) => {
|
|
68
|
+
void invokePromise(KanbanOperation.DeleteCard, { card });
|
|
69
|
+
},
|
|
70
|
+
[invokePromise],
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
if (!object || !db || !items || !projection || !change) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<Panel.Root role={role}>
|
|
79
|
+
<Panel.Toolbar asChild>
|
|
80
|
+
<Toolbar.Root />
|
|
81
|
+
</Panel.Toolbar>
|
|
82
|
+
<KanbanBoard.Root
|
|
83
|
+
kanban={object}
|
|
84
|
+
projection={projection}
|
|
85
|
+
items={items}
|
|
86
|
+
change={change}
|
|
87
|
+
onCardAdd={handleCardAdd}
|
|
88
|
+
onCardRemove={handleCardRemove}
|
|
89
|
+
>
|
|
90
|
+
<Panel.Content asChild>
|
|
91
|
+
<KanbanBoard.Content />
|
|
92
|
+
</Panel.Content>
|
|
93
|
+
</KanbanBoard.Root>
|
|
94
|
+
</Panel.Root>
|
|
95
|
+
);
|
|
96
|
+
};
|
|
@@ -5,40 +5,44 @@
|
|
|
5
5
|
import { RegistryContext } from '@effect-atom/atom-react';
|
|
6
6
|
import React, { useCallback, useContext, useMemo } from 'react';
|
|
7
7
|
|
|
8
|
+
import { type AppSurface } from '@dxos/app-toolkit/ui';
|
|
8
9
|
import { Obj } from '@dxos/echo';
|
|
9
10
|
import { Format } from '@dxos/echo/internal';
|
|
10
|
-
import {
|
|
11
|
-
import { useSchema } from '@dxos/react-client/echo';
|
|
11
|
+
import { useObject, useSchema } from '@dxos/react-client/echo';
|
|
12
12
|
import { Form, type FormFieldMap, SelectField } from '@dxos/react-ui-form';
|
|
13
|
-
import { useProjectionModel } from '@dxos/react-ui-kanban';
|
|
14
|
-
import { type Kanban } from '@dxos/react-ui-kanban/types';
|
|
15
13
|
import { getTypenameFromQuery } from '@dxos/schema';
|
|
16
14
|
|
|
17
|
-
import {
|
|
15
|
+
import { useProjectionModel } from '#hooks';
|
|
16
|
+
import { type Kanban, SettingsSchema } from '#types';
|
|
18
17
|
|
|
19
|
-
type KanbanViewEditorProps =
|
|
18
|
+
export type KanbanViewEditorProps = AppSurface.ObjectPropertiesProps<Kanban.Kanban>;
|
|
20
19
|
|
|
21
|
-
export const KanbanViewEditor = ({ object }: KanbanViewEditorProps) => {
|
|
20
|
+
export const KanbanViewEditor = ({ subject: object }: KanbanViewEditorProps) => {
|
|
22
21
|
const registry = useContext(RegistryContext);
|
|
23
22
|
const db = Obj.getDatabase(object);
|
|
24
|
-
const view = object.view
|
|
23
|
+
const [view, updateView] = useObject(object.view);
|
|
25
24
|
const currentTypename = view?.query ? getTypenameFromQuery(view.query.ast) : undefined;
|
|
26
25
|
const schema = useSchema(db, currentTypename);
|
|
27
26
|
const projection = useProjectionModel(schema, object, registry);
|
|
28
27
|
|
|
29
|
-
const fieldProjections = projection?.getFieldProjections()
|
|
30
|
-
const selectFields =
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
const fieldProjections = projection?.getFieldProjections() ?? [];
|
|
29
|
+
const selectFields = useMemo(
|
|
30
|
+
() =>
|
|
31
|
+
fieldProjections
|
|
32
|
+
.filter((field) => field.props.format === Format.TypeFormat.SingleSelect)
|
|
33
|
+
.map(({ field }) => ({ value: field.id, label: field.path })),
|
|
34
|
+
[fieldProjections],
|
|
35
|
+
);
|
|
33
36
|
|
|
34
|
-
const
|
|
37
|
+
const handleValuesChanged = useCallback(
|
|
35
38
|
(values: Partial<{ columnFieldId: string }>) => {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
if (values.columnFieldId != null) {
|
|
40
|
+
updateView((view) => {
|
|
41
|
+
view.projection.pivotFieldId = values.columnFieldId;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
40
44
|
},
|
|
41
|
-
[
|
|
45
|
+
[updateView],
|
|
42
46
|
);
|
|
43
47
|
|
|
44
48
|
const initialValues = useMemo(
|
|
@@ -52,7 +56,7 @@ export const KanbanViewEditor = ({ object }: KanbanViewEditorProps) => {
|
|
|
52
56
|
);
|
|
53
57
|
|
|
54
58
|
return (
|
|
55
|
-
<Form.Root schema={SettingsSchema} values={initialValues} fieldMap={fieldMap}
|
|
59
|
+
<Form.Root schema={SettingsSchema} values={initialValues} fieldMap={fieldMap} onValuesChanged={handleValuesChanged}>
|
|
56
60
|
<Form.FieldSet />
|
|
57
61
|
</Form.Root>
|
|
58
62
|
);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type ComponentType, lazy } from 'react';
|
|
6
|
+
|
|
7
|
+
export const KanbanContainer: ComponentType<any> = lazy(() => import('./KanbanContainer'));
|
|
8
|
+
export const KanbanViewEditor: ComponentType<any> = lazy(() => import('./KanbanViewEditor'));
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useMemo } from 'react';
|
|
6
|
+
|
|
7
|
+
import { Obj } from '@dxos/echo';
|
|
8
|
+
|
|
9
|
+
import { type Kanban, type KanbanChangeCallback } from '#types';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates a change callback for ECHO-backed kanban and items (plain function, no hooks).
|
|
13
|
+
* Use this when the kanban and items are stored in the ECHO database.
|
|
14
|
+
*/
|
|
15
|
+
export const createEchoChangeCallback = <T extends Obj.Unknown>(kanban: Kanban.Kanban): KanbanChangeCallback<T> => ({
|
|
16
|
+
kanban: (mutate) => Obj.change(kanban, (kanban) => mutate(kanban)),
|
|
17
|
+
setItemField: (item, field, value) => {
|
|
18
|
+
Obj.change(item, (item: any) => {
|
|
19
|
+
item[field] = value;
|
|
20
|
+
});
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns a memoized ECHO change callback for the given kanban.
|
|
26
|
+
* Returns null when kanban is undefined.
|
|
27
|
+
*/
|
|
28
|
+
export const useEchoChangeCallback = <T extends Obj.Unknown = Obj.Unknown>(
|
|
29
|
+
kanban: Kanban.Kanban | undefined,
|
|
30
|
+
): KanbanChangeCallback<T> | null => useMemo(() => (kanban ? createEchoChangeCallback<T>(kanban) : null), [kanban]);
|