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

Commit

Permalink
Hide the displayname edit button if disabled in the config
Browse files Browse the repository at this point in the history
  • Loading branch information
sandhose committed Apr 3, 2024
1 parent 3183c5f commit 5163f31
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 77 deletions.
4 changes: 4 additions & 0 deletions crates/graphql/src/model/site_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ pub struct SiteConfig {

/// Whether user can change their email.
email_change_allowed: bool,

/// Whether user can change their display name.
display_name_change_allowed: bool,
}

#[ComplexObject]
Expand All @@ -56,6 +59,7 @@ impl SiteConfig {
tos_uri: data_model.tos_uri.clone(),
imprint: data_model.imprint.clone(),
email_change_allowed: data_model.email_change_allowed,
display_name_change_allowed: data_model.displayname_change_allowed,
}
}
}
4 changes: 4 additions & 0 deletions frontend/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1266,6 +1266,10 @@ type SiteConfig implements Node {
"""
emailChangeAllowed: Boolean!
"""
Whether user can change their display name.
"""
displayNameChangeAllowed: Boolean!
"""
The ID of the site configuration.
"""
id: ID!
Expand Down
25 changes: 22 additions & 3 deletions frontend/src/components/UserGreeting/UserGreeting.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ import {
SetDisplayNameStatus,
} from "../../gql/graphql";

import UserGreeting, { FRAGMENT } from "./UserGreeting";
import UserGreeting, { CONFIG_FRAGMENT, FRAGMENT } from "./UserGreeting";

const Template: React.FC<{
displayName?: string;
mxid: string;
}> = ({ displayName, mxid }) => {
displayNameChangeAllowed: boolean;
}> = ({ displayName, mxid, displayNameChangeAllowed }) => {
const userId = "user id";

const mockClient = {
Expand Down Expand Up @@ -57,9 +58,17 @@ const Template: React.FC<{
FRAGMENT,
);

const config = makeFragmentData(
{
id: "site config id",
displayNameChangeAllowed,
},
CONFIG_FRAGMENT,
);

return (
<Provider value={mockClient}>
<UserGreeting user={user} />
<UserGreeting user={user} siteConfig={config} />
</Provider>
);
};
Expand All @@ -68,10 +77,14 @@ const meta = {
title: "UI/User Greeting",
component: Template,
args: {
displayNameChangeAllowed: true,
displayName: "Kilgore Trout",
mxid: "@kilgore:matrix.org",
},
argTypes: {
displayNameChangeAllowed: {
control: "boolean",
},
displayName: {
control: "text",
},
Expand All @@ -91,3 +104,9 @@ export const NoDisplayName: Story = {
displayName: undefined,
},
};

export const DisplayNameChangeNotAllowed: Story = {
args: {
displayNameChangeAllowed: false,
},
};
153 changes: 83 additions & 70 deletions frontend/src/components/UserGreeting/UserGreeting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ export const FRAGMENT = graphql(/* GraphQL */ `
}
`);

export const CONFIG_FRAGMENT = graphql(/* GraphQL */ `
fragment UserGreeting_siteConfig on SiteConfig {
id
displayNameChangeAllowed
}
`);

const SET_DISPLAYNAME_MUTATION = graphql(/* GraphQL */ `
mutation SetDisplayName($userId: ID!, $displayName: String) {
setDisplayName(input: { userId: $userId, displayName: $displayName }) {
Expand Down Expand Up @@ -77,11 +84,13 @@ const EditButton = forwardRef<

type Props = {
user: FragmentType<typeof FRAGMENT>;
siteConfig: FragmentType<typeof CONFIG_FRAGMENT>;
};

const UserGreeting: React.FC<Props> = ({ user }) => {
const UserGreeting: React.FC<Props> = ({ user, siteConfig }) => {
const fieldRef = useRef<HTMLInputElement>(null);
const data = useFragment(FRAGMENT, user);
const { displayNameChangeAllowed } = useFragment(CONFIG_FRAGMENT, siteConfig);

const [setDisplayNameResult, setDisplayName] = useMutation(
SET_DISPLAYNAME_MUTATION,
Expand Down Expand Up @@ -131,75 +140,79 @@ const UserGreeting: React.FC<Props> = ({ user }) => {
)}
</div>

<Dialog.Dialog
trigger={<EditButton label={t("action.edit")} />}
open={open}
onOpenChange={(open) => {
// Reset the form when the dialog is opened or closed
fieldRef.current?.form?.reset();
setOpen(open);
}}
>
<Dialog.Title>{t("frontend.account.edit_profile.title")}</Dialog.Title>

<Avatar
size="88px"
className="self-center"
id={data.matrix.mxid}
name={data.matrix.displayName || data.matrix.mxid}
/>

<Form.Root onSubmit={onSubmit}>
<div className={styles.dialogForm}>
<Form.Field
name="displayname"
serverInvalid={
setDisplayNameResult.data?.setDisplayName.status ===
SetDisplayNameStatus.Invalid
}
>
<Form.Label>
{t("frontend.account.edit_profile.display_name_label")}
</Form.Label>

<Form.ActionControl
type="text"
Icon={IconClose}
autoComplete="name"
defaultValue={data.matrix.displayName || undefined}
actionLabel={t("action.clear")}
ref={fieldRef}
onActionClick={() => {
if (fieldRef.current) {
fieldRef.current.value = "";
fieldRef.current.focus();
}
}}
/>

<Form.HelpMessage>
{t("frontend.account.edit_profile.display_name_help")}
</Form.HelpMessage>
</Form.Field>

<Form.Field name="mxid">
<Form.Label>
{t("frontend.account.edit_profile.username_label")}
</Form.Label>
<Form.TextControl value={data.matrix.mxid} readOnly />
</Form.Field>
</div>

<Form.Submit disabled={setDisplayNameResult.fetching}>
{setDisplayNameResult.fetching && <LoadingSpinner inline />}
{t("action.save")}
</Form.Submit>
</Form.Root>

<Dialog.Close asChild>
<Button kind="tertiary">{t("action.cancel")}</Button>
</Dialog.Close>
</Dialog.Dialog>
{displayNameChangeAllowed && (
<Dialog.Dialog
trigger={<EditButton label={t("action.edit")} />}
open={open}
onOpenChange={(open) => {
// Reset the form when the dialog is opened or closed
fieldRef.current?.form?.reset();
setOpen(open);
}}
>
<Dialog.Title>
{t("frontend.account.edit_profile.title")}
</Dialog.Title>

<Avatar
size="88px"
className="self-center"
id={data.matrix.mxid}
name={data.matrix.displayName || data.matrix.mxid}
/>

<Form.Root onSubmit={onSubmit}>
<div className={styles.dialogForm}>
<Form.Field
name="displayname"
serverInvalid={
setDisplayNameResult.data?.setDisplayName.status ===
SetDisplayNameStatus.Invalid
}
>
<Form.Label>
{t("frontend.account.edit_profile.display_name_label")}
</Form.Label>

<Form.ActionControl
type="text"
Icon={IconClose}
autoComplete="name"
defaultValue={data.matrix.displayName || undefined}
actionLabel={t("action.clear")}
ref={fieldRef}
onActionClick={() => {
if (fieldRef.current) {
fieldRef.current.value = "";
fieldRef.current.focus();
}
}}
/>

<Form.HelpMessage>
{t("frontend.account.edit_profile.display_name_help")}
</Form.HelpMessage>
</Form.Field>

<Form.Field name="mxid">
<Form.Label>
{t("frontend.account.edit_profile.username_label")}
</Form.Label>
<Form.TextControl value={data.matrix.mxid} readOnly />
</Form.Field>
</div>

<Form.Submit disabled={setDisplayNameResult.fetching}>
{setDisplayNameResult.fetching && <LoadingSpinner inline />}
{t("action.save")}
</Form.Submit>
</Form.Root>

<Dialog.Close asChild>
<Button kind="tertiary">{t("action.cancel")}</Button>
</Dialog.Close>
</Dialog.Dialog>
)}
</div>
);
};
Expand Down
14 changes: 11 additions & 3 deletions frontend/src/gql/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ const documents = {
types.SetPrimaryEmailDocument,
"\n fragment UserGreeting_user on User {\n id\n matrix {\n mxid\n displayName\n }\n }\n":
types.UserGreeting_UserFragmentDoc,
"\n fragment UserGreeting_siteConfig on SiteConfig {\n id\n displayNameChangeAllowed\n }\n":
types.UserGreeting_SiteConfigFragmentDoc,
"\n mutation SetDisplayName($userId: ID!, $displayName: String) {\n setDisplayName(input: { userId: $userId, displayName: $displayName }) {\n status\n user {\n id\n matrix {\n displayName\n }\n }\n }\n }\n":
types.SetDisplayNameDocument,
"\n mutation AddEmail($userId: ID!, $email: String!) {\n addEmail(input: { userId: $userId, email: $email }) {\n status\n violations\n email {\n id\n ...UserEmail_email\n }\n }\n }\n":
Expand Down Expand Up @@ -77,7 +79,7 @@ const documents = {
types.SessionsOverviewQueryDocument,
"\n query AppSessionsListQuery(\n $before: String\n $after: String\n $first: Int\n $last: Int\n ) {\n viewer {\n __typename\n\n ... on User {\n id\n appSessions(\n before: $before\n after: $after\n first: $first\n last: $last\n state: ACTIVE\n ) {\n edges {\n cursor\n node {\n __typename\n ...CompatSession_session\n ...OAuth2Session_session\n }\n }\n\n totalCount\n pageInfo {\n startCursor\n endCursor\n hasNextPage\n hasPreviousPage\n }\n }\n }\n }\n }\n":
types.AppSessionsListQueryDocument,
"\n query CurrentUserGreeting {\n viewerSession {\n __typename\n\n ... on BrowserSession {\n id\n\n user {\n id\n ...UnverifiedEmailAlert_user\n ...UserGreeting_user\n }\n }\n }\n }\n":
"\n query CurrentUserGreeting {\n viewerSession {\n __typename\n\n ... on BrowserSession {\n id\n\n user {\n id\n ...UnverifiedEmailAlert_user\n ...UserGreeting_user\n }\n }\n }\n\n siteConfig {\n id\n ...UserGreeting_siteConfig\n }\n }\n":
types.CurrentUserGreetingDocument,
"\n query OAuth2ClientQuery($id: ID!) {\n oauth2Client(id: $id) {\n ...OAuth2Client_detail\n }\n }\n":
types.OAuth2ClientQueryDocument,
Expand Down Expand Up @@ -213,6 +215,12 @@ export function graphql(
export function graphql(
source: "\n fragment UserGreeting_user on User {\n id\n matrix {\n mxid\n displayName\n }\n }\n",
): (typeof documents)["\n fragment UserGreeting_user on User {\n id\n matrix {\n mxid\n displayName\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n fragment UserGreeting_siteConfig on SiteConfig {\n id\n displayNameChangeAllowed\n }\n",
): (typeof documents)["\n fragment UserGreeting_siteConfig on SiteConfig {\n id\n displayNameChangeAllowed\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
Expand Down Expand Up @@ -301,8 +309,8 @@ export function graphql(
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(
source: "\n query CurrentUserGreeting {\n viewerSession {\n __typename\n\n ... on BrowserSession {\n id\n\n user {\n id\n ...UnverifiedEmailAlert_user\n ...UserGreeting_user\n }\n }\n }\n }\n",
): (typeof documents)["\n query CurrentUserGreeting {\n viewerSession {\n __typename\n\n ... on BrowserSession {\n id\n\n user {\n id\n ...UnverifiedEmailAlert_user\n ...UserGreeting_user\n }\n }\n }\n }\n"];
source: "\n query CurrentUserGreeting {\n viewerSession {\n __typename\n\n ... on BrowserSession {\n id\n\n user {\n id\n ...UnverifiedEmailAlert_user\n ...UserGreeting_user\n }\n }\n }\n\n siteConfig {\n id\n ...UserGreeting_siteConfig\n }\n }\n",
): (typeof documents)["\n query CurrentUserGreeting {\n viewerSession {\n __typename\n\n ... on BrowserSession {\n id\n\n user {\n id\n ...UnverifiedEmailAlert_user\n ...UserGreeting_user\n }\n }\n }\n\n siteConfig {\n id\n ...UserGreeting_siteConfig\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
Expand Down
Loading

0 comments on commit 5163f31

Please sign in to comment.