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

Commit17712b2

Browse files
committed
feat(site): allow recreating devcontainers and showing dirty status
This change allows showing the devcontainer dirty status in the UI aswell as a recreate button to update the devcontainer.Closes#16424
1 parentafaa20e commit17712b2

File tree

6 files changed

+111
-23
lines changed

6 files changed

+111
-23
lines changed

‎agent/agent_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2226,7 +2226,7 @@ func TestAgent_DevcontainerRecreate(t *testing.T) {
22262226
// devcontainer, we do it in a goroutine so we can process logs
22272227
// concurrently.
22282228
gofunc(container codersdk.WorkspaceAgentContainer) {
2229-
err:=conn.RecreateDevcontainer(ctx,container.ID)
2229+
_,err:=conn.RecreateDevcontainer(ctx,container.ID)
22302230
assert.NoError(t,err,"recreate devcontainer should succeed")
22312231
}(container)
22322232

‎coderd/workspaceagents.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,7 @@ func (api *API) workspaceAgentRecreateDevcontainer(rw http.ResponseWriter, r *ht
956956
}
957957
deferrelease()
958958

959-
err=agentConn.RecreateDevcontainer(ctx,container)
959+
m,err:=agentConn.RecreateDevcontainer(ctx,container)
960960
iferr!=nil {
961961
iferrors.Is(err,context.Canceled) {
962962
httpapi.Write(ctx,rw,http.StatusRequestTimeout, codersdk.Response{
@@ -977,7 +977,7 @@ func (api *API) workspaceAgentRecreateDevcontainer(rw http.ResponseWriter, r *ht
977977
return
978978
}
979979

980-
httpapi.Write(ctx,rw,http.StatusNoContent,nil)
980+
httpapi.Write(ctx,rw,http.StatusAccepted,m)
981981
}
982982

983983
// @Summary Get connection info for workspace agent

‎coderd/workspaceagents_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1483,7 +1483,7 @@ func TestWorkspaceAgentRecreateDevcontainer(t *testing.T) {
14831483

14841484
ctx:=testutil.Context(t,testutil.WaitLong)
14851485

1486-
err:=client.WorkspaceAgentRecreateDevcontainer(ctx,agentID,devContainer.ID)
1486+
_,err:=client.WorkspaceAgentRecreateDevcontainer(ctx,agentID,devContainer.ID)
14871487
ifwantStatus>0 {
14881488
cerr,ok:=codersdk.AsError(err)
14891489
require.True(t,ok,"expected error to be a coder error")

‎codersdk/workspaceagents.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -518,16 +518,20 @@ func (c *Client) WorkspaceAgentListContainers(ctx context.Context, agentID uuid.
518518
}
519519

520520
// WorkspaceAgentRecreateDevcontainer recreates the devcontainer with the given ID.
521-
func (c*Client)WorkspaceAgentRecreateDevcontainer(ctx context.Context,agentID uuid.UUID,containerIDOrNamestring)error {
521+
func (c*Client)WorkspaceAgentRecreateDevcontainer(ctx context.Context,agentID uuid.UUID,containerIDOrNamestring)(Response,error) {
522522
res,err:=c.Request(ctx,http.MethodPost,fmt.Sprintf("/api/v2/workspaceagents/%s/containers/devcontainers/container/%s/recreate",agentID,containerIDOrName),nil)
523523
iferr!=nil {
524-
returnerr
524+
returnResponse{},err
525525
}
526526
deferres.Body.Close()
527-
ifres.StatusCode!=http.StatusNoContent {
528-
returnReadBodyAsError(res)
527+
ifres.StatusCode!=http.StatusAccepted {
528+
returnResponse{},ReadBodyAsError(res)
529529
}
530-
returnnil
530+
varmResponse
531+
iferr:=json.NewDecoder(res.Body).Decode(&m);err!=nil {
532+
returnResponse{},xerrors.Errorf("decode response body: %w",err)
533+
}
534+
returnm,nil
531535
}
532536

533537
//nolint:revive // Follow is a control flag on the server as well.

‎codersdk/workspacesdk/agentconn.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -389,18 +389,22 @@ func (c *AgentConn) ListContainers(ctx context.Context) (codersdk.WorkspaceAgent
389389

390390
// RecreateDevcontainer recreates a devcontainer with the given container.
391391
// This is a blocking call and will wait for the container to be recreated.
392-
func (c*AgentConn)RecreateDevcontainer(ctx context.Context,containerIDOrNamestring)error {
392+
func (c*AgentConn)RecreateDevcontainer(ctx context.Context,containerIDOrNamestring)(codersdk.Response,error) {
393393
ctx,span:=tracing.StartSpan(ctx)
394394
deferspan.End()
395395
res,err:=c.apiRequest(ctx,http.MethodPost,"/api/v0/containers/devcontainers/container/"+containerIDOrName+"/recreate",nil)
396396
iferr!=nil {
397-
returnxerrors.Errorf("do request: %w",err)
397+
returncodersdk.Response{},xerrors.Errorf("do request: %w",err)
398398
}
399399
deferres.Body.Close()
400400
ifres.StatusCode!=http.StatusAccepted {
401-
returncodersdk.ReadBodyAsError(res)
401+
return codersdk.Response{},codersdk.ReadBodyAsError(res)
402402
}
403-
returnnil
403+
varm codersdk.Response
404+
iferr:=json.NewDecoder(res.Body).Decode(&m);err!=nil {
405+
return codersdk.Response{},xerrors.Errorf("decode response body: %w",err)
406+
}
407+
returnm,nil
404408
}
405409

406410
// apiRequest makes a request to the workspace agent's HTTP API server.

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

Lines changed: 90 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,24 @@ import type {
33
WorkspaceAgent,
44
WorkspaceAgentContainer,
55
}from"api/typesGenerated";
6+
import{Button}from"components/Button/Button";
7+
import{displayError}from"components/GlobalSnackbar/utils";
8+
import{
9+
HelpTooltip,
10+
HelpTooltipContent,
11+
HelpTooltipText,
12+
HelpTooltipTitle,
13+
HelpTooltipTrigger,
14+
}from"components/HelpTooltip/HelpTooltip";
615
import{
716
Tooltip,
817
TooltipContent,
918
TooltipProvider,
1019
TooltipTrigger,
1120
}from"components/Tooltip/Tooltip";
12-
import{ExternalLinkIcon}from"lucide-react";
21+
import{ExternalLinkIcon,Loader2Icon}from"lucide-react";
1322
importtype{FC}from"react";
23+
import{useState}from"react";
1424
import{portForwardURL}from"utils/portForward";
1525
import{AgentButton}from"./AgentButton";
1626
import{AgentDevcontainerSSHButton}from"./SSHButton/SSHButton";
@@ -32,24 +42,94 @@ export const AgentDevcontainerCard: FC<AgentDevcontainerCardProps> = ({
3242
})=>{
3343
constfolderPath=container.labels["devcontainer.local_folder"];
3444
constcontainerFolder=container.volumes[folderPath];
45+
const[isRecreating,setIsRecreating]=useState(false);
46+
47+
consthandleRecreateDevcontainer=async()=>{
48+
setIsRecreating(true);
49+
letrecreateSucceeded=false;
50+
try{
51+
constresponse=awaitfetch(
52+
`/api/v2/workspaceagents/${agent.id}/containers/devcontainers/container/${container.id}/recreate`,
53+
{
54+
method:"POST",
55+
},
56+
);
57+
if(!response.ok){
58+
consterrorData=awaitresponse.json().catch(()=>({}));
59+
thrownewError(
60+
errorData.message||`Failed to recreate:${response.statusText}`,
61+
);
62+
}
63+
// If the request was accepted (e.g. 202), we mark it as succeeded.
64+
// Once complete, the component will unmount, so the spinner will
65+
// disappear with it.
66+
if(response.status===202){
67+
recreateSucceeded=true;
68+
}
69+
}catch(error){
70+
consterrorMessage=
71+
errorinstanceofError ?error.message :"An unknown error occurred.";
72+
displayError(`Failed to recreate devcontainer:${errorMessage}`);
73+
console.error("Failed to recreate devcontainer:",error);
74+
}finally{
75+
if(!recreateSucceeded){
76+
setIsRecreating(false);
77+
}
78+
}
79+
};
3580

3681
return(
3782
<section
3883
className="border border-border border-dashed rounded p-6 "
3984
key={container.id}
4085
>
41-
<headerclassName="flex justify-between">
42-
<h3className="m-0 text-xs font-medium text-content-secondary">
43-
{container.name}
44-
</h3>
86+
<headerclassName="flex justify-between items-center mb-4">
87+
<divclassName="flex items-center gap-2">
88+
<h3className="m-0 text-xs font-medium text-content-secondary">
89+
{container.name}
90+
</h3>
91+
{container.devcontainer_dirty&&(
92+
<HelpTooltip>
93+
<HelpTooltipTriggerclassName="flex items-center text-xs text-warning-foreground ml-2">
94+
<span>Outdated</span>
95+
</HelpTooltipTrigger>
96+
<HelpTooltipContent>
97+
<HelpTooltipTitle>Devcontainer Outdated</HelpTooltipTitle>
98+
<HelpTooltipText>
99+
Devcontainer configuration has been modified and is outdated.
100+
Recreate to get an up-to-date container.
101+
</HelpTooltipText>
102+
</HelpTooltipContent>
103+
</HelpTooltip>
104+
)}
105+
</div>
45106

46-
<AgentDevcontainerSSHButton
47-
workspace={workspace.name}
48-
container={container.name}
49-
/>
107+
<divclassName="flex items-center gap-2">
108+
<Button
109+
variant="outline"
110+
size="sm"
111+
className="text-xs font-medium"
112+
onClick={handleRecreateDevcontainer}
113+
disabled={isRecreating}
114+
>
115+
{isRecreating ?(
116+
<>
117+
<Loader2IconclassName="mr-2 h-4 w-4 animate-spin"/>
118+
Recreating...
119+
</>
120+
) :(
121+
"Recreate"
122+
)}
123+
</Button>
124+
125+
<AgentDevcontainerSSHButton
126+
workspace={workspace.name}
127+
container={container.name}
128+
/>
129+
</div>
50130
</header>
51131

52-
<h4className="m-0 text-xl font-semibold">Forwarded ports</h4>
132+
<h4className="m-0 text-xl font-semibold mb-2">Forwarded ports</h4>
53133

54134
<divclassName="flex gap-4 flex-wrap mt-4">
55135
<VSCodeDevContainerButton

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp