@eventcatalog/core 2.10.0 → 2.11.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 (42) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +10 -2
  3. package/images/sponsors/gravitee-logo-black.svg +54 -0
  4. package/package.json +7 -3
  5. package/public/icons/discord.svg +1 -0
  6. package/public/icons/github-purple.svg +1 -0
  7. package/scripts/eventcatalog-config-file-utils.js +3 -14
  8. package/src/components/DocsNavigation.astro +12 -12
  9. package/src/components/Header.astro +18 -18
  10. package/src/components/Lists/OwnersList.tsx +21 -58
  11. package/src/components/Lists/PillList.tsx +20 -16
  12. package/src/components/Lists/PillListFlat.styles.css +8 -0
  13. package/src/components/Lists/PillListFlat.tsx +69 -0
  14. package/src/components/Lists/SpecificationsList.astro +4 -4
  15. package/src/components/Lists/VersionList.astro +33 -13
  16. package/src/components/Search.astro +5 -2
  17. package/src/components/SideBars/CatalogResourcesSideBar/index.tsx +120 -0
  18. package/src/components/SideBars/CatalogResourcesSideBar/styles.css +8 -0
  19. package/src/components/SideBars/DomainSideBar.astro +15 -8
  20. package/src/components/SideBars/MessageSideBar.astro +51 -43
  21. package/src/components/SideBars/ServiceSideBar.astro +23 -31
  22. package/src/components/Tables/Table.tsx +2 -2
  23. package/src/components/Tables/columns/MessageTableColumns.tsx +4 -4
  24. package/src/components/Tables/columns/ServiceTableColumns.tsx +4 -4
  25. package/src/layouts/DiscoverLayout.astro +7 -7
  26. package/src/layouts/Footer.astro +1 -1
  27. package/src/layouts/VerticalSideBarLayout.astro +312 -0
  28. package/src/layouts/VisualiserLayout.astro +6 -10
  29. package/src/pages/docs/[type]/[id]/[version]/asyncapi/index.astro +3 -2
  30. package/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +40 -5
  31. package/src/pages/docs/[type]/[id]/[version]/index.astro +149 -144
  32. package/src/pages/docs/[type]/[id]/[version]/spec/index.astro +13 -3
  33. package/src/pages/docs/[type]/[id]/[version]/spec/styles.css +3 -0
  34. package/src/pages/docs/index.astro +4 -4
  35. package/src/pages/docs/teams/[id]/index.astro +13 -10
  36. package/src/pages/docs/users/[id]/index.astro +115 -91
  37. package/src/pages/index.astro +83 -63
  38. package/src/pages/visualiser/[type]/[id]/[version]/index.astro +3 -1
  39. package/src/utils/collections/icons.ts +33 -0
  40. package/tailwind.config.mjs +2 -1
  41. package/src/components/Lists/BasicList.tsx +0 -59
  42. package/src/layouts/DocsLayout.astro +0 -62
@@ -20,9 +20,9 @@ import PageFindSearch from 'astro-pagefind/components/Search';
20
20
  </div>
21
21
  </div>
22
22
 
23
- <div id="search-dialog" class="hidden relative z-50" role="dialog" aria-modal="true">
23
+ <div id="search-dialog" class="hidden relative z-[100]" role="dialog" aria-modal="true">
24
24
  <div class="fixed inset-0 bg-gray-500 bg-opacity-25 transition-opacity search-background backdrop-blur-sm bg-black/10"></div>
25
- <div id="search-background" class="fixed inset-0 z-10 w-screen overflow-y-auto p-4 sm:p-6 md:p-20">
25
+ <div id="search-background" class="fixed inset-0 z-40 w-screen overflow-y-auto p-4 sm:p-6 md:p-20">
26
26
  <div
27
27
  id="command-pal"
28
28
  class="mx-auto max-w-xl divide-y divide-gray-100 overflow-hidden rounded-xl bg-white shadow-2xl ring-1 ring-black ring-opacity-5 transition-all"
@@ -49,6 +49,7 @@ import PageFindSearch from 'astro-pagefind/components/Search';
49
49
  const dummyInput = document.getElementById('search-dummy-input');
50
50
  const dialog = document.getElementById('search-dialog');
51
51
  const header = document.getElementById('eventcatalog-header');
52
+ const verticalNav = document.getElementById('eventcatalog-vertical-nav');
52
53
 
53
54
  // Listen for the short cut keys
54
55
  window.addEventListener('keydown', (event) => {
@@ -75,6 +76,7 @@ import PageFindSearch from 'astro-pagefind/components/Search';
75
76
  input && input.focus();
76
77
  }, 10);
77
78
  if (header) header.classList.remove('backdrop-blur-sm');
79
+ if (verticalNav) verticalNav.style.zIndex = '-100';
78
80
  // @ts-ignore
79
81
  dialog.style.display = 'block';
80
82
  });
@@ -85,6 +87,7 @@ import PageFindSearch from 'astro-pagefind/components/Search';
85
87
  // @ts-ignore
86
88
  if (e.target.id === 'search-background') {
87
89
  if (header) header.classList.add('backdrop-blur-sm');
90
+ if (verticalNav) verticalNav.style.zIndex = '10';
88
91
  dialog.style.display = 'none';
89
92
  }
90
93
  });
@@ -0,0 +1,120 @@
1
+ import React, { useState, useEffect, useMemo } from 'react';
2
+ import debounce from 'lodash.debounce';
3
+ import {
4
+ ChevronDownIcon,
5
+ ChevronUpIcon,
6
+ ServerIcon,
7
+ RectangleGroupIcon,
8
+ BoltIcon,
9
+ ChatBubbleLeftIcon,
10
+ MagnifyingGlassIcon,
11
+ QueueListIcon,
12
+ UserGroupIcon,
13
+ UserIcon,
14
+ } from '@heroicons/react/24/outline';
15
+ import './styles.css';
16
+ import { getIconForCollection as getIconForCollectionOriginal } from '@utils/collections/icons';
17
+
18
+ const CatalogResourcesSideBar = ({ resources, currentPath }: any) => {
19
+ const [data, setData] = useState(resources);
20
+ const [searchQuery, setSearchQuery] = useState('');
21
+ const [collapsedGroups, setCollapsedGroups] = useState<{ [key: string]: boolean }>({});
22
+
23
+ const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
24
+ setSearchQuery(e.target.value);
25
+ };
26
+
27
+ const debouncedHandleSearch = useMemo(() => debounce(handleSearch, 300), []);
28
+
29
+ useEffect(() => {
30
+ return () => {
31
+ debouncedHandleSearch.cancel();
32
+ };
33
+ }, [debouncedHandleSearch]);
34
+
35
+ const toggleGroupCollapse = (group: string) => {
36
+ setCollapsedGroups((prev) => ({
37
+ ...prev,
38
+ [group]: !prev[group],
39
+ }));
40
+ };
41
+
42
+ const filteredData = useMemo(() => {
43
+ if (!searchQuery) return data;
44
+
45
+ const lowercasedQuery = searchQuery.toLowerCase();
46
+ const filterCollection = (collection: any[]) =>
47
+ collection.filter((item) => item.label.toLowerCase().includes(lowercasedQuery));
48
+
49
+ return Object.keys(data).reduce((acc, key) => {
50
+ const filteredCollection = filterCollection(data[key]);
51
+ if (filteredCollection.length > 0) {
52
+ acc[key] = filteredCollection;
53
+ }
54
+ return acc;
55
+ }, {} as any);
56
+ }, [searchQuery, data]);
57
+
58
+ const getIconForCollection = useMemo(() => getIconForCollectionOriginal, []);
59
+
60
+ return (
61
+ <nav className="space-y-6 text-black ">
62
+ <div className="space-y-2">
63
+ <div className="mb-4 px-1">
64
+ <input
65
+ type="text"
66
+ placeholder="Filter catalog..."
67
+ 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"
68
+ onChange={debouncedHandleSearch}
69
+ />
70
+ </div>
71
+
72
+ {Object.keys(filteredData).length === 0 ? (
73
+ <div className="px-2 text-gray-400 dark:text-gray-200 text-sm">No results found</div>
74
+ ) : (
75
+ Object.keys(filteredData).map((key) => {
76
+ const collection = filteredData[key];
77
+ if (collection[0] && collection[0].visible === false) return null;
78
+ const isCollapsed = collapsedGroups[key];
79
+ return (
80
+ <ul className="w-full space-y-1.5 pb-2 pl-1 text-black" key={key}>
81
+ <li
82
+ className="font capitalize cursor-pointer flex items-center ml-1 text-[14px]"
83
+ onClick={() => toggleGroupCollapse(key)}
84
+ >
85
+ <span className="">{`${key} (${collection.length})`}</span>
86
+ <span className="ml-2 block">
87
+ {isCollapsed ? <ChevronDownIcon className="w-3 h-3" /> : <ChevronUpIcon className="w-3 h-3" />}
88
+ </span>
89
+ </li>
90
+ {!isCollapsed &&
91
+ collection.map((item: any) => {
92
+ const Icon = getIconForCollection(item.collection);
93
+ return (
94
+ <li
95
+ 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 ${currentPath.includes(item.href) ? ' bg-gradient-to-l from-purple-500 to-purple-700 font-normal text-white ' : 'font-thin'}`}
96
+ id={item.href}
97
+ key={item.href}
98
+ >
99
+ <a className={`flex px-1 justify-start items-center w-full rounded-md `} href={`${item.href}`}>
100
+ <Icon className="w-3 mr-2" />
101
+ <span className="block truncate !whitespace-normal">{item.label}</span>
102
+ {/* {item.label.length > 2 && (
103
+ <span className="tooltip rounded relative shadow-lg p-1 font-normal text-xs bg-white text-black ml-[30px] mt-12">
104
+ {item.label}
105
+ </span>
106
+ )} */}
107
+ </a>
108
+ </li>
109
+ );
110
+ })}
111
+ </ul>
112
+ );
113
+ })
114
+ )}
115
+ </div>
116
+ </nav>
117
+ );
118
+ };
119
+
120
+ export default CatalogResourcesSideBar;
@@ -0,0 +1,8 @@
1
+ .tooltip {
2
+ visibility: hidden;
3
+ position: absolute;
4
+ }
5
+ .has-tooltip:hover .tooltip {
6
+ visibility: visible;
7
+ z-index: 100;
8
+ }
@@ -1,9 +1,10 @@
1
1
  ---
2
2
  import OwnersList from '@components/Lists/OwnersList';
3
- import PillList from '@components/Lists/PillList';
3
+ import PillListFlat from '@components/Lists/PillListFlat';
4
4
  import VersionList from '@components/Lists/VersionList.astro';
5
5
  import { buildUrl } from '@utils/url-builder';
6
6
  import { getEntry, type CollectionEntry } from 'astro:content';
7
+ import { ScrollText, Workflow } from 'lucide-react';
7
8
  interface Props {
8
9
  domain: CollectionEntry<'domains'>;
9
10
  }
@@ -20,6 +21,7 @@ const serviceList = services.map((p) => ({
20
21
  label: p.data.name,
21
22
  badge: p.collection,
22
23
  tag: `v${p.data.version}`,
24
+ collection: p.collection,
23
25
  href: buildUrl(`/docs/${p.collection}/${p.data.id}/${p.data.version}`),
24
26
  }));
25
27
 
@@ -32,33 +34,38 @@ const ownersList = owners.map((o) => ({
32
34
  }));
33
35
  ---
34
36
 
35
- <aside class="sticky top-28 left-0 space-y-8 h-full overflow-y-auto">
37
+ <aside class="sticky top-28 left-0 space-y-8 h-full overflow-y-auto py-4">
36
38
  <div>
37
- <PillList
39
+ <PillListFlat
38
40
  title={`Services (${services.length})`}
39
41
  pills={serviceList}
40
42
  emptyMessage={`This domain does not contain any services.`}
41
43
  color="pink"
44
+ icon="ServerIcon"
42
45
  client:load
43
46
  />
47
+ {domain.data.versions && <VersionList versions={domain.data.versions} collectionItem={domain} />}
44
48
  <OwnersList
45
49
  title={`Domain owners (${ownersList.length})`}
46
50
  owners={ownersList}
47
51
  emptyMessage={`This domain does not have any documented owners.`}
48
52
  client:load
49
53
  />
50
- {domain.data.versions && <VersionList versions={domain.data.versions} collectionItem={domain} />}
51
54
  <div class="space-y-2">
52
55
  <a
53
56
  href={buildUrl(`/visualiser/${domain.collection}/${domain.data.id}/${domain.data.version}`)}
54
- class="block text-center rounded-md w-full bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-100/60 hover:text-primary"
55
- >View in Visualiser</a
57
+ class="flex items-center justify-center space-x-2 text-center rounded-md w-full bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-100/60 hover:text-primary"
56
58
  >
59
+ <Workflow strokeWidth={2} size={16} />
60
+ <span class="block">View in visualiser</span>
61
+ </a>
57
62
  <a
58
63
  href={buildUrl(`/docs/${domain.collection}/${domain.data.id}/${domain.data.version}/changelog`)}
59
- class="block text-center rounded-md w-full bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-100/60 hover:text-primary"
60
- >Changelog</a
64
+ class="flex items-center space-x-2 justify-center text-center rounded-md w-full bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-100/60 hover:text-primary"
61
65
  >
66
+ <ScrollText strokeWidth={2} size={16} />
67
+ <span class="block">Read changelog</span>
68
+ </a>
62
69
  </div>
63
70
  </div>
64
71
  </aside>
@@ -1,11 +1,12 @@
1
1
  ---
2
2
  import { getEntry, type CollectionEntry } from 'astro:content';
3
- import PillList from '@components/Lists/PillList';
3
+ import PillListFlat from '@components/Lists/PillListFlat';
4
4
  import OwnersList from '@components/Lists/OwnersList';
5
5
  import type { CollectionMessageTypes } from '@types';
6
6
  import * as path from 'path';
7
7
  import VersionList from '@components/Lists/VersionList.astro';
8
8
  import { buildUrl } from '@utils/url-builder';
9
+ import { FileDownIcon, ScrollText, Workflow } from 'lucide-react';
9
10
  interface Props {
10
11
  message: CollectionEntry<CollectionMessageTypes>;
11
12
  }
@@ -19,14 +20,16 @@ const ownersRaw = message.data?.owners || [];
19
20
  const owners = await Promise.all(ownersRaw.map((o) => getEntry(o)));
20
21
 
21
22
  const producerList = producers.map((p) => ({
22
- label: `${p.data.name} (service)`,
23
+ label: `${p.data.name}`,
23
24
  tag: `v${p.data.version}`,
25
+ collection: p.collection,
24
26
  href: buildUrl(`/docs/services/${p.data.id}/${p.data.version}`),
25
27
  }));
26
28
 
27
29
  const consumerList = consumers.map((p) => ({
28
- label: `${p.data.name} (service)`,
30
+ label: `${p.data.name}`,
29
31
  tag: `v${p.data.version}`,
32
+ collection: p.collection,
30
33
  href: buildUrl(`/docs/services/${p.data.id}/${p.data.version}`),
31
34
  }));
32
35
 
@@ -77,22 +80,41 @@ const schemaFilePath = message?.data?.schemaPath;
77
80
  const schemaURL = path.join(publicPath, schemaFilePath || '');
78
81
  ---
79
82
 
80
- <aside class="sticky top-28 left-0 space-y-8 h-full overflow-y-auto pb-20">
83
+ <aside class="sticky top-28 left-0 space-y-8 h-full overflow-y-auto py-4">
81
84
  <div class="">
82
- <PillList
83
- color="pink"
84
- title={`${type} Producers (${producerList.length})`}
85
- pills={producerList}
86
- emptyMessage={getProducerEmptyMessage(type)}
87
- client:load
88
- />
89
- <PillList
90
- color="pink"
91
- title={`${type} Consumers (${consumerList.length})`}
92
- pills={consumerList}
93
- emptyMessage={getConsumerEmptyMessage(type)}
94
- client:load
95
- />
85
+ {
86
+ producerList.length > 0 && (
87
+ <PillListFlat
88
+ color="pink"
89
+ title={`${type} Producers (${producerList.length})`}
90
+ pills={producerList}
91
+ emptyMessage={getProducerEmptyMessage(type)}
92
+ client:load
93
+ />
94
+ )
95
+ }
96
+ {
97
+ consumerList.length > 0 && (
98
+ <PillListFlat
99
+ color="pink"
100
+ title={`${type} Consumers (${consumerList.length})`}
101
+ pills={consumerList}
102
+ emptyMessage={getConsumerEmptyMessage(type)}
103
+ client:load
104
+ />
105
+ )
106
+ }
107
+
108
+ {
109
+ message.data.versions && (
110
+ <VersionList
111
+ title={`${type} versions (${message.data.versions?.length})`}
112
+ versions={message.data.versions}
113
+ collectionItem={message}
114
+ />
115
+ )
116
+ }
117
+
96
118
  <OwnersList
97
119
  title={`${type} owners (${ownersList.length})`}
98
120
  owners={ownersList}
@@ -100,48 +122,34 @@ const schemaURL = path.join(publicPath, schemaFilePath || '');
100
122
  client:load
101
123
  />
102
124
 
103
- {message.data.versions && <VersionList versions={message.data.versions} collectionItem={message} />}
104
-
105
125
  <div class="space-y-2">
106
126
  {
107
127
  message?.data?.schemaPath && (
108
128
  <a
109
129
  href={buildUrl(schemaURL, true)}
110
130
  download={`${message.data.name}(${message.data.version})-${schemaFilePath}`}
111
- class="hidden w-full md:inline-flex h-10 justify-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-200 bg-gray-800 hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-900"
131
+ class="flex items-center justify-center space-x-2 text-center rounded-md w-full bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-100/60 hover:text-primary"
112
132
  >
113
- <>
114
- <svg
115
- xmlns="http://www.w3.org/2000/svg"
116
- fill="none"
117
- viewBox="0 0 24 24"
118
- stroke-width="2"
119
- stroke="currentColor"
120
- aria-hidden="true"
121
- class="-ml-1 mr-2 h-5 w-5 text-gray-200"
122
- >
123
- <path
124
- stroke-linecap="round"
125
- stroke-linejoin="round"
126
- d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
127
- />
128
- </svg>
129
- <span>Download Schema</span>
130
- </>
133
+ <FileDownIcon strokeWidth={2} size={16} />
134
+ <span>Download schema</span>
131
135
  </a>
132
136
  )
133
137
  }
134
138
  <a
135
139
  href={buildUrl(`/visualiser/${message.collection}/${message.data.id}/${message.data.version}`)}
136
- class="block text-center rounded-md w-full bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-100/60 hover:text-primary"
137
- >View in Visualiser</a
140
+ class="flex items-center justify-center space-x-2 text-center rounded-md w-full bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-100/60 hover:text-primary"
138
141
  >
142
+ <Workflow strokeWidth={2} size={16} />
143
+ <span class="block">View in visualiser</span>
144
+ </a>
139
145
 
140
146
  <a
141
147
  href={buildUrl(`/docs/${message.collection}/${message.data.id}/${message.data.version}/changelog`)}
142
- class="block text-center rounded-md w-full bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-100/60 hover:text-primary"
143
- >Changelog</a
148
+ class="flex items-center space-x-2 justify-center text-center rounded-md w-full bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-100/60 hover:text-primary"
144
149
  >
150
+ <ScrollText strokeWidth={2} size={16} />
151
+ <span class="block">Read changelog</span>
152
+ </a>
145
153
  </div>
146
154
  </div>
147
155
  </aside>
@@ -1,10 +1,11 @@
1
1
  ---
2
2
  import OwnersList from '@components/Lists/OwnersList';
3
- import PillList from '@components/Lists/PillList';
3
+ import PillListFlat from '@components/Lists/PillListFlat';
4
4
  import SpecificationsList from '@components/Lists/SpecificationsList.astro';
5
5
  import VersionList from '@components/Lists/VersionList.astro';
6
6
  import { buildUrl } from '@utils/url-builder';
7
7
  import { getEntry, type CollectionEntry } from 'astro:content';
8
+ import { ScrollText, Workflow, FileDownIcon } from 'lucide-react';
8
9
  import { join } from 'node:path';
9
10
  interface Props {
10
11
  service: CollectionEntry<'services'>;
@@ -24,6 +25,7 @@ const sendsList = sends.map((p) => ({
24
25
  label: p.data.name,
25
26
  badge: p.collection,
26
27
  color: p.collection === 'events' ? 'orange' : 'blue',
28
+ collection: p.collection,
27
29
  tag: `v${p.data.version}`,
28
30
  href: buildUrl(`/docs/${p.collection}/${p.data.id}/${p.data.version}`),
29
31
  }));
@@ -32,6 +34,7 @@ const receivesList = receives.map((p) => ({
32
34
  badge: p.collection,
33
35
  color: p.collection === 'events' ? 'orange' : 'blue',
34
36
  tag: `v${p.data.version}`,
37
+ collection: p.collection,
35
38
  href: buildUrl(`/docs/${p.collection}/${p.data.id}/${p.data.version}`),
36
39
  }));
37
40
 
@@ -49,22 +52,26 @@ const schemaFilePath = service?.data?.schemaPath;
49
52
  const schemaURL = join(publicPath, schemaFilePath || '');
50
53
  ---
51
54
 
52
- <aside class="sticky top-28 left-0 space-y-8 h-full overflow-y-auto">
53
- <div id="sidebar-cta-portal">
54
- <PillList
55
+ <aside class="sticky top-28 left-0 h-full overflow-y-auto pr-6 py-4">
56
+ <div id="sidebar-cta-portal" class="">
57
+ <PillListFlat
55
58
  title={`Receives Messages (${receivesList.length})`}
56
59
  pills={receivesList}
57
60
  emptyMessage={`This service does not receive any messages.`}
58
61
  color="orange"
59
62
  client:load
60
63
  />
61
- <PillList
64
+ <PillListFlat
62
65
  title={`Sends Messages (${sendsList.length})`}
63
66
  pills={sendsList}
64
67
  emptyMessage={`This service does not send any messages.`}
65
68
  color="orange"
66
69
  client:load
67
70
  />
71
+ {service.data.versions && <VersionList versions={service.data.versions} collectionItem={service} />}
72
+
73
+ {service.data.specifications && <SpecificationsList collectionItem={service} />}
74
+
68
75
  <OwnersList
69
76
  title={`Service owners (${ownersList.length})`}
70
77
  owners={ownersList}
@@ -72,48 +79,33 @@ const schemaURL = join(publicPath, schemaFilePath || '');
72
79
  client:load
73
80
  />
74
81
 
75
- {service.data.versions && <VersionList versions={service.data.versions} collectionItem={service} />}
76
- {service.data.specifications && <SpecificationsList collectionItem={service} />}
77
-
78
82
  <div class="space-y-2">
79
83
  {
80
84
  service?.data?.schemaPath && (
81
85
  <a
82
86
  href={buildUrl(schemaURL, true)}
83
87
  download={`${service.data.name}(${service.data.version})-${schemaFilePath}`}
84
- class="hidden w-full md:inline-flex h-10 justify-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-200 bg-gray-800 hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-900"
88
+ class="flex items-center justify-center space-x-2 text-center rounded-md w-full bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-100/60 hover:text-primary"
85
89
  >
86
- <>
87
- <svg
88
- xmlns="http://www.w3.org/2000/svg"
89
- fill="none"
90
- viewBox="0 0 24 24"
91
- stroke-width="2"
92
- stroke="currentColor"
93
- aria-hidden="true"
94
- class="-ml-1 mr-2 h-5 w-5 text-gray-200"
95
- >
96
- <path
97
- stroke-linecap="round"
98
- stroke-linejoin="round"
99
- d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
100
- />
101
- </svg>
102
- <span>Download Schema</span>
103
- </>
90
+ <FileDownIcon strokeWidth={2} size={16} />
91
+ <span>Download schema</span>
104
92
  </a>
105
93
  )
106
94
  }
107
95
  <a
108
96
  href={buildUrl(`/visualiser/${service.collection}/${service.data.id}/${service.data.version}`)}
109
- class="block text-center rounded-md w-full bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-100/60 hover:text-primary"
110
- >View in Visualiser</a
97
+ class="flex items-center justify-center space-x-2 text-center rounded-md w-full bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-100/60 hover:text-primary"
111
98
  >
99
+ <Workflow strokeWidth={2} size={16} />
100
+ <span class="block">View in visualiser</span>
101
+ </a>
112
102
  <a
113
103
  href={buildUrl(`/docs/${service.collection}/${service.data.id}/${service.data.version}/changelog`)}
114
- class="block text-center rounded-md w-full bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-100/60 hover:text-primary"
115
- >Changelog</a
104
+ class="flex items-center space-x-2 justify-center text-center rounded-md w-full bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-100/60 hover:text-primary"
116
105
  >
106
+ <ScrollText strokeWidth={2} size={16} />
107
+ <span class="block">Read changelog</span>
108
+ </a>
117
109
  </div>
118
110
  </div>
119
111
  </aside>
@@ -64,8 +64,8 @@ export const Table = ({
64
64
  <div className=" bg-gray-100/20 rounded-md border-2 border-gray-200 shadow-sm ">
65
65
  <table className="min-w-full divide-y divide-gray-200 rounded-md ">
66
66
  <thead className="bg-gray-200/50">
67
- {table.getHeaderGroups().map((headerGroup) => (
68
- <tr key={headerGroup.id} className="rounded-tl-lg">
67
+ {table.getHeaderGroups().map((headerGroup, index) => (
68
+ <tr key={`${headerGroup}-${index}`} className="rounded-tl-lg">
69
69
  {headerGroup.headers.map((header) => (
70
70
  <th key={`${header.id}`} className="pl-4 pr-3 text-left text-sm font-semibold text-gray-800 sm:pl-0 ">
71
71
  <div className="flex flex-col justify-start px-2 py-2 space-y-2">
@@ -78,9 +78,9 @@ export const columns = () => [
78
78
  return <div className="font-light text-sm text-gray-400/60 text-left italic">No producers documented</div>;
79
79
  return (
80
80
  <ul className="">
81
- {producers.map((producer: any) => {
81
+ {producers.map((producer: any, index: number) => {
82
82
  return (
83
- <li className="py-2 group flex items-center space-x-2" key={producer.data.id}>
83
+ <li className="py-2 group flex items-center space-x-2" key={`${producer.data.id}-${index}`}>
84
84
  <a
85
85
  href={buildUrl(`/docs/${producer.collection}/${producer.data.id}/${producer.data.version}`)}
86
86
  className="group-hover:text-primary flex space-x-1 items-center "
@@ -118,9 +118,9 @@ export const columns = () => [
118
118
 
119
119
  return (
120
120
  <ul>
121
- {consumers.map((consumer: any) => {
121
+ {consumers.map((consumer: any, index: number) => {
122
122
  return (
123
- <li key={consumer.data.id} className="py-1 group font-light ">
123
+ <li key={`${consumer.data.id}-${index}`} className="py-1 group font-light ">
124
124
  <a
125
125
  href={buildUrl(`/docs/${consumer.collection}/${consumer.data.id}/${consumer.data.version}`)}
126
126
  className="group-hover:text-primary flex space-x-1 items-center "
@@ -71,11 +71,11 @@ export const columns = () => [
71
71
 
72
72
  return (
73
73
  <ul>
74
- {receives.map((consumer: any) => {
74
+ {receives.map((consumer: any, index: number) => {
75
75
  const type = consumer.collection.slice(0, -1);
76
76
  const { color, Icon } = useMemo(() => getColorAndIconForMessageType(type), [type]);
77
77
  return (
78
- <li key={consumer.data.id} className="py-1 group font-light ">
78
+ <li key={`${consumer.data.id}-${index}`} className="py-1 group font-light ">
79
79
  <a
80
80
  href={buildUrl(`/docs/${consumer.collection}/${consumer.data.id}/${consumer.data.version}`)}
81
81
  className="group-hover:text-primary flex space-x-1 items-center "
@@ -113,12 +113,12 @@ export const columns = () => [
113
113
 
114
114
  return (
115
115
  <ul>
116
- {sends.map((consumer: any) => {
116
+ {sends.map((consumer: any, index: number) => {
117
117
  const type = consumer.collection.slice(0, -1);
118
118
  const color = type === 'event' ? 'orange' : 'blue';
119
119
  const Icon = type === 'event' ? BoltIcon : ChatBubbleLeftIcon;
120
120
  return (
121
- <li key={consumer.data.id} className="py-1 group font-light">
121
+ <li key={`${consumer.data.id}-${index}`} className="py-1 group font-light">
122
122
  <a
123
123
  href={buildUrl(`/docs/${consumer.collection}/${consumer.data.id}/${consumer.data.version}`)}
124
124
  className="group-hover:text-primary flex space-x-1 items-center "
@@ -2,7 +2,6 @@
2
2
  import { Table } from '@components/Tables/Table';
3
3
  import { QueueListIcon, RectangleGroupIcon, BoltIcon, ChatBubbleLeftIcon } from '@heroicons/react/24/outline';
4
4
  import ServerIcon from '@heroicons/react/24/outline/ServerIcon';
5
- import PlainPage from '@layouts/PlainPage.astro';
6
5
  import { getCommands } from '@utils/commands';
7
6
  import { getDomains } from '@utils/domains/domains';
8
7
  import { getFlows } from '@utils/flows/flows';
@@ -11,6 +10,7 @@ import { getServices } from '@utils/services/services';
11
10
  import { buildUrl } from '@utils/url-builder';
12
11
  import { getQueries } from '@utils/queries';
13
12
  import { MagnifyingGlassIcon } from '@heroicons/react/20/solid';
13
+ import VerticalSideBarLayout from './VerticalSideBarLayout.astro';
14
14
 
15
15
  const events = await getEvents();
16
16
  const queries = await getQueries();
@@ -74,8 +74,8 @@ const tabs = [
74
74
  ];
75
75
  ---
76
76
 
77
- <PlainPage title={`Explore | ${title}`}>
78
- <main>
77
+ <VerticalSideBarLayout title={`Explore | ${title}`}>
78
+ <main class="ml-0">
79
79
  <div>
80
80
  <!-- <div class="sm:hidden">
81
81
  <label for="tabs" class="sr-only">Select a tab</label>
@@ -88,7 +88,7 @@ const tabs = [
88
88
  </div> -->
89
89
  <div class="hidden sm:block">
90
90
  <div class="border-b border-gray-200">
91
- <nav class="flex space-x-8 -mb-0.5" aria-label="Tabs">
91
+ <nav class="flex space-x-8 -mb-0.5 pl-6" aria-label="Tabs">
92
92
  {
93
93
  tabs.map((tab) => (
94
94
  <a
@@ -109,9 +109,9 @@ const tabs = [
109
109
  </div>
110
110
 
111
111
  <!-- Table -->
112
- <div class="pb-20">
112
+ <div class="pb-20 ml-6">
113
113
  <div>
114
- <div class="sm:flex sm:items-center py-8 pb-4">
114
+ <div class="sm:flex sm:items-center py-4 pb-4">
115
115
  <div class="sm:flex-auto space-y-2">
116
116
  <h1 class="text-4xl font-semibold text-gray-900 capitalize">{title}</h1>
117
117
  <p class="text-md text-gray-700">{subtitle}</p>
@@ -128,7 +128,7 @@ const tabs = [
128
128
  </div>
129
129
  </div>
130
130
  </main>
131
- </PlainPage>
131
+ </VerticalSideBarLayout>
132
132
 
133
133
  <style>
134
134
  .ec-align-top {
@@ -3,7 +3,7 @@ import { buildUrl } from '@utils/url-builder';
3
3
  const { className } = Astro.props;
4
4
  ---
5
5
 
6
- <footer class={`py-4 space-y-8 border-t border-gray-300 ${className}`}>
6
+ <footer class={`relative py-4 space-y-8 border-t border-gray-300 ${className}`}>
7
7
  <div class="flex justify-between items-center py-8 text-gray-500 text-sm font-light">
8
8
  <div class="flex space-x-5">
9
9
  <a href="https://github.com/event-catalog/eventcatalog" target="_blank"