@flanksource/clicky-ui 0.2.21 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Combobox.cjs +5 -2
- package/dist/components/Combobox.cjs.map +1 -1
- package/dist/components/Combobox.d.ts.map +1 -1
- package/dist/components/Combobox.js +5 -2
- package/dist/components/Combobox.js.map +1 -1
- package/dist/components/FilterBar.cjs +280 -253
- package/dist/components/FilterBar.cjs.map +1 -1
- package/dist/components/FilterBar.d.ts.map +1 -1
- package/dist/components/FilterBar.js +280 -253
- package/dist/components/FilterBar.js.map +1 -1
- package/dist/components/JsonSchemaForm.cjs +3 -1
- package/dist/components/JsonSchemaForm.cjs.map +1 -1
- package/dist/components/JsonSchemaForm.d.ts.map +1 -1
- package/dist/components/JsonSchemaForm.js +4 -2
- package/dist/components/JsonSchemaForm.js.map +1 -1
- package/dist/components/MultiSelect.cjs +29 -32
- package/dist/components/MultiSelect.cjs.map +1 -1
- package/dist/components/MultiSelect.d.ts.map +1 -1
- package/dist/components/MultiSelect.js +30 -33
- package/dist/components/MultiSelect.js.map +1 -1
- package/dist/components/TimeRange.cjs +29 -37
- package/dist/components/TimeRange.cjs.map +1 -1
- package/dist/components/TimeRange.d.ts.map +1 -1
- package/dist/components/TimeRange.js +30 -38
- package/dist/components/TimeRange.js.map +1 -1
- package/dist/components/TreePickerField.cjs +6 -3
- package/dist/components/TreePickerField.cjs.map +1 -1
- package/dist/components/TreePickerField.d.ts.map +1 -1
- package/dist/components/TreePickerField.js +6 -3
- package/dist/components/TreePickerField.js.map +1 -1
- package/dist/components/icon-menu-picker.cjs +9 -3
- package/dist/components/icon-menu-picker.cjs.map +1 -1
- package/dist/components/icon-menu-picker.d.ts.map +1 -1
- package/dist/components/icon-menu-picker.js +9 -3
- package/dist/components/icon-menu-picker.js.map +1 -1
- package/dist/components/json-schema-form-fields.cjs +80 -2
- package/dist/components/json-schema-form-fields.cjs.map +1 -1
- package/dist/components/json-schema-form-fields.d.ts +15 -0
- package/dist/components/json-schema-form-fields.d.ts.map +1 -1
- package/dist/components/json-schema-form-fields.js +81 -3
- package/dist/components/json-schema-form-fields.js.map +1 -1
- package/dist/components/json-schema-form-refs.cjs +60 -0
- package/dist/components/json-schema-form-refs.cjs.map +1 -0
- package/dist/components/json-schema-form-refs.d.ts +3 -0
- package/dist/components/json-schema-form-refs.d.ts.map +1 -0
- package/dist/components/json-schema-form-refs.js +60 -0
- package/dist/components/json-schema-form-refs.js.map +1 -0
- package/dist/components/json-schema-form-render.cjs +14 -2
- package/dist/components/json-schema-form-render.cjs.map +1 -1
- package/dist/components/json-schema-form-render.d.ts.map +1 -1
- package/dist/components/json-schema-form-render.js +15 -3
- package/dist/components/json-schema-form-render.js.map +1 -1
- package/dist/components/json-schema-form-resolve.cjs +5 -0
- package/dist/components/json-schema-form-resolve.cjs.map +1 -1
- package/dist/components/json-schema-form-resolve.d.ts.map +1 -1
- package/dist/components/json-schema-form-resolve.js +5 -0
- package/dist/components/json-schema-form-resolve.js.map +1 -1
- package/dist/components/json-schema-form-template-menu.cjs +83 -0
- package/dist/components/json-schema-form-template-menu.cjs.map +1 -0
- package/dist/components/json-schema-form-template-menu.d.ts +15 -0
- package/dist/components/json-schema-form-template-menu.d.ts.map +1 -0
- package/dist/components/json-schema-form-template-menu.js +83 -0
- package/dist/components/json-schema-form-template-menu.js.map +1 -0
- package/dist/components/json-schema-form-template.cjs +18 -0
- package/dist/components/json-schema-form-template.cjs.map +1 -0
- package/dist/components/json-schema-form-template.d.ts +13 -0
- package/dist/components/json-schema-form-template.d.ts.map +1 -0
- package/dist/components/json-schema-form-template.js +18 -0
- package/dist/components/json-schema-form-template.js.map +1 -0
- package/dist/components/json-schema-form-types.d.ts +5 -1
- package/dist/components/json-schema-form-types.d.ts.map +1 -1
- package/dist/components.cjs +4 -0
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.ts +3 -0
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +4 -0
- package/dist/components.js.map +1 -1
- package/dist/data/Clicky.cjs +6 -9
- package/dist/data/Clicky.cjs.map +1 -1
- package/dist/data/Clicky.d.ts.map +1 -1
- package/dist/data/Clicky.js +6 -9
- package/dist/data/Clicky.js.map +1 -1
- package/dist/data/DataTable.cjs +23 -17
- package/dist/data/DataTable.cjs.map +1 -1
- package/dist/data/DataTable.d.ts +7 -1
- package/dist/data/DataTable.d.ts.map +1 -1
- package/dist/data/DataTable.js +24 -18
- package/dist/data/DataTable.js.map +1 -1
- package/dist/data/Gauge.cjs +37 -4
- package/dist/data/Gauge.cjs.map +1 -1
- package/dist/data/Gauge.d.ts +6 -1
- package/dist/data/Gauge.d.ts.map +1 -1
- package/dist/data/Gauge.js +37 -4
- package/dist/data/Gauge.js.map +1 -1
- package/dist/data/TimeseriesCoreBars.cjs +127 -29
- package/dist/data/TimeseriesCoreBars.cjs.map +1 -1
- package/dist/data/TimeseriesCoreBars.d.ts +11 -1
- package/dist/data/TimeseriesCoreBars.d.ts.map +1 -1
- package/dist/data/TimeseriesCoreBars.js +128 -30
- package/dist/data/TimeseriesCoreBars.js.map +1 -1
- package/dist/data/TimeseriesGauge.cjs +105 -47
- package/dist/data/TimeseriesGauge.cjs.map +1 -1
- package/dist/data/TimeseriesGauge.d.ts +6 -1
- package/dist/data/TimeseriesGauge.d.ts.map +1 -1
- package/dist/data/TimeseriesGauge.js +105 -47
- package/dist/data/TimeseriesGauge.js.map +1 -1
- package/dist/data/WorkloadCard.cjs +371 -0
- package/dist/data/WorkloadCard.cjs.map +1 -0
- package/dist/data/WorkloadCard.d.ts +24 -0
- package/dist/data/WorkloadCard.d.ts.map +1 -0
- package/dist/data/WorkloadCard.js +371 -0
- package/dist/data/WorkloadCard.js.map +1 -0
- package/dist/data/WorkloadCard.model.cjs +51 -0
- package/dist/data/WorkloadCard.model.cjs.map +1 -0
- package/dist/data/WorkloadCard.model.d.ts +53 -0
- package/dist/data/WorkloadCard.model.d.ts.map +1 -0
- package/dist/data/WorkloadCard.model.js +51 -0
- package/dist/data/WorkloadCard.model.js.map +1 -0
- package/dist/data/ai/ChatFab.cjs +3 -1
- package/dist/data/ai/ChatFab.cjs.map +1 -1
- package/dist/data/ai/ChatFab.d.ts.map +1 -1
- package/dist/data/ai/ChatFab.js +3 -1
- package/dist/data/ai/ChatFab.js.map +1 -1
- package/dist/data/ai/ChatWindow.cjs +25 -7
- package/dist/data/ai/ChatWindow.cjs.map +1 -1
- package/dist/data/ai/ChatWindow.d.ts +11 -3
- package/dist/data/ai/ChatWindow.d.ts.map +1 -1
- package/dist/data/ai/ChatWindow.js +26 -8
- package/dist/data/ai/ChatWindow.js.map +1 -1
- package/dist/data/ai/chat-window-context.cjs +2 -1
- package/dist/data/ai/chat-window-context.cjs.map +1 -1
- package/dist/data/ai/chat-window-context.d.ts +1 -1
- package/dist/data/ai/chat-window-context.d.ts.map +1 -1
- package/dist/data/ai/chat-window-context.js +2 -1
- package/dist/data/ai/chat-window-context.js.map +1 -1
- package/dist/data/ai/context.cjs.map +1 -1
- package/dist/data/ai/context.d.ts +3 -0
- package/dist/data/ai/context.d.ts.map +1 -1
- package/dist/data/ai/context.js.map +1 -1
- package/dist/data/chat/Chat.cjs +9 -1
- package/dist/data/chat/Chat.cjs.map +1 -1
- package/dist/data/chat/Chat.d.ts +4 -2
- package/dist/data/chat/Chat.d.ts.map +1 -1
- package/dist/data/chat/Chat.js +10 -2
- package/dist/data/chat/Chat.js.map +1 -1
- package/dist/data/chat/Message.cjs +13 -4
- package/dist/data/chat/Message.cjs.map +1 -1
- package/dist/data/chat/Message.d.ts +4 -2
- package/dist/data/chat/Message.d.ts.map +1 -1
- package/dist/data/chat/Message.js +13 -4
- package/dist/data/chat/Message.js.map +1 -1
- package/dist/data/chat/ToolCall.cjs +9 -4
- package/dist/data/chat/ToolCall.cjs.map +1 -1
- package/dist/data/chat/ToolCall.d.ts +3 -2
- package/dist/data/chat/ToolCall.d.ts.map +1 -1
- package/dist/data/chat/ToolCall.js +9 -4
- package/dist/data/chat/ToolCall.js.map +1 -1
- package/dist/data/chat/index.d.ts +1 -1
- package/dist/data/chat/index.d.ts.map +1 -1
- package/dist/data/chat/types.cjs.map +1 -1
- package/dist/data/chat/types.d.ts +7 -0
- package/dist/data/chat/types.d.ts.map +1 -1
- package/dist/data/chat/types.js.map +1 -1
- package/dist/data/version-info.cjs +2 -2
- package/dist/data/version-info.js +2 -2
- package/dist/data.cjs +7 -0
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.ts +5 -3
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +8 -1
- package/dist/data.js.map +1 -1
- package/dist/hooks/use-sort.cjs +19 -10
- package/dist/hooks/use-sort.cjs.map +1 -1
- package/dist/hooks/use-sort.d.ts +3 -0
- package/dist/hooks/use-sort.d.ts.map +1 -1
- package/dist/hooks/use-sort.js +19 -10
- package/dist/hooks/use-sort.js.map +1 -1
- package/dist/index.cjs +11 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/layout/AppShell.cjs +6 -10
- package/dist/layout/AppShell.cjs.map +1 -1
- package/dist/layout/AppShell.d.ts +2 -0
- package/dist/layout/AppShell.d.ts.map +1 -1
- package/dist/layout/AppShell.js +6 -10
- package/dist/layout/AppShell.js.map +1 -1
- package/dist/overlay/DropdownMenu.cjs +50 -38
- package/dist/overlay/DropdownMenu.cjs.map +1 -1
- package/dist/overlay/DropdownMenu.d.ts +5 -1
- package/dist/overlay/DropdownMenu.d.ts.map +1 -1
- package/dist/overlay/DropdownMenu.js +50 -38
- package/dist/overlay/DropdownMenu.js.map +1 -1
- package/dist/overlay/HoverCard.cjs +7 -2
- package/dist/overlay/HoverCard.cjs.map +1 -1
- package/dist/overlay/HoverCard.d.ts.map +1 -1
- package/dist/overlay/HoverCard.js +7 -2
- package/dist/overlay/HoverCard.js.map +1 -1
- package/dist/overlay/Modal.cjs +20 -17
- package/dist/overlay/Modal.cjs.map +1 -1
- package/dist/overlay/Modal.d.ts.map +1 -1
- package/dist/overlay/Modal.js +21 -18
- package/dist/overlay/Modal.js.map +1 -1
- package/dist/overlay/Toast.cjs +9 -1
- package/dist/overlay/Toast.cjs.map +1 -1
- package/dist/overlay/Toast.d.ts.map +1 -1
- package/dist/overlay/Toast.js +9 -1
- package/dist/overlay/Toast.js.map +1 -1
- package/dist/overlay/modalStack.cjs +53 -1
- package/dist/overlay/modalStack.cjs.map +1 -1
- package/dist/overlay/modalStack.d.ts +12 -0
- package/dist/overlay/modalStack.d.ts.map +1 -1
- package/dist/overlay/modalStack.js +54 -2
- package/dist/overlay/modalStack.js.map +1 -1
- package/dist/overlay/zIndex.cjs +20 -0
- package/dist/overlay/zIndex.cjs.map +1 -0
- package/dist/overlay/zIndex.d.ts +39 -0
- package/dist/overlay/zIndex.d.ts.map +1 -0
- package/dist/overlay/zIndex.js +20 -0
- package/dist/overlay/zIndex.js.map +1 -0
- package/dist/rpc/AcceptPicker.cjs +28 -26
- package/dist/rpc/AcceptPicker.cjs.map +1 -1
- package/dist/rpc/AcceptPicker.d.ts.map +1 -1
- package/dist/rpc/AcceptPicker.js +29 -27
- package/dist/rpc/AcceptPicker.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -44,6 +44,8 @@ function TimeseriesGauge({
|
|
|
44
44
|
expandable = true,
|
|
45
45
|
thresholds = [75, 90],
|
|
46
46
|
centerDisplay = "value",
|
|
47
|
+
variant = "default",
|
|
48
|
+
showLabel = true,
|
|
47
49
|
fetcher = defaultFetcher,
|
|
48
50
|
className
|
|
49
51
|
}) {
|
|
@@ -83,60 +85,116 @@ function TimeseriesGauge({
|
|
|
83
85
|
const bounded = hasValue && limit !== void 0 && limit > 0;
|
|
84
86
|
const pct = bounded ? Math.min(100, Math.round(usage / limit * 100)) : 0;
|
|
85
87
|
const tone = toneClass(pct, thresholds);
|
|
88
|
+
const readout = centerDisplay === "percent" ? bounded ? `${pct}%` : hasValue ? "n/a" : "—" : hasValue ? formatUnit(usage, unit) : "—";
|
|
89
|
+
const titleText = `${title}: ${readout}`;
|
|
90
|
+
const canExpand = expandable && variant === "default";
|
|
91
|
+
const readoutTone = bounded ? tone : "text-foreground";
|
|
86
92
|
const chartSeries = useMemo(() => {
|
|
87
93
|
const s = [{ id: value.id, label: "value", ...value.transform ? { transform: value.transform } : {} }];
|
|
88
94
|
if (maxSeries) s.push({ id: maxSeries.id, label: "max", ...maxSeries.transform ? { transform: maxSeries.transform } : {} });
|
|
89
95
|
return s;
|
|
90
96
|
}, [value.id, value.transform, maxSeries]);
|
|
91
|
-
|
|
92
|
-
/* @__PURE__ */ jsxs(
|
|
93
|
-
|
|
94
|
-
/* @__PURE__ */ jsx("path", { d: GAUGE_PATH, fill: "none", stroke: "currentColor", strokeWidth: 9, strokeLinecap: "round", className: "text-muted" }),
|
|
95
|
-
/* @__PURE__ */ jsx(
|
|
96
|
-
"path",
|
|
97
|
-
{
|
|
98
|
-
d: GAUGE_PATH,
|
|
99
|
-
fill: "none",
|
|
100
|
-
stroke: "currentColor",
|
|
101
|
-
strokeWidth: 9,
|
|
102
|
-
strokeLinecap: "round",
|
|
103
|
-
className: tone,
|
|
104
|
-
strokeDasharray: GAUGE_ARC,
|
|
105
|
-
strokeDashoffset: GAUGE_ARC * (1 - pct / 100)
|
|
106
|
-
}
|
|
107
|
-
)
|
|
108
|
-
] }),
|
|
109
|
-
/* @__PURE__ */ jsx("span", { className: "absolute inset-x-0 bottom-0 text-center text-sm font-semibold text-foreground", children: centerDisplay === "percent" ? bounded ? `${pct}%` : hasValue ? "n/a" : "—" : hasValue ? formatUnit(usage, unit) : "—" }),
|
|
110
|
-
expandable && /* @__PURE__ */ jsx(
|
|
111
|
-
"button",
|
|
112
|
-
{
|
|
113
|
-
type: "button",
|
|
114
|
-
"aria-label": "Expand chart",
|
|
115
|
-
onClick: () => setExpanded(true),
|
|
116
|
-
className: "absolute right-0 top-0 text-muted-foreground hover:text-foreground",
|
|
117
|
-
children: /* @__PURE__ */ jsx(Icon, { icon: UiFullscreen, width: 12, height: 12 })
|
|
118
|
-
}
|
|
119
|
-
)
|
|
120
|
-
] }),
|
|
121
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
122
|
-
icon ? /* @__PURE__ */ jsx(GaugeIcon, { icon }) : null,
|
|
123
|
-
/* @__PURE__ */ jsx("span", { children: title })
|
|
124
|
-
] }),
|
|
125
|
-
expandable && /* @__PURE__ */ jsx(Modal, { open: expanded, onClose: () => setExpanded(false), title, size: "xl", children: /* @__PURE__ */ jsx(
|
|
126
|
-
TimeseriesPanel,
|
|
97
|
+
if (variant === "cell") {
|
|
98
|
+
return /* @__PURE__ */ jsxs(
|
|
99
|
+
"span",
|
|
127
100
|
{
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
101
|
+
className: cn(
|
|
102
|
+
"inline-flex min-w-0 items-center gap-1.5 whitespace-nowrap align-middle text-xs",
|
|
103
|
+
className
|
|
104
|
+
),
|
|
105
|
+
title: titleText,
|
|
106
|
+
"aria-label": !showLabel ? titleText : void 0,
|
|
107
|
+
children: [
|
|
108
|
+
icon ? /* @__PURE__ */ jsx(GaugeIcon, { icon }) : null,
|
|
109
|
+
showLabel ? /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate text-muted-foreground", children: title }) : null,
|
|
110
|
+
/* @__PURE__ */ jsx("span", { className: "relative h-4 w-8 shrink-0", "aria-hidden": "true", children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 100 50", className: "h-full w-full overflow-visible", children: [
|
|
111
|
+
/* @__PURE__ */ jsx(
|
|
112
|
+
"path",
|
|
113
|
+
{
|
|
114
|
+
d: GAUGE_PATH,
|
|
115
|
+
fill: "none",
|
|
116
|
+
stroke: "currentColor",
|
|
117
|
+
strokeWidth: 10,
|
|
118
|
+
strokeLinecap: "round",
|
|
119
|
+
className: "text-muted"
|
|
120
|
+
}
|
|
121
|
+
),
|
|
122
|
+
/* @__PURE__ */ jsx(
|
|
123
|
+
"path",
|
|
124
|
+
{
|
|
125
|
+
d: GAUGE_PATH,
|
|
126
|
+
fill: "none",
|
|
127
|
+
stroke: "currentColor",
|
|
128
|
+
strokeWidth: 10,
|
|
129
|
+
strokeLinecap: "round",
|
|
130
|
+
className: tone,
|
|
131
|
+
strokeDasharray: GAUGE_ARC,
|
|
132
|
+
strokeDashoffset: GAUGE_ARC * (1 - pct / 100)
|
|
133
|
+
}
|
|
134
|
+
)
|
|
135
|
+
] }) }),
|
|
136
|
+
/* @__PURE__ */ jsx("span", { className: cn("shrink-0 font-semibold tabular-nums", readoutTone), children: readout })
|
|
137
|
+
]
|
|
137
138
|
}
|
|
138
|
-
)
|
|
139
|
-
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
return /* @__PURE__ */ jsxs(
|
|
142
|
+
"div",
|
|
143
|
+
{
|
|
144
|
+
className: cn("flex flex-col items-center gap-1", className),
|
|
145
|
+
title: !showLabel ? titleText : void 0,
|
|
146
|
+
"aria-label": !showLabel ? titleText : void 0,
|
|
147
|
+
children: [
|
|
148
|
+
/* @__PURE__ */ jsxs("div", { className: "relative h-10 w-20", children: [
|
|
149
|
+
/* @__PURE__ */ jsxs("svg", { viewBox: "0 0 100 50", className: "h-full w-full overflow-visible", children: [
|
|
150
|
+
/* @__PURE__ */ jsx("path", { d: GAUGE_PATH, fill: "none", stroke: "currentColor", strokeWidth: 9, strokeLinecap: "round", className: "text-muted" }),
|
|
151
|
+
/* @__PURE__ */ jsx(
|
|
152
|
+
"path",
|
|
153
|
+
{
|
|
154
|
+
d: GAUGE_PATH,
|
|
155
|
+
fill: "none",
|
|
156
|
+
stroke: "currentColor",
|
|
157
|
+
strokeWidth: 9,
|
|
158
|
+
strokeLinecap: "round",
|
|
159
|
+
className: tone,
|
|
160
|
+
strokeDasharray: GAUGE_ARC,
|
|
161
|
+
strokeDashoffset: GAUGE_ARC * (1 - pct / 100)
|
|
162
|
+
}
|
|
163
|
+
)
|
|
164
|
+
] }),
|
|
165
|
+
/* @__PURE__ */ jsx("span", { className: "absolute inset-x-0 bottom-0 text-center text-sm font-semibold text-foreground", children: readout }),
|
|
166
|
+
canExpand && /* @__PURE__ */ jsx(
|
|
167
|
+
"button",
|
|
168
|
+
{
|
|
169
|
+
type: "button",
|
|
170
|
+
"aria-label": "Expand chart",
|
|
171
|
+
onClick: () => setExpanded(true),
|
|
172
|
+
className: "absolute right-0 top-0 text-muted-foreground hover:text-foreground",
|
|
173
|
+
children: /* @__PURE__ */ jsx(Icon, { icon: UiFullscreen, width: 12, height: 12 })
|
|
174
|
+
}
|
|
175
|
+
)
|
|
176
|
+
] }),
|
|
177
|
+
icon || showLabel ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
178
|
+
icon ? /* @__PURE__ */ jsx(GaugeIcon, { icon }) : null,
|
|
179
|
+
showLabel ? /* @__PURE__ */ jsx("span", { children: title }) : null
|
|
180
|
+
] }) : null,
|
|
181
|
+
canExpand && /* @__PURE__ */ jsx(Modal, { open: expanded, onClose: () => setExpanded(false), title, size: "xl", children: /* @__PURE__ */ jsx(
|
|
182
|
+
TimeseriesPanel,
|
|
183
|
+
{
|
|
184
|
+
title,
|
|
185
|
+
...icon ? { icon } : {},
|
|
186
|
+
...unit ? { unit } : {},
|
|
187
|
+
baseUrl,
|
|
188
|
+
series: chartSeries,
|
|
189
|
+
range,
|
|
190
|
+
refreshMs,
|
|
191
|
+
expandable: false,
|
|
192
|
+
fetcher
|
|
193
|
+
}
|
|
194
|
+
) })
|
|
195
|
+
]
|
|
196
|
+
}
|
|
197
|
+
);
|
|
140
198
|
}
|
|
141
199
|
export {
|
|
142
200
|
TimeseriesGauge
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimeseriesGauge.js","sources":["../../src/data/TimeseriesGauge.tsx"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { useMemo, useState } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { formatUnit } from \"../lib/format\";\nimport { Modal } from \"../overlay/Modal\";\nimport { UiFullscreen } from \"../icons\";\nimport { Icon, type StaticIconComponent } from \"./Icon\";\nimport {\n TimeseriesPanel,\n type TimeseriesResponse,\n type TimeseriesSeries,\n} from \"./TimeseriesPanel\";\n\n/** A metric series whose latest value drives the gauge fill or its maximum. */\nexport interface GaugeSeries {\n /** Metric id appended to the gauge's baseUrl, e.g. \"k8s.statefulset.cycle.cpu.usage\". */\n id: string;\n /** Maps the latest value before display (e.g. unit scaling). Identity when omitted. */\n transform?: (value: number) => number;\n}\n\nexport interface TimeseriesGaugeProps {\n /** Common prefix; the value/max requests are `baseUrl + id`. */\n baseUrl?: string;\n /** The metric whose latest value fills the gauge. */\n value: GaugeSeries;\n /**\n * The gauge maximum. Either a metric series (its latest value, e.g. a `.limit`\n * metric) or a fixed number. When omitted, or when the resolved max is 0, the\n * gauge shows the raw value with no fill (an unbounded reading).\n */\n max?: GaugeSeries | number;\n title: string;\n /** Iconify name or static icon component shown beside the label. */\n icon?: string | StaticIconComponent;\n /** Grafana-style unit key for the readout (e.g. \"bytes\", \"percent\", \"short\", \"ms\"). */\n unit?: string;\n /** Look-back window for the expand chart, passed as ?since=; defaults to \"1h\". */\n range?: string;\n /** Poll interval in ms; defaults to 5000. Pass 0 to disable polling. */\n refreshMs?: number;\n /** Show an expand button that opens the value/max time-series chart in a modal. Default true. */\n expandable?: boolean;\n /**\n * Utilisation thresholds (percent of max) at which the arc turns amber then\n * red. Defaults to [75, 90].\n */\n thresholds?: [warning: number, danger: number];\n /**\n * What to print in the centre: the formatted value (default) or the\n * utilisation percentage of max (e.g. CPU usage out of its millicore limit).\n */\n centerDisplay?: \"value\" | \"percent\";\n /** Override the default fetch (e.g. to route through an app's API client). */\n fetcher?: (url: string) => Promise<TimeseriesResponse>;\n className?: string;\n}\n\nconst defaultFetcher = async (url: string): Promise<TimeseriesResponse> => {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`metrics request failed: ${res.status}`);\n return res.json();\n};\n\n// Half-gauge SVG geometry: a 100×50 viewBox semicircle (radius 40, centre 50,50)\n// swept 180°. The arc length is π·r; stroke-dashoffset reveals value/max of it.\nconst GAUGE_RADIUS = 40;\nconst GAUGE_ARC = Math.PI * GAUGE_RADIUS;\nconst GAUGE_PATH = `M 10 50 A ${GAUGE_RADIUS} ${GAUGE_RADIUS} 0 0 1 90 50`;\n\nfunction toneClass(pct: number, [warn, danger]: [number, number]): string {\n if (pct >= danger) return \"text-red-500\";\n if (pct >= warn) return \"text-amber-500\";\n return \"text-emerald-500\";\n}\n\nfunction latestValue(resp: TimeseriesResponse | undefined): number | undefined {\n const points = resp?.points;\n if (!points || points.length === 0) return undefined;\n return points[points.length - 1]?.value;\n}\n\nfunction GaugeIcon({ icon }: { icon: string | StaticIconComponent }) {\n if (typeof icon === \"string\") {\n return <Icon name={icon} width={14} height={14} className=\"text-muted-foreground\" />;\n }\n return <Icon icon={icon} width={14} height={14} className=\"text-muted-foreground\" />;\n}\n\n/**\n * TimeseriesGauge renders a half (180°) radial gauge whose fill is the latest\n * value of a metric over its maximum (a `.limit`-style metric or a fixed number),\n * both read live from the timeseries store. The centre shows the utilisation\n * percentage, with the value/max caption below; the arc colour crosses warning\n * and danger thresholds. An expand button opens the full value/max time-series\n * chart in a modal (a `TimeseriesPanel`), so the gauge gives the at-a-glance\n * reading and the chart the trend.\n */\nexport function TimeseriesGauge({\n baseUrl = \"\",\n value,\n max,\n title,\n icon,\n unit,\n range = \"1h\",\n refreshMs = 5000,\n expandable = true,\n thresholds = [75, 90],\n centerDisplay = \"value\",\n fetcher = defaultFetcher,\n className,\n}: TimeseriesGaugeProps) {\n const [expanded, setExpanded] = useState(false);\n\n const maxIsSeries = typeof max === \"object\";\n const maxSeries = maxIsSeries ? max : undefined;\n const ids = useMemo(() => {\n const list = [value.id];\n if (maxSeries) list.push(maxSeries.id);\n return list;\n }, [value.id, maxSeries]);\n\n const results = useQueries({\n queries: ids.map((id) => {\n const u = new URL(baseUrl + id, window.location.origin);\n if (range) u.searchParams.set(\"since\", range);\n const requestUrl = u.pathname + u.search;\n return {\n queryKey: [\"timeseries\", requestUrl],\n queryFn: () => fetcher(requestUrl),\n refetchInterval: refreshMs > 0 ? refreshMs : false,\n staleTime: 0,\n retry: 0,\n };\n }),\n });\n\n const rawValue = latestValue(results[0]?.data);\n const hasValue = rawValue !== undefined;\n const usage = value.transform ? value.transform(rawValue ?? 0) : (rawValue ?? 0);\n\n let limit: number | undefined;\n if (typeof max === \"number\") {\n limit = max;\n } else if (maxSeries) {\n const rawMax = latestValue(results[1]?.data);\n limit = rawMax === undefined ? undefined : maxSeries.transform ? maxSeries.transform(rawMax) : rawMax;\n }\n\n const bounded = hasValue && limit !== undefined && limit > 0;\n const pct = bounded ? Math.min(100, Math.round((usage / (limit as number)) * 100)) : 0;\n const tone = toneClass(pct, thresholds);\n\n const chartSeries: TimeseriesSeries[] = useMemo(() => {\n const s: TimeseriesSeries[] = [{ id: value.id, label: \"value\", ...(value.transform ? { transform: value.transform } : {}) }];\n if (maxSeries) s.push({ id: maxSeries.id, label: \"max\", ...(maxSeries.transform ? { transform: maxSeries.transform } : {}) });\n return s;\n }, [value.id, value.transform, maxSeries]);\n\n return (\n <div className={cn(\"flex flex-col items-center gap-1\", className)}>\n <div className=\"relative h-10 w-20\">\n <svg viewBox=\"0 0 100 50\" className=\"h-full w-full overflow-visible\">\n <path d={GAUGE_PATH} fill=\"none\" stroke=\"currentColor\" strokeWidth={9} strokeLinecap=\"round\" className=\"text-muted\" />\n <path\n d={GAUGE_PATH}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={9}\n strokeLinecap=\"round\"\n className={tone}\n strokeDasharray={GAUGE_ARC}\n strokeDashoffset={GAUGE_ARC * (1 - pct / 100)}\n />\n </svg>\n <span className=\"absolute inset-x-0 bottom-0 text-center text-sm font-semibold text-foreground\">\n {centerDisplay === \"percent\"\n ? bounded\n ? `${pct}%`\n : hasValue\n ? \"n/a\"\n : \"—\"\n : hasValue\n ? formatUnit(usage, unit)\n : \"—\"}\n </span>\n {expandable && (\n <button\n type=\"button\"\n aria-label=\"Expand chart\"\n onClick={() => setExpanded(true)}\n className=\"absolute right-0 top-0 text-muted-foreground hover:text-foreground\"\n >\n <Icon icon={UiFullscreen} width={12} height={12} />\n </button>\n )}\n </div>\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n {icon ? <GaugeIcon icon={icon} /> : null}\n <span>{title}</span>\n </div>\n\n {expandable && (\n <Modal open={expanded} onClose={() => setExpanded(false)} title={title} size=\"xl\">\n <TimeseriesPanel\n title={title}\n {...(icon ? { icon } : {})}\n {...(unit ? { unit } : {})}\n baseUrl={baseUrl}\n series={chartSeries}\n range={range}\n refreshMs={refreshMs}\n expandable={false}\n fetcher={fetcher}\n />\n </Modal>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TimeseriesGauge.js","sources":["../../src/data/TimeseriesGauge.tsx"],"sourcesContent":["import { useQueries } from \"@tanstack/react-query\";\nimport { useMemo, useState } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { formatUnit } from \"../lib/format\";\nimport { Modal } from \"../overlay/Modal\";\nimport { UiFullscreen } from \"../icons\";\nimport { Icon, type StaticIconComponent } from \"./Icon\";\nimport {\n TimeseriesPanel,\n type TimeseriesResponse,\n type TimeseriesSeries,\n} from \"./TimeseriesPanel\";\n\n/** A metric series whose latest value drives the gauge fill or its maximum. */\nexport interface GaugeSeries {\n /** Metric id appended to the gauge's baseUrl, e.g. \"k8s.statefulset.cycle.cpu.usage\". */\n id: string;\n /** Maps the latest value before display (e.g. unit scaling). Identity when omitted. */\n transform?: (value: number) => number;\n}\n\nexport type TimeseriesGaugeVariant = \"default\" | \"cell\";\n\nexport interface TimeseriesGaugeProps {\n /** Common prefix; the value/max requests are `baseUrl + id`. */\n baseUrl?: string;\n /** The metric whose latest value fills the gauge. */\n value: GaugeSeries;\n /**\n * The gauge maximum. Either a metric series (its latest value, e.g. a `.limit`\n * metric) or a fixed number. When omitted, or when the resolved max is 0, the\n * gauge shows the raw value with no fill (an unbounded reading).\n */\n max?: GaugeSeries | number;\n title: string;\n /** Iconify name or static icon component shown beside the label. */\n icon?: string | StaticIconComponent;\n /** Grafana-style unit key for the readout (e.g. \"bytes\", \"percent\", \"short\", \"ms\"). */\n unit?: string;\n /** Look-back window for the expand chart, passed as ?since=; defaults to \"1h\". */\n range?: string;\n /** Poll interval in ms; defaults to 5000. Pass 0 to disable polling. */\n refreshMs?: number;\n /** Show an expand button that opens the value/max time-series chart in a modal. Default true. */\n expandable?: boolean;\n /**\n * Utilisation thresholds (percent of max) at which the arc turns amber then\n * red. Defaults to [75, 90].\n */\n thresholds?: [warning: number, danger: number];\n /**\n * What to print in the centre: the formatted value (default) or the\n * utilisation percentage of max (e.g. CPU usage out of its millicore limit).\n */\n centerDisplay?: \"value\" | \"percent\";\n /** Visual density/layout. `cell` is a compact inline form for table/grid cells. */\n variant?: TimeseriesGaugeVariant;\n /** Show the title text. Icons and values remain visible when false. */\n showLabel?: boolean;\n /** Override the default fetch (e.g. to route through an app's API client). */\n fetcher?: (url: string) => Promise<TimeseriesResponse>;\n className?: string;\n}\n\nconst defaultFetcher = async (url: string): Promise<TimeseriesResponse> => {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`metrics request failed: ${res.status}`);\n return res.json();\n};\n\n// Half-gauge SVG geometry: a 100×50 viewBox semicircle (radius 40, centre 50,50)\n// swept 180°. The arc length is π·r; stroke-dashoffset reveals value/max of it.\nconst GAUGE_RADIUS = 40;\nconst GAUGE_ARC = Math.PI * GAUGE_RADIUS;\nconst GAUGE_PATH = `M 10 50 A ${GAUGE_RADIUS} ${GAUGE_RADIUS} 0 0 1 90 50`;\n\nfunction toneClass(pct: number, [warn, danger]: [number, number]): string {\n if (pct >= danger) return \"text-red-500\";\n if (pct >= warn) return \"text-amber-500\";\n return \"text-emerald-500\";\n}\n\nfunction latestValue(resp: TimeseriesResponse | undefined): number | undefined {\n const points = resp?.points;\n if (!points || points.length === 0) return undefined;\n return points[points.length - 1]?.value;\n}\n\nfunction GaugeIcon({ icon }: { icon: string | StaticIconComponent }) {\n if (typeof icon === \"string\") {\n return <Icon name={icon} width={14} height={14} className=\"text-muted-foreground\" />;\n }\n return <Icon icon={icon} width={14} height={14} className=\"text-muted-foreground\" />;\n}\n\n/**\n * TimeseriesGauge renders a half (180°) radial gauge whose fill is the latest\n * value of a metric over its maximum (a `.limit`-style metric or a fixed number),\n * both read live from the timeseries store. The centre shows the utilisation\n * percentage, with the value/max caption below; the arc colour crosses warning\n * and danger thresholds. An expand button opens the full value/max time-series\n * chart in a modal (a `TimeseriesPanel`), so the gauge gives the at-a-glance\n * reading and the chart the trend.\n */\nexport function TimeseriesGauge({\n baseUrl = \"\",\n value,\n max,\n title,\n icon,\n unit,\n range = \"1h\",\n refreshMs = 5000,\n expandable = true,\n thresholds = [75, 90],\n centerDisplay = \"value\",\n variant = \"default\",\n showLabel = true,\n fetcher = defaultFetcher,\n className,\n}: TimeseriesGaugeProps) {\n const [expanded, setExpanded] = useState(false);\n\n const maxIsSeries = typeof max === \"object\";\n const maxSeries = maxIsSeries ? max : undefined;\n const ids = useMemo(() => {\n const list = [value.id];\n if (maxSeries) list.push(maxSeries.id);\n return list;\n }, [value.id, maxSeries]);\n\n const results = useQueries({\n queries: ids.map((id) => {\n const u = new URL(baseUrl + id, window.location.origin);\n if (range) u.searchParams.set(\"since\", range);\n const requestUrl = u.pathname + u.search;\n return {\n queryKey: [\"timeseries\", requestUrl],\n queryFn: () => fetcher(requestUrl),\n refetchInterval: refreshMs > 0 ? refreshMs : false,\n staleTime: 0,\n retry: 0,\n };\n }),\n });\n\n const rawValue = latestValue(results[0]?.data);\n const hasValue = rawValue !== undefined;\n const usage = value.transform ? value.transform(rawValue ?? 0) : (rawValue ?? 0);\n\n let limit: number | undefined;\n if (typeof max === \"number\") {\n limit = max;\n } else if (maxSeries) {\n const rawMax = latestValue(results[1]?.data);\n limit = rawMax === undefined ? undefined : maxSeries.transform ? maxSeries.transform(rawMax) : rawMax;\n }\n\n const bounded = hasValue && limit !== undefined && limit > 0;\n const pct = bounded ? Math.min(100, Math.round((usage / (limit as number)) * 100)) : 0;\n const tone = toneClass(pct, thresholds);\n const readout =\n centerDisplay === \"percent\"\n ? bounded\n ? `${pct}%`\n : hasValue\n ? \"n/a\"\n : \"—\"\n : hasValue\n ? formatUnit(usage, unit)\n : \"—\";\n const titleText = `${title}: ${readout}`;\n const canExpand = expandable && variant === \"default\";\n const readoutTone = bounded ? tone : \"text-foreground\";\n\n const chartSeries: TimeseriesSeries[] = useMemo(() => {\n const s: TimeseriesSeries[] = [{ id: value.id, label: \"value\", ...(value.transform ? { transform: value.transform } : {}) }];\n if (maxSeries) s.push({ id: maxSeries.id, label: \"max\", ...(maxSeries.transform ? { transform: maxSeries.transform } : {}) });\n return s;\n }, [value.id, value.transform, maxSeries]);\n\n if (variant === \"cell\") {\n return (\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 title={titleText}\n aria-label={!showLabel ? titleText : undefined}\n >\n {icon ? <GaugeIcon icon={icon} /> : null}\n {showLabel ? <span className=\"min-w-0 truncate text-muted-foreground\">{title}</span> : null}\n <span className=\"relative h-4 w-8 shrink-0\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 100 50\" className=\"h-full w-full overflow-visible\">\n <path\n d={GAUGE_PATH}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={10}\n strokeLinecap=\"round\"\n className=\"text-muted\"\n />\n <path\n d={GAUGE_PATH}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={10}\n strokeLinecap=\"round\"\n className={tone}\n strokeDasharray={GAUGE_ARC}\n strokeDashoffset={GAUGE_ARC * (1 - pct / 100)}\n />\n </svg>\n </span>\n <span className={cn(\"shrink-0 font-semibold tabular-nums\", readoutTone)}>\n {readout}\n </span>\n </span>\n );\n }\n\n return (\n <div\n className={cn(\"flex flex-col items-center gap-1\", className)}\n title={!showLabel ? titleText : undefined}\n aria-label={!showLabel ? titleText : undefined}\n >\n <div className=\"relative h-10 w-20\">\n <svg viewBox=\"0 0 100 50\" className=\"h-full w-full overflow-visible\">\n <path d={GAUGE_PATH} fill=\"none\" stroke=\"currentColor\" strokeWidth={9} strokeLinecap=\"round\" className=\"text-muted\" />\n <path\n d={GAUGE_PATH}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={9}\n strokeLinecap=\"round\"\n className={tone}\n strokeDasharray={GAUGE_ARC}\n strokeDashoffset={GAUGE_ARC * (1 - pct / 100)}\n />\n </svg>\n <span className=\"absolute inset-x-0 bottom-0 text-center text-sm font-semibold text-foreground\">\n {readout}\n </span>\n {canExpand && (\n <button\n type=\"button\"\n aria-label=\"Expand chart\"\n onClick={() => setExpanded(true)}\n className=\"absolute right-0 top-0 text-muted-foreground hover:text-foreground\"\n >\n <Icon icon={UiFullscreen} width={12} height={12} />\n </button>\n )}\n </div>\n {icon || showLabel ? (\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n {icon ? <GaugeIcon icon={icon} /> : null}\n {showLabel ? <span>{title}</span> : null}\n </div>\n ) : null}\n\n {canExpand && (\n <Modal open={expanded} onClose={() => setExpanded(false)} title={title} size=\"xl\">\n <TimeseriesPanel\n title={title}\n {...(icon ? { icon } : {})}\n {...(unit ? { unit } : {})}\n baseUrl={baseUrl}\n series={chartSeries}\n range={range}\n refreshMs={refreshMs}\n expandable={false}\n fetcher={fetcher}\n />\n </Modal>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const react = require("react");
|
|
5
|
+
const mi = require("@flanksource/icons/mi");
|
|
6
|
+
const utils = require("../lib/utils.cjs");
|
|
7
|
+
const Modal = require("../overlay/Modal.cjs");
|
|
8
|
+
const Badge = require("./Badge.cjs");
|
|
9
|
+
const Timestamp = require("./cells/Timestamp.cjs");
|
|
10
|
+
const Icon = require("./Icon.cjs");
|
|
11
|
+
const TimeseriesCoreBars = require("./TimeseriesCoreBars.cjs");
|
|
12
|
+
const TimeseriesGauge = require("./TimeseriesGauge.cjs");
|
|
13
|
+
const TimeseriesPanel = require("./TimeseriesPanel.cjs");
|
|
14
|
+
const WorkloadCard_model = require("./WorkloadCard.model.cjs");
|
|
15
|
+
const UiChip = require("../icons/components/UiChip.cjs");
|
|
16
|
+
const UiMemoryStick = require("../icons/components/UiMemoryStick.cjs");
|
|
17
|
+
const UiHardDrive = require("../icons/components/UiHardDrive.cjs");
|
|
18
|
+
const UiFullscreen = require("../icons/components/UiFullscreen.cjs");
|
|
19
|
+
const KIND_ICONS = {
|
|
20
|
+
service: mi.K8SService,
|
|
21
|
+
ingress: mi.K8SIngress,
|
|
22
|
+
deployment: mi.K8SDeployment,
|
|
23
|
+
statefulset: mi.K8SStatefulset,
|
|
24
|
+
pod: mi.K8SPod
|
|
25
|
+
};
|
|
26
|
+
const SIZE_CLASSES = {
|
|
27
|
+
sm: {
|
|
28
|
+
root: "p-2",
|
|
29
|
+
header: "mb-2 gap-2",
|
|
30
|
+
titleGap: "gap-1",
|
|
31
|
+
icon: "h-3.5 w-3.5",
|
|
32
|
+
name: "text-xs",
|
|
33
|
+
meta: "mt-0.5 gap-x-1.5 gap-y-0.5 text-[11px] leading-4",
|
|
34
|
+
statusSize: "xxs",
|
|
35
|
+
action: "h-5 w-5",
|
|
36
|
+
actionIcon: 12,
|
|
37
|
+
metricGrid: "grid-cols-1 gap-1.5",
|
|
38
|
+
metricVariant: "cell",
|
|
39
|
+
empty: "px-2 py-3 text-[11px]"
|
|
40
|
+
},
|
|
41
|
+
md: {
|
|
42
|
+
root: "p-3",
|
|
43
|
+
header: "mb-3 gap-2",
|
|
44
|
+
titleGap: "gap-1.5",
|
|
45
|
+
icon: "h-4 w-4",
|
|
46
|
+
name: "text-sm",
|
|
47
|
+
meta: "mt-0.5 gap-x-2 gap-y-0.5 text-xs",
|
|
48
|
+
statusSize: "xs",
|
|
49
|
+
action: "h-6 w-6",
|
|
50
|
+
actionIcon: 14,
|
|
51
|
+
metricGrid: "gap-3",
|
|
52
|
+
metricVariant: "default",
|
|
53
|
+
empty: "px-3 py-4 text-xs"
|
|
54
|
+
},
|
|
55
|
+
lg: {
|
|
56
|
+
root: "p-4",
|
|
57
|
+
header: "mb-4 gap-3",
|
|
58
|
+
titleGap: "gap-2",
|
|
59
|
+
icon: "h-5 w-5",
|
|
60
|
+
name: "text-base",
|
|
61
|
+
meta: "mt-1 gap-x-2 gap-y-1 text-xs",
|
|
62
|
+
statusSize: "sm",
|
|
63
|
+
action: "h-7 w-7",
|
|
64
|
+
actionIcon: 16,
|
|
65
|
+
metricGrid: "gap-4",
|
|
66
|
+
metricVariant: "default",
|
|
67
|
+
empty: "px-4 py-6 text-sm"
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const VARIANT_CLASSES = {
|
|
71
|
+
default: "border-border bg-card text-card-foreground",
|
|
72
|
+
outline: "border-border bg-background text-foreground",
|
|
73
|
+
subtle: "border-transparent bg-muted/35 text-foreground",
|
|
74
|
+
elevated: "border-border/70 bg-card text-card-foreground shadow-sm",
|
|
75
|
+
ghost: "border-transparent bg-transparent text-foreground"
|
|
76
|
+
};
|
|
77
|
+
function metricGridClass(count) {
|
|
78
|
+
if (count <= 1) return "grid-cols-1";
|
|
79
|
+
if (count === 2) return "grid-cols-2";
|
|
80
|
+
return "grid-cols-3";
|
|
81
|
+
}
|
|
82
|
+
function WorkloadIcon({
|
|
83
|
+
icon,
|
|
84
|
+
title,
|
|
85
|
+
className
|
|
86
|
+
}) {
|
|
87
|
+
if (typeof icon === "string") {
|
|
88
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { name: icon, title, ...className ? { className } : {} });
|
|
89
|
+
}
|
|
90
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon, title, ...className ? { className } : {} });
|
|
91
|
+
}
|
|
92
|
+
function metricSeries(metric) {
|
|
93
|
+
const series = [
|
|
94
|
+
{
|
|
95
|
+
id: metric.value.id,
|
|
96
|
+
label: metric.valueLabel ?? "usage",
|
|
97
|
+
...metric.value.transform ? { transform: metric.value.transform } : {}
|
|
98
|
+
}
|
|
99
|
+
];
|
|
100
|
+
if (typeof metric.max === "object") {
|
|
101
|
+
series.push({
|
|
102
|
+
id: metric.max.id,
|
|
103
|
+
label: metric.maxLabel ?? "limit",
|
|
104
|
+
...metric.max.transform ? { transform: metric.max.transform } : {}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return series;
|
|
108
|
+
}
|
|
109
|
+
function hasMetric(metrics) {
|
|
110
|
+
return Boolean(metrics.cpu || metrics.memory || metrics.disk);
|
|
111
|
+
}
|
|
112
|
+
function HeaderMeta({ children }) {
|
|
113
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex min-w-0 items-center gap-1", children: [
|
|
114
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
115
|
+
"span",
|
|
116
|
+
{
|
|
117
|
+
className: "h-1 w-1 shrink-0 rounded-full bg-muted-foreground/40",
|
|
118
|
+
"aria-hidden": true
|
|
119
|
+
}
|
|
120
|
+
),
|
|
121
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children })
|
|
122
|
+
] });
|
|
123
|
+
}
|
|
124
|
+
function WorkloadCard({
|
|
125
|
+
workload,
|
|
126
|
+
metrics,
|
|
127
|
+
baseUrl,
|
|
128
|
+
range = "1h",
|
|
129
|
+
refreshMs = 5e3,
|
|
130
|
+
expandable = true,
|
|
131
|
+
size = "md",
|
|
132
|
+
variant = "default",
|
|
133
|
+
fetcher,
|
|
134
|
+
className
|
|
135
|
+
}) {
|
|
136
|
+
var _a;
|
|
137
|
+
const [expanded, setExpanded] = react.useState(false);
|
|
138
|
+
const kindLabel = WorkloadCard_model.workloadKindLabel(workload.kind);
|
|
139
|
+
const statusLabel = WorkloadCard_model.workloadStatusLabel(workload.status);
|
|
140
|
+
const replicaText = WorkloadCard_model.formatReplicaCounts(workload.replicas);
|
|
141
|
+
const workloadIcon = workload.icon ?? KIND_ICONS[workload.kind];
|
|
142
|
+
const sizeClasses = SIZE_CLASSES[size];
|
|
143
|
+
const panelMetrics = react.useMemo(() => {
|
|
144
|
+
const list = [];
|
|
145
|
+
if (metrics.cpu) {
|
|
146
|
+
list.push({
|
|
147
|
+
key: "cpu",
|
|
148
|
+
title: metrics.cpu.title ?? "CPU",
|
|
149
|
+
unit: metrics.cpu.unit ?? "short",
|
|
150
|
+
icon: metrics.cpu.icon ?? UiChip.UiChip,
|
|
151
|
+
metric: metrics.cpu
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
if (metrics.memory) {
|
|
155
|
+
list.push({
|
|
156
|
+
key: "memory",
|
|
157
|
+
title: metrics.memory.title ?? "Memory",
|
|
158
|
+
unit: metrics.memory.unit ?? "bytes",
|
|
159
|
+
icon: metrics.memory.icon ?? UiMemoryStick.UiMemoryStick,
|
|
160
|
+
metric: metrics.memory
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
if (metrics.disk) {
|
|
164
|
+
list.push({
|
|
165
|
+
key: "disk",
|
|
166
|
+
title: metrics.disk.title ?? "Disk",
|
|
167
|
+
unit: metrics.disk.unit ?? "bytes",
|
|
168
|
+
icon: metrics.disk.icon ?? UiHardDrive.UiHardDrive,
|
|
169
|
+
metric: metrics.disk
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return list;
|
|
173
|
+
}, [metrics]);
|
|
174
|
+
const metricProps = {
|
|
175
|
+
...baseUrl !== void 0 ? { baseUrl } : {},
|
|
176
|
+
range,
|
|
177
|
+
refreshMs,
|
|
178
|
+
...fetcher !== void 0 ? { fetcher } : {}
|
|
179
|
+
};
|
|
180
|
+
const canExpand = expandable && hasMetric(metrics);
|
|
181
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
182
|
+
"div",
|
|
183
|
+
{
|
|
184
|
+
className: utils.cn(
|
|
185
|
+
"w-full rounded-md border",
|
|
186
|
+
VARIANT_CLASSES[variant],
|
|
187
|
+
sizeClasses.root,
|
|
188
|
+
className
|
|
189
|
+
),
|
|
190
|
+
"data-size": size,
|
|
191
|
+
"data-variant": variant,
|
|
192
|
+
children: [
|
|
193
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
194
|
+
"div",
|
|
195
|
+
{
|
|
196
|
+
className: utils.cn("flex items-start justify-between", sizeClasses.header),
|
|
197
|
+
children: [
|
|
198
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
199
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
200
|
+
"div",
|
|
201
|
+
{
|
|
202
|
+
className: utils.cn("flex min-w-0 items-center", sizeClasses.titleGap),
|
|
203
|
+
children: [
|
|
204
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
205
|
+
WorkloadIcon,
|
|
206
|
+
{
|
|
207
|
+
icon: workloadIcon,
|
|
208
|
+
title: kindLabel,
|
|
209
|
+
className: utils.cn("shrink-0 text-muted-foreground", sizeClasses.icon)
|
|
210
|
+
}
|
|
211
|
+
),
|
|
212
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
213
|
+
"span",
|
|
214
|
+
{
|
|
215
|
+
className: utils.cn("min-w-0 truncate font-medium", sizeClasses.name),
|
|
216
|
+
title: workload.name,
|
|
217
|
+
children: workload.name
|
|
218
|
+
}
|
|
219
|
+
)
|
|
220
|
+
]
|
|
221
|
+
}
|
|
222
|
+
),
|
|
223
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
224
|
+
"div",
|
|
225
|
+
{
|
|
226
|
+
className: utils.cn(
|
|
227
|
+
"flex flex-wrap items-center text-muted-foreground",
|
|
228
|
+
sizeClasses.meta
|
|
229
|
+
),
|
|
230
|
+
children: [
|
|
231
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: kindLabel }),
|
|
232
|
+
workload.namespace ? /* @__PURE__ */ jsxRuntime.jsx(HeaderMeta, { children: workload.namespace }) : null,
|
|
233
|
+
workload.role ? /* @__PURE__ */ jsxRuntime.jsx(HeaderMeta, { children: workload.role }) : null,
|
|
234
|
+
replicaText ? /* @__PURE__ */ jsxRuntime.jsx(HeaderMeta, { children: replicaText }) : null,
|
|
235
|
+
workload.createdAt !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs(HeaderMeta, { children: [
|
|
236
|
+
"age ",
|
|
237
|
+
/* @__PURE__ */ jsxRuntime.jsx(Timestamp.Timestamp, { value: workload.createdAt, format: "relative" })
|
|
238
|
+
] }) : null
|
|
239
|
+
]
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
] }),
|
|
243
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
244
|
+
statusLabel ? /* @__PURE__ */ jsxRuntime.jsx("span", { title: (_a = workload.status) == null ? void 0 : _a.message, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
245
|
+
Badge.Badge,
|
|
246
|
+
{
|
|
247
|
+
tone: WorkloadCard_model.workloadStatusTone(workload.status),
|
|
248
|
+
variant: "soft",
|
|
249
|
+
size: sizeClasses.statusSize,
|
|
250
|
+
children: statusLabel
|
|
251
|
+
}
|
|
252
|
+
) }) : null,
|
|
253
|
+
canExpand ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
254
|
+
"button",
|
|
255
|
+
{
|
|
256
|
+
type: "button",
|
|
257
|
+
"aria-label": `Open ${workload.name} history`,
|
|
258
|
+
title: "History",
|
|
259
|
+
onClick: () => setExpanded(true),
|
|
260
|
+
className: utils.cn(
|
|
261
|
+
"inline-flex items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
262
|
+
sizeClasses.action
|
|
263
|
+
),
|
|
264
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
265
|
+
Icon.Icon,
|
|
266
|
+
{
|
|
267
|
+
icon: UiFullscreen.UiFullscreen,
|
|
268
|
+
width: sizeClasses.actionIcon,
|
|
269
|
+
height: sizeClasses.actionIcon
|
|
270
|
+
}
|
|
271
|
+
)
|
|
272
|
+
}
|
|
273
|
+
) : null
|
|
274
|
+
] })
|
|
275
|
+
]
|
|
276
|
+
}
|
|
277
|
+
),
|
|
278
|
+
hasMetric(metrics) ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
279
|
+
"div",
|
|
280
|
+
{
|
|
281
|
+
className: utils.cn(
|
|
282
|
+
"grid items-start gap-3",
|
|
283
|
+
sizeClasses.metricVariant === "cell" ? sizeClasses.metricGrid : utils.cn(
|
|
284
|
+
metricGridClass(panelMetrics.length),
|
|
285
|
+
sizeClasses.metricGrid
|
|
286
|
+
)
|
|
287
|
+
),
|
|
288
|
+
children: [
|
|
289
|
+
metrics.cpu ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
290
|
+
TimeseriesCoreBars.TimeseriesCoreBars,
|
|
291
|
+
{
|
|
292
|
+
title: metrics.cpu.title ?? "CPU",
|
|
293
|
+
icon: metrics.cpu.icon ?? UiChip.UiChip,
|
|
294
|
+
value: metrics.cpu.value,
|
|
295
|
+
...metrics.cpu.max !== void 0 ? { max: metrics.cpu.max } : {},
|
|
296
|
+
...metrics.cpu.thresholds ? { thresholds: metrics.cpu.thresholds } : {},
|
|
297
|
+
...metrics.cpu.orientation ? { orientation: metrics.cpu.orientation } : {},
|
|
298
|
+
...metrics.cpu.showValue !== void 0 ? { showValue: metrics.cpu.showValue } : {},
|
|
299
|
+
variant: sizeClasses.metricVariant,
|
|
300
|
+
...metricProps
|
|
301
|
+
}
|
|
302
|
+
) : null,
|
|
303
|
+
metrics.memory ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
304
|
+
TimeseriesGauge.TimeseriesGauge,
|
|
305
|
+
{
|
|
306
|
+
title: metrics.memory.title ?? "Memory",
|
|
307
|
+
icon: metrics.memory.icon ?? UiMemoryStick.UiMemoryStick,
|
|
308
|
+
value: metrics.memory.value,
|
|
309
|
+
unit: metrics.memory.unit ?? "bytes",
|
|
310
|
+
expandable: false,
|
|
311
|
+
centerDisplay: metrics.memory.centerDisplay ?? "value",
|
|
312
|
+
variant: sizeClasses.metricVariant,
|
|
313
|
+
...metrics.memory.max !== void 0 ? { max: metrics.memory.max } : {},
|
|
314
|
+
...metrics.memory.thresholds ? { thresholds: metrics.memory.thresholds } : {},
|
|
315
|
+
...metricProps
|
|
316
|
+
}
|
|
317
|
+
) : null,
|
|
318
|
+
metrics.disk ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
319
|
+
TimeseriesGauge.TimeseriesGauge,
|
|
320
|
+
{
|
|
321
|
+
title: metrics.disk.title ?? "Disk",
|
|
322
|
+
icon: metrics.disk.icon ?? UiHardDrive.UiHardDrive,
|
|
323
|
+
value: metrics.disk.value,
|
|
324
|
+
unit: metrics.disk.unit ?? "bytes",
|
|
325
|
+
expandable: false,
|
|
326
|
+
centerDisplay: metrics.disk.centerDisplay ?? "value",
|
|
327
|
+
variant: sizeClasses.metricVariant,
|
|
328
|
+
...metrics.disk.max !== void 0 ? { max: metrics.disk.max } : {},
|
|
329
|
+
...metrics.disk.thresholds ? { thresholds: metrics.disk.thresholds } : {},
|
|
330
|
+
...metricProps
|
|
331
|
+
}
|
|
332
|
+
) : null
|
|
333
|
+
]
|
|
334
|
+
}
|
|
335
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
336
|
+
"div",
|
|
337
|
+
{
|
|
338
|
+
className: utils.cn(
|
|
339
|
+
"rounded-md border border-dashed border-border text-center text-muted-foreground",
|
|
340
|
+
sizeClasses.empty
|
|
341
|
+
),
|
|
342
|
+
children: "No metrics configured"
|
|
343
|
+
}
|
|
344
|
+
),
|
|
345
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
346
|
+
Modal.Modal,
|
|
347
|
+
{
|
|
348
|
+
open: expanded,
|
|
349
|
+
onClose: () => setExpanded(false),
|
|
350
|
+
title: `${workload.name} history`,
|
|
351
|
+
size: "xl",
|
|
352
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-3", children: panelMetrics.map(({ key, title, unit, icon, metric }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
353
|
+
TimeseriesPanel.TimeseriesPanel,
|
|
354
|
+
{
|
|
355
|
+
title,
|
|
356
|
+
icon,
|
|
357
|
+
series: metricSeries(metric),
|
|
358
|
+
...unit ? { unit } : {},
|
|
359
|
+
...metricProps,
|
|
360
|
+
expandable: false
|
|
361
|
+
},
|
|
362
|
+
key
|
|
363
|
+
)) })
|
|
364
|
+
}
|
|
365
|
+
)
|
|
366
|
+
]
|
|
367
|
+
}
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
exports.WorkloadCard = WorkloadCard;
|
|
371
|
+
//# sourceMappingURL=WorkloadCard.cjs.map
|