@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.
Files changed (29) hide show
  1. package/dist/channel/modules/channels/pages/ChannelDashboardPage.js +108 -98
  2. package/dist/channel/modules/channels/pages/ChannelDashboardPage.js.map +1 -1
  3. package/dist/channel/modules/channels/pages/ChannelDetailsPage.js +287 -277
  4. package/dist/channel/modules/channels/pages/ChannelDetailsPage.js.map +1 -1
  5. package/dist/channel/modules/channels/pages/ChannelSettingsPage.js +140 -131
  6. package/dist/channel/modules/channels/pages/ChannelSettingsPage.js.map +1 -1
  7. package/dist/channel/modules/channels/pages/ChannelUsersPage.js +170 -173
  8. package/dist/channel/modules/channels/pages/ChannelUsersPage.js.map +1 -1
  9. package/dist/channel/modules/channels/pages/ChannelsListPage.js +127 -120
  10. package/dist/channel/modules/channels/pages/ChannelsListPage.js.map +1 -1
  11. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js +161 -155
  12. package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js.map +1 -1
  13. package/dist/channel/modules/channels/pages/ConnectionsListPage.js +70 -68
  14. package/dist/channel/modules/channels/pages/ConnectionsListPage.js.map +1 -1
  15. package/dist/channel/modules/channels/pages/CreateChannelPage.js +27 -24
  16. package/dist/channel/modules/channels/pages/CreateChannelPage.js.map +1 -1
  17. package/dist/channel/modules/channels/pages/CreateConnectionPage.js +161 -156
  18. package/dist/channel/modules/channels/pages/CreateConnectionPage.js.map +1 -1
  19. package/dist/channel/modules/channels/pages/DeliveryHistoryPage.js +179 -182
  20. package/dist/channel/modules/channels/pages/DeliveryHistoryPage.js.map +1 -1
  21. package/dist/channel/modules/channels/pages/EditChannelPage.js +130 -122
  22. package/dist/channel/modules/channels/pages/EditChannelPage.js.map +1 -1
  23. package/dist/channel/modules/channels/pages/EditConnectionPage.js +137 -132
  24. package/dist/channel/modules/channels/pages/EditConnectionPage.js.map +1 -1
  25. package/dist/channel/modules/channels/pages/SendMessagePage.js +87 -84
  26. package/dist/channel/modules/channels/pages/SendMessagePage.js.map +1 -1
  27. package/dist/channel/modules/channels/pages/WebhookEventsPage.js +193 -194
  28. package/dist/channel/modules/channels/pages/WebhookEventsPage.js.map +1 -1
  29. 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 m, Edit as h, Loader2 as g, RefreshCw as _, Shield as v, Trash2 as y, XCircle as b } from "lucide-react";
12
- import { useNavigate as x, useParams as S } from "react-router-dom";
13
- import { usePermissions as C } from "@burdenoff/fe-libs/shared/providers/shell";
14
- import { jsx as w, jsxs as T } from "react/jsx-runtime";
15
- import { TagBadge as E } from "@burdenoff/fe-libs/tag";
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 D = {
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: b,
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 O() {
32
- let p = x(), { hasPermission: b } = C(), O = b(s.CHANNEL_UPDATE), k = S(), { connectionId: A } = k, { authToken: j, apiGatewayUrl: M, organizationId: N } = e(), [P, F] = l(k.channelId), [I, L] = l(null);
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 (P || !A) return;
35
+ if (F || !j) return;
35
36
  let e = !1;
36
37
  return (async () => {
37
38
  try {
38
- let t = await r(M, j, N).query({
39
+ let t = await r(N, M, P).query({
39
40
  query: i,
40
- variables: { id: A },
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 ? F(n.channelId) : L("Connection not found");
46
+ n?.channelId ? I(n.channelId) : R("Connection not found");
46
47
  } catch (t) {
47
- e || L(t instanceof Error ? t.message : "Failed to resolve connection");
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
- N
55
+ F,
56
+ N,
57
+ M,
58
+ P
58
59
  ]);
59
- let R = P, { channel: z, isLoading: B, error: V, runHealthCheck: H, deleteConnection: U } = a(R), { t: W } = u(), G = (e, t) => {
60
- let n = W(e);
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
- }, [K, q] = l(!1), [J, Y] = l(!1), [X, Z] = l(!1), Q = z?.connection, te = async () => {
63
- Y(!0);
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 H();
66
+ await U();
66
67
  } finally {
67
- Y(!1);
68
+ X(!1);
68
69
  }
69
- }, ne = async () => {
70
- if (A) {
71
- t("medium"), q(!0);
70
+ }, oe = async () => {
71
+ if (j) {
72
+ t("medium"), J(!0);
72
73
  try {
73
- await U(A), n("success"), p(`/channels/${R}`);
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
- q(!1);
81
+ J(!1);
81
82
  }
82
83
  }
83
84
  };
84
- if (B || !P && !I) return /* @__PURE__ */ w("div", {
85
+ if (V || !F && !L) return /* @__PURE__ */ S("div", {
85
86
  className: "flex items-center justify-center min-h-screen",
86
- children: /* @__PURE__ */ w(g, { className: "size-8 animate-spin text-text-secondary" })
87
+ children: /* @__PURE__ */ S(m, { className: "size-8 animate-spin text-text-secondary" })
87
88
  });
88
- if (I || V || !z) return /* @__PURE__ */ T("div", {
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__ */ w(d, { className: "size-12 text-status-error-text" }),
92
- /* @__PURE__ */ w("h1", {
92
+ /* @__PURE__ */ S(d, { className: "size-12 text-status-error-text" }),
93
+ /* @__PURE__ */ S("h1", {
93
94
  className: "text-xl font-semibold",
94
- children: G("channel.channelNotFound", "Channel not found")
95
+ children: K("channel.channelNotFound", "Channel not found")
95
96
  }),
96
- /* @__PURE__ */ w("button", {
97
+ /* @__PURE__ */ S("button", {
97
98
  type: "button",
98
99
  onClick: () => p("../../list"),
99
100
  className: "text-primary hover:underline",
100
- children: G("channel.backToChannels", "Back to channels")
101
+ children: K("channel.backToChannels", "Back to channels")
101
102
  })
102
103
  ]
103
104
  });
104
- if (!Q) return /* @__PURE__ */ T("div", {
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__ */ w(d, { className: "size-12 text-text-secondary" }),
108
- /* @__PURE__ */ w("h1", {
108
+ /* @__PURE__ */ S(d, { className: "size-12 text-text-secondary" }),
109
+ /* @__PURE__ */ S("h1", {
109
110
  className: "text-xl font-semibold",
110
- children: G("channel.noConnectionFound", "No connection found")
111
+ children: K("channel.noConnectionFound", "No connection found")
111
112
  }),
112
- /* @__PURE__ */ w("p", {
113
+ /* @__PURE__ */ S("p", {
113
114
  className: "text-sm text-text-secondary",
114
- children: G("channel.noConnectionConfigured", "This channel does not have a connection configured.")
115
+ children: K("channel.noConnectionConfigured", "This channel does not have a connection configured.")
115
116
  }),
116
- /* @__PURE__ */ w("button", {
117
+ /* @__PURE__ */ S("button", {
117
118
  type: "button",
118
- onClick: () => p(`/channels/${R}`),
119
+ onClick: () => p(`/channels/${z}`),
119
120
  className: "text-primary hover:underline",
120
- children: G("channel.backToChannel", "Back to channel")
121
+ children: K("channel.backToChannel", "Back to channel")
121
122
  })
122
123
  ]
123
124
  });
124
- let $ = D[String(Q.isHealthy)] || D.false, re = $.icon;
125
- return /* @__PURE__ */ w(o, {
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__ */ T("div", {
128
+ children: /* @__PURE__ */ C("div", {
128
129
  className: "min-h-screen bg-bg-surface",
129
- children: [/* @__PURE__ */ w("div", {
130
+ children: [/* @__PURE__ */ S("div", {
130
131
  className: "border-b bg-bg-surface",
131
- children: /* @__PURE__ */ w("div", {
132
+ children: /* @__PURE__ */ S("div", {
132
133
  className: "container mx-auto px-6 py-4",
133
- children: /* @__PURE__ */ T("div", {
134
+ children: /* @__PURE__ */ C("div", {
134
135
  className: "flex items-center justify-between",
135
- children: [/* @__PURE__ */ T("div", {
136
+ children: [/* @__PURE__ */ C("div", {
136
137
  className: "flex items-center gap-4",
137
- children: [/* @__PURE__ */ w("button", {
138
+ children: [/* @__PURE__ */ S("button", {
138
139
  type: "button",
139
- onClick: () => p(`/channels/${R}`),
140
+ onClick: () => p(`/channels/${z}`),
140
141
  className: "p-2 hover:bg-bg-sunken rounded-lg transition-colors",
141
- children: /* @__PURE__ */ w(f, { className: "size-5 " })
142
- }), /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("h1", {
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: G("channel.connectionDetails", "Connection Details")
145
- }), /* @__PURE__ */ T("p", {
145
+ children: K("channel.connectionDetails", "Connection Details")
146
+ }), /* @__PURE__ */ C("p", {
146
147
  className: "text-sm text-text-secondary",
147
148
  children: [
148
- z.name,
149
+ B.name,
149
150
  " • ",
150
- z.platform
151
+ B.platform
151
152
  ]
152
153
  })] })]
153
- }), /* @__PURE__ */ T("div", {
154
- className: "flex items-center gap-2",
155
- children: [/* @__PURE__ */ w(o, {
156
- permission: s.CHANNEL_EXECUTE,
157
- children: /* @__PURE__ */ T("button", {
158
- type: "button",
159
- onClick: te,
160
- disabled: J,
161
- className: "px-4 py-2 rounded-lg border hover:bg-bg-sunken transition-colors flex items-center gap-2",
162
- children: [J ? /* @__PURE__ */ w(g, { className: "size-4 animate-spin" }) : /* @__PURE__ */ w(_, { className: "size-4 " }), G("channel.runHealthCheck", "Run Health Check")]
163
- })
164
- }), O && /* @__PURE__ */ T("button", {
165
- type: "button",
166
- onClick: () => p(`/channels/${R}/edit`),
167
- className: "px-4 py-2 rounded-lg border hover:bg-bg-sunken transition-colors flex items-center gap-2",
168
- children: [/* @__PURE__ */ w(h, { className: "size-4 " }), G("channel.editChannel", "Edit Channel")]
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__ */ T("div", {
174
- className: "container mx-auto px-6 py-8 max-w-3xl space-y-6",
175
- children: [
176
- /* @__PURE__ */ w("div", {
177
- className: `p-6 rounded-lg border ${$.bgColor}`,
178
- children: /* @__PURE__ */ w("div", {
179
- className: "flex items-center justify-between",
180
- children: /* @__PURE__ */ T("div", {
181
- className: "flex items-center gap-4",
182
- children: [/* @__PURE__ */ w("div", {
183
- className: $.color,
184
- children: /* @__PURE__ */ w(re, { className: "size-10 " })
185
- }), /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("h2", {
186
- className: "text-xl font-semibold",
187
- children: $.label
188
- }), /* @__PURE__ */ w("p", {
189
- className: "text-sm text-text-secondary",
190
- children: Q.isHealthy ? G("channel.connectionWorking", "Connection is working properly") : G("channel.connectionNotWorking", "Connection is not working properly")
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
- /* @__PURE__ */ T("div", {
196
- className: "border rounded-lg p-6 space-y-4",
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__ */ w("h3", {
204
+ /* @__PURE__ */ S("h3", {
199
205
  className: "font-semibold",
200
- children: G("channel.connectionInformation", "Connection Information")
206
+ children: K("channel.connectionInformation", "Connection Information")
201
207
  }),
202
- /* @__PURE__ */ T("div", {
208
+ /* @__PURE__ */ C("div", {
203
209
  className: "grid grid-cols-2 gap-4",
204
210
  children: [
205
- /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
211
+ /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
206
212
  className: "text-sm text-text-secondary",
207
213
  children: "Connection ID"
208
- }), /* @__PURE__ */ w("p", {
214
+ }), /* @__PURE__ */ S("p", {
209
215
  className: "font-mono text-sm",
210
216
  children: Q.id
211
217
  })] }),
212
- /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
218
+ /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
213
219
  className: "text-sm text-text-secondary",
214
220
  children: "Auth Type"
215
- }), /* @__PURE__ */ T("p", {
221
+ }), /* @__PURE__ */ C("p", {
216
222
  className: "flex items-center gap-2",
217
- children: [/* @__PURE__ */ w(v, { className: "size-4 text-text-secondary" }), Q.authType]
223
+ children: [/* @__PURE__ */ S(g, { className: "size-4 text-text-secondary" }), Q.authType]
218
224
  })] }),
219
- /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
225
+ /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
220
226
  className: "text-sm text-text-secondary",
221
227
  children: "Status"
222
- }), /* @__PURE__ */ w("p", {
228
+ }), /* @__PURE__ */ S("p", {
223
229
  className: Q.isActive ? "text-status-success-text" : "text-text-secondary",
224
- children: Q.isActive ? G("channel.activeStatus", "Active") : G("channel.inactiveStatus", "Inactive")
230
+ children: Q.isActive ? K("channel.activeStatus", "Active") : K("channel.inactiveStatus", "Inactive")
225
231
  })] }),
226
- /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
232
+ /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
227
233
  className: "text-sm text-text-secondary",
228
234
  children: "Token Refresh"
229
- }), /* @__PURE__ */ w("p", {
235
+ }), /* @__PURE__ */ S("p", {
230
236
  className: Q.needsTokenRefresh ? "text-status-warning-text" : "text-text-secondary",
231
- children: Q.needsTokenRefresh ? G("channel.tokenRefreshRequired", "Required soon") : G("channel.tokenRefreshNotNeeded", "Not needed")
237
+ children: Q.needsTokenRefresh ? K("channel.tokenRefreshRequired", "Required soon") : K("channel.tokenRefreshNotNeeded", "Not needed")
232
238
  })] }),
233
- Q.lastTestedAt && /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
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__ */ T("p", {
242
+ }), /* @__PURE__ */ C("p", {
237
243
  className: "flex items-center gap-2",
238
- children: [/* @__PURE__ */ w(m, { className: "size-4 text-text-secondary" }), new Date(Q.lastTestedAt).toLocaleString()]
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__ */ T("div", { children: [/* @__PURE__ */ w("p", {
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__ */ T("p", {
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__ */ T("div", {
255
+ Q.testStatus && /* @__PURE__ */ C("div", {
250
256
  className: "pt-4 border-t",
251
- children: [/* @__PURE__ */ w("p", {
257
+ children: [/* @__PURE__ */ S("p", {
252
258
  className: "text-sm text-text-secondary mb-2",
253
259
  children: "Last Test Status"
254
- }), /* @__PURE__ */ w("div", {
260
+ }), /* @__PURE__ */ S("div", {
255
261
  className: "p-3 rounded-lg bg-bg-sunken",
256
- children: /* @__PURE__ */ w("p", {
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__ */ T("div", {
268
+ Q.tagAssignments && Q.tagAssignments.length > 0 && /* @__PURE__ */ C("div", {
263
269
  className: "pt-4 border-t",
264
- children: [/* @__PURE__ */ w("p", {
270
+ children: [/* @__PURE__ */ S("p", {
265
271
  className: "text-sm text-text-secondary mb-2",
266
- children: G("channel.tags", "Tags")
267
- }), /* @__PURE__ */ w("div", {
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__ */ w(E, {
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
- /* @__PURE__ */ T("div", {
280
- className: "border rounded-lg p-6 space-y-4",
281
- children: [/* @__PURE__ */ w("h3", {
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: G("channel.actions", "Actions")
284
- }), /* @__PURE__ */ T("div", {
285
- className: "flex items-center justify-between",
286
- children: [/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
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: G("channel.deleteConnection", "Delete Connection")
289
- }), /* @__PURE__ */ w("p", {
294
+ children: K("channel.deleteConnection", "Delete Connection")
295
+ }), /* @__PURE__ */ S("p", {
290
296
  className: "text-sm text-text-secondary",
291
- children: G("channel.deleteConnectionWarning", "Permanently remove this connection. The channel will become inactive.")
292
- })] }), X ? /* @__PURE__ */ T("div", {
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__ */ w("span", {
301
+ /* @__PURE__ */ S("span", {
296
302
  className: "text-sm text-text-secondary",
297
- children: G("channel.confirmDelete", "Confirm delete?")
303
+ children: K("channel.confirmDelete", "Confirm delete?")
298
304
  }),
299
- /* @__PURE__ */ T("button", {
305
+ /* @__PURE__ */ C("button", {
300
306
  type: "button",
301
- onClick: ne,
302
- disabled: K,
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: [K ? /* @__PURE__ */ w(g, { className: "size-4 animate-spin" }) : /* @__PURE__ */ w(y, { className: "size-4 " }), G("channel.delete", "Delete")]
310
+ children: [q ? /* @__PURE__ */ S(m, { className: "size-4 animate-spin" }) : /* @__PURE__ */ S(_, { className: "size-4 " }), K("channel.delete", "Delete")]
305
311
  }),
306
- /* @__PURE__ */ w("button", {
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: G("channel.cancel", "Cancel")
316
+ children: K("channel.cancel", "Cancel")
311
317
  })
312
318
  ]
313
- }) : /* @__PURE__ */ w(o, {
319
+ }) : /* @__PURE__ */ S(o, {
314
320
  permission: s.CHANNEL_CONNECTION_DELETE,
315
- children: /* @__PURE__ */ T("button", {
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__ */ w(y, { className: "size-4 " }), G("channel.delete", "Delete")]
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 { O as ConnectionDetailsPage };
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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"}