Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Disable profile controls if the HS doesn't allow them to be set #12652

Merged
merged 8 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/components/views/settings/AvatarSetting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ const AvatarSetting: React.FC<IProps> = ({
aria-labelledby={disabled ? undefined : a11yId}
// Inhibit tab stop as we have explicit upload/remove buttons
tabIndex={-1}
disabled={disabled}
>
<BaseAvatar idName={placeholderId} name={placeholderName} size="90px" />
</AccessibleButton>
Expand All @@ -184,6 +185,7 @@ const AvatarSetting: React.FC<IProps> = ({
onClick={uploadAvatar}
// Inhibit tab stop as we have explicit upload/remove buttons
tabIndex={-1}
disabled={disabled}
/>
);
}
Expand Down
19 changes: 17 additions & 2 deletions src/components/views/settings/UserProfileSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,17 @@ const UsernameBox: React.FC<UsernameBoxProps> = ({ username }) => {
);
};

interface UserProfileSettingsProps {
// Whether the homeserver allows the user to set their display name.
canSetDisplayName: boolean;
// Whether the homeserver allows the user to set their avatar.
canSetAvatar: boolean;
}

/**
* A group of settings views to allow the user to set their profile information.
*/
const UserProfileSettings: React.FC = () => {
const UserProfileSettings: React.FC<UserProfileSettingsProps> = ({ canSetDisplayName, canSetAvatar }) => {
const [avatarURL, setAvatarURL] = useState(OwnProfileStore.instance.avatarMxc);
const [displayName, setDisplayName] = useState(OwnProfileStore.instance.displayName ?? "");
const [initialDisplayName, setInitialDisplayName] = useState(OwnProfileStore.instance.displayName ?? "");
Expand Down Expand Up @@ -143,10 +150,16 @@ const UserProfileSettings: React.FC = () => {
[client],
);

const someFieldsDisabled = !canSetDisplayName || !canSetAvatar;

return (
<div className="mx_UserProfileSettings">
<h2>{_t("common|profile")}</h2>
<div>{_t("settings|general|profile_subtitle")}</div>
<div>
{someFieldsDisabled
? _t("settings|general|profile_subtitle_oidc")
: _t("settings|general|profile_subtitle")}
</div>
<div className="mx_UserProfileSettings_profile">
<AvatarSetting
avatar={avatarURL ?? undefined}
Expand All @@ -155,6 +168,7 @@ const UserProfileSettings: React.FC = () => {
removeAvatar={avatarURL ? onAvatarRemove : undefined}
placeholderName={displayName}
placeholderId={client.getUserId() ?? ""}
disabled={!canSetAvatar}
/>
<EditInPlace
className="mx_UserProfileSettings_profile_displayName"
Expand All @@ -169,6 +183,7 @@ const UserProfileSettings: React.FC = () => {
onCancel={onDisplayNameCancel}
onSave={onDisplayNameSave}
error={displayNameError ? _t("settings|general|display_name_error") : undefined}
disabled={!canSetDisplayName}
/>
</div>
{avatarError && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ interface IState {
idServerName?: string;
externalAccountManagementUrl?: string;
canMake3pidChanges: boolean;
canSetDisplayName: boolean;
canSetAvatar: boolean;
}

export default class GeneralUserSettingsTab extends React.Component<IProps, IState> {
Expand All @@ -72,6 +74,8 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
spellCheckLanguages: [],
canChangePassword: false,
canMake3pidChanges: false,
canSetDisplayName: false,
canSetAvatar: false,
};

this.getCapabilities();
Expand All @@ -95,7 +99,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
private async getCapabilities(): Promise<void> {
const cli = this.context.client!;

const capabilities = await cli.getCapabilities(); // this is cached
const capabilities = (await cli.getCapabilities()) ?? {};
const changePasswordCap = capabilities["m.change_password"];

// You can change your password so long as the capability isn't explicitly disabled. The implicit
Expand All @@ -110,7 +114,17 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
// so the behaviour for when it is missing has to be assume true
const canMake3pidChanges = !capabilities["m.3pid_changes"] || capabilities["m.3pid_changes"].enabled === true;

this.setState({ canChangePassword, externalAccountManagementUrl, canMake3pidChanges });
const canSetDisplayName =
!capabilities["m.set_displayname"] || capabilities["m.set_displayname"].enabled === true;
const canSetAvatar = !capabilities["m.set_avatar_url"] || capabilities["m.set_avatar_url"].enabled === true;

this.setState({
canChangePassword,
externalAccountManagementUrl,
canMake3pidChanges,
canSetDisplayName,
canSetAvatar,
});
}

private onLanguageChange = (newLanguage: string): void => {
Expand Down Expand Up @@ -309,7 +323,10 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
return (
<SettingsTab data-testid="mx_GeneralUserSettingsTab">
<SettingsSection>
<UserProfileSettings />
<UserProfileSettings
canSetDisplayName={this.state.canSetDisplayName}
canSetAvatar={this.state.canSetAvatar}
/>
<UserPersonalInfoSettings canMake3pidChanges={this.state.canMake3pidChanges} />
{this.renderAccountSection()}
{this.renderLanguageSection()}
Expand Down
1 change: 1 addition & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -2527,6 +2527,7 @@
"password_change_success": "Your password was successfully changed.",
"personal_info": "Personal info",
"profile_subtitle": "This is how you appear to others on the app.",
"profile_subtitle_oidc": "Your account is managed separately by an identity provider and so some of your personal information can’t be changed here.",
"remove_email_prompt": "Remove %(email)s?",
"remove_msisdn_prompt": "Remove %(phone)s?",
"spell_check_locale_placeholder": "Choose a locale",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const renderProfileSettings = (toastRack: Partial<ToastRack>, client: MatrixClie
return render(
<MatrixClientContext.Provider value={client}>
<ToastContext.Provider value={toastRack}>
<UserProfileSettings />
<UserProfileSettings canSetAvatar={true} canSetDisplayName={true} />
</ToastContext.Provider>
</MatrixClientContext.Provider>,
);
Expand Down
2 changes: 1 addition & 1 deletion test/test-utils/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export const mockClientMethodsEvents = () => ({
export const mockClientMethodsServer = (): Partial<Record<MethodLikeKeys<MatrixClient>, unknown>> => ({
getIdentityServerUrl: jest.fn(),
getHomeserverUrl: jest.fn(),
getCapabilities: jest.fn().mockReturnValue({}),
getCapabilities: jest.fn().mockResolvedValue({}),
getClientWellKnown: jest.fn().mockReturnValue({}),
waitForClientWellKnown: jest.fn().mockResolvedValue({}),
doesServerSupportUnstableFeature: jest.fn().mockResolvedValue(false),
Expand Down
Loading