From 950bf14d955b66858e18fd857248afa89a71b6e0 Mon Sep 17 00:00:00 2001 From: Ajay Bura Date: Wed, 12 Jan 2022 11:17:44 +0530 Subject: [PATCH 01/18] Fix markdown heading formatting Signed-off-by: Ajay Bura --- src/app/molecules/message/Message.scss | 29 ++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/app/molecules/message/Message.scss b/src/app/molecules/message/Message.scss index 8ec29bfd..279a246a 100644 --- a/src/app/molecules/message/Message.scss +++ b/src/app/molecules/message/Message.scss @@ -303,23 +303,40 @@ // markdown formating .message__body { + & h1, h2, h3, h4, h5, h6 { + margin: 0; + margin-bottom: var(--sp-ultra-tight); + font-weight: var(--fw-medium); + &:first-child { + margin-top: 0; + } + &:last-child { + margin-bottom: 0; + } + } & h1, & h2 { color: var(--tc-surface-high); - margin: var(--sp-loose) 0 var(--sp-normal); - line-height: var(--lh-h1); + margin-top: var(--sp-normal); + font-size: var(--fs-h2); + line-height: var(--lh-h2); + letter-spacing: var(--ls-h2); } & h3, & h4 { color: var(--tc-surface-high); - margin: var(--sp-normal) 0 var(--sp-tight); - line-height: var(--lh-h2); + margin-top: var(--sp-tight); + font-size: var(--fs-s1); + line-height: var(--lh-s1); + letter-spacing: var(--ls-s1); } & h5, & h6 { color: var(--tc-surface-high); - margin: var(--sp-tight) 0 var(--sp-extra-tight); - line-height: var(--lh-s1); + margin-top: var(--sp-extra-tight); + font-size: var(--fs-b1); + line-height: var(--lh-b1); + letter-spacing: var(--ls-b1); } & hr { border-color: var(--bg-divider); From 3f39fd487fb90d6eb2d3af594a2842b3c690b0cb Mon Sep 17 00:00:00 2001 From: Ajay Bura Date: Wed, 12 Jan 2022 11:40:55 +0530 Subject: [PATCH 02/18] Fix custom power level selection return NaN Signed-off-by: Ajay Bura --- src/app/molecules/power-level-selector/PowerLevelSelector.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/molecules/power-level-selector/PowerLevelSelector.jsx b/src/app/molecules/power-level-selector/PowerLevelSelector.jsx index 7d531bf4..ca3e8417 100644 --- a/src/app/molecules/power-level-selector/PowerLevelSelector.jsx +++ b/src/app/molecules/power-level-selector/PowerLevelSelector.jsx @@ -11,7 +11,7 @@ function PowerLevelSelector({ value, max, onSelect, }) { const handleSubmit = (e) => { - const powerLevel = e.target.elements['power-level']; + const powerLevel = e.target.elements['power-level']?.value; if (!powerLevel) return; onSelect(Number(powerLevel)); }; From 12f2eed5b3764acfd48ad562262fb2a9bbdd734f Mon Sep 17 00:00:00 2001 From: Ajay Bura Date: Wed, 12 Jan 2022 13:57:13 +0530 Subject: [PATCH 03/18] Add ability to change power level in profile viewer Signed-off-by: Ajay Bura --- .../profile-viewer/ProfileViewer.jsx | 69 ++++++++++++++++--- src/app/templates/client/Client.jsx | 2 + src/client/action/room.js | 11 +++ 3 files changed, 73 insertions(+), 9 deletions(-) diff --git a/src/app/organisms/profile-viewer/ProfileViewer.jsx b/src/app/organisms/profile-viewer/ProfileViewer.jsx index 73b722e5..b5940b4d 100644 --- a/src/app/organisms/profile-viewer/ProfileViewer.jsx +++ b/src/app/organisms/profile-viewer/ProfileViewer.jsx @@ -7,10 +7,11 @@ import { twemojify } from '../../../util/twemojify'; import initMatrix from '../../../client/initMatrix'; import cons from '../../../client/state/cons'; import navigation from '../../../client/state/navigation'; -import { selectRoom } from '../../../client/action/navigation'; +import { selectRoom, openReusableContextMenu } from '../../../client/action/navigation'; import * as roomActions from '../../../client/action/room'; import { getUsername, getUsernameOfRoomMember, getPowerLabel } from '../../../util/matrixUtil'; +import { getEventCords } from '../../../util/common'; import colorMXID from '../../../util/colorMXID'; import Text from '../../atoms/text/Text'; @@ -18,6 +19,7 @@ import Chip from '../../atoms/chip/Chip'; import IconButton from '../../atoms/button/IconButton'; import Avatar from '../../atoms/avatar/Avatar'; import Button from '../../atoms/button/Button'; +import PowerLevelSelector from '../../molecules/power-level-selector/PowerLevelSelector'; import Dialog from '../../molecules/dialog/Dialog'; import SettingTile from '../../molecules/setting-tile/SettingTile'; @@ -25,6 +27,8 @@ import ShieldEmptyIC from '../../../../public/res/ic/outlined/shield-empty.svg'; import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg'; import CrossIC from '../../../../public/res/ic/outlined/cross.svg'; +import { useForceUpdate } from '../../hooks/useForceUpdate'; + function SessionInfo({ userId }) { const [devices, setDevices] = useState(null); const mx = initMatrix.matrixClient; @@ -230,6 +234,7 @@ function ProfileViewer() { const [isOpen, setIsOpen] = useState(false); const [roomId, setRoomId] = useState(null); const [userId, setUserId] = useState(null); + const [, forceUpdate] = useForceUpdate(); const mx = initMatrix.matrixClient; const room = roomId ? mx.getRoom(roomId) : null; @@ -240,19 +245,30 @@ function ProfileViewer() { else username = getUsername(userId); } - function loadProfile(uId, rId) { - setIsOpen(true); - setUserId(uId); - setRoomId(rId); - } - useEffect(() => { + const loadProfile = (uId, rId) => { + setIsOpen(true); + setUserId(uId); + setRoomId(rId); + }; navigation.on(cons.events.navigation.PROFILE_VIEWER_OPENED, loadProfile); return () => { navigation.removeListener(cons.events.navigation.PROFILE_VIEWER_OPENED, loadProfile); }; }, []); + useEffect(() => { + const handlePowerLevelChange = (mEvent, member) => { + if (mEvent.getRoomId() === roomId && member.userId === userId) { + forceUpdate(); + } + }; + mx.on('RoomMember.powerLevel', handlePowerLevelChange); + return () => { + mx.removeListener('RoomMember.powerLevel', handlePowerLevelChange); + }; + }, [roomId, userId]); + const handleAfterClose = () => { setUserId(null); setRoomId(null); @@ -261,8 +277,40 @@ function ProfileViewer() { function renderProfile() { const member = room.getMember(userId) || mx.getUser(userId) || {}; const avatarMxc = member.getMxcAvatarUrl?.() || member.avatarUrl; + const powerLevel = member.powerLevel || 0; - const canChangeRole = room.currentState.maySendEvent('m.room.power_levels', mx.getUserId()); + const myPowerLevel = room.getMember(mx.getUserId())?.powerLevel || 0; + + const canChangeRole = ( + room.currentState.maySendEvent('m.room.power_levels', mx.getUserId()) + && (powerLevel < myPowerLevel || userId === mx.getUserId()) + ); + + const handleChangePowerLevel = (newPowerLevel) => { + if (newPowerLevel === powerLevel) return; + if (newPowerLevel === myPowerLevel + ? confirm('You will not be able to undo this change as you are promoting the user to have the same power level as yourself. Are you sure?') + : true + ) { + roomActions.setPowerLevel(roomId, userId, newPowerLevel); + } + }; + const handlePowerSelector = (e) => { + openReusableContextMenu( + 'bottom', + getEventCords(e, '.btn-surface'), + (closeMenu) => ( + { + closeMenu(); + handleChangePowerLevel(pl); + }} + /> + ), + ); + }; return (
@@ -279,7 +327,10 @@ function ProfileViewer() {
Role -
diff --git a/src/app/templates/client/Client.jsx b/src/app/templates/client/Client.jsx index 837724fb..3ec7f8dd 100644 --- a/src/app/templates/client/Client.jsx +++ b/src/app/templates/client/Client.jsx @@ -4,6 +4,7 @@ import './Client.scss'; import Text from '../../atoms/text/Text'; import Spinner from '../../atoms/spinner/Spinner'; import Navigation from '../../organisms/navigation/Navigation'; +import ReusableContextMenu from '../../atoms/context-menu/ReusableContextMenu'; import Room from '../../organisms/room/Room'; import Windows from '../../organisms/pw/Windows'; import Dialogs from '../../organisms/pw/Dialogs'; @@ -66,6 +67,7 @@ function Client() { + ); } diff --git a/src/client/action/room.js b/src/client/action/room.js index 5fe5faac..73783ef0 100644 --- a/src/client/action/room.js +++ b/src/client/action/room.js @@ -199,6 +199,16 @@ async function kick(roomId, userId) { return result; } +async function setPowerLevel(roomId, userId, powerLevel) { + const mx = initMatrix.matrixClient; + const room = mx.getRoom(roomId); + + const powerlevelEvent = room.currentState.getStateEvents('m.room.power_levels')[0]; + + const result = await mx.setPowerLevel(roomId, userId, powerLevel, powerlevelEvent); + return result; +} + function createSpaceShortcut(roomId) { appDispatcher.dispatch({ type: cons.actions.room.CREATE_SPACE_SHORTCUT, @@ -216,5 +226,6 @@ function deleteSpaceShortcut(roomId) { export { join, leave, create, invite, kick, + setPowerLevel, createSpaceShortcut, deleteSpaceShortcut, }; From b7fac8bcbce5299b3b86cc5d970876a734b4806d Mon Sep 17 00:00:00 2001 From: Ajay Bura Date: Wed, 12 Jan 2022 13:57:47 +0530 Subject: [PATCH 04/18] Update people drawer on power level change Signed-off-by: Ajay Bura --- src/app/organisms/room/PeopleDrawer.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/organisms/room/PeopleDrawer.jsx b/src/app/organisms/room/PeopleDrawer.jsx index 2ab9976c..026173d4 100644 --- a/src/app/organisms/room/PeopleDrawer.jsx +++ b/src/app/organisms/room/PeopleDrawer.jsx @@ -107,7 +107,7 @@ function PeopleDrawer({ roomId }) { let isRoomChanged = false; const updateMemberList = (event) => { if (isGettingMembers) return; - if (event && event?.event?.room_id !== roomId) return; + if (event && event?.getRoomId() !== roomId) return; setMemberList( simplyfiMembers( getMembersWithMembership(membership) @@ -125,6 +125,7 @@ function PeopleDrawer({ roomId }) { asyncSearch.on(asyncSearch.RESULT_SENT, handleSearchData); mx.on('RoomMember.membership', updateMemberList); + mx.on('RoomMember.powerLevel', updateMemberList); return () => { isRoomChanged = true; setMemberList([]); @@ -132,6 +133,7 @@ function PeopleDrawer({ roomId }) { setItemCount(PER_PAGE_MEMBER); asyncSearch.removeListener(asyncSearch.RESULT_SENT, handleSearchData); mx.removeListener('RoomMember.membership', updateMemberList); + mx.removeListener('RoomMember.powerLevel', updateMemberList); }; }, [roomId, membership]); From 57fc8b2f1abbeb705f6af00caecddd47581ed97b Mon Sep 17 00:00:00 2001 From: Ajay Bura Date: Wed, 12 Jan 2022 15:11:34 +0530 Subject: [PATCH 05/18] Fix quote from discord bridge Signed-off-by: Ajay Bura --- src/app/molecules/message/Message.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/molecules/message/Message.scss b/src/app/molecules/message/Message.scss index 279a246a..dd26e0fd 100644 --- a/src/app/molecules/message/Message.scss +++ b/src/app/molecules/message/Message.scss @@ -382,7 +382,7 @@ @include scrollbar.scroll--auto-hide; } & pre { - display: inline-block; + width: fit-content; max-width: 100%; @include scrollbar.scroll; @include scrollbar.scroll__h; @@ -393,7 +393,7 @@ } } & blockquote { - display: inline-block; + width: fit-content; max-width: 100%; @include dir.side(border, 4px solid var(--bg-surface-active), 0); white-space: initial !important; From e38ddebfb6d7e0d0355a21369a6c803bd1f9a146 Mon Sep 17 00:00:00 2001 From: Ajay Bura Date: Wed, 12 Jan 2022 16:46:56 +0530 Subject: [PATCH 06/18] Refactor code of profile viewer Signed-off-by: Ajay Bura --- .../profile-viewer/ProfileViewer.jsx | 67 +++++++++++-------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/src/app/organisms/profile-viewer/ProfileViewer.jsx b/src/app/organisms/profile-viewer/ProfileViewer.jsx index b5940b4d..87f085d8 100644 --- a/src/app/organisms/profile-viewer/ProfileViewer.jsx +++ b/src/app/organisms/profile-viewer/ProfileViewer.jsx @@ -230,20 +230,10 @@ ProfileFooter.propTypes = { onRequestClose: PropTypes.func.isRequired, }; -function ProfileViewer() { +function useToggleDialog() { const [isOpen, setIsOpen] = useState(false); const [roomId, setRoomId] = useState(null); const [userId, setUserId] = useState(null); - const [, forceUpdate] = useForceUpdate(); - - const mx = initMatrix.matrixClient; - const room = roomId ? mx.getRoom(roomId) : null; - let username = ''; - if (room !== null) { - const roomMember = room.getMember(userId); - if (roomMember) username = getUsernameOfRoomMember(roomMember); - else username = getUsername(userId); - } useEffect(() => { const loadProfile = (uId, rId) => { @@ -257,6 +247,19 @@ function ProfileViewer() { }; }, []); + const closeDialog = () => setIsOpen(false); + + const afterClose = () => { + setUserId(null); + setRoomId(null); + }; + + return [isOpen, roomId, userId, closeDialog, afterClose]; +} + +function useRerenderOnRoleChange(roomId, userId) { + const mx = initMatrix.matrixClient; + const [, forceUpdate] = useForceUpdate(); useEffect(() => { const handlePowerLevelChange = (mEvent, member) => { if (mEvent.getRoomId() === roomId && member.userId === userId) { @@ -268,17 +271,27 @@ function ProfileViewer() { mx.removeListener('RoomMember.powerLevel', handlePowerLevelChange); }; }, [roomId, userId]); +} - const handleAfterClose = () => { - setUserId(null); - setRoomId(null); - }; +function ProfileViewer() { + const [isOpen, roomId, userId, closeDialog, handleAfterClose] = useToggleDialog(); + useRerenderOnRoleChange(roomId, userId); - function renderProfile() { - const member = room.getMember(userId) || mx.getUser(userId) || {}; - const avatarMxc = member.getMxcAvatarUrl?.() || member.avatarUrl; + const mx = initMatrix.matrixClient; + const room = mx.getRoom(roomId); - const powerLevel = member.powerLevel || 0; + let [roomMember, username] = [null, null]; + + if (roomId) { + roomMember = room.getMember(userId); + username = roomMember ? getUsernameOfRoomMember(roomMember) : getUsername(userId); + } + + const renderProfile = () => { + const avatarMxc = roomMember.getMxcAvatarUrl?.() || mx.getMember(userId).avatarUrl; + const avatarUrl = avatarMxc ? mx.mxcUrlToHttp(avatarMxc, 80, 80, 'crop') : null; + + const powerLevel = roomMember.powerLevel || 0; const myPowerLevel = room.getMember(mx.getUserId())?.powerLevel || 0; const canChangeRole = ( @@ -295,6 +308,7 @@ function ProfileViewer() { roomActions.setPowerLevel(roomId, userId, newPowerLevel); } }; + const handlePowerSelector = (e) => { openReusableContextMenu( 'bottom', @@ -315,12 +329,7 @@ function ProfileViewer() { return (
- +
{twemojify(username)} {twemojify(userId)} @@ -340,12 +349,12 @@ function ProfileViewer() { setIsOpen(false)} + onRequestClose={closeDialog} /> )}
); - } + }; return ( setIsOpen(false)} - contentOptions={ setIsOpen(false)} tooltip="Close" />} + onRequestClose={closeDialog} + contentOptions={} > {roomId ? renderProfile() :
}
From 248fc1571646f0affc38b046ddee0583c1168010 Mon Sep 17 00:00:00 2001 From: Ajay Bura Date: Wed, 12 Jan 2022 18:26:52 +0530 Subject: [PATCH 07/18] Add option to kick user in profile viewer Signed-off-by: Ajay Bura --- .../profile-viewer/ProfileViewer.jsx | 68 +++++++++++++++---- .../profile-viewer/ProfileViewer.scss | 22 ++++++ src/client/action/room.js | 4 +- 3 files changed, 79 insertions(+), 15 deletions(-) diff --git a/src/app/organisms/profile-viewer/ProfileViewer.jsx b/src/app/organisms/profile-viewer/ProfileViewer.jsx index 87f085d8..e6b3a839 100644 --- a/src/app/organisms/profile-viewer/ProfileViewer.jsx +++ b/src/app/organisms/profile-viewer/ProfileViewer.jsx @@ -17,6 +17,7 @@ import colorMXID from '../../../util/colorMXID'; import Text from '../../atoms/text/Text'; import Chip from '../../atoms/chip/Chip'; import IconButton from '../../atoms/button/IconButton'; +import Input from '../../atoms/input/Input'; import Avatar from '../../atoms/avatar/Avatar'; import Button from '../../atoms/button/Button'; import PowerLevelSelector from '../../molecules/power-level-selector/PowerLevelSelector'; @@ -29,6 +30,45 @@ import CrossIC from '../../../../public/res/ic/outlined/cross.svg'; import { useForceUpdate } from '../../hooks/useForceUpdate'; +function ModerationTools({ + roomId, userId, +}) { + const mx = initMatrix.matrixClient; + const room = mx.getRoom(roomId); + const roomMember = room.getMember(userId); + + const myPowerLevel = room.getMember(mx.getUserId()).powerLevel; + const powerLevel = roomMember?.powerLevel || 0; + const canIKick = ( + roomMember?.membership === 'join' + && room.currentState.hasSufficientPowerLevelFor('kick', myPowerLevel) + && powerLevel < myPowerLevel + ); + + const handleKick = (e) => { + e.preventDefault(); + const kickReason = e.target.elements['kick-reason']?.value.trim(); + roomActions.kick(roomId, userId, kickReason !== '' ? kickReason : undefined); + }; + + return ( +
+ {canIKick && ( + <> +
+ + +
+ + )} +
+ ); +} +ModerationTools.propTypes = { + roomId: PropTypes.string.isRequired, + userId: PropTypes.string.isRequired, +}; + function SessionInfo({ userId }) { const [devices, setDevices] = useState(null); const mx = initMatrix.matrixClient; @@ -257,25 +297,30 @@ function useToggleDialog() { return [isOpen, roomId, userId, closeDialog, afterClose]; } -function useRerenderOnRoleChange(roomId, userId) { +function useRerenderOnProfileChange(roomId, userId) { const mx = initMatrix.matrixClient; const [, forceUpdate] = useForceUpdate(); useEffect(() => { - const handlePowerLevelChange = (mEvent, member) => { - if (mEvent.getRoomId() === roomId && member.userId === userId) { + const handleProfileChange = (mEvent, member) => { + if ( + mEvent.getRoomId() === roomId + && (member.userId === userId || member.userId === mx.getUserId()) + ) { forceUpdate(); } }; - mx.on('RoomMember.powerLevel', handlePowerLevelChange); + mx.on('RoomMember.powerLevel', handleProfileChange); + mx.on('RoomMember.membership', handleProfileChange); return () => { - mx.removeListener('RoomMember.powerLevel', handlePowerLevelChange); + mx.removeListener('RoomMember.powerLevel', handleProfileChange); + mx.removeListener('RoomMember.membership', handleProfileChange); }; }, [roomId, userId]); } function ProfileViewer() { const [isOpen, roomId, userId, closeDialog, handleAfterClose] = useToggleDialog(); - useRerenderOnRoleChange(roomId, userId); + useRerenderOnProfileChange(roomId, userId); const mx = initMatrix.matrixClient; const room = mx.getRoom(roomId); @@ -288,8 +333,8 @@ function ProfileViewer() { } const renderProfile = () => { - const avatarMxc = roomMember.getMxcAvatarUrl?.() || mx.getMember(userId).avatarUrl; - const avatarUrl = avatarMxc ? mx.mxcUrlToHttp(avatarMxc, 80, 80, 'crop') : null; + const avatarMxc = roomMember?.getMxcAvatarUrl?.() || mx.getUser(userId).avatarUrl; + const avatarUrl = (avatarMxc && avatarMxc !== 'null') ? mx.mxcUrlToHttp(avatarMxc, 80, 80, 'crop') : null; const powerLevel = roomMember.powerLevel || 0; const myPowerLevel = room.getMember(mx.getUserId())?.powerLevel || 0; @@ -344,13 +389,10 @@ function ProfileViewer() {
+ { userId !== mx.getUserId() && ( - + )} ); diff --git a/src/app/organisms/profile-viewer/ProfileViewer.scss b/src/app/organisms/profile-viewer/ProfileViewer.scss index 230c8db7..b8c46426 100644 --- a/src/app/organisms/profile-viewer/ProfileViewer.scss +++ b/src/app/organisms/profile-viewer/ProfileViewer.scss @@ -1,3 +1,4 @@ +@use '../../partials/flex'; @use '../../partials/dir'; .profile-viewer__dialog { @@ -61,6 +62,27 @@ } } +.profile-viewer__admin-tool { + .setting-tile { + margin-top: var(--sp-loose); + } +} + +.moderation-tools { + & > form { + margin: var(--sp-normal) 0; + display: flex; + align-items: flex-end; + & .input-container { + @extend .cp-fx__item-one; + @include dir.side(margin, 0, var(--sp-tight)); + } + & button { + height: 46px; + } + } +} + .session-info { & .setting-tile__title .text { color: var(--tc-surface-high); diff --git a/src/client/action/room.js b/src/client/action/room.js index 73783ef0..8d67afd0 100644 --- a/src/client/action/room.js +++ b/src/client/action/room.js @@ -192,10 +192,10 @@ async function invite(roomId, userId) { return result; } -async function kick(roomId, userId) { +async function kick(roomId, userId, reason) { const mx = initMatrix.matrixClient; - const result = await mx.kick(roomId, userId); + const result = await mx.kick(roomId, userId, reason); return result; } From a1d9c213375a5cfa71a9a549124c4278ff16d168 Mon Sep 17 00:00:00 2001 From: Ajay Bura Date: Wed, 12 Jan 2022 18:50:54 +0530 Subject: [PATCH 08/18] Add option to ban user in profile viewer Signed-off-by: Ajay Bura --- .../profile-viewer/ProfileViewer.jsx | 27 ++++++++++++++----- src/client/action/room.js | 9 ++++++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/app/organisms/profile-viewer/ProfileViewer.jsx b/src/app/organisms/profile-viewer/ProfileViewer.jsx index e6b3a839..6eb370de 100644 --- a/src/app/organisms/profile-viewer/ProfileViewer.jsx +++ b/src/app/organisms/profile-viewer/ProfileViewer.jsx @@ -44,6 +44,11 @@ function ModerationTools({ && room.currentState.hasSufficientPowerLevelFor('kick', myPowerLevel) && powerLevel < myPowerLevel ); + const canIBan = ( + ['join', 'leave'].includes(roomMember?.membership) + && room.currentState.hasSufficientPowerLevelFor('ban', myPowerLevel) + && powerLevel < myPowerLevel + ); const handleKick = (e) => { e.preventDefault(); @@ -51,15 +56,25 @@ function ModerationTools({ roomActions.kick(roomId, userId, kickReason !== '' ? kickReason : undefined); }; + const handleBan = (e) => { + e.preventDefault(); + const banReason = e.target.elements['ban-reason']?.value.trim(); + roomActions.ban(roomId, userId, banReason !== '' ? banReason : undefined); + }; + return (
{canIKick && ( - <> -
- - -
- +
+ + +
+ )} + {canIBan && ( +
+ + +
)}
); diff --git a/src/client/action/room.js b/src/client/action/room.js index 8d67afd0..59839da4 100644 --- a/src/client/action/room.js +++ b/src/client/action/room.js @@ -199,6 +199,13 @@ async function kick(roomId, userId, reason) { return result; } +async function ban(roomId, userId, reason) { + const mx = initMatrix.matrixClient; + + const result = await mx.ban(roomId, userId, reason); + return result; +} + async function setPowerLevel(roomId, userId, powerLevel) { const mx = initMatrix.matrixClient; const room = mx.getRoom(roomId); @@ -225,7 +232,7 @@ function deleteSpaceShortcut(roomId) { export { join, leave, - create, invite, kick, + create, invite, kick, ban, setPowerLevel, createSpaceShortcut, deleteSpaceShortcut, }; From 74464992e61467ee6e05624c634bb7da7174560f Mon Sep 17 00:00:00 2001 From: Ajay Bura Date: Thu, 13 Jan 2022 09:42:23 +0530 Subject: [PATCH 09/18] Redesign session chip in profile viewer Signed-off-by: Ajay Bura --- .../profile-viewer/ProfileViewer.jsx | 30 ++++++++++--------- .../profile-viewer/ProfileViewer.scss | 14 ++++++--- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/app/organisms/profile-viewer/ProfileViewer.jsx b/src/app/organisms/profile-viewer/ProfileViewer.jsx index 6eb370de..fc33b6d1 100644 --- a/src/app/organisms/profile-viewer/ProfileViewer.jsx +++ b/src/app/organisms/profile-viewer/ProfileViewer.jsx @@ -20,11 +20,13 @@ import IconButton from '../../atoms/button/IconButton'; import Input from '../../atoms/input/Input'; import Avatar from '../../atoms/avatar/Avatar'; import Button from '../../atoms/button/Button'; +import { MenuItem } from '../../atoms/context-menu/ContextMenu'; import PowerLevelSelector from '../../molecules/power-level-selector/PowerLevelSelector'; import Dialog from '../../molecules/dialog/Dialog'; import SettingTile from '../../molecules/setting-tile/SettingTile'; import ShieldEmptyIC from '../../../../public/res/ic/outlined/shield-empty.svg'; +import ChevronRightIC from '../../../../public/res/ic/outlined/chevron-right.svg'; import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg'; import CrossIC from '../../../../public/res/ic/outlined/cross.svg'; @@ -86,6 +88,7 @@ ModerationTools.propTypes = { function SessionInfo({ userId }) { const [devices, setDevices] = useState(null); + const [isVisible, setIsVisible] = useState(false); const mx = initMatrix.matrixClient; useEffect(() => { @@ -110,10 +113,11 @@ function SessionInfo({ userId }) { }, [userId]); function renderSessionChips() { + if (!isVisible) return null; return (
- {devices === null && Loading sessions...} - {devices?.length === 0 && No session found.} + {devices === null && Loading sessions...} + {devices?.length === 0 && No session found.} {devices !== null && (devices.map((device) => ( - + setIsVisible(!isVisible)} + iconSrc={isVisible ? ChevronBottomIC : ChevronRightIC} + > + {`View ${devices?.length > 0 ? `${devices.length} ` : ''}sessions`} + + {renderSessionChips()}
); } @@ -340,14 +347,9 @@ function ProfileViewer() { const mx = initMatrix.matrixClient; const room = mx.getRoom(roomId); - let [roomMember, username] = [null, null]; - - if (roomId) { - roomMember = room.getMember(userId); - username = roomMember ? getUsernameOfRoomMember(roomMember) : getUsername(userId); - } - const renderProfile = () => { + const roomMember = room.getMember(userId); + const username = roomMember ? getUsernameOfRoomMember(roomMember) : getUsername(userId); const avatarMxc = roomMember?.getMxcAvatarUrl?.() || mx.getUser(userId).avatarUrl; const avatarUrl = (avatarMxc && avatarMxc !== 'null') ? mx.mxcUrlToHttp(avatarMxc, 80, 80, 'crop') : null; @@ -417,7 +419,7 @@ function ProfileViewer() { } diff --git a/src/app/organisms/profile-viewer/ProfileViewer.scss b/src/app/organisms/profile-viewer/ProfileViewer.scss index b8c46426..35119b92 100644 --- a/src/app/organisms/profile-viewer/ProfileViewer.scss +++ b/src/app/organisms/profile-viewer/ProfileViewer.scss @@ -16,7 +16,6 @@ &__user { display: flex; padding-bottom: var(--sp-normal); - border-bottom: 1px solid var(--bg-surface-border); &__info { align-self: flex-end; @@ -84,11 +83,18 @@ } .session-info { - & .setting-tile__title .text { - color: var(--tc-surface-high); - } + box-shadow: var(--bs-surface-border); + border-radius: var(--bo-radius); + overflow: hidden; + &__chips { + border-top: 1px solid var(--bg-surface-border); + padding: var(--sp-tight); padding-top: var(--sp-ultra-tight); + + & > .text { + margin-top: var(--sp-extra-tight); + } & .chip { margin-top: var(--sp-extra-tight); @include dir.side(margin, 0, var(--sp-extra-tight)); From 0e17c57856855bbdb9babb7a26cae71b03ca40f1 Mon Sep 17 00:00:00 2001 From: Ajay Bura Date: Thu, 13 Jan 2022 09:46:08 +0530 Subject: [PATCH 10/18] Remove mention button from profile viewer Signed-off-by: Ajay Bura --- src/app/organisms/profile-viewer/ProfileViewer.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/app/organisms/profile-viewer/ProfileViewer.jsx b/src/app/organisms/profile-viewer/ProfileViewer.jsx index fc33b6d1..9c064844 100644 --- a/src/app/organisms/profile-viewer/ProfileViewer.jsx +++ b/src/app/organisms/profile-viewer/ProfileViewer.jsx @@ -23,7 +23,6 @@ import Button from '../../atoms/button/Button'; import { MenuItem } from '../../atoms/context-menu/ContextMenu'; import PowerLevelSelector from '../../molecules/power-level-selector/PowerLevelSelector'; import Dialog from '../../molecules/dialog/Dialog'; -import SettingTile from '../../molecules/setting-tile/SettingTile'; import ShieldEmptyIC from '../../../../public/res/ic/outlined/shield-empty.svg'; import ChevronRightIC from '../../../../public/res/ic/outlined/chevron-right.svg'; @@ -259,7 +258,6 @@ function ProfileFooter({ roomId, userId, onRequestClose }) { > {isCreatingDM ? 'Creating room...' : 'Message'} - { member?.membership === 'join' && } { (isInvited ? canIKick : room.canInvite(mx.getUserId())) && isInvitable && ( + { isBanned && canIKick && ( + + )} { (isInvited ? canIKick : room.canInvite(mx.getUserId())) && isInvitable && ( @@ -31,6 +33,7 @@ function RoomSelectorWrapper({ } RoomSelectorWrapper.defaultProps = { options: null, + onContextMenu: null, }; RoomSelectorWrapper.propTypes = { isSelected: PropTypes.bool.isRequired, @@ -38,12 +41,13 @@ RoomSelectorWrapper.propTypes = { onClick: PropTypes.func.isRequired, content: PropTypes.node.isRequired, options: PropTypes.node, + onContextMenu: PropTypes.func, }; function RoomSelector({ name, parentName, roomId, imageSrc, iconSrc, isSelected, isUnread, notificationCount, isAlert, - options, onClick, + options, onClick, onContextMenu, }) { return ( ); } @@ -87,6 +92,7 @@ RoomSelector.defaultProps = { imageSrc: null, iconSrc: null, options: null, + onContextMenu: null, }; RoomSelector.propTypes = { name: PropTypes.string.isRequired, @@ -103,6 +109,7 @@ RoomSelector.propTypes = { isAlert: PropTypes.bool.isRequired, options: PropTypes.node, onClick: PropTypes.func.isRequired, + onContextMenu: PropTypes.func, }; export default RoomSelector; diff --git a/src/app/organisms/navigation/Selector.jsx b/src/app/organisms/navigation/Selector.jsx index 507dc425..e321db82 100644 --- a/src/app/organisms/navigation/Selector.jsx +++ b/src/app/organisms/navigation/Selector.jsx @@ -106,6 +106,7 @@ function Selector({ notificationCount={abbreviateNumber(noti.getTotalNoti(roomId))} isAlert={noti.getHighlightNoti(roomId) !== 0} onClick={onClick} + onContextMenu={openRoomOptions} options={( Date: Thu, 13 Jan 2022 18:43:22 +0530 Subject: [PATCH 18/18] Add afterClose param to reusabel context menu Signed-off-by: Ajay Bura --- src/app/atoms/context-menu/ReusableContextMenu.jsx | 7 +++++-- src/client/action/navigation.js | 3 ++- src/client/state/navigation.js | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/app/atoms/context-menu/ReusableContextMenu.jsx b/src/app/atoms/context-menu/ReusableContextMenu.jsx index f3a3c0d9..59bdb142 100644 --- a/src/app/atoms/context-menu/ReusableContextMenu.jsx +++ b/src/app/atoms/context-menu/ReusableContextMenu.jsx @@ -23,12 +23,14 @@ function ReusableContextMenu() { openerRef.current.style.height = `${cords.height}px`; openerRef.current.click(); } - const handleContextMenuOpen = (placement, cords, render) => { + const handleContextMenuOpen = (placement, cords, render, afterClose) => { if (key) { closeMenu(); return; } - setData({ placement, cords, render }); + setData({ + placement, cords, render, afterClose, + }); }; navigation.on(cons.events.navigation.REUSABLE_CONTEXT_MENU_OPENED, handleContextMenuOpen); return () => { @@ -44,6 +46,7 @@ function ReusableContextMenu() { key = Math.random(); return; } + data?.afterClose?.(); if (setData) setData(null); if (key === null) return; diff --git a/src/client/action/navigation.js b/src/client/action/navigation.js index 377a6158..28aa0477 100644 --- a/src/client/action/navigation.js +++ b/src/client/action/navigation.js @@ -103,11 +103,12 @@ export function openSearch(term) { }); } -export function openReusableContextMenu(placement, cords, render) { +export function openReusableContextMenu(placement, cords, render, afterClose) { appDispatcher.dispatch({ type: cons.actions.navigation.OPEN_REUSABLE_CONTEXT_MENU, placement, cords, render, + afterClose, }); } diff --git a/src/client/state/navigation.js b/src/client/state/navigation.js index 674449f2..977cf7e9 100644 --- a/src/client/state/navigation.js +++ b/src/client/state/navigation.js @@ -146,6 +146,7 @@ class Navigation extends EventEmitter { action.placement, action.cords, action.render, + action.afterClose, ); }, };