@checkstack/integration-frontend 0.4.4 → 0.4.5

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,89 @@
1
1
  # @checkstack/integration-frontend
2
2
 
3
+ ## 0.4.5
4
+
5
+ ### Patch Changes
6
+
7
+ - f23f3c9: Retrofit the highest-traffic configuration list tables
8
+ (`HealthCheckList`, `SloConfigPage`, and the integration
9
+ `DeliveryLogsPage`) onto the `ResponsiveTable` + `MobileCardList`
10
+ primitives from `@checkstack/ui`. On `sm` and up each page still
11
+ renders the unchanged 5- to 7-column table; below that breakpoint a
12
+ sibling stacked-card layout surfaces the same data with the resource
13
+ name + status badge at the top, secondary columns in a muted line, and
14
+ the existing action buttons in a right-aligned footer. The
15
+ `HealthCheckListSkeleton` placeholder mirrors both branches so the page
16
+ no longer jumps when data resolves. No business logic, column order,
17
+ or query inputs changed.
18
+ - f23f3c9: Sweep every paginated `*-common` contract onto the canonical
19
+ `PaginationInput` / `PaginatedResult` from `@checkstack/common` and
20
+ remove the now-unused legacy exports.
21
+
22
+ **BREAKING CHANGE** - `@checkstack/common` drops the deprecated
23
+ `PaginationInputSchema`, `paginatedOutput`, and `PaginatedResponse`
24
+ symbols. Callers must consume `PaginationInput` (input) and
25
+ `PaginatedResult(itemSchema)` (output) instead. The canonical input is
26
+ `{ limit (1-100, default 20), offset (>= 0, default 0) }`; the
27
+ canonical output envelope is
28
+ `{ items, total, limit, offset }`.
29
+
30
+ **BREAKING CHANGE** - `@checkstack/notification-common` migrates
31
+ `getNotifications` off the legacy `PaginationInputSchema`
32
+ (`{ limit, offset, unreadOnly }` with output `{ notifications, total }`)
33
+ onto `ListNotificationsInputSchema =
34
+ PaginationInput.extend({ unreadOnly })` and
35
+ `PaginatedResult(NotificationSchema)`. The output key changes from
36
+ `notifications` to `items`, and `limit` / `offset` are now echoed on
37
+ the response. The `PaginationInput` type alias previously exported
38
+ from `notification-common` is removed - use `ListNotificationsInput`
39
+ or the canonical `PaginationInput` from `@checkstack/common`.
40
+
41
+ **BREAKING CHANGE** - `@checkstack/integration-common` migrates
42
+ `listSubscriptions` (inline `{ page, pageSize, ... }` -> output
43
+ `{ subscriptions, total }`) and `getDeliveryLogs` (via
44
+ `DeliveryLogQueryInputSchema` `{ subscriptionId?, eventType?, status?,
45
+ page, pageSize }` -> output `{ logs, total }`) onto the canonical
46
+ `PaginationInput.extend({...})` input and
47
+ `PaginatedResult(itemSchema)` output. External callers must switch
48
+ from `{ page, pageSize }` to `{ limit, offset }` and read response
49
+ items from `data.items` (no more `data.subscriptions` / `data.logs`).
50
+
51
+ The matching `*-backend` handlers were updated to consume the new
52
+ input shape (`offset` arithmetic in lieu of `(page - 1) * pageSize`)
53
+ and to echo `limit` / `offset` on the response. The `*-frontend` call
54
+ sites in `NotificationsPage`, `NotificationBell`, `IntegrationsPage`,
55
+ and `DeliveryLogsPage` were updated to send the new input shape and
56
+ read `data.items`.
57
+
58
+ - f23f3c9: Gate decorative motion and blur effects behind
59
+ `usePerformance().isLowPower` on a focused set of high-traffic plugin
60
+ pages (Dashboard, Dependency map, System node, Notification bell,
61
+ Announcement banner / cards, Anomaly field overrides editor, SLO
62
+ attribution chart, Catalog droppable group). Hover scales, backdrop
63
+ blurs, `animate-pulse`/`animate-ping` accents, and entry transitions
64
+ now drop to static states on low-power devices; functional UX
65
+ transitions (Drawer/Dialog open-close, colour transitions) are left
66
+ alone.
67
+
68
+ Standardise the post-mutation error-toast voice on plugin pages by
69
+ migrating multi-clause `toast.error(extractErrorMessage(error, "Failed
70
+ to X"))` call sites onto the `toastError(toast, "Failed to X", error)`
71
+ helper from `@checkstack/ui`. The helper applies the canonical
72
+ `"action: message"` prefix and 100-character truncation in one place,
73
+ and the now-orphaned `extractErrorMessage` imports are dropped from
74
+ the affected files. No business logic or component APIs changed.
75
+
76
+ - Updated dependencies [f23f3c9]
77
+ - Updated dependencies [f23f3c9]
78
+ - Updated dependencies [f23f3c9]
79
+ - Updated dependencies [f23f3c9]
80
+ - @checkstack/common@0.11.0
81
+ - @checkstack/frontend-api@0.5.2
82
+ - @checkstack/integration-common@0.5.0
83
+ - @checkstack/ui@1.10.0
84
+ - @checkstack/tips-frontend@0.2.5
85
+ - @checkstack/signal-frontend@0.1.4
86
+
3
87
  ## 0.4.4
4
88
 
5
89
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checkstack/integration-frontend",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "license": "Elastic-2.0",
5
5
  "type": "module",
6
6
  "main": "src/index.tsx",
@@ -17,8 +17,8 @@
17
17
  "@checkstack/frontend-api": "0.5.1",
18
18
  "@checkstack/integration-common": "0.4.0",
19
19
  "@checkstack/signal-frontend": "0.1.3",
20
- "@checkstack/tips-frontend": "0.2.3",
21
- "@checkstack/ui": "1.8.3",
20
+ "@checkstack/tips-frontend": "0.2.4",
21
+ "@checkstack/ui": "1.9.0",
22
22
  "lucide-react": "^0.344.0",
23
23
  "react": "^18.2.0",
24
24
  "react-router-dom": "^6.22.0"
@@ -23,10 +23,11 @@ import {
23
23
  SelectValue,
24
24
  Label,
25
25
  ConfirmationModal,
26
+ toastError,
26
27
  type LucideIconName,
27
28
  } from "@checkstack/ui";
28
29
  import { usePluginClient } from "@checkstack/frontend-api";
29
- import { resolveRoute, extractErrorMessage } from "@checkstack/common";
30
+ import { resolveRoute } from "@checkstack/common";
30
31
  import {
31
32
  IntegrationApi,
32
33
  integrationRoutes,
@@ -128,7 +129,7 @@ export const SubscriptionDialog = ({
128
129
  setSaving(false);
129
130
  },
130
131
  onError: (error) => {
131
- toast.error(extractErrorMessage(error, "Failed to create subscription"));
132
+ toastError(toast, "Failed to create subscription", error);
132
133
  setSaving(false);
133
134
  },
134
135
  });
@@ -141,7 +142,7 @@ export const SubscriptionDialog = ({
141
142
  setSaving(false);
142
143
  },
143
144
  onError: (error) => {
144
- toast.error(extractErrorMessage(error, "Failed to update subscription"));
145
+ toastError(toast, "Failed to update subscription", error);
145
146
  setSaving(false);
146
147
  },
147
148
  });
@@ -153,7 +154,7 @@ export const SubscriptionDialog = ({
153
154
  onOpenChange(false);
154
155
  },
155
156
  onError: (error) => {
156
- toast.error(extractErrorMessage(error, "Failed to delete subscription"));
157
+ toastError(toast, "Failed to delete subscription", error);
157
158
  },
158
159
  });
159
160
 
@@ -24,6 +24,8 @@ import {
24
24
  usePagination,
25
25
  usePaginationSync,
26
26
  BackLink,
27
+ ResponsiveTable,
28
+ MobileCardList,
27
29
  } from "@checkstack/ui";
28
30
  import { usePluginClient } from "@checkstack/frontend-api";
29
31
  import { resolveRoute } from "@checkstack/common";
@@ -70,17 +72,16 @@ export const DeliveryLogsPage = () => {
70
72
  const pagination = usePagination({ defaultLimit: 20 });
71
73
 
72
74
  // Fetch data with useQuery
73
- const page = Math.floor(pagination.offset / pagination.limit) + 1;
74
75
  const { data, isLoading, refetch } =
75
76
  integrationClient.getDeliveryLogs.useQuery({
76
- page,
77
- pageSize: pagination.limit,
77
+ limit: pagination.limit,
78
+ offset: pagination.offset,
78
79
  });
79
80
 
80
81
  // Sync total from response
81
82
  usePaginationSync(pagination, data?.total);
82
83
 
83
- const logs = data?.logs ?? [];
84
+ const logs = data?.items ?? [];
84
85
 
85
86
  // Retry mutation
86
87
  const retryMutation = integrationClient.retryDelivery.useMutation({
@@ -132,81 +133,141 @@ export const DeliveryLogsPage = () => {
132
133
  </div>
133
134
  </Card>
134
135
  ) : (
135
- <Card>
136
- <Table>
137
- <TableHeader>
138
- <TableRow>
139
- <TableHead>Status</TableHead>
140
- <TableHead>Subscription</TableHead>
141
- <TableHead>Event</TableHead>
142
- <TableHead>Attempts</TableHead>
143
- <TableHead>Created</TableHead>
144
- <TableHead>Error</TableHead>
145
- <TableHead></TableHead>
146
- </TableRow>
147
- </TableHeader>
148
- <TableBody>
149
- {logs.map((log: DeliveryLog) => {
150
- const config = statusConfig[log.status];
151
- return (
152
- <TableRow key={log.id}>
153
- <TableCell>
154
- <Badge
155
- variant={config.variant}
156
- className="flex items-center gap-1 w-fit"
157
- >
158
- {config.icon}
159
- {log.status}
160
- </Badge>
161
- </TableCell>
162
- <TableCell>
163
- <div className="font-medium">
164
- {log.subscriptionName ?? "Unknown"}
165
- </div>
166
- </TableCell>
167
- <TableCell>
168
- <div className="text-sm font-mono">
169
- {log.eventType}
170
- </div>
171
- </TableCell>
172
- <TableCell>{log.attempts}</TableCell>
173
- <TableCell>
174
- <div className="text-sm text-muted-foreground">
175
- {new Date(log.createdAt).toLocaleString()}
176
- </div>
177
- </TableCell>
178
- <TableCell>
179
- {log.errorMessage ? (
180
- <div
181
- className="text-sm text-destructive max-w-[200px] truncate"
182
- title={log.errorMessage}
183
- >
184
- {log.errorMessage}
185
- </div>
186
- ) : undefined}
187
- </TableCell>
188
- <TableCell>
189
- {log.status === "failed" && (
190
- <Button
191
- variant="ghost"
192
- size="sm"
193
- onClick={() => handleRetry(log.id)}
194
- disabled={retrying === log.id}
195
- >
196
- <RefreshCw
197
- className={`h-4 w-4 mr-1 ${
198
- retrying === log.id ? "animate-spin" : ""
199
- }`}
200
- />
201
- Retry
202
- </Button>
203
- )}
204
- </TableCell>
136
+ <>
137
+ <ResponsiveTable>
138
+ <Card>
139
+ <Table>
140
+ <TableHeader>
141
+ <TableRow>
142
+ <TableHead>Status</TableHead>
143
+ <TableHead>Subscription</TableHead>
144
+ <TableHead>Event</TableHead>
145
+ <TableHead>Attempts</TableHead>
146
+ <TableHead>Created</TableHead>
147
+ <TableHead>Error</TableHead>
148
+ <TableHead></TableHead>
205
149
  </TableRow>
206
- );
207
- })}
208
- </TableBody>
209
- </Table>
150
+ </TableHeader>
151
+ <TableBody>
152
+ {logs.map((log: DeliveryLog) => {
153
+ const config = statusConfig[log.status];
154
+ return (
155
+ <TableRow key={log.id}>
156
+ <TableCell>
157
+ <Badge
158
+ variant={config.variant}
159
+ className="flex items-center gap-1 w-fit"
160
+ >
161
+ {config.icon}
162
+ {log.status}
163
+ </Badge>
164
+ </TableCell>
165
+ <TableCell>
166
+ <div className="font-medium">
167
+ {log.subscriptionName ?? "Unknown"}
168
+ </div>
169
+ </TableCell>
170
+ <TableCell>
171
+ <div className="text-sm font-mono">
172
+ {log.eventType}
173
+ </div>
174
+ </TableCell>
175
+ <TableCell>{log.attempts}</TableCell>
176
+ <TableCell>
177
+ <div className="text-sm text-muted-foreground">
178
+ {new Date(log.createdAt).toLocaleString()}
179
+ </div>
180
+ </TableCell>
181
+ <TableCell>
182
+ {log.errorMessage ? (
183
+ <div
184
+ className="text-sm text-destructive max-w-[200px] truncate"
185
+ title={log.errorMessage}
186
+ >
187
+ {log.errorMessage}
188
+ </div>
189
+ ) : undefined}
190
+ </TableCell>
191
+ <TableCell>
192
+ {log.status === "failed" && (
193
+ <Button
194
+ variant="ghost"
195
+ size="sm"
196
+ onClick={() => handleRetry(log.id)}
197
+ disabled={retrying === log.id}
198
+ >
199
+ <RefreshCw
200
+ className={`h-4 w-4 mr-1 ${
201
+ retrying === log.id ? "animate-spin" : ""
202
+ }`}
203
+ />
204
+ Retry
205
+ </Button>
206
+ )}
207
+ </TableCell>
208
+ </TableRow>
209
+ );
210
+ })}
211
+ </TableBody>
212
+ </Table>
213
+ </Card>
214
+ </ResponsiveTable>
215
+
216
+ <MobileCardList>
217
+ {logs.map((log: DeliveryLog) => {
218
+ const config = statusConfig[log.status];
219
+ return (
220
+ <Card key={log.id} className="p-3">
221
+ <div className="flex items-start justify-between gap-2">
222
+ <span className="font-medium truncate">
223
+ {log.subscriptionName ?? "Unknown"}
224
+ </span>
225
+ <Badge
226
+ variant={config.variant}
227
+ className="flex items-center gap-1 w-fit shrink-0"
228
+ >
229
+ {config.icon}
230
+ {log.status}
231
+ </Badge>
232
+ </div>
233
+ <div className="mt-1 text-xs text-muted-foreground font-mono break-all">
234
+ {log.eventType}
235
+ </div>
236
+ <div className="mt-1 text-xs text-muted-foreground">
237
+ {log.attempts} attempt
238
+ {log.attempts === 1 ? "" : "s"} &middot;{" "}
239
+ {new Date(log.createdAt).toLocaleString()}
240
+ </div>
241
+ {log.errorMessage && (
242
+ <div
243
+ className="mt-2 text-xs text-destructive line-clamp-2"
244
+ title={log.errorMessage}
245
+ >
246
+ {log.errorMessage}
247
+ </div>
248
+ )}
249
+ {log.status === "failed" && (
250
+ <div className="mt-3 flex justify-end">
251
+ <Button
252
+ variant="ghost"
253
+ size="sm"
254
+ onClick={() => handleRetry(log.id)}
255
+ disabled={retrying === log.id}
256
+ >
257
+ <RefreshCw
258
+ className={`h-4 w-4 mr-1 ${
259
+ retrying === log.id ? "animate-spin" : ""
260
+ }`}
261
+ />
262
+ Retry
263
+ </Button>
264
+ </div>
265
+ )}
266
+ </Card>
267
+ );
268
+ })}
269
+ </MobileCardList>
270
+
210
271
  {pagination.totalPages > 1 && (
211
272
  <div className="p-4 border-t flex justify-center gap-2">
212
273
  <Button
@@ -230,7 +291,7 @@ export const DeliveryLogsPage = () => {
230
291
  </Button>
231
292
  </div>
232
293
  )}
233
- </Card>
294
+ </>
234
295
  )}
235
296
  </section>
236
297
  </div>
@@ -51,7 +51,7 @@ export const IntegrationsPage = () => {
51
51
  data: subscriptionsData,
52
52
  isLoading: subsLoading,
53
53
  refetch: refetchSubs,
54
- } = client.listSubscriptions.useQuery({ page: 1, pageSize: 100 });
54
+ } = client.listSubscriptions.useQuery({ limit: 100, offset: 0 });
55
55
 
56
56
  const { data: providers = [], isLoading: providersLoading } =
57
57
  client.listProviders.useQuery({});
@@ -74,7 +74,7 @@ export const IntegrationsPage = () => {
74
74
  },
75
75
  });
76
76
 
77
- const subscriptions = subscriptionsData?.subscriptions ?? [];
77
+ const subscriptions = subscriptionsData?.items ?? [];
78
78
  const loading = subsLoading || providersLoading || statsLoading;
79
79
 
80
80
  // Handle ?action=create URL parameter (from command palette)
@@ -42,10 +42,11 @@ import {
42
42
  useToast,
43
43
  ConfirmationModal,
44
44
  BackLink,
45
+ toastError,
45
46
  type LucideIconName,
46
47
  } from "@checkstack/ui";
47
48
  import { usePluginClient } from "@checkstack/frontend-api";
48
- import { resolveRoute, extractErrorMessage } from "@checkstack/common";
49
+ import { resolveRoute } from "@checkstack/common";
49
50
  import {
50
51
  IntegrationApi,
51
52
  integrationRoutes,
@@ -108,7 +109,7 @@ export const ProviderConnectionsPage = () => {
108
109
  setSaving(false);
109
110
  },
110
111
  onError: (error) => {
111
- toast.error(extractErrorMessage(error, "Failed to create connection"));
112
+ toastError(toast, "Failed to create connection", error);
112
113
  setSaving(false);
113
114
  },
114
115
  });
@@ -122,7 +123,7 @@ export const ProviderConnectionsPage = () => {
122
123
  setSaving(false);
123
124
  },
124
125
  onError: (error) => {
125
- toast.error(extractErrorMessage(error, "Failed to update connection"));
126
+ toastError(toast, "Failed to update connection", error);
126
127
  setSaving(false);
127
128
  },
128
129
  });
@@ -135,7 +136,7 @@ export const ProviderConnectionsPage = () => {
135
136
  toast.success("Connection deleted");
136
137
  },
137
138
  onError: (error) => {
138
- toast.error(extractErrorMessage(error, "Failed to delete connection"));
139
+ toastError(toast, "Failed to delete connection", error);
139
140
  },
140
141
  });
141
142
 
@@ -157,7 +158,7 @@ export const ProviderConnectionsPage = () => {
157
158
  ...prev,
158
159
  [variables.connectionId]: { success: false, message: "Test failed" },
159
160
  }));
160
- toast.error(extractErrorMessage(error, "Connection test failed"));
161
+ toastError(toast, "Connection test failed", error);
161
162
  setTestingId(undefined);
162
163
  },
163
164
  });