@burdenoff/microfe-channel 2026.526.1 → 2026.530.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/ChannelRoutes.js +5 -6
- package/dist/channel/ChannelRoutes.js.map +1 -1
- package/dist/channel/components/AdapterCredentialsForm.js +14 -2
- package/dist/channel/components/AdapterCredentialsForm.js.map +1 -1
- package/dist/channel/components/FeatureNotEnabled.js +1 -1
- package/dist/channel/components/FeatureNotEnabled.js.map +1 -1
- package/dist/channel/components/PermissionGuard.js +1 -1
- package/dist/channel/components/PermissionGuard.js.map +1 -1
- package/dist/channel/config/adapterCredentials.js +19 -11
- package/dist/channel/config/adapterCredentials.js.map +1 -1
- package/dist/channel/constants/permissions.js +3 -0
- package/dist/channel/constants/permissions.js.map +1 -1
- package/dist/channel/hooks/useChannelSubscription.js.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelDashboardPage.js +244 -220
- package/dist/channel/modules/channels/pages/ChannelDashboardPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelDetailsPage.js +416 -390
- package/dist/channel/modules/channels/pages/ChannelDetailsPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelSettingsPage.js +30 -15
- package/dist/channel/modules/channels/pages/ChannelSettingsPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelUsersPage.js +8 -2
- package/dist/channel/modules/channels/pages/ChannelUsersPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ChannelsListPage.js +241 -213
- package/dist/channel/modules/channels/pages/ChannelsListPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js +107 -98
- package/dist/channel/modules/channels/pages/ConnectionDetailsPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/ConnectionsListPage.js +160 -140
- package/dist/channel/modules/channels/pages/ConnectionsListPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/CreateChannelPage.js +47 -50
- package/dist/channel/modules/channels/pages/CreateChannelPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/CreateConnectionPage.js +16 -5
- package/dist/channel/modules/channels/pages/CreateConnectionPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/DeliveryHistoryPage.js +11 -4
- package/dist/channel/modules/channels/pages/DeliveryHistoryPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/EditChannelPage.js +17 -8
- package/dist/channel/modules/channels/pages/EditChannelPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/EditConnectionPage.js +11 -6
- package/dist/channel/modules/channels/pages/EditConnectionPage.js.map +1 -1
- package/dist/channel/modules/channels/pages/SendMessagePage.js +21 -9
- package/dist/channel/modules/channels/pages/SendMessagePage.js.map +1 -1
- package/dist/channel/modules/channels/pages/WebhookEventsPage.js +8 -1
- package/dist/channel/modules/channels/pages/WebhookEventsPage.js.map +1 -1
- package/dist/channel/pages/ChannelLandingPage.js +50 -35
- package/dist/channel/pages/ChannelLandingPage.js.map +1 -1
- package/dist/channel/providers/ChannelProvider.js +1 -1
- package/dist/channel/providers/ChannelProvider.js.map +1 -1
- package/package.json +2 -2
- package/dist/channel/modules/channels/pages/index.js +0 -14
|
@@ -5,10 +5,11 @@ import { useEffect as r, useState as i } from "react";
|
|
|
5
5
|
import { useI18n as a } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
6
6
|
import { AlertCircle as o, ArrowLeft as s, CheckCircle2 as c, Link as l, Loader2 as u, Plus as d, RefreshCw as f, Settings as p, XCircle as m } from "lucide-react";
|
|
7
7
|
import { useNavigate as h } from "react-router-dom";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { usePermissions as g } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
9
|
+
import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
|
|
10
|
+
import { TagBadge as b } from "@burdenoff/fe-libs/tag";
|
|
10
11
|
//#region src/channel/modules/channels/pages/ConnectionsListPage.tsx
|
|
11
|
-
var
|
|
12
|
+
var x = {
|
|
12
13
|
true: {
|
|
13
14
|
icon: c,
|
|
14
15
|
color: "text-status-success-text",
|
|
@@ -20,185 +21,201 @@ var b = {
|
|
|
20
21
|
label: "Unhealthy"
|
|
21
22
|
}
|
|
22
23
|
};
|
|
23
|
-
function
|
|
24
|
-
let c = h(), {
|
|
24
|
+
function S() {
|
|
25
|
+
let c = h(), { hasPermission: m } = g(), S = m(n.CHANNEL_CONNECTION_CREATE), { channels: C, isLoading: w, error: T, refetch: E } = e();
|
|
25
26
|
r(() => {
|
|
26
27
|
let e = setInterval(() => {
|
|
27
|
-
|
|
28
|
+
E();
|
|
28
29
|
}, 6e4);
|
|
29
30
|
return () => clearInterval(e);
|
|
30
|
-
}, [
|
|
31
|
-
let { t:
|
|
32
|
-
let n =
|
|
31
|
+
}, [E]);
|
|
32
|
+
let { t: D } = a(), O = (e, t) => {
|
|
33
|
+
let n = D(e);
|
|
33
34
|
return n === e ? t : n;
|
|
34
|
-
}, [
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
35
|
+
}, [k, A] = i("all"), [j, M] = i("all"), [N, P] = i(0), F = C.reduce((e, t) => {
|
|
36
|
+
let n = t.connection;
|
|
37
|
+
return n && e.push({
|
|
38
|
+
channelId: t.id,
|
|
39
|
+
channelName: t.name,
|
|
40
|
+
platform: t.platform,
|
|
41
|
+
adapterType: t.adapterType,
|
|
42
|
+
channelStatus: t.status,
|
|
43
|
+
connectionId: n.id,
|
|
44
|
+
isActive: n.isActive,
|
|
45
|
+
isHealthy: n.isHealthy,
|
|
46
|
+
needsTokenRefresh: n.needsTokenRefresh,
|
|
47
|
+
lastTestedAt: n.lastTestedAt,
|
|
48
|
+
authType: n.authType,
|
|
49
|
+
tagAssignments: n.tagAssignments ?? []
|
|
50
|
+
}), e;
|
|
51
|
+
}, []), I = [...new Set(F.map((e) => e.platform))], L = F.filter((e) => !(k === "healthy" && !e.isHealthy || k === "unhealthy" && e.isHealthy || j !== "all" && e.platform !== j)), R = Math.max(1, Math.ceil(L.length / 10)), z = L.slice(N * 10, (N + 1) * 10);
|
|
52
|
+
return w ? /* @__PURE__ */ v("div", {
|
|
49
53
|
className: "flex items-center justify-center min-h-screen",
|
|
50
|
-
children: /* @__PURE__ */
|
|
51
|
-
}) :
|
|
54
|
+
children: /* @__PURE__ */ v(u, { className: "size-8 animate-spin text-muted-foreground" })
|
|
55
|
+
}) : T ? /* @__PURE__ */ y("div", {
|
|
52
56
|
className: "flex flex-col items-center justify-center min-h-screen gap-4",
|
|
53
57
|
children: [
|
|
54
|
-
/* @__PURE__ */
|
|
55
|
-
/* @__PURE__ */
|
|
58
|
+
/* @__PURE__ */ v(o, { className: "size-12 text-destructive" }),
|
|
59
|
+
/* @__PURE__ */ v("h1", {
|
|
56
60
|
className: "text-xl font-semibold",
|
|
57
|
-
children:
|
|
61
|
+
children: O("channel.loadConnectionsFailed", "Failed to load connections")
|
|
58
62
|
}),
|
|
59
|
-
/* @__PURE__ */
|
|
63
|
+
/* @__PURE__ */ v("p", {
|
|
60
64
|
className: "text-sm text-muted-foreground",
|
|
61
|
-
children:
|
|
65
|
+
children: T
|
|
62
66
|
}),
|
|
63
|
-
/* @__PURE__ */
|
|
64
|
-
|
|
67
|
+
/* @__PURE__ */ v("button", {
|
|
68
|
+
type: "button",
|
|
69
|
+
onClick: () => E(),
|
|
65
70
|
className: "px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90",
|
|
66
|
-
children:
|
|
71
|
+
children: O("channel.retry", "Retry")
|
|
67
72
|
})
|
|
68
73
|
]
|
|
69
|
-
}) : /* @__PURE__ */
|
|
74
|
+
}) : /* @__PURE__ */ v(t, {
|
|
70
75
|
permission: n.CHANNEL_CONNECTION_READ,
|
|
71
|
-
children: /* @__PURE__ */
|
|
76
|
+
children: /* @__PURE__ */ y("div", {
|
|
72
77
|
className: "min-h-screen bg-background",
|
|
73
78
|
children: [
|
|
74
|
-
/* @__PURE__ */
|
|
79
|
+
/* @__PURE__ */ v("div", {
|
|
75
80
|
className: "border-b bg-card",
|
|
76
|
-
|
|
81
|
+
"data-tour": "channels-connections-header",
|
|
82
|
+
children: /* @__PURE__ */ v("div", {
|
|
77
83
|
className: "container mx-auto px-6 py-4",
|
|
78
|
-
children: /* @__PURE__ */
|
|
84
|
+
children: /* @__PURE__ */ y("div", {
|
|
79
85
|
className: "flex items-center justify-between",
|
|
80
|
-
children: [/* @__PURE__ */
|
|
86
|
+
children: [/* @__PURE__ */ y("div", {
|
|
81
87
|
className: "flex items-center gap-4",
|
|
82
|
-
children: [/* @__PURE__ */
|
|
88
|
+
children: [/* @__PURE__ */ v("button", {
|
|
89
|
+
type: "button",
|
|
83
90
|
onClick: () => c("./list"),
|
|
84
|
-
"aria-label":
|
|
91
|
+
"aria-label": O("channel.backToChannels", "Back to channels"),
|
|
85
92
|
className: "p-2 hover:bg-muted rounded-lg transition-colors",
|
|
86
|
-
children: /* @__PURE__ */
|
|
87
|
-
}), /* @__PURE__ */
|
|
93
|
+
children: /* @__PURE__ */ v(s, { className: "size-5 " })
|
|
94
|
+
}), /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("h1", {
|
|
88
95
|
className: "text-2xl font-bold",
|
|
89
|
-
children:
|
|
90
|
-
}), /* @__PURE__ */
|
|
96
|
+
children: O("channel.connections", "Connections")
|
|
97
|
+
}), /* @__PURE__ */ y("p", {
|
|
91
98
|
className: "text-sm text-muted-foreground",
|
|
92
99
|
children: [
|
|
93
|
-
|
|
100
|
+
L.length,
|
|
94
101
|
" connection",
|
|
95
|
-
|
|
102
|
+
L.length === 1 ? "" : "s"
|
|
96
103
|
]
|
|
97
104
|
})] })]
|
|
98
|
-
}), /* @__PURE__ */
|
|
105
|
+
}), S && /* @__PURE__ */ y("button", {
|
|
106
|
+
type: "button",
|
|
99
107
|
onClick: () => c("./create"),
|
|
100
108
|
className: "px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 transition-colors flex items-center gap-2",
|
|
101
|
-
children: [/* @__PURE__ */
|
|
109
|
+
children: [/* @__PURE__ */ v(d, { className: "size-4 " }), O("channel.newConnection", "New Connection")]
|
|
102
110
|
})]
|
|
103
111
|
})
|
|
104
112
|
})
|
|
105
113
|
}),
|
|
106
|
-
/* @__PURE__ */
|
|
114
|
+
/* @__PURE__ */ v("div", {
|
|
107
115
|
className: "container mx-auto px-6 py-4",
|
|
108
|
-
|
|
116
|
+
"data-tour": "channels-connections-filters",
|
|
117
|
+
children: /* @__PURE__ */ y("div", {
|
|
109
118
|
className: "flex items-center gap-4",
|
|
110
119
|
children: [
|
|
111
|
-
/* @__PURE__ */
|
|
112
|
-
value:
|
|
113
|
-
onChange: (e) =>
|
|
120
|
+
/* @__PURE__ */ y("select", {
|
|
121
|
+
value: j,
|
|
122
|
+
onChange: (e) => M(e.target.value),
|
|
114
123
|
className: "px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary",
|
|
115
|
-
children: [/* @__PURE__ */
|
|
124
|
+
children: [/* @__PURE__ */ v("option", {
|
|
116
125
|
value: "all",
|
|
117
|
-
children:
|
|
118
|
-
}),
|
|
126
|
+
children: O("channel.allPlatforms", "All Platforms")
|
|
127
|
+
}), I.map((e) => /* @__PURE__ */ v("option", {
|
|
119
128
|
value: e,
|
|
120
129
|
children: e
|
|
121
130
|
}, e))]
|
|
122
131
|
}),
|
|
123
|
-
/* @__PURE__ */
|
|
124
|
-
value:
|
|
125
|
-
onChange: (e) =>
|
|
132
|
+
/* @__PURE__ */ y("select", {
|
|
133
|
+
value: k,
|
|
134
|
+
onChange: (e) => A(e.target.value),
|
|
126
135
|
className: "px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary",
|
|
127
136
|
children: [
|
|
128
|
-
/* @__PURE__ */
|
|
137
|
+
/* @__PURE__ */ v("option", {
|
|
129
138
|
value: "all",
|
|
130
|
-
children:
|
|
139
|
+
children: O("channel.allStatus", "All Status")
|
|
131
140
|
}),
|
|
132
|
-
/* @__PURE__ */
|
|
141
|
+
/* @__PURE__ */ v("option", {
|
|
133
142
|
value: "healthy",
|
|
134
|
-
children:
|
|
143
|
+
children: O("channel.healthy", "Healthy")
|
|
135
144
|
}),
|
|
136
|
-
/* @__PURE__ */
|
|
145
|
+
/* @__PURE__ */ v("option", {
|
|
137
146
|
value: "unhealthy",
|
|
138
|
-
children:
|
|
147
|
+
children: O("channel.unhealthy", "Unhealthy")
|
|
139
148
|
})
|
|
140
149
|
]
|
|
141
150
|
}),
|
|
142
|
-
/* @__PURE__ */
|
|
143
|
-
|
|
144
|
-
|
|
151
|
+
/* @__PURE__ */ v("button", {
|
|
152
|
+
type: "button",
|
|
153
|
+
onClick: () => E(),
|
|
154
|
+
"aria-label": O("channel.refresh", "Refresh"),
|
|
145
155
|
className: "p-2 hover:bg-muted rounded-lg transition-colors",
|
|
146
|
-
children: /* @__PURE__ */
|
|
147
|
-
className: "
|
|
156
|
+
children: /* @__PURE__ */ v(f, {
|
|
157
|
+
className: "size-5 ",
|
|
148
158
|
"aria-hidden": "true"
|
|
149
159
|
})
|
|
150
160
|
})
|
|
151
161
|
]
|
|
152
162
|
})
|
|
153
163
|
}),
|
|
154
|
-
/* @__PURE__ */
|
|
164
|
+
/* @__PURE__ */ v("div", {
|
|
155
165
|
className: "container mx-auto px-6 pb-8",
|
|
156
|
-
children:
|
|
166
|
+
children: L.length === 0 ? /* @__PURE__ */ y("div", {
|
|
157
167
|
className: "text-center py-12",
|
|
158
168
|
children: [
|
|
159
|
-
/* @__PURE__ */
|
|
160
|
-
/* @__PURE__ */
|
|
169
|
+
/* @__PURE__ */ v(l, { className: "size-12 mx-auto text-muted-foreground mb-4" }),
|
|
170
|
+
/* @__PURE__ */ v("h2", {
|
|
161
171
|
className: "text-lg font-semibold mb-2",
|
|
162
|
-
children:
|
|
172
|
+
children: O("channel.noConnectionsFound", "No connections found")
|
|
163
173
|
}),
|
|
164
|
-
/* @__PURE__ */
|
|
174
|
+
/* @__PURE__ */ v("p", {
|
|
165
175
|
className: "text-sm text-muted-foreground mb-4",
|
|
166
|
-
children:
|
|
176
|
+
children: C.length === 0 ? O("channel.createChannelFirst", "Create a channel first to add connections") : O("channel.noConnectionsMatchFilter", "No connections match your filters")
|
|
167
177
|
}),
|
|
168
|
-
|
|
178
|
+
C.length === 0 ? S ? /* @__PURE__ */ v("button", {
|
|
179
|
+
type: "button",
|
|
169
180
|
onClick: () => c("./create"),
|
|
170
181
|
className: "px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90",
|
|
171
|
-
children:
|
|
172
|
-
}) : /* @__PURE__ */
|
|
182
|
+
children: O("channel.createConnection", "Create Connection")
|
|
183
|
+
}) : null : /* @__PURE__ */ v("button", {
|
|
184
|
+
type: "button",
|
|
173
185
|
onClick: () => {
|
|
174
|
-
|
|
186
|
+
A("all"), M("all");
|
|
175
187
|
},
|
|
176
188
|
className: "px-4 py-2 rounded-lg border hover:bg-muted",
|
|
177
|
-
children:
|
|
189
|
+
children: O("channel.clearFilters", "Clear Filters")
|
|
178
190
|
})
|
|
179
191
|
]
|
|
180
|
-
}) : /* @__PURE__ */
|
|
192
|
+
}) : /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v("div", {
|
|
181
193
|
className: "border rounded-lg divide-y",
|
|
182
|
-
children:
|
|
183
|
-
let t =
|
|
184
|
-
return /* @__PURE__ */
|
|
194
|
+
children: z.map((e) => {
|
|
195
|
+
let t = x[String(e.isHealthy)] || x.false, n = t.icon;
|
|
196
|
+
return /* @__PURE__ */ v("div", {
|
|
197
|
+
role: "button",
|
|
198
|
+
tabIndex: 0,
|
|
185
199
|
className: "p-4 hover:bg-muted/50 transition-colors cursor-pointer",
|
|
186
200
|
onClick: () => c(`./${e.channelId}`),
|
|
187
|
-
|
|
201
|
+
onKeyDown: (t) => {
|
|
202
|
+
(t.key === "Enter" || t.key === " ") && (t.preventDefault(), c(`./${e.channelId}`));
|
|
203
|
+
},
|
|
204
|
+
children: /* @__PURE__ */ y("div", {
|
|
188
205
|
className: "flex items-center justify-between",
|
|
189
|
-
children: [/* @__PURE__ */
|
|
206
|
+
children: [/* @__PURE__ */ y("div", {
|
|
190
207
|
className: "flex items-center gap-4",
|
|
191
|
-
children: [/* @__PURE__ */
|
|
208
|
+
children: [/* @__PURE__ */ v("div", {
|
|
192
209
|
className: t.color,
|
|
193
210
|
"aria-label": t.label,
|
|
194
|
-
children: /* @__PURE__ */
|
|
195
|
-
className: "
|
|
211
|
+
children: /* @__PURE__ */ v(n, {
|
|
212
|
+
className: "size-5 ",
|
|
196
213
|
"aria-hidden": "true"
|
|
197
214
|
})
|
|
198
|
-
}), /* @__PURE__ */
|
|
215
|
+
}), /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("p", {
|
|
199
216
|
className: "font-medium",
|
|
200
217
|
children: e.channelName
|
|
201
|
-
}), /* @__PURE__ */
|
|
218
|
+
}), /* @__PURE__ */ y("p", {
|
|
202
219
|
className: "text-sm text-muted-foreground",
|
|
203
220
|
children: [
|
|
204
221
|
e.platform,
|
|
@@ -208,111 +225,114 @@ function x() {
|
|
|
208
225
|
e.authType
|
|
209
226
|
]
|
|
210
227
|
})] })]
|
|
211
|
-
}), /* @__PURE__ */
|
|
228
|
+
}), /* @__PURE__ */ y("div", {
|
|
212
229
|
className: "flex items-center gap-4",
|
|
213
230
|
children: [
|
|
214
|
-
/* @__PURE__ */
|
|
231
|
+
/* @__PURE__ */ y("div", {
|
|
215
232
|
className: "text-right",
|
|
216
|
-
children: [/* @__PURE__ */
|
|
233
|
+
children: [/* @__PURE__ */ v("p", {
|
|
217
234
|
className: "text-sm",
|
|
218
|
-
children: e.channelStatus === "ACTIVE" ? /* @__PURE__ */
|
|
235
|
+
children: e.channelStatus === "ACTIVE" ? /* @__PURE__ */ v("span", {
|
|
219
236
|
className: "text-status-success-text",
|
|
220
|
-
children:
|
|
221
|
-
}) : e.channelStatus === "INACTIVE" ? /* @__PURE__ */
|
|
237
|
+
children: O("channel.activeStatus", "Active")
|
|
238
|
+
}) : e.channelStatus === "INACTIVE" ? /* @__PURE__ */ v("span", {
|
|
222
239
|
className: "text-muted-foreground",
|
|
223
|
-
children:
|
|
224
|
-
}) : e.channelStatus === "ERROR" ? /* @__PURE__ */
|
|
240
|
+
children: O("channel.inactiveStatus", "Inactive")
|
|
241
|
+
}) : e.channelStatus === "ERROR" ? /* @__PURE__ */ v("span", {
|
|
225
242
|
className: "text-status-error-text",
|
|
226
|
-
children:
|
|
227
|
-
}) : e.channelStatus === "SUSPENDED" ? /* @__PURE__ */
|
|
243
|
+
children: O("channel.errorStatus", "Error")
|
|
244
|
+
}) : e.channelStatus === "SUSPENDED" ? /* @__PURE__ */ v("span", {
|
|
228
245
|
className: "text-status-warning-text",
|
|
229
|
-
children:
|
|
230
|
-
}) : e.channelStatus === "ARCHIVED" ? /* @__PURE__ */
|
|
246
|
+
children: O("channel.suspendedStatus", "Suspended")
|
|
247
|
+
}) : e.channelStatus === "ARCHIVED" ? /* @__PURE__ */ v("span", {
|
|
231
248
|
className: "text-muted-foreground",
|
|
232
|
-
children:
|
|
233
|
-
}) : /* @__PURE__ */
|
|
249
|
+
children: O("channel.archivedStatus", "Archived")
|
|
250
|
+
}) : /* @__PURE__ */ v("span", {
|
|
234
251
|
className: "text-muted-foreground",
|
|
235
|
-
children:
|
|
252
|
+
children: O("channel.inactiveStatus", "Inactive")
|
|
236
253
|
})
|
|
237
|
-
}), e.lastTestedAt && /* @__PURE__ */
|
|
254
|
+
}), e.lastTestedAt && /* @__PURE__ */ y("p", {
|
|
238
255
|
className: "text-xs text-muted-foreground",
|
|
239
256
|
children: ["Last tested: ", new Date(e.lastTestedAt).toLocaleDateString()]
|
|
240
257
|
})]
|
|
241
258
|
}),
|
|
242
|
-
e.needsTokenRefresh && /* @__PURE__ */
|
|
259
|
+
e.needsTokenRefresh && /* @__PURE__ */ v("span", {
|
|
243
260
|
className: "px-2 py-1 text-xs bg-status-warning-bg-subtle text-status-warning-text rounded",
|
|
244
261
|
children: "Token Expires"
|
|
245
262
|
}),
|
|
246
|
-
e.tagAssignments.length > 0 && /* @__PURE__ */
|
|
263
|
+
e.tagAssignments.length > 0 && /* @__PURE__ */ y("div", {
|
|
247
264
|
className: "flex flex-wrap gap-1",
|
|
248
265
|
"aria-label": "Connection tags",
|
|
249
|
-
children: [e.tagAssignments.slice(0, 3).map((e) => /* @__PURE__ */
|
|
266
|
+
children: [e.tagAssignments.slice(0, 3).map((e) => /* @__PURE__ */ v(b, {
|
|
250
267
|
id: e.tagId,
|
|
251
268
|
label: e.tagId,
|
|
252
269
|
size: "sm"
|
|
253
|
-
}, e.id)), e.tagAssignments.length > 3 && /* @__PURE__ */
|
|
270
|
+
}, e.id)), e.tagAssignments.length > 3 && /* @__PURE__ */ y("span", {
|
|
254
271
|
className: "text-xs text-muted-foreground",
|
|
255
272
|
children: ["+", e.tagAssignments.length - 3]
|
|
256
273
|
})]
|
|
257
274
|
}),
|
|
258
|
-
/* @__PURE__ */
|
|
275
|
+
/* @__PURE__ */ v("button", {
|
|
276
|
+
type: "button",
|
|
259
277
|
onClick: (t) => {
|
|
260
278
|
t.stopPropagation(), c(`/channels/${e.channelId}`);
|
|
261
279
|
},
|
|
262
|
-
"aria-label":
|
|
280
|
+
"aria-label": O("channel.viewChannelSettings", "View channel settings"),
|
|
263
281
|
className: "p-2 hover:bg-muted rounded-lg transition-colors",
|
|
264
|
-
children: /* @__PURE__ */
|
|
282
|
+
children: /* @__PURE__ */ v(p, { className: "size-4 " })
|
|
265
283
|
})
|
|
266
284
|
]
|
|
267
285
|
})]
|
|
268
286
|
})
|
|
269
287
|
}, e.connectionId);
|
|
270
288
|
})
|
|
271
|
-
}),
|
|
289
|
+
}), L.length > 10 && /* @__PURE__ */ y("div", {
|
|
272
290
|
className: "flex items-center justify-between px-4 py-3 border border-border rounded-lg mt-3",
|
|
273
|
-
children: [/* @__PURE__ */
|
|
291
|
+
children: [/* @__PURE__ */ y("p", {
|
|
274
292
|
className: "text-sm text-muted-foreground",
|
|
275
293
|
children: [
|
|
276
|
-
|
|
294
|
+
O("channel.showing", "Showing"),
|
|
277
295
|
" ",
|
|
278
|
-
/* @__PURE__ */
|
|
296
|
+
/* @__PURE__ */ y("span", {
|
|
279
297
|
className: "font-medium",
|
|
280
298
|
children: [
|
|
281
|
-
|
|
299
|
+
N * 10 + 1,
|
|
282
300
|
"–",
|
|
283
|
-
Math.min((
|
|
301
|
+
Math.min((N + 1) * 10, L.length)
|
|
284
302
|
]
|
|
285
303
|
}),
|
|
286
304
|
" ",
|
|
287
|
-
|
|
305
|
+
O("channel.of", "of"),
|
|
288
306
|
" ",
|
|
289
|
-
/* @__PURE__ */
|
|
307
|
+
/* @__PURE__ */ v("span", {
|
|
290
308
|
className: "font-medium",
|
|
291
|
-
children:
|
|
309
|
+
children: L.length
|
|
292
310
|
})
|
|
293
311
|
]
|
|
294
|
-
}), /* @__PURE__ */
|
|
312
|
+
}), /* @__PURE__ */ y("div", {
|
|
295
313
|
className: "flex items-center gap-2",
|
|
296
314
|
children: [
|
|
297
|
-
/* @__PURE__ */
|
|
298
|
-
|
|
299
|
-
|
|
315
|
+
/* @__PURE__ */ v("button", {
|
|
316
|
+
type: "button",
|
|
317
|
+
onClick: () => P((e) => Math.max(0, e - 1)),
|
|
318
|
+
disabled: N === 0,
|
|
300
319
|
className: "px-3 py-1.5 text-sm border border-border rounded-lg hover:bg-muted transition-colors disabled:opacity-40 disabled:cursor-not-allowed",
|
|
301
|
-
children:
|
|
320
|
+
children: O("channel.previous", "Previous")
|
|
302
321
|
}),
|
|
303
|
-
/* @__PURE__ */
|
|
322
|
+
/* @__PURE__ */ y("span", {
|
|
304
323
|
className: "text-sm text-muted-foreground",
|
|
305
324
|
children: [
|
|
306
|
-
|
|
325
|
+
N + 1,
|
|
307
326
|
" / ",
|
|
308
|
-
|
|
327
|
+
R
|
|
309
328
|
]
|
|
310
329
|
}),
|
|
311
|
-
/* @__PURE__ */
|
|
312
|
-
|
|
313
|
-
|
|
330
|
+
/* @__PURE__ */ v("button", {
|
|
331
|
+
type: "button",
|
|
332
|
+
onClick: () => P((e) => Math.min(R - 1, e + 1)),
|
|
333
|
+
disabled: N >= R - 1,
|
|
314
334
|
className: "px-3 py-1.5 text-sm border border-border rounded-lg hover:bg-muted transition-colors disabled:opacity-40 disabled:cursor-not-allowed",
|
|
315
|
-
children:
|
|
335
|
+
children: O("channel.next", "Next")
|
|
316
336
|
})
|
|
317
337
|
]
|
|
318
338
|
})]
|
|
@@ -323,6 +343,6 @@ function x() {
|
|
|
323
343
|
});
|
|
324
344
|
}
|
|
325
345
|
//#endregion
|
|
326
|
-
export {
|
|
346
|
+
export { S as ConnectionsListPage };
|
|
327
347
|
|
|
328
348
|
//# sourceMappingURL=ConnectionsListPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConnectionsListPage.js","names":[],"sources":["../../../../../src/channel/modules/channels/pages/ConnectionsListPage.tsx"],"sourcesContent":["/**\n * Connections List Page\n *\n * Displays all connections across channels with their status.\n */\n\nimport { useState, useEffect } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { TagBadge } from '@burdenoff/fe-libs/tag';\nimport {\n ArrowLeft,\n Plus,\n Loader2,\n AlertCircle,\n CheckCircle2,\n XCircle,\n RefreshCw,\n Settings,\n Link,\n} from 'lucide-react';\nimport { useChannels } from '../../../hooks/useChannels';\nimport { PermissionGuard } from '../../../components/PermissionGuard';\nimport { CHANNEL_PERMISSIONS } from '../../../constants/permissions';\n\nconst HEALTH_CONFIG: Record<string, { icon: typeof CheckCircle2; color: string; label: string }> = {\n true: { icon: CheckCircle2, color: 'text-status-success-text', label: 'Healthy' },\n false: { icon: XCircle, color: 'text-status-error-text', label: 'Unhealthy' },\n};\n\nexport function ConnectionsListPage() {\n const navigate = useNavigate();\n const { channels, isLoading, error, refetch } = useChannels();\n\n // Poll for connection status updates every 60 s.\n // connectionStatusChanged subscription is scoped to a single channelId;\n // this page shows all connections, so polling is used instead.\n useEffect(() => {\n const timer = setInterval(() => {\n void refetch();\n }, 60_000);\n return () => clearInterval(timer);\n }, [refetch]);\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 // Filter state\n const [healthFilter, setHealthFilter] = useState<string>('all');\n const [platformFilter, setPlatformFilter] = useState<string>('all');\n const pageSize = 10;\n const [currentPage, setCurrentPage] = useState(0);\n\n // Get all connections from channels\n const connections = channels\n .filter((ch) => ch.connection)\n .map((ch) => ({\n channelId: ch.id,\n channelName: ch.name,\n platform: ch.platform,\n adapterType: ch.adapterType,\n channelStatus: ch.status,\n connectionId: ch.connection!.id,\n isActive: ch.connection!.isActive,\n isHealthy: ch.connection!.isHealthy,\n needsTokenRefresh: ch.connection!.needsTokenRefresh,\n lastTestedAt: ch.connection!.lastTestedAt,\n authType: ch.connection!.authType,\n tagAssignments: ch.connection!.tagAssignments ?? [],\n }));\n\n // Get unique platforms\n const platforms = [...new Set(connections.map((c) => c.platform))];\n\n // Apply filters\n const filteredConnections = connections.filter((conn) => {\n if (healthFilter === 'healthy' && !conn.isHealthy) return false;\n if (healthFilter === 'unhealthy' && conn.isHealthy) return false;\n if (platformFilter !== 'all' && conn.platform !== platformFilter) return false;\n return true;\n });\n\n const totalPages = Math.max(1, Math.ceil(filteredConnections.length / pageSize));\n const pagedConnections = filteredConnections.slice(\n currentPage * pageSize,\n (currentPage + 1) * pageSize\n );\n\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <Loader2 className=\"w-8 h-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-screen gap-4\">\n <AlertCircle className=\"w-12 h-12 text-destructive\" />\n <h1 className=\"text-xl font-semibold\">\n {tr('channel.loadConnectionsFailed', 'Failed to load connections')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">{error}</p>\n <button\n onClick={() => refetch()}\n className=\"px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90\"\n >\n {tr('channel.retry', 'Retry')}\n </button>\n </div>\n );\n }\n\n return (\n <PermissionGuard permission={CHANNEL_PERMISSIONS.CHANNEL_CONNECTION_READ}>\n <div className=\"min-h-screen bg-background\">\n {/* Header */}\n <div className=\"border-b bg-card\">\n <div className=\"container mx-auto px-6 py-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <button\n onClick={() => navigate('./list')}\n aria-label={tr('channel.backToChannels', 'Back to channels')}\n className=\"p-2 hover:bg-muted rounded-lg transition-colors\"\n >\n <ArrowLeft className=\"w-5 h-5\" />\n </button>\n <div>\n <h1 className=\"text-2xl font-bold\">{tr('channel.connections', 'Connections')}</h1>\n <p className=\"text-sm text-muted-foreground\">\n {filteredConnections.length} connection\n {filteredConnections.length !== 1 ? 's' : ''}\n </p>\n </div>\n </div>\n <button\n onClick={() => navigate('./create')}\n className=\"px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 transition-colors flex items-center gap-2\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('channel.newChannel', 'New Channel')}\n </button>\n </div>\n </div>\n </div>\n\n {/* Filters */}\n <div className=\"container mx-auto px-6 py-4\">\n <div className=\"flex items-center gap-4\">\n <select\n value={platformFilter}\n onChange={(e) => setPlatformFilter(e.target.value)}\n className=\"px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"all\">{tr('channel.allPlatforms', 'All Platforms')}</option>\n {platforms.map((p) => (\n <option key={p} value={p}>\n {p}\n </option>\n ))}\n </select>\n\n <select\n value={healthFilter}\n onChange={(e) => setHealthFilter(e.target.value)}\n className=\"px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"all\">{tr('channel.allStatus', 'All Status')}</option>\n <option value=\"healthy\">{tr('channel.healthy', 'Healthy')}</option>\n <option value=\"unhealthy\">{tr('channel.unhealthy', 'Unhealthy')}</option>\n </select>\n\n <button\n onClick={() => refetch()}\n aria-label={tr('channel.refresh', 'Refresh')}\n className=\"p-2 hover:bg-muted rounded-lg transition-colors\"\n >\n <RefreshCw className=\"w-5 h-5\" aria-hidden=\"true\" />\n </button>\n </div>\n </div>\n\n {/* Connections List */}\n <div className=\"container mx-auto px-6 pb-8\">\n {filteredConnections.length === 0 ? (\n <div className=\"text-center py-12\">\n <Link className=\"w-12 h-12 mx-auto text-muted-foreground mb-4\" />\n <h2 className=\"text-lg font-semibold mb-2\">\n {tr('channel.noConnectionsFound', 'No connections found')}\n </h2>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {channels.length === 0\n ? tr('channel.createChannelFirst', 'Create a channel first to add connections')\n : tr('channel.noConnectionsMatchFilter', 'No connections match your filters')}\n </p>\n {channels.length === 0 ? (\n <button\n onClick={() => navigate('./create')}\n className=\"px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90\"\n >\n {tr('channel.createChannel', 'Create Channel')}\n </button>\n ) : (\n <button\n onClick={() => {\n setHealthFilter('all');\n setPlatformFilter('all');\n }}\n className=\"px-4 py-2 rounded-lg border hover:bg-muted\"\n >\n {tr('channel.clearFilters', 'Clear Filters')}\n </button>\n )}\n </div>\n ) : (\n <>\n <div className=\"border rounded-lg divide-y\">\n {pagedConnections.map((conn) => {\n const health = HEALTH_CONFIG[String(conn.isHealthy)] || HEALTH_CONFIG.false;\n const HealthIcon = health.icon;\n\n return (\n <div\n key={conn.connectionId}\n className=\"p-4 hover:bg-muted/50 transition-colors cursor-pointer\"\n onClick={() => navigate(`./${conn.channelId}`)}\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <div className={health.color} aria-label={health.label}>\n <HealthIcon className=\"w-5 h-5\" aria-hidden=\"true\" />\n </div>\n <div>\n <p className=\"font-medium\">{conn.channelName}</p>\n <p className=\"text-sm text-muted-foreground\">\n {conn.platform} • {conn.adapterType} • {conn.authType}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-4\">\n <div className=\"text-right\">\n <p className=\"text-sm\">\n {conn.channelStatus === 'ACTIVE' ? (\n <span className=\"text-status-success-text\">\n {tr('channel.activeStatus', 'Active')}\n </span>\n ) : conn.channelStatus === 'INACTIVE' ? (\n <span className=\"text-muted-foreground\">\n {tr('channel.inactiveStatus', 'Inactive')}\n </span>\n ) : conn.channelStatus === 'ERROR' ? (\n <span className=\"text-status-error-text\">\n {tr('channel.errorStatus', 'Error')}\n </span>\n ) : conn.channelStatus === 'SUSPENDED' ? (\n <span className=\"text-status-warning-text\">\n {tr('channel.suspendedStatus', 'Suspended')}\n </span>\n ) : conn.channelStatus === 'ARCHIVED' ? (\n <span className=\"text-muted-foreground\">\n {tr('channel.archivedStatus', 'Archived')}\n </span>\n ) : (\n <span className=\"text-muted-foreground\">\n {tr('channel.inactiveStatus', 'Inactive')}\n </span>\n )}\n </p>\n {conn.lastTestedAt && (\n <p className=\"text-xs text-muted-foreground\">\n Last tested: {new Date(conn.lastTestedAt).toLocaleDateString()}\n </p>\n )}\n </div>\n\n {conn.needsTokenRefresh && (\n <span className=\"px-2 py-1 text-xs bg-status-warning-bg-subtle text-status-warning-text rounded\">\n Token Expires\n </span>\n )}\n\n {conn.tagAssignments.length > 0 && (\n <div className=\"flex flex-wrap gap-1\" aria-label=\"Connection tags\">\n {conn.tagAssignments.slice(0, 3).map((a) => (\n <TagBadge key={a.id} id={a.tagId} label={a.tagId} size=\"sm\" />\n ))}\n {conn.tagAssignments.length > 3 && (\n <span className=\"text-xs text-muted-foreground\">\n +{conn.tagAssignments.length - 3}\n </span>\n )}\n </div>\n )}\n\n <button\n onClick={(e) => {\n e.stopPropagation();\n navigate(`/channels/${conn.channelId}`);\n }}\n aria-label={tr('channel.viewChannelSettings', 'View channel settings')}\n className=\"p-2 hover:bg-muted rounded-lg transition-colors\"\n >\n <Settings className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n </div>\n );\n })}\n </div>\n {/* Pagination */}\n {filteredConnections.length > pageSize && (\n <div className=\"flex items-center justify-between px-4 py-3 border border-border rounded-lg mt-3\">\n <p className=\"text-sm text-muted-foreground\">\n {tr('channel.showing', 'Showing')}{' '}\n <span className=\"font-medium\">\n {currentPage * pageSize + 1}–\n {Math.min((currentPage + 1) * pageSize, filteredConnections.length)}\n </span>{' '}\n {tr('channel.of', 'of')}{' '}\n <span className=\"font-medium\">{filteredConnections.length}</span>\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setCurrentPage((p) => Math.max(0, p - 1))}\n disabled={currentPage === 0}\n className=\"px-3 py-1.5 text-sm border border-border rounded-lg hover:bg-muted transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {tr('channel.previous', 'Previous')}\n </button>\n <span className=\"text-sm text-muted-foreground\">\n {currentPage + 1} / {totalPages}\n </span>\n <button\n onClick={() => setCurrentPage((p) => Math.min(totalPages - 1, p + 1))}\n disabled={currentPage >= totalPages - 1}\n className=\"px-3 py-1.5 text-sm border border-border rounded-lg hover:bg-muted transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {tr('channel.next', 'Next')}\n </button>\n </div>\n </div>\n )}\n </>\n )}\n </div>\n </div>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ConnectionsListPage.js","names":[],"sources":["../../../../../src/channel/modules/channels/pages/ConnectionsListPage.tsx"],"sourcesContent":["/**\n * Connections List Page\n *\n * Displays all connections across channels with their status.\n */\n\nimport { useState, useEffect } from 'react';\nimport { useNavigate } 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 {\n ArrowLeft,\n Plus,\n Loader2,\n AlertCircle,\n CheckCircle2,\n XCircle,\n RefreshCw,\n Settings,\n Link,\n} from 'lucide-react';\nimport { useChannels } from '../../../hooks/useChannels';\nimport { PermissionGuard } from '../../../components/PermissionGuard';\nimport { CHANNEL_PERMISSIONS } from '../../../constants/permissions';\n\nconst HEALTH_CONFIG: Record<string, { icon: typeof CheckCircle2; color: string; label: string }> = {\n true: { icon: CheckCircle2, color: 'text-status-success-text', label: 'Healthy' },\n false: { icon: XCircle, color: 'text-status-error-text', label: 'Unhealthy' },\n};\n\nexport function ConnectionsListPage() {\n const navigate = useNavigate();\n const { hasPermission } = usePermissions();\n // Creating connections is admin-only (channel-connection:create) — hide otherwise.\n const canConnectionCreate = hasPermission(CHANNEL_PERMISSIONS.CHANNEL_CONNECTION_CREATE);\n const { channels, isLoading, error, refetch } = useChannels();\n\n // Poll for connection status updates every 60 s.\n // connectionStatusChanged subscription is scoped to a single channelId;\n // this page shows all connections, so polling is used instead.\n useEffect(() => {\n const timer = setInterval(() => {\n void refetch();\n }, 60_000);\n return () => clearInterval(timer);\n }, [refetch]);\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 // Filter state\n const [healthFilter, setHealthFilter] = useState<string>('all');\n const [platformFilter, setPlatformFilter] = useState<string>('all');\n const pageSize = 10;\n const [currentPage, setCurrentPage] = useState(0);\n\n // Get all connections from channels (single-pass; avoids filter().map() double traversal)\n const connections = channels.reduce<\n Array<{\n channelId: string;\n channelName: string;\n platform: (typeof channels)[number]['platform'];\n adapterType: (typeof channels)[number]['adapterType'];\n channelStatus: (typeof channels)[number]['status'];\n connectionId: string;\n isActive: boolean;\n isHealthy: boolean;\n needsTokenRefresh: boolean;\n lastTestedAt: string | null | undefined;\n authType: NonNullable<(typeof channels)[number]['connection']>['authType'];\n tagAssignments: NonNullable<\n NonNullable<(typeof channels)[number]['connection']>['tagAssignments']\n >;\n }>\n >((acc, ch) => {\n const conn = ch.connection;\n if (!conn) return acc;\n acc.push({\n channelId: ch.id,\n channelName: ch.name,\n platform: ch.platform,\n adapterType: ch.adapterType,\n channelStatus: ch.status,\n connectionId: conn.id,\n isActive: conn.isActive,\n isHealthy: conn.isHealthy,\n needsTokenRefresh: conn.needsTokenRefresh,\n lastTestedAt: conn.lastTestedAt,\n authType: conn.authType,\n tagAssignments: conn.tagAssignments ?? [],\n });\n return acc;\n }, []);\n\n // Get unique platforms\n const platforms = [...new Set(connections.map((c) => c.platform))];\n\n // Apply filters\n const filteredConnections = connections.filter((conn) => {\n if (healthFilter === 'healthy' && !conn.isHealthy) return false;\n if (healthFilter === 'unhealthy' && conn.isHealthy) return false;\n if (platformFilter !== 'all' && conn.platform !== platformFilter) return false;\n return true;\n });\n\n const totalPages = Math.max(1, Math.ceil(filteredConnections.length / pageSize));\n const pagedConnections = filteredConnections.slice(\n currentPage * pageSize,\n (currentPage + 1) * pageSize\n );\n\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <Loader2 className=\"size-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"flex flex-col items-center justify-center min-h-screen gap-4\">\n <AlertCircle className=\"size-12 text-destructive\" />\n <h1 className=\"text-xl font-semibold\">\n {tr('channel.loadConnectionsFailed', 'Failed to load connections')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">{error}</p>\n <button\n type=\"button\"\n onClick={() => refetch()}\n className=\"px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90\"\n >\n {tr('channel.retry', 'Retry')}\n </button>\n </div>\n );\n }\n\n return (\n <PermissionGuard permission={CHANNEL_PERMISSIONS.CHANNEL_CONNECTION_READ}>\n <div className=\"min-h-screen bg-background\">\n {/* Header */}\n <div className=\"border-b bg-card\" data-tour=\"channels-connections-header\">\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('./list')}\n aria-label={tr('channel.backToChannels', 'Back to channels')}\n className=\"p-2 hover:bg-muted rounded-lg transition-colors\"\n >\n <ArrowLeft className=\"size-5 \" />\n </button>\n <div>\n <h1 className=\"text-2xl font-bold\">{tr('channel.connections', 'Connections')}</h1>\n <p className=\"text-sm text-muted-foreground\">\n {filteredConnections.length} connection\n {filteredConnections.length !== 1 ? 's' : ''}\n </p>\n </div>\n </div>\n {canConnectionCreate && (\n <button\n type=\"button\"\n onClick={() => navigate('./create')}\n className=\"px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 transition-colors flex items-center gap-2\"\n >\n <Plus className=\"size-4 \" />\n {tr('channel.newConnection', 'New Connection')}\n </button>\n )}\n </div>\n </div>\n </div>\n\n {/* Filters */}\n <div className=\"container mx-auto px-6 py-4\" data-tour=\"channels-connections-filters\">\n <div className=\"flex items-center gap-4\">\n <select\n value={platformFilter}\n onChange={(e) => setPlatformFilter(e.target.value)}\n className=\"px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"all\">{tr('channel.allPlatforms', 'All Platforms')}</option>\n {platforms.map((p) => (\n <option key={p} value={p}>\n {p}\n </option>\n ))}\n </select>\n\n <select\n value={healthFilter}\n onChange={(e) => setHealthFilter(e.target.value)}\n className=\"px-4 py-2 rounded-lg border bg-background focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"all\">{tr('channel.allStatus', 'All Status')}</option>\n <option value=\"healthy\">{tr('channel.healthy', 'Healthy')}</option>\n <option value=\"unhealthy\">{tr('channel.unhealthy', 'Unhealthy')}</option>\n </select>\n\n <button\n type=\"button\"\n onClick={() => refetch()}\n aria-label={tr('channel.refresh', 'Refresh')}\n className=\"p-2 hover:bg-muted rounded-lg transition-colors\"\n >\n <RefreshCw className=\"size-5 \" aria-hidden=\"true\" />\n </button>\n </div>\n </div>\n\n {/* Connections List */}\n <div className=\"container mx-auto px-6 pb-8\">\n {filteredConnections.length === 0 ? (\n <div className=\"text-center py-12\">\n <Link className=\"size-12 mx-auto text-muted-foreground mb-4\" />\n <h2 className=\"text-lg font-semibold mb-2\">\n {tr('channel.noConnectionsFound', 'No connections found')}\n </h2>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {channels.length === 0\n ? tr('channel.createChannelFirst', 'Create a channel first to add connections')\n : tr('channel.noConnectionsMatchFilter', 'No connections match your filters')}\n </p>\n {channels.length === 0 ? (\n canConnectionCreate ? (\n <button\n type=\"button\"\n onClick={() => navigate('./create')}\n className=\"px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90\"\n >\n {tr('channel.createConnection', 'Create Connection')}\n </button>\n ) : null\n ) : (\n <button\n type=\"button\"\n onClick={() => {\n setHealthFilter('all');\n setPlatformFilter('all');\n }}\n className=\"px-4 py-2 rounded-lg border hover:bg-muted\"\n >\n {tr('channel.clearFilters', 'Clear Filters')}\n </button>\n )}\n </div>\n ) : (\n <>\n <div className=\"border rounded-lg divide-y\">\n {pagedConnections.map((conn) => {\n const health = HEALTH_CONFIG[String(conn.isHealthy)] || HEALTH_CONFIG.false;\n const HealthIcon = health.icon;\n\n return (\n <div\n key={conn.connectionId}\n role=\"button\"\n tabIndex={0}\n className=\"p-4 hover:bg-muted/50 transition-colors cursor-pointer\"\n onClick={() => navigate(`./${conn.channelId}`)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n navigate(`./${conn.channelId}`);\n }\n }}\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <div className={health.color} aria-label={health.label}>\n <HealthIcon className=\"size-5 \" aria-hidden=\"true\" />\n </div>\n <div>\n <p className=\"font-medium\">{conn.channelName}</p>\n <p className=\"text-sm text-muted-foreground\">\n {conn.platform} • {conn.adapterType} • {conn.authType}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-4\">\n <div className=\"text-right\">\n <p className=\"text-sm\">\n {conn.channelStatus === 'ACTIVE' ? (\n <span className=\"text-status-success-text\">\n {tr('channel.activeStatus', 'Active')}\n </span>\n ) : conn.channelStatus === 'INACTIVE' ? (\n <span className=\"text-muted-foreground\">\n {tr('channel.inactiveStatus', 'Inactive')}\n </span>\n ) : conn.channelStatus === 'ERROR' ? (\n <span className=\"text-status-error-text\">\n {tr('channel.errorStatus', 'Error')}\n </span>\n ) : conn.channelStatus === 'SUSPENDED' ? (\n <span className=\"text-status-warning-text\">\n {tr('channel.suspendedStatus', 'Suspended')}\n </span>\n ) : conn.channelStatus === 'ARCHIVED' ? (\n <span className=\"text-muted-foreground\">\n {tr('channel.archivedStatus', 'Archived')}\n </span>\n ) : (\n <span className=\"text-muted-foreground\">\n {tr('channel.inactiveStatus', 'Inactive')}\n </span>\n )}\n </p>\n {conn.lastTestedAt && (\n <p className=\"text-xs text-muted-foreground\">\n Last tested: {new Date(conn.lastTestedAt).toLocaleDateString()}\n </p>\n )}\n </div>\n\n {conn.needsTokenRefresh && (\n <span className=\"px-2 py-1 text-xs bg-status-warning-bg-subtle text-status-warning-text rounded\">\n Token Expires\n </span>\n )}\n\n {conn.tagAssignments.length > 0 && (\n <div className=\"flex flex-wrap gap-1\" aria-label=\"Connection tags\">\n {conn.tagAssignments.slice(0, 3).map((a) => (\n <TagBadge key={a.id} id={a.tagId} label={a.tagId} size=\"sm\" />\n ))}\n {conn.tagAssignments.length > 3 && (\n <span className=\"text-xs text-muted-foreground\">\n +{conn.tagAssignments.length - 3}\n </span>\n )}\n </div>\n )}\n\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n navigate(`/channels/${conn.channelId}`);\n }}\n aria-label={tr('channel.viewChannelSettings', 'View channel settings')}\n className=\"p-2 hover:bg-muted rounded-lg transition-colors\"\n >\n <Settings className=\"size-4 \" />\n </button>\n </div>\n </div>\n </div>\n );\n })}\n </div>\n {/* Pagination */}\n {filteredConnections.length > pageSize && (\n <div className=\"flex items-center justify-between px-4 py-3 border border-border rounded-lg mt-3\">\n <p className=\"text-sm text-muted-foreground\">\n {tr('channel.showing', 'Showing')}{' '}\n <span className=\"font-medium\">\n {currentPage * pageSize + 1}–\n {Math.min((currentPage + 1) * pageSize, filteredConnections.length)}\n </span>{' '}\n {tr('channel.of', 'of')}{' '}\n <span className=\"font-medium\">{filteredConnections.length}</span>\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => setCurrentPage((p) => Math.max(0, p - 1))}\n disabled={currentPage === 0}\n className=\"px-3 py-1.5 text-sm border border-border rounded-lg hover:bg-muted transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {tr('channel.previous', 'Previous')}\n </button>\n <span className=\"text-sm text-muted-foreground\">\n {currentPage + 1} / {totalPages}\n </span>\n <button\n type=\"button\"\n onClick={() => setCurrentPage((p) => Math.min(totalPages - 1, p + 1))}\n disabled={currentPage >= totalPages - 1}\n className=\"px-3 py-1.5 text-sm border border-border rounded-lg hover:bg-muted transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {tr('channel.next', 'Next')}\n </button>\n </div>\n </div>\n )}\n </>\n )}\n </div>\n </div>\n </PermissionGuard>\n );\n}\n"],"mappings":"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"}
|