@burdenoff/microfe-channel 2026.530.2 → 2026.624.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/dist/channel/components/AdapterCredentialsForm.js +11 -11
- package/dist/channel/components/AdapterCredentialsForm.js.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelDashboardPage.js +53 -53
- package/dist/channel/modules/channels/pages/ChannelDashboardPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelDetailsPage.js +78 -78
- package/dist/channel/modules/channels/pages/ChannelDetailsPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelSettingsPage.js +26 -26
- package/dist/channel/modules/channels/pages/ChannelSettingsPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelUsersPage.js +32 -32
- package/dist/channel/modules/channels/pages/ChannelUsersPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelsListPage.js +41 -41
- package/dist/channel/modules/channels/pages/ChannelsListPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js +30 -30
- package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ConnectionsListPage.js +29 -29
- package/dist/channel/modules/channels/pages/ConnectionsListPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/CreateChannelPage.js +28 -28
- package/dist/channel/modules/channels/pages/CreateChannelPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/CreateConnectionPage.js +8 -8
- package/dist/channel/modules/channels/pages/CreateConnectionPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/DeliveryHistoryPage.js +28 -28
- package/dist/channel/modules/channels/pages/DeliveryHistoryPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/EditChannelPage.js +25 -25
- package/dist/channel/modules/channels/pages/EditChannelPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/EditConnectionPage.js +4 -4
- package/dist/channel/modules/channels/pages/EditConnectionPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/SendMessagePage.js +27 -27
- package/dist/channel/modules/channels/pages/SendMessagePage.js.map +1 -1
- package/dist/channel/modules/channels/pages/WebhookEventsPage.js +29 -29
- package/dist/channel/modules/channels/pages/WebhookEventsPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -83,12 +83,12 @@ function O() {
|
|
|
83
83
|
};
|
|
84
84
|
if (B || !P && !I) return /* @__PURE__ */ w("div", {
|
|
85
85
|
className: "flex items-center justify-center min-h-screen",
|
|
86
|
-
children: /* @__PURE__ */ w(g, { className: "size-8 animate-spin text-
|
|
86
|
+
children: /* @__PURE__ */ w(g, { className: "size-8 animate-spin text-text-secondary" })
|
|
87
87
|
});
|
|
88
88
|
if (I || V || !z) return /* @__PURE__ */ T("div", {
|
|
89
89
|
className: "flex flex-col items-center justify-center min-h-screen gap-4",
|
|
90
90
|
children: [
|
|
91
|
-
/* @__PURE__ */ w(d, { className: "size-12 text-
|
|
91
|
+
/* @__PURE__ */ w(d, { className: "size-12 text-status-error-text" }),
|
|
92
92
|
/* @__PURE__ */ w("h1", {
|
|
93
93
|
className: "text-xl font-semibold",
|
|
94
94
|
children: G("channel.channelNotFound", "Channel not found")
|
|
@@ -104,13 +104,13 @@ function O() {
|
|
|
104
104
|
if (!Q) return /* @__PURE__ */ T("div", {
|
|
105
105
|
className: "flex flex-col items-center justify-center min-h-screen gap-4",
|
|
106
106
|
children: [
|
|
107
|
-
/* @__PURE__ */ w(d, { className: "size-12 text-
|
|
107
|
+
/* @__PURE__ */ w(d, { className: "size-12 text-text-secondary" }),
|
|
108
108
|
/* @__PURE__ */ w("h1", {
|
|
109
109
|
className: "text-xl font-semibold",
|
|
110
110
|
children: G("channel.noConnectionFound", "No connection found")
|
|
111
111
|
}),
|
|
112
112
|
/* @__PURE__ */ w("p", {
|
|
113
|
-
className: "text-sm text-
|
|
113
|
+
className: "text-sm text-text-secondary",
|
|
114
114
|
children: G("channel.noConnectionConfigured", "This channel does not have a connection configured.")
|
|
115
115
|
}),
|
|
116
116
|
/* @__PURE__ */ w("button", {
|
|
@@ -125,9 +125,9 @@ function O() {
|
|
|
125
125
|
return /* @__PURE__ */ w(o, {
|
|
126
126
|
permission: s.CHANNEL_CONNECTION_READ,
|
|
127
127
|
children: /* @__PURE__ */ T("div", {
|
|
128
|
-
className: "min-h-screen bg-
|
|
128
|
+
className: "min-h-screen bg-bg-surface",
|
|
129
129
|
children: [/* @__PURE__ */ w("div", {
|
|
130
|
-
className: "border-b bg-
|
|
130
|
+
className: "border-b bg-bg-surface",
|
|
131
131
|
children: /* @__PURE__ */ w("div", {
|
|
132
132
|
className: "container mx-auto px-6 py-4",
|
|
133
133
|
children: /* @__PURE__ */ T("div", {
|
|
@@ -137,13 +137,13 @@ function O() {
|
|
|
137
137
|
children: [/* @__PURE__ */ w("button", {
|
|
138
138
|
type: "button",
|
|
139
139
|
onClick: () => p(`/channels/${R}`),
|
|
140
|
-
className: "p-2 hover:bg-
|
|
140
|
+
className: "p-2 hover:bg-bg-sunken rounded-lg transition-colors",
|
|
141
141
|
children: /* @__PURE__ */ w(f, { className: "size-5 " })
|
|
142
142
|
}), /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("h1", {
|
|
143
143
|
className: "text-2xl font-bold",
|
|
144
144
|
children: G("channel.connectionDetails", "Connection Details")
|
|
145
145
|
}), /* @__PURE__ */ T("p", {
|
|
146
|
-
className: "text-sm text-
|
|
146
|
+
className: "text-sm text-text-secondary",
|
|
147
147
|
children: [
|
|
148
148
|
z.name,
|
|
149
149
|
" • ",
|
|
@@ -158,13 +158,13 @@ function O() {
|
|
|
158
158
|
type: "button",
|
|
159
159
|
onClick: te,
|
|
160
160
|
disabled: J,
|
|
161
|
-
className: "px-4 py-2 rounded-lg border hover:bg-
|
|
161
|
+
className: "px-4 py-2 rounded-lg border hover:bg-bg-sunken transition-colors flex items-center gap-2",
|
|
162
162
|
children: [J ? /* @__PURE__ */ w(g, { className: "size-4 animate-spin" }) : /* @__PURE__ */ w(_, { className: "size-4 " }), G("channel.runHealthCheck", "Run Health Check")]
|
|
163
163
|
})
|
|
164
164
|
}), O && /* @__PURE__ */ T("button", {
|
|
165
165
|
type: "button",
|
|
166
166
|
onClick: () => p(`/channels/${R}/edit`),
|
|
167
|
-
className: "px-4 py-2 rounded-lg border hover:bg-
|
|
167
|
+
className: "px-4 py-2 rounded-lg border hover:bg-bg-sunken transition-colors flex items-center gap-2",
|
|
168
168
|
children: [/* @__PURE__ */ w(h, { className: "size-4 " }), G("channel.editChannel", "Edit Channel")]
|
|
169
169
|
})]
|
|
170
170
|
})]
|
|
@@ -186,7 +186,7 @@ function O() {
|
|
|
186
186
|
className: "text-xl font-semibold",
|
|
187
187
|
children: $.label
|
|
188
188
|
}), /* @__PURE__ */ w("p", {
|
|
189
|
-
className: "text-sm text-
|
|
189
|
+
className: "text-sm text-text-secondary",
|
|
190
190
|
children: Q.isHealthy ? G("channel.connectionWorking", "Connection is working properly") : G("channel.connectionNotWorking", "Connection is not working properly")
|
|
191
191
|
})] })]
|
|
192
192
|
})
|
|
@@ -203,45 +203,45 @@ function O() {
|
|
|
203
203
|
className: "grid grid-cols-2 gap-4",
|
|
204
204
|
children: [
|
|
205
205
|
/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
|
|
206
|
-
className: "text-sm text-
|
|
206
|
+
className: "text-sm text-text-secondary",
|
|
207
207
|
children: "Connection ID"
|
|
208
208
|
}), /* @__PURE__ */ w("p", {
|
|
209
209
|
className: "font-mono text-sm",
|
|
210
210
|
children: Q.id
|
|
211
211
|
})] }),
|
|
212
212
|
/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
|
|
213
|
-
className: "text-sm text-
|
|
213
|
+
className: "text-sm text-text-secondary",
|
|
214
214
|
children: "Auth Type"
|
|
215
215
|
}), /* @__PURE__ */ T("p", {
|
|
216
216
|
className: "flex items-center gap-2",
|
|
217
|
-
children: [/* @__PURE__ */ w(v, { className: "size-4 text-
|
|
217
|
+
children: [/* @__PURE__ */ w(v, { className: "size-4 text-text-secondary" }), Q.authType]
|
|
218
218
|
})] }),
|
|
219
219
|
/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
|
|
220
|
-
className: "text-sm text-
|
|
220
|
+
className: "text-sm text-text-secondary",
|
|
221
221
|
children: "Status"
|
|
222
222
|
}), /* @__PURE__ */ w("p", {
|
|
223
|
-
className: Q.isActive ? "text-status-success-text" : "text-
|
|
223
|
+
className: Q.isActive ? "text-status-success-text" : "text-text-secondary",
|
|
224
224
|
children: Q.isActive ? G("channel.activeStatus", "Active") : G("channel.inactiveStatus", "Inactive")
|
|
225
225
|
})] }),
|
|
226
226
|
/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
|
|
227
|
-
className: "text-sm text-
|
|
227
|
+
className: "text-sm text-text-secondary",
|
|
228
228
|
children: "Token Refresh"
|
|
229
229
|
}), /* @__PURE__ */ w("p", {
|
|
230
|
-
className: Q.needsTokenRefresh ? "text-status-warning-text" : "text-
|
|
230
|
+
className: Q.needsTokenRefresh ? "text-status-warning-text" : "text-text-secondary",
|
|
231
231
|
children: Q.needsTokenRefresh ? G("channel.tokenRefreshRequired", "Required soon") : G("channel.tokenRefreshNotNeeded", "Not needed")
|
|
232
232
|
})] }),
|
|
233
233
|
Q.lastTestedAt && /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
|
|
234
|
-
className: "text-sm text-
|
|
234
|
+
className: "text-sm text-text-secondary",
|
|
235
235
|
children: "Last Tested"
|
|
236
236
|
}), /* @__PURE__ */ T("p", {
|
|
237
237
|
className: "flex items-center gap-2",
|
|
238
|
-
children: [/* @__PURE__ */ w(m, { className: "size-4 text-
|
|
238
|
+
children: [/* @__PURE__ */ w(m, { className: "size-4 text-text-secondary" }), new Date(Q.lastTestedAt).toLocaleString()]
|
|
239
239
|
})] }),
|
|
240
240
|
Q.daysUntilExpiry !== null && Q.daysUntilExpiry !== void 0 && /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
|
|
241
|
-
className: "text-sm text-
|
|
241
|
+
className: "text-sm text-text-secondary",
|
|
242
242
|
children: "Days Until Token Expiry"
|
|
243
243
|
}), /* @__PURE__ */ T("p", {
|
|
244
|
-
className: Q.daysUntilExpiry < 30 ? "text-status-warning-text" : "text-
|
|
244
|
+
className: Q.daysUntilExpiry < 30 ? "text-status-warning-text" : "text-text-secondary",
|
|
245
245
|
children: [Q.daysUntilExpiry, " days"]
|
|
246
246
|
})] })
|
|
247
247
|
]
|
|
@@ -249,10 +249,10 @@ function O() {
|
|
|
249
249
|
Q.testStatus && /* @__PURE__ */ T("div", {
|
|
250
250
|
className: "pt-4 border-t",
|
|
251
251
|
children: [/* @__PURE__ */ w("p", {
|
|
252
|
-
className: "text-sm text-
|
|
252
|
+
className: "text-sm text-text-secondary mb-2",
|
|
253
253
|
children: "Last Test Status"
|
|
254
254
|
}), /* @__PURE__ */ w("div", {
|
|
255
|
-
className: "p-3 rounded-lg bg-
|
|
255
|
+
className: "p-3 rounded-lg bg-bg-sunken",
|
|
256
256
|
children: /* @__PURE__ */ w("p", {
|
|
257
257
|
className: "font-mono text-sm",
|
|
258
258
|
children: Q.testStatus
|
|
@@ -262,7 +262,7 @@ function O() {
|
|
|
262
262
|
Q.tagAssignments && Q.tagAssignments.length > 0 && /* @__PURE__ */ T("div", {
|
|
263
263
|
className: "pt-4 border-t",
|
|
264
264
|
children: [/* @__PURE__ */ w("p", {
|
|
265
|
-
className: "text-sm text-
|
|
265
|
+
className: "text-sm text-text-secondary mb-2",
|
|
266
266
|
children: G("channel.tags", "Tags")
|
|
267
267
|
}), /* @__PURE__ */ w("div", {
|
|
268
268
|
className: "flex flex-wrap gap-1.5",
|
|
@@ -287,26 +287,26 @@ function O() {
|
|
|
287
287
|
className: "font-medium",
|
|
288
288
|
children: G("channel.deleteConnection", "Delete Connection")
|
|
289
289
|
}), /* @__PURE__ */ w("p", {
|
|
290
|
-
className: "text-sm text-
|
|
290
|
+
className: "text-sm text-text-secondary",
|
|
291
291
|
children: G("channel.deleteConnectionWarning", "Permanently remove this connection. The channel will become inactive.")
|
|
292
292
|
})] }), X ? /* @__PURE__ */ T("div", {
|
|
293
293
|
className: "flex items-center gap-2",
|
|
294
294
|
children: [
|
|
295
295
|
/* @__PURE__ */ w("span", {
|
|
296
|
-
className: "text-sm text-
|
|
296
|
+
className: "text-sm text-text-secondary",
|
|
297
297
|
children: G("channel.confirmDelete", "Confirm delete?")
|
|
298
298
|
}),
|
|
299
299
|
/* @__PURE__ */ T("button", {
|
|
300
300
|
type: "button",
|
|
301
301
|
onClick: ne,
|
|
302
302
|
disabled: K,
|
|
303
|
-
className: "px-4 py-2 rounded-lg bg-
|
|
303
|
+
className: "px-4 py-2 rounded-lg bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90 transition-colors flex items-center gap-2",
|
|
304
304
|
children: [K ? /* @__PURE__ */ w(g, { className: "size-4 animate-spin" }) : /* @__PURE__ */ w(y, { className: "size-4 " }), G("channel.delete", "Delete")]
|
|
305
305
|
}),
|
|
306
306
|
/* @__PURE__ */ w("button", {
|
|
307
307
|
type: "button",
|
|
308
308
|
onClick: () => Z(!1),
|
|
309
|
-
className: "px-4 py-2 rounded-lg border hover:bg-
|
|
309
|
+
className: "px-4 py-2 rounded-lg border hover:bg-bg-sunken transition-colors",
|
|
310
310
|
children: G("channel.cancel", "Cancel")
|
|
311
311
|
})
|
|
312
312
|
]
|
|
@@ -315,7 +315,7 @@ function O() {
|
|
|
315
315
|
children: /* @__PURE__ */ T("button", {
|
|
316
316
|
type: "button",
|
|
317
317
|
onClick: () => Z(!0),
|
|
318
|
-
className: "px-4 py-2 rounded-lg text-
|
|
318
|
+
className: "px-4 py-2 rounded-lg text-status-error-text border border-status-error-border hover:bg-status-error-bg/10 transition-colors flex items-center gap-2",
|
|
319
319
|
children: [/* @__PURE__ */ w(y, { className: "size-4 " }), G("channel.delete", "Delete")]
|
|
320
320
|
})
|
|
321
321
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConnectionDetailsPage.js","names":[],"sources":["../../../../../src/channel/modules/channels/pages/ConnectionDetailsPage.tsx"],"sourcesContent":["/**\n * Connection Details Page\n *\n * View and manage a specific connection within a channel.\n */\n\nimport { useEffect, useState } from 'react';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { TagBadge } from '@burdenoff/fe-libs/tag';\nimport { reportShellError } from '../../../utils/shellBridge';\nimport { nativeImpact, nativeNotify } from '../../../../utils/nativeBridge';\nimport {\n ArrowLeft,\n Loader2,\n AlertCircle,\n CheckCircle2,\n XCircle,\n RefreshCw,\n Trash2,\n Edit,\n Shield,\n Clock,\n} from 'lucide-react';\nimport { useChannel } from '../../../hooks/useChannels';\nimport { useChannel as useChannelContext } from '../../../providers/ChannelProvider';\nimport { getGlobalChannelClient } from '../../../graphql/global-client';\nimport {\n GetConnectionDocument,\n type GetConnectionQuery,\n} from '../../../../generated/global-operations';\nimport { PermissionGuard } from '../../../components/PermissionGuard';\nimport { CHANNEL_PERMISSIONS } from '../../../constants/permissions';\n\nconst HEALTH_CONFIG: Record<\n string,\n { icon: typeof CheckCircle2; color: string; bgColor: string; label: string }\n> = {\n true: {\n icon: CheckCircle2,\n color: 'text-status-success-text',\n bgColor: 'bg-status-success-bg-subtle',\n label: 'Healthy',\n },\n false: {\n icon: XCircle,\n color: 'text-status-error-text',\n bgColor: 'bg-error-500/10',\n label: 'Unhealthy',\n },\n};\n\nexport function ConnectionDetailsPage() {\n const navigate = useNavigate();\n const { hasPermission } = usePermissions();\n const canUpdate = hasPermission(CHANNEL_PERMISSIONS.CHANNEL_UPDATE);\n const params = useParams<{ channelId?: string; connectionId: string }>();\n const { connectionId } = params;\n const { authToken, apiGatewayUrl, organizationId } = useChannelContext();\n\n // Route may be /channels/connections/:connectionId (no channelId in URL).\n // Resolve channelId from getConnection when absent so downstream channel hooks work.\n const [resolvedChannelId, setResolvedChannelId] = useState<string | undefined>(params.channelId);\n const [resolveError, setResolveError] = useState<string | null>(null);\n\n useEffect(() => {\n if (resolvedChannelId || !connectionId) return;\n let cancelled = false;\n void (async () => {\n try {\n const client = getGlobalChannelClient(apiGatewayUrl, authToken, organizationId);\n const result = await client.query<GetConnectionQuery>({\n query: GetConnectionDocument,\n variables: { id: connectionId },\n fetchPolicy: 'network-only',\n });\n if (cancelled) return;\n const conn = result.data?.getConnection;\n if (conn?.channelId) setResolvedChannelId(conn.channelId);\n else setResolveError('Connection not found');\n } catch (err) {\n if (!cancelled)\n setResolveError(err instanceof Error ? err.message : 'Failed to resolve connection');\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [connectionId, resolvedChannelId, apiGatewayUrl, authToken, organizationId]);\n\n const channelId = resolvedChannelId;\n const { channel, isLoading, error, runHealthCheck, deleteConnection } = useChannel(channelId);\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n const [isDeleting, setIsDeleting] = useState(false);\n const [isRunningHealth, setIsRunningHealth] = useState(false);\n const [deleteConfirm, setDeleteConfirm] = useState(false);\n\n const connection = channel?.connection;\n\n // Run health check\n const handleRunHealthCheck = async () => {\n setIsRunningHealth(true);\n try {\n await runHealthCheck();\n } finally {\n setIsRunningHealth(false);\n }\n };\n\n // Delete connection\n const handleDelete = async () => {\n if (!connectionId) return;\n void nativeImpact('medium');\n setIsDeleting(true);\n try {\n // deleteConnection throws on failure; success is guaranteed if it returns.\n await deleteConnection(connectionId);\n void nativeNotify('success');\n navigate(`/channels/${channelId}`);\n } catch (err) {\n void nativeNotify('error');\n reportShellError(\n err,\n { module: 'channel', context: { action: 'Failed to delete connection' } },\n '[channel] Failed to delete connection'\n );\n } finally {\n setIsDeleting(false);\n }\n };\n\n if (isLoading || (!resolvedChannelId && !resolveError)) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <Loader2 className=\"size-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (resolveError || error || !channel) {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-screen gap-4\">\n <AlertCircle className=\"size-12 text-destructive\" />\n <h1 className=\"text-xl font-semibold\">\n {tr('channel.channelNotFound', 'Channel not found')}\n </h1>\n <button\n type=\"button\"\n onClick={() => navigate('../../list')}\n className=\"text-primary hover:underline\"\n >\n {tr('channel.backToChannels', 'Back to channels')}\n </button>\n </div>\n );\n }\n\n if (!connection) {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-screen gap-4\">\n <AlertCircle className=\"size-12 text-muted-foreground\" />\n <h1 className=\"text-xl font-semibold\">\n {tr('channel.noConnectionFound', 'No connection found')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n 'channel.noConnectionConfigured',\n 'This channel does not have a connection configured.'\n )}\n </p>\n <button\n type=\"button\"\n onClick={() => navigate(`/channels/${channelId}`)}\n className=\"text-primary hover:underline\"\n >\n {tr('channel.backToChannel', 'Back to channel')}\n </button>\n </div>\n );\n }\n\n const health = HEALTH_CONFIG[String(connection.isHealthy)] || HEALTH_CONFIG.false;\n const HealthIcon = health.icon;\n\n return (\n <PermissionGuard permission={CHANNEL_PERMISSIONS.CHANNEL_CONNECTION_READ}>\n <div className=\"min-h-screen bg-background\">\n {/* Header */}\n <div className=\"border-b bg-card\">\n <div className=\"container mx-auto px-6 py-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => navigate(`/channels/${channelId}`)}\n className=\"p-2 hover:bg-muted rounded-lg transition-colors\"\n >\n <ArrowLeft className=\"size-5 \" />\n </button>\n <div>\n <h1 className=\"text-2xl font-bold\">\n {tr('channel.connectionDetails', 'Connection Details')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {channel.name} • {channel.platform}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <PermissionGuard permission={CHANNEL_PERMISSIONS.CHANNEL_EXECUTE}>\n <button\n type=\"button\"\n onClick={handleRunHealthCheck}\n disabled={isRunningHealth}\n className=\"px-4 py-2 rounded-lg border hover:bg-muted transition-colors flex items-center gap-2\"\n >\n {isRunningHealth ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <RefreshCw className=\"size-4 \" />\n )}\n {tr('channel.runHealthCheck', 'Run Health Check')}\n </button>\n </PermissionGuard>\n {canUpdate && (\n <button\n type=\"button\"\n onClick={() => navigate(`/channels/${channelId}/edit`)}\n className=\"px-4 py-2 rounded-lg border hover:bg-muted transition-colors flex items-center gap-2\"\n >\n <Edit className=\"size-4 \" />\n {tr('channel.editChannel', 'Edit Channel')}\n </button>\n )}\n </div>\n </div>\n </div>\n </div>\n\n {/* Content */}\n <div className=\"container mx-auto px-6 py-8 max-w-3xl space-y-6\">\n {/* Health Status */}\n <div className={`p-6 rounded-lg border ${health.bgColor}`}>\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <div className={health.color}>\n <HealthIcon className=\"size-10 \" />\n </div>\n <div>\n <h2 className=\"text-xl font-semibold\">{health.label}</h2>\n <p className=\"text-sm text-muted-foreground\">\n {connection.isHealthy\n ? tr('channel.connectionWorking', 'Connection is working properly')\n : tr('channel.connectionNotWorking', 'Connection is not working properly')}\n </p>\n </div>\n </div>\n </div>\n </div>\n\n {/* Connection Info */}\n <div className=\"border rounded-lg p-6 space-y-4\">\n <h3 className=\"font-semibold\">\n {tr('channel.connectionInformation', 'Connection Information')}\n </h3>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-muted-foreground\">Connection ID</p>\n <p className=\"font-mono text-sm\">{connection.id}</p>\n </div>\n\n <div>\n <p className=\"text-sm text-muted-foreground\">Auth Type</p>\n <p className=\"flex items-center gap-2\">\n <Shield className=\"size-4 text-muted-foreground\" />\n {connection.authType}\n </p>\n </div>\n\n <div>\n <p className=\"text-sm text-muted-foreground\">Status</p>\n <p\n className={\n connection.isActive ? 'text-status-success-text' : 'text-muted-foreground'\n }\n >\n {connection.isActive\n ? tr('channel.activeStatus', 'Active')\n : tr('channel.inactiveStatus', 'Inactive')}\n </p>\n </div>\n\n <div>\n <p className=\"text-sm text-muted-foreground\">Token Refresh</p>\n <p\n className={\n connection.needsTokenRefresh\n ? 'text-status-warning-text'\n : 'text-muted-foreground'\n }\n >\n {connection.needsTokenRefresh\n ? tr('channel.tokenRefreshRequired', 'Required soon')\n : tr('channel.tokenRefreshNotNeeded', 'Not needed')}\n </p>\n </div>\n\n {connection.lastTestedAt && (\n <div>\n <p className=\"text-sm text-muted-foreground\">Last Tested</p>\n <p className=\"flex items-center gap-2\">\n <Clock className=\"size-4 text-muted-foreground\" />\n {new Date(connection.lastTestedAt).toLocaleString()}\n </p>\n </div>\n )}\n\n {connection.daysUntilExpiry !== null && connection.daysUntilExpiry !== undefined && (\n <div>\n <p className=\"text-sm text-muted-foreground\">Days Until Token Expiry</p>\n <p\n className={\n connection.daysUntilExpiry < 30\n ? 'text-status-warning-text'\n : 'text-muted-foreground'\n }\n >\n {connection.daysUntilExpiry} days\n </p>\n </div>\n )}\n </div>\n\n {connection.testStatus && (\n <div className=\"pt-4 border-t\">\n <p className=\"text-sm text-muted-foreground mb-2\">Last Test Status</p>\n <div className=\"p-3 rounded-lg bg-muted\">\n <p className=\"font-mono text-sm\">{connection.testStatus}</p>\n </div>\n </div>\n )}\n\n {connection.tagAssignments && connection.tagAssignments.length > 0 && (\n <div className=\"pt-4 border-t\">\n <p className=\"text-sm text-muted-foreground mb-2\">{tr('channel.tags', 'Tags')}</p>\n <div className=\"flex flex-wrap gap-1.5\" aria-label=\"Connection tags\">\n {connection.tagAssignments.map((a) => (\n <TagBadge key={a.id} id={a.tagId} label={a.tagId} size=\"md\" />\n ))}\n </div>\n </div>\n )}\n </div>\n\n {/* Actions */}\n <div className=\"border rounded-lg p-6 space-y-4\">\n <h3 className=\"font-semibold\">{tr('channel.actions', 'Actions')}</h3>\n\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"font-medium\">{tr('channel.deleteConnection', 'Delete Connection')}</p>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\n 'channel.deleteConnectionWarning',\n 'Permanently remove this connection. The channel will become inactive.'\n )}\n </p>\n </div>\n\n {!deleteConfirm ? (\n <PermissionGuard permission={CHANNEL_PERMISSIONS.CHANNEL_CONNECTION_DELETE}>\n <button\n type=\"button\"\n onClick={() => setDeleteConfirm(true)}\n className=\"px-4 py-2 rounded-lg text-destructive border border-destructive hover:bg-destructive/10 transition-colors flex items-center gap-2\"\n >\n <Trash2 className=\"size-4 \" />\n {tr('channel.delete', 'Delete')}\n </button>\n </PermissionGuard>\n ) : (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-muted-foreground\">\n {tr('channel.confirmDelete', 'Confirm delete?')}\n </span>\n <button\n type=\"button\"\n onClick={handleDelete}\n disabled={isDeleting}\n className=\"px-4 py-2 rounded-lg bg-destructive text-destructive-foreground hover:bg-destructive/90 transition-colors flex items-center gap-2\"\n >\n {isDeleting ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <Trash2 className=\"size-4 \" />\n )}\n {tr('channel.delete', 'Delete')}\n </button>\n <button\n type=\"button\"\n onClick={() => setDeleteConfirm(false)}\n className=\"px-4 py-2 rounded-lg border hover:bg-muted transition-colors\"\n >\n {tr('channel.cancel', 'Cancel')}\n </button>\n </div>\n )}\n </div>\n </div>\n </div>\n </div>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ConnectionDetailsPage.js","names":[],"sources":["../../../../../src/channel/modules/channels/pages/ConnectionDetailsPage.tsx"],"sourcesContent":["/**\n * Connection Details Page\n *\n * View and manage a specific connection within a channel.\n */\n\nimport { useEffect, useState } from 'react';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { TagBadge } from '@burdenoff/fe-libs/tag';\nimport { reportShellError } from '../../../utils/shellBridge';\nimport { nativeImpact, nativeNotify } from '../../../../utils/nativeBridge';\nimport {\n ArrowLeft,\n Loader2,\n AlertCircle,\n CheckCircle2,\n XCircle,\n RefreshCw,\n Trash2,\n Edit,\n Shield,\n Clock,\n} from 'lucide-react';\nimport { useChannel } from '../../../hooks/useChannels';\nimport { useChannel as useChannelContext } from '../../../providers/ChannelProvider';\nimport { getGlobalChannelClient } from '../../../graphql/global-client';\nimport {\n GetConnectionDocument,\n type GetConnectionQuery,\n} from '../../../../generated/global-operations';\nimport { PermissionGuard } from '../../../components/PermissionGuard';\nimport { CHANNEL_PERMISSIONS } from '../../../constants/permissions';\n\nconst HEALTH_CONFIG: Record<\n string,\n { icon: typeof CheckCircle2; color: string; bgColor: string; label: string }\n> = {\n true: {\n icon: CheckCircle2,\n color: 'text-status-success-text',\n bgColor: 'bg-status-success-bg-subtle',\n label: 'Healthy',\n },\n false: {\n icon: XCircle,\n color: 'text-status-error-text',\n bgColor: 'bg-error-500/10',\n label: 'Unhealthy',\n },\n};\n\nexport function ConnectionDetailsPage() {\n const navigate = useNavigate();\n const { hasPermission } = usePermissions();\n const canUpdate = hasPermission(CHANNEL_PERMISSIONS.CHANNEL_UPDATE);\n const params = useParams<{ channelId?: string; connectionId: string }>();\n const { connectionId } = params;\n const { authToken, apiGatewayUrl, organizationId } = useChannelContext();\n\n // Route may be /channels/connections/:connectionId (no channelId in URL).\n // Resolve channelId from getConnection when absent so downstream channel hooks work.\n const [resolvedChannelId, setResolvedChannelId] = useState<string | undefined>(params.channelId);\n const [resolveError, setResolveError] = useState<string | null>(null);\n\n useEffect(() => {\n if (resolvedChannelId || !connectionId) return;\n let cancelled = false;\n void (async () => {\n try {\n const client = getGlobalChannelClient(apiGatewayUrl, authToken, organizationId);\n const result = await client.query<GetConnectionQuery>({\n query: GetConnectionDocument,\n variables: { id: connectionId },\n fetchPolicy: 'network-only',\n });\n if (cancelled) return;\n const conn = result.data?.getConnection;\n if (conn?.channelId) setResolvedChannelId(conn.channelId);\n else setResolveError('Connection not found');\n } catch (err) {\n if (!cancelled)\n setResolveError(err instanceof Error ? err.message : 'Failed to resolve connection');\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [connectionId, resolvedChannelId, apiGatewayUrl, authToken, organizationId]);\n\n const channelId = resolvedChannelId;\n const { channel, isLoading, error, runHealthCheck, deleteConnection } = useChannel(channelId);\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n const [isDeleting, setIsDeleting] = useState(false);\n const [isRunningHealth, setIsRunningHealth] = useState(false);\n const [deleteConfirm, setDeleteConfirm] = useState(false);\n\n const connection = channel?.connection;\n\n // Run health check\n const handleRunHealthCheck = async () => {\n setIsRunningHealth(true);\n try {\n await runHealthCheck();\n } finally {\n setIsRunningHealth(false);\n }\n };\n\n // Delete connection\n const handleDelete = async () => {\n if (!connectionId) return;\n void nativeImpact('medium');\n setIsDeleting(true);\n try {\n // deleteConnection throws on failure; success is guaranteed if it returns.\n await deleteConnection(connectionId);\n void nativeNotify('success');\n navigate(`/channels/${channelId}`);\n } catch (err) {\n void nativeNotify('error');\n reportShellError(\n err,\n { module: 'channel', context: { action: 'Failed to delete connection' } },\n '[channel] Failed to delete connection'\n );\n } finally {\n setIsDeleting(false);\n }\n };\n\n if (isLoading || (!resolvedChannelId && !resolveError)) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <Loader2 className=\"size-8 animate-spin text-text-secondary\" />\n </div>\n );\n }\n\n if (resolveError || error || !channel) {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-screen gap-4\">\n <AlertCircle className=\"size-12 text-status-error-text\" />\n <h1 className=\"text-xl font-semibold\">\n {tr('channel.channelNotFound', 'Channel not found')}\n </h1>\n <button\n type=\"button\"\n onClick={() => navigate('../../list')}\n className=\"text-primary hover:underline\"\n >\n {tr('channel.backToChannels', 'Back to channels')}\n </button>\n </div>\n );\n }\n\n if (!connection) {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-screen gap-4\">\n <AlertCircle className=\"size-12 text-text-secondary\" />\n <h1 className=\"text-xl font-semibold\">\n {tr('channel.noConnectionFound', 'No connection found')}\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'channel.noConnectionConfigured',\n 'This channel does not have a connection configured.'\n )}\n </p>\n <button\n type=\"button\"\n onClick={() => navigate(`/channels/${channelId}`)}\n className=\"text-primary hover:underline\"\n >\n {tr('channel.backToChannel', 'Back to channel')}\n </button>\n </div>\n );\n }\n\n const health = HEALTH_CONFIG[String(connection.isHealthy)] || HEALTH_CONFIG.false;\n const HealthIcon = health.icon;\n\n return (\n <PermissionGuard permission={CHANNEL_PERMISSIONS.CHANNEL_CONNECTION_READ}>\n <div className=\"min-h-screen bg-bg-surface\">\n {/* Header */}\n <div className=\"border-b bg-bg-surface\">\n <div className=\"container mx-auto px-6 py-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <button\n type=\"button\"\n onClick={() => navigate(`/channels/${channelId}`)}\n className=\"p-2 hover:bg-bg-sunken rounded-lg transition-colors\"\n >\n <ArrowLeft className=\"size-5 \" />\n </button>\n <div>\n <h1 className=\"text-2xl font-bold\">\n {tr('channel.connectionDetails', 'Connection Details')}\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {channel.name} • {channel.platform}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <PermissionGuard permission={CHANNEL_PERMISSIONS.CHANNEL_EXECUTE}>\n <button\n type=\"button\"\n onClick={handleRunHealthCheck}\n disabled={isRunningHealth}\n className=\"px-4 py-2 rounded-lg border hover:bg-bg-sunken transition-colors flex items-center gap-2\"\n >\n {isRunningHealth ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <RefreshCw className=\"size-4 \" />\n )}\n {tr('channel.runHealthCheck', 'Run Health Check')}\n </button>\n </PermissionGuard>\n {canUpdate && (\n <button\n type=\"button\"\n onClick={() => navigate(`/channels/${channelId}/edit`)}\n className=\"px-4 py-2 rounded-lg border hover:bg-bg-sunken transition-colors flex items-center gap-2\"\n >\n <Edit className=\"size-4 \" />\n {tr('channel.editChannel', 'Edit Channel')}\n </button>\n )}\n </div>\n </div>\n </div>\n </div>\n\n {/* Content */}\n <div className=\"container mx-auto px-6 py-8 max-w-3xl space-y-6\">\n {/* Health Status */}\n <div className={`p-6 rounded-lg border ${health.bgColor}`}>\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <div className={health.color}>\n <HealthIcon className=\"size-10 \" />\n </div>\n <div>\n <h2 className=\"text-xl font-semibold\">{health.label}</h2>\n <p className=\"text-sm text-text-secondary\">\n {connection.isHealthy\n ? tr('channel.connectionWorking', 'Connection is working properly')\n : tr('channel.connectionNotWorking', 'Connection is not working properly')}\n </p>\n </div>\n </div>\n </div>\n </div>\n\n {/* Connection Info */}\n <div className=\"border rounded-lg p-6 space-y-4\">\n <h3 className=\"font-semibold\">\n {tr('channel.connectionInformation', 'Connection Information')}\n </h3>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Connection ID</p>\n <p className=\"font-mono text-sm\">{connection.id}</p>\n </div>\n\n <div>\n <p className=\"text-sm text-text-secondary\">Auth Type</p>\n <p className=\"flex items-center gap-2\">\n <Shield className=\"size-4 text-text-secondary\" />\n {connection.authType}\n </p>\n </div>\n\n <div>\n <p className=\"text-sm text-text-secondary\">Status</p>\n <p\n className={\n connection.isActive ? 'text-status-success-text' : 'text-text-secondary'\n }\n >\n {connection.isActive\n ? tr('channel.activeStatus', 'Active')\n : tr('channel.inactiveStatus', 'Inactive')}\n </p>\n </div>\n\n <div>\n <p className=\"text-sm text-text-secondary\">Token Refresh</p>\n <p\n className={\n connection.needsTokenRefresh\n ? 'text-status-warning-text'\n : 'text-text-secondary'\n }\n >\n {connection.needsTokenRefresh\n ? tr('channel.tokenRefreshRequired', 'Required soon')\n : tr('channel.tokenRefreshNotNeeded', 'Not needed')}\n </p>\n </div>\n\n {connection.lastTestedAt && (\n <div>\n <p className=\"text-sm text-text-secondary\">Last Tested</p>\n <p className=\"flex items-center gap-2\">\n <Clock className=\"size-4 text-text-secondary\" />\n {new Date(connection.lastTestedAt).toLocaleString()}\n </p>\n </div>\n )}\n\n {connection.daysUntilExpiry !== null && connection.daysUntilExpiry !== undefined && (\n <div>\n <p className=\"text-sm text-text-secondary\">Days Until Token Expiry</p>\n <p\n className={\n connection.daysUntilExpiry < 30\n ? 'text-status-warning-text'\n : 'text-text-secondary'\n }\n >\n {connection.daysUntilExpiry} days\n </p>\n </div>\n )}\n </div>\n\n {connection.testStatus && (\n <div className=\"pt-4 border-t\">\n <p className=\"text-sm text-text-secondary mb-2\">Last Test Status</p>\n <div className=\"p-3 rounded-lg bg-bg-sunken\">\n <p className=\"font-mono text-sm\">{connection.testStatus}</p>\n </div>\n </div>\n )}\n\n {connection.tagAssignments && connection.tagAssignments.length > 0 && (\n <div className=\"pt-4 border-t\">\n <p className=\"text-sm text-text-secondary mb-2\">{tr('channel.tags', 'Tags')}</p>\n <div className=\"flex flex-wrap gap-1.5\" aria-label=\"Connection tags\">\n {connection.tagAssignments.map((a) => (\n <TagBadge key={a.id} id={a.tagId} label={a.tagId} size=\"md\" />\n ))}\n </div>\n </div>\n )}\n </div>\n\n {/* Actions */}\n <div className=\"border rounded-lg p-6 space-y-4\">\n <h3 className=\"font-semibold\">{tr('channel.actions', 'Actions')}</h3>\n\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"font-medium\">{tr('channel.deleteConnection', 'Delete Connection')}</p>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'channel.deleteConnectionWarning',\n 'Permanently remove this connection. The channel will become inactive.'\n )}\n </p>\n </div>\n\n {!deleteConfirm ? (\n <PermissionGuard permission={CHANNEL_PERMISSIONS.CHANNEL_CONNECTION_DELETE}>\n <button\n type=\"button\"\n onClick={() => setDeleteConfirm(true)}\n className=\"px-4 py-2 rounded-lg text-status-error-text border border-status-error-border hover:bg-status-error-bg/10 transition-colors flex items-center gap-2\"\n >\n <Trash2 className=\"size-4 \" />\n {tr('channel.delete', 'Delete')}\n </button>\n </PermissionGuard>\n ) : (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-text-secondary\">\n {tr('channel.confirmDelete', 'Confirm delete?')}\n </span>\n <button\n type=\"button\"\n onClick={handleDelete}\n disabled={isDeleting}\n className=\"px-4 py-2 rounded-lg bg-status-error-bg text-status-error-text hover:bg-status-error-bg/90 transition-colors flex items-center gap-2\"\n >\n {isDeleting ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <Trash2 className=\"size-4 \" />\n )}\n {tr('channel.delete', 'Delete')}\n </button>\n <button\n type=\"button\"\n onClick={() => setDeleteConfirm(false)}\n className=\"px-4 py-2 rounded-lg border hover:bg-bg-sunken transition-colors\"\n >\n {tr('channel.cancel', 'Cancel')}\n </button>\n </div>\n )}\n </div>\n </div>\n </div>\n </div>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}
|
|
@@ -51,33 +51,33 @@ function S() {
|
|
|
51
51
|
}, []), I = [...new Set(F.map((e) => e.platform))], L = F.filter((e) => !(k === "healthy" && !e.isHealthy || k === "unhealthy" && e.isHealthy || j !== "all" && e.platform !== j)), R = Math.max(1, Math.ceil(L.length / 10)), z = L.slice(N * 10, (N + 1) * 10);
|
|
52
52
|
return w ? /* @__PURE__ */ v("div", {
|
|
53
53
|
className: "flex items-center justify-center min-h-screen",
|
|
54
|
-
children: /* @__PURE__ */ v(u, { className: "size-8 animate-spin text-
|
|
54
|
+
children: /* @__PURE__ */ v(u, { className: "size-8 animate-spin text-text-secondary" })
|
|
55
55
|
}) : T ? /* @__PURE__ */ y("div", {
|
|
56
56
|
className: "flex flex-col items-center justify-center min-h-screen gap-4",
|
|
57
57
|
children: [
|
|
58
|
-
/* @__PURE__ */ v(o, { className: "size-12 text-
|
|
58
|
+
/* @__PURE__ */ v(o, { className: "size-12 text-status-error-text" }),
|
|
59
59
|
/* @__PURE__ */ v("h1", {
|
|
60
60
|
className: "text-xl font-semibold",
|
|
61
61
|
children: O("channel.loadConnectionsFailed", "Failed to load connections")
|
|
62
62
|
}),
|
|
63
63
|
/* @__PURE__ */ v("p", {
|
|
64
|
-
className: "text-sm text-
|
|
64
|
+
className: "text-sm text-text-secondary",
|
|
65
65
|
children: T
|
|
66
66
|
}),
|
|
67
67
|
/* @__PURE__ */ v("button", {
|
|
68
68
|
type: "button",
|
|
69
69
|
onClick: () => E(),
|
|
70
|
-
className: "px-4 py-2 rounded-lg bg-primary text-primary-
|
|
70
|
+
className: "px-4 py-2 rounded-lg bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90",
|
|
71
71
|
children: O("channel.retry", "Retry")
|
|
72
72
|
})
|
|
73
73
|
]
|
|
74
74
|
}) : /* @__PURE__ */ v(t, {
|
|
75
75
|
permission: n.CHANNEL_CONNECTION_READ,
|
|
76
76
|
children: /* @__PURE__ */ y("div", {
|
|
77
|
-
className: "min-h-screen bg-
|
|
77
|
+
className: "min-h-screen bg-bg-surface",
|
|
78
78
|
children: [
|
|
79
79
|
/* @__PURE__ */ v("div", {
|
|
80
|
-
className: "border-b bg-
|
|
80
|
+
className: "border-b bg-bg-surface",
|
|
81
81
|
"data-tour": "channels-connections-header",
|
|
82
82
|
children: /* @__PURE__ */ v("div", {
|
|
83
83
|
className: "container mx-auto px-6 py-4",
|
|
@@ -89,13 +89,13 @@ function S() {
|
|
|
89
89
|
type: "button",
|
|
90
90
|
onClick: () => c("./list"),
|
|
91
91
|
"aria-label": O("channel.backToChannels", "Back to channels"),
|
|
92
|
-
className: "p-2 hover:bg-
|
|
92
|
+
className: "p-2 hover:bg-bg-sunken rounded-lg transition-colors",
|
|
93
93
|
children: /* @__PURE__ */ v(s, { className: "size-5 " })
|
|
94
94
|
}), /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("h1", {
|
|
95
95
|
className: "text-2xl font-bold",
|
|
96
96
|
children: O("channel.connections", "Connections")
|
|
97
97
|
}), /* @__PURE__ */ y("p", {
|
|
98
|
-
className: "text-sm text-
|
|
98
|
+
className: "text-sm text-text-secondary",
|
|
99
99
|
children: [
|
|
100
100
|
L.length,
|
|
101
101
|
" connection",
|
|
@@ -105,7 +105,7 @@ function S() {
|
|
|
105
105
|
}), S && /* @__PURE__ */ y("button", {
|
|
106
106
|
type: "button",
|
|
107
107
|
onClick: () => c("./create"),
|
|
108
|
-
className: "px-4 py-2 rounded-lg bg-primary text-primary-
|
|
108
|
+
className: "px-4 py-2 rounded-lg bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90 transition-colors flex items-center gap-2",
|
|
109
109
|
children: [/* @__PURE__ */ v(d, { className: "size-4 " }), O("channel.newConnection", "New Connection")]
|
|
110
110
|
})]
|
|
111
111
|
})
|
|
@@ -120,7 +120,7 @@ function S() {
|
|
|
120
120
|
/* @__PURE__ */ y("select", {
|
|
121
121
|
value: j,
|
|
122
122
|
onChange: (e) => M(e.target.value),
|
|
123
|
-
className: "px-4 py-2 rounded-lg border bg-
|
|
123
|
+
className: "px-4 py-2 rounded-lg border bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary",
|
|
124
124
|
children: [/* @__PURE__ */ v("option", {
|
|
125
125
|
value: "all",
|
|
126
126
|
children: O("channel.allPlatforms", "All Platforms")
|
|
@@ -132,7 +132,7 @@ function S() {
|
|
|
132
132
|
/* @__PURE__ */ y("select", {
|
|
133
133
|
value: k,
|
|
134
134
|
onChange: (e) => A(e.target.value),
|
|
135
|
-
className: "px-4 py-2 rounded-lg border bg-
|
|
135
|
+
className: "px-4 py-2 rounded-lg border bg-bg-surface focus:outline-none focus:ring-2 focus:ring-primary",
|
|
136
136
|
children: [
|
|
137
137
|
/* @__PURE__ */ v("option", {
|
|
138
138
|
value: "all",
|
|
@@ -152,7 +152,7 @@ function S() {
|
|
|
152
152
|
type: "button",
|
|
153
153
|
onClick: () => E(),
|
|
154
154
|
"aria-label": O("channel.refresh", "Refresh"),
|
|
155
|
-
className: "p-2 hover:bg-
|
|
155
|
+
className: "p-2 hover:bg-bg-sunken rounded-lg transition-colors",
|
|
156
156
|
children: /* @__PURE__ */ v(f, {
|
|
157
157
|
className: "size-5 ",
|
|
158
158
|
"aria-hidden": "true"
|
|
@@ -166,26 +166,26 @@ function S() {
|
|
|
166
166
|
children: L.length === 0 ? /* @__PURE__ */ y("div", {
|
|
167
167
|
className: "text-center py-12",
|
|
168
168
|
children: [
|
|
169
|
-
/* @__PURE__ */ v(l, { className: "size-12 mx-auto text-
|
|
169
|
+
/* @__PURE__ */ v(l, { className: "size-12 mx-auto text-text-secondary mb-4" }),
|
|
170
170
|
/* @__PURE__ */ v("h2", {
|
|
171
171
|
className: "text-lg font-semibold mb-2",
|
|
172
172
|
children: O("channel.noConnectionsFound", "No connections found")
|
|
173
173
|
}),
|
|
174
174
|
/* @__PURE__ */ v("p", {
|
|
175
|
-
className: "text-sm text-
|
|
175
|
+
className: "text-sm text-text-secondary mb-4",
|
|
176
176
|
children: C.length === 0 ? O("channel.createChannelFirst", "Create a channel first to add connections") : O("channel.noConnectionsMatchFilter", "No connections match your filters")
|
|
177
177
|
}),
|
|
178
178
|
C.length === 0 ? S ? /* @__PURE__ */ v("button", {
|
|
179
179
|
type: "button",
|
|
180
180
|
onClick: () => c("./create"),
|
|
181
|
-
className: "px-4 py-2 rounded-lg bg-primary text-primary-
|
|
181
|
+
className: "px-4 py-2 rounded-lg bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg/90",
|
|
182
182
|
children: O("channel.createConnection", "Create Connection")
|
|
183
183
|
}) : null : /* @__PURE__ */ v("button", {
|
|
184
184
|
type: "button",
|
|
185
185
|
onClick: () => {
|
|
186
186
|
A("all"), M("all");
|
|
187
187
|
},
|
|
188
|
-
className: "px-4 py-2 rounded-lg border hover:bg-
|
|
188
|
+
className: "px-4 py-2 rounded-lg border hover:bg-bg-sunken",
|
|
189
189
|
children: O("channel.clearFilters", "Clear Filters")
|
|
190
190
|
})
|
|
191
191
|
]
|
|
@@ -196,7 +196,7 @@ function S() {
|
|
|
196
196
|
return /* @__PURE__ */ v("div", {
|
|
197
197
|
role: "button",
|
|
198
198
|
tabIndex: 0,
|
|
199
|
-
className: "p-4 hover:bg-
|
|
199
|
+
className: "p-4 hover:bg-bg-sunken/50 transition-colors cursor-pointer",
|
|
200
200
|
onClick: () => c(`./${e.channelId}`),
|
|
201
201
|
onKeyDown: (t) => {
|
|
202
202
|
(t.key === "Enter" || t.key === " ") && (t.preventDefault(), c(`./${e.channelId}`));
|
|
@@ -216,7 +216,7 @@ function S() {
|
|
|
216
216
|
className: "font-medium",
|
|
217
217
|
children: e.channelName
|
|
218
218
|
}), /* @__PURE__ */ y("p", {
|
|
219
|
-
className: "text-sm text-
|
|
219
|
+
className: "text-sm text-text-secondary",
|
|
220
220
|
children: [
|
|
221
221
|
e.platform,
|
|
222
222
|
" • ",
|
|
@@ -236,7 +236,7 @@ function S() {
|
|
|
236
236
|
className: "text-status-success-text",
|
|
237
237
|
children: O("channel.activeStatus", "Active")
|
|
238
238
|
}) : e.channelStatus === "INACTIVE" ? /* @__PURE__ */ v("span", {
|
|
239
|
-
className: "text-
|
|
239
|
+
className: "text-text-secondary",
|
|
240
240
|
children: O("channel.inactiveStatus", "Inactive")
|
|
241
241
|
}) : e.channelStatus === "ERROR" ? /* @__PURE__ */ v("span", {
|
|
242
242
|
className: "text-status-error-text",
|
|
@@ -245,14 +245,14 @@ function S() {
|
|
|
245
245
|
className: "text-status-warning-text",
|
|
246
246
|
children: O("channel.suspendedStatus", "Suspended")
|
|
247
247
|
}) : e.channelStatus === "ARCHIVED" ? /* @__PURE__ */ v("span", {
|
|
248
|
-
className: "text-
|
|
248
|
+
className: "text-text-secondary",
|
|
249
249
|
children: O("channel.archivedStatus", "Archived")
|
|
250
250
|
}) : /* @__PURE__ */ v("span", {
|
|
251
|
-
className: "text-
|
|
251
|
+
className: "text-text-secondary",
|
|
252
252
|
children: O("channel.inactiveStatus", "Inactive")
|
|
253
253
|
})
|
|
254
254
|
}), e.lastTestedAt && /* @__PURE__ */ y("p", {
|
|
255
|
-
className: "text-xs text-
|
|
255
|
+
className: "text-xs text-text-secondary",
|
|
256
256
|
children: ["Last tested: ", new Date(e.lastTestedAt).toLocaleDateString()]
|
|
257
257
|
})]
|
|
258
258
|
}),
|
|
@@ -268,7 +268,7 @@ function S() {
|
|
|
268
268
|
label: e.tagId,
|
|
269
269
|
size: "sm"
|
|
270
270
|
}, e.id)), e.tagAssignments.length > 3 && /* @__PURE__ */ y("span", {
|
|
271
|
-
className: "text-xs text-
|
|
271
|
+
className: "text-xs text-text-secondary",
|
|
272
272
|
children: ["+", e.tagAssignments.length - 3]
|
|
273
273
|
})]
|
|
274
274
|
}),
|
|
@@ -278,7 +278,7 @@ function S() {
|
|
|
278
278
|
t.stopPropagation(), c(`/channels/${e.channelId}`);
|
|
279
279
|
},
|
|
280
280
|
"aria-label": O("channel.viewChannelSettings", "View channel settings"),
|
|
281
|
-
className: "p-2 hover:bg-
|
|
281
|
+
className: "p-2 hover:bg-bg-sunken rounded-lg transition-colors",
|
|
282
282
|
children: /* @__PURE__ */ v(p, { className: "size-4 " })
|
|
283
283
|
})
|
|
284
284
|
]
|
|
@@ -287,9 +287,9 @@ function S() {
|
|
|
287
287
|
}, e.connectionId);
|
|
288
288
|
})
|
|
289
289
|
}), L.length > 10 && /* @__PURE__ */ y("div", {
|
|
290
|
-
className: "flex items-center justify-between px-4 py-3 border border-border rounded-lg mt-3",
|
|
290
|
+
className: "flex items-center justify-between px-4 py-3 border border-border-subtle rounded-lg mt-3",
|
|
291
291
|
children: [/* @__PURE__ */ y("p", {
|
|
292
|
-
className: "text-sm text-
|
|
292
|
+
className: "text-sm text-text-secondary",
|
|
293
293
|
children: [
|
|
294
294
|
O("channel.showing", "Showing"),
|
|
295
295
|
" ",
|
|
@@ -316,11 +316,11 @@ function S() {
|
|
|
316
316
|
type: "button",
|
|
317
317
|
onClick: () => P((e) => Math.max(0, e - 1)),
|
|
318
318
|
disabled: N === 0,
|
|
319
|
-
className: "px-3 py-1.5 text-sm border border-border rounded-lg hover:bg-
|
|
319
|
+
className: "px-3 py-1.5 text-sm border border-border-subtle rounded-lg hover:bg-bg-sunken transition-colors disabled:opacity-40 disabled:cursor-not-allowed",
|
|
320
320
|
children: O("channel.previous", "Previous")
|
|
321
321
|
}),
|
|
322
322
|
/* @__PURE__ */ y("span", {
|
|
323
|
-
className: "text-sm text-
|
|
323
|
+
className: "text-sm text-text-secondary",
|
|
324
324
|
children: [
|
|
325
325
|
N + 1,
|
|
326
326
|
" / ",
|
|
@@ -331,7 +331,7 @@ function S() {
|
|
|
331
331
|
type: "button",
|
|
332
332
|
onClick: () => P((e) => Math.min(R - 1, e + 1)),
|
|
333
333
|
disabled: N >= R - 1,
|
|
334
|
-
className: "px-3 py-1.5 text-sm border border-border rounded-lg hover:bg-
|
|
334
|
+
className: "px-3 py-1.5 text-sm border border-border-subtle rounded-lg hover:bg-bg-sunken transition-colors disabled:opacity-40 disabled:cursor-not-allowed",
|
|
335
335
|
children: O("channel.next", "Next")
|
|
336
336
|
})
|
|
337
337
|
]
|