@dxos/plugin-thread 0.6.10 → 0.6.11-staging.e6894a4
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/{chunk-TL3JITN7.mjs → chunk-GKPZHUT3.mjs} +2 -1
- package/dist/lib/browser/chunk-GKPZHUT3.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +157 -116
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/types.mjs +1 -1
- package/dist/lib/node/{chunk-WPPLQNMJ.cjs → chunk-D5GOVXHS.cjs} +5 -4
- package/dist/lib/node/chunk-D5GOVXHS.cjs.map +7 -0
- package/dist/lib/node/index.cjs +167 -126
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/types.cjs +2 -2
- package/dist/lib/node/types.cjs.map +1 -1
- package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +7 -0
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +28 -28
- package/src/ThreadPlugin.tsx +153 -101
- package/src/types.ts +10 -0
- package/dist/lib/browser/chunk-TL3JITN7.mjs.map +0 -7
- package/dist/lib/node/chunk-WPPLQNMJ.cjs.map +0 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["types.cjs"],
|
|
4
|
-
"sourcesContent": ["import {\n ThreadAction\n} from \"./chunk-
|
|
4
|
+
"sourcesContent": ["import {\n ThreadAction\n} from \"./chunk-D5GOVXHS.cjs\";\nimport \"./chunk-BWBONZGU.cjs\";\nexport {\n ThreadAction\n};\n//# sourceMappingURL=types.cjs.map\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAEO;AACP,4BAAO;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThreadPlugin.d.ts","sourceRoot":"","sources":["../../../src/ThreadPlugin.tsx"],"names":[],"mappings":"AAQA,OAAO,EAML,KAAK,gBAAgB,
|
|
1
|
+
{"version":3,"file":"ThreadPlugin.d.ts","sourceRoot":"","sources":["../../../src/ThreadPlugin.tsx"],"names":[],"mappings":"AAQA,OAAO,EAML,KAAK,gBAAgB,EAWtB,MAAM,qBAAqB,CAAC;AAqC7B,OAAO,EAAqC,KAAK,oBAAoB,EAA4B,MAAM,SAAS,CAAC;AAcjH,eAAO,MAAM,YAAY,QAAO,gBAAgB,CAAC,oBAAoB,CAmtBpE,CAAC"}
|
|
@@ -6,9 +6,16 @@ export declare enum ThreadAction {
|
|
|
6
6
|
CREATE = "dxos.org/plugin/thread/action/create",
|
|
7
7
|
SELECT = "dxos.org/plugin/thread/action/select",
|
|
8
8
|
DELETE = "dxos.org/plugin/thread/action/delete",
|
|
9
|
+
ON_MESSAGE_ADD = "dxos.org/plugin/thread/action/on-message-add",
|
|
9
10
|
DELETE_MESSAGE = "dxos.org/plugin/thread/action/delete-message",
|
|
10
11
|
TOGGLE_RESOLVED = "dxos.org/plugin/thread/action/toggle-resolved"
|
|
11
12
|
}
|
|
13
|
+
export type ThreadProvides<T> = {
|
|
14
|
+
thread: {
|
|
15
|
+
predicate: (obj: any) => obj is T;
|
|
16
|
+
createSort: (obj: T) => (anchorA: string, anchorB: string) => number;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
12
19
|
export type ThreadPluginProvides = SurfaceProvides & IntentResolverProvides & GraphBuilderProvides & MetadataRecordsProvides & SettingsProvides & TranslationsProvides & SchemaProvides & MarkdownExtensionProvides;
|
|
13
20
|
export type ThreadSettingsProps = {
|
|
14
21
|
standalone?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,EACvB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAK3D,oBAAY,YAAY;IACtB,MAAM,yCAA4B;IAClC,MAAM,yCAA4B;IAClC,MAAM,yCAA4B;IAClC,cAAc,iDAAoC;IAClD,eAAe,kDAAqC;CACrD;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,EACvB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAK3D,oBAAY,YAAY;IACtB,MAAM,yCAA4B;IAClC,MAAM,yCAA4B;IAClC,MAAM,yCAA4B;IAClC,cAAc,iDAAoC;IAClD,cAAc,iDAAoC;IAClD,eAAe,kDAAqC;CACrD;AAID,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,MAAM,EAAE;QACN,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC;QAClC,UAAU,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;KACtE,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,eAAe,GAChD,sBAAsB,GACtB,oBAAoB,GACpB,uBAAuB,GACvB,gBAAgB,GAChB,oBAAoB,GACpB,cAAc,GACd,yBAAyB,CAAC;AAE5B,MAAM,MAAM,mBAAmB,GAAG;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAE3D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,UAAU,CAAC;CAClB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/plugin-thread",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.11-staging.e6894a4",
|
|
4
4
|
"description": "DXOS Threads Surface plugin",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -51,28 +51,28 @@
|
|
|
51
51
|
"@preact/signals-core": "^1.6.0",
|
|
52
52
|
"date-fns": "^3.3.1",
|
|
53
53
|
"lodash.get": "^4.4.2",
|
|
54
|
-
"@dxos/
|
|
55
|
-
"@dxos/
|
|
56
|
-
"@dxos/
|
|
57
|
-
"@dxos/
|
|
58
|
-
"@dxos/
|
|
59
|
-
"@dxos/
|
|
60
|
-
"@dxos/
|
|
61
|
-
"@dxos/plugin-
|
|
62
|
-
"@dxos/plugin-
|
|
63
|
-
"@dxos/
|
|
64
|
-
"@dxos/plugin-markdown": "0.6.
|
|
65
|
-
"@dxos/plugin-
|
|
66
|
-
"@dxos/plugin-
|
|
67
|
-
"@dxos/plugin-space": "0.6.
|
|
68
|
-
"@dxos/react-client": "0.6.
|
|
69
|
-
"@dxos/react-ui-
|
|
70
|
-
"@dxos/react-ui-
|
|
71
|
-
"@dxos/react-ui-editor": "0.6.
|
|
72
|
-
"@dxos/react-ui-
|
|
73
|
-
"@dxos/react-ui-
|
|
74
|
-
"@dxos/react-ui-thread": "0.6.
|
|
75
|
-
"@dxos/util": "0.6.
|
|
54
|
+
"@dxos/async": "0.6.11-staging.e6894a4",
|
|
55
|
+
"@dxos/display-name": "0.6.11-staging.e6894a4",
|
|
56
|
+
"@dxos/echo-schema": "0.6.11-staging.e6894a4",
|
|
57
|
+
"@dxos/invariant": "0.6.11-staging.e6894a4",
|
|
58
|
+
"@dxos/local-storage": "0.6.11-staging.e6894a4",
|
|
59
|
+
"@dxos/log": "0.6.11-staging.e6894a4",
|
|
60
|
+
"@dxos/plugin-attention": "0.6.11-staging.e6894a4",
|
|
61
|
+
"@dxos/plugin-client": "0.6.11-staging.e6894a4",
|
|
62
|
+
"@dxos/plugin-graph": "0.6.11-staging.e6894a4",
|
|
63
|
+
"@dxos/app-framework": "0.6.11-staging.e6894a4",
|
|
64
|
+
"@dxos/plugin-markdown": "0.6.11-staging.e6894a4",
|
|
65
|
+
"@dxos/plugin-observability": "0.6.11-staging.e6894a4",
|
|
66
|
+
"@dxos/plugin-settings": "0.6.11-staging.e6894a4",
|
|
67
|
+
"@dxos/plugin-space": "0.6.11-staging.e6894a4",
|
|
68
|
+
"@dxos/react-client": "0.6.11-staging.e6894a4",
|
|
69
|
+
"@dxos/react-ui-attention": "0.6.11-staging.e6894a4",
|
|
70
|
+
"@dxos/react-ui-deck": "0.6.11-staging.e6894a4",
|
|
71
|
+
"@dxos/react-ui-editor": "0.6.11-staging.e6894a4",
|
|
72
|
+
"@dxos/react-ui-theme": "0.6.11-staging.e6894a4",
|
|
73
|
+
"@dxos/react-ui-mosaic": "0.6.11-staging.e6894a4",
|
|
74
|
+
"@dxos/react-ui-thread": "0.6.11-staging.e6894a4",
|
|
75
|
+
"@dxos/util": "0.6.11-staging.e6894a4"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"@phosphor-icons/react": "^2.1.5",
|
|
@@ -82,16 +82,16 @@
|
|
|
82
82
|
"react": "~18.2.0",
|
|
83
83
|
"react-dom": "~18.2.0",
|
|
84
84
|
"vite": "^5.3.4",
|
|
85
|
-
"@dxos/
|
|
86
|
-
"@dxos/
|
|
87
|
-
"@dxos/storybook-utils": "0.6.
|
|
85
|
+
"@dxos/react-ui": "0.6.11-staging.e6894a4",
|
|
86
|
+
"@dxos/random": "0.6.11-staging.e6894a4",
|
|
87
|
+
"@dxos/storybook-utils": "0.6.11-staging.e6894a4"
|
|
88
88
|
},
|
|
89
89
|
"optionalDependencies": {
|
|
90
90
|
"@phosphor-icons/react": "^2.1.5",
|
|
91
91
|
"react": "^18.0.0",
|
|
92
92
|
"react-dom": "^18.0.0",
|
|
93
|
-
"@dxos/react-ui": "0.6.
|
|
94
|
-
"@dxos/react-ui-theme": "0.6.
|
|
93
|
+
"@dxos/react-ui": "0.6.11-staging.e6894a4",
|
|
94
|
+
"@dxos/react-ui-theme": "0.6.11-staging.e6894a4"
|
|
95
95
|
},
|
|
96
96
|
"publishConfig": {
|
|
97
97
|
"access": "public"
|
package/src/ThreadPlugin.tsx
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { Chat, type IconProps } from '@phosphor-icons/react';
|
|
6
6
|
import { computed, effect } from '@preact/signals-core';
|
|
7
|
-
import React from 'react';
|
|
7
|
+
import React, { useCallback } from 'react';
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
type IntentPluginProvides,
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
isLayoutParts,
|
|
23
23
|
parseMetadataResolverPlugin,
|
|
24
24
|
type IntentDispatcher,
|
|
25
|
+
useResolvePlugins,
|
|
25
26
|
} from '@dxos/app-framework';
|
|
26
27
|
import { type UnsubscribeCallback } from '@dxos/async';
|
|
27
28
|
import { type EchoReactiveObject, getTypename } from '@dxos/echo-schema';
|
|
@@ -40,7 +41,6 @@ import {
|
|
|
40
41
|
Filter,
|
|
41
42
|
createDocAccessor,
|
|
42
43
|
fullyQualifiedId,
|
|
43
|
-
getRangeFromCursor,
|
|
44
44
|
loadObjectReferences,
|
|
45
45
|
} from '@dxos/react-client/echo';
|
|
46
46
|
import { ScrollArea } from '@dxos/react-ui';
|
|
@@ -60,9 +60,10 @@ import {
|
|
|
60
60
|
} from './components';
|
|
61
61
|
import meta, { THREAD_ITEM, THREAD_PLUGIN } from './meta';
|
|
62
62
|
import translations from './translations';
|
|
63
|
-
import { ThreadAction, type ThreadPluginProvides, type ThreadSettingsProps } from './types';
|
|
63
|
+
import { ThreadAction, type ThreadProvides, type ThreadPluginProvides, type ThreadSettingsProps } from './types';
|
|
64
64
|
|
|
65
65
|
type ThreadState = {
|
|
66
|
+
/** An in-memory staging area for threads that are being drafted. */
|
|
66
67
|
staging: Record<string, ThreadType[]>;
|
|
67
68
|
current?: string | undefined;
|
|
68
69
|
focus?: boolean;
|
|
@@ -72,6 +73,7 @@ type SubjectId = string;
|
|
|
72
73
|
const initialViewState = { showResolvedThreads: false };
|
|
73
74
|
type ViewStore = Record<SubjectId, typeof initialViewState>;
|
|
74
75
|
|
|
76
|
+
// TODO(Zan): Every instance of `cursor` should be replaced with `anchor`.
|
|
75
77
|
export const ThreadPlugin = (): PluginDefinition<ThreadPluginProvides> => {
|
|
76
78
|
const settings = new LocalStorageStore<ThreadSettingsProps>(THREAD_PLUGIN);
|
|
77
79
|
const state = create<ThreadState>({ staging: {} });
|
|
@@ -311,6 +313,16 @@ export const ThreadPlugin = (): PluginDefinition<ThreadPluginProvides> => {
|
|
|
311
313
|
case 'complementary': {
|
|
312
314
|
const location = navigationPlugin?.provides.location;
|
|
313
315
|
|
|
316
|
+
const providesThreadsConfig = useCallback(
|
|
317
|
+
(plugin: any): Plugin<ThreadProvides<any>> | undefined =>
|
|
318
|
+
// TODO(Zan): More robust runtime check.
|
|
319
|
+
'thread' in plugin.provides ? (plugin as Plugin<ThreadProvides<any>>) : undefined,
|
|
320
|
+
[],
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
const threadsIntegrators = useResolvePlugins(providesThreadsConfig);
|
|
324
|
+
const threadProvides = threadsIntegrators.map((p) => p.provides.thread);
|
|
325
|
+
|
|
314
326
|
if (data.object instanceof ChannelType && data.object.threads[0]) {
|
|
315
327
|
const channel = data.object;
|
|
316
328
|
// TODO(zan): Maybe we should have utility for positional main object ids.
|
|
@@ -329,45 +341,41 @@ export const ThreadPlugin = (): PluginDefinition<ThreadPluginProvides> => {
|
|
|
329
341
|
return <ThreadArticle thread={data.object.threads[0]} />;
|
|
330
342
|
}
|
|
331
343
|
|
|
332
|
-
if (data.subject instanceof
|
|
333
|
-
|
|
334
|
-
|
|
344
|
+
if (data.subject instanceof ThreadType) {
|
|
345
|
+
return (
|
|
346
|
+
<>
|
|
347
|
+
<ChatHeading attendableId={data.subject.id} />
|
|
348
|
+
<ChatContainer thread={data.subject} />
|
|
349
|
+
</>
|
|
350
|
+
);
|
|
351
|
+
}
|
|
335
352
|
|
|
336
|
-
|
|
337
|
-
|
|
353
|
+
if (
|
|
354
|
+
data.subject &&
|
|
355
|
+
typeof data.subject === 'object' &&
|
|
356
|
+
'threads' in data.subject &&
|
|
357
|
+
Array.isArray(data.subject.threads)
|
|
358
|
+
) {
|
|
359
|
+
const threads = data.subject.threads
|
|
360
|
+
.concat(state.staging[fullyQualifiedId(data.subject)])
|
|
361
|
+
.filter(nonNullable);
|
|
362
|
+
|
|
363
|
+
const createSort = threadProvides.find((p) => p.predicate(data.subject))?.createSort;
|
|
364
|
+
if (createSort) {
|
|
365
|
+
const sort = createSort(data.subject);
|
|
366
|
+
threads.sort((a, b) => sort(a.anchor, b.anchor));
|
|
338
367
|
}
|
|
339
368
|
|
|
340
|
-
const getStartPosition = (cursor: string | undefined) => {
|
|
341
|
-
const range = cursor ? getRangeFromCursor(accessor, cursor) : undefined;
|
|
342
|
-
return range?.start ?? Number.MAX_SAFE_INTEGER;
|
|
343
|
-
};
|
|
344
|
-
|
|
345
|
-
const threads = doc.threads
|
|
346
|
-
.concat(state.staging[data.subject.id])
|
|
347
|
-
.filter(nonNullable)
|
|
348
|
-
.sort((a, b) => getStartPosition(a.anchor) - getStartPosition(b.anchor));
|
|
349
|
-
|
|
350
369
|
const detached = data.subject.threads
|
|
351
370
|
.filter(nonNullable)
|
|
352
371
|
.filter(({ anchor }) => !anchor)
|
|
353
372
|
.map((thread) => thread.id);
|
|
354
373
|
|
|
355
|
-
const qualifiedSubjectId = fullyQualifiedId(
|
|
374
|
+
const qualifiedSubjectId = fullyQualifiedId(data.subject);
|
|
356
375
|
const attention = attentionPlugin?.provides.attention?.attended ?? new Set([qualifiedSubjectId]);
|
|
357
376
|
const attendableAttrs = createAttendableAttributes(qualifiedSubjectId);
|
|
358
|
-
const space = getSpace(doc);
|
|
359
377
|
const { showResolvedThreads } = getViewState(qualifiedSubjectId);
|
|
360
378
|
|
|
361
|
-
const dispatchAnalytic = (name: string, meta: any) => {
|
|
362
|
-
void dispatch?.({
|
|
363
|
-
action: ObservabilityAction.SEND_EVENT,
|
|
364
|
-
data: {
|
|
365
|
-
name,
|
|
366
|
-
properties: { ...meta, space: space?.id },
|
|
367
|
-
},
|
|
368
|
-
});
|
|
369
|
-
};
|
|
370
|
-
|
|
371
379
|
return (
|
|
372
380
|
<div role='none' className='contents group/attention' {...attendableAttrs}>
|
|
373
381
|
{role === 'complementary' && <CommentsHeading attendableId={qualifiedSubjectId} />}
|
|
@@ -396,14 +404,14 @@ export const ThreadPlugin = (): PluginDefinition<ThreadPluginProvides> => {
|
|
|
396
404
|
dispatch?.({
|
|
397
405
|
plugin: THREAD_PLUGIN,
|
|
398
406
|
action: ThreadAction.DELETE,
|
|
399
|
-
data: {
|
|
407
|
+
data: { subject: data.subject, thread },
|
|
400
408
|
})
|
|
401
409
|
}
|
|
402
410
|
onMessageDelete={(thread, messageId) =>
|
|
403
411
|
dispatch?.({
|
|
404
412
|
plugin: THREAD_PLUGIN,
|
|
405
413
|
action: ThreadAction.DELETE_MESSAGE,
|
|
406
|
-
data: {
|
|
414
|
+
data: { subject: data.subject, thread, messageId },
|
|
407
415
|
})
|
|
408
416
|
}
|
|
409
417
|
onThreadToggleResolved={(thread) =>
|
|
@@ -414,19 +422,9 @@ export const ThreadPlugin = (): PluginDefinition<ThreadPluginProvides> => {
|
|
|
414
422
|
})
|
|
415
423
|
}
|
|
416
424
|
onComment={(thread) => {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
// Move thread from staging to document.
|
|
421
|
-
thread.status = 'active';
|
|
422
|
-
doc.threads ? doc.threads.push(thread) : (doc.threads = [thread]);
|
|
423
|
-
state.staging[doc.id] = state.staging[doc.id]?.filter((t) => t.id !== thread.id);
|
|
424
|
-
dispatchAnalytic('threads.thread-created', { threadId: thread.id });
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
dispatchAnalytic('threads.message-added', {
|
|
428
|
-
threadId: thread.id,
|
|
429
|
-
threadLength: thread.messages.length,
|
|
425
|
+
void intentPlugin?.provides.intent.dispatch({
|
|
426
|
+
action: ThreadAction.ON_MESSAGE_ADD,
|
|
427
|
+
data: { thread, subject: data.subject },
|
|
430
428
|
});
|
|
431
429
|
}}
|
|
432
430
|
/>
|
|
@@ -438,13 +436,6 @@ export const ThreadPlugin = (): PluginDefinition<ThreadPluginProvides> => {
|
|
|
438
436
|
</ScrollArea.Root>
|
|
439
437
|
</div>
|
|
440
438
|
);
|
|
441
|
-
} else if (data.subject instanceof ThreadType) {
|
|
442
|
-
return (
|
|
443
|
-
<>
|
|
444
|
-
<ChatHeading attendableId={data.subject.id} />
|
|
445
|
-
<ChatContainer thread={data.subject} />
|
|
446
|
-
</>
|
|
447
|
-
);
|
|
448
439
|
}
|
|
449
440
|
}
|
|
450
441
|
}
|
|
@@ -456,7 +447,50 @@ export const ThreadPlugin = (): PluginDefinition<ThreadPluginProvides> => {
|
|
|
456
447
|
resolver: async (intent) => {
|
|
457
448
|
switch (intent.action) {
|
|
458
449
|
case ThreadAction.CREATE: {
|
|
459
|
-
|
|
450
|
+
if (intent.data && intent.data.cursor !== undefined) {
|
|
451
|
+
const { cursor, name, subject } = intent.data;
|
|
452
|
+
|
|
453
|
+
const subjectId = fullyQualifiedId(subject);
|
|
454
|
+
const thread = create(ThreadType, { name, anchor: cursor, messages: [], status: 'staged' });
|
|
455
|
+
|
|
456
|
+
const stagingArea = state.staging[subjectId];
|
|
457
|
+
if (stagingArea) {
|
|
458
|
+
stagingArea.push(thread);
|
|
459
|
+
} else {
|
|
460
|
+
state.staging[subjectId] = [thread];
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
return {
|
|
464
|
+
data: thread,
|
|
465
|
+
intents: [
|
|
466
|
+
[
|
|
467
|
+
{
|
|
468
|
+
action: NavigationAction.OPEN,
|
|
469
|
+
data: {
|
|
470
|
+
activeParts: {
|
|
471
|
+
complementary: `${subjectId}${SLUG_PATH_SEPARATOR}comments${SLUG_COLLECTION_INDICATOR}`,
|
|
472
|
+
},
|
|
473
|
+
},
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
action: ThreadAction.SELECT,
|
|
477
|
+
data: { current: thread.id, focus: true },
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
action: LayoutAction.SET_LAYOUT,
|
|
481
|
+
data: {
|
|
482
|
+
element: 'complementary',
|
|
483
|
+
subject: subjectId,
|
|
484
|
+
state: true,
|
|
485
|
+
},
|
|
486
|
+
},
|
|
487
|
+
],
|
|
488
|
+
],
|
|
489
|
+
};
|
|
490
|
+
} else {
|
|
491
|
+
// NOTE: This is the standalone thread creation case.
|
|
492
|
+
return { data: create(ChannelType, { threads: [create(ThreadType, { messages: [] })] }) };
|
|
493
|
+
}
|
|
460
494
|
}
|
|
461
495
|
|
|
462
496
|
case ThreadAction.SELECT: {
|
|
@@ -493,32 +527,33 @@ export const ThreadPlugin = (): PluginDefinition<ThreadPluginProvides> => {
|
|
|
493
527
|
}
|
|
494
528
|
|
|
495
529
|
case ThreadAction.DELETE: {
|
|
496
|
-
const {
|
|
497
|
-
if (!(
|
|
530
|
+
const { subject, thread } = intent.data ?? {};
|
|
531
|
+
if (!(subject instanceof DocumentType) || !(thread instanceof ThreadType)) {
|
|
498
532
|
return;
|
|
499
533
|
}
|
|
500
534
|
|
|
501
|
-
const
|
|
535
|
+
const subjectId = fullyQualifiedId(subject);
|
|
536
|
+
const stagingArea = state.staging[subjectId];
|
|
502
537
|
if (stagingArea) {
|
|
503
538
|
// Check if we're deleting a thread that's in the staging area.
|
|
504
539
|
// If so, remove it from the staging area without ceremony.
|
|
505
|
-
const index =
|
|
540
|
+
const index = stagingArea.findIndex((t) => t.id === thread.id);
|
|
506
541
|
if (index !== -1) {
|
|
507
|
-
|
|
542
|
+
stagingArea.splice(index, 1);
|
|
508
543
|
return;
|
|
509
544
|
}
|
|
510
545
|
}
|
|
511
546
|
|
|
512
547
|
const space = getSpace(thread);
|
|
513
|
-
if (!space || !
|
|
548
|
+
if (!space || !subject.threads) {
|
|
514
549
|
return;
|
|
515
550
|
}
|
|
516
551
|
|
|
517
552
|
if (!intent.undo) {
|
|
518
|
-
const index =
|
|
519
|
-
const cursor =
|
|
553
|
+
const index = subject.threads.findIndex((t) => t?.id === thread.id);
|
|
554
|
+
const cursor = subject.threads[index]?.anchor;
|
|
520
555
|
if (index !== -1) {
|
|
521
|
-
|
|
556
|
+
subject.threads?.splice(index, 1);
|
|
522
557
|
}
|
|
523
558
|
|
|
524
559
|
space.db.remove(thread);
|
|
@@ -540,7 +575,7 @@ export const ThreadPlugin = (): PluginDefinition<ThreadPluginProvides> => {
|
|
|
540
575
|
} else if (intent.undo) {
|
|
541
576
|
// TODO(wittjosiah): SDK should do this automatically.
|
|
542
577
|
const savedThread = space.db.add(thread);
|
|
543
|
-
|
|
578
|
+
subject.threads.push(savedThread);
|
|
544
579
|
|
|
545
580
|
return {
|
|
546
581
|
data: true,
|
|
@@ -556,11 +591,52 @@ export const ThreadPlugin = (): PluginDefinition<ThreadPluginProvides> => {
|
|
|
556
591
|
}
|
|
557
592
|
break;
|
|
558
593
|
}
|
|
594
|
+
|
|
595
|
+
case ThreadAction.ON_MESSAGE_ADD: {
|
|
596
|
+
const { thread, subject } = intent.data ?? {};
|
|
597
|
+
if (
|
|
598
|
+
!(thread instanceof ThreadType) ||
|
|
599
|
+
!(subject && typeof subject === 'object' && 'threads' in subject)
|
|
600
|
+
) {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
const subjectId = fullyQualifiedId(subject);
|
|
605
|
+
const space = getSpace(subject);
|
|
606
|
+
const intents = [];
|
|
607
|
+
const analyticsProperties = { threadId: thread.id, spaceId: space?.id };
|
|
608
|
+
|
|
609
|
+
if (state.staging[subjectId]?.find((t) => t === thread)) {
|
|
610
|
+
// Move thread from staging to document.
|
|
611
|
+
thread.status = 'active';
|
|
612
|
+
subject.threads ? subject.threads.push(thread) : (subject.threads = [thread]);
|
|
613
|
+
state.staging[subjectId] = state.staging[subjectId]?.filter((t) => t.id !== thread.id);
|
|
614
|
+
|
|
615
|
+
intents.push({
|
|
616
|
+
action: ObservabilityAction.SEND_EVENT,
|
|
617
|
+
data: { name: 'threads.thread-created', properties: analyticsProperties },
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
intents.push({
|
|
622
|
+
action: ObservabilityAction.SEND_EVENT,
|
|
623
|
+
data: {
|
|
624
|
+
name: 'threads.message-added',
|
|
625
|
+
properties: { ...analyticsProperties, threadLength: thread.messages.length },
|
|
626
|
+
},
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
return {
|
|
630
|
+
data: thread,
|
|
631
|
+
intents: [intents],
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
|
|
559
635
|
case ThreadAction.DELETE_MESSAGE: {
|
|
560
|
-
const {
|
|
561
|
-
const space = getSpace(
|
|
636
|
+
const { subject, thread, messageId } = intent.data ?? {};
|
|
637
|
+
const space = getSpace(subject);
|
|
562
638
|
|
|
563
|
-
if (!(
|
|
639
|
+
if (!(subject instanceof DocumentType) || !(thread instanceof ThreadType) || !space) {
|
|
564
640
|
return;
|
|
565
641
|
}
|
|
566
642
|
|
|
@@ -574,7 +650,7 @@ export const ThreadPlugin = (): PluginDefinition<ThreadPluginProvides> => {
|
|
|
574
650
|
if (messageIndex === 0 && thread.messages.length === 1) {
|
|
575
651
|
// If the message is the only message in the thread, delete the thread.
|
|
576
652
|
return {
|
|
577
|
-
intents: [[{ action: ThreadAction.DELETE, data: {
|
|
653
|
+
intents: [[{ action: ThreadAction.DELETE, data: { subject, thread } }]],
|
|
578
654
|
};
|
|
579
655
|
} else {
|
|
580
656
|
thread.messages.splice(messageIndex, 1);
|
|
@@ -638,7 +714,7 @@ export const ThreadPlugin = (): PluginDefinition<ThreadPluginProvides> => {
|
|
|
638
714
|
|
|
639
715
|
// TODO(Zan): When we have the deepsignal specific equivalent of this we should use that instead.
|
|
640
716
|
const threads = computed(() =>
|
|
641
|
-
[...doc.threads.filter(nonNullable), ...(state.staging[doc
|
|
717
|
+
[...doc.threads.filter(nonNullable), ...(state.staging[fullyQualifiedId(doc)] ?? [])].filter(
|
|
642
718
|
(thread) => !(thread?.status === 'resolved'),
|
|
643
719
|
),
|
|
644
720
|
);
|
|
@@ -673,43 +749,19 @@ export const ThreadPlugin = (): PluginDefinition<ThreadPluginProvides> => {
|
|
|
673
749
|
onCreate: ({ cursor }) => {
|
|
674
750
|
const [start, end] = cursor.split(':');
|
|
675
751
|
const name = doc.content && getTextInRange(createDocAccessor(doc.content, ['content']), start, end);
|
|
676
|
-
const thread = create(ThreadType, { name, anchor: cursor, messages: [], status: 'staged' });
|
|
677
752
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
void intentPlugin?.provides.intent.dispatch([
|
|
686
|
-
{
|
|
687
|
-
action: NavigationAction.OPEN,
|
|
688
|
-
data: {
|
|
689
|
-
activeParts: {
|
|
690
|
-
complementary: `${fullyQualifiedId(doc)}${SLUG_PATH_SEPARATOR}comments${SLUG_COLLECTION_INDICATOR}`,
|
|
691
|
-
},
|
|
692
|
-
},
|
|
693
|
-
},
|
|
694
|
-
{
|
|
695
|
-
action: ThreadAction.SELECT,
|
|
696
|
-
data: { current: thread.id, focus: true },
|
|
697
|
-
},
|
|
698
|
-
{
|
|
699
|
-
action: LayoutAction.SET_LAYOUT,
|
|
700
|
-
data: {
|
|
701
|
-
element: 'complementary',
|
|
702
|
-
subject: doc,
|
|
703
|
-
state: true,
|
|
704
|
-
},
|
|
753
|
+
void intentPlugin?.provides.intent.dispatch({
|
|
754
|
+
action: ThreadAction.CREATE,
|
|
755
|
+
data: {
|
|
756
|
+
cursor,
|
|
757
|
+
name,
|
|
758
|
+
subject: doc,
|
|
705
759
|
},
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
return thread.id;
|
|
760
|
+
});
|
|
709
761
|
},
|
|
710
762
|
onDelete: ({ id }) => {
|
|
711
763
|
// If the thread is in the staging area, remove it.
|
|
712
|
-
const stagingArea = state.staging[doc
|
|
764
|
+
const stagingArea = state.staging[fullyQualifiedId(doc)];
|
|
713
765
|
if (stagingArea) {
|
|
714
766
|
const index = stagingArea.findIndex((thread) => thread.id === id);
|
|
715
767
|
if (index !== -1) {
|
|
@@ -724,7 +776,7 @@ export const ThreadPlugin = (): PluginDefinition<ThreadPluginProvides> => {
|
|
|
724
776
|
},
|
|
725
777
|
onUpdate: ({ id, cursor }) => {
|
|
726
778
|
const thread =
|
|
727
|
-
state.staging[doc
|
|
779
|
+
state.staging[fullyQualifiedId(doc)]?.find((thread) => thread.id === id) ??
|
|
728
780
|
doc.threads.find((thread) => thread?.id === id);
|
|
729
781
|
|
|
730
782
|
if (thread instanceof ThreadType && thread.anchor) {
|
package/src/types.ts
CHANGED
|
@@ -21,10 +21,20 @@ export enum ThreadAction {
|
|
|
21
21
|
CREATE = `${THREAD_ACTION}/create`,
|
|
22
22
|
SELECT = `${THREAD_ACTION}/select`,
|
|
23
23
|
DELETE = `${THREAD_ACTION}/delete`,
|
|
24
|
+
ON_MESSAGE_ADD = `${THREAD_ACTION}/on-message-add`,
|
|
24
25
|
DELETE_MESSAGE = `${THREAD_ACTION}/delete-message`,
|
|
25
26
|
TOGGLE_RESOLVED = `${THREAD_ACTION}/toggle-resolved`,
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
// TODO(Zan): Move this to the plugin-space plugin or another common location
|
|
30
|
+
// when we implement threads in sheets.
|
|
31
|
+
export type ThreadProvides<T> = {
|
|
32
|
+
thread: {
|
|
33
|
+
predicate: (obj: any) => obj is T;
|
|
34
|
+
createSort: (obj: T) => (anchorA: string, anchorB: string) => number;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
|
|
28
38
|
export type ThreadPluginProvides = SurfaceProvides &
|
|
29
39
|
IntentResolverProvides &
|
|
30
40
|
GraphBuilderProvides &
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/types.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport type {\n GraphBuilderProvides,\n IntentResolverProvides,\n MetadataRecordsProvides,\n SettingsProvides,\n SurfaceProvides,\n TranslationsProvides,\n} from '@dxos/app-framework';\nimport { type SchemaProvides } from '@dxos/plugin-client';\nimport { type MarkdownExtensionProvides } from '@dxos/plugin-markdown';\nimport { type ThreadType } from '@dxos/plugin-space/types';\n\nimport { THREAD_PLUGIN } from './meta';\n\nconst THREAD_ACTION = `${THREAD_PLUGIN}/action`;\nexport enum ThreadAction {\n CREATE = `${THREAD_ACTION}/create`,\n SELECT = `${THREAD_ACTION}/select`,\n DELETE = `${THREAD_ACTION}/delete`,\n DELETE_MESSAGE = `${THREAD_ACTION}/delete-message`,\n TOGGLE_RESOLVED = `${THREAD_ACTION}/toggle-resolved`,\n}\n\nexport type ThreadPluginProvides = SurfaceProvides &\n IntentResolverProvides &\n GraphBuilderProvides &\n MetadataRecordsProvides &\n SettingsProvides &\n TranslationsProvides &\n SchemaProvides &\n MarkdownExtensionProvides;\n\nexport type ThreadSettingsProps = { standalone?: boolean };\n\nexport interface ThreadModel {\n root: ThreadType;\n}\n"],
|
|
5
|
-
"mappings": ";;;;;AAkBA,IAAMA,gBAAgB,GAAGC,aAAAA;;UACbC,eAAAA;0CACD,GAAGF,aAAAA,SAAsB,IAAA;0CACzB,GAAGA,aAAAA,SAAsB,IAAA;0CACzB,GAAGA,aAAAA,SAAsB,IAAA;kDACjB,GAAGA,aAAAA,iBAA8B,IAAA;mDAChC,GAAGA,aAAAA,kBAA+B,IAAA;GAL1CE,iBAAAA,eAAAA,CAAAA,EAAAA;",
|
|
6
|
-
"names": ["THREAD_ACTION", "THREAD_PLUGIN", "ThreadAction"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/types.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport type {\n GraphBuilderProvides,\n IntentResolverProvides,\n MetadataRecordsProvides,\n SettingsProvides,\n SurfaceProvides,\n TranslationsProvides,\n} from '@dxos/app-framework';\nimport { type SchemaProvides } from '@dxos/plugin-client';\nimport { type MarkdownExtensionProvides } from '@dxos/plugin-markdown';\nimport { type ThreadType } from '@dxos/plugin-space/types';\n\nimport { THREAD_PLUGIN } from './meta';\n\nconst THREAD_ACTION = `${THREAD_PLUGIN}/action`;\nexport enum ThreadAction {\n CREATE = `${THREAD_ACTION}/create`,\n SELECT = `${THREAD_ACTION}/select`,\n DELETE = `${THREAD_ACTION}/delete`,\n DELETE_MESSAGE = `${THREAD_ACTION}/delete-message`,\n TOGGLE_RESOLVED = `${THREAD_ACTION}/toggle-resolved`,\n}\n\nexport type ThreadPluginProvides = SurfaceProvides &\n IntentResolverProvides &\n GraphBuilderProvides &\n MetadataRecordsProvides &\n SettingsProvides &\n TranslationsProvides &\n SchemaProvides &\n MarkdownExtensionProvides;\n\nexport type ThreadSettingsProps = { standalone?: boolean };\n\nexport interface ThreadModel {\n root: ThreadType;\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAkBA,IAAMA,gBAAgB,GAAGC,mCAAAA;;UACbC,eAAAA;0CACD,GAAGF,aAAAA,SAAsB,IAAA;0CACzB,GAAGA,aAAAA,SAAsB,IAAA;0CACzB,GAAGA,aAAAA,SAAsB,IAAA;kDACjB,GAAGA,aAAAA,iBAA8B,IAAA;mDAChC,GAAGA,aAAAA,kBAA+B,IAAA;GAL1CE,iBAAAA,eAAAA,CAAAA,EAAAA;",
|
|
6
|
-
"names": ["THREAD_ACTION", "THREAD_PLUGIN", "ThreadAction"]
|
|
7
|
-
}
|