@erd-studio/renderer 0.1.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/README.md +9 -9
- package/dist/{chunk-IAFK7ZZV.js → chunk-HWA32XG5.js} +126 -50
- package/dist/editor.js +9 -9
- package/dist/index.js +3 -3
- package/dist/styles.css +56 -0
- package/dist/types/ErdCanvas.d.ts +4 -4
- package/dist/types/canvas/useCanvasGraph.d.ts +4 -4
- package/dist/types/components/DetailPanel/AliasEditor.d.ts +1 -1
- package/dist/types/components/DetailPanel/ColumnEditor.d.ts +2 -2
- package/dist/types/components/DetailPanel/ModelRationale.d.ts +5 -5
- package/dist/types/components/DetailPanel/RoleEditor.d.ts +3 -3
- package/dist/types/components/Graph/ColumnTooltip.d.ts +1 -1
- package/dist/types/components/Graph/ModelNode.d.ts +4 -4
- package/dist/types/components/Legend/Legend.d.ts +1 -1
- package/dist/types/components/common/ColumnRowEditor.d.ts +2 -2
- package/dist/types/editor.d.ts +2 -2
- package/dist/types/hooks/useColumnReorder.d.ts +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/lib/badgeLabels.d.ts +1 -1
- package/dist/types/lib/dragHandleSides.d.ts +2 -2
- package/dist/types/lib/graphTransformer.d.ts +7 -7
- package/dist/types/lib/modelLabels.d.ts +3 -3
- package/dist/types/lib/nodeOverlays.d.ts +4 -4
- package/dist/types/lib/nodeSizing.d.ts +6 -6
- package/dist/types/store/editorStore.d.ts +8 -8
- package/dist/types/types/graph.d.ts +18 -13
- package/package.json +3 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@erd-studio/renderer`. While `0.x`, a breaking change bumps the minor version.
|
|
4
|
+
|
|
5
|
+
## 0.3.0
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- Pins `@erd-studio/core` 0.3.0, which reads schema v6, the table naming ([#181](https://github.com/liam-machine/erd-studio/issues/181)). No change to the renderer's own API: a v6 subject area reaches `ErdCanvas` as the same `DisplaySubjectArea` its v5 twin does.
|
|
9
|
+
|
|
10
|
+
## 0.2.0
|
|
11
|
+
|
|
12
|
+
### Changed (breaking)
|
|
13
|
+
- **Exports use the new words: table and subject area** ([#180](https://github.com/liam-machine/erd-studio/issues/180), part 2 of [#162](https://github.com/liam-machine/erd-studio/issues/162)). What was called a *model* is a **table**, and a *domain* is a **subject area**. Pins `@erd-studio/core` 0.2.0. The types re-exported from core carry its new names. Only names changed: every function behaves as before, and object shapes, property names (`DisplaySubjectArea.models`, `domainPath`, `ErdCanvas`'s `domain` prop, …), message `type` strings and the files read on disk are the same, so a `DisplaySubjectArea` from 0.2.0 is the `DisplayDomain` of 0.1.x. There are no aliases for the old names. Rename the imports:
|
|
14
|
+
|
|
15
|
+
| 0.1.x | 0.2.0 |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `computeModelLabels` | `computeTableLabels` |
|
|
18
|
+
| `DisplayDomain` | `DisplaySubjectArea` |
|
|
19
|
+
| `DisplayModel` | `DisplayTable` |
|
|
20
|
+
| `LabelledModel` | `LabelledTable` |
|
|
21
|
+
| `matchesModelSearch` | `matchesTableSearch` |
|
|
22
|
+
| `ModelFlowNode` | `TableFlowNode` |
|
|
23
|
+
| `ModelNode` | `TableNode` |
|
|
24
|
+
| `ModelNodeData` | `TableNodeData` |
|
|
25
|
+
| `ModelRole` | `TableRole` |
|
|
26
|
+
| `transformDomain` | `transformSubjectArea` |
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @erd-studio/renderer
|
|
2
2
|
|
|
3
|
-
The entity-relationship diagram canvas from the [ERD Studio](https://github.com/liam-machine/erd-studio) VS Code extension, packaged for reuse. It is built on React Flow and renders a `
|
|
3
|
+
The entity-relationship diagram canvas from the [ERD Studio](https://github.com/liam-machine/erd-studio) VS Code extension, packaged for reuse. It is built on React Flow and renders a `DisplaySubjectArea` from `@erd-studio/core`: model nodes with their columns and key badges, FK edges with cardinality, annotations, the detail panel and the legend.
|
|
4
4
|
|
|
5
5
|
Peer dependencies: `react` and `react-dom` 18.3+, `@xyflow/react` 12.4+.
|
|
6
6
|
|
|
@@ -8,8 +8,8 @@ Peer dependencies: `react` and `react-dom` 18.3+, `@xyflow/react` 12.4+.
|
|
|
8
8
|
|
|
9
9
|
| Import | What it is for |
|
|
10
10
|
|---|---|
|
|
11
|
-
| `@erd-studio/renderer` | Showing a domain: the `ErdCanvas` viewer component (below), plus `
|
|
12
|
-
| `@erd-studio/renderer/editor` | Everything above plus what a host needs to build a full editor around the canvas, as the extension's webview does: the store (below), the host adapter, `useCanvasGraph`, `CanvasBackdrop`, `canvasNodeTypes` / `canvasEdgeTypes`, the components (`
|
|
11
|
+
| `@erd-studio/renderer` | Showing a domain: the `ErdCanvas` viewer component (below), plus `transformSubjectArea` (a `DisplaySubjectArea` to React Flow nodes and edges), `pickHandleSides`, `repickHandleSides` / `nodeRect`, the diagram exporters re-exported from `@erd-studio/core` (below), and the display, domain and graph types (`DisplaySubjectArea`, `TableFlowNode`, `FkFlowEdge`, …). |
|
|
12
|
+
| `@erd-studio/renderer/editor` | Everything above plus what a host needs to build a full editor around the canvas, as the extension's webview does: the store (below), the host adapter, `useCanvasGraph`, `CanvasBackdrop`, `canvasNodeTypes` / `canvasEdgeTypes`, the components (`TableNode`, `FkEdge`, `AnnotationNode`, `AnnotationEdge`, `DetailPanel`, `Legend`, `KeyBadge`, `KeyBadgeGroup`, `DataTypeSelect`, `ColumnRowEditor`), the canvas hooks and the pure helpers. |
|
|
13
13
|
| `@erd-studio/renderer/store` | The canvas store on its own, with no React Flow runtime: `createCanvasSlice`, `createCanvasStore`, `CanvasStoreProvider`, `useEditorStore`, `useEditorStoreApi` and their types. |
|
|
14
14
|
| `@erd-studio/renderer/sizing` | Model node size estimation (`NODE_WIDTH`, `estimateNodeWidth`, `estimateNodeHeight`, `countVisibleColumnRows`, `resolveNodeDimensions`), for layout code that needs node sizes before React Flow has measured them. No components. |
|
|
15
15
|
| `@erd-studio/renderer/styles.css` | The stylesheet: every component's CSS in cascade order, then the theme tokens. It `@import`s `@xyflow/react/dist/style.css`, which your bundler resolves. |
|
|
@@ -18,14 +18,14 @@ All four JavaScript entry points share their modules, so a store or context crea
|
|
|
18
18
|
|
|
19
19
|
## Viewer: `ErdCanvas`
|
|
20
20
|
|
|
21
|
-
`ErdCanvas` renders a `
|
|
21
|
+
`ErdCanvas` renders a `DisplaySubjectArea` read-only, the way the extension shows a read-only domain: model nodes with their columns and key badges, FK edges, annotations, the minimap, the legend, and the detail panel a click on a model opens. It presents no editing affordances and posts nothing anywhere.
|
|
22
22
|
|
|
23
23
|
```tsx
|
|
24
24
|
import { useRef, useState } from 'react';
|
|
25
|
-
import { ErdCanvas, type ErdCanvasHandle, type
|
|
25
|
+
import { ErdCanvas, type ErdCanvasHandle, type DisplaySubjectArea } from '@erd-studio/renderer';
|
|
26
26
|
import '@erd-studio/renderer/styles.css';
|
|
27
27
|
|
|
28
|
-
function Diagram({ domain }: { domain:
|
|
28
|
+
function Diagram({ domain }: { domain: DisplaySubjectArea }) {
|
|
29
29
|
const canvas = useRef<ErdCanvasHandle>(null);
|
|
30
30
|
const [moved, setMoved] = useState(false);
|
|
31
31
|
return (
|
|
@@ -51,12 +51,12 @@ Each `ErdCanvas` has its own store, so several can share a page.
|
|
|
51
51
|
|
|
52
52
|
## Exporting a diagram
|
|
53
53
|
|
|
54
|
-
The `.` entry re-exports `@erd-studio/core`'s one-way exporters, so a page that shows a diagram with `ErdCanvas` can offer it as text without depending on core itself: `toMermaid`, `toDbml`, `exportDiagram`, `diagramExportFileName`, `DIAGRAM_EXPORT_FORMATS`, `DIAGRAM_EXPORT_FILE_EXTENSIONS` and the `DiagramExportFormat` type. They are pure functions with no React or DOM use; the same `
|
|
54
|
+
The `.` entry re-exports `@erd-studio/core`'s one-way exporters, so a page that shows a diagram with `ErdCanvas` can offer it as text without depending on core itself: `toMermaid`, `toDbml`, `exportDiagram`, `diagramExportFileName`, `DIAGRAM_EXPORT_FORMATS`, `DIAGRAM_EXPORT_FILE_EXTENSIONS` and the `DiagramExportFormat` type. They are pure functions with no React or DOM use; the same `DisplaySubjectArea` gives the same text everywhere ERD Studio exports it.
|
|
55
55
|
|
|
56
56
|
```ts
|
|
57
|
-
import { exportDiagram, diagramExportFileName, type
|
|
57
|
+
import { exportDiagram, diagramExportFileName, type DisplaySubjectArea } from '@erd-studio/renderer';
|
|
58
58
|
|
|
59
|
-
function downloadDbml(domain:
|
|
59
|
+
function downloadDbml(domain: DisplaySubjectArea) {
|
|
60
60
|
const text = exportDiagram(domain, 'dbml'); // or 'mermaid'
|
|
61
61
|
const url = URL.createObjectURL(new Blob([text], { type: 'text/plain' }));
|
|
62
62
|
const link = Object.assign(document.createElement('a'), { href: url, download: diagramExportFileName(domain, 'dbml') });
|
|
@@ -102,7 +102,7 @@ function foldComposites(rels) {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
// src/lib/modelLabels.ts
|
|
105
|
-
function
|
|
105
|
+
function computeTableLabels(models) {
|
|
106
106
|
const baseOf = (m) => m.alias?.trim() || m.name;
|
|
107
107
|
const counts = /* @__PURE__ */ new Map();
|
|
108
108
|
for (const m of models) {
|
|
@@ -120,7 +120,7 @@ function computeModelLabels(models) {
|
|
|
120
120
|
}
|
|
121
121
|
return labels;
|
|
122
122
|
}
|
|
123
|
-
function
|
|
123
|
+
function matchesTableSearch(data, query) {
|
|
124
124
|
return data.modelName.toLowerCase().includes(query) || data.label !== void 0 && data.label.toLowerCase().includes(query);
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -153,7 +153,7 @@ function pickHandleSides(source, target) {
|
|
|
153
153
|
return dy >= 0 ? { sourceSide: "bottom", targetSide: "top" } : { sourceSide: "top", targetSide: "bottom" };
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
|
-
function
|
|
156
|
+
function transformSubjectArea(domain, options) {
|
|
157
157
|
const { models, relationships, viewConfig, layer, stage, layerConfig, readOnly } = domain;
|
|
158
158
|
const positions = viewConfig.positions ?? {};
|
|
159
159
|
const discrepancyMap = /* @__PURE__ */ new Map();
|
|
@@ -176,7 +176,7 @@ function transformDomain(domain, options) {
|
|
|
176
176
|
data: { ...data, isExpanded: options?.isExpanded?.(id) ?? false },
|
|
177
177
|
measured: void 0
|
|
178
178
|
});
|
|
179
|
-
const labels =
|
|
179
|
+
const labels = computeTableLabels(models);
|
|
180
180
|
const nodes = models.map((model) => {
|
|
181
181
|
const columns = mapColumns(model);
|
|
182
182
|
const position = positionMap.get(model.name) ?? DEFAULT_POSITION;
|
|
@@ -278,6 +278,7 @@ function transformDomain(domain, options) {
|
|
|
278
278
|
cardinality: rel.cardinality,
|
|
279
279
|
...rel.role ? { role: rel.role } : {},
|
|
280
280
|
...rel.pairs ? { pairs: rel.pairs, compositeKey: rel.compositeKey } : {},
|
|
281
|
+
...rel.keysContradict && !readOnly ? { keysContradict: true } : {},
|
|
281
282
|
stage,
|
|
282
283
|
...readOnly ? { readOnly: true } : {},
|
|
283
284
|
...discStatus ? { discrepancyStatus: discStatus } : {},
|
|
@@ -403,7 +404,7 @@ function applyNodeOverlays(nodes, edges, state) {
|
|
|
403
404
|
return node;
|
|
404
405
|
}
|
|
405
406
|
const data = node.data;
|
|
406
|
-
const searchDimmed = query ? !
|
|
407
|
+
const searchDimmed = query ? !matchesTableSearch(data, query) : false;
|
|
407
408
|
const selectionDimmed = hasSelection && !connected.has(node.id);
|
|
408
409
|
const dimmed = searchDimmed || selectionDimmed;
|
|
409
410
|
const expanded = isExpanded(node.id);
|
|
@@ -479,7 +480,7 @@ function useCanvasGraph({
|
|
|
479
480
|
nodeDimensions,
|
|
480
481
|
isExpanded: isExpandedNow
|
|
481
482
|
};
|
|
482
|
-
let { nodes: newNodes, edges: newEdges } =
|
|
483
|
+
let { nodes: newNodes, edges: newEdges } = transformSubjectArea(domain, transformOptions);
|
|
483
484
|
newNodes = newNodes.map((n) => {
|
|
484
485
|
const prev = prevById.get(n.id);
|
|
485
486
|
return prev?.measured?.width != null && prev.measured.height != null ? { ...n, measured: prev.measured } : n;
|
|
@@ -1746,9 +1747,9 @@ function describeLoadError(error) {
|
|
|
1746
1747
|
}
|
|
1747
1748
|
function describeLoadWarning(warning) {
|
|
1748
1749
|
const key = warning.key ? `"${warning.key}"` : "A key";
|
|
1749
|
-
return `${key} is written twice (line ${warning.line}) \u2014 the last one is shown. Remove the other copy to edit this
|
|
1750
|
+
return `${key} is written twice (line ${warning.line}) \u2014 the last one is shown. Remove the other copy to edit this table.`;
|
|
1750
1751
|
}
|
|
1751
|
-
function
|
|
1752
|
+
function TableNodeComponent({ data, selected }) {
|
|
1752
1753
|
const { modelName, label, stage, layer, layerConfig, schema, columns, grain, meta, dimmed, readOnly, isGhost, ghostReason, provenance, loadError, loadWarning, isStub, isExpanded = false, onToggleExpansion, discrepancy, discrepancySourceStage, discrepancyTargetStage } = data;
|
|
1753
1754
|
const openNodeContextMenu = useEditorStore((s) => s.openNodeContextMenu);
|
|
1754
1755
|
const send = useSend();
|
|
@@ -1801,7 +1802,7 @@ function ModelNodeComponent({ data, selected }) {
|
|
|
1801
1802
|
}, [isExpanded, columnDiscrepancyMap, discrepancy]);
|
|
1802
1803
|
const isDiscExtra = discrepancy?.status === "extra";
|
|
1803
1804
|
const stageClass = isGhost ? "ghost" : stage;
|
|
1804
|
-
const title = label ? `${label} (
|
|
1805
|
+
const title = label ? `${label} (table ${modelName})` : modelName;
|
|
1805
1806
|
const modelMeta = useMemo2(() => metaRows(meta), [meta]);
|
|
1806
1807
|
const nameTip = useHoverTip(
|
|
1807
1808
|
ghostReason ? `${title} \u2014 ${GHOST_REASON_TITLE[ghostReason]}` : isDiscExtra ? `${title} \u2014 only in ${discrepancySourceStage ?? "this stage"}, not in ${discrepancyTargetStage ?? "the stage being compared"}` : title,
|
|
@@ -1974,7 +1975,7 @@ function ModelNodeComponent({ data, selected }) {
|
|
|
1974
1975
|
}
|
|
1975
1976
|
);
|
|
1976
1977
|
}
|
|
1977
|
-
var
|
|
1978
|
+
var TableNode = memo(TableNodeComponent);
|
|
1978
1979
|
|
|
1979
1980
|
// src/components/Graph/FkEdge.tsx
|
|
1980
1981
|
import { memo as memo2, useCallback as useCallback9, useMemo as useMemo3, useState as useState6 } from "react";
|
|
@@ -1986,6 +1987,7 @@ import {
|
|
|
1986
1987
|
useStoreApi,
|
|
1987
1988
|
useInternalNode
|
|
1988
1989
|
} from "@xyflow/react";
|
|
1990
|
+
import { backwardsRelationshipNote } from "@erd-studio/core";
|
|
1989
1991
|
|
|
1990
1992
|
// src/lib/cardinalityUtils.ts
|
|
1991
1993
|
function swapCardinality(c) {
|
|
@@ -2160,7 +2162,9 @@ function FkEdgeComponent({
|
|
|
2160
2162
|
return positions;
|
|
2161
2163
|
}, [positionsKey, neighbourIds, storeApi]);
|
|
2162
2164
|
const host = useCanvasHost();
|
|
2165
|
+
const viewer = useIsViewer();
|
|
2163
2166
|
const [hovered, setHovered] = useState6(false);
|
|
2167
|
+
const [backwardsHovered, setBackwardsHovered] = useState6(false);
|
|
2164
2168
|
const handleSwap = useCallback9(
|
|
2165
2169
|
(e) => {
|
|
2166
2170
|
if (!data) return;
|
|
@@ -2340,7 +2344,39 @@ function FkEdgeComponent({
|
|
|
2340
2344
|
children: "!"
|
|
2341
2345
|
}
|
|
2342
2346
|
),
|
|
2343
|
-
!readOnly && discrepancyStatus !== "missing" && /* @__PURE__ */
|
|
2347
|
+
viewer ? null : data.keysContradict && !readOnly && discrepancyStatus !== "missing" && /* @__PURE__ */ jsxs6(
|
|
2348
|
+
"span",
|
|
2349
|
+
{
|
|
2350
|
+
className: `fk-edge__backwards${dimmed ? " fk-edge__backwards--dimmed" : ""}`,
|
|
2351
|
+
style: {
|
|
2352
|
+
transform: `translate(-9px, -50%) translate(${midX}px, ${midY}px)`
|
|
2353
|
+
},
|
|
2354
|
+
onMouseEnter: (e) => {
|
|
2355
|
+
e.stopPropagation();
|
|
2356
|
+
setBackwardsHovered(true);
|
|
2357
|
+
},
|
|
2358
|
+
onMouseLeave: (e) => {
|
|
2359
|
+
e.stopPropagation();
|
|
2360
|
+
setBackwardsHovered(false);
|
|
2361
|
+
},
|
|
2362
|
+
children: [
|
|
2363
|
+
/* @__PURE__ */ jsx8(
|
|
2364
|
+
"span",
|
|
2365
|
+
{
|
|
2366
|
+
className: "fk-edge__backwards-icon",
|
|
2367
|
+
role: "img",
|
|
2368
|
+
"aria-label": "Probably drawn backwards",
|
|
2369
|
+
title: backwardsRelationshipNote(data, data.pairs ?? [{ fromColumn, toColumn }]),
|
|
2370
|
+
children: "\u26A0"
|
|
2371
|
+
}
|
|
2372
|
+
),
|
|
2373
|
+
backwardsHovered && // Turn round is ⇄: a backwards many-to-one becomes the one-to-many it
|
|
2374
|
+
// reads as, which the host stores the right way round (#163).
|
|
2375
|
+
/* @__PURE__ */ jsx8("button", { className: "fk-edge__backwards-btn", onClick: handleSwap, title: "Turn this relationship round", children: "Turn round" })
|
|
2376
|
+
]
|
|
2377
|
+
}
|
|
2378
|
+
),
|
|
2379
|
+
!readOnly && discrepancyStatus !== "missing" && !(data.keysContradict && !viewer) && /* @__PURE__ */ jsx8(
|
|
2344
2380
|
"span",
|
|
2345
2381
|
{
|
|
2346
2382
|
className: `fk-edge__swap-zone${dimmed ? " fk-edge__swap-zone--dimmed" : ""}`,
|
|
@@ -2572,7 +2608,7 @@ function AnnotationNodeInner({ data }) {
|
|
|
2572
2608
|
{
|
|
2573
2609
|
className: "annotation-node__link-handle nodrag",
|
|
2574
2610
|
onMouseDown: handleLinkDragStart,
|
|
2575
|
-
title: "Drag to a
|
|
2611
|
+
title: "Drag to a table to link",
|
|
2576
2612
|
children: "\u{1F517}"
|
|
2577
2613
|
}
|
|
2578
2614
|
),
|
|
@@ -2687,7 +2723,7 @@ function AnnotationEdgeInner({
|
|
|
2687
2723
|
var AnnotationEdge = memo4(AnnotationEdgeInner);
|
|
2688
2724
|
|
|
2689
2725
|
// src/canvas/flowTypes.ts
|
|
2690
|
-
var canvasNodeTypes = { model:
|
|
2726
|
+
var canvasNodeTypes = { model: TableNode, annotation: AnnotationNode };
|
|
2691
2727
|
var canvasEdgeTypes = { fk: FkEdge, annotationLink: AnnotationEdge };
|
|
2692
2728
|
|
|
2693
2729
|
// src/lib/dragHandleSides.ts
|
|
@@ -2868,7 +2904,7 @@ function hasRationaleContent(rationale) {
|
|
|
2868
2904
|
rationale.measures
|
|
2869
2905
|
].some(Boolean);
|
|
2870
2906
|
}
|
|
2871
|
-
function
|
|
2907
|
+
function TableRationale({ modelName, rationale, modelRole, grain }) {
|
|
2872
2908
|
const viewer = useIsViewer();
|
|
2873
2909
|
const [open, setOpen] = useState9(false);
|
|
2874
2910
|
const [forceShow, setForceShow] = useState9(false);
|
|
@@ -2931,7 +2967,7 @@ function ModelRationale({ modelName, rationale, modelRole, grain }) {
|
|
|
2931
2967
|
rationale,
|
|
2932
2968
|
fieldKey: "purpose",
|
|
2933
2969
|
label: "Purpose",
|
|
2934
|
-
placeholder: "What requirements does this
|
|
2970
|
+
placeholder: "What requirements does this table meet?",
|
|
2935
2971
|
autoEdit: !viewer && forceShow && !rationale?.purpose
|
|
2936
2972
|
}
|
|
2937
2973
|
),
|
|
@@ -2942,7 +2978,7 @@ function ModelRationale({ modelName, rationale, modelRole, grain }) {
|
|
|
2942
2978
|
rationale,
|
|
2943
2979
|
fieldKey: "design",
|
|
2944
2980
|
label: "Design",
|
|
2945
|
-
placeholder: "Why was this
|
|
2981
|
+
placeholder: "Why was this table designed this way?"
|
|
2946
2982
|
}
|
|
2947
2983
|
),
|
|
2948
2984
|
modelRole && /* @__PURE__ */ jsx12(
|
|
@@ -2952,7 +2988,7 @@ function ModelRationale({ modelName, rationale, modelRole, grain }) {
|
|
|
2952
2988
|
rationale,
|
|
2953
2989
|
fieldKey: "roleChoice",
|
|
2954
2990
|
label: "Role Choice",
|
|
2955
|
-
placeholder: "Why was this
|
|
2991
|
+
placeholder: "Why was this table role selected?"
|
|
2956
2992
|
}
|
|
2957
2993
|
),
|
|
2958
2994
|
grain && /* @__PURE__ */ jsx12(
|
|
@@ -3033,7 +3069,7 @@ function DescriptionEditor({ modelName, description }) {
|
|
|
3033
3069
|
{
|
|
3034
3070
|
className: "detail-panel__rationale-add-btn",
|
|
3035
3071
|
onClick: () => setEditing(true),
|
|
3036
|
-
title: "Add
|
|
3072
|
+
title: "Add table description",
|
|
3037
3073
|
children: "+ Add Description"
|
|
3038
3074
|
}
|
|
3039
3075
|
) });
|
|
@@ -3048,7 +3084,7 @@ function DescriptionEditor({ modelName, description }) {
|
|
|
3048
3084
|
value,
|
|
3049
3085
|
onChange: (e) => setValue(e.target.value),
|
|
3050
3086
|
onKeyDown: handleKeyDown,
|
|
3051
|
-
placeholder: "Describe this
|
|
3087
|
+
placeholder: "Describe this table...",
|
|
3052
3088
|
rows: 3,
|
|
3053
3089
|
autoFocus: true
|
|
3054
3090
|
}
|
|
@@ -3181,7 +3217,7 @@ function GrainEditor({ modelName, grain }) {
|
|
|
3181
3217
|
|
|
3182
3218
|
// src/components/DetailPanel/AliasEditor.tsx
|
|
3183
3219
|
import { useCallback as useCallback14, useEffect as useEffect10, useRef as useRef8, useState as useState12 } from "react";
|
|
3184
|
-
import {
|
|
3220
|
+
import { TABLE_ALIAS_MAX_LENGTH, TABLE_ALIAS_RULE, isValidTableAlias } from "@erd-studio/core";
|
|
3185
3221
|
import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3186
3222
|
function AliasEditor({ modelName, alias, readOnly }) {
|
|
3187
3223
|
const host = useCanvasHost();
|
|
@@ -3194,7 +3230,7 @@ function AliasEditor({ modelName, alias, readOnly }) {
|
|
|
3194
3230
|
}
|
|
3195
3231
|
}, [alias, editing]);
|
|
3196
3232
|
const trimmed = value.trim();
|
|
3197
|
-
const error = trimmed && !
|
|
3233
|
+
const error = trimmed && !isValidTableAlias(trimmed) ? TABLE_ALIAS_RULE : null;
|
|
3198
3234
|
const handleSave = useCallback14(() => {
|
|
3199
3235
|
if (error || settled.current) return;
|
|
3200
3236
|
settled.current = true;
|
|
@@ -3227,7 +3263,7 @@ function AliasEditor({ modelName, alias, readOnly }) {
|
|
|
3227
3263
|
}, []);
|
|
3228
3264
|
if (editing) {
|
|
3229
3265
|
return /* @__PURE__ */ jsxs12("div", { className: "detail-panel__metadata-row detail-panel__metadata-row--alias", children: [
|
|
3230
|
-
/* @__PURE__ */ jsx15("span", { className: "detail-panel__label detail-panel__label--wide", children: "
|
|
3266
|
+
/* @__PURE__ */ jsx15("span", { className: "detail-panel__label detail-panel__label--wide", children: "Warehouse name" }),
|
|
3231
3267
|
/* @__PURE__ */ jsxs12("span", { className: "detail-panel__alias-edit", children: [
|
|
3232
3268
|
/* @__PURE__ */ jsx15(
|
|
3233
3269
|
"input",
|
|
@@ -3235,26 +3271,26 @@ function AliasEditor({ modelName, alias, readOnly }) {
|
|
|
3235
3271
|
className: `detail-panel__alias-input${error ? " detail-panel__alias-input--error" : ""}`,
|
|
3236
3272
|
value,
|
|
3237
3273
|
placeholder: modelName,
|
|
3238
|
-
maxLength:
|
|
3274
|
+
maxLength: TABLE_ALIAS_MAX_LENGTH,
|
|
3239
3275
|
onChange: (e) => setValue(e.target.value),
|
|
3240
3276
|
onKeyDown: handleKeyDown,
|
|
3241
3277
|
onBlur: () => error ? handleCancel() : handleSave(),
|
|
3242
|
-
"aria-label": "
|
|
3278
|
+
"aria-label": "Warehouse name (alias)",
|
|
3243
3279
|
"aria-invalid": error ? true : void 0,
|
|
3244
3280
|
autoFocus: true
|
|
3245
3281
|
}
|
|
3246
3282
|
),
|
|
3247
|
-
/* @__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
|
|
3283
|
+
/* @__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 table's name." })
|
|
3248
3284
|
] })
|
|
3249
3285
|
] });
|
|
3250
3286
|
}
|
|
3251
3287
|
return /* @__PURE__ */ jsxs12("div", { className: "detail-panel__metadata-row detail-panel__metadata-row--alias", children: [
|
|
3252
|
-
/* @__PURE__ */ jsx15("span", { className: "detail-panel__label detail-panel__label--wide", children: "
|
|
3288
|
+
/* @__PURE__ */ jsx15("span", { className: "detail-panel__label detail-panel__label--wide", children: "Warehouse name" }),
|
|
3253
3289
|
/* @__PURE__ */ jsx15(
|
|
3254
3290
|
"span",
|
|
3255
3291
|
{
|
|
3256
3292
|
className: `detail-panel__value${alias ? "" : " detail-panel__value--muted"}`,
|
|
3257
|
-
title: alias ? `Built as ${alias} (dbt alias); the
|
|
3293
|
+
title: alias ? `Built as ${alias} (dbt alias); the table's name is ${modelName}` : "Same as the table's name",
|
|
3258
3294
|
onDoubleClick: readOnly ? void 0 : startEditing,
|
|
3259
3295
|
children: alias || modelName
|
|
3260
3296
|
}
|
|
@@ -3264,8 +3300,8 @@ function AliasEditor({ modelName, alias, readOnly }) {
|
|
|
3264
3300
|
{
|
|
3265
3301
|
className: "detail-panel__rationale-edit-btn detail-panel__alias-edit-btn",
|
|
3266
3302
|
onClick: startEditing,
|
|
3267
|
-
title: "Set the
|
|
3268
|
-
"aria-label": "Edit
|
|
3303
|
+
title: "Set the warehouse name (alias)",
|
|
3304
|
+
"aria-label": "Edit warehouse name",
|
|
3269
3305
|
children: "\u270E"
|
|
3270
3306
|
}
|
|
3271
3307
|
)
|
|
@@ -3415,7 +3451,7 @@ function KeyBadgeGroup({
|
|
|
3415
3451
|
"span",
|
|
3416
3452
|
{
|
|
3417
3453
|
className: "key-badge-group__warning",
|
|
3418
|
-
title: "Multiple primary keys detected in this
|
|
3454
|
+
title: "Multiple primary keys detected in this table",
|
|
3419
3455
|
children: "!"
|
|
3420
3456
|
}
|
|
3421
3457
|
) : null;
|
|
@@ -4308,7 +4344,7 @@ function MetaEditor({ modelName, columnName, meta, readOnly, compact }) {
|
|
|
4308
4344
|
"span",
|
|
4309
4345
|
{
|
|
4310
4346
|
className: `meta-editor__text${text ? "" : " meta-editor__text--structured"}`,
|
|
4311
|
-
title: editable && !text ? "Edit nested values in the
|
|
4347
|
+
title: editable && !text ? "Edit nested values in the table's file" : formatMetaValue(value),
|
|
4312
4348
|
onDoubleClick: editable && text ? () => startEdit(key, value) : void 0,
|
|
4313
4349
|
children: formatMetaValue(value)
|
|
4314
4350
|
}
|
|
@@ -4655,6 +4691,7 @@ function ColumnEditor({ modelName, columns, readOnly, modelRole }) {
|
|
|
4655
4691
|
}
|
|
4656
4692
|
|
|
4657
4693
|
// src/components/DetailPanel/DetailPanel.tsx
|
|
4694
|
+
import { backwardsRelationshipNote as backwardsRelationshipNote2 } from "@erd-studio/core";
|
|
4658
4695
|
import { Fragment as Fragment4, jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
4659
4696
|
function columnsText(rel, end) {
|
|
4660
4697
|
const cols = columnPairs(rel).map((p) => end === "from" ? p.fromColumn : p.toColumn);
|
|
@@ -4723,10 +4760,10 @@ function DetailPanel() {
|
|
|
4723
4760
|
return "Only the upper/lower case differs \u2014 rename to another name first";
|
|
4724
4761
|
}
|
|
4725
4762
|
if (domain && trimmed !== selectedNode && domain.models.some((m) => same(m.name))) {
|
|
4726
|
-
return "A
|
|
4763
|
+
return "A table with this name already exists";
|
|
4727
4764
|
}
|
|
4728
4765
|
if (trimmed !== selectedNode && existingModels.some((m) => m.source === "logical" && same(m.name))) {
|
|
4729
|
-
return "A
|
|
4766
|
+
return "A table with this name already exists in the Table Library";
|
|
4730
4767
|
}
|
|
4731
4768
|
return "";
|
|
4732
4769
|
},
|
|
@@ -4795,6 +4832,21 @@ function DetailPanel() {
|
|
|
4795
4832
|
},
|
|
4796
4833
|
[host]
|
|
4797
4834
|
);
|
|
4835
|
+
const handleTurnRound = useCallback22(
|
|
4836
|
+
(rel) => {
|
|
4837
|
+
host.postMessage({
|
|
4838
|
+
type: "updateRelationship",
|
|
4839
|
+
payload: {
|
|
4840
|
+
fromModel: rel.fromModel,
|
|
4841
|
+
fromColumn: rel.fromColumn,
|
|
4842
|
+
toModel: rel.toModel,
|
|
4843
|
+
toColumn: rel.toColumn,
|
|
4844
|
+
cardinality: swapCardinality(rel.cardinality)
|
|
4845
|
+
}
|
|
4846
|
+
});
|
|
4847
|
+
},
|
|
4848
|
+
[host]
|
|
4849
|
+
);
|
|
4798
4850
|
const handleRelationshipClick = useCallback22(
|
|
4799
4851
|
(x, y, rel) => {
|
|
4800
4852
|
const edgeData = {
|
|
@@ -4877,8 +4929,8 @@ function DetailPanel() {
|
|
|
4877
4929
|
{
|
|
4878
4930
|
className: "detail-panel__title-edit-btn",
|
|
4879
4931
|
onClick: handleStartRename,
|
|
4880
|
-
title: "Rename
|
|
4881
|
-
"aria-label": "Rename
|
|
4932
|
+
title: "Rename table",
|
|
4933
|
+
"aria-label": "Rename table",
|
|
4882
4934
|
children: "\u270E"
|
|
4883
4935
|
}
|
|
4884
4936
|
),
|
|
@@ -4914,7 +4966,7 @@ function DetailPanel() {
|
|
|
4914
4966
|
!isReadOnly && /* @__PURE__ */ jsx22("div", { className: "detail-panel__section", children: /* @__PURE__ */ jsx22(GrainEditor, { modelName: model.name, grain: model.grain }) }),
|
|
4915
4967
|
(!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 }) }),
|
|
4916
4968
|
(!viewer || hasRationaleContent(model.rationale)) && /* @__PURE__ */ jsx22("div", { className: "detail-panel__section", children: /* @__PURE__ */ jsx22(
|
|
4917
|
-
|
|
4969
|
+
TableRationale,
|
|
4918
4970
|
{
|
|
4919
4971
|
modelName: model.name,
|
|
4920
4972
|
rationale: model.rationale,
|
|
@@ -4924,7 +4976,7 @@ function DetailPanel() {
|
|
|
4924
4976
|
) }),
|
|
4925
4977
|
!isReadOnly && /* @__PURE__ */ jsx22("div", { className: "detail-panel__section detail-panel__section--actions", children: confirmingDelete ? /* @__PURE__ */ jsxs19(Fragment4, { children: [
|
|
4926
4978
|
/* @__PURE__ */ jsxs19("span", { className: "detail-panel__confirm-label", children: [
|
|
4927
|
-
"Remove
|
|
4979
|
+
"Remove table from subject area?",
|
|
4928
4980
|
totalRelationships > 0 ? ` (${totalRelationships} relationship(s) will also be removed)` : ""
|
|
4929
4981
|
] }),
|
|
4930
4982
|
/* @__PURE__ */ jsxs19("div", { className: "detail-panel__confirm-actions", children: [
|
|
@@ -4933,7 +4985,7 @@ function DetailPanel() {
|
|
|
4933
4985
|
{
|
|
4934
4986
|
className: "detail-panel__button detail-panel__button--danger",
|
|
4935
4987
|
onClick: handleDeleteModel,
|
|
4936
|
-
"aria-label": "Confirm remove
|
|
4988
|
+
"aria-label": "Confirm remove table",
|
|
4937
4989
|
children: "Yes, Remove"
|
|
4938
4990
|
}
|
|
4939
4991
|
),
|
|
@@ -4952,9 +5004,9 @@ function DetailPanel() {
|
|
|
4952
5004
|
{
|
|
4953
5005
|
className: "detail-panel__button detail-panel__button--danger",
|
|
4954
5006
|
onClick: () => setConfirmingDelete(true),
|
|
4955
|
-
title: "Remove this
|
|
4956
|
-
"aria-label": "Remove this
|
|
4957
|
-
children: "Remove from
|
|
5007
|
+
title: "Remove this table from the subject area",
|
|
5008
|
+
"aria-label": "Remove this table from the subject area",
|
|
5009
|
+
children: "Remove from Subject Area"
|
|
4958
5010
|
}
|
|
4959
5011
|
) }),
|
|
4960
5012
|
/* @__PURE__ */ jsx22("div", { className: "detail-panel__section", children: /* @__PURE__ */ jsx22(
|
|
@@ -5000,6 +5052,18 @@ function DetailPanel() {
|
|
|
5000
5052
|
] })
|
|
5001
5053
|
] }),
|
|
5002
5054
|
/* @__PURE__ */ jsx22("span", { className: "detail-panel__rel-cardinality", children: rel.cardinality }),
|
|
5055
|
+
viewer ? null : !isReadOnly && rel.keysContradict && /* @__PURE__ */ jsx22(
|
|
5056
|
+
"button",
|
|
5057
|
+
{
|
|
5058
|
+
className: "detail-panel__rel-backwards",
|
|
5059
|
+
onClick: (e) => {
|
|
5060
|
+
e.stopPropagation();
|
|
5061
|
+
handleTurnRound(rel);
|
|
5062
|
+
},
|
|
5063
|
+
title: `${backwardsRelationshipNote2(rel, rel.pairs ?? [rel])} Click to turn it round.`,
|
|
5064
|
+
children: "\u26A0 Turn round"
|
|
5065
|
+
}
|
|
5066
|
+
),
|
|
5003
5067
|
!isReadOnly && /* @__PURE__ */ jsx22(
|
|
5004
5068
|
"button",
|
|
5005
5069
|
{
|
|
@@ -5044,6 +5108,18 @@ function DetailPanel() {
|
|
|
5044
5108
|
/* @__PURE__ */ jsx22("span", { className: "detail-panel__rel-local", title: columnsText(rel, "to"), children: columnsText(rel, "to") })
|
|
5045
5109
|
] }),
|
|
5046
5110
|
/* @__PURE__ */ jsx22("span", { className: "detail-panel__rel-cardinality", children: rel.cardinality }),
|
|
5111
|
+
viewer ? null : !isReadOnly && rel.keysContradict && /* @__PURE__ */ jsx22(
|
|
5112
|
+
"button",
|
|
5113
|
+
{
|
|
5114
|
+
className: "detail-panel__rel-backwards",
|
|
5115
|
+
onClick: (e) => {
|
|
5116
|
+
e.stopPropagation();
|
|
5117
|
+
handleTurnRound(rel);
|
|
5118
|
+
},
|
|
5119
|
+
title: `${backwardsRelationshipNote2(rel, rel.pairs ?? [rel])} Click to turn it round.`,
|
|
5120
|
+
children: "\u26A0 Turn round"
|
|
5121
|
+
}
|
|
5122
|
+
),
|
|
5047
5123
|
!isReadOnly && /* @__PURE__ */ jsx22(
|
|
5048
5124
|
"button",
|
|
5049
5125
|
{
|
|
@@ -5155,7 +5231,7 @@ function Legend() {
|
|
|
5155
5231
|
] }),
|
|
5156
5232
|
/* @__PURE__ */ jsxs20("div", { className: "legend__item", children: [
|
|
5157
5233
|
/* @__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" }) }),
|
|
5158
|
-
/* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Note linked to
|
|
5234
|
+
/* @__PURE__ */ jsx23("span", { className: "legend__item-desc", children: "Note linked to table" })
|
|
5159
5235
|
] })
|
|
5160
5236
|
] })
|
|
5161
5237
|
] }),
|
|
@@ -5293,10 +5369,10 @@ function Legend() {
|
|
|
5293
5369
|
|
|
5294
5370
|
// src/ErdCanvas.tsx
|
|
5295
5371
|
import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
5296
|
-
function
|
|
5372
|
+
function toRenderableSubjectArea(domain) {
|
|
5297
5373
|
let modelsChanged = false;
|
|
5298
5374
|
const models = (domain.models ?? []).map((model) => {
|
|
5299
|
-
const renderable =
|
|
5375
|
+
const renderable = toRenderableTable(model);
|
|
5300
5376
|
if (renderable !== model) modelsChanged = true;
|
|
5301
5377
|
return renderable;
|
|
5302
5378
|
});
|
|
@@ -5312,7 +5388,7 @@ function toRenderableDomain(domain) {
|
|
|
5312
5388
|
readOnly: true
|
|
5313
5389
|
};
|
|
5314
5390
|
}
|
|
5315
|
-
function
|
|
5391
|
+
function toRenderableTable(model) {
|
|
5316
5392
|
if (model.columns == null) return { ...model, columns: [] };
|
|
5317
5393
|
if (model.columns.every((col) => col.dataType != null)) return model;
|
|
5318
5394
|
return { ...model, columns: model.columns.map(toRenderableColumn) };
|
|
@@ -5501,7 +5577,7 @@ function ErdCanvasInner({
|
|
|
5501
5577
|
);
|
|
5502
5578
|
}
|
|
5503
5579
|
var ErdCanvas = forwardRef(function ErdCanvas2(props, ref) {
|
|
5504
|
-
const renderable = useMemo7(() =>
|
|
5580
|
+
const renderable = useMemo7(() => toRenderableSubjectArea(props.domain), [props.domain]);
|
|
5505
5581
|
const [store] = useState20(() => createCanvasStore({ domain: renderable }));
|
|
5506
5582
|
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 }) }) }) });
|
|
5507
5583
|
});
|
|
@@ -5526,10 +5602,10 @@ export {
|
|
|
5526
5602
|
relationshipDisplayKey,
|
|
5527
5603
|
relationshipEdgeId,
|
|
5528
5604
|
foldComposites,
|
|
5529
|
-
|
|
5530
|
-
|
|
5605
|
+
computeTableLabels,
|
|
5606
|
+
matchesTableSearch,
|
|
5531
5607
|
pickHandleSides,
|
|
5532
|
-
|
|
5608
|
+
transformSubjectArea,
|
|
5533
5609
|
applyNodeOverlays,
|
|
5534
5610
|
useCanvasGraph,
|
|
5535
5611
|
STAGE_HEX,
|
|
@@ -5551,7 +5627,7 @@ export {
|
|
|
5551
5627
|
ADDITIVE_TITLE,
|
|
5552
5628
|
DISCREPANCY_PHRASE,
|
|
5553
5629
|
edgeHoverText,
|
|
5554
|
-
|
|
5630
|
+
TableNode,
|
|
5555
5631
|
swapCardinality,
|
|
5556
5632
|
FkEdge,
|
|
5557
5633
|
ANNOTATION_COLORS,
|
package/dist/editor.js
CHANGED
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
KeyBadge,
|
|
19
19
|
KeyBadgeGroup,
|
|
20
20
|
Legend,
|
|
21
|
-
ModelNode,
|
|
22
21
|
NOOP_CANVAS_HOST,
|
|
23
22
|
SCD_BADGE,
|
|
24
23
|
SCD_TITLE,
|
|
@@ -27,17 +26,18 @@ import {
|
|
|
27
26
|
SOURCE_ORDER,
|
|
28
27
|
SOURCE_PHRASE,
|
|
29
28
|
STAGE_HEX,
|
|
29
|
+
TableNode,
|
|
30
30
|
applyNodeOverlays,
|
|
31
31
|
canvasEdgeTypes,
|
|
32
32
|
canvasNodeTypes,
|
|
33
33
|
columnPairs,
|
|
34
|
-
|
|
34
|
+
computeTableLabels,
|
|
35
35
|
diagramExportFileName,
|
|
36
36
|
edgeHoverText,
|
|
37
37
|
exportDiagram,
|
|
38
38
|
foldComposites,
|
|
39
39
|
getDataTypeColor,
|
|
40
|
-
|
|
40
|
+
matchesTableSearch,
|
|
41
41
|
nodeRect,
|
|
42
42
|
pickHandleSides,
|
|
43
43
|
relationshipDisplayKey,
|
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
swapCardinality,
|
|
48
48
|
toDbml,
|
|
49
49
|
toMermaid,
|
|
50
|
-
|
|
50
|
+
transformSubjectArea,
|
|
51
51
|
useCanvasGraph,
|
|
52
52
|
useCanvasHost,
|
|
53
53
|
useColumnReorder,
|
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
useIsViewer,
|
|
56
56
|
useLongPressDrag,
|
|
57
57
|
useSend
|
|
58
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-HWA32XG5.js";
|
|
59
59
|
import "./chunk-QZGU5NZH.js";
|
|
60
60
|
import "./chunk-6XQXDZ4R.js";
|
|
61
61
|
import {
|
|
@@ -97,7 +97,6 @@ export {
|
|
|
97
97
|
KeyBadge,
|
|
98
98
|
KeyBadgeGroup,
|
|
99
99
|
Legend,
|
|
100
|
-
ModelNode,
|
|
101
100
|
NODE_THRESHOLD,
|
|
102
101
|
NODE_WIDTH,
|
|
103
102
|
NOOP_CANVAS_HOST,
|
|
@@ -108,11 +107,12 @@ export {
|
|
|
108
107
|
SOURCE_ORDER,
|
|
109
108
|
SOURCE_PHRASE,
|
|
110
109
|
STAGE_HEX,
|
|
110
|
+
TableNode,
|
|
111
111
|
applyNodeOverlays,
|
|
112
112
|
canvasEdgeTypes,
|
|
113
113
|
canvasNodeTypes,
|
|
114
114
|
columnPairs,
|
|
115
|
-
|
|
115
|
+
computeTableLabels,
|
|
116
116
|
countVisibleColumnRows,
|
|
117
117
|
createCanvasSlice,
|
|
118
118
|
createCanvasStore,
|
|
@@ -123,7 +123,7 @@ export {
|
|
|
123
123
|
exportDiagram,
|
|
124
124
|
foldComposites,
|
|
125
125
|
getDataTypeColor,
|
|
126
|
-
|
|
126
|
+
matchesTableSearch,
|
|
127
127
|
nodeRect,
|
|
128
128
|
pickHandleSides,
|
|
129
129
|
relationshipDisplayKey,
|
|
@@ -134,7 +134,7 @@ export {
|
|
|
134
134
|
swapCardinality,
|
|
135
135
|
toDbml,
|
|
136
136
|
toMermaid,
|
|
137
|
-
|
|
137
|
+
transformSubjectArea,
|
|
138
138
|
useCanvasGraph,
|
|
139
139
|
useCanvasHost,
|
|
140
140
|
useColumnExpansion,
|