mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
feat: group external apps on task page (#18107)
https://github.com/user-attachments/assets/ac03f9ad-9b89-400b-aabe-fade2997319b
This commit is contained in:
@@ -111,7 +111,7 @@ export const DropdownMenuItem = forwardRef<
|
||||
[
|
||||
"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-2 text-sm text-content-secondary font-medium outline-none transition-colors",
|
||||
"focus:bg-surface-secondary focus:text-content-primary data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
"[&>svg]:size-4 [&>svg]:shrink-0 no-underline",
|
||||
"[&>svg]:size-4 [&>svg]:shrink-0 [&>img]:size-4 [&>img]:shrink-0 no-underline",
|
||||
inset && "pl-8",
|
||||
],
|
||||
className,
|
||||
|
||||
@@ -131,9 +131,15 @@ export const Active: Story = {
|
||||
{
|
||||
...MockWorkspaceApp,
|
||||
id: "vscode",
|
||||
display_name: "VSCode",
|
||||
display_name: "VS Code Web",
|
||||
icon: "/icon/code.svg",
|
||||
},
|
||||
{
|
||||
...MockWorkspaceApp,
|
||||
id: "zed",
|
||||
display_name: "Zed",
|
||||
icon: "/icon/zed.svg",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -2,6 +2,12 @@ import { API } from "api/api";
|
||||
import { getErrorDetail, getErrorMessage } from "api/errors";
|
||||
import type { WorkspaceApp, WorkspaceStatus } from "api/typesGenerated";
|
||||
import { Button } from "components/Button/Button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "components/DropdownMenu/DropdownMenu";
|
||||
import { ExternalImage } from "components/ExternalImage/ExternalImage";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import { Margins } from "components/Margins/Margins";
|
||||
@@ -14,7 +20,12 @@ import {
|
||||
TooltipTrigger,
|
||||
} from "components/Tooltip/Tooltip";
|
||||
import { useProxy } from "contexts/ProxyContext";
|
||||
import { ArrowLeftIcon, LayoutGridIcon, RotateCcwIcon } from "lucide-react";
|
||||
import {
|
||||
ArrowLeftIcon,
|
||||
ChevronDownIcon,
|
||||
LayoutGridIcon,
|
||||
RotateCcwIcon,
|
||||
} from "lucide-react";
|
||||
import { AppStatusIcon } from "modules/apps/AppStatusIcon";
|
||||
import { getAppHref } from "modules/apps/apps";
|
||||
import { useAppLink } from "modules/apps/useAppLink";
|
||||
@@ -312,26 +323,67 @@ const TaskApps: FC<TaskAppsProps> = ({ task }) => {
|
||||
return src;
|
||||
});
|
||||
|
||||
const embeddedApps = apps.filter((app) => !app.external);
|
||||
const externalApps = apps.filter((app) => app.external);
|
||||
|
||||
return (
|
||||
<main className="flex-1 flex flex-col">
|
||||
<div className="border-0 border-b border-border border-solid w-full p-1 flex gap-2">
|
||||
{apps.map((app) => (
|
||||
<TaskAppButton
|
||||
key={app.id}
|
||||
task={task}
|
||||
app={app}
|
||||
active={app.id === activeAppId}
|
||||
onClick={(e) => {
|
||||
if (app.external) {
|
||||
return;
|
||||
}
|
||||
{embeddedApps
|
||||
.filter((app) => !app.external)
|
||||
.map((app) => (
|
||||
<TaskAppButton
|
||||
key={app.id}
|
||||
task={task}
|
||||
app={app}
|
||||
active={app.id === activeAppId}
|
||||
onClick={(e) => {
|
||||
if (app.external) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
setActiveAppId(app.id);
|
||||
setIframeSrc(e.currentTarget.href);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
e.preventDefault();
|
||||
setActiveAppId(app.id);
|
||||
setIframeSrc(e.currentTarget.href);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{externalApps.length > 0 && (
|
||||
<div className="ml-auto">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button size="sm" variant="subtle">
|
||||
Open in IDE
|
||||
<ChevronDownIcon />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
{externalApps
|
||||
.filter((app) => app.external)
|
||||
.map((app) => {
|
||||
const link = useAppLink(app, {
|
||||
agent,
|
||||
workspace: task.workspace,
|
||||
});
|
||||
|
||||
return (
|
||||
<DropdownMenuItem key={app.id} asChild>
|
||||
<RouterLink to={link.href}>
|
||||
{app.icon ? (
|
||||
<ExternalImage src={app.icon} />
|
||||
) : (
|
||||
<LayoutGridIcon />
|
||||
)}
|
||||
{link.label}
|
||||
</RouterLink>
|
||||
</DropdownMenuItem>
|
||||
);
|
||||
})}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex-1">
|
||||
|
||||
Reference in New Issue
Block a user