@burdenoff/microfe-conversations 2026.830.1 → 2026.830.2
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/conversations/components/ConversationRow.js +81 -81
- package/dist/conversations/components/ConversationRow.js.map +1 -1
- package/dist/conversations/components/MessageBubble.js +116 -113
- package/dist/conversations/components/MessageBubble.js.map +1 -1
- package/dist/conversations/components/PermissionGuard.js +13 -16
- package/dist/conversations/components/PermissionGuard.js.map +1 -1
- package/dist/conversations/index.js +1 -0
- package/dist/conversations/pages/ConversationAdminPages.js +64 -79
- package/dist/conversations/pages/ConversationAdminPages.js.map +1 -1
- package/dist/conversations/pages/ConversationDetailPage.js +120 -120
- package/dist/conversations/pages/ConversationDetailPage.js.map +1 -1
- package/dist/conversations/utils/i18n.js +3 -3
- package/dist/conversations/utils/i18n.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/translations/en.js +319 -0
- package/dist/translations/en.js.map +1 -0
- package/package.json +1 -1
|
@@ -138,7 +138,7 @@ var w = m`
|
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
`;
|
|
141
|
-
function N(e) {
|
|
141
|
+
function N(e, t) {
|
|
142
142
|
if (typeof e == "string") return e;
|
|
143
143
|
if (e && typeof e == "object" && "text" in e) {
|
|
144
144
|
let t = e.text;
|
|
@@ -147,7 +147,7 @@ function N(e) {
|
|
|
147
147
|
try {
|
|
148
148
|
return JSON.stringify(e);
|
|
149
149
|
} catch {
|
|
150
|
-
return
|
|
150
|
+
return t;
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
153
|
var P = new Intl.DateTimeFormat(void 0, {
|
|
@@ -198,15 +198,15 @@ function L() {
|
|
|
198
198
|
}),
|
|
199
199
|
a && s && /* @__PURE__ */ _("p", {
|
|
200
200
|
className: "text-sm text-text-secondary",
|
|
201
|
-
children: "Loading reports…"
|
|
201
|
+
children: n("conversations.admin.loadingReports", "Loading reports…")
|
|
202
202
|
}),
|
|
203
203
|
a && c && /* @__PURE__ */ _("p", {
|
|
204
204
|
className: "text-sm text-status-error-text",
|
|
205
205
|
children: c.message
|
|
206
206
|
}),
|
|
207
207
|
a && !s && !c && m.length === 0 && /* @__PURE__ */ _(r, {
|
|
208
|
-
title: "No reports waiting for review",
|
|
209
|
-
description: "Reported messages will appear here as they are submitted.",
|
|
208
|
+
title: n("conversations.admin.noReportsTitle", "No reports waiting for review"),
|
|
209
|
+
description: n("conversations.admin.noReportsDescription", "Reported messages will appear here as they are submitted."),
|
|
210
210
|
icon: /* @__PURE__ */ _(u, {
|
|
211
211
|
className: "size-6",
|
|
212
212
|
"aria-hidden": "true"
|
|
@@ -227,10 +227,10 @@ function L() {
|
|
|
227
227
|
className: "flex flex-wrap items-center gap-2",
|
|
228
228
|
children: [
|
|
229
229
|
/* @__PURE__ */ _(I, { children: e.status }),
|
|
230
|
-
e.message.isHidden && /* @__PURE__ */ _(I, { children: "Hidden" }),
|
|
231
|
-
/* @__PURE__ */
|
|
230
|
+
e.message.isHidden && /* @__PURE__ */ _(I, { children: n("conversations.admin.hidden", "Hidden") }),
|
|
231
|
+
/* @__PURE__ */ _("span", {
|
|
232
232
|
className: "text-xs text-text-secondary",
|
|
233
|
-
children:
|
|
233
|
+
children: n("conversations.admin.reportedAt", "Reported {{date}}", { date: F(e.createdAt) })
|
|
234
234
|
})
|
|
235
235
|
]
|
|
236
236
|
}),
|
|
@@ -240,27 +240,22 @@ function L() {
|
|
|
240
240
|
}),
|
|
241
241
|
/* @__PURE__ */ _("p", {
|
|
242
242
|
className: "rounded-md border border-border-seam bg-bg-sunken p-3 text-sm text-text-secondary",
|
|
243
|
-
children: N(e.message.content)
|
|
243
|
+
children: N(e.message.content, n("conversations.admin.messageContentUnavailable", "Message content unavailable"))
|
|
244
244
|
}),
|
|
245
|
-
/* @__PURE__ */
|
|
245
|
+
/* @__PURE__ */ _("p", {
|
|
246
246
|
className: "text-xs text-text-secondary",
|
|
247
|
-
children:
|
|
248
|
-
|
|
249
|
-
e.
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
" by ",
|
|
254
|
-
e.message.authorId,
|
|
255
|
-
"; reported by ",
|
|
256
|
-
e.reportedBy
|
|
257
|
-
]
|
|
247
|
+
children: n("conversations.admin.reportMeta", "Message {{messageId}} in conversation {{conversationId}} by {{authorId}}; reported by {{reportedBy}}", {
|
|
248
|
+
messageId: e.messageId,
|
|
249
|
+
conversationId: e.message.conversationId,
|
|
250
|
+
authorId: e.message.authorId,
|
|
251
|
+
reportedBy: e.reportedBy
|
|
252
|
+
})
|
|
258
253
|
})
|
|
259
254
|
]
|
|
260
255
|
}), /* @__PURE__ */ _(b, {
|
|
261
256
|
className: "shrink-0",
|
|
262
257
|
primary: {
|
|
263
|
-
label: "Hide and resolve",
|
|
258
|
+
label: n("conversations.admin.hideAndResolve", "Hide and resolve"),
|
|
264
259
|
disabled: p,
|
|
265
260
|
onSelect: () => void d({ variables: { input: {
|
|
266
261
|
reportId: e.id,
|
|
@@ -268,7 +263,7 @@ function L() {
|
|
|
268
263
|
} } })
|
|
269
264
|
},
|
|
270
265
|
actions: [{
|
|
271
|
-
label: "Dismiss",
|
|
266
|
+
label: n("conversations.admin.dismiss", "Dismiss"),
|
|
272
267
|
disabled: p,
|
|
273
268
|
onSelect: () => void d({ variables: { input: {
|
|
274
269
|
reportId: e.id,
|
|
@@ -307,23 +302,23 @@ function R() {
|
|
|
307
302
|
children: [/* @__PURE__ */ v("select", {
|
|
308
303
|
value: u,
|
|
309
304
|
onChange: (e) => d(e.target.value),
|
|
310
|
-
"aria-label": "Bulk action",
|
|
305
|
+
"aria-label": n("conversations.admin.bulkAction", "Bulk action"),
|
|
311
306
|
className: "min-h-11 rounded-md border border-border-seam bg-bg-surface px-3 py-2 text-sm text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]",
|
|
312
307
|
children: [
|
|
313
308
|
/* @__PURE__ */ _("option", {
|
|
314
309
|
value: "ARCHIVE",
|
|
315
|
-
children: "Archive"
|
|
310
|
+
children: n("conversations.archive", "Archive")
|
|
316
311
|
}),
|
|
317
312
|
/* @__PURE__ */ _("option", {
|
|
318
313
|
value: "UNARCHIVE",
|
|
319
|
-
children: "Unarchive"
|
|
314
|
+
children: n("conversations.unarchive", "Unarchive")
|
|
320
315
|
}),
|
|
321
316
|
/* @__PURE__ */ _("option", {
|
|
322
317
|
value: "DELETE",
|
|
323
|
-
children: "Delete"
|
|
318
|
+
children: n("conversations.delete", "Delete")
|
|
324
319
|
})
|
|
325
320
|
]
|
|
326
|
-
}), /* @__PURE__ */
|
|
321
|
+
}), /* @__PURE__ */ _(y, {
|
|
327
322
|
type: "button",
|
|
328
323
|
size: "sm",
|
|
329
324
|
disabled: o.size === 0 || T,
|
|
@@ -331,7 +326,7 @@ function R() {
|
|
|
331
326
|
conversationIds: Array.from(o),
|
|
332
327
|
action: u
|
|
333
328
|
} } }),
|
|
334
|
-
children:
|
|
329
|
+
children: n("conversations.admin.applyToCount", "Apply to {{count}}", { count: o.size })
|
|
335
330
|
})]
|
|
336
331
|
}),
|
|
337
332
|
children: [
|
|
@@ -353,7 +348,7 @@ function R() {
|
|
|
353
348
|
}),
|
|
354
349
|
a && p && /* @__PURE__ */ _("p", {
|
|
355
350
|
className: "text-sm text-text-secondary",
|
|
356
|
-
children: "Loading conversations…"
|
|
351
|
+
children: n("conversations.admin.loadingConversations", "Loading conversations…")
|
|
357
352
|
}),
|
|
358
353
|
a && m && /* @__PURE__ */ _("p", {
|
|
359
354
|
className: "text-sm text-status-error-text",
|
|
@@ -368,13 +363,13 @@ function R() {
|
|
|
368
363
|
children: w.bulkUpdateConversations.successCount
|
|
369
364
|
}), /* @__PURE__ */ _("p", {
|
|
370
365
|
className: "text-xs text-text-secondary",
|
|
371
|
-
children: "Succeeded"
|
|
366
|
+
children: n("conversations.admin.succeeded", "Succeeded")
|
|
372
367
|
})] }), /* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("p", {
|
|
373
368
|
className: "text-2xl font-semibold tabular-nums text-text-primary",
|
|
374
369
|
children: w.bulkUpdateConversations.failureCount
|
|
375
370
|
}), /* @__PURE__ */ _("p", {
|
|
376
371
|
className: "text-xs text-text-secondary",
|
|
377
|
-
children: "Failed"
|
|
372
|
+
children: n("conversations.admin.failed", "Failed")
|
|
378
373
|
})] })]
|
|
379
374
|
}),
|
|
380
375
|
a && /* @__PURE__ */ _("div", {
|
|
@@ -383,24 +378,21 @@ function R() {
|
|
|
383
378
|
className: "flex min-h-11 cursor-pointer items-center gap-3 border-b border-border-seam px-4 py-3 last:border-b-0 hover:bg-accent",
|
|
384
379
|
children: [/* @__PURE__ */ _("input", {
|
|
385
380
|
type: "checkbox",
|
|
386
|
-
"aria-label":
|
|
381
|
+
"aria-label": n("conversations.admin.selectConversationAria", "Select {{title}}", { title: e.title || n("conversations.admin.untitledConversation", "Untitled conversation") }),
|
|
387
382
|
checked: o.has(e.id),
|
|
388
383
|
onChange: () => k(e.id)
|
|
389
384
|
}), /* @__PURE__ */ v("div", {
|
|
390
385
|
className: "min-w-0 flex-1",
|
|
391
386
|
children: [/* @__PURE__ */ _("p", {
|
|
392
387
|
className: "truncate text-sm font-medium text-text-primary",
|
|
393
|
-
children: e.title || "Untitled conversation"
|
|
394
|
-
}), /* @__PURE__ */
|
|
388
|
+
children: e.title || n("conversations.admin.untitledConversation", "Untitled conversation")
|
|
389
|
+
}), /* @__PURE__ */ _("p", {
|
|
395
390
|
className: "text-xs text-text-secondary",
|
|
396
|
-
children:
|
|
397
|
-
e.type,
|
|
398
|
-
|
|
399
|
-
e.
|
|
400
|
-
|
|
401
|
-
" ",
|
|
402
|
-
F(e.updatedAt)
|
|
403
|
-
]
|
|
391
|
+
children: n("conversations.admin.conversationMeta", "{{type}} · {{state}} · Updated {{date}}", {
|
|
392
|
+
type: e.type,
|
|
393
|
+
state: e.state,
|
|
394
|
+
date: F(e.updatedAt)
|
|
395
|
+
})
|
|
404
396
|
})]
|
|
405
397
|
})]
|
|
406
398
|
}, e.id))
|
|
@@ -435,15 +427,15 @@ function z() {
|
|
|
435
427
|
}),
|
|
436
428
|
s && /* @__PURE__ */ _("p", {
|
|
437
429
|
className: "text-sm text-text-secondary",
|
|
438
|
-
children: "Loading activity…"
|
|
430
|
+
children: n("conversations.admin.loadingActivity", "Loading activity…")
|
|
439
431
|
}),
|
|
440
432
|
l && /* @__PURE__ */ _("p", {
|
|
441
433
|
className: "text-sm text-status-error-text",
|
|
442
434
|
children: l.message
|
|
443
435
|
}),
|
|
444
436
|
!s && !l && u.length === 0 && /* @__PURE__ */ _(r, {
|
|
445
|
-
title: "No activity found",
|
|
446
|
-
description: "Conversation admin actions will appear here.",
|
|
437
|
+
title: n("conversations.admin.noActivityTitle", "No activity found"),
|
|
438
|
+
description: n("conversations.admin.noActivityDescription", "Conversation admin actions will appear here."),
|
|
447
439
|
illustration: "empty-data"
|
|
448
440
|
}),
|
|
449
441
|
/* @__PURE__ */ _("div", {
|
|
@@ -464,16 +456,14 @@ function z() {
|
|
|
464
456
|
}),
|
|
465
457
|
/* @__PURE__ */ _("p", {
|
|
466
458
|
className: "mt-1 text-sm text-text-secondary",
|
|
467
|
-
children: e.description || "No description provided"
|
|
459
|
+
children: e.description || n("conversations.admin.noDescription", "No description provided")
|
|
468
460
|
}),
|
|
469
|
-
/* @__PURE__ */
|
|
461
|
+
/* @__PURE__ */ _("p", {
|
|
470
462
|
className: "mt-2 text-xs text-text-secondary",
|
|
471
|
-
children:
|
|
472
|
-
|
|
473
|
-
e.
|
|
474
|
-
|
|
475
|
-
e.resourceId ?? "workspace"
|
|
476
|
-
]
|
|
463
|
+
children: n("conversations.admin.auditMeta", "User {{userId}} · Resource {{resourceId}}", {
|
|
464
|
+
userId: e.userId,
|
|
465
|
+
resourceId: e.resourceId ?? n("conversations.admin.workspaceResource", "workspace")
|
|
466
|
+
})
|
|
477
467
|
})
|
|
478
468
|
]
|
|
479
469
|
}, e.id))
|
|
@@ -519,8 +509,8 @@ function B() {
|
|
|
519
509
|
children: r("conversations.admin.appsPurpose", "Extend conversations with apps and integrations — install bots, automations, or third-party connectors scoped to this workspace, adjust their settings, and remove the ones you no longer use.")
|
|
520
510
|
}),
|
|
521
511
|
/* @__PURE__ */ v(n, {
|
|
522
|
-
title: "Install app",
|
|
523
|
-
description: "Install a workspace-scoped conversation app by app ID.",
|
|
512
|
+
title: r("conversations.admin.installApp", "Install app"),
|
|
513
|
+
description: r("conversations.admin.installAppDescription", "Install a workspace-scoped conversation app by app ID."),
|
|
524
514
|
children: [/* @__PURE__ */ v(x, {
|
|
525
515
|
treatment: "glass",
|
|
526
516
|
glow: !0,
|
|
@@ -529,15 +519,15 @@ function B() {
|
|
|
529
519
|
/* @__PURE__ */ _("input", {
|
|
530
520
|
value: l,
|
|
531
521
|
onChange: (e) => u(e.target.value),
|
|
532
|
-
placeholder: "app-id",
|
|
533
|
-
"aria-label": "App ID",
|
|
522
|
+
placeholder: r("conversations.admin.appIdPlaceholder", "app-id"),
|
|
523
|
+
"aria-label": r("conversations.admin.appId", "App ID"),
|
|
534
524
|
className: "min-h-11 rounded-md border border-border-seam bg-bg-surface px-3 py-2 text-sm text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]"
|
|
535
525
|
}),
|
|
536
526
|
/* @__PURE__ */ _("textarea", {
|
|
537
527
|
value: f,
|
|
538
528
|
onChange: (e) => m(e.target.value),
|
|
539
529
|
rows: 3,
|
|
540
|
-
"aria-label": "App settings JSON",
|
|
530
|
+
"aria-label": r("conversations.admin.appSettingsJson", "App settings JSON"),
|
|
541
531
|
className: "rounded-md border border-border-seam bg-bg-surface px-3 py-2 text-sm text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]"
|
|
542
532
|
}),
|
|
543
533
|
/* @__PURE__ */ _(y, {
|
|
@@ -547,7 +537,7 @@ function B() {
|
|
|
547
537
|
onClick: () => {
|
|
548
538
|
let e = G(f);
|
|
549
539
|
if (!l.trim() || !e) {
|
|
550
|
-
D("Enter an app ID and a valid JSON settings object.");
|
|
540
|
+
D(r("conversations.admin.installAppError", "Enter an app ID and a valid JSON settings object."));
|
|
551
541
|
return;
|
|
552
542
|
}
|
|
553
543
|
D(null), R({ variables: { input: {
|
|
@@ -556,7 +546,7 @@ function B() {
|
|
|
556
546
|
settings: e
|
|
557
547
|
} } });
|
|
558
548
|
},
|
|
559
|
-
children: "Install"
|
|
549
|
+
children: r("conversations.admin.install", "Install")
|
|
560
550
|
})
|
|
561
551
|
]
|
|
562
552
|
}), E && /* @__PURE__ */ _("p", {
|
|
@@ -566,7 +556,7 @@ function B() {
|
|
|
566
556
|
}),
|
|
567
557
|
N && /* @__PURE__ */ _("p", {
|
|
568
558
|
className: "text-sm text-text-secondary",
|
|
569
|
-
children: "Loading app installations…"
|
|
559
|
+
children: r("conversations.admin.loadingAppInstallations", "Loading app installations…")
|
|
570
560
|
}),
|
|
571
561
|
P && /* @__PURE__ */ _("p", {
|
|
572
562
|
className: "text-sm text-status-error-text",
|
|
@@ -587,23 +577,18 @@ function B() {
|
|
|
587
577
|
className: "text-sm font-semibold text-text-primary",
|
|
588
578
|
children: e.appId
|
|
589
579
|
}), /* @__PURE__ */ _(I, { children: e.state })]
|
|
590
|
-
}), /* @__PURE__ */
|
|
580
|
+
}), /* @__PURE__ */ _("p", {
|
|
591
581
|
className: "text-xs text-text-secondary",
|
|
592
|
-
children:
|
|
593
|
-
|
|
594
|
-
e.
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
e.installedBy,
|
|
598
|
-
" on",
|
|
599
|
-
" ",
|
|
600
|
-
F(e.installedAt)
|
|
601
|
-
]
|
|
582
|
+
children: r("conversations.admin.appVersionMeta", "Version {{version}} · Installed by {{installedBy}} on {{installedAt}}", {
|
|
583
|
+
version: e.appVersion,
|
|
584
|
+
installedBy: e.installedBy,
|
|
585
|
+
installedAt: F(e.installedAt)
|
|
586
|
+
})
|
|
602
587
|
})]
|
|
603
588
|
}), /* @__PURE__ */ _(b, {
|
|
604
589
|
className: "shrink-0",
|
|
605
590
|
actions: [{
|
|
606
|
-
label: "Uninstall",
|
|
591
|
+
label: r("conversations.admin.uninstall", "Uninstall"),
|
|
607
592
|
intent: "destructive",
|
|
608
593
|
disabled: U,
|
|
609
594
|
icon: /* @__PURE__ */ _(p, {
|
|
@@ -611,19 +596,19 @@ function B() {
|
|
|
611
596
|
"aria-hidden": "true"
|
|
612
597
|
}),
|
|
613
598
|
onSelect: () => {
|
|
614
|
-
window.confirm(
|
|
599
|
+
window.confirm(r("conversations.admin.uninstallConfirm", "Uninstall {{appId}}? This removes the app and its settings from this workspace.", { appId: e.appId })) && H({ variables: { id: e.id } });
|
|
615
600
|
}
|
|
616
601
|
}]
|
|
617
602
|
})]
|
|
618
603
|
}), /* @__PURE__ */ _(C, {
|
|
619
604
|
className: "mt-3",
|
|
620
605
|
collapsedHeight: 0,
|
|
621
|
-
label: "Edit settings (JSON)",
|
|
606
|
+
label: r("conversations.admin.editSettingsJson", "Edit settings (JSON)"),
|
|
622
607
|
children: /* @__PURE__ */ v("div", {
|
|
623
608
|
className: "grid gap-2 pt-2",
|
|
624
609
|
children: [/* @__PURE__ */ _("textarea", {
|
|
625
610
|
rows: 5,
|
|
626
|
-
"aria-label":
|
|
611
|
+
"aria-label": r("conversations.admin.settingsForApp", "Settings for {{appId}}", { appId: e.appId }),
|
|
627
612
|
value: w[e.id] ?? "{}",
|
|
628
613
|
onChange: (t) => T((n) => ({
|
|
629
614
|
...n,
|
|
@@ -639,7 +624,7 @@ function B() {
|
|
|
639
624
|
onClick: () => {
|
|
640
625
|
let t = G(w[e.id] ?? "{}");
|
|
641
626
|
if (!t) {
|
|
642
|
-
D("Installation settings must be a valid JSON object.");
|
|
627
|
+
D(r("conversations.admin.settingsInvalidJson", "Installation settings must be a valid JSON object."));
|
|
643
628
|
return;
|
|
644
629
|
}
|
|
645
630
|
D(null), B({ variables: {
|
|
@@ -647,7 +632,7 @@ function B() {
|
|
|
647
632
|
settings: t
|
|
648
633
|
} });
|
|
649
634
|
},
|
|
650
|
-
children: "Save settings"
|
|
635
|
+
children: r("conversations.admin.saveSettings", "Save settings")
|
|
651
636
|
})]
|
|
652
637
|
})
|
|
653
638
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationAdminPages.js","names":[],"sources":["../../../src/conversations/pages/ConversationAdminPages.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from \"react\";\nimport { gql } from \"@apollo/client\";\nimport { useMutation, useQuery } from \"@apollo/client/react\";\nimport {\n Activity,\n Archive,\n CheckCircle2,\n Package,\n ShieldCheck,\n Trash2,\n} from \"lucide-react\";\n\nimport {\n Button,\n CTAOverflowMenu,\n GlassCard,\n PagePurpose,\n ShowMore,\n} from \"@burdenoff/fe-libs/ui\";\nimport { EmptyState, PageLayout, PageSection } from \"../components/PageLayout\";\nimport { useConversations } from \"../providers/ConversationsProvider\";\nimport { useTr } from \"../utils/i18n\";\n\nconst GET_MESSAGE_REPORTS = gql`\n query ConversationAdminMessageReports(\n $first: Int\n $filter: MessageReportFilter\n ) {\n messageReports(first: $first, filter: $filter) {\n edges {\n node {\n id\n messageId\n reportedBy\n reason\n status\n notes\n createdAt\n reviewedAt\n message {\n id\n conversationId\n authorId\n content\n isHidden\n createdAt\n }\n }\n }\n }\n }\n`;\n\nconst RESOLVE_MESSAGE_REPORT = gql`\n mutation ConversationAdminResolveMessageReport(\n $input: ResolveMessageReportInput!\n ) {\n resolveMessageReport(input: $input) {\n id\n status\n reviewedAt\n notes\n message {\n id\n isHidden\n }\n }\n }\n`;\n\nconst GET_BULK_CONVERSATIONS = gql`\n query ConversationAdminBulkConversations(\n $first: Int\n $filter: ConversationFilter\n ) {\n conversations(first: $first, filter: $filter) {\n edges {\n node {\n id\n title\n type\n state\n updatedAt\n }\n }\n }\n }\n`;\n\nconst BULK_UPDATE_CONVERSATIONS = gql`\n mutation ConversationAdminBulkUpdate(\n $input: BulkConversationOperationInput!\n ) {\n bulkUpdateConversations(input: $input) {\n success\n processedCount\n successCount\n failureCount\n conversationIds\n errors {\n conversationId\n message\n }\n }\n }\n`;\n\nconst GET_CONVERSATION_AUDIT_LOG = gql`\n query ConversationAdminAuditLog($filter: ActivityLogFilter) {\n getActivities(filter: $filter) {\n id\n action\n description\n resourceId\n resourceType\n userId\n timestamp\n }\n }\n`;\n\nconst GET_APP_INSTALLATIONS = gql`\n query ConversationAdminAppInstallations($workspaceId: ID) {\n appInstallations(workspaceId: $workspaceId) {\n id\n appId\n appVersion\n state\n settings\n permissions\n installedBy\n installedAt\n updatedAt\n }\n }\n`;\n\nconst INSTALL_APP = gql`\n mutation ConversationAdminInstallApp($input: InstallAppInput!) {\n installApp(input: $input) {\n id\n appId\n state\n settings\n installedAt\n }\n }\n`;\n\nconst UPDATE_APP_SETTINGS = gql`\n mutation ConversationAdminUpdateAppSettings($id: ID!, $settings: JSON!) {\n updateAppSettings(id: $id, settings: $settings) {\n id\n settings\n updatedAt\n }\n }\n`;\n\nconst UNINSTALL_APP = gql`\n mutation ConversationAdminUninstallApp($id: ID!) {\n uninstallApp(id: $id) {\n appInstallationId\n success\n }\n }\n`;\n\ninterface MessageReportNode {\n id: string;\n messageId: string;\n reportedBy: string;\n reason: string;\n status: string;\n notes?: string | null;\n createdAt: string;\n reviewedAt?: string | null;\n message: {\n id: string;\n conversationId: string;\n authorId: string;\n content: unknown;\n isHidden: boolean;\n createdAt: string;\n };\n}\n\ninterface ConversationNode {\n id: string;\n title?: string | null;\n type: string;\n state: string;\n updatedAt: string;\n}\n\ninterface ActivityLogNode {\n id: string;\n action: string;\n description?: string | null;\n resourceId?: string | null;\n resourceType?: string | null;\n userId: string;\n timestamp: string;\n}\n\ninterface AppInstallationNode {\n id: string;\n appId: string;\n appVersion: string;\n state: string;\n settings: unknown;\n permissions: string[];\n installedBy: string;\n installedAt: string;\n updatedAt: string;\n}\n\ninterface BulkUpdateConversationsResult {\n bulkUpdateConversations: {\n success: boolean;\n processedCount: number;\n successCount: number;\n failureCount: number;\n conversationIds: string[];\n errors: Array<{ conversationId: string; message: string }>;\n };\n}\n\nfunction formatContent(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (content && typeof content === \"object\" && \"text\" in content) {\n const text = (content as { text?: unknown }).text;\n if (typeof text === \"string\") return text;\n }\n try {\n return JSON.stringify(content);\n } catch {\n return \"Message content unavailable\";\n }\n}\n\nconst DATE_FORMATTER = new Intl.DateTimeFormat(undefined, {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n});\n\nfunction formatDate(value: string): string {\n return DATE_FORMATTER.format(new Date(value));\n}\n\nfunction StatusPill({ children }: { children: string }) {\n return (\n <span className=\"rounded-full border border-border-subtle bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\">\n {children}\n </span>\n );\n}\n\nexport function ModerationQueuePage() {\n const tr = useTr();\n const { workspaceId } = useConversations();\n const { data, loading, error, refetch } = useQuery<{\n messageReports: { edges: Array<{ node: MessageReportNode }> };\n }>(GET_MESSAGE_REPORTS, {\n variables: { first: 50, filter: { statuses: [\"PENDING\", \"REVIEWING\"] } },\n skip: !workspaceId,\n });\n const [resolveReport, { loading: resolving }] = useMutation(\n RESOLVE_MESSAGE_REPORT,\n {\n onCompleted: () => void refetch(),\n },\n );\n\n const reports = data?.messageReports.edges.map((edge) => edge.node) ?? [];\n\n return (\n <PageLayout\n title={tr(\"conversations.admin.moderationPageTitle\", \"Moderation queue\")}\n subtitle={tr(\n \"conversations.admin.moderationPageDescription\",\n \"Review reported messages and apply moderator decisions.\",\n )}\n icon={<ShieldCheck className=\"size-5\" aria-hidden=\"true\" />}\n maxWidth=\"2xl\"\n >\n <PagePurpose icon={<ShieldCheck className=\"size-4\" aria-hidden=\"true\" />}>\n {tr(\n \"conversations.admin.moderationPurpose\",\n \"Keep conversations safe: people can report messages they find abusive, spammy, or off-topic, and they land here for a moderator to hide the message or dismiss the report. Work the queue down to zero to stay on top of issues.\",\n )}\n </PagePurpose>\n {!workspaceId && (\n <EmptyState\n title={tr(\n \"conversations.admin.selectWorkspace\",\n \"Select a workspace\",\n )}\n description={tr(\n \"conversations.admin.selectWorkspaceModerationDescription\",\n \"Choose a workspace to review reported conversation messages.\",\n )}\n icon={<ShieldCheck className=\"size-6\" aria-hidden=\"true\" />}\n illustration=\"empty-generic\"\n />\n )}\n {workspaceId && loading && (\n <p className=\"text-sm text-text-secondary\">Loading reports…</p>\n )}\n {workspaceId && error && (\n <p className=\"text-sm text-status-error-text\">{error.message}</p>\n )}\n {workspaceId && !loading && !error && reports.length === 0 && (\n <EmptyState\n title=\"No reports waiting for review\"\n description=\"Reported messages will appear here as they are submitted.\"\n icon={<CheckCircle2 className=\"size-6\" aria-hidden=\"true\" />}\n illustration=\"empty-notifications\"\n />\n )}\n <div className=\"grid gap-3\">\n {reports.map((report) => (\n <GlassCard\n key={report.id}\n treatment=\"glass\"\n className=\"border-border-seam p-4\"\n >\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"space-y-2 min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusPill>{report.status}</StatusPill>\n {report.message.isHidden && <StatusPill>Hidden</StatusPill>}\n <span className=\"text-xs text-text-secondary\">\n Reported {formatDate(report.createdAt)}\n </span>\n </div>\n <p className=\"text-sm font-medium text-text-primary\">\n {report.reason}\n </p>\n <p className=\"rounded-md border border-border-seam bg-bg-sunken p-3 text-sm text-text-secondary\">\n {formatContent(report.message.content)}\n </p>\n <p className=\"text-xs text-text-secondary\">\n Message {report.messageId} in conversation{\" \"}\n {report.message.conversationId} by {report.message.authorId};\n reported by {report.reportedBy}\n </p>\n </div>\n {/* One primary CTA (hide + resolve), the secondary \"Dismiss\"\n collapses into the overflow menu. */}\n <CTAOverflowMenu\n className=\"shrink-0\"\n primary={{\n label: \"Hide and resolve\",\n disabled: resolving,\n onSelect: () =>\n void resolveReport({\n variables: {\n input: { reportId: report.id, action: \"HIDE_MESSAGE\" },\n },\n }),\n }}\n actions={[\n {\n label: \"Dismiss\",\n disabled: resolving,\n onSelect: () =>\n void resolveReport({\n variables: {\n input: { reportId: report.id, action: \"DISMISS\" },\n },\n }),\n },\n ]}\n />\n </div>\n </GlassCard>\n ))}\n </div>\n </PageLayout>\n );\n}\n\nexport function BulkOperationsPage() {\n const tr = useTr();\n const { workspaceId } = useConversations();\n const [selectedIds, setSelectedIds] = useState<Set<string>>(() => new Set());\n const [action, setAction] = useState<\"ARCHIVE\" | \"UNARCHIVE\" | \"DELETE\">(\n \"ARCHIVE\",\n );\n const { data, loading, error, refetch } = useQuery<{\n conversations: { edges: Array<{ node: ConversationNode }> };\n }>(GET_BULK_CONVERSATIONS, {\n variables: { first: 100 },\n skip: !workspaceId,\n });\n const [bulkUpdate, { data: bulkResult, loading: updating }] = useMutation<\n BulkUpdateConversationsResult,\n { input: { conversationIds: string[]; action: typeof action } }\n >(BULK_UPDATE_CONVERSATIONS, {\n onCompleted: () => {\n setSelectedIds(new Set());\n void refetch();\n },\n });\n const conversations =\n data?.conversations.edges.map((edge) => edge.node) ?? [];\n\n const toggle = (id: string) => {\n setSelectedIds((current) => {\n const next = new Set(current);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n };\n\n return (\n <PageLayout\n title={tr(\n \"conversations.admin.bulkOperationsPageTitle\",\n \"Bulk operations\",\n )}\n subtitle={tr(\n \"conversations.admin.bulkOperationsPageDescription\",\n \"Select workspace conversations and apply archive, unarchive, or delete operations.\",\n )}\n icon={<Archive className=\"size-5\" aria-hidden=\"true\" />}\n maxWidth=\"2xl\"\n headerActions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <select\n value={action}\n onChange={(event) => setAction(event.target.value as typeof action)}\n aria-label=\"Bulk action\"\n className=\"min-h-11 rounded-md border border-border-seam bg-bg-surface px-3 py-2 text-sm text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"ARCHIVE\">Archive</option>\n <option value=\"UNARCHIVE\">Unarchive</option>\n <option value=\"DELETE\">Delete</option>\n </select>\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={selectedIds.size === 0 || updating}\n onClick={() =>\n void bulkUpdate({\n variables: {\n input: { conversationIds: Array.from(selectedIds), action },\n },\n })\n }\n >\n Apply to {selectedIds.size}\n </Button>\n </div>\n }\n >\n <PagePurpose icon={<Archive className=\"size-4\" aria-hidden=\"true\" />}>\n {tr(\n \"conversations.admin.bulkPurpose\",\n \"Clean up at scale instead of one conversation at a time — select many conversations, then archive them to declutter inboxes, unarchive to restore, or delete the ones you no longer need. Handy for closing out finished projects or removing test threads.\",\n )}\n </PagePurpose>\n {!workspaceId && (\n <EmptyState\n title={tr(\n \"conversations.admin.selectWorkspace\",\n \"Select a workspace\",\n )}\n description={tr(\n \"conversations.admin.selectWorkspaceBulkDescription\",\n \"Choose a workspace to manage conversations in bulk.\",\n )}\n icon={<Archive className=\"size-6\" aria-hidden=\"true\" />}\n illustration=\"empty-generic\"\n />\n )}\n {workspaceId && loading && (\n <p className=\"text-sm text-text-secondary\">Loading conversations…</p>\n )}\n {workspaceId && error && (\n <p className=\"text-sm text-status-error-text\">{error.message}</p>\n )}\n {bulkResult?.bulkUpdateConversations && (\n <GlassCard\n treatment=\"metric\"\n glow\n className=\"grid grid-cols-2 gap-4 border-border-seam p-4 sm:max-w-md\"\n >\n <div>\n <p className=\"text-2xl font-semibold tabular-nums text-status-success-text\">\n {bulkResult.bulkUpdateConversations.successCount}\n </p>\n <p className=\"text-xs text-text-secondary\">Succeeded</p>\n </div>\n <div>\n <p className=\"text-2xl font-semibold tabular-nums text-text-primary\">\n {bulkResult.bulkUpdateConversations.failureCount}\n </p>\n <p className=\"text-xs text-text-secondary\">Failed</p>\n </div>\n </GlassCard>\n )}\n {workspaceId && (\n <div className=\"overflow-hidden rounded-lg border border-border-seam bg-bg-surface\">\n {conversations.map((conversation) => (\n <label\n key={conversation.id}\n className=\"flex min-h-11 cursor-pointer items-center gap-3 border-b border-border-seam px-4 py-3 last:border-b-0 hover:bg-accent\"\n >\n <input\n type=\"checkbox\"\n aria-label={`Select ${conversation.title || \"untitled conversation\"}`}\n checked={selectedIds.has(conversation.id)}\n onChange={() => toggle(conversation.id)}\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {conversation.title || \"Untitled conversation\"}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {conversation.type} · {conversation.state} · Updated{\" \"}\n {formatDate(conversation.updatedAt)}\n </p>\n </div>\n </label>\n ))}\n </div>\n )}\n </PageLayout>\n );\n}\n\nexport function ConversationAuditLogPage() {\n const tr = useTr();\n const { workspaceId } = useConversations();\n const { data, loading, error } = useQuery<{\n getActivities: ActivityLogNode[];\n }>(GET_CONVERSATION_AUDIT_LOG, {\n variables: {\n filter: { workspaceId, resourceType: \"conversation\", limit: 50 },\n },\n skip: !workspaceId,\n });\n const logs = data?.getActivities ?? [];\n\n return (\n <PageLayout\n title={tr(\"conversations.admin.auditLogPageTitle\", \"Audit log\")}\n subtitle={tr(\n \"conversations.admin.auditLogPageDescription\",\n \"Activity stream for admin and moderator actions on workspace conversations.\",\n )}\n icon={<Activity className=\"size-5\" aria-hidden=\"true\" />}\n maxWidth=\"2xl\"\n >\n <PagePurpose icon={<Activity className=\"size-4\" aria-hidden=\"true\" />}>\n {tr(\n \"conversations.admin.auditPurpose\",\n \"An accountability trail of who changed what — every admin and moderator action on workspace conversations is recorded here. Use it to investigate an incident, confirm a change was made, or satisfy a compliance review.\",\n )}\n </PagePurpose>\n {loading && (\n <p className=\"text-sm text-text-secondary\">Loading activity…</p>\n )}\n {error && (\n <p className=\"text-sm text-status-error-text\">{error.message}</p>\n )}\n {!loading && !error && logs.length === 0 && (\n <EmptyState\n title=\"No activity found\"\n description=\"Conversation admin actions will appear here.\"\n illustration=\"empty-data\"\n />\n )}\n <div className=\"grid gap-3\">\n {logs.map((log) => (\n <GlassCard\n key={log.id}\n treatment=\"plain\"\n className=\"border-border-seam p-4\"\n >\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <p className=\"text-sm font-medium text-text-primary\">\n {log.action}\n </p>\n <span className=\"text-xs tabular-nums text-text-secondary\">\n {formatDate(log.timestamp)}\n </span>\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {log.description || \"No description provided\"}\n </p>\n <p className=\"mt-2 text-xs text-text-secondary\">\n User {log.userId} · Resource {log.resourceId ?? \"workspace\"}\n </p>\n </GlassCard>\n ))}\n </div>\n </PageLayout>\n );\n}\n\nexport function AppInstallationsPage() {\n const tr = useTr();\n const { workspaceId } = useConversations();\n const [appId, setAppId] = useState(\"\");\n const [settingsInput, setSettingsInput] = useState(\"{}\");\n const [settingsDrafts, setSettingsDrafts] = useState<Record<string, string>>(\n {},\n );\n const [formError, setFormError] = useState<string | null>(null);\n const { data, loading, error, refetch } = useQuery<{\n appInstallations: AppInstallationNode[];\n }>(GET_APP_INSTALLATIONS, {\n variables: { workspaceId },\n skip: !workspaceId,\n });\n const [installApp, { loading: installing }] = useMutation(INSTALL_APP, {\n onCompleted: () => void refetch(),\n });\n const [updateSettings, { loading: saving }] = useMutation(\n UPDATE_APP_SETTINGS,\n { onCompleted: () => void refetch() },\n );\n const [uninstallApp, { loading: uninstalling }] = useMutation(UNINSTALL_APP, {\n onCompleted: () => void refetch(),\n });\n const installations = useMemo(\n () => data?.appInstallations ?? [],\n [data?.appInstallations],\n );\n\n useEffect(() => {\n setSettingsDrafts((current) => {\n if (installations.every((installation) => current[installation.id])) {\n return current;\n }\n const next = { ...current };\n for (const installation of installations) {\n if (!next[installation.id]) {\n next[installation.id] = JSON.stringify(\n installation.settings ?? {},\n null,\n 2,\n );\n }\n }\n return next;\n });\n }, [installations]);\n\n const parsedSettings = (raw: string): Record<string, unknown> | null => {\n try {\n const parsed = JSON.parse(raw) as unknown;\n return parsed && typeof parsed === \"object\" && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : null;\n } catch {\n return null;\n }\n };\n\n const handleInstall = () => {\n const settings = parsedSettings(settingsInput);\n if (!appId.trim() || !settings) {\n setFormError(\"Enter an app ID and a valid JSON settings object.\");\n return;\n }\n setFormError(null);\n void installApp({\n variables: { input: { appId: appId.trim(), workspaceId, settings } },\n });\n };\n\n return (\n <PageLayout\n title={tr(\n \"conversations.admin.appInstallationsPageTitle\",\n \"App installations\",\n )}\n subtitle={tr(\n \"conversations.admin.appInstallationsPageDescription\",\n \"Install, configure, and remove conversation apps and integrations.\",\n )}\n icon={<Package className=\"size-5\" aria-hidden=\"true\" />}\n maxWidth=\"2xl\"\n >\n <PagePurpose icon={<Package className=\"size-4\" aria-hidden=\"true\" />}>\n {tr(\n \"conversations.admin.appsPurpose\",\n \"Extend conversations with apps and integrations — install bots, automations, or third-party connectors scoped to this workspace, adjust their settings, and remove the ones you no longer use.\",\n )}\n </PagePurpose>\n <PageSection\n title=\"Install app\"\n description=\"Install a workspace-scoped conversation app by app ID.\"\n >\n {/* The single emphasis zone on this page — installing a new app is the\n primary action an admin takes here. */}\n <GlassCard\n treatment=\"glass\"\n glow\n className=\"grid gap-3 border-border-seam p-4 sm:grid-cols-[minmax(0,1fr)_minmax(0,2fr)_auto]\"\n >\n <input\n value={appId}\n onChange={(event) => setAppId(event.target.value)}\n placeholder=\"app-id\"\n aria-label=\"App ID\"\n className=\"min-h-11 rounded-md border border-border-seam bg-bg-surface px-3 py-2 text-sm text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n />\n <textarea\n value={settingsInput}\n onChange={(event) => setSettingsInput(event.target.value)}\n rows={3}\n aria-label=\"App settings JSON\"\n className=\"rounded-md border border-border-seam bg-bg-surface px-3 py-2 text-sm text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n />\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={installing}\n onClick={handleInstall}\n >\n Install\n </Button>\n </GlassCard>\n {formError && (\n <p className=\"text-sm text-status-error-text\">{formError}</p>\n )}\n </PageSection>\n {loading && (\n <p className=\"text-sm text-text-secondary\">\n Loading app installations…\n </p>\n )}\n {error && (\n <p className=\"text-sm text-status-error-text\">{error.message}</p>\n )}\n <div className=\"grid gap-3\">\n {installations.map((installation) => (\n <GlassCard\n key={installation.id}\n treatment=\"glass\"\n className=\"border-border-seam p-4\"\n >\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {installation.appId}\n </h3>\n <StatusPill>{installation.state}</StatusPill>\n </div>\n <p className=\"text-xs text-text-secondary\">\n Version {installation.appVersion} · Installed by{\" \"}\n {installation.installedBy} on{\" \"}\n {formatDate(installation.installedAt)}\n </p>\n </div>\n {/* Destructive uninstall lives behind the overflow menu and\n asks for confirmation before firing the mutation. */}\n <CTAOverflowMenu\n className=\"shrink-0\"\n actions={[\n {\n label: \"Uninstall\",\n intent: \"destructive\",\n disabled: uninstalling,\n icon: <Trash2 className=\"size-4\" aria-hidden=\"true\" />,\n onSelect: () => {\n if (\n !window.confirm(\n `Uninstall ${installation.appId}? This removes the app and its settings from this workspace.`,\n )\n ) {\n return;\n }\n void uninstallApp({\n variables: { id: installation.id },\n });\n },\n },\n ]}\n />\n </div>\n {/* The raw JSON settings editor is an advanced surface — collapse\n it behind progressive disclosure so the card stays calm. */}\n <ShowMore\n className=\"mt-3\"\n collapsedHeight={0}\n label=\"Edit settings (JSON)\"\n >\n <div className=\"grid gap-2 pt-2\">\n <textarea\n rows={5}\n aria-label={`Settings for ${installation.appId}`}\n value={settingsDrafts[installation.id] ?? \"{}\"}\n onChange={(event) =>\n setSettingsDrafts((current) => ({\n ...current,\n [installation.id]: event.target.value,\n }))\n }\n className=\"rounded-md border border-border-seam bg-bg-surface px-3 py-2 font-mono text-xs text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n />\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n disabled={saving}\n className=\"w-fit\"\n onClick={() => {\n const settings = parsedSettings(\n settingsDrafts[installation.id] ?? \"{}\",\n );\n if (!settings) {\n setFormError(\n \"Installation settings must be a valid JSON object.\",\n );\n return;\n }\n setFormError(null);\n void updateSettings({\n variables: { id: installation.id, settings },\n });\n }}\n >\n Save settings\n </Button>\n </div>\n </ShowMore>\n </GlassCard>\n ))}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ConversationAdminPages.js","names":[],"sources":["../../../src/conversations/pages/ConversationAdminPages.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from \"react\";\nimport { gql } from \"@apollo/client\";\nimport { useMutation, useQuery } from \"@apollo/client/react\";\nimport {\n Activity,\n Archive,\n CheckCircle2,\n Package,\n ShieldCheck,\n Trash2,\n} from \"lucide-react\";\n\nimport {\n Button,\n CTAOverflowMenu,\n GlassCard,\n PagePurpose,\n ShowMore,\n} from \"@burdenoff/fe-libs/ui\";\nimport { EmptyState, PageLayout, PageSection } from \"../components/PageLayout\";\nimport { useConversations } from \"../providers/ConversationsProvider\";\nimport { useTr } from \"../utils/i18n\";\n\nconst GET_MESSAGE_REPORTS = gql`\n query ConversationAdminMessageReports(\n $first: Int\n $filter: MessageReportFilter\n ) {\n messageReports(first: $first, filter: $filter) {\n edges {\n node {\n id\n messageId\n reportedBy\n reason\n status\n notes\n createdAt\n reviewedAt\n message {\n id\n conversationId\n authorId\n content\n isHidden\n createdAt\n }\n }\n }\n }\n }\n`;\n\nconst RESOLVE_MESSAGE_REPORT = gql`\n mutation ConversationAdminResolveMessageReport(\n $input: ResolveMessageReportInput!\n ) {\n resolveMessageReport(input: $input) {\n id\n status\n reviewedAt\n notes\n message {\n id\n isHidden\n }\n }\n }\n`;\n\nconst GET_BULK_CONVERSATIONS = gql`\n query ConversationAdminBulkConversations(\n $first: Int\n $filter: ConversationFilter\n ) {\n conversations(first: $first, filter: $filter) {\n edges {\n node {\n id\n title\n type\n state\n updatedAt\n }\n }\n }\n }\n`;\n\nconst BULK_UPDATE_CONVERSATIONS = gql`\n mutation ConversationAdminBulkUpdate(\n $input: BulkConversationOperationInput!\n ) {\n bulkUpdateConversations(input: $input) {\n success\n processedCount\n successCount\n failureCount\n conversationIds\n errors {\n conversationId\n message\n }\n }\n }\n`;\n\nconst GET_CONVERSATION_AUDIT_LOG = gql`\n query ConversationAdminAuditLog($filter: ActivityLogFilter) {\n getActivities(filter: $filter) {\n id\n action\n description\n resourceId\n resourceType\n userId\n timestamp\n }\n }\n`;\n\nconst GET_APP_INSTALLATIONS = gql`\n query ConversationAdminAppInstallations($workspaceId: ID) {\n appInstallations(workspaceId: $workspaceId) {\n id\n appId\n appVersion\n state\n settings\n permissions\n installedBy\n installedAt\n updatedAt\n }\n }\n`;\n\nconst INSTALL_APP = gql`\n mutation ConversationAdminInstallApp($input: InstallAppInput!) {\n installApp(input: $input) {\n id\n appId\n state\n settings\n installedAt\n }\n }\n`;\n\nconst UPDATE_APP_SETTINGS = gql`\n mutation ConversationAdminUpdateAppSettings($id: ID!, $settings: JSON!) {\n updateAppSettings(id: $id, settings: $settings) {\n id\n settings\n updatedAt\n }\n }\n`;\n\nconst UNINSTALL_APP = gql`\n mutation ConversationAdminUninstallApp($id: ID!) {\n uninstallApp(id: $id) {\n appInstallationId\n success\n }\n }\n`;\n\ninterface MessageReportNode {\n id: string;\n messageId: string;\n reportedBy: string;\n reason: string;\n status: string;\n notes?: string | null;\n createdAt: string;\n reviewedAt?: string | null;\n message: {\n id: string;\n conversationId: string;\n authorId: string;\n content: unknown;\n isHidden: boolean;\n createdAt: string;\n };\n}\n\ninterface ConversationNode {\n id: string;\n title?: string | null;\n type: string;\n state: string;\n updatedAt: string;\n}\n\ninterface ActivityLogNode {\n id: string;\n action: string;\n description?: string | null;\n resourceId?: string | null;\n resourceType?: string | null;\n userId: string;\n timestamp: string;\n}\n\ninterface AppInstallationNode {\n id: string;\n appId: string;\n appVersion: string;\n state: string;\n settings: unknown;\n permissions: string[];\n installedBy: string;\n installedAt: string;\n updatedAt: string;\n}\n\ninterface BulkUpdateConversationsResult {\n bulkUpdateConversations: {\n success: boolean;\n processedCount: number;\n successCount: number;\n failureCount: number;\n conversationIds: string[];\n errors: Array<{ conversationId: string; message: string }>;\n };\n}\n\nfunction formatContent(content: unknown, fallback: string): string {\n if (typeof content === \"string\") return content;\n if (content && typeof content === \"object\" && \"text\" in content) {\n const text = (content as { text?: unknown }).text;\n if (typeof text === \"string\") return text;\n }\n try {\n return JSON.stringify(content);\n } catch {\n return fallback;\n }\n}\n\nconst DATE_FORMATTER = new Intl.DateTimeFormat(undefined, {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n});\n\nfunction formatDate(value: string): string {\n return DATE_FORMATTER.format(new Date(value));\n}\n\nfunction StatusPill({ children }: { children: string }) {\n return (\n <span className=\"rounded-full border border-border-subtle bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\">\n {children}\n </span>\n );\n}\n\nexport function ModerationQueuePage() {\n const tr = useTr();\n const { workspaceId } = useConversations();\n const { data, loading, error, refetch } = useQuery<{\n messageReports: { edges: Array<{ node: MessageReportNode }> };\n }>(GET_MESSAGE_REPORTS, {\n variables: { first: 50, filter: { statuses: [\"PENDING\", \"REVIEWING\"] } },\n skip: !workspaceId,\n });\n const [resolveReport, { loading: resolving }] = useMutation(\n RESOLVE_MESSAGE_REPORT,\n {\n onCompleted: () => void refetch(),\n },\n );\n\n const reports = data?.messageReports.edges.map((edge) => edge.node) ?? [];\n\n return (\n <PageLayout\n title={tr(\"conversations.admin.moderationPageTitle\", \"Moderation queue\")}\n subtitle={tr(\n \"conversations.admin.moderationPageDescription\",\n \"Review reported messages and apply moderator decisions.\",\n )}\n icon={<ShieldCheck className=\"size-5\" aria-hidden=\"true\" />}\n maxWidth=\"2xl\"\n >\n <PagePurpose icon={<ShieldCheck className=\"size-4\" aria-hidden=\"true\" />}>\n {tr(\n \"conversations.admin.moderationPurpose\",\n \"Keep conversations safe: people can report messages they find abusive, spammy, or off-topic, and they land here for a moderator to hide the message or dismiss the report. Work the queue down to zero to stay on top of issues.\",\n )}\n </PagePurpose>\n {!workspaceId && (\n <EmptyState\n title={tr(\n \"conversations.admin.selectWorkspace\",\n \"Select a workspace\",\n )}\n description={tr(\n \"conversations.admin.selectWorkspaceModerationDescription\",\n \"Choose a workspace to review reported conversation messages.\",\n )}\n icon={<ShieldCheck className=\"size-6\" aria-hidden=\"true\" />}\n illustration=\"empty-generic\"\n />\n )}\n {workspaceId && loading && (\n <p className=\"text-sm text-text-secondary\">\n {tr(\"conversations.admin.loadingReports\", \"Loading reports…\")}\n </p>\n )}\n {workspaceId && error && (\n <p className=\"text-sm text-status-error-text\">{error.message}</p>\n )}\n {workspaceId && !loading && !error && reports.length === 0 && (\n <EmptyState\n title={tr(\n \"conversations.admin.noReportsTitle\",\n \"No reports waiting for review\",\n )}\n description={tr(\n \"conversations.admin.noReportsDescription\",\n \"Reported messages will appear here as they are submitted.\",\n )}\n icon={<CheckCircle2 className=\"size-6\" aria-hidden=\"true\" />}\n illustration=\"empty-notifications\"\n />\n )}\n <div className=\"grid gap-3\">\n {reports.map((report) => (\n <GlassCard\n key={report.id}\n treatment=\"glass\"\n className=\"border-border-seam p-4\"\n >\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"space-y-2 min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <StatusPill>{report.status}</StatusPill>\n {report.message.isHidden && (\n <StatusPill>\n {tr(\"conversations.admin.hidden\", \"Hidden\")}\n </StatusPill>\n )}\n <span className=\"text-xs text-text-secondary\">\n {tr(\"conversations.admin.reportedAt\", \"Reported {{date}}\", {\n date: formatDate(report.createdAt),\n })}\n </span>\n </div>\n <p className=\"text-sm font-medium text-text-primary\">\n {report.reason}\n </p>\n <p className=\"rounded-md border border-border-seam bg-bg-sunken p-3 text-sm text-text-secondary\">\n {formatContent(\n report.message.content,\n tr(\n \"conversations.admin.messageContentUnavailable\",\n \"Message content unavailable\",\n ),\n )}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {tr(\n \"conversations.admin.reportMeta\",\n \"Message {{messageId}} in conversation {{conversationId}} by {{authorId}}; reported by {{reportedBy}}\",\n {\n messageId: report.messageId,\n conversationId: report.message.conversationId,\n authorId: report.message.authorId,\n reportedBy: report.reportedBy,\n },\n )}\n </p>\n </div>\n {/* One primary CTA (hide + resolve), the secondary \"Dismiss\"\n collapses into the overflow menu. */}\n <CTAOverflowMenu\n className=\"shrink-0\"\n primary={{\n label: tr(\n \"conversations.admin.hideAndResolve\",\n \"Hide and resolve\",\n ),\n disabled: resolving,\n onSelect: () =>\n void resolveReport({\n variables: {\n input: { reportId: report.id, action: \"HIDE_MESSAGE\" },\n },\n }),\n }}\n actions={[\n {\n label: tr(\"conversations.admin.dismiss\", \"Dismiss\"),\n disabled: resolving,\n onSelect: () =>\n void resolveReport({\n variables: {\n input: { reportId: report.id, action: \"DISMISS\" },\n },\n }),\n },\n ]}\n />\n </div>\n </GlassCard>\n ))}\n </div>\n </PageLayout>\n );\n}\n\nexport function BulkOperationsPage() {\n const tr = useTr();\n const { workspaceId } = useConversations();\n const [selectedIds, setSelectedIds] = useState<Set<string>>(() => new Set());\n const [action, setAction] = useState<\"ARCHIVE\" | \"UNARCHIVE\" | \"DELETE\">(\n \"ARCHIVE\",\n );\n const { data, loading, error, refetch } = useQuery<{\n conversations: { edges: Array<{ node: ConversationNode }> };\n }>(GET_BULK_CONVERSATIONS, {\n variables: { first: 100 },\n skip: !workspaceId,\n });\n const [bulkUpdate, { data: bulkResult, loading: updating }] = useMutation<\n BulkUpdateConversationsResult,\n { input: { conversationIds: string[]; action: typeof action } }\n >(BULK_UPDATE_CONVERSATIONS, {\n onCompleted: () => {\n setSelectedIds(new Set());\n void refetch();\n },\n });\n const conversations =\n data?.conversations.edges.map((edge) => edge.node) ?? [];\n\n const toggle = (id: string) => {\n setSelectedIds((current) => {\n const next = new Set(current);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n };\n\n return (\n <PageLayout\n title={tr(\n \"conversations.admin.bulkOperationsPageTitle\",\n \"Bulk operations\",\n )}\n subtitle={tr(\n \"conversations.admin.bulkOperationsPageDescription\",\n \"Select workspace conversations and apply archive, unarchive, or delete operations.\",\n )}\n icon={<Archive className=\"size-5\" aria-hidden=\"true\" />}\n maxWidth=\"2xl\"\n headerActions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <select\n value={action}\n onChange={(event) => setAction(event.target.value as typeof action)}\n aria-label={tr(\"conversations.admin.bulkAction\", \"Bulk action\")}\n className=\"min-h-11 rounded-md border border-border-seam bg-bg-surface px-3 py-2 text-sm text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"ARCHIVE\">\n {tr(\"conversations.archive\", \"Archive\")}\n </option>\n <option value=\"UNARCHIVE\">\n {tr(\"conversations.unarchive\", \"Unarchive\")}\n </option>\n <option value=\"DELETE\">\n {tr(\"conversations.delete\", \"Delete\")}\n </option>\n </select>\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={selectedIds.size === 0 || updating}\n onClick={() =>\n void bulkUpdate({\n variables: {\n input: { conversationIds: Array.from(selectedIds), action },\n },\n })\n }\n >\n {tr(\"conversations.admin.applyToCount\", \"Apply to {{count}}\", {\n count: selectedIds.size,\n })}\n </Button>\n </div>\n }\n >\n <PagePurpose icon={<Archive className=\"size-4\" aria-hidden=\"true\" />}>\n {tr(\n \"conversations.admin.bulkPurpose\",\n \"Clean up at scale instead of one conversation at a time — select many conversations, then archive them to declutter inboxes, unarchive to restore, or delete the ones you no longer need. Handy for closing out finished projects or removing test threads.\",\n )}\n </PagePurpose>\n {!workspaceId && (\n <EmptyState\n title={tr(\n \"conversations.admin.selectWorkspace\",\n \"Select a workspace\",\n )}\n description={tr(\n \"conversations.admin.selectWorkspaceBulkDescription\",\n \"Choose a workspace to manage conversations in bulk.\",\n )}\n icon={<Archive className=\"size-6\" aria-hidden=\"true\" />}\n illustration=\"empty-generic\"\n />\n )}\n {workspaceId && loading && (\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"conversations.admin.loadingConversations\",\n \"Loading conversations…\",\n )}\n </p>\n )}\n {workspaceId && error && (\n <p className=\"text-sm text-status-error-text\">{error.message}</p>\n )}\n {bulkResult?.bulkUpdateConversations && (\n <GlassCard\n treatment=\"metric\"\n glow\n className=\"grid grid-cols-2 gap-4 border-border-seam p-4 sm:max-w-md\"\n >\n <div>\n <p className=\"text-2xl font-semibold tabular-nums text-status-success-text\">\n {bulkResult.bulkUpdateConversations.successCount}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {tr(\"conversations.admin.succeeded\", \"Succeeded\")}\n </p>\n </div>\n <div>\n <p className=\"text-2xl font-semibold tabular-nums text-text-primary\">\n {bulkResult.bulkUpdateConversations.failureCount}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {tr(\"conversations.admin.failed\", \"Failed\")}\n </p>\n </div>\n </GlassCard>\n )}\n {workspaceId && (\n <div className=\"overflow-hidden rounded-lg border border-border-seam bg-bg-surface\">\n {conversations.map((conversation) => (\n <label\n key={conversation.id}\n className=\"flex min-h-11 cursor-pointer items-center gap-3 border-b border-border-seam px-4 py-3 last:border-b-0 hover:bg-accent\"\n >\n <input\n type=\"checkbox\"\n aria-label={tr(\n \"conversations.admin.selectConversationAria\",\n \"Select {{title}}\",\n {\n title:\n conversation.title ||\n tr(\n \"conversations.admin.untitledConversation\",\n \"Untitled conversation\",\n ),\n },\n )}\n checked={selectedIds.has(conversation.id)}\n onChange={() => toggle(conversation.id)}\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {conversation.title ||\n tr(\n \"conversations.admin.untitledConversation\",\n \"Untitled conversation\",\n )}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {tr(\n \"conversations.admin.conversationMeta\",\n \"{{type}} · {{state}} · Updated {{date}}\",\n {\n type: conversation.type,\n state: conversation.state,\n date: formatDate(conversation.updatedAt),\n },\n )}\n </p>\n </div>\n </label>\n ))}\n </div>\n )}\n </PageLayout>\n );\n}\n\nexport function ConversationAuditLogPage() {\n const tr = useTr();\n const { workspaceId } = useConversations();\n const { data, loading, error } = useQuery<{\n getActivities: ActivityLogNode[];\n }>(GET_CONVERSATION_AUDIT_LOG, {\n variables: {\n filter: { workspaceId, resourceType: \"conversation\", limit: 50 },\n },\n skip: !workspaceId,\n });\n const logs = data?.getActivities ?? [];\n\n return (\n <PageLayout\n title={tr(\"conversations.admin.auditLogPageTitle\", \"Audit log\")}\n subtitle={tr(\n \"conversations.admin.auditLogPageDescription\",\n \"Activity stream for admin and moderator actions on workspace conversations.\",\n )}\n icon={<Activity className=\"size-5\" aria-hidden=\"true\" />}\n maxWidth=\"2xl\"\n >\n <PagePurpose icon={<Activity className=\"size-4\" aria-hidden=\"true\" />}>\n {tr(\n \"conversations.admin.auditPurpose\",\n \"An accountability trail of who changed what — every admin and moderator action on workspace conversations is recorded here. Use it to investigate an incident, confirm a change was made, or satisfy a compliance review.\",\n )}\n </PagePurpose>\n {loading && (\n <p className=\"text-sm text-text-secondary\">\n {tr(\"conversations.admin.loadingActivity\", \"Loading activity…\")}\n </p>\n )}\n {error && (\n <p className=\"text-sm text-status-error-text\">{error.message}</p>\n )}\n {!loading && !error && logs.length === 0 && (\n <EmptyState\n title={tr(\"conversations.admin.noActivityTitle\", \"No activity found\")}\n description={tr(\n \"conversations.admin.noActivityDescription\",\n \"Conversation admin actions will appear here.\",\n )}\n illustration=\"empty-data\"\n />\n )}\n <div className=\"grid gap-3\">\n {logs.map((log) => (\n <GlassCard\n key={log.id}\n treatment=\"plain\"\n className=\"border-border-seam p-4\"\n >\n <div className=\"flex flex-wrap items-center justify-between gap-2\">\n <p className=\"text-sm font-medium text-text-primary\">\n {log.action}\n </p>\n <span className=\"text-xs tabular-nums text-text-secondary\">\n {formatDate(log.timestamp)}\n </span>\n </div>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {log.description ||\n tr(\n \"conversations.admin.noDescription\",\n \"No description provided\",\n )}\n </p>\n <p className=\"mt-2 text-xs text-text-secondary\">\n {tr(\n \"conversations.admin.auditMeta\",\n \"User {{userId}} · Resource {{resourceId}}\",\n {\n userId: log.userId,\n resourceId:\n log.resourceId ??\n tr(\"conversations.admin.workspaceResource\", \"workspace\"),\n },\n )}\n </p>\n </GlassCard>\n ))}\n </div>\n </PageLayout>\n );\n}\n\nexport function AppInstallationsPage() {\n const tr = useTr();\n const { workspaceId } = useConversations();\n const [appId, setAppId] = useState(\"\");\n const [settingsInput, setSettingsInput] = useState(\"{}\");\n const [settingsDrafts, setSettingsDrafts] = useState<Record<string, string>>(\n {},\n );\n const [formError, setFormError] = useState<string | null>(null);\n const { data, loading, error, refetch } = useQuery<{\n appInstallations: AppInstallationNode[];\n }>(GET_APP_INSTALLATIONS, {\n variables: { workspaceId },\n skip: !workspaceId,\n });\n const [installApp, { loading: installing }] = useMutation(INSTALL_APP, {\n onCompleted: () => void refetch(),\n });\n const [updateSettings, { loading: saving }] = useMutation(\n UPDATE_APP_SETTINGS,\n { onCompleted: () => void refetch() },\n );\n const [uninstallApp, { loading: uninstalling }] = useMutation(UNINSTALL_APP, {\n onCompleted: () => void refetch(),\n });\n const installations = useMemo(\n () => data?.appInstallations ?? [],\n [data?.appInstallations],\n );\n\n useEffect(() => {\n setSettingsDrafts((current) => {\n if (installations.every((installation) => current[installation.id])) {\n return current;\n }\n const next = { ...current };\n for (const installation of installations) {\n if (!next[installation.id]) {\n next[installation.id] = JSON.stringify(\n installation.settings ?? {},\n null,\n 2,\n );\n }\n }\n return next;\n });\n }, [installations]);\n\n const parsedSettings = (raw: string): Record<string, unknown> | null => {\n try {\n const parsed = JSON.parse(raw) as unknown;\n return parsed && typeof parsed === \"object\" && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : null;\n } catch {\n return null;\n }\n };\n\n const handleInstall = () => {\n const settings = parsedSettings(settingsInput);\n if (!appId.trim() || !settings) {\n setFormError(\n tr(\n \"conversations.admin.installAppError\",\n \"Enter an app ID and a valid JSON settings object.\",\n ),\n );\n return;\n }\n setFormError(null);\n void installApp({\n variables: { input: { appId: appId.trim(), workspaceId, settings } },\n });\n };\n\n return (\n <PageLayout\n title={tr(\n \"conversations.admin.appInstallationsPageTitle\",\n \"App installations\",\n )}\n subtitle={tr(\n \"conversations.admin.appInstallationsPageDescription\",\n \"Install, configure, and remove conversation apps and integrations.\",\n )}\n icon={<Package className=\"size-5\" aria-hidden=\"true\" />}\n maxWidth=\"2xl\"\n >\n <PagePurpose icon={<Package className=\"size-4\" aria-hidden=\"true\" />}>\n {tr(\n \"conversations.admin.appsPurpose\",\n \"Extend conversations with apps and integrations — install bots, automations, or third-party connectors scoped to this workspace, adjust their settings, and remove the ones you no longer use.\",\n )}\n </PagePurpose>\n <PageSection\n title={tr(\"conversations.admin.installApp\", \"Install app\")}\n description={tr(\n \"conversations.admin.installAppDescription\",\n \"Install a workspace-scoped conversation app by app ID.\",\n )}\n >\n {/* The single emphasis zone on this page — installing a new app is the\n primary action an admin takes here. */}\n <GlassCard\n treatment=\"glass\"\n glow\n className=\"grid gap-3 border-border-seam p-4 sm:grid-cols-[minmax(0,1fr)_minmax(0,2fr)_auto]\"\n >\n <input\n value={appId}\n onChange={(event) => setAppId(event.target.value)}\n placeholder={tr(\"conversations.admin.appIdPlaceholder\", \"app-id\")}\n aria-label={tr(\"conversations.admin.appId\", \"App ID\")}\n className=\"min-h-11 rounded-md border border-border-seam bg-bg-surface px-3 py-2 text-sm text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n />\n <textarea\n value={settingsInput}\n onChange={(event) => setSettingsInput(event.target.value)}\n rows={3}\n aria-label={tr(\n \"conversations.admin.appSettingsJson\",\n \"App settings JSON\",\n )}\n className=\"rounded-md border border-border-seam bg-bg-surface px-3 py-2 text-sm text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n />\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={installing}\n onClick={handleInstall}\n >\n {tr(\"conversations.admin.install\", \"Install\")}\n </Button>\n </GlassCard>\n {formError && (\n <p className=\"text-sm text-status-error-text\">{formError}</p>\n )}\n </PageSection>\n {loading && (\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"conversations.admin.loadingAppInstallations\",\n \"Loading app installations…\",\n )}\n </p>\n )}\n {error && (\n <p className=\"text-sm text-status-error-text\">{error.message}</p>\n )}\n <div className=\"grid gap-3\">\n {installations.map((installation) => (\n <GlassCard\n key={installation.id}\n treatment=\"glass\"\n className=\"border-border-seam p-4\"\n >\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {installation.appId}\n </h3>\n <StatusPill>{installation.state}</StatusPill>\n </div>\n <p className=\"text-xs text-text-secondary\">\n {tr(\n \"conversations.admin.appVersionMeta\",\n \"Version {{version}} · Installed by {{installedBy}} on {{installedAt}}\",\n {\n version: installation.appVersion,\n installedBy: installation.installedBy,\n installedAt: formatDate(installation.installedAt),\n },\n )}\n </p>\n </div>\n {/* Destructive uninstall lives behind the overflow menu and\n asks for confirmation before firing the mutation. */}\n <CTAOverflowMenu\n className=\"shrink-0\"\n actions={[\n {\n label: tr(\"conversations.admin.uninstall\", \"Uninstall\"),\n intent: \"destructive\",\n disabled: uninstalling,\n icon: <Trash2 className=\"size-4\" aria-hidden=\"true\" />,\n onSelect: () => {\n if (\n !window.confirm(\n tr(\n \"conversations.admin.uninstallConfirm\",\n \"Uninstall {{appId}}? This removes the app and its settings from this workspace.\",\n { appId: installation.appId },\n ),\n )\n ) {\n return;\n }\n void uninstallApp({\n variables: { id: installation.id },\n });\n },\n },\n ]}\n />\n </div>\n {/* The raw JSON settings editor is an advanced surface — collapse\n it behind progressive disclosure so the card stays calm. */}\n <ShowMore\n className=\"mt-3\"\n collapsedHeight={0}\n label={tr(\n \"conversations.admin.editSettingsJson\",\n \"Edit settings (JSON)\",\n )}\n >\n <div className=\"grid gap-2 pt-2\">\n <textarea\n rows={5}\n aria-label={tr(\n \"conversations.admin.settingsForApp\",\n \"Settings for {{appId}}\",\n { appId: installation.appId },\n )}\n value={settingsDrafts[installation.id] ?? \"{}\"}\n onChange={(event) =>\n setSettingsDrafts((current) => ({\n ...current,\n [installation.id]: event.target.value,\n }))\n }\n className=\"rounded-md border border-border-seam bg-bg-surface px-3 py-2 font-mono text-xs text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n />\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n disabled={saving}\n className=\"w-fit\"\n onClick={() => {\n const settings = parsedSettings(\n settingsDrafts[installation.id] ?? \"{}\",\n );\n if (!settings) {\n setFormError(\n tr(\n \"conversations.admin.settingsInvalidJson\",\n \"Installation settings must be a valid JSON object.\",\n ),\n );\n return;\n }\n setFormError(null);\n void updateSettings({\n variables: { id: installation.id, settings },\n });\n }}\n >\n {tr(\"conversations.admin.saveSettings\", \"Save settings\")}\n </Button>\n </div>\n </ShowMore>\n </GlassCard>\n ))}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|