@dxos/plugin-pipeline 0.8.4-main.3eb6e50203 → 0.8.4-main.3fbcb4aa9b
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/neutral/PipelineContainer-7MK2SS76.mjs +69 -0
- package/dist/lib/neutral/PipelineContainer-7MK2SS76.mjs.map +7 -0
- package/dist/lib/neutral/PipelinePlugin.mjs +26 -0
- package/dist/lib/neutral/PipelinePlugin.mjs.map +7 -0
- package/dist/lib/neutral/PipelinePlugin.node.mjs +21 -0
- package/dist/lib/neutral/PipelinePlugin.node.mjs.map +7 -0
- package/dist/lib/{browser/PipelineSettings-YSGSJHBT.mjs → neutral/PipelineProperties-RRPQ3V6I.mjs} +75 -77
- package/dist/lib/neutral/PipelineProperties-RRPQ3V6I.mjs.map +7 -0
- package/dist/lib/neutral/app-graph-builder-ZLGRWRJU.mjs +44 -0
- package/dist/lib/neutral/app-graph-builder-ZLGRWRJU.mjs.map +7 -0
- package/dist/lib/neutral/capabilities/index.mjs +11 -0
- package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
- package/dist/lib/{browser/chunk-QWNKLHBY.mjs → neutral/chunk-ULB5DKWO.mjs} +2 -9
- package/dist/lib/{browser/chunk-QWNKLHBY.mjs.map → neutral/chunk-ULB5DKWO.mjs.map} +3 -3
- package/dist/lib/neutral/components/index.mjs +206 -0
- package/dist/lib/neutral/components/index.mjs.map +7 -0
- package/dist/lib/neutral/containers/index.mjs +9 -0
- package/dist/lib/neutral/containers/index.mjs.map +7 -0
- package/dist/lib/neutral/create-object-ZJYFACOI.mjs +25 -0
- package/dist/lib/neutral/create-object-ZJYFACOI.mjs.map +7 -0
- package/dist/lib/neutral/hooks/index.mjs +70 -0
- package/dist/lib/neutral/hooks/index.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/neutral/meta.mjs +7 -0
- package/dist/lib/neutral/meta.mjs.map +7 -0
- package/dist/lib/neutral/plugin.mjs +11 -0
- package/dist/lib/neutral/plugin.mjs.map +7 -0
- package/dist/lib/neutral/react-surface-TW6TRMO6.mjs +49 -0
- package/dist/lib/neutral/react-surface-TW6TRMO6.mjs.map +7 -0
- package/dist/lib/neutral/translations.mjs +38 -0
- package/dist/lib/neutral/translations.mjs.map +7 -0
- package/dist/lib/neutral/types/index.mjs +1 -0
- package/dist/lib/neutral/types/index.mjs.map +7 -0
- package/dist/types/src/PipelinePlugin.d.ts +1 -0
- package/dist/types/src/PipelinePlugin.d.ts.map +1 -1
- package/dist/types/src/PipelinePlugin.node.d.ts +4 -0
- package/dist/types/src/PipelinePlugin.node.d.ts.map +1 -0
- package/dist/types/src/PipelinePlugin.test.d.ts +2 -0
- package/dist/types/src/PipelinePlugin.test.d.ts.map +1 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts +6 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/capabilities/create-object.d.ts +11 -0
- package/dist/types/src/capabilities/create-object.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +9 -3
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- 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/components/PipelineComponent/PipelineColumn.d.ts +9 -0
- package/dist/types/src/components/PipelineComponent/PipelineColumn.d.ts.map +1 -0
- package/dist/types/src/components/PipelineComponent/PipelineComponent.d.ts +53 -0
- package/dist/types/src/components/PipelineComponent/PipelineComponent.d.ts.map +1 -0
- package/dist/types/src/components/PipelineComponent/PipelineComponent.stories.d.ts +62 -0
- package/dist/types/src/components/PipelineComponent/PipelineComponent.stories.d.ts.map +1 -0
- package/dist/types/src/components/PipelineComponent/index.d.ts +3 -0
- package/dist/types/src/components/PipelineComponent/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -4
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/PipelineContainer/PipelineContainer.d.ts +6 -0
- package/dist/types/src/containers/PipelineContainer/PipelineContainer.d.ts.map +1 -0
- package/dist/types/src/containers/PipelineContainer/PipelineContainer.stories.d.ts +76 -0
- package/dist/types/src/containers/PipelineContainer/PipelineContainer.stories.d.ts.map +1 -0
- package/dist/types/src/containers/PipelineContainer/index.d.ts +2 -0
- package/dist/types/src/containers/PipelineContainer/index.d.ts.map +1 -0
- package/dist/types/src/containers/PipelineProperties/PipelineProperties.d.ts +11 -0
- package/dist/types/src/containers/PipelineProperties/PipelineProperties.d.ts.map +1 -0
- package/dist/types/src/containers/PipelineProperties/index.d.ts +2 -0
- package/dist/types/src/containers/PipelineProperties/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 +2 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -0
- package/dist/types/src/hooks/usePipelineBoardModel.d.ts +6 -0
- package/dist/types/src/hooks/usePipelineBoardModel.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +0 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/plugin.d.ts +3 -0
- package/dist/types/src/plugin.d.ts.map +1 -0
- package/dist/types/src/templates/research.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +44 -25
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/index.d.ts +0 -2
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +100 -53
- package/src/PipelinePlugin.node.ts +19 -0
- package/src/PipelinePlugin.test.ts +27 -0
- package/src/PipelinePlugin.tsx +7 -31
- package/src/capabilities/app-graph-builder.ts +40 -0
- package/src/capabilities/create-object.ts +29 -0
- package/src/capabilities/index.ts +5 -3
- package/src/capabilities/react-surface.tsx +53 -0
- package/src/components/PipelineComponent/PipelineColumn.tsx +164 -0
- package/src/components/{PipelineComponent.stories.tsx → PipelineComponent/PipelineComponent.stories.tsx} +45 -30
- package/src/components/PipelineComponent/PipelineComponent.tsx +140 -0
- package/src/components/PipelineComponent/index.ts +6 -0
- package/src/components/index.ts +1 -7
- package/src/containers/PipelineContainer/PipelineContainer.stories.tsx +230 -0
- package/src/containers/PipelineContainer/PipelineContainer.tsx +84 -0
- package/src/containers/PipelineContainer/index.ts +5 -0
- package/src/{components/PipelineSettings.tsx → containers/PipelineProperties/PipelineProperties.tsx} +77 -65
- package/src/containers/PipelineProperties/index.ts +5 -0
- package/src/containers/index.ts +8 -0
- package/src/hooks/index.ts +5 -0
- package/src/hooks/usePipelineBoardModel.ts +79 -0
- package/src/index.ts +0 -1
- package/src/meta.ts +1 -1
- package/src/plugin.ts +9 -0
- package/src/templates/research.ts +16 -17
- package/src/translations.ts +22 -21
- package/src/types/index.ts +0 -3
- package/dist/lib/browser/PipelineContainer-I3TPA7ZN.mjs +0 -217
- package/dist/lib/browser/PipelineContainer-I3TPA7ZN.mjs.map +0 -7
- package/dist/lib/browser/PipelineSettings-YSGSJHBT.mjs.map +0 -7
- package/dist/lib/browser/app-graph-builder-NUJB33F7.mjs +0 -65
- package/dist/lib/browser/app-graph-builder-NUJB33F7.mjs.map +0 -7
- package/dist/lib/browser/chunk-7GVESVYR.mjs +0 -42
- package/dist/lib/browser/chunk-7GVESVYR.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -109
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/react-surface-JMMCTIL3.mjs +0 -57
- package/dist/lib/browser/react-surface-JMMCTIL3.mjs.map +0 -7
- package/dist/lib/browser/types/index.mjs +0 -10
- package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts +0 -6
- package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +0 -1
- package/dist/types/src/capabilities/app-graph-builder/index.d.ts +0 -3
- package/dist/types/src/capabilities/app-graph-builder/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/operation-resolver/index.d.ts +0 -2
- 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/PipelineColumn.d.ts +0 -10
- package/dist/types/src/components/PipelineColumn.d.ts.map +0 -1
- package/dist/types/src/components/PipelineComponent.d.ts +0 -38
- package/dist/types/src/components/PipelineComponent.d.ts.map +0 -1
- package/dist/types/src/components/PipelineComponent.stories.d.ts +0 -42
- package/dist/types/src/components/PipelineComponent.stories.d.ts.map +0 -1
- package/dist/types/src/components/PipelineContainer.d.ts +0 -7
- package/dist/types/src/components/PipelineContainer.d.ts.map +0 -1
- package/dist/types/src/components/PipelineContainer.stories.d.ts +0 -56
- package/dist/types/src/components/PipelineContainer.stories.d.ts.map +0 -1
- package/dist/types/src/components/PipelineSettings.d.ts +0 -12
- package/dist/types/src/components/PipelineSettings.d.ts.map +0 -1
- package/dist/types/src/types/PipelineAction.d.ts +0 -25
- package/dist/types/src/types/PipelineAction.d.ts.map +0 -1
- package/src/capabilities/app-graph-builder/app-graph-builder.ts +0 -51
- package/src/capabilities/app-graph-builder/index.ts +0 -7
- package/src/capabilities/operation-resolver/index.ts +0 -5
- package/src/capabilities/operation-resolver/operation-resolver.ts +0 -29
- package/src/capabilities/react-surface/index.ts +0 -7
- package/src/capabilities/react-surface/react-surface.tsx +0 -50
- package/src/components/PipelineColumn.tsx +0 -145
- package/src/components/PipelineComponent.tsx +0 -103
- package/src/components/PipelineContainer.stories.tsx +0 -226
- package/src/components/PipelineContainer.tsx +0 -57
- package/src/types/PipelineAction.ts +0 -29
- /package/dist/lib/{browser/types → neutral}/index.mjs.map +0 -0
|
@@ -2,31 +2,37 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { RegistryContext } from '@effect-atom/atom-react';
|
|
5
6
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
-
import React, { useCallback, useEffect } from 'react';
|
|
7
|
+
import React, { useCallback, useContext, useEffect, useMemo } from 'react';
|
|
7
8
|
|
|
8
9
|
import { Filter, Ref } from '@dxos/client/echo';
|
|
9
|
-
import { Obj, Query
|
|
10
|
-
import {
|
|
10
|
+
import { JsonSchema, Obj, Query } from '@dxos/echo';
|
|
11
|
+
import { Collection, View } from '@dxos/echo';
|
|
12
|
+
import { random } from '@dxos/random';
|
|
11
13
|
import { useQuery } from '@dxos/react-client/echo';
|
|
12
14
|
import { useClientStory, withClientProvider } from '@dxos/react-client/testing';
|
|
13
|
-
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
14
15
|
import { Form, omitId } from '@dxos/react-ui-form';
|
|
15
16
|
import { withMosaic } from '@dxos/react-ui-mosaic/testing';
|
|
16
|
-
import {
|
|
17
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
18
|
+
import { ViewModel } from '@dxos/schema';
|
|
17
19
|
import { createObjectFactory } from '@dxos/schema/testing';
|
|
20
|
+
import { withRegistry } from '@dxos/storybook-utils';
|
|
18
21
|
import { Person, Pipeline } from '@dxos/types';
|
|
19
22
|
|
|
20
|
-
import {
|
|
23
|
+
import { usePipelineBoardModel } from '#hooks';
|
|
24
|
+
import { translations } from '#translations';
|
|
21
25
|
|
|
22
|
-
import { type ItemProps, PipelineComponent
|
|
26
|
+
import { type ItemProps, PipelineComponent } from './PipelineComponent';
|
|
23
27
|
|
|
24
28
|
const StorybookProjectItem = ({ item, projectionModel }: ItemProps) => {
|
|
29
|
+
const personSchema = useMemo(() => omitId(Person.Person), []);
|
|
30
|
+
|
|
25
31
|
if (Obj.instanceOf(Person.Person, item)) {
|
|
26
|
-
const contact = item as Obj.
|
|
32
|
+
const contact = item as Obj.OfShape<Person.Person>;
|
|
27
33
|
|
|
28
34
|
return (
|
|
29
|
-
<Form.Root schema={
|
|
35
|
+
<Form.Root schema={personSchema} projection={projectionModel} values={contact} autoSave>
|
|
30
36
|
<Form.Viewport>
|
|
31
37
|
<Form.Content>
|
|
32
38
|
<Form.FieldSet />
|
|
@@ -40,9 +46,11 @@ const StorybookProjectItem = ({ item, projectionModel }: ItemProps) => {
|
|
|
40
46
|
};
|
|
41
47
|
|
|
42
48
|
const DefaultStory = () => {
|
|
49
|
+
const registry = useContext(RegistryContext);
|
|
43
50
|
const { space } = useClientStory();
|
|
44
51
|
const pipelines = useQuery(space?.db, Filter.type(Pipeline.Pipeline));
|
|
45
52
|
const pipeline = pipelines[0];
|
|
53
|
+
const model = usePipelineBoardModel(pipeline, registry);
|
|
46
54
|
|
|
47
55
|
const handleAddColumn = useCallback(() => {
|
|
48
56
|
if (!space || !pipeline) {
|
|
@@ -50,16 +58,16 @@ const DefaultStory = () => {
|
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
// Create a new view for contacts similar to the initialization.
|
|
53
|
-
const view =
|
|
61
|
+
const view = ViewModel.make({
|
|
54
62
|
query: Query.select(Filter.type(Person.Person)),
|
|
55
|
-
jsonSchema:
|
|
63
|
+
jsonSchema: JsonSchema.toJsonSchema(Person.Person),
|
|
56
64
|
fields: ['fullName'],
|
|
57
65
|
});
|
|
58
66
|
|
|
59
|
-
Obj.
|
|
60
|
-
|
|
67
|
+
Obj.update(pipeline, (pipeline) => {
|
|
68
|
+
pipeline.columns.push({
|
|
61
69
|
name: 'New Contacts',
|
|
62
|
-
view: Ref.make(view) as (typeof
|
|
70
|
+
view: Ref.make(view) as (typeof pipeline.columns)[number]['view'],
|
|
63
71
|
order: [],
|
|
64
72
|
});
|
|
65
73
|
});
|
|
@@ -73,16 +81,20 @@ const DefaultStory = () => {
|
|
|
73
81
|
|
|
74
82
|
return (
|
|
75
83
|
<PipelineComponent.Root Item={StorybookProjectItem} onAddColumn={handleAddColumn}>
|
|
76
|
-
<PipelineComponent.Content
|
|
84
|
+
<PipelineComponent.Content model={model}>
|
|
85
|
+
<PipelineComponent.Columns pipeline={pipeline} />
|
|
86
|
+
</PipelineComponent.Content>
|
|
77
87
|
</PipelineComponent.Root>
|
|
78
88
|
);
|
|
79
89
|
};
|
|
80
90
|
|
|
81
91
|
const MutationsStory = () => {
|
|
92
|
+
const registry = useContext(RegistryContext);
|
|
82
93
|
const { space } = useClientStory();
|
|
83
94
|
const pipelines = useQuery(space?.db, Filter.type(Pipeline.Pipeline));
|
|
84
95
|
const contacts = useQuery(space?.db, Filter.type(Person.Person));
|
|
85
96
|
const pipeline = pipelines[0];
|
|
97
|
+
const model = usePipelineBoardModel(pipeline, registry);
|
|
86
98
|
|
|
87
99
|
const handleAddColumn = useCallback(() => {
|
|
88
100
|
if (!space || !pipeline) {
|
|
@@ -90,16 +102,16 @@ const MutationsStory = () => {
|
|
|
90
102
|
}
|
|
91
103
|
|
|
92
104
|
// Create a new view for contacts similar to the initialization.
|
|
93
|
-
const view =
|
|
105
|
+
const view = ViewModel.make({
|
|
94
106
|
query: Query.select(Filter.type(Person.Person)),
|
|
95
|
-
jsonSchema:
|
|
107
|
+
jsonSchema: JsonSchema.toJsonSchema(Person.Person),
|
|
96
108
|
fields: ['fullName'],
|
|
97
109
|
});
|
|
98
110
|
|
|
99
|
-
Obj.
|
|
100
|
-
|
|
111
|
+
Obj.update(pipeline, (pipeline) => {
|
|
112
|
+
pipeline.columns.push({
|
|
101
113
|
name: 'New Contacts',
|
|
102
|
-
view: Ref.make(view) as (typeof
|
|
114
|
+
view: Ref.make(view) as (typeof pipeline.columns)[number]['view'],
|
|
103
115
|
order: [],
|
|
104
116
|
});
|
|
105
117
|
});
|
|
@@ -113,19 +125,19 @@ const MutationsStory = () => {
|
|
|
113
125
|
}
|
|
114
126
|
|
|
115
127
|
const interval = setInterval(() => {
|
|
116
|
-
const factory = createObjectFactory(space.db,
|
|
128
|
+
const factory = createObjectFactory(space.db, random as any);
|
|
117
129
|
const p = Math.random();
|
|
118
130
|
|
|
119
131
|
if (p < 0.4) {
|
|
120
132
|
// Append to the name
|
|
121
|
-
const contactToAdjust =
|
|
122
|
-
Obj.
|
|
123
|
-
|
|
133
|
+
const contactToAdjust = random.helpers.arrayElement(contacts);
|
|
134
|
+
Obj.update(contactToAdjust, (contactToAdjust) => {
|
|
135
|
+
contactToAdjust.fullName = (contactToAdjust.fullName ?? '') + ' X';
|
|
124
136
|
});
|
|
125
137
|
return;
|
|
126
138
|
} else if (p < 0.7 && contacts.length > 1) {
|
|
127
139
|
// Remove a contact (30% chance, but only if we have more than 1)
|
|
128
|
-
const contactToRemove =
|
|
140
|
+
const contactToRemove = random.helpers.arrayElement(contacts);
|
|
129
141
|
space.db.remove(contactToRemove);
|
|
130
142
|
} else {
|
|
131
143
|
// Add a new contact (30% chance)
|
|
@@ -142,16 +154,19 @@ const MutationsStory = () => {
|
|
|
142
154
|
|
|
143
155
|
return (
|
|
144
156
|
<PipelineComponent.Root Item={StorybookProjectItem} onAddColumn={handleAddColumn}>
|
|
145
|
-
<PipelineComponent.Content
|
|
157
|
+
<PipelineComponent.Content model={model}>
|
|
158
|
+
<PipelineComponent.Columns pipeline={pipeline} />
|
|
159
|
+
</PipelineComponent.Content>
|
|
146
160
|
</PipelineComponent.Root>
|
|
147
161
|
);
|
|
148
162
|
};
|
|
149
163
|
|
|
150
164
|
const meta = {
|
|
151
|
-
title: 'plugins/plugin-pipeline/PipelineComponent',
|
|
165
|
+
title: 'plugins/plugin-pipeline/components/PipelineComponent',
|
|
152
166
|
decorators: [
|
|
153
167
|
withTheme(),
|
|
154
168
|
withLayout({ layout: 'column' }),
|
|
169
|
+
withRegistry,
|
|
155
170
|
withMosaic(),
|
|
156
171
|
withClientProvider({
|
|
157
172
|
types: [Pipeline.Pipeline, View.View, Collection.Collection, Person.Person],
|
|
@@ -159,10 +174,10 @@ const meta = {
|
|
|
159
174
|
createSpace: true,
|
|
160
175
|
onCreateSpace: async ({ space }) => {
|
|
161
176
|
// Create a view for contacts.
|
|
162
|
-
const view =
|
|
177
|
+
const view = ViewModel.make({
|
|
163
178
|
name: 'Contacts',
|
|
164
179
|
query: Query.select(Filter.type(Person.Person)),
|
|
165
|
-
jsonSchema:
|
|
180
|
+
jsonSchema: JsonSchema.toJsonSchema(Person.Person),
|
|
166
181
|
fields: ['fullName'],
|
|
167
182
|
});
|
|
168
183
|
|
|
@@ -180,7 +195,7 @@ const meta = {
|
|
|
180
195
|
);
|
|
181
196
|
|
|
182
197
|
// Generate random contacts.
|
|
183
|
-
const factory = createObjectFactory(space.db,
|
|
198
|
+
const factory = createObjectFactory(space.db, random as any);
|
|
184
199
|
await factory([{ type: Person.Person, count: 12 }]);
|
|
185
200
|
},
|
|
186
201
|
}),
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useAtomValue } from '@effect-atom/atom-react';
|
|
6
|
+
import { createContext } from '@radix-ui/react-context';
|
|
7
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
8
|
+
import React, { type FC, type PropsWithChildren } from 'react';
|
|
9
|
+
|
|
10
|
+
import { Obj } from '@dxos/echo';
|
|
11
|
+
import { Toolbar, type ToolbarRootProps, useTranslation } from '@dxos/react-ui';
|
|
12
|
+
import { Board, type BoardModel, useBoard, useEventHandlerAdapter } from '@dxos/react-ui-mosaic';
|
|
13
|
+
import { type ProjectionModel } from '@dxos/schema';
|
|
14
|
+
import { type Pipeline } from '@dxos/types';
|
|
15
|
+
import { composable, composableProps, slottable } from '@dxos/ui-theme';
|
|
16
|
+
|
|
17
|
+
import { meta } from '#meta';
|
|
18
|
+
|
|
19
|
+
import { PipelineColumn } from './PipelineColumn';
|
|
20
|
+
|
|
21
|
+
type ItemProps = {
|
|
22
|
+
item: Obj.Unknown;
|
|
23
|
+
projectionModel?: ProjectionModel;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const itemNoOp = ({ item }: ItemProps) => <span>{item.id}</span>;
|
|
27
|
+
|
|
28
|
+
//
|
|
29
|
+
// Root
|
|
30
|
+
//
|
|
31
|
+
|
|
32
|
+
type PipelineContextValue = {
|
|
33
|
+
Item: FC<ItemProps>;
|
|
34
|
+
// TODO(wittjosiah): Support adding items.
|
|
35
|
+
// If the created item doesn't match the current query, it will not be visible.
|
|
36
|
+
// TODO(wittjosiah): onAddItem?: (schema: Schema.Schema.AnyNoContext) => void;
|
|
37
|
+
onAddColumn?: () => void;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
type PipelineRootProps = PropsWithChildren<PipelineContextValue>;
|
|
41
|
+
|
|
42
|
+
const PIPELINE_ROOT = 'Pipeline.Root';
|
|
43
|
+
|
|
44
|
+
const [PipelineRootContext, usePipeline] = createContext<PipelineContextValue>(PIPELINE_ROOT, {
|
|
45
|
+
Item: itemNoOp,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const PipelineRoot = ({ children, ...contextValue }: PipelineRootProps) => (
|
|
49
|
+
<PipelineRootContext {...contextValue}>{children}</PipelineRootContext>
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
PipelineRoot.displayName = PIPELINE_ROOT;
|
|
53
|
+
|
|
54
|
+
//
|
|
55
|
+
// Content
|
|
56
|
+
//
|
|
57
|
+
|
|
58
|
+
const PIPELINE_CONTENT_NAME = 'Pipeline.Content';
|
|
59
|
+
|
|
60
|
+
type PipelineContentProps = PropsWithChildren<{
|
|
61
|
+
model: BoardModel<Pipeline.Column, Obj.Unknown>;
|
|
62
|
+
}>;
|
|
63
|
+
|
|
64
|
+
const PipelineContent = slottable<HTMLDivElement, PipelineContentProps>(
|
|
65
|
+
({ asChild, model, children, ...props }, forwardedRef) => {
|
|
66
|
+
const Comp = asChild ? Slot : 'div';
|
|
67
|
+
return (
|
|
68
|
+
<Board.Root model={model}>
|
|
69
|
+
<Comp {...composableProps(props)} ref={forwardedRef}>
|
|
70
|
+
{children}
|
|
71
|
+
</Comp>
|
|
72
|
+
</Board.Root>
|
|
73
|
+
);
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
PipelineContent.displayName = PIPELINE_CONTENT_NAME;
|
|
78
|
+
|
|
79
|
+
//
|
|
80
|
+
// Columns
|
|
81
|
+
//
|
|
82
|
+
|
|
83
|
+
const PIPELINE_COLUMNS_NAME = 'Pipeline.Columns';
|
|
84
|
+
|
|
85
|
+
type PipelineColumnsProps = {
|
|
86
|
+
pipeline: Pipeline.Pipeline;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const PipelineColumns = composable<HTMLDivElement, PipelineColumnsProps>(({ pipeline, ...props }) => {
|
|
90
|
+
const { model } = useBoard(PIPELINE_COLUMNS_NAME);
|
|
91
|
+
const columns = useAtomValue(model.columns);
|
|
92
|
+
const eventHandler = useEventHandlerAdapter<Pipeline.Column, Obj.Unknown>({
|
|
93
|
+
id: pipeline.id,
|
|
94
|
+
// TODO(wittjosiah): Cast because columns array is readonly.
|
|
95
|
+
items: columns as any,
|
|
96
|
+
getId: model.getColumnId,
|
|
97
|
+
get: (data) => data as unknown as Obj.Unknown,
|
|
98
|
+
make: (object) => object as unknown as Pipeline.Column,
|
|
99
|
+
canDrop: ({ source }) => model.isColumn(source.data),
|
|
100
|
+
onChange: (mutate) => Obj.update(pipeline, (pipeline) => mutate(pipeline.columns)),
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
return <Board.Content {...props} id='pipeline' eventHandler={eventHandler} Tile={PipelineColumn} />;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
PipelineColumns.displayName = PIPELINE_COLUMNS_NAME;
|
|
107
|
+
|
|
108
|
+
//
|
|
109
|
+
// Toolbar
|
|
110
|
+
//
|
|
111
|
+
|
|
112
|
+
const PIPELINE_TOOLBAR_NAME = 'Pipeline.Toolbar';
|
|
113
|
+
|
|
114
|
+
export const PipelineToolbar = composable<HTMLDivElement, ToolbarRootProps>(({ children, ...props }, forwardedRef) => {
|
|
115
|
+
const { t } = useTranslation(meta.id);
|
|
116
|
+
const { onAddColumn } = usePipeline(PIPELINE_TOOLBAR_NAME);
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<Toolbar.Root {...composableProps(props)} ref={forwardedRef}>
|
|
120
|
+
<Toolbar.IconButton icon='ph--plus--regular' iconOnly label={t('add-column.label')} onClick={onAddColumn} />
|
|
121
|
+
</Toolbar.Root>
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
PipelineToolbar.displayName = PIPELINE_TOOLBAR_NAME;
|
|
126
|
+
|
|
127
|
+
//
|
|
128
|
+
// Project
|
|
129
|
+
//
|
|
130
|
+
|
|
131
|
+
export const PipelineComponent = {
|
|
132
|
+
Root: PipelineRoot,
|
|
133
|
+
Content: PipelineContent,
|
|
134
|
+
Columns: PipelineColumns,
|
|
135
|
+
Toolbar: PipelineToolbar,
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export { usePipeline };
|
|
139
|
+
|
|
140
|
+
export type { ItemProps, PipelineContextValue, PipelineRootProps, PipelineContentProps, PipelineColumnsProps };
|
package/src/components/index.ts
CHANGED
|
@@ -2,10 +2,4 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export type { PipelineContainerProps } from './PipelineContainer';
|
|
8
|
-
export type { PipelineObjectSettingsProps } from './PipelineSettings';
|
|
9
|
-
|
|
10
|
-
export const PipelineContainer = lazy(() => import('./PipelineContainer'));
|
|
11
|
-
export const PipelineObjectSettings = lazy(() => import('./PipelineSettings'));
|
|
5
|
+
export * from './PipelineComponent';
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Layer from 'effect/Layer';
|
|
8
|
+
import React from 'react';
|
|
9
|
+
|
|
10
|
+
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
11
|
+
import { Filter, Ref } from '@dxos/client/echo';
|
|
12
|
+
import { Database, Feed, JsonSchema, Obj, Query, Tag } from '@dxos/echo';
|
|
13
|
+
import { Collection, View } from '@dxos/echo';
|
|
14
|
+
import { createFeedServiceLayer } from '@dxos/echo-db';
|
|
15
|
+
import { ClientPlugin } from '@dxos/plugin-client/plugin';
|
|
16
|
+
import { initializeIdentity } from '@dxos/plugin-client/testing';
|
|
17
|
+
import { InboxPlugin } from '@dxos/plugin-inbox/plugin';
|
|
18
|
+
import { PreviewPlugin } from '@dxos/plugin-preview/testing';
|
|
19
|
+
import { StorybookPlugin, corePlugins } from '@dxos/plugin-testing';
|
|
20
|
+
import { random } from '@dxos/random';
|
|
21
|
+
import { useDatabase, useQuery } from '@dxos/react-client/echo';
|
|
22
|
+
import { translations as stackTranslations } from '@dxos/react-ui-stack/translations';
|
|
23
|
+
import { withLayout } from '@dxos/react-ui/testing';
|
|
24
|
+
import { ViewModel } from '@dxos/schema';
|
|
25
|
+
import { createObjectFactory } from '@dxos/schema/testing';
|
|
26
|
+
import { Message, Organization, Person, Pipeline, Task } from '@dxos/types';
|
|
27
|
+
|
|
28
|
+
import { translations } from '#translations';
|
|
29
|
+
|
|
30
|
+
import PipelineProperties from '../PipelineProperties';
|
|
31
|
+
import { PipelineContainer } from './PipelineContainer';
|
|
32
|
+
|
|
33
|
+
random.seed(0);
|
|
34
|
+
|
|
35
|
+
const DefaultStory = () => {
|
|
36
|
+
const db = useDatabase();
|
|
37
|
+
const pipelines = useQuery(db, Filter.type(Pipeline.Pipeline));
|
|
38
|
+
const pipeline = pipelines[0];
|
|
39
|
+
|
|
40
|
+
if (!pipeline) {
|
|
41
|
+
return <p>Loading…</p>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div className='grow grid grid-cols-[1fr_350px] overflow-hidden h-full w-full'>
|
|
46
|
+
<PipelineContainer role='article' subject={pipeline} attendableId='test' />
|
|
47
|
+
<PipelineProperties pipeline={pipeline} classNames='border-s border-separator' />
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const meta = {
|
|
53
|
+
title: 'plugins/plugin-pipeline/containers/PipelineContainer',
|
|
54
|
+
render: DefaultStory,
|
|
55
|
+
decorators: [
|
|
56
|
+
withLayout({ layout: 'fullscreen' }),
|
|
57
|
+
withPluginManager({
|
|
58
|
+
plugins: [
|
|
59
|
+
...corePlugins(),
|
|
60
|
+
StorybookPlugin({}),
|
|
61
|
+
ClientPlugin({
|
|
62
|
+
types: [
|
|
63
|
+
Tag.Tag,
|
|
64
|
+
Feed.Feed,
|
|
65
|
+
Pipeline.Pipeline,
|
|
66
|
+
View.View,
|
|
67
|
+
Collection.Collection,
|
|
68
|
+
Organization.Organization,
|
|
69
|
+
Task.Task,
|
|
70
|
+
Person.Person,
|
|
71
|
+
Message.Message,
|
|
72
|
+
],
|
|
73
|
+
onClientInitialized: Effect.fnUntraced(function* ({ client }) {
|
|
74
|
+
const { personalSpace } = yield* initializeIdentity(client);
|
|
75
|
+
|
|
76
|
+
yield* Effect.gen(function* () {
|
|
77
|
+
const tag = yield* Database.add(Tag.make({ label: 'important', hue: 'green' }));
|
|
78
|
+
const tagDxn = Obj.getDXN(tag).toString();
|
|
79
|
+
|
|
80
|
+
// Create a view for Contacts.
|
|
81
|
+
const personView = ViewModel.make({
|
|
82
|
+
query: Query.select(Filter.type(Person.Person)),
|
|
83
|
+
jsonSchema: JsonSchema.toJsonSchema(Person.Person),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Create a view for Organizations.
|
|
87
|
+
const organizationView = ViewModel.make({
|
|
88
|
+
query: Query.select(Filter.type(Organization.Organization)).select(Filter.tag(tagDxn)),
|
|
89
|
+
jsonSchema: JsonSchema.toJsonSchema(Organization.Organization),
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Create a view for Tasks.
|
|
93
|
+
const taskView = ViewModel.make({
|
|
94
|
+
query: Query.select(Filter.type(Task.Task)).select(Filter.tag(tagDxn)),
|
|
95
|
+
jsonSchema: JsonSchema.toJsonSchema(Task.Task),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Create a view for Project-Projects.
|
|
99
|
+
const projectView = ViewModel.make({
|
|
100
|
+
query: Query.select(Filter.type(Pipeline.Pipeline)),
|
|
101
|
+
jsonSchema: JsonSchema.toJsonSchema(Pipeline.Pipeline),
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Create a feed for Messages.
|
|
105
|
+
const messageFeed = yield* Database.add(Feed.make({ name: 'Messages' }));
|
|
106
|
+
const messages = Array.from({ length: 20 }).map(() =>
|
|
107
|
+
Obj.make(Message.Message, {
|
|
108
|
+
created: random.date.recent().toISOString(),
|
|
109
|
+
sender: { role: 'user' },
|
|
110
|
+
blocks: [{ _tag: 'text' as const, text: random.lorem.sentences(2) }],
|
|
111
|
+
}),
|
|
112
|
+
);
|
|
113
|
+
yield* Feed.append(messageFeed, messages);
|
|
114
|
+
|
|
115
|
+
const messageQueueDxn = Feed.getQueueDxn(messageFeed)!.toString();
|
|
116
|
+
const messageView = ViewModel.make({
|
|
117
|
+
query: Query.select(Filter.type(Message.Message)).from({
|
|
118
|
+
queues: [messageQueueDxn],
|
|
119
|
+
}),
|
|
120
|
+
jsonSchema: JsonSchema.toJsonSchema(Message.Message),
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Create a feed for Tasks (for testing feed switching in settings).
|
|
124
|
+
const taskFeed = yield* Database.add(Feed.make({ name: 'Tasks' }));
|
|
125
|
+
const feedTasks = Array.from({ length: 10 }).map(() =>
|
|
126
|
+
Obj.make(Task.Task, {
|
|
127
|
+
title: random.lorem.sentence(),
|
|
128
|
+
status: random.helpers.arrayElement(['todo', 'in-progress', 'done']) as any,
|
|
129
|
+
priority: random.helpers.arrayElement(['low', 'medium', 'high']) as any,
|
|
130
|
+
}),
|
|
131
|
+
);
|
|
132
|
+
yield* Feed.append(taskFeed, feedTasks);
|
|
133
|
+
|
|
134
|
+
// Create pipeline with columns.
|
|
135
|
+
const pipeline = Pipeline.make({
|
|
136
|
+
columns: [
|
|
137
|
+
{
|
|
138
|
+
name: 'Contacts',
|
|
139
|
+
view: Ref.make(personView),
|
|
140
|
+
order: [],
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: 'Organizations',
|
|
144
|
+
view: Ref.make(organizationView),
|
|
145
|
+
order: [],
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: 'Tasks',
|
|
149
|
+
view: Ref.make(taskView),
|
|
150
|
+
order: [],
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: 'Projects',
|
|
154
|
+
view: Ref.make(projectView),
|
|
155
|
+
order: [],
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: 'Messages',
|
|
159
|
+
view: Ref.make(messageView),
|
|
160
|
+
order: [],
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
});
|
|
164
|
+
yield* Database.add(pipeline);
|
|
165
|
+
|
|
166
|
+
// Generate sample Organizations.
|
|
167
|
+
for (const _ of Array.from({ length: 20 })) {
|
|
168
|
+
yield* Database.add(
|
|
169
|
+
Obj.make(Organization.Organization, {
|
|
170
|
+
[Obj.Meta]: {
|
|
171
|
+
tags: random.datatype.boolean() ? [tagDxn] : [],
|
|
172
|
+
},
|
|
173
|
+
name: random.company.name(),
|
|
174
|
+
website: random.internet.url(),
|
|
175
|
+
description: random.lorem.paragraph(),
|
|
176
|
+
image: random.image.url(),
|
|
177
|
+
}),
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Generate sample Tasks.
|
|
182
|
+
for (const _ of Array.from({ length: 20 })) {
|
|
183
|
+
yield* Database.add(
|
|
184
|
+
Obj.make(Task.Task, {
|
|
185
|
+
[Obj.Meta]: {
|
|
186
|
+
tags: random.datatype.boolean() ? [tagDxn] : [],
|
|
187
|
+
},
|
|
188
|
+
title: random.lorem.sentence(),
|
|
189
|
+
status: random.helpers.arrayElement(['todo', 'in-progress', 'done']) as any,
|
|
190
|
+
priority: random.helpers.arrayElement(['low', 'medium', 'high']) as any,
|
|
191
|
+
}),
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Generate sample Contacts.
|
|
196
|
+
const factory = createObjectFactory(personalSpace.db, random as any);
|
|
197
|
+
yield* Effect.promise(() => factory([{ type: Person.Person, count: 12 }]));
|
|
198
|
+
|
|
199
|
+
// Generate sample Projects.
|
|
200
|
+
for (const _ of Array.from({ length: 20 })) {
|
|
201
|
+
yield* Database.add(
|
|
202
|
+
Pipeline.make({
|
|
203
|
+
name: random.commerce.productName(),
|
|
204
|
+
description: random.lorem.sentence(),
|
|
205
|
+
}),
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
}).pipe(
|
|
209
|
+
Effect.provide(
|
|
210
|
+
Layer.merge(Database.layer(personalSpace.db), createFeedServiceLayer(personalSpace.queues)),
|
|
211
|
+
),
|
|
212
|
+
);
|
|
213
|
+
}),
|
|
214
|
+
}),
|
|
215
|
+
InboxPlugin(),
|
|
216
|
+
PreviewPlugin(),
|
|
217
|
+
],
|
|
218
|
+
}),
|
|
219
|
+
],
|
|
220
|
+
parameters: {
|
|
221
|
+
layout: 'fullscreen',
|
|
222
|
+
translations: [...translations, ...stackTranslations],
|
|
223
|
+
},
|
|
224
|
+
} satisfies Meta<typeof PipelineContainer>;
|
|
225
|
+
|
|
226
|
+
export default meta;
|
|
227
|
+
|
|
228
|
+
type Story = StoryObj<typeof meta>;
|
|
229
|
+
|
|
230
|
+
export const Default: Story = {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, { useCallback, useEffect } from 'react';
|
|
6
|
+
|
|
7
|
+
import { Capabilities } from '@dxos/app-framework';
|
|
8
|
+
import { Surface, useCapability, useOperationInvoker } from '@dxos/app-framework/ui';
|
|
9
|
+
import { LayoutOperation } from '@dxos/app-toolkit';
|
|
10
|
+
import {
|
|
11
|
+
AppSurface,
|
|
12
|
+
OBJECT_ACTIONS_CONTRIBUTION_ID,
|
|
13
|
+
OBJECT_ACTIONS_CONTRIBUTION_PRIORITY,
|
|
14
|
+
useObjectMenuItems,
|
|
15
|
+
} from '@dxos/app-toolkit/ui';
|
|
16
|
+
import { Panel } from '@dxos/react-ui';
|
|
17
|
+
import { linkedSegment } from '@dxos/react-ui-attention';
|
|
18
|
+
import { useAttention } from '@dxos/react-ui-attention';
|
|
19
|
+
import { useMenu } from '@dxos/react-ui-menu';
|
|
20
|
+
import { type Pipeline } from '@dxos/types';
|
|
21
|
+
|
|
22
|
+
import { type ItemProps, PipelineComponent } from '#components';
|
|
23
|
+
import { usePipelineBoardModel } from '#hooks';
|
|
24
|
+
|
|
25
|
+
const PIPELINE_ITEM = 'PipelineItem';
|
|
26
|
+
|
|
27
|
+
export type PipelineContainerProps = AppSurface.ObjectArticleProps<Pipeline.Pipeline>;
|
|
28
|
+
|
|
29
|
+
export const PipelineContainer = ({ role, subject: pipeline, attendableId }: PipelineContainerProps) => {
|
|
30
|
+
const registry = useCapability(Capabilities.AtomRegistry);
|
|
31
|
+
const model = usePipelineBoardModel(pipeline, registry);
|
|
32
|
+
const { invokePromise } = useOperationInvoker();
|
|
33
|
+
const { hasAttention } = useAttention(attendableId);
|
|
34
|
+
|
|
35
|
+
const handleColumnAdd = useCallback(
|
|
36
|
+
() =>
|
|
37
|
+
invokePromise(LayoutOperation.UpdateCompanion, {
|
|
38
|
+
subject: linkedSegment('settings'),
|
|
39
|
+
}),
|
|
40
|
+
[invokePromise],
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<PipelineComponent.Root Item={PipelineItem} onAddColumn={handleColumnAdd}>
|
|
45
|
+
<Panel.Root role={role}>
|
|
46
|
+
<Panel.Toolbar asChild>
|
|
47
|
+
<PipelineComponent.Toolbar disabled={!hasAttention} />
|
|
48
|
+
</Panel.Toolbar>
|
|
49
|
+
<Panel.Content asChild>
|
|
50
|
+
<PipelineComponent.Content asChild model={model}>
|
|
51
|
+
<PipelineComponent.Columns pipeline={pipeline} />
|
|
52
|
+
</PipelineComponent.Content>
|
|
53
|
+
</Panel.Content>
|
|
54
|
+
</Panel.Root>
|
|
55
|
+
</PipelineComponent.Root>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const PipelineItem = ({ item, projectionModel }: ItemProps) => {
|
|
60
|
+
const menu = useMenu(PIPELINE_ITEM);
|
|
61
|
+
const items = useObjectMenuItems(item);
|
|
62
|
+
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
menu.addMenuItems({
|
|
65
|
+
id: OBJECT_ACTIONS_CONTRIBUTION_ID,
|
|
66
|
+
mode: 'additive',
|
|
67
|
+
priority: OBJECT_ACTIONS_CONTRIBUTION_PRIORITY,
|
|
68
|
+
items,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return () => menu.removeMenuItems(OBJECT_ACTIONS_CONTRIBUTION_ID);
|
|
72
|
+
}, [menu, items]);
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<Surface.Surface
|
|
76
|
+
type={AppSurface.Card}
|
|
77
|
+
data={{
|
|
78
|
+
subject: item,
|
|
79
|
+
projection: projectionModel,
|
|
80
|
+
}}
|
|
81
|
+
limit={1}
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
|
+
};
|