Move the account management button (#12663)
* Disable profile controls if the HS doesn't allow them to be set Also updates to the js-sdk interface changes in https://github.com/matrix-org/matrix-js-sdk/pull/4246 * Remove unnecessary await * Pass disabled prop to accessiblebutton in avatarsetting * Move the account management button The section it lives in with the server name goes, and the button just lives on its own in the profile section. * Update test * Revert bits of previous PR that are no longer wanted because we squash merge so git can no longer make sense of what changes have been applied. * More squash-merge fails * More more squash merge fails
This commit is contained in:
parent
1fbc97296c
commit
e48110d7c6
5 changed files with 46 additions and 36 deletions
|
@ -47,6 +47,15 @@ limitations under the License.
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_UserProfileSettings_profile_buttons {
|
||||||
|
margin-top: var(--cpd-space-8x);
|
||||||
|
margin-bottom: var(--cpd-space-8x);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_UserProfileSettings_accountmanageIcon {
|
||||||
|
margin-right: var(--cpd-space-2x);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||||
import React, { ChangeEvent, useCallback, useEffect, useMemo, useState } from "react";
|
import React, { ChangeEvent, useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { EditInPlace, Alert, ErrorMessage } from "@vector-im/compound-web";
|
import { EditInPlace, Alert, ErrorMessage } from "@vector-im/compound-web";
|
||||||
|
import { Icon as PopOutIcon } from "@vector-im/compound-design-tokens/icons/pop-out.svg";
|
||||||
|
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import { OwnProfileStore } from "../../../stores/OwnProfileStore";
|
import { OwnProfileStore } from "../../../stores/OwnProfileStore";
|
||||||
|
@ -29,6 +30,7 @@ import UserIdentifierCustomisations from "../../../customisations/UserIdentifier
|
||||||
import { useId } from "../../../utils/useId";
|
import { useId } from "../../../utils/useId";
|
||||||
import CopyableText from "../elements/CopyableText";
|
import CopyableText from "../elements/CopyableText";
|
||||||
import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
|
import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
|
||||||
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
|
|
||||||
const SpinnerToast: React.FC = ({ children }) => (
|
const SpinnerToast: React.FC = ({ children }) => (
|
||||||
<>
|
<>
|
||||||
|
@ -55,7 +57,28 @@ const UsernameBox: React.FC<UsernameBoxProps> = ({ username }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface ManageAccountButtonProps {
|
||||||
|
externalAccountManagementUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ManageAccountButton: React.FC<ManageAccountButtonProps> = ({ externalAccountManagementUrl }) => (
|
||||||
|
<AccessibleButton
|
||||||
|
onClick={null}
|
||||||
|
element="a"
|
||||||
|
kind="primary"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer noopener"
|
||||||
|
href={externalAccountManagementUrl}
|
||||||
|
data-testid="external-account-management-link"
|
||||||
|
>
|
||||||
|
<PopOutIcon className="mx_UserProfileSettings_accountmanageIcon" width="24" height="24" />
|
||||||
|
{_t("settings|general|oidc_manage_button")}
|
||||||
|
</AccessibleButton>
|
||||||
|
);
|
||||||
|
|
||||||
interface UserProfileSettingsProps {
|
interface UserProfileSettingsProps {
|
||||||
|
// The URL to redirect the user to in order to manage their account.
|
||||||
|
externalAccountManagementUrl?: string;
|
||||||
// Whether the homeserver allows the user to set their display name.
|
// Whether the homeserver allows the user to set their display name.
|
||||||
canSetDisplayName: boolean;
|
canSetDisplayName: boolean;
|
||||||
// Whether the homeserver allows the user to set their avatar.
|
// Whether the homeserver allows the user to set their avatar.
|
||||||
|
@ -65,7 +88,11 @@ interface UserProfileSettingsProps {
|
||||||
/**
|
/**
|
||||||
* A group of settings views to allow the user to set their profile information.
|
* A group of settings views to allow the user to set their profile information.
|
||||||
*/
|
*/
|
||||||
const UserProfileSettings: React.FC<UserProfileSettingsProps> = ({ canSetDisplayName, canSetAvatar }) => {
|
const UserProfileSettings: React.FC<UserProfileSettingsProps> = ({
|
||||||
|
externalAccountManagementUrl,
|
||||||
|
canSetDisplayName,
|
||||||
|
canSetAvatar,
|
||||||
|
}) => {
|
||||||
const [avatarURL, setAvatarURL] = useState(OwnProfileStore.instance.avatarMxc);
|
const [avatarURL, setAvatarURL] = useState(OwnProfileStore.instance.avatarMxc);
|
||||||
const [displayName, setDisplayName] = useState(OwnProfileStore.instance.displayName ?? "");
|
const [displayName, setDisplayName] = useState(OwnProfileStore.instance.displayName ?? "");
|
||||||
const [avatarError, setAvatarError] = useState<boolean>(false);
|
const [avatarError, setAvatarError] = useState<boolean>(false);
|
||||||
|
@ -192,6 +219,11 @@ const UserProfileSettings: React.FC<UserProfileSettingsProps> = ({ canSetDisplay
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
{userIdentifier && <UsernameBox username={userIdentifier} />}
|
{userIdentifier && <UsernameBox username={userIdentifier} />}
|
||||||
|
{externalAccountManagementUrl && (
|
||||||
|
<div className="mx_UserProfileSettings_profile_buttons">
|
||||||
|
<ManageAccountButton externalAccountManagementUrl={externalAccountManagementUrl} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -215,33 +215,6 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let externalAccountManagement: JSX.Element | undefined;
|
|
||||||
if (this.state.externalAccountManagementUrl) {
|
|
||||||
const { hostname } = new URL(this.state.externalAccountManagementUrl);
|
|
||||||
|
|
||||||
externalAccountManagement = (
|
|
||||||
<>
|
|
||||||
<SettingsSubsectionText data-testid="external-account-management-outer">
|
|
||||||
{_t(
|
|
||||||
"settings|general|external_account_management",
|
|
||||||
{ hostname },
|
|
||||||
{ code: (sub) => <code>{sub}</code> },
|
|
||||||
)}
|
|
||||||
</SettingsSubsectionText>
|
|
||||||
<AccessibleButton
|
|
||||||
onClick={null}
|
|
||||||
element="a"
|
|
||||||
kind="primary"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer noopener"
|
|
||||||
href={this.state.externalAccountManagementUrl}
|
|
||||||
data-testid="external-account-management-link"
|
|
||||||
>
|
|
||||||
{_t("settings|general|oidc_manage_button")}
|
|
||||||
</AccessibleButton>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SettingsSubsection
|
<SettingsSubsection
|
||||||
|
@ -249,7 +222,6 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
|
||||||
stretchContent
|
stretchContent
|
||||||
data-testid="accountSection"
|
data-testid="accountSection"
|
||||||
>
|
>
|
||||||
{externalAccountManagement}
|
|
||||||
{passwordChangeSection}
|
{passwordChangeSection}
|
||||||
</SettingsSubsection>
|
</SettingsSubsection>
|
||||||
</>
|
</>
|
||||||
|
@ -324,6 +296,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
|
||||||
<SettingsTab data-testid="mx_GeneralUserSettingsTab">
|
<SettingsTab data-testid="mx_GeneralUserSettingsTab">
|
||||||
<SettingsSection>
|
<SettingsSection>
|
||||||
<UserProfileSettings
|
<UserProfileSettings
|
||||||
|
externalAccountManagementUrl={this.state.externalAccountManagementUrl}
|
||||||
canSetDisplayName={this.state.canSetDisplayName}
|
canSetDisplayName={this.state.canSetDisplayName}
|
||||||
canSetAvatar={this.state.canSetAvatar}
|
canSetAvatar={this.state.canSetAvatar}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -2511,7 +2511,6 @@
|
||||||
"error_revoke_msisdn_discovery": "Unable to revoke sharing for phone number",
|
"error_revoke_msisdn_discovery": "Unable to revoke sharing for phone number",
|
||||||
"error_share_email_discovery": "Unable to share email address",
|
"error_share_email_discovery": "Unable to share email address",
|
||||||
"error_share_msisdn_discovery": "Unable to share phone number",
|
"error_share_msisdn_discovery": "Unable to share phone number",
|
||||||
"external_account_management": "Your account details are managed separately at <code>%(hostname)s</code>.",
|
|
||||||
"identity_server_no_token": "No identity access token found",
|
"identity_server_no_token": "No identity access token found",
|
||||||
"identity_server_not_set": "Identity server not set",
|
"identity_server_not_set": "Identity server not set",
|
||||||
"incorrect_msisdn_verification": "Incorrect verification code",
|
"incorrect_msisdn_verification": "Incorrect verification code",
|
||||||
|
|
|
@ -92,13 +92,10 @@ describe("<GeneralUserSettingsTab />", () => {
|
||||||
} as unknown as OidcClientStore;
|
} as unknown as OidcClientStore;
|
||||||
jest.spyOn(stores, "oidcClientStore", "get").mockReturnValue(mockOidcClientStore);
|
jest.spyOn(stores, "oidcClientStore", "get").mockReturnValue(mockOidcClientStore);
|
||||||
|
|
||||||
const { getByTestId } = render(getComponent());
|
render(getComponent());
|
||||||
|
|
||||||
// wait for well-known call to settle
|
const manageAccountLink = await screen.findByRole("button", { name: "Manage account" });
|
||||||
await flushPromises();
|
expect(manageAccountLink.getAttribute("href")).toMatch(accountManagementLink);
|
||||||
|
|
||||||
expect(getByTestId("external-account-management-outer").textContent).toMatch(/.*id\.server\.org/);
|
|
||||||
expect(getByTestId("external-account-management-link").getAttribute("href")).toMatch(accountManagementLink);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Manage integrations", () => {
|
describe("Manage integrations", () => {
|
||||||
|
|
Loading…
Reference in a new issue