Skip to content

Commit

Permalink
feat(hide-threads): extends hidding thread with feature flags with TAC
Browse files Browse the repository at this point in the history
  • Loading branch information
marc.sirisak committed Jun 3, 2024
1 parent 4057a20 commit dc2dc45
Show file tree
Hide file tree
Showing 9 changed files with 247 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ export default function RoomHeader({
</>
)}

<Tooltip label={_t("common|threads")}>
{/* :TCHAP: extend-remove-thread-buttons <Tooltip label={_t("common|threads")}>
<IconButton
indicator={notificationLevelToIndicator(threadNotifications)}
onClick={(evt) => {
Expand All @@ -366,7 +366,25 @@ export default function RoomHeader({
>
<ThreadsIcon />
</IconButton>
</Tooltip>
</Tooltip> */}
{
TchapUIFeature.isFeatureActiveForHomeserver("feature_thread") ?
<Tooltip label={_t("common|threads")} data-testid="room-header-thread-button">
<IconButton
indicator={notificationLevelToIndicator(threadNotifications)}
onClick={(evt) => {
evt.stopPropagation();
RightPanelStore.instance.showOrHidePanel(RightPanelPhases.ThreadPanel);
PosthogTrackers.trackInteraction("WebRoomHeaderButtonsThreadsButton", evt);
}}
aria-label={_t("common|threads")}
>
<ThreadsIcon />
</IconButton>
</Tooltip>
: null
}
{/* end :TCHAP: */}
{notificationsEnabled && (
<Tooltip label={_t("notifications|enable_prompt_toast_title")}>
<IconButton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,15 @@ const maximumVectorState = (

const NotificationActivitySettings = (): JSX.Element => {
return (
<div>
// <div> :TCHAP: extend-remove-thread-buttons - we add data-testid to the parent for testing purpose, it is diffult to get to this element otherwise
<div data-testid="tac-notification-parent">
<SettingsFlag name="Notifications.showbold" level={SettingLevel.DEVICE} />
<SettingsFlag name="Notifications.tac_only_notifications" level={SettingLevel.DEVICE} />
{/* :TCHAP: extend-remove-thread-buttons <SettingsFlag name="Notifications.tac_only_notifications" level={SettingLevel.DEVICE} /> */}
{ TchapUIFeature.isFeatureActiveForHomeserver("feature_thread") ?
<SettingsFlag name="Notifications.tac_only_notifications" level={SettingLevel.DEVICE} />
: null
}
{/* end :TCHAP: */}
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ import { shouldShowComponent } from "../../../customisations/helpers/UIComponent
import { UIComponent } from "../../../settings/UIFeature";
import { ThreadsActivityCentre } from "./threads-activity-centre/";
import AccessibleButton from "../elements/AccessibleButton";
import TchapUIFeature from "../../../../../../src/tchap/util/TchapUIFeature"; // :TCHAP: extend-remove-thread-buttons

const useSpaces = (): [Room[], MetaSpace[], Room[], SpaceKey] => {
const invites = useEventEmitterState<Room[]>(SpaceStore.instance, UPDATE_INVITED_SPACES, () => {
Expand Down Expand Up @@ -418,8 +419,9 @@ const SpacePanel: React.FC = () => {
)}
</Droppable>

<ThreadsActivityCentre displayButtonLabel={!isPanelCollapsed} />

{/* :TCHAP: extend-remove-thread-buttons <ThreadsActivityCentre displayButtonLabel={!isPanelCollapsed} /> */}
{TchapUIFeature.isFeatureActiveForHomeserver("feature_thread") ? <ThreadsActivityCentre displayButtonLabel={!isPanelCollapsed} /> : null}
{/** end :TCHAP: */}
<QuickSettingsButton isPanelCollapsed={isPanelCollapsed} />
</nav>
</DragDropContext>
Expand Down
8 changes: 8 additions & 0 deletions patches/subtree-modifications.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,13 @@
"files": [
"src/components/views/settings/Notifications.tsx"
]
},
"extend-remove-thread-buttons": {
"issue": "https://github.com/tchapgouv/tchap-web-v4/issues/988",
"files": [
"src/components/views/spaces/SpacePanel.tsx",
"src/components/views/rooms/RoomHeader.tsx",
"src/components/views/settings/Notifications.tsx"
]
}
}
70 changes: 70 additions & 0 deletions test/unit-tests/tchap/components/views/rooms/RoomHeaders-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React from "react";
import { PendingEventOrdering, Room } from "matrix-js-sdk/src/matrix";
import { screen, render, RenderOptions } from "@testing-library/react";

import { stubClient } from "~matrix-react-sdk/test/test-utils";
import RoomHeader from "~matrix-react-sdk/src/components/views/rooms/RoomHeader";
import DMRoomMap from "~matrix-react-sdk/src/utils/DMRoomMap";
import { MatrixClientPeg } from "~matrix-react-sdk/src/MatrixClientPeg";
import MatrixClientContext from "~matrix-react-sdk/src/contexts/MatrixClientContext";
import SdkConfig from "~matrix-react-sdk/src/SdkConfig";

function getWrapper(): RenderOptions {
return {
wrapper: ({ children }) => (
<MatrixClientContext.Provider value={MatrixClientPeg.safeGet()}>{children}</MatrixClientContext.Provider>
),
};
}

describe("RoomHeader", () => {
let room: Room;
const ROOM_ID = "!1:example.org";
const featurethreadName: string = "feature_thread";
const homeserverName: string = "my.home.server";

const mockFeatureConfig = (homeservers: string[], feature: string) => {
// mock SdkConfig.get("tchap_features")
const config: ConfigOptions = { tchap_features: {} };
config.tchap_features[feature] = homeservers;
SdkConfig.put(config);
};

beforeEach(async () => {
stubClient();
room = new Room(ROOM_ID, MatrixClientPeg.get()!, "@alice:example.org", {
pendingEventOrdering: PendingEventOrdering.Detached,
});
DMRoomMap.setShared({
getUserIdForRoomId: jest.fn(),
} as unknown as DMRoomMap);
});

const getComponent = () => render(<RoomHeader room={room} />, getWrapper());

afterEach(() => {
SdkConfig.reset();
jest.restoreAllMocks();
});

it("renders the room header", () => {
const { container } = getComponent();
expect(container).toHaveTextContent(ROOM_ID);
});

it("display well the thread button when feature is activated", async () => {
mockFeatureConfig([homeserverName], featurethreadName);

getComponent();

expect(screen.queryByTestId("room-header-thread-button")).toBeInTheDocument;
});

it("hides the thread button when feature is deactivated", async () => {
mockFeatureConfig(["other.homeserver"], featurethreadName);

getComponent();

expect(screen.queryByTestId("room-header-thread-button")).not.toBeInTheDocument;
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
ThreepidMedium,
TweakName,
} from "matrix-js-sdk/src/matrix";
import { fireEvent, render, screen } from "@testing-library/react";
import { cleanup, fireEvent, render, screen } from "@testing-library/react";

import Notifications from "~matrix-react-sdk/src/components/views/settings/Notifications";
import {
Expand Down Expand Up @@ -157,7 +157,8 @@ const pushRules: IPushRules = {
} as IPushRules;

describe("<Notifications />", () => {
const featureName: string = "feature_email_notification";
const featureEmailName: string = "feature_email_notification";
const featurethreadName: string = "feature_thread";
const homeserverName: string = "my.home.server";

const getComponent = () => render(<Notifications />);
Expand Down Expand Up @@ -203,15 +204,14 @@ describe("<Notifications />", () => {

const testEmail = "[email protected]";

beforeEach(async () => {
// activate email notification in the config, otherwise the section won't appear
const config: ConfigOptions = {
tchap_features: {
[featureName]: [homeserverName],
},
};
const mockFeatureConfig = (homeservers: string[], featureList: string[] = []) => {
// mock SdkConfig.get("tchap_features")
const config: ConfigOptions = { tchap_features: {} };
featureList.forEach((feature) => (config.tchap_features[feature] = homeservers));
SdkConfig.put(config);
};

beforeEach(async () => {
// Mock the email so that the section can be activated
mockClient.getThreePids.mockResolvedValue({
threepids: [
Expand All @@ -231,22 +231,69 @@ describe("<Notifications />", () => {
await clearAllModals();
});

describe("email switches", () => {
it("display well the caption when email notification is activated", async () => {
await getComponentAndWait();
afterEach(() => {
SdkConfig.reset(); // we touch the config, so clean up
cleanup();
});

fireEvent.click(screen.getByTestId("notif-master-switch"));
it("display well the caption when email notification feature is activated", async () => {
// activate email notification in the config, otherwise the section won't appear
mockFeatureConfig([homeserverName], [featureEmailName]);

await flushPromises();
await getComponentAndWait();

const emailToggle = screen.getByTestId("notif-email-switch").querySelector('div[role="switch"]')!;
fireEvent.click(emailToggle);
fireEvent.click(screen.getByTestId("notif-master-switch"));

expect(
screen.findByText(
"Recevez un e-mail si au moins un message reste non lu pendant 72h. <a>En savoir plus</a>",
),
);
});
await flushPromises();

const emailToggle = screen.getByTestId("notif-email-switch");

const caption = emailToggle.querySelector(".mx_Caption");

expect(caption).toHaveClass("mx_Caption");
});

it("hides well the caption when email notification feature is deactivated for this homeserver", async () => {
mockFeatureConfig([homeserverName]);

await getComponentAndWait();

fireEvent.click(screen.getByTestId("notif-master-switch"));

await flushPromises();

expect(screen.queryByTestId("notif-email-switch")).not.toBeInTheDocument();
});

it("hides well the caption when email notification feature is not activated for this homeserver", async () => {
mockFeatureConfig(["other.server.fr"], [featureEmailName]);

await getComponentAndWait();

fireEvent.click(screen.getByTestId("notif-master-switch"));

await flushPromises();

expect(screen.queryByTestId("notif-email-switch")).not.toBeInTheDocument();
});

it("display well the tac notification switch when feature is activated", async () => {
mockFeatureConfig([homeserverName], [featurethreadName]);

await getComponentAndWait();

const tacNotifParentElement = screen.queryByTestId("tac-notification-parent");

expect(tacNotifParentElement?.children.length).toBe(2);
});

it("display hides the tac notification switch when feature is deactivated", async () => {
mockFeatureConfig([homeserverName]);

await getComponentAndWait();

const tacNotifParentElement = screen.queryByTestId("tac-notification-parent");

expect(tacNotifParentElement?.children.length).toBe(1);
});
});
47 changes: 47 additions & 0 deletions test/unit-tests/tchap/components/views/spaces/SpacePanel-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from "react";
import { render, cleanup } from "@testing-library/react";

import { stubClient } from "~matrix-react-sdk/test/test-utils";
import { MatrixClientPeg } from "~matrix-react-sdk/src/MatrixClientPeg";
import { wrapInMatrixClientContext, wrapInSdkContext } from "~matrix-react-sdk/test/test-utils";
import { SdkContextClass } from "~matrix-react-sdk/src/contexts/SDKContext";
import UnwrappedSpacePanel from "~matrix-react-sdk/src/components/views/spaces/SpacePanel";
import SdkConfig, { ConfigOptions } from "~tchap-web/linked-dependencies/matrix-react-sdk/src/SdkConfig";

describe("<SpacePanel />", () => {
const SpacePanel = wrapInSdkContext(wrapInMatrixClientContext(UnwrappedSpacePanel), SdkContextClass.instance);
const featureName: string = "feature_thread";
const homeserverName: string = "my.home.server";

const mockFeatureConfig = (homeservers: string[]) => {
// mock SdkConfig.get("tchap_features")
const config: ConfigOptions = { tchap_features: {} };
config.tchap_features[featureName] = homeservers;
SdkConfig.put(config);
};

const renderSpacePanel = () => render(<SpacePanel />);

beforeEach(() => {
stubClient();
MatrixClientPeg.getHomeserverName = () => homeserverName;
});

afterEach(() => {
cleanup();
});

it("returns true when the the homeserver include thread feature", () => {
mockFeatureConfig([homeserverName]);
const { container } = renderSpacePanel();

expect(container.getElementsByClassName("mx_ThreadsActivityCentre_container").length).toBe(1);
});

it("returns false when the the homeserver doesnt include thread feature", async () => {
mockFeatureConfig(["other.homeserver"]);
const { container } = renderSpacePanel();

expect(container.getElementsByClassName("mx_ThreadsActivityCentre_container").length).toBe(0);
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { stubClient } from "matrix-react-sdk/test/test-utils";
import SdkConfig, { ConfigOptions } from "matrix-react-sdk/src/SdkConfig";
import { MatrixClientPeg } from "matrix-react-sdk/src/MatrixClientPeg";
import React from "react";
Expand All @@ -7,6 +6,7 @@ import { CallState } from "matrix-js-sdk/src/webrtc/call";
import { fireEvent, render, waitFor } from "@testing-library/react";
import { MatrixClient } from "matrix-js-sdk/src/matrix";

import { stubClient } from "~matrix-react-sdk/test/test-utils";
import LegacyCallView from "~matrix-react-sdk/src/components/views/voip/LegacyCallView";
import DMRoomMap from "~matrix-react-sdk/src/utils/DMRoomMap";

Expand Down
Loading

0 comments on commit dc2dc45

Please sign in to comment.