@dxos/plugin-thread 0.8.1-staging.391c573 → 0.8.1-staging.97aedb1
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 +8 -1
- package/dist/types/src/components/ChatContainer.d.ts.map +1 -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/MessageContainer.d.ts +3 -2
- package/dist/types/src/components/MessageContainer.d.ts.map +1 -1
- package/dist/types/src/components/ThreadComplementary.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';
|