@dxos/plugin-thread 0.7.5-main.499c70c → 0.7.5-main.5ae2ba8
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/ThreadContainer-6OP5AG2W.mjs +19 -0
- package/dist/lib/browser/ThreadContainer-6OP5AG2W.mjs.map +7 -0
- package/dist/lib/browser/{chunk-ENERBDYI.mjs → chunk-636QDHE3.mjs} +3 -3
- package/dist/lib/browser/chunk-636QDHE3.mjs.map +7 -0
- package/dist/lib/browser/chunk-BNEWNQBO.mjs +71 -0
- package/dist/lib/browser/chunk-BNEWNQBO.mjs.map +7 -0
- package/dist/lib/browser/chunk-NAO3LZMZ.mjs +16 -0
- package/dist/lib/browser/chunk-NAO3LZMZ.mjs.map +7 -0
- package/dist/lib/browser/{chunk-OD2IZKRP.mjs → chunk-UPKU23DA.mjs} +29 -105
- package/dist/lib/browser/chunk-UPKU23DA.mjs.map +7 -0
- package/dist/lib/browser/chunk-VOMIDDNO.mjs +15 -0
- package/dist/lib/browser/chunk-VOMIDDNO.mjs.map +7 -0
- package/dist/lib/browser/{chunk-6KTMQPL4.mjs → chunk-YK3ICB7G.mjs} +5 -3
- package/dist/lib/browser/chunk-YK3ICB7G.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +150 -942
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/intent-resolver-FAFQ54NP.mjs +287 -0
- package/dist/lib/browser/intent-resolver-FAFQ54NP.mjs.map +7 -0
- package/dist/lib/browser/markdown-RPYOUBVR.mjs +112 -0
- package/dist/lib/browser/markdown-RPYOUBVR.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/react-surface-Y4MUSICN.mjs +433 -0
- package/dist/lib/browser/react-surface-Y4MUSICN.mjs.map +7 -0
- package/dist/lib/browser/settings-WQTE5AEZ.mjs +22 -0
- package/dist/lib/browser/settings-WQTE5AEZ.mjs.map +7 -0
- package/dist/lib/browser/state-GNFUURIC.mjs +33 -0
- package/dist/lib/browser/state-GNFUURIC.mjs.map +7 -0
- package/dist/lib/browser/types.mjs +6 -4
- package/dist/lib/node/{ThreadArticle-ZCNMFBAO.cjs → ThreadContainer-LTKKLPXX.cjs} +14 -13
- package/dist/lib/node/ThreadContainer-LTKKLPXX.cjs.map +7 -0
- package/dist/lib/node/chunk-AWSTZ2KN.cjs +93 -0
- package/dist/lib/node/chunk-AWSTZ2KN.cjs.map +7 -0
- package/dist/lib/node/{ThreadMain-5AYGCXXP.cjs → chunk-BHFHFTHO.cjs} +21 -23
- package/dist/lib/node/chunk-BHFHFTHO.cjs.map +7 -0
- package/dist/lib/node/{chunk-VW2P26MZ.cjs → chunk-CMEMMYDL.cjs} +11 -8
- package/dist/lib/node/chunk-CMEMMYDL.cjs.map +7 -0
- package/dist/lib/node/{chunk-IC2NICNC.cjs → chunk-F735VMTN.cjs} +7 -7
- package/dist/lib/node/chunk-F735VMTN.cjs.map +7 -0
- package/dist/lib/node/{meta.cjs → chunk-FPWNZ6TB.cjs} +13 -10
- package/dist/lib/node/chunk-FPWNZ6TB.cjs.map +7 -0
- package/dist/lib/node/{chunk-2CB5AVBL.cjs → chunk-RQR5Z23G.cjs} +74 -151
- package/dist/lib/node/chunk-RQR5Z23G.cjs.map +7 -0
- package/dist/lib/node/index.cjs +149 -935
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/intent-resolver-DVBEXJ33.cjs +299 -0
- package/dist/lib/node/intent-resolver-DVBEXJ33.cjs.map +7 -0
- package/dist/lib/node/markdown-ELRGISXE.cjs +122 -0
- package/dist/lib/node/markdown-ELRGISXE.cjs.map +7 -0
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/react-surface-7HLTN5XS.cjs +435 -0
- package/dist/lib/node/react-surface-7HLTN5XS.cjs.map +7 -0
- package/dist/lib/node/settings-7VQYARM5.cjs +36 -0
- package/dist/lib/node/settings-7VQYARM5.cjs.map +7 -0
- package/dist/lib/node/state-TQWEZ6B3.cjs +49 -0
- package/dist/lib/node/state-TQWEZ6B3.cjs.map +7 -0
- package/dist/lib/node/types.cjs +6 -4
- package/dist/lib/node/types.cjs.map +2 -2
- package/dist/lib/node-esm/ThreadContainer-SV74JFRH.mjs +20 -0
- package/dist/lib/node-esm/ThreadContainer-SV74JFRH.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-RMYATBXM.mjs → chunk-33NDMQQQ.mjs} +5 -3
- package/dist/lib/node-esm/chunk-33NDMQQQ.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-AQ74G3GY.mjs → chunk-CISLDOH7.mjs} +29 -105
- package/dist/lib/node-esm/chunk-CISLDOH7.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-7QRGG25F.mjs → chunk-FXUATCLW.mjs} +3 -3
- package/dist/lib/node-esm/chunk-FXUATCLW.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-HLWJTUWZ.mjs +73 -0
- package/dist/lib/node-esm/chunk-HLWJTUWZ.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-PJPVEO7E.mjs +17 -0
- package/dist/lib/node-esm/chunk-PJPVEO7E.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-ZJITX3TO.mjs +17 -0
- package/dist/lib/node-esm/chunk-ZJITX3TO.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +150 -942
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/intent-resolver-DHVLBNCC.mjs +288 -0
- package/dist/lib/node-esm/intent-resolver-DHVLBNCC.mjs.map +7 -0
- package/dist/lib/node-esm/markdown-23OB7EZG.mjs +113 -0
- package/dist/lib/node-esm/markdown-23OB7EZG.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/react-surface-AZHTTR6J.mjs +434 -0
- package/dist/lib/node-esm/react-surface-AZHTTR6J.mjs.map +7 -0
- package/dist/lib/node-esm/settings-SGMM7UDT.mjs +23 -0
- package/dist/lib/node-esm/settings-SGMM7UDT.mjs.map +7 -0
- package/dist/lib/node-esm/state-7MLR27YG.mjs +34 -0
- package/dist/lib/node-esm/state-7MLR27YG.mjs.map +7 -0
- package/dist/lib/node-esm/types.mjs +6 -4
- package/dist/types/src/ThreadPlugin.d.ts +1 -3
- package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/capabilities.d.ts +15 -0
- package/dist/types/src/capabilities/capabilities.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +10 -0
- package/dist/types/src/capabilities/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/intent-resolver.d.ts +4 -0
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -0
- package/dist/types/src/capabilities/markdown.d.ts +4 -0
- package/dist/types/src/capabilities/markdown.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface.d.ts +4 -0
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
- package/dist/types/src/capabilities/settings.d.ts +4 -0
- package/dist/types/src/capabilities/settings.d.ts.map +1 -0
- package/dist/types/src/capabilities/state.d.ts +7 -0
- package/dist/types/src/capabilities/state.d.ts.map +1 -0
- package/dist/types/src/components/Chat.stories.d.ts.map +1 -1
- package/dist/types/src/components/ChatContainer.d.ts +2 -3
- package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
- package/dist/types/src/components/CommentContainer.d.ts +1 -2
- 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 -8
- package/dist/types/src/components/CommentsContainer.d.ts.map +1 -1
- package/dist/types/src/components/MessageContainer.d.ts +1 -2
- package/dist/types/src/components/MessageContainer.d.ts.map +1 -1
- package/dist/types/src/components/ThreadComplementary.d.ts +2 -7
- package/dist/types/src/components/ThreadComplementary.d.ts.map +1 -1
- package/dist/types/src/components/ThreadContainer.d.ts +7 -0
- package/dist/types/src/components/ThreadContainer.d.ts.map +1 -0
- package/dist/types/src/components/ThreadSettings.d.ts +1 -2
- package/dist/types/src/components/ThreadSettings.d.ts.map +1 -1
- package/dist/types/src/components/command-extension.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +3 -15
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +12 -12
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/components/types.d.ts +5 -5
- package/dist/types/src/components/types.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +1 -2
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +9 -3
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +12 -18
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +31 -38
- package/src/ThreadPlugin.tsx +106 -475
- package/src/capabilities/capabilities.ts +19 -0
- package/src/capabilities/index.ts +13 -0
- package/src/capabilities/intent-resolver.ts +239 -0
- package/src/capabilities/markdown.ts +18 -0
- package/src/capabilities/react-surface.tsx +61 -0
- package/src/capabilities/settings.ts +14 -0
- package/src/capabilities/state.ts +25 -0
- package/src/components/Chat.stories.tsx +22 -24
- package/src/components/ChatContainer.tsx +2 -2
- package/src/components/CommentContainer.tsx +18 -32
- package/src/components/Comments.stories.tsx +8 -2
- package/src/components/CommentsContainer.tsx +1 -17
- package/src/components/MessageContainer.tsx +6 -19
- package/src/components/ThreadComplementary.tsx +118 -51
- package/src/components/ThreadContainer.tsx +22 -0
- package/src/components/ThreadSettings.tsx +5 -11
- package/src/components/command-extension.ts +2 -5
- package/src/components/index.ts +1 -2
- package/src/components/types.ts +5 -5
- package/src/index.ts +1 -5
- package/src/meta.ts +1 -1
- package/src/translations.ts +3 -1
- package/src/types.ts +6 -29
- package/dist/lib/browser/ThreadArticle-EWLTNU6Z.mjs +0 -18
- package/dist/lib/browser/ThreadArticle-EWLTNU6Z.mjs.map +0 -7
- package/dist/lib/browser/ThreadMain-ABEDFWHC.mjs +0 -26
- package/dist/lib/browser/ThreadMain-ABEDFWHC.mjs.map +0 -7
- package/dist/lib/browser/chunk-6KTMQPL4.mjs.map +0 -7
- package/dist/lib/browser/chunk-ENERBDYI.mjs.map +0 -7
- package/dist/lib/browser/chunk-OD2IZKRP.mjs.map +0 -7
- package/dist/lib/browser/meta.mjs +0 -11
- package/dist/lib/browser/meta.mjs.map +0 -7
- package/dist/lib/node/ThreadArticle-ZCNMFBAO.cjs.map +0 -7
- package/dist/lib/node/ThreadMain-5AYGCXXP.cjs.map +0 -7
- package/dist/lib/node/chunk-2CB5AVBL.cjs.map +0 -7
- package/dist/lib/node/chunk-IC2NICNC.cjs.map +0 -7
- package/dist/lib/node/chunk-VW2P26MZ.cjs.map +0 -7
- package/dist/lib/node/meta.cjs.map +0 -7
- package/dist/lib/node-esm/ThreadArticle-F37HYTOU.mjs +0 -19
- package/dist/lib/node-esm/ThreadArticle-F37HYTOU.mjs.map +0 -7
- package/dist/lib/node-esm/ThreadMain-OL6ZHNZY.mjs +0 -27
- package/dist/lib/node-esm/ThreadMain-OL6ZHNZY.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-7QRGG25F.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-AQ74G3GY.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-RMYATBXM.mjs.map +0 -7
- package/dist/lib/node-esm/meta.mjs +0 -12
- package/dist/lib/node-esm/meta.mjs.map +0 -7
- package/dist/types/src/components/ThreadArticle.d.ts +0 -5
- package/dist/types/src/components/ThreadArticle.d.ts.map +0 -1
- package/dist/types/src/components/ThreadMain.d.ts +0 -7
- package/dist/types/src/components/ThreadMain.d.ts.map +0 -1
- package/src/components/ThreadArticle.tsx +0 -18
- package/src/components/ThreadMain.tsx +0 -27
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
Capabilities,
|
|
7
|
+
contributes,
|
|
8
|
+
createIntent,
|
|
9
|
+
createResolver,
|
|
10
|
+
LayoutAction,
|
|
11
|
+
type PluginsContext,
|
|
12
|
+
} from '@dxos/app-framework';
|
|
13
|
+
import { Ref } from '@dxos/echo-schema';
|
|
14
|
+
import { log } from '@dxos/log';
|
|
15
|
+
import { ObservabilityAction } from '@dxos/plugin-observability/types';
|
|
16
|
+
import { ChannelType, ThreadType } from '@dxos/plugin-space/types';
|
|
17
|
+
import { create, fullyQualifiedId, getSpace, makeRef } from '@dxos/react-client/echo';
|
|
18
|
+
|
|
19
|
+
import { ThreadCapabilities } from './capabilities';
|
|
20
|
+
import { THREAD_PLUGIN } from '../meta';
|
|
21
|
+
import { ThreadAction } from '../types';
|
|
22
|
+
|
|
23
|
+
export default (context: PluginsContext) =>
|
|
24
|
+
contributes(Capabilities.IntentResolver, [
|
|
25
|
+
createResolver({
|
|
26
|
+
intent: ThreadAction.Create,
|
|
27
|
+
resolve: ({ name, cursor, subject }) => {
|
|
28
|
+
if (cursor && subject) {
|
|
29
|
+
// Seed the threads array if it does not exist.
|
|
30
|
+
if (subject?.threads === undefined) {
|
|
31
|
+
try {
|
|
32
|
+
// Static schema will throw an error if subject does not support threads array property.
|
|
33
|
+
subject.threads = [];
|
|
34
|
+
} catch (err) {
|
|
35
|
+
log.error('Subject does not support threads array', { typename: subject?.typename });
|
|
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];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
data: { object: thread },
|
|
52
|
+
intents: [
|
|
53
|
+
createIntent(ThreadAction.Select, { current: fullyQualifiedId(thread) }),
|
|
54
|
+
createIntent(LayoutAction.UpdateComplementary, { part: 'complementary', subject: 'comments' }),
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
} else {
|
|
58
|
+
// TODO(wittjosiah): Create separate intent for channel creation.
|
|
59
|
+
return {
|
|
60
|
+
data: { object: create(ChannelType, { threads: [makeRef(create(ThreadType, { messages: [] }))] }) },
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
}),
|
|
65
|
+
createResolver({
|
|
66
|
+
intent: ThreadAction.Select,
|
|
67
|
+
resolve: ({ current, skipOpen }) => {
|
|
68
|
+
const { state } = context.requestCapability(ThreadCapabilities.MutableState);
|
|
69
|
+
state.current = current;
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
intents: !skipOpen
|
|
73
|
+
? [createIntent(LayoutAction.UpdateComplementary, { part: 'complementary', subject: 'comments' })]
|
|
74
|
+
: undefined,
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
}),
|
|
78
|
+
createResolver({
|
|
79
|
+
intent: ThreadAction.ToggleResolved,
|
|
80
|
+
resolve: ({ thread }) => {
|
|
81
|
+
if (thread.status === 'active' || thread.status === undefined) {
|
|
82
|
+
thread.status = 'resolved';
|
|
83
|
+
} else if (thread.status === 'resolved') {
|
|
84
|
+
thread.status = 'active';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const space = getSpace(thread);
|
|
88
|
+
const spaceId = space?.id;
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
intents: [
|
|
92
|
+
createIntent(ObservabilityAction.SendEvent, {
|
|
93
|
+
name: 'threads.toggle-resolved',
|
|
94
|
+
properties: { threadId: thread.id, spaceId },
|
|
95
|
+
}),
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
}),
|
|
100
|
+
createResolver({
|
|
101
|
+
intent: ThreadAction.Delete,
|
|
102
|
+
resolve: ({ subject, thread }, undo) => {
|
|
103
|
+
const { state } = context.requestCapability(ThreadCapabilities.MutableState);
|
|
104
|
+
const subjectId = fullyQualifiedId(subject);
|
|
105
|
+
const draft = state.drafts[subjectId];
|
|
106
|
+
if (draft) {
|
|
107
|
+
// Check if we're deleting a draft; if so, remove it.
|
|
108
|
+
const index = draft.findIndex((t) => t.id === thread.id);
|
|
109
|
+
if (index !== -1) {
|
|
110
|
+
draft.splice(index, 1);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const space = getSpace(thread);
|
|
116
|
+
if (!space || !subject.threads) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!undo) {
|
|
121
|
+
const index = subject.threads.findIndex((t: any) => t?.id === thread.id);
|
|
122
|
+
const cursor = subject.threads[index]?.anchor;
|
|
123
|
+
if (index !== -1) {
|
|
124
|
+
subject.threads?.splice(index, 1);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
space.db.remove(thread);
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
undoable: {
|
|
131
|
+
message: ['thread deleted label', { ns: THREAD_PLUGIN }],
|
|
132
|
+
data: { cursor },
|
|
133
|
+
},
|
|
134
|
+
intents: [
|
|
135
|
+
createIntent(ObservabilityAction.SendEvent, {
|
|
136
|
+
name: 'threads.delete',
|
|
137
|
+
properties: { threadId: thread.id, spaceId: space.id },
|
|
138
|
+
}),
|
|
139
|
+
],
|
|
140
|
+
};
|
|
141
|
+
} else {
|
|
142
|
+
// TODO(wittjosiah): SDK should do this automatically.
|
|
143
|
+
const savedThread = space.db.add(thread);
|
|
144
|
+
subject.threads.push(savedThread);
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
intents: [
|
|
148
|
+
createIntent(ObservabilityAction.SendEvent, {
|
|
149
|
+
name: 'threads.undo-delete',
|
|
150
|
+
properties: { threadId: thread.id, spaceId: space.id },
|
|
151
|
+
}),
|
|
152
|
+
],
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
}),
|
|
157
|
+
createResolver({
|
|
158
|
+
intent: ThreadAction.OnMessageAdd,
|
|
159
|
+
resolve: ({ thread, subject }) => {
|
|
160
|
+
const { state } = context.requestCapability(ThreadCapabilities.MutableState);
|
|
161
|
+
const subjectId = fullyQualifiedId(subject);
|
|
162
|
+
const space = getSpace(subject);
|
|
163
|
+
const intents = [];
|
|
164
|
+
const analyticsProperties = { threadId: thread.id, spaceId: space?.id };
|
|
165
|
+
|
|
166
|
+
if (state.drafts[subjectId]?.find((t) => t === thread)) {
|
|
167
|
+
// Move draft to document.
|
|
168
|
+
thread.status = 'active';
|
|
169
|
+
subject.threads ? subject.threads.push(makeRef(thread)) : (subject.threads = [makeRef(thread)]);
|
|
170
|
+
state.drafts[subjectId] = state.drafts[subjectId]?.filter(({ id }) => id !== thread.id);
|
|
171
|
+
intents.push(
|
|
172
|
+
createIntent(ObservabilityAction.SendEvent, {
|
|
173
|
+
name: 'threads.thread-created',
|
|
174
|
+
properties: analyticsProperties,
|
|
175
|
+
}),
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
intents.push(
|
|
180
|
+
createIntent(ObservabilityAction.SendEvent, {
|
|
181
|
+
name: 'threads.message-added',
|
|
182
|
+
properties: { ...analyticsProperties, threadLength: thread.messages.length },
|
|
183
|
+
}),
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
return { intents };
|
|
187
|
+
},
|
|
188
|
+
}),
|
|
189
|
+
createResolver({
|
|
190
|
+
intent: ThreadAction.DeleteMessage,
|
|
191
|
+
resolve: ({ subject, thread, messageId, message, messageIndex }, undo) => {
|
|
192
|
+
const space = getSpace(subject);
|
|
193
|
+
|
|
194
|
+
if (!undo) {
|
|
195
|
+
const messageIndex = thread.messages.findIndex(Ref.hasObjectId(messageId));
|
|
196
|
+
const message = thread.messages[messageIndex]?.target;
|
|
197
|
+
if (!message) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (messageIndex === 0 && thread.messages.length === 1) {
|
|
202
|
+
// If the message is the only message in the thread, delete the thread.
|
|
203
|
+
return {
|
|
204
|
+
intents: [createIntent(ThreadAction.Delete, { subject, thread })],
|
|
205
|
+
};
|
|
206
|
+
} else {
|
|
207
|
+
thread.messages.splice(messageIndex, 1);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
undoable: {
|
|
212
|
+
message: ['message deleted label', { ns: THREAD_PLUGIN }],
|
|
213
|
+
data: { message, messageIndex },
|
|
214
|
+
},
|
|
215
|
+
intents: [
|
|
216
|
+
createIntent(ObservabilityAction.SendEvent, {
|
|
217
|
+
name: 'threads.message.delete',
|
|
218
|
+
properties: { threadId: thread.id, spaceId: space?.id },
|
|
219
|
+
}),
|
|
220
|
+
],
|
|
221
|
+
};
|
|
222
|
+
} else {
|
|
223
|
+
if (!messageIndex || !message) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
thread.messages.splice(messageIndex, 0, makeRef(message));
|
|
228
|
+
return {
|
|
229
|
+
intents: [
|
|
230
|
+
createIntent(ObservabilityAction.SendEvent, {
|
|
231
|
+
name: 'threads.message.undo-delete',
|
|
232
|
+
properties: { threadId: thread.id, spaceId: space?.id },
|
|
233
|
+
}),
|
|
234
|
+
],
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
}),
|
|
239
|
+
]);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Capabilities, contributes, type PluginsContext } from '@dxos/app-framework';
|
|
6
|
+
import { MarkdownCapabilities } from '@dxos/plugin-markdown';
|
|
7
|
+
|
|
8
|
+
import { ThreadCapabilities } from './capabilities';
|
|
9
|
+
import { threads } from '../extensions';
|
|
10
|
+
|
|
11
|
+
export default (context: PluginsContext) =>
|
|
12
|
+
contributes(MarkdownCapabilities.Extensions, [
|
|
13
|
+
({ document: doc }) => {
|
|
14
|
+
const { dispatchPromise: dispatch } = context.requestCapability(Capabilities.IntentDispatcher);
|
|
15
|
+
const { state } = context.requestCapability(ThreadCapabilities.MutableState);
|
|
16
|
+
return threads(state, doc, dispatch);
|
|
17
|
+
},
|
|
18
|
+
]);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
import { Capabilities, contributes, createSurface, useLayout } from '@dxos/app-framework';
|
|
8
|
+
import { type Ref } from '@dxos/echo-schema';
|
|
9
|
+
import { SettingsStore } from '@dxos/local-storage';
|
|
10
|
+
import { ChannelType, type ThreadType } from '@dxos/plugin-space/types';
|
|
11
|
+
import { getSpace } from '@dxos/react-client/echo';
|
|
12
|
+
|
|
13
|
+
import { ThreadContainer, ThreadComplementary, ThreadSettings } from '../components';
|
|
14
|
+
import { THREAD_PLUGIN } from '../meta';
|
|
15
|
+
import { type ThreadSettingsProps } from '../types';
|
|
16
|
+
|
|
17
|
+
export default () =>
|
|
18
|
+
contributes(Capabilities.ReactSurface, [
|
|
19
|
+
createSurface({
|
|
20
|
+
id: `${THREAD_PLUGIN}/channel`,
|
|
21
|
+
role: 'article',
|
|
22
|
+
filter: (data): data is { subject: ChannelType } =>
|
|
23
|
+
data.subject instanceof ChannelType && !!data.subject.threads[0],
|
|
24
|
+
component: ({ data, role }) => {
|
|
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
|
+
const currentPosition = layout.active.findIndex((id) => id === channel.id);
|
|
34
|
+
if (currentPosition > 0) {
|
|
35
|
+
const objectToTheLeft = layout.active[currentPosition - 1];
|
|
36
|
+
const context = getSpace(channel)?.db.getObjectById(objectToTheLeft);
|
|
37
|
+
return <ThreadContainer role={role} thread={thread} context={context} />;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return <ThreadContainer role={role} thread={thread} />;
|
|
41
|
+
},
|
|
42
|
+
}),
|
|
43
|
+
createSurface({
|
|
44
|
+
id: `${THREAD_PLUGIN}/thread`,
|
|
45
|
+
role: 'complementary--comments',
|
|
46
|
+
filter: (data): data is { subject: { threads: Ref<ThreadType>[] } } =>
|
|
47
|
+
!!data.subject &&
|
|
48
|
+
typeof data.subject === 'object' &&
|
|
49
|
+
'threads' in data.subject &&
|
|
50
|
+
Array.isArray(data.subject.threads) &&
|
|
51
|
+
!(data.subject instanceof ChannelType),
|
|
52
|
+
component: ({ data }) => <ThreadComplementary subject={data.subject} />,
|
|
53
|
+
}),
|
|
54
|
+
createSurface({
|
|
55
|
+
id: `${THREAD_PLUGIN}/settings`,
|
|
56
|
+
role: 'article',
|
|
57
|
+
filter: (data): data is { subject: SettingsStore<ThreadSettingsProps> } =>
|
|
58
|
+
data.subject instanceof SettingsStore && data.subject.prefix === THREAD_PLUGIN,
|
|
59
|
+
component: ({ data: { subject } }) => <ThreadSettings settings={subject.value} />,
|
|
60
|
+
}),
|
|
61
|
+
]);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Capabilities, contributes } from '@dxos/app-framework';
|
|
6
|
+
import { create } from '@dxos/live-object';
|
|
7
|
+
|
|
8
|
+
import { THREAD_PLUGIN } from '../meta';
|
|
9
|
+
import { type ThreadSettingsProps, ThreadSettingsSchema } from '../types';
|
|
10
|
+
|
|
11
|
+
export default () => {
|
|
12
|
+
const settings = create<ThreadSettingsProps>({});
|
|
13
|
+
return contributes(Capabilities.Settings, { schema: ThreadSettingsSchema, prefix: THREAD_PLUGIN, value: settings });
|
|
14
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { contributes } from '@dxos/app-framework';
|
|
6
|
+
import { create } from '@dxos/live-object';
|
|
7
|
+
|
|
8
|
+
import { ThreadCapabilities } from './capabilities';
|
|
9
|
+
import { type ThreadState, type ViewStore } from '../types';
|
|
10
|
+
|
|
11
|
+
const initialViewState = { showResolvedThreads: false };
|
|
12
|
+
|
|
13
|
+
export default () => {
|
|
14
|
+
const state = create<ThreadState>({ drafts: {} });
|
|
15
|
+
const viewStore = create<ViewStore>({});
|
|
16
|
+
|
|
17
|
+
const getViewState = (subjectId: string) => {
|
|
18
|
+
if (!viewStore[subjectId]) {
|
|
19
|
+
viewStore[subjectId] = { ...initialViewState };
|
|
20
|
+
}
|
|
21
|
+
return viewStore[subjectId];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
return contributes(ThreadCapabilities.State, { state, getViewState });
|
|
25
|
+
};
|
|
@@ -7,14 +7,14 @@ import '@dxos-theme';
|
|
|
7
7
|
import { type Meta } from '@storybook/react';
|
|
8
8
|
import React, { useEffect, useState } from 'react';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { Capabilities, contributes, createSurface } from '@dxos/app-framework';
|
|
11
|
+
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
11
12
|
import { MessageType, ThreadType } from '@dxos/plugin-space/types';
|
|
12
13
|
import { faker } from '@dxos/random';
|
|
13
14
|
import { useClient } from '@dxos/react-client';
|
|
14
15
|
import { type Space } from '@dxos/react-client/echo';
|
|
15
16
|
import { useIdentity } from '@dxos/react-client/halo';
|
|
16
|
-
import {
|
|
17
|
-
import { Mosaic } from '@dxos/react-ui-mosaic';
|
|
17
|
+
import { withClientProvider } from '@dxos/react-client/testing';
|
|
18
18
|
import { Thread } from '@dxos/react-ui-thread';
|
|
19
19
|
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
20
20
|
|
|
@@ -46,24 +46,7 @@ const Story = () => {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
return (
|
|
49
|
-
<
|
|
50
|
-
value={{
|
|
51
|
-
surfaces: {
|
|
52
|
-
ObjectMessage: createSurface({
|
|
53
|
-
id: 'test',
|
|
54
|
-
role: 'card',
|
|
55
|
-
component: ({ role }) => <span>{JSON.stringify({ role })}</span>,
|
|
56
|
-
}),
|
|
57
|
-
},
|
|
58
|
-
}}
|
|
59
|
-
>
|
|
60
|
-
<Mosaic.Root debug>
|
|
61
|
-
<main className='max-is-prose mli-auto bs-dvh overflow-hidden'>
|
|
62
|
-
{space && <ChatContainer thread={thread} />}
|
|
63
|
-
</main>
|
|
64
|
-
<Mosaic.DragOverlay />
|
|
65
|
-
</Mosaic.Root>
|
|
66
|
-
</SurfaceProvider>
|
|
49
|
+
<main className='max-is-prose mli-auto bs-dvh overflow-hidden'>{space && <ChatContainer thread={thread} />}</main>
|
|
67
50
|
);
|
|
68
51
|
};
|
|
69
52
|
|
|
@@ -72,9 +55,24 @@ export const Default = {};
|
|
|
72
55
|
const meta: Meta = {
|
|
73
56
|
title: 'plugins/plugin-thread/Chat',
|
|
74
57
|
component: Thread,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
58
|
+
render: () => <Story />,
|
|
59
|
+
decorators: [
|
|
60
|
+
withPluginManager({
|
|
61
|
+
capabilities: [
|
|
62
|
+
contributes(
|
|
63
|
+
Capabilities.ReactSurface,
|
|
64
|
+
createSurface({
|
|
65
|
+
id: 'test',
|
|
66
|
+
role: 'card',
|
|
67
|
+
component: ({ role }) => <span>{JSON.stringify({ role })}</span>,
|
|
68
|
+
}),
|
|
69
|
+
),
|
|
70
|
+
],
|
|
71
|
+
}),
|
|
72
|
+
withTheme,
|
|
73
|
+
withLayout({ fullscreen: true, tooltips: true }),
|
|
74
|
+
withClientProvider({ createSpace: true, types: [ThreadType, MessageType] }),
|
|
75
|
+
],
|
|
78
76
|
parameters: { translations },
|
|
79
77
|
};
|
|
80
78
|
|
|
@@ -7,7 +7,7 @@ import React, { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
|
7
7
|
import { Ref } from '@dxos/echo-schema';
|
|
8
8
|
import { create, makeRef, RefArray } from '@dxos/live-object';
|
|
9
9
|
import { MessageType } from '@dxos/plugin-space/types';
|
|
10
|
-
import { fullyQualifiedId, getSpace, useMembers
|
|
10
|
+
import { fullyQualifiedId, getSpace, useMembers } 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';
|
|
@@ -82,7 +82,7 @@ export const ChatContainer = ({ thread, context, current, autoFocusTextbox }: Th
|
|
|
82
82
|
sender: { identityKey: identity.identityKey.toHex() },
|
|
83
83
|
timestamp: new Date().toISOString(),
|
|
84
84
|
text: messageRef.current,
|
|
85
|
-
context: makeRef(context
|
|
85
|
+
context: context ? makeRef(context) : undefined,
|
|
86
86
|
}),
|
|
87
87
|
),
|
|
88
88
|
);
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
import { CheckCircle, X } from '@phosphor-icons/react';
|
|
6
6
|
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
import { MessageType } from '@dxos/plugin-space/types';
|
|
8
|
+
import { RefArray } from '@dxos/live-object';
|
|
10
9
|
import { fullyQualifiedId, getSpace, useMembers } from '@dxos/react-client/echo';
|
|
11
10
|
import { useIdentity } from '@dxos/react-client/halo';
|
|
12
11
|
import { Button, Tag, Tooltip, useThemeContext, useTranslation } from '@dxos/react-ui';
|
|
@@ -19,7 +18,7 @@ import {
|
|
|
19
18
|
mx,
|
|
20
19
|
} from '@dxos/react-ui-theme';
|
|
21
20
|
import { MessageTextbox, type MessageTextboxProps, Thread, ThreadFooter, ThreadHeading } from '@dxos/react-ui-thread';
|
|
22
|
-
import {
|
|
21
|
+
import { isNonNullable } from '@dxos/util';
|
|
23
22
|
|
|
24
23
|
import { MessageContainer } from './MessageContainer';
|
|
25
24
|
import { command } from './command-extension';
|
|
@@ -94,13 +93,12 @@ const DeleteThreadButton = ({ onDelete }: { onDelete: () => void }) => {
|
|
|
94
93
|
export const CommentContainer = ({
|
|
95
94
|
thread,
|
|
96
95
|
detached,
|
|
97
|
-
context,
|
|
98
96
|
current,
|
|
99
97
|
onAttend,
|
|
100
|
-
onThreadDelete,
|
|
101
|
-
onMessageDelete,
|
|
102
|
-
onResolve,
|
|
103
98
|
onComment,
|
|
99
|
+
onResolve,
|
|
100
|
+
onMessageDelete,
|
|
101
|
+
onThreadDelete,
|
|
104
102
|
}: ThreadContainerProps) => {
|
|
105
103
|
const identity = useIdentity()!;
|
|
106
104
|
const space = getSpace(thread);
|
|
@@ -129,33 +127,26 @@ export const CommentContainer = ({
|
|
|
129
127
|
const scrollToEnd = (behavior: ScrollBehavior) =>
|
|
130
128
|
setTimeout(() => threadScrollRef.current?.scrollIntoView({ behavior, block: 'end' }), 10);
|
|
131
129
|
|
|
132
|
-
const
|
|
130
|
+
const handleAttend = useCallback(() => onAttend?.(thread), [onAttend, thread]);
|
|
131
|
+
const handleResolve = useCallback(() => onResolve?.(thread), [onResolve, thread]);
|
|
132
|
+
const handleMessageDelete = useCallback((id: string) => onMessageDelete?.(thread, id), [onMessageDelete, thread]);
|
|
133
|
+
const handleThreadDelete = useCallback(() => onThreadDelete?.(thread), [onThreadDelete, thread]);
|
|
134
|
+
|
|
135
|
+
const handleComment: MessageTextboxProps['onSend'] = useCallback(() => {
|
|
133
136
|
if (!messageRef.current) {
|
|
134
137
|
return false;
|
|
135
138
|
}
|
|
136
139
|
|
|
137
|
-
thread.
|
|
138
|
-
makeRef(
|
|
139
|
-
create(MessageType, {
|
|
140
|
-
sender: { identityKey: identity.identityKey.toHex() },
|
|
141
|
-
timestamp: new Date().toISOString(),
|
|
142
|
-
text: messageRef.current,
|
|
143
|
-
context: context ? makeRef(context) : undefined,
|
|
144
|
-
}),
|
|
145
|
-
),
|
|
146
|
-
);
|
|
147
|
-
onComment?.(thread);
|
|
148
|
-
|
|
140
|
+
onComment?.(thread, messageRef.current);
|
|
149
141
|
messageRef.current = '';
|
|
150
142
|
scrollToEnd('instant');
|
|
151
143
|
rerenderEditor();
|
|
152
144
|
|
|
153
|
-
// TODO(burdon): Scroll to bottom.
|
|
154
145
|
return true;
|
|
155
146
|
}, [thread, identity]);
|
|
156
147
|
|
|
157
148
|
return (
|
|
158
|
-
<Thread onClickCapture={
|
|
149
|
+
<Thread onClickCapture={handleAttend} onFocusCapture={handleAttend} current={current} id={fullyQualifiedId(thread)}>
|
|
159
150
|
<div
|
|
160
151
|
role='none'
|
|
161
152
|
className={mx(
|
|
@@ -182,19 +173,14 @@ export const CommentContainer = ({
|
|
|
182
173
|
<div className='flex flex-row items-center pli-1'>
|
|
183
174
|
{thread.status === 'staged' && <Tag palette='neutral'>{t('draft button')}</Tag>}
|
|
184
175
|
{onResolve && !(thread?.status === 'staged') && (
|
|
185
|
-
<ToggleResolvedButton isResolved={thread?.status === 'resolved'} onResolve={
|
|
176
|
+
<ToggleResolvedButton isResolved={thread?.status === 'resolved'} onResolve={handleResolve} />
|
|
186
177
|
)}
|
|
187
|
-
{onThreadDelete && <DeleteThreadButton onDelete={
|
|
178
|
+
{onThreadDelete && <DeleteThreadButton onDelete={handleThreadDelete} />}
|
|
188
179
|
</div>
|
|
189
180
|
</div>
|
|
190
181
|
{/** TODO(dmaretskyi): How's `thread.messages` undefined? */}
|
|
191
|
-
{RefArray.allResolvedTargets(thread.messages?.filter(
|
|
192
|
-
<MessageContainer
|
|
193
|
-
key={message.id}
|
|
194
|
-
message={message}
|
|
195
|
-
members={members}
|
|
196
|
-
onDelete={(id: string) => onMessageDelete?.(id)}
|
|
197
|
-
/>
|
|
182
|
+
{RefArray.allResolvedTargets(thread.messages?.filter(isNonNullable) ?? []).map((message) => (
|
|
183
|
+
<MessageContainer key={message.id} message={message} members={members} onDelete={handleMessageDelete} />
|
|
198
184
|
))}
|
|
199
185
|
{/*
|
|
200
186
|
TODO(wittjosiah): Can't autofocus this generally.
|
|
@@ -202,7 +188,7 @@ export const CommentContainer = ({
|
|
|
202
188
|
Also, it steals focus from documents when first rendered.
|
|
203
189
|
Need to find a way to autofocus in one scenario only: when a new thread is created.
|
|
204
190
|
*/}
|
|
205
|
-
<MessageTextbox extensions={extensions} onSend={
|
|
191
|
+
<MessageTextbox extensions={extensions} onSend={handleComment} {...textboxMetadata} />
|
|
206
192
|
<ThreadFooter activity={activity}>{t('activity message')}</ThreadFooter>
|
|
207
193
|
{/* NOTE(thure): This can’t also be the `overflow-anchor` because `ScrollArea` injects an interceding node that contains this necessary ref’d element. */}
|
|
208
194
|
<div role='none' className='bs-px -mbs-px' ref={threadScrollRef} />
|
|
@@ -7,6 +7,8 @@ import '@dxos-theme';
|
|
|
7
7
|
import { type Meta } from '@storybook/react';
|
|
8
8
|
import React, { useEffect, useState } from 'react';
|
|
9
9
|
|
|
10
|
+
import { IntentPlugin } from '@dxos/app-framework';
|
|
11
|
+
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
10
12
|
import { MessageType, ThreadType } from '@dxos/plugin-space/types';
|
|
11
13
|
import { faker } from '@dxos/random';
|
|
12
14
|
import { Filter, fullyQualifiedId, useQuery, useSpace } from '@dxos/react-client/echo';
|
|
@@ -44,7 +46,7 @@ const Story = ({ spaceKey }: ClientRepeatedComponentProps) => {
|
|
|
44
46
|
|
|
45
47
|
return (
|
|
46
48
|
<div className='flex justify-center overflow-y-auto bg-white dark:bg-black'>
|
|
47
|
-
<div className='flex flex-col w-[
|
|
49
|
+
<div className='flex flex-col w-[30rem]'>
|
|
48
50
|
<CommentsContainer threads={threads} detached={detached} onThreadDelete={console.log} />
|
|
49
51
|
</div>
|
|
50
52
|
</div>
|
|
@@ -57,7 +59,11 @@ const meta: Meta = {
|
|
|
57
59
|
title: 'plugins/plugin-thread/Comments',
|
|
58
60
|
// TODO(wittjosiah): Use decorator.
|
|
59
61
|
render: () => <ClientRepeater component={Story} createIdentity createSpace types={[ThreadType, MessageType]} />,
|
|
60
|
-
decorators: [
|
|
62
|
+
decorators: [
|
|
63
|
+
withTheme,
|
|
64
|
+
withLayout({ fullscreen: true, tooltips: true }),
|
|
65
|
+
withPluginManager({ plugins: [IntentPlugin()] }),
|
|
66
|
+
],
|
|
61
67
|
parameters: { translations },
|
|
62
68
|
};
|
|
63
69
|
|
|
@@ -14,10 +14,7 @@ import { CommentContainer } from './CommentContainer';
|
|
|
14
14
|
import { type ThreadContainerProps } from './types';
|
|
15
15
|
import { THREAD_PLUGIN } from '../meta';
|
|
16
16
|
|
|
17
|
-
export type ThreadsContainerProps = Omit<
|
|
18
|
-
ThreadContainerProps,
|
|
19
|
-
'thread' | 'detached' | 'onAttend' | 'onThreadDelete' | 'onMessageDelete' | 'current' | 'autoFocus'
|
|
20
|
-
> & {
|
|
17
|
+
export type ThreadsContainerProps = Omit<ThreadContainerProps, 'thread' | 'detached' | 'current' | 'autoFocus'> & {
|
|
21
18
|
threads: ThreadType[];
|
|
22
19
|
/**
|
|
23
20
|
* Threads that are no longer anchored to a position in the object.
|
|
@@ -25,11 +22,6 @@ export type ThreadsContainerProps = Omit<
|
|
|
25
22
|
detached?: string[];
|
|
26
23
|
currentId?: string;
|
|
27
24
|
showResolvedThreads?: boolean;
|
|
28
|
-
onThreadAttend?: (thread: ThreadType) => void;
|
|
29
|
-
onThreadDelete?: (thread: ThreadType) => void;
|
|
30
|
-
onMessageDelete?: (thread: ThreadType, messageId: string) => void;
|
|
31
|
-
onThreadToggleResolved?: (thread: ThreadType) => void;
|
|
32
|
-
onComment?: (thread: ThreadType) => void;
|
|
33
25
|
};
|
|
34
26
|
|
|
35
27
|
/**
|
|
@@ -40,10 +32,6 @@ export const CommentsContainer = ({
|
|
|
40
32
|
detached = [],
|
|
41
33
|
currentId,
|
|
42
34
|
showResolvedThreads,
|
|
43
|
-
onThreadAttend,
|
|
44
|
-
onThreadDelete,
|
|
45
|
-
onMessageDelete,
|
|
46
|
-
onThreadToggleResolved,
|
|
47
35
|
...props
|
|
48
36
|
}: ThreadsContainerProps) => {
|
|
49
37
|
const { t } = useTranslation(THREAD_PLUGIN);
|
|
@@ -66,10 +54,6 @@ export const CommentsContainer = ({
|
|
|
66
54
|
thread={thread}
|
|
67
55
|
current={currentId === threadId}
|
|
68
56
|
detached={detached.includes(threadId)}
|
|
69
|
-
{...(onThreadAttend && { onAttend: () => onThreadAttend(thread) })}
|
|
70
|
-
{...(onThreadDelete && { onThreadDelete: () => onThreadDelete(thread) })}
|
|
71
|
-
{...(onMessageDelete && { onMessageDelete: (messageId: string) => onMessageDelete(thread, messageId) })}
|
|
72
|
-
{...(onThreadToggleResolved && { onResolve: () => onThreadToggleResolved(thread) })}
|
|
73
57
|
{...props}
|
|
74
58
|
/>
|
|
75
59
|
);
|