web-mojo 2.1.627 → 2.1.676

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 (61) hide show
  1. package/dist/admin.cjs.js +1 -1
  2. package/dist/admin.cjs.js.map +1 -1
  3. package/dist/admin.es.js +105 -75
  4. package/dist/admin.es.js.map +1 -1
  5. package/dist/auth.cjs.js +1 -1
  6. package/dist/auth.cjs.js.map +1 -1
  7. package/dist/auth.es.js +3 -3
  8. package/dist/auth.es.js.map +1 -1
  9. package/dist/charts.cjs.js +1 -1
  10. package/dist/charts.cjs.js.map +1 -1
  11. package/dist/charts.es.js +8 -590
  12. package/dist/charts.es.js.map +1 -1
  13. package/dist/chunks/{ChatView-swFqHyZi.js → ChatView-B3p8qSTr.js} +6 -6
  14. package/dist/chunks/{ChatView-swFqHyZi.js.map → ChatView-B3p8qSTr.js.map} +1 -1
  15. package/dist/chunks/{ChatView-BjbXRdAB.js → ChatView-BGlI_MSK.js} +2 -2
  16. package/dist/chunks/{ChatView-BjbXRdAB.js.map → ChatView-BGlI_MSK.js.map} +1 -1
  17. package/dist/chunks/{ContextMenu-CyfbvpND.js → ContextMenu-Bx0cE5UR.js} +2 -2
  18. package/dist/chunks/{ContextMenu-CyfbvpND.js.map → ContextMenu-Bx0cE5UR.js.map} +1 -1
  19. package/dist/chunks/{ContextMenu-DeL1AJ2K.js → ContextMenu-C5T3u9pD.js} +2 -2
  20. package/dist/chunks/{ContextMenu-DeL1AJ2K.js.map → ContextMenu-C5T3u9pD.js.map} +1 -1
  21. package/dist/chunks/{DataView-gB9r-zaX.js → DataView-DnmzuwRI.js} +2 -2
  22. package/dist/chunks/{DataView-gB9r-zaX.js.map → DataView-DnmzuwRI.js.map} +1 -1
  23. package/dist/chunks/{DataView-jx8l28w_.js → DataView-Qn3t_qcS.js} +2 -2
  24. package/dist/chunks/{DataView-jx8l28w_.js.map → DataView-Qn3t_qcS.js.map} +1 -1
  25. package/dist/chunks/{Dialog-Cj0Qxc7O.js → Dialog-CDwoJqc9.js} +5 -5
  26. package/dist/chunks/{Dialog-Cj0Qxc7O.js.map → Dialog-CDwoJqc9.js.map} +1 -1
  27. package/dist/chunks/{Dialog-JhRBUdiM.js → Dialog-DMXaIubd.js} +2 -2
  28. package/dist/chunks/{Dialog-JhRBUdiM.js.map → Dialog-DMXaIubd.js.map} +1 -1
  29. package/dist/chunks/{FormView-bFKcq_xg.js → FormView-66LGmBqh.js} +2 -2
  30. package/dist/chunks/{FormView-bFKcq_xg.js.map → FormView-66LGmBqh.js.map} +1 -1
  31. package/dist/chunks/{FormView-CpChFpxv.js → FormView-DP6RZ-L7.js} +2 -2
  32. package/dist/chunks/{FormView-CpChFpxv.js.map → FormView-DP6RZ-L7.js.map} +1 -1
  33. package/dist/chunks/{MetricsChart-DS6rz7HC.js → MetricsMiniChartWidget-CzqKovoB.js} +777 -4
  34. package/dist/chunks/MetricsMiniChartWidget-CzqKovoB.js.map +1 -0
  35. package/dist/chunks/{MetricsChart-Dv49hXjf.js → MetricsMiniChartWidget-hthLm2UU.js} +2 -2
  36. package/dist/chunks/MetricsMiniChartWidget-hthLm2UU.js.map +1 -0
  37. package/dist/chunks/{PDFViewer-DnsHONcG.js → PDFViewer-B1mYS5sx.js} +2 -2
  38. package/dist/chunks/{PDFViewer-DnsHONcG.js.map → PDFViewer-B1mYS5sx.js.map} +1 -1
  39. package/dist/chunks/{PDFViewer-CcHiuM7c.js → PDFViewer-DcCMCAcj.js} +3 -3
  40. package/dist/chunks/{PDFViewer-CcHiuM7c.js.map → PDFViewer-DcCMCAcj.js.map} +1 -1
  41. package/dist/chunks/{Page-DmOy8qUF.js → Page-CTj8NKBW.js} +2 -2
  42. package/dist/chunks/{Page-DmOy8qUF.js.map → Page-CTj8NKBW.js.map} +1 -1
  43. package/dist/chunks/{Page-DdYMaASr.js → Page-CayRLia1.js} +2 -2
  44. package/dist/chunks/{Page-DdYMaASr.js.map → Page-CayRLia1.js.map} +1 -1
  45. package/dist/chunks/{TopNav-Bat8EzdF.js → TopNav-CKO0_lBo.js} +5 -5
  46. package/dist/chunks/{TopNav-Bat8EzdF.js.map → TopNav-CKO0_lBo.js.map} +1 -1
  47. package/dist/chunks/{TopNav-CN_2e_48.js → TopNav-DMkIwiOK.js} +2 -2
  48. package/dist/chunks/{TopNav-CN_2e_48.js.map → TopNav-DMkIwiOK.js.map} +1 -1
  49. package/dist/chunks/{WebApp-DpGABopL.js → WebApp-BEjXQJb8.js} +2 -2
  50. package/dist/chunks/{WebApp-DpGABopL.js.map → WebApp-BEjXQJb8.js.map} +1 -1
  51. package/dist/chunks/{WebApp-DeoEYrl6.js → WebApp-nRyeYQ0g.js} +14 -13
  52. package/dist/chunks/{WebApp-DeoEYrl6.js.map → WebApp-nRyeYQ0g.js.map} +1 -1
  53. package/dist/docit.cjs.js +1 -1
  54. package/dist/docit.es.js +5 -5
  55. package/dist/index.cjs.js +1 -1
  56. package/dist/index.es.js +11 -11
  57. package/dist/lightbox.cjs.js +1 -1
  58. package/dist/lightbox.es.js +4 -4
  59. package/package.json +1 -1
  60. package/dist/chunks/MetricsChart-DS6rz7HC.js.map +0 -1
  61. package/dist/chunks/MetricsChart-Dv49hXjf.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import Dialog from "./Dialog-Cj0Qxc7O.js";
2
- import { V as View, d as dataFormatter } from "./WebApp-DeoEYrl6.js";
1
+ import Dialog from "./Dialog-CDwoJqc9.js";
2
+ import { V as View, d as dataFormatter } from "./WebApp-nRyeYQ0g.js";
3
3
  import { W as WebSocketClient } from "./WebSocketClient-B6ribe3B.js";
4
4
  class BaseChart extends View {
5
5
  constructor(options = {}) {
@@ -2092,10 +2092,783 @@ class MetricsChart extends SeriesChart {
2092
2092
  };
2093
2093
  }
2094
2094
  }
2095
+ class MiniChart extends View {
2096
+ constructor(options = {}) {
2097
+ super({
2098
+ className: "mini-chart",
2099
+ ...options
2100
+ });
2101
+ this.chartType = options.chartType || "line";
2102
+ this.data = options.data || [];
2103
+ this.width = options.width || "100%";
2104
+ this.height = options.height || 30;
2105
+ this.maintainAspectRatio = options.maintainAspectRatio || false;
2106
+ this.color = options.color || "rgba(54, 162, 235, 1)";
2107
+ this.fillColor = options.fillColor || "rgba(54, 162, 235, 0.1)";
2108
+ this.strokeWidth = options.strokeWidth || 2;
2109
+ this.barGap = options.barGap || 2;
2110
+ this.fill = options.fill !== false;
2111
+ this.smoothing = options.smoothing || 0.3;
2112
+ this.padding = options.padding || 2;
2113
+ this.minValue = options.minValue;
2114
+ this.maxValue = options.maxValue;
2115
+ this.showDots = options.showDots || false;
2116
+ this.dotRadius = options.dotRadius || 2;
2117
+ this.animate = options.animate !== false;
2118
+ this.animationDuration = options.animationDuration || 300;
2119
+ this.showTooltip = options.showTooltip !== false;
2120
+ this.tooltipFormatter = options.tooltipFormatter || null;
2121
+ this.tooltipTemplate = options.tooltipTemplate || null;
2122
+ this.valueFormat = options.valueFormat || null;
2123
+ this.labelFormat = options.labelFormat || null;
2124
+ this.showCrosshair = options.showCrosshair !== false;
2125
+ this.crosshairColor = options.crosshairColor || "rgba(0, 0, 0, 0.2)";
2126
+ this.crosshairWidth = options.crosshairWidth || 1;
2127
+ this.showXAxis = options.showXAxis || false;
2128
+ this.xAxisColor = options.xAxisColor || this.color;
2129
+ this.xAxisWidth = options.xAxisWidth || 1;
2130
+ this.xAxisDashed = options.xAxisDashed !== false;
2131
+ this.tooltip = null;
2132
+ this.crosshair = null;
2133
+ this.hoveredIndex = -1;
2134
+ this.dataFormatter = dataFormatter;
2135
+ this.labels = options.labels || null;
2136
+ }
2137
+ getTemplate() {
2138
+ const widthStyle = typeof this.width === "number" ? `${this.width}px` : this.width;
2139
+ const heightStyle = typeof this.height === "number" ? `${this.height}px` : this.height;
2140
+ const preserveAspectRatio = this.maintainAspectRatio ? "xMidYMid meet" : "none";
2141
+ return `
2142
+ <div class="mini-chart-wrapper" style="position: relative; display: block; width: ${widthStyle}; height: ${heightStyle};">
2143
+ <svg
2144
+ class="mini-chart-svg"
2145
+ width="100%"
2146
+ height="100%"
2147
+ viewBox="0 0 100 ${this.height}"
2148
+ preserveAspectRatio="${preserveAspectRatio}"
2149
+ style="display: block;">
2150
+ </svg>
2151
+ ${this.showTooltip ? '<div class="mini-chart-tooltip" style="display: none;"></div>' : ""}
2152
+ </div>
2153
+ `;
2154
+ }
2155
+ async onAfterRender() {
2156
+ this.svg = this.element.querySelector(".mini-chart-svg");
2157
+ this.tooltip = this.element.querySelector(".mini-chart-tooltip");
2158
+ this.updateDimensions();
2159
+ if (this.data && this.data.length > 0) {
2160
+ this.renderChart();
2161
+ }
2162
+ if (this.showTooltip && this.svg) {
2163
+ this.setupTooltip();
2164
+ }
2165
+ this.setupResizeObserver();
2166
+ }
2167
+ updateDimensions() {
2168
+ if (!this.svg) return;
2169
+ const rect = this.svg.getBoundingClientRect();
2170
+ this.actualWidth = rect.width || 100;
2171
+ this.actualHeight = rect.height || this.height;
2172
+ this.svg.setAttribute("viewBox", `0 0 ${this.actualWidth} ${this.actualHeight}`);
2173
+ }
2174
+ setupResizeObserver() {
2175
+ if (typeof ResizeObserver === "undefined") return;
2176
+ this.resizeObserver = new ResizeObserver(() => {
2177
+ this.updateDimensions();
2178
+ if (this.data && this.data.length > 0) {
2179
+ this.renderChart();
2180
+ }
2181
+ });
2182
+ if (this.svg) {
2183
+ this.resizeObserver.observe(this.svg);
2184
+ }
2185
+ }
2186
+ renderChart() {
2187
+ if (!this.svg || !this.data || this.data.length === 0) return;
2188
+ this.svg.innerHTML = "";
2189
+ const { min, max } = this.calculateBounds();
2190
+ if (this.showXAxis) {
2191
+ this.renderXAxis(min, max);
2192
+ }
2193
+ if (this.chartType === "line") {
2194
+ this.renderLine(min, max);
2195
+ } else if (this.chartType === "bar") {
2196
+ this.renderBar(min, max);
2197
+ }
2198
+ if (this.showCrosshair) {
2199
+ const height = this.getActualHeight();
2200
+ this.crosshair = this.createSVGElement("line", {
2201
+ x1: 0,
2202
+ y1: 0,
2203
+ x2: 0,
2204
+ y2: height,
2205
+ stroke: this.crosshairColor,
2206
+ "stroke-width": this.crosshairWidth,
2207
+ "stroke-dasharray": "3,3",
2208
+ style: "display: none; pointer-events: none;"
2209
+ });
2210
+ this.svg.appendChild(this.crosshair);
2211
+ }
2212
+ if (this.showTooltip && this.tooltip) {
2213
+ this.setupTooltip();
2214
+ }
2215
+ if (this.animate) {
2216
+ this.applyAnimation();
2217
+ }
2218
+ }
2219
+ renderXAxis(min, max) {
2220
+ const width = this.getActualWidth();
2221
+ const height = this.getActualHeight();
2222
+ let yPos;
2223
+ if (min <= 0 && max >= 0) {
2224
+ const range = max - min;
2225
+ const yScale = (height - this.padding * 2) / range;
2226
+ yPos = height - this.padding - (0 - min) * yScale;
2227
+ } else {
2228
+ yPos = height - this.padding;
2229
+ }
2230
+ const xAxis = this.createSVGElement("line", {
2231
+ x1: this.padding,
2232
+ y1: yPos,
2233
+ x2: width - this.padding,
2234
+ y2: yPos,
2235
+ stroke: this.xAxisColor,
2236
+ "stroke-width": this.xAxisWidth,
2237
+ "stroke-dasharray": this.xAxisDashed ? "2,2" : "none",
2238
+ "stroke-opacity": "0.5"
2239
+ });
2240
+ this.svg.appendChild(xAxis);
2241
+ }
2242
+ calculateBounds() {
2243
+ const values = this.data.map((d) => typeof d === "object" ? d.value : d);
2244
+ let min = this.minValue !== void 0 ? this.minValue : Math.min(...values);
2245
+ let max = this.maxValue !== void 0 ? this.maxValue : Math.max(...values);
2246
+ const range = max - min;
2247
+ if (range === 0) {
2248
+ if (this.chartType === "bar") {
2249
+ if (min === 0) {
2250
+ min = 0;
2251
+ max = 1;
2252
+ } else {
2253
+ min = min - 1;
2254
+ max = max + 1;
2255
+ }
2256
+ } else {
2257
+ min = min - 1;
2258
+ max = max + 1;
2259
+ }
2260
+ }
2261
+ return { min, max };
2262
+ }
2263
+ getActualWidth() {
2264
+ return this.actualWidth || this.width || 100;
2265
+ }
2266
+ getActualHeight() {
2267
+ return this.actualHeight || this.height || 30;
2268
+ }
2269
+ renderLine(min, max) {
2270
+ const values = this.data.map((d) => typeof d === "object" ? d.value : d);
2271
+ const points = this.calculatePoints(values, min, max);
2272
+ if (this.fill) {
2273
+ const areaPath = this.createAreaPath(points);
2274
+ const area = this.createSVGElement("path", {
2275
+ d: areaPath,
2276
+ fill: this.fillColor,
2277
+ stroke: "none"
2278
+ });
2279
+ this.svg.appendChild(area);
2280
+ }
2281
+ const linePath = this.smoothing > 0 ? this.createSmoothPath(points) : this.createLinePath(points);
2282
+ const line = this.createSVGElement("path", {
2283
+ d: linePath,
2284
+ fill: "none",
2285
+ stroke: this.color,
2286
+ "stroke-width": this.strokeWidth,
2287
+ "stroke-linecap": "round",
2288
+ "stroke-linejoin": "round"
2289
+ });
2290
+ this.svg.appendChild(line);
2291
+ if (this.showDots) {
2292
+ points.forEach((point) => {
2293
+ const dot = this.createSVGElement("circle", {
2294
+ cx: point.x,
2295
+ cy: point.y,
2296
+ r: this.dotRadius,
2297
+ fill: this.color
2298
+ });
2299
+ this.svg.appendChild(dot);
2300
+ });
2301
+ }
2302
+ }
2303
+ renderBar(min, max) {
2304
+ const values = this.data.map((d) => typeof d === "object" ? d.value : d);
2305
+ const points = this.calculatePoints(values, min, max);
2306
+ const width = this.getActualWidth();
2307
+ const height = this.getActualHeight();
2308
+ const barWidth = (width - this.padding * 2 - this.barGap * (values.length - 1)) / values.length;
2309
+ points.forEach((point, index) => {
2310
+ const barHeight = height - this.padding * 2 - point.y + this.padding;
2311
+ const x = point.x - barWidth / 2;
2312
+ const y = point.y;
2313
+ const bar = this.createSVGElement("rect", {
2314
+ x,
2315
+ y,
2316
+ width: barWidth,
2317
+ height: barHeight,
2318
+ fill: this.color,
2319
+ rx: 1,
2320
+ // Slight rounding
2321
+ "data-bar-index": index,
2322
+ class: "mini-chart-bar"
2323
+ });
2324
+ this.svg.appendChild(bar);
2325
+ });
2326
+ }
2327
+ calculatePoints(values, min, max) {
2328
+ const range = max - min;
2329
+ const width = this.getActualWidth();
2330
+ const height = this.getActualHeight();
2331
+ const xStep = (width - this.padding * 2) / (values.length - 1 || 1);
2332
+ const yScale = (height - this.padding * 2) / range;
2333
+ return values.map((value, index) => ({
2334
+ x: this.padding + index * xStep,
2335
+ y: height - this.padding - (value - min) * yScale
2336
+ }));
2337
+ }
2338
+ createLinePath(points) {
2339
+ if (points.length === 0) return "";
2340
+ let path = `M ${points[0].x},${points[0].y}`;
2341
+ for (let i = 1; i < points.length; i++) {
2342
+ path += ` L ${points[i].x},${points[i].y}`;
2343
+ }
2344
+ return path;
2345
+ }
2346
+ createSmoothPath(points) {
2347
+ if (points.length < 2) return this.createLinePath(points);
2348
+ let path = `M ${points[0].x},${points[0].y}`;
2349
+ for (let i = 0; i < points.length - 1; i++) {
2350
+ const current = points[i];
2351
+ const next = points[i + 1];
2352
+ const cp1x = current.x + (next.x - current.x) * this.smoothing;
2353
+ const cp1y = current.y;
2354
+ const cp2x = next.x - (next.x - current.x) * this.smoothing;
2355
+ const cp2y = next.y;
2356
+ path += ` C ${cp1x},${cp1y} ${cp2x},${cp2y} ${next.x},${next.y}`;
2357
+ }
2358
+ return path;
2359
+ }
2360
+ createAreaPath(points) {
2361
+ if (points.length === 0) return "";
2362
+ const linePath = this.smoothing > 0 ? this.createSmoothPath(points) : this.createLinePath(points);
2363
+ const lastPoint = points[points.length - 1];
2364
+ const firstPoint = points[0];
2365
+ const height = this.getActualHeight();
2366
+ return `${linePath} L ${lastPoint.x},${height - this.padding} L ${firstPoint.x},${height - this.padding} Z`;
2367
+ }
2368
+ createSVGElement(tag, attributes = {}) {
2369
+ const element = document.createElementNS("http://www.w3.org/2000/svg", tag);
2370
+ Object.entries(attributes).forEach(([key, value]) => {
2371
+ element.setAttribute(key, value);
2372
+ });
2373
+ return element;
2374
+ }
2375
+ applyAnimation() {
2376
+ const paths = this.svg.querySelectorAll("path");
2377
+ paths.forEach((path) => {
2378
+ const length = path.getTotalLength();
2379
+ path.style.strokeDasharray = length;
2380
+ path.style.strokeDashoffset = length;
2381
+ path.style.animation = `mini-chart-draw ${this.animationDuration}ms ease-out forwards`;
2382
+ });
2383
+ const bars = this.svg.querySelectorAll("rect");
2384
+ bars.forEach((bar, index) => {
2385
+ bar.style.transformOrigin = "bottom";
2386
+ bar.style.animation = `mini-chart-bar-grow ${this.animationDuration}ms ease-out ${index * 20}ms forwards`;
2387
+ bar.style.transform = "scaleY(0)";
2388
+ });
2389
+ }
2390
+ setupTooltip() {
2391
+ if (!this.svg || !this.tooltip) return;
2392
+ const values = this.data.map((d) => typeof d === "object" ? d.value : d);
2393
+ const points = this.calculatePoints(values, ...Object.values(this.calculateBounds()));
2394
+ const width = this.getActualWidth();
2395
+ const height = this.getActualHeight();
2396
+ const barWidth = width / values.length;
2397
+ points.forEach((point, index) => {
2398
+ const hitArea = this.createSVGElement("rect", {
2399
+ x: index * barWidth,
2400
+ y: 0,
2401
+ width: barWidth,
2402
+ height,
2403
+ fill: "transparent",
2404
+ style: "cursor: pointer;"
2405
+ });
2406
+ hitArea.addEventListener("mouseenter", (e) => {
2407
+ this.showTooltipAtIndex(index, e);
2408
+ });
2409
+ hitArea.addEventListener("mousemove", (e) => {
2410
+ this.updateTooltipPosition(e);
2411
+ });
2412
+ hitArea.addEventListener("mouseleave", () => {
2413
+ this.hideTooltip();
2414
+ });
2415
+ this.svg.appendChild(hitArea);
2416
+ });
2417
+ }
2418
+ showTooltipAtIndex(index, event) {
2419
+ if (!this.tooltip) return;
2420
+ this.hoveredIndex = index;
2421
+ const value = typeof this.data[index] === "object" ? this.data[index].value : this.data[index];
2422
+ const dataLabel = typeof this.data[index] === "object" ? this.data[index].label : null;
2423
+ const label = this.labels ? this.labels[index] : dataLabel;
2424
+ let content;
2425
+ if (this.tooltipTemplate && typeof this.tooltipTemplate === "function") {
2426
+ content = this.tooltipTemplate({ value, label, index, data: this.data[index] });
2427
+ } else {
2428
+ let displayValue = value;
2429
+ if (this.valueFormat && this.dataFormatter) {
2430
+ displayValue = this.dataFormatter.pipe(value, this.valueFormat);
2431
+ } else if (this.tooltipFormatter && typeof this.tooltipFormatter === "function") {
2432
+ displayValue = this.tooltipFormatter(value, index);
2433
+ } else {
2434
+ displayValue = typeof value === "number" ? value.toLocaleString() : value;
2435
+ }
2436
+ let displayLabel = label;
2437
+ if (label && this.labelFormat && this.dataFormatter) {
2438
+ displayLabel = this.dataFormatter.pipe(label, this.labelFormat);
2439
+ }
2440
+ content = `<strong>${displayValue}</strong>`;
2441
+ if (displayLabel) {
2442
+ content = `<div class="mini-chart-tooltip-label">${displayLabel}</div>${content}`;
2443
+ }
2444
+ }
2445
+ this.tooltip.innerHTML = content;
2446
+ this.tooltip.style.display = "block";
2447
+ this.updateTooltipPosition(event);
2448
+ if (this.chartType === "bar") {
2449
+ this.highlightBar(index);
2450
+ }
2451
+ if (this.crosshair && this.showCrosshair) {
2452
+ const width = this.getActualWidth();
2453
+ const barWidth = width / this.data.length;
2454
+ const x = index * barWidth + barWidth / 2;
2455
+ this.crosshair.setAttribute("x1", x);
2456
+ this.crosshair.setAttribute("x2", x);
2457
+ this.crosshair.style.display = "block";
2458
+ }
2459
+ }
2460
+ updateTooltipPosition(event) {
2461
+ if (!this.tooltip || this.tooltip.style.display === "none") return;
2462
+ const rect = this.svg.getBoundingClientRect();
2463
+ const x = event.clientX - rect.left;
2464
+ const y = event.clientY - rect.top;
2465
+ this.tooltip.style.left = `${x}px`;
2466
+ this.tooltip.style.top = `${y - 10}px`;
2467
+ this.tooltip.style.transform = "translate(-50%, -100%)";
2468
+ }
2469
+ hideTooltip() {
2470
+ if (this.tooltip) {
2471
+ this.tooltip.style.display = "none";
2472
+ this.hoveredIndex = -1;
2473
+ }
2474
+ if (this.chartType === "bar") {
2475
+ this.unhighlightBars();
2476
+ }
2477
+ if (this.crosshair) {
2478
+ this.crosshair.style.display = "none";
2479
+ }
2480
+ }
2481
+ highlightBar(index) {
2482
+ if (!this.svg) return;
2483
+ this.unhighlightBars();
2484
+ const bar = this.svg.querySelector(`rect.mini-chart-bar[data-bar-index="${index}"]`);
2485
+ if (bar) {
2486
+ bar.style.opacity = "0.7";
2487
+ }
2488
+ }
2489
+ unhighlightBars() {
2490
+ if (!this.svg) return;
2491
+ const bars = this.svg.querySelectorAll("rect.mini-chart-bar");
2492
+ bars.forEach((bar) => {
2493
+ bar.style.opacity = "1";
2494
+ });
2495
+ }
2496
+ // Public API
2497
+ setData(data) {
2498
+ this.data = data;
2499
+ if (this.svg) {
2500
+ this.renderChart();
2501
+ }
2502
+ }
2503
+ setColor(color) {
2504
+ this.color = color;
2505
+ if (this.svg) {
2506
+ this.renderChart();
2507
+ }
2508
+ }
2509
+ setType(type) {
2510
+ if (["line", "bar"].includes(type)) {
2511
+ this.chartType = type;
2512
+ if (this.svg) {
2513
+ this.renderChart();
2514
+ }
2515
+ }
2516
+ }
2517
+ resize(width, height) {
2518
+ this.width = width;
2519
+ this.height = height;
2520
+ this.updateDimensions();
2521
+ if (this.svg) {
2522
+ this.renderChart();
2523
+ }
2524
+ }
2525
+ async onBeforeDestroy() {
2526
+ if (this.resizeObserver) {
2527
+ this.resizeObserver.disconnect();
2528
+ this.resizeObserver = null;
2529
+ }
2530
+ await super.onBeforeDestroy();
2531
+ }
2532
+ }
2533
+ class MetricsMiniChart extends MiniChart {
2534
+ constructor(options = {}) {
2535
+ super(options);
2536
+ this.endpoint = options.endpoint || "/api/metrics/fetch";
2537
+ this.account = options.account || "global";
2538
+ this.granularity = options.granularity || "hours";
2539
+ this.slugs = options.slugs || null;
2540
+ this.category = options.category || null;
2541
+ this.dateStart = options.dateStart || null;
2542
+ this.dateEnd = options.dateEnd || null;
2543
+ this.defaultDateRange = options.defaultDateRange || "24h";
2544
+ this.isLoading = false;
2545
+ this.lastFetch = null;
2546
+ this.refreshInterval = options.refreshInterval;
2547
+ if (!this.dateStart || !this.dateEnd) {
2548
+ this.setQuickRange(this.defaultDateRange);
2549
+ }
2550
+ if (this.slugs && !Array.isArray(this.slugs)) {
2551
+ this.slugs = [this.slugs];
2552
+ }
2553
+ }
2554
+ async onAfterRender() {
2555
+ await super.onAfterRender();
2556
+ if (this.endpoint && (!this.data || this.data.length === 0)) {
2557
+ await this.fetchData();
2558
+ }
2559
+ if (this.refreshInterval && this.endpoint) {
2560
+ this.startAutoRefresh();
2561
+ }
2562
+ }
2563
+ buildApiParams() {
2564
+ const params = {
2565
+ granularity: this.granularity,
2566
+ account: this.account,
2567
+ with_labels: true
2568
+ };
2569
+ if (this.slugs && this.slugs.length > 0) {
2570
+ this.slugs.forEach((slug) => {
2571
+ if (!params["slugs[]"]) params["slugs[]"] = [];
2572
+ params["slugs[]"].push(slug);
2573
+ });
2574
+ }
2575
+ if (this.category) {
2576
+ params.category = this.category;
2577
+ }
2578
+ if (this.dateStart) {
2579
+ params.dr_start = Math.floor(this.dateStart.getTime() / 1e3);
2580
+ }
2581
+ if (this.dateEnd) {
2582
+ params.dr_end = Math.floor(this.dateEnd.getTime() / 1e3);
2583
+ }
2584
+ params._ = Date.now();
2585
+ return params;
2586
+ }
2587
+ async fetchData() {
2588
+ if (!this.endpoint) return;
2589
+ this.isLoading = true;
2590
+ try {
2591
+ const rest = this.getApp()?.rest;
2592
+ if (!rest) {
2593
+ throw new Error("No REST client available");
2594
+ }
2595
+ const params = this.buildApiParams();
2596
+ const response = await rest.GET(this.endpoint, params);
2597
+ if (!response.success) {
2598
+ throw new Error(response.message || "Network error");
2599
+ }
2600
+ if (!response.data?.status) {
2601
+ throw new Error(response.data?.error || "Server error");
2602
+ }
2603
+ const metricsData = response.data.data;
2604
+ this.processMetricsData(metricsData);
2605
+ this.lastFetch = /* @__PURE__ */ new Date();
2606
+ await this.render();
2607
+ this.emit("metrics:loaded", { chart: this, data: metricsData, params });
2608
+ } catch (error) {
2609
+ console.error("Failed to fetch metrics:", error);
2610
+ this.emit("metrics:error", { chart: this, error });
2611
+ } finally {
2612
+ this.isLoading = false;
2613
+ }
2614
+ }
2615
+ processMetricsData(metricsData) {
2616
+ const { data: metrics, labels } = metricsData;
2617
+ if (!metrics) return;
2618
+ const metricKeys = Object.keys(metrics);
2619
+ if (metricKeys.length === 0) return;
2620
+ const metricSlug = metricKeys[0];
2621
+ const values = metrics[metricSlug];
2622
+ const sanitizedValues = values.map((val) => {
2623
+ if (val === null || val === void 0 || val === "") return 0;
2624
+ return typeof val === "number" ? val : parseFloat(val) || 0;
2625
+ });
2626
+ this.labels = labels || null;
2627
+ this.setData(sanitizedValues);
2628
+ }
2629
+ setQuickRange(range) {
2630
+ const now = /* @__PURE__ */ new Date();
2631
+ let startDate;
2632
+ switch (range) {
2633
+ case "1h":
2634
+ startDate = new Date(now.getTime() - 60 * 60 * 1e3);
2635
+ break;
2636
+ case "24h":
2637
+ startDate = new Date(now.getTime() - 24 * 60 * 60 * 1e3);
2638
+ break;
2639
+ case "7d":
2640
+ startDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1e3);
2641
+ break;
2642
+ case "30d":
2643
+ startDate = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1e3);
2644
+ break;
2645
+ default:
2646
+ startDate = new Date(now.getTime() - 24 * 60 * 60 * 1e3);
2647
+ }
2648
+ this.dateStart = startDate;
2649
+ this.dateEnd = now;
2650
+ }
2651
+ startAutoRefresh() {
2652
+ if (this.refreshTimer) {
2653
+ clearInterval(this.refreshTimer);
2654
+ }
2655
+ this.refreshTimer = setInterval(() => {
2656
+ this.fetchData();
2657
+ }, this.refreshInterval);
2658
+ }
2659
+ stopAutoRefresh() {
2660
+ if (this.refreshTimer) {
2661
+ clearInterval(this.refreshTimer);
2662
+ this.refreshTimer = null;
2663
+ }
2664
+ }
2665
+ // Public API
2666
+ setGranularity(granularity) {
2667
+ this.granularity = granularity;
2668
+ return this.fetchData();
2669
+ }
2670
+ setDateRange(startDate, endDate) {
2671
+ this.dateStart = new Date(startDate);
2672
+ this.dateEnd = new Date(endDate);
2673
+ return this.fetchData();
2674
+ }
2675
+ setMetrics(slugs) {
2676
+ this.slugs = Array.isArray(slugs) ? slugs : [slugs];
2677
+ return this.fetchData();
2678
+ }
2679
+ refresh() {
2680
+ return this.fetchData();
2681
+ }
2682
+ async onBeforeDestroy() {
2683
+ this.stopAutoRefresh();
2684
+ await super.onBeforeDestroy();
2685
+ }
2686
+ }
2687
+ class MetricsMiniChartWidget extends View {
2688
+ constructor(options = {}) {
2689
+ super({
2690
+ ...options,
2691
+ tagName: "div",
2692
+ className: `metrics-mini-chart-widget ${options.className || ""}`.trim()
2693
+ });
2694
+ this.icon = options.icon || null;
2695
+ this.title = options.title || "";
2696
+ this.subtitle = options.subtitle || "";
2697
+ this.background = options.background || null;
2698
+ this.textColor = options.textColor || null;
2699
+ this.showTrending = !!options.showTrending;
2700
+ this.total = 0;
2701
+ this.lastValue = 0;
2702
+ this.prevValue = 0;
2703
+ this.trendingPercent = 0;
2704
+ this.trendingUp = null;
2705
+ this.hasTrending = false;
2706
+ this.trendingClass = "";
2707
+ this.trendingIcon = "";
2708
+ this.trendingLabel = "";
2709
+ this.chartOptions = {
2710
+ endpoint: options.endpoint,
2711
+ // defaults inside MetricsMiniChart
2712
+ account: options.account,
2713
+ granularity: options.granularity,
2714
+ slugs: options.slugs,
2715
+ category: options.category,
2716
+ dateStart: options.dateStart,
2717
+ dateEnd: options.dateEnd,
2718
+ defaultDateRange: options.defaultDateRange,
2719
+ refreshInterval: options.refreshInterval,
2720
+ // Visuals and interactions
2721
+ chartType: options.chartType || "line",
2722
+ showTooltip: options.showTooltip !== void 0 ? options.showTooltip : true,
2723
+ showXAxis: options.showXAxis || false,
2724
+ height: options.height || 80,
2725
+ width: options.chartWidth || options.width || "100%",
2726
+ color: options.color,
2727
+ fill: options.fill !== void 0 ? options.fill : true,
2728
+ fillColor: options.fillColor,
2729
+ smoothing: options.smoothing ?? 0.3,
2730
+ strokeWidth: options.strokeWidth,
2731
+ barGap: options.barGap,
2732
+ // Optional formatters and templates
2733
+ valueFormat: options.valueFormat,
2734
+ labelFormat: options.labelFormat,
2735
+ tooltipFormatter: options.tooltipFormatter,
2736
+ tooltipTemplate: options.tooltipTemplate,
2737
+ // Crosshair and axis styling overrides (optional passthroughs)
2738
+ showCrosshair: options.showCrosshair,
2739
+ crosshairColor: options.crosshairColor,
2740
+ crosshairWidth: options.crosshairWidth,
2741
+ xAxisColor: options.xAxisColor,
2742
+ xAxisWidth: options.xAxisWidth,
2743
+ xAxisDashed: options.xAxisDashed,
2744
+ // Other rendering params
2745
+ padding: options.padding,
2746
+ minValue: options.minValue,
2747
+ maxValue: options.maxValue,
2748
+ showDots: options.showDots,
2749
+ dotRadius: options.dotRadius,
2750
+ animate: options.animate,
2751
+ animationDuration: options.animationDuration
2752
+ };
2753
+ }
2754
+ async onInit() {
2755
+ this.chart = new MetricsMiniChart({
2756
+ ...this.chartOptions,
2757
+ containerId: "chart"
2758
+ // mount inside our template container
2759
+ });
2760
+ this.addChild(this.chart);
2761
+ this.header = new View({
2762
+ containerId: "chart-header",
2763
+ title: this.title,
2764
+ icon: this.icon,
2765
+ template: `
2766
+ <div class="d-flex justify-content-between align-items-start mb-2">
2767
+ <div class="me-3">
2768
+ <h6 class="card-title mb-1" style="${this.textColor ? `color: ${this.textColor}` : ""}">{{title}}</h6>
2769
+ <div class="card-subtitle" style="${this.textColor ? `color: ${this.textColor}` : ""}">${this.subtitle}</div>
2770
+ {{#hasTrending}}
2771
+ <div class="small mt-1 fw-semibold {{trendingClass}}" style="${this.textColor ? `color: ${this.textColor}` : ""}">
2772
+ <i class="{{trendingIcon}} me-1"></i>{{trendingLabel}}
2773
+ </div>
2774
+ {{/hasTrending}}
2775
+ </div>
2776
+ ${this.icon ? `<i class="${this.icon} fs-4 flex-shrink-0" aria-hidden="true" style="${this.textColor ? `color: ${this.textColor}` : ""}"></i>` : ""}
2777
+ </div>`
2778
+ });
2779
+ this.addChild(this.header);
2780
+ if (this.chart?.on) {
2781
+ this.chart.on("metrics:loaded", this.onChildMetricsLoaded, this);
2782
+ }
2783
+ this.updateFromChartData({ render: false });
2784
+ }
2785
+ onChildMetricsLoaded() {
2786
+ this.updateFromChartData({ render: true });
2787
+ }
2788
+ updateFromChartData({ render = true } = {}) {
2789
+ const values = Array.isArray(this.chart?.data) ? this.chart.data : null;
2790
+ if (!values || values.length === 0) {
2791
+ this.total = 0;
2792
+ this.hasTrending = false;
2793
+ this.header.title = this.title;
2794
+ if (render) this.render();
2795
+ return;
2796
+ }
2797
+ const nums = values.map((v) => {
2798
+ if (typeof v === "number") return v;
2799
+ if (v && typeof v.value === "number") return v.value;
2800
+ const n = parseFloat(v);
2801
+ return Number.isNaN(n) ? 0 : n;
2802
+ });
2803
+ this.header.title = this.title;
2804
+ this.header.total = nums.reduce((a, b) => a + b, 0);
2805
+ this.header.now_value = nums[nums.length - 1];
2806
+ if (nums.length >= 2) {
2807
+ const last = nums[nums.length - 1];
2808
+ const prev = nums[nums.length - 2];
2809
+ this.header.lastValue = last;
2810
+ this.header.prevValue = prev;
2811
+ let percent = 0;
2812
+ if (prev === 0) {
2813
+ percent = last > 0 ? 100 : 0;
2814
+ } else {
2815
+ percent = (last - prev) / Math.abs(prev) * 100;
2816
+ }
2817
+ this.header.trendingPercent = percent;
2818
+ this.header.trendingUp = percent >= 0;
2819
+ if (!this.textColor) {
2820
+ this.header.trendingClass = this.header.trendingUp ? "text-success" : "text-danger";
2821
+ } else {
2822
+ this.header.trendingClass = "";
2823
+ }
2824
+ this.header.trendingIcon = this.header.trendingUp ? "bi bi-arrow-up" : "bi bi-arrow-down";
2825
+ const sign = percent > 0 ? "+" : "";
2826
+ this.header.trendingLabel = `${sign}${percent.toFixed(1)}%`;
2827
+ this.header.hasTrending = true;
2828
+ } else {
2829
+ this.header.hasTrending = false;
2830
+ }
2831
+ if (render) {
2832
+ this.header.render();
2833
+ }
2834
+ }
2835
+ get cardStyle() {
2836
+ const styles = [];
2837
+ if (this.background) styles.push(`background: ${this.background}`);
2838
+ if (this.textColor) styles.push(`color: ${this.textColor}`);
2839
+ styles.push("border: 0");
2840
+ return styles.join("; ");
2841
+ }
2842
+ async getTemplate() {
2843
+ return `
2844
+ <div class="card h-100 shadow-sm" style="${this.cardStyle}">
2845
+ <div class="card-body p-3">
2846
+ <div data-container="chart-header"></div>
2847
+ <div data-container="chart"></div>
2848
+ </div>
2849
+ </div>
2850
+ `;
2851
+ }
2852
+ async onBeforeDestroy() {
2853
+ if (this.chart?.off) {
2854
+ this.chart.off("metrics:loaded", this.onChildMetricsLoaded, this);
2855
+ }
2856
+ await super.onBeforeDestroy();
2857
+ }
2858
+ refresh() {
2859
+ if (this.chart) {
2860
+ this.chart.account = this.account;
2861
+ this.chart.refresh();
2862
+ }
2863
+ }
2864
+ }
2095
2865
  export {
2096
2866
  BaseChart as B,
2097
2867
  MetricsChart as M,
2098
2868
  PieChart as P,
2099
- SeriesChart as S
2869
+ SeriesChart as S,
2870
+ MiniChart as a,
2871
+ MetricsMiniChart as b,
2872
+ MetricsMiniChartWidget as c
2100
2873
  };
2101
- //# sourceMappingURL=MetricsChart-DS6rz7HC.js.map
2874
+ //# sourceMappingURL=MetricsMiniChartWidget-CzqKovoB.js.map