@eventcatalog/core 5.0.0-beta.2 → 5.0.0-beta.20
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/LICENSE +234 -134
- package/README.md +5 -5
- package/dist/analytics/analytics.cjs +18 -3
- package/dist/analytics/analytics.d.cts +1 -1
- package/dist/analytics/analytics.d.ts +1 -1
- package/dist/analytics/analytics.js +3 -2
- package/dist/analytics/log-build.cjs +71 -35
- package/dist/analytics/log-build.js +5 -4
- package/dist/analytics/telemetry.cjs +42 -0
- package/dist/analytics/telemetry.d.cts +20 -0
- package/dist/analytics/telemetry.d.ts +20 -0
- package/dist/analytics/telemetry.js +8 -0
- package/dist/catalog-runtime.cjs +1 -1
- package/dist/{chunk-HGRFXTFC.js → chunk-3VQSVQTU.js} +1 -1
- package/dist/{chunk-KIDISU6X.js → chunk-5ZUN2TXB.js} +56 -33
- package/dist/{chunk-TQLRG35T.js → chunk-AWOO63ME.js} +71 -45
- package/dist/chunk-CPW6G62V.js +17 -0
- package/dist/{chunk-4J2ZM2HX.js → chunk-F236OJZD.js} +1 -1
- package/dist/{chunk-XARPIXWF.js → chunk-FWH5T6U4.js} +9 -3
- package/dist/{chunk-62EV4IJA.js → chunk-R2X4ZEF6.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +214 -129
- package/dist/eventcatalog.config.d.cts +59 -1
- package/dist/eventcatalog.config.d.ts +59 -1
- package/dist/eventcatalog.js +39 -15
- package/dist/federation/federate.js +2 -2
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/runtime-dependencies/@eventcatalog__visualiser__studio-fonts.css.mjs +3 -0
- package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.css.mjs +3 -0
- package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.mjs +3 -0
- package/dist/runtime-dependencies/@hocuspocus__provider.mjs +3 -0
- package/dist/runtime-dependencies/@hocuspocus__server.mjs +3 -0
- package/dist/runtime-dependencies/@mcp-b__webmcp-local-relay.mjs +3 -0
- package/dist/runtime-dependencies/@mcp-b__webmcp-polyfill.mjs +3 -0
- package/dist/runtime-dependencies/htmlparser2.mjs +3 -0
- package/dist/runtime-dependencies/manifest.json +13 -1
- package/dist/runtime-dependencies/react-hotkeys-hook.mjs +3 -0
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__cjs__create-element.js.mjs +3 -0
- package/dist/runtime-dependencies/y-protocols.mjs +3 -0
- package/dist/runtime-dependencies/y-protocols__awareness.mjs +3 -0
- package/dist/runtime-dependencies/yjs.mjs +3 -0
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/dist/utils/license-status.cjs +71 -45
- package/dist/utils/license-status.d.cts +14 -5
- package/dist/utils/license-status.d.ts +14 -5
- package/dist/utils/license-status.js +1 -1
- package/eventcatalog/astro.config.mjs +23 -1
- package/eventcatalog/integrations/skip-startup-reload.mjs +31 -0
- package/eventcatalog/integrations/stable-dependency-order.mjs +29 -0
- package/eventcatalog/integrations/storage.mjs +20 -0
- package/eventcatalog/integrations/studio-server.mjs +32 -0
- package/eventcatalog/src/components/CatalogGraph/CatalogForceGraph.tsx +39 -0
- package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +2 -0
- package/eventcatalog/src/components/Grids/utils.tsx +0 -23
- package/eventcatalog/src/components/Header.astro +3 -3
- package/eventcatalog/src/components/MDX/CodeGroup/CodeGroup.tsx +6 -1
- package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +42 -3
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +5 -1
- package/eventcatalog/src/components/NavigationProgress.astro +7 -0
- package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +2 -0
- package/eventcatalog/src/components/SchemaExplorer/ExamplesViewer.tsx +2 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaCodeModal.tsx +2 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +2 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +12 -4
- package/eventcatalog/src/components/Search/SearchDataLoader.astro +16 -28
- package/eventcatalog/src/components/Search/SearchModal.tsx +2 -10
- package/eventcatalog/src/components/Search/search-utils.ts +26 -0
- package/eventcatalog/src/components/Seo.astro +5 -1
- package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +53 -83
- package/eventcatalog/src/components/SideNav/NestedSideBar/storage.ts +2 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/utils.ts +131 -0
- package/eventcatalog/src/components/SideNav/SideNav.astro +9 -1
- package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +4 -62
- package/eventcatalog/src/components/Tables/Discover/columns.tsx +17 -150
- package/eventcatalog/src/components/Tables/Resources/ResourcesTable.tsx +425 -0
- package/eventcatalog/src/components/Tables/RowActionsMenu.tsx +157 -0
- package/eventcatalog/src/components/Tables/TablePagination.tsx +82 -0
- package/eventcatalog/src/features/ai/chat-api.ts +3 -3
- package/eventcatalog/src/features/auth/error.astro +4 -2
- package/eventcatalog/src/features/auth/login.astro +2 -1
- package/eventcatalog/src/features/auth/middleware/middleware-auth.ts +10 -0
- package/eventcatalog/src/features/auth/unauthorized.astro +1 -1
- package/eventcatalog/src/features/fields/pages/fields.astro +1 -1
- package/eventcatalog/src/features/integrations/eventcatalog-features.ts +34 -1
- package/eventcatalog/src/features/mcp/apps/architecture-diagram/node-chat.tsx +6 -45
- package/eventcatalog/src/features/mcp/apps/canvas/shared.ts +47 -0
- package/eventcatalog/src/features/mcp/apps/canvas/styles.css +24 -0
- package/eventcatalog/src/features/mcp/apps/canvas/view.tsx +278 -0
- package/eventcatalog/src/features/mcp/apps/generated/canvas.html +272 -0
- package/eventcatalog/src/features/mcp/apps/generated/viewer.html +77 -76
- package/eventcatalog/src/features/mcp/apps/shared/app-view.tsx +2 -1
- package/eventcatalog/src/features/mcp/mcp-apps.ts +6 -3
- package/eventcatalog/src/features/mcp/mcp-server.ts +36 -5
- package/eventcatalog/src/features/server/start.ts +25 -0
- package/eventcatalog/src/features/storage/database.ts +88 -0
- package/eventcatalog/src/features/storage/migrations.ts +85 -0
- package/eventcatalog/src/features/storage/sql/database.sql +5 -0
- package/eventcatalog/src/features/storage/sql/migrations/0001-studio-canvases.sql +12 -0
- package/eventcatalog/src/features/storage/sql/migrations.sql +15 -0
- package/eventcatalog/src/features/storage/sql.ts +28 -0
- package/eventcatalog/src/features/studio/agent-choreography.ts +384 -0
- package/eventcatalog/src/features/studio/agents.ts +28 -0
- package/eventcatalog/src/features/studio/api/canvases-api.ts +219 -0
- package/eventcatalog/src/features/studio/api/canvases.ts +25 -0
- package/eventcatalog/src/features/studio/api/client.ts +40 -0
- package/eventcatalog/src/features/studio/canvas-actions.ts +540 -0
- package/eventcatalog/src/features/studio/canvas-preview.ts +52 -0
- package/eventcatalog/src/features/studio/catalog-resources.ts +155 -0
- package/eventcatalog/src/features/studio/catalog.ts +173 -0
- package/eventcatalog/src/features/studio/components/CanvasHeader.tsx +518 -0
- package/eventcatalog/src/features/studio/components/CanvasStatusMenu.tsx +118 -0
- package/eventcatalog/src/features/studio/components/ConnectAgentDialog.tsx +434 -0
- package/eventcatalog/src/features/studio/components/ConnectionsChooser.tsx +143 -0
- package/eventcatalog/src/features/studio/components/DeleteCanvasDialog.tsx +65 -0
- package/eventcatalog/src/features/studio/components/Dialog.tsx +60 -0
- package/eventcatalog/src/features/studio/components/JoinForm.tsx +109 -0
- package/eventcatalog/src/features/studio/components/LeftPanel.tsx +203 -0
- package/eventcatalog/src/features/studio/components/NodeDetails.tsx +183 -0
- package/eventcatalog/src/features/studio/components/OpenInStudioDialog.tsx +79 -0
- package/eventcatalog/src/features/studio/components/Presence.tsx +293 -0
- package/eventcatalog/src/features/studio/components/ShareDialog.tsx +396 -0
- package/eventcatalog/src/features/studio/components/ShortcutsDialog.tsx +41 -0
- package/eventcatalog/src/features/studio/components/StudioDesigner.tsx +2091 -0
- package/eventcatalog/src/features/studio/components/StudioNotice.astro +24 -0
- package/eventcatalog/src/features/studio/document-name.ts +7 -0
- package/eventcatalog/src/features/studio/from-visualiser.ts +138 -0
- package/eventcatalog/src/features/studio/hooks/presence-sender.ts +63 -0
- package/eventcatalog/src/features/studio/hooks/presence-store.ts +119 -0
- package/eventcatalog/src/features/studio/hooks/use-canvas-webmcp.ts +353 -0
- package/eventcatalog/src/features/studio/hooks/use-comments.ts +54 -0
- package/eventcatalog/src/features/studio/hooks/use-follow-camera.ts +109 -0
- package/eventcatalog/src/features/studio/hooks/use-studio-flow.ts +782 -0
- package/eventcatalog/src/features/studio/identity.ts +59 -0
- package/eventcatalog/src/features/studio/limits.ts +2 -0
- package/eventcatalog/src/features/studio/pages/[id].astro +69 -0
- package/eventcatalog/src/features/studio/pages/index.astro +784 -0
- package/eventcatalog/src/features/studio/pages/webmcp-relay.ts +27 -0
- package/eventcatalog/src/features/studio/server/canvas-mcp.ts +495 -0
- package/eventcatalog/src/features/studio/server/runtime.ts +498 -0
- package/eventcatalog/src/features/studio/server/sign-in.ts +18 -0
- package/eventcatalog/src/features/studio/server/sql/storage.sql +18 -0
- package/eventcatalog/src/features/studio/server/storage.ts +90 -0
- package/eventcatalog/src/features/studio/server/tool-icons.ts +30 -0
- package/eventcatalog/src/features/studio/tool-sync.ts +75 -0
- package/eventcatalog/src/layouts/BaseLayout.astro +4 -4
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +13 -7
- package/eventcatalog/src/pages/_index.astro +1 -1
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.spec.ts +52 -63
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +34 -46
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +11 -29
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_ResourcesPage.astro +79 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.spec.ts +32 -14
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.ts +63 -58
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/index.astro +2 -62
- package/eventcatalog/src/pages/docs/[type]/[id]/index.astro +1 -1
- package/eventcatalog/src/pages/docs/services/[id]/[version]/resources/index.astro +13 -0
- package/eventcatalog/src/pages/index.astro +1 -1
- package/eventcatalog/src/pages/schemas/explorer/index.astro +1 -1
- package/eventcatalog/src/pages/visualiser/[type]/[id]/index.astro +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +24 -42
- package/eventcatalog/src/stores/sidebar-store/builders/flow.ts +2 -0
- package/eventcatalog/src/stores/sidebar-store/builders/message.ts +2 -0
- package/eventcatalog/src/stores/sidebar-store/builders/service.ts +23 -23
- package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +13 -0
- package/eventcatalog/src/stores/sidebar-store/builders/system.ts +18 -27
- package/eventcatalog/src/stores/sidebar-store/state.ts +5 -0
- package/eventcatalog/src/styles/tailwind.css +2 -2
- package/eventcatalog/src/types/react-syntax-highlighter.d.ts +10 -0
- package/eventcatalog/src/utils/collections/channels.ts +56 -1
- package/eventcatalog/src/utils/collections/flows.ts +50 -1
- package/eventcatalog/src/utils/collections/message-connections.ts +60 -0
- package/eventcatalog/src/utils/collections/message-triggers.ts +2 -1
- package/eventcatalog/src/utils/collections/resource-owners.ts +193 -0
- package/eventcatalog/src/utils/collections/resources.ts +310 -0
- package/eventcatalog/src/utils/collections/util.ts +31 -0
- package/eventcatalog/src/utils/feature.ts +8 -0
- package/eventcatalog/src/utils/git.ts +11 -5
- package/eventcatalog/src/utils/link-validation.ts +25 -19
- package/eventcatalog/src/utils/node-graphs/domain-entity-map.ts +3 -1
- package/eventcatalog/src/utils/node-graphs/domain-levels-node-graph.ts +3 -3
- package/eventcatalog/src/utils/node-graphs/export-mermaid.ts +0 -2
- package/eventcatalog/src/utils/node-graphs/layout-node-graph.ts +20 -1
- package/eventcatalog/src/utils/node-graphs/node-resource.ts +67 -0
- package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +1 -1
- package/eventcatalog/src/utils/page-title.ts +15 -0
- package/eventcatalog/src/utils/syntax-highlighter-renderer.ts +64 -0
- package/eventcatalog/src/utils/trial.ts +1 -1
- package/package.json +22 -16
- package/dist/runtime-dependencies/shelljs.mjs +0 -3
- package/eventcatalog/public/studio-bg.png +0 -0
- package/eventcatalog/src/components/Grids/DomainGrid.tsx +0 -838
- package/eventcatalog/src/components/Grids/MessageGrid.tsx +0 -344
- package/eventcatalog/src/components/Grids/SystemGrid.tsx +0 -185
- package/eventcatalog/src/components/Grids/components.tsx +0 -170
- package/eventcatalog/src/components/Grids/message-link.ts +0 -38
- package/eventcatalog/src/components/Studio/StudioPageModal.tsx +0 -150
- package/eventcatalog/src/components/Tables/SystemResources/SystemResourcesTable.tsx +0 -294
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_resources.spec.ts +0 -65
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_resources.ts +0 -46
- package/eventcatalog/src/pages/studio.astro +0 -316
- package/dist/{chunk-AYNZXUB5.js → chunk-KHACCTW2.js} +3 -3
|
@@ -37,10 +37,11 @@ __export(license_status_exports, {
|
|
|
37
37
|
});
|
|
38
38
|
module.exports = __toCommonJS(license_status_exports);
|
|
39
39
|
var import_boxen = __toESM(require("boxen"), 1);
|
|
40
|
+
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
40
41
|
var import_license2 = require("@eventcatalog/license");
|
|
41
42
|
|
|
42
43
|
// eventcatalog/src/utils/trial.ts
|
|
43
|
-
var TRIAL_LENGTH_DAYS =
|
|
44
|
+
var TRIAL_LENGTH_DAYS = 60;
|
|
44
45
|
var LICENSE_FAQ_URL = "https://www.eventcatalog.dev/license-faq";
|
|
45
46
|
var LICENSE_RENEW_URL = "https://eventcatalog.cloud";
|
|
46
47
|
var DAY_IN_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -159,75 +160,100 @@ var getLicenseAnalytics = (license = { state: "none" }, tsd) => ({
|
|
|
159
160
|
});
|
|
160
161
|
var formatDate = (date) => date.toLocaleDateString(void 0, { dateStyle: "medium" });
|
|
161
162
|
var formatDays = (days) => `${days} ${days === 1 ? "day" : "days"}`;
|
|
162
|
-
var
|
|
163
|
+
var PLAIN = { bold: (text) => text, dim: (text) => text, link: (text) => text };
|
|
164
|
+
var COLOURS = { bold: import_picocolors.default.bold, dim: import_picocolors.default.dim, link: (text) => import_picocolors.default.cyan(text) };
|
|
165
|
+
var render = ({ headline, rows, links }, colours) => {
|
|
166
|
+
const width = Math.max(0, ...[...rows, ...links].map(([label]) => label.length));
|
|
167
|
+
const row = ([label, value]) => `${colours.dim(label.padEnd(width))} ${value}`;
|
|
168
|
+
return [
|
|
169
|
+
colours.bold(headline),
|
|
170
|
+
...rows.length ? ["", ...rows.map(row)] : [],
|
|
171
|
+
...links.length ? ["", ...links.map(([label, url]) => row([label, colours.link(url)]))] : []
|
|
172
|
+
].join("\n");
|
|
173
|
+
};
|
|
174
|
+
var message = (content) => ({
|
|
175
|
+
...content,
|
|
176
|
+
text: render(content, PLAIN)
|
|
177
|
+
});
|
|
178
|
+
var getTrialRow = (tsd, now) => {
|
|
163
179
|
const trial = getTrialStatus(tsd, now);
|
|
164
180
|
if (!trial) return;
|
|
165
|
-
return
|
|
181
|
+
return [
|
|
182
|
+
"Trial",
|
|
183
|
+
trial.ended ? `Ended ${formatDate(trial.endsAt)}` : `${formatDays(trial.daysLeft)} left of ${TRIAL_LENGTH_DAYS} (ends ${formatDate(trial.endsAt)})`
|
|
184
|
+
];
|
|
166
185
|
};
|
|
167
186
|
var getLicenseStatusMessage = (license, tsd, now = Date.now()) => {
|
|
187
|
+
const licensing = ["Licensing", LICENSE_FAQ_URL];
|
|
188
|
+
const renew = ["Renew", LICENSE_RENEW_URL];
|
|
189
|
+
const licensedTo = "org" in license && license.org ? [["Licensed to", license.org]] : [];
|
|
168
190
|
if (license.state === "licensed") {
|
|
169
191
|
const daysLeft = Math.max(0, Math.ceil((license.expiresAt.getTime() - now) / DAY_IN_MS2));
|
|
170
|
-
const licensedTo = license.org ? `Licensed to ${license.org}` : "Licensed";
|
|
171
192
|
if (daysLeft < LICENSE_REMINDER_DAYS) {
|
|
172
|
-
return {
|
|
173
|
-
title: "EventCatalog
|
|
193
|
+
return message({
|
|
194
|
+
title: "EventCatalog license",
|
|
174
195
|
color: "yellow",
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
].join("\n")
|
|
180
|
-
};
|
|
196
|
+
headline: `Your commercial license expires in ${formatDays(daysLeft)}`,
|
|
197
|
+
rows: [...licensedTo, ["Expires", formatDate(license.expiresAt)]],
|
|
198
|
+
links: [renew]
|
|
199
|
+
});
|
|
181
200
|
}
|
|
182
|
-
return {
|
|
183
|
-
title: "EventCatalog
|
|
201
|
+
return message({
|
|
202
|
+
title: "EventCatalog license",
|
|
184
203
|
color: "green",
|
|
185
|
-
|
|
186
|
-
Valid until
|
|
187
|
-
|
|
204
|
+
headline: "Commercial license active",
|
|
205
|
+
rows: [...licensedTo, ["Valid until", `${formatDate(license.expiresAt)} (${formatDays(daysLeft)} left)`]],
|
|
206
|
+
links: []
|
|
207
|
+
});
|
|
188
208
|
}
|
|
189
209
|
if (license.state === "plan") return;
|
|
190
|
-
const
|
|
210
|
+
const trialRow = getTrialRow(tsd, now);
|
|
211
|
+
const trialRows = trialRow ? [trialRow] : [];
|
|
191
212
|
if (license.state === "none") {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return {
|
|
213
|
+
const trial = getTrialStatus(tsd, now);
|
|
214
|
+
if (!trial || !trialRow) return;
|
|
215
|
+
return message({
|
|
195
216
|
title: "EventCatalog trial",
|
|
196
|
-
color: ended ? "yellow" : "green",
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
217
|
+
color: trial.ended ? "yellow" : "green",
|
|
218
|
+
headline: trial.ended ? "Your EventCatalog trial has ended" : `You're on the ${TRIAL_LENGTH_DAYS}-day EventCatalog trial`,
|
|
219
|
+
rows: trialRows,
|
|
220
|
+
links: trial.ended ? [["Get a license", LICENSE_RENEW_URL], licensing] : [licensing]
|
|
221
|
+
});
|
|
200
222
|
}
|
|
201
223
|
if (license.state === "expired") {
|
|
202
|
-
const expiredOn = license.expiresAt ?
|
|
203
|
-
|
|
204
|
-
|
|
224
|
+
const expiredOn = license.expiresAt ? [
|
|
225
|
+
[
|
|
226
|
+
"Expired",
|
|
227
|
+
`${formatDate(license.expiresAt)} (${formatDays(Math.floor((now - license.expiresAt.getTime()) / DAY_IN_MS2))} ago)`
|
|
228
|
+
]
|
|
229
|
+
] : [];
|
|
230
|
+
return message({
|
|
231
|
+
title: "EventCatalog license",
|
|
205
232
|
color: "yellow",
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
`Learn about licensing: ${LICENSE_FAQ_URL}`
|
|
211
|
-
].filter(Boolean).join("\n")
|
|
212
|
-
};
|
|
233
|
+
headline: "Your commercial license has expired",
|
|
234
|
+
rows: [...licensedTo, ...expiredOn, ...trialRows],
|
|
235
|
+
links: [renew, licensing]
|
|
236
|
+
});
|
|
213
237
|
}
|
|
214
|
-
return {
|
|
238
|
+
return message({
|
|
215
239
|
title: "EventCatalog license",
|
|
216
240
|
color: "yellow",
|
|
217
|
-
|
|
218
|
-
|
|
241
|
+
headline: "Your license.jwt couldn't be verified",
|
|
242
|
+
rows: [["Reason", license.reason.charAt(0).toUpperCase() + license.reason.slice(1)], ...trialRows],
|
|
243
|
+
links: [licensing]
|
|
244
|
+
});
|
|
219
245
|
};
|
|
220
246
|
var printLicenseStatus = (license, tsd) => {
|
|
221
|
-
const
|
|
222
|
-
if (!
|
|
247
|
+
const status = getLicenseStatusMessage(license, tsd);
|
|
248
|
+
if (!status) return;
|
|
223
249
|
console.log(
|
|
224
|
-
(0, import_boxen.default)(
|
|
225
|
-
padding: 1,
|
|
250
|
+
(0, import_boxen.default)(render(status, COLOURS), {
|
|
251
|
+
padding: { top: 1, bottom: 1, left: 2, right: 2 },
|
|
226
252
|
margin: 1,
|
|
227
253
|
borderStyle: "round",
|
|
228
|
-
borderColor:
|
|
229
|
-
title:
|
|
230
|
-
titleAlignment: "
|
|
254
|
+
borderColor: status.color,
|
|
255
|
+
title: status.title,
|
|
256
|
+
titleAlignment: "left"
|
|
231
257
|
})
|
|
232
258
|
);
|
|
233
259
|
};
|
|
@@ -15,14 +15,23 @@ declare const getLicenseAnalytics: (license?: LicenseStatus, tsd?: unknown) => {
|
|
|
15
15
|
licenseExpiry: number | undefined;
|
|
16
16
|
trialExpiry: number | undefined;
|
|
17
17
|
};
|
|
18
|
+
type Row = [label: string, value: string];
|
|
18
19
|
/**
|
|
19
|
-
*
|
|
20
|
+
* What the license box says: a headline, the facts as aligned rows ("Licensed to acme"), and links on their own
|
|
21
|
+
* rows, so it can be read at a glance. `text` is the box's content without colours.
|
|
20
22
|
*/
|
|
21
|
-
|
|
23
|
+
type LicenseStatusMessage = {
|
|
22
24
|
title: string;
|
|
23
|
-
color:
|
|
25
|
+
color: 'green' | 'yellow';
|
|
26
|
+
headline: string;
|
|
27
|
+
rows: Row[];
|
|
28
|
+
links: Row[];
|
|
24
29
|
text: string;
|
|
25
|
-
}
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The license (or trial) box for the terminal. Undefined when there's nothing to show.
|
|
33
|
+
*/
|
|
34
|
+
declare const getLicenseStatusMessage: (license: LicenseStatus, tsd: unknown, now?: number) => LicenseStatusMessage | undefined;
|
|
26
35
|
declare const printLicenseStatus: (license: LicenseStatus, tsd: unknown) => void;
|
|
27
36
|
|
|
28
|
-
export { LicenseStatus, getLicenseAnalytics, getLicenseStatus, getLicenseStatusMessage, printLicenseStatus };
|
|
37
|
+
export { LicenseStatus, type LicenseStatusMessage, getLicenseAnalytics, getLicenseStatus, getLicenseStatusMessage, printLicenseStatus };
|
|
@@ -15,14 +15,23 @@ declare const getLicenseAnalytics: (license?: LicenseStatus, tsd?: unknown) => {
|
|
|
15
15
|
licenseExpiry: number | undefined;
|
|
16
16
|
trialExpiry: number | undefined;
|
|
17
17
|
};
|
|
18
|
+
type Row = [label: string, value: string];
|
|
18
19
|
/**
|
|
19
|
-
*
|
|
20
|
+
* What the license box says: a headline, the facts as aligned rows ("Licensed to acme"), and links on their own
|
|
21
|
+
* rows, so it can be read at a glance. `text` is the box's content without colours.
|
|
20
22
|
*/
|
|
21
|
-
|
|
23
|
+
type LicenseStatusMessage = {
|
|
22
24
|
title: string;
|
|
23
|
-
color:
|
|
25
|
+
color: 'green' | 'yellow';
|
|
26
|
+
headline: string;
|
|
27
|
+
rows: Row[];
|
|
28
|
+
links: Row[];
|
|
24
29
|
text: string;
|
|
25
|
-
}
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The license (or trial) box for the terminal. Undefined when there's nothing to show.
|
|
33
|
+
*/
|
|
34
|
+
declare const getLicenseStatusMessage: (license: LicenseStatus, tsd: unknown, now?: number) => LicenseStatusMessage | undefined;
|
|
26
35
|
declare const printLicenseStatus: (license: LicenseStatus, tsd: unknown) => void;
|
|
27
36
|
|
|
28
|
-
export { LicenseStatus, getLicenseAnalytics, getLicenseStatus, getLicenseStatusMessage, printLicenseStatus };
|
|
37
|
+
export { LicenseStatus, type LicenseStatusMessage, getLicenseAnalytics, getLicenseStatus, getLicenseStatusMessage, printLicenseStatus };
|
|
@@ -27,12 +27,16 @@ import expressiveCode from 'astro-expressive-code';
|
|
|
27
27
|
// preprocessors and the rehype plugin below load those same package defaults.
|
|
28
28
|
import expressiveCodeConfig from './ec.config.mjs';
|
|
29
29
|
import ecstudioWatcher from './integrations/ecstudio-watcher.mjs';
|
|
30
|
+
import storage from './integrations/storage.mjs';
|
|
31
|
+
import studioServer from './integrations/studio-server.mjs';
|
|
30
32
|
import eventCatalogIntegration from './src/features/integrations/eventcatalog-features.ts';
|
|
31
33
|
import eventCatalogRuntime, { getDevServerFileSystem, packageDirectory } from './integrations/eventcatalog-runtime.mjs';
|
|
32
34
|
import config from './src/utils/eventcatalog-config/source.ts';
|
|
33
35
|
import preprocessExpressiveCodeConfig from './integrations/expressive-code-config.mjs';
|
|
34
36
|
import catalogAssets from './integrations/catalog-assets.mjs';
|
|
35
37
|
import runtimeDependencies from './integrations/runtime-dependencies.mjs';
|
|
38
|
+
import stableDependencyOrder from './integrations/stable-dependency-order.mjs';
|
|
39
|
+
import skipStartupReload from './integrations/skip-startup-reload.mjs';
|
|
36
40
|
import { getRuntimePaths } from './integrations/runtime-paths.mjs';
|
|
37
41
|
import { collectClientDependencies } from './integrations/client-dependencies.mjs';
|
|
38
42
|
|
|
@@ -113,6 +117,11 @@ export default defineConfig({
|
|
|
113
117
|
|
|
114
118
|
// just turn this off for all users (for now...)
|
|
115
119
|
devToolbar: { enabled: false },
|
|
120
|
+
build: {
|
|
121
|
+
// Render several pages at once: pages wait on file reads and graph layouts, and a 640-event
|
|
122
|
+
// catalog built in ~40s rather than ~70s, with the same pages and less memory.
|
|
123
|
+
concurrency: 4,
|
|
124
|
+
},
|
|
116
125
|
|
|
117
126
|
// Unused resource types are valid. Astro otherwise warns on every getCollection()
|
|
118
127
|
// call for those empty collections ("check your content config file for errors").
|
|
@@ -139,6 +148,9 @@ export default defineConfig({
|
|
|
139
148
|
catalogAssets({ projectDirectory, generatedDirectory: join(runtimeDirectory, 'public') }),
|
|
140
149
|
effectiveOutput !== 'server' && compress && (await loadAstroCompressIntegration(projectDirectory)),
|
|
141
150
|
ecstudioWatcher(),
|
|
151
|
+
// Before Studio: its database is opened and migrated first
|
|
152
|
+
storage(),
|
|
153
|
+
studioServer(),
|
|
142
154
|
eventCatalogIntegration(),
|
|
143
155
|
linkValidation(config.linkValidation),
|
|
144
156
|
].filter(Boolean),
|
|
@@ -161,6 +173,8 @@ export default defineConfig({
|
|
|
161
173
|
},
|
|
162
174
|
plugins: [
|
|
163
175
|
runtimeDependencies(),
|
|
176
|
+
stableDependencyOrder(),
|
|
177
|
+
skipStartupReload(),
|
|
164
178
|
tailwindcss(),
|
|
165
179
|
...(await eventCatalogLikeC4(projectDirectory)),
|
|
166
180
|
...(config.trailingSlash === true ? [astroTrailingSlashEndpointFix()] : []),
|
|
@@ -219,7 +233,15 @@ export default defineConfig({
|
|
|
219
233
|
},
|
|
220
234
|
optimizeDeps: {
|
|
221
235
|
exclude: [],
|
|
222
|
-
include:
|
|
236
|
+
include: [
|
|
237
|
+
...collectClientDependencies(),
|
|
238
|
+
// <ClientRouter /> imports these from a virtual module the dependency scan can't follow,
|
|
239
|
+
// so without them every cold start re-bundles on the first page and reloads it
|
|
240
|
+
'astro/virtual-modules/transitions-events.js',
|
|
241
|
+
'astro/virtual-modules/transitions-router.js',
|
|
242
|
+
'astro/virtual-modules/transitions-swap-functions.js',
|
|
243
|
+
'astro/virtual-modules/transitions-types.js',
|
|
244
|
+
],
|
|
223
245
|
},
|
|
224
246
|
},
|
|
225
247
|
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Astro writes its content data store as the dev server starts, which sends the browser a
|
|
2
|
+
// full reload. With no browser connected yet, Vite holds that reload and hands it to the
|
|
3
|
+
// first page that connects, so the first page opened after every start loaded twice.
|
|
4
|
+
// A reload sent before any page has been served has nothing to refresh (a tab left open
|
|
5
|
+
// from the previous run reloads itself when it reconnects), so drop those. Once a page has
|
|
6
|
+
// been requested, reloads pass through as usual.
|
|
7
|
+
|
|
8
|
+
const isFullReload = (payload) => typeof payload === 'object' && payload?.type === 'full-reload';
|
|
9
|
+
|
|
10
|
+
export default function skipStartupReload() {
|
|
11
|
+
return {
|
|
12
|
+
name: 'eventcatalog:skip-startup-reload',
|
|
13
|
+
apply: 'serve',
|
|
14
|
+
configureServer(server) {
|
|
15
|
+
let pageRequested = false;
|
|
16
|
+
server.middlewares.use((req, _res, next) => {
|
|
17
|
+
// Browser navigations ask for HTML; the CLI's prewarm request doesn't
|
|
18
|
+
if (!pageRequested && req.headers.accept?.includes('text/html')) pageRequested = true;
|
|
19
|
+
next();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
for (const channel of new Set([server.ws, server.environments?.client?.hot].filter(Boolean))) {
|
|
23
|
+
const send = channel.send.bind(channel);
|
|
24
|
+
channel.send = (...args) => {
|
|
25
|
+
if (!pageRequested && isFullReload(args[0])) return;
|
|
26
|
+
return send(...args);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Astro crawls framework packages with vitefu, which looks them up concurrently and lists
|
|
2
|
+
// each one in `resolve.external` / `resolve.noExternal` as its lookup finishes, so the
|
|
3
|
+
// order changes from one start to the next. Vite hashes these lists unsorted to decide
|
|
4
|
+
// whether its pre-bundled dependencies are still valid, so every `eventcatalog dev` saw a
|
|
5
|
+
// "changed" config and re-bundled all of them. Only membership matters in these lists, so
|
|
6
|
+
// sorting them keeps the hash (and the dependency cache) stable across starts.
|
|
7
|
+
|
|
8
|
+
const byName = (a, b) => {
|
|
9
|
+
const left = String(a);
|
|
10
|
+
const right = String(b);
|
|
11
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const sortResolveLists = (resolve) => {
|
|
15
|
+
if (Array.isArray(resolve?.external)) resolve.external.sort(byName);
|
|
16
|
+
if (Array.isArray(resolve?.noExternal)) resolve.noExternal.sort(byName);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default function stableDependencyOrder() {
|
|
20
|
+
return {
|
|
21
|
+
name: 'eventcatalog:stable-dependency-order',
|
|
22
|
+
apply: 'serve',
|
|
23
|
+
configResolved(config) {
|
|
24
|
+
sortResolveLists(config.resolve);
|
|
25
|
+
sortResolveLists(config.ssr);
|
|
26
|
+
for (const environment of Object.values(config.environments ?? {})) sortResolveLists(environment.resolve);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { startStorage } from '../src/features/storage/database.ts';
|
|
2
|
+
|
|
3
|
+
// The state EventCatalog keeps (`storage` in eventcatalog.config.js): as the dev server starts, its database is opened
|
|
4
|
+
// and brought up to date (migrated), whether or not a feature that uses it is opened. `eventcatalog start` does the
|
|
5
|
+
// same through /_eventcatalog/start.
|
|
6
|
+
export default function storage() {
|
|
7
|
+
return {
|
|
8
|
+
name: 'eventcatalog-storage',
|
|
9
|
+
hooks: {
|
|
10
|
+
'astro:server:setup': async ({ logger }) => {
|
|
11
|
+
try {
|
|
12
|
+
const file = await startStorage();
|
|
13
|
+
if (file) logger.info(`Database ready (${file})`);
|
|
14
|
+
} catch (error) {
|
|
15
|
+
logger.error(`Could not open the database: ${error.message}`);
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { getStudioRuntime } from '../src/features/studio/server/runtime.ts';
|
|
2
|
+
import { isDatabaseTooNew } from '../src/features/storage/migrations.ts';
|
|
3
|
+
import config from '../src/utils/eventcatalog-config/source.ts';
|
|
4
|
+
import { isCanvasEnabled } from '../src/utils/feature.ts';
|
|
5
|
+
|
|
6
|
+
// Collaborative canvases: the collaboration WebSocket (Yjs over Hocuspocus), on the dev server's port.
|
|
7
|
+
// The runtime is shared with server code (e.g. MCP tools) through globalThis.
|
|
8
|
+
export default function studioServer() {
|
|
9
|
+
return {
|
|
10
|
+
name: 'eventcatalog-studio-server',
|
|
11
|
+
hooks: {
|
|
12
|
+
'astro:server:setup': async ({ server, logger }) => {
|
|
13
|
+
if (!isCanvasEnabled() || !server.httpServer) return;
|
|
14
|
+
const runtime = getStudioRuntime();
|
|
15
|
+
const projectDirectory = process.env.PROJECT_DIR || process.cwd();
|
|
16
|
+
// Canvases are loaded from storage before anyone can open one
|
|
17
|
+
try {
|
|
18
|
+
await runtime.useStorage(config.storage, projectDirectory);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
// Not kept in memory instead (changes would quietly stop being saved): Studio's pages say why
|
|
21
|
+
if (isDatabaseTooNew(error)) return logger.error(`Studio isn't available: ${error.message}`);
|
|
22
|
+
logger.error(`Could not use the Studio storage configured, keeping canvases in memory: ${error.message}`);
|
|
23
|
+
await runtime.useStorage({ type: 'memory' }, projectDirectory);
|
|
24
|
+
}
|
|
25
|
+
runtime.attach(server.httpServer);
|
|
26
|
+
const { type, location } = runtime.storage;
|
|
27
|
+
const kept = type === 'memory' ? 'kept in memory until the server restarts' : `stored in ${location}`;
|
|
28
|
+
logger.info(`Collaboration server ready at /_eventcatalog/studio (canvases ${kept})`);
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -170,6 +170,16 @@ const nodeRadius = (degree: number, isHub = false) =>
|
|
|
170
170
|
/** Above this node count, expensive extras (collision force) are disabled. */
|
|
171
171
|
const LARGE_GRAPH_NODE_COUNT = 1500;
|
|
172
172
|
|
|
173
|
+
/**
|
|
174
|
+
* The first layout settles before it paints instead of animating into place for ~5s: ticks
|
|
175
|
+
* run in short slices across frames (no long tasks) until it settles, ~40ms of work for 100
|
|
176
|
+
* nodes. Big catalogs stop once ticking has taken the work limit, paint past their largest
|
|
177
|
+
* moves and animate the rest. The limit counts ticking time, not elapsed time, so a page busy
|
|
178
|
+
* hydrating other islands doesn't cut the settle short.
|
|
179
|
+
*/
|
|
180
|
+
const INITIAL_SETTLE_SLICE_MS = 12;
|
|
181
|
+
const INITIAL_SETTLE_WORK_LIMIT_MS = 400;
|
|
182
|
+
|
|
173
183
|
/** Sprite resolution for node icons (drawn scaled-down, so keep it crisp) */
|
|
174
184
|
const ICON_SPRITE_SIZE = 64;
|
|
175
185
|
|
|
@@ -617,6 +627,10 @@ const CatalogForceGraph = ({
|
|
|
617
627
|
// normal-sized, whatever the lens's usual hubs are
|
|
618
628
|
const isHub = (d: SimNode) => (focusKey ? d.key === focusKey : hubs.has(d.collection));
|
|
619
629
|
|
|
630
|
+
// Later layouts (lens, focus and filter changes) animate from the previous positions
|
|
631
|
+
const isFirstLayout = positionsRef.current.size === 0;
|
|
632
|
+
// Nothing paints until the first layout has settled (see INITIAL_SETTLE_SLICE_MS)
|
|
633
|
+
let settling = isFirstLayout;
|
|
620
634
|
const visibleNodes: SimNode[] = viewNodes
|
|
621
635
|
.filter((n) => !hiddenCollections.has(n.collection))
|
|
622
636
|
.map((n) => ({ ...n, degree: 0, ...positionsRef.current.get(n.key) }));
|
|
@@ -734,6 +748,7 @@ const CatalogForceGraph = ({
|
|
|
734
748
|
};
|
|
735
749
|
|
|
736
750
|
const draw = () => {
|
|
751
|
+
if (settling) return;
|
|
737
752
|
context.save();
|
|
738
753
|
context.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0);
|
|
739
754
|
context.clearRect(0, 0, width, height);
|
|
@@ -1014,6 +1029,29 @@ const CatalogForceGraph = ({
|
|
|
1014
1029
|
);
|
|
1015
1030
|
}
|
|
1016
1031
|
|
|
1032
|
+
// Settle the first layout before it paints rather than animating it into place
|
|
1033
|
+
let settleFrame: number | undefined;
|
|
1034
|
+
if (isFirstLayout) {
|
|
1035
|
+
simulation.stop();
|
|
1036
|
+
let workLeft = INITIAL_SETTLE_WORK_LIMIT_MS;
|
|
1037
|
+
const settle = () => {
|
|
1038
|
+
const sliceStart = performance.now();
|
|
1039
|
+
const sliceEnd = sliceStart + Math.min(INITIAL_SETTLE_SLICE_MS, workLeft);
|
|
1040
|
+
while (simulation.alpha() > simulation.alphaMin() && performance.now() < sliceEnd) simulation.tick();
|
|
1041
|
+
workLeft -= performance.now() - sliceStart;
|
|
1042
|
+
if (simulation.alpha() > simulation.alphaMin() && workLeft > 0) {
|
|
1043
|
+
settleFrame = requestAnimationFrame(settle);
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
settling = false;
|
|
1047
|
+
// Settled: paint it as is (restarting would run one tick more than the animated
|
|
1048
|
+
// layout). Otherwise paint and animate whatever is left.
|
|
1049
|
+
if (simulation.alpha() <= simulation.alphaMin()) fitToView();
|
|
1050
|
+
else simulation.restart();
|
|
1051
|
+
};
|
|
1052
|
+
settleFrame = requestAnimationFrame(settle);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1017
1055
|
const findNode = (canvasX: number, canvasY: number): SimNode | null => {
|
|
1018
1056
|
if (Number.isNaN(canvasX) || Number.isNaN(canvasY)) return null;
|
|
1019
1057
|
const x = transform.invertX(canvasX);
|
|
@@ -1219,6 +1257,7 @@ const CatalogForceGraph = ({
|
|
|
1219
1257
|
for (const node of visibleNodes) {
|
|
1220
1258
|
if (node.x !== undefined && node.y !== undefined) positionsRef.current.set(node.key, { x: node.x, y: node.y });
|
|
1221
1259
|
}
|
|
1260
|
+
if (settleFrame !== undefined) cancelAnimationFrame(settleFrame);
|
|
1222
1261
|
simulation.stop();
|
|
1223
1262
|
// The tooltip outlives this effect — never leave it showing stale content
|
|
1224
1263
|
tooltip.style.opacity = '0';
|
|
@@ -29,6 +29,8 @@ const CHAT_PANEL_STYLES = `
|
|
|
29
29
|
}
|
|
30
30
|
.ec-chat-surface { font-weight: 400; }
|
|
31
31
|
.ec-chat-avatar { background: rgb(var(--ec-accent) / .06); animation: ec-chat-breathe 5s ease-in-out infinite; }
|
|
32
|
+
/* The closed panel stays on the page (off screen): a running animation there still costs every frame */
|
|
33
|
+
.ec-chat-surface[aria-hidden='true'] .ec-chat-avatar { animation-play-state: paused; }
|
|
32
34
|
.ec-chat-suggestion { width: fit-content; max-width: 100%; transition: background 180ms, transform 180ms; }
|
|
33
35
|
.ec-chat-suggestion:hover { transform: translateX(3px); }
|
|
34
36
|
.ec-chat-message { animation: fadeInUp 280ms ease-out both; }
|
|
@@ -24,26 +24,3 @@ export const getCollectionStyles = (collection: CollectionMessageTypes | Collect
|
|
|
24
24
|
return { color: 'gray', Icon: EnvelopeIcon };
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
|
-
|
|
28
|
-
export interface PaginationProps {
|
|
29
|
-
currentPage: number;
|
|
30
|
-
totalPages: number;
|
|
31
|
-
totalItems: number;
|
|
32
|
-
itemsPerPage: number;
|
|
33
|
-
onPageChange: (page: number) => void;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface SearchBarProps {
|
|
37
|
-
searchQuery: string;
|
|
38
|
-
onSearchChange: (query: string) => void;
|
|
39
|
-
placeholder?: string;
|
|
40
|
-
totalResults?: number;
|
|
41
|
-
totalItems?: number;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface TypeFilterProps {
|
|
45
|
-
selectedTypes: CollectionMessageTypes[];
|
|
46
|
-
onTypeChange: (types: CollectionMessageTypes[]) => void;
|
|
47
|
-
filteredCount?: number;
|
|
48
|
-
totalCount?: number;
|
|
49
|
-
}
|
|
@@ -94,16 +94,16 @@ const providerName = user?.provider ? providerNames[user.provider] || user.provi
|
|
|
94
94
|
<img
|
|
95
95
|
src={userImage}
|
|
96
96
|
alt=""
|
|
97
|
-
class="h-
|
|
97
|
+
class="h-7 w-7 rounded-full object-cover ring-1 ring-[rgb(var(--ec-page-border))]"
|
|
98
98
|
/>
|
|
99
99
|
) : (
|
|
100
|
-
<span class="h-
|
|
100
|
+
<span class="h-7 w-7 rounded-full bg-[rgb(var(--ec-accent-subtle))] text-[rgb(var(--ec-accent))] ring-1 ring-[rgb(var(--ec-page-border))] flex items-center justify-center text-[11px] font-semibold">
|
|
101
101
|
{userInitials}
|
|
102
102
|
</span>
|
|
103
103
|
)}
|
|
104
104
|
<svg
|
|
105
105
|
viewBox="0 0 24 24"
|
|
106
|
-
class="h-
|
|
106
|
+
class="h-3.5 w-3.5 transition-transform group-aria-expanded:rotate-180"
|
|
107
107
|
fill="none"
|
|
108
108
|
stroke="currentColor"
|
|
109
109
|
stroke-width="2"
|
|
@@ -167,7 +167,12 @@ export default function CodeGroup({
|
|
|
167
167
|
hidden={index !== active}
|
|
168
168
|
tabIndex={0}
|
|
169
169
|
>
|
|
170
|
-
{
|
|
170
|
+
{/* Astro's router marks scripts in this HTML with data-astro-exec before hydration, so it never matches exactly. */}
|
|
171
|
+
{item.html !== undefined ? (
|
|
172
|
+
<div suppressHydrationWarning dangerouslySetInnerHTML={{ __html: item.html }} />
|
|
173
|
+
) : (
|
|
174
|
+
item.content
|
|
175
|
+
)}
|
|
171
176
|
</div>
|
|
172
177
|
))}
|
|
173
178
|
</div>
|
|
@@ -12,10 +12,16 @@
|
|
|
12
12
|
* CSS ships in the page head and survives ClientRouter navigations (see NodeGraph.astro).
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import { useCallback, lazy, Suspense } from 'react';
|
|
15
|
+
import { useCallback, useState, lazy, Suspense } from 'react';
|
|
16
16
|
import type { Node, Edge } from '@xyflow/react';
|
|
17
|
-
import type { FlowGroupBy } from '@eventcatalog/visualiser';
|
|
17
|
+
import type { FlowGroupBy, OpenInStudioRequest } from '@eventcatalog/visualiser';
|
|
18
18
|
import { buildUrl } from '@utils/url-builder';
|
|
19
|
+
import { createCanvasThroughApi } from '@features/studio/api/client';
|
|
20
|
+
import { getStoredName } from '@features/studio/identity';
|
|
21
|
+
|
|
22
|
+
// Studio's canvas code (what turns a diagram into a canvas, and the dialog asking for its name) is only loaded when a
|
|
23
|
+
// diagram is opened in Studio: every page with a diagram would load it otherwise, with Studio on or not
|
|
24
|
+
const OpenInStudioDialog = lazy(() => import('@features/studio/components/OpenInStudioDialog'));
|
|
19
25
|
|
|
20
26
|
const NodeGraph = lazy(() =>
|
|
21
27
|
import('@eventcatalog/visualiser').then((module) => ({ default: module.NodeGraph }))
|
|
@@ -57,9 +63,11 @@ interface AstroNodeGraphProps {
|
|
|
57
63
|
preferenceScope?: string;
|
|
58
64
|
// Group a flow's steps into swimlanes to start with
|
|
59
65
|
swimlanes?: FlowGroupBy;
|
|
66
|
+
// The Studio API's address, when Studio is on: the menu can then start a canvas from the diagram
|
|
67
|
+
studioApiUrl?: string;
|
|
60
68
|
}
|
|
61
69
|
|
|
62
|
-
const AstroNodeGraph = ({ isDevMode = false, resourceKey, ...otherProps }: AstroNodeGraphProps) => {
|
|
70
|
+
const AstroNodeGraph = ({ isDevMode = false, resourceKey, studioApiUrl, ...otherProps }: AstroNodeGraphProps) => {
|
|
63
71
|
// Astro-specific navigation handler
|
|
64
72
|
const handleNavigate = useCallback((url: string) => {
|
|
65
73
|
// Use window.location for navigation since we can't import astro:transitions/client in a React component
|
|
@@ -108,6 +116,30 @@ const AstroNodeGraph = ({ isDevMode = false, resourceKey, ...otherProps }: Astro
|
|
|
108
116
|
}
|
|
109
117
|
}, []);
|
|
110
118
|
|
|
119
|
+
// Opening the diagram in Studio: asks what to call the canvas, then makes it with what the diagram shows and opens
|
|
120
|
+
// it (in this tab) at the level shown. What it shows is only taken once it's named (laying a level out can take a
|
|
121
|
+
// moment), and anything that goes wrong is shown in the dialog.
|
|
122
|
+
const [toOpen, setToOpen] = useState<OpenInStudioRequest | null>(null);
|
|
123
|
+
const closeOpenInStudio = useCallback(() => setToOpen(null), []);
|
|
124
|
+
const openInStudio = useCallback(
|
|
125
|
+
async (title: string | undefined) => {
|
|
126
|
+
if (!studioApiUrl || !toOpen) return;
|
|
127
|
+
const snapshot = await toOpen.getSnapshot();
|
|
128
|
+
const { canvasFromVisualiser } = await import('@features/studio/from-visualiser');
|
|
129
|
+
const { nodes, edges, levels } = canvasFromVisualiser(snapshot);
|
|
130
|
+
if (nodes.length === 0) throw new Error('Nothing on this diagram can go on a canvas yet');
|
|
131
|
+
const canvas = await createCanvasThroughApi(studioApiUrl, {
|
|
132
|
+
title,
|
|
133
|
+
createdBy: getStoredName() ?? undefined,
|
|
134
|
+
nodes,
|
|
135
|
+
edges,
|
|
136
|
+
levels,
|
|
137
|
+
});
|
|
138
|
+
window.location.assign(snapshot.level === 3 ? canvas.url : `${canvas.url}?level=${snapshot.level}`);
|
|
139
|
+
},
|
|
140
|
+
[studioApiUrl, toOpen]
|
|
141
|
+
);
|
|
142
|
+
|
|
111
143
|
return (
|
|
112
144
|
<Suspense fallback={<div>Loading graph...</div>}>
|
|
113
145
|
<NodeGraph
|
|
@@ -118,7 +150,14 @@ const AstroNodeGraph = ({ isDevMode = false, resourceKey, ...otherProps }: Astro
|
|
|
118
150
|
onBuildUrl={handleBuildUrl}
|
|
119
151
|
onSaveLayout={handleSaveLayout}
|
|
120
152
|
onResetLayout={handleResetLayout}
|
|
153
|
+
onOpenInStudio={studioApiUrl ? setToOpen : undefined}
|
|
121
154
|
/>
|
|
155
|
+
{toOpen && (
|
|
156
|
+
// Its own, so the diagram isn't swapped for "Loading graph..." while the dialog loads
|
|
157
|
+
<Suspense fallback={null}>
|
|
158
|
+
<OpenInStudioDialog title={toOpen.title} onOpen={openInStudio} onClose={closeOpenInStudio} />
|
|
159
|
+
</Suspense>
|
|
160
|
+
)}
|
|
122
161
|
</Suspense>
|
|
123
162
|
);
|
|
124
163
|
};
|