@eventcatalog/core 2.58.1 → 2.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +1 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/{chunk-X4GKQ2ZE.js → chunk-F5WMB6Q5.js} +1 -1
- package/dist/{chunk-N7MEYFUO.js → chunk-SCDNNFXH.js} +1 -1
- package/dist/{chunk-F3YDLMMR.js → chunk-T3QXQPTB.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -1
- package/dist/eventcatalog.js +3 -3
- package/eventcatalog/astro.config.mjs +13 -7
- package/eventcatalog/src/components/Grids/DomainGrid.tsx +67 -2
- package/eventcatalog/src/components/Grids/MessageGrid.tsx +157 -41
- package/eventcatalog/src/components/Grids/ServiceGrid.tsx +78 -14
- package/eventcatalog/src/components/MDX/NodeGraph/Edges/MultilineEdgeLabel.tsx +52 -0
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +13 -0
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.tsx +4 -1
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Data.tsx +55 -16
- package/eventcatalog/src/components/SideBars/ContainerSideBar.astro +180 -0
- package/eventcatalog/src/components/SideBars/ServiceSideBar.astro +41 -0
- package/eventcatalog/src/components/SideNav/ListViewSideBar/components/MessageList.tsx +1 -1
- package/eventcatalog/src/components/SideNav/ListViewSideBar/index.tsx +250 -59
- package/eventcatalog/src/components/SideNav/ListViewSideBar/types.ts +3 -0
- package/eventcatalog/src/components/SideNav/ListViewSideBar/utils.ts +35 -1
- package/eventcatalog/src/components/SideNav/TreeView/getTreeView.ts +2 -2
- package/eventcatalog/src/components/Tables/Table.tsx +22 -2
- package/eventcatalog/src/components/Tables/columns/ContainersTableColumns.tsx +152 -0
- package/eventcatalog/src/components/Tables/columns/index.tsx +3 -0
- package/eventcatalog/src/content.config.ts +57 -1
- package/eventcatalog/src/layouts/DiscoverLayout.astro +11 -1
- package/eventcatalog/src/pages/architecture/architecture.astro +9 -1
- package/eventcatalog/src/pages/discover/[type]/_index.data.ts +1 -1
- package/eventcatalog/src/pages/discover/[type]/index.astro +11 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +11 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +50 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/[version].md.ts +2 -0
- package/eventcatalog/src/pages/docs/llm/llms-full.txt.ts +4 -1
- package/eventcatalog/src/pages/docs/llm/llms-services.txt.ts +19 -1
- package/eventcatalog/src/pages/docs/llm/llms.txt.ts +3 -0
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +1 -1
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/data/_index.data.ts +80 -0
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/data/index.astro +52 -0
- package/eventcatalog/src/pages/visualiser/[type]/[id]/index.astro +9 -2
- package/eventcatalog/src/types/index.ts +20 -2
- package/eventcatalog/src/utils/collections/containers.ts +94 -0
- package/eventcatalog/src/utils/collections/icons.ts +3 -1
- package/eventcatalog/src/utils/collections/services.ts +15 -1
- package/eventcatalog/src/utils/collections/util.ts +4 -2
- package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +155 -0
- package/eventcatalog/src/utils/node-graphs/services-node-graph.ts +188 -82
- package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +2 -0
- package/package.json +3 -2
|
@@ -77,6 +77,11 @@ const ServiceItem = React.memo(
|
|
|
77
77
|
isVisualizer: boolean;
|
|
78
78
|
searchTerm: string;
|
|
79
79
|
}) => {
|
|
80
|
+
const readsAndWritesTo = item.writesTo.filter((writeTo) => item.readsFrom.some((readFrom) => readFrom.id === writeTo.id));
|
|
81
|
+
const resourceReads = item.readsFrom.filter((readFrom) => !readsAndWritesTo.some((writeTo) => writeTo.id === readFrom.id));
|
|
82
|
+
const resourceWrites = item.writesTo.filter((writeTo) => !readsAndWritesTo.some((readFrom) => readFrom.id === writeTo.id));
|
|
83
|
+
const hasData = item.writesTo.length > 0 || item.readsFrom.length > 0;
|
|
84
|
+
|
|
80
85
|
return (
|
|
81
86
|
<CollapsibleGroup
|
|
82
87
|
isCollapsed={collapsedGroups[item.href]}
|
|
@@ -115,6 +120,17 @@ const ServiceItem = React.memo(
|
|
|
115
120
|
>
|
|
116
121
|
<span className="truncate">Overview</span>
|
|
117
122
|
</a>
|
|
123
|
+
{isVisualizer && hasData && (
|
|
124
|
+
<a
|
|
125
|
+
href={buildUrl(`/${item.href}/data`)}
|
|
126
|
+
data-active={decodedCurrentPath === `${item.href}/data`}
|
|
127
|
+
className={`flex items-center px-2 py-1.5 text-xs text-gray-600 hover:bg-purple-100 rounded-md ${
|
|
128
|
+
decodedCurrentPath === `${item.href}/data` ? 'bg-purple-100 ' : 'hover:bg-purple-100'
|
|
129
|
+
}`}
|
|
130
|
+
>
|
|
131
|
+
<span className="truncate">Data Diagram</span>
|
|
132
|
+
</a>
|
|
133
|
+
)}
|
|
118
134
|
{!isVisualizer && (
|
|
119
135
|
<a
|
|
120
136
|
href={buildUrlWithParams('/architecture/docs/messages', {
|
|
@@ -185,6 +201,84 @@ const ServiceItem = React.memo(
|
|
|
185
201
|
>
|
|
186
202
|
<MessageList messages={item.sends} decodedCurrentPath={decodedCurrentPath} searchTerm={searchTerm} />
|
|
187
203
|
</CollapsibleGroup>
|
|
204
|
+
{!isVisualizer && hasData && (
|
|
205
|
+
<CollapsibleGroup
|
|
206
|
+
isCollapsed={collapsedGroups[`${item.href}-data`]}
|
|
207
|
+
onToggle={() => toggleGroupCollapse(`${item.href}-data`)}
|
|
208
|
+
title={
|
|
209
|
+
<button
|
|
210
|
+
onClick={(e) => {
|
|
211
|
+
e.stopPropagation();
|
|
212
|
+
toggleGroupCollapse(`${item.href}-data`);
|
|
213
|
+
}}
|
|
214
|
+
className="truncate underline ml-2 text-xs mb-1 py-1"
|
|
215
|
+
>
|
|
216
|
+
Data Stores ({readsAndWritesTo.length + resourceWrites.length + resourceReads.length})
|
|
217
|
+
</button>
|
|
218
|
+
}
|
|
219
|
+
>
|
|
220
|
+
{readsAndWritesTo.length > 0 && (
|
|
221
|
+
<CollapsibleGroup
|
|
222
|
+
className="ml-4"
|
|
223
|
+
isCollapsed={collapsedGroups[`${item.href}-writesTo-data`]}
|
|
224
|
+
onToggle={() => toggleGroupCollapse(`${item.href}-writesTo-data`)}
|
|
225
|
+
title={
|
|
226
|
+
<button
|
|
227
|
+
onClick={(e) => {
|
|
228
|
+
e.stopPropagation();
|
|
229
|
+
toggleGroupCollapse(`${item.href}-writesTo-data`);
|
|
230
|
+
}}
|
|
231
|
+
className="truncate underline ml-2 text-xs mb-1 py-1"
|
|
232
|
+
>
|
|
233
|
+
Reads and writes to
|
|
234
|
+
</button>
|
|
235
|
+
}
|
|
236
|
+
>
|
|
237
|
+
<MessageList messages={readsAndWritesTo} decodedCurrentPath={decodedCurrentPath} searchTerm={searchTerm} />
|
|
238
|
+
</CollapsibleGroup>
|
|
239
|
+
)}
|
|
240
|
+
{resourceWrites.length > 0 && (
|
|
241
|
+
<CollapsibleGroup
|
|
242
|
+
className="ml-4"
|
|
243
|
+
isCollapsed={collapsedGroups[`${item.href}-writesTo-data`]}
|
|
244
|
+
onToggle={() => toggleGroupCollapse(`${item.href}-writesTo-data`)}
|
|
245
|
+
title={
|
|
246
|
+
<button
|
|
247
|
+
onClick={(e) => {
|
|
248
|
+
e.stopPropagation();
|
|
249
|
+
toggleGroupCollapse(`${item.href}-writesTo-data`);
|
|
250
|
+
}}
|
|
251
|
+
className="truncate underline ml-2 text-xs mb-1 py-1"
|
|
252
|
+
>
|
|
253
|
+
Writes to
|
|
254
|
+
</button>
|
|
255
|
+
}
|
|
256
|
+
>
|
|
257
|
+
<MessageList messages={resourceWrites} decodedCurrentPath={decodedCurrentPath} searchTerm={searchTerm} />
|
|
258
|
+
</CollapsibleGroup>
|
|
259
|
+
)}
|
|
260
|
+
{resourceReads.length > 0 && (
|
|
261
|
+
<CollapsibleGroup
|
|
262
|
+
className="ml-4"
|
|
263
|
+
isCollapsed={collapsedGroups[`${item.href}-readsFrom-data`]}
|
|
264
|
+
onToggle={() => toggleGroupCollapse(`${item.href}-readsFrom-data`)}
|
|
265
|
+
title={
|
|
266
|
+
<button
|
|
267
|
+
onClick={(e) => {
|
|
268
|
+
e.stopPropagation();
|
|
269
|
+
toggleGroupCollapse(`${item.href}-readsFrom-data`);
|
|
270
|
+
}}
|
|
271
|
+
className="truncate underline ml-2 text-xs mb-1 py-1"
|
|
272
|
+
>
|
|
273
|
+
Reads From
|
|
274
|
+
</button>
|
|
275
|
+
}
|
|
276
|
+
>
|
|
277
|
+
<MessageList messages={resourceReads} decodedCurrentPath={decodedCurrentPath} searchTerm={searchTerm} />
|
|
278
|
+
</CollapsibleGroup>
|
|
279
|
+
)}
|
|
280
|
+
</CollapsibleGroup>
|
|
281
|
+
)}
|
|
188
282
|
{!isVisualizer && item.entities.length > 0 && (
|
|
189
283
|
<CollapsibleGroup
|
|
190
284
|
isCollapsed={collapsedGroups[`${item.href}-entities`]}
|
|
@@ -513,6 +607,7 @@ const ListViewSideBar: React.FC<ListViewSideBarProps> = ({ resources, currentPat
|
|
|
513
607
|
>
|
|
514
608
|
<span className="truncate">Overview</span>
|
|
515
609
|
</a>
|
|
610
|
+
|
|
516
611
|
{isVisualizer && hasEntities && (
|
|
517
612
|
<a
|
|
518
613
|
href={buildUrl(`/${item.href}/entity-map`)}
|
|
@@ -720,73 +815,169 @@ const ListViewSideBar: React.FC<ListViewSideBarProps> = ({ resources, currentPat
|
|
|
720
815
|
|
|
721
816
|
{filteredData['messagesNotInService'] && filteredData['messagesNotInService'].length > 0 && (
|
|
722
817
|
<div className="pt-4 pb-2">
|
|
723
|
-
<
|
|
724
|
-
{
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
818
|
+
<CollapsibleGroup
|
|
819
|
+
isCollapsed={collapsedGroups['messagesNotInService-group']}
|
|
820
|
+
onToggle={() => toggleGroupCollapse('messagesNotInService-group')}
|
|
821
|
+
title={
|
|
822
|
+
<button
|
|
823
|
+
onClick={(e) => {
|
|
824
|
+
e.stopPropagation();
|
|
825
|
+
toggleGroupCollapse('messagesNotInService-group');
|
|
826
|
+
}}
|
|
827
|
+
className="flex justify-between items-center pl-2 w-full text-xs"
|
|
828
|
+
>
|
|
829
|
+
<span className="truncate text-xs font-bold">Orphaned Messages</span>
|
|
830
|
+
</button>
|
|
831
|
+
}
|
|
832
|
+
>
|
|
833
|
+
<div className="space-y-2 border-gray-200/80 border-l pl-3 ml-[9px] mt-3">
|
|
834
|
+
{filteredData['messagesNotInService'].map((item: any) => (
|
|
835
|
+
<div key={item.href} data-active={decodedCurrentPath === item.href}>
|
|
836
|
+
<a
|
|
837
|
+
href={item.href}
|
|
838
|
+
data-active={decodedCurrentPath === item.href}
|
|
839
|
+
className={`flex items-center justify-between px-2 py-0.5 text-xs font-thin rounded-md ${
|
|
840
|
+
decodedCurrentPath === item.href ? 'bg-purple-100 text-purple-900' : 'hover:bg-purple-100'
|
|
841
|
+
}`}
|
|
738
842
|
>
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
843
|
+
<span className="truncate">
|
|
844
|
+
<HighlightedText text={item.label} searchTerm={debouncedSearchTerm} />
|
|
845
|
+
</span>
|
|
846
|
+
<span
|
|
847
|
+
className={`ml-2 text-[10px] font-medium px-2 uppercase py-0.5 rounded ${getMessageColorByCollection(item.collection)}`}
|
|
848
|
+
>
|
|
849
|
+
{getMessageCollectionName(item.collection, item)}
|
|
850
|
+
</span>
|
|
851
|
+
</a>
|
|
852
|
+
</div>
|
|
853
|
+
))}
|
|
854
|
+
</div>
|
|
855
|
+
</CollapsibleGroup>
|
|
745
856
|
</div>
|
|
746
857
|
)}
|
|
747
858
|
|
|
748
|
-
{
|
|
859
|
+
{/* Flows Group */}
|
|
860
|
+
{filteredData['flows'] && filteredData['flows'].length > 0 && (
|
|
749
861
|
<div className="pt-4 pb-2">
|
|
750
|
-
<
|
|
751
|
-
{
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
862
|
+
<CollapsibleGroup
|
|
863
|
+
isCollapsed={collapsedGroups['flows-group']}
|
|
864
|
+
onToggle={() => toggleGroupCollapse('flows-group')}
|
|
865
|
+
title={
|
|
866
|
+
<button
|
|
867
|
+
onClick={(e) => {
|
|
868
|
+
e.stopPropagation();
|
|
869
|
+
toggleGroupCollapse('flows-group');
|
|
870
|
+
}}
|
|
871
|
+
className="flex justify-between items-center pl-2 w-full text-xs"
|
|
872
|
+
>
|
|
873
|
+
<span className="truncate text-xs font-bold">Flows</span>
|
|
874
|
+
</button>
|
|
875
|
+
}
|
|
876
|
+
>
|
|
877
|
+
<div className="space-y-2 border-gray-200/80 border-l pl-3 ml-[9px] mt-3">
|
|
878
|
+
{filteredData['flows'].map((item: any) => (
|
|
879
|
+
<div key={item.href} data-active={decodedCurrentPath === item.href}>
|
|
880
|
+
<a
|
|
881
|
+
href={item.href}
|
|
882
|
+
data-active={decodedCurrentPath === item.href}
|
|
883
|
+
className={`flex items-center justify-between px-2 py-0.5 text-xs font-thin rounded-md ${
|
|
884
|
+
decodedCurrentPath === item.href ? 'bg-purple-100 text-purple-900' : 'hover:bg-purple-100'
|
|
885
|
+
}`}
|
|
886
|
+
>
|
|
887
|
+
<span className="truncate">
|
|
888
|
+
<HighlightedText text={item.label} searchTerm={debouncedSearchTerm} />
|
|
889
|
+
</span>
|
|
890
|
+
<span className={`ml-2 text-[10px] font-medium px-2 uppercase py-0.5 rounded bg-teal-50 text-teal-600`}>
|
|
891
|
+
FLOW
|
|
892
|
+
</span>
|
|
893
|
+
</a>
|
|
894
|
+
</div>
|
|
895
|
+
))}
|
|
896
|
+
</div>
|
|
897
|
+
</CollapsibleGroup>
|
|
768
898
|
</div>
|
|
769
899
|
)}
|
|
770
|
-
|
|
900
|
+
|
|
901
|
+
{/* Data Group */}
|
|
902
|
+
{filteredData['containers'] && filteredData['containers'].length > 0 && (
|
|
771
903
|
<div className="pt-4 pb-2">
|
|
772
|
-
<
|
|
773
|
-
{
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
904
|
+
<CollapsibleGroup
|
|
905
|
+
isCollapsed={collapsedGroups['data-group']}
|
|
906
|
+
onToggle={() => toggleGroupCollapse('data-group')}
|
|
907
|
+
title={
|
|
908
|
+
<button
|
|
909
|
+
onClick={(e) => {
|
|
910
|
+
e.stopPropagation();
|
|
911
|
+
toggleGroupCollapse('data-group');
|
|
912
|
+
}}
|
|
913
|
+
className="flex justify-between items-center pl-2 w-full text-xs"
|
|
914
|
+
>
|
|
915
|
+
<span className="truncate text-xs font-bold">Data</span>
|
|
916
|
+
</button>
|
|
917
|
+
}
|
|
918
|
+
>
|
|
919
|
+
<div className="space-y-2 border-gray-200/80 border-l pl-3 ml-[9px] mt-3">
|
|
920
|
+
{filteredData['containers'].map((item: any) => (
|
|
921
|
+
<div key={item.href} data-active={decodedCurrentPath === item.href}>
|
|
922
|
+
<a
|
|
923
|
+
href={item.href}
|
|
924
|
+
data-active={decodedCurrentPath === item.href}
|
|
925
|
+
className={`flex items-center justify-between px-2 py-0.5 text-xs font-thin rounded-md ${
|
|
926
|
+
decodedCurrentPath === item.href ? 'bg-purple-100 text-purple-900' : 'hover:bg-purple-100'
|
|
927
|
+
}`}
|
|
928
|
+
>
|
|
929
|
+
<span className="truncate">
|
|
930
|
+
<HighlightedText text={item.label} searchTerm={debouncedSearchTerm} />
|
|
931
|
+
</span>
|
|
932
|
+
<span className={`ml-2 text-[10px] font-medium px-2 uppercase py-0.5 rounded bg-blue-50 text-blue-600`}>
|
|
933
|
+
DATA
|
|
934
|
+
</span>
|
|
935
|
+
</a>
|
|
936
|
+
</div>
|
|
937
|
+
))}
|
|
938
|
+
</div>
|
|
939
|
+
</CollapsibleGroup>
|
|
940
|
+
</div>
|
|
941
|
+
)}
|
|
942
|
+
|
|
943
|
+
{filteredData['designs'] && filteredData['designs'].length > 0 && (
|
|
944
|
+
<div className="pt-4 pb-2">
|
|
945
|
+
<CollapsibleGroup
|
|
946
|
+
isCollapsed={collapsedGroups['designs-group']}
|
|
947
|
+
onToggle={() => toggleGroupCollapse('designs-group')}
|
|
948
|
+
title={
|
|
949
|
+
<button
|
|
950
|
+
onClick={(e) => {
|
|
951
|
+
e.stopPropagation();
|
|
952
|
+
toggleGroupCollapse('designs-group');
|
|
953
|
+
}}
|
|
954
|
+
className="flex justify-between items-center pl-2 w-full text-xs"
|
|
955
|
+
>
|
|
956
|
+
<span className="truncate text-xs font-bold">Designs</span>
|
|
957
|
+
</button>
|
|
958
|
+
}
|
|
959
|
+
>
|
|
960
|
+
<div className="space-y-2 border-gray-200/80 border-l pl-3 ml-[9px] mt-3">
|
|
961
|
+
{filteredData['designs'].map((item: any) => (
|
|
962
|
+
<div key={item.href} data-active={decodedCurrentPath === item.href}>
|
|
963
|
+
<a
|
|
964
|
+
href={item.href}
|
|
965
|
+
data-active={decodedCurrentPath === item.href}
|
|
966
|
+
className={`flex items-center justify-between px-2 py-0.5 text-xs font-thin rounded-md ${
|
|
967
|
+
decodedCurrentPath === item.href ? 'bg-purple-100 text-purple-900' : 'hover:bg-purple-100'
|
|
968
|
+
}`}
|
|
969
|
+
>
|
|
970
|
+
<span className="truncate">
|
|
971
|
+
<HighlightedText text={item.label} searchTerm={debouncedSearchTerm} />
|
|
972
|
+
</span>
|
|
973
|
+
<span className={`ml-2 text-[10px] font-medium px-2 uppercase py-0.5 rounded bg-teal-50 text-teal-600`}>
|
|
974
|
+
DESIGN
|
|
975
|
+
</span>
|
|
976
|
+
</a>
|
|
977
|
+
</div>
|
|
978
|
+
))}
|
|
979
|
+
</div>
|
|
980
|
+
</CollapsibleGroup>
|
|
790
981
|
</div>
|
|
791
982
|
)}
|
|
792
983
|
</>
|
|
@@ -33,6 +33,8 @@ export interface ServiceItem {
|
|
|
33
33
|
sends: MessageItem[];
|
|
34
34
|
receives: MessageItem[];
|
|
35
35
|
entities: EntityItem[];
|
|
36
|
+
writesTo: MessageItem[];
|
|
37
|
+
readsFrom: MessageItem[];
|
|
36
38
|
specifications?: {
|
|
37
39
|
type: string;
|
|
38
40
|
path: string;
|
|
@@ -79,6 +81,7 @@ export interface Resources {
|
|
|
79
81
|
commands?: MessageItem[];
|
|
80
82
|
queries?: MessageItem[];
|
|
81
83
|
events?: MessageItem[];
|
|
84
|
+
containers?: MessageItem[];
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
export interface ListViewSideBarProps {
|
|
@@ -8,6 +8,7 @@ import { getCommands } from '@utils/commands';
|
|
|
8
8
|
import { getEvents } from '@utils/events';
|
|
9
9
|
import { getQueries } from '@utils/queries';
|
|
10
10
|
import { getDesigns } from '@utils/collections/designs';
|
|
11
|
+
import { getContainers } from '@utils/collections/containers';
|
|
11
12
|
|
|
12
13
|
const stripCollection = (collection: any) => {
|
|
13
14
|
return collection.map((item: any) => ({
|
|
@@ -26,6 +27,7 @@ export async function getResourcesForNavigation({ currentPath }: { currentPath:
|
|
|
26
27
|
const domains = await getDomains({ getAllVersions: false });
|
|
27
28
|
const channels = await getChannels({ getAllVersions: false });
|
|
28
29
|
const flows = await getFlows({ getAllVersions: false });
|
|
30
|
+
const containers = await getContainers({ getAllVersions: false });
|
|
29
31
|
const designs = await getDesigns({ getAllVersions: false });
|
|
30
32
|
|
|
31
33
|
const messages = [...events, ...commands, ...queries];
|
|
@@ -43,7 +45,7 @@ export async function getResourcesForNavigation({ currentPath }: { currentPath:
|
|
|
43
45
|
const route = currentPath.includes('visualiser') ? 'visualiser' : 'docs';
|
|
44
46
|
|
|
45
47
|
// Just the domains for now.
|
|
46
|
-
const allDataAsSideNav = [...domains, ...services, ...flows, ...channels].reduce((acc, item) => {
|
|
48
|
+
const allDataAsSideNav = [...domains, ...services, ...flows, ...channels, ...containers].reduce((acc, item) => {
|
|
47
49
|
const title = item.collection;
|
|
48
50
|
const group = acc[title] || [];
|
|
49
51
|
|
|
@@ -54,6 +56,10 @@ export async function getResourcesForNavigation({ currentPath }: { currentPath:
|
|
|
54
56
|
const sends = isCollectionService ? item.data.sends || null : null;
|
|
55
57
|
const receives = isCollectionService ? item.data.receives || null : null;
|
|
56
58
|
const entities = isCollectionDomain || isCollectionService ? item.data.entities || null : null;
|
|
59
|
+
|
|
60
|
+
const writesTo = isCollectionService ? item.data.writesTo || null : null;
|
|
61
|
+
const readsFrom = isCollectionService ? item.data.readsFrom || null : null;
|
|
62
|
+
|
|
57
63
|
// Add href to the sends and receives
|
|
58
64
|
const sendsWithHref = sends?.map((send: any) => ({
|
|
59
65
|
id: send.data.id,
|
|
@@ -89,6 +95,32 @@ export async function getResourcesForNavigation({ currentPath }: { currentPath:
|
|
|
89
95
|
href: buildUrl(`/${route}/${entity.collection}/${entity.data.id}/${entity.data.version}`),
|
|
90
96
|
}));
|
|
91
97
|
|
|
98
|
+
const writesToWithHref = writesTo?.map((writeTo: any) => ({
|
|
99
|
+
id: writeTo.data.id,
|
|
100
|
+
data: {
|
|
101
|
+
name: writeTo.data.name,
|
|
102
|
+
sidebar: {
|
|
103
|
+
badge: writeTo.data.container_type || writeTo.collection,
|
|
104
|
+
backgroundColor: 'bg-blue-100 text-blue-600',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
collection: writeTo.collection,
|
|
108
|
+
href: buildUrl(`/${route}/${writeTo.collection}/${writeTo.data.id}/${writeTo.data.version}`),
|
|
109
|
+
}));
|
|
110
|
+
|
|
111
|
+
const readsFromWithHref = readsFrom?.map((readFrom: any) => ({
|
|
112
|
+
id: readFrom.data.id,
|
|
113
|
+
data: {
|
|
114
|
+
name: readFrom.data.name,
|
|
115
|
+
sidebar: {
|
|
116
|
+
badge: readFrom.data.container_type || readFrom.collection,
|
|
117
|
+
backgroundColor: 'bg-blue-100 text-indigo-600',
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
collection: readFrom.collection,
|
|
121
|
+
href: buildUrl(`/${route}/${readFrom.collection}/${readFrom.data.id}/${readFrom.data.version}`),
|
|
122
|
+
}));
|
|
123
|
+
|
|
92
124
|
// don't render items if we are in the visualiser and the item has visualiser set to false
|
|
93
125
|
if (currentPath.includes('visualiser') && item.data.visualiser === false) {
|
|
94
126
|
return acc;
|
|
@@ -115,6 +147,8 @@ export async function getResourcesForNavigation({ currentPath }: { currentPath:
|
|
|
115
147
|
receives: receivesWithHref,
|
|
116
148
|
entities: entitiesWithHref,
|
|
117
149
|
specifications: isCollectionService ? getSpecificationsForService(item) : null,
|
|
150
|
+
writesTo: writesToWithHref,
|
|
151
|
+
readsFrom: readsFromWithHref,
|
|
118
152
|
sidebar: item.data?.sidebar,
|
|
119
153
|
renderInVisualiser: item.data?.visualiser ?? true,
|
|
120
154
|
};
|
|
@@ -18,7 +18,7 @@ export type TreeNode = {
|
|
|
18
18
|
/**
|
|
19
19
|
* Resource types that should be in the sidenav
|
|
20
20
|
*/
|
|
21
|
-
const RESOURCE_TYPES = ['domains', 'entities', 'services', 'events', 'commands', 'queries', 'flows', 'channels'];
|
|
21
|
+
const RESOURCE_TYPES = ['domains', 'entities', 'services', 'events', 'commands', 'queries', 'flows', 'channels', 'containers'];
|
|
22
22
|
// const RESOURCE_TYPES = ['domains', 'services', 'events', 'commands', 'queries', 'flows', 'channels'];
|
|
23
23
|
|
|
24
24
|
/**
|
|
@@ -125,7 +125,7 @@ function groupChildrenByType(parentNode: TreeNode) {
|
|
|
125
125
|
.map(([type, nodes]) => {
|
|
126
126
|
return {
|
|
127
127
|
id: `${parentNode.id}/${type}`,
|
|
128
|
-
name: type,
|
|
128
|
+
name: type === 'containers' ? 'Data' : type,
|
|
129
129
|
type: type as CollectionKey,
|
|
130
130
|
version: '0',
|
|
131
131
|
children: nodes,
|
|
@@ -31,14 +31,16 @@ declare module '@tanstack/react-table' {
|
|
|
31
31
|
| 'ownedQueries'
|
|
32
32
|
| 'ownedEvents'
|
|
33
33
|
| 'ownedServices'
|
|
34
|
-
| 'associatedTeams'
|
|
34
|
+
| 'associatedTeams'
|
|
35
|
+
| 'servicesThatWriteToContainer'
|
|
36
|
+
| 'servicesThatReadFromContainer';
|
|
35
37
|
filteredItemHasVersion?: boolean;
|
|
36
38
|
showFilter?: boolean;
|
|
37
39
|
className?: string;
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
export type TCollectionTypes = 'domains' | 'services' | CollectionMessageTypes | 'flows' | 'users' | 'teams';
|
|
43
|
+
export type TCollectionTypes = 'domains' | 'services' | CollectionMessageTypes | 'flows' | 'users' | 'teams' | 'containers';
|
|
42
44
|
|
|
43
45
|
export type TData<T extends TCollectionTypes> = {
|
|
44
46
|
collection: T;
|
|
@@ -103,6 +105,24 @@ export type TData<T extends TCollectionTypes> = {
|
|
|
103
105
|
version: string;
|
|
104
106
|
};
|
|
105
107
|
}>;
|
|
108
|
+
// Only for containers
|
|
109
|
+
servicesThatWriteToContainer?: Array<{
|
|
110
|
+
collection: string; // Specify only 'services'?
|
|
111
|
+
data: {
|
|
112
|
+
id: string;
|
|
113
|
+
name: string;
|
|
114
|
+
version: string;
|
|
115
|
+
};
|
|
116
|
+
}>;
|
|
117
|
+
// Only for containers
|
|
118
|
+
servicesThatReadFromContainer?: Array<{
|
|
119
|
+
collection: string; // Specify only 'services'?
|
|
120
|
+
data: {
|
|
121
|
+
id: string;
|
|
122
|
+
name: string;
|
|
123
|
+
version: string;
|
|
124
|
+
};
|
|
125
|
+
}>;
|
|
106
126
|
// ---------------------------------------------------------------------------
|
|
107
127
|
// Users
|
|
108
128
|
avatarUrl?: string;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { createColumnHelper } from '@tanstack/react-table';
|
|
2
|
+
import { filterByName } from '../filters/custom-filters';
|
|
3
|
+
import { buildUrl } from '@utils/url-builder';
|
|
4
|
+
import { ServerIcon } from '@heroicons/react/24/solid';
|
|
5
|
+
import { DatabaseIcon } from 'lucide-react';
|
|
6
|
+
import { createBadgesColumn } from './SharedColumns';
|
|
7
|
+
import type { TData } from '../Table';
|
|
8
|
+
import { filterCollectionByName } from '../filters/custom-filters';
|
|
9
|
+
|
|
10
|
+
const columnHelper = createColumnHelper<TData<'containers'>>();
|
|
11
|
+
|
|
12
|
+
export const columns = () => [
|
|
13
|
+
columnHelper.accessor('data.name', {
|
|
14
|
+
id: 'name',
|
|
15
|
+
header: () => <span>Storage</span>,
|
|
16
|
+
cell: (info) => {
|
|
17
|
+
const containerRaw = info.row.original;
|
|
18
|
+
const color = 'blue';
|
|
19
|
+
return (
|
|
20
|
+
<div className=" group ">
|
|
21
|
+
<a
|
|
22
|
+
href={buildUrl(`/docs/${containerRaw.collection}/${containerRaw.data.id}/${containerRaw.data.version}`)}
|
|
23
|
+
className={`group-hover:text-${color}-500 flex space-x-1 items-center`}
|
|
24
|
+
>
|
|
25
|
+
<div className={`flex items-center border border-gray-300 shadow-sm rounded-md group-hover:border-${color}-400`}>
|
|
26
|
+
<span className="flex items-center">
|
|
27
|
+
<span className={`bg-${color}-500 group-hover:bg-${color}-600 h-full rounded-tl rounded-bl p-1`}>
|
|
28
|
+
<DatabaseIcon className="h-4 w-4 text-white" />
|
|
29
|
+
</span>
|
|
30
|
+
<span className="leading-none px-2 group-hover:underline group-hover:text-primary font-light">
|
|
31
|
+
{containerRaw.data.name} (v{containerRaw.data.version})
|
|
32
|
+
</span>
|
|
33
|
+
</span>
|
|
34
|
+
</div>
|
|
35
|
+
</a>
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
},
|
|
39
|
+
footer: (info) => info.column.id,
|
|
40
|
+
meta: {
|
|
41
|
+
filterVariant: 'name',
|
|
42
|
+
},
|
|
43
|
+
filterFn: filterByName,
|
|
44
|
+
}),
|
|
45
|
+
columnHelper.accessor('data.summary', {
|
|
46
|
+
id: 'summary',
|
|
47
|
+
header: () => 'Summary',
|
|
48
|
+
cell: (info) => <span className="font-light ">{info.renderValue()}</span>,
|
|
49
|
+
footer: (info) => info.column.id,
|
|
50
|
+
meta: {
|
|
51
|
+
showFilter: false,
|
|
52
|
+
className: 'max-w-md',
|
|
53
|
+
},
|
|
54
|
+
}),
|
|
55
|
+
columnHelper.accessor('data.servicesThatWriteToContainer', {
|
|
56
|
+
header: () => <span>Writes</span>,
|
|
57
|
+
meta: {
|
|
58
|
+
filterVariant: 'collection',
|
|
59
|
+
collectionFilterKey: 'servicesThatWriteToContainer',
|
|
60
|
+
},
|
|
61
|
+
cell: (info) => {
|
|
62
|
+
const services = info.getValue();
|
|
63
|
+
if (services?.length === 0 || !services)
|
|
64
|
+
return <div className="font-light text-sm text-gray-400/60 text-left italic">No services documented</div>;
|
|
65
|
+
return (
|
|
66
|
+
<ul className="">
|
|
67
|
+
{services.map((service, index) => {
|
|
68
|
+
return (
|
|
69
|
+
<li className="py-2 group flex items-center space-x-2" key={`${service.data.id}-${index}`}>
|
|
70
|
+
<a
|
|
71
|
+
href={buildUrl(`/docs/${service.collection}/${service.data.id}/${service.data.version}`)}
|
|
72
|
+
className="group-hover:text-primary flex space-x-1 items-center "
|
|
73
|
+
>
|
|
74
|
+
<div className="flex items-center border border-gray-300 shadow-sm rounded-md">
|
|
75
|
+
<span className="flex items-center">
|
|
76
|
+
<span className="bg-pink-500 h-full rounded-tl rounded-bl p-1">
|
|
77
|
+
<ServerIcon className="h-4 w-4 text-white" />
|
|
78
|
+
</span>
|
|
79
|
+
<span className="font-light leading-none px-2 group-hover:underline">
|
|
80
|
+
{service.data.name} (v{service.data.version})
|
|
81
|
+
</span>
|
|
82
|
+
</span>{' '}
|
|
83
|
+
</div>
|
|
84
|
+
</a>
|
|
85
|
+
</li>
|
|
86
|
+
);
|
|
87
|
+
})}
|
|
88
|
+
</ul>
|
|
89
|
+
);
|
|
90
|
+
},
|
|
91
|
+
footer: (info) => info.column.id,
|
|
92
|
+
filterFn: filterCollectionByName('servicesThatWriteToContainer'),
|
|
93
|
+
}),
|
|
94
|
+
columnHelper.accessor('data.servicesThatReadFromContainer', {
|
|
95
|
+
header: () => <span>Reads</span>,
|
|
96
|
+
meta: {
|
|
97
|
+
filterVariant: 'collection',
|
|
98
|
+
collectionFilterKey: 'servicesThatReadFromContainer',
|
|
99
|
+
},
|
|
100
|
+
cell: (info) => {
|
|
101
|
+
const services = info.getValue();
|
|
102
|
+
if (services?.length === 0 || !services)
|
|
103
|
+
return <div className="font-light text-sm text-gray-400/60 text-left italic">No services documented</div>;
|
|
104
|
+
return (
|
|
105
|
+
<ul className="">
|
|
106
|
+
{services.map((service, index) => {
|
|
107
|
+
return (
|
|
108
|
+
<li className="py-2 group flex items-center space-x-2" key={`${service.data.id}-${index}`}>
|
|
109
|
+
<a
|
|
110
|
+
href={buildUrl(`/docs/${service.collection}/${service.data.id}/${service.data.version}`)}
|
|
111
|
+
className="group-hover:text-primary flex space-x-1 items-center "
|
|
112
|
+
>
|
|
113
|
+
<div className="flex items-center border border-gray-300 shadow-sm rounded-md">
|
|
114
|
+
<span className="flex items-center">
|
|
115
|
+
<span className="bg-pink-500 h-full rounded-tl rounded-bl p-1">
|
|
116
|
+
<ServerIcon className="h-4 w-4 text-white" />
|
|
117
|
+
</span>
|
|
118
|
+
<span className="font-light leading-none px-2 group-hover:underline">
|
|
119
|
+
{service.data.name} (v{service.data.version})
|
|
120
|
+
</span>
|
|
121
|
+
</span>{' '}
|
|
122
|
+
</div>
|
|
123
|
+
</a>
|
|
124
|
+
</li>
|
|
125
|
+
);
|
|
126
|
+
})}
|
|
127
|
+
</ul>
|
|
128
|
+
);
|
|
129
|
+
},
|
|
130
|
+
footer: (info) => info.column.id,
|
|
131
|
+
filterFn: filterCollectionByName('servicesThatReadFromContainer'),
|
|
132
|
+
}),
|
|
133
|
+
createBadgesColumn(columnHelper),
|
|
134
|
+
columnHelper.accessor('data.name', {
|
|
135
|
+
header: () => <span />,
|
|
136
|
+
cell: (info) => {
|
|
137
|
+
const container = info.row.original;
|
|
138
|
+
return (
|
|
139
|
+
<a
|
|
140
|
+
className="hover:text-primary hover:underline px-4 font-light"
|
|
141
|
+
href={buildUrl(`/visualiser/${container.collection}/${container.data.id}/${container.data.version}`)}
|
|
142
|
+
>
|
|
143
|
+
Visualiser →
|
|
144
|
+
</a>
|
|
145
|
+
);
|
|
146
|
+
},
|
|
147
|
+
id: 'actions',
|
|
148
|
+
meta: {
|
|
149
|
+
showFilter: false,
|
|
150
|
+
},
|
|
151
|
+
}),
|
|
152
|
+
];
|