From 4227fa2fefff23ab9afcc5fea89fd8abf296d7e0 Mon Sep 17 00:00:00 2001 From: VKD Date: Sun, 6 Sep 2020 14:56:32 +0530 Subject: [PATCH 1/2] feat(UI): Add option to filter by status --- src/App.js | 57 +++++++++++++---- src/Components/FilterToggler/CheckBox.css | 3 + src/Components/FilterToggler/CheckBox.js | 26 ++++++++ src/Components/FilterToggler/FilterToggler.js | 61 +++++++++++++++++++ src/Components/Grid/GridTabView.css | 56 ++++++++--------- src/Components/Grid/Status.js | 2 +- src/Components/Grid/TabHeading.js | 1 + src/Components/Main/Main.js | 7 +++ src/Components/TreeView/Treeview.css | 15 ++--- 9 files changed, 180 insertions(+), 48 deletions(-) create mode 100644 src/Components/FilterToggler/CheckBox.css create mode 100644 src/Components/FilterToggler/CheckBox.js create mode 100644 src/Components/FilterToggler/FilterToggler.js diff --git a/src/App.js b/src/App.js index 9d49747..6b7e0d8 100644 --- a/src/App.js +++ b/src/App.js @@ -6,6 +6,7 @@ import Header from './Components/Header/Header'; import Sidebar from './Components/Sidebar/Sidebar'; import Main from './Components/Main/Main'; let data; +const statusList = []; class App extends Component { constructor(props) { data = window.resultData; @@ -13,14 +14,19 @@ class App extends Component { this.state = { menuState: 'close', testResults: data, - treeViewData: this.formatTreeViewData(data), + treeViewData: this.formatTreeViewData(data, []), information: this.getInformation(data), }; this.onTreeNodeClick = this.onTreeNodeClick.bind(this); this.state.gridData = this.state.treeViewData; this.menuStateChange = this.menuStateChange.bind(this); + this.onStatusChecked = this.onStatusChecked.bind(this); } - formatTreeViewData(testResults) { + getStatusList() { + return statusList; + } + + formatTreeViewData(testResults, statusFilter) { const testResultData = {}; Object.assign(testResultData, testResults); let treeViewData = []; @@ -40,13 +46,14 @@ class App extends Component { testResultData.testResults, [], id, + statusFilter, ); } treeViewData = rootElement; return treeViewData; } - parseTreeData(testResults, parentArray, id) { + parseTreeData(testResults, parentArray, id, statusFilter) { let subArray = []; testResults.forEach(element => { if (element.testFilePath || element.fullName) { @@ -70,15 +77,30 @@ class App extends Component { element.testResults, [], id, + statusFilter, ); - parentArray.push(nodeValue); + if ( + statusFilter.length === 0 || + nodeValue.children.length > 0 + ) { + parentArray.push(nodeValue); + } } else if (element.ancestorTitles) { - [subArray, id] = this.parseAncestor( - element.ancestorTitles, - element, - subArray, - id, - ); + if (statusList.indexOf(element.status) < 0) { + statusList.push(element.status); + } + if ( + statusFilter.length === 0 || + statusFilter.indexOf(element.status) >= 0 + ) { + [subArray, id] = this.parseAncestor( + element.ancestorTitles, + element, + subArray, + id, + statusFilter, + ); + } } } }); @@ -88,7 +110,7 @@ class App extends Component { return [parentArray, id]; } - parseAncestor(ancestors, testCase, parentArray, id) { + parseAncestor(ancestors, testCase, parentArray, id, statusFilter) { const ancestorCopy = [...ancestors]; if (ancestors.length > 0) { const itemTitle = ancestors[0]; @@ -113,6 +135,7 @@ class App extends Component { testCase, [], id, + statusFilter, ); parentArray.push(nodeValue); } else { @@ -139,6 +162,7 @@ class App extends Component { testCase, parentArray[elementIndex].children, id, + statusFilter, ); } } else { @@ -197,6 +221,15 @@ class App extends Component { return information; } + onStatusChecked = checkedStatuses => { + this.setState({ + gridData: this.formatTreeViewData( + this.state.testResults, + checkedStatuses, + ), + }); + }; + render() { return (
@@ -219,6 +252,8 @@ class App extends Component { this.state.testResults?.reporterOptions?.expandResults } information={this.state.information} + statusList={this.getStatusList()} + onStatusChecked={this.onStatusChecked} />
); diff --git a/src/Components/FilterToggler/CheckBox.css b/src/Components/FilterToggler/CheckBox.css new file mode 100644 index 0000000..8bab6fc --- /dev/null +++ b/src/Components/FilterToggler/CheckBox.css @@ -0,0 +1,3 @@ +.checkboxLable { + text-transform: capitalize; +} diff --git a/src/Components/FilterToggler/CheckBox.js b/src/Components/FilterToggler/CheckBox.js new file mode 100644 index 0000000..46319a3 --- /dev/null +++ b/src/Components/FilterToggler/CheckBox.js @@ -0,0 +1,26 @@ +import React, { Fragment } from 'react'; +import PropTypes from 'prop-types'; +import './CheckBox.css'; +export const CheckBox = props => { + return ( + + + + + ); +}; +CheckBox.propTypes = { + handleCheck: PropTypes.func.isRequired, + isChecked: PropTypes.bool, + value: PropTypes.string.isRequired, +}; +export default CheckBox; diff --git a/src/Components/FilterToggler/FilterToggler.js b/src/Components/FilterToggler/FilterToggler.js new file mode 100644 index 0000000..b100787 --- /dev/null +++ b/src/Components/FilterToggler/FilterToggler.js @@ -0,0 +1,61 @@ +import React from 'react'; +import CheckBox from './CheckBox'; +import PropTypes from 'prop-types'; +export default class FilterToggler extends React.Component { + constructor(props) { + super(props); + this.state = { + statusList: this.init(this.props.statusList), + }; + } + + init(statusList) { + if (statusList && statusList.length > 0) { + return statusList.map(status => { + return { value: status, isChecked: false }; + }); + } else { + return []; + } + } + + handleChecked = event => { + const checkStatuses = []; + this.state.statusList.forEach(status => { + if (status.value === event.target.value) { + status.isChecked = event.target.checked; + } + if (status.isChecked) { + checkStatuses.push(status.value); + } + }); + this.setState(this.state.statusList); + this.props.onStatusChecked(checkStatuses); + }; + render() { + if (this.props.statusList && this.props.statusList.length > 0) { + return ( +
+

+ Filter:{' '} + {this.state.statusList.map(status => { + return ( + + ); + })} +

+
+ ); + } else { + return null; + } + } +} +FilterToggler.propTypes = { + statusList: PropTypes.array, + onStatusChecked: PropTypes.func.isRequired, +}; diff --git a/src/Components/Grid/GridTabView.css b/src/Components/Grid/GridTabView.css index a24ad9b..937c7d3 100644 --- a/src/Components/Grid/GridTabView.css +++ b/src/Components/Grid/GridTabView.css @@ -1,17 +1,16 @@ - - /* Accordion styles */ - .tabs { +/* Accordion styles */ +.tabs { border-radius: 8px; box-shadow: 0 4px 4px -2px rgba(0, 0, 0, 0.5); padding: 1vh 0vw; - } +} - .tab { +.tab { width: 100%; color: white; overflow: hidden; - } - .tab-label { +} +.tab-label { display: -webkit-box; display: flex; -webkit-box-pack: justify; @@ -21,21 +20,21 @@ font-weight: bold; cursor: pointer; color: #ffffff; - font-size: .75rem; + font-size: 0.75rem; white-space: nowrap; - } - .tab-label:hover { +} +.tab-label:hover { background: #1a252f; - } - .tab-label::after { - content: "\276F"; +} +.tab-label::after { + content: '\276F'; width: 1em; height: 1em; text-align: center; -webkit-transition: all 0.35s; transition: all 0.35s; - } - .tab-content { +} +.tab-content { padding: 3px; color: #2c3e50; background: white; @@ -43,8 +42,8 @@ transition: all 0.35s; font-size: 1rem; display: none; - } - .tab-close { +} +.tab-close { display: -webkit-box; display: flex; -webkit-box-pack: end; @@ -53,26 +52,25 @@ font-size: 0.75em; background: #2c3e50; cursor: pointer; - } - .tab-close:hover { +} +.tab-close:hover { background: #1a252f; - } +} - input:checked + .tab-label { +input.togglerCheckBox:checked + .tab-label { background: #1a252f; - } - input:checked + .tab-label::after { +} +input.togglerCheckBox:checked + .tab-label::after { -webkit-transform: rotate(90deg); transform: rotate(90deg); - } - input:checked ~ .tab-content { +} +input.togglerCheckBox:checked ~ .tab-content { max-height: fit-content; display: block; - } +} -input { +input.togglerCheckBox { position: absolute; opacity: 0; z-index: -1; - } - +} diff --git a/src/Components/Grid/Status.js b/src/Components/Grid/Status.js index 9a0957d..5ebe13f 100644 --- a/src/Components/Grid/Status.js +++ b/src/Components/Grid/Status.js @@ -101,6 +101,6 @@ class Status extends Component { } } Status.propTypes = { - status: PropTypes.string.isRequired, + status: PropTypes.string, }; export default Status; diff --git a/src/Components/Grid/TabHeading.js b/src/Components/Grid/TabHeading.js index 6632d12..27a5e66 100644 --- a/src/Components/Grid/TabHeading.js +++ b/src/Components/Grid/TabHeading.js @@ -29,6 +29,7 @@ class TabHeading extends Component { id={`elem_${this.props.item.id}`} checked={this.state.isChecked} onChange={this.toggleChange} + className="togglerCheckBox" />