-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Implement UI for history visibility acknowledgement. #31156
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
kaylendog
merged 62 commits into
element-hq:develop
from
kaylendog:kaylendog/history-sharing/status
Dec 10, 2025
Merged
Changes from 55 commits
Commits
Show all changes
62 commits
Select commit
Hold shift + click to select a range
47ca834
feat: Implement UI for history visibility acknowledgement.
kaylendog efe05c7
tests: Add test suite for `RoomStatusBarHistoryVisible`.
kaylendog 568adbe
docs: Document `RoomStatusBarHistoryVisible` and props interface.
kaylendog 426c957
feat: Use newer `@vector-im/compound` components.
kaylendog a21f850
test: Update snapshots for `RoomStatusBarHistoryVisible` tests.
kaylendog 409d1eb
chore: Update playwright screenshots.
kaylendog a899629
feat: Move `RoomStatusBarHistoryVisible` to `shared-components`.
kaylendog 6a51c18
fix: Address review comments on `RoomStatusBarHistoryVisible`.
kaylendog a5fdc5b
fix: Address review comments on `RoomStatusBar` and tests.
kaylendog 7bc5d67
chore: Move `RoomStatusBarHistoryVisible` to `room/RoomStatusBarHisto…
kaylendog 636ecc9
chore: Fix linting issues.
kaylendog 4ae0b01
feat: Gate behind history visibility labs flag.
kaylendog 6d7bff7
feat: Add link to history sharing docs.
kaylendog a729c86
fix: Resolve build issue with shared-components.
kaylendog 30c41d1
tests: Enable history sharing lab for unit tests.
kaylendog 7444e3b
Merge remote-tracking branch 'upstream/develop' into kaylendog/histor…
kaylendog 6e49704
tests: Set labs flag in SettingsStore mock.
kaylendog 8620722
fix: Remove non-existent arg - documentation should be updated!
kaylendog ccec28f
chore: Remove old CSS rule filter.
kaylendog b8a54b9
fix: Use package name for import over relative path.
kaylendog bed81c3
fix: Mark styles as important due to improper CSS load order.
kaylendog bdc1067
docs: Add doc comments to `!important` directives.
kaylendog 746acc9
docs: Correct license header.
kaylendog f0377f8
tests: Update `RoomStatusBarHistoryVisible` snapshot.
kaylendog 90a0cab
Merge remote-tracking branch 'upstream/develop' into kaylendog/histor…
kaylendog 4e77fab
tests: Update shared history invite screenshot.
kaylendog 4c84126
tests: Revert spurious screenshot changes.
kaylendog c2ec426
Merge remote-tracking branch 'upstream/develop' into kaylendog/histor…
kaylendog 137d633
feat: Update to use `Banner` component.
kaylendog b8a1b6b
chore: Remove broken import.
kaylendog 656d90f
chore: Remove unused translation string.
kaylendog 3e6bf40
tests: Add `getHistoryVisibility` to `currentState` of stub room.
kaylendog 3072fe6
Merge remote-tracking branch 'upstream/develop' into kaylendog/histor…
kaylendog 641456d
tests: Update screenshot.
kaylendog ad48665
chore: Remove old snapshots.
kaylendog 54b938e
Merge branch 'develop' into kaylendog/history-sharing/status
kaylendog b14779a
Merge branch 'develop' into kaylendog/history-sharing/status
kaylendog 658c3d3
tests: Update playwright screenshot.
kaylendog be0fb6d
Merge branch 'develop' into kaylendog/history-sharing/status
kaylendog 14f2cbb
feat: Separate `HistoryVisibleBanner` hooks into MVVM architecture.
kaylendog 4bc039b
chore: Remove unused imports.
kaylendog bd78960
feat: Use info link over action button for `HistoryVisibleBanner`
kaylendog 21cb3c8
tests: Update snapshot for `HistoryVisibleBanner`.
kaylendog 86fa5a3
Merge remote-tracking branch 'upstream/develop' into kaylendog/histor…
kaylendog 321b5c2
chore: Remove unused imports.
kaylendog 69a8ae2
feat: Switch to MVVM architecture per style guide.
kaylendog 773e92c
Merge remote-tracking branch 'upstream/develop' into kaylendog/histor…
kaylendog 49dfc24
tests: Update snapshot for `HistoryVisibleBanner`.
kaylendog 5f22fa6
tests: Update shared components snapshots.
kaylendog 7a8c489
tests: Add unit tests for `HistoryVisibleBannerView` stories.
kaylendog e41e64c
fix: Linting errors from SonarCloud.
kaylendog e5bf5c3
feat: Finalise conversion to MVVM.
kaylendog e0e7017
Merge remote-tracking branch 'upstream/develop' into kaylendog/histor…
kaylendog f1b6112
fix: Silent `this` binding issue.
kaylendog 3602023
tests: Update playwright snapshot.
kaylendog c49a600
Merge remote-tracking branch 'upstream/develop' into kaylendog/histor…
kaylendog 50b5785
feat: Introduce wrapper component for `HistoryVisibleBanner`.
kaylendog 8477189
tests: Update playwright screenshots for `HistoryVisibleBanner`.
kaylendog b6b65b0
docs: Add doc comments to fields in `HistoryVisibleBannerViewModel`.
kaylendog 15843cc
Merge remote-tracking branch 'upstream/develop' into kaylendog/histor…
kaylendog 70e9baf
Merge remote-tracking branch 'upstream/develop' into kaylendog/histor…
kaylendog 042698a
tests: Update playwright snapshot.
kaylendog 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
Binary file added
BIN
+19.5 KB
...nents/playwright/snapshots/composer-historyvisiblebannerview--default-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions
42
...red-components/src/composer/HistoryVisibleBannerView/HistoryVisibleBannerView.stories.tsx
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,42 @@ | ||
| /* | ||
| * Copyright (c) 2025 Element Creations 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 { type Meta, type StoryFn } from "@storybook/react-vite"; | ||
| import React, { type JSX } from "react"; | ||
| import { fn } from "storybook/test"; | ||
|
|
||
| import { useMockedViewModel } from "../../useMockedViewModel"; | ||
| import { | ||
| HistoryVisibleBannerView, | ||
| type HistoryVisibleBannerViewActions, | ||
| type HistoryVisibleBannerViewSnapshot, | ||
| } from "./HistoryVisibleBannerView"; | ||
|
|
||
| type HistoryVisibleBannerProps = HistoryVisibleBannerViewSnapshot & HistoryVisibleBannerViewActions; | ||
|
|
||
| const HistoryVisibleBannerViewWrapper = ({ onClose, ...rest }: HistoryVisibleBannerProps): JSX.Element => { | ||
| const vm = useMockedViewModel(rest, { | ||
| onClose, | ||
| }); | ||
| return <HistoryVisibleBannerView vm={vm} />; | ||
| }; | ||
|
|
||
| export default { | ||
| title: "composer/HistoryVisibleBannerView", | ||
| component: HistoryVisibleBannerViewWrapper, | ||
| tags: ["autodocs"], | ||
| argTypes: {}, | ||
| args: { | ||
| visible: true, | ||
| onClose: fn(), | ||
| }, | ||
| } as Meta<typeof HistoryVisibleBannerViewWrapper>; | ||
|
|
||
| const Template: StoryFn<typeof HistoryVisibleBannerViewWrapper> = (args) => ( | ||
| <HistoryVisibleBannerViewWrapper {...args} /> | ||
| ); | ||
|
|
||
| export const Default = Template.bind({}); |
28 changes: 28 additions & 0 deletions
28
...shared-components/src/composer/HistoryVisibleBannerView/HistoryVisibleBannerView.test.tsx
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 (c) 2025 Element Creations 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 React from "react"; | ||
| import { render } from "jest-matrix-react"; | ||
| import { composeStories } from "@storybook/react-vite"; | ||
|
|
||
| import * as stories from "./HistoryVisibleBannerView.stories.tsx"; | ||
|
|
||
| const { Default } = composeStories(stories); | ||
|
|
||
| describe("HistoryVisibleBannerView", () => { | ||
| it("renders a history visible banner", () => { | ||
| const dismissFn = jest.fn(); | ||
|
|
||
| const { container } = render(<Default onClose={dismissFn} />); | ||
| expect(container).toMatchSnapshot(); | ||
|
|
||
| const button = container.querySelector("button"); | ||
| expect(button).not.toBeNull(); | ||
| button?.click(); | ||
| expect(dismissFn).toHaveBeenCalled(); | ||
| }); | ||
| }); |
79 changes: 79 additions & 0 deletions
79
...ages/shared-components/src/composer/HistoryVisibleBannerView/HistoryVisibleBannerView.tsx
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,79 @@ | ||
| /* | ||
| * Copyright (c) 2025 Element Creations 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 { Link } from "@vector-im/compound-web"; | ||
| import React, { type JSX } from "react"; | ||
|
|
||
| import { useViewModel } from "../../useViewModel"; | ||
| import { _t } from "../../utils/i18n"; | ||
| import { type ViewModel } from "../../viewmodel"; | ||
| import { Banner } from "../Banner"; | ||
|
|
||
| export interface HistoryVisibleBannerViewActions { | ||
| /** | ||
| * Called when the user dismisses the banner. | ||
| */ | ||
| onClose: () => void; | ||
| } | ||
|
|
||
| export interface HistoryVisibleBannerViewSnapshot { | ||
| /** | ||
| * Whether the banner is currently visible. | ||
| */ | ||
| visible: boolean; | ||
| } | ||
|
|
||
| /** | ||
| * The view model for the banner. | ||
| */ | ||
| export type HistoryVisibleBannerViewModel = ViewModel<HistoryVisibleBannerViewSnapshot> & | ||
| HistoryVisibleBannerViewActions; | ||
|
|
||
| interface HistoryVisibleBannerViewProps { | ||
| /** | ||
| * The view model for the banner. | ||
| */ | ||
| vm: HistoryVisibleBannerViewModel; | ||
| } | ||
|
|
||
| /** | ||
| * A component to alert that history is shared to new members of the room. | ||
| * | ||
| * @example | ||
| * ```tsx | ||
| * <HistoryVisibleBannerView vm={historyVisibleBannerViewModel} /> | ||
| * ``` | ||
| */ | ||
| export function HistoryVisibleBannerView({ vm }: Readonly<HistoryVisibleBannerViewProps>): JSX.Element { | ||
| const { visible } = useViewModel(vm); | ||
|
|
||
| const contents = _t( | ||
| "room|status_bar|history_visible", | ||
| {}, | ||
| { | ||
| a: substituteATag, | ||
| }, | ||
| ); | ||
|
|
||
| return ( | ||
| <> | ||
| {visible && ( | ||
| <Banner type="info" onClose={() => vm.onClose()}> | ||
| {contents} | ||
| </Banner> | ||
| )} | ||
| </> | ||
| ); | ||
| } | ||
|
|
||
| function substituteATag(sub: string): JSX.Element { | ||
| return ( | ||
| <Link href="https://element.io/en/help#e2ee-history-sharing" target="_blank"> | ||
| {sub} | ||
| </Link> | ||
| ); | ||
| } |
62 changes: 62 additions & 0 deletions
62
...rc/composer/HistoryVisibleBannerView/__snapshots__/HistoryVisibleBannerView.test.tsx.snap
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,62 @@ | ||
| // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing | ||
|
|
||
| exports[`HistoryVisibleBannerView renders a history visible banner 1`] = ` | ||
| <div> | ||
| <div | ||
| class="banner" | ||
| data-type="info" | ||
| > | ||
| <div | ||
| class="icon" | ||
| > | ||
| <svg | ||
| fill="currentColor" | ||
| font-size="24" | ||
| height="1em" | ||
| viewBox="0 0 24 24" | ||
| width="1em" | ||
| xmlns="http://www.w3.org/2000/svg" | ||
| > | ||
| <path | ||
| d="M11.288 7.288A.97.97 0 0 1 12 7q.424 0 .713.287Q13 7.576 13 8t-.287.713A.97.97 0 0 1 12 9a.97.97 0 0 1-.713-.287A.97.97 0 0 1 11 8q0-.424.287-.713m.001 4.001A.97.97 0 0 1 12 11q.424 0 .713.287.287.288.287.713v4q0 .424-.287.712A.97.97 0 0 1 12 17a.97.97 0 0 1-.713-.288A.97.97 0 0 1 11 16v-4q0-.424.287-.713" | ||
| /> | ||
| <path | ||
| clip-rule="evenodd" | ||
| d="M22 12c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10m-2 0a8 8 0 1 1-16 0 8 8 0 0 1 16 0" | ||
| fill-rule="evenodd" | ||
| /> | ||
| </svg> | ||
| </div> | ||
| <span | ||
| class="content" | ||
| > | ||
| <span> | ||
| Messages you send will be shared with new members invited to this room. | ||
| <a | ||
| class="_link_1v5rz_8" | ||
| data-kind="primary" | ||
| data-size="medium" | ||
| href="https://element.io/en/help#e2ee-history-sharing" | ||
| rel="noreferrer noopener" | ||
| target="_blank" | ||
| > | ||
| Learn more | ||
| </a> | ||
| </span> | ||
| </span> | ||
| <div | ||
| class="actions" | ||
| > | ||
| <button | ||
| class="_button_187yx_8" | ||
| data-kind="secondary" | ||
| data-size="sm" | ||
| role="button" | ||
| tabindex="0" | ||
| > | ||
| Dismiss | ||
| </button> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| `; |
8 changes: 8 additions & 0 deletions
8
packages/shared-components/src/composer/HistoryVisibleBannerView/index.ts
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,8 @@ | ||
| /* | ||
| * Copyright (c) 2025 Element Creations 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 * from "./HistoryVisibleBannerView"; |
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
Binary file modified
BIN
+4.81 KB
(110%)
...apshots/crypto/history-sharing.spec.ts/shared-history-invite-accepted-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
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
105 changes: 105 additions & 0 deletions
105
src/viewmodels/composer/HistoryVisibleBannerViewModel.tsx
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,105 @@ | ||
| /* | ||
| * Copyright (c) 2025 Element Creations 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 { | ||
| BaseViewModel, | ||
| type HistoryVisibleBannerViewModel as HistoryVisibleBannerViewModelInterface, | ||
| type HistoryVisibleBannerViewSnapshot, | ||
| } from "@element-hq/web-shared-components"; | ||
| import { HistoryVisibility, RoomStateEvent, type Room } from "matrix-js-sdk/src/matrix"; | ||
|
|
||
| import SettingsStore from "../../settings/SettingsStore"; | ||
| import { SettingLevel } from "../../settings/SettingLevel"; | ||
|
|
||
| interface Props { | ||
| room: Room; | ||
| } | ||
|
|
||
| export class HistoryVisibleBannerViewModel | ||
| extends BaseViewModel<HistoryVisibleBannerViewSnapshot, Props> | ||
| implements HistoryVisibleBannerViewModelInterface | ||
| { | ||
| private readonly featureWatcher: string; | ||
| private readonly acknowledgedWatcher: string; | ||
|
Comment on lines
29
to
34
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing tsdoc
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed in b6b65b0 |
||
|
|
||
| private static readonly computeSnapshot = (room: Room): HistoryVisibleBannerViewSnapshot => { | ||
| const featureEnabled = SettingsStore.getValue("feature_share_history_on_invite"); | ||
| const acknowledged = SettingsStore.getValue("acknowledgedHistoryVisibility", room.roomId); | ||
|
|
||
| return { | ||
| visible: | ||
| featureEnabled && | ||
| room.hasEncryptionStateEvent() && | ||
| room.getHistoryVisibility() !== HistoryVisibility.Joined && | ||
| !acknowledged, | ||
| }; | ||
| }; | ||
|
|
||
| public constructor(props: Props) { | ||
| super(props, HistoryVisibleBannerViewModel.computeSnapshot(props.room)); | ||
|
|
||
| this.disposables.trackListener(props.room, RoomStateEvent.Update, () => this.setSnapshot()); | ||
|
|
||
| // `SettingsStore` is not an `EventListener`, so we must manage these manually. | ||
| this.featureWatcher = SettingsStore.watchSetting( | ||
| "feature_share_history_on_invite", | ||
| null, | ||
| (_key, _roomId, _level, value: boolean) => this.setSnapshot(), | ||
| ); | ||
| this.acknowledgedWatcher = SettingsStore.watchSetting( | ||
| "acknowledgedHistoryVisibility", | ||
| props.room.roomId, | ||
| (_key, _roomId, _level, value: boolean) => this.setSnapshot(), | ||
| ); | ||
| } | ||
|
|
||
| private setSnapshot(): void { | ||
| const acknowledged = SettingsStore.getValue("acknowledgedHistoryVisibility", this.props.room.roomId); | ||
|
|
||
| // Reset the acknowleded flag when the history visibility is set back to joined. | ||
| if (this.props.room.getHistoryVisibility() === HistoryVisibility.Joined && acknowledged) { | ||
| SettingsStore.setValue( | ||
| "acknowledgedHistoryVisibility", | ||
| this.props.room.roomId, | ||
| SettingLevel.ROOM_ACCOUNT, | ||
| false, | ||
| ); | ||
| } | ||
|
|
||
| this.snapshot.set(HistoryVisibleBannerViewModel.computeSnapshot(this.props.room)); | ||
| } | ||
|
|
||
| /** | ||
| * Revoke the banner's acknoledgement status. | ||
| */ | ||
| public async revoke(): Promise<void> { | ||
| await SettingsStore.setValue( | ||
| "acknowledgedHistoryVisibility", | ||
| this.props.room.roomId, | ||
| SettingLevel.ROOM_ACCOUNT, | ||
| false, | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Called when the user dismisses the banner. | ||
| */ | ||
| public async onClose(): Promise<void> { | ||
| await SettingsStore.setValue( | ||
| "acknowledgedHistoryVisibility", | ||
| this.props.room.roomId, | ||
| SettingLevel.ROOM_ACCOUNT, | ||
| true, | ||
| ); | ||
| } | ||
|
|
||
| public dispose(): void { | ||
| super.dispose(); | ||
| SettingsStore.unwatchSetting(this.featureWatcher); | ||
| SettingsStore.unwatchSetting(this.acknowledgedWatcher); | ||
| } | ||
| } | ||
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At every render of the
MessageComposer, the vm will be recreated. We want to avoid that.You can:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in 50b5785