Thanks to visit codestin.com
Credit goes to github.com

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 <[email protected]> * Add CODER_ENABLE_WILDCARD_APPS env var * Fix portforward link * Remove t file Co-authored-by: Presley Pizzo <[email protected]>
1 parent 9b5ee8f commit 0552c36

File tree

5 files changed

+168
-1
lines changed

5 files changed

+168
-1
lines changed
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+
}
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

+6
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

+2-1
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

+4
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)