@dxos/plugin-thread 0.8.1-main.ae460ac → 0.8.1-staging.31c3ee1
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/ChatContainer-IOOAQW6S.mjs +138 -0
- package/dist/lib/browser/ChatContainer-IOOAQW6S.mjs.map +7 -0
- package/dist/lib/browser/app-graph-builder-6W4UKJDI.mjs +41 -0
- package/dist/lib/browser/app-graph-builder-6W4UKJDI.mjs.map +7 -0
- package/dist/lib/browser/{chunk-NAO3LZMZ.mjs → chunk-EP6MRLY7.mjs} +2 -2
- package/dist/lib/browser/{chunk-BNEWNQBO.mjs → chunk-QDJ3Y6WF.mjs} +14 -19
- package/dist/lib/browser/{chunk-BNEWNQBO.mjs.map → chunk-QDJ3Y6WF.mjs.map} +3 -3
- package/dist/lib/browser/chunk-S5ZR4FYW.mjs +17 -0
- package/dist/lib/browser/chunk-S5ZR4FYW.mjs.map +7 -0
- package/dist/lib/browser/{chunk-UPKU23DA.mjs → chunk-TFVPUPOO.mjs} +35 -140
- package/dist/lib/browser/chunk-TFVPUPOO.mjs.map +7 -0
- package/dist/lib/browser/{chunk-636QDHE3.mjs → chunk-WBJLUUOK.mjs} +1 -1
- package/dist/lib/browser/{chunk-636QDHE3.mjs.map → chunk-WBJLUUOK.mjs.map} +2 -2
- package/dist/lib/browser/{chunk-YK3ICB7G.mjs → chunk-WOG72DWE.mjs} +25 -11
- package/dist/lib/browser/chunk-WOG72DWE.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +47 -49
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/{intent-resolver-FAFQ54NP.mjs → intent-resolver-QAY4FLLM.mjs} +134 -94
- package/dist/lib/browser/intent-resolver-QAY4FLLM.mjs.map +7 -0
- package/dist/lib/browser/{markdown-RPYOUBVR.mjs → markdown-7KXBXCUS.mjs} +9 -10
- package/dist/lib/browser/markdown-7KXBXCUS.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{react-surface-Y4MUSICN.mjs → react-surface-MT3OWULR.mjs} +55 -51
- package/dist/lib/browser/react-surface-MT3OWULR.mjs.map +7 -0
- package/dist/lib/browser/{settings-WQTE5AEZ.mjs → settings-4FEC7EAX.mjs} +3 -3
- package/dist/lib/browser/{state-GNFUURIC.mjs → state-PNMSLKAH.mjs} +4 -3
- package/dist/lib/browser/state-PNMSLKAH.mjs.map +7 -0
- package/dist/lib/browser/types.mjs +2 -2
- package/dist/lib/node/ChatContainer-4FNDRF3G.cjs +163 -0
- package/dist/lib/node/ChatContainer-4FNDRF3G.cjs.map +7 -0
- package/dist/lib/node/app-graph-builder-HZNWT4QU.cjs +57 -0
- package/dist/lib/node/app-graph-builder-HZNWT4QU.cjs.map +7 -0
- package/dist/lib/node/{chunk-CMEMMYDL.cjs → chunk-46BSFPBV.cjs} +29 -15
- package/dist/lib/node/chunk-46BSFPBV.cjs.map +7 -0
- package/dist/lib/node/{chunk-AWSTZ2KN.cjs → chunk-AKINTFBH.cjs} +17 -23
- package/dist/lib/node/chunk-AKINTFBH.cjs.map +7 -0
- package/dist/lib/node/chunk-E7Z3BKRQ.cjs +232 -0
- package/dist/lib/node/chunk-E7Z3BKRQ.cjs.map +7 -0
- package/dist/lib/node/{chunk-FPWNZ6TB.cjs → chunk-NQ5DTPOY.cjs} +7 -7
- package/dist/lib/node/{chunk-F735VMTN.cjs → chunk-ONLWOUYZ.cjs} +4 -4
- package/dist/lib/node/{chunk-F735VMTN.cjs.map → chunk-ONLWOUYZ.cjs.map} +2 -2
- package/dist/lib/node/{chunk-BHFHFTHO.cjs → chunk-S2A6BXEA.cjs} +12 -9
- package/dist/lib/node/chunk-S2A6BXEA.cjs.map +7 -0
- package/dist/lib/node/index.cjs +78 -83
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/{intent-resolver-DVBEXJ33.cjs → intent-resolver-S6FE5OR7.cjs} +153 -113
- package/dist/lib/node/intent-resolver-S6FE5OR7.cjs.map +7 -0
- package/dist/lib/node/{markdown-ELRGISXE.cjs → markdown-L2WMCQKM.cjs} +13 -14
- package/dist/lib/node/markdown-L2WMCQKM.cjs.map +7 -0
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/{react-surface-7HLTN5XS.cjs → react-surface-Z45BYECE.cjs} +68 -64
- package/dist/lib/node/react-surface-Z45BYECE.cjs.map +7 -0
- package/dist/lib/node/{settings-7VQYARM5.cjs → settings-IXCPE55J.cjs} +8 -8
- package/dist/lib/node/{state-TQWEZ6B3.cjs → state-AT73KPGZ.cjs} +8 -7
- package/dist/lib/node/state-AT73KPGZ.cjs.map +7 -0
- package/dist/lib/node/types.cjs +4 -4
- package/dist/lib/node/types.cjs.map +1 -1
- package/dist/lib/node-esm/ChatContainer-NYLCL6QA.mjs +139 -0
- package/dist/lib/node-esm/ChatContainer-NYLCL6QA.mjs.map +7 -0
- package/dist/lib/node-esm/app-graph-builder-M3KK5QJH.mjs +42 -0
- package/dist/lib/node-esm/app-graph-builder-M3KK5QJH.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-FXUATCLW.mjs → chunk-42F2DTMM.mjs} +1 -1
- package/dist/lib/node-esm/{chunk-FXUATCLW.mjs.map → chunk-42F2DTMM.mjs.map} +2 -2
- package/dist/lib/node-esm/{chunk-CISLDOH7.mjs → chunk-ADTVMESP.mjs} +35 -140
- package/dist/lib/node-esm/chunk-ADTVMESP.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-33NDMQQQ.mjs → chunk-E446MGLP.mjs} +25 -11
- package/dist/lib/node-esm/chunk-E446MGLP.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-HLWJTUWZ.mjs → chunk-J56FORYF.mjs} +14 -19
- package/dist/lib/node-esm/{chunk-HLWJTUWZ.mjs.map → chunk-J56FORYF.mjs.map} +3 -3
- package/dist/lib/node-esm/{chunk-ZJITX3TO.mjs → chunk-WLY2HMDB.mjs} +2 -2
- package/dist/lib/node-esm/chunk-WSE23GSG.mjs +19 -0
- package/dist/lib/node-esm/chunk-WSE23GSG.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +47 -49
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/{intent-resolver-DHVLBNCC.mjs → intent-resolver-OURFRSSF.mjs} +134 -94
- package/dist/lib/node-esm/intent-resolver-OURFRSSF.mjs.map +7 -0
- package/dist/lib/node-esm/{markdown-23OB7EZG.mjs → markdown-ZKU23UVD.mjs} +9 -10
- package/dist/lib/node-esm/markdown-ZKU23UVD.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/{react-surface-AZHTTR6J.mjs → react-surface-KIJ767JK.mjs} +55 -51
- package/dist/lib/node-esm/react-surface-KIJ767JK.mjs.map +7 -0
- package/dist/lib/node-esm/{settings-SGMM7UDT.mjs → settings-ZUJQ4LWI.mjs} +3 -3
- package/dist/lib/node-esm/{state-7MLR27YG.mjs → state-SSDX5O67.mjs} +4 -3
- package/dist/lib/node-esm/state-SSDX5O67.mjs.map +7 -0
- package/dist/lib/node-esm/types.mjs +2 -2
- package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +181 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +177 -0
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/components/Chat.stories.d.ts.map +1 -1
- package/dist/types/src/components/ChatContainer.d.ts +10 -2
- package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
- package/dist/types/src/components/CommentContainer.d.ts +2 -1
- package/dist/types/src/components/CommentContainer.d.ts.map +1 -1
- package/dist/types/src/components/Comments.stories.d.ts.map +1 -1
- package/dist/types/src/components/CommentsContainer.d.ts +2 -1
- package/dist/types/src/components/CommentsContainer.d.ts.map +1 -1
- package/dist/types/src/components/MessageContainer.d.ts +5 -3
- package/dist/types/src/components/MessageContainer.d.ts.map +1 -1
- package/dist/types/src/components/ThreadComplementary.d.ts +2 -1
- package/dist/types/src/components/ThreadComplementary.d.ts.map +1 -1
- package/dist/types/src/components/ThreadSettings.d.ts +2 -1
- package/dist/types/src/components/ThreadSettings.d.ts.map +1 -1
- 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/components/testing.d.ts +45 -40
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/events.d.ts +4 -0
- package/dist/types/src/events.d.ts.map +1 -0
- package/dist/types/src/hooks/analytics.d.ts +2 -2
- package/dist/types/src/hooks/analytics.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +2 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +2 -7
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +5 -12
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +40 -9
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +33 -30
- package/src/ThreadPlugin.tsx +17 -28
- package/src/capabilities/app-graph-builder.ts +34 -0
- package/src/capabilities/index.ts +1 -0
- package/src/capabilities/intent-resolver.ts +97 -61
- package/src/capabilities/react-surface.tsx +29 -27
- package/src/capabilities/state.ts +1 -1
- package/src/components/Chat.stories.tsx +19 -9
- package/src/components/ChatContainer.tsx +29 -29
- package/src/components/CommentContainer.tsx +8 -2
- package/src/components/Comments.stories.tsx +2 -1
- package/src/components/MessageContainer.tsx +23 -17
- package/src/components/ThreadComplementary.tsx +26 -32
- package/src/components/index.ts +1 -2
- package/src/components/testing.ts +6 -29
- package/src/events.ts +11 -0
- package/src/extensions/threads.ts +3 -3
- package/src/hooks/analytics.ts +23 -18
- package/src/index.ts +2 -0
- package/src/meta.ts +2 -2
- package/src/translations.ts +2 -4
- package/src/types.ts +22 -8
- package/src/util.ts +1 -1
- package/dist/lib/browser/ThreadContainer-6OP5AG2W.mjs +0 -19
- package/dist/lib/browser/ThreadContainer-6OP5AG2W.mjs.map +0 -7
- package/dist/lib/browser/chunk-UPKU23DA.mjs.map +0 -7
- package/dist/lib/browser/chunk-VOMIDDNO.mjs +0 -15
- package/dist/lib/browser/chunk-VOMIDDNO.mjs.map +0 -7
- package/dist/lib/browser/chunk-YK3ICB7G.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-FAFQ54NP.mjs.map +0 -7
- package/dist/lib/browser/markdown-RPYOUBVR.mjs.map +0 -7
- package/dist/lib/browser/react-surface-Y4MUSICN.mjs.map +0 -7
- package/dist/lib/browser/state-GNFUURIC.mjs.map +0 -7
- package/dist/lib/node/ThreadContainer-LTKKLPXX.cjs +0 -45
- package/dist/lib/node/ThreadContainer-LTKKLPXX.cjs.map +0 -7
- package/dist/lib/node/chunk-AWSTZ2KN.cjs.map +0 -7
- package/dist/lib/node/chunk-BHFHFTHO.cjs.map +0 -7
- package/dist/lib/node/chunk-CMEMMYDL.cjs.map +0 -7
- package/dist/lib/node/chunk-RQR5Z23G.cjs +0 -331
- package/dist/lib/node/chunk-RQR5Z23G.cjs.map +0 -7
- package/dist/lib/node/intent-resolver-DVBEXJ33.cjs.map +0 -7
- package/dist/lib/node/markdown-ELRGISXE.cjs.map +0 -7
- package/dist/lib/node/react-surface-7HLTN5XS.cjs.map +0 -7
- package/dist/lib/node/state-TQWEZ6B3.cjs.map +0 -7
- package/dist/lib/node-esm/ThreadContainer-SV74JFRH.mjs +0 -20
- package/dist/lib/node-esm/ThreadContainer-SV74JFRH.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-33NDMQQQ.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-CISLDOH7.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-PJPVEO7E.mjs +0 -17
- package/dist/lib/node-esm/chunk-PJPVEO7E.mjs.map +0 -7
- package/dist/lib/node-esm/intent-resolver-DHVLBNCC.mjs.map +0 -7
- package/dist/lib/node-esm/markdown-23OB7EZG.mjs.map +0 -7
- package/dist/lib/node-esm/react-surface-AZHTTR6J.mjs.map +0 -7
- package/dist/lib/node-esm/state-7MLR27YG.mjs.map +0 -7
- package/dist/types/src/components/ThreadContainer.d.ts +0 -7
- package/dist/types/src/components/ThreadContainer.d.ts.map +0 -1
- package/src/components/ThreadContainer.tsx +0 -22
- /package/dist/lib/browser/{chunk-NAO3LZMZ.mjs.map → chunk-EP6MRLY7.mjs.map} +0 -0
- /package/dist/lib/browser/{settings-WQTE5AEZ.mjs.map → settings-4FEC7EAX.mjs.map} +0 -0
- /package/dist/lib/node/{chunk-FPWNZ6TB.cjs.map → chunk-NQ5DTPOY.cjs.map} +0 -0
- /package/dist/lib/node/{settings-7VQYARM5.cjs.map → settings-IXCPE55J.cjs.map} +0 -0
- /package/dist/lib/node-esm/{chunk-ZJITX3TO.mjs.map → chunk-WLY2HMDB.mjs.map} +0 -0
- /package/dist/lib/node-esm/{settings-SGMM7UDT.mjs.map → settings-ZUJQ4LWI.mjs.map} +0 -0
|
@@ -2,19 +2,17 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
LayoutAction,
|
|
11
|
-
type PluginsContext,
|
|
12
|
-
} from '@dxos/app-framework';
|
|
13
|
-
import { Ref } from '@dxos/echo-schema';
|
|
5
|
+
import { Capabilities, contributes, createIntent, createResolver, type PluginsContext } from '@dxos/app-framework';
|
|
6
|
+
import { ObjectId, Ref } from '@dxos/echo-schema';
|
|
7
|
+
import { invariant } from '@dxos/invariant';
|
|
8
|
+
import { DXN, QueueSubspaceTags } from '@dxos/keys';
|
|
9
|
+
import { refFromDXN } from '@dxos/live-object';
|
|
14
10
|
import { log } from '@dxos/log';
|
|
11
|
+
import { ATTENDABLE_PATH_SEPARATOR, DeckAction } from '@dxos/plugin-deck/types';
|
|
15
12
|
import { ObservabilityAction } from '@dxos/plugin-observability/types';
|
|
16
13
|
import { ChannelType, ThreadType } from '@dxos/plugin-space/types';
|
|
17
14
|
import { create, fullyQualifiedId, getSpace, makeRef } from '@dxos/react-client/echo';
|
|
15
|
+
import { MessageType } from '@dxos/schema';
|
|
18
16
|
|
|
19
17
|
import { ThreadCapabilities } from './capabilities';
|
|
20
18
|
import { THREAD_PLUGIN } from '../meta';
|
|
@@ -22,57 +20,58 @@ import { ThreadAction } from '../types';
|
|
|
22
20
|
|
|
23
21
|
export default (context: PluginsContext) =>
|
|
24
22
|
contributes(Capabilities.IntentResolver, [
|
|
23
|
+
createResolver({
|
|
24
|
+
intent: ThreadAction.CreateChannel,
|
|
25
|
+
resolve: ({ spaceId, name }) => ({
|
|
26
|
+
data: {
|
|
27
|
+
object: create(ChannelType, {
|
|
28
|
+
name,
|
|
29
|
+
queue: refFromDXN(new DXN(DXN.kind.QUEUE, [QueueSubspaceTags.DATA, spaceId, ObjectId.random()])),
|
|
30
|
+
}),
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
}),
|
|
25
34
|
createResolver({
|
|
26
35
|
intent: ThreadAction.Create,
|
|
27
36
|
resolve: ({ name, cursor, subject }) => {
|
|
28
|
-
if
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const { state } = context.requestCapability(ThreadCapabilities.MutableState);
|
|
41
|
-
const subjectId = fullyQualifiedId(subject);
|
|
42
|
-
const thread = create(ThreadType, { name, anchor: cursor, messages: [], status: 'staged' });
|
|
43
|
-
const draft = state.drafts[subjectId];
|
|
44
|
-
if (draft) {
|
|
45
|
-
draft.push(thread);
|
|
46
|
-
} else {
|
|
47
|
-
state.drafts[subjectId] = [thread];
|
|
37
|
+
// Seed the threads array if it does not exist.
|
|
38
|
+
if (subject?.threads === undefined) {
|
|
39
|
+
try {
|
|
40
|
+
// Static schema will throw an error if subject does not support threads array property.
|
|
41
|
+
subject.threads = [];
|
|
42
|
+
} catch (err) {
|
|
43
|
+
log.error('Subject does not support threads array', { typename: subject?.typename });
|
|
44
|
+
return;
|
|
48
45
|
}
|
|
46
|
+
}
|
|
49
47
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
};
|
|
48
|
+
const { state } = context.requestCapability(ThreadCapabilities.MutableState);
|
|
49
|
+
const subjectId = fullyQualifiedId(subject);
|
|
50
|
+
const thread = create(ThreadType, { name, anchor: cursor, messages: [], status: 'staged' });
|
|
51
|
+
const draft = state.drafts[subjectId];
|
|
52
|
+
if (draft) {
|
|
53
|
+
draft.push(thread);
|
|
57
54
|
} else {
|
|
58
|
-
|
|
59
|
-
return {
|
|
60
|
-
data: { object: create(ChannelType, { threads: [makeRef(create(ThreadType, { messages: [] }))] }) },
|
|
61
|
-
};
|
|
55
|
+
state.drafts[subjectId] = [thread];
|
|
62
56
|
}
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
data: { object: thread },
|
|
60
|
+
intents: [
|
|
61
|
+
createIntent(ThreadAction.Select, { current: fullyQualifiedId(thread) }),
|
|
62
|
+
createIntent(DeckAction.ChangeCompanion, {
|
|
63
|
+
primary: subjectId,
|
|
64
|
+
companion: `${subjectId}${ATTENDABLE_PATH_SEPARATOR}comments`,
|
|
65
|
+
}),
|
|
66
|
+
],
|
|
67
|
+
};
|
|
63
68
|
},
|
|
64
69
|
}),
|
|
65
70
|
createResolver({
|
|
66
71
|
intent: ThreadAction.Select,
|
|
67
|
-
resolve: ({ current
|
|
72
|
+
resolve: ({ current }) => {
|
|
68
73
|
const { state } = context.requestCapability(ThreadCapabilities.MutableState);
|
|
69
74
|
state.current = current;
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
intents: !skipOpen
|
|
73
|
-
? [createIntent(LayoutAction.UpdateComplementary, { part: 'complementary', subject: 'comments' })]
|
|
74
|
-
: undefined,
|
|
75
|
-
};
|
|
76
75
|
},
|
|
77
76
|
}),
|
|
78
77
|
createResolver({
|
|
@@ -85,13 +84,17 @@ export default (context: PluginsContext) =>
|
|
|
85
84
|
}
|
|
86
85
|
|
|
87
86
|
const space = getSpace(thread);
|
|
88
|
-
|
|
87
|
+
invariant(space, 'Space not found');
|
|
88
|
+
const spaceId = space.id;
|
|
89
89
|
|
|
90
90
|
return {
|
|
91
91
|
intents: [
|
|
92
92
|
createIntent(ObservabilityAction.SendEvent, {
|
|
93
93
|
name: 'threads.toggle-resolved',
|
|
94
|
-
properties: {
|
|
94
|
+
properties: {
|
|
95
|
+
spaceId,
|
|
96
|
+
threadId: thread.id,
|
|
97
|
+
},
|
|
95
98
|
}),
|
|
96
99
|
],
|
|
97
100
|
};
|
|
@@ -134,7 +137,10 @@ export default (context: PluginsContext) =>
|
|
|
134
137
|
intents: [
|
|
135
138
|
createIntent(ObservabilityAction.SendEvent, {
|
|
136
139
|
name: 'threads.delete',
|
|
137
|
-
properties: {
|
|
140
|
+
properties: {
|
|
141
|
+
spaceId: space.id,
|
|
142
|
+
threadId: thread.id,
|
|
143
|
+
},
|
|
138
144
|
}),
|
|
139
145
|
],
|
|
140
146
|
};
|
|
@@ -147,7 +153,10 @@ export default (context: PluginsContext) =>
|
|
|
147
153
|
intents: [
|
|
148
154
|
createIntent(ObservabilityAction.SendEvent, {
|
|
149
155
|
name: 'threads.undo-delete',
|
|
150
|
-
properties: {
|
|
156
|
+
properties: {
|
|
157
|
+
spaceId: space.id,
|
|
158
|
+
threadId: thread.id,
|
|
159
|
+
},
|
|
151
160
|
}),
|
|
152
161
|
],
|
|
153
162
|
};
|
|
@@ -155,13 +164,22 @@ export default (context: PluginsContext) =>
|
|
|
155
164
|
},
|
|
156
165
|
}),
|
|
157
166
|
createResolver({
|
|
158
|
-
intent: ThreadAction.
|
|
159
|
-
resolve: ({ thread, subject }) => {
|
|
167
|
+
intent: ThreadAction.AddMessage,
|
|
168
|
+
resolve: ({ thread, subject, sender, text }) => {
|
|
160
169
|
const { state } = context.requestCapability(ThreadCapabilities.MutableState);
|
|
161
170
|
const subjectId = fullyQualifiedId(subject);
|
|
162
171
|
const space = getSpace(subject);
|
|
172
|
+
invariant(space, 'Space not found');
|
|
163
173
|
const intents = [];
|
|
164
|
-
|
|
174
|
+
|
|
175
|
+
const message = create(MessageType, {
|
|
176
|
+
sender,
|
|
177
|
+
created: new Date().toISOString(),
|
|
178
|
+
blocks: [{ type: 'text', text }],
|
|
179
|
+
// TODO(wittjosiah): Context based on attention.
|
|
180
|
+
// context: context ? makeRef(context) : undefined,
|
|
181
|
+
});
|
|
182
|
+
thread.messages.push(makeRef(message));
|
|
165
183
|
|
|
166
184
|
if (state.drafts[subjectId]?.find((t) => t === thread)) {
|
|
167
185
|
// Move draft to document.
|
|
@@ -170,16 +188,25 @@ export default (context: PluginsContext) =>
|
|
|
170
188
|
state.drafts[subjectId] = state.drafts[subjectId]?.filter(({ id }) => id !== thread.id);
|
|
171
189
|
intents.push(
|
|
172
190
|
createIntent(ObservabilityAction.SendEvent, {
|
|
173
|
-
name: 'threads.
|
|
174
|
-
properties:
|
|
191
|
+
name: 'threads.create',
|
|
192
|
+
properties: {
|
|
193
|
+
spaceId: space.id,
|
|
194
|
+
threadId: thread.id,
|
|
195
|
+
},
|
|
175
196
|
}),
|
|
176
197
|
);
|
|
177
198
|
}
|
|
178
199
|
|
|
179
200
|
intents.push(
|
|
180
201
|
createIntent(ObservabilityAction.SendEvent, {
|
|
181
|
-
name: 'threads.message
|
|
182
|
-
properties: {
|
|
202
|
+
name: 'threads.message.add',
|
|
203
|
+
properties: {
|
|
204
|
+
spaceId: space.id,
|
|
205
|
+
threadId: thread.id,
|
|
206
|
+
threadLength: thread.messages.length,
|
|
207
|
+
messageId: message.id,
|
|
208
|
+
messageLength: text.length,
|
|
209
|
+
},
|
|
183
210
|
}),
|
|
184
211
|
);
|
|
185
212
|
|
|
@@ -190,6 +217,7 @@ export default (context: PluginsContext) =>
|
|
|
190
217
|
intent: ThreadAction.DeleteMessage,
|
|
191
218
|
resolve: ({ subject, thread, messageId, message, messageIndex }, undo) => {
|
|
192
219
|
const space = getSpace(subject);
|
|
220
|
+
invariant(space, 'Space not found');
|
|
193
221
|
|
|
194
222
|
if (!undo) {
|
|
195
223
|
const messageIndex = thread.messages.findIndex(Ref.hasObjectId(messageId));
|
|
@@ -215,12 +243,16 @@ export default (context: PluginsContext) =>
|
|
|
215
243
|
intents: [
|
|
216
244
|
createIntent(ObservabilityAction.SendEvent, {
|
|
217
245
|
name: 'threads.message.delete',
|
|
218
|
-
properties: {
|
|
246
|
+
properties: {
|
|
247
|
+
spaceId: space.id,
|
|
248
|
+
threadId: thread.id,
|
|
249
|
+
messageId: message.id,
|
|
250
|
+
},
|
|
219
251
|
}),
|
|
220
252
|
],
|
|
221
253
|
};
|
|
222
254
|
} else {
|
|
223
|
-
if (
|
|
255
|
+
if (messageIndex === undefined || !message) {
|
|
224
256
|
return;
|
|
225
257
|
}
|
|
226
258
|
|
|
@@ -229,7 +261,11 @@ export default (context: PluginsContext) =>
|
|
|
229
261
|
intents: [
|
|
230
262
|
createIntent(ObservabilityAction.SendEvent, {
|
|
231
263
|
name: 'threads.message.undo-delete',
|
|
232
|
-
properties: {
|
|
264
|
+
properties: {
|
|
265
|
+
spaceId: space.id,
|
|
266
|
+
threadId: thread.id,
|
|
267
|
+
messageId: message.id,
|
|
268
|
+
},
|
|
233
269
|
}),
|
|
234
270
|
],
|
|
235
271
|
};
|
|
@@ -6,11 +6,12 @@ import React from 'react';
|
|
|
6
6
|
|
|
7
7
|
import { Capabilities, contributes, createSurface, useLayout } from '@dxos/app-framework';
|
|
8
8
|
import { type Ref } from '@dxos/echo-schema';
|
|
9
|
+
import { DXN } from '@dxos/keys';
|
|
9
10
|
import { SettingsStore } from '@dxos/local-storage';
|
|
10
11
|
import { ChannelType, type ThreadType } from '@dxos/plugin-space/types';
|
|
11
|
-
import { getSpace } from '@dxos/react-client/echo';
|
|
12
|
+
import { getSpace, isSpace, type Space } from '@dxos/react-client/echo';
|
|
12
13
|
|
|
13
|
-
import {
|
|
14
|
+
import { ChatContainer, ThreadComplementary, ThreadSettings } from '../components';
|
|
14
15
|
import { THREAD_PLUGIN } from '../meta';
|
|
15
16
|
import { type ThreadSettingsProps } from '../types';
|
|
16
17
|
|
|
@@ -19,40 +20,41 @@ export default () =>
|
|
|
19
20
|
createSurface({
|
|
20
21
|
id: `${THREAD_PLUGIN}/channel`,
|
|
21
22
|
role: 'article',
|
|
22
|
-
filter: (data): data is { subject: ChannelType } =>
|
|
23
|
-
|
|
24
|
-
component: ({ data, role }) => {
|
|
23
|
+
filter: (data): data is { subject: ChannelType } => data.subject instanceof ChannelType,
|
|
24
|
+
component: ({ data: { subject: channel }, role }) => {
|
|
25
25
|
const layout = useLayout();
|
|
26
|
-
const channel = data.subject;
|
|
27
|
-
void channel.threads[0].load();
|
|
28
|
-
const thread = channel.threads[0].target;
|
|
29
|
-
if (!thread) {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
26
|
const currentPosition = layout.active.findIndex((id) => id === channel.id);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
const objectToTheLeft = layout.active[currentPosition - 1];
|
|
28
|
+
const context = currentPosition > 0 ? getSpace(channel)?.db.getObjectById(objectToTheLeft) : undefined;
|
|
29
|
+
const space = getSpace(channel);
|
|
30
|
+
if (!space) {
|
|
31
|
+
return null;
|
|
38
32
|
}
|
|
39
33
|
|
|
40
|
-
return <
|
|
34
|
+
return <ChatContainer space={space} dxn={channel.queue.dxn} context={context} />;
|
|
41
35
|
},
|
|
42
36
|
}),
|
|
43
37
|
createSurface({
|
|
44
|
-
id: `${THREAD_PLUGIN}/
|
|
45
|
-
role: '
|
|
46
|
-
filter: (data): data is {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
38
|
+
id: `${THREAD_PLUGIN}/comments`,
|
|
39
|
+
role: 'article',
|
|
40
|
+
filter: (data): data is { companionTo: { threads: Ref<ThreadType>[] } } =>
|
|
41
|
+
data.subject === 'comments' &&
|
|
42
|
+
!!data.companionTo &&
|
|
43
|
+
typeof data.companionTo === 'object' &&
|
|
44
|
+
'threads' in data.companionTo &&
|
|
45
|
+
Array.isArray(data.companionTo.threads),
|
|
46
|
+
// TODO(wittjosiah): This isn't scrolling properly in a plank.
|
|
47
|
+
component: ({ data }) => <ThreadComplementary subject={data.companionTo} />,
|
|
48
|
+
}),
|
|
49
|
+
createSurface({
|
|
50
|
+
id: `${THREAD_PLUGIN}/tabpanel`,
|
|
51
|
+
role: 'tabpanel',
|
|
52
|
+
filter: (data): data is { subject: DXN; space: Space } =>
|
|
53
|
+
data.subject instanceof DXN && data.type === 'chat' && isSpace(data.space),
|
|
54
|
+
component: ({ data: { subject: dxn, space } }) => <ChatContainer dxn={dxn} space={space} />,
|
|
53
55
|
}),
|
|
54
56
|
createSurface({
|
|
55
|
-
id: `${THREAD_PLUGIN}/settings`,
|
|
57
|
+
id: `${THREAD_PLUGIN}/plugin-settings`,
|
|
56
58
|
role: 'article',
|
|
57
59
|
filter: (data): data is { subject: SettingsStore<ThreadSettingsProps> } =>
|
|
58
60
|
data.subject instanceof SettingsStore && data.subject.prefix === THREAD_PLUGIN,
|
|
@@ -11,7 +11,7 @@ import { type ThreadState, type ViewStore } from '../types';
|
|
|
11
11
|
const initialViewState = { showResolvedThreads: false };
|
|
12
12
|
|
|
13
13
|
export default () => {
|
|
14
|
-
const state = create<ThreadState>({ drafts: {} });
|
|
14
|
+
const state = create<ThreadState>({ activities: {}, drafts: {} });
|
|
15
15
|
const viewStore = create<ViewStore>({});
|
|
16
16
|
|
|
17
17
|
const getViewState = (subjectId: string) => {
|
|
@@ -7,19 +7,22 @@ import '@dxos-theme';
|
|
|
7
7
|
import { type Meta } from '@storybook/react';
|
|
8
8
|
import React, { useEffect, useState } from 'react';
|
|
9
9
|
|
|
10
|
-
import { Capabilities, contributes, createSurface } from '@dxos/app-framework';
|
|
10
|
+
import { Capabilities, contributes, createSurface, IntentPlugin } from '@dxos/app-framework';
|
|
11
11
|
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
12
|
-
import {
|
|
12
|
+
import { ObjectId } from '@dxos/echo-schema';
|
|
13
|
+
import { DXN, QueueSubspaceTags } from '@dxos/keys';
|
|
14
|
+
import { refFromDXN } from '@dxos/live-object';
|
|
15
|
+
import { ChannelType, ThreadType } from '@dxos/plugin-space/types';
|
|
13
16
|
import { faker } from '@dxos/random';
|
|
14
17
|
import { useClient } from '@dxos/react-client';
|
|
15
|
-
import { type Space } from '@dxos/react-client/echo';
|
|
18
|
+
import { create, type Space } from '@dxos/react-client/echo';
|
|
16
19
|
import { useIdentity } from '@dxos/react-client/halo';
|
|
17
20
|
import { withClientProvider } from '@dxos/react-client/testing';
|
|
18
21
|
import { Thread } from '@dxos/react-ui-thread';
|
|
22
|
+
import { MessageType } from '@dxos/schema';
|
|
19
23
|
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
20
24
|
|
|
21
25
|
import { ChatContainer } from './ChatContainer';
|
|
22
|
-
import { createChatThread } from './testing';
|
|
23
26
|
import translations from '../translations';
|
|
24
27
|
|
|
25
28
|
faker.seed(1);
|
|
@@ -28,25 +31,31 @@ const Story = () => {
|
|
|
28
31
|
const client = useClient();
|
|
29
32
|
const identity = useIdentity();
|
|
30
33
|
const [space, setSpace] = useState<Space>();
|
|
31
|
-
const [
|
|
34
|
+
const [channel, setChannel] = useState<ChannelType | null>();
|
|
32
35
|
|
|
33
36
|
useEffect(() => {
|
|
34
37
|
if (identity) {
|
|
35
38
|
setTimeout(async () => {
|
|
36
39
|
const space = await client.spaces.create();
|
|
37
|
-
const
|
|
40
|
+
const channel = space.db.add(
|
|
41
|
+
create(ChannelType, {
|
|
42
|
+
queue: refFromDXN(new DXN(DXN.kind.QUEUE, [QueueSubspaceTags.DATA, space.id, ObjectId.random()])),
|
|
43
|
+
}),
|
|
44
|
+
);
|
|
38
45
|
setSpace(space);
|
|
39
|
-
|
|
46
|
+
setChannel(channel);
|
|
40
47
|
});
|
|
41
48
|
}
|
|
42
49
|
}, [identity]);
|
|
43
50
|
|
|
44
|
-
if (!identity || !
|
|
51
|
+
if (!identity || !channel || !space) {
|
|
45
52
|
return null;
|
|
46
53
|
}
|
|
47
54
|
|
|
48
55
|
return (
|
|
49
|
-
<main className='max-is-prose mli-auto bs-dvh overflow-hidden'>
|
|
56
|
+
<main className='max-is-prose mli-auto bs-dvh overflow-hidden'>
|
|
57
|
+
<ChatContainer space={space} dxn={channel.queue.dxn} />
|
|
58
|
+
</main>
|
|
50
59
|
);
|
|
51
60
|
};
|
|
52
61
|
|
|
@@ -58,6 +67,7 @@ const meta: Meta = {
|
|
|
58
67
|
render: () => <Story />,
|
|
59
68
|
decorators: [
|
|
60
69
|
withPluginManager({
|
|
70
|
+
plugins: [IntentPlugin()],
|
|
61
71
|
capabilities: [
|
|
62
72
|
contributes(
|
|
63
73
|
Capabilities.ReactSurface,
|
|
@@ -4,16 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
import React, { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
7
|
+
import { createStatic } from '@dxos/echo-schema';
|
|
8
|
+
import { type DXN } from '@dxos/keys';
|
|
9
|
+
import { makeRef } from '@dxos/live-object';
|
|
10
|
+
import { type Space, useMembers, useQueue } from '@dxos/react-client/echo';
|
|
11
11
|
import { useIdentity } from '@dxos/react-client/halo';
|
|
12
12
|
import { Icon, ScrollArea, useThemeContext, useTranslation } from '@dxos/react-ui';
|
|
13
13
|
import { createBasicExtensions, createThemeExtensions, listener } from '@dxos/react-ui-editor';
|
|
14
14
|
import { StackItem } from '@dxos/react-ui-stack';
|
|
15
15
|
import { mx } from '@dxos/react-ui-theme';
|
|
16
16
|
import { MessageTextbox, type MessageTextboxProps, Thread, ThreadFooter, threadLayout } from '@dxos/react-ui-thread';
|
|
17
|
+
import { MessageType } from '@dxos/schema';
|
|
17
18
|
|
|
18
19
|
import { MessageContainer } from './MessageContainer';
|
|
19
20
|
import { command } from './command-extension';
|
|
@@ -34,11 +35,17 @@ export const ChatHeading = ({ attendableId }: { attendableId?: string }) => {
|
|
|
34
35
|
);
|
|
35
36
|
};
|
|
36
37
|
|
|
37
|
-
export
|
|
38
|
+
export type ChatContainerProps = Omit<ThreadContainerProps, 'thread'> & {
|
|
39
|
+
space: Space;
|
|
40
|
+
dxn: DXN;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const ChatContainer = ({ space, dxn, context, current, autoFocusTextbox }: ChatContainerProps) => {
|
|
44
|
+
const id = dxn.toString();
|
|
38
45
|
const identity = useIdentity()!;
|
|
39
|
-
const space = getSpace(thread);
|
|
40
46
|
const members = useMembers(space?.key);
|
|
41
|
-
const
|
|
47
|
+
const queue = useQueue<MessageType>(dxn, { pollInterval: 1_000 });
|
|
48
|
+
const activity = useStatus(space, id);
|
|
42
49
|
const { t } = useTranslation(THREAD_PLUGIN);
|
|
43
50
|
// TODO(wittjosiah): This is a hack to reset the editor after a message is sent.
|
|
44
51
|
const [_count, _setCount] = useState(0);
|
|
@@ -47,7 +54,7 @@ export const ChatContainer = ({ thread, context, current, autoFocusTextbox }: Th
|
|
|
47
54
|
const threadScrollRef = useRef<HTMLDivElement | null>(null);
|
|
48
55
|
const { themeMode } = useThemeContext();
|
|
49
56
|
|
|
50
|
-
const textboxMetadata = getMessageMetadata(
|
|
57
|
+
const textboxMetadata = getMessageMetadata(id, identity);
|
|
51
58
|
const messageRef = useRef('');
|
|
52
59
|
const extensions = useMemo(
|
|
53
60
|
() => [
|
|
@@ -72,20 +79,18 @@ export const ChatContainer = ({ thread, context, current, autoFocusTextbox }: Th
|
|
|
72
79
|
|
|
73
80
|
// TODO(burdon): Change to model.
|
|
74
81
|
const handleCreate: MessageTextboxProps['onSend'] = () => {
|
|
75
|
-
if (!messageRef.current?.length) {
|
|
82
|
+
if (!messageRef.current?.length || !queue) {
|
|
76
83
|
return false;
|
|
77
84
|
}
|
|
78
85
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
),
|
|
88
|
-
);
|
|
86
|
+
queue.append([
|
|
87
|
+
createStatic(MessageType, {
|
|
88
|
+
sender: { identityDid: identity.did },
|
|
89
|
+
created: new Date().toISOString(),
|
|
90
|
+
blocks: [{ type: 'text', text: messageRef.current }],
|
|
91
|
+
properties: context ? { context: makeRef(context) } : undefined,
|
|
92
|
+
}),
|
|
93
|
+
]);
|
|
89
94
|
|
|
90
95
|
messageRef.current = '';
|
|
91
96
|
setAutoFocus(true);
|
|
@@ -94,24 +99,17 @@ export const ChatContainer = ({ thread, context, current, autoFocusTextbox }: Th
|
|
|
94
99
|
return true;
|
|
95
100
|
};
|
|
96
101
|
|
|
97
|
-
const handleDelete = (id: string) => {
|
|
98
|
-
const messageIndex = thread.messages.findIndex(Ref.hasObjectId(id));
|
|
99
|
-
if (messageIndex !== -1) {
|
|
100
|
-
thread.messages.splice(messageIndex, 1);
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
102
|
return (
|
|
105
103
|
<Thread
|
|
106
104
|
current={current}
|
|
107
|
-
id={
|
|
105
|
+
id={id}
|
|
108
106
|
classNames='bs-full grid-rows-[1fr_min-content_min-content] overflow-hidden transition-[padding-block-end] [[data-sidebar-inline-start-state=open]_&]:lg:pbe-0'
|
|
109
107
|
>
|
|
110
108
|
<ScrollArea.Root classNames='col-span-2'>
|
|
111
109
|
<ScrollArea.Viewport classNames='overflow-anchored after:overflow-anchor after:block after:bs-px after:-mbs-px [&>div]:min-bs-full [&>div]:!grid [&>div]:grid-rows-[1fr_0]'>
|
|
112
110
|
<div role='none' className={mx(threadLayout, 'place-self-end')}>
|
|
113
|
-
{
|
|
114
|
-
<MessageContainer key={message.id} message={message} members={members}
|
|
111
|
+
{(queue?.items ?? []).map((message) => (
|
|
112
|
+
<MessageContainer key={message.id} message={message} members={members} />
|
|
115
113
|
))}
|
|
116
114
|
</div>
|
|
117
115
|
{/* NOTE(thure): This can’t also be the `overflow-anchor` because `ScrollArea` injects an interceding node that contains this necessary ref’d element. */}
|
|
@@ -126,3 +124,5 @@ export const ChatContainer = ({ thread, context, current, autoFocusTextbox }: Th
|
|
|
126
124
|
</Thread>
|
|
127
125
|
);
|
|
128
126
|
};
|
|
127
|
+
|
|
128
|
+
export default ChatContainer;
|
|
@@ -179,8 +179,14 @@ export const CommentContainer = ({
|
|
|
179
179
|
</div>
|
|
180
180
|
</div>
|
|
181
181
|
{/** TODO(dmaretskyi): How's `thread.messages` undefined? */}
|
|
182
|
-
{RefArray.
|
|
183
|
-
<MessageContainer
|
|
182
|
+
{RefArray.targets(thread.messages?.filter(isNonNullable) ?? []).map((message) => (
|
|
183
|
+
<MessageContainer
|
|
184
|
+
key={message.id}
|
|
185
|
+
editable
|
|
186
|
+
message={message}
|
|
187
|
+
members={members}
|
|
188
|
+
onDelete={handleMessageDelete}
|
|
189
|
+
/>
|
|
184
190
|
))}
|
|
185
191
|
{/*
|
|
186
192
|
TODO(wittjosiah): Can't autofocus this generally.
|
|
@@ -9,11 +9,12 @@ import React, { useEffect, useState } from 'react';
|
|
|
9
9
|
|
|
10
10
|
import { IntentPlugin } from '@dxos/app-framework';
|
|
11
11
|
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
12
|
-
import {
|
|
12
|
+
import { ThreadType } from '@dxos/plugin-space/types';
|
|
13
13
|
import { faker } from '@dxos/random';
|
|
14
14
|
import { Filter, fullyQualifiedId, useQuery, useSpace } from '@dxos/react-client/echo';
|
|
15
15
|
import { useIdentity } from '@dxos/react-client/halo';
|
|
16
16
|
import { type ClientRepeatedComponentProps, ClientRepeater } from '@dxos/react-client/testing';
|
|
17
|
+
import { MessageType } from '@dxos/schema';
|
|
17
18
|
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
18
19
|
|
|
19
20
|
import { CommentsContainer } from './CommentsContainer';
|