diff options
Diffstat (limited to 'webui/src/bug')
19 files changed, 254 insertions, 228 deletions
diff --git a/webui/src/bug/Bug.graphql b/webui/src/bug/Bug.graphql new file mode 100644 index 00000000..112024aa --- /dev/null +++ b/webui/src/bug/Bug.graphql @@ -0,0 +1,14 @@ +#import "../Label.graphql" +#import "../Author.graphql" + +fragment Bug on Bug { + id + humanId + status + title + labels { + ...Label + } + createdAt + ...authored +} diff --git a/webui/src/bug/Bug.js b/webui/src/bug/Bug.tsx index 5a159f0f..f4029a5f 100644 --- a/webui/src/bug/Bug.js +++ b/webui/src/bug/Bug.tsx @@ -1,12 +1,14 @@ -import { makeStyles } from '@material-ui/styles'; import Typography from '@material-ui/core/Typography/Typography'; -import gql from 'graphql-tag'; +import { makeStyles } from '@material-ui/core/styles'; import React from 'react'; + import Author from '../Author'; import Date from '../Date'; -import TimelineQuery from './TimelineQuery'; import Label from '../Label'; +import { BugFragment } from './Bug.generated'; +import TimelineQuery from './TimelineQuery'; + const useStyles = makeStyles(theme => ({ main: { maxWidth: 800, @@ -51,7 +53,11 @@ const useStyles = makeStyles(theme => ({ }, })); -function Bug({ bug }) { +type Props = { + bug: BugFragment; +}; + +function Bug({ bug }: Props) { const classes = useStyles(); return ( <main className={classes.main}> @@ -85,20 +91,4 @@ function Bug({ bug }) { ); } -Bug.fragment = gql` - fragment Bug on Bug { - id - humanId - status - title - labels { - ...Label - } - createdAt - ...authored - } - ${Label.fragment} - ${Author.fragment} -`; - export default Bug; diff --git a/webui/src/bug/BugQuery.graphql b/webui/src/bug/BugQuery.graphql new file mode 100644 index 00000000..cdc4723f --- /dev/null +++ b/webui/src/bug/BugQuery.graphql @@ -0,0 +1,9 @@ +#import "./Bug.graphql" + +query GetBug($id: String!) { + repository { + bug(prefix: $id) { + ...Bug + } + } +} diff --git a/webui/src/bug/BugQuery.js b/webui/src/bug/BugQuery.js deleted file mode 100644 index dbf24c31..00000000 --- a/webui/src/bug/BugQuery.js +++ /dev/null @@ -1,30 +0,0 @@ -import CircularProgress from '@material-ui/core/CircularProgress'; -import gql from 'graphql-tag'; -import React from 'react'; -import { Query } from 'react-apollo'; - -import Bug from './Bug'; - -const QUERY = gql` - query GetBug($id: String!) { - defaultRepository { - bug(prefix: $id) { - ...Bug - } - } - } - - ${Bug.fragment} -`; - -const BugQuery = ({ match }) => ( - <Query query={QUERY} variables={{ id: match.params.id }}> - {({ loading, error, data }) => { - if (loading) return <CircularProgress />; - if (error) return <p>Error: {error}</p>; - return <Bug bug={data.defaultRepository.bug} />; - }} - </Query> -); - -export default BugQuery; diff --git a/webui/src/bug/BugQuery.tsx b/webui/src/bug/BugQuery.tsx new file mode 100644 index 00000000..2ecf718c --- /dev/null +++ b/webui/src/bug/BugQuery.tsx @@ -0,0 +1,22 @@ +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/LabelChange.js b/webui/src/bug/LabelChange.tsx index 4773e7eb..572579bd 100644 --- a/webui/src/bug/LabelChange.js +++ b/webui/src/bug/LabelChange.tsx @@ -1,10 +1,12 @@ -import { makeStyles } from '@material-ui/styles'; -import gql from 'graphql-tag'; +import { makeStyles } from '@material-ui/core/styles'; import React from 'react'; + import Author from '../Author'; import Date from '../Date'; import Label from '../Label'; +import { LabelChangeFragment } from './LabelChangeFragment.generated'; + const useStyles = makeStyles(theme => ({ main: { ...theme.typography.body1, @@ -15,7 +17,11 @@ const useStyles = makeStyles(theme => ({ }, })); -function LabelChange({ op }) { +type Props = { + op: LabelChangeFragment; +}; + +function LabelChange({ op }: Props) { const { added, removed } = op; const classes = useStyles(); return ( @@ -40,22 +46,4 @@ function LabelChange({ op }) { ); } -LabelChange.fragment = gql` - fragment LabelChange on TimelineItem { - ... on LabelChangeTimelineItem { - date - ...authored - added { - ...Label - } - removed { - ...Label - } - } - } - - ${Label.fragment} - ${Author.fragment} -`; - export default LabelChange; diff --git a/webui/src/bug/LabelChangeFragment.graphql b/webui/src/bug/LabelChangeFragment.graphql new file mode 100644 index 00000000..631de70c --- /dev/null +++ b/webui/src/bug/LabelChangeFragment.graphql @@ -0,0 +1,13 @@ +#import "../Author.graphql" +#import "../Label.graphql" + +fragment LabelChange on LabelChangeTimelineItem { + date + ...authored + added { + ...Label + } + removed { + ...Label + } +} diff --git a/webui/src/bug/Message.js b/webui/src/bug/Message.tsx index 06c12815..c8d0710d 100644 --- a/webui/src/bug/Message.js +++ b/webui/src/bug/Message.tsx @@ -1,11 +1,14 @@ -import { makeStyles } from '@material-ui/styles'; import Paper from '@material-ui/core/Paper'; -import gql from 'graphql-tag'; +import { makeStyles } from '@material-ui/core/styles'; import React from 'react'; + import Author from '../Author'; import { Avatar } from '../Author'; -import Date from '../Date'; import Content from '../Content'; +import Date from '../Date'; + +import { AddCommentFragment } from './MessageCommentFragment.generated'; +import { CreateFragment } from './MessageCreateFragment.generated'; const useStyles = makeStyles(theme => ({ author: { @@ -47,7 +50,11 @@ const useStyles = makeStyles(theme => ({ }, })); -function Message({ op }) { +type Props = { + op: AddCommentFragment | CreateFragment; +}; + +function Message({ op }: Props) { const classes = useStyles(); return ( <article className={classes.container}> @@ -69,30 +76,4 @@ function Message({ op }) { ); } -Message.createFragment = gql` - fragment Create on TimelineItem { - ... on CreateTimelineItem { - createdAt - ...authored - edited - message - } - } - - ${Author.fragment} -`; - -Message.commentFragment = gql` - fragment AddComment on TimelineItem { - ... on AddCommentTimelineItem { - createdAt - ...authored - edited - message - } - } - - ${Author.fragment} -`; - export default Message; diff --git a/webui/src/bug/MessageCommentFragment.graphql b/webui/src/bug/MessageCommentFragment.graphql new file mode 100644 index 00000000..38d626d0 --- /dev/null +++ b/webui/src/bug/MessageCommentFragment.graphql @@ -0,0 +1,8 @@ +#import "../Author.graphql" + +fragment AddComment on AddCommentTimelineItem { + createdAt + ...authored + edited + message +} diff --git a/webui/src/bug/MessageCreateFragment.graphql b/webui/src/bug/MessageCreateFragment.graphql new file mode 100644 index 00000000..08477470 --- /dev/null +++ b/webui/src/bug/MessageCreateFragment.graphql @@ -0,0 +1,8 @@ +#import "../Author.graphql" + +fragment Create on CreateTimelineItem { + createdAt + ...authored + edited + message +} diff --git a/webui/src/bug/SetStatus.js b/webui/src/bug/SetStatus.tsx index 070bbb8f..3e1a7989 100644 --- a/webui/src/bug/SetStatus.js +++ b/webui/src/bug/SetStatus.tsx @@ -1,9 +1,11 @@ -import { makeStyles } from '@material-ui/styles'; -import gql from 'graphql-tag'; +import { makeStyles } from '@material-ui/core/styles'; import React from 'react'; + import Author from '../Author'; import Date from '../Date'; +import { SetStatusFragment } from './SetStatusFragment.generated'; + const useStyles = makeStyles(theme => ({ main: { ...theme.typography.body1, @@ -11,7 +13,11 @@ const useStyles = makeStyles(theme => ({ }, })); -function SetStatus({ op }) { +type Props = { + op: SetStatusFragment; +}; + +function SetStatus({ op }: Props) { const classes = useStyles(); return ( <div className={classes.main}> @@ -22,16 +28,4 @@ function SetStatus({ op }) { ); } -SetStatus.fragment = gql` - fragment SetStatus on TimelineItem { - ... on SetStatusTimelineItem { - date - ...authored - status - } - } - - ${Author.fragment} -`; - export default SetStatus; diff --git a/webui/src/bug/SetStatusFragment.graphql b/webui/src/bug/SetStatusFragment.graphql new file mode 100644 index 00000000..0fdea01b --- /dev/null +++ b/webui/src/bug/SetStatusFragment.graphql @@ -0,0 +1,7 @@ +#import "../Author.graphql" + +fragment SetStatus on SetStatusTimelineItem { + date + ...authored + status +} diff --git a/webui/src/bug/SetTitle.js b/webui/src/bug/SetTitle.tsx index e4c30a8d..0b088e0b 100644 --- a/webui/src/bug/SetTitle.js +++ b/webui/src/bug/SetTitle.tsx @@ -1,9 +1,11 @@ -import { makeStyles } from '@material-ui/styles'; -import gql from 'graphql-tag'; +import { makeStyles } from '@material-ui/core/styles'; import React from 'react'; + import Author from '../Author'; import Date from '../Date'; +import { SetTitleFragment } from './SetTitleFragment.generated'; + const useStyles = makeStyles(theme => ({ main: { ...theme.typography.body1, @@ -14,7 +16,11 @@ const useStyles = makeStyles(theme => ({ }, })); -function SetTitle({ op }) { +type Props = { + op: SetTitleFragment; +}; + +function SetTitle({ op }: Props) { const classes = useStyles(); return ( <div className={classes.main}> @@ -28,17 +34,4 @@ function SetTitle({ op }) { ); } -SetTitle.fragment = gql` - fragment SetTitle on TimelineItem { - ... on SetTitleTimelineItem { - date - ...authored - title - was - } - } - - ${Author.fragment} -`; - export default SetTitle; diff --git a/webui/src/bug/SetTitleFragment.graphql b/webui/src/bug/SetTitleFragment.graphql new file mode 100644 index 00000000..432c4449 --- /dev/null +++ b/webui/src/bug/SetTitleFragment.graphql @@ -0,0 +1,8 @@ +#import "../Author.graphql" + +fragment SetTitle on SetTitleTimelineItem { + date + ...authored + title + was +} diff --git a/webui/src/bug/Timeline.js b/webui/src/bug/Timeline.js deleted file mode 100644 index 7d1946f2..00000000 --- a/webui/src/bug/Timeline.js +++ /dev/null @@ -1,43 +0,0 @@ -import { makeStyles } from '@material-ui/styles'; -import React from 'react'; -import LabelChange from './LabelChange'; -import Message from './Message'; -import SetStatus from './SetStatus'; -import SetTitle from './SetTitle'; - -const useStyles = makeStyles(theme => ({ - main: { - '& > *:not(:last-child)': { - marginBottom: theme.spacing(2), - }, - }, -})); - -const componentMap = { - CreateTimelineItem: Message, - AddCommentTimelineItem: Message, - LabelChangeTimelineItem: LabelChange, - SetTitleTimelineItem: SetTitle, - SetStatusTimelineItem: SetStatus, -}; - -function Timeline({ ops }) { - const classes = useStyles(); - - return ( - <div className={classes.main}> - {ops.map((op, index) => { - const Component = componentMap[op.__typename]; - - if (!Component) { - console.warn('unsupported operation type ' + op.__typename); - return null; - } - - return <Component key={index} op={op} />; - })} - </div> - ); -} - -export default Timeline; diff --git a/webui/src/bug/Timeline.tsx b/webui/src/bug/Timeline.tsx new file mode 100644 index 00000000..ba0f9fc7 --- /dev/null +++ b/webui/src/bug/Timeline.tsx @@ -0,0 +1,48 @@ +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 new file mode 100644 index 00000000..6d78ab7f --- /dev/null +++ b/webui/src/bug/TimelineQuery.graphql @@ -0,0 +1,39 @@ +#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.js b/webui/src/bug/TimelineQuery.js deleted file mode 100644 index ebb20f9d..00000000 --- a/webui/src/bug/TimelineQuery.js +++ /dev/null @@ -1,53 +0,0 @@ -import CircularProgress from '@material-ui/core/CircularProgress'; -import gql from 'graphql-tag'; -import React from 'react'; -import { Query } from 'react-apollo'; -import LabelChange from './LabelChange'; -import SetStatus from './SetStatus'; -import SetTitle from './SetTitle'; -import Timeline from './Timeline'; -import Message from './Message'; - -const QUERY = gql` - query($id: String!, $first: Int = 10, $after: String) { - defaultRepository { - bug(prefix: $id) { - timeline(first: $first, after: $after) { - nodes { - ...LabelChange - ...SetStatus - ...SetTitle - ...AddComment - ...Create - } - pageInfo { - hasNextPage - endCursor - } - } - } - } - } - ${Message.createFragment} - ${Message.commentFragment} - ${LabelChange.fragment} - ${SetTitle.fragment} - ${SetStatus.fragment} -`; - -const TimelineQuery = ({ id }) => ( - <Query query={QUERY} variables={{ id, first: 100 }}> - {({ loading, error, data, fetchMore }) => { - if (loading) return <CircularProgress />; - if (error) return <p>Error: {error}</p>; - return ( - <Timeline - ops={data.defaultRepository.bug.timeline.nodes} - fetchMore={fetchMore} - /> - ); - }} - </Query> -); - -export default TimelineQuery; diff --git a/webui/src/bug/TimelineQuery.tsx b/webui/src/bug/TimelineQuery.tsx new file mode 100644 index 00000000..9c4cf183 --- /dev/null +++ b/webui/src/bug/TimelineQuery.tsx @@ -0,0 +1,30 @@ +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; |