diff --git a/api/graphql/schema/repository.graphql b/api/graphql/schema/repository.graphql index 5ce932b73819bf32d9de76938609b176b5cd6b18..d7411be7dc51a42aaa4087edbf35717c1e27abc6 100644 --- a/api/graphql/schema/repository.graphql +++ b/api/graphql/schema/repository.graphql @@ -17,10 +17,6 @@ type Repository { query: String ): BugConnection! - allBugsDetail( - query: String - ): [Bug]! - bug(prefix: String!): Bug """All the identities""" diff --git a/webui/src/App.tsx b/webui/src/App.tsx index 0b77a892d5075369150ad96726ed996769add3b1..04da655a822de38b715635a95a9e1bc053f4f986 100644 --- a/webui/src/App.tsx +++ b/webui/src/App.tsx @@ -3,7 +3,7 @@ import { Route, Switch } from 'react-router'; import Layout from './components/Header'; import BugPage from './pages/bug'; -import IdentityPage from './pages/identity/Identity'; +import IdentityPage from './pages/identity'; import ListPage from './pages/list'; import NewBugPage from './pages/new/NewBugPage'; import NotFoundPage from './pages/notfound/NotFoundPage'; @@ -15,7 +15,7 @@ export default function App() { - + diff --git a/webui/src/components/Author.tsx b/webui/src/components/Author.tsx index d60e8969fdceb24d38c645593ad0181a350ed1ba..272ca5b515be2f89c065296b86b12b75c61c1e1a 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 {author.displayName}; - } - return ( - - {author.displayName} + + + {author.displayName} + ); }; diff --git a/webui/src/components/BugTitleForm/BugTitleForm.tsx b/webui/src/components/BugTitleForm/BugTitleForm.tsx index 665ecd4cf18c60759579986141da30a55e7c84c9..1092b203a9e77c72f4e51b3289e138393151381e 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 { @@ -182,7 +186,7 @@ function BugTitleForm({ bug }: Props) { {bugTitleEdition ? editableBugTitle() : readonlyBugTitle()}
- + {' opened this bug '} diff --git a/webui/src/components/CurrentIdentity/CurrentIdentity.graphql b/webui/src/components/CurrentIdentity/CurrentIdentity.graphql deleted file mode 100644 index 5a1786f7aa45aa38f8551128fa1bc507719cb856..0000000000000000000000000000000000000000 --- a/webui/src/components/CurrentIdentity/CurrentIdentity.graphql +++ /dev/null @@ -1,14 +0,0 @@ -query CurrentIdentity { - repository { - userIdentity { - id - humanId - displayName - email - name - avatarUrl - isProtected - login - } - } -} diff --git a/webui/src/components/Header/Header.tsx b/webui/src/components/Header/Header.tsx index 63146cc9c1d1051db00043b18b66ac09d573e8a5..56b359681ed33145dbb7f5a445ef2e38dc7bed39 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/Identity/CurrentIdentity.graphql b/webui/src/components/Identity/CurrentIdentity.graphql new file mode 100644 index 0000000000000000000000000000000000000000..054190df50c3900168cb95168adae93fda5a9eb6 --- /dev/null +++ b/webui/src/components/Identity/CurrentIdentity.graphql @@ -0,0 +1,9 @@ +#import "./IdentityFragment.graphql" + +query CurrentIdentity { + repository { + userIdentity { + ...Identity + } + } +} diff --git a/webui/src/components/CurrentIdentity/CurrentIdentity.tsx b/webui/src/components/Identity/CurrentIdentity.tsx similarity index 94% rename from webui/src/components/CurrentIdentity/CurrentIdentity.tsx rename to webui/src/components/Identity/CurrentIdentity.tsx index 962ce9ec9cc09120b3fe26c3f066d101316e66b2..1fd424c177450b3a1b04a5777d4fd7fa78577a87 100644 --- a/webui/src/components/CurrentIdentity/CurrentIdentity.tsx +++ b/webui/src/components/Identity/CurrentIdentity.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { Link as RouterLink } from 'react-router-dom'; import { Button, @@ -94,7 +95,8 @@ const CurrentIdentity = () => { Open profile diff --git a/webui/src/components/Identity/IdentityFragment.graphql b/webui/src/components/Identity/IdentityFragment.graphql new file mode 100644 index 0000000000000000000000000000000000000000..6c4e2483dcd06ab95910f008e669d2cef9c644e7 --- /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 0000000000000000000000000000000000000000..9cf102486236da0b62cb604e58de2503ee6fd5b4 --- /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 2476aad87cd4589bfaf4d05f9a34be107227f69c..ce120da13ceaa325df475f709853b3dcd765f316 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) => { diff --git a/webui/src/graphql/fragments.graphql b/webui/src/graphql/fragments.graphql index 03a235f9b144ac1db78570fd6e5e30b820427046..d01c488a004ab4c44c535115656a19f05b00570d 100644 --- a/webui/src/graphql/fragments.graphql +++ b/webui/src/graphql/fragments.graphql @@ -15,5 +15,6 @@ fragment authored on Authored { email displayName avatarUrl + humanId } } diff --git a/webui/src/pages/bug/LabelChange.tsx b/webui/src/pages/bug/LabelChange.tsx index 712c33fabdb2280baca87170027e0c054ff2edb2..868d8c9b97ba306cb71376e999725affc0b17972 100644 --- a/webui/src/pages/bug/LabelChange.tsx +++ b/webui/src/pages/bug/LabelChange.tsx @@ -1,5 +1,6 @@ import React from 'react'; +import { Typography } from '@material-ui/core'; import { makeStyles } from '@material-ui/core/styles'; import Author from 'src/components/Author'; @@ -10,11 +11,12 @@ import { LabelChangeFragment } from './LabelChangeFragment.generated'; const useStyles = makeStyles((theme) => ({ main: { - ...theme.typography.body2, + color: theme.palette.text.secondary, marginLeft: theme.spacing(1) + 40, }, author: { fontWeight: 'bold', + color: theme.palette.text.secondary, }, label: { maxWidth: '50ch', @@ -31,7 +33,7 @@ function LabelChange({ op }: Props) { const { added, removed } = op; const classes = useStyles(); return ( -
+ {added.length > 0 && added the } {added.map((label, index) => ( @@ -48,7 +50,7 @@ function LabelChange({ op }: Props) { {added.length + removed.length > 1 && 's'}{' '} -
+ ); } diff --git a/webui/src/pages/bug/Message.tsx b/webui/src/pages/bug/Message.tsx index 39b11ccdae7b3ab25dc9f50ccbda9ccef98321a9..808bb52529dcab99ae1ac1cf5218a2567f59b49e 100644 --- a/webui/src/pages/bug/Message.tsx +++ b/webui/src/pages/bug/Message.tsx @@ -21,6 +21,7 @@ import MessageHistoryDialog from './MessageHistoryDialog'; const useStyles = makeStyles((theme) => ({ author: { fontWeight: 'bold', + color: theme.palette.info.contrastText, }, container: { display: 'flex', diff --git a/webui/src/pages/bug/SetStatus.tsx b/webui/src/pages/bug/SetStatus.tsx index 855848f90249435db7597d32ff795a62407cb197..f231b9174257fb7052d61f39c99700f5b6c1acd3 100644 --- a/webui/src/pages/bug/SetStatus.tsx +++ b/webui/src/pages/bug/SetStatus.tsx @@ -1,5 +1,6 @@ import React from 'react'; +import { Typography } from '@material-ui/core'; import { makeStyles } from '@material-ui/core/styles'; import { Status } from '../../gqlTypes'; @@ -10,11 +11,12 @@ import { SetStatusFragment } from './SetStatusFragment.generated'; const useStyles = makeStyles((theme) => ({ main: { - ...theme.typography.body2, + color: theme.palette.text.secondary, marginLeft: theme.spacing(1) + 40, }, author: { fontWeight: 'bold', + color: theme.palette.text.secondary, }, })); @@ -29,11 +31,11 @@ function SetStatus({ op }: Props) { ]; return ( -
+ {status} this -
+ ); } diff --git a/webui/src/pages/bug/SetTitle.tsx b/webui/src/pages/bug/SetTitle.tsx index 98bea928f3e4b1614a83eee9298da56261b9f61e..057062f7d4e7c31a31b1c885866294044201493a 100644 --- a/webui/src/pages/bug/SetTitle.tsx +++ b/webui/src/pages/bug/SetTitle.tsx @@ -1,5 +1,6 @@ import React from 'react'; +import { Typography } from '@material-ui/core'; import { makeStyles } from '@material-ui/core/styles'; import Author from 'src/components/Author'; @@ -9,11 +10,12 @@ import { SetTitleFragment } from './SetTitleFragment.generated'; const useStyles = makeStyles((theme) => ({ main: { - ...theme.typography.body2, + color: theme.palette.text.secondary, marginLeft: theme.spacing(1) + 40, }, author: { fontWeight: 'bold', + color: theme.palette.text.secondary, }, before: { fontWeight: 'bold', @@ -31,14 +33,14 @@ type Props = { function SetTitle({ op }: Props) { const classes = useStyles(); return ( -
+ changed the title from {op.was} to {op.title}  -
+ ); } diff --git a/webui/src/pages/identity/BugList.tsx b/webui/src/pages/identity/BugList.tsx index e74c11d4b69c711b55b5d460663416a690d049e8..c7994827b24805e929fcff69322977248572ed76 100644 --- a/webui/src/pages/identity/BugList.tsx +++ b/webui/src/pages/identity/BugList.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { Card, Link, Typography } from '@material-ui/core'; +import { Card, Divider, Link, Typography } from '@material-ui/core'; import CircularProgress from '@material-ui/core/CircularProgress'; import { makeStyles } from '@material-ui/core/styles'; @@ -53,6 +53,7 @@ function BugList({ humanId }: Props) { {bug.title} + Created  @@ -64,6 +65,7 @@ function BugList({ humanId }: Props) { ); })} + {bugs?.length === 0 &&

No authored bugs by this user found.

}
); } diff --git a/webui/src/pages/identity/GetUserStatistic.graphql b/webui/src/pages/identity/GetUserStatistic.graphql new file mode 100644 index 0000000000000000000000000000000000000000..318b860dfbabda145f1e93c8ccea61069aee5c95 --- /dev/null +++ b/webui/src/pages/identity/GetUserStatistic.graphql @@ -0,0 +1,13 @@ +query GetUserStatistic($authorQuery: String!, $participantQuery: String!, $actionQuery: String!) { + repository { + authored: allBugs(query: $authorQuery) { + totalCount + }, + participated: allBugs(query: $participantQuery) { + totalCount + } + actions: allBugs(query: $actionQuery) { + totalCount + } + } +} diff --git a/webui/src/pages/identity/Identity.tsx b/webui/src/pages/identity/Identity.tsx index 8261c0f44eb676b904f4bcaa9cdfb72a4ba253dd..5bfc87c0d1aae3a0c4f39d9d15a26112b660033d 100644 --- a/webui/src/pages/identity/Identity.tsx +++ b/webui/src/pages/identity/Identity.tsx @@ -1,124 +1,145 @@ import React from 'react'; +import { Link as RouterLink } from 'react-router-dom'; -import { - Checkbox, - FormControlLabel, - Link, - Paper, - Typography, -} from '@material-ui/core'; +import { Link, Paper, Typography } from '@material-ui/core'; import Avatar from '@material-ui/core/Avatar'; +import CircularProgress from '@material-ui/core/CircularProgress'; +import Grid from '@material-ui/core/Grid'; import { makeStyles } from '@material-ui/core/styles'; import InfoIcon from '@material-ui/icons/Info'; import MailOutlineIcon from '@material-ui/icons/MailOutline'; -import { useCurrentIdentityQuery } from '../../components/CurrentIdentity/CurrentIdentity.generated'; +import { IdentityFragment } from '../../components/Identity/IdentityFragment.generated'; -import BugList from './BugList'; +import { useGetUserStatisticQuery } from './GetUserStatistic.generated'; const useStyles = makeStyles((theme) => ({ main: { maxWidth: 1000, margin: 'auto', - marginTop: theme.spacing(4), - padding: theme.spacing(3, 2), - display: 'flex', - }, - container: { - display: 'flex', - marginBottom: theme.spacing(1), - }, - leftSidebar: { - marginTop: theme.spacing(2), - flex: '0 0 200px', + marginTop: theme.spacing(3), }, content: { - marginTop: theme.spacing(5), - padding: theme.spacing(3, 2), - minWidth: 800, - backgroundColor: theme.palette.background.paper, - }, - rightSidebar: { - marginTop: theme.spacing(5), - flex: '0 0 200px', + padding: theme.spacing(0.5, 2, 2, 2), + wordWrap: 'break-word', }, large: { - width: theme.spacing(20), - height: theme.spacing(20), + minWidth: 200, + minHeight: 200, + margin: 'auto', + maxWidth: '100%', + maxHeight: '100%', }, - control: { - paddingBottom: theme.spacing(3), + heading: { + marginTop: theme.spacing(3), }, header: { ...theme.typography.h4, + wordBreak: 'break-word', + }, + infoIcon: { + verticalAlign: 'bottom', }, })); -const Identity = () => { +type Props = { + identity: IdentityFragment; +}; +const Identity = ({ identity }: Props) => { const classes = useStyles(); - const { data } = useCurrentIdentityQuery(); - const user = data?.repository?.userIdentity; - console.log(user); + const user = identity; + + const { loading, error, data } = useGetUserStatisticQuery({ + variables: { + authorQuery: 'author:' + user?.humanId, + participantQuery: 'participant:' + user?.humanId, + actionQuery: 'actor:' + user?.humanId, + }, + }); + + if (loading) return ; + if (error) return

Error: {error}

; + const statistic = data?.repository; + const authoredCount = statistic?.authored?.totalCount; + const participatedCount = statistic?.participated?.totalCount; + const actionCount = statistic?.actions?.totalCount; return (
-
-
-

- {user?.displayName ? user?.displayName : 'none'} -

- - {user?.displayName.charAt(0).toUpperCase()} - - - Your account - - - Name: {user?.name ? user?.name : '---'} - - - Id (truncated): {user?.humanId ? user?.humanId : '---'} - - - - Login: {user?.login ? user?.login : '---'} - - - - - {user?.email ? user?.email : '---'} - - - } - /> -
- - - Bugs authored by {user?.displayName} - - - -
-
+ + + + + {user?.displayName.charAt(0).toUpperCase()} + + + +
+

{user?.name}

+ + Name: {user?.displayName ? user?.displayName : '---'} + + + Id (truncated): {user?.humanId ? user?.humanId : '---'} + + + {user?.email && ( + + + + {user?.email} + + + )} +
+
+ +
+

Statistics

+ + + Created {authoredCount} bugs. + + + + + Participated to {participatedCount} bugs. + + + + + Interacted with {actionCount} bugs. + + +
+
+
+
); }; diff --git a/webui/src/pages/identity/IdentityQuery.tsx b/webui/src/pages/identity/IdentityQuery.tsx new file mode 100644 index 0000000000000000000000000000000000000000..964a9bacf07d02c33c4e3a85be5f88ff932611e1 --- /dev/null +++ b/webui/src/pages/identity/IdentityQuery.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { RouteComponentProps } from 'react-router-dom'; + +import CircularProgress from '@material-ui/core/CircularProgress'; + +import { useGetUserByIdQuery } from '../../components/Identity/UserIdentity.generated'; + +import Identity from './Identity'; + +type Props = RouteComponentProps<{ + id: string; +}>; + +const UserQuery: React.FC = ({ match }: Props) => { + const { loading, error, data } = useGetUserByIdQuery({ + variables: { userId: match.params.id }, + }); + if (loading) return ; + if (error) return

Error: {error}

; + if (!data?.repository?.identity) return

404.

; + return ; +}; + +export default UserQuery; diff --git a/webui/src/pages/identity/index.tsx b/webui/src/pages/identity/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..06208687e0d13eab85d1cf37b07bab29461a1bba --- /dev/null +++ b/webui/src/pages/identity/index.tsx @@ -0,0 +1 @@ +export { default } from './IdentityQuery'; diff --git a/webui/src/pages/list/BugRow.tsx b/webui/src/pages/list/BugRow.tsx index 87e45581113da61164fa2bed61d876dd57a6b625..a1466d6349d83a8117d8bb628b986e5d2f30e073 100644 --- a/webui/src/pages/list/BugRow.tsx +++ b/webui/src/pages/list/BugRow.tsx @@ -9,6 +9,7 @@ import CheckCircleOutline from '@material-ui/icons/CheckCircleOutline'; import CommentOutlinedIcon from '@material-ui/icons/CommentOutlined'; import ErrorOutline from '@material-ui/icons/ErrorOutline'; +import Author from 'src/components/Author'; import Date from 'src/components/Date'; import Label from 'src/components/Label'; import { Status } from 'src/gqlTypes'; @@ -117,7 +118,8 @@ function BugRow({ bug }: Props) {
{bug.humanId} opened  -  by {bug.author.displayName} +  by  +
diff --git a/webui/src/pages/list/ListQuery.tsx b/webui/src/pages/list/ListQuery.tsx index 2b46dca50270b5f16bdbe183fa58e077edab76a1..9aefd02d4e150a88315aa8ff1732289023d34df8 100644 --- a/webui/src/pages/list/ListQuery.tsx +++ b/webui/src/pages/list/ListQuery.tsx @@ -14,7 +14,7 @@ import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft'; import KeyboardArrowRight from '@material-ui/icons/KeyboardArrowRight'; import Skeleton from '@material-ui/lab/Skeleton'; -import { useCurrentIdentityQuery } from '../../components/CurrentIdentity/CurrentIdentity.generated'; +import { useCurrentIdentityQuery } from '../../components/Identity/CurrentIdentity.generated'; import IfLoggedIn from 'src/components/IfLoggedIn/IfLoggedIn'; import { parse, Query, stringify } from './Filter';