mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-09-13 22:32:26 +03:00
Fix space navigation & view space timeline dev-option (#2358)
* fix inaccessible space on alias change * fix new room in space open in home * allow opening space timeline * hide event timeline feature behind dev tool * add navToActivePath to clear cache function
This commit is contained in:
parent
e6f4eeca8e
commit
91632aa193
6 changed files with 81 additions and 15 deletions
|
@ -13,6 +13,8 @@ import { getOrphanParents } from '../utils/room';
|
||||||
import { roomToParentsAtom } from '../state/room/roomToParents';
|
import { roomToParentsAtom } from '../state/room/roomToParents';
|
||||||
import { mDirectAtom } from '../state/mDirectList';
|
import { mDirectAtom } from '../state/mDirectList';
|
||||||
import { useSelectedSpace } from './router/useSelectedSpace';
|
import { useSelectedSpace } from './router/useSelectedSpace';
|
||||||
|
import { settingsAtom } from '../state/settings';
|
||||||
|
import { useSetting } from '../state/hooks/settings';
|
||||||
|
|
||||||
export const useRoomNavigate = () => {
|
export const useRoomNavigate = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
@ -20,6 +22,7 @@ export const useRoomNavigate = () => {
|
||||||
const roomToParents = useAtomValue(roomToParentsAtom);
|
const roomToParents = useAtomValue(roomToParentsAtom);
|
||||||
const mDirects = useAtomValue(mDirectAtom);
|
const mDirects = useAtomValue(mDirectAtom);
|
||||||
const spaceSelectedId = useSelectedSpace();
|
const spaceSelectedId = useSelectedSpace();
|
||||||
|
const [developerTools] = useSetting(settingsAtom, 'developerTools');
|
||||||
|
|
||||||
const navigateSpace = useCallback(
|
const navigateSpace = useCallback(
|
||||||
(roomId: string) => {
|
(roomId: string) => {
|
||||||
|
@ -32,15 +35,22 @@ export const useRoomNavigate = () => {
|
||||||
const navigateRoom = useCallback(
|
const navigateRoom = useCallback(
|
||||||
(roomId: string, eventId?: string, opts?: NavigateOptions) => {
|
(roomId: string, eventId?: string, opts?: NavigateOptions) => {
|
||||||
const roomIdOrAlias = getCanonicalAliasOrRoomId(mx, roomId);
|
const roomIdOrAlias = getCanonicalAliasOrRoomId(mx, roomId);
|
||||||
|
const openSpaceTimeline = developerTools && spaceSelectedId === roomId;
|
||||||
|
|
||||||
const orphanParents = getOrphanParents(roomToParents, roomId);
|
const orphanParents = openSpaceTimeline ? [roomId] : getOrphanParents(roomToParents, roomId);
|
||||||
if (orphanParents.length > 0) {
|
if (orphanParents.length > 0) {
|
||||||
const pSpaceIdOrAlias = getCanonicalAliasOrRoomId(
|
const pSpaceIdOrAlias = getCanonicalAliasOrRoomId(
|
||||||
mx,
|
mx,
|
||||||
spaceSelectedId && orphanParents.includes(spaceSelectedId)
|
spaceSelectedId && orphanParents.includes(spaceSelectedId)
|
||||||
? spaceSelectedId
|
? spaceSelectedId
|
||||||
: orphanParents[0]
|
: orphanParents[0] // TODO: better orphan parent selection.
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (openSpaceTimeline) {
|
||||||
|
navigate(getSpaceRoomPath(pSpaceIdOrAlias, roomId, eventId), opts);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
navigate(getSpaceRoomPath(pSpaceIdOrAlias, roomIdOrAlias, eventId), opts);
|
navigate(getSpaceRoomPath(pSpaceIdOrAlias, roomIdOrAlias, eventId), opts);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -52,7 +62,7 @@ export const useRoomNavigate = () => {
|
||||||
|
|
||||||
navigate(getHomeRoomPath(roomIdOrAlias, eventId), opts);
|
navigate(getHomeRoomPath(roomIdOrAlias, eventId), opts);
|
||||||
},
|
},
|
||||||
[mx, navigate, spaceSelectedId, roomToParents, mDirects]
|
[mx, navigate, spaceSelectedId, roomToParents, mDirects, developerTools]
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -744,13 +744,14 @@ export function SpaceTabs({ scrollRef }: SpaceTabsProps) {
|
||||||
const targetSpaceId = target.getAttribute('data-id');
|
const targetSpaceId = target.getAttribute('data-id');
|
||||||
if (!targetSpaceId) return;
|
if (!targetSpaceId) return;
|
||||||
|
|
||||||
|
const spacePath = getSpacePath(getCanonicalAliasOrRoomId(mx, targetSpaceId));
|
||||||
if (screenSize === ScreenSize.Mobile) {
|
if (screenSize === ScreenSize.Mobile) {
|
||||||
navigate(getSpacePath(getCanonicalAliasOrRoomId(mx, targetSpaceId)));
|
navigate(spacePath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const activePath = navToActivePath.get(targetSpaceId);
|
const activePath = navToActivePath.get(targetSpaceId);
|
||||||
if (activePath) {
|
if (activePath && activePath.pathname.startsWith(spacePath)) {
|
||||||
navigate(joinPathComponent(activePath));
|
navigate(joinPathComponent(activePath));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
import React, { ReactNode } from 'react';
|
import React, { ReactNode } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtom, useAtomValue } from 'jotai';
|
||||||
import { useSelectedRoom } from '../../../hooks/router/useSelectedRoom';
|
import { useSelectedRoom } from '../../../hooks/router/useSelectedRoom';
|
||||||
import { IsDirectRoomProvider, RoomProvider } from '../../../hooks/useRoom';
|
import { IsDirectRoomProvider, RoomProvider } from '../../../hooks/useRoom';
|
||||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
||||||
import { JoinBeforeNavigate } from '../../../features/join-before-navigate';
|
import { JoinBeforeNavigate } from '../../../features/join-before-navigate';
|
||||||
import { useSpace } from '../../../hooks/useSpace';
|
import { useSpace } from '../../../hooks/useSpace';
|
||||||
import { getAllParents } from '../../../utils/room';
|
import { getAllParents, getSpaceChildren } from '../../../utils/room';
|
||||||
import { roomToParentsAtom } from '../../../state/room/roomToParents';
|
import { roomToParentsAtom } from '../../../state/room/roomToParents';
|
||||||
import { allRoomsAtom } from '../../../state/room-list/roomList';
|
import { allRoomsAtom } from '../../../state/room-list/roomList';
|
||||||
import { useSearchParamsViaServers } from '../../../hooks/router/useSearchParamsViaServers';
|
import { useSearchParamsViaServers } from '../../../hooks/router/useSearchParamsViaServers';
|
||||||
import { mDirectAtom } from '../../../state/mDirectList';
|
import { mDirectAtom } from '../../../state/mDirectList';
|
||||||
|
import { settingsAtom } from '../../../state/settings';
|
||||||
|
import { useSetting } from '../../../state/hooks/settings';
|
||||||
|
|
||||||
export function SpaceRouteRoomProvider({ children }: { children: ReactNode }) {
|
export function SpaceRouteRoomProvider({ children }: { children: ReactNode }) {
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const space = useSpace();
|
const space = useSpace();
|
||||||
const roomToParents = useAtomValue(roomToParentsAtom);
|
const [developerTools] = useSetting(settingsAtom, 'developerTools');
|
||||||
|
const [roomToParents, setRoomToParents] = useAtom(roomToParentsAtom);
|
||||||
const mDirects = useAtomValue(mDirectAtom);
|
const mDirects = useAtomValue(mDirectAtom);
|
||||||
const allRooms = useAtomValue(allRoomsAtom);
|
const allRooms = useAtomValue(allRoomsAtom);
|
||||||
|
|
||||||
|
@ -24,12 +27,36 @@ export function SpaceRouteRoomProvider({ children }: { children: ReactNode }) {
|
||||||
const roomId = useSelectedRoom();
|
const roomId = useSelectedRoom();
|
||||||
const room = mx.getRoom(roomId);
|
const room = mx.getRoom(roomId);
|
||||||
|
|
||||||
if (
|
if (!room || !allRooms.includes(room.roomId)) {
|
||||||
!room ||
|
// room is not joined
|
||||||
room.isSpaceRoom() ||
|
return (
|
||||||
!allRooms.includes(room.roomId) ||
|
<JoinBeforeNavigate
|
||||||
!getAllParents(roomToParents, room.roomId).has(space.roomId)
|
roomIdOrAlias={roomIdOrAlias!}
|
||||||
) {
|
eventId={eventId}
|
||||||
|
viaServers={viaServers}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (developerTools && room.isSpaceRoom() && room.roomId === space.roomId) {
|
||||||
|
// allow to view space timeline
|
||||||
|
return (
|
||||||
|
<RoomProvider key={room.roomId} value={room}>
|
||||||
|
<IsDirectRoomProvider value={mDirects.has(room.roomId)}>{children}</IsDirectRoomProvider>
|
||||||
|
</RoomProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!getAllParents(roomToParents, room.roomId).has(space.roomId)) {
|
||||||
|
if (getSpaceChildren(space).includes(room.roomId)) {
|
||||||
|
// fill missing roomToParent mapping
|
||||||
|
setRoomToParents({
|
||||||
|
type: 'PUT',
|
||||||
|
parent: space.roomId,
|
||||||
|
children: [room.roomId],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<JoinBeforeNavigate
|
<JoinBeforeNavigate
|
||||||
roomIdOrAlias={roomIdOrAlias!}
|
roomIdOrAlias={roomIdOrAlias!}
|
||||||
|
|
|
@ -75,6 +75,7 @@ import {
|
||||||
useRoomsNotificationPreferencesContext,
|
useRoomsNotificationPreferencesContext,
|
||||||
} from '../../../hooks/useRoomsNotificationPreferences';
|
} from '../../../hooks/useRoomsNotificationPreferences';
|
||||||
import { useOpenSpaceSettings } from '../../../state/hooks/spaceSettings';
|
import { useOpenSpaceSettings } from '../../../state/hooks/spaceSettings';
|
||||||
|
import { useRoomNavigate } from '../../../hooks/useRoomNavigate';
|
||||||
|
|
||||||
type SpaceMenuProps = {
|
type SpaceMenuProps = {
|
||||||
room: Room;
|
room: Room;
|
||||||
|
@ -83,11 +84,13 @@ type SpaceMenuProps = {
|
||||||
const SpaceMenu = forwardRef<HTMLDivElement, SpaceMenuProps>(({ room, requestClose }, ref) => {
|
const SpaceMenu = forwardRef<HTMLDivElement, SpaceMenuProps>(({ room, requestClose }, ref) => {
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const [hideActivity] = useSetting(settingsAtom, 'hideActivity');
|
const [hideActivity] = useSetting(settingsAtom, 'hideActivity');
|
||||||
|
const [developerTools] = useSetting(settingsAtom, 'developerTools');
|
||||||
const roomToParents = useAtomValue(roomToParentsAtom);
|
const roomToParents = useAtomValue(roomToParentsAtom);
|
||||||
const powerLevels = usePowerLevels(room);
|
const powerLevels = usePowerLevels(room);
|
||||||
const { getPowerLevel, canDoAction } = usePowerLevelsAPI(powerLevels);
|
const { getPowerLevel, canDoAction } = usePowerLevelsAPI(powerLevels);
|
||||||
const canInvite = canDoAction('invite', getPowerLevel(mx.getUserId() ?? ''));
|
const canInvite = canDoAction('invite', getPowerLevel(mx.getUserId() ?? ''));
|
||||||
const openSpaceSettings = useOpenSpaceSettings();
|
const openSpaceSettings = useOpenSpaceSettings();
|
||||||
|
const { navigateRoom } = useRoomNavigate();
|
||||||
|
|
||||||
const allChild = useSpaceChildren(
|
const allChild = useSpaceChildren(
|
||||||
allRoomsAtom,
|
allRoomsAtom,
|
||||||
|
@ -118,6 +121,11 @@ const SpaceMenu = forwardRef<HTMLDivElement, SpaceMenuProps>(({ room, requestClo
|
||||||
requestClose();
|
requestClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleOpenTimeline = () => {
|
||||||
|
navigateRoom(room.roomId);
|
||||||
|
requestClose();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Menu ref={ref} style={{ maxWidth: toRem(160), width: '100vw' }}>
|
<Menu ref={ref} style={{ maxWidth: toRem(160), width: '100vw' }}>
|
||||||
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
|
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
|
||||||
|
@ -168,6 +176,18 @@ const SpaceMenu = forwardRef<HTMLDivElement, SpaceMenuProps>(({ room, requestClo
|
||||||
Space Settings
|
Space Settings
|
||||||
</Text>
|
</Text>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
{developerTools && (
|
||||||
|
<MenuItem
|
||||||
|
onClick={handleOpenTimeline}
|
||||||
|
size="300"
|
||||||
|
after={<Icon size="100" src={Icons.Terminal} />}
|
||||||
|
radii="300"
|
||||||
|
>
|
||||||
|
<Text style={{ flexGrow: 1 }} as="span" size="T300" truncate>
|
||||||
|
Event Timeline
|
||||||
|
</Text>
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<Line variant="Surface" size="300" />
|
<Line variant="Surface" size="300" />
|
||||||
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
|
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
|
||||||
|
|
|
@ -9,6 +9,8 @@ import {
|
||||||
|
|
||||||
const NAV_TO_ACTIVE_PATH = 'navToActivePath';
|
const NAV_TO_ACTIVE_PATH = 'navToActivePath';
|
||||||
|
|
||||||
|
const getStoreKey = (userId: string): string => `${NAV_TO_ACTIVE_PATH}${userId}`;
|
||||||
|
|
||||||
type NavToActivePath = Map<string, Path>;
|
type NavToActivePath = Map<string, Path>;
|
||||||
|
|
||||||
type NavToActivePathAction =
|
type NavToActivePathAction =
|
||||||
|
@ -25,7 +27,7 @@ type NavToActivePathAction =
|
||||||
export type NavToActivePathAtom = WritableAtom<NavToActivePath, [NavToActivePathAction], undefined>;
|
export type NavToActivePathAtom = WritableAtom<NavToActivePath, [NavToActivePathAction], undefined>;
|
||||||
|
|
||||||
export const makeNavToActivePathAtom = (userId: string): NavToActivePathAtom => {
|
export const makeNavToActivePathAtom = (userId: string): NavToActivePathAtom => {
|
||||||
const storeKey = `${NAV_TO_ACTIVE_PATH}${userId}`;
|
const storeKey = getStoreKey(userId);
|
||||||
|
|
||||||
const baseNavToActivePathAtom = atomWithLocalStorage<NavToActivePath>(
|
const baseNavToActivePathAtom = atomWithLocalStorage<NavToActivePath>(
|
||||||
storeKey,
|
storeKey,
|
||||||
|
@ -64,3 +66,7 @@ export const makeNavToActivePathAtom = (userId: string): NavToActivePathAtom =>
|
||||||
|
|
||||||
return navToActivePathAtom;
|
return navToActivePathAtom;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const clearNavToActivePathStore = (userId: string) => {
|
||||||
|
localStorage.removeItem(getStoreKey(userId));
|
||||||
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { createClient, MatrixClient, IndexedDBStore, IndexedDBCryptoStore } from 'matrix-js-sdk';
|
import { createClient, MatrixClient, IndexedDBStore, IndexedDBCryptoStore } from 'matrix-js-sdk';
|
||||||
|
|
||||||
import { cryptoCallbacks } from './state/secretStorageKeys';
|
import { cryptoCallbacks } from './state/secretStorageKeys';
|
||||||
|
import { clearNavToActivePathStore } from '../app/state/navToActivePath';
|
||||||
|
|
||||||
type Session = {
|
type Session = {
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
|
@ -46,6 +47,7 @@ export const startClient = async (mx: MatrixClient) => {
|
||||||
|
|
||||||
export const clearCacheAndReload = async (mx: MatrixClient) => {
|
export const clearCacheAndReload = async (mx: MatrixClient) => {
|
||||||
mx.stopClient();
|
mx.stopClient();
|
||||||
|
clearNavToActivePathStore(mx.getSafeUserId());
|
||||||
await mx.store.deleteAllData();
|
await mx.store.deleteAllData();
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue