@checkstack/ui 1.3.6 → 1.4.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 CHANGED
@@ -1,5 +1,40 @@
1
1
  # @checkstack/ui
2
2
 
3
+ ## 1.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - bb1fea0: Redesign system detail page with hero banner, two-column layout, plugin metric tiles, and health check slide-over drawer.
8
+
9
+ ### New Components
10
+
11
+ - **MetricTile** (`@checkstack/ui`): Compact stat tile with icon, label, value, variant coloring
12
+ - **Sheet** (`@checkstack/ui`): Slide-over drawer built on Radix Dialog primitives
13
+
14
+ ### New Extension Slot
15
+
16
+ - **SystemOverviewMetricsSlot** (`@checkstack/catalog-common`): Plugin-contributed at-a-glance metric tiles in the system detail hero banner
17
+
18
+ ### Layout Changes
19
+
20
+ - System detail page now uses a hero banner with breadcrumb, status badges, and metric tile strip
21
+ - Two-column layout: monitoring content (left) and system context (right)
22
+ - Health checks rendered as compact card rows instead of heavy accordions
23
+ - Clicking a health check opens a slide-over drawer with summary tiles, timeline charts, and recent runs
24
+ - Right column uses lightweight borderless sections with dividers instead of heavy Card wrappers
25
+
26
+ ### Plugin Extensions
27
+
28
+ - Health check, SLO, Incident, and Maintenance plugins each contribute a metric tile to the hero banner
29
+
30
+ ### Patch Changes
31
+
32
+ - bb1fea0: feat: implement active incident and maintenance overview sheets on dashboard
33
+
34
+ - Replaces direct routing on status cards with slide-out overview sheets to gracefully degrade for users without manage permissions
35
+ - Refactors dashboard system groups into a clean table-style list layout for better density
36
+ - Makes global status cards more compact
37
+
3
38
  ## 1.3.6
4
39
 
5
40
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checkstack/ui",
3
- "version": "1.3.6",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "dependencies": {
@@ -27,7 +27,7 @@ export interface DateRangeFilterProps {
27
27
  className?: string;
28
28
  }
29
29
 
30
- const PRESETS: Array<{
30
+ export const PRESETS: Array<{
31
31
  id: DateRangePreset;
32
32
  label: string;
33
33
  shortLabel: string;
@@ -56,7 +56,7 @@ export function getPresetRange(preset: DateRangePreset): DateRange {
56
56
  }
57
57
  }
58
58
 
59
- function detectPreset(range: DateRange): DateRangePreset {
59
+ export function detectPreset(range: DateRange): DateRangePreset {
60
60
  const now = new Date();
61
61
  const diffMs = now.getTime() - range.startDate.getTime();
62
62
  const diffHours = diffMs / (1000 * 60 * 60);
@@ -0,0 +1,50 @@
1
+ import React from "react";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import { cn } from "../utils";
4
+
5
+ const metricTileVariants = cva(
6
+ "flex items-center gap-3 rounded-lg border bg-card p-3 min-w-0",
7
+ {
8
+ variants: {
9
+ variant: {
10
+ default: "border-border",
11
+ success: "border-success/30 bg-success/5",
12
+ warning: "border-warning/30 bg-warning/5",
13
+ destructive: "border-destructive/30 bg-destructive/5",
14
+ },
15
+ },
16
+ defaultVariants: {
17
+ variant: "default",
18
+ },
19
+ },
20
+ );
21
+
22
+ interface MetricTileProps
23
+ extends React.HTMLAttributes<HTMLDivElement>,
24
+ VariantProps<typeof metricTileVariants> {
25
+ icon: React.ElementType;
26
+ label: string;
27
+ value: string;
28
+ subtitle?: string;
29
+ }
30
+
31
+ export const MetricTile: React.FC<MetricTileProps> = ({
32
+ icon: Icon,
33
+ label,
34
+ value,
35
+ subtitle,
36
+ variant,
37
+ className,
38
+ ...props
39
+ }) => (
40
+ <div className={cn(metricTileVariants({ variant }), className)} {...props}>
41
+ <Icon className="h-4 w-4 text-muted-foreground shrink-0" />
42
+ <div className="min-w-0">
43
+ <p className="text-xs text-muted-foreground truncate">{label}</p>
44
+ <p className="text-sm font-semibold truncate">{value}</p>
45
+ {subtitle && (
46
+ <p className="text-xs text-muted-foreground truncate">{subtitle}</p>
47
+ )}
48
+ </div>
49
+ </div>
50
+ );
@@ -38,7 +38,7 @@ export const PageLayout: React.FC<PageLayoutProps> = ({
38
38
  loading,
39
39
  allowed,
40
40
  children,
41
- maxWidth = "3xl",
41
+ maxWidth = "7xl",
42
42
  }) => {
43
43
  // If loading is explicitly true, show loading state
44
44
  // If loading is undefined and allowed is false, also show loading state
@@ -0,0 +1,141 @@
1
+ import * as React from "react";
2
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+ import { X } from "lucide-react";
5
+ import { cn } from "../utils";
6
+ import { usePerformance } from "./PerformanceProvider";
7
+
8
+ const Sheet = DialogPrimitive.Root;
9
+ const SheetTrigger = DialogPrimitive.Trigger;
10
+ const SheetClose = DialogPrimitive.Close;
11
+ const SheetPortal = DialogPrimitive.Portal;
12
+
13
+ const SheetOverlay = React.forwardRef<
14
+ React.ElementRef<typeof DialogPrimitive.Overlay>,
15
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
16
+ >(({ className, ...props }, ref) => {
17
+ const { isLowPower } = usePerformance();
18
+ return (
19
+ <DialogPrimitive.Overlay
20
+ ref={ref}
21
+ className={cn(
22
+ "fixed inset-0 z-50 bg-black/50",
23
+ !isLowPower &&
24
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
25
+ className,
26
+ )}
27
+ {...props}
28
+ />
29
+ );
30
+ });
31
+ SheetOverlay.displayName = "SheetOverlay";
32
+
33
+ const sheetContentVariants = cva(
34
+ "fixed z-50 flex flex-col bg-background shadow-lg border-l border-border",
35
+ {
36
+ variants: {
37
+ size: {
38
+ default: "w-full sm:max-w-lg",
39
+ lg: "w-full sm:max-w-2xl",
40
+ xl: "w-full sm:max-w-4xl",
41
+ full: "w-full",
42
+ },
43
+ },
44
+ defaultVariants: {
45
+ size: "default",
46
+ },
47
+ },
48
+ );
49
+
50
+ interface SheetContentProps
51
+ extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>,
52
+ VariantProps<typeof sheetContentVariants> {}
53
+
54
+ const SheetContent = React.forwardRef<
55
+ React.ElementRef<typeof DialogPrimitive.Content>,
56
+ SheetContentProps
57
+ >(({ className, children, size, ...props }, ref) => {
58
+ const { isLowPower } = usePerformance();
59
+ return (
60
+ <SheetPortal>
61
+ <SheetOverlay />
62
+ <DialogPrimitive.Content
63
+ ref={ref}
64
+ className={cn(
65
+ sheetContentVariants({ size }),
66
+ "inset-y-0 right-0 h-full",
67
+ !isLowPower &&
68
+ "duration-300 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right",
69
+ className,
70
+ )}
71
+ {...props}
72
+ >
73
+ {children}
74
+ <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2">
75
+ <X className="h-4 w-4" />
76
+ <span className="sr-only">Close</span>
77
+ </DialogPrimitive.Close>
78
+ </DialogPrimitive.Content>
79
+ </SheetPortal>
80
+ );
81
+ });
82
+ SheetContent.displayName = "SheetContent";
83
+
84
+ const SheetHeader = ({
85
+ className,
86
+ ...props
87
+ }: React.HTMLAttributes<HTMLDivElement>) => (
88
+ <div
89
+ className={cn(
90
+ "flex flex-col gap-1.5 p-6 pb-4 border-b border-border",
91
+ className,
92
+ )}
93
+ {...props}
94
+ />
95
+ );
96
+ SheetHeader.displayName = "SheetHeader";
97
+
98
+ const SheetTitle = React.forwardRef<
99
+ React.ElementRef<typeof DialogPrimitive.Title>,
100
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
101
+ >(({ className, ...props }, ref) => (
102
+ <DialogPrimitive.Title
103
+ ref={ref}
104
+ className={cn("text-lg font-semibold", className)}
105
+ {...props}
106
+ />
107
+ ));
108
+ SheetTitle.displayName = "SheetTitle";
109
+
110
+ const SheetDescription = React.forwardRef<
111
+ React.ElementRef<typeof DialogPrimitive.Description>,
112
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
113
+ >(({ className, ...props }, ref) => (
114
+ <DialogPrimitive.Description
115
+ ref={ref}
116
+ className={cn("text-sm text-muted-foreground", className)}
117
+ {...props}
118
+ />
119
+ ));
120
+ SheetDescription.displayName = "SheetDescription";
121
+
122
+ const SheetBody = ({
123
+ className,
124
+ ...props
125
+ }: React.HTMLAttributes<HTMLDivElement>) => (
126
+ <div className={cn("flex-1 overflow-y-auto p-6", className)} {...props} />
127
+ );
128
+ SheetBody.displayName = "SheetBody";
129
+
130
+ export {
131
+ Sheet,
132
+ SheetPortal,
133
+ SheetOverlay,
134
+ SheetTrigger,
135
+ SheetClose,
136
+ SheetContent,
137
+ SheetHeader,
138
+ SheetBody,
139
+ SheetTitle,
140
+ SheetDescription,
141
+ };
@@ -32,22 +32,22 @@ export const StatusCard: React.FC<StatusCardProps> = ({
32
32
  )}
33
33
  {...props}
34
34
  >
35
- <CardHeader className="pb-2">
35
+ <CardHeader className="p-4 pb-2">
36
36
  <CardTitle
37
37
  className={cn(
38
- "text-lg font-medium",
38
+ "text-sm font-medium",
39
39
  isGradient ? "opacity-90 text-white" : "text-muted-foreground"
40
40
  )}
41
41
  >
42
42
  {title}
43
43
  </CardTitle>
44
44
  </CardHeader>
45
- <CardContent>
45
+ <CardContent className="p-4 pt-0">
46
46
  <div className="flex items-baseline gap-2">
47
47
  <span
48
48
  className={cn(
49
- "text-2xl font-semibold",
50
- isGradient ? "text-3xl font-bold" : "text-foreground"
49
+ "text-2xl font-bold tracking-tight",
50
+ isGradient ? "text-white" : "text-foreground"
51
51
  )}
52
52
  >
53
53
  {value}
@@ -65,7 +65,7 @@ export const StatusCard: React.FC<StatusCardProps> = ({
65
65
  {description && (
66
66
  <p
67
67
  className={cn(
68
- "mt-1 text-sm",
68
+ "mt-1 text-xs",
69
69
  isGradient ? "opacity-80" : "text-muted-foreground"
70
70
  )}
71
71
  >
package/src/index.ts CHANGED
@@ -55,3 +55,5 @@ export * from "./components/CodeEditor";
55
55
  export * from "./components/AnimatedNumber";
56
56
  export * from "./hooks/useAnimatedNumber";
57
57
  export * from "./components/IDELayout";
58
+ export * from "./components/MetricTile";
59
+ export * from "./components/Sheet";