webui: finish TypeScript conversion

ludovicm67 created

Change summary

webui/codegen.yaml                           | 16 +++---
webui/src/.gitignore                         |  2 
webui/src/Author.tsx                         |  6 ++
webui/src/bug/LabelChange.tsx                |  9 +++
webui/src/bug/LabelChangeFragment.graphql    | 18 +++----
webui/src/bug/Message.tsx                    | 10 +++
webui/src/bug/MessageCommentFragment.graphql | 12 ++---
webui/src/bug/MessageCreateFragment.graphql  | 12 ++---
webui/src/bug/SetStatus.tsx                  |  9 +++
webui/src/bug/SetStatusFragment.graphql      | 10 +--
webui/src/bug/SetTitle.tsx                   |  9 +++
webui/src/bug/SetTitleFragment.graphql       | 12 ++---
webui/src/bug/Timeline.js                    | 44 --------------------
webui/src/bug/Timeline.tsx                   | 48 ++++++++++++++++++++++
webui/src/bug/TimelineQuery.graphql          | 24 ++++++++--
webui/src/bug/TimelineQuery.tsx              | 18 +++++--
16 files changed, 150 insertions(+), 109 deletions(-)

Detailed changes

webui/codegen.yaml 🔗

@@ -2,22 +2,22 @@ schema: '../graphql/schema/*.graphql'
 overwrite: true
 documents: src/**/*.graphql
 generates:
-  ./src/fragmentTypes.js:
+  ./src/fragmentTypes.ts:
     plugins:
-    - fragment-matcher
+      - fragment-matcher
     config:
       module: es2015
   ./src/gqlTypes.ts:
     plugins:
-    - typescript
+      - typescript
   ./src/schema.json:
     plugins:
-    - introspection
+      - introspection
   ./src/:
     plugins:
-    - add: '/* eslint-disable @typescript-eslint/no-unused-vars, import/order */'
-    - typescript-operations
-    - typescript-react-apollo
+      - add: '/* eslint-disable @typescript-eslint/no-unused-vars, import/order */'
+      - typescript-operations
+      - typescript-react-apollo
     preset: near-operation-file
     presetConfig:
       extension: .generated.tsx
@@ -29,4 +29,4 @@ generates:
 
 hooks:
   afterAllFileWrite:
-  - prettier --write
+    - prettier --write

webui/src/Author.tsx 🔗

@@ -4,7 +4,11 @@ import React from 'react';
 
 import { AuthoredFragment } from './Author.generated';
 
-type Props = AuthoredFragment;
+type Props = AuthoredFragment & {
+  className?: string;
+  bold?: boolean;
+};
+
 const Author = ({ author, ...props }: Props) => {
   if (!author.email) {
     return <span {...props}>{author.displayName}</span>;

webui/src/bug/LabelChange.js → webui/src/bug/LabelChange.tsx 🔗

@@ -1,9 +1,10 @@
-import { makeStyles } from '@material-ui/styles';
+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: {
@@ -15,7 +16,11 @@ const useStyles = makeStyles(theme => ({
   },
 }));
 
-function LabelChange({ op }) {
+type Props = {
+  op: LabelChangeFragment;
+};
+
+function LabelChange({ op }: Props) {
   const { added, removed } = op;
   const classes = useStyles();
   return (

webui/src/bug/LabelChangeFragment.graphql 🔗

@@ -1,15 +1,13 @@
 #import "../Author.graphql"
 #import "../Label.graphql"
 
-fragment LabelChange on TimelineItem {
-  ... on LabelChangeTimelineItem {
-    date
-    ...authored
-    added {
-      ...Label
-    }
-    removed {
-      ...Label
-    }
+fragment LabelChange on LabelChangeTimelineItem {
+  date
+  ...authored
+  added {
+    ...Label
+  }
+  removed {
+    ...Label
   }
 }

webui/src/bug/Message.js → webui/src/bug/Message.tsx 🔗

@@ -1,11 +1,13 @@
 import Paper from '@material-ui/core/Paper';
-import { makeStyles } from '@material-ui/styles';
+import { makeStyles } from '@material-ui/core/styles';
 import React from 'react';
 
 import Author from '../Author';
 import { Avatar } from '../Author';
 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 +49,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}>

webui/src/bug/MessageCommentFragment.graphql 🔗

@@ -1,10 +1,8 @@
 #import "../Author.graphql"
 
-fragment AddComment on TimelineItem {
-  ... on AddCommentTimelineItem {
-    createdAt
-    ...authored
-    edited
-    message
-  }
+fragment AddComment on AddCommentTimelineItem {
+  createdAt
+  ...authored
+  edited
+  message
 }

webui/src/bug/MessageCreateFragment.graphql 🔗

@@ -1,10 +1,8 @@
 #import "../Author.graphql"
 
-fragment Create on TimelineItem {
-  ... on CreateTimelineItem {
-    createdAt
-    ...authored
-    edited
-    message
-  }
+fragment Create on CreateTimelineItem {
+  createdAt
+  ...authored
+  edited
+  message
 }

webui/src/bug/SetStatus.js → webui/src/bug/SetStatus.tsx 🔗

@@ -1,8 +1,9 @@
-import { makeStyles } from '@material-ui/styles';
+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: {
@@ -11,7 +12,11 @@ const useStyles = makeStyles(theme => ({
   },
 }));
 
-function SetStatus({ op }) {
+type Props = {
+  op: SetStatusFragment;
+};
+
+function SetStatus({ op }: Props) {
   const classes = useStyles();
   return (
     <div className={classes.main}>

webui/src/bug/SetStatusFragment.graphql 🔗

@@ -1,9 +1,7 @@
 #import "../Author.graphql"
 
-fragment SetStatus on TimelineItem {
-  ... on SetStatusTimelineItem {
-    date
-    ...authored
-    status
-  }
+fragment SetStatus on SetStatusTimelineItem {
+  date
+  ...authored
+  status
 }

webui/src/bug/SetTitle.js → webui/src/bug/SetTitle.tsx 🔗

@@ -1,8 +1,9 @@
-import { makeStyles } from '@material-ui/styles';
+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: {
@@ -14,7 +15,11 @@ const useStyles = makeStyles(theme => ({
   },
 }));
 
-function SetTitle({ op }) {
+type Props = {
+  op: SetTitleFragment;
+};
+
+function SetTitle({ op }: Props) {
   const classes = useStyles();
   return (
     <div className={classes.main}>

webui/src/bug/SetTitleFragment.graphql 🔗

@@ -1,10 +1,8 @@
 #import "../Author.graphql"
 
-fragment SetTitle on TimelineItem {
-  ... on SetTitleTimelineItem {
-    date
-    ...authored
-    title
-    was
-  }
+fragment SetTitle on SetTitleTimelineItem {
+  date
+  ...authored
+  title
+  was
 }

webui/src/bug/Timeline.js 🔗

@@ -1,44 +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;

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;

webui/src/bug/TimelineQuery.graphql 🔗

@@ -9,11 +9,7 @@ query Timeline($id: String!, $first: Int = 10, $after: String) {
     bug(prefix: $id) {
       timeline(first: $first, after: $after) {
         nodes {
-          ...LabelChange
-          ...SetStatus
-          ...SetTitle
-          ...AddComment
-          ...Create
+          ...TimelineItem
         }
         pageInfo {
           hasNextPage
@@ -23,3 +19,21 @@ query Timeline($id: String!, $first: Int = 10, $after: String) {
     }
   }
 }
+
+fragment TimelineItem on TimelineItem {
+  ... on LabelChangeTimelineItem {
+    ...LabelChange
+  }
+  ... on SetStatusTimelineItem {
+    ...SetStatus
+  }
+  ... on SetTitleTimelineItem {
+    ...SetTitle
+  }
+  ... on AddCommentTimelineItem {
+    ...AddComment
+  }
+  ... on CreateTimelineItem {
+    ...Create
+  }
+}

webui/src/bug/TimelineQuery.js → webui/src/bug/TimelineQuery.tsx 🔗

@@ -4,8 +4,12 @@ import React from 'react';
 import Timeline from './Timeline';
 import { useTimelineQuery } from './TimelineQuery.generated';
 
-const TimelineQuery = ({ id }) => {
-  const { loading, error, data, fetchMore } = useTimelineQuery({
+type Props = {
+  id: string;
+};
+
+const TimelineQuery = ({ id }: Props) => {
+  const { loading, error, data } = useTimelineQuery({
     variables: {
       id,
       first: 100,
@@ -14,9 +18,13 @@ const TimelineQuery = ({ id }) => {
 
   if (loading) return <CircularProgress />;
   if (error) return <p>Error: {error}</p>;
-  return (
-    <Timeline ops={data.repository.bug.timeline.nodes} fetchMore={fetchMore} />
-  );
+
+  const nodes = data?.repository?.bug?.timeline.nodes;
+  if (!nodes) {
+    return null;
+  }
+
+  return <Timeline ops={nodes} />;
 };
 
 export default TimelineQuery;