@agent-native/dispatch 0.31.4 → 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.
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-app-card.d.ts","sourceRoot":"","sources":["../../src/components/workspace-app-card.tsx"],"names":[],"mappings":"AA4BA,OAAO,EAOL,KAAK,mBAAmB,EACzB,MAAM,uBAAuB,CAAC;AAiC/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,mDAkOA"}
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 }), !isPending ? (_jsx("div", { className: "pointer-events-auto", children: _jsx(ShareButton, { resourceType: "workspace-app", resourceId: app.id, resourceTitle: app.name, trigger: "icon", triggerClassName: APP_CARD_ACTION_CLASS }) })) : null, _jsx(WorkspaceAppSettings, { app: app, isArchived: isArchived, isPending: isPending, onEdit: () => setEditOpen(true), onKeys: () => setKeysOpen(true), onResources: () => setResourcesOpen(true), onArchive: handleArchive, onUnarchive: handleUnarchive, onRemovePending: handleRemovePending, labels: {
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
- return (_jsxs(DropdownMenu, { children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { type: "button", variant: "ghost", size: "sm", "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 && !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 })] })] }));
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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/dispatch",
3
- "version": "0.31.4",
3
+ "version": "0.31.5",
4
4
  "description": "Dispatch — workspace control plane for agent-native apps. Vault, integrations, destinations, scheduled jobs, and cross-app delegation, shipped as a single drop-in package.",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -101,10 +101,10 @@
101
101
  "typescript-7": "npm:typescript@^7.0.2",
102
102
  "vite": "8.1.0",
103
103
  "vitest": "^4.1.5",
104
- "@agent-native/core": "0.0.0-beta-20260820210146"
104
+ "@agent-native/core": "0.167.1"
105
105
  },
106
106
  "peerDependencies": {
107
- "@agent-native/core": "0.0.0-beta-20260820210146",
107
+ "@agent-native/core": ">=0.8.0",
108
108
  "react": ">=19.2.7",
109
109
  "react-dom": ">=19.2.7",
110
110
  "react-router": ">=8"
@@ -1,4 +1,5 @@
1
1
  // @vitest-environment happy-dom
2
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
2
3
  import React, { act } from "react";
3
4
  import { createRoot, type Root } from "react-dom/client";
4
5
  import { MemoryRouter } from "react-router";
@@ -7,13 +8,29 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
7
8
  import { TooltipProvider } from "./ui/tooltip";
8
9
  import { WorkspaceAppCard } from "./workspace-app-card";
9
10
 
10
- vi.mock("@agent-native/core/client/sharing", () => ({
11
- ShareButton: ({ resourceTitle }: { resourceTitle?: string }) =>
12
- React.createElement(
13
- "button",
14
- { type: "button", "aria-label": `Share ${resourceTitle ?? "app"}` },
15
- "Share",
16
- ),
11
+ vi.mock("../../../core/dist/client/use-action.js", () => ({
12
+ useActionMutation: () => ({
13
+ mutate: vi.fn(),
14
+ isPending: false,
15
+ }),
16
+ useActionQuery: () => ({
17
+ data: {
18
+ ownerEmail: "owner@example.com",
19
+ orgId: null,
20
+ visibility: "private",
21
+ role: "owner",
22
+ shares: [],
23
+ },
24
+ isLoading: false,
25
+ isError: false,
26
+ error: null,
27
+ refetch: vi.fn(async () => undefined),
28
+ }),
29
+ }));
30
+
31
+ vi.mock("../../../core/dist/client/i18n.js", () => ({
32
+ useT: () => (key: string, values?: Record<string, unknown>) =>
33
+ String(values?.defaultValue ?? key),
17
34
  }));
18
35
 
19
36
  vi.mock("@agent-native/core/client/hooks", () => ({
@@ -44,6 +61,7 @@ vi.mock("@agent-native/core/client/host", () => ({
44
61
  describe("WorkspaceAppCard", () => {
45
62
  let container: HTMLDivElement;
46
63
  let root: Root;
64
+ let queryClient: QueryClient;
47
65
 
48
66
  beforeEach(() => {
49
67
  frameState.inBuilderFrame = false;
@@ -51,10 +69,17 @@ describe("WorkspaceAppCard", () => {
51
69
  container = document.createElement("div");
52
70
  document.body.appendChild(container);
53
71
  root = createRoot(container);
72
+ queryClient = new QueryClient({
73
+ defaultOptions: {
74
+ queries: { retry: false },
75
+ mutations: { retry: false },
76
+ },
77
+ });
54
78
  });
55
79
 
56
80
  afterEach(() => {
57
81
  act(() => root.unmount());
82
+ queryClient.clear();
58
83
  container.remove();
59
84
  vi.unstubAllGlobals();
60
85
  });
@@ -193,6 +218,77 @@ describe("WorkspaceAppCard", () => {
193
218
  }
194
219
  });
195
220
 
221
+ it("opens Share from the app settings menu instead of the card actions", async () => {
222
+ const animationFrameCallbacks: FrameRequestCallback[] = [];
223
+ vi.stubGlobal("requestAnimationFrame", (callback: FrameRequestCallback) => {
224
+ animationFrameCallbacks.push(callback);
225
+ return animationFrameCallbacks.length;
226
+ });
227
+
228
+ await act(async () => {
229
+ root.render(
230
+ <QueryClientProvider client={queryClient}>
231
+ <MemoryRouter>
232
+ <TooltipProvider>
233
+ <WorkspaceAppCard
234
+ app={{
235
+ id: "analytics",
236
+ name: "Analytics",
237
+ path: "/analytics",
238
+ status: "ready",
239
+ }}
240
+ />
241
+ </TooltipProvider>
242
+ </MemoryRouter>
243
+ </QueryClientProvider>,
244
+ );
245
+ });
246
+
247
+ expect(container.querySelector('button[aria-label="Share"]')).toBeNull();
248
+
249
+ const settingsButton = container.querySelector<HTMLButtonElement>(
250
+ 'button[aria-label="Settings for Analytics"]',
251
+ );
252
+ expect(settingsButton).not.toBeNull();
253
+
254
+ await act(async () => {
255
+ settingsButton?.dispatchEvent(
256
+ new MouseEvent("pointerdown", { bubbles: true, button: 0 }),
257
+ );
258
+ });
259
+
260
+ const shareItem = Array.from(
261
+ document.querySelectorAll<HTMLElement>('[role="menuitem"]'),
262
+ ).find((item) => item.textContent?.trim() === "Share");
263
+ expect(shareItem).not.toBeUndefined();
264
+
265
+ await act(async () => shareItem?.click());
266
+
267
+ expect(container.querySelector('button[aria-label="Share"]')).toBeNull();
268
+ expect(document.querySelector('[role="menu"]')).toBeNull();
269
+ expect(animationFrameCallbacks).toHaveLength(1);
270
+
271
+ await act(async () => animationFrameCallbacks.shift()?.(0));
272
+
273
+ expect(
274
+ container.querySelector('button[aria-label="Share"]'),
275
+ ).not.toBeNull();
276
+ expect(
277
+ document.body.querySelector("[data-agent-native-share-overlay]"),
278
+ ).not.toBeNull();
279
+
280
+ const shareButton = container.querySelector<HTMLButtonElement>(
281
+ 'button[aria-label="Share"]',
282
+ );
283
+ expect(shareButton).not.toBeNull();
284
+
285
+ await act(async () => shareButton?.click());
286
+ expect(animationFrameCallbacks).toHaveLength(1);
287
+
288
+ await act(async () => animationFrameCallbacks.shift()?.(0));
289
+ expect(document.activeElement).toBe(settingsButton);
290
+ });
291
+
196
292
  it("keeps pinning in the app open menu", async () => {
197
293
  const onTogglePinned = vi.fn();
198
294
  await act(async () => {
@@ -270,7 +366,7 @@ describe("WorkspaceAppCard", () => {
270
366
  expect(settingsMenu?.className).toContain("w-48");
271
367
  expect(settingsMenu?.className).toContain("bg-popover");
272
368
  expect(settingsMenu?.className).toContain("shadow-md");
273
- expect(document.querySelectorAll('[role="menuitem"] svg').length).toBe(4);
369
+ expect(document.querySelectorAll('[role="menuitem"] svg').length).toBe(5);
274
370
 
275
371
  await act(async () => resourcesItem?.click());
276
372
 
@@ -15,13 +15,14 @@ import {
15
15
  IconFileText,
16
16
  IconKey,
17
17
  IconPin,
18
+ IconShare3,
18
19
  IconSettings,
19
20
  IconTrash,
20
21
  IconUser,
21
22
  IconUsersGroup,
22
23
  IconWorld,
23
24
  } from "@tabler/icons-react";
24
- import { useEffect, useState, type FormEvent } from "react";
25
+ import { useEffect, useRef, useState, type FormEvent } from "react";
25
26
  import { useNavigate } from "react-router";
26
27
  import { toast } from "sonner";
27
28
 
@@ -67,6 +68,23 @@ import { AppResourceEffectiveStack } from "./workspace-resource-effective-stack"
67
68
  const APP_CARD_ACTION_CLASS =
68
69
  "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";
69
70
 
71
+ function deferWorkspaceAppOverlayOpen(
72
+ event: { preventDefault: () => void },
73
+ closeMenu: () => void,
74
+ openOverlay: () => void,
75
+ ): void {
76
+ event.preventDefault();
77
+ closeMenu();
78
+ if (
79
+ typeof window !== "undefined" &&
80
+ typeof window.requestAnimationFrame === "function"
81
+ ) {
82
+ window.requestAnimationFrame(() => openOverlay());
83
+ } else {
84
+ setTimeout(openOverlay, 0);
85
+ }
86
+ }
87
+
70
88
  export function WorkspaceAppCard({
71
89
  app,
72
90
  className,
@@ -211,17 +229,6 @@ export function WorkspaceAppCard({
211
229
  pendingOpenLabel={pendingOpenLabel}
212
230
  onTogglePinned={onTogglePinned}
213
231
  />
214
- {!isPending ? (
215
- <div className="pointer-events-auto">
216
- <ShareButton
217
- resourceType="workspace-app"
218
- resourceId={app.id}
219
- resourceTitle={app.name}
220
- trigger="icon"
221
- triggerClassName={APP_CARD_ACTION_CLASS}
222
- />
223
- </div>
224
- ) : null}
225
232
  <WorkspaceAppSettings
226
233
  app={app}
227
234
  isArchived={isArchived}
@@ -236,6 +243,7 @@ export function WorkspaceAppCard({
236
243
  createdBy: t("agents.dashboardMetadataCreatedBy"),
237
244
  owner: t("dispatch.pages.appMetadataOwner"),
238
245
  teams: t("dispatch.pages.appMetadataTeams"),
246
+ share: t("share.share", { defaultValue: "Share" }),
239
247
  }}
240
248
  />
241
249
  </div>
@@ -376,6 +384,7 @@ type WorkspaceAppMetadataLabels = {
376
384
  createdBy: string;
377
385
  owner: string;
378
386
  teams: string;
387
+ share: string;
379
388
  };
380
389
 
381
390
  function WorkspaceAppSettings({
@@ -401,66 +410,112 @@ function WorkspaceAppSettings({
401
410
  onRemovePending: () => void;
402
411
  labels: WorkspaceAppMetadataLabels;
403
412
  }) {
413
+ const [shareOpen, setShareOpen] = useState(false);
414
+ const [settingsOpen, setSettingsOpen] = useState(false);
415
+ const settingsTriggerRef = useRef<HTMLButtonElement>(null);
416
+
417
+ const handleShareOpenChange = (open: boolean) => {
418
+ setShareOpen(open);
419
+ if (open) return;
420
+
421
+ const restoreSettingsFocus = () => settingsTriggerRef.current?.focus();
422
+ if (
423
+ typeof window !== "undefined" &&
424
+ typeof window.requestAnimationFrame === "function"
425
+ ) {
426
+ window.requestAnimationFrame(restoreSettingsFocus);
427
+ } else {
428
+ setTimeout(restoreSettingsFocus, 0);
429
+ }
430
+ };
431
+
404
432
  return (
405
- <DropdownMenu>
406
- <Tooltip>
407
- <TooltipTrigger asChild>
408
- <DropdownMenuTrigger asChild>
409
- <Button
410
- type="button"
411
- variant="ghost"
412
- size="sm"
413
- aria-label={`Settings for ${app.name}`}
414
- className={APP_CARD_ACTION_CLASS}
433
+ <>
434
+ <DropdownMenu open={settingsOpen} onOpenChange={setSettingsOpen}>
435
+ <Tooltip>
436
+ <TooltipTrigger asChild>
437
+ <DropdownMenuTrigger asChild>
438
+ <Button
439
+ type="button"
440
+ variant="ghost"
441
+ size="sm"
442
+ ref={settingsTriggerRef}
443
+ aria-label={`Settings for ${app.name}`}
444
+ className={APP_CARD_ACTION_CLASS}
445
+ >
446
+ <IconSettings size={15} />
447
+ </Button>
448
+ </DropdownMenuTrigger>
449
+ </TooltipTrigger>
450
+ <TooltipContent>App settings</TooltipContent>
451
+ </Tooltip>
452
+ <DropdownMenuContent
453
+ align="end"
454
+ className={cn(APP_ACTION_MENU_CONTENT_CLASS, "min-w-max")}
455
+ >
456
+ <DropdownMenuItem onSelect={onEdit}>
457
+ <IconEdit size={14} aria-hidden="true" />
458
+ Edit details
459
+ </DropdownMenuItem>
460
+ {!isPending ? (
461
+ <DropdownMenuItem
462
+ onSelect={(event) =>
463
+ deferWorkspaceAppOverlayOpen(
464
+ event,
465
+ () => setSettingsOpen(false),
466
+ () => setShareOpen(true),
467
+ )
468
+ }
415
469
  >
416
- <IconSettings size={15} />
417
- </Button>
418
- </DropdownMenuTrigger>
419
- </TooltipTrigger>
420
- <TooltipContent>App settings</TooltipContent>
421
- </Tooltip>
422
- <DropdownMenuContent
423
- align="end"
424
- className={cn(APP_ACTION_MENU_CONTENT_CLASS, "min-w-max")}
425
- >
426
- <DropdownMenuItem onSelect={onEdit}>
427
- <IconEdit size={14} aria-hidden="true" />
428
- Edit details
429
- </DropdownMenuItem>
430
- {!isPending && !isArchived ? (
431
- <>
432
- <DropdownMenuItem onSelect={onKeys}>
433
- <IconKey size={14} aria-hidden="true" />
434
- Manage keys
470
+ <IconShare3 size={14} aria-hidden="true" />
471
+ {labels.share}
435
472
  </DropdownMenuItem>
436
- <DropdownMenuItem onSelect={onResources}>
437
- <IconFileText size={14} aria-hidden="true" />
438
- Agent resources
473
+ ) : null}
474
+ {!isPending && !isArchived ? (
475
+ <>
476
+ <DropdownMenuItem onSelect={onKeys}>
477
+ <IconKey size={14} aria-hidden="true" />
478
+ Manage keys
479
+ </DropdownMenuItem>
480
+ <DropdownMenuItem onSelect={onResources}>
481
+ <IconFileText size={14} aria-hidden="true" />
482
+ Agent resources
483
+ </DropdownMenuItem>
484
+ </>
485
+ ) : null}
486
+ {isPending ? (
487
+ <DropdownMenuItem
488
+ onSelect={onRemovePending}
489
+ className="text-destructive focus:text-destructive"
490
+ >
491
+ <IconTrash size={14} aria-hidden="true" />
492
+ Remove from list
439
493
  </DropdownMenuItem>
440
- </>
441
- ) : null}
442
- {isPending ? (
443
- <DropdownMenuItem
444
- onSelect={onRemovePending}
445
- className="text-destructive focus:text-destructive"
446
- >
447
- <IconTrash size={14} aria-hidden="true" />
448
- Remove from list
449
- </DropdownMenuItem>
450
- ) : isArchived ? (
451
- <DropdownMenuItem onSelect={onUnarchive}>
452
- <IconEye size={14} aria-hidden="true" />
453
- Restore to list
454
- </DropdownMenuItem>
455
- ) : (
456
- <DropdownMenuItem onSelect={onArchive}>
457
- <IconEyeOff size={14} aria-hidden="true" />
458
- Hide from list
459
- </DropdownMenuItem>
460
- )}
461
- <WorkspaceAppMetadata app={app} labels={labels} />
462
- </DropdownMenuContent>
463
- </DropdownMenu>
494
+ ) : isArchived ? (
495
+ <DropdownMenuItem onSelect={onUnarchive}>
496
+ <IconEye size={14} aria-hidden="true" />
497
+ Restore to list
498
+ </DropdownMenuItem>
499
+ ) : (
500
+ <DropdownMenuItem onSelect={onArchive}>
501
+ <IconEyeOff size={14} aria-hidden="true" />
502
+ Hide from list
503
+ </DropdownMenuItem>
504
+ )}
505
+ <WorkspaceAppMetadata app={app} labels={labels} />
506
+ </DropdownMenuContent>
507
+ </DropdownMenu>
508
+ {!isPending && shareOpen ? (
509
+ <ShareButton
510
+ resourceType="workspace-app"
511
+ resourceId={app.id}
512
+ resourceTitle={app.name}
513
+ defaultOpen
514
+ onOpenChange={handleShareOpenChange}
515
+ triggerClassName="sr-only"
516
+ />
517
+ ) : null}
518
+ </>
464
519
  );
465
520
  }
466
521