mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
test(site): move users page test to storybook (#14579)
By using [Storybook interaction tests](https://storybook.js.org/tutorials/ui-testing-handbook/react/en/interaction-testing/), we improve the developer experience, as we can see what is happening in the browser, use browser tools to debug, and snapshot the component after interactions, making our tests more reliable and easier to maintain. Fixes https://github.com/coder/coder/issues/14535
This commit is contained in:
+1
-1
@@ -1282,7 +1282,7 @@ class ApiMethods {
|
||||
updateUserPassword = async (
|
||||
userId: TypesGen.User["id"],
|
||||
updatePassword: TypesGen.UpdateUserPasswordRequest,
|
||||
): Promise<undefined> => {
|
||||
): Promise<void> => {
|
||||
await this.axios.put(`/api/v2/users/${userId}/password`, updatePassword);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { API } from "api/api";
|
||||
|
||||
export const deploymentConfigQueryKey = ["deployment", "config"];
|
||||
|
||||
export const deploymentConfig = () => {
|
||||
return {
|
||||
queryKey: ["deployment", "config"],
|
||||
queryKey: deploymentConfigQueryKey,
|
||||
queryFn: API.getDeploymentConfig,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { QueryClient, UseQueryOptions } from "react-query";
|
||||
|
||||
type GroupSortOrder = "asc" | "desc";
|
||||
|
||||
const groupsQueryKey = ["groups"];
|
||||
export const groupsQueryKey = ["groups"];
|
||||
|
||||
export const groups = () => {
|
||||
return {
|
||||
@@ -49,27 +49,29 @@ export type GroupsByUserId = Readonly<Map<string, readonly Group[]>>;
|
||||
export function groupsByUserId() {
|
||||
return {
|
||||
...groups(),
|
||||
select: (allGroups) => {
|
||||
// Sorting here means that nothing has to be sorted for the individual
|
||||
// user arrays later
|
||||
const sorted = sortGroupsByName(allGroups, "asc");
|
||||
const userIdMapper = new Map<string, Group[]>();
|
||||
select: selectGroupsByUserId,
|
||||
} satisfies UseQueryOptions<Group[], unknown, GroupsByUserId>;
|
||||
}
|
||||
|
||||
for (const group of sorted) {
|
||||
for (const user of group.members) {
|
||||
let groupsForUser = userIdMapper.get(user.id);
|
||||
if (groupsForUser === undefined) {
|
||||
groupsForUser = [];
|
||||
userIdMapper.set(user.id, groupsForUser);
|
||||
}
|
||||
export function selectGroupsByUserId(groups: Group[]): GroupsByUserId {
|
||||
// Sorting here means that nothing has to be sorted for the individual
|
||||
// user arrays later
|
||||
const sorted = sortGroupsByName(groups, "asc");
|
||||
const userIdMapper = new Map<string, Group[]>();
|
||||
|
||||
groupsForUser.push(group);
|
||||
}
|
||||
for (const group of sorted) {
|
||||
for (const user of group.members) {
|
||||
let groupsForUser = userIdMapper.get(user.id);
|
||||
if (groupsForUser === undefined) {
|
||||
groupsForUser = [];
|
||||
userIdMapper.set(user.id, groupsForUser);
|
||||
}
|
||||
|
||||
return userIdMapper as GroupsByUserId;
|
||||
},
|
||||
} satisfies UseQueryOptions<Group[], unknown, GroupsByUserId>;
|
||||
groupsForUser.push(group);
|
||||
}
|
||||
}
|
||||
|
||||
return userIdMapper as GroupsByUserId;
|
||||
}
|
||||
|
||||
export function groupsForUser(userId: string) {
|
||||
|
||||
@@ -9,9 +9,11 @@ const getRoleQueryKey = (organizationId: string, roleName: string) => [
|
||||
roleName,
|
||||
];
|
||||
|
||||
export const rolesQueryKey = ["roles"];
|
||||
|
||||
export const roles = () => {
|
||||
return {
|
||||
queryKey: ["roles"],
|
||||
queryKey: rolesQueryKey,
|
||||
queryFn: API.getRoles,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -115,11 +115,13 @@ export const updateRoles = (queryClient: QueryClient) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const authMethodsQueryKey = ["authMethods"];
|
||||
|
||||
export const authMethods = () => {
|
||||
return {
|
||||
// Even the endpoint being /users/authmethods we don't want to revalidate it
|
||||
// when users change so its better add a unique query key
|
||||
queryKey: ["authMethods"],
|
||||
queryKey: authMethodsQueryKey,
|
||||
queryFn: API.getAuthMethods,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -294,21 +294,21 @@ const PresetMenu: FC<PresetMenuProps> = ({
|
||||
</MenuItem>
|
||||
))}
|
||||
{learnMoreLink && (
|
||||
<>
|
||||
<Divider css={{ borderColor: theme.palette.divider }} />
|
||||
<MenuItem
|
||||
component="a"
|
||||
href={learnMoreLink}
|
||||
target="_blank"
|
||||
css={{ fontSize: 13, fontWeight: 500 }}
|
||||
onClick={() => {
|
||||
setIsOpen(false);
|
||||
}}
|
||||
>
|
||||
<OpenInNewOutlined css={{ fontSize: "14px !important" }} />
|
||||
View advanced filtering
|
||||
</MenuItem>
|
||||
</>
|
||||
<Divider css={{ borderColor: theme.palette.divider }} />
|
||||
)}
|
||||
{learnMoreLink && (
|
||||
<MenuItem
|
||||
component="a"
|
||||
href={learnMoreLink}
|
||||
target="_blank"
|
||||
css={{ fontSize: 13, fontWeight: 500 }}
|
||||
onClick={() => {
|
||||
setIsOpen(false);
|
||||
}}
|
||||
>
|
||||
<OpenInNewOutlined css={{ fontSize: "14px !important" }} />
|
||||
View advanced filtering
|
||||
</MenuItem>
|
||||
)}
|
||||
{learnMoreLink2 && learnMoreLabel2 && (
|
||||
<MenuItem
|
||||
|
||||
@@ -64,7 +64,7 @@ const updateUserRole = async (role: SlimRole) => {
|
||||
}
|
||||
|
||||
// Click on the "edit icon" to display the role options
|
||||
const editButton = within(userRow).getByTitle("Edit user roles");
|
||||
const editButton = within(userRow).getByLabelText("Edit user roles");
|
||||
fireEvent.click(editButton);
|
||||
|
||||
// Click on the role option
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { Interpolation, Theme } from "@emotion/react";
|
||||
import UserIcon from "@mui/icons-material/PersonOutline";
|
||||
import Checkbox from "@mui/material/Checkbox";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import type { SlimRole } from "api/typesGenerated";
|
||||
import {
|
||||
HelpTooltip,
|
||||
@@ -116,13 +117,15 @@ export const EditRolesButton: FC<EditRolesButtonProps> = ({
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverTrigger>
|
||||
<IconButton
|
||||
size="small"
|
||||
css={styles.editButton}
|
||||
title="Edit user roles"
|
||||
>
|
||||
<EditSquare />
|
||||
</IconButton>
|
||||
<Tooltip title="Edit user roles">
|
||||
<IconButton
|
||||
aria-label="Edit user roles"
|
||||
size="small"
|
||||
css={styles.editButton}
|
||||
>
|
||||
<EditSquare />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</PopoverTrigger>
|
||||
|
||||
<PopoverContent classes={{ paper }}>
|
||||
|
||||
@@ -0,0 +1,397 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { spyOn, userEvent, within } from "@storybook/test";
|
||||
import { API } from "api/api";
|
||||
import { deploymentConfigQueryKey } from "api/queries/deployment";
|
||||
import { groupsQueryKey } from "api/queries/groups";
|
||||
import { rolesQueryKey } from "api/queries/roles";
|
||||
import { authMethodsQueryKey, usersKey } from "api/queries/users";
|
||||
import type { User } from "api/typesGenerated";
|
||||
import { MockGroups } from "pages/UsersPage/storybookData/groups";
|
||||
import { MockRoles } from "pages/UsersPage/storybookData/roles";
|
||||
import { MockUsers } from "pages/UsersPage/storybookData/users";
|
||||
import { MockAuthMethodsAll, MockUser } from "testHelpers/entities";
|
||||
import {
|
||||
withAuthProvider,
|
||||
withDashboardProvider,
|
||||
withGlobalSnackbar,
|
||||
} from "testHelpers/storybook";
|
||||
import UsersPage from "./UsersPage";
|
||||
|
||||
const parameters = {
|
||||
queries: [
|
||||
// This query loads users for the filter menu, not for the table
|
||||
{
|
||||
key: usersKey({ limit: 25, offset: 25, q: "" }),
|
||||
data: {
|
||||
users: [],
|
||||
count: 60,
|
||||
},
|
||||
},
|
||||
// Users for the table
|
||||
{
|
||||
key: usersKey({ limit: 25, offset: 0, q: "" }),
|
||||
data: {
|
||||
users: MockUsers,
|
||||
count: 60,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: groupsQueryKey,
|
||||
data: MockGroups,
|
||||
},
|
||||
{
|
||||
key: authMethodsQueryKey,
|
||||
data: MockAuthMethodsAll,
|
||||
},
|
||||
{
|
||||
key: rolesQueryKey,
|
||||
data: MockRoles,
|
||||
},
|
||||
{
|
||||
key: deploymentConfigQueryKey,
|
||||
data: {
|
||||
config: {
|
||||
oidc: {
|
||||
user_role_field: "role",
|
||||
},
|
||||
},
|
||||
options: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
user: MockUser,
|
||||
permissions: {
|
||||
createUser: true,
|
||||
updateUsers: true,
|
||||
viewDeploymentValues: true,
|
||||
},
|
||||
};
|
||||
|
||||
const meta: Meta<typeof UsersPage> = {
|
||||
title: "pages/UsersPage",
|
||||
component: UsersPage,
|
||||
parameters,
|
||||
decorators: [withGlobalSnackbar, withAuthProvider, withDashboardProvider],
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof UsersPage>;
|
||||
|
||||
export const Loaded: Story = {};
|
||||
|
||||
export const SuspendUserSuccess: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const user = userEvent.setup();
|
||||
const userRow = canvasElement.querySelector<HTMLElement>("tbody tr");
|
||||
if (!userRow) {
|
||||
throw new Error("No user row found");
|
||||
}
|
||||
|
||||
// Return the updated user in the suspended response and ensure the users
|
||||
// query will return updated data.
|
||||
const updatedUser: User = { ...MockUsers[0], status: "suspended" };
|
||||
spyOn(API, "suspendUser").mockResolvedValue(updatedUser);
|
||||
spyOn(API, "getUsers").mockResolvedValue({
|
||||
users: replaceUser(MockUsers, 0, updatedUser),
|
||||
count: 60,
|
||||
});
|
||||
|
||||
await user.click(within(userRow).getByLabelText("More options"));
|
||||
const suspendButton = await within(userRow).findByText("Suspend", {
|
||||
exact: false,
|
||||
});
|
||||
await user.click(suspendButton);
|
||||
|
||||
const dialog = await within(document.body).findByRole("dialog");
|
||||
await user.click(within(dialog).getByRole("button", { name: "Suspend" }));
|
||||
await within(document.body).findByText("Successfully suspended the user.");
|
||||
},
|
||||
};
|
||||
|
||||
export const SuspendUserError: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const user = userEvent.setup();
|
||||
const userRow = canvasElement.querySelector<HTMLElement>("tbody tr");
|
||||
if (!userRow) {
|
||||
throw new Error("No user row found");
|
||||
}
|
||||
spyOn(API, "suspendUser").mockRejectedValue(undefined);
|
||||
|
||||
await user.click(within(userRow).getByLabelText("More options"));
|
||||
const suspendButton = await within(userRow).findByText("Suspend", {
|
||||
exact: false,
|
||||
});
|
||||
await user.click(suspendButton);
|
||||
|
||||
const dialog = await within(document.body).findByRole("dialog");
|
||||
await user.click(within(dialog).getByRole("button", { name: "Suspend" }));
|
||||
await within(document.body).findByText("Error suspending user.");
|
||||
},
|
||||
};
|
||||
|
||||
export const DeleteUserSuccess: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const user = userEvent.setup();
|
||||
const userRow = canvasElement.querySelector<HTMLElement>("tbody tr");
|
||||
if (!userRow) {
|
||||
throw new Error("No user row found");
|
||||
}
|
||||
|
||||
// The delete user operation does not return a value. However, we need to
|
||||
// ensure that the updated list of users, excluding the deleted one, is
|
||||
// returned when the users query is refetched.
|
||||
spyOn(API, "deleteUser").mockResolvedValue();
|
||||
spyOn(API, "getUsers").mockResolvedValue({
|
||||
users: MockUsers.slice(1),
|
||||
count: 59,
|
||||
});
|
||||
|
||||
await user.click(within(userRow).getByLabelText("More options"));
|
||||
const deleteButton = await within(userRow).findByText("Delete", {
|
||||
exact: false,
|
||||
});
|
||||
await user.click(deleteButton);
|
||||
|
||||
const dialog = await within(document.body).findByRole("dialog");
|
||||
const input = within(dialog).getByLabelText("Name of the user to delete");
|
||||
await user.type(input, MockUsers[0].username);
|
||||
await user.click(within(dialog).getByRole("button", { name: "Delete" }));
|
||||
await within(document.body).findByText("Successfully deleted the user.");
|
||||
},
|
||||
};
|
||||
|
||||
export const DeleteUserError: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const user = userEvent.setup();
|
||||
const userRow = canvasElement.querySelector<HTMLElement>("tbody tr");
|
||||
if (!userRow) {
|
||||
throw new Error("No user row found");
|
||||
}
|
||||
spyOn(API, "deleteUser").mockRejectedValue({});
|
||||
|
||||
await user.click(within(userRow).getByLabelText("More options"));
|
||||
const deleteButton = await within(userRow).findByText("Delete", {
|
||||
exact: false,
|
||||
});
|
||||
await user.click(deleteButton);
|
||||
|
||||
const dialog = await within(document.body).findByRole("dialog");
|
||||
const input = within(dialog).getByLabelText("Name of the user to delete");
|
||||
await user.type(input, MockUsers[0].username);
|
||||
await user.click(within(dialog).getByRole("button", { name: "Delete" }));
|
||||
await within(document.body).findByText("Error deleting user.");
|
||||
},
|
||||
};
|
||||
|
||||
export const ActivateUserSuccess: Story = {
|
||||
parameters: {
|
||||
queries: [
|
||||
...parameters.queries,
|
||||
// To activate a user, the user must be suspended first. Since we use the
|
||||
// first user in the test, we need to ensure it is suspended.
|
||||
{
|
||||
key: usersKey({ limit: 25, offset: 0, q: "" }),
|
||||
data: {
|
||||
users: replaceUser(MockUsers, 0, {
|
||||
...MockUsers[0],
|
||||
status: "suspended",
|
||||
}),
|
||||
count: 60,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const user = userEvent.setup();
|
||||
const userRow = canvasElement.querySelector<HTMLElement>("tbody tr");
|
||||
if (!userRow) {
|
||||
throw new Error("No user row found");
|
||||
}
|
||||
|
||||
// Return the updated user in the activate response and ensure the users
|
||||
// query will return updated data.
|
||||
const updatedUser: User = { ...MockUsers[0], status: "active" };
|
||||
spyOn(API, "activateUser").mockResolvedValue(updatedUser);
|
||||
spyOn(API, "getUsers").mockResolvedValue({
|
||||
users: replaceUser(MockUsers, 0, updatedUser),
|
||||
count: 60,
|
||||
});
|
||||
|
||||
await user.click(within(userRow).getByLabelText("More options"));
|
||||
const activateButton = await within(userRow).findByText("Activate", {
|
||||
exact: false,
|
||||
});
|
||||
await user.click(activateButton);
|
||||
|
||||
const dialog = await within(document.body).findByRole("dialog");
|
||||
await user.click(within(dialog).getByRole("button", { name: "Activate" }));
|
||||
await within(document.body).findByText("Successfully activated the user.");
|
||||
},
|
||||
};
|
||||
|
||||
export const ActivateUserError: Story = {
|
||||
parameters: ActivateUserSuccess.parameters,
|
||||
play: async ({ canvasElement }) => {
|
||||
const user = userEvent.setup();
|
||||
const userRow = canvasElement.querySelector<HTMLElement>("tbody tr");
|
||||
if (!userRow) {
|
||||
throw new Error("No user row found");
|
||||
}
|
||||
spyOn(API, "activateUser").mockRejectedValue({});
|
||||
|
||||
await user.click(within(userRow).getByLabelText("More options"));
|
||||
const activateButton = await within(userRow).findByText("Activate", {
|
||||
exact: false,
|
||||
});
|
||||
await user.click(activateButton);
|
||||
|
||||
const dialog = await within(document.body).findByRole("dialog");
|
||||
await user.click(within(dialog).getByRole("button", { name: "Activate" }));
|
||||
await within(document.body).findByText("Error activating user.");
|
||||
},
|
||||
};
|
||||
|
||||
export const ResetUserPasswordSuccess: Story = {
|
||||
parameters: {
|
||||
queries: [
|
||||
...parameters.queries,
|
||||
// Ensure the first user's login type is set to 'password' to reset their
|
||||
// password during the test.
|
||||
{
|
||||
key: usersKey({ limit: 25, offset: 0, q: "" }),
|
||||
data: {
|
||||
users: MockUsers.map((u, i) => {
|
||||
return i === 0 ? { ...u, login_type: "password" } : u;
|
||||
}),
|
||||
count: 60,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const user = userEvent.setup();
|
||||
const userRow = canvasElement.querySelector<HTMLElement>("tbody tr");
|
||||
if (!userRow) {
|
||||
throw new Error("No user row found");
|
||||
}
|
||||
spyOn(API, "updateUserPassword").mockResolvedValue();
|
||||
|
||||
await user.click(within(userRow).getByLabelText("More options"));
|
||||
const resetPasswordButton = await within(userRow).findByText(
|
||||
"Reset password",
|
||||
{ exact: false },
|
||||
);
|
||||
await user.click(resetPasswordButton);
|
||||
|
||||
const dialog = await within(document.body).findByRole("dialog");
|
||||
await user.click(
|
||||
within(dialog).getByRole("button", { name: "Reset password" }),
|
||||
);
|
||||
await within(document.body).findByText(
|
||||
"Successfully updated the user password.",
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const ResetUserPasswordError: Story = {
|
||||
parameters: ResetUserPasswordSuccess.parameters,
|
||||
play: async ({ canvasElement }) => {
|
||||
const user = userEvent.setup();
|
||||
const userRow = canvasElement.querySelector<HTMLElement>("tbody tr");
|
||||
if (!userRow) {
|
||||
throw new Error("No user row found");
|
||||
}
|
||||
spyOn(API, "updateUserPassword").mockRejectedValue({});
|
||||
|
||||
await user.click(within(userRow).getByLabelText("More options"));
|
||||
const resetPasswordButton = await within(userRow).findByText(
|
||||
"Reset password",
|
||||
{ exact: false },
|
||||
);
|
||||
await user.click(resetPasswordButton);
|
||||
|
||||
const dialog = await within(document.body).findByRole("dialog");
|
||||
await user.click(
|
||||
within(dialog).getByRole("button", { name: "Reset password" }),
|
||||
);
|
||||
await within(document.body).findByText(
|
||||
"Error on resetting the user password.",
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const UpdateUserRoleSuccess: Story = {
|
||||
parameters: {
|
||||
queries: [
|
||||
...parameters.queries,
|
||||
// Ensure the first user has the 'owner' role to test the edit functionality.
|
||||
{
|
||||
key: usersKey({ limit: 25, offset: 0, q: "" }),
|
||||
data: {
|
||||
users: replaceUser(MockUsers, 0, {
|
||||
...MockUsers[0],
|
||||
roles: [
|
||||
{ name: "owner", display_name: "Owner" },
|
||||
// We will update the user role to include auditor
|
||||
{ name: "auditor", display_name: "Auditor" },
|
||||
],
|
||||
}),
|
||||
count: 60,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const user = userEvent.setup();
|
||||
const userRow = canvasElement.querySelector<HTMLElement>("tbody tr");
|
||||
if (!userRow) {
|
||||
throw new Error("No user row found");
|
||||
}
|
||||
|
||||
// Return the updated user in the update roles response and ensure the users
|
||||
// query will return updated data.
|
||||
const updatedUser: User = {
|
||||
...MockUsers[0],
|
||||
roles: [
|
||||
{ name: "owner", display_name: "Owner" },
|
||||
// We will update the user role to include auditor
|
||||
{ name: "auditor", display_name: "Auditor" },
|
||||
],
|
||||
};
|
||||
spyOn(API, "updateUserRoles").mockResolvedValue(updatedUser);
|
||||
spyOn(API, "getUsers").mockResolvedValue({
|
||||
users: replaceUser(MockUsers, 0, updatedUser),
|
||||
count: 60,
|
||||
});
|
||||
|
||||
await user.click(within(userRow).getByLabelText("Edit user roles"));
|
||||
await user.click(
|
||||
within(userRow).getByLabelText("Auditor", { exact: false }),
|
||||
);
|
||||
await within(document.body).findByText(
|
||||
"Successfully updated the user roles.",
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const UpdateUserRoleError: Story = {
|
||||
parameters: UpdateUserRoleSuccess.parameters,
|
||||
play: async ({ canvasElement }) => {
|
||||
const user = userEvent.setup();
|
||||
const userRow = canvasElement.querySelector<HTMLElement>("tbody tr");
|
||||
if (!userRow) {
|
||||
throw new Error("No user row found");
|
||||
}
|
||||
spyOn(API, "updateUserRoles").mockRejectedValue({});
|
||||
|
||||
await user.click(within(userRow).getByLabelText("Edit user roles"));
|
||||
await user.click(
|
||||
within(userRow).getByLabelText("Auditor", { exact: false }),
|
||||
);
|
||||
await within(document.body).findByText("Error on updating the user roles.");
|
||||
},
|
||||
};
|
||||
|
||||
function replaceUser(users: User[], index: number, user: User) {
|
||||
return users.map((u, i) => (i === index ? user : u));
|
||||
}
|
||||
@@ -1,340 +0,0 @@
|
||||
import { fireEvent, screen, within } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { API } from "api/api";
|
||||
import type { SlimRole } from "api/typesGenerated";
|
||||
import { http, HttpResponse } from "msw";
|
||||
import {
|
||||
MockAuditorRole,
|
||||
MockUser,
|
||||
MockUser2,
|
||||
SuspendedMockUser,
|
||||
} from "testHelpers/entities";
|
||||
import { renderWithAuth } from "testHelpers/renderHelpers";
|
||||
import { server } from "testHelpers/server";
|
||||
import { Language as ResetPasswordDialogLanguage } from "./ResetPasswordDialog";
|
||||
import UsersPage from "./UsersPage";
|
||||
|
||||
jest.spyOn(console, "error").mockImplementation(() => {});
|
||||
|
||||
const renderPage = () => {
|
||||
return renderWithAuth(<UsersPage />);
|
||||
};
|
||||
|
||||
const suspendUser = async () => {
|
||||
const user = userEvent.setup();
|
||||
// Get the first user in the table
|
||||
const moreButtons = await screen.findAllByLabelText("More options");
|
||||
const firstMoreButton = moreButtons[0];
|
||||
await user.click(firstMoreButton);
|
||||
|
||||
const suspendButton = screen.getByTestId("suspend-button");
|
||||
await user.click(suspendButton);
|
||||
|
||||
// Check if the confirm message is displayed
|
||||
const confirmDialog = await screen.findByRole("dialog");
|
||||
const confirmButton = await within(confirmDialog).findByRole("button", {
|
||||
name: "Suspend",
|
||||
});
|
||||
await user.click(confirmButton);
|
||||
};
|
||||
|
||||
const deleteUser = async () => {
|
||||
const user = userEvent.setup();
|
||||
// Click on the "More options" button to display the "Delete" option
|
||||
// Needs to await fetching users and fetching permissions, because they're needed to see the more button
|
||||
const moreButtons = await screen.findAllByLabelText("More options");
|
||||
// get MockUser2
|
||||
const selectedMoreButton = moreButtons[1];
|
||||
|
||||
await user.click(selectedMoreButton);
|
||||
|
||||
const deleteButton = screen.getByText(/Delete/);
|
||||
await user.click(deleteButton);
|
||||
|
||||
// Confirm with text input
|
||||
const textField = screen.getByLabelText("Name of the user to delete");
|
||||
const dialog = screen.getByRole("dialog");
|
||||
await user.type(textField, MockUser2.username);
|
||||
|
||||
// Click on the "Confirm" button
|
||||
const confirmButton = within(dialog).getByRole("button", { name: "Delete" });
|
||||
await user.click(confirmButton);
|
||||
};
|
||||
|
||||
const activateUser = async () => {
|
||||
const moreButtons = await screen.findAllByLabelText("More options");
|
||||
const suspendedMoreButton = moreButtons[2];
|
||||
fireEvent.click(suspendedMoreButton);
|
||||
|
||||
const activateButton = screen.getByText(/Activate/);
|
||||
fireEvent.click(activateButton);
|
||||
|
||||
// Check if the confirm message is displayed
|
||||
const confirmDialog = screen.getByRole("dialog");
|
||||
|
||||
// Click on the "Confirm" button
|
||||
const confirmButton = within(confirmDialog).getByRole("button", {
|
||||
name: "Activate",
|
||||
});
|
||||
fireEvent.click(confirmButton);
|
||||
};
|
||||
|
||||
const resetUserPassword = async (setupActionSpies: () => void) => {
|
||||
const moreButtons = await screen.findAllByLabelText("More options");
|
||||
const firstMoreButton = moreButtons[0];
|
||||
fireEvent.click(firstMoreButton);
|
||||
|
||||
const resetPasswordButton = screen.getByText(/Reset password/);
|
||||
fireEvent.click(resetPasswordButton);
|
||||
|
||||
// Check if the confirm message is displayed
|
||||
const confirmDialog = screen.getByRole("dialog");
|
||||
expect(confirmDialog).toHaveTextContent(
|
||||
`You will need to send ${MockUser.username} the following password:`,
|
||||
);
|
||||
|
||||
// Setup spies to check the actions after
|
||||
setupActionSpies();
|
||||
|
||||
// Click on the "Confirm" button
|
||||
const confirmButton = within(confirmDialog).getByRole("button", {
|
||||
name: ResetPasswordDialogLanguage.confirmText,
|
||||
});
|
||||
|
||||
fireEvent.click(confirmButton);
|
||||
};
|
||||
|
||||
const updateUserRole = async (role: SlimRole) => {
|
||||
// Get the first user in the table
|
||||
const users = await screen.findAllByText(/.*@coder.com/);
|
||||
const userRow = users[0].closest("tr");
|
||||
if (!userRow) {
|
||||
throw new Error("Error on get the first user row");
|
||||
}
|
||||
|
||||
// Click on the "edit icon" to display the role options
|
||||
const editButton = within(userRow).getByTitle("Edit user roles");
|
||||
fireEvent.click(editButton);
|
||||
|
||||
// Click on the role option
|
||||
const fieldset = await screen.findByTitle("Available roles");
|
||||
const roleOption = within(fieldset).getByText(role.display_name);
|
||||
fireEvent.click(roleOption);
|
||||
|
||||
return {
|
||||
userRow,
|
||||
};
|
||||
};
|
||||
|
||||
describe("UsersPage", () => {
|
||||
describe("suspend user", () => {
|
||||
describe("when it is success", () => {
|
||||
it("shows a success message", async () => {
|
||||
renderPage();
|
||||
|
||||
server.use(
|
||||
http.put(`/api/v2/users/${MockUser.id}/status/suspend`, async () => {
|
||||
return HttpResponse.json(SuspendedMockUser);
|
||||
}),
|
||||
);
|
||||
|
||||
await suspendUser();
|
||||
|
||||
// Check if the success message is displayed
|
||||
await screen.findByText("Successfully suspended the user.");
|
||||
});
|
||||
});
|
||||
|
||||
describe("when it fails", () => {
|
||||
it("shows an error message", async () => {
|
||||
renderPage();
|
||||
|
||||
server.use(
|
||||
http.put(`/api/v2/users/${MockUser.id}/status/suspend`, async () => {
|
||||
return HttpResponse.json(
|
||||
{
|
||||
message: "Error suspending user.",
|
||||
},
|
||||
{ status: 400 },
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
await suspendUser();
|
||||
|
||||
// Check if the error message is displayed
|
||||
await screen.findByText("Error suspending user.");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("delete user", () => {
|
||||
describe("when it is success", () => {
|
||||
it("shows a success message", async () => {
|
||||
renderPage();
|
||||
|
||||
server.use(
|
||||
http.delete(`/api/v2/users/${MockUser2.id}`, async () => {
|
||||
return HttpResponse.json(MockUser2);
|
||||
}),
|
||||
);
|
||||
|
||||
await deleteUser();
|
||||
|
||||
// Check if the success message is displayed
|
||||
await screen.findByText("Successfully deleted the user.");
|
||||
});
|
||||
});
|
||||
describe("when it fails", () => {
|
||||
it("shows an error message", async () => {
|
||||
renderPage();
|
||||
|
||||
server.use(
|
||||
http.delete(`/api/v2/users/${MockUser2.id}`, async () => {
|
||||
return HttpResponse.json(
|
||||
{
|
||||
message: "Error deleting user.",
|
||||
},
|
||||
{ status: 400 },
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
await deleteUser();
|
||||
|
||||
// Check if the error message is displayed
|
||||
await screen.findByText("Error deleting user.");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("activate user", () => {
|
||||
describe("when user is successfully activated", () => {
|
||||
it("shows a success message and refreshes the page", async () => {
|
||||
renderPage();
|
||||
|
||||
server.use(
|
||||
http.put(
|
||||
`/api/v2/users/${SuspendedMockUser.id}/status/activate`,
|
||||
async () => {
|
||||
return HttpResponse.json(MockUser);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
await activateUser();
|
||||
|
||||
// Check if the success message is displayed
|
||||
await screen.findByText("Successfully activated the user.");
|
||||
});
|
||||
});
|
||||
describe("when activation fails", () => {
|
||||
it("shows an error message", async () => {
|
||||
renderPage();
|
||||
|
||||
server.use(
|
||||
http.put(
|
||||
`/api/v2/users/${SuspendedMockUser.id}/status/activate`,
|
||||
async () => {
|
||||
return HttpResponse.json(
|
||||
{
|
||||
message: "Error activating user.",
|
||||
},
|
||||
{ status: 400 },
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
await activateUser();
|
||||
|
||||
// Check if the error message is displayed
|
||||
await screen.findByText("Error activating user.");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("reset user password", () => {
|
||||
describe("when it is success", () => {
|
||||
it("shows a success message", async () => {
|
||||
renderPage();
|
||||
|
||||
await resetUserPassword(() => {
|
||||
jest
|
||||
.spyOn(API, "updateUserPassword")
|
||||
.mockResolvedValueOnce(undefined);
|
||||
});
|
||||
|
||||
// Check if the success message is displayed
|
||||
await screen.findByText("Successfully updated the user password.");
|
||||
|
||||
// Check if the API was called correctly
|
||||
expect(API.updateUserPassword).toBeCalledTimes(1);
|
||||
expect(API.updateUserPassword).toBeCalledWith(MockUser.id, {
|
||||
password: expect.any(String),
|
||||
old_password: "",
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("when it fails", () => {
|
||||
it("shows an error message", async () => {
|
||||
renderPage();
|
||||
|
||||
await resetUserPassword(() => {
|
||||
jest.spyOn(API, "updateUserPassword").mockRejectedValueOnce({});
|
||||
});
|
||||
|
||||
// Check if the error message is displayed
|
||||
await screen.findByText("Error on resetting the user password.");
|
||||
|
||||
// Check if the API was called correctly
|
||||
expect(API.updateUserPassword).toBeCalledTimes(1);
|
||||
expect(API.updateUserPassword).toBeCalledWith(MockUser.id, {
|
||||
password: expect.any(String),
|
||||
old_password: "",
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Update user role", () => {
|
||||
describe("when it is success", () => {
|
||||
it("updates the roles", async () => {
|
||||
renderPage();
|
||||
|
||||
server.use(
|
||||
http.put(`/api/v2/users/${MockUser.id}/roles`, async () => {
|
||||
return HttpResponse.json({
|
||||
...MockUser,
|
||||
roles: [...MockUser.roles, MockAuditorRole],
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
await updateUserRole(MockAuditorRole);
|
||||
|
||||
await screen.findByText("Successfully updated the user roles.");
|
||||
});
|
||||
});
|
||||
|
||||
describe("when it fails", () => {
|
||||
it("shows an error message", async () => {
|
||||
renderPage();
|
||||
|
||||
server.use(
|
||||
http.put(`/api/v2/users/${MockUser.id}/roles`, () => {
|
||||
return HttpResponse.json(
|
||||
{ message: "Error on updating the user roles." },
|
||||
{ status: 400 },
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
await updateUserRole(MockAuditorRole);
|
||||
|
||||
// Check if the error message is displayed
|
||||
await screen.findByText("Error on updating the user roles.");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -172,8 +172,11 @@ const UsersPage: FC = () => {
|
||||
entity="user"
|
||||
onCancel={() => setUserToDelete(undefined)}
|
||||
onConfirm={async () => {
|
||||
if (!userToDelete) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await deleteUserMutation.mutateAsync(userToDelete!.id);
|
||||
await deleteUserMutation.mutateAsync(userToDelete.id);
|
||||
setUserToDelete(undefined);
|
||||
displaySuccess("Successfully deleted the user.");
|
||||
} catch (e) {
|
||||
@@ -191,8 +194,11 @@ const UsersPage: FC = () => {
|
||||
confirmText="Suspend"
|
||||
onClose={() => setUserToSuspend(undefined)}
|
||||
onConfirm={async () => {
|
||||
if (!userToSuspend) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await suspendUserMutation.mutateAsync(userToSuspend!.id);
|
||||
await suspendUserMutation.mutateAsync(userToSuspend.id);
|
||||
setUserToSuspend(undefined);
|
||||
displaySuccess("Successfully suspended the user.");
|
||||
} catch (e) {
|
||||
@@ -216,8 +222,11 @@ const UsersPage: FC = () => {
|
||||
confirmText="Activate"
|
||||
onClose={() => setUserToActivate(undefined)}
|
||||
onConfirm={async () => {
|
||||
if (!userToActivate) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await activateUserMutation.mutateAsync(userToActivate!.id);
|
||||
await activateUserMutation.mutateAsync(userToActivate.id);
|
||||
setUserToActivate(undefined);
|
||||
displaySuccess("Successfully activated the user.");
|
||||
} catch (e) {
|
||||
@@ -242,10 +251,13 @@ const UsersPage: FC = () => {
|
||||
setConfirmResetPassword(undefined);
|
||||
}}
|
||||
onConfirm={async () => {
|
||||
if (!confirmResetPassword) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await updatePasswordMutation.mutateAsync({
|
||||
userId: confirmResetPassword!.user.id,
|
||||
password: confirmResetPassword!.newPassword,
|
||||
userId: confirmResetPassword.user.id,
|
||||
password: confirmResetPassword.newPassword,
|
||||
old_password: "",
|
||||
});
|
||||
setConfirmResetPassword(undefined);
|
||||
|
||||
@@ -28,7 +28,7 @@ const defaultFilterProps = getDefaultFilterProps<FilterProps>({
|
||||
});
|
||||
|
||||
const meta: Meta<typeof UsersPageView> = {
|
||||
title: "pages/UsersPage",
|
||||
title: "pages/UsersPageView",
|
||||
component: UsersPageView,
|
||||
args: {
|
||||
isNonInitialPage: false,
|
||||
|
||||
@@ -0,0 +1,544 @@
|
||||
import type { Group, GroupSource, User } from "api/typesGenerated";
|
||||
import { MockUsers } from "./users";
|
||||
|
||||
function findMockedUserById(id: string): User | undefined {
|
||||
const user = MockUsers.find((user) => user.id === id);
|
||||
return user;
|
||||
}
|
||||
|
||||
// These values were retrieved from the Coder API. Sensitive information such as
|
||||
// usernames, names, and emails has been replaced with fake user data to protect
|
||||
// privacy. This user data comes from the MockUsers to keep consistency.
|
||||
export const MockGroups: Group[] = [
|
||||
{
|
||||
id: "7621bbb4-5b04-4957-8419-cf4a683ac59a",
|
||||
name: "Everyone",
|
||||
display_name: "",
|
||||
organization_id: "7621bbb4-5b04-4957-8419-cf4a683ac59a",
|
||||
members: [findMockedUserById("5ccd3128-cbbb-4cfb-8139-5a1edbb60c71")],
|
||||
total_member_count: 1,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "data-platform",
|
||||
organization_display_name: "Data Platform",
|
||||
},
|
||||
{
|
||||
id: "d6f9d037-b9cd-4716-b424-64ef8f81e7f7",
|
||||
name: "Contractors",
|
||||
display_name: "",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [
|
||||
findMockedUserById("c5b28cf0-f72a-4b45-b3d5-00d3989d4ed5"),
|
||||
findMockedUserById("4c8ffd9b-7bc8-47db-9322-f4d5e0b51658"),
|
||||
],
|
||||
total_member_count: 2,
|
||||
avatar_url: "",
|
||||
quota_allowance: 10,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "82773b01-c3b3-4747-a956-d824293dd857",
|
||||
name: "Empty-other",
|
||||
display_name: "",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [
|
||||
findMockedUserById("af657bc3-6949-4b1b-bc2d-d41a40b546a4"),
|
||||
findMockedUserById("a73425d1-53a7-43d3-b6ae-cae9ba59b92b"),
|
||||
],
|
||||
total_member_count: 2,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "4522d478-04b2-4ced-9cf2-8f2ecbe73188",
|
||||
name: "DevOps",
|
||||
display_name: "",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [
|
||||
findMockedUserById("3f8c0eef-6a45-4759-a4d6-d00bbffb1369"),
|
||||
findMockedUserById("740bba7f-356d-4203-8f15-03ddee381998"),
|
||||
findMockedUserById("12b03f43-1bb7-4fca-967a-585c97f31682"),
|
||||
findMockedUserById("a73425d1-53a7-43d3-b6ae-cae9ba59b92b"),
|
||||
findMockedUserById("0bac0dfd-b086-4b6d-b8ba-789e0eca7451"),
|
||||
],
|
||||
total_member_count: 5,
|
||||
avatar_url: "/emojis/1fa84.png",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "d00ea21b-3eec-4f63-a0cd-acb00e3a2116",
|
||||
name: "ms-test-group",
|
||||
display_name: "display-name",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [findMockedUserById("ef2eebf7-9708-4076-9f71-a34af71f5d24")],
|
||||
total_member_count: 1,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "f7200783-62c0-4bfa-ae30-a542fc82dc8d",
|
||||
name: "Tinkerers",
|
||||
display_name: "",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [
|
||||
findMockedUserById("15890ddb-142c-443d-8fd5-cd8307256ab1"),
|
||||
findMockedUserById("ef2eebf7-9708-4076-9f71-a34af71f5d24"),
|
||||
findMockedUserById("af657bc3-6949-4b1b-bc2d-d41a40b546a4"),
|
||||
findMockedUserById("0bac0dfd-b086-4b6d-b8ba-789e0eca7451"),
|
||||
],
|
||||
total_member_count: 4,
|
||||
avatar_url: "/emojis/1f34c.png",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "e690870a-b24f-48fd-b75b-eee89098d588",
|
||||
name: "underscored_group",
|
||||
display_name: "",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [],
|
||||
total_member_count: 0,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "fd6ea877-06b6-4c03-b7c0-ea8f0707425b",
|
||||
name: "Sales",
|
||||
display_name: "",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [
|
||||
findMockedUserById("dd91e5f1-0e10-434e-9305-02129a6e4fdb"),
|
||||
findMockedUserById("829a99f8-4c4a-4280-9500-fb21f3afb201"),
|
||||
findMockedUserById("740bba7f-356d-4203-8f15-03ddee381998"),
|
||||
findMockedUserById("fdc2dab9-dabd-4980-843f-2e93042db566"),
|
||||
findMockedUserById("0bac0dfd-b086-4b6d-b8ba-789e0eca7451"),
|
||||
],
|
||||
total_member_count: 5,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "8b1539c5-6f5c-4630-a715-53b74c444e86",
|
||||
name: "eeee",
|
||||
display_name: "aaaaaa",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [],
|
||||
total_member_count: 0,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "a26c335f-1498-48e2-bd66-c6a5783fa5f2",
|
||||
name: "bruno-group",
|
||||
display_name: "",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [findMockedUserById("1c2baba2-40d6-4b9e-a788-fe393c1dbdbb")],
|
||||
total_member_count: 1,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "900074db-46ce-4165-9938-3f719348fd36",
|
||||
name: "F̷̡̮̩̞̺̹͔͇͖͇͊̓̈́̐̈́̃͋̀͂͂̄͘̚o̵̻̲̤̥͚͙͚̬͉͚̼̦̹̙͈̞̎̃͑̽̂͂̒͋̊̐̊̌̌͝r̶̭̖͊̊̕͘ḃ̵̢̡͍͎̝̲̼͔̩̥͎͕̪͂͜î̶̡͍̖̿̏̈̔̽͘͜d̶̼͔̜̰͛̂̊̆d̴̛̦̰̩̦̬͈͖̪͖̓̈́̊͂͝͠e̷̛̬̻͌̇́̃̌̓͠ń̴̙͖̉͐͌͌̎́͘̕͝",
|
||||
display_name: "F̷̡̮̩̞̺̹͔͇͖͇͊̓̈́̐̈́̃͋̀͂͂̄͘̚o̵̻̲̤̥͚͙͚̬͉͚̼̦̹̙͈̞̎̃͑̽̂͂̒͋̊̐̊̌̌͝r̶̭̖͊̊̕͘ḃ̵̢̡͍͎̝̲̼͔̩̥͎͕̪͂͜î̶̡͍̖̿̏̈̔̽͘͜d̶̼͔̜̰͛̂̊̆d̴̛̦̰̩̦̬͈͖̪͖̓̈́̊͂͝͠e̷̛̬̻͌̇́̃̌̓͠ń̴̙͖̉͐͌͌̎́͘̕͝",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [],
|
||||
total_member_count: 0,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "85020b78-2a36-4bd4-b00c-7b88dab6e333",
|
||||
name: "hi",
|
||||
display_name: "",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [],
|
||||
total_member_count: 0,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "5f8996c6-b3ba-4e39-97a1-dd44a73951de",
|
||||
name: "Winners",
|
||||
display_name: "",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [findMockedUserById("c5eb8310-cf4f-444c-b223-0e991f828b40")],
|
||||
total_member_count: 1,
|
||||
avatar_url: "",
|
||||
quota_allowance: 1000,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "0c6c1222-b65e-44c1-8bff-078d27fc10e6",
|
||||
name: "Some-group",
|
||||
display_name: "",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [],
|
||||
total_member_count: 0,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "394222ed-7559-47a8-a57c-1bc7998c0357",
|
||||
name: "kira-test",
|
||||
display_name: "kira-test",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [],
|
||||
total_member_count: 0,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
name: "Everyone",
|
||||
display_name: "",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [
|
||||
findMockedUserById("31d3fcc5-618e-48ab-80b9-dab8d9aba077"),
|
||||
findMockedUserById("bdbc1534-ba10-47be-a7cb-12a02de7a2c1"),
|
||||
findMockedUserById("a73425d1-53a7-43d3-b6ae-cae9ba59b92b"),
|
||||
findMockedUserById("9e7815af-bc48-435a-91c7-72dcbf26f036"),
|
||||
findMockedUserById("f787e795-b502-41a3-ad79-fe1cb7d3403a"),
|
||||
findMockedUserById("e97579fe-31c2-4e83-85d1-7241bf97ba4b"),
|
||||
findMockedUserById("b10bbeed-074f-472c-b454-c2525eba6c44"),
|
||||
findMockedUserById("0f452b63-64cb-4422-99ea-7391ccf7b4d5"),
|
||||
findMockedUserById("bd644669-f7f4-48e6-be38-e37b5017c24f"),
|
||||
findMockedUserById("f8f6345f-8751-4a37-87c7-a2f6325a248f"),
|
||||
findMockedUserById("a28e6213-b339-46e8-94ec-310d39ac8acb"),
|
||||
findMockedUserById("59da0bfe-9c99-47fa-a563-f9fdb18449d0"),
|
||||
findMockedUserById("1355d2c6-6505-4e64-b93b-1258bbe35f02"),
|
||||
findMockedUserById("4832f5d9-9773-4ea1-a65c-1b818c8cfae5"),
|
||||
findMockedUserById("9be730b0-37ce-4216-84dd-6a851d21436e"),
|
||||
findMockedUserById("f9c75a4e-9884-433a-80c9-2613bffbaf3f"),
|
||||
findMockedUserById("49ded266-e150-4213-826c-7f721f2b9a36"),
|
||||
findMockedUserById("00738e55-91cc-47bc-a494-206c8025b887"),
|
||||
findMockedUserById("c0240345-f14a-4632-b713-a0f09c2ed927"),
|
||||
findMockedUserById("ab872758-4f67-4b73-8d7d-460d83604990"),
|
||||
findMockedUserById("2a256f0b-625d-4afc-929c-0ad687141ebd"),
|
||||
findMockedUserById("4fde2562-7ec6-4ce7-b7de-359346641d6b"),
|
||||
findMockedUserById("4b9a6fda-c60d-4fb2-96fd-b872d1eebee9"),
|
||||
findMockedUserById("350441af-b2d3-401f-a795-39971f0a682b"),
|
||||
findMockedUserById("e67fbe91-384a-41f0-9836-0b8cea0dd7c8"),
|
||||
findMockedUserById("8099295b-d6bd-409b-b500-e31a12e54679"),
|
||||
findMockedUserById("b81dc9eb-af70-4ccd-840f-bab9d2c1bde5"),
|
||||
findMockedUserById("5bb278fe-a70f-4b5e-9eed-5df7d0e43f6b"),
|
||||
findMockedUserById("c5eb8310-cf4f-444c-b223-0e991f828b40"),
|
||||
findMockedUserById("8b474a55-d414-4b53-a6ba-760f3d4eed7b"),
|
||||
findMockedUserById("6a973d35-8e8e-4ff4-9f95-436d62e13d6f"),
|
||||
findMockedUserById("1c2baba2-40d6-4b9e-a788-fe393c1dbdbb"),
|
||||
findMockedUserById("5819ca76-94ba-4009-b924-ae077fe9c615"),
|
||||
findMockedUserById("1c3e3fff-6a0e-4179-9ba3-27f5443e6fce"),
|
||||
findMockedUserById("5ccd3128-cbbb-4cfb-8139-5a1edbb60c71"),
|
||||
findMockedUserById("bece715d-0145-45f6-97f1-42bd66b63959"),
|
||||
findMockedUserById("a34ed13c-9157-426b-8029-de02292eeaa2"),
|
||||
findMockedUserById("dd91e5f1-0e10-434e-9305-02129a6e4fdb"),
|
||||
findMockedUserById("135e83f1-ff91-4f91-8d23-f7e7fa6627f1"),
|
||||
findMockedUserById("2e1e7f76-ae77-424a-a209-f35a99731ec9"),
|
||||
findMockedUserById("6ed718bc-9b36-4120-bd5c-e809163ecef1"),
|
||||
findMockedUserById("d1e1792a-221d-413b-a7f4-51f33f395a9b"),
|
||||
findMockedUserById("c79f306f-4816-4ca9-8990-55406a45bdb5"),
|
||||
findMockedUserById("7a9f4857-e9c5-4f6c-8e1d-0827df5d753b"),
|
||||
findMockedUserById("9e3e4c5a-5949-417f-9380-d0a393c78bdd"),
|
||||
findMockedUserById("f2cdaba3-e0a3-447a-b186-eb10dc1d1d49"),
|
||||
findMockedUserById("3f8c0eef-6a45-4759-a4d6-d00bbffb1369"),
|
||||
findMockedUserById("bbaaa01d-b453-4079-b85e-74d333cc8b32"),
|
||||
findMockedUserById("d9522d62-f20d-463a-b07d-0c0e2b031907"),
|
||||
findMockedUserById("ae6024dc-5fe5-4d60-b19e-b8ef91e9504e"),
|
||||
findMockedUserById("21fe9106-02bb-45c7-8d48-8eda6378991e"),
|
||||
findMockedUserById("806e35bb-37fd-4810-b5f2-88aa47c30c84"),
|
||||
findMockedUserById("b3e1b884-1a5b-44eb-b8b3-423f8eddc503"),
|
||||
findMockedUserById("c57dd581-872f-4290-bb48-341554ae537b"),
|
||||
findMockedUserById("81e915cb-5064-41f7-b654-c96c846424e6"),
|
||||
findMockedUserById("12b03f43-1bb7-4fca-967a-585c97f31682"),
|
||||
findMockedUserById("15890ddb-142c-443d-8fd5-cd8307256ab1"),
|
||||
findMockedUserById("86e0067c-a4d5-4b75-9cf5-c605badeffc0"),
|
||||
findMockedUserById("12708eeb-3463-4c45-b1a8-4b5fef689c33"),
|
||||
findMockedUserById("8e215c92-4355-4722-bc27-cf5f06ee08e9"),
|
||||
findMockedUserById("49eaf40a-bdc1-4be2-9b53-53c5b24d7016"),
|
||||
findMockedUserById("9a0eee4a-ef7b-4197-b221-c9abf4d5b84a"),
|
||||
findMockedUserById("c323e5c3-57cb-45e7-81c4-56d6cacb2f8c"),
|
||||
findMockedUserById("78dd2361-4a5a-42b0-9ec3-3eea23af1094"),
|
||||
findMockedUserById("c5b28cf0-f72a-4b45-b3d5-00d3989d4ed5"),
|
||||
findMockedUserById("0f08a0c3-221e-42dc-9915-2ed85b3345dd"),
|
||||
findMockedUserById("2b2e8e9f-7a13-435c-b5d4-382182b6e5bb"),
|
||||
findMockedUserById("af657bc3-6949-4b1b-bc2d-d41a40b546a4"),
|
||||
findMockedUserById("4c8ffd9b-7bc8-47db-9322-f4d5e0b51658"),
|
||||
findMockedUserById("1da90b70-5d08-45d0-a5ee-822d1dd6397a"),
|
||||
findMockedUserById("e9b24091-a633-4ba0-9746-ca325a86f0f5"),
|
||||
findMockedUserById("27c64335-5e08-44ac-b93f-e454b82a9a06"),
|
||||
findMockedUserById("97d00652-d374-48a2-b94f-a136bf7cde01"),
|
||||
findMockedUserById("740bba7f-356d-4203-8f15-03ddee381998"),
|
||||
findMockedUserById("3b0d7f28-7ec0-4d0a-b634-57af9d739e06"),
|
||||
findMockedUserById("d12975ea-7a1e-4fb0-962e-0e3532f4db62"),
|
||||
findMockedUserById("4670a9f0-f37f-48e2-a240-58e97a193648"),
|
||||
findMockedUserById("8a98b6f7-20c1-46f1-8d58-bd2cc722b159"),
|
||||
findMockedUserById("7a4319a5-0dc1-41e1-95e4-f31e312b0ecc"),
|
||||
findMockedUserById("9bc756d1-5e95-4c6f-8e1b-a1bd20547151"),
|
||||
findMockedUserById("b006209d-fdd2-4716-afb2-104dafb32dfb"),
|
||||
findMockedUserById("c3480e4c-bdd9-4af6-9dfb-a336ae804817"),
|
||||
findMockedUserById("e95fa9e6-e2c3-41d4-a238-01849dd116af"),
|
||||
findMockedUserById("2374e95c-2e7b-4e54-9c6e-1cb2cb9aa4b4"),
|
||||
findMockedUserById("162600c0-4900-41d4-9bb0-f53925c1d176"),
|
||||
findMockedUserById("d96bf761-3f94-46b3-a1da-6316e2e4735d"),
|
||||
findMockedUserById("ef2eebf7-9708-4076-9f71-a34af71f5d24"),
|
||||
findMockedUserById("c915aeab-4ed1-42d6-95dc-49c50c5a288d"),
|
||||
findMockedUserById("612f7a53-95df-4c4b-98c2-cebd66f1a6d6"),
|
||||
findMockedUserById("da387280-f246-4329-ac3f-1c6e192b733e"),
|
||||
findMockedUserById("fdc2dab9-dabd-4980-843f-2e93042db566"),
|
||||
findMockedUserById("26efeb43-330f-4470-8f4e-7307b25020eb"),
|
||||
findMockedUserById("1e758aaf-9dde-4b8d-9727-538f1d2264d4"),
|
||||
findMockedUserById("9ed91bb9-db45-4cef-b39c-819856e98c30"),
|
||||
findMockedUserById("8016c8ca-42a1-4946-8c5f-030355200130"),
|
||||
findMockedUserById("13768036-8771-49b1-bf2f-0f61ff63c108"),
|
||||
findMockedUserById("794b8a1b-e2d6-4590-be88-1129b0424965"),
|
||||
findMockedUserById("946da1a2-9a18-4006-be65-310df64beca1"),
|
||||
findMockedUserById("983dc923-5b63-4361-ae95-5b2f0db2fb6e"),
|
||||
findMockedUserById("e5aef70f-f665-4358-afb2-2732dbddf7d2"),
|
||||
findMockedUserById("62a3d053-6a97-4ad3-9b6d-d5999e16b800"),
|
||||
findMockedUserById("58af7daf-5d08-456e-ae3b-5fba07b3df80"),
|
||||
findMockedUserById("db38462b-e63d-4304-87e9-2640eea4a3b8"),
|
||||
findMockedUserById("4a44ccb6-196b-4d98-a97d-8338bb751fc0"),
|
||||
findMockedUserById("61099b0d-71b3-44f2-ae15-45d8af34c614"),
|
||||
findMockedUserById("0bac0dfd-b086-4b6d-b8ba-789e0eca7451"),
|
||||
findMockedUserById("b8d75f48-6b3a-4c33-8a99-30f8f37b720f"),
|
||||
findMockedUserById("e3fef70d-f30e-43b4-b3a7-62a8e1a99ebb"),
|
||||
findMockedUserById("523d5587-f473-490d-9e5d-444de9b77d15"),
|
||||
findMockedUserById("b1b351ed-c489-473f-a11b-9432740f2a03"),
|
||||
findMockedUserById("c76577dd-6a9f-44e5-a0d4-54d4800aeca4"),
|
||||
findMockedUserById("3ab08cb8-3136-460f-a6b3-6febac00614d"),
|
||||
findMockedUserById("829a99f8-4c4a-4280-9500-fb21f3afb201"),
|
||||
findMockedUserById("7f5cc5e9-20ee-48ce-959d-081b3f52273e"),
|
||||
findMockedUserById("2087e3c0-0d13-494a-a0e6-483d74e043e8"),
|
||||
findMockedUserById("3e02d5f3-2ef1-4f52-95a8-738882d871cc"),
|
||||
findMockedUserById("51492787-2823-428b-862e-c7cb83d5eac7"),
|
||||
],
|
||||
total_member_count: 117,
|
||||
avatar_url: "",
|
||||
quota_allowance: 40,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "0b912bbd-743e-4415-9036-8217269de663",
|
||||
name: "Engineers",
|
||||
display_name: "",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [
|
||||
findMockedUserById("3f8c0eef-6a45-4759-a4d6-d00bbffb1369"),
|
||||
findMockedUserById("b006209d-fdd2-4716-afb2-104dafb32dfb"),
|
||||
findMockedUserById("59da0bfe-9c99-47fa-a563-f9fdb18449d0"),
|
||||
findMockedUserById("7f5cc5e9-20ee-48ce-959d-081b3f52273e"),
|
||||
findMockedUserById("12b03f43-1bb7-4fca-967a-585c97f31682"),
|
||||
findMockedUserById("d96bf761-3f94-46b3-a1da-6316e2e4735d"),
|
||||
findMockedUserById("af657bc3-6949-4b1b-bc2d-d41a40b546a4"),
|
||||
findMockedUserById("794b8a1b-e2d6-4590-be88-1129b0424965"),
|
||||
findMockedUserById("c323e5c3-57cb-45e7-81c4-56d6cacb2f8c"),
|
||||
findMockedUserById("78dd2361-4a5a-42b0-9ec3-3eea23af1094"),
|
||||
findMockedUserById("c5eb8310-cf4f-444c-b223-0e991f828b40"),
|
||||
findMockedUserById("a73425d1-53a7-43d3-b6ae-cae9ba59b92b"),
|
||||
findMockedUserById("0bac0dfd-b086-4b6d-b8ba-789e0eca7451"),
|
||||
findMockedUserById("b3e1b884-1a5b-44eb-b8b3-423f8eddc503"),
|
||||
findMockedUserById("9ed91bb9-db45-4cef-b39c-819856e98c30"),
|
||||
findMockedUserById("1c3e3fff-6a0e-4179-9ba3-27f5443e6fce"),
|
||||
findMockedUserById("e9b24091-a633-4ba0-9746-ca325a86f0f5"),
|
||||
],
|
||||
total_member_count: 17,
|
||||
avatar_url: "/emojis/1f9d1-200d-1f4bb.png",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "4f7d2a59-3999-4d03-b346-8070a4d601dc",
|
||||
name: "test-group",
|
||||
display_name: "Test Group",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [],
|
||||
total_member_count: 0,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "125b6423-a3c4-4419-abf9-dfcbbd7e8749",
|
||||
name: "bruno-group-2",
|
||||
display_name: "Bruno Group 2",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [],
|
||||
total_member_count: 0,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "cab1a90d-15be-4efe-8ddf-4dc83f3e547e",
|
||||
name: "bq-test-group",
|
||||
display_name: "",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [
|
||||
findMockedUserById("8e215c92-4355-4722-bc27-cf5f06ee08e9"),
|
||||
findMockedUserById("a73425d1-53a7-43d3-b6ae-cae9ba59b92b"),
|
||||
],
|
||||
total_member_count: 2,
|
||||
avatar_url: "/emojis/1f60d.png",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "1446698f-4f73-49e9-9dd2-e282a58f58e4",
|
||||
name: "wowzers",
|
||||
display_name: "Something else",
|
||||
organization_id: "703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
members: [
|
||||
findMockedUserById("86185021-756c-4b51-874f-a1deb00983f0"),
|
||||
findMockedUserById("794b8a1b-e2d6-4590-be88-1129b0424965"),
|
||||
],
|
||||
total_member_count: 2,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "coder",
|
||||
organization_display_name: "Coder",
|
||||
},
|
||||
{
|
||||
id: "21dfa187-531e-4a77-acb8-1ac6af314703",
|
||||
name: "Everyone",
|
||||
display_name: "",
|
||||
organization_id: "21dfa187-531e-4a77-acb8-1ac6af314703",
|
||||
members: [findMockedUserById("61099b0d-71b3-44f2-ae15-45d8af34c614")],
|
||||
total_member_count: 1,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "test-test",
|
||||
organization_display_name: "test-test",
|
||||
},
|
||||
{
|
||||
id: "163a803e-1c99-44ec-927e-5a5ccb37c6aa",
|
||||
name: "test",
|
||||
display_name: "",
|
||||
organization_id: "21dfa187-531e-4a77-acb8-1ac6af314703",
|
||||
members: [],
|
||||
total_member_count: 0,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "test-test",
|
||||
organization_display_name: "test-test",
|
||||
},
|
||||
{
|
||||
id: "cbdcf774-9412-4118-8cd9-b3f502c84dfb",
|
||||
name: "Everyone",
|
||||
display_name: "",
|
||||
organization_id: "cbdcf774-9412-4118-8cd9-b3f502c84dfb",
|
||||
members: [findMockedUserById("5ccd3128-cbbb-4cfb-8139-5a1edbb60c71")],
|
||||
total_member_count: 1,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "shared-compute",
|
||||
organization_display_name: "Shared Compute",
|
||||
},
|
||||
{
|
||||
id: "e2815018-6d5a-4751-a18d-e64641dee559",
|
||||
name: "Everyone",
|
||||
display_name: "",
|
||||
organization_id: "e2815018-6d5a-4751-a18d-e64641dee559",
|
||||
members: [findMockedUserById("8b474a55-d414-4b53-a6ba-760f3d4eed7b")],
|
||||
total_member_count: 1,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "docs-team",
|
||||
organization_display_name: "Documentors",
|
||||
},
|
||||
{
|
||||
id: "d79144d9-b30a-448a-9af8-7dac83b2e4ec",
|
||||
name: "Everyone",
|
||||
display_name: "",
|
||||
organization_id: "d79144d9-b30a-448a-9af8-7dac83b2e4ec",
|
||||
members: [findMockedUserById("1c3e3fff-6a0e-4179-9ba3-27f5443e6fce")],
|
||||
total_member_count: 1,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "data-science",
|
||||
organization_display_name: "Data Science",
|
||||
},
|
||||
{
|
||||
id: "8efa9208-656a-422d-842d-b9dec0cf1bf3",
|
||||
name: "Everyone",
|
||||
display_name: "",
|
||||
organization_id: "8efa9208-656a-422d-842d-b9dec0cf1bf3",
|
||||
members: [
|
||||
findMockedUserById("162600c0-4900-41d4-9bb0-f53925c1d176"),
|
||||
findMockedUserById("81e915cb-5064-41f7-b654-c96c846424e6"),
|
||||
findMockedUserById("c0240345-f14a-4632-b713-a0f09c2ed927"),
|
||||
findMockedUserById("c5eb8310-cf4f-444c-b223-0e991f828b40"),
|
||||
findMockedUserById("9be730b0-37ce-4216-84dd-6a851d21436e"),
|
||||
findMockedUserById("61099b0d-71b3-44f2-ae15-45d8af34c614"),
|
||||
],
|
||||
total_member_count: 6,
|
||||
avatar_url: "",
|
||||
quota_allowance: 0,
|
||||
source: "user",
|
||||
organization_name: "rabbit",
|
||||
organization_display_name: "rabbit",
|
||||
},
|
||||
].map((g) => ({
|
||||
...g,
|
||||
source: g.source as GroupSource,
|
||||
// The mock data from MockUsers contains only 25 users. It is possible that
|
||||
// some group members are not included in these mocked users. Therefore, we
|
||||
// should remove any group members that are not present in the mocked users
|
||||
// during testing.
|
||||
members: g.members.filter((m) => m !== undefined),
|
||||
}));
|
||||
@@ -0,0 +1,474 @@
|
||||
import type { AssignableRoles, RBACAction, Role } from "api/typesGenerated";
|
||||
|
||||
// The following values were retrieved from the Coder API.
|
||||
export const MockRoles: (AssignableRoles | Role)[] = [
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
site_permissions: [
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "api_key",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "assign_org_role",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "assign_role",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "audit_log",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "debug_info",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "deployment_config",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "deployment_stats",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "file",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "group",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "group_member",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "license",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "notification_preference",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "notification_template",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "oauth2_app",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "oauth2_app_code_token",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "oauth2_app_secret",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "organization",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "organization_member",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "provisioner_daemon",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "provisioner_keys",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "replicas",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "system",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "tailnet_coordinator",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "template",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "user",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "workspace_proxy",
|
||||
action: "*" as RBACAction,
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "workspace",
|
||||
action: "update",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "workspace",
|
||||
action: "delete",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "workspace",
|
||||
action: "start",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "workspace",
|
||||
action: "stop",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "workspace",
|
||||
action: "ssh",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "workspace",
|
||||
action: "application_connect",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "workspace",
|
||||
action: "create",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "workspace",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "workspace_dormant",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "workspace_dormant",
|
||||
action: "delete",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "workspace_dormant",
|
||||
action: "create",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "workspace_dormant",
|
||||
action: "update",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "workspace_dormant",
|
||||
action: "stop",
|
||||
},
|
||||
],
|
||||
organization_permissions: [],
|
||||
user_permissions: [],
|
||||
assignable: true,
|
||||
built_in: true,
|
||||
},
|
||||
{
|
||||
name: "template-admin",
|
||||
display_name: "Template Admin",
|
||||
site_permissions: [
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "file",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "file",
|
||||
action: "create",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "group",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "group_member",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "organization",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "organization_member",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "provisioner_daemon",
|
||||
action: "update",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "provisioner_daemon",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "provisioner_daemon",
|
||||
action: "delete",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "provisioner_daemon",
|
||||
action: "create",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "template",
|
||||
action: "create",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "template",
|
||||
action: "view_insights",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "template",
|
||||
action: "delete",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "template",
|
||||
action: "update",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "template",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "user",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "workspace",
|
||||
action: "read",
|
||||
},
|
||||
],
|
||||
organization_permissions: [],
|
||||
user_permissions: [],
|
||||
assignable: true,
|
||||
built_in: true,
|
||||
},
|
||||
{
|
||||
name: "user-admin",
|
||||
display_name: "User Admin",
|
||||
site_permissions: [
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "assign_org_role",
|
||||
action: "assign",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "assign_org_role",
|
||||
action: "delete",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "assign_org_role",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "assign_role",
|
||||
action: "assign",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "assign_role",
|
||||
action: "delete",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "assign_role",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "group",
|
||||
action: "delete",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "group",
|
||||
action: "update",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "group",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "group",
|
||||
action: "create",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "group_member",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "organization_member",
|
||||
action: "delete",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "organization_member",
|
||||
action: "create",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "organization_member",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "organization_member",
|
||||
action: "update",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "user",
|
||||
action: "read_personal",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "user",
|
||||
action: "update_personal",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "user",
|
||||
action: "delete",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "user",
|
||||
action: "update",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "user",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "user",
|
||||
action: "create",
|
||||
},
|
||||
],
|
||||
organization_permissions: [],
|
||||
user_permissions: [],
|
||||
assignable: true,
|
||||
built_in: true,
|
||||
},
|
||||
{
|
||||
name: "auditor",
|
||||
display_name: "Auditor",
|
||||
site_permissions: [
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "audit_log",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "deployment_config",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "deployment_stats",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "group",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "group_member",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "organization_member",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "template",
|
||||
action: "read",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "template",
|
||||
action: "view_insights",
|
||||
},
|
||||
{
|
||||
negate: false,
|
||||
resource_type: "user",
|
||||
action: "read",
|
||||
},
|
||||
],
|
||||
organization_permissions: [],
|
||||
user_permissions: [],
|
||||
built_in: true,
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,570 @@
|
||||
import type { LoginType, User, UserStatus } from "api/typesGenerated";
|
||||
|
||||
// The following username, name, and email are generated using ChatGPT to avoid
|
||||
// exposing real user data in mock values. While libraries like faker.js could
|
||||
// be used, static and deterministic values are preferred for snapshot tests to
|
||||
// ensure consistency.
|
||||
const fakeUserData = [
|
||||
{ username: "xbauer", name: "Joseph Page", email: "janet83@gmail.com" },
|
||||
{
|
||||
username: "terryjessica",
|
||||
name: "Deborah Gibson",
|
||||
email: "christianjames@yahoo.com",
|
||||
},
|
||||
{ username: "stephanie39", name: "Ivan Henry", email: "reidjohn@yahoo.com" },
|
||||
{
|
||||
username: "hweaver",
|
||||
name: "Tina Fleming",
|
||||
email: "gloriapeterson@salazar-donovan.com",
|
||||
},
|
||||
{
|
||||
username: "vhenderson",
|
||||
name: "Melissa Woods DVM",
|
||||
email: "josesalazar@jones.com",
|
||||
},
|
||||
{ username: "ronald64", name: "David Giles", email: "xlopez@tate.com" },
|
||||
{ username: "nsteele", name: "Austin Molina", email: "webbdennis@yahoo.com" },
|
||||
{
|
||||
username: "stonejonathan",
|
||||
name: "Brian Parks",
|
||||
email: "scott56@hotmail.com",
|
||||
},
|
||||
{
|
||||
username: "gary05",
|
||||
name: "Jeffrey Mosley",
|
||||
email: "matthewmyers@wheeler-butler.com",
|
||||
},
|
||||
{
|
||||
username: "oyates",
|
||||
name: "Richard Gonzalez",
|
||||
email: "sharon15@andrews-livingston.com",
|
||||
},
|
||||
{
|
||||
username: "cervantescolin",
|
||||
name: "Brian Hayes",
|
||||
email: "nataliemiller@clark.com",
|
||||
},
|
||||
{
|
||||
username: "carlosmadden",
|
||||
name: "Candace Castillo",
|
||||
email: "andrea62@schmitt-thomas.org",
|
||||
},
|
||||
{
|
||||
username: "leah46",
|
||||
name: "Mrs. Susan Murillo MD",
|
||||
email: "jamesschmitt@gmail.com",
|
||||
},
|
||||
{
|
||||
username: "eosborne",
|
||||
name: "Andrew Holland",
|
||||
email: "mileslauren@cruz.com",
|
||||
},
|
||||
{
|
||||
username: "rmorales",
|
||||
name: "Madison Shaffer",
|
||||
email: "wheeleralyssa@phillips.info",
|
||||
},
|
||||
{
|
||||
username: "haynesrachel",
|
||||
name: "Samantha Torres",
|
||||
email: "johnedwards@avery-diaz.com",
|
||||
},
|
||||
{
|
||||
username: "bakeramanda",
|
||||
name: "Michael Woods",
|
||||
email: "masseygabriel@hotmail.com",
|
||||
},
|
||||
{
|
||||
username: "gonzalesmeghan",
|
||||
name: "Tiffany Jackson",
|
||||
email: "psmith@yahoo.com",
|
||||
},
|
||||
{
|
||||
username: "xsmith",
|
||||
name: "Patrick Lewis",
|
||||
email: "christopher73@rivera.com",
|
||||
},
|
||||
{ username: "wrice", name: "Erica Smith", email: "ycisneros@hotmail.com" },
|
||||
{
|
||||
username: "anthonybrady",
|
||||
name: "Teresa Ward",
|
||||
email: "carolmartin@simmons.com",
|
||||
},
|
||||
{
|
||||
username: "matthew45",
|
||||
name: "Kevin Guerrero",
|
||||
email: "janet91@jones-brown.com",
|
||||
},
|
||||
{
|
||||
username: "brandon62",
|
||||
name: "Jennifer Jackson",
|
||||
email: "stephaniedixon@dorsey.info",
|
||||
},
|
||||
{
|
||||
username: "christinesmith",
|
||||
name: "Julian Torres",
|
||||
email: "alvarezamy@hotmail.com",
|
||||
},
|
||||
{
|
||||
username: "booneandrew",
|
||||
name: "Charles Johnson",
|
||||
email: "xblack@gmail.com",
|
||||
},
|
||||
];
|
||||
|
||||
// These values were retrieved from the Coder API. Sensitive information such as
|
||||
// usernames, names, and emails has been replaced with fake user data to protect
|
||||
// privacy.
|
||||
export const MockUsers: User[] = [
|
||||
{
|
||||
id: "a73425d1-53a7-43d3-b6ae-cae9ba59b92b",
|
||||
created_at: "2022-08-10T16:57:11.04414Z",
|
||||
updated_at: "2024-09-05T12:58:54.391687Z",
|
||||
last_seen_at: "2024-09-05T12:58:54.391687Z",
|
||||
status: "active",
|
||||
login_type: "github",
|
||||
theme_preference: "auto",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
},
|
||||
{
|
||||
name: "template-admin",
|
||||
display_name: "Template Admin",
|
||||
},
|
||||
{
|
||||
name: "user-admin",
|
||||
display_name: "User Admin",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "350441af-b2d3-401f-a795-39971f0a682b",
|
||||
created_at: "2024-07-23T14:40:20.205142Z",
|
||||
updated_at: "2024-08-08T19:04:18.108585Z",
|
||||
last_seen_at: "2024-08-08T19:04:18.108585Z",
|
||||
status: "active",
|
||||
login_type: "github",
|
||||
theme_preference: "",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [],
|
||||
},
|
||||
{
|
||||
id: "c0240345-f14a-4632-b713-a0f09c2ed927",
|
||||
created_at: "2023-09-07T20:16:41.654648Z",
|
||||
updated_at: "2024-08-27T17:34:35.171154Z",
|
||||
last_seen_at: "2024-08-27T17:34:35.171153Z",
|
||||
status: "active",
|
||||
login_type: "password",
|
||||
theme_preference: "",
|
||||
organization_ids: [
|
||||
"703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
"8efa9208-656a-422d-842d-b9dec0cf1bf3",
|
||||
],
|
||||
roles: [],
|
||||
},
|
||||
{
|
||||
id: "d96bf761-3f94-46b3-a1da-6316e2e4735d",
|
||||
created_at: "2023-08-14T15:04:56.932482Z",
|
||||
updated_at: "2024-09-05T13:04:25.741671Z",
|
||||
last_seen_at: "2024-09-05T13:04:25.741671Z",
|
||||
status: "active",
|
||||
login_type: "github",
|
||||
theme_preference: "light",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "27c64335-5e08-44ac-b93f-e454b82a9a06",
|
||||
created_at: "2024-06-10T18:10:33.595496Z",
|
||||
updated_at: "2024-07-25T22:39:21.144268Z",
|
||||
last_seen_at: "2024-07-25T22:39:21.144268Z",
|
||||
status: "active",
|
||||
login_type: "oidc",
|
||||
theme_preference: "",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [],
|
||||
},
|
||||
{
|
||||
id: "0f452b63-64cb-4422-99ea-7391ccf7b4d5",
|
||||
created_at: "2024-06-20T15:31:39.835721Z",
|
||||
updated_at: "2024-06-20T15:31:39.916055Z",
|
||||
last_seen_at: "2024-06-20T15:31:39.916055Z",
|
||||
status: "active",
|
||||
login_type: "github",
|
||||
theme_preference: "",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [],
|
||||
},
|
||||
{
|
||||
id: "135e83f1-ff91-4f91-8d23-f7e7fa6627f1",
|
||||
created_at: "2024-07-18T16:56:04.513102Z",
|
||||
updated_at: "2024-09-05T02:37:40.678649Z",
|
||||
last_seen_at: "2024-09-05T02:37:40.678649Z",
|
||||
status: "active",
|
||||
login_type: "github",
|
||||
theme_preference: "",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [],
|
||||
},
|
||||
{
|
||||
id: "9e3e4c5a-5949-417f-9380-d0a393c78bdd",
|
||||
created_at: "2024-07-15T02:00:51.816307Z",
|
||||
updated_at: "2024-09-05T04:32:12.923203Z",
|
||||
last_seen_at: "2024-09-05T04:32:12.923203Z",
|
||||
status: "active",
|
||||
login_type: "oidc",
|
||||
theme_preference: "",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "58af7daf-5d08-456e-ae3b-5fba07b3df80",
|
||||
created_at: "2024-07-22T20:31:19.143974Z",
|
||||
updated_at: "2024-07-25T13:21:14.248194Z",
|
||||
last_seen_at: "2024-07-25T13:21:14.248194Z",
|
||||
status: "active",
|
||||
login_type: "password",
|
||||
theme_preference: "",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [],
|
||||
},
|
||||
{
|
||||
id: "5ccd3128-cbbb-4cfb-8139-5a1edbb60c71",
|
||||
created_at: "2022-08-10T20:33:51.324299Z",
|
||||
updated_at: "2024-09-05T13:00:02.205822Z",
|
||||
last_seen_at: "2024-09-05T13:00:02.205822Z",
|
||||
status: "active",
|
||||
login_type: "github",
|
||||
theme_preference: "dark",
|
||||
organization_ids: [
|
||||
"cbdcf774-9412-4118-8cd9-b3f502c84dfb",
|
||||
"703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
"7621bbb4-5b04-4957-8419-cf4a683ac59a",
|
||||
],
|
||||
roles: [
|
||||
{
|
||||
name: "user-admin",
|
||||
display_name: "User Admin",
|
||||
},
|
||||
{
|
||||
name: "template-admin",
|
||||
display_name: "Template Admin",
|
||||
},
|
||||
{
|
||||
name: "auditor",
|
||||
display_name: "Auditor",
|
||||
},
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "af657bc3-6949-4b1b-bc2d-d41a40b546a4",
|
||||
created_at: "2022-08-10T16:35:11.879233Z",
|
||||
updated_at: "2024-09-05T13:12:27.319427Z",
|
||||
last_seen_at: "2024-09-05T13:12:27.319427Z",
|
||||
status: "active",
|
||||
login_type: "github",
|
||||
theme_preference: "dark",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
},
|
||||
{
|
||||
name: "user-admin",
|
||||
display_name: "User Admin",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "1c2baba2-40d6-4b9e-a788-fe393c1dbdbb",
|
||||
created_at: "2023-01-03T13:29:52.76039Z",
|
||||
updated_at: "2024-09-03T16:40:45.784352Z",
|
||||
last_seen_at: "2024-09-03T16:40:45.784352Z",
|
||||
status: "active",
|
||||
login_type: "password",
|
||||
theme_preference: "dark",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "f2cdaba3-e0a3-447a-b186-eb10dc1d1d49",
|
||||
created_at: "2024-02-02T20:37:29.606054Z",
|
||||
updated_at: "2024-06-10T14:31:49.820912Z",
|
||||
last_seen_at: "2024-06-10T14:31:49.820912Z",
|
||||
status: "active",
|
||||
login_type: "password",
|
||||
theme_preference: "",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [],
|
||||
},
|
||||
{
|
||||
id: "9bc756d1-5e95-4c6f-8e1b-a1bd20547151",
|
||||
created_at: "2024-09-04T11:29:24.168944Z",
|
||||
updated_at: "2024-09-04T11:29:24.658926Z",
|
||||
last_seen_at: "2024-09-04T11:29:24.658926Z",
|
||||
status: "active",
|
||||
login_type: "oidc",
|
||||
theme_preference: "",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "59da0bfe-9c99-47fa-a563-f9fdb18449d0",
|
||||
created_at: "2022-08-15T08:30:10.343828Z",
|
||||
updated_at: "2024-09-05T12:27:22.098297Z",
|
||||
last_seen_at: "2024-09-05T12:27:22.098297Z",
|
||||
status: "active",
|
||||
login_type: "oidc",
|
||||
theme_preference: "darkBlue",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "12b03f43-1bb7-4fca-967a-585c97f31682",
|
||||
created_at: "2022-08-10T15:35:20.553581Z",
|
||||
updated_at: "2024-09-05T13:23:46.237798Z",
|
||||
last_seen_at: "2024-09-05T13:23:46.237798Z",
|
||||
status: "active",
|
||||
login_type: "github",
|
||||
theme_preference: "dark",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
},
|
||||
{
|
||||
name: "template-admin",
|
||||
display_name: "Template Admin",
|
||||
},
|
||||
{
|
||||
name: "user-admin",
|
||||
display_name: "User Admin",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "78dd2361-4a5a-42b0-9ec3-3eea23af1094",
|
||||
created_at: "2022-08-10T17:14:30.475925Z",
|
||||
updated_at: "2024-09-04T20:40:17.036986Z",
|
||||
last_seen_at: "2024-09-04T20:40:17.036986Z",
|
||||
status: "active",
|
||||
login_type: "github",
|
||||
theme_preference: "auto",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
},
|
||||
{
|
||||
name: "template-admin",
|
||||
display_name: "Template Admin",
|
||||
},
|
||||
{
|
||||
name: "user-admin",
|
||||
display_name: "User Admin",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "4a44ccb6-196b-4d98-a97d-8338bb751fc0",
|
||||
created_at: "2024-08-26T09:00:17.565927Z",
|
||||
updated_at: "2024-09-05T12:45:45.987041Z",
|
||||
last_seen_at: "2024-09-05T12:45:45.987041Z",
|
||||
status: "active",
|
||||
login_type: "github",
|
||||
theme_preference: "auto",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "c323e5c3-57cb-45e7-81c4-56d6cacb2f8c",
|
||||
created_at: "2024-03-04T11:12:41.201352Z",
|
||||
updated_at: "2024-09-05T07:24:39.32465Z",
|
||||
last_seen_at: "2024-09-05T07:24:39.324649Z",
|
||||
status: "active",
|
||||
login_type: "oidc",
|
||||
theme_preference: "darkBlue",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "9e7815af-bc48-435a-91c7-72dcbf26f036",
|
||||
created_at: "2024-05-24T14:53:53.996555Z",
|
||||
updated_at: "2024-07-22T16:43:16.494533Z",
|
||||
last_seen_at: "2024-07-22T16:43:16.494533Z",
|
||||
status: "active",
|
||||
login_type: "oidc",
|
||||
theme_preference: "",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [],
|
||||
},
|
||||
{
|
||||
id: "3f8c0eef-6a45-4759-a4d6-d00bbffb1369",
|
||||
created_at: "2022-08-15T12:31:15.833843Z",
|
||||
updated_at: "2024-09-05T09:21:46.442564Z",
|
||||
last_seen_at: "2024-09-05T09:21:46.442564Z",
|
||||
status: "active",
|
||||
login_type: "github",
|
||||
theme_preference: "",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
},
|
||||
{
|
||||
name: "template-admin",
|
||||
display_name: "Template Admin",
|
||||
},
|
||||
{
|
||||
name: "user-admin",
|
||||
display_name: "User Admin",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "c5eb8310-cf4f-444c-b223-0e991f828b40",
|
||||
created_at: "2022-08-10T20:00:05.494466Z",
|
||||
updated_at: "2024-09-04T18:33:12.702949Z",
|
||||
last_seen_at: "2024-09-04T18:33:12.702948Z",
|
||||
status: "active",
|
||||
login_type: "github",
|
||||
theme_preference: "dark",
|
||||
organization_ids: [
|
||||
"703f72a1-76f6-4f89-9de6-8a3989693fe5",
|
||||
"8efa9208-656a-422d-842d-b9dec0cf1bf3",
|
||||
],
|
||||
roles: [
|
||||
{
|
||||
name: "template-admin",
|
||||
display_name: "Template Admin",
|
||||
},
|
||||
{
|
||||
name: "user-admin",
|
||||
display_name: "User Admin",
|
||||
},
|
||||
{
|
||||
name: "auditor",
|
||||
display_name: "Auditor",
|
||||
},
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "740bba7f-356d-4203-8f15-03ddee381998",
|
||||
created_at: "2022-08-10T18:13:52.084503Z",
|
||||
updated_at: "2024-09-05T11:56:07.949264Z",
|
||||
last_seen_at: "2024-09-05T11:56:07.949264Z",
|
||||
status: "active",
|
||||
login_type: "github",
|
||||
theme_preference: "dark",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
},
|
||||
{
|
||||
name: "template-admin",
|
||||
display_name: "Template Admin",
|
||||
},
|
||||
{
|
||||
name: "user-admin",
|
||||
display_name: "User Admin",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "806e35bb-37fd-4810-b5f2-88aa47c30c84",
|
||||
created_at: "2024-06-03T03:09:52.16976Z",
|
||||
updated_at: "2024-09-05T12:51:39.933117Z",
|
||||
last_seen_at: "2024-09-05T12:51:39.933117Z",
|
||||
status: "active",
|
||||
login_type: "oidc",
|
||||
theme_preference: "dark",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [
|
||||
{
|
||||
name: "user-admin",
|
||||
display_name: "User Admin",
|
||||
},
|
||||
{
|
||||
name: "template-admin",
|
||||
display_name: "Template Admin",
|
||||
},
|
||||
{
|
||||
name: "auditor",
|
||||
display_name: "Auditor",
|
||||
},
|
||||
{
|
||||
name: "owner",
|
||||
display_name: "Owner",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "3b0d7f28-7ec0-4d0a-b634-57af9d739e06",
|
||||
created_at: "2024-07-08T12:31:40.932658Z",
|
||||
updated_at: "2024-07-12T06:33:22.019268Z",
|
||||
last_seen_at: "2024-07-12T06:33:22.019268Z",
|
||||
status: "active",
|
||||
login_type: "github",
|
||||
theme_preference: "",
|
||||
organization_ids: ["703f72a1-76f6-4f89-9de6-8a3989693fe5"],
|
||||
roles: [],
|
||||
},
|
||||
].map((u, i) => ({
|
||||
...u,
|
||||
...fakeUserData[i],
|
||||
avatar_url: "",
|
||||
status: u.status as UserStatus,
|
||||
login_type: u.login_type as LoginType,
|
||||
}));
|
||||
Reference in New Issue
Block a user