snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-16 01:21:02 +05:00
commit 30810eecd7
10161 changed files with 987110 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
import type { IRoom } from '@rocket.chat/core-typings';
import { HeaderState } from '@rocket.chat/ui-client';
import { useSetting } from '@rocket.chat/ui-contexts';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
export type EncryptedProps = { room: IRoom };
const Encrypted = ({ room }: EncryptedProps) => {
const { t } = useTranslation();
const e2eEnabled = useSetting('E2E_Enable');
return e2eEnabled && room?.encrypted ? <HeaderState title={t('Encrypted')} icon='key' color='status-font-on-success' /> : null;
};
export default memo(Encrypted);

View File

@@ -0,0 +1,43 @@
import type { IRoom, ISubscription } from '@rocket.chat/core-typings';
import { IconButton } from '@rocket.chat/fuselage';
import { useStableCallback } from '@rocket.chat/fuselage-hooks';
import { useSetting, useTranslation } from '@rocket.chat/ui-contexts';
import { memo } from 'react';
import { useToggleFavoriteMutation } from '../../hooks/useToggleFavoriteMutation';
export type FavoriteProps = { room: IRoom & { f?: ISubscription['f'] } };
const Favorite = ({ room: { _id, f: favorite = false, t: type, name } }: FavoriteProps) => {
const t = useTranslation();
const isFavoritesEnabled = useSetting('Favorite_Rooms', true) && ['c', 'p', 'd', 't'].includes(type);
const { mutate: toggleFavorite } = useToggleFavoriteMutation();
const handleFavoriteClick = useStableCallback(() => {
if (!isFavoritesEnabled) {
return;
}
toggleFavorite({ roomId: _id, favorite: !favorite, roomName: name || '' });
});
const favoriteLabel = favorite ? `${t('Unfavorite')} ${name}` : `${t('Favorite')} ${name}`;
if (!isFavoritesEnabled) {
return null;
}
return (
<IconButton
small
marginInlineEnd={4}
icon={favorite ? 'star-filled' : 'star'}
title={favoriteLabel}
color={favorite ? 'status-font-on-warning' : undefined}
onClick={handleFavoriteClick}
/>
);
};
export default memo(Favorite);

View File

@@ -0,0 +1,57 @@
import type { IRoom } from '@rocket.chat/core-typings';
import { mockAppRoot } from '@rocket.chat/mock-providers';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import RoomGroupingMenu from './RoomGroupingMenu';
import { useHasLicenseModule } from '../../../../hooks/useHasLicenseModule';
import { useCategoryModals } from '../../../../sidebar/categories/hooks/useCategoryModals';
import { useMoveRoomCategory } from '../../../../sidebar/categories/hooks/useMoveRoomCategory';
import { useUserIsSubscribed } from '../../contexts/RoomContext';
import { useToggleFavoriteMutation } from '../../hooks/useToggleFavoriteMutation';
jest.mock('../../../../hooks/useHasLicenseModule', () => ({ useHasLicenseModule: jest.fn() }));
jest.mock('../../../../sidebar/categories/hooks/useMoveRoomCategory', () => ({ useMoveRoomCategory: jest.fn() }));
jest.mock('../../../../sidebar/categories/hooks/useCategoryModals', () => ({ useCategoryModals: jest.fn() }));
jest.mock('../../contexts/RoomContext', () => ({ useUserIsSubscribed: jest.fn() }));
jest.mock('../../hooks/useToggleFavoriteMutation', () => ({ useToggleFavoriteMutation: jest.fn() }));
const mockedUseCategoryModals = jest.mocked(useCategoryModals);
const mockedUseMoveRoomCategory = jest.mocked(useMoveRoomCategory);
const mockedUseHasLicenseModule = jest.mocked(useHasLicenseModule);
const mockedUseUserIsSubscribed = jest.mocked(useUserIsSubscribed);
const mockedUseToggleFavoriteMutation = jest.mocked(useToggleFavoriteMutation);
const ROOM_ID = 'test-room-id';
const catDesign = { _id: 'cat-design', name: 'Design', showUnreads: false };
const catOther = { _id: 'cat-other', name: 'Engineering', showUnreads: false };
const makeRoom = (overrides: Partial<IRoom & { f?: boolean; category?: string }> = {}): IRoom & { f?: boolean; category?: string } =>
({ _id: ROOM_ID, name: 'General', t: 'c', ...overrides }) as any;
const wrapper = mockAppRoot().withSetting('Favorite_Rooms', true).withUserPreference('sidebarCategories', [catDesign, catOther]).build();
beforeEach(() => {
mockedUseUserIsSubscribed.mockReturnValue(true);
mockedUseToggleFavoriteMutation.mockReturnValue({ mutate: jest.fn() } as any);
mockedUseCategoryModals.mockReturnValue({ openCreate: jest.fn(), openManage: jest.fn(), openDelete: jest.fn() });
mockedUseMoveRoomCategory.mockReturnValue({ mutate: jest.fn(), mutateAsync: jest.fn() } as any);
mockedUseHasLicenseModule.mockReturnValue({ data: true } as any);
});
it('shows Favorites in the grouping menu when the room is favorited', async () => {
render(<RoomGroupingMenu room={makeRoom({ f: true })} />, { wrapper });
await userEvent.click(screen.getByRole('button'));
expect(await screen.findByRole('menuitem', { name: 'Favorites' })).toBeInTheDocument();
});
it('shows the matching category in the grouping menu when the room has a category subscription field', async () => {
render(<RoomGroupingMenu room={makeRoom({ f: false, category: 'cat-design' })} />, { wrapper });
await userEvent.click(screen.getByRole('button'));
expect(await screen.findByRole('menuitem', { name: 'Design' })).toBeInTheDocument();
});

View File

@@ -0,0 +1,24 @@
import { isOmnichannelRoom, type IRoom, type ISubscription } from '@rocket.chat/core-typings';
import { memo } from 'react';
import Favorite from './Favorite';
import RoomHeaderCategoryMenu from './RoomHeaderCategoryMenu';
import { useHasLicenseModule } from '../../../../hooks/useHasLicenseModule';
import { useUserIsSubscribed } from '../../contexts/RoomContext';
const RoomGroupingMenu = ({ room }: { room: IRoom & { f?: ISubscription['f']; category?: ISubscription['category'] } }) => {
const subscribed = useUserIsSubscribed();
const { data: hasLicenseModule = false } = useHasLicenseModule('experimental-enterprise-features');
if (!subscribed) {
return null;
}
if (hasLicenseModule && !isOmnichannelRoom(room)) {
return <RoomHeaderCategoryMenu room={room} />;
}
return <Favorite room={room} />;
};
export default memo(RoomGroupingMenu);

View File

@@ -0,0 +1,51 @@
import type { IRoom, ISubscription } from '@rocket.chat/core-typings';
import { IconButton } from '@rocket.chat/fuselage';
import { GenericMenu } from '@rocket.chat/ui-client';
import { useSetting } from '@rocket.chat/ui-contexts';
import { useTranslation } from 'react-i18next';
import { useCategoryMenuItems } from '../../../../sidebar/categories/hooks/useCategoryMenuItems';
const getGroupingIcon = (favorite: boolean, category: boolean, isFavoritesEnabled: boolean): 'star-filled' | 'folder' | 'star' => {
if (favorite) {
return 'star-filled';
}
if (category) {
return 'folder';
}
return isFavoritesEnabled ? 'star' : 'folder';
};
type RoomHeaderCategoryMenuProps = {
room: IRoom & { f?: ISubscription['f']; category?: ISubscription['category'] };
};
const RoomHeaderCategoryMenu = ({ room }: RoomHeaderCategoryMenuProps) => {
const { t } = useTranslation();
const isFavoritesEnabled = useSetting('Favorite_Rooms', true);
const favorite = Boolean(room.f);
const category = Boolean(room.category);
const groupingIcon = getGroupingIcon(favorite, category, isFavoritesEnabled);
const { targetItems, utilItems } = useCategoryMenuItems({
rid: room._id,
name: room.name,
isFavorite: favorite,
categoryId: room.category,
});
const sections = [{ items: targetItems }, ...(utilItems.length ? [{ items: utilItems }] : [])];
return (
<GenericMenu
button={<IconButton small color={favorite ? 'status-font-on-warning' : undefined} icon={groupingIcon} marginInlineEnd={4} />}
title={t('Move_to')}
icon={groupingIcon}
sections={sections}
/>
);
};
export default RoomHeaderCategoryMenu;

View File

@@ -0,0 +1,20 @@
import type { IRoom } from '@rocket.chat/core-typings';
import { HeaderState } from '@rocket.chat/ui-client';
import { useSetting } from '@rocket.chat/ui-contexts';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
export type TranslateProps = {
room: IRoom;
};
const Translate = ({ room: { autoTranslateLanguage, autoTranslate } }: TranslateProps) => {
const { t } = useTranslation();
const autoTranslateEnabled = useSetting('AutoTranslate_Enabled');
const encryptedLabel = t('Translated');
return autoTranslateEnabled && autoTranslate && autoTranslateLanguage ? (
<HeaderState title={encryptedLabel} icon='language' color='info' />
) : null;
};
export default memo(Translate);