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
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:
15
apps/meteor/client/views/room/Header/icons/Encrypted.tsx
Normal file
15
apps/meteor/client/views/room/Header/icons/Encrypted.tsx
Normal 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);
|
||||
43
apps/meteor/client/views/room/Header/icons/Favorite.tsx
Normal file
43
apps/meteor/client/views/room/Header/icons/Favorite.tsx
Normal 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);
|
||||
@@ -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();
|
||||
});
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
20
apps/meteor/client/views/room/Header/icons/Translate.tsx
Normal file
20
apps/meteor/client/views/room/Header/icons/Translate.tsx
Normal 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);
|
||||
Reference in New Issue
Block a user