@agent-native/dispatch 0.31.3 → 0.31.5
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/components/layout/Layout.d.ts.map +1 -1
- package/dist/components/layout/Layout.js +1 -1
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/components/workspace-app-card.d.ts.map +1 -1
- package/dist/components/workspace-app-card.js +32 -4
- package/dist/components/workspace-app-card.js.map +1 -1
- package/dist/routes/pages/transactional-email.$appId.$id.d.ts.map +1 -1
- package/dist/routes/pages/transactional-email.$appId.$id.js.map +1 -1
- package/dist/routes/pages/transactional-email.js.map +1 -1
- package/dist/server/lib/mcp-gateway.d.ts.map +1 -1
- package/dist/server/lib/mcp-gateway.js +1 -1
- package/dist/server/lib/mcp-gateway.js.map +1 -1
- package/package.json +3 -3
- package/src/components/layout/Layout.tsx +1 -11
- package/src/components/workspace-app-card.spec.tsx +104 -8
- package/src/components/workspace-app-card.tsx +123 -68
- package/src/routes/pages/transactional-email.$appId.$id.tsx +1 -2
- package/src/routes/pages/transactional-email.tsx +1 -1
- package/src/server/lib/mcp-gateway.ts +1 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-app-card.d.ts","sourceRoot":"","sources":["../../src/components/workspace-app-card.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"workspace-app-card.d.ts","sourceRoot":"","sources":["../../src/components/workspace-app-card.tsx"],"names":[],"mappings":"AA6BA,OAAO,EAOL,KAAK,mBAAmB,EACzB,MAAM,uBAAuB,CAAC;AAkD/B,wBAAgB,gBAAgB,CAAC,EAC/B,GAAG,EACH,SAAS,EACT,QAAgB,EAChB,cAAc,GACf,EAAE;IACD,GAAG,EAAE,mBAAmB,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B,mDAwNA"}
|
|
@@ -3,8 +3,8 @@ import { APP_ACTION_MENU_CONTENT_CLASS } from "@agent-native/core/client/chat-fi
|
|
|
3
3
|
import { useActionMutation, useActionQuery, } from "@agent-native/core/client/hooks";
|
|
4
4
|
import { useT } from "@agent-native/core/client/i18n";
|
|
5
5
|
import { ShareButton } from "@agent-native/core/client/sharing";
|
|
6
|
-
import { IconChevronDown, IconChevronRight, IconClockHour4, IconEdit, IconEye, IconEyeOff, IconFileText, IconKey, IconPin, IconSettings, IconTrash, IconUser, IconUsersGroup, IconWorld, } from "@tabler/icons-react";
|
|
7
|
-
import { useEffect, useState } from "react";
|
|
6
|
+
import { IconChevronDown, IconChevronRight, IconClockHour4, IconEdit, IconEye, IconEyeOff, IconFileText, IconKey, IconPin, IconShare3, IconSettings, IconTrash, IconUser, IconUsersGroup, IconWorld, } from "@tabler/icons-react";
|
|
7
|
+
import { useEffect, useRef, useState } from "react";
|
|
8
8
|
import { useNavigate } from "react-router";
|
|
9
9
|
import { toast } from "sonner";
|
|
10
10
|
import { cn } from "../lib/utils.js";
|
|
@@ -24,6 +24,17 @@ import { Textarea } from "./ui/textarea.js";
|
|
|
24
24
|
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip.js";
|
|
25
25
|
import { AppResourceEffectiveStack } from "./workspace-resource-effective-stack.js";
|
|
26
26
|
const APP_CARD_ACTION_CLASS = "size-7 rounded-md p-0 text-muted-foreground transition-[background-color,color] hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring data-[state=open]:bg-accent data-[state=open]:text-foreground";
|
|
27
|
+
function deferWorkspaceAppOverlayOpen(event, closeMenu, openOverlay) {
|
|
28
|
+
event.preventDefault();
|
|
29
|
+
closeMenu();
|
|
30
|
+
if (typeof window !== "undefined" &&
|
|
31
|
+
typeof window.requestAnimationFrame === "function") {
|
|
32
|
+
window.requestAnimationFrame(() => openOverlay());
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
setTimeout(openOverlay, 0);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
27
38
|
export function WorkspaceAppCard({ app, className, isPinned = false, onTogglePinned, }) {
|
|
28
39
|
const t = useT();
|
|
29
40
|
const href = workspaceAppHref(app);
|
|
@@ -95,10 +106,11 @@ export function WorkspaceAppCard({ app, className, isPinned = false, onTogglePin
|
|
|
95
106
|
name: app.name,
|
|
96
107
|
defaultValue: isPinned ? "Unpin this app" : "Pin this app",
|
|
97
108
|
});
|
|
98
|
-
return (_jsxs(_Fragment, { children: [_jsxs(AppListRow, { className: cn(!href && "opacity-60", isArchived && "opacity-70", className), children: [_jsx(AppIcon, { id: app.id, name: app.name, size: "sm" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("h3", { className: "truncate text-sm font-semibold text-foreground", children: app.name }), app.description || isPending ? (_jsx("p", { className: "mt-0.5 truncate text-xs text-muted-foreground", children: app.description || pendingLabel })) : null, _jsxs("div", { className: "mt-1.5 flex min-w-0 flex-wrap items-center gap-2 text-[11px] text-muted-foreground", children: [isPending ? (_jsxs("span", { className: "inline-flex min-w-0 items-center gap-1 rounded-full bg-muted px-2 py-0.5", children: [_jsx(IconClockHour4, { size: 12 }), _jsx("span", { className: "truncate", children: pendingLabel })] })) : null, isArchived ? (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5", children: [_jsx(IconEyeOff, { size: 12 }), "Hidden"] })) : null, audience === "public" ? (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5", children: [_jsx(IconWorld, { size: 12 }), "Public"] })) : null] })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [_jsx(WorkspaceAppOpenActions, { app: app, href: directHref ?? href, openDirectly: Boolean(directHref), isPinned: isPinned, pinLabel: pinLabel, pendingOpenLabel: pendingOpenLabel, onTogglePinned: onTogglePinned }),
|
|
109
|
+
return (_jsxs(_Fragment, { children: [_jsxs(AppListRow, { className: cn(!href && "opacity-60", isArchived && "opacity-70", className), children: [_jsx(AppIcon, { id: app.id, name: app.name, size: "sm" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("h3", { className: "truncate text-sm font-semibold text-foreground", children: app.name }), app.description || isPending ? (_jsx("p", { className: "mt-0.5 truncate text-xs text-muted-foreground", children: app.description || pendingLabel })) : null, _jsxs("div", { className: "mt-1.5 flex min-w-0 flex-wrap items-center gap-2 text-[11px] text-muted-foreground", children: [isPending ? (_jsxs("span", { className: "inline-flex min-w-0 items-center gap-1 rounded-full bg-muted px-2 py-0.5", children: [_jsx(IconClockHour4, { size: 12 }), _jsx("span", { className: "truncate", children: pendingLabel })] })) : null, isArchived ? (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5", children: [_jsx(IconEyeOff, { size: 12 }), "Hidden"] })) : null, audience === "public" ? (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5", children: [_jsx(IconWorld, { size: 12 }), "Public"] })) : null] })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [_jsx(WorkspaceAppOpenActions, { app: app, href: directHref ?? href, openDirectly: Boolean(directHref), isPinned: isPinned, pinLabel: pinLabel, pendingOpenLabel: pendingOpenLabel, onTogglePinned: onTogglePinned }), _jsx(WorkspaceAppSettings, { app: app, isArchived: isArchived, isPending: isPending, onEdit: () => setEditOpen(true), onKeys: () => setKeysOpen(true), onResources: () => setResourcesOpen(true), onArchive: handleArchive, onUnarchive: handleUnarchive, onRemovePending: handleRemovePending, labels: {
|
|
99
110
|
createdBy: t("agents.dashboardMetadataCreatedBy"),
|
|
100
111
|
owner: t("dispatch.pages.appMetadataOwner"),
|
|
101
112
|
teams: t("dispatch.pages.appMetadataTeams"),
|
|
113
|
+
share: t("share.share", { defaultValue: "Share" }),
|
|
102
114
|
} })] })] }), _jsx(Dialog, { open: editOpen, onOpenChange: setEditOpen, children: _jsxs(DialogContent, { children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: "Edit app details" }) }), _jsxs("form", { className: "space-y-4", onSubmit: handleMetadataSubmit, children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: `app-name-${app.id}`, children: "Name" }), _jsx(Input, { id: `app-name-${app.id}`, value: draftName, maxLength: 120, onChange: (event) => setDraftName(event.target.value) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: `app-description-${app.id}`, children: "Description" }), _jsx(Textarea, { id: `app-description-${app.id}`, value: draftDescription, maxLength: 500, rows: 4, onChange: (event) => setDraftDescription(event.target.value) })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "outline", onClick: () => setEditOpen(false), children: "Cancel" }), _jsx(Button, { type: "submit", disabled: updateMetadata.isPending, children: updateMetadata.isPending ? "Saving..." : "Save" })] })] })] }) }), _jsx(Dialog, { open: keysOpen, onOpenChange: setKeysOpen, children: _jsxs(DialogContent, { className: "max-w-md", children: [_jsxs(DialogHeader, { children: [_jsxs(DialogTitle, { children: ["Manage keys for ", app.name] }), _jsx(DialogDescription, { children: "Choose which workspace credentials this app can use." })] }), _jsx(AppKeysPanel, { appId: app.id, appName: app.name }), _jsx(DialogFooter, { children: _jsx(Button, { type: "button", onClick: () => setKeysOpen(false), children: "Done" }) })] }) }), _jsx(AppResourcesDialog, { app: app, open: resourcesOpen, onOpenChange: setResourcesOpen })] }));
|
|
103
115
|
}
|
|
104
116
|
function WorkspaceAppOpenActions({ app, href, openDirectly, isPinned, pinLabel, pendingOpenLabel, onTogglePinned, }) {
|
|
@@ -123,7 +135,23 @@ function WorkspaceAppOpenActions({ app, href, openDirectly, isPinned, pinLabel,
|
|
|
123
135
|
: undefined }));
|
|
124
136
|
}
|
|
125
137
|
function WorkspaceAppSettings({ app, isArchived, isPending, onEdit, onKeys, onResources, onArchive, onUnarchive, onRemovePending, labels, }) {
|
|
126
|
-
|
|
138
|
+
const [shareOpen, setShareOpen] = useState(false);
|
|
139
|
+
const [settingsOpen, setSettingsOpen] = useState(false);
|
|
140
|
+
const settingsTriggerRef = useRef(null);
|
|
141
|
+
const handleShareOpenChange = (open) => {
|
|
142
|
+
setShareOpen(open);
|
|
143
|
+
if (open)
|
|
144
|
+
return;
|
|
145
|
+
const restoreSettingsFocus = () => settingsTriggerRef.current?.focus();
|
|
146
|
+
if (typeof window !== "undefined" &&
|
|
147
|
+
typeof window.requestAnimationFrame === "function") {
|
|
148
|
+
window.requestAnimationFrame(restoreSettingsFocus);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
setTimeout(restoreSettingsFocus, 0);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
return (_jsxs(_Fragment, { children: [_jsxs(DropdownMenu, { open: settingsOpen, onOpenChange: setSettingsOpen, children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { type: "button", variant: "ghost", size: "sm", ref: settingsTriggerRef, "aria-label": `Settings for ${app.name}`, className: APP_CARD_ACTION_CLASS, children: _jsx(IconSettings, { size: 15 }) }) }) }), _jsx(TooltipContent, { children: "App settings" })] }), _jsxs(DropdownMenuContent, { align: "end", className: cn(APP_ACTION_MENU_CONTENT_CLASS, "min-w-max"), children: [_jsxs(DropdownMenuItem, { onSelect: onEdit, children: [_jsx(IconEdit, { size: 14, "aria-hidden": "true" }), "Edit details"] }), !isPending ? (_jsxs(DropdownMenuItem, { onSelect: (event) => deferWorkspaceAppOverlayOpen(event, () => setSettingsOpen(false), () => setShareOpen(true)), children: [_jsx(IconShare3, { size: 14, "aria-hidden": "true" }), labels.share] })) : null, !isPending && !isArchived ? (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: onKeys, children: [_jsx(IconKey, { size: 14, "aria-hidden": "true" }), "Manage keys"] }), _jsxs(DropdownMenuItem, { onSelect: onResources, children: [_jsx(IconFileText, { size: 14, "aria-hidden": "true" }), "Agent resources"] })] })) : null, isPending ? (_jsxs(DropdownMenuItem, { onSelect: onRemovePending, className: "text-destructive focus:text-destructive", children: [_jsx(IconTrash, { size: 14, "aria-hidden": "true" }), "Remove from list"] })) : isArchived ? (_jsxs(DropdownMenuItem, { onSelect: onUnarchive, children: [_jsx(IconEye, { size: 14, "aria-hidden": "true" }), "Restore to list"] })) : (_jsxs(DropdownMenuItem, { onSelect: onArchive, children: [_jsx(IconEyeOff, { size: 14, "aria-hidden": "true" }), "Hide from list"] })), _jsx(WorkspaceAppMetadata, { app: app, labels: labels })] })] }), !isPending && shareOpen ? (_jsx(ShareButton, { resourceType: "workspace-app", resourceId: app.id, resourceTitle: app.name, defaultOpen: true, onOpenChange: handleShareOpenChange, triggerClassName: "sr-only" })) : null] }));
|
|
127
155
|
}
|
|
128
156
|
function WorkspaceAppMetadata({ app, labels, }) {
|
|
129
157
|
const trackedText = (value) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-app-card.js","sourceRoot":"","sources":["../../src/components/workspace-app-card.tsx"],"names":[],"mappings":"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","sourcesContent":["import { APP_ACTION_MENU_CONTENT_CLASS } from \"@agent-native/core/client/chat-first\";\nimport {\n useActionMutation,\n useActionQuery,\n} from \"@agent-native/core/client/hooks\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport { ShareButton } from \"@agent-native/core/client/sharing\";\nimport {\n IconChevronDown,\n IconChevronRight,\n IconClockHour4,\n IconEdit,\n IconEye,\n IconEyeOff,\n IconFileText,\n IconKey,\n IconPin,\n IconSettings,\n IconTrash,\n IconUser,\n IconUsersGroup,\n IconWorld,\n} from \"@tabler/icons-react\";\nimport { useEffect, useState, type FormEvent } from \"react\";\nimport { useNavigate } from \"react-router\";\nimport { toast } from \"sonner\";\n\nimport { cn } from \"../lib/utils\";\nimport {\n isPathMountedWorkspaceApp,\n isWorkspaceSsoApp,\n navigateToWorkspaceApp,\n workspaceAppDirectHref,\n workspaceAppHref,\n workspaceAppRoute,\n type WorkspaceAppSummary,\n} from \"../lib/workspace-apps\";\nimport { ActionQueryError } from \"./action-query-error\";\nimport { AppIcon } from \"./app-icon\";\nimport { AppKeysPanel } from \"./app-keys-popover\";\nimport { AppListRow } from \"./app-list-row\";\nimport { AppOpenActions } from \"./app-open-actions\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from \"./ui/dialog\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"./ui/dropdown-menu\";\nimport { Input } from \"./ui/input\";\nimport { Label } from \"./ui/label\";\nimport { Textarea } from \"./ui/textarea\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"./ui/tooltip\";\nimport { AppResourceEffectiveStack } from \"./workspace-resource-effective-stack\";\n\nconst APP_CARD_ACTION_CLASS =\n \"size-7 rounded-md p-0 text-muted-foreground transition-[background-color,color] hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring data-[state=open]:bg-accent data-[state=open]:text-foreground\";\n\nexport function WorkspaceAppCard({\n app,\n className,\n isPinned = false,\n onTogglePinned,\n}: {\n app: WorkspaceAppSummary;\n className?: string;\n isPinned?: boolean;\n onTogglePinned?: () => void;\n}) {\n const t = useT();\n const href = workspaceAppHref(app);\n const directHref =\n app.status !== \"pending\" &&\n !isWorkspaceSsoApp(app) &&\n isPathMountedWorkspaceApp(app)\n ? workspaceAppDirectHref(app, \"/\")\n : null;\n const isPending = app.status === \"pending\";\n const pendingLabel = app.statusLabel || \"Builder branch\";\n const pendingOpenLabel = t(\"dispatch.pages.openBuilderBranch\", {\n defaultValue: \"Open in Builder\",\n });\n const isArchived = !!app.archived;\n const audience = app.audience ?? \"internal\";\n const [editOpen, setEditOpen] = useState(false);\n const [keysOpen, setKeysOpen] = useState(false);\n const [resourcesOpen, setResourcesOpen] = useState(false);\n const [draftName, setDraftName] = useState(app.name);\n const [draftDescription, setDraftDescription] = useState(\n app.description || \"\",\n );\n\n useEffect(() => {\n if (editOpen) return;\n setDraftName(app.name);\n setDraftDescription(app.description || \"\");\n }, [app.description, app.name, editOpen]);\n\n const archive = useActionMutation(\"archive-workspace-app\", {\n onError: (err) =>\n toast.error(`Could not hide ${app.name}: ${stringifyError(err)}`),\n });\n const unarchive = useActionMutation(\"unarchive-workspace-app\", {\n onError: (err) =>\n toast.error(`Could not restore ${app.name}: ${stringifyError(err)}`),\n });\n const removePending = useActionMutation(\"remove-pending-workspace-app\", {\n onError: (err) =>\n toast.error(`Could not remove ${app.name}: ${stringifyError(err)}`),\n });\n const updateMetadata = useActionMutation(\"update-workspace-app-metadata\", {\n onSuccess: () => {\n toast.success(`Updated ${draftName.trim() || app.name}`);\n setEditOpen(false);\n },\n onError: (err) =>\n toast.error(`Could not update ${app.name}: ${stringifyError(err)}`),\n });\n\n const handleArchive = () => {\n archive.mutate({ appId: app.id });\n toast.success(`Hid ${app.name} from the Apps list`);\n };\n const handleUnarchive = () => {\n unarchive.mutate({ appId: app.id });\n toast.success(`Restored ${app.name} to the Apps list`);\n };\n const handleRemovePending = () => {\n removePending.mutate({ appId: app.id });\n toast.success(`Removed pending ${app.name}`);\n };\n const handleMetadataSubmit = (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n const name = draftName.trim();\n if (!name) {\n toast.error(\"App name is required.\");\n return;\n }\n updateMetadata.mutate({\n appId: app.id,\n name,\n description: draftDescription.trim(),\n });\n };\n const pinLabel = t(\n isPinned ? \"dispatch.pages.unpinApp\" : \"dispatch.pages.pinApp\",\n {\n name: app.name,\n defaultValue: isPinned ? \"Unpin this app\" : \"Pin this app\",\n },\n );\n\n return (\n <>\n <AppListRow\n className={cn(\n !href && \"opacity-60\",\n isArchived && \"opacity-70\",\n className,\n )}\n >\n <AppIcon id={app.id} name={app.name} size=\"sm\" />\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"truncate text-sm font-semibold text-foreground\">\n {app.name}\n </h3>\n {app.description || isPending ? (\n <p className=\"mt-0.5 truncate text-xs text-muted-foreground\">\n {app.description || pendingLabel}\n </p>\n ) : null}\n <div className=\"mt-1.5 flex min-w-0 flex-wrap items-center gap-2 text-[11px] text-muted-foreground\">\n {isPending ? (\n <span className=\"inline-flex min-w-0 items-center gap-1 rounded-full bg-muted px-2 py-0.5\">\n <IconClockHour4 size={12} />\n <span className=\"truncate\">{pendingLabel}</span>\n </span>\n ) : null}\n {isArchived ? (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5\">\n <IconEyeOff size={12} />\n Hidden\n </span>\n ) : null}\n {audience === \"public\" ? (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5\">\n <IconWorld size={12} />\n Public\n </span>\n ) : null}\n </div>\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <WorkspaceAppOpenActions\n app={app}\n href={directHref ?? href}\n openDirectly={Boolean(directHref)}\n isPinned={isPinned}\n pinLabel={pinLabel}\n pendingOpenLabel={pendingOpenLabel}\n onTogglePinned={onTogglePinned}\n />\n {!isPending ? (\n <div className=\"pointer-events-auto\">\n <ShareButton\n resourceType=\"workspace-app\"\n resourceId={app.id}\n resourceTitle={app.name}\n trigger=\"icon\"\n triggerClassName={APP_CARD_ACTION_CLASS}\n />\n </div>\n ) : null}\n <WorkspaceAppSettings\n app={app}\n isArchived={isArchived}\n isPending={isPending}\n onEdit={() => setEditOpen(true)}\n onKeys={() => setKeysOpen(true)}\n onResources={() => setResourcesOpen(true)}\n onArchive={handleArchive}\n onUnarchive={handleUnarchive}\n onRemovePending={handleRemovePending}\n labels={{\n createdBy: t(\"agents.dashboardMetadataCreatedBy\"),\n owner: t(\"dispatch.pages.appMetadataOwner\"),\n teams: t(\"dispatch.pages.appMetadataTeams\"),\n }}\n />\n </div>\n </AppListRow>\n <Dialog open={editOpen} onOpenChange={setEditOpen}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Edit app details</DialogTitle>\n </DialogHeader>\n <form className=\"space-y-4\" onSubmit={handleMetadataSubmit}>\n <div className=\"space-y-2\">\n <Label htmlFor={`app-name-${app.id}`}>Name</Label>\n <Input\n id={`app-name-${app.id}`}\n value={draftName}\n maxLength={120}\n onChange={(event) => setDraftName(event.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor={`app-description-${app.id}`}>Description</Label>\n <Textarea\n id={`app-description-${app.id}`}\n value={draftDescription}\n maxLength={500}\n rows={4}\n onChange={(event) => setDraftDescription(event.target.value)}\n />\n </div>\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setEditOpen(false)}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={updateMetadata.isPending}>\n {updateMetadata.isPending ? \"Saving...\" : \"Save\"}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n <Dialog open={keysOpen} onOpenChange={setKeysOpen}>\n <DialogContent className=\"max-w-md\">\n <DialogHeader>\n <DialogTitle>Manage keys for {app.name}</DialogTitle>\n <DialogDescription>\n Choose which workspace credentials this app can use.\n </DialogDescription>\n </DialogHeader>\n <AppKeysPanel appId={app.id} appName={app.name} />\n <DialogFooter>\n <Button type=\"button\" onClick={() => setKeysOpen(false)}>\n Done\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n <AppResourcesDialog\n app={app}\n open={resourcesOpen}\n onOpenChange={setResourcesOpen}\n />\n </>\n );\n}\n\nfunction WorkspaceAppOpenActions({\n app,\n href,\n openDirectly,\n isPinned,\n pinLabel,\n pendingOpenLabel,\n onTogglePinned,\n}: {\n app: WorkspaceAppSummary;\n href: string | null;\n openDirectly: boolean;\n isPinned: boolean;\n pinLabel: string;\n pendingOpenLabel: string;\n onTogglePinned?: () => void;\n}) {\n const navigate = useNavigate();\n const appRoute = workspaceAppRoute(app.id);\n const isPending = app.status === \"pending\";\n\n if (isPending) {\n return href ? (\n <Button asChild size=\"sm\" variant=\"outline\">\n <a href={href} target=\"_blank\" rel=\"noreferrer\">\n {pendingOpenLabel}\n </a>\n </Button>\n ) : (\n <Button size=\"sm\" variant=\"outline\" disabled>\n {pendingOpenLabel}\n </Button>\n );\n }\n\n if (!href) {\n return (\n <Button size=\"sm\" variant=\"outline\" disabled>\n Open app\n </Button>\n );\n }\n\n return (\n <AppOpenActions\n name={app.name}\n href={href}\n showNewTabOption\n onOpen={() =>\n openDirectly ? navigateToWorkspaceApp(href) : navigate(appRoute)\n }\n menuItems={\n onTogglePinned\n ? [\n {\n id: \"pin\",\n label: pinLabel,\n icon: <IconPin size={14} strokeWidth={isPinned ? 2.2 : 1.7} />,\n onSelect: onTogglePinned,\n },\n ]\n : undefined\n }\n />\n );\n}\n\ntype WorkspaceAppMetadataLabels = {\n createdBy: string;\n owner: string;\n teams: string;\n};\n\nfunction WorkspaceAppSettings({\n app,\n isArchived,\n isPending,\n onEdit,\n onKeys,\n onResources,\n onArchive,\n onUnarchive,\n onRemovePending,\n labels,\n}: {\n app: WorkspaceAppSummary;\n isArchived: boolean;\n isPending: boolean;\n onEdit: () => void;\n onKeys: () => void;\n onResources: () => void;\n onArchive: () => void;\n onUnarchive: () => void;\n onRemovePending: () => void;\n labels: WorkspaceAppMetadataLabels;\n}) {\n return (\n <DropdownMenu>\n <Tooltip>\n <TooltipTrigger asChild>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-label={`Settings for ${app.name}`}\n className={APP_CARD_ACTION_CLASS}\n >\n <IconSettings size={15} />\n </Button>\n </DropdownMenuTrigger>\n </TooltipTrigger>\n <TooltipContent>App settings</TooltipContent>\n </Tooltip>\n <DropdownMenuContent\n align=\"end\"\n className={cn(APP_ACTION_MENU_CONTENT_CLASS, \"min-w-max\")}\n >\n <DropdownMenuItem onSelect={onEdit}>\n <IconEdit size={14} aria-hidden=\"true\" />\n Edit details\n </DropdownMenuItem>\n {!isPending && !isArchived ? (\n <>\n <DropdownMenuItem onSelect={onKeys}>\n <IconKey size={14} aria-hidden=\"true\" />\n Manage keys\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={onResources}>\n <IconFileText size={14} aria-hidden=\"true\" />\n Agent resources\n </DropdownMenuItem>\n </>\n ) : null}\n {isPending ? (\n <DropdownMenuItem\n onSelect={onRemovePending}\n className=\"text-destructive focus:text-destructive\"\n >\n <IconTrash size={14} aria-hidden=\"true\" />\n Remove from list\n </DropdownMenuItem>\n ) : isArchived ? (\n <DropdownMenuItem onSelect={onUnarchive}>\n <IconEye size={14} aria-hidden=\"true\" />\n Restore to list\n </DropdownMenuItem>\n ) : (\n <DropdownMenuItem onSelect={onArchive}>\n <IconEyeOff size={14} aria-hidden=\"true\" />\n Hide from list\n </DropdownMenuItem>\n )}\n <WorkspaceAppMetadata app={app} labels={labels} />\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nfunction WorkspaceAppMetadata({\n app,\n labels,\n}: {\n app: WorkspaceAppSummary;\n labels: WorkspaceAppMetadataLabels;\n}) {\n const trackedText = (value: string | null | undefined): string | null => {\n const normalized = value?.trim();\n return normalized && normalized.toLowerCase() !== \"not tracked\"\n ? normalized\n : null;\n };\n const rows: Array<{\n id: string;\n icon: typeof IconUser;\n label: string;\n value: string;\n }> = [];\n\n const createdBy = trackedText(app.createdBy);\n if (createdBy) {\n rows.push({\n id: \"created-by\",\n icon: IconUser,\n label: labels.createdBy,\n value: createdBy,\n });\n }\n const owner = trackedText(app.owner);\n if (owner) {\n rows.push({\n id: \"owner\",\n icon: IconUser,\n label: labels.owner,\n value: owner,\n });\n }\n const teams = app.teams\n ?.map(trackedText)\n .filter((team): team is string => Boolean(team))\n .join(\", \");\n if (teams) {\n rows.push({\n id: \"teams\",\n icon: IconUsersGroup,\n label: labels.teams,\n value: teams,\n });\n }\n\n if (rows.length === 0) return null;\n\n return (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuLabel className=\"font-normal\">\n <div className=\"flex flex-col gap-1.5 text-xs text-muted-foreground\">\n {rows.map((row) => (\n <WorkspaceAppMetadataRow key={row.id} {...row} />\n ))}\n </div>\n </DropdownMenuLabel>\n </>\n );\n}\n\nfunction WorkspaceAppMetadataRow({\n icon: Icon,\n label,\n value,\n}: {\n icon: typeof IconUser;\n label: string;\n value: string;\n}) {\n return (\n <div className=\"flex items-start gap-1.5\">\n <Icon className=\"mt-0.5 h-3 w-3 shrink-0\" />\n <span className=\"shrink-0\">{label}</span>\n <span className=\"min-w-0 truncate text-foreground/80\">{value}</span>\n </div>\n );\n}\n\nfunction AppResourcesDialog({\n app,\n open,\n onOpenChange,\n}: {\n app: WorkspaceAppSummary;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const [inspectedResourceId, setInspectedResourceId] = useState<string | null>(\n null,\n );\n const query = useActionQuery(\n \"list-workspace-resources-for-app\",\n { appId: app.id },\n { enabled: open },\n );\n const { data, isLoading } = query;\n\n const resources = ((data as any)?.resources ?? []) as any[];\n const counts = (data as any)?.counts;\n\n return (\n <Dialog\n open={open}\n onOpenChange={(nextOpen) => {\n onOpenChange(nextOpen);\n if (!nextOpen) setInspectedResourceId(null);\n }}\n >\n <DialogContent className=\"max-w-2xl\">\n <DialogHeader>\n <DialogTitle>{app.name} agent resources</DialogTitle>\n <DialogDescription>\n Workspace-scope agent resources are inherited at runtime. App shared\n and personal resources can override them locally.\n </DialogDescription>\n </DialogHeader>\n <div className=\"space-y-4\">\n <div className=\"rounded-lg border bg-muted/30 px-3 py-2 text-xs leading-relaxed text-muted-foreground\">\n All-app agent resources live once at workspace scope and are read by\n each app agent when it builds context. Nothing is copied into this\n app.\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge variant=\"secondary\">{counts?.total ?? 0} total</Badge>\n <Badge variant=\"outline\">\n {counts?.workspace ?? counts?.global ?? 0} workspace\n </Badge>\n <Badge variant=\"outline\">{counts?.granted ?? 0} granted</Badge>\n <Badge variant=\"outline\">\n {counts?.autoLoaded ?? 0} auto-loaded\n </Badge>\n </div>\n\n {query.isError ? (\n <ActionQueryError\n error={query.error}\n onRetry={() => void query.refetch()}\n />\n ) : isLoading ? (\n <div className=\"space-y-2\">\n <div className=\"h-14 rounded-lg border bg-muted/30\" />\n <div className=\"h-14 rounded-lg border bg-muted/30\" />\n <div className=\"h-14 rounded-lg border bg-muted/30\" />\n </div>\n ) : resources.length === 0 ? (\n <div className=\"rounded-lg border border-dashed px-4 py-8 text-center text-sm text-muted-foreground\">\n No workspace or granted resources are visible to this app yet.\n </div>\n ) : (\n <div className=\"max-h-[420px] space-y-2 overflow-y-auto pr-1\">\n {resources.map((resource) => {\n const inspected = inspectedResourceId === resource.id;\n return (\n <div\n key={resource.id}\n className=\"rounded-lg border px-3 py-3\"\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-sm font-medium text-foreground\">\n {resource.name}\n </span>\n <Badge variant=\"secondary\">{resource.kind}</Badge>\n <Badge variant=\"outline\">\n {resource.source === \"workspace\"\n ? \"All apps\"\n : \"Granted\"}\n </Badge>\n {resource.autoLoaded ? (\n <Badge variant=\"outline\">Auto-loaded</Badge>\n ) : null}\n </div>\n <div className=\"mt-1 truncate font-mono text-xs text-muted-foreground\">\n {resource.path}\n </div>\n </div>\n <div className=\"flex shrink-0 flex-col items-end gap-2\">\n {resource.source === \"grant\" ? (\n <div className=\"text-right text-[11px] text-muted-foreground\">\n Selected grant\n </div>\n ) : null}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-7 px-2 text-xs\"\n onClick={(event) => {\n event.stopPropagation();\n setInspectedResourceId(\n inspected ? null : resource.id,\n );\n }}\n >\n {inspected ? (\n <IconChevronDown size={14} className=\"mr-1\" />\n ) : (\n <IconChevronRight size={14} className=\"mr-1\" />\n )}\n Stack\n </Button>\n </div>\n </div>\n\n {resource.description ? (\n <p className=\"mt-2 line-clamp-2 text-xs text-muted-foreground\">\n {resource.description}\n </p>\n ) : null}\n\n {inspected ? (\n <AppResourceEffectiveStack\n appId={app.id}\n resource={resource}\n />\n ) : null}\n </div>\n );\n })}\n </div>\n )}\n </div>\n <DialogFooter>\n <Button type=\"button\" onClick={() => onOpenChange(false)}>\n Done\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n\nfunction stringifyError(err: unknown): string {\n if (err instanceof Error) return err.message;\n return String(err);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"workspace-app-card.js","sourceRoot":"","sources":["../../src/components/workspace-app-card.tsx"],"names":[],"mappings":"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","sourcesContent":["import { APP_ACTION_MENU_CONTENT_CLASS } from \"@agent-native/core/client/chat-first\";\nimport {\n useActionMutation,\n useActionQuery,\n} from \"@agent-native/core/client/hooks\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport { ShareButton } from \"@agent-native/core/client/sharing\";\nimport {\n IconChevronDown,\n IconChevronRight,\n IconClockHour4,\n IconEdit,\n IconEye,\n IconEyeOff,\n IconFileText,\n IconKey,\n IconPin,\n IconShare3,\n IconSettings,\n IconTrash,\n IconUser,\n IconUsersGroup,\n IconWorld,\n} from \"@tabler/icons-react\";\nimport { useEffect, useRef, useState, type FormEvent } from \"react\";\nimport { useNavigate } from \"react-router\";\nimport { toast } from \"sonner\";\n\nimport { cn } from \"../lib/utils\";\nimport {\n isPathMountedWorkspaceApp,\n isWorkspaceSsoApp,\n navigateToWorkspaceApp,\n workspaceAppDirectHref,\n workspaceAppHref,\n workspaceAppRoute,\n type WorkspaceAppSummary,\n} from \"../lib/workspace-apps\";\nimport { ActionQueryError } from \"./action-query-error\";\nimport { AppIcon } from \"./app-icon\";\nimport { AppKeysPanel } from \"./app-keys-popover\";\nimport { AppListRow } from \"./app-list-row\";\nimport { AppOpenActions } from \"./app-open-actions\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from \"./ui/dialog\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"./ui/dropdown-menu\";\nimport { Input } from \"./ui/input\";\nimport { Label } from \"./ui/label\";\nimport { Textarea } from \"./ui/textarea\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"./ui/tooltip\";\nimport { AppResourceEffectiveStack } from \"./workspace-resource-effective-stack\";\n\nconst APP_CARD_ACTION_CLASS =\n \"size-7 rounded-md p-0 text-muted-foreground transition-[background-color,color] hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring data-[state=open]:bg-accent data-[state=open]:text-foreground\";\n\nfunction deferWorkspaceAppOverlayOpen(\n event: { preventDefault: () => void },\n closeMenu: () => void,\n openOverlay: () => void,\n): void {\n event.preventDefault();\n closeMenu();\n if (\n typeof window !== \"undefined\" &&\n typeof window.requestAnimationFrame === \"function\"\n ) {\n window.requestAnimationFrame(() => openOverlay());\n } else {\n setTimeout(openOverlay, 0);\n }\n}\n\nexport function WorkspaceAppCard({\n app,\n className,\n isPinned = false,\n onTogglePinned,\n}: {\n app: WorkspaceAppSummary;\n className?: string;\n isPinned?: boolean;\n onTogglePinned?: () => void;\n}) {\n const t = useT();\n const href = workspaceAppHref(app);\n const directHref =\n app.status !== \"pending\" &&\n !isWorkspaceSsoApp(app) &&\n isPathMountedWorkspaceApp(app)\n ? workspaceAppDirectHref(app, \"/\")\n : null;\n const isPending = app.status === \"pending\";\n const pendingLabel = app.statusLabel || \"Builder branch\";\n const pendingOpenLabel = t(\"dispatch.pages.openBuilderBranch\", {\n defaultValue: \"Open in Builder\",\n });\n const isArchived = !!app.archived;\n const audience = app.audience ?? \"internal\";\n const [editOpen, setEditOpen] = useState(false);\n const [keysOpen, setKeysOpen] = useState(false);\n const [resourcesOpen, setResourcesOpen] = useState(false);\n const [draftName, setDraftName] = useState(app.name);\n const [draftDescription, setDraftDescription] = useState(\n app.description || \"\",\n );\n\n useEffect(() => {\n if (editOpen) return;\n setDraftName(app.name);\n setDraftDescription(app.description || \"\");\n }, [app.description, app.name, editOpen]);\n\n const archive = useActionMutation(\"archive-workspace-app\", {\n onError: (err) =>\n toast.error(`Could not hide ${app.name}: ${stringifyError(err)}`),\n });\n const unarchive = useActionMutation(\"unarchive-workspace-app\", {\n onError: (err) =>\n toast.error(`Could not restore ${app.name}: ${stringifyError(err)}`),\n });\n const removePending = useActionMutation(\"remove-pending-workspace-app\", {\n onError: (err) =>\n toast.error(`Could not remove ${app.name}: ${stringifyError(err)}`),\n });\n const updateMetadata = useActionMutation(\"update-workspace-app-metadata\", {\n onSuccess: () => {\n toast.success(`Updated ${draftName.trim() || app.name}`);\n setEditOpen(false);\n },\n onError: (err) =>\n toast.error(`Could not update ${app.name}: ${stringifyError(err)}`),\n });\n\n const handleArchive = () => {\n archive.mutate({ appId: app.id });\n toast.success(`Hid ${app.name} from the Apps list`);\n };\n const handleUnarchive = () => {\n unarchive.mutate({ appId: app.id });\n toast.success(`Restored ${app.name} to the Apps list`);\n };\n const handleRemovePending = () => {\n removePending.mutate({ appId: app.id });\n toast.success(`Removed pending ${app.name}`);\n };\n const handleMetadataSubmit = (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n const name = draftName.trim();\n if (!name) {\n toast.error(\"App name is required.\");\n return;\n }\n updateMetadata.mutate({\n appId: app.id,\n name,\n description: draftDescription.trim(),\n });\n };\n const pinLabel = t(\n isPinned ? \"dispatch.pages.unpinApp\" : \"dispatch.pages.pinApp\",\n {\n name: app.name,\n defaultValue: isPinned ? \"Unpin this app\" : \"Pin this app\",\n },\n );\n\n return (\n <>\n <AppListRow\n className={cn(\n !href && \"opacity-60\",\n isArchived && \"opacity-70\",\n className,\n )}\n >\n <AppIcon id={app.id} name={app.name} size=\"sm\" />\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"truncate text-sm font-semibold text-foreground\">\n {app.name}\n </h3>\n {app.description || isPending ? (\n <p className=\"mt-0.5 truncate text-xs text-muted-foreground\">\n {app.description || pendingLabel}\n </p>\n ) : null}\n <div className=\"mt-1.5 flex min-w-0 flex-wrap items-center gap-2 text-[11px] text-muted-foreground\">\n {isPending ? (\n <span className=\"inline-flex min-w-0 items-center gap-1 rounded-full bg-muted px-2 py-0.5\">\n <IconClockHour4 size={12} />\n <span className=\"truncate\">{pendingLabel}</span>\n </span>\n ) : null}\n {isArchived ? (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5\">\n <IconEyeOff size={12} />\n Hidden\n </span>\n ) : null}\n {audience === \"public\" ? (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5\">\n <IconWorld size={12} />\n Public\n </span>\n ) : null}\n </div>\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <WorkspaceAppOpenActions\n app={app}\n href={directHref ?? href}\n openDirectly={Boolean(directHref)}\n isPinned={isPinned}\n pinLabel={pinLabel}\n pendingOpenLabel={pendingOpenLabel}\n onTogglePinned={onTogglePinned}\n />\n <WorkspaceAppSettings\n app={app}\n isArchived={isArchived}\n isPending={isPending}\n onEdit={() => setEditOpen(true)}\n onKeys={() => setKeysOpen(true)}\n onResources={() => setResourcesOpen(true)}\n onArchive={handleArchive}\n onUnarchive={handleUnarchive}\n onRemovePending={handleRemovePending}\n labels={{\n createdBy: t(\"agents.dashboardMetadataCreatedBy\"),\n owner: t(\"dispatch.pages.appMetadataOwner\"),\n teams: t(\"dispatch.pages.appMetadataTeams\"),\n share: t(\"share.share\", { defaultValue: \"Share\" }),\n }}\n />\n </div>\n </AppListRow>\n <Dialog open={editOpen} onOpenChange={setEditOpen}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Edit app details</DialogTitle>\n </DialogHeader>\n <form className=\"space-y-4\" onSubmit={handleMetadataSubmit}>\n <div className=\"space-y-2\">\n <Label htmlFor={`app-name-${app.id}`}>Name</Label>\n <Input\n id={`app-name-${app.id}`}\n value={draftName}\n maxLength={120}\n onChange={(event) => setDraftName(event.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label htmlFor={`app-description-${app.id}`}>Description</Label>\n <Textarea\n id={`app-description-${app.id}`}\n value={draftDescription}\n maxLength={500}\n rows={4}\n onChange={(event) => setDraftDescription(event.target.value)}\n />\n </div>\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setEditOpen(false)}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={updateMetadata.isPending}>\n {updateMetadata.isPending ? \"Saving...\" : \"Save\"}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n <Dialog open={keysOpen} onOpenChange={setKeysOpen}>\n <DialogContent className=\"max-w-md\">\n <DialogHeader>\n <DialogTitle>Manage keys for {app.name}</DialogTitle>\n <DialogDescription>\n Choose which workspace credentials this app can use.\n </DialogDescription>\n </DialogHeader>\n <AppKeysPanel appId={app.id} appName={app.name} />\n <DialogFooter>\n <Button type=\"button\" onClick={() => setKeysOpen(false)}>\n Done\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n <AppResourcesDialog\n app={app}\n open={resourcesOpen}\n onOpenChange={setResourcesOpen}\n />\n </>\n );\n}\n\nfunction WorkspaceAppOpenActions({\n app,\n href,\n openDirectly,\n isPinned,\n pinLabel,\n pendingOpenLabel,\n onTogglePinned,\n}: {\n app: WorkspaceAppSummary;\n href: string | null;\n openDirectly: boolean;\n isPinned: boolean;\n pinLabel: string;\n pendingOpenLabel: string;\n onTogglePinned?: () => void;\n}) {\n const navigate = useNavigate();\n const appRoute = workspaceAppRoute(app.id);\n const isPending = app.status === \"pending\";\n\n if (isPending) {\n return href ? (\n <Button asChild size=\"sm\" variant=\"outline\">\n <a href={href} target=\"_blank\" rel=\"noreferrer\">\n {pendingOpenLabel}\n </a>\n </Button>\n ) : (\n <Button size=\"sm\" variant=\"outline\" disabled>\n {pendingOpenLabel}\n </Button>\n );\n }\n\n if (!href) {\n return (\n <Button size=\"sm\" variant=\"outline\" disabled>\n Open app\n </Button>\n );\n }\n\n return (\n <AppOpenActions\n name={app.name}\n href={href}\n showNewTabOption\n onOpen={() =>\n openDirectly ? navigateToWorkspaceApp(href) : navigate(appRoute)\n }\n menuItems={\n onTogglePinned\n ? [\n {\n id: \"pin\",\n label: pinLabel,\n icon: <IconPin size={14} strokeWidth={isPinned ? 2.2 : 1.7} />,\n onSelect: onTogglePinned,\n },\n ]\n : undefined\n }\n />\n );\n}\n\ntype WorkspaceAppMetadataLabels = {\n createdBy: string;\n owner: string;\n teams: string;\n share: string;\n};\n\nfunction WorkspaceAppSettings({\n app,\n isArchived,\n isPending,\n onEdit,\n onKeys,\n onResources,\n onArchive,\n onUnarchive,\n onRemovePending,\n labels,\n}: {\n app: WorkspaceAppSummary;\n isArchived: boolean;\n isPending: boolean;\n onEdit: () => void;\n onKeys: () => void;\n onResources: () => void;\n onArchive: () => void;\n onUnarchive: () => void;\n onRemovePending: () => void;\n labels: WorkspaceAppMetadataLabels;\n}) {\n const [shareOpen, setShareOpen] = useState(false);\n const [settingsOpen, setSettingsOpen] = useState(false);\n const settingsTriggerRef = useRef<HTMLButtonElement>(null);\n\n const handleShareOpenChange = (open: boolean) => {\n setShareOpen(open);\n if (open) return;\n\n const restoreSettingsFocus = () => settingsTriggerRef.current?.focus();\n if (\n typeof window !== \"undefined\" &&\n typeof window.requestAnimationFrame === \"function\"\n ) {\n window.requestAnimationFrame(restoreSettingsFocus);\n } else {\n setTimeout(restoreSettingsFocus, 0);\n }\n };\n\n return (\n <>\n <DropdownMenu open={settingsOpen} onOpenChange={setSettingsOpen}>\n <Tooltip>\n <TooltipTrigger asChild>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n ref={settingsTriggerRef}\n aria-label={`Settings for ${app.name}`}\n className={APP_CARD_ACTION_CLASS}\n >\n <IconSettings size={15} />\n </Button>\n </DropdownMenuTrigger>\n </TooltipTrigger>\n <TooltipContent>App settings</TooltipContent>\n </Tooltip>\n <DropdownMenuContent\n align=\"end\"\n className={cn(APP_ACTION_MENU_CONTENT_CLASS, \"min-w-max\")}\n >\n <DropdownMenuItem onSelect={onEdit}>\n <IconEdit size={14} aria-hidden=\"true\" />\n Edit details\n </DropdownMenuItem>\n {!isPending ? (\n <DropdownMenuItem\n onSelect={(event) =>\n deferWorkspaceAppOverlayOpen(\n event,\n () => setSettingsOpen(false),\n () => setShareOpen(true),\n )\n }\n >\n <IconShare3 size={14} aria-hidden=\"true\" />\n {labels.share}\n </DropdownMenuItem>\n ) : null}\n {!isPending && !isArchived ? (\n <>\n <DropdownMenuItem onSelect={onKeys}>\n <IconKey size={14} aria-hidden=\"true\" />\n Manage keys\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={onResources}>\n <IconFileText size={14} aria-hidden=\"true\" />\n Agent resources\n </DropdownMenuItem>\n </>\n ) : null}\n {isPending ? (\n <DropdownMenuItem\n onSelect={onRemovePending}\n className=\"text-destructive focus:text-destructive\"\n >\n <IconTrash size={14} aria-hidden=\"true\" />\n Remove from list\n </DropdownMenuItem>\n ) : isArchived ? (\n <DropdownMenuItem onSelect={onUnarchive}>\n <IconEye size={14} aria-hidden=\"true\" />\n Restore to list\n </DropdownMenuItem>\n ) : (\n <DropdownMenuItem onSelect={onArchive}>\n <IconEyeOff size={14} aria-hidden=\"true\" />\n Hide from list\n </DropdownMenuItem>\n )}\n <WorkspaceAppMetadata app={app} labels={labels} />\n </DropdownMenuContent>\n </DropdownMenu>\n {!isPending && shareOpen ? (\n <ShareButton\n resourceType=\"workspace-app\"\n resourceId={app.id}\n resourceTitle={app.name}\n defaultOpen\n onOpenChange={handleShareOpenChange}\n triggerClassName=\"sr-only\"\n />\n ) : null}\n </>\n );\n}\n\nfunction WorkspaceAppMetadata({\n app,\n labels,\n}: {\n app: WorkspaceAppSummary;\n labels: WorkspaceAppMetadataLabels;\n}) {\n const trackedText = (value: string | null | undefined): string | null => {\n const normalized = value?.trim();\n return normalized && normalized.toLowerCase() !== \"not tracked\"\n ? normalized\n : null;\n };\n const rows: Array<{\n id: string;\n icon: typeof IconUser;\n label: string;\n value: string;\n }> = [];\n\n const createdBy = trackedText(app.createdBy);\n if (createdBy) {\n rows.push({\n id: \"created-by\",\n icon: IconUser,\n label: labels.createdBy,\n value: createdBy,\n });\n }\n const owner = trackedText(app.owner);\n if (owner) {\n rows.push({\n id: \"owner\",\n icon: IconUser,\n label: labels.owner,\n value: owner,\n });\n }\n const teams = app.teams\n ?.map(trackedText)\n .filter((team): team is string => Boolean(team))\n .join(\", \");\n if (teams) {\n rows.push({\n id: \"teams\",\n icon: IconUsersGroup,\n label: labels.teams,\n value: teams,\n });\n }\n\n if (rows.length === 0) return null;\n\n return (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuLabel className=\"font-normal\">\n <div className=\"flex flex-col gap-1.5 text-xs text-muted-foreground\">\n {rows.map((row) => (\n <WorkspaceAppMetadataRow key={row.id} {...row} />\n ))}\n </div>\n </DropdownMenuLabel>\n </>\n );\n}\n\nfunction WorkspaceAppMetadataRow({\n icon: Icon,\n label,\n value,\n}: {\n icon: typeof IconUser;\n label: string;\n value: string;\n}) {\n return (\n <div className=\"flex items-start gap-1.5\">\n <Icon className=\"mt-0.5 h-3 w-3 shrink-0\" />\n <span className=\"shrink-0\">{label}</span>\n <span className=\"min-w-0 truncate text-foreground/80\">{value}</span>\n </div>\n );\n}\n\nfunction AppResourcesDialog({\n app,\n open,\n onOpenChange,\n}: {\n app: WorkspaceAppSummary;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const [inspectedResourceId, setInspectedResourceId] = useState<string | null>(\n null,\n );\n const query = useActionQuery(\n \"list-workspace-resources-for-app\",\n { appId: app.id },\n { enabled: open },\n );\n const { data, isLoading } = query;\n\n const resources = ((data as any)?.resources ?? []) as any[];\n const counts = (data as any)?.counts;\n\n return (\n <Dialog\n open={open}\n onOpenChange={(nextOpen) => {\n onOpenChange(nextOpen);\n if (!nextOpen) setInspectedResourceId(null);\n }}\n >\n <DialogContent className=\"max-w-2xl\">\n <DialogHeader>\n <DialogTitle>{app.name} agent resources</DialogTitle>\n <DialogDescription>\n Workspace-scope agent resources are inherited at runtime. App shared\n and personal resources can override them locally.\n </DialogDescription>\n </DialogHeader>\n <div className=\"space-y-4\">\n <div className=\"rounded-lg border bg-muted/30 px-3 py-2 text-xs leading-relaxed text-muted-foreground\">\n All-app agent resources live once at workspace scope and are read by\n each app agent when it builds context. Nothing is copied into this\n app.\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge variant=\"secondary\">{counts?.total ?? 0} total</Badge>\n <Badge variant=\"outline\">\n {counts?.workspace ?? counts?.global ?? 0} workspace\n </Badge>\n <Badge variant=\"outline\">{counts?.granted ?? 0} granted</Badge>\n <Badge variant=\"outline\">\n {counts?.autoLoaded ?? 0} auto-loaded\n </Badge>\n </div>\n\n {query.isError ? (\n <ActionQueryError\n error={query.error}\n onRetry={() => void query.refetch()}\n />\n ) : isLoading ? (\n <div className=\"space-y-2\">\n <div className=\"h-14 rounded-lg border bg-muted/30\" />\n <div className=\"h-14 rounded-lg border bg-muted/30\" />\n <div className=\"h-14 rounded-lg border bg-muted/30\" />\n </div>\n ) : resources.length === 0 ? (\n <div className=\"rounded-lg border border-dashed px-4 py-8 text-center text-sm text-muted-foreground\">\n No workspace or granted resources are visible to this app yet.\n </div>\n ) : (\n <div className=\"max-h-[420px] space-y-2 overflow-y-auto pr-1\">\n {resources.map((resource) => {\n const inspected = inspectedResourceId === resource.id;\n return (\n <div\n key={resource.id}\n className=\"rounded-lg border px-3 py-3\"\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-sm font-medium text-foreground\">\n {resource.name}\n </span>\n <Badge variant=\"secondary\">{resource.kind}</Badge>\n <Badge variant=\"outline\">\n {resource.source === \"workspace\"\n ? \"All apps\"\n : \"Granted\"}\n </Badge>\n {resource.autoLoaded ? (\n <Badge variant=\"outline\">Auto-loaded</Badge>\n ) : null}\n </div>\n <div className=\"mt-1 truncate font-mono text-xs text-muted-foreground\">\n {resource.path}\n </div>\n </div>\n <div className=\"flex shrink-0 flex-col items-end gap-2\">\n {resource.source === \"grant\" ? (\n <div className=\"text-right text-[11px] text-muted-foreground\">\n Selected grant\n </div>\n ) : null}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-7 px-2 text-xs\"\n onClick={(event) => {\n event.stopPropagation();\n setInspectedResourceId(\n inspected ? null : resource.id,\n );\n }}\n >\n {inspected ? (\n <IconChevronDown size={14} className=\"mr-1\" />\n ) : (\n <IconChevronRight size={14} className=\"mr-1\" />\n )}\n Stack\n </Button>\n </div>\n </div>\n\n {resource.description ? (\n <p className=\"mt-2 line-clamp-2 text-xs text-muted-foreground\">\n {resource.description}\n </p>\n ) : null}\n\n {inspected ? (\n <AppResourceEffectiveStack\n appId={app.id}\n resource={resource}\n />\n ) : null}\n </div>\n );\n })}\n </div>\n )}\n </div>\n <DialogFooter>\n <Button type=\"button\" onClick={() => onOpenChange(false)}>\n Done\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n\nfunction stringifyError(err: unknown): string {\n if (err instanceof Error) return err.message;\n return String(err);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transactional-email.$appId.$id.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/transactional-email.$appId.$id.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transactional-email.$appId.$id.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/transactional-email.$appId.$id.tsx"],"names":[],"mappings":"AAgCA,wBAAgB,IAAI;;IAEnB;AAwHD,MAAM,CAAC,OAAO,UAAU,6BAA6B,oDAqNpD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transactional-email.$appId.$id.js","sourceRoot":"","sources":["../../../src/routes/pages/transactional-email.$appId.$id.tsx"],"names":[],"mappings":"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","sourcesContent":["import { callAction, useActionQuery } from \"@agent-native/core/client/hooks\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport { IconAlertTriangle, IconArrowLeft } from \"@tabler/icons-react\";\nimport { useQueries, useQuery } from \"@tanstack/react-query\";\nimport { useMemo } from \"react\";\nimport { Link, useLocation, useParams } from \"react-router\";\n\nimport {\n aggregateSharedEmails,\n callAppAction,\n fetchAppEmailCatalog,\n type AppEmailCatalog,\n type AppTransactionalEmail,\n type LocalTransactionalEmailCatalog,\n} from \"../../client/transactional-emails\";\nimport { ActionQueryError } from \"../../components/action-query-error\";\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport {\n ActivityTable,\n type EmailActivityEntry,\n} from \"../../components/transactional-email-activity\";\nimport {\n OpenRateCell,\n SendsCell,\n LastSentCell,\n type EmailEngagement,\n type ProviderMetricsResult,\n} from \"../../components/transactional-email-metrics\";\nimport { EmailPreviewPane } from \"../../components/transactional-email-preview\";\nimport { Alert, AlertDescription, AlertTitle } from \"../../components/ui/alert\";\nimport { Button } from \"../../components/ui/button\";\nimport { Skeleton } from \"../../components/ui/skeleton\";\n\nexport function meta() {\n return [{ title: \"Transactional email detail — Dispatch\" }];\n}\n\nconst WINDOW_DAYS = 30;\nconst ACTIVITY_LIMIT = 50;\n\ninterface WorkspaceAppRef {\n id: string;\n name: string;\n path: string;\n status?: \"ready\" | \"pending\";\n}\n\n/**\n * Resolves the one email this page shows, plus the app name/path to display.\n * The \"core\" appId is Dispatch's own registry, not a cross-app fetch — see\n * the same split in transactional-email.tsx.\n */\nfunction useEmailDetail(appId: string, id: string) {\n const isCore = appId === \"core\";\n const t = useT();\n\n const localQuery = useActionQuery<LocalTransactionalEmailCatalog>(\n \"list-transactional-emails\",\n { windowDays: WINDOW_DAYS },\n { enabled: isCore },\n );\n\n const appsQuery = useActionQuery<WorkspaceAppRef[]>(\"list-workspace-apps\", {\n includeAgentCards: false,\n });\n const readyApps = useMemo(\n () =>\n (appsQuery.data ?? []).filter(\n (candidate) => candidate.status !== \"pending\",\n ),\n [appsQuery.data],\n );\n const app = useMemo(\n () => readyApps.find((candidate) => candidate.id === appId),\n [readyApps, appId],\n );\n const coreCatalogQueries = useQueries({\n queries: readyApps.map((candidate) => ({\n queryKey: [\"transactional-email-catalog\", candidate.id, WINDOW_DAYS],\n queryFn: () => fetchAppEmailCatalog(candidate, WINDOW_DAYS),\n enabled: isCore,\n staleTime: Infinity,\n })),\n });\n const remoteQuery = useQuery({\n queryKey: [\"transactional-email-catalog\", appId, WINDOW_DAYS],\n queryFn: () => fetchAppEmailCatalog(app!, WINDOW_DAYS),\n enabled: !isCore && !!app,\n staleTime: Infinity,\n });\n\n if (isCore) {\n const appCatalogs = coreCatalogQueries\n .map((query) => query.data)\n .filter((catalog): catalog is AppEmailCatalog => Boolean(catalog));\n const aggregate = localQuery.data\n ? aggregateSharedEmails(localQuery.data, appCatalogs)\n : undefined;\n const email = aggregate?.emails.find((candidate) => candidate.id === id);\n const catalogError = coreCatalogQueries.find(\n (query) => query.data?.error || query.data?.statsError,\n )?.data;\n const queryError = coreCatalogQueries.find((query) => query.isError)?.error;\n const isLoading =\n localQuery.isLoading ||\n appsQuery.isLoading ||\n coreCatalogQueries.some((query) => query.isLoading);\n const isError =\n localQuery.isError || appsQuery.isError || Boolean(queryError);\n return {\n isLoading,\n isError,\n error: localQuery.error ?? appsQuery.error ?? queryError,\n onRetry: () => {\n void localQuery.refetch();\n void appsQuery.refetch();\n for (const query of coreCatalogQueries) void query.refetch();\n },\n appName: t(\"dispatch.transactionalEmail.sharedTitle\"),\n appPath: t(\"dispatch.transactionalEmail.sharedSubtitle\"),\n email,\n catalogError:\n aggregate?.statsError ??\n catalogError?.error ??\n catalogError?.statsError ??\n null,\n notFound: !isLoading && !isError && !email,\n };\n }\n\n const notFound =\n !appsQuery.isLoading &&\n !appsQuery.isError &&\n (!app ||\n (!remoteQuery.isLoading &&\n !remoteQuery.isError &&\n !remoteQuery.data?.error &&\n !remoteQuery.data?.emails.some((candidate) => candidate.id === id)));\n\n return {\n isLoading: appsQuery.isLoading || remoteQuery.isLoading,\n isError: appsQuery.isError || remoteQuery.isError,\n error: appsQuery.error ?? remoteQuery.error,\n onRetry: () => {\n void appsQuery.refetch();\n void remoteQuery.refetch();\n },\n appName: app?.name ?? appId,\n appPath: app?.path ?? \"\",\n email: remoteQuery.data?.emails.find((candidate) => candidate.id === id),\n catalogError: remoteQuery.data?.error ?? null,\n notFound,\n };\n}\n\nexport default function TransactionalEmailDetailRoute() {\n const t = useT();\n const location = useLocation();\n const params = useParams<{ appId: string; id: string }>();\n const appId = params.appId ?? \"\";\n const id = params.id ?? \"\";\n\n const detail = useEmailDetail(appId, id);\n\n const sharedProviderReason = t(\n \"dispatch.transactionalEmail.sharedProviderMetricsUnavailable\",\n );\n const engagementQuery = useQuery({\n queryKey: [\"list-email-engagement\", detail.appPath, id, WINDOW_DAYS],\n queryFn: () =>\n callAppAction<ProviderMetricsResult<EmailEngagement[]>>(\n detail.appPath,\n \"list-email-engagement\",\n { templateIds: [id], windowDays: WINDOW_DAYS },\n \"POST\",\n ),\n enabled: appId !== \"core\" && id.length > 0 && detail.appPath.length > 0,\n });\n const engagementResult = engagementQuery.data;\n const engagementUnavailable =\n appId === \"core\"\n ? sharedProviderReason\n : engagementResult && !engagementResult.available\n ? engagementResult.reason\n : engagementQuery.isError\n ? engagementQuery.error instanceof Error\n ? engagementQuery.error.message\n : String(engagementQuery.error)\n : null;\n const engagement = engagementResult?.available\n ? engagementResult.data.find((entry) => entry.templateId === id)\n : undefined;\n\n const activityQuery = useQuery({\n queryKey: [\"list-email-activity\", detail.appPath, id, ACTIVITY_LIMIT],\n queryFn: () =>\n callAppAction<ProviderMetricsResult<EmailActivityEntry[]>>(\n detail.appPath,\n \"list-email-activity\",\n { templateId: id, limit: ACTIVITY_LIMIT },\n \"GET\",\n ),\n enabled:\n appId !== \"core\" &&\n id.length > 0 &&\n detail.appPath.length > 0 &&\n !engagementUnavailable,\n });\n\n return (\n <DispatchShell\n title={detail.email?.name ?? t(\"dispatch.transactionalEmail.title\")}\n description={t(\"dispatch.transactionalEmail.description\")}\n >\n <div className=\"max-w-3xl space-y-4\">\n <Button asChild size=\"sm\" variant=\"ghost\" className=\"-ml-2\">\n <Link\n to={\n location.pathname.startsWith(\"/admin/\")\n ? \"/admin/transactional-email\"\n : \"/transactional-email\"\n }\n >\n <IconArrowLeft size={15} className=\"mr-1.5\" />\n {t(\"dispatch.transactionalEmail.title\")}\n </Link>\n </Button>\n\n {detail.isError ? (\n <ActionQueryError error={detail.error} onRetry={detail.onRetry} />\n ) : detail.isLoading ? (\n <div className=\"space-y-3\">\n <Skeleton className=\"h-6 w-64\" />\n <Skeleton className=\"h-32 w-full\" />\n </div>\n ) : detail.notFound || !detail.email ? (\n <Alert variant=\"destructive\">\n <IconAlertTriangle className=\"size-4\" />\n <AlertTitle>\n {t(\"dispatch.transactionalEmail.emailNotFound\")}\n </AlertTitle>\n <AlertDescription>\n {detail.catalogError ??\n t(\"dispatch.transactionalEmail.emailNotFoundDescription\")}\n </AlertDescription>\n </Alert>\n ) : (\n <>\n <section className=\"rounded-2xl bg-card p-5\">\n <div className=\"text-lg font-semibold text-foreground\">\n {detail.email.name}\n </div>\n <div className=\"mt-1 font-mono text-xs text-muted-foreground\">\n {detail.email.id}\n </div>\n <div className=\"mt-1 text-xs text-muted-foreground\">\n {detail.appName}\n {detail.appPath ? ` · ${detail.appPath}` : \"\"}\n </div>\n\n <dl className=\"mt-4 space-y-3 text-sm\">\n <div>\n <dt className=\"text-xs font-medium text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.trigger\")}\n </dt>\n <dd className=\"mt-1 text-foreground\">\n {detail.email.trigger}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs font-medium text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.recipient\")}\n </dt>\n <dd className=\"mt-1 text-foreground\">\n {detail.email.recipient}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs font-medium text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.sender\")}\n </dt>\n <dd className=\"mt-1 text-foreground\">\n {detail.email.sender}\n </dd>\n </div>\n </dl>\n\n <div className=\"mt-4 flex flex-wrap gap-6 border-t pt-4 text-sm\">\n <div>\n <div className=\"text-xs font-medium text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.sends\")}\n </div>\n <div className=\"mt-1\">\n <SendsCell\n sent={detail.email.sent}\n failed={detail.email.failed}\n />\n </div>\n </div>\n <div>\n <div className=\"text-xs font-medium text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.openRate\")}\n </div>\n <div className=\"mt-1\">\n <OpenRateCell\n engagement={engagement}\n unavailableReason={engagementUnavailable}\n loading={engagementQuery.isLoading}\n />\n </div>\n </div>\n <div>\n <div className=\"text-xs font-medium text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.lastSent\")}\n </div>\n <div className=\"mt-1\">\n <LastSentCell\n lastSentAt={detail.email.lastSentAt}\n sent={detail.email.sent}\n />\n </div>\n </div>\n </div>\n </section>\n\n <section className=\"rounded-2xl bg-card p-5\">\n <h2 className=\"text-sm font-medium text-foreground\">\n {t(\"dispatch.transactionalEmail.preview\")}\n </h2>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.previewDescription\")}\n </p>\n <div className=\"mt-4\">\n <EmailPreviewPane\n appId={appId}\n appPath={detail.appPath}\n id={detail.email.id}\n name={detail.email.name}\n />\n </div>\n </section>\n\n <section className=\"rounded-2xl bg-card p-5\">\n <h2 className=\"text-sm font-medium text-foreground\">\n {t(\"dispatch.transactionalEmail.activityLink\")}\n </h2>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.retentionNote\")}\n </p>\n <div className=\"mt-4\">\n <ActivityTable\n result={\n engagementUnavailable\n ? { available: false, reason: engagementUnavailable }\n : activityQuery.data\n }\n isLoading={activityQuery.isLoading}\n isError={activityQuery.isError}\n error={activityQuery.error}\n onRetry={() => void activityQuery.refetch()}\n />\n </div>\n </section>\n </>\n )}\n </div>\n </DispatchShell>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"transactional-email.$appId.$id.js","sourceRoot":"","sources":["../../../src/routes/pages/transactional-email.$appId.$id.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useActionQuery } from \"@agent-native/core/client/hooks\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport { IconAlertTriangle, IconArrowLeft } from \"@tabler/icons-react\";\nimport { useQueries, useQuery } from \"@tanstack/react-query\";\nimport { useMemo } from \"react\";\nimport { Link, useLocation, useParams } from \"react-router\";\n\nimport {\n aggregateSharedEmails,\n callAppAction,\n fetchAppEmailCatalog,\n type AppEmailCatalog,\n type LocalTransactionalEmailCatalog,\n} from \"../../client/transactional-emails\";\nimport { ActionQueryError } from \"../../components/action-query-error\";\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport {\n ActivityTable,\n type EmailActivityEntry,\n} from \"../../components/transactional-email-activity\";\nimport {\n OpenRateCell,\n SendsCell,\n LastSentCell,\n type EmailEngagement,\n type ProviderMetricsResult,\n} from \"../../components/transactional-email-metrics\";\nimport { EmailPreviewPane } from \"../../components/transactional-email-preview\";\nimport { Alert, AlertDescription, AlertTitle } from \"../../components/ui/alert\";\nimport { Button } from \"../../components/ui/button\";\nimport { Skeleton } from \"../../components/ui/skeleton\";\n\nexport function meta() {\n return [{ title: \"Transactional email detail — Dispatch\" }];\n}\n\nconst WINDOW_DAYS = 30;\nconst ACTIVITY_LIMIT = 50;\n\ninterface WorkspaceAppRef {\n id: string;\n name: string;\n path: string;\n status?: \"ready\" | \"pending\";\n}\n\n/**\n * Resolves the one email this page shows, plus the app name/path to display.\n * The \"core\" appId is Dispatch's own registry, not a cross-app fetch — see\n * the same split in transactional-email.tsx.\n */\nfunction useEmailDetail(appId: string, id: string) {\n const isCore = appId === \"core\";\n const t = useT();\n\n const localQuery = useActionQuery<LocalTransactionalEmailCatalog>(\n \"list-transactional-emails\",\n { windowDays: WINDOW_DAYS },\n { enabled: isCore },\n );\n\n const appsQuery = useActionQuery<WorkspaceAppRef[]>(\"list-workspace-apps\", {\n includeAgentCards: false,\n });\n const readyApps = useMemo(\n () =>\n (appsQuery.data ?? []).filter(\n (candidate) => candidate.status !== \"pending\",\n ),\n [appsQuery.data],\n );\n const app = useMemo(\n () => readyApps.find((candidate) => candidate.id === appId),\n [readyApps, appId],\n );\n const coreCatalogQueries = useQueries({\n queries: readyApps.map((candidate) => ({\n queryKey: [\"transactional-email-catalog\", candidate.id, WINDOW_DAYS],\n queryFn: () => fetchAppEmailCatalog(candidate, WINDOW_DAYS),\n enabled: isCore,\n staleTime: Infinity,\n })),\n });\n const remoteQuery = useQuery({\n queryKey: [\"transactional-email-catalog\", appId, WINDOW_DAYS],\n queryFn: () => fetchAppEmailCatalog(app!, WINDOW_DAYS),\n enabled: !isCore && !!app,\n staleTime: Infinity,\n });\n\n if (isCore) {\n const appCatalogs = coreCatalogQueries\n .map((query) => query.data)\n .filter((catalog): catalog is AppEmailCatalog => Boolean(catalog));\n const aggregate = localQuery.data\n ? aggregateSharedEmails(localQuery.data, appCatalogs)\n : undefined;\n const email = aggregate?.emails.find((candidate) => candidate.id === id);\n const catalogError = coreCatalogQueries.find(\n (query) => query.data?.error || query.data?.statsError,\n )?.data;\n const queryError = coreCatalogQueries.find((query) => query.isError)?.error;\n const isLoading =\n localQuery.isLoading ||\n appsQuery.isLoading ||\n coreCatalogQueries.some((query) => query.isLoading);\n const isError =\n localQuery.isError || appsQuery.isError || Boolean(queryError);\n return {\n isLoading,\n isError,\n error: localQuery.error ?? appsQuery.error ?? queryError,\n onRetry: () => {\n void localQuery.refetch();\n void appsQuery.refetch();\n for (const query of coreCatalogQueries) void query.refetch();\n },\n appName: t(\"dispatch.transactionalEmail.sharedTitle\"),\n appPath: t(\"dispatch.transactionalEmail.sharedSubtitle\"),\n email,\n catalogError:\n aggregate?.statsError ??\n catalogError?.error ??\n catalogError?.statsError ??\n null,\n notFound: !isLoading && !isError && !email,\n };\n }\n\n const notFound =\n !appsQuery.isLoading &&\n !appsQuery.isError &&\n (!app ||\n (!remoteQuery.isLoading &&\n !remoteQuery.isError &&\n !remoteQuery.data?.error &&\n !remoteQuery.data?.emails.some((candidate) => candidate.id === id)));\n\n return {\n isLoading: appsQuery.isLoading || remoteQuery.isLoading,\n isError: appsQuery.isError || remoteQuery.isError,\n error: appsQuery.error ?? remoteQuery.error,\n onRetry: () => {\n void appsQuery.refetch();\n void remoteQuery.refetch();\n },\n appName: app?.name ?? appId,\n appPath: app?.path ?? \"\",\n email: remoteQuery.data?.emails.find((candidate) => candidate.id === id),\n catalogError: remoteQuery.data?.error ?? null,\n notFound,\n };\n}\n\nexport default function TransactionalEmailDetailRoute() {\n const t = useT();\n const location = useLocation();\n const params = useParams<{ appId: string; id: string }>();\n const appId = params.appId ?? \"\";\n const id = params.id ?? \"\";\n\n const detail = useEmailDetail(appId, id);\n\n const sharedProviderReason = t(\n \"dispatch.transactionalEmail.sharedProviderMetricsUnavailable\",\n );\n const engagementQuery = useQuery({\n queryKey: [\"list-email-engagement\", detail.appPath, id, WINDOW_DAYS],\n queryFn: () =>\n callAppAction<ProviderMetricsResult<EmailEngagement[]>>(\n detail.appPath,\n \"list-email-engagement\",\n { templateIds: [id], windowDays: WINDOW_DAYS },\n \"POST\",\n ),\n enabled: appId !== \"core\" && id.length > 0 && detail.appPath.length > 0,\n });\n const engagementResult = engagementQuery.data;\n const engagementUnavailable =\n appId === \"core\"\n ? sharedProviderReason\n : engagementResult && !engagementResult.available\n ? engagementResult.reason\n : engagementQuery.isError\n ? engagementQuery.error instanceof Error\n ? engagementQuery.error.message\n : String(engagementQuery.error)\n : null;\n const engagement = engagementResult?.available\n ? engagementResult.data.find((entry) => entry.templateId === id)\n : undefined;\n\n const activityQuery = useQuery({\n queryKey: [\"list-email-activity\", detail.appPath, id, ACTIVITY_LIMIT],\n queryFn: () =>\n callAppAction<ProviderMetricsResult<EmailActivityEntry[]>>(\n detail.appPath,\n \"list-email-activity\",\n { templateId: id, limit: ACTIVITY_LIMIT },\n \"GET\",\n ),\n enabled:\n appId !== \"core\" &&\n id.length > 0 &&\n detail.appPath.length > 0 &&\n !engagementUnavailable,\n });\n\n return (\n <DispatchShell\n title={detail.email?.name ?? t(\"dispatch.transactionalEmail.title\")}\n description={t(\"dispatch.transactionalEmail.description\")}\n >\n <div className=\"max-w-3xl space-y-4\">\n <Button asChild size=\"sm\" variant=\"ghost\" className=\"-ml-2\">\n <Link\n to={\n location.pathname.startsWith(\"/admin/\")\n ? \"/admin/transactional-email\"\n : \"/transactional-email\"\n }\n >\n <IconArrowLeft size={15} className=\"mr-1.5\" />\n {t(\"dispatch.transactionalEmail.title\")}\n </Link>\n </Button>\n\n {detail.isError ? (\n <ActionQueryError error={detail.error} onRetry={detail.onRetry} />\n ) : detail.isLoading ? (\n <div className=\"space-y-3\">\n <Skeleton className=\"h-6 w-64\" />\n <Skeleton className=\"h-32 w-full\" />\n </div>\n ) : detail.notFound || !detail.email ? (\n <Alert variant=\"destructive\">\n <IconAlertTriangle className=\"size-4\" />\n <AlertTitle>\n {t(\"dispatch.transactionalEmail.emailNotFound\")}\n </AlertTitle>\n <AlertDescription>\n {detail.catalogError ??\n t(\"dispatch.transactionalEmail.emailNotFoundDescription\")}\n </AlertDescription>\n </Alert>\n ) : (\n <>\n <section className=\"rounded-2xl bg-card p-5\">\n <div className=\"text-lg font-semibold text-foreground\">\n {detail.email.name}\n </div>\n <div className=\"mt-1 font-mono text-xs text-muted-foreground\">\n {detail.email.id}\n </div>\n <div className=\"mt-1 text-xs text-muted-foreground\">\n {detail.appName}\n {detail.appPath ? ` · ${detail.appPath}` : \"\"}\n </div>\n\n <dl className=\"mt-4 space-y-3 text-sm\">\n <div>\n <dt className=\"text-xs font-medium text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.trigger\")}\n </dt>\n <dd className=\"mt-1 text-foreground\">\n {detail.email.trigger}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs font-medium text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.recipient\")}\n </dt>\n <dd className=\"mt-1 text-foreground\">\n {detail.email.recipient}\n </dd>\n </div>\n <div>\n <dt className=\"text-xs font-medium text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.sender\")}\n </dt>\n <dd className=\"mt-1 text-foreground\">\n {detail.email.sender}\n </dd>\n </div>\n </dl>\n\n <div className=\"mt-4 flex flex-wrap gap-6 border-t pt-4 text-sm\">\n <div>\n <div className=\"text-xs font-medium text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.sends\")}\n </div>\n <div className=\"mt-1\">\n <SendsCell\n sent={detail.email.sent}\n failed={detail.email.failed}\n />\n </div>\n </div>\n <div>\n <div className=\"text-xs font-medium text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.openRate\")}\n </div>\n <div className=\"mt-1\">\n <OpenRateCell\n engagement={engagement}\n unavailableReason={engagementUnavailable}\n loading={engagementQuery.isLoading}\n />\n </div>\n </div>\n <div>\n <div className=\"text-xs font-medium text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.lastSent\")}\n </div>\n <div className=\"mt-1\">\n <LastSentCell\n lastSentAt={detail.email.lastSentAt}\n sent={detail.email.sent}\n />\n </div>\n </div>\n </div>\n </section>\n\n <section className=\"rounded-2xl bg-card p-5\">\n <h2 className=\"text-sm font-medium text-foreground\">\n {t(\"dispatch.transactionalEmail.preview\")}\n </h2>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.previewDescription\")}\n </p>\n <div className=\"mt-4\">\n <EmailPreviewPane\n appId={appId}\n appPath={detail.appPath}\n id={detail.email.id}\n name={detail.email.name}\n />\n </div>\n </section>\n\n <section className=\"rounded-2xl bg-card p-5\">\n <h2 className=\"text-sm font-medium text-foreground\">\n {t(\"dispatch.transactionalEmail.activityLink\")}\n </h2>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.retentionNote\")}\n </p>\n <div className=\"mt-4\">\n <ActivityTable\n result={\n engagementUnavailable\n ? { available: false, reason: engagementUnavailable }\n : activityQuery.data\n }\n isLoading={activityQuery.isLoading}\n isError={activityQuery.isError}\n error={activityQuery.error}\n onRetry={() => void activityQuery.refetch()}\n />\n </div>\n </section>\n </>\n )}\n </div>\n </DispatchShell>\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transactional-email.js","sourceRoot":"","sources":["../../../src/routes/pages/transactional-email.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAc,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,gCAAgC,CAAC;AACtD,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,OAAO,EACP,cAAc,EACd,QAAQ,EACR,QAAQ,GACT,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EACL,qBAAqB,EACrB,aAAa,EACb,oBAAoB,GAIrB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EACL,aAAa,GAEd,MAAM,+CAA+C,CAAC;AACvD,OAAO,EACL,YAAY,EACZ,SAAS,EACT,YAAY,GAGb,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAC;AAChF,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,WAAW,GACZ,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACxD,OAAO,EACL,KAAK,EACL,SAAS,EACT,SAAS,EACT,SAAS,EACT,WAAW,EACX,QAAQ,GACT,MAAM,2BAA2B,CAAC;AAEnC,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,WAAW,GAAG,EAAE,CAAC;AACvB,MAAM,cAAc,GAAG,EAAE,CAAC;AAS1B,sEAAsE;AACtE,SAAS,aAAa,CAAC,EACrB,KAAK,EACL,KAAK,EACL,OAAO,EACP,IAAI,EACJ,YAAY,GAOb;IACC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;IACjB,OAAO,CACL,KAAC,MAAM,IAAC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,YAC5C,MAAC,aAAa,IAAC,SAAS,EAAC,WAAW,aAClC,MAAC,YAAY,eACX,KAAC,WAAW,cAAE,KAAK,CAAC,IAAI,GAAe,EACvC,KAAC,iBAAiB,cACf,CAAC,CAAC,gDAAgD,CAAC,GAClC,IACP,EAGf,KAAC,gBAAgB,IACf,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,KAAK,CAAC,EAAE,EACZ,IAAI,EAAE,KAAK,CAAC,IAAI,GAChB,IACY,GACT,CACV,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,EACtB,KAAK,EACL,OAAO,EACP,iBAAiB,EACjB,IAAI,EACJ,YAAY,GAOb;IACC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;IACjB,MAAM,aAAa,GAAG,QAAQ,CAAC;QAC7B,QAAQ,EAAE,CAAC,qBAAqB,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,cAAc,CAAC;QACpE,OAAO,EAAE,GAAG,EAAE,CACZ,aAAa,CACX,OAAO,EACP,qBAAqB,EACrB,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,EAC/C,KAAK,CACN;QACH,OAAO,EAAE,IAAI,IAAI,CAAC,iBAAiB;KACpC,CAAC,CAAC;IAEH,OAAO,CACL,KAAC,MAAM,IAAC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,YAC5C,MAAC,aAAa,IAAC,SAAS,EAAC,WAAW,aAClC,MAAC,YAAY,eACX,KAAC,WAAW,cACT,CAAC,CAAC,2CAA2C,EAAE;gCAC9C,IAAI,EAAE,KAAK,CAAC,IAAI;6BACjB,CAAC,GACU,EACd,KAAC,iBAAiB,cACf,CAAC,CAAC,2CAA2C,CAAC,GAC7B,IACP,EACf,KAAC,aAAa,IACZ,MAAM,EACJ,iBAAiB;wBACf,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE;wBACjD,CAAC,CAAC,aAAa,CAAC,IAAI,EAExB,SAAS,EAAE,aAAa,CAAC,SAAS,EAClC,OAAO,EAAE,aAAa,CAAC,OAAO,EAC9B,KAAK,EAAE,aAAa,CAAC,KAAK,EAC1B,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,aAAa,CAAC,OAAO,EAAE,GAC3C,IACY,GACT,CACV,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,EAChB,KAAK,EACL,KAAK,EACL,OAAO,EACP,UAAU,EACV,qBAAqB,EACrB,iBAAiB,GAQlB;IACC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;IACjB,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAC/B,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxD,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC;QACxD,CAAC,CAAC,4BAA4B;QAC9B,CAAC,CAAC,sBAAsB,CAAC;IAE3B,OAAO,CACL,MAAC,QAAQ,eACP,MAAC,SAAS,IAAC,SAAS,EAAC,WAAW,aAC9B,KAAC,IAAI,IACH,EAAE,EAAE,GAAG,UAAU,IAAI,KAAK,IAAI,KAAK,CAAC,EAAE,EAAE,EACxC,SAAS,EAAC,qDAAqD,YAE9D,KAAK,CAAC,IAAI,GACN,EACP,cAAK,SAAS,EAAC,yCAAyC,YACrD,KAAK,CAAC,EAAE,GACL,IACI,EACZ,KAAC,SAAS,IAAC,SAAS,EAAC,kDAAkD,YACpE,KAAK,CAAC,OAAO,GACJ,EACZ,KAAC,SAAS,IAAC,SAAS,EAAC,kDAAkD,YACpE,KAAK,CAAC,cAAc,GACX,EACZ,KAAC,SAAS,IAAC,SAAS,EAAC,kDAAkD,YACpE,KAAK,CAAC,WAAW,GACR,EACZ,KAAC,SAAS,IAAC,SAAS,EAAC,mBAAmB,YACtC,KAAC,SAAS,IAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,GAAI,GAC3C,EACZ,KAAC,SAAS,IAAC,SAAS,EAAC,mBAAmB,YACtC,KAAC,YAAY,IACX,UAAU,EAAE,UAAU,EACtB,iBAAiB,EAAE,qBAAqB,EACxC,OAAO,EAAE,iBAAiB,GAC1B,GACQ,EACZ,KAAC,SAAS,IAAC,SAAS,EAAC,yCAAyC,YAC5D,KAAC,YAAY,IAAC,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,GAAI,GACtD,EACZ,MAAC,SAAS,IAAC,SAAS,EAAC,WAAW,aAC9B,eAAK,SAAS,EAAC,wBAAwB,aACrC,MAAC,MAAM,IACL,OAAO,EAAC,SAAS,EACjB,IAAI,EAAC,IAAI,EACT,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,aAEnC,KAAC,OAAO,IAAC,SAAS,EAAC,QAAQ,GAAG,EAC7B,CAAC,CAAC,qCAAqC,CAAC,IAClC,EACT,MAAC,MAAM,IACL,OAAO,EAAC,OAAO,EACf,IAAI,EAAC,IAAI,EACT,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,aAEpC,KAAC,QAAQ,IAAC,SAAS,EAAC,QAAQ,GAAG,EAC9B,CAAC,CAAC,0CAA0C,CAAC,IACvC,IACL,EACN,KAAC,aAAa,IACZ,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,cAAc,GAC5B,EACF,KAAC,cAAc,IACb,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,iBAAiB,EAAE,qBAAqB,EACxC,IAAI,EAAE,YAAY,EAClB,YAAY,EAAE,eAAe,GAC7B,IACQ,IACH,CACZ,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,EACrB,OAAO,EACP,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,GAMlB;IACC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;IAEjB,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,OAAO,CACL,MAAC,KAAK,IAAC,OAAO,EAAC,aAAa,aAC1B,KAAC,iBAAiB,IAAC,SAAS,EAAC,QAAQ,GAAG,EACxC,KAAC,UAAU,cACR,CAAC,CAAC,+CAA+C,CAAC,GACxC,EACb,KAAC,gBAAgB,cAAE,OAAO,CAAC,KAAK,GAAoB,IAC9C,CACT,CAAC;IACJ,CAAC;IAED,OAAO,CACL,8BACG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CACpB,MAAC,KAAK,IAAC,SAAS,EAAC,MAAM,aACrB,KAAC,cAAc,IAAC,SAAS,EAAC,QAAQ,GAAG,EACrC,KAAC,UAAU,cACR,CAAC,CAAC,8CAA8C,CAAC,GACvC,EACb,KAAC,gBAAgB,cAAE,OAAO,CAAC,UAAU,GAAoB,IACnD,CACT,CAAC,CAAC,CAAC,IAAI,EACP,OAAO,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAC7B,cAAK,SAAS,EAAC,yEAAyE,YACrF,CAAC,CAAC,6CAA6C,CAAC,GAC7C,CACP,CAAC,CAAC,CAAC,CACF,MAAC,KAAK,eACJ,KAAC,WAAW,cACV,MAAC,QAAQ,eACP,KAAC,SAAS,cAAE,CAAC,CAAC,mCAAmC,CAAC,GAAa,EAC/D,KAAC,SAAS,cAAE,CAAC,CAAC,qCAAqC,CAAC,GAAa,EACjE,KAAC,SAAS,cACP,CAAC,CAAC,uCAAuC,CAAC,GACjC,EACZ,KAAC,SAAS,cAAE,CAAC,CAAC,oCAAoC,CAAC,GAAa,EAChE,KAAC,SAAS,cAAE,CAAC,CAAC,mCAAmC,CAAC,GAAa,EAC/D,KAAC,SAAS,cAAE,CAAC,CAAC,sCAAsC,CAAC,GAAa,EAClE,KAAC,SAAS,cAAE,CAAC,CAAC,sCAAsC,CAAC,GAAa,EAClE,KAAC,SAAS,KAAG,IACJ,GACC,EACd,KAAC,SAAS,cACP,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAC7B,KAAC,QAAQ,IAEP,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,OAAO,CAAC,KAAK,EACpB,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,UAAU,EAAE,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAC9C,qBAAqB,EAAE,qBAAqB,EAC5C,iBAAiB,EAAE,iBAAiB,IAN/B,KAAK,CAAC,EAAE,CAOb,CACH,CAAC,GACQ,IACN,CACT,IACA,CACJ,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,EACpB,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,YAAY,EACZ,OAAO,EACP,SAAS,EACT,OAAO,EACP,KAAK,EACL,OAAO,EACP,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,GAclB;IACC,OAAO,CACL,MAAC,WAAW,IACV,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,YAAY,EAC1B,SAAS,EAAC,qBAAqB,aAE/B,MAAC,kBAAkB,IAAC,SAAS,EAAC,qGAAqG,aACjI,gBAAM,SAAS,EAAC,yBAAyB,aACvC,KAAC,gBAAgB,IAAC,SAAS,EAAC,+FAA+F,GAAG,EAC9H,eAAM,SAAS,EAAC,qCAAqC,YAAE,IAAI,GAAQ,IAC9D,EACP,eAAM,SAAS,EAAC,yCAAyC,YAAE,IAAI,GAAQ,IACpD,EACrB,KAAC,kBAAkB,IAAC,SAAS,EAAC,yBAAyB,YACpD,OAAO,CAAC,CAAC,CAAC,CACT,KAAC,gBAAgB,IAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAI,CACrD,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAC1B,KAAC,QAAQ,IAAC,SAAS,EAAC,aAAa,GAAG,CACrC,CAAC,CAAC,CAAC,CACF,KAAC,aAAa,IACZ,OAAO,EAAE,OAAO,EAChB,oBAAoB,EAAE,oBAAoB,EAC1C,qBAAqB,EAAE,qBAAqB,EAC5C,iBAAiB,EAAE,iBAAiB,GACpC,CACH,GACkB,IACT,CACf,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,uBAAuB;IAC7C,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;IACjB,MAAM,SAAS,GAAG,cAAc,CAAoB,qBAAqB,EAAE;QACzE,iBAAiB,EAAE,KAAK;KACzB,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,OAAO,CAClB,GAAG,EAAE,CACH,CAAC,SAAS,CAAC,IAAI,IAAI,EAAE,CAAC;SACnB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC;SACzC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,EACnE,CAAC,SAAS,CAAC,IAAI,CAAC,CACjB,CAAC;IAEF,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAA0B,EAAE,CAAC,CAAC;IACtE,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAEnD,MAAM,WAAW,GAAG,cAAc,CAChC,2BAA2B,EAC3B,EAAE,UAAU,EAAE,WAAW,EAAE,CAC5B,CAAC;IAEF,MAAM,cAAc,GAAG,UAAU,CAAC;QAChC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAC1B,QAAQ,EAAE,CAAC,6BAA6B,EAAE,GAAG,CAAC,EAAE,EAAE,WAAW,CAAC;YAC9D,OAAO,EAAE,GAAG,EAAE,CAAC,oBAAoB,CAAC,GAAG,EAAE,WAAW,CAAC;YACrD,OAAO,EAAE,UAAU,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,IAAI;YAChD,SAAS,EAAE,QAAQ;SACpB,CAAC,CAAC;KACJ,CAAC,CAAC;IAEH,MAAM,aAAa,GAAG,OAAO,CAA8B,GAAG,EAAE;QAC9D,IAAI,CAAC,WAAW,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC;QACxC,MAAM,SAAS,GAAG,qBAAqB,CACrC,WAAW,CAAC,IAAI,EAChB,cAAc;aACX,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;aAC1B,MAAM,CAAC,CAAC,OAAO,EAA8B,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CACrE,CAAC;QACF,OAAO;YACL,KAAK,EAAE,MAAM;YACb,OAAO,EAAE,CAAC,CAAC,yCAAyC,CAAC;YACrD,OAAO,EAAE,CAAC,CAAC,4CAA4C,CAAC;YACxD,MAAM,EAAE,SAAS,CAAC,MAAM;YACxB,KAAK,EAAE,IAAI;YACX,UAAU,EAAE,SAAS,CAAC,UAAU;SACjC,CAAC;IACJ,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC;IAE1C,MAAM,iBAAiB,GAAG,UAAU,CAAC;QACnC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YAC/B,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;YAC5C,MAAM,WAAW,GACf,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK;gBACvB,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;gBACzC,CAAC,CAAC,EAAE,CAAC;YACT,OAAO;gBACL,QAAQ,EAAE;oBACR,uBAAuB;oBACvB,GAAG,CAAC,EAAE;oBACN,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;oBACrB,WAAW;iBACZ;gBACD,OAAO,EAAE,GAAG,EAAE,CACZ,aAAa,CACX,GAAG,CAAC,IAAI,EACR,uBAAuB,EACvB,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,EACxC,MAAM,CACP;gBACH,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,IAAI,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;aAC7D,CAAC;QACJ,CAAC,CAAC;KACH,CAAC,CAAC;IAEH,MAAM,aAAa,GACjB,WAAW,CAAC,SAAS;QACrB,CAAC,UAAU,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;IAClE,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC;IACzE,MAAM,oBAAoB,GAAG,CAAC,CAC5B,8DAA8D,CAC/D,CAAC;IAEF,OAAO,CACL,KAAC,aAAa,IACZ,KAAK,EAAE,CAAC,CAAC,mCAAmC,CAAC,EAC7C,WAAW,EAAE,CAAC,CAAC,yCAAyC,CAAC,YAEzD,eAAK,SAAS,EAAC,qBAAqB,aAClC,MAAC,KAAK,eACJ,KAAC,cAAc,IAAC,SAAS,EAAC,QAAQ,GAAG,EACrC,KAAC,UAAU,cACR,CAAC,CAAC,4CAA4C,CAAC,GACrC,EACb,KAAC,gBAAgB,cACd,CAAC,CAAC,2CAA2C,CAAC,GAC9B,IACb,EAEP,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CACnB,KAAC,gBAAgB,IACf,KAAK,EAAE,SAAS,CAAC,KAAK,EACtB,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,SAAS,CAAC,OAAO,EAAE,GACvC,CACH,CAAC,CAAC,CAAC,IAAI,EAEP,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CACrB,eAAK,SAAS,EAAC,WAAW,aACxB,KAAC,QAAQ,IAAC,SAAS,EAAC,yBAAyB,GAAG,EAChD,KAAC,QAAQ,IAAC,SAAS,EAAC,yBAAyB,GAAG,IAC5C,CACP,CAAC,CAAC,CAAC,IAAI,EAEP,CAAC,SAAS,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAC3C,eAAK,SAAS,EAAC,uFAAuF,aACpG,KAAC,QAAQ,IAAC,SAAS,EAAC,qBAAqB,GAAG,EAC3C,CAAC,CAAC,oCAAoC,CAAC,IACpC,CACP,CAAC,CAAC,CAAC,IAAI,EAER,KAAC,YAAY,IACX,IAAI,EAAE,CAAC,CAAC,yCAAyC,CAAC,EAClD,IAAI,EAAE,CAAC,CAAC,4CAA4C,CAAC,EACrD,IAAI,EAAE,UAAU,EAChB,YAAY,EAAE,aAAa,EAC3B,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,WAAW,CAAC,OAAO,IAAI,OAAO,CAAC,WAAW,CAAC,EACpD,KAAK,EAAE,WAAW,CAAC,KAAK,IAAI,WAAW,EACvC,OAAO,EAAE,GAAG,EAAE;wBACZ,KAAK,WAAW,CAAC,OAAO,EAAE,CAAC;wBAC3B,KAAK,MAAM,KAAK,IAAI,cAAc;4BAAE,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;oBAC3D,CAAC,EACD,oBAAoB,EAAE,IAAI,GAAG,EAAE,EAC/B,qBAAqB,EAAE,oBAAoB,EAC3C,iBAAiB,EAAE,KAAK,GACxB,EAED,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;oBACvB,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;oBACpC,MAAM,eAAe,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;oBACjD,MAAM,gBAAgB,GAAG,eAAe,EAAE,IAAI,CAAC;oBAC/C,MAAM,qBAAqB,GACzB,gBAAgB,IAAI,CAAC,gBAAgB,CAAC,SAAS;wBAC7C,CAAC,CAAC,gBAAgB,CAAC,MAAM;wBACzB,CAAC,CAAC,eAAe,EAAE,OAAO;4BACxB,CAAC,CAAC,eAAe,CAAC,KAAK,YAAY,KAAK;gCACtC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,OAAO;gCAC/B,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC;4BACjC,CAAC,CAAC,IAAI,CAAC;oBACb,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAA2B,CAAC;oBAChE,IAAI,gBAAgB,EAAE,SAAS,EAAE,CAAC;wBAChC,KAAK,MAAM,KAAK,IAAI,gBAAgB,CAAC,IAAI,EAAE,CAAC;4BAC1C,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;wBACpD,CAAC;oBACH,CAAC;oBACD,OAAO,CACL,KAAC,YAAY,IAEX,IAAI,EAAE,GAAG,CAAC,IAAI,EACd,IAAI,EAAE,GAAG,CAAC,IAAI,EACd,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,IAAI,EAC/B,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE,CACrB,WAAW,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,EAE5D,OAAO,EAAE,KAAK,EAAE,IAAI,EACpB,SAAS,EAAE,KAAK,EAAE,SAAS,IAAI,KAAK,EACpC,OAAO,EAAE,KAAK,EAAE,OAAO,IAAI,KAAK,EAChC,KAAK,EAAE,KAAK,EAAE,KAAK,EACnB,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE,OAAO,EAAE,EACpC,oBAAoB,EAAE,oBAAoB,EAC1C,qBAAqB,EAAE,qBAAqB,EAC5C,iBAAiB,EAAE,eAAe,EAAE,SAAS,IAAI,KAAK,IAdjD,GAAG,CAAC,EAAE,CAeX,CACH,CAAC;gBACJ,CAAC,CAAC,IACE,GACQ,CACjB,CAAC;AACJ,CAAC","sourcesContent":["import { callAction, useActionQuery } from \"@agent-native/core/client/hooks\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport {\n IconAlertTriangle,\n IconChevronRight,\n IconEye,\n IconInfoCircle,\n IconList,\n IconMail,\n} from \"@tabler/icons-react\";\nimport { useQueries, useQuery } from \"@tanstack/react-query\";\nimport { useMemo, useState } from \"react\";\nimport { Link, useLocation } from \"react-router\";\n\nimport {\n aggregateSharedEmails,\n callAppAction,\n fetchAppEmailCatalog,\n type AppEmailCatalog,\n type AppTransactionalEmail,\n type LocalTransactionalEmailCatalog,\n} from \"../../client/transactional-emails\";\nimport { ActionQueryError } from \"../../components/action-query-error\";\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport {\n ActivityTable,\n type EmailActivityEntry,\n} from \"../../components/transactional-email-activity\";\nimport {\n OpenRateCell,\n SendsCell,\n LastSentCell,\n type EmailEngagement,\n type ProviderMetricsResult,\n} from \"../../components/transactional-email-metrics\";\nimport { EmailPreviewPane } from \"../../components/transactional-email-preview\";\nimport { Alert, AlertDescription, AlertTitle } from \"../../components/ui/alert\";\nimport { Button } from \"../../components/ui/button\";\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"../../components/ui/collapsible\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from \"../../components/ui/dialog\";\nimport { Skeleton } from \"../../components/ui/skeleton\";\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"../../components/ui/table\";\n\nexport function meta() {\n return [{ title: \"Transactional email — Dispatch\" }];\n}\n\nconst WINDOW_DAYS = 30;\nconst ACTIVITY_LIMIT = 50;\n\ninterface WorkspaceAppRef {\n id: string;\n name: string;\n path: string;\n status?: \"ready\" | \"pending\";\n}\n\n/** Shape of the local `list-transactional-emails` action response. */\nfunction PreviewDialog({\n email,\n appId,\n appPath,\n open,\n onOpenChange,\n}: {\n email: AppTransactionalEmail;\n appId: string;\n appPath: string;\n open: boolean;\n onOpenChange: (next: boolean) => void;\n}) {\n const t = useT();\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-w-3xl\">\n <DialogHeader>\n <DialogTitle>{email.name}</DialogTitle>\n <DialogDescription>\n {t(\"dispatch.transactionalEmail.previewDescription\")}\n </DialogDescription>\n </DialogHeader>\n {/* Dialog content only mounts while open, so this fetches on open and\n drops the request when closed rather than needing an enabled flag. */}\n <EmailPreviewPane\n appId={appId}\n appPath={appPath}\n id={email.id}\n name={email.name}\n />\n </DialogContent>\n </Dialog>\n );\n}\n\nfunction ActivityDialog({\n email,\n appPath,\n unavailableReason,\n open,\n onOpenChange,\n}: {\n email: AppTransactionalEmail;\n appPath: string;\n unavailableReason: string | null;\n open: boolean;\n onOpenChange: (next: boolean) => void;\n}) {\n const t = useT();\n const activityQuery = useQuery({\n queryKey: [\"list-email-activity\", appPath, email.id, ACTIVITY_LIMIT],\n queryFn: () =>\n callAppAction<ProviderMetricsResult<EmailActivityEntry[]>>(\n appPath,\n \"list-email-activity\",\n { templateId: email.id, limit: ACTIVITY_LIMIT },\n \"GET\",\n ),\n enabled: open && !unavailableReason,\n });\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-w-4xl\">\n <DialogHeader>\n <DialogTitle>\n {t(\"dispatch.transactionalEmail.activityTitle\", {\n name: email.name,\n })}\n </DialogTitle>\n <DialogDescription>\n {t(\"dispatch.transactionalEmail.retentionNote\")}\n </DialogDescription>\n </DialogHeader>\n <ActivityTable\n result={\n unavailableReason\n ? { available: false, reason: unavailableReason }\n : activityQuery.data\n }\n isLoading={activityQuery.isLoading}\n isError={activityQuery.isError}\n error={activityQuery.error}\n onRetry={() => void activityQuery.refetch()}\n />\n </DialogContent>\n </Dialog>\n );\n}\n\nfunction EmailRow({\n email,\n appId,\n appPath,\n engagement,\n engagementUnavailable,\n engagementLoading,\n}: {\n email: AppTransactionalEmail;\n appId: string;\n appPath: string;\n engagement: EmailEngagement | undefined;\n engagementUnavailable: string | null;\n engagementLoading: boolean;\n}) {\n const t = useT();\n const location = useLocation();\n const [previewOpen, setPreviewOpen] = useState(false);\n const [activityOpen, setActivityOpen] = useState(false);\n const detailBase = location.pathname.startsWith(\"/admin/\")\n ? \"/admin/transactional-email\"\n : \"/transactional-email\";\n\n return (\n <TableRow>\n <TableCell className=\"align-top\">\n <Link\n to={`${detailBase}/${appId}/${email.id}`}\n className=\"text-sm font-medium text-foreground hover:underline\"\n >\n {email.name}\n </Link>\n <div className=\"font-mono text-xs text-muted-foreground\">\n {email.id}\n </div>\n </TableCell>\n <TableCell className=\"max-w-64 align-top text-xs text-muted-foreground\">\n {email.trigger}\n </TableCell>\n <TableCell className=\"max-w-56 align-top text-xs text-muted-foreground\">\n {email.recipientLabel}\n </TableCell>\n <TableCell className=\"max-w-56 align-top text-xs text-muted-foreground\">\n {email.senderLabel}\n </TableCell>\n <TableCell className=\"align-top text-sm\">\n <SendsCell sent={email.sent} failed={email.failed} />\n </TableCell>\n <TableCell className=\"align-top text-sm\">\n <OpenRateCell\n engagement={engagement}\n unavailableReason={engagementUnavailable}\n loading={engagementLoading}\n />\n </TableCell>\n <TableCell className=\"align-top text-xs text-muted-foreground\">\n <LastSentCell lastSentAt={email.lastSentAt} sent={email.sent} />\n </TableCell>\n <TableCell className=\"align-top\">\n <div className=\"flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setPreviewOpen(true)}\n >\n <IconEye className=\"size-4\" />\n {t(\"dispatch.transactionalEmail.preview\")}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setActivityOpen(true)}\n >\n <IconList className=\"size-4\" />\n {t(\"dispatch.transactionalEmail.activityLink\")}\n </Button>\n </div>\n <PreviewDialog\n email={email}\n appId={appId}\n appPath={appPath}\n open={previewOpen}\n onOpenChange={setPreviewOpen}\n />\n <ActivityDialog\n email={email}\n appPath={appPath}\n unavailableReason={engagementUnavailable}\n open={activityOpen}\n onOpenChange={setActivityOpen}\n />\n </TableCell>\n </TableRow>\n );\n}\n\nfunction AppEmailTable({\n catalog,\n engagementByTemplate,\n engagementUnavailable,\n engagementLoading,\n}: {\n catalog: AppEmailCatalog;\n engagementByTemplate: Map<string, EmailEngagement>;\n engagementUnavailable: string | null;\n engagementLoading: boolean;\n}) {\n const t = useT();\n\n if (catalog.error) {\n return (\n <Alert variant=\"destructive\">\n <IconAlertTriangle className=\"size-4\" />\n <AlertTitle>\n {t(\"dispatch.transactionalEmail.catalogUnreadable\")}\n </AlertTitle>\n <AlertDescription>{catalog.error}</AlertDescription>\n </Alert>\n );\n }\n\n return (\n <>\n {catalog.statsError ? (\n <Alert className=\"mb-4\">\n <IconInfoCircle className=\"size-4\" />\n <AlertTitle>\n {t(\"dispatch.transactionalEmail.countsUnreadable\")}\n </AlertTitle>\n <AlertDescription>{catalog.statsError}</AlertDescription>\n </Alert>\n ) : null}\n {catalog.emails.length === 0 ? (\n <div className=\"rounded-xl border border-dashed px-4 py-6 text-sm text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.appSendsNoEmail\")}\n </div>\n ) : (\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>{t(\"dispatch.transactionalEmail.email\")}</TableHead>\n <TableHead>{t(\"dispatch.transactionalEmail.trigger\")}</TableHead>\n <TableHead>\n {t(\"dispatch.transactionalEmail.recipient\")}\n </TableHead>\n <TableHead>{t(\"dispatch.transactionalEmail.sender\")}</TableHead>\n <TableHead>{t(\"dispatch.transactionalEmail.sends\")}</TableHead>\n <TableHead>{t(\"dispatch.transactionalEmail.openRate\")}</TableHead>\n <TableHead>{t(\"dispatch.transactionalEmail.lastSent\")}</TableHead>\n <TableHead />\n </TableRow>\n </TableHeader>\n <TableBody>\n {catalog.emails.map((email) => (\n <EmailRow\n key={email.id}\n email={email}\n appId={catalog.appId}\n appPath={catalog.appPath}\n engagement={engagementByTemplate.get(email.id)}\n engagementUnavailable={engagementUnavailable}\n engagementLoading={engagementLoading}\n />\n ))}\n </TableBody>\n </Table>\n )}\n </>\n );\n}\n\nfunction AppEmailCard({\n name,\n path,\n open,\n onOpenChange,\n catalog,\n isLoading,\n isError,\n error,\n onRetry,\n engagementByTemplate,\n engagementUnavailable,\n engagementLoading,\n}: {\n name: string;\n path: string;\n open: boolean;\n onOpenChange: (next: boolean) => void;\n catalog: AppEmailCatalog | undefined;\n isLoading: boolean;\n isError: boolean;\n error: unknown;\n onRetry: () => void;\n engagementByTemplate: Map<string, EmailEngagement>;\n engagementUnavailable: string | null;\n engagementLoading: boolean;\n}) {\n return (\n <Collapsible\n open={open}\n onOpenChange={onOpenChange}\n className=\"rounded-2xl bg-card\"\n >\n <CollapsibleTrigger className=\"group flex w-full cursor-pointer items-center justify-between gap-3 p-5 text-left hover:bg-muted/20\">\n <span className=\"flex items-center gap-2\">\n <IconChevronRight className=\"h-4 w-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-90\" />\n <span className=\"text-sm font-medium text-foreground\">{name}</span>\n </span>\n <span className=\"font-mono text-xs text-muted-foreground\">{path}</span>\n </CollapsibleTrigger>\n <CollapsibleContent className=\"border-t px-5 pb-5 pt-4\">\n {isError ? (\n <ActionQueryError error={error} onRetry={onRetry} />\n ) : isLoading || !catalog ? (\n <Skeleton className=\"h-24 w-full\" />\n ) : (\n <AppEmailTable\n catalog={catalog}\n engagementByTemplate={engagementByTemplate}\n engagementUnavailable={engagementUnavailable}\n engagementLoading={engagementLoading}\n />\n )}\n </CollapsibleContent>\n </Collapsible>\n );\n}\n\nexport default function TransactionalEmailRoute() {\n const t = useT();\n const appsQuery = useActionQuery<WorkspaceAppRef[]>(\"list-workspace-apps\", {\n includeAgentCards: false,\n });\n\n const apps = useMemo(\n () =>\n (appsQuery.data ?? [])\n .filter((app) => app.status !== \"pending\")\n .map((app) => ({ id: app.id, name: app.name, path: app.path })),\n [appsQuery.data],\n );\n\n const [expanded, setExpanded] = useState<Record<string, boolean>>({});\n const [sharedOpen, setSharedOpen] = useState(true);\n\n const sharedQuery = useActionQuery<LocalTransactionalEmailCatalog>(\n \"list-transactional-emails\",\n { windowDays: WINDOW_DAYS },\n );\n\n const catalogQueries = useQueries({\n queries: apps.map((app) => ({\n queryKey: [\"transactional-email-catalog\", app.id, WINDOW_DAYS],\n queryFn: () => fetchAppEmailCatalog(app, WINDOW_DAYS),\n enabled: sharedOpen || expanded[app.id] === true,\n staleTime: Infinity,\n })),\n });\n\n const sharedCatalog = useMemo<AppEmailCatalog | undefined>(() => {\n if (!sharedQuery.data) return undefined;\n const aggregate = aggregateSharedEmails(\n sharedQuery.data,\n catalogQueries\n .map((query) => query.data)\n .filter((catalog): catalog is AppEmailCatalog => Boolean(catalog)),\n );\n return {\n appId: \"core\",\n appName: t(\"dispatch.transactionalEmail.sharedTitle\"),\n appPath: t(\"dispatch.transactionalEmail.sharedSubtitle\"),\n emails: aggregate.emails,\n error: null,\n statsError: aggregate.statsError,\n };\n }, [sharedQuery.data, catalogQueries, t]);\n\n const engagementQueries = useQueries({\n queries: apps.map((app, index) => {\n const catalog = catalogQueries[index]?.data;\n const templateIds =\n catalog && !catalog.error\n ? catalog.emails.map((email) => email.id)\n : [];\n return {\n queryKey: [\n \"list-email-engagement\",\n app.id,\n templateIds.join(\",\"),\n WINDOW_DAYS,\n ],\n queryFn: () =>\n callAppAction<ProviderMetricsResult<EmailEngagement[]>>(\n app.path,\n \"list-email-engagement\",\n { templateIds, windowDays: WINDOW_DAYS },\n \"POST\",\n ),\n enabled: expanded[app.id] === true && templateIds.length > 0,\n };\n }),\n });\n\n const sharedLoading =\n sharedQuery.isLoading ||\n (sharedOpen && catalogQueries.some((query) => query.isLoading));\n const sharedError = catalogQueries.find((query) => query.isError)?.error;\n const sharedProviderReason = t(\n \"dispatch.transactionalEmail.sharedProviderMetricsUnavailable\",\n );\n\n return (\n <DispatchShell\n title={t(\"dispatch.transactionalEmail.title\")}\n description={t(\"dispatch.transactionalEmail.description\")}\n >\n <div className=\"flex flex-col gap-4\">\n <Alert>\n <IconInfoCircle className=\"size-4\" />\n <AlertTitle>\n {t(\"dispatch.transactionalEmail.retentionTitle\")}\n </AlertTitle>\n <AlertDescription>\n {t(\"dispatch.transactionalEmail.retentionNote\")}\n </AlertDescription>\n </Alert>\n\n {appsQuery.isError ? (\n <ActionQueryError\n error={appsQuery.error}\n onRetry={() => void appsQuery.refetch()}\n />\n ) : null}\n\n {appsQuery.isLoading ? (\n <div className=\"space-y-3\">\n <Skeleton className=\"h-16 w-full rounded-2xl\" />\n <Skeleton className=\"h-16 w-full rounded-2xl\" />\n </div>\n ) : null}\n\n {!appsQuery.isLoading && apps.length === 0 ? (\n <div className=\"rounded-2xl border border-dashed px-6 py-12 text-center text-sm text-muted-foreground\">\n <IconMail className=\"mx-auto mb-2 size-5\" />\n {t(\"dispatch.transactionalEmail.noApps\")}\n </div>\n ) : null}\n\n <AppEmailCard\n name={t(\"dispatch.transactionalEmail.sharedTitle\")}\n path={t(\"dispatch.transactionalEmail.sharedSubtitle\")}\n open={sharedOpen}\n onOpenChange={setSharedOpen}\n catalog={sharedCatalog}\n isLoading={sharedLoading}\n isError={sharedQuery.isError || Boolean(sharedError)}\n error={sharedQuery.error ?? sharedError}\n onRetry={() => {\n void sharedQuery.refetch();\n for (const query of catalogQueries) void query.refetch();\n }}\n engagementByTemplate={new Map()}\n engagementUnavailable={sharedProviderReason}\n engagementLoading={false}\n />\n\n {apps.map((app, index) => {\n const query = catalogQueries[index];\n const engagementQuery = engagementQueries[index];\n const engagementResult = engagementQuery?.data;\n const engagementUnavailable =\n engagementResult && !engagementResult.available\n ? engagementResult.reason\n : engagementQuery?.isError\n ? engagementQuery.error instanceof Error\n ? engagementQuery.error.message\n : String(engagementQuery.error)\n : null;\n const engagementByTemplate = new Map<string, EmailEngagement>();\n if (engagementResult?.available) {\n for (const entry of engagementResult.data) {\n engagementByTemplate.set(entry.templateId, entry);\n }\n }\n return (\n <AppEmailCard\n key={app.id}\n name={app.name}\n path={app.path}\n open={expanded[app.id] === true}\n onOpenChange={(next) =>\n setExpanded((current) => ({ ...current, [app.id]: next }))\n }\n catalog={query?.data}\n isLoading={query?.isLoading ?? false}\n isError={query?.isError ?? false}\n error={query?.error}\n onRetry={() => void query?.refetch()}\n engagementByTemplate={engagementByTemplate}\n engagementUnavailable={engagementUnavailable}\n engagementLoading={engagementQuery?.isLoading ?? false}\n />\n );\n })}\n </div>\n </DispatchShell>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"transactional-email.js","sourceRoot":"","sources":["../../../src/routes/pages/transactional-email.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useActionQuery } from \"@agent-native/core/client/hooks\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport {\n IconAlertTriangle,\n IconChevronRight,\n IconEye,\n IconInfoCircle,\n IconList,\n IconMail,\n} from \"@tabler/icons-react\";\nimport { useQueries, useQuery } from \"@tanstack/react-query\";\nimport { useMemo, useState } from \"react\";\nimport { Link, useLocation } from \"react-router\";\n\nimport {\n aggregateSharedEmails,\n callAppAction,\n fetchAppEmailCatalog,\n type AppEmailCatalog,\n type AppTransactionalEmail,\n type LocalTransactionalEmailCatalog,\n} from \"../../client/transactional-emails\";\nimport { ActionQueryError } from \"../../components/action-query-error\";\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport {\n ActivityTable,\n type EmailActivityEntry,\n} from \"../../components/transactional-email-activity\";\nimport {\n OpenRateCell,\n SendsCell,\n LastSentCell,\n type EmailEngagement,\n type ProviderMetricsResult,\n} from \"../../components/transactional-email-metrics\";\nimport { EmailPreviewPane } from \"../../components/transactional-email-preview\";\nimport { Alert, AlertDescription, AlertTitle } from \"../../components/ui/alert\";\nimport { Button } from \"../../components/ui/button\";\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"../../components/ui/collapsible\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from \"../../components/ui/dialog\";\nimport { Skeleton } from \"../../components/ui/skeleton\";\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"../../components/ui/table\";\n\nexport function meta() {\n return [{ title: \"Transactional email — Dispatch\" }];\n}\n\nconst WINDOW_DAYS = 30;\nconst ACTIVITY_LIMIT = 50;\n\ninterface WorkspaceAppRef {\n id: string;\n name: string;\n path: string;\n status?: \"ready\" | \"pending\";\n}\n\n/** Shape of the local `list-transactional-emails` action response. */\nfunction PreviewDialog({\n email,\n appId,\n appPath,\n open,\n onOpenChange,\n}: {\n email: AppTransactionalEmail;\n appId: string;\n appPath: string;\n open: boolean;\n onOpenChange: (next: boolean) => void;\n}) {\n const t = useT();\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-w-3xl\">\n <DialogHeader>\n <DialogTitle>{email.name}</DialogTitle>\n <DialogDescription>\n {t(\"dispatch.transactionalEmail.previewDescription\")}\n </DialogDescription>\n </DialogHeader>\n {/* Dialog content only mounts while open, so this fetches on open and\n drops the request when closed rather than needing an enabled flag. */}\n <EmailPreviewPane\n appId={appId}\n appPath={appPath}\n id={email.id}\n name={email.name}\n />\n </DialogContent>\n </Dialog>\n );\n}\n\nfunction ActivityDialog({\n email,\n appPath,\n unavailableReason,\n open,\n onOpenChange,\n}: {\n email: AppTransactionalEmail;\n appPath: string;\n unavailableReason: string | null;\n open: boolean;\n onOpenChange: (next: boolean) => void;\n}) {\n const t = useT();\n const activityQuery = useQuery({\n queryKey: [\"list-email-activity\", appPath, email.id, ACTIVITY_LIMIT],\n queryFn: () =>\n callAppAction<ProviderMetricsResult<EmailActivityEntry[]>>(\n appPath,\n \"list-email-activity\",\n { templateId: email.id, limit: ACTIVITY_LIMIT },\n \"GET\",\n ),\n enabled: open && !unavailableReason,\n });\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-w-4xl\">\n <DialogHeader>\n <DialogTitle>\n {t(\"dispatch.transactionalEmail.activityTitle\", {\n name: email.name,\n })}\n </DialogTitle>\n <DialogDescription>\n {t(\"dispatch.transactionalEmail.retentionNote\")}\n </DialogDescription>\n </DialogHeader>\n <ActivityTable\n result={\n unavailableReason\n ? { available: false, reason: unavailableReason }\n : activityQuery.data\n }\n isLoading={activityQuery.isLoading}\n isError={activityQuery.isError}\n error={activityQuery.error}\n onRetry={() => void activityQuery.refetch()}\n />\n </DialogContent>\n </Dialog>\n );\n}\n\nfunction EmailRow({\n email,\n appId,\n appPath,\n engagement,\n engagementUnavailable,\n engagementLoading,\n}: {\n email: AppTransactionalEmail;\n appId: string;\n appPath: string;\n engagement: EmailEngagement | undefined;\n engagementUnavailable: string | null;\n engagementLoading: boolean;\n}) {\n const t = useT();\n const location = useLocation();\n const [previewOpen, setPreviewOpen] = useState(false);\n const [activityOpen, setActivityOpen] = useState(false);\n const detailBase = location.pathname.startsWith(\"/admin/\")\n ? \"/admin/transactional-email\"\n : \"/transactional-email\";\n\n return (\n <TableRow>\n <TableCell className=\"align-top\">\n <Link\n to={`${detailBase}/${appId}/${email.id}`}\n className=\"text-sm font-medium text-foreground hover:underline\"\n >\n {email.name}\n </Link>\n <div className=\"font-mono text-xs text-muted-foreground\">\n {email.id}\n </div>\n </TableCell>\n <TableCell className=\"max-w-64 align-top text-xs text-muted-foreground\">\n {email.trigger}\n </TableCell>\n <TableCell className=\"max-w-56 align-top text-xs text-muted-foreground\">\n {email.recipientLabel}\n </TableCell>\n <TableCell className=\"max-w-56 align-top text-xs text-muted-foreground\">\n {email.senderLabel}\n </TableCell>\n <TableCell className=\"align-top text-sm\">\n <SendsCell sent={email.sent} failed={email.failed} />\n </TableCell>\n <TableCell className=\"align-top text-sm\">\n <OpenRateCell\n engagement={engagement}\n unavailableReason={engagementUnavailable}\n loading={engagementLoading}\n />\n </TableCell>\n <TableCell className=\"align-top text-xs text-muted-foreground\">\n <LastSentCell lastSentAt={email.lastSentAt} sent={email.sent} />\n </TableCell>\n <TableCell className=\"align-top\">\n <div className=\"flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setPreviewOpen(true)}\n >\n <IconEye className=\"size-4\" />\n {t(\"dispatch.transactionalEmail.preview\")}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setActivityOpen(true)}\n >\n <IconList className=\"size-4\" />\n {t(\"dispatch.transactionalEmail.activityLink\")}\n </Button>\n </div>\n <PreviewDialog\n email={email}\n appId={appId}\n appPath={appPath}\n open={previewOpen}\n onOpenChange={setPreviewOpen}\n />\n <ActivityDialog\n email={email}\n appPath={appPath}\n unavailableReason={engagementUnavailable}\n open={activityOpen}\n onOpenChange={setActivityOpen}\n />\n </TableCell>\n </TableRow>\n );\n}\n\nfunction AppEmailTable({\n catalog,\n engagementByTemplate,\n engagementUnavailable,\n engagementLoading,\n}: {\n catalog: AppEmailCatalog;\n engagementByTemplate: Map<string, EmailEngagement>;\n engagementUnavailable: string | null;\n engagementLoading: boolean;\n}) {\n const t = useT();\n\n if (catalog.error) {\n return (\n <Alert variant=\"destructive\">\n <IconAlertTriangle className=\"size-4\" />\n <AlertTitle>\n {t(\"dispatch.transactionalEmail.catalogUnreadable\")}\n </AlertTitle>\n <AlertDescription>{catalog.error}</AlertDescription>\n </Alert>\n );\n }\n\n return (\n <>\n {catalog.statsError ? (\n <Alert className=\"mb-4\">\n <IconInfoCircle className=\"size-4\" />\n <AlertTitle>\n {t(\"dispatch.transactionalEmail.countsUnreadable\")}\n </AlertTitle>\n <AlertDescription>{catalog.statsError}</AlertDescription>\n </Alert>\n ) : null}\n {catalog.emails.length === 0 ? (\n <div className=\"rounded-xl border border-dashed px-4 py-6 text-sm text-muted-foreground\">\n {t(\"dispatch.transactionalEmail.appSendsNoEmail\")}\n </div>\n ) : (\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>{t(\"dispatch.transactionalEmail.email\")}</TableHead>\n <TableHead>{t(\"dispatch.transactionalEmail.trigger\")}</TableHead>\n <TableHead>\n {t(\"dispatch.transactionalEmail.recipient\")}\n </TableHead>\n <TableHead>{t(\"dispatch.transactionalEmail.sender\")}</TableHead>\n <TableHead>{t(\"dispatch.transactionalEmail.sends\")}</TableHead>\n <TableHead>{t(\"dispatch.transactionalEmail.openRate\")}</TableHead>\n <TableHead>{t(\"dispatch.transactionalEmail.lastSent\")}</TableHead>\n <TableHead />\n </TableRow>\n </TableHeader>\n <TableBody>\n {catalog.emails.map((email) => (\n <EmailRow\n key={email.id}\n email={email}\n appId={catalog.appId}\n appPath={catalog.appPath}\n engagement={engagementByTemplate.get(email.id)}\n engagementUnavailable={engagementUnavailable}\n engagementLoading={engagementLoading}\n />\n ))}\n </TableBody>\n </Table>\n )}\n </>\n );\n}\n\nfunction AppEmailCard({\n name,\n path,\n open,\n onOpenChange,\n catalog,\n isLoading,\n isError,\n error,\n onRetry,\n engagementByTemplate,\n engagementUnavailable,\n engagementLoading,\n}: {\n name: string;\n path: string;\n open: boolean;\n onOpenChange: (next: boolean) => void;\n catalog: AppEmailCatalog | undefined;\n isLoading: boolean;\n isError: boolean;\n error: unknown;\n onRetry: () => void;\n engagementByTemplate: Map<string, EmailEngagement>;\n engagementUnavailable: string | null;\n engagementLoading: boolean;\n}) {\n return (\n <Collapsible\n open={open}\n onOpenChange={onOpenChange}\n className=\"rounded-2xl bg-card\"\n >\n <CollapsibleTrigger className=\"group flex w-full cursor-pointer items-center justify-between gap-3 p-5 text-left hover:bg-muted/20\">\n <span className=\"flex items-center gap-2\">\n <IconChevronRight className=\"h-4 w-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-90\" />\n <span className=\"text-sm font-medium text-foreground\">{name}</span>\n </span>\n <span className=\"font-mono text-xs text-muted-foreground\">{path}</span>\n </CollapsibleTrigger>\n <CollapsibleContent className=\"border-t px-5 pb-5 pt-4\">\n {isError ? (\n <ActionQueryError error={error} onRetry={onRetry} />\n ) : isLoading || !catalog ? (\n <Skeleton className=\"h-24 w-full\" />\n ) : (\n <AppEmailTable\n catalog={catalog}\n engagementByTemplate={engagementByTemplate}\n engagementUnavailable={engagementUnavailable}\n engagementLoading={engagementLoading}\n />\n )}\n </CollapsibleContent>\n </Collapsible>\n );\n}\n\nexport default function TransactionalEmailRoute() {\n const t = useT();\n const appsQuery = useActionQuery<WorkspaceAppRef[]>(\"list-workspace-apps\", {\n includeAgentCards: false,\n });\n\n const apps = useMemo(\n () =>\n (appsQuery.data ?? [])\n .filter((app) => app.status !== \"pending\")\n .map((app) => ({ id: app.id, name: app.name, path: app.path })),\n [appsQuery.data],\n );\n\n const [expanded, setExpanded] = useState<Record<string, boolean>>({});\n const [sharedOpen, setSharedOpen] = useState(true);\n\n const sharedQuery = useActionQuery<LocalTransactionalEmailCatalog>(\n \"list-transactional-emails\",\n { windowDays: WINDOW_DAYS },\n );\n\n const catalogQueries = useQueries({\n queries: apps.map((app) => ({\n queryKey: [\"transactional-email-catalog\", app.id, WINDOW_DAYS],\n queryFn: () => fetchAppEmailCatalog(app, WINDOW_DAYS),\n enabled: sharedOpen || expanded[app.id] === true,\n staleTime: Infinity,\n })),\n });\n\n const sharedCatalog = useMemo<AppEmailCatalog | undefined>(() => {\n if (!sharedQuery.data) return undefined;\n const aggregate = aggregateSharedEmails(\n sharedQuery.data,\n catalogQueries\n .map((query) => query.data)\n .filter((catalog): catalog is AppEmailCatalog => Boolean(catalog)),\n );\n return {\n appId: \"core\",\n appName: t(\"dispatch.transactionalEmail.sharedTitle\"),\n appPath: t(\"dispatch.transactionalEmail.sharedSubtitle\"),\n emails: aggregate.emails,\n error: null,\n statsError: aggregate.statsError,\n };\n }, [sharedQuery.data, catalogQueries, t]);\n\n const engagementQueries = useQueries({\n queries: apps.map((app, index) => {\n const catalog = catalogQueries[index]?.data;\n const templateIds =\n catalog && !catalog.error\n ? catalog.emails.map((email) => email.id)\n : [];\n return {\n queryKey: [\n \"list-email-engagement\",\n app.id,\n templateIds.join(\",\"),\n WINDOW_DAYS,\n ],\n queryFn: () =>\n callAppAction<ProviderMetricsResult<EmailEngagement[]>>(\n app.path,\n \"list-email-engagement\",\n { templateIds, windowDays: WINDOW_DAYS },\n \"POST\",\n ),\n enabled: expanded[app.id] === true && templateIds.length > 0,\n };\n }),\n });\n\n const sharedLoading =\n sharedQuery.isLoading ||\n (sharedOpen && catalogQueries.some((query) => query.isLoading));\n const sharedError = catalogQueries.find((query) => query.isError)?.error;\n const sharedProviderReason = t(\n \"dispatch.transactionalEmail.sharedProviderMetricsUnavailable\",\n );\n\n return (\n <DispatchShell\n title={t(\"dispatch.transactionalEmail.title\")}\n description={t(\"dispatch.transactionalEmail.description\")}\n >\n <div className=\"flex flex-col gap-4\">\n <Alert>\n <IconInfoCircle className=\"size-4\" />\n <AlertTitle>\n {t(\"dispatch.transactionalEmail.retentionTitle\")}\n </AlertTitle>\n <AlertDescription>\n {t(\"dispatch.transactionalEmail.retentionNote\")}\n </AlertDescription>\n </Alert>\n\n {appsQuery.isError ? (\n <ActionQueryError\n error={appsQuery.error}\n onRetry={() => void appsQuery.refetch()}\n />\n ) : null}\n\n {appsQuery.isLoading ? (\n <div className=\"space-y-3\">\n <Skeleton className=\"h-16 w-full rounded-2xl\" />\n <Skeleton className=\"h-16 w-full rounded-2xl\" />\n </div>\n ) : null}\n\n {!appsQuery.isLoading && apps.length === 0 ? (\n <div className=\"rounded-2xl border border-dashed px-6 py-12 text-center text-sm text-muted-foreground\">\n <IconMail className=\"mx-auto mb-2 size-5\" />\n {t(\"dispatch.transactionalEmail.noApps\")}\n </div>\n ) : null}\n\n <AppEmailCard\n name={t(\"dispatch.transactionalEmail.sharedTitle\")}\n path={t(\"dispatch.transactionalEmail.sharedSubtitle\")}\n open={sharedOpen}\n onOpenChange={setSharedOpen}\n catalog={sharedCatalog}\n isLoading={sharedLoading}\n isError={sharedQuery.isError || Boolean(sharedError)}\n error={sharedQuery.error ?? sharedError}\n onRetry={() => {\n void sharedQuery.refetch();\n for (const query of catalogQueries) void query.refetch();\n }}\n engagementByTemplate={new Map()}\n engagementUnavailable={sharedProviderReason}\n engagementLoading={false}\n />\n\n {apps.map((app, index) => {\n const query = catalogQueries[index];\n const engagementQuery = engagementQueries[index];\n const engagementResult = engagementQuery?.data;\n const engagementUnavailable =\n engagementResult && !engagementResult.available\n ? engagementResult.reason\n : engagementQuery?.isError\n ? engagementQuery.error instanceof Error\n ? engagementQuery.error.message\n : String(engagementQuery.error)\n : null;\n const engagementByTemplate = new Map<string, EmailEngagement>();\n if (engagementResult?.available) {\n for (const entry of engagementResult.data) {\n engagementByTemplate.set(entry.templateId, entry);\n }\n }\n return (\n <AppEmailCard\n key={app.id}\n name={app.name}\n path={app.path}\n open={expanded[app.id] === true}\n onOpenChange={(next) =>\n setExpanded((current) => ({ ...current, [app.id]: next }))\n }\n catalog={query?.data}\n isLoading={query?.isLoading ?? false}\n isError={query?.isError ?? false}\n error={query?.error}\n onRetry={() => void query?.refetch()}\n engagementByTemplate={engagementByTemplate}\n engagementUnavailable={engagementUnavailable}\n engagementLoading={engagementQuery?.isLoading ?? false}\n />\n );\n })}\n </div>\n </DispatchShell>\n );\n}\n"]}
|