move room permission to new sdk

This commit is contained in:
Ajay Bura 2026-07-24 10:02:57 +05:30
commit f54880395b
4 changed files with 73 additions and 59 deletions

View file

@ -2,23 +2,28 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Badge, Box, Button, Chip, config, Icon, Icons, Menu, Spinner, Text } from 'folds';
import produce from 'immer';
import { putStateEvent } from 'neurone/lib/api/matrix/client/v3/rooms';
import { SequenceCard } from '../../../components/sequence-card';
import { SequenceCardStyle } from '../styles.css';
import { SettingTile } from '../../../components/setting-tile';
import {
applyPermissionPower,
getPermissionPower,
IPowerLevels,
PermissionLocation,
usePowerLevelsContext,
} from '../../../hooks/usePowerLevels';
import { PermissionGroup } from './types';
import { getPowerLevelTag, getPowers, usePowerLevelTags } from '../../../hooks/usePowerLevelTags';
import {
usePowerLevelTagsContext,
getPowers,
getPowerLevelTag,
} from '../../../hooks/usePowerLevelTags';
import { useRoom } from '../../../hooks/useRoom';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { StateEvent } from '../../../../types/matrix/room';
import { StateEventType } from '../../../../types/matrix/room';
import { PowerSwitcher } from '../../../components/power';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import { useAlive } from '../../../hooks/useAlive';
import { useClient } from '../../../hooks/useClient';
const USER_DEFAULT_LOCATION: PermissionLocation = {
user: true,
@ -26,19 +31,15 @@ const USER_DEFAULT_LOCATION: PermissionLocation = {
type PermissionGroupsProps = {
canEdit: boolean;
powerLevels: IPowerLevels;
permissionGroups: PermissionGroup[];
};
export function PermissionGroups({
powerLevels,
permissionGroups,
canEdit,
}: PermissionGroupsProps) {
const mx = useMatrixClient();
const room = useRoom();
export function PermissionGroups({ permissionGroups, canEdit }: PermissionGroupsProps) {
const ct = useClient();
const roomId = useRoom();
const alive = useAlive();
const powerLevelTags = usePowerLevelTags(room, powerLevels);
const powerLevels = usePowerLevelsContext();
const powerLevelTags = usePowerLevelTagsContext();
const maxPower = useMemo(() => Math.max(...getPowers(powerLevelTags)), [powerLevelTags]);
const [permissionUpdate, setPermissionUpdate] = useState<Map<PermissionLocation, number>>(
@ -85,8 +86,13 @@ export function PermissionGroups({
return draftPowerLevels;
});
await mx.sendStateEvent(room.roomId, StateEvent.RoomPowerLevels as any, editedPowerLevels);
}, [mx, room, powerLevels, permissionUpdate, permissionGroups])
await ct.requestAuthJSON(
putStateEvent({
pathParams: { roomId, eventType: StateEventType.RoomPowerLevels, stateKey: '' },
body: editedPowerLevels,
})
);
}, [ct, roomId, powerLevels, permissionUpdate, permissionGroups])
);
const resetChanges = useCallback(() => {

View file

@ -16,18 +16,22 @@ import {
} from 'folds';
import { SequenceCard } from '../../../components/sequence-card';
import { SequenceCardStyle } from '../styles.css';
import { getPowers, usePowerLevelTags } from '../../../hooks/usePowerLevelTags';
import { getPowers, usePowerLevelTagsContext } from '../../../hooks/usePowerLevelTags';
import { SettingTile } from '../../../components/setting-tile';
import { getPermissionPower, IPowerLevels } from '../../../hooks/usePowerLevels';
import {
getPermissionPower,
IPowerLevels,
usePowerLevelsContext,
} from '../../../hooks/usePowerLevels';
import { useRoom } from '../../../hooks/useRoom';
import { PowerColorBadge, PowerIcon } from '../../../components/power';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { useMediaAuthentication } from '../../../hooks/useMediaAuthentication';
import { stopPropagation } from '../../../utils/keyboard';
import { PermissionGroup } from './types';
import { getPowerTagIconSrc } from '../../../hooks/useMemberPowerTag';
import { useRoomCreatorsTag } from '../../../hooks/useRoomCreatorsTag';
import { useRoomCreators } from '../../../hooks/useRoomCreators';
import { useClient } from '../../../hooks/useClient';
type PeekPermissionsProps = {
powerLevels: IPowerLevels;
@ -103,23 +107,24 @@ function PeekPermissions({ powerLevels, power, permissionGroups, children }: Pee
}
type PowersProps = {
powerLevels: IPowerLevels;
permissionGroups: PermissionGroup[];
onEdit?: () => void;
};
export function Powers({ powerLevels, permissionGroups, onEdit }: PowersProps) {
const mx = useMatrixClient();
export function Powers({ permissionGroups, onEdit }: PowersProps) {
const ct = useClient();
const useAuthentication = useMediaAuthentication();
const room = useRoom();
const powerLevelTags = usePowerLevelTags(room, powerLevels);
const powerLevels = usePowerLevelsContext();
const powerLevelTags = usePowerLevelTagsContext();
const creators = useRoomCreators(room);
const creatorsTag = useRoomCreatorsTag();
const creatorTagIconSrc =
creatorsTag.icon && getPowerTagIconSrc(mx, useAuthentication, creatorsTag.icon);
creatorsTag.icon && getPowerTagIconSrc(ct, useAuthentication, creatorsTag.icon);
return (
<Box direction="Column" gap="100">
{creators.size > 0 && (
{creators && creators.size > 0 && (
<SequenceCard
variant="SurfaceVariant"
className={SequenceCardStyle}
@ -178,7 +183,7 @@ export function Powers({ powerLevels, permissionGroups, onEdit }: PowersProps) {
<Box gap="200" wrap="Wrap">
{getPowers(powerLevelTags).map((power) => {
const tag = powerLevelTags[power];
const tagIconSrc = tag.icon && getPowerTagIconSrc(mx, useAuthentication, tag.icon);
const tagIconSrc = tag.icon && getPowerTagIconSrc(ct, useAuthentication, tag.icon);
return (
<PeekPermissions

View file

@ -19,9 +19,9 @@ import {
Tooltip,
} from 'folds';
import { HexColorPicker } from 'react-colorful';
import { useAtomValue } from 'jotai';
import { putStateEvent } from 'neurone/lib/api/matrix/client/v3/rooms';
import { Page, PageContent, PageHeader } from '../../../components/page';
import { IPowerLevels } from '../../../hooks/usePowerLevels';
import { usePowerLevelsContext } from '../../../hooks/usePowerLevels';
import { SequenceCard } from '../../../components/sequence-card';
import { SequenceCardStyle } from '../styles.css';
import { SettingTile } from '../../../components/setting-tile';
@ -29,7 +29,7 @@ import {
getPowers,
getUsedPowers,
PowerLevelTags,
usePowerLevelTags,
usePowerLevelTagsContext,
} from '../../../hooks/usePowerLevelTags';
import { useRoom } from '../../../hooks/useRoom';
import { HexColorPickerPopOut } from '../../../components/HexColorPickerPopOut';
@ -37,18 +37,17 @@ import { PowerColorBadge, PowerIcon } from '../../../components/power';
import { UseStateProvider } from '../../../components/UseStateProvider';
import { EmojiBoard } from '../../../components/emoji-board';
import { useImagePackRooms } from '../../../hooks/useImagePackRooms';
import { roomToParentsAtom } from '../../../state/room/roomToParents';
import { useMediaAuthentication } from '../../../hooks/useMediaAuthentication';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { useFilePicker } from '../../../hooks/useFilePicker';
import { CompactUploadCardRenderer } from '../../../components/upload-card';
import { createUploadAtom, UploadSuccess } from '../../../state/upload';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import { MemberPowerTag, MemberPowerTagIcon, StateEvent } from '../../../../types/matrix/room';
import { MemberPowerTag, MemberPowerTagIcon, StateEventType } from '../../../../types/matrix/room';
import { useAlive } from '../../../hooks/useAlive';
import { BetaNoticeBadge } from '../../../components/BetaNoticeBadge';
import { getPowerTagIconSrc } from '../../../hooks/useMemberPowerTag';
import { creatorsSupported } from '../../../utils/matrix';
import { useClient } from '../../../hooks/useClient';
type EditPowerProps = {
maxPower: number;
@ -58,13 +57,12 @@ type EditPowerProps = {
onClose: () => void;
};
function EditPower({ maxPower, power, tag, onSave, onClose }: EditPowerProps) {
const mx = useMatrixClient();
const room = useRoom();
const roomToParents = useAtomValue(roomToParentsAtom);
const ct = useClient();
const roomId = useRoom();
const useAuthentication = useMediaAuthentication();
const supportCreators = creatorsSupported(room.getVersion());
const supportCreators = creatorsSupported(ct.roomToVersion.read.get(roomId) ?? '1');
const imagePackRooms = useImagePackRooms(room.roomId, roomToParents);
const imagePackRooms = useImagePackRooms(roomId);
const [iconFile, setIconFile] = useState<File>();
const pickFile = useFilePicker(setIconFile, false);
@ -72,7 +70,7 @@ function EditPower({ maxPower, power, tag, onSave, onClose }: EditPowerProps) {
const [tagColor, setTagColor] = useState<string | undefined>(tag?.color);
const [tagIcon, setTagIcon] = useState<MemberPowerTagIcon | undefined>(tag?.icon);
const uploadingIcon = iconFile && !tagIcon;
const tagIconSrc = tagIcon && getPowerTagIconSrc(mx, useAuthentication, tagIcon);
const tagIconSrc = tagIcon && getPowerTagIconSrc(ct, useAuthentication, tagIcon);
const iconUploadAtom = useMemo(() => {
if (iconFile) return createUploadAtom(iconFile);
@ -285,20 +283,22 @@ function EditPower({ maxPower, power, tag, onSave, onClose }: EditPowerProps) {
}
type PowersEditorProps = {
powerLevels: IPowerLevels;
requestClose: () => void;
};
export function PowersEditor({ powerLevels, requestClose }: PowersEditorProps) {
const mx = useMatrixClient();
export function PowersEditor({ requestClose }: PowersEditorProps) {
const ct = useClient();
const useAuthentication = useMediaAuthentication();
const room = useRoom();
const roomId = useRoom();
const alive = useAlive();
const powerLevels = usePowerLevelsContext();
const [usedPowers, maxPower] = useMemo(() => {
const up = getUsedPowers(powerLevels);
return [up, Math.max(...Array.from(up))];
}, [powerLevels]);
const powerLevelTags = usePowerLevelTags(room, powerLevels);
const powerLevelTags = usePowerLevelTagsContext();
const [editedPowerTags, setEditedPowerTags] = useState<PowerLevelTags>();
const [deleted, setDeleted] = useState<Set<number>>(new Set());
@ -333,8 +333,13 @@ export function PowersEditor({ powerLevels, requestClose }: PowersEditorProps) {
deleted.forEach((power) => {
delete content[power];
});
await mx.sendStateEvent(room.roomId, StateEvent.PowerLevelTags as any, content);
}, [mx, room, powerLevelTags, editedPowerTags, deleted])
await ct.requestAuthJSON(
putStateEvent({
pathParams: { roomId, eventType: StateEventType.PowerLevelTags, stateKey: '' },
body: content,
})
);
}, [ct, roomId, powerLevelTags, editedPowerTags, deleted])
);
const resetChanges = useCallback(() => {
@ -420,7 +425,7 @@ export function PowersEditor({ powerLevels, requestClose }: PowersEditorProps) {
{getPowers(powerTags).map((power) => {
const tag = powerTags[power];
const tagIconSrc =
tag.icon && getPowerTagIconSrc(mx, useAuthentication, tag.icon);
tag.icon && getPowerTagIconSrc(ct, useAuthentication, tag.icon);
return (
<SequenceCard

View file

@ -2,27 +2,30 @@ import React, { useState } from 'react';
import { Box, Icon, IconButton, Icons, Scroll, Text } from 'folds';
import { Page, PageContent, PageHeader } from '../../../components/page';
import { useRoom } from '../../../hooks/useRoom';
import { usePowerLevels } from '../../../hooks/usePowerLevels';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { StateEvent } from '../../../../types/matrix/room';
import { usePowerLevelsContext } from '../../../hooks/usePowerLevels';
import { StateEventType } from '../../../../types/matrix/room';
import { usePermissionGroups } from './usePermissionItems';
import { PermissionGroups, Powers, PowersEditor } from '../../common-settings/permissions';
import { useRoomCreators } from '../../../hooks/useRoomCreators';
import { useRoomPermissions } from '../../../hooks/useRoomPermissions';
import { useClient } from '../../../hooks/useClient';
type PermissionsProps = {
requestClose: () => void;
};
export function Permissions({ requestClose }: PermissionsProps) {
const mx = useMatrixClient();
const ct = useClient();
const room = useRoom();
const powerLevels = usePowerLevels(room);
const powerLevels = usePowerLevelsContext();
const creators = useRoomCreators(room);
const permissions = useRoomPermissions(creators, powerLevels);
const canEditPowers = permissions.stateEvent(StateEvent.PowerLevelTags, mx.getSafeUserId());
const canEditPermissions = permissions.stateEvent(StateEvent.RoomPowerLevels, mx.getSafeUserId());
const canEditPowers = permissions.stateEvent(StateEventType.PowerLevelTags, ct.session.userId);
const canEditPermissions = permissions.stateEvent(
StateEventType.RoomPowerLevels,
ct.session.userId
);
const permissionGroups = usePermissionGroups();
const [powerEditor, setPowerEditor] = useState(false);
@ -32,7 +35,7 @@ export function Permissions({ requestClose }: PermissionsProps) {
};
if (canEditPowers && powerEditor) {
return <PowersEditor powerLevels={powerLevels} requestClose={() => setPowerEditor(false)} />;
return <PowersEditor requestClose={() => setPowerEditor(false)} />;
}
return (
@ -56,15 +59,10 @@ export function Permissions({ requestClose }: PermissionsProps) {
<PageContent>
<Box direction="Column" gap="700">
<Powers
powerLevels={powerLevels}
onEdit={canEditPowers ? handleEditPowers : undefined}
permissionGroups={permissionGroups}
/>
<PermissionGroups
canEdit={canEditPermissions}
powerLevels={powerLevels}
permissionGroups={permissionGroups}
/>
<PermissionGroups canEdit={canEditPermissions} permissionGroups={permissionGroups} />
</Box>
</PageContent>
</Scroll>