@peter.prib/renderengine 0.13.0 → 0.15.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/README.md +480 -302
- package/bin/renderengine.mjs +157 -0
- package/dist/renderengine-workspace.umd.js +49217 -37484
- package/dist/renderengine.umd.js +24899 -13093
- package/documentation/REFERENCE.md +68 -1
- package/package.json +13 -3
- package/src/CanvasRenderer.js +225 -200
- package/src/SVGRenderer.js +476 -454
- package/src/archimate.js +22 -2
- package/src/archimateArchiFormat.js +1735 -1701
- package/src/archimateArchive.js +36 -7
- package/src/archimateCSV.js +93 -37
- package/src/archimateDrawio.js +2 -0
- package/src/archimateExchangeFormat.js +3 -1
- package/src/chartCatalog.js +269 -3
- package/src/charting/Annotations.js +169 -0
- package/src/charting/ArchimateDiagramEditor.js +54 -10
- package/src/charting/Axis.js +217 -5
- package/src/charting/Chart.js +99 -9
- package/src/charting/Chart3D.js +7 -2
- package/src/charting/ChartBox.js +8 -1
- package/src/charting/ColorPalette.js +42 -4
- package/src/charting/DiagramEditor.js +174 -39
- package/src/charting/DiagramEditorCommands.js +28 -0
- package/src/charting/Edge.js +7 -0
- package/src/charting/Hierarchy.js +142 -0
- package/src/charting/InteractionManager.js +4 -0
- package/src/charting/ModelFileFormat.js +5 -1
- package/src/charting/SettingsManager.js +35 -0
- package/src/charting/ShapePaths.js +82 -10
- package/src/charting/archimate/ArchimateCsvFileFormat.js +51 -12
- package/src/charting/archimate/ArchimateElementTemplate.js +235 -231
- package/src/charting/ask/AskBar.js +388 -0
- package/src/charting/ask/AskView.js +400 -0
- package/src/charting/charts/AlluvialDiagram.js +311 -0
- package/src/charting/charts/AreaChart.js +69 -15
- package/src/charting/charts/BarChart.js +38 -3
- package/src/charting/charts/BarChart3D.js +6 -4
- package/src/charting/charts/BarChart3DOrbit.js +3 -1
- package/src/charting/charts/BarChartBase.js +26 -6
- package/src/charting/charts/BeeswarmChart.js +164 -0
- package/src/charting/charts/BoxPlotChart.js +25 -3
- package/src/charting/charts/BubbleChart.js +4 -1
- package/src/charting/charts/CalendarHeatmapChart.js +2 -1
- package/src/charting/charts/CandlestickChart.js +172 -4
- package/src/charting/charts/ChordDiagram.js +107 -4
- package/src/charting/charts/CirclePackChart.js +81 -0
- package/src/charting/charts/ComboChart.js +233 -0
- package/src/charting/charts/ContourChart.js +310 -0
- package/src/charting/charts/DensityChart.js +1 -1
- package/src/charting/charts/DonutChart3D.js +13 -0
- package/src/charting/charts/DumbbellChart.js +217 -0
- package/src/charting/charts/EcdfChart.js +150 -0
- package/src/charting/charts/FunnelChart.js +5 -2
- package/src/charting/charts/GeoMapChart.js +132 -11
- package/src/charting/charts/GroupedBarChart.js +44 -3
- package/src/charting/charts/GroupedDistributionChart.js +26 -1
- package/src/charting/charts/HeatmapChart.js +6 -3
- package/src/charting/charts/HexbinChart.js +137 -0
- package/src/charting/charts/HierarchyChart.js +77 -3
- package/src/charting/charts/HistogramChart.js +2 -2
- package/src/charting/charts/HorizonChart.js +105 -0
- package/src/charting/charts/IcicleChart.js +47 -0
- package/src/charting/charts/KagiChart.js +167 -0
- package/src/charting/charts/LineChart.js +74 -18
- package/src/charting/charts/LollipopChart.js +104 -0
- package/src/charting/charts/MarimekkoChart.js +75 -0
- package/src/charting/charts/OhlcChart.js +79 -0
- package/src/charting/charts/OutlineChart.js +10 -8
- package/src/charting/charts/ParallelCoordinatesChart.js +11 -3
- package/src/charting/charts/ParetoChart.js +92 -0
- package/src/charting/charts/PieChart.js +195 -17
- package/src/charting/charts/PieChart3D.js +137 -0
- package/src/charting/charts/PipeChart.js +5 -2
- package/src/charting/charts/PointAndFigureChart.js +198 -0
- package/src/charting/charts/PolarAreaChart.js +189 -0
- package/src/charting/charts/PopulationPyramidChart.js +4 -4
- package/src/charting/charts/RadarChart.js +12 -5
- package/src/charting/charts/RadialBarChart.js +6 -3
- package/src/charting/charts/RenkoChart.js +178 -0
- package/src/charting/charts/RidgelineChart.js +113 -0
- package/src/charting/charts/SankeyDiagram.js +129 -6
- package/src/charting/charts/ScatterChart.js +19 -3
- package/src/charting/charts/ScatterMatrixChart.js +119 -0
- package/src/charting/charts/SlopegraphChart.js +205 -0
- package/src/charting/charts/SparklineTableChart.js +166 -0
- package/src/charting/charts/StackedBarChart.js +125 -11
- package/src/charting/charts/StackedBarChart3DOrbit.js +14 -6
- package/src/charting/charts/StreamGraphChart.js +18 -3
- package/src/charting/charts/SunburstChart.js +28 -8
- package/src/charting/charts/SurfaceChart3D.js +157 -0
- package/src/charting/charts/TreemapChart.js +31 -11
- package/src/charting/charts/ViolinChart.js +20 -2
- package/src/charting/charts/WaterfallChart.js +2 -2
- package/src/charting/charts/WordCloudChart.js +2 -2
- package/src/charting/datamodel/ArchimateDataLink.js +70 -0
- package/src/charting/datamodel/DataLineage.js +150 -0
- package/src/charting/datamodel/DataModel.js +83 -1
- package/src/charting/datamodel/ModelMapping.js +87 -0
- package/src/charting/datamodel/SqlDdl.js +110 -85
- package/src/charting/datamodel/index.js +3 -0
- package/src/charting/decision/DecisionWorkbench.js +295 -0
- package/src/charting/diagrams/ArchimateDiagram.js +25 -9
- package/src/charting/diagrams/ArchimateModel.js +1382 -1238
- package/src/charting/diagrams/GraphDiagram.js +1424 -1350
- package/src/charting/diagrams/SketchView.js +121 -0
- package/src/charting/diagrams/sketchBoxKinds.js +30 -0
- package/src/charting/modelTree/AnalysisPanel.js +101 -23
- package/src/charting/modelTree/NavigatorModel.js +410 -0
- package/src/charting/modelTree/NavigatorPanel.js +453 -0
- package/src/charting/pivot/PivotChart.js +310 -13
- package/src/charting/pivot/PivotGridChart.js +322 -34
- package/src/charting/pivot/PivotView.js +626 -21
- package/src/charting/report/TemplatedReport.js +547 -0
- package/src/charting/templates/BoxTemplate.js +28 -27
- package/src/charting/templates/PackageTemplate.js +26 -25
- package/src/charting/templates/SwimlaneTemplate.js +19 -18
- package/src/charting/templates/Template.js +219 -212
- package/src/cli.js +146 -0
- package/src/index.js +3370 -2899
- package/src/workspace/Workspace.js +126 -7
- package/src/workspace/archimateServices.js +4 -0
- package/src/workspace/parts/ArchimateCanvasPart.js +1 -1
- package/src/workspace/styles.js +36 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { ArchimateModel, ArchimateView } from './ArchimateModel.js';
|
|
2
|
+
import { SKETCH_BOX_KINDS, DEFAULT_SKETCH_PALETTE } from './sketchBoxKinds.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SketchView — a sketch view as Archi has them (archimate:SketchModel):
|
|
6
|
+
* stickies (sketch-model-sticky), stick-figure actors (sketch-model-actor)
|
|
7
|
+
* and plain lines between them, drawn on a background paper or grid.
|
|
8
|
+
*
|
|
9
|
+
* Supports palette editing: custom sticky colours/styles, actor defaults,
|
|
10
|
+
* and importing/exporting palette configurations as JSON.
|
|
11
|
+
*/
|
|
12
|
+
export class SketchView extends ArchimateView {
|
|
13
|
+
static kind = 'sketch';
|
|
14
|
+
|
|
15
|
+
static BOX_KINDS = SKETCH_BOX_KINDS;
|
|
16
|
+
|
|
17
|
+
static BACKGROUNDS = Object.freeze({
|
|
18
|
+
NONE: 0,
|
|
19
|
+
GRID: 1,
|
|
20
|
+
LINES: 2,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
constructor(model, spec = {}) {
|
|
24
|
+
super(model, { archiViewType: 'sketch-model', elementIds: [], ...spec });
|
|
25
|
+
this._palette = spec.palette ? JSON.parse(JSON.stringify(spec.palette)) : [...DEFAULT_SKETCH_PALETTE];
|
|
26
|
+
if (spec.background !== undefined) this.background = spec.background;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** The background kind (0 = none/plain, 1 = grid, 2 = lines). */
|
|
30
|
+
get background() {
|
|
31
|
+
const attr = this.archi?.attributes?.background;
|
|
32
|
+
return attr !== undefined ? Number(attr) : (this._background ?? 0);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
set background(val) {
|
|
36
|
+
const num = Number(val) || 0;
|
|
37
|
+
this._background = num;
|
|
38
|
+
if (!this.archi) this.archi = {};
|
|
39
|
+
if (!this.archi.attributes) this.archi.attributes = {};
|
|
40
|
+
this.archi.attributes.background = String(num);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** The sketch palette presets. */
|
|
44
|
+
get palette() {
|
|
45
|
+
return [...this._palette];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
set palette(entries) {
|
|
49
|
+
if (!Array.isArray(entries)) throw new TypeError('Sketch palette must be an array of entries');
|
|
50
|
+
this._palette = entries.map(e => ({ ...e }));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Add or update a palette entry. */
|
|
54
|
+
setPaletteEntry(entry) {
|
|
55
|
+
if (!entry || !entry.id) throw new TypeError('Palette entry requires an id');
|
|
56
|
+
const idx = this._palette.findIndex(e => e.id === entry.id);
|
|
57
|
+
if (idx >= 0) this._palette[idx] = { ...this._palette[idx], ...entry };
|
|
58
|
+
else this._palette.push({ ...entry });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Remove a palette entry by id. */
|
|
62
|
+
removePaletteEntry(id) {
|
|
63
|
+
this._palette = this._palette.filter(e => e.id !== id);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Export the palette as a JSON string or object. */
|
|
67
|
+
exportPalette({ asString = true } = {}) {
|
|
68
|
+
const data = {
|
|
69
|
+
version: 1,
|
|
70
|
+
viewKind: 'sketch',
|
|
71
|
+
background: this.background,
|
|
72
|
+
entries: this.palette,
|
|
73
|
+
};
|
|
74
|
+
return asString ? JSON.stringify(data, null, 2) : data;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Import a palette from a JSON string or object. */
|
|
78
|
+
importPalette(source) {
|
|
79
|
+
const data = typeof source === 'string' ? JSON.parse(source) : source;
|
|
80
|
+
if (!data || !Array.isArray(data.entries)) {
|
|
81
|
+
throw new TypeError('Invalid sketch palette format: entries array expected');
|
|
82
|
+
}
|
|
83
|
+
if (data.background !== undefined) this.background = data.background;
|
|
84
|
+
this.palette = data.entries;
|
|
85
|
+
return this.palette;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** CSS background styles matching this sketch's background setting. */
|
|
89
|
+
backgroundStyle() {
|
|
90
|
+
switch (this.background) {
|
|
91
|
+
case 1: // Grid
|
|
92
|
+
return {
|
|
93
|
+
backgroundImage: 'linear-gradient(#e5e7eb 1px, transparent 1px), linear-gradient(90deg, #e5e7eb 1px, transparent 1px)',
|
|
94
|
+
backgroundSize: '20px 20px',
|
|
95
|
+
backgroundColor: '#fafafa',
|
|
96
|
+
};
|
|
97
|
+
case 2: // Lines
|
|
98
|
+
return {
|
|
99
|
+
backgroundImage: 'linear-gradient(#e5e7eb 1px, transparent 1px)',
|
|
100
|
+
backgroundSize: '100% 24px',
|
|
101
|
+
backgroundColor: '#fffdfa',
|
|
102
|
+
};
|
|
103
|
+
case 0: // Plain
|
|
104
|
+
default:
|
|
105
|
+
return {
|
|
106
|
+
backgroundColor: '#ffffff',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
toJSON() {
|
|
112
|
+
return {
|
|
113
|
+
...super.toJSON(),
|
|
114
|
+
background: this.background,
|
|
115
|
+
palette: this.palette,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Self-register with ArchimateModel
|
|
121
|
+
ArchimateModel.registerViewType('sketch-model', SketchView);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { CanvasBoxKind } from '../canvas/CanvasBoxKind.js';
|
|
2
|
+
|
|
3
|
+
export const DEFAULT_SKETCH_PALETTE = Object.freeze([
|
|
4
|
+
{ id: 'sticky-yellow', name: 'Yellow Sticky', color: '#fff59d', type: 'sticky' },
|
|
5
|
+
{ id: 'sticky-green', name: 'Green Sticky', color: '#c8e6c9', type: 'sticky' },
|
|
6
|
+
{ id: 'sticky-blue', name: 'Blue Sticky', color: '#bbdefb', type: 'sticky' },
|
|
7
|
+
{ id: 'sticky-pink', name: 'Pink Sticky', color: '#f8bbd0', type: 'sticky' },
|
|
8
|
+
{ id: 'sticky-orange', name: 'Orange Sticky', color: '#ffe0b2', type: 'sticky' },
|
|
9
|
+
{ id: 'sticky-white', name: 'White Sticky', color: '#ffffff', type: 'sticky' },
|
|
10
|
+
{ id: 'actor', name: 'Actor', color: '#000000', type: 'actor' },
|
|
11
|
+
]);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Archi's sketch palette: Stickies and Actors (stick figures).
|
|
15
|
+
*/
|
|
16
|
+
export const SKETCH_BOX_KINDS = Object.freeze([
|
|
17
|
+
new CanvasBoxKind({
|
|
18
|
+
key: 'sticky', label: 'Sticky', icon: '🗒', archiVisualType: 'sketch-model-sticky', width: 120, height: 80,
|
|
19
|
+
appearance: { fillColor: '#fff59d', strokeColor: 'none', textAlign: 'center', textPosition: 'middle' },
|
|
20
|
+
}),
|
|
21
|
+
new CanvasBoxKind({
|
|
22
|
+
key: 'actor', label: 'Actor', icon: '👤', archiVisualType: 'sketch-model-actor', width: 60, height: 100, shape: 'stick-figure',
|
|
23
|
+
appearance: { strokeColor: '#000000', textAlign: 'center', textPosition: 'top' },
|
|
24
|
+
}),
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
/** A sketch box kind by key, or undefined. */
|
|
28
|
+
export function sketchBoxKind(key) {
|
|
29
|
+
return SKETCH_BOX_KINDS.find(k => k.key === key);
|
|
30
|
+
}
|
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
import { treeLayerOf } from './ModelTreePanel.js';
|
|
2
2
|
import { typeTitle } from '../archimate/archimateNames.js';
|
|
3
|
+
import { NavigatorPanel } from './NavigatorPanel.js';
|
|
4
|
+
|
|
5
|
+
export { NavigatorPanel, buildNavigatorPanel } from './NavigatorPanel.js';
|
|
6
|
+
export { NavigatorModel } from './NavigatorModel.js';
|
|
7
|
+
|
|
8
|
+
let currentAnalysisMode = 'analysis';
|
|
9
|
+
|
|
10
|
+
export function setAnalysisMode(mode) {
|
|
11
|
+
if (mode === 'analysis' || mode === 'navigator') {
|
|
12
|
+
currentAnalysisMode = mode;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function getAnalysisMode() {
|
|
17
|
+
return currentAnalysisMode;
|
|
18
|
+
}
|
|
19
|
+
|
|
3
20
|
/**
|
|
4
21
|
* Builds analysis data for a selected element: "Used in Views", incoming/outgoing relationships.
|
|
5
22
|
*/
|
|
6
23
|
export function buildAnalysisData(model, elementId) {
|
|
7
|
-
const element = model
|
|
24
|
+
const element = model?.getElement(elementId);
|
|
8
25
|
if (!element) return null;
|
|
9
26
|
|
|
10
27
|
const rels = model.relationshipsFor(elementId);
|
|
@@ -18,35 +35,88 @@ export function buildAnalysisData(model, elementId) {
|
|
|
18
35
|
}
|
|
19
36
|
|
|
20
37
|
/**
|
|
21
|
-
* DOM shell for rendering analysis panel.
|
|
38
|
+
* DOM shell for rendering analysis and visual navigator panel.
|
|
22
39
|
* Builds via doc.createElement/Object.assign, never innerHTML.
|
|
23
40
|
*/
|
|
24
|
-
export function buildAnalysisPanel(doc, { model, elementId, onSelectItem = () => {} } = {}) {
|
|
41
|
+
export function buildAnalysisPanel(doc, { model, elementId, onSelectItem = () => {}, onSelectView = () => {} } = {}) {
|
|
25
42
|
const panel = doc.createElement('div');
|
|
26
43
|
panel.style.cssText = `
|
|
27
44
|
display: flex;
|
|
28
45
|
flex-direction: column;
|
|
29
46
|
height: 100%;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
font-family: sans-serif;
|
|
47
|
+
padding: 6px 8px;
|
|
48
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
33
49
|
font-size: 13px;
|
|
34
50
|
overflow: hidden;
|
|
51
|
+
background: #fff;
|
|
35
52
|
`;
|
|
36
53
|
|
|
54
|
+
// Mode tabs: [ Analysis | Navigator ]
|
|
55
|
+
const header = doc.createElement('div');
|
|
56
|
+
header.style.cssText = 'display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid #e1e4e8; padding-bottom: 4px; margin-bottom: 6px; flex-shrink: 0;';
|
|
57
|
+
|
|
58
|
+
const tabs = doc.createElement('div');
|
|
59
|
+
tabs.style.cssText = 'display: flex; gap: 4px;';
|
|
60
|
+
|
|
61
|
+
const makeTab = (key, label) => {
|
|
62
|
+
const t = doc.createElement('button');
|
|
63
|
+
t.type = 'button';
|
|
64
|
+
t.textContent = label;
|
|
65
|
+
const active = (currentAnalysisMode === key);
|
|
66
|
+
t.style.cssText = `
|
|
67
|
+
font-size: 11px;
|
|
68
|
+
padding: 2px 8px;
|
|
69
|
+
border: 1px solid ${active ? '#0366d6' : '#d1d5da'};
|
|
70
|
+
border-radius: 3px;
|
|
71
|
+
background: ${active ? '#0366d6' : '#fff'};
|
|
72
|
+
color: ${active ? '#fff' : '#333'};
|
|
73
|
+
cursor: pointer;
|
|
74
|
+
font-weight: ${active ? '600' : 'normal'};
|
|
75
|
+
`;
|
|
76
|
+
t.addEventListener('click', () => {
|
|
77
|
+
currentAnalysisMode = key;
|
|
78
|
+
const updated = buildAnalysisPanel(doc, { model, elementId, onSelectItem, onSelectView });
|
|
79
|
+
panel.replaceWith(updated);
|
|
80
|
+
});
|
|
81
|
+
return t;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
tabs.appendChild(makeTab('analysis', 'Analysis'));
|
|
85
|
+
tabs.appendChild(makeTab('navigator', 'Navigator'));
|
|
86
|
+
header.appendChild(tabs);
|
|
87
|
+
panel.appendChild(header);
|
|
88
|
+
|
|
89
|
+
// If Navigator mode is active, render the step-by-step NavigatorPanel
|
|
90
|
+
if (currentAnalysisMode === 'navigator') {
|
|
91
|
+
const navPanel = new NavigatorPanel(doc, {
|
|
92
|
+
model,
|
|
93
|
+
elementId,
|
|
94
|
+
onSelectItem,
|
|
95
|
+
onSelectView,
|
|
96
|
+
});
|
|
97
|
+
const navWrap = doc.createElement('div');
|
|
98
|
+
navWrap.style.cssText = 'flex: 1; overflow: hidden; display: flex; flex-direction: column; min-height: 0;';
|
|
99
|
+
navWrap.appendChild(navPanel.dom);
|
|
100
|
+
panel.appendChild(navWrap);
|
|
101
|
+
return panel;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Default Analysis summary mode
|
|
37
105
|
const data = buildAnalysisData(model, elementId);
|
|
38
106
|
if (!data) {
|
|
39
|
-
|
|
107
|
+
const empty = doc.createElement('div');
|
|
108
|
+
empty.style.cssText = 'color: #888; font-style: italic; padding: 12px; text-align: center;';
|
|
109
|
+
empty.textContent = '(No element selected)';
|
|
110
|
+
panel.appendChild(empty);
|
|
40
111
|
return panel;
|
|
41
112
|
}
|
|
42
113
|
|
|
43
114
|
// Element details
|
|
44
115
|
const detailsDiv = doc.createElement('div');
|
|
45
|
-
detailsDiv.style.cssText = 'padding: 8px; background: #
|
|
116
|
+
detailsDiv.style.cssText = 'padding: 8px; background: #f6f8fa; border: 1px solid #e1e4e8; border-radius: 4px; margin-bottom: 8px; flex-shrink: 0;';
|
|
46
117
|
|
|
47
118
|
const nameRow = Object.assign(doc.createElement('div'), { textContent: `Name: ${data.element.name || '(unnamed)'}` });
|
|
48
|
-
const typeRow = Object.assign(doc.createElement('div'), { textContent: `Type: ${data.element.type}` });
|
|
49
|
-
// Its layer as the diagram draws it (a stored one, else its type's), as the tree files it.
|
|
119
|
+
const typeRow = Object.assign(doc.createElement('div'), { textContent: `Type: ${typeTitle(data.element.type)}` });
|
|
50
120
|
const layerRow = Object.assign(doc.createElement('div'), { textContent: `Layer: ${typeTitle(treeLayerOf(data.element))}` });
|
|
51
121
|
|
|
52
122
|
detailsDiv.appendChild(nameRow);
|
|
@@ -54,28 +124,34 @@ export function buildAnalysisPanel(doc, { model, elementId, onSelectItem = () =>
|
|
|
54
124
|
detailsDiv.appendChild(layerRow);
|
|
55
125
|
panel.appendChild(detailsDiv);
|
|
56
126
|
|
|
127
|
+
const bodyDiv = doc.createElement('div');
|
|
128
|
+
bodyDiv.style.cssText = 'flex: 1; overflow-y: auto; min-height: 0; display: flex; flex-direction: column; gap: 8px;';
|
|
129
|
+
|
|
57
130
|
// Used in Views
|
|
58
131
|
const usedDiv = doc.createElement('div');
|
|
59
132
|
usedDiv.style.cssText = 'flex-shrink: 0;';
|
|
60
133
|
|
|
61
134
|
const usedLabel = Object.assign(doc.createElement('div'), {
|
|
62
135
|
textContent: `Used in Views (${data.usedInViews.length})`,
|
|
63
|
-
style: 'font-weight:
|
|
136
|
+
style: 'font-weight: 600; font-size: 11px; color: #586069; text-transform: uppercase; margin-bottom: 4px;',
|
|
64
137
|
});
|
|
65
138
|
usedDiv.appendChild(usedLabel);
|
|
66
139
|
|
|
67
140
|
if (data.usedInViews.length === 0) {
|
|
68
141
|
usedDiv.appendChild(Object.assign(doc.createElement('div'), {
|
|
69
142
|
textContent: '(no views)',
|
|
70
|
-
style: 'font-size: 12px; color: #
|
|
143
|
+
style: 'font-size: 12px; color: #888;',
|
|
71
144
|
}));
|
|
72
145
|
} else {
|
|
73
146
|
for (const view of data.usedInViews) {
|
|
74
|
-
const row = buildAnalysisRow(doc, view.name, () =>
|
|
147
|
+
const row = buildAnalysisRow(doc, view.name || 'View', () => {
|
|
148
|
+
onSelectView(view.id);
|
|
149
|
+
onSelectItem({ kind: 'view', id: view.id });
|
|
150
|
+
});
|
|
75
151
|
usedDiv.appendChild(row);
|
|
76
152
|
}
|
|
77
153
|
}
|
|
78
|
-
|
|
154
|
+
bodyDiv.appendChild(usedDiv);
|
|
79
155
|
|
|
80
156
|
// Incoming relationships
|
|
81
157
|
const incomingDiv = doc.createElement('div');
|
|
@@ -83,24 +159,24 @@ export function buildAnalysisPanel(doc, { model, elementId, onSelectItem = () =>
|
|
|
83
159
|
|
|
84
160
|
const incomingLabel = Object.assign(doc.createElement('div'), {
|
|
85
161
|
textContent: `Incoming (${data.incoming.length})`,
|
|
86
|
-
style: 'font-weight:
|
|
162
|
+
style: 'font-weight: 600; font-size: 11px; color: #586069; text-transform: uppercase; margin-bottom: 4px; margin-top: 4px;',
|
|
87
163
|
});
|
|
88
164
|
incomingDiv.appendChild(incomingLabel);
|
|
89
165
|
|
|
90
166
|
if (data.incoming.length === 0) {
|
|
91
167
|
incomingDiv.appendChild(Object.assign(doc.createElement('div'), {
|
|
92
168
|
textContent: '(none)',
|
|
93
|
-
style: 'font-size: 12px; color: #
|
|
169
|
+
style: 'font-size: 12px; color: #888;',
|
|
94
170
|
}));
|
|
95
171
|
} else {
|
|
96
172
|
for (const rel of data.incoming) {
|
|
97
173
|
const source = model.getElement(rel.source);
|
|
98
|
-
const label = `${source?.name || rel.source} → ${rel.kind}`;
|
|
174
|
+
const label = `${source?.name || rel.source} → ${typeTitle(rel.kind)}`;
|
|
99
175
|
const row = buildAnalysisRow(doc, label, () => onSelectItem({ kind: 'relationship', id: rel.id }));
|
|
100
176
|
incomingDiv.appendChild(row);
|
|
101
177
|
}
|
|
102
178
|
}
|
|
103
|
-
|
|
179
|
+
bodyDiv.appendChild(incomingDiv);
|
|
104
180
|
|
|
105
181
|
// Outgoing relationships
|
|
106
182
|
const outgoingDiv = doc.createElement('div');
|
|
@@ -108,25 +184,26 @@ export function buildAnalysisPanel(doc, { model, elementId, onSelectItem = () =>
|
|
|
108
184
|
|
|
109
185
|
const outgoingLabel = Object.assign(doc.createElement('div'), {
|
|
110
186
|
textContent: `Outgoing (${data.outgoing.length})`,
|
|
111
|
-
style: 'font-weight:
|
|
187
|
+
style: 'font-weight: 600; font-size: 11px; color: #586069; text-transform: uppercase; margin-bottom: 4px; margin-top: 4px; flex-shrink: 0;',
|
|
112
188
|
});
|
|
113
189
|
outgoingDiv.appendChild(outgoingLabel);
|
|
114
190
|
|
|
115
191
|
if (data.outgoing.length === 0) {
|
|
116
192
|
outgoingDiv.appendChild(Object.assign(doc.createElement('div'), {
|
|
117
193
|
textContent: '(none)',
|
|
118
|
-
style: 'font-size: 12px; color: #
|
|
194
|
+
style: 'font-size: 12px; color: #888;',
|
|
119
195
|
}));
|
|
120
196
|
} else {
|
|
121
197
|
for (const rel of data.outgoing) {
|
|
122
198
|
const target = model.getElement(rel.target);
|
|
123
|
-
const label = `${rel.kind} → ${target?.name || rel.target}`;
|
|
199
|
+
const label = `${typeTitle(rel.kind)} → ${target?.name || rel.target}`;
|
|
124
200
|
const row = buildAnalysisRow(doc, label, () => onSelectItem({ kind: 'relationship', id: rel.id }));
|
|
125
201
|
outgoingDiv.appendChild(row);
|
|
126
202
|
}
|
|
127
203
|
}
|
|
128
|
-
|
|
204
|
+
bodyDiv.appendChild(outgoingDiv);
|
|
129
205
|
|
|
206
|
+
panel.appendChild(bodyDiv);
|
|
130
207
|
return panel;
|
|
131
208
|
}
|
|
132
209
|
|
|
@@ -143,13 +220,14 @@ function buildAnalysisRow(doc, label, onClick) {
|
|
|
143
220
|
cursor: pointer;
|
|
144
221
|
user-select: none;
|
|
145
222
|
font-size: 12px;
|
|
223
|
+
color: #24292e;
|
|
146
224
|
transition: background-color 0.1s;
|
|
147
225
|
`;
|
|
148
226
|
row.textContent = label;
|
|
149
227
|
|
|
150
228
|
row.addEventListener('click', onClick);
|
|
151
229
|
row.addEventListener('mouseenter', () => {
|
|
152
|
-
row.style.background = '#
|
|
230
|
+
row.style.background = '#f1f3f5';
|
|
153
231
|
});
|
|
154
232
|
row.addEventListener('mouseleave', () => {
|
|
155
233
|
row.style.background = '';
|