aboutsummaryrefslogtreecommitdiffstats
path: root/webui/src/bug
diff options
context:
space:
mode:
Diffstat (limited to 'webui/src/bug')
-rw-r--r--webui/src/bug/Bug.graphql14
-rw-r--r--webui/src/bug/Bug.tsx (renamed from webui/src/bug/Bug.js)30
-rw-r--r--webui/src/bug/BugQuery.graphql9
-rw-r--r--webui/src/bug/BugQuery.js30
-rw-r--r--webui/src/bug/BugQuery.tsx22
-rw-r--r--webui/src/bug/LabelChange.tsx (renamed from webui/src/bug/LabelChange.js)30
-rw-r--r--webui/src/bug/LabelChangeFragment.graphql13
-rw-r--r--webui/src/bug/Message.tsx (renamed from webui/src/bug/Message.js)41
-rw-r--r--webui/src/bug/MessageCommentFragment.graphql8
-rw-r--r--webui/src/bug/MessageCreateFragment.graphql8
-rw-r--r--webui/src/bug/SetStatus.tsx (renamed from webui/src/bug/SetStatus.js)24
-rw-r--r--webui/src/bug/SetStatusFragment.graphql7
-rw-r--r--webui/src/bug/SetTitle.tsx (renamed from webui/src/bug/SetTitle.js)25
-rw-r--r--webui/src/bug/SetTitleFragment.graphql8
-rw-r--r--webui/src/bug/Timeline.js43
-rw-r--r--webui/src/bug/Timeline.tsx48
-rw-r--r--webui/src/bug/TimelineQuery.graphql39
-rw-r--r--webui/src/bug/TimelineQuery.js53
-rw-r--r--webui/src/bug/TimelineQuery.tsx30
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;