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

Commitc05da12

Browse files
committed
do not show app links to users without workspace update access
1 parentbccde3f commitc05da12

File tree

6 files changed

+137
-35
lines changed

6 files changed

+137
-35
lines changed

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

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,10 @@ interface ResourcesProps {
6363
resources?:WorkspaceResource[]
6464
getResourcesError?:Error
6565
workspace:Workspace
66+
canUpdateWorkspace:boolean
6667
}
6768

68-
exportconstResources:FC<ResourcesProps>=({ resources, getResourcesError, workspace})=>{
69+
exportconstResources:FC<ResourcesProps>=({ resources, getResourcesError, workspace, canUpdateWorkspace})=>{
6970
conststyles=useStyles()
7071
consttheme:Theme=useTheme()
7172

@@ -89,7 +90,7 @@ export const Resources: FC<ResourcesProps> = ({ resources, getResourcesError, wo
8990
<AgentHelpTooltip/>
9091
</Stack>
9192
</TableCell>
92-
<TableCell>{Language.accessLabel}</TableCell>
93+
{canUpdateWorkspace&&<TableCell>{Language.accessLabel}</TableCell>}
9394
<TableCell>{Language.statusLabel}</TableCell>
9495
</TableHeaderRow>
9596
</TableHead>
@@ -130,28 +131,30 @@ export const Resources: FC<ResourcesProps> = ({ resources, getResourcesError, wo
130131
{agent.name}
131132
<spanclassName={styles.operatingSystem}>{agent.operating_system}</span>
132133
</TableCell>
133-
<TableCell>
134-
<Stack>
135-
{agent.status==="connected"&&(
136-
<TerminalLink
137-
className={styles.accessLink}
138-
workspaceName={workspace.name}
139-
agentName={agent.name}
140-
userName={workspace.owner_name}
141-
/>
142-
)}
143-
{agent.status==="connected"&&
144-
agent.apps.map((app)=>(
145-
<AppLink
146-
key={app.name}
147-
appIcon={app.icon}
148-
appName={app.name}
149-
userName={workspace.owner_name}
134+
{canUpdateWorkspace&&(
135+
<TableCell>
136+
<Stack>
137+
{agent.status==="connected"&&(
138+
<TerminalLink
139+
className={styles.accessLink}
150140
workspaceName={workspace.name}
141+
agentName={agent.name}
142+
userName={workspace.owner_name}
151143
/>
152-
))}
153-
</Stack>
154-
</TableCell>
144+
)}
145+
{agent.status==="connected"&&
146+
agent.apps.map((app)=>(
147+
<AppLink
148+
key={app.name}
149+
appIcon={app.icon}
150+
appName={app.name}
151+
userName={workspace.owner_name}
152+
workspaceName={workspace.name}
153+
/>
154+
))}
155+
</Stack>
156+
</TableCell>
157+
)}
155158
<TableCell>
156159
<spanstyle={{color:getDisplayAgentStatus(theme,agent).color}}>
157160
{getDisplayAgentStatus(theme,agent).status}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ Started.args = {
2222
handleStop:action("stop"),
2323
resources:[Mocks.MockWorkspaceResource,Mocks.MockWorkspaceResource2],
2424
builds:[Mocks.MockWorkspaceBuild],
25+
canUpdateWorkspace:true,
26+
}
27+
28+
exportconstWithoutUpdateAccess=Template.bind({})
29+
WithoutUpdateAccess.args={
30+
...Started.args,
31+
canUpdateWorkspace:false,
2532
}
2633

2734
exportconstStarting=Template.bind({})

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export interface WorkspaceProps {
2626
resources?:TypesGen.WorkspaceResource[]
2727
getResourcesError?:Error
2828
builds?:TypesGen.WorkspaceBuild[]
29+
canUpdateWorkspace:boolean
2930
}
3031

3132
/**
@@ -42,6 +43,7 @@ export const Workspace: FC<WorkspaceProps> = ({
4243
resources,
4344
getResourcesError,
4445
builds,
46+
canUpdateWorkspace,
4547
})=>{
4648
conststyles=useStyles()
4749

@@ -74,7 +76,12 @@ export const Workspace: FC<WorkspaceProps> = ({
7476

7577
<WorkspaceStatsworkspace={workspace}/>
7678

77-
<Resourcesresources={resources}getResourcesError={getResourcesError}workspace={workspace}/>
79+
<Resources
80+
resources={resources}
81+
getResourcesError={getResourcesError}
82+
workspace={workspace}
83+
canUpdateWorkspace={canUpdateWorkspace}
84+
/>
7885

7986
<WorkspaceSectiontitle="Timeline"contentsProps={{className:styles.timelineContents}}>
8087
<BuildsTablebuilds={builds}className={styles.timelineTable}/>

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import{useMachine}from"@xstate/react"
2-
importReact,{useEffect}from"react"
1+
import{useMachine,useSelector}from"@xstate/react"
2+
importReact,{useContext,useEffect}from"react"
33
import{Helmet}from"react-helmet"
44
import{useNavigate,useParams}from"react-router-dom"
55
import{DeleteWorkspaceDialog}from"../../components/DeleteWorkspaceDialog/DeleteWorkspaceDialog"
@@ -8,6 +8,8 @@ import { FullScreenLoader } from "../../components/Loader/FullScreenLoader"
88
import{Workspace}from"../../components/Workspace/Workspace"
99
import{firstOrItem}from"../../util/array"
1010
import{pageTitle}from"../../util/page"
11+
import{selectUser}from"../../xServices/auth/authSelectors"
12+
import{XServiceContext}from"../../xServices/StateContext"
1113
import{workspaceMachine}from"../../xServices/workspace/workspaceXService"
1214
import{workspaceScheduleBannerMachine}from"../../xServices/workspaceSchedule/workspaceScheduleBannerXService"
1315

@@ -17,8 +19,13 @@ export const WorkspacePage: React.FC = () => {
1719
constusername=firstOrItem(usernameQueryParam,null)
1820
constworkspaceName=firstOrItem(workspaceQueryParam,null)
1921

20-
const[workspaceState,workspaceSend]=useMachine(workspaceMachine)
21-
const{ workspace, resources, getWorkspaceError, getResourcesError, builds}=workspaceState.context
22+
constxServices=useContext(XServiceContext)
23+
constme=useSelector(xServices.authXService,selectUser)
24+
25+
const[workspaceState,workspaceSend]=useMachine(workspaceMachine.withContext({userId:me?.id}))
26+
const{ workspace, resources, getWorkspaceError, getResourcesError, builds, permissions}=workspaceState.context
27+
28+
constcanUpdateWorkspace=!!permissions?.updateWorkspace
2229

2330
const[bannerState,bannerSend]=useMachine(workspaceScheduleBannerMachine)
2431

@@ -57,6 +64,7 @@ export const WorkspacePage: React.FC = () => {
5764
resources={resources}
5865
getResourcesError={getResourcesErrorinstanceofError ?getResourcesError :undefined}
5966
builds={builds}
67+
canUpdateWorkspace={canUpdateWorkspace}
6068
/>
6169
<DeleteWorkspaceDialog
6270
isOpen={workspaceState.matches({ready:{build:"askingDelete"}})}

‎site/src/xServices/auth/authSelectors.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,7 @@ export const selectOrgId = (state: AuthState): string | undefined => {
1010
exportconstselectPermissions=(state:AuthState):AuthContext["permissions"]=>{
1111
returnstate.context.permissions
1212
}
13+
14+
exportconstselectUser=(state:AuthState):AuthContext["me"]=>{
15+
returnstate.context.me
16+
}

‎site/src/xServices/workspace/workspaceXService.ts

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ const Language = {
1717
buildError:"Workspace action failed.",
1818
}
1919

20+
typePermissions=Record<keyofReturnType<typeofpermissionsToCheck>,boolean>
21+
2022
exportinterfaceWorkspaceContext{
2123
workspace?:TypesGen.Workspace
2224
template?:TypesGen.Template
@@ -26,14 +28,18 @@ export interface WorkspaceContext {
2628
// error creating a new WorkspaceBuild
2729
buildError?:Error|unknown
2830
// these are separate from getX errors because they don't make the page unusable
29-
refreshWorkspaceError:Error|unknown
30-
refreshTemplateError:Error|unknown
31-
getResourcesError:Error|unknown
31+
refreshWorkspaceError?:Error|unknown
32+
refreshTemplateError?:Error|unknown
33+
getResourcesError?:Error|unknown
3234
// Builds
3335
builds?:TypesGen.WorkspaceBuild[]
3436
getBuildsError?:Error|unknown
3537
loadMoreBuildsError?:Error|unknown
36-
cancellationMessage:string
38+
cancellationMessage?:string
39+
// permissions
40+
permissions?:Permissions
41+
checkPermissionsError?:Error|unknown
42+
userId?:string
3743
}
3844

3945
exporttypeWorkspaceEvent=
@@ -48,6 +54,30 @@ export type WorkspaceEvent =
4854
|{type:"LOAD_MORE_BUILDS"}
4955
|{type:"REFRESH_TIMELINE"}
5056

57+
exportconstchecks={
58+
readWorkspace:"readWorkspace",
59+
updateWorkspace:"updateWorkspace",
60+
}asconst
61+
62+
constpermissionsToCheck=(workspace:TypesGen.Workspace)=>({
63+
[checks.readWorkspace]:{
64+
object:{
65+
resource_type:"workspace",
66+
resource_id:workspace.id,
67+
owner_id:workspace.owner_id,
68+
},
69+
action:"read",
70+
},
71+
[checks.updateWorkspace]:{
72+
object:{
73+
resource_type:"workspace",
74+
resource_id:workspace.id,
75+
owner_id:workspace.owner_id,
76+
},
77+
action:"update",
78+
},
79+
})
80+
5181
exportconstworkspaceMachine=createMachine(
5282
{
5383
tsTypes:{}asimport("./workspaceXService.typegen").Typegen0,
@@ -82,6 +112,9 @@ export const workspaceMachine = createMachine(
82112
loadMoreBuilds:{
83113
data:TypesGen.WorkspaceBuild[]
84114
}
115+
checkPermissions:{
116+
data:TypesGen.UserAuthorizationResponse
117+
}
85118
},
86119
},
87120
id:"workspaceState",
@@ -99,7 +132,7 @@ export const workspaceMachine = createMachine(
99132
src:"getWorkspace",
100133
id:"getWorkspace",
101134
onDone:{
102-
target:"ready",
135+
target:"gettingPermissions",
103136
actions:["assignWorkspace"],
104137
},
105138
onError:{
@@ -109,6 +142,25 @@ export const workspaceMachine = createMachine(
109142
},
110143
tags:"loading",
111144
},
145+
gettingPermissions:{
146+
entry:"clearGetPermissionsError",
147+
invoke:{
148+
src:"checkPermissions",
149+
id:"checkPermissions",
150+
onDone:[
151+
{
152+
actions:["assignPermissions"],
153+
target:"ready",
154+
},
155+
],
156+
onError:[
157+
{
158+
actions:"assignGetPermissionsError",
159+
target:"error",
160+
},
161+
],
162+
},
163+
},
112164
ready:{
113165
type:"parallel",
114166
states:{
@@ -312,6 +364,7 @@ export const workspaceMachine = createMachine(
312364
workspace:undefined,
313365
template:undefined,
314366
build:undefined,
367+
permissions:undefined,
315368
}),
316369
assignWorkspace:assign({
317370
workspace:(_,event)=>event.data,
@@ -323,6 +376,17 @@ export const workspaceMachine = createMachine(
323376
assignTemplate:assign({
324377
template:(_,event)=>event.data,
325378
}),
379+
assignPermissions:assign({
380+
// Setting event.data as Permissions to be more stricted. So we know
381+
// what permissions we asked for.
382+
permissions:(_,event)=>event.dataasPermissions,
383+
}),
384+
assignGetPermissionsError:assign({
385+
checkPermissionsError:(_,event)=>event.data,
386+
}),
387+
clearGetPermissionsError:assign({
388+
checkPermissionsError:(_)=>undefined,
389+
}),
326390
assignBuild:(_,event)=>
327391
assign({
328392
build:event.data,
@@ -347,7 +411,7 @@ export const workspaceMachine = createMachine(
347411
cancellationMessage:undefined,
348412
}),
349413
displayCancellationError:(context)=>{
350-
displayError(context.cancellationMessage)
414+
displayError(context.cancellationMessage||"Cancellation failed")
351415
},
352416
assignRefreshWorkspaceError:(_,event)=>
353417
assign({
@@ -487,14 +551,23 @@ export const workspaceMachine = createMachine(
487551
if(context.workspace){
488552
returnawaitAPI.getWorkspaceBuilds(context.workspace.id)
489553
}else{
490-
throwError("Cannotrefresh workspace without id")
554+
throwError("Cannotget builds without id")
491555
}
492556
},
493557
loadMoreBuilds:async(context)=>{
494558
if(context.workspace){
495559
returnawaitAPI.getWorkspaceBuilds(context.workspace.id)
496560
}else{
497-
throwError("Cannot refresh workspace without id")
561+
throwError("Cannot load more builds without id")
562+
}
563+
},
564+
checkPermissions:async(context)=>{
565+
if(context.workspace&&context.userId){
566+
returnawaitAPI.checkUserPermissions(context.userId,{
567+
checks:permissionsToCheck(context.workspace),
568+
})
569+
}else{
570+
throwError("Cannot check permissions without both workspace and user id")
498571
}
499572
},
500573
},

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp