@erd-studio/renderer 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-3PJCC7BX.js → chunk-5OQLRX7R.js} +825 -445
- package/dist/{chunk-HOQPSLHQ.js → chunk-DUQ2TTQH.js} +4 -2
- package/dist/editor.js +6 -2
- package/dist/index.js +2 -2
- package/dist/sizing.js +1 -1
- package/dist/styles.css +234 -0
- package/dist/types/components/DetailPanel/AliasEditor.d.ts +19 -0
- package/dist/types/components/DetailPanel/MetaEditor.d.ts +21 -0
- package/dist/types/components/Graph/HoverTip.d.ts +7 -4
- package/dist/types/components/common/ColumnRowEditor.d.ts +3 -1
- package/dist/types/editor.d.ts +1 -0
- package/dist/types/lib/metaFormat.d.ts +8 -0
- package/dist/types/lib/modelLabels.d.ts +26 -0
- package/dist/types/lib/nodeSizing.d.ts +1 -1
- package/dist/types/types/graph.d.ts +16 -1
- package/package.json +2 -2
|
@@ -57,14 +57,16 @@ var COL_ROW_PADDING = 20;
|
|
|
57
57
|
var COL_ROW_GAPS = 46;
|
|
58
58
|
var EXTRA_BADGE_WIDTH = 30;
|
|
59
59
|
var HEADER_PADDING = 20;
|
|
60
|
+
var CHAR_WIDTH_ID = 6;
|
|
61
|
+
var ID_GAP = 8;
|
|
60
62
|
var LAYER_BADGE_WIDTH = 36;
|
|
61
63
|
var SOURCE_BADGE_WIDTH = 30;
|
|
62
64
|
var WIDTH_SAFETY_MARGIN = 24;
|
|
63
65
|
var MIN_NODE_WIDTH = 220;
|
|
64
66
|
var MAX_NODE_WIDTH = 560;
|
|
65
67
|
function estimateNodeWidth(data) {
|
|
66
|
-
const { modelName, columns, provenance } = data;
|
|
67
|
-
const headerWidth = HEADER_PADDING + modelName.length * CHAR_WIDTH_BODY + LAYER_BADGE_WIDTH + (provenance ? SOURCE_BADGE_WIDTH : 0);
|
|
68
|
+
const { modelName, label, columns, provenance } = data;
|
|
69
|
+
const headerWidth = HEADER_PADDING + (label ? label.length * CHAR_WIDTH_BODY + ID_GAP + modelName.length * CHAR_WIDTH_ID : modelName.length * CHAR_WIDTH_BODY) + LAYER_BADGE_WIDTH + (provenance ? SOURCE_BADGE_WIDTH : 0);
|
|
68
70
|
let maxColWidth = 0;
|
|
69
71
|
for (const col of columns) {
|
|
70
72
|
const keyBadges = (col.isPrimaryKey ? 1 : 0) + (col.isForeignKey ? 1 : 0) + (col.isNaturalKey ? 1 : 0);
|
package/dist/editor.js
CHANGED
|
@@ -28,8 +28,10 @@ import {
|
|
|
28
28
|
applyNodeOverlays,
|
|
29
29
|
canvasEdgeTypes,
|
|
30
30
|
canvasNodeTypes,
|
|
31
|
+
computeModelLabels,
|
|
31
32
|
edgeHoverText,
|
|
32
33
|
getDataTypeColor,
|
|
34
|
+
matchesModelSearch,
|
|
33
35
|
nodeRect,
|
|
34
36
|
pickHandleSides,
|
|
35
37
|
repickHandleSides,
|
|
@@ -43,7 +45,7 @@ import {
|
|
|
43
45
|
useIsViewer,
|
|
44
46
|
useLongPressDrag,
|
|
45
47
|
useSend
|
|
46
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-5OQLRX7R.js";
|
|
47
49
|
import "./chunk-QZGU5NZH.js";
|
|
48
50
|
import "./chunk-6XQXDZ4R.js";
|
|
49
51
|
import {
|
|
@@ -55,7 +57,7 @@ import {
|
|
|
55
57
|
estimateNodeWidth,
|
|
56
58
|
resolveNodeDimensions,
|
|
57
59
|
useColumnExpansion
|
|
58
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-DUQ2TTQH.js";
|
|
59
61
|
import {
|
|
60
62
|
CanvasStoreProvider,
|
|
61
63
|
createCanvasSlice,
|
|
@@ -97,6 +99,7 @@ export {
|
|
|
97
99
|
applyNodeOverlays,
|
|
98
100
|
canvasEdgeTypes,
|
|
99
101
|
canvasNodeTypes,
|
|
102
|
+
computeModelLabels,
|
|
100
103
|
countVisibleColumnRows,
|
|
101
104
|
createCanvasSlice,
|
|
102
105
|
createCanvasStore,
|
|
@@ -104,6 +107,7 @@ export {
|
|
|
104
107
|
estimateNodeHeight,
|
|
105
108
|
estimateNodeWidth,
|
|
106
109
|
getDataTypeColor,
|
|
110
|
+
matchesModelSearch,
|
|
107
111
|
nodeRect,
|
|
108
112
|
pickHandleSides,
|
|
109
113
|
repickHandleSides,
|
package/dist/index.js
CHANGED
package/dist/sizing.js
CHANGED
package/dist/styles.css
CHANGED
|
@@ -219,6 +219,30 @@
|
|
|
219
219
|
.column-tooltip__value {
|
|
220
220
|
font-size: 13px;
|
|
221
221
|
}
|
|
222
|
+
.column-tooltip__meta {
|
|
223
|
+
padding-top: 6px;
|
|
224
|
+
border-top: 1px solid var(--vscode-editorHoverWidget-border, var(--panel-border, #454545));
|
|
225
|
+
display: grid;
|
|
226
|
+
grid-template-columns: minmax(52px, max-content) minmax(0, 1fr);
|
|
227
|
+
column-gap: 10px;
|
|
228
|
+
row-gap: 4px;
|
|
229
|
+
}
|
|
230
|
+
.column-tooltip__meta > .column-tooltip__label {
|
|
231
|
+
grid-column: 1 / -1;
|
|
232
|
+
}
|
|
233
|
+
.column-tooltip__meta .column-tooltip__row {
|
|
234
|
+
display: contents;
|
|
235
|
+
}
|
|
236
|
+
.column-tooltip__details + .column-tooltip__meta {
|
|
237
|
+
margin-top: 6px;
|
|
238
|
+
}
|
|
239
|
+
.column-tooltip__meta-key {
|
|
240
|
+
max-width: 190px;
|
|
241
|
+
overflow-wrap: break-word;
|
|
242
|
+
font-family: var(--vscode-editor-font-family, monospace);
|
|
243
|
+
font-size: 12px;
|
|
244
|
+
color: var(--vscode-descriptionForeground, #888);
|
|
245
|
+
}
|
|
222
246
|
|
|
223
247
|
/* src/components/Graph/HoverTip.css */
|
|
224
248
|
.hover-tip {
|
|
@@ -242,6 +266,24 @@
|
|
|
242
266
|
.hover-tip--visible {
|
|
243
267
|
opacity: 1;
|
|
244
268
|
}
|
|
269
|
+
.hover-tip__rows {
|
|
270
|
+
margin-top: 6px;
|
|
271
|
+
padding-top: 6px;
|
|
272
|
+
border-top: 1px solid var(--vscode-editorHoverWidget-border, var(--panel-border, #454545));
|
|
273
|
+
display: grid;
|
|
274
|
+
grid-template-columns: minmax(52px, max-content) minmax(0, 1fr);
|
|
275
|
+
column-gap: 10px;
|
|
276
|
+
row-gap: 3px;
|
|
277
|
+
}
|
|
278
|
+
.hover-tip__row {
|
|
279
|
+
display: contents;
|
|
280
|
+
}
|
|
281
|
+
.hover-tip__label {
|
|
282
|
+
max-width: 190px;
|
|
283
|
+
overflow-wrap: break-word;
|
|
284
|
+
font-family: var(--vscode-editor-font-family, monospace);
|
|
285
|
+
color: var(--vscode-descriptionForeground, #888);
|
|
286
|
+
}
|
|
245
287
|
|
|
246
288
|
/* src/components/Graph/ModelNode.css */
|
|
247
289
|
.model-node {
|
|
@@ -306,6 +348,13 @@
|
|
|
306
348
|
flex: 1;
|
|
307
349
|
white-space: nowrap;
|
|
308
350
|
}
|
|
351
|
+
.model-node__model-id {
|
|
352
|
+
margin-left: 8px;
|
|
353
|
+
font-family: var(--vscode-editor-font-family, monospace);
|
|
354
|
+
font-size: 10px;
|
|
355
|
+
font-weight: 400;
|
|
356
|
+
color: var(--dim-fg);
|
|
357
|
+
}
|
|
309
358
|
.model-node__badge {
|
|
310
359
|
flex-shrink: 0;
|
|
311
360
|
padding: 1px 5px;
|
|
@@ -634,6 +683,36 @@
|
|
|
634
683
|
font-style: italic;
|
|
635
684
|
text-align: center;
|
|
636
685
|
}
|
|
686
|
+
.model-node__load-error {
|
|
687
|
+
display: flex;
|
|
688
|
+
flex-direction: column;
|
|
689
|
+
align-items: center;
|
|
690
|
+
gap: 6px;
|
|
691
|
+
padding: 8px 10px;
|
|
692
|
+
background: var(--warning-bg);
|
|
693
|
+
color: var(--warning-fg);
|
|
694
|
+
text-align: center;
|
|
695
|
+
}
|
|
696
|
+
.model-node__load-error-text {
|
|
697
|
+
font-size: 11px;
|
|
698
|
+
line-height: 1.4;
|
|
699
|
+
}
|
|
700
|
+
.model-node__load-error-open {
|
|
701
|
+
padding: 2px 10px;
|
|
702
|
+
border: none;
|
|
703
|
+
border-radius: 3px;
|
|
704
|
+
background: var(--button-bg);
|
|
705
|
+
color: var(--button-fg);
|
|
706
|
+
font-size: 11px;
|
|
707
|
+
cursor: pointer;
|
|
708
|
+
}
|
|
709
|
+
.model-node__load-error-open:hover {
|
|
710
|
+
background: var(--button-hover-bg);
|
|
711
|
+
}
|
|
712
|
+
.model-node__load-error-open:focus-visible {
|
|
713
|
+
outline: 1px solid var(--focus-border);
|
|
714
|
+
outline-offset: 1px;
|
|
715
|
+
}
|
|
637
716
|
.model-node__expand-button {
|
|
638
717
|
display: block;
|
|
639
718
|
width: 100%;
|
|
@@ -2046,6 +2125,45 @@ body[data-vscode-theme-kind=vscode-high-contrast] .annotation-node__link-badge {
|
|
|
2046
2125
|
.detail-panel__label--wide {
|
|
2047
2126
|
min-width: 84px;
|
|
2048
2127
|
}
|
|
2128
|
+
.detail-panel__value--muted {
|
|
2129
|
+
color: var(--dim-fg);
|
|
2130
|
+
}
|
|
2131
|
+
.detail-panel__metadata-row--alias .detail-panel__alias-edit-btn {
|
|
2132
|
+
width: 18px;
|
|
2133
|
+
height: 18px;
|
|
2134
|
+
font-size: 11px;
|
|
2135
|
+
}
|
|
2136
|
+
.detail-panel__metadata-row--alias:hover .detail-panel__alias-edit-btn {
|
|
2137
|
+
opacity: 1;
|
|
2138
|
+
}
|
|
2139
|
+
.detail-panel__alias-edit {
|
|
2140
|
+
display: flex;
|
|
2141
|
+
flex: 1;
|
|
2142
|
+
flex-direction: column;
|
|
2143
|
+
gap: 3px;
|
|
2144
|
+
min-width: 0;
|
|
2145
|
+
}
|
|
2146
|
+
.detail-panel__alias-input {
|
|
2147
|
+
padding: 2px 6px;
|
|
2148
|
+
font-family: var(--vscode-editor-font-family, monospace);
|
|
2149
|
+
font-size: 11px;
|
|
2150
|
+
color: var(--input-fg, var(--editor-fg));
|
|
2151
|
+
background: var(--input-bg);
|
|
2152
|
+
border: 1px solid var(--focus-border);
|
|
2153
|
+
border-radius: 3px;
|
|
2154
|
+
outline: none;
|
|
2155
|
+
}
|
|
2156
|
+
.detail-panel__alias-input--error {
|
|
2157
|
+
border-color: var(--error-fg);
|
|
2158
|
+
}
|
|
2159
|
+
.detail-panel__alias-hint {
|
|
2160
|
+
font-size: 10px;
|
|
2161
|
+
line-height: 1.3;
|
|
2162
|
+
color: var(--dim-fg);
|
|
2163
|
+
}
|
|
2164
|
+
.detail-panel__alias-hint--error {
|
|
2165
|
+
color: var(--error-fg);
|
|
2166
|
+
}
|
|
2049
2167
|
.detail-panel__value--provenance {
|
|
2050
2168
|
font-family: inherit;
|
|
2051
2169
|
color: var(--dim-fg);
|
|
@@ -2559,6 +2677,122 @@ body[data-vscode-theme-kind=vscode-high-contrast] .annotation-node__link-badge {
|
|
|
2559
2677
|
.detail-panel__grain-section:hover .detail-panel__rationale-edit-btn {
|
|
2560
2678
|
opacity: 1;
|
|
2561
2679
|
}
|
|
2680
|
+
.meta-editor {
|
|
2681
|
+
display: flex;
|
|
2682
|
+
flex-direction: column;
|
|
2683
|
+
gap: 6px;
|
|
2684
|
+
}
|
|
2685
|
+
.meta-editor__title {
|
|
2686
|
+
margin: 0;
|
|
2687
|
+
}
|
|
2688
|
+
.meta-editor__label {
|
|
2689
|
+
font-size: 10px;
|
|
2690
|
+
text-transform: uppercase;
|
|
2691
|
+
letter-spacing: 0.04em;
|
|
2692
|
+
color: var(--vscode-descriptionForeground, #888);
|
|
2693
|
+
}
|
|
2694
|
+
.meta-editor__list {
|
|
2695
|
+
margin: 0;
|
|
2696
|
+
display: flex;
|
|
2697
|
+
flex-direction: column;
|
|
2698
|
+
gap: 2px;
|
|
2699
|
+
}
|
|
2700
|
+
.meta-editor__row {
|
|
2701
|
+
display: grid;
|
|
2702
|
+
grid-template-columns: minmax(70px, 35%) 1fr auto;
|
|
2703
|
+
align-items: baseline;
|
|
2704
|
+
gap: 8px;
|
|
2705
|
+
padding: 2px 4px;
|
|
2706
|
+
border-radius: 3px;
|
|
2707
|
+
}
|
|
2708
|
+
.meta-editor__row:hover {
|
|
2709
|
+
background: var(--input-bg);
|
|
2710
|
+
}
|
|
2711
|
+
.meta-editor__key {
|
|
2712
|
+
font-family: var(--vscode-editor-font-family);
|
|
2713
|
+
font-size: 11px;
|
|
2714
|
+
color: var(--vscode-descriptionForeground, #888);
|
|
2715
|
+
overflow: hidden;
|
|
2716
|
+
text-overflow: ellipsis;
|
|
2717
|
+
white-space: nowrap;
|
|
2718
|
+
}
|
|
2719
|
+
.meta-editor__value {
|
|
2720
|
+
margin: 0;
|
|
2721
|
+
min-width: 0;
|
|
2722
|
+
font-size: 12px;
|
|
2723
|
+
color: var(--editor-fg);
|
|
2724
|
+
}
|
|
2725
|
+
.meta-editor__text {
|
|
2726
|
+
overflow-wrap: anywhere;
|
|
2727
|
+
}
|
|
2728
|
+
.meta-editor__text--structured {
|
|
2729
|
+
font-family: var(--vscode-editor-font-family);
|
|
2730
|
+
font-size: 11px;
|
|
2731
|
+
color: var(--dim-fg);
|
|
2732
|
+
}
|
|
2733
|
+
.meta-editor__actions {
|
|
2734
|
+
display: flex;
|
|
2735
|
+
gap: 2px;
|
|
2736
|
+
visibility: hidden;
|
|
2737
|
+
}
|
|
2738
|
+
.meta-editor__row:hover .meta-editor__actions,
|
|
2739
|
+
.meta-editor__row:focus-within .meta-editor__actions {
|
|
2740
|
+
visibility: visible;
|
|
2741
|
+
}
|
|
2742
|
+
.meta-editor__icon-btn {
|
|
2743
|
+
border: none;
|
|
2744
|
+
background: transparent;
|
|
2745
|
+
color: var(--vscode-descriptionForeground, #888);
|
|
2746
|
+
cursor: pointer;
|
|
2747
|
+
font-size: 12px;
|
|
2748
|
+
line-height: 1;
|
|
2749
|
+
padding: 1px 3px;
|
|
2750
|
+
}
|
|
2751
|
+
.meta-editor__icon-btn:hover,
|
|
2752
|
+
.meta-editor__icon-btn:focus-visible {
|
|
2753
|
+
color: var(--editor-fg);
|
|
2754
|
+
}
|
|
2755
|
+
.meta-editor__input {
|
|
2756
|
+
width: 100%;
|
|
2757
|
+
box-sizing: border-box;
|
|
2758
|
+
padding: 3px 6px;
|
|
2759
|
+
border: 1px solid var(--panel-border);
|
|
2760
|
+
border-radius: 3px;
|
|
2761
|
+
background: var(--input-bg);
|
|
2762
|
+
color: var(--input-fg);
|
|
2763
|
+
font-size: 12px;
|
|
2764
|
+
}
|
|
2765
|
+
.meta-editor__input:focus {
|
|
2766
|
+
outline: none;
|
|
2767
|
+
border-color: var(--focus-border);
|
|
2768
|
+
}
|
|
2769
|
+
.meta-editor__input--key {
|
|
2770
|
+
font-family: var(--vscode-editor-font-family);
|
|
2771
|
+
}
|
|
2772
|
+
.meta-editor__new {
|
|
2773
|
+
display: flex;
|
|
2774
|
+
flex-direction: column;
|
|
2775
|
+
gap: 4px;
|
|
2776
|
+
}
|
|
2777
|
+
.meta-editor__new-actions {
|
|
2778
|
+
display: flex;
|
|
2779
|
+
gap: 6px;
|
|
2780
|
+
}
|
|
2781
|
+
.meta-editor__error {
|
|
2782
|
+
font-size: 11px;
|
|
2783
|
+
color: var(--error-fg);
|
|
2784
|
+
}
|
|
2785
|
+
.meta-editor__add-btn {
|
|
2786
|
+
align-self: flex-start;
|
|
2787
|
+
}
|
|
2788
|
+
.meta-editor--compact {
|
|
2789
|
+
margin-top: 6px;
|
|
2790
|
+
gap: 4px;
|
|
2791
|
+
}
|
|
2792
|
+
.meta-editor--compact .meta-editor__add-btn {
|
|
2793
|
+
padding: 3px 8px;
|
|
2794
|
+
font-size: 10px;
|
|
2795
|
+
}
|
|
2562
2796
|
|
|
2563
2797
|
/* src/components/Legend/Legend.css */
|
|
2564
2798
|
.legend-toggle {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AliasEditor — the "Table name" row of the detail panel's metadata.
|
|
3
|
+
*
|
|
4
|
+
* A model's name is its identity; its alias is the table dbt builds it as.
|
|
5
|
+
* Setting one is how two layers can each have a `date` table: the models are
|
|
6
|
+
* `silver_date` and `gold_date`, both with the alias `date`.
|
|
7
|
+
*
|
|
8
|
+
* Read mode shows the table name (the model name, dimmed, when there is no
|
|
9
|
+
* alias). Edit mode is a single input: Enter saves, Escape cancels, and an
|
|
10
|
+
* empty value clears the alias.
|
|
11
|
+
*/
|
|
12
|
+
interface AliasEditorProps {
|
|
13
|
+
modelName: string;
|
|
14
|
+
alias?: string;
|
|
15
|
+
/** Physical stage and the viewer: show the value, offer no edit. */
|
|
16
|
+
readOnly: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare function AliasEditor({ modelName, alias, readOnly }: AliasEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MetaEditor — the structured metadata (`meta:`) of a model or a column.
|
|
3
|
+
*
|
|
4
|
+
* Top-level text values are edited in place; a nested map, a list, `true` /
|
|
5
|
+
* `false` or an empty value is shown as it is and edited in the model file,
|
|
6
|
+
* so the canvas never rewrites a value it cannot represent. Every change is
|
|
7
|
+
* posted as an `updateMeta` patch (set or remove one key), never the whole map.
|
|
8
|
+
*/
|
|
9
|
+
import type { Meta } from '@erd-studio/core';
|
|
10
|
+
import { formatMetaValue } from '../../lib/metaFormat.js';
|
|
11
|
+
export { formatMetaValue };
|
|
12
|
+
interface MetaEditorProps {
|
|
13
|
+
modelName: string;
|
|
14
|
+
/** Edit this column's `meta` instead of the model's. */
|
|
15
|
+
columnName?: string;
|
|
16
|
+
meta?: Meta;
|
|
17
|
+
readOnly?: boolean;
|
|
18
|
+
/** Smaller layout for a column row. */
|
|
19
|
+
compact?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare function MetaEditor({ modelName, columnName, meta, readOnly, compact }: MetaEditorProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -14,12 +14,15 @@
|
|
|
14
14
|
* a callback ref rather than in an effect that would re-render.
|
|
15
15
|
*/
|
|
16
16
|
import './HoverTip.css';
|
|
17
|
+
/** Label/value pairs shown under the text, e.g. a model's `meta:` entries. */
|
|
18
|
+
export type HoverTipRows = ReadonlyArray<readonly [string, string]>;
|
|
17
19
|
interface HoverTipProps {
|
|
18
20
|
text: string;
|
|
21
|
+
rows?: HoverTipRows;
|
|
19
22
|
anchorRef: React.RefObject<HTMLElement | null>;
|
|
20
23
|
visible: boolean;
|
|
21
24
|
}
|
|
22
|
-
export declare function HoverTip({ text, anchorRef, visible }: HoverTipProps): import("react").ReactPortal | null;
|
|
25
|
+
export declare function HoverTip({ text, rows, anchorRef, visible }: HoverTipProps): import("react").ReactPortal | null;
|
|
23
26
|
export interface UseHoverTipReturn<T extends HTMLElement> {
|
|
24
27
|
/**
|
|
25
28
|
* Spread onto the element the tip describes.
|
|
@@ -40,8 +43,8 @@ export interface UseHoverTipReturn<T extends HTMLElement> {
|
|
|
40
43
|
/**
|
|
41
44
|
* Attach a hover tip to one element.
|
|
42
45
|
*
|
|
43
|
-
* `aria-label` carries the same text, so the explanation is not
|
|
44
|
-
* screen reader that will never fire a mouseenter.
|
|
46
|
+
* `aria-label` carries the same text (and rows), so the explanation is not
|
|
47
|
+
* lost to a screen reader that will never fire a mouseenter.
|
|
45
48
|
*/
|
|
46
|
-
export declare function useHoverTip<T extends HTMLElement = HTMLElement>(text: string): UseHoverTipReturn<T>;
|
|
49
|
+
export declare function useHoverTip<T extends HTMLElement = HTMLElement>(text: string, rows?: HoverTipRows): UseHoverTipReturn<T>;
|
|
47
50
|
export {};
|
|
@@ -71,5 +71,7 @@ export interface ColumnRowEditorProps {
|
|
|
71
71
|
onSelect?: (e: React.MouseEvent) => void;
|
|
72
72
|
/** Whether the store says this column should enter edit mode (F2). */
|
|
73
73
|
isEditingActive?: boolean;
|
|
74
|
+
/** Rendered at the foot of the expanded area — the column's metadata editor. */
|
|
75
|
+
metaSlot?: React.ReactNode;
|
|
74
76
|
}
|
|
75
|
-
export declare function ColumnRowEditor({ column, mode, existingColumnNames, onUpdate, onDelete, onCancel, showIndicators, showDelete, onTogglePK, onToggleFK, onToggleNK, showMultiplePKWarning, modelRole, expanded, onToggleExpand, dragHandleProps, isDragOver, isBeingDragged, isSelected, onSelect, isEditingActive, }: ColumnRowEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
77
|
+
export declare function ColumnRowEditor({ column, mode, existingColumnNames, onUpdate, onDelete, onCancel, showIndicators, showDelete, onTogglePK, onToggleFK, onToggleNK, showMultiplePKWarning, modelRole, expanded, onToggleExpand, dragHandleProps, isDragOver, isBeingDragged, isSelected, onSelect, isEditingActive, metaSlot, }: ColumnRowEditorProps): import("react/jsx-runtime").JSX.Element;
|
package/dist/types/editor.d.ts
CHANGED
|
@@ -24,4 +24,5 @@ export * from './lib/stageColors.js';
|
|
|
24
24
|
export * from './lib/dataTypeColors.js';
|
|
25
25
|
export * from './lib/badgeLabels.js';
|
|
26
26
|
export { swapCardinality } from './lib/cardinalityUtils.js';
|
|
27
|
+
export { computeModelLabels, matchesModelSearch, type LabelledModel } from './lib/modelLabels.js';
|
|
27
28
|
export { ANNOTATION_COLORS } from './lib/annotationColors.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plain-text rendering of a `meta` map for the canvas hover tips. The value
|
|
3
|
+
* formatter itself is core's, shared with the Detail panel and the CLI.
|
|
4
|
+
*/
|
|
5
|
+
import { formatMetaValue, type Meta } from '@erd-studio/core';
|
|
6
|
+
export { formatMetaValue };
|
|
7
|
+
/** `[key, text]` pairs in file order; empty for a missing or empty map. */
|
|
8
|
+
export declare function metaRows(meta: Meta | undefined): [string, string][];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a model node's header says.
|
|
3
|
+
*
|
|
4
|
+
* A model's NAME is its identity (domain files, relationships, positions); its
|
|
5
|
+
* LABEL is what a person reads. They differ when the model sets an `alias` —
|
|
6
|
+
* the table name dbt builds it as — which is how `silver_date` and `gold_date`
|
|
7
|
+
* can both be the table `date`. Two models on one canvas that would read the
|
|
8
|
+
* same are told apart by schema (`silver.date`, `gold.date`).
|
|
9
|
+
*/
|
|
10
|
+
/** The fields a label is computed from. */
|
|
11
|
+
export interface LabelledModel {
|
|
12
|
+
name: string;
|
|
13
|
+
schema?: string;
|
|
14
|
+
alias?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Header label per model name, for the models whose label differs from their
|
|
18
|
+
* name. A model absent from the map is labelled with its name, exactly as
|
|
19
|
+
* before aliases existed.
|
|
20
|
+
*/
|
|
21
|
+
export declare function computeModelLabels(models: readonly LabelledModel[]): Map<string, string>;
|
|
22
|
+
/** Whether a search query (already lower-cased) matches a model by name or label. */
|
|
23
|
+
export declare function matchesModelSearch(data: {
|
|
24
|
+
modelName: string;
|
|
25
|
+
label?: string;
|
|
26
|
+
}, query: string): boolean;
|
|
@@ -47,4 +47,4 @@ export declare function resolveNodeDimensions(node: Pick<ModelFlowNode, 'data' |
|
|
|
47
47
|
* slightly more space than the minimum estimate, preventing overlap
|
|
48
48
|
* when font rendering or badge widths differ from the approximation.
|
|
49
49
|
*/
|
|
50
|
-
export declare function estimateNodeWidth(data: Pick<ModelNodeData, 'modelName' | 'columns' | 'provenance'>): number;
|
|
50
|
+
export declare function estimateNodeWidth(data: Pick<ModelNodeData, 'modelName' | 'label' | 'columns' | 'provenance'>): number;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* these shapes.
|
|
7
7
|
*/
|
|
8
8
|
import type { Node, Edge } from '@xyflow/react';
|
|
9
|
-
import type { AnnotationColor, Cardinality, Layer, ModelRole, Stage } from '@erd-studio/core';
|
|
9
|
+
import type { AnnotationColor, Cardinality, Layer, Meta, ModelLoadError, ModelRole, Stage } from '@erd-studio/core';
|
|
10
10
|
import type { LayerConfig } from '@erd-studio/core';
|
|
11
11
|
import type { ModelDiscrepancy } from '@erd-studio/core';
|
|
12
12
|
import type { PhysicalProvenance } from '@erd-studio/core';
|
|
@@ -25,11 +25,19 @@ export interface ColumnDisplay {
|
|
|
25
25
|
scdType?: 0 | 1 | 2;
|
|
26
26
|
/** Additive type for fact measure columns. */
|
|
27
27
|
additiveType?: 'additive' | 'semi-additive' | 'non-additive';
|
|
28
|
+
/** Structured metadata (`meta:`) — shown in the tooltip. Absent when empty. */
|
|
29
|
+
meta?: Meta;
|
|
28
30
|
}
|
|
29
31
|
/** Data payload for a ModelNode React Flow node. */
|
|
30
32
|
export type ModelNodeData = {
|
|
31
33
|
/** Model name (unique within a domain). */
|
|
32
34
|
modelName: string;
|
|
35
|
+
/**
|
|
36
|
+
* Header label when it differs from `modelName`: the model's table name
|
|
37
|
+
* (`alias`), qualified by schema when another model on the canvas would read
|
|
38
|
+
* the same. See `computeModelLabels`.
|
|
39
|
+
*/
|
|
40
|
+
label?: string;
|
|
33
41
|
/** The active design stage. */
|
|
34
42
|
stage: Stage;
|
|
35
43
|
/** Data warehouse layer. */
|
|
@@ -56,6 +64,8 @@ export type ModelNodeData = {
|
|
|
56
64
|
grain?: string;
|
|
57
65
|
/** Model's role in the data warehouse architecture. Shown as badge on node. */
|
|
58
66
|
modelRole?: ModelRole;
|
|
67
|
+
/** Structured metadata (`meta:`) — shown in the name's hover tip. Absent when empty. */
|
|
68
|
+
meta?: Meta;
|
|
59
69
|
/** Whether this stage is read-only (physical). */
|
|
60
70
|
readOnly?: boolean;
|
|
61
71
|
/**
|
|
@@ -77,6 +87,11 @@ export type ModelNodeData = {
|
|
|
77
87
|
* off the logical canvas without a stage check.
|
|
78
88
|
*/
|
|
79
89
|
provenance?: PhysicalProvenance;
|
|
90
|
+
/**
|
|
91
|
+
* The model's file exists but could not be read (logical stage only): the
|
|
92
|
+
* node shows the error and an "Open file" button instead of "No columns".
|
|
93
|
+
*/
|
|
94
|
+
loadError?: ModelLoadError;
|
|
80
95
|
/** Whether this model is in stub display mode (PK/NK columns only). */
|
|
81
96
|
isStub: boolean;
|
|
82
97
|
/** Per-model discrepancy data when a cross-stage comparison report is active. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@erd-studio/renderer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "ERD Studio's React Flow canvas: the entity-relationship diagram renderer shared by the VS Code extension, with a read-only viewer mode.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"repository": {
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"prepack": "npm run build"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@erd-studio/core": "0.1.
|
|
49
|
+
"@erd-studio/core": "0.1.2",
|
|
50
50
|
"zustand": "^5.0.0"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|