@agent-native/dispatch 0.33.1-nightly-20260902192636 → 0.33.1
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 +2 -2
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/components/workspace-app-card.js +5 -1
- package/dist/components/workspace-app-card.js.map +1 -1
- package/dist/lib/workspace-apps.d.ts.map +1 -1
- package/dist/lib/workspace-apps.js +4 -4
- package/dist/lib/workspace-apps.js.map +1 -1
- package/dist/lib/workspace-apps.test.js +29 -0
- package/dist/lib/workspace-apps.test.js.map +1 -1
- package/package.json +4 -4
- package/src/components/dispatch-control-plane.spec.tsx +1 -0
- package/src/components/layout/Layout.tsx +1 -2
- package/src/components/workspace-app-card.spec.tsx +69 -1
- package/src/components/workspace-app-card.tsx +4 -3
- package/src/components/workspace-app-host.spec.tsx +24 -0
- package/src/lib/workspace-apps.test.ts +36 -0
- package/src/lib/workspace-apps.ts +7 -4
|
@@ -136,7 +136,11 @@ function WorkspaceAppOpenActions({ app, href, openDirectly, isPinned, pinLabel,
|
|
|
136
136
|
if (!href) {
|
|
137
137
|
return (_jsx(Button, { size: "sm", variant: "outline", disabled: true, children: "Open app" }));
|
|
138
138
|
}
|
|
139
|
-
return (_jsx(AppOpenActions, { name: app.name, href: href, showNewTabOption: true, onOpen: () =>
|
|
139
|
+
return (_jsx(AppOpenActions, { name: app.name, href: href, showNewTabOption: true, onOpen: () => {
|
|
140
|
+
if (!openDirectly || navigateToWorkspaceApp(href))
|
|
141
|
+
return;
|
|
142
|
+
void navigate(appRoute);
|
|
143
|
+
}, menuItems: onTogglePinned
|
|
140
144
|
? [
|
|
141
145
|
{
|
|
142
146
|
id: "pin",
|
|
@@ -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 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 shouldOpenWorkspaceAppInTopWindow,\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\n// The settings menu's own DropdownMenuContent restores focus to its trigger\n// once its FocusScope unmounts, independent of the requestAnimationFrame\n// above. If that restore lands after the deferred overlay's DismissableLayer\n// has already mounted, the resulting focusin event reads as an outside\n// interaction and immediately dismisses the overlay we just opened. Skip the\n// default restore whenever we're mid-handoff to a sibling overlay — mirrors\n// AgentPanel's identical guard (consumeAgentPanelOverlayFocusRestore).\nfunction consumeWorkspaceAppOverlayFocusRestore(\n pendingOverlayRef: { current: boolean },\n event: { preventDefault: () => void },\n): void {\n if (!pendingOverlayRef.current) return;\n pendingOverlayRef.current = false;\n event.preventDefault();\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(\n directHref && shouldOpenWorkspaceAppInTopWindow(),\n )}\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 const pendingShareOverlayRef = useRef(false);\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 onCloseAutoFocus={(event) =>\n consumeWorkspaceAppOverlayFocusRestore(\n pendingShareOverlayRef,\n event,\n )\n }\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 () => {\n pendingShareOverlayRef.current = true;\n setSettingsOpen(false);\n },\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
|
+
{"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 shouldOpenWorkspaceAppInTopWindow,\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\n// The settings menu's own DropdownMenuContent restores focus to its trigger\n// once its FocusScope unmounts, independent of the requestAnimationFrame\n// above. If that restore lands after the deferred overlay's DismissableLayer\n// has already mounted, the resulting focusin event reads as an outside\n// interaction and immediately dismisses the overlay we just opened. Skip the\n// default restore whenever we're mid-handoff to a sibling overlay — mirrors\n// AgentPanel's identical guard (consumeAgentPanelOverlayFocusRestore).\nfunction consumeWorkspaceAppOverlayFocusRestore(\n pendingOverlayRef: { current: boolean },\n event: { preventDefault: () => void },\n): void {\n if (!pendingOverlayRef.current) return;\n pendingOverlayRef.current = false;\n event.preventDefault();\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(\n directHref && shouldOpenWorkspaceAppInTopWindow(),\n )}\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 if (!openDirectly || navigateToWorkspaceApp(href)) return;\n void 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 const pendingShareOverlayRef = useRef(false);\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 onCloseAutoFocus={(event) =>\n consumeWorkspaceAppOverlayFocusRestore(\n pendingShareOverlayRef,\n event,\n )\n }\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 () => {\n pendingShareOverlayRef.current = true;\n setSettingsOpen(false);\n },\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":"workspace-apps.d.ts","sourceRoot":"","sources":["../../src/lib/workspace-apps.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"workspace-apps.d.ts","sourceRoot":"","sources":["../../src/lib/workspace-apps.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CHAT_FIRST_DEFAULT_APP_IDS } from "@agent-native/core/client/chat-first";
|
|
2
|
-
import { isInBuilderFrame } from "@agent-native/core/client/host";
|
|
2
|
+
import { getClientSurface, isInBuilderFrame, } from "@agent-native/core/client/host";
|
|
3
3
|
import { resolveEnvironmentTargets, withBuilderUtmTrackingParams, } from "@agent-native/core/shared";
|
|
4
4
|
import { CANONICAL_WORKSPACE_SSO_APP_ORIGINS, isWorkspaceSsoAppUrl, } from "../shared/workspace-sso.js";
|
|
5
5
|
export function isDispatchWorkspaceAppId(appId) {
|
|
@@ -284,9 +284,9 @@ export function isPendingBuilderHref(app) {
|
|
|
284
284
|
export function shouldOpenWorkspaceAppInTopWindow() {
|
|
285
285
|
if (typeof window === "undefined")
|
|
286
286
|
return false;
|
|
287
|
-
//
|
|
288
|
-
//
|
|
289
|
-
return isInBuilderFrame();
|
|
287
|
+
// Standard browser iframes stay inline; Builder and native shells need the
|
|
288
|
+
// app as the top-level document so browser APIs such as WebMCP bind to it.
|
|
289
|
+
return isInBuilderFrame() || getClientSurface() !== "web";
|
|
290
290
|
}
|
|
291
291
|
export function navigateToWorkspaceApp(href) {
|
|
292
292
|
if (typeof window === "undefined")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-apps.js","sourceRoot":"","sources":["../../src/lib/workspace-apps.ts"],"names":[],"mappings":"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","sourcesContent":["import { CHAT_FIRST_DEFAULT_APP_IDS } from \"@agent-native/core/client/chat-first\";\nimport { isInBuilderFrame } from \"@agent-native/core/client/host\";\nimport {\n resolveEnvironmentTargets,\n withBuilderUtmTrackingParams,\n} from \"@agent-native/core/shared\";\n\nimport {\n CANONICAL_WORKSPACE_SSO_APP_ORIGINS,\n isWorkspaceSsoAppUrl,\n} from \"../shared/workspace-sso\";\n\nexport interface WorkspaceAppSummary {\n id: string;\n name: string;\n description?: string;\n path: string;\n url?: string | null;\n isDispatch?: boolean;\n audience?: \"internal\" | \"public\";\n visibility?: \"private\" | \"org\";\n publicPaths?: string[];\n protectedPaths?: string[];\n status?: \"ready\" | \"pending\";\n statusLabel?: string;\n builderUrl?: string | null;\n branchName?: string | null;\n createdAt?: string | null;\n createdBy?: string | null;\n owner?: string | null;\n teams?: string[];\n agentCardUrl?: string | null;\n agentCardReachable?: boolean;\n a2aEndpointUrl?: string | null;\n agentName?: string | null;\n agentSkillsCount?: number | null;\n archived?: boolean;\n workspaceSso?: boolean;\n}\n\ninterface WorkspaceAppHrefSource {\n path?: string | null;\n url?: string | null;\n workspaceSso?: boolean;\n}\n\nexport function isDispatchWorkspaceAppId(appId: string): boolean {\n return appId.trim().toLowerCase() === \"dispatch\";\n}\n\nfunction clientRuntimeEnvironment(): \"production\" | \"development\" {\n const importMetaEnv = (\n import.meta as unknown as {\n env?: Record<string, string | boolean | undefined>;\n }\n ).env;\n const processEnv = (\n globalThis as typeof globalThis & {\n process?: { env?: Record<string, string | boolean | undefined> };\n }\n ).process?.env;\n const env = { ...processEnv, ...importMetaEnv };\n if (\n env.PROD === true ||\n env.MODE === \"production\" ||\n env.NODE_ENV === \"production\"\n ) {\n return \"production\";\n }\n if (\n env.DEV === true ||\n env.MODE === \"development\" ||\n env.MODE === \"test\" ||\n env.NODE_ENV === \"development\" ||\n env.NODE_ENV === \"test\"\n ) {\n return \"development\";\n }\n return \"production\";\n}\n\nfunction clientEnvironmentLane(): \"production\" | \"beta\" {\n if (typeof window === \"undefined\") return \"production\";\n const hostname = window.location.hostname\n .trim()\n .toLowerCase()\n .replace(/\\.$/, \"\");\n const targets = resolveEnvironmentTargets(hostname);\n return targets?.betaHost === hostname ? \"beta\" : \"production\";\n}\n\n/**\n * The workspace SSO action only accepts an exact registered app identity and\n * origin. The catalog's boolean is a server-derived projection for custom\n * registrations; the URL check keeps malformed metadata out of the action.\n */\nexport function isWorkspaceSsoApp(\n app: WorkspaceAppHrefSource & { id: string },\n): boolean {\n const rawUrl = app.url?.trim();\n if (!rawUrl) return false;\n try {\n const url = new URL(rawUrl);\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return false;\n if (app.workspaceSso === true) return true;\n return isWorkspaceSsoAppUrl(\n { id: app.id, url: rawUrl },\n {\n nodeEnv: clientRuntimeEnvironment(),\n environmentLane: clientEnvironmentLane(),\n },\n );\n // coercion-ok: malformed app metadata is not eligible for workspace SSO.\n } catch {\n return false;\n }\n}\n\nfunction isCanonicalWorkspaceSsoOrigin(rawUrl: string): boolean {\n try {\n const origin = new URL(rawUrl).origin;\n return Object.values(CANONICAL_WORKSPACE_SSO_APP_ORIGINS).some(\n (canonicalOrigin) => canonicalOrigin === origin,\n );\n } catch {\n // coercion-ok: malformed app metadata is not a canonical first-party app.\n return false;\n }\n}\n\n/**\n * A mounted app URL leaves Dispatch's `/apps/:id` host route. Canonical\n * first-party origins can stay inline even at `/`, while external published\n * apps must open at their own origin regardless of their path.\n */\nexport function isPathMountedWorkspaceApp(\n app: WorkspaceAppHrefSource,\n): boolean {\n const rawUrl = app.url?.trim();\n if (rawUrl) {\n try {\n const pathname = new URL(rawUrl).pathname.replace(/\\/+$/, \"\") || \"/\";\n return pathname !== \"/\" || !isCanonicalWorkspaceSsoOrigin(rawUrl);\n // coercion-ok: invalid absolute URLs use the mounted path fallback.\n } catch {\n // Fall through to the mounted path for relative manifest values.\n }\n }\n const path = app.path?.trim().replace(/\\/+$/, \"\") || \"/\";\n return path !== \"/\";\n}\n\nexport function isDefaultWorkspaceAppHiddenId(appId: string): boolean {\n const normalized = appId.trim().toLowerCase();\n return normalized === \"chat\" || isDispatchWorkspaceAppId(normalized);\n}\n\nexport function isWorkspaceAppVisibleInDefaultLaunchers(\n app: Pick<WorkspaceAppSummary, \"id\" | \"isDispatch\">,\n): boolean {\n return !app.isDispatch && !isDefaultWorkspaceAppHiddenId(app.id);\n}\n\nfunction defaultWorkspaceAppUrl(rawUrl: string): string {\n if (typeof window === \"undefined\") return rawUrl;\n\n const hostname = window.location.hostname\n .trim()\n .toLowerCase()\n .replace(/\\.$/, \"\");\n const requestTargets = resolveEnvironmentTargets(hostname);\n if (!requestTargets || requestTargets.betaHost !== hostname) return rawUrl;\n\n try {\n const url = new URL(rawUrl);\n const appTargets = resolveEnvironmentTargets(url.hostname);\n if (!appTargets) return rawUrl;\n url.protocol = \"https:\";\n url.hostname = appTargets.betaHost;\n url.port = \"\";\n return url.toString();\n } catch {\n // coercion-ok: malformed default metadata remains an absent navigation target.\n return rawUrl;\n }\n}\n\nexport function workspaceAppRoute(appId: string): string {\n return `/apps/${encodeURIComponent(appId)}`;\n}\n\nfunction normalizeWorkspaceAppRoutePath(rawPath: string): URL | null {\n if (\n typeof rawPath !== \"string\" ||\n !rawPath.startsWith(\"/\") ||\n rawPath.startsWith(\"//\") ||\n /[\\u0000-\\u001f\\u007f]/.test(rawPath)\n ) {\n return null;\n }\n\n try {\n return new URL(rawPath, \"https://agent-native.invalid\");\n } catch {\n // coercion-ok: malformed child routes are ignored by the host.\n return null;\n }\n}\n\nfunction normalizedWorkspaceAppMountPath(rawPath: string): string {\n const pathname = rawPath.split(/[?#]/, 1)[0] ?? rawPath;\n const normalized = `/${pathname.replace(/^[/\\\\]+/, \"\")}`;\n return normalized.replace(/\\/+$/, \"\") || \"/\";\n}\n\nfunction workspaceAppMountPath(\n app: Pick<WorkspaceAppSummary, \"path\" | \"url\">,\n): string {\n const rawUrl = app.url?.trim();\n if (rawUrl) {\n try {\n const parsed = new URL(rawUrl);\n if (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") {\n return normalizedWorkspaceAppMountPath(parsed.pathname);\n }\n // coercion-ok: invalid URL falls back to app path.\n } catch {\n // Fall through to the mounted path when optional URL metadata is invalid.\n }\n }\n return normalizedWorkspaceAppMountPath(app.path?.trim() || \"/\");\n}\n\n/**\n * Convert a child app route into Dispatch's shareable workspace-app route.\n * Mounted workspace apps may report their full mount path, while hosted apps\n * normally report only the app-local path, so accept both forms here.\n */\nexport function workspaceAppRouteForChildPath(\n app: Pick<WorkspaceAppSummary, \"id\" | \"path\" | \"url\">,\n childPath: string,\n): string | null {\n const parsed = normalizeWorkspaceAppRoutePath(childPath);\n if (!parsed) return null;\n\n const mountPath = workspaceAppMountPath(app);\n const relativePathname =\n mountPath !== \"/\" &&\n (parsed.pathname === mountPath ||\n parsed.pathname.startsWith(`${mountPath}/`))\n ? parsed.pathname.slice(mountPath.length) || \"/\"\n : parsed.pathname;\n const routePath = workspaceAppRoute(app.id);\n const suffix = relativePathname === \"/\" ? \"\" : relativePathname;\n return `${routePath}${suffix}${parsed.search}${parsed.hash}`;\n}\n\nexport function workspaceAppInitialPathFromSplat(\n routeSplat: string | undefined,\n search: string,\n hash: string,\n): string | undefined {\n const pathname = routeSplat?.trim()\n ? `/${routeSplat.trim().replace(/^[/\\\\]+/, \"\")}`\n : \"/\";\n const parsed = normalizeWorkspaceAppRoutePath(`${pathname}${search}${hash}`);\n if (!parsed) return undefined;\n const path = `${parsed.pathname}${parsed.search}${parsed.hash}`;\n return path === \"/\" ? undefined : path;\n}\n\nexport function workspaceAppIdFromRoute(pathname: string): string | null {\n const match = pathname.match(/^\\/apps\\/([^/]+)(?:\\/|$)/);\n if (!match) return null;\n try {\n const appId = decodeURIComponent(match[1]).trim();\n return appId || null;\n } catch {\n // coercion-ok: malformed app routes are inactive, not app ids.\n return null;\n }\n}\n\nexport function workspaceAppHref(app: WorkspaceAppSummary): string | null {\n if (app.status === \"pending\") {\n return app.builderUrl\n ? withBuilderUtmTrackingParams(app.builderUrl, {\n campaign: \"product\",\n content: \"dispatch_branch\",\n })\n : null;\n }\n return app.path || app.url || null;\n}\n\nexport function workspaceAppEmbedTarget(\n app: Pick<WorkspaceAppSummary, \"path\" | \"url\">,\n): { path?: string; url?: string } {\n const url = app.url?.trim();\n if (url) return { url };\n\n const path = app.path.trim();\n return path.startsWith(\"/\") ? { path } : path ? { url: path } : {};\n}\n\n/**\n * Resolve an app route without an embed ticket so the target can render its\n * own error document when session setup fails.\n */\nexport function workspaceAppDirectHref(\n app: WorkspaceAppHrefSource,\n targetPath: string,\n): string | null {\n const target = targetPath.trim();\n if (!target || !target.startsWith(\"/\") || target.startsWith(\"//\")) {\n return null;\n }\n\n let targetUrl: URL;\n try {\n targetUrl = new URL(target, \"https://agent-native.invalid\");\n } catch {\n // coercion-ok: invalid relative target input has no safe href.\n return null;\n }\n const targetPathname = targetUrl.pathname || \"/\";\n\n let absoluteBase: URL | null = null;\n const rawUrl = app.url?.trim();\n if (rawUrl) {\n try {\n const parsedBase = new URL(rawUrl);\n if (parsedBase.protocol === \"http:\" || parsedBase.protocol === \"https:\") {\n absoluteBase = parsedBase;\n }\n // coercion-ok: invalid app URLs use the mounted path fallback below.\n } catch {\n absoluteBase = null;\n }\n }\n\n const mountedPath = app.path?.trim();\n const basePath = absoluteBase\n ? absoluteBase.pathname\n : mountedPath\n ? `/${mountedPath.replace(/^[/\\\\]+/, \"\").split(/[?#]/, 1)[0]}`\n : null;\n if (!basePath) return null;\n\n const normalizedBasePath = basePath.replace(/\\/+$/, \"\") || \"/\";\n const targetIsMountedPath =\n normalizedBasePath !== \"/\" &&\n (targetPathname === normalizedBasePath ||\n targetPathname.startsWith(`${normalizedBasePath}/`));\n const resolvedPath = targetIsMountedPath\n ? targetPathname\n : normalizedBasePath === \"/\"\n ? targetPathname\n : targetPathname === \"/\"\n ? normalizedBasePath\n : `${normalizedBasePath}/${targetPathname.replace(/^\\/+/, \"\")}`;\n\n if (absoluteBase) {\n absoluteBase.pathname = resolvedPath;\n absoluteBase.search = targetUrl.search;\n absoluteBase.hash = targetUrl.hash;\n return absoluteBase.toString();\n }\n\n return `${resolvedPath}${targetUrl.search}${targetUrl.hash}`;\n}\n\nexport function isPendingBuilderHref(app: WorkspaceAppSummary): boolean {\n return app.status === \"pending\" && !!app.builderUrl;\n}\n\nexport function shouldOpenWorkspaceAppInTopWindow(): boolean {\n if (typeof window === \"undefined\") return false;\n // A generic iframe is an inline host by design. Only Builder owns the\n // parent navigation contract for workspace apps.\n return isInBuilderFrame();\n}\n\nexport function navigateToWorkspaceApp(href: string): boolean {\n if (typeof window === \"undefined\") return false;\n\n try {\n const targetUrl = new URL(href, window.location.href);\n if (targetUrl.protocol !== \"http:\" && targetUrl.protocol !== \"https:\") {\n return false;\n }\n const targetWindow =\n shouldOpenWorkspaceAppInTopWindow() && window.top ? window.top : window;\n targetWindow.location.href = targetUrl.href;\n return true;\n } catch {\n // coercion-ok: a blocked top-window assignment is an expected fallback signal.\n return false;\n }\n}\n\n/**\n * Keep the chat-first rail useful before a workspace manifest is populated.\n * Mounted workspace rows still win, so custom names and routes remain the\n * source of truth once an app exists in the workspace.\n */\nexport function mergeChatFirstWorkspaceApps(\n apps: readonly WorkspaceAppSummary[] | undefined,\n): WorkspaceAppSummary[] {\n const merged = new Map<string, WorkspaceAppSummary>();\n for (const id of CHAT_FIRST_DEFAULT_APP_IDS) {\n merged.set(id, {\n id,\n name: id.charAt(0).toUpperCase() + id.slice(1),\n // The five default rows are hosted sibling apps, not routes owned by\n // Dispatch. Keep a mounted path for legacy callers, but give embed\n // session resolution the exact canonical origin.\n path: \"/\",\n url: defaultWorkspaceAppUrl(CANONICAL_WORKSPACE_SSO_APP_ORIGINS[id]),\n status: \"ready\",\n });\n }\n for (const app of apps ?? []) merged.set(app.id, app);\n\n return [...merged.values()];\n}\n"]}
|
|
1
|
+
{"version":3,"file":"workspace-apps.js","sourceRoot":"","sources":["../../src/lib/workspace-apps.ts"],"names":[],"mappings":"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","sourcesContent":["import { CHAT_FIRST_DEFAULT_APP_IDS } from \"@agent-native/core/client/chat-first\";\nimport {\n getClientSurface,\n isInBuilderFrame,\n} from \"@agent-native/core/client/host\";\nimport {\n resolveEnvironmentTargets,\n withBuilderUtmTrackingParams,\n} from \"@agent-native/core/shared\";\n\nimport {\n CANONICAL_WORKSPACE_SSO_APP_ORIGINS,\n isWorkspaceSsoAppUrl,\n} from \"../shared/workspace-sso\";\n\nexport interface WorkspaceAppSummary {\n id: string;\n name: string;\n description?: string;\n path: string;\n url?: string | null;\n isDispatch?: boolean;\n audience?: \"internal\" | \"public\";\n visibility?: \"private\" | \"org\";\n publicPaths?: string[];\n protectedPaths?: string[];\n status?: \"ready\" | \"pending\";\n statusLabel?: string;\n builderUrl?: string | null;\n branchName?: string | null;\n createdAt?: string | null;\n createdBy?: string | null;\n owner?: string | null;\n teams?: string[];\n agentCardUrl?: string | null;\n agentCardReachable?: boolean;\n a2aEndpointUrl?: string | null;\n agentName?: string | null;\n agentSkillsCount?: number | null;\n archived?: boolean;\n workspaceSso?: boolean;\n}\n\ninterface WorkspaceAppHrefSource {\n path?: string | null;\n url?: string | null;\n workspaceSso?: boolean;\n}\n\nexport function isDispatchWorkspaceAppId(appId: string): boolean {\n return appId.trim().toLowerCase() === \"dispatch\";\n}\n\nfunction clientRuntimeEnvironment(): \"production\" | \"development\" {\n const importMetaEnv = (\n import.meta as unknown as {\n env?: Record<string, string | boolean | undefined>;\n }\n ).env;\n const processEnv = (\n globalThis as typeof globalThis & {\n process?: { env?: Record<string, string | boolean | undefined> };\n }\n ).process?.env;\n const env = { ...processEnv, ...importMetaEnv };\n if (\n env.PROD === true ||\n env.MODE === \"production\" ||\n env.NODE_ENV === \"production\"\n ) {\n return \"production\";\n }\n if (\n env.DEV === true ||\n env.MODE === \"development\" ||\n env.MODE === \"test\" ||\n env.NODE_ENV === \"development\" ||\n env.NODE_ENV === \"test\"\n ) {\n return \"development\";\n }\n return \"production\";\n}\n\nfunction clientEnvironmentLane(): \"production\" | \"beta\" {\n if (typeof window === \"undefined\") return \"production\";\n const hostname = window.location.hostname\n .trim()\n .toLowerCase()\n .replace(/\\.$/, \"\");\n const targets = resolveEnvironmentTargets(hostname);\n return targets?.betaHost === hostname ? \"beta\" : \"production\";\n}\n\n/**\n * The workspace SSO action only accepts an exact registered app identity and\n * origin. The catalog's boolean is a server-derived projection for custom\n * registrations; the URL check keeps malformed metadata out of the action.\n */\nexport function isWorkspaceSsoApp(\n app: WorkspaceAppHrefSource & { id: string },\n): boolean {\n const rawUrl = app.url?.trim();\n if (!rawUrl) return false;\n try {\n const url = new URL(rawUrl);\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return false;\n if (app.workspaceSso === true) return true;\n return isWorkspaceSsoAppUrl(\n { id: app.id, url: rawUrl },\n {\n nodeEnv: clientRuntimeEnvironment(),\n environmentLane: clientEnvironmentLane(),\n },\n );\n // coercion-ok: malformed app metadata is not eligible for workspace SSO.\n } catch {\n return false;\n }\n}\n\nfunction isCanonicalWorkspaceSsoOrigin(rawUrl: string): boolean {\n try {\n const origin = new URL(rawUrl).origin;\n return Object.values(CANONICAL_WORKSPACE_SSO_APP_ORIGINS).some(\n (canonicalOrigin) => canonicalOrigin === origin,\n );\n } catch {\n // coercion-ok: malformed app metadata is not a canonical first-party app.\n return false;\n }\n}\n\n/**\n * A mounted app URL leaves Dispatch's `/apps/:id` host route. Canonical\n * first-party origins can stay inline even at `/`, while external published\n * apps must open at their own origin regardless of their path.\n */\nexport function isPathMountedWorkspaceApp(\n app: WorkspaceAppHrefSource,\n): boolean {\n const rawUrl = app.url?.trim();\n if (rawUrl) {\n try {\n const pathname = new URL(rawUrl).pathname.replace(/\\/+$/, \"\") || \"/\";\n return pathname !== \"/\" || !isCanonicalWorkspaceSsoOrigin(rawUrl);\n // coercion-ok: invalid absolute URLs use the mounted path fallback.\n } catch {\n // Fall through to the mounted path for relative manifest values.\n }\n }\n const path = app.path?.trim().replace(/\\/+$/, \"\") || \"/\";\n return path !== \"/\";\n}\n\nexport function isDefaultWorkspaceAppHiddenId(appId: string): boolean {\n const normalized = appId.trim().toLowerCase();\n return normalized === \"chat\" || isDispatchWorkspaceAppId(normalized);\n}\n\nexport function isWorkspaceAppVisibleInDefaultLaunchers(\n app: Pick<WorkspaceAppSummary, \"id\" | \"isDispatch\">,\n): boolean {\n return !app.isDispatch && !isDefaultWorkspaceAppHiddenId(app.id);\n}\n\nfunction defaultWorkspaceAppUrl(rawUrl: string): string {\n if (typeof window === \"undefined\") return rawUrl;\n\n const hostname = window.location.hostname\n .trim()\n .toLowerCase()\n .replace(/\\.$/, \"\");\n const requestTargets = resolveEnvironmentTargets(hostname);\n if (!requestTargets || requestTargets.betaHost !== hostname) return rawUrl;\n\n try {\n const url = new URL(rawUrl);\n const appTargets = resolveEnvironmentTargets(url.hostname);\n if (!appTargets) return rawUrl;\n url.protocol = \"https:\";\n url.hostname = appTargets.betaHost;\n url.port = \"\";\n return url.toString();\n } catch {\n // coercion-ok: malformed default metadata remains an absent navigation target.\n return rawUrl;\n }\n}\n\nexport function workspaceAppRoute(appId: string): string {\n return `/apps/${encodeURIComponent(appId)}`;\n}\n\nfunction normalizeWorkspaceAppRoutePath(rawPath: string): URL | null {\n if (\n typeof rawPath !== \"string\" ||\n !rawPath.startsWith(\"/\") ||\n rawPath.startsWith(\"//\") ||\n /[\\u0000-\\u001f\\u007f]/.test(rawPath)\n ) {\n return null;\n }\n\n try {\n return new URL(rawPath, \"https://agent-native.invalid\");\n } catch {\n // coercion-ok: malformed child routes are ignored by the host.\n return null;\n }\n}\n\nfunction normalizedWorkspaceAppMountPath(rawPath: string): string {\n const pathname = rawPath.split(/[?#]/, 1)[0] ?? rawPath;\n const normalized = `/${pathname.replace(/^[/\\\\]+/, \"\")}`;\n return normalized.replace(/\\/+$/, \"\") || \"/\";\n}\n\nfunction workspaceAppMountPath(\n app: Pick<WorkspaceAppSummary, \"path\" | \"url\">,\n): string {\n const rawUrl = app.url?.trim();\n if (rawUrl) {\n try {\n const parsed = new URL(rawUrl);\n if (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") {\n return normalizedWorkspaceAppMountPath(parsed.pathname);\n }\n // coercion-ok: invalid URL falls back to app path.\n } catch {\n // Fall through to the mounted path when optional URL metadata is invalid.\n }\n }\n return normalizedWorkspaceAppMountPath(app.path?.trim() || \"/\");\n}\n\n/**\n * Convert a child app route into Dispatch's shareable workspace-app route.\n * Mounted workspace apps may report their full mount path, while hosted apps\n * normally report only the app-local path, so accept both forms here.\n */\nexport function workspaceAppRouteForChildPath(\n app: Pick<WorkspaceAppSummary, \"id\" | \"path\" | \"url\">,\n childPath: string,\n): string | null {\n const parsed = normalizeWorkspaceAppRoutePath(childPath);\n if (!parsed) return null;\n\n const mountPath = workspaceAppMountPath(app);\n const relativePathname =\n mountPath !== \"/\" &&\n (parsed.pathname === mountPath ||\n parsed.pathname.startsWith(`${mountPath}/`))\n ? parsed.pathname.slice(mountPath.length) || \"/\"\n : parsed.pathname;\n const routePath = workspaceAppRoute(app.id);\n const suffix = relativePathname === \"/\" ? \"\" : relativePathname;\n return `${routePath}${suffix}${parsed.search}${parsed.hash}`;\n}\n\nexport function workspaceAppInitialPathFromSplat(\n routeSplat: string | undefined,\n search: string,\n hash: string,\n): string | undefined {\n const pathname = routeSplat?.trim()\n ? `/${routeSplat.trim().replace(/^[/\\\\]+/, \"\")}`\n : \"/\";\n const parsed = normalizeWorkspaceAppRoutePath(`${pathname}${search}${hash}`);\n if (!parsed) return undefined;\n const path = `${parsed.pathname}${parsed.search}${parsed.hash}`;\n return path === \"/\" ? undefined : path;\n}\n\nexport function workspaceAppIdFromRoute(pathname: string): string | null {\n const match = pathname.match(/^\\/apps\\/([^/]+)(?:\\/|$)/);\n if (!match) return null;\n try {\n const appId = decodeURIComponent(match[1]).trim();\n return appId || null;\n } catch {\n // coercion-ok: malformed app routes are inactive, not app ids.\n return null;\n }\n}\n\nexport function workspaceAppHref(app: WorkspaceAppSummary): string | null {\n if (app.status === \"pending\") {\n return app.builderUrl\n ? withBuilderUtmTrackingParams(app.builderUrl, {\n campaign: \"product\",\n content: \"dispatch_branch\",\n })\n : null;\n }\n return app.path || app.url || null;\n}\n\nexport function workspaceAppEmbedTarget(\n app: Pick<WorkspaceAppSummary, \"path\" | \"url\">,\n): { path?: string; url?: string } {\n const url = app.url?.trim();\n if (url) return { url };\n\n const path = app.path.trim();\n return path.startsWith(\"/\") ? { path } : path ? { url: path } : {};\n}\n\n/**\n * Resolve an app route without an embed ticket so the target can render its\n * own error document when session setup fails.\n */\nexport function workspaceAppDirectHref(\n app: WorkspaceAppHrefSource,\n targetPath: string,\n): string | null {\n const target = targetPath.trim();\n if (!target || !target.startsWith(\"/\") || target.startsWith(\"//\")) {\n return null;\n }\n\n let targetUrl: URL;\n try {\n targetUrl = new URL(target, \"https://agent-native.invalid\");\n } catch {\n // coercion-ok: invalid relative target input has no safe href.\n return null;\n }\n const targetPathname = targetUrl.pathname || \"/\";\n\n let absoluteBase: URL | null = null;\n const rawUrl = app.url?.trim();\n if (rawUrl) {\n try {\n const parsedBase = new URL(rawUrl);\n if (parsedBase.protocol === \"http:\" || parsedBase.protocol === \"https:\") {\n absoluteBase = parsedBase;\n }\n // coercion-ok: invalid app URLs use the mounted path fallback below.\n } catch {\n absoluteBase = null;\n }\n }\n\n const mountedPath = app.path?.trim();\n const basePath = absoluteBase\n ? absoluteBase.pathname\n : mountedPath\n ? `/${mountedPath.replace(/^[/\\\\]+/, \"\").split(/[?#]/, 1)[0]}`\n : null;\n if (!basePath) return null;\n\n const normalizedBasePath = basePath.replace(/\\/+$/, \"\") || \"/\";\n const targetIsMountedPath =\n normalizedBasePath !== \"/\" &&\n (targetPathname === normalizedBasePath ||\n targetPathname.startsWith(`${normalizedBasePath}/`));\n const resolvedPath = targetIsMountedPath\n ? targetPathname\n : normalizedBasePath === \"/\"\n ? targetPathname\n : targetPathname === \"/\"\n ? normalizedBasePath\n : `${normalizedBasePath}/${targetPathname.replace(/^\\/+/, \"\")}`;\n\n if (absoluteBase) {\n absoluteBase.pathname = resolvedPath;\n absoluteBase.search = targetUrl.search;\n absoluteBase.hash = targetUrl.hash;\n return absoluteBase.toString();\n }\n\n return `${resolvedPath}${targetUrl.search}${targetUrl.hash}`;\n}\n\nexport function isPendingBuilderHref(app: WorkspaceAppSummary): boolean {\n return app.status === \"pending\" && !!app.builderUrl;\n}\n\nexport function shouldOpenWorkspaceAppInTopWindow(): boolean {\n if (typeof window === \"undefined\") return false;\n // Standard browser iframes stay inline; Builder and native shells need the\n // app as the top-level document so browser APIs such as WebMCP bind to it.\n return isInBuilderFrame() || getClientSurface() !== \"web\";\n}\n\nexport function navigateToWorkspaceApp(href: string): boolean {\n if (typeof window === \"undefined\") return false;\n\n try {\n const targetUrl = new URL(href, window.location.href);\n if (targetUrl.protocol !== \"http:\" && targetUrl.protocol !== \"https:\") {\n return false;\n }\n const targetWindow =\n shouldOpenWorkspaceAppInTopWindow() && window.top ? window.top : window;\n targetWindow.location.href = targetUrl.href;\n return true;\n } catch {\n // coercion-ok: a blocked top-window assignment is an expected fallback signal.\n return false;\n }\n}\n\n/**\n * Keep the chat-first rail useful before a workspace manifest is populated.\n * Mounted workspace rows still win, so custom names and routes remain the\n * source of truth once an app exists in the workspace.\n */\nexport function mergeChatFirstWorkspaceApps(\n apps: readonly WorkspaceAppSummary[] | undefined,\n): WorkspaceAppSummary[] {\n const merged = new Map<string, WorkspaceAppSummary>();\n for (const id of CHAT_FIRST_DEFAULT_APP_IDS) {\n merged.set(id, {\n id,\n name: id.charAt(0).toUpperCase() + id.slice(1),\n // The five default rows are hosted sibling apps, not routes owned by\n // Dispatch. Keep a mounted path for legacy callers, but give embed\n // session resolution the exact canonical origin.\n path: \"/\",\n url: defaultWorkspaceAppUrl(CANONICAL_WORKSPACE_SSO_APP_ORIGINS[id]),\n status: \"ready\",\n });\n }\n for (const app of apps ?? []) merged.set(app.id, app);\n\n return [...merged.values()];\n}\n"]}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
// @vitest-environment happy-dom
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
3
3
|
import { navigateToWorkspaceApp, shouldOpenWorkspaceAppInTopWindow, workspaceAppDirectHref, workspaceAppEmbedTarget, } from "./workspace-apps.js";
|
|
4
|
+
const defaultUserAgent = navigator.userAgent;
|
|
5
|
+
function setUserAgent(userAgent) {
|
|
6
|
+
Object.defineProperty(navigator, "userAgent", {
|
|
7
|
+
configurable: true,
|
|
8
|
+
value: userAgent,
|
|
9
|
+
});
|
|
10
|
+
}
|
|
4
11
|
function setAncestorOrigin(origin) {
|
|
5
12
|
Object.defineProperty(window.location, "ancestorOrigins", {
|
|
6
13
|
configurable: true,
|
|
@@ -51,6 +58,7 @@ describe("navigateToWorkspaceApp", () => {
|
|
|
51
58
|
afterEach(() => {
|
|
52
59
|
window.history.replaceState({}, "", "/");
|
|
53
60
|
setAncestorOrigin(null);
|
|
61
|
+
setUserAgent(defaultUserAgent);
|
|
54
62
|
Object.defineProperty(window, "parent", {
|
|
55
63
|
configurable: true,
|
|
56
64
|
value: window,
|
|
@@ -67,6 +75,27 @@ describe("navigateToWorkspaceApp", () => {
|
|
|
67
75
|
});
|
|
68
76
|
expect(shouldOpenWorkspaceAppInTopWindow()).toBe(false);
|
|
69
77
|
});
|
|
78
|
+
it("keeps unrelated Electron webviews inline", () => {
|
|
79
|
+
setUserAgent("Mozilla/5.0 Electron/38.0");
|
|
80
|
+
expect(shouldOpenWorkspaceAppInTopWindow()).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
it("ignores a generic Electron preload global", () => {
|
|
83
|
+
setUserAgent("Mozilla/5.0 Electron/38.0");
|
|
84
|
+
Object.defineProperty(window, "electronAPI", {
|
|
85
|
+
configurable: true,
|
|
86
|
+
value: {},
|
|
87
|
+
});
|
|
88
|
+
try {
|
|
89
|
+
expect(shouldOpenWorkspaceAppInTopWindow()).toBe(false);
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
delete window.electronAPI;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
it("uses the top window in known native desktop hosts", () => {
|
|
96
|
+
setUserAgent("Mozilla/5.0 Electron/38.0 ChatGPT/1.0");
|
|
97
|
+
expect(shouldOpenWorkspaceAppInTopWindow()).toBe(true);
|
|
98
|
+
});
|
|
70
99
|
it("keeps the hosted Dispatch shell inline", () => {
|
|
71
100
|
Object.defineProperty(window, "parent", {
|
|
72
101
|
configurable: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-apps.test.js","sourceRoot":"","sources":["../../src/lib/workspace-apps.test.ts"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment happy-dom\nimport { afterEach, beforeEach, describe, expect, it } from \"vitest\";\n\nimport {\n navigateToWorkspaceApp,\n shouldOpenWorkspaceAppInTopWindow,\n workspaceAppDirectHref,\n workspaceAppEmbedTarget,\n} from \"./workspace-apps\";\n\nfunction setAncestorOrigin(origin: string | null) {\n Object.defineProperty(window.location, \"ancestorOrigins\", {\n configurable: true,\n value: origin\n ? {\n 0: origin,\n length: 1,\n item: (index: number) => (index === 0 ? origin : null),\n }\n : undefined,\n });\n}\n\ndescribe(\"workspaceAppEmbedTarget\", () => {\n it(\"uses the app URL as the embed root when a mount path is also present\", () => {\n expect(\n workspaceAppEmbedTarget({\n path: \"/content\",\n url: \"https://workspace.example.test/content\",\n }),\n ).toEqual({ url: \"https://workspace.example.test/content\" });\n });\n\n it(\"falls back to the mounted path when no app URL is available\", () => {\n expect(workspaceAppEmbedTarget({ path: \"/content\", url: null })).toEqual({\n path: \"/content\",\n });\n });\n});\n\ndescribe(\"workspaceAppDirectHref\", () => {\n it(\"joins an app-relative route onto an absolute app URL\", () => {\n expect(\n workspaceAppDirectHref(\n { path: \"/atlas\", url: \"https://workspace.example.test/atlas\" },\n \"/emails?status=failed#latest\",\n ),\n ).toBe(\"https://workspace.example.test/atlas/emails?status=failed#latest\");\n });\n\n it(\"does not duplicate a mount path already present in the target\", () => {\n expect(\n workspaceAppDirectHref(\n { path: \"/atlas\", url: \"https://workspace.example.test/atlas\" },\n \"/atlas\",\n ),\n ).toBe(\"https://workspace.example.test/atlas\");\n });\n\n it(\"resolves a mounted relative app path\", () => {\n expect(workspaceAppDirectHref({ path: \"/atlas\" }, \"/emails\")).toBe(\n \"/atlas/emails\",\n );\n });\n\n it(\"falls back to a safe mount path when the app URL is invalid\", () => {\n expect(\n workspaceAppDirectHref(\n { path: \"/atlas\", url: \"javascript:alert(1)\" },\n \"/\",\n ),\n ).toBe(\"/atlas\");\n });\n\n it(\"rejects an unsafe target path\", () => {\n expect(workspaceAppDirectHref({ path: \"/atlas\" }, \"//evil.example\")).toBe(\n null,\n );\n });\n});\n\ndescribe(\"navigateToWorkspaceApp\", () => {\n beforeEach(() => {\n window.history.replaceState({}, \"\", \"/\");\n setAncestorOrigin(null);\n });\n\n afterEach(() => {\n window.history.replaceState({}, \"\", \"/\");\n setAncestorOrigin(null);\n Object.defineProperty(window, \"parent\", {\n configurable: true,\n value: window,\n });\n Object.defineProperty(window, \"top\", {\n configurable: true,\n value: window,\n });\n });\n\n it(\"keeps a normal iframe inline\", () => {\n Object.defineProperty(window, \"parent\", {\n configurable: true,\n value: {},\n });\n\n expect(shouldOpenWorkspaceAppInTopWindow()).toBe(false);\n });\n\n it(\"keeps the hosted Dispatch shell inline\", () => {\n Object.defineProperty(window, \"parent\", {\n configurable: true,\n value: {},\n });\n setAncestorOrigin(\"https://agent-workspace.builder.io\");\n\n expect(shouldOpenWorkspaceAppInTopWindow()).toBe(false);\n });\n\n it(\"uses the top window when Dispatch is inside a Builder webview\", () => {\n const topWindow = { location: { href: \"\" } } as unknown as Window;\n window.history.replaceState({}, \"\", \"/?builder.preview=interact\");\n Object.defineProperty(window, \"parent\", {\n configurable: true,\n value: {},\n });\n Object.defineProperty(window, \"top\", {\n configurable: true,\n value: topWindow,\n });\n\n expect(shouldOpenWorkspaceAppInTopWindow()).toBe(true);\n navigateToWorkspaceApp(\"/mail\");\n\n expect(topWindow.location.href).toBe(\n new URL(\"/mail\", window.location.href).href,\n );\n });\n\n it(\"reports when the embedded top window rejects navigation\", () => {\n const location = {} as Location;\n Object.defineProperty(location, \"href\", {\n configurable: true,\n set: () => {\n throw new Error(\"Top navigation is blocked\");\n },\n });\n const topWindow = { location } as unknown as Window;\n window.history.replaceState({}, \"\", \"/?builder.preview=interact\");\n Object.defineProperty(window, \"parent\", {\n configurable: true,\n value: {},\n });\n Object.defineProperty(window, \"top\", {\n configurable: true,\n value: topWindow,\n });\n\n expect(navigateToWorkspaceApp(\"/mail\")).toBe(false);\n });\n\n it(\"rejects non-http navigation targets\", () => {\n const topWindow = { location: { href: \"\" } } as unknown as Window;\n Object.defineProperty(window, \"parent\", {\n configurable: true,\n value: {},\n });\n Object.defineProperty(window, \"top\", {\n configurable: true,\n value: topWindow,\n });\n\n expect(navigateToWorkspaceApp(\"javascript:alert(1)\")).toBe(false);\n expect(topWindow.location.href).toBe(\"\");\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"workspace-apps.test.js","sourceRoot":"","sources":["../../src/lib/workspace-apps.test.ts"],"names":[],"mappings":"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","sourcesContent":["// @vitest-environment happy-dom\nimport { afterEach, beforeEach, describe, expect, it } from \"vitest\";\n\nimport {\n navigateToWorkspaceApp,\n shouldOpenWorkspaceAppInTopWindow,\n workspaceAppDirectHref,\n workspaceAppEmbedTarget,\n} from \"./workspace-apps\";\n\nconst defaultUserAgent = navigator.userAgent;\n\nfunction setUserAgent(userAgent: string) {\n Object.defineProperty(navigator, \"userAgent\", {\n configurable: true,\n value: userAgent,\n });\n}\n\nfunction setAncestorOrigin(origin: string | null) {\n Object.defineProperty(window.location, \"ancestorOrigins\", {\n configurable: true,\n value: origin\n ? {\n 0: origin,\n length: 1,\n item: (index: number) => (index === 0 ? origin : null),\n }\n : undefined,\n });\n}\n\ndescribe(\"workspaceAppEmbedTarget\", () => {\n it(\"uses the app URL as the embed root when a mount path is also present\", () => {\n expect(\n workspaceAppEmbedTarget({\n path: \"/content\",\n url: \"https://workspace.example.test/content\",\n }),\n ).toEqual({ url: \"https://workspace.example.test/content\" });\n });\n\n it(\"falls back to the mounted path when no app URL is available\", () => {\n expect(workspaceAppEmbedTarget({ path: \"/content\", url: null })).toEqual({\n path: \"/content\",\n });\n });\n});\n\ndescribe(\"workspaceAppDirectHref\", () => {\n it(\"joins an app-relative route onto an absolute app URL\", () => {\n expect(\n workspaceAppDirectHref(\n { path: \"/atlas\", url: \"https://workspace.example.test/atlas\" },\n \"/emails?status=failed#latest\",\n ),\n ).toBe(\"https://workspace.example.test/atlas/emails?status=failed#latest\");\n });\n\n it(\"does not duplicate a mount path already present in the target\", () => {\n expect(\n workspaceAppDirectHref(\n { path: \"/atlas\", url: \"https://workspace.example.test/atlas\" },\n \"/atlas\",\n ),\n ).toBe(\"https://workspace.example.test/atlas\");\n });\n\n it(\"resolves a mounted relative app path\", () => {\n expect(workspaceAppDirectHref({ path: \"/atlas\" }, \"/emails\")).toBe(\n \"/atlas/emails\",\n );\n });\n\n it(\"falls back to a safe mount path when the app URL is invalid\", () => {\n expect(\n workspaceAppDirectHref(\n { path: \"/atlas\", url: \"javascript:alert(1)\" },\n \"/\",\n ),\n ).toBe(\"/atlas\");\n });\n\n it(\"rejects an unsafe target path\", () => {\n expect(workspaceAppDirectHref({ path: \"/atlas\" }, \"//evil.example\")).toBe(\n null,\n );\n });\n});\n\ndescribe(\"navigateToWorkspaceApp\", () => {\n beforeEach(() => {\n window.history.replaceState({}, \"\", \"/\");\n setAncestorOrigin(null);\n });\n\n afterEach(() => {\n window.history.replaceState({}, \"\", \"/\");\n setAncestorOrigin(null);\n setUserAgent(defaultUserAgent);\n Object.defineProperty(window, \"parent\", {\n configurable: true,\n value: window,\n });\n Object.defineProperty(window, \"top\", {\n configurable: true,\n value: window,\n });\n });\n\n it(\"keeps a normal iframe inline\", () => {\n Object.defineProperty(window, \"parent\", {\n configurable: true,\n value: {},\n });\n\n expect(shouldOpenWorkspaceAppInTopWindow()).toBe(false);\n });\n\n it(\"keeps unrelated Electron webviews inline\", () => {\n setUserAgent(\"Mozilla/5.0 Electron/38.0\");\n\n expect(shouldOpenWorkspaceAppInTopWindow()).toBe(false);\n });\n\n it(\"ignores a generic Electron preload global\", () => {\n setUserAgent(\"Mozilla/5.0 Electron/38.0\");\n Object.defineProperty(window, \"electronAPI\", {\n configurable: true,\n value: {},\n });\n\n try {\n expect(shouldOpenWorkspaceAppInTopWindow()).toBe(false);\n } finally {\n delete (window as unknown as { electronAPI?: unknown }).electronAPI;\n }\n });\n\n it(\"uses the top window in known native desktop hosts\", () => {\n setUserAgent(\"Mozilla/5.0 Electron/38.0 ChatGPT/1.0\");\n\n expect(shouldOpenWorkspaceAppInTopWindow()).toBe(true);\n });\n\n it(\"keeps the hosted Dispatch shell inline\", () => {\n Object.defineProperty(window, \"parent\", {\n configurable: true,\n value: {},\n });\n setAncestorOrigin(\"https://agent-workspace.builder.io\");\n\n expect(shouldOpenWorkspaceAppInTopWindow()).toBe(false);\n });\n\n it(\"uses the top window when Dispatch is inside a Builder webview\", () => {\n const topWindow = { location: { href: \"\" } } as unknown as Window;\n window.history.replaceState({}, \"\", \"/?builder.preview=interact\");\n Object.defineProperty(window, \"parent\", {\n configurable: true,\n value: {},\n });\n Object.defineProperty(window, \"top\", {\n configurable: true,\n value: topWindow,\n });\n\n expect(shouldOpenWorkspaceAppInTopWindow()).toBe(true);\n navigateToWorkspaceApp(\"/mail\");\n\n expect(topWindow.location.href).toBe(\n new URL(\"/mail\", window.location.href).href,\n );\n });\n\n it(\"reports when the embedded top window rejects navigation\", () => {\n const location = {} as Location;\n Object.defineProperty(location, \"href\", {\n configurable: true,\n set: () => {\n throw new Error(\"Top navigation is blocked\");\n },\n });\n const topWindow = { location } as unknown as Window;\n window.history.replaceState({}, \"\", \"/?builder.preview=interact\");\n Object.defineProperty(window, \"parent\", {\n configurable: true,\n value: {},\n });\n Object.defineProperty(window, \"top\", {\n configurable: true,\n value: topWindow,\n });\n\n expect(navigateToWorkspaceApp(\"/mail\")).toBe(false);\n });\n\n it(\"rejects non-http navigation targets\", () => {\n const topWindow = { location: { href: \"\" } } as unknown as Window;\n Object.defineProperty(window, \"parent\", {\n configurable: true,\n value: {},\n });\n Object.defineProperty(window, \"top\", {\n configurable: true,\n value: topWindow,\n });\n\n expect(navigateToWorkspaceApp(\"javascript:alert(1)\")).toBe(false);\n expect(topWindow.location.href).toBe(\"\");\n });\n});\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/dispatch",
|
|
3
|
-
"version": "0.33.1
|
|
3
|
+
"version": "0.33.1",
|
|
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": {
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"tailwind-merge": "^3.5.0",
|
|
88
88
|
"vaul": "^1.1.2",
|
|
89
89
|
"zod": "^4.3.6",
|
|
90
|
-
"@agent-native/toolkit": "0.19.2
|
|
90
|
+
"@agent-native/toolkit": "0.19.2"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
93
|
"@react-router/dev": "^8.1.0",
|
|
@@ -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.176.4
|
|
104
|
+
"@agent-native/core": "0.176.4"
|
|
105
105
|
},
|
|
106
106
|
"peerDependencies": {
|
|
107
|
-
"@agent-native/core": "0.
|
|
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"
|
|
@@ -1516,8 +1516,7 @@ export function Layout({
|
|
|
1516
1516
|
? workspaceAppDirectHref(registration, "/")
|
|
1517
1517
|
: null;
|
|
1518
1518
|
if (directHref && shouldOpenWorkspaceAppInTopWindow()) {
|
|
1519
|
-
navigateToWorkspaceApp(directHref);
|
|
1520
|
-
return;
|
|
1519
|
+
if (navigateToWorkspaceApp(directHref)) return;
|
|
1521
1520
|
}
|
|
1522
1521
|
void navigate(dispatchNavLinkTarget(workspaceAppRoute(app.id)));
|
|
1523
1522
|
},
|