Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit306a2aa

Browse files
committed
Implement home, refresh, and open in new tab
1 parent3d41d7f commit306a2aa

File tree

2 files changed

+98
-64
lines changed

2 files changed

+98
-64
lines changed

‎site/src/pages/TaskPage/TaskAppIframe.tsx

Lines changed: 92 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
11
importtype{WorkspaceApp}from"api/typesGenerated";
2+
import{Button}from"components/Button/Button";
3+
import{
4+
DropdownMenu,
5+
DropdownMenuContent,
6+
DropdownMenuItem,
7+
DropdownMenuTrigger,
8+
}from"components/DropdownMenu/DropdownMenu";
9+
import{
10+
EllipsisVertical,
11+
ExternalLinkIcon,
12+
HouseIcon,
13+
RotateCwIcon,
14+
}from"lucide-react";
15+
import{openAppInNewWindow}from"modules/apps/apps";
216
import{useAppLink}from"modules/apps/useAppLink";
317
importtype{Task}from"modules/tasks/tasks";
4-
importtype{FC}from"react";
18+
import{typeFC,useRef}from"react";
519
import{cn}from"utils/cn";
620

721
typeTaskAppIFrameProps={
@@ -31,24 +45,85 @@ export const TaskAppIFrame: FC<TaskAppIFrameProps> = ({
3145
workspace:task.workspace,
3246
});
3347

34-
lethref=link.href;
35-
try{
36-
consturl=newURL(link.href);
37-
if(pathname){
38-
url.pathname=pathname;
48+
constappHref=():string=>{
49+
try{
50+
consturl=newURL(link.href,location.href);
51+
if(pathname){
52+
url.pathname=pathname;
53+
}
54+
returnurl.toString();
55+
}catch(err){
56+
console.warn(`Failed to parse URL${link.href} for app${app.id}`,err);
57+
returnlink.href;
3958
}
40-
href=url.toString();
41-
}catch(err){
42-
console.warn(`Failed to parse URL${link.href} for app${app.id}`,err);
43-
}
59+
};
60+
61+
constframeRef=useRef<HTMLIFrameElement>(null);
62+
constframeSrc=appHref();
4463

4564
return(
46-
<iframe
47-
src={href}
48-
title={link.label}
49-
loading="eager"
50-
className={cn([active ?"block" :"hidden","w-full h-full border-0"])}
51-
allow="clipboard-read; clipboard-write"
52-
/>
65+
<>
66+
<divclassName="bg-surface-tertiary flex items-center p-2 py-1 gap-1">
67+
<Button
68+
size="icon"
69+
variant="subtle"
70+
onClick={(e)=>{
71+
e.preventDefault();
72+
if(frameRef.current?.contentWindow){
73+
frameRef.current.contentWindow.location.reload();
74+
}
75+
}}
76+
>
77+
<RotateCwIcon/>
78+
<spanclassName="sr-only">Refresh</span>
79+
</Button>
80+
81+
<Button
82+
size="icon"
83+
variant="subtle"
84+
onClick={(e)=>{
85+
e.preventDefault();
86+
if(frameRef.current?.contentWindow){
87+
frameRef.current.contentWindow.location.href=appHref();
88+
}
89+
}}
90+
>
91+
<HouseIcon/>
92+
<spanclassName="sr-only">Home</span>
93+
</Button>
94+
95+
{/* Possibly we will put a URL bar here, but for now we cannot due to
96+
* cross-origin restrictions in iframes. */}
97+
<divclassName="w-full"></div>
98+
99+
<DropdownMenu>
100+
<DropdownMenuTriggerasChild>
101+
<Buttonsize="icon"variant="subtle"aria-label="More options">
102+
<EllipsisVerticalaria-hidden="true"/>
103+
<spanclassName="sr-only">More options</span>
104+
</Button>
105+
</DropdownMenuTrigger>
106+
<DropdownMenuContentalign="end">
107+
<DropdownMenuItem
108+
onClick={()=>{
109+
openAppInNewWindow(frameSrc);
110+
}}
111+
>
112+
<ExternalLinkIcon/>
113+
Open app in new tab
114+
</DropdownMenuItem>
115+
</DropdownMenuContent>
116+
</DropdownMenu>
117+
</div>
118+
119+
<iframe
120+
ref={frameRef}
121+
src={frameSrc}
122+
title={link.label}
123+
loading="eager"
124+
className={cn([active ?"block" :"hidden","w-full h-full border-0"])}
125+
allow="clipboard-read; clipboard-write"
126+
/>
127+
</>
53128
);
54129
};

‎site/src/pages/TaskPage/TaskApps.tsx

Lines changed: 6 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,7 @@ import {
77
DropdownMenuTrigger,
88
}from"components/DropdownMenu/DropdownMenu";
99
import{ExternalImage}from"components/ExternalImage/ExternalImage";
10-
import{
11-
ArrowLeftIcon,
12-
ArrowRightIcon,
13-
ChevronDownIcon,
14-
EllipsisVertical,
15-
HouseIcon,
16-
LayoutGridIcon,
17-
RefreshCwIcon,
18-
RotateCwIcon,
19-
}from"lucide-react";
10+
import{ChevronDownIcon,LayoutGridIcon}from"lucide-react";
2011
import{useAppLink}from"modules/apps/useAppLink";
2112
importtype{Task}from"modules/tasks/tasks";
2213
importtypeReactfrom"react";
@@ -25,7 +16,6 @@ import { Link as RouterLink } from "react-router-dom";
2516
import{cn}from"utils/cn";
2617
import{TaskAppIFrame}from"./TaskAppIframe";
2718
import{AI_APP_CHAT_SLUG}from"./constants";
28-
import{Input}from"components/Input/Input";
2919

3020
typeTaskAppsProps={
3121
task:Task;
@@ -42,13 +32,10 @@ export const TaskApps: FC<TaskAppsProps> = ({ task }) => {
4232
.flatMap((a)=>a?.apps)
4333
.filter((a)=>!!a&&a.slug!==AI_APP_CHAT_SLUG);
4434

45-
constembeddedApps=apps.filter((app)=>!app.external);
46-
constexternalApps=apps.filter((app)=>app.external);
47-
4835
const[activeAppId,setActiveAppId]=useState<string>(()=>{
49-
constappId=embeddedApps[0]?.id;
36+
constappId=task.workspace.latest_app_status?.app_id;
5037
if(!appId){
51-
thrownewError("Noapps found in task");
38+
thrownewError("Noactive app found in task");
5239
}
5340
returnappId;
5441
});
@@ -65,6 +52,9 @@ export const TaskApps: FC<TaskAppsProps> = ({ task }) => {
6552
thrownewError(`Agent for app${activeAppId} not found in task workspace`);
6653
}
6754

55+
constembeddedApps=apps.filter((app)=>!app.external);
56+
constexternalApps=apps.filter((app)=>app.external);
57+
6858
return(
6959
<mainclassName="flex-1 flex flex-col">
7060
<divclassName="w-full flex items-center border-0 border-b border-border border-solid">
@@ -118,37 +108,6 @@ export const TaskApps: FC<TaskAppsProps> = ({ task }) => {
118108
)}
119109
</div>
120110

121-
<divclassName="bg-surface-tertiary p-2 py-1 flex items-center gap-1">
122-
<divclassName="flex items-center">
123-
<Buttonsize="icon"variant="subtle">
124-
<ArrowLeftIcon/>
125-
<spanclassName="sr-only">Back</span>
126-
</Button>
127-
128-
<Buttonsize="icon"variant="subtle">
129-
<ArrowRightIcon/>
130-
<spanclassName="sr-only">Forward</span>
131-
</Button>
132-
133-
<Buttonsize="icon"variant="subtle">
134-
<RotateCwIcon/>
135-
<spanclassName="sr-only">Refresh</span>
136-
</Button>
137-
138-
<Buttonsize="icon"variant="subtle">
139-
<HouseIcon/>
140-
<spanclassName="sr-only">Home</span>
141-
</Button>
142-
</div>
143-
144-
<InputclassName="w-full rounded-full bg-surface-secondary h-9 md:text-xs"/>
145-
146-
<Buttonsize="icon"variant="subtle">
147-
<EllipsisVertical/>
148-
<spanclassName="sr-only">More options</span>
149-
</Button>
150-
</div>
151-
152111
<divclassName="flex-1">
153112
{embeddedApps.map((app)=>{
154113
return(

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp