@checkstack/healthcheck-frontend 0.11.8 → 0.12.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.
@@ -1,190 +0,0 @@
1
- import React, { useState, useEffect } from "react";
2
- import {
3
- HealthCheckConfiguration,
4
- HealthCheckStrategyDto,
5
- CreateHealthCheckConfiguration,
6
- CollectorConfigEntry,
7
- } from "@checkstack/healthcheck-common";
8
- import {
9
- Button,
10
- Input,
11
- Label,
12
- PluginConfigForm,
13
- useToast,
14
- Dialog,
15
- DialogContent,
16
- DialogDescription,
17
- DialogHeader,
18
- DialogTitle,
19
- DialogFooter,
20
- } from "@checkstack/ui";
21
- import { useCollectors } from "../hooks/useCollectors";
22
- import { CollectorList } from "./CollectorList";
23
- import { TeamAccessEditor } from "@checkstack/auth-frontend";
24
-
25
- interface HealthCheckEditorProps {
26
- strategies: HealthCheckStrategyDto[];
27
- initialData?: HealthCheckConfiguration;
28
- onSave: (data: CreateHealthCheckConfiguration) => Promise<void>;
29
- onCancel: () => void;
30
- open: boolean;
31
- }
32
-
33
- export const HealthCheckEditor: React.FC<HealthCheckEditorProps> = ({
34
- strategies,
35
- initialData,
36
- onSave,
37
- onCancel,
38
- open,
39
- }) => {
40
- const [name, setName] = useState(initialData?.name || "");
41
- const [strategyId, setStrategyId] = useState(initialData?.strategyId || "");
42
- const [interval, setInterval] = useState(
43
- initialData?.intervalSeconds?.toString() || "60",
44
- );
45
- const [config, setConfig] = useState<Record<string, unknown>>(
46
- (initialData?.config as Record<string, unknown>) || {},
47
- );
48
- const [collectors, setCollectors] = useState<CollectorConfigEntry[]>(
49
- initialData?.collectors || [],
50
- );
51
-
52
- const toast = useToast();
53
- const [loading, setLoading] = useState(false);
54
- const [collectorsValid, setCollectorsValid] = useState(true);
55
-
56
- // Fetch available collectors for the selected strategy
57
- const { collectors: availableCollectors, loading: collectorsLoading } =
58
- useCollectors(strategyId);
59
-
60
- // Reset form when dialog opens with new data
61
- useEffect(() => {
62
- if (open) {
63
- setName(initialData?.name || "");
64
- setStrategyId(initialData?.strategyId || "");
65
- setInterval(initialData?.intervalSeconds?.toString() || "60");
66
- setConfig((initialData?.config as Record<string, unknown>) || {});
67
- setCollectors(initialData?.collectors || []);
68
- }
69
- }, [open, initialData]);
70
-
71
- // Clear collectors when strategy changes (new strategy = different collectors)
72
- const handleStrategyChange = (id: string) => {
73
- setStrategyId(id);
74
- setConfig({});
75
- setCollectors([]);
76
- };
77
-
78
- const handleSave = async (e: React.FormEvent) => {
79
- e.preventDefault();
80
- setLoading(true);
81
- try {
82
- await onSave({
83
- name,
84
- strategyId,
85
- intervalSeconds: Number.parseInt(interval, 10),
86
- config,
87
- collectors, // Always send the array, even if empty, to allow clearing
88
- });
89
- } catch (error) {
90
- const message =
91
- error instanceof Error ? error.message : "Failed to save health check";
92
- toast.error(message);
93
- console.error(error);
94
- } finally {
95
- setLoading(false);
96
- }
97
- };
98
-
99
- return (
100
- <Dialog open={open} onOpenChange={(isOpen) => !isOpen && onCancel()}>
101
- <DialogContent size="lg">
102
- <form onSubmit={handleSave}>
103
- <DialogHeader>
104
- <DialogTitle>
105
- {initialData ? "Edit Health Check" : "Create Health Check"}
106
- </DialogTitle>
107
- <DialogDescription className="sr-only">
108
- {initialData
109
- ? "Modify the settings for this health check configuration"
110
- : "Configure a new health check to monitor your services"}
111
- </DialogDescription>
112
- </DialogHeader>
113
-
114
- <div className="space-y-6 py-4">
115
- <div className="space-y-2">
116
- <Label htmlFor="name">Name</Label>
117
- <Input
118
- id="name"
119
- value={name}
120
- onChange={(e) => setName(e.target.value)}
121
- required
122
- />
123
- </div>
124
-
125
- <div className="space-y-2">
126
- <Label htmlFor="interval">Interval (seconds)</Label>
127
- <Input
128
- id="interval"
129
- type="number"
130
- min="1"
131
- value={interval}
132
- onChange={(e) => setInterval(e.target.value)}
133
- required
134
- />
135
- {Number.parseInt(interval, 10) < 60 && (
136
- <p className="text-sm text-amber-600 dark:text-amber-400">
137
- ⚠️ Sub-minute intervals generate large amounts of data and may
138
- impact chart loading performance. Consider using intervals of
139
- 60 seconds or more or drastically reduce the retention period
140
- for raw data.
141
- </p>
142
- )}
143
- </div>
144
-
145
- <PluginConfigForm
146
- label="Strategy"
147
- plugins={strategies}
148
- selectedPluginId={strategyId}
149
- onPluginChange={handleStrategyChange}
150
- config={config}
151
- onConfigChange={setConfig}
152
- disabled={!!initialData}
153
- />
154
-
155
- {/* Collector Configuration Section */}
156
- {strategyId && (
157
- <CollectorList
158
- strategyId={strategyId}
159
- availableCollectors={availableCollectors}
160
- configuredCollectors={collectors}
161
- onChange={setCollectors}
162
- loading={collectorsLoading}
163
- onValidChange={setCollectorsValid}
164
- />
165
- )}
166
-
167
- {/* Team Access Editor - only shown for existing configurations */}
168
- {initialData?.id && (
169
- <TeamAccessEditor
170
- resourceType="healthcheck.configuration"
171
- resourceId={initialData.id}
172
- compact
173
- expanded
174
- />
175
- )}
176
- </div>
177
-
178
- <DialogFooter>
179
- <Button type="button" variant="outline" onClick={onCancel}>
180
- Cancel
181
- </Button>
182
- <Button type="submit" disabled={loading || !collectorsValid}>
183
- {loading ? "Saving..." : "Save"}
184
- </Button>
185
- </DialogFooter>
186
- </form>
187
- </DialogContent>
188
- </Dialog>
189
- );
190
- };