tmex-cli 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/runtime/server.js +466 -232
  2. package/package.json +1 -1
  3. package/resources/fe-dist/assets/DevicePage-iSkEDEpS.js +4570 -0
  4. package/resources/fe-dist/assets/DevicePage-iSkEDEpS.js.map +1 -0
  5. package/resources/fe-dist/assets/DevicesPage-CtNzaW_c.js +2143 -0
  6. package/resources/fe-dist/assets/{DevicesPage-BTB6mlBW.js.map → DevicesPage-CtNzaW_c.js.map} +1 -1
  7. package/resources/fe-dist/assets/SettingsPage-D25_d6j9.js +1144 -0
  8. package/resources/fe-dist/assets/{SettingsPage-BDVq_Akt.js.map → SettingsPage-D25_d6j9.js.map} +1 -1
  9. package/resources/fe-dist/assets/index-CJaX5rlK.css +4527 -0
  10. package/resources/fe-dist/assets/index-dsVN7rgz.js +200 -0
  11. package/resources/fe-dist/assets/index-dsVN7rgz.js.map +1 -0
  12. package/resources/fe-dist/assets/select-BNsiC9zT.js +2805 -0
  13. package/resources/fe-dist/assets/{select-7tfuDWw3.js.map → select-BNsiC9zT.js.map} +1 -1
  14. package/resources/fe-dist/assets/switch-CIU4AisU.js +234 -0
  15. package/resources/fe-dist/assets/{switch-CNHRGb7-.js.map → switch-CIU4AisU.js.map} +1 -1
  16. package/resources/fe-dist/assets/useValueChanged-V23H0VpC.js +351 -0
  17. package/resources/fe-dist/assets/{useValueChanged-Bi_NzPTr.js.map → useValueChanged-V23H0VpC.js.map} +1 -1
  18. package/resources/fe-dist/index.html +2 -2
  19. package/resources/gateway-drizzle/meta/0000_snapshot.json +6 -17
  20. package/resources/gateway-drizzle/meta/0001_snapshot.json +6 -17
  21. package/resources/gateway-drizzle/meta/_journal.json +1 -1
  22. package/resources/fe-dist/assets/DevicePage-BE5Hlzny.js +0 -26
  23. package/resources/fe-dist/assets/DevicePage-BE5Hlzny.js.map +0 -1
  24. package/resources/fe-dist/assets/DevicesPage-BTB6mlBW.js +0 -17
  25. package/resources/fe-dist/assets/SettingsPage-BDVq_Akt.js +0 -17
  26. package/resources/fe-dist/assets/index-Chps0Pui.js +0 -448
  27. package/resources/fe-dist/assets/index-Chps0Pui.js.map +0 -1
  28. package/resources/fe-dist/assets/index-CyKyNcdz.css +0 -1
  29. package/resources/fe-dist/assets/select-7tfuDWw3.js +0 -17
  30. package/resources/fe-dist/assets/switch-CNHRGb7-.js +0 -12
  31. package/resources/fe-dist/assets/useValueChanged-Bi_NzPTr.js +0 -7
@@ -0,0 +1,1144 @@
1
+ import {
2
+ u as B,
3
+ c as G,
4
+ d as ce,
5
+ B as d,
6
+ I as de,
7
+ j as e,
8
+ a as ge,
9
+ r as i,
10
+ f as o,
11
+ t as pe,
12
+ i as ve,
13
+ b as xe,
14
+ e as z,
15
+ } from './index-dsVN7rgz.js';
16
+ import {
17
+ a as $,
18
+ d as Ce,
19
+ c as D,
20
+ f as Ee,
21
+ b as I,
22
+ C as M,
23
+ e as Se,
24
+ g as Te,
25
+ I as g,
26
+ u as j,
27
+ S as ke,
28
+ } from './select-BNsiC9zT.js';
29
+ import { S as F, a as Ie, L as me } from './switch-CIU4AisU.js'; /**
30
+ * @license lucide-react v0.564.0 - ISC
31
+ *
32
+ * This source code is licensed under the ISC license.
33
+ * See the LICENSE file in the root directory of this source tree.
34
+ */
35
+ import {
36
+ g as $e,
37
+ e as Ae,
38
+ a as Be,
39
+ A as Fe,
40
+ f as Me,
41
+ b as Pe,
42
+ c as Re,
43
+ T as je,
44
+ d as qe,
45
+ } from './useValueChanged-V23H0VpC.js';
46
+ const De = [
47
+ ['path', { d: 'M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8', key: '1357e3' }],
48
+ ['path', { d: 'M3 3v5h5', key: '1xhq8a' }],
49
+ ],
50
+ ze = G('rotate-ccw', De); /**
51
+ * @license lucide-react v0.564.0 - ISC
52
+ *
53
+ * This source code is licensed under the ISC license.
54
+ * See the LICENSE file in the root directory of this source tree.
55
+ */
56
+ const Le = [
57
+ [
58
+ 'path',
59
+ {
60
+ d: 'M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z',
61
+ key: '1c8476',
62
+ },
63
+ ],
64
+ ['path', { d: 'M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7', key: '1ydtos' }],
65
+ ['path', { d: 'M7 3v4a1 1 0 0 0 1 1h7', key: 't51u73' }],
66
+ ],
67
+ L = G('save', Le); /**
68
+ * @license lucide-react v0.564.0 - ISC
69
+ *
70
+ * This source code is licensed under the ISC license.
71
+ * See the LICENSE file in the root directory of this source tree.
72
+ */
73
+ const Qe = [
74
+ [
75
+ 'path',
76
+ {
77
+ d: 'M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z',
78
+ key: 'oel41y',
79
+ },
80
+ ],
81
+ ],
82
+ he = G('shield', Qe);
83
+ async function h(s, m) {
84
+ try {
85
+ return (await s.json()).error ?? m;
86
+ } catch {
87
+ return m;
88
+ }
89
+ }
90
+ function We() {
91
+ var ie, oe, re, le;
92
+ const { t: s } = B(),
93
+ m = ge(),
94
+ { refreshSettings: u } = xe(),
95
+ [n, r] = i.useState('site'),
96
+ x = ce((t) => t.theme),
97
+ y = ce((t) => t.setTheme),
98
+ b = x === 'dark',
99
+ [w, k] = i.useState('tmex'),
100
+ [C, S] = i.useState(window.location.origin),
101
+ [p, N] = i.useState('en_US'),
102
+ [f, P] = i.useState(6),
103
+ [R, q] = i.useState(!0),
104
+ [E, A] = i.useState(!0),
105
+ [T, a] = i.useState(2),
106
+ [l, v] = i.useState(10),
107
+ [we, be] = i.useState(!1),
108
+ [Q, X] = i.useState(''),
109
+ [K, Y] = i.useState(''),
110
+ [fe, ye] = i.useState(null),
111
+ [U, Z] = i.useState(''),
112
+ [O, ee] = i.useState(''),
113
+ Ne = (t) => {
114
+ const c = t ? 'dark' : 'light';
115
+ y(c), document.documentElement.classList.toggle('dark', c === 'dark');
116
+ },
117
+ _ = z({
118
+ queryKey: ['site-settings'],
119
+ queryFn: async () => {
120
+ const t = await fetch('/api/settings/site');
121
+ if (!t.ok) throw new Error(await h(t, s('settings.loadFailed')));
122
+ return await t.json();
123
+ },
124
+ }),
125
+ H = z({
126
+ queryKey: ['telegram-bots'],
127
+ queryFn: async () => {
128
+ const t = await fetch('/api/settings/telegram/bots');
129
+ if (!t.ok) throw new Error(await h(t, s('telegram.loadBotsFailed')));
130
+ return await t.json();
131
+ },
132
+ });
133
+ i.useEffect(() => {
134
+ var c;
135
+ const t = (c = _.data) == null ? void 0 : c.settings;
136
+ t &&
137
+ (k(t.siteName),
138
+ S(t.siteUrl),
139
+ N(t.language ?? 'en_US'),
140
+ P(t.bellThrottleSeconds),
141
+ q(t.enableBrowserBellToast ?? !0),
142
+ A(t.enableTelegramBellPush ?? !0),
143
+ a(t.sshReconnectMaxRetries),
144
+ v(t.sshReconnectDelaySeconds));
145
+ }, [(ie = _.data) == null ? void 0 : ie.settings]);
146
+ const se = j({
147
+ mutationFn: async () => {
148
+ const c = await fetch('/api/settings/site', {
149
+ method: 'PATCH',
150
+ headers: { 'Content-Type': 'application/json' },
151
+ body: JSON.stringify({
152
+ siteName: w,
153
+ siteUrl: C,
154
+ language: p,
155
+ bellThrottleSeconds: f,
156
+ enableBrowserBellToast: R,
157
+ enableTelegramBellPush: E,
158
+ sshReconnectMaxRetries: T,
159
+ sshReconnectDelaySeconds: l,
160
+ }),
161
+ });
162
+ if (!c.ok) throw new Error(await h(c, s('settings.saveFailed')));
163
+ },
164
+ onSuccess: async () => {
165
+ var t, c;
166
+ await Promise.all([m.invalidateQueries({ queryKey: ['site-settings'] }), u()]),
167
+ o.success(s('settings.settingsSaved')),
168
+ ((c = (t = _.data) == null ? void 0 : t.settings) == null ? void 0 : c.language) !== p &&
169
+ (ve.changeLanguage(p), be(!0));
170
+ },
171
+ onError: (t) => {
172
+ o.error(t instanceof Error ? t.message : s('common.error'));
173
+ },
174
+ }),
175
+ W = j({
176
+ mutationFn: async () => {
177
+ const t = await fetch('/api/settings/telegram/bots', {
178
+ method: 'POST',
179
+ headers: { 'Content-Type': 'application/json' },
180
+ body: JSON.stringify({ name: Q, token: K, enabled: !0, allowAuthRequests: !0 }),
181
+ });
182
+ if (!t.ok) throw new Error(await h(t, s('telegram.createFailed')));
183
+ },
184
+ onSuccess: async () => {
185
+ X(''),
186
+ Y(''),
187
+ await m.invalidateQueries({ queryKey: ['telegram-bots'] }),
188
+ o.success(s('common.success'));
189
+ },
190
+ onError: (t) => {
191
+ o.error(t instanceof Error ? t.message : s('common.error'));
192
+ },
193
+ }),
194
+ te = ((oe = H.data) == null ? void 0 : oe.bots) ?? [],
195
+ J = z({
196
+ queryKey: ['webhooks'],
197
+ queryFn: async () => {
198
+ const t = await fetch('/api/webhooks');
199
+ if (!t.ok) throw new Error(await h(t, s('webhook.loadFailed')));
200
+ return await t.json();
201
+ },
202
+ }),
203
+ V = j({
204
+ mutationFn: async () => {
205
+ const t = await fetch('/api/webhooks', {
206
+ method: 'POST',
207
+ headers: { 'Content-Type': 'application/json' },
208
+ body: JSON.stringify({ url: U, secret: O }),
209
+ });
210
+ if (!t.ok) throw new Error(await h(t, s('webhook.createFailed')));
211
+ },
212
+ onSuccess: async () => {
213
+ Z(''),
214
+ ee(''),
215
+ await m.invalidateQueries({ queryKey: ['webhooks'] }),
216
+ o.success(s('common.success'));
217
+ },
218
+ onError: (t) => {
219
+ o.error(t instanceof Error ? t.message : s('common.error'));
220
+ },
221
+ }),
222
+ ae = j({
223
+ mutationFn: async (t) => {
224
+ const c = await fetch(`/api/webhooks/${t}`, { method: 'DELETE' });
225
+ if (!c.ok) throw new Error(await h(c, s('webhook.deleteFailed')));
226
+ },
227
+ onSuccess: async () => {
228
+ await m.invalidateQueries({ queryKey: ['webhooks'] }), o.success(s('common.success'));
229
+ },
230
+ onError: (t) => {
231
+ o.error(t instanceof Error ? t.message : s('common.error'));
232
+ },
233
+ }),
234
+ ne = ((re = J.data) == null ? void 0 : re.webhooks) ?? [];
235
+ return e.jsxs('div', {
236
+ className:
237
+ 'mx-auto flex w-full max-w-6xl flex-col gap-4 p-3 pb-[calc(2rem+env(safe-area-inset-bottom))] sm:gap-6 sm:p-5',
238
+ 'data-testid': 'settings-page',
239
+ children: [
240
+ e.jsxs('div', {
241
+ className: 'flex flex-wrap gap-2',
242
+ children: [
243
+ e.jsx(d, {
244
+ type: 'button',
245
+ size: 'sm',
246
+ variant: n === 'site' ? 'default' : 'outline',
247
+ 'data-testid': 'settings-tab-site',
248
+ onClick: () => r('site'),
249
+ children: s('settings.siteSettings'),
250
+ }),
251
+ e.jsx(d, {
252
+ type: 'button',
253
+ size: 'sm',
254
+ variant: n === 'notifications' ? 'default' : 'outline',
255
+ 'data-testid': 'settings-tab-notifications',
256
+ onClick: () => r('notifications'),
257
+ children: s('settings.notificationsTab'),
258
+ }),
259
+ e.jsx(d, {
260
+ type: 'button',
261
+ size: 'sm',
262
+ variant: n === 'telegram' ? 'default' : 'outline',
263
+ 'data-testid': 'settings-tab-telegram',
264
+ onClick: () => r('telegram'),
265
+ children: s('telegram.title'),
266
+ }),
267
+ e.jsx(d, {
268
+ type: 'button',
269
+ size: 'sm',
270
+ variant: n === 'webhooks' ? 'default' : 'outline',
271
+ 'data-testid': 'settings-tab-webhooks',
272
+ onClick: () => r('webhooks'),
273
+ children: s('webhook.title'),
274
+ }),
275
+ ],
276
+ }),
277
+ n === 'site' &&
278
+ e.jsxs(M, {
279
+ className: 'border-0 ring-0',
280
+ children: [
281
+ e.jsx($, { children: e.jsx(I, { children: s('settings.siteSettings') }) }),
282
+ e.jsxs(D, {
283
+ className: 'space-y-6',
284
+ children: [
285
+ e.jsxs('div', {
286
+ className: 'space-y-2',
287
+ children: [
288
+ e.jsx('label', {
289
+ className: 'block text-sm font-medium',
290
+ htmlFor: 'site-name-input',
291
+ children: s('settings.siteName'),
292
+ }),
293
+ e.jsx(g, {
294
+ id: 'site-name-input',
295
+ value: w,
296
+ onChange: (t) => k(t.target.value),
297
+ placeholder: s('settings.siteNamePlaceholder'),
298
+ className: 'min-h-10',
299
+ }),
300
+ ],
301
+ }),
302
+ e.jsxs('div', {
303
+ className: 'space-y-2',
304
+ children: [
305
+ e.jsx('label', {
306
+ className: 'block text-sm font-medium',
307
+ htmlFor: 'site-url-input',
308
+ children: s('settings.siteUrl'),
309
+ }),
310
+ e.jsx(g, {
311
+ id: 'site-url-input',
312
+ value: C,
313
+ onChange: (t) => S(t.target.value),
314
+ placeholder: s('settings.siteUrlPlaceholder'),
315
+ className: 'min-h-10',
316
+ }),
317
+ ],
318
+ }),
319
+ e.jsxs('div', {
320
+ className: 'space-y-2',
321
+ children: [
322
+ e.jsx('label', {
323
+ className: 'block text-sm font-medium',
324
+ htmlFor: 'language-select',
325
+ children: s('settings.language'),
326
+ }),
327
+ e.jsxs(ke, {
328
+ value: p,
329
+ onValueChange: (t) => {
330
+ t && N(t);
331
+ },
332
+ children: [
333
+ e.jsx(Ce, {
334
+ id: 'language-select',
335
+ 'data-testid': 'settings-language-select',
336
+ className: 'w-full min-h-10',
337
+ children: e.jsx(Se, {
338
+ placeholder: s('settings.language'),
339
+ children:
340
+ ((le = de.locales.find((t) => t.code === p)) == null
341
+ ? void 0
342
+ : le.nativeName) ?? p,
343
+ }),
344
+ }),
345
+ e.jsx(Ee, {
346
+ className: 'max-h-[var(--tmex-viewport-height)]',
347
+ children: de.locales.map((t) =>
348
+ e.jsx(Te, { value: t.code, children: t.nativeName }, t.code)
349
+ ),
350
+ }),
351
+ ],
352
+ }),
353
+ we &&
354
+ e.jsx('p', {
355
+ className: 'mt-1 text-xs text-primary',
356
+ 'data-testid': 'settings-refresh-notice',
357
+ children: s('settings.refreshToApply'),
358
+ }),
359
+ ],
360
+ }),
361
+ e.jsx('div', {
362
+ className: 'space-y-3',
363
+ children: e.jsxs('div', {
364
+ className:
365
+ 'flex min-h-10 items-center justify-between gap-4 rounded-lg border border-border bg-card px-4 py-2.5',
366
+ children: [
367
+ e.jsx('div', {
368
+ className: 'min-w-0 pr-2',
369
+ children: e.jsx('div', {
370
+ className: 'text-sm font-medium',
371
+ children: s('settings.theme'),
372
+ }),
373
+ }),
374
+ e.jsx(F, {
375
+ checked: b,
376
+ onCheckedChange: (t) => Ne(!!t),
377
+ 'data-testid': 'settings-theme-toggle',
378
+ }),
379
+ ],
380
+ }),
381
+ }),
382
+ ],
383
+ }),
384
+ ],
385
+ }),
386
+ n === 'notifications' &&
387
+ e.jsxs(M, {
388
+ className: 'border-0 ring-0',
389
+ children: [
390
+ e.jsx($, { children: e.jsx(I, { children: s('settings.notificationsTab') }) }),
391
+ e.jsxs(D, {
392
+ className: 'space-y-6',
393
+ children: [
394
+ e.jsxs('div', {
395
+ className: 'space-y-3',
396
+ children: [
397
+ e.jsxs('div', {
398
+ className:
399
+ 'flex min-h-10 items-center justify-between gap-4 rounded-lg border border-border bg-card px-4 py-2.5',
400
+ children: [
401
+ e.jsx('div', {
402
+ className: 'min-w-0 pr-2',
403
+ children: e.jsx('div', {
404
+ className: 'text-sm font-medium',
405
+ children: s('settings.enableBrowserBellToast'),
406
+ }),
407
+ }),
408
+ e.jsx(F, {
409
+ checked: R,
410
+ onCheckedChange: (t) => q(!!t),
411
+ 'data-testid': 'settings-enable-browser-bell-toast',
412
+ }),
413
+ ],
414
+ }),
415
+ e.jsxs('div', {
416
+ className:
417
+ 'flex min-h-10 items-center justify-between gap-4 rounded-lg border border-border bg-card px-4 py-2.5',
418
+ children: [
419
+ e.jsx('div', {
420
+ className: 'min-w-0 pr-2',
421
+ children: e.jsx('div', {
422
+ className: 'text-sm font-medium',
423
+ children: s('settings.enableTelegramBellPush'),
424
+ }),
425
+ }),
426
+ e.jsx(F, {
427
+ checked: E,
428
+ onCheckedChange: (t) => A(!!t),
429
+ 'data-testid': 'settings-enable-telegram-bell-push',
430
+ }),
431
+ ],
432
+ }),
433
+ ],
434
+ }),
435
+ e.jsxs('div', {
436
+ className: 'grid grid-cols-1 gap-4 sm:grid-cols-3',
437
+ children: [
438
+ e.jsxs('div', {
439
+ className: 'space-y-2',
440
+ children: [
441
+ e.jsx('label', {
442
+ className: 'block text-sm font-medium',
443
+ htmlFor: 'bell-throttle-input',
444
+ children: s('settings.bellThrottle'),
445
+ }),
446
+ e.jsx(g, {
447
+ id: 'bell-throttle-input',
448
+ type: 'number',
449
+ value: f,
450
+ min: 0,
451
+ max: 300,
452
+ onChange: (t) => P(Number(t.target.value)),
453
+ className: 'min-h-10',
454
+ }),
455
+ ],
456
+ }),
457
+ e.jsxs('div', {
458
+ className: 'space-y-2',
459
+ children: [
460
+ e.jsx('label', {
461
+ className: 'block text-sm font-medium',
462
+ htmlFor: 'ssh-reconnect-retries-input',
463
+ children: s('settings.sshReconnectMaxRetries'),
464
+ }),
465
+ e.jsx(g, {
466
+ id: 'ssh-reconnect-retries-input',
467
+ type: 'number',
468
+ value: T,
469
+ min: 0,
470
+ max: 20,
471
+ onChange: (t) => a(Number(t.target.value)),
472
+ className: 'min-h-10',
473
+ }),
474
+ ],
475
+ }),
476
+ e.jsxs('div', {
477
+ className: 'space-y-2',
478
+ children: [
479
+ e.jsx('label', {
480
+ className: 'block text-sm font-medium',
481
+ htmlFor: 'ssh-reconnect-delay-input',
482
+ children: s('settings.sshReconnectDelay'),
483
+ }),
484
+ e.jsx(g, {
485
+ id: 'ssh-reconnect-delay-input',
486
+ type: 'number',
487
+ value: l,
488
+ min: 1,
489
+ max: 300,
490
+ onChange: (t) => v(Number(t.target.value)),
491
+ className: 'min-h-10',
492
+ }),
493
+ ],
494
+ }),
495
+ ],
496
+ }),
497
+ ],
498
+ }),
499
+ ],
500
+ }),
501
+ n === 'telegram' &&
502
+ e.jsxs(M, {
503
+ className: 'border-0 ring-0',
504
+ children: [
505
+ e.jsx($, { children: e.jsx(I, { children: s('telegram.title') }) }),
506
+ e.jsxs(D, {
507
+ className: 'space-y-6',
508
+ children: [
509
+ e.jsx('div', {
510
+ className: 'space-y-4',
511
+ children: e.jsxs('div', {
512
+ className: 'grid grid-cols-1 gap-4 md:grid-cols-12 md:items-end',
513
+ children: [
514
+ e.jsxs('div', {
515
+ className: 'md:col-span-4 space-y-2',
516
+ children: [
517
+ e.jsx('label', {
518
+ className: 'block text-sm font-medium',
519
+ htmlFor: 'new-bot-name',
520
+ children: s('telegram.botName'),
521
+ }),
522
+ e.jsx(g, {
523
+ id: 'new-bot-name',
524
+ value: Q,
525
+ onChange: (t) => X(t.target.value),
526
+ placeholder: s('telegram.botNamePlaceholder'),
527
+ className: 'min-h-10',
528
+ }),
529
+ ],
530
+ }),
531
+ e.jsxs('div', {
532
+ className: 'md:col-span-6 space-y-2',
533
+ children: [
534
+ e.jsx('label', {
535
+ className: 'block text-sm font-medium',
536
+ htmlFor: 'new-bot-token',
537
+ children: s('telegram.botToken'),
538
+ }),
539
+ e.jsx(g, {
540
+ id: 'new-bot-token',
541
+ type: 'password',
542
+ value: K,
543
+ onChange: (t) => Y(t.target.value),
544
+ placeholder: s('telegram.botTokenPlaceholder'),
545
+ className: 'min-h-10',
546
+ }),
547
+ ],
548
+ }),
549
+ e.jsx('div', {
550
+ className: 'md:col-span-2',
551
+ children: e.jsxs(d, {
552
+ variant: 'default',
553
+ className: 'w-full md:w-auto',
554
+ 'data-testid': 'telegram-add-bot',
555
+ onClick: () => W.mutate(),
556
+ disabled: W.isPending || !Q.trim() || !K.trim(),
557
+ children: [
558
+ W.isPending
559
+ ? e.jsx(me, { className: 'h-4 w-4 animate-spin' })
560
+ : e.jsx(L, { className: 'h-4 w-4' }),
561
+ s('telegram.addBot'),
562
+ ],
563
+ }),
564
+ }),
565
+ ],
566
+ }),
567
+ }),
568
+ e.jsxs('div', {
569
+ className: 'space-y-3',
570
+ children: [
571
+ H.isLoading &&
572
+ e.jsx('div', {
573
+ className: 'text-sm text-muted-foreground',
574
+ children: s('common.loading'),
575
+ }),
576
+ !H.isLoading &&
577
+ te.length === 0 &&
578
+ e.jsx('div', {
579
+ className: 'text-sm text-muted-foreground',
580
+ children: s('telegram.addBot'),
581
+ }),
582
+ te.map((t) =>
583
+ e.jsx(
584
+ Ke,
585
+ {
586
+ bot: t,
587
+ expanded: fe === t.id,
588
+ onToggleExpand: () => {
589
+ ye((c) => (c === t.id ? null : t.id));
590
+ },
591
+ },
592
+ t.id
593
+ )
594
+ ),
595
+ ],
596
+ }),
597
+ ],
598
+ }),
599
+ ],
600
+ }),
601
+ n === 'webhooks' &&
602
+ e.jsxs(M, {
603
+ className: 'border-0 ring-0',
604
+ children: [
605
+ e.jsx($, { children: e.jsx(I, { children: s('webhook.title') }) }),
606
+ e.jsxs(D, {
607
+ className: 'space-y-6',
608
+ children: [
609
+ e.jsxs('div', {
610
+ className: 'grid grid-cols-1 gap-4 md:grid-cols-12 md:items-end',
611
+ children: [
612
+ e.jsxs('div', {
613
+ className: 'md:col-span-6 space-y-2',
614
+ children: [
615
+ e.jsx('label', {
616
+ className: 'block text-sm font-medium',
617
+ htmlFor: 'webhook-url-input',
618
+ children: s('webhook.url'),
619
+ }),
620
+ e.jsx(g, {
621
+ id: 'webhook-url-input',
622
+ 'data-testid': 'webhook-url-input',
623
+ value: U,
624
+ onChange: (t) => Z(t.target.value),
625
+ placeholder: 'https://example.com/webhook',
626
+ className: 'min-h-10',
627
+ }),
628
+ ],
629
+ }),
630
+ e.jsxs('div', {
631
+ className: 'md:col-span-4 space-y-2',
632
+ children: [
633
+ e.jsx('label', {
634
+ className: 'block text-sm font-medium',
635
+ htmlFor: 'webhook-secret-input',
636
+ children: s('webhook.secret'),
637
+ }),
638
+ e.jsx(g, {
639
+ id: 'webhook-secret-input',
640
+ 'data-testid': 'webhook-secret-input',
641
+ value: O,
642
+ onChange: (t) => ee(t.target.value),
643
+ placeholder: s('webhook.secretPlaceholder'),
644
+ className: 'min-h-10',
645
+ }),
646
+ ],
647
+ }),
648
+ e.jsx('div', {
649
+ className: 'md:col-span-2',
650
+ children: e.jsxs(d, {
651
+ variant: 'default',
652
+ className: 'w-full md:w-auto',
653
+ 'data-testid': 'webhook-add',
654
+ onClick: () => V.mutate(),
655
+ disabled: V.isPending || !U.trim() || !O.trim(),
656
+ children: [
657
+ V.isPending
658
+ ? e.jsx(me, { className: 'h-4 w-4 animate-spin' })
659
+ : e.jsx(L, { className: 'h-4 w-4' }),
660
+ s('webhook.add'),
661
+ ],
662
+ }),
663
+ }),
664
+ ],
665
+ }),
666
+ e.jsxs('div', {
667
+ className: 'space-y-2',
668
+ children: [
669
+ J.isLoading &&
670
+ e.jsx('div', {
671
+ className: 'text-sm text-muted-foreground',
672
+ children: s('common.loading'),
673
+ }),
674
+ !J.isLoading &&
675
+ ne.length === 0 &&
676
+ e.jsx('div', {
677
+ className: 'text-sm text-muted-foreground',
678
+ children: s('webhook.empty'),
679
+ }),
680
+ ne.map((t) =>
681
+ e.jsxs(
682
+ 'div',
683
+ {
684
+ 'data-testid': 'webhook-item',
685
+ 'data-webhook-url': t.url,
686
+ className:
687
+ 'flex items-center justify-between gap-3 rounded-lg border border-border bg-card px-4 py-2.5',
688
+ children: [
689
+ e.jsxs('div', {
690
+ className: 'min-w-0',
691
+ children: [
692
+ e.jsx('div', {
693
+ className: 'truncate text-sm font-medium',
694
+ children: t.url,
695
+ }),
696
+ e.jsx('div', {
697
+ className: 'text-xs text-muted-foreground',
698
+ children: new Date(t.createdAt).toLocaleString(pe(p)),
699
+ }),
700
+ ],
701
+ }),
702
+ e.jsx(d, {
703
+ variant: 'ghost',
704
+ size: 'icon-sm',
705
+ 'data-testid': 'webhook-delete',
706
+ onClick: () => ae.mutate(t.id),
707
+ disabled: ae.isPending,
708
+ 'aria-label': s('common.delete'),
709
+ title: s('common.delete'),
710
+ children: e.jsx(je, { className: 'h-4 w-4' }),
711
+ }),
712
+ ],
713
+ },
714
+ t.id
715
+ )
716
+ ),
717
+ ],
718
+ }),
719
+ ],
720
+ }),
721
+ ],
722
+ }),
723
+ (n === 'site' || n === 'notifications') &&
724
+ e.jsx('div', {
725
+ className: 'flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-end',
726
+ children: e.jsxs(d, {
727
+ variant: 'default',
728
+ 'data-testid': 'settings-save',
729
+ onClick: () => se.mutate(),
730
+ disabled: se.isPending,
731
+ className: 'w-full sm:w-auto',
732
+ children: [e.jsx(L, { className: 'h-4 w-4' }), s('common.save')],
733
+ }),
734
+ }),
735
+ ],
736
+ });
737
+ }
738
+ function Ke({ bot: s, expanded: m, onToggleExpand: u }) {
739
+ var T;
740
+ const { t: n } = B(),
741
+ r = ge(),
742
+ [x, y] = i.useState(s.name),
743
+ [b, w] = i.useState(''),
744
+ [k, C] = i.useState(s.enabled),
745
+ [S, p] = i.useState(s.allowAuthRequests);
746
+ i.useEffect(() => {
747
+ y(s.name), C(s.enabled), p(s.allowAuthRequests);
748
+ }, [s.allowAuthRequests, s.enabled, s.name]);
749
+ const N = z({
750
+ queryKey: ['telegram-bot-chats', s.id],
751
+ enabled: m,
752
+ queryFn: async () => {
753
+ const a = await fetch(`/api/settings/telegram/bots/${s.id}/chats`);
754
+ if (!a.ok) throw new Error(await h(a, n('telegram.loadChatsFailed')));
755
+ return await a.json();
756
+ },
757
+ }),
758
+ f = i.useMemo(() => {
759
+ var l;
760
+ const a = ((l = N.data) == null ? void 0 : l.chats) ?? [];
761
+ return {
762
+ pending: a.filter((v) => v.status === 'pending'),
763
+ authorized: a.filter((v) => v.status === 'authorized'),
764
+ };
765
+ }, [(T = N.data) == null ? void 0 : T.chats]),
766
+ P = j({
767
+ mutationFn: async () => {
768
+ const a = { name: x, enabled: k, allowAuthRequests: S };
769
+ b.trim() && (a.token = b.trim());
770
+ const l = await fetch(`/api/settings/telegram/bots/${s.id}`, {
771
+ method: 'PATCH',
772
+ headers: { 'Content-Type': 'application/json' },
773
+ body: JSON.stringify(a),
774
+ });
775
+ if (!l.ok) throw new Error(await h(l, n('telegram.updateFailed')));
776
+ },
777
+ onSuccess: async () => {
778
+ w(''),
779
+ await r.invalidateQueries({ queryKey: ['telegram-bots'] }),
780
+ o.success(n('common.success'));
781
+ },
782
+ onError: (a) => {
783
+ o.error(a instanceof Error ? a.message : n('common.error'));
784
+ },
785
+ }),
786
+ R = j({
787
+ mutationFn: async () => {
788
+ const a = await fetch(`/api/settings/telegram/bots/${s.id}`, { method: 'DELETE' });
789
+ if (!a.ok) throw new Error(await h(a, n('telegram.deleteFailed')));
790
+ },
791
+ onSuccess: async () => {
792
+ await r.invalidateQueries({ queryKey: ['telegram-bots'] }), o.success(n('common.success'));
793
+ },
794
+ onError: (a) => {
795
+ o.error(a instanceof Error ? a.message : n('common.error'));
796
+ },
797
+ }),
798
+ q = j({
799
+ mutationFn: async (a) => {
800
+ const l = await fetch(
801
+ `/api/settings/telegram/bots/${s.id}/chats/${encodeURIComponent(a)}/approve`,
802
+ { method: 'POST' }
803
+ );
804
+ if (!l.ok) throw new Error(await h(l, n('telegram.approveFailed')));
805
+ },
806
+ onSuccess: async () => {
807
+ await Promise.all([
808
+ r.invalidateQueries({ queryKey: ['telegram-bots'] }),
809
+ r.invalidateQueries({ queryKey: ['telegram-bot-chats', s.id] }),
810
+ ]),
811
+ o.success(n('common.success'));
812
+ },
813
+ onError: (a) => {
814
+ o.error(a instanceof Error ? a.message : n('common.error'));
815
+ },
816
+ }),
817
+ E = j({
818
+ mutationFn: async (a) => {
819
+ const l = await fetch(
820
+ `/api/settings/telegram/bots/${s.id}/chats/${encodeURIComponent(a)}`,
821
+ { method: 'DELETE' }
822
+ );
823
+ if (!l.ok) throw new Error(await h(l, n('telegram.removeFailed')));
824
+ },
825
+ onSuccess: async () => {
826
+ await Promise.all([
827
+ r.invalidateQueries({ queryKey: ['telegram-bots'] }),
828
+ r.invalidateQueries({ queryKey: ['telegram-bot-chats', s.id] }),
829
+ ]),
830
+ o.success(n('common.success'));
831
+ },
832
+ onError: (a) => {
833
+ o.error(a instanceof Error ? a.message : n('common.error'));
834
+ },
835
+ }),
836
+ A = j({
837
+ mutationFn: async (a) => {
838
+ const l = await fetch(
839
+ `/api/settings/telegram/bots/${s.id}/chats/${encodeURIComponent(a)}/test`,
840
+ { method: 'POST' }
841
+ );
842
+ if (!l.ok) throw new Error(await h(l, n('telegram.testMessageFailed')));
843
+ },
844
+ onSuccess: () => {
845
+ o.success(n('common.success'));
846
+ },
847
+ onError: (a) => {
848
+ o.error(a instanceof Error ? a.message : n('common.error'));
849
+ },
850
+ });
851
+ return e.jsxs('div', {
852
+ className: 'space-y-4 rounded-md border-0 bg-card p-4',
853
+ 'data-testid': `telegram-bot-card-${s.id}`,
854
+ 'data-bot-name': s.name,
855
+ children: [
856
+ e.jsxs('div', {
857
+ className: 'flex items-center justify-between gap-3',
858
+ children: [
859
+ e.jsxs('div', {
860
+ children: [
861
+ e.jsx('div', { className: 'font-medium', children: s.name }),
862
+ e.jsxs('div', {
863
+ className: 'text-xs text-muted-foreground',
864
+ children: [s.authorizedCount, ' / ', s.pendingCount],
865
+ }),
866
+ ],
867
+ }),
868
+ e.jsx(d, {
869
+ variant: 'ghost',
870
+ 'data-testid': `telegram-bot-toggle-${s.id}`,
871
+ onClick: u,
872
+ children: n(m ? 'common.collapse' : 'common.expand'),
873
+ }),
874
+ ],
875
+ }),
876
+ e.jsxs('div', {
877
+ className: 'grid grid-cols-1 gap-4 md:grid-cols-12 md:items-end',
878
+ children: [
879
+ e.jsxs('div', {
880
+ className: 'md:col-span-3 space-y-2',
881
+ children: [
882
+ e.jsx('label', {
883
+ className: 'block text-sm font-medium',
884
+ htmlFor: `bot-name-${s.id}`,
885
+ children: n('telegram.botName'),
886
+ }),
887
+ e.jsx(g, {
888
+ id: `bot-name-${s.id}`,
889
+ value: x,
890
+ onChange: (a) => y(a.target.value),
891
+ className: 'min-h-10',
892
+ }),
893
+ ],
894
+ }),
895
+ e.jsxs('div', {
896
+ className: 'md:col-span-4 space-y-2',
897
+ children: [
898
+ e.jsx('label', {
899
+ className: 'block text-sm font-medium',
900
+ htmlFor: `bot-token-${s.id}`,
901
+ children: n('telegram.botToken'),
902
+ }),
903
+ e.jsx(g, {
904
+ id: `bot-token-${s.id}`,
905
+ type: 'password',
906
+ value: b,
907
+ onChange: (a) => w(a.target.value),
908
+ placeholder: n('telegram.tokenPlaceholder'),
909
+ className: 'min-h-10',
910
+ }),
911
+ ],
912
+ }),
913
+ e.jsx('div', {
914
+ className: 'md:col-span-2',
915
+ children: e.jsxs('div', {
916
+ className:
917
+ 'flex min-h-10 items-center justify-between gap-3 rounded-lg border border-border bg-background px-3 py-2.5',
918
+ children: [
919
+ e.jsx('span', { className: 'text-sm font-medium', children: n('common.enabled') }),
920
+ e.jsx(F, { checked: k, onCheckedChange: (a) => C(!!a) }),
921
+ ],
922
+ }),
923
+ }),
924
+ e.jsx('div', {
925
+ className: 'md:col-span-3',
926
+ children: e.jsxs('div', {
927
+ className:
928
+ 'flex min-h-10 items-center justify-between gap-3 rounded-lg border border-border bg-background px-3 py-2.5',
929
+ children: [
930
+ e.jsx('span', {
931
+ className: 'text-sm font-medium',
932
+ children: n('telegram.allowAuthRequests'),
933
+ }),
934
+ e.jsx(F, { checked: S, onCheckedChange: (a) => p(!!a) }),
935
+ ],
936
+ }),
937
+ }),
938
+ ],
939
+ }),
940
+ e.jsxs('div', {
941
+ className: 'flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-end',
942
+ children: [
943
+ e.jsxs(d, {
944
+ variant: 'destructive',
945
+ 'data-testid': `telegram-bot-delete-${s.id}`,
946
+ onClick: () => R.mutate(),
947
+ className: 'w-full sm:w-auto',
948
+ children: [e.jsx(je, { className: 'h-4 w-4' }), n('telegram.deleteBot')],
949
+ }),
950
+ e.jsxs(d, {
951
+ variant: 'default',
952
+ 'data-testid': `telegram-bot-save-${s.id}`,
953
+ onClick: () => P.mutate(),
954
+ className: 'w-full sm:w-auto',
955
+ children: [e.jsx(L, { className: 'h-4 w-4' }), n('common.save')],
956
+ }),
957
+ ],
958
+ }),
959
+ m &&
960
+ e.jsxs('div', {
961
+ className: 'grid grid-cols-1 gap-4 border-t border-border pt-4 lg:grid-cols-2',
962
+ children: [
963
+ e.jsxs('div', {
964
+ className: 'space-y-2',
965
+ children: [
966
+ e.jsxs('h3', {
967
+ className: 'text-sm font-semibold flex items-center gap-1',
968
+ children: [e.jsx(he, { className: 'h-4 w-4' }), n('telegram.pendingChats')],
969
+ }),
970
+ f.pending.length === 0 &&
971
+ e.jsx('div', { className: 'text-xs text-muted-foreground', children: '-' }),
972
+ f.pending.map((a) =>
973
+ e.jsx(
974
+ ue,
975
+ {
976
+ chat: a,
977
+ pending: !0,
978
+ onApprove: () => q.mutate(a.chatId),
979
+ onDelete: () => E.mutate(a.chatId),
980
+ },
981
+ `${a.botId}-${a.chatId}`
982
+ )
983
+ ),
984
+ ],
985
+ }),
986
+ e.jsxs('div', {
987
+ className: 'space-y-2',
988
+ children: [
989
+ e.jsxs('h3', {
990
+ className: 'text-sm font-semibold flex items-center gap-1',
991
+ children: [e.jsx(he, { className: 'h-4 w-4' }), n('telegram.chats')],
992
+ }),
993
+ f.authorized.length === 0 &&
994
+ e.jsx('div', { className: 'text-xs text-muted-foreground', children: '-' }),
995
+ f.authorized.map((a) =>
996
+ e.jsx(
997
+ ue,
998
+ {
999
+ chat: a,
1000
+ pending: !1,
1001
+ onTest: () => A.mutate(a.chatId),
1002
+ onDelete: () => E.mutate(a.chatId),
1003
+ },
1004
+ `${a.botId}-${a.chatId}`
1005
+ )
1006
+ ),
1007
+ ],
1008
+ }),
1009
+ N.isLoading &&
1010
+ e.jsx('div', {
1011
+ className: 'lg:col-span-2 text-xs text-muted-foreground',
1012
+ children: n('common.loading'),
1013
+ }),
1014
+ ],
1015
+ }),
1016
+ ],
1017
+ });
1018
+ }
1019
+ function ue({ chat: s, pending: m, onApprove: u, onDelete: n, onTest: r }) {
1020
+ const { t: x } = B(),
1021
+ y = xe((b) => {
1022
+ var w;
1023
+ return ((w = b.settings) == null ? void 0 : w.language) ?? 'en_US';
1024
+ });
1025
+ return e.jsxs('div', {
1026
+ className: 'space-y-2 rounded border-0 bg-background p-3',
1027
+ children: [
1028
+ e.jsx('div', {
1029
+ className: 'text-sm font-medium truncate',
1030
+ title: s.displayName,
1031
+ children: s.displayName,
1032
+ }),
1033
+ e.jsxs('div', {
1034
+ className: 'text-xs text-muted-foreground',
1035
+ children: [x('telegram.chatId'), ':', s.chatId],
1036
+ }),
1037
+ e.jsx('div', {
1038
+ className: 'text-xs text-muted-foreground',
1039
+ children: new Date(s.appliedAt).toLocaleString(pe(y)),
1040
+ }),
1041
+ e.jsx('div', {
1042
+ className: 'flex items-center justify-end gap-2 pt-1',
1043
+ children: m
1044
+ ? e.jsxs(e.Fragment, {
1045
+ children: [
1046
+ e.jsx(d, {
1047
+ variant: 'outline',
1048
+ size: 'sm',
1049
+ onClick: n,
1050
+ children: x('telegram.reject'),
1051
+ }),
1052
+ e.jsx(d, {
1053
+ variant: 'default',
1054
+ size: 'sm',
1055
+ onClick: u,
1056
+ children: x('telegram.authorize'),
1057
+ }),
1058
+ ],
1059
+ })
1060
+ : e.jsxs(e.Fragment, {
1061
+ children: [
1062
+ e.jsxs(d, {
1063
+ variant: 'secondary',
1064
+ size: 'sm',
1065
+ onClick: r,
1066
+ children: [
1067
+ e.jsx(Ie, { className: 'h-3.5 w-3.5' }),
1068
+ x('telegram.sendTestMessage'),
1069
+ ],
1070
+ }),
1071
+ e.jsx(d, {
1072
+ variant: 'destructive',
1073
+ size: 'sm',
1074
+ onClick: n,
1075
+ children: x('common.delete'),
1076
+ }),
1077
+ ],
1078
+ }),
1079
+ }),
1080
+ ],
1081
+ });
1082
+ }
1083
+ function Je() {
1084
+ const { t: s } = B();
1085
+ return e.jsx(e.Fragment, { children: s('sidebar.settings') });
1086
+ }
1087
+ function Ve() {
1088
+ const { t: s } = B(),
1089
+ [m, u] = i.useState(!1),
1090
+ n = j({
1091
+ mutationFn: async () => {
1092
+ const r = await fetch('/api/settings/restart', { method: 'POST' });
1093
+ if (!r.ok) throw new Error(await h(r, s('settings.restartFailed')));
1094
+ },
1095
+ onSuccess: () => {
1096
+ o.success(s('settings.restartScheduled'));
1097
+ },
1098
+ onError: (r) => {
1099
+ o.error(r instanceof Error ? r.message : s('common.error'));
1100
+ },
1101
+ });
1102
+ return e.jsxs(e.Fragment, {
1103
+ children: [
1104
+ e.jsx(d, {
1105
+ variant: 'ghost',
1106
+ size: 'icon-sm',
1107
+ onClick: () => u(!0),
1108
+ disabled: n.isPending,
1109
+ 'aria-label': s('settings.restartGateway'),
1110
+ title: s('settings.restartGateway'),
1111
+ className: 'text-destructive hover:text-destructive hover:bg-destructive/10',
1112
+ children: e.jsx(ze, { className: 'h-4 w-4' }),
1113
+ }),
1114
+ e.jsx(Fe, {
1115
+ open: m,
1116
+ onOpenChange: u,
1117
+ children: e.jsxs(Be, {
1118
+ children: [
1119
+ e.jsxs(Pe, {
1120
+ children: [
1121
+ e.jsx(Re, { children: s('settings.restartGateway') }),
1122
+ e.jsx(qe, { children: s('settings.restartConfirm') }),
1123
+ ],
1124
+ }),
1125
+ e.jsxs(Ae, {
1126
+ children: [
1127
+ e.jsx(Me, { onClick: () => u(!1), children: s('common.cancel') }),
1128
+ e.jsx($e, {
1129
+ variant: 'destructive',
1130
+ onClick: () => {
1131
+ n.mutate(), u(!1);
1132
+ },
1133
+ children: s('common.confirm'),
1134
+ }),
1135
+ ],
1136
+ }),
1137
+ ],
1138
+ }),
1139
+ }),
1140
+ ],
1141
+ });
1142
+ }
1143
+ export { Ve as PageActions, Je as PageTitle, We as default };
1144
+ //# sourceMappingURL=SettingsPage-D25_d6j9.js.map