Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
5b5b4a5
feat(channel-settings): add per-channel link preview setting (#7734)
kushkumarkashyap7280 Jan 27, 2026
d131eb6
chore: add changeset
kushkumarkashyap7280 Jan 27, 2026
4db8774
Merge branch 'develop' into feat/7734-per-channel-link-previews
kushkumarkashyap7280 Jan 27, 2026
a40718f
refactor: use translation key and optimize db lookup
kushkumarkashyap7280 Jan 27, 2026
69d2686
refactor: use translation key and optimize db lookup
kushkumarkashyap7280 Jan 27, 2026
4320d71
Merge branch 'feat/7734-per-channel-link-previews' of https://github.…
kushkumarkashyap7280 Jan 27, 2026
57f82a2
style: add field hint and remove inline comments per review
kushkumarkashyap7280 Jan 27, 2026
81a93c9
Merge branch 'develop' into feat/7734-per-channel-link-previews
kushkumarkashyap7280 Jan 27, 2026
db2d8e9
Merge branch 'develop' into feat/7734-per-channel-link-previews
kushkumarkashyap7280 Jan 28, 2026
737cf8f
Merge branch 'develop' into feat/7734-per-channel-link-previews
kushkumarkashyap7280 Jan 28, 2026
2fd50a4
Merge branch 'develop' into feat/7734-per-channel-link-previews
kushkumarkashyap7280 Jan 29, 2026
e738e8e
Merge branch 'develop' into feat/7734-per-channel-link-previews
kushkumarkashyap7280 Jan 29, 2026
3f11691
Merge branch 'develop' into feat/7734-per-channel-link-previews
kushkumarkashyap7280 Jan 29, 2026
1fa79eb
Merge branch 'develop' into feat/7734-per-channel-link-previews
kushkumarkashyap7280 Jan 30, 2026
0755294
Merge branch 'develop' into feat/7734-per-channel-link-previews
kushkumarkashyap7280 Jan 31, 2026
e855c40
Merge branch 'develop' into feat/7734-per-channel-link-previews
kushkumarkashyap7280 Feb 1, 2026
d9f386f
Merge branch 'develop' into feat/7734-per-channel-link-previews
kushkumarkashyap7280 Feb 23, 2026
f57a46f
Merge branch 'develop' into feat/7734-per-channel-link-previews
kushkumarkashyap7280 Feb 26, 2026
8148750
Merge branch 'RocketChat:develop' into feat/7734-per-channel-link-pre…
kushkumarkashyap7280 Mar 5, 2026
e9db9a7
Merge branch 'develop' into feat/7734-per-channel-link-previews
kushkumarkashyap7280 Mar 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type RoomSettings = {
retentionIgnoreThreads: boolean;
retentionOverrideGlobal: boolean;
encrypted: boolean;
linksEmbed: boolean;
favorite: {
favorite: boolean;
defaultValue: boolean;
Expand Down Expand Up @@ -265,6 +266,10 @@ const settingSavers: RoomSettingsSavers = {
await saveRoomTopic(rid, value, user);
}
},
async linksEmbed({ value, rid }) {
// This saves the value directly to the room document in MongoDB
await Rooms.updateOne({ _id: rid }, { $set: { linksEmbed: value } });
},
async roomAnnouncement({ value, room, rid, user }) {
if (!value && !room.announcement) {
return;
Expand Down Expand Up @@ -386,6 +391,8 @@ const fields: (keyof RoomSettings)[] = [
'retentionIgnoreThreads',
'retentionOverrideGlobal',
'encrypted',

'linksEmbed',
'favorite',
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,9 @@ const EditRoomInfo = ({ room, onClickClose, onClickBack }: EditRoomInfoProps) =>
const retentionExcludePinnedField = useId();
const retentionFilesOnlyField = useId();
const retentionIgnoreThreads = useId();


const linksEmbedField = useId();

const showAdvancedSettings = canViewReadOnly || readOnly || canViewArchived || canViewJoinCode || canViewHideSysMes;
const showRetentionPolicy = canEditRoomRetentionPolicy && retentionPolicy?.enabled;
Expand Down Expand Up @@ -489,6 +492,25 @@ const EditRoomInfo = ({ room, onClickClose, onClickBack }: EditRoomInfoProps) =>
</FieldRow>
</Field>
)}
{/* START OF NEW LINK PREVIEW TOGGLE */}
<Field>
<FieldRow>
<FieldLabel htmlFor={linksEmbedField}>Enable Link Previews</FieldLabel>
<Controller
control={control}
name='linksEmbed'
render={({ field: { value, ...field } }) => (
<ToggleSwitch
id={linksEmbedField}
{...field}
checked={value}
disabled={isFederated}
/>
)}
/>
</FieldRow>
</Field>
Comment on lines +494 to +512
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's check the file structure and find the relevant context
cat -n apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditRoomInfo.tsx | sed -n '480,530p'

Repository: RocketChat/Rocket.Chat

Length of output: 2007


🏁 Script executed:

# Check for permission checks on other toggles in the same file
rg -n 'canView|Permission' apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditRoomInfo.tsx -B2 -A2

Repository: RocketChat/Rocket.Chat

Length of output: 2560


🏁 Script executed:

# Search for linksEmbed references to understand permission handling
rg -n 'linksEmbed' apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/ -r . --type ts -C3

Repository: RocketChat/Rocket.Chat

Length of output: 4133


🏁 Script executed:

# Check the useEditRoomPermissions hook or similar to understand the permission pattern
rg -n 'useEditRoomPermissions\|const.*Permission.*=' apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditRoomInfo.tsx -A3

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Find and read the useEditRoomPermissions file
fd -n 'useEditRoomPermissions.ts' apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/

Repository: RocketChat/Rocket.Chat

Length of output: 296


🏁 Script executed:

# Read the useEditRoomPermissions file to see all available permissions
cat -n apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomPermissions.ts

Repository: RocketChat/Rocket.Chat

Length of output: 3580


🏁 Script executed:

# Check if LINKS_EMBED or similar setting exists in RoomSettingsEnum
rg -n 'LINKS_EMBED|RoomSettingsEnum' apps/meteor --type ts | grep -i 'links\|embed'

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Search for RoomSettingsEnum definition to see all available settings
fd 'RoomSettingsEnum' --type ts

Repository: RocketChat/Rocket.Chat

Length of output: 235


🏁 Script executed:

# Search for RoomSettingsEnum definition
find . -name '*RoomSettingsEnum*' -type f

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

# Search for LINKS_EMBED in definition directory
rg 'LINKS_EMBED|linksEmbed' definition/ --max-count 20

Repository: RocketChat/Rocket.Chat

Length of output: 117


🏁 Script executed:

# Search for IRoomTypeConfig file mentioned in imports
find . -name 'IRoomTypeConfig*' -type f

Repository: RocketChat/Rocket.Chat

Length of output: 109


🏁 Script executed:

# Read the IRoomTypeConfig.ts file to find RoomSettingsEnum
cat -n ./apps/meteor/definition/IRoomTypeConfig.ts

Repository: RocketChat/Rocket.Chat

Length of output: 4798


🏁 Script executed:

# Also check if linksEmbed is mentioned in any permission or settings context
rg 'linksEmbed' apps/meteor --max-count 30

Repository: RocketChat/Rocket.Chat

Length of output: 1480


🏁 Script executed:

# Search for global "Embed Link Previews" or similar admin setting
rg 'Embed.*Link|linksEmbed.*admin|Link.*Previews.*setting' apps/meteor --max-count 20

Repository: RocketChat/Rocket.Chat

Length of output: 774


🏁 Script executed:

# Check the PR or recent commits mentioning linksEmbed to understand PR objectives
git log --oneline --all --grep='linksEmbed\|link.*preview' | head -20

Repository: RocketChat/Rocket.Chat

Length of output: 711


🏁 Script executed:

# Look for FieldHint usage patterns in the same file
rg -A3 '<FieldHint' apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditRoomInfo.tsx

Repository: RocketChat/Rocket.Chat

Length of output: 1148


Add a FieldHint to explain the linksEmbed behavior and consider adding a permission check for consistency.

The linksEmbed toggle lacks a FieldHint, while all other toggles in this section (readOnly, archived, reactWhenReadOnly) have explanatory hints. Additionally, linksEmbed is rendered unconditionally, unlike the other toggles which all check permission guards (canViewReadOnly, canViewArchived, canViewJoinCode, canViewHideSysMes). Consider whether this field should follow the same permission pattern established by the rest of the section.

🔧 Suggested improvement with hint
 <Field>
 	<FieldRow>
 		<FieldLabel htmlFor={linksEmbedField}>{t('Enable_Link_Previews')}</FieldLabel>
 		<Controller
 			control={control}
 			name='linksEmbed'
 			render={({ field: { value, ...field } }) => (
 				<ToggleSwitch
 					id={linksEmbedField}
 					{...field}
 					checked={value}
 					disabled={isFederated}
+					aria-describedby={`${linksEmbedField}-hint`}
 				/>
 			)}
 		/>
 	</FieldRow>
+	<FieldHint id={`${linksEmbedField}-hint`}>
+		{t('Enable_Link_Previews_Description')}
+	</FieldHint>
 </Field>
🤖 Prompt for AI Agents
In
`@apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/EditRoomInfo.tsx`
around lines 496 - 512, The linksEmbed toggle (Controller for name='linksEmbed',
id linksEmbedField, rendering ToggleSwitch) needs a FieldHint added to match
other toggles and should be rendered conditionally using the same
permission-guard pattern as the other fields; wrap the existing <Field> block in
the same permission check used for the other toggles (e.g., the canView... guard
pattern) and add a <FieldHint> with the appropriate translation key (e.g.,
t('Links_Previews_Hint') or similar) to explain linksEmbed behavior so it
matches the UI/permission consistency of readOnly/archived/reactWhenReadOnly.

{/* END OF NEW LINK PREVIEW TOGGLE */}
</FieldGroup>
</AccordionItem>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export type EditRoomInfoFormData = {
showChannels: boolean;
showDiscussions: boolean;
joinCode: string;
linksEmbed: boolean;
systemMessages: MessageTypesValues[];
};

Expand All @@ -52,6 +53,7 @@ export const useEditRoomInitialValues = (room: IRoomWithRetentionPolicy): Partia
joinCodeRequired: !!joinCodeRequired,
systemMessages: Array.isArray(sysMes) ? sysMes : [],
hideSysMes: Array.isArray(sysMes) ? !!sysMes?.length : !!sysMes,
linksEmbed: room.linksEmbed !== false,
encrypted,
...(canEditRoomRetentionPolicy &&
retentionPolicy?.enabled && {
Expand Down
12 changes: 11 additions & 1 deletion apps/meteor/server/services/messages/hooks/AfterSaveOEmbed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type {
} from '@rocket.chat/core-typings';
import { isOEmbedUrlWithMetadata } from '@rocket.chat/core-typings';
import { Logger } from '@rocket.chat/logger';
import { OEmbedCache, Messages } from '@rocket.chat/models';
import { OEmbedCache, Messages, Rooms } from '@rocket.chat/models';
import { serverFetch as fetch } from '@rocket.chat/server-fetch';
import he from 'he';
import iconv from 'iconv-lite';
Expand Down Expand Up @@ -327,13 +327,23 @@ const getRelevantMetaTags = function (metaObj: OEmbedMeta): Record<string, strin
const insertMaxWidthInOembedHtml = (oembedHtml?: string): string | undefined =>
oembedHtml?.replace('iframe', 'iframe style="max-width: 100%;width:400px;height:225px"');


const rocketUrlParser = async function (message: IMessage): Promise<IMessage> {
log.debug({ msg: 'Parsing message URLs' });

// 1. Keep the Global Check
if (!settings.get('API_Embed')) {
return message;
}

// 2. NEW: Check the Per-Channel Setting
// We fetch the room to see if the user disabled previews for this specific channel.
const room = await Rooms.findOneById(message.rid, { projection: { linksEmbed: 1 } });
if (room?.linksEmbed === false) {
return message; // STOP here if the room says "No Previews"
}

// 3. Keep the rest of the existing checks...
if (!Array.isArray(message.urls)) {
return message;
}
Expand Down
8 changes: 8 additions & 0 deletions packages/core-typings/src/IRoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import type { RoomType } from './RoomType';
import type { Branded } from './utils';

export interface IRoom extends IRocketChatRecord {
/**
* Enable or disable link previews for this room. If undefined, falls back to global setting.
*/
linksEmbed?: boolean;
t: RoomType;
name?: string;
fname?: string;
Expand Down Expand Up @@ -361,6 +365,10 @@ export type RoomAdminFieldsType =
| 'abacAttributes';

export interface IRoomWithRetentionPolicy extends IRoom {
/**
* Enable or disable link previews for this room. If undefined, falls back to global setting.
*/
linksEmbed?: boolean;
retention: {
enabled?: boolean;
maxAge: number;
Expand Down