From c57174f392dbfb64aaf31533b01da70f69621720 Mon Sep 17 00:00:00 2001 From: biboswan Date: Thu, 24 Jan 2019 03:36:31 +0530 Subject: [PATCH 01/14] Initial display of lastfire fires --- src/components/HookForm/index.jsx | 123 +++++++++--------- .../Hooks/ViewHook/hookLastFires.graphql | 9 ++ src/views/Hooks/ViewHook/index.jsx | 48 ++++--- 3 files changed, 106 insertions(+), 74 deletions(-) create mode 100644 src/views/Hooks/ViewHook/hookLastFires.graphql diff --git a/src/components/HookForm/index.jsx b/src/components/HookForm/index.jsx index cc800b6c..20d0d9fd 100644 --- a/src/components/HookForm/index.jsx +++ b/src/components/HookForm/index.jsx @@ -1,6 +1,5 @@ import React, { Component, Fragment } from 'react'; -import { Link } from 'react-router-dom'; -import { string, bool, func, oneOfType, object } from 'prop-types'; +import { string, bool, func, oneOfType, object, array } from 'prop-types'; import classNames from 'classnames'; import { equals, assocPath } from 'ramda'; import cloneDeep from 'lodash.clonedeep'; @@ -11,6 +10,10 @@ import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import ListItemText from '@material-ui/core/ListItemText'; import ListSubheader from '@material-ui/core/ListSubheader'; +import ExpansionPanel from '@material-ui/core/ExpansionPanel'; +import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails'; +import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import TextField from '@material-ui/core/TextField'; import Switch from '@material-ui/core/Switch'; import FormGroup from '@material-ui/core/FormGroup'; @@ -21,15 +24,14 @@ import Typography from '@material-ui/core/Typography'; import FlashIcon from 'mdi-react/FlashIcon'; import PlusIcon from 'mdi-react/PlusIcon'; import DeleteIcon from 'mdi-react/DeleteIcon'; -import LinkIcon from 'mdi-react/LinkIcon'; import ContentSaveIcon from 'mdi-react/ContentSaveIcon'; import { docs } from 'taskcluster-lib-urls'; +import ErrorPanel from '../ErrorPanel'; import Button from '../Button'; import SpeedDial from '../SpeedDial'; import SpeedDialAction from '../SpeedDialAction'; import DialogAction from '../DialogAction'; import DateDistance from '../DateDistance'; -import { HOOKS_LAST_FIRE_TYPE } from '../../utils/constants'; import { hook } from '../../utils/prop-types'; import removeKeys from '../../utils/removeKeys'; @@ -120,6 +122,7 @@ export default class HookForm extends Component { static defaultProps = { isNewHook: false, hook: initialHook, + hookLastFires: null, onTriggerHook: null, onCreateHook: null, onUpdateHook: null, @@ -131,6 +134,8 @@ export default class HookForm extends Component { static propTypes = { /** A GraphQL hook response. Not needed when creating a new hook */ hook: hook.isRequired, + /** Object */ + hookLastFires: array, /** Set to `true` when creating a new hook. */ isNewHook: bool, /** Callback function fired when a hook is triggered. */ @@ -153,6 +158,8 @@ export default class HookForm extends Component { state = { hook: null, + hookLastFires: null, + lastFirePanelExpanded: '', // eslint-disable-next-line react/no-unused-state previousHook: null, taskInput: '', @@ -165,7 +172,10 @@ export default class HookForm extends Component { }; static getDerivedStateFromProps(props, state) { - if (equals(props.hook, state.previousHook)) { + if ( + equals(props.hook, state.previousHook) && + equals(props.hookLastFires, state.hookLastFires) + ) { return null; } @@ -173,6 +183,7 @@ export default class HookForm extends Component { return { hook: props.hook, + hookLastFires: props.hookLastFires, previousHook: props.hook, taskInput: JSON.stringify( removeKeys(cloneDeep(hook.task), ['__typename']), @@ -395,6 +406,12 @@ export default class HookForm extends Component { ), }); + handleLastFirePanelChange = panel => (event, expanded) => { + this.setState({ + lastFirePanelExpanded: expanded ? panel : false, + }); + }; + render() { const { actionLoading, @@ -412,10 +429,11 @@ export default class HookForm extends Component { triggerSchemaInput, triggerContextInput, hook, + hookLastFires, validation, + lastFirePanelExpanded, } = this.state; /* eslint-disable-next-line no-underscore-dangle */ - const lastFireTypeName = !isNewHook && hook.status.lastFire.__typename; return ( @@ -508,62 +526,49 @@ export default class HookForm extends Component { /> - {!isNewHook && ( - - - - ) - } - /> - - {lastFireTypeName === HOOKS_LAST_FIRE_TYPE.SUCCESSFUL_FIRE ? ( - - - - - ) : ( - - - {JSON.stringify(hook.status.lastFire.error, null, 2)} - - ) - } - /> - - )} - + + {hookLastFires ? ( + - ) : ( - 'n/a' - ) + primary={ + + Last Fired Hooks + } /> - - - )} + {hookLastFires.map( + ({ taskId, taskCreateTime, result, error }) => ( + + + }> + + {taskId} + + + {result} + + + + + + + + {' '} + + + + ) + )} + + ) : ( + '' + )} + !params.hookId, - options: ({ match: { params } }) => ({ - variables: { - hookGroupId: params.hookGroupId, - hookId: decodeURIComponent(params.hookId), - }, +@compose( + graphql(hookLastFiresQuery, { + skip: ({ match: { params } }) => !params.hookId, + options: ({ match: { params } }) => ({ + variables: { + hookGroupId: params.hookGroupId, + hookId: decodeURIComponent(params.hookId), + }, + }), + name: 'lastFiresData', }), -}) + graphql(hookQuery, { + skip: ({ match: { params } }) => !params.hookId, + options: ({ match: { params } }) => ({ + variables: { + hookGroupId: params.hookGroupId, + hookId: decodeURIComponent(params.hookId), + }, + }), + name: 'hookData', + }) +) export default class ViewHook extends Component { state = { actionLoading: false, @@ -128,13 +142,13 @@ export default class ViewHook extends Component { }; render() { - const { isNewHook, data } = this.props; + const { isNewHook, hookData, lastFiresData } = this.props; const { error: err, dialogError, actionLoading, dialogOpen } = this.state; - const error = (data && data.error) || err; + const hookDataError = (hookData && hookData.error) || err; return ( - + {isNewHook ? ( ) : ( - {!data.hook && data.loading && } - {data.hook && ( + {!hookData.hook && hookData.loading && } + {hookData.hook && ( + new Date(b.taskCreateTime) - new Date(a.taskCreateTime) + )} dialogOpen={dialogOpen} onTriggerHook={this.handleTriggerHook} onUpdateHook={this.handleUpdateHook} From 7a33df86b6f4a972ff7ec612affb9d337bd5d569 Mon Sep 17 00:00:00 2001 From: biboswan Date: Fri, 25 Jan 2019 00:37:30 +0530 Subject: [PATCH 02/14] Improve responsiveness and overall ui with Grid --- src/components/HookForm/index.jsx | 95 +++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 25 deletions(-) diff --git a/src/components/HookForm/index.jsx b/src/components/HookForm/index.jsx index 20d0d9fd..61ccd988 100644 --- a/src/components/HookForm/index.jsx +++ b/src/components/HookForm/index.jsx @@ -1,4 +1,5 @@ import React, { Component, Fragment } from 'react'; +import { Link } from 'react-router-dom'; import { string, bool, func, oneOfType, object, array } from 'prop-types'; import classNames from 'classnames'; import { equals, assocPath } from 'ramda'; @@ -26,6 +27,7 @@ import PlusIcon from 'mdi-react/PlusIcon'; import DeleteIcon from 'mdi-react/DeleteIcon'; import ContentSaveIcon from 'mdi-react/ContentSaveIcon'; import { docs } from 'taskcluster-lib-urls'; +import Label from '@mozilla-frontend-infra/components/Label'; import ErrorPanel from '../ErrorPanel'; import Button from '../Button'; import SpeedDial from '../SpeedDial'; @@ -116,6 +118,12 @@ const initialHook = { subheader: { fontSize: theme.typography.pxToRem(16), }, + hookLastFires: { + width: '100%', + }, + scrollX: { + overflowX: 'scroll', + }, })) /** A form to view/edit/create a hook */ export default class HookForm extends Component { @@ -528,39 +536,62 @@ export default class HookForm extends Component { {hookLastFires ? ( - + - Last Fired Hooks + Last Hook Fire Attempts } /> {hookLastFires.map( - ({ taskId, taskCreateTime, result, error }) => ( + ({ taskId, taskCreateTime, firedBy, result, error }) => ( - - }> - - {taskId} - - - {result} - - - - - - - - {' '} - - + + + +
{firedBy}
+
+ +
+                              
+                            
+
+
+ + + }> + + + {(result === 'SUCCESS' && ( + + {taskId} + + )) || {taskId}} + + + + + + + + + + + +
) )} @@ -569,6 +600,20 @@ export default class HookForm extends Component { '' )}
+ {!isNewHook && ( + + + ) : ( + 'n/a' + ) + } + /> + + )} Date: Fri, 25 Jan 2019 00:53:14 +0530 Subject: [PATCH 03/14] Remove unwanted class --- src/components/HookForm/index.jsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/HookForm/index.jsx b/src/components/HookForm/index.jsx index 61ccd988..7274c530 100644 --- a/src/components/HookForm/index.jsx +++ b/src/components/HookForm/index.jsx @@ -121,9 +121,6 @@ const initialHook = { hookLastFires: { width: '100%', }, - scrollX: { - overflowX: 'scroll', - }, })) /** A form to view/edit/create a hook */ export default class HookForm extends Component { From a154a505ff48900e2fb071398797db341ee3f289 Mon Sep 17 00:00:00 2001 From: biboswan Date: Fri, 25 Jan 2019 18:36:41 +0530 Subject: [PATCH 04/14] Merge two hook graphql queries into one --- src/components/HookForm/index.jsx | 6 ++- src/views/Hooks/ViewHook/hook.graphql | 7 +++ .../Hooks/ViewHook/hookLastFires.graphql | 9 ---- src/views/Hooks/ViewHook/index.jsx | 46 +++++++------------ 4 files changed, 27 insertions(+), 41 deletions(-) delete mode 100644 src/views/Hooks/ViewHook/hookLastFires.graphql diff --git a/src/components/HookForm/index.jsx b/src/components/HookForm/index.jsx index 7274c530..21e22d79 100644 --- a/src/components/HookForm/index.jsx +++ b/src/components/HookForm/index.jsx @@ -137,9 +137,11 @@ export default class HookForm extends Component { }; static propTypes = { - /** A GraphQL hook response. Not needed when creating a new hook */ + /** Part of a GraphQL hook response containing info about that hook. + Not needed when creating a new hook */ hook: hook.isRequired, - /** Object */ + /** Part of the same Grahql hook response as above containing info + about some last hook fired attempts */ hookLastFires: array, /** Set to `true` when creating a new hook. */ isNewHook: bool, diff --git a/src/views/Hooks/ViewHook/hook.graphql b/src/views/Hooks/ViewHook/hook.graphql index 8db5474c..52d42ae2 100644 --- a/src/views/Hooks/ViewHook/hook.graphql +++ b/src/views/Hooks/ViewHook/hook.graphql @@ -45,5 +45,12 @@ query Hook($hookGroupId: ID!, $hookId: ID!) { tags extra } + }, + hookLastFires(hookGroupId: $hookGroupId, hookId: $hookId) { + taskId + firedBy + taskCreateTime + result + error } } diff --git a/src/views/Hooks/ViewHook/hookLastFires.graphql b/src/views/Hooks/ViewHook/hookLastFires.graphql deleted file mode 100644 index 2ca70c86..00000000 --- a/src/views/Hooks/ViewHook/hookLastFires.graphql +++ /dev/null @@ -1,9 +0,0 @@ -query HookLastFires($hookGroupId: ID!, $hookId: ID!) { - hookLastFires(hookGroupId: $hookGroupId, hookId: $hookId) { - taskId - firedBy - taskCreateTime - result - error - } -} \ No newline at end of file diff --git a/src/views/Hooks/ViewHook/index.jsx b/src/views/Hooks/ViewHook/index.jsx index ddbbe41c..c293e082 100644 --- a/src/views/Hooks/ViewHook/index.jsx +++ b/src/views/Hooks/ViewHook/index.jsx @@ -1,6 +1,6 @@ import { hot } from 'react-hot-loader'; import React, { Component, Fragment } from 'react'; -import { graphql, withApollo, compose } from 'react-apollo'; +import { graphql, withApollo } from 'react-apollo'; import Spinner from '@mozilla-frontend-infra/components/Spinner'; import Dashboard from '../../../components/Dashboard'; import HookForm from '../../../components/HookForm'; @@ -10,32 +10,18 @@ import createHookQuery from './createHook.graphql'; import deleteHookQuery from './deleteHook.graphql'; import updateHookQuery from './updateHook.graphql'; import triggerHookQuery from './triggerHook.graphql'; -import hookLastFiresQuery from './hookLastFires.graphql'; @hot(module) @withApollo -@compose( - graphql(hookLastFiresQuery, { - skip: ({ match: { params } }) => !params.hookId, - options: ({ match: { params } }) => ({ - variables: { - hookGroupId: params.hookGroupId, - hookId: decodeURIComponent(params.hookId), - }, - }), - name: 'lastFiresData', +@graphql(hookQuery, { + skip: ({ match: { params } }) => !params.hookId, + options: ({ match: { params } }) => ({ + variables: { + hookGroupId: params.hookGroupId, + hookId: decodeURIComponent(params.hookId), + }, }), - graphql(hookQuery, { - skip: ({ match: { params } }) => !params.hookId, - options: ({ match: { params } }) => ({ - variables: { - hookGroupId: params.hookGroupId, - hookId: decodeURIComponent(params.hookId), - }, - }), - name: 'hookData', - }) -) +}) export default class ViewHook extends Component { state = { actionLoading: false, @@ -142,13 +128,13 @@ export default class ViewHook extends Component { }; render() { - const { isNewHook, hookData, lastFiresData } = this.props; + const { isNewHook, data } = this.props; const { error: err, dialogError, actionLoading, dialogOpen } = this.state; - const hookDataError = (hookData && hookData.error) || err; + const error = (data && data.error) || err; return ( - + {isNewHook ? ( ) : ( - {!hookData.hook && hookData.loading && } - {hookData.hook && ( + {!data.hook && data.loading && } + {data.hook && ( new Date(b.taskCreateTime) - new Date(a.taskCreateTime) )} From f55678d6d32eac6236fffdb62090716b273d8c88 Mon Sep 17 00:00:00 2001 From: biboswan Date: Sat, 26 Jan 2019 01:24:28 +0530 Subject: [PATCH 05/14] Replace expansion panel with datatable --- src/components/HookForm/index.jsx | 133 +++++++++++++----------------- 1 file changed, 56 insertions(+), 77 deletions(-) diff --git a/src/components/HookForm/index.jsx b/src/components/HookForm/index.jsx index 21e22d79..ddf8183a 100644 --- a/src/components/HookForm/index.jsx +++ b/src/components/HookForm/index.jsx @@ -11,10 +11,8 @@ import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import ListItemText from '@material-ui/core/ListItemText'; import ListSubheader from '@material-ui/core/ListSubheader'; -import ExpansionPanel from '@material-ui/core/ExpansionPanel'; -import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails'; -import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import TableRow from '@material-ui/core/TableRow'; +import TableCell from '@material-ui/core/TableCell'; import TextField from '@material-ui/core/TextField'; import Switch from '@material-ui/core/Switch'; import FormGroup from '@material-ui/core/FormGroup'; @@ -29,6 +27,7 @@ import ContentSaveIcon from 'mdi-react/ContentSaveIcon'; import { docs } from 'taskcluster-lib-urls'; import Label from '@mozilla-frontend-infra/components/Label'; import ErrorPanel from '../ErrorPanel'; +import DataTable from '../DataTable'; import Button from '../Button'; import SpeedDial from '../SpeedDial'; import SpeedDialAction from '../SpeedDialAction'; @@ -118,8 +117,16 @@ const initialHook = { subheader: { fontSize: theme.typography.pxToRem(16), }, - hookLastFires: { - width: '100%', + displayBlock: { + display: 'block', + }, + errorTableCell: { + whiteSpace: 'normal', + }, + errorPanel: { + maxHeight: '300px', + maxWidth: '75ch', + overflowY: 'scroll', }, })) /** A form to view/edit/create a hook */ @@ -166,7 +173,6 @@ export default class HookForm extends Component { state = { hook: null, hookLastFires: null, - lastFirePanelExpanded: '', // eslint-disable-next-line react/no-unused-state previousHook: null, taskInput: '', @@ -413,12 +419,6 @@ export default class HookForm extends Component { ), }); - handleLastFirePanelChange = panel => (event, expanded) => { - this.setState({ - lastFirePanelExpanded: expanded ? panel : false, - }); - }; - render() { const { actionLoading, @@ -438,7 +438,6 @@ export default class HookForm extends Component { hook, hookLastFires, validation, - lastFirePanelExpanded, } = this.state; /* eslint-disable-next-line no-underscore-dangle */ @@ -533,70 +532,50 @@ export default class HookForm extends Component { /> - - {hookLastFires ? ( - - - Last Hook Fire Attempts - - } - /> - {hookLastFires.map( - ({ taskId, taskCreateTime, firedBy, result, error }) => ( - - - - -
{firedBy}
-
- -
-                              
-                            
-
-
- - - }> - - - {(result === 'SUCCESS' && ( - - {taskId} - - )) || {taskId}} - - - - - - - - - - - -
-
- ) + + + Last Hook Fire Attempts + + } + /> + {hookLastFires && ( + ( + + + {(hookFire.result === 'SUCCESS' && ( + + {hookFire.taskId} + + )) || {hookFire.taskId}} + + + {hookFire.firedBy} + + + + + + + + + {(hookFire.result === 'ERROR' && ( + + )) || N/A} + + )} -
- ) : ( - '' + /> )}
{!isNewHook && ( From c5f5a16599d325ba7b509ef3f7d26a27d89d0aa2 Mon Sep 17 00:00:00 2001 From: biboswan Date: Thu, 7 Feb 2019 00:42:17 +0530 Subject: [PATCH 06/14] Add pagination --- src/components/DataTable/index.jsx | 43 +++++++++++++++++++++++++++++- src/components/HookForm/index.jsx | 29 +++++++++++++++----- 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/components/DataTable/index.jsx b/src/components/DataTable/index.jsx index bb7c9fb5..398f2d5c 100644 --- a/src/components/DataTable/index.jsx +++ b/src/components/DataTable/index.jsx @@ -7,6 +7,7 @@ import { oneOf, oneOfType, object, + bool, } from 'prop-types'; import Table from '@material-ui/core/Table'; import TableBody from '@material-ui/core/TableBody'; @@ -14,6 +15,7 @@ import TableCell from '@material-ui/core/TableCell'; import TableHead from '@material-ui/core/TableHead'; import TableSortLabel from '@material-ui/core/TableSortLabel'; import TableRow from '@material-ui/core/TableRow'; +import TablePagination from '@material-ui/core/TablePagination'; /** * A table to display a set of data elements. @@ -26,6 +28,12 @@ export default class DataTable extends Component { sortByHeader: null, sortDirection: 'desc', noItemsMessage: 'No items for this page.', + isPaginate: false, + }; + + state = { + page: 0, + rowsPerPage: 10, }; static propTypes = { @@ -66,6 +74,10 @@ export default class DataTable extends Component { * A message to display when there is no items to display. */ noItemsMessage: string, + /** + * Whether to paginate the table + */ + isPaginate: bool, }; handleHeaderClick = ({ target }) => { @@ -76,6 +88,14 @@ export default class DataTable extends Component { } }; + handleChangePage = (event, page) => { + this.setState({ page }); + }; + + handleChangeRowsPerPage = event => { + this.setState({ rowsPerPage: event.target.value }); + }; + render() { const { items, @@ -85,8 +105,10 @@ export default class DataTable extends Component { sortByHeader, sortDirection, noItemsMessage, + isPaginate, } = this.props; const colSpan = columnsSize || (headers && headers.length) || 0; + const { page, rowsPerPage } = this.state; return ( @@ -115,9 +137,28 @@ export default class DataTable extends Component { ) : ( - items.map(renderRow) + items + .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) + .map(renderRow) )} + {isPaginate && ( + + )}
); } diff --git a/src/components/HookForm/index.jsx b/src/components/HookForm/index.jsx index ddf8183a..8b3502e8 100644 --- a/src/components/HookForm/index.jsx +++ b/src/components/HookForm/index.jsx @@ -6,6 +6,10 @@ import { equals, assocPath } from 'ramda'; import cloneDeep from 'lodash.clonedeep'; import CodeEditor from '@mozilla-frontend-infra/components/CodeEditor'; import Code from '@mozilla-frontend-infra/components/Code'; +import ExpansionPanel from '@material-ui/core/ExpansionPanel'; +import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary'; +import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import { withStyles } from '@material-ui/core/styles'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; @@ -184,6 +188,8 @@ export default class HookForm extends Component { validation: {}, }; + expandsionSummary = React.createRef(); + static getDerivedStateFromProps(props, state) { if ( equals(props.hook, state.previousHook) && @@ -439,8 +445,8 @@ export default class HookForm extends Component { hookLastFires, validation, } = this.state; - /* eslint-disable-next-line no-underscore-dangle */ + /* eslint-disable-next-line no-underscore-dangle */ return ( @@ -544,6 +550,7 @@ export default class HookForm extends Component { ( @@ -566,11 +573,21 @@ export default class HookForm extends Component { {(hookFire.result === 'ERROR' && ( - + + }> + + Show/Hide + + + + + + )) || N/A} From 87993e385172e8db6671fde11ca381a105a1061d Mon Sep 17 00:00:00 2001 From: biboswan Date: Fri, 15 Feb 2019 17:29:05 +0530 Subject: [PATCH 07/14] minor fix --- src/components/HookForm/index.jsx | 2 +- src/views/Hooks/ViewHook/index.jsx | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/HookForm/index.jsx b/src/components/HookForm/index.jsx index 8b3502e8..1b5c9b74 100644 --- a/src/components/HookForm/index.jsx +++ b/src/components/HookForm/index.jsx @@ -588,7 +588,7 @@ export default class HookForm extends Component { /> - )) || N/A} + )) || n/a} )} diff --git a/src/views/Hooks/ViewHook/index.jsx b/src/views/Hooks/ViewHook/index.jsx index c293e082..0d3cf9bd 100644 --- a/src/views/Hooks/ViewHook/index.jsx +++ b/src/views/Hooks/ViewHook/index.jsx @@ -131,6 +131,11 @@ export default class ViewHook extends Component { const { isNewHook, data } = this.props; const { error: err, dialogError, actionLoading, dialogOpen } = this.state; const error = (data && data.error) || err; + const hookLastFires = + data.hookLastFires && + data.hookLastFires.sort( + (a, b) => new Date(b.taskCreateTime) - new Date(a.taskCreateTime) + ); return ( @@ -152,10 +157,7 @@ export default class ViewHook extends Component { dialogError={dialogError} actionLoading={actionLoading} hook={data.hook} - hookLastFires={data.hookLastFires.sort( - (a, b) => - new Date(b.taskCreateTime) - new Date(a.taskCreateTime) - )} + hookLastFires={hookLastFires} dialogOpen={dialogOpen} onTriggerHook={this.handleTriggerHook} onUpdateHook={this.handleUpdateHook} From f98d3850e680ffbc18d628005f9ed6be19fc54ff Mon Sep 17 00:00:00 2001 From: biboswan Date: Sat, 16 Feb 2019 04:27:19 +0530 Subject: [PATCH 08/14] Add toggle view for error --- src/components/HookForm/index.jsx | 22 +++------- src/components/ToggleView/index.jsx | 63 +++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 17 deletions(-) create mode 100644 src/components/ToggleView/index.jsx diff --git a/src/components/HookForm/index.jsx b/src/components/HookForm/index.jsx index 1b5c9b74..8742b1e3 100644 --- a/src/components/HookForm/index.jsx +++ b/src/components/HookForm/index.jsx @@ -6,10 +6,6 @@ import { equals, assocPath } from 'ramda'; import cloneDeep from 'lodash.clonedeep'; import CodeEditor from '@mozilla-frontend-infra/components/CodeEditor'; import Code from '@mozilla-frontend-infra/components/Code'; -import ExpansionPanel from '@material-ui/core/ExpansionPanel'; -import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary'; -import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import { withStyles } from '@material-ui/core/styles'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; @@ -39,6 +35,7 @@ import DialogAction from '../DialogAction'; import DateDistance from '../DateDistance'; import { hook } from '../../utils/prop-types'; import removeKeys from '../../utils/removeKeys'; +import ToggleView from '../ToggleView'; const initialHook = { metadata: { @@ -188,8 +185,6 @@ export default class HookForm extends Component { validation: {}, }; - expandsionSummary = React.createRef(); - static getDerivedStateFromProps(props, state) { if ( equals(props.hook, state.previousHook) && @@ -446,7 +441,6 @@ export default class HookForm extends Component { validation, } = this.state; - /* eslint-disable-next-line no-underscore-dangle */ return ( @@ -573,21 +567,15 @@ export default class HookForm extends Component { {(hookFire.result === 'ERROR' && ( - - }> - - Show/Hide - - - + - - + } + /> )) || n/a} diff --git a/src/components/ToggleView/index.jsx b/src/components/ToggleView/index.jsx new file mode 100644 index 00000000..b70af19e --- /dev/null +++ b/src/components/ToggleView/index.jsx @@ -0,0 +1,63 @@ +import React, { Component, Fragment } from 'react'; +import { withStyles } from '@material-ui/core/styles'; +import classNames from 'classnames'; +import Typography from '@material-ui/core/Typography'; +import { bool, node, object } from 'prop-types'; +import Button from '../Button'; + +@withStyles(theme => ({ + infoButton: { + backgroundColor: theme.palette.info[700], + marginBottom: '4px', + }, +})) +export default class ToggleView extends Component { + static defaultProps = { + defaultExpanded: false, + panel: null, + btnStyle: null, + }; + + state = { + expanded: null, + }; + + static propTypes = { + /** indicate whether the panel will be shown by default */ + defaultExpanded: bool, + /** the panel element to be shown */ + panel: node.isRequired, + /** style of the toggle button to override default styles */ + btnStyle: object, + }; + + static getDerivedStateFromProps(props, state) { + if (state.expanded === null) { + return { + expanded: props.defaultExpanded, + }; + } + } + + handleClick = () => { + this.setState({ expanded: !this.state.expanded }); + }; + + render() { + const { btnStyle, panel, classes, ...props } = this.props; + const { expanded } = this.state; + + return ( + + + {expanded && panel} + + ); + } +} From 4674382870fc8c96279e776bf0b4f7f136c40a5b Mon Sep 17 00:00:00 2001 From: biboswan Date: Fri, 22 Feb 2019 23:19:57 +0530 Subject: [PATCH 09/14] Add drawer to display error info --- src/components/Button/index.jsx | 4 +- src/components/HookForm/index.jsx | 101 ++++++++++++++++++++++++---- src/components/ToggleView/index.jsx | 63 ----------------- 3 files changed, 91 insertions(+), 77 deletions(-) delete mode 100644 src/components/ToggleView/index.jsx diff --git a/src/components/Button/index.jsx b/src/components/Button/index.jsx index b5752d1c..9aaa60f7 100644 --- a/src/components/Button/index.jsx +++ b/src/components/Button/index.jsx @@ -50,7 +50,7 @@ export default class Button extends Component { spanProps: object, }; - handleButtonClick = () => { + handleButtonClick = e => { const { onClick, track } = this.props; if (track && process.env.GA_TRACKING_ID) { @@ -60,7 +60,7 @@ export default class Button extends Component { } if (onClick) { - onClick(); + onClick(e); } }; diff --git a/src/components/HookForm/index.jsx b/src/components/HookForm/index.jsx index 8742b1e3..a8d3d5e1 100644 --- a/src/components/HookForm/index.jsx +++ b/src/components/HookForm/index.jsx @@ -1,3 +1,4 @@ +/* eslint-disable no-plusplus */ import React, { Component, Fragment } from 'react'; import { Link } from 'react-router-dom'; import { string, bool, func, oneOfType, object, array } from 'prop-types'; @@ -6,6 +7,8 @@ import { equals, assocPath } from 'ramda'; import cloneDeep from 'lodash.clonedeep'; import CodeEditor from '@mozilla-frontend-infra/components/CodeEditor'; import Code from '@mozilla-frontend-infra/components/Code'; +import Drawer from '@material-ui/core/Drawer'; +import memoize from 'fast-memoize'; import { withStyles } from '@material-ui/core/styles'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; @@ -19,6 +22,7 @@ import FormGroup from '@material-ui/core/FormGroup'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import Grid from '@material-ui/core/Grid'; import IconButton from '@material-ui/core/IconButton'; +import InformationVariantIcon from 'mdi-react/InformationVariantIcon'; import Typography from '@material-ui/core/Typography'; import FlashIcon from 'mdi-react/FlashIcon'; import PlusIcon from 'mdi-react/PlusIcon'; @@ -35,7 +39,6 @@ import DialogAction from '../DialogAction'; import DateDistance from '../DateDistance'; import { hook } from '../../utils/prop-types'; import removeKeys from '../../utils/removeKeys'; -import ToggleView from '../ToggleView'; const initialHook = { metadata: { @@ -129,6 +132,19 @@ const initialHook = { maxWidth: '75ch', overflowY: 'scroll', }, + infoButton: { + marginLeft: -theme.spacing.double, + marginRight: theme.spacing.unit, + }, + headline: { + paddingLeft: theme.spacing.triple, + paddingRight: theme.spacing.triple, + }, + metadataContainer: { + paddingTop: theme.spacing.double, + paddingBottom: theme.spacing.double, + width: 400, + }, })) /** A form to view/edit/create a hook */ export default class HookForm extends Component { @@ -183,6 +199,8 @@ export default class HookForm extends Component { taskValidJson: true, triggerSchemaValidJson: true, validation: {}, + drawerOpen: false, + drawerData: null, }; static getDerivedStateFromProps(props, state) { @@ -420,6 +438,39 @@ export default class HookForm extends Component { ), }); + handleDrawerClose = () => { + this.setState({ + drawerOpen: false, + drawerData: null, + }); + }; + + handleDrawerOpen = ({ target: { name } }) => + memoize( + name => { + const { hookLastFires } = this.state; + let body; + const lastFiresLength = hookLastFires.length; + + for (let i = 0; i < lastFiresLength; i++) { + const { taskId, result, error } = hookLastFires[i]; + + if (taskId === name) { + body = result === 'ERROR' && error; + break; + } + } + + this.setState({ + drawerOpen: true, + drawerData: { headline: name, body }, + }); + }, + { + serializer: name => name, + } + )(name); + render() { const { actionLoading, @@ -439,7 +490,10 @@ export default class HookForm extends Component { hook, hookLastFires, validation, + drawerOpen, + drawerData, } = this.state; + const iconSize = 16; return ( @@ -566,17 +620,13 @@ export default class HookForm extends Component { - {(hookFire.result === 'ERROR' && ( - - } - /> - )) || n/a} + )} @@ -797,6 +847,33 @@ export default class HookForm extends Component { } /> )} + +
+ + {drawerData && drawerData.headline} + + + + + )) || n/a + } + /> + + +
+
); } diff --git a/src/components/ToggleView/index.jsx b/src/components/ToggleView/index.jsx deleted file mode 100644 index b70af19e..00000000 --- a/src/components/ToggleView/index.jsx +++ /dev/null @@ -1,63 +0,0 @@ -import React, { Component, Fragment } from 'react'; -import { withStyles } from '@material-ui/core/styles'; -import classNames from 'classnames'; -import Typography from '@material-ui/core/Typography'; -import { bool, node, object } from 'prop-types'; -import Button from '../Button'; - -@withStyles(theme => ({ - infoButton: { - backgroundColor: theme.palette.info[700], - marginBottom: '4px', - }, -})) -export default class ToggleView extends Component { - static defaultProps = { - defaultExpanded: false, - panel: null, - btnStyle: null, - }; - - state = { - expanded: null, - }; - - static propTypes = { - /** indicate whether the panel will be shown by default */ - defaultExpanded: bool, - /** the panel element to be shown */ - panel: node.isRequired, - /** style of the toggle button to override default styles */ - btnStyle: object, - }; - - static getDerivedStateFromProps(props, state) { - if (state.expanded === null) { - return { - expanded: props.defaultExpanded, - }; - } - } - - handleClick = () => { - this.setState({ expanded: !this.state.expanded }); - }; - - render() { - const { btnStyle, panel, classes, ...props } = this.props; - const { expanded } = this.state; - - return ( - - - {expanded && panel} - - ); - } -} From 01563657707435d4ae22b57cab36ceac83cc0370 Mon Sep 17 00:00:00 2001 From: biboswan Date: Sat, 23 Feb 2019 01:21:09 +0530 Subject: [PATCH 10/14] Minor tweak --- src/components/HookForm/index.jsx | 37 +++++++++++++++++-------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/components/HookForm/index.jsx b/src/components/HookForm/index.jsx index a8d3d5e1..af00cb3f 100644 --- a/src/components/HookForm/index.jsx +++ b/src/components/HookForm/index.jsx @@ -453,10 +453,10 @@ export default class HookForm extends Component { const lastFiresLength = hookLastFires.length; for (let i = 0; i < lastFiresLength; i++) { - const { taskId, result, error } = hookLastFires[i]; + const { taskId, error } = hookLastFires[i]; if (taskId === name) { - body = result === 'ERROR' && error; + body = error; break; } } @@ -620,13 +620,16 @@ export default class HookForm extends Component { - + {(hookFire.result === 'ERROR' && ( + + )) || n/a} )} @@ -860,14 +863,14 @@ export default class HookForm extends Component { - )) || n/a + drawerData && + drawerData.body && ( + + ) } /> From e238f6fb90a42aea90aa3e13df52b40be0b3e3be Mon Sep 17 00:00:00 2001 From: biboswan Date: Sat, 23 Feb 2019 15:26:46 +0530 Subject: [PATCH 11/14] add link icon for taskids --- src/components/HookForm/index.jsx | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/components/HookForm/index.jsx b/src/components/HookForm/index.jsx index af00cb3f..a2b1214e 100644 --- a/src/components/HookForm/index.jsx +++ b/src/components/HookForm/index.jsx @@ -30,6 +30,7 @@ import DeleteIcon from 'mdi-react/DeleteIcon'; import ContentSaveIcon from 'mdi-react/ContentSaveIcon'; import { docs } from 'taskcluster-lib-urls'; import Label from '@mozilla-frontend-infra/components/Label'; +import LinkIcon from 'mdi-react/LinkIcon'; import ErrorPanel from '../ErrorPanel'; import DataTable from '../DataTable'; import Button from '../Button'; @@ -37,6 +38,7 @@ import SpeedDial from '../SpeedDial'; import SpeedDialAction from '../SpeedDialAction'; import DialogAction from '../DialogAction'; import DateDistance from '../DateDistance'; +import TableCellListItem from '../TableCellListItem'; import { hook } from '../../utils/prop-types'; import removeKeys from '../../utils/removeKeys'; @@ -602,11 +604,22 @@ export default class HookForm extends Component { renderRow={hookFire => ( - {(hookFire.result === 'SUCCESS' && ( - - {hookFire.taskId} - - )) || {hookFire.taskId}} + + {hookFire.taskId}} + /> + {hookFire.result === 'SUCCESS' && ( + + )} + {hookFire.firedBy} From 8bb249fe0fdb9aab6bc7608cba0b17be6b68a52b Mon Sep 17 00:00:00 2001 From: biboswan Date: Mon, 25 Feb 2019 23:00:09 +0530 Subject: [PATCH 12/14] minor tweak --- src/components/HookForm/index.jsx | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/components/HookForm/index.jsx b/src/components/HookForm/index.jsx index a2b1214e..9d751d72 100644 --- a/src/components/HookForm/index.jsx +++ b/src/components/HookForm/index.jsx @@ -604,22 +604,18 @@ export default class HookForm extends Component { renderRow={hookFire => ( - - {hookFire.taskId}} - /> - {hookFire.result === 'SUCCESS' && ( + {(hookFire.result === 'SUCCESS' && ( + + {hookFire.taskId}} + /> - )} - + + )) || {hookFire.taskId}} {hookFire.firedBy} @@ -640,7 +636,6 @@ export default class HookForm extends Component { name={hookFire.taskId} onClick={this.handleDrawerOpen}> - )) )) || n/a} From 2b28062613f885367a5d3edb3b9ae080ef26e0c9 Mon Sep 17 00:00:00 2001 From: biboswan Date: Wed, 13 Mar 2019 16:25:22 +0530 Subject: [PATCH 13/14] Remove 1-20 part and text rename --- src/components/DataTable/index.jsx | 58 +++++++++++++++++++----------- src/components/HookForm/index.jsx | 12 ++++--- 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/src/components/DataTable/index.jsx b/src/components/DataTable/index.jsx index 398f2d5c..c09a5c66 100644 --- a/src/components/DataTable/index.jsx +++ b/src/components/DataTable/index.jsx @@ -9,14 +9,25 @@ import { object, bool, } from 'prop-types'; +import { withStyles } from '@material-ui/core/styles'; import Table from '@material-ui/core/Table'; import TableBody from '@material-ui/core/TableBody'; +import TableFooter from '@material-ui/core/TableFooter'; import TableCell from '@material-ui/core/TableCell'; import TableHead from '@material-ui/core/TableHead'; import TableSortLabel from '@material-ui/core/TableSortLabel'; import TableRow from '@material-ui/core/TableRow'; import TablePagination from '@material-ui/core/TablePagination'; +@withStyles(() => ({ + noDisplay: { + display: 'none', + }, + tablePaginationRoot: { + position: 'relative', + left: '207%', + }, +})) /** * A table to display a set of data elements. */ @@ -33,7 +44,6 @@ export default class DataTable extends Component { state = { page: 0, - rowsPerPage: 10, }; static propTypes = { @@ -92,12 +102,9 @@ export default class DataTable extends Component { this.setState({ page }); }; - handleChangeRowsPerPage = event => { - this.setState({ rowsPerPage: event.target.value }); - }; - render() { const { + classes, items, columnsSize, renderRow, @@ -108,7 +115,8 @@ export default class DataTable extends Component { isPaginate, } = this.props; const colSpan = columnsSize || (headers && headers.length) || 0; - const { page, rowsPerPage } = this.state; + const { page } = this.state; + const rowsPerPage = 5; return ( @@ -143,21 +151,29 @@ export default class DataTable extends Component { )} {isPaginate && ( - + + + + + )}
); diff --git a/src/components/HookForm/index.jsx b/src/components/HookForm/index.jsx index 9d751d72..9222819e 100644 --- a/src/components/HookForm/index.jsx +++ b/src/components/HookForm/index.jsx @@ -591,15 +591,19 @@ export default class HookForm extends Component { - Last Hook Fire Attempts - + Last Fired Results } /> {hookLastFires && ( ( From aa51ef90d099c5a39d4073dc1e89f13918337695 Mon Sep 17 00:00:00 2001 From: biboswan Date: Fri, 15 Mar 2019 18:40:51 +0530 Subject: [PATCH 14/14] add scrollbar --- src/components/DataTable/index.jsx | 122 ++++++++++++++--------------- src/components/HookForm/index.jsx | 2 +- 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/components/DataTable/index.jsx b/src/components/DataTable/index.jsx index c09a5c66..9f363b5a 100644 --- a/src/components/DataTable/index.jsx +++ b/src/components/DataTable/index.jsx @@ -1,4 +1,4 @@ -import React, { Component } from 'react'; +import React, { Component, Fragment } from 'react'; import { arrayOf, func, @@ -12,7 +12,6 @@ import { import { withStyles } from '@material-ui/core/styles'; import Table from '@material-ui/core/Table'; import TableBody from '@material-ui/core/TableBody'; -import TableFooter from '@material-ui/core/TableFooter'; import TableCell from '@material-ui/core/TableCell'; import TableHead from '@material-ui/core/TableHead'; import TableSortLabel from '@material-ui/core/TableSortLabel'; @@ -21,11 +20,13 @@ import TablePagination from '@material-ui/core/TablePagination'; @withStyles(() => ({ noDisplay: { - display: 'none', + visibility: 'hidden', }, - tablePaginationRoot: { - position: 'relative', - left: '207%', + table: { + minWidth: 1020, + }, + tableWrapper: { + overflowX: 'auto', }, })) /** @@ -119,63 +120,62 @@ export default class DataTable extends Component { const rowsPerPage = 5; return ( - - {headers && ( - - - {headers.map(header => ( - - - {header} - - - ))} - - - )} - - {items.length === 0 ? ( - - - {noItemsMessage} - - - ) : ( - items - .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) - .map(renderRow) - )} - + +
+
+ {headers && ( + + + {headers.map(header => ( + + + {header} + + + ))} + + + )} + + {items.length === 0 ? ( + + + {noItemsMessage} + + + ) : ( + items + .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) + .map(renderRow) + )} + +
+ {isPaginate && ( - - - - - + )} - +
); } } diff --git a/src/components/HookForm/index.jsx b/src/components/HookForm/index.jsx index 9222819e..d7a74a53 100644 --- a/src/components/HookForm/index.jsx +++ b/src/components/HookForm/index.jsx @@ -130,7 +130,7 @@ const initialHook = { whiteSpace: 'normal', }, errorPanel: { - maxHeight: '300px', + maxHeight: 300, maxWidth: '75ch', overflowY: 'scroll', },