@checkstack/healthcheck-frontend 0.2.0 → 0.3.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 +104 -0
- package/package.json +1 -1
- package/src/auto-charts/schema-parser.ts +1 -1
- package/src/components/AssertionBuilder.tsx +8 -0
- package/src/components/HealthCheckDiagram.tsx +6 -6
- package/src/components/HealthCheckMenuItems.tsx +4 -7
- package/src/components/SystemHealthCheckAssignment.tsx +5 -5
- package/src/hooks/useHealthCheckData.ts +29 -29
- package/src/index.tsx +4 -4
- package/src/pages/HealthCheckConfigPage.tsx +8 -8
- package/src/pages/HealthCheckHistoryDetailPage.tsx +9 -6
- package/src/pages/HealthCheckHistoryPage.tsx +6 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,109 @@
|
|
|
1
1
|
# @checkstack/healthcheck-frontend
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 9faec1f: # Unified AccessRule Terminology Refactoring
|
|
8
|
+
|
|
9
|
+
This release completes a comprehensive terminology refactoring from "permission" to "accessRule" across the entire codebase, establishing a consistent and modern access control vocabulary.
|
|
10
|
+
|
|
11
|
+
## Changes
|
|
12
|
+
|
|
13
|
+
### Core Infrastructure (`@checkstack/common`)
|
|
14
|
+
|
|
15
|
+
- Introduced `AccessRule` interface as the primary access control type
|
|
16
|
+
- Added `accessPair()` helper for creating read/manage access rule pairs
|
|
17
|
+
- Added `access()` builder for individual access rules
|
|
18
|
+
- Replaced `Permission` type with `AccessRule` throughout
|
|
19
|
+
|
|
20
|
+
### API Changes
|
|
21
|
+
|
|
22
|
+
- `env.registerPermissions()` → `env.registerAccessRules()`
|
|
23
|
+
- `meta.permissions` → `meta.access` in RPC contracts
|
|
24
|
+
- `usePermission()` → `useAccess()` in frontend hooks
|
|
25
|
+
- Route `permission:` field → `accessRule:` field
|
|
26
|
+
|
|
27
|
+
### UI Changes
|
|
28
|
+
|
|
29
|
+
- "Roles & Permissions" tab → "Roles & Access Rules"
|
|
30
|
+
- "You don't have permission..." → "You don't have access..."
|
|
31
|
+
- All permission-related UI text updated
|
|
32
|
+
|
|
33
|
+
### Documentation & Templates
|
|
34
|
+
|
|
35
|
+
- Updated 18 documentation files with AccessRule terminology
|
|
36
|
+
- Updated 7 scaffolding templates with `accessPair()` pattern
|
|
37
|
+
- All code examples use new AccessRule API
|
|
38
|
+
|
|
39
|
+
## Migration Guide
|
|
40
|
+
|
|
41
|
+
### Backend Plugins
|
|
42
|
+
|
|
43
|
+
```diff
|
|
44
|
+
- import { permissionList } from "./permissions";
|
|
45
|
+
- env.registerPermissions(permissionList);
|
|
46
|
+
+ import { accessRules } from "./access";
|
|
47
|
+
+ env.registerAccessRules(accessRules);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### RPC Contracts
|
|
51
|
+
|
|
52
|
+
```diff
|
|
53
|
+
- .meta({ userType: "user", permissions: [permissions.read.id] })
|
|
54
|
+
+ .meta({ userType: "user", access: [access.read] })
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Frontend Hooks
|
|
58
|
+
|
|
59
|
+
```diff
|
|
60
|
+
- const canRead = accessApi.usePermission(permissions.read.id);
|
|
61
|
+
+ const canRead = accessApi.useAccess(access.read);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Routes
|
|
65
|
+
|
|
66
|
+
```diff
|
|
67
|
+
- permission: permissions.entityRead.id,
|
|
68
|
+
+ accessRule: access.read,
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- 827b286: Add array assertion operators for string array fields
|
|
72
|
+
|
|
73
|
+
New operators for asserting on array fields (e.g., playerNames in RCON collectors):
|
|
74
|
+
|
|
75
|
+
- **includes** - Check if array contains a specific value
|
|
76
|
+
- **notIncludes** - Check if array does NOT contain a specific value
|
|
77
|
+
- **lengthEquals** - Check if array length equals a value
|
|
78
|
+
- **lengthGreaterThan** - Check if array length is greater than a value
|
|
79
|
+
- **lengthLessThan** - Check if array length is less than a value
|
|
80
|
+
- **isEmpty** - Check if array is empty
|
|
81
|
+
- **isNotEmpty** - Check if array has at least one element
|
|
82
|
+
|
|
83
|
+
Also exports a new `arrayField()` schema factory for creating array assertion schemas.
|
|
84
|
+
|
|
85
|
+
### Patch Changes
|
|
86
|
+
|
|
87
|
+
- f533141: Enforce health result factory function usage via branded types
|
|
88
|
+
|
|
89
|
+
- Added `healthResultSchema()` builder that enforces the use of factory functions at compile-time
|
|
90
|
+
- Added `healthResultArray()` factory for array fields (e.g., DNS resolved values)
|
|
91
|
+
- Added branded `HealthResultField<T>` type to mark schemas created by factory functions
|
|
92
|
+
- Consolidated `ChartType` and `HealthResultMeta` into `@checkstack/common` as single source of truth
|
|
93
|
+
- Updated all 12 health check strategies and 11 collectors to use `healthResultSchema()`
|
|
94
|
+
- Using raw `z.number()` etc. inside `healthResultSchema()` now causes a TypeScript error
|
|
95
|
+
|
|
96
|
+
- Updated dependencies [9faec1f]
|
|
97
|
+
- Updated dependencies [95eeec7]
|
|
98
|
+
- Updated dependencies [f533141]
|
|
99
|
+
- @checkstack/auth-frontend@0.2.0
|
|
100
|
+
- @checkstack/catalog-common@1.1.0
|
|
101
|
+
- @checkstack/common@0.2.0
|
|
102
|
+
- @checkstack/frontend-api@0.1.0
|
|
103
|
+
- @checkstack/healthcheck-common@0.3.0
|
|
104
|
+
- @checkstack/ui@0.2.0
|
|
105
|
+
- @checkstack/signal-frontend@0.0.6
|
|
106
|
+
|
|
3
107
|
## 0.2.0
|
|
4
108
|
|
|
5
109
|
### Minor Changes
|
package/package.json
CHANGED
|
@@ -81,6 +81,13 @@ const OPERATORS: Record<FieldType, { value: string; label: string }[]> = {
|
|
|
81
81
|
],
|
|
82
82
|
enum: [{ value: "equals", label: "Equals" }],
|
|
83
83
|
array: [
|
|
84
|
+
{ value: "includes", label: "Includes" },
|
|
85
|
+
{ value: "notIncludes", label: "Not Includes" },
|
|
86
|
+
{ value: "lengthEquals", label: "Length Equals" },
|
|
87
|
+
{ value: "lengthGreaterThan", label: "Length Greater Than" },
|
|
88
|
+
{ value: "lengthLessThan", label: "Length Less Than" },
|
|
89
|
+
{ value: "isEmpty", label: "Is Empty" },
|
|
90
|
+
{ value: "isNotEmpty", label: "Is Not Empty" },
|
|
84
91
|
{ value: "exists", label: "Exists" },
|
|
85
92
|
{ value: "notExists", label: "Not Exists" },
|
|
86
93
|
],
|
|
@@ -98,6 +105,7 @@ const OPERATORS: Record<FieldType, { value: string; label: string }[]> = {
|
|
|
98
105
|
// Operators that don't need a value input
|
|
99
106
|
const VALUE_LESS_OPERATORS = new Set([
|
|
100
107
|
"isEmpty",
|
|
108
|
+
"isNotEmpty",
|
|
101
109
|
"isTrue",
|
|
102
110
|
"isFalse",
|
|
103
111
|
"exists",
|
|
@@ -44,20 +44,20 @@ export function HealthCheckDiagram({
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
* Wrapper that shows
|
|
47
|
+
* Wrapper that shows access message when user lacks access.
|
|
48
48
|
*/
|
|
49
|
-
export function
|
|
50
|
-
|
|
49
|
+
export function HealthCheckDiagramAccessGate({
|
|
50
|
+
hasAccess,
|
|
51
51
|
children,
|
|
52
52
|
}: {
|
|
53
|
-
|
|
53
|
+
hasAccess: boolean;
|
|
54
54
|
children: React.ReactNode;
|
|
55
55
|
}) {
|
|
56
|
-
if (!
|
|
56
|
+
if (!hasAccess) {
|
|
57
57
|
return (
|
|
58
58
|
<InfoBanner variant="info">
|
|
59
59
|
Additional strategy-specific visualizations are available with the
|
|
60
|
-
"Read Health Check Details"
|
|
60
|
+
"Read Health Check Details" access rule.
|
|
61
61
|
</InfoBanner>
|
|
62
62
|
);
|
|
63
63
|
}
|
|
@@ -3,20 +3,17 @@ import { Link } from "react-router-dom";
|
|
|
3
3
|
import { Activity } from "lucide-react";
|
|
4
4
|
import type { UserMenuItemsContext } from "@checkstack/frontend-api";
|
|
5
5
|
import { DropdownMenuItem } from "@checkstack/ui";
|
|
6
|
-
import {
|
|
6
|
+
import { resolveRoute } from "@checkstack/common";
|
|
7
7
|
import {
|
|
8
8
|
healthcheckRoutes,
|
|
9
|
-
|
|
9
|
+
healthCheckAccess,
|
|
10
10
|
pluginMetadata,
|
|
11
11
|
} from "@checkstack/healthcheck-common";
|
|
12
12
|
|
|
13
13
|
export const HealthCheckMenuItems = ({
|
|
14
|
-
|
|
14
|
+
accessRules: userPerms,
|
|
15
15
|
}: UserMenuItemsContext) => {
|
|
16
|
-
const qualifiedId =
|
|
17
|
-
pluginMetadata,
|
|
18
|
-
permissions.healthCheckRead
|
|
19
|
-
);
|
|
16
|
+
const qualifiedId = `${pluginMetadata.pluginId}.${healthCheckAccess.configuration.read.id}`;
|
|
20
17
|
const canRead = userPerms.includes("*") || userPerms.includes(qualifiedId);
|
|
21
18
|
|
|
22
19
|
if (!canRead) {
|
|
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react";
|
|
|
2
2
|
import {
|
|
3
3
|
useApi,
|
|
4
4
|
type SlotContext,
|
|
5
|
-
|
|
5
|
+
accessApiRef,
|
|
6
6
|
} from "@checkstack/frontend-api";
|
|
7
7
|
import { healthCheckApiRef, HealthCheckConfiguration } from "../api";
|
|
8
8
|
import {
|
|
@@ -32,6 +32,7 @@ import type { StateThresholds } from "@checkstack/healthcheck-common";
|
|
|
32
32
|
import {
|
|
33
33
|
DEFAULT_STATE_THRESHOLDS,
|
|
34
34
|
healthcheckRoutes,
|
|
35
|
+
healthCheckAccess,
|
|
35
36
|
} from "@checkstack/healthcheck-common";
|
|
36
37
|
import { resolveRoute } from "@checkstack/common";
|
|
37
38
|
import { DEFAULT_RETENTION_CONFIG } from "@checkstack/healthcheck-common";
|
|
@@ -52,10 +53,9 @@ export const SystemHealthCheckAssignment: React.FC<Props> = ({
|
|
|
52
53
|
systemName: _systemName,
|
|
53
54
|
}) => {
|
|
54
55
|
const api = useApi(healthCheckApiRef);
|
|
55
|
-
const
|
|
56
|
-
const { allowed: canManage } =
|
|
57
|
-
|
|
58
|
-
"manage"
|
|
56
|
+
const accessApi = useApi(accessApiRef);
|
|
57
|
+
const { allowed: canManage } = accessApi.useAccess(
|
|
58
|
+
healthCheckAccess.configuration.manage
|
|
59
59
|
);
|
|
60
60
|
const [configs, setConfigs] = useState<HealthCheckConfiguration[]>([]);
|
|
61
61
|
const [associations, setAssociations] = useState<AssociationState[]>([]);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useEffect, useState, useMemo, useCallback } from "react";
|
|
2
|
-
import { useApi,
|
|
2
|
+
import { useApi, accessApiRef } from "@checkstack/frontend-api";
|
|
3
3
|
import { healthCheckApiRef } from "../api";
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
healthCheckAccess,
|
|
6
6
|
DEFAULT_RETENTION_CONFIG,
|
|
7
7
|
type RetentionConfig,
|
|
8
8
|
HEALTH_CHECK_RUN_COMPLETED,
|
|
@@ -36,10 +36,10 @@ interface UseHealthCheckDataResult {
|
|
|
36
36
|
isAggregated: boolean;
|
|
37
37
|
/** The resolved retention config */
|
|
38
38
|
retentionConfig: RetentionConfig;
|
|
39
|
-
/** Whether user has
|
|
40
|
-
|
|
41
|
-
/** Whether
|
|
42
|
-
|
|
39
|
+
/** Whether user has access to view detailed data */
|
|
40
|
+
hasAccess: boolean;
|
|
41
|
+
/** Whether access is still loading */
|
|
42
|
+
accessLoading: boolean;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/**
|
|
@@ -52,14 +52,14 @@ interface UseHealthCheckDataResult {
|
|
|
52
52
|
*
|
|
53
53
|
* @example
|
|
54
54
|
* ```tsx
|
|
55
|
-
* const { context, loading,
|
|
55
|
+
* const { context, loading, hasAccess } = useHealthCheckData({
|
|
56
56
|
* systemId,
|
|
57
57
|
* configurationId,
|
|
58
58
|
* strategyId,
|
|
59
59
|
* dateRange: { startDate, endDate },
|
|
60
60
|
* });
|
|
61
61
|
*
|
|
62
|
-
* if (!
|
|
62
|
+
* if (!hasAccess) return <NoAccessMessage />;
|
|
63
63
|
* if (loading) return <LoadingSpinner />;
|
|
64
64
|
* if (!context) return null;
|
|
65
65
|
*
|
|
@@ -75,11 +75,11 @@ export function useHealthCheckData({
|
|
|
75
75
|
offset = 0,
|
|
76
76
|
}: UseHealthCheckDataProps): UseHealthCheckDataResult {
|
|
77
77
|
const api = useApi(healthCheckApiRef);
|
|
78
|
-
const
|
|
78
|
+
const accessApi = useApi(accessApiRef);
|
|
79
79
|
|
|
80
|
-
//
|
|
81
|
-
const { allowed:
|
|
82
|
-
|
|
80
|
+
// Access state
|
|
81
|
+
const { allowed: hasAccess, loading: accessLoading } =
|
|
82
|
+
accessApi.useAccess(healthCheckAccess.details);
|
|
83
83
|
|
|
84
84
|
// Retention config state
|
|
85
85
|
const [retentionConfig, setRetentionConfig] = useState<RetentionConfig>(
|
|
@@ -160,24 +160,24 @@ export function useHealthCheckData({
|
|
|
160
160
|
|
|
161
161
|
// Fetch raw data when in raw mode
|
|
162
162
|
useEffect(() => {
|
|
163
|
-
if (!
|
|
163
|
+
if (!hasAccess || accessLoading || retentionLoading || isAggregated)
|
|
164
164
|
return;
|
|
165
165
|
fetchRawData(true);
|
|
166
166
|
}, [
|
|
167
167
|
fetchRawData,
|
|
168
|
-
|
|
169
|
-
|
|
168
|
+
hasAccess,
|
|
169
|
+
accessLoading,
|
|
170
170
|
retentionLoading,
|
|
171
171
|
isAggregated,
|
|
172
172
|
]);
|
|
173
173
|
|
|
174
174
|
// Listen for realtime health check updates to refresh data silently
|
|
175
175
|
useSignal(HEALTH_CHECK_RUN_COMPLETED, ({ systemId: changedId }) => {
|
|
176
|
-
// Only refresh if we're in raw mode (not aggregated) and have
|
|
176
|
+
// Only refresh if we're in raw mode (not aggregated) and have access
|
|
177
177
|
if (
|
|
178
178
|
changedId === systemId &&
|
|
179
|
-
|
|
180
|
-
!
|
|
179
|
+
hasAccess &&
|
|
180
|
+
!accessLoading &&
|
|
181
181
|
!retentionLoading &&
|
|
182
182
|
!isAggregated
|
|
183
183
|
) {
|
|
@@ -188,8 +188,8 @@ export function useHealthCheckData({
|
|
|
188
188
|
// Fetch aggregated data when in aggregated mode
|
|
189
189
|
useEffect(() => {
|
|
190
190
|
if (
|
|
191
|
-
!
|
|
192
|
-
|
|
191
|
+
!hasAccess ||
|
|
192
|
+
accessLoading ||
|
|
193
193
|
retentionLoading ||
|
|
194
194
|
!isAggregated
|
|
195
195
|
)
|
|
@@ -198,7 +198,7 @@ export function useHealthCheckData({
|
|
|
198
198
|
setAggregatedLoading(true);
|
|
199
199
|
// Use daily buckets for ranges > 30 days, hourly otherwise
|
|
200
200
|
const bucketSize = dateRangeDays > 30 ? "daily" : "hourly";
|
|
201
|
-
// Use detailed endpoint to get aggregatedResult since we have
|
|
201
|
+
// Use detailed endpoint to get aggregatedResult since we have access
|
|
202
202
|
api
|
|
203
203
|
.getDetailedAggregatedHistory({
|
|
204
204
|
systemId,
|
|
@@ -217,8 +217,8 @@ export function useHealthCheckData({
|
|
|
217
217
|
api,
|
|
218
218
|
systemId,
|
|
219
219
|
configurationId,
|
|
220
|
-
|
|
221
|
-
|
|
220
|
+
hasAccess,
|
|
221
|
+
accessLoading,
|
|
222
222
|
retentionLoading,
|
|
223
223
|
isAggregated,
|
|
224
224
|
dateRangeDays,
|
|
@@ -227,7 +227,7 @@ export function useHealthCheckData({
|
|
|
227
227
|
]);
|
|
228
228
|
|
|
229
229
|
const context = useMemo((): HealthCheckDiagramSlotContext | undefined => {
|
|
230
|
-
if (!
|
|
230
|
+
if (!hasAccess || accessLoading || retentionLoading) {
|
|
231
231
|
return undefined;
|
|
232
232
|
}
|
|
233
233
|
|
|
@@ -249,8 +249,8 @@ export function useHealthCheckData({
|
|
|
249
249
|
runs: rawRuns,
|
|
250
250
|
};
|
|
251
251
|
}, [
|
|
252
|
-
|
|
253
|
-
|
|
252
|
+
hasAccess,
|
|
253
|
+
accessLoading,
|
|
254
254
|
retentionLoading,
|
|
255
255
|
isAggregated,
|
|
256
256
|
systemId,
|
|
@@ -261,7 +261,7 @@ export function useHealthCheckData({
|
|
|
261
261
|
]);
|
|
262
262
|
|
|
263
263
|
const loading =
|
|
264
|
-
|
|
264
|
+
accessLoading ||
|
|
265
265
|
retentionLoading ||
|
|
266
266
|
(isAggregated ? aggregatedLoading : rawLoading);
|
|
267
267
|
|
|
@@ -270,7 +270,7 @@ export function useHealthCheckData({
|
|
|
270
270
|
loading,
|
|
271
271
|
isAggregated,
|
|
272
272
|
retentionConfig,
|
|
273
|
-
|
|
274
|
-
|
|
273
|
+
hasAccess,
|
|
274
|
+
accessLoading,
|
|
275
275
|
};
|
|
276
276
|
}
|
package/src/index.tsx
CHANGED
|
@@ -13,7 +13,7 @@ import { HealthCheckMenuItems } from "./components/HealthCheckMenuItems";
|
|
|
13
13
|
import { HealthCheckSystemOverview } from "./components/HealthCheckSystemOverview";
|
|
14
14
|
import { SystemHealthCheckAssignment } from "./components/SystemHealthCheckAssignment";
|
|
15
15
|
import { SystemHealthBadge } from "./components/SystemHealthBadge";
|
|
16
|
-
import {
|
|
16
|
+
import { healthCheckAccess } from "@checkstack/healthcheck-common";
|
|
17
17
|
import { autoChartExtension } from "./auto-charts";
|
|
18
18
|
|
|
19
19
|
import {
|
|
@@ -49,19 +49,19 @@ export default createFrontendPlugin({
|
|
|
49
49
|
route: healthcheckRoutes.routes.config,
|
|
50
50
|
element: <HealthCheckConfigPage />,
|
|
51
51
|
title: "Health Checks",
|
|
52
|
-
|
|
52
|
+
accessRule: healthCheckAccess.configuration.manage,
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
route: healthcheckRoutes.routes.history,
|
|
56
56
|
element: <HealthCheckHistoryPage />,
|
|
57
57
|
title: "Health Check History",
|
|
58
|
-
|
|
58
|
+
accessRule: healthCheckAccess.configuration.read,
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
61
|
route: healthcheckRoutes.routes.historyDetail,
|
|
62
62
|
element: <HealthCheckHistoryDetailPage />,
|
|
63
63
|
title: "Health Check Detail",
|
|
64
|
-
|
|
64
|
+
accessRule: healthCheckAccess.details,
|
|
65
65
|
},
|
|
66
66
|
],
|
|
67
67
|
apis: [
|
|
@@ -3,7 +3,7 @@ import { useSearchParams } from "react-router-dom";
|
|
|
3
3
|
import {
|
|
4
4
|
useApi,
|
|
5
5
|
wrapInSuspense,
|
|
6
|
-
|
|
6
|
+
accessApiRef,
|
|
7
7
|
} from "@checkstack/frontend-api";
|
|
8
8
|
import { healthCheckApiRef } from "../api";
|
|
9
9
|
import {
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
HealthCheckStrategyDto,
|
|
12
12
|
CreateHealthCheckConfiguration,
|
|
13
13
|
healthcheckRoutes,
|
|
14
|
+
healthCheckAccess,
|
|
14
15
|
} from "@checkstack/healthcheck-common";
|
|
15
16
|
import { HealthCheckList } from "../components/HealthCheckList";
|
|
16
17
|
import { HealthCheckEditor } from "../components/HealthCheckEditor";
|
|
@@ -21,13 +22,12 @@ import { resolveRoute } from "@checkstack/common";
|
|
|
21
22
|
|
|
22
23
|
const HealthCheckConfigPageContent = () => {
|
|
23
24
|
const api = useApi(healthCheckApiRef);
|
|
24
|
-
const
|
|
25
|
+
const accessApi = useApi(accessApiRef);
|
|
25
26
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
26
|
-
const { allowed: canRead, loading:
|
|
27
|
-
|
|
28
|
-
const { allowed: canManage } =
|
|
29
|
-
|
|
30
|
-
"manage"
|
|
27
|
+
const { allowed: canRead, loading: accessLoading } =
|
|
28
|
+
accessApi.useAccess(healthCheckAccess.configuration.read);
|
|
29
|
+
const { allowed: canManage } = accessApi.useAccess(
|
|
30
|
+
healthCheckAccess.configuration.manage
|
|
31
31
|
);
|
|
32
32
|
|
|
33
33
|
const [configurations, setConfigurations] = useState<
|
|
@@ -113,7 +113,7 @@ const HealthCheckConfigPageContent = () => {
|
|
|
113
113
|
<PageLayout
|
|
114
114
|
title="Health Checks"
|
|
115
115
|
subtitle="Manage health check configurations"
|
|
116
|
-
loading={
|
|
116
|
+
loading={accessLoading}
|
|
117
117
|
allowed={canRead}
|
|
118
118
|
actions={
|
|
119
119
|
<div className="flex gap-2">
|
|
@@ -2,10 +2,13 @@ import { useState } from "react";
|
|
|
2
2
|
import {
|
|
3
3
|
useApi,
|
|
4
4
|
wrapInSuspense,
|
|
5
|
-
|
|
5
|
+
accessApiRef,
|
|
6
6
|
} from "@checkstack/frontend-api";
|
|
7
7
|
import { healthCheckApiRef } from "../api";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
healthcheckRoutes,
|
|
10
|
+
healthCheckAccess,
|
|
11
|
+
} from "@checkstack/healthcheck-common";
|
|
9
12
|
import { resolveRoute } from "@checkstack/common";
|
|
10
13
|
import {
|
|
11
14
|
PageLayout,
|
|
@@ -32,9 +35,9 @@ const HealthCheckHistoryDetailPageContent = () => {
|
|
|
32
35
|
}>();
|
|
33
36
|
|
|
34
37
|
const api = useApi(healthCheckApiRef);
|
|
35
|
-
const
|
|
36
|
-
const { allowed: canManage, loading:
|
|
37
|
-
|
|
38
|
+
const accessApi = useApi(accessApiRef);
|
|
39
|
+
const { allowed: canManage, loading: accessLoading } =
|
|
40
|
+
accessApi.useAccess(healthCheckAccess.configuration.manage);
|
|
38
41
|
|
|
39
42
|
const [dateRange, setDateRange] = useState<DateRange>(getDefaultDateRange);
|
|
40
43
|
|
|
@@ -65,7 +68,7 @@ const HealthCheckHistoryDetailPageContent = () => {
|
|
|
65
68
|
0,
|
|
66
69
|
8
|
|
67
70
|
)}...`}
|
|
68
|
-
loading={
|
|
71
|
+
loading={accessLoading}
|
|
69
72
|
allowed={canManage}
|
|
70
73
|
actions={
|
|
71
74
|
<BackLink to={resolveRoute(healthcheckRoutes.routes.history)}>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useApi,
|
|
3
3
|
wrapInSuspense,
|
|
4
|
-
|
|
4
|
+
accessApiRef,
|
|
5
5
|
} from "@checkstack/frontend-api";
|
|
6
6
|
import { healthCheckApiRef } from "../api";
|
|
7
7
|
import {
|
|
@@ -16,12 +16,13 @@ import {
|
|
|
16
16
|
HealthCheckRunsTable,
|
|
17
17
|
type HealthCheckRunDetailed,
|
|
18
18
|
} from "../components/HealthCheckRunsTable";
|
|
19
|
+
import { healthCheckAccess } from "@checkstack/healthcheck-common";
|
|
19
20
|
|
|
20
21
|
const HealthCheckHistoryPageContent = () => {
|
|
21
22
|
const api = useApi(healthCheckApiRef);
|
|
22
|
-
const
|
|
23
|
-
const { allowed: canManage, loading:
|
|
24
|
-
|
|
23
|
+
const accessApi = useApi(accessApiRef);
|
|
24
|
+
const { allowed: canManage, loading: accessLoading } =
|
|
25
|
+
accessApi.useAccess(healthCheckAccess.configuration.manage);
|
|
25
26
|
|
|
26
27
|
const {
|
|
27
28
|
items: runs,
|
|
@@ -42,7 +43,7 @@ const HealthCheckHistoryPageContent = () => {
|
|
|
42
43
|
<PageLayout
|
|
43
44
|
title="Health Check History"
|
|
44
45
|
subtitle="Detailed run history with full result data"
|
|
45
|
-
loading={
|
|
46
|
+
loading={accessLoading}
|
|
46
47
|
allowed={canManage}
|
|
47
48
|
>
|
|
48
49
|
<Card>
|