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

Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
5a47132
feat: Add ACL list support to rego objects
Emyrk Sep 13, 2022
03f69bf
Add unit tests
Emyrk Sep 13, 2022
91a358d
Rename ACL list
Emyrk Sep 13, 2022
8f837b7
Flip rego json to key by user id
Emyrk Sep 15, 2022
8378c9b
feat: add template ACL
sreya Sep 17, 2022
54a0d13
add down migration
sreya Sep 19, 2022
72ea751
remove unused file
sreya Sep 19, 2022
d533a16
undo insert templates query change
sreya Sep 19, 2022
f56fcf9
add patch endpoint tests
sreya Sep 19, 2022
f162694
Unit test use shadowed copied value
Emyrk Sep 19, 2022
ea25c08
Allow wildcards for ACL list
Emyrk Sep 19, 2022
5a081eb
fix authorize bug
sreya Sep 19, 2022
072b3e4
feat: Allow filter to accept objects of multiple types
Emyrk Sep 19, 2022
205c36c
add support for private templates
sreya Sep 19, 2022
ba32928
go.mod
sreya Sep 19, 2022
5c6344f
Merge branch 'main' into resource_acl_list
sreya Sep 19, 2022
ef15908
fix rbac merge woes
sreya Sep 19, 2022
8ab5200
update migration
sreya Sep 19, 2022
c040e8e
fix workspaces_test
sreya Sep 19, 2022
1f4ceee
remove sqlx
sreya Sep 19, 2022
7cc71e1
fix audit
sreya Sep 19, 2022
131d5ed
fix lint
sreya Sep 19, 2022
8c3ee6a
Revert "remove sqlx"
sreya Sep 19, 2022
fe2af91
add test for list templates
sreya Sep 20, 2022
0218c4e
fix error msg
sreya Sep 20, 2022
6883106
fix sqlx woes
sreya Sep 20, 2022
4fbd9be
fix lint
sreya Sep 20, 2022
c96a6ca
fix audit
sreya Sep 20, 2022
57ba8b3
make gen
sreya Sep 20, 2022
c66d247
Merge branch 'main' into resource_acl_list
sreya Sep 20, 2022
0af367a
fix merge woes
sreya Sep 20, 2022
f6c3f51
fix test template
sreya Sep 20, 2022
6e72286
fmt
sreya Sep 20, 2022
44bcbde
Add base layout
BrunoQuaresma Sep 21, 2022
0f80beb
Add table
BrunoQuaresma Sep 21, 2022
d274d62
Add search user
BrunoQuaresma Sep 21, 2022
943c76b
Add user role
BrunoQuaresma Sep 21, 2022
7f7f1d3
Add update and delete
BrunoQuaresma Sep 21, 2022
967a1a9
Fix summary view
BrunoQuaresma Sep 21, 2022
1324991
Merge branch 'resource_acl_list' of github.com:coder/coder into resou…
BrunoQuaresma Sep 21, 2022
bd34d20
Merge branch 'resource_acl_list' of github.com:coder/coder into resou…
sreya Sep 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add update and delete
  • Loading branch information
BrunoQuaresma committed Sep 21, 2022
commit 7f7f1d3dba71e4cb2a96248514ab08b13119c481
2 changes: 1 addition & 1 deletion site/src/components/TemplateLayout/TemplateLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export const TemplateLayout: FC = () => {
</div>

<Margins>
<Outlet context={templateState.context} />
<Outlet context={{ templateContext: templateState.context, permissions }} />
</Margins>

<DeleteDialog
Expand Down
16 changes: 16 additions & 0 deletions site/src/hooks/useMe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useSelector } from "@xstate/react"
import { User } from "api/typesGenerated"
import { useContext } from "react"
import { selectUser } from "xServices/auth/authSelectors"
import { XServiceContext } from "xServices/StateContext"

export const useMe = (): User => {
const xServices = useContext(XServiceContext)
const me = useSelector(xServices.authXService, selectUser)

if (!me) {
throw new Error("User not found.")
}

return me
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import { useMachine } from "@xstate/react"
import { useMe } from "hooks/useMe"
import { FC } from "react"
import { Helmet } from "react-helmet-async"
import { useOutletContext } from "react-router-dom"
import { pageTitle } from "util/page"
import { Permissions } from "xServices/auth/authXService"
import { templateUsersMachine } from "xServices/template/templateUsersXService"
import { TemplateContext } from "xServices/template/templateXService"
import { TemplateCollaboratorsPageView } from "./TemplateCollaboratorsPageView"

export const TemplateCollaboratorsPage: FC<React.PropsWithChildren<unknown>> = () => {
const { templateContext, permissions } = useOutletContext<{
templateContext: TemplateContext
permissions: Permissions
}>()
const { template, activeTemplateVersion, templateResources, deleteTemplateError } =
useOutletContext<TemplateContext>()
templateContext

if (!template || !activeTemplateVersion || !templateResources) {
throw new Error(
Expand All @@ -18,20 +24,32 @@ export const TemplateCollaboratorsPage: FC<React.PropsWithChildren<unknown>> = (
}

const [state, send] = useMachine(templateUsersMachine, { context: { templateId: template.id } })
const { templateUsers } = state.context
const { templateUsers, userToBeUpdated } = state.context
const me = useMe()
const userTemplateRole = template.user_roles[me.id]
const canUpdatesUsers =
permissions.deleteTemplates || userTemplateRole === "admin" || template.created_by_id === me.id

return (
<>
<Helmet>
<title>{pageTitle(`${template.name} · Collaborators`)}</title>
</Helmet>
<TemplateCollaboratorsPageView
canUpdateUsers={canUpdatesUsers}
templateUsers={templateUsers}
deleteTemplateError={deleteTemplateError}
onAddUser={(user, role, reset) => {
send("ADD_USER", { user, role, onDone: reset })
}}
isAddingUser={state.matches("addingUser")}
onUpdateUser={(user, role) => {
send("UPDATE_USER_ROLE", { user, role })
}}
updatingUser={userToBeUpdated}
onRemoveUser={(user) => {
send("REMOVE_USER", { user })
}}
/>
</>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { ErrorSummary } from "components/ErrorSummary/ErrorSummary"
import { LoadingButton } from "components/LoadingButton/LoadingButton"
import { Stack } from "components/Stack/Stack"
import { TableLoader } from "components/TableLoader/TableLoader"
import { TableRowMenu } from "components/TableRowMenu/TableRowMenu"
import debounce from "just-debounce-it"
import { ChangeEvent, FC, useState } from "react"
import { searchUserMachine } from "xServices/users/searchUserXService"
Expand Down Expand Up @@ -150,11 +151,24 @@ export interface TemplateCollaboratorsPageViewProps {
templateUsers: TemplateUser[] | undefined
onAddUser: (user: User, role: TemplateRole, reset: () => void) => void
isAddingUser: boolean
canUpdateUsers: boolean
onUpdateUser: (user: User, role: TemplateRole) => void
updatingUser: TemplateUser | undefined
onRemoveUser: (user: User) => void
}

export const TemplateCollaboratorsPageView: FC<
React.PropsWithChildren<TemplateCollaboratorsPageViewProps>
> = ({ deleteTemplateError, templateUsers, onAddUser, isAddingUser }) => {
> = ({
deleteTemplateError,
templateUsers,
onAddUser,
isAddingUser,
updatingUser,
onUpdateUser,
canUpdateUsers,
onRemoveUser,
}) => {
const styles = useStyles()
const deleteError = deleteTemplateError ? (
<ErrorSummary error={deleteTemplateError} dismissible />
Expand All @@ -168,8 +182,9 @@ export const TemplateCollaboratorsPageView: FC<
<Table>
<TableHead>
<TableRow>
<TableCell>User</TableCell>
<TableCell>Role</TableCell>
<TableCell width="60%">User</TableCell>
<TableCell width="40%">Role</TableCell>
<TableCell width="1%" />
</TableRow>
</TableHead>
<TableBody>
Expand Down Expand Up @@ -206,7 +221,45 @@ export const TemplateCollaboratorsPageView: FC<
}
/>
</TableCell>
<TableCell>{user.role}</TableCell>
<TableCell>
{canUpdateUsers ? (
<Select
value={user.role}
variant="outlined"
className={styles.updateSelect}
disabled={updatingUser && updatingUser.id === user.id}
onChange={(event) => {
onUpdateUser(user, event.target.value as TemplateRole)
}}
>
<MenuItem key="read" value="read">
Read
</MenuItem>
<MenuItem key="write" value="write">
Write
</MenuItem>
<MenuItem key="admin" value="admin">
Admin
</MenuItem>
</Select>
) : (
user.role
)}
</TableCell>

{canUpdateUsers && (
<TableCell>
<TableRowMenu
data={user}
menuItems={[
{
label: "Remove",
onClick: () => onRemoveUser(user),
},
]}
/>
</TableCell>
)}
</TableRow>
))}
</Cond>
Expand Down Expand Up @@ -245,5 +298,17 @@ export const useStyles = makeStyles((theme) => {
height: theme.spacing(4.5),
borderRadius: "100%",
},

updateSelect: {
margin: 0,
// Set a fixed width for the select. It avoids selects having different sizes
// depending on how many roles they have selected.
width: theme.spacing(25),
"& .MuiSelect-root": {
// Adjusting padding because it does not have label
paddingTop: theme.spacing(1.5),
paddingBottom: theme.spacing(1.5),
},
},
}
})
2 changes: 1 addition & 1 deletion site/src/xServices/auth/authXService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const permissionsToCheck = {
},
} as const

type Permissions = Record<keyof typeof permissionsToCheck, boolean>
export type Permissions = Record<keyof typeof permissionsToCheck, boolean>

export interface AuthContext {
getUserError?: Error | unknown
Expand Down
99 changes: 91 additions & 8 deletions site/src/xServices/template/templateUsersXService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getTemplateUserRoles, updateTemplateMeta } from "api/api"
import { TemplateRole, TemplateUser, User } from "api/typesGenerated"
import { displaySuccess } from "components/GlobalSnackbar/utils"
import { assign, createMachine } from "xstate"

export const templateUsersMachine = createMachine(
Expand All @@ -9,6 +10,7 @@ export const templateUsersMachine = createMachine(
templateId: string
templateUsers?: TemplateUser[]
userToBeAdded?: TemplateUser
userToBeUpdated?: TemplateUser
addUserCallback?: () => void
},
services: {} as {
Expand All @@ -18,13 +20,26 @@ export const templateUsersMachine = createMachine(
addUser: {
data: unknown
}
updateUser: {
data: unknown
}
},
events: {} as {
type: "ADD_USER"
user: User
role: TemplateRole
onDone: () => void
},
events: {} as
| {
type: "ADD_USER"
user: User
role: TemplateRole
onDone: () => void
}
| {
type: "UPDATE_USER_ROLE"
user: User
role: TemplateRole
}
| {
type: "REMOVE_USER"
user: User
},
},
tsTypes: {} as import("./templateUsersXService.typegen").Typegen0,
id: "templateUserRoles",
Expand All @@ -42,14 +57,38 @@ export const templateUsersMachine = createMachine(
idle: {
on: {
ADD_USER: { target: "addingUser", actions: ["assignUserToBeAdded"] },
UPDATE_USER_ROLE: { target: "updatingUser", actions: ["assignUserToBeUpdated"] },
REMOVE_USER: { target: "removingUser", actions: ["removeUserFromTemplateUsers"] },
},
},
addingUser: {
invoke: {
src: "addUser",
onDone: {
target: "idle",
actions: ["addUserToTemplateUsers", "runCallback"],
actions: ["addUserToTemplateUsers", "runAddCallback"],
},
},
},
updatingUser: {
invoke: {
src: "updateUser",
onDone: {
target: "idle",
actions: [
"updateUserOnTemplateUsers",
"clearUserToBeUpdated",
"displayUpdateSuccessMessage",
],
},
},
},
removingUser: {
invoke: {
src: "removeUser",
onDone: {
target: "idle",
actions: ["displayRemoveSuccessMessage"],
},
},
},
Expand All @@ -64,6 +103,18 @@ export const templateUsersMachine = createMachine(
[user.id]: role,
},
}),
updateUser: ({ templateId }, { user, role }) =>
updateTemplateMeta(templateId, {
user_perms: {
[user.id]: role,
},
}),
removeUser: ({ templateId }, { user }) =>
updateTemplateMeta(templateId, {
user_perms: {
[user.id]: "",
},
}),
},
actions: {
assignTemplateUsers: assign({
Expand All @@ -81,11 +132,43 @@ export const templateUsersMachine = createMachine(
return [...templateUsers, userToBeAdded]
},
}),
runCallback: ({ addUserCallback }) => {
runAddCallback: ({ addUserCallback }) => {
if (addUserCallback) {
addUserCallback()
}
},
assignUserToBeUpdated: assign({
userToBeUpdated: (_, { user, role }) => ({ ...user, role }),
}),
updateUserOnTemplateUsers: assign({
templateUsers: ({ templateUsers, userToBeUpdated }) => {
if (!templateUsers || !userToBeUpdated) {
throw new Error("No user to be updated.")
}
return templateUsers.map((oldTemplateUser) => {
return oldTemplateUser.id === userToBeUpdated.id ? userToBeUpdated : oldTemplateUser
})
},
}),
clearUserToBeUpdated: assign({
userToBeUpdated: (_) => undefined,
}),
displayUpdateSuccessMessage: () => {
displaySuccess("Collaborator role update successfully!")
},
removeUserFromTemplateUsers: assign({
templateUsers: ({ templateUsers }, { user }) => {
if (!templateUsers) {
throw new Error("No user to be removed.")
}
return templateUsers.filter((oldTemplateUser) => {
return oldTemplateUser.id !== user.id
})
},
}),
displayRemoveSuccessMessage: () => {
displaySuccess("Collaborator removed successfully!")
},
},
},
)