mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
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:
@@ -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();
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user