Implement UI for history visibility acknowledgement. (#31156)
* feat: Implement UI for history visibility acknowledgement. Shows a banner above the message composer whenever a user opens a room with non-join history visibility, which they can dismiss. - Whenever a user opens an encrypted room with non-join history visibility, show them a banner, unless we have already marked it as dismissed. - Whenever a user opens an encrypted room with joined history visibility, we unmark it as dismissed. Issue: https://github.com/element-hq/element-meta/issues/2875 * tests: Add test suite for `RoomStatusBarHistoryVisible`. * docs: Document `RoomStatusBarHistoryVisible` and props interface. * feat: Use newer `@vector-im/compound` components. * test: Update snapshots for `RoomStatusBarHistoryVisible` tests. * chore: Update playwright screenshots. * feat: Move `RoomStatusBarHistoryVisible` to `shared-components`. * fix: Address review comments on `RoomStatusBarHistoryVisible`. * fix: Address review comments on `RoomStatusBar` and tests. * chore: Move `RoomStatusBarHistoryVisible` to `room/RoomStatusBarHistoryVisible` * chore: Fix linting issues. * feat: Gate behind history visibility labs flag. * feat: Add link to history sharing docs. * fix: Resolve build issue with shared-components. * tests: Enable history sharing lab for unit tests. * tests: Set labs flag in SettingsStore mock. * fix: Remove non-existent arg - documentation should be updated! * chore: Remove old CSS rule filter. * fix: Use package name for import over relative path. * fix: Mark styles as important due to improper CSS load order. * docs: Add doc comments to `!important` directives. This change should restore my status as a good person. * docs: Correct license header. * tests: Update `RoomStatusBarHistoryVisible` snapshot. * tests: Update shared history invite screenshot. * tests: Revert spurious screenshot changes. * feat: Update to use `Banner` component. * chore: Remove broken import. * chore: Remove unused translation string. * tests: Add `getHistoryVisibility` to `currentState` of stub room. * tests: Update screenshot. * chore: Remove old snapshots. * tests: Update playwright screenshot. * feat: Separate `HistoryVisibleBanner` hooks into MVVM architecture. * chore: Remove unused imports. * feat: Use info link over action button for `HistoryVisibleBanner` * tests: Update snapshot for `HistoryVisibleBanner`. * chore: Remove unused imports. * feat: Switch to MVVM architecture per style guide. * tests: Update snapshot for `HistoryVisibleBanner`. * tests: Update shared components snapshots. * tests: Add unit tests for `HistoryVisibleBannerView` stories. * fix: Linting errors from SonarCloud. * feat: Finalise conversion to MVVM. * fix: Silent `this` binding issue. * tests: Update playwright snapshot. * feat: Introduce wrapper component for `HistoryVisibleBanner`. * tests: Update playwright screenshots for `HistoryVisibleBanner`. * docs: Add doc comments to fields in `HistoryVisibleBannerViewModel`. * tests: Update playwright snapshot.
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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 { Room } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { SettingLevel } from "../../../../../src/settings/SettingLevel";
|
||||
import SettingsStore, { type CallbackFn } from "../../../../../src/settings/SettingsStore";
|
||||
import { mkEvent, stubClient, upsertRoomStateEvents } from "../../../../test-utils";
|
||||
import { HistoryVisibleBannerViewModel } from "../../../../../src/viewmodels/composer/HistoryVisibleBannerViewModel";
|
||||
|
||||
describe("HistoryVisibleBannerViewModel", () => {
|
||||
const ROOM_ID = "!roomId:example.org";
|
||||
|
||||
let room: Room;
|
||||
let watcherCallbacks: CallbackFn[];
|
||||
let acknowledgedHistoryVisibility: boolean;
|
||||
|
||||
beforeEach(() => {
|
||||
watcherCallbacks = [];
|
||||
acknowledgedHistoryVisibility = false;
|
||||
|
||||
jest.spyOn(SettingsStore, "setValue").mockImplementation(async (settingName, roomId, level, value) => {
|
||||
if (settingName === "acknowledgedHistoryVisibility") {
|
||||
acknowledgedHistoryVisibility = value;
|
||||
}
|
||||
watcherCallbacks.forEach((callbackFn) => callbackFn(settingName, roomId, level, value, value));
|
||||
});
|
||||
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName, roomId) => {
|
||||
if (settingName === "acknowledgedHistoryVisibility") {
|
||||
return acknowledgedHistoryVisibility;
|
||||
}
|
||||
if (settingName === "feature_share_history_on_invite") {
|
||||
return true;
|
||||
}
|
||||
return SettingsStore.getDefaultValue(settingName);
|
||||
});
|
||||
|
||||
jest.spyOn(SettingsStore, "watchSetting").mockImplementation((settingName, roomId, callbackFn) => {
|
||||
watcherCallbacks.push(callbackFn);
|
||||
return `mockWatcherId-${settingName}-${roomId}`;
|
||||
});
|
||||
|
||||
stubClient();
|
||||
room = new Room(ROOM_ID, {} as any, "@user:example.org");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it("should not show the banner in unencrypted rooms", () => {
|
||||
const vm = new HistoryVisibleBannerViewModel({ room });
|
||||
expect(vm.getSnapshot().visible).toBe(false);
|
||||
});
|
||||
|
||||
it("should not show the banner in encrypted rooms with joined history visibility", () => {
|
||||
upsertRoomStateEvents(room, [
|
||||
mkEvent({
|
||||
event: true,
|
||||
type: "m.room.encryption",
|
||||
user: "@user1:server",
|
||||
content: {},
|
||||
}),
|
||||
mkEvent({
|
||||
event: true,
|
||||
type: "m.room.history_visibility",
|
||||
content: {
|
||||
history_visibility: "joined",
|
||||
},
|
||||
user: "@user1:server",
|
||||
}),
|
||||
]);
|
||||
|
||||
const vm = new HistoryVisibleBannerViewModel({ room });
|
||||
expect(vm.getSnapshot().visible).toBe(false);
|
||||
});
|
||||
|
||||
it("should not show the banner if it has been dismissed", async () => {
|
||||
await SettingsStore.setValue("acknowledgedHistoryVisibility", ROOM_ID, SettingLevel.ROOM_ACCOUNT, true);
|
||||
upsertRoomStateEvents(room, [
|
||||
mkEvent({
|
||||
event: true,
|
||||
type: "m.room.encryption",
|
||||
user: "@user1:server",
|
||||
content: {},
|
||||
}),
|
||||
mkEvent({
|
||||
event: true,
|
||||
type: "m.room.history_visibility",
|
||||
user: "@user1:server",
|
||||
content: {
|
||||
history_visibility: "shared",
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
const vm = new HistoryVisibleBannerViewModel({ room });
|
||||
expect(vm.getSnapshot().visible).toBe(false);
|
||||
vm.dispose();
|
||||
});
|
||||
|
||||
it("should show the banner in encrypted rooms with non-joined history visibility", async () => {
|
||||
upsertRoomStateEvents(room, [
|
||||
mkEvent({
|
||||
event: true,
|
||||
type: "m.room.encryption",
|
||||
user: "@user1:server",
|
||||
content: {},
|
||||
}),
|
||||
mkEvent({
|
||||
event: true,
|
||||
type: "m.room.history_visibility",
|
||||
user: "@user1:server",
|
||||
content: {
|
||||
history_visibility: "shared",
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
const vm = new HistoryVisibleBannerViewModel({ room });
|
||||
expect(vm.getSnapshot().visible).toBe(true);
|
||||
await vm.onClose();
|
||||
expect(vm.getSnapshot().visible).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user