feat: add … to actions that require confirmation (#9862)

This commit is contained in:
Kayla Washburn
2023-09-25 15:25:02 -06:00
committed by GitHub
parent ff3fc0971c
commit dac1375880
8 changed files with 78 additions and 86 deletions
@@ -36,7 +36,7 @@ export const LicenseCard = ({
return (
<Paper key={license.id} elevation={2} className={styles.licenseCard}>
<ConfirmDialog
type="info"
type="delete"
hideCancel={false}
open={licenseIDMarkedForRemoval !== undefined}
onConfirm={() => {
@@ -105,11 +105,11 @@ export const LicenseCard = ({
<Stack spacing={2}>
<Button
className={styles.removeButton}
variant="text"
variant="contained"
size="small"
onClick={() => setLicenseIDMarkedForRemoval(license.id)}
>
Remove
Remove&hellip;
</Button>
</Stack>
</Stack>
@@ -148,10 +148,6 @@ const useStyles = makeStyles((theme) => ({
color: theme.palette.text.secondary,
},
removeButton: {
height: "17px",
minHeight: "17px",
padding: 0,
border: "none",
color: theme.palette.error.main,
"&:hover": {
backgroundColor: "transparent",
@@ -110,10 +110,10 @@ const LicensesSettingsPageView: FC<Props> = ({
<Stack alignItems="center" spacing={1}>
<Stack alignItems="center" spacing={0.5}>
<span className={styles.title}>
You don{"'"}t have any licenses!
You don&apos;t have any licenses!
</span>
<span className={styles.description}>
You{"'"}re missing out on high availability, RBAC, quotas, and
You&apos;re missing out on high availability, RBAC, quotas, and
much more. Contact{" "}
<MuiLink href="mailto:sales@coder.com">sales</MuiLink> or{" "}
<MuiLink href="https://coder.com/trial">
+19 -8
View File
@@ -1,5 +1,4 @@
import Button from "@mui/material/Button";
import Link from "@mui/material/Link";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell from "@mui/material/TableCell";
@@ -60,6 +59,7 @@ export const GroupPage: React.FC = () => {
const [isDeletingGroup, setIsDeletingGroup] = useState(false);
const isLoading = !groupData || !permissions;
const canUpdateGroup = permissions ? permissions.canUpdateGroup : false;
const styles = useStyles();
return (
<>
@@ -80,17 +80,22 @@ export const GroupPage: React.FC = () => {
<PageHeader
actions={
<Maybe condition={canUpdateGroup}>
<Link to="settings" component={RouterLink}>
<Button startIcon={<SettingsOutlined />}>Settings</Button>
</Link>
<Button
startIcon={<SettingsOutlined />}
to="settings"
component={RouterLink}
>
Settings
</Button>
<Button
disabled={groupData?.id === groupData?.organization_id}
onClick={() => {
setIsDeletingGroup(true);
}}
startIcon={<DeleteOutline />}
className={styles.removeButton}
>
Delete
Delete&hellip;
</Button>
</Maybe>
}
@@ -184,11 +189,11 @@ export const GroupPage: React.FC = () => {
</Cond>
</ChooseOne>
{group && (
{groupQuery.data && (
<DeleteDialog
isOpen={isDeletingGroup}
confirmLoading={deleteGroupMutation.isLoading}
name={group.name}
name={groupQuery.data.name}
entity="group"
onConfirm={async () => {
try {
@@ -303,10 +308,16 @@ const GroupMemberRow = (props: {
);
};
const useStyles = makeStyles(() => ({
const useStyles = makeStyles((theme) => ({
autoComplete: {
width: 300,
},
removeButton: {
color: theme.palette.error.main,
"&:hover": {
backgroundColor: "transparent",
},
},
}));
export default GroupPage;
@@ -2,7 +2,6 @@ import { fireEvent, screen, within } from "@testing-library/react";
import * as API from "../../../api/api";
import { renderWithAuth } from "../../../testHelpers/renderHelpers";
import { Language as SSHKeysPageLanguage, SSHKeysPage } from "./SSHKeysPage";
import { Language as SSHKeysPageViewLanguage } from "./SSHKeysPageView";
import { MockGitSSHKey, mockApiError } from "testHelpers/entities";
describe("SSH keys Page", () => {
@@ -20,9 +19,7 @@ describe("SSH keys Page", () => {
await screen.findByText(MockGitSSHKey.public_key);
// Click on the "Regenerate" button to display the confirm dialog
const regenerateButton = screen.getByRole("button", {
name: SSHKeysPageViewLanguage.regenerateLabel,
});
const regenerateButton = screen.getByTestId("regenerate");
fireEvent.click(regenerateButton);
const confirmDialog = screen.getByRole("dialog");
expect(confirmDialog).toHaveTextContent(
@@ -67,9 +64,7 @@ describe("SSH keys Page", () => {
);
// Click on the "Regenerate" button to display the confirm dialog
const regenerateButton = screen.getByRole("button", {
name: SSHKeysPageViewLanguage.regenerateLabel,
});
const regenerateButton = screen.getByTestId("regenerate");
fireEvent.click(regenerateButton);
const confirmDialog = screen.getByRole("dialog");
expect(confirmDialog).toHaveTextContent(
@@ -1,9 +1,9 @@
import { PropsWithChildren, FC, useState } from "react";
import { ConfirmDialog } from "../../../components/Dialogs/ConfirmDialog/ConfirmDialog";
import { Section } from "../../../components/SettingsLayout/Section";
import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog";
import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
import { Section } from "components/SettingsLayout/Section";
import { SSHKeysPageView } from "./SSHKeysPageView";
import { regenerateUserSSHKey, userSSHKey } from "api/queries/sshKeys";
import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { getErrorMessage } from "api/errors";
@@ -8,10 +8,6 @@ import { Stack } from "components/Stack/Stack";
import { FC } from "react";
import { ErrorAlert } from "components/Alert/ErrorAlert";
export const Language = {
regenerateLabel: "Regenerate",
};
export interface SSHKeysPageViewProps {
isLoading: boolean;
getSSHKeyError?: unknown;
@@ -57,8 +53,8 @@ export const SSHKeysPageView: FC<
</p>
<CodeExample code={sshKey.public_key.trim()} />
<div>
<Button onClick={onRegenerateClick}>
{Language.regenerateLabel}
<Button onClick={onRegenerateClick} data-testid="regenerate">
Regenerate&hellip;
</Button>
</div>
</>
+8 -8
View File
@@ -9,11 +9,11 @@ import {
MockOwnerRole,
} from "testHelpers/entities";
import { Language as usersXServiceLanguage } from "xServices/users/usersXService";
import * as API from "../../api/api";
import { Role } from "../../api/typesGenerated";
import * as API from "api/api";
import { Role } from "api/typesGenerated";
import { Language as ResetPasswordDialogLanguage } from "./ResetPasswordDialog";
import { renderWithAuth } from "../../testHelpers/renderHelpers";
import { server } from "../../testHelpers/server";
import { renderWithAuth } from "testHelpers/renderHelpers";
import { server } from "testHelpers/server";
import { Language as UsersPageLanguage, UsersPage } from "./UsersPage";
const renderPage = () => {
@@ -29,7 +29,7 @@ const suspendUser = async (setupActionSpies: () => void) => {
await user.click(firstMoreButton);
const menu = await screen.findByRole("menu");
const suspendButton = within(menu).getByText("Suspend");
const suspendButton = within(menu).getByText(/Suspend/);
await user.click(suspendButton);
@@ -60,7 +60,7 @@ const deleteUser = async (setupActionSpies: () => void) => {
await user.click(selectedMoreButton);
const menu = await screen.findByRole("menu");
const deleteButton = within(menu).getByText("Delete");
const deleteButton = within(menu).getByText(/Delete/);
await user.click(deleteButton);
@@ -89,7 +89,7 @@ const activateUser = async (setupActionSpies: () => void) => {
fireEvent.click(suspendedMoreButton);
const menu = screen.getByRole("menu");
const activateButton = within(menu).getByText("Activate");
const activateButton = within(menu).getByText(/Activate/);
fireEvent.click(activateButton);
// Check if the confirm message is displayed
@@ -115,7 +115,7 @@ const resetUserPassword = async (setupActionSpies: () => void) => {
fireEvent.click(firstMoreButton);
const menu = screen.getByRole("menu");
const resetPasswordButton = within(menu).getByText("Reset password");
const resetPasswordButton = within(menu).getByText(/Reset password/);
fireEvent.click(resetPasswordButton);
@@ -4,7 +4,7 @@ import TableCell from "@mui/material/TableCell";
import TableRow from "@mui/material/TableRow";
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne";
import { Pill } from "components/Pill/Pill";
import { FC, ReactNode } from "react";
import { type FC } from "react";
import * as TypesGen from "../../../api/typesGenerated";
import { combineClasses } from "../../../utils/combineClasses";
import { AvatarData } from "../../../components/AvatarData/AvatarData";
@@ -215,51 +215,45 @@ export const UsersTableBody: FC<
<TableCell>
<TableRowMenu
data={user}
menuItems={
menuItems={[
// Return either suspend or activate depending on status
(user.status === "active" || user.status === "dormant"
? [
{
label: "Suspend" as ReactNode,
onClick: onSuspendUser,
disabled: false,
},
]
: [
{
label: "Activate" as ReactNode,
onClick: onActivateUser,
disabled: false,
},
]
).concat(
{
label: "Delete",
onClick: onDeleteUser,
disabled: user.id === actorID,
},
{
label: "Reset password",
onClick: onResetUserPassword,
disabled: user.login_type !== "password",
},
{
label: "View workspaces",
onClick: onListWorkspaces,
disabled: false,
},
{
label: (
<>
View activity
{!canViewActivity && <EnterpriseBadge />}
</>
),
onClick: onViewActivity,
disabled: !canViewActivity,
},
)
}
user.status === "active" || user.status === "dormant"
? {
label: <>Suspend&hellip;</>,
onClick: onSuspendUser,
disabled: false,
}
: {
label: <>Activate&hellip;</>,
onClick: onActivateUser,
disabled: false,
},
{
label: <>Delete&hellip;</>,
onClick: onDeleteUser,
disabled: user.id === actorID,
},
{
label: <>Reset password&hellip;</>,
onClick: onResetUserPassword,
disabled: user.login_type !== "password",
},
{
label: "View workspaces",
onClick: onListWorkspaces,
disabled: false,
},
{
label: (
<>
View activity
{!canViewActivity && <EnterpriseBadge />}
</>
),
onClick: onViewActivity,
disabled: !canViewActivity,
},
]}
/>
</TableCell>
)}