web-mojo 2.1.627 → 2.1.675

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-BmWwT0QF.js} +6 -6
  14. package/dist/chunks/{ChatView-swFqHyZi.js.map → ChatView-BmWwT0QF.js.map} +1 -1
  15. package/dist/chunks/{ChatView-BjbXRdAB.js → ChatView-Dpxy85W3.js} +2 -2
  16. package/dist/chunks/{ChatView-BjbXRdAB.js.map → ChatView-Dpxy85W3.js.map} +1 -1
  17. package/dist/chunks/{ContextMenu-DeL1AJ2K.js → ContextMenu-C1A4AVbi.js} +2 -2
  18. package/dist/chunks/{ContextMenu-DeL1AJ2K.js.map → ContextMenu-C1A4AVbi.js.map} +1 -1
  19. package/dist/chunks/{ContextMenu-CyfbvpND.js → ContextMenu-CqUg8Aov.js} +2 -2
  20. package/dist/chunks/{ContextMenu-CyfbvpND.js.map → ContextMenu-CqUg8Aov.js.map} +1 -1
  21. package/dist/chunks/{DataView-gB9r-zaX.js → DataView-BZBAmV6d.js} +2 -2
  22. package/dist/chunks/{DataView-gB9r-zaX.js.map → DataView-BZBAmV6d.js.map} +1 -1
  23. package/dist/chunks/{DataView-jx8l28w_.js → DataView-C73dhEBE.js} +2 -2
  24. package/dist/chunks/{DataView-jx8l28w_.js.map → DataView-C73dhEBE.js.map} +1 -1
  25. package/dist/chunks/{Dialog-Cj0Qxc7O.js → Dialog-CaQZlPs8.js} +5 -5
  26. package/dist/chunks/{Dialog-Cj0Qxc7O.js.map → Dialog-CaQZlPs8.js.map} +1 -1
  27. package/dist/chunks/{Dialog-JhRBUdiM.js → Dialog-CsYKb5_K.js} +2 -2
  28. package/dist/chunks/{Dialog-JhRBUdiM.js.map → Dialog-CsYKb5_K.js.map} +1 -1
  29. package/dist/chunks/{FormView-CpChFpxv.js → FormView-BQet49yz.js} +2 -2
  30. package/dist/chunks/{FormView-CpChFpxv.js.map → FormView-BQet49yz.js.map} +1 -1
  31. package/dist/chunks/{FormView-bFKcq_xg.js → FormView-C5gHgWj-.js} +2 -2
  32. package/dist/chunks/{FormView-bFKcq_xg.js.map → FormView-C5gHgWj-.js.map} +1 -1
  33. package/dist/chunks/{MetricsChart-DS6rz7HC.js → MetricsMiniChartWidget-0QE0WL-x.js} +771 -4
  34. package/dist/chunks/MetricsMiniChartWidget-0QE0WL-x.js.map +1 -0
  35. package/dist/chunks/{MetricsChart-Dv49hXjf.js → MetricsMiniChartWidget-hp1SBgB2.js} +2 -2
  36. package/dist/chunks/MetricsMiniChartWidget-hp1SBgB2.js.map +1 -0
  37. package/dist/chunks/{PDFViewer-CcHiuM7c.js → PDFViewer-CJAsn0H1.js} +3 -3
  38. package/dist/chunks/{PDFViewer-CcHiuM7c.js.map → PDFViewer-CJAsn0H1.js.map} +1 -1
  39. package/dist/chunks/{PDFViewer-DnsHONcG.js → PDFViewer-CX5bKmKa.js} +2 -2
  40. package/dist/chunks/{PDFViewer-DnsHONcG.js.map → PDFViewer-CX5bKmKa.js.map} +1 -1
  41. package/dist/chunks/{Page-DmOy8qUF.js → Page-DJtwfAf4.js} +2 -2
  42. package/dist/chunks/{Page-DmOy8qUF.js.map → Page-DJtwfAf4.js.map} +1 -1
  43. package/dist/chunks/{Page-DdYMaASr.js → Page-Oo8qO-IX.js} +2 -2
  44. package/dist/chunks/{Page-DdYMaASr.js.map → Page-Oo8qO-IX.js.map} +1 -1
  45. package/dist/chunks/{TopNav-CN_2e_48.js → TopNav-C4tISlAt.js} +2 -2
  46. package/dist/chunks/{TopNav-CN_2e_48.js.map → TopNav-C4tISlAt.js.map} +1 -1
  47. package/dist/chunks/{TopNav-Bat8EzdF.js → TopNav-QlJo-F9B.js} +5 -5
  48. package/dist/chunks/{TopNav-Bat8EzdF.js.map → TopNav-QlJo-F9B.js.map} +1 -1
  49. package/dist/chunks/{WebApp-DeoEYrl6.js → WebApp-BWnjZ-UU.js} +14 -13
  50. package/dist/chunks/{WebApp-DeoEYrl6.js.map → WebApp-BWnjZ-UU.js.map} +1 -1
  51. package/dist/chunks/{WebApp-DpGABopL.js → WebApp-DgFbFcSM.js} +2 -2
  52. package/dist/chunks/{WebApp-DpGABopL.js.map → WebApp-DgFbFcSM.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-CaQZlPs8.js";
2
+ import { V as View, d as dataFormatter } from "./WebApp-BWnjZ-UU.js";
3
3
  import { W as WebSocketClient } from "./WebSocketClient-B6ribe3B.js";
4
4
  class BaseChart extends View {
5
5
  constructor(options = {}) {
@@ -2092,10 +2092,777 @@ 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
+ }
2095
2859
  export {
2096
2860
  BaseChart as B,
2097
2861
  MetricsChart as M,
2098
2862
  PieChart as P,
2099
- SeriesChart as S
2863
+ SeriesChart as S,
2864
+ MiniChart as a,
2865
+ MetricsMiniChart as b,
2866
+ MetricsMiniChartWidget as c
2100
2867
  };
2101
- //# sourceMappingURL=MetricsChart-DS6rz7HC.js.map
2868
+ //# sourceMappingURL=MetricsMiniChartWidget-0QE0WL-x.js.map