@agent-native/dispatch 0.15.12 → 0.15.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/actions/create-workspace-resource.d.ts +13 -13
  2. package/dist/actions/delete-destination.d.ts +12 -12
  3. package/dist/actions/delete-workspace-resource.d.ts +13 -13
  4. package/dist/actions/provider-api-register.d.ts +3 -3
  5. package/dist/actions/send-platform-message.js +3 -1
  6. package/dist/actions/send-platform-message.js.map +1 -1
  7. package/dist/actions/update-workspace-resource.d.ts +13 -13
  8. package/dist/components/messaging-setup-panel.d.ts.map +1 -1
  9. package/dist/components/messaging-setup-panel.js +96 -72
  10. package/dist/components/messaging-setup-panel.js.map +1 -1
  11. package/dist/routes/pages/approvals.d.ts.map +1 -1
  12. package/dist/routes/pages/approvals.js +13 -9
  13. package/dist/routes/pages/approvals.js.map +1 -1
  14. package/dist/routes/pages/destinations.d.ts.map +1 -1
  15. package/dist/routes/pages/destinations.js +33 -30
  16. package/dist/routes/pages/destinations.js.map +1 -1
  17. package/dist/server/lib/dispatch-integrations.d.ts.map +1 -1
  18. package/dist/server/lib/dispatch-integrations.js +3 -6
  19. package/dist/server/lib/dispatch-integrations.js.map +1 -1
  20. package/package.json +3 -3
  21. package/src/actions/send-platform-message.spec.ts +21 -0
  22. package/src/actions/send-platform-message.ts +3 -2
  23. package/src/components/messaging-setup-panel.spec.tsx +51 -0
  24. package/src/components/messaging-setup-panel.tsx +601 -512
  25. package/src/routes/pages/approvals.tsx +75 -57
  26. package/src/routes/pages/destinations.tsx +107 -85
  27. package/src/server/lib/dispatch-integrations.spec.ts +39 -1
  28. package/src/server/lib/dispatch-integrations.ts +3 -10
@@ -6,6 +6,19 @@ declare const _default: import("@agent-native/core").ActionDefinition<{
6
6
  content: string;
7
7
  scope: "all" | "selected";
8
8
  }, {
9
+ id: string;
10
+ ownerEmail: string;
11
+ orgId: string | null;
12
+ kind: string;
13
+ name: string;
14
+ description: string | null;
15
+ path: string;
16
+ content: string;
17
+ scope: string;
18
+ createdBy: string;
19
+ createdAt: number;
20
+ updatedAt: number;
21
+ } | {
9
22
  id: string;
10
23
  ownerEmail: string;
11
24
  orgId: string | null;
@@ -22,19 +35,6 @@ declare const _default: import("@agent-native/core").ActionDefinition<{
22
35
  reviewedAt: number | null;
23
36
  createdAt: number;
24
37
  updatedAt: number;
25
- } | {
26
- id: string;
27
- ownerEmail: string;
28
- orgId: string | null;
29
- kind: string;
30
- name: string;
31
- description: string | null;
32
- path: string;
33
- content: string;
34
- scope: string;
35
- createdBy: string;
36
- createdAt: number;
37
- updatedAt: number;
38
38
  }>;
39
39
  export default _default;
40
40
  //# sourceMappingURL=create-workspace-resource.d.ts.map
@@ -1,6 +1,18 @@
1
1
  declare const _default: import("@agent-native/core").ActionDefinition<{
2
2
  id: string;
3
3
  }, {
4
+ id: string;
5
+ ownerEmail: string;
6
+ orgId: string | null;
7
+ name: string;
8
+ platform: string;
9
+ destination: string;
10
+ threadRef: string | null;
11
+ notes: string | null;
12
+ createdBy: string;
13
+ createdAt: number;
14
+ updatedAt: number;
15
+ } | {
4
16
  id: string;
5
17
  ownerEmail: string;
6
18
  orgId: string | null;
@@ -17,18 +29,6 @@ declare const _default: import("@agent-native/core").ActionDefinition<{
17
29
  reviewedAt: number | null;
18
30
  createdAt: number;
19
31
  updatedAt: number;
20
- } | {
21
- id: string;
22
- ownerEmail: string;
23
- orgId: string | null;
24
- name: string;
25
- platform: string;
26
- destination: string;
27
- threadRef: string | null;
28
- notes: string | null;
29
- createdBy: string;
30
- createdAt: number;
31
- updatedAt: number;
32
32
  }>;
33
33
  export default _default;
34
34
  //# sourceMappingURL=delete-destination.d.ts.map
@@ -1,6 +1,19 @@
1
1
  declare const _default: import("@agent-native/core").ActionDefinition<{
2
2
  id: string;
3
3
  }, {
4
+ id: string;
5
+ ownerEmail: string;
6
+ orgId: string | null;
7
+ kind: string;
8
+ name: string;
9
+ description: string | null;
10
+ path: string;
11
+ content: string;
12
+ scope: string;
13
+ createdBy: string;
14
+ createdAt: number;
15
+ updatedAt: number;
16
+ } | {
4
17
  id: string;
5
18
  ownerEmail: string;
6
19
  orgId: string | null;
@@ -17,19 +30,6 @@ declare const _default: import("@agent-native/core").ActionDefinition<{
17
30
  reviewedAt: number | null;
18
31
  createdAt: number;
19
32
  updatedAt: number;
20
- } | {
21
- id: string;
22
- ownerEmail: string;
23
- orgId: string | null;
24
- kind: string;
25
- name: string;
26
- description: string | null;
27
- path: string;
28
- content: string;
29
- scope: string;
30
- createdBy: string;
31
- createdAt: number;
32
- updatedAt: number;
33
33
  }>;
34
34
  export default _default;
35
35
  //# sourceMappingURL=delete-workspace-resource.d.ts.map
@@ -48,6 +48,7 @@ declare const _default: import("node_modules/@agent-native/core/dist").ActionDef
48
48
  scope?: "org" | "user" | undefined;
49
49
  }, {
50
50
  id?: undefined;
51
+ found?: undefined;
51
52
  deleted?: undefined;
52
53
  providers: {
53
54
  id: string;
@@ -60,7 +61,6 @@ declare const _default: import("node_modules/@agent-native/core/dist").ActionDef
60
61
  }[];
61
62
  count: number;
62
63
  provider?: undefined;
63
- found?: undefined;
64
64
  registered?: undefined;
65
65
  label?: undefined;
66
66
  message?: undefined;
@@ -85,21 +85,21 @@ declare const _default: import("node_modules/@agent-native/core/dist").ActionDef
85
85
  label?: undefined;
86
86
  message?: undefined;
87
87
  } | {
88
+ found?: undefined;
88
89
  providers?: undefined;
89
90
  count?: undefined;
90
91
  provider?: undefined;
91
- found?: undefined;
92
92
  deleted: boolean;
93
93
  id: string;
94
94
  registered?: undefined;
95
95
  label?: undefined;
96
96
  message?: undefined;
97
97
  } | {
98
+ found?: undefined;
98
99
  deleted?: undefined;
99
100
  providers?: undefined;
100
101
  count?: undefined;
101
102
  provider?: undefined;
102
- found?: undefined;
103
103
  registered: boolean;
104
104
  id: string;
105
105
  label: string;
@@ -22,7 +22,9 @@ async function assertOutboundConfigured(platform, tenantId) {
22
22
  const managed = installation
23
23
  ? await resolveIntegrationTokenBundle("slack", installation.installationKey)
24
24
  : null;
25
- const token = managed?.accessToken ?? (await resolveSecret("SLACK_BOT_TOKEN"));
25
+ const token = tenantId
26
+ ? managed?.accessToken
27
+ : (managed?.accessToken ?? (await resolveSecret("SLACK_BOT_TOKEN")));
26
28
  if (!token) {
27
29
  throw new Error(tenantId
28
30
  ? "That Slack workspace is not connected"
@@ -1 +1 @@
1
- {"version":3,"file":"send-platform-message.js","sourceRoot":"","sources":["../../src/actions/send-platform-message.ts"],"names":[],"mappings":"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","sourcesContent":["import { defineAction } from \"@agent-native/core\";\nimport {\n listIntegrationInstallations,\n resolveIntegrationTokenBundle,\n} from \"@agent-native/core/integrations\";\nimport {\n getRequestOrgId,\n getRequestUserEmail,\n slackAdapter,\n telegramAdapter,\n emailAdapter,\n isEmailConfigured,\n resolveSecret,\n} from \"@agent-native/core/server\";\nimport { z } from \"zod\";\n\nimport { getDestinationById } from \"../server/lib/dispatch-store.js\";\n\nfunction getAdapter(\n platform: \"slack\" | \"telegram\" | \"email\",\n slackToken?: string,\n) {\n if (platform === \"email\") return emailAdapter();\n return platform === \"slack\"\n ? slackAdapter({ resolveBotToken: async () => slackToken })\n : telegramAdapter();\n}\n\nasync function assertOutboundConfigured(\n platform: \"slack\" | \"telegram\" | \"email\",\n tenantId?: string,\n): Promise<string | undefined> {\n if (platform === \"slack\") {\n const userEmail = getRequestUserEmail();\n if (!userEmail) throw new Error(\"An authenticated user is required\");\n const installations = tenantId\n ? await listIntegrationInstallations(\n { userEmail, orgId: getRequestOrgId() ?? null },\n \"slack\",\n )\n : [];\n const installation =\n installations.find(\n (candidate) =>\n candidate.teamId === tenantId || candidate.enterpriseId === tenantId,\n ) ?? null;\n const managed = installation\n ? await resolveIntegrationTokenBundle(\n \"slack\",\n installation.installationKey,\n )\n : null;\n const token =\n managed?.accessToken ?? (await resolveSecret(\"SLACK_BOT_TOKEN\"));\n if (!token) {\n throw new Error(\n tenantId\n ? \"That Slack workspace is not connected\"\n : \"Select a Slack workspace for managed outbound messaging\",\n );\n }\n return token;\n }\n if (platform === \"telegram\" && !(await resolveSecret(\"TELEGRAM_BOT_TOKEN\"))) {\n throw new Error(\"Telegram outbound messaging is not configured\");\n }\n if (platform === \"email\") {\n if (\n !(await resolveSecret(\"EMAIL_AGENT_ADDRESS\")) ||\n !(await isEmailConfigured())\n ) {\n throw new Error(\"Email outbound messaging is not configured\");\n }\n }\n}\n\nexport default defineAction({\n description:\n \"Send a proactive message to a saved Slack, Telegram, or email destination.\",\n schema: z.object({\n platform: z.enum([\"slack\", \"telegram\", \"email\"]).optional(),\n destinationId: z.string().optional().describe(\"Saved destination id\"),\n destination: z.string().optional().describe(\"Raw platform destination id\"),\n threadRef: z.string().optional().describe(\"Optional thread reference\"),\n tenantId: z\n .string()\n .optional()\n .describe(\"Slack workspace/team id for managed installations\"),\n text: z.string().describe(\"Message to send\"),\n }),\n audit: {\n recordInputs: false,\n target: (args) => ({\n type: \"destination\",\n id: args.destinationId || args.destination || \"unknown\",\n visibility: \"private\",\n }),\n summary: (args) => `Sent proactive ${args.platform || \"saved\"} message`,\n },\n run: async ({\n platform,\n destinationId,\n destination,\n threadRef,\n tenantId,\n text,\n }) => {\n const saved = destinationId\n ? await getDestinationById(destinationId)\n : null;\n const resolvedPlatform = (saved?.platform || platform) as\n | \"slack\"\n | \"telegram\"\n | \"email\"\n | undefined;\n const resolvedDestination = saved?.destination || destination;\n const resolvedThreadRef = saved?.threadRef || threadRef || null;\n\n if (!resolvedPlatform || !resolvedDestination) {\n throw new Error(\"A platform and destination are required\");\n }\n\n const slackToken = await assertOutboundConfigured(\n resolvedPlatform,\n tenantId,\n );\n\n const adapter = getAdapter(resolvedPlatform, slackToken);\n if (!adapter.sendMessageToTarget) {\n throw new Error(\n `Platform ${resolvedPlatform} does not support proactive outbound messaging`,\n );\n }\n\n await adapter.sendMessageToTarget(adapter.formatAgentResponse(text), {\n destination: resolvedDestination,\n threadRef: resolvedThreadRef,\n label: saved?.name || undefined,\n tenantId,\n });\n\n return {\n ok: true,\n platform: resolvedPlatform,\n destination: resolvedDestination,\n threadRef: resolvedThreadRef,\n };\n },\n});\n"]}
1
+ {"version":3,"file":"send-platform-message.js","sourceRoot":"","sources":["../../src/actions/send-platform-message.ts"],"names":[],"mappings":"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","sourcesContent":["import { defineAction } from \"@agent-native/core\";\nimport {\n listIntegrationInstallations,\n resolveIntegrationTokenBundle,\n} from \"@agent-native/core/integrations\";\nimport {\n getRequestOrgId,\n getRequestUserEmail,\n slackAdapter,\n telegramAdapter,\n emailAdapter,\n isEmailConfigured,\n resolveSecret,\n} from \"@agent-native/core/server\";\nimport { z } from \"zod\";\n\nimport { getDestinationById } from \"../server/lib/dispatch-store.js\";\n\nfunction getAdapter(\n platform: \"slack\" | \"telegram\" | \"email\",\n slackToken?: string,\n) {\n if (platform === \"email\") return emailAdapter();\n return platform === \"slack\"\n ? slackAdapter({ resolveBotToken: async () => slackToken })\n : telegramAdapter();\n}\n\nasync function assertOutboundConfigured(\n platform: \"slack\" | \"telegram\" | \"email\",\n tenantId?: string,\n): Promise<string | undefined> {\n if (platform === \"slack\") {\n const userEmail = getRequestUserEmail();\n if (!userEmail) throw new Error(\"An authenticated user is required\");\n const installations = tenantId\n ? await listIntegrationInstallations(\n { userEmail, orgId: getRequestOrgId() ?? null },\n \"slack\",\n )\n : [];\n const installation =\n installations.find(\n (candidate) =>\n candidate.teamId === tenantId || candidate.enterpriseId === tenantId,\n ) ?? null;\n const managed = installation\n ? await resolveIntegrationTokenBundle(\n \"slack\",\n installation.installationKey,\n )\n : null;\n const token = tenantId\n ? managed?.accessToken\n : (managed?.accessToken ?? (await resolveSecret(\"SLACK_BOT_TOKEN\")));\n if (!token) {\n throw new Error(\n tenantId\n ? \"That Slack workspace is not connected\"\n : \"Select a Slack workspace for managed outbound messaging\",\n );\n }\n return token;\n }\n if (platform === \"telegram\" && !(await resolveSecret(\"TELEGRAM_BOT_TOKEN\"))) {\n throw new Error(\"Telegram outbound messaging is not configured\");\n }\n if (platform === \"email\") {\n if (\n !(await resolveSecret(\"EMAIL_AGENT_ADDRESS\")) ||\n !(await isEmailConfigured())\n ) {\n throw new Error(\"Email outbound messaging is not configured\");\n }\n }\n}\n\nexport default defineAction({\n description:\n \"Send a proactive message to a saved Slack, Telegram, or email destination.\",\n schema: z.object({\n platform: z.enum([\"slack\", \"telegram\", \"email\"]).optional(),\n destinationId: z.string().optional().describe(\"Saved destination id\"),\n destination: z.string().optional().describe(\"Raw platform destination id\"),\n threadRef: z.string().optional().describe(\"Optional thread reference\"),\n tenantId: z\n .string()\n .optional()\n .describe(\"Slack workspace/team id for managed installations\"),\n text: z.string().describe(\"Message to send\"),\n }),\n audit: {\n recordInputs: false,\n target: (args) => ({\n type: \"destination\",\n id: args.destinationId || args.destination || \"unknown\",\n visibility: \"private\",\n }),\n summary: (args) => `Sent proactive ${args.platform || \"saved\"} message`,\n },\n run: async ({\n platform,\n destinationId,\n destination,\n threadRef,\n tenantId,\n text,\n }) => {\n const saved = destinationId\n ? await getDestinationById(destinationId)\n : null;\n const resolvedPlatform = (saved?.platform || platform) as\n | \"slack\"\n | \"telegram\"\n | \"email\"\n | undefined;\n const resolvedDestination = saved?.destination || destination;\n const resolvedThreadRef = saved?.threadRef || threadRef || null;\n\n if (!resolvedPlatform || !resolvedDestination) {\n throw new Error(\"A platform and destination are required\");\n }\n\n const slackToken = await assertOutboundConfigured(\n resolvedPlatform,\n tenantId,\n );\n\n const adapter = getAdapter(resolvedPlatform, slackToken);\n if (!adapter.sendMessageToTarget) {\n throw new Error(\n `Platform ${resolvedPlatform} does not support proactive outbound messaging`,\n );\n }\n\n await adapter.sendMessageToTarget(adapter.formatAgentResponse(text), {\n destination: resolvedDestination,\n threadRef: resolvedThreadRef,\n label: saved?.name || undefined,\n tenantId,\n });\n\n return {\n ok: true,\n platform: resolvedPlatform,\n destination: resolvedDestination,\n threadRef: resolvedThreadRef,\n };\n },\n});\n"]}
@@ -5,19 +5,6 @@ declare const _default: import("@agent-native/core").ActionDefinition<{
5
5
  content?: string | undefined;
6
6
  scope?: "all" | "selected" | undefined;
7
7
  }, {
8
- id: string;
9
- ownerEmail: string;
10
- orgId: string | null;
11
- kind: string;
12
- name: string;
13
- description: string | null;
14
- path: string;
15
- content: string;
16
- scope: string;
17
- createdBy: string;
18
- createdAt: number;
19
- updatedAt: number;
20
- } | {
21
8
  id: string;
22
9
  ownerEmail: string;
23
10
  orgId: string | null;
@@ -34,6 +21,19 @@ declare const _default: import("@agent-native/core").ActionDefinition<{
34
21
  reviewedAt: number | null;
35
22
  createdAt: number;
36
23
  updatedAt: number;
24
+ } | {
25
+ id: string;
26
+ ownerEmail: string;
27
+ orgId: string | null;
28
+ kind: string;
29
+ name: string;
30
+ description: string | null;
31
+ path: string;
32
+ content: string;
33
+ scope: string;
34
+ createdBy: string;
35
+ createdAt: number;
36
+ updatedAt: number;
37
37
  }>;
38
38
  export default _default;
39
39
  //# sourceMappingURL=update-workspace-resource.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messaging-setup-panel.d.ts","sourceRoot":"","sources":["../../src/components/messaging-setup-panel.tsx"],"names":[],"mappings":"AAoKA,wBAAgB,mBAAmB,oDAs2BlC"}
1
+ {"version":3,"file":"messaging-setup-panel.d.ts","sourceRoot":"","sources":["../../src/components/messaging-setup-panel.tsx"],"names":[],"mappings":"AAyMA,wBAAgB,mBAAmB,oDA05BlC"}
@@ -5,6 +5,7 @@ import { listBuiltInChannelIntegrations, } from "@agent-native/core/integrations
5
5
  import { IconBrandDiscord, IconBrandSlack, IconBrandTelegram, IconBrandTeams, IconBrandWhatsapp, IconCheck, IconChevronRight, IconCopy, IconExternalLink, IconFileDescription, IconInfoCircle, IconLoader2, IconMail, IconPlug, } from "@tabler/icons-react";
6
6
  import { useEffect, useMemo, useState } from "react";
7
7
  import { toast } from "sonner";
8
+ import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from "./ui/accordion.js";
8
9
  import { Button } from "./ui/button.js";
9
10
  import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "./ui/collapsible.js";
10
11
  import { Input } from "./ui/input.js";
@@ -39,11 +40,14 @@ function HelpTooltip({ content }) {
39
40
  }
40
41
  function StatusPill({ tone, label, }) {
41
42
  const toneClass = tone === "success"
42
- ? "border-emerald-500/30 bg-emerald-500/10 text-emerald-300"
43
+ ? "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300"
43
44
  : tone === "warning"
44
- ? "border-amber-500/30 bg-amber-500/10 text-amber-300"
45
- : "border-border bg-muted/40 text-muted-foreground";
46
- return (_jsx("span", { className: `inline-flex items-center rounded-full border px-2.5 py-1 text-[11px] font-medium ${toneClass}`, children: label }));
45
+ ? "bg-amber-500/10 text-amber-700 dark:text-amber-300"
46
+ : "bg-muted text-muted-foreground";
47
+ return (_jsx("span", { className: `inline-flex items-center rounded-full px-2 py-1 text-[11px] font-medium ${toneClass}`, children: label }));
48
+ }
49
+ function DisclosureSection({ title, summary, children, defaultOpen = false, }) {
50
+ return (_jsxs(Collapsible, { defaultOpen: defaultOpen, className: "border-t", children: [_jsxs(CollapsibleTrigger, { className: "group flex w-full cursor-pointer items-center justify-between gap-3 py-3 text-left", children: [_jsxs("span", { className: "min-w-0", children: [_jsx("span", { className: "block text-sm font-medium text-foreground", children: title }), summary ? (_jsx("span", { className: "mt-0.5 block truncate text-xs text-muted-foreground", children: summary })) : null] }), _jsx(IconChevronRight, { className: "h-4 w-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-90" })] }), _jsx(CollapsibleContent, { className: "pb-3", children: children })] }));
47
51
  }
48
52
  /** Render a non-secret env value (e.g. EMAIL_AGENT_ADDRESS) as a copyable
49
53
  * text block. We can't read the actual value from the backend (env-status
@@ -305,7 +309,7 @@ export function MessagingSetupPanel() {
305
309
  setSavingScope(null);
306
310
  }
307
311
  };
308
- return (_jsxs("div", { className: "space-y-4", children: [_jsx("div", { className: "grid gap-4 xl:grid-cols-2", children: CHANNELS.map((platform) => {
312
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx(Accordion, { type: "single", collapsible: true, className: "overflow-hidden rounded-2xl border bg-card", children: CHANNELS.map((platform) => {
309
313
  const status = statusByPlatform.get(platform.id);
310
314
  const configured = !!status?.configured ||
311
315
  (platform.id === "slack" &&
@@ -315,75 +319,95 @@ export function MessagingSetupPanel() {
315
319
  const primaryEnvKeys = envKeys.filter((envKey) => envKey.key !== "SLACK_BOT_TOKEN");
316
320
  const legacyEnvKeys = envKeys.filter((envKey) => envKey.key === "SLACK_BOT_TOKEN");
317
321
  const missingRequiredCredentials = hasMissingRequiredCredentials(envKeys, envStatusByKey);
322
+ const configuredCredentialCount = envKeys.filter((envKey) => envStatusByKey.get(envKey.key)?.configured).length;
323
+ const credentialSummary = envLoading
324
+ ? "Checking saved credentials"
325
+ : missingRequiredCredentials
326
+ ? "Required credentials are missing"
327
+ : `${configuredCredentialCount} saved`;
318
328
  const Icon = PLATFORM_ICONS[platform.iconKey] ?? IconPlug;
319
- return (_jsxs("section", { className: "rounded-2xl border bg-card p-5", children: [_jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-xl border bg-muted/30 text-foreground", children: _jsx(Icon, { size: 18 }) }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("h3", { className: "text-base font-semibold text-foreground", children: platform.name }), _jsx(ConnectionStatus, { configured: configured, enabled: enabled })] }), _jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: platform.description })] })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [_jsx(Button, { asChild: true, variant: "ghost", size: "sm", className: "h-7 px-2 text-xs text-muted-foreground", children: _jsxs("a", { href: platform.documentation.href, target: "_blank", rel: "noreferrer", children: ["Docs", _jsx(IconExternalLink, { className: "ml-1 h-3 w-3" })] }) }), platform.documentation.externalHref ? (_jsx(Button, { asChild: true, variant: "ghost", size: "sm", className: "h-7 px-2 text-xs text-muted-foreground", children: _jsxs("a", { href: platform.documentation.externalHref, target: "_blank", rel: "noreferrer", children: [platform.documentation.externalLabel ?? "Open", _jsx(IconExternalLink, { className: "ml-1 h-3 w-3" })] }) })) : null] })] }), platform.id === "slack" ? (_jsxs("div", { className: "mt-5 space-y-3 rounded-xl border bg-muted/20 p-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: t("messaging.managed.title") }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: t("messaging.managed.description") }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: t("messaging.managed.agentManifestDescription") })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Button, { asChild: true, variant: "outline", size: "sm", children: _jsxs("a", { href: managedSlackAgentManifestUrl(), children: [_jsx(IconFileDescription, { className: "mr-2 h-4 w-4" }), t("messaging.managed.agentManifest")] }) }), missingRequiredCredentials ? (_jsxs(Button, { size: "sm", disabled: true, children: [_jsx(IconBrandSlack, { className: "mr-2 h-4 w-4" }), t("messaging.managed.addToSlack")] })) : (_jsx(Button, { asChild: true, size: "sm", children: _jsxs("a", { href: managedIntegrationOAuthUrl("slack"), children: [_jsx(IconBrandSlack, { className: "mr-2 h-4 w-4" }), t("messaging.managed.addToSlack")] }) }))] }), missingRequiredCredentials ? (_jsx("p", { className: "max-w-72 text-xs text-amber-700 dark:text-amber-300", children: t("messaging.managed.requiredCredentials") })) : null] })] }), installations.length ? (_jsx("div", { className: "space-y-2", children: installations.map((installation) => (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 rounded-lg border bg-background/60 px-3 py-2", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: installation.teamName ||
320
- installation.enterpriseName ||
321
- installation.teamId ||
322
- t("messaging.managed.workspaceFallback") }), _jsx("div", { className: "mt-0.5 text-xs text-muted-foreground", children: t("messaging.managed.scopesUpdated", {
323
- count: installation.scopes.length,
324
- date: formatDate(installation.updatedAt, {
325
- dateStyle: "medium",
326
- }),
327
- }) })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(StatusPill, { tone: installation.health === "healthy"
328
- ? "success"
329
- : installation.health === "degraded" ||
330
- installation.health === "revoked"
331
- ? "warning"
332
- : "neutral", label: t(`messaging.managed.health.${installation.health}`) }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => runInstallationAction(installation, "test"), disabled: installationAction === `test:${installation.id}`, children: t("messaging.managed.test") }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => runInstallationAction(installation, "disconnect"), disabled: installationAction ===
333
- `disconnect:${installation.id}`, children: t("messaging.managed.disconnect") })] })] }, installation.id))) })) : (_jsx("p", { className: "text-xs text-muted-foreground", children: t("messaging.managed.empty") }))] })) : null, platform.id === "slack" && scopes.length ? (_jsxs("div", { className: "mt-4 space-y-3 rounded-xl border bg-muted/20 p-4", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: t("messaging.managed.channelAccessTitle") }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: t("messaging.managed.channelAccessDescription") })] }), scopes.map((scope) => {
334
- const subjectId = JSON.stringify([
335
- scope.platform,
336
- scope.tenantId,
337
- scope.conversationId,
338
- ]);
339
- const budget = budgets.find((item) => item.subjectType === "scope" &&
340
- item.subjectId === subjectId &&
341
- item.period === "month");
342
- return (_jsxs("div", { className: "space-y-3 rounded-lg border bg-background/60 p-3", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("div", { children: [_jsx("div", { className: "font-mono text-xs text-foreground", children: scope.conversationId }), _jsx("div", { className: "mt-0.5 text-xs text-muted-foreground", children: t("messaging.managed.isolatedIdentity", {
343
- trust: t(`messaging.managed.trust.${scope.trust}`),
344
- }) })] }), _jsx(StatusPill, { tone: scope.trust === "trusted" ? "success" : "warning", label: t(`messaging.managed.trust.${scope.trust}`) })] }), _jsx("div", { className: "grid gap-2 sm:grid-cols-3", children: [
345
- [
346
- "requireMention",
347
- t("messaging.managed.requireMention"),
348
- ],
349
- ["allowGuests", t("messaging.managed.allowGuests")],
350
- [
351
- "allowExternalShared",
352
- t("messaging.managed.allowSlackConnect"),
353
- ],
354
- ].map(([key, label]) => (_jsxs("label", { className: "flex items-center justify-between gap-2 rounded-md border px-2.5 py-2 text-xs", children: [label, _jsx(Switch, { checked: scope.policy[key], disabled: savingScope === scope.id, onCheckedChange: (checked) => updateScopePolicy(scope, { [key]: checked }) })] }, key))) }), _jsxs("div", { className: "flex flex-wrap items-end gap-2", children: [_jsxs("div", { className: "min-w-40 flex-1 space-y-1", children: [_jsx("label", { className: "text-xs font-medium text-foreground", children: t("messaging.managed.monthlyBudgetUsd") }), _jsx(Input, { inputMode: "decimal", value: scopeBudget[scope.id] ??
355
- (budget
356
- ? String(budget.limitMicros / 1_000_000)
357
- : ""), onChange: (event) => setScopeBudget((current) => ({
329
+ return (_jsxs(AccordionItem, { value: platform.id, className: "border-b last:border-b-0", children: [_jsx(AccordionTrigger, { className: "gap-3 px-4 text-left hover:no-underline", children: _jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [_jsx(Icon, { className: "h-5 w-5 shrink-0 text-muted-foreground" }), _jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("h3", { className: "text-base font-semibold text-foreground", children: platform.name }), _jsx(ConnectionStatus, { configured: configured, enabled: enabled })] }), _jsx("p", { className: "mt-1 truncate text-sm text-muted-foreground", children: platform.description })] })] }) }), _jsx(AccordionContent, { className: "px-4", children: _jsxs("div", { className: "border-t", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 py-3", children: [_jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: enabled
330
+ ? "Messages are flowing"
331
+ : configured
332
+ ? "Ready to connect"
333
+ : "Finish setup to connect" }), _jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: credentialSummary })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [platform.id === "telegram" && configured ? (_jsx(Button, { variant: "outline", size: "sm", onClick: () => runSetup(platform), disabled: setupPlatform === platform.id, children: setupPlatform === platform.id ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Setting up..."] })) : ("Set up webhook") })) : null, !configured && !enabled ? (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { tabIndex: 0, children: _jsx(Button, { size: "sm", disabled: true, children: "Enable" }) }) }), _jsx(TooltipContent, { children: "Save the required credentials first." })] })) : (_jsx(Button, { size: "sm", onClick: () => togglePlatform(platform, enabled), disabled: togglingPlatform === platform.id, children: togglingPlatform === platform.id ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Saving..."] })) : enabled ? ("Disable") : ("Enable") }))] })] }), platform.id === "slack" ? (_jsx(DisclosureSection, { title: t("messaging.managed.title"), summary: installations.length
334
+ ? `${installations.length} connected`
335
+ : "No workspaces connected yet", children: _jsxs("div", { className: "space-y-3", children: [_jsxs("p", { className: "text-xs text-muted-foreground", children: [t("messaging.managed.description"), " ", t("messaging.managed.agentManifestDescription")] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Button, { asChild: true, variant: "outline", size: "sm", children: _jsxs("a", { href: managedSlackAgentManifestUrl(), children: [_jsx(IconFileDescription, { className: "mr-2 h-4 w-4" }), t("messaging.managed.agentManifest")] }) }), missingRequiredCredentials ? (_jsxs(Button, { size: "sm", disabled: true, children: [_jsx(IconBrandSlack, { className: "mr-2 h-4 w-4" }), t("messaging.managed.addToSlack")] })) : (_jsx(Button, { asChild: true, size: "sm", children: _jsxs("a", { href: managedIntegrationOAuthUrl("slack"), children: [_jsx(IconBrandSlack, { className: "mr-2 h-4 w-4" }), t("messaging.managed.addToSlack")] }) }))] }), missingRequiredCredentials ? (_jsx("p", { className: "text-xs text-amber-700 dark:text-amber-300", children: t("messaging.managed.requiredCredentials") })) : null, installations.length ? (_jsx("div", { className: "divide-y rounded-lg bg-muted/20 px-3", children: installations.map((installation) => (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 py-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: installation.teamName ||
336
+ installation.enterpriseName ||
337
+ installation.teamId ||
338
+ t("messaging.managed.workspaceFallback") }), _jsx("div", { className: "mt-0.5 text-xs text-muted-foreground", children: t("messaging.managed.scopesUpdated", {
339
+ count: installation.scopes.length,
340
+ date: formatDate(installation.updatedAt, {
341
+ dateStyle: "medium",
342
+ }),
343
+ }) })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(StatusPill, { tone: installation.health === "healthy"
344
+ ? "success"
345
+ : installation.health === "degraded" ||
346
+ installation.health === "revoked"
347
+ ? "warning"
348
+ : "neutral", label: t(`messaging.managed.health.${installation.health}`) }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => runInstallationAction(installation, "test"), disabled: installationAction ===
349
+ `test:${installation.id}`, children: t("messaging.managed.test") }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => runInstallationAction(installation, "disconnect"), disabled: installationAction ===
350
+ `disconnect:${installation.id}`, children: t("messaging.managed.disconnect") })] })] }, installation.id))) })) : (_jsx("p", { className: "text-xs text-muted-foreground", children: t("messaging.managed.empty") }))] }) })) : null, platform.id === "slack" && scopes.length ? (_jsx(DisclosureSection, { title: t("messaging.managed.channelAccessTitle"), summary: `${scopes.length} channel${scopes.length === 1 ? "" : "s"}`, children: _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-xs text-muted-foreground", children: t("messaging.managed.channelAccessDescription") }), scopes.map((scope) => {
351
+ const subjectId = JSON.stringify([
352
+ scope.platform,
353
+ scope.tenantId,
354
+ scope.conversationId,
355
+ ]);
356
+ const budget = budgets.find((item) => item.subjectType === "scope" &&
357
+ item.subjectId === subjectId &&
358
+ item.period === "month");
359
+ return (_jsxs(Collapsible, { className: "border-b last:border-b-0", children: [_jsxs(CollapsibleTrigger, { className: "group flex w-full cursor-pointer items-center justify-between gap-3 py-3 text-left", children: [_jsxs("span", { className: "min-w-0", children: [_jsx("span", { className: "block truncate font-mono text-xs text-foreground", children: scope.conversationId }), _jsx("span", { className: "mt-0.5 block text-xs text-muted-foreground", children: t("messaging.managed.isolatedIdentity", {
360
+ trust: t(`messaging.managed.trust.${scope.trust}`),
361
+ }) })] }), _jsxs("span", { className: "flex shrink-0 items-center gap-2", children: [_jsx(StatusPill, { tone: scope.trust === "trusted"
362
+ ? "success"
363
+ : "warning", label: t(`messaging.managed.trust.${scope.trust}`) }), _jsx(IconChevronRight, { className: "h-4 w-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-90" })] })] }), _jsxs(CollapsibleContent, { className: "pb-3", children: [_jsx("div", { className: "grid gap-2 sm:grid-cols-3", children: [
364
+ [
365
+ "requireMention",
366
+ t("messaging.managed.requireMention"),
367
+ ],
368
+ [
369
+ "allowGuests",
370
+ t("messaging.managed.allowGuests"),
371
+ ],
372
+ [
373
+ "allowExternalShared",
374
+ t("messaging.managed.allowSlackConnect"),
375
+ ],
376
+ ].map(([key, label]) => (_jsxs("label", { className: "flex items-center justify-between gap-2 rounded-md border px-2.5 py-2 text-xs", children: [label, _jsx(Switch, { checked: scope.policy[key], disabled: savingScope === scope.id, onCheckedChange: (checked) => updateScopePolicy(scope, {
377
+ [key]: checked,
378
+ }) })] }, key))) }), _jsxs("div", { className: "flex flex-wrap items-end gap-2", children: [_jsxs("div", { className: "min-w-40 flex-1 space-y-1", children: [_jsx("label", { className: "text-xs font-medium text-foreground", children: t("messaging.managed.monthlyBudgetUsd") }), _jsx(Input, { inputMode: "decimal", value: scopeBudget[scope.id] ??
379
+ (budget
380
+ ? String(budget.limitMicros / 1_000_000)
381
+ : ""), onChange: (event) => setScopeBudget((current) => ({
382
+ ...current,
383
+ [scope.id]: event.target.value,
384
+ })), placeholder: "25" })] }), _jsx(Button, { variant: "outline", onClick: () => saveScopeBudget(scope), disabled: savingScope === `budget:${scope.id}`, children: t("messaging.managed.saveBudget") })] })] })] }, scope.id));
385
+ })] }) })) : null, _jsx(DisclosureSection, { title: "Setup steps", summary: `${platform.setup.steps.length} step${platform.setup.steps.length === 1 ? "" : "s"}`, children: _jsx("ol", { className: "space-y-2 rounded-lg bg-muted/20 px-3 py-3 text-sm text-muted-foreground", children: platform.setup.steps.map((step, index) => (_jsxs("li", { className: "flex gap-2", children: [_jsxs("span", { className: "text-muted-foreground/60", children: [index + 1, "."] }), _jsx("span", { children: step })] }, step))) }) }), _jsxs(DisclosureSection, { title: "Credentials", summary: credentialSummary, children: [_jsx("div", { className: "space-y-3", children: primaryEnvKeys.map((envKey) => {
386
+ const envStatus = envStatusByKey.get(envKey.key);
387
+ const isConfigured = !!envStatus?.configured;
388
+ const helpText = envKey.helpText ?? envStatus?.helpText;
389
+ const label = envKey.label || envStatus?.label || envKey.key;
390
+ // Email agent address is not a secret — show it plainly
391
+ // so users can copy and share it.
392
+ const isPublicValue = envKey.key === "EMAIL_AGENT_ADDRESS";
393
+ return (_jsxs("div", { className: "space-y-1.5", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs("label", { className: "text-xs font-medium text-foreground", children: [label, !envKey.required ? (_jsx("span", { className: "ml-1 text-muted-foreground", children: "(optional)" })) : null] }), helpText ? (_jsx(HelpTooltip, { content: helpText })) : null] }), isConfigured ? (_jsx(StatusPill, { tone: "success", label: "Saved" })) : (_jsx(StatusPill, { tone: "neutral", label: envKey.required ? "Missing" : "Not set" }))] }), isConfigured && isPublicValue ? (_jsx(PublicValueReveal, { envKey: envKey.key })) : !isConfigured ? (_jsx(Input, { type: isPublicValue ? "text" : "password", value: envValues[envKey.key] || "", onChange: (event) => setEnvValues((current) => ({
358
394
  ...current,
359
- [scope.id]: event.target.value,
360
- })), placeholder: "25" })] }), _jsx(Button, { variant: "outline", onClick: () => saveScopeBudget(scope), disabled: savingScope === `budget:${scope.id}`, children: t("messaging.managed.saveBudget") })] })] }, scope.id));
361
- })] })) : null, _jsxs(Collapsible, { className: "mt-5", children: [_jsxs(CollapsibleTrigger, { className: "group flex w-full cursor-pointer items-center gap-1.5 text-xs font-medium text-muted-foreground hover:text-foreground", children: [_jsx(IconChevronRight, { className: "h-3.5 w-3.5 transition-transform group-data-[state=open]:rotate-90" }), _jsx("span", { children: "Setup steps" })] }), _jsx(CollapsibleContent, { children: _jsx("div", { className: "mt-2 rounded-xl border bg-muted/20 p-4", children: _jsx("ol", { className: "space-y-2 text-sm text-muted-foreground", children: platform.setup.steps.map((step, index) => (_jsxs("li", { className: "flex gap-2", children: [_jsxs("span", { className: "text-muted-foreground/60", children: [index + 1, "."] }), _jsx("span", { children: step })] }, step))) }) }) })] }), _jsxs("div", { className: "mt-4 space-y-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: "Credentials" }), envLoading ? (_jsx("span", { className: "text-xs text-muted-foreground", children: "Checking..." })) : null] }), _jsx("div", { className: "space-y-3", children: primaryEnvKeys.map((envKey) => {
362
- const envStatus = envStatusByKey.get(envKey.key);
363
- const isConfigured = !!envStatus?.configured;
364
- const helpText = envKey.helpText ?? envStatus?.helpText;
365
- const label = envKey.label || envStatus?.label || envKey.key;
366
- // Email agent address is not a secret — show it plainly
367
- // so users can copy and share it.
368
- const isPublicValue = envKey.key === "EMAIL_AGENT_ADDRESS";
369
- return (_jsxs("div", { className: "space-y-1.5", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs("label", { className: "text-xs font-medium text-foreground", children: [label, !envKey.required ? (_jsx("span", { className: "ml-1 text-muted-foreground", children: "(optional)" })) : null] }), helpText ? (_jsx(HelpTooltip, { content: helpText })) : null] }), isConfigured ? (_jsx(StatusPill, { tone: "success", label: "Saved" })) : (_jsx(StatusPill, { tone: "neutral", label: envKey.required ? "Missing" : "Not set" }))] }), isConfigured && isPublicValue ? (_jsx(PublicValueReveal, { envKey: envKey.key })) : !isConfigured ? (_jsx(Input, { type: isPublicValue ? "text" : "password", value: envValues[envKey.key] || "", onChange: (event) => setEnvValues((current) => ({
370
- ...current,
371
- [envKey.key]: event.target.value,
372
- })), placeholder: isPublicValue
373
- ? "agent@yourcompany.com"
374
- : `Enter ${label}`, autoComplete: "off" })) : null] }, envKey.key));
375
- }) }), legacyEnvKeys.length ? (_jsxs(Collapsible, { children: [_jsxs(CollapsibleTrigger, { className: "group flex w-full cursor-pointer items-center gap-1.5 text-xs font-medium text-muted-foreground hover:text-foreground", children: [_jsx(IconChevronRight, { className: "h-3.5 w-3.5 transition-transform group-data-[state=open]:rotate-90" }), _jsx("span", { children: legacyEnvKeys[0]?.label })] }), _jsx(CollapsibleContent, { children: _jsxs("div", { className: "mt-2 space-y-3 rounded-xl border border-amber-500/30 bg-amber-500/5 p-4", children: [_jsx("p", { className: "text-xs text-muted-foreground", children: legacyEnvKeys[0]?.helpText }), legacyEnvKeys.map((envKey) => {
376
- const envStatus = envStatusByKey.get(envKey.key);
377
- const isConfigured = !!envStatus?.configured;
378
- const helpText = envKey.helpText ?? envStatus?.helpText;
379
- const label = envKey.label || envStatus?.label || envKey.key;
380
- return (_jsxs("div", { className: "space-y-1.5", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("label", { className: "text-xs font-medium text-foreground", children: label }), helpText ? (_jsx(HelpTooltip, { content: helpText })) : null] }), _jsx(StatusPill, { tone: isConfigured ? "success" : "neutral", label: isConfigured ? "Saved" : "Not set" })] }), !isConfigured ? (_jsx(Input, { type: "password", value: envValues[envKey.key] || "", onChange: (event) => setEnvValues((current) => ({
381
- ...current,
382
- [envKey.key]: event.target.value,
383
- })), placeholder: `Enter ${label}`, autoComplete: "off" })) : null] }, envKey.key));
384
- }), legacyEnvKeys.some((envKey) => !envStatusByKey.get(envKey.key)?.configured) ? (_jsx(Button, { variant: "outline", onClick: () => saveEnvKeys(platform, legacyEnvKeys.map((envKey) => envKey.key)), disabled: savingKeysFor === platform.id, children: savingKeysFor === platform.id
385
- ? "Saving..."
386
- : "Save credentials" })) : null] }) })] })) : null, missingRequiredCredentials ? (_jsx(Button, { variant: "outline", onClick: () => saveEnvKeys(platform, envKeys.map((k) => k.key)), disabled: savingKeysFor === platform.id, children: savingKeysFor === platform.id ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Saving..."] })) : ("Save credentials") })) : null] }), status?.webhookUrl ? (_jsxs("div", { className: "mt-4 space-y-2", children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: "Webhook URL" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("code", { className: "flex-1 truncate rounded-md border bg-muted/30 px-3 py-2 text-xs text-foreground", children: status.webhookUrl }), _jsx(Button, { variant: "outline", size: "icon", onClick: () => copyWebhook(status.webhookUrl), "aria-label": `Copy ${platform.name} webhook URL`, children: copiedWebhook === status.webhookUrl ? (_jsx(IconCheck, { className: "h-4 w-4" })) : (_jsx(IconCopy, { className: "h-4 w-4" })) })] })] })) : null, _jsxs("div", { className: "mt-5 flex flex-wrap items-center justify-end gap-2 border-t border-border pt-4", children: [platform.id === "telegram" && configured ? (_jsx(Button, { variant: "outline", onClick: () => runSetup(platform), disabled: setupPlatform === platform.id, children: setupPlatform === platform.id ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Setting up..."] })) : ("Set up webhook") })) : null, !configured && !enabled ? (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { tabIndex: 0, children: _jsx(Button, { disabled: true, children: "Enable" }) }) }), _jsx(TooltipContent, { children: "Save the required credentials first." })] })) : (_jsx(Button, { onClick: () => togglePlatform(platform, enabled), disabled: togglingPlatform === platform.id, children: togglingPlatform === platform.id ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Saving..."] })) : enabled ? ("Disable") : ("Enable") }))] })] }, platform.id));
395
+ [envKey.key]: event.target.value,
396
+ })), placeholder: isPublicValue
397
+ ? "agent@yourcompany.com"
398
+ : `Enter ${label}`, autoComplete: "off" })) : null] }, envKey.key));
399
+ }) }), legacyEnvKeys.length ? (_jsxs(Collapsible, { children: [_jsxs(CollapsibleTrigger, { className: "group flex w-full cursor-pointer items-center gap-1.5 text-xs font-medium text-muted-foreground hover:text-foreground", children: [_jsx(IconChevronRight, { className: "h-3.5 w-3.5 transition-transform group-data-[state=open]:rotate-90" }), _jsx("span", { children: legacyEnvKeys[0]?.label })] }), _jsx(CollapsibleContent, { children: _jsxs("div", { className: "mt-2 space-y-3 rounded-xl border border-amber-500/30 bg-amber-500/5 p-4", children: [_jsx("p", { className: "text-xs text-muted-foreground", children: legacyEnvKeys[0]?.helpText }), legacyEnvKeys.map((envKey) => {
400
+ const envStatus = envStatusByKey.get(envKey.key);
401
+ const isConfigured = !!envStatus?.configured;
402
+ const helpText = envKey.helpText ?? envStatus?.helpText;
403
+ const label = envKey.label || envStatus?.label || envKey.key;
404
+ return (_jsxs("div", { className: "space-y-1.5", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("label", { className: "text-xs font-medium text-foreground", children: label }), helpText ? (_jsx(HelpTooltip, { content: helpText })) : null] }), _jsx(StatusPill, { tone: isConfigured ? "success" : "neutral", label: isConfigured ? "Saved" : "Not set" })] }), !isConfigured ? (_jsx(Input, { type: "password", value: envValues[envKey.key] || "", onChange: (event) => setEnvValues((current) => ({
405
+ ...current,
406
+ [envKey.key]: event.target.value,
407
+ })), placeholder: `Enter ${label}`, autoComplete: "off" })) : null] }, envKey.key));
408
+ }), legacyEnvKeys.some((envKey) => !envStatusByKey.get(envKey.key)?.configured) ? (_jsx(Button, { variant: "outline", onClick: () => saveEnvKeys(platform, legacyEnvKeys.map((envKey) => envKey.key)), disabled: savingKeysFor === platform.id, children: savingKeysFor === platform.id
409
+ ? "Saving..."
410
+ : "Save credentials" })) : null] }) })] })) : null, missingRequiredCredentials ? (_jsx(Button, { variant: "outline", onClick: () => saveEnvKeys(platform, envKeys.map((k) => k.key)), disabled: savingKeysFor === platform.id, children: savingKeysFor === platform.id ? (_jsxs(_Fragment, { children: [_jsx(IconLoader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Saving..."] })) : ("Save credentials") })) : null] }), status?.webhookUrl ? (_jsx(DisclosureSection, { title: "Webhook URL", summary: "Copy the endpoint for this channel", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("code", { className: "flex-1 truncate rounded-md bg-muted/30 px-3 py-2 text-xs text-foreground", children: status.webhookUrl }), _jsx(Button, { variant: "outline", size: "icon", onClick: () => copyWebhook(status.webhookUrl), "aria-label": `Copy ${platform.name} webhook URL`, children: copiedWebhook === status.webhookUrl ? (_jsx(IconCheck, { className: "h-4 w-4" })) : (_jsx(IconCopy, { className: "h-4 w-4" })) })] }) })) : null, _jsx(DisclosureSection, { title: "Resources", summary: "Documentation and external links", children: _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Button, { asChild: true, variant: "ghost", size: "sm", className: "px-0 text-xs text-muted-foreground hover:bg-transparent hover:text-foreground", children: _jsxs("a", { href: platform.documentation.href, target: "_blank", rel: "noreferrer", children: ["Docs", _jsx(IconExternalLink, { className: "ml-1 h-3 w-3" })] }) }), platform.documentation.externalHref ? (_jsx(Button, { asChild: true, variant: "ghost", size: "sm", className: "px-0 text-xs text-muted-foreground hover:bg-transparent hover:text-foreground", children: _jsxs("a", { href: platform.documentation.externalHref, target: "_blank", rel: "noreferrer", children: [platform.documentation.externalLabel ?? "Open", _jsx(IconExternalLink, { className: "ml-1 h-3 w-3" })] }) })) : null] }) })] }) })] }, platform.id));
387
411
  }) }), loading ? (_jsx("div", { className: "rounded-2xl border border-dashed px-4 py-6 text-sm text-muted-foreground", children: "Loading messaging status..." })) : null] }));
388
412
  }
389
413
  //# sourceMappingURL=messaging-setup-panel.js.map