@agent-native/dispatch 0.27.1 → 0.27.3
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/actions/provider-api-register.d.ts +16 -16
- package/dist/components/workspace-app-host.d.ts.map +1 -1
- package/dist/components/workspace-app-host.js +6 -1
- package/dist/components/workspace-app-host.js.map +1 -1
- package/package.json +3 -3
- package/src/components/workspace-app-host.spec.tsx +68 -3
- package/src/components/workspace-app-host.tsx +5 -1
|
@@ -47,9 +47,7 @@ declare const _default: import("node_modules/@agent-native/core/dist").ActionDef
|
|
|
47
47
|
notes?: string | undefined;
|
|
48
48
|
scope?: "org" | "user" | undefined;
|
|
49
49
|
}, {
|
|
50
|
-
|
|
51
|
-
id?: undefined;
|
|
52
|
-
provider?: undefined;
|
|
50
|
+
found?: undefined;
|
|
53
51
|
deleted?: undefined;
|
|
54
52
|
providers: {
|
|
55
53
|
id: string;
|
|
@@ -61,45 +59,47 @@ declare const _default: import("node_modules/@agent-native/core/dist").ActionDef
|
|
|
61
59
|
updatedAt: number;
|
|
62
60
|
}[];
|
|
63
61
|
count: number;
|
|
64
|
-
|
|
62
|
+
provider?: undefined;
|
|
65
63
|
registered?: undefined;
|
|
64
|
+
id?: undefined;
|
|
66
65
|
label?: undefined;
|
|
67
|
-
} | {
|
|
68
66
|
message?: undefined;
|
|
69
|
-
|
|
70
|
-
id?: undefined;
|
|
67
|
+
} | {
|
|
71
68
|
deleted?: undefined;
|
|
72
69
|
providers?: undefined;
|
|
70
|
+
count?: undefined;
|
|
73
71
|
found: boolean;
|
|
74
72
|
provider: import("node_modules/@agent-native/core/dist/provider-api").CustomProviderConfig;
|
|
75
73
|
registered?: undefined;
|
|
74
|
+
id?: undefined;
|
|
76
75
|
label?: undefined;
|
|
77
|
-
} | {
|
|
78
76
|
message?: undefined;
|
|
79
|
-
|
|
80
|
-
provider?: undefined;
|
|
77
|
+
} | {
|
|
81
78
|
deleted?: undefined;
|
|
82
79
|
providers?: undefined;
|
|
80
|
+
count?: undefined;
|
|
81
|
+
provider?: undefined;
|
|
83
82
|
found: boolean;
|
|
84
83
|
id: string;
|
|
85
84
|
registered?: undefined;
|
|
86
85
|
label?: undefined;
|
|
87
|
-
} | {
|
|
88
86
|
message?: undefined;
|
|
87
|
+
} | {
|
|
88
|
+
found?: undefined;
|
|
89
|
+
providers?: undefined;
|
|
89
90
|
count?: undefined;
|
|
90
91
|
provider?: undefined;
|
|
91
|
-
providers?: undefined;
|
|
92
|
-
found?: undefined;
|
|
93
92
|
deleted: boolean;
|
|
94
93
|
id: string;
|
|
95
94
|
registered?: undefined;
|
|
96
95
|
label?: undefined;
|
|
96
|
+
message?: undefined;
|
|
97
97
|
} | {
|
|
98
|
-
|
|
99
|
-
provider?: undefined;
|
|
98
|
+
found?: undefined;
|
|
100
99
|
deleted?: undefined;
|
|
101
100
|
providers?: undefined;
|
|
102
|
-
|
|
101
|
+
count?: undefined;
|
|
102
|
+
provider?: undefined;
|
|
103
103
|
registered: boolean;
|
|
104
104
|
id: string;
|
|
105
105
|
label: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-app-host.d.ts","sourceRoot":"","sources":["../../src/components/workspace-app-host.tsx"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,sCAAsC,CAAC;AAoC9C,UAAU,iBAAiB;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,CAAC;CACnB;AA8CD,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,iBAAiB,CAEnB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,UAAU,sBAAsB;IAC9B,GAAG,EAAE,oBAAoB,CAAC;IAC1B,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,GAAG,EACH,SAAS,EACT,WAAmB,EACnB,IAA2B,GAC5B,EAAE,sBAAsB,
|
|
1
|
+
{"version":3,"file":"workspace-app-host.d.ts","sourceRoot":"","sources":["../../src/components/workspace-app-host.tsx"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,sCAAsC,CAAC;AAoC9C,UAAU,iBAAiB;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,CAAC;CACnB;AA8CD,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,iBAAiB,CAEnB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,UAAU,sBAAsB;IAC9B,GAAG,EAAE,oBAAoB,CAAC;IAC1B,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,GAAG,EACH,SAAS,EACT,WAAmB,EACnB,IAA2B,GAC5B,EAAE,sBAAsB,mDA2NxB;AAED,wBAAgB,gBAAgB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,mDA2J7D;AAID,wBAAgB,qBAAqB,CAAC,EACpC,WAAW,GACZ,EAAE;IACD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,mDAwCA"}
|
|
@@ -56,6 +56,7 @@ export function WorkspaceAppFrame({ app, embedPath, chatSidebar = false, copy =
|
|
|
56
56
|
: "light";
|
|
57
57
|
const [embedUrl, setEmbedUrl] = useState(null);
|
|
58
58
|
const [embedError, setEmbedError] = useState(null);
|
|
59
|
+
const [isDirectFallback, setIsDirectFallback] = useState(false);
|
|
59
60
|
const [embedAttempt, setEmbedAttempt] = useState(0);
|
|
60
61
|
const [authState, setAuthState] = useState("unknown");
|
|
61
62
|
const embedFrameRef = useRef(null);
|
|
@@ -64,6 +65,8 @@ export function WorkspaceAppFrame({ app, embedPath, chatSidebar = false, copy =
|
|
|
64
65
|
}, [theme]);
|
|
65
66
|
const handleFrameLoad = useCallback(() => {
|
|
66
67
|
postThemeToFrame();
|
|
68
|
+
if (isDirectFallback)
|
|
69
|
+
setEmbedError(null);
|
|
67
70
|
const frame = embedFrameRef.current;
|
|
68
71
|
let frameUrl = embedUrl;
|
|
69
72
|
try {
|
|
@@ -76,7 +79,7 @@ export function WorkspaceAppFrame({ app, embedPath, chatSidebar = false, copy =
|
|
|
76
79
|
const nextAuthState = resolveWorkspaceAppAuthState(frameUrl);
|
|
77
80
|
if (nextAuthState !== "unknown")
|
|
78
81
|
setAuthState(nextAuthState);
|
|
79
|
-
}, [embedUrl, postThemeToFrame]);
|
|
82
|
+
}, [embedUrl, isDirectFallback, postThemeToFrame]);
|
|
80
83
|
const workspaceSsoEnabled = useFeatureFlag(DISPATCH_WORKSPACE_SSO_FLAG.key);
|
|
81
84
|
const createEmbedSession = useActionMutation("create_embed_session", {
|
|
82
85
|
skipActionQueryInvalidation: true,
|
|
@@ -108,6 +111,7 @@ export function WorkspaceAppFrame({ app, embedPath, chatSidebar = false, copy =
|
|
|
108
111
|
let cancelled = false;
|
|
109
112
|
setEmbedUrl(null);
|
|
110
113
|
setEmbedError(null);
|
|
114
|
+
setIsDirectFallback(false);
|
|
111
115
|
setAuthState("unknown");
|
|
112
116
|
const createSession = workspaceSsoEnabled
|
|
113
117
|
? createWorkspaceSsoEmbedSession
|
|
@@ -121,6 +125,7 @@ export function WorkspaceAppFrame({ app, embedPath, chatSidebar = false, copy =
|
|
|
121
125
|
.catch((cause) => {
|
|
122
126
|
if (cancelled)
|
|
123
127
|
return;
|
|
128
|
+
setIsDirectFallback(true);
|
|
124
129
|
setEmbedUrl(workspaceAppDirectHref({ path: app.path ?? "", url: app.url }, embedPath ?? "/"));
|
|
125
130
|
setEmbedError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
126
131
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-app-host.js","sourceRoot":"","sources":["../../src/components/workspace-app-host.tsx"],"names":[],"mappings":"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","sourcesContent":["import { AgentSidebar } from \"@agent-native/core/client/agent-chat\";\nimport {\n ChatFirstAppPane,\n defaultChatFirstCopy,\n type ChatFirstCopy,\n} from \"@agent-native/core/client/chat-first\";\nimport { useFeatureFlag } from \"@agent-native/core/client/feature-flags\";\nimport {\n useActionMutation,\n useActionQuery,\n} from \"@agent-native/core/client/hooks\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport { withBuilderUtmTrackingParams } from \"@agent-native/core/shared/builder-link-tracking\";\nimport {\n IconArrowLeft,\n IconArrowUpRight,\n IconClockHour4,\n IconLock,\n} from \"@tabler/icons-react\";\nimport { useTheme } from \"next-themes\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Link } from \"react-router\";\n\nimport { isEmbedSessionExpiredMessage } from \"../lib/embed-session-recovery\";\nimport {\n mergeChatFirstWorkspaceApps,\n workspaceAppDirectHref,\n workspaceAppEmbedTarget,\n workspaceAppHref,\n type WorkspaceAppSummary,\n} from \"../lib/workspace-apps\";\nimport { DISPATCH_WORKSPACE_SSO_FLAG } from \"../shared/feature-flags\";\nimport { ActionQueryError } from \"./action-query-error\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { Skeleton } from \"./ui/skeleton\";\n\ninterface EmbedSessionResult {\n startUrl: string;\n}\n\ninterface EmbedSessionInput {\n app?: string;\n path?: string;\n url?: string;\n chrome: \"minimal\";\n}\n\ninterface GrantedWorkspaceAppSummary {\n id: string;\n name: string;\n url?: string | null;\n}\n\ninterface GrantedWorkspaceAppsResult {\n apps: GrantedWorkspaceAppSummary[];\n}\n\ntype WorkspaceAppTheme = \"light\" | \"dark\";\ntype WorkspaceAppAuthState = \"unknown\" | \"authenticated\" | \"unauthenticated\";\n\nfunction resolveWorkspaceAppAuthState(\n rawUrl: string | null,\n): WorkspaceAppAuthState {\n if (!rawUrl) return \"unknown\";\n try {\n const lastSegment = new URL(rawUrl, window.location.origin).pathname\n .split(\"/\")\n .filter(Boolean)\n .at(-1)\n ?.toLowerCase();\n if (\n lastSegment === \"sign-in\" ||\n lastSegment === \"login\" ||\n lastSegment === \"signup\"\n ) {\n return \"unauthenticated\";\n }\n return \"authenticated\";\n } catch {\n return \"unknown\";\n }\n}\n\nfunction buildWorkspaceAppThemeUpdate(theme: WorkspaceAppTheme) {\n return {\n type: \"agent-native-theme-update\" as const,\n theme,\n isDark: theme === \"dark\",\n };\n}\n\nexport function buildChatFirstEmbedSessionInput(\n appId: string,\n path: string,\n): EmbedSessionInput {\n return { app: appId, path, chrome: \"minimal\" };\n}\n\nexport interface WorkspaceAppFrameApp {\n id: string;\n name: string;\n path?: string | null;\n url?: string | null;\n}\n\ninterface WorkspaceAppFrameProps {\n app: WorkspaceAppFrameApp;\n /** Chat-first app tabs use their own route while standalone hosts use app metadata. */\n embedPath?: string;\n /** Chat-first app surfaces own the parent chat rail around the iframe. */\n chatSidebar?: boolean;\n copy?: ChatFirstCopy;\n}\n\nexport function WorkspaceAppFrame({\n app,\n embedPath,\n chatSidebar = false,\n copy = defaultChatFirstCopy,\n}: WorkspaceAppFrameProps) {\n const { resolvedTheme } = useTheme();\n const theme: WorkspaceAppTheme =\n resolvedTheme === \"dark\" || resolvedTheme === \"light\"\n ? resolvedTheme\n : typeof document !== \"undefined\" &&\n document.documentElement.classList.contains(\"dark\")\n ? \"dark\"\n : \"light\";\n const [embedUrl, setEmbedUrl] = useState<string | null>(null);\n const [embedError, setEmbedError] = useState<Error | null>(null);\n const [embedAttempt, setEmbedAttempt] = useState(0);\n const [authState, setAuthState] = useState<WorkspaceAppAuthState>(\"unknown\");\n const embedFrameRef = useRef<HTMLIFrameElement>(null);\n const postThemeToFrame = useCallback(() => {\n embedFrameRef.current?.contentWindow?.postMessage(\n buildWorkspaceAppThemeUpdate(theme),\n \"*\",\n );\n }, [theme]);\n const handleFrameLoad = useCallback(() => {\n postThemeToFrame();\n const frame = embedFrameRef.current;\n let frameUrl = embedUrl;\n try {\n frameUrl = frame?.contentWindow?.location.href ?? frameUrl;\n // coercion-ok: Cross-origin frames cannot expose location; their auth state arrives by message.\n } catch {\n // Cross-origin app frames report their auth state through postMessage.\n }\n const nextAuthState = resolveWorkspaceAppAuthState(frameUrl);\n if (nextAuthState !== \"unknown\") setAuthState(nextAuthState);\n }, [embedUrl, postThemeToFrame]);\n const workspaceSsoEnabled = useFeatureFlag(DISPATCH_WORKSPACE_SSO_FLAG.key);\n const createEmbedSession = useActionMutation<\n EmbedSessionResult,\n EmbedSessionInput\n >(\"create_embed_session\", {\n skipActionQueryInvalidation: true,\n });\n const createWorkspaceSsoEmbedSession = useActionMutation<\n EmbedSessionResult,\n EmbedSessionInput\n >(\"create-workspace-app-embed-session\", {\n skipActionQueryInvalidation: true,\n });\n const appHref = workspaceAppHref({\n id: app.id,\n name: app.name,\n path: app.path ?? \"\",\n url: app.url,\n });\n const embedInput = useMemo<EmbedSessionInput | null>(() => {\n if (embedPath !== undefined) {\n return buildChatFirstEmbedSessionInput(app.id, embedPath);\n }\n if (!appHref) return null;\n return {\n app: app.id,\n ...workspaceAppEmbedTarget({ path: app.path ?? \"\", url: app.url }),\n chrome: \"minimal\",\n };\n }, [app.id, app.path, app.url, appHref, embedPath]);\n\n useEffect(() => {\n if (!embedInput) return;\n let cancelled = false;\n setEmbedUrl(null);\n setEmbedError(null);\n setAuthState(\"unknown\");\n const createSession = workspaceSsoEnabled\n ? createWorkspaceSsoEmbedSession\n : createEmbedSession;\n void createSession\n .mutateAsync(embedInput)\n .then((result) => {\n if (!cancelled) setEmbedUrl(result.startUrl);\n })\n .catch((cause: unknown) => {\n if (cancelled) return;\n setEmbedUrl(\n workspaceAppDirectHref(\n { path: app.path ?? \"\", url: app.url },\n embedPath ?? \"/\",\n ),\n );\n setEmbedError(\n cause instanceof Error ? cause : new Error(String(cause)),\n );\n });\n return () => {\n cancelled = true;\n };\n }, [\n app.id,\n app.path,\n app.url,\n createEmbedSession.mutateAsync,\n createWorkspaceSsoEmbedSession.mutateAsync,\n embedInput,\n embedPath,\n embedAttempt,\n workspaceSsoEnabled,\n ]);\n\n useEffect(() => {\n const handleEmbedSessionExpired = (event: MessageEvent) => {\n if (\n !isEmbedSessionExpiredMessage(event, embedFrameRef.current, embedUrl)\n ) {\n return;\n }\n setEmbedAttempt((attempt) => attempt + 1);\n };\n\n window.addEventListener(\"message\", handleEmbedSessionExpired);\n return () =>\n window.removeEventListener(\"message\", handleEmbedSessionExpired);\n }, [embedUrl]);\n\n useEffect(() => {\n const handleAuthState = (event: MessageEvent) => {\n const frame = embedFrameRef.current;\n if (!frame || event.source !== frame.contentWindow) return;\n if (event.data?.type !== \"agentNative.authState\") return;\n const status = event.data.data?.status;\n if (status === \"authenticated\" || status === \"unauthenticated\") {\n setAuthState(status);\n }\n };\n\n window.addEventListener(\"message\", handleAuthState);\n return () => window.removeEventListener(\"message\", handleAuthState);\n }, []);\n\n useEffect(() => {\n postThemeToFrame();\n }, [embedUrl, postThemeToFrame]);\n\n const appPane = (\n <ChatFirstAppPane\n app={app}\n status={\n embedUrl\n ? \"ready\"\n : embedError\n ? \"error\"\n : embedInput\n ? \"loading\"\n : \"unresolved\"\n }\n embedUrl={embedUrl}\n errorMessage={embedError?.message}\n onRetry={\n embedInput ? () => setEmbedAttempt((attempt) => attempt + 1) : undefined\n }\n renderEmbed={({ url, title }) => (\n <iframe\n key={url + \":\" + embedAttempt}\n data-dispatch-workspace-app-frame\n src={url}\n title={title ?? app.name}\n ref={embedFrameRef}\n onLoad={handleFrameLoad}\n referrerPolicy=\"no-referrer\"\n allow=\"clipboard-read; clipboard-write\"\n className=\"h-full w-full border-0 bg-background\"\n />\n )}\n copy={copy}\n />\n );\n\n if (!chatSidebar) return appPane;\n\n return (\n <AgentSidebar\n position=\"left\"\n defaultOpen\n openStorageKey=\"dispatch-app-chat\"\n storageKey={`dispatch-app-chat:${app.id}`}\n scope={{\n type: \"workspace-app\",\n id: app.id,\n label: app.name,\n contextKey: `workspace-app:${app.id}`,\n }}\n agentChatSurface=\"app\"\n showTabBar\n suppressInlineOpenApp\n dynamicSuggestions={false}\n suggestions={[]}\n emptyStateText={`Ask about ${app.name}`}\n composerSlot={\n authState === \"unauthenticated\" ? (\n <div className=\"flex shrink-0 items-center px-3 pb-1\">\n <button\n type=\"button\"\n data-dispatch-app-sign-in\n aria-label={`Sign in to ${app.name} on the right`}\n title={`Sign in to ${app.name} on the right`}\n onClick={() => embedFrameRef.current?.focus()}\n className=\"inline-flex h-6 shrink-0 items-center gap-1 rounded-full border border-border/70 bg-background/60 px-2 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n >\n <IconLock size={12} stroke={1.8} />\n <span>Sign in on the right</span>\n <IconArrowUpRight size={12} stroke={1.8} />\n </button>\n </div>\n ) : null\n }\n >\n {appPane}\n </AgentSidebar>\n );\n}\n\nexport function WorkspaceAppHost({ appId }: { appId?: string }) {\n const t = useT();\n const workspaceAppsQuery = useActionQuery<WorkspaceAppSummary[]>(\n \"list-workspace-apps\",\n { includeAgentCards: false },\n );\n const grantedAppsQuery = useActionQuery<GrantedWorkspaceAppsResult>(\n \"list_apps\",\n {},\n );\n const apps = useMemo(() => {\n const merged = new Map<string, WorkspaceAppSummary>();\n\n for (const app of mergeChatFirstWorkspaceApps(workspaceAppsQuery.data)) {\n merged.set(app.id.trim().toLowerCase(), app);\n }\n for (const app of grantedAppsQuery.data?.apps ?? []) {\n const id = app.id.trim();\n if (!id || merged.has(id.toLowerCase())) continue;\n merged.set(id.toLowerCase(), {\n id,\n name: app.name.trim() || id,\n path: \"\",\n url: app.url?.trim() || null,\n status: \"ready\",\n });\n }\n\n return [...merged.values()];\n }, [grantedAppsQuery.data?.apps, workspaceAppsQuery.data]);\n const app = useMemo(\n () =>\n apps.find(\n (item) => item.id.trim().toLowerCase() === appId?.trim().toLowerCase(),\n ) ?? null,\n [appId, apps],\n );\n const isLoading = workspaceAppsQuery.isLoading || grantedAppsQuery.isLoading;\n const queryError = workspaceAppsQuery.isError\n ? workspaceAppsQuery.error\n : grantedAppsQuery.isError\n ? grantedAppsQuery.error\n : null;\n\n if (queryError && !app) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl\">\n <ActionQueryError\n error={queryError}\n onRetry={() => {\n void workspaceAppsQuery.refetch();\n void grantedAppsQuery.refetch();\n }}\n />\n </div>\n </div>\n );\n }\n\n if (isLoading && !app) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl space-y-3 rounded-xl border bg-card p-6\">\n <Skeleton className=\"h-5 w-48\" />\n <Skeleton className=\"h-4 w-full\" />\n <Skeleton className=\"h-4 w-2/3\" />\n </div>\n </div>\n );\n }\n\n if (!app) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl rounded-xl border bg-card p-6\">\n <Button asChild size=\"sm\" variant=\"ghost\" className=\"-ml-2 mb-4\">\n <Link to=\"/apps\">\n <IconArrowLeft size={15} className=\"mr-1.5\" />\n {t(\"dispatch.nav.apps\")}\n </Link>\n </Button>\n <div className=\"space-y-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(\"dispatch.pages.appNotFound\")}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"dispatch.pages.pageNotFoundDescription\")}\n </p>\n </div>\n </div>\n </div>\n );\n }\n\n if (app.status === \"pending\") {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl rounded-xl border bg-card p-6\">\n <Button asChild size=\"sm\" variant=\"ghost\" className=\"-ml-2 mb-4\">\n <Link to=\"/apps\">\n <IconArrowLeft size={15} className=\"mr-1.5\" />\n {t(\"dispatch.nav.apps\")}\n </Link>\n </Button>\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {app.name}\n </h2>\n <Badge\n variant=\"outline\"\n className=\"gap-1 border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300\"\n >\n <IconClockHour4 size={12} />\n {t(\"dispatch.pages.building\")}\n </Badge>\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"dispatch.pages.appBuildingPrefix\")}{\" \"}\n <span className=\"font-mono text-foreground\">{app.path}</span>{\" \"}\n {t(\"dispatch.pages.appBuildingSuffix\")}\n </p>\n {app.builderUrl ? (\n <Button asChild>\n <a\n href={withBuilderUtmTrackingParams(app.builderUrl, {\n campaign: \"product\",\n content: \"dispatch_branch\",\n })}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n {t(\"dispatch.pages.openBuilderBranch\", {\n defaultValue: \"Open in Builder\",\n })}\n </a>\n </Button>\n ) : null}\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-dispatch-workspace-app-host\n className=\"flex h-full min-h-0 flex-col bg-background\"\n >\n <div className=\"min-h-0 flex-1 bg-muted/20\">\n <WorkspaceAppFrame app={app} />\n </div>\n </div>\n );\n}\n\nconst MAX_KEEP_ALIVE_APPS = 3;\n\nexport function WorkspaceAppKeepAlive({\n activeAppId,\n}: {\n activeAppId: string | null;\n}) {\n const [visitedAppIds, setVisitedAppIds] = useState<string[]>(() =>\n activeAppId ? [activeAppId] : [],\n );\n\n useEffect(() => {\n if (!activeAppId) return;\n setVisitedAppIds((current) =>\n [activeAppId, ...current.filter((appId) => appId !== activeAppId)].slice(\n 0,\n MAX_KEEP_ALIVE_APPS,\n ),\n );\n }, [activeAppId]);\n\n const renderedAppIds =\n activeAppId && !visitedAppIds.includes(activeAppId)\n ? [activeAppId, ...visitedAppIds]\n : visitedAppIds;\n\n return (\n <div\n data-dispatch-workspace-app-cache\n className={activeAppId ? \"absolute inset-0 overflow-hidden\" : \"hidden\"}\n >\n {renderedAppIds.map((appId) => {\n const active = appId === activeAppId;\n return (\n <div\n key={appId}\n data-dispatch-workspace-app-cache-entry={appId}\n aria-hidden={!active}\n className={active ? \"h-full min-h-0\" : \"hidden\"}\n >\n <WorkspaceAppHost appId={appId} />\n </div>\n );\n })}\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"workspace-app-host.js","sourceRoot":"","sources":["../../src/components/workspace-app-host.tsx"],"names":[],"mappings":"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","sourcesContent":["import { AgentSidebar } from \"@agent-native/core/client/agent-chat\";\nimport {\n ChatFirstAppPane,\n defaultChatFirstCopy,\n type ChatFirstCopy,\n} from \"@agent-native/core/client/chat-first\";\nimport { useFeatureFlag } from \"@agent-native/core/client/feature-flags\";\nimport {\n useActionMutation,\n useActionQuery,\n} from \"@agent-native/core/client/hooks\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport { withBuilderUtmTrackingParams } from \"@agent-native/core/shared/builder-link-tracking\";\nimport {\n IconArrowLeft,\n IconArrowUpRight,\n IconClockHour4,\n IconLock,\n} from \"@tabler/icons-react\";\nimport { useTheme } from \"next-themes\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Link } from \"react-router\";\n\nimport { isEmbedSessionExpiredMessage } from \"../lib/embed-session-recovery\";\nimport {\n mergeChatFirstWorkspaceApps,\n workspaceAppDirectHref,\n workspaceAppEmbedTarget,\n workspaceAppHref,\n type WorkspaceAppSummary,\n} from \"../lib/workspace-apps\";\nimport { DISPATCH_WORKSPACE_SSO_FLAG } from \"../shared/feature-flags\";\nimport { ActionQueryError } from \"./action-query-error\";\nimport { Badge } from \"./ui/badge\";\nimport { Button } from \"./ui/button\";\nimport { Skeleton } from \"./ui/skeleton\";\n\ninterface EmbedSessionResult {\n startUrl: string;\n}\n\ninterface EmbedSessionInput {\n app?: string;\n path?: string;\n url?: string;\n chrome: \"minimal\";\n}\n\ninterface GrantedWorkspaceAppSummary {\n id: string;\n name: string;\n url?: string | null;\n}\n\ninterface GrantedWorkspaceAppsResult {\n apps: GrantedWorkspaceAppSummary[];\n}\n\ntype WorkspaceAppTheme = \"light\" | \"dark\";\ntype WorkspaceAppAuthState = \"unknown\" | \"authenticated\" | \"unauthenticated\";\n\nfunction resolveWorkspaceAppAuthState(\n rawUrl: string | null,\n): WorkspaceAppAuthState {\n if (!rawUrl) return \"unknown\";\n try {\n const lastSegment = new URL(rawUrl, window.location.origin).pathname\n .split(\"/\")\n .filter(Boolean)\n .at(-1)\n ?.toLowerCase();\n if (\n lastSegment === \"sign-in\" ||\n lastSegment === \"login\" ||\n lastSegment === \"signup\"\n ) {\n return \"unauthenticated\";\n }\n return \"authenticated\";\n } catch {\n return \"unknown\";\n }\n}\n\nfunction buildWorkspaceAppThemeUpdate(theme: WorkspaceAppTheme) {\n return {\n type: \"agent-native-theme-update\" as const,\n theme,\n isDark: theme === \"dark\",\n };\n}\n\nexport function buildChatFirstEmbedSessionInput(\n appId: string,\n path: string,\n): EmbedSessionInput {\n return { app: appId, path, chrome: \"minimal\" };\n}\n\nexport interface WorkspaceAppFrameApp {\n id: string;\n name: string;\n path?: string | null;\n url?: string | null;\n}\n\ninterface WorkspaceAppFrameProps {\n app: WorkspaceAppFrameApp;\n /** Chat-first app tabs use their own route while standalone hosts use app metadata. */\n embedPath?: string;\n /** Chat-first app surfaces own the parent chat rail around the iframe. */\n chatSidebar?: boolean;\n copy?: ChatFirstCopy;\n}\n\nexport function WorkspaceAppFrame({\n app,\n embedPath,\n chatSidebar = false,\n copy = defaultChatFirstCopy,\n}: WorkspaceAppFrameProps) {\n const { resolvedTheme } = useTheme();\n const theme: WorkspaceAppTheme =\n resolvedTheme === \"dark\" || resolvedTheme === \"light\"\n ? resolvedTheme\n : typeof document !== \"undefined\" &&\n document.documentElement.classList.contains(\"dark\")\n ? \"dark\"\n : \"light\";\n const [embedUrl, setEmbedUrl] = useState<string | null>(null);\n const [embedError, setEmbedError] = useState<Error | null>(null);\n const [isDirectFallback, setIsDirectFallback] = useState(false);\n const [embedAttempt, setEmbedAttempt] = useState(0);\n const [authState, setAuthState] = useState<WorkspaceAppAuthState>(\"unknown\");\n const embedFrameRef = useRef<HTMLIFrameElement>(null);\n const postThemeToFrame = useCallback(() => {\n embedFrameRef.current?.contentWindow?.postMessage(\n buildWorkspaceAppThemeUpdate(theme),\n \"*\",\n );\n }, [theme]);\n const handleFrameLoad = useCallback(() => {\n postThemeToFrame();\n if (isDirectFallback) setEmbedError(null);\n const frame = embedFrameRef.current;\n let frameUrl = embedUrl;\n try {\n frameUrl = frame?.contentWindow?.location.href ?? frameUrl;\n // coercion-ok: Cross-origin frames cannot expose location; their auth state arrives by message.\n } catch {\n // Cross-origin app frames report their auth state through postMessage.\n }\n const nextAuthState = resolveWorkspaceAppAuthState(frameUrl);\n if (nextAuthState !== \"unknown\") setAuthState(nextAuthState);\n }, [embedUrl, isDirectFallback, postThemeToFrame]);\n const workspaceSsoEnabled = useFeatureFlag(DISPATCH_WORKSPACE_SSO_FLAG.key);\n const createEmbedSession = useActionMutation<\n EmbedSessionResult,\n EmbedSessionInput\n >(\"create_embed_session\", {\n skipActionQueryInvalidation: true,\n });\n const createWorkspaceSsoEmbedSession = useActionMutation<\n EmbedSessionResult,\n EmbedSessionInput\n >(\"create-workspace-app-embed-session\", {\n skipActionQueryInvalidation: true,\n });\n const appHref = workspaceAppHref({\n id: app.id,\n name: app.name,\n path: app.path ?? \"\",\n url: app.url,\n });\n const embedInput = useMemo<EmbedSessionInput | null>(() => {\n if (embedPath !== undefined) {\n return buildChatFirstEmbedSessionInput(app.id, embedPath);\n }\n if (!appHref) return null;\n return {\n app: app.id,\n ...workspaceAppEmbedTarget({ path: app.path ?? \"\", url: app.url }),\n chrome: \"minimal\",\n };\n }, [app.id, app.path, app.url, appHref, embedPath]);\n\n useEffect(() => {\n if (!embedInput) return;\n let cancelled = false;\n setEmbedUrl(null);\n setEmbedError(null);\n setIsDirectFallback(false);\n setAuthState(\"unknown\");\n const createSession = workspaceSsoEnabled\n ? createWorkspaceSsoEmbedSession\n : createEmbedSession;\n void createSession\n .mutateAsync(embedInput)\n .then((result) => {\n if (!cancelled) setEmbedUrl(result.startUrl);\n })\n .catch((cause: unknown) => {\n if (cancelled) return;\n setIsDirectFallback(true);\n setEmbedUrl(\n workspaceAppDirectHref(\n { path: app.path ?? \"\", url: app.url },\n embedPath ?? \"/\",\n ),\n );\n setEmbedError(\n cause instanceof Error ? cause : new Error(String(cause)),\n );\n });\n return () => {\n cancelled = true;\n };\n }, [\n app.id,\n app.path,\n app.url,\n createEmbedSession.mutateAsync,\n createWorkspaceSsoEmbedSession.mutateAsync,\n embedInput,\n embedPath,\n embedAttempt,\n workspaceSsoEnabled,\n ]);\n\n useEffect(() => {\n const handleEmbedSessionExpired = (event: MessageEvent) => {\n if (\n !isEmbedSessionExpiredMessage(event, embedFrameRef.current, embedUrl)\n ) {\n return;\n }\n setEmbedAttempt((attempt) => attempt + 1);\n };\n\n window.addEventListener(\"message\", handleEmbedSessionExpired);\n return () =>\n window.removeEventListener(\"message\", handleEmbedSessionExpired);\n }, [embedUrl]);\n\n useEffect(() => {\n const handleAuthState = (event: MessageEvent) => {\n const frame = embedFrameRef.current;\n if (!frame || event.source !== frame.contentWindow) return;\n if (event.data?.type !== \"agentNative.authState\") return;\n const status = event.data.data?.status;\n if (status === \"authenticated\" || status === \"unauthenticated\") {\n setAuthState(status);\n }\n };\n\n window.addEventListener(\"message\", handleAuthState);\n return () => window.removeEventListener(\"message\", handleAuthState);\n }, []);\n\n useEffect(() => {\n postThemeToFrame();\n }, [embedUrl, postThemeToFrame]);\n\n const appPane = (\n <ChatFirstAppPane\n app={app}\n status={\n embedUrl\n ? \"ready\"\n : embedError\n ? \"error\"\n : embedInput\n ? \"loading\"\n : \"unresolved\"\n }\n embedUrl={embedUrl}\n errorMessage={embedError?.message}\n onRetry={\n embedInput ? () => setEmbedAttempt((attempt) => attempt + 1) : undefined\n }\n renderEmbed={({ url, title }) => (\n <iframe\n key={url + \":\" + embedAttempt}\n data-dispatch-workspace-app-frame\n src={url}\n title={title ?? app.name}\n ref={embedFrameRef}\n onLoad={handleFrameLoad}\n referrerPolicy=\"no-referrer\"\n allow=\"clipboard-read; clipboard-write\"\n className=\"h-full w-full border-0 bg-background\"\n />\n )}\n copy={copy}\n />\n );\n\n if (!chatSidebar) return appPane;\n\n return (\n <AgentSidebar\n position=\"left\"\n defaultOpen\n openStorageKey=\"dispatch-app-chat\"\n storageKey={`dispatch-app-chat:${app.id}`}\n scope={{\n type: \"workspace-app\",\n id: app.id,\n label: app.name,\n contextKey: `workspace-app:${app.id}`,\n }}\n agentChatSurface=\"app\"\n showTabBar\n suppressInlineOpenApp\n dynamicSuggestions={false}\n suggestions={[]}\n emptyStateText={`Ask about ${app.name}`}\n composerSlot={\n authState === \"unauthenticated\" ? (\n <div className=\"flex shrink-0 items-center px-3 pb-1\">\n <button\n type=\"button\"\n data-dispatch-app-sign-in\n aria-label={`Sign in to ${app.name} on the right`}\n title={`Sign in to ${app.name} on the right`}\n onClick={() => embedFrameRef.current?.focus()}\n className=\"inline-flex h-6 shrink-0 items-center gap-1 rounded-full border border-border/70 bg-background/60 px-2 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\"\n >\n <IconLock size={12} stroke={1.8} />\n <span>Sign in on the right</span>\n <IconArrowUpRight size={12} stroke={1.8} />\n </button>\n </div>\n ) : null\n }\n >\n {appPane}\n </AgentSidebar>\n );\n}\n\nexport function WorkspaceAppHost({ appId }: { appId?: string }) {\n const t = useT();\n const workspaceAppsQuery = useActionQuery<WorkspaceAppSummary[]>(\n \"list-workspace-apps\",\n { includeAgentCards: false },\n );\n const grantedAppsQuery = useActionQuery<GrantedWorkspaceAppsResult>(\n \"list_apps\",\n {},\n );\n const apps = useMemo(() => {\n const merged = new Map<string, WorkspaceAppSummary>();\n\n for (const app of mergeChatFirstWorkspaceApps(workspaceAppsQuery.data)) {\n merged.set(app.id.trim().toLowerCase(), app);\n }\n for (const app of grantedAppsQuery.data?.apps ?? []) {\n const id = app.id.trim();\n if (!id || merged.has(id.toLowerCase())) continue;\n merged.set(id.toLowerCase(), {\n id,\n name: app.name.trim() || id,\n path: \"\",\n url: app.url?.trim() || null,\n status: \"ready\",\n });\n }\n\n return [...merged.values()];\n }, [grantedAppsQuery.data?.apps, workspaceAppsQuery.data]);\n const app = useMemo(\n () =>\n apps.find(\n (item) => item.id.trim().toLowerCase() === appId?.trim().toLowerCase(),\n ) ?? null,\n [appId, apps],\n );\n const isLoading = workspaceAppsQuery.isLoading || grantedAppsQuery.isLoading;\n const queryError = workspaceAppsQuery.isError\n ? workspaceAppsQuery.error\n : grantedAppsQuery.isError\n ? grantedAppsQuery.error\n : null;\n\n if (queryError && !app) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl\">\n <ActionQueryError\n error={queryError}\n onRetry={() => {\n void workspaceAppsQuery.refetch();\n void grantedAppsQuery.refetch();\n }}\n />\n </div>\n </div>\n );\n }\n\n if (isLoading && !app) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl space-y-3 rounded-xl border bg-card p-6\">\n <Skeleton className=\"h-5 w-48\" />\n <Skeleton className=\"h-4 w-full\" />\n <Skeleton className=\"h-4 w-2/3\" />\n </div>\n </div>\n );\n }\n\n if (!app) {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl rounded-xl border bg-card p-6\">\n <Button asChild size=\"sm\" variant=\"ghost\" className=\"-ml-2 mb-4\">\n <Link to=\"/apps\">\n <IconArrowLeft size={15} className=\"mr-1.5\" />\n {t(\"dispatch.nav.apps\")}\n </Link>\n </Button>\n <div className=\"space-y-3\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {t(\"dispatch.pages.appNotFound\")}\n </h2>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"dispatch.pages.pageNotFoundDescription\")}\n </p>\n </div>\n </div>\n </div>\n );\n }\n\n if (app.status === \"pending\") {\n return (\n <div className=\"flex h-full min-h-0 items-center justify-center p-6\">\n <div className=\"w-full max-w-2xl rounded-xl border bg-card p-6\">\n <Button asChild size=\"sm\" variant=\"ghost\" className=\"-ml-2 mb-4\">\n <Link to=\"/apps\">\n <IconArrowLeft size={15} className=\"mr-1.5\" />\n {t(\"dispatch.nav.apps\")}\n </Link>\n </Button>\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h2 className=\"text-base font-semibold text-foreground\">\n {app.name}\n </h2>\n <Badge\n variant=\"outline\"\n className=\"gap-1 border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300\"\n >\n <IconClockHour4 size={12} />\n {t(\"dispatch.pages.building\")}\n </Badge>\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {t(\"dispatch.pages.appBuildingPrefix\")}{\" \"}\n <span className=\"font-mono text-foreground\">{app.path}</span>{\" \"}\n {t(\"dispatch.pages.appBuildingSuffix\")}\n </p>\n {app.builderUrl ? (\n <Button asChild>\n <a\n href={withBuilderUtmTrackingParams(app.builderUrl, {\n campaign: \"product\",\n content: \"dispatch_branch\",\n })}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n {t(\"dispatch.pages.openBuilderBranch\", {\n defaultValue: \"Open in Builder\",\n })}\n </a>\n </Button>\n ) : null}\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div\n data-dispatch-workspace-app-host\n className=\"flex h-full min-h-0 flex-col bg-background\"\n >\n <div className=\"min-h-0 flex-1 bg-muted/20\">\n <WorkspaceAppFrame app={app} />\n </div>\n </div>\n );\n}\n\nconst MAX_KEEP_ALIVE_APPS = 3;\n\nexport function WorkspaceAppKeepAlive({\n activeAppId,\n}: {\n activeAppId: string | null;\n}) {\n const [visitedAppIds, setVisitedAppIds] = useState<string[]>(() =>\n activeAppId ? [activeAppId] : [],\n );\n\n useEffect(() => {\n if (!activeAppId) return;\n setVisitedAppIds((current) =>\n [activeAppId, ...current.filter((appId) => appId !== activeAppId)].slice(\n 0,\n MAX_KEEP_ALIVE_APPS,\n ),\n );\n }, [activeAppId]);\n\n const renderedAppIds =\n activeAppId && !visitedAppIds.includes(activeAppId)\n ? [activeAppId, ...visitedAppIds]\n : visitedAppIds;\n\n return (\n <div\n data-dispatch-workspace-app-cache\n className={activeAppId ? \"absolute inset-0 overflow-hidden\" : \"hidden\"}\n >\n {renderedAppIds.map((appId) => {\n const active = appId === activeAppId;\n return (\n <div\n key={appId}\n data-dispatch-workspace-app-cache-entry={appId}\n aria-hidden={!active}\n className={active ? \"h-full min-h-0\" : \"hidden\"}\n >\n <WorkspaceAppHost appId={appId} />\n </div>\n );\n })}\n </div>\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/dispatch",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.3",
|
|
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.16.
|
|
90
|
+
"@agent-native/toolkit": "0.16.3"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
93
|
"@react-router/dev": "^8.1.0",
|
|
@@ -101,7 +101,7 @@
|
|
|
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.157.
|
|
104
|
+
"@agent-native/core": "0.157.10"
|
|
105
105
|
},
|
|
106
106
|
"peerDependencies": {
|
|
107
107
|
"@agent-native/core": ">=0.8.0",
|
|
@@ -11,6 +11,7 @@ const clientState = vi.hoisted(() => {
|
|
|
11
11
|
const workspaceSsoMutateAsync = vi.fn().mockImplementation(async () => ({
|
|
12
12
|
startUrl: "about:blank",
|
|
13
13
|
}));
|
|
14
|
+
const legacyErrorMutateAsync = vi.fn();
|
|
14
15
|
const actionNames: string[] = [];
|
|
15
16
|
return {
|
|
16
17
|
actionNames,
|
|
@@ -22,6 +23,10 @@ const clientState = vi.hoisted(() => {
|
|
|
22
23
|
},
|
|
23
24
|
],
|
|
24
25
|
legacyMutateAsync,
|
|
26
|
+
legacyMutateError: null as Error | null,
|
|
27
|
+
legacyErrorMutateAsync,
|
|
28
|
+
frameLoadHandler: null as (() => void) | null,
|
|
29
|
+
suppressFrameLoad: false,
|
|
25
30
|
theme: "dark" as "dark" | "light",
|
|
26
31
|
workspaceSsoEnabled: false,
|
|
27
32
|
workspaceSsoMutateAsync,
|
|
@@ -39,17 +44,33 @@ vi.mock("@agent-native/core/client/chat-first", () => ({
|
|
|
39
44
|
ChatFirstAppPane: ({
|
|
40
45
|
app,
|
|
41
46
|
embedUrl,
|
|
47
|
+
errorMessage,
|
|
42
48
|
renderEmbed,
|
|
43
49
|
status,
|
|
44
50
|
}: {
|
|
45
51
|
app: { name: string } | null;
|
|
46
52
|
embedUrl?: string | null;
|
|
53
|
+
errorMessage?: string;
|
|
47
54
|
renderEmbed: (target: { url: string; title?: string }) => React.ReactNode;
|
|
48
55
|
status: string;
|
|
49
56
|
}) => (
|
|
50
|
-
<div
|
|
57
|
+
<div
|
|
58
|
+
data-chat-first-app-error={errorMessage ?? ""}
|
|
59
|
+
data-chat-first-app-status={status}
|
|
60
|
+
>
|
|
51
61
|
{status === "ready" && embedUrl
|
|
52
|
-
?
|
|
62
|
+
? (() => {
|
|
63
|
+
const frame = renderEmbed({ url: embedUrl, title: app?.name });
|
|
64
|
+
if (clientState.suppressFrameLoad && React.isValidElement(frame)) {
|
|
65
|
+
clientState.frameLoadHandler =
|
|
66
|
+
(frame.props as { onLoad?: () => void }).onLoad ?? null;
|
|
67
|
+
return React.cloneElement(frame, {
|
|
68
|
+
onLoad: undefined,
|
|
69
|
+
src: undefined,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return frame;
|
|
73
|
+
})()
|
|
53
74
|
: null}
|
|
54
75
|
</div>
|
|
55
76
|
),
|
|
@@ -67,7 +88,9 @@ vi.mock("@agent-native/core/client/hooks", () => ({
|
|
|
67
88
|
mutateAsync:
|
|
68
89
|
name === "create-workspace-app-embed-session"
|
|
69
90
|
? clientState.workspaceSsoMutateAsync
|
|
70
|
-
: clientState.
|
|
91
|
+
: clientState.legacyMutateError
|
|
92
|
+
? clientState.legacyErrorMutateAsync
|
|
93
|
+
: clientState.legacyMutateAsync,
|
|
71
94
|
};
|
|
72
95
|
},
|
|
73
96
|
useActionQuery: (name: string) => ({
|
|
@@ -131,6 +154,10 @@ describe("WorkspaceAppKeepAlive", () => {
|
|
|
131
154
|
root = createRoot(container);
|
|
132
155
|
clientState.actionNames.length = 0;
|
|
133
156
|
clientState.legacyMutateAsync.mockClear();
|
|
157
|
+
clientState.legacyMutateError = null;
|
|
158
|
+
clientState.legacyErrorMutateAsync.mockReset();
|
|
159
|
+
clientState.frameLoadHandler = null;
|
|
160
|
+
clientState.suppressFrameLoad = false;
|
|
134
161
|
clientState.workspaceSsoMutateAsync.mockClear();
|
|
135
162
|
clientState.theme = "dark";
|
|
136
163
|
clientState.workspaceSsoEnabled = false;
|
|
@@ -267,6 +294,44 @@ describe("WorkspaceAppKeepAlive", () => {
|
|
|
267
294
|
);
|
|
268
295
|
});
|
|
269
296
|
|
|
297
|
+
it("clears the embed error after a direct fallback iframe loads", async () => {
|
|
298
|
+
clientState.legacyMutateError = new Error("Restore request failed");
|
|
299
|
+
clientState.legacyErrorMutateAsync.mockRejectedValue(
|
|
300
|
+
clientState.legacyMutateError,
|
|
301
|
+
);
|
|
302
|
+
clientState.suppressFrameLoad = true;
|
|
303
|
+
|
|
304
|
+
await act(async () => {
|
|
305
|
+
root.render(
|
|
306
|
+
<WorkspaceAppFrame app={{ id: "mail", name: "Mail", path: "/mail" }} />,
|
|
307
|
+
);
|
|
308
|
+
await Promise.resolve();
|
|
309
|
+
await Promise.resolve();
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
const iframe = container.querySelector<HTMLIFrameElement>("iframe");
|
|
313
|
+
expect(iframe).not.toBeNull();
|
|
314
|
+
expect(
|
|
315
|
+
container
|
|
316
|
+
.querySelector("[data-chat-first-app-error]")
|
|
317
|
+
?.getAttribute("data-chat-first-app-error"),
|
|
318
|
+
).toBe("Restore request failed");
|
|
319
|
+
|
|
320
|
+
if (!iframe) throw new Error("Workspace app iframe was not rendered");
|
|
321
|
+
expect(clientState.frameLoadHandler).not.toBeNull();
|
|
322
|
+
|
|
323
|
+
await act(async () => {
|
|
324
|
+
clientState.frameLoadHandler?.();
|
|
325
|
+
await Promise.resolve();
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
expect(
|
|
329
|
+
container
|
|
330
|
+
.querySelector("[data-chat-first-app-error]")
|
|
331
|
+
?.getAttribute("data-chat-first-app-error"),
|
|
332
|
+
).toBe("");
|
|
333
|
+
});
|
|
334
|
+
|
|
270
335
|
it("evicts the oldest inactive app after reaching the keep-alive limit", async () => {
|
|
271
336
|
await act(async () => {
|
|
272
337
|
root.render(<WorkspaceAppKeepAlive activeAppId="mail" />);
|
|
@@ -129,6 +129,7 @@ export function WorkspaceAppFrame({
|
|
|
129
129
|
: "light";
|
|
130
130
|
const [embedUrl, setEmbedUrl] = useState<string | null>(null);
|
|
131
131
|
const [embedError, setEmbedError] = useState<Error | null>(null);
|
|
132
|
+
const [isDirectFallback, setIsDirectFallback] = useState(false);
|
|
132
133
|
const [embedAttempt, setEmbedAttempt] = useState(0);
|
|
133
134
|
const [authState, setAuthState] = useState<WorkspaceAppAuthState>("unknown");
|
|
134
135
|
const embedFrameRef = useRef<HTMLIFrameElement>(null);
|
|
@@ -140,6 +141,7 @@ export function WorkspaceAppFrame({
|
|
|
140
141
|
}, [theme]);
|
|
141
142
|
const handleFrameLoad = useCallback(() => {
|
|
142
143
|
postThemeToFrame();
|
|
144
|
+
if (isDirectFallback) setEmbedError(null);
|
|
143
145
|
const frame = embedFrameRef.current;
|
|
144
146
|
let frameUrl = embedUrl;
|
|
145
147
|
try {
|
|
@@ -150,7 +152,7 @@ export function WorkspaceAppFrame({
|
|
|
150
152
|
}
|
|
151
153
|
const nextAuthState = resolveWorkspaceAppAuthState(frameUrl);
|
|
152
154
|
if (nextAuthState !== "unknown") setAuthState(nextAuthState);
|
|
153
|
-
}, [embedUrl, postThemeToFrame]);
|
|
155
|
+
}, [embedUrl, isDirectFallback, postThemeToFrame]);
|
|
154
156
|
const workspaceSsoEnabled = useFeatureFlag(DISPATCH_WORKSPACE_SSO_FLAG.key);
|
|
155
157
|
const createEmbedSession = useActionMutation<
|
|
156
158
|
EmbedSessionResult,
|
|
@@ -187,6 +189,7 @@ export function WorkspaceAppFrame({
|
|
|
187
189
|
let cancelled = false;
|
|
188
190
|
setEmbedUrl(null);
|
|
189
191
|
setEmbedError(null);
|
|
192
|
+
setIsDirectFallback(false);
|
|
190
193
|
setAuthState("unknown");
|
|
191
194
|
const createSession = workspaceSsoEnabled
|
|
192
195
|
? createWorkspaceSsoEmbedSession
|
|
@@ -198,6 +201,7 @@ export function WorkspaceAppFrame({
|
|
|
198
201
|
})
|
|
199
202
|
.catch((cause: unknown) => {
|
|
200
203
|
if (cancelled) return;
|
|
204
|
+
setIsDirectFallback(true);
|
|
201
205
|
setEmbedUrl(
|
|
202
206
|
workspaceAppDirectHref(
|
|
203
207
|
{ path: app.path ?? "", url: app.url },
|