Skip to content

Commit

Permalink
Replace raw files popup with a table #277
Browse files Browse the repository at this point in the history
* Added material-ui x DataGrid and styling dependencies to package.json
* New Menu item in 'Files' popup to view 'Route Files'
* New FilesTable modal that utilizes mui DataGrid component to display a table with links for all segment(s) uploaded files.
  • Loading branch information
RossGGG committed Jun 2, 2024
1 parent bd4f6cc commit 25bc8b7
Showing 1 changed file with 206 additions and 0 deletions.
206 changes: 206 additions & 0 deletions src/components/Files/FileTable.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import Obstruction from 'obstruction';

import {withStyles, Divider, Typography, Button, Modal, Paper} from '@material-ui/core';
import {DataGrid} from '@mui/x-data-grid';

import DownloadIcon from '@material-ui/icons/FileDownload';
import Colors from '../../colors';
import Theme from '../../theme';
import ResizeHandler from '../ResizeHandler';

const styles = (theme) => ({
modal: {
position: 'absolute',
padding: theme.spacing.unit * 2,
width: 'max-content',
maxWidth: '90%',
left: '50%',
top: '50%',
transform: 'translate(-50%, -50%)',
outline: 'none',
},
titleContainer: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'baseline',
marginBottom: 5,
},
titleIcon: {
marginRight: 8,
},
buttonGroup: {
textAlign: 'right',
},
uploadContainer: {
margin: `${theme.spacing.unit}px 0`,
color: Colors.white90,
textAlign: 'left',
overflowY: 'auto',
},
uploadButton: {
color: Colors.white,
borderRadius: 13,
fontSize: '0.8rem',
padding: '4px 12px',
minHeight: 19,
backgroundColor: Colors.white05,
'&:hover': {
backgroundColor: Colors.white10,
},
},
dataGrid: {
border: 'none',
'& .MuiDataGrid-row': {
color: theme.palette.common.white,
'--DataGrid-row-border-color': 'transparent',
},
'& .MuiDataGrid-columnHeader': {
backgroundColor: theme.palette.grey[300],
color: theme.palette.common.white,
textAlign: 'center',
},
'& .MuiDataGrid-columnHeaderTitle': {
lineSpacing: 1.5,
whiteSpace: 'normal',
},
'& .MuiDataGrid-footerContainer': {
color: theme.palette.common.white,
borderColor: theme.palette.common.white,
},
'& .MuiTablePagination-root, & .MuiTablePagination-selectIcon': {
color: theme.palette.common.white,
},
'& .MuiDataGrid-cell:focus, & .MuiDataGrid-cell:focus-within': {
outline: 'none',
},
},
});


const FILE_NAMES = {
qcameras: { filename: 'qcamera.ts', label: "Road Camera (Lo-Res)" },
cameras: { filename: 'fcamera.hevc', label: 'Road Camera' },
dcameras: { filename: 'dcamera.hevc', label: "Driver Camera" },
ecameras: { filename: 'ecamera.hevc', label: "Wide Road Camera" },
qlogs: { filename: 'qlog.bz2', label: 'Logs (Decimated)' },
logs: { filename: 'rlog.bz2', label: 'Logs' },
};

class FileTable extends Component {
constructor(props) {
super(props);

this.state = {
windowWidth: window.innerWidth,
windowHeight: window.innerHeight
};
}

getSegmentIndex(segmentName) {
return segmentName.split("--").slice(-1)[0]
}

filesToRows(files) {
if (files) {
const segments = {};
for (let [key, data] of Object.entries(files)) {
const [segment, file_type] = key.split("/");
segments[segment] = { ...segments[segment], ...{ [file_type]: data.url } };
}

const sortedSegments = Object.entries(segments).sort((a, b) => {
// Sort the entries by segment number
const aSegmentIndex = parseInt(this.getSegmentIndex(a[0]));
const bSegmentIndex = parseInt(this.getSegmentIndex(b[0]));
if (aSegmentIndex < bSegmentIndex) return -1;
if (aSegmentIndex > bSegmentIndex) return 1;
return 0;
});

const rows = []

for (let [segmentName, segmentFiles] of sortedSegments) {
rows.push({
id: this.getSegmentIndex(segmentName),
segmentName: segmentName,
...segmentFiles
});
}

return rows;
}
}

render() {
const { classes, currentRoute, files } = this.props;
const { windowWidth, windowHeight } = this.state;

Check failure on line 138 in src/components/Files/FileTable.jsx

View workflow job for this annotation

GitHub Actions / test

'windowWidth' is assigned a value but never used

const columns = [
{ field: 'id', headerName: "#", type: 'number', width: 5 },
{ field: 'segmentName', headerName: 'Segment', width: 325 },
];

columns.push(...Object.entries(FILE_NAMES).map(([key, { filename, label }]) => {
return {
field: key,
headerName: label,
headerAlign: 'center',
align: 'center',
display: 'flex',
minWidth: label.includes("Camera") ? 120 : 100,
sortable: false,
filterable: false,
renderCell: (params) => (
<Button className={classes.uploadButton} href={params.value} target="_blank" rel="noopener noreferrer">
{params.value.match(/(?<=\/)[\w.]+(?=\?)/gm)[0]}
</Button>
),
}
}));
columns.slice(-1)[0].width = null;
columns.slice(-1)[0].flex = 1;

const rows = this.filesToRows(files);

return (
<>
<ResizeHandler onResize={(ww, wh) => this.setState({ windowWidth: ww, windowHeight: wh })}/>
<Modal aria-labelledby="file-table-modal" open={this.props.open} onClose={this.props.onClose}>
<Paper className={classes.modal}>
<div className={classes.titleContainer}>
<Typography variant="title"><DownloadIcon className={classes.titleIcon}/>Route Files</Typography>
<Typography vfd ariant="caption" style={{ marginLeft: 8 }}>{currentRoute.fullname}</Typography>
</div>
<Divider/>
<div className={classes.uploadContainer} style={{ maxHeight: (windowHeight * 0.80) }}>
<DataGrid
columns={columns}
rows={rows}
pageSize={2}
density='compact'
getRowClassName={(params) =>
params.indexRelativeToCurrentPage % 2 === 0 ? 'even' : 'odd'
}
sx={styles(Theme).dataGrid}
/>
</div>
<div className={classes.buttonGroup}>
<Button variant="contained" className={classes.cancelButton} onClick={this.props.onClose}>
Close
</Button>
</div>
</Paper>
</Modal>
</>
);
}
}

const stateToProps = Obstruction({
files: 'files',
currentRoute: 'currentRoute'
});

export default connect(stateToProps)(withStyles(styles)(FileTable));

0 comments on commit 25bc8b7

Please sign in to comment.