diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 4564741a290..a99a22687e0 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -34,7 +34,7 @@ import { useStateArray } from "../../hooks/useStateArray"; import { _t } from "../../languageHandler"; import PosthogTrackers from "../../PosthogTrackers"; import { inviteMultipleToRoom, showRoomInviteDialog } from "../../RoomInvite"; -import { UIComponent } from "../../settings/UIFeature"; +import { UIComponent, UIFeature } from "../../settings/UIFeature"; import { UPDATE_EVENT } from "../../stores/AsyncStore"; import RightPanelStore from "../../stores/right-panel/RightPanelStore"; import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases"; @@ -74,6 +74,7 @@ import MainSplit from "./MainSplit"; import RightPanel from "./RightPanel"; import SpaceHierarchy, { showRoom } from "./SpaceHierarchy"; import { RoomPermalinkCreator } from "../../utils/permalinks/Permalinks"; +import SettingsStore from "../../settings/SettingsStore"; interface IProps { space: Room; @@ -173,7 +174,7 @@ const SpaceLandingAddButton: React.FC<{ space: Room }> = ({ space }) => { showAddExistingRooms(space); }} /> - {canCreateSpace && ( + {canCreateSpace && SettingsStore.getValue(UIFeature.ShowCreateSpaceButton) && ( = ({ space, hideHeader, onFinished, ... )} - {canAddSubSpaces && ( + {SettingsStore.getValue(UIFeature.AddSubSpace) && canAddSubSpaces && ( { // align the context menu's icons with the icon which opened the context menu @@ -269,7 +270,7 @@ const RoomListHeader: React.FC = ({ onVisibilityChange }) => { disabled={!canAddSubRooms} title={!canAddSubRooms ? _t("spaces|error_no_permission_add_room") : undefined} /> - {canCreateSpaces && ( + {SettingsStore.getValue(UIFeature.AddSpace) && canCreateSpaces && ( ( ))} {children} - {shouldShowComponent(UIComponent.CreateSpaces) && ( - + {SettingsStore.getValue(UIFeature.ShowCreateSpaceButton) && ( + <> + {shouldShowComponent(UIComponent.CreateSpaces) && ( + + )} + )} ); diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index 4846d8db907..e35fa4fd895 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -1239,6 +1239,18 @@ export const SETTINGS: { [setting: string]: ISetting } = { supportedLevels: LEVELS_UI_FEATURE, default: true, }, + [UIFeature.ShowCreateSpaceButton]: { + supportedLevels: LEVELS_UI_FEATURE, + default: true, + }, + [UIFeature.AddSubSpace]: { + supportedLevels: LEVELS_UI_FEATURE, + default: true, + }, + [UIFeature.AddSpace]: { + supportedLevels: LEVELS_UI_FEATURE, + default: true, + }, [UIFeature.ShowStickersButtonSetting]: { supportedLevels: LEVELS_UI_FEATURE, default: true, diff --git a/src/settings/UIFeature.ts b/src/settings/UIFeature.ts index 5e9a18cafcd..6c1b9a6588e 100644 --- a/src/settings/UIFeature.ts +++ b/src/settings/UIFeature.ts @@ -33,6 +33,9 @@ export const enum UIFeature { RoomHistorySettings = "UIFeature.roomHistorySettings", TimelineEnableRelativeDates = "UIFeature.timelineEnableRelativeDates", BulkUnverifiedSessionsReminder = "UIFeature.BulkUnverifiedSessionsReminder", + ShowCreateSpaceButton = "UIFeature.showCreateSpaceButton", + AddSubSpace = "UIFeature.addSubSpace", + AddSpace = "UIFeature.addSpace", ShowStickersButtonSetting = "UIFeature.showStickersButtonSetting", InsertTrailingColonSetting = "UIFeature.insertTrailingColonSetting", ShowJoinLeavesSetting = "UIFeature.showJoinLeavesSetting", diff --git a/test/components/views/context_menus/SpaceContextMenu-test.tsx b/test/components/views/context_menus/SpaceContextMenu-test.tsx index 9e787b8bd0f..3c4677d8b9c 100644 --- a/test/components/views/context_menus/SpaceContextMenu-test.tsx +++ b/test/components/views/context_menus/SpaceContextMenu-test.tsx @@ -31,7 +31,8 @@ import { } from "../../../../src/utils/space"; import { leaveSpace } from "../../../../src/utils/leave-behaviour"; import { shouldShowComponent } from "../../../../src/customisations/helpers/UIComponents"; -import { UIComponent } from "../../../../src/settings/UIFeature"; +import { UIComponent, UIFeature } from "../../../../src/settings/UIFeature"; +import SettingsStore from "../../../../src/settings/SettingsStore"; jest.mock("../../../../src/customisations/helpers/UIComponents", () => ({ shouldShowComponent: jest.fn(), @@ -223,4 +224,41 @@ describe("", () => { expect(onFinished).toHaveBeenCalled(); }); }); + + describe("UIFeature.AddSubSpace feature flag", () => { + const space = makeMockSpace(); + + beforeEach(() => { + // set space to allow adding children to space + mocked(space.currentState.maySendStateEvent).mockReturnValue(true); + mocked(shouldShowComponent).mockReturnValue(true); + jest.clearAllMocks(); + }); + + it("UIFeature.AddSubSpace = true: renders create space button when UIFeature is true", () => { + jest.spyOn(SettingsStore, "getValue").mockImplementation((name) => { + if (name === UIFeature.AddSubSpace) return true; + else return "default"; + }); + renderComponent({ space }); + + screen.debug(); + + expect(screen.getByTestId("add-to-space-header")).toBeInTheDocument(); + expect(screen.getByTestId("new-room-option")).toBeInTheDocument(); + expect(screen.queryByTestId("new-subspace-option")).toBeInTheDocument(); + }); + + it("UIFeature.AddSubSpace = false: does not render create space button when UIFeature is false", () => { + jest.spyOn(SettingsStore, "getValue").mockImplementation((name) => { + if (name === UIFeature.AddSubSpace) return false; + else return "default"; + }); + renderComponent({ space }); + + expect(screen.getByTestId("add-to-space-header")).toBeInTheDocument(); + expect(screen.getByTestId("new-room-option")).toBeInTheDocument(); + expect(screen.queryByTestId("new-subspace-option")).not.toBeInTheDocument(); + }); + }); }); diff --git a/test/components/views/rooms/RoomListHeader-test.tsx b/test/components/views/rooms/RoomListHeader-test.tsx index 47cceedd202..46f00b54c85 100644 --- a/test/components/views/rooms/RoomListHeader-test.tsx +++ b/test/components/views/rooms/RoomListHeader-test.tsx @@ -29,7 +29,7 @@ import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import SettingsStore from "../../../../src/settings/SettingsStore"; import { SettingLevel } from "../../../../src/settings/SettingLevel"; import { shouldShowComponent } from "../../../../src/customisations/helpers/UIComponents"; -import { UIComponent } from "../../../../src/settings/UIFeature"; +import { UIComponent, UIFeature } from "../../../../src/settings/UIFeature"; const RoomListHeader = testUtils.wrapInMatrixClientContext(_RoomListHeader); @@ -285,4 +285,30 @@ describe("RoomListHeader", () => { checkIsDisabled(items[3]); }); }); + + describe("UIFeature.AddSpace", () => { + it("UIFeature.AddSpace = true: renders Add Space when user has permission to add spaces", async () => { + jest.spyOn(SettingsStore, "getValue").mockImplementation((name) => { + if (name === UIFeature.AddSpace) return true; + else return "default"; + }); + + const testSpace = setupSpace(client); + await setupPlusMenu(client, testSpace); + + expect(screen.getByText("Add space")).toBeInTheDocument(); + }); + + it("UIFeature.AddSpace = false: does not render Add Space when user has permission to add spaces", async () => { + jest.spyOn(SettingsStore, "getValue").mockImplementation((name) => { + if (name === UIFeature.AddSpace) return false; + else return "default"; + }); + + const testSpace = setupSpace(client); + await setupPlusMenu(client, testSpace); + + expect(screen.queryByText("Add space")).not.toBeInTheDocument(); + }); + }); }); diff --git a/test/components/views/spaces/SpacePanel-test.tsx b/test/components/views/spaces/SpacePanel-test.tsx index 828ad55280b..74a341363fb 100644 --- a/test/components/views/spaces/SpacePanel-test.tsx +++ b/test/components/views/spaces/SpacePanel-test.tsx @@ -26,7 +26,7 @@ import { import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import { MetaSpace, SpaceKey } from "../../../../src/stores/spaces"; import { shouldShowComponent } from "../../../../src/customisations/helpers/UIComponents"; -import { UIComponent } from "../../../../src/settings/UIFeature"; +import { UIComponent, UIFeature } from "../../../../src/settings/UIFeature"; import { mkStubRoom, wrapInMatrixClientContext, wrapInSdkContext } from "../../../test-utils"; import { SdkContextClass } from "../../../../src/contexts/SDKContext"; import SpaceStore from "../../../../src/stores/spaces/SpaceStore"; @@ -182,6 +182,24 @@ describe("", () => { fireEvent.click(screen.getByTestId("create-space-button")); screen.getByTestId("create-space-button"); }); + it("renders create space button when UIFeature is true", () => { + jest.spyOn(SettingsStore, "getValue").mockImplementation((name) => { + if (name === UIFeature.ShowCreateSpaceButton) return true; + return true; + }); + mocked(shouldShowComponent).mockReturnValue(true); + render(); + expect(screen.queryByTestId("create-space-button")).not.toBeNull(); + }); + it("does not render create space button when UIFeature is false", () => { + jest.spyOn(SettingsStore, "getValue").mockImplementation((name) => { + if (name === UIFeature.ShowCreateSpaceButton) return false; + return true; + }); + mocked(shouldShowComponent).mockReturnValue(true); + render(); + expect(screen.queryByTestId("create-space-button")).toBeNull(); + }); }); it("should allow rearranging via drag and drop", async () => {