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

Commit0899774

Browse files
feat: add open in vscode button for devcontainers
1 parentd6c034d commit0899774

File tree

4 files changed

+232
-7
lines changed

4 files changed

+232
-7
lines changed

‎site/src/modules/resources/AgentDevcontainerCard.stories.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
importtype{Meta,StoryObj}from"@storybook/react";
22
import{
33
MockWorkspace,
4+
MockWorkspaceAgent,
45
MockWorkspaceAgentContainer,
56
MockWorkspaceAgentContainerPorts,
67
}from"testHelpers/entities";
@@ -13,7 +14,7 @@ const meta: Meta<typeof AgentDevcontainerCard> = {
1314
container:MockWorkspaceAgentContainer,
1415
workspace:MockWorkspace,
1516
wildcardHostname:"*.wildcard.hostname",
16-
agentName:"dev",
17+
agent:MockWorkspaceAgent,
1718
},
1819
};
1920

‎site/src/modules/resources/AgentDevcontainerCard.tsx

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,35 @@
11
importLinkfrom"@mui/material/Link";
22
importTooltip,{typeTooltipProps}from"@mui/material/Tooltip";
3-
importtype{Workspace,WorkspaceAgentContainer}from"api/typesGenerated";
3+
importtype{
4+
Workspace,
5+
WorkspaceAgent,
6+
WorkspaceAgentContainer,
7+
}from"api/typesGenerated";
48
import{ExternalLinkIcon}from"lucide-react";
59
importtype{FC}from"react";
610
import{portForwardURL}from"utils/portForward";
711
import{AgentButton}from"./AgentButton";
812
import{AgentDevcontainerSSHButton}from"./SSHButton/SSHButton";
913
import{TerminalLink}from"./TerminalLink/TerminalLink";
14+
import{VSCodeDevContainerButton}from"./VSCodeDevContainerButton/VSCodeDevContainerButton";
1015

1116
typeAgentDevcontainerCardProps={
17+
agent:WorkspaceAgent;
1218
container:WorkspaceAgentContainer;
1319
workspace:Workspace;
1420
wildcardHostname:string;
15-
agentName:string;
1621
};
1722

1823
exportconstAgentDevcontainerCard:FC<AgentDevcontainerCardProps>=({
24+
agent,
1925
container,
2026
workspace,
21-
agentName,
2227
wildcardHostname,
2328
})=>{
29+
constfolderPath=container.labels["devcontainer.local_folder"];
30+
constconfigFile=container.labels["devcontainer.config_file"];
31+
constcontainerFolder=container.volumes[folderPath];
32+
2433
return(
2534
<section
2635
className="border border-border border-dashed rounded p-6 "
@@ -40,9 +49,18 @@ export const AgentDevcontainerCard: FC<AgentDevcontainerCardProps> = ({
4049
<h4className="m-0 text-xl font-semibold">Forwarded ports</h4>
4150

4251
<divclassName="flex gap-4 flex-wrap mt-4">
52+
<VSCodeDevContainerButton
53+
userName={workspace.owner_name}
54+
workspaceName={workspace.name}
55+
folderPath={folderPath}
56+
devContainerPath={configFile}
57+
devContainerFolder={containerFolder}
58+
displayApps={agent.display_apps}
59+
/>
60+
4361
<TerminalLink
4462
workspaceName={workspace.name}
45-
agentName={agentName}
63+
agentName={agent.name}
4664
containerName={container.name}
4765
userName={workspace.owner_name}
4866
/>
@@ -58,7 +76,7 @@ export const AgentDevcontainerCard: FC<AgentDevcontainerCardProps> = ({
5876
?portForwardURL(
5977
wildcardHostname,
6078
port.host_port!,
61-
agentName,
79+
agent.name,
6280
workspace.name,
6381
workspace.owner_name,
6482
location.protocol==="https" ?"https" :"http",

‎site/src/modules/resources/AgentRow.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ export const AgentRow: FC<AgentRowProps> = ({
289289
container={container}
290290
workspace={workspace}
291291
wildcardHostname={proxy.preferredWildcardHostname}
292-
agentName={agent.name}
292+
agent={agent}
293293
/>
294294
);
295295
})}
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
importKeyboardArrowDownIconfrom"@mui/icons-material/KeyboardArrowDown";
2+
importButtonGroupfrom"@mui/material/ButtonGroup";
3+
importMenufrom"@mui/material/Menu";
4+
importMenuItemfrom"@mui/material/MenuItem";
5+
import{API}from"api/api";
6+
importtype{DisplayApp}from"api/typesGenerated";
7+
import{VSCodeIcon}from"components/Icons/VSCodeIcon";
8+
import{VSCodeInsidersIcon}from"components/Icons/VSCodeInsidersIcon";
9+
import{typeFC,useRef,useState}from"react";
10+
import{AgentButton}from"../AgentButton";
11+
import{DisplayAppNameMap}from"../AppLink/AppLink";
12+
13+
exportinterfaceVSCodeDevContainerButtonProps{
14+
userName:string;
15+
workspaceName:string;
16+
agentName?:string;
17+
folderPath:string;
18+
devContainerPath:string;
19+
devContainerFolder:string;
20+
displayApps:readonlyDisplayApp[];
21+
}
22+
23+
typeVSCodeVariant="vscode"|"vscode-insiders";
24+
25+
constVARIANT_KEY="vscode-variant";
26+
27+
exportconstVSCodeDevContainerButton:FC<VSCodeDevContainerButtonProps>=(
28+
props,
29+
)=>{
30+
const[isVariantMenuOpen,setIsVariantMenuOpen]=useState(false);
31+
constpreviousVariant=localStorage.getItem(VARIANT_KEY);
32+
const[variant,setVariant]=useState<VSCodeVariant>(()=>{
33+
if(!previousVariant){
34+
return"vscode";
35+
}
36+
returnpreviousVariantasVSCodeVariant;
37+
});
38+
constmenuAnchorRef=useRef<HTMLDivElement>(null);
39+
40+
constselectVariant=(variant:VSCodeVariant)=>{
41+
localStorage.setItem(VARIANT_KEY,variant);
42+
setVariant(variant);
43+
setIsVariantMenuOpen(false);
44+
};
45+
46+
constincludesVSCodeDesktop=props.displayApps.includes("vscode");
47+
constincludesVSCodeInsiders=props.displayApps.includes("vscode_insiders");
48+
49+
returnincludesVSCodeDesktop&&includesVSCodeInsiders ?(
50+
<div>
51+
<ButtonGroupref={menuAnchorRef}variant="outlined">
52+
{variant==="vscode" ?(
53+
<VSCodeButton{...props}/>
54+
) :(
55+
<VSCodeInsidersButton{...props}/>
56+
)}
57+
58+
<AgentButton
59+
aria-controls={
60+
isVariantMenuOpen ?"vscode-variant-button-menu" :undefined
61+
}
62+
aria-expanded={isVariantMenuOpen ?"true" :undefined}
63+
aria-label="select VSCode variant"
64+
aria-haspopup="menu"
65+
disableRipple
66+
onClick={()=>{
67+
setIsVariantMenuOpen(true);
68+
}}
69+
css={{paddingLeft:0,paddingRight:0}}
70+
>
71+
<KeyboardArrowDownIconcss={{fontSize:16}}/>
72+
</AgentButton>
73+
</ButtonGroup>
74+
75+
<Menu
76+
open={isVariantMenuOpen}
77+
anchorEl={menuAnchorRef.current}
78+
onClose={()=>setIsVariantMenuOpen(false)}
79+
css={{
80+
"& .MuiMenu-paper":{
81+
width:menuAnchorRef.current?.clientWidth,
82+
},
83+
}}
84+
>
85+
<MenuItem
86+
css={{fontSize:14}}
87+
onClick={()=>{
88+
selectVariant("vscode");
89+
}}
90+
>
91+
<VSCodeIconcss={{width:12,height:12}}/>
92+
{DisplayAppNameMap.vscode}
93+
</MenuItem>
94+
<MenuItem
95+
css={{fontSize:14}}
96+
onClick={()=>{
97+
selectVariant("vscode-insiders");
98+
}}
99+
>
100+
<VSCodeInsidersIconcss={{width:12,height:12}}/>
101+
{DisplayAppNameMap.vscode_insiders}
102+
</MenuItem>
103+
</Menu>
104+
</div>
105+
) :includesVSCodeDesktop ?(
106+
<VSCodeButton{...props}/>
107+
) :(
108+
<VSCodeInsidersButton{...props}/>
109+
);
110+
};
111+
112+
constVSCodeButton:FC<VSCodeDevContainerButtonProps>=({
113+
userName,
114+
workspaceName,
115+
agentName,
116+
folderPath,
117+
devContainerPath,
118+
devContainerFolder,
119+
})=>{
120+
const[loading,setLoading]=useState(false);
121+
122+
return(
123+
<AgentButton
124+
startIcon={<VSCodeIcon/>}
125+
disabled={loading}
126+
onClick={()=>{
127+
setLoading(true);
128+
API.getApiKey()
129+
.then(({ key})=>{
130+
constquery=newURLSearchParams({
131+
owner:userName,
132+
workspace:workspaceName,
133+
url:location.origin,
134+
token:key,
135+
devContainerPath,
136+
devContainerFolder,
137+
});
138+
if(agentName){
139+
query.set("agent",agentName);
140+
}
141+
if(folderPath){
142+
query.set("folder",folderPath);
143+
}
144+
145+
location.href=`vscode://coder.coder-remote/openDevContainer?${query.toString()}`;
146+
})
147+
.catch((ex)=>{
148+
console.error(ex);
149+
})
150+
.finally(()=>{
151+
setLoading(false);
152+
});
153+
}}
154+
>
155+
{DisplayAppNameMap.vscode}
156+
</AgentButton>
157+
);
158+
};
159+
160+
constVSCodeInsidersButton:FC<VSCodeDevContainerButtonProps>=({
161+
userName,
162+
workspaceName,
163+
agentName,
164+
folderPath,
165+
devContainerPath,
166+
devContainerFolder,
167+
})=>{
168+
const[loading,setLoading]=useState(false);
169+
170+
return(
171+
<AgentButton
172+
startIcon={<VSCodeInsidersIcon/>}
173+
disabled={loading}
174+
onClick={()=>{
175+
setLoading(true);
176+
API.getApiKey()
177+
.then(({ key})=>{
178+
constquery=newURLSearchParams({
179+
owner:userName,
180+
workspace:workspaceName,
181+
url:location.origin,
182+
token:key,
183+
devContainerPath,
184+
devContainerFolder,
185+
});
186+
if(agentName){
187+
query.set("agent",agentName);
188+
}
189+
if(folderPath){
190+
query.set("folder",folderPath);
191+
}
192+
193+
location.href=`vscode-insiders://coder.coder-remote/openDevContainer?${query.toString()}`;
194+
})
195+
.catch((ex)=>{
196+
console.error(ex);
197+
})
198+
.finally(()=>{
199+
setLoading(false);
200+
});
201+
}}
202+
>
203+
{DisplayAppNameMap.vscode_insiders}
204+
</AgentButton>
205+
);
206+
};

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp