Merge pull request #3465 from matrix-org/t3chguy/nvl/userinfo

UserInfo consolidation of GroupMemberInfo and MemberInfo panels
pull/21833/head
Michael Telatynski 2019-10-21 15:50:08 +01:00 committed by GitHub
commit c5d5cd72bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1527 additions and 10 deletions

View File

@ -12,6 +12,7 @@ module.exports = {
extends: [matrixJsSdkPath + "/.eslintrc.js"],
plugins: [
"react",
"react-hooks",
"flowtype",
"babel"
],
@ -104,6 +105,9 @@ module.exports = {
// crashes currently: https://github.com/eslint/eslint/issues/6274
"generator-star-spacing": "off",
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
},
settings: {
flowtype: {

View File

@ -135,6 +135,7 @@
"eslint-plugin-babel": "^5.2.1",
"eslint-plugin-flowtype": "^2.30.0",
"eslint-plugin-react": "^7.7.0",
"eslint-plugin-react-hooks": "^2.0.1",
"estree-walker": "^0.5.0",
"expect": "^24.1.0",
"file-loader": "^3.0.1",

View File

@ -131,6 +131,7 @@
@import "./views/messages/_TextualEvent.scss";
@import "./views/messages/_UnknownBody.scss";
@import "./views/messages/_ViewSourceEvent.scss";
@import "./views/right_panel/_UserInfo.scss";
@import "./views/room_settings/_AliasSettings.scss";
@import "./views/room_settings/_ColorSettings.scss";
@import "./views/rooms/_AppsDrawer.scss";

View File

@ -0,0 +1,175 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 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.
*/
.mx_UserInfo {
display: flex;
flex-direction: column;
flex: 1;
overflow-y: auto;
}
.mx_UserInfo_profile .mx_E2EIcon {
display: inline;
margin: auto;
padding-right: 25px;
mask-size: contain;
}
.mx_UserInfo_cancel {
height: 16px;
width: 16px;
padding: 10px 0 10px 10px;
cursor: pointer;
mask-image: url('$(res)/img/minimise.svg');
mask-repeat: no-repeat;
mask-position: 16px center;
background-color: $rightpanel-button-color;
}
.mx_UserInfo_profile h2 {
flex: 1;
overflow-x: auto;
max-height: 50px;
}
.mx_UserInfo h2 {
font-size: 16px;
font-weight: 600;
margin: 16px 0 8px 0;
}
.mx_UserInfo_container {
padding: 0 16px 16px 16px;
border-bottom: 1px solid lightgray;
}
.mx_UserInfo_memberDetailsContainer {
padding-bottom: 0;
}
.mx_UserInfo .mx_RoomTile_nameContainer {
width: 154px;
}
.mx_UserInfo .mx_RoomTile_badge {
display: none;
}
.mx_UserInfo .mx_RoomTile_name {
width: 160px;
}
.mx_UserInfo_avatar {
background: $tagpanel-bg-color;
}
.mx_UserInfo_avatar > img {
height: auto;
width: 100%;
max-height: 30vh;
object-fit: contain;
display: block;
}
.mx_UserInfo_avatar .mx_BaseAvatar.mx_BaseAvatar_image {
cursor: zoom-in;
}
.mx_UserInfo h3 {
text-transform: uppercase;
color: $input-darker-fg-color;
font-weight: bold;
font-size: 12px;
margin: 4px 0;
}
.mx_UserInfo_profileField {
font-size: 15px;
position: relative;
text-align: center;
}
.mx_UserInfo_memberDetails {
text-align: center;
}
.mx_UserInfo_field {
cursor: pointer;
font-size: 15px;
color: $primary-fg-color;
margin-left: 8px;
line-height: 23px;
}
.mx_UserInfo_createRoom {
cursor: pointer;
display: flex;
align-items: center;
padding: 0 8px;
}
.mx_UserInfo_createRoom_label {
width: initial !important;
cursor: pointer;
}
.mx_UserInfo_statusMessage {
font-size: 11px;
opacity: 0.5;
overflow: hidden;
white-space: nowrap;
text-overflow: clip;
}
.mx_UserInfo .mx_UserInfo_scrollContainer {
flex: 1;
padding-bottom: 16px;
}
.mx_UserInfo .mx_UserInfo_scrollContainer .mx_UserInfo_container {
padding-top: 16px;
padding-bottom: 0;
border-bottom: none;
}
.mx_UserInfo_container_header {
display: flex;
}
.mx_UserInfo_container_header_right {
position: relative;
margin-left: auto;
}
.mx_UserInfo_newDmButton {
background-color: $roomheader-addroom-bg-color;
border-radius: 10px; // 16/2 + 2 padding
height: 16px;
flex: 0 0 16px;
&::before {
background-color: $roomheader-addroom-fg-color;
mask: url('$(res)/img/icons-room-add.svg');
mask-repeat: no-repeat;
mask-position: center;
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
}

View File

@ -27,6 +27,7 @@ import { MatrixClient } from 'matrix-js-sdk';
import RateLimitedFunc from '../../ratelimitedfunc';
import { showGroupInviteDialog, showGroupAddRoomDialog } from '../../GroupAddressPicker';
import GroupStore from '../../stores/GroupStore';
import SettingsStore from "../../settings/SettingsStore";
export default class RightPanel extends React.Component {
static get propTypes() {
@ -165,6 +166,7 @@ export default class RightPanel extends React.Component {
render() {
const MemberList = sdk.getComponent('rooms.MemberList');
const MemberInfo = sdk.getComponent('rooms.MemberInfo');
const UserInfo = sdk.getComponent('right_panel.UserInfo');
const ThirdPartyMemberInfo = sdk.getComponent('rooms.ThirdPartyMemberInfo');
const NotificationPanel = sdk.getComponent('structures.NotificationPanel');
const FilePanel = sdk.getComponent('structures.FilePanel');
@ -183,14 +185,46 @@ export default class RightPanel extends React.Component {
} else if (this.state.phase === RightPanel.Phase.GroupRoomList) {
panel = <GroupRoomList groupId={this.props.groupId} key={this.props.groupId} />;
} else if (this.state.phase === RightPanel.Phase.RoomMemberInfo) {
panel = <MemberInfo member={this.state.member} key={this.props.roomId || this.state.member.userId} />;
if (SettingsStore.isFeatureEnabled("feature_user_info_panel")) {
const onClose = () => {
dis.dispatch({
action: "view_user",
member: null,
});
};
panel = <UserInfo
user={this.state.member}
roomId={this.props.roomId}
key={this.props.roomId || this.state.member.userId}
onClose={onClose}
/>;
} else {
panel = <MemberInfo member={this.state.member} key={this.props.roomId || this.state.member.userId} />;
}
} else if (this.state.phase === RightPanel.Phase.Room3pidMemberInfo) {
panel = <ThirdPartyMemberInfo event={this.state.event} key={this.props.roomId} />;
} else if (this.state.phase === RightPanel.Phase.GroupMemberInfo) {
panel = <GroupMemberInfo
groupMember={this.state.member}
groupId={this.props.groupId}
key={this.state.member.user_id} />;
if (SettingsStore.isFeatureEnabled("feature_user_info_panel")) {
const onClose = () => {
dis.dispatch({
action: "view_user",
member: null,
});
};
panel = <UserInfo
user={this.state.member}
groupId={this.props.groupId}
key={this.state.member.userId}
onClose={onClose} />;
} else {
panel = (
<GroupMemberInfo
groupMember={this.state.member}
groupId={this.props.groupId}
key={this.state.member.user_id}
/>
);
}
} else if (this.state.phase === RightPanel.Phase.GroupRoomInfo) {
panel = <GroupRoomInfo
groupRoomId={this.state.groupRoomId}

View File

@ -596,6 +596,7 @@ module.exports = createReactClass({
e.preventDefault();
// Update the IS in account data. Actually using it may trigger terms.
// eslint-disable-next-line react-hooks/rules-of-hooks
useDefaultIdentityServer();
// Add email as a valid address type.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
/*
Copyright 2019 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 {useRef, useEffect} from "react";
// Hook to wrap event emitter on and removeListener in hook lifecycle
export const useEventEmitter = (emitter, eventName, handler) => {
// Create a ref that stores handler
const savedHandler = useRef();
// Update ref.current value if handler changes.
useEffect(() => {
savedHandler.current = handler;
}, [handler]);
useEffect(
() => {
// Create event listener that calls handler function stored in ref
const eventListener = event => savedHandler.current(event);
// Add event listener
emitter.on(eventName, eventListener);
// Remove event listener on cleanup
return () => {
emitter.removeListener(eventName, eventListener);
};
},
[eventName, emitter], // Re-run if eventName or emitter changes
);
};

View File

@ -334,6 +334,7 @@
"Group & filter rooms by custom tags (refresh to apply changes)": "Group & filter rooms by custom tags (refresh to apply changes)",
"Render simple counters in room header": "Render simple counters in room header",
"Multiple integration managers": "Multiple integration managers",
"Use the new, consistent UserInfo panel for Room Members and Group Members": "Use the new, consistent UserInfo panel for Room Members and Group Members",
"Use the new, faster, composer for writing messages": "Use the new, faster, composer for writing messages",
"Enable Emoji suggestions while typing": "Enable Emoji suggestions while typing",
"Use compact timeline layout": "Use compact timeline layout",
@ -1028,6 +1029,16 @@
"When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.": "When someone puts a URL in their message, a URL preview can be shown to give more information about that link such as the title, description, and an image from the website.",
"Members": "Members",
"Files": "Files",
"Trust & Devices": "Trust & Devices",
"Direct messages": "Direct messages",
"Remove from community": "Remove from community",
"Disinvite this user from community?": "Disinvite this user from community?",
"Remove this user from community?": "Remove this user from community?",
"Failed to withdraw invitation": "Failed to withdraw invitation",
"Failed to remove user from community": "Failed to remove user from community",
"Failed to deactivate user": "Failed to deactivate user",
"This client does not support end-to-end encryption.": "This client does not support end-to-end encryption.",
"Messages in this room are not end-to-end encrypted.": "Messages in this room are not end-to-end encrypted.",
"Sunday": "Sunday",
"Monday": "Monday",
"Tuesday": "Tuesday",
@ -1072,11 +1083,6 @@
"Removed or unknown message type": "Removed or unknown message type",
"Message removed by %(userId)s": "Message removed by %(userId)s",
"Message removed": "Message removed",
"Remove from community": "Remove from community",
"Disinvite this user from community?": "Disinvite this user from community?",
"Remove this user from community?": "Remove this user from community?",
"Failed to withdraw invitation": "Failed to withdraw invitation",
"Failed to remove user from community": "Failed to remove user from community",
"Failed to load group members": "Failed to load group members",
"Filter community members": "Filter community members",
"Invite to this community": "Invite to this community",

View File

@ -120,6 +120,12 @@ export const SETTINGS = {
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_user_info_panel": {
isFeature: true,
displayName: _td("Use the new, consistent UserInfo panel for Room Members and Group Members"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"useCiderComposer": {
displayName: _td("Use the new, faster, composer for writing messages"),
supportedLevels: LEVELS_ACCOUNT_SETTINGS,

View File

@ -0,0 +1,31 @@
/*
Copyright 2019 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 PropTypes from "prop-types";
import {MatrixClient} from "matrix-js-sdk";
// Higher Order Component to allow use of legacy MatrixClient React Context
// in Functional Components which do not otherwise support legacy React Contexts
export default (Component) => class extends React.PureComponent {
static contextTypes = {
matrixClient: PropTypes.instanceOf(MatrixClient).isRequired,
};
render() {
return <Component {...this.props} matrixClient={this.context.matrixClient} />;
}
};

View File

@ -2891,6 +2891,11 @@ eslint-plugin-flowtype@^2.30.0:
dependencies:
lodash "^4.17.10"
eslint-plugin-react-hooks@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.0.1.tgz#e898ec26a0a335af6f7b0ad1f0bedda7143ed756"
integrity sha512-xir+3KHKo86AasxlCV8AHRtIZPHljqCRRUYgASkbatmt0fad4+5GgC7zkT7o/06hdKM6MIwp8giHVXqBPaarHQ==
eslint-plugin-react@^7.7.0:
version "7.14.3"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.14.3.tgz#911030dd7e98ba49e1b2208599571846a66bdf13"