diff options
Diffstat (limited to 'webui/src/bug')
-rw-r--r-- | webui/src/bug/Bug.graphql | 13 | ||||
-rw-r--r-- | webui/src/bug/Bug.tsx | 97 | ||||
-rw-r--r-- | webui/src/bug/BugQuery.graphql | 9 | ||||
-rw-r--r-- | webui/src/bug/BugQuery.tsx | 22 | ||||
-rw-r--r-- | webui/src/bug/CommentForm.graphql | 5 | ||||
-rw-r--r-- | webui/src/bug/CommentForm.tsx | 145 | ||||
-rw-r--r-- | webui/src/bug/LabelChange.tsx | 49 | ||||
-rw-r--r-- | webui/src/bug/LabelChangeFragment.graphql | 12 | ||||
-rw-r--r-- | webui/src/bug/Message.tsx | 78 | ||||
-rw-r--r-- | webui/src/bug/MessageCommentFragment.graphql | 8 | ||||
-rw-r--r-- | webui/src/bug/MessageCreateFragment.graphql | 8 | ||||
-rw-r--r-- | webui/src/bug/SetStatus.tsx | 31 | ||||
-rw-r--r-- | webui/src/bug/SetStatusFragment.graphql | 7 | ||||
-rw-r--r-- | webui/src/bug/SetTitle.tsx | 37 | ||||
-rw-r--r-- | webui/src/bug/SetTitleFragment.graphql | 8 | ||||
-rw-r--r-- | webui/src/bug/Timeline.tsx | 48 | ||||
-rw-r--r-- | webui/src/bug/TimelineQuery.graphql | 39 | ||||
-rw-r--r-- | webui/src/bug/TimelineQuery.tsx | 30 |
18 files changed, 0 insertions, 646 deletions
diff --git a/webui/src/bug/Bug.graphql b/webui/src/bug/Bug.graphql deleted file mode 100644 index 498242c0..00000000 --- a/webui/src/bug/Bug.graphql +++ /dev/null @@ -1,13 +0,0 @@ -#import "../components/fragments.graphql" - -fragment Bug on Bug { - id - humanId - status - title - labels { - ...Label - } - createdAt - ...authored -} diff --git a/webui/src/bug/Bug.tsx b/webui/src/bug/Bug.tsx deleted file mode 100644 index 0e53e447..00000000 --- a/webui/src/bug/Bug.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import Typography from '@material-ui/core/Typography/Typography'; -import { makeStyles } from '@material-ui/core/styles'; -import React from 'react'; - -import Author from '../components/Author'; -import Date from '../components/Date'; -import Label from '../components/Label'; - -import { BugFragment } from './Bug.generated'; -import CommentForm from './CommentForm'; -import TimelineQuery from './TimelineQuery'; - -const useStyles = makeStyles(theme => ({ - main: { - maxWidth: 800, - margin: 'auto', - marginTop: theme.spacing(4), - }, - header: { - marginLeft: theme.spacing(1) + 40, - }, - title: { - ...theme.typography.h5, - }, - id: { - ...theme.typography.subtitle1, - marginLeft: theme.spacing(1), - }, - container: { - display: 'flex', - marginBottom: theme.spacing(1), - }, - timeline: { - flex: 1, - marginTop: theme.spacing(2), - marginRight: theme.spacing(2), - minWidth: 0, - }, - sidebar: { - marginTop: theme.spacing(2), - flex: '0 0 200px', - }, - labelList: { - listStyle: 'none', - padding: 0, - margin: 0, - }, - label: { - marginTop: theme.spacing(1), - marginBottom: theme.spacing(1), - '& > *': { - display: 'block', - }, - }, -})); - -type Props = { - bug: BugFragment; -}; - -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> - </div> - - <div className={classes.container}> - <div className={classes.timeline}> - <TimelineQuery id={bug.id} /> - </div> - <div className={classes.sidebar}> - <Typography variant={'subtitle1'}>Labels</Typography> - <ul className={classes.labelList}> - {bug.labels.map(l => ( - <li className={classes.label} key={l.name}> - <Label label={l} key={l.name} /> - </li> - ))} - </ul> - </div> - </div> - - <CommentForm bugId={bug.id} /> - </main> - ); -} - -export default Bug; diff --git a/webui/src/bug/BugQuery.graphql b/webui/src/bug/BugQuery.graphql deleted file mode 100644 index cdc4723f..00000000 --- a/webui/src/bug/BugQuery.graphql +++ /dev/null @@ -1,9 +0,0 @@ -#import "./Bug.graphql" - -query GetBug($id: String!) { - repository { - bug(prefix: $id) { - ...Bug - } - } -} diff --git a/webui/src/bug/BugQuery.tsx b/webui/src/bug/BugQuery.tsx deleted file mode 100644 index 2ecf718c..00000000 --- a/webui/src/bug/BugQuery.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import CircularProgress from '@material-ui/core/CircularProgress'; -import React from 'react'; -import { RouteComponentProps } from 'react-router-dom'; - -import Bug from './Bug'; -import { useGetBugQuery } from './BugQuery.generated'; - -type Props = RouteComponentProps<{ - id: string; -}>; - -const BugQuery: React.FC<Props> = ({ match }: Props) => { - const { loading, error, data } = useGetBugQuery({ - variables: { id: match.params.id }, - }); - if (loading) return <CircularProgress />; - if (error) return <p>Error: {error}</p>; - if (!data?.repository?.bug) return <p>404.</p>; - return <Bug bug={data.repository.bug} />; -}; - -export default BugQuery; diff --git a/webui/src/bug/CommentForm.graphql b/webui/src/bug/CommentForm.graphql deleted file mode 100644 index 33d21193..00000000 --- a/webui/src/bug/CommentForm.graphql +++ /dev/null @@ -1,5 +0,0 @@ -mutation AddComment($input: AddCommentInput!) { - addComment(input: $input) { - operation { id } - } -} diff --git a/webui/src/bug/CommentForm.tsx b/webui/src/bug/CommentForm.tsx deleted file mode 100644 index a915ecf0..00000000 --- a/webui/src/bug/CommentForm.tsx +++ /dev/null @@ -1,145 +0,0 @@ -import Button from '@material-ui/core/Button'; -import Paper from '@material-ui/core/Paper'; -import Tab from '@material-ui/core/Tab'; -import Tabs from '@material-ui/core/Tabs'; -import TextField from '@material-ui/core/TextField'; -import { makeStyles, Theme } from '@material-ui/core/styles'; -import React, { useState, useRef } from 'react'; - -import Content from '../components/Content'; - -import { useAddCommentMutation } from './CommentForm.generated'; -import { TimelineDocument } from './TimelineQuery.generated'; - -type StyleProps = { loading: boolean }; -const useStyles = makeStyles<Theme, StyleProps>(theme => ({ - container: { - margin: theme.spacing(2, 0), - padding: theme.spacing(0, 2, 2, 2), - }, - textarea: {}, - tabContent: { - margin: theme.spacing(2, 0), - }, - preview: { - borderBottom: `solid 3px ${theme.palette.grey['200']}`, - minHeight: '5rem', - }, - actions: { - display: 'flex', - justifyContent: 'flex-end', - }, -})); - -type TabPanelProps = { - children: React.ReactNode; - value: number; - index: number; -} & React.HTMLProps<HTMLDivElement>; -function TabPanel({ children, value, index, ...props }: TabPanelProps) { - return ( - <div - role="tabpanel" - hidden={value !== index} - id={`editor-tabpanel-${index}`} - aria-labelledby={`editor-tab-${index}`} - {...props} - > - {value === index && children} - </div> - ); -} - -const a11yProps = (index: number) => ({ - id: `editor-tab-${index}`, - 'aria-controls': `editor-tabpanel-${index}`, -}); - -type Props = { - bugId: string; -}; - -function CommentForm({ bugId }: Props) { - const [addComment, { loading }] = useAddCommentMutation(); - const [input, setInput] = useState<string>(''); - const [tab, setTab] = useState(0); - const classes = useStyles({ loading }); - const form = useRef<HTMLFormElement>(null); - - const submit = () => { - addComment({ - variables: { - input: { - prefix: bugId, - message: input, - }, - }, - refetchQueries: [ - // TODO: update the cache instead of refetching - { - query: TimelineDocument, - variables: { - id: bugId, - first: 100, - }, - }, - ], - awaitRefetchQueries: true, - }).then(() => setInput('')); - }; - - const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { - e.preventDefault(); - submit(); - }; - - const handleKeyDown = (e: React.KeyboardEvent<HTMLElement>) => { - // Submit on cmd/ctrl+enter - if ((e.metaKey || e.altKey) && e.keyCode === 13) { - submit(); - } - }; - - return ( - <Paper className={classes.container}> - <form onSubmit={handleSubmit} ref={form}> - <Tabs value={tab} onChange={(_, t) => setTab(t)}> - <Tab label="Write" {...a11yProps(0)} /> - <Tab label="Preview" {...a11yProps(1)} /> - </Tabs> - <div className={classes.tabContent}> - <TabPanel value={tab} index={0}> - <TextField - onKeyDown={handleKeyDown} - fullWidth - label="Comment" - placeholder="Leave a comment" - className={classes.textarea} - multiline - value={input} - variant="filled" - rows="4" // TODO: rowsMin support - onChange={(e: any) => setInput(e.target.value)} - disabled={loading} - /> - </TabPanel> - <TabPanel value={tab} index={1} className={classes.preview}> - <Content markdown={input} /> - </TabPanel> - </div> - <div className={classes.actions}> - <Button - variant="contained" - color="primary" - type="submit" - disabled={loading} - > - Comment - </Button> - </div> - </form> - </Paper> - ); -} - -export default CommentForm; diff --git a/webui/src/bug/LabelChange.tsx b/webui/src/bug/LabelChange.tsx deleted file mode 100644 index a3950524..00000000 --- a/webui/src/bug/LabelChange.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { makeStyles } from '@material-ui/core/styles'; -import React from 'react'; - -import Author from '../components/Author'; -import Date from '../components/Date'; -import Label from '../components/Label'; - -import { LabelChangeFragment } from './LabelChangeFragment.generated'; - -const useStyles = makeStyles(theme => ({ - main: { - ...theme.typography.body1, - marginLeft: theme.spacing(1) + 40, - }, - author: { - fontWeight: 'bold', - }, -})); - -type Props = { - op: LabelChangeFragment; -}; - -function LabelChange({ op }: Props) { - const { added, removed } = op; - const classes = useStyles(); - return ( - <div className={classes.main}> - <Author author={op.author} className={classes.author} /> - {added.length > 0 && <span> added the </span>} - {added.map((label, index) => ( - <Label key={index} label={label} /> - ))} - {added.length > 0 && removed.length > 0 && <span> and</span>} - {removed.length > 0 && <span> removed the </span>} - {removed.map((label, index) => ( - <Label key={index} label={label} /> - ))} - <span> - {' '} - label - {added.length + removed.length > 1 && 's'}{' '} - </span> - <Date date={op.date} /> - </div> - ); -} - -export default LabelChange; diff --git a/webui/src/bug/LabelChangeFragment.graphql b/webui/src/bug/LabelChangeFragment.graphql deleted file mode 100644 index 01b94a98..00000000 --- a/webui/src/bug/LabelChangeFragment.graphql +++ /dev/null @@ -1,12 +0,0 @@ -#import "../components/fragments.graphql" - -fragment LabelChange on LabelChangeTimelineItem { - date - ...authored - added { - ...Label - } - removed { - ...Label - } -} diff --git a/webui/src/bug/Message.tsx b/webui/src/bug/Message.tsx deleted file mode 100644 index a61ed3f2..00000000 --- a/webui/src/bug/Message.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import Paper from '@material-ui/core/Paper'; -import { makeStyles } from '@material-ui/core/styles'; -import React from 'react'; - -import Author, { Avatar } from '../components/Author'; -import Date from '../components/Date'; -import Content from '../components/Content'; - -import { AddCommentFragment } from './MessageCommentFragment.generated'; -import { CreateFragment } from './MessageCreateFragment.generated'; - -const useStyles = makeStyles(theme => ({ - author: { - fontWeight: 'bold', - }, - container: { - display: 'flex', - }, - avatar: { - marginTop: 2, - }, - bubble: { - flex: 1, - marginLeft: theme.spacing(1), - minWidth: 0, - }, - header: { - ...theme.typography.body1, - color: '#444', - padding: '0.5rem 1rem', - borderBottom: '1px solid #ddd', - display: 'flex', - }, - title: { - flex: 1, - }, - tag: { - ...theme.typography.button, - color: '#888', - border: '#ddd solid 1px', - padding: '0 0.5rem', - fontSize: '0.75rem', - borderRadius: 2, - marginLeft: '0.5rem', - }, - body: { - ...theme.typography.body2, - padding: '0 1rem', - }, -})); - -type Props = { - op: AddCommentFragment | CreateFragment; -}; - -function Message({ op }: Props) { - const classes = useStyles(); - return ( - <article className={classes.container}> - <Avatar author={op.author} className={classes.avatar} /> - <Paper elevation={1} className={classes.bubble}> - <header className={classes.header}> - <div className={classes.title}> - <Author className={classes.author} author={op.author} /> - <span> commented </span> - <Date date={op.createdAt} /> - </div> - {op.edited && <div className={classes.tag}>Edited</div>} - </header> - <section className={classes.body}> - <Content markdown={op.message} /> - </section> - </Paper> - </article> - ); -} - -export default Message; diff --git a/webui/src/bug/MessageCommentFragment.graphql b/webui/src/bug/MessageCommentFragment.graphql deleted file mode 100644 index 61156fee..00000000 --- a/webui/src/bug/MessageCommentFragment.graphql +++ /dev/null @@ -1,8 +0,0 @@ -#import "../components/fragments.graphql" - -fragment AddComment on AddCommentTimelineItem { - createdAt - ...authored - edited - message -} diff --git a/webui/src/bug/MessageCreateFragment.graphql b/webui/src/bug/MessageCreateFragment.graphql deleted file mode 100644 index e371b9dc..00000000 --- a/webui/src/bug/MessageCreateFragment.graphql +++ /dev/null @@ -1,8 +0,0 @@ -#import "../components/fragments.graphql" - -fragment Create on CreateTimelineItem { - createdAt - ...authored - edited - message -} diff --git a/webui/src/bug/SetStatus.tsx b/webui/src/bug/SetStatus.tsx deleted file mode 100644 index 86105c8a..00000000 --- a/webui/src/bug/SetStatus.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { makeStyles } from '@material-ui/core/styles'; -import React from 'react'; - -import Author from '../components/Author'; -import Date from '../components/Date'; - -import { SetStatusFragment } from './SetStatusFragment.generated'; - -const useStyles = makeStyles(theme => ({ - main: { - ...theme.typography.body1, - marginLeft: theme.spacing(1) + 40, - }, -})); - -type Props = { - op: SetStatusFragment; -}; - -function SetStatus({ op }: Props) { - const classes = useStyles(); - return ( - <div className={classes.main}> - <Author author={op.author} bold /> - <span> {op.status.toLowerCase()} this</span> - <Date date={op.date} /> - </div> - ); -} - -export default SetStatus; diff --git a/webui/src/bug/SetStatusFragment.graphql b/webui/src/bug/SetStatusFragment.graphql deleted file mode 100644 index 5a3986d0..00000000 --- a/webui/src/bug/SetStatusFragment.graphql +++ /dev/null @@ -1,7 +0,0 @@ -#import "../components/fragments.graphql" - -fragment SetStatus on SetStatusTimelineItem { - date - ...authored - status -} diff --git a/webui/src/bug/SetTitle.tsx b/webui/src/bug/SetTitle.tsx deleted file mode 100644 index e57aaafb..00000000 --- a/webui/src/bug/SetTitle.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { makeStyles } from '@material-ui/core/styles'; -import React from 'react'; - -import Author from '../components/Author'; -import Date from '../components/Date'; - -import { SetTitleFragment } from './SetTitleFragment.generated'; - -const useStyles = makeStyles(theme => ({ - main: { - ...theme.typography.body1, - marginLeft: theme.spacing(1) + 40, - }, - bold: { - fontWeight: 'bold', - }, -})); - -type Props = { - op: SetTitleFragment; -}; - -function SetTitle({ op }: Props) { - const classes = useStyles(); - return ( - <div className={classes.main}> - <Author author={op.author} className={classes.bold} /> - <span> changed the title from </span> - <span className={classes.bold}>{op.was}</span> - <span> to </span> - <span className={classes.bold}>{op.title}</span> - <Date date={op.date} /> - </div> - ); -} - -export default SetTitle; diff --git a/webui/src/bug/SetTitleFragment.graphql b/webui/src/bug/SetTitleFragment.graphql deleted file mode 100644 index 22d2185c..00000000 --- a/webui/src/bug/SetTitleFragment.graphql +++ /dev/null @@ -1,8 +0,0 @@ -#import "../components/fragments.graphql" - -fragment SetTitle on SetTitleTimelineItem { - date - ...authored - title - was -} diff --git a/webui/src/bug/Timeline.tsx b/webui/src/bug/Timeline.tsx deleted file mode 100644 index ba0f9fc7..00000000 --- a/webui/src/bug/Timeline.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { makeStyles } from '@material-ui/core/styles'; -import React from 'react'; - -import LabelChange from './LabelChange'; -import Message from './Message'; -import SetStatus from './SetStatus'; -import SetTitle from './SetTitle'; -import { TimelineItemFragment } from './TimelineQuery.generated'; - -const useStyles = makeStyles(theme => ({ - main: { - '& > *:not(:last-child)': { - marginBottom: theme.spacing(2), - }, - }, -})); - -type Props = { - ops: Array<TimelineItemFragment>; -}; - -function Timeline({ ops }: Props) { - const classes = useStyles(); - - return ( - <div className={classes.main}> - {ops.map((op, index) => { - switch (op.__typename) { - case 'CreateTimelineItem': - return <Message key={index} op={op} />; - case 'AddCommentTimelineItem': - return <Message key={index} op={op} />; - case 'LabelChangeTimelineItem': - return <LabelChange key={index} op={op} />; - case 'SetTitleTimelineItem': - return <SetTitle key={index} op={op} />; - case 'SetStatusTimelineItem': - return <SetStatus key={index} op={op} />; - } - - console.warn('unsupported operation type ' + op.__typename); - return null; - })} - </div> - ); -} - -export default Timeline; diff --git a/webui/src/bug/TimelineQuery.graphql b/webui/src/bug/TimelineQuery.graphql deleted file mode 100644 index 6d78ab7f..00000000 --- a/webui/src/bug/TimelineQuery.graphql +++ /dev/null @@ -1,39 +0,0 @@ -#import "./MessageCreateFragment.graphql" -#import "./MessageCommentFragment.graphql" -#import "./LabelChangeFragment.graphql" -#import "./SetTitleFragment.graphql" -#import "./SetStatusFragment.graphql" - -query Timeline($id: String!, $first: Int = 10, $after: String) { - repository { - bug(prefix: $id) { - timeline(first: $first, after: $after) { - nodes { - ...TimelineItem - } - pageInfo { - hasNextPage - endCursor - } - } - } - } -} - -fragment TimelineItem on TimelineItem { - ... on LabelChangeTimelineItem { - ...LabelChange - } - ... on SetStatusTimelineItem { - ...SetStatus - } - ... on SetTitleTimelineItem { - ...SetTitle - } - ... on AddCommentTimelineItem { - ...AddComment - } - ... on CreateTimelineItem { - ...Create - } -} diff --git a/webui/src/bug/TimelineQuery.tsx b/webui/src/bug/TimelineQuery.tsx deleted file mode 100644 index 9c4cf183..00000000 --- a/webui/src/bug/TimelineQuery.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import CircularProgress from '@material-ui/core/CircularProgress'; -import React from 'react'; - -import Timeline from './Timeline'; -import { useTimelineQuery } from './TimelineQuery.generated'; - -type Props = { - id: string; -}; - -const TimelineQuery = ({ id }: Props) => { - const { loading, error, data } = useTimelineQuery({ - variables: { - id, - first: 100, - }, - }); - - if (loading) return <CircularProgress />; - if (error) return <p>Error: {error}</p>; - - const nodes = data?.repository?.bug?.timeline.nodes; - if (!nodes) { - return null; - } - - return <Timeline ops={nodes} />; -}; - -export default TimelineQuery; |