@flanksource/clicky-ui 0.3.37 → 0.3.39
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/README.md +36 -0
- package/dist/data/TimeseriesCoreBars.cjs +10 -36
- package/dist/data/TimeseriesCoreBars.cjs.map +1 -1
- package/dist/data/TimeseriesCoreBars.d.ts +1 -1
- package/dist/data/TimeseriesCoreBars.d.ts.map +1 -1
- package/dist/data/TimeseriesCoreBars.js +8 -34
- package/dist/data/TimeseriesCoreBars.js.map +1 -1
- package/dist/data/TimeseriesGauge.cjs +12 -36
- package/dist/data/TimeseriesGauge.cjs.map +1 -1
- package/dist/data/TimeseriesGauge.d.ts +14 -4
- package/dist/data/TimeseriesGauge.d.ts.map +1 -1
- package/dist/data/TimeseriesGauge.js +10 -34
- package/dist/data/TimeseriesGauge.js.map +1 -1
- package/dist/data/TimeseriesPanel.cjs +82 -39
- package/dist/data/TimeseriesPanel.cjs.map +1 -1
- package/dist/data/TimeseriesPanel.d.ts +1 -1
- package/dist/data/TimeseriesPanel.d.ts.map +1 -1
- package/dist/data/TimeseriesPanel.js +82 -39
- package/dist/data/TimeseriesPanel.js.map +1 -1
- package/dist/data/TimeseriesPanel.model.cjs +1 -0
- package/dist/data/TimeseriesPanel.model.cjs.map +1 -1
- package/dist/data/TimeseriesPanel.model.d.ts +38 -2
- package/dist/data/TimeseriesPanel.model.d.ts.map +1 -1
- package/dist/data/TimeseriesPanel.model.js +1 -0
- package/dist/data/TimeseriesPanel.model.js.map +1 -1
- package/dist/data/WorkloadCard.cjs +67 -31
- package/dist/data/WorkloadCard.cjs.map +1 -1
- package/dist/data/WorkloadCard.d.ts +19 -6
- package/dist/data/WorkloadCard.d.ts.map +1 -1
- package/dist/data/WorkloadCard.js +69 -33
- package/dist/data/WorkloadCard.js.map +1 -1
- package/dist/data/WorkloadCard.model.cjs +16 -10
- package/dist/data/WorkloadCard.model.cjs.map +1 -1
- package/dist/data/WorkloadCard.model.d.ts +29 -1
- package/dist/data/WorkloadCard.model.d.ts.map +1 -1
- package/dist/data/WorkloadCard.model.js +17 -11
- package/dist/data/WorkloadCard.model.js.map +1 -1
- package/dist/data/timeseries-query.cjs +51 -0
- package/dist/data/timeseries-query.cjs.map +1 -0
- package/dist/data/timeseries-query.d.ts +31 -0
- package/dist/data/timeseries-query.d.ts.map +1 -0
- package/dist/data/timeseries-query.js +51 -0
- package/dist/data/timeseries-query.js.map +1 -0
- package/dist/data/version-info.cjs +3 -3
- package/dist/data/version-info.js +3 -3
- package/dist/data.cjs +1 -0
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.ts +2 -2
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +3 -2
- package/dist/index.cjs +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -1
- package/package.json +1 -1
|
@@ -1,12 +1,20 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
1
2
|
import { TimeseriesResponse } from './TimeseriesPanel';
|
|
2
3
|
import { WorkloadCardMetrics, WorkloadCardWorkload } from './WorkloadCard.model';
|
|
3
4
|
export interface WorkloadCardProps {
|
|
4
5
|
workload: WorkloadCardWorkload;
|
|
6
|
+
/**
|
|
7
|
+
* CPU/memory/disk series. Each is requested as `baseUrl + id` via `fetcher`,
|
|
8
|
+
* or loaded by its own `load` function (then `id` is the cache key and must
|
|
9
|
+
* be unique per data source).
|
|
10
|
+
*/
|
|
5
11
|
metrics: WorkloadCardMetrics;
|
|
6
12
|
baseUrl?: string;
|
|
7
13
|
range?: string;
|
|
8
14
|
refreshMs?: number;
|
|
9
15
|
expandable?: boolean;
|
|
16
|
+
/** Controls rendered beside status and history, owned by the host domain. */
|
|
17
|
+
headerActions?: ReactNode;
|
|
10
18
|
size?: WorkloadCardSize;
|
|
11
19
|
variant?: WorkloadCardVariant;
|
|
12
20
|
fetcher?: (url: string) => Promise<TimeseriesResponse>;
|
|
@@ -15,11 +23,16 @@ export interface WorkloadCardProps {
|
|
|
15
23
|
export type WorkloadCardSize = "sm" | "md" | "lg";
|
|
16
24
|
export type WorkloadCardVariant = "default" | "outline" | "subtle" | "elevated" | "ghost";
|
|
17
25
|
/**
|
|
18
|
-
* WorkloadCard is a compact resource card for
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
26
|
+
* WorkloadCard is a compact resource card for a workload: a Kubernetes
|
|
27
|
+
* resource (`kind`) or anything else (a free-form `type`, `icon` and
|
|
28
|
+
* `metadata`). It shows identity, status, subtitle metadata, and
|
|
29
|
+
* CPU/memory/disk utilization backed by the existing time-series primitives:
|
|
30
|
+
* CPU and memory as core-style bars (memory at one bar per GiB) and disk as a
|
|
31
|
+
* linear progress bar. Callers own the metric series (URL ids or `load`
|
|
32
|
+
* functions); the card only composes them.
|
|
33
|
+
*
|
|
34
|
+
* Like the timeseries widgets it renders, it needs a react-query
|
|
35
|
+
* `QueryClientProvider` above it.
|
|
23
36
|
*/
|
|
24
|
-
export declare function WorkloadCard({ workload, metrics, baseUrl, range, refreshMs, expandable, size, variant, fetcher, className, }: WorkloadCardProps): import("react").JSX.Element;
|
|
37
|
+
export declare function WorkloadCard({ workload, metrics, baseUrl, range, refreshMs, expandable, headerActions, size, variant, fetcher, className, }: WorkloadCardProps): import("react").JSX.Element;
|
|
25
38
|
//# sourceMappingURL=WorkloadCard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkloadCard.d.ts","sourceRoot":"","sources":["../../src/data/WorkloadCard.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WorkloadCard.d.ts","sourceRoot":"","sources":["../../src/data/WorkloadCard.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAe1D,OAAO,EAGL,KAAK,kBAAkB,EAExB,MAAM,mBAAmB,CAAC;AAQ3B,OAAO,EAOL,KAAK,mBAAmB,EAExB,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,oBAAoB,CAAC;IAC/B;;;;OAIG;IACH,OAAO,EAAE,mBAAmB,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,gBAAgB,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAClD,MAAM,MAAM,mBAAmB,GAC3B,SAAS,GACT,SAAS,GACT,QAAQ,GACR,UAAU,GACV,OAAO,CAAC;AA2MZ;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,OAAO,EACP,OAAO,EACP,KAAY,EACZ,SAAgB,EAChB,UAAiB,EACjB,aAAa,EACb,IAAW,EACX,OAAmB,EACnB,OAAO,EACP,SAAS,GACV,EAAE,iBAAiB,+BA2OnB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsxs, jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useMemo } from "react";
|
|
3
3
|
import { K8SPod, K8SStatefulset, K8SDeployment, K8SIngress, K8SService } from "@flanksource/icons/mi";
|
|
4
4
|
import { cn } from "../lib/utils.js";
|
|
@@ -9,7 +9,8 @@ import { Icon } from "./Icon.js";
|
|
|
9
9
|
import { TimeseriesCoreBars } from "./TimeseriesCoreBars.js";
|
|
10
10
|
import { TimeseriesGauge } from "./TimeseriesGauge.js";
|
|
11
11
|
import { TimeseriesPanel } from "./TimeseriesPanel.js";
|
|
12
|
-
import {
|
|
12
|
+
import { workloadTypeLabel, workloadStatusLabel, workloadStatusTone, formatReplicaCounts } from "./WorkloadCard.model.js";
|
|
13
|
+
import { UiBox } from "../icons/components/UiBox.js";
|
|
13
14
|
import { UiChip } from "../icons/components/UiChip.js";
|
|
14
15
|
import { UiMemoryStick } from "../icons/components/UiMemoryStick.js";
|
|
15
16
|
import { UiHardDrive } from "../icons/components/UiHardDrive.js";
|
|
@@ -77,7 +78,7 @@ function metricGridClass(count) {
|
|
|
77
78
|
if (count === 2) return "grid-cols-2";
|
|
78
79
|
return "grid-cols-3";
|
|
79
80
|
}
|
|
80
|
-
const MEMORY_BAR_UNIT = { perBar: 1024 ** 3, label: "
|
|
81
|
+
const MEMORY_BAR_UNIT = { perBar: 1024 ** 3, label: "GiB", barLabel: "GiB" };
|
|
81
82
|
function WorkloadIcon({
|
|
82
83
|
icon,
|
|
83
84
|
title,
|
|
@@ -90,36 +91,69 @@ function WorkloadIcon({
|
|
|
90
91
|
}
|
|
91
92
|
function metricSeries(metric) {
|
|
92
93
|
const series = [
|
|
93
|
-
{
|
|
94
|
-
id: metric.value.id,
|
|
95
|
-
label: metric.valueLabel ?? "usage",
|
|
96
|
-
...metric.value.transform ? { transform: metric.value.transform } : {}
|
|
97
|
-
}
|
|
94
|
+
{ ...metric.value, label: metric.valueLabel ?? "usage" }
|
|
98
95
|
];
|
|
99
96
|
if (typeof metric.max === "object") {
|
|
100
|
-
series.push({
|
|
101
|
-
id: metric.max.id,
|
|
102
|
-
label: metric.maxLabel ?? "limit",
|
|
103
|
-
...metric.max.transform ? { transform: metric.max.transform } : {}
|
|
104
|
-
});
|
|
97
|
+
series.push({ ...metric.max, label: metric.maxLabel ?? "limit" });
|
|
105
98
|
}
|
|
106
99
|
return series;
|
|
107
100
|
}
|
|
101
|
+
function metricReferenceLines(metric) {
|
|
102
|
+
if (typeof metric.max !== "number") return [];
|
|
103
|
+
return [{ value: metric.max, label: metric.maxLabel ?? "capacity" }];
|
|
104
|
+
}
|
|
108
105
|
function hasMetric(metrics) {
|
|
109
106
|
return Boolean(metrics.cpu || metrics.memory || metrics.disk);
|
|
110
107
|
}
|
|
111
|
-
function HeaderMeta({
|
|
112
|
-
|
|
113
|
-
|
|
108
|
+
function HeaderMeta({
|
|
109
|
+
separator,
|
|
110
|
+
title,
|
|
111
|
+
children
|
|
112
|
+
}) {
|
|
113
|
+
return /* @__PURE__ */ jsxs("span", { className: "inline-flex min-w-0 items-center gap-1", title, children: [
|
|
114
|
+
separator ? /* @__PURE__ */ jsx(
|
|
114
115
|
"span",
|
|
115
116
|
{
|
|
116
117
|
className: "h-1 w-1 shrink-0 rounded-full bg-muted-foreground/40",
|
|
117
118
|
"aria-hidden": true
|
|
118
119
|
}
|
|
119
|
-
),
|
|
120
|
+
) : null,
|
|
120
121
|
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children })
|
|
121
122
|
] });
|
|
122
123
|
}
|
|
124
|
+
function headerMetaItems(workload, typeLabel) {
|
|
125
|
+
var _a;
|
|
126
|
+
const items = [];
|
|
127
|
+
if (typeLabel) items.push({ key: "type", content: typeLabel });
|
|
128
|
+
if (workload.namespace) {
|
|
129
|
+
items.push({ key: "namespace", content: workload.namespace });
|
|
130
|
+
}
|
|
131
|
+
if (workload.role) items.push({ key: "role", content: workload.role });
|
|
132
|
+
const replicaText = formatReplicaCounts(workload.replicas);
|
|
133
|
+
if (replicaText) items.push({ key: "replicas", content: replicaText });
|
|
134
|
+
if (workload.createdAt !== void 0) {
|
|
135
|
+
items.push({
|
|
136
|
+
key: "age",
|
|
137
|
+
content: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
138
|
+
"age ",
|
|
139
|
+
/* @__PURE__ */ jsx(Timestamp, { value: workload.createdAt, format: "relative" })
|
|
140
|
+
] })
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
(_a = workload.metadata) == null ? void 0 : _a.forEach((item, i) => {
|
|
144
|
+
const plain = typeof item.value === "string" || typeof item.value === "number";
|
|
145
|
+
items.push({
|
|
146
|
+
key: `meta-${i}`,
|
|
147
|
+
content: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
148
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground/70", children: item.label }),
|
|
149
|
+
" ",
|
|
150
|
+
item.value
|
|
151
|
+
] }),
|
|
152
|
+
title: plain ? `${item.label}: ${item.value}` : item.label
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
return items;
|
|
156
|
+
}
|
|
123
157
|
function WorkloadCard({
|
|
124
158
|
workload,
|
|
125
159
|
metrics,
|
|
@@ -127,6 +161,7 @@ function WorkloadCard({
|
|
|
127
161
|
range = "1h",
|
|
128
162
|
refreshMs = 5e3,
|
|
129
163
|
expandable = true,
|
|
164
|
+
headerActions,
|
|
130
165
|
size = "md",
|
|
131
166
|
variant = "default",
|
|
132
167
|
fetcher,
|
|
@@ -134,10 +169,10 @@ function WorkloadCard({
|
|
|
134
169
|
}) {
|
|
135
170
|
var _a;
|
|
136
171
|
const [expanded, setExpanded] = useState(false);
|
|
137
|
-
const
|
|
172
|
+
const typeLabel = workloadTypeLabel(workload);
|
|
138
173
|
const statusLabel = workloadStatusLabel(workload.status);
|
|
139
|
-
const
|
|
140
|
-
const workloadIcon = workload.icon ?? KIND_ICONS[workload.kind];
|
|
174
|
+
const metaItems = headerMetaItems(workload, typeLabel);
|
|
175
|
+
const workloadIcon = workload.icon ?? (workload.kind ? KIND_ICONS[workload.kind] : UiBox);
|
|
141
176
|
const sizeClasses = SIZE_CLASSES[size];
|
|
142
177
|
const panelMetrics = useMemo(() => {
|
|
143
178
|
const list = [];
|
|
@@ -204,7 +239,7 @@ function WorkloadCard({
|
|
|
204
239
|
WorkloadIcon,
|
|
205
240
|
{
|
|
206
241
|
icon: workloadIcon,
|
|
207
|
-
title:
|
|
242
|
+
title: typeLabel ?? workload.name,
|
|
208
243
|
className: cn("shrink-0 text-muted-foreground", sizeClasses.icon)
|
|
209
244
|
}
|
|
210
245
|
),
|
|
@@ -219,25 +254,24 @@ function WorkloadCard({
|
|
|
219
254
|
]
|
|
220
255
|
}
|
|
221
256
|
),
|
|
222
|
-
/* @__PURE__ */
|
|
257
|
+
metaItems.length > 0 ? /* @__PURE__ */ jsx(
|
|
223
258
|
"div",
|
|
224
259
|
{
|
|
225
260
|
className: cn(
|
|
226
261
|
"flex flex-wrap items-center text-muted-foreground",
|
|
227
262
|
sizeClasses.meta
|
|
228
263
|
),
|
|
229
|
-
children:
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
]
|
|
264
|
+
children: metaItems.map((item, i) => /* @__PURE__ */ jsx(
|
|
265
|
+
HeaderMeta,
|
|
266
|
+
{
|
|
267
|
+
separator: i > 0,
|
|
268
|
+
title: item.title,
|
|
269
|
+
children: item.content
|
|
270
|
+
},
|
|
271
|
+
item.key
|
|
272
|
+
))
|
|
239
273
|
}
|
|
240
|
-
)
|
|
274
|
+
) : null
|
|
241
275
|
] }),
|
|
242
276
|
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
243
277
|
statusLabel ? /* @__PURE__ */ jsx("span", { title: (_a = workload.status) == null ? void 0 : _a.message, children: /* @__PURE__ */ jsx(
|
|
@@ -249,6 +283,7 @@ function WorkloadCard({
|
|
|
249
283
|
children: statusLabel
|
|
250
284
|
}
|
|
251
285
|
) }) : null,
|
|
286
|
+
headerActions,
|
|
252
287
|
canExpand ? /* @__PURE__ */ jsx(
|
|
253
288
|
"button",
|
|
254
289
|
{
|
|
@@ -353,6 +388,7 @@ function WorkloadCard({
|
|
|
353
388
|
title,
|
|
354
389
|
icon,
|
|
355
390
|
series: metricSeries(metric),
|
|
391
|
+
referenceLines: metricReferenceLines(metric),
|
|
356
392
|
...unit ? { unit } : {},
|
|
357
393
|
...metricProps,
|
|
358
394
|
expandable: false
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkloadCard.js","sources":["../../src/data/WorkloadCard.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from \"react\";\nimport {\n K8SDeployment,\n K8SIngress,\n K8SPod,\n K8SService,\n K8SStatefulset,\n} from \"@flanksource/icons/mi\";\nimport { cn } from \"../lib/utils\";\nimport { Modal } from \"../overlay/Modal\";\nimport { Badge } from \"./Badge\";\nimport { Timestamp } from \"./cells/Timestamp\";\nimport { Icon, type StaticIconComponent } from \"./Icon\";\nimport { TimeseriesCoreBars } from \"./TimeseriesCoreBars\";\nimport { TimeseriesGauge } from \"./TimeseriesGauge\";\nimport {\n TimeseriesPanel,\n type TimeseriesResponse,\n type TimeseriesSeries,\n} from \"./TimeseriesPanel\";\nimport { UiChip, UiFullscreen, UiHardDrive, UiMemoryStick } from \"../icons\";\nimport {\n formatReplicaCounts,\n workloadKindLabel,\n workloadStatusLabel,\n workloadStatusTone,\n type WorkloadCardIcon,\n type WorkloadCardKind,\n type WorkloadCardMetrics,\n type WorkloadCardResourceMetric,\n type WorkloadCardWorkload,\n} from \"./WorkloadCard.model\";\n\nexport interface WorkloadCardProps {\n workload: WorkloadCardWorkload;\n metrics: WorkloadCardMetrics;\n baseUrl?: string;\n range?: string;\n refreshMs?: number;\n expandable?: boolean;\n size?: WorkloadCardSize;\n variant?: WorkloadCardVariant;\n fetcher?: (url: string) => Promise<TimeseriesResponse>;\n className?: string;\n}\n\nexport type WorkloadCardSize = \"sm\" | \"md\" | \"lg\";\nexport type WorkloadCardVariant =\n | \"default\"\n | \"outline\"\n | \"subtle\"\n | \"elevated\"\n | \"ghost\";\n\ntype MetricKey = keyof WorkloadCardMetrics;\n\ntype PanelMetric = {\n key: MetricKey;\n title: string;\n unit?: string;\n icon: WorkloadCardIcon;\n metric: WorkloadCardResourceMetric;\n};\n\nconst KIND_ICONS: Record<WorkloadCardKind, StaticIconComponent> = {\n service: K8SService,\n ingress: K8SIngress,\n deployment: K8SDeployment,\n statefulset: K8SStatefulset,\n pod: K8SPod,\n};\n\ntype WorkloadCardSizeClasses = {\n root: string;\n header: string;\n titleGap: string;\n icon: string;\n name: string;\n meta: string;\n statusSize: \"xxs\" | \"xs\" | \"sm\";\n action: string;\n actionIcon: number;\n metricGrid: string;\n metricVariant: \"default\" | \"cell\";\n empty: string;\n};\n\nconst SIZE_CLASSES: Record<WorkloadCardSize, WorkloadCardSizeClasses> = {\n sm: {\n root: \"p-2\",\n header: \"mb-2 gap-2\",\n titleGap: \"gap-1\",\n icon: \"h-3.5 w-3.5\",\n name: \"text-xs\",\n meta: \"mt-0.5 gap-x-1.5 gap-y-0.5 text-[11px] leading-4\",\n statusSize: \"xxs\",\n action: \"h-5 w-5\",\n actionIcon: 12,\n metricGrid: \"grid-cols-1 gap-1.5\",\n metricVariant: \"cell\",\n empty: \"px-2 py-3 text-[11px]\",\n },\n md: {\n root: \"p-3\",\n header: \"mb-3 gap-2\",\n titleGap: \"gap-1.5\",\n icon: \"h-4 w-4\",\n name: \"text-sm\",\n meta: \"mt-0.5 gap-x-2 gap-y-0.5 text-xs\",\n statusSize: \"xs\",\n action: \"h-6 w-6\",\n actionIcon: 14,\n metricGrid: \"gap-3\",\n metricVariant: \"default\",\n empty: \"px-3 py-4 text-xs\",\n },\n lg: {\n root: \"p-4\",\n header: \"mb-4 gap-3\",\n titleGap: \"gap-2\",\n icon: \"h-5 w-5\",\n name: \"text-base\",\n meta: \"mt-1 gap-x-2 gap-y-1 text-xs\",\n statusSize: \"sm\",\n action: \"h-7 w-7\",\n actionIcon: 16,\n metricGrid: \"gap-4\",\n metricVariant: \"default\",\n empty: \"px-4 py-6 text-sm\",\n },\n};\n\nconst VARIANT_CLASSES: Record<WorkloadCardVariant, string> = {\n default: \"border-border bg-card text-card-foreground\",\n outline: \"border-border bg-background text-foreground\",\n subtle: \"border-transparent bg-muted/35 text-foreground\",\n elevated: \"border-border/70 bg-card text-card-foreground shadow-sm\",\n ghost: \"border-transparent bg-transparent text-foreground\",\n};\n\nfunction metricGridClass(count: number): string {\n if (count <= 1) return \"grid-cols-1\";\n if (count === 2) return \"grid-cols-2\";\n return \"grid-cols-3\";\n}\n\n// Memory renders as cores-style bars at one bar per gigabyte, matching CPU; bytes\n// are fed raw and TimeseriesCoreBars divides by perBar so captions read \"x GB\".\nconst MEMORY_BAR_UNIT = { perBar: 1024 ** 3, label: \"GB\", barLabel: \"GB\" };\n\nfunction WorkloadIcon({\n icon,\n title,\n className,\n}: {\n icon: WorkloadCardIcon;\n title: string;\n className?: string;\n}) {\n if (typeof icon === \"string\") {\n return (\n <Icon name={icon} title={title} {...(className ? { className } : {})} />\n );\n }\n return (\n <Icon icon={icon} title={title} {...(className ? { className } : {})} />\n );\n}\n\nfunction metricSeries(metric: WorkloadCardResourceMetric): TimeseriesSeries[] {\n const series: TimeseriesSeries[] = [\n {\n id: metric.value.id,\n label: metric.valueLabel ?? \"usage\",\n ...(metric.value.transform ? { transform: metric.value.transform } : {}),\n },\n ];\n if (typeof metric.max === \"object\") {\n series.push({\n id: metric.max.id,\n label: metric.maxLabel ?? \"limit\",\n ...(metric.max.transform ? { transform: metric.max.transform } : {}),\n });\n }\n return series;\n}\n\nfunction hasMetric(metrics: WorkloadCardMetrics): boolean {\n return Boolean(metrics.cpu || metrics.memory || metrics.disk);\n}\n\nfunction HeaderMeta({ children }: { children: ReactNode }) {\n return (\n <span className=\"inline-flex min-w-0 items-center gap-1\">\n <span\n className=\"h-1 w-1 shrink-0 rounded-full bg-muted-foreground/40\"\n aria-hidden\n />\n <span className=\"min-w-0 truncate\">{children}</span>\n </span>\n );\n}\n\n/**\n * WorkloadCard is a compact resource card for Kubernetes-style workloads. It\n * shows workload identity, status, replica/age metadata, and CPU/memory/disk\n * utilization backed by the existing time-series primitives: CPU and memory as\n * core-style bars (memory at one bar per GB) and disk as a linear progress bar.\n * Callers own the metric ids; the card only composes the supplied series.\n */\nexport function WorkloadCard({\n workload,\n metrics,\n baseUrl,\n range = \"1h\",\n refreshMs = 5000,\n expandable = true,\n size = \"md\",\n variant = \"default\",\n fetcher,\n className,\n}: WorkloadCardProps) {\n const [expanded, setExpanded] = useState(false);\n const kindLabel = workloadKindLabel(workload.kind);\n const statusLabel = workloadStatusLabel(workload.status);\n const replicaText = formatReplicaCounts(workload.replicas);\n const workloadIcon = workload.icon ?? KIND_ICONS[workload.kind];\n const sizeClasses = SIZE_CLASSES[size];\n\n const panelMetrics = useMemo(() => {\n const list: PanelMetric[] = [];\n if (metrics.cpu) {\n list.push({\n key: \"cpu\",\n title: metrics.cpu.title ?? \"CPU\",\n unit: metrics.cpu.unit ?? \"short\",\n icon: metrics.cpu.icon ?? UiChip,\n metric: metrics.cpu,\n });\n }\n if (metrics.memory) {\n list.push({\n key: \"memory\",\n title: metrics.memory.title ?? \"Memory\",\n unit: metrics.memory.unit ?? \"bytes\",\n icon: metrics.memory.icon ?? UiMemoryStick,\n metric: metrics.memory,\n });\n }\n if (metrics.disk) {\n list.push({\n key: \"disk\",\n title: metrics.disk.title ?? \"Disk\",\n unit: metrics.disk.unit ?? \"bytes\",\n icon: metrics.disk.icon ?? UiHardDrive,\n metric: metrics.disk,\n });\n }\n return list;\n }, [metrics]);\n\n const metricProps = {\n ...(baseUrl !== undefined ? { baseUrl } : {}),\n range,\n refreshMs,\n ...(fetcher !== undefined ? { fetcher } : {}),\n };\n const canExpand = expandable && hasMetric(metrics);\n\n return (\n <div\n className={cn(\n \"w-full rounded-md border\",\n VARIANT_CLASSES[variant],\n sizeClasses.root,\n className,\n )}\n data-size={size}\n data-variant={variant}\n >\n <div\n className={cn(\"flex items-start justify-between\", sizeClasses.header)}\n >\n <div className=\"min-w-0\">\n <div\n className={cn(\"flex min-w-0 items-center\", sizeClasses.titleGap)}\n >\n <WorkloadIcon\n icon={workloadIcon}\n title={kindLabel}\n className={cn(\"shrink-0 text-muted-foreground\", sizeClasses.icon)}\n />\n <span\n className={cn(\"min-w-0 truncate font-medium\", sizeClasses.name)}\n title={workload.name}\n >\n {workload.name}\n </span>\n </div>\n <div\n className={cn(\n \"flex flex-wrap items-center text-muted-foreground\",\n sizeClasses.meta,\n )}\n >\n <span>{kindLabel}</span>\n {workload.namespace ? (\n <HeaderMeta>{workload.namespace}</HeaderMeta>\n ) : null}\n {workload.role ? <HeaderMeta>{workload.role}</HeaderMeta> : null}\n {replicaText ? <HeaderMeta>{replicaText}</HeaderMeta> : null}\n {workload.createdAt !== undefined ? (\n <HeaderMeta>\n age <Timestamp value={workload.createdAt} format=\"relative\" />\n </HeaderMeta>\n ) : null}\n </div>\n </div>\n <div className=\"flex shrink-0 items-center gap-1\">\n {statusLabel ? (\n <span title={workload.status?.message}>\n <Badge\n tone={workloadStatusTone(workload.status)}\n variant=\"soft\"\n size={sizeClasses.statusSize}\n >\n {statusLabel}\n </Badge>\n </span>\n ) : null}\n {canExpand ? (\n <button\n type=\"button\"\n aria-label={`Open ${workload.name} history`}\n title=\"History\"\n onClick={() => setExpanded(true)}\n className={cn(\n \"inline-flex items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\",\n sizeClasses.action,\n )}\n >\n <Icon\n icon={UiFullscreen}\n width={sizeClasses.actionIcon}\n height={sizeClasses.actionIcon}\n />\n </button>\n ) : null}\n </div>\n </div>\n\n {hasMetric(metrics) ? (\n <div\n className={cn(\n \"grid items-start gap-3\",\n sizeClasses.metricVariant === \"cell\"\n ? sizeClasses.metricGrid\n : cn(\n metricGridClass(panelMetrics.length),\n sizeClasses.metricGrid,\n ),\n )}\n >\n {metrics.cpu ? (\n <TimeseriesCoreBars\n title={metrics.cpu.title ?? \"CPU\"}\n icon={metrics.cpu.icon ?? UiChip}\n value={metrics.cpu.value}\n {...(metrics.cpu.max !== undefined\n ? { max: metrics.cpu.max }\n : {})}\n {...(metrics.cpu.thresholds\n ? { thresholds: metrics.cpu.thresholds }\n : {})}\n {...(metrics.cpu.orientation\n ? { orientation: metrics.cpu.orientation }\n : {})}\n {...(metrics.cpu.showValue !== undefined\n ? { showValue: metrics.cpu.showValue }\n : {})}\n variant={sizeClasses.metricVariant}\n {...metricProps}\n />\n ) : null}\n {metrics.memory ? (\n <TimeseriesCoreBars\n title={metrics.memory.title ?? \"Memory\"}\n icon={metrics.memory.icon ?? UiMemoryStick}\n value={metrics.memory.value}\n unit={MEMORY_BAR_UNIT}\n variant={sizeClasses.metricVariant}\n {...(metrics.memory.max !== undefined\n ? { max: metrics.memory.max }\n : {})}\n {...(metrics.memory.thresholds\n ? { thresholds: metrics.memory.thresholds }\n : {})}\n {...metricProps}\n />\n ) : null}\n {metrics.disk ? (\n <TimeseriesGauge\n title={metrics.disk.title ?? \"Disk\"}\n icon={metrics.disk.icon ?? UiHardDrive}\n value={metrics.disk.value}\n unit={metrics.disk.unit ?? \"bytes\"}\n shape=\"linear\"\n expandable={false}\n centerDisplay={metrics.disk.centerDisplay ?? \"value\"}\n variant={sizeClasses.metricVariant}\n {...(metrics.disk.max !== undefined\n ? { max: metrics.disk.max }\n : {})}\n {...(metrics.disk.thresholds\n ? { thresholds: metrics.disk.thresholds }\n : {})}\n {...metricProps}\n />\n ) : null}\n </div>\n ) : (\n <div\n className={cn(\n \"rounded-md border border-dashed border-border text-center text-muted-foreground\",\n sizeClasses.empty,\n )}\n >\n No metrics configured\n </div>\n )}\n\n <Modal\n open={expanded}\n onClose={() => setExpanded(false)}\n title={`${workload.name} history`}\n size=\"xl\"\n >\n <div className=\"flex flex-col gap-3\">\n {panelMetrics.map(({ key, title, unit, icon, metric }) => (\n <TimeseriesPanel\n key={key}\n title={title}\n icon={icon}\n series={metricSeries(metric)}\n {...(unit ? { unit } : {})}\n {...metricProps}\n expandable={false}\n />\n ))}\n </div>\n </Modal>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkloadCard.js","sources":["../../src/data/WorkloadCard.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from \"react\";\nimport {\n K8SDeployment,\n K8SIngress,\n K8SPod,\n K8SService,\n K8SStatefulset,\n} from \"@flanksource/icons/mi\";\nimport { cn } from \"../lib/utils\";\nimport { Modal } from \"../overlay/Modal\";\nimport { Badge } from \"./Badge\";\nimport { Timestamp } from \"./cells/Timestamp\";\nimport { Icon, type StaticIconComponent } from \"./Icon\";\nimport { TimeseriesCoreBars } from \"./TimeseriesCoreBars\";\nimport { TimeseriesGauge } from \"./TimeseriesGauge\";\nimport {\n TimeseriesPanel,\n type TimeseriesReferenceLine,\n type TimeseriesResponse,\n type TimeseriesSeries,\n} from \"./TimeseriesPanel\";\nimport {\n UiBox,\n UiChip,\n UiFullscreen,\n UiHardDrive,\n UiMemoryStick,\n} from \"../icons\";\nimport {\n formatReplicaCounts,\n workloadStatusLabel,\n workloadStatusTone,\n workloadTypeLabel,\n type WorkloadCardIcon,\n type WorkloadCardKind,\n type WorkloadCardMetrics,\n type WorkloadCardResourceMetric,\n type WorkloadCardWorkload,\n} from \"./WorkloadCard.model\";\n\nexport interface WorkloadCardProps {\n workload: WorkloadCardWorkload;\n /**\n * CPU/memory/disk series. Each is requested as `baseUrl + id` via `fetcher`,\n * or loaded by its own `load` function (then `id` is the cache key and must\n * be unique per data source).\n */\n metrics: WorkloadCardMetrics;\n baseUrl?: string;\n range?: string;\n refreshMs?: number;\n expandable?: boolean;\n /** Controls rendered beside status and history, owned by the host domain. */\n headerActions?: ReactNode;\n size?: WorkloadCardSize;\n variant?: WorkloadCardVariant;\n fetcher?: (url: string) => Promise<TimeseriesResponse>;\n className?: string;\n}\n\nexport type WorkloadCardSize = \"sm\" | \"md\" | \"lg\";\nexport type WorkloadCardVariant =\n | \"default\"\n | \"outline\"\n | \"subtle\"\n | \"elevated\"\n | \"ghost\";\n\ntype MetricKey = keyof WorkloadCardMetrics;\n\ntype PanelMetric = {\n key: MetricKey;\n title: string;\n unit?: string;\n icon: WorkloadCardIcon;\n metric: WorkloadCardResourceMetric;\n};\n\nconst KIND_ICONS: Record<WorkloadCardKind, StaticIconComponent> = {\n service: K8SService,\n ingress: K8SIngress,\n deployment: K8SDeployment,\n statefulset: K8SStatefulset,\n pod: K8SPod,\n};\n\ntype WorkloadCardSizeClasses = {\n root: string;\n header: string;\n titleGap: string;\n icon: string;\n name: string;\n meta: string;\n statusSize: \"xxs\" | \"xs\" | \"sm\";\n action: string;\n actionIcon: number;\n metricGrid: string;\n metricVariant: \"default\" | \"cell\";\n empty: string;\n};\n\nconst SIZE_CLASSES: Record<WorkloadCardSize, WorkloadCardSizeClasses> = {\n sm: {\n root: \"p-2\",\n header: \"mb-2 gap-2\",\n titleGap: \"gap-1\",\n icon: \"h-3.5 w-3.5\",\n name: \"text-xs\",\n meta: \"mt-0.5 gap-x-1.5 gap-y-0.5 text-[11px] leading-4\",\n statusSize: \"xxs\",\n action: \"h-5 w-5\",\n actionIcon: 12,\n metricGrid: \"grid-cols-1 gap-1.5\",\n metricVariant: \"cell\",\n empty: \"px-2 py-3 text-[11px]\",\n },\n md: {\n root: \"p-3\",\n header: \"mb-3 gap-2\",\n titleGap: \"gap-1.5\",\n icon: \"h-4 w-4\",\n name: \"text-sm\",\n meta: \"mt-0.5 gap-x-2 gap-y-0.5 text-xs\",\n statusSize: \"xs\",\n action: \"h-6 w-6\",\n actionIcon: 14,\n metricGrid: \"gap-3\",\n metricVariant: \"default\",\n empty: \"px-3 py-4 text-xs\",\n },\n lg: {\n root: \"p-4\",\n header: \"mb-4 gap-3\",\n titleGap: \"gap-2\",\n icon: \"h-5 w-5\",\n name: \"text-base\",\n meta: \"mt-1 gap-x-2 gap-y-1 text-xs\",\n statusSize: \"sm\",\n action: \"h-7 w-7\",\n actionIcon: 16,\n metricGrid: \"gap-4\",\n metricVariant: \"default\",\n empty: \"px-4 py-6 text-sm\",\n },\n};\n\nconst VARIANT_CLASSES: Record<WorkloadCardVariant, string> = {\n default: \"border-border bg-card text-card-foreground\",\n outline: \"border-border bg-background text-foreground\",\n subtle: \"border-transparent bg-muted/35 text-foreground\",\n elevated: \"border-border/70 bg-card text-card-foreground shadow-sm\",\n ghost: \"border-transparent bg-transparent text-foreground\",\n};\n\nfunction metricGridClass(count: number): string {\n if (count <= 1) return \"grid-cols-1\";\n if (count === 2) return \"grid-cols-2\";\n return \"grid-cols-3\";\n}\n\n// Memory renders as cores-style bars at one bar per gibibyte, matching CPU; bytes\n// are fed raw and TimeseriesCoreBars divides by perBar so captions read \"x GiB\".\nconst MEMORY_BAR_UNIT = { perBar: 1024 ** 3, label: \"GiB\", barLabel: \"GiB\" };\n\nfunction WorkloadIcon({\n icon,\n title,\n className,\n}: {\n icon: WorkloadCardIcon;\n title: string;\n className?: string;\n}) {\n if (typeof icon === \"string\") {\n return (\n <Icon name={icon} title={title} {...(className ? { className } : {})} />\n );\n }\n return (\n <Icon icon={icon} title={title} {...(className ? { className } : {})} />\n );\n}\n\nfunction metricSeries(metric: WorkloadCardResourceMetric): TimeseriesSeries[] {\n const series: TimeseriesSeries[] = [\n { ...metric.value, label: metric.valueLabel ?? \"usage\" },\n ];\n if (typeof metric.max === \"object\") {\n series.push({ ...metric.max, label: metric.maxLabel ?? \"limit\" });\n }\n return series;\n}\n\n// A fixed numeric max has no series to plot, so the history chart draws it as\n// a flat capacity line instead.\nfunction metricReferenceLines(\n metric: WorkloadCardResourceMetric,\n): TimeseriesReferenceLine[] {\n if (typeof metric.max !== \"number\") return [];\n return [{ value: metric.max, label: metric.maxLabel ?? \"capacity\" }];\n}\n\nfunction hasMetric(metrics: WorkloadCardMetrics): boolean {\n return Boolean(metrics.cpu || metrics.memory || metrics.disk);\n}\n\ntype HeaderMetaItem = { key: string; content: ReactNode; title?: string };\n\nfunction HeaderMeta({\n separator,\n title,\n children,\n}: {\n separator: boolean;\n title?: string | undefined;\n children: ReactNode;\n}) {\n return (\n <span className=\"inline-flex min-w-0 items-center gap-1\" title={title}>\n {separator ? (\n <span\n className=\"h-1 w-1 shrink-0 rounded-full bg-muted-foreground/40\"\n aria-hidden\n />\n ) : null}\n <span className=\"min-w-0 truncate\">{children}</span>\n </span>\n );\n}\n\nfunction headerMetaItems(\n workload: WorkloadCardWorkload,\n typeLabel: string | undefined,\n): HeaderMetaItem[] {\n const items: HeaderMetaItem[] = [];\n if (typeLabel) items.push({ key: \"type\", content: typeLabel });\n if (workload.namespace) {\n items.push({ key: \"namespace\", content: workload.namespace });\n }\n if (workload.role) items.push({ key: \"role\", content: workload.role });\n const replicaText = formatReplicaCounts(workload.replicas);\n if (replicaText) items.push({ key: \"replicas\", content: replicaText });\n if (workload.createdAt !== undefined) {\n items.push({\n key: \"age\",\n content: (\n <>\n age <Timestamp value={workload.createdAt} format=\"relative\" />\n </>\n ),\n });\n }\n workload.metadata?.forEach((item, i) => {\n const plain =\n typeof item.value === \"string\" || typeof item.value === \"number\";\n items.push({\n key: `meta-${i}`,\n content: (\n <>\n <span className=\"text-muted-foreground/70\">{item.label}</span>{\" \"}\n {item.value}\n </>\n ),\n title: plain ? `${item.label}: ${item.value}` : item.label,\n });\n });\n return items;\n}\n\n/**\n * WorkloadCard is a compact resource card for a workload: a Kubernetes\n * resource (`kind`) or anything else (a free-form `type`, `icon` and\n * `metadata`). It shows identity, status, subtitle metadata, and\n * CPU/memory/disk utilization backed by the existing time-series primitives:\n * CPU and memory as core-style bars (memory at one bar per GiB) and disk as a\n * linear progress bar. Callers own the metric series (URL ids or `load`\n * functions); the card only composes them.\n *\n * Like the timeseries widgets it renders, it needs a react-query\n * `QueryClientProvider` above it.\n */\nexport function WorkloadCard({\n workload,\n metrics,\n baseUrl,\n range = \"1h\",\n refreshMs = 5000,\n expandable = true,\n headerActions,\n size = \"md\",\n variant = \"default\",\n fetcher,\n className,\n}: WorkloadCardProps) {\n const [expanded, setExpanded] = useState(false);\n const typeLabel = workloadTypeLabel(workload);\n const statusLabel = workloadStatusLabel(workload.status);\n const metaItems = headerMetaItems(workload, typeLabel);\n const workloadIcon =\n workload.icon ?? (workload.kind ? KIND_ICONS[workload.kind] : UiBox);\n const sizeClasses = SIZE_CLASSES[size];\n\n const panelMetrics = useMemo(() => {\n const list: PanelMetric[] = [];\n if (metrics.cpu) {\n list.push({\n key: \"cpu\",\n title: metrics.cpu.title ?? \"CPU\",\n unit: metrics.cpu.unit ?? \"short\",\n icon: metrics.cpu.icon ?? UiChip,\n metric: metrics.cpu,\n });\n }\n if (metrics.memory) {\n list.push({\n key: \"memory\",\n title: metrics.memory.title ?? \"Memory\",\n unit: metrics.memory.unit ?? \"bytes\",\n icon: metrics.memory.icon ?? UiMemoryStick,\n metric: metrics.memory,\n });\n }\n if (metrics.disk) {\n list.push({\n key: \"disk\",\n title: metrics.disk.title ?? \"Disk\",\n unit: metrics.disk.unit ?? \"bytes\",\n icon: metrics.disk.icon ?? UiHardDrive,\n metric: metrics.disk,\n });\n }\n return list;\n }, [metrics]);\n\n const metricProps = {\n ...(baseUrl !== undefined ? { baseUrl } : {}),\n range,\n refreshMs,\n ...(fetcher !== undefined ? { fetcher } : {}),\n };\n const canExpand = expandable && hasMetric(metrics);\n\n return (\n <div\n className={cn(\n \"w-full rounded-md border\",\n VARIANT_CLASSES[variant],\n sizeClasses.root,\n className,\n )}\n data-size={size}\n data-variant={variant}\n >\n <div\n className={cn(\"flex items-start justify-between\", sizeClasses.header)}\n >\n <div className=\"min-w-0\">\n <div\n className={cn(\"flex min-w-0 items-center\", sizeClasses.titleGap)}\n >\n <WorkloadIcon\n icon={workloadIcon}\n title={typeLabel ?? workload.name}\n className={cn(\"shrink-0 text-muted-foreground\", sizeClasses.icon)}\n />\n <span\n className={cn(\"min-w-0 truncate font-medium\", sizeClasses.name)}\n title={workload.name}\n >\n {workload.name}\n </span>\n </div>\n {metaItems.length > 0 ? (\n <div\n className={cn(\n \"flex flex-wrap items-center text-muted-foreground\",\n sizeClasses.meta,\n )}\n >\n {metaItems.map((item, i) => (\n <HeaderMeta\n key={item.key}\n separator={i > 0}\n title={item.title}\n >\n {item.content}\n </HeaderMeta>\n ))}\n </div>\n ) : null}\n </div>\n <div className=\"flex shrink-0 items-center gap-1\">\n {statusLabel ? (\n <span title={workload.status?.message}>\n <Badge\n tone={workloadStatusTone(workload.status)}\n variant=\"soft\"\n size={sizeClasses.statusSize}\n >\n {statusLabel}\n </Badge>\n </span>\n ) : null}\n {headerActions}\n {canExpand ? (\n <button\n type=\"button\"\n aria-label={`Open ${workload.name} history`}\n title=\"History\"\n onClick={() => setExpanded(true)}\n className={cn(\n \"inline-flex items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\",\n sizeClasses.action,\n )}\n >\n <Icon\n icon={UiFullscreen}\n width={sizeClasses.actionIcon}\n height={sizeClasses.actionIcon}\n />\n </button>\n ) : null}\n </div>\n </div>\n\n {hasMetric(metrics) ? (\n <div\n className={cn(\n \"grid items-start gap-3\",\n sizeClasses.metricVariant === \"cell\"\n ? sizeClasses.metricGrid\n : cn(\n metricGridClass(panelMetrics.length),\n sizeClasses.metricGrid,\n ),\n )}\n >\n {metrics.cpu ? (\n <TimeseriesCoreBars\n title={metrics.cpu.title ?? \"CPU\"}\n icon={metrics.cpu.icon ?? UiChip}\n value={metrics.cpu.value}\n {...(metrics.cpu.max !== undefined\n ? { max: metrics.cpu.max }\n : {})}\n {...(metrics.cpu.thresholds\n ? { thresholds: metrics.cpu.thresholds }\n : {})}\n {...(metrics.cpu.orientation\n ? { orientation: metrics.cpu.orientation }\n : {})}\n {...(metrics.cpu.showValue !== undefined\n ? { showValue: metrics.cpu.showValue }\n : {})}\n variant={sizeClasses.metricVariant}\n {...metricProps}\n />\n ) : null}\n {metrics.memory ? (\n <TimeseriesCoreBars\n title={metrics.memory.title ?? \"Memory\"}\n icon={metrics.memory.icon ?? UiMemoryStick}\n value={metrics.memory.value}\n unit={MEMORY_BAR_UNIT}\n variant={sizeClasses.metricVariant}\n {...(metrics.memory.max !== undefined\n ? { max: metrics.memory.max }\n : {})}\n {...(metrics.memory.thresholds\n ? { thresholds: metrics.memory.thresholds }\n : {})}\n {...metricProps}\n />\n ) : null}\n {metrics.disk ? (\n <TimeseriesGauge\n title={metrics.disk.title ?? \"Disk\"}\n icon={metrics.disk.icon ?? UiHardDrive}\n value={metrics.disk.value}\n unit={metrics.disk.unit ?? \"bytes\"}\n shape=\"linear\"\n expandable={false}\n centerDisplay={metrics.disk.centerDisplay ?? \"value\"}\n variant={sizeClasses.metricVariant}\n {...(metrics.disk.max !== undefined\n ? { max: metrics.disk.max }\n : {})}\n {...(metrics.disk.thresholds\n ? { thresholds: metrics.disk.thresholds }\n : {})}\n {...metricProps}\n />\n ) : null}\n </div>\n ) : (\n <div\n className={cn(\n \"rounded-md border border-dashed border-border text-center text-muted-foreground\",\n sizeClasses.empty,\n )}\n >\n No metrics configured\n </div>\n )}\n\n <Modal\n open={expanded}\n onClose={() => setExpanded(false)}\n title={`${workload.name} history`}\n size=\"xl\"\n >\n <div className=\"flex flex-col gap-3\">\n {panelMetrics.map(({ key, title, unit, icon, metric }) => (\n <TimeseriesPanel\n key={key}\n title={title}\n icon={icon}\n series={metricSeries(metric)}\n referenceLines={metricReferenceLines(metric)}\n {...(unit ? { unit } : {})}\n {...metricProps}\n expandable={false}\n />\n ))}\n </div>\n </Modal>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -14,21 +14,26 @@ function workloadKindLabel(kind) {
|
|
|
14
14
|
return "Pod";
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
+
function workloadTypeLabel(workload) {
|
|
18
|
+
if (workload.type) return workload.type;
|
|
19
|
+
return workload.kind ? workloadKindLabel(workload.kind) : void 0;
|
|
20
|
+
}
|
|
17
21
|
function workloadStatusLabel(status) {
|
|
18
22
|
return (status == null ? void 0 : status.label) ?? (status == null ? void 0 : status.code) ?? (status == null ? void 0 : status.health);
|
|
19
23
|
}
|
|
20
24
|
function workloadStatusTone(status) {
|
|
25
|
+
var _a;
|
|
21
26
|
if (status == null ? void 0 : status.tone) return status.tone;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
switch ((_a = status == null ? void 0 : status.health) == null ? void 0 : _a.trim().toLowerCase()) {
|
|
28
|
+
case "healthy":
|
|
29
|
+
return "success";
|
|
30
|
+
case "warning":
|
|
31
|
+
return "warning";
|
|
32
|
+
case "unhealthy":
|
|
33
|
+
return "danger";
|
|
34
|
+
default:
|
|
35
|
+
return "neutral";
|
|
36
|
+
}
|
|
32
37
|
}
|
|
33
38
|
function formatReplicaCounts(replicas) {
|
|
34
39
|
if (!replicas) return void 0;
|
|
@@ -48,4 +53,5 @@ exports.formatReplicaCounts = formatReplicaCounts;
|
|
|
48
53
|
exports.workloadKindLabel = workloadKindLabel;
|
|
49
54
|
exports.workloadStatusLabel = workloadStatusLabel;
|
|
50
55
|
exports.workloadStatusTone = workloadStatusTone;
|
|
56
|
+
exports.workloadTypeLabel = workloadTypeLabel;
|
|
51
57
|
//# sourceMappingURL=WorkloadCard.model.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkloadCard.model.cjs","sources":["../../src/data/WorkloadCard.model.ts"],"sourcesContent":["import type { BadgeTone } from \"./Badge\";\nimport type { StaticIconComponent } from \"./Icon\";\nimport type { ProgressBarsOrientation } from \"./ProgressBars\";\nimport type { GaugeSeries } from \"./TimeseriesGauge\";\n\nexport type WorkloadCardKind =\n | \"service\"\n | \"ingress\"\n | \"deployment\"\n | \"statefulset\"\n | \"pod\";\n\nexport type WorkloadCardIcon = string | StaticIconComponent;\n\nexport interface WorkloadCardReplicas {\n ready?: number;\n desired?: number;\n available?: number;\n}\n\nexport interface WorkloadCardStatus {\n label?: string;\n code?: string;\n health?: string;\n message?: string;\n tone?: BadgeTone;\n}\n\nexport interface WorkloadCardWorkload {\n kind
|
|
1
|
+
{"version":3,"file":"WorkloadCard.model.cjs","sources":["../../src/data/WorkloadCard.model.ts"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { BadgeTone } from \"./Badge\";\nimport type { StaticIconComponent } from \"./Icon\";\nimport type { ProgressBarsOrientation } from \"./ProgressBars\";\nimport type { GaugeSeries } from \"./TimeseriesGauge\";\n\nexport type WorkloadCardKind =\n | \"service\"\n | \"ingress\"\n | \"deployment\"\n | \"statefulset\"\n | \"pod\";\n\nexport type WorkloadCardIcon = string | StaticIconComponent;\n\nexport interface WorkloadCardReplicas {\n ready?: number;\n desired?: number;\n available?: number;\n}\n\nexport interface WorkloadCardStatus {\n /** Badge text; falls back to `code`, then `health`. Never affects the tone. */\n label?: string;\n code?: string;\n /** Drives the tone: healthy → success, warning → warning, unhealthy → danger. */\n health?: string;\n /** Hover text for the status badge. */\n message?: string;\n /** Explicit badge tone; overrides the `health` mapping. */\n tone?: BadgeTone;\n}\n\n/** One caller-defined fact shown in the card's subtitle row, e.g. a region. */\nexport interface WorkloadCardMetadataItem {\n label: string;\n value: ReactNode;\n}\n\n/**\n * The workload a card describes. Kubernetes workloads set `kind` (which picks\n * the icon and type label); anything else sets a free-form `type` label and\n * its own `icon`, and describes itself through `metadata`.\n */\nexport interface WorkloadCardWorkload {\n /** Kubernetes kind; picks the default icon and type label. */\n kind?: WorkloadCardKind;\n /** Display label for the workload type, e.g. \"EC2 instance\". Overrides the kind label. */\n type?: string;\n name: string;\n namespace?: string;\n role?: string;\n createdAt?: string | number | Date;\n replicas?: WorkloadCardReplicas;\n status?: WorkloadCardStatus;\n icon?: WorkloadCardIcon;\n /** Extra label/value facts rendered after the built-ins in the subtitle row. */\n metadata?: ReadonlyArray<WorkloadCardMetadataItem>;\n}\n\nexport interface WorkloadCardResourceMetric {\n title?: string;\n value: GaugeSeries;\n max?: GaugeSeries | number;\n valueLabel?: string;\n maxLabel?: string;\n unit?: string;\n icon?: WorkloadCardIcon;\n thresholds?: [warning: number, danger: number];\n centerDisplay?: \"value\" | \"percent\";\n}\n\nexport interface WorkloadCardCpuMetric extends WorkloadCardResourceMetric {\n orientation?: ProgressBarsOrientation;\n showValue?: boolean;\n}\n\nexport interface WorkloadCardMetrics {\n cpu?: WorkloadCardCpuMetric;\n memory?: WorkloadCardResourceMetric;\n disk?: WorkloadCardResourceMetric;\n}\n\nexport function workloadKindLabel(kind: WorkloadCardKind): string {\n switch (kind) {\n case \"statefulset\":\n return \"StatefulSet\";\n case \"deployment\":\n return \"Deployment\";\n case \"service\":\n return \"Service\";\n case \"ingress\":\n return \"Ingress\";\n case \"pod\":\n return \"Pod\";\n }\n}\n\n/** The type label shown in the subtitle: `type`, else the kind's label. */\nexport function workloadTypeLabel(\n workload: Pick<WorkloadCardWorkload, \"kind\" | \"type\">,\n): string | undefined {\n if (workload.type) return workload.type;\n return workload.kind ? workloadKindLabel(workload.kind) : undefined;\n}\n\nexport function workloadStatusLabel(\n status: WorkloadCardStatus | undefined,\n): string | undefined {\n return status?.label ?? status?.code ?? status?.health;\n}\n\n/**\n * The status badge tone: an explicit `tone`, else a fixed mapping of `health`\n * (healthy → success, warning → warning, unhealthy → danger, anything else →\n * neutral). Free-text `label`/`code` never affect the tone — substring guesses\n * misfire (\"NotReady\" contains \"ready\", \"Broken\" contains \"ok\").\n */\nexport function workloadStatusTone(\n status: WorkloadCardStatus | undefined,\n): BadgeTone {\n if (status?.tone) return status.tone;\n switch (status?.health?.trim().toLowerCase()) {\n case \"healthy\":\n return \"success\";\n case \"warning\":\n return \"warning\";\n case \"unhealthy\":\n return \"danger\";\n default:\n return \"neutral\";\n }\n}\n\nexport function formatReplicaCounts(\n replicas: WorkloadCardReplicas | undefined,\n): string | undefined {\n if (!replicas) return undefined;\n if (replicas.ready !== undefined && replicas.desired !== undefined) {\n return `${replicas.ready}/${replicas.desired} ready`;\n }\n if (replicas.available !== undefined && replicas.desired !== undefined) {\n return `${replicas.available}/${replicas.desired} available`;\n }\n if (replicas.ready !== undefined) return `${replicas.ready} ready`;\n if (replicas.desired !== undefined) return `${replicas.desired} desired`;\n if (replicas.available !== undefined)\n return `${replicas.available} available`;\n return undefined;\n}\n"],"names":[],"mappings":";;AAmFO,SAAS,kBAAkB,MAAgC;AAChE,UAAQ,MAAA;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EAAA;AAEb;AAGO,SAAS,kBACd,UACoB;AACpB,MAAI,SAAS,KAAM,QAAO,SAAS;AACnC,SAAO,SAAS,OAAO,kBAAkB,SAAS,IAAI,IAAI;AAC5D;AAEO,SAAS,oBACd,QACoB;AACpB,UAAO,iCAAQ,WAAS,iCAAQ,UAAQ,iCAAQ;AAClD;AAQO,SAAS,mBACd,QACW;;AACX,MAAI,iCAAQ,KAAM,QAAO,OAAO;AAChC,WAAQ,sCAAQ,WAAR,mBAAgB,OAAO,eAAY;AAAA,IACzC,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EAAA;AAEb;AAEO,SAAS,oBACd,UACoB;AACpB,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI,SAAS,UAAU,UAAa,SAAS,YAAY,QAAW;AAClE,WAAO,GAAG,SAAS,KAAK,IAAI,SAAS,OAAO;AAAA,EAC9C;AACA,MAAI,SAAS,cAAc,UAAa,SAAS,YAAY,QAAW;AACtE,WAAO,GAAG,SAAS,SAAS,IAAI,SAAS,OAAO;AAAA,EAClD;AACA,MAAI,SAAS,UAAU,OAAW,QAAO,GAAG,SAAS,KAAK;AAC1D,MAAI,SAAS,YAAY,OAAW,QAAO,GAAG,SAAS,OAAO;AAC9D,MAAI,SAAS,cAAc;AACzB,WAAO,GAAG,SAAS,SAAS;AAC9B,SAAO;AACT;;;;;;"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
1
2
|
import { BadgeTone } from './Badge';
|
|
2
3
|
import { StaticIconComponent } from './Icon';
|
|
3
4
|
import { ProgressBarsOrientation } from './ProgressBars';
|
|
@@ -10,14 +11,31 @@ export interface WorkloadCardReplicas {
|
|
|
10
11
|
available?: number;
|
|
11
12
|
}
|
|
12
13
|
export interface WorkloadCardStatus {
|
|
14
|
+
/** Badge text; falls back to `code`, then `health`. Never affects the tone. */
|
|
13
15
|
label?: string;
|
|
14
16
|
code?: string;
|
|
17
|
+
/** Drives the tone: healthy → success, warning → warning, unhealthy → danger. */
|
|
15
18
|
health?: string;
|
|
19
|
+
/** Hover text for the status badge. */
|
|
16
20
|
message?: string;
|
|
21
|
+
/** Explicit badge tone; overrides the `health` mapping. */
|
|
17
22
|
tone?: BadgeTone;
|
|
18
23
|
}
|
|
24
|
+
/** One caller-defined fact shown in the card's subtitle row, e.g. a region. */
|
|
25
|
+
export interface WorkloadCardMetadataItem {
|
|
26
|
+
label: string;
|
|
27
|
+
value: ReactNode;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The workload a card describes. Kubernetes workloads set `kind` (which picks
|
|
31
|
+
* the icon and type label); anything else sets a free-form `type` label and
|
|
32
|
+
* its own `icon`, and describes itself through `metadata`.
|
|
33
|
+
*/
|
|
19
34
|
export interface WorkloadCardWorkload {
|
|
20
|
-
kind
|
|
35
|
+
/** Kubernetes kind; picks the default icon and type label. */
|
|
36
|
+
kind?: WorkloadCardKind;
|
|
37
|
+
/** Display label for the workload type, e.g. "EC2 instance". Overrides the kind label. */
|
|
38
|
+
type?: string;
|
|
21
39
|
name: string;
|
|
22
40
|
namespace?: string;
|
|
23
41
|
role?: string;
|
|
@@ -25,6 +43,8 @@ export interface WorkloadCardWorkload {
|
|
|
25
43
|
replicas?: WorkloadCardReplicas;
|
|
26
44
|
status?: WorkloadCardStatus;
|
|
27
45
|
icon?: WorkloadCardIcon;
|
|
46
|
+
/** Extra label/value facts rendered after the built-ins in the subtitle row. */
|
|
47
|
+
metadata?: ReadonlyArray<WorkloadCardMetadataItem>;
|
|
28
48
|
}
|
|
29
49
|
export interface WorkloadCardResourceMetric {
|
|
30
50
|
title?: string;
|
|
@@ -47,7 +67,15 @@ export interface WorkloadCardMetrics {
|
|
|
47
67
|
disk?: WorkloadCardResourceMetric;
|
|
48
68
|
}
|
|
49
69
|
export declare function workloadKindLabel(kind: WorkloadCardKind): string;
|
|
70
|
+
/** The type label shown in the subtitle: `type`, else the kind's label. */
|
|
71
|
+
export declare function workloadTypeLabel(workload: Pick<WorkloadCardWorkload, "kind" | "type">): string | undefined;
|
|
50
72
|
export declare function workloadStatusLabel(status: WorkloadCardStatus | undefined): string | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* The status badge tone: an explicit `tone`, else a fixed mapping of `health`
|
|
75
|
+
* (healthy → success, warning → warning, unhealthy → danger, anything else →
|
|
76
|
+
* neutral). Free-text `label`/`code` never affect the tone — substring guesses
|
|
77
|
+
* misfire ("NotReady" contains "ready", "Broken" contains "ok").
|
|
78
|
+
*/
|
|
51
79
|
export declare function workloadStatusTone(status: WorkloadCardStatus | undefined): BadgeTone;
|
|
52
80
|
export declare function formatReplicaCounts(replicas: WorkloadCardReplicas | undefined): string | undefined;
|
|
53
81
|
//# sourceMappingURL=WorkloadCard.model.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkloadCard.model.d.ts","sourceRoot":"","sources":["../../src/data/WorkloadCard.model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,SAAS,GACT,YAAY,GACZ,aAAa,GACb,KAAK,CAAC;AAEV,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,mBAAmB,CAAC;AAE5D,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"WorkloadCard.model.d.ts","sourceRoot":"","sources":["../../src/data/WorkloadCard.model.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,21 +12,26 @@ function workloadKindLabel(kind) {
|
|
|
12
12
|
return "Pod";
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
+
function workloadTypeLabel(workload) {
|
|
16
|
+
if (workload.type) return workload.type;
|
|
17
|
+
return workload.kind ? workloadKindLabel(workload.kind) : void 0;
|
|
18
|
+
}
|
|
15
19
|
function workloadStatusLabel(status) {
|
|
16
20
|
return (status == null ? void 0 : status.label) ?? (status == null ? void 0 : status.code) ?? (status == null ? void 0 : status.health);
|
|
17
21
|
}
|
|
18
22
|
function workloadStatusTone(status) {
|
|
23
|
+
var _a;
|
|
19
24
|
if (status == null ? void 0 : status.tone) return status.tone;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
switch ((_a = status == null ? void 0 : status.health) == null ? void 0 : _a.trim().toLowerCase()) {
|
|
26
|
+
case "healthy":
|
|
27
|
+
return "success";
|
|
28
|
+
case "warning":
|
|
29
|
+
return "warning";
|
|
30
|
+
case "unhealthy":
|
|
31
|
+
return "danger";
|
|
32
|
+
default:
|
|
33
|
+
return "neutral";
|
|
34
|
+
}
|
|
30
35
|
}
|
|
31
36
|
function formatReplicaCounts(replicas) {
|
|
32
37
|
if (!replicas) return void 0;
|
|
@@ -46,6 +51,7 @@ export {
|
|
|
46
51
|
formatReplicaCounts,
|
|
47
52
|
workloadKindLabel,
|
|
48
53
|
workloadStatusLabel,
|
|
49
|
-
workloadStatusTone
|
|
54
|
+
workloadStatusTone,
|
|
55
|
+
workloadTypeLabel
|
|
50
56
|
};
|
|
51
57
|
//# sourceMappingURL=WorkloadCard.model.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkloadCard.model.js","sources":["../../src/data/WorkloadCard.model.ts"],"sourcesContent":["import type { BadgeTone } from \"./Badge\";\nimport type { StaticIconComponent } from \"./Icon\";\nimport type { ProgressBarsOrientation } from \"./ProgressBars\";\nimport type { GaugeSeries } from \"./TimeseriesGauge\";\n\nexport type WorkloadCardKind =\n | \"service\"\n | \"ingress\"\n | \"deployment\"\n | \"statefulset\"\n | \"pod\";\n\nexport type WorkloadCardIcon = string | StaticIconComponent;\n\nexport interface WorkloadCardReplicas {\n ready?: number;\n desired?: number;\n available?: number;\n}\n\nexport interface WorkloadCardStatus {\n label?: string;\n code?: string;\n health?: string;\n message?: string;\n tone?: BadgeTone;\n}\n\nexport interface WorkloadCardWorkload {\n kind
|
|
1
|
+
{"version":3,"file":"WorkloadCard.model.js","sources":["../../src/data/WorkloadCard.model.ts"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { BadgeTone } from \"./Badge\";\nimport type { StaticIconComponent } from \"./Icon\";\nimport type { ProgressBarsOrientation } from \"./ProgressBars\";\nimport type { GaugeSeries } from \"./TimeseriesGauge\";\n\nexport type WorkloadCardKind =\n | \"service\"\n | \"ingress\"\n | \"deployment\"\n | \"statefulset\"\n | \"pod\";\n\nexport type WorkloadCardIcon = string | StaticIconComponent;\n\nexport interface WorkloadCardReplicas {\n ready?: number;\n desired?: number;\n available?: number;\n}\n\nexport interface WorkloadCardStatus {\n /** Badge text; falls back to `code`, then `health`. Never affects the tone. */\n label?: string;\n code?: string;\n /** Drives the tone: healthy → success, warning → warning, unhealthy → danger. */\n health?: string;\n /** Hover text for the status badge. */\n message?: string;\n /** Explicit badge tone; overrides the `health` mapping. */\n tone?: BadgeTone;\n}\n\n/** One caller-defined fact shown in the card's subtitle row, e.g. a region. */\nexport interface WorkloadCardMetadataItem {\n label: string;\n value: ReactNode;\n}\n\n/**\n * The workload a card describes. Kubernetes workloads set `kind` (which picks\n * the icon and type label); anything else sets a free-form `type` label and\n * its own `icon`, and describes itself through `metadata`.\n */\nexport interface WorkloadCardWorkload {\n /** Kubernetes kind; picks the default icon and type label. */\n kind?: WorkloadCardKind;\n /** Display label for the workload type, e.g. \"EC2 instance\". Overrides the kind label. */\n type?: string;\n name: string;\n namespace?: string;\n role?: string;\n createdAt?: string | number | Date;\n replicas?: WorkloadCardReplicas;\n status?: WorkloadCardStatus;\n icon?: WorkloadCardIcon;\n /** Extra label/value facts rendered after the built-ins in the subtitle row. */\n metadata?: ReadonlyArray<WorkloadCardMetadataItem>;\n}\n\nexport interface WorkloadCardResourceMetric {\n title?: string;\n value: GaugeSeries;\n max?: GaugeSeries | number;\n valueLabel?: string;\n maxLabel?: string;\n unit?: string;\n icon?: WorkloadCardIcon;\n thresholds?: [warning: number, danger: number];\n centerDisplay?: \"value\" | \"percent\";\n}\n\nexport interface WorkloadCardCpuMetric extends WorkloadCardResourceMetric {\n orientation?: ProgressBarsOrientation;\n showValue?: boolean;\n}\n\nexport interface WorkloadCardMetrics {\n cpu?: WorkloadCardCpuMetric;\n memory?: WorkloadCardResourceMetric;\n disk?: WorkloadCardResourceMetric;\n}\n\nexport function workloadKindLabel(kind: WorkloadCardKind): string {\n switch (kind) {\n case \"statefulset\":\n return \"StatefulSet\";\n case \"deployment\":\n return \"Deployment\";\n case \"service\":\n return \"Service\";\n case \"ingress\":\n return \"Ingress\";\n case \"pod\":\n return \"Pod\";\n }\n}\n\n/** The type label shown in the subtitle: `type`, else the kind's label. */\nexport function workloadTypeLabel(\n workload: Pick<WorkloadCardWorkload, \"kind\" | \"type\">,\n): string | undefined {\n if (workload.type) return workload.type;\n return workload.kind ? workloadKindLabel(workload.kind) : undefined;\n}\n\nexport function workloadStatusLabel(\n status: WorkloadCardStatus | undefined,\n): string | undefined {\n return status?.label ?? status?.code ?? status?.health;\n}\n\n/**\n * The status badge tone: an explicit `tone`, else a fixed mapping of `health`\n * (healthy → success, warning → warning, unhealthy → danger, anything else →\n * neutral). Free-text `label`/`code` never affect the tone — substring guesses\n * misfire (\"NotReady\" contains \"ready\", \"Broken\" contains \"ok\").\n */\nexport function workloadStatusTone(\n status: WorkloadCardStatus | undefined,\n): BadgeTone {\n if (status?.tone) return status.tone;\n switch (status?.health?.trim().toLowerCase()) {\n case \"healthy\":\n return \"success\";\n case \"warning\":\n return \"warning\";\n case \"unhealthy\":\n return \"danger\";\n default:\n return \"neutral\";\n }\n}\n\nexport function formatReplicaCounts(\n replicas: WorkloadCardReplicas | undefined,\n): string | undefined {\n if (!replicas) return undefined;\n if (replicas.ready !== undefined && replicas.desired !== undefined) {\n return `${replicas.ready}/${replicas.desired} ready`;\n }\n if (replicas.available !== undefined && replicas.desired !== undefined) {\n return `${replicas.available}/${replicas.desired} available`;\n }\n if (replicas.ready !== undefined) return `${replicas.ready} ready`;\n if (replicas.desired !== undefined) return `${replicas.desired} desired`;\n if (replicas.available !== undefined)\n return `${replicas.available} available`;\n return undefined;\n}\n"],"names":[],"mappings":"AAmFO,SAAS,kBAAkB,MAAgC;AAChE,UAAQ,MAAA;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EAAA;AAEb;AAGO,SAAS,kBACd,UACoB;AACpB,MAAI,SAAS,KAAM,QAAO,SAAS;AACnC,SAAO,SAAS,OAAO,kBAAkB,SAAS,IAAI,IAAI;AAC5D;AAEO,SAAS,oBACd,QACoB;AACpB,UAAO,iCAAQ,WAAS,iCAAQ,UAAQ,iCAAQ;AAClD;AAQO,SAAS,mBACd,QACW;AArCN;AAsCL,MAAI,iCAAQ,KAAM,QAAO,OAAO;AAChC,WAAQ,sCAAQ,WAAR,mBAAgB,OAAO,eAAY;AAAA,IACzC,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EAAA;AAEb;AAEO,SAAS,oBACd,UACoB;AACpB,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI,SAAS,UAAU,UAAa,SAAS,YAAY,QAAW;AAClE,WAAO,GAAG,SAAS,KAAK,IAAI,SAAS,OAAO;AAAA,EAC9C;AACA,MAAI,SAAS,cAAc,UAAa,SAAS,YAAY,QAAW;AACtE,WAAO,GAAG,SAAS,SAAS,IAAI,SAAS,OAAO;AAAA,EAClD;AACA,MAAI,SAAS,UAAU,OAAW,QAAO,GAAG,SAAS,KAAK;AAC1D,MAAI,SAAS,YAAY,OAAW,QAAO,GAAG,SAAS,OAAO;AAC9D,MAAI,SAAS,cAAc;AACzB,WAAO,GAAG,SAAS,SAAS;AAC9B,SAAO;AACT;"}
|