@flanksource/clicky-ui 0.3.4 → 0.3.6

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 (77) hide show
  1. package/dist/ai.cjs +15 -0
  2. package/dist/ai.cjs.map +1 -1
  3. package/dist/ai.js +15 -0
  4. package/dist/ai.js.map +1 -1
  5. package/dist/data/ProgressBars.cjs +194 -0
  6. package/dist/data/ProgressBars.cjs.map +1 -0
  7. package/dist/data/ProgressBars.d.ts +85 -0
  8. package/dist/data/ProgressBars.d.ts.map +1 -0
  9. package/dist/data/ProgressBars.js +194 -0
  10. package/dist/data/ProgressBars.js.map +1 -0
  11. package/dist/data/ProgressBars.model.cjs +27 -0
  12. package/dist/data/ProgressBars.model.cjs.map +1 -0
  13. package/dist/data/ProgressBars.model.d.ts +20 -0
  14. package/dist/data/ProgressBars.model.d.ts.map +1 -0
  15. package/dist/data/ProgressBars.model.js +27 -0
  16. package/dist/data/ProgressBars.model.js.map +1 -0
  17. package/dist/data/TimeseriesCoreBars.cjs +19 -173
  18. package/dist/data/TimeseriesCoreBars.cjs.map +1 -1
  19. package/dist/data/TimeseriesCoreBars.d.ts +9 -26
  20. package/dist/data/TimeseriesCoreBars.d.ts.map +1 -1
  21. package/dist/data/TimeseriesCoreBars.js +20 -174
  22. package/dist/data/TimeseriesCoreBars.js.map +1 -1
  23. package/dist/data/WorkloadCard.model.cjs.map +1 -1
  24. package/dist/data/WorkloadCard.model.d.ts +2 -2
  25. package/dist/data/WorkloadCard.model.d.ts.map +1 -1
  26. package/dist/data/WorkloadCard.model.js.map +1 -1
  27. package/dist/data/ai/SessionViewer.cjs +275 -0
  28. package/dist/data/ai/SessionViewer.cjs.map +1 -0
  29. package/dist/data/ai/SessionViewer.d.ts +33 -0
  30. package/dist/data/ai/SessionViewer.d.ts.map +1 -0
  31. package/dist/data/ai/SessionViewer.fixtures.d.ts +4 -0
  32. package/dist/data/ai/SessionViewer.fixtures.d.ts.map +1 -0
  33. package/dist/data/ai/SessionViewer.js +275 -0
  34. package/dist/data/ai/SessionViewer.js.map +1 -0
  35. package/dist/data/ai/SessionViewer.model.cjs +275 -0
  36. package/dist/data/ai/SessionViewer.model.cjs.map +1 -0
  37. package/dist/data/ai/SessionViewer.model.d.ts +87 -0
  38. package/dist/data/ai/SessionViewer.model.d.ts.map +1 -0
  39. package/dist/data/ai/SessionViewer.model.js +275 -0
  40. package/dist/data/ai/SessionViewer.model.js.map +1 -0
  41. package/dist/data/ai/SessionViewerMenu.cjs +190 -0
  42. package/dist/data/ai/SessionViewerMenu.cjs.map +1 -0
  43. package/dist/data/ai/SessionViewerMenu.d.ts +24 -0
  44. package/dist/data/ai/SessionViewerMenu.d.ts.map +1 -0
  45. package/dist/data/ai/SessionViewerMenu.js +190 -0
  46. package/dist/data/ai/SessionViewerMenu.js.map +1 -0
  47. package/dist/data/ai/index.d.ts +3 -0
  48. package/dist/data/ai/index.d.ts.map +1 -1
  49. package/dist/data/ai/session-categories.cjs +219 -0
  50. package/dist/data/ai/session-categories.cjs.map +1 -0
  51. package/dist/data/ai/session-categories.d.ts +36 -0
  52. package/dist/data/ai/session-categories.d.ts.map +1 -0
  53. package/dist/data/ai/session-categories.js +219 -0
  54. package/dist/data/ai/session-categories.js.map +1 -0
  55. package/dist/data/test-runner/TestRunner.fixtures.d.ts.map +1 -1
  56. package/dist/data/version-info.cjs +3 -3
  57. package/dist/data/version-info.cjs.map +1 -1
  58. package/dist/data/version-info.js +3 -3
  59. package/dist/data/version-info.js.map +1 -1
  60. package/dist/data.cjs +4 -2
  61. package/dist/data.cjs.map +1 -1
  62. package/dist/data.d.ts +3 -2
  63. package/dist/data.d.ts.map +1 -1
  64. package/dist/data.js +4 -2
  65. package/dist/data.js.map +1 -1
  66. package/dist/index.cjs +4 -2
  67. package/dist/index.cjs.map +1 -1
  68. package/dist/index.js +4 -2
  69. package/dist/index.js.map +1 -1
  70. package/dist/styles.css +1 -1
  71. package/package.json +1 -1
  72. package/dist/data/TimeseriesCoreBars.model.cjs +0 -27
  73. package/dist/data/TimeseriesCoreBars.model.cjs.map +0 -1
  74. package/dist/data/TimeseriesCoreBars.model.d.ts +0 -20
  75. package/dist/data/TimeseriesCoreBars.model.d.ts.map +0 -1
  76. package/dist/data/TimeseriesCoreBars.model.js +0 -27
  77. package/dist/data/TimeseriesCoreBars.model.js.map +0 -1
package/dist/ai.cjs CHANGED
@@ -1,14 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const sessionCategories = require("./data/ai/session-categories.cjs");
3
4
  const ChatFab = require("./data/ai/ChatFab.cjs");
4
5
  const ChatWindow = require("./data/ai/ChatWindow.cjs");
5
6
  const ChatWindowManager = require("./data/ai/ChatWindowManager.cjs");
6
7
  const ContextBadges = require("./data/ai/ContextBadges.cjs");
7
8
  const ContextUsage = require("./data/chat/ContextUsage.cjs");
9
+ const SessionViewer = require("./data/ai/SessionViewer.cjs");
8
10
  const ThreadPicker = require("./data/ai/ThreadPicker.cjs");
9
11
  const ToolPreferences = require("./data/ai/ToolPreferences.cjs");
12
+ const SessionViewer_model = require("./data/ai/SessionViewer.model.cjs");
10
13
  const context = require("./data/ai/context.cjs");
11
14
  const chatWindowContext = require("./data/ai/chat-window-context.cjs");
15
+ exports.CATEGORY_LABELS = sessionCategories.CATEGORY_LABELS;
16
+ exports.classifyCommand = sessionCategories.classifyCommand;
17
+ exports.classifyToolCategory = sessionCategories.classifyToolCategory;
18
+ exports.collectSessionFilters = sessionCategories.collectSessionFilters;
19
+ exports.eventCategory = sessionCategories.eventCategory;
20
+ exports.isEventVisible = sessionCategories.isEventVisible;
12
21
  exports.ChatFab = ChatFab.ChatFab;
13
22
  exports.ChatWindow = ChatWindow.ChatWindow;
14
23
  exports.ChatWindowLayer = ChatWindow.ChatWindowLayer;
@@ -16,8 +25,14 @@ exports.ChatWindowManagerProvider = ChatWindowManager.ChatWindowManagerProvider;
16
25
  exports.ContextBadges = ContextBadges.ContextBadges;
17
26
  exports.ContextBadgesReadonly = ContextBadges.ContextBadgesReadonly;
18
27
  exports.ContextUsage = ContextUsage.ContextUsage;
28
+ exports.SessionViewer = SessionViewer.SessionViewer;
19
29
  exports.ThreadPicker = ThreadPicker.ThreadPicker;
20
30
  exports.ToolPreferences = ToolPreferences.ToolPreferences;
31
+ exports.getSessionAction = SessionViewer_model.getSessionAction;
32
+ exports.normalizeSession = SessionViewer_model.normalizeSession;
33
+ exports.splitMcpTool = SessionViewer_model.splitMcpTool;
34
+ exports.summarizeSession = SessionViewer_model.summarizeSession;
35
+ exports.summarizeToolInput = SessionViewer_model.summarizeToolInput;
21
36
  exports.makeContextId = context.makeContextId;
22
37
  exports.parseContextPrefix = context.parseContextPrefix;
23
38
  exports.serializeContext = context.serializeContext;
package/dist/ai.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ai.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"ai.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/ai.js CHANGED
@@ -1,13 +1,17 @@
1
+ import { CATEGORY_LABELS, classifyCommand, classifyToolCategory, collectSessionFilters, eventCategory, isEventVisible } from "./data/ai/session-categories.js";
1
2
  import { ChatFab } from "./data/ai/ChatFab.js";
2
3
  import { ChatWindow, ChatWindowLayer } from "./data/ai/ChatWindow.js";
3
4
  import { ChatWindowManagerProvider } from "./data/ai/ChatWindowManager.js";
4
5
  import { ContextBadges, ContextBadgesReadonly } from "./data/ai/ContextBadges.js";
5
6
  import { ContextUsage } from "./data/chat/ContextUsage.js";
7
+ import { SessionViewer } from "./data/ai/SessionViewer.js";
6
8
  import { ThreadPicker } from "./data/ai/ThreadPicker.js";
7
9
  import { ToolPreferences } from "./data/ai/ToolPreferences.js";
10
+ import { getSessionAction, normalizeSession, splitMcpTool, summarizeSession, summarizeToolInput } from "./data/ai/SessionViewer.model.js";
8
11
  import { makeContextId, parseContextPrefix, serializeContext } from "./data/ai/context.js";
9
12
  import { nextPromptId, useChatWindowManager } from "./data/ai/chat-window-context.js";
10
13
  export {
14
+ CATEGORY_LABELS,
11
15
  ChatFab,
12
16
  ChatWindow,
13
17
  ChatWindowLayer,
@@ -15,12 +19,23 @@ export {
15
19
  ContextBadges,
16
20
  ContextBadgesReadonly,
17
21
  ContextUsage,
22
+ SessionViewer,
18
23
  ThreadPicker,
19
24
  ToolPreferences,
25
+ classifyCommand,
26
+ classifyToolCategory,
27
+ collectSessionFilters,
28
+ eventCategory,
29
+ getSessionAction,
30
+ isEventVisible,
20
31
  makeContextId,
21
32
  nextPromptId,
33
+ normalizeSession,
22
34
  parseContextPrefix,
23
35
  serializeContext,
36
+ splitMcpTool,
37
+ summarizeSession,
38
+ summarizeToolInput,
24
39
  useChatWindowManager
25
40
  };
26
41
  //# sourceMappingURL=ai.js.map
package/dist/ai.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ai.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
1
+ {"version":3,"file":"ai.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;"}
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const utils = require("../lib/utils.cjs");
5
+ const Icon = require("./Icon.cjs");
6
+ const ProgressBars_model = require("./ProgressBars.model.cjs");
7
+ const GaugeHoverCard = require("./GaugeHoverCard.cjs");
8
+ function toneClass(pct, [warn, danger]) {
9
+ if (pct >= danger) return "bg-red-500";
10
+ if (pct >= warn) return "bg-amber-500";
11
+ return "bg-emerald-500";
12
+ }
13
+ function ProgressBarsIcon({ icon }) {
14
+ if (typeof icon === "string") {
15
+ return /* @__PURE__ */ jsxRuntime.jsx(
16
+ Icon.Icon,
17
+ {
18
+ name: icon,
19
+ width: 14,
20
+ height: 14,
21
+ className: "text-muted-foreground"
22
+ }
23
+ );
24
+ }
25
+ return /* @__PURE__ */ jsxRuntime.jsx(
26
+ Icon.Icon,
27
+ {
28
+ icon,
29
+ width: 14,
30
+ height: 14,
31
+ className: "text-muted-foreground"
32
+ }
33
+ );
34
+ }
35
+ function defaultFormatUnits(units) {
36
+ return Number.isInteger(units) ? String(units) : units.toFixed(1);
37
+ }
38
+ function ProgressBars({
39
+ usage,
40
+ max,
41
+ unit,
42
+ title,
43
+ icon,
44
+ thresholds = [75, 90],
45
+ variant = "default",
46
+ showLabel = true,
47
+ showValue = true,
48
+ showCapacity = false,
49
+ orientation,
50
+ stats,
51
+ hoverCard = true,
52
+ hoverFooter,
53
+ className
54
+ }) {
55
+ const perBar = (unit == null ? void 0 : unit.perBar) ?? 1e3;
56
+ const unitLabel = (unit == null ? void 0 : unit.label) ?? "cores";
57
+ const barLabel = (unit == null ? void 0 : unit.barLabel) ?? "core";
58
+ const formatUnits = (unit == null ? void 0 : unit.format) ?? defaultFormatUnits;
59
+ const model = ProgressBars_model.deriveProgressBars(usage, max, perBar);
60
+ const tone = toneClass(model.pct, thresholds);
61
+ const usageText = formatUnits(model.usageUnits);
62
+ const capacityText = model.limitUnits !== void 0 ? formatUnits(model.limitUnits) : "?";
63
+ const caption = !model.hasUsage ? "—" : showCapacity ? `${usageText} / ${capacityText} ${unitLabel}` : `${usageText} ${unitLabel}`;
64
+ const compactCaption = !model.hasUsage ? "—" : showCapacity ? `${usageText}/${capacityText} ${unitLabel}` : `${usageText} ${unitLabel}`;
65
+ const titleText = `${title}: ${compactCaption}`;
66
+ const isCell = variant === "cell";
67
+ const pctTone = model.limitUnits === void 0 ? void 0 : model.pct >= thresholds[1] ? "text-red-500" : model.pct >= thresholds[0] ? "text-amber-500" : "text-emerald-500";
68
+ const fmt = (n) => `${formatUnits(n)} ${unitLabel}`;
69
+ const hoverRows = model.hasUsage ? [
70
+ { label: "Current", value: fmt(model.usageUnits), ...pctTone ? { tone: pctTone } : {} },
71
+ ...stats ? [
72
+ { label: "Min", value: fmt(stats.min / perBar) },
73
+ { label: "Max", value: fmt(stats.max / perBar) },
74
+ { label: "Avg", value: fmt(stats.avg / perBar) }
75
+ ] : [],
76
+ ...model.limitUnits !== void 0 ? [{ label: "Capacity", value: fmt(model.limitUnits) }] : []
77
+ ] : [];
78
+ const resolvedOrientation = orientation ?? "vertical";
79
+ const isDense = model.barCount > 4;
80
+ const valueText = isCell ? compactCaption : caption;
81
+ const hiddenAccessibleText = !showLabel || !showValue ? titleText : void 0;
82
+ const bars = /* @__PURE__ */ jsxRuntime.jsx(
83
+ "span",
84
+ {
85
+ className: utils.cn(
86
+ "flex shrink-0",
87
+ resolvedOrientation === "vertical" ? utils.cn("items-end", isCell ? "h-4 gap-px" : "h-10 gap-0.5") : utils.cn(
88
+ "flex-col justify-center",
89
+ isCell ? "h-4 w-10 gap-px" : "h-10 w-16 gap-0.5"
90
+ )
91
+ ),
92
+ "aria-hidden": isCell ? "true" : void 0,
93
+ "data-orientation": resolvedOrientation,
94
+ "data-bar-count": model.barCount,
95
+ "data-bar-density": isDense ? "compact" : "default",
96
+ children: model.bars.map((bar, i) => {
97
+ const barPct = Math.round(bar.fill * 100);
98
+ return /* @__PURE__ */ jsxRuntime.jsx(
99
+ "span",
100
+ {
101
+ className: utils.cn(
102
+ "relative overflow-hidden bg-muted",
103
+ resolvedOrientation === "vertical" ? utils.cn(
104
+ "h-full",
105
+ isCell ? isDense ? "w-[3px] rounded-[2px]" : "w-1.5 rounded-[2px]" : isDense ? "w-1 rounded-sm" : "w-2 rounded-sm"
106
+ ) : utils.cn("min-h-px w-full flex-1 rounded-[2px]")
107
+ ),
108
+ title: `${barLabel} ${i + 1}: ${barPct}%`,
109
+ "aria-label": !isCell ? `${barLabel} ${i + 1}: ${barPct}%` : void 0,
110
+ "data-fill": bar.fill,
111
+ children: /* @__PURE__ */ jsxRuntime.jsx(
112
+ "span",
113
+ {
114
+ className: utils.cn(
115
+ "absolute bottom-0 left-0 transition-all duration-300",
116
+ tone
117
+ ),
118
+ style: resolvedOrientation === "vertical" ? { height: `${barPct}%`, right: 0 } : { width: `${barPct}%`, top: 0 }
119
+ }
120
+ )
121
+ },
122
+ i
123
+ );
124
+ })
125
+ }
126
+ );
127
+ const valueNode = showValue ? /* @__PURE__ */ jsxRuntime.jsx(
128
+ "span",
129
+ {
130
+ className: utils.cn(
131
+ "shrink-0 font-semibold tabular-nums text-foreground",
132
+ isCell ? null : "text-xs"
133
+ ),
134
+ children: valueText
135
+ }
136
+ ) : null;
137
+ const label = icon || showLabel ? /* @__PURE__ */ jsxRuntime.jsxs(
138
+ "span",
139
+ {
140
+ className: utils.cn(
141
+ "inline-flex min-w-0 items-center gap-1 text-xs text-muted-foreground"
142
+ ),
143
+ children: [
144
+ icon ? /* @__PURE__ */ jsxRuntime.jsx(ProgressBarsIcon, { icon }) : null,
145
+ showLabel ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: title }) : null
146
+ ]
147
+ }
148
+ ) : null;
149
+ const useHover = hoverCard && hoverRows.length > 0;
150
+ if (isCell) {
151
+ const cell = /* @__PURE__ */ jsxRuntime.jsxs(
152
+ "span",
153
+ {
154
+ className: utils.cn(
155
+ "inline-flex min-w-0 items-center gap-1.5 whitespace-nowrap align-middle text-xs",
156
+ className
157
+ ),
158
+ ...useHover ? {} : { title: titleText },
159
+ "aria-label": useHover ? titleText : hiddenAccessibleText,
160
+ children: [
161
+ label,
162
+ bars,
163
+ valueNode
164
+ ]
165
+ }
166
+ );
167
+ return useHover ? /* @__PURE__ */ jsxRuntime.jsx(GaugeHoverCard.GaugeHoverCard, { title, rows: hoverRows, footer: hoverFooter, trigger: cell }) : cell;
168
+ }
169
+ const block = /* @__PURE__ */ jsxRuntime.jsxs(
170
+ "div",
171
+ {
172
+ className: utils.cn("flex flex-col items-center gap-1", className),
173
+ ...useHover ? {} : { title: hiddenAccessibleText },
174
+ "aria-label": useHover ? titleText : hiddenAccessibleText,
175
+ children: [
176
+ bars,
177
+ valueNode,
178
+ label
179
+ ]
180
+ }
181
+ );
182
+ return useHover ? /* @__PURE__ */ jsxRuntime.jsx(
183
+ GaugeHoverCard.GaugeHoverCard,
184
+ {
185
+ title,
186
+ rows: hoverRows,
187
+ footer: hoverFooter,
188
+ trigger: block,
189
+ className: "w-full justify-center"
190
+ }
191
+ ) : block;
192
+ }
193
+ exports.ProgressBars = ProgressBars;
194
+ //# sourceMappingURL=ProgressBars.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProgressBars.cjs","sources":["../../src/data/ProgressBars.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, type StaticIconComponent } from \"./Icon\";\nimport { deriveProgressBars } from \"./ProgressBars.model\";\nimport { GaugeHoverCard, type GaugeHoverRow } from \"./GaugeHoverCard\";\n\nexport type ProgressBarsVariant = \"default\" | \"cell\";\nexport type ProgressBarsOrientation = \"horizontal\" | \"vertical\";\n\n/**\n * Describes what one bar represents, letting the same component render CPU cores,\n * memory gigabytes, or any other quantised capacity. Defaults model CPU cores.\n */\nexport interface ProgressBarsUnit {\n /** Raw value that fills one bar, in the domain of `usage`/`max`. Default 1000 (millicores → 1 core). */\n perBar?: number;\n /** Caption/tooltip suffix naming the unit, plural. Default \"cores\". */\n label?: string;\n /** Per-bar hover tooltip noun, singular. Default \"core\". */\n barLabel?: string;\n /** Format a bar-unit count for the caption. Default: integers as-is, else 1 decimal. */\n format?: (units: number) => string;\n}\n\n/** Summary statistics for the hover card, in the same domain as `usage`/`max`. */\nexport interface ProgressBarsStats {\n /** Smallest value over the window. */\n min: number;\n /** Largest value over the window. */\n max: number;\n /** Mean value over the window. */\n avg: number;\n}\n\nexport interface ProgressBarsProps {\n /** Usage that fills the bars, in the raw domain (e.g. CPU millicores). */\n usage: number | undefined;\n /**\n * The capacity, in the same raw domain as `usage`. Determines the number of\n * bars (one per `unit.perBar`). When omitted or 0, the bar count falls back to\n * the ceiling of the usage so an unbounded reading still renders.\n */\n max?: number;\n /** What one bar represents. Defaults to CPU cores (perBar 1000, label \"cores\"). */\n unit?: ProgressBarsUnit;\n title: string;\n /** Iconify name or static icon component shown beside the label. */\n icon?: string | StaticIconComponent;\n /**\n * Utilisation thresholds (percent of capacity) at which the fill turns amber\n * then red. Defaults to [75, 90].\n */\n thresholds?: [warning: number, danger: number];\n /** Visual density/layout. `cell` is a compact inline form for table/grid cells. */\n variant?: ProgressBarsVariant;\n /** Show the title text. Icons and values remain visible unless separately hidden. */\n showLabel?: boolean;\n /** Show the value/capacity caption. Icons and bars remain visible when false. */\n showValue?: boolean;\n /**\n * Include the capacity in the caption (\"2.3 / 4 cores\"). Defaults to false — the\n * caption shows only the current value (\"2.3 cores\") since the bars already\n * convey capacity. Set true to append the \"/ <capacity>\".\n */\n showCapacity?: boolean;\n /** Bar direction. Vertical bars fill bottom-up; horizontal bars fill left-to-right. */\n orientation?: ProgressBarsOrientation;\n /**\n * Summary stats for the hover card's Min/Max/Avg rows, in the SAME raw domain as\n * `usage`/`max` (NOT divided by perBar). Pass null to omit those rows.\n */\n stats?: ProgressBarsStats | null;\n /**\n * Wrap the bars in a hover card summarising the metric (label + current / min /\n * max / avg / capacity). Defaults to true.\n */\n hoverCard?: boolean;\n /** Footer note in the hover card, e.g. the look-back window (\"over last 1h\"). */\n hoverFooter?: ReactNode;\n className?: string;\n}\n\nfunction toneClass(pct: number, [warn, danger]: [number, number]): string {\n if (pct >= danger) return \"bg-red-500\";\n if (pct >= warn) return \"bg-amber-500\";\n return \"bg-emerald-500\";\n}\n\nfunction ProgressBarsIcon({ icon }: { icon: string | StaticIconComponent }) {\n if (typeof icon === \"string\") {\n return (\n <Icon\n name={icon}\n width={14}\n height={14}\n className=\"text-muted-foreground\"\n />\n );\n }\n return (\n <Icon\n icon={icon}\n width={14}\n height={14}\n className=\"text-muted-foreground\"\n />\n );\n}\n\nfunction defaultFormatUnits(units: number): string {\n return Number.isInteger(units) ? String(units) : units.toFixed(1);\n}\n\n/**\n * ProgressBars renders quantised utilisation as a row of bars — one bar per unit\n * of capacity (the ceiling of the limit) — filled left to right by the usage. The\n * bar that straddles the usage boundary is partially filled (\"blocked out\") to\n * show the fractional unit in use, and the trailing bars stay empty to show\n * headroom; the bar colour crosses warning and danger thresholds. A \"<used> /\n * <capacity>\" caption sits below with the icon+title. It is purely presentational\n * — pass plain `usage`/`max` numbers (TimeseriesCoreBars wraps it with live data).\n */\nexport function ProgressBars({\n usage,\n max,\n unit,\n title,\n icon,\n thresholds = [75, 90],\n variant = \"default\",\n showLabel = true,\n showValue = true,\n showCapacity = false,\n orientation,\n stats,\n hoverCard = true,\n hoverFooter,\n className,\n}: ProgressBarsProps) {\n const perBar = unit?.perBar ?? 1000;\n const unitLabel = unit?.label ?? \"cores\";\n const barLabel = unit?.barLabel ?? \"core\";\n const formatUnits = unit?.format ?? defaultFormatUnits;\n\n const model = deriveProgressBars(usage, max, perBar);\n const tone = toneClass(model.pct, thresholds);\n const usageText = formatUnits(model.usageUnits);\n const capacityText =\n model.limitUnits !== undefined ? formatUnits(model.limitUnits) : \"?\";\n const caption = !model.hasUsage\n ? \"—\"\n : showCapacity\n ? `${usageText} / ${capacityText} ${unitLabel}`\n : `${usageText} ${unitLabel}`;\n const compactCaption = !model.hasUsage\n ? \"—\"\n : showCapacity\n ? `${usageText}/${capacityText} ${unitLabel}`\n : `${usageText} ${unitLabel}`;\n const titleText = `${title}: ${compactCaption}`;\n const isCell = variant === \"cell\";\n\n // Hover card: surface current/min/max/avg/capacity in bar-units (stats are in\n // the raw domain, so divide by perBar) so they read in the same unit as the\n // caption. A bounded reading colours the current row by its threshold.\n const pctTone =\n model.limitUnits === undefined\n ? undefined\n : model.pct >= thresholds[1]\n ? \"text-red-500\"\n : model.pct >= thresholds[0]\n ? \"text-amber-500\"\n : \"text-emerald-500\";\n const fmt = (n: number) => `${formatUnits(n)} ${unitLabel}`;\n const hoverRows: GaugeHoverRow[] = model.hasUsage\n ? [\n { label: \"Current\", value: fmt(model.usageUnits), ...(pctTone ? { tone: pctTone } : {}) },\n ...(stats\n ? [\n { label: \"Min\", value: fmt(stats.min / perBar) },\n { label: \"Max\", value: fmt(stats.max / perBar) },\n { label: \"Avg\", value: fmt(stats.avg / perBar) },\n ]\n : []),\n ...(model.limitUnits !== undefined\n ? [{ label: \"Capacity\", value: fmt(model.limitUnits) }]\n : []),\n ]\n : [];\n\n const resolvedOrientation = orientation ?? \"vertical\";\n const isDense = model.barCount > 4;\n const valueText = isCell ? compactCaption : caption;\n const hiddenAccessibleText = !showLabel || !showValue ? titleText : undefined;\n const bars = (\n <span\n className={cn(\n \"flex shrink-0\",\n resolvedOrientation === \"vertical\"\n ? cn(\"items-end\", isCell ? \"h-4 gap-px\" : \"h-10 gap-0.5\")\n : cn(\n \"flex-col justify-center\",\n isCell ? \"h-4 w-10 gap-px\" : \"h-10 w-16 gap-0.5\",\n ),\n )}\n aria-hidden={isCell ? \"true\" : undefined}\n data-orientation={resolvedOrientation}\n data-bar-count={model.barCount}\n data-bar-density={isDense ? \"compact\" : \"default\"}\n >\n {model.bars.map((bar, i) => {\n const barPct = Math.round(bar.fill * 100);\n return (\n <span\n key={i}\n className={cn(\n \"relative overflow-hidden bg-muted\",\n resolvedOrientation === \"vertical\"\n ? cn(\n \"h-full\",\n isCell\n ? isDense\n ? \"w-[3px] rounded-[2px]\"\n : \"w-1.5 rounded-[2px]\"\n : isDense\n ? \"w-1 rounded-sm\"\n : \"w-2 rounded-sm\",\n )\n : cn(\"min-h-px w-full flex-1 rounded-[2px]\"),\n )}\n title={`${barLabel} ${i + 1}: ${barPct}%`}\n aria-label={!isCell ? `${barLabel} ${i + 1}: ${barPct}%` : undefined}\n data-fill={bar.fill}\n >\n <span\n className={cn(\n \"absolute bottom-0 left-0 transition-all duration-300\",\n tone,\n )}\n style={\n resolvedOrientation === \"vertical\"\n ? { height: `${barPct}%`, right: 0 }\n : { width: `${barPct}%`, top: 0 }\n }\n />\n </span>\n );\n })}\n </span>\n );\n const valueNode = showValue ? (\n <span\n className={cn(\n \"shrink-0 font-semibold tabular-nums text-foreground\",\n isCell ? null : \"text-xs\",\n )}\n >\n {valueText}\n </span>\n ) : null;\n const label =\n icon || showLabel ? (\n <span\n className={cn(\n \"inline-flex min-w-0 items-center gap-1 text-xs text-muted-foreground\",\n )}\n >\n {icon ? <ProgressBarsIcon icon={icon} /> : null}\n {showLabel ? <span className=\"min-w-0 truncate\">{title}</span> : null}\n </span>\n ) : null;\n\n const useHover = hoverCard && hoverRows.length > 0;\n\n if (isCell) {\n const cell = (\n <span\n className={cn(\n \"inline-flex min-w-0 items-center gap-1.5 whitespace-nowrap align-middle text-xs\",\n className,\n )}\n {...(useHover ? {} : { title: titleText })}\n aria-label={useHover ? titleText : hiddenAccessibleText}\n >\n {label}\n {bars}\n {valueNode}\n </span>\n );\n return useHover ? (\n <GaugeHoverCard title={title} rows={hoverRows} footer={hoverFooter} trigger={cell} />\n ) : (\n cell\n );\n }\n\n const block = (\n <div\n className={cn(\"flex flex-col items-center gap-1\", className)}\n {...(useHover ? {} : { title: hiddenAccessibleText })}\n aria-label={useHover ? titleText : hiddenAccessibleText}\n >\n {bars}\n {valueNode}\n {label}\n </div>\n );\n return useHover ? (\n <GaugeHoverCard\n title={title}\n rows={hoverRows}\n footer={hoverFooter}\n trigger={block}\n className=\"w-full justify-center\"\n />\n ) : (\n block\n );\n}\n"],"names":["jsx","Icon","deriveProgressBars","cn","jsxs","GaugeHoverCard"],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ import { ReactNode } from 'react';
2
+ import { StaticIconComponent } from './Icon';
3
+ export type ProgressBarsVariant = "default" | "cell";
4
+ export type ProgressBarsOrientation = "horizontal" | "vertical";
5
+ /**
6
+ * Describes what one bar represents, letting the same component render CPU cores,
7
+ * memory gigabytes, or any other quantised capacity. Defaults model CPU cores.
8
+ */
9
+ export interface ProgressBarsUnit {
10
+ /** Raw value that fills one bar, in the domain of `usage`/`max`. Default 1000 (millicores → 1 core). */
11
+ perBar?: number;
12
+ /** Caption/tooltip suffix naming the unit, plural. Default "cores". */
13
+ label?: string;
14
+ /** Per-bar hover tooltip noun, singular. Default "core". */
15
+ barLabel?: string;
16
+ /** Format a bar-unit count for the caption. Default: integers as-is, else 1 decimal. */
17
+ format?: (units: number) => string;
18
+ }
19
+ /** Summary statistics for the hover card, in the same domain as `usage`/`max`. */
20
+ export interface ProgressBarsStats {
21
+ /** Smallest value over the window. */
22
+ min: number;
23
+ /** Largest value over the window. */
24
+ max: number;
25
+ /** Mean value over the window. */
26
+ avg: number;
27
+ }
28
+ export interface ProgressBarsProps {
29
+ /** Usage that fills the bars, in the raw domain (e.g. CPU millicores). */
30
+ usage: number | undefined;
31
+ /**
32
+ * The capacity, in the same raw domain as `usage`. Determines the number of
33
+ * bars (one per `unit.perBar`). When omitted or 0, the bar count falls back to
34
+ * the ceiling of the usage so an unbounded reading still renders.
35
+ */
36
+ max?: number;
37
+ /** What one bar represents. Defaults to CPU cores (perBar 1000, label "cores"). */
38
+ unit?: ProgressBarsUnit;
39
+ title: string;
40
+ /** Iconify name or static icon component shown beside the label. */
41
+ icon?: string | StaticIconComponent;
42
+ /**
43
+ * Utilisation thresholds (percent of capacity) at which the fill turns amber
44
+ * then red. Defaults to [75, 90].
45
+ */
46
+ thresholds?: [warning: number, danger: number];
47
+ /** Visual density/layout. `cell` is a compact inline form for table/grid cells. */
48
+ variant?: ProgressBarsVariant;
49
+ /** Show the title text. Icons and values remain visible unless separately hidden. */
50
+ showLabel?: boolean;
51
+ /** Show the value/capacity caption. Icons and bars remain visible when false. */
52
+ showValue?: boolean;
53
+ /**
54
+ * Include the capacity in the caption ("2.3 / 4 cores"). Defaults to false — the
55
+ * caption shows only the current value ("2.3 cores") since the bars already
56
+ * convey capacity. Set true to append the "/ <capacity>".
57
+ */
58
+ showCapacity?: boolean;
59
+ /** Bar direction. Vertical bars fill bottom-up; horizontal bars fill left-to-right. */
60
+ orientation?: ProgressBarsOrientation;
61
+ /**
62
+ * Summary stats for the hover card's Min/Max/Avg rows, in the SAME raw domain as
63
+ * `usage`/`max` (NOT divided by perBar). Pass null to omit those rows.
64
+ */
65
+ stats?: ProgressBarsStats | null;
66
+ /**
67
+ * Wrap the bars in a hover card summarising the metric (label + current / min /
68
+ * max / avg / capacity). Defaults to true.
69
+ */
70
+ hoverCard?: boolean;
71
+ /** Footer note in the hover card, e.g. the look-back window ("over last 1h"). */
72
+ hoverFooter?: ReactNode;
73
+ className?: string;
74
+ }
75
+ /**
76
+ * ProgressBars renders quantised utilisation as a row of bars — one bar per unit
77
+ * of capacity (the ceiling of the limit) — filled left to right by the usage. The
78
+ * bar that straddles the usage boundary is partially filled ("blocked out") to
79
+ * show the fractional unit in use, and the trailing bars stay empty to show
80
+ * headroom; the bar colour crosses warning and danger thresholds. A "<used> /
81
+ * <capacity>" caption sits below with the icon+title. It is purely presentational
82
+ * — pass plain `usage`/`max` numbers (TimeseriesCoreBars wraps it with live data).
83
+ */
84
+ export declare function ProgressBars({ usage, max, unit, title, icon, thresholds, variant, showLabel, showValue, showCapacity, orientation, stats, hoverCard, hoverFooter, className, }: ProgressBarsProps): import("react/jsx-runtime").JSX.Element;
85
+ //# sourceMappingURL=ProgressBars.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProgressBars.d.ts","sourceRoot":"","sources":["../../src/data/ProgressBars.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAQ,KAAK,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAIxD,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,MAAM,CAAC;AACrD,MAAM,MAAM,uBAAuB,GAAG,YAAY,GAAG,UAAU,CAAC;AAEhE;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,wGAAwG;IACxG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wFAAwF;IACxF,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CACpC;AAED,kFAAkF;AAClF,MAAM,WAAW,iBAAiB;IAChC,sCAAsC;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,qCAAqC;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,kCAAkC;IAClC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,iBAAiB;IAChC,0EAA0E;IAC1E,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,mFAAmF;IACnF,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,GAAG,mBAAmB,CAAC;IACpC;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,mFAAmF;IACnF,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,qFAAqF;IACrF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uFAAuF;IACvF,WAAW,CAAC,EAAE,uBAAuB,CAAC;IACtC;;;OAGG;IACH,KAAK,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACjC;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iFAAiF;IACjF,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAiCD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,GAAG,EACH,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,UAAqB,EACrB,OAAmB,EACnB,SAAgB,EAChB,SAAgB,EAChB,YAAoB,EACpB,WAAW,EACX,KAAK,EACL,SAAgB,EAChB,WAAW,EACX,SAAS,GACV,EAAE,iBAAiB,2CAoLnB"}
@@ -0,0 +1,194 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../lib/utils.js";
3
+ import { Icon } from "./Icon.js";
4
+ import { deriveProgressBars } from "./ProgressBars.model.js";
5
+ import { GaugeHoverCard } from "./GaugeHoverCard.js";
6
+ function toneClass(pct, [warn, danger]) {
7
+ if (pct >= danger) return "bg-red-500";
8
+ if (pct >= warn) return "bg-amber-500";
9
+ return "bg-emerald-500";
10
+ }
11
+ function ProgressBarsIcon({ icon }) {
12
+ if (typeof icon === "string") {
13
+ return /* @__PURE__ */ jsx(
14
+ Icon,
15
+ {
16
+ name: icon,
17
+ width: 14,
18
+ height: 14,
19
+ className: "text-muted-foreground"
20
+ }
21
+ );
22
+ }
23
+ return /* @__PURE__ */ jsx(
24
+ Icon,
25
+ {
26
+ icon,
27
+ width: 14,
28
+ height: 14,
29
+ className: "text-muted-foreground"
30
+ }
31
+ );
32
+ }
33
+ function defaultFormatUnits(units) {
34
+ return Number.isInteger(units) ? String(units) : units.toFixed(1);
35
+ }
36
+ function ProgressBars({
37
+ usage,
38
+ max,
39
+ unit,
40
+ title,
41
+ icon,
42
+ thresholds = [75, 90],
43
+ variant = "default",
44
+ showLabel = true,
45
+ showValue = true,
46
+ showCapacity = false,
47
+ orientation,
48
+ stats,
49
+ hoverCard = true,
50
+ hoverFooter,
51
+ className
52
+ }) {
53
+ const perBar = (unit == null ? void 0 : unit.perBar) ?? 1e3;
54
+ const unitLabel = (unit == null ? void 0 : unit.label) ?? "cores";
55
+ const barLabel = (unit == null ? void 0 : unit.barLabel) ?? "core";
56
+ const formatUnits = (unit == null ? void 0 : unit.format) ?? defaultFormatUnits;
57
+ const model = deriveProgressBars(usage, max, perBar);
58
+ const tone = toneClass(model.pct, thresholds);
59
+ const usageText = formatUnits(model.usageUnits);
60
+ const capacityText = model.limitUnits !== void 0 ? formatUnits(model.limitUnits) : "?";
61
+ const caption = !model.hasUsage ? "—" : showCapacity ? `${usageText} / ${capacityText} ${unitLabel}` : `${usageText} ${unitLabel}`;
62
+ const compactCaption = !model.hasUsage ? "—" : showCapacity ? `${usageText}/${capacityText} ${unitLabel}` : `${usageText} ${unitLabel}`;
63
+ const titleText = `${title}: ${compactCaption}`;
64
+ const isCell = variant === "cell";
65
+ const pctTone = model.limitUnits === void 0 ? void 0 : model.pct >= thresholds[1] ? "text-red-500" : model.pct >= thresholds[0] ? "text-amber-500" : "text-emerald-500";
66
+ const fmt = (n) => `${formatUnits(n)} ${unitLabel}`;
67
+ const hoverRows = model.hasUsage ? [
68
+ { label: "Current", value: fmt(model.usageUnits), ...pctTone ? { tone: pctTone } : {} },
69
+ ...stats ? [
70
+ { label: "Min", value: fmt(stats.min / perBar) },
71
+ { label: "Max", value: fmt(stats.max / perBar) },
72
+ { label: "Avg", value: fmt(stats.avg / perBar) }
73
+ ] : [],
74
+ ...model.limitUnits !== void 0 ? [{ label: "Capacity", value: fmt(model.limitUnits) }] : []
75
+ ] : [];
76
+ const resolvedOrientation = orientation ?? "vertical";
77
+ const isDense = model.barCount > 4;
78
+ const valueText = isCell ? compactCaption : caption;
79
+ const hiddenAccessibleText = !showLabel || !showValue ? titleText : void 0;
80
+ const bars = /* @__PURE__ */ jsx(
81
+ "span",
82
+ {
83
+ className: cn(
84
+ "flex shrink-0",
85
+ resolvedOrientation === "vertical" ? cn("items-end", isCell ? "h-4 gap-px" : "h-10 gap-0.5") : cn(
86
+ "flex-col justify-center",
87
+ isCell ? "h-4 w-10 gap-px" : "h-10 w-16 gap-0.5"
88
+ )
89
+ ),
90
+ "aria-hidden": isCell ? "true" : void 0,
91
+ "data-orientation": resolvedOrientation,
92
+ "data-bar-count": model.barCount,
93
+ "data-bar-density": isDense ? "compact" : "default",
94
+ children: model.bars.map((bar, i) => {
95
+ const barPct = Math.round(bar.fill * 100);
96
+ return /* @__PURE__ */ jsx(
97
+ "span",
98
+ {
99
+ className: cn(
100
+ "relative overflow-hidden bg-muted",
101
+ resolvedOrientation === "vertical" ? cn(
102
+ "h-full",
103
+ isCell ? isDense ? "w-[3px] rounded-[2px]" : "w-1.5 rounded-[2px]" : isDense ? "w-1 rounded-sm" : "w-2 rounded-sm"
104
+ ) : cn("min-h-px w-full flex-1 rounded-[2px]")
105
+ ),
106
+ title: `${barLabel} ${i + 1}: ${barPct}%`,
107
+ "aria-label": !isCell ? `${barLabel} ${i + 1}: ${barPct}%` : void 0,
108
+ "data-fill": bar.fill,
109
+ children: /* @__PURE__ */ jsx(
110
+ "span",
111
+ {
112
+ className: cn(
113
+ "absolute bottom-0 left-0 transition-all duration-300",
114
+ tone
115
+ ),
116
+ style: resolvedOrientation === "vertical" ? { height: `${barPct}%`, right: 0 } : { width: `${barPct}%`, top: 0 }
117
+ }
118
+ )
119
+ },
120
+ i
121
+ );
122
+ })
123
+ }
124
+ );
125
+ const valueNode = showValue ? /* @__PURE__ */ jsx(
126
+ "span",
127
+ {
128
+ className: cn(
129
+ "shrink-0 font-semibold tabular-nums text-foreground",
130
+ isCell ? null : "text-xs"
131
+ ),
132
+ children: valueText
133
+ }
134
+ ) : null;
135
+ const label = icon || showLabel ? /* @__PURE__ */ jsxs(
136
+ "span",
137
+ {
138
+ className: cn(
139
+ "inline-flex min-w-0 items-center gap-1 text-xs text-muted-foreground"
140
+ ),
141
+ children: [
142
+ icon ? /* @__PURE__ */ jsx(ProgressBarsIcon, { icon }) : null,
143
+ showLabel ? /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: title }) : null
144
+ ]
145
+ }
146
+ ) : null;
147
+ const useHover = hoverCard && hoverRows.length > 0;
148
+ if (isCell) {
149
+ const cell = /* @__PURE__ */ jsxs(
150
+ "span",
151
+ {
152
+ className: cn(
153
+ "inline-flex min-w-0 items-center gap-1.5 whitespace-nowrap align-middle text-xs",
154
+ className
155
+ ),
156
+ ...useHover ? {} : { title: titleText },
157
+ "aria-label": useHover ? titleText : hiddenAccessibleText,
158
+ children: [
159
+ label,
160
+ bars,
161
+ valueNode
162
+ ]
163
+ }
164
+ );
165
+ return useHover ? /* @__PURE__ */ jsx(GaugeHoverCard, { title, rows: hoverRows, footer: hoverFooter, trigger: cell }) : cell;
166
+ }
167
+ const block = /* @__PURE__ */ jsxs(
168
+ "div",
169
+ {
170
+ className: cn("flex flex-col items-center gap-1", className),
171
+ ...useHover ? {} : { title: hiddenAccessibleText },
172
+ "aria-label": useHover ? titleText : hiddenAccessibleText,
173
+ children: [
174
+ bars,
175
+ valueNode,
176
+ label
177
+ ]
178
+ }
179
+ );
180
+ return useHover ? /* @__PURE__ */ jsx(
181
+ GaugeHoverCard,
182
+ {
183
+ title,
184
+ rows: hoverRows,
185
+ footer: hoverFooter,
186
+ trigger: block,
187
+ className: "w-full justify-center"
188
+ }
189
+ ) : block;
190
+ }
191
+ export {
192
+ ProgressBars
193
+ };
194
+ //# sourceMappingURL=ProgressBars.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProgressBars.js","sources":["../../src/data/ProgressBars.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon, type StaticIconComponent } from \"./Icon\";\nimport { deriveProgressBars } from \"./ProgressBars.model\";\nimport { GaugeHoverCard, type GaugeHoverRow } from \"./GaugeHoverCard\";\n\nexport type ProgressBarsVariant = \"default\" | \"cell\";\nexport type ProgressBarsOrientation = \"horizontal\" | \"vertical\";\n\n/**\n * Describes what one bar represents, letting the same component render CPU cores,\n * memory gigabytes, or any other quantised capacity. Defaults model CPU cores.\n */\nexport interface ProgressBarsUnit {\n /** Raw value that fills one bar, in the domain of `usage`/`max`. Default 1000 (millicores → 1 core). */\n perBar?: number;\n /** Caption/tooltip suffix naming the unit, plural. Default \"cores\". */\n label?: string;\n /** Per-bar hover tooltip noun, singular. Default \"core\". */\n barLabel?: string;\n /** Format a bar-unit count for the caption. Default: integers as-is, else 1 decimal. */\n format?: (units: number) => string;\n}\n\n/** Summary statistics for the hover card, in the same domain as `usage`/`max`. */\nexport interface ProgressBarsStats {\n /** Smallest value over the window. */\n min: number;\n /** Largest value over the window. */\n max: number;\n /** Mean value over the window. */\n avg: number;\n}\n\nexport interface ProgressBarsProps {\n /** Usage that fills the bars, in the raw domain (e.g. CPU millicores). */\n usage: number | undefined;\n /**\n * The capacity, in the same raw domain as `usage`. Determines the number of\n * bars (one per `unit.perBar`). When omitted or 0, the bar count falls back to\n * the ceiling of the usage so an unbounded reading still renders.\n */\n max?: number;\n /** What one bar represents. Defaults to CPU cores (perBar 1000, label \"cores\"). */\n unit?: ProgressBarsUnit;\n title: string;\n /** Iconify name or static icon component shown beside the label. */\n icon?: string | StaticIconComponent;\n /**\n * Utilisation thresholds (percent of capacity) at which the fill turns amber\n * then red. Defaults to [75, 90].\n */\n thresholds?: [warning: number, danger: number];\n /** Visual density/layout. `cell` is a compact inline form for table/grid cells. */\n variant?: ProgressBarsVariant;\n /** Show the title text. Icons and values remain visible unless separately hidden. */\n showLabel?: boolean;\n /** Show the value/capacity caption. Icons and bars remain visible when false. */\n showValue?: boolean;\n /**\n * Include the capacity in the caption (\"2.3 / 4 cores\"). Defaults to false — the\n * caption shows only the current value (\"2.3 cores\") since the bars already\n * convey capacity. Set true to append the \"/ <capacity>\".\n */\n showCapacity?: boolean;\n /** Bar direction. Vertical bars fill bottom-up; horizontal bars fill left-to-right. */\n orientation?: ProgressBarsOrientation;\n /**\n * Summary stats for the hover card's Min/Max/Avg rows, in the SAME raw domain as\n * `usage`/`max` (NOT divided by perBar). Pass null to omit those rows.\n */\n stats?: ProgressBarsStats | null;\n /**\n * Wrap the bars in a hover card summarising the metric (label + current / min /\n * max / avg / capacity). Defaults to true.\n */\n hoverCard?: boolean;\n /** Footer note in the hover card, e.g. the look-back window (\"over last 1h\"). */\n hoverFooter?: ReactNode;\n className?: string;\n}\n\nfunction toneClass(pct: number, [warn, danger]: [number, number]): string {\n if (pct >= danger) return \"bg-red-500\";\n if (pct >= warn) return \"bg-amber-500\";\n return \"bg-emerald-500\";\n}\n\nfunction ProgressBarsIcon({ icon }: { icon: string | StaticIconComponent }) {\n if (typeof icon === \"string\") {\n return (\n <Icon\n name={icon}\n width={14}\n height={14}\n className=\"text-muted-foreground\"\n />\n );\n }\n return (\n <Icon\n icon={icon}\n width={14}\n height={14}\n className=\"text-muted-foreground\"\n />\n );\n}\n\nfunction defaultFormatUnits(units: number): string {\n return Number.isInteger(units) ? String(units) : units.toFixed(1);\n}\n\n/**\n * ProgressBars renders quantised utilisation as a row of bars — one bar per unit\n * of capacity (the ceiling of the limit) — filled left to right by the usage. The\n * bar that straddles the usage boundary is partially filled (\"blocked out\") to\n * show the fractional unit in use, and the trailing bars stay empty to show\n * headroom; the bar colour crosses warning and danger thresholds. A \"<used> /\n * <capacity>\" caption sits below with the icon+title. It is purely presentational\n * — pass plain `usage`/`max` numbers (TimeseriesCoreBars wraps it with live data).\n */\nexport function ProgressBars({\n usage,\n max,\n unit,\n title,\n icon,\n thresholds = [75, 90],\n variant = \"default\",\n showLabel = true,\n showValue = true,\n showCapacity = false,\n orientation,\n stats,\n hoverCard = true,\n hoverFooter,\n className,\n}: ProgressBarsProps) {\n const perBar = unit?.perBar ?? 1000;\n const unitLabel = unit?.label ?? \"cores\";\n const barLabel = unit?.barLabel ?? \"core\";\n const formatUnits = unit?.format ?? defaultFormatUnits;\n\n const model = deriveProgressBars(usage, max, perBar);\n const tone = toneClass(model.pct, thresholds);\n const usageText = formatUnits(model.usageUnits);\n const capacityText =\n model.limitUnits !== undefined ? formatUnits(model.limitUnits) : \"?\";\n const caption = !model.hasUsage\n ? \"—\"\n : showCapacity\n ? `${usageText} / ${capacityText} ${unitLabel}`\n : `${usageText} ${unitLabel}`;\n const compactCaption = !model.hasUsage\n ? \"—\"\n : showCapacity\n ? `${usageText}/${capacityText} ${unitLabel}`\n : `${usageText} ${unitLabel}`;\n const titleText = `${title}: ${compactCaption}`;\n const isCell = variant === \"cell\";\n\n // Hover card: surface current/min/max/avg/capacity in bar-units (stats are in\n // the raw domain, so divide by perBar) so they read in the same unit as the\n // caption. A bounded reading colours the current row by its threshold.\n const pctTone =\n model.limitUnits === undefined\n ? undefined\n : model.pct >= thresholds[1]\n ? \"text-red-500\"\n : model.pct >= thresholds[0]\n ? \"text-amber-500\"\n : \"text-emerald-500\";\n const fmt = (n: number) => `${formatUnits(n)} ${unitLabel}`;\n const hoverRows: GaugeHoverRow[] = model.hasUsage\n ? [\n { label: \"Current\", value: fmt(model.usageUnits), ...(pctTone ? { tone: pctTone } : {}) },\n ...(stats\n ? [\n { label: \"Min\", value: fmt(stats.min / perBar) },\n { label: \"Max\", value: fmt(stats.max / perBar) },\n { label: \"Avg\", value: fmt(stats.avg / perBar) },\n ]\n : []),\n ...(model.limitUnits !== undefined\n ? [{ label: \"Capacity\", value: fmt(model.limitUnits) }]\n : []),\n ]\n : [];\n\n const resolvedOrientation = orientation ?? \"vertical\";\n const isDense = model.barCount > 4;\n const valueText = isCell ? compactCaption : caption;\n const hiddenAccessibleText = !showLabel || !showValue ? titleText : undefined;\n const bars = (\n <span\n className={cn(\n \"flex shrink-0\",\n resolvedOrientation === \"vertical\"\n ? cn(\"items-end\", isCell ? \"h-4 gap-px\" : \"h-10 gap-0.5\")\n : cn(\n \"flex-col justify-center\",\n isCell ? \"h-4 w-10 gap-px\" : \"h-10 w-16 gap-0.5\",\n ),\n )}\n aria-hidden={isCell ? \"true\" : undefined}\n data-orientation={resolvedOrientation}\n data-bar-count={model.barCount}\n data-bar-density={isDense ? \"compact\" : \"default\"}\n >\n {model.bars.map((bar, i) => {\n const barPct = Math.round(bar.fill * 100);\n return (\n <span\n key={i}\n className={cn(\n \"relative overflow-hidden bg-muted\",\n resolvedOrientation === \"vertical\"\n ? cn(\n \"h-full\",\n isCell\n ? isDense\n ? \"w-[3px] rounded-[2px]\"\n : \"w-1.5 rounded-[2px]\"\n : isDense\n ? \"w-1 rounded-sm\"\n : \"w-2 rounded-sm\",\n )\n : cn(\"min-h-px w-full flex-1 rounded-[2px]\"),\n )}\n title={`${barLabel} ${i + 1}: ${barPct}%`}\n aria-label={!isCell ? `${barLabel} ${i + 1}: ${barPct}%` : undefined}\n data-fill={bar.fill}\n >\n <span\n className={cn(\n \"absolute bottom-0 left-0 transition-all duration-300\",\n tone,\n )}\n style={\n resolvedOrientation === \"vertical\"\n ? { height: `${barPct}%`, right: 0 }\n : { width: `${barPct}%`, top: 0 }\n }\n />\n </span>\n );\n })}\n </span>\n );\n const valueNode = showValue ? (\n <span\n className={cn(\n \"shrink-0 font-semibold tabular-nums text-foreground\",\n isCell ? null : \"text-xs\",\n )}\n >\n {valueText}\n </span>\n ) : null;\n const label =\n icon || showLabel ? (\n <span\n className={cn(\n \"inline-flex min-w-0 items-center gap-1 text-xs text-muted-foreground\",\n )}\n >\n {icon ? <ProgressBarsIcon icon={icon} /> : null}\n {showLabel ? <span className=\"min-w-0 truncate\">{title}</span> : null}\n </span>\n ) : null;\n\n const useHover = hoverCard && hoverRows.length > 0;\n\n if (isCell) {\n const cell = (\n <span\n className={cn(\n \"inline-flex min-w-0 items-center gap-1.5 whitespace-nowrap align-middle text-xs\",\n className,\n )}\n {...(useHover ? {} : { title: titleText })}\n aria-label={useHover ? titleText : hiddenAccessibleText}\n >\n {label}\n {bars}\n {valueNode}\n </span>\n );\n return useHover ? (\n <GaugeHoverCard title={title} rows={hoverRows} footer={hoverFooter} trigger={cell} />\n ) : (\n cell\n );\n }\n\n const block = (\n <div\n className={cn(\"flex flex-col items-center gap-1\", className)}\n {...(useHover ? {} : { title: hiddenAccessibleText })}\n aria-label={useHover ? titleText : hiddenAccessibleText}\n >\n {bars}\n {valueNode}\n {label}\n </div>\n );\n return useHover ? (\n <GaugeHoverCard\n title={title}\n rows={hoverRows}\n footer={hoverFooter}\n trigger={block}\n className=\"w-full justify-center\"\n />\n ) : (\n block\n );\n}\n"],"names":[],"mappings":"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"}