@eventcatalog/core 5.0.0-beta.2 → 5.0.0-beta.4

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 (65) hide show
  1. package/dist/analytics/analytics.cjs +1 -1
  2. package/dist/analytics/analytics.js +2 -2
  3. package/dist/analytics/log-build.cjs +1 -1
  4. package/dist/analytics/log-build.js +3 -3
  5. package/dist/{chunk-HGRFXTFC.js → chunk-M7OVJHPV.js} +1 -1
  6. package/dist/{chunk-KIDISU6X.js → chunk-PL3T5TWF.js} +1 -1
  7. package/dist/{chunk-62EV4IJA.js → chunk-Q7FBYUCZ.js} +1 -1
  8. package/dist/{chunk-4J2ZM2HX.js → chunk-TOMV5YJH.js} +1 -1
  9. package/dist/{chunk-XARPIXWF.js → chunk-VA77ENFQ.js} +1 -1
  10. package/dist/constants.cjs +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/eventcatalog.cjs +1 -1
  13. package/dist/eventcatalog.js +5 -5
  14. package/dist/generate.cjs +1 -1
  15. package/dist/generate.js +3 -3
  16. package/dist/runtime-dependencies/manifest.json +0 -1
  17. package/dist/utils/cli-logger.cjs +1 -1
  18. package/dist/utils/cli-logger.js +2 -2
  19. package/eventcatalog/src/components/Grids/utils.tsx +0 -23
  20. package/eventcatalog/src/components/MDX/CodeGroup/CodeGroup.tsx +6 -1
  21. package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +12 -4
  22. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +16 -7
  23. package/eventcatalog/src/components/SideNav/NestedSideBar/utils.ts +10 -0
  24. package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +4 -62
  25. package/eventcatalog/src/components/Tables/Discover/columns.tsx +17 -150
  26. package/eventcatalog/src/components/Tables/Resources/ResourcesTable.tsx +425 -0
  27. package/eventcatalog/src/components/Tables/RowActionsMenu.tsx +157 -0
  28. package/eventcatalog/src/components/Tables/TablePagination.tsx +82 -0
  29. package/eventcatalog/src/features/ai/chat-api.ts +3 -3
  30. package/eventcatalog/src/features/mcp/apps/generated/viewer.html +75 -74
  31. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +0 -2
  32. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.spec.ts +52 -63
  33. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +34 -46
  34. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +11 -29
  35. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_ResourcesPage.astro +79 -0
  36. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.spec.ts +32 -14
  37. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.ts +63 -58
  38. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/index.astro +2 -62
  39. package/eventcatalog/src/pages/docs/services/[id]/[version]/resources/index.astro +13 -0
  40. package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +24 -42
  41. package/eventcatalog/src/stores/sidebar-store/builders/flow.ts +2 -0
  42. package/eventcatalog/src/stores/sidebar-store/builders/message.ts +2 -0
  43. package/eventcatalog/src/stores/sidebar-store/builders/service.ts +23 -23
  44. package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +13 -0
  45. package/eventcatalog/src/stores/sidebar-store/builders/system.ts +18 -27
  46. package/eventcatalog/src/stores/sidebar-store/state.ts +5 -0
  47. package/eventcatalog/src/styles/tailwind.css +2 -2
  48. package/eventcatalog/src/utils/collections/channels.ts +56 -1
  49. package/eventcatalog/src/utils/collections/flows.ts +50 -1
  50. package/eventcatalog/src/utils/collections/message-connections.ts +60 -0
  51. package/eventcatalog/src/utils/collections/message-triggers.ts +2 -1
  52. package/eventcatalog/src/utils/collections/resource-owners.ts +193 -0
  53. package/eventcatalog/src/utils/collections/resources.ts +310 -0
  54. package/eventcatalog/src/utils/collections/util.ts +31 -0
  55. package/eventcatalog/src/utils/git.ts +11 -5
  56. package/package.json +8 -10
  57. package/dist/runtime-dependencies/shelljs.mjs +0 -3
  58. package/eventcatalog/src/components/Grids/DomainGrid.tsx +0 -838
  59. package/eventcatalog/src/components/Grids/MessageGrid.tsx +0 -344
  60. package/eventcatalog/src/components/Grids/SystemGrid.tsx +0 -185
  61. package/eventcatalog/src/components/Grids/components.tsx +0 -170
  62. package/eventcatalog/src/components/Grids/message-link.ts +0 -38
  63. package/eventcatalog/src/components/Tables/SystemResources/SystemResourcesTable.tsx +0 -294
  64. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_resources.spec.ts +0 -65
  65. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_resources.ts +0 -46
@@ -0,0 +1,157 @@
1
+ import { useEffect, useLayoutEffect, useRef, useState } from 'react';
2
+ import { createPortal } from 'react-dom';
3
+ import { CodeBracketIcon, DocumentTextIcon, MapIcon } from '@heroicons/react/24/solid';
4
+ import { EllipsisVerticalIcon, StarIcon } from '@heroicons/react/24/outline';
5
+ import { useStore } from '@nanostores/react';
6
+ import { favoritesStore, toggleFavorite } from '@stores/favorites-store';
7
+
8
+ const MENU_WIDTH = 280;
9
+ const MENU_GAP = 6;
10
+
11
+ interface RowActionsMenuProps {
12
+ title: string;
13
+ /** Link to the resource's documentation page. */
14
+ href: string;
15
+ /** Link to the resource in the visualiser. The menu leaves the visualiser out when absent. */
16
+ visualiserHref?: string;
17
+ /** Link to the resource's schema page. The menu leaves the schema out when absent. */
18
+ schemaHref?: string;
19
+ favorite: { nodeKey: string; badge: string };
20
+ }
21
+
22
+ /** The "..." menu at the end of a table row, with links to the resource and a favorite toggle. */
23
+ export function RowActionsMenu({ title, href, visualiserHref, schemaHref, favorite }: RowActionsMenuProps) {
24
+ const [isOpen, setIsOpen] = useState(false);
25
+ const buttonRef = useRef<HTMLButtonElement>(null);
26
+ const menuRef = useRef<HTMLDivElement>(null);
27
+ const [menuPosition, setMenuPosition] = useState<{ top: number; left: number } | null>(null);
28
+ const favorites = useStore(favoritesStore);
29
+ const isFavorite = favorites.some((fav) => fav.nodeKey === favorite.nodeKey);
30
+
31
+ // The table lives inside scrollable, overflow-hidden containers, so the menu is
32
+ // rendered in a portal with fixed positioning to avoid being clipped.
33
+ const updatePosition = () => {
34
+ const button = buttonRef.current;
35
+ if (!button) return;
36
+ const rect = button.getBoundingClientRect();
37
+ const menuHeight = menuRef.current?.offsetHeight ?? 0;
38
+ const spaceBelow = window.innerHeight - rect.bottom;
39
+
40
+ // Flip above the trigger when there isn't enough room below it.
41
+ const openUpwards = menuHeight > 0 && spaceBelow < menuHeight + MENU_GAP && rect.top > spaceBelow;
42
+ const top = openUpwards ? rect.top - menuHeight - MENU_GAP : rect.bottom + MENU_GAP;
43
+ const left = Math.max(MENU_GAP, rect.right - MENU_WIDTH);
44
+
45
+ setMenuPosition({ top, left });
46
+ };
47
+
48
+ useLayoutEffect(() => {
49
+ if (!isOpen) return;
50
+ updatePosition();
51
+ // eslint-disable-next-line react-hooks/exhaustive-deps
52
+ }, [isOpen]);
53
+
54
+ useEffect(() => {
55
+ if (!isOpen) return;
56
+
57
+ const handlePointerDown = (event: MouseEvent) => {
58
+ const target = event.target as Node;
59
+ if (!menuRef.current?.contains(target) && !buttonRef.current?.contains(target)) {
60
+ setIsOpen(false);
61
+ }
62
+ };
63
+
64
+ const handleEscape = (event: KeyboardEvent) => {
65
+ if (event.key === 'Escape') {
66
+ setIsOpen(false);
67
+ }
68
+ };
69
+
70
+ const handleReposition = () => updatePosition();
71
+
72
+ document.addEventListener('mousedown', handlePointerDown);
73
+ document.addEventListener('keydown', handleEscape);
74
+ window.addEventListener('resize', handleReposition);
75
+ window.addEventListener('scroll', handleReposition, true);
76
+
77
+ return () => {
78
+ document.removeEventListener('mousedown', handlePointerDown);
79
+ document.removeEventListener('keydown', handleEscape);
80
+ window.removeEventListener('resize', handleReposition);
81
+ window.removeEventListener('scroll', handleReposition, true);
82
+ };
83
+ }, [isOpen]);
84
+
85
+ const handleToggleFavorite = () => {
86
+ toggleFavorite({ nodeKey: favorite.nodeKey, path: [], title, badge: favorite.badge, href });
87
+ setIsOpen(false);
88
+ };
89
+
90
+ return (
91
+ <div className="relative flex justify-end">
92
+ <button
93
+ ref={buttonRef}
94
+ type="button"
95
+ aria-label="Actions"
96
+ aria-haspopup="menu"
97
+ aria-expanded={isOpen}
98
+ onClick={() => setIsOpen((prev) => !prev)}
99
+ className="rounded-md p-1.5 text-[rgb(var(--ec-icon-color))] transition-colors hover:bg-[rgb(var(--ec-content-hover)/0.5)] hover:text-[rgb(var(--ec-page-text))]"
100
+ >
101
+ <EllipsisVerticalIcon className="h-4 w-4" />
102
+ </button>
103
+
104
+ {isOpen &&
105
+ typeof document !== 'undefined' &&
106
+ createPortal(
107
+ <div
108
+ ref={menuRef}
109
+ role="menu"
110
+ style={{
111
+ position: 'fixed',
112
+ top: menuPosition?.top ?? -9999,
113
+ left: menuPosition?.left ?? -9999,
114
+ width: MENU_WIDTH,
115
+ visibility: menuPosition ? 'visible' : 'hidden',
116
+ }}
117
+ className="z-50 overflow-hidden rounded-xl border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-dropdown-bg))] shadow-xl"
118
+ >
119
+ <a
120
+ href={href}
121
+ className="flex items-center gap-2.5 px-3 py-2.5 text-xs font-medium text-[rgb(var(--ec-page-text))] transition-colors hover:bg-[rgb(var(--ec-content-hover))] hover:text-[rgb(var(--ec-accent))]"
122
+ >
123
+ <DocumentTextIcon className="h-3.5 w-3.5 text-[rgb(var(--ec-page-text-muted))]" />
124
+ View documentation
125
+ </a>
126
+ {visualiserHref && (
127
+ <a
128
+ href={visualiserHref}
129
+ className="flex items-center gap-2.5 px-3 py-2.5 text-xs font-medium text-[rgb(var(--ec-page-text))] transition-colors hover:bg-[rgb(var(--ec-content-hover))] hover:text-[rgb(var(--ec-accent))]"
130
+ >
131
+ <MapIcon className="h-3.5 w-3.5 text-[rgb(var(--ec-page-text-muted))]" />
132
+ View in visualiser
133
+ </a>
134
+ )}
135
+ {schemaHref && (
136
+ <a
137
+ href={schemaHref}
138
+ className="flex items-center gap-2.5 px-3 py-2.5 text-xs font-medium text-[rgb(var(--ec-page-text))] transition-colors hover:bg-[rgb(var(--ec-content-hover))] hover:text-[rgb(var(--ec-accent))]"
139
+ >
140
+ <CodeBracketIcon className="h-3.5 w-3.5 text-[rgb(var(--ec-page-text-muted))]" />
141
+ View schema
142
+ </a>
143
+ )}
144
+ <button
145
+ type="button"
146
+ onClick={handleToggleFavorite}
147
+ className="flex w-full items-center gap-2.5 px-3 py-2.5 text-left text-xs font-medium text-[rgb(var(--ec-page-text))] transition-colors hover:bg-[rgb(var(--ec-content-hover))] hover:text-[rgb(var(--ec-accent))]"
148
+ >
149
+ <StarIcon className="h-3.5 w-3.5 text-[rgb(var(--ec-page-text-muted))]" />
150
+ {isFavorite ? 'Remove from favorites' : 'Add to favorites'}
151
+ </button>
152
+ </div>,
153
+ document.body
154
+ )}
155
+ </div>
156
+ );
157
+ }
@@ -0,0 +1,82 @@
1
+ import { useEffect, useState } from 'react';
2
+ import type { Table } from '@tanstack/react-table';
3
+ import { ChevronLeft, ChevronRight } from 'lucide-react';
4
+
5
+ export const PAGE_SIZE_OPTIONS = [10, 25, 50, 100];
6
+
7
+ /** Page size for a table, remembered in the browser under `storageKey`. */
8
+ export function useStoredPageSize(storageKey: string) {
9
+ const [pageSize, setPageSize] = useState<number>(() => {
10
+ if (typeof window === 'undefined') return 10;
11
+ const stored = Number(window.localStorage.getItem(storageKey));
12
+ return PAGE_SIZE_OPTIONS.includes(stored) ? stored : 10;
13
+ });
14
+ useEffect(() => {
15
+ if (typeof window !== 'undefined') {
16
+ window.localStorage.setItem(storageKey, String(pageSize));
17
+ }
18
+ }, [pageSize, storageKey]);
19
+ return [pageSize, setPageSize] as const;
20
+ }
21
+
22
+ interface TablePaginationProps<TData> {
23
+ table: Table<TData>;
24
+ pageSize: number;
25
+ onPageSizeChange: (pageSize: number) => void;
26
+ }
27
+
28
+ /** Footer with the result count, page size picker and previous/next page controls. */
29
+ export function TablePagination<TData>({ table, pageSize, onPageSizeChange }: TablePaginationProps<TData>) {
30
+ const totalResults = table.getPrePaginationRowModel().rows.length;
31
+
32
+ return (
33
+ <div className="flex-shrink-0 flex items-center justify-between px-6 py-3 border-t border-[rgb(var(--ec-page-border))]">
34
+ <div className="flex items-center gap-3 text-xs text-[rgb(var(--ec-page-text-muted))]">
35
+ {totalResults > 0 && (
36
+ <span>
37
+ <span className="font-medium text-[rgb(var(--ec-page-text))]">{table.getRowModel().rows.length}</span> of{' '}
38
+ <span className="font-medium text-[rgb(var(--ec-page-text))]">{totalResults}</span> results
39
+ </span>
40
+ )}
41
+ {totalResults > 0 && <span aria-hidden className="h-3 w-px bg-[rgb(var(--ec-page-border))]" />}
42
+ <label className="flex items-center gap-1.5">
43
+ <span>Per page</span>
44
+ <select
45
+ value={pageSize}
46
+ onChange={(e) => onPageSizeChange(Number(e.target.value))}
47
+ className="cursor-pointer rounded bg-transparent px-1 py-0.5 font-medium text-[rgb(var(--ec-page-text))] hover:bg-[rgb(var(--ec-content-hover))] focus:bg-[rgb(var(--ec-content-hover))] focus:outline-none"
48
+ >
49
+ {PAGE_SIZE_OPTIONS.map((size) => (
50
+ <option key={size} value={size}>
51
+ {size}
52
+ </option>
53
+ ))}
54
+ </select>
55
+ </label>
56
+ </div>
57
+ <div className="flex items-center gap-1.5">
58
+ <button
59
+ className="p-1.5 text-[rgb(var(--ec-icon-color))] hover:text-[rgb(var(--ec-page-text))] disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
60
+ onClick={() => table.previousPage()}
61
+ disabled={!table.getCanPreviousPage()}
62
+ title="Previous page"
63
+ >
64
+ <ChevronLeft className="w-4 h-4" />
65
+ </button>
66
+ <span className="text-xs tabular-nums text-[rgb(var(--ec-page-text-muted))] min-w-[60px] text-center">
67
+ <span className="font-medium text-[rgb(var(--ec-page-text))]">{table.getState().pagination.pageIndex + 1}</span>
68
+ {' / '}
69
+ <span>{table.getPageCount() || 1}</span>
70
+ </span>
71
+ <button
72
+ className="p-1.5 text-[rgb(var(--ec-icon-color))] hover:text-[rgb(var(--ec-page-text))] disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
73
+ onClick={() => table.nextPage()}
74
+ disabled={!table.getCanNextPage()}
75
+ title="Next page"
76
+ >
77
+ <ChevronRight className="w-4 h-4" />
78
+ </button>
79
+ </div>
80
+ </div>
81
+ );
82
+ }
@@ -127,10 +127,10 @@ The user will ask you some questions about the software architecture catalog, yo
127
127
 
128
128
  At point the referer url (${referrer}) will be the URL of the page the user is on, you should use this to help you answer the question,
129
129
  You may be able to get the resource from the URL
130
- - Example if the url is like /docs|visualiser|architecture/{collection}/{id}/{version}
130
+ - Example if the url is like /docs|visualiser/{collection}/{id}/{version}
131
131
  - (e.g /docs/events/MyEvent/1.0.0) in this case the id is MyEvent and the version is 1.0.0 and collection is events.
132
132
  - (e.g /visualiser/domains/MyDomain/1.0.0) in this case the id is MyDomain and the version is 1.0.0 and collection is domains.
133
- - (e.g /architecture/services/MyService/1.0.0) in this case the id is MyService and the version is 1.0.0 and collection is services.
133
+ - (e.g /docs/services/MyService/1.0.0/resources) in this case the id is MyService and the version is 1.0.0 and collection is services; the user is looking at the resources the service uses.
134
134
 
135
135
  The referer URL is: ${referrer}
136
136
 
@@ -159,7 +159,7 @@ When responding:
159
159
  - The link options are:
160
160
  - If you want to get the documentation for a resource use the /docs/ prefix (e.g /docs/{collection}/{id}/{version})
161
161
  - If you want to let the user know they can visualize a resource use the /visualiser/ prefix (e.g /visualiser/{collection}/{id}/{version})
162
- - If you want to let the user know they can see the architecture of a resource use the /architecture/ prefix (e.g /architecture/{collection}/{id}/{version})
162
+ - If you want to show the user everything a domain, system, service, flow, channel or message (event, command, query) contains, uses or connects to, link its Resources page (e.g /docs/{collection}/{id}/{version}/resources). Only those collections have a Resources page.
163
163
  - If you don't know the version, use the getResource tool to fetch the resource and get the actual version number before creating the link.
164
164
  7. When you return a schema, use code blocks to render the schema to the user too, for example if the schema is in JSON format use \`\`\`json and if the schema is in YAML format use \`\`\`yaml
165
165
  8. IMPORTANT: After answering each question, ALWAYS use the suggestFollowUpQuestions tool to suggest 2-3 relevant follow-up questions the user might want to ask next. These should be contextual to the conversation and help the user explore related topics.