webui: display label changes in the timeline + cleaning evrywhere

Michael Muré created

Change summary

webui/src/Author.js            | 24 +++++++++++++++++++
webui/src/Date.js              | 11 +++++++++
webui/src/Label.js             | 15 ++++++++++++
webui/src/bug/Bug.js           | 13 ++++-----
webui/src/bug/LabelChange.js   | 44 ++++++++++++++++++++++++++++++++++++
webui/src/bug/Message.js       | 23 ++++++------------
webui/src/bug/Timeline.js      |  7 ++++-
webui/src/bug/TimelineQuery.js |  5 +++
webui/src/list/BugRow.js       | 17 ++++---------
9 files changed, 122 insertions(+), 37 deletions(-)

Detailed changes

webui/src/Author.js 🔗

@@ -0,0 +1,24 @@
+import Tooltip from '@material-ui/core/Tooltip/Tooltip'
+import React from 'react'
+import { withStyles } from '@material-ui/core/styles'
+
+const styles = theme => ({
+  author: {
+    ...theme.typography.body2,
+  },
+  bold: {
+    fontWeight: 'bold'
+  }
+})
+
+const Author = ({author, bold, classes}) => {
+  const klass = bold ? [classes.author, classes.bold] : [classes.author]
+
+  return (
+    <Tooltip title={author.email}>
+      <span className={klass.join(' ')}>{author.name}</span>
+    </Tooltip>
+  )
+}
+
+export default withStyles(styles)(Author)

webui/src/Date.js 🔗

@@ -0,0 +1,11 @@
+import Tooltip from '@material-ui/core/Tooltip/Tooltip'
+import * as moment from 'moment'
+import React from 'react'
+
+const Date = ({date}) => (
+  <Tooltip title={moment(date).format('MMMM D, YYYY, h:mm a')}>
+    <span> {moment(date).fromNow()} </span>
+  </Tooltip>
+)
+
+export default Date

webui/src/Label.js 🔗

@@ -0,0 +1,15 @@
+import React from 'react'
+import { withStyles } from '@material-ui/core/styles'
+
+const styles = theme => ({
+  label: {
+    padding: '0 4px',
+    margin: '0 1px',
+    backgroundColor: '#da9898',
+    borderRadius: '3px'
+  },
+})
+
+const Label = ({label, classes}) => <span className={classes.label}>{label}</span>
+
+export default withStyles(styles)(Label)

webui/src/bug/Bug.js 🔗

@@ -1,9 +1,9 @@
 import { withStyles } from '@material-ui/core/styles'
-import Tooltip from '@material-ui/core/Tooltip/Tooltip'
 import Typography from '@material-ui/core/Typography/Typography'
 import gql from 'graphql-tag'
-import * as moment from 'moment'
 import React from 'react'
+import Author from '../Author'
+import Date from '../Date'
 import TimelineQuery from './TimelineQuery'
 
 const styles = theme => ({
@@ -21,7 +21,8 @@ const styles = theme => ({
     marginLeft: 15,
   },
   container: {
-    display: 'flex'
+    display: 'flex',
+    marginBottom: 30
   },
   timeline: {
     width: '70%',
@@ -47,11 +48,9 @@ const Bug = ({bug, classes}) => (
       <span className={classes.id}>{bug.humanId}</span>
 
       <Typography color={'textSecondary'}>
-        <Tooltip title={bug.author.email}><span>{bug.author.name}</span></Tooltip>
+        <Author author={bug.author}/>
         <span> opened this bug </span>
-        <Tooltip title={moment(bug.createdAt).format('MMMM D, YYYY, h:mm a')}>
-          <span> {moment(bug.createdAt).fromNow()} </span>
-        </Tooltip>
+        <Date date={bug.createdAt} />
       </Typography>
     </div>
 

webui/src/bug/LabelChange.js 🔗

@@ -0,0 +1,44 @@
+import { withStyles } from '@material-ui/core/styles'
+import gql from 'graphql-tag'
+import React from 'react'
+import Author from '../Author'
+import Date from '../Date'
+import Label from '../Label'
+
+const styles = theme => ({
+  main: {
+    ...theme.typography.body2
+  },
+})
+
+const LabelChange = ({op, classes}) => {
+  const {added, removed} = op
+  return (
+    <div className={classes.main}>
+      <Author author={op.author} bold />
+      { 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>
+  )
+}
+
+LabelChange.fragment = gql`
+  fragment LabelChange on Operation {
+    ... on LabelChangeOperation {
+      date
+      author {
+        name
+        email
+      }
+      added
+      removed
+    }
+  }
+`
+
+export default withStyles(styles)(LabelChange)

webui/src/bug/Message.js 🔗

@@ -1,9 +1,9 @@
 import { withStyles } from '@material-ui/core/styles'
-import Tooltip from '@material-ui/core/Tooltip/Tooltip'
 import Typography from '@material-ui/core/Typography'
 import gql from 'graphql-tag'
-import * as moment from 'moment'
 import React from 'react'
+import Author from '../Author'
+import Date from '../Date'
 
 const styles = theme => ({
   header: {
@@ -14,10 +14,6 @@ const styles = theme => ({
     borderTopLeftRadius: 3,
     borderTopRightRadius: 3,
   },
-  author: {
-    ...theme.typography.body2,
-    fontWeight: 'bold'
-  },
   message: {
     borderLeft: '1px solid #d1d5da',
     borderRight: '1px solid #d1d5da',
@@ -25,23 +21,20 @@ const styles = theme => ({
     borderBottomLeftRadius: 3,
     borderBottomRightRadius: 3,
     backgroundColor: '#fff',
-    minHeight: 50
+    minHeight: 50,
+    padding: 5,
   }
 })
 
-const Message = ({message, classes}) => (
+const Message = ({op, classes}) => (
   <div>
     <div className={classes.header}>
-      <Tooltip title={message.author.email}>
-        <span className={classes.author}>{message.author.name}</span>
-      </Tooltip>
+      <Author className={classes.author} author={op.author} bold />
       <span> commented </span>
-      <Tooltip title={moment(message.date).format('MMMM D, YYYY, h:mm a')}>
-        <span> {moment(message.date).fromNow()} </span>
-      </Tooltip>
+      <Date date={op.date} />
     </div>
     <div className={classes.message}>
-      <Typography>{message.message}</Typography>
+      <Typography>{op.message}</Typography>
     </div>
   </div>
 )

webui/src/bug/Timeline.js 🔗

@@ -1,5 +1,6 @@
 import { withStyles } from '@material-ui/core/styles'
 import React from 'react'
+import LabelChange from './LabelChange'
 import Message from './Message'
 
 const styles = theme => ({
@@ -26,9 +27,11 @@ class Timeline extends React.Component {
         { ops.map((op, index) => {
           switch (op.__typename) {
             case 'CreateOperation':
-              return <Message key={index} message={op}/>
+              return <Message key={index} op={op}/>
             case 'AddCommentOperation':
-              return <Message key={index} message={op}/>
+              return <Message key={index} op={op}/>
+            case 'LabelChangeOperation':
+              return <LabelChange key={index} op={op}/>
 
             default:
               console.log('unsupported operation type ' + op.__typename)

webui/src/bug/TimelineQuery.js 🔗

@@ -2,6 +2,7 @@ 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 Timeline from './Timeline'
 import Message from './Message'
 
@@ -13,6 +14,7 @@ const QUERY = gql`
           nodes {
             ...Create
             ...Comment
+            ...LabelChange
           }
           pageInfo {
             hasNextPage
@@ -24,10 +26,11 @@ const QUERY = gql`
   }
   ${Message.createFragment}
   ${Message.commentFragment}
+  ${LabelChange.fragment}
 `
 
 const TimelineQuery = ({id}) => (
-  <Query query={QUERY} variables={{id}}>
+  <Query query={QUERY} variables={{id, first: 100}}>
     {({loading, error, data, fetchMore}) => {
       if (loading) return <CircularProgress/>
       if (error) return <p>Error: {error}</p>

webui/src/list/BugRow.js 🔗

@@ -5,9 +5,10 @@ import Tooltip from '@material-ui/core/Tooltip/Tooltip'
 import Typography from '@material-ui/core/Typography'
 import ErrorOutline from '@material-ui/icons/ErrorOutline'
 import gql from 'graphql-tag'
-import * as moment from 'moment'
 import React from 'react'
 import { Link } from 'react-router-dom'
+import Date from '../Date'
+import Label from '../Label'
 
 const Open = ({className}) => <Tooltip title="Open">
   <ErrorOutline nativeColor='#28a745' className={className}/>
@@ -46,12 +47,6 @@ const styles = theme => ({
   labels: {
     display: 'inline-block',
     paddingLeft: theme.spacing.unit,
-    '&>span': {
-      padding: '0 4px',
-      margin: '0 1px',
-      backgroundColor: '#da9898',
-      borderRadius: '3px'
-    }
   }
 })
 
@@ -68,16 +63,14 @@ const BugRow = ({bug, classes}) => (
             </Typography>
             <span className={classes.labels}>
               {bug.labels.map(l => (
-                <span key={l}>{l}</span>)
-              )}
+                <Label key={l} label={l}/>
+              ))}
             </span>
           </div>
         </Link>
         <Typography color={'textSecondary'}>
           {bug.humanId} opened
-          <Tooltip title={moment(bug.createdAt).format('MMMM D, YYYY, h:mm a')}>
-            <span> {moment(bug.createdAt).fromNow()} </span>
-          </Tooltip>
+          <Date date={bug.createdAt} />
           by {bug.author.name}
         </Typography>
       </div>