Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: warn self change on roles settings #28926

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion src/components/views/settings/PowerLevelSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
import PowerSelector from "../elements/PowerSelector";
import { _t } from "../../../languageHandler";
import SettingsFieldset from "./SettingsFieldset";
import Modal from "../../../Modal";
import QuestionDialog from "../dialogs/QuestionDialog";

/**
* Display in a fieldset, the power level of the users and allow to change them.
Expand Down Expand Up @@ -77,6 +79,13 @@ export function PowerLevelSelector({
// No user to display, we return the children into fragment to convert it to JSX.Element type
if (!users.length) return <>{children}</>;

// check at least one admin in the list
const roomHasAtLeastOneAdmin = (usersLevels: Record<string, number>) : boolean => {
const userLevelValues = Object.values(usersLevels);
// At least one user as the pL 100 which means he is admin
return userLevelValues.some((uL) => uL === 100);
}

return (
<SettingsFieldset legend={title}>
{users.map((userId) => {
Expand All @@ -96,7 +105,26 @@ export function PowerLevelSelector({
disabled={!canChange}
label={userId}
key={userId}
onChange={(value) => setCurrentPowerLevel({ value, userId })}
onChange={async (value) => {
const userLevelsTmp = Object.assign({}, userLevels);
userLevelsTmp[userId] = value;

if (!roomHasAtLeastOneAdmin(userLevelsTmp)) {
const { finished } = Modal.createDialog(QuestionDialog, {
title: _t("common|warning"),
description: (
<div>
{_t("user_info|demote_self_confirm_room")}
</div>
),
button: _t("action|continue"),
});
const [confirmed] = await finished;
if (!confirmed) return;
}
setCurrentPowerLevel({ value, userId });
}
}
/>
);
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,12 @@ describe("PowerLevelSelector", () => {

it("should be able to change the power level of the current user", async () => {
const onClick = jest.fn();
renderPLS({ onClick });
const userLevels = {
[currentUser]: 100,
"@alice:server.org": 100,
"@bob:server.org": 0,
};
renderPLS({ userLevels, onClick });

// Until the power level is changed, the apply button should be disabled
// compound button is using aria-disabled instead of the disabled attribute, we can't toBeDisabled on it
Expand Down Expand Up @@ -107,4 +112,34 @@ describe("PowerLevelSelector", () => {

expect(screen.getByText("empty label")).toBeInTheDocument();
});

it("should display modal warning if user is last admin", async () => {
const onClick = jest.fn();

renderPLS({ onClick });

// Until the power level is changed, the apply button should be disabled
// compound button is using aria-disabled instead of the disabled attribute, we can't toBeDisabled on it
expect(screen.getByRole("button", { name: "Apply" })).toHaveAttribute("aria-disabled", "true");

const select = screen.getByRole("combobox", { name: currentUser });
// Sanity check
expect(select).toHaveValue("100");

// Change current user power level to 50
await userEvent.selectOptions(select, "50");

// modal should appear because only admin in the room
expect(screen.findByText("WARNING")).toBeTruthy();

await userEvent.click(screen.getByRole("button", { name: "Continue" }));

expect(select).toHaveValue("50");
// After the user level changes, the apply button should be enabled
expect(screen.getByRole("button", { name: "Apply" })).toHaveAttribute("aria-disabled", "false");

// Click on Apply should call onClick with the new power level
await userEvent.click(screen.getByRole("button", { name: "Apply" }));
expect(onClick).toHaveBeenCalledWith(50, currentUser);
});
});
Loading