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

Commita2429a7

Browse files
committed
feat: hook up port dropdown to workspace page
1 parentec8162a commita2429a7

File tree

4 files changed

+197
-11
lines changed

4 files changed

+197
-11
lines changed

‎site/src/components/Resources/Resources.tsx

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
1+
importButtonfrom"@material-ui/core/Button"
12
import{makeStyles,Theme}from"@material-ui/core/styles"
23
importTablefrom"@material-ui/core/Table"
34
importTableBodyfrom"@material-ui/core/TableBody"
45
importTableCellfrom"@material-ui/core/TableCell"
56
importTableHeadfrom"@material-ui/core/TableHead"
67
importTableRowfrom"@material-ui/core/TableRow"
8+
importCompareArrowsIconfrom"@material-ui/icons/CompareArrows"
79
importuseThemefrom"@material-ui/styles/useTheme"
810
importReactfrom"react"
9-
import{Workspace,WorkspaceResource}from"../../api/typesGenerated"
11+
import{Workspace,WorkspaceAgent,WorkspaceResource}from"../../api/typesGenerated"
1012
import{getDisplayAgentStatus}from"../../util/workspace"
1113
import{TableHeaderRow}from"../TableHeaders/TableHeaders"
1214
import{TerminalLink}from"../TerminalLink/TerminalLink"
1315
import{WorkspaceSection}from"../WorkspaceSection/WorkspaceSection"
1416

1517
constLanguage={
18+
portForwardLabel:"Port forward",
1619
resources:"Resources",
1720
resourceLabel:"Resource",
1821
agentsLabel:"Agents",
@@ -22,12 +25,18 @@ const Language = {
2225
}
2326

2427
interfaceResourcesProps{
28+
handleOpenPortForward:(agent:WorkspaceAgent,anchorEl:HTMLElement)=>void
2529
resources?:WorkspaceResource[]
2630
getResourcesError?:Error
2731
workspace:Workspace
2832
}
2933

30-
exportconstResources:React.FC<ResourcesProps>=({ resources, getResourcesError, workspace})=>{
34+
exportconstResources:React.FC<ResourcesProps>=({
35+
handleOpenPortForward,
36+
resources,
37+
getResourcesError,
38+
workspace,
39+
})=>{
3140
conststyles=useStyles()
3241
consttheme:Theme=useTheme()
3342

@@ -89,12 +98,22 @@ export const Resources: React.FC<ResourcesProps> = ({ resources, getResourcesErr
8998
</TableCell>
9099
<TableCell>
91100
{agent.status==="connected"&&(
92-
<TerminalLink
93-
className={styles.accessLink}
94-
workspaceName={workspace.name}
95-
agentName={agent.name}
96-
userName={workspace.owner_name}
97-
/>
101+
<>
102+
<TerminalLink
103+
className={styles.accessLink}
104+
workspaceName={workspace.name}
105+
agentName={agent.name}
106+
userName={workspace.owner_name}
107+
/>
108+
<Button
109+
variant="text"
110+
className={styles.accessLink}
111+
onClick={(event)=>handleOpenPortForward(agent,event.currentTarget)}
112+
>
113+
<CompareArrowsIcon/>
114+
{Language.portForwardLabel}
115+
</Button>
116+
</>
98117
)}
99118
</TableCell>
100119
</TableRow>
@@ -134,9 +153,16 @@ const useStyles = makeStyles((theme) => ({
134153
},
135154

136155
accessLink:{
156+
alignItems:"center",
137157
color:theme.palette.text.secondary,
138158
display:"flex",
139-
alignItems:"center",
159+
border:0,
160+
padding:0,
161+
162+
"&:hover":{
163+
backgroundColor:"unset",
164+
textDecoration:"underline",
165+
},
140166

141167
"& svg":{
142168
width:16,

‎site/src/components/Workspace/Workspace.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface WorkspaceProps {
1616
handleStop:()=>void
1717
handleUpdate:()=>void
1818
handleCancel:()=>void
19+
handleOpenPortForward:(agent:TypesGen.WorkspaceAgent,anchorEl:HTMLElement)=>void
1920
workspace:TypesGen.Workspace
2021
resources?:TypesGen.WorkspaceResource[]
2122
getResourcesError?:Error
@@ -30,6 +31,7 @@ export const Workspace: React.FC<WorkspaceProps> = ({
3031
handleStop,
3132
handleUpdate,
3233
handleCancel,
34+
handleOpenPortForward,
3335
workspace,
3436
resources,
3537
getResourcesError,
@@ -64,7 +66,12 @@ export const Workspace: React.FC<WorkspaceProps> = ({
6466
<Stackdirection="row"spacing={3}className={styles.layout}>
6567
<Stackspacing={3}className={styles.main}>
6668
<WorkspaceStatsworkspace={workspace}/>
67-
<Resourcesresources={resources}getResourcesError={getResourcesError}workspace={workspace}/>
69+
<Resources
70+
handleOpenPortForward={handleOpenPortForward}
71+
resources={resources}
72+
getResourcesError={getResourcesError}
73+
workspace={workspace}
74+
/>
6875
<WorkspaceSectiontitle="Timeline"contentsProps={{className:styles.timelineContents}}>
6976
<BuildsTablebuilds={builds}className={styles.timelineTable}/>
7077
</WorkspaceSection>

‎site/src/pages/WorkspacePage/WorkspacePage.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import{useMachine}from"@xstate/react"
2-
importReact,{useEffect}from"react"
2+
importReact,{useEffect,useState}from"react"
33
import{useParams}from"react-router-dom"
44
import{ErrorSummary}from"../../components/ErrorSummary/ErrorSummary"
55
import{FullScreenLoader}from"../../components/Loader/FullScreenLoader"
66
import{Margins}from"../../components/Margins/Margins"
7+
import{PortForwardDropdown}from"../../components/PortForwardDropdown/PortForwardDropdown"
78
import{Stack}from"../../components/Stack/Stack"
89
import{Workspace}from"../../components/Workspace/Workspace"
910
import{firstOrItem}from"../../util/array"
11+
import{agentMachine}from"../../xServices/agent/agentXService"
1012
import{workspaceMachine}from"../../xServices/workspace/workspaceXService"
1113

1214
exportconstWorkspacePage:React.FC=()=>{
@@ -16,6 +18,10 @@ export const WorkspacePage: React.FC = () => {
1618
const[workspaceState,workspaceSend]=useMachine(workspaceMachine)
1719
const{ workspace, resources, getWorkspaceError, getResourcesError, builds}=workspaceState.context
1820

21+
const[agentState,agentSend]=useMachine(agentMachine)
22+
const{ netstat}=agentState.context
23+
const[portForwardAnchorEl,setPortForwardAnchorEl]=useState<HTMLElement>()
24+
1925
/**
2026
* Get workspace, template, and organization on mount and whenever workspaceId changes.
2127
* workspaceSend should not change.
@@ -38,10 +44,24 @@ export const WorkspacePage: React.FC = () => {
3844
handleStop={()=>workspaceSend("STOP")}
3945
handleUpdate={()=>workspaceSend("UPDATE")}
4046
handleCancel={()=>workspaceSend("CANCEL")}
47+
handleOpenPortForward={(agent,anchorEl)=>{
48+
agentSend("CONNECT",{agentId:agent.id})
49+
setPortForwardAnchorEl(anchorEl)
50+
}}
4151
resources={resources}
4252
getResourcesError={getResourcesErrorinstanceofError ?getResourcesError :undefined}
4353
builds={builds}
4454
/>
55+
<PortForwardDropdown
56+
open={!!portForwardAnchorEl}
57+
anchorEl={portForwardAnchorEl}
58+
netstat={netstat}
59+
onClose={()=>{
60+
agentSend("DISCONNECT")
61+
setPortForwardAnchorEl(undefined)
62+
}}
63+
urlFormatter={(port)=>`${location.protocol}//${port}--${workspace.owner_name}--${location.host}`}
64+
/>
4565
</Stack>
4666
</Margins>
4767
)
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import{assign,createMachine}from"xstate"
2+
import*asTypesfrom"../../api/types"
3+
import{errorString}from"../../util/error"
4+
5+
exportinterfaceAgentContext{
6+
agentId?:string
7+
netstat?:Types.NetstatResponse
8+
websocket?:WebSocket
9+
}
10+
11+
exporttypeAgentEvent=
12+
|{type:"CONNECT";agentId:string}
13+
|{type:"STAT";data:Types.NetstatResponse}
14+
|{type:"DISCONNECT"}
15+
16+
exportconstagentMachine=createMachine(
17+
{
18+
tsTypes:{}asimport("./agentXService.typegen").Typegen0,
19+
schema:{
20+
context:{}asAgentContext,
21+
events:{}asAgentEvent,
22+
services:{}as{
23+
connect:{
24+
data:WebSocket
25+
}
26+
},
27+
},
28+
id:"agentState",
29+
initial:"disconnected",
30+
states:{
31+
connecting:{
32+
invoke:{
33+
src:"connect",
34+
id:"connect",
35+
onDone:[
36+
{
37+
actions:["assignWebsocket","clearNetstat"],
38+
target:"connected",
39+
},
40+
],
41+
onError:[
42+
{
43+
actions:"assignWebsocketError",
44+
target:"disconnected",
45+
},
46+
],
47+
},
48+
},
49+
connected:{
50+
on:{
51+
STAT:{
52+
actions:"assignNetstat",
53+
},
54+
DISCONNECT:{
55+
actions:["disconnect","clearNetstat"],
56+
target:"disconnected",
57+
},
58+
},
59+
},
60+
disconnected:{
61+
on:{
62+
CONNECT:{
63+
actions:"assignConnection",
64+
target:"connecting",
65+
},
66+
},
67+
},
68+
},
69+
},
70+
{
71+
services:{
72+
connect:(context)=>(send)=>{
73+
returnnewPromise<WebSocket>((resolve,reject)=>{
74+
if(!context.agentId){
75+
returnreject("agent ID is not set")
76+
}
77+
constproto=location.protocol==="https:" ?"wss:" :"ws:"
78+
constsocket=newWebSocket(`${proto}//${location.host}/api/v2/workspaceagents/${context.agentId}/netstat`)
79+
socket.binaryType="arraybuffer"
80+
socket.addEventListener("open",()=>{
81+
resolve(socket)
82+
})
83+
socket.addEventListener("error",(error)=>{
84+
reject(error)
85+
})
86+
socket.addEventListener("close",()=>{
87+
send({
88+
type:"DISCONNECT",
89+
})
90+
})
91+
socket.addEventListener("message",(event)=>{
92+
try{
93+
send({
94+
type:"STAT",
95+
data:JSON.parse(newTextDecoder().decode(event.data)),
96+
})
97+
}catch(error){
98+
send({
99+
type:"STAT",
100+
data:{
101+
error:errorString(error),
102+
},
103+
})
104+
}
105+
})
106+
})
107+
},
108+
},
109+
actions:{
110+
assignConnection:assign((context,event)=>({
111+
...context,
112+
agentId:event.agentId,
113+
})),
114+
assignWebsocket:assign({
115+
websocket:(_,event)=>event.data,
116+
}),
117+
assignWebsocketError:assign({
118+
netstat:(_,event)=>({error:errorString(event.data)}),
119+
}),
120+
clearNetstat:assign((context:AgentContext)=>({
121+
...context,
122+
netstat:undefined,
123+
})),
124+
assignNetstat:assign({
125+
netstat:(_,event)=>event.data,
126+
}),
127+
disconnect:(context:AgentContext)=>{
128+
// Code 1000 is a successful exit!
129+
context.websocket?.close(1000)
130+
},
131+
},
132+
},
133+
)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp