Feature - Replace tables with a more advanced component
- Replaced Table in Reportees table with mui-datatable package - Removed Sorting function in Reportees component and using default mui-datatble sorting feature
This commit is contained in:
Родитель
cce6da53c4
Коммит
39ada188a7
|
@ -31,6 +31,7 @@
|
|||
"chart.js": "^2.7.3",
|
||||
"mitt": "^1.1.3",
|
||||
"moment": "^2.23.0",
|
||||
"mui-datatables": "^2.4.0",
|
||||
"prop-types": "^15",
|
||||
"query-string": "^6.2.0",
|
||||
"react": "^16",
|
||||
|
|
|
@ -1,92 +1,14 @@
|
|||
import React from 'react';
|
||||
import PropTypes 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 TableCell from '@material-ui/core/TableCell';
|
||||
import TableHead from '@material-ui/core/TableHead';
|
||||
import TableRow from '@material-ui/core/TableRow';
|
||||
import TableSortLabel from '@material-ui/core/TableSortLabel';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import { withStyles, createMuiTheme, MuiThemeProvider } from '@material-ui/core/styles';
|
||||
import MUIDataTable from 'mui-datatables';
|
||||
import CONFIG from '../../config';
|
||||
|
||||
const styles = {
|
||||
root: {},
|
||||
};
|
||||
|
||||
|
||||
function propertyComparatorAscending(a, b, orderBy) {
|
||||
const valueA = a[orderBy];
|
||||
const valueB = b[orderBy];
|
||||
|
||||
// Values can either be strings or objects with a "count" property.
|
||||
// Case 1: they're strings.
|
||||
if (typeof valueA === 'string') {
|
||||
return valueA.localeCompare(valueB);
|
||||
}
|
||||
|
||||
// Case 2: they're objects with a count property.
|
||||
const countA = valueA ? valueA.count : 0;
|
||||
const countB = valueB ? valueB.count : 0;
|
||||
|
||||
return countA - countB;
|
||||
}
|
||||
|
||||
function stableSort(array, cmp) {
|
||||
const stabilizedThis = array.map((el, index) => [el, index]);
|
||||
stabilizedThis.sort((a, b) => {
|
||||
const order = cmp(a[0], b[0]);
|
||||
if (order !== 0) return order;
|
||||
return a[1] - b[1];
|
||||
});
|
||||
const result = stabilizedThis.map(el => el[0]);
|
||||
return result;
|
||||
}
|
||||
|
||||
function getSorting(order, orderBy) {
|
||||
return order === 'asc'
|
||||
? (a, b) => propertyComparatorAscending(a, b, orderBy)
|
||||
: (a, b) => -propertyComparatorAscending(a, b, orderBy);
|
||||
}
|
||||
|
||||
function TableHeadCell({
|
||||
metricUid, orderBy, order, label, onClick,
|
||||
}) {
|
||||
return (
|
||||
<TableCell
|
||||
align="right"
|
||||
sortDirection={orderBy === metricUid ? order : false}
|
||||
>
|
||||
<Tooltip
|
||||
title="Click to sort the table by this column"
|
||||
placement="bottom-end"
|
||||
>
|
||||
<TableSortLabel
|
||||
active={orderBy === metricUid}
|
||||
direction={order}
|
||||
onClick={onClick}
|
||||
>
|
||||
{label}
|
||||
</TableSortLabel>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
);
|
||||
}
|
||||
|
||||
TableHeadCell.propTypes = {
|
||||
metricUid: PropTypes.string.isRequired,
|
||||
orderBy: PropTypes.string.isRequired,
|
||||
order: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
class Reportees extends React.PureComponent {
|
||||
state = {
|
||||
orderBy: 'cn',
|
||||
order: 'asc',
|
||||
};
|
||||
|
||||
getMergedProps() {
|
||||
const { metrics, partialOrg, ldapEmail } = this.props;
|
||||
|
||||
|
@ -99,111 +21,94 @@ class Reportees extends React.PureComponent {
|
|||
...reportee,
|
||||
...metrics[reportee.bugzillaEmail],
|
||||
}));
|
||||
|
||||
return reporteesWithMetrics;
|
||||
// Sort dataset in ascending order and return
|
||||
return reporteesWithMetrics.sort((a, b) => a.cn.localeCompare(b.cn));
|
||||
}
|
||||
|
||||
createSortHandler = property => (event) => {
|
||||
this.handleRequestSort(event, property);
|
||||
};
|
||||
|
||||
handleRequestSort = (event, property) => {
|
||||
const { order, orderBy } = this.state;
|
||||
|
||||
let newOrder;
|
||||
|
||||
// If we click on the same column several times in a row, we simply switch
|
||||
// the prevous value.
|
||||
if (orderBy === property) {
|
||||
newOrder = order === 'asc' ? 'desc' : 'asc';
|
||||
} else if (property === 'cn') {
|
||||
// For most properties we want to order in the descending order first.
|
||||
// ... except when sorting by cn.
|
||||
newOrder = 'asc';
|
||||
} else {
|
||||
newOrder = 'desc';
|
||||
}
|
||||
|
||||
this.setState({
|
||||
orderBy: property,
|
||||
order: newOrder,
|
||||
});
|
||||
};
|
||||
// Custom styles to override default MUI theme
|
||||
getMuiTheme = () => createMuiTheme({
|
||||
overrides: {
|
||||
MUIDataTableBodyCell: {
|
||||
root: {
|
||||
textAlign: 'center',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
const { order, orderBy } = this.state;
|
||||
// MUI table options
|
||||
const options = {
|
||||
filter: true,
|
||||
selectableRows: false,
|
||||
sort: true,
|
||||
responsive: 'stacked',
|
||||
rowsPerPage: 10,
|
||||
download: false,
|
||||
print: false,
|
||||
viewColumns: false,
|
||||
};
|
||||
|
||||
const metricsAsArray = Object.entries(CONFIG.reporteesMetrics);
|
||||
|
||||
const tableHeader = [];
|
||||
|
||||
// Form Table column headers using metricsArray
|
||||
// Add Full name directly into columns Heading array
|
||||
const firstColumn = {
|
||||
name: 'cn',
|
||||
label: 'Full Name',
|
||||
};
|
||||
|
||||
tableHeader.push(firstColumn);
|
||||
|
||||
// push other columns from metricsAsArray in the config.js file to tableHeader array
|
||||
metricsAsArray.forEach(([metricUid, { label }]) => {
|
||||
const column = {
|
||||
name: `${metricUid}`,
|
||||
label,
|
||||
options: {
|
||||
filter: false,
|
||||
customBodyRender: value => (
|
||||
<a
|
||||
href={value !== undefined ? value.link : '#'}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{ value !== undefined ? value.count : '' }
|
||||
</a>
|
||||
),
|
||||
},
|
||||
};
|
||||
tableHeader.push(column);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableHeadCell
|
||||
metricUid="cn"
|
||||
orderBy={orderBy}
|
||||
order={order}
|
||||
label="Full Name"
|
||||
onClick={this.createSortHandler('cn')}
|
||||
/>
|
||||
{metricsAsArray.map(([metricUid, { label }]) => (
|
||||
<TableHeadCell
|
||||
key={metricUid}
|
||||
metricUid={metricUid}
|
||||
orderBy={orderBy}
|
||||
order={order}
|
||||
label={label}
|
||||
onClick={this.createSortHandler(metricUid)}
|
||||
/>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{stableSort(
|
||||
this.getMergedProps(),
|
||||
getSorting(order, orderBy),
|
||||
)
|
||||
.map(({
|
||||
cn, mail, bugzillaEmail, ...metricsValues
|
||||
}) => (
|
||||
<TableRow key={mail}>
|
||||
<TableCell key={mail}>{cn}</TableCell>
|
||||
{metricsAsArray.map(([metricUid]) => {
|
||||
const countLink = metricsValues[metricUid];
|
||||
return (
|
||||
<TableCell align="right" key={metricUid}>
|
||||
{countLink && (
|
||||
<a
|
||||
key={countLink.link}
|
||||
href={countLink.link}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{countLink.count}
|
||||
</a>
|
||||
)}
|
||||
</TableCell>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<MuiThemeProvider theme={this.getMuiTheme()}>
|
||||
<MUIDataTable
|
||||
title="Reportees"
|
||||
data={this.getMergedProps()}
|
||||
columns={tableHeader}
|
||||
options={options}
|
||||
/>
|
||||
</MuiThemeProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reportees.propTypes = {
|
||||
classes: PropTypes.shape({}).isRequired,
|
||||
ldapEmail: PropTypes.string.isRequired,
|
||||
ldapEmail: PropTypes.string,
|
||||
partialOrg: PropTypes.shape({}).isRequired,
|
||||
metrics: PropTypes.shape({}),
|
||||
};
|
||||
|
||||
Reportees.defaultProps = {
|
||||
metrics: {},
|
||||
ldapEmail: '',
|
||||
};
|
||||
|
||||
export default withStyles(styles)(Reportees);
|
||||
|
|
53
yarn.lock
53
yarn.lock
|
@ -5646,11 +5646,41 @@ lodash.clonedeep@^4.5.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
|
||||
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
|
||||
|
||||
lodash.find@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1"
|
||||
integrity sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=
|
||||
|
||||
lodash.flow@^3.1.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a"
|
||||
integrity sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=
|
||||
|
||||
lodash.get@^4.4.2:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
|
||||
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
|
||||
|
||||
lodash.isequal@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
||||
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
|
||||
|
||||
lodash.isundefined@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz#23ef3d9535565203a66cefd5b830f848911afb48"
|
||||
integrity sha1-I+89lTVWUgOmbO/VuDD4SJEa+0g=
|
||||
|
||||
lodash.memoize@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
|
||||
|
||||
lodash.merge@^4.6.0:
|
||||
version "4.6.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54"
|
||||
integrity sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==
|
||||
|
||||
lodash.omit@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60"
|
||||
|
@ -6042,6 +6072,22 @@ ms@^2.1.1:
|
|||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
|
||||
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
|
||||
|
||||
mui-datatables@^2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/mui-datatables/-/mui-datatables-2.4.0.tgz#7bc967e5daac8e359bf217fc06c7635badd6533b"
|
||||
integrity sha512-JmQjmuatUpOZPDUOOGvu4qZUSTXNwf+dQvyTX0yLosdmWJcXL9EYgrDQy2Fca3iqWDEfcLa7zdW/24zdjnltHA==
|
||||
dependencies:
|
||||
classnames "^2.2.5"
|
||||
lodash.clonedeep "^4.5.0"
|
||||
lodash.find "^4.6.0"
|
||||
lodash.get "^4.4.2"
|
||||
lodash.isequal "^4.5.0"
|
||||
lodash.isundefined "^3.0.1"
|
||||
lodash.memoize "^4.1.2"
|
||||
lodash.merge "^4.6.0"
|
||||
prop-types "^15.6.0"
|
||||
react-to-print "^2.0.0-alpha.7"
|
||||
|
||||
multicast-dns-service-types@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901"
|
||||
|
@ -7238,6 +7284,13 @@ react-test-renderer@^16.6.3:
|
|||
react-is "^16.8.6"
|
||||
scheduler "^0.13.6"
|
||||
|
||||
react-to-print@^2.0.0-alpha.7:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/react-to-print/-/react-to-print-2.1.2.tgz#6fb30cb79fc90f773dce76d25e2a896efd31b461"
|
||||
integrity sha512-oCbFoqPxIWG2lMigp9RMEp3bw5jU2uAjs3N3EdikfemDraLTFuh+kcXdr4eazmH+734TvpCQ70sgcCOfjmXyRQ==
|
||||
dependencies:
|
||||
prop-types "^15.6.2"
|
||||
|
||||
react-transition-group@^2.2.1:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
|
||||
|
|
Загрузка…
Ссылка в новой задаче