@burdenoff/microfe-conversations 2026.624.1 → 2026.625.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.
@@ -1 +1 @@
1
- {"version":3,"file":"AdminConversationsLandingPage.js","names":[],"sources":["../../../src/conversations/pages/AdminConversationsLandingPage.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { useMemo } from \"react\";\nimport { Link } from \"react-router-dom\";\nimport {\n MessageCircle,\n ShieldCheck,\n ListChecks,\n Activity,\n Package,\n ChevronRight,\n} from \"lucide-react\";\nimport { useTr } from \"../utils/i18n\";\n\ninterface AdminSectionDefinition {\n id: string;\n /** i18n key used for the card label */\n labelKey: string;\n /** English fallback rendered when the i18n key is not resolved */\n labelFallback: string;\n /** i18n key used for the card description */\n descriptionKey: string;\n /** English fallback for the description */\n descriptionFallback: string;\n /** Route path relative to the admin basePath */\n path: string;\n icon: ReactNode;\n}\n\n// Module-scoped section catalogue. The icon JSX is stable (purely presentational,\n// no context or dynamic props) so constructing once at parse time avoids rebuilding\n// four lucide nodes on every render. If icons ever need to respond to context\n// (theme, RBAC), move the icon field into the useMemo mapper below.\nconst SECTION_DEFINITIONS: AdminSectionDefinition[] = [\n {\n id: \"moderation\",\n labelKey: \"conversations.admin.moderation\",\n labelFallback: \"Moderation\",\n descriptionKey: \"conversations.admin.moderationDescription\",\n descriptionFallback:\n \"Reported and flagged messages, moderation actions, and reviewer assignments.\",\n path: \"moderation\",\n icon: <ShieldCheck className=\"size-5\" aria-hidden=\"true\" />,\n },\n {\n id: \"bulk\",\n labelKey: \"conversations.admin.bulkOperations\",\n labelFallback: \"Bulk Operations\",\n descriptionKey: \"conversations.admin.bulkOperationsDescription\",\n descriptionFallback:\n \"Bulk archive / unarchive, participant edits, and cross-conversation actions.\",\n path: \"bulk\",\n icon: <ListChecks className=\"size-5\" aria-hidden=\"true\" />,\n },\n {\n id: \"audit\",\n labelKey: \"conversations.admin.auditLog\",\n labelFallback: \"Audit Log\",\n descriptionKey: \"conversations.admin.auditLogDescription\",\n descriptionFallback:\n \"Activity stream for admin / moderator actions on workspace conversations.\",\n path: \"audit\",\n icon: <Activity className=\"size-5\" aria-hidden=\"true\" />,\n },\n {\n id: \"apps\",\n labelKey: \"conversations.admin.appInstallations\",\n labelFallback: \"App Installations\",\n descriptionKey: \"conversations.admin.appInstallationsDescription\",\n descriptionFallback:\n \"Install, configure, and remove conversation apps and integrations.\",\n path: \"apps\",\n icon: <Package className=\"size-5\" aria-hidden=\"true\" />,\n },\n];\n\n/**\n * Admin-facing landing page for the Conversations microfrontend.\n *\n * Lightweight overview + section directory. Each card links to its canonical\n * sub-route (`/moderation`, `/bulk`, `/audit`, `/apps`) for the API-backed\n * admin surfaces.\n */\nexport function AdminConversationsLandingPage() {\n const tr = useTr();\n\n const sections = useMemo(\n () =>\n SECTION_DEFINITIONS.map((section) => ({\n ...section,\n label: tr(section.labelKey, section.labelFallback),\n description: tr(section.descriptionKey, section.descriptionFallback),\n })),\n [tr],\n );\n\n return (\n <div className=\"flex flex-col h-full\">\n <div className=\"border-b border-border-subtle px-6 py-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"p-2 rounded-md bg-bg-sunken\">\n <MessageCircle\n className=\"size-5 text-text-secondary\"\n aria-hidden=\"true\"\n />\n </div>\n <div>\n <h1 className=\"text-lg font-semibold text-text-primary\">\n {tr(\"conversations.admin.landingTitle\", \"Conversations admin\")}\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"conversations.admin.landingDescription\",\n \"Governance tools for workspace conversations. Select a section below to continue.\",\n )}\n </p>\n </div>\n </div>\n </div>\n <div className=\"flex-1 min-h-0 overflow-auto p-6\">\n <div className=\"grid gap-3 sm:grid-cols-2 max-w-3xl\">\n {sections.map((section) => (\n <Link\n key={section.id}\n to={section.path}\n className=\"group flex items-start gap-3 rounded-lg border border-border-subtle bg-bg-surface p-4 transition-colors hover:border-border-subtle hover:bg-accent\"\n >\n <div className=\"p-2 rounded-md bg-bg-sunken text-text-secondary group-hover:text-text-primary\">\n {section.icon}\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"text-sm font-medium text-text-primary\">\n {section.label}\n </span>\n <ChevronRight\n className=\"size-4 text-text-secondary\"\n aria-hidden=\"true\"\n />\n </div>\n <p className=\"mt-1 text-xs text-text-secondary\">\n {section.description}\n </p>\n </div>\n </Link>\n ))}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;AAgCA,IAAM,IAAgD;CACpD;EACE,IAAI;EACJ,UAAU;EACV,eAAe;EACf,gBAAgB;EAChB,qBACE;EACF,MAAM;EACN,MAAM,kBAAC,GAAD;GAAa,WAAU;GAAS,eAAY;GAAS,CAAA;EAC5D;CACD;EACE,IAAI;EACJ,UAAU;EACV,eAAe;EACf,gBAAgB;EAChB,qBACE;EACF,MAAM;EACN,MAAM,kBAAC,GAAD;GAAY,WAAU;GAAS,eAAY;GAAS,CAAA;EAC3D;CACD;EACE,IAAI;EACJ,UAAU;EACV,eAAe;EACf,gBAAgB;EAChB,qBACE;EACF,MAAM;EACN,MAAM,kBAAC,GAAD;GAAU,WAAU;GAAS,eAAY;GAAS,CAAA;EACzD;CACD;EACE,IAAI;EACJ,UAAU;EACV,eAAe;EACf,gBAAgB;EAChB,qBACE;EACF,MAAM;EACN,MAAM,kBAAC,GAAD;GAAS,WAAU;GAAS,eAAY;GAAS,CAAA;EACxD;CACF;AASD,SAAgB,IAAgC;CAC9C,IAAM,IAAK,GAAO,EAEZ,IAAW,QAEb,EAAoB,KAAK,OAAa;EACpC,GAAG;EACH,OAAO,EAAG,EAAQ,UAAU,EAAQ,cAAc;EAClD,aAAa,EAAG,EAAQ,gBAAgB,EAAQ,oBAAoB;EACrE,EAAE,EACL,CAAC,EAAG,CACL;AAED,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MACE,WAAU;MACV,eAAY;MACZ,CAAA;KACE,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,oCAAoC,sBAAsB;KAC3D,CAAA,EACL,kBAAC,KAAD;KAAG,WAAU;eACV,EACC,0CACA,oFACD;KACC,CAAA,CACA,EAAA,CAAA,CACF;;GACF,CAAA,EACN,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAS,KAAK,MACb,kBAAC,GAAD;KAEE,IAAI,EAAQ;KACZ,WAAU;eAHZ,CAKE,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAQ;MACL,CAAA,EACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAQ;QACJ,CAAA,EACP,kBAAC,GAAD;QACE,WAAU;QACV,eAAY;QACZ,CAAA,CACE;UACN,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAQ;OACP,CAAA,CACA;QACD;OArBA,EAAQ,GAqBR,CACP;IACE,CAAA;GACF,CAAA,CACF"}
1
+ {"version":3,"file":"AdminConversationsLandingPage.js","names":[],"sources":["../../../src/conversations/pages/AdminConversationsLandingPage.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { useMemo } from \"react\";\nimport { Link } from \"react-router-dom\";\nimport {\n MessageCircle,\n ShieldCheck,\n ListChecks,\n Activity,\n Package,\n ChevronRight,\n} from \"lucide-react\";\nimport { GlassCard, EmphasisPanel, GradientText } from \"@burdenoff/fe-libs/ui\";\nimport { useTr } from \"../utils/i18n\";\n\ninterface AdminSectionDefinition {\n id: string;\n /** i18n key used for the card label */\n labelKey: string;\n /** English fallback rendered when the i18n key is not resolved */\n labelFallback: string;\n /** i18n key used for the card description */\n descriptionKey: string;\n /** English fallback for the description */\n descriptionFallback: string;\n /** Route path relative to the admin basePath */\n path: string;\n icon: ReactNode;\n /** The single featured section — gets the glowing glass treatment. */\n featured?: boolean;\n}\n\n// Module-scoped section catalogue. The icon JSX is stable (purely presentational,\n// no context or dynamic props) so constructing once at parse time avoids rebuilding\n// four lucide nodes on every render. If icons ever need to respond to context\n// (theme, RBAC), move the icon field into the useMemo mapper below.\nconst SECTION_DEFINITIONS: AdminSectionDefinition[] = [\n {\n id: \"moderation\",\n labelKey: \"conversations.admin.moderation\",\n labelFallback: \"Moderation\",\n descriptionKey: \"conversations.admin.moderationDescription\",\n descriptionFallback:\n \"Reported and flagged messages, moderation actions, and reviewer assignments.\",\n path: \"moderation\",\n icon: <ShieldCheck className=\"size-5\" aria-hidden=\"true\" />,\n featured: true,\n },\n {\n id: \"bulk\",\n labelKey: \"conversations.admin.bulkOperations\",\n labelFallback: \"Bulk Operations\",\n descriptionKey: \"conversations.admin.bulkOperationsDescription\",\n descriptionFallback:\n \"Bulk archive / unarchive, participant edits, and cross-conversation actions.\",\n path: \"bulk\",\n icon: <ListChecks className=\"size-5\" aria-hidden=\"true\" />,\n },\n {\n id: \"audit\",\n labelKey: \"conversations.admin.auditLog\",\n labelFallback: \"Audit Log\",\n descriptionKey: \"conversations.admin.auditLogDescription\",\n descriptionFallback:\n \"Activity stream for admin / moderator actions on workspace conversations.\",\n path: \"audit\",\n icon: <Activity className=\"size-5\" aria-hidden=\"true\" />,\n },\n {\n id: \"apps\",\n labelKey: \"conversations.admin.appInstallations\",\n labelFallback: \"App Installations\",\n descriptionKey: \"conversations.admin.appInstallationsDescription\",\n descriptionFallback:\n \"Install, configure, and remove conversation apps and integrations.\",\n path: \"apps\",\n icon: <Package className=\"size-5\" aria-hidden=\"true\" />,\n },\n];\n\n/**\n * Admin-facing landing page for the Conversations microfrontend.\n *\n * Lightweight overview + section directory. Each card links to its canonical\n * sub-route (`/moderation`, `/bulk`, `/audit`, `/apps`) for the API-backed\n * admin surfaces.\n */\nexport function AdminConversationsLandingPage() {\n const tr = useTr();\n\n const sections = useMemo(\n () =>\n SECTION_DEFINITIONS.map((section) => ({\n ...section,\n label: tr(section.labelKey, section.labelFallback),\n description: tr(section.descriptionKey, section.descriptionFallback),\n })),\n [tr],\n );\n\n return (\n <div className=\"flex flex-col h-full\">\n <div className=\"flex-1 min-h-0 overflow-auto p-4 sm:p-6\">\n <div className=\"mx-auto w-full max-w-3xl space-y-6\">\n {/* Hero / summary zone — the single emphasis panel on this page. */}\n <EmphasisPanel>\n <div className=\"flex items-start gap-3\">\n <div className=\"p-2 rounded-lg bg-gloss-card text-text-secondary border border-border-seam\">\n <MessageCircle className=\"size-5\" aria-hidden=\"true\" />\n </div>\n <div className=\"min-w-0\">\n <h1 className=\"text-lg font-semibold text-text-primary\">\n <GradientText>\n {tr(\n \"conversations.admin.landingTitle\",\n \"Conversations admin\",\n )}\n </GradientText>\n </h1>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {tr(\n \"conversations.admin.landingDescription\",\n \"Governance tools for workspace conversations. Select a section below to continue.\",\n )}\n </p>\n </div>\n </div>\n </EmphasisPanel>\n\n <div className=\"grid gap-3 sm:grid-cols-2\">\n {sections.map((section) => (\n <Link\n key={section.id}\n to={section.path}\n className=\"group rounded-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <GlassCard\n treatment=\"glass\"\n glow={section.featured}\n className=\"flex items-start gap-3 border-border-seam p-4 shadow-[var(--shadow-pop)]\"\n >\n <div className=\"p-2 rounded-md bg-bg-sunken text-text-secondary group-hover:text-text-primary\">\n {section.icon}\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"text-sm font-medium text-text-primary\">\n {section.label}\n </span>\n <ChevronRight\n className=\"size-4 text-text-secondary\"\n aria-hidden=\"true\"\n />\n </div>\n <p className=\"mt-1 text-xs text-text-secondary\">\n {section.description}\n </p>\n </div>\n </GlassCard>\n </Link>\n ))}\n </div>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAmCA,IAAM,IAAgD;CACpD;EACE,IAAI;EACJ,UAAU;EACV,eAAe;EACf,gBAAgB;EAChB,qBACE;EACF,MAAM;EACN,MAAM,kBAAC,GAAD;GAAa,WAAU;GAAS,eAAY;GAAS,CAAA;EAC3D,UAAU;EACX;CACD;EACE,IAAI;EACJ,UAAU;EACV,eAAe;EACf,gBAAgB;EAChB,qBACE;EACF,MAAM;EACN,MAAM,kBAAC,GAAD;GAAY,WAAU;GAAS,eAAY;GAAS,CAAA;EAC3D;CACD;EACE,IAAI;EACJ,UAAU;EACV,eAAe;EACf,gBAAgB;EAChB,qBACE;EACF,MAAM;EACN,MAAM,kBAAC,GAAD;GAAU,WAAU;GAAS,eAAY;GAAS,CAAA;EACzD;CACD;EACE,IAAI;EACJ,UAAU;EACV,eAAe;EACf,gBAAgB;EAChB,qBACE;EACF,MAAM;EACN,MAAM,kBAAC,GAAD;GAAS,WAAU;GAAS,eAAY;GAAS,CAAA;EACxD;CACF;AASD,SAAgB,IAAgC;CAC9C,IAAM,IAAK,GAAO,EAEZ,IAAW,QAEb,EAAoB,KAAK,OAAa;EACpC,GAAG;EACH,OAAO,EAAG,EAAQ,UAAU,EAAQ,cAAc;EAClD,aAAa,EAAG,EAAQ,gBAAgB,EAAQ,oBAAoB;EACrE,EAAE,EACL,CAAC,EAAG,CACL;AAED,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,OAAD;IAAK,WAAU;cAAf,CAEE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,GAAD;OAAe,WAAU;OAAS,eAAY;OAAS,CAAA;MACnD,CAAA,EACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBACZ,kBAAC,GAAD,EAAA,UACG,EACC,oCACA,sBACD,EACY,CAAA;OACZ,CAAA,EACL,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,0CACA,oFACD;OACC,CAAA,CACA;QACF;QACQ,CAAA,EAEhB,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAS,KAAK,MACb,kBAAC,GAAD;MAEE,IAAI,EAAQ;MACZ,WAAU;gBAEV,kBAAC,GAAD;OACE,WAAU;OACV,MAAM,EAAQ;OACd,WAAU;iBAHZ,CAKE,kBAAC,OAAD;QAAK,WAAU;kBACZ,EAAQ;QACL,CAAA,EACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBACb,EAAQ;UACJ,CAAA,EACP,kBAAC,GAAD;UACE,WAAU;UACV,eAAY;UACZ,CAAA,CACE;YACN,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAQ;SACP,CAAA,CACA;UACI;;MACP,EA3BA,EAAQ,GA2BR,CACP;KACE,CAAA,CACF;;GACF,CAAA;EACF,CAAA"}
@@ -8,8 +8,9 @@ import { Activity as c, Archive as l, CheckCircle2 as u, Package as d, ShieldChe
8
8
  import { gql as m } from "@apollo/client";
9
9
  import { useMutation as h, useQuery as g } from "@apollo/client/react";
10
10
  import { jsx as _, jsxs as v } from "react/jsx-runtime";
11
+ import { Button as y, CTAOverflowMenu as b, GlassCard as x, ShowMore as S } from "@burdenoff/fe-libs/ui";
11
12
  //#region src/conversations/pages/ConversationAdminPages.tsx
12
- var y = m`
13
+ var C = m`
13
14
  query ConversationAdminMessageReports(
14
15
  $first: Int
15
16
  $filter: MessageReportFilter
@@ -37,7 +38,7 @@ var y = m`
37
38
  }
38
39
  }
39
40
  }
40
- `, b = m`
41
+ `, w = m`
41
42
  mutation ConversationAdminResolveMessageReport(
42
43
  $input: ResolveMessageReportInput!
43
44
  ) {
@@ -52,7 +53,7 @@ var y = m`
52
53
  }
53
54
  }
54
55
  }
55
- `, x = m`
56
+ `, T = m`
56
57
  query ConversationAdminBulkConversations(
57
58
  $first: Int
58
59
  $filter: ConversationFilter
@@ -69,7 +70,7 @@ var y = m`
69
70
  }
70
71
  }
71
72
  }
72
- `, S = m`
73
+ `, E = m`
73
74
  mutation ConversationAdminBulkUpdate(
74
75
  $input: BulkConversationOperationInput!
75
76
  ) {
@@ -85,7 +86,7 @@ var y = m`
85
86
  }
86
87
  }
87
88
  }
88
- `, C = m`
89
+ `, D = m`
89
90
  query ConversationAdminAuditLog($filter: ActivityLogFilter) {
90
91
  getActivities(filter: $filter) {
91
92
  id
@@ -97,7 +98,7 @@ var y = m`
97
98
  timestamp
98
99
  }
99
100
  }
100
- `, w = m`
101
+ `, O = m`
101
102
  query ConversationAdminAppInstallations($workspaceId: ID) {
102
103
  appInstallations(workspaceId: $workspaceId) {
103
104
  id
@@ -111,7 +112,7 @@ var y = m`
111
112
  updatedAt
112
113
  }
113
114
  }
114
- `, T = m`
115
+ `, k = m`
115
116
  mutation ConversationAdminInstallApp($input: InstallAppInput!) {
116
117
  installApp(input: $input) {
117
118
  id
@@ -121,7 +122,7 @@ var y = m`
121
122
  installedAt
122
123
  }
123
124
  }
124
- `, E = m`
125
+ `, A = m`
125
126
  mutation ConversationAdminUpdateAppSettings($id: ID!, $settings: JSON!) {
126
127
  updateAppSettings(id: $id, settings: $settings) {
127
128
  id
@@ -129,7 +130,7 @@ var y = m`
129
130
  updatedAt
130
131
  }
131
132
  }
132
- `, D = m`
133
+ `, j = m`
133
134
  mutation ConversationAdminUninstallApp($id: ID!) {
134
135
  uninstallApp(id: $id) {
135
136
  appInstallationId
@@ -137,7 +138,7 @@ var y = m`
137
138
  }
138
139
  }
139
140
  `;
140
- function O(e) {
141
+ function M(e) {
141
142
  if (typeof e == "string") return e;
142
143
  if (e && typeof e == "object" && "text" in e) {
143
144
  let t = e.text;
@@ -149,27 +150,27 @@ function O(e) {
149
150
  return "Message content unavailable";
150
151
  }
151
152
  }
152
- var k = new Intl.DateTimeFormat(void 0, {
153
+ var N = new Intl.DateTimeFormat(void 0, {
153
154
  dateStyle: "medium",
154
155
  timeStyle: "short"
155
156
  });
156
- function A(e) {
157
- return k.format(new Date(e));
157
+ function P(e) {
158
+ return N.format(new Date(e));
158
159
  }
159
- function j({ children: e }) {
160
+ function F({ children: e }) {
160
161
  return /* @__PURE__ */ _("span", {
161
162
  className: "rounded-full border border-border-subtle bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary",
162
163
  children: e
163
164
  });
164
165
  }
165
- function M() {
166
- let n = t(), { workspaceId: a } = e(), { data: o, loading: s, error: c, refetch: l } = g(y, {
166
+ function I() {
167
+ let n = t(), { workspaceId: a } = e(), { data: o, loading: s, error: c, refetch: l } = g(C, {
167
168
  variables: {
168
169
  first: 50,
169
170
  filter: { statuses: ["PENDING", "REVIEWING"] }
170
171
  },
171
172
  skip: !a
172
- }), [d, { loading: p }] = h(b, { onCompleted: () => void l() }), m = o?.messageReports.edges.map((e) => e.node) ?? [];
173
+ }), [d, { loading: p }] = h(w, { onCompleted: () => void l() }), m = o?.messageReports.edges.map((e) => e.node) ?? [];
173
174
  return /* @__PURE__ */ v(i, {
174
175
  title: n("conversations.admin.moderationPageTitle", "Moderation queue"),
175
176
  subtitle: n("conversations.admin.moderationPageDescription", "Review reported messages and apply moderator decisions."),
@@ -185,7 +186,8 @@ function M() {
185
186
  icon: /* @__PURE__ */ _(f, {
186
187
  className: "size-6",
187
188
  "aria-hidden": "true"
188
- })
189
+ }),
190
+ illustration: "empty-generic"
189
191
  }),
190
192
  a && s && /* @__PURE__ */ _("p", {
191
193
  className: "text-sm text-text-secondary",
@@ -201,25 +203,27 @@ function M() {
201
203
  icon: /* @__PURE__ */ _(u, {
202
204
  className: "size-6",
203
205
  "aria-hidden": "true"
204
- })
206
+ }),
207
+ illustration: "empty-notifications"
205
208
  }),
206
209
  /* @__PURE__ */ _("div", {
207
210
  className: "grid gap-3",
208
- children: m.map((e) => /* @__PURE__ */ _("article", {
209
- className: "rounded-lg border border-border-subtle bg-bg-surface p-4 shadow-sm",
211
+ children: m.map((e) => /* @__PURE__ */ _(x, {
212
+ treatment: "glass",
213
+ className: "border-border-seam p-4",
210
214
  children: /* @__PURE__ */ v("div", {
211
215
  className: "flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between",
212
216
  children: [/* @__PURE__ */ v("div", {
213
- className: "space-y-2",
217
+ className: "space-y-2 min-w-0",
214
218
  children: [
215
219
  /* @__PURE__ */ v("div", {
216
220
  className: "flex flex-wrap items-center gap-2",
217
221
  children: [
218
- /* @__PURE__ */ _(j, { children: e.status }),
219
- e.message.isHidden && /* @__PURE__ */ _(j, { children: "Hidden" }),
222
+ /* @__PURE__ */ _(F, { children: e.status }),
223
+ e.message.isHidden && /* @__PURE__ */ _(F, { children: "Hidden" }),
220
224
  /* @__PURE__ */ v("span", {
221
225
  className: "text-xs text-text-secondary",
222
- children: ["Reported ", A(e.createdAt)]
226
+ children: ["Reported ", P(e.createdAt)]
223
227
  })
224
228
  ]
225
229
  }),
@@ -228,8 +232,8 @@ function M() {
228
232
  children: e.reason
229
233
  }),
230
234
  /* @__PURE__ */ _("p", {
231
- className: "rounded-md bg-bg-sunken p-3 text-sm text-text-secondary",
232
- children: O(e.message.content)
235
+ className: "rounded-md border border-border-seam bg-bg-sunken p-3 text-sm text-text-secondary",
236
+ children: M(e.message.content)
233
237
  }),
234
238
  /* @__PURE__ */ v("p", {
235
239
  className: "text-xs text-text-secondary",
@@ -246,27 +250,24 @@ function M() {
246
250
  ]
247
251
  })
248
252
  ]
249
- }), /* @__PURE__ */ v("div", {
250
- className: "flex flex-wrap gap-2",
251
- children: [/* @__PURE__ */ _("button", {
252
- type: "button",
253
+ }), /* @__PURE__ */ _(b, {
254
+ className: "shrink-0",
255
+ primary: {
256
+ label: "Hide and resolve",
253
257
  disabled: p,
254
- className: "rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary hover:bg-accent disabled:opacity-50",
255
- onClick: () => void d({ variables: { input: {
258
+ onSelect: () => void d({ variables: { input: {
256
259
  reportId: e.id,
257
- action: "DISMISS"
258
- } } }),
259
- children: "Dismiss"
260
- }), /* @__PURE__ */ _("button", {
261
- type: "button",
260
+ action: "HIDE_MESSAGE"
261
+ } } })
262
+ },
263
+ actions: [{
264
+ label: "Dismiss",
262
265
  disabled: p,
263
- className: "rounded-md bg-action-primary-bg px-3 py-2 text-sm text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-50",
264
- onClick: () => void d({ variables: { input: {
266
+ onSelect: () => void d({ variables: { input: {
265
267
  reportId: e.id,
266
- action: "HIDE_MESSAGE"
267
- } } }),
268
- children: "Hide and resolve"
269
- })]
268
+ action: "DISMISS"
269
+ } } })
270
+ }]
270
271
  })]
271
272
  })
272
273
  }, e.id))
@@ -274,13 +275,13 @@ function M() {
274
275
  ]
275
276
  });
276
277
  }
277
- function N() {
278
- let n = t(), { workspaceId: a } = e(), [o, c] = s(() => /* @__PURE__ */ new Set()), [u, d] = s("ARCHIVE"), { data: f, loading: p, error: m, refetch: y } = g(x, {
278
+ function L() {
279
+ let n = t(), { workspaceId: a } = e(), [o, c] = s(() => /* @__PURE__ */ new Set()), [u, d] = s("ARCHIVE"), { data: f, loading: p, error: m, refetch: b } = g(T, {
279
280
  variables: { first: 100 },
280
281
  skip: !a
281
- }), [b, { data: C, loading: w }] = h(S, { onCompleted: () => {
282
- c(/* @__PURE__ */ new Set()), y();
283
- } }), T = f?.conversations.edges.map((e) => e.node) ?? [], E = (e) => {
282
+ }), [S, { data: C, loading: w }] = h(E, { onCompleted: () => {
283
+ c(/* @__PURE__ */ new Set()), b();
284
+ } }), D = f?.conversations.edges.map((e) => e.node) ?? [], O = (e) => {
284
285
  c((t) => {
285
286
  let n = new Set(t);
286
287
  return n.has(e) ? n.delete(e) : n.add(e), n;
@@ -299,7 +300,8 @@ function N() {
299
300
  children: [/* @__PURE__ */ v("select", {
300
301
  value: u,
301
302
  onChange: (e) => d(e.target.value),
302
- className: "rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary",
303
+ "aria-label": "Bulk action",
304
+ 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)]",
303
305
  children: [
304
306
  /* @__PURE__ */ _("option", {
305
307
  value: "ARCHIVE",
@@ -314,11 +316,11 @@ function N() {
314
316
  children: "Delete"
315
317
  })
316
318
  ]
317
- }), /* @__PURE__ */ v("button", {
319
+ }), /* @__PURE__ */ v(y, {
318
320
  type: "button",
321
+ size: "sm",
319
322
  disabled: o.size === 0 || w,
320
- className: "rounded-md bg-action-primary-bg px-3 py-2 text-sm text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-50",
321
- onClick: () => void b({ variables: { input: {
323
+ onClick: () => void S({ variables: { input: {
322
324
  conversationIds: Array.from(o),
323
325
  action: u
324
326
  } } }),
@@ -332,7 +334,8 @@ function N() {
332
334
  icon: /* @__PURE__ */ _(l, {
333
335
  className: "size-6",
334
336
  "aria-hidden": "true"
335
- })
337
+ }),
338
+ illustration: "empty-generic"
336
339
  }),
337
340
  a && p && /* @__PURE__ */ _("p", {
338
341
  className: "text-sm text-text-secondary",
@@ -342,25 +345,32 @@ function N() {
342
345
  className: "text-sm text-status-error-text",
343
346
  children: m.message
344
347
  }),
345
- C?.bulkUpdateConversations && /* @__PURE__ */ v("div", {
346
- className: "rounded-lg border border-border-subtle bg-bg-sunken p-3 text-sm text-text-secondary",
347
- children: [
348
- C.bulkUpdateConversations.successCount,
349
- " succeeded,",
350
- " ",
351
- C.bulkUpdateConversations.failureCount,
352
- " failed."
353
- ]
348
+ C?.bulkUpdateConversations && /* @__PURE__ */ v(x, {
349
+ treatment: "metric",
350
+ className: "grid grid-cols-2 gap-4 border-border-seam p-4 sm:max-w-md",
351
+ children: [/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("p", {
352
+ className: "text-2xl font-semibold tabular-nums text-status-success-text",
353
+ children: C.bulkUpdateConversations.successCount
354
+ }), /* @__PURE__ */ _("p", {
355
+ className: "text-xs text-text-secondary",
356
+ children: "Succeeded"
357
+ })] }), /* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("p", {
358
+ className: "text-2xl font-semibold tabular-nums text-text-primary",
359
+ children: C.bulkUpdateConversations.failureCount
360
+ }), /* @__PURE__ */ _("p", {
361
+ className: "text-xs text-text-secondary",
362
+ children: "Failed"
363
+ })] })]
354
364
  }),
355
365
  a && /* @__PURE__ */ _("div", {
356
- className: "overflow-hidden rounded-lg border border-border-subtle bg-bg-surface",
357
- children: T.map((e) => /* @__PURE__ */ v("label", {
358
- className: "flex cursor-pointer items-center gap-3 border-b border-border-subtle px-4 py-3 last:border-b-0 hover:bg-accent",
366
+ className: "overflow-hidden rounded-lg border border-border-seam bg-bg-surface",
367
+ children: D.map((e) => /* @__PURE__ */ v("label", {
368
+ 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",
359
369
  children: [/* @__PURE__ */ _("input", {
360
370
  type: "checkbox",
361
371
  "aria-label": `Select ${e.title || "untitled conversation"}`,
362
372
  checked: o.has(e.id),
363
- onChange: () => E(e.id)
373
+ onChange: () => O(e.id)
364
374
  }), /* @__PURE__ */ v("div", {
365
375
  className: "min-w-0 flex-1",
366
376
  children: [/* @__PURE__ */ _("p", {
@@ -374,7 +384,7 @@ function N() {
374
384
  e.state,
375
385
  " · Updated",
376
386
  " ",
377
- A(e.updatedAt)
387
+ P(e.updatedAt)
378
388
  ]
379
389
  })]
380
390
  })]
@@ -383,8 +393,8 @@ function N() {
383
393
  ]
384
394
  });
385
395
  }
386
- function P() {
387
- let n = t(), { workspaceId: a } = e(), { data: o, loading: s, error: l } = g(C, {
396
+ function R() {
397
+ let n = t(), { workspaceId: a } = e(), { data: o, loading: s, error: l } = g(D, {
388
398
  variables: { filter: {
389
399
  workspaceId: a,
390
400
  resourceType: "conversation",
@@ -411,12 +421,14 @@ function P() {
411
421
  }),
412
422
  !s && !l && u.length === 0 && /* @__PURE__ */ _(r, {
413
423
  title: "No activity found",
414
- description: "Conversation admin actions will appear here."
424
+ description: "Conversation admin actions will appear here.",
425
+ illustration: "empty-data"
415
426
  }),
416
427
  /* @__PURE__ */ _("div", {
417
428
  className: "grid gap-3",
418
- children: u.map((e) => /* @__PURE__ */ v("article", {
419
- className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
429
+ children: u.map((e) => /* @__PURE__ */ v(x, {
430
+ treatment: "plain",
431
+ className: "border-border-seam p-4",
420
432
  children: [
421
433
  /* @__PURE__ */ v("div", {
422
434
  className: "flex flex-wrap items-center justify-between gap-2",
@@ -424,8 +436,8 @@ function P() {
424
436
  className: "text-sm font-medium text-text-primary",
425
437
  children: e.action
426
438
  }), /* @__PURE__ */ _("span", {
427
- className: "text-xs text-text-secondary",
428
- children: A(e.timestamp)
439
+ className: "text-xs tabular-nums text-text-secondary",
440
+ children: P(e.timestamp)
429
441
  })]
430
442
  }),
431
443
  /* @__PURE__ */ _("p", {
@@ -447,20 +459,20 @@ function P() {
447
459
  ]
448
460
  });
449
461
  }
450
- function F() {
451
- let r = t(), { workspaceId: c } = e(), [l, u] = s(""), [f, m] = s("{}"), [y, b] = s({}), [x, S] = s(null), { data: C, loading: O, error: k, refetch: M } = g(w, {
462
+ function z() {
463
+ let r = t(), { workspaceId: c } = e(), [l, u] = s(""), [f, m] = s("{}"), [C, w] = s({}), [T, E] = s(null), { data: D, loading: M, error: N, refetch: I } = g(O, {
452
464
  variables: { workspaceId: c },
453
465
  skip: !c
454
- }), [N, { loading: P }] = h(T, { onCompleted: () => void M() }), [F, { loading: I }] = h(E, { onCompleted: () => void M() }), [L, { loading: R }] = h(D, { onCompleted: () => void M() }), z = o(() => C?.appInstallations ?? [], [C?.appInstallations]);
466
+ }), [L, { loading: R }] = h(k, { onCompleted: () => void I() }), [z, { loading: B }] = h(A, { onCompleted: () => void I() }), [V, { loading: H }] = h(j, { onCompleted: () => void I() }), U = o(() => D?.appInstallations ?? [], [D?.appInstallations]);
455
467
  a(() => {
456
- b((e) => {
457
- if (z.every((t) => e[t.id])) return e;
468
+ w((e) => {
469
+ if (U.every((t) => e[t.id])) return e;
458
470
  let t = { ...e };
459
- for (let e of z) t[e.id] || (t[e.id] = JSON.stringify(e.settings ?? {}, null, 2));
471
+ for (let e of U) t[e.id] || (t[e.id] = JSON.stringify(e.settings ?? {}, null, 2));
460
472
  return t;
461
473
  });
462
- }, [z]);
463
- let B = (e) => {
474
+ }, [U]);
475
+ let W = (e) => {
464
476
  try {
465
477
  let t = JSON.parse(e);
466
478
  return t && typeof t == "object" && !Array.isArray(t) ? t : null;
@@ -481,33 +493,33 @@ function F() {
481
493
  title: "Install app",
482
494
  description: "Install a workspace-scoped conversation app by app ID.",
483
495
  children: [/* @__PURE__ */ v("div", {
484
- className: "grid gap-3 rounded-lg border border-border-subtle bg-bg-surface p-4 sm:grid-cols-[minmax(0,1fr)_minmax(0,2fr)_auto]",
496
+ className: "grid gap-3 rounded-lg border border-border-seam bg-bg-surface p-4 sm:grid-cols-[minmax(0,1fr)_minmax(0,2fr)_auto]",
485
497
  children: [
486
498
  /* @__PURE__ */ _("input", {
487
499
  value: l,
488
500
  onChange: (e) => u(e.target.value),
489
501
  placeholder: "app-id",
490
502
  "aria-label": "App ID",
491
- className: "rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary"
503
+ 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)]"
492
504
  }),
493
505
  /* @__PURE__ */ _("textarea", {
494
506
  value: f,
495
507
  onChange: (e) => m(e.target.value),
496
508
  rows: 3,
497
509
  "aria-label": "App settings JSON",
498
- className: "rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary"
510
+ 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)]"
499
511
  }),
500
- /* @__PURE__ */ _("button", {
512
+ /* @__PURE__ */ _(y, {
501
513
  type: "button",
502
- disabled: P,
503
- className: "rounded-md bg-action-primary-bg px-3 py-2 text-sm text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-50",
514
+ size: "sm",
515
+ disabled: R,
504
516
  onClick: () => {
505
- let e = B(f);
517
+ let e = W(f);
506
518
  if (!l.trim() || !e) {
507
- S("Enter an app ID and a valid JSON settings object.");
519
+ E("Enter an app ID and a valid JSON settings object.");
508
520
  return;
509
521
  }
510
- S(null), N({ variables: { input: {
522
+ E(null), L({ variables: { input: {
511
523
  appId: l.trim(),
512
524
  workspaceId: c,
513
525
  settings: e
@@ -516,81 +528,97 @@ function F() {
516
528
  children: "Install"
517
529
  })
518
530
  ]
519
- }), x && /* @__PURE__ */ _("p", {
531
+ }), T && /* @__PURE__ */ _("p", {
520
532
  className: "text-sm text-status-error-text",
521
- children: x
533
+ children: T
522
534
  })]
523
535
  }),
524
- O && /* @__PURE__ */ _("p", {
536
+ M && /* @__PURE__ */ _("p", {
525
537
  className: "text-sm text-text-secondary",
526
538
  children: "Loading app installations…"
527
539
  }),
528
- k && /* @__PURE__ */ _("p", {
540
+ N && /* @__PURE__ */ _("p", {
529
541
  className: "text-sm text-status-error-text",
530
- children: k.message
542
+ children: N.message
531
543
  }),
532
544
  /* @__PURE__ */ _("div", {
533
545
  className: "grid gap-3",
534
- children: z.map((e) => /* @__PURE__ */ v("article", {
535
- className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
546
+ children: U.map((e) => /* @__PURE__ */ v(x, {
547
+ treatment: "glass",
548
+ className: "border-border-seam p-4",
536
549
  children: [/* @__PURE__ */ v("div", {
537
550
  className: "flex flex-wrap items-start justify-between gap-3",
538
- children: [/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ v("div", {
539
- className: "flex items-center gap-2",
540
- children: [/* @__PURE__ */ _("h3", {
541
- className: "text-sm font-semibold text-text-primary",
542
- children: e.appId
543
- }), /* @__PURE__ */ _(j, { children: e.state })]
544
- }), /* @__PURE__ */ v("p", {
545
- className: "text-xs text-text-secondary",
546
- children: [
547
- "Version ",
548
- e.appVersion,
549
- " · Installed by",
550
- " ",
551
- e.installedBy,
552
- " on",
553
- " ",
554
- A(e.installedAt)
555
- ]
556
- })] }), /* @__PURE__ */ v("button", {
557
- type: "button",
558
- disabled: R,
559
- className: "inline-flex items-center gap-2 rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary hover:bg-accent disabled:opacity-50",
560
- onClick: () => void L({ variables: { id: e.id } }),
561
- children: [/* @__PURE__ */ _(p, {
562
- className: "size-4",
563
- "aria-hidden": "true"
564
- }), "Uninstall"]
565
- })]
566
- }), /* @__PURE__ */ v("div", {
567
- className: "mt-3 grid gap-2",
568
- children: [/* @__PURE__ */ _("textarea", {
569
- rows: 5,
570
- "aria-label": `Settings for ${e.appId}`,
571
- value: y[e.id] ?? "{}",
572
- onChange: (t) => b((n) => ({
573
- ...n,
574
- [e.id]: t.target.value
575
- })),
576
- className: "rounded-md border border-border-subtle bg-bg-surface px-3 py-2 font-mono text-xs text-text-primary"
577
- }), /* @__PURE__ */ _("button", {
578
- type: "button",
579
- disabled: I,
580
- className: "w-fit rounded-md bg-secondary px-3 py-2 text-sm text-secondary-foreground hover:bg-secondary/90 disabled:opacity-50",
581
- onClick: () => {
582
- let t = B(y[e.id] ?? "{}");
583
- if (!t) {
584
- S("Installation settings must be a valid JSON object.");
585
- return;
551
+ children: [/* @__PURE__ */ v("div", {
552
+ className: "min-w-0",
553
+ children: [/* @__PURE__ */ v("div", {
554
+ className: "flex items-center gap-2",
555
+ children: [/* @__PURE__ */ _("h3", {
556
+ className: "text-sm font-semibold text-text-primary",
557
+ children: e.appId
558
+ }), /* @__PURE__ */ _(F, { children: e.state })]
559
+ }), /* @__PURE__ */ v("p", {
560
+ className: "text-xs text-text-secondary",
561
+ children: [
562
+ "Version ",
563
+ e.appVersion,
564
+ " · Installed by",
565
+ " ",
566
+ e.installedBy,
567
+ " on",
568
+ " ",
569
+ P(e.installedAt)
570
+ ]
571
+ })]
572
+ }), /* @__PURE__ */ _(b, {
573
+ className: "shrink-0",
574
+ actions: [{
575
+ label: "Uninstall",
576
+ intent: "destructive",
577
+ disabled: H,
578
+ icon: /* @__PURE__ */ _(p, {
579
+ className: "size-4",
580
+ "aria-hidden": "true"
581
+ }),
582
+ onSelect: () => {
583
+ window.confirm(`Uninstall ${e.appId}? This removes the app and its settings from this workspace.`) && V({ variables: { id: e.id } });
586
584
  }
587
- S(null), F({ variables: {
588
- id: e.id,
589
- settings: t
590
- } });
591
- },
592
- children: "Save settings"
585
+ }]
593
586
  })]
587
+ }), /* @__PURE__ */ _(S, {
588
+ className: "mt-3",
589
+ collapsedHeight: 0,
590
+ label: "Edit settings (JSON)",
591
+ children: /* @__PURE__ */ v("div", {
592
+ className: "grid gap-2 pt-2",
593
+ children: [/* @__PURE__ */ _("textarea", {
594
+ rows: 5,
595
+ "aria-label": `Settings for ${e.appId}`,
596
+ value: C[e.id] ?? "{}",
597
+ onChange: (t) => w((n) => ({
598
+ ...n,
599
+ [e.id]: t.target.value
600
+ })),
601
+ 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)]"
602
+ }), /* @__PURE__ */ _(y, {
603
+ type: "button",
604
+ variant: "secondary",
605
+ size: "sm",
606
+ disabled: B,
607
+ className: "w-fit",
608
+ onClick: () => {
609
+ let t = W(C[e.id] ?? "{}");
610
+ if (!t) {
611
+ E("Installation settings must be a valid JSON object.");
612
+ return;
613
+ }
614
+ E(null), z({ variables: {
615
+ id: e.id,
616
+ settings: t
617
+ } });
618
+ },
619
+ children: "Save settings"
620
+ })]
621
+ })
594
622
  })]
595
623
  }, e.id))
596
624
  })
@@ -598,6 +626,6 @@ function F() {
598
626
  });
599
627
  }
600
628
  //#endregion
601
- export { F as AppInstallationsPage, N as BulkOperationsPage, P as ConversationAuditLogPage, M as ModerationQueuePage };
629
+ export { z as AppInstallationsPage, L as BulkOperationsPage, R as ConversationAuditLogPage, I as ModerationQueuePage };
602
630
 
603
631
  //# sourceMappingURL=ConversationAdminPages.js.map