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

Commitedf985b

Browse files
committed
do not show app links to users without workspace update access
1 parentb0e8f65 commitedf985b

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
@@ -28,6 +28,7 @@ export interface WorkspaceProps {
2828
resources?:TypesGen.WorkspaceResource[]
2929
getResourcesError?:Error
3030
builds?:TypesGen.WorkspaceBuild[]
31+
canUpdateWorkspace:boolean
3132
}
3233

3334
/**
@@ -44,6 +45,7 @@ export const Workspace: FC<WorkspaceProps> = ({
4445
resources,
4546
getResourcesError,
4647
builds,
48+
canUpdateWorkspace,
4749
})=>{
4850
conststyles=useStyles()
4951
constnavigate=useNavigate()
@@ -80,7 +82,12 @@ export const Workspace: FC<WorkspaceProps> = ({
8082
<WorkspaceStatsworkspace={workspace}/>
8183

8284
{!!resources&&!!resources.length&&(
83-
<Resourcesresources={resources}getResourcesError={getResourcesError}workspace={workspace}/>
85+
<Resources
86+
resources={resources}
87+
getResourcesError={getResourcesError}
88+
workspace={workspace}
89+
canUpdateWorkspace={canUpdateWorkspace}
90+
/>
8491
)}
8592

8693
<WorkspaceSectiontitle="Timeline"contentsProps={{className:styles.timelineContents}}>

‎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{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

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

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

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

@@ -56,6 +63,7 @@ export const WorkspacePage: React.FC = () => {
5663
resources={resources}
5764
getResourcesError={getResourcesErrorinstanceofError ?getResourcesError :undefined}
5865
builds={builds}
66+
canUpdateWorkspace={canUpdateWorkspace}
5967
/>
6068
<DeleteWorkspaceDialog
6169
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({
@@ -489,14 +553,23 @@ export const workspaceMachine = createMachine(
489553
if(context.workspace){
490554
returnawaitAPI.getWorkspaceBuilds(context.workspace.id)
491555
}else{
492-
throwError("Cannotrefresh workspace without id")
556+
throwError("Cannotget builds without id")
493557
}
494558
},
495559
loadMoreBuilds:async(context)=>{
496560
if(context.workspace){
497561
returnawaitAPI.getWorkspaceBuilds(context.workspace.id)
498562
}else{
499-
throwError("Cannot refresh workspace without id")
563+
throwError("Cannot load more builds without id")
564+
}
565+
},
566+
checkPermissions:async(context)=>{
567+
if(context.workspace&&context.userId){
568+
returnawaitAPI.checkUserPermissions(context.userId,{
569+
checks:permissionsToCheck(context.workspace),
570+
})
571+
}else{
572+
throwError("Cannot check permissions without both workspace and user id")
500573
}
501574
},
502575
},

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp