@diagrammo/dgmo 0.5.3 → 0.5.5
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/README.md +16 -16
- package/dist/cli.cjs +158 -158
- package/dist/index.cjs +762 -318
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -23
- package/dist/index.d.ts +37 -23
- package/dist/index.js +761 -318
- package/dist/index.js.map +1 -1
- package/docs/language-reference.md +20 -2
- package/package.json +1 -1
- package/src/d3.ts +236 -204
- package/src/index.ts +3 -0
- package/src/infra/compute.ts +88 -10
- package/src/infra/layout.ts +97 -12
- package/src/infra/parser.ts +47 -4
- package/src/infra/renderer.ts +216 -42
- package/src/infra/roles.ts +15 -0
- package/src/infra/types.ts +7 -0
- package/src/initiative-status/collapse.ts +76 -0
- package/src/initiative-status/layout.ts +193 -26
- package/src/initiative-status/renderer.ts +94 -46
- package/src/org/layout.ts +5 -2
- package/src/org/renderer.ts +65 -11
- package/src/org/resolver.ts +1 -1
- package/src/sharing.ts +12 -0
package/dist/index.js
CHANGED
|
@@ -6861,7 +6861,10 @@ var init_types2 = __esm({
|
|
|
6861
6861
|
"buffer",
|
|
6862
6862
|
"drain-rate",
|
|
6863
6863
|
"retention-hours",
|
|
6864
|
-
"partitions"
|
|
6864
|
+
"partitions",
|
|
6865
|
+
"slo-availability",
|
|
6866
|
+
"slo-p90-latency-ms",
|
|
6867
|
+
"slo-warning-margin"
|
|
6865
6868
|
]);
|
|
6866
6869
|
EDGE_ONLY_KEYS = /* @__PURE__ */ new Set(["rps"]);
|
|
6867
6870
|
}
|
|
@@ -6997,6 +7000,18 @@ function parseInfra(content) {
|
|
|
6997
7000
|
result.options["default-uptime"] = trimmed.replace(/^default-uptime\s*:\s*/i, "").trim();
|
|
6998
7001
|
continue;
|
|
6999
7002
|
}
|
|
7003
|
+
if (/^slo-availability\s*:/i.test(trimmed)) {
|
|
7004
|
+
result.options["slo-availability"] = trimmed.replace(/^slo-availability\s*:\s*/i, "").trim();
|
|
7005
|
+
continue;
|
|
7006
|
+
}
|
|
7007
|
+
if (/^slo-p90-latency-ms\s*:/i.test(trimmed)) {
|
|
7008
|
+
result.options["slo-p90-latency-ms"] = trimmed.replace(/^slo-p90-latency-ms\s*:\s*/i, "").trim();
|
|
7009
|
+
continue;
|
|
7010
|
+
}
|
|
7011
|
+
if (/^slo-warning-margin\s*:/i.test(trimmed)) {
|
|
7012
|
+
result.options["slo-warning-margin"] = trimmed.replace(/^slo-warning-margin\s*:\s*/i, "").trim();
|
|
7013
|
+
continue;
|
|
7014
|
+
}
|
|
7000
7015
|
if (/^scenario\s*:/i.test(trimmed)) {
|
|
7001
7016
|
finishCurrentNode();
|
|
7002
7017
|
finishCurrentTagGroup();
|
|
@@ -7141,12 +7156,19 @@ function parseInfra(content) {
|
|
|
7141
7156
|
if (simpleConn) {
|
|
7142
7157
|
const targetName = simpleConn[1].trim();
|
|
7143
7158
|
const splitStr = simpleConn[2];
|
|
7159
|
+
const fanoutStr = simpleConn[3];
|
|
7144
7160
|
const split = splitStr ? parseFloat(splitStr) : null;
|
|
7161
|
+
const fanoutRaw = fanoutStr ? parseInt(fanoutStr, 10) : null;
|
|
7162
|
+
if (fanoutRaw !== null && fanoutRaw < 1) {
|
|
7163
|
+
warn(lineNumber, `Fan-out multiplier must be at least 1 (got x${fanoutRaw}). Ignoring.`);
|
|
7164
|
+
}
|
|
7165
|
+
const fanout = fanoutRaw !== null && fanoutRaw >= 1 ? fanoutRaw : null;
|
|
7145
7166
|
result.edges.push({
|
|
7146
7167
|
sourceId: currentNode.id,
|
|
7147
7168
|
targetId: nodeId2(targetName),
|
|
7148
7169
|
label: "",
|
|
7149
7170
|
split,
|
|
7171
|
+
fanout,
|
|
7150
7172
|
lineNumber
|
|
7151
7173
|
});
|
|
7152
7174
|
continue;
|
|
@@ -7156,7 +7178,13 @@ function parseInfra(content) {
|
|
|
7156
7178
|
const label = connMatch[1]?.trim() || "";
|
|
7157
7179
|
const targetName = connMatch[2].trim();
|
|
7158
7180
|
const splitStr = connMatch[3];
|
|
7181
|
+
const fanoutStr = connMatch[4];
|
|
7159
7182
|
const split = splitStr ? parseFloat(splitStr) : null;
|
|
7183
|
+
const fanoutRaw = fanoutStr ? parseInt(fanoutStr, 10) : null;
|
|
7184
|
+
if (fanoutRaw !== null && fanoutRaw < 1) {
|
|
7185
|
+
warn(lineNumber, `Fan-out multiplier must be at least 1 (got x${fanoutRaw}). Ignoring.`);
|
|
7186
|
+
}
|
|
7187
|
+
const fanout = fanoutRaw !== null && fanoutRaw >= 1 ? fanoutRaw : null;
|
|
7160
7188
|
let targetId;
|
|
7161
7189
|
const targetGroupMatch = targetName.match(GROUP_RE);
|
|
7162
7190
|
if (targetGroupMatch) {
|
|
@@ -7169,14 +7197,20 @@ function parseInfra(content) {
|
|
|
7169
7197
|
targetId,
|
|
7170
7198
|
label,
|
|
7171
7199
|
split,
|
|
7200
|
+
fanout,
|
|
7172
7201
|
lineNumber
|
|
7173
7202
|
});
|
|
7174
7203
|
continue;
|
|
7175
7204
|
}
|
|
7205
|
+
if (/^description\s*:\s*$/i.test(trimmed)) continue;
|
|
7176
7206
|
const propMatch = trimmed.match(PROPERTY_RE);
|
|
7177
7207
|
if (propMatch) {
|
|
7178
7208
|
const key = propMatch[1].toLowerCase();
|
|
7179
7209
|
const rawVal = propMatch[2].trim();
|
|
7210
|
+
if (key === "description" && currentNode) {
|
|
7211
|
+
if (!currentNode.isEdge) currentNode.description = rawVal;
|
|
7212
|
+
continue;
|
|
7213
|
+
}
|
|
7180
7214
|
if (!INFRA_BEHAVIOR_KEYS.has(key) && !EDGE_ONLY_KEYS.has(key)) {
|
|
7181
7215
|
const allKeys = [...INFRA_BEHAVIOR_KEYS, ...EDGE_ONLY_KEYS];
|
|
7182
7216
|
let msg = `Unknown property '${key}'.`;
|
|
@@ -7278,12 +7312,12 @@ var init_parser9 = __esm({
|
|
|
7278
7312
|
init_diagnostics();
|
|
7279
7313
|
init_parsing();
|
|
7280
7314
|
init_types2();
|
|
7281
|
-
CONNECTION_RE = /^-(?:([^-].*?))?->\s+(.+?)(?:(?:\s*\|\s*|\s+)split\s*:?\s*(\d+)%)?\s*$/;
|
|
7282
|
-
SIMPLE_CONNECTION_RE = /^->\s+(.+?)(?:(?:\s*\|\s*|\s+)split\s*:?\s*(\d+)%)?\s*$/;
|
|
7315
|
+
CONNECTION_RE = /^-(?:([^-].*?))?->\s+(.+?)(?:(?:\s*\|\s*|\s+)split\s*:?\s*(\d+)%)?\s*(?:x(\d+))?\s*$/;
|
|
7316
|
+
SIMPLE_CONNECTION_RE = /^->\s+(.+?)(?:(?:\s*\|\s*|\s+)split\s*:?\s*(\d+)%)?\s*(?:x(\d+))?\s*$/;
|
|
7283
7317
|
GROUP_RE = /^\[([^\]]+)\]$/;
|
|
7284
7318
|
TAG_GROUP_RE = /^tag\s*:\s*(\w[\w\s]*?)(?:\s+alias\s+(\w+))?\s*$/;
|
|
7285
7319
|
TAG_VALUE_RE = /^(\w[\w\s]*?)(?:\(([^)]+)\))?(\s+default)?\s*$/;
|
|
7286
|
-
COMPONENT_RE = /^([a-zA-Z_][\w]*)(.*)$/;
|
|
7320
|
+
COMPONENT_RE = /^([a-zA-Z_][\w-]*)(.*)$/;
|
|
7287
7321
|
PIPE_META_RE = /[|,]\s*(\w+)\s*:\s*([^|,]+)/g;
|
|
7288
7322
|
PROPERTY_RE = /^([\w-]+)\s*:\s*(.+)$/;
|
|
7289
7323
|
PERCENT_RE = /^([\d.]+)%$/;
|
|
@@ -7518,7 +7552,7 @@ function centerHeavyChildren(node) {
|
|
|
7518
7552
|
}
|
|
7519
7553
|
node.children = result;
|
|
7520
7554
|
}
|
|
7521
|
-
function computeLegendGroups(tagGroups,
|
|
7555
|
+
function computeLegendGroups(tagGroups, showEyeIcons, usedValuesByGroup) {
|
|
7522
7556
|
const groups = [];
|
|
7523
7557
|
for (const group of tagGroups) {
|
|
7524
7558
|
if (group.entries.length === 0) continue;
|
|
@@ -7531,7 +7565,8 @@ function computeLegendGroups(tagGroups, _showEyeIcons, usedValuesByGroup) {
|
|
|
7531
7565
|
for (const entry of visibleEntries) {
|
|
7532
7566
|
entriesWidth += LEGEND_DOT_R * 2 + LEGEND_ENTRY_DOT_GAP + entry.value.length * LEGEND_ENTRY_FONT_W + LEGEND_ENTRY_TRAIL;
|
|
7533
7567
|
}
|
|
7534
|
-
const
|
|
7568
|
+
const eyeSpace = showEyeIcons ? LEGEND_EYE_SIZE + LEGEND_EYE_GAP : 0;
|
|
7569
|
+
const capsuleWidth = LEGEND_CAPSULE_PAD * 2 + pillWidth + 4 + eyeSpace + entriesWidth;
|
|
7535
7570
|
groups.push({
|
|
7536
7571
|
name: group.name,
|
|
7537
7572
|
alias: group.alias,
|
|
@@ -8164,7 +8199,7 @@ function layoutOrg(parsed, hiddenCounts, activeTagGroup, hiddenAttributes, expan
|
|
|
8164
8199
|
height: finalHeight
|
|
8165
8200
|
};
|
|
8166
8201
|
}
|
|
8167
|
-
var CHAR_WIDTH, META_LINE_HEIGHT, HEADER_HEIGHT, SEPARATOR_GAP, CARD_H_PAD, CARD_V_PAD, MIN_CARD_WIDTH, H_GAP, V_GAP, MARGIN, CONTAINER_PAD_X, CONTAINER_PAD_BOTTOM, CONTAINER_LABEL_HEIGHT, CONTAINER_META_LINE_HEIGHT, STACK_V_GAP, LEGEND_GAP, LEGEND_HEIGHT, LEGEND_PILL_PAD, LEGEND_PILL_FONT_W, LEGEND_CAPSULE_PAD, LEGEND_DOT_R, LEGEND_ENTRY_FONT_W, LEGEND_ENTRY_DOT_GAP, LEGEND_ENTRY_TRAIL, LEGEND_GROUP_GAP;
|
|
8202
|
+
var CHAR_WIDTH, META_LINE_HEIGHT, HEADER_HEIGHT, SEPARATOR_GAP, CARD_H_PAD, CARD_V_PAD, MIN_CARD_WIDTH, H_GAP, V_GAP, MARGIN, CONTAINER_PAD_X, CONTAINER_PAD_BOTTOM, CONTAINER_LABEL_HEIGHT, CONTAINER_META_LINE_HEIGHT, STACK_V_GAP, LEGEND_GAP, LEGEND_HEIGHT, LEGEND_PILL_PAD, LEGEND_PILL_FONT_W, LEGEND_CAPSULE_PAD, LEGEND_DOT_R, LEGEND_ENTRY_FONT_W, LEGEND_ENTRY_DOT_GAP, LEGEND_ENTRY_TRAIL, LEGEND_GROUP_GAP, LEGEND_EYE_SIZE, LEGEND_EYE_GAP;
|
|
8168
8203
|
var init_layout = __esm({
|
|
8169
8204
|
"src/org/layout.ts"() {
|
|
8170
8205
|
"use strict";
|
|
@@ -8194,6 +8229,8 @@ var init_layout = __esm({
|
|
|
8194
8229
|
LEGEND_ENTRY_DOT_GAP = 4;
|
|
8195
8230
|
LEGEND_ENTRY_TRAIL = 8;
|
|
8196
8231
|
LEGEND_GROUP_GAP = 12;
|
|
8232
|
+
LEGEND_EYE_SIZE = 14;
|
|
8233
|
+
LEGEND_EYE_GAP = 6;
|
|
8197
8234
|
}
|
|
8198
8235
|
});
|
|
8199
8236
|
|
|
@@ -8296,22 +8333,27 @@ function renderOrg(container, parsed, layout, palette, isDark, onClickItem, expo
|
|
|
8296
8333
|
const layoutLegendShift = LEGEND_HEIGHT2 + LEGEND_GROUP_GAP2;
|
|
8297
8334
|
const fixedLegend = !exportDims && hasLegend && !legendOnly;
|
|
8298
8335
|
const legendReserve = fixedLegend ? LEGEND_HEIGHT2 + LEGEND_FIXED_GAP : 0;
|
|
8336
|
+
const fixedTitle = !exportDims && !!parsed.title;
|
|
8337
|
+
const titleReserve = fixedTitle ? TITLE_HEIGHT : 0;
|
|
8299
8338
|
const diagramW = layout.width;
|
|
8300
|
-
let diagramH = layout.height + titleOffset;
|
|
8339
|
+
let diagramH = layout.height + (fixedTitle ? 0 : titleOffset);
|
|
8301
8340
|
if (fixedLegend) {
|
|
8302
8341
|
diagramH -= layoutLegendShift;
|
|
8303
8342
|
}
|
|
8304
|
-
const availH = height - DIAGRAM_PADDING * 2 - legendReserve;
|
|
8343
|
+
const availH = height - DIAGRAM_PADDING * 2 - legendReserve - titleReserve;
|
|
8305
8344
|
const scaleX = (width - DIAGRAM_PADDING * 2) / diagramW;
|
|
8306
8345
|
const scaleY = availH / diagramH;
|
|
8307
8346
|
const scale = Math.min(MAX_SCALE, scaleX, scaleY);
|
|
8308
8347
|
const scaledW = diagramW * scale;
|
|
8309
8348
|
const offsetX = (width - scaledW) / 2;
|
|
8310
|
-
const offsetY = legendPosition === "top" && fixedLegend ? DIAGRAM_PADDING + legendReserve : DIAGRAM_PADDING;
|
|
8349
|
+
const offsetY = legendPosition === "top" && fixedLegend ? DIAGRAM_PADDING + legendReserve + titleReserve : DIAGRAM_PADDING + titleReserve;
|
|
8311
8350
|
const svg = d3Selection.select(container).append("svg").attr("width", width).attr("height", height).style("font-family", FONT_FAMILY);
|
|
8312
8351
|
const mainG = svg.append("g").attr("transform", `translate(${offsetX}, ${offsetY}) scale(${scale})`);
|
|
8313
8352
|
if (parsed.title) {
|
|
8314
|
-
const
|
|
8353
|
+
const titleParent = fixedTitle ? svg : mainG;
|
|
8354
|
+
const titleX = fixedTitle ? width / 2 : diagramW / 2;
|
|
8355
|
+
const titleY = fixedTitle ? DIAGRAM_PADDING + TITLE_FONT_SIZE : TITLE_FONT_SIZE;
|
|
8356
|
+
const titleEl = titleParent.append("text").attr("x", titleX).attr("y", titleY).attr("text-anchor", "middle").attr("fill", palette.text).attr("font-size", TITLE_FONT_SIZE).attr("font-weight", "bold").attr("class", "org-title chart-title").style(
|
|
8315
8357
|
"cursor",
|
|
8316
8358
|
onClickItem && parsed.titleLineNumber ? "pointer" : "default"
|
|
8317
8359
|
).text(parsed.title);
|
|
@@ -8326,7 +8368,7 @@ function renderOrg(container, parsed, layout, palette, isDark, onClickItem, expo
|
|
|
8326
8368
|
}
|
|
8327
8369
|
}
|
|
8328
8370
|
}
|
|
8329
|
-
const contentG = mainG.append("g").attr("transform", `translate(0, ${titleOffset})`);
|
|
8371
|
+
const contentG = mainG.append("g").attr("transform", `translate(0, ${fixedTitle ? 0 : titleOffset})`);
|
|
8330
8372
|
const displayNames = /* @__PURE__ */ new Map();
|
|
8331
8373
|
for (const group of parsed.tagGroups) {
|
|
8332
8374
|
displayNames.set(group.name.toLowerCase(), group.name);
|
|
@@ -8454,7 +8496,7 @@ function renderOrg(container, parsed, layout, palette, isDark, onClickItem, expo
|
|
|
8454
8496
|
}
|
|
8455
8497
|
const legendParent = fixedLegend ? svg.append("g").attr("class", "org-legend-fixed").attr(
|
|
8456
8498
|
"transform",
|
|
8457
|
-
legendPosition === "bottom" ? `translate(0, ${height - DIAGRAM_PADDING - LEGEND_HEIGHT2})` : `translate(0, ${DIAGRAM_PADDING})`
|
|
8499
|
+
legendPosition === "bottom" ? `translate(0, ${height - DIAGRAM_PADDING - LEGEND_HEIGHT2})` : `translate(0, ${DIAGRAM_PADDING + titleReserve})`
|
|
8458
8500
|
) : contentG;
|
|
8459
8501
|
for (const group of visibleGroups) {
|
|
8460
8502
|
const isActive = legendOnly || activeTagGroup != null && group.name.toLowerCase() === activeTagGroup.toLowerCase();
|
|
@@ -8475,8 +8517,19 @@ function renderOrg(container, parsed, layout, palette, isDark, onClickItem, expo
|
|
|
8475
8517
|
gEl.append("rect").attr("x", pillXOff).attr("y", pillYOff).attr("width", pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", "none").attr("stroke", mix(palette.textMuted, palette.bg, 50)).attr("stroke-width", 0.75);
|
|
8476
8518
|
}
|
|
8477
8519
|
gEl.append("text").attr("x", pillXOff + pillWidth / 2).attr("y", LEGEND_HEIGHT2 / 2 + LEGEND_PILL_FONT_SIZE / 2 - 2).attr("font-size", LEGEND_PILL_FONT_SIZE).attr("font-weight", "500").attr("fill", isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(pillLabel);
|
|
8520
|
+
if (isActive && fixedLegend) {
|
|
8521
|
+
const groupKey = group.name.toLowerCase();
|
|
8522
|
+
const isHidden = hiddenAttributes?.has(groupKey) ?? false;
|
|
8523
|
+
const eyeX = pillXOff + pillWidth + LEGEND_EYE_GAP2;
|
|
8524
|
+
const eyeY = (LEGEND_HEIGHT2 - LEGEND_EYE_SIZE2) / 2;
|
|
8525
|
+
const hitPad = 6;
|
|
8526
|
+
const eyeG = gEl.append("g").attr("class", "org-legend-eye").attr("data-legend-visibility", groupKey).style("cursor", "pointer").attr("opacity", isHidden ? 0.4 : 0.7);
|
|
8527
|
+
eyeG.append("rect").attr("x", eyeX - hitPad).attr("y", eyeY - hitPad).attr("width", LEGEND_EYE_SIZE2 + hitPad * 2).attr("height", LEGEND_EYE_SIZE2 + hitPad * 2).attr("fill", "transparent").attr("pointer-events", "all");
|
|
8528
|
+
eyeG.append("path").attr("d", isHidden ? EYE_CLOSED_PATH : EYE_OPEN_PATH).attr("transform", `translate(${eyeX}, ${eyeY})`).attr("fill", "none").attr("stroke", palette.textMuted).attr("stroke-width", 1.2).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
|
|
8529
|
+
}
|
|
8478
8530
|
if (isActive) {
|
|
8479
|
-
|
|
8531
|
+
const eyeShift = fixedLegend ? LEGEND_EYE_SIZE2 + LEGEND_EYE_GAP2 : 0;
|
|
8532
|
+
let entryX = pillXOff + pillWidth + 4 + eyeShift;
|
|
8480
8533
|
for (const entry of group.entries) {
|
|
8481
8534
|
const entryG = gEl.append("g").attr("data-legend-entry", entry.value.toLowerCase()).style("cursor", "pointer");
|
|
8482
8535
|
entryG.append("circle").attr("cx", entryX + LEGEND_DOT_R2).attr("cy", LEGEND_HEIGHT2 / 2).attr("r", LEGEND_DOT_R2).attr("fill", entry.color);
|
|
@@ -8522,7 +8575,7 @@ function renderOrgForExport(content, theme, palette) {
|
|
|
8522
8575
|
document.body.removeChild(container);
|
|
8523
8576
|
}
|
|
8524
8577
|
}
|
|
8525
|
-
var DIAGRAM_PADDING, MAX_SCALE, TITLE_HEIGHT, TITLE_FONT_SIZE, LABEL_FONT_SIZE, META_FONT_SIZE, META_LINE_HEIGHT2, HEADER_HEIGHT2, SEPARATOR_GAP2, EDGE_STROKE_WIDTH, NODE_STROKE_WIDTH, CARD_RADIUS, CONTAINER_RADIUS, CONTAINER_LABEL_FONT_SIZE, CONTAINER_META_FONT_SIZE, CONTAINER_META_LINE_HEIGHT2, CONTAINER_HEADER_HEIGHT, COLLAPSE_BAR_HEIGHT, COLLAPSE_BAR_INSET, LEGEND_HEIGHT2, LEGEND_PILL_PAD2, LEGEND_PILL_FONT_SIZE, LEGEND_PILL_FONT_W2, LEGEND_CAPSULE_PAD2, LEGEND_DOT_R2, LEGEND_ENTRY_FONT_SIZE, LEGEND_ENTRY_FONT_W2, LEGEND_ENTRY_DOT_GAP2, LEGEND_ENTRY_TRAIL2, LEGEND_GROUP_GAP2, LEGEND_FIXED_GAP;
|
|
8578
|
+
var DIAGRAM_PADDING, MAX_SCALE, TITLE_HEIGHT, TITLE_FONT_SIZE, LABEL_FONT_SIZE, META_FONT_SIZE, META_LINE_HEIGHT2, HEADER_HEIGHT2, SEPARATOR_GAP2, EDGE_STROKE_WIDTH, NODE_STROKE_WIDTH, CARD_RADIUS, CONTAINER_RADIUS, CONTAINER_LABEL_FONT_SIZE, CONTAINER_META_FONT_SIZE, CONTAINER_META_LINE_HEIGHT2, CONTAINER_HEADER_HEIGHT, COLLAPSE_BAR_HEIGHT, COLLAPSE_BAR_INSET, LEGEND_HEIGHT2, LEGEND_PILL_PAD2, LEGEND_PILL_FONT_SIZE, LEGEND_PILL_FONT_W2, LEGEND_CAPSULE_PAD2, LEGEND_DOT_R2, LEGEND_ENTRY_FONT_SIZE, LEGEND_ENTRY_FONT_W2, LEGEND_ENTRY_DOT_GAP2, LEGEND_ENTRY_TRAIL2, LEGEND_GROUP_GAP2, LEGEND_EYE_SIZE2, LEGEND_EYE_GAP2, LEGEND_FIXED_GAP, EYE_OPEN_PATH, EYE_CLOSED_PATH;
|
|
8526
8579
|
var init_renderer = __esm({
|
|
8527
8580
|
"src/org/renderer.ts"() {
|
|
8528
8581
|
"use strict";
|
|
@@ -8560,7 +8613,11 @@ var init_renderer = __esm({
|
|
|
8560
8613
|
LEGEND_ENTRY_DOT_GAP2 = 4;
|
|
8561
8614
|
LEGEND_ENTRY_TRAIL2 = 8;
|
|
8562
8615
|
LEGEND_GROUP_GAP2 = 12;
|
|
8616
|
+
LEGEND_EYE_SIZE2 = 14;
|
|
8617
|
+
LEGEND_EYE_GAP2 = 6;
|
|
8563
8618
|
LEGEND_FIXED_GAP = 8;
|
|
8619
|
+
EYE_OPEN_PATH = "M1 7s2.5-5 6-5 6 5 6 5-2.5 5-6 5-6-5-6-5z M7 9.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z";
|
|
8620
|
+
EYE_CLOSED_PATH = "M2.5 2.5l9 9 M1.5 7s2.2-4 5.5-4c1.2 0 2.2.5 3 1.1 M12.5 7s-2.2 4-5.5 4c-1.2 0-2.2-.5-3-1.1";
|
|
8564
8621
|
}
|
|
8565
8622
|
});
|
|
8566
8623
|
|
|
@@ -8610,7 +8667,7 @@ function computeLegendGroups2(tagGroups, usedValuesByGroup) {
|
|
|
8610
8667
|
for (const entry of visibleEntries) {
|
|
8611
8668
|
entriesWidth += LEGEND_DOT_R3 * 2 + LEGEND_ENTRY_DOT_GAP3 + entry.value.length * LEGEND_ENTRY_FONT_W3 + LEGEND_ENTRY_TRAIL3;
|
|
8612
8669
|
}
|
|
8613
|
-
const eyeSpace =
|
|
8670
|
+
const eyeSpace = LEGEND_EYE_SIZE3 + LEGEND_EYE_GAP3;
|
|
8614
8671
|
const capsuleWidth = LEGEND_CAPSULE_PAD3 * 2 + pillWidth + 4 + eyeSpace + entriesWidth;
|
|
8615
8672
|
groups.push({
|
|
8616
8673
|
name: group.name,
|
|
@@ -9012,7 +9069,7 @@ function layoutSitemap(parsed, hiddenCounts, activeTagGroup, hiddenAttributes, e
|
|
|
9012
9069
|
height: totalHeight
|
|
9013
9070
|
};
|
|
9014
9071
|
}
|
|
9015
|
-
var CHAR_WIDTH2, META_LINE_HEIGHT3, HEADER_HEIGHT3, SEPARATOR_GAP3, CARD_H_PAD2, CARD_V_PAD2, MIN_CARD_WIDTH2, MARGIN2, CONTAINER_PAD_X2, CONTAINER_PAD_TOP, CONTAINER_PAD_BOTTOM2, CONTAINER_LABEL_HEIGHT2, CONTAINER_META_LINE_HEIGHT3, LEGEND_HEIGHT3, LEGEND_PILL_PAD3, LEGEND_PILL_FONT_W3, LEGEND_CAPSULE_PAD3, LEGEND_DOT_R3, LEGEND_ENTRY_FONT_W3, LEGEND_ENTRY_DOT_GAP3, LEGEND_ENTRY_TRAIL3, LEGEND_GROUP_GAP3,
|
|
9072
|
+
var CHAR_WIDTH2, META_LINE_HEIGHT3, HEADER_HEIGHT3, SEPARATOR_GAP3, CARD_H_PAD2, CARD_V_PAD2, MIN_CARD_WIDTH2, MARGIN2, CONTAINER_PAD_X2, CONTAINER_PAD_TOP, CONTAINER_PAD_BOTTOM2, CONTAINER_LABEL_HEIGHT2, CONTAINER_META_LINE_HEIGHT3, LEGEND_HEIGHT3, LEGEND_PILL_PAD3, LEGEND_PILL_FONT_W3, LEGEND_CAPSULE_PAD3, LEGEND_DOT_R3, LEGEND_ENTRY_FONT_W3, LEGEND_ENTRY_DOT_GAP3, LEGEND_ENTRY_TRAIL3, LEGEND_GROUP_GAP3, LEGEND_EYE_SIZE3, LEGEND_EYE_GAP3, OVERLAP_GAP;
|
|
9016
9073
|
var init_layout2 = __esm({
|
|
9017
9074
|
"src/sitemap/layout.ts"() {
|
|
9018
9075
|
"use strict";
|
|
@@ -9039,8 +9096,8 @@ var init_layout2 = __esm({
|
|
|
9039
9096
|
LEGEND_ENTRY_DOT_GAP3 = 4;
|
|
9040
9097
|
LEGEND_ENTRY_TRAIL3 = 8;
|
|
9041
9098
|
LEGEND_GROUP_GAP3 = 12;
|
|
9042
|
-
|
|
9043
|
-
|
|
9099
|
+
LEGEND_EYE_SIZE3 = 14;
|
|
9100
|
+
LEGEND_EYE_GAP3 = 6;
|
|
9044
9101
|
OVERLAP_GAP = 20;
|
|
9045
9102
|
}
|
|
9046
9103
|
});
|
|
@@ -9394,15 +9451,15 @@ function renderLegend(parent, legendGroups, palette, isDark, activeTagGroup, fix
|
|
|
9394
9451
|
if (isActive && fixedWidth != null) {
|
|
9395
9452
|
const groupKey = group.name.toLowerCase();
|
|
9396
9453
|
const isHidden = hiddenAttributes?.has(groupKey) ?? false;
|
|
9397
|
-
const eyeX = pillXOff + pillW +
|
|
9398
|
-
const eyeY = (LEGEND_HEIGHT4 -
|
|
9454
|
+
const eyeX = pillXOff + pillW + LEGEND_EYE_GAP4;
|
|
9455
|
+
const eyeY = (LEGEND_HEIGHT4 - LEGEND_EYE_SIZE4) / 2;
|
|
9399
9456
|
const hitPad = 6;
|
|
9400
9457
|
const eyeG = legendG.append("g").attr("class", "sitemap-legend-eye").attr("data-legend-visibility", groupKey).style("cursor", "pointer").attr("opacity", isHidden ? 0.4 : 0.7);
|
|
9401
|
-
eyeG.append("rect").attr("x", eyeX - hitPad).attr("y", eyeY - hitPad).attr("width",
|
|
9402
|
-
eyeG.append("path").attr("d", isHidden ?
|
|
9458
|
+
eyeG.append("rect").attr("x", eyeX - hitPad).attr("y", eyeY - hitPad).attr("width", LEGEND_EYE_SIZE4 + hitPad * 2).attr("height", LEGEND_EYE_SIZE4 + hitPad * 2).attr("fill", "transparent").attr("pointer-events", "all");
|
|
9459
|
+
eyeG.append("path").attr("d", isHidden ? EYE_CLOSED_PATH2 : EYE_OPEN_PATH2).attr("transform", `translate(${eyeX}, ${eyeY})`).attr("fill", "none").attr("stroke", palette.textMuted).attr("stroke-width", 1.2).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
|
|
9403
9460
|
}
|
|
9404
9461
|
if (isActive) {
|
|
9405
|
-
const eyeShift = fixedWidth != null ?
|
|
9462
|
+
const eyeShift = fixedWidth != null ? LEGEND_EYE_SIZE4 + LEGEND_EYE_GAP4 : 0;
|
|
9406
9463
|
let entryX = pillXOff + pillW + 4 + eyeShift;
|
|
9407
9464
|
for (const entry of group.entries) {
|
|
9408
9465
|
const entryG = legendG.append("g").attr("data-legend-entry", entry.value.toLowerCase()).style("cursor", "pointer");
|
|
@@ -9455,7 +9512,7 @@ async function renderSitemapForExport(content, theme, palette) {
|
|
|
9455
9512
|
const brandColor = theme === "transparent" ? "#888" : effectivePalette.textMuted;
|
|
9456
9513
|
return injectBranding2(svgHtml, brandColor);
|
|
9457
9514
|
}
|
|
9458
|
-
var DIAGRAM_PADDING2, MAX_SCALE2, TITLE_HEIGHT2, TITLE_FONT_SIZE2, LABEL_FONT_SIZE2, META_FONT_SIZE2, META_LINE_HEIGHT4, HEADER_HEIGHT4, SEPARATOR_GAP4, EDGE_STROKE_WIDTH2, NODE_STROKE_WIDTH2, CARD_RADIUS2, CONTAINER_RADIUS2, CONTAINER_LABEL_FONT_SIZE2, CONTAINER_META_FONT_SIZE2, CONTAINER_META_LINE_HEIGHT4, CONTAINER_HEADER_HEIGHT2, ARROWHEAD_W, ARROWHEAD_H, EDGE_LABEL_FONT_SIZE, COLLAPSE_BAR_HEIGHT2, LEGEND_HEIGHT4, LEGEND_FIXED_GAP2, LEGEND_PILL_PAD4, LEGEND_PILL_FONT_SIZE2, LEGEND_PILL_FONT_W4, LEGEND_CAPSULE_PAD4, LEGEND_DOT_R4, LEGEND_ENTRY_FONT_SIZE2, LEGEND_ENTRY_FONT_W4, LEGEND_ENTRY_DOT_GAP4, LEGEND_ENTRY_TRAIL4, LEGEND_GROUP_GAP4,
|
|
9515
|
+
var DIAGRAM_PADDING2, MAX_SCALE2, TITLE_HEIGHT2, TITLE_FONT_SIZE2, LABEL_FONT_SIZE2, META_FONT_SIZE2, META_LINE_HEIGHT4, HEADER_HEIGHT4, SEPARATOR_GAP4, EDGE_STROKE_WIDTH2, NODE_STROKE_WIDTH2, CARD_RADIUS2, CONTAINER_RADIUS2, CONTAINER_LABEL_FONT_SIZE2, CONTAINER_META_FONT_SIZE2, CONTAINER_META_LINE_HEIGHT4, CONTAINER_HEADER_HEIGHT2, ARROWHEAD_W, ARROWHEAD_H, EDGE_LABEL_FONT_SIZE, COLLAPSE_BAR_HEIGHT2, LEGEND_HEIGHT4, LEGEND_FIXED_GAP2, LEGEND_PILL_PAD4, LEGEND_PILL_FONT_SIZE2, LEGEND_PILL_FONT_W4, LEGEND_CAPSULE_PAD4, LEGEND_DOT_R4, LEGEND_ENTRY_FONT_SIZE2, LEGEND_ENTRY_FONT_W4, LEGEND_ENTRY_DOT_GAP4, LEGEND_ENTRY_TRAIL4, LEGEND_GROUP_GAP4, LEGEND_EYE_SIZE4, LEGEND_EYE_GAP4, lineGenerator, EYE_OPEN_PATH2, EYE_CLOSED_PATH2;
|
|
9459
9516
|
var init_renderer2 = __esm({
|
|
9460
9517
|
"src/sitemap/renderer.ts"() {
|
|
9461
9518
|
"use strict";
|
|
@@ -9494,11 +9551,11 @@ var init_renderer2 = __esm({
|
|
|
9494
9551
|
LEGEND_ENTRY_DOT_GAP4 = 4;
|
|
9495
9552
|
LEGEND_ENTRY_TRAIL4 = 8;
|
|
9496
9553
|
LEGEND_GROUP_GAP4 = 12;
|
|
9497
|
-
|
|
9498
|
-
|
|
9554
|
+
LEGEND_EYE_SIZE4 = 14;
|
|
9555
|
+
LEGEND_EYE_GAP4 = 6;
|
|
9499
9556
|
lineGenerator = d3Shape.line().x((d) => d.x).y((d) => d.y).curve(d3Shape.curveBasis);
|
|
9500
|
-
|
|
9501
|
-
|
|
9557
|
+
EYE_OPEN_PATH2 = "M1 7s2.5-5 6-5 6 5 6 5-2.5 5-6 5-6-5-6-5z M7 9.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z";
|
|
9558
|
+
EYE_CLOSED_PATH2 = "M2.5 2.5l9 9 M1.5 7s2.2-4 5.5-4c1.2 0 2.2.5 3 1.1 M12.5 7s-2.2 4-5.5 4c-1.2 0-2.2-.5-3-1.1";
|
|
9502
9559
|
}
|
|
9503
9560
|
});
|
|
9504
9561
|
|
|
@@ -10734,7 +10791,8 @@ var init_renderer5 = __esm({
|
|
|
10734
10791
|
// src/initiative-status/layout.ts
|
|
10735
10792
|
var layout_exports5 = {};
|
|
10736
10793
|
__export(layout_exports5, {
|
|
10737
|
-
layoutInitiativeStatus: () => layoutInitiativeStatus
|
|
10794
|
+
layoutInitiativeStatus: () => layoutInitiativeStatus,
|
|
10795
|
+
rollUpStatus: () => rollUpStatus
|
|
10738
10796
|
});
|
|
10739
10797
|
import dagre4 from "@dagrejs/dagre";
|
|
10740
10798
|
function rollUpStatus(members) {
|
|
@@ -10749,14 +10807,28 @@ function rollUpStatus(members) {
|
|
|
10749
10807
|
}
|
|
10750
10808
|
return worst;
|
|
10751
10809
|
}
|
|
10752
|
-
function layoutInitiativeStatus(parsed) {
|
|
10753
|
-
if (parsed.nodes.length === 0) {
|
|
10810
|
+
function layoutInitiativeStatus(parsed, collapseResult) {
|
|
10811
|
+
if (parsed.nodes.length === 0 && (!collapseResult || collapseResult.collapsedGroupStatuses.size === 0)) {
|
|
10754
10812
|
return { nodes: [], edges: [], groups: [], width: 0, height: 0 };
|
|
10755
10813
|
}
|
|
10756
|
-
const
|
|
10814
|
+
const originalGroups = collapseResult?.originalGroups ?? parsed.groups;
|
|
10815
|
+
const collapsedGroupStatuses = collapseResult?.collapsedGroupStatuses ?? /* @__PURE__ */ new Map();
|
|
10816
|
+
const collapsedGroupLabels = new Set(
|
|
10817
|
+
originalGroups.map((g2) => g2.label).filter((l) => !parsed.groups.some((g2) => g2.label === l))
|
|
10818
|
+
);
|
|
10819
|
+
const hasGroups = parsed.groups.length > 0 || collapsedGroupLabels.size > 0;
|
|
10757
10820
|
const g = new dagre4.graphlib.Graph({ multigraph: true, compound: hasGroups });
|
|
10758
10821
|
g.setGraph({ rankdir: "LR", nodesep: NODESEP, ranksep: RANKSEP });
|
|
10759
10822
|
g.setDefaultEdgeLabel(() => ({}));
|
|
10823
|
+
for (const group of originalGroups) {
|
|
10824
|
+
if (collapsedGroupLabels.has(group.label)) {
|
|
10825
|
+
const collapsedW = Math.max(
|
|
10826
|
+
NODE_WIDTH,
|
|
10827
|
+
Math.ceil(group.label.length * CHAR_WIDTH_RATIO * NODE_FONT_SIZE) + NODE_TEXT_PADDING * 2
|
|
10828
|
+
);
|
|
10829
|
+
g.setNode(group.label, { label: group.label, width: collapsedW, height: NODE_HEIGHT });
|
|
10830
|
+
}
|
|
10831
|
+
}
|
|
10760
10832
|
for (const group of parsed.groups) {
|
|
10761
10833
|
g.setNode(`__group_${group.label}`, { label: group.label, clusterLabelPos: "top" });
|
|
10762
10834
|
}
|
|
@@ -10787,38 +10859,130 @@ function layoutInitiativeStatus(parsed) {
|
|
|
10787
10859
|
height: pos.height
|
|
10788
10860
|
};
|
|
10789
10861
|
});
|
|
10790
|
-
const
|
|
10791
|
-
const
|
|
10792
|
-
|
|
10793
|
-
|
|
10794
|
-
|
|
10862
|
+
const posMap = new Map(layoutNodes.map((n) => [n.label, n]));
|
|
10863
|
+
for (const label of collapsedGroupLabels) {
|
|
10864
|
+
const pos = g.node(label);
|
|
10865
|
+
if (pos) posMap.set(label, { x: pos.x, y: pos.y, width: pos.width, height: pos.height });
|
|
10866
|
+
}
|
|
10867
|
+
const allNodeX = [...posMap.values()].map((n) => n.x);
|
|
10868
|
+
const avgNodeY = layoutNodes.length > 0 ? layoutNodes.reduce((s, n) => s + n.y, 0) / layoutNodes.length : 0;
|
|
10869
|
+
const avgNodeX = layoutNodes.length > 0 ? layoutNodes.reduce((s, n) => s + n.x, 0) / layoutNodes.length : 0;
|
|
10870
|
+
const edgeYOffsets = new Array(parsed.edges.length).fill(0);
|
|
10871
|
+
const edgeParallelCounts = new Array(parsed.edges.length).fill(1);
|
|
10872
|
+
const parallelGroups = /* @__PURE__ */ new Map();
|
|
10873
|
+
for (let i = 0; i < parsed.edges.length; i++) {
|
|
10874
|
+
const edge = parsed.edges[i];
|
|
10875
|
+
const key = `${edge.source}\0${edge.target}`;
|
|
10876
|
+
parallelGroups.set(key, parallelGroups.get(key) ?? []);
|
|
10877
|
+
parallelGroups.get(key).push(i);
|
|
10878
|
+
}
|
|
10879
|
+
for (const group of parallelGroups.values()) {
|
|
10880
|
+
const capped = group.slice(0, MAX_PARALLEL_EDGES);
|
|
10881
|
+
for (const idx of group.slice(MAX_PARALLEL_EDGES)) {
|
|
10882
|
+
edgeParallelCounts[idx] = 0;
|
|
10883
|
+
}
|
|
10884
|
+
if (capped.length < 2) continue;
|
|
10885
|
+
const effectiveSpacing = Math.min(PARALLEL_SPACING, (NODE_HEIGHT - PARALLEL_EDGE_MARGIN) / (capped.length - 1));
|
|
10886
|
+
for (let j = 0; j < capped.length; j++) {
|
|
10887
|
+
edgeYOffsets[capped[j]] = (j - (capped.length - 1) / 2) * effectiveSpacing;
|
|
10888
|
+
edgeParallelCounts[capped[j]] = capped.length;
|
|
10889
|
+
}
|
|
10890
|
+
}
|
|
10891
|
+
const layoutEdges = [];
|
|
10892
|
+
for (let i = 0; i < parsed.edges.length; i++) {
|
|
10893
|
+
const edge = parsed.edges[i];
|
|
10894
|
+
const src = posMap.get(edge.source);
|
|
10895
|
+
const tgt = posMap.get(edge.target);
|
|
10896
|
+
if (edgeParallelCounts[i] === 0) continue;
|
|
10897
|
+
if (!src || !tgt) continue;
|
|
10898
|
+
const yOffset = edgeYOffsets[i];
|
|
10899
|
+
const parallelCount = edgeParallelCounts[i];
|
|
10795
10900
|
const exitX = src.x + src.width / 2;
|
|
10796
10901
|
const enterX = tgt.x - tgt.width / 2;
|
|
10797
10902
|
const dagreEdge = g.edge(edge.source, edge.target, `e${i}`);
|
|
10798
10903
|
const dagrePoints = dagreEdge?.points ?? [];
|
|
10799
10904
|
const hasIntermediateRank = allNodeX.some((x) => x > src.x + 20 && x < tgt.x - 20);
|
|
10800
10905
|
const step = Math.min((enterX - exitX) * 0.15, 20);
|
|
10801
|
-
const
|
|
10802
|
-
|
|
10803
|
-
|
|
10804
|
-
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
|
|
10811
|
-
|
|
10812
|
-
|
|
10906
|
+
const isBackEdge = tgt.x < src.x - 5;
|
|
10907
|
+
const isYDisplaced = !isBackEdge && Math.abs(tgt.y - src.y) > NODESEP;
|
|
10908
|
+
let points;
|
|
10909
|
+
if (isBackEdge) {
|
|
10910
|
+
const routeAbove = Math.min(src.y, tgt.y) > avgNodeY;
|
|
10911
|
+
const srcHalfH = src.height / 2;
|
|
10912
|
+
const tgtHalfH = tgt.height / 2;
|
|
10913
|
+
const rawMidX = (src.x + tgt.x) / 2;
|
|
10914
|
+
const spreadDir = avgNodeX < rawMidX ? 1 : -1;
|
|
10915
|
+
const unclamped = Math.abs(src.x - tgt.x) < NODE_WIDTH ? rawMidX + spreadDir * BACK_EDGE_MIN_SPREAD : rawMidX;
|
|
10916
|
+
const midX = Math.min(src.x, Math.max(tgt.x, unclamped));
|
|
10917
|
+
if (routeAbove) {
|
|
10918
|
+
const arcY = Math.min(src.y - srcHalfH, tgt.y - tgtHalfH) - BACK_EDGE_MARGIN;
|
|
10919
|
+
points = [
|
|
10920
|
+
{ x: src.x, y: src.y - srcHalfH },
|
|
10921
|
+
{ x: midX, y: arcY },
|
|
10922
|
+
{ x: tgt.x, y: tgt.y - tgtHalfH }
|
|
10923
|
+
];
|
|
10924
|
+
} else {
|
|
10925
|
+
const arcY = Math.max(src.y + srcHalfH, tgt.y + tgtHalfH) + BACK_EDGE_MARGIN;
|
|
10926
|
+
points = [
|
|
10927
|
+
{ x: src.x, y: src.y + srcHalfH },
|
|
10928
|
+
{ x: midX, y: arcY },
|
|
10929
|
+
{ x: tgt.x, y: tgt.y + tgtHalfH }
|
|
10930
|
+
];
|
|
10931
|
+
}
|
|
10932
|
+
} else if (isYDisplaced) {
|
|
10933
|
+
const exitY = tgt.y > src.y + NODESEP ? src.y + src.height / 2 : src.y - src.height / 2;
|
|
10934
|
+
const midX = Math.max(src.x + 1, (src.x + enterX) / 2);
|
|
10935
|
+
const midY = (exitY + tgt.y) / 2;
|
|
10936
|
+
points = [
|
|
10937
|
+
{ x: src.x, y: exitY },
|
|
10938
|
+
{ x: midX, y: midY },
|
|
10939
|
+
{ x: enterX, y: tgt.y }
|
|
10940
|
+
];
|
|
10941
|
+
} else if (tgt.x > src.x && !hasIntermediateRank) {
|
|
10942
|
+
points = [
|
|
10943
|
+
{ x: exitX, y: src.y },
|
|
10944
|
+
// exits node center — stays pinned
|
|
10945
|
+
{ x: exitX + step, y: src.y + yOffset },
|
|
10946
|
+
// fans out
|
|
10947
|
+
{ x: enterX - step, y: tgt.y + yOffset },
|
|
10948
|
+
// still fanned
|
|
10949
|
+
{ x: enterX, y: tgt.y }
|
|
10950
|
+
// enters node center — stays pinned
|
|
10951
|
+
];
|
|
10952
|
+
} else {
|
|
10953
|
+
points = dagrePoints.length >= 2 ? [
|
|
10954
|
+
{ x: exitX, y: src.y + yOffset },
|
|
10955
|
+
...dagrePoints.slice(1, -1),
|
|
10956
|
+
{ x: enterX, y: tgt.y + yOffset }
|
|
10957
|
+
] : dagrePoints;
|
|
10958
|
+
}
|
|
10959
|
+
layoutEdges.push({
|
|
10813
10960
|
source: edge.source,
|
|
10814
10961
|
target: edge.target,
|
|
10815
10962
|
label: edge.label,
|
|
10816
10963
|
status: edge.status,
|
|
10817
10964
|
lineNumber: edge.lineNumber,
|
|
10818
|
-
points
|
|
10819
|
-
|
|
10820
|
-
|
|
10965
|
+
points,
|
|
10966
|
+
parallelCount
|
|
10967
|
+
});
|
|
10968
|
+
}
|
|
10821
10969
|
const layoutGroups = [];
|
|
10970
|
+
for (const group of originalGroups) {
|
|
10971
|
+
if (collapsedGroupLabels.has(group.label)) {
|
|
10972
|
+
const pos = g.node(group.label);
|
|
10973
|
+
if (!pos) continue;
|
|
10974
|
+
layoutGroups.push({
|
|
10975
|
+
label: group.label,
|
|
10976
|
+
status: collapsedGroupStatuses.get(group.label) ?? null,
|
|
10977
|
+
x: pos.x - pos.width / 2,
|
|
10978
|
+
y: pos.y - pos.height / 2,
|
|
10979
|
+
width: pos.width,
|
|
10980
|
+
height: pos.height,
|
|
10981
|
+
lineNumber: group.lineNumber,
|
|
10982
|
+
collapsed: true
|
|
10983
|
+
});
|
|
10984
|
+
}
|
|
10985
|
+
}
|
|
10822
10986
|
if (parsed.groups.length > 0) {
|
|
10823
10987
|
const nMap = new Map(layoutNodes.map((n) => [n.label, n]));
|
|
10824
10988
|
for (const group of parsed.groups) {
|
|
@@ -10842,7 +11006,8 @@ function layoutInitiativeStatus(parsed) {
|
|
|
10842
11006
|
y: minY - GROUP_PADDING,
|
|
10843
11007
|
width: maxX - minX + GROUP_PADDING * 2,
|
|
10844
11008
|
height: maxY - minY + GROUP_PADDING * 2,
|
|
10845
|
-
lineNumber: group.lineNumber
|
|
11009
|
+
lineNumber: group.lineNumber,
|
|
11010
|
+
collapsed: false
|
|
10846
11011
|
});
|
|
10847
11012
|
}
|
|
10848
11013
|
}
|
|
@@ -10868,7 +11033,7 @@ function layoutInitiativeStatus(parsed) {
|
|
|
10868
11033
|
totalHeight += 40;
|
|
10869
11034
|
return { nodes: layoutNodes, edges: layoutEdges, groups: layoutGroups, width: totalWidth, height: totalHeight };
|
|
10870
11035
|
}
|
|
10871
|
-
var STATUS_PRIORITY, PHI, NODE_HEIGHT, NODE_WIDTH, GROUP_PADDING, NODESEP, RANKSEP;
|
|
11036
|
+
var STATUS_PRIORITY, PHI, NODE_HEIGHT, NODE_WIDTH, GROUP_PADDING, NODESEP, RANKSEP, PARALLEL_SPACING, PARALLEL_EDGE_MARGIN, MAX_PARALLEL_EDGES, BACK_EDGE_MARGIN, BACK_EDGE_MIN_SPREAD, CHAR_WIDTH_RATIO, NODE_FONT_SIZE, NODE_TEXT_PADDING;
|
|
10872
11037
|
var init_layout5 = __esm({
|
|
10873
11038
|
"src/initiative-status/layout.ts"() {
|
|
10874
11039
|
"use strict";
|
|
@@ -10879,6 +11044,14 @@ var init_layout5 = __esm({
|
|
|
10879
11044
|
GROUP_PADDING = 20;
|
|
10880
11045
|
NODESEP = 80;
|
|
10881
11046
|
RANKSEP = 160;
|
|
11047
|
+
PARALLEL_SPACING = 16;
|
|
11048
|
+
PARALLEL_EDGE_MARGIN = 12;
|
|
11049
|
+
MAX_PARALLEL_EDGES = 5;
|
|
11050
|
+
BACK_EDGE_MARGIN = 40;
|
|
11051
|
+
BACK_EDGE_MIN_SPREAD = Math.round(NODE_WIDTH * 0.75);
|
|
11052
|
+
CHAR_WIDTH_RATIO = 0.6;
|
|
11053
|
+
NODE_FONT_SIZE = 13;
|
|
11054
|
+
NODE_TEXT_PADDING = 12;
|
|
10882
11055
|
}
|
|
10883
11056
|
});
|
|
10884
11057
|
|
|
@@ -10936,10 +11109,10 @@ function splitCamelCase(word) {
|
|
|
10936
11109
|
return parts.length > 1 ? parts : [word];
|
|
10937
11110
|
}
|
|
10938
11111
|
function fitTextToNode(label, nodeWidth, nodeHeight) {
|
|
10939
|
-
const maxTextWidth = nodeWidth -
|
|
11112
|
+
const maxTextWidth = nodeWidth - NODE_TEXT_PADDING2 * 2;
|
|
10940
11113
|
const lineHeight = 1.3;
|
|
10941
|
-
for (let fontSize =
|
|
10942
|
-
const charWidth2 = fontSize *
|
|
11114
|
+
for (let fontSize = NODE_FONT_SIZE2; fontSize >= MIN_NODE_FONT_SIZE; fontSize--) {
|
|
11115
|
+
const charWidth2 = fontSize * CHAR_WIDTH_RATIO2;
|
|
10943
11116
|
const maxCharsPerLine = Math.floor(maxTextWidth / charWidth2);
|
|
10944
11117
|
const maxLines = Math.floor((nodeHeight - 8) / (fontSize * lineHeight));
|
|
10945
11118
|
if (maxCharsPerLine < 2 || maxLines < 1) continue;
|
|
@@ -11000,8 +11173,8 @@ function fitTextToNode(label, nodeWidth, nodeHeight) {
|
|
|
11000
11173
|
return { lines: hardLines, fontSize };
|
|
11001
11174
|
}
|
|
11002
11175
|
}
|
|
11003
|
-
const charWidth = MIN_NODE_FONT_SIZE *
|
|
11004
|
-
const maxChars = Math.floor((nodeWidth -
|
|
11176
|
+
const charWidth = MIN_NODE_FONT_SIZE * CHAR_WIDTH_RATIO2;
|
|
11177
|
+
const maxChars = Math.floor((nodeWidth - NODE_TEXT_PADDING2 * 2) / charWidth);
|
|
11005
11178
|
const truncated = label.length > maxChars ? label.slice(0, maxChars - 1) + "\u2026" : label;
|
|
11006
11179
|
return { lines: [truncated], fontSize: MIN_NODE_FONT_SIZE };
|
|
11007
11180
|
}
|
|
@@ -11224,21 +11397,27 @@ function renderInitiativeStatus(container, parsed, layout, palette, isDark, onCl
|
|
|
11224
11397
|
const labelMap = /* @__PURE__ */ new Map();
|
|
11225
11398
|
for (const lp of labelPlacements) labelMap.set(lp.edgeIdx, lp);
|
|
11226
11399
|
for (const group of layout.groups) {
|
|
11227
|
-
if (group.
|
|
11228
|
-
|
|
11229
|
-
|
|
11230
|
-
|
|
11231
|
-
|
|
11232
|
-
|
|
11233
|
-
|
|
11234
|
-
|
|
11235
|
-
|
|
11236
|
-
|
|
11237
|
-
|
|
11238
|
-
|
|
11239
|
-
|
|
11240
|
-
|
|
11241
|
-
|
|
11400
|
+
if (group.collapsed) {
|
|
11401
|
+
const fillCol = nodeFill4(group.status, palette, isDark);
|
|
11402
|
+
const strokeCol = nodeStroke4(group.status, palette, isDark);
|
|
11403
|
+
const textCol = nodeTextColor(group.status, palette, isDark);
|
|
11404
|
+
const clipId = `clip-group-${group.lineNumber}`;
|
|
11405
|
+
const groupG = contentG.append("g").attr("class", "is-group is-group-collapsed").attr("data-line-number", String(group.lineNumber)).attr("data-group-toggle", group.label).style("cursor", "pointer");
|
|
11406
|
+
groupG.append("clipPath").attr("id", clipId).append("rect").attr("x", group.x).attr("y", group.y).attr("width", group.width).attr("height", group.height).attr("rx", NODE_RX);
|
|
11407
|
+
groupG.append("rect").attr("x", group.x).attr("y", group.y).attr("width", group.width).attr("height", group.height).attr("rx", NODE_RX).attr("fill", fillCol).attr("stroke", strokeCol).attr("stroke-width", NODE_STROKE_WIDTH5);
|
|
11408
|
+
groupG.append("rect").attr("x", group.x).attr("y", group.y + group.height - COLLAPSE_BAR_HEIGHT3).attr("width", group.width).attr("height", COLLAPSE_BAR_HEIGHT3).attr("fill", strokeCol).attr("clip-path", `url(#${clipId})`).attr("class", "is-collapse-bar");
|
|
11409
|
+
groupG.append("text").attr("x", group.x + group.width / 2).attr("y", group.y + group.height / 2 - COLLAPSE_BAR_HEIGHT3 / 2).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", textCol).attr("font-size", NODE_FONT_SIZE2).attr("font-weight", "bold").attr("font-family", FONT_FAMILY).text(group.label);
|
|
11410
|
+
} else {
|
|
11411
|
+
if (group.width === 0 && group.height === 0) continue;
|
|
11412
|
+
const gx = group.x - GROUP_EXTRA_PADDING;
|
|
11413
|
+
const gy = group.y - GROUP_EXTRA_PADDING - GROUP_LABEL_FONT_SIZE - 4;
|
|
11414
|
+
const gw = group.width + GROUP_EXTRA_PADDING * 2;
|
|
11415
|
+
const gh = group.height + GROUP_EXTRA_PADDING * 2 + GROUP_LABEL_FONT_SIZE + 4;
|
|
11416
|
+
const fillColor = isDark ? palette.surface : palette.bg;
|
|
11417
|
+
const strokeColor = palette.textMuted;
|
|
11418
|
+
const groupG = contentG.append("g").attr("class", "is-group").attr("data-line-number", String(group.lineNumber)).attr("data-group-toggle", group.label).style("cursor", "pointer");
|
|
11419
|
+
groupG.append("rect").attr("x", gx).attr("y", gy).attr("width", gw).attr("height", gh).attr("rx", 6).attr("fill", fillColor).attr("stroke", strokeColor).attr("stroke-opacity", 0.5);
|
|
11420
|
+
groupG.append("text").attr("x", gx + 8).attr("y", gy + GROUP_LABEL_FONT_SIZE + 4).attr("fill", strokeColor).attr("font-size", GROUP_LABEL_FONT_SIZE).attr("font-weight", "bold").attr("opacity", 0.7).attr("class", "is-group-label").text(group.label);
|
|
11242
11421
|
}
|
|
11243
11422
|
}
|
|
11244
11423
|
for (let ei = 0; ei < layout.edges.length; ei++) {
|
|
@@ -11249,7 +11428,7 @@ function renderInitiativeStatus(container, parsed, layout, palette, isDark, onCl
|
|
|
11249
11428
|
const edgeG = contentG.append("g").attr("class", "is-edge-group").attr("data-line-number", String(edge.lineNumber));
|
|
11250
11429
|
const pathD = lineGenerator4(edge.points);
|
|
11251
11430
|
if (pathD) {
|
|
11252
|
-
edgeG.append("path").attr("d", pathD).attr("fill", "none").attr("stroke", "transparent").attr("stroke-width", 16);
|
|
11431
|
+
edgeG.append("path").attr("d", pathD).attr("fill", "none").attr("stroke", "transparent").attr("stroke-width", Math.max(6, Math.round(16 / (edge.parallelCount ?? 1))));
|
|
11253
11432
|
edgeG.append("path").attr("d", pathD).attr("fill", "none").attr("stroke", edgeColor2).attr("stroke-width", EDGE_STROKE_WIDTH5).attr("marker-end", `url(#${markerId})`).attr("class", "is-edge");
|
|
11254
11433
|
}
|
|
11255
11434
|
const lp = labelMap.get(ei);
|
|
@@ -11329,7 +11508,7 @@ function renderInitiativeStatusForExport(content, theme, palette) {
|
|
|
11329
11508
|
document.body.removeChild(container);
|
|
11330
11509
|
}
|
|
11331
11510
|
}
|
|
11332
|
-
var DIAGRAM_PADDING6, MAX_SCALE5,
|
|
11511
|
+
var DIAGRAM_PADDING6, MAX_SCALE5, NODE_FONT_SIZE2, MIN_NODE_FONT_SIZE, EDGE_LABEL_FONT_SIZE4, EDGE_STROKE_WIDTH5, NODE_STROKE_WIDTH5, NODE_RX, ARROWHEAD_W2, ARROWHEAD_H2, CHAR_WIDTH_RATIO2, NODE_TEXT_PADDING2, SERVICE_RX, GROUP_EXTRA_PADDING, GROUP_LABEL_FONT_SIZE, COLLAPSE_BAR_HEIGHT3, lineGenerator4;
|
|
11333
11512
|
var init_renderer6 = __esm({
|
|
11334
11513
|
"src/initiative-status/renderer.ts"() {
|
|
11335
11514
|
"use strict";
|
|
@@ -11339,19 +11518,20 @@ var init_renderer6 = __esm({
|
|
|
11339
11518
|
init_layout5();
|
|
11340
11519
|
DIAGRAM_PADDING6 = 20;
|
|
11341
11520
|
MAX_SCALE5 = 3;
|
|
11342
|
-
|
|
11521
|
+
NODE_FONT_SIZE2 = 13;
|
|
11343
11522
|
MIN_NODE_FONT_SIZE = 9;
|
|
11344
11523
|
EDGE_LABEL_FONT_SIZE4 = 11;
|
|
11345
11524
|
EDGE_STROKE_WIDTH5 = 2;
|
|
11346
11525
|
NODE_STROKE_WIDTH5 = 2;
|
|
11347
11526
|
NODE_RX = 8;
|
|
11348
|
-
ARROWHEAD_W2 =
|
|
11349
|
-
ARROWHEAD_H2 =
|
|
11350
|
-
|
|
11351
|
-
|
|
11527
|
+
ARROWHEAD_W2 = 5;
|
|
11528
|
+
ARROWHEAD_H2 = 4;
|
|
11529
|
+
CHAR_WIDTH_RATIO2 = 0.6;
|
|
11530
|
+
NODE_TEXT_PADDING2 = 12;
|
|
11352
11531
|
SERVICE_RX = 10;
|
|
11353
11532
|
GROUP_EXTRA_PADDING = 8;
|
|
11354
11533
|
GROUP_LABEL_FONT_SIZE = 11;
|
|
11534
|
+
COLLAPSE_BAR_HEIGHT3 = 6;
|
|
11355
11535
|
lineGenerator4 = d3Shape4.line().x((d) => d.x).y((d) => d.y).curve(d3Shape4.curveMonotoneX);
|
|
11356
11536
|
}
|
|
11357
11537
|
});
|
|
@@ -14129,7 +14309,7 @@ function renderFlowchart(container, graph, layout, palette, isDark, onClickItem,
|
|
|
14129
14309
|
});
|
|
14130
14310
|
}
|
|
14131
14311
|
renderNodeShape2(nodeG, node, palette, isDark, endTerminalIds, colorOff);
|
|
14132
|
-
nodeG.append("text").attr("x", 0).attr("y", 0).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", palette.text).attr("font-size",
|
|
14312
|
+
nodeG.append("text").attr("x", 0).attr("y", 0).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", palette.text).attr("font-size", NODE_FONT_SIZE3).text(node.label);
|
|
14133
14313
|
}
|
|
14134
14314
|
}
|
|
14135
14315
|
function renderFlowchartForExport(content, theme, palette) {
|
|
@@ -14167,7 +14347,7 @@ function renderFlowchartForExport(content, theme, palette) {
|
|
|
14167
14347
|
document.body.removeChild(container);
|
|
14168
14348
|
}
|
|
14169
14349
|
}
|
|
14170
|
-
var DIAGRAM_PADDING8, MAX_SCALE7,
|
|
14350
|
+
var DIAGRAM_PADDING8, MAX_SCALE7, NODE_FONT_SIZE3, EDGE_LABEL_FONT_SIZE6, EDGE_STROKE_WIDTH7, NODE_STROKE_WIDTH7, ARROWHEAD_W3, ARROWHEAD_H3, IO_SKEW, SUBROUTINE_INSET, DOC_WAVE_HEIGHT, lineGenerator6;
|
|
14171
14351
|
var init_flowchart_renderer = __esm({
|
|
14172
14352
|
"src/graph/flowchart-renderer.ts"() {
|
|
14173
14353
|
"use strict";
|
|
@@ -14177,7 +14357,7 @@ var init_flowchart_renderer = __esm({
|
|
|
14177
14357
|
init_layout7();
|
|
14178
14358
|
DIAGRAM_PADDING8 = 20;
|
|
14179
14359
|
MAX_SCALE7 = 3;
|
|
14180
|
-
|
|
14360
|
+
NODE_FONT_SIZE3 = 13;
|
|
14181
14361
|
EDGE_LABEL_FONT_SIZE6 = 11;
|
|
14182
14362
|
EDGE_STROKE_WIDTH7 = 1.5;
|
|
14183
14363
|
NODE_STROKE_WIDTH7 = 1.5;
|
|
@@ -14365,23 +14545,26 @@ function collapseGroups(parsed, collapsedIds, defaultLatencyMs = 0, defaultUptim
|
|
|
14365
14545
|
if (!collapsedIds.has(group.id)) continue;
|
|
14366
14546
|
const children = groupChildren.get(group.id) ?? [];
|
|
14367
14547
|
if (children.length === 0) continue;
|
|
14368
|
-
let totalLatency = 0;
|
|
14369
14548
|
let minEffectiveCapacity = Infinity;
|
|
14370
14549
|
let hasMaxRps = false;
|
|
14371
14550
|
let composedUptime = 1;
|
|
14372
14551
|
const behaviorProps = [];
|
|
14373
14552
|
const perChildCapacities = [];
|
|
14553
|
+
const childIdSet = new Set(children.map((c) => c.id));
|
|
14554
|
+
const childLatencies = /* @__PURE__ */ new Map();
|
|
14374
14555
|
for (const child of children) {
|
|
14375
14556
|
const latencyProp = child.properties.find((p) => p.key === "latency-ms");
|
|
14376
14557
|
const childIsServerless = child.properties.some((p) => p.key === "concurrency");
|
|
14558
|
+
let childLat;
|
|
14377
14559
|
if (childIsServerless) {
|
|
14378
14560
|
const durationProp = child.properties.find((p) => p.key === "duration-ms");
|
|
14379
|
-
|
|
14561
|
+
childLat = durationProp ? typeof durationProp.value === "number" ? durationProp.value : parseFloat(String(durationProp.value)) || 100 : 100;
|
|
14380
14562
|
} else if (latencyProp) {
|
|
14381
|
-
|
|
14563
|
+
childLat = typeof latencyProp.value === "number" ? latencyProp.value : parseFloat(String(latencyProp.value)) || 0;
|
|
14382
14564
|
} else {
|
|
14383
|
-
|
|
14565
|
+
childLat = defaultLatencyMs;
|
|
14384
14566
|
}
|
|
14567
|
+
childLatencies.set(child.id, childLat);
|
|
14385
14568
|
const maxRps = child.properties.find((p) => p.key === "max-rps");
|
|
14386
14569
|
if (maxRps) {
|
|
14387
14570
|
hasMaxRps = true;
|
|
@@ -14412,6 +14595,59 @@ function collapseGroups(parsed, collapsedIds, defaultLatencyMs = 0, defaultUptim
|
|
|
14412
14595
|
}
|
|
14413
14596
|
}
|
|
14414
14597
|
}
|
|
14598
|
+
const entryIds = /* @__PURE__ */ new Set();
|
|
14599
|
+
const exitIds = /* @__PURE__ */ new Set();
|
|
14600
|
+
for (const edge of inboundEdges) {
|
|
14601
|
+
if (childIdSet.has(edge.targetId)) entryIds.add(edge.targetId);
|
|
14602
|
+
}
|
|
14603
|
+
for (const edge of outboundEdges) {
|
|
14604
|
+
if (childIdSet.has(edge.sourceId)) exitIds.add(edge.sourceId);
|
|
14605
|
+
}
|
|
14606
|
+
for (const edge of crossGroupEdges) {
|
|
14607
|
+
if (childIdSet.has(edge.sourceId)) exitIds.add(edge.sourceId);
|
|
14608
|
+
if (childIdSet.has(edge.targetId)) entryIds.add(edge.targetId);
|
|
14609
|
+
}
|
|
14610
|
+
const fwdAdj = /* @__PURE__ */ new Map();
|
|
14611
|
+
for (const edge of internalEdges) {
|
|
14612
|
+
if (!childIdSet.has(edge.sourceId) || !childIdSet.has(edge.targetId)) continue;
|
|
14613
|
+
const list = fwdAdj.get(edge.sourceId) ?? [];
|
|
14614
|
+
list.push(edge.targetId);
|
|
14615
|
+
fwdAdj.set(edge.sourceId, list);
|
|
14616
|
+
}
|
|
14617
|
+
const topoOrder = [];
|
|
14618
|
+
const tsVisited = /* @__PURE__ */ new Set();
|
|
14619
|
+
const dfsTopoSort = (id) => {
|
|
14620
|
+
if (tsVisited.has(id)) return;
|
|
14621
|
+
tsVisited.add(id);
|
|
14622
|
+
for (const next of fwdAdj.get(id) ?? []) dfsTopoSort(next);
|
|
14623
|
+
topoOrder.unshift(id);
|
|
14624
|
+
};
|
|
14625
|
+
for (const child of children) dfsTopoSort(child.id);
|
|
14626
|
+
const dist = /* @__PURE__ */ new Map();
|
|
14627
|
+
for (const child of children) {
|
|
14628
|
+
dist.set(child.id, entryIds.has(child.id) ? childLatencies.get(child.id) ?? 0 : -Infinity);
|
|
14629
|
+
}
|
|
14630
|
+
for (const nodeId3 of topoOrder) {
|
|
14631
|
+
const curDist = dist.get(nodeId3) ?? -Infinity;
|
|
14632
|
+
if (curDist === -Infinity) continue;
|
|
14633
|
+
for (const nextId of fwdAdj.get(nodeId3) ?? []) {
|
|
14634
|
+
const newDist = curDist + (childLatencies.get(nextId) ?? 0);
|
|
14635
|
+
if (newDist > (dist.get(nextId) ?? -Infinity)) dist.set(nextId, newDist);
|
|
14636
|
+
}
|
|
14637
|
+
}
|
|
14638
|
+
let totalLatency = 0;
|
|
14639
|
+
if (exitIds.size > 0) {
|
|
14640
|
+
for (const id of exitIds) {
|
|
14641
|
+
const d = dist.get(id);
|
|
14642
|
+
if (d !== void 0 && d > -Infinity && d > totalLatency) totalLatency = d;
|
|
14643
|
+
}
|
|
14644
|
+
} else if (entryIds.size > 0) {
|
|
14645
|
+
for (const [, d] of dist) {
|
|
14646
|
+
if (d > 0 && d > totalLatency) totalLatency = d;
|
|
14647
|
+
}
|
|
14648
|
+
} else {
|
|
14649
|
+
for (const [, lat] of childLatencies) totalLatency += lat;
|
|
14650
|
+
}
|
|
14415
14651
|
const props = [];
|
|
14416
14652
|
if (totalLatency > 0) props.push({ key: "latency-ms", value: totalLatency, lineNumber: group.lineNumber });
|
|
14417
14653
|
const groupInstances = typeof group.instances === "number" ? group.instances : 1;
|
|
@@ -14644,8 +14880,10 @@ function computeInfra(parsed, params = {}) {
|
|
|
14644
14880
|
const resolved = resolveSplits(outbound, diagnostics);
|
|
14645
14881
|
for (const { edge, split } of resolved) {
|
|
14646
14882
|
const edgeRps = outboundRps * (split / 100);
|
|
14883
|
+
const fanout = edge.fanout != null && edge.fanout >= 1 ? edge.fanout : 1;
|
|
14884
|
+
const fanoutedRps = edgeRps * fanout;
|
|
14647
14885
|
const edgeKey = `${edge.sourceId}->${edge.targetId}`;
|
|
14648
|
-
computedEdgeRps.set(edgeKey,
|
|
14886
|
+
computedEdgeRps.set(edgeKey, fanoutedRps);
|
|
14649
14887
|
let targetIds;
|
|
14650
14888
|
const groupChildren = groupChildMap.get(edge.targetId);
|
|
14651
14889
|
if (groupChildren && groupChildren.length > 0) {
|
|
@@ -14654,7 +14892,7 @@ function computeInfra(parsed, params = {}) {
|
|
|
14654
14892
|
targetIds = [edge.targetId];
|
|
14655
14893
|
}
|
|
14656
14894
|
for (const targetId of targetIds) {
|
|
14657
|
-
const perTarget =
|
|
14895
|
+
const perTarget = fanoutedRps / targetIds.length;
|
|
14658
14896
|
const existing = computedRps.get(targetId) ?? 0;
|
|
14659
14897
|
computedRps.set(targetId, existing + perTarget);
|
|
14660
14898
|
const prevLatency = computedLatency.get(targetId) ?? 0;
|
|
@@ -14750,6 +14988,7 @@ function computeInfra(parsed, params = {}) {
|
|
|
14750
14988
|
const resolved = resolveSplits(outbound, []);
|
|
14751
14989
|
const paths = [];
|
|
14752
14990
|
for (const { edge, split } of resolved) {
|
|
14991
|
+
const fanout = edge.fanout != null && edge.fanout >= 1 ? edge.fanout : 1;
|
|
14753
14992
|
const groupChildren = groupChildMap.get(edge.targetId);
|
|
14754
14993
|
const targetIds = groupChildren && groupChildren.length > 0 ? groupChildren : [edge.targetId];
|
|
14755
14994
|
for (const targetId of targetIds) {
|
|
@@ -14760,20 +14999,20 @@ function computeInfra(parsed, params = {}) {
|
|
|
14760
14999
|
latency: nodeLatency + cp.latency,
|
|
14761
15000
|
uptime: nodeUptimeFrac * cp.uptime,
|
|
14762
15001
|
availability: nodeAvail * cp.availability,
|
|
14763
|
-
weight: cp.weight * (split / 100) / targetIds.length * 0.95
|
|
15002
|
+
weight: cp.weight * (split / 100) / targetIds.length * fanout * 0.95
|
|
14764
15003
|
});
|
|
14765
15004
|
paths.push({
|
|
14766
15005
|
latency: coldLatency + cp.latency,
|
|
14767
15006
|
uptime: nodeUptimeFrac * cp.uptime,
|
|
14768
15007
|
availability: nodeAvail * cp.availability,
|
|
14769
|
-
weight: cp.weight * (split / 100) / targetIds.length * 0.05
|
|
15008
|
+
weight: cp.weight * (split / 100) / targetIds.length * fanout * 0.05
|
|
14770
15009
|
});
|
|
14771
15010
|
} else {
|
|
14772
15011
|
paths.push({
|
|
14773
15012
|
latency: nodeLatency + cp.latency,
|
|
14774
15013
|
uptime: nodeUptimeFrac * cp.uptime,
|
|
14775
15014
|
availability: nodeAvail * cp.availability,
|
|
14776
|
-
weight: cp.weight * (split / 100) / targetIds.length
|
|
15015
|
+
weight: cp.weight * (split / 100) / targetIds.length * fanout
|
|
14777
15016
|
});
|
|
14778
15017
|
}
|
|
14779
15018
|
}
|
|
@@ -14928,6 +15167,7 @@ function computeInfra(parsed, params = {}) {
|
|
|
14928
15167
|
queueMetrics,
|
|
14929
15168
|
properties: node.properties,
|
|
14930
15169
|
tags: node.tags,
|
|
15170
|
+
description: node.description,
|
|
14931
15171
|
lineNumber: node.lineNumber
|
|
14932
15172
|
};
|
|
14933
15173
|
});
|
|
@@ -14952,6 +15192,7 @@ function computeInfra(parsed, params = {}) {
|
|
|
14952
15192
|
label: edge.label,
|
|
14953
15193
|
computedRps: rps,
|
|
14954
15194
|
split: resolvedSplit,
|
|
15195
|
+
fanout: edge.fanout,
|
|
14955
15196
|
lineNumber: edge.lineNumber
|
|
14956
15197
|
};
|
|
14957
15198
|
});
|
|
@@ -14978,7 +15219,8 @@ var init_compute = __esm({
|
|
|
14978
15219
|
// src/infra/layout.ts
|
|
14979
15220
|
var layout_exports8 = {};
|
|
14980
15221
|
__export(layout_exports8, {
|
|
14981
|
-
layoutInfra: () => layoutInfra
|
|
15222
|
+
layoutInfra: () => layoutInfra,
|
|
15223
|
+
separateGroups: () => separateGroups
|
|
14982
15224
|
});
|
|
14983
15225
|
import dagre7 from "@dagrejs/dagre";
|
|
14984
15226
|
function countDisplayProps(node, expanded, options) {
|
|
@@ -15045,7 +15287,7 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
15045
15287
|
if (expanded) {
|
|
15046
15288
|
allKeys.push("p50", "p90", "p99");
|
|
15047
15289
|
} else {
|
|
15048
|
-
allKeys.push("
|
|
15290
|
+
allKeys.push("p90");
|
|
15049
15291
|
}
|
|
15050
15292
|
}
|
|
15051
15293
|
if (node.computedUptime < 1) {
|
|
@@ -15087,13 +15329,21 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
15087
15329
|
}
|
|
15088
15330
|
if (computedRows > 0) {
|
|
15089
15331
|
const perc = node.computedLatencyPercentiles;
|
|
15090
|
-
const msValues = expanded ? [perc.p50, perc.p90, perc.p99] : [perc.
|
|
15332
|
+
const msValues = expanded ? [perc.p50, perc.p90, perc.p99] : [perc.p90];
|
|
15091
15333
|
for (const ms of msValues) {
|
|
15092
15334
|
if (ms > 0) {
|
|
15093
15335
|
const valLen = formatMs(ms).length;
|
|
15094
15336
|
maxRowWidth = Math.max(maxRowWidth, (maxKeyLen + 2 + valLen) * META_CHAR_WIDTH3);
|
|
15095
15337
|
}
|
|
15096
15338
|
}
|
|
15339
|
+
if (perc.p90 > 0) {
|
|
15340
|
+
const rawThreshold = node.properties.find((p) => p.key === "slo-p90-latency-ms")?.value ?? options?.["slo-p90-latency-ms"];
|
|
15341
|
+
const threshold = rawThreshold != null ? parseFloat(String(rawThreshold)) : NaN;
|
|
15342
|
+
if (!isNaN(threshold) && threshold > 0) {
|
|
15343
|
+
const combinedVal = `${formatMs(perc.p90)} / ${formatMs(threshold)}`;
|
|
15344
|
+
maxRowWidth = Math.max(maxRowWidth, (maxKeyLen + 2 + combinedVal.length) * META_CHAR_WIDTH3);
|
|
15345
|
+
}
|
|
15346
|
+
}
|
|
15097
15347
|
if (node.computedUptime < 1) {
|
|
15098
15348
|
const valLen = formatUptime(node.computedUptime).length;
|
|
15099
15349
|
maxRowWidth = Math.max(maxRowWidth, (maxKeyLen + 2 + valLen) * META_CHAR_WIDTH3);
|
|
@@ -15106,21 +15356,26 @@ function computeNodeWidth2(node, expanded, options) {
|
|
|
15106
15356
|
maxRowWidth = Math.max(maxRowWidth, "CB: OPEN".length * META_CHAR_WIDTH3 + 8);
|
|
15107
15357
|
}
|
|
15108
15358
|
}
|
|
15109
|
-
|
|
15359
|
+
const DESC_MAX_CHARS2 = 120;
|
|
15360
|
+
const descText = expanded && node.description && !node.isEdge ? node.description : "";
|
|
15361
|
+
const descTruncated = descText.length > DESC_MAX_CHARS2 ? descText.slice(0, DESC_MAX_CHARS2 - 1) + "\u2026" : descText;
|
|
15362
|
+
const descWidth = descTruncated.length > 0 ? descTruncated.length * META_CHAR_WIDTH3 + PADDING_X3 : 0;
|
|
15363
|
+
return Math.max(MIN_NODE_WIDTH2, labelWidth, maxRowWidth + 20, descWidth);
|
|
15110
15364
|
}
|
|
15111
15365
|
function computeNodeHeight2(node, expanded, options) {
|
|
15112
15366
|
const propCount = countDisplayProps(node, expanded, options);
|
|
15113
15367
|
const computedCount = countComputedRows(node, expanded);
|
|
15114
15368
|
const hasRps = node.computedRps > 0;
|
|
15115
|
-
|
|
15116
|
-
|
|
15369
|
+
const descH = expanded && node.description && !node.isEdge ? META_LINE_HEIGHT7 : 0;
|
|
15370
|
+
if (propCount === 0 && computedCount === 0 && !hasRps) return NODE_HEADER_HEIGHT + descH + NODE_PAD_BOTTOM;
|
|
15371
|
+
let h = NODE_HEADER_HEIGHT + descH + NODE_SEPARATOR_GAP;
|
|
15117
15372
|
const computedSectionCount = (hasRps ? 1 : 0) + computedCount;
|
|
15118
15373
|
h += computedSectionCount * META_LINE_HEIGHT7;
|
|
15119
15374
|
if (computedSectionCount > 0 && propCount > 0) h += NODE_SEPARATOR_GAP;
|
|
15120
15375
|
h += propCount * META_LINE_HEIGHT7;
|
|
15121
15376
|
if (hasRoles(node)) h += ROLE_DOT_ROW;
|
|
15122
15377
|
h += NODE_PAD_BOTTOM;
|
|
15123
|
-
if (node.id.startsWith("[")) h +=
|
|
15378
|
+
if (node.id.startsWith("[")) h += COLLAPSE_BAR_HEIGHT4;
|
|
15124
15379
|
return h;
|
|
15125
15380
|
}
|
|
15126
15381
|
function formatRps(rps) {
|
|
@@ -15147,7 +15402,36 @@ function formatUptime(fraction) {
|
|
|
15147
15402
|
if (pct >= 99) return `${pct.toFixed(1)}%`;
|
|
15148
15403
|
return `${pct.toFixed(1)}%`;
|
|
15149
15404
|
}
|
|
15150
|
-
function
|
|
15405
|
+
function separateGroups(groups, nodes, isLR, maxIterations = 20) {
|
|
15406
|
+
for (let iter = 0; iter < maxIterations; iter++) {
|
|
15407
|
+
let anyOverlap = false;
|
|
15408
|
+
for (let i = 0; i < groups.length; i++) {
|
|
15409
|
+
for (let j = i + 1; j < groups.length; j++) {
|
|
15410
|
+
const ga = groups[i];
|
|
15411
|
+
const gb = groups[j];
|
|
15412
|
+
const primaryOverlap = isLR ? Math.min(ga.y + ga.height, gb.y + gb.height) - Math.max(ga.y, gb.y) : Math.min(ga.x + ga.width, gb.x + gb.width) - Math.max(ga.x, gb.x);
|
|
15413
|
+
if (primaryOverlap <= 0) continue;
|
|
15414
|
+
const crossOverlap = isLR ? Math.min(ga.x + ga.width, gb.x + gb.width) - Math.max(ga.x, gb.x) : Math.min(ga.y + ga.height, gb.y + gb.height) - Math.max(ga.y, gb.y);
|
|
15415
|
+
if (crossOverlap <= 0) continue;
|
|
15416
|
+
anyOverlap = true;
|
|
15417
|
+
const shift = primaryOverlap + GROUP_GAP;
|
|
15418
|
+
const aCenter = isLR ? ga.y + ga.height / 2 : ga.x + ga.width / 2;
|
|
15419
|
+
const bCenter = isLR ? gb.y + gb.height / 2 : gb.x + gb.width / 2;
|
|
15420
|
+
const groupToShift = aCenter <= bCenter ? gb : ga;
|
|
15421
|
+
if (isLR) groupToShift.y += shift;
|
|
15422
|
+
else groupToShift.x += shift;
|
|
15423
|
+
for (const node of nodes) {
|
|
15424
|
+
if (node.groupId === groupToShift.id) {
|
|
15425
|
+
if (isLR) node.y += shift;
|
|
15426
|
+
else node.x += shift;
|
|
15427
|
+
}
|
|
15428
|
+
}
|
|
15429
|
+
}
|
|
15430
|
+
}
|
|
15431
|
+
if (!anyOverlap) break;
|
|
15432
|
+
}
|
|
15433
|
+
}
|
|
15434
|
+
function layoutInfra(computed, expandedNodeIds, collapsedNodes) {
|
|
15151
15435
|
if (computed.nodes.length === 0) {
|
|
15152
15436
|
return { nodes: [], edges: [], groups: [], options: {}, width: 0, height: 0 };
|
|
15153
15437
|
}
|
|
@@ -15169,7 +15453,7 @@ function layoutInfra(computed, selectedNodeId, collapsedNodes) {
|
|
|
15169
15453
|
const heightMap = /* @__PURE__ */ new Map();
|
|
15170
15454
|
for (const node of computed.nodes) {
|
|
15171
15455
|
const isNodeCollapsed = collapsedNodes?.has(node.id) ?? false;
|
|
15172
|
-
const expanded = !isNodeCollapsed && node.id
|
|
15456
|
+
const expanded = !isNodeCollapsed && (expandedNodeIds?.has(node.id) ?? false);
|
|
15173
15457
|
const width = computeNodeWidth2(node, expanded, computed.options);
|
|
15174
15458
|
const height = isNodeCollapsed ? NODE_HEADER_HEIGHT + NODE_PAD_BOTTOM : computeNodeHeight2(node, expanded, computed.options);
|
|
15175
15459
|
widthMap.set(node.id, width);
|
|
@@ -15230,6 +15514,7 @@ function layoutInfra(computed, selectedNodeId, collapsedNodes) {
|
|
|
15230
15514
|
queueMetrics: node.queueMetrics,
|
|
15231
15515
|
properties: node.properties,
|
|
15232
15516
|
tags: node.tags,
|
|
15517
|
+
description: node.description,
|
|
15233
15518
|
lineNumber: node.lineNumber
|
|
15234
15519
|
};
|
|
15235
15520
|
});
|
|
@@ -15244,6 +15529,7 @@ function layoutInfra(computed, selectedNodeId, collapsedNodes) {
|
|
|
15244
15529
|
label: edge.label,
|
|
15245
15530
|
computedRps: edge.computedRps,
|
|
15246
15531
|
split: edge.split,
|
|
15532
|
+
fanout: edge.fanout,
|
|
15247
15533
|
points: edgeData?.points ?? [],
|
|
15248
15534
|
lineNumber: edge.lineNumber
|
|
15249
15535
|
});
|
|
@@ -15255,6 +15541,7 @@ function layoutInfra(computed, selectedNodeId, collapsedNodes) {
|
|
|
15255
15541
|
label: edge.label,
|
|
15256
15542
|
computedRps: edge.computedRps,
|
|
15257
15543
|
split: edge.split,
|
|
15544
|
+
fanout: edge.fanout,
|
|
15258
15545
|
points: edgeData?.points ?? [],
|
|
15259
15546
|
lineNumber: edge.lineNumber
|
|
15260
15547
|
});
|
|
@@ -15296,6 +15583,7 @@ function layoutInfra(computed, selectedNodeId, collapsedNodes) {
|
|
|
15296
15583
|
lineNumber: group.lineNumber
|
|
15297
15584
|
};
|
|
15298
15585
|
});
|
|
15586
|
+
separateGroups(layoutGroups, layoutNodes, isLR);
|
|
15299
15587
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
15300
15588
|
for (const node of layoutNodes) {
|
|
15301
15589
|
const left = node.x - node.width / 2;
|
|
@@ -15357,7 +15645,7 @@ function layoutInfra(computed, selectedNodeId, collapsedNodes) {
|
|
|
15357
15645
|
height: totalHeight
|
|
15358
15646
|
};
|
|
15359
15647
|
}
|
|
15360
|
-
var MIN_NODE_WIDTH2, NODE_HEADER_HEIGHT, META_LINE_HEIGHT7, NODE_SEPARATOR_GAP, NODE_PAD_BOTTOM, ROLE_DOT_ROW,
|
|
15648
|
+
var MIN_NODE_WIDTH2, NODE_HEADER_HEIGHT, META_LINE_HEIGHT7, NODE_SEPARATOR_GAP, NODE_PAD_BOTTOM, ROLE_DOT_ROW, COLLAPSE_BAR_HEIGHT4, CHAR_WIDTH6, META_CHAR_WIDTH3, PADDING_X3, GROUP_PADDING3, GROUP_HEADER_HEIGHT, EDGE_MARGIN, DISPLAY_KEYS, DISPLAY_NAMES, GROUP_GAP;
|
|
15361
15649
|
var init_layout8 = __esm({
|
|
15362
15650
|
"src/infra/layout.ts"() {
|
|
15363
15651
|
"use strict";
|
|
@@ -15367,7 +15655,7 @@ var init_layout8 = __esm({
|
|
|
15367
15655
|
NODE_SEPARATOR_GAP = 4;
|
|
15368
15656
|
NODE_PAD_BOTTOM = 10;
|
|
15369
15657
|
ROLE_DOT_ROW = 12;
|
|
15370
|
-
|
|
15658
|
+
COLLAPSE_BAR_HEIGHT4 = 6;
|
|
15371
15659
|
CHAR_WIDTH6 = 7;
|
|
15372
15660
|
META_CHAR_WIDTH3 = 6;
|
|
15373
15661
|
PADDING_X3 = 24;
|
|
@@ -15395,11 +15683,11 @@ var init_layout8 = __esm({
|
|
|
15395
15683
|
DISPLAY_NAMES = {
|
|
15396
15684
|
"cache-hit": "cache hit",
|
|
15397
15685
|
"firewall-block": "fw block",
|
|
15398
|
-
"ratelimit-rps": "rate limit",
|
|
15686
|
+
"ratelimit-rps": "rate limit RPS",
|
|
15399
15687
|
"latency-ms": "latency",
|
|
15400
15688
|
"uptime": "uptime",
|
|
15401
15689
|
"instances": "instances",
|
|
15402
|
-
"max-rps": "
|
|
15690
|
+
"max-rps": "max RPS",
|
|
15403
15691
|
"cb-error-threshold": "CB error",
|
|
15404
15692
|
"cb-latency-threshold-ms": "CB latency",
|
|
15405
15693
|
"concurrency": "concurrency",
|
|
@@ -15410,6 +15698,7 @@ var init_layout8 = __esm({
|
|
|
15410
15698
|
"retention-hours": "retention",
|
|
15411
15699
|
"partitions": "partitions"
|
|
15412
15700
|
};
|
|
15701
|
+
GROUP_GAP = 24;
|
|
15413
15702
|
}
|
|
15414
15703
|
});
|
|
15415
15704
|
|
|
@@ -15424,6 +15713,13 @@ function inferRoles(properties) {
|
|
|
15424
15713
|
}
|
|
15425
15714
|
return roles;
|
|
15426
15715
|
}
|
|
15716
|
+
function collectFanoutSourceIds(edges) {
|
|
15717
|
+
const ids = /* @__PURE__ */ new Set();
|
|
15718
|
+
for (const e of edges) {
|
|
15719
|
+
if (e.fanout != null) ids.add(e.sourceId);
|
|
15720
|
+
}
|
|
15721
|
+
return ids;
|
|
15722
|
+
}
|
|
15427
15723
|
function collectDiagramRoles(allProperties) {
|
|
15428
15724
|
const seen = /* @__PURE__ */ new Set();
|
|
15429
15725
|
const roles = [];
|
|
@@ -15437,7 +15733,7 @@ function collectDiagramRoles(allProperties) {
|
|
|
15437
15733
|
}
|
|
15438
15734
|
return roles;
|
|
15439
15735
|
}
|
|
15440
|
-
var ROLE_RULES;
|
|
15736
|
+
var ROLE_RULES, FANOUT_ROLE;
|
|
15441
15737
|
var init_roles = __esm({
|
|
15442
15738
|
"src/infra/roles.ts"() {
|
|
15443
15739
|
"use strict";
|
|
@@ -15450,6 +15746,7 @@ var init_roles = __esm({
|
|
|
15450
15746
|
{ keys: ["concurrency"], role: { name: "Serverless", color: "#06b6d4" } },
|
|
15451
15747
|
{ keys: ["buffer"], role: { name: "Queue", color: "#8b5cf6" } }
|
|
15452
15748
|
];
|
|
15749
|
+
FANOUT_ROLE = { name: "Fan-Out", color: "#f97316" };
|
|
15453
15750
|
}
|
|
15454
15751
|
});
|
|
15455
15752
|
|
|
@@ -15462,6 +15759,20 @@ __export(renderer_exports8, {
|
|
|
15462
15759
|
});
|
|
15463
15760
|
import * as d3Selection9 from "d3-selection";
|
|
15464
15761
|
import * as d3Shape7 from "d3-shape";
|
|
15762
|
+
function resolveNodeSlo(node, diagramOptions) {
|
|
15763
|
+
const nodeProp = (key) => node.properties.find((p) => p.key === key);
|
|
15764
|
+
const availRaw = nodeProp("slo-availability")?.value ?? diagramOptions["slo-availability"];
|
|
15765
|
+
const latencyRaw = nodeProp("slo-p90-latency-ms")?.value ?? diagramOptions["slo-p90-latency-ms"];
|
|
15766
|
+
const marginRaw = nodeProp("slo-warning-margin")?.value ?? diagramOptions["slo-warning-margin"];
|
|
15767
|
+
const availParsed = availRaw != null ? parseFloat(String(availRaw).replace("%", "")) / 100 : NaN;
|
|
15768
|
+
const availThreshold = !isNaN(availParsed) ? availParsed : null;
|
|
15769
|
+
const latencyParsed = latencyRaw != null ? parseFloat(String(latencyRaw)) : NaN;
|
|
15770
|
+
const latencyP90 = !isNaN(latencyParsed) ? latencyParsed : null;
|
|
15771
|
+
const marginParsed = marginRaw != null ? parseFloat(String(marginRaw).replace("%", "")) / 100 : NaN;
|
|
15772
|
+
const warningMargin = !isNaN(marginParsed) ? marginParsed : 0.05;
|
|
15773
|
+
if (availThreshold == null && latencyP90 == null) return null;
|
|
15774
|
+
return { availThreshold, latencyP90, warningMargin };
|
|
15775
|
+
}
|
|
15465
15776
|
function nodeBorderPoint(node, target) {
|
|
15466
15777
|
const hw = node.width / 2;
|
|
15467
15778
|
const hh = node.height / 2;
|
|
@@ -15498,7 +15809,17 @@ function isWarning(node) {
|
|
|
15498
15809
|
const cap = Number(maxRps.value) * node.computedInstances;
|
|
15499
15810
|
return cap > 0 && node.computedRps / cap > 0.7;
|
|
15500
15811
|
}
|
|
15501
|
-
function
|
|
15812
|
+
function truncateDesc(text) {
|
|
15813
|
+
if (text.length <= DESC_MAX_CHARS) return text;
|
|
15814
|
+
return text.slice(0, DESC_MAX_CHARS - 1) + "\u2026";
|
|
15815
|
+
}
|
|
15816
|
+
function sloLatencyColor(p90, slo) {
|
|
15817
|
+
const t = slo.latencyP90 ?? 0;
|
|
15818
|
+
if (t === 0) return COLOR_HEALTHY;
|
|
15819
|
+
const m = slo.warningMargin;
|
|
15820
|
+
return p90 > t ? COLOR_OVERLOADED : p90 > t * (1 - m) ? COLOR_WARNING : COLOR_HEALTHY;
|
|
15821
|
+
}
|
|
15822
|
+
function getComputedRows(node, expanded, slo) {
|
|
15502
15823
|
const rows = [];
|
|
15503
15824
|
if (node.computedConcurrentInvocations > 0) {
|
|
15504
15825
|
const concurrency = getNodeNumProp(node, "concurrency", 0);
|
|
@@ -15512,9 +15833,23 @@ function getComputedRows(node, expanded) {
|
|
|
15512
15833
|
if (p.p50 > 0 || p.p90 > 0 || p.p99 > 0) {
|
|
15513
15834
|
if (expanded) {
|
|
15514
15835
|
rows.push({ key: "p50", value: formatMsShort(p.p50) });
|
|
15515
|
-
|
|
15836
|
+
if (slo?.latencyP90 != null) {
|
|
15837
|
+
const color = sloLatencyColor(p.p90, slo);
|
|
15838
|
+
const p90Value = color !== COLOR_HEALTHY ? `${formatMsShort(p.p90)} / ${formatMsShort(slo.latencyP90)}` : formatMsShort(p.p90);
|
|
15839
|
+
rows.push({ key: "p90", value: p90Value, color, inverted: color !== COLOR_HEALTHY });
|
|
15840
|
+
} else {
|
|
15841
|
+
rows.push({ key: "p90", value: formatMsShort(p.p90) });
|
|
15842
|
+
}
|
|
15843
|
+
rows.push({ key: "p99", value: formatMsShort(p.p99) });
|
|
15844
|
+
} else if (p.p90 > 0) {
|
|
15845
|
+
if (slo?.latencyP90 != null) {
|
|
15846
|
+
const color = sloLatencyColor(p.p90, slo);
|
|
15847
|
+
const p90Value = color !== COLOR_HEALTHY ? `${formatMsShort(p.p90)} / ${formatMsShort(slo.latencyP90)}` : formatMsShort(p.p90);
|
|
15848
|
+
rows.push({ key: "p90", value: p90Value, color, inverted: color !== COLOR_HEALTHY });
|
|
15849
|
+
} else {
|
|
15850
|
+
rows.push({ key: "p90", value: formatMsShort(p.p90) });
|
|
15851
|
+
}
|
|
15516
15852
|
}
|
|
15517
|
-
rows.push({ key: "p99", value: formatMsShort(p.p99) });
|
|
15518
15853
|
}
|
|
15519
15854
|
if (node.computedUptime < 1) {
|
|
15520
15855
|
const declaredUptime = node.properties.find((p2) => p2.key === "uptime");
|
|
@@ -15525,8 +15860,17 @@ function getComputedRows(node, expanded) {
|
|
|
15525
15860
|
}
|
|
15526
15861
|
}
|
|
15527
15862
|
if (node.computedAvailability < 1) {
|
|
15528
|
-
|
|
15529
|
-
|
|
15863
|
+
let color;
|
|
15864
|
+
if (slo?.availThreshold != null) {
|
|
15865
|
+
const t = slo.availThreshold;
|
|
15866
|
+
const m = slo.warningMargin;
|
|
15867
|
+
if (node.computedAvailability < t) color = COLOR_OVERLOADED;
|
|
15868
|
+
else if (node.computedAvailability < Math.min(1, t + m)) color = COLOR_WARNING;
|
|
15869
|
+
else color = COLOR_HEALTHY;
|
|
15870
|
+
} else {
|
|
15871
|
+
color = node.computedAvailability < 0.95 ? COLOR_OVERLOADED : node.computedAvailability < 0.99 ? COLOR_WARNING : void 0;
|
|
15872
|
+
}
|
|
15873
|
+
rows.push({ key: "availability", value: formatUptimeShort(node.computedAvailability), color, inverted: color != null && color !== COLOR_HEALTHY });
|
|
15530
15874
|
}
|
|
15531
15875
|
if (node.computedCbState === "open") {
|
|
15532
15876
|
rows.push({ key: "CB", value: "OPEN", color: COLOR_OVERLOADED, inverted: true });
|
|
@@ -15614,7 +15958,7 @@ function formatRpsShort2(rps) {
|
|
|
15614
15958
|
if (rps >= 1e3) return `${(rps / 1e3).toFixed(1)}k`;
|
|
15615
15959
|
return `${Math.round(rps)}`;
|
|
15616
15960
|
}
|
|
15617
|
-
function worstNodeSeverity(node) {
|
|
15961
|
+
function worstNodeSeverity(node, slo) {
|
|
15618
15962
|
let worst = "normal";
|
|
15619
15963
|
const upgrade = (s) => {
|
|
15620
15964
|
if (s === "overloaded") worst = "overloaded";
|
|
@@ -15625,8 +15969,22 @@ function worstNodeSeverity(node) {
|
|
|
15625
15969
|
if (node.overloaded) upgrade("overloaded");
|
|
15626
15970
|
if (node.rateLimited) upgrade("warning");
|
|
15627
15971
|
if (isWarning(node)) upgrade("warning");
|
|
15628
|
-
if (
|
|
15629
|
-
|
|
15972
|
+
if (slo?.availThreshold != null) {
|
|
15973
|
+
const t = slo.availThreshold;
|
|
15974
|
+
const m = slo.warningMargin;
|
|
15975
|
+
if (node.computedAvailability < t) upgrade("overloaded");
|
|
15976
|
+
else if (node.computedAvailability < Math.min(1, t + m)) upgrade("warning");
|
|
15977
|
+
} else {
|
|
15978
|
+
if (node.computedAvailability < 0.95) upgrade("overloaded");
|
|
15979
|
+
else if (node.computedAvailability < 0.99) upgrade("warning");
|
|
15980
|
+
}
|
|
15981
|
+
if (slo?.latencyP90 != null) {
|
|
15982
|
+
const t = slo.latencyP90;
|
|
15983
|
+
const m = slo.warningMargin;
|
|
15984
|
+
const p90 = node.computedLatencyPercentiles.p90;
|
|
15985
|
+
if (p90 > t) upgrade("overloaded");
|
|
15986
|
+
else if (p90 > t * (1 - m)) upgrade("warning");
|
|
15987
|
+
}
|
|
15630
15988
|
if (node.computedCbState === "open") upgrade("overloaded");
|
|
15631
15989
|
if (node.queueMetrics && node.queueMetrics.fillRate > 0) {
|
|
15632
15990
|
if (node.queueMetrics.timeToOverflow < 60) upgrade("overloaded");
|
|
@@ -15644,10 +16002,14 @@ function worstNodeSeverity(node) {
|
|
|
15644
16002
|
else if (preRl > nodeRateLimit * 0.8) upgrade("warning");
|
|
15645
16003
|
}
|
|
15646
16004
|
}
|
|
16005
|
+
if (worst === "normal" && slo != null) {
|
|
16006
|
+
const availGreen = slo.availThreshold == null || node.computedAvailability >= Math.min(1, slo.availThreshold + slo.warningMargin);
|
|
16007
|
+
const latencyGreen = slo.latencyP90 == null || node.computedLatencyPercentiles.p90 <= slo.latencyP90 * (1 - slo.warningMargin);
|
|
16008
|
+
if (availGreen && latencyGreen) return "healthy";
|
|
16009
|
+
}
|
|
15647
16010
|
return worst;
|
|
15648
16011
|
}
|
|
15649
|
-
function nodeColor(
|
|
15650
|
-
const severity = worstNodeSeverity(node);
|
|
16012
|
+
function nodeColor(_node, palette, isDark, severity) {
|
|
15651
16013
|
if (severity === "overloaded") {
|
|
15652
16014
|
return {
|
|
15653
16015
|
fill: mix(palette.bg, COLOR_OVERLOADED, isDark ? 80 : 92),
|
|
@@ -15662,6 +16024,13 @@ function nodeColor(node, palette, isDark) {
|
|
|
15662
16024
|
textFill: palette.text
|
|
15663
16025
|
};
|
|
15664
16026
|
}
|
|
16027
|
+
if (severity === "healthy") {
|
|
16028
|
+
return {
|
|
16029
|
+
fill: mix(palette.bg, COLOR_HEALTHY, isDark ? 85 : 93),
|
|
16030
|
+
stroke: COLOR_HEALTHY,
|
|
16031
|
+
textFill: palette.text
|
|
16032
|
+
};
|
|
16033
|
+
}
|
|
15665
16034
|
return {
|
|
15666
16035
|
fill: isDark ? mix(palette.bg, palette.text, 90) : mix(palette.bg, palette.text, 95),
|
|
15667
16036
|
stroke: isDark ? mix(palette.text, palette.bg, 60) : mix(palette.text, palette.bg, 40),
|
|
@@ -15755,10 +16124,12 @@ function resolveActiveTagStroke(node, activeGroup, tagGroups, palette) {
|
|
|
15755
16124
|
if (!tv?.color) return null;
|
|
15756
16125
|
return resolveColor(tv.color, palette);
|
|
15757
16126
|
}
|
|
15758
|
-
function renderNodes(svg, nodes, palette, isDark, animate,
|
|
16127
|
+
function renderNodes(svg, nodes, palette, isDark, animate, expandedNodeIds, activeGroup, diagramOptions, collapsedNodes, tagGroups, fanoutSourceIds, scaledGroupIds) {
|
|
15759
16128
|
const mutedColor = palette.textMuted;
|
|
15760
16129
|
for (const node of nodes) {
|
|
15761
|
-
|
|
16130
|
+
const slo = !node.isEdge && diagramOptions ? resolveNodeSlo(node, diagramOptions) : null;
|
|
16131
|
+
const severity = worstNodeSeverity(node, slo);
|
|
16132
|
+
let { fill: fill2, stroke: stroke2, textFill } = nodeColor(node, palette, isDark, severity);
|
|
15762
16133
|
if (activeGroup && tagGroups && !node.isEdge) {
|
|
15763
16134
|
const tagStroke = resolveActiveTagStroke(node, activeGroup, tagGroups, palette);
|
|
15764
16135
|
if (tagStroke) {
|
|
@@ -15770,7 +16141,6 @@ function renderNodes(svg, nodes, palette, isDark, animate, selectedNodeId, activ
|
|
|
15770
16141
|
if (animate && node.isEdge) {
|
|
15771
16142
|
cls += " infra-node-edge-throb";
|
|
15772
16143
|
} else if (animate && !node.isEdge) {
|
|
15773
|
-
const severity = worstNodeSeverity(node);
|
|
15774
16144
|
if (node.computedCbState === "open") cls += " infra-node-cb-open";
|
|
15775
16145
|
else if (severity === "overloaded") cls += " infra-node-overload";
|
|
15776
16146
|
else if (severity === "warning") cls += " infra-node-warning";
|
|
@@ -15787,26 +16157,36 @@ function renderNodes(svg, nodes, palette, isDark, animate, selectedNodeId, activ
|
|
|
15787
16157
|
for (const role of roles) {
|
|
15788
16158
|
g.attr(`data-role-${role.name.toLowerCase().replace(/\s+/g, "-")}`, "true");
|
|
15789
16159
|
}
|
|
16160
|
+
if (fanoutSourceIds?.has(node.id)) {
|
|
16161
|
+
g.attr("data-role-fan-out", "true");
|
|
16162
|
+
}
|
|
15790
16163
|
}
|
|
15791
16164
|
const x = node.x - node.width / 2;
|
|
15792
16165
|
const y = node.y - node.height / 2;
|
|
15793
16166
|
const isCollapsedGroup = node.id.startsWith("[");
|
|
15794
|
-
const strokeWidth =
|
|
16167
|
+
const strokeWidth = severity !== "normal" ? OVERLOAD_STROKE_WIDTH : NODE_STROKE_WIDTH8;
|
|
15795
16168
|
g.append("rect").attr("x", x).attr("y", y).attr("width", node.width).attr("height", node.height).attr("rx", NODE_BORDER_RADIUS).attr("fill", fill2).attr("stroke", stroke2).attr("stroke-width", strokeWidth);
|
|
15796
|
-
const headerCenterY = y + NODE_HEADER_HEIGHT2 / 2 +
|
|
15797
|
-
g.append("text").attr("x", node.x).attr("y", headerCenterY).attr("text-anchor", "middle").attr("font-family", FONT_FAMILY).attr("font-size",
|
|
16169
|
+
const headerCenterY = y + NODE_HEADER_HEIGHT2 / 2 + NODE_FONT_SIZE4 * 0.35;
|
|
16170
|
+
g.append("text").attr("x", node.x).attr("y", headerCenterY).attr("text-anchor", "middle").attr("font-family", FONT_FAMILY).attr("font-size", NODE_FONT_SIZE4).attr("font-weight", "600").attr("fill", textFill).text(node.label);
|
|
15798
16171
|
const isNodeCollapsed = collapsedNodes?.has(node.id) ?? false;
|
|
15799
16172
|
if (isNodeCollapsed) {
|
|
15800
16173
|
const chevronY = y + node.height - 6;
|
|
15801
16174
|
g.append("text").attr("x", node.x).attr("y", chevronY).attr("text-anchor", "middle").attr("font-family", FONT_FAMILY).attr("font-size", 8).attr("fill", textFill).attr("opacity", 0.5).text("\u25BC");
|
|
15802
16175
|
}
|
|
15803
16176
|
if (!isNodeCollapsed) {
|
|
15804
|
-
const expanded = node.id
|
|
16177
|
+
const expanded = expandedNodeIds?.has(node.id) ?? false;
|
|
16178
|
+
const descH = expanded && node.description && !node.isEdge ? META_LINE_HEIGHT8 : 0;
|
|
16179
|
+
if (descH > 0 && node.description) {
|
|
16180
|
+
const descTruncated = truncateDesc(node.description);
|
|
16181
|
+
const isTruncated = descTruncated !== node.description;
|
|
16182
|
+
const textEl = g.append("text").attr("x", node.x).attr("y", y + NODE_HEADER_HEIGHT2 + META_LINE_HEIGHT8 / 2 + META_FONT_SIZE4 * 0.35).attr("text-anchor", "middle").attr("font-family", FONT_FAMILY).attr("font-size", META_FONT_SIZE4).attr("fill", mutedColor).text(descTruncated);
|
|
16183
|
+
if (isTruncated) textEl.append("title").text(node.description);
|
|
16184
|
+
}
|
|
15805
16185
|
const displayProps = !node.isEdge && expanded ? getDisplayProps(node, expanded, diagramOptions) : [];
|
|
15806
|
-
const computedRows = getComputedRows(node, expanded);
|
|
16186
|
+
const computedRows = getComputedRows(node, expanded, slo);
|
|
15807
16187
|
const hasContent = displayProps.length > 0 || computedRows.length > 0 || node.computedRps > 0;
|
|
15808
16188
|
if (hasContent) {
|
|
15809
|
-
const sepY = y + NODE_HEADER_HEIGHT2;
|
|
16189
|
+
const sepY = y + NODE_HEADER_HEIGHT2 + descH;
|
|
15810
16190
|
g.append("line").attr("x1", x).attr("y1", sepY).attr("x2", x + node.width).attr("y2", sepY).attr("stroke", stroke2).attr("stroke-opacity", 0.3).attr("stroke-width", 1);
|
|
15811
16191
|
const computedSection = [];
|
|
15812
16192
|
const declaredSection = [];
|
|
@@ -15902,14 +16282,15 @@ function renderNodes(svg, nodes, palette, isDark, animate, selectedNodeId, activ
|
|
|
15902
16282
|
rowIdx++;
|
|
15903
16283
|
}
|
|
15904
16284
|
}
|
|
15905
|
-
|
|
16285
|
+
const inScaledGroup = node.groupId != null && (scaledGroupIds?.has(node.groupId) ?? false);
|
|
16286
|
+
if (!node.isEdge && node.computedConcurrentInvocations === 0 && node.computedInstances > 1 && !inScaledGroup) {
|
|
15906
16287
|
const badgeText = `${node.computedInstances}x`;
|
|
15907
16288
|
g.append("text").attr("x", x + node.width - 6).attr("y", y + NODE_HEADER_HEIGHT2 / 2 + META_FONT_SIZE4 * 0.35).attr("text-anchor", "end").attr("font-family", FONT_FAMILY).attr("font-size", META_FONT_SIZE4).attr("fill", mutedColor).attr("data-instance-node", node.id).style("cursor", "pointer").text(badgeText);
|
|
15908
16289
|
}
|
|
15909
16290
|
const showDots = activeGroup != null && activeGroup.toLowerCase() === "capabilities";
|
|
15910
16291
|
const roles = showDots && !node.isEdge ? inferRoles(node.properties) : [];
|
|
15911
16292
|
if (roles.length > 0) {
|
|
15912
|
-
const dotY = isCollapsedGroup ? y + node.height -
|
|
16293
|
+
const dotY = isCollapsedGroup ? y + node.height - COLLAPSE_BAR_HEIGHT5 - NODE_PAD_BOTTOM2 / 2 : y + node.height - NODE_PAD_BOTTOM2 / 2;
|
|
15913
16294
|
const totalDotsWidth = roles.length * (ROLE_DOT_RADIUS * 2 + 2) - 2;
|
|
15914
16295
|
const startX = node.x - totalDotsWidth / 2 + ROLE_DOT_RADIUS;
|
|
15915
16296
|
for (let i = 0; i < roles.length; i++) {
|
|
@@ -15919,7 +16300,7 @@ function renderNodes(svg, nodes, palette, isDark, animate, selectedNodeId, activ
|
|
|
15919
16300
|
if (isCollapsedGroup) {
|
|
15920
16301
|
const clipId = `clip-${node.id.replace(/[[\]\s]/g, "")}`;
|
|
15921
16302
|
g.append("clipPath").attr("id", clipId).append("rect").attr("x", x).attr("y", y).attr("width", node.width).attr("height", node.height).attr("rx", NODE_BORDER_RADIUS);
|
|
15922
|
-
g.append("rect").attr("x", x + COLLAPSE_BAR_INSET2).attr("y", y + node.height -
|
|
16303
|
+
g.append("rect").attr("x", x + COLLAPSE_BAR_INSET2).attr("y", y + node.height - COLLAPSE_BAR_HEIGHT5).attr("width", node.width - COLLAPSE_BAR_INSET2 * 2).attr("height", COLLAPSE_BAR_HEIGHT5).attr("fill", stroke2).attr("clip-path", `url(#${clipId})`).attr("class", "infra-collapse-bar");
|
|
15923
16304
|
}
|
|
15924
16305
|
}
|
|
15925
16306
|
}
|
|
@@ -15988,9 +16369,12 @@ function renderRejectParticles(svg, nodes) {
|
|
|
15988
16369
|
}
|
|
15989
16370
|
}
|
|
15990
16371
|
}
|
|
15991
|
-
function computeInfraLegendGroups(nodes, tagGroups, palette) {
|
|
16372
|
+
function computeInfraLegendGroups(nodes, tagGroups, palette, edges) {
|
|
15992
16373
|
const groups = [];
|
|
15993
16374
|
const roles = collectDiagramRoles(nodes.filter((n) => !n.isEdge).map((n) => n.properties));
|
|
16375
|
+
if (edges && collectFanoutSourceIds(edges).size > 0) {
|
|
16376
|
+
roles.push(FANOUT_ROLE);
|
|
16377
|
+
}
|
|
15994
16378
|
if (roles.length > 0) {
|
|
15995
16379
|
const entries = roles.map((r) => ({
|
|
15996
16380
|
value: r.name,
|
|
@@ -16045,7 +16429,7 @@ function computePlaybackWidth(playback) {
|
|
|
16045
16429
|
let entriesW = 8;
|
|
16046
16430
|
entriesW += LEGEND_PILL_FONT_SIZE5 * 0.8 + 6;
|
|
16047
16431
|
for (const s of playback.speedOptions) {
|
|
16048
|
-
entriesW += `${s}x`.length * LEGEND_ENTRY_FONT_W7 +
|
|
16432
|
+
entriesW += `${s}x`.length * LEGEND_ENTRY_FONT_W7 + SPEED_BADGE_H_PAD * 2 + SPEED_BADGE_GAP;
|
|
16049
16433
|
}
|
|
16050
16434
|
return LEGEND_CAPSULE_PAD7 * 2 + pillWidth + entriesW;
|
|
16051
16435
|
}
|
|
@@ -16116,16 +16500,21 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
16116
16500
|
for (const s of playback.speedOptions) {
|
|
16117
16501
|
const label = `${s}x`;
|
|
16118
16502
|
const isActive = playback.speed === s;
|
|
16119
|
-
|
|
16120
|
-
|
|
16503
|
+
const slotW = label.length * LEGEND_ENTRY_FONT_W7 + SPEED_BADGE_H_PAD * 2;
|
|
16504
|
+
const badgeH = LEGEND_ENTRY_FONT_SIZE6 + SPEED_BADGE_V_PAD * 2;
|
|
16505
|
+
const badgeY = (LEGEND_HEIGHT8 - badgeH) / 2;
|
|
16506
|
+
const speedG = pbG.append("g").attr("data-playback-action", "set-speed").attr("data-playback-value", String(s)).style("cursor", "pointer");
|
|
16507
|
+
speedG.append("rect").attr("x", entryX).attr("y", badgeY).attr("width", slotW).attr("height", badgeH).attr("rx", badgeH / 2).attr("fill", isActive ? palette.primary : "transparent");
|
|
16508
|
+
speedG.append("text").attr("x", entryX + slotW / 2).attr("y", entryY).attr("font-family", FONT_FAMILY).attr("font-size", LEGEND_ENTRY_FONT_SIZE6).attr("font-weight", isActive ? "600" : "400").attr("fill", isActive ? palette.bg : palette.textMuted).attr("text-anchor", "middle").text(label);
|
|
16509
|
+
entryX += slotW + SPEED_BADGE_GAP;
|
|
16121
16510
|
}
|
|
16122
16511
|
}
|
|
16123
16512
|
cursorX += fullW + LEGEND_GROUP_GAP5;
|
|
16124
16513
|
}
|
|
16125
16514
|
}
|
|
16126
|
-
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback,
|
|
16515
|
+
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, expandedNodeIds, exportMode, collapsedNodes) {
|
|
16127
16516
|
d3Selection9.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
16128
|
-
const legendGroups = computeInfraLegendGroups(layout.nodes, tagGroups ?? [], palette);
|
|
16517
|
+
const legendGroups = computeInfraLegendGroups(layout.nodes, tagGroups ?? [], palette, layout.edges);
|
|
16129
16518
|
const hasLegend = legendGroups.length > 0 || !!playback;
|
|
16130
16519
|
const fixedLegend = !exportMode && hasLegend;
|
|
16131
16520
|
const legendOffset = hasLegend && !fixedLegend ? LEGEND_HEIGHT8 : 0;
|
|
@@ -16182,7 +16571,14 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
16182
16571
|
}
|
|
16183
16572
|
renderGroups(svg, layout.groups, palette, isDark);
|
|
16184
16573
|
renderEdgePaths(svg, layout.edges, layout.nodes, palette, isDark, shouldAnimate);
|
|
16185
|
-
|
|
16574
|
+
const fanoutSourceIds = collectFanoutSourceIds(layout.edges);
|
|
16575
|
+
const scaledGroupIds = new Set(
|
|
16576
|
+
layout.groups.filter((g) => {
|
|
16577
|
+
const gi = typeof g.instances === "number" ? g.instances : typeof g.instances === "string" ? parseInt(String(g.instances), 10) || 0 : 0;
|
|
16578
|
+
return gi > 1;
|
|
16579
|
+
}).map((g) => g.id)
|
|
16580
|
+
);
|
|
16581
|
+
renderNodes(svg, layout.nodes, palette, isDark, shouldAnimate, expandedNodeIds, activeGroup, layout.options, collapsedNodes, tagGroups ?? [], fanoutSourceIds, scaledGroupIds);
|
|
16186
16582
|
if (shouldAnimate) {
|
|
16187
16583
|
renderRejectParticles(svg, layout.nodes);
|
|
16188
16584
|
}
|
|
@@ -16204,7 +16600,7 @@ function parseAndLayoutInfra(content) {
|
|
|
16204
16600
|
const layout = layoutInfra(computed);
|
|
16205
16601
|
return { parsed, computed, layout };
|
|
16206
16602
|
}
|
|
16207
|
-
var
|
|
16603
|
+
var NODE_FONT_SIZE4, META_FONT_SIZE4, META_LINE_HEIGHT8, EDGE_LABEL_FONT_SIZE7, GROUP_LABEL_FONT_SIZE2, NODE_BORDER_RADIUS, EDGE_STROKE_WIDTH8, NODE_STROKE_WIDTH8, OVERLOAD_STROKE_WIDTH, ROLE_DOT_RADIUS, NODE_HEADER_HEIGHT2, NODE_SEPARATOR_GAP2, NODE_PAD_BOTTOM2, COLLAPSE_BAR_HEIGHT5, COLLAPSE_BAR_INSET2, LEGEND_HEIGHT8, LEGEND_PILL_PAD7, LEGEND_PILL_FONT_SIZE5, LEGEND_PILL_FONT_W7, LEGEND_CAPSULE_PAD7, LEGEND_DOT_R8, LEGEND_ENTRY_FONT_SIZE6, LEGEND_ENTRY_FONT_W7, LEGEND_ENTRY_DOT_GAP7, LEGEND_ENTRY_TRAIL7, LEGEND_GROUP_GAP5, LEGEND_FIXED_GAP3, SPEED_BADGE_H_PAD, SPEED_BADGE_V_PAD, SPEED_BADGE_GAP, COLOR_HEALTHY, COLOR_WARNING, COLOR_OVERLOADED, FLOW_SPEED_MIN, FLOW_SPEED_MAX, PARTICLE_R, PARTICLE_COUNT_MIN, PARTICLE_COUNT_MAX, NODE_PULSE_SPEED, NODE_PULSE_OVERLOAD, REJECT_PARTICLE_R, REJECT_DROP_DISTANCE, REJECT_DURATION_MIN, REJECT_DURATION_MAX, REJECT_COUNT_MIN, REJECT_COUNT_MAX, lineGenerator7, PROP_DISPLAY, DESC_MAX_CHARS, RPS_FORMAT_KEYS, MS_FORMAT_KEYS, PCT_FORMAT_KEYS;
|
|
16208
16604
|
var init_renderer8 = __esm({
|
|
16209
16605
|
"src/infra/renderer.ts"() {
|
|
16210
16606
|
"use strict";
|
|
@@ -16215,7 +16611,7 @@ var init_renderer8 = __esm({
|
|
|
16215
16611
|
init_parser9();
|
|
16216
16612
|
init_compute();
|
|
16217
16613
|
init_layout8();
|
|
16218
|
-
|
|
16614
|
+
NODE_FONT_SIZE4 = 13;
|
|
16219
16615
|
META_FONT_SIZE4 = 10;
|
|
16220
16616
|
META_LINE_HEIGHT8 = 14;
|
|
16221
16617
|
EDGE_LABEL_FONT_SIZE7 = 11;
|
|
@@ -16228,7 +16624,7 @@ var init_renderer8 = __esm({
|
|
|
16228
16624
|
NODE_HEADER_HEIGHT2 = 28;
|
|
16229
16625
|
NODE_SEPARATOR_GAP2 = 4;
|
|
16230
16626
|
NODE_PAD_BOTTOM2 = 10;
|
|
16231
|
-
|
|
16627
|
+
COLLAPSE_BAR_HEIGHT5 = 6;
|
|
16232
16628
|
COLLAPSE_BAR_INSET2 = 0;
|
|
16233
16629
|
LEGEND_HEIGHT8 = 28;
|
|
16234
16630
|
LEGEND_PILL_PAD7 = 16;
|
|
@@ -16242,6 +16638,10 @@ var init_renderer8 = __esm({
|
|
|
16242
16638
|
LEGEND_ENTRY_TRAIL7 = 8;
|
|
16243
16639
|
LEGEND_GROUP_GAP5 = 12;
|
|
16244
16640
|
LEGEND_FIXED_GAP3 = 16;
|
|
16641
|
+
SPEED_BADGE_H_PAD = 5;
|
|
16642
|
+
SPEED_BADGE_V_PAD = 3;
|
|
16643
|
+
SPEED_BADGE_GAP = 6;
|
|
16644
|
+
COLOR_HEALTHY = "#22c55e";
|
|
16245
16645
|
COLOR_WARNING = "#eab308";
|
|
16246
16646
|
COLOR_OVERLOADED = "#ef4444";
|
|
16247
16647
|
FLOW_SPEED_MIN = 2.5;
|
|
@@ -16260,22 +16660,23 @@ var init_renderer8 = __esm({
|
|
|
16260
16660
|
lineGenerator7 = d3Shape7.line().x((d) => d.x).y((d) => d.y).curve(d3Shape7.curveBasis);
|
|
16261
16661
|
PROP_DISPLAY = {
|
|
16262
16662
|
"cache-hit": "cache hit",
|
|
16263
|
-
"firewall-block": "
|
|
16264
|
-
"ratelimit-rps": "rate limit",
|
|
16663
|
+
"firewall-block": "firewall block",
|
|
16664
|
+
"ratelimit-rps": "rate limit RPS",
|
|
16265
16665
|
"latency-ms": "latency",
|
|
16266
16666
|
"uptime": "uptime",
|
|
16267
16667
|
"instances": "instances",
|
|
16268
|
-
"max-rps": "
|
|
16269
|
-
"cb-error-threshold": "CB error",
|
|
16270
|
-
"cb-latency-threshold-ms": "CB latency",
|
|
16668
|
+
"max-rps": "max RPS",
|
|
16669
|
+
"cb-error-threshold": "CB error threshold",
|
|
16670
|
+
"cb-latency-threshold-ms": "CB latency threshold",
|
|
16271
16671
|
"concurrency": "concurrency",
|
|
16272
16672
|
"duration-ms": "duration",
|
|
16273
16673
|
"cold-start-ms": "cold start",
|
|
16274
16674
|
"buffer": "buffer",
|
|
16275
|
-
"drain-rate": "drain",
|
|
16675
|
+
"drain-rate": "drain rate",
|
|
16276
16676
|
"retention-hours": "retention",
|
|
16277
16677
|
"partitions": "partitions"
|
|
16278
16678
|
};
|
|
16679
|
+
DESC_MAX_CHARS = 120;
|
|
16279
16680
|
RPS_FORMAT_KEYS = /* @__PURE__ */ new Set(["max-rps", "ratelimit-rps"]);
|
|
16280
16681
|
MS_FORMAT_KEYS = /* @__PURE__ */ new Set(["latency-ms", "cb-latency-threshold-ms", "duration-ms", "cold-start-ms"]);
|
|
16281
16682
|
PCT_FORMAT_KEYS = /* @__PURE__ */ new Set(["cache-hit", "firewall-block", "uptime", "cb-error-threshold"]);
|
|
@@ -16466,7 +16867,7 @@ function renderState(container, graph, layout, palette, isDark, onClickItem, exp
|
|
|
16466
16867
|
const w = node.width;
|
|
16467
16868
|
const h = node.height;
|
|
16468
16869
|
nodeG.append("rect").attr("x", -w / 2).attr("y", -h / 2).attr("width", w).attr("height", h).attr("rx", STATE_CORNER_RADIUS).attr("ry", STATE_CORNER_RADIUS).attr("fill", stateFill(palette, isDark, node.color, colorOff)).attr("stroke", stateStroke(palette, node.color, colorOff)).attr("stroke-width", NODE_STROKE_WIDTH9);
|
|
16469
|
-
nodeG.append("text").attr("x", 0).attr("y", 0).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", palette.text).attr("font-size",
|
|
16870
|
+
nodeG.append("text").attr("x", 0).attr("y", 0).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", palette.text).attr("font-size", NODE_FONT_SIZE5).text(node.label);
|
|
16470
16871
|
}
|
|
16471
16872
|
}
|
|
16472
16873
|
}
|
|
@@ -16505,7 +16906,7 @@ function renderStateForExport(content, theme, palette) {
|
|
|
16505
16906
|
document.body.removeChild(container);
|
|
16506
16907
|
}
|
|
16507
16908
|
}
|
|
16508
|
-
var DIAGRAM_PADDING9, MAX_SCALE8,
|
|
16909
|
+
var DIAGRAM_PADDING9, MAX_SCALE8, NODE_FONT_SIZE5, EDGE_LABEL_FONT_SIZE8, GROUP_LABEL_FONT_SIZE3, EDGE_STROKE_WIDTH9, NODE_STROKE_WIDTH9, ARROWHEAD_W4, ARROWHEAD_H4, PSEUDOSTATE_RADIUS, STATE_CORNER_RADIUS, GROUP_EXTRA_PADDING2, lineGenerator8;
|
|
16509
16910
|
var init_state_renderer = __esm({
|
|
16510
16911
|
"src/graph/state-renderer.ts"() {
|
|
16511
16912
|
"use strict";
|
|
@@ -16515,7 +16916,7 @@ var init_state_renderer = __esm({
|
|
|
16515
16916
|
init_layout7();
|
|
16516
16917
|
DIAGRAM_PADDING9 = 20;
|
|
16517
16918
|
MAX_SCALE8 = 3;
|
|
16518
|
-
|
|
16919
|
+
NODE_FONT_SIZE5 = 13;
|
|
16519
16920
|
EDGE_LABEL_FONT_SIZE8 = 11;
|
|
16520
16921
|
GROUP_LABEL_FONT_SIZE3 = 11;
|
|
16521
16922
|
EDGE_STROKE_WIDTH9 = 1.5;
|
|
@@ -18127,7 +18528,6 @@ function parseD3(content, palette) {
|
|
|
18127
18528
|
timelineSwimlanes: false,
|
|
18128
18529
|
vennSets: [],
|
|
18129
18530
|
vennOverlaps: [],
|
|
18130
|
-
vennShowValues: false,
|
|
18131
18531
|
quadrantLabels: {
|
|
18132
18532
|
topRight: null,
|
|
18133
18533
|
topLeft: null,
|
|
@@ -18149,6 +18549,9 @@ function parseD3(content, palette) {
|
|
|
18149
18549
|
result.error = formatDgmoError(diag);
|
|
18150
18550
|
return result;
|
|
18151
18551
|
};
|
|
18552
|
+
const warn = (line10, message) => {
|
|
18553
|
+
result.diagnostics.push(makeDgmoError(line10, message, "warning"));
|
|
18554
|
+
};
|
|
18152
18555
|
if (!content || !content.trim()) {
|
|
18153
18556
|
return fail(0, "Empty content");
|
|
18154
18557
|
}
|
|
@@ -18344,25 +18747,38 @@ function parseD3(content, palette) {
|
|
|
18344
18747
|
}
|
|
18345
18748
|
}
|
|
18346
18749
|
if (result.type === "venn") {
|
|
18347
|
-
|
|
18348
|
-
|
|
18349
|
-
|
|
18350
|
-
|
|
18351
|
-
|
|
18352
|
-
|
|
18353
|
-
|
|
18354
|
-
|
|
18355
|
-
|
|
18750
|
+
if (/\+/.test(line10)) {
|
|
18751
|
+
const colonIdx = line10.indexOf(":");
|
|
18752
|
+
let setsPart;
|
|
18753
|
+
let label;
|
|
18754
|
+
if (colonIdx >= 0) {
|
|
18755
|
+
setsPart = line10.substring(0, colonIdx).trim();
|
|
18756
|
+
label = line10.substring(colonIdx + 1).trim() || null;
|
|
18757
|
+
} else {
|
|
18758
|
+
setsPart = line10.trim();
|
|
18759
|
+
label = null;
|
|
18760
|
+
}
|
|
18761
|
+
const rawSets = setsPart.split("+").map((s) => s.trim()).filter(Boolean);
|
|
18762
|
+
if (rawSets.length >= 2) {
|
|
18763
|
+
result.vennOverlaps.push({ sets: rawSets, label, lineNumber });
|
|
18764
|
+
continue;
|
|
18765
|
+
}
|
|
18356
18766
|
}
|
|
18357
|
-
const
|
|
18358
|
-
|
|
18359
|
-
|
|
18360
|
-
|
|
18361
|
-
|
|
18362
|
-
|
|
18363
|
-
|
|
18364
|
-
|
|
18365
|
-
|
|
18767
|
+
const setDeclMatch = line10.match(/^([^(:]+?)(?:\(([^)]+)\))?(?:\s+alias\s+(\S+))?\s*$/i);
|
|
18768
|
+
if (setDeclMatch) {
|
|
18769
|
+
const name = setDeclMatch[1].trim();
|
|
18770
|
+
const colorName = setDeclMatch[2]?.trim() ?? null;
|
|
18771
|
+
let color = null;
|
|
18772
|
+
if (colorName) {
|
|
18773
|
+
const resolved = resolveColor(colorName, palette);
|
|
18774
|
+
if (resolved.startsWith("#")) {
|
|
18775
|
+
color = resolved;
|
|
18776
|
+
} else {
|
|
18777
|
+
warn(lineNumber, `Unknown color "${colorName}" on set "${name}". Using auto-assigned color.`);
|
|
18778
|
+
}
|
|
18779
|
+
}
|
|
18780
|
+
const alias = setDeclMatch[3]?.trim() ?? null;
|
|
18781
|
+
result.vennSets.push({ name, alias, color, lineNumber });
|
|
18366
18782
|
continue;
|
|
18367
18783
|
}
|
|
18368
18784
|
}
|
|
@@ -18502,15 +18918,6 @@ function parseD3(content, palette) {
|
|
|
18502
18918
|
}
|
|
18503
18919
|
continue;
|
|
18504
18920
|
}
|
|
18505
|
-
if (key === "values") {
|
|
18506
|
-
const v = line10.substring(colonIndex + 1).trim().toLowerCase();
|
|
18507
|
-
if (v === "off") {
|
|
18508
|
-
result.vennShowValues = false;
|
|
18509
|
-
} else if (v === "on") {
|
|
18510
|
-
result.vennShowValues = true;
|
|
18511
|
-
}
|
|
18512
|
-
continue;
|
|
18513
|
-
}
|
|
18514
18921
|
if (key === "rotate") {
|
|
18515
18922
|
const v = line10.substring(colonIndex + 1).trim().toLowerCase();
|
|
18516
18923
|
if (v === "none" || v === "mixed" || v === "angled") {
|
|
@@ -18588,9 +18995,6 @@ function parseD3(content, palette) {
|
|
|
18588
18995
|
if (result.type === "sequence") {
|
|
18589
18996
|
return result;
|
|
18590
18997
|
}
|
|
18591
|
-
const warn = (line10, message) => {
|
|
18592
|
-
result.diagnostics.push(makeDgmoError(line10, message, "warning"));
|
|
18593
|
-
};
|
|
18594
18998
|
if (result.type === "wordcloud") {
|
|
18595
18999
|
if (result.words.length === 0 && freeformLines.length > 0) {
|
|
18596
19000
|
result.words = tokenizeFreeformText(freeformLines.join(" "));
|
|
@@ -18662,29 +19066,34 @@ function parseD3(content, palette) {
|
|
|
18662
19066
|
}
|
|
18663
19067
|
if (result.type === "venn") {
|
|
18664
19068
|
if (result.vennSets.length < 2) {
|
|
18665
|
-
return fail(1, 'At least 2 sets are required. Add
|
|
19069
|
+
return fail(1, 'At least 2 sets are required. Add set names (e.g., "Apples", "Oranges")');
|
|
18666
19070
|
}
|
|
18667
19071
|
if (result.vennSets.length > 3) {
|
|
18668
|
-
return fail(1, "
|
|
19072
|
+
return fail(1, "Venn diagrams support 2\u20133 sets");
|
|
19073
|
+
}
|
|
19074
|
+
const setNameLower = new Map(
|
|
19075
|
+
result.vennSets.map((s) => [s.name.toLowerCase(), s.name])
|
|
19076
|
+
);
|
|
19077
|
+
const aliasLower = /* @__PURE__ */ new Map();
|
|
19078
|
+
for (const s of result.vennSets) {
|
|
19079
|
+
if (s.alias) aliasLower.set(s.alias.toLowerCase(), s.name);
|
|
18669
19080
|
}
|
|
18670
|
-
const
|
|
19081
|
+
const resolveSetRef = (ref) => setNameLower.get(ref.toLowerCase()) ?? aliasLower.get(ref.toLowerCase()) ?? null;
|
|
18671
19082
|
const validOverlaps = [];
|
|
18672
19083
|
for (const ov of result.vennOverlaps) {
|
|
19084
|
+
const resolvedSets = [];
|
|
18673
19085
|
let valid = true;
|
|
18674
|
-
for (const
|
|
18675
|
-
|
|
18676
|
-
|
|
19086
|
+
for (const ref of ov.sets) {
|
|
19087
|
+
const resolved = resolveSetRef(ref);
|
|
19088
|
+
if (!resolved) {
|
|
19089
|
+
result.diagnostics.push(makeDgmoError(ov.lineNumber, `Intersection references unknown set or alias "${ref}"`));
|
|
18677
19090
|
if (!result.error) result.error = formatDgmoError(result.diagnostics[result.diagnostics.length - 1]);
|
|
18678
19091
|
valid = false;
|
|
18679
19092
|
break;
|
|
18680
19093
|
}
|
|
19094
|
+
resolvedSets.push(resolved);
|
|
18681
19095
|
}
|
|
18682
|
-
if (
|
|
18683
|
-
const minSetSize = Math.min(...ov.sets.map((s) => setMap.get(s)));
|
|
18684
|
-
if (ov.size > minSetSize) {
|
|
18685
|
-
warn(ov.lineNumber, `Overlap size ${ov.size} exceeds smallest constituent set size ${minSetSize}`);
|
|
18686
|
-
}
|
|
18687
|
-
validOverlaps.push(ov);
|
|
19096
|
+
if (valid) validOverlaps.push({ ...ov, sets: resolvedSets.sort() });
|
|
18688
19097
|
}
|
|
18689
19098
|
result.vennOverlaps = validOverlaps;
|
|
18690
19099
|
return result;
|
|
@@ -19838,7 +20247,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19838
20247
|
return;
|
|
19839
20248
|
}
|
|
19840
20249
|
const BAR_H = 22;
|
|
19841
|
-
const
|
|
20250
|
+
const GROUP_GAP2 = 12;
|
|
19842
20251
|
const useGroupedHorizontal = tagLanes != null || timelineSort === "group" && timelineGroups.length > 0;
|
|
19843
20252
|
if (useGroupedHorizontal) {
|
|
19844
20253
|
let lanes;
|
|
@@ -19871,7 +20280,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19871
20280
|
};
|
|
19872
20281
|
const innerWidth = width - margin.left - margin.right;
|
|
19873
20282
|
const innerHeight = height - margin.top - margin.bottom;
|
|
19874
|
-
const totalGaps = (lanes.length - 1) *
|
|
20283
|
+
const totalGaps = (lanes.length - 1) * GROUP_GAP2;
|
|
19875
20284
|
const rowH = Math.min(28, (innerHeight - totalGaps) / totalEventRows);
|
|
19876
20285
|
const xScale = d3Scale.scaleLinear().domain([minDate - datePadding, maxDate + datePadding]).range([0, innerWidth]);
|
|
19877
20286
|
const svg = d3Selection12.select(container).append("svg").attr("width", width).attr("height", height).style("background", bgColor);
|
|
@@ -19921,8 +20330,8 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19921
20330
|
lanes.forEach((lane, idx) => {
|
|
19922
20331
|
const laneSpan = lane.events.length * rowH;
|
|
19923
20332
|
const fillColor = idx % 2 === 0 ? textColor : "transparent";
|
|
19924
|
-
g.append("rect").attr("class", "tl-swimlane").attr("data-group", lane.name).attr("x", -margin.left).attr("y", swimY).attr("width", innerWidth + margin.left).attr("height", laneSpan + (idx < lanes.length - 1 ?
|
|
19925
|
-
swimY += laneSpan +
|
|
20333
|
+
g.append("rect").attr("class", "tl-swimlane").attr("data-group", lane.name).attr("x", -margin.left).attr("y", swimY).attr("width", innerWidth + margin.left).attr("height", laneSpan + (idx < lanes.length - 1 ? GROUP_GAP2 : 0)).attr("fill", fillColor).attr("opacity", 0.06);
|
|
20334
|
+
swimY += laneSpan + GROUP_GAP2;
|
|
19926
20335
|
});
|
|
19927
20336
|
}
|
|
19928
20337
|
for (const lane of lanes) {
|
|
@@ -20003,7 +20412,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20003
20412
|
evG.append("text").attr("x", flipLeft ? x - 10 : x + 10).attr("y", y).attr("dy", "0.35em").attr("text-anchor", flipLeft ? "end" : "start").attr("fill", textColor).attr("font-size", "12px").text(ev.label);
|
|
20004
20413
|
}
|
|
20005
20414
|
});
|
|
20006
|
-
curY += laneSpan +
|
|
20415
|
+
curY += laneSpan + GROUP_GAP2;
|
|
20007
20416
|
}
|
|
20008
20417
|
} else {
|
|
20009
20418
|
const sorted = timelineEvents.slice().sort((a, b) => parseTimelineDate(a.date) - parseTimelineDate(b.date));
|
|
@@ -20406,49 +20815,6 @@ function renderWordCloudAsync(container, parsed, palette, _isDark, exportDims) {
|
|
|
20406
20815
|
}).start();
|
|
20407
20816
|
});
|
|
20408
20817
|
}
|
|
20409
|
-
function radiusFromArea(area) {
|
|
20410
|
-
return Math.sqrt(area / Math.PI);
|
|
20411
|
-
}
|
|
20412
|
-
function circleOverlapArea(r1, r2, d) {
|
|
20413
|
-
if (d >= r1 + r2) return 0;
|
|
20414
|
-
if (d + Math.min(r1, r2) <= Math.max(r1, r2)) {
|
|
20415
|
-
return Math.PI * Math.min(r1, r2) ** 2;
|
|
20416
|
-
}
|
|
20417
|
-
const part1 = r1 * r1 * Math.acos((d * d + r1 * r1 - r2 * r2) / (2 * d * r1));
|
|
20418
|
-
const part2 = r2 * r2 * Math.acos((d * d + r2 * r2 - r1 * r1) / (2 * d * r2));
|
|
20419
|
-
const part3 = 0.5 * Math.sqrt((-d + r1 + r2) * (d + r1 - r2) * (d - r1 + r2) * (d + r1 + r2));
|
|
20420
|
-
return part1 + part2 - part3;
|
|
20421
|
-
}
|
|
20422
|
-
function distanceForOverlap(r1, r2, targetArea) {
|
|
20423
|
-
if (targetArea <= 0) return r1 + r2;
|
|
20424
|
-
const minR = Math.min(r1, r2);
|
|
20425
|
-
if (targetArea >= Math.PI * minR * minR) return Math.abs(r1 - r2);
|
|
20426
|
-
let lo = Math.abs(r1 - r2);
|
|
20427
|
-
let hi = r1 + r2;
|
|
20428
|
-
for (let i = 0; i < 64; i++) {
|
|
20429
|
-
const mid = (lo + hi) / 2;
|
|
20430
|
-
if (circleOverlapArea(r1, r2, mid) > targetArea) {
|
|
20431
|
-
lo = mid;
|
|
20432
|
-
} else {
|
|
20433
|
-
hi = mid;
|
|
20434
|
-
}
|
|
20435
|
-
}
|
|
20436
|
-
return (lo + hi) / 2;
|
|
20437
|
-
}
|
|
20438
|
-
function thirdCirclePosition(ax, ay, dAC, bx, by, dBC) {
|
|
20439
|
-
const dx = bx - ax;
|
|
20440
|
-
const dy = by - ay;
|
|
20441
|
-
const dAB = Math.sqrt(dx * dx + dy * dy);
|
|
20442
|
-
if (dAB === 0) return { x: ax + dAC, y: ay };
|
|
20443
|
-
const cosA = (dAB * dAB + dAC * dAC - dBC * dBC) / (2 * dAB * dAC);
|
|
20444
|
-
const sinA = Math.sqrt(Math.max(0, 1 - cosA * cosA));
|
|
20445
|
-
const ux = dx / dAB;
|
|
20446
|
-
const uy = dy / dAB;
|
|
20447
|
-
return {
|
|
20448
|
-
x: ax + dAC * (cosA * ux - sinA * uy),
|
|
20449
|
-
y: ay + dAC * (cosA * uy + sinA * ux)
|
|
20450
|
-
};
|
|
20451
|
-
}
|
|
20452
20818
|
function fitCirclesToContainerAsymmetric(circles, w, h, mLeft, mRight, mTop, mBottom) {
|
|
20453
20819
|
if (circles.length === 0) return [];
|
|
20454
20820
|
let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
|
|
@@ -20523,54 +20889,28 @@ function regionCentroid(circles, inside) {
|
|
|
20523
20889
|
return { x: sx / count, y: sy / count };
|
|
20524
20890
|
}
|
|
20525
20891
|
function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims) {
|
|
20526
|
-
const { vennSets, vennOverlaps,
|
|
20892
|
+
const { vennSets, vennOverlaps, title } = parsed;
|
|
20527
20893
|
if (vennSets.length < 2) return;
|
|
20528
20894
|
const init2 = initD3Chart(container, palette, exportDims);
|
|
20529
20895
|
if (!init2) return;
|
|
20530
20896
|
const { svg, width, height, textColor, colors } = init2;
|
|
20531
20897
|
const titleHeight = title ? 40 : 0;
|
|
20532
|
-
const radii = vennSets.map((s) => radiusFromArea(s.size));
|
|
20533
|
-
const overlapMap = /* @__PURE__ */ new Map();
|
|
20534
|
-
for (const ov of vennOverlaps) {
|
|
20535
|
-
overlapMap.set(ov.sets.join("&"), ov.size);
|
|
20536
|
-
}
|
|
20537
|
-
let rawCircles;
|
|
20538
20898
|
const n = vennSets.length;
|
|
20899
|
+
const BASE_R = 100;
|
|
20900
|
+
const OVERLAP_DISTANCE = BASE_R * 1.4;
|
|
20901
|
+
let rawCircles;
|
|
20539
20902
|
if (n === 2) {
|
|
20540
|
-
const d = distanceForOverlap(
|
|
20541
|
-
radii[0],
|
|
20542
|
-
radii[1],
|
|
20543
|
-
overlapMap.get([vennSets[0].name, vennSets[1].name].sort().join("&")) ?? 0
|
|
20544
|
-
);
|
|
20545
20903
|
rawCircles = [
|
|
20546
|
-
{ x: -
|
|
20547
|
-
{ x:
|
|
20904
|
+
{ x: -OVERLAP_DISTANCE / 2, y: 0, r: BASE_R },
|
|
20905
|
+
{ x: OVERLAP_DISTANCE / 2, y: 0, r: BASE_R }
|
|
20548
20906
|
];
|
|
20549
20907
|
} else {
|
|
20550
|
-
const
|
|
20551
|
-
const
|
|
20552
|
-
const dAB = distanceForOverlap(
|
|
20553
|
-
radii[0],
|
|
20554
|
-
radii[1],
|
|
20555
|
-
overlapMap.get(pairKey(0, 1)) ?? 0
|
|
20556
|
-
);
|
|
20557
|
-
const dAC = distanceForOverlap(
|
|
20558
|
-
radii[0],
|
|
20559
|
-
radii[2],
|
|
20560
|
-
overlapMap.get(pairKey(0, 2)) ?? 0
|
|
20561
|
-
);
|
|
20562
|
-
const dBC = distanceForOverlap(
|
|
20563
|
-
radii[1],
|
|
20564
|
-
radii[2],
|
|
20565
|
-
overlapMap.get(pairKey(1, 2)) ?? 0
|
|
20566
|
-
);
|
|
20567
|
-
const ax = -dAB / 2;
|
|
20568
|
-
const bx = dAB / 2;
|
|
20569
|
-
const cPos = thirdCirclePosition(ax, 0, dAC, bx, 0, dBC);
|
|
20908
|
+
const s = OVERLAP_DISTANCE;
|
|
20909
|
+
const h = Math.sqrt(3) / 2 * s;
|
|
20570
20910
|
rawCircles = [
|
|
20571
|
-
{ x:
|
|
20572
|
-
{ x:
|
|
20573
|
-
{ x:
|
|
20911
|
+
{ x: -s / 2, y: h / 3, r: BASE_R },
|
|
20912
|
+
{ x: s / 2, y: h / 3, r: BASE_R },
|
|
20913
|
+
{ x: 0, y: -(2 * h) / 3, r: BASE_R }
|
|
20574
20914
|
];
|
|
20575
20915
|
}
|
|
20576
20916
|
const setColors = vennSets.map(
|
|
@@ -20583,8 +20923,7 @@ function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims)
|
|
|
20583
20923
|
const edgePad = 8;
|
|
20584
20924
|
const labelTextPad = 4;
|
|
20585
20925
|
for (let i = 0; i < n; i++) {
|
|
20586
|
-
const
|
|
20587
|
-
const estimatedWidth = displayName.length * 8.5 + stubLen + edgePad + labelTextPad;
|
|
20926
|
+
const estimatedWidth = vennSets[i].name.length * 8.5 + stubLen + edgePad + labelTextPad;
|
|
20588
20927
|
const dx = rawCircles[i].x - clusterCx;
|
|
20589
20928
|
const dy = rawCircles[i].y - clusterCy;
|
|
20590
20929
|
if (Math.abs(dx) >= Math.abs(dy)) {
|
|
@@ -20606,7 +20945,8 @@ function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims)
|
|
|
20606
20945
|
marginTop,
|
|
20607
20946
|
marginBottom
|
|
20608
20947
|
).map((c) => ({ ...c, y: c.y + titleHeight }));
|
|
20609
|
-
const
|
|
20948
|
+
const scaledR = circles[0].r;
|
|
20949
|
+
svg.append("style").text("circle:focus, circle:focus-visible { outline: none !important; }");
|
|
20610
20950
|
renderChartTitle(svg, title, parsed.titleLineNumber, width, textColor, onClickItem);
|
|
20611
20951
|
const circleEls = [];
|
|
20612
20952
|
const circleGroup = svg.append("g");
|
|
@@ -20614,17 +20954,59 @@ function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims)
|
|
|
20614
20954
|
const el = circleGroup.append("circle").attr("cx", c.x).attr("cy", c.y).attr("r", c.r).attr("fill", setColors[i]).attr("fill-opacity", 0.35).attr("stroke", setColors[i]).attr("stroke-width", 2).style("pointer-events", "none");
|
|
20615
20955
|
circleEls.push(el);
|
|
20616
20956
|
});
|
|
20957
|
+
const defs = svg.append("defs");
|
|
20958
|
+
circles.forEach((c, i) => {
|
|
20959
|
+
defs.append("clipPath").attr("id", `vcp-${i}`).append("circle").attr("cx", c.x).attr("cy", c.y).attr("r", c.r);
|
|
20960
|
+
});
|
|
20961
|
+
const regionIdxSets = circles.map((_, i) => [i]);
|
|
20962
|
+
if (n === 2) {
|
|
20963
|
+
regionIdxSets.push([0, 1]);
|
|
20964
|
+
} else {
|
|
20965
|
+
regionIdxSets.push([0, 1], [0, 2], [1, 2], [0, 1, 2]);
|
|
20966
|
+
}
|
|
20967
|
+
const overlayGroup = svg.append("g").style("pointer-events", "none");
|
|
20968
|
+
const overlayEls = /* @__PURE__ */ new Map();
|
|
20969
|
+
for (const idxs of regionIdxSets) {
|
|
20970
|
+
const key = idxs.join("-");
|
|
20971
|
+
const excluded = Array.from({ length: n }, (_, j) => j).filter((j) => !idxs.includes(j));
|
|
20972
|
+
let clipId = `vcp-${idxs[0]}`;
|
|
20973
|
+
for (let k = 1; k < idxs.length; k++) {
|
|
20974
|
+
const nestedId = `vcp-n-${idxs.slice(0, k + 1).join("-")}`;
|
|
20975
|
+
const ci = idxs[k];
|
|
20976
|
+
defs.append("clipPath").attr("id", nestedId).append("circle").attr("cx", circles[ci].x).attr("cy", circles[ci].y).attr("r", circles[ci].r).attr("clip-path", `url(#${clipId})`);
|
|
20977
|
+
clipId = nestedId;
|
|
20978
|
+
}
|
|
20979
|
+
let regionLineNumber = null;
|
|
20980
|
+
if (idxs.length === 1) {
|
|
20981
|
+
regionLineNumber = vennSets[idxs[0]].lineNumber;
|
|
20982
|
+
} else {
|
|
20983
|
+
const sortedNames = idxs.map((i) => vennSets[i].name).sort();
|
|
20984
|
+
const ov = vennOverlaps.find(
|
|
20985
|
+
(o) => o.sets.length === sortedNames.length && o.sets.every((s, k) => s === sortedNames[k])
|
|
20986
|
+
);
|
|
20987
|
+
regionLineNumber = ov?.lineNumber ?? null;
|
|
20988
|
+
}
|
|
20989
|
+
const el = overlayGroup.append("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height).attr("fill", "white").attr("fill-opacity", 0).attr("class", "venn-region-overlay").attr("data-line-number", regionLineNumber != null ? String(regionLineNumber) : "0").attr("clip-path", `url(#${clipId})`);
|
|
20990
|
+
if (excluded.length > 0) {
|
|
20991
|
+
const maskId = `vvm-${key}`;
|
|
20992
|
+
const mask = defs.append("mask").attr("id", maskId);
|
|
20993
|
+
mask.append("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height).attr("fill", "white");
|
|
20994
|
+
for (const j of excluded) {
|
|
20995
|
+
mask.append("circle").attr("cx", circles[j].x).attr("cy", circles[j].y).attr("r", circles[j].r).attr("fill", "black");
|
|
20996
|
+
}
|
|
20997
|
+
el.attr("mask", `url(#${maskId})`);
|
|
20998
|
+
}
|
|
20999
|
+
overlayEls.set(key, el);
|
|
21000
|
+
}
|
|
21001
|
+
const showRegionOverlay = (idxs) => {
|
|
21002
|
+
const key = [...idxs].sort((a, b) => a - b).join("-");
|
|
21003
|
+
overlayEls.forEach((el, k) => el.attr("fill-opacity", k === key ? 0 : 0.55));
|
|
21004
|
+
};
|
|
21005
|
+
const hideAllOverlays = () => {
|
|
21006
|
+
overlayEls.forEach((el) => el.attr("fill-opacity", 0));
|
|
21007
|
+
};
|
|
20617
21008
|
const gcx = circles.reduce((s, c) => s + c.x, 0) / n;
|
|
20618
21009
|
const gcy = circles.reduce((s, c) => s + c.y, 0) / n;
|
|
20619
|
-
function rayCircleExit(ox, oy, dx, dy, c) {
|
|
20620
|
-
const lx = ox - c.x;
|
|
20621
|
-
const ly = oy - c.y;
|
|
20622
|
-
const b = lx * dx + ly * dy;
|
|
20623
|
-
const det = b * b - (lx * lx + ly * ly - c.r * c.r);
|
|
20624
|
-
if (det < 0) return 0;
|
|
20625
|
-
return -b + Math.sqrt(det);
|
|
20626
|
-
}
|
|
20627
|
-
const labelGroup = svg.append("g").style("pointer-events", "none");
|
|
20628
21010
|
function exclusiveHSpan(px, py, ci) {
|
|
20629
21011
|
const dy = py - circles[ci].y;
|
|
20630
21012
|
const halfChord = Math.sqrt(Math.max(0, circles[ci].r * circles[ci].r - dy * dy));
|
|
@@ -20647,8 +21029,9 @@ function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims)
|
|
|
20647
21029
|
const MIN_FONT = 10;
|
|
20648
21030
|
const MAX_FONT = 22;
|
|
20649
21031
|
const INTERNAL_PAD = 12;
|
|
21032
|
+
const labelGroup = svg.append("g").style("pointer-events", "none");
|
|
20650
21033
|
circles.forEach((c, i) => {
|
|
20651
|
-
const text = vennSets[i].
|
|
21034
|
+
const text = vennSets[i].name;
|
|
20652
21035
|
const inside = circles.map((_, j) => j === i);
|
|
20653
21036
|
const centroid = regionCentroid(circles, inside);
|
|
20654
21037
|
const availW = exclusiveHSpan(centroid.x, centroid.y, i);
|
|
@@ -20683,11 +21066,8 @@ function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims)
|
|
|
20683
21066
|
let textX = stubEndX + (isRight ? labelTextPad : -labelTextPad);
|
|
20684
21067
|
const textY = stubEndY;
|
|
20685
21068
|
const estW = text.length * 8.5;
|
|
20686
|
-
if (isRight)
|
|
20687
|
-
|
|
20688
|
-
} else {
|
|
20689
|
-
textX = Math.max(textX, estW + 4);
|
|
20690
|
-
}
|
|
21069
|
+
if (isRight) textX = Math.min(textX, width - estW - 4);
|
|
21070
|
+
else textX = Math.max(textX, estW + 4);
|
|
20691
21071
|
labelGroup.append("text").attr("x", textX).attr("y", Math.max(14, Math.min(height - 4, textY))).attr("text-anchor", textAnchor).attr("dominant-baseline", "central").attr("fill", textColor).attr("font-size", "14px").attr("font-weight", "bold").text(text);
|
|
20692
21072
|
}
|
|
20693
21073
|
});
|
|
@@ -20715,40 +21095,57 @@ function renderVenn(container, parsed, palette, isDark, onClickItem, exportDims)
|
|
|
20715
21095
|
return Math.max(0, right - left);
|
|
20716
21096
|
}
|
|
20717
21097
|
for (const ov of vennOverlaps) {
|
|
21098
|
+
if (!ov.label) continue;
|
|
20718
21099
|
const idxs = ov.sets.map((s) => vennSets.findIndex((vs) => vs.name === s));
|
|
20719
21100
|
if (idxs.some((idx) => idx < 0)) continue;
|
|
20720
|
-
if (!ov.label) continue;
|
|
20721
21101
|
const inside = circles.map((_, j) => idxs.includes(j));
|
|
20722
21102
|
const centroid = regionCentroid(circles, inside);
|
|
20723
|
-
const text = ov.label;
|
|
20724
21103
|
const availW = overlapHSpan(centroid.y, idxs);
|
|
20725
21104
|
const fitFont = Math.min(MAX_FONT, Math.max(
|
|
20726
21105
|
MIN_FONT,
|
|
20727
|
-
(availW - INTERNAL_PAD * 2) / (
|
|
21106
|
+
(availW - INTERNAL_PAD * 2) / (ov.label.length * CH_RATIO)
|
|
20728
21107
|
));
|
|
20729
|
-
labelGroup.append("text").attr("x", centroid.x).attr("y", centroid.y).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", textColor).attr("font-size", `${Math.round(fitFont)}px`).attr("font-weight", "600").text(
|
|
21108
|
+
labelGroup.append("text").attr("x", centroid.x).attr("y", centroid.y).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", textColor).attr("font-size", `${Math.round(fitFont)}px`).attr("font-weight", "600").text(ov.label);
|
|
20730
21109
|
}
|
|
20731
21110
|
const hoverGroup = svg.append("g");
|
|
20732
21111
|
circles.forEach((c, i) => {
|
|
20733
|
-
|
|
20734
|
-
|
|
20735
|
-
hoverGroup.append("circle").attr("cx", c.x).attr("cy", c.y).attr("r", c.r).attr("fill", "transparent").attr("data-line-number", String(vennSets[i].lineNumber)).style("cursor", onClickItem ? "pointer" : "default").on("mouseenter", (event) => {
|
|
20736
|
-
circleEls.forEach((el, ci) => {
|
|
20737
|
-
el.attr("fill-opacity", ci === i ? 0.5 : 0.1);
|
|
20738
|
-
});
|
|
20739
|
-
showTooltip(tooltip, tipHtml, event);
|
|
20740
|
-
}).on("mousemove", (event) => {
|
|
20741
|
-
showTooltip(tooltip, tipHtml, event);
|
|
21112
|
+
hoverGroup.append("circle").attr("cx", c.x).attr("cy", c.y).attr("r", c.r).attr("fill", "transparent").attr("stroke", "none").attr("class", "venn-hit-target").attr("data-line-number", String(vennSets[i].lineNumber)).style("cursor", onClickItem ? "pointer" : "default").style("outline", "none").on("mouseenter", () => {
|
|
21113
|
+
showRegionOverlay([i]);
|
|
20742
21114
|
}).on("mouseleave", () => {
|
|
20743
|
-
|
|
20744
|
-
|
|
20745
|
-
|
|
20746
|
-
|
|
20747
|
-
}).on("click", () => {
|
|
20748
|
-
if (onClickItem && vennSets[i].lineNumber)
|
|
20749
|
-
onClickItem(vennSets[i].lineNumber);
|
|
21115
|
+
hideAllOverlays();
|
|
21116
|
+
}).on("click", function() {
|
|
21117
|
+
this.blur?.();
|
|
21118
|
+
if (onClickItem && vennSets[i].lineNumber) onClickItem(vennSets[i].lineNumber);
|
|
20750
21119
|
});
|
|
20751
21120
|
});
|
|
21121
|
+
const overlayR = scaledR * 0.35;
|
|
21122
|
+
const subsets = [];
|
|
21123
|
+
if (n === 2) {
|
|
21124
|
+
subsets.push({ idxs: [0, 1], sets: [vennSets[0].name, vennSets[1].name].sort() });
|
|
21125
|
+
} else {
|
|
21126
|
+
for (let a = 0; a < n; a++) {
|
|
21127
|
+
for (let b = a + 1; b < n; b++) {
|
|
21128
|
+
subsets.push({ idxs: [a, b], sets: [vennSets[a].name, vennSets[b].name].sort() });
|
|
21129
|
+
}
|
|
21130
|
+
}
|
|
21131
|
+
subsets.push({ idxs: [0, 1, 2], sets: [vennSets[0].name, vennSets[1].name, vennSets[2].name].sort() });
|
|
21132
|
+
}
|
|
21133
|
+
for (const subset of subsets) {
|
|
21134
|
+
const { idxs, sets } = subset;
|
|
21135
|
+
const inside = circles.map((_, j) => idxs.includes(j));
|
|
21136
|
+
const centroid = regionCentroid(circles, inside);
|
|
21137
|
+
const declaredOv = vennOverlaps.find(
|
|
21138
|
+
(ov) => ov.sets.length === sets.length && ov.sets.every((s, k) => s === sets[k])
|
|
21139
|
+
);
|
|
21140
|
+
hoverGroup.append("circle").attr("cx", centroid.x).attr("cy", centroid.y).attr("r", overlayR).attr("fill", "transparent").attr("stroke", "none").attr("class", "venn-hit-target").attr("data-line-number", declaredOv ? String(declaredOv.lineNumber) : "").style("cursor", onClickItem && declaredOv ? "pointer" : "default").style("outline", "none").on("mouseenter", () => {
|
|
21141
|
+
showRegionOverlay(idxs);
|
|
21142
|
+
}).on("mouseleave", () => {
|
|
21143
|
+
hideAllOverlays();
|
|
21144
|
+
}).on("click", function() {
|
|
21145
|
+
this.blur?.();
|
|
21146
|
+
if (onClickItem && declaredOv) onClickItem(declaredOv.lineNumber);
|
|
21147
|
+
});
|
|
21148
|
+
}
|
|
20752
21149
|
}
|
|
20753
21150
|
function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportDims) {
|
|
20754
21151
|
const {
|
|
@@ -20856,8 +21253,8 @@ function renderQuadrant(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
20856
21253
|
const LABEL_MAX_FONT = 48;
|
|
20857
21254
|
const LABEL_MIN_FONT = 14;
|
|
20858
21255
|
const LABEL_PAD = 40;
|
|
20859
|
-
const
|
|
20860
|
-
const estTextWidth = (text, fontSize) => text.length * fontSize *
|
|
21256
|
+
const CHAR_WIDTH_RATIO3 = 0.6;
|
|
21257
|
+
const estTextWidth = (text, fontSize) => text.length * fontSize * CHAR_WIDTH_RATIO3;
|
|
20861
21258
|
const quadrantLabelLayout = (text, qw2, qh2) => {
|
|
20862
21259
|
const availW = qw2 - LABEL_PAD;
|
|
20863
21260
|
const availH = qh2 - LABEL_PAD;
|
|
@@ -21680,6 +22077,43 @@ init_renderer7();
|
|
|
21680
22077
|
init_parser7();
|
|
21681
22078
|
init_layout5();
|
|
21682
22079
|
init_renderer6();
|
|
22080
|
+
|
|
22081
|
+
// src/initiative-status/collapse.ts
|
|
22082
|
+
init_layout5();
|
|
22083
|
+
function collapseInitiativeStatus(parsed, collapsedGroups) {
|
|
22084
|
+
const originalGroups = parsed.groups;
|
|
22085
|
+
if (collapsedGroups.size === 0) {
|
|
22086
|
+
return { parsed, collapsedGroupStatuses: /* @__PURE__ */ new Map(), originalGroups };
|
|
22087
|
+
}
|
|
22088
|
+
const nodeToGroup = /* @__PURE__ */ new Map();
|
|
22089
|
+
const collapsedGroupStatuses = /* @__PURE__ */ new Map();
|
|
22090
|
+
for (const group of parsed.groups) {
|
|
22091
|
+
if (!collapsedGroups.has(group.label)) continue;
|
|
22092
|
+
const children = group.nodeLabels.map((l) => parsed.nodes.find((n) => n.label === l)).filter((n) => n !== void 0);
|
|
22093
|
+
for (const node of children) nodeToGroup.set(node.label, group.label);
|
|
22094
|
+
collapsedGroupStatuses.set(group.label, rollUpStatus(children));
|
|
22095
|
+
}
|
|
22096
|
+
const nodes = parsed.nodes.filter((n) => !nodeToGroup.has(n.label));
|
|
22097
|
+
const edgeKeys = /* @__PURE__ */ new Set();
|
|
22098
|
+
const edges = [];
|
|
22099
|
+
for (const edge of parsed.edges) {
|
|
22100
|
+
const src = nodeToGroup.get(edge.source) ?? edge.source;
|
|
22101
|
+
const tgt = nodeToGroup.get(edge.target) ?? edge.target;
|
|
22102
|
+
if (src === tgt) continue;
|
|
22103
|
+
const key = `${src}|${tgt}|${edge.label ?? ""}`;
|
|
22104
|
+
if (edgeKeys.has(key)) continue;
|
|
22105
|
+
edgeKeys.add(key);
|
|
22106
|
+
edges.push({ ...edge, source: src, target: tgt });
|
|
22107
|
+
}
|
|
22108
|
+
const groups = parsed.groups.filter((g) => !collapsedGroups.has(g.label));
|
|
22109
|
+
return {
|
|
22110
|
+
parsed: { ...parsed, nodes, edges, groups },
|
|
22111
|
+
collapsedGroupStatuses,
|
|
22112
|
+
originalGroups
|
|
22113
|
+
};
|
|
22114
|
+
}
|
|
22115
|
+
|
|
22116
|
+
// src/index.ts
|
|
21683
22117
|
init_parser8();
|
|
21684
22118
|
init_layout2();
|
|
21685
22119
|
init_renderer2();
|
|
@@ -21937,7 +22371,7 @@ async function resolveFile(content, filePath, readFileFn, diagnostics, ancestorC
|
|
|
21937
22371
|
continue;
|
|
21938
22372
|
}
|
|
21939
22373
|
if (isTagBlockHeading(trimmed)) continue;
|
|
21940
|
-
if (lines[i]
|
|
22374
|
+
if (/^\s/.test(lines[i])) continue;
|
|
21941
22375
|
const tagsMatch = trimmed.match(TAGS_RE);
|
|
21942
22376
|
if (tagsMatch) {
|
|
21943
22377
|
tagsDirective = tagsMatch[1].trim();
|
|
@@ -22179,6 +22613,12 @@ function encodeDiagramUrl(dsl, options) {
|
|
|
22179
22613
|
if (options?.viewState?.swimlaneTagGroup) {
|
|
22180
22614
|
hash += `&swim=${encodeURIComponent(options.viewState.swimlaneTagGroup)}`;
|
|
22181
22615
|
}
|
|
22616
|
+
if (options?.viewState?.palette && options.viewState.palette !== "nord") {
|
|
22617
|
+
hash += `&pal=${encodeURIComponent(options.viewState.palette)}`;
|
|
22618
|
+
}
|
|
22619
|
+
if (options?.viewState?.theme && options.viewState.theme !== "dark") {
|
|
22620
|
+
hash += `&th=${encodeURIComponent(options.viewState.theme)}`;
|
|
22621
|
+
}
|
|
22182
22622
|
return { url: `${baseUrl}?${hash}#${hash}` };
|
|
22183
22623
|
}
|
|
22184
22624
|
function decodeDiagramUrl(hash) {
|
|
@@ -22205,6 +22645,8 @@ function decodeDiagramUrl(hash) {
|
|
|
22205
22645
|
if (key === "swim" && val) {
|
|
22206
22646
|
viewState.swimlaneTagGroup = val;
|
|
22207
22647
|
}
|
|
22648
|
+
if (key === "pal" && val) viewState.palette = val;
|
|
22649
|
+
if (key === "th" && (val === "light" || val === "dark")) viewState.theme = val;
|
|
22208
22650
|
}
|
|
22209
22651
|
if (payload.startsWith("dgmo=")) {
|
|
22210
22652
|
payload = payload.slice(5);
|
|
@@ -22237,6 +22679,7 @@ export {
|
|
|
22237
22679
|
buildRenderSequence,
|
|
22238
22680
|
buildThemeCSS,
|
|
22239
22681
|
catppuccinPalette,
|
|
22682
|
+
collapseInitiativeStatus,
|
|
22240
22683
|
collapseOrgTree,
|
|
22241
22684
|
collapseSitemapTree,
|
|
22242
22685
|
collectDiagramRoles,
|