diff --git a/src/components/views/settings/PowerLevelSelector.tsx b/src/components/views/settings/PowerLevelSelector.tsx index 5bc2da9f92b..9598dbf455f 100644 --- a/src/components/views/settings/PowerLevelSelector.tsx +++ b/src/components/views/settings/PowerLevelSelector.tsx @@ -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. @@ -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) : 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 ( {users.map((userId) => { @@ -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: ( +
+ {_t("user_info|demote_self_confirm_room")} +
+ ), + button: _t("action|continue"), + }); + const [confirmed] = await finished; + if (!confirmed) return; + } + setCurrentPowerLevel({ value, userId }); + } + } /> ); })} diff --git a/test/unit-tests/components/views/settings/PowerLevelSelector-test.tsx b/test/unit-tests/components/views/settings/PowerLevelSelector-test.tsx index d94587f0f38..93ce63093de 100644 --- a/test/unit-tests/components/views/settings/PowerLevelSelector-test.tsx +++ b/test/unit-tests/components/views/settings/PowerLevelSelector-test.tsx @@ -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 @@ -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); + }); });