Skip to content

Commit 4c2b5df

Browse files
author
Kerry
authored
Poll history - access poll history from room settings (matrix-org#10356)
* add poll history tab to room settings * test poll history in room settings * remove posthog tracking for poll his * use consistent label for polls history
1 parent 9f66082 commit 4c2b5df

File tree

5 files changed

+303
-0
lines changed

5 files changed

+303
-0
lines changed

Diff for: res/css/views/dialogs/_RoomSettingsDialog.pcss

+4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ limitations under the License.
4242
mask-image: url("$(res)/img/feather-customised/bridge.svg");
4343
}
4444

45+
.mx_RoomSettingsDialog_pollsIcon::before {
46+
mask-image: url("$(res)/img/element-icons/room/composer/poll.svg");
47+
}
48+
4549
.mx_RoomSettingsDialog_warningIcon::before {
4650
mask-image: url("$(res)/img/element-icons/room/settings/advanced.svg");
4751
}

Diff for: src/components/views/dialogs/RoomSettingsDialog.tsx

+13
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import { Action } from "../../../dispatcher/actions";
3535
import { VoipRoomSettingsTab } from "../settings/tabs/room/VoipRoomSettingsTab";
3636
import { ActionPayload } from "../../../dispatcher/payloads";
3737
import { NonEmptyArray } from "../../../@types/common";
38+
import { PollHistoryTab } from "../settings/tabs/room/PollHistoryTab";
3839

3940
export const ROOM_GENERAL_TAB = "ROOM_GENERAL_TAB";
4041
export const ROOM_VOIP_TAB = "ROOM_VOIP_TAB";
@@ -43,6 +44,7 @@ export const ROOM_ROLES_TAB = "ROOM_ROLES_TAB";
4344
export const ROOM_NOTIFICATIONS_TAB = "ROOM_NOTIFICATIONS_TAB";
4445
export const ROOM_BRIDGES_TAB = "ROOM_BRIDGES_TAB";
4546
export const ROOM_ADVANCED_TAB = "ROOM_ADVANCED_TAB";
47+
export const ROOM_POLL_HISTORY_TAB = "ROOM_POLL_HISTORY_TAB";
4648

4749
interface IProps {
4850
roomId: string;
@@ -162,6 +164,17 @@ export default class RoomSettingsDialog extends React.Component<IProps, IState>
162164
);
163165
}
164166

167+
if (SettingsStore.getValue("feature_poll_history")) {
168+
tabs.push(
169+
new Tab(
170+
ROOM_POLL_HISTORY_TAB,
171+
_td("Polls history"),
172+
"mx_RoomSettingsDialog_pollsIcon",
173+
<PollHistoryTab roomId={this.props.roomId} onFinished={() => this.props.onFinished(true)} />,
174+
),
175+
);
176+
}
177+
165178
if (SettingsStore.getValue(UIFeature.AdvancedSettings)) {
166179
tabs.push(
167180
new Tab(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
Copyright 2023 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import React, { useContext } from "react";
18+
19+
import MatrixClientContext from "../../../../../contexts/MatrixClientContext";
20+
import { PollHistory } from "../../../polls/pollHistory/PollHistory";
21+
import { RoomPermalinkCreator } from "../../../../../utils/permalinks/Permalinks";
22+
23+
interface IProps {
24+
roomId: string;
25+
onFinished: () => void;
26+
}
27+
28+
export const PollHistoryTab: React.FC<IProps> = ({ roomId, onFinished }) => {
29+
const matrixClient = useContext(MatrixClientContext);
30+
const room = matrixClient.getRoom(roomId);
31+
if (!room) {
32+
return null;
33+
}
34+
const permalinkCreator = new RoomPermalinkCreator(room, roomId);
35+
36+
return (
37+
<div className="mx_SettingsTab">
38+
<PollHistory
39+
room={room}
40+
permalinkCreator={permalinkCreator}
41+
matrixClient={matrixClient}
42+
onFinished={onFinished}
43+
/>
44+
</div>
45+
);
46+
};
+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
Copyright 2023 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import React from "react";
18+
import { fireEvent, render, screen } from "@testing-library/react";
19+
import { Room, Visibility } from "matrix-js-sdk/src/matrix";
20+
21+
import { getMockClientWithEventEmitter, mockClientMethodsUser } from "../../../test-utils";
22+
import RoomSettingsDialog from "../../../../src/components/views/dialogs/RoomSettingsDialog";
23+
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
24+
import SettingsStore from "../../../../src/settings/SettingsStore";
25+
import { UIFeature } from "../../../../src/settings/UIFeature";
26+
27+
describe("<RoomSettingsDialog />", () => {
28+
const userId = "@alice:server.org";
29+
const mockClient = getMockClientWithEventEmitter({
30+
...mockClientMethodsUser(userId),
31+
isRoomEncrypted: jest.fn().mockReturnValue(false),
32+
getRoom: jest.fn(),
33+
getDomain: jest.fn().mockReturnValue("server.org"),
34+
getLocalAliases: jest.fn().mockResolvedValue({ aliases: [] }),
35+
getRoomDirectoryVisibility: jest.fn().mockResolvedValue({ visibility: Visibility.Private }),
36+
getOrCreateFilter: jest.fn(),
37+
});
38+
39+
const roomId = "!room:server.org";
40+
const room = new Room(roomId, mockClient, userId);
41+
42+
jest.spyOn(SettingsStore, "getValue");
43+
44+
beforeEach(() => {
45+
jest.clearAllMocks();
46+
47+
mockClient.getRoom.mockReturnValue(room);
48+
49+
jest.spyOn(SettingsStore, "getValue").mockReset().mockReturnValue(false);
50+
});
51+
52+
const getComponent = (onFinished = jest.fn()) =>
53+
render(<RoomSettingsDialog roomId={roomId} onFinished={onFinished} />, {
54+
wrapper: ({ children }) => (
55+
<MatrixClientContext.Provider value={mockClient}>{children}</MatrixClientContext.Provider>
56+
),
57+
});
58+
59+
describe("Settings tabs", () => {
60+
it("renders default tabs correctly", () => {
61+
const { container } = getComponent();
62+
expect(container.querySelectorAll(".mx_TabbedView_tabLabel")).toMatchSnapshot();
63+
});
64+
65+
it("renders voip settings tab when enabled", () => {
66+
jest.spyOn(SettingsStore, "getValue").mockImplementation(
67+
(settingName) => settingName === "feature_group_calls",
68+
);
69+
getComponent();
70+
expect(screen.getByTestId("settings-tab-ROOM_VOIP_TAB")).toBeInTheDocument();
71+
});
72+
73+
it("renders bridges settings tab when enabled", () => {
74+
jest.spyOn(SettingsStore, "getValue").mockImplementation(
75+
(settingName) => settingName === "feature_bridge_state",
76+
);
77+
getComponent();
78+
expect(screen.getByTestId("settings-tab-ROOM_BRIDGES_TAB")).toBeInTheDocument();
79+
});
80+
81+
it("renders advanced settings tab when enabled", () => {
82+
jest.spyOn(SettingsStore, "getValue").mockImplementation(
83+
(settingName) => settingName === UIFeature.AdvancedSettings,
84+
);
85+
getComponent();
86+
expect(screen.getByTestId("settings-tab-ROOM_ADVANCED_TAB")).toBeInTheDocument();
87+
});
88+
});
89+
90+
describe("poll history", () => {
91+
beforeEach(() => {
92+
jest.spyOn(SettingsStore, "getValue").mockImplementation(
93+
(settingName) => settingName === "feature_poll_history",
94+
);
95+
96+
mockClient.getOrCreateFilter.mockResolvedValue("filterId");
97+
});
98+
it("renders poll history tab", () => {
99+
getComponent();
100+
expect(screen.getByTestId("settings-tab-ROOM_POLL_HISTORY_TAB")).toBeInTheDocument();
101+
});
102+
103+
it("displays poll history when tab clicked", () => {
104+
const { container } = getComponent();
105+
106+
fireEvent.click(screen.getByText("Polls history"));
107+
108+
expect(container.querySelector(".mx_SettingsTab")).toMatchSnapshot();
109+
});
110+
});
111+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`<RoomSettingsDialog /> Settings tabs renders default tabs correctly 1`] = `
4+
NodeList [
5+
<div
6+
class="mx_AccessibleButton mx_TabbedView_tabLabel mx_TabbedView_tabLabel_active"
7+
data-testid="settings-tab-ROOM_GENERAL_TAB"
8+
role="button"
9+
tabindex="0"
10+
>
11+
<span
12+
class="mx_TabbedView_maskedIcon mx_RoomSettingsDialog_settingsIcon"
13+
/>
14+
<span
15+
class="mx_TabbedView_tabLabel_text"
16+
>
17+
General
18+
</span>
19+
</div>,
20+
<div
21+
class="mx_AccessibleButton mx_TabbedView_tabLabel "
22+
data-testid="settings-tab-ROOM_SECURITY_TAB"
23+
role="button"
24+
tabindex="0"
25+
>
26+
<span
27+
class="mx_TabbedView_maskedIcon mx_RoomSettingsDialog_securityIcon"
28+
/>
29+
<span
30+
class="mx_TabbedView_tabLabel_text"
31+
>
32+
Security & Privacy
33+
</span>
34+
</div>,
35+
<div
36+
class="mx_AccessibleButton mx_TabbedView_tabLabel "
37+
data-testid="settings-tab-ROOM_ROLES_TAB"
38+
role="button"
39+
tabindex="0"
40+
>
41+
<span
42+
class="mx_TabbedView_maskedIcon mx_RoomSettingsDialog_rolesIcon"
43+
/>
44+
<span
45+
class="mx_TabbedView_tabLabel_text"
46+
>
47+
Roles & Permissions
48+
</span>
49+
</div>,
50+
<div
51+
class="mx_AccessibleButton mx_TabbedView_tabLabel "
52+
data-testid="settings-tab-ROOM_NOTIFICATIONS_TAB"
53+
role="button"
54+
tabindex="0"
55+
>
56+
<span
57+
class="mx_TabbedView_maskedIcon mx_RoomSettingsDialog_notificationsIcon"
58+
/>
59+
<span
60+
class="mx_TabbedView_tabLabel_text"
61+
>
62+
Notifications
63+
</span>
64+
</div>,
65+
]
66+
`;
67+
68+
exports[`<RoomSettingsDialog /> poll history displays poll history when tab clicked 1`] = `
69+
<div
70+
class="mx_SettingsTab"
71+
>
72+
<div
73+
class="mx_PollHistory_content"
74+
>
75+
<h2
76+
class="mx_Heading_h2 mx_PollHistory_header"
77+
>
78+
Polls history
79+
</h2>
80+
<div
81+
class="mx_PollHistoryList"
82+
>
83+
<fieldset
84+
class="mx_FilterTabGroup"
85+
>
86+
<label
87+
data-testid="filter-tab-PollHistory_filter-ACTIVE"
88+
>
89+
<input
90+
checked=""
91+
name="PollHistory_filter"
92+
type="radio"
93+
value="ACTIVE"
94+
/>
95+
<span>
96+
Active polls
97+
</span>
98+
</label>
99+
<label
100+
data-testid="filter-tab-PollHistory_filter-ENDED"
101+
>
102+
<input
103+
name="PollHistory_filter"
104+
type="radio"
105+
value="ENDED"
106+
/>
107+
<span>
108+
Past polls
109+
</span>
110+
</label>
111+
</fieldset>
112+
<div
113+
class="mx_PollHistoryList_loading mx_PollHistoryList_noResultsYet"
114+
>
115+
<div
116+
class="mx_InlineSpinner"
117+
>
118+
<div
119+
aria-label="Loading…"
120+
class="mx_InlineSpinner_icon mx_Spinner_icon"
121+
style="width: 16px; height: 16px;"
122+
/>
123+
</div>
124+
Loading polls
125+
</div>
126+
</div>
127+
</div>
128+
</div>
129+
`;

0 commit comments

Comments
 (0)