@eventcatalog/core 2.33.12 → 2.34.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 (36) 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-5THCKFYU.js → chunk-GUCQ43OT.js} +1 -1
  6. package/dist/{chunk-GXZYW6VG.js → chunk-VU6QMU5H.js} +1 -1
  7. package/dist/{chunk-K3CDZR6K.js → chunk-XOPHTY4E.js} +1 -1
  8. package/dist/constants.cjs +1 -1
  9. package/dist/constants.js +1 -1
  10. package/dist/eventcatalog.cjs +1 -1
  11. package/dist/eventcatalog.js +3 -3
  12. package/eventcatalog/src/components/Grids/DomainGrid.tsx +52 -0
  13. package/eventcatalog/src/components/Grids/ServiceGrid.tsx +198 -168
  14. package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.tsx +40 -16
  15. package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Channel.tsx +3 -1
  16. package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Command.tsx +3 -1
  17. package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Custom.tsx +1 -1
  18. package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Event.tsx +13 -2
  19. package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Query.tsx +3 -1
  20. package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Service.tsx +3 -1
  21. package/eventcatalog/src/components/MDX/NodeGraph/Nodes/User.tsx +1 -1
  22. package/eventcatalog/src/components/MDX/SchemaViewer/SchemaViewerRoot.astro +0 -3
  23. package/eventcatalog/src/components/SideBars/DomainSideBar.astro +47 -2
  24. package/eventcatalog/src/components/SideBars/ServiceSideBar.astro +22 -0
  25. package/eventcatalog/src/components/SideNav/ListViewSideBar/index.tsx +11 -1
  26. package/eventcatalog/src/components/SideNav/ListViewSideBar/types.ts +1 -0
  27. package/eventcatalog/src/components/SideNav/ListViewSideBar/utils.ts +1 -0
  28. package/eventcatalog/src/content.config.ts +1 -0
  29. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/index.tsx +0 -3
  30. package/eventcatalog/src/pages/architecture/architecture.astro +17 -6
  31. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +1 -5
  32. package/eventcatalog/src/pages/docs/teams/[id]/index.astro +100 -102
  33. package/eventcatalog/src/pages/docs/users/[id]/index.astro +4 -12
  34. package/eventcatalog/src/utils/collections/domains.ts +32 -2
  35. package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +31 -2
  36. package/package.json +1 -1
@@ -37,7 +37,7 @@ var import_axios = __toESM(require("axios"), 1);
37
37
  var import_os = __toESM(require("os"), 1);
38
38
 
39
39
  // package.json
40
- var version = "2.33.12";
40
+ var version = "2.34.1";
41
41
 
42
42
  // src/constants.ts
43
43
  var VERSION = version;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "../chunk-5THCKFYU.js";
4
- import "../chunk-K3CDZR6K.js";
3
+ } from "../chunk-GUCQ43OT.js";
4
+ import "../chunk-XOPHTY4E.js";
5
5
  export {
6
6
  raiseEvent
7
7
  };
@@ -106,7 +106,7 @@ var import_axios = __toESM(require("axios"), 1);
106
106
  var import_os = __toESM(require("os"), 1);
107
107
 
108
108
  // package.json
109
- var version = "2.33.12";
109
+ var version = "2.34.1";
110
110
 
111
111
  // src/constants.ts
112
112
  var VERSION = version;
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  log_build_default
3
- } from "../chunk-GXZYW6VG.js";
4
- import "../chunk-5THCKFYU.js";
5
- import "../chunk-K3CDZR6K.js";
3
+ } from "../chunk-VU6QMU5H.js";
4
+ import "../chunk-GUCQ43OT.js";
5
+ import "../chunk-XOPHTY4E.js";
6
6
  import "../chunk-E7TXTI7G.js";
7
7
  export {
8
8
  log_build_default as default
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-K3CDZR6K.js";
3
+ } from "./chunk-XOPHTY4E.js";
4
4
 
5
5
  // src/analytics/analytics.js
6
6
  import axios from "axios";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "./chunk-5THCKFYU.js";
3
+ } from "./chunk-GUCQ43OT.js";
4
4
  import {
5
5
  getEventCatalogConfigFile,
6
6
  verifyRequiredFieldsAreInCatalogConfigFile
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "2.33.12";
2
+ var version = "2.34.1";
3
3
 
4
4
  // src/constants.ts
5
5
  var VERSION = version;
@@ -25,7 +25,7 @@ __export(constants_exports, {
25
25
  module.exports = __toCommonJS(constants_exports);
26
26
 
27
27
  // package.json
28
- var version = "2.33.12";
28
+ var version = "2.34.1";
29
29
 
30
30
  // src/constants.ts
31
31
  var VERSION = version;
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-K3CDZR6K.js";
3
+ } from "./chunk-XOPHTY4E.js";
4
4
  export {
5
5
  VERSION
6
6
  };
@@ -157,7 +157,7 @@ var import_axios = __toESM(require("axios"), 1);
157
157
  var import_os = __toESM(require("os"), 1);
158
158
 
159
159
  // package.json
160
- var version = "2.33.12";
160
+ var version = "2.34.1";
161
161
 
162
162
  // src/constants.ts
163
163
  var VERSION = version;
@@ -6,15 +6,15 @@ import {
6
6
  } from "./chunk-UKJ7F5WR.js";
7
7
  import {
8
8
  log_build_default
9
- } from "./chunk-GXZYW6VG.js";
10
- import "./chunk-5THCKFYU.js";
9
+ } from "./chunk-VU6QMU5H.js";
10
+ import "./chunk-GUCQ43OT.js";
11
11
  import {
12
12
  catalogToAstro,
13
13
  checkAndConvertMdToMdx
14
14
  } from "./chunk-7SI5EVOX.js";
15
15
  import {
16
16
  VERSION
17
- } from "./chunk-K3CDZR6K.js";
17
+ } from "./chunk-XOPHTY4E.js";
18
18
  import {
19
19
  isBackstagePluginEnabled,
20
20
  isEventCatalogScaleEnabled,
@@ -10,6 +10,7 @@ export interface ExtendedDomain extends CollectionEntry<'domains'> {
10
10
  sends: CollectionEntry<CollectionMessageTypes>[];
11
11
  receives: CollectionEntry<CollectionMessageTypes>[];
12
12
  services: CollectionEntry<'services'>[];
13
+ domains: CollectionEntry<'domains'>[];
13
14
  }
14
15
 
15
16
  interface DomainGridProps {
@@ -102,6 +103,12 @@ export default function DomainGrid({ domains, embeded }: DomainGridProps) {
102
103
  </p>
103
104
 
104
105
  <div className="flex gap-4 mb-4">
106
+ <div className="flex items-center gap-2 bg-white rounded-lg px-3 py-2 border border-orange-200">
107
+ <RectangleGroupIcon className="h-4 w-4 text-yellow-500" />
108
+ <div className="flex">
109
+ <p className="text-sm font-medium text-gray-900">{domain.data.domains?.length || 0} Subdomains</p>
110
+ </div>
111
+ </div>
105
112
  <div className="flex items-center gap-2 bg-white rounded-lg px-3 py-2 border border-pink-200">
106
113
  <ServerIcon className="h-4 w-4 text-pink-500" />
107
114
  <div className="flex">
@@ -119,6 +126,41 @@ export default function DomainGrid({ domains, embeded }: DomainGridProps) {
119
126
  </div>
120
127
 
121
128
  <div className="space-y-6">
129
+ {/* Subdomains and there services */}
130
+ {domain.data.domains?.slice(0, 2).map((subdomain: any) => (
131
+ <div
132
+ key={subdomain.data.id}
133
+ className="block space-y-2 bg-white border-2 border-dashed border-orange-400 p-4 rounded-lg transition-colors duration-200"
134
+ >
135
+ <div className="flex items-center justify-between">
136
+ <div className="flex items-center gap-2">
137
+ <RectangleGroupIcon className="h-4 w-4 text-orange-500" />
138
+ <h4 className="text-sm font-medium text-gray-900">
139
+ {subdomain.data.name || subdomain.data.id} (Subdomain)
140
+ </h4>
141
+ </div>
142
+ <span className="text-xs text-gray-500">v{subdomain.data.version}</span>
143
+ </div>
144
+
145
+ <div className="flex gap-4">
146
+ <div className="flex items-center gap-2 bg-white rounded-lg px-3 py-2 border border-pink-200">
147
+ <ServerIcon className="h-4 w-4 text-pink-500" />
148
+ <div className="flex">
149
+ <p className="text-sm font-medium text-gray-900">{subdomain.data.services?.length || 0} Services</p>
150
+ </div>
151
+ </div>
152
+ <div className="flex items-center gap-2 bg-white rounded-lg px-3 py-2 border border-gray-200">
153
+ <EnvelopeIcon className="h-4 w-4 text-blue-500" />
154
+ <div>
155
+ <p className="text-sm font-medium text-gray-900">
156
+ {(subdomain.sends?.length || 0) + (subdomain.receives?.length || 0)} Messages
157
+ </p>
158
+ </div>
159
+ </div>
160
+ </div>
161
+ </div>
162
+ ))}
163
+
122
164
  {/* Services and their messages */}
123
165
  {domain.data.services?.slice(0, 2).map((service: any) => (
124
166
  <div
@@ -211,6 +253,16 @@ export default function DomainGrid({ domains, embeded }: DomainGridProps) {
211
253
  </div>
212
254
  </div>
213
255
  ))}
256
+ {domain.data.domains && domain.data.domains.length > 2 && (
257
+ <div className="block space-y-2 bg-white border-2 border-dashed border-orange-400 p-4 rounded-lg transition-colors duration-200">
258
+ <div className="flex items-center justify-between">
259
+ <div className="flex items-center gap-2">
260
+ <RectangleGroupIcon className="h-4 w-4 text-orange-500/70" />
261
+ <h4 className="text-sm font-medium text-gray-600">+{domain.data.domains.length - 2} more subdomains</h4>
262
+ </div>
263
+ </div>
264
+ </div>
265
+ )}
214
266
  {domain.data.services && domain.data.services.length > 2 && (
215
267
  <div className="block space-y-2 bg-white border-2 border-dashed border-pink-400 p-4 rounded-lg transition-colors duration-200">
216
268
  <div className="flex items-center justify-between">
@@ -1,4 +1,4 @@
1
- import { useState, useMemo, useEffect } from 'react';
1
+ import { useState, useMemo, useEffect, memo } from 'react';
2
2
  import { ServerIcon, ChevronRightIcon } from '@heroicons/react/24/outline';
3
3
  import { RectangleGroupIcon } from '@heroicons/react/24/outline';
4
4
  import { buildUrl, buildUrlWithParams } from '@utils/url-builder';
@@ -6,13 +6,187 @@ import type { CollectionEntry } from 'astro:content';
6
6
  import type { CollectionMessageTypes } from '@types';
7
7
  import { getCollectionStyles } from './utils';
8
8
  import { SearchBar, TypeFilters, Pagination } from './components';
9
+ import type { ExtendedDomain } from './DomainGrid';
10
+
11
+ // Message component for reuse
12
+ const Message = memo(({ message, collection }: { message: any; collection: string }) => {
13
+ const { Icon, color } = getCollectionStyles(message.collection);
14
+ return (
15
+ <a
16
+ href={buildUrl(`/docs/${message.collection}/${message.data.id}/${message.data.version}`)}
17
+ className="group flex border border-gray-200 items-center gap-1 rounded-md text-[11px] font-medium hover:bg-gray-50 transition-colors duration-200 bg-white"
18
+ >
19
+ <div className="bg-white border-r border-gray-200 px-2 py-1.5 rounded-l-md">
20
+ <Icon className={`h-3 w-3 text-${color}-500`} />
21
+ </div>
22
+ <span className="px-1 py-1 truncate max-w-[140px]">{message.data.name}</span>
23
+ </a>
24
+ );
25
+ });
26
+
27
+ // Messages Container component
28
+ const MessagesContainer = memo(
29
+ ({ messages, type, selectedTypes }: { messages: any[]; type: 'receives' | 'sends'; selectedTypes: string[] }) => {
30
+ const bgColor = type === 'receives' ? 'blue' : 'green';
31
+ const filteredMessages = messages?.filter(
32
+ (message: any) => selectedTypes.length === 0 || selectedTypes.includes(message.collection)
33
+ );
34
+
35
+ return (
36
+ <div className={`flex-1 h-full flex flex-col bg-${bgColor}-100 border border-${bgColor}-300 rounded-lg p-4`}>
37
+ <div className="space-y-2 flex-1">
38
+ {filteredMessages?.map((message: any) => (
39
+ <Message key={message.data.name} message={message} collection={message.collection} />
40
+ ))}
41
+ {(!messages?.length ||
42
+ (selectedTypes.length > 0 && !messages?.some((message: any) => selectedTypes.includes(message.collection)))) && (
43
+ <div className="text-center py-4">
44
+ <p className="text-gray-500 text-[10px]">
45
+ {selectedTypes.length > 0
46
+ ? `Service does not ${type} ${selectedTypes.join(' or ')}`
47
+ : `Service does not ${type} any messages`}
48
+ </p>
49
+ </div>
50
+ )}
51
+ </div>
52
+ </div>
53
+ );
54
+ }
55
+ );
56
+
57
+ // Service Card component
58
+ const ServiceCard = memo(({ service, urlParams, selectedTypes }: { service: any; urlParams: any; selectedTypes: string[] }) => {
59
+ return (
60
+ <a
61
+ href={buildUrlWithParams('/architecture/messages', {
62
+ serviceName: service.data.name,
63
+ serviceId: service.data.id,
64
+ domainId: urlParams?.domainId,
65
+ domainName: urlParams?.domainName,
66
+ })}
67
+ className="group hover:bg-pink-50 bg-white border-2 border-dashed border-pink-400 rounded-lg shadow-sm hover:shadow-lg transition-all duration-200 overflow-hidden "
68
+ >
69
+ <div className="p-6">
70
+ <div className="flex items-center justify-between mb-3">
71
+ <div className="flex items-center gap-2 w-full">
72
+ <ServerIcon className="h-5 w-5 text-pink-500" />
73
+ <h3 className="text-lg font-semibold text-gray-900 truncate group-hover:underline transition-colors duration-200 w-full max-w-[90%]">
74
+ {service.data.name || service.data.id} (v{service.data.version})
75
+ </h3>
76
+ </div>
77
+ </div>
78
+
79
+ {service.data.summary && <p className="text-gray-600 text-sm line-clamp-2 min-h-[2.5rem]">{service.data.summary}</p>}
80
+
81
+ {!urlParams?.serviceName && (
82
+ <div className="flex items-center gap-4 mt-4">
83
+ <MessagesContainer messages={service.data.receives} type="receives" selectedTypes={selectedTypes} />
84
+
85
+ <div className="flex items-center gap-2 max-w-[200px]">
86
+ <div className="w-4 h-[2px] bg-blue-200"></div>
87
+ <div className="bg-white border-2 border-pink-100 rounded-lg p-4 shadow-sm">
88
+ <div className="flex flex-col items-center gap-3">
89
+ <ServerIcon className="h-8 w-8 text-pink-500" />
90
+ <div className="text-center">
91
+ <p className="text-sm font-medium text-gray-900">{service.data.name || service.data.id}</p>
92
+ <p className="text-xs text-gray-500">v{service.data.version}</p>
93
+ </div>
94
+ </div>
95
+ </div>
96
+ <div className="w-4 h-[2px] bg-emerald-200"></div>
97
+ </div>
98
+
99
+ <MessagesContainer messages={service.data.sends} type="sends" selectedTypes={selectedTypes} />
100
+ </div>
101
+ )}
102
+ </div>
103
+ </a>
104
+ );
105
+ });
106
+
107
+ // Domain Section component
108
+ const DomainSection = memo(
109
+ ({ domain, services, urlParams, selectedTypes }: { domain: any; services: any[]; urlParams: any; selectedTypes: string[] }) => {
110
+ const subdomains = domain.data.domains || [];
111
+ const allSubDomainServices = subdomains.map((subdomain: any) => subdomain.data.services || []).flat();
112
+
113
+ const servicesWithoutSubdomains = services.filter((service) => {
114
+ return !allSubDomainServices.some((s: any) => s.id === service.data.id);
115
+ });
116
+
117
+ return (
118
+ <div className="space-y-6">
119
+ {servicesWithoutSubdomains.length > 0 && (
120
+ <div className="grid grid-cols-1 sm:grid-cols-1 lg:grid-cols-1 xl:grid-cols-2 gap-6">
121
+ {servicesWithoutSubdomains.map((service) => (
122
+ <ServiceCard key={service.data.id} service={service} urlParams={urlParams} selectedTypes={selectedTypes} />
123
+ ))}
124
+ </div>
125
+ )}
126
+
127
+ {subdomains.map((subdomainRef: any) => {
128
+ const subdomain = domain.data.domains?.find((d: any) => d.data.id === subdomainRef.data.id);
129
+ if (!subdomain) return null;
130
+
131
+ const subdomainServices = services.filter((service) =>
132
+ subdomain.data.services?.some((s: any) => s.id === service.data.id)
133
+ );
134
+
135
+ if (subdomainServices.length === 0) return null;
136
+
137
+ return (
138
+ <div key={subdomain.data.id} className="bg-orange-50 border-2 border-orange-400 rounded-lg p-6 space-y-4">
139
+ <div className="flex items-center justify-between">
140
+ <div className="flex items-center gap-2">
141
+ <RectangleGroupIcon className="h-5 w-5 text-orange-500" />
142
+ <h3 className="text-xl font-semibold text-gray-900">{subdomain.data.name} (Subdomain)</h3>
143
+ </div>
144
+ <div className="flex gap-2">
145
+ <a
146
+ href={buildUrl(`/visualiser/domains/${subdomain.data.id}`)}
147
+ className="inline-flex items-center px-3 py-2 text-sm font-medium bg-white border border-gray-300 rounded-md transition-colors duration-200"
148
+ >
149
+ View in visualizer
150
+ </a>
151
+ <a
152
+ href={buildUrl(`/docs/domains/${subdomain.data.id}`)}
153
+ className="inline-flex items-center px-3 py-2 text-sm font-medium text-black border border-gray-300 bg-white rounded-md transition-colors duration-200"
154
+ >
155
+ Read documentation
156
+ </a>
157
+ </div>
158
+ </div>
159
+
160
+ <div className="grid grid-cols-1 sm:grid-cols-1 lg:grid-cols-1 xl:grid-cols-2 gap-6">
161
+ {subdomainServices.map((service) => (
162
+ <ServiceCard
163
+ key={service.data.id}
164
+ service={service}
165
+ urlParams={{
166
+ ...urlParams,
167
+ domainId: subdomain.data.id,
168
+ domainName: `${subdomain.data.name} (Subdomain)`,
169
+ }}
170
+ selectedTypes={selectedTypes}
171
+ />
172
+ ))}
173
+ </div>
174
+ </div>
175
+ );
176
+ })}
177
+ </div>
178
+ );
179
+ }
180
+ );
9
181
 
10
182
  interface ServiceGridProps {
11
183
  services: CollectionEntry<'services'>[];
184
+ domains: ExtendedDomain[];
12
185
  embeded: boolean;
13
186
  }
14
187
 
15
- export default function ServiceGrid({ services, embeded }: ServiceGridProps) {
188
+ // Main ServiceGrid component
189
+ export default function ServiceGrid({ services, domains, embeded }: ServiceGridProps) {
16
190
  const [searchQuery, setSearchQuery] = useState('');
17
191
  const [currentPage, setCurrentPage] = useState(1);
18
192
  const [selectedTypes, setSelectedTypes] = useState<CollectionMessageTypes[]>([]);
@@ -24,35 +198,27 @@ export default function ServiceGrid({ services, embeded }: ServiceGridProps) {
24
198
  serviceName?: string;
25
199
  } | null>(null);
26
200
 
27
- // Effect to sync URL params with state
28
201
  useEffect(() => {
29
202
  const params = new URLSearchParams(window.location.search);
30
- const serviceIds = params.get('serviceIds')?.split(',').filter(Boolean);
31
- const domainId = params.get('domainId') || undefined;
32
- const domainName = params.get('domainName') || undefined;
33
- const serviceName = params.get('serviceName') || undefined;
34
203
  setUrlParams({
35
- serviceIds,
36
- domainId,
37
- domainName,
38
- serviceName,
204
+ serviceIds: params.get('serviceIds')?.split(',').filter(Boolean),
205
+ domainId: params.get('domainId') || undefined,
206
+ domainName: params.get('domainName') || undefined,
207
+ serviceName: params.get('serviceName') || undefined,
39
208
  });
40
209
  }, []);
41
210
 
42
211
  const filteredAndSortedServices = useMemo(() => {
43
- // Don't filter until we have URL params
44
212
  if (urlParams === null) return [];
45
213
 
46
214
  let result = [...services];
47
215
 
48
- // Filter by service IDs if present
49
216
  if (urlParams.serviceIds?.length) {
50
217
  result = result.filter(
51
218
  (service) => urlParams.serviceIds?.includes(service.data.id) && !service.data.id.includes('/versioned/')
52
219
  );
53
220
  }
54
221
 
55
- // Filter by search query
56
222
  if (searchQuery) {
57
223
  const query = searchQuery.toLowerCase();
58
224
  result = result.filter(
@@ -64,7 +230,6 @@ export default function ServiceGrid({ services, embeded }: ServiceGridProps) {
64
230
  );
65
231
  }
66
232
 
67
- // Filter by selected message types
68
233
  if (selectedTypes.length > 0) {
69
234
  result = result.filter((service) => {
70
235
  const hasMatchingSends = service.data.sends?.some((message: any) => selectedTypes.includes(message.collection));
@@ -73,18 +238,14 @@ export default function ServiceGrid({ services, embeded }: ServiceGridProps) {
73
238
  });
74
239
  }
75
240
 
76
- // Sort by name by default
77
241
  result.sort((a, b) => (a.data.name || a.data.id).localeCompare(b.data.name || b.data.id));
78
-
79
242
  return result;
80
243
  }, [services, searchQuery, urlParams, selectedTypes]);
81
244
 
82
- // Add pagination calculation
83
245
  const paginatedServices = useMemo(() => {
84
246
  if (urlParams?.domainId || urlParams?.serviceIds?.length) {
85
247
  return filteredAndSortedServices;
86
248
  }
87
-
88
249
  const startIndex = (currentPage - 1) * ITEMS_PER_PAGE;
89
250
  return filteredAndSortedServices.slice(startIndex, startIndex + ITEMS_PER_PAGE);
90
251
  }, [filteredAndSortedServices, currentPage, urlParams]);
@@ -94,7 +255,6 @@ export default function ServiceGrid({ services, embeded }: ServiceGridProps) {
94
255
  return Math.ceil(filteredAndSortedServices.length / ITEMS_PER_PAGE);
95
256
  }, [filteredAndSortedServices.length, urlParams]);
96
257
 
97
- // Reset pagination when search query or filters change
98
258
  useEffect(() => {
99
259
  setCurrentPage(1);
100
260
  }, [searchQuery, selectedTypes]);
@@ -184,155 +344,25 @@ export default function ServiceGrid({ services, embeded }: ServiceGridProps) {
184
344
 
185
345
  {filteredAndSortedServices.length > 0 && (
186
346
  <div className={`rounded-xl overflow-hidden ${urlParams?.domainId ? 'bg-yellow-50 p-8 border-2 border-yellow-400' : ''}`}>
187
- {urlParams?.domainName && (
188
- <>
189
- <div className="mb-6 flex items-center justify-between">
190
- <div className="flex items-center gap-2">
191
- <RectangleGroupIcon className="h-5 w-5 text-yellow-500" />
192
- <span className="text-2xl font-semibold text-gray-900">{urlParams.domainName}</span>
193
- </div>
194
- <div className="flex gap-2">
195
- <a
196
- href={buildUrl(`/visualiser/domains/${urlParams.domainId}`)}
197
- className="inline-flex items-center px-3 py-2 text-sm font-medium bg-white border border-gray-300 rounded-md transition-colors duration-200"
198
- >
199
- View in visualizer
200
- </a>
201
- <a
202
- href={buildUrl(`/docs/domains/${urlParams.domainId}`)}
203
- className="inline-flex items-center px-3 py-2 text-sm font-medium text-black border border-gray-300 bg-white rounded-md transition-colors duration-200"
204
- >
205
- Read documentation
206
- </a>
207
- </div>
208
- </div>
209
- </>
347
+ {urlParams?.domainName ? (
348
+ domains
349
+ .filter((domain: ExtendedDomain) => domain.data.id === urlParams.domainId)
350
+ .map((domain: ExtendedDomain) => (
351
+ <DomainSection
352
+ key={domain.data.id}
353
+ domain={domain}
354
+ services={paginatedServices}
355
+ urlParams={urlParams}
356
+ selectedTypes={selectedTypes}
357
+ />
358
+ ))
359
+ ) : (
360
+ <div className={`grid grid-cols-1 sm:grid-cols-1 lg:grid-cols-1 xl:grid-cols-${embeded ? 1 : 2} gap-6`}>
361
+ {paginatedServices.map((service) => (
362
+ <ServiceCard key={service.data.id} service={service} urlParams={urlParams} selectedTypes={selectedTypes} />
363
+ ))}
364
+ </div>
210
365
  )}
211
-
212
- <div className={`grid grid-cols-1 sm:grid-cols-1 lg:grid-cols-1 xl:grid-cols-${embeded ? 1 : 2} gap-6`}>
213
- {paginatedServices.map((service) => {
214
- return (
215
- <a
216
- key={service.data.id}
217
- href={buildUrlWithParams('/architecture/messages', {
218
- serviceName: service.data.name,
219
- serviceId: service.data.id,
220
- domainId: urlParams?.domainId,
221
- domainName: urlParams?.domainName,
222
- })}
223
- className="group hover:bg-pink-50 bg-white border-2 border-dashed border-pink-400 rounded-lg shadow-sm hover:shadow-lg transition-all duration-200 overflow-hidden"
224
- >
225
- <div className="p-6">
226
- <div className="flex items-center justify-between mb-3">
227
- <div className="flex items-center gap-2 w-full">
228
- <ServerIcon className="h-5 w-5 text-pink-500" />
229
- <h3 className="text-lg font-semibold text-gray-900 truncate group-hover:underline transition-colors duration-200 w-full max-w-[90%]">
230
- {service.data.name || service.data.id} (v{service.data.version})
231
- </h3>
232
- </div>
233
- </div>
234
-
235
- {service.data.summary && (
236
- <p className="text-gray-600 text-sm line-clamp-2 min-h-[2.5rem]">{service.data.summary}</p>
237
- )}
238
-
239
- <div className="space-y-4">
240
- {/* Messages Section */}
241
- {!urlParams?.serviceName && (
242
- <div className="flex items-center gap-4">
243
- <div className="flex-1 h-full flex flex-col bg-blue-100 border border-blue-300 rounded-lg p-4">
244
- <div className="space-y-2 flex-1">
245
- {service.data.receives
246
- ?.filter(
247
- (message: any) => selectedTypes.length === 0 || selectedTypes.includes(message.collection)
248
- )
249
- ?.map((message: any) => {
250
- const { Icon, color } = getCollectionStyles(message.collection);
251
- return (
252
- <a
253
- key={message.data.name}
254
- href={buildUrl(`/docs/${message.collection}/${message.data.id}/${message.data.version}`)}
255
- className="group flex border border-gray-200 items-center gap-1 rounded-md text-[11px] font-medium hover:bg-gray-50 transition-colors duration-200 bg-white"
256
- >
257
- <div className="bg-white border-r border-gray-200 px-2 py-1.5 rounded-l-md">
258
- <Icon className={`h-3 w-3 text-${color}-500`} />
259
- </div>
260
- <span className="px-1 py-1 truncate max-w-[140px]">{message.data.name}</span>
261
- </a>
262
- );
263
- })}
264
- {(!service.data.receives?.length ||
265
- (selectedTypes.length > 0 &&
266
- !service.data.receives?.some((message: any) =>
267
- selectedTypes.includes(message.collection)
268
- ))) && (
269
- <div className="text-center py-4">
270
- <p className="text-gray-500 text-[10px]">
271
- {selectedTypes.length > 0
272
- ? `Service does not receive ${selectedTypes.join(' or ')}`
273
- : 'Service does not receive any messages'}
274
- </p>
275
- </div>
276
- )}
277
- </div>
278
- </div>
279
-
280
- <div className="flex items-center gap-2 max-w-[200px]">
281
- <div className="w-4 h-[2px] bg-blue-200"></div>
282
- <div className="bg-white border-2 border-pink-100 rounded-lg p-4 shadow-sm">
283
- <div className="flex flex-col items-center gap-3">
284
- <ServerIcon className="h-8 w-8 text-pink-500" />
285
- <div className="text-center">
286
- <p className="text-sm font-medium text-gray-900">{service.data.name || service.data.id}</p>
287
- <p className="text-xs text-gray-500">v{service.data.version}</p>
288
- </div>
289
- </div>
290
- </div>
291
- <div className="w-4 h-[2px] bg-emerald-200"></div>
292
- </div>
293
-
294
- <div className="flex-1 h-full flex flex-col bg-green-100 border border-green-300 rounded-lg p-4">
295
- <div className="space-y-2 flex-1">
296
- {service.data.sends
297
- ?.filter(
298
- (message: any) => selectedTypes.length === 0 || selectedTypes.includes(message.collection)
299
- )
300
- ?.map((message: any) => {
301
- const { Icon, color } = getCollectionStyles(message.collection);
302
- return (
303
- <a
304
- key={message.data.name}
305
- href={buildUrl(`/docs/${message.collection}/${message.data.id}/${message.data.version}`)}
306
- className="group flex border border-gray-200 items-center gap-1 rounded-md text-[11px] font-medium hover:bg-gray-50 transition-colors duration-200 bg-white"
307
- >
308
- <div className="bg-white border-r border-gray-200 px-2 py-1.5 rounded-l-md">
309
- <Icon className={`h-3 w-3 text-${color}-500`} />
310
- </div>
311
- <span className="px-1 py-1 truncate max-w-[140px]">{message.data.name}</span>
312
- </a>
313
- );
314
- })}
315
- {(!service.data.sends?.length ||
316
- (selectedTypes.length > 0 &&
317
- !service.data.sends?.some((message: any) => selectedTypes.includes(message.collection)))) && (
318
- <div className="text-center py-4 ">
319
- <p className="text-gray-500 text-[10px]">
320
- {selectedTypes.length > 0
321
- ? `Service does not send ${selectedTypes.join(' or ')}`
322
- : 'Service does not send any messages'}
323
- </p>
324
- </div>
325
- )}
326
- </div>
327
- </div>
328
- </div>
329
- )}
330
- </div>
331
- </div>
332
- </a>
333
- );
334
- })}
335
- </div>
336
366
  </div>
337
367
  )}
338
368