Automatically adjust history visibility when making a room private (#30713)

* Refactor StyledRadioButton to provide proper labels.

* Automatically change history settings to members only if room is made private

* Add tests

* lint

* lint further

* Fix clickable buttons

* Revert functional component-ing

* text tweaks

* update snapshots

* Add unit test for history vis changes

* lint

* Update snapshots

* Fix flakes

* lint
This commit is contained in:
Will Hunt
2025-09-08 14:54:15 +00:00
committed by GitHub
parent 6d05bfc4c5
commit 6b510a535b
8 changed files with 239 additions and 25 deletions
@@ -35,7 +35,6 @@ export interface JoinRuleSettingsProps {
closeSettingsFn(): void;
onError(error: unknown): void;
beforeChange?(joinRule: JoinRule): Promise<boolean>; // if returns false then aborts the change
aliasWarning?: ReactNode;
disabledOptions?: Set<JoinRule>;
hiddenOptions?: Set<JoinRule>;
recommendedOption?: JoinRule;
@@ -44,7 +43,6 @@ export interface JoinRuleSettingsProps {
const JoinRuleSettings: React.FC<JoinRuleSettingsProps> = ({
room,
promptUpgrade,
aliasWarning,
onError,
beforeChange,
closeSettingsFn,
@@ -209,12 +207,7 @@ const JoinRuleSettings: React.FC<JoinRuleSettingsProps> = ({
{
value: JoinRule.Public,
label: withRecommendLabel(_t("common|public"), JoinRule.Public),
description: (
<>
{_t("room_settings|security|join_rule_public_description")}
{aliasWarning}
</>
),
description: <>{_t("room_settings|security|join_rule_public_description")}</>,
},
];
@@ -251,19 +251,28 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
private renderJoinRule(): JSX.Element {
const room = this.props.room;
let aliasWarning: JSX.Element | undefined;
if (room.getJoinRule() === JoinRule.Public && !this.state.hasAliases) {
aliasWarning = (
<div className="mx_SecurityRoomSettingsTab_warning">
<WarningIcon width={15} height={15} />
<span>{_t("room_settings|security|public_without_alias_warning")}</span>
</div>
);
}
const description = _t("room_settings|security|join_rule_description", {
roomName: room.name,
});
const isPublic = room.getJoinRule() === JoinRule.Public;
const description = (
<>
<p>
{_t("room_settings|security|join_rule_description", {
roomName: room.name,
})}
</p>
{isPublic && this.state.history === HistoryVisibility.WorldReadable && (
<div className="mx_SecurityRoomSettingsTab_warning">
<WarningIcon width={15} height={15} />
<span>{_t("room_settings|security|join_rule_world_readable_description")}</span>
</div>
)}
{isPublic && !this.state.hasAliases && (
<div className="mx_SecurityRoomSettingsTab_warning">
<WarningIcon width={15} height={15} />
<span>{_t("room_settings|security|public_without_alias_warning")}</span>
</div>
)}
</>
);
let advanced: JSX.Element | undefined;
if (room.getJoinRule() === JoinRule.Public) {
@@ -290,7 +299,6 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
onError={this.onJoinRuleChangeError}
closeSettingsFn={this.props.closeSettingsFn}
promptUpgrade={true}
aliasWarning={aliasWarning}
/>
{advanced}
</SettingsFieldset>
@@ -342,6 +350,57 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
if (!confirm) return false;
}
// If the room is going from public to private AND the room is join readable, we want to encourage the user
// to change the history visibility.
const currentlyPublic = this.props.room.getJoinRule() === JoinRule.Public;
if (this.state.history === HistoryVisibility.WorldReadable && currentlyPublic && joinRule !== JoinRule.Public) {
const client = this.context;
const canChangeHistory = this.props.room.currentState?.mayClientSendStateEvent(
EventType.RoomHistoryVisibility,
client,
);
// If we can't change the history visibility, then don't allow the join rule transition. This is a unlikely occurance
// and if this is the case, a room administator should step in.
if (!canChangeHistory) {
const dialog = Modal.createDialog(ErrorDialog, {
title: _t(
"room_settings|security|cannot_change_to_private_due_to_missing_history_visiblity_permissions|title",
),
description: (
<p>
{_t(
"room_settings|security|cannot_change_to_private_due_to_missing_history_visiblity_permissions|description",
)}
</p>
),
});
await dialog.finished;
return false;
}
// Adjust the history visibility first.
try {
await this.context.sendStateEvent(
this.props.room.roomId,
EventType.RoomHistoryVisibility,
{
history_visibility: HistoryVisibility.Shared,
},
"",
);
this.setState({ history: HistoryVisibility.Shared });
} catch (ex) {
logger.error("Failed to change history visibility", ex);
Modal.createDialog(ErrorDialog, {
title: _t("common|error"),
description: _t("error|update_history_visibility"),
});
// If we fail to update the history visibility
return false;
}
}
return true;
};