diff options
-rw-r--r-- | webui/src/components/BugTitleForm/BugTitleForm.tsx | 197 | ||||
-rw-r--r-- | webui/src/components/BugTitleForm/SetTitle.graphql | 7 | ||||
-rw-r--r-- | webui/src/pages/bug/Bug.tsx | 26 | ||||
-rw-r--r-- | webui/src/pages/new/NewBugPage.tsx | 5 |
4 files changed, 213 insertions, 22 deletions
diff --git a/webui/src/components/BugTitleForm/BugTitleForm.tsx b/webui/src/components/BugTitleForm/BugTitleForm.tsx new file mode 100644 index 00000000..16441c93 --- /dev/null +++ b/webui/src/components/BugTitleForm/BugTitleForm.tsx @@ -0,0 +1,197 @@ +import React, { useState } from 'react'; + +import { + Button, + fade, + makeStyles, + TextField, + Typography, +} from '@material-ui/core'; + +import { TimelineDocument } from '../../pages/bug/TimelineQuery.generated'; +import Author from 'src/components/Author'; +import Date from 'src/components/Date'; +import { BugFragment } from 'src/pages/bug/Bug.generated'; + +import { useSetTitleMutation } from './SetTitle.generated'; + +/** + * Css in JS styles + */ +const useStyles = makeStyles((theme) => ({ + header: { + display: 'flex', + flexDirection: 'column', + }, + headerTitle: { + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-between', + }, + readOnlyTitle: { + ...theme.typography.h5, + }, + readOnlyId: { + ...theme.typography.subtitle1, + marginLeft: theme.spacing(1), + }, + editButtonContainer: { + display: 'flex', + flexDirection: 'row', + justifyContent: 'flex-start', + alignItems: 'center', + minWidth: 200, + marginLeft: theme.spacing(2), + }, + greenButton: { + marginLeft: '8px', + backgroundColor: '#2ea44fd9', + color: '#fff', + '&:hover': { + backgroundColor: '#2ea44f', + }, + }, + titleInput: { + borderRadius: theme.shape.borderRadius, + borderColor: fade(theme.palette.primary.main, 0.2), + borderStyle: 'solid', + borderWidth: '1px', + backgroundColor: fade(theme.palette.primary.main, 0.05), + padding: theme.spacing(0, 0), + minWidth: 336, + transition: theme.transitions.create([ + 'width', + 'borderColor', + 'backgroundColor', + ]), + }, +})); + +interface Props { + bug: BugFragment; +} + +/** + * Component for bug title change + * @param bug Selected bug in list page + */ +function BugTitleForm({ bug }: Props) { + const [bugTitleEdition, setbugTitleEdition] = useState(false); + const [setTitle, { loading, error }] = useSetTitleMutation(); + const [issueTitle, setIssueTitle] = useState(bug.title); + const classes = useStyles(); + let issueTitleInput: any; + + function isFormValid() { + if (issueTitleInput) { + return issueTitleInput.value.length > 0 ? true : false; + } else { + return false; + } + } + + function submitNewTitle() { + if (!isFormValid()) return; + setTitle({ + variables: { + input: { + prefix: bug.humanId, + title: issueTitleInput.value, + }, + }, + refetchQueries: [ + // TODO: update the cache instead of refetching + { + query: TimelineDocument, + variables: { + id: bug.id, + first: 100, + }, + }, + ], + awaitRefetchQueries: true, + }).then(() => setbugTitleEdition(false)); + } + + function cancelChange() { + setIssueTitle(bug.title); + setbugTitleEdition(false); + } + + function editableBugTitle() { + return ( + <form className={classes.headerTitle} onSubmit={submitNewTitle}> + <TextField + inputRef={(node) => { + issueTitleInput = node; + }} + className={classes.titleInput} + variant="outlined" + fullWidth + margin="dense" + value={issueTitle} + onChange={(event: any) => setIssueTitle(event.target.value)} + /> + <div className={classes.editButtonContainer}> + <Button + size="small" + variant="contained" + type="submit" + disabled={issueTitle.length === 0} + > + Save + </Button> + <Button size="small" onClick={() => cancelChange()}> + Cancel + </Button> + </div> + </form> + ); + } + + function readonlyBugTitle() { + return ( + <div className={classes.headerTitle}> + <div> + <span className={classes.readOnlyTitle}>{bug.title}</span> + <span className={classes.readOnlyId}>{bug.humanId}</span> + </div> + <div className={classes.editButtonContainer}> + <Button + size="small" + variant="contained" + onClick={() => setbugTitleEdition(!bugTitleEdition)} + > + Edit + </Button> + <Button + className={classes.greenButton} + size="small" + variant="contained" + href="/new" + > + New issue + </Button> + </div> + </div> + ); + } + + if (loading) return <div>Loading...</div>; + if (error) return <div>Error</div>; + + return ( + <div className={classes.header}> + {bugTitleEdition ? editableBugTitle() : readonlyBugTitle()} + <div className="classes.headerSubtitle"> + <Typography color={'textSecondary'}> + <Author author={bug.author} /> + {' opened this bug '} + <Date date={bug.createdAt} /> + </Typography> + </div> + </div> + ); +} + +export default BugTitleForm; diff --git a/webui/src/components/BugTitleForm/SetTitle.graphql b/webui/src/components/BugTitleForm/SetTitle.graphql new file mode 100644 index 00000000..b96af155 --- /dev/null +++ b/webui/src/components/BugTitleForm/SetTitle.graphql @@ -0,0 +1,7 @@ +mutation setTitle($input: SetTitleInput!) { + setTitle(input: $input) { + bug { + id + } + } +}
\ No newline at end of file diff --git a/webui/src/pages/bug/Bug.tsx b/webui/src/pages/bug/Bug.tsx index 8d6d11cc..f2a116f8 100644 --- a/webui/src/pages/bug/Bug.tsx +++ b/webui/src/pages/bug/Bug.tsx @@ -1,10 +1,8 @@ import React from 'react'; -import Typography from '@material-ui/core/Typography/Typography'; import { makeStyles } from '@material-ui/core/styles'; -import Author from 'src/components/Author'; -import Date from 'src/components/Date'; +import BugTitleForm from 'src/components/BugTitleForm/BugTitleForm'; import Label from 'src/components/Label'; import IfLoggedIn from 'src/layout/IfLoggedIn'; @@ -12,21 +10,19 @@ import { BugFragment } from './Bug.generated'; import CommentForm from './CommentForm'; import TimelineQuery from './TimelineQuery'; +/** + * Css in JS Styles + */ const useStyles = makeStyles((theme) => ({ main: { maxWidth: 1000, margin: 'auto', marginTop: theme.spacing(4), + overflow: 'hidden', }, header: { marginLeft: theme.spacing(3) + 40, - }, - title: { - ...theme.typography.h5, - }, - id: { - ...theme.typography.subtitle1, - marginLeft: theme.spacing(1), + marginRight: theme.spacing(2), }, container: { display: 'flex', @@ -73,17 +69,11 @@ type Props = { function Bug({ bug }: Props) { const classes = useStyles(); + return ( <main className={classes.main}> <div className={classes.header}> - <span className={classes.title}>{bug.title}</span> - <span className={classes.id}>{bug.humanId}</span> - - <Typography color={'textSecondary'}> - <Author author={bug.author} /> - {' opened this bug '} - <Date date={bug.createdAt} /> - </Typography> + <BugTitleForm bug={bug} /> </div> <div className={classes.container}> diff --git a/webui/src/pages/new/NewBugPage.tsx b/webui/src/pages/new/NewBugPage.tsx index 8e06706f..c70cddaa 100644 --- a/webui/src/pages/new/NewBugPage.tsx +++ b/webui/src/pages/new/NewBugPage.tsx @@ -64,9 +64,6 @@ function NewBugPage() { function submitNewIssue(e: FormEvent) { e.preventDefault(); if (!isFormValid()) return; - console.log('submitNewISsue'); - console.log('title: ', issueTitle); - console.log('comment: ', issueComment); newBug({ variables: { input: { @@ -82,7 +79,7 @@ function NewBugPage() { return issueTitle.length > 0 && issueComment.length > 0 ? true : false; } - if (loading) return <div>Loading</div>; + if (loading) return <div>Loading...</div>; if (error) return <div>Error</div>; return ( |