Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #6658 from matrix-org/gsouquet/threaded-messaging-…
Browse files Browse the repository at this point in the history
…2349
  • Loading branch information
germain-gg authored Sep 1, 2021
2 parents e0363dd + bf3c8e5 commit 7621a9a
Show file tree
Hide file tree
Showing 20 changed files with 506 additions and 11 deletions.
1 change: 1 addition & 0 deletions .stylelintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module.exports = {
"selector-list-comma-newline-after": null,
"at-rule-no-unknown": null,
"no-descending-specificity": null,
"no-empty-first-line": true,
"scss/at-rule-no-unknown": [true, {
// https://github.com/vector-im/element-web/issues/10544
"ignoreAtRules": ["define-mixin"],
Expand Down
4 changes: 4 additions & 0 deletions res/css/views/messages/_MessageActionBar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ limitations under the License.
mask-image: url('$(res)/img/element-icons/room/message-bar/reply.svg');
}

.mx_MessageActionBar_threadButton::after {
mask-image: url('$(res)/img/element-icons/message/thread.svg');
}

.mx_MessageActionBar_editButton::after {
mask-image: url('$(res)/img/element-icons/room/message-bar/edit.svg');
}
Expand Down
4 changes: 4 additions & 0 deletions res/css/views/right_panel/_RoomSummaryCard.scss
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,10 @@ limitations under the License.
mask-image: url('$(res)/img/element-icons/room/files.svg');
}

.mx_RoomSummaryCard_icon_threads::before {
mask-image: url('$(res)/img/element-icons/message/thread.svg');
}

.mx_RoomSummaryCard_icon_share::before {
mask-image: url('$(res)/img/element-icons/room/share.svg');
}
Expand Down
60 changes: 60 additions & 0 deletions res/css/views/rooms/_EventTile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,7 @@ $hover-select-border: 4px;

// Remove some of the default tile padding so that the error is centered
margin-right: 0;

.mx_EventTile_line {
padding-left: 0;
margin-right: 0;
Expand Down Expand Up @@ -674,3 +675,62 @@ $hover-select-border: 4px;
margin-right: 0;
}
}

.mx_ThreadInfo:hover {
cursor: pointer;
}

.mx_ThreadView {
display: flex;
flex-direction: column;

.mx_ScrollPanel {
margin-top: 20px;

.mx_RoomView_MessageList {
padding: 0;
}
}

.mx_EventTile_senderDetails {
display: flex;
align-items: center;
gap: 6px;
margin-bottom: 6px;

a {
flex: 1;
min-width: none;
max-width: 100%;
display: flex;
align-items: center;

.mx_SenderProfile {
flex: 1;
}
}
}

.mx_ThreadView_List {
flex: 1;
overflow: scroll;
}

.mx_EventTile_roomName {
display: none;
}

.mx_EventTile_line {
padding-left: 0 !important;
order: 10 !important;
}

.mx_EventTile {
width: 100%;
display: flex;
flex-direction: column;
margin-top: 0;
padding-bottom: 5px;
margin-bottom: 5px;
}
}
16 changes: 16 additions & 0 deletions res/css/views/rooms/_MessageComposer.scss
Original file line number Diff line number Diff line change
Expand Up @@ -340,3 +340,19 @@ limitations under the License.
height: 50px;
}
}

/**
* Unstable compact mode
*/

.mx_MessageComposer.mx_MessageComposer--compact {
margin-right: 0;

.mx_MessageComposer_wrapper {
padding: 0;
}

.mx_MessageComposer_button:last-child {
margin-right: 0;
}
}
4 changes: 4 additions & 0 deletions res/img/element-icons/message/thread.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/MatrixClientPeg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ class MatrixClientPegClass implements IMatrixClientPeg {
opts.pendingEventOrdering = PendingEventOrdering.Detached;
opts.lazyLoadMembers = true;
opts.clientWellKnownPollPeriod = 2 * 60 * 60; // 2 hours
opts.experimentalThreadSupport = SettingsStore.getValue("feature_thread");

// Connect the matrix client to the dispatcher and setting handlers
MatrixActionCreators.start(this.matrixClient);
Expand Down
11 changes: 11 additions & 0 deletions src/components/structures/MessagePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ interface IProps {
onUnfillRequest?(backwards: boolean, scrollToken: string): void;

getRelationsForEvent?(eventId: string, relationType: string, eventType: string): Relations;

hideThreadedMessages?: boolean;
}

interface IState {
Expand Down Expand Up @@ -265,6 +267,9 @@ export default class MessagePanel extends React.Component<IProps, IState> {
componentDidMount() {
this.calculateRoomMembersCount();
this.props.room?.on("RoomState.members", this.calculateRoomMembersCount);
if (SettingsStore.getValue("feature_thread")) {
this.props.room?.getThreads().forEach(thread => thread.fetchReplyChain());
}
this.isMounted = true;
}

Expand Down Expand Up @@ -443,6 +448,12 @@ export default class MessagePanel extends React.Component<IProps, IState> {
// Always show highlighted event
if (this.props.highlightedEventId === mxEv.getId()) return true;

if (mxEv.replyEventId
&& this.props.hideThreadedMessages
&& SettingsStore.getValue("feature_thread")) {
return false;
}

return !shouldHideEvent(mxEv, this.context);
}

Expand Down
20 changes: 20 additions & 0 deletions src/components/structures/RightPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,21 @@ import GroupRoomInfo from "../views/groups/GroupRoomInfo";
import UserInfo from "../views/right_panel/UserInfo";
import ThirdPartyMemberInfo from "../views/rooms/ThirdPartyMemberInfo";
import FilePanel from "./FilePanel";
import ThreadView from "./ThreadView";
import ThreadPanel from "./ThreadPanel";
import NotificationPanel from "./NotificationPanel";
import ResizeNotifier from "../../utils/ResizeNotifier";
import PinnedMessagesCard from "../views/right_panel/PinnedMessagesCard";
import { throttle } from 'lodash';
import SpaceStore from "../../stores/SpaceStore";
import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks';

interface IProps {
room?: Room; // if showing panels for a given room, this is set
groupId?: string; // if showing panels for a given group, this is set
user?: User; // used if we know the user ahead of opening the panel
resizeNotifier: ResizeNotifier;
permalinkCreator?: RoomPermalinkCreator;
}

interface IState {
Expand Down Expand Up @@ -309,6 +313,22 @@ export default class RightPanel extends React.Component<IProps, IState> {
panel = <FilePanel roomId={roomId} resizeNotifier={this.props.resizeNotifier} onClose={this.onClose} />;
break;

case RightPanelPhases.ThreadView:
panel = <ThreadView
room={this.props.room}
resizeNotifier={this.props.resizeNotifier}
onClose={this.onClose}
mxEvent={this.state.event}
permalinkCreator={this.props.permalinkCreator} />;
break;

case RightPanelPhases.ThreadPanel:
panel = <ThreadPanel
roomId={roomId}
resizeNotifier={this.props.resizeNotifier}
onClose={this.onClose} />;
break;

case RightPanelPhases.RoomSummary:
panel = <RoomSummaryCard room={this.props.room} onClose={this.onClose} />;
break;
Expand Down
5 changes: 4 additions & 1 deletion src/components/structures/RoomView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2052,7 +2052,10 @@ export default class RoomView extends React.Component<IProps, IState> {

const showRightPanel = this.state.room && this.state.showRightPanel;
const rightPanel = showRightPanel
? <RightPanel room={this.state.room} resizeNotifier={this.props.resizeNotifier} />
? <RightPanel
room={this.state.room}
resizeNotifier={this.props.resizeNotifier}
permalinkCreator={this.getPermalinkCreatorForRoom(this.state.room)} />
: null;

const timelineClasses = classNames("mx_RoomView_timeline", {
Expand Down
93 changes: 93 additions & 0 deletions src/components/structures/ThreadPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
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 { MatrixEvent, Room } from 'matrix-js-sdk/src';
import { Thread } from 'matrix-js-sdk/src/models/thread';

import BaseCard from "../views/right_panel/BaseCard";
import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
import { replaceableComponent } from "../../utils/replaceableComponent";
import { MatrixClientPeg } from '../../MatrixClientPeg';

import ResizeNotifier from '../../utils/ResizeNotifier';
import EventTile from '../views/rooms/EventTile';

interface IProps {
roomId: string;
onClose: () => void;
resizeNotifier: ResizeNotifier;
}

interface IState {
threads?: Thread[];
}

@replaceableComponent("structures.ThreadView")
export default class ThreadPanel extends React.Component<IProps, IState> {
private room: Room;

constructor(props: IProps) {
super(props);
this.room = MatrixClientPeg.get().getRoom(this.props.roomId);
}

public componentDidMount(): void {
this.room.on("Thread.update", this.onThreadEventReceived);
this.room.on("Thread.ready", this.onThreadEventReceived);
}

public componentWillUnmount(): void {
this.room.removeListener("Thread.update", this.onThreadEventReceived);
this.room.removeListener("Thread.ready", this.onThreadEventReceived);
}

private onThreadEventReceived = () => this.updateThreads();

private updateThreads = (callback?: () => void): void => {
this.setState({
threads: this.room.getThreads(),
}, callback);
};

private renderEventTile(event: MatrixEvent): JSX.Element {
return <EventTile
key={event.getId()}
mxEvent={event}
enableFlair={false}
showReadReceipts={false}
as="div"
/>;
}

public render(): JSX.Element {
return (
<BaseCard
className="mx_ThreadPanel"
onClose={this.props.onClose}
previousPhase={RightPanelPhases.RoomSummary}
>
{
this.state?.threads.map((thread: Thread) => {
if (thread.ready) {
return this.renderEventTile(thread.rootEvent);
}
})
}
</BaseCard>
);
}
}
Loading

0 comments on commit 7621a9a

Please sign in to comment.