feat: enhance update notification layout and add room info display in developer tools
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Text,
|
||||
@@ -11,7 +11,14 @@ import {
|
||||
MenuItem,
|
||||
config,
|
||||
color,
|
||||
TextArea,
|
||||
Dialog,
|
||||
Overlay,
|
||||
OverlayBackdrop,
|
||||
OverlayCenter,
|
||||
Modal,
|
||||
} from 'folds';
|
||||
import FocusTrap from 'focus-trap-react';
|
||||
import { Page, PageContent, PageHeader } from '../../../components/page';
|
||||
import { SequenceCard } from '../../../components/sequence-card';
|
||||
import { SequenceCardStyle } from '../styles.css';
|
||||
@@ -30,6 +37,10 @@ import {
|
||||
AccountDataSubmitCallback,
|
||||
} from '../../../components/AccountDataEditor';
|
||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
||||
import { stopPropagation } from '../../../utils/keyboard';
|
||||
import { usePowerLevels } from '../../../hooks/usePowerLevels';
|
||||
import { useRoomCreators } from '../../../hooks/useRoomCreators';
|
||||
import { isSpace } from '../../../utils/room';
|
||||
|
||||
type DeveloperToolsProps = {
|
||||
requestClose: () => void;
|
||||
@@ -41,6 +52,8 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||
|
||||
const roomState = useRoomState(room);
|
||||
const accountData = useRoomAccountData(room);
|
||||
const powerLevels = usePowerLevels(room);
|
||||
const creators = useRoomCreators(room);
|
||||
|
||||
const [expandState, setExpandState] = useState(false);
|
||||
const [expandStateType, setExpandStateType] = useState<string>();
|
||||
@@ -49,6 +62,72 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||
|
||||
const [expandAccountData, setExpandAccountData] = useState(false);
|
||||
const [accountDataType, setAccountDataType] = useState<string | null>();
|
||||
const [showRoomInfo, setShowRoomInfo] = useState(false);
|
||||
|
||||
const roomInfoJson = useMemo(() => {
|
||||
const liveTimeline = room.getLiveTimeline();
|
||||
const liveEvents = liveTimeline.getEvents();
|
||||
const oldestEvent = liveEvents.length > 0 ? liveEvents[0] : null;
|
||||
const newestEvent = liveEvents.length > 0 ? liveEvents[liveEvents.length - 1] : null;
|
||||
|
||||
// Get power level tags
|
||||
const powerLevelTagsEvent = room.currentState.getStateEvents('in.cinny.room.power_level_tags', '');
|
||||
const powerLevelTags = powerLevelTagsEvent?.getContent();
|
||||
|
||||
const info: any = {
|
||||
roomId: room.roomId,
|
||||
name: room.name,
|
||||
canonicalAlias: room.canonicalAlias,
|
||||
altAliases: room.getAltAliases(),
|
||||
isSpace: isSpace(room),
|
||||
joinRule: room.getJoinRule(),
|
||||
guestAccess: room.getGuestAccess(),
|
||||
historyVisibility: room.getHistoryVisibility(),
|
||||
myUserId: mx.getUserId(),
|
||||
myMembership: room.getMyMembership(),
|
||||
creator: Array.from(creators),
|
||||
memberCount: room.getJoinedMemberCount(),
|
||||
invitedMemberCount: room.getInvitedMemberCount(),
|
||||
powerLevels,
|
||||
powerLevelTags: powerLevelTags || null,
|
||||
tags: room.tags,
|
||||
notificationCounts: {
|
||||
total: room.getRoomUnreadNotificationCount('total'),
|
||||
highlight: room.getRoomUnreadNotificationCount('highlight'),
|
||||
},
|
||||
timeline: {
|
||||
oldestEventTs: oldestEvent?.getTs(),
|
||||
newestEventTs: newestEvent?.getTs(),
|
||||
liveEventsCount: liveEvents.length,
|
||||
timelineSetSize: room.getTimelineSets().length,
|
||||
},
|
||||
encryption: room.hasEncryptionStateEvent(),
|
||||
state: {} as any,
|
||||
accountData: {} as any,
|
||||
};
|
||||
|
||||
// Add all state events
|
||||
roomState.forEach((stateKeyToEvents, eventType) => {
|
||||
info.state[eventType] = {};
|
||||
stateKeyToEvents.forEach((event, stateKey) => {
|
||||
info.state[eventType][stateKey || '_default'] = {
|
||||
content: event.getContent(),
|
||||
sender: event.getSender(),
|
||||
stateKey: event.getStateKey(),
|
||||
eventId: event.getId(),
|
||||
timestamp: event.getTs(),
|
||||
unsigned: event.getUnsigned(),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// Add account data
|
||||
accountData.forEach((content, type) => {
|
||||
info.accountData[type] = content;
|
||||
});
|
||||
|
||||
return JSON.stringify(info, null, 2);
|
||||
}, [room, mx, roomState, accountData, powerLevels, creators]);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
setOpenStateEvent(undefined);
|
||||
@@ -82,6 +161,62 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||
return <StateEventEditor {...openStateEvent} requestClose={handleClose} />;
|
||||
}
|
||||
|
||||
if (showRoomInfo) {
|
||||
return (
|
||||
<Overlay open backdrop={<OverlayBackdrop />}>
|
||||
<OverlayCenter>
|
||||
<FocusTrap
|
||||
focusTrapOptions={{
|
||||
initialFocus: false,
|
||||
onDeactivate: () => setShowRoomInfo(false),
|
||||
escapeDeactivates: stopPropagation,
|
||||
}}
|
||||
>
|
||||
<Modal size="500" variant="Surface">
|
||||
<Box direction="Column" gap="400" style={{ height: '80vh' }}>
|
||||
<Box justifyContent="SpaceBetween" alignItems="Center" gap="200">
|
||||
<Text size="H4" truncate>
|
||||
{isSpace(room) ? 'Space' : 'Room'} Information
|
||||
</Text>
|
||||
<Box gap="200">
|
||||
<Button
|
||||
onClick={() => copyToClipboard(roomInfoJson)}
|
||||
variant="Secondary"
|
||||
fill="Soft"
|
||||
size="300"
|
||||
radii="300"
|
||||
>
|
||||
<Text size="B300">Copy All</Text>
|
||||
</Button>
|
||||
<IconButton onClick={() => setShowRoomInfo(false)} variant="Surface" size="300">
|
||||
<Icon src={Icons.Cross} size="200" />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box grow="Yes" style={{ minHeight: 0 }}>
|
||||
<Scroll hideTrack visibility="Hover" size="300">
|
||||
<TextArea
|
||||
style={{
|
||||
minHeight: '100%',
|
||||
fontFamily: 'monospace',
|
||||
fontSize: '12px',
|
||||
resize: 'none',
|
||||
}}
|
||||
defaultValue={roomInfoJson}
|
||||
readOnly
|
||||
autoComplete="off"
|
||||
onFocus={(e) => e.target.select()}
|
||||
/>
|
||||
</Scroll>
|
||||
</Box>
|
||||
</Box>
|
||||
</Modal>
|
||||
</FocusTrap>
|
||||
</OverlayCenter>
|
||||
</Overlay>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<PageHeader outlined={false}>
|
||||
@@ -144,6 +279,23 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<SettingTile
|
||||
title={`View ${isSpace(room) ? 'Space' : 'Room'} Information`}
|
||||
description="Display comprehensive information about this room/space including state, members, power levels, and more."
|
||||
after={
|
||||
<Button
|
||||
onClick={() => setShowRoomInfo(true)}
|
||||
variant="Primary"
|
||||
fill="Soft"
|
||||
size="300"
|
||||
radii="300"
|
||||
outlined
|
||||
before={<Icon src={Icons.Info} size="50" />}
|
||||
>
|
||||
<Text size="B300">View Info</Text>
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</SequenceCard>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
Reference in New Issue
Block a user