-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Global configuration flag for media previews #29582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
63 commits
Select commit
Hold shift + click to select a range
2f4272f
Modify useMediaVisible to take a room.
Half-Shot 31c53f8
Add initial support for a account data level key.
Half-Shot a51b7d0
Merge remote-tracking branch 'origin/develop' into hs/media-previews-…
Half-Shot 084823a
Update controls.
Half-Shot b12a13e
Update settings
Half-Shot 3550303
Lint and fixes
Half-Shot 2b6151f
make some tests go happy
Half-Shot 8407a97
lint
Half-Shot ddadcc6
Merge branch 'develop' into hs/media-previews-server-config
Half-Shot c291165
Merge branch 'develop' into hs/media-previews-server-config
Half-Shot 8487a8f
i18n
Half-Shot 5bc0b3c
update preferences
Half-Shot 1ff42d3
prettier
Half-Shot bd8ed66
Update settings tab.
Half-Shot 6c9638d
Merge remote-tracking branch 'origin/develop' into hs/media-previews-…
Half-Shot a217cb1
update screenshot
Half-Shot b37b560
Update docs
Half-Shot b66e024
Rewrite controller
Half-Shot 806f5be
Rewrite tons of tests
Half-Shot ef5f044
Rewrite RoomAvatar to be a functional component
Half-Shot ee4581e
lint
Half-Shot d1213b7
lint
Half-Shot 3bdd0f4
Tidy up comments
Half-Shot 81b400a
Apply media visible hook to inline images.
Half-Shot b1c056a
Move conditionals.
Half-Shot a51eab0
copyright all the things
Half-Shot 9c278b9
Merge branch 'develop' into hs/media-previews-server-config
Half-Shot 0202ef7
Review changes
Half-Shot 7014484
Update html utils to properly discard media.
Half-Shot 31253a4
Merge remote-tracking branch 'origin/develop' into hs/media-previews-…
Half-Shot 5c5484c
Types fix
Half-Shot 3d49a61
Fixing tests that break settings getValue expectations
Half-Shot 17459e4
Merge remote-tracking branch 'origin/develop' into hs/media-previews-…
Half-Shot dc1dda9
Fix logic around media preview calculation
Half-Shot dbd533a
Fix room header tests
Half-Shot 0330933
Fixup tests for timelinePanel
Half-Shot 4a11e0e
Clear settings in matrixchat
Half-Shot 2c95cf1
Update tests to use SettingsStore where possible.
Half-Shot f9d13a8
fix bug
Half-Shot c7a7ca0
revert changes to client.ts
Half-Shot 4796ba9
Merge remote-tracking branch 'origin/develop' into hs/media-previews-…
Half-Shot cd579bc
copyright years
Half-Shot 1042706
Add header
Half-Shot bda2f22
Merge remote-tracking branch 'origin/develop' into hs/media-previews-…
Half-Shot 60d6e5c
Add a test for MediaPreviewAccountSettingsTab
Half-Shot a06a1c7
Mark initMatrixClient as optional
Half-Shot b9437bb
Improve on types
Half-Shot 1dba7e4
Ensure we do not set the account data twice.
Half-Shot 7809f44
Merge remote-tracking branch 'origin/develop' into hs/media-previews-…
Half-Shot a4143ca
lint
Half-Shot 3df67ae
Merge branch 'develop' into hs/media-previews-server-config
Half-Shot 6eb75db
Merge remote-tracking branch 'origin/develop' into hs/media-previews-…
Half-Shot a0b6613
Review changes
Half-Shot f415233
Ensure we include the client on rendered messages.
Half-Shot 50857de
Fix test
Half-Shot dcc24ec
Merge branch 'develop' into hs/media-previews-server-config
Half-Shot 38190ab
update labels
Half-Shot 7ff6ac9
clean designs
Half-Shot a7da5af
update settings tab
Half-Shot f165dae
update snapshot
Half-Shot 4bba73c
Merge branch 'develop' into hs/media-previews-server-config
Half-Shot 12e337a
copyright
Half-Shot 1efe4b5
prevent mutation
Half-Shot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
/* | ||
Copyright 2025 New Vector Ltd. | ||
|
||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial | ||
Please see LICENSE files in the repository root for full details. | ||
*/ | ||
|
||
import * as fs from "node:fs"; | ||
import { type EventType, type MsgType, type RoomJoinRulesEventContent } from "matrix-js-sdk/src/types"; | ||
|
||
import { test, expect } from "../../element-web-test"; | ||
|
||
const MEDIA_FILE = fs.readFileSync("playwright/sample-files/riot.png"); | ||
|
||
test.describe("Media preview settings", () => { | ||
test.use({ | ||
displayName: "Alan", | ||
room: async ({ app, page, homeserver, bot, user }, use) => { | ||
const mxc = (await bot.uploadContent(MEDIA_FILE, { name: "image.png", type: "image/png" })).content_uri; | ||
const roomId = await bot.createRoom({ | ||
name: "Test room", | ||
invite: [user.userId], | ||
initial_state: [{ type: "m.room.avatar", content: { url: mxc }, state_key: "" }], | ||
}); | ||
await bot.sendEvent(roomId, null, "m.room.message" as EventType, { | ||
msgtype: "m.image" as MsgType, | ||
body: "image.png", | ||
url: mxc, | ||
}); | ||
|
||
await use({ roomId }); | ||
}, | ||
}); | ||
|
||
test("should be able to hide avatars of inviters", { tag: "@screenshot" }, async ({ page, app, room, user }) => { | ||
let settings = await app.settings.openUserSettings("Preferences"); | ||
await settings.getByLabel("Hide avatars of room and inviter").click(); | ||
await app.closeDialog(); | ||
await app.viewRoomById(room.roomId); | ||
await expect( | ||
page.getByRole("complementary").filter({ hasText: "Do you want to join Test room" }), | ||
).toMatchScreenshot("invite-no-avatar.png"); | ||
Check failure on line 42 in playwright/e2e/timeline/media-preview-settings.spec.ts
|
||
await expect( | ||
page.getByRole("tree", { name: "Rooms" }).getByRole("treeitem", { name: "Test room" }), | ||
).toMatchScreenshot("invite-room-tree-no-avatar.png"); | ||
|
||
// And then go back to being visible | ||
settings = await app.settings.openUserSettings("Preferences"); | ||
await settings.getByLabel("Hide avatars of room and inviter").click(); | ||
await app.closeDialog(); | ||
await page.goto("#/home"); | ||
await app.viewRoomById(room.roomId); | ||
await expect( | ||
page.getByRole("complementary").filter({ hasText: "Do you want to join Test room" }), | ||
).toMatchScreenshot("invite-with-avatar.png"); | ||
await expect( | ||
page.getByRole("tree", { name: "Rooms" }).getByRole("treeitem", { name: "Test room" }), | ||
).toMatchScreenshot("invite-room-tree-with-avatar.png"); | ||
}); | ||
|
||
test("should be able to hide media in rooms globally", async ({ page, app, room, user }) => { | ||
const settings = await app.settings.openUserSettings("Preferences"); | ||
await settings.getByLabel("Show media in timeline").getByRole("radio", { name: "Always hide" }).click(); | ||
await app.closeDialog(); | ||
await app.viewRoomById(room.roomId); | ||
await page.getByRole("button", { name: "Accept" }).click(); | ||
await expect(page.getByText("Show image")).toBeVisible(); | ||
}); | ||
test("should be able to hide media in non-private rooms globally", async ({ page, app, room, user, bot }) => { | ||
await bot.sendStateEvent(room.roomId, "m.room.join_rules", { | ||
join_rule: "public", | ||
}); | ||
const settings = await app.settings.openUserSettings("Preferences"); | ||
await settings.getByLabel("Show media in timeline").getByLabel("In private rooms").click(); | ||
await app.closeDialog(); | ||
await app.viewRoomById(room.roomId); | ||
await page.getByRole("button", { name: "Accept" }).click(); | ||
await expect(page.getByText("Show image")).toBeVisible(); | ||
for (const joinRule of ["invite", "knock", "restricted"] as RoomJoinRulesEventContent["join_rule"][]) { | ||
await bot.sendStateEvent(room.roomId, "m.room.join_rules", { | ||
join_rule: joinRule, | ||
} satisfies RoomJoinRulesEventContent); | ||
await expect(page.getByText("Show image")).not.toBeVisible(); | ||
} | ||
}); | ||
test("should be able to show media in rooms globally", async ({ page, app, room, user }) => { | ||
const settings = await app.settings.openUserSettings("Preferences"); | ||
await settings.getByLabel("Show media in timeline").getByRole("radio", { name: "Always show" }).click(); | ||
await app.closeDialog(); | ||
await app.viewRoomById(room.roomId); | ||
await page.getByRole("button", { name: "Accept" }).click(); | ||
await expect(page.getByText("Show image")).not.toBeVisible(); | ||
}); | ||
test("should be able to hide media in an individual room", async ({ page, app, room, user }) => { | ||
const settings = await app.settings.openUserSettings("Preferences"); | ||
await settings.getByLabel("Show media in timeline").getByRole("radio", { name: "Always show" }).click(); | ||
await app.closeDialog(); | ||
|
||
await app.viewRoomById(room.roomId); | ||
await page.getByRole("button", { name: "Accept" }).click(); | ||
|
||
const roomSettings = await app.settings.openRoomSettings("General"); | ||
await roomSettings.getByLabel("Show media in timeline").getByRole("radio", { name: "Always hide" }).click(); | ||
await app.closeDialog(); | ||
|
||
await expect(page.getByText("Show image")).toBeVisible(); | ||
}); | ||
test("should be able to show media in an individual room", async ({ page, app, room, user }) => { | ||
const settings = await app.settings.openUserSettings("Preferences"); | ||
await settings.getByLabel("Show media in timeline").getByRole("radio", { name: "Always hide" }).click(); | ||
await app.closeDialog(); | ||
|
||
await app.viewRoomById(room.roomId); | ||
await page.getByRole("button", { name: "Accept" }).click(); | ||
|
||
const roomSettings = await app.settings.openRoomSettings("General"); | ||
await roomSettings.getByLabel("Show media in timeline").getByRole("radio", { name: "Always show" }).click(); | ||
await app.closeDialog(); | ||
|
||
await expect(page.getByText("Show image")).not.toBeVisible(); | ||
}); | ||
}); |
Binary file modified
BIN
-5.74 KB
(98%)
...b.spec.ts/Preferences-user-settings-tab-should-be-rendered-properly-1-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+16.2 KB
...ht/snapshots/timeline/media-preview-settings.spec.ts/invite-no-avatar-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+2.76 KB
...ts/timeline/media-preview-settings.spec.ts/invite-room-tree-no-avatar-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+3.74 KB
.../timeline/media-preview-settings.spec.ts/invite-room-tree-with-avatar-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+17.3 KB
.../snapshots/timeline/media-preview-settings.spec.ts/invite-with-avatar-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
res/css/views/settings/tabs/user/_MediaPreviewAccountSettings.pcss
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* | ||
Copyright 2025 New Vector Ltd. | ||
|
||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial | ||
Please see LICENSE files in the repository root for full details. | ||
*/ | ||
|
||
.mx_MediaPreviewAccountSetting_Radio { | ||
margin: var(--cpd-space-1x) 0; | ||
} | ||
|
||
.mx_MediaPreviewAccountSetting { | ||
margin-top: var(--cpd-space-1x); | ||
} | ||
|
||
.mx_MediaPreviewAccountSetting_RadioHelp { | ||
margin-top: 0; | ||
margin-bottom: var(--cpd-space-1x); | ||
} | ||
|
||
.mx_MediaPreviewAccountSetting_Form { | ||
width: 100%; | ||
} | ||
|
||
.mx_MediaPreviewAccountSetting_ToggleSwitch { | ||
font: var(--cpd-font-body-md-medium); | ||
letter-spacing: var(--cpd-font-letter-spacing-body-md); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/* | ||
Copyright 2025 New Vector Ltd. | ||
|
||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial | ||
Please see LICENSE files in the repository root for full details. | ||
*/ | ||
|
||
export enum MediaPreviewValue { | ||
/** | ||
* Media previews should be enabled. | ||
*/ | ||
On = "on", | ||
/** | ||
* Media previews should only be enabled for rooms with non-public join rules. | ||
*/ | ||
Private = "private", | ||
/** | ||
* Media previews should be disabled. | ||
*/ | ||
Off = "off", | ||
} | ||
|
||
export const MEDIA_PREVIEW_ACCOUNT_DATA_TYPE = "io.element.msc4278.media_preview_config"; | ||
export interface MediaPreviewConfig extends Record<string, unknown> { | ||
/** | ||
* Media preview setting for thumbnails of media in rooms. | ||
*/ | ||
media_previews: MediaPreviewValue; | ||
/** | ||
* Media preview settings for avatars of rooms we have been invited to. | ||
*/ | ||
invite_avatars: MediaPreviewValue.On | MediaPreviewValue.Off; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
/* | ||
Copyright 2024 New Vector Ltd. | ||
Copyright 2024, 2025 New Vector Ltd. | ||
Copyright 2019 Michael Telatynski <[email protected]> | ||
Copyright 2019 The Matrix.org Foundation C.I.C. | ||
Copyright 2017, 2018 New Vector Ltd | ||
|
@@ -294,6 +294,10 @@ export interface EventRenderOpts { | |
disableBigEmoji?: boolean; | ||
stripReplyFallback?: boolean; | ||
forComposerQuote?: boolean; | ||
/** | ||
* Should inline media be rendered? | ||
*/ | ||
mediaIsVisible?: boolean; | ||
} | ||
|
||
function analyseEvent(content: IContent, highlights: Optional<string[]>, opts: EventRenderOpts = {}): EventAnalysis { | ||
|
@@ -302,6 +306,20 @@ function analyseEvent(content: IContent, highlights: Optional<string[]>, opts: E | |
sanitizeParams = composerSanitizeHtmlParams; | ||
} | ||
|
||
if (opts.mediaIsVisible === false && sanitizeParams.transformTags?.["img"]) { | ||
// Prevent mutating the source of sanitizeParams. | ||
sanitizeParams = { | ||
...sanitizeParams, | ||
transformTags: { | ||
...sanitizeParams.transformTags, | ||
img: (tagName) => { | ||
// Remove element | ||
return { tagName, attribs: {} }; | ||
}, | ||
}, | ||
}; | ||
} | ||
|
||
try { | ||
const isFormattedBody = | ||
content.format === "org.matrix.custom.html" && typeof content.formatted_body === "string"; | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.