@checkstack/catalog-frontend 0.3.8 → 0.3.9
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,28 @@
|
|
|
1
1
|
# @checkstack/catalog-frontend
|
|
2
2
|
|
|
3
|
+
## 0.3.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 223081d: Add icon support to PageLayout and improve mobile responsiveness
|
|
8
|
+
|
|
9
|
+
**PageLayout Icons:**
|
|
10
|
+
|
|
11
|
+
- Added required `icon` prop to `PageLayout` and `PageHeader` components that accepts a Lucide icon component reference
|
|
12
|
+
- Icons are rendered with consistent `h-6 w-6 text-primary` styling
|
|
13
|
+
- Updated all page components to include appropriate icons in their headers
|
|
14
|
+
|
|
15
|
+
**Mobile Layout Improvements:**
|
|
16
|
+
|
|
17
|
+
- Standardized responsive padding in main app shell (`p-3` on mobile, `p-6` on desktop)
|
|
18
|
+
- Added `CardHeaderRow` component for mobile-safe card headers with proper wrapping
|
|
19
|
+
- Improved `DateRangeFilter` responsive behavior with vertical stacking on mobile
|
|
20
|
+
- Migrated pages to use `PageLayout` for consistent responsive behavior
|
|
21
|
+
|
|
22
|
+
- Updated dependencies [223081d]
|
|
23
|
+
- @checkstack/ui@0.5.0
|
|
24
|
+
- @checkstack/auth-frontend@0.5.5
|
|
25
|
+
|
|
3
26
|
## 0.3.8
|
|
4
27
|
|
|
5
28
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -12,21 +12,20 @@ import {
|
|
|
12
12
|
catalogAccess,
|
|
13
13
|
} from "@checkstack/catalog-common";
|
|
14
14
|
import {
|
|
15
|
-
|
|
15
|
+
PageLayout,
|
|
16
16
|
Card,
|
|
17
17
|
CardHeader,
|
|
18
|
+
CardHeaderRow,
|
|
18
19
|
CardTitle,
|
|
19
20
|
CardContent,
|
|
20
21
|
Button,
|
|
21
22
|
Label,
|
|
22
|
-
LoadingSpinner,
|
|
23
23
|
EmptyState,
|
|
24
|
-
AccessDenied,
|
|
25
24
|
EditableText,
|
|
26
25
|
ConfirmationModal,
|
|
27
26
|
useToast,
|
|
28
27
|
} from "@checkstack/ui";
|
|
29
|
-
import { Plus, Trash2, LayoutGrid, Server,
|
|
28
|
+
import { Plus, Trash2, LayoutGrid, Server, Edit } from "lucide-react";
|
|
30
29
|
import { SystemEditor } from "./SystemEditor";
|
|
31
30
|
import { GroupEditor } from "./GroupEditor";
|
|
32
31
|
|
|
@@ -36,7 +35,7 @@ export const CatalogConfigPage = () => {
|
|
|
36
35
|
const toast = useToast();
|
|
37
36
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
38
37
|
const { allowed: canManage, loading: accessLoading } = accessApi.useAccess(
|
|
39
|
-
catalogAccess.system.manage
|
|
38
|
+
catalogAccess.system.manage,
|
|
40
39
|
);
|
|
41
40
|
|
|
42
41
|
const [selectedGroupId, setSelectedGroupId] = useState("");
|
|
@@ -104,7 +103,7 @@ export const CatalogConfigPage = () => {
|
|
|
104
103
|
},
|
|
105
104
|
onError: (error) => {
|
|
106
105
|
toast.error(
|
|
107
|
-
error instanceof Error ? error.message : "Failed to create system"
|
|
106
|
+
error instanceof Error ? error.message : "Failed to create system",
|
|
108
107
|
);
|
|
109
108
|
},
|
|
110
109
|
});
|
|
@@ -118,7 +117,7 @@ export const CatalogConfigPage = () => {
|
|
|
118
117
|
},
|
|
119
118
|
onError: (error) => {
|
|
120
119
|
toast.error(
|
|
121
|
-
error instanceof Error ? error.message : "Failed to update system"
|
|
120
|
+
error instanceof Error ? error.message : "Failed to update system",
|
|
122
121
|
);
|
|
123
122
|
},
|
|
124
123
|
});
|
|
@@ -131,7 +130,7 @@ export const CatalogConfigPage = () => {
|
|
|
131
130
|
},
|
|
132
131
|
onError: (error) => {
|
|
133
132
|
toast.error(
|
|
134
|
-
error instanceof Error ? error.message : "Failed to delete system"
|
|
133
|
+
error instanceof Error ? error.message : "Failed to delete system",
|
|
135
134
|
);
|
|
136
135
|
},
|
|
137
136
|
});
|
|
@@ -144,7 +143,7 @@ export const CatalogConfigPage = () => {
|
|
|
144
143
|
},
|
|
145
144
|
onError: (error) => {
|
|
146
145
|
toast.error(
|
|
147
|
-
error instanceof Error ? error.message : "Failed to create group"
|
|
146
|
+
error instanceof Error ? error.message : "Failed to create group",
|
|
148
147
|
);
|
|
149
148
|
},
|
|
150
149
|
});
|
|
@@ -157,7 +156,7 @@ export const CatalogConfigPage = () => {
|
|
|
157
156
|
},
|
|
158
157
|
onError: (error) => {
|
|
159
158
|
toast.error(
|
|
160
|
-
error instanceof Error ? error.message : "Failed to delete group"
|
|
159
|
+
error instanceof Error ? error.message : "Failed to delete group",
|
|
161
160
|
);
|
|
162
161
|
},
|
|
163
162
|
});
|
|
@@ -169,7 +168,7 @@ export const CatalogConfigPage = () => {
|
|
|
169
168
|
},
|
|
170
169
|
onError: (error) => {
|
|
171
170
|
toast.error(
|
|
172
|
-
error instanceof Error ? error.message : "Failed to update group name"
|
|
171
|
+
error instanceof Error ? error.message : "Failed to update group name",
|
|
173
172
|
);
|
|
174
173
|
throw error;
|
|
175
174
|
},
|
|
@@ -183,7 +182,9 @@ export const CatalogConfigPage = () => {
|
|
|
183
182
|
},
|
|
184
183
|
onError: (error) => {
|
|
185
184
|
toast.error(
|
|
186
|
-
error instanceof Error
|
|
185
|
+
error instanceof Error
|
|
186
|
+
? error.message
|
|
187
|
+
: "Failed to add system to group",
|
|
187
188
|
);
|
|
188
189
|
},
|
|
189
190
|
});
|
|
@@ -198,7 +199,7 @@ export const CatalogConfigPage = () => {
|
|
|
198
199
|
toast.error(
|
|
199
200
|
error instanceof Error
|
|
200
201
|
? error.message
|
|
201
|
-
: "Failed to remove system from group"
|
|
202
|
+
: "Failed to remove system from group",
|
|
202
203
|
);
|
|
203
204
|
},
|
|
204
205
|
});
|
|
@@ -259,37 +260,33 @@ export const CatalogConfigPage = () => {
|
|
|
259
260
|
updateGroupMutation.mutate({ id, data: { name: newName } });
|
|
260
261
|
};
|
|
261
262
|
|
|
262
|
-
if (loading || accessLoading) return <LoadingSpinner />;
|
|
263
|
-
|
|
264
|
-
if (!canManage) {
|
|
265
|
-
return <AccessDenied />;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
263
|
const selectedGroup = groups.find((g) => g.id === selectedGroupId);
|
|
269
264
|
const availableSystems = systems.filter(
|
|
270
|
-
(s) => !selectedGroup?.systemIds?.includes(s.id)
|
|
265
|
+
(s) => !selectedGroup?.systemIds?.includes(s.id),
|
|
271
266
|
);
|
|
272
267
|
|
|
273
268
|
return (
|
|
274
|
-
<
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
269
|
+
<PageLayout
|
|
270
|
+
title="Catalog Management"
|
|
271
|
+
subtitle="Manage systems and logical groups within your infrastructure"
|
|
272
|
+
icon={Server}
|
|
273
|
+
loading={loading || accessLoading}
|
|
274
|
+
allowed={canManage}
|
|
275
|
+
>
|
|
281
276
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
|
282
277
|
{/* Systems Management */}
|
|
283
278
|
<Card>
|
|
284
|
-
<CardHeader
|
|
285
|
-
<
|
|
286
|
-
<
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
<
|
|
291
|
-
|
|
292
|
-
|
|
279
|
+
<CardHeader>
|
|
280
|
+
<CardHeaderRow>
|
|
281
|
+
<CardTitle className="flex items-center gap-2">
|
|
282
|
+
<Server className="w-5 h-5 text-muted-foreground" />
|
|
283
|
+
Systems
|
|
284
|
+
</CardTitle>
|
|
285
|
+
<Button size="sm" onClick={() => setIsSystemEditorOpen(true)}>
|
|
286
|
+
<Plus className="w-4 h-4 mr-2" />
|
|
287
|
+
Add System
|
|
288
|
+
</Button>
|
|
289
|
+
</CardHeaderRow>
|
|
293
290
|
</CardHeader>
|
|
294
291
|
<CardContent className="space-y-4">
|
|
295
292
|
{systems.length === 0 ? (
|
|
@@ -347,15 +344,17 @@ export const CatalogConfigPage = () => {
|
|
|
347
344
|
|
|
348
345
|
{/* Groups Management */}
|
|
349
346
|
<Card>
|
|
350
|
-
<CardHeader
|
|
351
|
-
<
|
|
352
|
-
<
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
<
|
|
357
|
-
|
|
358
|
-
|
|
347
|
+
<CardHeader>
|
|
348
|
+
<CardHeaderRow>
|
|
349
|
+
<CardTitle className="flex items-center gap-2">
|
|
350
|
+
<LayoutGrid className="w-5 h-5 text-muted-foreground" />
|
|
351
|
+
Groups
|
|
352
|
+
</CardTitle>
|
|
353
|
+
<Button size="sm" onClick={() => setIsGroupEditorOpen(true)}>
|
|
354
|
+
<Plus className="w-4 h-4 mr-2" />
|
|
355
|
+
Add Group
|
|
356
|
+
</Button>
|
|
357
|
+
</CardHeaderRow>
|
|
359
358
|
</CardHeader>
|
|
360
359
|
<CardContent className="space-y-4">
|
|
361
360
|
{groups.length === 0 ? (
|
|
@@ -516,6 +515,6 @@ export const CatalogConfigPage = () => {
|
|
|
516
515
|
confirmText="Delete"
|
|
517
516
|
variant="danger"
|
|
518
517
|
/>
|
|
519
|
-
</
|
|
518
|
+
</PageLayout>
|
|
520
519
|
);
|
|
521
520
|
};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { useApi, loggerApiRef } from "@checkstack/frontend-api";
|
|
3
|
+
import { PageLayout } from "@checkstack/ui";
|
|
4
|
+
import { Layers } from "lucide-react";
|
|
3
5
|
|
|
4
6
|
export const CatalogPage = () => {
|
|
5
7
|
const logger = useApi(loggerApiRef);
|
|
@@ -9,9 +11,8 @@ export const CatalogPage = () => {
|
|
|
9
11
|
}, [logger]);
|
|
10
12
|
|
|
11
13
|
return (
|
|
12
|
-
<
|
|
13
|
-
<h2 className="text-2xl font-semibold mb-4">Catalog</h2>
|
|
14
|
+
<PageLayout title="Catalog" icon={Layers}>
|
|
14
15
|
<p className="text-muted-foreground">Welcome to the Service Catalog.</p>
|
|
15
|
-
</
|
|
16
|
+
</PageLayout>
|
|
16
17
|
);
|
|
17
18
|
};
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
CardHeader,
|
|
18
18
|
CardTitle,
|
|
19
19
|
CardContent,
|
|
20
|
-
|
|
20
|
+
PageLayout,
|
|
21
21
|
SubscribeButton,
|
|
22
22
|
useToast,
|
|
23
23
|
BackLink,
|
|
@@ -74,7 +74,7 @@ export const SystemDetailPage: React.FC = () => {
|
|
|
74
74
|
},
|
|
75
75
|
onError: (error) => {
|
|
76
76
|
toast.error(
|
|
77
|
-
error instanceof Error ? error.message : "Failed to subscribe"
|
|
77
|
+
error instanceof Error ? error.message : "Failed to subscribe",
|
|
78
78
|
);
|
|
79
79
|
},
|
|
80
80
|
});
|
|
@@ -87,7 +87,7 @@ export const SystemDetailPage: React.FC = () => {
|
|
|
87
87
|
},
|
|
88
88
|
onError: (error) => {
|
|
89
89
|
toast.error(
|
|
90
|
-
error instanceof Error ? error.message : "Failed to unsubscribe"
|
|
90
|
+
error instanceof Error ? error.message : "Failed to unsubscribe",
|
|
91
91
|
);
|
|
92
92
|
},
|
|
93
93
|
});
|
|
@@ -103,7 +103,7 @@ export const SystemDetailPage: React.FC = () => {
|
|
|
103
103
|
useEffect(() => {
|
|
104
104
|
if (groupsData && systemId) {
|
|
105
105
|
const systemGroups = groupsData.filter((group) =>
|
|
106
|
-
group.systemIds?.includes(systemId)
|
|
106
|
+
group.systemIds?.includes(systemId),
|
|
107
107
|
);
|
|
108
108
|
setGroups(systemGroups);
|
|
109
109
|
}
|
|
@@ -129,26 +129,32 @@ export const SystemDetailPage: React.FC = () => {
|
|
|
129
129
|
unsubscribeMutation.mutate({ groupId: getSystemGroupId() });
|
|
130
130
|
};
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
132
|
+
// Actions for the page header
|
|
133
|
+
const headerActions = (
|
|
134
|
+
<div className="flex items-center gap-4 flex-wrap">
|
|
135
|
+
{session && (
|
|
136
|
+
<SubscribeButton
|
|
137
|
+
isSubscribed={isSubscribed}
|
|
138
|
+
onSubscribe={handleSubscribe}
|
|
139
|
+
onUnsubscribe={handleUnsubscribe}
|
|
140
|
+
loading={
|
|
141
|
+
subscriptionLoading ||
|
|
142
|
+
subscribeMutation.isPending ||
|
|
143
|
+
unsubscribeMutation.isPending
|
|
144
|
+
}
|
|
145
|
+
/>
|
|
146
|
+
)}
|
|
147
|
+
<BackLink onClick={() => navigate("/")}>Back to Dashboard</BackLink>
|
|
148
|
+
</div>
|
|
149
|
+
);
|
|
139
150
|
|
|
140
|
-
if (notFound
|
|
151
|
+
if (notFound) {
|
|
141
152
|
return (
|
|
142
|
-
<
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
System Not Found
|
|
148
|
-
</h1>
|
|
149
|
-
</div>
|
|
150
|
-
<BackLink onClick={() => navigate("/")}>Back to Dashboard</BackLink>
|
|
151
|
-
</div>
|
|
153
|
+
<PageLayout
|
|
154
|
+
title="System Not Found"
|
|
155
|
+
icon={Activity}
|
|
156
|
+
actions={headerActions}
|
|
157
|
+
>
|
|
152
158
|
<Card className="border-destructive/30 bg-destructive/10">
|
|
153
159
|
<CardContent className="p-12 text-center">
|
|
154
160
|
<p className="text-destructive">
|
|
@@ -156,35 +162,23 @@ export const SystemDetailPage: React.FC = () => {
|
|
|
156
162
|
</p>
|
|
157
163
|
</CardContent>
|
|
158
164
|
</Card>
|
|
159
|
-
</
|
|
165
|
+
</PageLayout>
|
|
160
166
|
);
|
|
161
167
|
}
|
|
162
168
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
<div className="flex items-center gap-3">
|
|
168
|
-
<Activity className="h-8 w-8 text-primary" />
|
|
169
|
-
<h1 className="text-3xl font-bold text-foreground">{system.name}</h1>
|
|
170
|
-
</div>
|
|
171
|
-
<div className="flex items-center gap-4">
|
|
172
|
-
{session && (
|
|
173
|
-
<SubscribeButton
|
|
174
|
-
isSubscribed={isSubscribed}
|
|
175
|
-
onSubscribe={handleSubscribe}
|
|
176
|
-
onUnsubscribe={handleUnsubscribe}
|
|
177
|
-
loading={
|
|
178
|
-
subscriptionLoading ||
|
|
179
|
-
subscribeMutation.isPending ||
|
|
180
|
-
unsubscribeMutation.isPending
|
|
181
|
-
}
|
|
182
|
-
/>
|
|
183
|
-
)}
|
|
184
|
-
<BackLink onClick={() => navigate("/")}>Back to Dashboard</BackLink>
|
|
185
|
-
</div>
|
|
186
|
-
</div>
|
|
169
|
+
// Guard for TypeScript - PageLayout already handles loading state
|
|
170
|
+
if (!system) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
187
173
|
|
|
174
|
+
return (
|
|
175
|
+
<PageLayout
|
|
176
|
+
title={system.name}
|
|
177
|
+
icon={Activity}
|
|
178
|
+
loading={loading}
|
|
179
|
+
actions={headerActions}
|
|
180
|
+
maxWidth="full"
|
|
181
|
+
>
|
|
188
182
|
{/* Top Extension Slot for urgent items like maintenance alerts */}
|
|
189
183
|
<ExtensionSlot slot={SystemDetailsTopSlot} context={{ system }} />
|
|
190
184
|
|
|
@@ -310,8 +304,7 @@ export const SystemDetailPage: React.FC = () => {
|
|
|
310
304
|
</Card>
|
|
311
305
|
)}
|
|
312
306
|
|
|
313
|
-
{/* Extension Slot for System Details */}
|
|
314
307
|
<ExtensionSlot slot={SystemDetailsSlot} context={{ system }} />
|
|
315
|
-
</
|
|
308
|
+
</PageLayout>
|
|
316
309
|
);
|
|
317
310
|
};
|