Skip to content

Commit 0552c36

Browse files
feat: Add portforward to the UI (#3812)
* feat: Add portforward to the UI * Update site/src/components/PortForwardButton/PortForwardButton.tsx Co-authored-by: Presley Pizzo <1290996+presleyp@users.noreply.github.com> * Add CODER_ENABLE_WILDCARD_APPS env var * Fix portforward link * Remove t file Co-authored-by: Presley Pizzo <1290996+presleyp@users.noreply.github.com>
1 parent 9b5ee8f commit 0552c36

File tree

5 files changed

+168
-1
lines changed

5 files changed

+168
-1
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { Story } from "@storybook/react"
2+
import { MockWorkspace, MockWorkspaceAgent } from "../../testHelpers/renderHelpers"
3+
import { PortForwardButton, PortForwardButtonProps } from "./PortForwardButton"
4+
5+
export default {
6+
title: "components/PortForwardButton",
7+
component: PortForwardButton,
8+
}
9+
10+
const Template: Story<PortForwardButtonProps> = (args) => <PortForwardButton {...args} />
11+
12+
export const Closed = Template.bind({})
13+
Closed.args = {
14+
username: MockWorkspace.owner_name,
15+
workspaceName: MockWorkspace.name,
16+
agentName: MockWorkspaceAgent.name,
17+
}
18+
19+
export const Opened = Template.bind({})
20+
Opened.args = {
21+
username: MockWorkspace.owner_name,
22+
workspaceName: MockWorkspace.name,
23+
agentName: MockWorkspaceAgent.name,
24+
defaultIsOpen: true,
25+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import Button from "@material-ui/core/Button"
2+
import Link from "@material-ui/core/Link"
3+
import Popover from "@material-ui/core/Popover"
4+
import { makeStyles } from "@material-ui/core/styles"
5+
import TextField from "@material-ui/core/TextField"
6+
import OpenInNewOutlined from "@material-ui/icons/OpenInNewOutlined"
7+
import { Stack } from "components/Stack/Stack"
8+
import { useRef, useState } from "react"
9+
import { colors } from "theme/colors"
10+
import { CodeExample } from "../CodeExample/CodeExample"
11+
import { HelpTooltipLink, HelpTooltipLinksGroup, HelpTooltipText } from "../Tooltips/HelpTooltip"
12+
13+
export interface PortForwardButtonProps {
14+
username: string
15+
workspaceName: string
16+
agentName: string
17+
defaultIsOpen?: boolean
18+
}
19+
20+
export const PortForwardButton: React.FC<React.PropsWithChildren<PortForwardButtonProps>> = ({
21+
workspaceName,
22+
agentName,
23+
username,
24+
defaultIsOpen = false,
25+
}) => {
26+
const anchorRef = useRef<HTMLButtonElement>(null)
27+
const [isOpen, setIsOpen] = useState(defaultIsOpen)
28+
const id = isOpen ? "schedule-popover" : undefined
29+
const styles = useStyles()
30+
const [port, setPort] = useState("3000")
31+
const { location } = window
32+
const urlExample =
33+
process.env.CODER_ENABLE_WILDCARD_APPS === "true"
34+
? `${location.protocol}//${port}--${agentName}--${workspaceName}--${username}.${location.host}`
35+
: `${location.protocol}//${location.host}/@${username}/${workspaceName}.${agentName}/apps/${port}`
36+
37+
const onClose = () => {
38+
setIsOpen(false)
39+
}
40+
41+
return (
42+
<>
43+
<Button
44+
startIcon={<OpenInNewOutlined />}
45+
size="small"
46+
ref={anchorRef}
47+
onClick={() => {
48+
setIsOpen(true)
49+
}}
50+
>
51+
Port forward
52+
</Button>
53+
<Popover
54+
classes={{ paper: styles.popoverPaper }}
55+
id={id}
56+
open={isOpen}
57+
anchorEl={anchorRef.current}
58+
onClose={onClose}
59+
anchorOrigin={{
60+
vertical: "bottom",
61+
horizontal: "left",
62+
}}
63+
transformOrigin={{
64+
vertical: "top",
65+
horizontal: "left",
66+
}}
67+
>
68+
<Stack direction="column" spacing={1}>
69+
<HelpTooltipText>
70+
You can port forward this resource by typing the{" "}
71+
<strong>port, workspace name, agent name</strong> and <strong>your username</strong> in
72+
the URL like the example below
73+
</HelpTooltipText>
74+
75+
<CodeExample code={urlExample} />
76+
77+
<HelpTooltipText>
78+
Or you can use the following form to open it in a new tab.
79+
</HelpTooltipText>
80+
81+
<Stack direction="row" spacing={1} alignItems="center">
82+
<TextField
83+
label="Port"
84+
type="number"
85+
value={port}
86+
className={styles.portField}
87+
onChange={(e) => {
88+
setPort(e.currentTarget.value)
89+
}}
90+
/>
91+
<Link
92+
underline="none"
93+
href={urlExample}
94+
target="_blank"
95+
rel="noreferrer"
96+
className={styles.openUrlButton}
97+
>
98+
<Button>Open URL</Button>
99+
</Link>
100+
</Stack>
101+
102+
<HelpTooltipLinksGroup>
103+
<HelpTooltipLink href="https://coder.com/docs/coder-oss/latest/port-forward">
104+
Port forward
105+
</HelpTooltipLink>
106+
</HelpTooltipLinksGroup>
107+
</Stack>
108+
</Popover>
109+
</>
110+
)
111+
}
112+
113+
const useStyles = makeStyles((theme) => ({
114+
popoverPaper: {
115+
padding: `${theme.spacing(2.5)}px ${theme.spacing(3.5)}px ${theme.spacing(3.5)}px`,
116+
width: theme.spacing(46),
117+
color: theme.palette.text.secondary,
118+
marginTop: theme.spacing(0.25),
119+
},
120+
121+
openUrlButton: {
122+
flexShrink: 0,
123+
},
124+
125+
portField: {
126+
// The default border don't contrast well with the popover
127+
"& .MuiOutlinedInput-root .MuiOutlinedInput-notchedOutline": {
128+
borderColor: colors.gray[10],
129+
},
130+
},
131+
}))

site/src/components/Resources/Resources.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { Skeleton } from "@material-ui/lab"
1010
import useTheme from "@material-ui/styles/useTheme"
1111
import { CloseDropdown, OpenDropdown } from "components/DropdownArrows/DropdownArrows"
1212
import { ErrorSummary } from "components/ErrorSummary/ErrorSummary"
13+
import { PortForwardButton } from "components/PortForwardButton/PortForwardButton"
1314
import { TableCellDataPrimary } from "components/TableCellData/TableCellData"
1415
import { FC, useState } from "react"
1516
import { getDisplayAgentStatus, getDisplayVersionStatus } from "util/workspace"
@@ -150,6 +151,11 @@ export const Resources: FC<React.PropsWithChildren<ResourcesProps>> = ({
150151
{canUpdateWorkspace && agent.status === "connected" && (
151152
<>
152153
<SSHButton workspaceName={workspace.name} agentName={agent.name} />
154+
<PortForwardButton
155+
username={workspace.owner_name}
156+
workspaceName={workspace.name}
157+
agentName={agent.name}
158+
/>
153159
<TerminalLink
154160
workspaceName={workspace.name}
155161
agentName={agent.name}

site/src/components/Tooltips/HelpTooltip/HelpTooltip.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,9 @@ const useStyles = makeStyles((theme) => ({
226226
},
227227

228228
link: {
229-
display: "flex",
229+
display: "inline-flex",
230230
alignItems: "center",
231+
width: "fit-content",
231232
},
232233

233234
linkIcon: {

site/webpack.common.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@ import { Configuration, EnvironmentPlugin } from "webpack"
1414
const environmentPlugin = new EnvironmentPlugin({
1515
INSPECT_XSTATE: "",
1616
CODER_VERSION: "main",
17+
CODER_ENABLE_WILDCARD_APPS: "",
1718
})
1819
console.info(`--- Setting INSPECT_XSTATE to '${process.env.INSPECT_XSTATE || ""}'`)
1920
console.info(`--- Setting CODER_VERSION to '${process.env.CODER_VERSION || "main"}'`)
21+
console.info(
22+
`--- Setting CODER_ENABLE_WILDCARD_APPS to '${process.env.CODER_ENABLE_WILDCARD_APPS ?? ""}'`,
23+
)
2024
console.info(`--- Setting NODE_ENV to '${process.env.NODE_ENV || ""}'`)
2125

2226
/**

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy