* rework general settings * account settings - WIP * add missing key prop * add object url hook * extract wide modal styles * profile settings and image editor - WIP * add outline style to upload card * remove file param from bind upload atom hook * add compact variant to upload card * add compact upload card renderer * add option to update profile avatar * add option to change profile displayname * allow displayname change based on capabilities check * rearrange settings components into folders * add system notification settings * add initial page param in settings * convert account data hook to typescript * add push rule hook * add notification mode hook * add notification mode switcher component * add all messages notification settings options * add special messages notification settings * add keyword notifications * add ignored users section * improve ignore user list strings * add about settings * add access token option in about settings * add developer tools settings * add expand button to account data dev tool option * update folds * fix editable active element textarea check * do not close dialog when editable element in focus * add text area plugins * add text area intent handler hook * add newline intent mod in text area * add next line hotkey in text area intent hook * add syntax error position dom utility function * add account data editor * add button to send new account data in dev tools * improve custom emoji plugin * add more custom emojis hooks * add text util css * add word break in setting tile title and description * emojis and sticker user settings - WIP * view image packs from settings * emoji pack editing - WIP * add option to edit pack meta * change saved changes message * add image edit and delete controls * add option to upload pack images and apply changes * fix state event type when updating image pack * lazy load pack image tile img * hide upload image button when user can not edit pack * add option to add or remove global image packs * upgrade to rust crypto (#2168) * update matrix js sdk * remove dead code * use rust crypto * update setPowerLevel usage * fix types * fix deprecated isRoomEncrypted method uses * fix deprecated room.currentState uses * fix deprecated import/export room keys func * fix merge issues in image pack file * fix remaining issues in image pack file * start indexedDBStore * update package lock and vite-plugin-top-level-await * user session settings - WIP * add useAsync hook * add password stage uia * add uia flow matrix error hook * add UIA action component * add options to delete sessions * add sso uia stage * fix SSO stage complete error * encryption - WIP * update user settings encryption terminology * add default variant to password input * use password input in uia password stage * add options for local backup in user settings * remove typo in import local backup password input label * online backup - WIP * fix uia sso action * move access token settings from about to developer tools * merge encryption tab into sessions and rename it to devices * add device placeholder tile * add logout dialog * add logout button for current device * move other devices in component * render unverified device verification tile * add learn more section for current device verification * add device verification status badge * add info card component * add index file for password input component * add types for secret storage * add component to access secret storage key * manual verification - WIP * update matrix-js-sdk to v35 * add manual verification * use react query for device list * show unverified tab on sidebar * fix device list updates * add session key details to current device * render restore encryption backup * fix loading state of restore backup * fix unverified tab settings closes after verification * key backup tile - WIP * fix unverified tab badge * rename session key to device key in device tile * improve backup restore functionality * fix restore button enabled after layout reload during restoring backup * update backup info on status change * add backup disconnection failures * add device verification using sas * restore backup after verification * show option to logout on startup error screen * fix key backup hook update on decryption key cached * add option to enable device verification * add device verification reset dialog * add logout button in settings drawer * add encrypted message lost on logout * fix backup restore never finish with 0 keys * fix setup dialog hides when enabling device verification * show backup details in menu * update setup device verification body copy * replace deprecated method * fix displayname appear as mxid in settings * remove old refactored codes * fix types
284 lines
8.9 KiB
JavaScript
284 lines
8.9 KiB
JavaScript
import React, { useEffect } from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import './RoomPermissions.scss';
|
|
import { EventTimeline } from 'matrix-js-sdk';
|
|
|
|
import { getPowerLabel } from '../../../util/matrixUtil';
|
|
import { openReusableContextMenu } from '../../../client/action/navigation';
|
|
import { getEventCords } from '../../../util/common';
|
|
|
|
import Text from '../../atoms/text/Text';
|
|
import Button from '../../atoms/button/Button';
|
|
import { MenuHeader } from '../../atoms/context-menu/ContextMenu';
|
|
import PowerLevelSelector from '../power-level-selector/PowerLevelSelector';
|
|
import SettingTile from '../setting-tile/SettingTile';
|
|
|
|
import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg';
|
|
|
|
import { useForceUpdate } from '../../hooks/useForceUpdate';
|
|
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
|
import { getStateEvent } from '../../utils/room';
|
|
|
|
const permissionsInfo = {
|
|
users_default: {
|
|
name: 'Default role',
|
|
description: 'Set default role for all members.',
|
|
default: 0,
|
|
},
|
|
events_default: {
|
|
name: 'Send messages',
|
|
description: 'Set minimum power level to send messages in room.',
|
|
default: 0,
|
|
},
|
|
'm.reaction': {
|
|
parent: 'events',
|
|
name: 'Send reactions',
|
|
description: 'Set minimum power level to send reactions in room.',
|
|
default: 0,
|
|
},
|
|
redact: {
|
|
name: 'Delete messages sent by others',
|
|
description: 'Set minimum power level to delete messages in room.',
|
|
default: 50,
|
|
},
|
|
notifications: {
|
|
name: 'Ping room',
|
|
description: 'Set minimum power level to ping room.',
|
|
default: {
|
|
room: 50,
|
|
},
|
|
},
|
|
'm.space.child': {
|
|
parent: 'events',
|
|
name: 'Manage rooms in space',
|
|
description: 'Set minimum power level to manage rooms in space.',
|
|
default: 50,
|
|
},
|
|
invite: {
|
|
name: 'Invite',
|
|
description: 'Set minimum power level to invite members.',
|
|
default: 50,
|
|
},
|
|
kick: {
|
|
name: 'Kick',
|
|
description: 'Set minimum power level to kick members.',
|
|
default: 50,
|
|
},
|
|
ban: {
|
|
name: 'Ban',
|
|
description: 'Set minimum power level to ban members.',
|
|
default: 50,
|
|
},
|
|
'm.room.avatar': {
|
|
parent: 'events',
|
|
name: 'Change avatar',
|
|
description: 'Set minimum power level to change room/space avatar.',
|
|
default: 50,
|
|
},
|
|
'm.room.name': {
|
|
parent: 'events',
|
|
name: 'Change name',
|
|
description: 'Set minimum power level to change room/space name.',
|
|
default: 50,
|
|
},
|
|
'm.room.topic': {
|
|
parent: 'events',
|
|
name: 'Change topic',
|
|
description: 'Set minimum power level to change room/space topic.',
|
|
default: 50,
|
|
},
|
|
state_default: {
|
|
name: 'Change settings',
|
|
description: 'Set minimum power level to change settings.',
|
|
default: 50,
|
|
},
|
|
'm.room.canonical_alias': {
|
|
parent: 'events',
|
|
name: 'Change published address',
|
|
description: 'Set minimum power level to publish and set main address.',
|
|
default: 50,
|
|
},
|
|
'm.room.power_levels': {
|
|
parent: 'events',
|
|
name: 'Change permissions',
|
|
description: 'Set minimum power level to change permissions.',
|
|
default: 50,
|
|
},
|
|
'm.room.encryption': {
|
|
parent: 'events',
|
|
name: 'Enable room encryption',
|
|
description: 'Set minimum power level to enable room encryption.',
|
|
default: 50,
|
|
},
|
|
'm.room.history_visibility': {
|
|
parent: 'events',
|
|
name: 'Change history visibility',
|
|
description: 'Set minimum power level to change room messages history visibility.',
|
|
default: 50,
|
|
},
|
|
'm.room.tombstone': {
|
|
parent: 'events',
|
|
name: 'Upgrade room',
|
|
description: 'Set minimum power level to upgrade room.',
|
|
default: 50,
|
|
},
|
|
'm.room.pinned_events': {
|
|
parent: 'events',
|
|
name: 'Pin messages',
|
|
description: 'Set minimum power level to pin messages in room.',
|
|
default: 50,
|
|
},
|
|
'm.room.server_acl': {
|
|
parent: 'events',
|
|
name: 'Change server ACLs',
|
|
description: 'Set minimum power level to change server ACLs.',
|
|
default: 50,
|
|
},
|
|
'im.vector.modular.widgets': {
|
|
parent: 'events',
|
|
name: 'Modify widgets',
|
|
description: 'Set minimum power level to modify room widgets.',
|
|
default: 50,
|
|
},
|
|
};
|
|
|
|
const roomPermsGroups = {
|
|
'General Permissions': ['users_default', 'events_default', 'm.reaction', 'redact', 'notifications'],
|
|
'Manage members permissions': ['invite', 'kick', 'ban'],
|
|
'Room profile permissions': ['m.room.avatar', 'm.room.name', 'm.room.topic'],
|
|
'Settings permissions': ['state_default', 'm.room.canonical_alias', 'm.room.power_levels', 'm.room.encryption', 'm.room.history_visibility'],
|
|
'Other permissions': ['m.room.tombstone', 'm.room.pinned_events', 'm.room.server_acl', 'im.vector.modular.widgets'],
|
|
};
|
|
|
|
const spacePermsGroups = {
|
|
'General Permissions': ['users_default', 'm.space.child'],
|
|
'Manage members permissions': ['invite', 'kick', 'ban'],
|
|
'Space profile permissions': ['m.room.avatar', 'm.room.name', 'm.room.topic'],
|
|
'Settings permissions': ['state_default', 'm.room.canonical_alias', 'm.room.power_levels'],
|
|
};
|
|
|
|
function useRoomStateUpdate(roomId) {
|
|
const [, forceUpdate] = useForceUpdate();
|
|
const mx = useMatrixClient();
|
|
|
|
useEffect(() => {
|
|
const handleStateEvent = (event) => {
|
|
if (event.getRoomId() !== roomId) return;
|
|
forceUpdate();
|
|
};
|
|
|
|
mx.on('RoomState.events', handleStateEvent);
|
|
return () => {
|
|
mx.removeListener('RoomState.events', handleStateEvent);
|
|
};
|
|
}, [mx, roomId]);
|
|
}
|
|
|
|
function RoomPermissions({ roomId }) {
|
|
useRoomStateUpdate(roomId);
|
|
const mx = useMatrixClient();
|
|
const room = mx.getRoom(roomId);
|
|
const pLEvent = getStateEvent(room, 'm.room.power_levels');
|
|
const permissions = pLEvent.getContent();
|
|
const canChangePermission = room.getLiveTimeline().getState(EventTimeline.FORWARDS)?.maySendStateEvent('m.room.power_levels', mx.getUserId());
|
|
const myPowerLevel = room.getMember(mx.getUserId())?.powerLevel ?? 100;
|
|
|
|
const handlePowerSelector = (e, permKey, parentKey, powerLevel) => {
|
|
const handlePowerLevelChange = (newPowerLevel) => {
|
|
if (powerLevel === newPowerLevel) return;
|
|
|
|
const newPermissions = { ...permissions };
|
|
if (parentKey) {
|
|
newPermissions[parentKey] = {
|
|
...permissions[parentKey],
|
|
[permKey]: newPowerLevel,
|
|
};
|
|
} else if (permKey === 'notifications') {
|
|
newPermissions[permKey] = {
|
|
...permissions[permKey],
|
|
room: newPowerLevel,
|
|
};
|
|
} else {
|
|
newPermissions[permKey] = newPowerLevel;
|
|
}
|
|
|
|
mx.sendStateEvent(roomId, 'm.room.power_levels', newPermissions);
|
|
};
|
|
|
|
openReusableContextMenu(
|
|
'bottom',
|
|
getEventCords(e, '.btn-surface'),
|
|
(closeMenu) => (
|
|
<PowerLevelSelector
|
|
value={powerLevel}
|
|
max={myPowerLevel}
|
|
onSelect={(pl) => {
|
|
closeMenu();
|
|
handlePowerLevelChange(pl);
|
|
}}
|
|
/>
|
|
),
|
|
);
|
|
};
|
|
|
|
const permsGroups = room.isSpaceRoom() ? spacePermsGroups : roomPermsGroups;
|
|
return (
|
|
<div className="room-permissions">
|
|
{
|
|
Object.keys(permsGroups).map((groupKey) => {
|
|
const groupedPermKeys = permsGroups[groupKey];
|
|
return (
|
|
<div className="room-permissions__card" key={groupKey}>
|
|
<MenuHeader>{groupKey}</MenuHeader>
|
|
{
|
|
groupedPermKeys.map((permKey) => {
|
|
const permInfo = permissionsInfo[permKey];
|
|
|
|
let powerLevel = 0;
|
|
let permValue = permInfo.parent
|
|
? permissions[permInfo.parent]?.[permKey]
|
|
: permissions[permKey];
|
|
|
|
if (permValue === undefined) permValue = permInfo.default;
|
|
|
|
if (typeof permValue === 'number') {
|
|
powerLevel = permValue;
|
|
} else if (permKey === 'notifications') {
|
|
powerLevel = permValue.room ?? 50;
|
|
}
|
|
return (
|
|
<SettingTile
|
|
key={permKey}
|
|
title={permInfo.name}
|
|
content={<Text variant="b3">{permInfo.description}</Text>}
|
|
options={(
|
|
<Button
|
|
onClick={
|
|
canChangePermission
|
|
? (e) => handlePowerSelector(e, permKey, permInfo.parent, powerLevel)
|
|
: null
|
|
}
|
|
iconSrc={canChangePermission ? ChevronBottomIC : null}
|
|
>
|
|
<Text variant="b2">
|
|
{`${getPowerLabel(powerLevel) || 'Member'} - ${powerLevel}`}
|
|
</Text>
|
|
</Button>
|
|
)}
|
|
/>
|
|
);
|
|
})
|
|
}
|
|
</div>
|
|
);
|
|
})
|
|
}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
RoomPermissions.propTypes = {
|
|
roomId: PropTypes.string.isRequired,
|
|
};
|
|
|
|
export default RoomPermissions;
|