@dxos/plugin-thread 0.6.10 → 0.6.11-staging.32b42e4

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,
@@ -21,7 +21,7 @@ import {
21
21
  import { Chat } from "@phosphor-icons/react";
22
22
  import { computed, effect } from "@preact/signals-core";
23
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";
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";
@@ -325,6 +325,7 @@ var translations_default = [
325
325
  var initialViewState = {
326
326
  showResolvedThreads: false
327
327
  };
328
+ var providesThreadsConfig = (plugin) => "thread" in plugin.provides ? plugin : void 0;
328
329
  var ThreadPlugin = () => {
329
330
  const settings = new LocalStorageStore(THREAD_PLUGIN);
330
331
  const state = create2({
@@ -591,6 +592,8 @@ var ThreadPlugin = () => {
591
592
  case "article":
592
593
  case "complementary": {
593
594
  const location = navigationPlugin?.provides.location;
595
+ const threadsIntegrators = useResolvePlugins(providesThreadsConfig);
596
+ const threadProvides = threadsIntegrators.map((p) => p.provides.thread);
594
597
  if (data.object instanceof ChannelType && data.object.threads[0]) {
595
598
  const channel = data.object;
596
599
  if (isLayoutParts(location?.active) && location.active.main) {
@@ -609,39 +612,27 @@ var ThreadPlugin = () => {
609
612
  thread: data.object.threads[0]
610
613
  });
611
614
  }
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;
615
+ if (data.subject instanceof ThreadType) {
616
+ return /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(ChatHeading, {
617
+ attendableId: data.subject.id
618
+ }), /* @__PURE__ */ React5.createElement(ChatContainer, {
619
+ thread: data.subject
620
+ }));
621
+ }
622
+ 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));
619
628
  }
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
629
  const detached = data.subject.threads.filter(nonNullable2).filter(({ anchor }) => !anchor).map((thread) => thread.id);
626
- const qualifiedSubjectId = fullyQualifiedId(doc);
630
+ const qualifiedSubjectId = fullyQualifiedId(data.subject);
627
631
  const attention = attentionPlugin?.provides.attention?.attended ?? /* @__PURE__ */ new Set([
628
632
  qualifiedSubjectId
629
633
  ]);
630
634
  const attendableAttrs = createAttendableAttributes(qualifiedSubjectId);
631
- const space = getSpace2(doc);
632
635
  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
636
  return /* @__PURE__ */ React5.createElement("div", {
646
637
  role: "none",
647
638
  className: "contents group/attention",
@@ -673,7 +664,7 @@ var ThreadPlugin = () => {
673
664
  plugin: THREAD_PLUGIN,
674
665
  action: ThreadAction.DELETE,
675
666
  data: {
676
- document: data.subject,
667
+ subject: data.subject,
677
668
  thread
678
669
  }
679
670
  }),
@@ -681,7 +672,7 @@ var ThreadPlugin = () => {
681
672
  plugin: THREAD_PLUGIN,
682
673
  action: ThreadAction.DELETE_MESSAGE,
683
674
  data: {
684
- document: data.subject,
675
+ subject: data.subject,
685
676
  thread,
686
677
  messageId
687
678
  }
@@ -694,32 +685,18 @@ var ThreadPlugin = () => {
694
685
  }
695
686
  }),
696
687
  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
688
+ void intentPlugin?.provides.intent.dispatch({
689
+ action: ThreadAction.ON_MESSAGE_ADD,
690
+ data: {
691
+ thread,
692
+ subject: data.subject
693
+ }
711
694
  });
712
695
  }
713
696
  }), /* @__PURE__ */ React5.createElement("div", {
714
697
  role: "none",
715
698
  className: "bs-10"
716
699
  }), /* @__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
700
  }
724
701
  }
725
702
  }
@@ -730,15 +707,64 @@ var ThreadPlugin = () => {
730
707
  resolver: async (intent) => {
731
708
  switch (intent.action) {
732
709
  case ThreadAction.CREATE: {
733
- return {
734
- data: create2(ChannelType, {
735
- threads: [
736
- create2(ThreadType, {
737
- messages: []
738
- })
710
+ if (intent.data && intent.data.cursor !== void 0) {
711
+ const { cursor, name, subject } = intent.data;
712
+ const subjectId = fullyQualifiedId(subject);
713
+ const thread = create2(ThreadType, {
714
+ name,
715
+ anchor: cursor,
716
+ messages: [],
717
+ status: "staged"
718
+ });
719
+ const stagingArea = state.staging[subjectId];
720
+ if (stagingArea) {
721
+ stagingArea.push(thread);
722
+ } else {
723
+ state.staging[subjectId] = [
724
+ thread
725
+ ];
726
+ }
727
+ return {
728
+ data: thread,
729
+ intents: [
730
+ [
731
+ {
732
+ action: NavigationAction.OPEN,
733
+ data: {
734
+ activeParts: {
735
+ complementary: `${subjectId}${SLUG_PATH_SEPARATOR}comments${SLUG_COLLECTION_INDICATOR}`
736
+ }
737
+ }
738
+ },
739
+ {
740
+ action: ThreadAction.SELECT,
741
+ data: {
742
+ current: thread.id,
743
+ focus: true
744
+ }
745
+ },
746
+ {
747
+ action: LayoutAction.SET_LAYOUT,
748
+ data: {
749
+ element: "complementary",
750
+ subject: subjectId,
751
+ state: true
752
+ }
753
+ }
754
+ ]
739
755
  ]
740
- })
741
- };
756
+ };
757
+ } else {
758
+ return {
759
+ data: create2(ChannelType, {
760
+ threads: [
761
+ create2(ThreadType, {
762
+ messages: []
763
+ })
764
+ ]
765
+ })
766
+ };
767
+ }
742
768
  }
743
769
  case ThreadAction.SELECT: {
744
770
  state.focus = intent.data?.current === state.current ? state.focus : intent.data?.focus;
@@ -777,27 +803,28 @@ var ThreadPlugin = () => {
777
803
  };
778
804
  }
779
805
  case ThreadAction.DELETE: {
780
- const { document: doc, thread } = intent.data ?? {};
781
- if (!(doc instanceof DocumentType) || !(thread instanceof ThreadType)) {
806
+ const { subject, thread } = intent.data ?? {};
807
+ if (!(subject instanceof DocumentType) || !(thread instanceof ThreadType)) {
782
808
  return;
783
809
  }
784
- const stagingArea = state.staging[doc.id];
810
+ const subjectId = fullyQualifiedId(subject);
811
+ const stagingArea = state.staging[subjectId];
785
812
  if (stagingArea) {
786
- const index = state.staging[doc.id]?.findIndex((t) => t.id === thread.id);
813
+ const index = stagingArea.findIndex((t) => t.id === thread.id);
787
814
  if (index !== -1) {
788
- state.staging[doc.id]?.splice(index, 1);
815
+ stagingArea.splice(index, 1);
789
816
  return;
790
817
  }
791
818
  }
792
819
  const space = getSpace2(thread);
793
- if (!space || !doc.threads) {
820
+ if (!space || !subject.threads) {
794
821
  return;
795
822
  }
796
823
  if (!intent.undo) {
797
- const index = doc.threads.findIndex((t) => t?.id === thread.id);
798
- const cursor = doc.threads[index]?.anchor;
824
+ const index = subject.threads.findIndex((t) => t?.id === thread.id);
825
+ const cursor = subject.threads[index]?.anchor;
799
826
  if (index !== -1) {
800
- doc.threads?.splice(index, 1);
827
+ subject.threads?.splice(index, 1);
801
828
  }
802
829
  space.db.remove(thread);
803
830
  return {
@@ -824,7 +851,7 @@ var ThreadPlugin = () => {
824
851
  };
825
852
  } else if (intent.undo) {
826
853
  const savedThread = space.db.add(thread);
827
- doc.threads.push(savedThread);
854
+ subject.threads.push(savedThread);
828
855
  return {
829
856
  data: true,
830
857
  intents: [
@@ -845,10 +872,53 @@ var ThreadPlugin = () => {
845
872
  }
846
873
  break;
847
874
  }
875
+ case ThreadAction.ON_MESSAGE_ADD: {
876
+ const { thread, subject } = intent.data ?? {};
877
+ if (!(thread instanceof ThreadType) || !(subject && typeof subject === "object" && "threads" in subject)) {
878
+ return;
879
+ }
880
+ const subjectId = fullyQualifiedId(subject);
881
+ const space = getSpace2(subject);
882
+ const intents = [];
883
+ const analyticsProperties = {
884
+ threadId: thread.id,
885
+ spaceId: space?.id
886
+ };
887
+ if (state.staging[subjectId]?.find((t) => t === thread)) {
888
+ thread.status = "active";
889
+ subject.threads ? subject.threads.push(thread) : subject.threads = [
890
+ thread
891
+ ];
892
+ state.staging[subjectId] = state.staging[subjectId]?.filter((t) => t.id !== thread.id);
893
+ intents.push({
894
+ action: ObservabilityAction.SEND_EVENT,
895
+ data: {
896
+ name: "threads.thread-created",
897
+ properties: analyticsProperties
898
+ }
899
+ });
900
+ }
901
+ intents.push({
902
+ action: ObservabilityAction.SEND_EVENT,
903
+ data: {
904
+ name: "threads.message-added",
905
+ properties: {
906
+ ...analyticsProperties,
907
+ threadLength: thread.messages.length
908
+ }
909
+ }
910
+ });
911
+ return {
912
+ data: thread,
913
+ intents: [
914
+ intents
915
+ ]
916
+ };
917
+ }
848
918
  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) {
919
+ const { subject, thread, messageId } = intent.data ?? {};
920
+ const space = getSpace2(subject);
921
+ if (!(subject instanceof DocumentType) || !(thread instanceof ThreadType) || !space) {
852
922
  return;
853
923
  }
854
924
  if (!intent.undo) {
@@ -864,7 +934,7 @@ var ThreadPlugin = () => {
864
934
  {
865
935
  action: ThreadAction.DELETE,
866
936
  data: {
867
- document: doc,
937
+ subject,
868
938
  thread
869
939
  }
870
940
  }
@@ -937,7 +1007,7 @@ var ThreadPlugin = () => {
937
1007
  }
938
1008
  const threads = computed(() => [
939
1009
  ...doc.threads.filter(nonNullable2),
940
- ...state.staging[doc.id] ?? []
1010
+ ...state.staging[fullyQualifiedId(doc)] ?? []
941
1011
  ].filter((thread) => !(thread?.status === "resolved")));
942
1012
  return [
943
1013
  listener2({
@@ -966,49 +1036,17 @@ var ThreadPlugin = () => {
966
1036
  const name = doc.content && getTextInRange(createDocAccessor(doc.content, [
967
1037
  "content"
968
1038
  ]), 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
- }
1039
+ void intentPlugin?.provides.intent.dispatch({
1040
+ action: ThreadAction.CREATE,
1041
+ data: {
1042
+ cursor,
1043
+ name,
1044
+ subject: doc
1006
1045
  }
1007
- ]);
1008
- return thread.id;
1046
+ });
1009
1047
  },
1010
1048
  onDelete: ({ id }) => {
1011
- const stagingArea = state.staging[doc.id];
1049
+ const stagingArea = state.staging[fullyQualifiedId(doc)];
1012
1050
  if (stagingArea) {
1013
1051
  const index = stagingArea.findIndex((thread2) => thread2.id === id);
1014
1052
  if (index !== -1) {
@@ -1021,7 +1059,7 @@ var ThreadPlugin = () => {
1021
1059
  }
1022
1060
  },
1023
1061
  onUpdate: ({ id, cursor }) => {
1024
- const thread = state.staging[doc.id]?.find((thread2) => thread2.id === id) ?? doc.threads.find((thread2) => thread2?.id === id);
1062
+ const thread = state.staging[fullyQualifiedId(doc)]?.find((thread2) => thread2.id === id) ?? doc.threads.find((thread2) => thread2?.id === id);
1025
1063
  if (thread instanceof ThreadType && thread.anchor) {
1026
1064
  const [start, end] = thread.anchor.split(":");
1027
1065
  thread.name = doc.content && getTextInRange(createDocAccessor(doc.content, [