@dxos/plugin-thread 0.6.10 → 0.6.11-staging.e6894a4

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.
@@ -9,6 +9,7 @@ var ThreadAction;
9
9
  ThreadAction2[ThreadAction2["CREATE"] = `${THREAD_ACTION}/create`] = "CREATE";
10
10
  ThreadAction2[ThreadAction2["SELECT"] = `${THREAD_ACTION}/select`] = "SELECT";
11
11
  ThreadAction2[ThreadAction2["DELETE"] = `${THREAD_ACTION}/delete`] = "DELETE";
12
+ ThreadAction2[ThreadAction2["ON_MESSAGE_ADD"] = `${THREAD_ACTION}/on-message-add`] = "ON_MESSAGE_ADD";
12
13
  ThreadAction2[ThreadAction2["DELETE_MESSAGE"] = `${THREAD_ACTION}/delete-message`] = "DELETE_MESSAGE";
13
14
  ThreadAction2[ThreadAction2["TOGGLE_RESOLVED"] = `${THREAD_ACTION}/toggle-resolved`] = "TOGGLE_RESOLVED";
14
15
  })(ThreadAction || (ThreadAction = {}));
@@ -16,4 +17,4 @@ var ThreadAction;
16
17
  export {
17
18
  ThreadAction
18
19
  };
19
- //# sourceMappingURL=chunk-TL3JITN7.mjs.map
20
+ //# sourceMappingURL=chunk-GKPZHUT3.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/types.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport type {\n GraphBuilderProvides,\n IntentResolverProvides,\n MetadataRecordsProvides,\n SettingsProvides,\n SurfaceProvides,\n TranslationsProvides,\n} from '@dxos/app-framework';\nimport { type SchemaProvides } from '@dxos/plugin-client';\nimport { type MarkdownExtensionProvides } from '@dxos/plugin-markdown';\nimport { type ThreadType } from '@dxos/plugin-space/types';\n\nimport { THREAD_PLUGIN } from './meta';\n\nconst THREAD_ACTION = `${THREAD_PLUGIN}/action`;\nexport enum ThreadAction {\n CREATE = `${THREAD_ACTION}/create`,\n SELECT = `${THREAD_ACTION}/select`,\n DELETE = `${THREAD_ACTION}/delete`,\n ON_MESSAGE_ADD = `${THREAD_ACTION}/on-message-add`,\n DELETE_MESSAGE = `${THREAD_ACTION}/delete-message`,\n TOGGLE_RESOLVED = `${THREAD_ACTION}/toggle-resolved`,\n}\n\n// TODO(Zan): Move this to the plugin-space plugin or another common location\n// when we implement threads in sheets.\nexport type ThreadProvides<T> = {\n thread: {\n predicate: (obj: any) => obj is T;\n createSort: (obj: T) => (anchorA: string, anchorB: string) => number;\n };\n};\n\nexport type ThreadPluginProvides = SurfaceProvides &\n IntentResolverProvides &\n GraphBuilderProvides &\n MetadataRecordsProvides &\n SettingsProvides &\n TranslationsProvides &\n SchemaProvides &\n MarkdownExtensionProvides;\n\nexport type ThreadSettingsProps = { standalone?: boolean };\n\nexport interface ThreadModel {\n root: ThreadType;\n}\n"],
5
+ "mappings": ";;;;;AAkBA,IAAMA,gBAAgB,GAAGC,aAAAA;;UACbC,eAAAA;0CACD,GAAGF,aAAAA,SAAsB,IAAA;0CACzB,GAAGA,aAAAA,SAAsB,IAAA;0CACzB,GAAGA,aAAAA,SAAsB,IAAA;kDACjB,GAAGA,aAAAA,iBAA8B,IAAA;kDACjC,GAAGA,aAAAA,iBAA8B,IAAA;mDAChC,GAAGA,aAAAA,kBAA+B,IAAA;GAN1CE,iBAAAA,eAAAA,CAAAA,EAAAA;",
6
+ "names": ["THREAD_ACTION", "THREAD_PLUGIN", "ThreadAction"]
7
+ }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ThreadAction
3
- } from "./chunk-TL3JITN7.mjs";
3
+ } from "./chunk-GKPZHUT3.mjs";
4
4
  import {
5
5
  ChatContainer,
6
6
  ChatHeading,
@@ -20,8 +20,8 @@ import {
20
20
  // packages/plugins/plugin-thread/src/ThreadPlugin.tsx
21
21
  import { Chat } from "@phosphor-icons/react";
22
22
  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 } from "@dxos/app-framework";
23
+ import React5, { useCallback as useCallback2 } from "react";
24
+ import { LayoutAction, NavigationAction, parseIntentPlugin, parseNavigationPlugin, resolvePlugin, parseGraphPlugin, SLUG_PATH_SEPARATOR, SLUG_COLLECTION_INDICATOR, isLayoutParts, parseMetadataResolverPlugin, useResolvePlugins } from "@dxos/app-framework";
25
25
  import { getTypename } from "@dxos/echo-schema";
26
26
  import { create as create2 } from "@dxos/echo-schema";
27
27
  import { LocalStorageStore } from "@dxos/local-storage";
@@ -32,7 +32,7 @@ import { DocumentType } from "@dxos/plugin-markdown/types";
32
32
  import { ObservabilityAction } from "@dxos/plugin-observability/meta";
33
33
  import { SpaceAction } from "@dxos/plugin-space";
34
34
  import { ThreadType, MessageType as MessageType2, ChannelType } from "@dxos/plugin-space/types";
35
- import { getSpace as getSpace2, getTextInRange, Filter, createDocAccessor, fullyQualifiedId, getRangeFromCursor, loadObjectReferences } from "@dxos/react-client/echo";
35
+ import { getSpace as getSpace2, getTextInRange, Filter, createDocAccessor, fullyQualifiedId, loadObjectReferences } from "@dxos/react-client/echo";
36
36
  import { ScrollArea } from "@dxos/react-ui";
37
37
  import { createAttendableAttributes } from "@dxos/react-ui-attention";
38
38
  import { comments, createExternalCommentSync, listener as listener2 } from "@dxos/react-ui-editor";
@@ -591,6 +591,12 @@ var ThreadPlugin = () => {
591
591
  case "article":
592
592
  case "complementary": {
593
593
  const location = navigationPlugin?.provides.location;
594
+ const providesThreadsConfig = useCallback2((plugin) => (
595
+ // TODO(Zan): More robust runtime check.
596
+ "thread" in plugin.provides ? plugin : void 0
597
+ ), []);
598
+ const threadsIntegrators = useResolvePlugins(providesThreadsConfig);
599
+ const threadProvides = threadsIntegrators.map((p) => p.provides.thread);
594
600
  if (data.object instanceof ChannelType && data.object.threads[0]) {
595
601
  const channel = data.object;
596
602
  if (isLayoutParts(location?.active) && location.active.main) {
@@ -609,39 +615,27 @@ var ThreadPlugin = () => {
609
615
  thread: data.object.threads[0]
610
616
  });
611
617
  }
612
- if (data.subject instanceof DocumentType) {
613
- const doc = data.subject;
614
- const accessor = doc.content ? createDocAccessor(doc.content, [
615
- "content"
616
- ]) : void 0;
617
- if (!accessor) {
618
- return null;
618
+ if (data.subject instanceof ThreadType) {
619
+ return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(ChatHeading, {
620
+ attendableId: data.subject.id
621
+ }), /* @__PURE__ */ React5.createElement(ChatContainer, {
622
+ thread: data.subject
623
+ }));
624
+ }
625
+ if (data.subject && typeof data.subject === "object" && "threads" in data.subject && Array.isArray(data.subject.threads)) {
626
+ const threads = data.subject.threads.concat(state.staging[fullyQualifiedId(data.subject)]).filter(nonNullable2);
627
+ const createSort = threadProvides.find((p) => p.predicate(data.subject))?.createSort;
628
+ if (createSort) {
629
+ const sort = createSort(data.subject);
630
+ threads.sort((a, b) => sort(a.anchor, b.anchor));
619
631
  }
620
- const getStartPosition = (cursor) => {
621
- const range = cursor ? getRangeFromCursor(accessor, cursor) : void 0;
622
- return range?.start ?? Number.MAX_SAFE_INTEGER;
623
- };
624
- const threads = doc.threads.concat(state.staging[data.subject.id]).filter(nonNullable2).sort((a, b) => getStartPosition(a.anchor) - getStartPosition(b.anchor));
625
632
  const detached = data.subject.threads.filter(nonNullable2).filter(({ anchor }) => !anchor).map((thread) => thread.id);
626
- const qualifiedSubjectId = fullyQualifiedId(doc);
633
+ const qualifiedSubjectId = fullyQualifiedId(data.subject);
627
634
  const attention = attentionPlugin?.provides.attention?.attended ?? /* @__PURE__ */ new Set([
628
635
  qualifiedSubjectId
629
636
  ]);
630
637
  const attendableAttrs = createAttendableAttributes(qualifiedSubjectId);
631
- const space = getSpace2(doc);
632
638
  const { showResolvedThreads } = getViewState(qualifiedSubjectId);
633
- const dispatchAnalytic = (name, meta) => {
634
- void dispatch?.({
635
- action: ObservabilityAction.SEND_EVENT,
636
- data: {
637
- name,
638
- properties: {
639
- ...meta,
640
- space: space?.id
641
- }
642
- }
643
- });
644
- };
645
639
  return /* @__PURE__ */ React5.createElement("div", {
646
640
  role: "none",
647
641
  className: "contents group/attention",
@@ -673,7 +667,7 @@ var ThreadPlugin = () => {
673
667
  plugin: THREAD_PLUGIN,
674
668
  action: ThreadAction.DELETE,
675
669
  data: {
676
- document: data.subject,
670
+ subject: data.subject,
677
671
  thread
678
672
  }
679
673
  }),
@@ -681,7 +675,7 @@ var ThreadPlugin = () => {
681
675
  plugin: THREAD_PLUGIN,
682
676
  action: ThreadAction.DELETE_MESSAGE,
683
677
  data: {
684
- document: data.subject,
678
+ subject: data.subject,
685
679
  thread,
686
680
  messageId
687
681
  }
@@ -694,32 +688,18 @@ var ThreadPlugin = () => {
694
688
  }
695
689
  }),
696
690
  onComment: (thread) => {
697
- const doc2 = data.subject;
698
- if (state.staging[doc2.id]?.find((t) => t === thread)) {
699
- thread.status = "active";
700
- doc2.threads ? doc2.threads.push(thread) : doc2.threads = [
701
- thread
702
- ];
703
- state.staging[doc2.id] = state.staging[doc2.id]?.filter((t) => t.id !== thread.id);
704
- dispatchAnalytic("threads.thread-created", {
705
- threadId: thread.id
706
- });
707
- }
708
- dispatchAnalytic("threads.message-added", {
709
- threadId: thread.id,
710
- threadLength: thread.messages.length
691
+ void intentPlugin?.provides.intent.dispatch({
692
+ action: ThreadAction.ON_MESSAGE_ADD,
693
+ data: {
694
+ thread,
695
+ subject: data.subject
696
+ }
711
697
  });
712
698
  }
713
699
  }), /* @__PURE__ */ React5.createElement("div", {
714
700
  role: "none",
715
701
  className: "bs-10"
716
702
  }), /* @__PURE__ */ React5.createElement(ScrollArea.Scrollbar, null, /* @__PURE__ */ React5.createElement(ScrollArea.Thumb, null)))));
717
- } else if (data.subject instanceof ThreadType) {
718
- return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(ChatHeading, {
719
- attendableId: data.subject.id
720
- }), /* @__PURE__ */ React5.createElement(ChatContainer, {
721
- thread: data.subject
722
- }));
723
703
  }
724
704
  }
725
705
  }
@@ -730,15 +710,64 @@ var ThreadPlugin = () => {
730
710
  resolver: async (intent) => {
731
711
  switch (intent.action) {
732
712
  case ThreadAction.CREATE: {
733
- return {
734
- data: create2(ChannelType, {
735
- threads: [
736
- create2(ThreadType, {
737
- messages: []
738
- })
713
+ if (intent.data && intent.data.cursor !== void 0) {
714
+ const { cursor, name, subject } = intent.data;
715
+ const subjectId = fullyQualifiedId(subject);
716
+ const thread = create2(ThreadType, {
717
+ name,
718
+ anchor: cursor,
719
+ messages: [],
720
+ status: "staged"
721
+ });
722
+ const stagingArea = state.staging[subjectId];
723
+ if (stagingArea) {
724
+ stagingArea.push(thread);
725
+ } else {
726
+ state.staging[subjectId] = [
727
+ thread
728
+ ];
729
+ }
730
+ return {
731
+ data: thread,
732
+ intents: [
733
+ [
734
+ {
735
+ action: NavigationAction.OPEN,
736
+ data: {
737
+ activeParts: {
738
+ complementary: `${subjectId}${SLUG_PATH_SEPARATOR}comments${SLUG_COLLECTION_INDICATOR}`
739
+ }
740
+ }
741
+ },
742
+ {
743
+ action: ThreadAction.SELECT,
744
+ data: {
745
+ current: thread.id,
746
+ focus: true
747
+ }
748
+ },
749
+ {
750
+ action: LayoutAction.SET_LAYOUT,
751
+ data: {
752
+ element: "complementary",
753
+ subject: subjectId,
754
+ state: true
755
+ }
756
+ }
757
+ ]
739
758
  ]
740
- })
741
- };
759
+ };
760
+ } else {
761
+ return {
762
+ data: create2(ChannelType, {
763
+ threads: [
764
+ create2(ThreadType, {
765
+ messages: []
766
+ })
767
+ ]
768
+ })
769
+ };
770
+ }
742
771
  }
743
772
  case ThreadAction.SELECT: {
744
773
  state.focus = intent.data?.current === state.current ? state.focus : intent.data?.focus;
@@ -777,27 +806,28 @@ var ThreadPlugin = () => {
777
806
  };
778
807
  }
779
808
  case ThreadAction.DELETE: {
780
- const { document: doc, thread } = intent.data ?? {};
781
- if (!(doc instanceof DocumentType) || !(thread instanceof ThreadType)) {
809
+ const { subject, thread } = intent.data ?? {};
810
+ if (!(subject instanceof DocumentType) || !(thread instanceof ThreadType)) {
782
811
  return;
783
812
  }
784
- const stagingArea = state.staging[doc.id];
813
+ const subjectId = fullyQualifiedId(subject);
814
+ const stagingArea = state.staging[subjectId];
785
815
  if (stagingArea) {
786
- const index = state.staging[doc.id]?.findIndex((t) => t.id === thread.id);
816
+ const index = stagingArea.findIndex((t) => t.id === thread.id);
787
817
  if (index !== -1) {
788
- state.staging[doc.id]?.splice(index, 1);
818
+ stagingArea.splice(index, 1);
789
819
  return;
790
820
  }
791
821
  }
792
822
  const space = getSpace2(thread);
793
- if (!space || !doc.threads) {
823
+ if (!space || !subject.threads) {
794
824
  return;
795
825
  }
796
826
  if (!intent.undo) {
797
- const index = doc.threads.findIndex((t) => t?.id === thread.id);
798
- const cursor = doc.threads[index]?.anchor;
827
+ const index = subject.threads.findIndex((t) => t?.id === thread.id);
828
+ const cursor = subject.threads[index]?.anchor;
799
829
  if (index !== -1) {
800
- doc.threads?.splice(index, 1);
830
+ subject.threads?.splice(index, 1);
801
831
  }
802
832
  space.db.remove(thread);
803
833
  return {
@@ -824,7 +854,7 @@ var ThreadPlugin = () => {
824
854
  };
825
855
  } else if (intent.undo) {
826
856
  const savedThread = space.db.add(thread);
827
- doc.threads.push(savedThread);
857
+ subject.threads.push(savedThread);
828
858
  return {
829
859
  data: true,
830
860
  intents: [
@@ -845,10 +875,53 @@ var ThreadPlugin = () => {
845
875
  }
846
876
  break;
847
877
  }
878
+ case ThreadAction.ON_MESSAGE_ADD: {
879
+ const { thread, subject } = intent.data ?? {};
880
+ if (!(thread instanceof ThreadType) || !(subject && typeof subject === "object" && "threads" in subject)) {
881
+ return;
882
+ }
883
+ const subjectId = fullyQualifiedId(subject);
884
+ const space = getSpace2(subject);
885
+ const intents = [];
886
+ const analyticsProperties = {
887
+ threadId: thread.id,
888
+ spaceId: space?.id
889
+ };
890
+ if (state.staging[subjectId]?.find((t) => t === thread)) {
891
+ thread.status = "active";
892
+ subject.threads ? subject.threads.push(thread) : subject.threads = [
893
+ thread
894
+ ];
895
+ state.staging[subjectId] = state.staging[subjectId]?.filter((t) => t.id !== thread.id);
896
+ intents.push({
897
+ action: ObservabilityAction.SEND_EVENT,
898
+ data: {
899
+ name: "threads.thread-created",
900
+ properties: analyticsProperties
901
+ }
902
+ });
903
+ }
904
+ intents.push({
905
+ action: ObservabilityAction.SEND_EVENT,
906
+ data: {
907
+ name: "threads.message-added",
908
+ properties: {
909
+ ...analyticsProperties,
910
+ threadLength: thread.messages.length
911
+ }
912
+ }
913
+ });
914
+ return {
915
+ data: thread,
916
+ intents: [
917
+ intents
918
+ ]
919
+ };
920
+ }
848
921
  case ThreadAction.DELETE_MESSAGE: {
849
- const { document: doc, thread, messageId } = intent.data ?? {};
850
- const space = getSpace2(doc);
851
- if (!(doc instanceof DocumentType) || !(thread instanceof ThreadType) || !space) {
922
+ const { subject, thread, messageId } = intent.data ?? {};
923
+ const space = getSpace2(subject);
924
+ if (!(subject instanceof DocumentType) || !(thread instanceof ThreadType) || !space) {
852
925
  return;
853
926
  }
854
927
  if (!intent.undo) {
@@ -864,7 +937,7 @@ var ThreadPlugin = () => {
864
937
  {
865
938
  action: ThreadAction.DELETE,
866
939
  data: {
867
- document: doc,
940
+ subject,
868
941
  thread
869
942
  }
870
943
  }
@@ -937,7 +1010,7 @@ var ThreadPlugin = () => {
937
1010
  }
938
1011
  const threads = computed(() => [
939
1012
  ...doc.threads.filter(nonNullable2),
940
- ...state.staging[doc.id] ?? []
1013
+ ...state.staging[fullyQualifiedId(doc)] ?? []
941
1014
  ].filter((thread) => !(thread?.status === "resolved")));
942
1015
  return [
943
1016
  listener2({
@@ -966,49 +1039,17 @@ var ThreadPlugin = () => {
966
1039
  const name = doc.content && getTextInRange(createDocAccessor(doc.content, [
967
1040
  "content"
968
1041
  ]), start, end);
969
- const thread = create2(ThreadType, {
970
- name,
971
- anchor: cursor,
972
- messages: [],
973
- status: "staged"
974
- });
975
- const stagingArea = state.staging[doc.id];
976
- if (stagingArea) {
977
- stagingArea.push(thread);
978
- } else {
979
- state.staging[doc.id] = [
980
- thread
981
- ];
982
- }
983
- void intentPlugin?.provides.intent.dispatch([
984
- {
985
- action: NavigationAction.OPEN,
986
- data: {
987
- activeParts: {
988
- complementary: `${fullyQualifiedId(doc)}${SLUG_PATH_SEPARATOR}comments${SLUG_COLLECTION_INDICATOR}`
989
- }
990
- }
991
- },
992
- {
993
- action: ThreadAction.SELECT,
994
- data: {
995
- current: thread.id,
996
- focus: true
997
- }
998
- },
999
- {
1000
- action: LayoutAction.SET_LAYOUT,
1001
- data: {
1002
- element: "complementary",
1003
- subject: doc,
1004
- state: true
1005
- }
1042
+ void intentPlugin?.provides.intent.dispatch({
1043
+ action: ThreadAction.CREATE,
1044
+ data: {
1045
+ cursor,
1046
+ name,
1047
+ subject: doc
1006
1048
  }
1007
- ]);
1008
- return thread.id;
1049
+ });
1009
1050
  },
1010
1051
  onDelete: ({ id }) => {
1011
- const stagingArea = state.staging[doc.id];
1052
+ const stagingArea = state.staging[fullyQualifiedId(doc)];
1012
1053
  if (stagingArea) {
1013
1054
  const index = stagingArea.findIndex((thread2) => thread2.id === id);
1014
1055
  if (index !== -1) {
@@ -1021,7 +1062,7 @@ var ThreadPlugin = () => {
1021
1062
  }
1022
1063
  },
1023
1064
  onUpdate: ({ id, cursor }) => {
1024
- const thread = state.staging[doc.id]?.find((thread2) => thread2.id === id) ?? doc.threads.find((thread2) => thread2?.id === id);
1065
+ const thread = state.staging[fullyQualifiedId(doc)]?.find((thread2) => thread2.id === id) ?? doc.threads.find((thread2) => thread2?.id === id);
1025
1066
  if (thread instanceof ThreadType && thread.anchor) {
1026
1067
  const [start, end] = thread.anchor.split(":");
1027
1068
  thread.name = doc.content && getTextInRange(createDocAccessor(doc.content, [