@eventcatalog/core 2.57.0 → 2.57.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +1 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/{chunk-NVY3KN4D.js → chunk-A7SEN2P6.js} +1 -1
- package/dist/{chunk-6ILF3VK6.js → chunk-C2EHTPRH.js} +1 -1
- package/dist/{chunk-24JFJA4V.js → chunk-IZVKIJ4Q.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -1
- package/dist/eventcatalog.js +3 -3
- package/eventcatalog/astro.config.mjs +6 -1
- package/eventcatalog/src/components/Lists/PillListFlat.tsx +108 -27
- package/eventcatalog/src/components/MDX/Attachments.astro +158 -0
- package/eventcatalog/src/components/MDX/Tiles/Tile.astro +31 -15
- package/eventcatalog/src/components/MDX/Tiles/Tiles.astro +3 -3
- package/eventcatalog/src/components/MDX/components.tsx +2 -0
- package/eventcatalog/src/components/SideBars/ChannelSideBar.astro +25 -0
- package/eventcatalog/src/components/SideBars/DomainSideBar.astro +25 -0
- package/eventcatalog/src/components/SideBars/EntitySideBar.astro +24 -0
- package/eventcatalog/src/components/SideBars/FlowSideBar.astro +25 -0
- package/eventcatalog/src/components/SideBars/MessageSideBar.astro +25 -0
- package/eventcatalog/src/components/SideBars/ServiceSideBar.astro +25 -0
- package/eventcatalog/src/content.config.ts +18 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +26 -6
- package/package.json +3 -2
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
log_build_default
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-A7SEN2P6.js";
|
|
4
|
+
import "../chunk-IZVKIJ4Q.js";
|
|
5
|
+
import "../chunk-C2EHTPRH.js";
|
|
6
6
|
import "../chunk-UPONRQSN.js";
|
|
7
7
|
export {
|
|
8
8
|
log_build_default as default
|
package/dist/constants.cjs
CHANGED
package/dist/constants.js
CHANGED
package/dist/eventcatalog.cjs
CHANGED
package/dist/eventcatalog.js
CHANGED
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
} from "./chunk-PLNJC7NZ.js";
|
|
7
7
|
import {
|
|
8
8
|
log_build_default
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-A7SEN2P6.js";
|
|
10
|
+
import "./chunk-IZVKIJ4Q.js";
|
|
11
11
|
import {
|
|
12
12
|
catalogToAstro,
|
|
13
13
|
checkAndConvertMdToMdx
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
import "./chunk-55D645EH.js";
|
|
16
16
|
import {
|
|
17
17
|
VERSION
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-C2EHTPRH.js";
|
|
19
19
|
import {
|
|
20
20
|
getProjectOutDir,
|
|
21
21
|
isAuthEnabled,
|
|
@@ -2,6 +2,7 @@ import { defineConfig } from 'astro/config';
|
|
|
2
2
|
import tailwind from '@astrojs/tailwind';
|
|
3
3
|
import mdx from '@astrojs/mdx';
|
|
4
4
|
import react from '@astrojs/react';
|
|
5
|
+
import { searchForWorkspaceRoot } from 'vite';
|
|
5
6
|
import { mermaid } from "./src/remark-plugins/mermaid"
|
|
6
7
|
import { plantuml } from "./src/remark-plugins/plantuml"
|
|
7
8
|
import { join } from 'node:path';
|
|
@@ -94,7 +95,11 @@ export default defineConfig({
|
|
|
94
95
|
},
|
|
95
96
|
server: {
|
|
96
97
|
fs: {
|
|
97
|
-
allow: [
|
|
98
|
+
allow: [
|
|
99
|
+
'..',
|
|
100
|
+
'./node_modules/@fontsource',
|
|
101
|
+
searchForWorkspaceRoot(process.cwd()),
|
|
102
|
+
]
|
|
98
103
|
}
|
|
99
104
|
},
|
|
100
105
|
worker: {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/react';
|
|
2
2
|
import { ChevronDownIcon } from '@heroicons/react/20/solid';
|
|
3
3
|
import { getIconForCollection as getIconForCollectionOriginal } from '@utils/collections/icons';
|
|
4
|
-
import { useMemo } from 'react';
|
|
4
|
+
import { useMemo, useState } from 'react';
|
|
5
|
+
import * as icons from 'lucide-react'; // Import all icons
|
|
5
6
|
|
|
6
7
|
import './PillListFlat.styles.css';
|
|
7
8
|
|
|
@@ -14,17 +15,80 @@ interface Props {
|
|
|
14
15
|
label: string;
|
|
15
16
|
badge?: string;
|
|
16
17
|
href?: string;
|
|
18
|
+
target?: '_blank' | '_self';
|
|
17
19
|
tag?: string;
|
|
18
20
|
color?: string;
|
|
19
21
|
collection?: string;
|
|
20
22
|
description?: string;
|
|
21
23
|
icon?: string;
|
|
24
|
+
subgroup?: string | undefined;
|
|
22
25
|
}[];
|
|
23
26
|
emptyMessage?: string;
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
const PillList = ({ title, pills, emptyMessage, color = 'gray', limit = 10, ...props }: Props) => {
|
|
27
30
|
const getIconForCollection = useMemo(() => getIconForCollectionOriginal, []);
|
|
31
|
+
const [collapsedSubgroups, setCollapsedSubgroups] = useState<Set<string>>(new Set());
|
|
32
|
+
|
|
33
|
+
const groupedPills = useMemo(() => {
|
|
34
|
+
const grouped = new Map<string, typeof pills>();
|
|
35
|
+
const ungrouped: typeof pills = [];
|
|
36
|
+
|
|
37
|
+
pills.forEach((pill) => {
|
|
38
|
+
if (pill.subgroup) {
|
|
39
|
+
if (!grouped.has(pill.subgroup)) {
|
|
40
|
+
grouped.set(pill.subgroup, []);
|
|
41
|
+
}
|
|
42
|
+
grouped.get(pill.subgroup)!.push(pill);
|
|
43
|
+
} else {
|
|
44
|
+
ungrouped.push(pill);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return { grouped, ungrouped };
|
|
49
|
+
}, [pills]);
|
|
50
|
+
|
|
51
|
+
const toggleSubgroup = (subgroupName: string) => {
|
|
52
|
+
setCollapsedSubgroups((prev) => {
|
|
53
|
+
const newSet = new Set(prev);
|
|
54
|
+
if (newSet.has(subgroupName)) {
|
|
55
|
+
newSet.delete(subgroupName);
|
|
56
|
+
} else {
|
|
57
|
+
newSet.add(subgroupName);
|
|
58
|
+
}
|
|
59
|
+
return newSet;
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const renderPillItem = (item: (typeof pills)[0]) => {
|
|
64
|
+
const href = item.href ?? '#';
|
|
65
|
+
const Icon = item.collection ? getIconForCollection(item.collection) : null;
|
|
66
|
+
const PillIcon = item.icon ? (icons as any)[item.icon] : null;
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<li
|
|
70
|
+
className=" has-tooltip rounded-md text-gray-600 group px-1 w-full hover:bg-gradient-to-l hover:from-purple-500 hover:to-purple-700 hover:text-white hover:font-normal "
|
|
71
|
+
key={item.href}
|
|
72
|
+
>
|
|
73
|
+
<a className={`leading-3`} href={href} target={item.target ?? '_self'}>
|
|
74
|
+
<span className="space-x-2 flex items-center">
|
|
75
|
+
{Icon && !PillIcon && <Icon className="h-4 w-4 shrink-0" />}
|
|
76
|
+
{PillIcon && <PillIcon className="h-4 w-4 shrink-0" />}
|
|
77
|
+
<span className="font-light text-sm truncate">
|
|
78
|
+
{item.label} {item.tag && <>({item.tag})</>}
|
|
79
|
+
</span>
|
|
80
|
+
{item.label.length > 24 && (
|
|
81
|
+
<span className="tooltip rounded relative shadow-lg p-1 font-normal text-xs bg-white text-black ml-[30px] mt-12">
|
|
82
|
+
{item.label} {item.tag && <>({item.tag})</>}
|
|
83
|
+
</span>
|
|
84
|
+
)}
|
|
85
|
+
</span>
|
|
86
|
+
{item.description && <span className="text-[9px] block ml-6 mt-1 leading-0">{item.description}</span>}
|
|
87
|
+
</a>
|
|
88
|
+
</li>
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
|
|
28
92
|
return (
|
|
29
93
|
<div className="">
|
|
30
94
|
<div className="mx-auto w-full max-w-lg divide-y divide-white/5 rounded-xl bg-white/5">
|
|
@@ -34,39 +98,56 @@ const PillList = ({ title, pills, emptyMessage, color = 'gray', limit = 10, ...p
|
|
|
34
98
|
<ChevronDownIcon className="size-5 ml-2 fill-black/60 group-data-[hover]:fill-black/50 group-data-[open]:rotate-180" />
|
|
35
99
|
</DisclosureButton>
|
|
36
100
|
<DisclosurePanel className="mt-2 text-sm/5 text-black/50">
|
|
37
|
-
<
|
|
38
|
-
{
|
|
39
|
-
|
|
40
|
-
|
|
101
|
+
<div className="space-y-2">
|
|
102
|
+
{groupedPills.ungrouped.length > 0 && (
|
|
103
|
+
<ul role="list" className="space-y-2">
|
|
104
|
+
{groupedPills.ungrouped.map(renderPillItem)}
|
|
105
|
+
</ul>
|
|
106
|
+
)}
|
|
41
107
|
|
|
108
|
+
{Array.from(groupedPills.grouped.entries()).map(([subgroupName, subgroupPills]) => {
|
|
109
|
+
const isCollapsed = collapsedSubgroups.has(subgroupName);
|
|
42
110
|
return (
|
|
43
|
-
<
|
|
44
|
-
className="
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
111
|
+
<div key={subgroupName} className="space-y-">
|
|
112
|
+
<div className="flex items-center">
|
|
113
|
+
<button
|
|
114
|
+
onClick={(e) => {
|
|
115
|
+
e.stopPropagation();
|
|
116
|
+
toggleSubgroup(subgroupName);
|
|
117
|
+
}}
|
|
118
|
+
className="p-1 hover:bg-gray-100 rounded-md"
|
|
119
|
+
>
|
|
120
|
+
<div className={`transition-transform duration-150 ${isCollapsed ? '' : 'rotate-180'}`}>
|
|
121
|
+
<ChevronDownIcon className="h-3 w-3 text-gray-500" />
|
|
122
|
+
</div>
|
|
123
|
+
</button>
|
|
124
|
+
<button
|
|
125
|
+
onClick={(e) => {
|
|
126
|
+
e.stopPropagation();
|
|
127
|
+
toggleSubgroup(subgroupName);
|
|
128
|
+
}}
|
|
129
|
+
className="flex-grow flex items-center justify-between px-2 py-0.5 text-xs font-bold rounded-md text-gray-900 uppercase"
|
|
130
|
+
>
|
|
131
|
+
{subgroupName} ({subgroupPills.length})
|
|
132
|
+
</button>
|
|
133
|
+
</div>
|
|
134
|
+
<div
|
|
135
|
+
className={`overflow-hidden transition-[height] duration-150 ease-out ${isCollapsed ? 'h-0' : 'h-auto'}`}
|
|
136
|
+
>
|
|
137
|
+
<ul role="list" className="space-y-2 border-l border-gray-200/80 ml-[9px] pl-4 pt-2">
|
|
138
|
+
{subgroupPills.map(renderPillItem)}
|
|
139
|
+
</ul>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
62
142
|
);
|
|
63
143
|
})}
|
|
144
|
+
|
|
64
145
|
{pills.length === 0 && emptyMessage && (
|
|
65
|
-
<
|
|
146
|
+
<div className="inline mr-2 leading-tight text-xs">
|
|
66
147
|
<span className="text-gray-400">{emptyMessage}</span>
|
|
67
|
-
</
|
|
148
|
+
</div>
|
|
68
149
|
)}
|
|
69
|
-
</
|
|
150
|
+
</div>
|
|
70
151
|
</DisclosurePanel>
|
|
71
152
|
</Disclosure>
|
|
72
153
|
</div>
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { ComponentType } from 'react';
|
|
3
|
+
import * as Icons from '@heroicons/react/24/outline';
|
|
4
|
+
import * as SolidIcons from '@heroicons/react/24/solid';
|
|
5
|
+
import * as LucideIcons from 'lucide-react';
|
|
6
|
+
|
|
7
|
+
interface AttachmentObject {
|
|
8
|
+
url: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
type?: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
summary?: string;
|
|
13
|
+
icon?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type Attachment = string | AttachmentObject;
|
|
17
|
+
|
|
18
|
+
interface Props {
|
|
19
|
+
title?: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
columns?: number;
|
|
22
|
+
data: {
|
|
23
|
+
attachments: Attachment[];
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const { title = 'Attachments', description, columns = 2, ...props } = Astro.props;
|
|
28
|
+
const { attachments } = props.data;
|
|
29
|
+
|
|
30
|
+
function getIconForAttachment(attachment: AttachmentObject): ComponentType<{ className?: string }> | null {
|
|
31
|
+
// If custom icon is provided, try to find it
|
|
32
|
+
if (attachment.icon) {
|
|
33
|
+
const customIcon =
|
|
34
|
+
(LucideIcons as any)[attachment.icon] || (Icons as any)[attachment.icon] || (SolidIcons as any)[attachment.icon];
|
|
35
|
+
if (customIcon) return customIcon;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Default to link icon for all attachments
|
|
39
|
+
return Icons.LinkIcon;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function normalizeAttachment(attachment: Attachment): AttachmentObject {
|
|
43
|
+
if (typeof attachment === 'string') {
|
|
44
|
+
// Extract filename from URL for title
|
|
45
|
+
const urlParts = attachment.split('/');
|
|
46
|
+
const filename = urlParts[urlParts.length - 1];
|
|
47
|
+
const title = filename.includes('.') ? filename.split('.')[0] : filename || 'Link';
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
url: attachment,
|
|
51
|
+
title: title.replace(/[-_]/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return attachment;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isExternalUrl(url: string): boolean {
|
|
58
|
+
return url.startsWith('http://') || url.startsWith('https://');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const normalizedAttachments = attachments.map(normalizeAttachment);
|
|
62
|
+
|
|
63
|
+
// Group attachments by type
|
|
64
|
+
const groupedAttachments = normalizedAttachments.reduce(
|
|
65
|
+
(groups, attachment) => {
|
|
66
|
+
const type = attachment.type || 'Other';
|
|
67
|
+
if (!groups[type]) {
|
|
68
|
+
groups[type] = [];
|
|
69
|
+
}
|
|
70
|
+
groups[type].push(attachment);
|
|
71
|
+
return groups;
|
|
72
|
+
},
|
|
73
|
+
{} as Record<string, AttachmentObject[]>
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const sortedGroups = Object.entries(groupedAttachments).sort(([a], [b]) => {
|
|
77
|
+
if (a === 'Other') return 1;
|
|
78
|
+
if (b === 'Other') return -1;
|
|
79
|
+
return a.localeCompare(b);
|
|
80
|
+
});
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
<section class="not-prose my-8">
|
|
84
|
+
{title && <h3 class="flex items-center gap-2 text-3xl font-bold mb-4">{title}</h3>}
|
|
85
|
+
|
|
86
|
+
{description && <p class="text-gray-600 mb-6 prose prose-md">{description}</p>}
|
|
87
|
+
|
|
88
|
+
{
|
|
89
|
+
normalizedAttachments.length === 0 ? (
|
|
90
|
+
<div class="text-gray-500 text-sm italic">No attachments available.</div>
|
|
91
|
+
) : (
|
|
92
|
+
<div class="space-y-6">
|
|
93
|
+
{sortedGroups.map(([groupType, groupAttachments], index) => (
|
|
94
|
+
<div key={groupType + index}>
|
|
95
|
+
<h4 class="text-sm font-medium text-gray-900 mb-3 uppercase tracking-wider">
|
|
96
|
+
{groupType} ({groupAttachments.length})
|
|
97
|
+
</h4>
|
|
98
|
+
<div class={`grid grid-cols-1 ${columns === 1 ? '' : `md:grid-cols-${Math.min(columns, 3)}`} gap-4`}>
|
|
99
|
+
{groupAttachments.map((attachment) => {
|
|
100
|
+
const IconComponent = getIconForAttachment(attachment);
|
|
101
|
+
const isExternal = isExternalUrl(attachment.url);
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<a
|
|
105
|
+
href={attachment.url}
|
|
106
|
+
target={isExternal ? '_blank' : '_self'}
|
|
107
|
+
rel={isExternal ? 'noopener noreferrer' : undefined}
|
|
108
|
+
class="group block bg-white border border-gray-200 rounded-lg p-4 transition-all duration-200 hover:shadow-md hover:border-purple-300 hover:bg-purple-50/30 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2"
|
|
109
|
+
>
|
|
110
|
+
<div class="flex items-start gap-3">
|
|
111
|
+
<div class="flex-shrink-0 p-2 bg-gray-100 rounded-lg group-hover:bg-purple-100 transition-colors duration-200">
|
|
112
|
+
{IconComponent && <IconComponent className="w-5 h-5 text-gray-600 group-hover:text-purple-600" />}
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<div class="flex-grow min-w-0">
|
|
116
|
+
<div class="flex items-center gap-2">
|
|
117
|
+
<h5 class="text-sm font-medium text-gray-900 group-hover:text-purple-900 truncate">
|
|
118
|
+
{attachment.title || 'Attachment'}
|
|
119
|
+
</h5>
|
|
120
|
+
{isExternal && (
|
|
121
|
+
<Icons.ArrowTopRightOnSquareIcon className="w-3 h-3 text-gray-400 group-hover:text-purple-500 flex-shrink-0" />
|
|
122
|
+
)}
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
{attachment.summary && (
|
|
126
|
+
<p class="mt-1 text-xs text-gray-600 group-hover:text-purple-700 line-clamp-2">{attachment.summary}</p>
|
|
127
|
+
)}
|
|
128
|
+
|
|
129
|
+
{attachment.description && (
|
|
130
|
+
<p class="mt-1 text-xs text-gray-600 group-hover:text-purple-700 line-clamp-2">
|
|
131
|
+
{attachment.description}
|
|
132
|
+
</p>
|
|
133
|
+
)}
|
|
134
|
+
|
|
135
|
+
<div class="mt-2 text-xs text-gray-400 group-hover:text-purple-500 truncate">
|
|
136
|
+
{attachment.url.replace(/^https?:\/\//, '')}
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
</a>
|
|
141
|
+
);
|
|
142
|
+
})}
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
))}
|
|
146
|
+
</div>
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
</section>
|
|
150
|
+
|
|
151
|
+
<style>
|
|
152
|
+
.line-clamp-2 {
|
|
153
|
+
display: -webkit-box;
|
|
154
|
+
-webkit-line-clamp: 2;
|
|
155
|
+
-webkit-box-orient: vertical;
|
|
156
|
+
overflow: hidden;
|
|
157
|
+
}
|
|
158
|
+
</style>
|
|
@@ -23,20 +23,36 @@ function startsWithProtocol(str: string) {
|
|
|
23
23
|
}
|
|
24
24
|
---
|
|
25
25
|
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
26
|
+
<div class="group">
|
|
27
|
+
<!-- Card with just the icon -->
|
|
28
|
+
<a
|
|
29
|
+
href={startsWithProtocol(href) ? href : buildUrl(href)}
|
|
30
|
+
target={openWindow ? '_blank' : '_self'}
|
|
31
|
+
class="block relative bg-white border border-gray-200 rounded-xl p-8 h-48 transition-all duration-300 ease-out hover:border-purple-300 hover:shadow-lg hover:shadow-purple-500/10 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2 overflow-hidden"
|
|
32
|
+
>
|
|
33
|
+
<!-- Icon centered in card with grid background -->
|
|
34
|
+
<div class="relative h-full flex items-center justify-center">
|
|
35
|
+
<!-- Squared paper grid behind icon -->
|
|
36
|
+
<div
|
|
37
|
+
class="absolute inset-0 opacity-15"
|
|
38
|
+
style="background-image:
|
|
39
|
+
linear-gradient(rgba(147, 51, 234, 0.2) 1px, transparent 1px),
|
|
40
|
+
linear-gradient(90deg, rgba(147, 51, 234, 0.2) 1px, transparent 1px);
|
|
41
|
+
background-size: 16px 16px;"
|
|
42
|
+
>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
{IconComponent && <IconComponent className="relative w-16 h-16 text-purple-600 stroke-1" />}
|
|
40
46
|
</div>
|
|
47
|
+
</a>
|
|
48
|
+
|
|
49
|
+
<!-- Title and description outside card -->
|
|
50
|
+
<div class="mt-4 space-y-0">
|
|
51
|
+
<h2 class="text-gray-900 text-lg font-semibold">
|
|
52
|
+
{title}
|
|
53
|
+
</h2>
|
|
54
|
+
<p class="text-gray-600 text-sm leading-relaxed">
|
|
55
|
+
{description}
|
|
56
|
+
</p>
|
|
41
57
|
</div>
|
|
42
|
-
</
|
|
58
|
+
</div>
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
const { title, columns = 2 } = Astro.props;
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
<section class="not-prose">
|
|
6
|
-
{title && <h2 class="text-2xl font-bold text-gray-800 mb-
|
|
7
|
-
<div class={`grid grid-cols-1 md:grid-cols-${columns} gap-
|
|
5
|
+
<section class="not-prose my-8">
|
|
6
|
+
{title && <h2 class="text-2xl font-bold text-gray-800 mb-6">{title}</h2>}
|
|
7
|
+
<div class={`grid grid-cols-1 md:grid-cols-${columns} gap-6 w-full not-prose`}>
|
|
8
8
|
<slot />
|
|
9
9
|
</div>
|
|
10
10
|
</section>
|
|
@@ -13,6 +13,7 @@ import Admonition from '@components/MDX/Admonition';
|
|
|
13
13
|
import OpenAPI from '@components/MDX/OpenAPI/OpenAPI.astro';
|
|
14
14
|
import AsyncAPI from '@components/MDX/AsyncAPI/AsyncAPI.astro';
|
|
15
15
|
import ChannelInformation from '@components/MDX/ChannelInformation/ChannelInformation';
|
|
16
|
+
import Attachments from '@components/MDX/Attachments.astro';
|
|
16
17
|
import MessageTable from '@components/MDX/MessageTable/MessageTable.astro';
|
|
17
18
|
import ResourceGroupTable from '@components/MDX/ResourceGroupTable/ResourceGroupTable.astro';
|
|
18
19
|
import EntityPropertiesTable from '@components/MDX/EntityPropertiesTable/EntityPropertiesTable.astro';
|
|
@@ -34,6 +35,7 @@ import RemoteSchema from '@components/MDX/RemoteSchema.astro';
|
|
|
34
35
|
|
|
35
36
|
const components = (props: any) => {
|
|
36
37
|
return {
|
|
38
|
+
Attachments: (mdxProp: any) => jsx(Attachments, { ...props, ...mdxProp }),
|
|
37
39
|
Accordion,
|
|
38
40
|
AccordionGroup,
|
|
39
41
|
Admonition,
|
|
@@ -27,6 +27,19 @@ const parameters = Object.keys(channelParameters).map((key) => ({
|
|
|
27
27
|
...channelParameters[key],
|
|
28
28
|
}));
|
|
29
29
|
|
|
30
|
+
const attachments = channel.data.attachments || [];
|
|
31
|
+
|
|
32
|
+
const attachmentsList = attachments.map((a) => {
|
|
33
|
+
const attachmentIsURL = typeof a === 'string';
|
|
34
|
+
return {
|
|
35
|
+
label: attachmentIsURL ? a : (a.title ?? a.url),
|
|
36
|
+
href: attachmentIsURL ? a : a.url,
|
|
37
|
+
icon: attachmentIsURL ? 'ExternalLinkIcon' : (a.icon ?? 'ExternalLinkIcon'),
|
|
38
|
+
target: '_blank' as const,
|
|
39
|
+
subgroup: attachmentIsURL ? undefined : (a.type ?? ''),
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
|
|
30
43
|
const paramsList = parameters.map((param) => ({
|
|
31
44
|
label: param.key,
|
|
32
45
|
description: param?.description,
|
|
@@ -139,6 +152,18 @@ const shouldRenderSideBarSection = (section: string) => {
|
|
|
139
152
|
)
|
|
140
153
|
}
|
|
141
154
|
|
|
155
|
+
{
|
|
156
|
+
channel.data.attachments && shouldRenderSideBarSection('attachments') && (
|
|
157
|
+
<PillListFlat
|
|
158
|
+
title={`Attachments (${attachmentsList.length})`}
|
|
159
|
+
pills={attachmentsList}
|
|
160
|
+
emptyMessage={`This channel does not have any attachments.`}
|
|
161
|
+
color="pink"
|
|
162
|
+
client:load
|
|
163
|
+
/>
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
|
|
142
167
|
{
|
|
143
168
|
ownersList.length > 0 && shouldRenderSideBarSection('owners') && (
|
|
144
169
|
<OwnersList
|
|
@@ -25,6 +25,8 @@ const subDomains = (domain.data.domains as CollectionEntry<'domains'>[]) || [];
|
|
|
25
25
|
// @ts-ignore
|
|
26
26
|
const entities = (domain.data.entities as CollectionEntry<'entities'>[]) || [];
|
|
27
27
|
|
|
28
|
+
const attachments = domain.data.attachments || [];
|
|
29
|
+
|
|
28
30
|
const ubiquitousLanguage = await getUbiquitousLanguage(domain);
|
|
29
31
|
const hasUbiquitousLanguage = ubiquitousLanguage.length > 0;
|
|
30
32
|
const ubiquitousLanguageDictionary = hasUbiquitousLanguage ? ubiquitousLanguage[0].data.dictionary : [];
|
|
@@ -106,6 +108,18 @@ const ownersList = filteredOwners.map((o) => ({
|
|
|
106
108
|
href: buildUrl(`/docs/${o.collection}/${o.data.id}`),
|
|
107
109
|
}));
|
|
108
110
|
|
|
111
|
+
const attachmentsList = attachments.map((a) => {
|
|
112
|
+
const attachmentIsURL = typeof a === 'string';
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
label: attachmentIsURL ? a : (a.title ?? a.url),
|
|
116
|
+
href: attachmentIsURL ? a : a.url,
|
|
117
|
+
icon: attachmentIsURL ? 'ExternalLinkIcon' : (a.icon ?? 'ExternalLinkIcon'),
|
|
118
|
+
target: '_blank' as const,
|
|
119
|
+
subgroup: attachmentIsURL ? undefined : (a.type ?? ''),
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
|
|
109
123
|
const shouldRenderSideBarSection = (section: string) => {
|
|
110
124
|
if (!domain.data.detailsPanel) {
|
|
111
125
|
return true;
|
|
@@ -208,6 +222,17 @@ const shouldRenderSideBarSection = (section: string) => {
|
|
|
208
222
|
<VersionList versions={domain.data.versions} collectionItem={domain} />
|
|
209
223
|
)
|
|
210
224
|
}
|
|
225
|
+
{
|
|
226
|
+
domain.data.attachments && shouldRenderSideBarSection('attachments') && (
|
|
227
|
+
<PillListFlat
|
|
228
|
+
title={`Attachments (${attachmentsList.length})`}
|
|
229
|
+
pills={attachmentsList}
|
|
230
|
+
emptyMessage={`This domain does not have any attachments.`}
|
|
231
|
+
color="pink"
|
|
232
|
+
client:load
|
|
233
|
+
/>
|
|
234
|
+
)
|
|
235
|
+
}
|
|
211
236
|
{
|
|
212
237
|
domain.data.repository && shouldRenderSideBarSection('repository') && (
|
|
213
238
|
<RepositoryList repository={domain.data.repository?.url} language={domain.data.repository?.language} />
|
|
@@ -23,6 +23,19 @@ const services = (entity.data.services as CollectionEntry<'services'>[]) || [];
|
|
|
23
23
|
// @ts-ignore
|
|
24
24
|
const domains = (entity.data.domains as CollectionEntry<'domains'>[]) || [];
|
|
25
25
|
|
|
26
|
+
const attachments = entity.data.attachments || [];
|
|
27
|
+
|
|
28
|
+
const attachmentsList = attachments.map((a) => {
|
|
29
|
+
const attachmentIsURL = typeof a === 'string';
|
|
30
|
+
return {
|
|
31
|
+
label: attachmentIsURL ? a : (a.title ?? a.url),
|
|
32
|
+
href: attachmentIsURL ? a : a.url,
|
|
33
|
+
icon: attachmentIsURL ? 'ExternalLinkIcon' : (a.icon ?? 'ExternalLinkIcon'),
|
|
34
|
+
target: '_blank' as const,
|
|
35
|
+
subgroup: attachmentIsURL ? undefined : (a.type ?? ''),
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
|
|
26
39
|
const ownersList = filteredOwners.map((o) => ({
|
|
27
40
|
label: o.data.name,
|
|
28
41
|
type: o.collection,
|
|
@@ -87,6 +100,17 @@ const shouldRenderSideBarSection = (section: string) => {
|
|
|
87
100
|
<VersionList versions={entity.data.versions} collectionItem={entity} />
|
|
88
101
|
)
|
|
89
102
|
}
|
|
103
|
+
{
|
|
104
|
+
entity.data.attachments && shouldRenderSideBarSection('attachments') && (
|
|
105
|
+
<PillListFlat
|
|
106
|
+
title={`Attachments (${attachmentsList.length})`}
|
|
107
|
+
pills={attachmentsList}
|
|
108
|
+
emptyMessage={`This entity does not have any attachments.`}
|
|
109
|
+
color="pink"
|
|
110
|
+
client:load
|
|
111
|
+
/>
|
|
112
|
+
)
|
|
113
|
+
}
|
|
90
114
|
{
|
|
91
115
|
filteredOwners.length > 0 && shouldRenderSideBarSection('owners') && (
|
|
92
116
|
<OwnersList
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import OwnersList from '@components/Lists/OwnersList';
|
|
3
3
|
import VersionList from '@components/Lists/VersionList.astro';
|
|
4
|
+
import PillListFlat from '@components/Lists/PillListFlat';
|
|
4
5
|
import { buildUrl } from '@utils/url-builder';
|
|
5
6
|
import { getOwner } from '@utils/collections/owners';
|
|
6
7
|
import type { CollectionEntry } from 'astro:content';
|
|
@@ -30,6 +31,19 @@ const ownersList = filteredOwners.map((o) => ({
|
|
|
30
31
|
|
|
31
32
|
const isRSSEnabled = config.rss?.enabled;
|
|
32
33
|
|
|
34
|
+
const attachments = flow.data.attachments || [];
|
|
35
|
+
|
|
36
|
+
const attachmentsList = attachments.map((a) => {
|
|
37
|
+
const attachmentIsURL = typeof a === 'string';
|
|
38
|
+
return {
|
|
39
|
+
label: attachmentIsURL ? a : (a.title ?? a.url),
|
|
40
|
+
href: attachmentIsURL ? a : a.url,
|
|
41
|
+
icon: attachmentIsURL ? 'ExternalLinkIcon' : (a.icon ?? 'ExternalLinkIcon'),
|
|
42
|
+
target: '_blank' as const,
|
|
43
|
+
subgroup: attachmentIsURL ? undefined : (a.type ?? ''),
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
|
|
33
47
|
const shouldRenderSideBarSection = (section: string) => {
|
|
34
48
|
if (!flow.data.detailsPanel) {
|
|
35
49
|
return true;
|
|
@@ -51,6 +65,17 @@ const shouldRenderSideBarSection = (section: string) => {
|
|
|
51
65
|
<VersionList versions={flow.data.versions} collectionItem={flow} />
|
|
52
66
|
)
|
|
53
67
|
}
|
|
68
|
+
{
|
|
69
|
+
flow.data.attachments && shouldRenderSideBarSection('attachments') && (
|
|
70
|
+
<PillListFlat
|
|
71
|
+
title={`Attachments (${attachmentsList.length})`}
|
|
72
|
+
pills={attachmentsList}
|
|
73
|
+
emptyMessage={`This flow does not have any attachments.`}
|
|
74
|
+
color="pink"
|
|
75
|
+
client:load
|
|
76
|
+
/>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
54
79
|
|
|
55
80
|
{
|
|
56
81
|
shouldRenderSideBarSection('owners') && (
|
|
@@ -29,6 +29,19 @@ const filteredOwners = owners.filter((o) => o !== undefined);
|
|
|
29
29
|
|
|
30
30
|
const resourceGroups = message.data?.resourceGroups || [];
|
|
31
31
|
|
|
32
|
+
const attachments = message.data.attachments || [];
|
|
33
|
+
|
|
34
|
+
const attachmentsList = attachments.map((a) => {
|
|
35
|
+
const attachmentIsURL = typeof a === 'string';
|
|
36
|
+
return {
|
|
37
|
+
label: attachmentIsURL ? a : (a.title ?? a.url),
|
|
38
|
+
href: attachmentIsURL ? a : a.url,
|
|
39
|
+
icon: attachmentIsURL ? 'ExternalLinkIcon' : (a.icon ?? 'ExternalLinkIcon'),
|
|
40
|
+
target: '_blank' as const,
|
|
41
|
+
subgroup: attachmentIsURL ? undefined : (a.type ?? ''),
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
|
|
32
45
|
const producerList = producers.map((p) => ({
|
|
33
46
|
label: `${p.data.name}`,
|
|
34
47
|
tag: `v${p.data.version}`,
|
|
@@ -153,6 +166,18 @@ const shouldRenderSideBarSection = (section: string) => {
|
|
|
153
166
|
)
|
|
154
167
|
}
|
|
155
168
|
|
|
169
|
+
{
|
|
170
|
+
message.data.attachments && shouldRenderSideBarSection('attachments') && (
|
|
171
|
+
<PillListFlat
|
|
172
|
+
title={`Attachments (${attachmentsList.length})`}
|
|
173
|
+
pills={attachmentsList}
|
|
174
|
+
emptyMessage={`This ${type} does not have any attachments.`}
|
|
175
|
+
color="pink"
|
|
176
|
+
client:load
|
|
177
|
+
/>
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
|
|
156
181
|
{
|
|
157
182
|
ownersList.length > 0 && shouldRenderSideBarSection('owners') && (
|
|
158
183
|
<OwnersList
|
|
@@ -35,6 +35,19 @@ const resourceGroups = service.data?.resourceGroups || [];
|
|
|
35
35
|
|
|
36
36
|
const domainsServiceBelongsTo = await getDomainsForService(service);
|
|
37
37
|
|
|
38
|
+
const attachments = service.data.attachments || [];
|
|
39
|
+
|
|
40
|
+
const attachmentsList = attachments.map((a) => {
|
|
41
|
+
const attachmentIsURL = typeof a === 'string';
|
|
42
|
+
return {
|
|
43
|
+
label: attachmentIsURL ? a : (a.title ?? a.url),
|
|
44
|
+
href: attachmentIsURL ? a : a.url,
|
|
45
|
+
icon: attachmentIsURL ? 'ExternalLinkIcon' : (a.icon ?? 'ExternalLinkIcon'),
|
|
46
|
+
target: '_blank' as const,
|
|
47
|
+
subgroup: attachmentIsURL ? undefined : (a.type ?? ''),
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
|
|
38
51
|
const sendsList = sends
|
|
39
52
|
.sort((a, b) => a.collection.localeCompare(b.collection))
|
|
40
53
|
.map((p) => ({
|
|
@@ -141,6 +154,18 @@ const shouldRenderSideBarSection = (section: string) => {
|
|
|
141
154
|
)
|
|
142
155
|
}
|
|
143
156
|
|
|
157
|
+
{
|
|
158
|
+
service.data.attachments && shouldRenderSideBarSection('attachments') && (
|
|
159
|
+
<PillListFlat
|
|
160
|
+
title={`Attachments (${attachmentsList.length})`}
|
|
161
|
+
pills={attachmentsList}
|
|
162
|
+
emptyMessage={`This service does not have any attachments.`}
|
|
163
|
+
color="pink"
|
|
164
|
+
client:load
|
|
165
|
+
/>
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
|
|
144
169
|
{
|
|
145
170
|
service.data.specifications && shouldRenderSideBarSection('specifications') && (
|
|
146
171
|
<SpecificationsList collectionItem={service} />
|
|
@@ -147,6 +147,20 @@ const baseSchema = z.object({
|
|
|
147
147
|
])
|
|
148
148
|
.optional(),
|
|
149
149
|
visualiser: z.boolean().optional(),
|
|
150
|
+
attachments: z
|
|
151
|
+
.array(
|
|
152
|
+
z.union([
|
|
153
|
+
z.string().url(), // simple case
|
|
154
|
+
z.object({
|
|
155
|
+
url: z.string().url(),
|
|
156
|
+
title: z.string().optional(),
|
|
157
|
+
type: z.string().optional(), // e.g. "architecture-record", "diagram"
|
|
158
|
+
description: z.string().optional(),
|
|
159
|
+
icon: z.string().optional(),
|
|
160
|
+
}),
|
|
161
|
+
])
|
|
162
|
+
)
|
|
163
|
+
.optional(),
|
|
150
164
|
// Used by eventcatalog
|
|
151
165
|
versions: z.array(z.string()).optional(),
|
|
152
166
|
latestVersion: z.string().optional(),
|
|
@@ -259,6 +273,7 @@ const messageDetailsPanelPropertySchema = z.object({
|
|
|
259
273
|
repository: detailPanelPropertySchema.optional(),
|
|
260
274
|
owners: detailPanelPropertySchema.optional(),
|
|
261
275
|
changelog: detailPanelPropertySchema.optional(),
|
|
276
|
+
attachments: detailPanelPropertySchema.optional(),
|
|
262
277
|
});
|
|
263
278
|
|
|
264
279
|
const events = defineCollection({
|
|
@@ -411,6 +426,7 @@ const domains = defineCollection({
|
|
|
411
426
|
versions: detailPanelPropertySchema.optional(),
|
|
412
427
|
owners: detailPanelPropertySchema.optional(),
|
|
413
428
|
changelog: detailPanelPropertySchema.optional(),
|
|
429
|
+
attachments: detailPanelPropertySchema.optional(),
|
|
414
430
|
})
|
|
415
431
|
.optional(),
|
|
416
432
|
})
|
|
@@ -451,6 +467,7 @@ const channels = defineCollection({
|
|
|
451
467
|
repository: detailPanelPropertySchema.optional(),
|
|
452
468
|
owners: detailPanelPropertySchema.optional(),
|
|
453
469
|
changelog: detailPanelPropertySchema.optional(),
|
|
470
|
+
attachments: detailPanelPropertySchema.optional(),
|
|
454
471
|
})
|
|
455
472
|
.optional(),
|
|
456
473
|
})
|
|
@@ -522,6 +539,7 @@ const entities = defineCollection({
|
|
|
522
539
|
versions: detailPanelPropertySchema.optional(),
|
|
523
540
|
owners: detailPanelPropertySchema.optional(),
|
|
524
541
|
changelog: detailPanelPropertySchema.optional(),
|
|
542
|
+
attachments: detailPanelPropertySchema.optional(),
|
|
525
543
|
})
|
|
526
544
|
.optional(),
|
|
527
545
|
})
|
|
@@ -267,17 +267,37 @@ nodeGraphs.push({
|
|
|
267
267
|
<h2 class="text-lg pt-2 text-gray-500 font-light">{props.data.summary}</h2>
|
|
268
268
|
{
|
|
269
269
|
badges && (
|
|
270
|
-
<div class="flex flex-wrap
|
|
270
|
+
<div class="flex flex-wrap gap-3 py-4">
|
|
271
271
|
{badges.map((badge: any) => {
|
|
272
272
|
return (
|
|
273
|
-
<a href={badge.url || '#'} class="
|
|
273
|
+
<a href={badge.url || '#'} class="group transition-all duration-200 hover:scale-105">
|
|
274
274
|
<span
|
|
275
275
|
id={badge.id || ''}
|
|
276
|
-
class={`
|
|
276
|
+
class={`
|
|
277
|
+
inline-flex items-center gap-2 px-3 py-1.5 rounded-lg text-sm font-medium
|
|
278
|
+
bg-${badge.backgroundColor || 'white'}-50 border border-${badge.backgroundColor || 'gray'}-200
|
|
279
|
+
text-${badge.textColor || 'gray'}-700 shadow-sm
|
|
280
|
+
hover:bg-${badge.backgroundColor || 'purple'}-100 hover:border-${badge.backgroundColor || 'purple'}-300
|
|
281
|
+
hover:shadow-md hover:text-${badge.textColor || 'purple'}-800
|
|
282
|
+
transition-all duration-200 ease-out
|
|
283
|
+
${badge.class ? badge.class : ''}
|
|
284
|
+
`}
|
|
277
285
|
>
|
|
278
|
-
{badge.icon &&
|
|
279
|
-
|
|
280
|
-
|
|
286
|
+
{badge.icon && (
|
|
287
|
+
<badge.icon
|
|
288
|
+
className={`w-4 h-4 flex-shrink-0 text-${badge.textColor || 'gray'}-600 group-hover:text-${badge.textColor || 'purple'}-700 transition-colors duration-200`}
|
|
289
|
+
/>
|
|
290
|
+
)}
|
|
291
|
+
{badge.iconURL && (
|
|
292
|
+
<img
|
|
293
|
+
src={badge.iconURL}
|
|
294
|
+
class="w-4 h-4 flex-shrink-0 opacity-80 group-hover:opacity-100 transition-opacity duration-200"
|
|
295
|
+
alt=""
|
|
296
|
+
/>
|
|
297
|
+
)}
|
|
298
|
+
<span class={`group-hover:text-${badge.textColor || 'purple'}-800 transition-colors duration-200`}>
|
|
299
|
+
{badge.content}
|
|
300
|
+
</span>
|
|
281
301
|
</span>
|
|
282
302
|
</a>
|
|
283
303
|
);
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"url": "https://github.com/event-catalog/eventcatalog.git"
|
|
7
7
|
},
|
|
8
8
|
"type": "module",
|
|
9
|
-
"version": "2.57.
|
|
9
|
+
"version": "2.57.2",
|
|
10
10
|
"publishConfig": {
|
|
11
11
|
"access": "public"
|
|
12
12
|
},
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"@eventcatalog/license": "^0.0.6",
|
|
39
39
|
"@eventcatalog/linter": "^0.0.2",
|
|
40
40
|
"@eventcatalog/sdk": "^2.2.7",
|
|
41
|
-
"@eventcatalog/visualizer": "^0.0.
|
|
41
|
+
"@eventcatalog/visualizer": "^0.0.6",
|
|
42
42
|
"@fontsource/inter": "^5.2.5",
|
|
43
43
|
"@headlessui/react": "^2.0.3",
|
|
44
44
|
"@heroicons/react": "^2.1.3",
|
|
@@ -129,6 +129,7 @@
|
|
|
129
129
|
"prettier": "^3.3.3",
|
|
130
130
|
"prettier-plugin-astro": "^0.14.1",
|
|
131
131
|
"tsup": "^8.1.0",
|
|
132
|
+
"vite": "^7.1.7",
|
|
132
133
|
"vite-tsconfig-paths": "^4.3.2",
|
|
133
134
|
"vitest": "2.1.6"
|
|
134
135
|
},
|