@diagrammo/dgmo 0.4.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +152 -152
- package/dist/index.cjs +546 -154
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -20
- package/dist/index.d.ts +25 -20
- package/dist/index.js +546 -154
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/chart.ts +5 -2
- package/src/d3.ts +388 -21
- package/src/echarts.ts +13 -12
- package/src/er/parser.ts +88 -3
- package/src/er/renderer.ts +91 -2
- package/src/er/types.ts +3 -0
- package/src/infra/layout.ts +6 -3
- package/src/infra/parser.ts +2 -2
- package/src/infra/renderer.ts +52 -8
- package/src/kanban/mutations.ts +1 -1
- package/src/kanban/parser.ts +55 -36
- package/src/sharing.ts +8 -0
package/dist/index.js
CHANGED
|
@@ -1357,6 +1357,94 @@ var init_parsing = __esm({
|
|
|
1357
1357
|
}
|
|
1358
1358
|
});
|
|
1359
1359
|
|
|
1360
|
+
// src/utils/tag-groups.ts
|
|
1361
|
+
function isTagBlockHeading(trimmed) {
|
|
1362
|
+
return TAG_BLOCK_RE.test(trimmed) || GROUP_HEADING_RE.test(trimmed);
|
|
1363
|
+
}
|
|
1364
|
+
function resolveTagColor(metadata, tagGroups, activeGroupName, isContainer) {
|
|
1365
|
+
if (!activeGroupName) return void 0;
|
|
1366
|
+
const group = tagGroups.find(
|
|
1367
|
+
(g) => g.name.toLowerCase() === activeGroupName.toLowerCase()
|
|
1368
|
+
);
|
|
1369
|
+
if (!group) return void 0;
|
|
1370
|
+
const metaValue = metadata[group.name.toLowerCase()] ?? (isContainer ? void 0 : group.defaultValue);
|
|
1371
|
+
if (!metaValue) return "#999999";
|
|
1372
|
+
return group.entries.find(
|
|
1373
|
+
(e) => e.value.toLowerCase() === metaValue.toLowerCase()
|
|
1374
|
+
)?.color ?? "#999999";
|
|
1375
|
+
}
|
|
1376
|
+
function validateTagValues(entities, tagGroups, pushWarning, suggestFn) {
|
|
1377
|
+
if (tagGroups.length === 0) return;
|
|
1378
|
+
const groupMap = /* @__PURE__ */ new Map();
|
|
1379
|
+
for (const g of tagGroups) groupMap.set(g.name.toLowerCase(), g);
|
|
1380
|
+
for (const entity of entities) {
|
|
1381
|
+
for (const [key, value] of Object.entries(entity.metadata)) {
|
|
1382
|
+
const group = groupMap.get(key);
|
|
1383
|
+
if (!group) continue;
|
|
1384
|
+
const match = group.entries.some(
|
|
1385
|
+
(e) => e.value.toLowerCase() === value.toLowerCase()
|
|
1386
|
+
);
|
|
1387
|
+
if (!match) {
|
|
1388
|
+
const defined = group.entries.map((e) => e.value);
|
|
1389
|
+
let msg = `Unknown value '${value}' for tag group '${group.name}'`;
|
|
1390
|
+
const hint = suggestFn?.(value, defined);
|
|
1391
|
+
if (hint) {
|
|
1392
|
+
msg += `. ${hint}`;
|
|
1393
|
+
} else {
|
|
1394
|
+
msg += ` \u2014 defined values: ${defined.join(", ")}`;
|
|
1395
|
+
}
|
|
1396
|
+
pushWarning(entity.lineNumber, msg);
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
function injectDefaultTagMetadata(entities, tagGroups, skip) {
|
|
1402
|
+
const defaults = [];
|
|
1403
|
+
for (const group of tagGroups) {
|
|
1404
|
+
if (group.defaultValue) {
|
|
1405
|
+
defaults.push({ key: group.name.toLowerCase(), value: group.defaultValue });
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
if (defaults.length === 0) return;
|
|
1409
|
+
for (const entity of entities) {
|
|
1410
|
+
if (skip?.(entity)) continue;
|
|
1411
|
+
for (const { key, value } of defaults) {
|
|
1412
|
+
if (!(key in entity.metadata)) {
|
|
1413
|
+
entity.metadata[key] = value;
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
function matchTagBlockHeading(trimmed) {
|
|
1419
|
+
const tagMatch = trimmed.match(TAG_BLOCK_RE);
|
|
1420
|
+
if (tagMatch) {
|
|
1421
|
+
return {
|
|
1422
|
+
name: tagMatch[1].trim(),
|
|
1423
|
+
alias: tagMatch[2] || void 0,
|
|
1424
|
+
colorHint: tagMatch[3] || void 0,
|
|
1425
|
+
deprecated: false
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
const groupMatch = trimmed.match(GROUP_HEADING_RE);
|
|
1429
|
+
if (groupMatch) {
|
|
1430
|
+
return {
|
|
1431
|
+
name: groupMatch[1].trim(),
|
|
1432
|
+
alias: groupMatch[2] || void 0,
|
|
1433
|
+
colorHint: groupMatch[3] || void 0,
|
|
1434
|
+
deprecated: true
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1437
|
+
return null;
|
|
1438
|
+
}
|
|
1439
|
+
var TAG_BLOCK_RE, GROUP_HEADING_RE;
|
|
1440
|
+
var init_tag_groups = __esm({
|
|
1441
|
+
"src/utils/tag-groups.ts"() {
|
|
1442
|
+
"use strict";
|
|
1443
|
+
TAG_BLOCK_RE = /^tag:\s+(.+?)(?:\s+alias\s+(\w+))?(?:\s*\(([^)]+)\))?\s*$/i;
|
|
1444
|
+
GROUP_HEADING_RE = /^##\s+(.+?)(?:\s+alias\s+(\w+))?(?:\s*\(([^)]+)\))?\s*$/;
|
|
1445
|
+
}
|
|
1446
|
+
});
|
|
1447
|
+
|
|
1360
1448
|
// src/sequence/participant-inference.ts
|
|
1361
1449
|
function inferParticipantType(name) {
|
|
1362
1450
|
for (const rule of PARTICIPANT_RULES) {
|
|
@@ -1686,94 +1774,6 @@ var init_arrows = __esm({
|
|
|
1686
1774
|
}
|
|
1687
1775
|
});
|
|
1688
1776
|
|
|
1689
|
-
// src/utils/tag-groups.ts
|
|
1690
|
-
function isTagBlockHeading(trimmed) {
|
|
1691
|
-
return TAG_BLOCK_RE.test(trimmed) || GROUP_HEADING_RE.test(trimmed);
|
|
1692
|
-
}
|
|
1693
|
-
function resolveTagColor(metadata, tagGroups, activeGroupName, isContainer) {
|
|
1694
|
-
if (!activeGroupName) return void 0;
|
|
1695
|
-
const group = tagGroups.find(
|
|
1696
|
-
(g) => g.name.toLowerCase() === activeGroupName.toLowerCase()
|
|
1697
|
-
);
|
|
1698
|
-
if (!group) return void 0;
|
|
1699
|
-
const metaValue = metadata[group.name.toLowerCase()] ?? (isContainer ? void 0 : group.defaultValue);
|
|
1700
|
-
if (!metaValue) return "#999999";
|
|
1701
|
-
return group.entries.find(
|
|
1702
|
-
(e) => e.value.toLowerCase() === metaValue.toLowerCase()
|
|
1703
|
-
)?.color ?? "#999999";
|
|
1704
|
-
}
|
|
1705
|
-
function validateTagValues(entities, tagGroups, pushWarning, suggestFn) {
|
|
1706
|
-
if (tagGroups.length === 0) return;
|
|
1707
|
-
const groupMap = /* @__PURE__ */ new Map();
|
|
1708
|
-
for (const g of tagGroups) groupMap.set(g.name.toLowerCase(), g);
|
|
1709
|
-
for (const entity of entities) {
|
|
1710
|
-
for (const [key, value] of Object.entries(entity.metadata)) {
|
|
1711
|
-
const group = groupMap.get(key);
|
|
1712
|
-
if (!group) continue;
|
|
1713
|
-
const match = group.entries.some(
|
|
1714
|
-
(e) => e.value.toLowerCase() === value.toLowerCase()
|
|
1715
|
-
);
|
|
1716
|
-
if (!match) {
|
|
1717
|
-
const defined = group.entries.map((e) => e.value);
|
|
1718
|
-
let msg = `Unknown value '${value}' for tag group '${group.name}'`;
|
|
1719
|
-
const hint = suggestFn?.(value, defined);
|
|
1720
|
-
if (hint) {
|
|
1721
|
-
msg += `. ${hint}`;
|
|
1722
|
-
} else {
|
|
1723
|
-
msg += ` \u2014 defined values: ${defined.join(", ")}`;
|
|
1724
|
-
}
|
|
1725
|
-
pushWarning(entity.lineNumber, msg);
|
|
1726
|
-
}
|
|
1727
|
-
}
|
|
1728
|
-
}
|
|
1729
|
-
}
|
|
1730
|
-
function injectDefaultTagMetadata(entities, tagGroups, skip) {
|
|
1731
|
-
const defaults = [];
|
|
1732
|
-
for (const group of tagGroups) {
|
|
1733
|
-
if (group.defaultValue) {
|
|
1734
|
-
defaults.push({ key: group.name.toLowerCase(), value: group.defaultValue });
|
|
1735
|
-
}
|
|
1736
|
-
}
|
|
1737
|
-
if (defaults.length === 0) return;
|
|
1738
|
-
for (const entity of entities) {
|
|
1739
|
-
if (skip?.(entity)) continue;
|
|
1740
|
-
for (const { key, value } of defaults) {
|
|
1741
|
-
if (!(key in entity.metadata)) {
|
|
1742
|
-
entity.metadata[key] = value;
|
|
1743
|
-
}
|
|
1744
|
-
}
|
|
1745
|
-
}
|
|
1746
|
-
}
|
|
1747
|
-
function matchTagBlockHeading(trimmed) {
|
|
1748
|
-
const tagMatch = trimmed.match(TAG_BLOCK_RE);
|
|
1749
|
-
if (tagMatch) {
|
|
1750
|
-
return {
|
|
1751
|
-
name: tagMatch[1].trim(),
|
|
1752
|
-
alias: tagMatch[2] || void 0,
|
|
1753
|
-
colorHint: tagMatch[3] || void 0,
|
|
1754
|
-
deprecated: false
|
|
1755
|
-
};
|
|
1756
|
-
}
|
|
1757
|
-
const groupMatch = trimmed.match(GROUP_HEADING_RE);
|
|
1758
|
-
if (groupMatch) {
|
|
1759
|
-
return {
|
|
1760
|
-
name: groupMatch[1].trim(),
|
|
1761
|
-
alias: groupMatch[2] || void 0,
|
|
1762
|
-
colorHint: groupMatch[3] || void 0,
|
|
1763
|
-
deprecated: true
|
|
1764
|
-
};
|
|
1765
|
-
}
|
|
1766
|
-
return null;
|
|
1767
|
-
}
|
|
1768
|
-
var TAG_BLOCK_RE, GROUP_HEADING_RE;
|
|
1769
|
-
var init_tag_groups = __esm({
|
|
1770
|
-
"src/utils/tag-groups.ts"() {
|
|
1771
|
-
"use strict";
|
|
1772
|
-
TAG_BLOCK_RE = /^tag:\s+(.+?)(?:\s+alias\s+(\w+))?(?:\s*\(([^)]+)\))?\s*$/i;
|
|
1773
|
-
GROUP_HEADING_RE = /^##\s+(.+?)(?:\s+alias\s+(\w+))?(?:\s*\(([^)]+)\))?\s*$/;
|
|
1774
|
-
}
|
|
1775
|
-
});
|
|
1776
|
-
|
|
1777
1777
|
// src/sequence/parser.ts
|
|
1778
1778
|
var parser_exports = {};
|
|
1779
1779
|
__export(parser_exports, {
|
|
@@ -3361,6 +3361,7 @@ function parseERDiagram(content, palette) {
|
|
|
3361
3361
|
options: {},
|
|
3362
3362
|
tables: [],
|
|
3363
3363
|
relationships: [],
|
|
3364
|
+
tagGroups: [],
|
|
3364
3365
|
diagnostics: [],
|
|
3365
3366
|
error: null
|
|
3366
3367
|
};
|
|
@@ -3378,6 +3379,8 @@ function parseERDiagram(content, palette) {
|
|
|
3378
3379
|
const tableMap = /* @__PURE__ */ new Map();
|
|
3379
3380
|
let currentTable = null;
|
|
3380
3381
|
let contentStarted = false;
|
|
3382
|
+
let currentTagGroup = null;
|
|
3383
|
+
const aliasMap = /* @__PURE__ */ new Map();
|
|
3381
3384
|
function getOrCreateTable(name, lineNumber) {
|
|
3382
3385
|
const id = tableId(name);
|
|
3383
3386
|
const existing = tableMap.get(id);
|
|
@@ -3386,6 +3389,7 @@ function parseERDiagram(content, palette) {
|
|
|
3386
3389
|
id,
|
|
3387
3390
|
name,
|
|
3388
3391
|
columns: [],
|
|
3392
|
+
metadata: {},
|
|
3389
3393
|
lineNumber
|
|
3390
3394
|
};
|
|
3391
3395
|
tableMap.set(id, table);
|
|
@@ -3402,6 +3406,50 @@ function parseERDiagram(content, palette) {
|
|
|
3402
3406
|
continue;
|
|
3403
3407
|
}
|
|
3404
3408
|
if (trimmed.startsWith("//")) continue;
|
|
3409
|
+
if (!contentStarted && indent === 0) {
|
|
3410
|
+
const tagBlockMatch = matchTagBlockHeading(trimmed);
|
|
3411
|
+
if (tagBlockMatch) {
|
|
3412
|
+
if (tagBlockMatch.deprecated) {
|
|
3413
|
+
result.diagnostics.push(makeDgmoError(
|
|
3414
|
+
lineNumber,
|
|
3415
|
+
`'## ${tagBlockMatch.name}' is deprecated for tag groups \u2014 use 'tag: ${tagBlockMatch.name}' instead`,
|
|
3416
|
+
"warning"
|
|
3417
|
+
));
|
|
3418
|
+
}
|
|
3419
|
+
currentTagGroup = {
|
|
3420
|
+
name: tagBlockMatch.name,
|
|
3421
|
+
alias: tagBlockMatch.alias,
|
|
3422
|
+
entries: [],
|
|
3423
|
+
lineNumber
|
|
3424
|
+
};
|
|
3425
|
+
if (tagBlockMatch.alias) {
|
|
3426
|
+
aliasMap.set(tagBlockMatch.alias.toLowerCase(), tagBlockMatch.name.toLowerCase());
|
|
3427
|
+
}
|
|
3428
|
+
result.tagGroups.push(currentTagGroup);
|
|
3429
|
+
continue;
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
if (currentTagGroup && !contentStarted && indent > 0) {
|
|
3433
|
+
const isDefault = /\bdefault\s*$/.test(trimmed);
|
|
3434
|
+
const entryText = isDefault ? trimmed.replace(/\s+default\s*$/, "").trim() : trimmed;
|
|
3435
|
+
const { label, color } = extractColor(entryText, palette);
|
|
3436
|
+
if (!color) {
|
|
3437
|
+
result.diagnostics.push(makeDgmoError(
|
|
3438
|
+
lineNumber,
|
|
3439
|
+
`Expected 'Value(color)' in tag group '${currentTagGroup.name}'`,
|
|
3440
|
+
"warning"
|
|
3441
|
+
));
|
|
3442
|
+
continue;
|
|
3443
|
+
}
|
|
3444
|
+
if (isDefault) {
|
|
3445
|
+
currentTagGroup.defaultValue = label;
|
|
3446
|
+
}
|
|
3447
|
+
currentTagGroup.entries.push({ value: label, color, lineNumber });
|
|
3448
|
+
continue;
|
|
3449
|
+
}
|
|
3450
|
+
if (currentTagGroup && indent === 0) {
|
|
3451
|
+
currentTagGroup = null;
|
|
3452
|
+
}
|
|
3405
3453
|
if (!contentStarted && indent === 0 && /^[a-z][a-z0-9-]*\s*:/i.test(trimmed)) {
|
|
3406
3454
|
const colonIdx = trimmed.indexOf(":");
|
|
3407
3455
|
const key = trimmed.substring(0, colonIdx).trim().toLowerCase();
|
|
@@ -3483,6 +3531,11 @@ function parseERDiagram(content, palette) {
|
|
|
3483
3531
|
const table = getOrCreateTable(name, lineNumber);
|
|
3484
3532
|
if (color) table.color = color;
|
|
3485
3533
|
table.lineNumber = lineNumber;
|
|
3534
|
+
const pipeStr = tableDecl[3]?.trim();
|
|
3535
|
+
if (pipeStr) {
|
|
3536
|
+
const meta = parsePipeMetadata(["", pipeStr], aliasMap);
|
|
3537
|
+
Object.assign(table.metadata, meta);
|
|
3538
|
+
}
|
|
3486
3539
|
currentTable = table;
|
|
3487
3540
|
continue;
|
|
3488
3541
|
}
|
|
@@ -3492,6 +3545,27 @@ function parseERDiagram(content, palette) {
|
|
|
3492
3545
|
result.diagnostics.push(diag);
|
|
3493
3546
|
result.error = formatDgmoError(diag);
|
|
3494
3547
|
}
|
|
3548
|
+
if (result.tagGroups.length > 0) {
|
|
3549
|
+
const tagEntities = result.tables.map((t) => ({
|
|
3550
|
+
metadata: t.metadata,
|
|
3551
|
+
lineNumber: t.lineNumber
|
|
3552
|
+
}));
|
|
3553
|
+
validateTagValues(
|
|
3554
|
+
tagEntities,
|
|
3555
|
+
result.tagGroups,
|
|
3556
|
+
(line10, msg) => result.diagnostics.push(makeDgmoError(line10, msg, "warning")),
|
|
3557
|
+
suggest
|
|
3558
|
+
);
|
|
3559
|
+
for (const group of result.tagGroups) {
|
|
3560
|
+
if (!group.defaultValue) continue;
|
|
3561
|
+
const key = group.name.toLowerCase();
|
|
3562
|
+
for (const table of result.tables) {
|
|
3563
|
+
if (!table.metadata[key]) {
|
|
3564
|
+
table.metadata[key] = group.defaultValue;
|
|
3565
|
+
}
|
|
3566
|
+
}
|
|
3567
|
+
}
|
|
3568
|
+
}
|
|
3495
3569
|
if (result.tables.length >= 2 && result.relationships.length >= 1 && !result.error) {
|
|
3496
3570
|
const connectedIds = /* @__PURE__ */ new Set();
|
|
3497
3571
|
for (const rel of result.relationships) {
|
|
@@ -3543,7 +3617,8 @@ var init_parser3 = __esm({
|
|
|
3543
3617
|
init_colors();
|
|
3544
3618
|
init_diagnostics();
|
|
3545
3619
|
init_parsing();
|
|
3546
|
-
|
|
3620
|
+
init_tag_groups();
|
|
3621
|
+
TABLE_DECL_RE = /^([a-zA-Z_]\w*)(?:\s*\(([^)]+)\))?(?:\s*\|(.+))?$/;
|
|
3547
3622
|
COLUMN_RE = /^(\w+)(?:\s*:\s*(\w[\w()]*(?:\s*\[\])?))?(?:\s+\[([^\]]+)\])?\s*$/;
|
|
3548
3623
|
INDENT_REL_RE = /^([1*?])-(?:(.+)-)?([1*?])\s+([a-zA-Z_]\w*)\s*$/;
|
|
3549
3624
|
CONSTRAINT_MAP = {
|
|
@@ -3581,7 +3656,10 @@ function parseChart(content, palette) {
|
|
|
3581
3656
|
const trimmed = lines[i].trim();
|
|
3582
3657
|
const lineNumber = i + 1;
|
|
3583
3658
|
if (!trimmed) continue;
|
|
3584
|
-
if (/^#{2,}\s+/.test(trimmed))
|
|
3659
|
+
if (/^#{2,}\s+/.test(trimmed)) {
|
|
3660
|
+
result.diagnostics.push(makeDgmoError(lineNumber, `'${trimmed}' \u2014 ## syntax is no longer supported. Use [Group] containers instead`));
|
|
3661
|
+
continue;
|
|
3662
|
+
}
|
|
3585
3663
|
if (trimmed.startsWith("//")) continue;
|
|
3586
3664
|
const colonIndex = trimmed.indexOf(":");
|
|
3587
3665
|
if (colonIndex === -1) continue;
|
|
@@ -3729,9 +3807,16 @@ function parseEChart(content, palette) {
|
|
|
3729
3807
|
const trimmed = lines[i].trim();
|
|
3730
3808
|
const lineNumber = i + 1;
|
|
3731
3809
|
if (!trimmed) continue;
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3810
|
+
if (/^#{2,}\s+/.test(trimmed)) {
|
|
3811
|
+
const name = trimmed.replace(/^#{2,}\s+/, "").replace(/\s*\([^)]*\)\s*$/, "").trim();
|
|
3812
|
+
result.diagnostics.push(makeDgmoError(lineNumber, `'## ${name}' is no longer supported. Use '[${name}]' instead`));
|
|
3813
|
+
continue;
|
|
3814
|
+
}
|
|
3815
|
+
if (trimmed.startsWith("//")) continue;
|
|
3816
|
+
const categoryMatch = trimmed.match(/^\[(.+?)\](?:\s*\(([^)]+)\))?\s*$/);
|
|
3817
|
+
if (categoryMatch) {
|
|
3818
|
+
const catName = categoryMatch[1].trim();
|
|
3819
|
+
const catColor = categoryMatch[2] ? resolveColor(categoryMatch[2].trim(), palette) : null;
|
|
3735
3820
|
if (catColor) {
|
|
3736
3821
|
if (!result.categoryColors) result.categoryColors = {};
|
|
3737
3822
|
result.categoryColors[catName] = catColor;
|
|
@@ -3739,12 +3824,6 @@ function parseEChart(content, palette) {
|
|
|
3739
3824
|
currentCategory = catName;
|
|
3740
3825
|
continue;
|
|
3741
3826
|
}
|
|
3742
|
-
if (trimmed.startsWith("//")) continue;
|
|
3743
|
-
const categoryMatch = trimmed.match(/^\[(.+)\]$/);
|
|
3744
|
-
if (categoryMatch) {
|
|
3745
|
-
currentCategory = categoryMatch[1].trim();
|
|
3746
|
-
continue;
|
|
3747
|
-
}
|
|
3748
3827
|
const colonIndex = trimmed.indexOf(":");
|
|
3749
3828
|
if (result.type === "sankey" && colonIndex === -1) {
|
|
3750
3829
|
const indent = measureIndent(lines[i]);
|
|
@@ -5375,6 +5454,7 @@ function parseKanban(content, palette) {
|
|
|
5375
5454
|
let currentTagGroup = null;
|
|
5376
5455
|
let currentColumn = null;
|
|
5377
5456
|
let currentCard = null;
|
|
5457
|
+
let cardBaseIndent = 0;
|
|
5378
5458
|
let columnCounter = 0;
|
|
5379
5459
|
let cardCounter = 0;
|
|
5380
5460
|
const aliasMap = /* @__PURE__ */ new Map();
|
|
@@ -5474,7 +5554,14 @@ function parseKanban(content, palette) {
|
|
|
5474
5554
|
}
|
|
5475
5555
|
currentTagGroup = null;
|
|
5476
5556
|
}
|
|
5477
|
-
const
|
|
5557
|
+
const indent = measureIndent(line10);
|
|
5558
|
+
if (LEGACY_COLUMN_RE.test(trimmed)) {
|
|
5559
|
+
const legacyMatch = trimmed.match(LEGACY_COLUMN_RE);
|
|
5560
|
+
const name = legacyMatch[1].replace(/\s*\(.*\)\s*$/, "").trim();
|
|
5561
|
+
warn(lineNumber, `'== ${name} ==' is no longer supported. Use '[${name}]' instead`);
|
|
5562
|
+
continue;
|
|
5563
|
+
}
|
|
5564
|
+
const columnMatch = indent === 0 ? trimmed.match(COLUMN_RE2) : null;
|
|
5478
5565
|
if (columnMatch) {
|
|
5479
5566
|
contentStarted = true;
|
|
5480
5567
|
currentTagGroup = null;
|
|
@@ -5486,16 +5573,20 @@ function parseKanban(content, palette) {
|
|
|
5486
5573
|
}
|
|
5487
5574
|
currentCard = null;
|
|
5488
5575
|
columnCounter++;
|
|
5489
|
-
const
|
|
5490
|
-
const
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5576
|
+
const colName = columnMatch[1].trim();
|
|
5577
|
+
const colColor = columnMatch[2] ? resolveColor(columnMatch[2].trim(), palette) : void 0;
|
|
5578
|
+
let wipLimit;
|
|
5579
|
+
const pipeStr = columnMatch[3];
|
|
5580
|
+
if (pipeStr) {
|
|
5581
|
+
const wipMatch = pipeStr.match(/\bwip\s*:\s*(\d+)\b/i);
|
|
5582
|
+
if (wipMatch) {
|
|
5583
|
+
wipLimit = parseInt(wipMatch[1], 10);
|
|
5584
|
+
}
|
|
5585
|
+
}
|
|
5495
5586
|
currentColumn = {
|
|
5496
5587
|
id: `col-${columnCounter}`,
|
|
5497
5588
|
name: colName,
|
|
5498
|
-
wipLimit
|
|
5589
|
+
wipLimit,
|
|
5499
5590
|
color: colColor,
|
|
5500
5591
|
cards: [],
|
|
5501
5592
|
lineNumber
|
|
@@ -5510,24 +5601,25 @@ function parseKanban(content, palette) {
|
|
|
5510
5601
|
warn(lineNumber, "Card line found before any column");
|
|
5511
5602
|
continue;
|
|
5512
5603
|
}
|
|
5513
|
-
|
|
5514
|
-
if (indent > 0 && currentCard) {
|
|
5604
|
+
if (currentCard && indent > cardBaseIndent) {
|
|
5515
5605
|
currentCard.details.push(trimmed);
|
|
5516
5606
|
currentCard.endLineNumber = lineNumber;
|
|
5517
5607
|
continue;
|
|
5518
5608
|
}
|
|
5519
|
-
if (
|
|
5609
|
+
if (indent > 0) {
|
|
5610
|
+
cardCounter++;
|
|
5611
|
+
const card = parseCardLine(
|
|
5612
|
+
trimmed,
|
|
5613
|
+
lineNumber,
|
|
5614
|
+
cardCounter,
|
|
5615
|
+
aliasMap,
|
|
5616
|
+
palette
|
|
5617
|
+
);
|
|
5618
|
+
cardBaseIndent = indent;
|
|
5619
|
+
currentCard = card;
|
|
5620
|
+
currentColumn.cards.push(card);
|
|
5621
|
+
continue;
|
|
5520
5622
|
}
|
|
5521
|
-
cardCounter++;
|
|
5522
|
-
const card = parseCardLine(
|
|
5523
|
-
trimmed,
|
|
5524
|
-
lineNumber,
|
|
5525
|
-
cardCounter,
|
|
5526
|
-
aliasMap,
|
|
5527
|
-
palette
|
|
5528
|
-
);
|
|
5529
|
-
currentCard = card;
|
|
5530
|
-
currentColumn.cards.push(card);
|
|
5531
5623
|
}
|
|
5532
5624
|
if (currentCard) {
|
|
5533
5625
|
}
|
|
@@ -5561,7 +5653,7 @@ function parseKanban(content, palette) {
|
|
|
5561
5653
|
}
|
|
5562
5654
|
}
|
|
5563
5655
|
if (result.columns.length === 0 && !result.error) {
|
|
5564
|
-
return fail(1, "No columns found. Use
|
|
5656
|
+
return fail(1, "No columns found. Use [Column Name] to define columns");
|
|
5565
5657
|
}
|
|
5566
5658
|
return result;
|
|
5567
5659
|
}
|
|
@@ -5598,14 +5690,16 @@ function parseCardLine(trimmed, lineNumber, counter, aliasMap, palette) {
|
|
|
5598
5690
|
color
|
|
5599
5691
|
};
|
|
5600
5692
|
}
|
|
5601
|
-
var COLUMN_RE2;
|
|
5693
|
+
var COLUMN_RE2, LEGACY_COLUMN_RE;
|
|
5602
5694
|
var init_parser5 = __esm({
|
|
5603
5695
|
"src/kanban/parser.ts"() {
|
|
5604
5696
|
"use strict";
|
|
5605
5697
|
init_diagnostics();
|
|
5698
|
+
init_colors();
|
|
5606
5699
|
init_tag_groups();
|
|
5607
5700
|
init_parsing();
|
|
5608
|
-
COLUMN_RE2 =
|
|
5701
|
+
COLUMN_RE2 = /^\[(.+?)\](?:\s*\(([^)]+)\))?\s*(?:\|\s*(.+))?$/;
|
|
5702
|
+
LEGACY_COLUMN_RE = /^==\s+(.+?)\s*(?:\[wip:\s*(\d+)\])?\s*==$/;
|
|
5609
5703
|
}
|
|
5610
5704
|
});
|
|
5611
5705
|
|
|
@@ -7190,7 +7284,7 @@ var init_parser9 = __esm({
|
|
|
7190
7284
|
TAG_GROUP_RE = /^tag\s*:\s*(\w[\w\s]*?)(?:\s+alias\s+(\w+))?\s*$/;
|
|
7191
7285
|
TAG_VALUE_RE = /^(\w[\w\s]*?)(?:\(([^)]+)\))?(\s+default)?\s*$/;
|
|
7192
7286
|
COMPONENT_RE = /^([a-zA-Z_][\w]*)(.*)$/;
|
|
7193
|
-
PIPE_META_RE =
|
|
7287
|
+
PIPE_META_RE = /[|,]\s*(\w+)\s*:\s*([^|,]+)/g;
|
|
7194
7288
|
PROPERTY_RE = /^([\w-]+)\s*:\s*(.+)$/;
|
|
7195
7289
|
PERCENT_RE = /^([\d.]+)%$/;
|
|
7196
7290
|
RANGE_RE = /^(\d+)-(\d+)$/;
|
|
@@ -9556,7 +9650,7 @@ function computeCardArchive(content, parsed, cardId) {
|
|
|
9556
9650
|
const trimmedEnd = withoutCard.length > 0 && withoutCard[withoutCard.length - 1].trim() === "" ? withoutCard : [...withoutCard, ""];
|
|
9557
9651
|
return [
|
|
9558
9652
|
...trimmedEnd,
|
|
9559
|
-
"
|
|
9653
|
+
"[Archive]",
|
|
9560
9654
|
...cardLines
|
|
9561
9655
|
].join("\n");
|
|
9562
9656
|
}
|
|
@@ -10437,7 +10531,7 @@ function drawCardinality(g, point, prevPoint, cardinality, color, useLabels) {
|
|
|
10437
10531
|
g.append("line").attr("x1", bx + px * spread).attr("y1", by + py * spread).attr("x2", bx - px * spread).attr("y2", by - py * spread).attr("stroke", color).attr("stroke-width", sw);
|
|
10438
10532
|
}
|
|
10439
10533
|
}
|
|
10440
|
-
function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem, exportDims) {
|
|
10534
|
+
function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem, exportDims, activeTagGroup) {
|
|
10441
10535
|
d3Selection5.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
10442
10536
|
const width = exportDims?.width ?? container.clientWidth;
|
|
10443
10537
|
const height = exportDims?.height ?? container.clientHeight;
|
|
@@ -10507,8 +10601,16 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10507
10601
|
}
|
|
10508
10602
|
for (let ni = 0; ni < layout.nodes.length; ni++) {
|
|
10509
10603
|
const node = layout.nodes[ni];
|
|
10510
|
-
const
|
|
10604
|
+
const tagColor = resolveTagColor(node.metadata, parsed.tagGroups, activeTagGroup ?? null);
|
|
10605
|
+
const nodeColor2 = node.color ?? tagColor ?? seriesColors2[ni % seriesColors2.length];
|
|
10511
10606
|
const nodeG = contentG.append("g").attr("transform", `translate(${node.x}, ${node.y})`).attr("class", "er-table").attr("data-line-number", String(node.lineNumber)).attr("data-node-id", node.id);
|
|
10607
|
+
if (activeTagGroup) {
|
|
10608
|
+
const tagKey = activeTagGroup.toLowerCase();
|
|
10609
|
+
const tagValue = node.metadata[tagKey];
|
|
10610
|
+
if (tagValue) {
|
|
10611
|
+
nodeG.attr(`data-tag-${tagKey}`, tagValue.toLowerCase());
|
|
10612
|
+
}
|
|
10613
|
+
}
|
|
10512
10614
|
if (onClickItem) {
|
|
10513
10615
|
nodeG.style("cursor", "pointer").on("click", () => {
|
|
10514
10616
|
onClickItem(node.lineNumber);
|
|
@@ -10540,6 +10642,35 @@ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem
|
|
|
10540
10642
|
}
|
|
10541
10643
|
}
|
|
10542
10644
|
}
|
|
10645
|
+
if (parsed.tagGroups.length > 0) {
|
|
10646
|
+
const LEGEND_Y_PAD = 16;
|
|
10647
|
+
const LEGEND_PILL_H = 22;
|
|
10648
|
+
const LEGEND_PILL_RX = 11;
|
|
10649
|
+
const LEGEND_PILL_PAD9 = 10;
|
|
10650
|
+
const LEGEND_GAP2 = 8;
|
|
10651
|
+
const LEGEND_FONT_SIZE2 = 11;
|
|
10652
|
+
const LEGEND_GROUP_GAP7 = 16;
|
|
10653
|
+
const legendG = svg.append("g").attr("class", "er-tag-legend");
|
|
10654
|
+
let legendX = DIAGRAM_PADDING5;
|
|
10655
|
+
let legendY = height - DIAGRAM_PADDING5;
|
|
10656
|
+
for (const group of parsed.tagGroups) {
|
|
10657
|
+
const groupG = legendG.append("g").attr("data-legend-group", group.name.toLowerCase());
|
|
10658
|
+
const labelText = groupG.append("text").attr("x", legendX).attr("y", legendY + LEGEND_PILL_H / 2).attr("dominant-baseline", "central").attr("fill", palette.textMuted).attr("font-size", LEGEND_FONT_SIZE2).attr("font-family", FONT_FAMILY).text(`${group.name}:`);
|
|
10659
|
+
const labelWidth = (labelText.node()?.getComputedTextLength?.() ?? group.name.length * 7) + 6;
|
|
10660
|
+
legendX += labelWidth;
|
|
10661
|
+
for (const entry of group.entries) {
|
|
10662
|
+
const pillG = groupG.append("g").attr("data-legend-entry", entry.value.toLowerCase()).style("cursor", "pointer");
|
|
10663
|
+
const tmpText = legendG.append("text").attr("font-size", LEGEND_FONT_SIZE2).attr("font-family", FONT_FAMILY).text(entry.value);
|
|
10664
|
+
const textW = tmpText.node()?.getComputedTextLength?.() ?? entry.value.length * 7;
|
|
10665
|
+
tmpText.remove();
|
|
10666
|
+
const pillW = textW + LEGEND_PILL_PAD9 * 2;
|
|
10667
|
+
pillG.append("rect").attr("x", legendX).attr("y", legendY).attr("width", pillW).attr("height", LEGEND_PILL_H).attr("rx", LEGEND_PILL_RX).attr("ry", LEGEND_PILL_RX).attr("fill", mix(entry.color, isDark ? palette.surface : palette.bg, 25)).attr("stroke", entry.color).attr("stroke-width", 1);
|
|
10668
|
+
pillG.append("text").attr("x", legendX + pillW / 2).attr("y", legendY + LEGEND_PILL_H / 2).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", palette.text).attr("font-size", LEGEND_FONT_SIZE2).attr("font-family", FONT_FAMILY).text(entry.value);
|
|
10669
|
+
legendX += pillW + LEGEND_GAP2;
|
|
10670
|
+
}
|
|
10671
|
+
legendX += LEGEND_GROUP_GAP7;
|
|
10672
|
+
}
|
|
10673
|
+
}
|
|
10543
10674
|
}
|
|
10544
10675
|
function renderERDiagramForExport(content, theme, palette) {
|
|
10545
10676
|
const parsed = parseERDiagram(content, palette);
|
|
@@ -10583,6 +10714,7 @@ var init_renderer5 = __esm({
|
|
|
10583
10714
|
init_fonts();
|
|
10584
10715
|
init_color_utils();
|
|
10585
10716
|
init_palettes();
|
|
10717
|
+
init_tag_groups();
|
|
10586
10718
|
init_parser3();
|
|
10587
10719
|
init_layout4();
|
|
10588
10720
|
DIAGRAM_PADDING5 = 20;
|
|
@@ -15015,7 +15147,7 @@ function formatUptime(fraction) {
|
|
|
15015
15147
|
if (pct >= 99) return `${pct.toFixed(1)}%`;
|
|
15016
15148
|
return `${pct.toFixed(1)}%`;
|
|
15017
15149
|
}
|
|
15018
|
-
function layoutInfra(computed, selectedNodeId) {
|
|
15150
|
+
function layoutInfra(computed, selectedNodeId, collapsedNodes) {
|
|
15019
15151
|
if (computed.nodes.length === 0) {
|
|
15020
15152
|
return { nodes: [], edges: [], groups: [], options: {}, width: 0, height: 0 };
|
|
15021
15153
|
}
|
|
@@ -15036,9 +15168,10 @@ function layoutInfra(computed, selectedNodeId) {
|
|
|
15036
15168
|
const widthMap = /* @__PURE__ */ new Map();
|
|
15037
15169
|
const heightMap = /* @__PURE__ */ new Map();
|
|
15038
15170
|
for (const node of computed.nodes) {
|
|
15039
|
-
const
|
|
15171
|
+
const isNodeCollapsed = collapsedNodes?.has(node.id) ?? false;
|
|
15172
|
+
const expanded = !isNodeCollapsed && node.id === selectedNodeId;
|
|
15040
15173
|
const width = computeNodeWidth2(node, expanded, computed.options);
|
|
15041
|
-
const height = computeNodeHeight2(node, expanded, computed.options);
|
|
15174
|
+
const height = isNodeCollapsed ? NODE_HEADER_HEIGHT + NODE_PAD_BOTTOM : computeNodeHeight2(node, expanded, computed.options);
|
|
15042
15175
|
widthMap.set(node.id, width);
|
|
15043
15176
|
heightMap.set(node.id, height);
|
|
15044
15177
|
const inGroup = groupedNodeIds.has(node.id);
|
|
@@ -15612,10 +15745,27 @@ function renderEdgeLabels(svg, edges, palette, isDark, animate) {
|
|
|
15612
15745
|
}
|
|
15613
15746
|
}
|
|
15614
15747
|
}
|
|
15615
|
-
function
|
|
15748
|
+
function resolveActiveTagStroke(node, activeGroup, tagGroups, palette) {
|
|
15749
|
+
const tg = tagGroups.find((t) => t.name.toLowerCase() === activeGroup.toLowerCase());
|
|
15750
|
+
if (!tg) return null;
|
|
15751
|
+
const tagKey = (tg.alias ?? tg.name).toLowerCase();
|
|
15752
|
+
const tagVal = node.tags[tagKey];
|
|
15753
|
+
if (!tagVal) return null;
|
|
15754
|
+
const tv = tg.values.find((v) => v.name.toLowerCase() === tagVal.toLowerCase());
|
|
15755
|
+
if (!tv?.color) return null;
|
|
15756
|
+
return resolveColor(tv.color, palette);
|
|
15757
|
+
}
|
|
15758
|
+
function renderNodes(svg, nodes, palette, isDark, animate, selectedNodeId, activeGroup, diagramOptions, collapsedNodes, tagGroups) {
|
|
15616
15759
|
const mutedColor = palette.textMuted;
|
|
15617
15760
|
for (const node of nodes) {
|
|
15618
|
-
|
|
15761
|
+
let { fill: fill2, stroke: stroke2, textFill } = nodeColor(node, palette, isDark);
|
|
15762
|
+
if (activeGroup && tagGroups && !node.isEdge) {
|
|
15763
|
+
const tagStroke = resolveActiveTagStroke(node, activeGroup, tagGroups, palette);
|
|
15764
|
+
if (tagStroke) {
|
|
15765
|
+
stroke2 = tagStroke;
|
|
15766
|
+
fill2 = mix(palette.bg, tagStroke, isDark ? 88 : 94);
|
|
15767
|
+
}
|
|
15768
|
+
}
|
|
15619
15769
|
let cls = "infra-node";
|
|
15620
15770
|
if (animate && node.isEdge) {
|
|
15621
15771
|
cls += " infra-node-edge-throb";
|
|
@@ -15625,9 +15775,9 @@ function renderNodes(svg, nodes, palette, isDark, animate, selectedNodeId, activ
|
|
|
15625
15775
|
else if (severity === "overloaded") cls += " infra-node-overload";
|
|
15626
15776
|
else if (severity === "warning") cls += " infra-node-warning";
|
|
15627
15777
|
}
|
|
15628
|
-
const g = svg.append("g").attr("class", cls).attr("data-line-number", node.lineNumber).attr("data-infra-node", node.id);
|
|
15778
|
+
const g = svg.append("g").attr("class", cls).attr("data-line-number", node.lineNumber).attr("data-infra-node", node.id).attr("data-node-collapse", node.id).style("cursor", "pointer");
|
|
15629
15779
|
if (node.id.startsWith("[")) {
|
|
15630
|
-
g.attr("data-node-toggle", node.id)
|
|
15780
|
+
g.attr("data-node-toggle", node.id);
|
|
15631
15781
|
}
|
|
15632
15782
|
for (const [tagKey, tagVal] of Object.entries(node.tags)) {
|
|
15633
15783
|
g.attr(`data-tag-${tagKey.toLowerCase()}`, tagVal.toLowerCase());
|
|
@@ -15645,7 +15795,12 @@ function renderNodes(svg, nodes, palette, isDark, animate, selectedNodeId, activ
|
|
|
15645
15795
|
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);
|
|
15646
15796
|
const headerCenterY = y + NODE_HEADER_HEIGHT2 / 2 + NODE_FONT_SIZE3 * 0.35;
|
|
15647
15797
|
g.append("text").attr("x", node.x).attr("y", headerCenterY).attr("text-anchor", "middle").attr("font-family", FONT_FAMILY).attr("font-size", NODE_FONT_SIZE3).attr("font-weight", "600").attr("fill", textFill).text(node.label);
|
|
15648
|
-
|
|
15798
|
+
const isNodeCollapsed = collapsedNodes?.has(node.id) ?? false;
|
|
15799
|
+
if (isNodeCollapsed) {
|
|
15800
|
+
const chevronY = y + node.height - 6;
|
|
15801
|
+
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
|
+
}
|
|
15803
|
+
if (!isNodeCollapsed) {
|
|
15649
15804
|
const expanded = node.id === selectedNodeId;
|
|
15650
15805
|
const displayProps = !node.isEdge && expanded ? getDisplayProps(node, expanded, diagramOptions) : [];
|
|
15651
15806
|
const computedRows = getComputedRows(node, expanded);
|
|
@@ -15968,7 +16123,7 @@ function renderLegend3(rootSvg, legendGroups, totalWidth, legendY, palette, isDa
|
|
|
15968
16123
|
cursorX += fullW + LEGEND_GROUP_GAP5;
|
|
15969
16124
|
}
|
|
15970
16125
|
}
|
|
15971
|
-
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, selectedNodeId, exportMode) {
|
|
16126
|
+
function renderInfra(container, layout, palette, isDark, title, titleLineNumber, tagGroups, activeGroup, animate, playback, selectedNodeId, exportMode, collapsedNodes) {
|
|
15972
16127
|
d3Selection9.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
15973
16128
|
const legendGroups = computeInfraLegendGroups(layout.nodes, tagGroups ?? [], palette);
|
|
15974
16129
|
const hasLegend = legendGroups.length > 0 || !!playback;
|
|
@@ -16027,7 +16182,7 @@ function renderInfra(container, layout, palette, isDark, title, titleLineNumber,
|
|
|
16027
16182
|
}
|
|
16028
16183
|
renderGroups(svg, layout.groups, palette, isDark);
|
|
16029
16184
|
renderEdgePaths(svg, layout.edges, layout.nodes, palette, isDark, shouldAnimate);
|
|
16030
|
-
renderNodes(svg, layout.nodes, palette, isDark, shouldAnimate, selectedNodeId, activeGroup, layout.options);
|
|
16185
|
+
renderNodes(svg, layout.nodes, palette, isDark, shouldAnimate, selectedNodeId, activeGroup, layout.options, collapsedNodes, tagGroups ?? []);
|
|
16031
16186
|
if (shouldAnimate) {
|
|
16032
16187
|
renderRejectParticles(svg, layout.nodes);
|
|
16033
16188
|
}
|
|
@@ -17966,6 +18121,7 @@ function parseD3(content, palette) {
|
|
|
17966
18121
|
timelineGroups: [],
|
|
17967
18122
|
timelineEras: [],
|
|
17968
18123
|
timelineMarkers: [],
|
|
18124
|
+
timelineTagGroups: [],
|
|
17969
18125
|
timelineSort: "time",
|
|
17970
18126
|
timelineScale: true,
|
|
17971
18127
|
timelineSwimlanes: false,
|
|
@@ -18000,25 +18156,75 @@ function parseD3(content, palette) {
|
|
|
18000
18156
|
const freeformLines = [];
|
|
18001
18157
|
let currentArcGroup = null;
|
|
18002
18158
|
let currentTimelineGroup = null;
|
|
18159
|
+
let currentTimelineTagGroup = null;
|
|
18160
|
+
const timelineAliasMap = /* @__PURE__ */ new Map();
|
|
18003
18161
|
for (let i = 0; i < lines.length; i++) {
|
|
18004
|
-
const
|
|
18162
|
+
const rawLine = lines[i];
|
|
18163
|
+
const line10 = rawLine.trim();
|
|
18164
|
+
const indent = rawLine.length - rawLine.trimStart().length;
|
|
18005
18165
|
const lineNumber = i + 1;
|
|
18006
18166
|
if (!line10) continue;
|
|
18007
|
-
|
|
18008
|
-
|
|
18167
|
+
if (result.type === "timeline" && indent === 0) {
|
|
18168
|
+
const tagBlockMatch = matchTagBlockHeading(line10);
|
|
18169
|
+
if (tagBlockMatch) {
|
|
18170
|
+
if (tagBlockMatch.deprecated) {
|
|
18171
|
+
result.diagnostics.push(makeDgmoError(
|
|
18172
|
+
lineNumber,
|
|
18173
|
+
`'## ${tagBlockMatch.name}' is deprecated for tag groups \u2014 use 'tag: ${tagBlockMatch.name}' instead`,
|
|
18174
|
+
"warning"
|
|
18175
|
+
));
|
|
18176
|
+
}
|
|
18177
|
+
currentTimelineTagGroup = {
|
|
18178
|
+
name: tagBlockMatch.name,
|
|
18179
|
+
alias: tagBlockMatch.alias,
|
|
18180
|
+
entries: [],
|
|
18181
|
+
lineNumber
|
|
18182
|
+
};
|
|
18183
|
+
if (tagBlockMatch.alias) {
|
|
18184
|
+
timelineAliasMap.set(tagBlockMatch.alias.toLowerCase(), tagBlockMatch.name.toLowerCase());
|
|
18185
|
+
}
|
|
18186
|
+
result.timelineTagGroups.push(currentTimelineTagGroup);
|
|
18187
|
+
continue;
|
|
18188
|
+
}
|
|
18189
|
+
}
|
|
18190
|
+
if (currentTimelineTagGroup && indent > 0) {
|
|
18191
|
+
const trimmedEntry = line10;
|
|
18192
|
+
const isDefault = /\bdefault\s*$/.test(trimmedEntry);
|
|
18193
|
+
const entryText = isDefault ? trimmedEntry.replace(/\s+default\s*$/, "").trim() : trimmedEntry;
|
|
18194
|
+
const { label, color } = extractColor(entryText, palette);
|
|
18195
|
+
if (color) {
|
|
18196
|
+
if (isDefault) currentTimelineTagGroup.defaultValue = label;
|
|
18197
|
+
currentTimelineTagGroup.entries.push({ value: label, color, lineNumber });
|
|
18198
|
+
continue;
|
|
18199
|
+
}
|
|
18200
|
+
}
|
|
18201
|
+
if (currentTimelineTagGroup && indent === 0) {
|
|
18202
|
+
currentTimelineTagGroup = null;
|
|
18203
|
+
}
|
|
18204
|
+
const groupMatch = line10.match(/^\[(.+?)\](?:\s*\(([^)]+)\))?\s*$/);
|
|
18205
|
+
if (groupMatch) {
|
|
18009
18206
|
if (result.type === "arc") {
|
|
18010
|
-
const name =
|
|
18011
|
-
const color =
|
|
18207
|
+
const name = groupMatch[1].trim();
|
|
18208
|
+
const color = groupMatch[2] ? resolveColor(groupMatch[2].trim(), palette) : null;
|
|
18012
18209
|
result.arcNodeGroups.push({ name, nodes: [], color, lineNumber });
|
|
18013
18210
|
currentArcGroup = name;
|
|
18014
18211
|
} else if (result.type === "timeline") {
|
|
18015
|
-
const name =
|
|
18016
|
-
const color =
|
|
18212
|
+
const name = groupMatch[1].trim();
|
|
18213
|
+
const color = groupMatch[2] ? resolveColor(groupMatch[2].trim(), palette) : null;
|
|
18017
18214
|
result.timelineGroups.push({ name, color, lineNumber });
|
|
18018
18215
|
currentTimelineGroup = name;
|
|
18019
18216
|
}
|
|
18020
18217
|
continue;
|
|
18021
18218
|
}
|
|
18219
|
+
if (/^#{2,}\s+/.test(line10) && (result.type === "arc" || result.type === "timeline")) {
|
|
18220
|
+
const name = line10.replace(/^#{2,}\s+/, "").replace(/\s*\([^)]*\)\s*$/, "").trim();
|
|
18221
|
+
result.diagnostics.push(makeDgmoError(lineNumber, `'## ${name}' is no longer supported. Use '[${name}]' instead`, "warning"));
|
|
18222
|
+
continue;
|
|
18223
|
+
}
|
|
18224
|
+
if (indent === 0) {
|
|
18225
|
+
currentArcGroup = null;
|
|
18226
|
+
currentTimelineGroup = null;
|
|
18227
|
+
}
|
|
18022
18228
|
if (line10.startsWith("//")) {
|
|
18023
18229
|
continue;
|
|
18024
18230
|
}
|
|
@@ -18090,11 +18296,14 @@ function parseD3(content, palette) {
|
|
|
18090
18296
|
const amount = parseFloat(durationMatch[2]);
|
|
18091
18297
|
const unit = durationMatch[3];
|
|
18092
18298
|
const endDate = addDurationToDate(startDate, amount, unit);
|
|
18299
|
+
const segments = durationMatch[5].split("|");
|
|
18300
|
+
const metadata = segments.length > 1 ? parsePipeMetadata(["", ...segments.slice(1)], timelineAliasMap) : {};
|
|
18093
18301
|
result.timelineEvents.push({
|
|
18094
18302
|
date: startDate,
|
|
18095
18303
|
endDate,
|
|
18096
|
-
label:
|
|
18304
|
+
label: segments[0].trim(),
|
|
18097
18305
|
group: currentTimelineGroup,
|
|
18306
|
+
metadata,
|
|
18098
18307
|
lineNumber,
|
|
18099
18308
|
uncertain
|
|
18100
18309
|
});
|
|
@@ -18104,11 +18313,14 @@ function parseD3(content, palette) {
|
|
|
18104
18313
|
/^(\d{4}(?:-\d{2})?(?:-\d{2})?)\s*->\s*(\d{4}(?:-\d{2})?(?:-\d{2})?)(\?)?\s*:\s*(.+)$/
|
|
18105
18314
|
);
|
|
18106
18315
|
if (rangeMatch) {
|
|
18316
|
+
const segments = rangeMatch[4].split("|");
|
|
18317
|
+
const metadata = segments.length > 1 ? parsePipeMetadata(["", ...segments.slice(1)], timelineAliasMap) : {};
|
|
18107
18318
|
result.timelineEvents.push({
|
|
18108
18319
|
date: rangeMatch[1],
|
|
18109
18320
|
endDate: rangeMatch[2],
|
|
18110
|
-
label:
|
|
18321
|
+
label: segments[0].trim(),
|
|
18111
18322
|
group: currentTimelineGroup,
|
|
18323
|
+
metadata,
|
|
18112
18324
|
lineNumber,
|
|
18113
18325
|
uncertain: rangeMatch[3] === "?"
|
|
18114
18326
|
});
|
|
@@ -18118,11 +18330,14 @@ function parseD3(content, palette) {
|
|
|
18118
18330
|
/^(\d{4}(?:-\d{2})?(?:-\d{2})?)\s*:\s*(.+)$/
|
|
18119
18331
|
);
|
|
18120
18332
|
if (pointMatch) {
|
|
18333
|
+
const segments = pointMatch[2].split("|");
|
|
18334
|
+
const metadata = segments.length > 1 ? parsePipeMetadata(["", ...segments.slice(1)], timelineAliasMap) : {};
|
|
18121
18335
|
result.timelineEvents.push({
|
|
18122
18336
|
date: pointMatch[1],
|
|
18123
18337
|
endDate: null,
|
|
18124
|
-
label:
|
|
18338
|
+
label: segments[0].trim(),
|
|
18125
18339
|
group: currentTimelineGroup,
|
|
18340
|
+
metadata,
|
|
18126
18341
|
lineNumber
|
|
18127
18342
|
});
|
|
18128
18343
|
continue;
|
|
@@ -18385,7 +18600,7 @@ function parseD3(content, palette) {
|
|
|
18385
18600
|
}
|
|
18386
18601
|
if (result.arcNodeGroups.length > 0) {
|
|
18387
18602
|
if (result.arcOrder === "name" || result.arcOrder === "degree") {
|
|
18388
|
-
warn(1, `Cannot use "order: ${result.arcOrder}" with
|
|
18603
|
+
warn(1, `Cannot use "order: ${result.arcOrder}" with [Group] headers. Use "order: group" or remove group headers.`);
|
|
18389
18604
|
result.arcOrder = "group";
|
|
18390
18605
|
}
|
|
18391
18606
|
if (result.arcOrder === "appearance") {
|
|
@@ -18398,6 +18613,23 @@ function parseD3(content, palette) {
|
|
|
18398
18613
|
if (result.timelineEvents.length === 0) {
|
|
18399
18614
|
warn(1, 'No events found. Add events as "YYYY: description" or "YYYY->YYYY: description"');
|
|
18400
18615
|
}
|
|
18616
|
+
if (result.timelineTagGroups.length > 0) {
|
|
18617
|
+
validateTagValues(
|
|
18618
|
+
result.timelineEvents,
|
|
18619
|
+
result.timelineTagGroups,
|
|
18620
|
+
(line10, msg) => result.diagnostics.push(makeDgmoError(line10, msg, "warning")),
|
|
18621
|
+
suggest
|
|
18622
|
+
);
|
|
18623
|
+
for (const group of result.timelineTagGroups) {
|
|
18624
|
+
if (!group.defaultValue) continue;
|
|
18625
|
+
const key = group.name.toLowerCase();
|
|
18626
|
+
for (const event of result.timelineEvents) {
|
|
18627
|
+
if (!event.metadata[key]) {
|
|
18628
|
+
event.metadata[key] = group.defaultValue;
|
|
18629
|
+
}
|
|
18630
|
+
}
|
|
18631
|
+
}
|
|
18632
|
+
}
|
|
18401
18633
|
return result;
|
|
18402
18634
|
}
|
|
18403
18635
|
if (result.type === "venn") {
|
|
@@ -19156,7 +19388,7 @@ function buildEventTooltipHtml(ev) {
|
|
|
19156
19388
|
function buildEraTooltipHtml(era) {
|
|
19157
19389
|
return `<strong>${era.label}</strong><br>${formatDateLabel(era.startDate)} \u2192 ${formatDateLabel(era.endDate)}`;
|
|
19158
19390
|
}
|
|
19159
|
-
function renderTimeline(container, parsed, palette, isDark, onClickItem, exportDims) {
|
|
19391
|
+
function renderTimeline(container, parsed, palette, isDark, onClickItem, exportDims, activeTagGroup) {
|
|
19160
19392
|
d3Selection12.select(container).selectAll(":not([data-d3-tooltip])").remove();
|
|
19161
19393
|
const {
|
|
19162
19394
|
timelineEvents,
|
|
@@ -19184,6 +19416,10 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19184
19416
|
groupColorMap.set(grp.name, grp.color ?? colors[i % colors.length]);
|
|
19185
19417
|
});
|
|
19186
19418
|
function eventColor(ev) {
|
|
19419
|
+
if (activeTagGroup) {
|
|
19420
|
+
const tagColor = resolveTagColor(ev.metadata, parsed.timelineTagGroups, activeTagGroup);
|
|
19421
|
+
if (tagColor) return tagColor;
|
|
19422
|
+
}
|
|
19187
19423
|
if (ev.group && groupColorMap.has(ev.group)) {
|
|
19188
19424
|
return groupColorMap.get(ev.group);
|
|
19189
19425
|
}
|
|
@@ -19254,10 +19490,36 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19254
19490
|
}
|
|
19255
19491
|
function fadeReset(g) {
|
|
19256
19492
|
g.selectAll(
|
|
19257
|
-
".tl-event, .tl-legend-item, .tl-lane-header, .tl-marker"
|
|
19493
|
+
".tl-event, .tl-legend-item, .tl-lane-header, .tl-marker, .tl-tag-legend-entry"
|
|
19258
19494
|
).attr("opacity", 1);
|
|
19259
19495
|
g.selectAll(".tl-era").attr("opacity", 1);
|
|
19260
19496
|
}
|
|
19497
|
+
function fadeToTagValue(g, tagKey, tagValue) {
|
|
19498
|
+
const attrName = `data-tag-${tagKey}`;
|
|
19499
|
+
g.selectAll(".tl-event").each(function() {
|
|
19500
|
+
const el = d3Selection12.select(this);
|
|
19501
|
+
const val = el.attr(attrName);
|
|
19502
|
+
el.attr("opacity", val === tagValue ? 1 : FADE_OPACITY);
|
|
19503
|
+
});
|
|
19504
|
+
g.selectAll(".tl-legend-item, .tl-lane-header").attr(
|
|
19505
|
+
"opacity",
|
|
19506
|
+
FADE_OPACITY
|
|
19507
|
+
);
|
|
19508
|
+
g.selectAll(".tl-marker").attr("opacity", FADE_OPACITY);
|
|
19509
|
+
g.selectAll(".tl-tag-legend-entry").each(function() {
|
|
19510
|
+
const el = d3Selection12.select(this);
|
|
19511
|
+
const entryValue = el.attr("data-legend-entry");
|
|
19512
|
+
if (entryValue === "__group__") return;
|
|
19513
|
+
const entryGroup = el.attr("data-tag-group");
|
|
19514
|
+
el.attr("opacity", entryGroup === tagKey && entryValue === tagValue ? 1 : FADE_OPACITY);
|
|
19515
|
+
});
|
|
19516
|
+
}
|
|
19517
|
+
function setTagAttrs(evG, ev) {
|
|
19518
|
+
for (const [key, value] of Object.entries(ev.metadata)) {
|
|
19519
|
+
evG.attr(`data-tag-${key}`, value.toLowerCase());
|
|
19520
|
+
}
|
|
19521
|
+
}
|
|
19522
|
+
const tagLegendReserve = parsed.timelineTagGroups.length > 0 ? 36 : 0;
|
|
19261
19523
|
if (isVertical) {
|
|
19262
19524
|
if (timelineSort === "group" && timelineGroups.length > 0) {
|
|
19263
19525
|
const groupNames = timelineGroups.map((gr) => gr.name);
|
|
@@ -19269,7 +19531,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19269
19531
|
const scaleMargin = timelineScale ? 40 : 0;
|
|
19270
19532
|
const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
|
|
19271
19533
|
const margin = {
|
|
19272
|
-
top: 104 + markerMargin,
|
|
19534
|
+
top: 104 + markerMargin + tagLegendReserve,
|
|
19273
19535
|
right: 40 + scaleMargin,
|
|
19274
19536
|
bottom: 40,
|
|
19275
19537
|
left: 60 + scaleMargin
|
|
@@ -19345,6 +19607,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19345
19607
|
}).on("click", () => {
|
|
19346
19608
|
if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
|
|
19347
19609
|
});
|
|
19610
|
+
setTagAttrs(evG, ev);
|
|
19348
19611
|
if (ev.endDate) {
|
|
19349
19612
|
const y2 = yScale(parseTimelineDate(ev.endDate));
|
|
19350
19613
|
const rectH = Math.max(y2 - y, 4);
|
|
@@ -19371,7 +19634,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19371
19634
|
const scaleMargin = timelineScale ? 40 : 0;
|
|
19372
19635
|
const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
|
|
19373
19636
|
const margin = {
|
|
19374
|
-
top: 104 + markerMargin,
|
|
19637
|
+
top: 104 + markerMargin + tagLegendReserve,
|
|
19375
19638
|
right: 200,
|
|
19376
19639
|
bottom: 40,
|
|
19377
19640
|
left: 60 + scaleMargin
|
|
@@ -19451,6 +19714,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19451
19714
|
}).on("click", () => {
|
|
19452
19715
|
if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
|
|
19453
19716
|
});
|
|
19717
|
+
setTagAttrs(evG, ev);
|
|
19454
19718
|
if (ev.endDate) {
|
|
19455
19719
|
const y2 = yScale(parseTimelineDate(ev.endDate));
|
|
19456
19720
|
const rectH = Math.max(y2 - y, 4);
|
|
@@ -19503,7 +19767,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19503
19767
|
const dynamicLeftMargin = Math.max(120, maxGroupNameLen * 7 + 30);
|
|
19504
19768
|
const baseTopMargin = title ? 50 : 20;
|
|
19505
19769
|
const margin = {
|
|
19506
|
-
top: baseTopMargin + (timelineScale ? 40 : 0) + markerMargin,
|
|
19770
|
+
top: baseTopMargin + (timelineScale ? 40 : 0) + markerMargin + tagLegendReserve,
|
|
19507
19771
|
right: 40,
|
|
19508
19772
|
bottom: 40 + scaleMargin,
|
|
19509
19773
|
left: dynamicLeftMargin
|
|
@@ -19606,6 +19870,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19606
19870
|
}).on("click", () => {
|
|
19607
19871
|
if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
|
|
19608
19872
|
});
|
|
19873
|
+
setTagAttrs(evG, ev);
|
|
19609
19874
|
if (ev.endDate) {
|
|
19610
19875
|
const x2 = xScale(parseTimelineDate(ev.endDate));
|
|
19611
19876
|
const rectW = Math.max(x2 - x, 4);
|
|
@@ -19647,7 +19912,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19647
19912
|
const scaleMargin = timelineScale ? 24 : 0;
|
|
19648
19913
|
const markerMargin = timelineMarkers.length > 0 ? 30 : 0;
|
|
19649
19914
|
const margin = {
|
|
19650
|
-
top: 104 + (timelineScale ? 40 : 0) + markerMargin,
|
|
19915
|
+
top: 104 + (timelineScale ? 40 : 0) + markerMargin + tagLegendReserve,
|
|
19651
19916
|
right: 40,
|
|
19652
19917
|
bottom: 40 + scaleMargin,
|
|
19653
19918
|
left: 60
|
|
@@ -19743,6 +20008,7 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19743
20008
|
}).on("click", () => {
|
|
19744
20009
|
if (onClickItem && ev.lineNumber) onClickItem(ev.lineNumber);
|
|
19745
20010
|
});
|
|
20011
|
+
setTagAttrs(evG, ev);
|
|
19746
20012
|
if (ev.endDate) {
|
|
19747
20013
|
const x2 = xScale(parseTimelineDate(ev.endDate));
|
|
19748
20014
|
const rectW = Math.max(x2 - x, 4);
|
|
@@ -19778,6 +20044,124 @@ function renderTimeline(container, parsed, palette, isDark, onClickItem, exportD
|
|
|
19778
20044
|
}
|
|
19779
20045
|
});
|
|
19780
20046
|
}
|
|
20047
|
+
if (parsed.timelineTagGroups.length > 0) {
|
|
20048
|
+
const LG_HEIGHT = 28;
|
|
20049
|
+
const LG_PILL_PAD = 16;
|
|
20050
|
+
const LG_PILL_FONT_SIZE = 11;
|
|
20051
|
+
const LG_PILL_FONT_W = LG_PILL_FONT_SIZE * 0.6;
|
|
20052
|
+
const LG_CAPSULE_PAD = 4;
|
|
20053
|
+
const LG_DOT_R = 4;
|
|
20054
|
+
const LG_ENTRY_FONT_SIZE = 10;
|
|
20055
|
+
const LG_ENTRY_FONT_W = LG_ENTRY_FONT_SIZE * 0.6;
|
|
20056
|
+
const LG_ENTRY_DOT_GAP = 4;
|
|
20057
|
+
const LG_ENTRY_TRAIL = 8;
|
|
20058
|
+
const LG_GROUP_GAP = 12;
|
|
20059
|
+
const mainSvg = d3Selection12.select(container).select("svg");
|
|
20060
|
+
const mainG = mainSvg.select("g");
|
|
20061
|
+
if (!mainSvg.empty() && !mainG.empty()) {
|
|
20062
|
+
let drawLegend2 = function() {
|
|
20063
|
+
mainSvg.selectAll(".tl-tag-legend-group").remove();
|
|
20064
|
+
const totalW = legendGroups.reduce((s, lg) => {
|
|
20065
|
+
const isActive = currentActiveGroup != null && lg.group.name.toLowerCase() === currentActiveGroup.toLowerCase();
|
|
20066
|
+
return s + (isActive ? lg.expandedWidth : lg.minifiedWidth);
|
|
20067
|
+
}, 0) + (legendGroups.length - 1) * LG_GROUP_GAP;
|
|
20068
|
+
let cx = (width - totalW) / 2;
|
|
20069
|
+
for (const lg of legendGroups) {
|
|
20070
|
+
const isActive = currentActiveGroup != null && lg.group.name.toLowerCase() === currentActiveGroup.toLowerCase();
|
|
20071
|
+
const pillLabel = lg.group.name;
|
|
20072
|
+
const pillWidth = pillLabel.length * LG_PILL_FONT_W + LG_PILL_PAD;
|
|
20073
|
+
const gEl = mainSvg.append("g").attr("transform", `translate(${cx}, ${legendY})`).attr("class", "tl-tag-legend-group tl-tag-legend-entry").attr("data-legend-group", lg.group.name.toLowerCase()).attr("data-tag-group", lg.group.name.toLowerCase()).attr("data-legend-entry", "__group__").style("cursor", "pointer").on("click", () => {
|
|
20074
|
+
const groupKey = lg.group.name.toLowerCase();
|
|
20075
|
+
currentActiveGroup = currentActiveGroup === groupKey ? null : groupKey;
|
|
20076
|
+
drawLegend2();
|
|
20077
|
+
recolorEvents2();
|
|
20078
|
+
});
|
|
20079
|
+
if (isActive) {
|
|
20080
|
+
gEl.append("rect").attr("width", lg.expandedWidth).attr("height", LG_HEIGHT).attr("rx", LG_HEIGHT / 2).attr("fill", groupBg);
|
|
20081
|
+
}
|
|
20082
|
+
const pillXOff = isActive ? LG_CAPSULE_PAD : 0;
|
|
20083
|
+
const pillYOff = isActive ? LG_CAPSULE_PAD : 0;
|
|
20084
|
+
const pillH = LG_HEIGHT - (isActive ? LG_CAPSULE_PAD * 2 : 0);
|
|
20085
|
+
gEl.append("rect").attr("x", pillXOff).attr("y", pillYOff).attr("width", pillWidth).attr("height", pillH).attr("rx", pillH / 2).attr("fill", isActive ? palette.bg : groupBg);
|
|
20086
|
+
if (isActive) {
|
|
20087
|
+
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);
|
|
20088
|
+
}
|
|
20089
|
+
gEl.append("text").attr("x", pillXOff + pillWidth / 2).attr("y", LG_HEIGHT / 2 + LG_PILL_FONT_SIZE / 2 - 2).attr("font-size", LG_PILL_FONT_SIZE).attr("font-weight", "500").attr("font-family", FONT_FAMILY).attr("fill", isActive ? palette.text : palette.textMuted).attr("text-anchor", "middle").text(pillLabel);
|
|
20090
|
+
if (isActive) {
|
|
20091
|
+
let entryX = pillXOff + pillWidth + 4;
|
|
20092
|
+
for (const entry of lg.group.entries) {
|
|
20093
|
+
const tagKey = lg.group.name.toLowerCase();
|
|
20094
|
+
const tagVal = entry.value.toLowerCase();
|
|
20095
|
+
const entryG = gEl.append("g").attr("class", "tl-tag-legend-entry").attr("data-tag-group", tagKey).attr("data-legend-entry", tagVal).style("cursor", "pointer").on("mouseenter", (event) => {
|
|
20096
|
+
event.stopPropagation();
|
|
20097
|
+
fadeToTagValue(mainG, tagKey, tagVal);
|
|
20098
|
+
mainSvg.selectAll(".tl-tag-legend-entry").each(function() {
|
|
20099
|
+
const el = d3Selection12.select(this);
|
|
20100
|
+
const ev = el.attr("data-legend-entry");
|
|
20101
|
+
if (ev === "__group__") return;
|
|
20102
|
+
const eg = el.attr("data-tag-group");
|
|
20103
|
+
el.attr("opacity", eg === tagKey && ev === tagVal ? 1 : FADE_OPACITY);
|
|
20104
|
+
});
|
|
20105
|
+
}).on("mouseleave", (event) => {
|
|
20106
|
+
event.stopPropagation();
|
|
20107
|
+
fadeReset(mainG);
|
|
20108
|
+
mainSvg.selectAll(".tl-tag-legend-entry").attr("opacity", 1);
|
|
20109
|
+
}).on("click", (event) => {
|
|
20110
|
+
event.stopPropagation();
|
|
20111
|
+
});
|
|
20112
|
+
entryG.append("circle").attr("cx", entryX + LG_DOT_R).attr("cy", LG_HEIGHT / 2).attr("r", LG_DOT_R).attr("fill", entry.color);
|
|
20113
|
+
const textX = entryX + LG_DOT_R * 2 + LG_ENTRY_DOT_GAP;
|
|
20114
|
+
entryG.append("text").attr("x", textX).attr("y", LG_HEIGHT / 2 + LG_ENTRY_FONT_SIZE / 2 - 1).attr("font-size", LG_ENTRY_FONT_SIZE).attr("font-family", FONT_FAMILY).attr("fill", palette.textMuted).text(entry.value);
|
|
20115
|
+
entryX = textX + entry.value.length * LG_ENTRY_FONT_W + LG_ENTRY_TRAIL;
|
|
20116
|
+
}
|
|
20117
|
+
}
|
|
20118
|
+
cx += (isActive ? lg.expandedWidth : lg.minifiedWidth) + LG_GROUP_GAP;
|
|
20119
|
+
}
|
|
20120
|
+
}, recolorEvents2 = function() {
|
|
20121
|
+
mainG.selectAll(".tl-event").each(function() {
|
|
20122
|
+
const el = d3Selection12.select(this);
|
|
20123
|
+
const lineNum = el.attr("data-line-number");
|
|
20124
|
+
const ev = lineNum ? eventByLine.get(lineNum) : void 0;
|
|
20125
|
+
if (!ev) return;
|
|
20126
|
+
let color;
|
|
20127
|
+
if (currentActiveGroup) {
|
|
20128
|
+
const tagColor = resolveTagColor(
|
|
20129
|
+
ev.metadata,
|
|
20130
|
+
parsed.timelineTagGroups,
|
|
20131
|
+
currentActiveGroup
|
|
20132
|
+
);
|
|
20133
|
+
color = tagColor ?? (ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor);
|
|
20134
|
+
} else {
|
|
20135
|
+
color = ev.group && groupColorMap.has(ev.group) ? groupColorMap.get(ev.group) : textColor;
|
|
20136
|
+
}
|
|
20137
|
+
el.selectAll("rect").attr("fill", color);
|
|
20138
|
+
el.selectAll("circle:not(.tl-event-point-outline)").attr("fill", color);
|
|
20139
|
+
});
|
|
20140
|
+
};
|
|
20141
|
+
var drawLegend = drawLegend2, recolorEvents = recolorEvents2;
|
|
20142
|
+
const legendY = title ? 50 : 10;
|
|
20143
|
+
const groupBg = isDark ? mix(palette.surface, palette.bg, 50) : mix(palette.surface, palette.bg, 30);
|
|
20144
|
+
const legendGroups = parsed.timelineTagGroups.map((g) => {
|
|
20145
|
+
const pillW = g.name.length * LG_PILL_FONT_W + LG_PILL_PAD;
|
|
20146
|
+
let entryX = LG_CAPSULE_PAD + pillW + 4;
|
|
20147
|
+
for (const entry of g.entries) {
|
|
20148
|
+
const textX = entryX + LG_DOT_R * 2 + LG_ENTRY_DOT_GAP;
|
|
20149
|
+
entryX = textX + entry.value.length * LG_ENTRY_FONT_W + LG_ENTRY_TRAIL;
|
|
20150
|
+
}
|
|
20151
|
+
return {
|
|
20152
|
+
group: g,
|
|
20153
|
+
minifiedWidth: pillW,
|
|
20154
|
+
expandedWidth: entryX + LG_CAPSULE_PAD
|
|
20155
|
+
};
|
|
20156
|
+
});
|
|
20157
|
+
let currentActiveGroup = activeTagGroup ?? null;
|
|
20158
|
+
const eventByLine = /* @__PURE__ */ new Map();
|
|
20159
|
+
for (const ev of timelineEvents) {
|
|
20160
|
+
eventByLine.set(String(ev.lineNumber), ev);
|
|
20161
|
+
}
|
|
20162
|
+
drawLegend2();
|
|
20163
|
+
}
|
|
20164
|
+
}
|
|
19781
20165
|
}
|
|
19782
20166
|
function getRotateFn(mode) {
|
|
19783
20167
|
if (mode === "mixed") return () => Math.random() > 0.5 ? 0 : 90;
|
|
@@ -20763,8 +21147,10 @@ var init_d3 = __esm({
|
|
|
20763
21147
|
init_branding();
|
|
20764
21148
|
init_colors();
|
|
20765
21149
|
init_palettes();
|
|
21150
|
+
init_color_utils();
|
|
20766
21151
|
init_diagnostics();
|
|
20767
21152
|
init_parsing();
|
|
21153
|
+
init_tag_groups();
|
|
20768
21154
|
DEFAULT_CLOUD_OPTIONS = {
|
|
20769
21155
|
rotate: "none",
|
|
20770
21156
|
max: 0,
|
|
@@ -21623,6 +22009,9 @@ function encodeDiagramUrl(dsl, options) {
|
|
|
21623
22009
|
if (options?.viewState?.activeTagGroup) {
|
|
21624
22010
|
hash += `&tag=${encodeURIComponent(options.viewState.activeTagGroup)}`;
|
|
21625
22011
|
}
|
|
22012
|
+
if (options?.viewState?.collapsedGroups?.length) {
|
|
22013
|
+
hash += `&cg=${encodeURIComponent(options.viewState.collapsedGroups.join(","))}`;
|
|
22014
|
+
}
|
|
21626
22015
|
return { url: `${baseUrl}?${hash}#${hash}` };
|
|
21627
22016
|
}
|
|
21628
22017
|
function decodeDiagramUrl(hash) {
|
|
@@ -21643,6 +22032,9 @@ function decodeDiagramUrl(hash) {
|
|
|
21643
22032
|
if (key === "tag" && val) {
|
|
21644
22033
|
viewState.activeTagGroup = val;
|
|
21645
22034
|
}
|
|
22035
|
+
if (key === "cg" && val) {
|
|
22036
|
+
viewState.collapsedGroups = val.split(",").filter(Boolean);
|
|
22037
|
+
}
|
|
21646
22038
|
}
|
|
21647
22039
|
if (payload.startsWith("dgmo=")) {
|
|
21648
22040
|
payload = payload.slice(5);
|