@dxos/plugin-thread 0.7.4-staging.f7e8224 → 0.7.5-labs.071a3e2

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.
Files changed (200) hide show
  1. package/dist/lib/browser/ThreadContainer-T4WIBHY6.mjs +19 -0
  2. package/dist/lib/browser/ThreadContainer-T4WIBHY6.mjs.map +7 -0
  3. package/dist/lib/browser/app-graph-builder-IANFWFYN.mjs +121 -0
  4. package/dist/lib/browser/app-graph-builder-IANFWFYN.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-52HWDLBR.mjs → chunk-5EQVG4L3.mjs} +33 -121
  6. package/dist/lib/browser/chunk-5EQVG4L3.mjs.map +7 -0
  7. package/dist/lib/browser/{chunk-ENERBDYI.mjs → chunk-636QDHE3.mjs} +3 -3
  8. package/dist/lib/browser/chunk-636QDHE3.mjs.map +7 -0
  9. package/dist/lib/browser/chunk-BNEWNQBO.mjs +71 -0
  10. package/dist/lib/browser/chunk-BNEWNQBO.mjs.map +7 -0
  11. package/dist/lib/browser/chunk-L4QHQNDC.mjs +18 -0
  12. package/dist/lib/browser/chunk-L4QHQNDC.mjs.map +7 -0
  13. package/dist/lib/browser/chunk-NAO3LZMZ.mjs +16 -0
  14. package/dist/lib/browser/chunk-NAO3LZMZ.mjs.map +7 -0
  15. package/dist/lib/browser/chunk-NO5AZLUZ.mjs +81 -0
  16. package/dist/lib/browser/chunk-NO5AZLUZ.mjs.map +7 -0
  17. package/dist/lib/browser/index.mjs +147 -1094
  18. package/dist/lib/browser/index.mjs.map +4 -4
  19. package/dist/lib/browser/intent-resolver-QFP6L3AF.mjs +287 -0
  20. package/dist/lib/browser/intent-resolver-QFP6L3AF.mjs.map +7 -0
  21. package/dist/lib/browser/markdown-2NBXKXCY.mjs +112 -0
  22. package/dist/lib/browser/markdown-2NBXKXCY.mjs.map +7 -0
  23. package/dist/lib/browser/meta.json +1 -1
  24. package/dist/lib/browser/react-surface-LDPZN456.mjs +424 -0
  25. package/dist/lib/browser/react-surface-LDPZN456.mjs.map +7 -0
  26. package/dist/lib/browser/settings-TKOPRXSU.mjs +22 -0
  27. package/dist/lib/browser/settings-TKOPRXSU.mjs.map +7 -0
  28. package/dist/lib/browser/state-GNFUURIC.mjs +33 -0
  29. package/dist/lib/browser/state-GNFUURIC.mjs.map +7 -0
  30. package/dist/lib/browser/types.mjs +6 -4
  31. package/dist/lib/node/{ThreadArticle-I7ADXDW3.cjs → ThreadContainer-4XACAVGV.cjs} +14 -13
  32. package/dist/lib/node/ThreadContainer-4XACAVGV.cjs.map +7 -0
  33. package/dist/lib/node/app-graph-builder-LFEDPJLK.cjs +135 -0
  34. package/dist/lib/node/app-graph-builder-LFEDPJLK.cjs.map +7 -0
  35. package/dist/lib/node/{ThreadMain-MRNJC3TI.cjs → chunk-346YIZVL.cjs} +26 -23
  36. package/dist/lib/node/chunk-346YIZVL.cjs.map +7 -0
  37. package/dist/lib/node/chunk-AUVKOX5Q.cjs +101 -0
  38. package/dist/lib/node/chunk-AUVKOX5Q.cjs.map +7 -0
  39. package/dist/lib/node/chunk-AWSTZ2KN.cjs +93 -0
  40. package/dist/lib/node/chunk-AWSTZ2KN.cjs.map +7 -0
  41. package/dist/lib/node/{chunk-IC2NICNC.cjs → chunk-F735VMTN.cjs} +7 -7
  42. package/dist/lib/node/chunk-F735VMTN.cjs.map +7 -0
  43. package/dist/lib/node/{meta.cjs → chunk-FPWNZ6TB.cjs} +13 -10
  44. package/dist/lib/node/chunk-FPWNZ6TB.cjs.map +7 -0
  45. package/dist/lib/node/{chunk-YCDM2SZM.cjs → chunk-VAZ3BCTU.cjs} +77 -168
  46. package/dist/lib/node/chunk-VAZ3BCTU.cjs.map +7 -0
  47. package/dist/lib/node/index.cjs +142 -1083
  48. package/dist/lib/node/index.cjs.map +4 -4
  49. package/dist/lib/node/intent-resolver-ZSOQILPJ.cjs +299 -0
  50. package/dist/lib/node/intent-resolver-ZSOQILPJ.cjs.map +7 -0
  51. package/dist/lib/node/markdown-FWRKMSKV.cjs +122 -0
  52. package/dist/lib/node/markdown-FWRKMSKV.cjs.map +7 -0
  53. package/dist/lib/node/meta.json +1 -1
  54. package/dist/lib/node/react-surface-MCQUT7BC.cjs +426 -0
  55. package/dist/lib/node/react-surface-MCQUT7BC.cjs.map +7 -0
  56. package/dist/lib/node/settings-TH4YSUVU.cjs +36 -0
  57. package/dist/lib/node/settings-TH4YSUVU.cjs.map +7 -0
  58. package/dist/lib/node/state-TQWEZ6B3.cjs +49 -0
  59. package/dist/lib/node/state-TQWEZ6B3.cjs.map +7 -0
  60. package/dist/lib/node/types.cjs +6 -4
  61. package/dist/lib/node/types.cjs.map +2 -2
  62. package/dist/lib/node-esm/ThreadContainer-FGFB25TQ.mjs +20 -0
  63. package/dist/lib/node-esm/ThreadContainer-FGFB25TQ.mjs.map +7 -0
  64. package/dist/lib/node-esm/app-graph-builder-IXHFRMCY.mjs +122 -0
  65. package/dist/lib/node-esm/app-graph-builder-IXHFRMCY.mjs.map +7 -0
  66. package/dist/lib/node-esm/chunk-3INUK3A6.mjs +20 -0
  67. package/dist/lib/node-esm/chunk-3INUK3A6.mjs.map +7 -0
  68. package/dist/lib/node-esm/chunk-B3CF35MY.mjs +82 -0
  69. package/dist/lib/node-esm/chunk-B3CF35MY.mjs.map +7 -0
  70. package/dist/lib/node-esm/{chunk-JG7MXH6O.mjs → chunk-DKCH2H5C.mjs} +33 -121
  71. package/dist/lib/node-esm/chunk-DKCH2H5C.mjs.map +7 -0
  72. package/dist/lib/node-esm/{chunk-7QRGG25F.mjs → chunk-FXUATCLW.mjs} +3 -3
  73. package/dist/lib/node-esm/chunk-FXUATCLW.mjs.map +7 -0
  74. package/dist/lib/node-esm/chunk-HLWJTUWZ.mjs +73 -0
  75. package/dist/lib/node-esm/chunk-HLWJTUWZ.mjs.map +7 -0
  76. package/dist/lib/node-esm/chunk-ZJITX3TO.mjs +17 -0
  77. package/dist/lib/node-esm/chunk-ZJITX3TO.mjs.map +7 -0
  78. package/dist/lib/node-esm/index.mjs +147 -1094
  79. package/dist/lib/node-esm/index.mjs.map +4 -4
  80. package/dist/lib/node-esm/intent-resolver-MHP4C2NZ.mjs +288 -0
  81. package/dist/lib/node-esm/intent-resolver-MHP4C2NZ.mjs.map +7 -0
  82. package/dist/lib/node-esm/markdown-6AQFDAW3.mjs +113 -0
  83. package/dist/lib/node-esm/markdown-6AQFDAW3.mjs.map +7 -0
  84. package/dist/lib/node-esm/meta.json +1 -1
  85. package/dist/lib/node-esm/react-surface-6JMVZUDM.mjs +425 -0
  86. package/dist/lib/node-esm/react-surface-6JMVZUDM.mjs.map +7 -0
  87. package/dist/lib/node-esm/settings-KEDRR7RM.mjs +23 -0
  88. package/dist/lib/node-esm/settings-KEDRR7RM.mjs.map +7 -0
  89. package/dist/lib/node-esm/state-7MLR27YG.mjs +34 -0
  90. package/dist/lib/node-esm/state-7MLR27YG.mjs.map +7 -0
  91. package/dist/lib/node-esm/types.mjs +6 -4
  92. package/dist/types/src/ThreadPlugin.d.ts +1 -3
  93. package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
  94. package/dist/types/src/capabilities/app-graph-builder.d.ts +180 -0
  95. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  96. package/dist/types/src/capabilities/capabilities.d.ts +15 -0
  97. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -0
  98. package/dist/types/src/capabilities/index.d.ts +187 -0
  99. package/dist/types/src/capabilities/index.d.ts.map +1 -0
  100. package/dist/types/src/capabilities/intent-resolver.d.ts +4 -0
  101. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -0
  102. package/dist/types/src/capabilities/markdown.d.ts +4 -0
  103. package/dist/types/src/capabilities/markdown.d.ts.map +1 -0
  104. package/dist/types/src/capabilities/react-surface.d.ts +4 -0
  105. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  106. package/dist/types/src/capabilities/settings.d.ts +4 -0
  107. package/dist/types/src/capabilities/settings.d.ts.map +1 -0
  108. package/dist/types/src/capabilities/state.d.ts +7 -0
  109. package/dist/types/src/capabilities/state.d.ts.map +1 -0
  110. package/dist/types/src/components/Chat.stories.d.ts.map +1 -1
  111. package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
  112. package/dist/types/src/components/CommentContainer.d.ts +1 -1
  113. package/dist/types/src/components/CommentContainer.d.ts.map +1 -1
  114. package/dist/types/src/components/CommentsContainer.d.ts +2 -7
  115. package/dist/types/src/components/CommentsContainer.d.ts.map +1 -1
  116. package/dist/types/src/components/MessageContainer.d.ts.map +1 -1
  117. package/dist/types/src/components/ThreadComplementary.d.ts +1 -6
  118. package/dist/types/src/components/ThreadComplementary.d.ts.map +1 -1
  119. package/dist/types/src/components/ThreadContainer.d.ts +7 -0
  120. package/dist/types/src/components/ThreadContainer.d.ts.map +1 -0
  121. package/dist/types/src/components/command-extension.d.ts.map +1 -1
  122. package/dist/types/src/components/index.d.ts +3 -15
  123. package/dist/types/src/components/index.d.ts.map +1 -1
  124. package/dist/types/src/components/testing.d.ts +50 -66
  125. package/dist/types/src/components/testing.d.ts.map +1 -1
  126. package/dist/types/src/components/types.d.ts +5 -5
  127. package/dist/types/src/components/types.d.ts.map +1 -1
  128. package/dist/types/src/extensions/threads.d.ts +2 -2
  129. package/dist/types/src/extensions/threads.d.ts.map +1 -1
  130. package/dist/types/src/hooks/analytics.d.ts.map +1 -1
  131. package/dist/types/src/index.d.ts +1 -3
  132. package/dist/types/src/index.d.ts.map +1 -1
  133. package/dist/types/src/meta.d.ts +1 -2
  134. package/dist/types/src/meta.d.ts.map +1 -1
  135. package/dist/types/src/translations.d.ts +3 -0
  136. package/dist/types/src/translations.d.ts.map +1 -1
  137. package/dist/types/src/types.d.ts +86 -22
  138. package/dist/types/src/types.d.ts.map +1 -1
  139. package/dist/types/tsconfig.tsbuildinfo +1 -0
  140. package/package.json +30 -38
  141. package/src/ThreadPlugin.tsx +108 -620
  142. package/src/capabilities/app-graph-builder.ts +119 -0
  143. package/src/capabilities/capabilities.ts +19 -0
  144. package/src/capabilities/index.ts +14 -0
  145. package/src/capabilities/intent-resolver.ts +239 -0
  146. package/src/capabilities/markdown.ts +18 -0
  147. package/src/capabilities/react-surface.tsx +62 -0
  148. package/src/capabilities/settings.ts +14 -0
  149. package/src/capabilities/state.ts +25 -0
  150. package/src/components/Chat.stories.tsx +26 -22
  151. package/src/components/ChatContainer.tsx +12 -10
  152. package/src/components/CommentContainer.tsx +21 -32
  153. package/src/components/CommentsContainer.tsx +1 -17
  154. package/src/components/MessageContainer.tsx +7 -5
  155. package/src/components/ThreadComplementary.tsx +91 -68
  156. package/src/components/ThreadContainer.tsx +22 -0
  157. package/src/components/ThreadSettings.tsx +3 -3
  158. package/src/components/command-extension.ts +2 -5
  159. package/src/components/index.ts +1 -2
  160. package/src/components/testing.ts +26 -22
  161. package/src/components/types.ts +5 -5
  162. package/src/extensions/threads.ts +16 -25
  163. package/src/hooks/analytics.ts +6 -10
  164. package/src/index.ts +1 -5
  165. package/src/meta.ts +1 -1
  166. package/src/translations.ts +1 -0
  167. package/src/types.ts +70 -38
  168. package/dist/lib/browser/ThreadArticle-6IXTL7CH.mjs +0 -18
  169. package/dist/lib/browser/ThreadArticle-6IXTL7CH.mjs.map +0 -7
  170. package/dist/lib/browser/ThreadMain-4IAS67KE.mjs +0 -26
  171. package/dist/lib/browser/ThreadMain-4IAS67KE.mjs.map +0 -7
  172. package/dist/lib/browser/chunk-52HWDLBR.mjs.map +0 -7
  173. package/dist/lib/browser/chunk-ENERBDYI.mjs.map +0 -7
  174. package/dist/lib/browser/chunk-XUHNZID5.mjs +0 -20
  175. package/dist/lib/browser/chunk-XUHNZID5.mjs.map +0 -7
  176. package/dist/lib/browser/meta.mjs +0 -11
  177. package/dist/lib/browser/meta.mjs.map +0 -7
  178. package/dist/lib/node/ThreadArticle-I7ADXDW3.cjs.map +0 -7
  179. package/dist/lib/node/ThreadMain-MRNJC3TI.cjs.map +0 -7
  180. package/dist/lib/node/chunk-IC2NICNC.cjs.map +0 -7
  181. package/dist/lib/node/chunk-XFO6D2LG.cjs +0 -39
  182. package/dist/lib/node/chunk-XFO6D2LG.cjs.map +0 -7
  183. package/dist/lib/node/chunk-YCDM2SZM.cjs.map +0 -7
  184. package/dist/lib/node/meta.cjs.map +0 -7
  185. package/dist/lib/node-esm/ThreadArticle-CJHYMF2W.mjs +0 -19
  186. package/dist/lib/node-esm/ThreadArticle-CJHYMF2W.mjs.map +0 -7
  187. package/dist/lib/node-esm/ThreadMain-VISGW4IF.mjs +0 -27
  188. package/dist/lib/node-esm/ThreadMain-VISGW4IF.mjs.map +0 -7
  189. package/dist/lib/node-esm/chunk-7QRGG25F.mjs.map +0 -7
  190. package/dist/lib/node-esm/chunk-I5MU54RT.mjs +0 -21
  191. package/dist/lib/node-esm/chunk-I5MU54RT.mjs.map +0 -7
  192. package/dist/lib/node-esm/chunk-JG7MXH6O.mjs.map +0 -7
  193. package/dist/lib/node-esm/meta.mjs +0 -12
  194. package/dist/lib/node-esm/meta.mjs.map +0 -7
  195. package/dist/types/src/components/ThreadArticle.d.ts +0 -5
  196. package/dist/types/src/components/ThreadArticle.d.ts.map +0 -1
  197. package/dist/types/src/components/ThreadMain.d.ts +0 -7
  198. package/dist/types/src/components/ThreadMain.d.ts.map +0 -1
  199. package/src/components/ThreadArticle.tsx +0 -18
  200. package/src/components/ThreadMain.tsx +0 -27
@@ -2,122 +2,77 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import React from 'react';
6
-
7
5
  import {
8
- type IntentPluginProvides,
9
- isLayoutParts,
10
- LayoutAction,
11
- type LocationProvides,
12
- NavigationAction,
13
- parseIntentPlugin,
14
- parseMetadataResolverPlugin,
15
- parseNavigationPlugin,
16
- type Plugin,
17
- type PluginDefinition,
18
- resolvePlugin,
6
+ allOf,
7
+ Capabilities,
8
+ contributes,
9
+ createIntent,
10
+ defineModule,
11
+ definePlugin,
12
+ Events,
13
+ type PluginsContext,
19
14
  } from '@dxos/app-framework';
20
- import { type UnsubscribeCallback } from '@dxos/async';
21
- import { LocalStorageStore } from '@dxos/local-storage';
22
- import { log } from '@dxos/log';
23
- import { parseClientPlugin } from '@dxos/plugin-client';
24
- import { type ActionGroup, createExtension, isActionGroup, toSignal } from '@dxos/plugin-graph';
25
- import { ObservabilityAction } from '@dxos/plugin-observability/meta';
26
- import { memoizeQuery, SpaceAction } from '@dxos/plugin-space';
15
+ import { ClientCapabilities, ClientEvents } from '@dxos/plugin-client';
16
+ import { DeckCapabilities } from '@dxos/plugin-deck';
27
17
  import { ChannelType, MessageType, ThreadType } from '@dxos/plugin-space/types';
28
- import {
29
- create,
30
- fullyQualifiedId,
31
- getSpace,
32
- getTypename,
33
- loadObjectReferences,
34
- parseId,
35
- type ReactiveEchoObject,
36
- SpaceState,
37
- } from '@dxos/react-client/echo';
18
+ import { type ReactiveEchoObject, RefArray } from '@dxos/react-client/echo';
38
19
  import { translations as threadTranslations } from '@dxos/react-ui-thread';
39
20
 
40
- import {
41
- ChatContainer,
42
- ChatHeading,
43
- ThreadArticle,
44
- ThreadComplementary,
45
- ThreadMain,
46
- ThreadSettings,
47
- } from './components';
48
- import { threads } from './extensions';
49
- import meta, { THREAD_ITEM, THREAD_PLUGIN } from './meta';
21
+ import { AppGraphBuilder, IntentResolver, Markdown, ReactSurface, ThreadSettings, ThreadState } from './capabilities';
22
+ import { meta, THREAD_ITEM, THREAD_PLUGIN } from './meta';
50
23
  import translations from './translations';
51
- import { ThreadAction, type ThreadPluginProvides, type ThreadSettingsProps, type ThreadState } from './types';
52
-
53
- type SubjectId = string;
54
-
55
- const initialViewState = { showResolvedThreads: false };
56
-
57
- type ViewStore = Record<SubjectId, typeof initialViewState>;
24
+ import { ThreadAction, type ThreadSettingsProps } from './types';
58
25
 
59
26
  // TODO(Zan): Every instance of `cursor` should be replaced with `anchor`.
60
27
  // NOTE(burdon): Review/discuss CursorConverter semantics.
61
- export const ThreadPlugin = (): PluginDefinition<
62
- Omit<ThreadPluginProvides, 'echo'>,
63
- Pick<ThreadPluginProvides, 'echo'>
64
- > => {
65
- const settings = new LocalStorageStore<ThreadSettingsProps>(THREAD_PLUGIN);
66
- const state = create<ThreadState>({ drafts: {} });
67
-
68
- const viewStore = create<ViewStore>({});
69
- const getViewState = (subjectId: string) => {
70
- if (!viewStore[subjectId]) {
71
- viewStore[subjectId] = { ...initialViewState };
72
- }
73
- return viewStore[subjectId];
74
- };
75
-
76
- let navigationPlugin: Plugin<LocationProvides> | undefined;
77
- let intentPlugin: Plugin<IntentPluginProvides> | undefined;
78
-
79
- const unsubscribeCallbacks = [] as UnsubscribeCallback[];
80
-
81
- return {
82
- meta,
83
- initialize: async () => {
84
- settings.prop({ key: 'standalone', type: LocalStorageStore.bool({ allowUndefined: true }) });
85
-
86
- return {
87
- echo: {
88
- system: [ThreadType, MessageType],
89
- // TODO(wittjosiah): Requires reload.
90
- ...(settings.values.standalone ? { schema: [ChannelType] } : {}),
91
- },
92
- };
93
- },
94
- ready: async (plugins) => {
95
- navigationPlugin = resolvePlugin(plugins, parseNavigationPlugin);
96
- intentPlugin = resolvePlugin(plugins, parseIntentPlugin)!;
97
- },
98
- unload: async () => {
99
- unsubscribeCallbacks.forEach((unsubscribe) => unsubscribe());
100
- },
101
- provides: {
102
- settings: settings.values,
103
- metadata: {
104
- records: {
105
- [ChannelType.typename]: {
106
- createObject: ThreadAction.CREATE,
28
+ export const ThreadPlugin = () =>
29
+ definePlugin(meta, [
30
+ defineModule({
31
+ id: `${meta.id}/module/settings`,
32
+ activatesOn: Events.SetupSettings,
33
+ activate: ThreadSettings,
34
+ }),
35
+ defineModule({
36
+ id: `${meta.id}/module/state`,
37
+ activatesOn: Events.Startup,
38
+ activate: ThreadState,
39
+ }),
40
+ defineModule({
41
+ id: `${meta.id}/module/translations`,
42
+ activatesOn: Events.SetupTranslations,
43
+ activate: () => contributes(Capabilities.Translations, [...translations, ...threadTranslations]),
44
+ }),
45
+ defineModule({
46
+ id: `${meta.id}/module/metadata`,
47
+ activatesOn: Events.SetupMetadata,
48
+ activate: () => [
49
+ contributes(Capabilities.Metadata, {
50
+ id: ChannelType.typename,
51
+ metadata: {
52
+ createObject: (props: { name?: string }) => createIntent(ThreadAction.Create, props),
107
53
  placeholder: ['channel name placeholder', { ns: THREAD_PLUGIN }],
108
54
  icon: 'ph--chat--regular',
109
55
  // TODO(wittjosiah): Move out of metadata.
110
- loadReferences: (channel: ChannelType) => loadObjectReferences(channel, (channel) => channel.threads),
56
+ loadReferences: async (channel: ChannelType) => await RefArray.loadAll(channel.threads ?? []),
111
57
  },
112
- [ThreadType.typename]: {
58
+ }),
59
+ contributes(Capabilities.Metadata, {
60
+ id: ThreadType.typename,
61
+ metadata: {
113
62
  // TODO(wittjosiah): Move out of metadata.
114
- loadReferences: (thread: ThreadType) => loadObjectReferences(thread, (thread) => thread.messages),
63
+ loadReferences: async (thread: ThreadType) => await RefArray.loadAll(thread.messages ?? []),
115
64
  },
116
- [MessageType.typename]: {
65
+ }),
66
+ contributes(Capabilities.Metadata, {
67
+ id: MessageType.typename,
68
+ metadata: {
117
69
  // TODO(wittjosiah): Move out of metadata.
118
70
  loadReferences: (message: MessageType) => [], // loadObjectReferences(message, (message) => [...message.parts, message.context]),
119
71
  },
120
- [THREAD_ITEM]: {
72
+ }),
73
+ contributes(Capabilities.Metadata, {
74
+ id: THREAD_ITEM,
75
+ metadata: {
121
76
  parse: (item: ReactiveEchoObject<any>, type: string) => {
122
77
  switch (type) {
123
78
  case 'node':
@@ -129,526 +84,59 @@ export const ThreadPlugin = (): PluginDefinition<
129
84
  }
130
85
  },
131
86
  },
132
- },
133
- },
134
- translations: [...translations, ...threadTranslations],
135
- complementary: {
136
- panels: [
137
- {
138
- id: 'comments',
139
- label: ['open comments panel label', { ns: THREAD_PLUGIN }],
140
- icon: 'ph--chat-text--regular',
141
- },
142
- ],
143
- },
144
- graph: {
145
- builder: (plugins) => {
146
- const client = resolvePlugin(plugins, parseClientPlugin)?.provides.client;
147
- const dispatch = resolvePlugin(plugins, parseIntentPlugin)?.provides.intent.dispatch;
148
- const metadataResolver = resolvePlugin(plugins, parseMetadataResolverPlugin)?.provides.metadata.resolver;
149
- if (!client || !dispatch || !metadataResolver) {
150
- return [];
151
- }
152
-
153
- const type = 'orphan-comments-for-subject';
154
- const icon = 'ph--chat-text--regular';
155
-
156
- return [
157
- createExtension({
158
- id: `${THREAD_PLUGIN}/comments-for-subject`,
159
- resolver: ({ id }) => {
160
- // TODO(Zan): Find util (or make one).
161
- if (!id.endsWith('~comments')) {
162
- return;
163
- }
164
-
165
- const [subjectId] = id.split('~');
166
- const { spaceId, objectId } = parseId(subjectId);
167
- const spaces = toSignal(
168
- (onChange) => client.spaces.subscribe(() => onChange()).unsubscribe,
169
- () => client.spaces.get(),
170
- );
171
- const space = spaces?.find(
172
- (space) => space.id === spaceId && space.state.get() === SpaceState.SPACE_READY,
173
- );
174
- if (!objectId) {
175
- // TODO(wittjosiah): Support comments for arbitrary subjects.
176
- // This is to ensure that the comments panel is not stuck on an old object.
177
- return {
178
- id,
179
- type,
180
- data: null,
181
- properties: {
182
- icon,
183
- label: ['unnamed object threads label', { ns: THREAD_PLUGIN }],
184
- showResolvedThreads: false,
185
- object: null,
186
- space,
187
- },
188
- };
189
- }
190
-
191
- const [object] = memoizeQuery(space, { id: objectId });
192
- if (!object || !subjectId) {
193
- return;
194
- }
195
-
196
- const meta = metadataResolver(getTypename(object) ?? '');
197
- const label = meta.label?.(object) ||
198
- object.name ||
199
- meta.placeholder || ['unnamed object threads label', { ns: THREAD_PLUGIN }];
200
-
201
- const viewState = getViewState(subjectId);
202
-
203
- return {
204
- id,
205
- type,
206
- data: null,
207
- properties: {
208
- icon,
209
- label,
210
- showResolvedThreads: viewState.showResolvedThreads,
211
- object,
212
- },
213
- };
214
- },
215
- actions: ({ node }) => {
216
- const dataId = node.id.split('~').at(0);
217
- if (!node.id.endsWith('~comments') || !dataId) {
218
- return;
219
- }
220
-
221
- const [spaceId, objectId] = dataId.split(':');
222
-
223
- const viewState = getViewState(dataId);
224
- const toggle = () => {
225
- const newToggleState = !viewState.showResolvedThreads;
226
- viewState.showResolvedThreads = newToggleState;
227
- void dispatch({
228
- action: ObservabilityAction.SEND_EVENT,
229
- data: {
230
- name: 'threads.toggle-show-resolved',
231
- properties: { spaceId, threadId: objectId, showResolved: newToggleState },
232
- },
233
- });
234
- };
235
-
236
- return [
237
- {
238
- id: `${THREAD_PLUGIN}/toggle-show-resolved/${node.id}`,
239
- data: toggle,
240
- properties: {
241
- label: ['toggle show resolved', { ns: THREAD_PLUGIN }],
242
- menuItemType: 'toggle',
243
- isChecked: viewState.showResolvedThreads,
244
- testId: 'threadPlugin.toggleShowResolved',
245
- icon: viewState.showResolvedThreads ? 'ph--eye-slash--regular' : 'ph--eye--regular',
246
- },
247
- },
248
- ];
249
- },
250
- }),
251
- createExtension({
252
- id: ThreadAction.CREATE,
253
- filter: (node): node is ActionGroup =>
254
- !!settings.values.standalone && isActionGroup(node) && node.id.startsWith(SpaceAction.ADD_OBJECT),
255
- actions: ({ node }) => {
256
- const id = node.id.split('/').at(-1);
257
- const [spaceId, objectId] = id?.split(':') ?? [];
258
- const space = client.spaces.get().find((space) => space.id === spaceId);
259
- const object = objectId && space?.db.getObjectById(objectId);
260
- const target = objectId ? object : space;
261
- if (!target) {
262
- return;
263
- }
264
-
265
- return [
266
- {
267
- id: `${THREAD_PLUGIN}/create/${node.id}`,
268
- data: async () => {
269
- await dispatch([
270
- { plugin: THREAD_PLUGIN, action: ThreadAction.CREATE },
271
- { action: SpaceAction.ADD_OBJECT, data: { target } },
272
- { action: NavigationAction.OPEN },
273
- ]);
274
- },
275
- properties: {
276
- label: ['create channel label', { ns: THREAD_PLUGIN }],
277
- icon: 'ph--chat--regular',
278
- testId: 'threadPlugin.createObject',
279
- },
280
- },
281
- ];
282
- },
283
- }),
284
- ];
285
- },
286
- },
287
- surface: {
288
- component: ({ data, role }) => {
289
- switch (role) {
290
- case 'main': {
291
- return data.active instanceof ChannelType && data.active.threads[0] ? (
292
- <ThreadMain thread={data.active.threads[0]} />
293
- ) : null;
294
- }
295
-
296
- case 'settings': {
297
- return data.plugin === meta.id ? <ThreadSettings settings={settings.values} /> : null;
298
- }
299
-
300
- case 'article': {
301
- const location = navigationPlugin?.provides.location;
302
-
303
- if (data.object instanceof ChannelType && data.object.threads[0]) {
304
- const channel = data.object;
305
- // TODO(zan): Maybe we should have utility for positional main object ids.
306
- if (isLayoutParts(location?.active) && location.active.main) {
307
- const layoutEntries = location.active.main;
308
- const currentPosition = layoutEntries.findIndex((entry) => channel.id === entry.id);
309
- if (currentPosition > 0) {
310
- const objectToTheLeft = layoutEntries[currentPosition - 1];
311
- const context = getSpace(data.object)?.db.getObjectById(objectToTheLeft.id);
312
- return <ThreadArticle thread={data.object.threads[0]} context={context} />;
313
- }
314
- }
315
-
316
- return <ThreadArticle thread={data.object.threads[0]} />;
317
- }
318
-
319
- if (data.subject instanceof ThreadType) {
320
- return (
321
- <>
322
- <ChatHeading attendableId={data.subject.id} />
323
- <ChatContainer thread={data.subject} />
324
- </>
325
- );
326
- }
327
-
328
- break;
329
- }
330
-
331
- case 'complementary--comments': {
332
- if (
333
- data.subject &&
334
- typeof data.subject === 'object' &&
335
- 'threads' in data.subject &&
336
- Array.isArray(data.subject.threads) &&
337
- !(data.subject instanceof ChannelType)
338
- ) {
339
- const { showResolvedThreads } = getViewState(fullyQualifiedId(data.subject));
340
- return (
341
- <ThreadComplementary
342
- role={role}
343
- subject={data.subject}
344
- drafts={state.drafts[fullyQualifiedId(data.subject)]}
345
- current={state.current}
346
- showResolvedThreads={showResolvedThreads}
347
- />
348
- );
349
- }
350
-
351
- break;
352
- }
353
- }
354
-
355
- return null;
356
- },
357
- },
358
- intent: {
359
- resolver: async (intent) => {
360
- switch (intent.action) {
361
- case ThreadAction.CREATE: {
362
- if (intent.data && intent.data.cursor !== undefined) {
363
- const { cursor, name, subject } = intent.data;
364
-
365
- // Seed the threads array if it does not exist.
366
- if (subject?.threads === undefined) {
367
- try {
368
- // Static schema will throw an error if subject does not support threads array property.
369
- subject.threads = [];
370
- } catch (err) {
371
- log.error('Subject does not support threads array', subject?.typename);
372
- return;
373
- }
374
- }
375
-
376
- const subjectId = fullyQualifiedId(subject);
377
- const thread = create(ThreadType, { name, anchor: cursor, messages: [], status: 'staged' });
378
- const draft = state.drafts[subjectId];
379
- if (draft) {
380
- draft.push(thread);
381
- } else {
382
- state.drafts[subjectId] = [thread];
383
- }
384
-
385
- return {
386
- data: thread,
387
- intents: [
388
- [
389
- {
390
- action: ThreadAction.SELECT,
391
- data: { current: fullyQualifiedId(thread) },
392
- },
393
- ],
394
- [
395
- {
396
- action: NavigationAction.OPEN,
397
- data: {
398
- activeParts: { complementary: 'comments' },
399
- },
400
- },
401
- ],
402
- [
403
- {
404
- action: LayoutAction.SET_LAYOUT,
405
- data: {
406
- element: 'complementary',
407
- state: true,
408
- },
409
- },
410
- ],
411
- ],
412
- };
413
- } else {
414
- // NOTE: This is the standalone thread creation case.
415
- return {
416
- data: create(ChannelType, { threads: [create(ThreadType, { messages: [] })] }),
417
- };
418
- }
419
- }
420
-
421
- case ThreadAction.SELECT: {
422
- state.current = intent.data?.current;
423
-
424
- return {
425
- data: true,
426
- intents: !intent.data?.skipOpen
427
- ? [
428
- [
429
- {
430
- action: NavigationAction.OPEN,
431
- data: {
432
- activeParts: { complementary: 'comments' },
433
- },
434
- },
435
- ],
436
- ]
437
- : [],
438
- };
439
- }
440
-
441
- case ThreadAction.TOGGLE_RESOLVED: {
442
- const { thread } = intent.data ?? {};
443
- if (!(thread instanceof ThreadType)) {
444
- return;
445
- }
446
-
447
- if (thread.status === 'active' || thread.status === undefined) {
448
- thread.status = 'resolved';
449
- } else if (thread.status === 'resolved') {
450
- thread.status = 'active';
451
- }
452
-
453
- const space = getSpace(thread);
454
- const spaceId = space?.id;
455
-
456
- return {
457
- data: true,
458
- intents: [
459
- [
460
- {
461
- action: ObservabilityAction.SEND_EVENT,
462
- data: { name: 'threads.toggle-resolved', properties: { threadId: thread.id, spaceId } },
463
- },
464
- ],
465
- ],
466
- };
467
- }
468
-
469
- case ThreadAction.DELETE: {
470
- const { subject, thread } = intent.data ?? {};
471
- if (
472
- !(thread instanceof ThreadType) ||
473
- !(subject && typeof subject === 'object' && 'threads' in subject)
474
- ) {
475
- return;
476
- }
477
-
478
- const subjectId = fullyQualifiedId(subject);
479
- const draft = state.drafts[subjectId];
480
- if (draft) {
481
- // Check if we're deleting a draft; if so, remove it.
482
- const index = draft.findIndex((t) => t.id === thread.id);
483
- if (index !== -1) {
484
- draft.splice(index, 1);
485
- return { data: true };
486
- }
487
- }
488
-
489
- const space = getSpace(thread);
490
- if (!space || !subject.threads) {
491
- return;
492
- }
493
-
494
- if (!intent.undo) {
495
- const index = subject.threads.findIndex((t: any) => t?.id === thread.id);
496
- const cursor = subject.threads[index]?.anchor;
497
- if (index !== -1) {
498
- subject.threads?.splice(index, 1);
499
- }
500
-
501
- space.db.remove(thread);
502
-
503
- return {
504
- undoable: {
505
- message: translations[0]['en-US'][THREAD_PLUGIN]['thread deleted label'],
506
- data: { cursor },
507
- },
508
- intents: [
509
- [
510
- {
511
- action: ObservabilityAction.SEND_EVENT,
512
- data: { name: 'threads.delete', properties: { threadId: thread.id, spaceId: space.id } },
513
- },
514
- ],
515
- ],
516
- };
517
- } else if (intent.undo) {
518
- // TODO(wittjosiah): SDK should do this automatically.
519
- const savedThread = space.db.add(thread);
520
- subject.threads.push(savedThread);
521
-
522
- return {
523
- data: true,
524
- intents: [
525
- [
526
- {
527
- action: ObservabilityAction.SEND_EVENT,
528
- data: { name: 'threads.undo-delete', properties: { threadId: thread.id, spaceId: space.id } },
529
- },
530
- ],
531
- ],
532
- };
533
- }
534
- break;
535
- }
536
-
537
- case ThreadAction.ON_MESSAGE_ADD: {
538
- const { thread, subject } = intent.data ?? {};
539
- if (
540
- !(thread instanceof ThreadType) ||
541
- !(subject && typeof subject === 'object' && 'threads' in subject && Array.isArray(subject.threads))
542
- ) {
543
- return;
544
- }
545
-
546
- const subjectId = fullyQualifiedId(subject);
547
- const space = getSpace(subject);
548
- const intents = [];
549
- const analyticsProperties = { threadId: thread.id, spaceId: space?.id };
550
-
551
- if (state.drafts[subjectId]?.find((t) => t === thread)) {
552
- // Move draft to document.
553
- thread.status = 'active';
554
- subject.threads ? subject.threads.push(thread) : (subject.threads = [thread]);
555
- state.drafts[subjectId] = state.drafts[subjectId]?.filter(({ id }) => id !== thread.id);
556
- intents.push({
557
- action: ObservabilityAction.SEND_EVENT,
558
- data: { name: 'threads.thread-created', properties: analyticsProperties },
559
- });
560
- }
561
-
562
- intents.push({
563
- action: ObservabilityAction.SEND_EVENT,
564
- data: {
565
- name: 'threads.message-added',
566
- properties: { ...analyticsProperties, threadLength: thread.messages.length },
567
- },
568
- });
569
-
570
- return {
571
- data: thread,
572
- intents: [intents],
573
- };
574
- }
575
-
576
- case ThreadAction.DELETE_MESSAGE: {
577
- const { subject, thread, messageId } = intent.data ?? {};
578
- const space = getSpace(subject);
579
-
580
- if (
581
- !(thread instanceof ThreadType) ||
582
- !(subject && typeof subject === 'object' && 'threads' in subject)
583
- ) {
584
- return;
585
- }
586
-
587
- if (!intent.undo) {
588
- const message = thread.messages.find((m) => m?.id === messageId);
589
- const messageIndex = thread.messages.findIndex((m) => m?.id === messageId);
590
- if (messageIndex === -1 || !message) {
591
- return undefined;
592
- }
593
-
594
- if (messageIndex === 0 && thread.messages.length === 1) {
595
- // If the message is the only message in the thread, delete the thread.
596
- return {
597
- intents: [[{ action: ThreadAction.DELETE, data: { subject, thread } }]],
598
- };
599
- } else {
600
- thread.messages.splice(messageIndex, 1);
601
- }
602
-
603
- return {
604
- undoable: {
605
- message: translations[0]['en-US'][THREAD_PLUGIN]['message deleted label'],
606
- data: { message, messageIndex },
607
- },
608
- intents: [
609
- [
610
- {
611
- action: ObservabilityAction.SEND_EVENT,
612
- data: {
613
- name: 'threads.message.delete',
614
- properties: { threadId: thread.id, spaceId: space?.id },
615
- },
616
- },
617
- ],
618
- ],
619
- };
620
- } else if (intent.undo) {
621
- const message = intent.data?.message;
622
- const messageIndex = intent.data?.messageIndex;
623
- if (!(message instanceof MessageType) || !(typeof messageIndex === 'number')) {
624
- return;
625
- }
626
-
627
- thread.messages.splice(messageIndex, 0, message);
628
- return {
629
- data: true,
630
- intents: [
631
- [
632
- {
633
- action: ObservabilityAction.SEND_EVENT,
634
- data: {
635
- name: 'threads.message.undo-delete',
636
- properties: { threadId: thread.id, spaceId: space?.id },
637
- },
638
- },
639
- ],
640
- ],
641
- };
642
- }
643
- }
644
- }
645
- },
646
- },
647
- markdown: {
648
- extensions: ({ document: doc }) => {
649
- return threads(state, doc, intentPlugin?.provides.intent.dispatch);
650
- },
87
+ }),
88
+ ],
89
+ }),
90
+ defineModule({
91
+ id: `${meta.id}/module/schema`,
92
+ activatesOn: ClientEvents.SetupSchema,
93
+ activate: () => contributes(ClientCapabilities.SystemSchema, [ThreadType, MessageType]),
94
+ }),
95
+ defineModule({
96
+ id: `${meta.id}/module/channel-schema`,
97
+ activatesOn: allOf(Events.SettingsReady, ClientEvents.ClientReady),
98
+ activate: (context: PluginsContext) => {
99
+ const client = context.requestCapability(ClientCapabilities.Client);
100
+ const settings = context
101
+ .requestCapability(Capabilities.SettingsStore)
102
+ .getStore<ThreadSettingsProps>(THREAD_PLUGIN)!.value;
103
+ if (settings.standalone) {
104
+ // TODO(wittjosiah): Requires reload to disable.
105
+ client.addTypes([ChannelType]);
106
+ return contributes(ClientCapabilities.Schema, [ChannelType]);
107
+ }
108
+
109
+ return [];
651
110
  },
652
- },
653
- };
654
- };
111
+ }),
112
+ defineModule({
113
+ id: `${meta.id}/module/complementary-panel`,
114
+ activatesOn: Events.Startup,
115
+ activate: () =>
116
+ contributes(DeckCapabilities.ComplementaryPanel, {
117
+ id: 'comments',
118
+ label: ['comments panel label', { ns: THREAD_PLUGIN }],
119
+ icon: 'ph--chat-text--regular',
120
+ }),
121
+ }),
122
+ defineModule({
123
+ id: `${meta.id}/module/markdown`,
124
+ activatesOn: Events.Startup,
125
+ activate: Markdown,
126
+ }),
127
+ defineModule({
128
+ id: `${meta.id}/module/react-surface`,
129
+ activatesOn: Events.SetupSurfaces,
130
+ activate: ReactSurface,
131
+ }),
132
+ defineModule({
133
+ id: `${meta.id}/module/intent-resolver`,
134
+ activatesOn: Events.SetupIntents,
135
+ activate: IntentResolver,
136
+ }),
137
+ defineModule({
138
+ id: `${meta.id}/module/app-graph-builder`,
139
+ activatesOn: Events.SetupAppGraph,
140
+ activate: AppGraphBuilder,
141
+ }),
142
+ ]);