{
- dis.dispatch({
- action: Action.SetRightPanelPhase,
- phase: RightPanelPhases.ThreadView,
- refireParams: {
- event: this.props.mxEvent,
- },
- });
+ dispatchShowThreadEvent(this.props.mxEvent);
}}
>
diff --git a/src/components/views/rooms/RoomHeader.tsx b/src/components/views/rooms/RoomHeader.tsx
index d0e438bcda..e3b4804ae6 100644
--- a/src/components/views/rooms/RoomHeader.tsx
+++ b/src/components/views/rooms/RoomHeader.tsx
@@ -155,58 +155,55 @@ export default class RoomHeader extends React.Component {
/>;
}
- let forgetButton;
- if (this.props.onForgetClick) {
- forgetButton =
- ;
- }
+ const buttons: JSX.Element[] = [];
- let appsButton;
- if (this.props.onAppsClick) {
- appsButton =
- ;
- }
-
- let searchButton;
- if (this.props.onSearchClick && this.props.inRoom) {
- searchButton =
- ;
- }
-
- let voiceCallButton;
- let videoCallButton;
if (this.props.inRoom && SettingsStore.getValue("showCallButtonsInComposer")) {
- voiceCallButton =
- this.props.onCallPlaced(PlaceCallType.Voice)}
- title={_t("Voice call")} />;
- videoCallButton =
- ) => ev.shiftKey ?
- this.displayInfoDialogAboutScreensharing() : this.props.onCallPlaced(PlaceCallType.Video)}
- title={_t("Video call")} />;
+ const voiceCallButton = this.props.onCallPlaced(PlaceCallType.Voice)}
+ title={_t("Voice call")}
+ />;
+ const videoCallButton = ) => ev.shiftKey ?
+ this.displayInfoDialogAboutScreensharing() : this.props.onCallPlaced(PlaceCallType.Video)}
+ title={_t("Video call")}
+ />;
+ buttons.push(voiceCallButton, videoCallButton);
+ }
+
+ if (this.props.onForgetClick) {
+ const forgetButton = ;
+ buttons.push(forgetButton);
+ }
+
+ if (this.props.onAppsClick) {
+ const appsButton = ;
+ buttons.push(appsButton);
+ }
+
+ if (this.props.onSearchClick && this.props.inRoom) {
+ const searchButton = ;
+ buttons.push(searchButton);
}
const rightRow =
- { videoCallButton }
- { voiceCallButton }
- { forgetButton }
- { appsButton }
- { searchButton }
+ { buttons }
;
const e2eIcon = this.props.e2eStatus ? : undefined;
diff --git a/src/contexts/RoomContext.ts b/src/contexts/RoomContext.ts
index d3a4fadd19..c5426e0dcd 100644
--- a/src/contexts/RoomContext.ts
+++ b/src/contexts/RoomContext.ts
@@ -21,9 +21,10 @@ import { Layout } from "../settings/Layout";
export enum TimelineRenderingType {
Room,
+ Thread,
+ ThreadsList,
File,
Notification,
- Thread
}
const RoomContext = createContext({
diff --git a/src/dispatcher/dispatch-actions/threads.ts b/src/dispatcher/dispatch-actions/threads.ts
new file mode 100644
index 0000000000..cda2f55707
--- /dev/null
+++ b/src/dispatcher/dispatch-actions/threads.ts
@@ -0,0 +1,38 @@
+/*
+Copyright 2021 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+import { MatrixEvent } from "matrix-js-sdk/src/models/event";
+import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
+import { Action } from "../actions";
+import dis from '../dispatcher';
+import { SetRightPanelPhasePayload } from "../payloads/SetRightPanelPhasePayload";
+
+export const dispatchShowThreadEvent = (event: MatrixEvent) => {
+ dis.dispatch({
+ action: Action.SetRightPanelPhase,
+ phase: RightPanelPhases.ThreadView,
+ refireParams: {
+ event,
+ },
+ });
+};
+
+export const dispatchShowThreadsPanelEvent = () => {
+ dis.dispatch({
+ action: Action.SetRightPanelPhase,
+ phase: RightPanelPhases.ThreadPanel,
+ });
+};
+
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index fc68c60943..3e61146acb 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -1831,6 +1831,7 @@
"Nothing pinned, yet": "Nothing pinned, yet",
"If you have permissions, open the menu on any message and select Pin to stick them here.": "If you have permissions, open the menu on any message and select Pin to stick them here.",
"Pinned messages": "Pinned messages",
+ "Threads": "Threads",
"Room Info": "Room Info",
"You can only pin up to %(count)s widgets|other": "You can only pin up to %(count)s widgets",
"Unpin a widget to view it in this panel": "Unpin a widget to view it in this panel",
@@ -2974,6 +2975,11 @@
"You can add more later too, including already existing ones.": "You can add more later too, including already existing ones.",
"What projects are you working on?": "What projects are you working on?",
"We'll create rooms for each of them. You can add more later too, including already existing ones.": "We'll create rooms for each of them. You can add more later too, including already existing ones.",
+ "My threads": "My threads",
+ "Shows all threads you’ve participated in": "Shows all threads you’ve participated in",
+ "All threads": "All threads",
+ "Shows all threads from current room": "Shows all threads from current room",
+ "Show:": "Show:",
"Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.": "Tried to load a specific point in this room's timeline, but you do not have permission to view the message in question.",
"Tried to load a specific point in this room's timeline, but was unable to find it.": "Tried to load a specific point in this room's timeline, but was unable to find it.",
"Failed to load timeline position": "Failed to load timeline position",
diff --git a/test/components/structures/ThreadPanel-test.tsx b/test/components/structures/ThreadPanel-test.tsx
new file mode 100644
index 0000000000..d6de2ebde6
--- /dev/null
+++ b/test/components/structures/ThreadPanel-test.tsx
@@ -0,0 +1,81 @@
+/*
+Copyright 2021 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import React from 'react';
+import { shallow, mount, configure } from "enzyme";
+import '../../skinned-sdk';
+import Adapter from "@wojtekmaj/enzyme-adapter-react-17";
+
+import {
+ ThreadFilterType,
+ ThreadPanelHeader,
+ ThreadPanelHeaderFilterOptionItem,
+} from '../../../src/components/structures/ThreadPanel';
+import { ContextMenuButton } from '../../../src/accessibility/context_menu/ContextMenuButton';
+import ContextMenu from '../../../src/components/structures/ContextMenu';
+import { _t } from '../../../src/languageHandler';
+
+configure({ adapter: new Adapter() });
+
+describe('ThreadPanel', () => {
+ describe('Header', () => {
+ it('expect that All filter for ThreadPanelHeader properly renders Show: All threads', () => {
+ const wrapper = shallow(
+ undefined} />,
+ );
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('expect that My filter for ThreadPanelHeader properly renders Show: My threads', () => {
+ const wrapper = shallow(
+ undefined} />,
+ );
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ it('expect that ThreadPanelHeader properly opens a context menu when clicked on the button', () => {
+ const wrapper = mount(
+ undefined} />,
+ );
+ const found = wrapper.find(ContextMenuButton);
+ expect(found).not.toBe(undefined);
+ expect(found).not.toBe(null);
+ expect(wrapper.exists(ContextMenu)).toEqual(false);
+ found.simulate('click');
+ expect(wrapper.exists(ContextMenu)).toEqual(true);
+ });
+
+ it('expect that ThreadPanelHeader has the correct option selected in the context menu', () => {
+ const wrapper = mount(
+ undefined} />,
+ );
+ wrapper.find(ContextMenuButton).simulate('click');
+ const found = wrapper.find(ThreadPanelHeaderFilterOptionItem);
+ expect(found.length).toEqual(2);
+ const foundButton = found.find('[aria-selected=true]').first();
+ expect(foundButton.text()).toEqual(`${_t("All threads")}${_t('Shows all threads from current room')}`);
+ expect(foundButton).toMatchSnapshot();
+ });
+ });
+});
diff --git a/test/components/structures/__snapshots__/ThreadPanel-test.tsx.snap b/test/components/structures/__snapshots__/ThreadPanel-test.tsx.snap
new file mode 100644
index 0000000000..016da53ddd
--- /dev/null
+++ b/test/components/structures/__snapshots__/ThreadPanel-test.tsx.snap
@@ -0,0 +1,71 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ThreadPanel Header expect that All filter for ThreadPanelHeader properly renders Show: All threads 1`] = `
+
+
+ Threads
+
+
+ Show: All threads
+
+
+`;
+
+exports[`ThreadPanel Header expect that My filter for ThreadPanelHeader properly renders Show: My threads 1`] = `
+
+
+ Threads
+
+
+ Show: My threads
+
+
+`;
+
+exports[`ThreadPanel Header expect that ThreadPanelHeader has the correct option selected in the context menu 1`] = `
+
+
+
+ All threads
+
+
+ Shows all threads from current room
+
+
+
+`;