diff --git a/site/src/pages/UsersPage/UsersPage.test.tsx b/site/src/pages/UsersPage/UsersPage.test.tsx
index d371c9fa58d60..ea57bbb978970 100644
--- a/site/src/pages/UsersPage/UsersPage.test.tsx
+++ b/site/src/pages/UsersPage/UsersPage.test.tsx
@@ -1,4 +1,5 @@
import { fireEvent, screen, waitFor, within } from "@testing-library/react"
+import { rest } from "msw"
import React from "react"
import * as API from "../../api/api"
import { Role } from "../../api/typesGenerated"
@@ -7,8 +8,11 @@ import { Language as ResetPasswordDialogLanguage } from "../../components/ResetP
import { Language as RoleSelectLanguage } from "../../components/RoleSelect/RoleSelect"
import { Language as UsersTableLanguage } from "../../components/UsersTable/UsersTable"
import { MockAuditorRole, MockUser, MockUser2, render } from "../../testHelpers/renderHelpers"
+import { server } from "../../testHelpers/server"
+import { permissionsToCheck } from "../../xServices/auth/authXService"
import { Language as usersXServiceLanguage } from "../../xServices/users/usersXService"
import { Language as UsersPageLanguage, UsersPage } from "./UsersPage"
+import { Language as UsersViewLanguage } from "./UsersPageView"
const suspendUser = async (setupActionSpies: () => void) => {
// Get the first user in the table
@@ -99,6 +103,32 @@ describe("Users Page", () => {
expect(users.length).toEqual(2)
})
+ it("shows 'New user' button to an authorized user", () => {
+ render()
+ const newUserButton = screen.queryByText(UsersViewLanguage.newUserButton)
+ expect(newUserButton).toBeDefined()
+ })
+
+ it("does not show 'New user' button to unauthorized user", () => {
+ server.use(
+ rest.post("/api/v2/users/:userId/authorization", async (req, res, ctx) => {
+ const permissions = Object.keys(permissionsToCheck)
+ const response = permissions.reduce((obj, permission) => {
+ return {
+ ...obj,
+ [permission]: true,
+ createUser: false,
+ }
+ }, {})
+
+ return res(ctx.status(200), ctx.json(response))
+ }),
+ )
+ render()
+ const newUserButton = screen.queryByText(UsersViewLanguage.newUserButton)
+ expect(newUserButton).toBeNull()
+ })
+
describe("suspend user", () => {
describe("when it is success", () => {
it("shows a success message and refresh the page", async () => {
diff --git a/site/src/pages/UsersPage/UsersPage.tsx b/site/src/pages/UsersPage/UsersPage.tsx
index b52cf1c69aa62..e28b962b2b634 100644
--- a/site/src/pages/UsersPage/UsersPage.tsx
+++ b/site/src/pages/UsersPage/UsersPage.tsx
@@ -23,6 +23,7 @@ export const UsersPage: React.FC = () => {
const userToResetPassword = users?.find((u) => u.id === userIdToResetPassword)
const permissions = useSelector(xServices.authXService, selectPermissions)
const canEditUsers = permissions && permissions.updateUsers
+ const canCreateUser = permissions && permissions.createUser
const { roles } = rolesState.context
// Is loading if
// - permissions are not loaded or
@@ -70,6 +71,7 @@ export const UsersPage: React.FC = () => {
isUpdatingUserRoles={usersState.matches("updatingUserRoles")}
isLoading={isLoading}
canEditUsers={canEditUsers}
+ canCreateUser={canCreateUser}
/>
= (args) =>
-export const Ready = Template.bind({})
-Ready.args = {
+export const Admin = Template.bind({})
+Admin.args = {
users: [MockUser, MockUser2],
roles: MockSiteRoles,
+ canCreateUser: true,
+ canEditUsers: true,
}
+
+export const Member = Template.bind({})
+Member.args = { ...Admin.args, canCreateUser: false, canEditUsers: false }
+
export const Empty = Template.bind({})
-Empty.args = {
- users: [],
- roles: MockSiteRoles,
-}
+Empty.args = { ...Admin.args, users: [] }
diff --git a/site/src/pages/UsersPage/UsersPageView.tsx b/site/src/pages/UsersPage/UsersPageView.tsx
index 8bb637c16c4aa..be5367d748ab5 100644
--- a/site/src/pages/UsersPage/UsersPageView.tsx
+++ b/site/src/pages/UsersPage/UsersPageView.tsx
@@ -17,6 +17,7 @@ export interface UsersPageViewProps {
error?: unknown
isUpdatingUserRoles?: boolean
canEditUsers?: boolean
+ canCreateUser?: boolean
isLoading?: boolean
openUserCreationDialog: () => void
onSuspendUser: (user: TypesGen.User) => void
@@ -34,11 +35,13 @@ export const UsersPageView: React.FC = ({
error,
isUpdatingUserRoles,
canEditUsers,
+ canCreateUser,
isLoading,
}) => {
+ const newUserAction = canCreateUser ? { text: Language.newUserButton, onClick: openUserCreationDialog } : undefined
return (
-
+
{error ? (
diff --git a/site/src/xServices/auth/authXService.ts b/site/src/xServices/auth/authXService.ts
index deba485615995..3e634fc8b58d8 100644
--- a/site/src/xServices/auth/authXService.ts
+++ b/site/src/xServices/auth/authXService.ts
@@ -12,6 +12,7 @@ export const Language = {
export const checks = {
readAllUsers: "readAllUsers",
updateUsers: "updateUsers",
+ createUser: "createUser",
createTemplates: "createTemplates",
} as const
@@ -28,6 +29,12 @@ export const permissionsToCheck = {
},
action: "update",
},
+ [checks.createUser]: {
+ object: {
+ resource_type: "user",
+ },
+ action: "create",
+ },
[checks.createTemplates]: {
object: {
resource_type: "template",