@myop/cli 0.1.6 → 0.1.8
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.
|
@@ -1,5 +1,101 @@
|
|
|
1
1
|
const SVG_NS = 'http://www.w3.org/2000/svg';
|
|
2
2
|
|
|
3
|
+
// Storage keys
|
|
4
|
+
const STORAGE_KEYS = {
|
|
5
|
+
REQUEST_LOG: 'myop_dev_request_log',
|
|
6
|
+
ORIGINS: 'myop_dev_origins',
|
|
7
|
+
COMPONENT_LINES: 'myop_dev_component_lines',
|
|
8
|
+
NODE_POSITIONS: 'myop_dev_node_positions',
|
|
9
|
+
EXPANDED_LABELS: 'myop_dev_expanded_labels',
|
|
10
|
+
ZOOM_LEVEL: 'myop_dev_zoom_level',
|
|
11
|
+
PAN_X: 'myop_dev_pan_x',
|
|
12
|
+
PAN_Y: 'myop_dev_pan_y'
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// Load data from localStorage
|
|
16
|
+
function loadFromStorage() {
|
|
17
|
+
try {
|
|
18
|
+
// Load request log
|
|
19
|
+
const savedRequestLog = localStorage.getItem(STORAGE_KEYS.REQUEST_LOG);
|
|
20
|
+
if (savedRequestLog) {
|
|
21
|
+
requestLog = JSON.parse(savedRequestLog);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Load origins
|
|
25
|
+
const savedOrigins = localStorage.getItem(STORAGE_KEYS.ORIGINS);
|
|
26
|
+
if (savedOrigins) {
|
|
27
|
+
origins = JSON.parse(savedOrigins);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Load component lines
|
|
31
|
+
const savedComponentLines = localStorage.getItem(STORAGE_KEYS.COMPONENT_LINES);
|
|
32
|
+
if (savedComponentLines) {
|
|
33
|
+
const parsed = JSON.parse(savedComponentLines);
|
|
34
|
+
componentLines = new Map(Object.entries(parsed));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Load node positions
|
|
38
|
+
const savedNodePositions = localStorage.getItem(STORAGE_KEYS.NODE_POSITIONS);
|
|
39
|
+
if (savedNodePositions) {
|
|
40
|
+
const parsed = JSON.parse(savedNodePositions);
|
|
41
|
+
nodePositions = new Map(Object.entries(parsed));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Load expanded labels
|
|
45
|
+
const savedExpandedLabels = localStorage.getItem(STORAGE_KEYS.EXPANDED_LABELS);
|
|
46
|
+
if (savedExpandedLabels) {
|
|
47
|
+
expandedLabels = new Set(JSON.parse(savedExpandedLabels));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Load zoom and pan state
|
|
51
|
+
const savedZoomLevel = localStorage.getItem(STORAGE_KEYS.ZOOM_LEVEL);
|
|
52
|
+
if (savedZoomLevel) {
|
|
53
|
+
zoomLevel = parseFloat(savedZoomLevel);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const savedPanX = localStorage.getItem(STORAGE_KEYS.PAN_X);
|
|
57
|
+
if (savedPanX) {
|
|
58
|
+
panX = parseFloat(savedPanX);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const savedPanY = localStorage.getItem(STORAGE_KEYS.PAN_Y);
|
|
62
|
+
if (savedPanY) {
|
|
63
|
+
panY = parseFloat(savedPanY);
|
|
64
|
+
}
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error('Error loading from localStorage:', error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Save data to localStorage
|
|
71
|
+
function saveToStorage() {
|
|
72
|
+
try {
|
|
73
|
+
// Save request log
|
|
74
|
+
localStorage.setItem(STORAGE_KEYS.REQUEST_LOG, JSON.stringify(requestLog));
|
|
75
|
+
|
|
76
|
+
// Save origins
|
|
77
|
+
localStorage.setItem(STORAGE_KEYS.ORIGINS, JSON.stringify(origins));
|
|
78
|
+
|
|
79
|
+
// Save component lines (convert Map to object)
|
|
80
|
+
const componentLinesObj = Object.fromEntries(componentLines);
|
|
81
|
+
localStorage.setItem(STORAGE_KEYS.COMPONENT_LINES, JSON.stringify(componentLinesObj));
|
|
82
|
+
|
|
83
|
+
// Save node positions (convert Map to object)
|
|
84
|
+
const nodePositionsObj = Object.fromEntries(nodePositions);
|
|
85
|
+
localStorage.setItem(STORAGE_KEYS.NODE_POSITIONS, JSON.stringify(nodePositionsObj));
|
|
86
|
+
|
|
87
|
+
// Save expanded labels (convert Set to array)
|
|
88
|
+
localStorage.setItem(STORAGE_KEYS.EXPANDED_LABELS, JSON.stringify(Array.from(expandedLabels)));
|
|
89
|
+
|
|
90
|
+
// Save zoom and pan state
|
|
91
|
+
localStorage.setItem(STORAGE_KEYS.ZOOM_LEVEL, zoomLevel.toString());
|
|
92
|
+
localStorage.setItem(STORAGE_KEYS.PAN_X, panX.toString());
|
|
93
|
+
localStorage.setItem(STORAGE_KEYS.PAN_Y, panY.toString());
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.error('Error saving to localStorage:', error);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
3
99
|
// Initialize data
|
|
4
100
|
let components = []; // Array of {id, path, name}
|
|
5
101
|
let origins = [];
|
|
@@ -22,6 +118,9 @@ let panY = 0;
|
|
|
22
118
|
let isPanning = false;
|
|
23
119
|
let panStart = { x: 0, y: 0 };
|
|
24
120
|
|
|
121
|
+
// Load persisted data on startup
|
|
122
|
+
loadFromStorage();
|
|
123
|
+
|
|
25
124
|
// Connect to SSE
|
|
26
125
|
const eventSource = new EventSource('/events');
|
|
27
126
|
|
|
@@ -32,13 +131,36 @@ eventSource.onmessage = (event) => {
|
|
|
32
131
|
components = data.components;
|
|
33
132
|
updateComponentsList();
|
|
34
133
|
renderArchitecture();
|
|
134
|
+
saveToStorage();
|
|
35
135
|
} else if (data.type === 'origins') {
|
|
36
|
-
origins
|
|
136
|
+
// Merge new origins with existing ones from localStorage
|
|
137
|
+
const existingOriginsMap = new Map(origins.map(o => [o.url, o]));
|
|
138
|
+
data.origins.forEach(newOrigin => {
|
|
139
|
+
const existing = existingOriginsMap.get(newOrigin.url);
|
|
140
|
+
if (existing) {
|
|
141
|
+
// Keep the higher request count
|
|
142
|
+
newOrigin.requestCount = Math.max(existing.requestCount, newOrigin.requestCount);
|
|
143
|
+
}
|
|
144
|
+
existingOriginsMap.set(newOrigin.url, newOrigin);
|
|
145
|
+
});
|
|
146
|
+
origins = Array.from(existingOriginsMap.values());
|
|
37
147
|
renderArchitecture();
|
|
148
|
+
saveToStorage();
|
|
38
149
|
} else if (data.type === 'requestLog') {
|
|
39
|
-
|
|
150
|
+
// Merge server log with existing log from localStorage
|
|
151
|
+
const existingTimestamps = new Set(requestLog.map(r => r.timestamp));
|
|
152
|
+
data.log.forEach(entry => {
|
|
153
|
+
if (!existingTimestamps.has(entry.timestamp)) {
|
|
154
|
+
requestLog.push(entry);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
// Keep only the most recent entries
|
|
158
|
+
if (requestLog.length > 100) {
|
|
159
|
+
requestLog = requestLog.slice(-100);
|
|
160
|
+
}
|
|
40
161
|
updateActivityLog();
|
|
41
162
|
updateStats();
|
|
163
|
+
saveToStorage();
|
|
42
164
|
} else if (data.type === 'request') {
|
|
43
165
|
handleNewRequest(data);
|
|
44
166
|
}
|
|
@@ -91,6 +213,9 @@ function drag(evt) {
|
|
|
91
213
|
}
|
|
92
214
|
|
|
93
215
|
function endDrag(evt) {
|
|
216
|
+
if (draggedElement) {
|
|
217
|
+
saveToStorage(); // Save node positions after drag
|
|
218
|
+
}
|
|
94
219
|
draggedElement = null;
|
|
95
220
|
evt.preventDefault();
|
|
96
221
|
}
|
|
@@ -140,11 +265,13 @@ function updateViewBox() {
|
|
|
140
265
|
function zoomIn() {
|
|
141
266
|
zoomLevel = Math.min(zoomLevel * 1.2, 5);
|
|
142
267
|
updateViewBox();
|
|
268
|
+
saveToStorage();
|
|
143
269
|
}
|
|
144
270
|
|
|
145
271
|
function zoomOut() {
|
|
146
272
|
zoomLevel = Math.max(zoomLevel / 1.2, 0.5);
|
|
147
273
|
updateViewBox();
|
|
274
|
+
saveToStorage();
|
|
148
275
|
}
|
|
149
276
|
|
|
150
277
|
function resetZoom() {
|
|
@@ -152,6 +279,7 @@ function resetZoom() {
|
|
|
152
279
|
panX = 0;
|
|
153
280
|
panY = 0;
|
|
154
281
|
updateViewBox();
|
|
282
|
+
saveToStorage();
|
|
155
283
|
}
|
|
156
284
|
|
|
157
285
|
function handleWheel(e) {
|
|
@@ -159,6 +287,7 @@ function handleWheel(e) {
|
|
|
159
287
|
const delta = e.deltaY > 0 ? 0.9 : 1.1;
|
|
160
288
|
zoomLevel = Math.max(0.5, Math.min(5, zoomLevel * delta));
|
|
161
289
|
updateViewBox();
|
|
290
|
+
saveToStorage();
|
|
162
291
|
}
|
|
163
292
|
|
|
164
293
|
function startPan(e) {
|
|
@@ -182,6 +311,7 @@ function endPan() {
|
|
|
182
311
|
isPanning = false;
|
|
183
312
|
const svg = document.getElementById('architecture-svg');
|
|
184
313
|
svg.classList.remove('panning');
|
|
314
|
+
saveToStorage(); // Save pan position after panning
|
|
185
315
|
}
|
|
186
316
|
}
|
|
187
317
|
|
|
@@ -602,6 +732,7 @@ function redrawRequestLines() {
|
|
|
602
732
|
expandedLabels.add(labelKey);
|
|
603
733
|
}
|
|
604
734
|
redrawRequestLines();
|
|
735
|
+
saveToStorage();
|
|
605
736
|
};
|
|
606
737
|
|
|
607
738
|
const labelBg = document.createElementNS(SVG_NS, 'rect');
|
|
@@ -669,6 +800,7 @@ function redrawRequestLines() {
|
|
|
669
800
|
expandedLabels.add(labelKey2);
|
|
670
801
|
}
|
|
671
802
|
redrawRequestLines();
|
|
803
|
+
saveToStorage();
|
|
672
804
|
};
|
|
673
805
|
|
|
674
806
|
const labelBg2 = document.createElementNS(SVG_NS, 'rect');
|
|
@@ -760,6 +892,12 @@ function updateStats() {
|
|
|
760
892
|
|
|
761
893
|
function handleNewRequest(data) {
|
|
762
894
|
requestLog.push(data);
|
|
895
|
+
|
|
896
|
+
// Keep log size limited
|
|
897
|
+
if (requestLog.length > 100) {
|
|
898
|
+
requestLog.shift();
|
|
899
|
+
}
|
|
900
|
+
|
|
763
901
|
updateActivityLog();
|
|
764
902
|
updateStats();
|
|
765
903
|
|
|
@@ -780,8 +918,48 @@ function handleNewRequest(data) {
|
|
|
780
918
|
|
|
781
919
|
// Redraw lines
|
|
782
920
|
redrawRequestLines();
|
|
921
|
+
|
|
922
|
+
// Save to localStorage
|
|
923
|
+
saveToStorage();
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// Add clear data button functionality
|
|
927
|
+
function clearStoredData() {
|
|
928
|
+
if (confirm('Clear all stored data (request logs, origins, positions)?')) {
|
|
929
|
+
// Clear localStorage
|
|
930
|
+
Object.values(STORAGE_KEYS).forEach(key => localStorage.removeItem(key));
|
|
931
|
+
|
|
932
|
+
// Reset in-memory data structures
|
|
933
|
+
requestLog.length = 0;
|
|
934
|
+
origins.length = 0;
|
|
935
|
+
componentLines.clear();
|
|
936
|
+
nodePositions.clear();
|
|
937
|
+
expandedLabels.clear();
|
|
938
|
+
|
|
939
|
+
// Reset zoom and pan
|
|
940
|
+
zoomLevel = 1;
|
|
941
|
+
panX = 0;
|
|
942
|
+
panY = 0;
|
|
943
|
+
|
|
944
|
+
// Reset stats
|
|
945
|
+
totalRequests = 0;
|
|
946
|
+
localRequests = 0;
|
|
947
|
+
proxiedRequests = 0;
|
|
948
|
+
|
|
949
|
+
// Re-render everything
|
|
950
|
+
renderArchitecture();
|
|
951
|
+
updateComponentsList();
|
|
952
|
+
updateActivityLog();
|
|
953
|
+
updateStats();
|
|
954
|
+
updateViewBox();
|
|
955
|
+
|
|
956
|
+
console.log('🗑️ All stored data cleared');
|
|
957
|
+
}
|
|
783
958
|
}
|
|
784
959
|
|
|
960
|
+
// Export function for use in HTML
|
|
961
|
+
window.clearStoredData = clearStoredData;
|
|
962
|
+
|
|
785
963
|
// Initial render
|
|
786
964
|
renderArchitecture();
|
|
787
965
|
updateComponentsList();
|
|
@@ -32,6 +32,7 @@ ${styles}
|
|
|
32
32
|
<div class="tab active">Network Architecture</div>
|
|
33
33
|
<div class="tab">Performance</div>
|
|
34
34
|
<div class="tab">Console</div>
|
|
35
|
+
<button class="clear-data-btn" onclick="clearStoredData()" title="Clear all stored data">🗑️ Clear Data</button>
|
|
35
36
|
</div>
|
|
36
37
|
|
|
37
38
|
<div class="main-content">
|
|
@@ -85,6 +85,33 @@ body {
|
|
|
85
85
|
border-bottom: 2px solid #007acc;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
.clear-data-btn {
|
|
89
|
+
margin-left: auto;
|
|
90
|
+
margin-right: 10px;
|
|
91
|
+
padding: 5px 12px;
|
|
92
|
+
background: #3e3e42;
|
|
93
|
+
border: 1px solid #5a5a5f;
|
|
94
|
+
color: #cccccc;
|
|
95
|
+
font-size: 11px;
|
|
96
|
+
font-family: inherit;
|
|
97
|
+
cursor: pointer;
|
|
98
|
+
border-radius: 3px;
|
|
99
|
+
display: flex;
|
|
100
|
+
align-items: center;
|
|
101
|
+
gap: 4px;
|
|
102
|
+
transition: all 0.2s;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.clear-data-btn:hover {
|
|
106
|
+
background: #4e4e52;
|
|
107
|
+
border-color: #007acc;
|
|
108
|
+
color: #ffffff;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.clear-data-btn:active {
|
|
112
|
+
background: #2e2e32;
|
|
113
|
+
}
|
|
114
|
+
|
|
88
115
|
.main-content {
|
|
89
116
|
display: flex;
|
|
90
117
|
flex: 1;
|