@burdenoff/microfe-channel 2026.624.3 → 2026.625.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/modules/channels/pages/ChannelDashboardPage.js +108 -98
- package/dist/channel/modules/channels/pages/ChannelDashboardPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelDetailsPage.js +287 -277
- package/dist/channel/modules/channels/pages/ChannelDetailsPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelSettingsPage.js +140 -131
- package/dist/channel/modules/channels/pages/ChannelSettingsPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelUsersPage.js +170 -173
- package/dist/channel/modules/channels/pages/ChannelUsersPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelsListPage.js +127 -120
- package/dist/channel/modules/channels/pages/ChannelsListPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js +161 -155
- package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ConnectionsListPage.js +70 -68
- package/dist/channel/modules/channels/pages/ConnectionsListPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/CreateChannelPage.js +27 -24
- package/dist/channel/modules/channels/pages/CreateChannelPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/CreateConnectionPage.js +161 -156
- package/dist/channel/modules/channels/pages/CreateConnectionPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/DeliveryHistoryPage.js +179 -182
- package/dist/channel/modules/channels/pages/DeliveryHistoryPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/EditChannelPage.js +130 -122
- package/dist/channel/modules/channels/pages/EditChannelPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/EditConnectionPage.js +137 -132
- package/dist/channel/modules/channels/pages/EditConnectionPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/SendMessagePage.js +87 -84
- package/dist/channel/modules/channels/pages/SendMessagePage.js.map +1 -1
- package/dist/channel/modules/channels/pages/WebhookEventsPage.js +193 -194
- package/dist/channel/modules/channels/pages/WebhookEventsPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -8,13 +8,14 @@ import { PermissionGuard as o } from "../../../components/PermissionGuard.js";
|
|
|
8
8
|
import { CHANNEL_PERMISSIONS as s } from "../../../constants/permissions.js";
|
|
9
9
|
import { useEffect as c, useState as l } from "react";
|
|
10
10
|
import { useI18n as u } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
11
|
-
import { AlertCircle as d, ArrowLeft as f, CheckCircle2 as p, Clock as
|
|
12
|
-
import { useNavigate as
|
|
13
|
-
import { usePermissions as
|
|
14
|
-
import { jsx as
|
|
15
|
-
import {
|
|
11
|
+
import { AlertCircle as d, ArrowLeft as f, CheckCircle2 as p, Clock as te, Edit as ne, Loader2 as m, RefreshCw as h, Shield as g, Trash2 as _, XCircle as v } from "lucide-react";
|
|
12
|
+
import { useNavigate as y, useParams as b } from "react-router-dom";
|
|
13
|
+
import { usePermissions as x } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
14
|
+
import { jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
15
|
+
import { CTAOverflowMenu as w, EmphasisPanel as T, GlassCard as E } from "@burdenoff/fe-libs/ui";
|
|
16
|
+
import { TagBadge as D } from "@burdenoff/fe-libs/tag";
|
|
16
17
|
//#region src/channel/modules/channels/pages/ConnectionDetailsPage.tsx
|
|
17
|
-
var
|
|
18
|
+
var O = {
|
|
18
19
|
true: {
|
|
19
20
|
icon: p,
|
|
20
21
|
color: "text-status-success-text",
|
|
@@ -22,252 +23,257 @@ var D = {
|
|
|
22
23
|
label: "Healthy"
|
|
23
24
|
},
|
|
24
25
|
false: {
|
|
25
|
-
icon:
|
|
26
|
+
icon: v,
|
|
26
27
|
color: "text-status-error-text",
|
|
27
28
|
bgColor: "bg-error-500/10",
|
|
28
29
|
label: "Unhealthy"
|
|
29
30
|
}
|
|
30
31
|
};
|
|
31
|
-
function
|
|
32
|
-
let p =
|
|
32
|
+
function k() {
|
|
33
|
+
let p = y(), { hasPermission: v } = x(), k = v(s.CHANNEL_UPDATE), re = v(s.CHANNEL_EXECUTE), A = b(), { connectionId: j } = A, { authToken: M, apiGatewayUrl: N, organizationId: P } = e(), [F, I] = l(A.channelId), [L, R] = l(null);
|
|
33
34
|
c(() => {
|
|
34
|
-
if (
|
|
35
|
+
if (F || !j) return;
|
|
35
36
|
let e = !1;
|
|
36
37
|
return (async () => {
|
|
37
38
|
try {
|
|
38
|
-
let t = await r(
|
|
39
|
+
let t = await r(N, M, P).query({
|
|
39
40
|
query: i,
|
|
40
|
-
variables: { id:
|
|
41
|
+
variables: { id: j },
|
|
41
42
|
fetchPolicy: "network-only"
|
|
42
43
|
});
|
|
43
44
|
if (e) return;
|
|
44
45
|
let n = t.data?.getConnection;
|
|
45
|
-
n?.channelId ?
|
|
46
|
+
n?.channelId ? I(n.channelId) : R("Connection not found");
|
|
46
47
|
} catch (t) {
|
|
47
|
-
e ||
|
|
48
|
+
e || R(t instanceof Error ? t.message : "Failed to resolve connection");
|
|
48
49
|
}
|
|
49
50
|
})(), () => {
|
|
50
51
|
e = !0;
|
|
51
52
|
};
|
|
52
53
|
}, [
|
|
53
|
-
A,
|
|
54
|
-
P,
|
|
55
|
-
M,
|
|
56
54
|
j,
|
|
57
|
-
|
|
55
|
+
F,
|
|
56
|
+
N,
|
|
57
|
+
M,
|
|
58
|
+
P
|
|
58
59
|
]);
|
|
59
|
-
let
|
|
60
|
-
let n =
|
|
60
|
+
let z = F, { channel: B, isLoading: V, error: H, runHealthCheck: U, deleteConnection: W } = a(z), { t: G } = u(), K = (e, t) => {
|
|
61
|
+
let n = G(e);
|
|
61
62
|
return n === e ? t : n;
|
|
62
|
-
}, [
|
|
63
|
-
|
|
63
|
+
}, [q, J] = l(!1), [Y, X] = l(!1), [ie, Z] = l(!1), Q = B?.connection, ae = async () => {
|
|
64
|
+
X(!0);
|
|
64
65
|
try {
|
|
65
|
-
await
|
|
66
|
+
await U();
|
|
66
67
|
} finally {
|
|
67
|
-
|
|
68
|
+
X(!1);
|
|
68
69
|
}
|
|
69
|
-
},
|
|
70
|
-
if (
|
|
71
|
-
t("medium"),
|
|
70
|
+
}, oe = async () => {
|
|
71
|
+
if (j) {
|
|
72
|
+
t("medium"), J(!0);
|
|
72
73
|
try {
|
|
73
|
-
await
|
|
74
|
+
await W(j), n("success"), p(`/channels/${z}`);
|
|
74
75
|
} catch (e) {
|
|
75
76
|
n("error"), ee(e, {
|
|
76
77
|
module: "channel",
|
|
77
78
|
context: { action: "Failed to delete connection" }
|
|
78
79
|
}, "[channel] Failed to delete connection");
|
|
79
80
|
} finally {
|
|
80
|
-
|
|
81
|
+
J(!1);
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
};
|
|
84
|
-
if (
|
|
85
|
+
if (V || !F && !L) return /* @__PURE__ */ S("div", {
|
|
85
86
|
className: "flex items-center justify-center min-h-screen",
|
|
86
|
-
children: /* @__PURE__ */
|
|
87
|
+
children: /* @__PURE__ */ S(m, { className: "size-8 animate-spin text-text-secondary" })
|
|
87
88
|
});
|
|
88
|
-
if (
|
|
89
|
+
if (L || H || !B) return /* @__PURE__ */ C("div", {
|
|
89
90
|
className: "flex flex-col items-center justify-center min-h-screen gap-4",
|
|
90
91
|
children: [
|
|
91
|
-
/* @__PURE__ */
|
|
92
|
-
/* @__PURE__ */
|
|
92
|
+
/* @__PURE__ */ S(d, { className: "size-12 text-status-error-text" }),
|
|
93
|
+
/* @__PURE__ */ S("h1", {
|
|
93
94
|
className: "text-xl font-semibold",
|
|
94
|
-
children:
|
|
95
|
+
children: K("channel.channelNotFound", "Channel not found")
|
|
95
96
|
}),
|
|
96
|
-
/* @__PURE__ */
|
|
97
|
+
/* @__PURE__ */ S("button", {
|
|
97
98
|
type: "button",
|
|
98
99
|
onClick: () => p("../../list"),
|
|
99
100
|
className: "text-primary hover:underline",
|
|
100
|
-
children:
|
|
101
|
+
children: K("channel.backToChannels", "Back to channels")
|
|
101
102
|
})
|
|
102
103
|
]
|
|
103
104
|
});
|
|
104
|
-
if (!Q) return /* @__PURE__ */
|
|
105
|
+
if (!Q) return /* @__PURE__ */ C("div", {
|
|
105
106
|
className: "flex flex-col items-center justify-center min-h-screen gap-4",
|
|
106
107
|
children: [
|
|
107
|
-
/* @__PURE__ */
|
|
108
|
-
/* @__PURE__ */
|
|
108
|
+
/* @__PURE__ */ S(d, { className: "size-12 text-text-secondary" }),
|
|
109
|
+
/* @__PURE__ */ S("h1", {
|
|
109
110
|
className: "text-xl font-semibold",
|
|
110
|
-
children:
|
|
111
|
+
children: K("channel.noConnectionFound", "No connection found")
|
|
111
112
|
}),
|
|
112
|
-
/* @__PURE__ */
|
|
113
|
+
/* @__PURE__ */ S("p", {
|
|
113
114
|
className: "text-sm text-text-secondary",
|
|
114
|
-
children:
|
|
115
|
+
children: K("channel.noConnectionConfigured", "This channel does not have a connection configured.")
|
|
115
116
|
}),
|
|
116
|
-
/* @__PURE__ */
|
|
117
|
+
/* @__PURE__ */ S("button", {
|
|
117
118
|
type: "button",
|
|
118
|
-
onClick: () => p(`/channels/${
|
|
119
|
+
onClick: () => p(`/channels/${z}`),
|
|
119
120
|
className: "text-primary hover:underline",
|
|
120
|
-
children:
|
|
121
|
+
children: K("channel.backToChannel", "Back to channel")
|
|
121
122
|
})
|
|
122
123
|
]
|
|
123
124
|
});
|
|
124
|
-
let $ =
|
|
125
|
-
return /* @__PURE__ */
|
|
125
|
+
let $ = O[String(Q.isHealthy)] || O.false, se = $.icon;
|
|
126
|
+
return /* @__PURE__ */ S(o, {
|
|
126
127
|
permission: s.CHANNEL_CONNECTION_READ,
|
|
127
|
-
children: /* @__PURE__ */
|
|
128
|
+
children: /* @__PURE__ */ C("div", {
|
|
128
129
|
className: "min-h-screen bg-bg-surface",
|
|
129
|
-
children: [/* @__PURE__ */
|
|
130
|
+
children: [/* @__PURE__ */ S("div", {
|
|
130
131
|
className: "border-b bg-bg-surface",
|
|
131
|
-
children: /* @__PURE__ */
|
|
132
|
+
children: /* @__PURE__ */ S("div", {
|
|
132
133
|
className: "container mx-auto px-6 py-4",
|
|
133
|
-
children: /* @__PURE__ */
|
|
134
|
+
children: /* @__PURE__ */ C("div", {
|
|
134
135
|
className: "flex items-center justify-between",
|
|
135
|
-
children: [/* @__PURE__ */
|
|
136
|
+
children: [/* @__PURE__ */ C("div", {
|
|
136
137
|
className: "flex items-center gap-4",
|
|
137
|
-
children: [/* @__PURE__ */
|
|
138
|
+
children: [/* @__PURE__ */ S("button", {
|
|
138
139
|
type: "button",
|
|
139
|
-
onClick: () => p(`/channels/${
|
|
140
|
+
onClick: () => p(`/channels/${z}`),
|
|
140
141
|
className: "p-2 hover:bg-bg-sunken rounded-lg transition-colors",
|
|
141
|
-
children: /* @__PURE__ */
|
|
142
|
-
}), /* @__PURE__ */
|
|
142
|
+
children: /* @__PURE__ */ S(f, { className: "size-5 " })
|
|
143
|
+
}), /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("h1", {
|
|
143
144
|
className: "text-2xl font-bold",
|
|
144
|
-
children:
|
|
145
|
-
}), /* @__PURE__ */
|
|
145
|
+
children: K("channel.connectionDetails", "Connection Details")
|
|
146
|
+
}), /* @__PURE__ */ C("p", {
|
|
146
147
|
className: "text-sm text-text-secondary",
|
|
147
148
|
children: [
|
|
148
|
-
|
|
149
|
+
B.name,
|
|
149
150
|
" • ",
|
|
150
|
-
|
|
151
|
+
B.platform
|
|
151
152
|
]
|
|
152
153
|
})] })]
|
|
153
|
-
}), /* @__PURE__ */
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
154
|
+
}), /* @__PURE__ */ S(w, {
|
|
155
|
+
primary: k ? {
|
|
156
|
+
label: K("channel.editChannel", "Edit Channel"),
|
|
157
|
+
icon: /* @__PURE__ */ S(ne, {
|
|
158
|
+
className: "size-4",
|
|
159
|
+
"aria-hidden": "true"
|
|
160
|
+
}),
|
|
161
|
+
onSelect: () => p(`/channels/${z}/edit`)
|
|
162
|
+
} : void 0,
|
|
163
|
+
actions: re ? [{
|
|
164
|
+
label: K("channel.runHealthCheck", "Run Health Check"),
|
|
165
|
+
icon: Y ? /* @__PURE__ */ S(m, {
|
|
166
|
+
className: "size-4 animate-spin",
|
|
167
|
+
"aria-hidden": "true"
|
|
168
|
+
}) : /* @__PURE__ */ S(h, {
|
|
169
|
+
className: "size-4",
|
|
170
|
+
"aria-hidden": "true"
|
|
171
|
+
}),
|
|
172
|
+
disabled: Y,
|
|
173
|
+
onSelect: () => void ae()
|
|
174
|
+
}] : []
|
|
170
175
|
})]
|
|
171
176
|
})
|
|
172
177
|
})
|
|
173
|
-
}), /* @__PURE__ */
|
|
174
|
-
className: "container mx-auto px-6 py-8 max-w-
|
|
175
|
-
children: [
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
})] })]
|
|
192
|
-
})
|
|
178
|
+
}), /* @__PURE__ */ C("div", {
|
|
179
|
+
className: "container mx-auto px-6 py-8 max-w-5xl space-y-6",
|
|
180
|
+
children: [/* @__PURE__ */ S(T, {
|
|
181
|
+
className: "p-6",
|
|
182
|
+
children: /* @__PURE__ */ S("div", {
|
|
183
|
+
className: "flex items-center justify-between",
|
|
184
|
+
children: /* @__PURE__ */ C("div", {
|
|
185
|
+
className: "flex items-center gap-4",
|
|
186
|
+
children: [/* @__PURE__ */ S("div", {
|
|
187
|
+
className: $.color,
|
|
188
|
+
children: /* @__PURE__ */ S(se, { className: "size-10 " })
|
|
189
|
+
}), /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("h2", {
|
|
190
|
+
className: "text-xl font-semibold",
|
|
191
|
+
children: $.label
|
|
192
|
+
}), /* @__PURE__ */ S("p", {
|
|
193
|
+
className: "text-sm text-text-secondary",
|
|
194
|
+
children: Q.isHealthy ? K("channel.connectionWorking", "Connection is working properly") : K("channel.connectionNotWorking", "Connection is not working properly")
|
|
195
|
+
})] })]
|
|
193
196
|
})
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
|
|
197
|
+
})
|
|
198
|
+
}), /* @__PURE__ */ C("div", {
|
|
199
|
+
className: "grid gap-6 lg:grid-cols-3",
|
|
200
|
+
children: [/* @__PURE__ */ C(E, {
|
|
201
|
+
treatment: "plain",
|
|
202
|
+
className: "border-border-seam p-6 space-y-4 lg:col-span-2",
|
|
197
203
|
children: [
|
|
198
|
-
/* @__PURE__ */
|
|
204
|
+
/* @__PURE__ */ S("h3", {
|
|
199
205
|
className: "font-semibold",
|
|
200
|
-
children:
|
|
206
|
+
children: K("channel.connectionInformation", "Connection Information")
|
|
201
207
|
}),
|
|
202
|
-
/* @__PURE__ */
|
|
208
|
+
/* @__PURE__ */ C("div", {
|
|
203
209
|
className: "grid grid-cols-2 gap-4",
|
|
204
210
|
children: [
|
|
205
|
-
/* @__PURE__ */
|
|
211
|
+
/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
206
212
|
className: "text-sm text-text-secondary",
|
|
207
213
|
children: "Connection ID"
|
|
208
|
-
}), /* @__PURE__ */
|
|
214
|
+
}), /* @__PURE__ */ S("p", {
|
|
209
215
|
className: "font-mono text-sm",
|
|
210
216
|
children: Q.id
|
|
211
217
|
})] }),
|
|
212
|
-
/* @__PURE__ */
|
|
218
|
+
/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
213
219
|
className: "text-sm text-text-secondary",
|
|
214
220
|
children: "Auth Type"
|
|
215
|
-
}), /* @__PURE__ */
|
|
221
|
+
}), /* @__PURE__ */ C("p", {
|
|
216
222
|
className: "flex items-center gap-2",
|
|
217
|
-
children: [/* @__PURE__ */
|
|
223
|
+
children: [/* @__PURE__ */ S(g, { className: "size-4 text-text-secondary" }), Q.authType]
|
|
218
224
|
})] }),
|
|
219
|
-
/* @__PURE__ */
|
|
225
|
+
/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
220
226
|
className: "text-sm text-text-secondary",
|
|
221
227
|
children: "Status"
|
|
222
|
-
}), /* @__PURE__ */
|
|
228
|
+
}), /* @__PURE__ */ S("p", {
|
|
223
229
|
className: Q.isActive ? "text-status-success-text" : "text-text-secondary",
|
|
224
|
-
children: Q.isActive ?
|
|
230
|
+
children: Q.isActive ? K("channel.activeStatus", "Active") : K("channel.inactiveStatus", "Inactive")
|
|
225
231
|
})] }),
|
|
226
|
-
/* @__PURE__ */
|
|
232
|
+
/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
227
233
|
className: "text-sm text-text-secondary",
|
|
228
234
|
children: "Token Refresh"
|
|
229
|
-
}), /* @__PURE__ */
|
|
235
|
+
}), /* @__PURE__ */ S("p", {
|
|
230
236
|
className: Q.needsTokenRefresh ? "text-status-warning-text" : "text-text-secondary",
|
|
231
|
-
children: Q.needsTokenRefresh ?
|
|
237
|
+
children: Q.needsTokenRefresh ? K("channel.tokenRefreshRequired", "Required soon") : K("channel.tokenRefreshNotNeeded", "Not needed")
|
|
232
238
|
})] }),
|
|
233
|
-
Q.lastTestedAt && /* @__PURE__ */
|
|
239
|
+
Q.lastTestedAt && /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
234
240
|
className: "text-sm text-text-secondary",
|
|
235
241
|
children: "Last Tested"
|
|
236
|
-
}), /* @__PURE__ */
|
|
242
|
+
}), /* @__PURE__ */ C("p", {
|
|
237
243
|
className: "flex items-center gap-2",
|
|
238
|
-
children: [/* @__PURE__ */
|
|
244
|
+
children: [/* @__PURE__ */ S(te, { className: "size-4 text-text-secondary" }), new Date(Q.lastTestedAt).toLocaleString()]
|
|
239
245
|
})] }),
|
|
240
|
-
Q.daysUntilExpiry !== null && Q.daysUntilExpiry !== void 0 && /* @__PURE__ */
|
|
246
|
+
Q.daysUntilExpiry !== null && Q.daysUntilExpiry !== void 0 && /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
241
247
|
className: "text-sm text-text-secondary",
|
|
242
248
|
children: "Days Until Token Expiry"
|
|
243
|
-
}), /* @__PURE__ */
|
|
249
|
+
}), /* @__PURE__ */ C("p", {
|
|
244
250
|
className: Q.daysUntilExpiry < 30 ? "text-status-warning-text" : "text-text-secondary",
|
|
245
251
|
children: [Q.daysUntilExpiry, " days"]
|
|
246
252
|
})] })
|
|
247
253
|
]
|
|
248
254
|
}),
|
|
249
|
-
Q.testStatus && /* @__PURE__ */
|
|
255
|
+
Q.testStatus && /* @__PURE__ */ C("div", {
|
|
250
256
|
className: "pt-4 border-t",
|
|
251
|
-
children: [/* @__PURE__ */
|
|
257
|
+
children: [/* @__PURE__ */ S("p", {
|
|
252
258
|
className: "text-sm text-text-secondary mb-2",
|
|
253
259
|
children: "Last Test Status"
|
|
254
|
-
}), /* @__PURE__ */
|
|
260
|
+
}), /* @__PURE__ */ S("div", {
|
|
255
261
|
className: "p-3 rounded-lg bg-bg-sunken",
|
|
256
|
-
children: /* @__PURE__ */
|
|
262
|
+
children: /* @__PURE__ */ S("p", {
|
|
257
263
|
className: "font-mono text-sm",
|
|
258
264
|
children: Q.testStatus
|
|
259
265
|
})
|
|
260
266
|
})]
|
|
261
267
|
}),
|
|
262
|
-
Q.tagAssignments && Q.tagAssignments.length > 0 && /* @__PURE__ */
|
|
268
|
+
Q.tagAssignments && Q.tagAssignments.length > 0 && /* @__PURE__ */ C("div", {
|
|
263
269
|
className: "pt-4 border-t",
|
|
264
|
-
children: [/* @__PURE__ */
|
|
270
|
+
children: [/* @__PURE__ */ S("p", {
|
|
265
271
|
className: "text-sm text-text-secondary mb-2",
|
|
266
|
-
children:
|
|
267
|
-
}), /* @__PURE__ */
|
|
272
|
+
children: K("channel.tags", "Tags")
|
|
273
|
+
}), /* @__PURE__ */ S("div", {
|
|
268
274
|
className: "flex flex-wrap gap-1.5",
|
|
269
275
|
"aria-label": "Connection tags",
|
|
270
|
-
children: Q.tagAssignments.map((e) => /* @__PURE__ */
|
|
276
|
+
children: Q.tagAssignments.map((e) => /* @__PURE__ */ S(D, {
|
|
271
277
|
id: e.tagId,
|
|
272
278
|
label: e.tagId,
|
|
273
279
|
size: "md"
|
|
@@ -275,58 +281,58 @@ function O() {
|
|
|
275
281
|
})]
|
|
276
282
|
})
|
|
277
283
|
]
|
|
278
|
-
}),
|
|
279
|
-
|
|
280
|
-
className: "border
|
|
281
|
-
children: [/* @__PURE__ */
|
|
284
|
+
}), /* @__PURE__ */ C(E, {
|
|
285
|
+
treatment: "plain",
|
|
286
|
+
className: "border-border-seam p-6 space-y-4 lg:col-span-1",
|
|
287
|
+
children: [/* @__PURE__ */ S("h3", {
|
|
282
288
|
className: "font-semibold",
|
|
283
|
-
children:
|
|
284
|
-
}), /* @__PURE__ */
|
|
285
|
-
className: "flex
|
|
286
|
-
children: [/* @__PURE__ */
|
|
289
|
+
children: K("channel.actions", "Actions")
|
|
290
|
+
}), /* @__PURE__ */ C("div", {
|
|
291
|
+
className: "flex flex-col gap-3",
|
|
292
|
+
children: [/* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
|
|
287
293
|
className: "font-medium",
|
|
288
|
-
children:
|
|
289
|
-
}), /* @__PURE__ */
|
|
294
|
+
children: K("channel.deleteConnection", "Delete Connection")
|
|
295
|
+
}), /* @__PURE__ */ S("p", {
|
|
290
296
|
className: "text-sm text-text-secondary",
|
|
291
|
-
children:
|
|
292
|
-
})] }),
|
|
297
|
+
children: K("channel.deleteConnectionWarning", "Permanently remove this connection. The channel will become inactive.")
|
|
298
|
+
})] }), ie ? /* @__PURE__ */ C("div", {
|
|
293
299
|
className: "flex items-center gap-2",
|
|
294
300
|
children: [
|
|
295
|
-
/* @__PURE__ */
|
|
301
|
+
/* @__PURE__ */ S("span", {
|
|
296
302
|
className: "text-sm text-text-secondary",
|
|
297
|
-
children:
|
|
303
|
+
children: K("channel.confirmDelete", "Confirm delete?")
|
|
298
304
|
}),
|
|
299
|
-
/* @__PURE__ */
|
|
305
|
+
/* @__PURE__ */ C("button", {
|
|
300
306
|
type: "button",
|
|
301
|
-
onClick:
|
|
302
|
-
disabled:
|
|
307
|
+
onClick: oe,
|
|
308
|
+
disabled: q,
|
|
303
309
|
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
|
-
children: [
|
|
310
|
+
children: [q ? /* @__PURE__ */ S(m, { className: "size-4 animate-spin" }) : /* @__PURE__ */ S(_, { className: "size-4 " }), K("channel.delete", "Delete")]
|
|
305
311
|
}),
|
|
306
|
-
/* @__PURE__ */
|
|
312
|
+
/* @__PURE__ */ S("button", {
|
|
307
313
|
type: "button",
|
|
308
314
|
onClick: () => Z(!1),
|
|
309
315
|
className: "px-4 py-2 rounded-lg border hover:bg-bg-sunken transition-colors",
|
|
310
|
-
children:
|
|
316
|
+
children: K("channel.cancel", "Cancel")
|
|
311
317
|
})
|
|
312
318
|
]
|
|
313
|
-
}) : /* @__PURE__ */
|
|
319
|
+
}) : /* @__PURE__ */ S(o, {
|
|
314
320
|
permission: s.CHANNEL_CONNECTION_DELETE,
|
|
315
|
-
children: /* @__PURE__ */
|
|
321
|
+
children: /* @__PURE__ */ C("button", {
|
|
316
322
|
type: "button",
|
|
317
323
|
onClick: () => Z(!0),
|
|
318
324
|
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
|
-
children: [/* @__PURE__ */
|
|
325
|
+
children: [/* @__PURE__ */ S(_, { className: "size-4 " }), K("channel.delete", "Delete")]
|
|
320
326
|
})
|
|
321
327
|
})]
|
|
322
328
|
})]
|
|
323
|
-
})
|
|
324
|
-
]
|
|
329
|
+
})]
|
|
330
|
+
})]
|
|
325
331
|
})]
|
|
326
332
|
})
|
|
327
333
|
});
|
|
328
334
|
}
|
|
329
335
|
//#endregion
|
|
330
|
-
export {
|
|
336
|
+
export { k as ConnectionDetailsPage };
|
|
331
337
|
|
|
332
338
|
//# sourceMappingURL=ConnectionDetailsPage.js.map
|
|
@@ -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-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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"}
|
|
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 { CTAOverflowMenu, EmphasisPanel, GlassCard } from '@burdenoff/fe-libs/ui';\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 canExecute = hasPermission(CHANNEL_PERMISSIONS.CHANNEL_EXECUTE);\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 <CTAOverflowMenu\n primary={\n canUpdate\n ? {\n label: tr('channel.editChannel', 'Edit Channel'),\n icon: <Edit className=\"size-4\" aria-hidden=\"true\" />,\n onSelect: () => navigate(`/channels/${channelId}/edit`),\n }\n : undefined\n }\n actions={\n canExecute\n ? [\n {\n label: tr('channel.runHealthCheck', 'Run Health Check'),\n icon: isRunningHealth ? (\n <Loader2 className=\"size-4 animate-spin\" aria-hidden=\"true\" />\n ) : (\n <RefreshCw className=\"size-4\" aria-hidden=\"true\" />\n ),\n disabled: isRunningHealth,\n onSelect: () => void handleRunHealthCheck(),\n },\n ]\n : []\n }\n />\n </div>\n </div>\n </div>\n\n {/* Content */}\n <div className=\"container mx-auto px-6 py-8 max-w-5xl space-y-6\">\n {/* Health Status */}\n <EmphasisPanel className=\"p-6\">\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 </EmphasisPanel>\n\n <div className=\"grid gap-6 lg:grid-cols-3\">\n {/* Connection Info */}\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-6 space-y-4 lg:col-span-2\">\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 </GlassCard>\n\n {/* Actions */}\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-6 space-y-4 lg:col-span-1\">\n <h3 className=\"font-semibold\">{tr('channel.actions', 'Actions')}</h3>\n\n <div className=\"flex flex-col gap-3\">\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 </GlassCard>\n </div>\n </div>\n </div>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}
|