@checkstack/incident-frontend 0.4.25 → 0.5.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 +42 -0
- package/package.json +1 -1
- package/src/components/SystemIncidentPanel.tsx +62 -157
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# @checkstack/incident-frontend
|
|
2
2
|
|
|
3
|
+
## 0.5.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- @checkstack/dashboard-frontend@0.4.1
|
|
8
|
+
|
|
9
|
+
## 0.5.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- bb1fea0: Redesign system detail page with hero banner, two-column layout, plugin metric tiles, and health check slide-over drawer.
|
|
14
|
+
|
|
15
|
+
### New Components
|
|
16
|
+
|
|
17
|
+
- **MetricTile** (`@checkstack/ui`): Compact stat tile with icon, label, value, variant coloring
|
|
18
|
+
- **Sheet** (`@checkstack/ui`): Slide-over drawer built on Radix Dialog primitives
|
|
19
|
+
|
|
20
|
+
### New Extension Slot
|
|
21
|
+
|
|
22
|
+
- **SystemOverviewMetricsSlot** (`@checkstack/catalog-common`): Plugin-contributed at-a-glance metric tiles in the system detail hero banner
|
|
23
|
+
|
|
24
|
+
### Layout Changes
|
|
25
|
+
|
|
26
|
+
- System detail page now uses a hero banner with breadcrumb, status badges, and metric tile strip
|
|
27
|
+
- Two-column layout: monitoring content (left) and system context (right)
|
|
28
|
+
- Health checks rendered as compact card rows instead of heavy accordions
|
|
29
|
+
- Clicking a health check opens a slide-over drawer with summary tiles, timeline charts, and recent runs
|
|
30
|
+
- Right column uses lightweight borderless sections with dividers instead of heavy Card wrappers
|
|
31
|
+
|
|
32
|
+
### Plugin Extensions
|
|
33
|
+
|
|
34
|
+
- Health check, SLO, Incident, and Maintenance plugins each contribute a metric tile to the hero banner
|
|
35
|
+
|
|
36
|
+
### Patch Changes
|
|
37
|
+
|
|
38
|
+
- Updated dependencies [bb1fea0]
|
|
39
|
+
- Updated dependencies [bb1fea0]
|
|
40
|
+
- @checkstack/dashboard-frontend@0.4.0
|
|
41
|
+
- @checkstack/ui@1.4.0
|
|
42
|
+
- @checkstack/catalog-common@1.4.0
|
|
43
|
+
- @checkstack/auth-frontend@0.5.26
|
|
44
|
+
|
|
3
45
|
## 0.4.25
|
|
4
46
|
|
|
5
47
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -10,49 +10,13 @@ import {
|
|
|
10
10
|
INCIDENT_UPDATED,
|
|
11
11
|
type IncidentWithSystems,
|
|
12
12
|
} from "@checkstack/incident-common";
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
CardHeader,
|
|
16
|
-
CardTitle,
|
|
17
|
-
CardContent,
|
|
18
|
-
Badge,
|
|
19
|
-
LoadingSpinner,
|
|
20
|
-
Button,
|
|
21
|
-
} from "@checkstack/ui";
|
|
22
|
-
import { AlertTriangle, Clock, History, ChevronRight } from "lucide-react";
|
|
23
|
-
import { formatDistanceToNow } from "date-fns";
|
|
13
|
+
import { Badge, LoadingSpinner, Button } from "@checkstack/ui";
|
|
14
|
+
import { AlertTriangle, History } from "lucide-react";
|
|
24
15
|
|
|
25
16
|
type Props = SlotContext<typeof SystemDetailsTopSlot>;
|
|
26
17
|
|
|
27
18
|
const SEVERITY_WEIGHTS = { critical: 3, major: 2, minor: 1 } as const;
|
|
28
19
|
|
|
29
|
-
function getSeverityColor(severity: string): string {
|
|
30
|
-
switch (severity) {
|
|
31
|
-
case "critical": {
|
|
32
|
-
return "border-destructive/30 bg-destructive/5";
|
|
33
|
-
}
|
|
34
|
-
case "major": {
|
|
35
|
-
return "border-warning/30 bg-warning/5";
|
|
36
|
-
}
|
|
37
|
-
default: {
|
|
38
|
-
return "border-info/30 bg-info/5";
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function getSeverityHeaderColor(severity: string): string {
|
|
44
|
-
switch (severity) {
|
|
45
|
-
case "critical": {
|
|
46
|
-
return "bg-destructive/10";
|
|
47
|
-
}
|
|
48
|
-
case "major": {
|
|
49
|
-
return "bg-warning/10";
|
|
50
|
-
}
|
|
51
|
-
default: {
|
|
52
|
-
return "bg-info/10";
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
20
|
|
|
57
21
|
function findMostSevereIncident(
|
|
58
22
|
incidents: IncidentWithSystems[]
|
|
@@ -97,137 +61,78 @@ export const SystemIncidentPanel: React.FC<Props> = ({ system }) => {
|
|
|
97
61
|
|
|
98
62
|
if (loading) {
|
|
99
63
|
return (
|
|
100
|
-
<
|
|
101
|
-
<
|
|
102
|
-
|
|
103
|
-
</CardContent>
|
|
104
|
-
</Card>
|
|
64
|
+
<div className="flex items-center justify-center rounded-md border border-border/50 bg-card px-3 py-2">
|
|
65
|
+
<LoadingSpinner />
|
|
66
|
+
</div>
|
|
105
67
|
);
|
|
106
68
|
}
|
|
107
69
|
|
|
108
70
|
if (incidents.length === 0) {
|
|
109
|
-
// Show a subtle card with just the history button when no active incidents
|
|
110
71
|
return (
|
|
111
|
-
<
|
|
112
|
-
<
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
</Button>
|
|
128
|
-
</div>
|
|
129
|
-
</CardContent>
|
|
130
|
-
</Card>
|
|
72
|
+
<div className="flex items-center justify-between rounded-md border border-border/50 bg-card px-3 py-2">
|
|
73
|
+
<div className="flex items-center gap-2 text-muted-foreground">
|
|
74
|
+
<AlertTriangle className="h-3.5 w-3.5" />
|
|
75
|
+
<span className="text-sm">No active incidents</span>
|
|
76
|
+
</div>
|
|
77
|
+
<Button variant="ghost" size="sm" className="h-7 text-xs" asChild>
|
|
78
|
+
<Link
|
|
79
|
+
to={resolveRoute(incidentRoutes.routes.systemHistory, {
|
|
80
|
+
systemId: system.id,
|
|
81
|
+
})}
|
|
82
|
+
>
|
|
83
|
+
<History className="h-3 w-3 mr-1" />
|
|
84
|
+
History
|
|
85
|
+
</Link>
|
|
86
|
+
</Button>
|
|
87
|
+
</div>
|
|
131
88
|
);
|
|
132
89
|
}
|
|
133
90
|
|
|
134
|
-
const getStatusBadge = (status: string) => {
|
|
135
|
-
switch (status) {
|
|
136
|
-
case "investigating": {
|
|
137
|
-
return <Badge variant="destructive">Investigating</Badge>;
|
|
138
|
-
}
|
|
139
|
-
case "identified": {
|
|
140
|
-
return <Badge variant="warning">Identified</Badge>;
|
|
141
|
-
}
|
|
142
|
-
case "fixing": {
|
|
143
|
-
return <Badge variant="warning">Fixing</Badge>;
|
|
144
|
-
}
|
|
145
|
-
case "monitoring": {
|
|
146
|
-
return <Badge variant="info">Monitoring</Badge>;
|
|
147
|
-
}
|
|
148
|
-
default: {
|
|
149
|
-
return <Badge>{status}</Badge>;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
// Use the most severe incident for the card styling
|
|
155
91
|
const mostSevere = findMostSevereIncident(incidents);
|
|
92
|
+
const severityColor =
|
|
93
|
+
mostSevere.severity === "critical"
|
|
94
|
+
? "border-destructive/30 bg-destructive/5"
|
|
95
|
+
: mostSevere.severity === "major"
|
|
96
|
+
? "border-warning/30 bg-warning/5"
|
|
97
|
+
: "border-info/30 bg-info/5";
|
|
156
98
|
|
|
157
99
|
return (
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
100
|
+
<div
|
|
101
|
+
className={`flex items-center justify-between rounded-md border px-3 py-2 ${severityColor}`}
|
|
102
|
+
>
|
|
103
|
+
<div className="flex items-center gap-2 min-w-0">
|
|
104
|
+
<AlertTriangle className="h-3.5 w-3.5 text-destructive shrink-0" />
|
|
105
|
+
<span className="text-sm font-medium truncate">
|
|
106
|
+
{incidents.length} active incident{incidents.length > 1 ? "s" : ""}
|
|
107
|
+
</span>
|
|
108
|
+
<div className="flex items-center gap-1.5">
|
|
109
|
+
{incidents.map((i) => (
|
|
110
|
+
<Badge
|
|
111
|
+
key={i.id}
|
|
112
|
+
variant={
|
|
113
|
+
i.severity === "critical"
|
|
114
|
+
? "destructive"
|
|
115
|
+
: i.severity === "major"
|
|
116
|
+
? "warning"
|
|
117
|
+
: "secondary"
|
|
118
|
+
}
|
|
119
|
+
className="text-xs"
|
|
176
120
|
>
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
</Button>
|
|
121
|
+
{i.severity}
|
|
122
|
+
</Badge>
|
|
123
|
+
))}
|
|
181
124
|
</div>
|
|
182
|
-
</
|
|
183
|
-
<
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
<h4 className="font-medium text-foreground">{i.title}</h4>
|
|
195
|
-
<ChevronRight className="h-4 w-4 text-muted-foreground" />
|
|
196
|
-
</div>
|
|
197
|
-
<div className="flex items-center gap-2">
|
|
198
|
-
<Badge
|
|
199
|
-
variant={
|
|
200
|
-
i.severity === "critical"
|
|
201
|
-
? "destructive"
|
|
202
|
-
: i.severity === "major"
|
|
203
|
-
? "warning"
|
|
204
|
-
: "secondary"
|
|
205
|
-
}
|
|
206
|
-
>
|
|
207
|
-
{i.severity}
|
|
208
|
-
</Badge>
|
|
209
|
-
{getStatusBadge(i.status)}
|
|
210
|
-
</div>
|
|
211
|
-
</div>
|
|
212
|
-
{i.description && (
|
|
213
|
-
<p className="text-sm text-muted-foreground mb-2">
|
|
214
|
-
{i.description}
|
|
215
|
-
</p>
|
|
216
|
-
)}
|
|
217
|
-
<div className="flex gap-4 text-xs text-muted-foreground">
|
|
218
|
-
<div className="flex items-center gap-1">
|
|
219
|
-
<Clock className="h-3 w-3" />
|
|
220
|
-
<span>
|
|
221
|
-
Started{" "}
|
|
222
|
-
{formatDistanceToNow(new Date(i.createdAt), {
|
|
223
|
-
addSuffix: true,
|
|
224
|
-
})}
|
|
225
|
-
</span>
|
|
226
|
-
</div>
|
|
227
|
-
</div>
|
|
228
|
-
</Link>
|
|
229
|
-
))}
|
|
230
|
-
</CardContent>
|
|
231
|
-
</Card>
|
|
125
|
+
</div>
|
|
126
|
+
<Button variant="ghost" size="sm" className="h-7 text-xs shrink-0" asChild>
|
|
127
|
+
<Link
|
|
128
|
+
to={resolveRoute(incidentRoutes.routes.systemHistory, {
|
|
129
|
+
systemId: system.id,
|
|
130
|
+
})}
|
|
131
|
+
>
|
|
132
|
+
<History className="h-3 w-3 mr-1" />
|
|
133
|
+
View
|
|
134
|
+
</Link>
|
|
135
|
+
</Button>
|
|
136
|
+
</div>
|
|
232
137
|
);
|
|
233
138
|
};
|