@dxos/plugin-thread 0.6.11 → 0.6.12-main.5a87ad5

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 (79) hide show
  1. package/dist/lib/browser/{ThreadArticle-O64ZECMF.mjs → ThreadArticle-4VU752F4.mjs} +3 -3
  2. package/dist/lib/browser/{ThreadMain-ZDCRC6RG.mjs → ThreadMain-ML3P4XSD.mjs} +3 -3
  3. package/dist/lib/browser/{chunk-5IBJO53M.mjs → chunk-7NUYW5IW.mjs} +2 -5
  4. package/dist/lib/browser/chunk-7NUYW5IW.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-GKPZHUT3.mjs → chunk-GJRBBPXI.mjs} +2 -2
  6. package/dist/lib/browser/{chunk-GKPZHUT3.mjs.map → chunk-GJRBBPXI.mjs.map} +1 -1
  7. package/dist/lib/browser/{chunk-P7ZE5N5M.mjs → chunk-XF5QKI75.mjs} +13 -11
  8. package/dist/lib/browser/chunk-XF5QKI75.mjs.map +7 -0
  9. package/dist/lib/browser/index.mjs +237 -207
  10. package/dist/lib/browser/index.mjs.map +4 -4
  11. package/dist/lib/browser/meta.json +1 -1
  12. package/dist/lib/browser/meta.mjs +1 -1
  13. package/dist/lib/browser/types.mjs +2 -2
  14. package/dist/lib/node/{ThreadArticle-DO56JXBU.cjs → ThreadArticle-ERUHPHVT.cjs} +7 -7
  15. package/dist/lib/node/{ThreadMain-XJX75GHG.cjs → ThreadMain-6DN7FDNB.cjs} +7 -7
  16. package/dist/lib/node/{chunk-BWBONZGU.cjs → chunk-6EVXCSDS.cjs} +5 -18
  17. package/dist/lib/node/chunk-6EVXCSDS.cjs.map +7 -0
  18. package/dist/lib/node/{chunk-D5GOVXHS.cjs → chunk-FXD3DYMO.cjs} +6 -6
  19. package/dist/lib/node/{chunk-D5GOVXHS.cjs.map → chunk-FXD3DYMO.cjs.map} +1 -1
  20. package/dist/lib/node/{chunk-5PZNPPQF.cjs → chunk-PZVUW4W2.cjs} +65 -63
  21. package/dist/lib/node/chunk-PZVUW4W2.cjs.map +7 -0
  22. package/dist/lib/node/index.cjs +324 -296
  23. package/dist/lib/node/index.cjs.map +4 -4
  24. package/dist/lib/node/meta.cjs +4 -4
  25. package/dist/lib/node/meta.cjs.map +1 -1
  26. package/dist/lib/node/meta.json +1 -1
  27. package/dist/lib/node/types.cjs +3 -3
  28. package/dist/lib/node/types.cjs.map +1 -1
  29. package/dist/lib/node-esm/ThreadArticle-NKI5F4W5.mjs +19 -0
  30. package/dist/lib/node-esm/ThreadArticle-NKI5F4W5.mjs.map +7 -0
  31. package/dist/lib/node-esm/ThreadMain-2A3VQLCW.mjs +27 -0
  32. package/dist/lib/node-esm/ThreadMain-2A3VQLCW.mjs.map +7 -0
  33. package/dist/lib/node-esm/chunk-A44C4MTQ.mjs +413 -0
  34. package/dist/lib/node-esm/chunk-A44C4MTQ.mjs.map +7 -0
  35. package/dist/lib/node-esm/chunk-Y475KZTX.mjs +20 -0
  36. package/dist/lib/node-esm/chunk-Y475KZTX.mjs.map +7 -0
  37. package/dist/lib/node-esm/chunk-YO46JGAE.mjs +21 -0
  38. package/dist/lib/node-esm/chunk-YO46JGAE.mjs.map +7 -0
  39. package/dist/lib/node-esm/index.mjs +1133 -0
  40. package/dist/lib/node-esm/index.mjs.map +7 -0
  41. package/dist/lib/node-esm/meta.json +1 -0
  42. package/dist/lib/node-esm/meta.mjs +12 -0
  43. package/dist/lib/node-esm/meta.mjs.map +7 -0
  44. package/dist/lib/node-esm/types.mjs +9 -0
  45. package/dist/lib/node-esm/types.mjs.map +7 -0
  46. package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
  47. package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
  48. package/dist/types/src/components/CommentContainer.d.ts.map +1 -1
  49. package/dist/types/src/components/CommentsContainer.d.ts.map +1 -1
  50. package/dist/types/src/components/MessageContainer.d.ts.map +1 -1
  51. package/dist/types/src/components/ThreadComplementary.d.ts +11 -0
  52. package/dist/types/src/components/ThreadComplementary.d.ts.map +1 -0
  53. package/dist/types/src/components/testing.d.ts +2 -0
  54. package/dist/types/src/components/testing.d.ts.map +1 -1
  55. package/dist/types/src/meta.d.ts +1 -4
  56. package/dist/types/src/meta.d.ts.map +1 -1
  57. package/dist/types/src/types.d.ts +1 -1
  58. package/dist/types/src/types.d.ts.map +1 -1
  59. package/package.json +37 -34
  60. package/src/ThreadPlugin.tsx +68 -178
  61. package/src/components/ChatContainer.tsx +7 -8
  62. package/src/components/CommentContainer.tsx +10 -7
  63. package/src/components/Comments.stories.tsx +2 -2
  64. package/src/components/CommentsContainer.tsx +22 -18
  65. package/src/components/MessageContainer.tsx +2 -1
  66. package/src/components/ThreadComplementary.tsx +120 -0
  67. package/src/meta.tsx +1 -5
  68. package/src/types.ts +1 -1
  69. package/dist/lib/browser/chunk-5IBJO53M.mjs.map +0 -7
  70. package/dist/lib/browser/chunk-P7ZE5N5M.mjs.map +0 -7
  71. package/dist/lib/node/chunk-5PZNPPQF.cjs.map +0 -7
  72. package/dist/lib/node/chunk-BWBONZGU.cjs.map +0 -7
  73. package/dist/types/src/types.test.d.ts +0 -2
  74. package/dist/types/src/types.test.d.ts.map +0 -1
  75. package/src/types.test.ts +0 -13
  76. /package/dist/lib/browser/{ThreadArticle-O64ZECMF.mjs.map → ThreadArticle-4VU752F4.mjs.map} +0 -0
  77. /package/dist/lib/browser/{ThreadMain-ZDCRC6RG.mjs.map → ThreadMain-ML3P4XSD.mjs.map} +0 -0
  78. /package/dist/lib/node/{ThreadArticle-DO56JXBU.cjs.map → ThreadArticle-ERUHPHVT.cjs.map} +0 -0
  79. /package/dist/lib/node/{ThreadMain-XJX75GHG.cjs.map → ThreadMain-6DN7FDNB.cjs.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ThreadAction
3
- } from "./chunk-GKPZHUT3.mjs";
3
+ } from "./chunk-GJRBBPXI.mjs";
4
4
  import {
5
5
  ChatContainer,
6
6
  ChatHeading,
@@ -10,34 +10,30 @@ import {
10
10
  useAnalyticsCallback,
11
11
  useOnEditAnalytics,
12
12
  useStatus
13
- } from "./chunk-P7ZE5N5M.mjs";
13
+ } from "./chunk-XF5QKI75.mjs";
14
14
  import {
15
15
  THREAD_ITEM,
16
16
  THREAD_PLUGIN,
17
17
  meta_default
18
- } from "./chunk-5IBJO53M.mjs";
18
+ } from "./chunk-7NUYW5IW.mjs";
19
19
 
20
20
  // packages/plugins/plugin-thread/src/ThreadPlugin.tsx
21
- import { Chat } from "@phosphor-icons/react";
22
21
  import { computed, effect } from "@preact/signals-core";
23
- import React5 from "react";
24
- import { LayoutAction, NavigationAction, parseIntentPlugin, parseNavigationPlugin, resolvePlugin, parseGraphPlugin, SLUG_PATH_SEPARATOR, SLUG_COLLECTION_INDICATOR, isLayoutParts, parseMetadataResolverPlugin, useResolvePlugins } from "@dxos/app-framework";
22
+ import React6 from "react";
23
+ import { LayoutAction as LayoutAction2, NavigationAction, parseIntentPlugin, parseNavigationPlugin, resolvePlugin, isLayoutParts, parseMetadataResolverPlugin } from "@dxos/app-framework";
25
24
  import { getTypename } from "@dxos/echo-schema";
26
25
  import { create as create2 } from "@dxos/echo-schema";
27
26
  import { LocalStorageStore } from "@dxos/local-storage";
28
- import { parseAttentionPlugin } from "@dxos/plugin-attention";
27
+ import { log } from "@dxos/log";
29
28
  import { parseClientPlugin } from "@dxos/plugin-client";
30
- import { createExtension, isActionGroup } from "@dxos/plugin-graph";
31
- import { DocumentType } from "@dxos/plugin-markdown/types";
29
+ import { createExtension, isActionGroup, toSignal } from "@dxos/plugin-graph";
32
30
  import { ObservabilityAction } from "@dxos/plugin-observability/meta";
33
31
  import { SpaceAction } from "@dxos/plugin-space";
34
32
  import { ThreadType, MessageType as MessageType2, ChannelType } from "@dxos/plugin-space/types";
35
- import { getSpace as getSpace2, getTextInRange, Filter, createDocAccessor, fullyQualifiedId, loadObjectReferences } from "@dxos/react-client/echo";
36
- import { ScrollArea } from "@dxos/react-ui";
37
- import { createAttendableAttributes } from "@dxos/react-ui-attention";
33
+ import { getSpace as getSpace2, getTextInRange, createDocAccessor, fullyQualifiedId as fullyQualifiedId4, loadObjectReferences } from "@dxos/react-client/echo";
38
34
  import { comments, createExternalCommentSync, listener as listener2 } from "@dxos/react-ui-editor";
39
35
  import { translations as threadTranslations } from "@dxos/react-ui-thread";
40
- import { nonNullable as nonNullable2 } from "@dxos/util";
36
+ import { nonNullable as nonNullable3 } from "@dxos/util";
41
37
 
42
38
  // packages/plugins/plugin-thread/src/components/index.ts
43
39
  import React4 from "react";
@@ -61,7 +57,7 @@ import { CheckCircle, X } from "@phosphor-icons/react";
61
57
  import React2, { useCallback, useEffect, useMemo, useRef, useState } from "react";
62
58
  import { create } from "@dxos/echo-schema";
63
59
  import { MessageType } from "@dxos/plugin-space/types";
64
- import { getSpace, useMembers } from "@dxos/react-client/echo";
60
+ import { fullyQualifiedId, getSpace, useMembers } from "@dxos/react-client/echo";
65
61
  import { useIdentity } from "@dxos/react-client/halo";
66
62
  import { Button, Tag, Tooltip, useThemeContext, useTranslation as useTranslation2 } from "@dxos/react-ui";
67
63
  import { createBasicExtensions, createThemeExtensions, listener } from "@dxos/react-ui-editor";
@@ -118,12 +114,12 @@ var CommentContainer = ({ thread, detached, context, current, autoFocusTextbox,
118
114
  const identity = useIdentity();
119
115
  const space = getSpace(thread);
120
116
  const members = useMembers(space?.key);
121
- const activity = useStatus(space, thread.id);
117
+ const activity = useStatus(space, fullyQualifiedId(thread));
122
118
  const { t } = useTranslation2(THREAD_PLUGIN);
123
119
  const threadScrollRef = useRef(null);
124
120
  const [autoFocus, setAutoFocus] = useState(!!autoFocusTextbox);
125
121
  const { themeMode } = useThemeContext();
126
- const textboxMetadata = getMessageMetadata(thread.id, identity);
122
+ const textboxMetadata = getMessageMetadata(fullyQualifiedId(thread), identity);
127
123
  const [_count, _setCount] = useState(0);
128
124
  const rerenderEditor = () => _setCount((count) => count + 1);
129
125
  const messageRef = useRef("");
@@ -172,12 +168,11 @@ var CommentContainer = ({ thread, detached, context, current, autoFocusTextbox,
172
168
  thread,
173
169
  identity
174
170
  ]);
175
- const handleDeleteMessage = (id) => onMessageDelete?.(id);
176
171
  return /* @__PURE__ */ React2.createElement(Thread, {
177
172
  onClickCapture: onAttend,
178
173
  onFocusCapture: onAttend,
179
174
  current,
180
- id: thread.id
175
+ id: fullyQualifiedId(thread)
181
176
  }, /* @__PURE__ */ React2.createElement("div", {
182
177
  role: "none",
183
178
  className: mx("col-span-2 grid grid-cols-[var(--rail-size)_1fr_min-content]", hoverableControls, hoverableFocusedWithinControls)
@@ -201,7 +196,7 @@ var CommentContainer = ({ thread, detached, context, current, autoFocusTextbox,
201
196
  key: message.id,
202
197
  message,
203
198
  members,
204
- onDelete: handleDeleteMessage
199
+ onDelete: (id) => onMessageDelete?.(id)
205
200
  })), /* @__PURE__ */ React2.createElement(MessageTextbox, {
206
201
  extensions,
207
202
  autoFocus,
@@ -217,10 +212,11 @@ var CommentContainer = ({ thread, detached, context, current, autoFocusTextbox,
217
212
  };
218
213
 
219
214
  // packages/plugins/plugin-thread/src/components/CommentsContainer.tsx
220
- import { ChatText, Quotes } from "@phosphor-icons/react";
215
+ import { ChatText } from "@phosphor-icons/react";
221
216
  import React3, { useEffect as useEffect2 } from "react";
222
- import { useTranslation as useTranslation3, Trans } from "@dxos/react-ui";
223
- import { PlankHeading, plankHeadingIconProps } from "@dxos/react-ui-deck";
217
+ import { fullyQualifiedId as fullyQualifiedId2 } from "@dxos/react-client/echo";
218
+ import { useTranslation as useTranslation3, Icon, Trans } from "@dxos/react-ui";
219
+ import { PlankHeading } from "@dxos/react-ui-deck";
224
220
  import { descriptionText, mx as mx2 } from "@dxos/react-ui-theme";
225
221
  var CommentsHeading = ({ attendableId }) => {
226
222
  const { t } = useTranslation3(THREAD_PLUGIN);
@@ -229,7 +225,10 @@ var CommentsHeading = ({ attendableId }) => {
229
225
  className: "flex items-center"
230
226
  }, /* @__PURE__ */ React3.createElement(PlankHeading.Button, {
231
227
  attendableId
232
- }, /* @__PURE__ */ React3.createElement(Quotes, plankHeadingIconProps)), /* @__PURE__ */ React3.createElement(PlankHeading.Label, {
228
+ }, /* @__PURE__ */ React3.createElement(Icon, {
229
+ icon: "ph--quotes--regular",
230
+ size: 5
231
+ })), /* @__PURE__ */ React3.createElement(PlankHeading.Label, {
233
232
  attendableId
234
233
  }, t("comments heading")));
235
234
  };
@@ -246,26 +245,29 @@ var CommentsContainer = ({ threads, detached = [], currentId, autoFocusCurrentTe
246
245
  }, [
247
246
  currentId
248
247
  ]);
249
- return /* @__PURE__ */ React3.createElement(React3.Fragment, null, filteredThreads.length > 0 ? filteredThreads.map((thread) => /* @__PURE__ */ React3.createElement(CommentContainer, {
250
- key: thread.id,
251
- thread,
252
- current: currentId === thread.id,
253
- detached: detached.includes(thread.id),
254
- autoFocusTextbox: autoFocusCurrentTextbox && currentId === thread.id,
255
- ...onThreadAttend && {
256
- onAttend: () => onThreadAttend(thread)
257
- },
258
- ...onThreadDelete && {
259
- onThreadDelete: () => onThreadDelete(thread)
260
- },
261
- ...onMessageDelete && {
262
- onMessageDelete: (messageId) => onMessageDelete(thread, messageId)
263
- },
264
- ...onThreadToggleResolved && {
265
- onResolve: () => onThreadToggleResolved(thread)
266
- },
267
- ...props
268
- })) : /* @__PURE__ */ React3.createElement("div", {
248
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, filteredThreads.length > 0 ? filteredThreads.map((thread) => {
249
+ const threadId = fullyQualifiedId2(thread);
250
+ return /* @__PURE__ */ React3.createElement(CommentContainer, {
251
+ key: threadId,
252
+ thread,
253
+ current: currentId === threadId,
254
+ detached: detached.includes(threadId),
255
+ autoFocusTextbox: autoFocusCurrentTextbox && currentId === threadId,
256
+ ...onThreadAttend && {
257
+ onAttend: () => onThreadAttend(thread)
258
+ },
259
+ ...onThreadDelete && {
260
+ onThreadDelete: () => onThreadDelete(thread)
261
+ },
262
+ ...onMessageDelete && {
263
+ onMessageDelete: (messageId) => onMessageDelete(thread, messageId)
264
+ },
265
+ ...onThreadToggleResolved && {
266
+ onResolve: () => onThreadToggleResolved(thread)
267
+ },
268
+ ...props
269
+ });
270
+ }) : /* @__PURE__ */ React3.createElement("div", {
269
271
  role: "alert",
270
272
  className: mx2(descriptionText, "place-self-center border border-dashed border-neutral-400/50 rounded-lg text-center p-4 m-4")
271
273
  }, /* @__PURE__ */ React3.createElement("h2", {
@@ -282,8 +284,124 @@ var CommentsContainer = ({ threads, detached = [], currentId, autoFocusCurrentTe
282
284
  };
283
285
 
284
286
  // packages/plugins/plugin-thread/src/components/index.ts
285
- var ThreadMain = React4.lazy(() => import("./ThreadMain-ZDCRC6RG.mjs"));
286
- var ThreadArticle = React4.lazy(() => import("./ThreadArticle-O64ZECMF.mjs"));
287
+ var ThreadMain = React4.lazy(() => import("./ThreadMain-ML3P4XSD.mjs"));
288
+ var ThreadArticle = React4.lazy(() => import("./ThreadArticle-4VU752F4.mjs"));
289
+
290
+ // packages/plugins/plugin-thread/src/components/ThreadComplementary.tsx
291
+ import React5, { useEffect as useEffect3, useMemo as useMemo2 } from "react";
292
+ import { LayoutAction, useIntentDispatcher, useResolvePlugins } from "@dxos/app-framework";
293
+ import { fullyQualifiedId as fullyQualifiedId3 } from "@dxos/react-client/echo";
294
+ import { ScrollArea } from "@dxos/react-ui";
295
+ import { createAttendableAttributes, useAttentionContext } from "@dxos/react-ui-attention";
296
+ import { nonNullable as nonNullable2 } from "@dxos/util";
297
+ var providesThreadsConfig = (plugin) => "thread" in plugin.provides ? plugin : void 0;
298
+ var ThreadComplementary = ({ role, subject, stagedThreads, current, focus, showResolvedThreads }) => {
299
+ const dispatch = useIntentDispatcher();
300
+ const threadsIntegrators = useResolvePlugins(providesThreadsConfig);
301
+ const threadProvides = useMemo2(() => threadsIntegrators.map((p) => p.provides.thread), [
302
+ threadsIntegrators
303
+ ]);
304
+ const createSort = useMemo2(() => threadProvides.find((p) => p.predicate(subject))?.createSort, [
305
+ threadProvides,
306
+ subject
307
+ ]);
308
+ const sort = useMemo2(() => createSort?.(subject), [
309
+ createSort,
310
+ subject
311
+ ]);
312
+ const threads = useMemo2(() => {
313
+ return subject.threads.concat(stagedThreads ?? []).filter(nonNullable2);
314
+ }, [
315
+ JSON.stringify(subject.threads),
316
+ JSON.stringify(stagedThreads)
317
+ ]);
318
+ const detachedIds = useMemo2(() => {
319
+ return threads.filter(({ anchor }) => !anchor).map((thread) => fullyQualifiedId3(thread));
320
+ }, [
321
+ threads
322
+ ]);
323
+ useEffect3(() => {
324
+ if (!sort) {
325
+ return;
326
+ }
327
+ threads.sort((a, b) => sort(a?.anchor, b?.anchor));
328
+ }, [
329
+ sort,
330
+ threads
331
+ ]);
332
+ const { attended } = useAttentionContext("Thread Complementary");
333
+ const qualifiedSubjectId = fullyQualifiedId3(subject);
334
+ const attendableAttrs = createAttendableAttributes(qualifiedSubjectId);
335
+ return /* @__PURE__ */ React5.createElement("div", {
336
+ role: "none",
337
+ className: "contents group/attention",
338
+ ...attendableAttrs
339
+ }, role === "complementary" && /* @__PURE__ */ React5.createElement(CommentsHeading, {
340
+ attendableId: qualifiedSubjectId
341
+ }), /* @__PURE__ */ React5.createElement(ScrollArea.Root, {
342
+ classNames: "row-span-2"
343
+ }, /* @__PURE__ */ React5.createElement(ScrollArea.Viewport, null, /* @__PURE__ */ React5.createElement(CommentsContainer, {
344
+ threads,
345
+ detached: detachedIds,
346
+ currentId: attended.has(qualifiedSubjectId) ? current : void 0,
347
+ autoFocusCurrentTextbox: focus,
348
+ showResolvedThreads,
349
+ onThreadAttend: (thread) => {
350
+ const threadId = fullyQualifiedId3(thread);
351
+ if (current !== threadId) {
352
+ current = threadId;
353
+ void dispatch?.([
354
+ {
355
+ action: LayoutAction.SCROLL_INTO_VIEW,
356
+ data: {
357
+ id: fullyQualifiedId3(subject),
358
+ thread: threadId,
359
+ cursor: thread.anchor
360
+ }
361
+ }
362
+ ]);
363
+ }
364
+ },
365
+ onThreadDelete: (thread) => {
366
+ return dispatch({
367
+ plugin: THREAD_PLUGIN,
368
+ action: ThreadAction.DELETE,
369
+ data: {
370
+ subject,
371
+ thread
372
+ }
373
+ });
374
+ },
375
+ onMessageDelete: (thread, messageId) => dispatch({
376
+ plugin: THREAD_PLUGIN,
377
+ action: ThreadAction.DELETE_MESSAGE,
378
+ data: {
379
+ subject,
380
+ thread,
381
+ messageId
382
+ }
383
+ }),
384
+ onThreadToggleResolved: (thread) => dispatch({
385
+ plugin: THREAD_PLUGIN,
386
+ action: ThreadAction.TOGGLE_RESOLVED,
387
+ data: {
388
+ thread
389
+ }
390
+ }),
391
+ onComment: (thread) => {
392
+ void dispatch({
393
+ action: ThreadAction.ON_MESSAGE_ADD,
394
+ data: {
395
+ thread,
396
+ subject
397
+ }
398
+ });
399
+ }
400
+ }), /* @__PURE__ */ React5.createElement("div", {
401
+ role: "none",
402
+ className: "bs-10"
403
+ }), /* @__PURE__ */ React5.createElement(ScrollArea.Scrollbar, null, /* @__PURE__ */ React5.createElement(ScrollArea.Thumb, null)))));
404
+ };
287
405
 
288
406
  // packages/plugins/plugin-thread/src/translations.ts
289
407
  var translations_default = [
@@ -322,10 +440,10 @@ var translations_default = [
322
440
  ];
323
441
 
324
442
  // packages/plugins/plugin-thread/src/ThreadPlugin.tsx
443
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/plugins/plugin-thread/src/ThreadPlugin.tsx";
325
444
  var initialViewState = {
326
445
  showResolvedThreads: false
327
446
  };
328
- var providesThreadsConfig = (plugin) => "thread" in plugin.provides ? plugin : void 0;
329
447
  var ThreadPlugin = () => {
330
448
  const settings = new LocalStorageStore(THREAD_PLUGIN);
331
449
  const state = create2({
@@ -340,10 +458,8 @@ var ThreadPlugin = () => {
340
458
  }
341
459
  return viewStore[subjectId];
342
460
  };
343
- let attentionPlugin;
344
461
  let navigationPlugin;
345
462
  let intentPlugin;
346
- let dispatch;
347
463
  const unsubscribeCallbacks = [];
348
464
  return {
349
465
  meta: meta_default,
@@ -354,36 +470,8 @@ var ThreadPlugin = () => {
354
470
  allowUndefined: true
355
471
  })
356
472
  });
357
- attentionPlugin = resolvePlugin(plugins, parseAttentionPlugin);
358
473
  navigationPlugin = resolvePlugin(plugins, parseNavigationPlugin);
359
474
  intentPlugin = resolvePlugin(plugins, parseIntentPlugin);
360
- dispatch = intentPlugin?.provides.intent.dispatch;
361
- const graphPlugin = resolvePlugin(plugins, parseGraphPlugin);
362
- const client = resolvePlugin(plugins, parseClientPlugin)?.provides.client;
363
- if (!client) {
364
- return;
365
- }
366
- const channelsQuery = client.spaces.query(Filter.schema(ChannelType));
367
- const queryUnsubscribe = channelsQuery.subscribe();
368
- const unsubscribe = effect(() => {
369
- const attention = attentionPlugin?.provides.attention;
370
- if (!attention?.attended) {
371
- return;
372
- }
373
- const firstAttendedNodeWithComments = Array.from(attention.attended).map((id) => graphPlugin?.provides.graph.findNode(id)).find((node) => node?.data instanceof DocumentType && (node.data.threads?.length ?? 0) > 0);
374
- if (firstAttendedNodeWithComments) {
375
- void intentPlugin?.provides.intent.dispatch({
376
- action: NavigationAction.OPEN,
377
- data: {
378
- activeParts: {
379
- complementary: `${firstAttendedNodeWithComments.id}${SLUG_PATH_SEPARATOR}comments`
380
- }
381
- }
382
- });
383
- }
384
- });
385
- unsubscribeCallbacks.push(queryUnsubscribe);
386
- unsubscribeCallbacks.push(unsubscribe);
387
475
  },
388
476
  unload: async () => {
389
477
  unsubscribeCallbacks.forEach((unsubscribe) => unsubscribe());
@@ -399,8 +487,7 @@ var ThreadPlugin = () => {
399
487
  ns: THREAD_PLUGIN
400
488
  }
401
489
  ],
402
- icon: (props) => /* @__PURE__ */ React5.createElement(Chat, props),
403
- iconSymbol: "ph--chat--regular",
490
+ icon: "ph--chat--regular",
404
491
  // TODO(wittjosiah): Move out of metadata.
405
492
  loadReferences: (channel) => loadObjectReferences(channel, (channel2) => channel2.threads)
406
493
  },
@@ -447,9 +534,9 @@ var ThreadPlugin = () => {
447
534
  graph: {
448
535
  builder: (plugins) => {
449
536
  const client = resolvePlugin(plugins, parseClientPlugin)?.provides.client;
450
- const dispatch2 = resolvePlugin(plugins, parseIntentPlugin)?.provides.intent.dispatch;
537
+ const dispatch = resolvePlugin(plugins, parseIntentPlugin)?.provides.intent.dispatch;
451
538
  const metadataResolver = resolvePlugin(plugins, parseMetadataResolverPlugin)?.provides.metadata.resolver;
452
- if (!client || !dispatch2 || !metadataResolver) {
539
+ if (!client || !dispatch || !metadataResolver) {
453
540
  return [];
454
541
  }
455
542
  return [
@@ -459,27 +546,33 @@ var ThreadPlugin = () => {
459
546
  if (!id.endsWith("~comments")) {
460
547
  return;
461
548
  }
462
- const docId = id.split("~").at(0);
463
- const [spaceId, objectId] = docId?.split(":") ?? [];
549
+ const subjectId = id.split("~").at(0);
550
+ const [spaceId, objectId] = subjectId?.split(":") ?? [];
464
551
  const space = client.spaces.get().find((space2) => space2.id === spaceId);
465
- const doc = space?.db.getObjectById(objectId);
466
- if (!doc || !docId) {
552
+ const object = toSignal((onChange) => {
553
+ const timeout = setTimeout(async () => {
554
+ await space?.db.loadObjectById(objectId);
555
+ onChange();
556
+ });
557
+ return () => clearTimeout(timeout);
558
+ }, () => space?.db.getObjectById(objectId), subjectId);
559
+ if (!object || !subjectId) {
467
560
  return;
468
561
  }
469
- const docMeta = metadataResolver(getTypename(doc) ?? "");
470
- const label = docMeta.label?.(doc) || doc.name || docMeta.placeholder || [
562
+ const meta = metadataResolver(getTypename(object) ?? "");
563
+ const label = meta.label?.(object) || object.name || meta.placeholder || [
471
564
  "unnamed object threads label",
472
565
  {
473
566
  ns: THREAD_PLUGIN
474
567
  }
475
568
  ];
476
- const viewState = getViewState(docId);
569
+ const viewState = getViewState(subjectId);
477
570
  return {
478
571
  id,
479
572
  type: "orphan-comments-for-subject",
480
- data: doc,
573
+ data: object,
481
574
  properties: {
482
- icon: meta_default.iconComponent,
575
+ icon: meta.icon,
483
576
  label,
484
577
  showResolvedThreads: viewState.showResolvedThreads
485
578
  }
@@ -495,7 +588,7 @@ var ThreadPlugin = () => {
495
588
  const toggle = () => {
496
589
  const newToggleState = !viewState.showResolvedThreads;
497
590
  viewState.showResolvedThreads = newToggleState;
498
- void dispatch2({
591
+ void dispatch({
499
592
  action: ObservabilityAction.SEND_EVENT,
500
593
  data: {
501
594
  name: "threads.toggle-show-resolved",
@@ -520,7 +613,8 @@ var ThreadPlugin = () => {
520
613
  ],
521
614
  menuItemType: "toggle",
522
615
  isChecked: viewState.showResolvedThreads,
523
- testId: "threadPlugin.toggleShowResolved"
616
+ testId: "threadPlugin.toggleShowResolved",
617
+ icon: viewState.showResolvedThreads ? "ph--eye-slash--regular" : "ph--eye--regular"
524
618
  }
525
619
  }
526
620
  ];
@@ -542,7 +636,7 @@ var ThreadPlugin = () => {
542
636
  {
543
637
  id: `${THREAD_PLUGIN}/create/${node.id}`,
544
638
  data: async () => {
545
- await dispatch2([
639
+ await dispatch([
546
640
  {
547
641
  plugin: THREAD_PLUGIN,
548
642
  action: ThreadAction.CREATE
@@ -565,8 +659,7 @@ var ThreadPlugin = () => {
565
659
  ns: THREAD_PLUGIN
566
660
  }
567
661
  ],
568
- icon: (props) => /* @__PURE__ */ React5.createElement(Chat, props),
569
- iconSymbol: "ph--chat--regular",
662
+ icon: "ph--chat--regular",
570
663
  testId: "threadPlugin.createObject"
571
664
  }
572
665
  }
@@ -580,20 +673,18 @@ var ThreadPlugin = () => {
580
673
  component: ({ data, role }) => {
581
674
  switch (role) {
582
675
  case "main": {
583
- return data.active instanceof ChannelType && data.active.threads[0] ? /* @__PURE__ */ React5.createElement(ThreadMain, {
676
+ return data.active instanceof ChannelType && data.active.threads[0] ? /* @__PURE__ */ React6.createElement(ThreadMain, {
584
677
  thread: data.active.threads[0]
585
678
  }) : null;
586
679
  }
587
680
  case "settings": {
588
- return data.plugin === meta_default.id ? /* @__PURE__ */ React5.createElement(ThreadSettings, {
681
+ return data.plugin === meta_default.id ? /* @__PURE__ */ React6.createElement(ThreadSettings, {
589
682
  settings: settings.values
590
683
  }) : null;
591
684
  }
592
685
  case "article":
593
686
  case "complementary": {
594
687
  const location = navigationPlugin?.provides.location;
595
- const threadsIntegrators = useResolvePlugins(providesThreadsConfig);
596
- const threadProvides = threadsIntegrators.map((p) => p.provides.thread);
597
688
  if (data.object instanceof ChannelType && data.object.threads[0]) {
598
689
  const channel = data.object;
599
690
  if (isLayoutParts(location?.active) && location.active.main) {
@@ -602,101 +693,33 @@ var ThreadPlugin = () => {
602
693
  if (currentPosition > 0) {
603
694
  const objectToTheLeft = layoutEntries[currentPosition - 1];
604
695
  const context = getSpace2(data.object)?.db.getObjectById(objectToTheLeft.id);
605
- return /* @__PURE__ */ React5.createElement(ThreadArticle, {
696
+ return /* @__PURE__ */ React6.createElement(ThreadArticle, {
606
697
  thread: data.object.threads[0],
607
698
  context
608
699
  });
609
700
  }
610
701
  }
611
- return /* @__PURE__ */ React5.createElement(ThreadArticle, {
702
+ return /* @__PURE__ */ React6.createElement(ThreadArticle, {
612
703
  thread: data.object.threads[0]
613
704
  });
614
705
  }
615
706
  if (data.subject instanceof ThreadType) {
616
- return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(ChatHeading, {
707
+ return /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(ChatHeading, {
617
708
  attendableId: data.subject.id
618
- }), /* @__PURE__ */ React5.createElement(ChatContainer, {
709
+ }), /* @__PURE__ */ React6.createElement(ChatContainer, {
619
710
  thread: data.subject
620
711
  }));
621
712
  }
622
713
  if (data.subject && typeof data.subject === "object" && "threads" in data.subject && Array.isArray(data.subject.threads)) {
623
- const threads = data.subject.threads.concat(state.staging[fullyQualifiedId(data.subject)]).filter(nonNullable2);
624
- const createSort = threadProvides.find((p) => p.predicate(data.subject))?.createSort;
625
- if (createSort) {
626
- const sort = createSort(data.subject);
627
- threads.sort((a, b) => sort(a.anchor, b.anchor));
628
- }
629
- const detached = data.subject.threads.filter(nonNullable2).filter(({ anchor }) => !anchor).map((thread) => thread.id);
630
- const qualifiedSubjectId = fullyQualifiedId(data.subject);
631
- const attention = attentionPlugin?.provides.attention?.attended ?? /* @__PURE__ */ new Set([
632
- qualifiedSubjectId
633
- ]);
634
- const attendableAttrs = createAttendableAttributes(qualifiedSubjectId);
635
- const { showResolvedThreads } = getViewState(qualifiedSubjectId);
636
- return /* @__PURE__ */ React5.createElement("div", {
637
- role: "none",
638
- className: "contents group/attention",
639
- ...attendableAttrs
640
- }, role === "complementary" && /* @__PURE__ */ React5.createElement(CommentsHeading, {
641
- attendableId: qualifiedSubjectId
642
- }), /* @__PURE__ */ React5.createElement(ScrollArea.Root, {
643
- classNames: "row-span-2"
644
- }, /* @__PURE__ */ React5.createElement(ScrollArea.Viewport, null, /* @__PURE__ */ React5.createElement(CommentsContainer, {
645
- threads,
646
- detached,
647
- currentId: attention.has(qualifiedSubjectId) ? state.current : void 0,
648
- autoFocusCurrentTextbox: state.focus,
649
- showResolvedThreads,
650
- onThreadAttend: (thread) => {
651
- if (state.current !== thread.id) {
652
- state.current = thread.id;
653
- void dispatch?.({
654
- action: LayoutAction.SCROLL_INTO_VIEW,
655
- data: {
656
- id: fullyQualifiedId(data.subject),
657
- thread: fullyQualifiedId(thread),
658
- cursor: thread.anchor
659
- }
660
- });
661
- }
662
- },
663
- onThreadDelete: (thread) => dispatch?.({
664
- plugin: THREAD_PLUGIN,
665
- action: ThreadAction.DELETE,
666
- data: {
667
- subject: data.subject,
668
- thread
669
- }
670
- }),
671
- onMessageDelete: (thread, messageId) => dispatch?.({
672
- plugin: THREAD_PLUGIN,
673
- action: ThreadAction.DELETE_MESSAGE,
674
- data: {
675
- subject: data.subject,
676
- thread,
677
- messageId
678
- }
679
- }),
680
- onThreadToggleResolved: (thread) => dispatch?.({
681
- plugin: THREAD_PLUGIN,
682
- action: ThreadAction.TOGGLE_RESOLVED,
683
- data: {
684
- thread
685
- }
686
- }),
687
- onComment: (thread) => {
688
- void intentPlugin?.provides.intent.dispatch({
689
- action: ThreadAction.ON_MESSAGE_ADD,
690
- data: {
691
- thread,
692
- subject: data.subject
693
- }
694
- });
695
- }
696
- }), /* @__PURE__ */ React5.createElement("div", {
697
- role: "none",
698
- className: "bs-10"
699
- }), /* @__PURE__ */ React5.createElement(ScrollArea.Scrollbar, null, /* @__PURE__ */ React5.createElement(ScrollArea.Thumb, null)))));
714
+ const { showResolvedThreads } = getViewState(fullyQualifiedId4(data.subject));
715
+ return /* @__PURE__ */ React6.createElement(ThreadComplementary, {
716
+ role,
717
+ subject: data.subject,
718
+ stagedThreads: state.staging[fullyQualifiedId4(data.subject)],
719
+ current: state.current,
720
+ focus: true,
721
+ showResolvedThreads
722
+ });
700
723
  }
701
724
  }
702
725
  }
@@ -709,7 +732,20 @@ var ThreadPlugin = () => {
709
732
  case ThreadAction.CREATE: {
710
733
  if (intent.data && intent.data.cursor !== void 0) {
711
734
  const { cursor, name, subject } = intent.data;
712
- const subjectId = fullyQualifiedId(subject);
735
+ if (subject?.threads === void 0) {
736
+ try {
737
+ subject.threads = [];
738
+ } catch (e) {
739
+ log.error("Subject does not support threads array", subject?.typename, {
740
+ F: __dxlog_file,
741
+ L: 332,
742
+ S: void 0,
743
+ C: (f, a) => f(...a)
744
+ });
745
+ return;
746
+ }
747
+ }
748
+ const subjectId = fullyQualifiedId4(subject);
713
749
  const thread = create2(ThreadType, {
714
750
  name,
715
751
  anchor: cursor,
@@ -728,23 +764,15 @@ var ThreadPlugin = () => {
728
764
  data: thread,
729
765
  intents: [
730
766
  [
731
- {
732
- action: NavigationAction.OPEN,
733
- data: {
734
- activeParts: {
735
- complementary: `${subjectId}${SLUG_PATH_SEPARATOR}comments${SLUG_COLLECTION_INDICATOR}`
736
- }
737
- }
738
- },
739
767
  {
740
768
  action: ThreadAction.SELECT,
741
769
  data: {
742
- current: thread.id,
770
+ current: fullyQualifiedId4(thread),
743
771
  focus: true
744
772
  }
745
773
  },
746
774
  {
747
- action: LayoutAction.SET_LAYOUT,
775
+ action: LayoutAction2.SET_LAYOUT,
748
776
  data: {
749
777
  element: "complementary",
750
778
  subject: subjectId,
@@ -804,16 +832,18 @@ var ThreadPlugin = () => {
804
832
  }
805
833
  case ThreadAction.DELETE: {
806
834
  const { subject, thread } = intent.data ?? {};
807
- if (!(subject instanceof DocumentType) || !(thread instanceof ThreadType)) {
835
+ if (!(thread instanceof ThreadType) || !(subject && typeof subject === "object" && "threads" in subject)) {
808
836
  return;
809
837
  }
810
- const subjectId = fullyQualifiedId(subject);
838
+ const subjectId = fullyQualifiedId4(subject);
811
839
  const stagingArea = state.staging[subjectId];
812
840
  if (stagingArea) {
813
841
  const index = stagingArea.findIndex((t) => t.id === thread.id);
814
842
  if (index !== -1) {
815
843
  stagingArea.splice(index, 1);
816
- return;
844
+ return {
845
+ data: true
846
+ };
817
847
  }
818
848
  }
819
849
  const space = getSpace2(thread);
@@ -874,10 +904,10 @@ var ThreadPlugin = () => {
874
904
  }
875
905
  case ThreadAction.ON_MESSAGE_ADD: {
876
906
  const { thread, subject } = intent.data ?? {};
877
- if (!(thread instanceof ThreadType) || !(subject && typeof subject === "object" && "threads" in subject)) {
907
+ if (!(thread instanceof ThreadType) || !(subject && typeof subject === "object" && "threads" in subject && Array.isArray(subject.threads))) {
878
908
  return;
879
909
  }
880
- const subjectId = fullyQualifiedId(subject);
910
+ const subjectId = fullyQualifiedId4(subject);
881
911
  const space = getSpace2(subject);
882
912
  const intents = [];
883
913
  const analyticsProperties = {
@@ -918,7 +948,7 @@ var ThreadPlugin = () => {
918
948
  case ThreadAction.DELETE_MESSAGE: {
919
949
  const { subject, thread, messageId } = intent.data ?? {};
920
950
  const space = getSpace2(subject);
921
- if (!(subject instanceof DocumentType) || !(thread instanceof ThreadType) || !space) {
951
+ if (!(thread instanceof ThreadType) || !(subject && typeof subject === "object" && "threads" in subject)) {
922
952
  return;
923
953
  }
924
954
  if (!intent.undo) {
@@ -960,7 +990,7 @@ var ThreadPlugin = () => {
960
990
  name: "threads.message.delete",
961
991
  properties: {
962
992
  threadId: thread.id,
963
- spaceId: space.id
993
+ spaceId: space?.id
964
994
  }
965
995
  }
966
996
  }
@@ -984,7 +1014,7 @@ var ThreadPlugin = () => {
984
1014
  name: "threads.message.undo-delete",
985
1015
  properties: {
986
1016
  threadId: thread.id,
987
- spaceId: space.id
1017
+ spaceId: space?.id
988
1018
  }
989
1019
  }
990
1020
  }
@@ -1006,8 +1036,8 @@ var ThreadPlugin = () => {
1006
1036
  ];
1007
1037
  }
1008
1038
  const threads = computed(() => [
1009
- ...doc.threads.filter(nonNullable2),
1010
- ...state.staging[fullyQualifiedId(doc)] ?? []
1039
+ ...doc.threads.filter(nonNullable3),
1040
+ ...state.staging[fullyQualifiedId4(doc)] ?? []
1011
1041
  ].filter((thread) => !(thread?.status === "resolved")));
1012
1042
  return [
1013
1043
  listener2({
@@ -1026,7 +1056,7 @@ var ThreadPlugin = () => {
1026
1056
  }
1027
1057
  }),
1028
1058
  createExternalCommentSync(doc.id, (sink) => effect(() => sink()), () => threads.value.filter((thread) => thread?.anchor).map((thread) => ({
1029
- id: thread.id,
1059
+ id: fullyQualifiedId4(thread),
1030
1060
  cursor: thread.anchor
1031
1061
  }))),
1032
1062
  comments({
@@ -1046,9 +1076,9 @@ var ThreadPlugin = () => {
1046
1076
  });
1047
1077
  },
1048
1078
  onDelete: ({ id }) => {
1049
- const stagingArea = state.staging[fullyQualifiedId(doc)];
1079
+ const stagingArea = state.staging[fullyQualifiedId4(doc)];
1050
1080
  if (stagingArea) {
1051
- const index = stagingArea.findIndex((thread2) => thread2.id === id);
1081
+ const index = stagingArea.findIndex((thread2) => fullyQualifiedId4(thread2) === id);
1052
1082
  if (index !== -1) {
1053
1083
  stagingArea.splice(index, 1);
1054
1084
  }
@@ -1059,7 +1089,7 @@ var ThreadPlugin = () => {
1059
1089
  }
1060
1090
  },
1061
1091
  onUpdate: ({ id, cursor }) => {
1062
- const thread = state.staging[fullyQualifiedId(doc)]?.find((thread2) => thread2.id === id) ?? doc.threads.find((thread2) => thread2?.id === id);
1092
+ const thread = state.staging[fullyQualifiedId4(doc)]?.find((thread2) => fullyQualifiedId4(thread2) === id) ?? doc.threads.find((thread2) => thread2?.id === id);
1063
1093
  if (thread instanceof ThreadType && thread.anchor) {
1064
1094
  const [start, end] = thread.anchor.split(":");
1065
1095
  thread.name = doc.content && getTextInRange(createDocAccessor(doc.content, [
@@ -1069,9 +1099,9 @@ var ThreadPlugin = () => {
1069
1099
  }
1070
1100
  },
1071
1101
  onSelect: ({ selection: { current, closest } }) => {
1072
- const dispatch2 = intentPlugin?.provides.intent.dispatch;
1073
- if (dispatch2) {
1074
- void dispatch2([
1102
+ const dispatch = intentPlugin?.provides.intent.dispatch;
1103
+ if (dispatch) {
1104
+ void dispatch([
1075
1105
  {
1076
1106
  action: ThreadAction.SELECT,
1077
1107
  data: {