Global configuration flag for media previews (#29582)

* Modify useMediaVisible to take a room.

* Add initial support for a account data level key.

* Update controls.

* Update settings

* Lint and fixes

* make some tests go happy

* lint

* i18n

* update preferences

* prettier

* Update settings tab.

* update screenshot

* Update docs

* Rewrite controller

* Rewrite tons of tests

* Rewrite RoomAvatar to be a functional component

This is so we can use hooks to determine the setting state.

* lint

* lint

* Tidy up comments

* Apply media visible hook to inline images.

* Move conditionals.

* copyright all the things

* Review changes

* Update html utils to properly discard media.

* Types fix

* Fixing tests that break settings getValue expectations

* Fix logic around media preview calculation

* Fix room header tests

* Fixup tests for timelinePanel

* Clear settings in matrixchat

* Update tests to use SettingsStore where possible.

* fix bug

* revert changes to client.ts

* copyright years

* Add header

* Add a test for MediaPreviewAccountSettingsTab

* Mark initMatrixClient as optional

* Improve on types

* Ensure we do not set the account data twice.

* lint

* Review changes

* Ensure we include the client on rendered messages.

* Fix test

* update labels

* clean designs

* update settings tab

* update snapshot

* copyright

* prevent mutation
This commit is contained in:
Will Hunt
2025-04-22 10:37:47 +01:00
committed by GitHub
parent da6ac36f11
commit 75d9898dff
44 changed files with 1427 additions and 422 deletions
@@ -1,12 +1,12 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2024, 2025 New Vector Ltd.
Copyright 2022 The Matrix.org Foundation C.I.C.
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 React, { act } from "react";
import React from "react";
import { fireEvent, render, screen, waitFor, waitForElementToBeRemoved } from "jest-matrix-react";
import { EventType, getHttpUriForMxc, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
import fetchMock from "fetch-mock-jest";
@@ -24,10 +24,11 @@ import {
mockClientMethodsDevice,
mockClientMethodsServer,
mockClientMethodsUser,
withClientContextRenderOptions,
} from "../../../../test-utils";
import { MediaEventHelper } from "../../../../../src/utils/MediaEventHelper";
import SettingsStore from "../../../../../src/settings/SettingsStore";
import { SettingLevel } from "../../../../../src/settings/SettingLevel";
import { MediaPreviewValue } from "../../../../../src/@types/media_preview";
jest.mock("matrix-encrypt-attachment", () => ({
decryptAttachment: jest.fn(),
@@ -42,6 +43,7 @@ describe("<MImageBody/>", () => {
...mockClientMethodsDevice(deviceId),
...mockClientMethodsCrypto(),
getRooms: jest.fn().mockReturnValue([]),
getRoom: jest.fn(),
getIgnoredUsers: jest.fn(),
getVersions: jest.fn().mockResolvedValue({
unstable_features: {
@@ -85,6 +87,7 @@ describe("<MImageBody/>", () => {
});
afterEach(() => {
SettingsStore.reset();
mocked(encrypt.decryptAttachment).mockReset();
});
@@ -97,6 +100,7 @@ describe("<MImageBody/>", () => {
mxEvent={encryptedMediaEvent}
mediaEventHelper={new MediaEventHelper(encryptedMediaEvent)}
/>,
withClientContextRenderOptions(cli),
);
// thumbnail with dimensions present
@@ -112,6 +116,7 @@ describe("<MImageBody/>", () => {
mxEvent={encryptedMediaEvent}
mediaEventHelper={new MediaEventHelper(encryptedMediaEvent)}
/>,
withClientContextRenderOptions(cli),
);
expect(fetchMock).toHaveBeenCalledWith(url);
@@ -129,6 +134,7 @@ describe("<MImageBody/>", () => {
mxEvent={encryptedMediaEvent}
mediaEventHelper={new MediaEventHelper(encryptedMediaEvent)}
/>,
withClientContextRenderOptions(cli),
);
await screen.findByText("Error decrypting image");
@@ -136,25 +142,12 @@ describe("<MImageBody/>", () => {
describe("with image previews/thumbnails disabled", () => {
beforeEach(() => {
act(() => {
SettingsStore.setValue("showImages", null, SettingLevel.DEVICE, false);
});
});
afterEach(() => {
act(() => {
SettingsStore.setValue(
"showImages",
null,
SettingLevel.DEVICE,
SettingsStore.getDefaultValue("showImages"),
);
SettingsStore.setValue(
"showMediaEventIds",
null,
SettingLevel.DEVICE,
SettingsStore.getDefaultValue("showMediaEventIds"),
);
const origFn = SettingsStore.getValue;
jest.spyOn(SettingsStore, "getValue").mockImplementation((setting, ...args) => {
if (setting === "mediaPreviewConfig") {
return { invite_avatars: MediaPreviewValue.Off, media_previews: MediaPreviewValue.Off };
}
return origFn(setting, ...args);
});
});
@@ -167,6 +160,7 @@ describe("<MImageBody/>", () => {
mxEvent={encryptedMediaEvent}
mediaEventHelper={new MediaEventHelper(encryptedMediaEvent)}
/>,
withClientContextRenderOptions(cli),
);
expect(screen.getByText("Show image")).toBeInTheDocument();
@@ -183,6 +177,7 @@ describe("<MImageBody/>", () => {
mxEvent={encryptedMediaEvent}
mediaEventHelper={new MediaEventHelper(encryptedMediaEvent)}
/>,
withClientContextRenderOptions(cli),
);
expect(screen.getByText("Show image")).toBeInTheDocument();
@@ -220,6 +215,7 @@ describe("<MImageBody/>", () => {
const { container } = render(
<MImageBody {...props} mxEvent={event} mediaEventHelper={new MediaEventHelper(event)} />,
withClientContextRenderOptions(cli),
);
const img = container.querySelector(".mx_MImageBody_thumbnail")!;
@@ -273,6 +269,7 @@ describe("<MImageBody/>", () => {
const { container } = render(
<MImageBody {...props} mxEvent={event} mediaEventHelper={new MediaEventHelper(event)} />,
withClientContextRenderOptions(cli),
);
// Wait for spinners to go away
@@ -298,6 +295,7 @@ describe("<MImageBody/>", () => {
const { container } = render(
<MImageBody {...props} mxEvent={event} mediaEventHelper={new MediaEventHelper(event)} />,
withClientContextRenderOptions(cli),
);
const img = container.querySelector(".mx_MImageBody_thumbnail")!;