@erd-studio/renderer 0.1.0 → 0.1.1

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.
@@ -4,7 +4,7 @@ import {
4
4
  NODE_WIDTH,
5
5
  resolveNodeDimensions,
6
6
  useColumnExpansion
7
- } from "./chunk-HOQPSLHQ.js";
7
+ } from "./chunk-DUQ2TTQH.js";
8
8
  import {
9
9
  CanvasStoreProvider,
10
10
  createCanvasStore,
@@ -15,12 +15,12 @@ import {
15
15
  // src/ErdCanvas.tsx
16
16
  import {
17
17
  forwardRef,
18
- useCallback as useCallback22,
19
- useEffect as useEffect14,
18
+ useCallback as useCallback24,
19
+ useEffect as useEffect16,
20
20
  useImperativeHandle,
21
21
  useMemo as useMemo7,
22
- useRef as useRef10,
23
- useState as useState18
22
+ useRef as useRef12,
23
+ useState as useState20
24
24
  } from "react";
25
25
  import {
26
26
  ReactFlow,
@@ -66,8 +66,32 @@ function useIsViewer() {
66
66
  // src/canvas/useCanvasGraph.ts
67
67
  import { useCallback as useCallback2, useEffect, useRef } from "react";
68
68
 
69
+ // src/lib/modelLabels.ts
70
+ function computeModelLabels(models) {
71
+ const baseOf = (m) => m.alias?.trim() || m.name;
72
+ const counts = /* @__PURE__ */ new Map();
73
+ for (const m of models) {
74
+ const key = baseOf(m).toLowerCase();
75
+ counts.set(key, (counts.get(key) ?? 0) + 1);
76
+ }
77
+ const labels = /* @__PURE__ */ new Map();
78
+ for (const m of models) {
79
+ const base = baseOf(m);
80
+ const clashes = (counts.get(base.toLowerCase()) ?? 0) > 1;
81
+ const label = clashes && m.schema ? `${m.schema}.${base}` : base;
82
+ if (label !== m.name) {
83
+ labels.set(m.name, label);
84
+ }
85
+ }
86
+ return labels;
87
+ }
88
+ function matchesModelSearch(data, query) {
89
+ return data.modelName.toLowerCase().includes(query) || data.label !== void 0 && data.label.toLowerCase().includes(query);
90
+ }
91
+
69
92
  // src/lib/graphTransformer.ts
70
93
  var DEFAULT_POSITION = { x: 0, y: 0 };
94
+ var hasMeta = (meta) => !!meta && Object.keys(meta).length > 0;
71
95
  function mapColumns(model) {
72
96
  const mapped = model.columns.map((col) => ({
73
97
  name: col.name,
@@ -77,7 +101,8 @@ function mapColumns(model) {
77
101
  isForeignKey: col.isForeignKey,
78
102
  isNaturalKey: col.isNaturalKey,
79
103
  ...col.scdType != null ? { scdType: col.scdType } : {},
80
- ...col.additiveType ? { additiveType: col.additiveType } : {}
104
+ ...col.additiveType ? { additiveType: col.additiveType } : {},
105
+ ...hasMeta(col.meta) ? { meta: col.meta } : {}
81
106
  }));
82
107
  return mapped;
83
108
  }
@@ -115,6 +140,7 @@ function transformDomain(domain, options) {
115
140
  data: { ...data, isExpanded: options?.isExpanded?.(id) ?? false },
116
141
  measured: void 0
117
142
  });
143
+ const labels = computeModelLabels(models);
118
144
  const nodes = models.map((model) => {
119
145
  const columns = mapColumns(model);
120
146
  const position = positionMap.get(model.name) ?? DEFAULT_POSITION;
@@ -125,6 +151,7 @@ function transformDomain(domain, options) {
125
151
  position,
126
152
  data: {
127
153
  modelName: model.name,
154
+ ...labels.has(model.name) ? { label: labels.get(model.name) } : {},
128
155
  stage,
129
156
  layer,
130
157
  layerConfig,
@@ -134,6 +161,7 @@ function transformDomain(domain, options) {
134
161
  ...model.rationale && (model.rationale.purpose || model.rationale.design || model.rationale.grainChoice || model.rationale.roleChoice || model.rationale.scdStrategy || model.rationale.measures) ? { hasRationale: true } : {},
135
162
  ...model.grain ? { grain: model.grain } : {},
136
163
  ...model.modelRole ? { modelRole: model.modelRole } : {},
164
+ ...hasMeta(model.meta) ? { meta: model.meta } : {},
137
165
  ...readOnly ? { readOnly: true } : {},
138
166
  // Strict `=== false`: logical models leave existsInProject undefined,
139
167
  // so `!model.existsInProject` would ghost the entire logical canvas.
@@ -142,6 +170,7 @@ function transformDomain(domain, options) {
142
170
  // spreads `...data` and never recomputes it, so memoised nodes are
143
171
  // untouched. Never derive it inside an overlay pass.
144
172
  ...model.provenance ? { provenance: model.provenance } : {},
173
+ ...model.loadError ? { loadError: model.loadError } : {},
145
174
  ...disc ? { discrepancy: disc } : {},
146
175
  ...disc && options?.discrepancyReport ? {
147
176
  discrepancySourceStage: options.discrepancyReport.sourceStage,
@@ -326,7 +355,7 @@ function applyNodeOverlays(nodes, edges, state) {
326
355
  return node;
327
356
  }
328
357
  const data = node.data;
329
- const searchDimmed = query ? !data.modelName.toLowerCase().includes(query) : false;
358
+ const searchDimmed = query ? !matchesModelSearch(data, query) : false;
330
359
  const selectionDimmed = hasSelection && !connected.has(node.id);
331
360
  const dimmed = searchDimmed || selectionDimmed;
332
361
  const expanded = isExpanded(node.id);
@@ -1015,6 +1044,14 @@ function DataTypeSelect({
1015
1044
  // src/components/Graph/ColumnTooltip.tsx
1016
1045
  import { useCallback as useCallback6 } from "react";
1017
1046
  import { createPortal as createPortal2 } from "react-dom";
1047
+
1048
+ // src/lib/metaFormat.ts
1049
+ import { formatMetaValue } from "@erd-studio/core";
1050
+ function metaRows(meta) {
1051
+ return Object.entries(meta ?? {}).map(([key, value]) => [key, formatMetaValue(value)]);
1052
+ }
1053
+
1054
+ // src/components/Graph/ColumnTooltip.tsx
1018
1055
  import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1019
1056
  var SCD_LABELS = {
1020
1057
  0: "Type 0 \u2014 Fixed (never changes)",
@@ -1029,7 +1066,7 @@ var ADDITIVE_LABELS = {
1029
1066
  var FLIP_THRESHOLD = 80;
1030
1067
  var TOOLTIP_GAP = 6;
1031
1068
  function hasTooltipContent(column) {
1032
- return !!(column.description || column.isPrimaryKey || column.isForeignKey || column.isNaturalKey || column.scdType != null || column.additiveType);
1069
+ return !!(column.description || column.isPrimaryKey || column.isForeignKey || column.isNaturalKey || column.scdType != null || column.additiveType || metaRows(column.meta).length > 0);
1033
1070
  }
1034
1071
  function ColumnTooltip({ column, anchorRef, visible }) {
1035
1072
  const keys = [];
@@ -1038,7 +1075,8 @@ function ColumnTooltip({ column, anchorRef, visible }) {
1038
1075
  if (column.isNaturalKey) keys.push("Natural Key");
1039
1076
  const hasExtras = keys.length > 0 || column.scdType != null || column.additiveType;
1040
1077
  const hasDescription = !!column.description;
1041
- const hasContent = hasDescription || hasExtras;
1078
+ const meta = metaRows(column.meta);
1079
+ const hasContent = hasDescription || hasExtras || meta.length > 0;
1042
1080
  const positionRef = useCallback6(
1043
1081
  (tooltip) => {
1044
1082
  if (!tooltip || !anchorRef.current) return;
@@ -1078,20 +1116,30 @@ function ColumnTooltip({ column, anchorRef, visible }) {
1078
1116
  /* @__PURE__ */ jsx5("span", { className: "column-tooltip__label", children: "Measure" }),
1079
1117
  /* @__PURE__ */ jsx5("span", { className: "column-tooltip__value", children: ADDITIVE_LABELS[column.additiveType] ?? column.additiveType })
1080
1118
  ] })
1081
- ] })
1119
+ ] }),
1120
+ meta.length > 0 && /* @__PURE__ */ jsx5(MetaSection, { rows: meta })
1082
1121
  ] }),
1083
1122
  document.body
1084
1123
  );
1085
1124
  }
1125
+ function MetaSection({ rows }) {
1126
+ return /* @__PURE__ */ jsxs3("div", { className: "column-tooltip__meta", children: [
1127
+ /* @__PURE__ */ jsx5("div", { className: "column-tooltip__label", children: "Metadata" }),
1128
+ rows.map(([key, value]) => /* @__PURE__ */ jsxs3("div", { className: "column-tooltip__row", children: [
1129
+ /* @__PURE__ */ jsx5("span", { className: "column-tooltip__meta-key", children: key }),
1130
+ /* @__PURE__ */ jsx5("span", { className: "column-tooltip__value", children: value })
1131
+ ] }, key))
1132
+ ] });
1133
+ }
1086
1134
 
1087
1135
  // src/components/Graph/HoverTip.tsx
1088
1136
  import { useCallback as useCallback7, useRef as useRef5, useState as useState4 } from "react";
1089
1137
  import { createPortal as createPortal3 } from "react-dom";
1090
- import { jsx as jsx6 } from "react/jsx-runtime";
1138
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1091
1139
  var HOVER_DELAY_MS = 450;
1092
1140
  var FLIP_THRESHOLD2 = 60;
1093
1141
  var TIP_GAP = 6;
1094
- function HoverTip({ text, anchorRef, visible }) {
1142
+ function HoverTip({ text, rows, anchorRef, visible }) {
1095
1143
  const positionRef = useCallback7(
1096
1144
  (tip) => {
1097
1145
  if (!tip || !anchorRef.current) {
@@ -1116,11 +1164,17 @@ function HoverTip({ text, anchorRef, visible }) {
1116
1164
  return null;
1117
1165
  }
1118
1166
  return createPortal3(
1119
- /* @__PURE__ */ jsx6("div", { ref: positionRef, className: "hover-tip", role: "tooltip", children: text }),
1167
+ /* @__PURE__ */ jsxs4("div", { ref: positionRef, className: "hover-tip", role: "tooltip", children: [
1168
+ text,
1169
+ rows && rows.length > 0 && /* @__PURE__ */ jsx6("div", { className: "hover-tip__rows", children: rows.map(([label, value]) => /* @__PURE__ */ jsxs4("div", { className: "hover-tip__row", children: [
1170
+ /* @__PURE__ */ jsx6("span", { className: "hover-tip__label", children: label }),
1171
+ /* @__PURE__ */ jsx6("span", { className: "hover-tip__value", children: value })
1172
+ ] }, label)) })
1173
+ ] }),
1120
1174
  document.body
1121
1175
  );
1122
1176
  }
1123
- function useHoverTip(text) {
1177
+ function useHoverTip(text, rows) {
1124
1178
  const ref = useRef5(null);
1125
1179
  const timer = useRef5(null);
1126
1180
  const [visible, setVisible] = useState4(false);
@@ -1137,9 +1191,10 @@ function useHoverTip(text) {
1137
1191
  }
1138
1192
  setVisible(false);
1139
1193
  }, []);
1194
+ const label = rows && rows.length > 0 ? `${text}; ${rows.map(([k, v]) => `${k}: ${v}`).join("; ")}` : text;
1140
1195
  return {
1141
- anchorProps: { ref, onMouseEnter, onMouseLeave, "aria-label": text },
1142
- tip: /* @__PURE__ */ jsx6(HoverTip, { text, anchorRef: ref, visible })
1196
+ anchorProps: { ref, onMouseEnter, onMouseLeave, "aria-label": label },
1197
+ tip: /* @__PURE__ */ jsx6(HoverTip, { text, rows, anchorRef: ref, visible })
1143
1198
  };
1144
1199
  }
1145
1200
 
@@ -1202,7 +1257,7 @@ function edgeHoverText(edge) {
1202
1257
  }
1203
1258
 
1204
1259
  // src/components/Graph/ModelNode.tsx
1205
- import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
1260
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1206
1261
  var LAYER_BADGE_FALLBACK = {
1207
1262
  bronze: "BRZ",
1208
1263
  silver: "SLV",
@@ -1292,15 +1347,15 @@ function ColumnRow({ column, modelName, readOnly, existingColumnNames, discrepan
1292
1347
  cancelEdit();
1293
1348
  return;
1294
1349
  }
1295
- if (!/^[a-z0-9_]+$/.test(trimmed)) {
1350
+ if (!/^[A-Za-z0-9_]+$/.test(trimmed)) {
1296
1351
  if (revertOnError) {
1297
1352
  cancelEdit();
1298
1353
  return;
1299
1354
  }
1300
- setEditError("Use lowercase letters, numbers, underscores");
1355
+ setEditError("Use only letters, numbers, underscores");
1301
1356
  return;
1302
1357
  }
1303
- if (trimmed !== column.name && existingColumnNames?.includes(trimmed)) {
1358
+ if (trimmed !== column.name && existingColumnNames?.some((n) => n !== column.name && n.toLowerCase() === trimmed.toLowerCase())) {
1304
1359
  if (revertOnError) {
1305
1360
  cancelEdit();
1306
1361
  return;
@@ -1466,7 +1521,7 @@ function ColumnRow({ column, modelName, readOnly, existingColumnNames, discrepan
1466
1521
  const reorderDragClass = isReorderDragging ? "model-node__column--reorder-dragging" : "";
1467
1522
  const reorderTargetClass = isReorderTarget ? "model-node__column--reorder-target" : "";
1468
1523
  const discrepancyClass = discrepancy?.status === "extra" ? "model-node__column--disc-extra" : discrepancy?.status === "type-mismatch" ? "model-node__column--disc-mismatch" : "";
1469
- return /* @__PURE__ */ jsxs4(
1524
+ return /* @__PURE__ */ jsxs5(
1470
1525
  "div",
1471
1526
  {
1472
1527
  ref: elementRef,
@@ -1488,7 +1543,7 @@ function ColumnRow({ column, modelName, readOnly, existingColumnNames, discrepan
1488
1543
  children: "\u283F"
1489
1544
  }
1490
1545
  ),
1491
- /* @__PURE__ */ jsxs4("span", { className: "model-node__col-indicators", children: [
1546
+ /* @__PURE__ */ jsxs5("span", { className: "model-node__col-indicators", children: [
1492
1547
  column.isPrimaryKey && /* @__PURE__ */ jsx7(KeyBadge, { type: "PK", active: true, mode: "readonly" }),
1493
1548
  column.isForeignKey && /* @__PURE__ */ jsx7(KeyBadge, { type: "FK", active: true, mode: "readonly" }),
1494
1549
  column.isNaturalKey && /* @__PURE__ */ jsx7(KeyBadge, { type: "NK", active: true, mode: "readonly" })
@@ -1552,17 +1607,17 @@ function ColumnRow({ column, modelName, readOnly, existingColumnNames, discrepan
1552
1607
  className: "nodrag",
1553
1608
  autoOpen: true
1554
1609
  }
1555
- ) : discrepancy?.status === "type-mismatch" ? /* @__PURE__ */ jsxs4("span", { className: "model-node__col-type model-node__col-type--mismatch", title: `${discrepancySourceStage ?? "current"}: ${discrepancy.sourceDataType}, ${discrepancyTargetStage ?? "target"}: ${discrepancy.targetDataType}`, children: [
1556
- /* @__PURE__ */ jsxs4("span", { className: "model-node__col-type-line", style: { color: STAGE_HEX[discrepancySourceStage ?? ""] ?? "inherit" }, children: [
1557
- /* @__PURE__ */ jsxs4("span", { className: "model-node__col-type-stage", children: [
1610
+ ) : discrepancy?.status === "type-mismatch" ? /* @__PURE__ */ jsxs5("span", { className: "model-node__col-type model-node__col-type--mismatch", title: `${discrepancySourceStage ?? "current"}: ${discrepancy.sourceDataType}, ${discrepancyTargetStage ?? "target"}: ${discrepancy.targetDataType}`, children: [
1611
+ /* @__PURE__ */ jsxs5("span", { className: "model-node__col-type-line", style: { color: STAGE_HEX[discrepancySourceStage ?? ""] ?? "inherit" }, children: [
1612
+ /* @__PURE__ */ jsxs5("span", { className: "model-node__col-type-stage", children: [
1558
1613
  discrepancySourceStage ?? "current",
1559
1614
  ":"
1560
1615
  ] }),
1561
1616
  " ",
1562
1617
  discrepancy.sourceDataType
1563
1618
  ] }),
1564
- /* @__PURE__ */ jsxs4("span", { className: "model-node__col-type-line", style: { color: STAGE_HEX[discrepancyTargetStage ?? ""] ?? "inherit" }, children: [
1565
- /* @__PURE__ */ jsxs4("span", { className: "model-node__col-type-stage", children: [
1619
+ /* @__PURE__ */ jsxs5("span", { className: "model-node__col-type-line", style: { color: STAGE_HEX[discrepancyTargetStage ?? ""] ?? "inherit" }, children: [
1620
+ /* @__PURE__ */ jsxs5("span", { className: "model-node__col-type-stage", children: [
1566
1621
  discrepancyTargetStage ?? "target",
1567
1622
  ":"
1568
1623
  ] }),
@@ -1613,8 +1668,14 @@ function ColumnRow({ column, modelName, readOnly, existingColumnNames, discrepan
1613
1668
  }
1614
1669
  );
1615
1670
  }
1671
+ function describeLoadError(error) {
1672
+ if (error.kind === "read") {
1673
+ return "ERD Studio can't read this file.";
1674
+ }
1675
+ return error.line !== void 0 ? `YAML error on line ${error.line} \u2014 ERD Studio can't read this file.` : "YAML error \u2014 ERD Studio can't read this file.";
1676
+ }
1616
1677
  function ModelNodeComponent({ data, selected }) {
1617
- const { modelName, stage, layer, layerConfig, schema, columns, grain, dimmed, readOnly, isGhost, ghostReason, provenance, isStub, isExpanded = false, onToggleExpansion, discrepancy, discrepancySourceStage, discrepancyTargetStage } = data;
1678
+ const { modelName, label, stage, layer, layerConfig, schema, columns, grain, meta, dimmed, readOnly, isGhost, ghostReason, provenance, loadError, isStub, isExpanded = false, onToggleExpansion, discrepancy, discrepancySourceStage, discrepancyTargetStage } = data;
1618
1679
  const openNodeContextMenu = useEditorStore((s) => s.openNodeContextMenu);
1619
1680
  const send = useSend();
1620
1681
  const viewer = useIsViewer();
@@ -1666,8 +1727,11 @@ function ModelNodeComponent({ data, selected }) {
1666
1727
  }, [isExpanded, columnDiscrepancyMap, discrepancy]);
1667
1728
  const isDiscExtra = discrepancy?.status === "extra";
1668
1729
  const stageClass = isGhost ? "ghost" : stage;
1730
+ const title = label ? `${label} (model ${modelName})` : modelName;
1731
+ const modelMeta = useMemo2(() => metaRows(meta), [meta]);
1669
1732
  const nameTip = useHoverTip(
1670
- ghostReason ? `${modelName} \u2014 ${GHOST_REASON_TITLE[ghostReason]}` : isDiscExtra ? `${modelName} \u2014 only in ${discrepancySourceStage ?? "this stage"}, not in ${discrepancyTargetStage ?? "the stage being compared"}` : modelName
1733
+ ghostReason ? `${title} \u2014 ${GHOST_REASON_TITLE[ghostReason]}` : isDiscExtra ? `${title} \u2014 only in ${discrepancySourceStage ?? "this stage"}, not in ${discrepancyTargetStage ?? "the stage being compared"}` : title,
1734
+ modelMeta
1671
1735
  );
1672
1736
  const sourceTip = useHoverTip(
1673
1737
  provenance ? sourceTitle(provenance, columns) : ""
@@ -1675,7 +1739,7 @@ function ModelNodeComponent({ data, selected }) {
1675
1739
  const badgeTip = useHoverTip(
1676
1740
  schema ? `Database schema: ${schema}` : `Layer: ${layerConfig?.label ?? layer} \u2014 no dbt schema resolved (run dbt compile or dbt docs generate)`
1677
1741
  );
1678
- return /* @__PURE__ */ jsxs4(
1742
+ return /* @__PURE__ */ jsxs5(
1679
1743
  "div",
1680
1744
  {
1681
1745
  className: `model-node model-node--${stageClass}${ghostReason ? ` model-node--ghost-${ghostReason}` : ""}${dimmed ? " model-node--dimmed" : ""}${readOnly ? " model-node--readonly" : ""}${isDiscExtra ? " model-node--disc-extra" : ""}${selected ? " model-node--selected" : ""}`,
@@ -1690,8 +1754,11 @@ function ModelNodeComponent({ data, selected }) {
1690
1754
  /* @__PURE__ */ jsx7(Handle, { type: "target", position: Position.Bottom, id: "node-bottom-tgt", style: NODE_HANDLE_STYLE }),
1691
1755
  /* @__PURE__ */ jsx7(Handle, { type: "source", position: Position.Left, id: "node-left-src", style: NODE_HANDLE_STYLE }),
1692
1756
  /* @__PURE__ */ jsx7(Handle, { type: "target", position: Position.Left, id: "node-left-tgt", style: NODE_HANDLE_STYLE }),
1693
- /* @__PURE__ */ jsxs4("div", { className: "model-node__header", children: [
1694
- /* @__PURE__ */ jsx7("span", { className: "model-node__name", ...nameTip.anchorProps, children: modelName }),
1757
+ /* @__PURE__ */ jsxs5("div", { className: "model-node__header", children: [
1758
+ /* @__PURE__ */ jsxs5("span", { className: "model-node__name", ...nameTip.anchorProps, children: [
1759
+ label ?? modelName,
1760
+ label && /* @__PURE__ */ jsx7("span", { className: "model-node__model-id", children: modelName })
1761
+ ] }),
1695
1762
  nameTip.tip,
1696
1763
  provenance && /* @__PURE__ */ jsx7(
1697
1764
  "span",
@@ -1717,7 +1784,7 @@ function ModelNodeComponent({ data, selected }) {
1717
1784
  badgeTip.tip
1718
1785
  ] }),
1719
1786
  grain && /* @__PURE__ */ jsx7("div", { className: "model-node__grain", title: grain, children: grain }),
1720
- /* @__PURE__ */ jsxs4("div", { className: "model-node__columns", children: [
1787
+ /* @__PURE__ */ jsxs5("div", { className: "model-node__columns", children: [
1721
1788
  displayColumns.map((col, idx) => /* @__PURE__ */ jsx7(
1722
1789
  ColumnRow,
1723
1790
  {
@@ -1734,7 +1801,7 @@ function ModelNodeComponent({ data, selected }) {
1734
1801
  },
1735
1802
  col.name
1736
1803
  )),
1737
- hiddenCount > 0 && /* @__PURE__ */ jsxs4(
1804
+ hiddenCount > 0 && /* @__PURE__ */ jsxs5(
1738
1805
  "button",
1739
1806
  {
1740
1807
  className: "model-node__expand-button",
@@ -1756,19 +1823,19 @@ function ModelNodeComponent({ data, selected }) {
1756
1823
  children: "Show less"
1757
1824
  }
1758
1825
  ),
1759
- missingColumns.length > 0 && /* @__PURE__ */ jsxs4(Fragment2, { children: [
1826
+ missingColumns.length > 0 && /* @__PURE__ */ jsxs5(Fragment2, { children: [
1760
1827
  /* @__PURE__ */ jsx7(
1761
1828
  "div",
1762
1829
  {
1763
1830
  className: "model-node__separator model-node__separator--disc",
1764
1831
  title: `Below this line: columns ${discrepancyTargetStage ?? "the compared stage"} has and ${discrepancySourceStage ?? "this stage"} does not`,
1765
- children: /* @__PURE__ */ jsxs4("span", { className: "model-node__separator-label model-node__separator-label--missing", children: [
1832
+ children: /* @__PURE__ */ jsxs5("span", { className: "model-node__separator-label model-node__separator-label--missing", children: [
1766
1833
  "only in ",
1767
1834
  discrepancyTargetStage ?? "comparison"
1768
1835
  ] })
1769
1836
  }
1770
1837
  ),
1771
- missingColumns.map((cd) => /* @__PURE__ */ jsxs4(
1838
+ missingColumns.map((cd) => /* @__PURE__ */ jsxs5(
1772
1839
  "div",
1773
1840
  {
1774
1841
  className: "model-node__column model-node__column--disc-missing nodrag",
@@ -1776,7 +1843,7 @@ function ModelNodeComponent({ data, selected }) {
1776
1843
  children: [
1777
1844
  /* @__PURE__ */ jsx7("span", { className: "model-node__col-name", children: cd.name }),
1778
1845
  /* @__PURE__ */ jsx7("span", { className: "model-node__col-type", style: { color: cd.targetDataType ? getDataTypeColor(cd.targetDataType) : void 0 }, children: cd.targetDataType ?? "" }),
1779
- /* @__PURE__ */ jsxs4("span", { className: "model-node__col-disc-badge model-node__col-disc-badge--missing", children: [
1846
+ /* @__PURE__ */ jsxs5("span", { className: "model-node__col-disc-badge model-node__col-disc-badge--missing", children: [
1780
1847
  discrepancyTargetStage ?? "target",
1781
1848
  " only"
1782
1849
  ] })
@@ -1785,13 +1852,27 @@ function ModelNodeComponent({ data, selected }) {
1785
1852
  `ghost-${cd.name}`
1786
1853
  ))
1787
1854
  ] }),
1788
- columns.length === 0 && !missingColumns.length && /* @__PURE__ */ jsx7("div", { className: "model-node__empty", children: "No columns" })
1855
+ columns.length === 0 && !missingColumns.length && (loadError ? /* @__PURE__ */ jsxs5("div", { className: "model-node__load-error", role: "alert", children: [
1856
+ /* @__PURE__ */ jsx7("span", { className: "model-node__load-error-text", children: describeLoadError(loadError) }),
1857
+ !viewer && /* @__PURE__ */ jsx7(
1858
+ "button",
1859
+ {
1860
+ type: "button",
1861
+ className: "model-node__load-error-open nodrag",
1862
+ onClick: (e) => {
1863
+ e.stopPropagation();
1864
+ send({ type: "openModelFile", payload: { modelName } });
1865
+ },
1866
+ children: "Open file"
1867
+ }
1868
+ )
1869
+ ] }) : /* @__PURE__ */ jsx7("div", { className: "model-node__empty", children: "No columns" }))
1789
1870
  ] }),
1790
- /* @__PURE__ */ jsxs4("div", { className: "model-node__footer", children: [
1871
+ /* @__PURE__ */ jsxs5("div", { className: "model-node__footer", children: [
1791
1872
  isStub ? `${displayColumns.length} key col${displayColumns.length !== 1 ? "s" : ""} of ${columns.length}` : `${columns.length} ${columns.length === 1 ? "column" : "columns"}`,
1792
1873
  discrepancy && discrepancy.columns.length > 0 && (() => {
1793
1874
  const issues = discrepancy.columns.filter((c) => c.status !== "matched").length;
1794
- return issues > 0 ? /* @__PURE__ */ jsxs4("span", { className: "model-node__footer-disc", title: `${issues} column discrepanc${issues === 1 ? "y" : "ies"}`, children: [
1875
+ return issues > 0 ? /* @__PURE__ */ jsxs5("span", { className: "model-node__footer-disc", title: `${issues} column discrepanc${issues === 1 ? "y" : "ies"}`, children: [
1795
1876
  " ",
1796
1877
  "\xB7 ",
1797
1878
  issues,
@@ -1932,7 +2013,7 @@ function buildPositionsKey(nodeLookup, nodeIds) {
1932
2013
  }
1933
2014
 
1934
2015
  // src/components/Graph/FkEdge.tsx
1935
- import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
2016
+ import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1936
2017
  var PATH_GAP = 20;
1937
2018
  var LABEL_OFFSET = 8;
1938
2019
  var SELF_LOOP_RADIUS = 55;
@@ -2089,7 +2170,7 @@ function FkEdgeComponent({
2089
2170
  const tgtLabel = offsetPoint(adjustedTargetX, adjustedTargetY, targetPosition, LABEL_OFFSET);
2090
2171
  const midX = isSelfLoop ? (src.x + tgt.x) / 2 + SELF_LOOP_RADIUS * 0.75 : (adjustedSourceX + adjustedTargetX) / 2;
2091
2172
  const midY = isSelfLoop ? (src.y + tgt.y) / 2 - SELF_LOOP_RADIUS * 0.75 : (adjustedSourceY + adjustedTargetY) / 2;
2092
- return /* @__PURE__ */ jsxs5(Fragment3, { children: [
2173
+ return /* @__PURE__ */ jsxs6(Fragment3, { children: [
2093
2174
  /* @__PURE__ */ jsx8(
2094
2175
  "path",
2095
2176
  {
@@ -2109,7 +2190,7 @@ function FkEdgeComponent({
2109
2190
  children: /* @__PURE__ */ jsx8("title", { children: edgeTitle })
2110
2191
  }
2111
2192
  ),
2112
- /* @__PURE__ */ jsxs5(EdgeLabelRenderer, { children: [
2193
+ /* @__PURE__ */ jsxs6(EdgeLabelRenderer, { children: [
2113
2194
  /* @__PURE__ */ jsx8(
2114
2195
  "span",
2115
2196
  {
@@ -2187,7 +2268,7 @@ var ANNOTATION_COLORS = [
2187
2268
  ];
2188
2269
 
2189
2270
  // src/components/Graph/AnnotationNode.tsx
2190
- import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
2271
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
2191
2272
  var HANDLE_STYLE = {
2192
2273
  width: 1,
2193
2274
  height: 1,
@@ -2359,7 +2440,7 @@ function AnnotationNodeInner({ data }) {
2359
2440
  if (data.height) style.height = data.height;
2360
2441
  }
2361
2442
  const modelNames = domain?.models.map((m) => m.name) ?? [];
2362
- return /* @__PURE__ */ jsxs6(
2443
+ return /* @__PURE__ */ jsxs7(
2363
2444
  "div",
2364
2445
  {
2365
2446
  ref: containerRef,
@@ -2367,7 +2448,7 @@ function AnnotationNodeInner({ data }) {
2367
2448
  style,
2368
2449
  onDoubleClick: viewer ? void 0 : handleDoubleClick,
2369
2450
  children: [
2370
- !data.readOnly && /* @__PURE__ */ jsxs6("div", { className: "annotation-node__toolbar", children: [
2451
+ !data.readOnly && /* @__PURE__ */ jsxs7("div", { className: "annotation-node__toolbar", children: [
2371
2452
  /* @__PURE__ */ jsx9(
2372
2453
  "div",
2373
2454
  {
@@ -2390,7 +2471,7 @@ function AnnotationNodeInner({ data }) {
2390
2471
  children: "\u22EF"
2391
2472
  }
2392
2473
  ),
2393
- toolbarOpen && /* @__PURE__ */ jsxs6("div", { ref: toolbarPanelRef, className: "annotation-node__toolbar-panel nodrag nowheel", onClick: (e) => e.stopPropagation(), children: [
2474
+ toolbarOpen && /* @__PURE__ */ jsxs7("div", { ref: toolbarPanelRef, className: "annotation-node__toolbar-panel nodrag nowheel", onClick: (e) => e.stopPropagation(), children: [
2394
2475
  /* @__PURE__ */ jsx9("div", { className: "annotation-node__color-row", children: ANNOTATION_COLORS.map((opt) => /* @__PURE__ */ jsx9(
2395
2476
  "button",
2396
2477
  {
@@ -2401,7 +2482,7 @@ function AnnotationNodeInner({ data }) {
2401
2482
  },
2402
2483
  opt.value
2403
2484
  )) }),
2404
- /* @__PURE__ */ jsx9("div", { className: "annotation-node__link-row", children: /* @__PURE__ */ jsxs6(
2485
+ /* @__PURE__ */ jsx9("div", { className: "annotation-node__link-row", children: /* @__PURE__ */ jsxs7(
2405
2486
  "select",
2406
2487
  {
2407
2488
  className: "annotation-node__link-select nodrag",
@@ -2428,7 +2509,7 @@ function AnnotationNodeInner({ data }) {
2428
2509
  placeholder: "Type a build note..."
2429
2510
  }
2430
2511
  ) : /* @__PURE__ */ jsx9("div", { className: "annotation-node__text", children: data.text || /* @__PURE__ */ jsx9("span", { className: "annotation-node__placeholder", children: "Double-click to edit..." }) }),
2431
- data.linkedModel && /* @__PURE__ */ jsxs6("div", { className: "annotation-node__link-badge", title: `Linked to ${data.linkedModel}`, children: [
2512
+ data.linkedModel && /* @__PURE__ */ jsxs7("div", { className: "annotation-node__link-badge", title: `Linked to ${data.linkedModel}`, children: [
2432
2513
  "\u{1F517} ",
2433
2514
  data.linkedModel
2434
2515
  ] }),
@@ -2542,7 +2623,7 @@ function repickHandleSides(nodes, edges, movedIds) {
2542
2623
  }
2543
2624
 
2544
2625
  // src/components/DetailPanel/DetailPanel.tsx
2545
- import { useCallback as useCallback20, useEffect as useEffect13, useMemo as useMemo6, useState as useState17 } from "react";
2626
+ import { useCallback as useCallback22, useEffect as useEffect15, useMemo as useMemo6, useState as useState19 } from "react";
2546
2627
  import { Panel } from "@xyflow/react";
2547
2628
 
2548
2629
  // src/components/DetailPanel/ModelRationale.tsx
@@ -2550,7 +2631,7 @@ import { useMemo as useMemo4, useState as useState9 } from "react";
2550
2631
 
2551
2632
  // src/components/DetailPanel/RationaleField.tsx
2552
2633
  import { useCallback as useCallback11, useEffect as useEffect7, useState as useState8 } from "react";
2553
- import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
2634
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
2554
2635
  function RationaleField({ modelName, rationale, fieldKey, label, placeholder, autoEdit }) {
2555
2636
  const host = useCanvasHost();
2556
2637
  const viewer = useIsViewer();
@@ -2592,13 +2673,13 @@ function RationaleField({ modelName, rationale, fieldKey, label, placeholder, au
2592
2673
  );
2593
2674
  if (viewer) {
2594
2675
  if (!hasContent) return null;
2595
- return /* @__PURE__ */ jsxs7("div", { className: "detail-panel__rationale-section", children: [
2676
+ return /* @__PURE__ */ jsxs8("div", { className: "detail-panel__rationale-section", children: [
2596
2677
  /* @__PURE__ */ jsx11("div", { className: "detail-panel__rationale-header", children: /* @__PURE__ */ jsx11("h4", { className: "detail-panel__section-title", style: { margin: 0 }, children: label }) }),
2597
2678
  /* @__PURE__ */ jsx11("div", { className: "detail-panel__rationale-field", children: /* @__PURE__ */ jsx11("p", { className: "detail-panel__rationale-text", children: rationale?.[fieldKey] }) })
2598
2679
  ] });
2599
2680
  }
2600
2681
  if (!hasContent && !editing) {
2601
- return /* @__PURE__ */ jsx11("div", { className: "detail-panel__rationale-section", children: /* @__PURE__ */ jsxs7(
2682
+ return /* @__PURE__ */ jsx11("div", { className: "detail-panel__rationale-section", children: /* @__PURE__ */ jsxs8(
2602
2683
  "button",
2603
2684
  {
2604
2685
  className: "detail-panel__rationale-add-btn",
@@ -2612,7 +2693,7 @@ function RationaleField({ modelName, rationale, fieldKey, label, placeholder, au
2612
2693
  ) });
2613
2694
  }
2614
2695
  if (editing) {
2615
- return /* @__PURE__ */ jsxs7("div", { className: "detail-panel__rationale-section", onKeyDown: handleKeyDown, children: [
2696
+ return /* @__PURE__ */ jsxs8("div", { className: "detail-panel__rationale-section", onKeyDown: handleKeyDown, children: [
2616
2697
  /* @__PURE__ */ jsx11("div", { className: "detail-panel__rationale-header", children: /* @__PURE__ */ jsx11("h4", { className: "detail-panel__section-title", style: { margin: 0 }, children: label }) }),
2617
2698
  /* @__PURE__ */ jsx11(
2618
2699
  "textarea",
@@ -2625,14 +2706,14 @@ function RationaleField({ modelName, rationale, fieldKey, label, placeholder, au
2625
2706
  autoFocus: true
2626
2707
  }
2627
2708
  ),
2628
- /* @__PURE__ */ jsxs7("div", { className: "detail-panel__rationale-actions", children: [
2709
+ /* @__PURE__ */ jsxs8("div", { className: "detail-panel__rationale-actions", children: [
2629
2710
  /* @__PURE__ */ jsx11("button", { className: "detail-panel__button", onClick: handleSave, children: "Save" }),
2630
2711
  /* @__PURE__ */ jsx11("button", { className: "detail-panel__button", onClick: handleCancel, children: "Cancel" })
2631
2712
  ] })
2632
2713
  ] });
2633
2714
  }
2634
- return /* @__PURE__ */ jsxs7("div", { className: "detail-panel__rationale-section", children: [
2635
- /* @__PURE__ */ jsxs7("div", { className: "detail-panel__rationale-header", children: [
2715
+ return /* @__PURE__ */ jsxs8("div", { className: "detail-panel__rationale-section", children: [
2716
+ /* @__PURE__ */ jsxs8("div", { className: "detail-panel__rationale-header", children: [
2636
2717
  /* @__PURE__ */ jsx11("h4", { className: "detail-panel__section-title", style: { margin: 0 }, children: label }),
2637
2718
  /* @__PURE__ */ jsx11(
2638
2719
  "button",
@@ -2657,7 +2738,7 @@ function RationaleField({ modelName, rationale, fieldKey, label, placeholder, au
2657
2738
  }
2658
2739
 
2659
2740
  // src/components/DetailPanel/ModelRationale.tsx
2660
- import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
2741
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
2661
2742
  function hasRationaleContent(rationale) {
2662
2743
  if (!rationale) return false;
2663
2744
  return [
@@ -2703,8 +2784,8 @@ function ModelRationale({ modelName, rationale, modelRole, grain }) {
2703
2784
  }
2704
2785
  ) });
2705
2786
  }
2706
- return /* @__PURE__ */ jsxs8("div", { className: "detail-panel__rationale-section", children: [
2707
- /* @__PURE__ */ jsxs8(
2787
+ return /* @__PURE__ */ jsxs9("div", { className: "detail-panel__rationale-section", children: [
2788
+ /* @__PURE__ */ jsxs9(
2708
2789
  "button",
2709
2790
  {
2710
2791
  className: "detail-panel__rationale-toggle",
@@ -2716,7 +2797,7 @@ function ModelRationale({ modelName, rationale, modelRole, grain }) {
2716
2797
  children: [
2717
2798
  /* @__PURE__ */ jsx12("span", { className: `detail-panel__rationale-chevron${open ? " detail-panel__rationale-chevron--open" : ""}`, children: "\u25B8" }),
2718
2799
  "Design Rationale",
2719
- filledCount > 0 && /* @__PURE__ */ jsxs8("span", { className: "detail-panel__rationale-count", children: [
2800
+ filledCount > 0 && /* @__PURE__ */ jsxs9("span", { className: "detail-panel__rationale-count", children: [
2720
2801
  "(",
2721
2802
  filledCount,
2722
2803
  ")"
@@ -2724,7 +2805,7 @@ function ModelRationale({ modelName, rationale, modelRole, grain }) {
2724
2805
  ]
2725
2806
  }
2726
2807
  ),
2727
- open && /* @__PURE__ */ jsxs8("div", { className: "detail-panel__rationale-body", children: [
2808
+ open && /* @__PURE__ */ jsxs9("div", { className: "detail-panel__rationale-body", children: [
2728
2809
  /* @__PURE__ */ jsx12(
2729
2810
  RationaleField,
2730
2811
  {
@@ -2792,7 +2873,7 @@ function ModelRationale({ modelName, rationale, modelRole, grain }) {
2792
2873
 
2793
2874
  // src/components/DetailPanel/DescriptionEditor.tsx
2794
2875
  import { useCallback as useCallback12, useEffect as useEffect8, useState as useState10 } from "react";
2795
- import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
2876
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
2796
2877
  function DescriptionEditor({ modelName, description }) {
2797
2878
  const host = useCanvasHost();
2798
2879
  const [editing, setEditing] = useState10(false);
@@ -2840,7 +2921,7 @@ function DescriptionEditor({ modelName, description }) {
2840
2921
  ) });
2841
2922
  }
2842
2923
  if (editing) {
2843
- return /* @__PURE__ */ jsxs9("div", { className: "detail-panel__description-section", children: [
2924
+ return /* @__PURE__ */ jsxs10("div", { className: "detail-panel__description-section", children: [
2844
2925
  /* @__PURE__ */ jsx13("div", { className: "detail-panel__rationale-header", children: /* @__PURE__ */ jsx13("h4", { className: "detail-panel__section-title", style: { margin: 0 }, children: "Description" }) }),
2845
2926
  /* @__PURE__ */ jsx13(
2846
2927
  "textarea",
@@ -2854,14 +2935,14 @@ function DescriptionEditor({ modelName, description }) {
2854
2935
  autoFocus: true
2855
2936
  }
2856
2937
  ),
2857
- /* @__PURE__ */ jsxs9("div", { className: "detail-panel__rationale-actions", children: [
2938
+ /* @__PURE__ */ jsxs10("div", { className: "detail-panel__rationale-actions", children: [
2858
2939
  /* @__PURE__ */ jsx13("button", { className: "detail-panel__button", onClick: handleSave, children: "Save" }),
2859
2940
  /* @__PURE__ */ jsx13("button", { className: "detail-panel__button", onClick: handleCancel, children: "Cancel" })
2860
2941
  ] })
2861
2942
  ] });
2862
2943
  }
2863
- return /* @__PURE__ */ jsxs9("div", { className: "detail-panel__description-section", children: [
2864
- /* @__PURE__ */ jsxs9("div", { className: "detail-panel__rationale-header", children: [
2944
+ return /* @__PURE__ */ jsxs10("div", { className: "detail-panel__description-section", children: [
2945
+ /* @__PURE__ */ jsxs10("div", { className: "detail-panel__rationale-header", children: [
2865
2946
  /* @__PURE__ */ jsx13("h4", { className: "detail-panel__section-title", style: { margin: 0 }, children: "Description" }),
2866
2947
  /* @__PURE__ */ jsx13(
2867
2948
  "button",
@@ -2887,7 +2968,7 @@ function DescriptionEditor({ modelName, description }) {
2887
2968
 
2888
2969
  // src/components/DetailPanel/GrainEditor.tsx
2889
2970
  import { useCallback as useCallback13, useEffect as useEffect9, useState as useState11 } from "react";
2890
- import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
2971
+ import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
2891
2972
  function GrainEditor({ modelName, grain }) {
2892
2973
  const host = useCanvasHost();
2893
2974
  const [editing, setEditing] = useState11(false);
@@ -2935,7 +3016,7 @@ function GrainEditor({ modelName, grain }) {
2935
3016
  ) });
2936
3017
  }
2937
3018
  if (editing) {
2938
- return /* @__PURE__ */ jsxs10("div", { className: "detail-panel__grain-section", children: [
3019
+ return /* @__PURE__ */ jsxs11("div", { className: "detail-panel__grain-section", children: [
2939
3020
  /* @__PURE__ */ jsx14("div", { className: "detail-panel__rationale-header", children: /* @__PURE__ */ jsx14("h4", { className: "detail-panel__section-title", style: { margin: 0 }, children: "Grain" }) }),
2940
3021
  /* @__PURE__ */ jsx14(
2941
3022
  "textarea",
@@ -2949,14 +3030,14 @@ function GrainEditor({ modelName, grain }) {
2949
3030
  autoFocus: true
2950
3031
  }
2951
3032
  ),
2952
- /* @__PURE__ */ jsxs10("div", { className: "detail-panel__rationale-actions", children: [
3033
+ /* @__PURE__ */ jsxs11("div", { className: "detail-panel__rationale-actions", children: [
2953
3034
  /* @__PURE__ */ jsx14("button", { className: "detail-panel__button", onClick: handleSave, children: "Save" }),
2954
3035
  /* @__PURE__ */ jsx14("button", { className: "detail-panel__button", onClick: handleCancel, children: "Cancel" })
2955
3036
  ] })
2956
3037
  ] });
2957
3038
  }
2958
- return /* @__PURE__ */ jsxs10("div", { className: "detail-panel__grain-section", children: [
2959
- /* @__PURE__ */ jsxs10("div", { className: "detail-panel__rationale-header", children: [
3039
+ return /* @__PURE__ */ jsxs11("div", { className: "detail-panel__grain-section", children: [
3040
+ /* @__PURE__ */ jsxs11("div", { className: "detail-panel__rationale-header", children: [
2960
3041
  /* @__PURE__ */ jsx14("h4", { className: "detail-panel__section-title", style: { margin: 0 }, children: "Grain" }),
2961
3042
  /* @__PURE__ */ jsx14(
2962
3043
  "button",
@@ -2980,9 +3061,102 @@ function GrainEditor({ modelName, grain }) {
2980
3061
  ] });
2981
3062
  }
2982
3063
 
3064
+ // src/components/DetailPanel/AliasEditor.tsx
3065
+ import { useCallback as useCallback14, useEffect as useEffect10, useRef as useRef8, useState as useState12 } from "react";
3066
+ import { MODEL_ALIAS_MAX_LENGTH, MODEL_ALIAS_RULE, isValidModelAlias } from "@erd-studio/core";
3067
+ import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
3068
+ function AliasEditor({ modelName, alias, readOnly }) {
3069
+ const host = useCanvasHost();
3070
+ const [editing, setEditing] = useState12(false);
3071
+ const [value, setValue] = useState12(alias ?? "");
3072
+ const settled = useRef8(false);
3073
+ useEffect10(() => {
3074
+ if (!editing) {
3075
+ setValue(alias ?? "");
3076
+ }
3077
+ }, [alias, editing]);
3078
+ const trimmed = value.trim();
3079
+ const error = trimmed && !isValidModelAlias(trimmed) ? MODEL_ALIAS_RULE : null;
3080
+ const handleSave = useCallback14(() => {
3081
+ if (error || settled.current) return;
3082
+ settled.current = true;
3083
+ const next = trimmed === modelName ? "" : trimmed;
3084
+ if (next !== (alias ?? "")) {
3085
+ host.postMessage({ type: "updateModelAlias", payload: { modelName, alias: next } });
3086
+ }
3087
+ setEditing(false);
3088
+ }, [host, modelName, alias, trimmed, error]);
3089
+ const handleCancel = useCallback14(() => {
3090
+ settled.current = true;
3091
+ setValue(alias ?? "");
3092
+ setEditing(false);
3093
+ }, [alias]);
3094
+ const handleKeyDown = useCallback14(
3095
+ (e) => {
3096
+ if (e.key === "Enter") {
3097
+ e.preventDefault();
3098
+ handleSave();
3099
+ } else if (e.key === "Escape") {
3100
+ e.preventDefault();
3101
+ handleCancel();
3102
+ }
3103
+ },
3104
+ [handleSave, handleCancel]
3105
+ );
3106
+ const startEditing = useCallback14(() => {
3107
+ settled.current = false;
3108
+ setEditing(true);
3109
+ }, []);
3110
+ if (editing) {
3111
+ return /* @__PURE__ */ jsxs12("div", { className: "detail-panel__metadata-row detail-panel__metadata-row--alias", children: [
3112
+ /* @__PURE__ */ jsx15("span", { className: "detail-panel__label detail-panel__label--wide", children: "Table name" }),
3113
+ /* @__PURE__ */ jsxs12("span", { className: "detail-panel__alias-edit", children: [
3114
+ /* @__PURE__ */ jsx15(
3115
+ "input",
3116
+ {
3117
+ className: `detail-panel__alias-input${error ? " detail-panel__alias-input--error" : ""}`,
3118
+ value,
3119
+ placeholder: modelName,
3120
+ maxLength: MODEL_ALIAS_MAX_LENGTH,
3121
+ onChange: (e) => setValue(e.target.value),
3122
+ onKeyDown: handleKeyDown,
3123
+ onBlur: () => error ? handleCancel() : handleSave(),
3124
+ "aria-label": "Table name (alias)",
3125
+ "aria-invalid": error ? true : void 0,
3126
+ autoFocus: true
3127
+ }
3128
+ ),
3129
+ /* @__PURE__ */ jsx15("span", { className: `detail-panel__alias-hint${error ? " detail-panel__alias-hint--error" : ""}`, children: error ?? "The table dbt builds (its alias). Leave blank to use the model name." })
3130
+ ] })
3131
+ ] });
3132
+ }
3133
+ return /* @__PURE__ */ jsxs12("div", { className: "detail-panel__metadata-row detail-panel__metadata-row--alias", children: [
3134
+ /* @__PURE__ */ jsx15("span", { className: "detail-panel__label detail-panel__label--wide", children: "Table name" }),
3135
+ /* @__PURE__ */ jsx15(
3136
+ "span",
3137
+ {
3138
+ className: `detail-panel__value${alias ? "" : " detail-panel__value--muted"}`,
3139
+ title: alias ? `Built as ${alias} (dbt alias); the model is ${modelName}` : "Same as the model name",
3140
+ onDoubleClick: readOnly ? void 0 : startEditing,
3141
+ children: alias || modelName
3142
+ }
3143
+ ),
3144
+ !readOnly && /* @__PURE__ */ jsx15(
3145
+ "button",
3146
+ {
3147
+ className: "detail-panel__rationale-edit-btn detail-panel__alias-edit-btn",
3148
+ onClick: startEditing,
3149
+ title: "Set the table name (alias)",
3150
+ "aria-label": "Edit table name",
3151
+ children: "\u270E"
3152
+ }
3153
+ )
3154
+ ] });
3155
+ }
3156
+
2983
3157
  // src/components/DetailPanel/RoleEditor.tsx
2984
- import { useCallback as useCallback14 } from "react";
2985
- import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
3158
+ import { useCallback as useCallback15 } from "react";
3159
+ import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
2986
3160
  var ROLE_OPTIONS = [
2987
3161
  { value: "conformed-dim", label: "Conformed Dimension" },
2988
3162
  { value: "domain-dim", label: "Domain Dimension" },
@@ -2996,7 +3170,7 @@ var ROLE_OPTIONS = [
2996
3170
  ];
2997
3171
  function RoleEditor({ modelName, modelRole }) {
2998
3172
  const host = useCanvasHost();
2999
- const handleChange = useCallback14(
3173
+ const handleChange = useCallback15(
3000
3174
  (e) => {
3001
3175
  const value = e.target.value;
3002
3176
  if (value === (modelRole ?? "")) return;
@@ -3010,17 +3184,17 @@ function RoleEditor({ modelName, modelRole }) {
3010
3184
  },
3011
3185
  [host, modelName, modelRole]
3012
3186
  );
3013
- return /* @__PURE__ */ jsxs11("div", { className: "detail-panel__role-section", children: [
3014
- /* @__PURE__ */ jsx15("h4", { className: "detail-panel__section-title", style: { margin: 0 }, children: "Role" }),
3015
- /* @__PURE__ */ jsxs11(
3187
+ return /* @__PURE__ */ jsxs13("div", { className: "detail-panel__role-section", children: [
3188
+ /* @__PURE__ */ jsx16("h4", { className: "detail-panel__section-title", style: { margin: 0 }, children: "Role" }),
3189
+ /* @__PURE__ */ jsxs13(
3016
3190
  "select",
3017
3191
  {
3018
3192
  className: "detail-panel__role-select",
3019
3193
  value: modelRole ?? "",
3020
3194
  onChange: handleChange,
3021
3195
  children: [
3022
- /* @__PURE__ */ jsx15("option", { value: "", children: "No role" }),
3023
- ROLE_OPTIONS.map((opt) => /* @__PURE__ */ jsx15("option", { value: opt.value, children: opt.label }, opt.value))
3196
+ /* @__PURE__ */ jsx16("option", { value: "", children: "No role" }),
3197
+ ROLE_OPTIONS.map((opt) => /* @__PURE__ */ jsx16("option", { value: opt.value, children: opt.label }, opt.value))
3024
3198
  ]
3025
3199
  }
3026
3200
  )
@@ -3028,15 +3202,15 @@ function RoleEditor({ modelName, modelRole }) {
3028
3202
  }
3029
3203
 
3030
3204
  // src/components/DetailPanel/ColumnEditor.tsx
3031
- import { useCallback as useCallback19, useEffect as useEffect12, useMemo as useMemo5, useState as useState16 } from "react";
3205
+ import { useCallback as useCallback21, useEffect as useEffect14, useMemo as useMemo5, useState as useState18 } from "react";
3032
3206
 
3033
3207
  // src/components/common/ColumnRowEditor.tsx
3034
- import { useCallback as useCallback17, useEffect as useEffect11, useRef as useRef9, useState as useState14 } from "react";
3208
+ import { useCallback as useCallback18, useEffect as useEffect12, useRef as useRef10, useState as useState15 } from "react";
3035
3209
 
3036
3210
  // src/components/common/KeyBadgeGroup.tsx
3037
- import { useCallback as useCallback15, useEffect as useEffect10, useLayoutEffect, useRef as useRef8, useState as useState12 } from "react";
3211
+ import { useCallback as useCallback16, useEffect as useEffect11, useLayoutEffect, useRef as useRef9, useState as useState13 } from "react";
3038
3212
  import { createPortal as createPortal4 } from "react-dom";
3039
- import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
3213
+ import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
3040
3214
  var KEY_CONFIG = [
3041
3215
  { type: "PK", label: "Primary Key", description: "Unique identifier for each row" },
3042
3216
  { type: "FK", label: "Foreign Key", description: "References another table" },
@@ -3054,11 +3228,11 @@ function KeyBadgeGroup({
3054
3228
  showMultiplePKWarning = false
3055
3229
  }) {
3056
3230
  const viewer = useIsViewer();
3057
- const [isOpen, setIsOpen] = useState12(false);
3058
- const [dropdownPos, setDropdownPos] = useState12({ top: 0, left: 0 });
3059
- const containerRef = useRef8(null);
3060
- const triggerRef = useRef8(null);
3061
- const dropdownRef = useRef8(null);
3231
+ const [isOpen, setIsOpen] = useState13(false);
3232
+ const [dropdownPos, setDropdownPos] = useState13({ top: 0, left: 0 });
3233
+ const containerRef = useRef9(null);
3234
+ const triggerRef = useRef9(null);
3235
+ const dropdownRef = useRef9(null);
3062
3236
  const isEditable = mode === "editable" && (onTogglePK || onToggleFK || onToggleNK);
3063
3237
  useLayoutEffect(() => {
3064
3238
  if (isOpen && triggerRef.current) {
@@ -3069,7 +3243,7 @@ function KeyBadgeGroup({
3069
3243
  });
3070
3244
  }
3071
3245
  }, [isOpen]);
3072
- useEffect10(() => {
3246
+ useEffect11(() => {
3073
3247
  const handleClickOutside = (e) => {
3074
3248
  const target = e.target;
3075
3249
  const clickedInContainer = containerRef.current?.contains(target);
@@ -3084,7 +3258,7 @@ function KeyBadgeGroup({
3084
3258
  }
3085
3259
  return void 0;
3086
3260
  }, [isOpen]);
3087
- const handleKeyDown = useCallback15(
3261
+ const handleKeyDown = useCallback16(
3088
3262
  (e) => {
3089
3263
  if (e.key === "Escape") {
3090
3264
  e.preventDefault();
@@ -3107,19 +3281,19 @@ function KeyBadgeGroup({
3107
3281
  FK: isForeignKey,
3108
3282
  NK: isNaturalKey
3109
3283
  };
3110
- const handleToggle = useCallback15(() => {
3284
+ const handleToggle = useCallback16(() => {
3111
3285
  if (isEditable) {
3112
3286
  setIsOpen((prev) => !prev);
3113
3287
  }
3114
3288
  }, [isEditable]);
3115
- const handleOptionClick = useCallback15(
3289
+ const handleOptionClick = useCallback16(
3116
3290
  (type, e) => {
3117
3291
  e.stopPropagation();
3118
3292
  toggleHandlers[type]?.();
3119
3293
  },
3120
3294
  [toggleHandlers]
3121
3295
  );
3122
- const warningIcon = showMultiplePKWarning && isPrimaryKey ? /* @__PURE__ */ jsx16(
3296
+ const warningIcon = showMultiplePKWarning && isPrimaryKey ? /* @__PURE__ */ jsx17(
3123
3297
  "span",
3124
3298
  {
3125
3299
  className: "key-badge-group__warning",
@@ -3127,14 +3301,14 @@ function KeyBadgeGroup({
3127
3301
  children: "!"
3128
3302
  }
3129
3303
  ) : null;
3130
- return /* @__PURE__ */ jsxs12(
3304
+ return /* @__PURE__ */ jsxs14(
3131
3305
  "div",
3132
3306
  {
3133
3307
  ref: containerRef,
3134
3308
  className: `key-badge-group ${isOpen ? "key-badge-group--open" : ""} ${isEditable ? "key-badge-group--editable" : ""}`,
3135
3309
  onKeyDown: handleKeyDown,
3136
3310
  children: [
3137
- /* @__PURE__ */ jsxs12(
3311
+ /* @__PURE__ */ jsxs14(
3138
3312
  "button",
3139
3313
  {
3140
3314
  ref: triggerRef,
@@ -3146,7 +3320,7 @@ function KeyBadgeGroup({
3146
3320
  "aria-expanded": isOpen,
3147
3321
  title: isEditable ? "Click to edit key types" : void 0,
3148
3322
  children: [
3149
- selectedKeys.length > 0 ? /* @__PURE__ */ jsx16("span", { className: "key-badge-group__selected", children: selectedKeys.map((type) => /* @__PURE__ */ jsx16(
3323
+ selectedKeys.length > 0 ? /* @__PURE__ */ jsx17("span", { className: "key-badge-group__selected", children: selectedKeys.map((type) => /* @__PURE__ */ jsx17(
3150
3324
  KeyBadge,
3151
3325
  {
3152
3326
  type,
@@ -3155,17 +3329,17 @@ function KeyBadgeGroup({
3155
3329
  status
3156
3330
  },
3157
3331
  type
3158
- )) }) : /* @__PURE__ */ jsx16("span", { className: "key-badge-group__empty", children: "\u2014" }),
3159
- isEditable ? /* @__PURE__ */ jsx16("span", { className: "key-badge-group__arrow", children: "\u25BE" }) : viewer ? (
3332
+ )) }) : /* @__PURE__ */ jsx17("span", { className: "key-badge-group__empty", children: "\u2014" }),
3333
+ isEditable ? /* @__PURE__ */ jsx17("span", { className: "key-badge-group__arrow", children: "\u25BE" }) : viewer ? (
3160
3334
  // Viewer: keep the arrow's space so rows line up with the editor.
3161
- /* @__PURE__ */ jsx16("span", { className: "key-badge-group__arrow", "aria-hidden": true, style: { visibility: "hidden" }, children: "\u25BE" })
3335
+ /* @__PURE__ */ jsx17("span", { className: "key-badge-group__arrow", "aria-hidden": true, style: { visibility: "hidden" }, children: "\u25BE" })
3162
3336
  ) : null,
3163
3337
  warningIcon
3164
3338
  ]
3165
3339
  }
3166
3340
  ),
3167
3341
  isOpen && createPortal4(
3168
- /* @__PURE__ */ jsx16(
3342
+ /* @__PURE__ */ jsx17(
3169
3343
  "div",
3170
3344
  {
3171
3345
  ref: dropdownRef,
@@ -3174,7 +3348,7 @@ function KeyBadgeGroup({
3174
3348
  children: KEY_CONFIG.map(({ type, label, description }) => {
3175
3349
  const isActive = activeStates[type];
3176
3350
  const handler = toggleHandlers[type];
3177
- return /* @__PURE__ */ jsxs12(
3351
+ return /* @__PURE__ */ jsxs14(
3178
3352
  "div",
3179
3353
  {
3180
3354
  className: `key-badge-group__option ${isActive ? "key-badge-group__option--active" : ""}`,
@@ -3189,8 +3363,8 @@ function KeyBadgeGroup({
3189
3363
  }
3190
3364
  },
3191
3365
  children: [
3192
- /* @__PURE__ */ jsx16("span", { className: "key-badge-group__checkbox", children: isActive ? "\u2713" : "" }),
3193
- /* @__PURE__ */ jsx16(
3366
+ /* @__PURE__ */ jsx17("span", { className: "key-badge-group__checkbox", children: isActive ? "\u2713" : "" }),
3367
+ /* @__PURE__ */ jsx17(
3194
3368
  KeyBadge,
3195
3369
  {
3196
3370
  type,
@@ -3199,9 +3373,9 @@ function KeyBadgeGroup({
3199
3373
  status
3200
3374
  }
3201
3375
  ),
3202
- /* @__PURE__ */ jsxs12("span", { className: "key-badge-group__label", children: [
3203
- /* @__PURE__ */ jsx16("span", { className: "key-badge-group__label-text", children: label }),
3204
- /* @__PURE__ */ jsx16("span", { className: "key-badge-group__label-desc", children: description })
3376
+ /* @__PURE__ */ jsxs14("span", { className: "key-badge-group__label", children: [
3377
+ /* @__PURE__ */ jsx17("span", { className: "key-badge-group__label-text", children: label }),
3378
+ /* @__PURE__ */ jsx17("span", { className: "key-badge-group__label-desc", children: description })
3205
3379
  ] })
3206
3380
  ]
3207
3381
  },
@@ -3218,13 +3392,13 @@ function KeyBadgeGroup({
3218
3392
  }
3219
3393
 
3220
3394
  // src/hooks/useFocusWithinRow.ts
3221
- import { useCallback as useCallback16, useState as useState13 } from "react";
3395
+ import { useCallback as useCallback17, useState as useState14 } from "react";
3222
3396
  function useFocusWithinRow(onFocusLeave) {
3223
- const [isFocusWithin, setIsFocusWithin] = useState13(false);
3224
- const handleFocus = useCallback16(() => {
3397
+ const [isFocusWithin, setIsFocusWithin] = useState14(false);
3398
+ const handleFocus = useCallback17(() => {
3225
3399
  setIsFocusWithin(true);
3226
3400
  }, []);
3227
- const handleBlur = useCallback16(
3401
+ const handleBlur = useCallback17(
3228
3402
  (e) => {
3229
3403
  const currentTarget = e.currentTarget;
3230
3404
  requestAnimationFrame(() => {
@@ -3246,17 +3420,17 @@ function useFocusWithinRow(onFocusLeave) {
3246
3420
  }
3247
3421
 
3248
3422
  // src/components/common/ColumnRowEditor.tsx
3249
- import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
3423
+ import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
3250
3424
  function validateColumnName(name, existingNames, currentName) {
3251
3425
  const trimmed = name.trim();
3252
3426
  if (!trimmed) {
3253
3427
  return "Name is required";
3254
3428
  }
3255
- if (!/^[a-z0-9_]+$/.test(trimmed)) {
3256
- return "Use lowercase letters, numbers, underscores";
3429
+ if (!/^[A-Za-z0-9_]+$/.test(trimmed)) {
3430
+ return "Use only letters, numbers, underscores";
3257
3431
  }
3258
3432
  const otherNames = existingNames.filter((n) => n !== currentName);
3259
- if (otherNames.includes(trimmed)) {
3433
+ if (otherNames.some((n) => n.toLowerCase() === trimmed.toLowerCase())) {
3260
3434
  return "Column name already exists";
3261
3435
  }
3262
3436
  return null;
@@ -3282,9 +3456,10 @@ function ColumnRowEditor({
3282
3456
  isBeingDragged = false,
3283
3457
  isSelected = false,
3284
3458
  onSelect,
3285
- isEditingActive = false
3459
+ isEditingActive = false,
3460
+ metaSlot
3286
3461
  }) {
3287
- const [localColumn, setLocalColumn] = useState14({
3462
+ const [localColumn, setLocalColumn] = useState15({
3288
3463
  name: column.name,
3289
3464
  dataType: column.dataType,
3290
3465
  description: column.description,
@@ -3294,18 +3469,18 @@ function ColumnRowEditor({
3294
3469
  scdType: column.scdType,
3295
3470
  additiveType: column.additiveType
3296
3471
  });
3297
- const [editingField, setEditingField] = useState14(
3472
+ const [editingField, setEditingField] = useState15(
3298
3473
  mode === "new" ? "name" : null
3299
3474
  );
3300
- const [validationError, setValidationError] = useState14(null);
3301
- const [confirmingDelete, setConfirmingDelete] = useState14(false);
3302
- const deleteTimerRef = useRef9(null);
3303
- const nameInputRef = useRef9(null);
3304
- const descriptionInputRef = useRef9(null);
3305
- const isSavingRef = useRef9(false);
3306
- const isSwitchingFieldRef = useRef9(false);
3307
- const skipNextBlurSaveRef = useRef9(false);
3308
- useEffect11(() => {
3475
+ const [validationError, setValidationError] = useState15(null);
3476
+ const [confirmingDelete, setConfirmingDelete] = useState15(false);
3477
+ const deleteTimerRef = useRef10(null);
3478
+ const nameInputRef = useRef10(null);
3479
+ const descriptionInputRef = useRef10(null);
3480
+ const isSavingRef = useRef10(false);
3481
+ const isSwitchingFieldRef = useRef10(false);
3482
+ const skipNextBlurSaveRef = useRef10(false);
3483
+ useEffect12(() => {
3309
3484
  if (!isSavingRef.current) {
3310
3485
  setLocalColumn({
3311
3486
  name: column.name,
@@ -3329,12 +3504,12 @@ function ColumnRowEditor({
3329
3504
  column.scdType,
3330
3505
  column.additiveType
3331
3506
  ]);
3332
- useEffect11(() => {
3507
+ useEffect12(() => {
3333
3508
  return () => {
3334
3509
  if (deleteTimerRef.current) clearTimeout(deleteTimerRef.current);
3335
3510
  };
3336
3511
  }, []);
3337
- useEffect11(() => {
3512
+ useEffect12(() => {
3338
3513
  if (isEditingActive && !editingField && mode !== "readonly") {
3339
3514
  isSwitchingFieldRef.current = true;
3340
3515
  setEditingField("name");
@@ -3344,7 +3519,7 @@ function ColumnRowEditor({
3344
3519
  });
3345
3520
  }
3346
3521
  }, [isEditingActive, editingField, mode]);
3347
- useEffect11(() => {
3522
+ useEffect12(() => {
3348
3523
  if (editingField === "name" && nameInputRef.current) {
3349
3524
  nameInputRef.current.focus();
3350
3525
  nameInputRef.current.select();
@@ -3355,7 +3530,7 @@ function ColumnRowEditor({
3355
3530
  descriptionInputRef.current.setSelectionRange(len, len);
3356
3531
  }
3357
3532
  }, [editingField]);
3358
- const handleSave = useCallback17(() => {
3533
+ const handleSave = useCallback18(() => {
3359
3534
  if (mode === "readonly") return;
3360
3535
  const error = validateColumnName(
3361
3536
  localColumn.name,
@@ -3396,7 +3571,7 @@ function ColumnRowEditor({
3396
3571
  }
3397
3572
  }
3398
3573
  });
3399
- const handleFieldClick = useCallback17(
3574
+ const handleFieldClick = useCallback18(
3400
3575
  (field) => {
3401
3576
  if (mode === "readonly") return;
3402
3577
  isSwitchingFieldRef.current = true;
@@ -3411,7 +3586,7 @@ function ColumnRowEditor({
3411
3586
  },
3412
3587
  [mode]
3413
3588
  );
3414
- const handleKeyDown = useCallback17(
3589
+ const handleKeyDown = useCallback18(
3415
3590
  (e) => {
3416
3591
  if (e.key === "Enter") {
3417
3592
  e.preventDefault();
@@ -3439,7 +3614,7 @@ function ColumnRowEditor({
3439
3614
  },
3440
3615
  [mode, column, handleSave, onCancel]
3441
3616
  );
3442
- const handleDataTypeChange = useCallback17(
3617
+ const handleDataTypeChange = useCallback18(
3443
3618
  (newType) => {
3444
3619
  setLocalColumn((prev) => ({ ...prev, dataType: newType }));
3445
3620
  setEditingField(null);
@@ -3467,7 +3642,7 @@ function ColumnRowEditor({
3467
3642
  },
3468
3643
  [mode, localColumn, existingColumnNames, column.name, onUpdate]
3469
3644
  );
3470
- const handleDeleteClick = useCallback17(
3645
+ const handleDeleteClick = useCallback18(
3471
3646
  (e) => {
3472
3647
  e.stopPropagation();
3473
3648
  if (confirmingDelete) {
@@ -3483,7 +3658,7 @@ function ColumnRowEditor({
3483
3658
  },
3484
3659
  [confirmingDelete, onDelete]
3485
3660
  );
3486
- const handleCancelDelete = useCallback17(
3661
+ const handleCancelDelete = useCallback18(
3487
3662
  (e) => {
3488
3663
  e.stopPropagation();
3489
3664
  if (deleteTimerRef.current) clearTimeout(deleteTimerRef.current);
@@ -3491,7 +3666,7 @@ function ColumnRowEditor({
3491
3666
  },
3492
3667
  []
3493
3668
  );
3494
- const handleScdTypeChange = useCallback17(
3669
+ const handleScdTypeChange = useCallback18(
3495
3670
  (e) => {
3496
3671
  const raw = e.target.value;
3497
3672
  const value = raw === "" ? void 0 : Number(raw);
@@ -3514,7 +3689,7 @@ function ColumnRowEditor({
3514
3689
  },
3515
3690
  [mode, localColumn, onUpdate]
3516
3691
  );
3517
- const handleAdditiveTypeChange = useCallback17(
3692
+ const handleAdditiveTypeChange = useCallback18(
3518
3693
  (e) => {
3519
3694
  const value = e.target.value || void 0;
3520
3695
  setLocalColumn((prev) => ({ ...prev, additiveType: value }));
@@ -3536,7 +3711,7 @@ function ColumnRowEditor({
3536
3711
  },
3537
3712
  [mode, localColumn, onUpdate]
3538
3713
  );
3539
- const handleChevronClick = useCallback17(
3714
+ const handleChevronClick = useCallback18(
3540
3715
  (e) => {
3541
3716
  e.stopPropagation();
3542
3717
  onToggleExpand?.({ altKey: e.altKey });
@@ -3548,7 +3723,7 @@ function ColumnRowEditor({
3548
3723
  const hasDescription = Boolean(localColumn.description?.trim());
3549
3724
  const isDimRole = modelRole?.includes("dim") || modelRole === "reference";
3550
3725
  const isFactRole = modelRole?.includes("fact") || modelRole?.includes("snapshot");
3551
- const handleRowClick = useCallback17(
3726
+ const handleRowClick = useCallback18(
3552
3727
  (e) => {
3553
3728
  const target = e.target;
3554
3729
  if (target.closest("button") || target.closest("input") || target.closest("select") || target.closest("textarea") || target.closest(".key-badge-group")) {
@@ -3569,9 +3744,9 @@ function ColumnRowEditor({
3569
3744
  isDragOver && "column-row-editor--drag-over",
3570
3745
  isBeingDragged && "column-row-editor--dragging"
3571
3746
  ].filter(Boolean).join(" ");
3572
- return /* @__PURE__ */ jsxs13("div", { className: rowClasses, ...rowProps, onClick: mode !== "new" ? handleRowClick : void 0, children: [
3573
- /* @__PURE__ */ jsxs13("div", { className: "column-row-editor__main", children: [
3574
- /* @__PURE__ */ jsx17(
3747
+ return /* @__PURE__ */ jsxs15("div", { className: rowClasses, ...rowProps, onClick: mode !== "new" ? handleRowClick : void 0, children: [
3748
+ /* @__PURE__ */ jsxs15("div", { className: "column-row-editor__main", children: [
3749
+ /* @__PURE__ */ jsx18(
3575
3750
  "span",
3576
3751
  {
3577
3752
  className: `column-row-editor__drag-handle${!dragHandleProps ? " column-row-editor__drag-handle--hidden" : ""}`,
@@ -3579,7 +3754,7 @@ function ColumnRowEditor({
3579
3754
  children: "\u283F"
3580
3755
  }
3581
3756
  ),
3582
- onToggleExpand && /* @__PURE__ */ jsx17(
3757
+ onToggleExpand && /* @__PURE__ */ jsx18(
3583
3758
  "button",
3584
3759
  {
3585
3760
  className: "column-row-editor__chevron",
@@ -3590,7 +3765,7 @@ function ColumnRowEditor({
3590
3765
  children: expanded ? "\u25BE" : "\u25B8"
3591
3766
  }
3592
3767
  ),
3593
- showIndicators && /* @__PURE__ */ jsx17(
3768
+ showIndicators && /* @__PURE__ */ jsx18(
3594
3769
  KeyBadgeGroup,
3595
3770
  {
3596
3771
  isPrimaryKey: column.isPrimaryKey ?? false,
@@ -3613,7 +3788,7 @@ function ColumnRowEditor({
3613
3788
  showMultiplePKWarning
3614
3789
  }
3615
3790
  ),
3616
- isEditing && editingField === "name" ? /* @__PURE__ */ jsx17(
3791
+ isEditing && editingField === "name" ? /* @__PURE__ */ jsx18(
3617
3792
  "input",
3618
3793
  {
3619
3794
  ref: nameInputRef,
@@ -3624,7 +3799,7 @@ function ColumnRowEditor({
3624
3799
  onKeyDown: handleKeyDown,
3625
3800
  placeholder: "column_name"
3626
3801
  }
3627
- ) : /* @__PURE__ */ jsx17(
3802
+ ) : /* @__PURE__ */ jsx18(
3628
3803
  "span",
3629
3804
  {
3630
3805
  className: "column-row-editor__name",
@@ -3633,10 +3808,10 @@ function ColumnRowEditor({
3633
3808
  handleFieldClick("name");
3634
3809
  },
3635
3810
  title: mode !== "readonly" ? "Double-click to edit" : void 0,
3636
- children: localColumn.name || /* @__PURE__ */ jsx17("em", { className: "column-row-editor__placeholder", children: "column_name" })
3811
+ children: localColumn.name || /* @__PURE__ */ jsx18("em", { className: "column-row-editor__placeholder", children: "column_name" })
3637
3812
  }
3638
3813
  ),
3639
- !expanded && hasDescription && /* @__PURE__ */ jsx17(
3814
+ !expanded && hasDescription && /* @__PURE__ */ jsx18(
3640
3815
  "span",
3641
3816
  {
3642
3817
  className: "column-row-editor__info-badge",
@@ -3645,7 +3820,7 @@ function ColumnRowEditor({
3645
3820
  children: "\u24D8"
3646
3821
  }
3647
3822
  ),
3648
- isEditing && editingField === "dataType" ? /* @__PURE__ */ jsx17(
3823
+ isEditing && editingField === "dataType" ? /* @__PURE__ */ jsx18(
3649
3824
  DataTypeSelect,
3650
3825
  {
3651
3826
  value: localColumn.dataType,
@@ -3657,7 +3832,7 @@ function ColumnRowEditor({
3657
3832
  className: "column-row-editor__type-select",
3658
3833
  autoOpen: true
3659
3834
  }
3660
- ) : /* @__PURE__ */ jsx17(
3835
+ ) : /* @__PURE__ */ jsx18(
3661
3836
  "span",
3662
3837
  {
3663
3838
  className: "column-row-editor__type",
@@ -3669,8 +3844,8 @@ function ColumnRowEditor({
3669
3844
  children: localColumn.dataType
3670
3845
  }
3671
3846
  ),
3672
- showDelete && mode !== "readonly" && mode !== "new" && (confirmingDelete ? /* @__PURE__ */ jsxs13("span", { className: "column-row-editor__delete-confirm", children: [
3673
- /* @__PURE__ */ jsx17(
3847
+ showDelete && mode !== "readonly" && mode !== "new" && (confirmingDelete ? /* @__PURE__ */ jsxs15("span", { className: "column-row-editor__delete-confirm", children: [
3848
+ /* @__PURE__ */ jsx18(
3674
3849
  "button",
3675
3850
  {
3676
3851
  className: "column-row-editor__delete-confirm-yes",
@@ -3680,7 +3855,7 @@ function ColumnRowEditor({
3680
3855
  children: "Delete?"
3681
3856
  }
3682
3857
  ),
3683
- /* @__PURE__ */ jsx17(
3858
+ /* @__PURE__ */ jsx18(
3684
3859
  "button",
3685
3860
  {
3686
3861
  className: "column-row-editor__delete-confirm-no",
@@ -3690,7 +3865,7 @@ function ColumnRowEditor({
3690
3865
  children: "\u2715"
3691
3866
  }
3692
3867
  )
3693
- ] }) : /* @__PURE__ */ jsx17(
3868
+ ] }) : /* @__PURE__ */ jsx18(
3694
3869
  "button",
3695
3870
  {
3696
3871
  className: "column-row-editor__delete",
@@ -3701,8 +3876,8 @@ function ColumnRowEditor({
3701
3876
  }
3702
3877
  ))
3703
3878
  ] }),
3704
- expanded && /* @__PURE__ */ jsxs13("div", { className: "column-row-editor__description-area", children: [
3705
- editingField === "description" ? /* @__PURE__ */ jsx17(
3879
+ expanded && /* @__PURE__ */ jsxs15("div", { className: "column-row-editor__description-area", children: [
3880
+ editingField === "description" ? /* @__PURE__ */ jsx18(
3706
3881
  "textarea",
3707
3882
  {
3708
3883
  ref: descriptionInputRef,
@@ -3723,7 +3898,7 @@ function ColumnRowEditor({
3723
3898
  placeholder: "Add a description for this column...",
3724
3899
  rows: 2
3725
3900
  }
3726
- ) : /* @__PURE__ */ jsx17(
3901
+ ) : /* @__PURE__ */ jsx18(
3727
3902
  "div",
3728
3903
  {
3729
3904
  className: `column-row-editor__description-text ${!hasDescription ? "column-row-editor__description-text--empty" : ""}`,
@@ -3732,9 +3907,9 @@ function ColumnRowEditor({
3732
3907
  children: localColumn.description || (mode !== "readonly" ? "\u270F Add description..." : "No description")
3733
3908
  }
3734
3909
  ),
3735
- isDimRole && /* @__PURE__ */ jsxs13("div", { className: "column-row-editor__metadata-row", children: [
3736
- /* @__PURE__ */ jsx17("label", { className: "column-row-editor__metadata-label", children: "SCD Type" }),
3737
- /* @__PURE__ */ jsxs13(
3910
+ isDimRole && /* @__PURE__ */ jsxs15("div", { className: "column-row-editor__metadata-row", children: [
3911
+ /* @__PURE__ */ jsx18("label", { className: "column-row-editor__metadata-label", children: "SCD Type" }),
3912
+ /* @__PURE__ */ jsxs15(
3738
3913
  "select",
3739
3914
  {
3740
3915
  className: "column-row-editor__metadata-select",
@@ -3742,17 +3917,17 @@ function ColumnRowEditor({
3742
3917
  onChange: handleScdTypeChange,
3743
3918
  disabled: mode === "readonly",
3744
3919
  children: [
3745
- /* @__PURE__ */ jsx17("option", { value: "", children: "Not set" }),
3746
- /* @__PURE__ */ jsx17("option", { value: "0", children: "Type 0 \u2014 Never changes" }),
3747
- /* @__PURE__ */ jsx17("option", { value: "1", children: "Type 1 \u2014 Overwrite" }),
3748
- /* @__PURE__ */ jsx17("option", { value: "2", children: "Type 2 \u2014 Track history" })
3920
+ /* @__PURE__ */ jsx18("option", { value: "", children: "Not set" }),
3921
+ /* @__PURE__ */ jsx18("option", { value: "0", children: "Type 0 \u2014 Never changes" }),
3922
+ /* @__PURE__ */ jsx18("option", { value: "1", children: "Type 1 \u2014 Overwrite" }),
3923
+ /* @__PURE__ */ jsx18("option", { value: "2", children: "Type 2 \u2014 Track history" })
3749
3924
  ]
3750
3925
  }
3751
3926
  )
3752
3927
  ] }),
3753
- isFactRole && /* @__PURE__ */ jsxs13("div", { className: "column-row-editor__metadata-row", children: [
3754
- /* @__PURE__ */ jsx17("label", { className: "column-row-editor__metadata-label", children: "Additive" }),
3755
- /* @__PURE__ */ jsxs13(
3928
+ isFactRole && /* @__PURE__ */ jsxs15("div", { className: "column-row-editor__metadata-row", children: [
3929
+ /* @__PURE__ */ jsx18("label", { className: "column-row-editor__metadata-label", children: "Additive" }),
3930
+ /* @__PURE__ */ jsxs15(
3756
3931
  "select",
3757
3932
  {
3758
3933
  className: "column-row-editor__metadata-select",
@@ -3760,22 +3935,23 @@ function ColumnRowEditor({
3760
3935
  onChange: handleAdditiveTypeChange,
3761
3936
  disabled: mode === "readonly",
3762
3937
  children: [
3763
- /* @__PURE__ */ jsx17("option", { value: "", children: "Not set" }),
3764
- /* @__PURE__ */ jsx17("option", { value: "additive", children: "Additive \u2014 Sum across all dims" }),
3765
- /* @__PURE__ */ jsx17("option", { value: "semi-additive", children: "Semi-additive \u2014 Not across time" }),
3766
- /* @__PURE__ */ jsx17("option", { value: "non-additive", children: "Non-additive \u2014 Store components" })
3938
+ /* @__PURE__ */ jsx18("option", { value: "", children: "Not set" }),
3939
+ /* @__PURE__ */ jsx18("option", { value: "additive", children: "Additive \u2014 Sum across all dims" }),
3940
+ /* @__PURE__ */ jsx18("option", { value: "semi-additive", children: "Semi-additive \u2014 Not across time" }),
3941
+ /* @__PURE__ */ jsx18("option", { value: "non-additive", children: "Non-additive \u2014 Store components" })
3767
3942
  ]
3768
3943
  }
3769
3944
  )
3770
- ] })
3945
+ ] }),
3946
+ metaSlot
3771
3947
  ] }),
3772
- validationError && /* @__PURE__ */ jsx17("span", { className: "column-row-editor__error", children: validationError })
3948
+ validationError && /* @__PURE__ */ jsx18("span", { className: "column-row-editor__error", children: validationError })
3773
3949
  ] });
3774
3950
  }
3775
3951
 
3776
3952
  // src/components/DetailPanel/BulkColumnActions.tsx
3777
- import { useCallback as useCallback18, useState as useState15 } from "react";
3778
- import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
3953
+ import { useCallback as useCallback19, useState as useState16 } from "react";
3954
+ import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
3779
3955
  function BulkColumnActions({
3780
3956
  modelName,
3781
3957
  selectedColumns,
@@ -3783,7 +3959,7 @@ function BulkColumnActions({
3783
3959
  onClearSelection
3784
3960
  }) {
3785
3961
  const send = useSend();
3786
- const [showTypeSelect, setShowTypeSelect] = useState15(false);
3962
+ const [showTypeSelect, setShowTypeSelect] = useState16(false);
3787
3963
  const selectedColumnData = columns.filter((c) => selectedColumns.includes(c.name));
3788
3964
  const keyMajority = (key) => {
3789
3965
  const count = selectedColumnData.filter((c) => c[key]).length;
@@ -3792,7 +3968,7 @@ function BulkColumnActions({
3792
3968
  const majorityPK = keyMajority("isPrimaryKey");
3793
3969
  const majorityFK = keyMajority("isForeignKey");
3794
3970
  const majorityNK = keyMajority("isNaturalKey");
3795
- const handleBulkDelete = useCallback18(() => {
3971
+ const handleBulkDelete = useCallback19(() => {
3796
3972
  for (const colName of selectedColumns) {
3797
3973
  send({
3798
3974
  type: "removeColumn",
@@ -3801,7 +3977,7 @@ function BulkColumnActions({
3801
3977
  }
3802
3978
  onClearSelection();
3803
3979
  }, [selectedColumns, modelName, send, onClearSelection]);
3804
- const handleBulkToggleKey = useCallback18(
3980
+ const handleBulkToggleKey = useCallback19(
3805
3981
  (keyType, currentMajority) => {
3806
3982
  const newValue = !currentMajority;
3807
3983
  for (const colName of selectedColumns) {
@@ -3813,7 +3989,7 @@ function BulkColumnActions({
3813
3989
  },
3814
3990
  [selectedColumns, modelName, send]
3815
3991
  );
3816
- const handleBulkSetType = useCallback18(
3992
+ const handleBulkSetType = useCallback19(
3817
3993
  (newType) => {
3818
3994
  for (const col of selectedColumnData) {
3819
3995
  send({
@@ -3838,12 +4014,12 @@ function BulkColumnActions({
3838
4014
  },
3839
4015
  [selectedColumnData, modelName, send]
3840
4016
  );
3841
- return /* @__PURE__ */ jsxs14("div", { className: "bulk-column-actions", children: [
3842
- /* @__PURE__ */ jsxs14("span", { className: "bulk-column-actions__count", children: [
4017
+ return /* @__PURE__ */ jsxs16("div", { className: "bulk-column-actions", children: [
4018
+ /* @__PURE__ */ jsxs16("span", { className: "bulk-column-actions__count", children: [
3843
4019
  selectedColumns.length,
3844
4020
  " selected"
3845
4021
  ] }),
3846
- /* @__PURE__ */ jsxs14(
4022
+ /* @__PURE__ */ jsxs16(
3847
4023
  "button",
3848
4024
  {
3849
4025
  className: "bulk-column-actions__btn bulk-column-actions__btn--danger",
@@ -3856,8 +4032,8 @@ function BulkColumnActions({
3856
4032
  ]
3857
4033
  }
3858
4034
  ),
3859
- /* @__PURE__ */ jsx18("div", { className: "bulk-column-actions__divider" }),
3860
- /* @__PURE__ */ jsx18(
4035
+ /* @__PURE__ */ jsx19("div", { className: "bulk-column-actions__divider" }),
4036
+ /* @__PURE__ */ jsx19(
3861
4037
  "button",
3862
4038
  {
3863
4039
  className: `bulk-column-actions__key-btn ${majorityPK ? "bulk-column-actions__key-btn--active" : ""}`,
@@ -3866,7 +4042,7 @@ function BulkColumnActions({
3866
4042
  children: "PK"
3867
4043
  }
3868
4044
  ),
3869
- /* @__PURE__ */ jsx18(
4045
+ /* @__PURE__ */ jsx19(
3870
4046
  "button",
3871
4047
  {
3872
4048
  className: `bulk-column-actions__key-btn ${majorityFK ? "bulk-column-actions__key-btn--active" : ""}`,
@@ -3875,7 +4051,7 @@ function BulkColumnActions({
3875
4051
  children: "FK"
3876
4052
  }
3877
4053
  ),
3878
- /* @__PURE__ */ jsx18(
4054
+ /* @__PURE__ */ jsx19(
3879
4055
  "button",
3880
4056
  {
3881
4057
  className: `bulk-column-actions__key-btn ${majorityNK ? "bulk-column-actions__key-btn--active" : ""}`,
@@ -3884,8 +4060,8 @@ function BulkColumnActions({
3884
4060
  children: "NK"
3885
4061
  }
3886
4062
  ),
3887
- /* @__PURE__ */ jsx18("div", { className: "bulk-column-actions__divider" }),
3888
- showTypeSelect ? /* @__PURE__ */ jsx18(
4063
+ /* @__PURE__ */ jsx19("div", { className: "bulk-column-actions__divider" }),
4064
+ showTypeSelect ? /* @__PURE__ */ jsx19(
3889
4065
  DataTypeSelect,
3890
4066
  {
3891
4067
  value: "",
@@ -3894,7 +4070,7 @@ function BulkColumnActions({
3894
4070
  className: "bulk-column-actions__type-select",
3895
4071
  autoOpen: true
3896
4072
  }
3897
- ) : /* @__PURE__ */ jsx18(
4073
+ ) : /* @__PURE__ */ jsx19(
3898
4074
  "button",
3899
4075
  {
3900
4076
  className: "bulk-column-actions__btn",
@@ -3903,7 +4079,7 @@ function BulkColumnActions({
3903
4079
  children: "Set Type"
3904
4080
  }
3905
4081
  ),
3906
- /* @__PURE__ */ jsx18(
4082
+ /* @__PURE__ */ jsx19(
3907
4083
  "button",
3908
4084
  {
3909
4085
  className: "bulk-column-actions__btn bulk-column-actions__btn--clear",
@@ -3915,8 +4091,194 @@ function BulkColumnActions({
3915
4091
  ] });
3916
4092
  }
3917
4093
 
4094
+ // src/components/DetailPanel/MetaEditor.tsx
4095
+ import { useCallback as useCallback20, useEffect as useEffect13, useRef as useRef11, useState as useState17 } from "react";
4096
+ import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
4097
+ var hasKey = (meta, key) => !!meta && Object.prototype.hasOwnProperty.call(meta, key);
4098
+ function MetaEditor({ modelName, columnName, meta, readOnly, compact }) {
4099
+ const host = useCanvasHost();
4100
+ const viewer = useIsViewer();
4101
+ const editable = !readOnly && !viewer;
4102
+ const entries = Object.entries(meta ?? {});
4103
+ const [editingKey, setEditingKey] = useState17(null);
4104
+ const [editValue, setEditValue] = useState17("");
4105
+ const [adding, setAdding] = useState17(false);
4106
+ const [newKey, setNewKey] = useState17("");
4107
+ const [newValue, setNewValue] = useState17("");
4108
+ const [error, setError] = useState17(null);
4109
+ const savedRef = useRef11(false);
4110
+ useEffect13(() => {
4111
+ if (editingKey !== null && !hasKey(meta, editingKey)) setEditingKey(null);
4112
+ }, [meta, editingKey]);
4113
+ const post = useCallback20(
4114
+ (patch) => {
4115
+ host.postMessage({
4116
+ type: "updateMeta",
4117
+ payload: { modelName, ...columnName !== void 0 ? { columnName } : {}, ...patch }
4118
+ });
4119
+ },
4120
+ [host, modelName, columnName]
4121
+ );
4122
+ const startEdit = useCallback20((key, value) => {
4123
+ savedRef.current = false;
4124
+ setEditingKey(key);
4125
+ setEditValue(value);
4126
+ }, []);
4127
+ const saveValue = useCallback20(() => {
4128
+ if (editingKey === null || savedRef.current) return;
4129
+ savedRef.current = true;
4130
+ if (editValue !== meta?.[editingKey]) post({ set: { [editingKey]: editValue } });
4131
+ setEditingKey(null);
4132
+ }, [editingKey, editValue, meta, post]);
4133
+ const cancelEdit = useCallback20(() => {
4134
+ savedRef.current = true;
4135
+ setEditingKey(null);
4136
+ }, []);
4137
+ const saveNew = useCallback20(() => {
4138
+ const key = newKey.trim();
4139
+ if (!key) {
4140
+ setError("Key is required");
4141
+ return;
4142
+ }
4143
+ if (hasKey(meta, key)) {
4144
+ setError(`"${key}" already exists`);
4145
+ return;
4146
+ }
4147
+ post({ set: { [key]: newValue } });
4148
+ setAdding(false);
4149
+ setNewKey("");
4150
+ setNewValue("");
4151
+ setError(null);
4152
+ }, [newKey, newValue, meta, post]);
4153
+ const cancelNew = useCallback20(() => {
4154
+ setAdding(false);
4155
+ setNewKey("");
4156
+ setNewValue("");
4157
+ setError(null);
4158
+ }, []);
4159
+ if (entries.length === 0 && !editable) return null;
4160
+ const block = compact ? "meta-editor meta-editor--compact" : "meta-editor";
4161
+ return /* @__PURE__ */ jsxs17("div", { className: block, children: [
4162
+ !compact && /* @__PURE__ */ jsx20("h4", { className: "detail-panel__section-title meta-editor__title", children: "Metadata" }),
4163
+ compact && entries.length > 0 && /* @__PURE__ */ jsx20("span", { className: "meta-editor__label", children: "Metadata" }),
4164
+ entries.length > 0 && /* @__PURE__ */ jsx20("dl", { className: "meta-editor__list", children: entries.map(([key, value]) => {
4165
+ const text = typeof value === "string";
4166
+ const editingThis = editingKey === key;
4167
+ return /* @__PURE__ */ jsxs17("div", { className: "meta-editor__row", children: [
4168
+ /* @__PURE__ */ jsx20("dt", { className: "meta-editor__key", title: key, children: key }),
4169
+ /* @__PURE__ */ jsx20("dd", { className: "meta-editor__value", children: editingThis ? /* @__PURE__ */ jsx20(
4170
+ "input",
4171
+ {
4172
+ className: "meta-editor__input",
4173
+ value: editValue,
4174
+ onChange: (e) => setEditValue(e.target.value),
4175
+ onBlur: saveValue,
4176
+ onKeyDown: (e) => {
4177
+ if (e.key === "Enter") {
4178
+ e.preventDefault();
4179
+ saveValue();
4180
+ }
4181
+ if (e.key === "Escape") {
4182
+ e.preventDefault();
4183
+ cancelEdit();
4184
+ }
4185
+ },
4186
+ "aria-label": `Value of ${key}`,
4187
+ autoFocus: true
4188
+ }
4189
+ ) : /* @__PURE__ */ jsx20(
4190
+ "span",
4191
+ {
4192
+ className: `meta-editor__text${text ? "" : " meta-editor__text--structured"}`,
4193
+ title: editable && !text ? "Edit nested values in the model file" : formatMetaValue(value),
4194
+ onDoubleClick: editable && text ? () => startEdit(key, value) : void 0,
4195
+ children: formatMetaValue(value)
4196
+ }
4197
+ ) }),
4198
+ editable && !editingThis && /* @__PURE__ */ jsxs17("span", { className: "meta-editor__actions", children: [
4199
+ text && /* @__PURE__ */ jsx20(
4200
+ "button",
4201
+ {
4202
+ className: "meta-editor__icon-btn",
4203
+ onClick: () => startEdit(key, value),
4204
+ title: `Edit ${key}`,
4205
+ "aria-label": `Edit ${key}`,
4206
+ children: "\u270E"
4207
+ }
4208
+ ),
4209
+ /* @__PURE__ */ jsx20(
4210
+ "button",
4211
+ {
4212
+ className: "meta-editor__icon-btn",
4213
+ onClick: () => post({ remove: [key] }),
4214
+ title: `Remove ${key}`,
4215
+ "aria-label": `Remove ${key}`,
4216
+ children: "\xD7"
4217
+ }
4218
+ )
4219
+ ] })
4220
+ ] }, key);
4221
+ }) }),
4222
+ editable && (adding ? /* @__PURE__ */ jsxs17("div", { className: "meta-editor__new", children: [
4223
+ /* @__PURE__ */ jsx20(
4224
+ "input",
4225
+ {
4226
+ className: "meta-editor__input meta-editor__input--key",
4227
+ value: newKey,
4228
+ onChange: (e) => {
4229
+ setNewKey(e.target.value);
4230
+ setError(null);
4231
+ },
4232
+ onKeyDown: (e) => {
4233
+ if (e.key === "Escape") {
4234
+ e.preventDefault();
4235
+ cancelNew();
4236
+ }
4237
+ },
4238
+ placeholder: "key (e.g. owner)",
4239
+ "aria-label": "Metadata key",
4240
+ autoFocus: true
4241
+ }
4242
+ ),
4243
+ /* @__PURE__ */ jsx20(
4244
+ "input",
4245
+ {
4246
+ className: "meta-editor__input",
4247
+ value: newValue,
4248
+ onChange: (e) => setNewValue(e.target.value),
4249
+ onKeyDown: (e) => {
4250
+ if (e.key === "Enter") {
4251
+ e.preventDefault();
4252
+ saveNew();
4253
+ }
4254
+ if (e.key === "Escape") {
4255
+ e.preventDefault();
4256
+ cancelNew();
4257
+ }
4258
+ },
4259
+ placeholder: "value",
4260
+ "aria-label": "Metadata value"
4261
+ }
4262
+ ),
4263
+ /* @__PURE__ */ jsxs17("div", { className: "meta-editor__new-actions", children: [
4264
+ /* @__PURE__ */ jsx20("button", { className: "detail-panel__button", onClick: saveNew, children: "Add" }),
4265
+ /* @__PURE__ */ jsx20("button", { className: "detail-panel__button", onClick: cancelNew, children: "Cancel" })
4266
+ ] }),
4267
+ error && /* @__PURE__ */ jsx20("span", { className: "meta-editor__error", children: error })
4268
+ ] }) : /* @__PURE__ */ jsx20(
4269
+ "button",
4270
+ {
4271
+ className: "detail-panel__rationale-add-btn meta-editor__add-btn",
4272
+ onClick: () => setAdding(true),
4273
+ title: "Add structured metadata such as owner, source system or lineage",
4274
+ children: "+ Add Metadata"
4275
+ }
4276
+ ))
4277
+ ] });
4278
+ }
4279
+
3918
4280
  // src/components/DetailPanel/ColumnEditor.tsx
3919
- import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
4281
+ import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
3920
4282
  function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
3921
4283
  const send = useSend();
3922
4284
  const viewer = useIsViewer();
@@ -3926,14 +4288,14 @@ function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
3926
4288
  const toggleColumnSelection = useEditorStore((s) => s.toggleColumnSelection);
3927
4289
  const selectColumnRange = useEditorStore((s) => s.selectColumnRange);
3928
4290
  const clearColumnSelection = useEditorStore((s) => s.clearColumnSelection);
3929
- const [isAddingColumn, setIsAddingColumn] = useState16(false);
3930
- const [expandedColumns, setExpandedColumns] = useState16(/* @__PURE__ */ new Set());
4291
+ const [isAddingColumn, setIsAddingColumn] = useState18(false);
4292
+ const [expandedColumns, setExpandedColumns] = useState18(/* @__PURE__ */ new Set());
3931
4293
  const existingColumnNames = useMemo5(
3932
4294
  () => columns.map((c) => c.name),
3933
4295
  [columns]
3934
4296
  );
3935
4297
  const isEditable = !readOnly;
3936
- const handleReorder = useCallback19(
4298
+ const handleReorder = useCallback21(
3937
4299
  (orderedNames) => {
3938
4300
  send({
3939
4301
  type: "reorderColumns",
@@ -3946,11 +4308,11 @@ function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
3946
4308
  columns,
3947
4309
  onReorder: handleReorder
3948
4310
  });
3949
- const handleAddColumn = useCallback19(() => {
4311
+ const handleAddColumn = useCallback21(() => {
3950
4312
  if (isAddingColumn) return;
3951
4313
  setIsAddingColumn(true);
3952
4314
  }, [isAddingColumn]);
3953
- const handleColumnUpdate = useCallback19(
4315
+ const handleColumnUpdate = useCallback21(
3954
4316
  (oldName, updated, isNew) => {
3955
4317
  if (isNew) {
3956
4318
  const { scdType, additiveType, ...rest } = updated;
@@ -3973,7 +4335,7 @@ function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
3973
4335
  },
3974
4336
  [send, modelName]
3975
4337
  );
3976
- const handleColumnDelete = useCallback19(
4338
+ const handleColumnDelete = useCallback21(
3977
4339
  (columnName) => {
3978
4340
  send({
3979
4341
  type: "removeColumn",
@@ -3982,16 +4344,16 @@ function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
3982
4344
  },
3983
4345
  [send, modelName]
3984
4346
  );
3985
- const handleCancelNew = useCallback19(() => {
4347
+ const handleCancelNew = useCallback21(() => {
3986
4348
  setIsAddingColumn(false);
3987
4349
  }, []);
3988
- const handleExpandAll = useCallback19(() => {
4350
+ const handleExpandAll = useCallback21(() => {
3989
4351
  setExpandedColumns(new Set(columns.map((c) => c.name)));
3990
4352
  }, [columns]);
3991
- const handleCollapseAll = useCallback19(() => {
4353
+ const handleCollapseAll = useCallback21(() => {
3992
4354
  setExpandedColumns(/* @__PURE__ */ new Set());
3993
4355
  }, []);
3994
- const handleToggleExpand = useCallback19((columnName, opts) => {
4356
+ const handleToggleExpand = useCallback21((columnName, opts) => {
3995
4357
  if (opts?.altKey) {
3996
4358
  setExpandedColumns((prev) => prev.has(columnName) ? /* @__PURE__ */ new Set() : new Set(columns.map((c) => c.name)));
3997
4359
  } else {
@@ -4006,7 +4368,7 @@ function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
4006
4368
  });
4007
4369
  }
4008
4370
  }, [columns]);
4009
- useEffect12(() => {
4371
+ useEffect14(() => {
4010
4372
  const currentNames = new Set(columns.map((c) => c.name));
4011
4373
  const pruned = selectedColumns.filter((n) => currentNames.has(n));
4012
4374
  if (pruned.length !== selectedColumns.length) {
@@ -4017,7 +4379,7 @@ function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
4017
4379
  }
4018
4380
  }
4019
4381
  }, [columns, selectedColumns, clearColumnSelection]);
4020
- const handleColumnSelect = useCallback19(
4382
+ const handleColumnSelect = useCallback21(
4021
4383
  (columnName, e) => {
4022
4384
  const allNames = orderedColumns.map((c) => c.name);
4023
4385
  if (e.shiftKey) {
@@ -4030,7 +4392,7 @@ function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
4030
4392
  },
4031
4393
  [orderedColumns, selectColumn, toggleColumnSelection, selectColumnRange]
4032
4394
  );
4033
- const handleToggleKey = useCallback19(
4395
+ const handleToggleKey = useCallback21(
4034
4396
  (columnName, keyType, currentValue) => {
4035
4397
  send({
4036
4398
  type: "toggleColumnKey",
@@ -4054,16 +4416,16 @@ function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
4054
4416
  isForeignKey: false,
4055
4417
  isNaturalKey: false
4056
4418
  };
4057
- return /* @__PURE__ */ jsxs15("div", { className: "column-editor", children: [
4058
- /* @__PURE__ */ jsxs15("div", { className: "column-editor__header", children: [
4059
- /* @__PURE__ */ jsxs15("h4", { className: "column-editor__title", children: [
4419
+ return /* @__PURE__ */ jsxs18("div", { className: "column-editor", children: [
4420
+ /* @__PURE__ */ jsxs18("div", { className: "column-editor__header", children: [
4421
+ /* @__PURE__ */ jsxs18("h4", { className: "column-editor__title", children: [
4060
4422
  "Columns (",
4061
4423
  columns.length,
4062
4424
  ")"
4063
4425
  ] }),
4064
- /* @__PURE__ */ jsxs15("div", { className: "column-editor__header-actions", children: [
4065
- columns.length > 0 && /* @__PURE__ */ jsxs15("div", { className: "column-editor__expand-controls", children: [
4066
- !allExpanded && /* @__PURE__ */ jsx19(
4426
+ /* @__PURE__ */ jsxs18("div", { className: "column-editor__header-actions", children: [
4427
+ columns.length > 0 && /* @__PURE__ */ jsxs18("div", { className: "column-editor__expand-controls", children: [
4428
+ !allExpanded && /* @__PURE__ */ jsx21(
4067
4429
  "button",
4068
4430
  {
4069
4431
  className: "column-editor__expand-btn",
@@ -4073,7 +4435,7 @@ function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
4073
4435
  children: "\u229E"
4074
4436
  }
4075
4437
  ),
4076
- anyExpanded && /* @__PURE__ */ jsx19(
4438
+ anyExpanded && /* @__PURE__ */ jsx21(
4077
4439
  "button",
4078
4440
  {
4079
4441
  className: "column-editor__expand-btn",
@@ -4084,7 +4446,7 @@ function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
4084
4446
  }
4085
4447
  )
4086
4448
  ] }),
4087
- isEditable && /* @__PURE__ */ jsx19(
4449
+ isEditable && /* @__PURE__ */ jsx21(
4088
4450
  "button",
4089
4451
  {
4090
4452
  className: "column-editor__add-btn",
@@ -4096,7 +4458,7 @@ function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
4096
4458
  )
4097
4459
  ] })
4098
4460
  ] }),
4099
- isEditable && selectedColumns.length > 1 && /* @__PURE__ */ jsx19(
4461
+ isEditable && selectedColumns.length > 1 && /* @__PURE__ */ jsx21(
4100
4462
  BulkColumnActions,
4101
4463
  {
4102
4464
  modelName,
@@ -4105,9 +4467,9 @@ function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
4105
4467
  onClearSelection: clearColumnSelection
4106
4468
  }
4107
4469
  ),
4108
- /* @__PURE__ */ jsxs15("div", { className: "column-editor__list", children: [
4109
- columns.length === 0 && !isAddingColumn && /* @__PURE__ */ jsx19("div", { className: "column-editor__empty", children: "No columns" }),
4110
- orderedColumns.map((col, idx) => /* @__PURE__ */ jsx19(
4470
+ /* @__PURE__ */ jsxs18("div", { className: "column-editor__list", children: [
4471
+ columns.length === 0 && !isAddingColumn && /* @__PURE__ */ jsx21("div", { className: "column-editor__empty", children: "No columns" }),
4472
+ orderedColumns.map((col, idx) => /* @__PURE__ */ jsx21(
4111
4473
  ColumnRowEditor,
4112
4474
  {
4113
4475
  column: col,
@@ -4129,11 +4491,21 @@ function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
4129
4491
  isBeingDragged: dragIndex === idx,
4130
4492
  isSelected: selectedColumns.includes(col.name),
4131
4493
  onSelect: (e) => handleColumnSelect(col.name, e),
4132
- isEditingActive: editingColumn === col.name
4494
+ isEditingActive: editingColumn === col.name,
4495
+ metaSlot: /* @__PURE__ */ jsx21(
4496
+ MetaEditor,
4497
+ {
4498
+ modelName,
4499
+ columnName: col.name,
4500
+ meta: col.meta,
4501
+ readOnly: !isEditable,
4502
+ compact: true
4503
+ }
4504
+ )
4133
4505
  },
4134
4506
  col.name
4135
4507
  )),
4136
- isAddingColumn && /* @__PURE__ */ jsx19(
4508
+ isAddingColumn && /* @__PURE__ */ jsx21(
4137
4509
  ColumnRowEditor,
4138
4510
  {
4139
4511
  column: newColumnTemplate,
@@ -4151,7 +4523,7 @@ function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
4151
4523
  "__new__"
4152
4524
  )
4153
4525
  ] }),
4154
- isEditable && columns.length > 0 && /* @__PURE__ */ jsx19(
4526
+ isEditable && columns.length > 0 && /* @__PURE__ */ jsx21(
4155
4527
  "button",
4156
4528
  {
4157
4529
  className: "column-editor__add-btn column-editor__add-btn--bottom",
@@ -4165,7 +4537,7 @@ function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
4165
4537
  }
4166
4538
 
4167
4539
  // src/components/DetailPanel/DetailPanel.tsx
4168
- import { Fragment as Fragment4, jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
4540
+ import { Fragment as Fragment4, jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
4169
4541
  var SOURCE_NAME = {
4170
4542
  catalog: "warehouse catalog",
4171
4543
  yml: "your dbt .yml",
@@ -4197,62 +4569,66 @@ function DetailPanel() {
4197
4569
  const pendingDeleteConfirmation = useEditorStore((s) => s.pendingDeleteConfirmation);
4198
4570
  const setPendingDeleteConfirmation = useEditorStore((s) => s.setPendingDeleteConfirmation);
4199
4571
  const openEdgeContextMenu = useEditorStore((s) => s.openEdgeContextMenu);
4200
- const [confirmingDelete, setConfirmingDelete] = useState17(false);
4201
- const [editingName, setEditingName] = useState17(false);
4202
- const [nameValue, setNameValue] = useState17("");
4203
- const [nameError, setNameError] = useState17("");
4204
- useEffect13(() => {
4572
+ const [confirmingDelete, setConfirmingDelete] = useState19(false);
4573
+ const [editingName, setEditingName] = useState19(false);
4574
+ const [nameValue, setNameValue] = useState19("");
4575
+ const [nameError, setNameError] = useState19("");
4576
+ useEffect15(() => {
4205
4577
  if (pendingDeleteConfirmation && detailPanelOpen) {
4206
4578
  setConfirmingDelete(true);
4207
4579
  setPendingDeleteConfirmation(false);
4208
4580
  }
4209
4581
  }, [pendingDeleteConfirmation, detailPanelOpen, setPendingDeleteConfirmation]);
4210
- useEffect13(() => {
4582
+ useEffect15(() => {
4211
4583
  setEditingName(false);
4212
4584
  setNameValue("");
4213
4585
  setNameError("");
4214
4586
  }, [selectedNode]);
4215
- const handleClose = useCallback20(() => {
4587
+ const handleClose = useCallback22(() => {
4216
4588
  setDetailPanelOpen(false);
4217
4589
  selectNode(null);
4218
4590
  setConfirmingDelete(false);
4219
4591
  }, [setDetailPanelOpen, selectNode]);
4220
- const validateModelName = useCallback20(
4592
+ const validateModelName = useCallback22(
4221
4593
  (value) => {
4222
4594
  const trimmed = value.trim();
4223
4595
  if (!trimmed) return "Name cannot be empty";
4224
4596
  if (/\s/.test(trimmed)) return "Name cannot contain spaces";
4225
- if (!/^[a-z]/.test(trimmed)) return "Must start with a lowercase letter";
4226
- if (!/^[a-z][a-z0-9_]*$/.test(trimmed)) return "Only lowercase letters, numbers, and underscores";
4227
- if (domain && trimmed !== selectedNode && domain.models.some((m) => m.name === trimmed)) {
4597
+ if (!/^[A-Za-z]/.test(trimmed)) return "Must start with a letter";
4598
+ if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(trimmed)) return "Only letters, numbers, and underscores";
4599
+ const same = (name) => name.toLowerCase() === trimmed.toLowerCase();
4600
+ if (selectedNode && trimmed !== selectedNode && same(selectedNode)) {
4601
+ return "Only the upper/lower case differs \u2014 rename to another name first";
4602
+ }
4603
+ if (domain && trimmed !== selectedNode && domain.models.some((m) => same(m.name))) {
4228
4604
  return "A model with this name already exists";
4229
4605
  }
4230
- if (trimmed !== selectedNode && existingModels.some((m) => m.source === "logical" && m.name === trimmed)) {
4606
+ if (trimmed !== selectedNode && existingModels.some((m) => m.source === "logical" && same(m.name))) {
4231
4607
  return "A model with this name already exists in the model library";
4232
4608
  }
4233
4609
  return "";
4234
4610
  },
4235
4611
  [domain, selectedNode, existingModels]
4236
4612
  );
4237
- const handleStartRename = useCallback20(() => {
4613
+ const handleStartRename = useCallback22(() => {
4238
4614
  if (!selectedNode) return;
4239
4615
  setNameValue(selectedNode);
4240
4616
  setNameError("");
4241
4617
  setEditingName(true);
4242
4618
  }, [selectedNode]);
4243
- const handleCancelRename = useCallback20(() => {
4619
+ const handleCancelRename = useCallback22(() => {
4244
4620
  setEditingName(false);
4245
4621
  setNameValue("");
4246
4622
  setNameError("");
4247
4623
  }, []);
4248
- const handleNameChange = useCallback20(
4624
+ const handleNameChange = useCallback22(
4249
4625
  (value) => {
4250
4626
  setNameValue(value);
4251
4627
  setNameError(validateModelName(value));
4252
4628
  },
4253
4629
  [validateModelName]
4254
4630
  );
4255
- const handleSubmitRename = useCallback20(() => {
4631
+ const handleSubmitRename = useCallback22(() => {
4256
4632
  if (!selectedNode) return;
4257
4633
  const trimmed = nameValue.trim();
4258
4634
  if (!trimmed || trimmed === selectedNode) {
@@ -4273,7 +4649,7 @@ function DetailPanel() {
4273
4649
  setEditingName(false);
4274
4650
  setNameError("");
4275
4651
  }, [selectedNode, nameValue, host, selectNode, validateModelName]);
4276
- const handleDeleteModel = useCallback20(() => {
4652
+ const handleDeleteModel = useCallback22(() => {
4277
4653
  if (!selectedNode) return;
4278
4654
  host.postMessage({
4279
4655
  type: "removeModel",
@@ -4282,7 +4658,7 @@ function DetailPanel() {
4282
4658
  setConfirmingDelete(false);
4283
4659
  handleClose();
4284
4660
  }, [selectedNode, host, handleClose]);
4285
- const handleDeleteRelationship = useCallback20(
4661
+ const handleDeleteRelationship = useCallback22(
4286
4662
  (rel) => {
4287
4663
  host.postMessage({
4288
4664
  type: "removeRelationship",
@@ -4296,7 +4672,7 @@ function DetailPanel() {
4296
4672
  },
4297
4673
  [host]
4298
4674
  );
4299
- const handleRelationshipClick = useCallback20(
4675
+ const handleRelationshipClick = useCallback22(
4300
4676
  (x, y, rel) => {
4301
4677
  const edgeData = {
4302
4678
  fromModel: rel.fromModel,
@@ -4330,10 +4706,10 @@ function DetailPanel() {
4330
4706
  }
4331
4707
  const { outgoing, incoming } = relationships;
4332
4708
  const totalRelationships = outgoing.length + incoming.length;
4333
- return /* @__PURE__ */ jsxs16(Panel, { position: "top-right", className: "detail-panel", children: [
4334
- /* @__PURE__ */ jsxs16("div", { className: "detail-panel__header", children: [
4335
- editingName ? /* @__PURE__ */ jsxs16("div", { className: "detail-panel__title-edit", children: [
4336
- /* @__PURE__ */ jsx20(
4709
+ return /* @__PURE__ */ jsxs19(Panel, { position: "top-right", className: "detail-panel", children: [
4710
+ /* @__PURE__ */ jsxs19("div", { className: "detail-panel__header", children: [
4711
+ editingName ? /* @__PURE__ */ jsxs19("div", { className: "detail-panel__title-edit", children: [
4712
+ /* @__PURE__ */ jsx22(
4337
4713
  "input",
4338
4714
  {
4339
4715
  className: `detail-panel__title-input${nameError ? " detail-panel__title-input--error" : ""}`,
@@ -4359,8 +4735,8 @@ function DetailPanel() {
4359
4735
  spellCheck: false
4360
4736
  }
4361
4737
  ),
4362
- nameError && /* @__PURE__ */ jsx20("span", { className: "detail-panel__title-error", children: nameError })
4363
- ] }) : /* @__PURE__ */ jsx20(
4738
+ nameError && /* @__PURE__ */ jsx22("span", { className: "detail-panel__title-error", children: nameError })
4739
+ ] }) : /* @__PURE__ */ jsx22(
4364
4740
  "h3",
4365
4741
  {
4366
4742
  className: `detail-panel__title${!isReadOnly ? " detail-panel__title--editable" : ""}`,
@@ -4369,7 +4745,7 @@ function DetailPanel() {
4369
4745
  children: model.name
4370
4746
  }
4371
4747
  ),
4372
- !isReadOnly && !editingName && /* @__PURE__ */ jsx20(
4748
+ !isReadOnly && !editingName && /* @__PURE__ */ jsx22(
4373
4749
  "button",
4374
4750
  {
4375
4751
  className: "detail-panel__title-edit-btn",
@@ -4379,7 +4755,7 @@ function DetailPanel() {
4379
4755
  children: "\u270E"
4380
4756
  }
4381
4757
  ),
4382
- /* @__PURE__ */ jsx20(
4758
+ /* @__PURE__ */ jsx22(
4383
4759
  "button",
4384
4760
  {
4385
4761
  className: "detail-panel__close",
@@ -4390,25 +4766,27 @@ function DetailPanel() {
4390
4766
  }
4391
4767
  )
4392
4768
  ] }),
4393
- /* @__PURE__ */ jsxs16("div", { className: "detail-panel__section", children: [
4394
- /* @__PURE__ */ jsxs16("div", { className: "detail-panel__metadata", children: [
4395
- /* @__PURE__ */ jsxs16("div", { className: "detail-panel__metadata-row", children: [
4396
- /* @__PURE__ */ jsx20("span", { className: "detail-panel__label", children: "Schema" }),
4397
- /* @__PURE__ */ jsx20("span", { className: "detail-panel__value", children: model.schema || "\u2014" })
4769
+ /* @__PURE__ */ jsxs19("div", { className: "detail-panel__section", children: [
4770
+ /* @__PURE__ */ jsxs19("div", { className: "detail-panel__metadata", children: [
4771
+ /* @__PURE__ */ jsxs19("div", { className: "detail-panel__metadata-row", children: [
4772
+ /* @__PURE__ */ jsx22("span", { className: "detail-panel__label detail-panel__label--wide", children: "Schema" }),
4773
+ /* @__PURE__ */ jsx22("span", { className: "detail-panel__value", children: model.schema || "\u2014" })
4398
4774
  ] }),
4399
- model.provenance && /* @__PURE__ */ jsxs16("div", { className: "detail-panel__metadata-row", children: [
4400
- /* @__PURE__ */ jsx20("span", { className: "detail-panel__label detail-panel__label--wide", children: "Columns from" }),
4401
- /* @__PURE__ */ jsx20("span", { className: "detail-panel__value detail-panel__value--provenance", children: describeProvenance(
4775
+ /* @__PURE__ */ jsx22(AliasEditor, { modelName: model.name, alias: model.alias, readOnly: isReadOnly || viewer }),
4776
+ model.provenance && /* @__PURE__ */ jsxs19("div", { className: "detail-panel__metadata-row", children: [
4777
+ /* @__PURE__ */ jsx22("span", { className: "detail-panel__label detail-panel__label--wide", children: "Columns from" }),
4778
+ /* @__PURE__ */ jsx22("span", { className: "detail-panel__value detail-panel__value--provenance", children: describeProvenance(
4402
4779
  model.provenance,
4403
4780
  model.columns.filter((c) => !c.dataType).length
4404
4781
  ) })
4405
4782
  ] })
4406
4783
  ] }),
4407
- isReadOnly ? model.description && /* @__PURE__ */ jsx20("p", { className: "detail-panel__description", children: model.description }) : /* @__PURE__ */ jsx20(DescriptionEditor, { modelName: model.name, description: model.description })
4784
+ isReadOnly ? model.description && /* @__PURE__ */ jsx22("p", { className: "detail-panel__description", children: model.description }) : /* @__PURE__ */ jsx22(DescriptionEditor, { modelName: model.name, description: model.description })
4408
4785
  ] }),
4409
- !isReadOnly && /* @__PURE__ */ jsx20("div", { className: "detail-panel__section", children: /* @__PURE__ */ jsx20(RoleEditor, { modelName: model.name, modelRole: model.modelRole }) }),
4410
- !isReadOnly && /* @__PURE__ */ jsx20("div", { className: "detail-panel__section", children: /* @__PURE__ */ jsx20(GrainEditor, { modelName: model.name, grain: model.grain }) }),
4411
- (!viewer || hasRationaleContent(model.rationale)) && /* @__PURE__ */ jsx20("div", { className: "detail-panel__section", children: /* @__PURE__ */ jsx20(
4786
+ !isReadOnly && /* @__PURE__ */ jsx22("div", { className: "detail-panel__section", children: /* @__PURE__ */ jsx22(RoleEditor, { modelName: model.name, modelRole: model.modelRole }) }),
4787
+ !isReadOnly && /* @__PURE__ */ jsx22("div", { className: "detail-panel__section", children: /* @__PURE__ */ jsx22(GrainEditor, { modelName: model.name, grain: model.grain }) }),
4788
+ (!isReadOnly && !viewer || model.meta && Object.keys(model.meta).length > 0) && /* @__PURE__ */ jsx22("div", { className: "detail-panel__section", children: /* @__PURE__ */ jsx22(MetaEditor, { modelName: model.name, meta: model.meta, readOnly: isReadOnly }) }),
4789
+ (!viewer || hasRationaleContent(model.rationale)) && /* @__PURE__ */ jsx22("div", { className: "detail-panel__section", children: /* @__PURE__ */ jsx22(
4412
4790
  ModelRationale,
4413
4791
  {
4414
4792
  modelName: model.name,
@@ -4417,13 +4795,13 @@ function DetailPanel() {
4417
4795
  grain: model.grain
4418
4796
  }
4419
4797
  ) }),
4420
- !isReadOnly && /* @__PURE__ */ jsx20("div", { className: "detail-panel__section detail-panel__section--actions", children: confirmingDelete ? /* @__PURE__ */ jsxs16(Fragment4, { children: [
4421
- /* @__PURE__ */ jsxs16("span", { className: "detail-panel__confirm-label", children: [
4798
+ !isReadOnly && /* @__PURE__ */ jsx22("div", { className: "detail-panel__section detail-panel__section--actions", children: confirmingDelete ? /* @__PURE__ */ jsxs19(Fragment4, { children: [
4799
+ /* @__PURE__ */ jsxs19("span", { className: "detail-panel__confirm-label", children: [
4422
4800
  "Remove model from domain?",
4423
4801
  totalRelationships > 0 ? ` (${totalRelationships} relationship(s) will also be removed)` : ""
4424
4802
  ] }),
4425
- /* @__PURE__ */ jsxs16("div", { className: "detail-panel__confirm-actions", children: [
4426
- /* @__PURE__ */ jsx20(
4803
+ /* @__PURE__ */ jsxs19("div", { className: "detail-panel__confirm-actions", children: [
4804
+ /* @__PURE__ */ jsx22(
4427
4805
  "button",
4428
4806
  {
4429
4807
  className: "detail-panel__button detail-panel__button--danger",
@@ -4432,7 +4810,7 @@ function DetailPanel() {
4432
4810
  children: "Yes, Remove"
4433
4811
  }
4434
4812
  ),
4435
- /* @__PURE__ */ jsx20(
4813
+ /* @__PURE__ */ jsx22(
4436
4814
  "button",
4437
4815
  {
4438
4816
  className: "detail-panel__button",
@@ -4442,7 +4820,7 @@ function DetailPanel() {
4442
4820
  }
4443
4821
  )
4444
4822
  ] })
4445
- ] }) : /* @__PURE__ */ jsx20(
4823
+ ] }) : /* @__PURE__ */ jsx22(
4446
4824
  "button",
4447
4825
  {
4448
4826
  className: "detail-panel__button detail-panel__button--danger",
@@ -4452,7 +4830,7 @@ function DetailPanel() {
4452
4830
  children: "Remove from Domain"
4453
4831
  }
4454
4832
  ) }),
4455
- /* @__PURE__ */ jsx20("div", { className: "detail-panel__section", children: /* @__PURE__ */ jsx20(
4833
+ /* @__PURE__ */ jsx22("div", { className: "detail-panel__section", children: /* @__PURE__ */ jsx22(
4456
4834
  ColumnEditor,
4457
4835
  {
4458
4836
  modelName: model.name,
@@ -4461,14 +4839,14 @@ function DetailPanel() {
4461
4839
  modelRole: model.modelRole
4462
4840
  }
4463
4841
  ) }),
4464
- totalRelationships > 0 && /* @__PURE__ */ jsxs16("div", { className: "detail-panel__section", children: [
4465
- /* @__PURE__ */ jsxs16("h4", { className: "detail-panel__section-title", children: [
4842
+ totalRelationships > 0 && /* @__PURE__ */ jsxs19("div", { className: "detail-panel__section", children: [
4843
+ /* @__PURE__ */ jsxs19("h4", { className: "detail-panel__section-title", children: [
4466
4844
  "Relationships (",
4467
4845
  totalRelationships,
4468
4846
  ")"
4469
4847
  ] }),
4470
- /* @__PURE__ */ jsxs16("div", { className: "detail-panel__relationships", children: [
4471
- outgoing.map((rel) => /* @__PURE__ */ jsxs16(
4848
+ /* @__PURE__ */ jsxs19("div", { className: "detail-panel__relationships", children: [
4849
+ outgoing.map((rel) => /* @__PURE__ */ jsxs19(
4472
4850
  "div",
4473
4851
  {
4474
4852
  className: viewer ? "detail-panel__relationship" : "detail-panel__relationship detail-panel__relationship--clickable",
@@ -4484,18 +4862,18 @@ function DetailPanel() {
4484
4862
  },
4485
4863
  title: viewer ? void 0 : "Click to edit cardinality",
4486
4864
  children: [
4487
- /* @__PURE__ */ jsx20("span", { className: "detail-panel__rel-direction", title: "Outgoing FK", children: "\u2192" }),
4488
- /* @__PURE__ */ jsxs16("span", { className: "detail-panel__rel-columns", children: [
4489
- /* @__PURE__ */ jsx20("span", { className: "detail-panel__rel-local", title: rel.fromColumn, children: rel.fromColumn }),
4490
- /* @__PURE__ */ jsx20("span", { className: "detail-panel__rel-arrow", children: "\u2192" }),
4491
- /* @__PURE__ */ jsxs16("span", { className: "detail-panel__rel-target", title: `${rel.toModel}.${rel.toColumn}`, children: [
4865
+ /* @__PURE__ */ jsx22("span", { className: "detail-panel__rel-direction", title: "Outgoing FK", children: "\u2192" }),
4866
+ /* @__PURE__ */ jsxs19("span", { className: "detail-panel__rel-columns", children: [
4867
+ /* @__PURE__ */ jsx22("span", { className: "detail-panel__rel-local", title: rel.fromColumn, children: rel.fromColumn }),
4868
+ /* @__PURE__ */ jsx22("span", { className: "detail-panel__rel-arrow", children: "\u2192" }),
4869
+ /* @__PURE__ */ jsxs19("span", { className: "detail-panel__rel-target", title: `${rel.toModel}.${rel.toColumn}`, children: [
4492
4870
  rel.toModel,
4493
4871
  ".",
4494
4872
  rel.toColumn
4495
4873
  ] })
4496
4874
  ] }),
4497
- /* @__PURE__ */ jsx20("span", { className: "detail-panel__rel-cardinality", children: rel.cardinality }),
4498
- !isReadOnly && /* @__PURE__ */ jsx20(
4875
+ /* @__PURE__ */ jsx22("span", { className: "detail-panel__rel-cardinality", children: rel.cardinality }),
4876
+ !isReadOnly && /* @__PURE__ */ jsx22(
4499
4877
  "button",
4500
4878
  {
4501
4879
  className: "detail-panel__rel-delete",
@@ -4512,7 +4890,7 @@ function DetailPanel() {
4512
4890
  },
4513
4891
  `out-${rel.fromColumn}-${rel.toModel}-${rel.toColumn}`
4514
4892
  )),
4515
- incoming.map((rel) => /* @__PURE__ */ jsxs16(
4893
+ incoming.map((rel) => /* @__PURE__ */ jsxs19(
4516
4894
  "div",
4517
4895
  {
4518
4896
  className: viewer ? "detail-panel__relationship" : "detail-panel__relationship detail-panel__relationship--clickable",
@@ -4528,18 +4906,18 @@ function DetailPanel() {
4528
4906
  },
4529
4907
  title: viewer ? void 0 : "Click to edit cardinality",
4530
4908
  children: [
4531
- /* @__PURE__ */ jsx20("span", { className: "detail-panel__rel-direction", title: "Incoming FK", children: "\u2190" }),
4532
- /* @__PURE__ */ jsxs16("span", { className: "detail-panel__rel-columns", children: [
4533
- /* @__PURE__ */ jsxs16("span", { className: "detail-panel__rel-target", title: `${rel.fromModel}.${rel.fromColumn}`, children: [
4909
+ /* @__PURE__ */ jsx22("span", { className: "detail-panel__rel-direction", title: "Incoming FK", children: "\u2190" }),
4910
+ /* @__PURE__ */ jsxs19("span", { className: "detail-panel__rel-columns", children: [
4911
+ /* @__PURE__ */ jsxs19("span", { className: "detail-panel__rel-target", title: `${rel.fromModel}.${rel.fromColumn}`, children: [
4534
4912
  rel.fromModel,
4535
4913
  ".",
4536
4914
  rel.fromColumn
4537
4915
  ] }),
4538
- /* @__PURE__ */ jsx20("span", { className: "detail-panel__rel-arrow", children: "\u2192" }),
4539
- /* @__PURE__ */ jsx20("span", { className: "detail-panel__rel-local", title: rel.toColumn, children: rel.toColumn })
4916
+ /* @__PURE__ */ jsx22("span", { className: "detail-panel__rel-arrow", children: "\u2192" }),
4917
+ /* @__PURE__ */ jsx22("span", { className: "detail-panel__rel-local", title: rel.toColumn, children: rel.toColumn })
4540
4918
  ] }),
4541
- /* @__PURE__ */ jsx20("span", { className: "detail-panel__rel-cardinality", children: rel.cardinality }),
4542
- !isReadOnly && /* @__PURE__ */ jsx20(
4919
+ /* @__PURE__ */ jsx22("span", { className: "detail-panel__rel-cardinality", children: rel.cardinality }),
4920
+ !isReadOnly && /* @__PURE__ */ jsx22(
4543
4921
  "button",
4544
4922
  {
4545
4923
  className: "detail-panel__rel-delete",
@@ -4562,20 +4940,20 @@ function DetailPanel() {
4562
4940
  }
4563
4941
 
4564
4942
  // src/components/Legend/Legend.tsx
4565
- import { useCallback as useCallback21 } from "react";
4943
+ import { useCallback as useCallback23 } from "react";
4566
4944
  import { Panel as Panel2 } from "@xyflow/react";
4567
- import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
4945
+ import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
4568
4946
  function Legend() {
4569
4947
  const legendOpen = useEditorStore((s) => s.legendOpen);
4570
4948
  const setLegendOpen = useEditorStore((s) => s.setLegendOpen);
4571
- const handleToggle = useCallback21(() => {
4949
+ const handleToggle = useCallback23(() => {
4572
4950
  setLegendOpen(!legendOpen);
4573
4951
  }, [legendOpen, setLegendOpen]);
4574
- const handleClose = useCallback21(() => {
4952
+ const handleClose = useCallback23(() => {
4575
4953
  setLegendOpen(false);
4576
4954
  }, [setLegendOpen]);
4577
4955
  if (!legendOpen) {
4578
- return /* @__PURE__ */ jsx21(Panel2, { position: "bottom-left", className: "legend-toggle", children: /* @__PURE__ */ jsx21(
4956
+ return /* @__PURE__ */ jsx23(Panel2, { position: "bottom-left", className: "legend-toggle", children: /* @__PURE__ */ jsx23(
4579
4957
  "button",
4580
4958
  {
4581
4959
  className: "legend-toggle__button",
@@ -4586,10 +4964,10 @@ function Legend() {
4586
4964
  }
4587
4965
  ) });
4588
4966
  }
4589
- return /* @__PURE__ */ jsxs17(Panel2, { position: "bottom-left", className: "legend", children: [
4590
- /* @__PURE__ */ jsxs17("div", { className: "legend__header", children: [
4591
- /* @__PURE__ */ jsx21("span", { className: "legend__title", children: "Legend" }),
4592
- /* @__PURE__ */ jsx21(
4967
+ return /* @__PURE__ */ jsxs20(Panel2, { position: "bottom-left", className: "legend", children: [
4968
+ /* @__PURE__ */ jsxs20("div", { className: "legend__header", children: [
4969
+ /* @__PURE__ */ jsx23("span", { className: "legend__title", children: "Legend" }),
4970
+ /* @__PURE__ */ jsx23(
4593
4971
  "button",
4594
4972
  {
4595
4973
  className: "legend__close",
@@ -4600,183 +4978,183 @@ function Legend() {
4600
4978
  }
4601
4979
  )
4602
4980
  ] }),
4603
- /* @__PURE__ */ jsxs17("div", { className: "legend__content", children: [
4604
- /* @__PURE__ */ jsxs17("section", { className: "legend__section", children: [
4605
- /* @__PURE__ */ jsx21("h3", { className: "legend__section-title", children: "Design Stages" }),
4606
- /* @__PURE__ */ jsxs17("div", { className: "legend__items", children: [
4607
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4608
- /* @__PURE__ */ jsx21("div", { className: "legend__model-card legend__model-card--logical", children: /* @__PURE__ */ jsx21("div", { className: "legend__model-header legend__model-header--logical" }) }),
4609
- /* @__PURE__ */ jsxs17("div", { className: "legend__item-text", children: [
4610
- /* @__PURE__ */ jsx21("span", { className: "legend__item-label", children: "Logical" }),
4611
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Your data model design" })
4981
+ /* @__PURE__ */ jsxs20("div", { className: "legend__content", children: [
4982
+ /* @__PURE__ */ jsxs20("section", { className: "legend__section", children: [
4983
+ /* @__PURE__ */ jsx23("h3", { className: "legend__section-title", children: "Design Stages" }),
4984
+ /* @__PURE__ */ jsxs20("div", { className: "legend__items", children: [
4985
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
4986
+ /* @__PURE__ */ jsx23("div", { className: "legend__model-card legend__model-card--logical", children: /* @__PURE__ */ jsx23("div", { className: "legend__model-header legend__model-header--logical" }) }),
4987
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item-text", children: [
4988
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-label", children: "Logical" }),
4989
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Your data model design" })
4612
4990
  ] })
4613
4991
  ] }),
4614
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4615
- /* @__PURE__ */ jsx21("div", { className: "legend__model-card legend__model-card--physical", children: /* @__PURE__ */ jsx21("div", { className: "legend__model-header legend__model-header--physical" }) }),
4616
- /* @__PURE__ */ jsxs17("div", { className: "legend__item-text", children: [
4617
- /* @__PURE__ */ jsx21("span", { className: "legend__item-label", children: "Physical" }),
4618
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Declared in dbt .yml files (read-only)" })
4992
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
4993
+ /* @__PURE__ */ jsx23("div", { className: "legend__model-card legend__model-card--physical", children: /* @__PURE__ */ jsx23("div", { className: "legend__model-header legend__model-header--physical" }) }),
4994
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item-text", children: [
4995
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-label", children: "Physical" }),
4996
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Declared in dbt .yml files (read-only)" })
4619
4997
  ] })
4620
4998
  ] }),
4621
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4622
- /* @__PURE__ */ jsx21("div", { className: "legend__model-card legend__model-card--ghost", children: /* @__PURE__ */ jsx21("div", { className: "legend__model-header legend__model-header--ghost" }) }),
4623
- /* @__PURE__ */ jsxs17("div", { className: "legend__item-text", children: [
4624
- /* @__PURE__ */ jsx21("span", { className: "legend__item-label", children: "Ghost" }),
4625
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Not found in your dbt project" })
4999
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5000
+ /* @__PURE__ */ jsx23("div", { className: "legend__model-card legend__model-card--ghost", children: /* @__PURE__ */ jsx23("div", { className: "legend__model-header legend__model-header--ghost" }) }),
5001
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item-text", children: [
5002
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-label", children: "Ghost" }),
5003
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Not found in your dbt project" })
4626
5004
  ] })
4627
5005
  ] }),
4628
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4629
- /* @__PURE__ */ jsx21("div", { className: "legend__model-card legend__model-card--ghost legend__model-card--ghost-disabled", children: /* @__PURE__ */ jsx21("div", { className: "legend__model-header legend__model-header--ghost" }) }),
4630
- /* @__PURE__ */ jsxs17("div", { className: "legend__item-text", children: [
4631
- /* @__PURE__ */ jsx21("span", { className: "legend__item-label", children: "Ghost, dotted" }),
4632
- /* @__PURE__ */ jsxs17("span", { className: "legend__item-desc", children: [
5006
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5007
+ /* @__PURE__ */ jsx23("div", { className: "legend__model-card legend__model-card--ghost legend__model-card--ghost-disabled", children: /* @__PURE__ */ jsx23("div", { className: "legend__model-header legend__model-header--ghost" }) }),
5008
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item-text", children: [
5009
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-label", children: "Ghost, dotted" }),
5010
+ /* @__PURE__ */ jsxs20("span", { className: "legend__item-desc", children: [
4633
5011
  "Disabled in dbt \u2014 ",
4634
- /* @__PURE__ */ jsx21("code", { children: "ref()" }),
5012
+ /* @__PURE__ */ jsx23("code", { children: "ref()" }),
4635
5013
  " to it will not compile"
4636
5014
  ] })
4637
5015
  ] })
4638
5016
  ] })
4639
5017
  ] })
4640
5018
  ] }),
4641
- /* @__PURE__ */ jsxs17("section", { className: "legend__section", children: [
4642
- /* @__PURE__ */ jsx21("h3", { className: "legend__section-title", children: "Annotations" }),
4643
- /* @__PURE__ */ jsxs17("div", { className: "legend__items", children: [
4644
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4645
- /* @__PURE__ */ jsx21("div", { className: "legend__annotation-card" }),
4646
- /* @__PURE__ */ jsxs17("div", { className: "legend__item-text", children: [
4647
- /* @__PURE__ */ jsx21("span", { className: "legend__item-label", children: "Build Note" }),
4648
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Temporary note on canvas" })
5019
+ /* @__PURE__ */ jsxs20("section", { className: "legend__section", children: [
5020
+ /* @__PURE__ */ jsx23("h3", { className: "legend__section-title", children: "Annotations" }),
5021
+ /* @__PURE__ */ jsxs20("div", { className: "legend__items", children: [
5022
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5023
+ /* @__PURE__ */ jsx23("div", { className: "legend__annotation-card" }),
5024
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item-text", children: [
5025
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-label", children: "Build Note" }),
5026
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Temporary note on canvas" })
4649
5027
  ] })
4650
5028
  ] }),
4651
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4652
- /* @__PURE__ */ jsx21("svg", { className: "legend__edge-sample", viewBox: "0 0 48 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx21("line", { x1: "0", y1: "4", x2: "48", y2: "4", className: "legend__edge legend__edge--annotation" }) }),
4653
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Note linked to model" })
5029
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5030
+ /* @__PURE__ */ jsx23("svg", { className: "legend__edge-sample", viewBox: "0 0 48 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx23("line", { x1: "0", y1: "4", x2: "48", y2: "4", className: "legend__edge legend__edge--annotation" }) }),
5031
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Note linked to model" })
4654
5032
  ] })
4655
5033
  ] })
4656
5034
  ] }),
4657
- /* @__PURE__ */ jsxs17("section", { className: "legend__section", children: [
4658
- /* @__PURE__ */ jsx21("h3", { className: "legend__section-title", children: "Cardinality" }),
4659
- /* @__PURE__ */ jsxs17("div", { className: "legend__items legend__items--cardinality", children: [
4660
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4661
- /* @__PURE__ */ jsxs17("div", { className: "legend__cardinality", children: [
4662
- /* @__PURE__ */ jsx21("span", { className: "legend__cardinality-label legend__cardinality-label--many", children: "*" }),
4663
- /* @__PURE__ */ jsx21("svg", { className: "legend__cardinality-line", viewBox: "0 0 32 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx21("line", { x1: "0", y1: "4", x2: "32", y2: "4", className: "legend__edge legend__edge--logical" }) }),
4664
- /* @__PURE__ */ jsx21("span", { className: "legend__cardinality-label", children: "1" })
5035
+ /* @__PURE__ */ jsxs20("section", { className: "legend__section", children: [
5036
+ /* @__PURE__ */ jsx23("h3", { className: "legend__section-title", children: "Cardinality" }),
5037
+ /* @__PURE__ */ jsxs20("div", { className: "legend__items legend__items--cardinality", children: [
5038
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5039
+ /* @__PURE__ */ jsxs20("div", { className: "legend__cardinality", children: [
5040
+ /* @__PURE__ */ jsx23("span", { className: "legend__cardinality-label legend__cardinality-label--many", children: "*" }),
5041
+ /* @__PURE__ */ jsx23("svg", { className: "legend__cardinality-line", viewBox: "0 0 32 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx23("line", { x1: "0", y1: "4", x2: "32", y2: "4", className: "legend__edge legend__edge--logical" }) }),
5042
+ /* @__PURE__ */ jsx23("span", { className: "legend__cardinality-label", children: "1" })
4665
5043
  ] }),
4666
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Many-to-one" })
5044
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Many-to-one" })
4667
5045
  ] }),
4668
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4669
- /* @__PURE__ */ jsxs17("div", { className: "legend__cardinality", children: [
4670
- /* @__PURE__ */ jsx21("span", { className: "legend__cardinality-label", children: "1" }),
4671
- /* @__PURE__ */ jsx21("svg", { className: "legend__cardinality-line", viewBox: "0 0 32 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx21("line", { x1: "0", y1: "4", x2: "32", y2: "4", className: "legend__edge legend__edge--logical" }) }),
4672
- /* @__PURE__ */ jsx21("span", { className: "legend__cardinality-label", children: "1" })
5046
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5047
+ /* @__PURE__ */ jsxs20("div", { className: "legend__cardinality", children: [
5048
+ /* @__PURE__ */ jsx23("span", { className: "legend__cardinality-label", children: "1" }),
5049
+ /* @__PURE__ */ jsx23("svg", { className: "legend__cardinality-line", viewBox: "0 0 32 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx23("line", { x1: "0", y1: "4", x2: "32", y2: "4", className: "legend__edge legend__edge--logical" }) }),
5050
+ /* @__PURE__ */ jsx23("span", { className: "legend__cardinality-label", children: "1" })
4673
5051
  ] }),
4674
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "One-to-one" })
5052
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "One-to-one" })
4675
5053
  ] }),
4676
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4677
- /* @__PURE__ */ jsxs17("div", { className: "legend__cardinality", children: [
4678
- /* @__PURE__ */ jsx21("span", { className: "legend__cardinality-label", children: "1" }),
4679
- /* @__PURE__ */ jsx21("svg", { className: "legend__cardinality-line", viewBox: "0 0 32 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx21("line", { x1: "0", y1: "4", x2: "32", y2: "4", className: "legend__edge legend__edge--logical" }) }),
4680
- /* @__PURE__ */ jsx21("span", { className: "legend__cardinality-label legend__cardinality-label--many", children: "*" })
5054
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5055
+ /* @__PURE__ */ jsxs20("div", { className: "legend__cardinality", children: [
5056
+ /* @__PURE__ */ jsx23("span", { className: "legend__cardinality-label", children: "1" }),
5057
+ /* @__PURE__ */ jsx23("svg", { className: "legend__cardinality-line", viewBox: "0 0 32 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx23("line", { x1: "0", y1: "4", x2: "32", y2: "4", className: "legend__edge legend__edge--logical" }) }),
5058
+ /* @__PURE__ */ jsx23("span", { className: "legend__cardinality-label legend__cardinality-label--many", children: "*" })
4681
5059
  ] }),
4682
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "One-to-many" })
5060
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "One-to-many" })
4683
5061
  ] }),
4684
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4685
- /* @__PURE__ */ jsxs17("div", { className: "legend__cardinality", children: [
4686
- /* @__PURE__ */ jsx21("span", { className: "legend__cardinality-label legend__cardinality-label--many", children: "*" }),
4687
- /* @__PURE__ */ jsx21("svg", { className: "legend__cardinality-line", viewBox: "0 0 32 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx21("line", { x1: "0", y1: "4", x2: "32", y2: "4", className: "legend__edge legend__edge--logical" }) }),
4688
- /* @__PURE__ */ jsx21("span", { className: "legend__cardinality-label legend__cardinality-label--many", children: "*" })
5062
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5063
+ /* @__PURE__ */ jsxs20("div", { className: "legend__cardinality", children: [
5064
+ /* @__PURE__ */ jsx23("span", { className: "legend__cardinality-label legend__cardinality-label--many", children: "*" }),
5065
+ /* @__PURE__ */ jsx23("svg", { className: "legend__cardinality-line", viewBox: "0 0 32 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx23("line", { x1: "0", y1: "4", x2: "32", y2: "4", className: "legend__edge legend__edge--logical" }) }),
5066
+ /* @__PURE__ */ jsx23("span", { className: "legend__cardinality-label legend__cardinality-label--many", children: "*" })
4689
5067
  ] }),
4690
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Many-to-many" })
5068
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Many-to-many" })
4691
5069
  ] })
4692
5070
  ] }),
4693
- /* @__PURE__ */ jsx21("h4", { className: "legend__subsection-title", children: "Line colour follows the stage" }),
4694
- /* @__PURE__ */ jsxs17("div", { className: "legend__items legend__items--disc-edges", children: [
4695
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4696
- /* @__PURE__ */ jsx21("svg", { className: "legend__edge-sample", viewBox: "0 0 48 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx21("line", { x1: "0", y1: "4", x2: "48", y2: "4", className: "legend__edge legend__edge--logical" }) }),
4697
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Logical" })
5071
+ /* @__PURE__ */ jsx23("h4", { className: "legend__subsection-title", children: "Line colour follows the stage" }),
5072
+ /* @__PURE__ */ jsxs20("div", { className: "legend__items legend__items--disc-edges", children: [
5073
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5074
+ /* @__PURE__ */ jsx23("svg", { className: "legend__edge-sample", viewBox: "0 0 48 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx23("line", { x1: "0", y1: "4", x2: "48", y2: "4", className: "legend__edge legend__edge--logical" }) }),
5075
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Logical" })
4698
5076
  ] }),
4699
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4700
- /* @__PURE__ */ jsx21("svg", { className: "legend__edge-sample", viewBox: "0 0 48 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx21("line", { x1: "0", y1: "4", x2: "48", y2: "4", className: "legend__edge legend__edge--physical" }) }),
4701
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Physical" })
5077
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5078
+ /* @__PURE__ */ jsx23("svg", { className: "legend__edge-sample", viewBox: "0 0 48 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx23("line", { x1: "0", y1: "4", x2: "48", y2: "4", className: "legend__edge legend__edge--physical" }) }),
5079
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Physical" })
4702
5080
  ] })
4703
5081
  ] })
4704
5082
  ] }),
4705
- /* @__PURE__ */ jsxs17("section", { className: "legend__section", children: [
4706
- /* @__PURE__ */ jsx21("h3", { className: "legend__section-title", children: "Header Badges" }),
4707
- /* @__PURE__ */ jsx21("div", { className: "legend__items", children: /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4708
- /* @__PURE__ */ jsx21("span", { className: "legend__badge legend__badge--schema", children: "SLV" }),
4709
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Database schema, or the layer when dbt has not resolved one" })
5083
+ /* @__PURE__ */ jsxs20("section", { className: "legend__section", children: [
5084
+ /* @__PURE__ */ jsx23("h3", { className: "legend__section-title", children: "Header Badges" }),
5085
+ /* @__PURE__ */ jsx23("div", { className: "legend__items", children: /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5086
+ /* @__PURE__ */ jsx23("span", { className: "legend__badge legend__badge--schema", children: "SLV" }),
5087
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Database schema, or the layer when dbt has not resolved one" })
4710
5088
  ] }) }),
4711
- /* @__PURE__ */ jsx21("h4", { className: "legend__subsection-title", children: "Where the shape came from (Physical)" }),
4712
- /* @__PURE__ */ jsx21("div", { className: "legend__items legend__items--sources", children: SOURCE_ORDER.map((source) => /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4713
- /* @__PURE__ */ jsx21("span", { className: `legend__badge legend__badge--source legend__badge--source-${source}`, children: SOURCE_LABEL[source] }),
4714
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: SOURCE_LEGEND_DESC[source] })
5089
+ /* @__PURE__ */ jsx23("h4", { className: "legend__subsection-title", children: "Where the shape came from (Physical)" }),
5090
+ /* @__PURE__ */ jsx23("div", { className: "legend__items legend__items--sources", children: SOURCE_ORDER.map((source) => /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5091
+ /* @__PURE__ */ jsx23("span", { className: `legend__badge legend__badge--source legend__badge--source-${source}`, children: SOURCE_LABEL[source] }),
5092
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: SOURCE_LEGEND_DESC[source] })
4715
5093
  ] }, source)) })
4716
5094
  ] }),
4717
- /* @__PURE__ */ jsxs17("section", { className: "legend__section", children: [
4718
- /* @__PURE__ */ jsx21("h3", { className: "legend__section-title", children: "Column Badges" }),
4719
- /* @__PURE__ */ jsxs17("div", { className: "legend__items legend__items--badges", children: [
4720
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4721
- /* @__PURE__ */ jsx21("span", { className: "legend__badge legend__badge--pk", children: "PK" }),
4722
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Primary key" })
5095
+ /* @__PURE__ */ jsxs20("section", { className: "legend__section", children: [
5096
+ /* @__PURE__ */ jsx23("h3", { className: "legend__section-title", children: "Column Badges" }),
5097
+ /* @__PURE__ */ jsxs20("div", { className: "legend__items legend__items--badges", children: [
5098
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5099
+ /* @__PURE__ */ jsx23("span", { className: "legend__badge legend__badge--pk", children: "PK" }),
5100
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Primary key" })
4723
5101
  ] }),
4724
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4725
- /* @__PURE__ */ jsx21("span", { className: "legend__badge legend__badge--fk", children: "FK" }),
4726
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Foreign key" })
5102
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5103
+ /* @__PURE__ */ jsx23("span", { className: "legend__badge legend__badge--fk", children: "FK" }),
5104
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Foreign key" })
4727
5105
  ] }),
4728
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4729
- /* @__PURE__ */ jsx21("span", { className: "legend__badge legend__badge--nk", children: "NK" }),
4730
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Natural key" })
5106
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5107
+ /* @__PURE__ */ jsx23("span", { className: "legend__badge legend__badge--nk", children: "NK" }),
5108
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Natural key" })
4731
5109
  ] })
4732
5110
  ] }),
4733
- /* @__PURE__ */ jsxs17("div", { className: "legend__items legend__items--symbols", children: [
4734
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4735
- /* @__PURE__ */ jsx21("span", { className: "legend__symbols legend__symbols--scd", children: [0, 1, 2].map((t) => /* @__PURE__ */ jsx21("span", { title: SCD_TITLE[t], children: SCD_BADGE[t] }, t)) }),
4736
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "SCD type \u2014 fixed / overwritten / new row per change" })
5111
+ /* @__PURE__ */ jsxs20("div", { className: "legend__items legend__items--symbols", children: [
5112
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5113
+ /* @__PURE__ */ jsx23("span", { className: "legend__symbols legend__symbols--scd", children: [0, 1, 2].map((t) => /* @__PURE__ */ jsx23("span", { title: SCD_TITLE[t], children: SCD_BADGE[t] }, t)) }),
5114
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "SCD type \u2014 fixed / overwritten / new row per change" })
4737
5115
  ] }),
4738
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4739
- /* @__PURE__ */ jsx21("span", { className: "legend__symbols legend__symbols--additive", children: Object.keys(ADDITIVE_BADGE).map((a) => /* @__PURE__ */ jsx21("span", { title: ADDITIVE_TITLE[a], children: ADDITIVE_BADGE[a] }, a)) }),
4740
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Additive / semi-additive / non-additive measure" })
5116
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5117
+ /* @__PURE__ */ jsx23("span", { className: "legend__symbols legend__symbols--additive", children: Object.keys(ADDITIVE_BADGE).map((a) => /* @__PURE__ */ jsx23("span", { title: ADDITIVE_TITLE[a], children: ADDITIVE_BADGE[a] }, a)) }),
5118
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Additive / semi-additive / non-additive measure" })
4741
5119
  ] })
4742
5120
  ] })
4743
5121
  ] }),
4744
- /* @__PURE__ */ jsxs17("section", { className: "legend__section", children: [
4745
- /* @__PURE__ */ jsx21("h3", { className: "legend__section-title", children: "Comparing Stages" }),
4746
- /* @__PURE__ */ jsx21("p", { className: "legend__note legend__note--lead", children: "Shown while a comparison is open (Diff)." }),
4747
- /* @__PURE__ */ jsxs17("div", { className: "legend__items", children: [
4748
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4749
- /* @__PURE__ */ jsx21("span", { className: "legend__swatch legend__swatch--extra" }),
4750
- /* @__PURE__ */ jsxs17("span", { className: "legend__item-desc", children: [
5122
+ /* @__PURE__ */ jsxs20("section", { className: "legend__section", children: [
5123
+ /* @__PURE__ */ jsx23("h3", { className: "legend__section-title", children: "Comparing Stages" }),
5124
+ /* @__PURE__ */ jsx23("p", { className: "legend__note legend__note--lead", children: "Shown while a comparison is open (Diff)." }),
5125
+ /* @__PURE__ */ jsxs20("div", { className: "legend__items", children: [
5126
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5127
+ /* @__PURE__ */ jsx23("span", { className: "legend__swatch legend__swatch--extra" }),
5128
+ /* @__PURE__ */ jsxs20("span", { className: "legend__item-desc", children: [
4751
5129
  "Amber \u2014 only in the stage you are viewing (",
4752
- /* @__PURE__ */ jsx21("code", { children: "only here" }),
5130
+ /* @__PURE__ */ jsx23("code", { children: "only here" }),
4753
5131
  ")"
4754
5132
  ] })
4755
5133
  ] }),
4756
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4757
- /* @__PURE__ */ jsx21("span", { className: "legend__swatch legend__swatch--mismatch" }),
4758
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Red \u2014 declared differently in each stage" })
5134
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5135
+ /* @__PURE__ */ jsx23("span", { className: "legend__swatch legend__swatch--mismatch" }),
5136
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Red \u2014 declared differently in each stage" })
4759
5137
  ] }),
4760
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4761
- /* @__PURE__ */ jsx21("span", { className: "legend__swatch legend__swatch--missing" }),
4762
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Grey, struck through \u2014 only in the stage being compared against" })
5138
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5139
+ /* @__PURE__ */ jsx23("span", { className: "legend__swatch legend__swatch--missing" }),
5140
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Grey, struck through \u2014 only in the stage being compared against" })
4763
5141
  ] })
4764
5142
  ] }),
4765
- /* @__PURE__ */ jsx21("h4", { className: "legend__subsection-title", children: "Relationship lines" }),
4766
- /* @__PURE__ */ jsxs17("div", { className: "legend__items legend__items--disc-edges", children: [
4767
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4768
- /* @__PURE__ */ jsx21("svg", { className: "legend__edge-sample", viewBox: "0 0 48 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx21("line", { x1: "0", y1: "4", x2: "48", y2: "4", className: "legend__edge legend__edge--disc-extra" }) }),
4769
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Only in this stage" })
5143
+ /* @__PURE__ */ jsx23("h4", { className: "legend__subsection-title", children: "Relationship lines" }),
5144
+ /* @__PURE__ */ jsxs20("div", { className: "legend__items legend__items--disc-edges", children: [
5145
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5146
+ /* @__PURE__ */ jsx23("svg", { className: "legend__edge-sample", viewBox: "0 0 48 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx23("line", { x1: "0", y1: "4", x2: "48", y2: "4", className: "legend__edge legend__edge--disc-extra" }) }),
5147
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Only in this stage" })
4770
5148
  ] }),
4771
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4772
- /* @__PURE__ */ jsx21("svg", { className: "legend__edge-sample", viewBox: "0 0 48 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx21("line", { x1: "0", y1: "4", x2: "48", y2: "4", className: "legend__edge legend__edge--disc-missing" }) }),
4773
- /* @__PURE__ */ jsx21("span", { className: "legend__item-desc", children: "Only in the compared stage" })
5149
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5150
+ /* @__PURE__ */ jsx23("svg", { className: "legend__edge-sample", viewBox: "0 0 48 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx23("line", { x1: "0", y1: "4", x2: "48", y2: "4", className: "legend__edge legend__edge--disc-missing" }) }),
5151
+ /* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Only in the compared stage" })
4774
5152
  ] }),
4775
- /* @__PURE__ */ jsxs17("div", { className: "legend__item", children: [
4776
- /* @__PURE__ */ jsx21("svg", { className: "legend__edge-sample", viewBox: "0 0 48 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx21("line", { x1: "0", y1: "4", x2: "48", y2: "4", className: "legend__edge legend__edge--disc-mismatch" }) }),
4777
- /* @__PURE__ */ jsxs17("span", { className: "legend__item-desc", children: [
5153
+ /* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
5154
+ /* @__PURE__ */ jsx23("svg", { className: "legend__edge-sample", viewBox: "0 0 48 8", "aria-hidden": "true", children: /* @__PURE__ */ jsx23("line", { x1: "0", y1: "4", x2: "48", y2: "4", className: "legend__edge legend__edge--disc-mismatch" }) }),
5155
+ /* @__PURE__ */ jsxs20("span", { className: "legend__item-desc", children: [
4778
5156
  "Cardinality differs (",
4779
- /* @__PURE__ */ jsx21("code", { children: "!" }),
5157
+ /* @__PURE__ */ jsx23("code", { children: "!" }),
4780
5158
  " at the midpoint)"
4781
5159
  ] })
4782
5160
  ] })
@@ -4787,7 +5165,7 @@ function Legend() {
4787
5165
  }
4788
5166
 
4789
5167
  // src/ErdCanvas.tsx
4790
- import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
5168
+ import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
4791
5169
  function toRenderableDomain(domain) {
4792
5170
  let modelsChanged = false;
4793
5171
  const models = (domain.models ?? []).map((model) => {
@@ -4844,17 +5222,17 @@ function ErdCanvasInner({
4844
5222
  const edges = useEditorStore((s) => s.edges);
4845
5223
  const setNodes = useEditorStore((s) => s.setNodes);
4846
5224
  const setEdges = useEditorStore((s) => s.setEdges);
4847
- useEffect14(() => {
5225
+ useEffect16(() => {
4848
5226
  if (storeApi.getState().domain !== domainProp) {
4849
5227
  storeApi.getState().setDomain(domainProp);
4850
5228
  }
4851
5229
  }, [domainProp, storeApi]);
4852
- const onLayoutModifiedChangeRef = useRef10(onLayoutModifiedChange);
5230
+ const onLayoutModifiedChangeRef = useRef12(onLayoutModifiedChange);
4853
5231
  onLayoutModifiedChangeRef.current = onLayoutModifiedChange;
4854
- const onReadyRef = useRef10(onReady);
5232
+ const onReadyRef = useRef12(onReady);
4855
5233
  onReadyRef.current = onReady;
4856
- const [shiftHeld, setShiftHeld] = useState18(false);
4857
- useEffect14(() => {
5234
+ const [shiftHeld, setShiftHeld] = useState20(false);
5235
+ useEffect16(() => {
4858
5236
  const down = (e) => {
4859
5237
  if (e.key === "Shift") setShiftHeld(true);
4860
5238
  };
@@ -4872,23 +5250,23 @@ function ErdCanvasInner({
4872
5250
  };
4873
5251
  }, []);
4874
5252
  const { expandAll } = useColumnExpansion();
4875
- const hasAutoExpandedRef = useRef10(false);
4876
- useEffect14(() => {
5253
+ const hasAutoExpandedRef = useRef12(false);
5254
+ useEffect16(() => {
4877
5255
  if (!domain || hasAutoExpandedRef.current) return;
4878
5256
  hasAutoExpandedRef.current = true;
4879
5257
  if (domain.models.length < NODE_THRESHOLD) {
4880
5258
  expandAll(domain.models.map((m) => m.name));
4881
5259
  }
4882
5260
  }, [domain, expandAll]);
4883
- const baselineRef = useRef10(EMPTY_BASELINE);
4884
- const modifiedRef = useRef10(false);
4885
- const setModified = useCallback22((modified) => {
5261
+ const baselineRef = useRef12(EMPTY_BASELINE);
5262
+ const modifiedRef = useRef12(false);
5263
+ const setModified = useCallback24((modified) => {
4886
5264
  if (modifiedRef.current === modified) return;
4887
5265
  modifiedRef.current = modified;
4888
5266
  onLayoutModifiedChangeRef.current?.(modified);
4889
5267
  }, []);
4890
- const [transformed, setTransformed] = useState18(false);
4891
- const onTransformed = useCallback22(
5268
+ const [transformed, setTransformed] = useState20(false);
5269
+ const onTransformed = useCallback24(
4892
5270
  (newNodes, newEdges) => {
4893
5271
  baselineRef.current = captureBaseline(newNodes, newEdges);
4894
5272
  setModified(false);
@@ -4897,7 +5275,7 @@ function ErdCanvasInner({
4897
5275
  [setModified]
4898
5276
  );
4899
5277
  const { onNodeClick, onEdgeClick, onPaneClick, onSelectionChange } = useCanvasGraph({ onTransformed });
4900
- const onNodesChange = useCallback22(
5278
+ const onNodesChange = useCallback24(
4901
5279
  (changes) => {
4902
5280
  const state = storeApi.getState();
4903
5281
  const updatedNodes = applyNodeChanges(changes, state.nodes);
@@ -4913,7 +5291,7 @@ function ErdCanvasInner({
4913
5291
  },
4914
5292
  [storeApi, setNodes, setEdges, setModified]
4915
5293
  );
4916
- const resetLayout = useCallback22(() => {
5294
+ const resetLayout = useCallback24(() => {
4917
5295
  const baseline = baselineRef.current;
4918
5296
  const state = storeApi.getState();
4919
5297
  let nodesChanged = false;
@@ -4936,9 +5314,9 @@ function ErdCanvasInner({
4936
5314
  }, [storeApi, setNodes, setEdges, setModified]);
4937
5315
  useImperativeHandle(handleRef, () => ({ resetLayout }), [resetLayout]);
4938
5316
  const nodesInitialized = useNodesInitialized();
4939
- const readyFiredRef = useRef10(false);
5317
+ const readyFiredRef = useRef12(false);
4940
5318
  const canFireReady = transformed && (nodesInitialized || nodes.length === 0);
4941
- useEffect14(() => {
5319
+ useEffect16(() => {
4942
5320
  if (!canFireReady || readyFiredRef.current) return;
4943
5321
  let second = 0;
4944
5322
  const first = requestAnimationFrame(() => {
@@ -4952,13 +5330,13 @@ function ErdCanvasInner({
4952
5330
  cancelAnimationFrame(second);
4953
5331
  };
4954
5332
  }, [canFireReady]);
4955
- return /* @__PURE__ */ jsxs18(
5333
+ return /* @__PURE__ */ jsxs21(
4956
5334
  "div",
4957
5335
  {
4958
5336
  className: className ? `editor-canvas ${className}` : "editor-canvas",
4959
5337
  style: { position: "relative", width: "100%", height: "100%", display: "flex", flexDirection: "column", ...style },
4960
5338
  children: [
4961
- /* @__PURE__ */ jsxs18(
5339
+ /* @__PURE__ */ jsxs21(
4962
5340
  ReactFlow,
4963
5341
  {
4964
5342
  style: { flex: "1 1 0", minHeight: 0 },
@@ -4985,20 +5363,20 @@ function ErdCanvasInner({
4985
5363
  deleteKeyCode: null,
4986
5364
  proOptions: { hideAttribution: true },
4987
5365
  children: [
4988
- /* @__PURE__ */ jsx22(CanvasBackdrop, {}),
4989
- /* @__PURE__ */ jsx22(DetailPanel, {})
5366
+ /* @__PURE__ */ jsx24(CanvasBackdrop, {}),
5367
+ /* @__PURE__ */ jsx24(DetailPanel, {})
4990
5368
  ]
4991
5369
  }
4992
5370
  ),
4993
- /* @__PURE__ */ jsx22(Legend, {})
5371
+ /* @__PURE__ */ jsx24(Legend, {})
4994
5372
  ]
4995
5373
  }
4996
5374
  );
4997
5375
  }
4998
5376
  var ErdCanvas = forwardRef(function ErdCanvas2(props, ref) {
4999
5377
  const renderable = useMemo7(() => toRenderableDomain(props.domain), [props.domain]);
5000
- const [store] = useState18(() => createCanvasStore({ domain: renderable }));
5001
- return /* @__PURE__ */ jsx22(CanvasStoreProvider, { store, children: /* @__PURE__ */ jsx22(CanvasEnvironmentProvider, { host: NOOP_CANVAS_HOST, viewer: true, children: /* @__PURE__ */ jsx22(ReactFlowProvider, { children: /* @__PURE__ */ jsx22(ErdCanvasInner, { ...props, domain: renderable, handleRef: ref }) }) }) });
5378
+ const [store] = useState20(() => createCanvasStore({ domain: renderable }));
5379
+ return /* @__PURE__ */ jsx24(CanvasStoreProvider, { store, children: /* @__PURE__ */ jsx24(CanvasEnvironmentProvider, { host: NOOP_CANVAS_HOST, viewer: true, children: /* @__PURE__ */ jsx24(ReactFlowProvider, { children: /* @__PURE__ */ jsx24(ErdCanvasInner, { ...props, domain: renderable, handleRef: ref }) }) }) });
5002
5380
  });
5003
5381
 
5004
5382
  export {
@@ -5007,6 +5385,8 @@ export {
5007
5385
  useCanvasHost,
5008
5386
  useSend,
5009
5387
  useIsViewer,
5388
+ computeModelLabels,
5389
+ matchesModelSearch,
5010
5390
  pickHandleSides,
5011
5391
  transformDomain,
5012
5392
  applyNodeOverlays,