@eventcatalog/core 2.27.0 → 2.28.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-LMNJPHFP.js → chunk-KGWJTMWU.js} +1 -1
- package/dist/{chunk-2VGR4HMJ.js → chunk-KYGD25IE.js} +1 -1
- package/dist/{chunk-CTL6CH3C.js → chunk-RCPEAVRY.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -1
- package/dist/eventcatalog.config.d.cts +1 -4
- package/dist/eventcatalog.config.d.ts +1 -4
- package/dist/eventcatalog.js +3 -3
- package/eventcatalog/public/logo.svg +14 -0
- package/eventcatalog/src/components/Grids/ServiceGrid.tsx +2 -4
- package/eventcatalog/src/components/SideNav/ListViewSideBar/components/CollapsibleGroup.tsx +46 -0
- package/eventcatalog/src/components/SideNav/ListViewSideBar/components/MessageList.tsx +31 -0
- package/eventcatalog/src/components/SideNav/ListViewSideBar/index.tsx +390 -0
- package/eventcatalog/src/components/SideNav/ListViewSideBar/types.ts +48 -0
- package/eventcatalog/src/components/SideNav/ListViewSideBar/utils.ts +103 -0
- package/eventcatalog/src/components/SideNav/SideNav.astro +8 -7
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +7 -7
- package/eventcatalog/src/pages/architecture/[type]/index.astro +3 -77
- package/eventcatalog/src/pages/architecture/architecture.astro +81 -0
- package/eventcatalog/src/pages/architecture/docs/[type]/index.astro +14 -0
- package/eventcatalog/src/pages/index.astro +1 -1
- package/package.json +1 -1
- package/eventcatalog/src/components/SideNav/CatalogResourcesSideBar/getCatalogResources.ts +0 -65
- package/eventcatalog/src/components/SideNav/CatalogResourcesSideBar/index.tsx +0 -138
- package/eventcatalog/src/components/SideNav/CatalogResourcesSideBar/styles.css +0 -8
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface MessageItem {
|
|
2
|
+
href: string;
|
|
3
|
+
label: string;
|
|
4
|
+
service: string;
|
|
5
|
+
id: string;
|
|
6
|
+
direction: 'sends' | 'receives';
|
|
7
|
+
type: 'command' | 'query' | 'event';
|
|
8
|
+
data: {
|
|
9
|
+
name: string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ServiceItem {
|
|
14
|
+
href: string;
|
|
15
|
+
label: string;
|
|
16
|
+
name: string;
|
|
17
|
+
id: string;
|
|
18
|
+
sends: MessageItem[];
|
|
19
|
+
receives: MessageItem[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface DomainItem {
|
|
23
|
+
href: string;
|
|
24
|
+
label: string;
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
services: any[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface FlowItem {
|
|
31
|
+
href: string;
|
|
32
|
+
label: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface Resources {
|
|
36
|
+
domains?: DomainItem[];
|
|
37
|
+
services?: ServiceItem[];
|
|
38
|
+
flows?: FlowItem[];
|
|
39
|
+
messagesNotInService?: MessageItem[];
|
|
40
|
+
commands?: MessageItem[];
|
|
41
|
+
queries?: MessageItem[];
|
|
42
|
+
events?: MessageItem[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface ListViewSideBarProps {
|
|
46
|
+
resources: Resources;
|
|
47
|
+
currentPath: string;
|
|
48
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { isCollectionVisibleInCatalog } from '@eventcatalog';
|
|
2
|
+
import { buildUrl } from '@utils/url-builder';
|
|
3
|
+
import { getChannels } from '@utils/channels';
|
|
4
|
+
import { getDomains } from '@utils/collections/domains';
|
|
5
|
+
import { getFlows } from '@utils/collections/flows';
|
|
6
|
+
import { getServices } from '@utils/collections/services';
|
|
7
|
+
import { getCommands } from '@utils/commands';
|
|
8
|
+
import { getEvents } from '@utils/events';
|
|
9
|
+
import { getQueries } from '@utils/queries';
|
|
10
|
+
|
|
11
|
+
export async function getResourcesForNavigation({ currentPath }: { currentPath: string }) {
|
|
12
|
+
const events = await getEvents({ getAllVersions: false });
|
|
13
|
+
const commands = await getCommands({ getAllVersions: false });
|
|
14
|
+
const queries = await getQueries({ getAllVersions: false });
|
|
15
|
+
const services = await getServices({ getAllVersions: false });
|
|
16
|
+
const domains = await getDomains({ getAllVersions: false });
|
|
17
|
+
const channels = await getChannels({ getAllVersions: false });
|
|
18
|
+
const flows = await getFlows({ getAllVersions: false });
|
|
19
|
+
|
|
20
|
+
const messages = [...events, ...commands, ...queries];
|
|
21
|
+
|
|
22
|
+
// messages that are not in a service (sends or receives)
|
|
23
|
+
const messagesNotInService = messages.filter(
|
|
24
|
+
(message) =>
|
|
25
|
+
!services.some(
|
|
26
|
+
(service) =>
|
|
27
|
+
service.data?.sends?.some((send: any) => send.data.id === message.data.id) ||
|
|
28
|
+
service.data?.receives?.some((receive: any) => receive.data.id === message.data.id)
|
|
29
|
+
)
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const route = currentPath.includes('visualiser') ? 'visualiser' : 'docs';
|
|
33
|
+
|
|
34
|
+
// Just the domains for now.
|
|
35
|
+
const allDataAsSideNav = [...domains, ...services, ...flows, ...channels].reduce((acc, item) => {
|
|
36
|
+
const title = item.collection;
|
|
37
|
+
const group = acc[title] || [];
|
|
38
|
+
|
|
39
|
+
const servicesCount = item.collection === 'domains' ? item.data.services?.length || 0 : 0;
|
|
40
|
+
const sends = item.collection === 'services' ? item.data.sends || null : null;
|
|
41
|
+
const receives = item.collection === 'services' ? item.data.receives || null : null;
|
|
42
|
+
|
|
43
|
+
// Add href to the sends and receives
|
|
44
|
+
const sendsWithHref = sends?.map((send: any) => ({
|
|
45
|
+
...send,
|
|
46
|
+
href: buildUrl(`/${route}/${send.collection}/${send.data.id}/${send.data.version}`),
|
|
47
|
+
}));
|
|
48
|
+
const receivesWithHref = receives?.map((receive: any) => ({
|
|
49
|
+
...receive,
|
|
50
|
+
href: buildUrl(`/${route}/${receive.collection}/${receive.data.id}/${receive.data.version}`),
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
const navigationItem = {
|
|
54
|
+
label: item.data.name,
|
|
55
|
+
version: item.data.version,
|
|
56
|
+
// items: item.collection === 'users' ? [] : item.headings,
|
|
57
|
+
visible: isCollectionVisibleInCatalog(item.collection),
|
|
58
|
+
// @ts-ignore
|
|
59
|
+
href: item.data.version
|
|
60
|
+
? // @ts-ignore
|
|
61
|
+
buildUrl(`/${route}/${item.collection}/${item.data.id}/${item.data.version}`)
|
|
62
|
+
: buildUrl(`/${route}/${item.collection}/${item.data.id}`),
|
|
63
|
+
collection: item.collection,
|
|
64
|
+
servicesCount,
|
|
65
|
+
id: item.data.id,
|
|
66
|
+
name: item.data.name,
|
|
67
|
+
services: item.collection === 'domains' ? item.data.services : null,
|
|
68
|
+
sends: sendsWithHref,
|
|
69
|
+
receives: receivesWithHref,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
group.push(navigationItem);
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
...acc,
|
|
76
|
+
[title]: group,
|
|
77
|
+
};
|
|
78
|
+
}, {} as any);
|
|
79
|
+
|
|
80
|
+
// Add messagesNotInService
|
|
81
|
+
const messagesNotInServiceAsSideNav = messagesNotInService.map((item) => ({
|
|
82
|
+
label: item.data.name,
|
|
83
|
+
version: item.data.version,
|
|
84
|
+
id: item.data.id,
|
|
85
|
+
name: item.data.name,
|
|
86
|
+
href: buildUrl(`/${route}/${item.collection}/${item.data.id}/${item.data.version}`),
|
|
87
|
+
collection: item.collection,
|
|
88
|
+
}));
|
|
89
|
+
|
|
90
|
+
const sideNav = {
|
|
91
|
+
...(currentPath.includes('visualiser')
|
|
92
|
+
? {
|
|
93
|
+
'bounded context map': [
|
|
94
|
+
{ label: 'Domain map', href: buildUrl('/visualiser/context-map'), collection: 'bounded-context-map' },
|
|
95
|
+
],
|
|
96
|
+
}
|
|
97
|
+
: {}),
|
|
98
|
+
...allDataAsSideNav,
|
|
99
|
+
messagesNotInService: messagesNotInServiceAsSideNav,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
return sideNav;
|
|
103
|
+
}
|
|
@@ -3,29 +3,30 @@ import type { HTMLAttributes } from 'astro/types';
|
|
|
3
3
|
import config from '@config';
|
|
4
4
|
|
|
5
5
|
// FlatView
|
|
6
|
-
import
|
|
7
|
-
import { getCatalogResources } from './CatalogResourcesSideBar/getCatalogResources';
|
|
6
|
+
import { getResourcesForNavigation as getListViewResources } from './ListViewSideBar/utils';
|
|
8
7
|
|
|
9
8
|
// TreeView
|
|
10
9
|
import { SideNavTreeView } from './TreeView';
|
|
11
10
|
import { getTreeView } from './TreeView/getTreeView';
|
|
12
11
|
|
|
12
|
+
import ListViewSideBar from './ListViewSideBar';
|
|
13
|
+
|
|
13
14
|
interface Props extends Omit<HTMLAttributes<'div'>, 'children'> {}
|
|
14
15
|
|
|
15
16
|
const currentPath = Astro.url.pathname;
|
|
16
17
|
|
|
17
18
|
let props;
|
|
18
19
|
|
|
19
|
-
const SIDENAV_TYPE = config?.docs?.sidebar?.type ?? '
|
|
20
|
+
const SIDENAV_TYPE = config?.docs?.sidebar?.type ?? 'LIST_VIEW';
|
|
20
21
|
|
|
21
|
-
if (SIDENAV_TYPE === '
|
|
22
|
-
props = await getCatalogResources({ currentPath });
|
|
23
|
-
} else if (SIDENAV_TYPE === 'TREE_VIEW') {
|
|
22
|
+
if (SIDENAV_TYPE === 'TREE_VIEW') {
|
|
24
23
|
props = getTreeView({ projectDir: process.env.PROJECT_DIR!, currentPath });
|
|
24
|
+
} else if (SIDENAV_TYPE === 'LIST_VIEW') {
|
|
25
|
+
props = await getListViewResources({ currentPath });
|
|
25
26
|
}
|
|
26
27
|
---
|
|
27
28
|
|
|
28
29
|
<div {...Astro.props}>
|
|
29
|
-
{SIDENAV_TYPE === '
|
|
30
|
+
{SIDENAV_TYPE === 'LIST_VIEW' && <ListViewSideBar resources={props} currentPath={currentPath} client:only />}
|
|
30
31
|
{SIDENAV_TYPE === 'TREE_VIEW' && <SideNavTreeView client:only transition:persist tree={props} />}
|
|
31
32
|
</div>
|
|
@@ -5,11 +5,11 @@ interface Props {
|
|
|
5
5
|
description?: string;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
import { BookOpenText, Workflow, TableProperties, House, BookUser, MessageSquare, BotMessageSquare } from 'lucide-react';
|
|
8
|
+
import { BookOpenText, Workflow, TableProperties, House, BookUser, MessageSquare, BotMessageSquare, Users } from 'lucide-react';
|
|
9
9
|
import Header from '../components/Header.astro';
|
|
10
10
|
import SEO from '../components/Seo.astro';
|
|
11
11
|
import SideNav from '../components/SideNav/SideNav.astro';
|
|
12
|
-
import '@fontsource/inter';
|
|
12
|
+
// import '@fontsource/inter';
|
|
13
13
|
|
|
14
14
|
import { getCommands } from '@utils/commands';
|
|
15
15
|
import { getDomains } from '@utils/collections/domains';
|
|
@@ -66,7 +66,7 @@ const navigationItems = [
|
|
|
66
66
|
label: 'Documentation',
|
|
67
67
|
icon: BookOpenText,
|
|
68
68
|
href: catalogHasDefaultLandingPageForDocs ? buildUrl('/docs') : getDefaultUrl('docs', '/docs'),
|
|
69
|
-
current: currentPath.includes('/docs'),
|
|
69
|
+
current: currentPath.includes('/docs') || currentPath.includes('/architecture/docs/'),
|
|
70
70
|
sidebar: true,
|
|
71
71
|
},
|
|
72
72
|
{
|
|
@@ -87,8 +87,8 @@ const navigationItems = [
|
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
89
|
id: '/directory',
|
|
90
|
-
label: '
|
|
91
|
-
icon:
|
|
90
|
+
label: 'Users & Teams',
|
|
91
|
+
icon: Users,
|
|
92
92
|
href: buildUrl('/directory/users'),
|
|
93
93
|
current: currentPath.includes('/directory'),
|
|
94
94
|
sidebar: false,
|
|
@@ -98,7 +98,7 @@ const navigationItems = [
|
|
|
98
98
|
label: 'Architecture',
|
|
99
99
|
icon: BookUser,
|
|
100
100
|
href: buildUrl('/architecture/domains'),
|
|
101
|
-
current: currentPath.includes('/architecture'),
|
|
101
|
+
current: currentPath.includes('/architecture/'),
|
|
102
102
|
sidebar: false,
|
|
103
103
|
hidden: true,
|
|
104
104
|
},
|
|
@@ -175,7 +175,7 @@ const canPageBeEmbedded = process.env.ENABLE_EMBED === 'true';
|
|
|
175
175
|
|
|
176
176
|
<SideNav
|
|
177
177
|
id="sidebar"
|
|
178
|
-
class={`sidebar-transition h-content overflow-y-auto bg-white border-r border-gray-100 w-
|
|
178
|
+
class={`sidebar-transition h-content overflow-y-auto bg-white border-r border-gray-100 w-80 ml-16 ${showSideBarOnLoad ? 'block' : 'hidden'}`}
|
|
179
179
|
/>
|
|
180
180
|
</aside>
|
|
181
181
|
<main
|
|
@@ -1,25 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
import
|
|
3
|
-
import { getServices } from '@utils/collections/services';
|
|
4
|
-
import { getMessages } from '@utils/messages';
|
|
5
|
-
import type { ExtendedDomain } from '@components/Grids/DomainGrid';
|
|
6
|
-
import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
|
|
7
|
-
import DomainGrid from '@components/Grids/DomainGrid';
|
|
8
|
-
import ServiceGrid from '@components/Grids/ServiceGrid';
|
|
9
|
-
import MessageGrid from '@components/Grids/MessageGrid';
|
|
10
|
-
|
|
11
|
-
import type { CollectionEntry } from 'astro:content';
|
|
12
|
-
import type { CollectionMessageTypes } from '@types';
|
|
13
|
-
|
|
14
|
-
import { ClientRouter, fade } from 'astro:transitions';
|
|
15
|
-
// Define valid types and their corresponding data fetchers
|
|
16
|
-
const VALID_TYPES = ['domains', 'services', 'messages'] as const;
|
|
17
|
-
type ValidType = (typeof VALID_TYPES)[number];
|
|
18
|
-
|
|
19
|
-
interface Service extends CollectionEntry<'services'> {
|
|
20
|
-
sends: CollectionEntry<'events' | 'commands' | 'queries'>[];
|
|
21
|
-
receives: CollectionEntry<'events' | 'commands' | 'queries'>[];
|
|
22
|
-
}
|
|
2
|
+
import Architecture from '../architecture.astro';
|
|
23
3
|
|
|
24
4
|
export async function getStaticPaths() {
|
|
25
5
|
const VALID_TYPES = ['domains', 'services', 'messages'] as const;
|
|
@@ -28,61 +8,7 @@ export async function getStaticPaths() {
|
|
|
28
8
|
}));
|
|
29
9
|
}
|
|
30
10
|
|
|
31
|
-
const { type } = Astro.params
|
|
32
|
-
|
|
33
|
-
// Get data based on type
|
|
34
|
-
let items: ExtendedDomain[] | Service[] | CollectionEntry<'commands'>[] | CollectionEntry<CollectionMessageTypes>[] = [];
|
|
35
|
-
|
|
36
|
-
if (type === 'domains') {
|
|
37
|
-
const domains = await getDomains({ getAllVersions: false });
|
|
38
|
-
|
|
39
|
-
// Get messages for each domain
|
|
40
|
-
items = await Promise.all(
|
|
41
|
-
domains.map(async (domain) => {
|
|
42
|
-
const messages = await getMessagesForDomain(domain);
|
|
43
|
-
// @ts-ignore we have to remove markdown information, as it's all send to the astro components. This reduced the page size.
|
|
44
|
-
return {
|
|
45
|
-
...domain,
|
|
46
|
-
sends: messages.sends.map((s) => ({ ...s, body: undefined, catalog: undefined })),
|
|
47
|
-
receives: messages.receives.map((r) => ({ ...r, body: undefined, catalog: undefined })),
|
|
48
|
-
catalog: undefined,
|
|
49
|
-
body: undefined,
|
|
50
|
-
} as ExtendedDomain;
|
|
51
|
-
})
|
|
52
|
-
);
|
|
53
|
-
} else if (type === 'services') {
|
|
54
|
-
const services = await getServices({ getAllVersions: false });
|
|
55
|
-
let filteredServices = services.map((s) => {
|
|
56
|
-
// @ts-ignore we have to remove markdown information, as it's all send to the astro components. This reduced the page size.
|
|
57
|
-
return {
|
|
58
|
-
...s,
|
|
59
|
-
sends: (s.data.sends || []).map((s) => ({ ...s, body: undefined, catalog: undefined })),
|
|
60
|
-
receives: (s.data.receives || []).map((r) => ({ ...r, body: undefined, catalog: undefined })),
|
|
61
|
-
catalog: undefined,
|
|
62
|
-
body: undefined,
|
|
63
|
-
} as Service;
|
|
64
|
-
}) as unknown as Service[];
|
|
65
|
-
items = filteredServices;
|
|
66
|
-
} else if (type === 'messages') {
|
|
67
|
-
const { events, commands, queries } = await getMessages({ getAllVersions: false });
|
|
68
|
-
const messages = [...events, ...commands, ...queries];
|
|
69
|
-
items = messages.map((m) => ({
|
|
70
|
-
...m,
|
|
71
|
-
body: undefined,
|
|
72
|
-
catalog: undefined,
|
|
73
|
-
})) as unknown as CollectionEntry<CollectionMessageTypes>[];
|
|
74
|
-
}
|
|
11
|
+
const { type } = Astro.params;
|
|
75
12
|
---
|
|
76
13
|
|
|
77
|
-
<
|
|
78
|
-
<div class="bg-white min-h-screen">
|
|
79
|
-
<div class="max-w-[90em] mx-auto">
|
|
80
|
-
<div class="px-6 py-6" transition:animate={fade({ duration: '0.4s' })}>
|
|
81
|
-
{type === 'domains' && <DomainGrid domains={items as ExtendedDomain[]} client:load />}
|
|
82
|
-
{type === 'services' && <ServiceGrid services={items as unknown as Service[]} client:load />}
|
|
83
|
-
{type === 'messages' && <MessageGrid messages={items as CollectionEntry<CollectionMessageTypes>[]} client:load />}
|
|
84
|
-
</div>
|
|
85
|
-
</div>
|
|
86
|
-
<ClientRouter />
|
|
87
|
-
</div>
|
|
88
|
-
</VerticalSideBarLayout>
|
|
14
|
+
<Architecture type={type} />
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { getDomains, getMessagesForDomain } from '@utils/collections/domains';
|
|
3
|
+
import { getServices } from '@utils/collections/services';
|
|
4
|
+
import { getMessages } from '@utils/messages';
|
|
5
|
+
import type { ExtendedDomain } from '@components/Grids/DomainGrid';
|
|
6
|
+
import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
|
|
7
|
+
import DomainGrid from '@components/Grids/DomainGrid';
|
|
8
|
+
import ServiceGrid from '@components/Grids/ServiceGrid';
|
|
9
|
+
import MessageGrid from '@components/Grids/MessageGrid';
|
|
10
|
+
|
|
11
|
+
import type { CollectionEntry } from 'astro:content';
|
|
12
|
+
import type { CollectionMessageTypes } from '@types';
|
|
13
|
+
|
|
14
|
+
import { ClientRouter, fade } from 'astro:transitions';
|
|
15
|
+
// Define valid types and their corresponding data fetchers
|
|
16
|
+
const VALID_TYPES = ['domains', 'services', 'messages'] as const;
|
|
17
|
+
type ValidType = (typeof VALID_TYPES)[number];
|
|
18
|
+
|
|
19
|
+
interface Service extends CollectionEntry<'services'> {
|
|
20
|
+
sends: CollectionEntry<'events' | 'commands' | 'queries'>[];
|
|
21
|
+
receives: CollectionEntry<'events' | 'commands' | 'queries'>[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const { type } = Astro.props as { type: ValidType };
|
|
25
|
+
|
|
26
|
+
// Get data based on type
|
|
27
|
+
let items: ExtendedDomain[] | Service[] | CollectionEntry<'commands'>[] | CollectionEntry<CollectionMessageTypes>[] = [];
|
|
28
|
+
|
|
29
|
+
if (type === 'domains') {
|
|
30
|
+
const domains = await getDomains({ getAllVersions: false });
|
|
31
|
+
|
|
32
|
+
// Get messages for each domain
|
|
33
|
+
items = await Promise.all(
|
|
34
|
+
domains.map(async (domain) => {
|
|
35
|
+
const messages = await getMessagesForDomain(domain);
|
|
36
|
+
// @ts-ignore we have to remove markdown information, as it's all send to the astro components. This reduced the page size.
|
|
37
|
+
return {
|
|
38
|
+
...domain,
|
|
39
|
+
sends: messages.sends.map((s) => ({ ...s, body: undefined, catalog: undefined })),
|
|
40
|
+
receives: messages.receives.map((r) => ({ ...r, body: undefined, catalog: undefined })),
|
|
41
|
+
catalog: undefined,
|
|
42
|
+
body: undefined,
|
|
43
|
+
} as ExtendedDomain;
|
|
44
|
+
})
|
|
45
|
+
);
|
|
46
|
+
} else if (type === 'services') {
|
|
47
|
+
const services = await getServices({ getAllVersions: false });
|
|
48
|
+
let filteredServices = services.map((s) => {
|
|
49
|
+
// @ts-ignore we have to remove markdown information, as it's all send to the astro components. This reduced the page size.
|
|
50
|
+
return {
|
|
51
|
+
...s,
|
|
52
|
+
sends: (s.data.sends || []).map((s) => ({ ...s, body: undefined, catalog: undefined })),
|
|
53
|
+
receives: (s.data.receives || []).map((r) => ({ ...r, body: undefined, catalog: undefined })),
|
|
54
|
+
catalog: undefined,
|
|
55
|
+
body: undefined,
|
|
56
|
+
} as Service;
|
|
57
|
+
}) as unknown as Service[];
|
|
58
|
+
items = filteredServices;
|
|
59
|
+
} else if (type === 'messages') {
|
|
60
|
+
const { events, commands, queries } = await getMessages({ getAllVersions: false });
|
|
61
|
+
const messages = [...events, ...commands, ...queries];
|
|
62
|
+
items = messages.map((m) => ({
|
|
63
|
+
...m,
|
|
64
|
+
body: undefined,
|
|
65
|
+
catalog: undefined,
|
|
66
|
+
})) as unknown as CollectionEntry<CollectionMessageTypes>[];
|
|
67
|
+
}
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
<VerticalSideBarLayout title={'EventCatalog'}>
|
|
71
|
+
<div class="bg-white min-h-screen">
|
|
72
|
+
<div class="max-w-[90em] mx-auto">
|
|
73
|
+
<div class="px-6 py-6" transition:animate={fade({ duration: '0.4s' })}>
|
|
74
|
+
{type === 'domains' && <DomainGrid domains={items as ExtendedDomain[]} client:load />}
|
|
75
|
+
{type === 'services' && <ServiceGrid services={items as unknown as Service[]} client:load />}
|
|
76
|
+
{type === 'messages' && <MessageGrid messages={items as CollectionEntry<CollectionMessageTypes>[]} client:load />}
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
<ClientRouter />
|
|
80
|
+
</div>
|
|
81
|
+
</VerticalSideBarLayout>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Architecture from '../../architecture.astro';
|
|
3
|
+
|
|
4
|
+
export async function getStaticPaths() {
|
|
5
|
+
const VALID_TYPES = ['domains', 'services', 'messages'] as const;
|
|
6
|
+
return VALID_TYPES.map((type) => ({
|
|
7
|
+
params: { type },
|
|
8
|
+
}));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { type } = Astro.params;
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<Architecture type={type} />
|
|
@@ -133,7 +133,7 @@ const topTiles = [
|
|
|
133
133
|
<main class="container px-8 lg:px-8 mx-auto py-8 max-w-[80em]">
|
|
134
134
|
<div class="mb-12">
|
|
135
135
|
<h1 class="text-4xl font-semibold mb-4 text-gray-900 font-inter">
|
|
136
|
-
{config?.organizationName || 'EventCatalog'}
|
|
136
|
+
{config?.organizationName || 'EventCatalog'}
|
|
137
137
|
</h1>
|
|
138
138
|
<p class="text-base mb-0 text-gray-600 max-w-3xl">
|
|
139
139
|
{config.tagline || 'Comprehensive event-driven architecture documentation covering events, services, domains.'}
|
package/package.json
CHANGED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { isCollectionVisibleInCatalog } from '@eventcatalog';
|
|
2
|
-
import { buildUrl } from '@utils/url-builder';
|
|
3
|
-
import { getChannels } from '@utils/channels';
|
|
4
|
-
import { getDomains } from '@utils/collections/domains';
|
|
5
|
-
import { getFlows } from '@utils/collections/flows';
|
|
6
|
-
import { getServices } from '@utils/collections/services';
|
|
7
|
-
import { getCommands } from '@utils/commands';
|
|
8
|
-
import { getEvents } from '@utils/events';
|
|
9
|
-
import { getQueries } from '@utils/queries';
|
|
10
|
-
import { getTeams } from '@utils/teams';
|
|
11
|
-
import { getUsers } from '@utils/users';
|
|
12
|
-
|
|
13
|
-
export async function getCatalogResources({ currentPath }: { currentPath: string }) {
|
|
14
|
-
const events = await getEvents({ getAllVersions: false });
|
|
15
|
-
const commands = await getCommands({ getAllVersions: false });
|
|
16
|
-
const queries = await getQueries({ getAllVersions: false });
|
|
17
|
-
const services = await getServices({ getAllVersions: false });
|
|
18
|
-
const domains = await getDomains({ getAllVersions: false });
|
|
19
|
-
const channels = await getChannels({ getAllVersions: false });
|
|
20
|
-
const flows = await getFlows({ getAllVersions: false });
|
|
21
|
-
|
|
22
|
-
const messages = [...events, ...commands, ...queries];
|
|
23
|
-
|
|
24
|
-
// @ts-ignore for large catalogs https://github.com/event-catalog/eventcatalog/issues/552
|
|
25
|
-
const allData = [...domains, ...services, ...messages, ...channels, ...flows];
|
|
26
|
-
|
|
27
|
-
const allDataAsSideNav = allData.reduce((acc, item) => {
|
|
28
|
-
const title = item.collection;
|
|
29
|
-
const group = acc[title] || [];
|
|
30
|
-
const route = currentPath.includes('visualiser') ? 'visualiser' : 'docs';
|
|
31
|
-
|
|
32
|
-
const navigationItem = {
|
|
33
|
-
label: item.data.name,
|
|
34
|
-
version: item.data.version,
|
|
35
|
-
// items: item.collection === 'users' ? [] : item.headings,
|
|
36
|
-
visible: isCollectionVisibleInCatalog(item.collection),
|
|
37
|
-
// @ts-ignore
|
|
38
|
-
href: item.data.version
|
|
39
|
-
? // @ts-ignore
|
|
40
|
-
buildUrl(`/${route}/${item.collection}/${item.data.id}/${item.data.version}`)
|
|
41
|
-
: buildUrl(`/${route}/${item.collection}/${item.data.id}`),
|
|
42
|
-
collection: item.collection,
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
group.push(navigationItem);
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
...acc,
|
|
49
|
-
[title]: group,
|
|
50
|
-
};
|
|
51
|
-
}, {} as any);
|
|
52
|
-
|
|
53
|
-
const sideNav = {
|
|
54
|
-
...(currentPath.includes('visualiser')
|
|
55
|
-
? {
|
|
56
|
-
'bounded context map': [
|
|
57
|
-
{ label: 'Domain map', href: buildUrl('/visualiser/context-map'), collection: 'bounded-context-map' },
|
|
58
|
-
],
|
|
59
|
-
}
|
|
60
|
-
: {}),
|
|
61
|
-
...allDataAsSideNav,
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
return sideNav;
|
|
65
|
-
}
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect, useMemo } from 'react';
|
|
2
|
-
import debounce from 'lodash.debounce';
|
|
3
|
-
import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/24/outline';
|
|
4
|
-
import './styles.css';
|
|
5
|
-
import { getIconForCollection as getIconForCollectionOriginal } from '@utils/collections/icons';
|
|
6
|
-
|
|
7
|
-
const STORAGE_KEY = 'EventCatalog:catalogSidebarCollapsedGroups';
|
|
8
|
-
|
|
9
|
-
interface CatalogResourcesSideBarProps {
|
|
10
|
-
resources: any;
|
|
11
|
-
currentPath: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const CatalogResourcesSideBar: React.FC<CatalogResourcesSideBarProps> = ({ resources, currentPath }) => {
|
|
15
|
-
if (typeof window === 'undefined') {
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const [data, setData] = useState(resources);
|
|
20
|
-
const [searchQuery, setSearchQuery] = useState('');
|
|
21
|
-
const [isInitialized, setIsInitialized] = useState(false);
|
|
22
|
-
const [collapsedGroups, setCollapsedGroups] = useState<{ [key: string]: boolean }>(() => {
|
|
23
|
-
if (typeof window !== 'undefined') {
|
|
24
|
-
const saved = window.localStorage.getItem(STORAGE_KEY);
|
|
25
|
-
setIsInitialized(true);
|
|
26
|
-
return saved ? JSON.parse(saved) : {};
|
|
27
|
-
}
|
|
28
|
-
return {};
|
|
29
|
-
});
|
|
30
|
-
const decodedCurrentPath = decodeURIComponent(currentPath);
|
|
31
|
-
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
if (typeof window !== 'undefined') {
|
|
34
|
-
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(collapsedGroups));
|
|
35
|
-
}
|
|
36
|
-
}, [collapsedGroups]);
|
|
37
|
-
|
|
38
|
-
const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
39
|
-
setSearchQuery(e.target.value);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const debouncedHandleSearch = useMemo(() => debounce(handleSearch, 300), []);
|
|
43
|
-
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
return () => {
|
|
46
|
-
debouncedHandleSearch.cancel();
|
|
47
|
-
};
|
|
48
|
-
}, [debouncedHandleSearch]);
|
|
49
|
-
|
|
50
|
-
const toggleGroupCollapse = (group: string) => {
|
|
51
|
-
setCollapsedGroups((prev) => ({
|
|
52
|
-
...prev,
|
|
53
|
-
[group]: !prev[group],
|
|
54
|
-
}));
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const filteredData = useMemo(() => {
|
|
58
|
-
if (!searchQuery) return data;
|
|
59
|
-
|
|
60
|
-
const lowercasedQuery = searchQuery.toLowerCase();
|
|
61
|
-
const filterCollection = (collection: any[]) =>
|
|
62
|
-
collection.filter((item) => item.label.toLowerCase().includes(lowercasedQuery));
|
|
63
|
-
|
|
64
|
-
return Object.keys(data).reduce((acc, key) => {
|
|
65
|
-
const filteredCollection = filterCollection(data[key]);
|
|
66
|
-
if (filteredCollection.length > 0) {
|
|
67
|
-
acc[key] = filteredCollection;
|
|
68
|
-
}
|
|
69
|
-
return acc;
|
|
70
|
-
}, {} as any);
|
|
71
|
-
}, [searchQuery, data]);
|
|
72
|
-
|
|
73
|
-
const getIconForCollection = useMemo(() => getIconForCollectionOriginal, []);
|
|
74
|
-
|
|
75
|
-
if (!isInitialized) return null;
|
|
76
|
-
|
|
77
|
-
return (
|
|
78
|
-
<nav className="space-y-6 text-black px-5 py-4 ">
|
|
79
|
-
<div className="space-y-2">
|
|
80
|
-
<div className="mb-4 px-1">
|
|
81
|
-
<input
|
|
82
|
-
type="text"
|
|
83
|
-
placeholder="Filter catalog..."
|
|
84
|
-
className="w-full font-light px-3 py-1 text-sm text-gray-600 border border-purple-300 rounded-md focus:outline-none focus:ring-2 focus:ring-purple-500"
|
|
85
|
-
onChange={debouncedHandleSearch}
|
|
86
|
-
/>
|
|
87
|
-
</div>
|
|
88
|
-
|
|
89
|
-
{Object.keys(filteredData).length === 0 ? (
|
|
90
|
-
<div className="px-2 text-gray-400 dark:text-gray-200 text-sm">No results found</div>
|
|
91
|
-
) : (
|
|
92
|
-
Object.keys(filteredData).map((key) => {
|
|
93
|
-
const collection = filteredData[key];
|
|
94
|
-
if (collection[0] && collection[0].visible === false) return null;
|
|
95
|
-
const isCollapsed = collapsedGroups[key];
|
|
96
|
-
|
|
97
|
-
return (
|
|
98
|
-
<ul className="w-full space-y-1.5 pb-2 pl-1 text-black" key={key}>
|
|
99
|
-
<li
|
|
100
|
-
className="font capitalize cursor-pointer flex items-center ml-1 text-[14px]"
|
|
101
|
-
onClick={() => toggleGroupCollapse(key)}
|
|
102
|
-
>
|
|
103
|
-
<span className="">{`${key} (${collection.length})`}</span>
|
|
104
|
-
<span className="ml-2 block">
|
|
105
|
-
{isCollapsed ? <ChevronDownIcon className="w-3 h-3" /> : <ChevronUpIcon className="w-3 h-3" />}
|
|
106
|
-
</span>
|
|
107
|
-
</li>
|
|
108
|
-
{!isCollapsed &&
|
|
109
|
-
collection.map((item: any) => {
|
|
110
|
-
const Icon = getIconForCollection(item.collection);
|
|
111
|
-
return (
|
|
112
|
-
<li
|
|
113
|
-
className={`w-full has-tooltip text-md xl:text-sm space-y-2 scroll-m-20 rounded-md text-black hover:bg-gradient-to-l hover:from-purple-500 hover:to-purple-700 hover:text-white ${decodedCurrentPath.includes(item.href) ? ' bg-gradient-to-l from-purple-500 to-purple-700 font-normal text-white ' : 'font-thin'}`}
|
|
114
|
-
id={item.href}
|
|
115
|
-
key={item.href}
|
|
116
|
-
>
|
|
117
|
-
<a className={`flex px-1 justify-start items-center w-full rounded-md `} href={`${item.href}`}>
|
|
118
|
-
<Icon className="w-3 mr-2" />
|
|
119
|
-
<span className="block truncate !whitespace-normal">{item.label}</span>
|
|
120
|
-
{/* {item.label.length > 2 && (
|
|
121
|
-
<span className="tooltip rounded relative shadow-lg p-1 font-normal text-xs bg-white text-black ml-[30px] mt-12">
|
|
122
|
-
{item.label}
|
|
123
|
-
</span>
|
|
124
|
-
)} */}
|
|
125
|
-
</a>
|
|
126
|
-
</li>
|
|
127
|
-
);
|
|
128
|
-
})}
|
|
129
|
-
</ul>
|
|
130
|
-
);
|
|
131
|
-
})
|
|
132
|
-
)}
|
|
133
|
-
</div>
|
|
134
|
-
</nav>
|
|
135
|
-
);
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
export default CatalogResourcesSideBar;
|