mirror of
				https://github.com/cinnyapp/cinny.git
				synced 2025-11-04 06:20:28 +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 { mDirectAtom } from '../state/mDirectList';
 | 
			
		||||
import { useSelectedSpace } from './router/useSelectedSpace';
 | 
			
		||||
import { settingsAtom } from '../state/settings';
 | 
			
		||||
import { useSetting } from '../state/hooks/settings';
 | 
			
		||||
 | 
			
		||||
export const useRoomNavigate = () => {
 | 
			
		||||
  const navigate = useNavigate();
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +22,7 @@ export const useRoomNavigate = () => {
 | 
			
		|||
  const roomToParents = useAtomValue(roomToParentsAtom);
 | 
			
		||||
  const mDirects = useAtomValue(mDirectAtom);
 | 
			
		||||
  const spaceSelectedId = useSelectedSpace();
 | 
			
		||||
  const [developerTools] = useSetting(settingsAtom, 'developerTools');
 | 
			
		||||
 | 
			
		||||
  const navigateSpace = useCallback(
 | 
			
		||||
    (roomId: string) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -32,15 +35,22 @@ export const useRoomNavigate = () => {
 | 
			
		|||
  const navigateRoom = useCallback(
 | 
			
		||||
    (roomId: string, eventId?: string, opts?: NavigateOptions) => {
 | 
			
		||||
      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) {
 | 
			
		||||
        const pSpaceIdOrAlias = getCanonicalAliasOrRoomId(
 | 
			
		||||
          mx,
 | 
			
		||||
          spaceSelectedId && orphanParents.includes(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);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +62,7 @@ export const useRoomNavigate = () => {
 | 
			
		|||
 | 
			
		||||
      navigate(getHomeRoomPath(roomIdOrAlias, eventId), opts);
 | 
			
		||||
    },
 | 
			
		||||
    [mx, navigate, spaceSelectedId, roomToParents, mDirects]
 | 
			
		||||
    [mx, navigate, spaceSelectedId, roomToParents, mDirects, developerTools]
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -744,13 +744,14 @@ export function SpaceTabs({ scrollRef }: SpaceTabsProps) {
 | 
			
		|||
    const targetSpaceId = target.getAttribute('data-id');
 | 
			
		||||
    if (!targetSpaceId) return;
 | 
			
		||||
 | 
			
		||||
    const spacePath = getSpacePath(getCanonicalAliasOrRoomId(mx, targetSpaceId));
 | 
			
		||||
    if (screenSize === ScreenSize.Mobile) {
 | 
			
		||||
      navigate(getSpacePath(getCanonicalAliasOrRoomId(mx, targetSpaceId)));
 | 
			
		||||
      navigate(spacePath);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const activePath = navToActivePath.get(targetSpaceId);
 | 
			
		||||
    if (activePath) {
 | 
			
		||||
    if (activePath && activePath.pathname.startsWith(spacePath)) {
 | 
			
		||||
      navigate(joinPathComponent(activePath));
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,21 +1,24 @@
 | 
			
		|||
import React, { ReactNode } from 'react';
 | 
			
		||||
import { useParams } from 'react-router-dom';
 | 
			
		||||
import { useAtomValue } from 'jotai';
 | 
			
		||||
import { useAtom, useAtomValue } from 'jotai';
 | 
			
		||||
import { useSelectedRoom } from '../../../hooks/router/useSelectedRoom';
 | 
			
		||||
import { IsDirectRoomProvider, RoomProvider } from '../../../hooks/useRoom';
 | 
			
		||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
 | 
			
		||||
import { JoinBeforeNavigate } from '../../../features/join-before-navigate';
 | 
			
		||||
import { useSpace } from '../../../hooks/useSpace';
 | 
			
		||||
import { getAllParents } from '../../../utils/room';
 | 
			
		||||
import { getAllParents, getSpaceChildren } from '../../../utils/room';
 | 
			
		||||
import { roomToParentsAtom } from '../../../state/room/roomToParents';
 | 
			
		||||
import { allRoomsAtom } from '../../../state/room-list/roomList';
 | 
			
		||||
import { useSearchParamsViaServers } from '../../../hooks/router/useSearchParamsViaServers';
 | 
			
		||||
import { mDirectAtom } from '../../../state/mDirectList';
 | 
			
		||||
import { settingsAtom } from '../../../state/settings';
 | 
			
		||||
import { useSetting } from '../../../state/hooks/settings';
 | 
			
		||||
 | 
			
		||||
export function SpaceRouteRoomProvider({ children }: { children: ReactNode }) {
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const space = useSpace();
 | 
			
		||||
  const roomToParents = useAtomValue(roomToParentsAtom);
 | 
			
		||||
  const [developerTools] = useSetting(settingsAtom, 'developerTools');
 | 
			
		||||
  const [roomToParents, setRoomToParents] = useAtom(roomToParentsAtom);
 | 
			
		||||
  const mDirects = useAtomValue(mDirectAtom);
 | 
			
		||||
  const allRooms = useAtomValue(allRoomsAtom);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -24,12 +27,36 @@ export function SpaceRouteRoomProvider({ children }: { children: ReactNode }) {
 | 
			
		|||
  const roomId = useSelectedRoom();
 | 
			
		||||
  const room = mx.getRoom(roomId);
 | 
			
		||||
 | 
			
		||||
  if (
 | 
			
		||||
    !room ||
 | 
			
		||||
    room.isSpaceRoom() ||
 | 
			
		||||
    !allRooms.includes(room.roomId) ||
 | 
			
		||||
    !getAllParents(roomToParents, room.roomId).has(space.roomId)
 | 
			
		||||
  ) {
 | 
			
		||||
  if (!room || !allRooms.includes(room.roomId)) {
 | 
			
		||||
    // room is not joined
 | 
			
		||||
    return (
 | 
			
		||||
      <JoinBeforeNavigate
 | 
			
		||||
        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 (
 | 
			
		||||
      <JoinBeforeNavigate
 | 
			
		||||
        roomIdOrAlias={roomIdOrAlias!}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -75,6 +75,7 @@ import {
 | 
			
		|||
  useRoomsNotificationPreferencesContext,
 | 
			
		||||
} from '../../../hooks/useRoomsNotificationPreferences';
 | 
			
		||||
import { useOpenSpaceSettings } from '../../../state/hooks/spaceSettings';
 | 
			
		||||
import { useRoomNavigate } from '../../../hooks/useRoomNavigate';
 | 
			
		||||
 | 
			
		||||
type SpaceMenuProps = {
 | 
			
		||||
  room: Room;
 | 
			
		||||
| 
						 | 
				
			
			@ -83,11 +84,13 @@ type SpaceMenuProps = {
 | 
			
		|||
const SpaceMenu = forwardRef<HTMLDivElement, SpaceMenuProps>(({ room, requestClose }, ref) => {
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const [hideActivity] = useSetting(settingsAtom, 'hideActivity');
 | 
			
		||||
  const [developerTools] = useSetting(settingsAtom, 'developerTools');
 | 
			
		||||
  const roomToParents = useAtomValue(roomToParentsAtom);
 | 
			
		||||
  const powerLevels = usePowerLevels(room);
 | 
			
		||||
  const { getPowerLevel, canDoAction } = usePowerLevelsAPI(powerLevels);
 | 
			
		||||
  const canInvite = canDoAction('invite', getPowerLevel(mx.getUserId() ?? ''));
 | 
			
		||||
  const openSpaceSettings = useOpenSpaceSettings();
 | 
			
		||||
  const { navigateRoom } = useRoomNavigate();
 | 
			
		||||
 | 
			
		||||
  const allChild = useSpaceChildren(
 | 
			
		||||
    allRoomsAtom,
 | 
			
		||||
| 
						 | 
				
			
			@ -118,6 +121,11 @@ const SpaceMenu = forwardRef<HTMLDivElement, SpaceMenuProps>(({ room, requestClo
 | 
			
		|||
    requestClose();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleOpenTimeline = () => {
 | 
			
		||||
    navigateRoom(room.roomId);
 | 
			
		||||
    requestClose();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Menu ref={ref} style={{ maxWidth: toRem(160), width: '100vw' }}>
 | 
			
		||||
      <Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
 | 
			
		||||
| 
						 | 
				
			
			@ -168,6 +176,18 @@ const SpaceMenu = forwardRef<HTMLDivElement, SpaceMenuProps>(({ room, requestClo
 | 
			
		|||
            Space Settings
 | 
			
		||||
          </Text>
 | 
			
		||||
        </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>
 | 
			
		||||
      <Line variant="Surface" size="300" />
 | 
			
		||||
      <Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,8 @@ import {
 | 
			
		|||
 | 
			
		||||
const NAV_TO_ACTIVE_PATH = 'navToActivePath';
 | 
			
		||||
 | 
			
		||||
const getStoreKey = (userId: string): string => `${NAV_TO_ACTIVE_PATH}${userId}`;
 | 
			
		||||
 | 
			
		||||
type NavToActivePath = Map<string, Path>;
 | 
			
		||||
 | 
			
		||||
type NavToActivePathAction =
 | 
			
		||||
| 
						 | 
				
			
			@ -25,7 +27,7 @@ type NavToActivePathAction =
 | 
			
		|||
export type NavToActivePathAtom = WritableAtom<NavToActivePath, [NavToActivePathAction], undefined>;
 | 
			
		||||
 | 
			
		||||
export const makeNavToActivePathAtom = (userId: string): NavToActivePathAtom => {
 | 
			
		||||
  const storeKey = `${NAV_TO_ACTIVE_PATH}${userId}`;
 | 
			
		||||
  const storeKey = getStoreKey(userId);
 | 
			
		||||
 | 
			
		||||
  const baseNavToActivePathAtom = atomWithLocalStorage<NavToActivePath>(
 | 
			
		||||
    storeKey,
 | 
			
		||||
| 
						 | 
				
			
			@ -64,3 +66,7 @@ export const makeNavToActivePathAtom = (userId: string): 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 { cryptoCallbacks } from './state/secretStorageKeys';
 | 
			
		||||
import { clearNavToActivePathStore } from '../app/state/navToActivePath';
 | 
			
		||||
 | 
			
		||||
type Session = {
 | 
			
		||||
  baseUrl: string;
 | 
			
		||||
| 
						 | 
				
			
			@ -46,6 +47,7 @@ export const startClient = async (mx: MatrixClient) => {
 | 
			
		|||
 | 
			
		||||
export const clearCacheAndReload = async (mx: MatrixClient) => {
 | 
			
		||||
  mx.stopClient();
 | 
			
		||||
  clearNavToActivePathStore(mx.getSafeUserId());
 | 
			
		||||
  await mx.store.deleteAllData();
 | 
			
		||||
  window.location.reload();
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue