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:
227
apps/meteor/client/lib/rooms/roomCoordinator.tsx
Normal file
227
apps/meteor/client/lib/rooms/roomCoordinator.tsx
Normal file
@@ -0,0 +1,227 @@
|
||||
import type { IRoom, RoomType, IUser, AtLeast, ValueOf, ISubscription } from '@rocket.chat/core-typings';
|
||||
import type { RouteName } from '@rocket.chat/ui-contexts';
|
||||
|
||||
import type {
|
||||
RoomSettingsEnum,
|
||||
RoomMemberActions,
|
||||
UiTextContext,
|
||||
IRoomTypeClientDirectives,
|
||||
RoomIdentification,
|
||||
IRoomTypeRouteConfig,
|
||||
IRoomTypeClientConfig,
|
||||
} from '../../../definition/IRoomTypeConfig';
|
||||
import { RoomCoordinator } from '../../../lib/rooms/coordinator';
|
||||
import { router } from '../../providers/RouterProvider';
|
||||
import { Subscriptions } from '../../stores';
|
||||
import RoomRoute from '../../views/room/RoomRoute';
|
||||
import MainLayout from '../../views/root/MainLayout';
|
||||
import { absoluteUrl } from '../absoluteUrl';
|
||||
import { appLayout } from '../appLayout';
|
||||
import { hasPermission } from '../authorization';
|
||||
|
||||
class RoomCoordinatorClient extends RoomCoordinator {
|
||||
public add(roomConfig: IRoomTypeClientConfig, directives: Partial<IRoomTypeClientDirectives>): void {
|
||||
this.addRoomType(roomConfig, {
|
||||
allowRoomSettingChange(_room: Partial<IRoom>, _setting: ValueOf<typeof RoomSettingsEnum>): boolean {
|
||||
return true;
|
||||
},
|
||||
allowMemberAction(
|
||||
_room: Partial<IRoom>,
|
||||
_action: ValueOf<typeof RoomMemberActions>,
|
||||
_showingUserId: IUser['_id'],
|
||||
_userSubscription?: ISubscription,
|
||||
): boolean {
|
||||
return false;
|
||||
},
|
||||
roomName(_room: AtLeast<IRoom, '_id' | 'name' | 'fname' | 'prid'>): string {
|
||||
return '';
|
||||
},
|
||||
isGroupChat(_room: Partial<IRoom>): boolean {
|
||||
return false;
|
||||
},
|
||||
getUiText(_context: ValueOf<typeof UiTextContext>): string {
|
||||
return '';
|
||||
},
|
||||
getAvatarPath(_room): string {
|
||||
return '';
|
||||
},
|
||||
findRoom(_identifier: string): IRoom | undefined {
|
||||
return undefined;
|
||||
},
|
||||
isLivechatRoom(): boolean {
|
||||
return false;
|
||||
},
|
||||
canSendMessage(room: IRoom): boolean {
|
||||
return Subscriptions.state.count((record) => record.rid === room._id) > 0;
|
||||
},
|
||||
...directives,
|
||||
config: roomConfig,
|
||||
});
|
||||
}
|
||||
|
||||
public getRoomDirectives(roomType: string): IRoomTypeClientDirectives {
|
||||
return this.roomTypes[roomType].directives as IRoomTypeClientDirectives;
|
||||
}
|
||||
|
||||
public openRouteLink(
|
||||
roomType: RoomType,
|
||||
subData: RoomIdentification,
|
||||
queryParams?: Record<string, string>,
|
||||
options: { replace?: boolean; routeParamsOverrides?: Record<string, string> } = {},
|
||||
): void {
|
||||
const config = this.getRoomTypeConfig(roomType);
|
||||
if (!config?.route) {
|
||||
return;
|
||||
}
|
||||
|
||||
let _routeData = {};
|
||||
if (config.route.link) {
|
||||
_routeData = config.route.link(subData);
|
||||
} else if (subData?.name) {
|
||||
_routeData = {
|
||||
name: subData.name,
|
||||
};
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
router.navigate(
|
||||
{
|
||||
pattern: config.route.path ?? '/home',
|
||||
params: { ..._routeData, ...options.routeParamsOverrides },
|
||||
search: queryParams,
|
||||
},
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
public isLivechatRoom(roomType: string): boolean {
|
||||
return Boolean(this.getRoomDirectives(roomType).isLivechatRoom());
|
||||
}
|
||||
|
||||
public getRoomName(roomType: string, roomData: AtLeast<IRoom, '_id' | 'name' | 'fname' | 'prid'>): string {
|
||||
return this.getRoomDirectives(roomType).roomName(roomData) ?? '';
|
||||
}
|
||||
|
||||
readOnly(room?: IRoom, user?: AtLeast<IUser, 'username'> | null): boolean {
|
||||
if (!room) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const directives = this.getRoomDirectives(room.t);
|
||||
if (directives?.readOnly) {
|
||||
return directives.readOnly(room, user);
|
||||
}
|
||||
|
||||
if (!user?.username) {
|
||||
return Boolean(room.ro);
|
||||
}
|
||||
|
||||
if (!room) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Array.isArray(room.muted) && room.muted.indexOf(user.username) !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (room.ro) {
|
||||
if (Array.isArray(room.unmuted) && room.unmuted.indexOf(user.username) !== -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasPermission('post-readonly', room._id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private validateRoute<TRouteName extends RouteName>(route: IRoomTypeRouteConfig<TRouteName>): void {
|
||||
const { name, path, link } = route;
|
||||
|
||||
if (typeof name !== 'string' || name.length === 0) {
|
||||
throw new Error('The route name must be a string.');
|
||||
}
|
||||
|
||||
if (path !== undefined && (typeof path !== 'string' || path.length === 0)) {
|
||||
throw new Error('The route path must be a string.');
|
||||
}
|
||||
|
||||
if (!['undefined', 'function'].includes(typeof link)) {
|
||||
throw new Error('The route link must be a function.');
|
||||
}
|
||||
}
|
||||
|
||||
protected override validateRoomConfig(roomConfig: IRoomTypeClientConfig): void {
|
||||
super.validateRoomConfig(roomConfig);
|
||||
|
||||
const { route, label } = roomConfig;
|
||||
|
||||
if (route !== undefined) {
|
||||
this.validateRoute(route);
|
||||
}
|
||||
|
||||
if (label !== undefined && (typeof label !== 'string' || label.length === 0)) {
|
||||
throw new Error('The label must be a string.');
|
||||
}
|
||||
}
|
||||
|
||||
protected override addRoomType(roomConfig: IRoomTypeClientConfig, directives: IRoomTypeClientDirectives): void {
|
||||
super.addRoomType(roomConfig, directives);
|
||||
|
||||
if (roomConfig.route?.path && roomConfig.route.name && directives.extractOpenRoomParams) {
|
||||
const {
|
||||
route: { name, path },
|
||||
} = roomConfig;
|
||||
const { extractOpenRoomParams } = directives;
|
||||
router.defineRoutes([
|
||||
{
|
||||
path,
|
||||
id: name,
|
||||
element: appLayout.wrap(
|
||||
<MainLayout>
|
||||
<RoomRoute key={name} extractOpenRoomParams={extractOpenRoomParams} />
|
||||
</MainLayout>,
|
||||
),
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public getURL(roomType: string, subData: RoomIdentification): string | false {
|
||||
const config = this.getRoomTypeConfig(roomType);
|
||||
if (!config?.route) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const routeData = this.getRouteData(roomType, subData);
|
||||
if (!routeData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return absoluteUrl(
|
||||
router.buildRoutePath({
|
||||
name: config.route.name,
|
||||
params: routeData,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
public isRouteNameKnown(routeName: string): boolean {
|
||||
return Boolean(this.getRouteNameIdentifier(routeName));
|
||||
}
|
||||
|
||||
public getRouteNameIdentifier(routeName: string): string | undefined {
|
||||
if (!routeName) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Object.keys(this.roomTypes).find((key) => this.roomTypes[key].config.route?.name === routeName);
|
||||
}
|
||||
}
|
||||
|
||||
export const roomCoordinator = new RoomCoordinatorClient();
|
||||
12
apps/meteor/client/lib/rooms/roomTypes/conversation.ts
Normal file
12
apps/meteor/client/lib/rooms/roomTypes/conversation.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { getConversationRoomType } from '../../../../lib/rooms/roomTypes/conversation';
|
||||
import { roomCoordinator } from '../roomCoordinator';
|
||||
|
||||
export const ConversationRoomType = getConversationRoomType(roomCoordinator);
|
||||
|
||||
roomCoordinator.add(
|
||||
{
|
||||
...ConversationRoomType,
|
||||
label: 'Conversations',
|
||||
},
|
||||
{},
|
||||
);
|
||||
149
apps/meteor/client/lib/rooms/roomTypes/direct.ts
Normal file
149
apps/meteor/client/lib/rooms/roomTypes/direct.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import type { AtLeast } from '@rocket.chat/core-typings';
|
||||
import { isRoomFederated } from '@rocket.chat/core-typings';
|
||||
import type { SubscriptionWithRoom } from '@rocket.chat/ui-contexts';
|
||||
|
||||
import type { IRoomTypeClientDirectives } from '../../../../definition/IRoomTypeConfig';
|
||||
import { RoomSettingsEnum, RoomMemberActions, UiTextContext } from '../../../../definition/IRoomTypeConfig';
|
||||
import { getDirectMessageRoomType } from '../../../../lib/rooms/roomTypes/direct';
|
||||
import { Users, Rooms, Subscriptions } from '../../../stores';
|
||||
import * as Federation from '../../federation/Federation';
|
||||
import { getAvatarURL } from '../../getAvatarURL';
|
||||
import { getUserAvatarURL } from '../../getUserAvatarURL';
|
||||
import { settings } from '../../settings';
|
||||
import { roomCoordinator } from '../roomCoordinator';
|
||||
|
||||
export const DirectMessageRoomType = getDirectMessageRoomType(roomCoordinator);
|
||||
|
||||
roomCoordinator.add(
|
||||
{
|
||||
...DirectMessageRoomType,
|
||||
label: 'Direct_Messages',
|
||||
},
|
||||
{
|
||||
allowRoomSettingChange(_room, setting) {
|
||||
if (isRoomFederated(_room)) {
|
||||
return Federation.isRoomSettingAllowed(_room, setting);
|
||||
}
|
||||
switch (setting) {
|
||||
case RoomSettingsEnum.TYPE:
|
||||
case RoomSettingsEnum.NAME:
|
||||
case RoomSettingsEnum.SYSTEM_MESSAGES:
|
||||
case RoomSettingsEnum.DESCRIPTION:
|
||||
case RoomSettingsEnum.READ_ONLY:
|
||||
case RoomSettingsEnum.REACT_WHEN_READ_ONLY:
|
||||
case RoomSettingsEnum.ARCHIVE_OR_UNARCHIVE:
|
||||
case RoomSettingsEnum.JOIN_CODE:
|
||||
return false;
|
||||
case RoomSettingsEnum.E2E:
|
||||
return settings.peek('E2E_Enable') === true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
allowMemberAction(room, action, showingUserId, userSubscription) {
|
||||
if (isRoomFederated(room)) {
|
||||
return Federation.actionAllowed(room, action, showingUserId, userSubscription);
|
||||
}
|
||||
switch (action) {
|
||||
case RoomMemberActions.BLOCK:
|
||||
return !this.isGroupChat(room);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
roomName(roomData) {
|
||||
const subscription = ((): { fname?: string; name?: string } | undefined => {
|
||||
if (roomData.fname || roomData.name) {
|
||||
return {
|
||||
fname: roomData.fname,
|
||||
name: roomData.name,
|
||||
};
|
||||
}
|
||||
|
||||
if (!roomData._id) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return Subscriptions.state.find((record) => record.rid === roomData._id);
|
||||
})();
|
||||
|
||||
if (!subscription) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (settings.peek('UI_Use_Real_Name') && subscription.fname) {
|
||||
return subscription.fname;
|
||||
}
|
||||
|
||||
return subscription.name;
|
||||
},
|
||||
|
||||
isGroupChat(room) {
|
||||
return (room?.uids?.length || 0) > 2;
|
||||
},
|
||||
|
||||
getUiText(context) {
|
||||
switch (context) {
|
||||
case UiTextContext.HIDE_WARNING:
|
||||
return 'Hide_Private_Warning';
|
||||
case UiTextContext.LEAVE_WARNING:
|
||||
return 'Leave_Private_Warning';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
},
|
||||
|
||||
getAvatarPath(room) {
|
||||
if (!room) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// if coming from sidenav search
|
||||
if (room.name && room.avatarETag) {
|
||||
return getUserAvatarURL(room.name, room.avatarETag);
|
||||
}
|
||||
|
||||
if (this.isGroupChat(room)) {
|
||||
return getAvatarURL({
|
||||
username: (room.uids || []).length + (room.usernames || []).join(),
|
||||
cache: room.avatarETag,
|
||||
}) as string;
|
||||
}
|
||||
|
||||
const subscriptionName = Subscriptions.state.find((record) => record.rid === room._id)?.name;
|
||||
if (subscriptionName) {
|
||||
const { username, avatarETag } = Users.state.find((record) => record.username === subscriptionName) || {};
|
||||
return getUserAvatarURL(username || subscriptionName, avatarETag);
|
||||
}
|
||||
|
||||
return getUserAvatarURL(room.name || this.roomName(room) || '');
|
||||
},
|
||||
|
||||
getIcon(room) {
|
||||
if (isRoomFederated(room)) {
|
||||
return 'globe';
|
||||
}
|
||||
|
||||
if (this.isGroupChat(room)) {
|
||||
return 'balloon';
|
||||
}
|
||||
|
||||
return 'at';
|
||||
},
|
||||
|
||||
extractOpenRoomParams({ rid }) {
|
||||
return { type: 'd', reference: rid };
|
||||
},
|
||||
|
||||
findRoom(identifier) {
|
||||
const predicate = (record: SubscriptionWithRoom) => record.t === 'd' && (record.name === identifier || record.rid === identifier);
|
||||
|
||||
const subscription = Subscriptions.state.find(predicate);
|
||||
if (subscription?.rid) {
|
||||
return Rooms.state.get(subscription.rid);
|
||||
}
|
||||
},
|
||||
} as AtLeast<IRoomTypeClientDirectives, 'isGroupChat' | 'roomName'>,
|
||||
);
|
||||
16
apps/meteor/client/lib/rooms/roomTypes/favorite.ts
Normal file
16
apps/meteor/client/lib/rooms/roomTypes/favorite.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { getFavoriteRoomType } from '../../../../lib/rooms/roomTypes/favorite';
|
||||
import { roomCoordinator } from '../roomCoordinator';
|
||||
|
||||
export const FavoriteRoomType = getFavoriteRoomType(roomCoordinator);
|
||||
|
||||
roomCoordinator.add(
|
||||
{
|
||||
...FavoriteRoomType,
|
||||
label: 'Favorites',
|
||||
},
|
||||
{
|
||||
getIcon() {
|
||||
return 'star';
|
||||
},
|
||||
},
|
||||
);
|
||||
7
apps/meteor/client/lib/rooms/roomTypes/index.ts
Normal file
7
apps/meteor/client/lib/rooms/roomTypes/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import './conversation';
|
||||
import './direct';
|
||||
import './favorite';
|
||||
import './livechat';
|
||||
import './private';
|
||||
import './public';
|
||||
import './unread';
|
||||
79
apps/meteor/client/lib/rooms/roomTypes/livechat.ts
Normal file
79
apps/meteor/client/lib/rooms/roomTypes/livechat.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import type { AtLeast, ValueOf } from '@rocket.chat/core-typings';
|
||||
|
||||
import type { IRoomTypeClientDirectives } from '../../../../definition/IRoomTypeConfig';
|
||||
import { RoomSettingsEnum, RoomMemberActions, UiTextContext } from '../../../../definition/IRoomTypeConfig';
|
||||
import { getLivechatRoomType } from '../../../../lib/rooms/roomTypes/livechat';
|
||||
import { Rooms, Subscriptions } from '../../../stores';
|
||||
import { getAvatarURL } from '../../getAvatarURL';
|
||||
import { roomCoordinator } from '../roomCoordinator';
|
||||
|
||||
export const LivechatRoomType = getLivechatRoomType(roomCoordinator);
|
||||
|
||||
roomCoordinator.add(
|
||||
{
|
||||
...LivechatRoomType,
|
||||
label: 'Omnichannel',
|
||||
},
|
||||
{
|
||||
allowRoomSettingChange(_room, setting) {
|
||||
switch (setting) {
|
||||
case RoomSettingsEnum.JOIN_CODE:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
allowMemberAction(_room, action) {
|
||||
return ([RoomMemberActions.INVITE, RoomMemberActions.JOIN] as Array<ValueOf<typeof RoomMemberActions>>).includes(action);
|
||||
},
|
||||
|
||||
roomName(room) {
|
||||
return room.name || room.fname || (room as any).label;
|
||||
},
|
||||
|
||||
getUiText(context) {
|
||||
switch (context) {
|
||||
case UiTextContext.HIDE_WARNING:
|
||||
return 'Hide_Livechat_Warning';
|
||||
case UiTextContext.LEAVE_WARNING:
|
||||
return 'Leave_Livechat_Warning';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
},
|
||||
|
||||
getAvatarPath(room) {
|
||||
return getAvatarURL({ username: `@${this.roomName(room)}` }) || '';
|
||||
},
|
||||
|
||||
findRoom(identifier) {
|
||||
return Rooms.state.get(identifier);
|
||||
},
|
||||
|
||||
isLivechatRoom() {
|
||||
return true;
|
||||
},
|
||||
|
||||
canSendMessage(room) {
|
||||
return Boolean(room?.open);
|
||||
},
|
||||
|
||||
readOnly(room) {
|
||||
if (!room?.open) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const subscription = Subscriptions.state.find((record) => record.rid === room._id);
|
||||
return !subscription;
|
||||
},
|
||||
|
||||
getIcon() {
|
||||
return 'livechat';
|
||||
},
|
||||
|
||||
extractOpenRoomParams({ id }) {
|
||||
return { type: 'l', reference: id };
|
||||
},
|
||||
} as AtLeast<IRoomTypeClientDirectives, 'roomName'>,
|
||||
);
|
||||
117
apps/meteor/client/lib/rooms/roomTypes/private.ts
Normal file
117
apps/meteor/client/lib/rooms/roomTypes/private.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import type { AtLeast, IRoom } from '@rocket.chat/core-typings';
|
||||
import { isRoomFederated } from '@rocket.chat/core-typings';
|
||||
|
||||
import type { IRoomTypeClientDirectives } from '../../../../definition/IRoomTypeConfig';
|
||||
import { RoomSettingsEnum, RoomMemberActions, UiTextContext } from '../../../../definition/IRoomTypeConfig';
|
||||
import { getPrivateRoomType } from '../../../../lib/rooms/roomTypes/private';
|
||||
import { Rooms } from '../../../stores';
|
||||
import * as Federation from '../../federation/Federation';
|
||||
import { getRoomAvatarURL } from '../../getRoomAvatarURL';
|
||||
import { settings } from '../../settings';
|
||||
import { roomCoordinator } from '../roomCoordinator';
|
||||
|
||||
export const PrivateRoomType = getPrivateRoomType(roomCoordinator);
|
||||
|
||||
roomCoordinator.add(
|
||||
{
|
||||
...PrivateRoomType,
|
||||
label: 'Private_Groups',
|
||||
},
|
||||
{
|
||||
allowRoomSettingChange(room, setting) {
|
||||
if (isRoomFederated(room)) {
|
||||
return Federation.isRoomSettingAllowed(room, setting);
|
||||
}
|
||||
switch (setting) {
|
||||
case RoomSettingsEnum.JOIN_CODE:
|
||||
return false;
|
||||
case RoomSettingsEnum.BROADCAST:
|
||||
return Boolean(room.broadcast);
|
||||
case RoomSettingsEnum.READ_ONLY:
|
||||
return !room.broadcast;
|
||||
case RoomSettingsEnum.REACT_WHEN_READ_ONLY:
|
||||
return Boolean(!room.broadcast && room.ro);
|
||||
case RoomSettingsEnum.E2E:
|
||||
return settings.peek('E2E_Enable') === true;
|
||||
case RoomSettingsEnum.SYSTEM_MESSAGES:
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
allowMemberAction(_room, action, showingUserId, userSubscription) {
|
||||
if (isRoomFederated(_room)) {
|
||||
return Federation.actionAllowed(_room, action, showingUserId, userSubscription);
|
||||
}
|
||||
switch (action) {
|
||||
case RoomMemberActions.BLOCK:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
roomName(roomData) {
|
||||
if (roomData.prid || isRoomFederated(roomData)) {
|
||||
return roomData.fname;
|
||||
}
|
||||
if (settings.peek('UI_Allow_room_names_with_special_chars')) {
|
||||
return roomData.fname || roomData.name;
|
||||
}
|
||||
|
||||
return roomData.name;
|
||||
},
|
||||
|
||||
isGroupChat(_room) {
|
||||
return true;
|
||||
},
|
||||
|
||||
getUiText(context) {
|
||||
switch (context) {
|
||||
case UiTextContext.HIDE_WARNING:
|
||||
return 'Hide_Group_Warning';
|
||||
case UiTextContext.LEAVE_WARNING:
|
||||
return 'Leave_Group_Warning';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
},
|
||||
|
||||
getAvatarPath(room) {
|
||||
return getRoomAvatarURL({ roomId: room._id, cache: room.avatarETag });
|
||||
},
|
||||
|
||||
getIcon(room) {
|
||||
if (room.abacAttributes) {
|
||||
if (room.teamMain) {
|
||||
return 'team-shield';
|
||||
}
|
||||
return 'hash-shield';
|
||||
}
|
||||
|
||||
if (room.prid) {
|
||||
return 'discussion';
|
||||
}
|
||||
if (room.teamMain) {
|
||||
return 'team-lock';
|
||||
}
|
||||
|
||||
if (isRoomFederated(room)) {
|
||||
return 'globe';
|
||||
}
|
||||
|
||||
return 'hashtag-lock';
|
||||
},
|
||||
|
||||
extractOpenRoomParams({ name }) {
|
||||
return { type: 'p', reference: name };
|
||||
},
|
||||
|
||||
findRoom(identifier) {
|
||||
const predicate = (record: IRoom): boolean => {
|
||||
return record.t === 'p' && record.name === identifier;
|
||||
};
|
||||
return Rooms.state.find(predicate);
|
||||
},
|
||||
} as AtLeast<IRoomTypeClientDirectives, 'isGroupChat' | 'roomName'>,
|
||||
);
|
||||
106
apps/meteor/client/lib/rooms/roomTypes/public.ts
Normal file
106
apps/meteor/client/lib/rooms/roomTypes/public.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import type { AtLeast, IRoom } from '@rocket.chat/core-typings';
|
||||
import { isRoomFederated } from '@rocket.chat/core-typings';
|
||||
|
||||
import type { IRoomTypeClientDirectives } from '../../../../definition/IRoomTypeConfig';
|
||||
import { RoomSettingsEnum, RoomMemberActions, UiTextContext } from '../../../../definition/IRoomTypeConfig';
|
||||
import { getPublicRoomType } from '../../../../lib/rooms/roomTypes/public';
|
||||
import { Rooms } from '../../../stores';
|
||||
import * as Federation from '../../federation/Federation';
|
||||
import { getRoomAvatarURL } from '../../getRoomAvatarURL';
|
||||
import { settings } from '../../settings';
|
||||
import { roomCoordinator } from '../roomCoordinator';
|
||||
|
||||
export const PublicRoomType = getPublicRoomType(roomCoordinator);
|
||||
|
||||
roomCoordinator.add(
|
||||
{
|
||||
...PublicRoomType,
|
||||
label: 'Channels',
|
||||
},
|
||||
{
|
||||
allowRoomSettingChange(room, setting) {
|
||||
if (isRoomFederated(room)) {
|
||||
return Federation.isRoomSettingAllowed(room, setting);
|
||||
}
|
||||
switch (setting) {
|
||||
case RoomSettingsEnum.BROADCAST:
|
||||
return Boolean(room.broadcast);
|
||||
case RoomSettingsEnum.READ_ONLY:
|
||||
return Boolean(!room.broadcast);
|
||||
case RoomSettingsEnum.REACT_WHEN_READ_ONLY:
|
||||
return Boolean(!room.broadcast && room.ro);
|
||||
case RoomSettingsEnum.E2E:
|
||||
return false;
|
||||
case RoomSettingsEnum.SYSTEM_MESSAGES:
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
allowMemberAction(_room, action, showingUserId, userSubscription) {
|
||||
if (isRoomFederated(_room)) {
|
||||
return Federation.actionAllowed(_room, action, showingUserId, userSubscription);
|
||||
}
|
||||
switch (action) {
|
||||
case RoomMemberActions.BLOCK:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
roomName(roomData) {
|
||||
if (roomData.prid || isRoomFederated(roomData)) {
|
||||
return roomData.fname;
|
||||
}
|
||||
if (settings.peek('UI_Allow_room_names_with_special_chars')) {
|
||||
return roomData.fname || roomData.name;
|
||||
}
|
||||
return roomData.name;
|
||||
},
|
||||
|
||||
isGroupChat(_room) {
|
||||
return true;
|
||||
},
|
||||
|
||||
getUiText(context) {
|
||||
switch (context) {
|
||||
case UiTextContext.HIDE_WARNING:
|
||||
return 'Hide_Room_Warning';
|
||||
case UiTextContext.LEAVE_WARNING:
|
||||
return 'Leave_Room_Warning';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
},
|
||||
|
||||
getAvatarPath(room) {
|
||||
return getRoomAvatarURL({ roomId: room._id, cache: room.avatarETag });
|
||||
},
|
||||
|
||||
getIcon(room) {
|
||||
if (room.prid) {
|
||||
return 'discussion';
|
||||
}
|
||||
if (room.teamMain) {
|
||||
return 'team';
|
||||
}
|
||||
if (isRoomFederated(room)) {
|
||||
return 'globe';
|
||||
}
|
||||
|
||||
return 'hashtag';
|
||||
},
|
||||
|
||||
extractOpenRoomParams({ name }) {
|
||||
return { type: 'c', reference: name };
|
||||
},
|
||||
|
||||
findRoom(identifier) {
|
||||
const predicate = (record: IRoom): boolean => {
|
||||
return record.t === 'c' && record.name === identifier;
|
||||
};
|
||||
return Rooms.state.find(predicate);
|
||||
},
|
||||
} as AtLeast<IRoomTypeClientDirectives, 'isGroupChat' | 'roomName'>,
|
||||
);
|
||||
12
apps/meteor/client/lib/rooms/roomTypes/unread.ts
Normal file
12
apps/meteor/client/lib/rooms/roomTypes/unread.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { getUnreadRoomType } from '../../../../lib/rooms/roomTypes/unread';
|
||||
import { roomCoordinator } from '../roomCoordinator';
|
||||
|
||||
export const UnreadRoomType = getUnreadRoomType(roomCoordinator);
|
||||
|
||||
roomCoordinator.add(
|
||||
{
|
||||
...UnreadRoomType,
|
||||
label: 'Unread',
|
||||
},
|
||||
{},
|
||||
);
|
||||
Reference in New Issue
Block a user