chore: improve iframe loading time (#18134)

- Pre-load all the embed app iframes
- Avoid reloading the iframe when the selected app changes
This commit is contained in:
Bruno Quaresma
2025-05-30 15:30:35 -03:00
committed by GitHub
parent 00502dc653
commit 9fbccc032d
2 changed files with 56 additions and 22 deletions
+15 -3
View File
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from "@storybook/react";
import { spyOn } from "@storybook/test";
import { expect, spyOn, within } from "@storybook/test";
import {
MockFailedWorkspace,
MockStartingWorkspace,
@@ -115,9 +115,8 @@ export const Active: Story = {
...MockWorkspaceApp,
id: "claude-code",
display_name: "Claude Code",
slug: "claude-code",
icon: "/icon/claude.svg",
url: `${window.location.protocol}/iframe.html?viewMode=story&id=pages-terminal--ready&args=&globals=`,
external: true,
statuses: [
MockWorkspaceAppStatus,
{
@@ -131,11 +130,13 @@ export const Active: Story = {
{
...MockWorkspaceApp,
id: "vscode",
slug: "vscode",
display_name: "VS Code Web",
icon: "/icon/code.svg",
},
{
...MockWorkspaceApp,
slug: "zed",
id: "zed",
display_name: "Zed",
icon: "/icon/zed.svg",
@@ -153,4 +154,15 @@ export const Active: Story = {
},
});
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const vscodeIframe = await canvas.findByTitle("VS Code Web");
const zedIframe = await canvas.findByTitle("Zed");
const claudeIframe = await canvas.findByTitle("Claude Code");
expect(vscodeIframe).not.toBeVisible();
expect(zedIframe).not.toBeVisible();
expect(claudeIframe).toBeVisible();
},
};
+41 -19
View File
@@ -19,7 +19,6 @@ import {
TooltipProvider,
TooltipTrigger,
} from "components/Tooltip/Tooltip";
import { useProxy } from "contexts/ProxyContext";
import {
ArrowLeftIcon,
ChevronDownIcon,
@@ -27,7 +26,6 @@ import {
RotateCcwIcon,
} from "lucide-react";
import { AppStatusIcon } from "modules/apps/AppStatusIcon";
import { getAppHref } from "modules/apps/apps";
import { useAppLink } from "modules/apps/useAppLink";
import { AI_PROMPT_PARAMETER_NAME, type Task } from "modules/tasks/tasks";
import { WorkspaceAppStatus } from "modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus";
@@ -312,17 +310,6 @@ const TaskApps: FC<TaskAppsProps> = ({ task }) => {
throw new Error(`Agent for app ${activeAppId} not found in task workspace`);
}
const { proxy } = useProxy();
const [iframeSrc, setIframeSrc] = useState(() => {
const src = getAppHref(activeApp, {
agent,
workspace: task.workspace,
path: proxy.preferredPathAppURL,
host: proxy.preferredWildcardHostname,
});
return src;
});
const embeddedApps = apps.filter((app) => !app.external);
const externalApps = apps.filter((app) => app.external);
@@ -344,7 +331,6 @@ const TaskApps: FC<TaskAppsProps> = ({ task }) => {
e.preventDefault();
setActiveAppId(app.id);
setIframeSrc(e.currentTarget.href);
}}
/>
))}
@@ -387,11 +373,16 @@ const TaskApps: FC<TaskAppsProps> = ({ task }) => {
</div>
<div className="flex-1">
<iframe
title={activeApp.display_name ?? activeApp.slug}
className="w-full h-full border-0"
src={iframeSrc}
/>
{embeddedApps.map((app) => {
return (
<TaskAppIFrame
key={app.id}
active={activeAppId === app.id}
app={app}
task={task}
/>
);
})}
</div>
</main>
);
@@ -443,6 +434,37 @@ const TaskAppButton: FC<TaskAppButtonProps> = ({
);
};
type TaskAppIFrameProps = {
task: Task;
app: WorkspaceApp;
active: boolean;
};
const TaskAppIFrame: FC<TaskAppIFrameProps> = ({ task, app, active }) => {
const agent = task.workspace.latest_build.resources
.flatMap((r) => r.agents)
.filter((a) => !!a)
.find((a) => a.apps.some((a) => a.id === app.id));
if (!agent) {
throw new Error(`Agent for app ${app.id} not found in task workspace`);
}
const link = useAppLink(app, {
agent,
workspace: task.workspace,
});
return (
<iframe
src={link.href}
title={link.label}
loading="eager"
className={cn([active ? "block" : "hidden", "w-full h-full border-0"])}
/>
);
};
export const data = {
fetchTask: async (workspaceOwnerUsername: string, workspaceName: string) => {
const workspace = await API.getWorkspaceByOwnerAndName(