@checkstack/healthcheck-frontend 0.5.0 → 0.6.0
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 +30 -0
- package/package.json +1 -1
- package/src/components/CollectorList.tsx +63 -56
- package/src/components/HealthCheckList.tsx +53 -11
- package/src/components/HealthCheckSystemOverview.tsx +16 -17
- package/src/pages/HealthCheckConfigPage.tsx +27 -5
- package/src/pages/HealthCheckHistoryDetailPage.tsx +5 -3
- package/src/pages/HealthCheckHistoryPage.tsx +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @checkstack/healthcheck-frontend
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 11d2679: Add ability to pause health check configurations globally. When paused, health checks continue to be scheduled but execution is skipped for all systems using that configuration. Users with manage access can pause/resume from the Health Checks config page.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 223081d: Add icon support to PageLayout and improve mobile responsiveness
|
|
12
|
+
|
|
13
|
+
**PageLayout Icons:**
|
|
14
|
+
|
|
15
|
+
- Added required `icon` prop to `PageLayout` and `PageHeader` components that accepts a Lucide icon component reference
|
|
16
|
+
- Icons are rendered with consistent `h-6 w-6 text-primary` styling
|
|
17
|
+
- Updated all page components to include appropriate icons in their headers
|
|
18
|
+
|
|
19
|
+
**Mobile Layout Improvements:**
|
|
20
|
+
|
|
21
|
+
- Standardized responsive padding in main app shell (`p-3` on mobile, `p-6` on desktop)
|
|
22
|
+
- Added `CardHeaderRow` component for mobile-safe card headers with proper wrapping
|
|
23
|
+
- Improved `DateRangeFilter` responsive behavior with vertical stacking on mobile
|
|
24
|
+
- Migrated pages to use `PageLayout` for consistent responsive behavior
|
|
25
|
+
|
|
26
|
+
- Updated dependencies [11d2679]
|
|
27
|
+
- Updated dependencies [223081d]
|
|
28
|
+
- @checkstack/healthcheck-common@0.6.0
|
|
29
|
+
- @checkstack/ui@0.5.0
|
|
30
|
+
- @checkstack/auth-frontend@0.5.5
|
|
31
|
+
- @checkstack/dashboard-frontend@0.3.10
|
|
32
|
+
|
|
3
33
|
## 0.5.0
|
|
4
34
|
|
|
5
35
|
### Minor Changes
|
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
Card,
|
|
8
8
|
CardContent,
|
|
9
9
|
CardHeader,
|
|
10
|
+
CardHeaderRow,
|
|
10
11
|
CardTitle,
|
|
11
12
|
Label,
|
|
12
13
|
Select,
|
|
@@ -157,62 +158,68 @@ export const CollectorList: React.FC<CollectorListProps> = ({
|
|
|
157
158
|
|
|
158
159
|
return (
|
|
159
160
|
<Card>
|
|
160
|
-
<CardHeader
|
|
161
|
-
<
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
<
|
|
165
|
-
<
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
161
|
+
<CardHeader>
|
|
162
|
+
<CardHeaderRow>
|
|
163
|
+
<CardTitle className="text-base">Check Items</CardTitle>
|
|
164
|
+
{addableCollectors.length > 0 && (
|
|
165
|
+
<Select value="" onValueChange={handleAdd}>
|
|
166
|
+
<SelectTrigger className="w-[200px]">
|
|
167
|
+
<Plus className="h-4 w-4 mr-2" />
|
|
168
|
+
<SelectValue placeholder="Add collector..." />
|
|
169
|
+
</SelectTrigger>
|
|
170
|
+
<SelectContent>
|
|
171
|
+
{/* Built-in collectors first */}
|
|
172
|
+
{builtInCollectors.length > 0 && (
|
|
173
|
+
<>
|
|
174
|
+
<div className="px-2 py-1.5 text-xs font-semibold text-muted-foreground">
|
|
175
|
+
Built-in
|
|
176
|
+
</div>
|
|
177
|
+
{builtInCollectors
|
|
178
|
+
.filter((c) =>
|
|
179
|
+
addableCollectors.some((a) => a.id === c.id),
|
|
180
|
+
)
|
|
181
|
+
.map((collector) => (
|
|
182
|
+
<SelectItem key={collector.id} value={collector.id}>
|
|
183
|
+
<div className="flex items-center gap-2">
|
|
184
|
+
<span>{collector.displayName}</span>
|
|
185
|
+
{collector.allowMultiple && (
|
|
186
|
+
<Badge variant="outline" className="text-xs">
|
|
187
|
+
Multiple
|
|
188
|
+
</Badge>
|
|
189
|
+
)}
|
|
190
|
+
</div>
|
|
191
|
+
</SelectItem>
|
|
192
|
+
))}
|
|
193
|
+
</>
|
|
194
|
+
)}
|
|
195
|
+
{/* External collectors */}
|
|
196
|
+
{externalCollectors.length > 0 && (
|
|
197
|
+
<>
|
|
198
|
+
<div className="px-2 py-1.5 text-xs font-semibold text-muted-foreground">
|
|
199
|
+
External
|
|
200
|
+
</div>
|
|
201
|
+
{externalCollectors
|
|
202
|
+
.filter((c) =>
|
|
203
|
+
addableCollectors.some((a) => a.id === c.id),
|
|
204
|
+
)
|
|
205
|
+
.map((collector) => (
|
|
206
|
+
<SelectItem key={collector.id} value={collector.id}>
|
|
207
|
+
<div className="flex items-center gap-2">
|
|
208
|
+
<span>{collector.displayName}</span>
|
|
209
|
+
{collector.allowMultiple && (
|
|
210
|
+
<Badge variant="outline" className="text-xs">
|
|
211
|
+
Multiple
|
|
212
|
+
</Badge>
|
|
213
|
+
)}
|
|
214
|
+
</div>
|
|
215
|
+
</SelectItem>
|
|
216
|
+
))}
|
|
217
|
+
</>
|
|
218
|
+
)}
|
|
219
|
+
</SelectContent>
|
|
220
|
+
</Select>
|
|
221
|
+
)}
|
|
222
|
+
</CardHeaderRow>
|
|
216
223
|
</CardHeader>
|
|
217
224
|
<CardContent>
|
|
218
225
|
{configuredCollectors.length === 0 ? (
|
|
@@ -11,14 +11,18 @@ import {
|
|
|
11
11
|
TableHeader,
|
|
12
12
|
TableRow,
|
|
13
13
|
Button,
|
|
14
|
+
Badge,
|
|
14
15
|
} from "@checkstack/ui";
|
|
15
|
-
import { Trash2, Edit } from "lucide-react";
|
|
16
|
+
import { Trash2, Edit, Pause, Play } from "lucide-react";
|
|
16
17
|
|
|
17
18
|
interface HealthCheckListProps {
|
|
18
19
|
configurations: HealthCheckConfiguration[];
|
|
19
20
|
strategies: HealthCheckStrategyDto[];
|
|
20
21
|
onEdit: (config: HealthCheckConfiguration) => void;
|
|
21
22
|
onDelete: (id: string) => void;
|
|
23
|
+
onPause?: (id: string) => void;
|
|
24
|
+
onResume?: (id: string) => void;
|
|
25
|
+
canManage?: boolean;
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
export const HealthCheckList: React.FC<HealthCheckListProps> = ({
|
|
@@ -26,6 +30,9 @@ export const HealthCheckList: React.FC<HealthCheckListProps> = ({
|
|
|
26
30
|
strategies,
|
|
27
31
|
onEdit,
|
|
28
32
|
onDelete,
|
|
33
|
+
onPause,
|
|
34
|
+
onResume,
|
|
35
|
+
canManage = true,
|
|
29
36
|
}) => {
|
|
30
37
|
const getStrategyName = (id: string) => {
|
|
31
38
|
return strategies.find((s) => s.id === id)?.displayName || id;
|
|
@@ -39,24 +46,57 @@ export const HealthCheckList: React.FC<HealthCheckListProps> = ({
|
|
|
39
46
|
<TableHead>Name</TableHead>
|
|
40
47
|
<TableHead>Strategy</TableHead>
|
|
41
48
|
<TableHead>Interval (s)</TableHead>
|
|
49
|
+
<TableHead>Status</TableHead>
|
|
42
50
|
<TableHead className="text-right">Actions</TableHead>
|
|
43
51
|
</TableRow>
|
|
44
52
|
</TableHeader>
|
|
45
53
|
<TableBody>
|
|
46
54
|
{configurations.length === 0 ? (
|
|
47
55
|
<TableRow>
|
|
48
|
-
<TableCell colSpan={
|
|
56
|
+
<TableCell colSpan={5} className="h-24 text-center">
|
|
49
57
|
No health checks configured.
|
|
50
58
|
</TableCell>
|
|
51
59
|
</TableRow>
|
|
52
60
|
) : (
|
|
53
61
|
configurations.map((config) => (
|
|
54
|
-
<TableRow
|
|
62
|
+
<TableRow
|
|
63
|
+
key={config.id}
|
|
64
|
+
className={config.paused ? "opacity-60" : ""}
|
|
65
|
+
>
|
|
55
66
|
<TableCell className="font-medium">{config.name}</TableCell>
|
|
56
67
|
<TableCell>{getStrategyName(config.strategyId)}</TableCell>
|
|
57
68
|
<TableCell>{config.intervalSeconds}</TableCell>
|
|
69
|
+
<TableCell>
|
|
70
|
+
{config.paused ? (
|
|
71
|
+
<Badge variant="secondary">Paused</Badge>
|
|
72
|
+
) : (
|
|
73
|
+
<Badge variant="default">Active</Badge>
|
|
74
|
+
)}
|
|
75
|
+
</TableCell>
|
|
58
76
|
<TableCell className="text-right">
|
|
59
77
|
<div className="flex justify-end gap-2">
|
|
78
|
+
{canManage &&
|
|
79
|
+
onPause &&
|
|
80
|
+
onResume &&
|
|
81
|
+
(config.paused ? (
|
|
82
|
+
<Button
|
|
83
|
+
variant="ghost"
|
|
84
|
+
size="icon"
|
|
85
|
+
onClick={() => onResume(config.id)}
|
|
86
|
+
title="Resume health check"
|
|
87
|
+
>
|
|
88
|
+
<Play className="h-4 w-4" />
|
|
89
|
+
</Button>
|
|
90
|
+
) : (
|
|
91
|
+
<Button
|
|
92
|
+
variant="ghost"
|
|
93
|
+
size="icon"
|
|
94
|
+
onClick={() => onPause(config.id)}
|
|
95
|
+
title="Pause health check"
|
|
96
|
+
>
|
|
97
|
+
<Pause className="h-4 w-4" />
|
|
98
|
+
</Button>
|
|
99
|
+
))}
|
|
60
100
|
<Button
|
|
61
101
|
variant="ghost"
|
|
62
102
|
size="icon"
|
|
@@ -64,14 +104,16 @@ export const HealthCheckList: React.FC<HealthCheckListProps> = ({
|
|
|
64
104
|
>
|
|
65
105
|
<Edit className="h-4 w-4" />
|
|
66
106
|
</Button>
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
107
|
+
{canManage && (
|
|
108
|
+
<Button
|
|
109
|
+
variant="ghost"
|
|
110
|
+
size="icon"
|
|
111
|
+
className="text-destructive hover:text-destructive"
|
|
112
|
+
onClick={() => onDelete(config.id)}
|
|
113
|
+
>
|
|
114
|
+
<Trash2 className="h-4 w-4" />
|
|
115
|
+
</Button>
|
|
116
|
+
)}
|
|
75
117
|
</div>
|
|
76
118
|
</TableCell>
|
|
77
119
|
</TableRow>
|
|
@@ -180,10 +180,7 @@ const ExpandedDetails: React.FC<ExpandedRowProps> = ({ item, systemId }) => {
|
|
|
180
180
|
</div>
|
|
181
181
|
|
|
182
182
|
{/* Date Range Filter */}
|
|
183
|
-
<
|
|
184
|
-
<span className="text-sm text-muted-foreground">Time Range:</span>
|
|
185
|
-
<DateRangeFilter value={dateRange} onChange={setDateRange} />
|
|
186
|
-
</div>
|
|
183
|
+
<DateRangeFilter value={dateRange} onChange={setDateRange} />
|
|
187
184
|
|
|
188
185
|
{/* Charts Section */}
|
|
189
186
|
{renderCharts()}
|
|
@@ -301,28 +298,31 @@ export function HealthCheckSystemOverview(props: SlotProps) {
|
|
|
301
298
|
return (
|
|
302
299
|
<div key={item.configurationId} className="rounded-md border bg-card">
|
|
303
300
|
<button
|
|
304
|
-
className="w-full
|
|
301
|
+
className="w-full p-4 text-left hover:bg-muted/50 transition-colors"
|
|
305
302
|
onClick={() =>
|
|
306
303
|
setExpandedRow(isExpanded ? undefined : item.configurationId)
|
|
307
304
|
}
|
|
308
305
|
>
|
|
306
|
+
{/* Header row: chevron, name, badge */}
|
|
309
307
|
<div className="flex items-center gap-3">
|
|
310
308
|
{isExpanded ? (
|
|
311
|
-
<ChevronDown className="h-4 w-4 text-muted-foreground" />
|
|
309
|
+
<ChevronDown className="h-4 w-4 text-muted-foreground shrink-0" />
|
|
312
310
|
) : (
|
|
313
|
-
<ChevronRight className="h-4 w-4 text-muted-foreground" />
|
|
311
|
+
<ChevronRight className="h-4 w-4 text-muted-foreground shrink-0" />
|
|
314
312
|
)}
|
|
315
|
-
<div>
|
|
316
|
-
<
|
|
317
|
-
<
|
|
318
|
-
Last run:{" "}
|
|
319
|
-
{item.lastRunAt
|
|
320
|
-
? formatDistanceToNow(item.lastRunAt, { addSuffix: true })
|
|
321
|
-
: "never"}
|
|
322
|
-
</div>
|
|
313
|
+
<div className="flex-1 min-w-0 flex items-center justify-between gap-2">
|
|
314
|
+
<span className="font-medium truncate">{item.name}</span>
|
|
315
|
+
<HealthBadge status={item.state} />
|
|
323
316
|
</div>
|
|
324
317
|
</div>
|
|
325
|
-
|
|
318
|
+
{/* Details row: last run + sparkline */}
|
|
319
|
+
<div className="ml-7 mt-1 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2">
|
|
320
|
+
<span className="text-sm text-muted-foreground">
|
|
321
|
+
Last run:{" "}
|
|
322
|
+
{item.lastRunAt
|
|
323
|
+
? formatDistanceToNow(item.lastRunAt, { addSuffix: true })
|
|
324
|
+
: "never"}
|
|
325
|
+
</span>
|
|
326
326
|
{item.recentStatusHistory.length > 0 && (
|
|
327
327
|
<HealthCheckSparkline
|
|
328
328
|
runs={item.recentStatusHistory.map((status) => ({
|
|
@@ -330,7 +330,6 @@ export function HealthCheckSystemOverview(props: SlotProps) {
|
|
|
330
330
|
}))}
|
|
331
331
|
/>
|
|
332
332
|
)}
|
|
333
|
-
<HealthBadge status={item.state} />
|
|
334
333
|
</div>
|
|
335
334
|
</button>
|
|
336
335
|
{isExpanded && <ExpandedDetails item={item} systemId={systemId} />}
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
PageLayout,
|
|
22
22
|
useToast,
|
|
23
23
|
} from "@checkstack/ui";
|
|
24
|
-
import { Plus, History } from "lucide-react";
|
|
24
|
+
import { Plus, History, Activity } from "lucide-react";
|
|
25
25
|
import { Link } from "react-router-dom";
|
|
26
26
|
import { resolveRoute } from "@checkstack/common";
|
|
27
27
|
|
|
@@ -31,10 +31,10 @@ const HealthCheckConfigPageContent = () => {
|
|
|
31
31
|
const toast = useToast();
|
|
32
32
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
33
33
|
const { allowed: canRead, loading: accessLoading } = accessApi.useAccess(
|
|
34
|
-
healthCheckAccess.configuration.read
|
|
34
|
+
healthCheckAccess.configuration.read,
|
|
35
35
|
);
|
|
36
36
|
const { allowed: canManage } = accessApi.useAccess(
|
|
37
|
-
healthCheckAccess.configuration.manage
|
|
37
|
+
healthCheckAccess.configuration.manage,
|
|
38
38
|
);
|
|
39
39
|
|
|
40
40
|
const [isEditorOpen, setIsEditorOpen] = useState(false);
|
|
@@ -52,7 +52,7 @@ const HealthCheckConfigPageContent = () => {
|
|
|
52
52
|
|
|
53
53
|
// Fetch strategies with useQuery
|
|
54
54
|
const { data: strategies = [] } = healthCheckClient.getStrategies.useQuery(
|
|
55
|
-
{}
|
|
55
|
+
{},
|
|
56
56
|
);
|
|
57
57
|
|
|
58
58
|
const configurations = configurationsData?.configurations ?? [];
|
|
@@ -100,6 +100,24 @@ const HealthCheckConfigPageContent = () => {
|
|
|
100
100
|
},
|
|
101
101
|
});
|
|
102
102
|
|
|
103
|
+
const pauseMutation = healthCheckClient.pauseConfiguration.useMutation({
|
|
104
|
+
onSuccess: () => {
|
|
105
|
+
void refetchConfigurations();
|
|
106
|
+
},
|
|
107
|
+
onError: (error) => {
|
|
108
|
+
toast.error(error instanceof Error ? error.message : "Failed to pause");
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const resumeMutation = healthCheckClient.resumeConfiguration.useMutation({
|
|
113
|
+
onSuccess: () => {
|
|
114
|
+
void refetchConfigurations();
|
|
115
|
+
},
|
|
116
|
+
onError: (error) => {
|
|
117
|
+
toast.error(error instanceof Error ? error.message : "Failed to resume");
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
103
121
|
const handleCreate = () => {
|
|
104
122
|
setEditingConfig(undefined);
|
|
105
123
|
setIsEditorOpen(true);
|
|
@@ -137,6 +155,7 @@ const HealthCheckConfigPageContent = () => {
|
|
|
137
155
|
<PageLayout
|
|
138
156
|
title="Health Checks"
|
|
139
157
|
subtitle="Manage health check configurations"
|
|
158
|
+
icon={Activity}
|
|
140
159
|
loading={accessLoading}
|
|
141
160
|
allowed={canRead}
|
|
142
161
|
actions={
|
|
@@ -159,6 +178,9 @@ const HealthCheckConfigPageContent = () => {
|
|
|
159
178
|
strategies={strategies}
|
|
160
179
|
onEdit={handleEdit}
|
|
161
180
|
onDelete={handleDelete}
|
|
181
|
+
onPause={(id) => pauseMutation.mutate(id)}
|
|
182
|
+
onResume={(id) => resumeMutation.mutate(id)}
|
|
183
|
+
canManage={canManage}
|
|
162
184
|
/>
|
|
163
185
|
|
|
164
186
|
<HealthCheckEditor
|
|
@@ -184,5 +206,5 @@ const HealthCheckConfigPageContent = () => {
|
|
|
184
206
|
};
|
|
185
207
|
|
|
186
208
|
export const HealthCheckConfigPage = wrapInSuspense(
|
|
187
|
-
HealthCheckConfigPageContent
|
|
209
|
+
HealthCheckConfigPageContent,
|
|
188
210
|
);
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
type DateRange,
|
|
26
26
|
} from "@checkstack/ui";
|
|
27
27
|
import { useParams } from "react-router-dom";
|
|
28
|
+
import { History } from "lucide-react";
|
|
28
29
|
import {
|
|
29
30
|
HealthCheckRunsTable,
|
|
30
31
|
type HealthCheckRunDetailed,
|
|
@@ -39,7 +40,7 @@ const HealthCheckHistoryDetailPageContent = () => {
|
|
|
39
40
|
const healthCheckClient = usePluginClient(HealthCheckApi);
|
|
40
41
|
const accessApi = useApi(accessApiRef);
|
|
41
42
|
const { allowed: canManage, loading: accessLoading } = accessApi.useAccess(
|
|
42
|
-
healthCheckAccess.configuration.manage
|
|
43
|
+
healthCheckAccess.configuration.manage,
|
|
43
44
|
);
|
|
44
45
|
|
|
45
46
|
const [dateRange, setDateRange] = useState<DateRange>(getDefaultDateRange);
|
|
@@ -67,8 +68,9 @@ const HealthCheckHistoryDetailPageContent = () => {
|
|
|
67
68
|
title="Health Check Run History"
|
|
68
69
|
subtitle={`System: ${systemId} • Configuration: ${configurationId?.slice(
|
|
69
70
|
0,
|
|
70
|
-
8
|
|
71
|
+
8,
|
|
71
72
|
)}...`}
|
|
73
|
+
icon={History}
|
|
72
74
|
loading={accessLoading}
|
|
73
75
|
allowed={canManage}
|
|
74
76
|
actions={
|
|
@@ -100,5 +102,5 @@ const HealthCheckHistoryDetailPageContent = () => {
|
|
|
100
102
|
};
|
|
101
103
|
|
|
102
104
|
export const HealthCheckHistoryDetailPage = wrapInSuspense(
|
|
103
|
-
HealthCheckHistoryDetailPageContent
|
|
105
|
+
HealthCheckHistoryDetailPageContent,
|
|
104
106
|
);
|
|
@@ -21,12 +21,13 @@ import {
|
|
|
21
21
|
healthCheckAccess,
|
|
22
22
|
HealthCheckApi,
|
|
23
23
|
} from "@checkstack/healthcheck-common";
|
|
24
|
+
import { History } from "lucide-react";
|
|
24
25
|
|
|
25
26
|
const HealthCheckHistoryPageContent = () => {
|
|
26
27
|
const healthCheckClient = usePluginClient(HealthCheckApi);
|
|
27
28
|
const accessApi = useApi(accessApiRef);
|
|
28
29
|
const { allowed: canManage, loading: accessLoading } = accessApi.useAccess(
|
|
29
|
-
healthCheckAccess.configuration.manage
|
|
30
|
+
healthCheckAccess.configuration.manage,
|
|
30
31
|
);
|
|
31
32
|
|
|
32
33
|
// Pagination state
|
|
@@ -47,6 +48,7 @@ const HealthCheckHistoryPageContent = () => {
|
|
|
47
48
|
<PageLayout
|
|
48
49
|
title="Health Check History"
|
|
49
50
|
subtitle="Detailed run history with full result data"
|
|
51
|
+
icon={History}
|
|
50
52
|
loading={accessLoading}
|
|
51
53
|
allowed={canManage}
|
|
52
54
|
>
|
|
@@ -68,5 +70,5 @@ const HealthCheckHistoryPageContent = () => {
|
|
|
68
70
|
};
|
|
69
71
|
|
|
70
72
|
export const HealthCheckHistoryPage = wrapInSuspense(
|
|
71
|
-
HealthCheckHistoryPageContent
|
|
73
|
+
HealthCheckHistoryPageContent,
|
|
72
74
|
);
|