Skip to content

Commit b1c2bf9

Browse files
committed
ui-1
1 parent eb65c72 commit b1c2bf9

File tree

7 files changed

+109
-66
lines changed

7 files changed

+109
-66
lines changed

agent/agentcontainers/api.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -656,13 +656,16 @@ func (api *API) getContainers() (codersdk.WorkspaceAgentListContainersResponse,
656656
return codersdk.WorkspaceAgentListContainersResponse{}, api.containersErr
657657
}
658658

659-
devcontainers := make([]codersdk.WorkspaceAgentDevcontainer, 0, len(api.knownDevcontainers))
660-
for _, dc := range api.knownDevcontainers {
661-
devcontainers = append(devcontainers, dc)
659+
var devcontainers []codersdk.WorkspaceAgentDevcontainer
660+
if len(api.knownDevcontainers) > 0 {
661+
devcontainers = make([]codersdk.WorkspaceAgentDevcontainer, 0, len(api.knownDevcontainers))
662+
for _, dc := range api.knownDevcontainers {
663+
devcontainers = append(devcontainers, dc)
664+
}
665+
slices.SortFunc(devcontainers, func(a, b codersdk.WorkspaceAgentDevcontainer) int {
666+
return strings.Compare(a.ID.String(), b.ID.String())
667+
})
662668
}
663-
slices.SortFunc(devcontainers, func(a, b codersdk.WorkspaceAgentDevcontainer) int {
664-
return strings.Compare(a.ID.String(), b.ID.String())
665-
})
666669

667670
return codersdk.WorkspaceAgentListContainersResponse{
668671
Devcontainers: devcontainers,

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

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,23 @@ import {
66
MockWorkspaceAgentContainerPorts,
77
} from "testHelpers/entities";
88
import { AgentDevcontainerCard } from "./AgentDevcontainerCard";
9+
import type { WorkspaceAgentDevcontainer } from "api/typesGenerated";
10+
11+
const MockWorkspaceAgentDevcontainer: WorkspaceAgentDevcontainer = {
12+
id: "test-devcontainer-id",
13+
name: "test-devcontainer",
14+
workspace_folder: "/workspace/test",
15+
config_path: "/workspace/test/.devcontainer/devcontainer.json",
16+
status: "running",
17+
dirty: false,
18+
container: MockWorkspaceAgentContainer,
19+
};
920

1021
const meta: Meta<typeof AgentDevcontainerCard> = {
1122
title: "modules/resources/AgentDevcontainerCard",
1223
component: AgentDevcontainerCard,
1324
args: {
14-
container: MockWorkspaceAgentContainer,
25+
devcontainer: MockWorkspaceAgentDevcontainer,
1526
workspace: MockWorkspace,
1627
wildcardHostname: "*.wildcard.hostname",
1728
agent: MockWorkspaceAgent,
@@ -25,30 +36,39 @@ export const NoPorts: Story = {};
2536

2637
export const WithPorts: Story = {
2738
args: {
28-
container: {
29-
...MockWorkspaceAgentContainer,
30-
ports: MockWorkspaceAgentContainerPorts,
39+
devcontainer: {
40+
...MockWorkspaceAgentDevcontainer,
41+
container: {
42+
...MockWorkspaceAgentContainer,
43+
ports: MockWorkspaceAgentContainerPorts,
44+
},
3145
},
3246
},
3347
};
3448

3549
export const Dirty: Story = {
3650
args: {
37-
container: {
38-
...MockWorkspaceAgentContainer,
39-
devcontainer_dirty: true,
40-
ports: MockWorkspaceAgentContainerPorts,
51+
devcontainer: {
52+
...MockWorkspaceAgentDevcontainer,
53+
dirty: true,
54+
container: {
55+
...MockWorkspaceAgentContainer,
56+
ports: MockWorkspaceAgentContainerPorts,
57+
},
4158
},
4259
},
4360
};
4461

4562
export const Recreating: Story = {
4663
args: {
47-
container: {
48-
...MockWorkspaceAgentContainer,
49-
devcontainer_dirty: true,
50-
devcontainer_status: "starting",
51-
ports: MockWorkspaceAgentContainerPorts,
64+
devcontainer: {
65+
...MockWorkspaceAgentDevcontainer,
66+
dirty: true,
67+
status: "starting",
68+
container: {
69+
...MockWorkspaceAgentContainer,
70+
ports: MockWorkspaceAgentContainerPorts,
71+
},
5272
},
5373
},
5474
};

site/src/modules/resources/AgentDevcontainerCard.tsx

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type {
22
Workspace,
33
WorkspaceAgent,
4-
WorkspaceAgentContainer,
4+
WorkspaceAgentDevcontainer,
55
} from "api/typesGenerated";
66
import { Button } from "components/Button/Button";
77
import { displayError } from "components/GlobalSnackbar/utils";
@@ -24,33 +24,34 @@ import type { FC } from "react";
2424
import { useEffect, useState } from "react";
2525
import { portForwardURL } from "utils/portForward";
2626
import { AgentButton } from "./AgentButton";
27-
import { AgentDevcontainerSSHButton } from "./SSHButton/SSHButton";
27+
import {
28+
AgentDevcontainerSSHButton,
29+
AgentSSHButton,
30+
} from "./SSHButton/SSHButton";
2831
import { TerminalLink } from "./TerminalLink/TerminalLink";
2932
import { VSCodeDevContainerButton } from "./VSCodeDevContainerButton/VSCodeDevContainerButton";
3033

3134
type AgentDevcontainerCardProps = {
3235
agent: WorkspaceAgent;
33-
container: WorkspaceAgentContainer;
36+
devcontainer: WorkspaceAgentDevcontainer;
3437
workspace: Workspace;
3538
wildcardHostname: string;
3639
};
3740

3841
export const AgentDevcontainerCard: FC<AgentDevcontainerCardProps> = ({
3942
agent,
40-
container,
43+
devcontainer,
4144
workspace,
4245
wildcardHostname,
4346
}) => {
44-
const folderPath = container.labels["devcontainer.local_folder"];
45-
const containerFolder = container.volumes[folderPath];
4647
const [isRecreating, setIsRecreating] = useState(false);
4748

4849
const handleRecreateDevcontainer = async () => {
4950
setIsRecreating(true);
5051
let recreateSucceeded = false;
5152
try {
5253
const response = await fetch(
53-
`/api/v2/workspaceagents/${agent.id}/containers/devcontainers/container/${container.id}/recreate`,
54+
`/api/v2/workspaceagents/${agent.id}/containers/devcontainers/container/${devcontainer.container?.id}/recreate`,
5455
{
5556
method: "POST",
5657
},
@@ -79,27 +80,35 @@ export const AgentDevcontainerCard: FC<AgentDevcontainerCardProps> = ({
7980
}
8081
};
8182

82-
// If the container is starting, reflect this in the recreate button.
83+
// If the devcontainer is starting, reflect this in the recreate button.
8384
useEffect(() => {
84-
if (container.devcontainer_status === "starting") {
85+
if (devcontainer.status === "starting") {
8586
setIsRecreating(true);
8687
} else {
8788
setIsRecreating(false);
8889
}
89-
}, [container.devcontainer_status]);
90+
}, [devcontainer.status]);
9091

9192
return (
9293
<section
9394
className="border border-border border-dashed rounded p-6 "
94-
key={container.id}
95+
key={devcontainer.id}
9596
>
9697
<header className="flex justify-between items-center mb-4">
9798
<div className="flex items-center gap-2">
9899
<h3 className="m-0 text-xs font-medium text-content-secondary">
99100
dev container:{" "}
100-
<span className="font-semibold">{container.name}</span>
101+
<span className="font-semibold">
102+
{devcontainer.name}
103+
{devcontainer.container && (
104+
<span className="text-content-tertiary">
105+
{" "}
106+
({devcontainer.container.name})
107+
</span>
108+
)}
109+
</span>
101110
</h3>
102-
{container.devcontainer_dirty && (
111+
{devcontainer.dirty && (
103112
<HelpTooltip>
104113
<HelpTooltipTrigger className="flex items-center text-xs text-content-warning ml-2">
105114
<span>Outdated</span>
@@ -126,10 +135,17 @@ export const AgentDevcontainerCard: FC<AgentDevcontainerCardProps> = ({
126135
Recreate
127136
</Button>
128137

129-
<AgentDevcontainerSSHButton
138+
{/* <AgentDevcontainerSSHButton
130139
workspace={workspace.name}
131-
container={container.name}
132-
/>
140+
container={devcontainer.container?.name || devcontainer.name}
141+
/> */}
142+
{agent.display_apps.includes("ssh_helper") && ( // TODO agent
143+
<AgentSSHButton
144+
workspaceName={workspace.name}
145+
agentName={devcontainer.name}
146+
workspaceOwnerUsername={workspace.owner_name}
147+
/>
148+
)}
133149
</div>
134150
</header>
135151

@@ -139,20 +155,19 @@ export const AgentDevcontainerCard: FC<AgentDevcontainerCardProps> = ({
139155
<VSCodeDevContainerButton
140156
userName={workspace.owner_name}
141157
workspaceName={workspace.name}
142-
devContainerName={container.name}
143-
devContainerFolder={containerFolder}
144-
displayApps={agent.display_apps}
145-
agentName={agent.name}
158+
devContainerName={devcontainer.name}
159+
devContainerFolder={devcontainer.workspace_folder}
160+
displayApps={agent.display_apps} // TODO agent
161+
agentName={devcontainer.name}
146162
/>
147163

148164
<TerminalLink
149165
workspaceName={workspace.name}
150-
agentName={agent.name}
151-
containerName={container.name}
166+
agentName={devcontainer.name}
152167
userName={workspace.owner_name}
153168
/>
154169
{wildcardHostname !== "" &&
155-
container.ports.map((port) => {
170+
devcontainer.container?.ports.map((port) => {
156171
const portLabel = `${port.port}/${port.network.toUpperCase()}`;
157172
const hasHostBind =
158173
port.host_port !== undefined && port.host_ip !== undefined;

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,17 @@ export const GroupApp: Story = {
288288
export const Devcontainer: Story = {
289289
beforeEach: () => {
290290
spyOn(API, "getAgentContainers").mockResolvedValue({
291+
devcontainers: [
292+
{
293+
id: "test-devcontainer-id",
294+
name: "test-devcontainer",
295+
workspace_folder: "/workspace/test",
296+
config_path: "/workspace/test/.devcontainer/devcontainer.json",
297+
status: "running",
298+
dirty: false,
299+
container: M.MockWorkspaceAgentContainer,
300+
},
301+
],
291302
containers: [M.MockWorkspaceAgentContainer],
292303
});
293304
},

site/src/modules/resources/AgentRow.tsx

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -140,16 +140,11 @@ export const AgentRow: FC<AgentRowProps> = ({
140140
setBottomOfLogs(distanceFromBottom < AGENT_LOG_LINE_HEIGHT);
141141
}, []);
142142

143-
const { data: containers } = useQuery({
143+
const { data: devcontainers } = useQuery({
144144
queryKey: ["agents", agent.id, "containers"],
145-
queryFn: () =>
146-
// Only return devcontainers
147-
API.getAgentContainers(agent.id, [
148-
"devcontainer.config_file=",
149-
"devcontainer.local_folder=",
150-
]),
145+
queryFn: () => API.getAgentContainers(agent.id),
151146
enabled: agent.status === "connected",
152-
select: (res) => res.containers.filter((c) => c.status === "running"),
147+
select: (res) => res.devcontainers,
153148
// TODO: Implement a websocket connection to get updates on containers
154149
// without having to poll.
155150
refetchInterval: ({ state }) => {
@@ -164,7 +159,7 @@ export const AgentRow: FC<AgentRowProps> = ({
164159
const [showParentApps, setShowParentApps] = useState(false);
165160

166161
let shouldDisplayAppsSection = shouldDisplayAgentApps;
167-
if (containers && containers.length > 0 && !showParentApps) {
162+
if (devcontainers && devcontainers.length > 0 && !showParentApps) {
168163
shouldDisplayAppsSection = false;
169164
}
170165

@@ -200,7 +195,7 @@ export const AgentRow: FC<AgentRowProps> = ({
200195
</div>
201196

202197
<div className="flex items-center gap-2">
203-
{containers && containers.length > 0 && (
198+
{devcontainers && devcontainers.length > 0 && (
204199
<Button
205200
variant="outline"
206201
size="sm"
@@ -289,13 +284,13 @@ export const AgentRow: FC<AgentRowProps> = ({
289284
</section>
290285
)}
291286

292-
{containers && containers.length > 0 && (
287+
{devcontainers && devcontainers.length > 0 && (
293288
<section className="flex flex-col gap-4">
294-
{containers.map((container) => {
289+
{devcontainers.map((devcontainer) => {
295290
return (
296291
<AgentDevcontainerCard
297-
key={container.id}
298-
container={container}
292+
key={devcontainer.id}
293+
devcontainer={devcontainer}
299294
workspace={workspace}
300295
wildcardHostname={proxy.preferredWildcardHostname}
301296
agent={agent}

site/src/modules/resources/SSHButton/SSHButton.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,12 @@ export const AgentSSHButton: FC<AgentSSHButtonProps> = ({
8787

8888
interface AgentDevcontainerSSHButtonProps {
8989
workspace: string;
90-
container: string;
90+
agentName: string;
9191
}
9292

9393
export const AgentDevcontainerSSHButton: FC<
9494
AgentDevcontainerSSHButtonProps
95-
> = ({ workspace, container }) => {
95+
> = ({ workspace, agentName }) => {
9696
const paper = useClassName(classNames.paper, []);
9797

9898
return (
@@ -116,8 +116,8 @@ export const AgentDevcontainerSSHButton: FC<
116116
<ol style={{ margin: 0, padding: 0 }}>
117117
<Stack spacing={0.5} css={styles.codeExamples}>
118118
<SSHStep
119-
helpText="Connect to the container:"
120-
codeExample={`coder ssh ${workspace} -c ${container}`}
119+
helpText="Connect to the dev container:"
120+
codeExample={`coder ssh ${workspace}.${agentName}`}
121121
/>
122122
</Stack>
123123
</ol>
@@ -151,11 +151,11 @@ const SSHStep: FC<SSHStepProps> = ({ helpText, codeExample }) => (
151151

152152
const classNames = {
153153
paper: (css, theme) => css`
154-
padding: 16px 24px 24px;
155-
width: 304px;
156-
color: ${theme.palette.text.secondary};
157-
margin-top: 2px;
158-
`,
154+
padding: 16px 24px 24px;
155+
width: 304px;
156+
color: ${theme.palette.text.secondary};
157+
margin-top: 2px;
158+
`,
159159
} satisfies Record<string, ClassName>;
160160

161161
const styles = {

site/src/testHelpers/entities.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4390,7 +4390,6 @@ export const MockWorkspaceAgentContainer: TypesGen.WorkspaceAgentContainer = {
43904390
volumes: {
43914391
"/mnt/volume1": "/volume1",
43924392
},
4393-
devcontainer_dirty: false,
43944393
};
43954394

43964395
export const MockWorkspaceAppStatuses: TypesGen.WorkspaceAppStatus[] = [

0 commit comments

Comments
 (0)