aboutsummaryrefslogtreecommitdiffstats
path: root/webui/src/components
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2021-04-23 00:16:57 +0200
committerGitHub <noreply@github.com>2021-04-23 00:16:57 +0200
commita8f3b55986982db5f7c3918acaba2c214c919d11 (patch)
tree19706066a71c32684979b019aa62525481ff4891 /webui/src/components
parent271ca35d19a9649f6d0512760aed70c8778822fc (diff)
parent774bae6d432c13cfa0de3ddc2f111927743243fe (diff)
downloadgit-bug-a8f3b55986982db5f7c3918acaba2c214c919d11.tar.gz
Merge pull request #605 from GlancingMind/upstream-12-allow-users-to-inspect-their-current-identity-details
WebUI: Add user profile
Diffstat (limited to 'webui/src/components')
-rw-r--r--webui/src/components/Author.tsx12
-rw-r--r--webui/src/components/BugTitleForm/BugTitleForm.tsx8
-rw-r--r--webui/src/components/CurrentIdentity/CurrentIdentity.tsx31
-rw-r--r--webui/src/components/Header/Header.tsx2
-rw-r--r--webui/src/components/Identity/CurrentIdentity.graphql (renamed from webui/src/components/CurrentIdentity/CurrentIdentity.graphql)5
-rw-r--r--webui/src/components/Identity/CurrentIdentity.tsx114
-rw-r--r--webui/src/components/Identity/IdentityFragment.graphql10
-rw-r--r--webui/src/components/Identity/UserIdentity.graphql9
-rw-r--r--webui/src/components/IfLoggedIn/IfLoggedIn.tsx2
9 files changed, 150 insertions, 43 deletions
diff --git a/webui/src/components/Author.tsx b/webui/src/components/Author.tsx
index d60e8969..593b5d36 100644
--- a/webui/src/components/Author.tsx
+++ b/webui/src/components/Author.tsx
@@ -1,6 +1,8 @@
import React from 'react';
+import { Link as RouterLink } from 'react-router-dom';
import MAvatar from '@material-ui/core/Avatar';
+import Link from '@material-ui/core/Link';
import Tooltip from '@material-ui/core/Tooltip/Tooltip';
import { AuthoredFragment } from '../graphql/fragments.generated';
@@ -11,13 +13,11 @@ type Props = AuthoredFragment & {
};
const Author = ({ author, ...props }: Props) => {
- if (!author.email) {
- return <span {...props}>{author.displayName}</span>;
- }
-
return (
- <Tooltip title={author.email}>
- <span {...props}>{author.displayName}</span>
+ <Tooltip title={`Goto the ${author.displayName}'s profile.`}>
+ <Link {...props} component={RouterLink} to={`/user/${author.id}`}>
+ {author.displayName}
+ </Link>
</Tooltip>
);
};
diff --git a/webui/src/components/BugTitleForm/BugTitleForm.tsx b/webui/src/components/BugTitleForm/BugTitleForm.tsx
index 665ecd4c..2a3c4db0 100644
--- a/webui/src/components/BugTitleForm/BugTitleForm.tsx
+++ b/webui/src/components/BugTitleForm/BugTitleForm.tsx
@@ -52,6 +52,10 @@ const useStyles = makeStyles((theme) => ({
saveButton: {
marginRight: theme.spacing(1),
},
+ author: {
+ fontWeight: 'bold',
+ color: theme.palette.text.secondary,
+ },
}));
interface Props {
@@ -86,7 +90,7 @@ function BugTitleForm({ bug }: Props) {
setTitle({
variables: {
input: {
- prefix: bug.humanId,
+ prefix: bug.id,
title: issueTitleInput.value,
},
},
@@ -182,7 +186,7 @@ function BugTitleForm({ bug }: Props) {
{bugTitleEdition ? editableBugTitle() : readonlyBugTitle()}
<div className="classes.headerSubtitle">
<Typography color={'textSecondary'}>
- <Author author={bug.author} />
+ <Author author={bug.author} className={classes.author} />
{' opened this bug '}
<Date date={bug.createdAt} />
</Typography>
diff --git a/webui/src/components/CurrentIdentity/CurrentIdentity.tsx b/webui/src/components/CurrentIdentity/CurrentIdentity.tsx
deleted file mode 100644
index 8cd3585b..00000000
--- a/webui/src/components/CurrentIdentity/CurrentIdentity.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import React from 'react';
-
-import Avatar from '@material-ui/core/Avatar';
-import { makeStyles } from '@material-ui/core/styles';
-
-import { useCurrentIdentityQuery } from './CurrentIdentity.generated';
-
-const useStyles = makeStyles((theme) => ({
- displayName: {
- marginLeft: theme.spacing(2),
- },
-}));
-
-const CurrentIdentity = () => {
- const classes = useStyles();
- const { loading, error, data } = useCurrentIdentityQuery();
-
- if (error || loading || !data?.repository?.userIdentity) return null;
-
- const user = data.repository.userIdentity;
- return (
- <>
- <Avatar src={user.avatarUrl ? user.avatarUrl : undefined}>
- {user.displayName.charAt(0).toUpperCase()}
- </Avatar>
- <div className={classes.displayName}>{user.displayName}</div>
- </>
- );
-};
-
-export default CurrentIdentity;
diff --git a/webui/src/components/Header/Header.tsx b/webui/src/components/Header/Header.tsx
index 63146cc9..56b35968 100644
--- a/webui/src/components/Header/Header.tsx
+++ b/webui/src/components/Header/Header.tsx
@@ -8,7 +8,7 @@ import Toolbar from '@material-ui/core/Toolbar';
import Tooltip from '@material-ui/core/Tooltip/Tooltip';
import { makeStyles } from '@material-ui/core/styles';
-import CurrentIdentity from '../CurrentIdentity/CurrentIdentity';
+import CurrentIdentity from '../Identity/CurrentIdentity';
import { LightSwitch } from '../Themer';
const useStyles = makeStyles((theme) => ({
diff --git a/webui/src/components/CurrentIdentity/CurrentIdentity.graphql b/webui/src/components/Identity/CurrentIdentity.graphql
index 2794a40f..054190df 100644
--- a/webui/src/components/CurrentIdentity/CurrentIdentity.graphql
+++ b/webui/src/components/Identity/CurrentIdentity.graphql
@@ -1,8 +1,9 @@
+#import "./IdentityFragment.graphql"
+
query CurrentIdentity {
repository {
userIdentity {
- displayName
- avatarUrl
+ ...Identity
}
}
}
diff --git a/webui/src/components/Identity/CurrentIdentity.tsx b/webui/src/components/Identity/CurrentIdentity.tsx
new file mode 100644
index 00000000..2d62dcdb
--- /dev/null
+++ b/webui/src/components/Identity/CurrentIdentity.tsx
@@ -0,0 +1,114 @@
+import React from 'react';
+import { Link as RouterLink } from 'react-router-dom';
+
+import {
+ Button,
+ ClickAwayListener,
+ Grow,
+ Link,
+ MenuItem,
+ MenuList,
+ Paper,
+ Popper,
+} from '@material-ui/core';
+import Avatar from '@material-ui/core/Avatar';
+import { makeStyles } from '@material-ui/core/styles';
+import LockIcon from '@material-ui/icons/Lock';
+
+import { useCurrentIdentityQuery } from './CurrentIdentity.generated';
+
+const useStyles = makeStyles((theme) => ({
+ displayName: {
+ marginLeft: theme.spacing(2),
+ },
+ hidden: {
+ display: 'none',
+ },
+ profileLink: {
+ ...theme.typography.button,
+ },
+ popupButton: {
+ textTransform: 'none',
+ color: theme.palette.primary.contrastText,
+ },
+}));
+
+const CurrentIdentity = () => {
+ const classes = useStyles();
+ const { loading, error, data } = useCurrentIdentityQuery();
+
+ const [open, setOpen] = React.useState(false);
+ const anchorRef = React.useRef<HTMLButtonElement>(null);
+
+ if (error || loading || !data?.repository?.userIdentity) return null;
+
+ const user = data.repository.userIdentity;
+
+ const handleToggle = () => {
+ setOpen((prevOpen) => !prevOpen);
+ };
+
+ const handleClose = (event: any) => {
+ if (anchorRef.current && anchorRef.current.contains(event.target)) {
+ return;
+ }
+ setOpen(false);
+ };
+
+ return (
+ <>
+ <Button
+ ref={anchorRef}
+ aria-controls={open ? 'menu-list-grow' : undefined}
+ aria-haspopup="true"
+ onClick={handleToggle}
+ className={classes.popupButton}
+ >
+ <Avatar src={user.avatarUrl ? user.avatarUrl : undefined}>
+ {user.displayName.charAt(0).toUpperCase()}
+ </Avatar>
+ <div className={classes.displayName}>{user.displayName}</div>
+ <LockIcon
+ color="secondary"
+ className={user.isProtected ? '' : classes.hidden}
+ />
+ </Button>
+ <Popper
+ open={open}
+ anchorEl={anchorRef.current}
+ role={undefined}
+ transition
+ disablePortal
+ >
+ {({ TransitionProps, placement }) => (
+ <Grow
+ {...TransitionProps}
+ style={{
+ transformOrigin:
+ placement === 'bottom' ? 'center top' : 'center bottom',
+ }}
+ >
+ <Paper>
+ <ClickAwayListener onClickAway={handleClose}>
+ <MenuList autoFocusItem={open} id="menu-list-grow">
+ <MenuItem>
+ <Link
+ color="inherit"
+ className={classes.profileLink}
+ component={RouterLink}
+ to={`/user/${user.id}`}
+ >
+ Open profile
+ </Link>
+ </MenuItem>
+ </MenuList>
+ </ClickAwayListener>
+ </Paper>
+ </Grow>
+ )}
+ </Popper>
+ </>
+ );
+};
+
+export default CurrentIdentity;
diff --git a/webui/src/components/Identity/IdentityFragment.graphql b/webui/src/components/Identity/IdentityFragment.graphql
new file mode 100644
index 00000000..6c4e2483
--- /dev/null
+++ b/webui/src/components/Identity/IdentityFragment.graphql
@@ -0,0 +1,10 @@
+fragment Identity on Identity {
+ id
+ humanId
+ displayName
+ email
+ name
+ avatarUrl
+ isProtected
+ login
+}
diff --git a/webui/src/components/Identity/UserIdentity.graphql b/webui/src/components/Identity/UserIdentity.graphql
new file mode 100644
index 00000000..9cf10248
--- /dev/null
+++ b/webui/src/components/Identity/UserIdentity.graphql
@@ -0,0 +1,9 @@
+#import "./IdentityFragment.graphql"
+
+query GetUserById($userId: String!) {
+ repository {
+ identity(prefix: $userId) {
+ ...Identity
+ }
+ }
+}
diff --git a/webui/src/components/IfLoggedIn/IfLoggedIn.tsx b/webui/src/components/IfLoggedIn/IfLoggedIn.tsx
index 2476aad8..ce120da1 100644
--- a/webui/src/components/IfLoggedIn/IfLoggedIn.tsx
+++ b/webui/src/components/IfLoggedIn/IfLoggedIn.tsx
@@ -1,6 +1,6 @@
import React from 'react';
-import { useCurrentIdentityQuery } from '../CurrentIdentity/CurrentIdentity.generated';
+import { useCurrentIdentityQuery } from '../Identity/CurrentIdentity.generated';
type Props = { children: () => React.ReactNode };
const IfLoggedIn = ({ children }: Props) => {