Skip to content

Commit

Permalink
chore: Do not load unnecessary CachedCollection data for embedded lay…
Browse files Browse the repository at this point in the history
…out (#34138)
  • Loading branch information
gabriellsh authored Dec 19, 2024
1 parent 48b4cfe commit 224cc68
Show file tree
Hide file tree
Showing 9 changed files with 224 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ class CachedChatSubscription extends CachedCollection<SubscriptionWithRoom, ISub
};
}

async upsertSubscription(record: ISubscription): Promise<void> {
return this.handleRecordEvent('changed', record);
}

protected deserializeFromCache(record: unknown) {
const deserialized = super.deserializeFromCache(record);

Expand Down
5 changes: 2 additions & 3 deletions apps/meteor/app/ui-utils/client/lib/LegacyRoomManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { roomCoordinator } from '../../../../client/lib/rooms/roomCoordinator';
import { fireGlobalEvent } from '../../../../client/lib/utils/fireGlobalEvent';
import { getConfig } from '../../../../client/lib/utils/getConfig';
import { callbacks } from '../../../../lib/callbacks';
import { CachedChatRoom, Messages, Subscriptions, CachedChatSubscription } from '../../../models/client';
import { Messages, Subscriptions, CachedChatSubscription } from '../../../models/client';
import { sdk } from '../../../utils/client/lib/SDKClient';

const maxRoomsOpen = parseInt(getConfig('maxRoomsOpen') ?? '5') || 5;
Expand Down Expand Up @@ -79,8 +79,7 @@ function getOpenedRoomByRid(rid: IRoom['_id']) {
}

const computation = Tracker.autorun(() => {
const ready = CachedChatRoom.ready.get() && mainReady.get();
if (ready !== true) {
if (!mainReady.get()) {
return;
}
Tracker.nonreactive(() =>
Expand Down
68 changes: 37 additions & 31 deletions apps/meteor/client/lib/cachedCollections/CachedCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,23 +69,6 @@ export class CachedCollection<T extends { _id: string }, U = T> {
: () => undefined;

CachedCollectionManager.register(this);

if (!userRelated) {
void this.init();
return;
}

if (process.env.NODE_ENV === 'test') {
return;
}

onLoggedIn(() => {
void this.init();
});

Accounts.onLogout(() => {
this.ready.set(false);
});
}

protected get eventName(): `${Name}-changed` | `${string}/${Name}-changed` {
Expand Down Expand Up @@ -239,23 +222,27 @@ export class CachedCollection<T extends { _id: string }, U = T> {
async setupListener() {
sdk.stream(this.eventType, [this.eventName], (async (action: 'removed' | 'changed', record: any) => {
this.log('record received', action, record);
const newRecord = this.handleReceived(record, action);
await this.handleRecordEvent(action, record);
}) as (...args: unknown[]) => void);
}

if (!hasId(newRecord)) {
return;
}
protected async handleRecordEvent(action: 'removed' | 'changed', record: any) {
const newRecord = this.handleReceived(record, action);

if (action === 'removed') {
this.collection.remove(newRecord._id);
} else {
const { _id } = newRecord;
if (!_id) {
return;
}
this.collection.upsert({ _id } as any, newRecord);
if (!hasId(newRecord)) {
return;
}

if (action === 'removed') {
this.collection.remove(newRecord._id);
} else {
const { _id } = newRecord;
if (!_id) {
return;
}
await this.save();
}) as (...args: unknown[]) => void);
this.collection.upsert({ _id } as any, newRecord);
}
await this.save();
}

trySync(delay = 10) {
Expand Down Expand Up @@ -368,4 +355,23 @@ export class CachedCollection<T extends { _id: string }, U = T> {
}

private reconnectionComputation: Tracker.Computation | undefined;

listen() {
if (!this.userRelated) {
void this.init();
return;
}

if (process.env.NODE_ENV === 'test') {
return;
}

onLoggedIn(() => {
void this.init();
});

Accounts.onLogout(() => {
this.ready.set(false);
});
}
}
6 changes: 5 additions & 1 deletion apps/meteor/client/providers/AuthorizationProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { ReactNode } from 'react';
import React, { useCallback, useEffect } from 'react';

import { hasPermission, hasAtLeastOnePermission, hasAllPermission, hasRole } from '../../app/authorization/client';
import { Roles } from '../../app/models/client/models/Roles';
import { Roles, AuthzCachedCollection } from '../../app/models/client';
import { useReactiveValue } from '../hooks/useReactiveValue';
import { createReactiveSubscriptionFactory } from '../lib/createReactiveSubscriptionFactory';

Expand Down Expand Up @@ -48,6 +48,10 @@ const AuthorizationProvider = ({ children }: AuthorizationProviderProps) => {
),
);

useEffect(() => {
AuthzCachedCollection.listen();
}, []);

useEffect(() => {
contextValue.roleStore.roles = roles;
contextValue.roleStore.emit('change', roles);
Expand Down
112 changes: 112 additions & 0 deletions apps/meteor/client/views/room/RoomOpenerEmbedded.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import type { ISubscription, RoomType } from '@rocket.chat/core-typings';
import { Box, States, StatesIcon, StatesSubtitle, StatesTitle } from '@rocket.chat/fuselage';
import { FeaturePreviewOff, FeaturePreviewOn } from '@rocket.chat/ui-client';
import { useEndpoint } from '@rocket.chat/ui-contexts';
import { useQuery } from '@tanstack/react-query';
import type { ReactElement } from 'react';
import React, { lazy, Suspense } from 'react';
import { useTranslation } from 'react-i18next';

import RoomSkeleton from './RoomSkeleton';
import RoomSidepanel from './Sidepanel/RoomSidepanel';
import { useOpenRoom } from './hooks/useOpenRoom';
import { CachedChatSubscription } from '../../../app/models/client';
import { FeaturePreviewSidePanelNavigation } from '../../components/FeaturePreviewSidePanelNavigation';
import { Header } from '../../components/Header';
import { getErrorMessage } from '../../lib/errorHandling';
import { NotAuthorizedError } from '../../lib/errors/NotAuthorizedError';
import { OldUrlRoomError } from '../../lib/errors/OldUrlRoomError';
import { RoomNotFoundError } from '../../lib/errors/RoomNotFoundError';

const RoomProvider = lazy(() => import('./providers/RoomProvider'));
const RoomNotFound = lazy(() => import('./RoomNotFound'));
const Room = lazy(() => import('./Room'));
const RoomLayout = lazy(() => import('./layout/RoomLayout'));
const NotAuthorizedPage = lazy(() => import('../notAuthorized/NotAuthorizedPage'));

type RoomOpenerProps = {
type: RoomType;
reference: string;
};

const isDirectOrOmnichannelRoom = (type: RoomType) => type === 'd' || type === 'l';

const RoomOpenerEmbedded = ({ type, reference }: RoomOpenerProps): ReactElement => {
const { data, error, isSuccess, isError, isLoading } = useOpenRoom({ type, reference });

const getSubscription = useEndpoint('GET', '/v1/subscriptions.getOne');

const rid = data?.rid;
useQuery(
['subscriptions', rid],
() => {
if (!rid) {
throw new Error('Room not found');
}
return getSubscription({ roomId: rid });
},
{
enabled: !!rid,
suspense: true,
onSuccess({ subscription }) {
if (!subscription) {
throw new Error('Room not found');
}
CachedChatSubscription.upsertSubscription(subscription as unknown as ISubscription);
},
},
);

const { t } = useTranslation();

return (
<Box display='flex' w='full' h='full'>
{!isDirectOrOmnichannelRoom(type) && (
<FeaturePreviewSidePanelNavigation>
<FeaturePreviewOff>{null}</FeaturePreviewOff>
<FeaturePreviewOn>
<RoomSidepanel />
</FeaturePreviewOn>
</FeaturePreviewSidePanelNavigation>
)}

<Suspense fallback={<RoomSkeleton />}>
{isLoading && <RoomSkeleton />}
{isSuccess && (
<RoomProvider rid={data.rid}>
<Room />
</RoomProvider>
)}
{isError &&
(() => {
if (error instanceof OldUrlRoomError) {
return <RoomSkeleton />;
}

if (error instanceof RoomNotFoundError) {
return <RoomNotFound />;
}

if (error instanceof NotAuthorizedError) {
return <NotAuthorizedPage />;
}

return (
<RoomLayout
header={<Header />}
body={
<States>
<StatesIcon name='circle-exclamation' variation='danger' />
<StatesTitle>{t('core.Error')}</StatesTitle>
<StatesSubtitle>{getErrorMessage(error)}</StatesSubtitle>
</States>
}
/>
);
})()}
</Suspense>
</Box>
);
};

export default RoomOpenerEmbedded;
8 changes: 8 additions & 0 deletions apps/meteor/client/views/room/RoomRoute.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { useRouter } from '@rocket.chat/ui-contexts';
import React, { useLayoutEffect, useState } from 'react';

import RoomOpener from './RoomOpener';
import RoomOpenerEmbedded from './RoomOpenerEmbedded';
import { useEmbeddedLayout } from '../../hooks/useEmbeddedLayout';

type RoomRouteProps = {
extractOpenRoomParams: (routeParams: Record<string, string | null | undefined>) => {
Expand All @@ -15,6 +17,8 @@ const RoomRoute = ({ extractOpenRoomParams }: RoomRouteProps) => {
const router = useRouter();
const [params, setParams] = useState(() => extractOpenRoomParams(router.getRouteParameters()));

const isEmbeddedLayout = useEmbeddedLayout();

useLayoutEffect(
() =>
router.subscribeToRouteChange(() => {
Expand All @@ -23,6 +27,10 @@ const RoomRoute = ({ extractOpenRoomParams }: RoomRouteProps) => {
[extractOpenRoomParams, router],
);

if (isEmbeddedLayout) {
return <RoomOpenerEmbedded {...params} />;
}

return <RoomOpener {...params} />;
};

Expand Down
36 changes: 36 additions & 0 deletions apps/meteor/client/views/root/MainLayout/EmbeddedPreload.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useUserId } from '@rocket.chat/ui-contexts';
import type { ReactElement, ReactNode } from 'react';
import React, { useEffect } from 'react';

import { CachedChatRoom, CachedChatSubscription } from '../../../../app/models/client';
import { settings } from '../../../../app/settings/client';
import { mainReady } from '../../../../app/ui-utils/client';
import { useReactiveVar } from '../../../hooks/useReactiveVar';
import { isSyncReady } from '../../../lib/userData';
import PageLoading from '../PageLoading';

const EmbeddedPreload = ({ children }: { children: ReactNode }): ReactElement => {
const uid = useUserId();
const subscriptionsReady = useReactiveVar(CachedChatSubscription.ready);
const settingsReady = useReactiveVar(settings.cachedCollection.ready);
const userDataReady = useReactiveVar(isSyncReady);

const ready = !uid || (userDataReady && subscriptionsReady && settingsReady);

useEffect(() => {
mainReady.set(ready);
}, [ready]);

useEffect(() => {
CachedChatSubscription.ready.set(true);
CachedChatRoom.ready.set(true);
}, [ready]);

if (!ready) {
return <PageLoading />;
}

return <>{children}</>;
};

export default EmbeddedPreload;
14 changes: 14 additions & 0 deletions apps/meteor/client/views/root/MainLayout/MainLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import type { ReactElement, ReactNode } from 'react';
import React, { Suspense } from 'react';

import AuthenticationCheck from './AuthenticationCheck';
import EmbeddedPreload from './EmbeddedPreload';
import Preload from './Preload';
import { useCustomScript } from './useCustomScript';
import { useEmbeddedLayout } from '../../../hooks/useEmbeddedLayout';

type MainLayoutProps = {
children?: ReactNode;
Expand All @@ -12,6 +14,18 @@ type MainLayoutProps = {
const MainLayout = ({ children = null }: MainLayoutProps): ReactElement => {
useCustomScript();

const isEmbeddedLayout = useEmbeddedLayout();

if (isEmbeddedLayout) {
return (
<EmbeddedPreload>
<AuthenticationCheck>
<Suspense fallback={null}>{children}</Suspense>
</AuthenticationCheck>
</EmbeddedPreload>
);
}

return (
<Preload>
<AuthenticationCheck>
Expand Down
7 changes: 6 additions & 1 deletion apps/meteor/client/views/root/MainLayout/Preload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useUserId } from '@rocket.chat/ui-contexts';
import type { ReactElement, ReactNode } from 'react';
import React, { useEffect } from 'react';

import { CachedChatSubscription } from '../../../../app/models/client';
import { CachedChatRoom, CachedChatSubscription } from '../../../../app/models/client';
import { settings } from '../../../../app/settings/client';
import { mainReady } from '../../../../app/ui-utils/client';
import { useReactiveVar } from '../../../hooks/useReactiveVar';
Expand All @@ -21,6 +21,11 @@ const Preload = ({ children }: { children: ReactNode }): ReactElement => {
mainReady.set(ready);
}, [ready]);

useEffect(() => {
CachedChatSubscription.listen();
CachedChatRoom.listen();
}, []);

if (!ready) {
return <PageLoading />;
}
Expand Down

0 comments on commit 224cc68

Please sign in to comment.