@checkstack/healthcheck-frontend 0.17.0 → 0.17.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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @checkstack/healthcheck-frontend
|
|
2
2
|
|
|
3
|
+
## 0.17.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 42b0832: Refactor auto-chart layout to make collector grouping more dominant. Chart titles now show only the metric label (e.g. "Avg Response Time") instead of the prefixed "{collectorId}: Metric" form. Collector groups display the collector name as a heading with a badge containing the full collector id. Cards now stack at full width and their contents are center-aligned.
|
|
8
|
+
|
|
3
9
|
## 0.17.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/package.json
CHANGED
|
@@ -10,7 +10,7 @@ import { extractChartFields, getFieldValue } from "./schema-parser";
|
|
|
10
10
|
import { useStrategySchemas } from "./useStrategySchemas";
|
|
11
11
|
import type { HealthCheckDiagramSlotContext } from "../slots";
|
|
12
12
|
import { SparklineTooltip } from "../components/SparklineTooltip";
|
|
13
|
-
import { Card, CardContent, CardHeader, CardTitle } from "@checkstack/ui";
|
|
13
|
+
import { Badge, Card, CardContent, CardHeader, CardTitle } from "@checkstack/ui";
|
|
14
14
|
import {
|
|
15
15
|
PieChart,
|
|
16
16
|
Pie,
|
|
@@ -86,7 +86,7 @@ export function AutoChartGrid({ context }: AutoChartGridProps) {
|
|
|
86
86
|
<div className="space-y-6 mt-4">
|
|
87
87
|
{/* Strategy-level fields */}
|
|
88
88
|
{strategyFields.length > 0 && (
|
|
89
|
-
<div className="
|
|
89
|
+
<div className="space-y-4">
|
|
90
90
|
{strategyFields.map((field) => (
|
|
91
91
|
<AutoChartCard
|
|
92
92
|
key={field.name}
|
|
@@ -118,6 +118,7 @@ interface CollectorGroupData {
|
|
|
118
118
|
instanceKey: string;
|
|
119
119
|
collectorId: string;
|
|
120
120
|
displayName: string;
|
|
121
|
+
instanceLabel?: string;
|
|
121
122
|
fields: ExpandedChartField[];
|
|
122
123
|
}
|
|
123
124
|
|
|
@@ -140,15 +141,15 @@ function buildCollectorGroups(
|
|
|
140
141
|
|
|
141
142
|
// Create a group for each instance
|
|
142
143
|
for (const [index, instanceKey] of instanceKeys.entries()) {
|
|
143
|
-
const displayName =
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
: `${collectorId.split(".").pop() || collectorId} #${index + 1}`;
|
|
144
|
+
const displayName = collectorId.split(".").pop() || collectorId;
|
|
145
|
+
const instanceLabel =
|
|
146
|
+
instanceKeys.length > 1 ? `#${index + 1}` : undefined;
|
|
147
147
|
|
|
148
148
|
groups.push({
|
|
149
149
|
instanceKey,
|
|
150
150
|
collectorId,
|
|
151
151
|
displayName,
|
|
152
|
+
instanceLabel,
|
|
152
153
|
fields: collectorFields.map((field) => ({
|
|
153
154
|
...field,
|
|
154
155
|
instanceKey,
|
|
@@ -174,7 +175,8 @@ function CollectorGroup({
|
|
|
174
175
|
context: HealthCheckDiagramSlotContext;
|
|
175
176
|
baselines: AnomalyBaselineDto[];
|
|
176
177
|
}) {
|
|
177
|
-
//
|
|
178
|
+
// Order: narrow (summary) cards first, then wide timeline cards.
|
|
179
|
+
// Layout is now fully stacked at 100% width.
|
|
178
180
|
const narrowFields = group.fields.filter(
|
|
179
181
|
(f) => !WIDE_CHART_TYPES.has(f.chartType),
|
|
180
182
|
);
|
|
@@ -184,26 +186,30 @@ function CollectorGroup({
|
|
|
184
186
|
|
|
185
187
|
return (
|
|
186
188
|
<div className="space-y-4">
|
|
187
|
-
<
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
/>
|
|
201
|
-
))}
|
|
202
|
-
</div>
|
|
203
|
-
)}
|
|
189
|
+
<div className="flex items-center gap-2 flex-wrap border-b pb-2">
|
|
190
|
+
<h3 className="text-lg font-semibold capitalize">
|
|
191
|
+
{group.displayName}
|
|
192
|
+
</h3>
|
|
193
|
+
{group.instanceLabel && (
|
|
194
|
+
<span className="text-sm font-medium text-muted-foreground">
|
|
195
|
+
{group.instanceLabel}
|
|
196
|
+
</span>
|
|
197
|
+
)}
|
|
198
|
+
<Badge variant="outline" className="font-mono">
|
|
199
|
+
{group.collectorId}
|
|
200
|
+
</Badge>
|
|
201
|
+
</div>
|
|
204
202
|
|
|
205
|
-
{/* Wide timeline cards - assertion plus timeline fields */}
|
|
206
203
|
<div className="space-y-4">
|
|
204
|
+
{narrowFields.map((field) => (
|
|
205
|
+
<AutoChartCard
|
|
206
|
+
key={`${field.instanceKey}-${field.name}`}
|
|
207
|
+
field={field}
|
|
208
|
+
context={context}
|
|
209
|
+
baselines={baselines}
|
|
210
|
+
/>
|
|
211
|
+
))}
|
|
212
|
+
|
|
207
213
|
<AssertionStatusCard
|
|
208
214
|
context={context}
|
|
209
215
|
instanceKey={group.instanceKey}
|
|
@@ -275,9 +281,11 @@ function AssertionStatusCard({
|
|
|
275
281
|
return (
|
|
276
282
|
<Card>
|
|
277
283
|
<CardHeader className="pb-2">
|
|
278
|
-
<CardTitle className="text-sm font-medium">
|
|
284
|
+
<CardTitle className="text-sm font-medium text-center">
|
|
285
|
+
Assertion
|
|
286
|
+
</CardTitle>
|
|
279
287
|
</CardHeader>
|
|
280
|
-
<CardContent>
|
|
288
|
+
<CardContent className="text-center">
|
|
281
289
|
<div className="text-sm text-muted-foreground">No data</div>
|
|
282
290
|
</CardContent>
|
|
283
291
|
</Card>
|
|
@@ -298,14 +306,14 @@ function AssertionStatusCard({
|
|
|
298
306
|
>
|
|
299
307
|
<CardHeader className="pb-2">
|
|
300
308
|
<CardTitle
|
|
301
|
-
className={`text-sm font-medium ${latestResult.passed ? "" : "text-red-600"}`}
|
|
309
|
+
className={`text-sm font-medium text-center ${latestResult.passed ? "" : "text-red-600"}`}
|
|
302
310
|
>
|
|
303
311
|
{latestResult.passed ? "Assertion" : "Assertion Failed"}
|
|
304
312
|
</CardTitle>
|
|
305
313
|
</CardHeader>
|
|
306
|
-
<CardContent className="space-y-2">
|
|
314
|
+
<CardContent className="space-y-2 text-center">
|
|
307
315
|
{/* Current status with rate */}
|
|
308
|
-
<div className="flex items-center gap-2">
|
|
316
|
+
<div className="flex items-center justify-center gap-2">
|
|
309
317
|
<div
|
|
310
318
|
className={`w-3 h-3 rounded-full ${
|
|
311
319
|
latestResult.passed ? "bg-green-500" : "bg-red-500"
|
|
@@ -449,9 +457,11 @@ function AutoChartCard({ field, context, baselines }: AutoChartCardProps) {
|
|
|
449
457
|
return (
|
|
450
458
|
<Card>
|
|
451
459
|
<CardHeader className="pb-2">
|
|
452
|
-
<CardTitle className="text-sm font-medium">
|
|
460
|
+
<CardTitle className="text-sm font-medium text-center">
|
|
461
|
+
{field.label}
|
|
462
|
+
</CardTitle>
|
|
453
463
|
</CardHeader>
|
|
454
|
-
<CardContent>
|
|
464
|
+
<CardContent className="flex flex-col items-center text-center [&>*]:w-full">
|
|
455
465
|
<ChartRenderer field={field} context={context} baseline={baseline} />
|
|
456
466
|
</CardContent>
|
|
457
467
|
</Card>
|
|
@@ -592,8 +602,8 @@ function GaugeRenderer({ field, context, baseline }: ChartRendererProps) {
|
|
|
592
602
|
const data = [{ name: field.label, value: numValue, fill: fillColor }];
|
|
593
603
|
|
|
594
604
|
return (
|
|
595
|
-
<div className="flex flex-col gap-2">
|
|
596
|
-
<div className="flex items-center gap-3">
|
|
605
|
+
<div className="flex flex-col gap-2 items-center">
|
|
606
|
+
<div className="flex items-center justify-center gap-3">
|
|
597
607
|
<ResponsiveContainer width={80} height={80}>
|
|
598
608
|
<RadialBarChart
|
|
599
609
|
cx="50%"
|
|
@@ -681,7 +691,7 @@ function BooleanRenderer({ field, context, baseline }: ChartRendererProps) {
|
|
|
681
691
|
return (
|
|
682
692
|
<div className="space-y-2">
|
|
683
693
|
{/* Current status with rate */}
|
|
684
|
-
<div className="flex items-center gap-2">
|
|
694
|
+
<div className="flex items-center justify-center gap-2">
|
|
685
695
|
<div
|
|
686
696
|
className={`w-3 h-3 rounded-full ${
|
|
687
697
|
latestValue ? "bg-green-500" : "bg-red-500"
|
|
@@ -753,7 +763,7 @@ function TextRenderer({ field, context, baseline }: ChartRendererProps) {
|
|
|
753
763
|
return (
|
|
754
764
|
<div className="space-y-2">
|
|
755
765
|
{/* Current value with count */}
|
|
756
|
-
<div className="flex items-center gap-2">
|
|
766
|
+
<div className="flex items-center justify-center gap-2">
|
|
757
767
|
<span className="text-sm font-mono">{latestValue || "—"}</span>
|
|
758
768
|
{!allSame && (
|
|
759
769
|
<span className="text-xs text-muted-foreground">
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import type { ChartField } from "./schema-parser";
|
|
9
9
|
import { extractChartFields, getFieldValue } from "./schema-parser";
|
|
10
10
|
import { useStrategySchemas } from "./useStrategySchemas";
|
|
11
|
-
import { Card, CardContent, CardHeader, CardTitle } from "@checkstack/ui";
|
|
11
|
+
import { Badge, Card, CardContent, CardHeader, CardTitle } from "@checkstack/ui";
|
|
12
12
|
import { RadialBarChart, RadialBar, ResponsiveContainer } from "recharts";
|
|
13
13
|
|
|
14
14
|
interface SingleRunChartGridProps {
|
|
@@ -62,7 +62,7 @@ export function SingleRunChartGrid({
|
|
|
62
62
|
<div className="space-y-6">
|
|
63
63
|
{/* Strategy-level fields */}
|
|
64
64
|
{strategyFields.length > 0 && (
|
|
65
|
-
<div className="
|
|
65
|
+
<div className="space-y-4">
|
|
66
66
|
{strategyFields.map((field) => (
|
|
67
67
|
<SingleValueCard
|
|
68
68
|
key={field.name}
|
|
@@ -124,12 +124,13 @@ function CollectorSection({
|
|
|
124
124
|
|
|
125
125
|
return (
|
|
126
126
|
<div className="space-y-4">
|
|
127
|
-
<div className="flex items-center gap-2">
|
|
128
|
-
<
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
127
|
+
<div className="flex items-center gap-2 flex-wrap border-b pb-2">
|
|
128
|
+
<h3 className="text-lg font-semibold capitalize">{displayName}</h3>
|
|
129
|
+
<Badge variant="outline" className="font-mono">
|
|
130
|
+
{collectorId}
|
|
131
|
+
</Badge>
|
|
132
|
+
<span className="text-xs text-muted-foreground font-mono">
|
|
133
|
+
{instanceId.slice(0, 8)}
|
|
133
134
|
</span>
|
|
134
135
|
</div>
|
|
135
136
|
|
|
@@ -165,7 +166,7 @@ function CollectorSection({
|
|
|
165
166
|
</Card>
|
|
166
167
|
)}
|
|
167
168
|
|
|
168
|
-
<div className="
|
|
169
|
+
<div className="space-y-4">
|
|
169
170
|
{fields.map((field) => (
|
|
170
171
|
<SingleValueCard
|
|
171
172
|
key={field.name}
|
|
@@ -190,9 +191,11 @@ function SingleValueCard({ field, value }: SingleValueCardProps) {
|
|
|
190
191
|
return (
|
|
191
192
|
<Card>
|
|
192
193
|
<CardHeader className="pb-2">
|
|
193
|
-
<CardTitle className="text-sm font-medium">
|
|
194
|
+
<CardTitle className="text-sm font-medium text-center">
|
|
195
|
+
{field.label}
|
|
196
|
+
</CardTitle>
|
|
194
197
|
</CardHeader>
|
|
195
|
-
<CardContent>
|
|
198
|
+
<CardContent className="flex flex-col items-center text-center [&>*]:w-full">
|
|
196
199
|
<SingleValueRenderer field={field} value={value} />
|
|
197
200
|
</CardContent>
|
|
198
201
|
</Card>
|
|
@@ -292,7 +295,7 @@ function GaugeRenderer({ value, unit }: { value: unknown; unit?: string }) {
|
|
|
292
295
|
const data = [{ name: "value", value: clampedValue, fill: fillColor }];
|
|
293
296
|
|
|
294
297
|
return (
|
|
295
|
-
<div className="flex items-center gap-3">
|
|
298
|
+
<div className="flex items-center justify-center gap-3">
|
|
296
299
|
<ResponsiveContainer width={80} height={80}>
|
|
297
300
|
<RadialBarChart
|
|
298
301
|
cx="50%"
|
|
@@ -330,7 +333,7 @@ function BooleanRenderer({ value }: { value: unknown }) {
|
|
|
330
333
|
const boolValue = Boolean(value);
|
|
331
334
|
|
|
332
335
|
return (
|
|
333
|
-
<div className="flex items-center gap-2">
|
|
336
|
+
<div className="flex items-center justify-center gap-2">
|
|
334
337
|
<div
|
|
335
338
|
className={`w-3 h-3 rounded-full ${
|
|
336
339
|
boolValue ? "bg-green-500" : "bg-red-500"
|
|
@@ -108,12 +108,9 @@ function extractFieldsFromProperties(
|
|
|
108
108
|
if (!chartType) continue;
|
|
109
109
|
|
|
110
110
|
// Use just field name - collectorId is stored separately for data lookup
|
|
111
|
+
// and surfaced via a separate badge in the group header
|
|
111
112
|
const field = extractSingleField(fieldName, prop);
|
|
112
113
|
field.collectorId = collectorId;
|
|
113
|
-
// Prefix label with collector ID for clarity
|
|
114
|
-
if (!prop["x-chart-label"]?.includes(collectorId)) {
|
|
115
|
-
field.label = `${collectorId}: ${field.label}`;
|
|
116
|
-
}
|
|
117
114
|
fields.push(field);
|
|
118
115
|
}
|
|
119
116
|
|