@checkstack/integration-frontend 0.4.4 → 0.5.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 +218 -0
- package/package.json +8 -8
- package/src/components/IntegrationMenuItem.tsx +14 -9
- package/src/index.tsx +9 -14
- package/src/pages/IntegrationsLandingPage.tsx +116 -0
- package/src/pages/ProviderConnectionsPage.tsx +6 -5
- package/src/components/CreateSubscriptionDialog.tsx +0 -651
- package/src/pages/DeliveryLogsPage.tsx +0 -239
- package/src/pages/IntegrationsPage.tsx +0 -378
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,223 @@
|
|
|
1
1
|
# @checkstack/integration-frontend
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e2d6f25: feat(automation): connection picker for integration actions + restore Integrations menu
|
|
8
|
+
|
|
9
|
+
Connection-backed automation actions (Jira, Teams, Webex) now render a
|
|
10
|
+
working connection picker plus cascading provider dropdowns in the
|
|
11
|
+
visual editor, and the Integrations entry is back in the user menu.
|
|
12
|
+
|
|
13
|
+
**Contract.** `ActionDefinition` gained an optional
|
|
14
|
+
`connectionProviderId` (and it is surfaced on `ActionInfoSchema` and
|
|
15
|
+
mapped in the `listActions` router). It carries the integration
|
|
16
|
+
provider's fully-qualified id, derived from the provider plugin's own
|
|
17
|
+
`pluginMetadata.pluginId` (never a hardcoded string), so the editor
|
|
18
|
+
knows which provider backs an action's dropdowns and it matches the
|
|
19
|
+
`qualifiedId` the integration provider registry assigns.
|
|
20
|
+
|
|
21
|
+
**Providers.** Jira, Teams and Webex each export
|
|
22
|
+
`*_PROVIDER_LOCAL_ID` / `*_PROVIDER_QUALIFIED_ID`, register their
|
|
23
|
+
provider with the local id, and add a `CONNECTION_OPTIONS`
|
|
24
|
+
(`"connectionOptions"`) resolver name. Their `post_message` /
|
|
25
|
+
issue actions set `connectionProviderId` and expose `connectionId`
|
|
26
|
+
as an `x-options-resolver` dropdown instead of a hidden field.
|
|
27
|
+
|
|
28
|
+
**Frontend bridge.** A new `useConnectionOptionResolvers` hook
|
|
29
|
+
(`@checkstack/automation-frontend`, which now depends on
|
|
30
|
+
`@checkstack/integration-common`) turns an action's
|
|
31
|
+
`x-options-resolver` schema fields into live data: the
|
|
32
|
+
`connectionOptions` resolver lists the provider's connections via
|
|
33
|
+
`listConnections`, and every other resolver name is forwarded to
|
|
34
|
+
`getConnectionOptions` for the selected `connectionId`, passing the
|
|
35
|
+
live form values as `context` for dependent fields. `ProviderActionBody`
|
|
36
|
+
now passes this map to `DynamicForm` (it was previously missing
|
|
37
|
+
entirely, so connection-backed actions had no working dropdowns).
|
|
38
|
+
|
|
39
|
+
**frontend-api.** `usePluginClient` procedures now also expose a typed
|
|
40
|
+
imperative `.call(input)` alongside `.useQuery` / `.useMutation`, for
|
|
41
|
+
async callbacks that cannot host a hook (such as a `DynamicForm`
|
|
42
|
+
options resolver). Additive, non-breaking.
|
|
43
|
+
|
|
44
|
+
**Integrations menu.** Re-added `IntegrationMenuItem` and a new
|
|
45
|
+
`IntegrationsLandingPage`, wired into `integration-frontend` as a list
|
|
46
|
+
route and a `UserMenuItemsSlot` entry under the "Configuration" group.
|
|
47
|
+
|
|
48
|
+
**Action card polish.** The action editor's secondary metadata (id,
|
|
49
|
+
description, failure behaviour) is now grouped into one quiet settings
|
|
50
|
+
panel with consistent small uppercase "eyebrow" labels, so the action's
|
|
51
|
+
own configuration stays the focal point. The raw failure checkbox was
|
|
52
|
+
replaced with the standard `Checkbox` control, and the provider action
|
|
53
|
+
picker / configuration sections gained consistent section headers and a
|
|
54
|
+
divider. The per-step "type" dropdown was removed: an action's kind is
|
|
55
|
+
fixed at creation, so changing it now means adding a new step and
|
|
56
|
+
deleting the old one (avoids the surprising full-config reset that
|
|
57
|
+
switching kinds used to trigger).
|
|
58
|
+
|
|
59
|
+
**Add-step picker.** Adding a step now opens a Home-Assistant-style
|
|
60
|
+
dialog where the operator decides the step type up front: an "Actions"
|
|
61
|
+
tab lists the registered provider actions grouped by category
|
|
62
|
+
(searchable; picking one presets the step's `action`), and a "Blocks"
|
|
63
|
+
tab lists the structural building blocks (choose / parallel / repeat /
|
|
64
|
+
etc.). Because the concrete action is chosen here, the in-card action
|
|
65
|
+
switcher was removed - a step's action is fixed once created. Composite
|
|
66
|
+
blocks now start with an empty child list (filled via the nested
|
|
67
|
+
add-step picker) instead of seeding an unconfigurable empty action.
|
|
68
|
+
|
|
69
|
+
- 41c77f4: feat(automation): one-time migration of webhook subscriptions + remove legacy integration backend
|
|
70
|
+
|
|
71
|
+
**BREAKING CHANGES** (platform is in BETA — no major bump):
|
|
72
|
+
|
|
73
|
+
- `IntegrationProvider` no longer carries `config` (subscription
|
|
74
|
+
config) or `deliver`. The interface now models a connection provider
|
|
75
|
+
only: connection schema + `getConnectionOptions` + `testConnection`.
|
|
76
|
+
- The legacy subscription / delivery-log / event endpoints
|
|
77
|
+
(`listSubscriptions`, `createSubscription`, `getDeliveryLogs`,
|
|
78
|
+
`listEventTypes`, …) are removed from `integrationContract`.
|
|
79
|
+
- `delivery-coordinator`, `hook-subscriber`, `event-registry`, and the
|
|
80
|
+
`integrationEventExtensionPoint` are deleted. Plugins that
|
|
81
|
+
previously called `integrationEvents.registerEvent(...)` now
|
|
82
|
+
register their hooks as automation triggers via
|
|
83
|
+
`automationTriggerExtensionPoint.registerTrigger(...)`.
|
|
84
|
+
- Frontend pages `IntegrationsPage` and `DeliveryLogsPage` are gone;
|
|
85
|
+
the integration plugin's only remaining UI is connection
|
|
86
|
+
management. Subscription management lives under `/automation/...`.
|
|
87
|
+
- `webhook_subscriptions` and `delivery_logs` tables stay in the
|
|
88
|
+
database for one release as a safety net (no code reads or writes
|
|
89
|
+
them), and will be dropped in a follow-up migration.
|
|
90
|
+
|
|
91
|
+
**New**:
|
|
92
|
+
|
|
93
|
+
- `jira.create_issue`, `teams.post_message`, `webex.post_message`,
|
|
94
|
+
`webhook.send`, `integration-script.run_shell`, and
|
|
95
|
+
`integration-script.run_script` actions registered against the
|
|
96
|
+
Automation Platform with matching `*.message`, `*.delivery`,
|
|
97
|
+
`shell.result`, and `script.result` artifact types. The script
|
|
98
|
+
plugin exposes **two** actions — `run_shell` runs bash via the
|
|
99
|
+
shared `ShellScriptRunner` (Monaco `shell` editor), `run_script`
|
|
100
|
+
runs an ESM module in a Bun subprocess via `EsmScriptRunner`
|
|
101
|
+
(Monaco `typescript` editor + `defineIntegration` helper) — to
|
|
102
|
+
preserve the legacy provider split. `jira.create_issue` keeps the
|
|
103
|
+
dynamic field-mapping dropdown (driven by
|
|
104
|
+
`JIRA_RESOLVERS.FIELD_OPTIONS`).
|
|
105
|
+
- One-time data migration runs on boot in
|
|
106
|
+
`automation-backend.afterPluginsReady`. It reads
|
|
107
|
+
`webhook_subscriptions` via a new service RPC
|
|
108
|
+
`IntegrationApi.listLegacySubscriptions`, translates each row into
|
|
109
|
+
a single-trigger / single-action automation (marked with
|
|
110
|
+
`managed_by = "migrated-subscription:<id>"`), and is idempotent
|
|
111
|
+
across restarts.
|
|
112
|
+
- Failed translations are recorded in a new
|
|
113
|
+
`automation_migration_failures` table and surfaced via
|
|
114
|
+
`AutomationApi.listMigrationFailures` /
|
|
115
|
+
`acknowledgeMigrationFailure` so admins can review and re-create
|
|
116
|
+
failed entries by hand.
|
|
117
|
+
|
|
118
|
+
### Patch Changes
|
|
119
|
+
|
|
120
|
+
- Updated dependencies [e2d6f25]
|
|
121
|
+
- Updated dependencies [41c77f4]
|
|
122
|
+
- Updated dependencies [41c77f4]
|
|
123
|
+
- Updated dependencies [41c77f4]
|
|
124
|
+
- Updated dependencies [41c77f4]
|
|
125
|
+
- Updated dependencies [41c77f4]
|
|
126
|
+
- Updated dependencies [4832e33]
|
|
127
|
+
- Updated dependencies [6d52276]
|
|
128
|
+
- Updated dependencies [35bc682]
|
|
129
|
+
- Updated dependencies [c39ee69]
|
|
130
|
+
- @checkstack/frontend-api@0.6.0
|
|
131
|
+
- @checkstack/ui@1.11.0
|
|
132
|
+
- @checkstack/integration-common@0.6.0
|
|
133
|
+
- @checkstack/common@0.12.0
|
|
134
|
+
- @checkstack/tips-frontend@0.2.6
|
|
135
|
+
- @checkstack/signal-frontend@0.1.5
|
|
136
|
+
|
|
137
|
+
## 0.4.5
|
|
138
|
+
|
|
139
|
+
### Patch Changes
|
|
140
|
+
|
|
141
|
+
- f23f3c9: Retrofit the highest-traffic configuration list tables
|
|
142
|
+
(`HealthCheckList`, `SloConfigPage`, and the integration
|
|
143
|
+
`DeliveryLogsPage`) onto the `ResponsiveTable` + `MobileCardList`
|
|
144
|
+
primitives from `@checkstack/ui`. On `sm` and up each page still
|
|
145
|
+
renders the unchanged 5- to 7-column table; below that breakpoint a
|
|
146
|
+
sibling stacked-card layout surfaces the same data with the resource
|
|
147
|
+
name + status badge at the top, secondary columns in a muted line, and
|
|
148
|
+
the existing action buttons in a right-aligned footer. The
|
|
149
|
+
`HealthCheckListSkeleton` placeholder mirrors both branches so the page
|
|
150
|
+
no longer jumps when data resolves. No business logic, column order,
|
|
151
|
+
or query inputs changed.
|
|
152
|
+
- f23f3c9: Sweep every paginated `*-common` contract onto the canonical
|
|
153
|
+
`PaginationInput` / `PaginatedResult` from `@checkstack/common` and
|
|
154
|
+
remove the now-unused legacy exports.
|
|
155
|
+
|
|
156
|
+
**BREAKING CHANGE** - `@checkstack/common` drops the deprecated
|
|
157
|
+
`PaginationInputSchema`, `paginatedOutput`, and `PaginatedResponse`
|
|
158
|
+
symbols. Callers must consume `PaginationInput` (input) and
|
|
159
|
+
`PaginatedResult(itemSchema)` (output) instead. The canonical input is
|
|
160
|
+
`{ limit (1-100, default 20), offset (>= 0, default 0) }`; the
|
|
161
|
+
canonical output envelope is
|
|
162
|
+
`{ items, total, limit, offset }`.
|
|
163
|
+
|
|
164
|
+
**BREAKING CHANGE** - `@checkstack/notification-common` migrates
|
|
165
|
+
`getNotifications` off the legacy `PaginationInputSchema`
|
|
166
|
+
(`{ limit, offset, unreadOnly }` with output `{ notifications, total }`)
|
|
167
|
+
onto `ListNotificationsInputSchema =
|
|
168
|
+
PaginationInput.extend({ unreadOnly })` and
|
|
169
|
+
`PaginatedResult(NotificationSchema)`. The output key changes from
|
|
170
|
+
`notifications` to `items`, and `limit` / `offset` are now echoed on
|
|
171
|
+
the response. The `PaginationInput` type alias previously exported
|
|
172
|
+
from `notification-common` is removed - use `ListNotificationsInput`
|
|
173
|
+
or the canonical `PaginationInput` from `@checkstack/common`.
|
|
174
|
+
|
|
175
|
+
**BREAKING CHANGE** - `@checkstack/integration-common` migrates
|
|
176
|
+
`listSubscriptions` (inline `{ page, pageSize, ... }` -> output
|
|
177
|
+
`{ subscriptions, total }`) and `getDeliveryLogs` (via
|
|
178
|
+
`DeliveryLogQueryInputSchema` `{ subscriptionId?, eventType?, status?,
|
|
179
|
+
page, pageSize }` -> output `{ logs, total }`) onto the canonical
|
|
180
|
+
`PaginationInput.extend({...})` input and
|
|
181
|
+
`PaginatedResult(itemSchema)` output. External callers must switch
|
|
182
|
+
from `{ page, pageSize }` to `{ limit, offset }` and read response
|
|
183
|
+
items from `data.items` (no more `data.subscriptions` / `data.logs`).
|
|
184
|
+
|
|
185
|
+
The matching `*-backend` handlers were updated to consume the new
|
|
186
|
+
input shape (`offset` arithmetic in lieu of `(page - 1) * pageSize`)
|
|
187
|
+
and to echo `limit` / `offset` on the response. The `*-frontend` call
|
|
188
|
+
sites in `NotificationsPage`, `NotificationBell`, `IntegrationsPage`,
|
|
189
|
+
and `DeliveryLogsPage` were updated to send the new input shape and
|
|
190
|
+
read `data.items`.
|
|
191
|
+
|
|
192
|
+
- f23f3c9: Gate decorative motion and blur effects behind
|
|
193
|
+
`usePerformance().isLowPower` on a focused set of high-traffic plugin
|
|
194
|
+
pages (Dashboard, Dependency map, System node, Notification bell,
|
|
195
|
+
Announcement banner / cards, Anomaly field overrides editor, SLO
|
|
196
|
+
attribution chart, Catalog droppable group). Hover scales, backdrop
|
|
197
|
+
blurs, `animate-pulse`/`animate-ping` accents, and entry transitions
|
|
198
|
+
now drop to static states on low-power devices; functional UX
|
|
199
|
+
transitions (Drawer/Dialog open-close, colour transitions) are left
|
|
200
|
+
alone.
|
|
201
|
+
|
|
202
|
+
Standardise the post-mutation error-toast voice on plugin pages by
|
|
203
|
+
migrating multi-clause `toast.error(extractErrorMessage(error, "Failed
|
|
204
|
+
to X"))` call sites onto the `toastError(toast, "Failed to X", error)`
|
|
205
|
+
helper from `@checkstack/ui`. The helper applies the canonical
|
|
206
|
+
`"action: message"` prefix and 100-character truncation in one place,
|
|
207
|
+
and the now-orphaned `extractErrorMessage` imports are dropped from
|
|
208
|
+
the affected files. No business logic or component APIs changed.
|
|
209
|
+
|
|
210
|
+
- Updated dependencies [f23f3c9]
|
|
211
|
+
- Updated dependencies [f23f3c9]
|
|
212
|
+
- Updated dependencies [f23f3c9]
|
|
213
|
+
- Updated dependencies [f23f3c9]
|
|
214
|
+
- @checkstack/common@0.11.0
|
|
215
|
+
- @checkstack/frontend-api@0.5.2
|
|
216
|
+
- @checkstack/integration-common@0.5.0
|
|
217
|
+
- @checkstack/ui@1.10.0
|
|
218
|
+
- @checkstack/tips-frontend@0.2.5
|
|
219
|
+
- @checkstack/signal-frontend@0.1.4
|
|
220
|
+
|
|
3
221
|
## 0.4.4
|
|
4
222
|
|
|
5
223
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/integration-frontend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"license": "Elastic-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.tsx",
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
"lint:code": "eslint . --max-warnings 0"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@checkstack/common": "0.
|
|
17
|
-
"@checkstack/frontend-api": "0.5.
|
|
18
|
-
"@checkstack/integration-common": "0.
|
|
19
|
-
"@checkstack/signal-frontend": "0.1.
|
|
20
|
-
"@checkstack/tips-frontend": "0.2.
|
|
21
|
-
"@checkstack/ui": "1.
|
|
16
|
+
"@checkstack/common": "0.11.0",
|
|
17
|
+
"@checkstack/frontend-api": "0.5.2",
|
|
18
|
+
"@checkstack/integration-common": "0.5.0",
|
|
19
|
+
"@checkstack/signal-frontend": "0.1.4",
|
|
20
|
+
"@checkstack/tips-frontend": "0.2.5",
|
|
21
|
+
"@checkstack/ui": "1.10.0",
|
|
22
22
|
"lucide-react": "^0.344.0",
|
|
23
23
|
"react": "^18.2.0",
|
|
24
24
|
"react-router-dom": "^6.22.0"
|
|
@@ -27,6 +27,6 @@
|
|
|
27
27
|
"typescript": "^5.0.0",
|
|
28
28
|
"@types/react": "^18.2.0",
|
|
29
29
|
"@checkstack/tsconfig": "0.0.7",
|
|
30
|
-
"@checkstack/scripts": "0.3.
|
|
30
|
+
"@checkstack/scripts": "0.3.3"
|
|
31
31
|
}
|
|
32
32
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Link } from "react-router-dom";
|
|
2
3
|
import { Webhook } from "lucide-react";
|
|
3
4
|
import { DropdownMenuItem } from "@checkstack/ui";
|
|
4
5
|
import type { UserMenuItemsContext } from "@checkstack/frontend-api";
|
|
@@ -8,12 +9,17 @@ import {
|
|
|
8
9
|
integrationAccess,
|
|
9
10
|
pluginMetadata,
|
|
10
11
|
} from "@checkstack/integration-common";
|
|
11
|
-
import React from "react";
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* "Integrations" entry in the user menu. Links to the integrations landing
|
|
15
|
+
* page (provider list); each provider links on to its connection-management
|
|
16
|
+
* page. Gated on `integration.manage` — mirrors the access check the routes
|
|
17
|
+
* themselves enforce, but hiding the link is the cleaner UX for users who
|
|
18
|
+
* can't manage connections.
|
|
19
|
+
*/
|
|
13
20
|
export const IntegrationMenuItem = ({
|
|
14
21
|
accessRules: userPerms,
|
|
15
22
|
}: UserMenuItemsContext) => {
|
|
16
|
-
const navigate = useNavigate();
|
|
17
23
|
const qualifiedId = `${pluginMetadata.pluginId}.${integrationAccess.manage.id}`;
|
|
18
24
|
const allowed = userPerms.includes("*") || userPerms.includes(qualifiedId);
|
|
19
25
|
|
|
@@ -22,11 +28,10 @@ export const IntegrationMenuItem = ({
|
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
return (
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
</DropdownMenuItem>
|
|
31
|
+
<Link to={resolveRoute(integrationRoutes.routes.list)}>
|
|
32
|
+
<DropdownMenuItem icon={<Webhook className="h-4 w-4" />}>
|
|
33
|
+
Integrations
|
|
34
|
+
</DropdownMenuItem>
|
|
35
|
+
</Link>
|
|
31
36
|
);
|
|
32
37
|
};
|
package/src/index.tsx
CHANGED
|
@@ -8,27 +8,23 @@ import {
|
|
|
8
8
|
pluginMetadata,
|
|
9
9
|
integrationAccess,
|
|
10
10
|
} from "@checkstack/integration-common";
|
|
11
|
-
import {
|
|
12
|
-
import { DeliveryLogsPage } from "./pages/DeliveryLogsPage";
|
|
11
|
+
import { IntegrationsLandingPage } from "./pages/IntegrationsLandingPage";
|
|
13
12
|
import { ProviderConnectionsPage } from "./pages/ProviderConnectionsPage";
|
|
14
13
|
import { IntegrationMenuItem } from "./components/IntegrationMenuItem";
|
|
15
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Integration frontend — now scoped to connection management. The
|
|
17
|
+
* legacy subscription / delivery-log pages were removed when the
|
|
18
|
+
* platform moved to the Automation Platform model; operators manage
|
|
19
|
+
* automations in `/automation/...` instead. The landing page lists
|
|
20
|
+
* providers and links each to its connection-management page.
|
|
21
|
+
*/
|
|
16
22
|
export const integrationPlugin = createFrontendPlugin({
|
|
17
23
|
metadata: pluginMetadata,
|
|
18
24
|
routes: [
|
|
19
25
|
{
|
|
20
26
|
route: integrationRoutes.routes.list,
|
|
21
|
-
element: <
|
|
22
|
-
accessRule: integrationAccess.manage,
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
route: integrationRoutes.routes.logs,
|
|
26
|
-
element: <DeliveryLogsPage />,
|
|
27
|
-
accessRule: integrationAccess.manage,
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
route: integrationRoutes.routes.deliveryLogs,
|
|
31
|
-
element: <DeliveryLogsPage />,
|
|
27
|
+
element: <IntegrationsLandingPage />,
|
|
32
28
|
accessRule: integrationAccess.manage,
|
|
33
29
|
},
|
|
34
30
|
{
|
|
@@ -48,7 +44,6 @@ export const integrationPlugin = createFrontendPlugin({
|
|
|
48
44
|
|
|
49
45
|
export default integrationPlugin;
|
|
50
46
|
|
|
51
|
-
// Re-export registry and types for providers to register custom config components
|
|
52
47
|
export {
|
|
53
48
|
registerProviderConfigExtension,
|
|
54
49
|
getProviderConfigExtension,
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { Link } from "react-router-dom";
|
|
2
|
+
import {
|
|
3
|
+
PageLayout,
|
|
4
|
+
Card,
|
|
5
|
+
CardContent,
|
|
6
|
+
EmptyState,
|
|
7
|
+
LoadingSpinner,
|
|
8
|
+
DynamicIcon,
|
|
9
|
+
Badge,
|
|
10
|
+
type LucideIconName,
|
|
11
|
+
} from "@checkstack/ui";
|
|
12
|
+
import { Webhook, ArrowRight } from "lucide-react";
|
|
13
|
+
import { usePluginClient } from "@checkstack/frontend-api";
|
|
14
|
+
import { resolveRoute } from "@checkstack/common";
|
|
15
|
+
import { IntegrationApi, integrationRoutes } from "@checkstack/integration-common";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Integrations landing page — lists every registered integration provider
|
|
19
|
+
* and links each to its connection-management page. This is the entry
|
|
20
|
+
* point reached from the "Integrations" user-menu item; the per-provider
|
|
21
|
+
* `ProviderConnectionsPage` lives at `/connections/:providerId`.
|
|
22
|
+
*
|
|
23
|
+
* Only providers that declare a `connectionSchema` (i.e. need site-wide
|
|
24
|
+
* credentials) are actionable here; others are shown disabled so operators
|
|
25
|
+
* understand why there's nothing to configure.
|
|
26
|
+
*/
|
|
27
|
+
export const IntegrationsLandingPage = () => {
|
|
28
|
+
const client = usePluginClient(IntegrationApi);
|
|
29
|
+
const { data: providers = [], isLoading } = client.listProviders.useQuery({});
|
|
30
|
+
|
|
31
|
+
if (isLoading) {
|
|
32
|
+
return (
|
|
33
|
+
<PageLayout title="Integrations" icon={Webhook}>
|
|
34
|
+
<div className="flex items-center justify-center py-12">
|
|
35
|
+
<LoadingSpinner />
|
|
36
|
+
</div>
|
|
37
|
+
</PageLayout>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (providers.length === 0) {
|
|
42
|
+
return (
|
|
43
|
+
<PageLayout title="Integrations" icon={Webhook}>
|
|
44
|
+
<EmptyState
|
|
45
|
+
icon={<Webhook className="h-12 w-12" />}
|
|
46
|
+
title="No integration providers"
|
|
47
|
+
description="Install an integration plugin (e.g. Jira, Teams, Webex) to manage its connections here."
|
|
48
|
+
/>
|
|
49
|
+
</PageLayout>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<PageLayout
|
|
55
|
+
title="Integrations"
|
|
56
|
+
subtitle="Manage site-wide connections for your integration providers"
|
|
57
|
+
icon={Webhook}
|
|
58
|
+
>
|
|
59
|
+
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
|
60
|
+
{providers.map((provider) => {
|
|
61
|
+
const card = (
|
|
62
|
+
<Card
|
|
63
|
+
className={
|
|
64
|
+
provider.hasConnectionSchema
|
|
65
|
+
? "transition-colors hover:border-primary/50"
|
|
66
|
+
: "opacity-60"
|
|
67
|
+
}
|
|
68
|
+
>
|
|
69
|
+
<CardContent className="flex items-start gap-3 p-4">
|
|
70
|
+
<DynamicIcon
|
|
71
|
+
name={(provider.icon as LucideIconName) ?? "Webhook"}
|
|
72
|
+
className="mt-0.5 h-5 w-5 shrink-0 text-muted-foreground"
|
|
73
|
+
/>
|
|
74
|
+
<div className="min-w-0 flex-1">
|
|
75
|
+
<div className="flex items-center gap-2">
|
|
76
|
+
<span className="truncate text-sm font-semibold">
|
|
77
|
+
{provider.displayName}
|
|
78
|
+
</span>
|
|
79
|
+
{!provider.hasConnectionSchema && (
|
|
80
|
+
<Badge variant="outline" className="shrink-0 text-[10px]">
|
|
81
|
+
No connections
|
|
82
|
+
</Badge>
|
|
83
|
+
)}
|
|
84
|
+
</div>
|
|
85
|
+
{provider.description && (
|
|
86
|
+
<p className="mt-0.5 truncate text-xs text-muted-foreground">
|
|
87
|
+
{provider.description}
|
|
88
|
+
</p>
|
|
89
|
+
)}
|
|
90
|
+
</div>
|
|
91
|
+
{provider.hasConnectionSchema && (
|
|
92
|
+
<ArrowRight className="mt-0.5 h-4 w-4 shrink-0 text-muted-foreground" />
|
|
93
|
+
)}
|
|
94
|
+
</CardContent>
|
|
95
|
+
</Card>
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
if (!provider.hasConnectionSchema) {
|
|
99
|
+
return <div key={provider.qualifiedId}>{card}</div>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<Link
|
|
104
|
+
key={provider.qualifiedId}
|
|
105
|
+
to={resolveRoute(integrationRoutes.routes.connections, {
|
|
106
|
+
providerId: provider.qualifiedId,
|
|
107
|
+
})}
|
|
108
|
+
>
|
|
109
|
+
{card}
|
|
110
|
+
</Link>
|
|
111
|
+
);
|
|
112
|
+
})}
|
|
113
|
+
</div>
|
|
114
|
+
</PageLayout>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
161
|
+
toastError(toast, "Connection test failed", error);
|
|
161
162
|
setTestingId(undefined);
|
|
162
163
|
},
|
|
163
164
|
});
|