@eventcatalog/core 2.14.3 → 2.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. package/README.md +2 -1
  2. package/bin/eventcatalog.js +2 -0
  3. package/default-files-for-collections/ubiquitousLanguages.md +7 -0
  4. package/dist/analytics/analytics.cjs +71 -0
  5. package/dist/analytics/analytics.d.cts +3 -0
  6. package/dist/analytics/analytics.d.ts +3 -0
  7. package/dist/analytics/analytics.js +7 -0
  8. package/dist/analytics/log-build.cjs +155 -0
  9. package/dist/analytics/log-build.d.cts +7 -0
  10. package/dist/analytics/log-build.d.ts +7 -0
  11. package/dist/analytics/log-build.js +9 -0
  12. package/dist/catalog-to-astro-content-directory.cjs +286 -0
  13. package/dist/catalog-to-astro-content-directory.d.cts +3 -0
  14. package/dist/catalog-to-astro-content-directory.d.ts +3 -0
  15. package/dist/catalog-to-astro-content-directory.js +8 -0
  16. package/dist/chunk-55YPRY5U.js +87 -0
  17. package/dist/chunk-5RNDOKYT.js +97 -0
  18. package/dist/chunk-6VJTKPOS.js +30 -0
  19. package/dist/chunk-BT6ILNB3.js +33 -0
  20. package/dist/chunk-DMGFALQN.js +9 -0
  21. package/dist/chunk-E7TXTI7G.js +78 -0
  22. package/{scripts/watcher.js → dist/chunk-NTCYOR4N.js} +29 -52
  23. package/dist/chunk-YEQVKHST.js +56 -0
  24. package/dist/constants.cjs +35 -0
  25. package/dist/constants.d.cts +3 -0
  26. package/dist/constants.d.ts +3 -0
  27. package/dist/constants.js +6 -0
  28. package/dist/eventcatalog-config-file-utils.cjs +116 -0
  29. package/dist/eventcatalog-config-file-utils.d.cts +7 -0
  30. package/dist/eventcatalog-config-file-utils.d.ts +7 -0
  31. package/dist/eventcatalog-config-file-utils.js +14 -0
  32. package/{bin/dist → dist}/eventcatalog.cjs +35 -36
  33. package/{bin/dist → dist}/eventcatalog.config.cjs +1 -1
  34. package/dist/eventcatalog.config.js +0 -0
  35. package/dist/eventcatalog.d.cts +2 -0
  36. package/dist/eventcatalog.d.ts +2 -0
  37. package/dist/eventcatalog.js +116 -0
  38. package/dist/generate.cjs +121 -0
  39. package/dist/generate.d.cts +3 -0
  40. package/dist/generate.d.ts +3 -0
  41. package/dist/generate.js +7 -0
  42. package/dist/map-catalog-to-astro.cjs +131 -0
  43. package/dist/map-catalog-to-astro.d.cts +28 -0
  44. package/dist/map-catalog-to-astro.d.ts +28 -0
  45. package/dist/map-catalog-to-astro.js +6 -0
  46. package/dist/watcher.cjs +231 -0
  47. package/dist/watcher.d.cts +21 -0
  48. package/dist/watcher.d.ts +21 -0
  49. package/dist/watcher.js +8 -0
  50. package/{src → eventcatalog/src}/components/MDX/NodeGraph/Edges/AnimatedMessageEdge.tsx +1 -1
  51. package/{src → eventcatalog/src}/components/MDX/NodeGraph/NodeGraph.tsx +28 -38
  52. package/{src → eventcatalog/src}/components/MDX/SchemaViewer/SchemaViewer.astro +6 -1
  53. package/{src → eventcatalog/src}/components/SideBars/CatalogResourcesSideBar/index.tsx +19 -1
  54. package/{src → eventcatalog/src}/components/SideBars/DomainSideBar.astro +23 -0
  55. package/eventcatalog/src/components/Tables/columns/ServiceTableColumns.tsx +196 -0
  56. package/{src → eventcatalog/src}/content/config.ts +18 -0
  57. package/eventcatalog/src/hooks/eventcatalog-visualizer.ts +89 -0
  58. package/eventcatalog/src/pages/docs/[type]/[id]/language.astro +301 -0
  59. package/{src → eventcatalog/src}/utils/collections/domains.ts +17 -2
  60. package/{src → eventcatalog/src}/utils/collections/icons.ts +3 -0
  61. package/{src → eventcatalog/src}/utils/node-graphs/message-node-graph.ts +2 -27
  62. package/{src → eventcatalog/src}/utils/node-graphs/utils/utils.ts +60 -3
  63. package/package.json +12 -3
  64. package/.all-contributorsrc +0 -436
  65. package/.changeset/config.json +0 -11
  66. package/.github/CODEOWNERS +0 -3
  67. package/.github/ISSUE_TEMPLATE/bug.yml +0 -84
  68. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  69. package/.github/ISSUE_TEMPLATE/feature.yml +0 -48
  70. package/.github/PULL_REQUEST_TEMPLATE.md +0 -14
  71. package/.github/funding.yml +0 -1
  72. package/.github/workflows/lint.yml +0 -22
  73. package/.github/workflows/release.yml +0 -34
  74. package/.github/workflows/test-bin.yml +0 -29
  75. package/.github/workflows/test-e2e.yml +0 -27
  76. package/.github/workflows/verify-build.yml +0 -28
  77. package/.prettierignore +0 -7
  78. package/.prettierrc +0 -18
  79. package/CHANGELOG.md +0 -1296
  80. package/bin/dist/eventcatalog.d.cts +0 -1
  81. package/bin/dist/eventcatalog.d.ts +0 -1
  82. package/bin/dist/eventcatalog.js +0 -531
  83. package/bin/eventcatalog.config.ts +0 -34
  84. package/images/example.png +0 -0
  85. package/images/sponsors/gravitee-logo-black.svg +0 -54
  86. package/images/sponsors/hookdeck.svg +0 -11
  87. package/images/sponsors/oso-logo-green.png +0 -0
  88. package/scripts/analytics/analytics.js +0 -31
  89. package/scripts/analytics/log-build.js +0 -26
  90. package/scripts/build-ci.js +0 -27
  91. package/scripts/catalog-to-astro-content-directory.js +0 -115
  92. package/scripts/ci/test.js +0 -24
  93. package/scripts/constants.ts +0 -3
  94. package/scripts/eventcatalog-config-file-utils.js +0 -89
  95. package/scripts/generate.js +0 -65
  96. package/scripts/map-catalog-to-astro.js +0 -174
  97. package/scripts/start-catalog-locally.js +0 -26
  98. package/src/components/Tables/columns/ServiceTableColumns.tsx +0 -164
  99. /package/{bin/dist → dist}/eventcatalog.config.d.cts +0 -0
  100. /package/{bin/dist → dist}/eventcatalog.config.d.ts +0 -0
  101. /package/{astro.config.mjs → eventcatalog/astro.config.mjs} +0 -0
  102. /package/{global.d.ts → eventcatalog/global.d.ts} +0 -0
  103. /package/{public → eventcatalog/public}/favicon.ico +0 -0
  104. /package/{public → eventcatalog/public}/icons/asyncapi.svg +0 -0
  105. /package/{public → eventcatalog/public}/icons/discord.svg +0 -0
  106. /package/{public → eventcatalog/public}/icons/github-purple.svg +0 -0
  107. /package/{public → eventcatalog/public}/icons/github.svg +0 -0
  108. /package/{public → eventcatalog/public}/icons/ms-teams.svg +0 -0
  109. /package/{public → eventcatalog/public}/icons/openapi.svg +0 -0
  110. /package/{public → eventcatalog/public}/icons/protocols/kafka.svg +0 -0
  111. /package/{public → eventcatalog/public}/icons/x-twitter.svg +0 -0
  112. /package/{public → eventcatalog/public}/icons/youtube.svg +0 -0
  113. /package/{public → eventcatalog/public}/logo.png +0 -0
  114. /package/{public → eventcatalog/public}/openapi.yml +0 -0
  115. /package/{public → eventcatalog/public}/opengraph.png +0 -0
  116. /package/{public → eventcatalog/public}/slack-icon.svg +0 -0
  117. /package/{src → eventcatalog/src}/components/DiscoverInsight.astro +0 -0
  118. /package/{src → eventcatalog/src}/components/DocsNavigation.astro +0 -0
  119. /package/{src → eventcatalog/src}/components/Header.astro +0 -0
  120. /package/{src → eventcatalog/src}/components/Lists/OwnersList.tsx +0 -0
  121. /package/{src → eventcatalog/src}/components/Lists/PillList.tsx +0 -0
  122. /package/{src → eventcatalog/src}/components/Lists/PillListFlat.styles.css +0 -0
  123. /package/{src → eventcatalog/src}/components/Lists/PillListFlat.tsx +0 -0
  124. /package/{src → eventcatalog/src}/components/Lists/ProtocolList.tsx +0 -0
  125. /package/{src → eventcatalog/src}/components/Lists/RepositoryList.astro +0 -0
  126. /package/{src → eventcatalog/src}/components/Lists/SpecificationsList.astro +0 -0
  127. /package/{src → eventcatalog/src}/components/Lists/VersionList.astro +0 -0
  128. /package/{src → eventcatalog/src}/components/MDX/Accordion/Accordion.astro +0 -0
  129. /package/{src → eventcatalog/src}/components/MDX/Accordion/Accordion.tsx +0 -0
  130. /package/{src → eventcatalog/src}/components/MDX/Accordion/AccordionGroup.astro +0 -0
  131. /package/{src → eventcatalog/src}/components/MDX/Admonition.tsx +0 -0
  132. /package/{src → eventcatalog/src}/components/MDX/AsyncAPI/AsyncAPI.astro +0 -0
  133. /package/{src → eventcatalog/src}/components/MDX/ChannelInformation/ChannelInformation.tsx +0 -0
  134. /package/{src → eventcatalog/src}/components/MDX/File.tsx +0 -0
  135. /package/{src → eventcatalog/src}/components/MDX/Flow/Flow.astro +0 -0
  136. /package/{src → eventcatalog/src}/components/MDX/NodeGraph/DownloadButton.tsx +0 -0
  137. /package/{src → eventcatalog/src}/components/MDX/NodeGraph/NodeGraph.astro +0 -0
  138. /package/{src → eventcatalog/src}/components/MDX/NodeGraph/NodeGraphPortal.tsx +0 -0
  139. /package/{src → eventcatalog/src}/components/MDX/NodeGraph/Nodes/Channel.tsx +0 -0
  140. /package/{src → eventcatalog/src}/components/MDX/NodeGraph/Nodes/Command.tsx +0 -0
  141. /package/{src → eventcatalog/src}/components/MDX/NodeGraph/Nodes/Event.tsx +0 -0
  142. /package/{src → eventcatalog/src}/components/MDX/NodeGraph/Nodes/ExternalSystem.tsx +0 -0
  143. /package/{src → eventcatalog/src}/components/MDX/NodeGraph/Nodes/Query.tsx +0 -0
  144. /package/{src → eventcatalog/src}/components/MDX/NodeGraph/Nodes/Service.tsx +0 -0
  145. /package/{src → eventcatalog/src}/components/MDX/NodeGraph/Nodes/Step.tsx +0 -0
  146. /package/{src → eventcatalog/src}/components/MDX/NodeGraph/Nodes/User.tsx +0 -0
  147. /package/{src → eventcatalog/src}/components/MDX/OpenAPI/OpenAPI.astro +0 -0
  148. /package/{src → eventcatalog/src}/components/MDX/Schema.astro +0 -0
  149. /package/{src → eventcatalog/src}/components/MDX/SchemaViewer/SchemaViewer.tsx +0 -0
  150. /package/{src → eventcatalog/src}/components/MDX/SchemaViewer/SchemaViewerPortal.tsx +0 -0
  151. /package/{src → eventcatalog/src}/components/MDX/Steps/Step.astro +0 -0
  152. /package/{src → eventcatalog/src}/components/MDX/Steps/Steps.astro +0 -0
  153. /package/{src → eventcatalog/src}/components/MDX/Tiles/Tile.astro +0 -0
  154. /package/{src → eventcatalog/src}/components/MDX/Tiles/Tiles.astro +0 -0
  155. /package/{src → eventcatalog/src}/components/MDX/components.tsx +0 -0
  156. /package/{src → eventcatalog/src}/components/MDX/page-components.tsx +0 -0
  157. /package/{src → eventcatalog/src}/components/Search.astro +0 -0
  158. /package/{src → eventcatalog/src}/components/Seo.astro +0 -0
  159. /package/{src → eventcatalog/src}/components/SideBars/CatalogResourcesSideBar/styles.css +0 -0
  160. /package/{src → eventcatalog/src}/components/SideBars/ChannelSideBar.astro +0 -0
  161. /package/{src → eventcatalog/src}/components/SideBars/MessageSideBar.astro +0 -0
  162. /package/{src → eventcatalog/src}/components/SideBars/ServiceSideBar.astro +0 -0
  163. /package/{src → eventcatalog/src}/components/Tables/DebouncedInput.tsx +0 -0
  164. /package/{src → eventcatalog/src}/components/Tables/Table.tsx +0 -0
  165. /package/{src → eventcatalog/src}/components/Tables/columns/DomainTableColumns.tsx +0 -0
  166. /package/{src → eventcatalog/src}/components/Tables/columns/FlowTableColumns.tsx +0 -0
  167. /package/{src → eventcatalog/src}/components/Tables/columns/MessageTableColumns.tsx +0 -0
  168. /package/{src → eventcatalog/src}/components/Tables/columns/index.tsx +0 -0
  169. /package/{src → eventcatalog/src}/components/Tables/filters/custom-filters.ts +0 -0
  170. /package/{src → eventcatalog/src}/env.d.ts +0 -0
  171. /package/{src → eventcatalog/src}/icons/protocols/WebSocket.svg +0 -0
  172. /package/{src → eventcatalog/src}/icons/protocols/amqp.svg +0 -0
  173. /package/{src → eventcatalog/src}/icons/protocols/eventbridge.svg +0 -0
  174. /package/{src → eventcatalog/src}/icons/protocols/googlepubsub.svg +0 -0
  175. /package/{src → eventcatalog/src}/icons/protocols/http.svg +0 -0
  176. /package/{src → eventcatalog/src}/icons/protocols/index.ts +0 -0
  177. /package/{src → eventcatalog/src}/icons/protocols/jms.svg +0 -0
  178. /package/{src → eventcatalog/src}/icons/protocols/kafka.svg +0 -0
  179. /package/{src → eventcatalog/src}/icons/protocols/mercure.svg +0 -0
  180. /package/{src → eventcatalog/src}/icons/protocols/mqtt.svg +0 -0
  181. /package/{src → eventcatalog/src}/icons/protocols/nats.svg +0 -0
  182. /package/{src → eventcatalog/src}/icons/protocols/pulsar.svg +0 -0
  183. /package/{src → eventcatalog/src}/icons/protocols/redis.svg +0 -0
  184. /package/{src → eventcatalog/src}/icons/protocols/sns.svg +0 -0
  185. /package/{src → eventcatalog/src}/icons/protocols/solace.svg +0 -0
  186. /package/{src → eventcatalog/src}/icons/protocols/sqs.svg +0 -0
  187. /package/{src → eventcatalog/src}/icons/protocols/ws.svg +0 -0
  188. /package/{src → eventcatalog/src}/layouts/CustomDocsPageLayout.astro +0 -0
  189. /package/{src → eventcatalog/src}/layouts/DiscoverLayout.astro +0 -0
  190. /package/{src → eventcatalog/src}/layouts/Footer.astro +0 -0
  191. /package/{src → eventcatalog/src}/layouts/PlainPage.astro +0 -0
  192. /package/{src → eventcatalog/src}/layouts/VerticalSideBarLayout.astro +0 -0
  193. /package/{src → eventcatalog/src}/layouts/VisualiserLayout.astro +0 -0
  194. /package/{src → eventcatalog/src}/pages/discover/[type]/index.astro +0 -0
  195. /package/{src → eventcatalog/src}/pages/docs/[type]/[id]/[version]/asyncapi/index.astro +0 -0
  196. /package/{src → eventcatalog/src}/pages/docs/[type]/[id]/[version]/changelog/index.astro +0 -0
  197. /package/{src → eventcatalog/src}/pages/docs/[type]/[id]/[version]/index.astro +0 -0
  198. /package/{src → eventcatalog/src}/pages/docs/[type]/[id]/[version]/spec/_styles.css +0 -0
  199. /package/{src → eventcatalog/src}/pages/docs/[type]/[id]/[version]/spec/index.astro +0 -0
  200. /package/{src → eventcatalog/src}/pages/docs/[type]/[id]/index.astro +0 -0
  201. /package/{src → eventcatalog/src}/pages/docs/index.astro +0 -0
  202. /package/{src → eventcatalog/src}/pages/docs/teams/[id]/index.astro +0 -0
  203. /package/{src → eventcatalog/src}/pages/docs/users/[id]/index.astro +0 -0
  204. /package/{src → eventcatalog/src}/pages/index.astro +0 -0
  205. /package/{src → eventcatalog/src}/pages/visualiser/[type]/[id]/[version]/index.astro +0 -0
  206. /package/{src → eventcatalog/src}/pages/visualiser/[type]/[id]/index.astro +0 -0
  207. /package/{src → eventcatalog/src}/remark-plugins/mermaid.ts +0 -0
  208. /package/{src → eventcatalog/src}/types/index.ts +0 -0
  209. /package/{src → eventcatalog/src}/utils/channels.ts +0 -0
  210. /package/{src → eventcatalog/src}/utils/collections/changelogs.ts +0 -0
  211. /package/{src → eventcatalog/src}/utils/collections/file-diffs.ts +0 -0
  212. /package/{src → eventcatalog/src}/utils/collections/flows.ts +0 -0
  213. /package/{src → eventcatalog/src}/utils/collections/services.ts +0 -0
  214. /package/{src → eventcatalog/src}/utils/collections/util.ts +0 -0
  215. /package/{src → eventcatalog/src}/utils/collections/versions.ts +0 -0
  216. /package/{src → eventcatalog/src}/utils/colors.ts +0 -0
  217. /package/{src → eventcatalog/src}/utils/commands.ts +0 -0
  218. /package/{src → eventcatalog/src}/utils/eventcatalog-config/catalog.ts +0 -0
  219. /package/{src → eventcatalog/src}/utils/events.ts +0 -0
  220. /package/{src → eventcatalog/src}/utils/example-remark-plugin.mjs +0 -0
  221. /package/{src → eventcatalog/src}/utils/messages.ts +0 -0
  222. /package/{src → eventcatalog/src}/utils/node-graphs/domains-node-graph.ts +0 -0
  223. /package/{src → eventcatalog/src}/utils/node-graphs/flows-node-graph.ts +0 -0
  224. /package/{src → eventcatalog/src}/utils/node-graphs/services-node-graph.ts +0 -0
  225. /package/{src → eventcatalog/src}/utils/page-loaders/page-data-loader.ts +0 -0
  226. /package/{src → eventcatalog/src}/utils/pages.ts +0 -0
  227. /package/{src → eventcatalog/src}/utils/queries.ts +0 -0
  228. /package/{src → eventcatalog/src}/utils/teams.ts +0 -0
  229. /package/{src → eventcatalog/src}/utils/url-builder.ts +0 -0
  230. /package/{src → eventcatalog/src}/utils/users.ts +0 -0
  231. /package/{tailwind.config.mjs → eventcatalog/tailwind.config.mjs} +0 -0
  232. /package/{tsconfig.json → eventcatalog/tsconfig.json} +0 -0
@@ -3,6 +3,7 @@ import OwnersList from '@components/Lists/OwnersList';
3
3
  import PillListFlat from '@components/Lists/PillListFlat';
4
4
  import RepositoryList from '@components/Lists/RepositoryList.astro';
5
5
  import VersionList from '@components/Lists/VersionList.astro';
6
+ import { getUbiquitousLanguage } from '@utils/collections/domains';
6
7
  import { buildUrl } from '@utils/url-builder';
7
8
  import { getEntry, type CollectionEntry } from 'astro:content';
8
9
  import { ScrollText, Workflow } from 'lucide-react';
@@ -14,6 +15,9 @@ const { domain } = Astro.props;
14
15
 
15
16
  // @ts-ignore
16
17
  const services = (domain.data.services as CollectionEntry<'services'>[]) || [];
18
+ const ubiquitousLanguage = await getUbiquitousLanguage(domain);
19
+ const hasUbiquitousLanguage = ubiquitousLanguage.length > 0;
20
+ const ubiquitousLanguageDictionary = hasUbiquitousLanguage ? ubiquitousLanguage[0].data.dictionary : [];
17
21
 
18
22
  const ownersRaw = domain.data?.owners || [];
19
23
  const owners = await Promise.all(ownersRaw.map((o) => getEntry(o)));
@@ -26,6 +30,13 @@ const serviceList = services.map((p) => ({
26
30
  href: buildUrl(`/docs/${p.collection}/${p.data.id}/${p.data.version}`),
27
31
  }));
28
32
 
33
+ const ubiquitousLanguageList = ubiquitousLanguageDictionary?.map((l) => ({
34
+ label: l.name,
35
+ badge: 'Ubiquitous Language',
36
+ collection: 'ubiquitousLanguages',
37
+ href: buildUrl(`/docs/${domain.collection}/${domain.data.id}/language?id=${l.id}`),
38
+ }));
39
+
29
40
  const ownersList = owners.map((o) => ({
30
41
  label: o.data.name,
31
42
  type: o.collection,
@@ -45,6 +56,17 @@ const ownersList = owners.map((o) => ({
45
56
  icon="ServerIcon"
46
57
  client:load
47
58
  />
59
+ {
60
+ ubiquitousLanguageList && hasUbiquitousLanguage && (
61
+ <PillListFlat
62
+ title={`Ubiquitous Language Dictionary (${ubiquitousLanguageDictionary?.length})`}
63
+ pills={ubiquitousLanguageList}
64
+ color="pink"
65
+ emptyMessage={`This domain does not have any documented ubiquitous language.`}
66
+ client:load
67
+ />
68
+ )
69
+ }
48
70
  {domain.data.versions && <VersionList versions={domain.data.versions} collectionItem={domain} />}
49
71
  {
50
72
  domain.data.repository && (
@@ -57,6 +79,7 @@ const ownersList = owners.map((o) => ({
57
79
  emptyMessage={`This domain does not have any documented owners.`}
58
80
  client:load
59
81
  />
82
+
60
83
  <div class="space-y-2">
61
84
  <a
62
85
  href={buildUrl(`/visualiser/${domain.collection}/${domain.data.id}/${domain.data.version}`)}
@@ -0,0 +1,196 @@
1
+ import { ServerIcon, BoltIcon, ChatBubbleLeftIcon } from '@heroicons/react/24/solid';
2
+ import { createColumnHelper } from '@tanstack/react-table';
3
+ import type { CollectionEntry } from 'astro:content';
4
+ import { useMemo, useState } from 'react';
5
+ import { filterByName, filterCollectionByName } from '../filters/custom-filters';
6
+ import { buildUrl } from '@utils/url-builder';
7
+ import { getColorAndIconForMessageType } from './MessageTableColumns';
8
+
9
+ const columnHelper = createColumnHelper<CollectionEntry<'services'>>();
10
+
11
+ export const columns = () => [
12
+ columnHelper.accessor('data.name', {
13
+ id: 'name',
14
+ header: () => <span>Service</span>,
15
+ cell: (info) => {
16
+ const messageRaw = info.row.original;
17
+ const color = 'pink';
18
+ return (
19
+ <div className="group font-light">
20
+ <a
21
+ href={buildUrl(`/docs/${messageRaw.collection}/${messageRaw.data.id}/${messageRaw.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
+ <ServerIcon className="h-4 w-4 text-white" />
28
+ </span>
29
+ <span className="leading-none px-2 group-hover:underline group-hover:text-primary">
30
+ {messageRaw.data.name} (v{messageRaw.data.version})
31
+ </span>
32
+ </span>
33
+ </div>
34
+ </a>
35
+ </div>
36
+ );
37
+ },
38
+ meta: {
39
+ filterVariant: 'name',
40
+ },
41
+ filterFn: filterByName,
42
+ }),
43
+ // columnHelper.accessor('data.version', {
44
+ // header: () => <span>Version</span>,
45
+ // cell: (info) => {
46
+ // const service = info.row.original;
47
+ // return <div className="text-left">{`v${info.getValue()} ${service.data.latestVersion === service.data.version ? '(latest)': ''}`}</div>
48
+ // },
49
+ // footer: (info) => info.column.id,
50
+ // }),
51
+ columnHelper.accessor('data.summary', {
52
+ id: 'summary',
53
+ header: () => 'Summary',
54
+ cell: (info) => <span className="font-light ">{info.renderValue()}</span>,
55
+ footer: (info) => info.column.id,
56
+ meta: {
57
+ showFilter: false,
58
+ className: 'max-w-md',
59
+ },
60
+ }),
61
+ columnHelper.accessor('data.receives', {
62
+ header: () => <span>Receives</span>,
63
+ meta: {
64
+ filterVariant: 'collection',
65
+ collectionFilterKey: 'receives',
66
+ },
67
+ cell: (info) => {
68
+ const receives = info.getValue() || [];
69
+ const isExpandable = receives?.length > 10;
70
+ const isOpen = isExpandable ? receives?.length < 10 : true;
71
+ const [isExpanded, setIsExpanded] = useState(isOpen);
72
+
73
+ const receiversWithIcons = useMemo(
74
+ () =>
75
+ receives?.map((consumer: any) => {
76
+ const type = consumer.collection.slice(0, -1);
77
+ return {
78
+ ...consumer,
79
+ ...getColorAndIconForMessageType(type),
80
+ };
81
+ }) || [],
82
+ [receives]
83
+ );
84
+
85
+ if (receives?.length === 0 || !receives)
86
+ return <div className="text-sm text-gray-400/80 text-left italic">Service receives no messages.</div>;
87
+
88
+ return (
89
+ <div>
90
+ {isExpandable && (
91
+ <button onClick={() => setIsExpanded(!isExpanded)} className="mb-2 text-sm text-gray-600 hover:text-gray-900">
92
+ {isExpanded ? '▼' : '▶'} {receives.length} message{receives.length !== 1 ? 's' : ''}
93
+ </button>
94
+ )}
95
+ {isExpanded && (
96
+ <ul>
97
+ {receiversWithIcons.map((consumer: any, index: number) => (
98
+ <li key={`${consumer.data.id}-${index}`} className="py-1 group font-light ">
99
+ <a
100
+ href={buildUrl(`/docs/${consumer.collection}/${consumer.data.id}/${consumer.data.version}`)}
101
+ className="group-hover:text-primary flex space-x-1 items-center "
102
+ >
103
+ <div className={`flex items-center border border-gray-300 shadow-sm rounded-md`}>
104
+ <span className="flex items-center">
105
+ <span className={`bg-${consumer.color}-500 h-full rounded-tl rounded-bl p-1`}>
106
+ <consumer.Icon className="h-4 w-4 text-white" />
107
+ </span>
108
+ <span className="leading-none px-2 group-hover:underline ">
109
+ {consumer.data.name} (v{consumer.data.version})
110
+ </span>
111
+ </span>
112
+ </div>
113
+ </a>
114
+ </li>
115
+ ))}
116
+ </ul>
117
+ )}
118
+ </div>
119
+ );
120
+ },
121
+ filterFn: filterCollectionByName('receives'),
122
+ }),
123
+ columnHelper.accessor('data.sends', {
124
+ header: () => <span>Sends</span>,
125
+ meta: {
126
+ filterVariant: 'collection',
127
+ collectionFilterKey: 'sends',
128
+ },
129
+ cell: (info) => {
130
+ const sends = info.getValue() || [];
131
+ const isExpandable = sends?.length > 10;
132
+ const isOpen = isExpandable ? sends?.length < 10 : true;
133
+ const [isExpanded, setIsExpanded] = useState(isOpen);
134
+
135
+ if (sends?.length === 0 || !sends)
136
+ return <div className="text-sm text-gray-400/80 text-left italic">Service sends no messages.</div>;
137
+
138
+ return (
139
+ <div>
140
+ {isExpandable && (
141
+ <button onClick={() => setIsExpanded(!isExpanded)} className="mb-2 text-sm text-gray-600 hover:text-gray-900">
142
+ {isExpanded ? '▼' : '▶'} {sends.length} message{sends.length !== 1 ? 's' : ''}
143
+ </button>
144
+ )}
145
+ {isExpanded && (
146
+ <ul>
147
+ {sends.map((consumer: any, index: number) => {
148
+ const type = consumer.collection.slice(0, -1);
149
+ const color = type === 'event' ? 'orange' : 'blue';
150
+ const Icon = type === 'event' ? BoltIcon : ChatBubbleLeftIcon;
151
+ return (
152
+ <li key={`${consumer.data.id}-${index}`} className="py-1 group font-light">
153
+ <a
154
+ href={buildUrl(`/docs/${consumer.collection}/${consumer.data.id}/${consumer.data.version}`)}
155
+ className="group-hover:text-primary flex space-x-1 items-center "
156
+ >
157
+ <div className={`flex items-center border border-gray-300 shadow-sm rounded-md`}>
158
+ <span className="flex items-center">
159
+ <span className={`bg-${color}-500 h-full rounded-tl rounded-bl p-1`}>
160
+ <Icon className="h-4 w-4 text-white" />
161
+ </span>
162
+ <span className="leading-none px-2 group-hover:underline ">
163
+ {consumer.data.name} (v{consumer.data.version})
164
+ </span>
165
+ </span>
166
+ </div>
167
+ </a>
168
+ </li>
169
+ );
170
+ })}
171
+ </ul>
172
+ )}
173
+ </div>
174
+ );
175
+ },
176
+ filterFn: filterCollectionByName('sends'),
177
+ }),
178
+ columnHelper.accessor('data.name', {
179
+ header: () => <span />,
180
+ cell: (info) => {
181
+ const domain = info.row.original;
182
+ return (
183
+ <a
184
+ className="hover:text-primary hover:underline px-4 font-light"
185
+ href={buildUrl(`/visualiser/${domain.collection}/${domain.data.id}/${domain.data.version}`)}
186
+ >
187
+ Visualiser &rarr;
188
+ </a>
189
+ );
190
+ },
191
+ id: 'actions',
192
+ meta: {
193
+ showFilter: false,
194
+ },
195
+ }),
196
+ ];
@@ -221,6 +221,23 @@ const domains = defineCollection({
221
221
  .merge(baseSchema),
222
222
  });
223
223
 
224
+ const ubiquitousLanguages = defineCollection({
225
+ type: 'content',
226
+ schema: z.object({
227
+ dictionary: z
228
+ .array(
229
+ z.object({
230
+ id: z.string(),
231
+ name: z.string(),
232
+ summary: z.string().optional(),
233
+ description: z.string().optional(),
234
+ icon: z.string().optional(),
235
+ })
236
+ )
237
+ .optional(),
238
+ }),
239
+ });
240
+
224
241
  const users = defineCollection({
225
242
  type: 'content',
226
243
  schema: z.object({
@@ -270,4 +287,5 @@ export const collections = {
270
287
  flows,
271
288
  pages,
272
289
  changelogs,
290
+ ubiquitousLanguages,
273
291
  };
@@ -0,0 +1,89 @@
1
+ import { useCallback, useMemo, useState, useEffect } from 'react';
2
+ import { type Edge, type Node } from 'reactflow';
3
+ import {
4
+ createEdge,
5
+ generatedIdForEdge,
6
+ generateIdForNode,
7
+ getEdgeLabelForMessageAsSource,
8
+ getEdgeLabelForServiceAsTarget,
9
+ getNodesAndEdgesFromDagre,
10
+ } from '@utils/node-graphs/utils/utils';
11
+
12
+ interface EventCatalogVisualizerProps {
13
+ nodes: Node[];
14
+ edges: Edge[];
15
+ setNodes: (nodes: Node[]) => void;
16
+ setEdges: (edges: Edge[]) => void;
17
+ }
18
+
19
+ export const useEventCatalogVisualiser = ({ nodes, edges, setNodes, setEdges }: EventCatalogVisualizerProps) => {
20
+ const [hideChannels, setHideChannels] = useState(false);
21
+ const [initialNodes] = useState(nodes);
22
+ const [initialEdges] = useState(edges);
23
+
24
+ // Initialize hideChannels from localStorage
25
+ useEffect(() => {
26
+ const storedHideChannels = localStorage.getItem('EventCatalog:hideChannels');
27
+ if (storedHideChannels !== null) {
28
+ setHideChannels(storedHideChannels === 'true');
29
+ }
30
+ }, []);
31
+
32
+ const toggleChannelsVisibility = useCallback(() => {
33
+ setHideChannels((prev) => {
34
+ const newValue = !prev;
35
+ localStorage.setItem('EventCatalog:hideChannels', JSON.stringify(newValue));
36
+ return newValue;
37
+ });
38
+ }, []);
39
+
40
+ const channels = useMemo(() => nodes.filter((node) => node.type === 'channels'), [nodes]);
41
+ const updatedNodes = useMemo(() => nodes.filter((node) => node.type !== 'channels'), [nodes]);
42
+
43
+ const updatedEdges = useMemo(() => {
44
+ return edges.reduce<Edge[]>((acc, edge) => {
45
+ const { source, target, data } = edge;
46
+ const targetIsChannel = channels.some((channel) => channel.id === target);
47
+ const sourceIsChannel = channels.some((channel) => channel.id === source);
48
+
49
+ if (!sourceIsChannel && !targetIsChannel) {
50
+ return [...acc, edge];
51
+ }
52
+
53
+ if (sourceIsChannel) {
54
+ const edgeLabel =
55
+ data.target.collection === 'services'
56
+ ? getEdgeLabelForMessageAsSource(data.source)
57
+ : getEdgeLabelForServiceAsTarget(data.target);
58
+
59
+ return [
60
+ ...acc,
61
+ createEdge({
62
+ id: generatedIdForEdge(data.source, data.target),
63
+ source: generateIdForNode(data.source),
64
+ target: generateIdForNode(data.target),
65
+ label: edgeLabel,
66
+ }),
67
+ ];
68
+ }
69
+
70
+ return [...acc, edge];
71
+ }, []);
72
+ }, [edges, channels]);
73
+
74
+ useEffect(() => {
75
+ if (hideChannels) {
76
+ const { nodes: newNodes, edges: newEdges } = getNodesAndEdgesFromDagre({ nodes: updatedNodes, edges: updatedEdges });
77
+ setNodes(newNodes);
78
+ setEdges(newEdges);
79
+ } else {
80
+ setNodes(initialNodes);
81
+ setEdges(initialEdges);
82
+ }
83
+ }, [hideChannels]);
84
+
85
+ return {
86
+ hideChannels,
87
+ toggleChannelsVisibility,
88
+ };
89
+ };
@@ -0,0 +1,301 @@
1
+ ---
2
+ import Footer from '@layouts/Footer.astro';
3
+ import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
4
+ import { getDomains, type Domain, getUbiquitousLanguage } from '@utils/collections/domains';
5
+ import type { CollectionEntry } from 'astro:content';
6
+ import { ViewTransitions } from 'astro:transitions';
7
+ import * as LucideIcons from 'lucide-react';
8
+
9
+ export async function getStaticPaths() {
10
+ const domains = await getDomains();
11
+
12
+ const buildPages = (collection: CollectionEntry<'domains'>[]) => {
13
+ return collection.map((item) => ({
14
+ params: {
15
+ type: item.collection,
16
+ id: item.data.id,
17
+ },
18
+ props: {
19
+ type: item.collection,
20
+ ...item,
21
+ },
22
+ }));
23
+ };
24
+
25
+ return [...buildPages(domains)];
26
+ }
27
+
28
+ const props = Astro.props;
29
+ const pageTitle = `${props.collection} | ${props.data.name}`.replace(/^\w/, (c) => c.toUpperCase());
30
+ const ubiquitousLanguages = await getUbiquitousLanguage(props);
31
+
32
+ const ubiquitousLanguage = ubiquitousLanguages[0];
33
+ ---
34
+
35
+ <VerticalSideBarLayout title={pageTitle} description={props.data.summary}>
36
+ <main class="flex sm:px-8 docs-layout h-full">
37
+ <div class="flex docs-layout w-full">
38
+ <div class="w-full lg:mr-2 pr-8 overflow-y-auto py-8 min-h-[50em]">
39
+ <nav class="flex mb-4" aria-label="Breadcrumb">
40
+ <ol class="inline-flex items-center space-x-1 md:space-x-3">
41
+ <li class="inline-flex items-center">
42
+ <a
43
+ href={`/docs/${props.type}/${props.data.id}/${props.data.latestVersion}`}
44
+ class="inline-flex items-center text-sm font-medium text-gray-500 hover:text-primary"
45
+ >
46
+ <svg
47
+ class="w-3 h-3 mr-2.5"
48
+ aria-hidden="true"
49
+ xmlns="http://www.w3.org/2000/svg"
50
+ fill="none"
51
+ viewBox="0 0 24 24"
52
+ stroke-width="2"
53
+ stroke="currentColor"
54
+ >
55
+ <path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18"></path>
56
+ </svg>
57
+ Back to Documentation
58
+ </a>
59
+ </li>
60
+ </ol>
61
+ </nav>
62
+
63
+ <div class="border-b border-gray-200 flex justify-between items-start md:pb-2">
64
+ <div>
65
+ <h2 id="doc-page-header" class="text-2xl md:text-4xl font-bold text-black">Domain Language Explorer</h2>
66
+ <h2 class="text-2xl pt-2 text-gray-500 font-light">{props.data.name} domain</h2>
67
+ </div>
68
+ </div>
69
+
70
+ {
71
+ !ubiquitousLanguage && (
72
+ <div class="bg-yellow-50 border-l-4 border-yellow-400 p-4 my-4">
73
+ <p class="text-yellow-700">
74
+ This domain does not have any defined ubiquitous language terms yet. Consider adding some terms to help establish
75
+ a common vocabulary for your domain.
76
+ </p>
77
+ </div>
78
+ )
79
+ }
80
+
81
+ <div class="py-4 w-full min-h-[calc(100vh-10em)]">
82
+ {
83
+ ubiquitousLanguage && (
84
+ <>
85
+ <div class="mb-6">
86
+ <input
87
+ type="text"
88
+ id="searchInput"
89
+ placeholder="Search terms..."
90
+ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
91
+ />
92
+ </div>
93
+
94
+ {!ubiquitousLanguage ? (
95
+ <div class="text-center py-12 bg-gray-50 rounded-lg">
96
+ <h3 class="text-lg font-medium text-gray-900">No domain language terms</h3>
97
+ <p class="mt-2 text-sm text-gray-500">There are no language terms defined for this domain yet.</p>
98
+ </div>
99
+ ) : (
100
+ <div id="termsGrid" class="grid grid-cols-1 md:grid-cols-3 gap-4">
101
+ {ubiquitousLanguage?.data?.dictionary?.map((term) => (
102
+ <div class="term-card block bg-white border border-gray-200 rounded-lg p-6 transition-all duration-300 ease-in-out hover:shadow-md hover:border-primary focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-primary focus:ring-white min-h-[12em] cursor-pointer">
103
+ <div class="flex flex-col h-full space-y-8">
104
+ {term.icon && (
105
+ <>
106
+ {(() => {
107
+ const Icon = LucideIcons[term.icon as keyof typeof LucideIcons];
108
+ //@ts-ignore
109
+ return Icon ? <Icon className="w-6 h-6 text-primary" /> : null;
110
+ })()}
111
+ </>
112
+ )}
113
+ <div>
114
+ <h3 class="text-gray-800 text-lg font-semibold transition-colors duration-300 ease-in-out group-hover:text-gray-300">
115
+ {term.name}
116
+ </h3>
117
+ <div class="term-content">
118
+ <p class="summary-text text-gray-600 transition-colors duration-300 ease-in-out group-hover:text-gray-200 m-0 font-light text-sm mb-4">
119
+ {term.summary}
120
+ </p>
121
+ {term.description && (
122
+ <>
123
+ <p class="description-text hidden text-gray-600 transition-colors duration-300 ease-in-out group-hover:text-gray-200 m-0 font-light text-sm whitespace-pre-line">
124
+ {term.description}
125
+ </p>
126
+ <span class="show-more-text text-sm text-primary font-medium">Show more</span>
127
+ </>
128
+ )}
129
+ </div>
130
+ </div>
131
+ </div>
132
+ </div>
133
+ ))}
134
+ </div>
135
+ )}
136
+
137
+ <div id="noSearchResults" class="hidden text-center py-12 bg-gray-50 rounded-lg">
138
+ <h3 class="text-lg font-medium text-gray-900">No matching terms</h3>
139
+ <p class="mt-2 text-sm text-gray-500">Try adjusting your search terms.</p>
140
+ </div>
141
+ </>
142
+ )
143
+ }
144
+ </div>
145
+
146
+ <Footer />
147
+ </div>
148
+ </div>
149
+ <ViewTransitions />
150
+ </main>
151
+
152
+ <script>
153
+ function initializeSearch() {
154
+ const searchInput = document.getElementById('searchInput');
155
+ const termCards = document.querySelectorAll('.term-card');
156
+ const noSearchResults = document.getElementById('noSearchResults');
157
+
158
+ searchInput?.addEventListener('input', (e) => {
159
+ const searchTerm = (e.target as HTMLInputElement).value.toLowerCase();
160
+ let visibleCount = 0;
161
+
162
+ termCards.forEach((card) => {
163
+ const title = card.querySelector('h3')?.textContent?.toLowerCase() || '';
164
+ const description = card.querySelector('p')?.textContent?.toLowerCase() || '';
165
+ const matches = title.includes(searchTerm) || description.includes(searchTerm);
166
+
167
+ card.classList.toggle('hidden', !matches);
168
+ if (matches) visibleCount++;
169
+ });
170
+
171
+ // Show/hide no results message
172
+ if (noSearchResults) {
173
+ noSearchResults.classList.toggle('hidden', visibleCount > 0);
174
+ }
175
+ });
176
+ }
177
+
178
+ function initializeShowMore() {
179
+ const cards = document.querySelectorAll('.term-card');
180
+
181
+ cards.forEach((card) => {
182
+ const newCard = card.cloneNode(true);
183
+ if (card.parentNode) {
184
+ card.parentNode.replaceChild(newCard, card);
185
+ // Initially show summary
186
+ const summary = (newCard as Element).querySelector('.summary-text');
187
+ summary?.classList.add('visible');
188
+ }
189
+ newCard.addEventListener('click', () => {
190
+ const description = (newCard as Element).querySelector('.description-text');
191
+ const summary = (newCard as Element).querySelector('.summary-text');
192
+ const showMoreText = (newCard as Element).querySelector('.show-more-text');
193
+
194
+ if (description && summary && showMoreText) {
195
+ (newCard as Element).classList.toggle('expanded');
196
+ description.classList.toggle('visible');
197
+ summary.classList.toggle('visible');
198
+ showMoreText.textContent = description.classList.contains('visible') ? 'Show less' : 'Show more';
199
+ }
200
+ });
201
+ });
202
+ }
203
+
204
+ function highlightMatchingTerm() {
205
+ const urlParams = new URLSearchParams(window.location.search);
206
+ const termId = urlParams.get('id');
207
+
208
+ if (termId) {
209
+ const cards = document.querySelectorAll('.term-card');
210
+ cards.forEach((card) => {
211
+ const termName = card.querySelector('h3')?.textContent?.trim();
212
+ if (termName?.toLowerCase() === termId.toLowerCase()) {
213
+ // Add highlight class
214
+ card.classList.add('highlighted');
215
+ (card as HTMLElement).click();
216
+
217
+ setTimeout(() => {
218
+ // Scroll into view
219
+ card.scrollIntoView({ behavior: 'smooth', block: 'center' });
220
+ }, 300);
221
+ }
222
+ });
223
+ }
224
+ }
225
+
226
+ document.addEventListener('astro:page-load', () => {
227
+ initializeShowMore();
228
+ initializeSearch();
229
+ highlightMatchingTerm();
230
+ });
231
+
232
+ initializeShowMore();
233
+ initializeSearch();
234
+ highlightMatchingTerm();
235
+ </script>
236
+
237
+ <style is:global>
238
+ .term-card {
239
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
240
+ min-height: 12em;
241
+ }
242
+
243
+ .term-card.expanded {
244
+ min-height: 24em;
245
+ background-color: rgb(249 250 251);
246
+ z-index: 10;
247
+ box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1);
248
+ }
249
+
250
+ .summary-text,
251
+ .description-text {
252
+ transition:
253
+ opacity 0.3s ease-in-out,
254
+ max-height 0.3s ease-in-out;
255
+ opacity: 0;
256
+ max-height: 0;
257
+ overflow: hidden;
258
+ display: none;
259
+ }
260
+
261
+ .summary-text.visible,
262
+ .description-text.visible {
263
+ opacity: 1;
264
+ max-height: 500px;
265
+ margin-bottom: 1rem;
266
+ display: block;
267
+ }
268
+
269
+ .description-text {
270
+ white-space: pre-line;
271
+ line-height: 1.5;
272
+ }
273
+
274
+ .show-more-text {
275
+ display: block;
276
+ margin-top: 0.5rem;
277
+ }
278
+
279
+ .term-card.expanded .show-more-text {
280
+ display: none;
281
+ }
282
+
283
+ .term-card.highlighted {
284
+ border-color: var(--color-primary);
285
+ box-shadow: 0 0 0 2px var(--color-primary);
286
+ animation: pulse 1s;
287
+ }
288
+
289
+ @keyframes pulse {
290
+ 0%,
291
+ 100% {
292
+ transform: scale(1);
293
+ box-shadow: 0 0 0 2px var(--color-primary);
294
+ }
295
+ 50% {
296
+ transform: scale(1.01);
297
+ box-shadow: 0 0 0 4px var(--color-primary);
298
+ }
299
+ }
300
+ </style>
301
+ </VerticalSideBarLayout>