web-mojo 2.1.528 → 2.1.529

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.
Files changed (57) hide show
  1. package/dist/admin.cjs.js +1 -1
  2. package/dist/admin.es.js +10 -10
  3. package/dist/auth.cjs.js +1 -1
  4. package/dist/auth.cjs.js.map +1 -1
  5. package/dist/auth.es.js +3 -3
  6. package/dist/auth.es.js.map +1 -1
  7. package/dist/charts.cjs.js +1 -1
  8. package/dist/charts.cjs.js.map +1 -1
  9. package/dist/charts.es.js +679 -2
  10. package/dist/charts.es.js.map +1 -1
  11. package/dist/chunks/{ChatView-DnPPYYCT.js → ChatView-5DP7NWav.js} +6 -6
  12. package/dist/chunks/{ChatView-DnPPYYCT.js.map → ChatView-5DP7NWav.js.map} +1 -1
  13. package/dist/chunks/{ChatView-Qwuok8bH.js → ChatView-D0uBPb-J.js} +2 -2
  14. package/dist/chunks/{ChatView-Qwuok8bH.js.map → ChatView-D0uBPb-J.js.map} +1 -1
  15. package/dist/chunks/{ContextMenu-CgQIud8b.js → ContextMenu-C_0Ufmea.js} +2 -2
  16. package/dist/chunks/{ContextMenu-CgQIud8b.js.map → ContextMenu-C_0Ufmea.js.map} +1 -1
  17. package/dist/chunks/{ContextMenu-DgF_M_Pj.js → ContextMenu-D7PRlvcY.js} +2 -2
  18. package/dist/chunks/{ContextMenu-DgF_M_Pj.js.map → ContextMenu-D7PRlvcY.js.map} +1 -1
  19. package/dist/chunks/{DataView-BHTwAHpY.js → DataView-COb1gukO.js} +2 -2
  20. package/dist/chunks/{DataView-BHTwAHpY.js.map → DataView-COb1gukO.js.map} +1 -1
  21. package/dist/chunks/{DataView-BEqs1Pbg.js → DataView-T7wmnYqr.js} +2 -2
  22. package/dist/chunks/{DataView-BEqs1Pbg.js.map → DataView-T7wmnYqr.js.map} +1 -1
  23. package/dist/chunks/{Dialog-DNDFTWv_.js → Dialog-BX09s8EF.js} +2 -2
  24. package/dist/chunks/{Dialog-DNDFTWv_.js.map → Dialog-BX09s8EF.js.map} +1 -1
  25. package/dist/chunks/{Dialog-WCJDa_8U.js → Dialog-dm5fTLiY.js} +5 -5
  26. package/dist/chunks/{Dialog-WCJDa_8U.js.map → Dialog-dm5fTLiY.js.map} +1 -1
  27. package/dist/chunks/{FormView-DH-UJLzo.js → FormView--Wybw8OP.js} +2 -2
  28. package/dist/chunks/{FormView-DH-UJLzo.js.map → FormView--Wybw8OP.js.map} +1 -1
  29. package/dist/chunks/{FormView-Dcglin9Q.js → FormView-5PM8GJfG.js} +2 -2
  30. package/dist/chunks/{FormView-Dcglin9Q.js.map → FormView-5PM8GJfG.js.map} +1 -1
  31. package/dist/chunks/{MetricsChart-D-ZdyC42.js → MetricsChart-BWQ1YAJP.js} +2 -2
  32. package/dist/chunks/{MetricsChart-D-ZdyC42.js.map → MetricsChart-BWQ1YAJP.js.map} +1 -1
  33. package/dist/chunks/{MetricsChart-DGCKUIiB.js → MetricsChart-fDEOs6eG.js} +3 -3
  34. package/dist/chunks/{MetricsChart-DGCKUIiB.js.map → MetricsChart-fDEOs6eG.js.map} +1 -1
  35. package/dist/chunks/{PDFViewer-z84GKWqb.js → PDFViewer-BbYyy42P.js} +3 -3
  36. package/dist/chunks/{PDFViewer-z84GKWqb.js.map → PDFViewer-BbYyy42P.js.map} +1 -1
  37. package/dist/chunks/{PDFViewer-S1ivvTey.js → PDFViewer-DPhlBTFr.js} +2 -2
  38. package/dist/chunks/{PDFViewer-S1ivvTey.js.map → PDFViewer-DPhlBTFr.js.map} +1 -1
  39. package/dist/chunks/{Page-DUG_G5w_.js → Page-B7v6uh02.js} +2 -2
  40. package/dist/chunks/{Page-DUG_G5w_.js.map → Page-B7v6uh02.js.map} +1 -1
  41. package/dist/chunks/{Page-DQiZAy4-.js → Page-CcIMnuov.js} +2 -2
  42. package/dist/chunks/{Page-DQiZAy4-.js.map → Page-CcIMnuov.js.map} +1 -1
  43. package/dist/chunks/{TopNav--ilmn8l5.js → TopNav-BC51rpEJ.js} +2 -2
  44. package/dist/chunks/{TopNav--ilmn8l5.js.map → TopNav-BC51rpEJ.js.map} +1 -1
  45. package/dist/chunks/{TopNav-eHFb32R9.js → TopNav-CudazPzU.js} +2 -2
  46. package/dist/chunks/{TopNav-eHFb32R9.js.map → TopNav-CudazPzU.js.map} +1 -1
  47. package/dist/chunks/{WebApp-DvBzh_tG.js → WebApp-C5V1vLhz.js} +2 -2
  48. package/dist/chunks/{WebApp-DvBzh_tG.js.map → WebApp-C5V1vLhz.js.map} +1 -1
  49. package/dist/chunks/{WebApp-DyegmBiJ.js → WebApp-tr4cjBu1.js} +13 -13
  50. package/dist/chunks/{WebApp-DyegmBiJ.js.map → WebApp-tr4cjBu1.js.map} +1 -1
  51. package/dist/docit.cjs.js +1 -1
  52. package/dist/docit.es.js +5 -5
  53. package/dist/index.cjs.js +1 -1
  54. package/dist/index.es.js +11 -11
  55. package/dist/lightbox.cjs.js +1 -1
  56. package/dist/lightbox.es.js +4 -4
  57. package/package.json +1 -1
package/dist/charts.es.js CHANGED
@@ -1,9 +1,686 @@
1
- import { B, M, P, S } from "./chunks/MetricsChart-DGCKUIiB.js";
2
- import { B as B2, b, a, c, e, f, W } from "./chunks/WebApp-DyegmBiJ.js";
1
+ import { B, M, P, S } from "./chunks/MetricsChart-fDEOs6eG.js";
2
+ import { V as View } from "./chunks/WebApp-tr4cjBu1.js";
3
+ import { B as B2, b, a, c, e, f, W } from "./chunks/WebApp-tr4cjBu1.js";
4
+ class MiniChart extends View {
5
+ constructor(options = {}) {
6
+ super({
7
+ className: "mini-chart",
8
+ ...options
9
+ });
10
+ this.chartType = options.chartType || "line";
11
+ this.data = options.data || [];
12
+ this.width = options.width || "100%";
13
+ this.height = options.height || 30;
14
+ this.maintainAspectRatio = options.maintainAspectRatio || false;
15
+ this.color = options.color || "rgba(54, 162, 235, 1)";
16
+ this.fillColor = options.fillColor || "rgba(54, 162, 235, 0.1)";
17
+ this.strokeWidth = options.strokeWidth || 2;
18
+ this.barGap = options.barGap || 2;
19
+ this.fill = options.fill !== false;
20
+ this.smoothing = options.smoothing || 0.3;
21
+ this.padding = options.padding || 2;
22
+ this.minValue = options.minValue;
23
+ this.maxValue = options.maxValue;
24
+ this.showDots = options.showDots || false;
25
+ this.dotRadius = options.dotRadius || 2;
26
+ this.animate = options.animate !== false;
27
+ this.animationDuration = options.animationDuration || 300;
28
+ this.showTooltip = options.showTooltip !== false;
29
+ this.tooltipFormatter = options.tooltipFormatter || null;
30
+ this.showCrosshair = options.showCrosshair !== false;
31
+ this.crosshairColor = options.crosshairColor || "rgba(0, 0, 0, 0.2)";
32
+ this.crosshairWidth = options.crosshairWidth || 1;
33
+ this.tooltip = null;
34
+ this.crosshair = null;
35
+ this.hoveredIndex = -1;
36
+ }
37
+ getTemplate() {
38
+ const widthStyle = typeof this.width === "number" ? `${this.width}px` : this.width;
39
+ const heightStyle = typeof this.height === "number" ? `${this.height}px` : this.height;
40
+ const preserveAspectRatio = this.maintainAspectRatio ? "xMidYMid meet" : "none";
41
+ return `
42
+ <div class="mini-chart-wrapper" style="position: relative; display: block; width: ${widthStyle}; height: ${heightStyle};">
43
+ <svg
44
+ class="mini-chart-svg"
45
+ width="100%"
46
+ height="100%"
47
+ viewBox="0 0 100 ${this.height}"
48
+ preserveAspectRatio="${preserveAspectRatio}"
49
+ style="display: block;">
50
+ </svg>
51
+ ${this.showTooltip ? '<div class="mini-chart-tooltip" style="display: none;"></div>' : ""}
52
+ </div>
53
+ `;
54
+ }
55
+ async onAfterRender() {
56
+ this.svg = this.element.querySelector(".mini-chart-svg");
57
+ this.tooltip = this.element.querySelector(".mini-chart-tooltip");
58
+ this.updateDimensions();
59
+ if (this.data && this.data.length > 0) {
60
+ this.renderChart();
61
+ }
62
+ if (this.showTooltip && this.svg) {
63
+ this.setupTooltip();
64
+ }
65
+ this.setupResizeObserver();
66
+ }
67
+ updateDimensions() {
68
+ if (!this.svg) return;
69
+ const rect = this.svg.getBoundingClientRect();
70
+ this.actualWidth = rect.width || 100;
71
+ this.actualHeight = rect.height || this.height;
72
+ this.svg.setAttribute("viewBox", `0 0 ${this.actualWidth} ${this.actualHeight}`);
73
+ }
74
+ setupResizeObserver() {
75
+ if (typeof ResizeObserver === "undefined") return;
76
+ this.resizeObserver = new ResizeObserver(() => {
77
+ this.updateDimensions();
78
+ if (this.data && this.data.length > 0) {
79
+ this.renderChart();
80
+ }
81
+ });
82
+ if (this.svg) {
83
+ this.resizeObserver.observe(this.svg);
84
+ }
85
+ }
86
+ renderChart() {
87
+ if (!this.svg || !this.data || this.data.length === 0) return;
88
+ this.svg.innerHTML = "";
89
+ const { min, max } = this.calculateBounds();
90
+ if (this.chartType === "line") {
91
+ this.renderLine(min, max);
92
+ } else if (this.chartType === "bar") {
93
+ this.renderBar(min, max);
94
+ }
95
+ if (this.showCrosshair) {
96
+ const height = this.getActualHeight();
97
+ this.crosshair = this.createSVGElement("line", {
98
+ x1: 0,
99
+ y1: 0,
100
+ x2: 0,
101
+ y2: height,
102
+ stroke: this.crosshairColor,
103
+ "stroke-width": this.crosshairWidth,
104
+ "stroke-dasharray": "3,3",
105
+ style: "display: none; pointer-events: none;"
106
+ });
107
+ this.svg.appendChild(this.crosshair);
108
+ }
109
+ if (this.showTooltip && this.tooltip) {
110
+ this.setupTooltip();
111
+ }
112
+ if (this.animate) {
113
+ this.applyAnimation();
114
+ }
115
+ }
116
+ calculateBounds() {
117
+ const values = this.data.map((d) => typeof d === "object" ? d.value : d);
118
+ let min = this.minValue !== void 0 ? this.minValue : Math.min(...values);
119
+ let max = this.maxValue !== void 0 ? this.maxValue : Math.max(...values);
120
+ const range = max - min;
121
+ if (range === 0) {
122
+ min = min - 1;
123
+ max = max + 1;
124
+ }
125
+ return { min, max };
126
+ }
127
+ getActualWidth() {
128
+ return this.actualWidth || this.width || 100;
129
+ }
130
+ getActualHeight() {
131
+ return this.actualHeight || this.height || 30;
132
+ }
133
+ renderLine(min, max) {
134
+ const values = this.data.map((d) => typeof d === "object" ? d.value : d);
135
+ const points = this.calculatePoints(values, min, max);
136
+ if (this.fill) {
137
+ const areaPath = this.createAreaPath(points);
138
+ const area = this.createSVGElement("path", {
139
+ d: areaPath,
140
+ fill: this.fillColor,
141
+ stroke: "none"
142
+ });
143
+ this.svg.appendChild(area);
144
+ }
145
+ const linePath = this.smoothing > 0 ? this.createSmoothPath(points) : this.createLinePath(points);
146
+ const line = this.createSVGElement("path", {
147
+ d: linePath,
148
+ fill: "none",
149
+ stroke: this.color,
150
+ "stroke-width": this.strokeWidth,
151
+ "stroke-linecap": "round",
152
+ "stroke-linejoin": "round"
153
+ });
154
+ this.svg.appendChild(line);
155
+ if (this.showDots) {
156
+ points.forEach((point) => {
157
+ const dot = this.createSVGElement("circle", {
158
+ cx: point.x,
159
+ cy: point.y,
160
+ r: this.dotRadius,
161
+ fill: this.color
162
+ });
163
+ this.svg.appendChild(dot);
164
+ });
165
+ }
166
+ }
167
+ renderBar(min, max) {
168
+ const values = this.data.map((d) => typeof d === "object" ? d.value : d);
169
+ const points = this.calculatePoints(values, min, max);
170
+ const width = this.getActualWidth();
171
+ const height = this.getActualHeight();
172
+ const barWidth = (width - this.padding * 2 - this.barGap * (values.length - 1)) / values.length;
173
+ points.forEach((point, index) => {
174
+ const barHeight = height - this.padding * 2 - point.y + this.padding;
175
+ const x = point.x - barWidth / 2;
176
+ const y = point.y;
177
+ const bar = this.createSVGElement("rect", {
178
+ x,
179
+ y,
180
+ width: barWidth,
181
+ height: barHeight,
182
+ fill: this.color,
183
+ rx: 1,
184
+ // Slight rounding
185
+ "data-bar-index": index,
186
+ class: "mini-chart-bar"
187
+ });
188
+ this.svg.appendChild(bar);
189
+ });
190
+ }
191
+ calculatePoints(values, min, max) {
192
+ const range = max - min;
193
+ const width = this.getActualWidth();
194
+ const height = this.getActualHeight();
195
+ const xStep = (width - this.padding * 2) / (values.length - 1 || 1);
196
+ const yScale = (height - this.padding * 2) / range;
197
+ return values.map((value, index) => ({
198
+ x: this.padding + index * xStep,
199
+ y: height - this.padding - (value - min) * yScale
200
+ }));
201
+ }
202
+ createLinePath(points) {
203
+ if (points.length === 0) return "";
204
+ let path = `M ${points[0].x},${points[0].y}`;
205
+ for (let i = 1; i < points.length; i++) {
206
+ path += ` L ${points[i].x},${points[i].y}`;
207
+ }
208
+ return path;
209
+ }
210
+ createSmoothPath(points) {
211
+ if (points.length < 2) return this.createLinePath(points);
212
+ let path = `M ${points[0].x},${points[0].y}`;
213
+ for (let i = 0; i < points.length - 1; i++) {
214
+ const current = points[i];
215
+ const next = points[i + 1];
216
+ const cp1x = current.x + (next.x - current.x) * this.smoothing;
217
+ const cp1y = current.y;
218
+ const cp2x = next.x - (next.x - current.x) * this.smoothing;
219
+ const cp2y = next.y;
220
+ path += ` C ${cp1x},${cp1y} ${cp2x},${cp2y} ${next.x},${next.y}`;
221
+ }
222
+ return path;
223
+ }
224
+ createAreaPath(points) {
225
+ if (points.length === 0) return "";
226
+ const linePath = this.smoothing > 0 ? this.createSmoothPath(points) : this.createLinePath(points);
227
+ const lastPoint = points[points.length - 1];
228
+ const firstPoint = points[0];
229
+ const height = this.getActualHeight();
230
+ return `${linePath} L ${lastPoint.x},${height - this.padding} L ${firstPoint.x},${height - this.padding} Z`;
231
+ }
232
+ createSVGElement(tag, attributes = {}) {
233
+ const element = document.createElementNS("http://www.w3.org/2000/svg", tag);
234
+ Object.entries(attributes).forEach(([key, value]) => {
235
+ element.setAttribute(key, value);
236
+ });
237
+ return element;
238
+ }
239
+ applyAnimation() {
240
+ const paths = this.svg.querySelectorAll("path");
241
+ paths.forEach((path) => {
242
+ const length = path.getTotalLength();
243
+ path.style.strokeDasharray = length;
244
+ path.style.strokeDashoffset = length;
245
+ path.style.animation = `mini-chart-draw ${this.animationDuration}ms ease-out forwards`;
246
+ });
247
+ const bars = this.svg.querySelectorAll("rect");
248
+ bars.forEach((bar, index) => {
249
+ bar.style.transformOrigin = "bottom";
250
+ bar.style.animation = `mini-chart-bar-grow ${this.animationDuration}ms ease-out ${index * 20}ms forwards`;
251
+ bar.style.transform = "scaleY(0)";
252
+ });
253
+ }
254
+ setupTooltip() {
255
+ if (!this.svg || !this.tooltip) return;
256
+ const values = this.data.map((d) => typeof d === "object" ? d.value : d);
257
+ const points = this.calculatePoints(values, ...Object.values(this.calculateBounds()));
258
+ const width = this.getActualWidth();
259
+ const height = this.getActualHeight();
260
+ const barWidth = width / values.length;
261
+ points.forEach((point, index) => {
262
+ const hitArea = this.createSVGElement("rect", {
263
+ x: index * barWidth,
264
+ y: 0,
265
+ width: barWidth,
266
+ height,
267
+ fill: "transparent",
268
+ style: "cursor: pointer;"
269
+ });
270
+ hitArea.addEventListener("mouseenter", (e2) => {
271
+ this.showTooltipAtIndex(index, e2);
272
+ });
273
+ hitArea.addEventListener("mousemove", (e2) => {
274
+ this.updateTooltipPosition(e2);
275
+ });
276
+ hitArea.addEventListener("mouseleave", () => {
277
+ this.hideTooltip();
278
+ });
279
+ this.svg.appendChild(hitArea);
280
+ });
281
+ }
282
+ showTooltipAtIndex(index, event) {
283
+ if (!this.tooltip) return;
284
+ this.hoveredIndex = index;
285
+ const value = typeof this.data[index] === "object" ? this.data[index].value : this.data[index];
286
+ const label = typeof this.data[index] === "object" ? this.data[index].label : null;
287
+ let displayValue = value;
288
+ if (this.tooltipFormatter) {
289
+ if (typeof this.tooltipFormatter === "function") {
290
+ displayValue = this.tooltipFormatter(value, index);
291
+ }
292
+ } else {
293
+ displayValue = typeof value === "number" ? value.toLocaleString() : value;
294
+ }
295
+ let content = `<strong>${displayValue}</strong>`;
296
+ if (label) {
297
+ content = `${label}<br>${content}`;
298
+ }
299
+ this.tooltip.innerHTML = content;
300
+ this.tooltip.style.display = "block";
301
+ this.updateTooltipPosition(event);
302
+ if (this.chartType === "bar") {
303
+ this.highlightBar(index);
304
+ }
305
+ if (this.crosshair && this.showCrosshair) {
306
+ const width = this.getActualWidth();
307
+ const barWidth = width / this.data.length;
308
+ const x = index * barWidth + barWidth / 2;
309
+ this.crosshair.setAttribute("x1", x);
310
+ this.crosshair.setAttribute("x2", x);
311
+ this.crosshair.style.display = "block";
312
+ }
313
+ }
314
+ updateTooltipPosition(event) {
315
+ if (!this.tooltip || this.tooltip.style.display === "none") return;
316
+ const rect = this.svg.getBoundingClientRect();
317
+ const x = event.clientX - rect.left;
318
+ const y = event.clientY - rect.top;
319
+ this.tooltip.style.left = `${x}px`;
320
+ this.tooltip.style.top = `${y - 10}px`;
321
+ this.tooltip.style.transform = "translate(-50%, -100%)";
322
+ }
323
+ hideTooltip() {
324
+ if (this.tooltip) {
325
+ this.tooltip.style.display = "none";
326
+ this.hoveredIndex = -1;
327
+ }
328
+ if (this.chartType === "bar") {
329
+ this.unhighlightBars();
330
+ }
331
+ if (this.crosshair) {
332
+ this.crosshair.style.display = "none";
333
+ }
334
+ }
335
+ highlightBar(index) {
336
+ if (!this.svg) return;
337
+ this.unhighlightBars();
338
+ const bar = this.svg.querySelector(`rect.mini-chart-bar[data-bar-index="${index}"]`);
339
+ if (bar) {
340
+ bar.style.opacity = "0.7";
341
+ }
342
+ }
343
+ unhighlightBars() {
344
+ if (!this.svg) return;
345
+ const bars = this.svg.querySelectorAll("rect.mini-chart-bar");
346
+ bars.forEach((bar) => {
347
+ bar.style.opacity = "1";
348
+ });
349
+ }
350
+ // Public API
351
+ setData(data) {
352
+ this.data = data;
353
+ if (this.svg) {
354
+ this.renderChart();
355
+ }
356
+ }
357
+ setColor(color) {
358
+ this.color = color;
359
+ if (this.svg) {
360
+ this.renderChart();
361
+ }
362
+ }
363
+ setType(type) {
364
+ if (["line", "bar"].includes(type)) {
365
+ this.chartType = type;
366
+ if (this.svg) {
367
+ this.renderChart();
368
+ }
369
+ }
370
+ }
371
+ resize(width, height) {
372
+ this.width = width;
373
+ this.height = height;
374
+ this.updateDimensions();
375
+ if (this.svg) {
376
+ this.renderChart();
377
+ }
378
+ }
379
+ async onBeforeDestroy() {
380
+ if (this.resizeObserver) {
381
+ this.resizeObserver.disconnect();
382
+ this.resizeObserver = null;
383
+ }
384
+ await super.onBeforeDestroy();
385
+ }
386
+ }
387
+ class MetricsMiniChart extends View {
388
+ constructor(options = {}) {
389
+ super({
390
+ className: "metrics-mini-chart",
391
+ ...options
392
+ });
393
+ this.label = options.label || "";
394
+ this.value = options.value || 0;
395
+ this.data = options.data || [];
396
+ this.trend = options.trend;
397
+ this.trendValue = options.trendValue;
398
+ this.chartType = options.chartType || "line";
399
+ this.chartWidth = options.chartWidth || 100;
400
+ this.chartHeight = options.chartHeight || 40;
401
+ this.chartColor = options.chartColor || "rgba(54, 162, 235, 1)";
402
+ this.fill = options.fill !== false;
403
+ this.smoothing = options.smoothing || 0.3;
404
+ this.valueFormatter = options.valueFormatter || null;
405
+ this.suffix = options.suffix || "";
406
+ this.prefix = options.prefix || "";
407
+ this.variant = options.variant || "default";
408
+ this.size = options.size || "md";
409
+ this.layout = options.layout || "horizontal";
410
+ this.endpoint = options.endpoint || "/api/metrics/fetch";
411
+ this.account = options.account || "global";
412
+ this.granularity = options.granularity || "hours";
413
+ this.slugs = options.slugs || null;
414
+ this.category = options.category || null;
415
+ this.dateStart = options.dateStart || null;
416
+ this.dateEnd = options.dateEnd || null;
417
+ this.defaultDateRange = options.defaultDateRange || "24h";
418
+ this.isLoading = false;
419
+ this.lastFetch = null;
420
+ this.refreshInterval = options.refreshInterval;
421
+ if (!this.dateStart || !this.dateEnd) {
422
+ this.setQuickRange(this.defaultDateRange);
423
+ }
424
+ if (this.slugs && !Array.isArray(this.slugs)) {
425
+ this.slugs = [this.slugs];
426
+ }
427
+ this.miniChart = null;
428
+ }
429
+ getTemplate() {
430
+ const sizeClass = `metrics-mini-chart-${this.size}`;
431
+ const variantClass = this.variant !== "default" ? `metrics-mini-chart-${this.variant}` : "";
432
+ const layoutClass = `metrics-mini-chart-${this.layout}`;
433
+ return `
434
+ <div class="metrics-mini-chart-container ${sizeClass} ${variantClass} ${layoutClass}">
435
+ <div class="metrics-info">
436
+ <div class="metrics-label">${this.escapeHtml(this.label)}</div>
437
+ <div class="metrics-value-row">
438
+ <div class="metrics-value" data-ref="value">
439
+ ${this.formatValue(this.value)}
440
+ </div>
441
+ ${this.renderTrendBadge()}
442
+ </div>
443
+ </div>
444
+ <div class="metrics-chart" data-container="chart"></div>
445
+ </div>
446
+ `;
447
+ }
448
+ async onInit() {
449
+ this.miniChart = new MiniChart({
450
+ chartType: this.chartType,
451
+ data: this.data,
452
+ width: this.chartWidth,
453
+ height: this.chartHeight,
454
+ color: this.getChartColor(),
455
+ fillColor: this.getFillColor(),
456
+ fill: this.fill,
457
+ smoothing: this.smoothing,
458
+ animate: true
459
+ });
460
+ this.addChild(this.miniChart, "chart");
461
+ if (this.refreshInterval && this.endpoint) {
462
+ this.startAutoRefresh();
463
+ }
464
+ }
465
+ async onAfterRender() {
466
+ await super.onAfterRender();
467
+ if (this.endpoint && this.data.length === 0) {
468
+ await this.fetchData();
469
+ }
470
+ }
471
+ renderTrendBadge() {
472
+ if (!this.trend && this.trendValue === void 0) {
473
+ return "";
474
+ }
475
+ const trend = this.trend || (this.trendValue > 0 ? "up" : "down");
476
+ const trendIcon = trend === "up" ? "bi-arrow-up" : "bi-arrow-down";
477
+ const trendClass = trend === "up" ? "trend-up" : "trend-down";
478
+ const trendValueStr = this.trendValue !== void 0 ? `${Math.abs(this.trendValue)}%` : "";
479
+ return `
480
+ <span class="metrics-trend ${trendClass}">
481
+ <i class="bi ${trendIcon}"></i>
482
+ ${trendValueStr}
483
+ </span>
484
+ `;
485
+ }
486
+ getChartColor() {
487
+ const colorMap = {
488
+ success: "rgba(75, 192, 192, 1)",
489
+ danger: "rgba(255, 99, 132, 1)",
490
+ warning: "rgba(255, 206, 86, 1)",
491
+ info: "rgba(54, 162, 235, 1)",
492
+ default: this.chartColor
493
+ };
494
+ return colorMap[this.variant] || this.chartColor;
495
+ }
496
+ getFillColor() {
497
+ const color = this.getChartColor();
498
+ return color.replace(/[\d.]+\)$/, "0.1)");
499
+ }
500
+ formatValue(value) {
501
+ let formatted = value;
502
+ if (this.valueFormatter) {
503
+ if (typeof this.valueFormatter === "function") {
504
+ formatted = this.valueFormatter(value);
505
+ } else if (this.dataFormatter) {
506
+ formatted = this.dataFormatter.pipe(value, this.valueFormatter);
507
+ }
508
+ } else {
509
+ if (typeof value === "number") {
510
+ formatted = value.toLocaleString();
511
+ }
512
+ }
513
+ return `${this.prefix}${formatted}${this.suffix}`;
514
+ }
515
+ escapeHtml(text) {
516
+ const div = document.createElement("div");
517
+ div.textContent = text;
518
+ return div.innerHTML;
519
+ }
520
+ buildApiParams() {
521
+ const params = {
522
+ granularity: this.granularity,
523
+ account: this.account,
524
+ with_labels: true
525
+ };
526
+ if (this.slugs && this.slugs.length > 0) {
527
+ this.slugs.forEach((slug) => {
528
+ if (!params["slugs[]"]) params["slugs[]"] = [];
529
+ params["slugs[]"].push(slug);
530
+ });
531
+ }
532
+ if (this.category) {
533
+ params.category = this.category;
534
+ }
535
+ if (this.dateStart) {
536
+ params.dr_start = Math.floor(this.dateStart.getTime() / 1e3);
537
+ }
538
+ if (this.dateEnd) {
539
+ params.dr_end = Math.floor(this.dateEnd.getTime() / 1e3);
540
+ }
541
+ params._ = Date.now();
542
+ return params;
543
+ }
544
+ async fetchData() {
545
+ if (!this.endpoint) return;
546
+ this.isLoading = true;
547
+ try {
548
+ const rest = this.getApp()?.rest;
549
+ if (!rest) {
550
+ throw new Error("No REST client available");
551
+ }
552
+ const params = this.buildApiParams();
553
+ const response = await rest.GET(this.endpoint, params);
554
+ if (!response.success) {
555
+ throw new Error(response.message || "Network error");
556
+ }
557
+ if (!response.data?.status) {
558
+ throw new Error(response.data?.error || "Server error");
559
+ }
560
+ const metricsData = response.data.data;
561
+ this.processMetricsData(metricsData);
562
+ this.lastFetch = /* @__PURE__ */ new Date();
563
+ await this.render();
564
+ this.emit("metrics:loaded", { chart: this, data: metricsData, params });
565
+ } catch (error) {
566
+ console.error("Failed to fetch metrics:", error);
567
+ this.emit("metrics:error", { chart: this, error });
568
+ } finally {
569
+ this.isLoading = false;
570
+ }
571
+ }
572
+ processMetricsData(metricsData) {
573
+ const { data: metrics, labels } = metricsData;
574
+ if (!metrics) return;
575
+ const metricKeys = Object.keys(metrics);
576
+ if (metricKeys.length === 0) return;
577
+ const metricSlug = metricKeys[0];
578
+ const values = metrics[metricSlug];
579
+ const sanitizedValues = values.map((val) => {
580
+ if (val === null || val === void 0 || val === "") return 0;
581
+ return typeof val === "number" ? val : parseFloat(val) || 0;
582
+ });
583
+ this.setData(sanitizedValues);
584
+ const currentValue = sanitizedValues[sanitizedValues.length - 1] || 0;
585
+ this.setValue(currentValue);
586
+ if (sanitizedValues.length >= 2) {
587
+ const firstValue = sanitizedValues[0];
588
+ const lastValue = sanitizedValues[sanitizedValues.length - 1];
589
+ if (firstValue !== 0) {
590
+ this.trendValue = parseFloat(((lastValue - firstValue) / firstValue * 100).toFixed(1));
591
+ this.trend = this.trendValue >= 0 ? "up" : "down";
592
+ }
593
+ }
594
+ }
595
+ setQuickRange(range) {
596
+ const now = /* @__PURE__ */ new Date();
597
+ let startDate;
598
+ switch (range) {
599
+ case "1h":
600
+ startDate = new Date(now.getTime() - 60 * 60 * 1e3);
601
+ break;
602
+ case "24h":
603
+ startDate = new Date(now.getTime() - 24 * 60 * 60 * 1e3);
604
+ break;
605
+ case "7d":
606
+ startDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1e3);
607
+ break;
608
+ case "30d":
609
+ startDate = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1e3);
610
+ break;
611
+ default:
612
+ startDate = new Date(now.getTime() - 24 * 60 * 60 * 1e3);
613
+ }
614
+ this.dateStart = startDate;
615
+ this.dateEnd = now;
616
+ }
617
+ startAutoRefresh() {
618
+ if (this.refreshTimer) {
619
+ clearInterval(this.refreshTimer);
620
+ }
621
+ this.refreshTimer = setInterval(() => {
622
+ this.fetchData();
623
+ }, this.refreshInterval);
624
+ }
625
+ stopAutoRefresh() {
626
+ if (this.refreshTimer) {
627
+ clearInterval(this.refreshTimer);
628
+ this.refreshTimer = null;
629
+ }
630
+ }
631
+ // Public API
632
+ setValue(value) {
633
+ this.value = value;
634
+ const valueElement = this.element?.querySelector('[data-ref="value"]');
635
+ if (valueElement) {
636
+ valueElement.textContent = this.formatValue(value);
637
+ }
638
+ }
639
+ setData(data) {
640
+ this.data = data;
641
+ if (this.miniChart) {
642
+ this.miniChart.setData(data);
643
+ }
644
+ if (data.length >= 2 && this.trendValue === void 0) {
645
+ const first = typeof data[0] === "object" ? data[0].value : data[0];
646
+ const last = typeof data[data.length - 1] === "object" ? data[data.length - 1].value : data[data.length - 1];
647
+ if (first !== 0) {
648
+ this.trendValue = ((last - first) / first * 100).toFixed(1);
649
+ this.trend = this.trendValue > 0 ? "up" : "down";
650
+ }
651
+ }
652
+ }
653
+ setLabel(label) {
654
+ this.label = label;
655
+ const labelElement = this.element?.querySelector(".metrics-label");
656
+ if (labelElement) {
657
+ labelElement.textContent = label;
658
+ }
659
+ }
660
+ setVariant(variant) {
661
+ if (this.element) {
662
+ this.element.querySelector(".metrics-mini-chart-container")?.classList.remove(`metrics-mini-chart-${this.variant}`);
663
+ this.element.querySelector(".metrics-mini-chart-container")?.classList.add(`metrics-mini-chart-${variant}`);
664
+ }
665
+ this.variant = variant;
666
+ if (this.miniChart) {
667
+ this.miniChart.setColor(this.getChartColor());
668
+ }
669
+ }
670
+ refresh() {
671
+ return this.fetchData();
672
+ }
673
+ async onBeforeDestroy() {
674
+ this.stopAutoRefresh();
675
+ await super.onBeforeDestroy();
676
+ }
677
+ }
3
678
  export {
4
679
  B2 as BUILD_TIME,
5
680
  B as BaseChart,
6
681
  M as MetricsChart,
682
+ MetricsMiniChart,
683
+ MiniChart,
7
684
  P as PieChart,
8
685
  S as SeriesChart,
9
686
  b as VERSION,