@eventcatalog/core 2.4.0 → 2.5.1

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 (44) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +8 -1
  3. package/bin/dist/eventcatalog.cjs +5 -4
  4. package/bin/dist/eventcatalog.js +5 -4
  5. package/package.json +8 -6
  6. package/scripts/catalog-to-astro-content-directory.js +32 -1
  7. package/scripts/default-files-for-collections/flows.md +11 -0
  8. package/scripts/default-files-for-collections/pages.md +1 -0
  9. package/scripts/watcher.js +1 -2
  10. package/src/components/DocsNavigation.astro +5 -1
  11. package/src/components/MDX/Flow/Flow.astro +63 -0
  12. package/src/components/MDX/NodeGraph/NodeGraph.astro +12 -0
  13. package/src/components/MDX/NodeGraph/NodeGraph.tsx +75 -33
  14. package/src/components/MDX/NodeGraph/Nodes/ExternalSystem.tsx +79 -0
  15. package/src/components/MDX/NodeGraph/Nodes/Service.tsx +0 -12
  16. package/src/components/MDX/NodeGraph/Nodes/Step.tsx +69 -0
  17. package/src/components/MDX/NodeGraph/Nodes/User.tsx +79 -0
  18. package/src/components/MDX/components.tsx +2 -0
  19. package/src/components/SideBars/DomainSideBar.astro +1 -1
  20. package/src/components/Tables/columns/FlowTableColumns.tsx +82 -0
  21. package/src/components/Tables/columns/index.tsx +3 -0
  22. package/src/content/config.ts +65 -5
  23. package/src/layouts/DiscoverLayout.astro +11 -1
  24. package/src/layouts/VisualiserLayout.astro +33 -22
  25. package/src/pages/discover/[type]/index.astro +3 -0
  26. package/src/pages/docs/[type]/[id]/[version]/index.astro +12 -3
  27. package/src/pages/docs/teams/[id]/index.astro +14 -0
  28. package/src/pages/docs/users/[id]/index.astro +23 -4
  29. package/src/pages/visualiser/[type]/[id]/[version]/index.astro +9 -2
  30. package/src/types/index.ts +1 -1
  31. package/src/utils/collections/util.ts +22 -0
  32. package/src/utils/commands/node-graph.ts +13 -2
  33. package/src/utils/config/catalog.ts +1 -0
  34. package/src/utils/domains/domains.ts +3 -5
  35. package/src/utils/domains/node-graph.ts +28 -9
  36. package/src/utils/events/node-graph.ts +13 -2
  37. package/src/utils/flows/flows.ts +59 -0
  38. package/src/utils/flows/node-graph.ts +153 -0
  39. package/src/utils/services/node-graph.ts +16 -5
  40. package/src/utils/services/services.ts +3 -26
  41. package/src/utils/teams.ts +7 -1
  42. package/src/utils/users.ts +8 -0
  43. package/src/utils/versions/versions.ts +26 -0
  44. package/tailwind.config.mjs +1 -0
@@ -0,0 +1,69 @@
1
+ import { EnvelopeIcon } from '@heroicons/react/16/solid';
2
+ import type { CollectionEntry } from 'astro:content';
3
+ import { Handle } from 'reactflow';
4
+
5
+ interface Data {
6
+ title: string;
7
+ label: string;
8
+ bgColor: string;
9
+ color: string;
10
+ mode: 'simple' | 'full';
11
+ step: { id: string; title: string; summary: string };
12
+ showTarget?: boolean;
13
+ showSource?: boolean;
14
+ }
15
+
16
+ function classNames(...classes: any) {
17
+ return classes.filter(Boolean).join(' ');
18
+ }
19
+
20
+ export default function StepNode({ data, sourcePosition, targetPosition }: any) {
21
+ const { mode, step, showTarget = true, showSource = true } = data as Data;
22
+
23
+ const { title, summary } = step;
24
+
25
+ const renderTarget = showTarget || true;
26
+ const renderSource = showSource || true;
27
+
28
+ return (
29
+ <div className={classNames('w-full rounded-md border flex justify-start bg-white text-black border-blue-400 min-h-[3em]')}>
30
+ <div
31
+ className={classNames(
32
+ 'bg-gradient-to-b from-gray-700 to-gray-700 relative flex items-center w-5 justify-center rounded-l-sm text-orange-100-500',
33
+ `border-r-[1px] border-gray-500`
34
+ )}
35
+ >
36
+ {mode === 'full' && (
37
+ <span className="rotate -rotate-90 w-1/2 text-center absolute bottom-1 text-[9px] text-white font-bold uppercase tracking-[3px] ">
38
+ Step
39
+ </span>
40
+ )}
41
+ </div>
42
+ <div className="p-1 min-w-60 max-w-[min-content]">
43
+ {renderTarget && <Handle type="target" position={targetPosition} />}
44
+ {renderSource && <Handle type="source" position={sourcePosition} />}
45
+
46
+ {!summary && (
47
+ <div className="h-full flex items-center">
48
+ <span className="text-sm font-bold block pb-0.5">{title}</span>
49
+ </div>
50
+ )}
51
+
52
+ {summary && (
53
+ <>
54
+ <div className={classNames(mode === 'full' ? `border-b border-gray-200` : '')}>
55
+ <span className="text-xs font-bold block pb-0.5">{title}</span>
56
+ </div>
57
+ {mode === 'full' && (
58
+ <div className="divide-y divide-gray-200 ">
59
+ <div className="leading-3 py-1">
60
+ <span className="text-[8px] font-light">{summary}</span>
61
+ </div>
62
+ </div>
63
+ )}
64
+ </>
65
+ )}
66
+ </div>
67
+ </div>
68
+ );
69
+ }
@@ -0,0 +1,79 @@
1
+ import { UserIcon } from '@heroicons/react/20/solid';
2
+ import { Handle } from 'reactflow';
3
+
4
+ interface Data {
5
+ title: string;
6
+ label: string;
7
+ bgColor: string;
8
+ color: string;
9
+ mode: 'simple' | 'full';
10
+ step: { id: string; title: string; summary: string; name: string; actor: { name: string } };
11
+ showTarget?: boolean;
12
+ showSource?: boolean;
13
+ }
14
+
15
+ function classNames(...classes: any) {
16
+ return classes.filter(Boolean).join(' ');
17
+ }
18
+
19
+ export default function UserNode({ data, sourcePosition, targetPosition }: any) {
20
+ const { mode, step, showTarget = true, showSource = true } = data as Data;
21
+
22
+ const { summary, actor: { name } = {} } = step;
23
+
24
+ const renderTarget = showTarget || true;
25
+ const renderSource = showSource || true;
26
+
27
+ return (
28
+ <div
29
+ className={classNames(
30
+ `w-full rounded-md border flex justify-start bg-white text-black border-yellow-400`,
31
+ mode === 'full' ? 'min-h-[5em]' : 'min-h-[2em]'
32
+ )}
33
+ >
34
+ <div
35
+ className={classNames(
36
+ 'bg-gradient-to-b from-yellow-400 to-yellow-600 relative flex items-center w-5 justify-center rounded-l-sm text-orange-100-500',
37
+ `border-r-[1px] border-yellow-500`
38
+ )}
39
+ >
40
+ <UserIcon className="w-4 h-4 opacity-90 text-white absolute top-1 " />
41
+ {mode === 'full' && (
42
+ <span className="rotate -rotate-90 w-1/2 text-center absolute bottom-1 text-[9px] text-white font-bold uppercase tracking-[3px] ">
43
+ ACTOR
44
+ </span>
45
+ )}
46
+ </div>
47
+ <div className="p-1 min-w-60 max-w-[min-content]">
48
+ {renderTarget && <Handle type="target" position={targetPosition} />}
49
+ {renderSource && <Handle type="source" position={sourcePosition} />}
50
+
51
+ {(!summary || mode !== 'full') && (
52
+ <div className="h-full ">
53
+ <span className="text-sm font-bold block pb-0.5 block w-full">{name}</span>
54
+ {mode === 'simple' && (
55
+ <div className="w-full text-right">
56
+ <span className=" w-full text-[10px] text-gray-500 font-light block pt-0.5 pb-0.5 ">Event</span>
57
+ </div>
58
+ )}
59
+ </div>
60
+ )}
61
+
62
+ {summary && mode === 'full' && (
63
+ <>
64
+ <div className={classNames(mode === 'full' ? `border-b border-gray-200` : '')}>
65
+ <span className="text-xs font-bold block pb-0.5">{name}</span>
66
+ </div>
67
+ {mode === 'full' && (
68
+ <div className="divide-y divide-gray-200 ">
69
+ <div className="leading-3 py-1">
70
+ <span className="text-[8px] font-light">{summary}</span>
71
+ </div>
72
+ </div>
73
+ )}
74
+ </>
75
+ )}
76
+ </div>
77
+ </div>
78
+ );
79
+ }
@@ -3,6 +3,7 @@ import Schema from '@components/MDX/Schema';
3
3
  import File from '@components/MDX/File';
4
4
  import Accordion from '@components/MDX/Accordion/Accordion.astro';
5
5
  import AccordionGroup from '@components/MDX/Accordion/AccordionGroup.astro';
6
+ import Flow from '@components/MDX/Flow/Flow.astro';
6
7
  import Admonition from '@components/MDX/Admonition';
7
8
  import OpenAPI from '@components/MDX/OpenAPI/OpenAPI';
8
9
 
@@ -14,6 +15,7 @@ const components = (props: any) => {
14
15
  return {
15
16
  Accordion,
16
17
  AccordionGroup,
18
+ Flow,
17
19
  Admonition: (mdxProp: any) => <Admonition {...mdxProp} {...props} />,
18
20
  File: (mdxProp: any) => File({ ...props, ...mdxProp }),
19
21
  NodeGraph: (mdxProp: any) => NodeGraphPortal({ ...props.data, ...mdxProp }),
@@ -42,7 +42,7 @@ const ownersList = owners.map((o) => ({
42
42
  client:load
43
43
  />
44
44
  <OwnersList
45
- title={`Service owners (${ownersList.length})`}
45
+ title={`Domain owners (${ownersList.length})`}
46
46
  owners={ownersList}
47
47
  emptyMessage={`This domain does not have any documented owners.`}
48
48
  client:load
@@ -0,0 +1,82 @@
1
+ import { ServerIcon } from '@heroicons/react/20/solid';
2
+ import { RectangleGroupIcon } from '@heroicons/react/20/solid';
3
+ import { createColumnHelper } from '@tanstack/react-table';
4
+ import type { CollectionEntry } from 'astro:content';
5
+ import { filterByName, filterCollectionByName } from '../filters/custom-filters';
6
+ import { buildUrl } from '@utils/url-builder';
7
+ import { QueueListIcon } from '@heroicons/react/24/solid';
8
+
9
+ const columnHelper = createColumnHelper<CollectionEntry<'flows'>>();
10
+
11
+ export const columns = () => [
12
+ columnHelper.accessor('data.name', {
13
+ id: 'name',
14
+ header: () => <span>Flow</span>,
15
+ cell: (info) => {
16
+ const flowRaw = info.row.original;
17
+ const color = 'teal';
18
+ return (
19
+ <div className=" group ">
20
+ <a
21
+ href={buildUrl(`/docs/${flowRaw.collection}/${flowRaw.data.id}/${flowRaw.data.version}`)}
22
+ className={`group-hover:text-${color}-500 flex space-x-1 items-center`}
23
+ >
24
+ <div className={`flex items-center border border-gray-300 shadow-sm rounded-md group-hover:border-${color}-400`}>
25
+ <span className="flex items-center">
26
+ <span className={`bg-${color}-500 group-hover:bg-${color}-600 h-full rounded-tl rounded-bl p-1`}>
27
+ <QueueListIcon className="h-4 w-4 text-white" />
28
+ </span>
29
+ <span className="leading-none px-2 group-hover:underline group-hover:text-purple-500 font-light">
30
+ {flowRaw.data.name} (v{flowRaw.data.version})
31
+ </span>
32
+ </span>
33
+ </div>
34
+ </a>
35
+ </div>
36
+ );
37
+ },
38
+ footer: (info) => info.column.id,
39
+ meta: {
40
+ filterVariant: 'name',
41
+ },
42
+ filterFn: filterByName,
43
+ }),
44
+ columnHelper.accessor('data.version', {
45
+ header: () => <span>Version</span>,
46
+ cell: (info) => {
47
+ const service = info.row.original;
48
+ return (
49
+ <div className="text-left font-light">{`v${info.getValue()} ${service.data.latestVersion === service.data.version ? '(latest)' : ''}`}</div>
50
+ );
51
+ },
52
+ footer: (info) => info.column.id,
53
+ }),
54
+ columnHelper.accessor('data.summary', {
55
+ id: 'summary',
56
+ header: () => 'Summary',
57
+ cell: (info) => <span className="font-light ">{info.renderValue()}</span>,
58
+ footer: (info) => info.column.id,
59
+ meta: {
60
+ showFilter: false,
61
+ className: 'max-w-md',
62
+ },
63
+ }),
64
+ columnHelper.accessor('data.name', {
65
+ header: () => <span />,
66
+ cell: (info) => {
67
+ const domain = info.row.original;
68
+ return (
69
+ <a
70
+ className="hover:text-purple-500 hover:underline px-4 font-light"
71
+ href={buildUrl(`/visualiser/${domain.collection}/${domain.data.id}/${domain.data.version}`)}
72
+ >
73
+ Visualiser &rarr;
74
+ </a>
75
+ );
76
+ },
77
+ id: 'actions',
78
+ meta: {
79
+ showFilter: false,
80
+ },
81
+ }),
82
+ ];
@@ -1,6 +1,7 @@
1
1
  import { columns as MessageTableColumns } from './MessageTableColumns';
2
2
  import { columns as ServiceTableColumns } from './ServiceTableColumns';
3
3
  import { columns as DomainTableColumns } from './DomainTableColumns';
4
+ import { columns as FlowTableColumns } from './FlowTableColumns';
4
5
 
5
6
  export const getColumnsByCollection = (collection: string): any => {
6
7
  switch (collection) {
@@ -11,6 +12,8 @@ export const getColumnsByCollection = (collection: string): any => {
11
12
  return ServiceTableColumns();
12
13
  case 'domains':
13
14
  return DomainTableColumns();
15
+ case 'flows':
16
+ return FlowTableColumns();
14
17
  default:
15
18
  return [];
16
19
  }
@@ -13,6 +13,11 @@ const pages = defineCollection({
13
13
  }),
14
14
  });
15
15
 
16
+ const pointer = z.object({
17
+ id: z.string(),
18
+ version: z.string().optional().default('latest'),
19
+ });
20
+
16
21
  const changelogs = defineCollection({
17
22
  type: 'content',
18
23
  schema: z.object({
@@ -58,6 +63,63 @@ const baseSchema = z.object({
58
63
  .optional(),
59
64
  });
60
65
 
66
+ const flowStep = z
67
+ .union([
68
+ // Can be a string or a number just to reference a step
69
+ z.union([z.string(), z.number()]),
70
+ z
71
+ .object({
72
+ id: z.union([z.string(), z.number()]),
73
+ label: z.string().optional(),
74
+ })
75
+ .optional(),
76
+ ])
77
+ .optional();
78
+
79
+ const flows = defineCollection({
80
+ type: 'content',
81
+ schema: z
82
+ .object({
83
+ steps: z.array(
84
+ z
85
+ .object({
86
+ id: z.union([z.string(), z.number()]),
87
+ type: z.enum(['node', 'message', 'user', 'actor']).optional(),
88
+ title: z.string(),
89
+ summary: z.string().optional(),
90
+ message: pointer.optional(),
91
+ service: pointer.optional(),
92
+ actor: z
93
+ .object({
94
+ name: z.string(),
95
+ })
96
+ .optional(),
97
+ externalSystem: z
98
+ .object({
99
+ name: z.string(),
100
+ summary: z.string().optional(),
101
+ url: z.string().url().optional(),
102
+ })
103
+ .optional(),
104
+ next_step: flowStep,
105
+ next_steps: z.array(flowStep).optional(),
106
+ })
107
+ .refine((data) => {
108
+ if (!data.message && !data.service && !data.actor) return true;
109
+ // Cant have both next_steps and next_steps
110
+ if (data.next_step && data.next_steps) return false;
111
+ // Either message or service or actor must be present, but not all
112
+ return (
113
+ (data.message && !data.service && !data.actor) ||
114
+ (!data.message && data.service) ||
115
+ (data.actor && !data.message && !data.service)
116
+ );
117
+ })
118
+ ),
119
+ })
120
+ .merge(baseSchema),
121
+ });
122
+
61
123
  const events = defineCollection({
62
124
  type: 'content',
63
125
  schema: z
@@ -78,11 +140,6 @@ const commands = defineCollection({
78
140
  .merge(baseSchema),
79
141
  });
80
142
 
81
- const pointer = z.object({
82
- id: z.string(),
83
- version: z.string().optional().default('latest'),
84
- });
85
-
86
143
  const services = defineCollection({
87
144
  type: 'content',
88
145
  schema: z
@@ -112,6 +169,7 @@ const users = defineCollection({
112
169
  hidden: z.boolean().optional(),
113
170
  email: z.string().optional(),
114
171
  slackDirectMessageUrl: z.string().optional(),
172
+ ownedDomains: z.array(reference('domains')).optional(),
115
173
  ownedServices: z.array(reference('services')).optional(),
116
174
  ownedEvents: z.array(reference('events')).optional(),
117
175
  ownedCommands: z.array(reference('commands')).optional(),
@@ -130,6 +188,7 @@ const teams = defineCollection({
130
188
  slackDirectMessageUrl: z.string().optional(),
131
189
  members: z.array(reference('users')).optional(),
132
190
  ownedCommands: z.array(reference('commands')).optional(),
191
+ ownedDomains: z.array(reference('domains')).optional(),
133
192
  ownedServices: z.array(reference('services')).optional(),
134
193
  ownedEvents: z.array(reference('events')).optional(),
135
194
  }),
@@ -142,6 +201,7 @@ export const collections = {
142
201
  users,
143
202
  teams,
144
203
  domains,
204
+ flows,
145
205
  pages,
146
206
  changelogs,
147
207
  };
@@ -1,11 +1,12 @@
1
1
  ---
2
2
  import { Table } from '@components/Tables/Table';
3
- import { RectangleGroupIcon } from '@heroicons/react/24/outline';
3
+ import { QueueListIcon, RectangleGroupIcon } from '@heroicons/react/24/outline';
4
4
  import EnvelopeIcon from '@heroicons/react/24/outline/EnvelopeIcon';
5
5
  import ServerIcon from '@heroicons/react/24/outline/ServerIcon';
6
6
  import PlainPage from '@layouts/PlainPage.astro';
7
7
  import { getCommands } from '@utils/commands';
8
8
  import { getDomains } from '@utils/domains/domains';
9
+ import { getFlows } from '@utils/flows/flows';
9
10
  import { getEvents } from '@utils/events';
10
11
  import { getServices } from '@utils/services/services';
11
12
  import { buildUrl } from '@utils/url-builder';
@@ -14,6 +15,7 @@ const events = await getEvents();
14
15
  const commands = await getCommands();
15
16
  const services = await getServices();
16
17
  const domains = await getDomains();
18
+ const flows = await getFlows();
17
19
 
18
20
  const { title, subtitle, data, type } = Astro.props;
19
21
  const currentPath = Astro.url.pathname;
@@ -51,6 +53,14 @@ const tabs = [
51
53
  activeColor: 'yellow',
52
54
  enabled: domains.length > 0,
53
55
  },
56
+ {
57
+ label: `Flows (${flows.length})`,
58
+ href: buildUrl('/discover/flows'),
59
+ isActive: currentPath === '/discover/flows',
60
+ icon: QueueListIcon,
61
+ activeColor: 'teal',
62
+ enabled: flows.length > 0,
63
+ },
54
64
  ];
55
65
  ---
56
66
 
@@ -1,29 +1,36 @@
1
1
  ---
2
2
  import BasicList from '@components/Lists/BasicList';
3
3
  import PlainPage from '@layouts/PlainPage.astro';
4
- import type { CollectionTypes } from '@types';
5
4
  import { getCommands } from '@utils/commands';
6
5
  import { getDomains } from '@utils/domains/domains';
7
6
  import { getEvents } from '@utils/events';
7
+ import { getFlows } from '@utils/flows/flows';
8
8
  import { getServices } from '@utils/services/services';
9
9
  import { buildUrl } from '@utils/url-builder';
10
- import type { CollectionEntry } from 'astro:content';
11
10
  import { ViewTransitions } from 'astro:transitions';
12
11
 
13
- const [services, events, commands, domains] = await Promise.all([getServices(), getEvents(), getCommands(), getDomains()]);
12
+ const [services, events, commands, domains, flows] = await Promise.all([
13
+ getServices(),
14
+ getEvents(),
15
+ getCommands(),
16
+ getDomains(),
17
+ getFlows(),
18
+ ]);
14
19
 
15
20
  // @ts-ignore for large catalogs https://github.com/event-catalog/eventcatalog/issues/552
16
- const navItems = [...domains, ...services, ...events, ...commands];
21
+ const navItems = [...domains, ...services, ...events, ...commands, ...flows];
17
22
 
18
- const navigation = navItems.reduce((acc, item) => {
19
- // @ts-ignore
20
- const group = acc[item.collection] || [];
23
+ const navigation = navItems
24
+ .filter((item) => item.data.version === item.data.latestVersion)
25
+ .reduce((acc, item) => {
26
+ // @ts-ignore
27
+ const group = acc[item.collection] || [];
21
28
 
22
- return {
23
- ...acc,
24
- [item.collection]: [...group, item],
25
- };
26
- }, {}) as any;
29
+ return {
30
+ ...acc,
31
+ [item.collection]: [...group, item],
32
+ };
33
+ }, {}) as any;
27
34
 
28
35
  const currentPath = Astro.url.pathname;
29
36
  const { title, description } = Astro.props;
@@ -53,16 +60,20 @@ const getColor = (collection: string) => {
53
60
  >
54
61
  {
55
62
  Object.keys(navigation).map((key: any) => {
56
- const items = navigation[key].map((item: any) => {
57
- const isCurrent = currentPath.includes(`${item.collection}/${item.data.id}/${item.data.version}`);
58
- return {
59
- label: item.data.name,
60
- version: item.data.version,
61
- color: getColor(item.collection),
62
- href: buildUrl(`/visualiser/${item.collection}/${item.data.id}/${item.data.version}`),
63
- active: isCurrent,
64
- };
65
- });
63
+ const items = navigation[key]
64
+ .map((item: any) => {
65
+ const isCurrent = currentPath.includes(`${item.collection}/${item.data.id}/${item.data.version}`);
66
+ const isLatest = item.data.version === item.data.latestVersion;
67
+ if (!isLatest) return null;
68
+ return {
69
+ label: item.data.name,
70
+ version: item.data.version,
71
+ color: getColor(item.collection),
72
+ href: buildUrl(`/visualiser/${item.collection}/${item.data.id}/${item.data.version}`),
73
+ active: isCurrent,
74
+ };
75
+ })
76
+ .filter((n: any) => n !== null);
66
77
  return (
67
78
  <BasicList
68
79
  title={`${key} (${navigation[key].length})`}
@@ -6,12 +6,14 @@ import type { CollectionTypes } from '@types';
6
6
  import { getCommands } from '@utils/commands';
7
7
  import { getServices } from '@utils/services/services';
8
8
  import { getDomains } from '@utils/domains/domains';
9
+ import { getFlows } from '@utils/flows/flows';
9
10
 
10
11
  export async function getStaticPaths() {
11
12
  const events = await getEvents();
12
13
  const commands = await getCommands();
13
14
  const services = await getServices();
14
15
  const domains = await getDomains();
16
+ const flows = await getFlows();
15
17
 
16
18
  const buildPage = (type: string, collection: CollectionEntry<CollectionTypes>[]) => {
17
19
  return {
@@ -30,6 +32,7 @@ export async function getStaticPaths() {
30
32
  buildPage('commands', commands),
31
33
  buildPage('services', services),
32
34
  buildPage('domains', domains),
35
+ buildPage('flows', flows),
33
36
  ];
34
37
  }
35
38
 
@@ -5,6 +5,7 @@ import Footer from '@layouts/Footer.astro';
5
5
 
6
6
  import components from '@components/MDX/components';
7
7
  import NodeGraph from '@components/MDX/NodeGraph/NodeGraph.astro';
8
+ import SchemaViewer from '@components/MDX/SchemaViewer/SchemaViewer.astro';
8
9
 
9
10
  // SideBars
10
11
  import ServiceSideBar from '@components/SideBars/ServiceSideBar.astro';
@@ -13,18 +14,20 @@ import MessageSideBar from '@components/SideBars/MessageSideBar.astro';
13
14
  import { getEvents } from '@utils/events';
14
15
  import { getServices } from '@utils/services/services';
15
16
  import { getCommands } from '@utils/commands';
16
- import { EnvelopeIcon, PencilIcon, RectangleGroupIcon, ServerIcon } from '@heroicons/react/24/outline';
17
+ import { EnvelopeIcon, PencilIcon, QueueListIcon, RectangleGroupIcon, ServerIcon } from '@heroicons/react/24/outline';
17
18
  import { getDomains } from '@utils/domains/domains';
18
19
  import DomainSideBar from '@components/SideBars/DomainSideBar.astro';
19
20
  import type { CollectionTypes } from '@types';
20
- import SchemaViewer from '@components/MDX/SchemaViewer/SchemaViewer.astro';
21
+
21
22
  import { buildUrl } from '@utils/url-builder';
23
+ import { getFlows } from '@utils/flows/flows';
22
24
 
23
25
  export async function getStaticPaths() {
24
26
  const events = await getEvents();
25
27
  const commands = await getCommands();
26
28
  const services = await getServices();
27
29
  const domains = await getDomains();
30
+ const flows = await getFlows();
28
31
 
29
32
  const buildPages = (collection: CollectionEntry<CollectionTypes>[]) => {
30
33
  return collection.map((item) => ({
@@ -40,7 +43,7 @@ export async function getStaticPaths() {
40
43
  }));
41
44
  };
42
45
 
43
- return [...buildPages(domains), ...buildPages(events), ...buildPages(services), ...buildPages(commands)];
46
+ return [...buildPages(domains), ...buildPages(events), ...buildPages(services), ...buildPages(commands), ...buildPages(flows)];
44
47
  }
45
48
 
46
49
  const props = Astro.props;
@@ -70,6 +73,12 @@ const getBadge = () => {
70
73
  class: 'text-yellow-400',
71
74
  };
72
75
  }
76
+
77
+ if (props.collection === 'flows') {
78
+ return { backgroundColor: 'teal', textColor: 'teal', content: 'Flow', icon: QueueListIcon, class: 'text-gray' };
79
+ }
80
+
81
+ return { backgroundColor: 'teal', textColor: 'teal', content: '', icon: QueueListIcon, class: 'text-gray' };
73
82
  };
74
83
 
75
84
  const badges = [getBadge(), ...contentBadges];
@@ -34,6 +34,7 @@ const { Content } = await render();
34
34
  const membersRaw = props.data.members || [];
35
35
  const members = await Promise.all(membersRaw.map((m) => getEntry(m)));
36
36
 
37
+ const domains = props.data.ownedDomains as CollectionEntry<'domains'>[];
37
38
  const services = props.data.ownedServices as CollectionEntry<'services'>[];
38
39
  const events = props.data.ownedEvents as CollectionEntry<'events'>[];
39
40
  const commands = props.data.ownedCommands as CollectionEntry<'commands'>[];
@@ -46,6 +47,12 @@ const membersList = members.map((o) => ({
46
47
  href: buildUrl(`/docs/${o.collection}/${o.data.id}`),
47
48
  }));
48
49
 
50
+ const ownedDomainsList = domains.map((p) => ({
51
+ label: `${p.data.name}`,
52
+ href: buildUrl(`/docs/${p.collection}/${p.data.id}/${p.data.version}`),
53
+ tag: `v${p.data.version}`,
54
+ }));
55
+
49
56
  const ownedServicesList = services.map((p) => ({
50
57
  label: `${p.data.name} (service)`,
51
58
  href: buildUrl(`/docs/${p.collection}/${p.data.id}/${p.data.version}`),
@@ -112,6 +119,13 @@ const ownedEventsList = [...events, ...commands].map((p) => ({
112
119
  </main>
113
120
  <aside class="sticky top-20 h-[calc(100vh-theme(spacing.16))] w-56 overflow-y-auto">
114
121
  <div class="divide-y-2 divide-gray-100">
122
+ <PillList
123
+ color="pink"
124
+ title={`Owned domains (${ownedDomainsList.length})`}
125
+ pills={ownedDomainsList}
126
+ emptyMessage={`${props.data.name} does not own any domains.`}
127
+ client:load
128
+ />
115
129
  <PillList
116
130
  color="blue"
117
131
  title={`Owned services (${ownedServicesList.length})`}