@anyshift/backstage-plugin-anyshift 0.1.0-beta.2 → 0.1.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/README.md +14 -1
  3. package/dist/api/AnyshiftApi.esm.js +61 -7
  4. package/dist/api/AnyshiftApi.esm.js.map +1 -1
  5. package/dist/components/ask/AskAnyshiftCard.esm.js +348 -0
  6. package/dist/components/ask/AskAnyshiftCard.esm.js.map +1 -0
  7. package/dist/components/ask/askPresenters.esm.js +1203 -0
  8. package/dist/components/ask/askPresenters.esm.js.map +1 -0
  9. package/dist/components/ask/askScope.esm.js +27 -0
  10. package/dist/components/ask/askScope.esm.js.map +1 -0
  11. package/dist/components/ask/askSuggestions.esm.js +41 -0
  12. package/dist/components/ask/askSuggestions.esm.js.map +1 -0
  13. package/dist/components/cloud/CloudImpactSection.esm.js +54 -0
  14. package/dist/components/cloud/CloudImpactSection.esm.js.map +1 -0
  15. package/dist/components/cloud/CloudPage.esm.js +104 -0
  16. package/dist/components/cloud/CloudPage.esm.js.map +1 -0
  17. package/dist/components/cloud/CloudRelationshipSections.esm.js +43 -0
  18. package/dist/components/cloud/CloudRelationshipSections.esm.js.map +1 -0
  19. package/dist/components/cloud/CloudResourceContent.esm.js +495 -0
  20. package/dist/components/cloud/CloudResourceContent.esm.js.map +1 -0
  21. package/dist/components/entity/AnyshiftEntityContent.esm.js +128 -23
  22. package/dist/components/entity/AnyshiftEntityContent.esm.js.map +1 -1
  23. package/dist/components/entity/ArchitectureOperationDetails.esm.js +107 -0
  24. package/dist/components/entity/ArchitectureOperationDetails.esm.js.map +1 -0
  25. package/dist/components/entity/BriefSections.esm.js +24 -4
  26. package/dist/components/entity/BriefSections.esm.js.map +1 -1
  27. package/dist/components/entity/DatadogLiveSignal.esm.js +85 -23
  28. package/dist/components/entity/DatadogLiveSignal.esm.js.map +1 -1
  29. package/dist/components/entity/MermaidArchitecture.esm.js +202 -43
  30. package/dist/components/entity/MermaidArchitecture.esm.js.map +1 -1
  31. package/dist/components/entity/SectionPresenters.esm.js +145 -82
  32. package/dist/components/entity/SectionPresenters.esm.js.map +1 -1
  33. package/dist/components/entity/architectureDiagram.esm.js +48 -15
  34. package/dist/components/entity/architectureDiagram.esm.js.map +1 -1
  35. package/dist/components/entity/architectureGraph.esm.js +145 -0
  36. package/dist/components/entity/architectureGraph.esm.js.map +1 -0
  37. package/dist/components/entity/entityIdentity.esm.js +40 -0
  38. package/dist/components/entity/entityIdentity.esm.js.map +1 -0
  39. package/dist/components/entity/relatedCatalogEntities.esm.js +60 -0
  40. package/dist/components/entity/relatedCatalogEntities.esm.js.map +1 -0
  41. package/dist/components/explorer/AnyshiftExplorerPage.esm.js +222 -21
  42. package/dist/components/explorer/AnyshiftExplorerPage.esm.js.map +1 -1
  43. package/dist/components/explorer/DatadogOperationsRadar.esm.js +92 -31
  44. package/dist/components/explorer/DatadogOperationsRadar.esm.js.map +1 -1
  45. package/dist/index.d.ts +26 -102
  46. package/dist/index.esm.js +1 -1
  47. package/dist/package.json.esm.js +10 -10
  48. package/dist/plugin.esm.js +51 -8
  49. package/dist/plugin.esm.js.map +1 -1
  50. package/dist/routes.esm.js +2 -1
  51. package/dist/routes.esm.js.map +1 -1
  52. package/package.json +11 -11
@@ -1,15 +1,15 @@
1
- import { jsxs, jsx } from 'react/jsx-runtime';
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import { Box, Typography, makeStyles } from '@material-ui/core';
3
3
  import { EvidenceDisclosure } from './EvidenceDisclosure.esm.js';
4
4
 
5
5
  const STATE_COPY = {
6
6
  firing: {
7
7
  headline: "Service on fire",
8
- detail: (signal) => `${signal.active} ${signal.active === 1 ? "monitor" : "monitors"} firing now`
8
+ detail: (signal) => `${signal.activeHasMore ? "At least " : ""}${signal.active} ${signal.active === 1 ? "alert" : "alerts"} firing now`
9
9
  },
10
10
  noisy: {
11
11
  headline: "Quiet now \xB7 noisy lately",
12
- detail: () => "No monitor is firing now."
12
+ detail: () => "No alert is firing now."
13
13
  },
14
14
  quiet: {
15
15
  headline: "Quiet",
@@ -17,7 +17,7 @@ const STATE_COPY = {
17
17
  },
18
18
  unavailable: {
19
19
  headline: "Signal unavailable",
20
- detail: () => "No Datadog signal evidence was returned."
20
+ detail: (signal) => signal.partial ? "Operational alert evidence is incomplete." : "No operational alert evidence was returned."
21
21
  }
22
22
  };
23
23
  const STATE_COLORS = {
@@ -87,22 +87,66 @@ const DatadogSignalStripPresenter = ({ data }) => {
87
87
  /* @__PURE__ */ jsx(Typography, { variant: "h6", className: classes.headline, children: copy.headline }),
88
88
  /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", children: compactSummary(signal) })
89
89
  ] }),
90
- signal.partial && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", component: "p", children: "Some Datadog evidence is temporarily unavailable." }),
90
+ signal.partial && /* @__PURE__ */ jsxs(Fragment, { children: [
91
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", component: "p", children: signal.activeHasMore ? "Additional alert rows are available; the loaded count is a lower bound." : "Some operational alert evidence is temporarily unavailable." }),
92
+ /* @__PURE__ */ jsx(AlertCoverage, { signal })
93
+ ] }),
91
94
  /* @__PURE__ */ jsx(EvidenceDisclosure, { data })
92
95
  ] });
93
96
  };
97
+ const AlertCoverage = ({ signal }) => /* @__PURE__ */ jsxs(Fragment, { children: [
98
+ signal.providers.filter((provider) => provider.status !== "available").map((provider) => /* @__PURE__ */ jsxs(
99
+ Typography,
100
+ {
101
+ variant: "caption",
102
+ color: "textSecondary",
103
+ component: "p",
104
+ children: [
105
+ "Alert coverage: ",
106
+ readableProvider(provider.provider),
107
+ " ",
108
+ provider.status,
109
+ "."
110
+ ]
111
+ },
112
+ provider.provider
113
+ )),
114
+ signal.warnings.map((warning) => /* @__PURE__ */ jsxs(
115
+ Typography,
116
+ {
117
+ variant: "caption",
118
+ color: "textSecondary",
119
+ component: "p",
120
+ children: [
121
+ "Alert warning: ",
122
+ warning.message,
123
+ warning.message.endsWith(".") ? "" : "."
124
+ ]
125
+ },
126
+ `${warning.provider ?? "alert"}:${warning.message}`
127
+ ))
128
+ ] });
94
129
  function datadogSignalFrom(data) {
95
130
  const root = recordFrom(data);
96
131
  const alerts = recordFrom(root.alerts);
97
132
  const alertNoise = recordFrom(root.alertNoise);
98
133
  const counts = recordFrom(alertNoise.counts);
99
134
  const alertCause = recordFrom(root.alertCause);
100
- const firingMonitors = uniqueMonitors(recordsFrom(alerts.firing), "firing");
135
+ const providers = providerCoverageFrom(alerts.providers);
136
+ const warnings = warningsFrom(alerts.warnings);
137
+ const activeHasMore = recordFrom(alerts.page).hasMore === true;
138
+ const alertEvidenceIncomplete = alerts.partial === true || activeHasMore || providers.some((provider) => provider.status !== "available") || warnings.length > 0;
139
+ const firingMonitors = uniqueMonitors(
140
+ recordsFrom(alerts.items).filter(
141
+ (record) => textFrom(record, "status") === "firing"
142
+ ),
143
+ "alert"
144
+ );
101
145
  const noisyMonitors = uniqueMonitors(
102
146
  recordsFrom(alertNoise.monitors),
103
147
  "noise"
104
148
  );
105
- const active = numberFrom(alerts.total) ?? firingMonitors.length;
149
+ const active = firingMonitors.length;
106
150
  const fires = numberFrom(counts.totalFires) ?? noisyMonitors.reduce((total, monitor) => total + (monitor.fires ?? 0), 0);
107
151
  const recovers = noisyMonitors.reduce(
108
152
  (total, monitor) => total + (monitor.recovers ?? 0),
@@ -113,8 +157,9 @@ function datadogSignalFrom(data) {
113
157
  const hasEvidence = isRecord(root.alerts) || isRecord(root.alertNoise);
114
158
  const changes = Array.isArray(alertCause.changes) ? alertCause.changes.length : void 0;
115
159
  return {
116
- state: !hasEvidence ? "unavailable" : active > 0 ? "firing" : fires > 0 || flapping > 0 || stuck > 0 ? "noisy" : "quiet",
160
+ state: !hasEvidence ? "unavailable" : active > 0 ? "firing" : alertEvidenceIncomplete ? "unavailable" : fires > 0 || flapping > 0 || stuck > 0 ? "noisy" : "quiet",
117
161
  active,
162
+ activeHasMore,
118
163
  fires,
119
164
  recovers,
120
165
  flapping,
@@ -122,27 +167,44 @@ function datadogSignalFrom(data) {
122
167
  firingMonitors,
123
168
  noisyMonitors,
124
169
  ...changes !== void 0 ? { correlatedChanges: changes } : {},
125
- partial: Array.isArray(root.errors) && root.errors.length > 0
170
+ partial: Array.isArray(root.errors) && root.errors.length > 0 || alertEvidenceIncomplete,
171
+ providers,
172
+ warnings
126
173
  };
127
174
  }
175
+ function providerCoverageFrom(value) {
176
+ return recordsFrom(value).flatMap((provider) => {
177
+ const name = textFrom(provider, "provider");
178
+ const status = textFrom(provider, "status");
179
+ return name && status ? [{ provider: name, status }] : [];
180
+ });
181
+ }
182
+ function warningsFrom(value) {
183
+ return recordsFrom(value).flatMap((warning) => {
184
+ const message = textFrom(warning, "message");
185
+ const provider = textFrom(warning, "provider");
186
+ return message ? [{ message, ...provider ? { provider } : {} }] : [];
187
+ });
188
+ }
189
+ function readableProvider(provider) {
190
+ return provider.charAt(0).toUpperCase() + provider.slice(1);
191
+ }
128
192
  function uniqueMonitors(records, source) {
129
193
  const unique = /* @__PURE__ */ new Map();
130
194
  records.forEach((record) => {
131
- const name = textFrom(record, source === "firing" ? "monitor" : "name");
195
+ const name = textFrom(record, source === "alert" ? "title" : "name");
132
196
  if (!name) return;
197
+ const service = recordFrom(record.service);
133
198
  const monitor = {
134
- key: [
135
- name,
136
- textFrom(record, "state"),
137
- textFrom(record, "service"),
138
- textFrom(record, "workload"),
139
- textFrom(record, "namespace")
140
- ].filter(Boolean).join("|").toLowerCase(),
199
+ key: source === "alert" ? textFrom(record, "id") ?? name.toLowerCase() : [name, textFrom(record, "noiseKind")].filter(Boolean).join("|").toLowerCase(),
141
200
  name,
142
- state: textFrom(record, "state"),
143
- service: textFrom(record, "service"),
144
- workload: textFrom(record, "workload"),
145
- namespace: textFrom(record, "namespace"),
201
+ state: source === "alert" ? textFrom(record, "providerStatus") ?? textFrom(record, "status") : textFrom(record, "state"),
202
+ provider: source === "alert" ? textFrom(record, "provider") : void 0,
203
+ severity: source === "alert" ? textFrom(record, "severity") : void 0,
204
+ providerStatus: source === "alert" ? textFrom(record, "providerStatus") : void 0,
205
+ service: source === "alert" ? textFrom(service, "name") : textFrom(record, "service"),
206
+ workload: source === "alert" ? textFrom(service, "name") : textFrom(record, "workload"),
207
+ namespace: source === "alert" ? textFrom(service, "namespace") : textFrom(record, "namespace"),
146
208
  fires: numberFrom(record.fires),
147
209
  recovers: numberFrom(record.recovers),
148
210
  noiseKind: textFrom(record, "noiseKind")
@@ -154,7 +216,7 @@ function uniqueMonitors(records, source) {
154
216
  function compactSummary(signal) {
155
217
  if (signal.state === "firing") {
156
218
  const summary = [
157
- `${signal.active} ${signal.active === 1 ? "monitor" : "monitors"}`
219
+ `${signal.activeHasMore ? "At least " : ""}${signal.active} ${signal.active === 1 ? "alert" : "alerts"}`
158
220
  ];
159
221
  if (signal.correlatedChanges) {
160
222
  summary.push(
@@ -167,7 +229,7 @@ function compactSummary(signal) {
167
229
  return `${signal.fires} fire \xB7 ${signal.flapping} flapping`;
168
230
  }
169
231
  if (signal.state === "quiet") return "No recent paging noise";
170
- return "No Datadog signal evidence returned";
232
+ return signal.partial ? "Operational alert evidence incomplete" : "No operational alert evidence returned";
171
233
  }
172
234
  function recordFrom(value) {
173
235
  return isRecord(value) ? value : {};
@@ -1 +1 @@
1
- {"version":3,"file":"DatadogLiveSignal.esm.js","sources":["../../../src/components/entity/DatadogLiveSignal.tsx"],"sourcesContent":["import {\n Box,\n Chip,\n Divider,\n Grid,\n Typography,\n makeStyles,\n} from '@material-ui/core';\nimport { EvidenceDisclosure } from './EvidenceDisclosure';\n\ntype SignalState = 'firing' | 'noisy' | 'quiet' | 'unavailable';\n\ninterface SignalMonitor {\n key: string;\n name: string;\n state?: string;\n service?: string;\n workload?: string;\n namespace?: string;\n fires?: number;\n recovers?: number;\n noiseKind?: string;\n}\n\nexport interface DatadogSignal {\n state: SignalState;\n active: number;\n fires: number;\n recovers: number;\n flapping: number;\n stuck: number;\n firingMonitors: SignalMonitor[];\n noisyMonitors: SignalMonitor[];\n correlatedChanges?: number;\n partial: boolean;\n}\n\nconst STATE_COPY: Record<\n SignalState,\n { headline: string; detail: (signal: DatadogSignal) => string }\n> = {\n firing: {\n headline: 'Service on fire',\n detail: signal =>\n `${signal.active} ${\n signal.active === 1 ? 'monitor' : 'monitors'\n } firing now`,\n },\n noisy: {\n headline: 'Quiet now · noisy lately',\n detail: () => 'No monitor is firing now.',\n },\n quiet: {\n headline: 'Quiet',\n detail: () => 'No paging activity in the last 7 days.',\n },\n unavailable: {\n headline: 'Signal unavailable',\n detail: () => 'No Datadog signal evidence was returned.',\n },\n};\n\nconst STATE_COLORS: Record<SignalState, string> = {\n firing: '#d63230',\n noisy: '#d97706',\n quiet: '#238636',\n unavailable: '#6b7280',\n};\n\nconst useStyles = makeStyles(theme => ({\n root: {\n borderLeft: '4px solid',\n paddingLeft: theme.spacing(2),\n },\n eyebrow: {\n color: '#632ca6',\n fontWeight: 700,\n letterSpacing: '0.12em',\n },\n headline: {\n fontWeight: 700,\n letterSpacing: '-0.025em',\n },\n statusDot: {\n width: 10,\n height: 10,\n borderRadius: '50%',\n flex: '0 0 auto',\n },\n metric: {\n minWidth: 92,\n padding: theme.spacing(1, 1.5),\n border: `1px solid ${theme.palette.divider}`,\n borderRadius: theme.shape.borderRadius,\n },\n metricValue: {\n fontWeight: 700,\n fontVariantNumeric: 'tabular-nums',\n },\n monitorRow: {\n padding: theme.spacing(1.25, 0),\n },\n monitorName: {\n overflowWrap: 'anywhere',\n },\n partial: {\n marginTop: theme.spacing(2),\n padding: theme.spacing(1),\n borderRadius: theme.shape.borderRadius,\n backgroundColor: theme.palette.action.hover,\n },\n}));\n\nexport const DatadogLiveSignalPresenter = ({ data }: { data: unknown }) => {\n const classes = useStyles();\n const signal = datadogSignalFrom(data);\n const copy = STATE_COPY[signal.state];\n const color = STATE_COLORS[signal.state];\n const monitors =\n signal.state === 'firing' ? signal.firingMonitors : signal.noisyMonitors;\n\n return (\n <Box className={classes.root} style={{ borderLeftColor: color }}>\n <Grid container spacing={3} alignItems=\"flex-start\">\n <Grid item xs={12} md={5}>\n <Typography variant=\"overline\" className={classes.eyebrow}>\n Datadog · live graph signal\n </Typography>\n <Box display=\"flex\" alignItems=\"center\" gridGap={10}>\n <span\n className={classes.statusDot}\n style={{ backgroundColor: color }}\n aria-hidden=\"true\"\n />\n <Typography variant=\"h4\" className={classes.headline}>\n {copy.headline}\n </Typography>\n </Box>\n <Box mt={0.5}>\n <Typography variant=\"body2\" color=\"textSecondary\">\n {copy.detail(signal)}\n </Typography>\n </Box>\n {signal.correlatedChanges !== undefined &&\n signal.correlatedChanges > 0 && (\n <Box mt={2}>\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label={`${signal.correlatedChanges} correlated ${\n signal.correlatedChanges === 1 ? 'change' : 'changes'\n } · 24h`}\n />\n </Box>\n )}\n </Grid>\n <Grid item xs={12} md={7}>\n <Typography variant=\"overline\" color=\"textSecondary\">\n Last 7 days\n </Typography>\n <Box display=\"flex\" flexWrap=\"wrap\" gridGap={8} mt={0.5}>\n <SignalMetric value={signal.fires} label=\"fire\" classes={classes} />\n <SignalMetric\n value={signal.recovers}\n label=\"recover\"\n classes={classes}\n />\n <SignalMetric\n value={signal.flapping}\n label=\"flapping\"\n classes={classes}\n />\n <SignalMetric\n value={signal.stuck}\n label=\"stuck\"\n classes={classes}\n />\n </Box>\n </Grid>\n </Grid>\n\n {monitors.length > 0 && (\n <Box mt={2}>\n <Divider />\n {monitors.slice(0, 5).map((monitor, index) => (\n <Box key={monitor.key}>\n {index > 0 && <Divider />}\n <Box\n className={classes.monitorRow}\n display=\"flex\"\n justifyContent=\"space-between\"\n alignItems=\"flex-start\"\n gridGap={16}\n >\n <Typography variant=\"subtitle2\" className={classes.monitorName}>\n {monitor.name}\n </Typography>\n <Typography\n variant=\"caption\"\n color=\"textSecondary\"\n style={{ flex: '0 0 auto', textAlign: 'right' }}\n >\n {monitorSummary(monitor, signal.state)}\n </Typography>\n </Box>\n </Box>\n ))}\n </Box>\n )}\n\n {signal.partial && (\n <Typography\n variant=\"caption\"\n color=\"textSecondary\"\n className={classes.partial}\n component=\"p\"\n >\n Some Datadog evidence is temporarily unavailable.\n </Typography>\n )}\n <EvidenceDisclosure data={data} />\n </Box>\n );\n};\n\nexport const DatadogSignalStripPresenter = ({ data }: { data: unknown }) => {\n const classes = useStyles();\n const signal = datadogSignalFrom(data);\n const copy = STATE_COPY[signal.state];\n const color = STATE_COLORS[signal.state];\n\n return (\n <Box px={2} py={1.5} style={{ borderLeft: `4px solid ${color}` }}>\n <Box display=\"flex\" flexWrap=\"wrap\" alignItems=\"center\" gridGap={8}>\n <span\n className={classes.statusDot}\n style={{ backgroundColor: color }}\n aria-hidden=\"true\"\n />\n <Typography variant=\"h6\" className={classes.headline}>\n {copy.headline}\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n {compactSummary(signal)}\n </Typography>\n </Box>\n {signal.partial && (\n <Typography variant=\"caption\" color=\"textSecondary\" component=\"p\">\n Some Datadog evidence is temporarily unavailable.\n </Typography>\n )}\n <EvidenceDisclosure data={data} />\n </Box>\n );\n};\n\nconst SignalMetric = ({\n value,\n label,\n classes,\n}: {\n value: number;\n label: string;\n classes: ReturnType<typeof useStyles>;\n}) => (\n <Box className={classes.metric}>\n <Typography variant=\"subtitle2\" className={classes.metricValue}>\n {value} {label}\n </Typography>\n </Box>\n);\n\nexport function datadogSignalFrom(data: unknown): DatadogSignal {\n const root = recordFrom(data);\n const alerts = recordFrom(root.alerts);\n const alertNoise = recordFrom(root.alertNoise);\n const counts = recordFrom(alertNoise.counts);\n const alertCause = recordFrom(root.alertCause);\n const firingMonitors = uniqueMonitors(recordsFrom(alerts.firing), 'firing');\n const noisyMonitors = uniqueMonitors(\n recordsFrom(alertNoise.monitors),\n 'noise',\n );\n const active = numberFrom(alerts.total) ?? firingMonitors.length;\n const fires =\n numberFrom(counts.totalFires) ??\n noisyMonitors.reduce((total, monitor) => total + (monitor.fires ?? 0), 0);\n const recovers = noisyMonitors.reduce(\n (total, monitor) => total + (monitor.recovers ?? 0),\n 0,\n );\n const flapping =\n numberFrom(counts.flapping) ??\n noisyMonitors.filter(monitor => monitor.noiseKind === 'flapping').length;\n const stuck =\n numberFrom(counts.stuck) ??\n noisyMonitors.filter(monitor => monitor.noiseKind === 'stuck').length;\n const hasEvidence = isRecord(root.alerts) || isRecord(root.alertNoise);\n const changes = Array.isArray(alertCause.changes)\n ? alertCause.changes.length\n : undefined;\n\n return {\n state: !hasEvidence\n ? 'unavailable'\n : active > 0\n ? 'firing'\n : fires > 0 || flapping > 0 || stuck > 0\n ? 'noisy'\n : 'quiet',\n active,\n fires,\n recovers,\n flapping,\n stuck,\n firingMonitors,\n noisyMonitors,\n ...(changes !== undefined ? { correlatedChanges: changes } : {}),\n partial: Array.isArray(root.errors) && root.errors.length > 0,\n };\n}\n\nfunction uniqueMonitors(\n records: Array<Record<string, unknown>>,\n source: 'firing' | 'noise',\n): SignalMonitor[] {\n const unique = new Map<string, SignalMonitor>();\n records.forEach(record => {\n const name = textFrom(record, source === 'firing' ? 'monitor' : 'name');\n if (!name) return;\n const monitor: SignalMonitor = {\n key: [\n name,\n textFrom(record, 'state'),\n textFrom(record, 'service'),\n textFrom(record, 'workload'),\n textFrom(record, 'namespace'),\n ]\n .filter(Boolean)\n .join('|')\n .toLowerCase(),\n name,\n state: textFrom(record, 'state'),\n service: textFrom(record, 'service'),\n workload: textFrom(record, 'workload'),\n namespace: textFrom(record, 'namespace'),\n fires: numberFrom(record.fires),\n recovers: numberFrom(record.recovers),\n noiseKind: textFrom(record, 'noiseKind'),\n };\n if (!unique.has(monitor.key)) unique.set(monitor.key, monitor);\n });\n return [...unique.values()];\n}\n\nfunction monitorSummary(monitor: SignalMonitor, state: SignalState): string {\n if (state === 'firing') {\n return [\n monitor.state,\n monitor.workload || monitor.service,\n monitor.namespace,\n ]\n .filter(Boolean)\n .join(' · ');\n }\n return [\n `${monitor.fires ?? 0} fire / ${monitor.recovers ?? 0} recover`,\n monitor.noiseKind,\n ]\n .filter(Boolean)\n .join(' · ');\n}\n\nfunction compactSummary(signal: DatadogSignal): string {\n if (signal.state === 'firing') {\n const summary = [\n `${signal.active} ${signal.active === 1 ? 'monitor' : 'monitors'}`,\n ];\n if (signal.correlatedChanges) {\n summary.push(\n `${signal.correlatedChanges} correlated ${\n signal.correlatedChanges === 1 ? 'change' : 'changes'\n }`,\n );\n }\n return summary.join(' · ');\n }\n if (signal.state === 'noisy') {\n return `${signal.fires} fire · ${signal.flapping} flapping`;\n }\n if (signal.state === 'quiet') return 'No recent paging noise';\n return 'No Datadog signal evidence returned';\n}\n\nfunction recordFrom(value: unknown): Record<string, unknown> {\n return isRecord(value) ? value : {};\n}\n\nfunction recordsFrom(value: unknown): Array<Record<string, unknown>> {\n return Array.isArray(value) ? value.filter(isRecord) : [];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction numberFrom(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value)\n ? value\n : undefined;\n}\n\nfunction textFrom(\n value: Record<string, unknown>,\n key: string,\n): string | undefined {\n const candidate = value[key];\n return typeof candidate === 'string' && candidate.trim()\n ? candidate.trim()\n : undefined;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DatadogLiveSignal.esm.js","sources":["../../../src/components/entity/DatadogLiveSignal.tsx"],"sourcesContent":["import {\n Box,\n Chip,\n Divider,\n Grid,\n Typography,\n makeStyles,\n} from '@material-ui/core';\nimport { EvidenceDisclosure } from './EvidenceDisclosure';\n\ntype SignalState = 'firing' | 'noisy' | 'quiet' | 'unavailable';\n\ninterface SignalMonitor {\n key: string;\n name: string;\n provider?: string;\n severity?: string;\n providerStatus?: string;\n state?: string;\n service?: string;\n workload?: string;\n namespace?: string;\n fires?: number;\n recovers?: number;\n noiseKind?: string;\n}\n\ninterface SignalProviderCoverage {\n provider: string;\n status: string;\n}\n\ninterface SignalWarning {\n message: string;\n provider?: string;\n}\n\nexport interface DatadogSignal {\n state: SignalState;\n active: number;\n activeHasMore: boolean;\n fires: number;\n recovers: number;\n flapping: number;\n stuck: number;\n firingMonitors: SignalMonitor[];\n noisyMonitors: SignalMonitor[];\n correlatedChanges?: number;\n partial: boolean;\n providers: SignalProviderCoverage[];\n warnings: SignalWarning[];\n}\n\nconst STATE_COPY: Record<\n SignalState,\n { headline: string; detail: (signal: DatadogSignal) => string }\n> = {\n firing: {\n headline: 'Service on fire',\n detail: signal =>\n `${signal.activeHasMore ? 'At least ' : ''}${signal.active} ${\n signal.active === 1 ? 'alert' : 'alerts'\n } firing now`,\n },\n noisy: {\n headline: 'Quiet now · noisy lately',\n detail: () => 'No alert is firing now.',\n },\n quiet: {\n headline: 'Quiet',\n detail: () => 'No paging activity in the last 7 days.',\n },\n unavailable: {\n headline: 'Signal unavailable',\n detail: signal =>\n signal.partial\n ? 'Operational alert evidence is incomplete.'\n : 'No operational alert evidence was returned.',\n },\n};\n\nconst STATE_COLORS: Record<SignalState, string> = {\n firing: '#d63230',\n noisy: '#d97706',\n quiet: '#238636',\n unavailable: '#6b7280',\n};\n\nconst useStyles = makeStyles(theme => ({\n root: {\n borderLeft: '4px solid',\n paddingLeft: theme.spacing(2),\n },\n eyebrow: {\n color: '#632ca6',\n fontWeight: 700,\n letterSpacing: '0.12em',\n },\n headline: {\n fontWeight: 700,\n letterSpacing: '-0.025em',\n },\n statusDot: {\n width: 10,\n height: 10,\n borderRadius: '50%',\n flex: '0 0 auto',\n },\n metric: {\n minWidth: 92,\n padding: theme.spacing(1, 1.5),\n border: `1px solid ${theme.palette.divider}`,\n borderRadius: theme.shape.borderRadius,\n },\n metricValue: {\n fontWeight: 700,\n fontVariantNumeric: 'tabular-nums',\n },\n monitorRow: {\n padding: theme.spacing(1.25, 0),\n },\n monitorName: {\n overflowWrap: 'anywhere',\n },\n partial: {\n marginTop: theme.spacing(2),\n padding: theme.spacing(1),\n borderRadius: theme.shape.borderRadius,\n backgroundColor: theme.palette.action.hover,\n },\n}));\n\nexport const DatadogLiveSignalPresenter = ({ data }: { data: unknown }) => {\n const classes = useStyles();\n const signal = datadogSignalFrom(data);\n const copy = STATE_COPY[signal.state];\n const color = STATE_COLORS[signal.state];\n const monitors =\n signal.state === 'firing' ? signal.firingMonitors : signal.noisyMonitors;\n\n return (\n <Box className={classes.root} style={{ borderLeftColor: color }}>\n <Grid container spacing={3} alignItems=\"flex-start\">\n <Grid item xs={12} md={5}>\n <Typography variant=\"overline\" className={classes.eyebrow}>\n Operational alerts · live graph signal\n </Typography>\n <Box display=\"flex\" alignItems=\"center\" gridGap={10}>\n <span\n className={classes.statusDot}\n style={{ backgroundColor: color }}\n aria-hidden=\"true\"\n />\n <Typography variant=\"h4\" className={classes.headline}>\n {copy.headline}\n </Typography>\n </Box>\n <Box mt={0.5}>\n <Typography variant=\"body2\" color=\"textSecondary\">\n {copy.detail(signal)}\n </Typography>\n </Box>\n {signal.correlatedChanges !== undefined &&\n signal.correlatedChanges > 0 && (\n <Box mt={2}>\n <Chip\n size=\"small\"\n variant=\"outlined\"\n label={`${signal.correlatedChanges} correlated ${\n signal.correlatedChanges === 1 ? 'change' : 'changes'\n } · 24h`}\n />\n </Box>\n )}\n </Grid>\n <Grid item xs={12} md={7}>\n <Typography variant=\"overline\" color=\"textSecondary\">\n Last 7 days\n </Typography>\n <Box display=\"flex\" flexWrap=\"wrap\" gridGap={8} mt={0.5}>\n <SignalMetric value={signal.fires} label=\"fire\" classes={classes} />\n <SignalMetric\n value={signal.recovers}\n label=\"recover\"\n classes={classes}\n />\n <SignalMetric\n value={signal.flapping}\n label=\"flapping\"\n classes={classes}\n />\n <SignalMetric\n value={signal.stuck}\n label=\"stuck\"\n classes={classes}\n />\n </Box>\n </Grid>\n </Grid>\n\n {monitors.length > 0 && (\n <Box mt={2}>\n <Divider />\n {monitors.slice(0, 5).map((monitor, index) => (\n <Box key={monitor.key}>\n {index > 0 && <Divider />}\n <Box\n className={classes.monitorRow}\n display=\"flex\"\n justifyContent=\"space-between\"\n alignItems=\"flex-start\"\n gridGap={16}\n >\n <Typography variant=\"subtitle2\" className={classes.monitorName}>\n {monitor.name}\n </Typography>\n <Typography\n variant=\"caption\"\n color=\"textSecondary\"\n style={{ flex: '0 0 auto', textAlign: 'right' }}\n >\n {monitorSummary(monitor, signal.state)}\n </Typography>\n </Box>\n </Box>\n ))}\n </Box>\n )}\n\n {signal.partial && (\n <>\n <Typography\n variant=\"caption\"\n color=\"textSecondary\"\n className={classes.partial}\n component=\"p\"\n >\n {signal.activeHasMore\n ? 'Additional alert rows are available; the loaded count is a lower bound.'\n : 'Some operational alert evidence is temporarily unavailable.'}\n </Typography>\n <AlertCoverage signal={signal} />\n </>\n )}\n <EvidenceDisclosure data={data} />\n </Box>\n );\n};\n\nexport const DatadogSignalStripPresenter = ({ data }: { data: unknown }) => {\n const classes = useStyles();\n const signal = datadogSignalFrom(data);\n const copy = STATE_COPY[signal.state];\n const color = STATE_COLORS[signal.state];\n\n return (\n <Box px={2} py={1.5} style={{ borderLeft: `4px solid ${color}` }}>\n <Box display=\"flex\" flexWrap=\"wrap\" alignItems=\"center\" gridGap={8}>\n <span\n className={classes.statusDot}\n style={{ backgroundColor: color }}\n aria-hidden=\"true\"\n />\n <Typography variant=\"h6\" className={classes.headline}>\n {copy.headline}\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n {compactSummary(signal)}\n </Typography>\n </Box>\n {signal.partial && (\n <>\n <Typography variant=\"caption\" color=\"textSecondary\" component=\"p\">\n {signal.activeHasMore\n ? 'Additional alert rows are available; the loaded count is a lower bound.'\n : 'Some operational alert evidence is temporarily unavailable.'}\n </Typography>\n <AlertCoverage signal={signal} />\n </>\n )}\n <EvidenceDisclosure data={data} />\n </Box>\n );\n};\n\nconst AlertCoverage = ({ signal }: { signal: DatadogSignal }) => (\n <>\n {signal.providers\n .filter(provider => provider.status !== 'available')\n .map(provider => (\n <Typography\n key={provider.provider}\n variant=\"caption\"\n color=\"textSecondary\"\n component=\"p\"\n >\n Alert coverage: {readableProvider(provider.provider)}{' '}\n {provider.status}.\n </Typography>\n ))}\n {signal.warnings.map(warning => (\n <Typography\n key={`${warning.provider ?? 'alert'}:${warning.message}`}\n variant=\"caption\"\n color=\"textSecondary\"\n component=\"p\"\n >\n Alert warning: {warning.message}\n {warning.message.endsWith('.') ? '' : '.'}\n </Typography>\n ))}\n </>\n);\n\nconst SignalMetric = ({\n value,\n label,\n classes,\n}: {\n value: number;\n label: string;\n classes: ReturnType<typeof useStyles>;\n}) => (\n <Box className={classes.metric}>\n <Typography variant=\"subtitle2\" className={classes.metricValue}>\n {value} {label}\n </Typography>\n </Box>\n);\n\nexport function datadogSignalFrom(data: unknown): DatadogSignal {\n const root = recordFrom(data);\n const alerts = recordFrom(root.alerts);\n const alertNoise = recordFrom(root.alertNoise);\n const counts = recordFrom(alertNoise.counts);\n const alertCause = recordFrom(root.alertCause);\n const providers = providerCoverageFrom(alerts.providers);\n const warnings = warningsFrom(alerts.warnings);\n const activeHasMore = recordFrom(alerts.page).hasMore === true;\n const alertEvidenceIncomplete =\n alerts.partial === true ||\n activeHasMore ||\n providers.some(provider => provider.status !== 'available') ||\n warnings.length > 0;\n const firingMonitors = uniqueMonitors(\n recordsFrom(alerts.items).filter(\n record => textFrom(record, 'status') === 'firing',\n ),\n 'alert',\n );\n const noisyMonitors = uniqueMonitors(\n recordsFrom(alertNoise.monitors),\n 'noise',\n );\n const active = firingMonitors.length;\n const fires =\n numberFrom(counts.totalFires) ??\n noisyMonitors.reduce((total, monitor) => total + (monitor.fires ?? 0), 0);\n const recovers = noisyMonitors.reduce(\n (total, monitor) => total + (monitor.recovers ?? 0),\n 0,\n );\n const flapping =\n numberFrom(counts.flapping) ??\n noisyMonitors.filter(monitor => monitor.noiseKind === 'flapping').length;\n const stuck =\n numberFrom(counts.stuck) ??\n noisyMonitors.filter(monitor => monitor.noiseKind === 'stuck').length;\n const hasEvidence = isRecord(root.alerts) || isRecord(root.alertNoise);\n const changes = Array.isArray(alertCause.changes)\n ? alertCause.changes.length\n : undefined;\n\n return {\n state: !hasEvidence\n ? 'unavailable'\n : active > 0\n ? 'firing'\n : alertEvidenceIncomplete\n ? 'unavailable'\n : fires > 0 || flapping > 0 || stuck > 0\n ? 'noisy'\n : 'quiet',\n active,\n activeHasMore,\n fires,\n recovers,\n flapping,\n stuck,\n firingMonitors,\n noisyMonitors,\n ...(changes !== undefined ? { correlatedChanges: changes } : {}),\n partial:\n (Array.isArray(root.errors) && root.errors.length > 0) ||\n alertEvidenceIncomplete,\n providers,\n warnings,\n };\n}\n\nfunction providerCoverageFrom(value: unknown): SignalProviderCoverage[] {\n return recordsFrom(value).flatMap(provider => {\n const name = textFrom(provider, 'provider');\n const status = textFrom(provider, 'status');\n return name && status ? [{ provider: name, status }] : [];\n });\n}\n\nfunction warningsFrom(value: unknown): SignalWarning[] {\n return recordsFrom(value).flatMap(warning => {\n const message = textFrom(warning, 'message');\n const provider = textFrom(warning, 'provider');\n return message ? [{ message, ...(provider ? { provider } : {}) }] : [];\n });\n}\n\nfunction readableProvider(provider: string): string {\n return provider.charAt(0).toUpperCase() + provider.slice(1);\n}\n\nfunction uniqueMonitors(\n records: Array<Record<string, unknown>>,\n source: 'alert' | 'noise',\n): SignalMonitor[] {\n const unique = new Map<string, SignalMonitor>();\n records.forEach(record => {\n const name = textFrom(record, source === 'alert' ? 'title' : 'name');\n if (!name) return;\n const service = recordFrom(record.service);\n const monitor: SignalMonitor = {\n key:\n source === 'alert'\n ? textFrom(record, 'id') ?? name.toLowerCase()\n : [name, textFrom(record, 'noiseKind')]\n .filter(Boolean)\n .join('|')\n .toLowerCase(),\n name,\n state:\n source === 'alert'\n ? textFrom(record, 'providerStatus') ?? textFrom(record, 'status')\n : textFrom(record, 'state'),\n provider: source === 'alert' ? textFrom(record, 'provider') : undefined,\n severity: source === 'alert' ? textFrom(record, 'severity') : undefined,\n providerStatus:\n source === 'alert' ? textFrom(record, 'providerStatus') : undefined,\n service:\n source === 'alert'\n ? textFrom(service, 'name')\n : textFrom(record, 'service'),\n workload:\n source === 'alert'\n ? textFrom(service, 'name')\n : textFrom(record, 'workload'),\n namespace:\n source === 'alert'\n ? textFrom(service, 'namespace')\n : textFrom(record, 'namespace'),\n fires: numberFrom(record.fires),\n recovers: numberFrom(record.recovers),\n noiseKind: textFrom(record, 'noiseKind'),\n };\n if (!unique.has(monitor.key)) unique.set(monitor.key, monitor);\n });\n return [...unique.values()];\n}\n\nfunction monitorSummary(monitor: SignalMonitor, state: SignalState): string {\n if (state === 'firing') {\n return [\n monitor.provider,\n monitor.severity,\n monitor.providerStatus ?? monitor.state,\n monitor.workload || monitor.service,\n monitor.namespace,\n ]\n .filter(Boolean)\n .join(' · ');\n }\n return [\n `${monitor.fires ?? 0} fire / ${monitor.recovers ?? 0} recover`,\n monitor.noiseKind,\n ]\n .filter(Boolean)\n .join(' · ');\n}\n\nfunction compactSummary(signal: DatadogSignal): string {\n if (signal.state === 'firing') {\n const summary = [\n `${signal.activeHasMore ? 'At least ' : ''}${signal.active} ${\n signal.active === 1 ? 'alert' : 'alerts'\n }`,\n ];\n if (signal.correlatedChanges) {\n summary.push(\n `${signal.correlatedChanges} correlated ${\n signal.correlatedChanges === 1 ? 'change' : 'changes'\n }`,\n );\n }\n return summary.join(' · ');\n }\n if (signal.state === 'noisy') {\n return `${signal.fires} fire · ${signal.flapping} flapping`;\n }\n if (signal.state === 'quiet') return 'No recent paging noise';\n return signal.partial\n ? 'Operational alert evidence incomplete'\n : 'No operational alert evidence returned';\n}\n\nfunction recordFrom(value: unknown): Record<string, unknown> {\n return isRecord(value) ? value : {};\n}\n\nfunction recordsFrom(value: unknown): Array<Record<string, unknown>> {\n return Array.isArray(value) ? value.filter(isRecord) : [];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction numberFrom(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value)\n ? value\n : undefined;\n}\n\nfunction textFrom(\n value: Record<string, unknown>,\n key: string,\n): string | undefined {\n const candidate = value[key];\n return typeof candidate === 'string' && candidate.trim()\n ? candidate.trim()\n : undefined;\n}\n"],"names":[],"mappings":"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"}
@@ -1,47 +1,114 @@
1
- import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { Box, CircularProgress, Typography } from '@material-ui/core';
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { Box, CircularProgress, Typography, makeStyles } from '@material-ui/core';
3
3
  import mermaid from 'mermaid';
4
4
  import { useMemo, useRef, useState, useEffect } from 'react';
5
5
  import { buildArchitectureDiagram } from './architectureDiagram.esm.js';
6
+ import { operationPreview, ArchitectureOperationDetails } from './ArchitectureOperationDetails.esm.js';
6
7
 
7
8
  let diagramSequence = 0;
8
9
  let mermaidInitialized = false;
9
- const RelationshipFallback = ({
10
- relationships
11
- }) => /* @__PURE__ */ jsxs(Box, { mt: 2, children: [
12
- /* @__PURE__ */ jsx(Typography, { color: "error", variant: "body2", role: "alert", children: "The architecture diagram could not be drawn. Showing relationships instead." }),
13
- /* @__PURE__ */ jsx(
14
- Box,
15
- {
16
- component: "ul",
17
- m: 0,
18
- mt: 1,
19
- p: 0,
20
- "aria-label": "Architecture relationships",
21
- children: relationships.map((relationship) => /* @__PURE__ */ jsx(
22
- Box,
23
- {
24
- component: "li",
25
- py: 0.5,
26
- style: { listStyle: "none" },
27
- children: /* @__PURE__ */ jsx(Typography, { variant: "body2", children: relationship })
28
- },
29
- relationship
30
- ))
10
+ const useStyles = makeStyles((theme) => ({
11
+ diagram: {
12
+ "& .anyshift-http-edge-affordance": {
13
+ cursor: "pointer"
14
+ },
15
+ "& .anyshift-http-edge-affordance:focus": {
16
+ outline: `2px solid ${theme.palette.text.primary}`,
17
+ outlineOffset: 2
18
+ },
19
+ "& .edgeLabel.anyshift-http-edge-affordance rect": {
20
+ rx: 4,
21
+ ry: 4,
22
+ stroke: theme.palette.divider,
23
+ strokeWidth: 1
24
+ }
25
+ },
26
+ fallbackButton: {
27
+ appearance: "none",
28
+ background: "transparent",
29
+ border: 0,
30
+ color: "inherit",
31
+ cursor: "pointer",
32
+ font: "inherit",
33
+ padding: 0,
34
+ textAlign: "left",
35
+ "&:focus": {
36
+ outline: `2px solid ${theme.palette.text.primary}`,
37
+ outlineOffset: 2
31
38
  }
32
- )
33
- ] });
39
+ }
40
+ }));
41
+ const hasUsableOperations = (relationship) => relationship.operationCount > 0 && operationPreview(relationship) !== "";
42
+ const RelationshipFallback = ({
43
+ relationships,
44
+ onSelect,
45
+ selectedId
46
+ }) => {
47
+ const classes = useStyles();
48
+ return /* @__PURE__ */ jsxs(Box, { mt: 2, children: [
49
+ /* @__PURE__ */ jsx(Typography, { color: "error", variant: "body2", role: "alert", children: "The architecture diagram could not be drawn. Showing relationships instead." }),
50
+ /* @__PURE__ */ jsx(
51
+ Box,
52
+ {
53
+ component: "ul",
54
+ m: 0,
55
+ mt: 1,
56
+ p: 0,
57
+ "aria-label": "Architecture relationships",
58
+ children: relationships.map((relationship) => /* @__PURE__ */ jsx(
59
+ Box,
60
+ {
61
+ component: "li",
62
+ py: 0.5,
63
+ style: { listStyle: "none" },
64
+ children: hasUsableOperations(relationship) ? /* @__PURE__ */ jsx(
65
+ "button",
66
+ {
67
+ "aria-label": `Show HTTP operations for ${relationship.fromLabel} to ${relationship.toLabel}`,
68
+ "aria-expanded": selectedId === relationship.id,
69
+ className: classes.fallbackButton,
70
+ onClick: () => onSelect(relationship),
71
+ type: "button",
72
+ children: /* @__PURE__ */ jsx(Typography, { component: "span", variant: "body2", children: relationship.label })
73
+ }
74
+ ) : /* @__PURE__ */ jsx(Typography, { variant: "body2", children: relationship.label })
75
+ },
76
+ relationship.id
77
+ ))
78
+ }
79
+ )
80
+ ] });
81
+ };
34
82
  const ArchitectureDiagram = ({
35
83
  graph,
36
84
  view = "runtime"
37
85
  }) => {
86
+ const classes = useStyles();
38
87
  const definition = useMemo(
39
88
  () => buildArchitectureDiagram(graph, { view }),
40
89
  [graph, view]
41
90
  );
42
91
  const diagramId = useRef(`anyshift-architecture-${diagramSequence++}`);
92
+ const diagramRef = useRef(null);
43
93
  const [svg, setSvg] = useState();
44
94
  const [renderFailed, setRenderFailed] = useState(false);
95
+ const [selectedId, setSelectedId] = useState();
96
+ const [previewId, setPreviewId] = useState();
97
+ const operationRelationships = useMemo(
98
+ () => definition.relationships.filter(hasUsableOperations),
99
+ [definition.relationships]
100
+ );
101
+ const relationshipsById = useMemo(
102
+ () => new Map(
103
+ operationRelationships.map((relationship) => [
104
+ relationship.id,
105
+ relationship
106
+ ])
107
+ ),
108
+ [operationRelationships]
109
+ );
110
+ const selectedRelationship = selectedId ? relationshipsById.get(selectedId) : void 0;
111
+ const previewRelationship = previewId ? relationshipsById.get(previewId) : void 0;
45
112
  useEffect(() => {
46
113
  let active = true;
47
114
  setSvg(void 0);
@@ -64,25 +131,117 @@ const ArchitectureDiagram = ({
64
131
  active = false;
65
132
  };
66
133
  }, [definition.source]);
67
- if (renderFailed) {
68
- return /* @__PURE__ */ jsx(RelationshipFallback, { relationships: definition.fallbackRelationships });
69
- }
70
- if (!svg) {
71
- return /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", gridGap: 8, py: 3, children: [
134
+ useEffect(() => {
135
+ if (selectedId && !relationshipsById.has(selectedId)) {
136
+ setSelectedId(void 0);
137
+ }
138
+ if (previewId && !relationshipsById.has(previewId)) {
139
+ setPreviewId(void 0);
140
+ }
141
+ }, [previewId, relationshipsById, selectedId]);
142
+ useEffect(() => {
143
+ if (!svg || !diagramRef.current) return;
144
+ const edgePaths = diagramRef.current.querySelectorAll(".edgePath");
145
+ const edgeLabels = diagramRef.current.querySelectorAll(".edgeLabel");
146
+ operationRelationships.forEach((relationship) => {
147
+ const ariaLabel = `HTTP operations for ${relationship.fromLabel} to ${relationship.toLabel}`;
148
+ [
149
+ edgePaths.item(relationship.diagramIndex),
150
+ edgeLabels.item(relationship.diagramIndex)
151
+ ].forEach((element) => {
152
+ if (!(element instanceof HTMLElement || element instanceof SVGElement)) {
153
+ return;
154
+ }
155
+ element.dataset.anyshiftEdgeId = relationship.id;
156
+ element.setAttribute("role", "button");
157
+ element.setAttribute("tabindex", "0");
158
+ element.setAttribute("aria-label", ariaLabel);
159
+ element.setAttribute(
160
+ "aria-expanded",
161
+ String(selectedId === relationship.id)
162
+ );
163
+ element.classList.add("anyshift-http-edge-affordance");
164
+ });
165
+ });
166
+ }, [operationRelationships, selectedId, svg]);
167
+ const relationshipFromTarget = (target) => {
168
+ if (!(target instanceof Element)) return void 0;
169
+ const edge = target.closest("[data-anyshift-edge-id]");
170
+ const id = edge?.dataset.anyshiftEdgeId;
171
+ return id ? relationshipsById.get(id) : void 0;
172
+ };
173
+ const selectRelationship = (target) => {
174
+ const relationship = relationshipFromTarget(target);
175
+ if (relationship) setSelectedId(relationship.id);
176
+ };
177
+ const handleKeyDown = (event) => {
178
+ if (event.key === "Enter" || event.key === " ") {
179
+ const relationship = relationshipFromTarget(event.target);
180
+ if (relationship) {
181
+ event.preventDefault();
182
+ setSelectedId(relationship.id);
183
+ }
184
+ }
185
+ if (event.key === "Escape") setSelectedId(void 0);
186
+ };
187
+ const handleMouseOver = (event) => {
188
+ const relationship = relationshipFromTarget(event.target);
189
+ if (relationship) setPreviewId(relationship.id);
190
+ };
191
+ const handleMouseOut = (event) => {
192
+ const relationship = relationshipFromTarget(event.target);
193
+ const nextRelationship = relationshipFromTarget(event.relatedTarget);
194
+ if (relationship && relationship.id !== nextRelationship?.id) {
195
+ setPreviewId(void 0);
196
+ }
197
+ };
198
+ const handleFocus = (event) => {
199
+ const relationship = relationshipFromTarget(event.target);
200
+ if (relationship) setPreviewId(relationship.id);
201
+ };
202
+ const handleBlur = (event) => {
203
+ const relationship = relationshipFromTarget(event.target);
204
+ const nextRelationship = relationshipFromTarget(event.relatedTarget);
205
+ if (relationship && relationship.id !== nextRelationship?.id) {
206
+ setPreviewId(void 0);
207
+ }
208
+ };
209
+ return /* @__PURE__ */ jsxs(Box, { onKeyDown: handleKeyDown, children: [
210
+ renderFailed ? /* @__PURE__ */ jsx(
211
+ RelationshipFallback,
212
+ {
213
+ relationships: definition.relationships,
214
+ onSelect: (relationship) => setSelectedId(relationship.id),
215
+ selectedId
216
+ }
217
+ ) : !svg ? /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", gridGap: 8, py: 3, children: [
72
218
  /* @__PURE__ */ jsx(CircularProgress, { size: 18 }),
73
219
  /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", children: "Drawing architecture\u2026" })
74
- ] });
75
- }
76
- return /* @__PURE__ */ jsx(
77
- Box,
78
- {
79
- "aria-label": "C4 architecture diagram",
80
- role: "img",
81
- mt: 1,
82
- style: { overflowX: "auto" },
83
- dangerouslySetInnerHTML: { __html: svg }
84
- }
85
- );
220
+ ] }) : /* @__PURE__ */ jsx(
221
+ Box,
222
+ {
223
+ "aria-label": "C4 architecture diagram",
224
+ className: classes.diagram,
225
+ onBlur: handleBlur,
226
+ onClick: (event) => selectRelationship(event.target),
227
+ onFocus: handleFocus,
228
+ onMouseOut: handleMouseOut,
229
+ onMouseOver: handleMouseOver,
230
+ role: "group",
231
+ mt: 1,
232
+ style: { overflowX: "auto" },
233
+ children: /* @__PURE__ */ jsx("div", { ref: diagramRef, dangerouslySetInnerHTML: { __html: svg } })
234
+ }
235
+ ),
236
+ previewRelationship && /* @__PURE__ */ jsx(Typography, { role: "tooltip", variant: "caption", color: "textSecondary", children: operationPreview(previewRelationship) }),
237
+ selectedRelationship && /* @__PURE__ */ jsx(Box, { mt: 2, children: /* @__PURE__ */ jsx(
238
+ ArchitectureOperationDetails,
239
+ {
240
+ relationship: selectedRelationship,
241
+ onClose: () => setSelectedId(void 0)
242
+ }
243
+ ) })
244
+ ] });
86
245
  };
87
246
 
88
247
  export { ArchitectureDiagram };
@@ -1 +1 @@
1
- {"version":3,"file":"MermaidArchitecture.esm.js","sources":["../../../src/components/entity/MermaidArchitecture.tsx"],"sourcesContent":["import { Box, CircularProgress, Typography } from '@material-ui/core';\nimport mermaid from 'mermaid';\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n buildArchitectureDiagram,\n type ArchitectureGraph,\n} from './architectureDiagram';\n\nlet diagramSequence = 0;\nlet mermaidInitialized = false;\n\nconst RelationshipFallback = ({\n relationships,\n}: {\n relationships: string[];\n}) => (\n <Box mt={2}>\n <Typography color=\"error\" variant=\"body2\" role=\"alert\">\n The architecture diagram could not be drawn. Showing relationships\n instead.\n </Typography>\n <Box\n component=\"ul\"\n m={0}\n mt={1}\n p={0}\n aria-label=\"Architecture relationships\"\n >\n {relationships.map(relationship => (\n <Box\n component=\"li\"\n key={relationship}\n py={0.5}\n style={{ listStyle: 'none' }}\n >\n <Typography variant=\"body2\">{relationship}</Typography>\n </Box>\n ))}\n </Box>\n </Box>\n);\n\nexport const ArchitectureDiagram = ({\n graph,\n view = 'runtime',\n}: {\n graph: ArchitectureGraph;\n view?: 'context' | 'runtime';\n}) => {\n const definition = useMemo(\n () => buildArchitectureDiagram(graph, { view }),\n [graph, view],\n );\n const diagramId = useRef(`anyshift-architecture-${diagramSequence++}`);\n const [svg, setSvg] = useState<string>();\n const [renderFailed, setRenderFailed] = useState(false);\n\n useEffect(() => {\n let active = true;\n setSvg(undefined);\n setRenderFailed(false);\n\n if (!mermaidInitialized) {\n mermaid.initialize({\n startOnLoad: false,\n securityLevel: 'strict',\n theme: 'base',\n flowchart: { htmlLabels: false, curve: 'basis' },\n });\n mermaidInitialized = true;\n }\n\n Promise.resolve()\n .then(() => mermaid.render(diagramId.current, definition.source))\n .then(result => {\n if (active) setSvg(result.svg);\n })\n .catch(() => {\n if (active) setRenderFailed(true);\n });\n\n return () => {\n active = false;\n };\n }, [definition.source]);\n\n if (renderFailed) {\n return (\n <RelationshipFallback relationships={definition.fallbackRelationships} />\n );\n }\n\n if (!svg) {\n return (\n <Box display=\"flex\" alignItems=\"center\" gridGap={8} py={3}>\n <CircularProgress size={18} />\n <Typography variant=\"body2\" color=\"textSecondary\">\n Drawing architecture…\n </Typography>\n </Box>\n );\n }\n\n return (\n <Box\n aria-label=\"C4 architecture diagram\"\n role=\"img\"\n mt={1}\n style={{ overflowX: 'auto' }}\n dangerouslySetInnerHTML={{ __html: svg }}\n />\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MermaidArchitecture.esm.js","sources":["../../../src/components/entity/MermaidArchitecture.tsx"],"sourcesContent":["import {\n Box,\n CircularProgress,\n Typography,\n makeStyles,\n} from '@material-ui/core';\nimport mermaid from 'mermaid';\nimport {\n type FocusEvent,\n type KeyboardEvent,\n type MouseEvent,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n buildArchitectureDiagram,\n type ArchitectureGraph,\n type ArchitectureDiagramRelationship,\n} from './architectureDiagram';\nimport {\n ArchitectureOperationDetails,\n operationPreview,\n} from './ArchitectureOperationDetails';\n\nlet diagramSequence = 0;\nlet mermaidInitialized = false;\n\nconst useStyles = makeStyles(theme => ({\n diagram: {\n '& .anyshift-http-edge-affordance': {\n cursor: 'pointer',\n },\n '& .anyshift-http-edge-affordance:focus': {\n outline: `2px solid ${theme.palette.text.primary}`,\n outlineOffset: 2,\n },\n '& .edgeLabel.anyshift-http-edge-affordance rect': {\n rx: 4,\n ry: 4,\n stroke: theme.palette.divider,\n strokeWidth: 1,\n },\n },\n fallbackButton: {\n appearance: 'none',\n background: 'transparent',\n border: 0,\n color: 'inherit',\n cursor: 'pointer',\n font: 'inherit',\n padding: 0,\n textAlign: 'left',\n '&:focus': {\n outline: `2px solid ${theme.palette.text.primary}`,\n outlineOffset: 2,\n },\n },\n}));\n\nconst hasUsableOperations = (\n relationship: ArchitectureDiagramRelationship,\n): boolean =>\n relationship.operationCount > 0 && operationPreview(relationship) !== '';\n\nconst RelationshipFallback = ({\n relationships,\n onSelect,\n selectedId,\n}: {\n relationships: ArchitectureDiagramRelationship[];\n onSelect: (relationship: ArchitectureDiagramRelationship) => void;\n selectedId?: string;\n}) => {\n const classes = useStyles();\n return (\n <Box mt={2}>\n <Typography color=\"error\" variant=\"body2\" role=\"alert\">\n The architecture diagram could not be drawn. Showing relationships\n instead.\n </Typography>\n <Box\n component=\"ul\"\n m={0}\n mt={1}\n p={0}\n aria-label=\"Architecture relationships\"\n >\n {relationships.map(relationship => (\n <Box\n component=\"li\"\n key={relationship.id}\n py={0.5}\n style={{ listStyle: 'none' }}\n >\n {hasUsableOperations(relationship) ? (\n <button\n aria-label={`Show HTTP operations for ${relationship.fromLabel} to ${relationship.toLabel}`}\n aria-expanded={selectedId === relationship.id}\n className={classes.fallbackButton}\n onClick={() => onSelect(relationship)}\n type=\"button\"\n >\n <Typography component=\"span\" variant=\"body2\">\n {relationship.label}\n </Typography>\n </button>\n ) : (\n <Typography variant=\"body2\">{relationship.label}</Typography>\n )}\n </Box>\n ))}\n </Box>\n </Box>\n );\n};\n\nexport const ArchitectureDiagram = ({\n graph,\n view = 'runtime',\n}: {\n graph: ArchitectureGraph;\n view?: 'context' | 'runtime';\n}) => {\n const classes = useStyles();\n const definition = useMemo(\n () => buildArchitectureDiagram(graph, { view }),\n [graph, view],\n );\n const diagramId = useRef(`anyshift-architecture-${diagramSequence++}`);\n const diagramRef = useRef<HTMLDivElement>(null);\n const [svg, setSvg] = useState<string>();\n const [renderFailed, setRenderFailed] = useState(false);\n const [selectedId, setSelectedId] = useState<string>();\n const [previewId, setPreviewId] = useState<string>();\n const operationRelationships = useMemo(\n () => definition.relationships.filter(hasUsableOperations),\n [definition.relationships],\n );\n const relationshipsById = useMemo(\n () =>\n new Map(\n operationRelationships.map(relationship => [\n relationship.id,\n relationship,\n ]),\n ),\n [operationRelationships],\n );\n const selectedRelationship = selectedId\n ? relationshipsById.get(selectedId)\n : undefined;\n const previewRelationship = previewId\n ? relationshipsById.get(previewId)\n : undefined;\n\n useEffect(() => {\n let active = true;\n setSvg(undefined);\n setRenderFailed(false);\n\n if (!mermaidInitialized) {\n mermaid.initialize({\n startOnLoad: false,\n securityLevel: 'strict',\n theme: 'base',\n flowchart: { htmlLabels: false, curve: 'basis' },\n });\n mermaidInitialized = true;\n }\n\n Promise.resolve()\n .then(() => mermaid.render(diagramId.current, definition.source))\n .then(result => {\n if (active) setSvg(result.svg);\n })\n .catch(() => {\n if (active) setRenderFailed(true);\n });\n\n return () => {\n active = false;\n };\n }, [definition.source]);\n\n useEffect(() => {\n if (selectedId && !relationshipsById.has(selectedId)) {\n setSelectedId(undefined);\n }\n if (previewId && !relationshipsById.has(previewId)) {\n setPreviewId(undefined);\n }\n }, [previewId, relationshipsById, selectedId]);\n\n useEffect(() => {\n if (!svg || !diagramRef.current) return;\n\n const edgePaths = diagramRef.current.querySelectorAll('.edgePath');\n const edgeLabels = diagramRef.current.querySelectorAll('.edgeLabel');\n operationRelationships.forEach(relationship => {\n const ariaLabel = `HTTP operations for ${relationship.fromLabel} to ${relationship.toLabel}`;\n [\n edgePaths.item(relationship.diagramIndex),\n edgeLabels.item(relationship.diagramIndex),\n ].forEach(element => {\n if (\n !(element instanceof HTMLElement || element instanceof SVGElement)\n ) {\n return;\n }\n element.dataset.anyshiftEdgeId = relationship.id;\n element.setAttribute('role', 'button');\n element.setAttribute('tabindex', '0');\n element.setAttribute('aria-label', ariaLabel);\n element.setAttribute(\n 'aria-expanded',\n String(selectedId === relationship.id),\n );\n element.classList.add('anyshift-http-edge-affordance');\n });\n });\n }, [operationRelationships, selectedId, svg]);\n\n const relationshipFromTarget = (target: EventTarget | null) => {\n if (!(target instanceof Element)) return undefined;\n const edge = target.closest<HTMLElement>('[data-anyshift-edge-id]');\n const id = edge?.dataset.anyshiftEdgeId;\n return id ? relationshipsById.get(id) : undefined;\n };\n\n const selectRelationship = (target: EventTarget | null) => {\n const relationship = relationshipFromTarget(target);\n if (relationship) setSelectedId(relationship.id);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n const relationship = relationshipFromTarget(event.target);\n if (relationship) {\n event.preventDefault();\n setSelectedId(relationship.id);\n }\n }\n if (event.key === 'Escape') setSelectedId(undefined);\n };\n\n const handleMouseOver = (event: MouseEvent<HTMLElement>) => {\n const relationship = relationshipFromTarget(event.target);\n if (relationship) setPreviewId(relationship.id);\n };\n\n const handleMouseOut = (event: MouseEvent<HTMLElement>) => {\n const relationship = relationshipFromTarget(event.target);\n const nextRelationship = relationshipFromTarget(event.relatedTarget);\n if (relationship && relationship.id !== nextRelationship?.id) {\n setPreviewId(undefined);\n }\n };\n\n const handleFocus = (event: FocusEvent<HTMLElement>) => {\n const relationship = relationshipFromTarget(event.target);\n if (relationship) setPreviewId(relationship.id);\n };\n\n const handleBlur = (event: FocusEvent<HTMLElement>) => {\n const relationship = relationshipFromTarget(event.target);\n const nextRelationship = relationshipFromTarget(event.relatedTarget);\n if (relationship && relationship.id !== nextRelationship?.id) {\n setPreviewId(undefined);\n }\n };\n\n return (\n <Box onKeyDown={handleKeyDown}>\n {renderFailed ? (\n <RelationshipFallback\n relationships={definition.relationships}\n onSelect={relationship => setSelectedId(relationship.id)}\n selectedId={selectedId}\n />\n ) : !svg ? (\n <Box display=\"flex\" alignItems=\"center\" gridGap={8} py={3}>\n <CircularProgress size={18} />\n <Typography variant=\"body2\" color=\"textSecondary\">\n Drawing architecture…\n </Typography>\n </Box>\n ) : (\n <Box\n aria-label=\"C4 architecture diagram\"\n className={classes.diagram}\n onBlur={handleBlur}\n onClick={event => selectRelationship(event.target)}\n onFocus={handleFocus}\n onMouseOut={handleMouseOut}\n onMouseOver={handleMouseOver}\n role=\"group\"\n mt={1}\n style={{ overflowX: 'auto' }}\n >\n <div ref={diagramRef} dangerouslySetInnerHTML={{ __html: svg }} />\n </Box>\n )}\n {previewRelationship && (\n <Typography role=\"tooltip\" variant=\"caption\" color=\"textSecondary\">\n {operationPreview(previewRelationship)}\n </Typography>\n )}\n {selectedRelationship && (\n <Box mt={2}>\n <ArchitectureOperationDetails\n relationship={selectedRelationship}\n onClose={() => setSelectedId(undefined)}\n />\n </Box>\n )}\n </Box>\n );\n};\n"],"names":[],"mappings":"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"}