@eventcatalog/core 3.42.0 → 3.43.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.
Files changed (52) hide show
  1. package/dist/analytics/analytics.cjs +1 -1
  2. package/dist/analytics/analytics.js +2 -2
  3. package/dist/analytics/count-resources.cjs +1 -0
  4. package/dist/analytics/count-resources.js +1 -1
  5. package/dist/analytics/log-build.cjs +3 -1
  6. package/dist/analytics/log-build.js +4 -4
  7. package/dist/{chunk-6FAGUEM4.js → chunk-2EI3M7OO.js} +1 -1
  8. package/dist/{chunk-UQIDXF2V.js → chunk-7M5IQL3J.js} +1 -1
  9. package/dist/{chunk-3DVHEVHQ.js → chunk-DAOXTQVS.js} +1 -0
  10. package/dist/{chunk-VPZ77Y6E.js → chunk-KY74BE42.js} +1 -1
  11. package/dist/{chunk-L66TCSM7.js → chunk-QV2PKXZM.js} +3 -2
  12. package/dist/{chunk-QMORF42U.js → chunk-ZONBICNH.js} +8 -0
  13. package/dist/{chunk-KE6YTTLB.js → chunk-ZQHBDPIY.js} +1 -1
  14. package/dist/constants.cjs +1 -1
  15. package/dist/constants.js +1 -1
  16. package/dist/eventcatalog.cjs +11 -1
  17. package/dist/eventcatalog.js +7 -7
  18. package/dist/generate.cjs +1 -1
  19. package/dist/generate.js +3 -3
  20. package/dist/search-indexer.cjs +8 -0
  21. package/dist/search-indexer.js +1 -1
  22. package/dist/utils/cli-logger.cjs +1 -1
  23. package/dist/utils/cli-logger.js +2 -2
  24. package/eventcatalog/src/components/MDX/Attachments.astro +3 -3
  25. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +11 -2
  26. package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +100 -2
  27. package/eventcatalog/src/components/Tables/Discover/columns.tsx +53 -1
  28. package/eventcatalog/src/content.config.ts +61 -0
  29. package/eventcatalog/src/enterprise/collections/resource-docs-utils.ts +19 -0
  30. package/eventcatalog/src/layouts/DiscoverLayout.astro +12 -1
  31. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +98 -46
  32. package/eventcatalog/src/pages/discover/[type]/_index.data.ts +5 -0
  33. package/eventcatalog/src/pages/discover/[type]/index.astro +17 -0
  34. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +1 -0
  35. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +68 -2
  36. package/eventcatalog/src/pages/docs/llm/llms-full.txt.ts +1 -0
  37. package/eventcatalog/src/pages/docs/teams/[id]/index.astro +26 -1
  38. package/eventcatalog/src/pages/docs/users/[id]/index.astro +26 -1
  39. package/eventcatalog/src/stores/sidebar-store/builders/adr.ts +150 -0
  40. package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +2 -0
  41. package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +50 -0
  42. package/eventcatalog/src/stores/sidebar-store/state.ts +209 -68
  43. package/eventcatalog/src/types/index.ts +2 -0
  44. package/eventcatalog/src/utils/collection-colors.ts +2 -0
  45. package/eventcatalog/src/utils/collections/adr-constants.ts +53 -0
  46. package/eventcatalog/src/utils/collections/adrs.ts +146 -0
  47. package/eventcatalog/src/utils/collections/icons.ts +2 -0
  48. package/eventcatalog/src/utils/collections/teams.ts +6 -1
  49. package/eventcatalog/src/utils/collections/users.ts +17 -10
  50. package/eventcatalog/src/utils/collections/util.ts +2 -0
  51. package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +2 -0
  52. package/package.json +3 -3
@@ -1,6 +1,8 @@
1
1
  import { getCollection } from 'astro:content';
2
2
  import type { CollectionEntry } from 'astro:content';
3
3
  import { getAgents } from '@utils/collections/agents';
4
+ import { getAdrAliasNodeKey, getAdrNodeKey, getAdrs, type Adr } from '@utils/collections/adrs';
5
+ import { ADR_STATUS_VALUES, formatAdrStatus } from '@utils/collections/adr-constants';
4
6
  import { getContainers } from '@utils/collections/containers';
5
7
  import { getDomains } from '@utils/collections/domains';
6
8
  import { getServices } from '@utils/collections/services';
@@ -22,12 +24,18 @@ import { buildMessageNode } from './builders/message';
22
24
  import { buildContainerNode } from './builders/container';
23
25
  import { buildFlowNode } from './builders/flow';
24
26
  import { buildDataProductNode } from './builders/data-product';
27
+ import { buildAdrNode } from './builders/adr';
25
28
  import config from '@config';
26
29
  import { getDesigns } from '@utils/collections/designs';
27
30
  import { getChannels } from '@utils/collections/channels';
28
31
  import { createVersionedMap, findInMap } from '@utils/collections/util';
29
32
  import { iconFieldsForResource } from '@utils/icon';
30
- import { buildQuickReferenceSection, buildResourceDocsSection, shouldRenderSideBarSection } from './builders/shared';
33
+ import {
34
+ buildQuickReferenceSection,
35
+ buildResourceDocsSection,
36
+ shouldRenderSideBarSection,
37
+ withArchitectureDecisionsSection,
38
+ } from './builders/shared';
31
39
  import { isChangelogEnabled } from '@utils/feature';
32
40
 
33
41
  export type { NavigationData, NavNode, ChildRef };
@@ -41,6 +49,35 @@ type ServiceEntry = CollectionEntry<'services'>;
41
49
  type ContainerEntry = CollectionEntry<'containers'>;
42
50
  type DataProductEntry = CollectionEntry<'data-products'>;
43
51
 
52
+ const byResourceName = <T extends { data: { name?: string; id: string } }>(a: T, b: T) => {
53
+ const name = (a.data.name || a.data.id).localeCompare(b.data.name || b.data.id);
54
+ if (name !== 0) return name;
55
+ return a.data.id.localeCompare(b.data.id);
56
+ };
57
+
58
+ const sortByResourceName = <T extends { data: { name?: string; id: string } }>(items: T[]) => [...items].sort(byResourceName);
59
+
60
+ const byAdrDateDesc = (a: Adr, b: Adr) => {
61
+ const date = new Date(b.data.date).getTime() - new Date(a.data.date).getTime();
62
+ if (date !== 0) return date;
63
+ return byResourceName(a, b);
64
+ };
65
+
66
+ const groupAdrsByStatus = (adrs: Adr[]): NavNode[] =>
67
+ ADR_STATUS_VALUES.reduce<NavNode[]>((groups, status) => {
68
+ const adrsForStatus = adrs.filter((adr) => adr.data.status === status);
69
+ if (adrsForStatus.length === 0) return groups;
70
+
71
+ groups.push({
72
+ type: 'group',
73
+ title: `${formatAdrStatus(status)} (${adrsForStatus.length})`,
74
+ subtle: true,
75
+ pages: [...adrsForStatus].sort(byAdrDateDesc).map(getAdrNodeKey),
76
+ });
77
+
78
+ return groups;
79
+ }, []);
80
+
44
81
  const getMessageNodeKey = (message: MessageEntry) =>
45
82
  `${pluralizeMessageType(message)}:${message.data.id}:${message.data.version}`;
46
83
 
@@ -254,6 +291,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
254
291
  diagrams,
255
292
  dataProducts,
256
293
  entities,
294
+ adrs,
257
295
  resourceDocs,
258
296
  resourceDocCategories,
259
297
  ] = await Promise.all([
@@ -270,6 +308,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
270
308
  getDiagrams({ getAllVersions: false }),
271
309
  getDataProducts({ getAllVersions: false }),
272
310
  getEntities({ getAllVersions: false }),
311
+ getAdrs({ getAllVersions: false }),
273
312
  getResourceDocs(),
274
313
  getResourceDocCategories(),
275
314
  ]);
@@ -289,9 +328,13 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
289
328
  queries,
290
329
  flows,
291
330
  containers,
331
+ channels,
292
332
  diagrams,
293
333
  dataProducts,
294
334
  entities,
335
+ adrs,
336
+ users,
337
+ teams,
295
338
  resourceDocs,
296
339
  resourceDocCategories,
297
340
  };
@@ -348,9 +391,25 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
348
391
  })
349
392
  );
350
393
 
394
+ const adrsWithOwners = await Promise.all(
395
+ adrs.map(async (adr) => {
396
+ const owners = await Promise.all((adr.data.owners || []).map((owner) => getOwner(owner)));
397
+ const decisionMakers = await Promise.all((adr.data.decisionMakers || []).map((owner) => getOwner(owner)));
398
+ return {
399
+ adr,
400
+ owners: owners.filter((o) => o !== undefined),
401
+ decisionMakers: decisionMakers.filter((o) => o !== undefined),
402
+ };
403
+ })
404
+ );
405
+
351
406
  const flowNodes = flows.reduce(
352
407
  (acc, flow) => {
353
- acc[`flow:${flow.data.id}:${flow.data.version}`] = buildFlowNode(flow, context);
408
+ acc[`flow:${flow.data.id}:${flow.data.version}`] = withArchitectureDecisionsSection(
409
+ buildFlowNode(flow, context),
410
+ flow,
411
+ adrs
412
+ );
354
413
  return acc;
355
414
  },
356
415
  {} as Record<string, NavNode>
@@ -359,7 +418,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
359
418
  const domainNodes = domainsWithOwners.reduce(
360
419
  (acc, { domain, owners }) => {
361
420
  const versionedKey = `domain:${domain.data.id}:${domain.data.version}`;
362
- acc[versionedKey] = buildDomainNode(domain, owners, context);
421
+ acc[versionedKey] = withArchitectureDecisionsSection(buildDomainNode(domain, owners, context), domain, adrs);
363
422
  if (domain.data.latestVersion === domain.data.version) {
364
423
  // Store reference to versioned key instead of duplicating the full node
365
424
  acc[`domain:${domain.data.id}`] = versionedKey;
@@ -447,7 +506,11 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
447
506
  (acc, { agent, owners }) => {
448
507
  const versionedKey = `agent:${agent.data.id}:${agent.data.version}`;
449
508
  const agentChannels = agentChannelsMap.get(`${agent.data.id}:${agent.data.version}`) || [];
450
- acc[versionedKey] = buildAgentNode(agent, owners, context, agentChannels, flowRefsByAgent.get(versionedKey) || []);
509
+ acc[versionedKey] = withArchitectureDecisionsSection(
510
+ buildAgentNode(agent, owners, context, agentChannels, flowRefsByAgent.get(versionedKey) || []),
511
+ agent,
512
+ adrs
513
+ );
451
514
  if (agent.data.latestVersion === agent.data.version) {
452
515
  acc[`agent:${agent.data.id}`] = versionedKey;
453
516
  }
@@ -460,7 +523,11 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
460
523
  (acc, { service, owners }) => {
461
524
  const versionedKey = `service:${service.data.id}:${service.data.version}`;
462
525
  const serviceChannels = serviceChannelsMap.get(`${service.data.id}:${service.data.version}`) || [];
463
- acc[versionedKey] = buildServiceNode(service, owners, context, serviceChannels, flowRefsByService.get(versionedKey) || []);
526
+ acc[versionedKey] = withArchitectureDecisionsSection(
527
+ buildServiceNode(service, owners, context, serviceChannels, flowRefsByService.get(versionedKey) || []),
528
+ service,
529
+ adrs
530
+ );
464
531
  if (service.data.latestVersion === service.data.version) {
465
532
  // Store reference to versioned key instead of duplicating the full node
466
533
  acc[`service:${service.data.id}`] = versionedKey;
@@ -498,7 +565,11 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
498
565
  const type = pluralizeMessageType(message as any);
499
566
  const versionedKey = `${type}:${message.data.id}:${message.data.version}`;
500
567
  const hasFieldUsage = messagesWithFieldUsage.has(message.data.id);
501
- acc[versionedKey] = buildMessageNode(message, owners, context, hasFieldUsage, flowRefsByMessage.get(versionedKey) || []);
568
+ acc[versionedKey] = withArchitectureDecisionsSection(
569
+ buildMessageNode(message, owners, context, hasFieldUsage, flowRefsByMessage.get(versionedKey) || []),
570
+ message,
571
+ adrs
572
+ );
502
573
  if (message.data.latestVersion === message.data.version) {
503
574
  // Store reference to versioned key instead of duplicating the full node
504
575
  acc[`${type}:${message.data.id}`] = versionedKey;
@@ -513,7 +584,11 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
513
584
  const containerNodes = containerWithOwners.reduce(
514
585
  (acc, { container, owners }) => {
515
586
  const versionedKey = `container:${container.data.id}:${container.data.version}`;
516
- acc[versionedKey] = buildContainerNode(container, owners, context, flowRefsByContainer.get(versionedKey) || []);
587
+ acc[versionedKey] = withArchitectureDecisionsSection(
588
+ buildContainerNode(container, owners, context, flowRefsByContainer.get(versionedKey) || []),
589
+ container,
590
+ adrs
591
+ );
517
592
  if (container.data.latestVersion === container.data.version) {
518
593
  // Store reference to versioned key instead of duplicating the full node
519
594
  acc[`container:${container.data.id}`] = versionedKey;
@@ -547,11 +622,10 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
547
622
  const dataProductNodes = dataProductWithOwners.reduce(
548
623
  (acc, { dataProduct, owners }) => {
549
624
  const versionedKey = `data-product:${dataProduct.data.id}:${dataProduct.data.version}`;
550
- acc[versionedKey] = buildDataProductNode(
625
+ acc[versionedKey] = withArchitectureDecisionsSection(
626
+ buildDataProductNode(dataProduct, owners, dataProductContext, flowRefsByDataProduct.get(versionedKey) || []),
551
627
  dataProduct,
552
- owners,
553
- dataProductContext,
554
- flowRefsByDataProduct.get(versionedKey) || []
628
+ adrs
555
629
  );
556
630
  if (dataProduct.data.latestVersion === dataProduct.data.version) {
557
631
  acc[`data-product:${dataProduct.data.id}`] = versionedKey;
@@ -561,17 +635,33 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
561
635
  {} as Record<string, NavNode | string>
562
636
  );
563
637
 
638
+ const adrNodes = adrsWithOwners.reduce(
639
+ (acc, { adr, owners, decisionMakers }) => {
640
+ const versionedKey = getAdrNodeKey(adr);
641
+ acc[versionedKey] = buildAdrNode(adr, owners, decisionMakers, context);
642
+ if (adr.data.latestVersion === adr.data.version) {
643
+ acc[getAdrAliasNodeKey(adr)] = versionedKey;
644
+ }
645
+ return acc;
646
+ },
647
+ {} as Record<string, NavNode | string>
648
+ );
649
+
564
650
  const entityNodes = entities.reduce(
565
651
  (acc, entity) => {
566
652
  const versionedKey = `entity:${entity.data.id}:${entity.data.version}`;
567
- acc[versionedKey] = {
568
- type: 'item',
569
- title: entity.data.name,
570
- badge: 'Entity',
571
- summary: entity.data.summary,
572
- icon: 'Box',
573
- href: buildUrl(`/docs/entities/${entity.data.id}/${entity.data.version}`),
574
- };
653
+ acc[versionedKey] = withArchitectureDecisionsSection(
654
+ {
655
+ type: 'item',
656
+ title: entity.data.name,
657
+ badge: 'Entity',
658
+ summary: entity.data.summary,
659
+ icon: 'Box',
660
+ href: buildUrl(`/docs/entities/${entity.data.id}/${entity.data.version}`),
661
+ },
662
+ entity,
663
+ adrs
664
+ );
575
665
  if (entity.data.latestVersion === entity.data.version) {
576
666
  acc[`entity:${entity.data.id}`] = versionedKey;
577
667
  }
@@ -593,13 +683,38 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
593
683
  {} as Record<string, NavNode>
594
684
  );
595
685
 
686
+ const diagramNodes = diagrams.reduce(
687
+ (acc, diagram) => {
688
+ const versionedKey = `diagram:${diagram.data.id}:${diagram.data.version}`;
689
+ acc[versionedKey] = withArchitectureDecisionsSection(
690
+ {
691
+ type: 'item',
692
+ title: diagram.data.name,
693
+ badge: 'Diagram',
694
+ href: buildUrl(`/diagrams/${diagram.data.id}/${diagram.data.version}`),
695
+ },
696
+ diagram,
697
+ adrs
698
+ );
699
+ if (diagram.data.latestVersion === diagram.data.version) {
700
+ acc[`diagram:${diagram.data.id}`] = versionedKey;
701
+ }
702
+ return acc;
703
+ },
704
+ {} as Record<string, NavNode | string>
705
+ );
706
+
596
707
  const userNodes = users.reduce(
597
708
  (acc, user) => {
598
- acc[`user:${user.data.id}`] = {
599
- type: 'item',
600
- title: user.data.name,
601
- href: buildUrl(`/docs/users/${user.data.id}`),
602
- };
709
+ acc[`user:${user.data.id}`] = withArchitectureDecisionsSection(
710
+ {
711
+ type: 'item',
712
+ title: user.data.name,
713
+ href: buildUrl(`/docs/users/${user.data.id}`),
714
+ },
715
+ user,
716
+ adrs
717
+ );
603
718
  return acc;
604
719
  },
605
720
  {} as Record<string, NavNode>
@@ -615,29 +730,33 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
615
730
  resourceDocs,
616
731
  resourceDocCategories
617
732
  );
618
- acc[versionedKey] = {
619
- type: 'item',
620
- title: channel.data.name,
621
- badge: 'Channel',
622
- summary: channel.data.summary,
623
- ...iconFieldsForResource(channel.data, 'ArrowRightLeft'),
624
- pages: [
625
- buildQuickReferenceSection(
626
- [
627
- {
628
- title: 'Overview',
629
- href: buildUrl(`/docs/${channel.collection}/${channel.data.id}/${channel.data.version}`),
630
- },
631
- isChangelogEnabled() &&
632
- shouldRenderSideBarSection(channel, 'changelog') && {
633
- title: 'Changelog',
634
- href: buildUrl(`/docs/${channel.collection}/${channel.data.id}/${channel.data.version}/changelog`),
733
+ acc[versionedKey] = withArchitectureDecisionsSection(
734
+ {
735
+ type: 'item',
736
+ title: channel.data.name,
737
+ badge: 'Channel',
738
+ summary: channel.data.summary,
739
+ ...iconFieldsForResource(channel.data, 'ArrowRightLeft'),
740
+ pages: [
741
+ buildQuickReferenceSection(
742
+ [
743
+ {
744
+ title: 'Overview',
745
+ href: buildUrl(`/docs/${channel.collection}/${channel.data.id}/${channel.data.version}`),
635
746
  },
636
- ].filter(Boolean) as { title: string; href: string }[]
637
- ),
638
- docsSection,
639
- ].filter(Boolean) as ChildRef[],
640
- };
747
+ isChangelogEnabled() &&
748
+ shouldRenderSideBarSection(channel, 'changelog') && {
749
+ title: 'Changelog',
750
+ href: buildUrl(`/docs/${channel.collection}/${channel.data.id}/${channel.data.version}/changelog`),
751
+ },
752
+ ].filter(Boolean) as { title: string; href: string }[]
753
+ ),
754
+ docsSection,
755
+ ].filter(Boolean) as ChildRef[],
756
+ },
757
+ channel,
758
+ adrs
759
+ );
641
760
 
642
761
  if (channel.data.latestVersion === channel.data.version) {
643
762
  // Store reference to versioned key instead of duplicating the full node
@@ -650,11 +769,15 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
650
769
 
651
770
  const teamNodes = teams.reduce(
652
771
  (acc, team) => {
653
- acc[`team:${team.data.id}`] = {
654
- type: 'item',
655
- title: team.data.name,
656
- href: buildUrl(`/docs/teams/${team.data.id}`),
657
- };
772
+ acc[`team:${team.data.id}`] = withArchitectureDecisionsSection(
773
+ {
774
+ type: 'item',
775
+ title: team.data.name,
776
+ href: buildUrl(`/docs/teams/${team.data.id}`),
777
+ },
778
+ team,
779
+ adrs
780
+ );
658
781
  return acc;
659
782
  },
660
783
  {} as Record<string, NavNode>
@@ -667,7 +790,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
667
790
  type: 'group',
668
791
  title: 'Domains',
669
792
  icon: 'Boxes',
670
- pages: rootDomains.map((domain) => `domain:${domain.data.id}:${domain.data.version}`),
793
+ pages: sortByResourceName(rootDomains).map((domain) => `domain:${domain.data.id}:${domain.data.version}`),
671
794
  };
672
795
  }
673
796
 
@@ -677,14 +800,21 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
677
800
  type: 'item',
678
801
  title: 'Domains',
679
802
  icon: 'Boxes',
680
- pages: domains.map((domain) => `domain:${domain.data.id}:${domain.data.version}`),
803
+ pages: sortByResourceName(domains).map((domain) => `domain:${domain.data.id}:${domain.data.version}`),
681
804
  });
682
805
 
683
806
  const agentsList = createLeaf(agents, {
684
807
  type: 'item',
685
808
  title: 'Agents',
686
809
  icon: 'Bot',
687
- pages: agents.map((agent) => `agent:${agent.data.id}:${agent.data.version}`),
810
+ pages: sortByResourceName(agents).map((agent) => `agent:${agent.data.id}:${agent.data.version}`),
811
+ });
812
+
813
+ const adrsList = createLeaf(adrs, {
814
+ type: 'item',
815
+ title: 'Decision Records',
816
+ icon: 'BookText',
817
+ pages: groupAdrsByStatus(adrs),
688
818
  });
689
819
 
690
820
  const internalServices = services.filter((service) => !service.data.externalSystem);
@@ -694,91 +824,93 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
694
824
  type: 'item',
695
825
  title: 'Services',
696
826
  icon: 'Server',
697
- pages: internalServices.map((service) => `service:${service.data.id}:${service.data.version}`),
827
+ pages: sortByResourceName(internalServices).map((service) => `service:${service.data.id}:${service.data.version}`),
698
828
  });
699
829
 
700
830
  const externalSystemsList = createLeaf(externalServices, {
701
831
  type: 'item',
702
832
  title: 'External Systems',
703
833
  icon: 'Globe',
704
- pages: externalServices.map((service) => `service:${service.data.id}:${service.data.version}`),
834
+ pages: sortByResourceName(externalServices).map((service) => `service:${service.data.id}:${service.data.version}`),
705
835
  });
706
836
 
707
837
  const eventsList = createLeaf(events, {
708
838
  type: 'group',
709
839
  title: 'Events',
710
840
  icon: 'Zap',
711
- pages: events.map((event) => `event:${event.data.id}:${event.data.version}`),
841
+ pages: sortByResourceName(events).map((event) => `event:${event.data.id}:${event.data.version}`),
712
842
  });
713
843
 
714
844
  const commandsList = createLeaf(commands, {
715
845
  type: 'group',
716
846
  title: 'Commands',
717
847
  icon: 'Terminal',
718
- pages: commands.map((command) => `command:${command.data.id}:${command.data.version}`),
848
+ pages: sortByResourceName(commands).map((command) => `command:${command.data.id}:${command.data.version}`),
719
849
  });
720
850
 
721
851
  const queriesList = createLeaf(queries, {
722
852
  type: 'group',
723
853
  title: 'Queries',
724
854
  icon: 'Search',
725
- pages: queries.map((query) => `query:${query.data.id}:${query.data.version}`),
855
+ pages: sortByResourceName(queries).map((query) => `query:${query.data.id}:${query.data.version}`),
726
856
  });
727
857
 
728
858
  const flowsList = createLeaf(flows, {
729
859
  type: 'item',
730
860
  title: 'Flows',
731
861
  icon: 'Waypoints',
732
- pages: flows.map((flow) => `flow:${flow.data.id}:${flow.data.version}`),
862
+ pages: sortByResourceName(flows).map((flow) => `flow:${flow.data.id}:${flow.data.version}`),
733
863
  });
734
864
 
735
865
  const containersList = createLeaf(containers, {
736
866
  type: 'item',
737
867
  title: 'Data Stores',
738
868
  icon: 'Database',
739
- pages: containers.map((container) => `container:${container.data.id}:${container.data.version}`),
869
+ pages: sortByResourceName(containers).map((container) => `container:${container.data.id}:${container.data.version}`),
740
870
  });
741
871
 
742
872
  const dataProductsList = createLeaf(dataProducts, {
743
873
  type: 'item',
744
874
  title: 'Data Products',
745
875
  icon: 'Package',
746
- pages: dataProducts.map((dataProduct) => `data-product:${dataProduct.data.id}:${dataProduct.data.version}`),
876
+ pages: sortByResourceName(dataProducts).map(
877
+ (dataProduct) => `data-product:${dataProduct.data.id}:${dataProduct.data.version}`
878
+ ),
747
879
  });
748
880
 
749
881
  const entitiesList = createLeaf(entities, {
750
882
  type: 'item',
751
883
  title: 'Entities',
752
884
  icon: 'Box',
753
- pages: entities.map((entity) => `entity:${entity.data.id}:${entity.data.version}`),
885
+ pages: sortByResourceName(entities).map((entity) => `entity:${entity.data.id}:${entity.data.version}`),
754
886
  });
755
887
 
756
888
  const designsList = createLeaf(designs, {
757
889
  type: 'item',
758
890
  title: 'Designs',
759
891
  icon: 'SquareMousePointer',
760
- pages: designs.map((design) => `design:${design.data.id}`),
892
+ pages: sortByResourceName(designs).map((design) => `design:${design.data.id}`),
761
893
  });
762
894
 
763
895
  const teamsList = createLeaf(teams, {
764
896
  type: 'group',
765
897
  title: 'Teams',
766
898
  icon: 'Users',
767
- pages: teams.map((team) => `team:${team.data.id}`),
899
+ pages: sortByResourceName(teams).map((team) => `team:${team.data.id}`),
768
900
  });
769
901
 
770
902
  const usersList = createLeaf(users, {
771
903
  type: 'group',
772
904
  title: 'Users',
773
905
  icon: 'User',
774
- pages: users.map((user) => `user:${user.data.id}`),
906
+ pages: sortByResourceName(users).map((user) => `user:${user.data.id}`),
775
907
  });
776
908
 
777
909
  const channelList = createLeaf(channels, {
778
910
  type: 'item',
779
911
  title: 'Channels',
780
912
  icon: 'ArrowRightLeft',
781
- pages: channels.map((channel) => `channel:${channel.data.id}:${channel.data.version}`),
913
+ pages: sortByResourceName(channels).map((channel) => `channel:${channel.data.id}:${channel.data.version}`),
782
914
  });
783
915
 
784
916
  const messagesChildren = ['list:events', 'list:commands', 'list:queries'].filter(
@@ -811,6 +943,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
811
943
  'list:domains',
812
944
  'list:services',
813
945
  'list:agents',
946
+ 'list:adrs',
814
947
  'list:external-systems',
815
948
  'list:messages',
816
949
  'list:channels',
@@ -825,6 +958,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
825
958
  domainsList,
826
959
  servicesList,
827
960
  agentsList,
961
+ adrsList,
828
962
  externalSystemsList,
829
963
  messagesList,
830
964
  channelList,
@@ -836,7 +970,11 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
836
970
  peopleList,
837
971
  ];
838
972
 
839
- const validAllChildren = allChildrenKeys.filter((_, idx) => allChildrenNodes[idx] !== undefined);
973
+ const validAllChildren = allChildrenKeys
974
+ .map((key, idx) => ({ key, node: allChildrenNodes[idx] }))
975
+ .filter((item): item is { key: string; node: NavNode } => item.node !== undefined)
976
+ .sort((a, b) => a.node.title.localeCompare(b.node.title))
977
+ .map((item) => item.key);
840
978
 
841
979
  let allList;
842
980
  if (validAllChildren.length > 0) {
@@ -852,6 +990,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
852
990
  ...(domainsList ? { 'list:domains': domainsList } : {}),
853
991
  ...(servicesList ? { 'list:services': servicesList } : {}),
854
992
  ...(agentsList ? { 'list:agents': agentsList } : {}),
993
+ ...(adrsList ? { 'list:adrs': adrsList } : {}),
855
994
  ...(externalSystemsList ? { 'list:external-systems': externalSystemsList } : {}),
856
995
  ...(eventsList ? { 'list:events': eventsList } : {}),
857
996
  ...(commandsList ? { 'list:commands': commandsList } : {}),
@@ -892,6 +1031,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
892
1031
  ...rootDomainsNodes,
893
1032
  ...domainNodes,
894
1033
  ...agentNodes,
1034
+ ...adrNodes,
895
1035
  ...serviceNodes,
896
1036
  ...messageNodes,
897
1037
  ...channelNodes,
@@ -901,6 +1041,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
901
1041
  ...flowNodes,
902
1042
  ...userNodes,
903
1043
  ...teamNodes,
1044
+ ...diagramNodes,
904
1045
  ...designNodes,
905
1046
  ...systemNode,
906
1047
  ...allNodes,
@@ -1,5 +1,6 @@
1
1
  export type CollectionTypes =
2
2
  | 'agents'
3
+ | 'adrs'
3
4
  | 'commands'
4
5
  | 'events'
5
6
  | 'queries'
@@ -15,6 +16,7 @@ export type CollectionMessageTypes = 'commands' | 'events' | 'queries';
15
16
  export type CollectionUserTypes = 'users' | 'teams';
16
17
  export type PageTypes =
17
18
  | 'agents'
19
+ | 'adrs'
18
20
  | 'events'
19
21
  | 'commands'
20
22
  | 'queries'
@@ -36,6 +36,8 @@ export const getColorForCollection = (collection: string): CollectionColor => {
36
36
  return 'yellow';
37
37
  case 'agents':
38
38
  return 'sky';
39
+ case 'adrs':
40
+ return 'purple';
39
41
  case 'services':
40
42
  return 'pink';
41
43
  case 'data-products':
@@ -0,0 +1,53 @@
1
+ export const ADR_STATUS = {
2
+ PROPOSED: 'proposed',
3
+ ACCEPTED: 'accepted',
4
+ REJECTED: 'rejected',
5
+ DEPRECATED: 'deprecated',
6
+ SUPERSEDED: 'superseded',
7
+ } as const;
8
+
9
+ export const ADR_STATUS_VALUES = [
10
+ ADR_STATUS.PROPOSED,
11
+ ADR_STATUS.ACCEPTED,
12
+ ADR_STATUS.REJECTED,
13
+ ADR_STATUS.DEPRECATED,
14
+ ADR_STATUS.SUPERSEDED,
15
+ ] as const;
16
+
17
+ export type AdrStatus = (typeof ADR_STATUS)[keyof typeof ADR_STATUS];
18
+
19
+ export const adrStatusBadgeColor: Record<AdrStatus, string> = {
20
+ [ADR_STATUS.PROPOSED]: 'amber',
21
+ [ADR_STATUS.ACCEPTED]: 'green',
22
+ [ADR_STATUS.REJECTED]: 'red',
23
+ [ADR_STATUS.DEPRECATED]: 'gray',
24
+ [ADR_STATUS.SUPERSEDED]: 'purple',
25
+ };
26
+
27
+ export const isAdrCollection = (collection: string | undefined): collection is 'adrs' => collection === 'adrs';
28
+
29
+ export const hasAdrStatus = (adr: { data?: { status?: string } }, status: AdrStatus) => adr.data?.status === status;
30
+
31
+ export const isDeprecatedAdr = (adr: { data?: { status?: string } }) => hasAdrStatus(adr, ADR_STATUS.DEPRECATED);
32
+
33
+ export const isSupersededAdr = (adr: { data?: { status?: string } }) => hasAdrStatus(adr, ADR_STATUS.SUPERSEDED);
34
+
35
+ export const formatAdrStatus = (status: AdrStatus) =>
36
+ status
37
+ .split('-')
38
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
39
+ .join(' ');
40
+
41
+ export const formatAdrDate = (date: Date) =>
42
+ new Intl.DateTimeFormat('en-US', {
43
+ timeZone: 'UTC',
44
+ year: 'numeric',
45
+ month: 'long',
46
+ day: 'numeric',
47
+ }).format(date);
48
+
49
+ export const createAdrStatusBadge = (status: AdrStatus) => ({
50
+ content: formatAdrStatus(status),
51
+ backgroundColor: adrStatusBadgeColor[status],
52
+ textColor: adrStatusBadgeColor[status],
53
+ });