Skip to content

Commit 89486e8

Browse files
committed
feat: group external apps on task page
1 parent 177bda3 commit 89486e8

File tree

2 files changed

+66
-19
lines changed

2 files changed

+66
-19
lines changed

site/src/components/DropdownMenu/DropdownMenu.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ export const DropdownMenuItem = forwardRef<
111111
[
112112
"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",
113113
"focus:bg-surface-secondary focus:text-content-primary data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
114-
"[&>svg]:size-4 [&>svg]:shrink-0 no-underline",
114+
"[&>svg]:size-4 [&>svg]:shrink-0 [&>img]:size-4 [&>img]:shrink-0 no-underline",
115115
inset && "pl-8",
116116
],
117117
className,

site/src/pages/TaskPage/TaskPage.tsx

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ import { API } from "api/api";
22
import { getErrorDetail, getErrorMessage } from "api/errors";
33
import type { WorkspaceApp, WorkspaceStatus } from "api/typesGenerated";
44
import { Button } from "components/Button/Button";
5+
import {
6+
DropdownMenu,
7+
DropdownMenuContent,
8+
DropdownMenuItem,
9+
DropdownMenuTrigger,
10+
} from "components/DropdownMenu/DropdownMenu";
511
import { ExternalImage } from "components/ExternalImage/ExternalImage";
612
import { Loader } from "components/Loader/Loader";
713
import { Margins } from "components/Margins/Margins";
@@ -14,7 +20,12 @@ import {
1420
TooltipTrigger,
1521
} from "components/Tooltip/Tooltip";
1622
import { useProxy } from "contexts/ProxyContext";
17-
import { ArrowLeftIcon, LayoutGridIcon, RotateCcwIcon } from "lucide-react";
23+
import {
24+
ArrowLeftIcon,
25+
ChevronDownIcon,
26+
LayoutGridIcon,
27+
RotateCcwIcon,
28+
} from "lucide-react";
1829
import { AppStatusIcon } from "modules/apps/AppStatusIcon";
1930
import { getAppHref } from "modules/apps/apps";
2031
import { useAppLink } from "modules/apps/useAppLink";
@@ -307,23 +318,59 @@ const TaskApps: FC<TaskAppsProps> = ({ task }) => {
307318
return (
308319
<main className="flex-1 flex flex-col">
309320
<div className="border-0 border-b border-border border-solid w-full p-1 flex gap-2">
310-
{apps.map((app) => (
311-
<TaskAppButton
312-
key={app.id}
313-
task={task}
314-
app={app}
315-
active={app.id === activeAppId}
316-
onClick={(e) => {
317-
if (app.external) {
318-
return;
319-
}
320-
321-
e.preventDefault();
322-
setActiveAppId(app.id);
323-
setIframeSrc(e.currentTarget.href);
324-
}}
325-
/>
326-
))}
321+
{apps
322+
.filter((app) => !app.external)
323+
.map((app) => (
324+
<TaskAppButton
325+
key={app.id}
326+
task={task}
327+
app={app}
328+
active={app.id === activeAppId}
329+
onClick={(e) => {
330+
if (app.external) {
331+
return;
332+
}
333+
334+
e.preventDefault();
335+
setActiveAppId(app.id);
336+
setIframeSrc(e.currentTarget.href);
337+
}}
338+
/>
339+
))}
340+
341+
<div className="ml-auto">
342+
<DropdownMenu>
343+
<DropdownMenuTrigger asChild>
344+
<Button size="sm" variant="subtle">
345+
Open in
346+
<ChevronDownIcon />
347+
</Button>
348+
</DropdownMenuTrigger>
349+
<DropdownMenuContent>
350+
{apps
351+
.filter((app) => app.external)
352+
.map((app) => {
353+
const link = useAppLink(app, {
354+
agent,
355+
workspace: task.workspace,
356+
});
357+
358+
return (
359+
<DropdownMenuItem key={app.id} asChild>
360+
<RouterLink to={link.href}>
361+
{app.icon ? (
362+
<ExternalImage src={app.icon} />
363+
) : (
364+
<LayoutGridIcon />
365+
)}
366+
{link.label}
367+
</RouterLink>
368+
</DropdownMenuItem>
369+
);
370+
})}
371+
</DropdownMenuContent>
372+
</DropdownMenu>
373+
</div>
327374
</div>
328375

329376
<div className="flex-1">

0 commit comments

Comments
 (0)