tuimon 0.1.0 → 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/AI.md +191 -0
- package/README.md +240 -94
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +3 -0
- package/dist/browser.js.map +1 -1
- package/dist/cli.js +224 -3
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +17 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +106 -0
- package/dist/config.js.map +1 -0
- package/dist/fkeybar.d.ts.map +1 -1
- package/dist/fkeybar.js +13 -0
- package/dist/fkeybar.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +148 -18
- package/dist/index.js.map +1 -1
- package/dist/layout/generator-css.d.ts +3 -0
- package/dist/layout/generator-css.d.ts.map +1 -0
- package/dist/layout/generator-css.js +202 -0
- package/dist/layout/generator-css.js.map +1 -0
- package/dist/layout/generator-js.d.ts +3 -0
- package/dist/layout/generator-js.d.ts.map +1 -0
- package/dist/layout/generator-js.js +353 -0
- package/dist/layout/generator-js.js.map +1 -0
- package/dist/layout/generator.d.ts +4 -0
- package/dist/layout/generator.d.ts.map +1 -0
- package/dist/layout/generator.js +124 -0
- package/dist/layout/generator.js.map +1 -0
- package/dist/layout/theme.d.ts +4 -0
- package/dist/layout/theme.d.ts.map +1 -0
- package/dist/layout/theme.js +28 -0
- package/dist/layout/theme.js.map +1 -0
- package/dist/layout/types.d.ts +68 -0
- package/dist/layout/types.d.ts.map +1 -0
- package/dist/layout/types.js +3 -0
- package/dist/layout/types.js.map +1 -0
- package/dist/quick/auto-layout.d.ts +5 -0
- package/dist/quick/auto-layout.d.ts.map +1 -0
- package/dist/quick/auto-layout.js +262 -0
- package/dist/quick/auto-layout.js.map +1 -0
- package/dist/quick/db/detect.d.ts +16 -0
- package/dist/quick/db/detect.d.ts.map +1 -0
- package/dist/quick/db/detect.js +131 -0
- package/dist/quick/db/detect.js.map +1 -0
- package/dist/quick/db/mongo.d.ts +10 -0
- package/dist/quick/db/mongo.d.ts.map +1 -0
- package/dist/quick/db/mongo.js +81 -0
- package/dist/quick/db/mongo.js.map +1 -0
- package/dist/quick/db/mysql.d.ts +8 -0
- package/dist/quick/db/mysql.d.ts.map +1 -0
- package/dist/quick/db/mysql.js +43 -0
- package/dist/quick/db/mysql.js.map +1 -0
- package/dist/quick/db/postgres.d.ts +8 -0
- package/dist/quick/db/postgres.d.ts.map +1 -0
- package/dist/quick/db/postgres.js +47 -0
- package/dist/quick/db/postgres.js.map +1 -0
- package/dist/quick/db/sqlite.d.ts +8 -0
- package/dist/quick/db/sqlite.d.ts.map +1 -0
- package/dist/quick/db/sqlite.js +43 -0
- package/dist/quick/db/sqlite.js.map +1 -0
- package/dist/quick/db-mode.d.ts +13 -0
- package/dist/quick/db-mode.d.ts.map +1 -0
- package/dist/quick/db-mode.js +159 -0
- package/dist/quick/db-mode.js.map +1 -0
- package/dist/quick/detect.d.ts +4 -0
- package/dist/quick/detect.d.ts.map +1 -0
- package/dist/quick/detect.js +76 -0
- package/dist/quick/detect.js.map +1 -0
- package/dist/quick/file-mode.d.ts +5 -0
- package/dist/quick/file-mode.d.ts.map +1 -0
- package/dist/quick/file-mode.js +158 -0
- package/dist/quick/file-mode.js.map +1 -0
- package/dist/quick/parsers/csv.d.ts +3 -0
- package/dist/quick/parsers/csv.d.ts.map +1 -0
- package/dist/quick/parsers/csv.js +145 -0
- package/dist/quick/parsers/csv.js.map +1 -0
- package/dist/quick/parsers/detect-meta.d.ts +7 -0
- package/dist/quick/parsers/detect-meta.d.ts.map +1 -0
- package/dist/quick/parsers/detect-meta.js +35 -0
- package/dist/quick/parsers/detect-meta.js.map +1 -0
- package/dist/quick/parsers/json.d.ts +3 -0
- package/dist/quick/parsers/json.d.ts.map +1 -0
- package/dist/quick/parsers/json.js +74 -0
- package/dist/quick/parsers/json.js.map +1 -0
- package/dist/quick/parsers/log.d.ts +3 -0
- package/dist/quick/parsers/log.d.ts.map +1 -0
- package/dist/quick/parsers/log.js +185 -0
- package/dist/quick/parsers/log.js.map +1 -0
- package/dist/quick/parsers/modsec.d.ts +3 -0
- package/dist/quick/parsers/modsec.d.ts.map +1 -0
- package/dist/quick/parsers/modsec.js +338 -0
- package/dist/quick/parsers/modsec.js.map +1 -0
- package/dist/quick/presets/coverage.d.ts +3 -0
- package/dist/quick/presets/coverage.d.ts.map +1 -0
- package/dist/quick/presets/coverage.js +362 -0
- package/dist/quick/presets/coverage.js.map +1 -0
- package/dist/quick/presets/deps.d.ts +3 -0
- package/dist/quick/presets/deps.d.ts.map +1 -0
- package/dist/quick/presets/deps.js +194 -0
- package/dist/quick/presets/deps.js.map +1 -0
- package/dist/quick/presets/docker.d.ts +3 -0
- package/dist/quick/presets/docker.d.ts.map +1 -0
- package/dist/quick/presets/docker.js +100 -0
- package/dist/quick/presets/docker.js.map +1 -0
- package/dist/quick/presets/git.d.ts +3 -0
- package/dist/quick/presets/git.d.ts.map +1 -0
- package/dist/quick/presets/git.js +116 -0
- package/dist/quick/presets/git.js.map +1 -0
- package/dist/quick/presets/ps.d.ts +3 -0
- package/dist/quick/presets/ps.d.ts.map +1 -0
- package/dist/quick/presets/ps.js +168 -0
- package/dist/quick/presets/ps.js.map +1 -0
- package/dist/quick/presets/runner.d.ts +3 -0
- package/dist/quick/presets/runner.d.ts.map +1 -0
- package/dist/quick/presets/runner.js +20 -0
- package/dist/quick/presets/runner.js.map +1 -0
- package/dist/quick/presets/types.d.ts +7 -0
- package/dist/quick/presets/types.d.ts.map +1 -0
- package/dist/quick/presets/types.js +2 -0
- package/dist/quick/presets/types.js.map +1 -0
- package/dist/quick/types.d.ts +90 -0
- package/dist/quick/types.d.ts.map +1 -0
- package/dist/quick/types.js +3 -0
- package/dist/quick/types.js.map +1 -0
- package/dist/quick/watch-mode.d.ts +3 -0
- package/dist/quick/watch-mode.d.ts.map +1 -0
- package/dist/quick/watch-mode.js +156 -0
- package/dist/quick/watch-mode.js.map +1 -0
- package/dist/server.js +2 -2
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +9 -2
- package/dist/types.d.ts.map +1 -1
- package/examples/demo.ts +134 -0
- package/examples/generate-access-log.ts +42 -0
- package/examples/screenshot-test.ts +105 -0
- package/examples/screenshot.png +0 -0
- package/frame-log.txt +830 -0
- package/package.json +10 -5
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
export function generateJs(layout, t) {
|
|
2
|
+
const allWidgets = [...(layout.stats ?? []), ...(layout.panels ?? [])];
|
|
3
|
+
const widgetMapJson = JSON.stringify(Object.fromEntries(allWidgets.map((w) => [w.id, w.type])));
|
|
4
|
+
const throttleMapJson = JSON.stringify(Object.fromEntries(allWidgets.filter((w) => w.throttle).map((w) => [w.id, w.throttle])));
|
|
5
|
+
const chartColorsJson = JSON.stringify(t.chartColors);
|
|
6
|
+
return `
|
|
7
|
+
(function() {
|
|
8
|
+
'use strict';
|
|
9
|
+
var CHART_COLORS = ${chartColorsJson};
|
|
10
|
+
var WIDGET_MAP = ${widgetMapJson};
|
|
11
|
+
var THROTTLE_MAP = ${throttleMapJson};
|
|
12
|
+
var lastUpdateTime = {};
|
|
13
|
+
var charts = {};
|
|
14
|
+
var lineHistory = {};
|
|
15
|
+
var MAX_LINE_POINTS = 60;
|
|
16
|
+
var MAX_BAR_POINTS = 20;
|
|
17
|
+
var MAX_EVENTS = 10;
|
|
18
|
+
var theme = ${JSON.stringify({
|
|
19
|
+
success: t.success,
|
|
20
|
+
warning: t.warning,
|
|
21
|
+
danger: t.danger,
|
|
22
|
+
textMuted: t.textMuted,
|
|
23
|
+
text: t.text,
|
|
24
|
+
border: t.border,
|
|
25
|
+
panelBg: t.panelBg,
|
|
26
|
+
})};
|
|
27
|
+
|
|
28
|
+
// ── HTML escaping for innerHTML safety ──
|
|
29
|
+
function escHtml(s) {
|
|
30
|
+
if (s == null) return '';
|
|
31
|
+
return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ── Normalization ──
|
|
35
|
+
function normalize(id, raw) {
|
|
36
|
+
var type = WIDGET_MAP[id];
|
|
37
|
+
if (!type) return raw;
|
|
38
|
+
|
|
39
|
+
if (type === 'stat') {
|
|
40
|
+
if (typeof raw === 'number' || typeof raw === 'string') return { value: raw };
|
|
41
|
+
return raw;
|
|
42
|
+
}
|
|
43
|
+
if (type === 'gauge') {
|
|
44
|
+
if (typeof raw === 'number') return { value: raw, max: 100 };
|
|
45
|
+
return raw;
|
|
46
|
+
}
|
|
47
|
+
if (type === 'line') {
|
|
48
|
+
if (raw && typeof raw === 'object' && !Array.isArray(raw) && !raw.series) {
|
|
49
|
+
return { _kvUpdate: raw };
|
|
50
|
+
}
|
|
51
|
+
return raw;
|
|
52
|
+
}
|
|
53
|
+
if (type === 'event-log') {
|
|
54
|
+
if (!Array.isArray(raw)) return raw;
|
|
55
|
+
return raw.map(function(item) {
|
|
56
|
+
if (typeof item === 'string') return { text: item, type: 'info', time: new Date().toLocaleTimeString() };
|
|
57
|
+
if (!item.time) item.time = new Date().toLocaleTimeString();
|
|
58
|
+
if (!item.type) item.type = 'info';
|
|
59
|
+
return item;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (type === 'status-grid') {
|
|
63
|
+
if (!Array.isArray(raw)) return raw;
|
|
64
|
+
return raw.map(function(item) {
|
|
65
|
+
if (typeof item === 'string') return { label: item, status: 'ok' };
|
|
66
|
+
return item;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return raw;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ── Widget updaters ──
|
|
73
|
+
function updateStat(id, data) {
|
|
74
|
+
var valEl = document.getElementById('val-' + id);
|
|
75
|
+
var trendEl = document.getElementById('trend-' + id);
|
|
76
|
+
var unitEl = document.getElementById('unit-' + id);
|
|
77
|
+
if (valEl) valEl.textContent = typeof data.value === 'number' ? data.value.toLocaleString() : data.value;
|
|
78
|
+
if (trendEl) trendEl.textContent = data.trend || '';
|
|
79
|
+
if (unitEl) unitEl.textContent = data.unit || '';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function updateGauge(id, data) {
|
|
83
|
+
var max = data.max || 100;
|
|
84
|
+
var pct = Math.min(100, Math.round((data.value / max) * 100));
|
|
85
|
+
var valEl = document.getElementById('val-' + id);
|
|
86
|
+
var fillEl = document.getElementById('gauge-' + id);
|
|
87
|
+
if (valEl) valEl.textContent = pct + '%' + (data.label ? ' ' + data.label : '');
|
|
88
|
+
if (fillEl) {
|
|
89
|
+
fillEl.style.width = pct + '%';
|
|
90
|
+
if (pct > 80) fillEl.style.background = theme.danger;
|
|
91
|
+
else if (pct > 60) fillEl.style.background = theme.warning;
|
|
92
|
+
else fillEl.style.background = theme.success;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function ensureLineChart(id) {
|
|
97
|
+
if (charts[id]) return charts[id];
|
|
98
|
+
var canvas = document.getElementById('chart-' + id);
|
|
99
|
+
if (!canvas) return null;
|
|
100
|
+
lineHistory[id] = {};
|
|
101
|
+
charts[id] = new Chart(canvas, {
|
|
102
|
+
type: 'line',
|
|
103
|
+
data: { labels: [], datasets: [] },
|
|
104
|
+
options: {
|
|
105
|
+
responsive: true, maintainAspectRatio: false, animation: false,
|
|
106
|
+
scales: {
|
|
107
|
+
y: { grid: { color: theme.border + '22' }, ticks: { color: theme.textMuted } },
|
|
108
|
+
x: { display: false },
|
|
109
|
+
},
|
|
110
|
+
plugins: { legend: { labels: { color: theme.text, font: { size: 10 } } } },
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
return charts[id];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function updateLine(id, data) {
|
|
117
|
+
var chart = ensureLineChart(id);
|
|
118
|
+
if (!chart) return;
|
|
119
|
+
var hist = lineHistory[id];
|
|
120
|
+
|
|
121
|
+
if (data._kvUpdate) {
|
|
122
|
+
var kv = data._kvUpdate;
|
|
123
|
+
Object.keys(kv).forEach(function(key) {
|
|
124
|
+
if (!hist[key]) hist[key] = [];
|
|
125
|
+
hist[key].push(kv[key]);
|
|
126
|
+
if (hist[key].length > MAX_LINE_POINTS) hist[key].shift();
|
|
127
|
+
});
|
|
128
|
+
} else if (data.series) {
|
|
129
|
+
data.series.forEach(function(s) {
|
|
130
|
+
if (!hist[s.label]) hist[s.label] = [];
|
|
131
|
+
s.data.forEach(function(v) { hist[s.label].push(v); });
|
|
132
|
+
if (hist[s.label].length > MAX_LINE_POINTS) hist[s.label] = hist[s.label].slice(-MAX_LINE_POINTS);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
var labels = Object.keys(hist);
|
|
137
|
+
var maxLen = 0;
|
|
138
|
+
labels.forEach(function(k) { if (hist[k].length > maxLen) maxLen = hist[k].length; });
|
|
139
|
+
chart.data.labels = Array.from({ length: maxLen }, function(_, i) { return i; });
|
|
140
|
+
chart.data.datasets = labels.map(function(label, i) {
|
|
141
|
+
return {
|
|
142
|
+
label: label,
|
|
143
|
+
data: hist[label],
|
|
144
|
+
borderColor: CHART_COLORS[i % CHART_COLORS.length],
|
|
145
|
+
backgroundColor: CHART_COLORS[i % CHART_COLORS.length] + '18',
|
|
146
|
+
fill: true, tension: 0.3, pointRadius: 0, borderWidth: 2,
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
chart.update();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function ensureDoughnutChart(id) {
|
|
153
|
+
if (charts[id]) return charts[id];
|
|
154
|
+
var canvas = document.getElementById('chart-' + id);
|
|
155
|
+
if (!canvas) return null;
|
|
156
|
+
charts[id] = new Chart(canvas, {
|
|
157
|
+
type: 'doughnut',
|
|
158
|
+
data: { labels: [], datasets: [{ data: [], backgroundColor: [], borderWidth: 0 }] },
|
|
159
|
+
options: {
|
|
160
|
+
responsive: true, maintainAspectRatio: false, animation: false, cutout: '60%',
|
|
161
|
+
plugins: { legend: { position: 'bottom', labels: { color: theme.text, font: { size: 10 }, padding: 12 } } },
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
return charts[id];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function updateDoughnut(id, data) {
|
|
168
|
+
var chart = ensureDoughnutChart(id);
|
|
169
|
+
if (!chart) return;
|
|
170
|
+
var keys = Object.keys(data);
|
|
171
|
+
chart.data.labels = keys;
|
|
172
|
+
chart.data.datasets[0].data = keys.map(function(k) { return data[k]; });
|
|
173
|
+
chart.data.datasets[0].backgroundColor = keys.map(function(_, i) { return CHART_COLORS[i % CHART_COLORS.length]; });
|
|
174
|
+
chart.update();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function ensureBarChart(id) {
|
|
178
|
+
if (charts[id]) return charts[id];
|
|
179
|
+
var canvas = document.getElementById('chart-' + id);
|
|
180
|
+
if (!canvas) return null;
|
|
181
|
+
charts[id] = new Chart(canvas, {
|
|
182
|
+
type: 'bar',
|
|
183
|
+
data: { labels: [], datasets: [{ data: [], backgroundColor: [] }] },
|
|
184
|
+
options: {
|
|
185
|
+
responsive: true, maintainAspectRatio: false, animation: false,
|
|
186
|
+
scales: {
|
|
187
|
+
y: { grid: { color: theme.border + '22' }, ticks: { color: theme.textMuted } },
|
|
188
|
+
x: { ticks: { color: theme.textMuted, font: { size: 10 } } },
|
|
189
|
+
},
|
|
190
|
+
plugins: { legend: { display: false } },
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
return charts[id];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function updateBar(id, data) {
|
|
197
|
+
var chart = ensureBarChart(id);
|
|
198
|
+
if (!chart) return;
|
|
199
|
+
var keys = Object.keys(data);
|
|
200
|
+
chart.data.labels = keys;
|
|
201
|
+
chart.data.datasets[0].data = keys.map(function(k) { return data[k]; });
|
|
202
|
+
chart.data.datasets[0].backgroundColor = keys.map(function(_, i) { return CHART_COLORS[i % CHART_COLORS.length]; });
|
|
203
|
+
chart.update();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function updateEventLog(id, data) {
|
|
207
|
+
var list = document.getElementById('list-' + id);
|
|
208
|
+
if (!list || !Array.isArray(data)) return;
|
|
209
|
+
var items = data.slice(0, MAX_EVENTS);
|
|
210
|
+
list.innerHTML = items.map(function(e) {
|
|
211
|
+
return '<div class="event-entry ' + escHtml(e.type || '') + '">'
|
|
212
|
+
+ '<span class="event-time">' + escHtml(e.time || '') + '</span>'
|
|
213
|
+
+ '<span class="event-text">' + escHtml(e.text || '') + '</span>'
|
|
214
|
+
+ '</div>';
|
|
215
|
+
}).join('');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function updateStatusGrid(id, data) {
|
|
219
|
+
var grid = document.getElementById('grid-' + id);
|
|
220
|
+
if (!grid || !Array.isArray(data)) return;
|
|
221
|
+
grid.innerHTML = data.map(function(item) {
|
|
222
|
+
return '<div class="status-item">'
|
|
223
|
+
+ '<div class="status-dot ' + escHtml(item.status || 'unknown') + '"></div>'
|
|
224
|
+
+ '<span class="status-label">' + escHtml(item.label || '') + '</span>'
|
|
225
|
+
+ '</div>';
|
|
226
|
+
}).join('');
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// ── Table with pagination ──
|
|
230
|
+
var tableState = {}; // { id: { data, page, perPage } }
|
|
231
|
+
|
|
232
|
+
function updateTable(id, data) {
|
|
233
|
+
var wrap = document.getElementById('table-' + id);
|
|
234
|
+
if (!wrap || !data || !data.columns || !data.rows) return;
|
|
235
|
+
|
|
236
|
+
if (!tableState[id]) {
|
|
237
|
+
tableState[id] = { data: data, page: 0, perPage: 25 };
|
|
238
|
+
} else {
|
|
239
|
+
tableState[id].data = data;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
renderTablePage(id);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function renderTablePage(id) {
|
|
246
|
+
var wrap = document.getElementById('table-' + id);
|
|
247
|
+
var state = tableState[id];
|
|
248
|
+
if (!wrap || !state) return;
|
|
249
|
+
|
|
250
|
+
var data = state.data;
|
|
251
|
+
var cols = data.columns;
|
|
252
|
+
var allRows = data.rows;
|
|
253
|
+
|
|
254
|
+
// Auto-calculate rows per page based on panel height
|
|
255
|
+
// ~22px per row, ~30px header, ~25px footer
|
|
256
|
+
var wrapH = wrap.clientHeight || 300;
|
|
257
|
+
var perPage = Math.max(5, Math.floor((wrapH - 65) / 22));
|
|
258
|
+
state.perPage = perPage;
|
|
259
|
+
|
|
260
|
+
var totalPages = Math.max(1, Math.ceil(allRows.length / perPage));
|
|
261
|
+
if (state.page >= totalPages) state.page = totalPages - 1;
|
|
262
|
+
if (state.page < 0) state.page = 0;
|
|
263
|
+
|
|
264
|
+
var start = state.page * perPage;
|
|
265
|
+
var pageRows = allRows.slice(start, start + perPage);
|
|
266
|
+
|
|
267
|
+
var tableHtml = '<table><thead><tr>';
|
|
268
|
+
cols.forEach(function(c) { tableHtml += '<th>' + escHtml(c) + '</th>'; });
|
|
269
|
+
tableHtml += '</tr></thead><tbody>';
|
|
270
|
+
pageRows.forEach(function(row) {
|
|
271
|
+
tableHtml += '<tr>';
|
|
272
|
+
cols.forEach(function(c) {
|
|
273
|
+
var val = row[c];
|
|
274
|
+
var isNum = typeof val === 'number';
|
|
275
|
+
tableHtml += '<td' + (isNum ? ' class="num"' : '') + '>'
|
|
276
|
+
+ (val != null ? escHtml(isNum ? val.toLocaleString() : String(val)) : '')
|
|
277
|
+
+ '</td>';
|
|
278
|
+
});
|
|
279
|
+
tableHtml += '</tr>';
|
|
280
|
+
});
|
|
281
|
+
tableHtml += '</tbody></table>';
|
|
282
|
+
|
|
283
|
+
var html = '<div class="table-scroll">' + tableHtml + '</div>';
|
|
284
|
+
|
|
285
|
+
if (totalPages > 1) {
|
|
286
|
+
html += '<div class="table-info">'
|
|
287
|
+
+ '\u25C0 Page ' + (state.page + 1) + ' of ' + totalPages
|
|
288
|
+
+ ' (' + allRows.length.toLocaleString() + ' rows) \u25B6'
|
|
289
|
+
+ ' | \u2191\u2193 Arrow keys to navigate'
|
|
290
|
+
+ '</div>';
|
|
291
|
+
} else if (allRows.length > 0) {
|
|
292
|
+
html += '<div class="table-info">' + allRows.length.toLocaleString() + ' rows</div>';
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
wrap.innerHTML = html;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Listen for page navigation keys from TuiMon
|
|
299
|
+
window.addEventListener('tuimon:tableNav', function(e) {
|
|
300
|
+
var detail = e.detail;
|
|
301
|
+
var ids = Object.keys(tableState);
|
|
302
|
+
if (ids.length === 0) return;
|
|
303
|
+
var id = ids[0]; // navigate first table
|
|
304
|
+
var state = tableState[id];
|
|
305
|
+
if (!state) return;
|
|
306
|
+
|
|
307
|
+
var totalPages = Math.max(1, Math.ceil(state.data.rows.length / state.perPage));
|
|
308
|
+
|
|
309
|
+
switch (detail.action) {
|
|
310
|
+
case 'next': state.page = Math.min(state.page + 1, totalPages - 1); break;
|
|
311
|
+
case 'prev': state.page = Math.max(state.page - 1, 0); break;
|
|
312
|
+
case 'first': state.page = 0; break;
|
|
313
|
+
case 'last': state.page = totalPages - 1; break;
|
|
314
|
+
}
|
|
315
|
+
renderTablePage(id);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// ── Main update handler ──
|
|
319
|
+
TuiMon.onUpdate(function(data) {
|
|
320
|
+
var timeEl = document.getElementById('dash-time');
|
|
321
|
+
if (timeEl) timeEl.textContent = new Date().toLocaleTimeString();
|
|
322
|
+
|
|
323
|
+
var now = Date.now();
|
|
324
|
+
Object.keys(data).forEach(function(id) {
|
|
325
|
+
var type = WIDGET_MAP[id];
|
|
326
|
+
if (!type) return;
|
|
327
|
+
|
|
328
|
+
// Throttle check — skip if updated too recently
|
|
329
|
+
var throttle = THROTTLE_MAP[id];
|
|
330
|
+
if (throttle) {
|
|
331
|
+
var last = lastUpdateTime[id] || 0;
|
|
332
|
+
if (now - last < throttle) return;
|
|
333
|
+
}
|
|
334
|
+
lastUpdateTime[id] = now;
|
|
335
|
+
|
|
336
|
+
var val = normalize(id, data[id]);
|
|
337
|
+
|
|
338
|
+
switch (type) {
|
|
339
|
+
case 'stat': updateStat(id, val); break;
|
|
340
|
+
case 'gauge': updateGauge(id, val); break;
|
|
341
|
+
case 'line': updateLine(id, val); break;
|
|
342
|
+
case 'doughnut': updateDoughnut(id, val); break;
|
|
343
|
+
case 'bar': updateBar(id, val); break;
|
|
344
|
+
case 'event-log': updateEventLog(id, val); break;
|
|
345
|
+
case 'status-grid': updateStatusGrid(id, val); break;
|
|
346
|
+
case 'table': updateTable(id, val); break;
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
})();
|
|
351
|
+
`;
|
|
352
|
+
}
|
|
353
|
+
//# sourceMappingURL=generator-js.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator-js.js","sourceRoot":"","sources":["../../src/layout/generator-js.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,UAAU,CAAC,MAAoB,EAAE,CAAc;IAC7D,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAA;IACtE,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAClC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAC1D,CAAA;IACD,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CACpC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CACxF,CAAA;IACD,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAA;IAErD,OAAO;;;2BAGkB,eAAe;yBACjB,aAAa;2BACX,eAAe;;;;;;;oBAOtB,IAAI,CAAC,SAAS,CAAC;QAC3B,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,OAAO,EAAE,CAAC,CAAC,OAAO;KACnB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqUL,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { LayoutConfig, ThemeConfig } from './types.js';
|
|
2
|
+
export declare function validateLayout(layout: LayoutConfig): void;
|
|
3
|
+
export declare function generateDashboardHtml(layout: LayoutConfig, themeOverrides?: Partial<ThemeConfig>): string;
|
|
4
|
+
//# sourceMappingURL=generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/layout/generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAgB,WAAW,EAAE,MAAM,YAAY,CAAA;AAOzE,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAezD;AA+DD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,MAAM,CAsDzG"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { mergeTheme } from './theme.js';
|
|
2
|
+
import { generateCss } from './generator-css.js';
|
|
3
|
+
import { generateJs } from './generator-js.js';
|
|
4
|
+
// ─── Validation ──────────────────────────────────────────────────────────────
|
|
5
|
+
export function validateLayout(layout) {
|
|
6
|
+
const stats = layout.stats ?? [];
|
|
7
|
+
const panels = layout.panels ?? [];
|
|
8
|
+
if (stats.length === 0 && panels.length === 0) {
|
|
9
|
+
throw new Error('[tuimon] Layout must have at least one stat or panel widget');
|
|
10
|
+
}
|
|
11
|
+
const ids = new Set();
|
|
12
|
+
for (const w of [...stats, ...panels]) {
|
|
13
|
+
if (ids.has(w.id)) {
|
|
14
|
+
throw new Error(`[tuimon] Duplicate widget id: "${w.id}"`);
|
|
15
|
+
}
|
|
16
|
+
ids.add(w.id);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
// ─── Widget HTML generators ─────────────────────────────────────────────────
|
|
20
|
+
function statCardHtml(w) {
|
|
21
|
+
if (w.type === 'gauge') {
|
|
22
|
+
return `
|
|
23
|
+
<div class="stat-card" data-widget-id="${w.id}" data-widget-type="gauge">
|
|
24
|
+
<div class="stat-label">${esc(w.label)}</div>
|
|
25
|
+
<div class="stat-value" id="val-${w.id}">--</div>
|
|
26
|
+
<div class="gauge-track">
|
|
27
|
+
<div class="gauge-fill" id="gauge-${w.id}" style="width: 0%"></div>
|
|
28
|
+
</div>
|
|
29
|
+
</div>`;
|
|
30
|
+
}
|
|
31
|
+
return `
|
|
32
|
+
<div class="stat-card" data-widget-id="${w.id}" data-widget-type="stat">
|
|
33
|
+
<div class="stat-label">${esc(w.label)}</div>
|
|
34
|
+
<div class="stat-value" id="val-${w.id}">--</div>
|
|
35
|
+
<div class="stat-extra">
|
|
36
|
+
<span class="stat-trend" id="trend-${w.id}"></span>
|
|
37
|
+
<span class="stat-unit" id="unit-${w.id}"></span>
|
|
38
|
+
</div>
|
|
39
|
+
</div>`;
|
|
40
|
+
}
|
|
41
|
+
function panelHtml(w) {
|
|
42
|
+
const spanStyle = w.span && w.span > 1 ? ` style="grid-column: span ${w.span}"` : '';
|
|
43
|
+
const tmKey = w.shortcut ? ` data-tm-key="${w.shortcut}" data-tm-label="${esc(w.shortcutLabel ?? w.label)}"` : '';
|
|
44
|
+
let inner = '';
|
|
45
|
+
switch (w.type) {
|
|
46
|
+
case 'line':
|
|
47
|
+
case 'bar':
|
|
48
|
+
case 'doughnut':
|
|
49
|
+
inner = `<div class="chart-wrap"><canvas id="chart-${w.id}"></canvas></div>`;
|
|
50
|
+
break;
|
|
51
|
+
case 'event-log':
|
|
52
|
+
inner = `<div class="event-list" id="list-${w.id}"><div class="event-empty">Waiting for data...</div></div>`;
|
|
53
|
+
break;
|
|
54
|
+
case 'status-grid':
|
|
55
|
+
inner = `<div class="status-grid" id="grid-${w.id}"></div>`;
|
|
56
|
+
break;
|
|
57
|
+
case 'table':
|
|
58
|
+
inner = `<div class="table-wrap" id="table-${w.id}"><div class="event-empty">Waiting for data...</div></div>`;
|
|
59
|
+
break;
|
|
60
|
+
default:
|
|
61
|
+
inner = `<div id="content-${w.id}"></div>`;
|
|
62
|
+
}
|
|
63
|
+
return `
|
|
64
|
+
<div class="panel" data-widget-id="${w.id}" data-widget-type="${w.type}"${spanStyle}${tmKey}>
|
|
65
|
+
<div class="panel-header">${esc(w.label)}</div>
|
|
66
|
+
${inner}
|
|
67
|
+
</div>`;
|
|
68
|
+
}
|
|
69
|
+
function esc(s) {
|
|
70
|
+
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
71
|
+
}
|
|
72
|
+
// ─── Main generator ──────────────────────────────────────────────────────────
|
|
73
|
+
export function generateDashboardHtml(layout, themeOverrides) {
|
|
74
|
+
validateLayout(layout);
|
|
75
|
+
const theme = mergeTheme(layout.theme ?? themeOverrides);
|
|
76
|
+
const stats = layout.stats ?? [];
|
|
77
|
+
const panels = layout.panels ?? [];
|
|
78
|
+
const title = layout.title ?? 'TuiMon';
|
|
79
|
+
const statCardsHtml = stats.map((w) => statCardHtml(w)).join('');
|
|
80
|
+
const panelsHtml = panels.map((w) => panelHtml(w)).join('');
|
|
81
|
+
// Inline TuiMon client bridge so the page is fully self-contained
|
|
82
|
+
const clientBridge = `
|
|
83
|
+
;(function() {
|
|
84
|
+
window.__tuimon_ready__ = false;
|
|
85
|
+
window.__tuimon_update__ = function(data) {
|
|
86
|
+
window.__tuimon_ready__ = false;
|
|
87
|
+
window.dispatchEvent(new CustomEvent('tuimon:update', { detail: data }));
|
|
88
|
+
window.__tuimon_ready__ = true;
|
|
89
|
+
};
|
|
90
|
+
window.TuiMon = window.TuiMon || {
|
|
91
|
+
onUpdate: function(cb) { window.addEventListener('tuimon:update', function(e) { cb(e.detail); }); },
|
|
92
|
+
set: function(sel, val) {
|
|
93
|
+
var el = document.querySelector(sel);
|
|
94
|
+
if (!el) return;
|
|
95
|
+
if (typeof val === 'string') el.textContent = val;
|
|
96
|
+
else if (typeof val === 'number') el.textContent = val.toLocaleString();
|
|
97
|
+
else if (typeof val === 'object' && val !== null) Object.assign(el.style, val);
|
|
98
|
+
},
|
|
99
|
+
notify: function(msg, dur) { window.dispatchEvent(new CustomEvent('tuimon:notify', { detail: { message: msg, duration: dur || 2000 } })); },
|
|
100
|
+
};
|
|
101
|
+
})();
|
|
102
|
+
`;
|
|
103
|
+
return `<!DOCTYPE html>
|
|
104
|
+
<html lang="en">
|
|
105
|
+
<head>
|
|
106
|
+
<meta charset="UTF-8">
|
|
107
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
108
|
+
<title>${esc(title)}</title>
|
|
109
|
+
<script>${clientBridge}<\/script>
|
|
110
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4"><\/script>
|
|
111
|
+
<style>${generateCss(theme)}</style>
|
|
112
|
+
</head>
|
|
113
|
+
<body>
|
|
114
|
+
<div class="dash-header">
|
|
115
|
+
<span class="dash-title">${esc(title)}</span>
|
|
116
|
+
<span class="dash-time" id="dash-time"></span>
|
|
117
|
+
</div>
|
|
118
|
+
${stats.length > 0 ? ` <div class="stat-row">${statCardsHtml}\n </div>` : ''}
|
|
119
|
+
${panels.length > 0 ? ` <div class="panel-grid">${panelsHtml}\n </div>` : ''}
|
|
120
|
+
<script>${generateJs(layout, theme)}<\/script>
|
|
121
|
+
</body>
|
|
122
|
+
</html>`;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/layout/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/layout/theme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,eAAO,MAAM,aAAa,EAAE,WAiB3B,CAAA;AAED,wBAAgB,UAAU,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW,CAOxE"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const DEFAULT_THEME = {
|
|
2
|
+
bg: '#0a0e1a',
|
|
3
|
+
panelBg: '#0f1629',
|
|
4
|
+
border: '#00e5ff',
|
|
5
|
+
text: '#e0e6ed',
|
|
6
|
+
textMuted: '#5a6a7a',
|
|
7
|
+
accent: '#00e5ff',
|
|
8
|
+
success: '#00e676',
|
|
9
|
+
warning: '#ffab40',
|
|
10
|
+
danger: '#ff5252',
|
|
11
|
+
purple: '#b388ff',
|
|
12
|
+
chartColors: [
|
|
13
|
+
'#00e5ff', '#ff6e40', '#00e676', '#b388ff',
|
|
14
|
+
'#ffab40', '#ff5252', '#40c4ff', '#69f0ae',
|
|
15
|
+
'#ffd740', '#ff80ab', '#448aff', '#b2ff59',
|
|
16
|
+
],
|
|
17
|
+
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, monospace",
|
|
18
|
+
};
|
|
19
|
+
export function mergeTheme(overrides) {
|
|
20
|
+
if (!overrides)
|
|
21
|
+
return { ...DEFAULT_THEME };
|
|
22
|
+
return {
|
|
23
|
+
...DEFAULT_THEME,
|
|
24
|
+
...overrides,
|
|
25
|
+
chartColors: overrides.chartColors ? [...overrides.chartColors] : [...DEFAULT_THEME.chartColors],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/layout/theme.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAgB;IACxC,EAAE,EAAE,SAAS;IACb,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,SAAS;IACf,SAAS,EAAE,SAAS;IACpB,MAAM,EAAE,SAAS;IACjB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,SAAS;IACjB,WAAW,EAAE;QACX,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS;QAC1C,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS;QAC1C,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS;KAC3C;IACD,UAAU,EAAE,kEAAkE;CAC/E,CAAA;AAED,MAAM,UAAU,UAAU,CAAC,SAAgC;IACzD,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,GAAG,aAAa,EAAE,CAAA;IAC3C,OAAO;QACL,GAAG,aAAa;QAChB,GAAG,SAAS;QACZ,WAAW,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,WAAW,CAAC;KACjG,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export type WidgetType = 'stat' | 'gauge' | 'line' | 'doughnut' | 'bar' | 'event-log' | 'status-grid' | 'table';
|
|
2
|
+
export interface WidgetConfig {
|
|
3
|
+
/** Data key — dash.render({ [id]: value }) */
|
|
4
|
+
id: string;
|
|
5
|
+
/** Display title shown in panel header */
|
|
6
|
+
label: string;
|
|
7
|
+
/** Widget visualization type */
|
|
8
|
+
type: WidgetType;
|
|
9
|
+
/** Grid column span (default 1) */
|
|
10
|
+
span?: number;
|
|
11
|
+
/** Single letter shortcut — shown as [X] badge in panel border */
|
|
12
|
+
shortcut?: string;
|
|
13
|
+
/** Label for the shortcut badge */
|
|
14
|
+
shortcutLabel?: string;
|
|
15
|
+
/** Minimum ms between updates for this widget. Defaults to global refresh rate. */
|
|
16
|
+
throttle?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface LayoutConfig {
|
|
19
|
+
/** Dashboard title (top bar) */
|
|
20
|
+
title?: string;
|
|
21
|
+
/** Top row stat/gauge cards */
|
|
22
|
+
stats?: WidgetConfig[];
|
|
23
|
+
/** Main grid panels */
|
|
24
|
+
panels?: WidgetConfig[];
|
|
25
|
+
/** Override default theme colors */
|
|
26
|
+
theme?: Partial<ThemeConfig>;
|
|
27
|
+
}
|
|
28
|
+
export interface ThemeConfig {
|
|
29
|
+
bg: string;
|
|
30
|
+
panelBg: string;
|
|
31
|
+
border: string;
|
|
32
|
+
text: string;
|
|
33
|
+
textMuted: string;
|
|
34
|
+
accent: string;
|
|
35
|
+
success: string;
|
|
36
|
+
warning: string;
|
|
37
|
+
danger: string;
|
|
38
|
+
purple: string;
|
|
39
|
+
chartColors: string[];
|
|
40
|
+
fontFamily: string;
|
|
41
|
+
}
|
|
42
|
+
export interface StatData {
|
|
43
|
+
value: number | string;
|
|
44
|
+
trend?: string;
|
|
45
|
+
unit?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface GaugeData {
|
|
48
|
+
value: number;
|
|
49
|
+
max?: number;
|
|
50
|
+
label?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface LineData {
|
|
53
|
+
series: Array<{
|
|
54
|
+
label: string;
|
|
55
|
+
data: number[];
|
|
56
|
+
}>;
|
|
57
|
+
max?: number;
|
|
58
|
+
}
|
|
59
|
+
export interface EventEntry {
|
|
60
|
+
text: string;
|
|
61
|
+
type?: 'info' | 'success' | 'warning' | 'error';
|
|
62
|
+
time?: string;
|
|
63
|
+
}
|
|
64
|
+
export interface StatusEntry {
|
|
65
|
+
label: string;
|
|
66
|
+
status: 'ok' | 'warn' | 'error' | 'unknown';
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/layout/types.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,KAAK,GAAG,WAAW,GAAG,aAAa,GAAG,OAAO,CAAA;AAE/G,MAAM,WAAW,YAAY;IAC3B,8CAA8C;IAC9C,EAAE,EAAE,MAAM,CAAA;IACV,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAA;IACb,gCAAgC;IAChC,IAAI,EAAE,UAAU,CAAA;IAChB,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mCAAmC;IACnC,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAID,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,+BAA+B;IAC/B,KAAK,CAAC,EAAE,YAAY,EAAE,CAAA;IACtB,uBAAuB;IACvB,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;IACvB,oCAAoC;IACpC,KAAK,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;CAC7B;AAID,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;CACnB;AAID,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IACtB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;IAChD,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAA;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;CAC5C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/layout/types.ts"],"names":[],"mappings":"AAAA,gFAAgF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { LayoutConfig } from '../layout/types.js';
|
|
2
|
+
import type { ParsedData } from './types.js';
|
|
3
|
+
export declare function autoLayout(data: ParsedData, filePath?: string): LayoutConfig;
|
|
4
|
+
export declare function dataToWidgetData(data: ParsedData): Record<string, unknown>;
|
|
5
|
+
//# sourceMappingURL=auto-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-layout.d.ts","sourceRoot":"","sources":["../../src/quick/auto-layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,oBAAoB,CAAA;AACpE,OAAO,KAAK,EAAkC,UAAU,EAAE,MAAM,YAAY,CAAA;AAU5E,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,YAAY,CAa5E;AAwID,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAW1E"}
|