a lot of improvements

- allow edit custom profiles
- improve styles
- remove test custom profile
This commit is contained in:
jjavierdguezas 2020-07-20 11:13:35 +02:00
parent 0b0b6e2a02
commit 30e6897d08
4 changed files with 137 additions and 60 deletions

View file

@ -1,4 +1,4 @@
import React, {useState, useRef} from 'react';
import React, {useState} from 'react';
import cx from 'classnames';
import Button from '@material-ui/core/Button';
import Table from '@material-ui/core/Table';
@ -12,6 +12,7 @@ import CancelOutlinedIcon from '@material-ui/icons/CancelOutlined';
import AddCircleOutlineOutlinedIcon from '@material-ui/icons/AddCircleOutlineOutlined';
import TextField from '@material-ui/core/TextField';
import NumberFormat from 'react-number-format';
import InputAdornment from '@material-ui/core/InputAdornment';
import commonStyles from '../../common.styles.css';
import styles from './styles.css';
@ -41,9 +42,9 @@ export default function ProfileManager({
profiles,
onSave
}) {
const tableRef = useRef(null);
const [currentProfiles, updateProfiles] = useState(profiles);
const [newElement, setNewElement] = useState({type: 'Custom'});
const [editModeRows, toggleEditModeRows] = useState({})
const newElementIsInvalid = (newElement.title != null && (newElement.title.trim() == "" || newElement.title.length > 20 || currentProfiles.filter(x => x.title === newElement.title).length !== 0));
@ -51,8 +52,6 @@ export default function ProfileManager({
if (!newElementIsInvalid && newElement.title != null) {
setNewElement({type: 'Custom'});
updateProfiles([...currentProfiles, newElement]);
tableRef.current.scrollTop = 6;
console.log(tableRef.current);
}
}
@ -60,9 +59,23 @@ export default function ProfileManager({
updateProfiles(currentProfiles.filter(p => p.title !== title));
}
const updateProfile = (title, key, value) => {
const profile = currentProfiles.find(x => x.title === title);
if (profile != null && profile.type === 'Custom') {
profile[key] = value;
updateProfiles([...currentProfiles]);
}
}
const toggleEditMode = (row) => {
if (row.type !== 'Custom') return;
editModeRows[row.title] = !editModeRows[row.title];
toggleEditModeRows({...editModeRows});
}
return (
<div className={cx(styles.profileManagerContainer)}>
<TableContainer ref={tableRef} className={cx(styles.profilesContainer)}>
<TableContainer className={cx(styles.profilesContainer)}>
<Table size="small">
<TableHead className={cx(styles.profilesHeader)}>
<TableRow>
@ -70,18 +83,66 @@ export default function ProfileManager({
<TableCell style={{ width: "21%" }} align="right">Download</TableCell>
<TableCell style={{ width: "21%" }} align="right">Upload</TableCell>
<TableCell style={{ width: "21%" }} align="right">Latency</TableCell>
<TableCell style={{ width: "5%" }} align="right"></TableCell>
<TableCell style={{ width: "5%" }} align="right"/>
</TableRow>
</TableHead>
<TableBody>
{currentProfiles.map((row) => (
<TableRow key={row.title} className={cx(styles.profilesRow)}>
<TableCell component="th" scope="row">
<TableCell component="th" scope="row" className={cx({[styles.customProfile]: row.type === 'Custom'})} onClick={() => toggleEditMode(row)}>
{row.title}
</TableCell>
<TableCell align="right">{row.downloadKps}</TableCell>
<TableCell align="right">{row.uploadKps}</TableCell>
<TableCell align="right">{row.latencyMs}</TableCell>
<TableCell align="right">
{row.type !== 'Online' &&
<TextField
className={cx(styles.numericField, {[styles.numericFieldDisabled]: row.type !== 'Custom' || !editModeRows[row.title]})}
value={row.downloadKps == null ? '' : row.downloadKps}
onChange={(e) => updateProfile(row.title, 'downloadKps', e.target.value)}
fullWidth
variant="outlined"
placeholder={row.type !== 'Custom' || !editModeRows[row.title] ? "": "(optional)"}
InputProps={{
inputComponent: NumberFormatCustom,
endAdornment: <InputAdornment position="end">Kb/s</InputAdornment>,
}}
disabled={row.type !== 'Custom' || !editModeRows[row.title]}
/>
}
</TableCell>
<TableCell align="right">
{row.type !== 'Online' &&
<TextField
className={cx(styles.numericField, {[styles.numericFieldDisabled]: row.type !== 'Custom' || !editModeRows[row.title]})}
value={row.uploadKps == null ? '' : row.uploadKps}
onChange={(e) => updateProfile(row.title, 'uploadKps', e.target.value)}
fullWidth
variant="outlined"
placeholder={row.type !== 'Custom' || !editModeRows[row.title] ? "": "(optional)"}
InputProps={{
inputComponent: NumberFormatCustom,
endAdornment: <InputAdornment position="end">Kb/s</InputAdornment>,
}}
disabled={row.type !== 'Custom' || !editModeRows[row.title]}
/>
}
</TableCell>
<TableCell align="right">
{row.type !== 'Online' &&
<TextField
className={cx(styles.numericField, {[styles.numericFieldDisabled]: row.type !== 'Custom' || !editModeRows[row.title]})}
value={row.latencyMs == null ? '' : row.latencyMs}
onChange={(e) => updateProfile(row.title, 'latencyMs', e.target.value)}
fullWidth
variant="outlined"
placeholder={row.type !== 'Custom' || !editModeRows[row.title] ? "": "(optional)"}
InputProps={{
inputComponent: NumberFormatCustom,
endAdornment: <InputAdornment position="end">ms</InputAdornment>,
}}
disabled={row.type !== 'Custom' || !editModeRows[row.title]}
/>
}
</TableCell>
<TableCell align="right">
{row.type === 'Custom' && <CancelOutlinedIcon className={cx(styles.actionIcon)} onClick={() => removeProfile(row.title)} />}
</TableCell>
@ -94,52 +155,56 @@ export default function ProfileManager({
<TableHead className={cx(styles.profilesHeader)}>
<TableRow>
<TableCell style={{ width: "32%" }}>
<TextField
autoFocus
value={newElement.title || ''}
onChange={(e) => setNewElement({...newElement, title: e.target.value})}
error={newElementIsInvalid}
fullWidth
variant="outlined"
<TextField
autoFocus
value={newElement.title || ''}
onChange={(e) => setNewElement({...newElement, title: e.target.value})}
error={newElementIsInvalid}
fullWidth
variant="outlined"
placeholder="New Profile Name"
className={cx(styles.titleField)}
/>
</TableCell>
<TableCell style={{ width: "21%" }} align="right">
<TextField
className={cx(styles.numericField)}
value={newElement.downloadKps || ''}
onChange={(e) => setNewElement({...newElement, downloadKps: e.target.value})}
fullWidth
variant="outlined"
placeholder="Kb/s (optional)"
className={cx(styles.numericField)}
value={newElement.downloadKps == null ? '' : newElement.downloadKps}
onChange={(e) => setNewElement({...newElement, downloadKps: e.target.value})}
fullWidth
variant="outlined"
placeholder="(optional)"
InputProps={{
inputComponent: NumberFormatCustom,
endAdornment: <InputAdornment position="end">Kb/s</InputAdornment>,
}}
/>
</TableCell>
<TableCell style={{ width: "21%" }} align="right">
<TextField
className={cx(styles.numericField)}
value={newElement.uploadKps || ''}
onChange={(e) => setNewElement({...newElement, uploadKps: e.target.value})}
fullWidth
variant="outlined"
placeholder="Kb/s (optional)"
className={cx(styles.numericField)}
value={newElement.uploadKps == null ? '' : newElement.uploadKps}
onChange={(e) => setNewElement({...newElement, uploadKps: e.target.value})}
fullWidth
variant="outlined"
placeholder="(optional)"
InputProps={{
inputComponent: NumberFormatCustom,
endAdornment: <InputAdornment position="end">Kb/s</InputAdornment>,
}}
/>
</TableCell>
<TableCell style={{ width: "21%" }} align="right">
<TextField
className={cx(styles.numericField)}
value={newElement.latencyMs || ''}
onChange={(e) => setNewElement({...newElement, latencyMs: e.target.value})}
fullWidth
variant="outlined"
placeholder="ms (optional)"
className={cx(styles.numericField)}
value={newElement.latencyMs == null ? '' : newElement.latencyMs}
onChange={(e) => setNewElement({...newElement, latencyMs: e.target.value})}
fullWidth
variant="outlined"
placeholder="(optional)"
InputProps={{
inputComponent: NumberFormatCustom,
endAdornment: <InputAdornment position="end">ms</InputAdornment>,
}}
/>
</TableCell>

View file

@ -1,39 +1,58 @@
.profileManagerContainer {
height: 600px;
padding: 20px;
height: 600px;
padding: 20px;
}
.profilesContainer {
max-height: 430px;
overflow-y: auto;
flex-grow: 1;
max-height: 430px;
overflow-y: auto;
flex-grow: 1;
}
.profilesHeader > tr > th {
font-size: 20px;
font-weight: bold;
font-size: 20px;
font-weight: bold;
}
.profilesRow > th,
td {
padding-right: 16px !important;
}
.profilesRow > th {
margin-right: 16px;
cursor: default;
}
.profilesRow > th.customProfile {
cursor: pointer;
}
.actionIcon {
pointer-events: all;
cursor: pointer;
color: white;
pointer-events: all;
cursor: pointer;
color: white;
}
.actionIcon:hover {
color: #6075ef;
color: #6075ef;
}
.saveButton {
position: absolute !important;
bottom: 25px;
right: 25px;
position: absolute !important;
bottom: 25px;
right: 25px;
}
.numericField * {
text-align: right;
text-align: right;
font-size: 14px !important;
}
.numericFieldDisabled fieldset {
border: 0 !important;
}
.numericFieldDisabled input {
color: white !important;
}
.titleField * {
font-size: 14px !important;
}

View file

@ -29,7 +29,7 @@ const selectStyles = {
? '#ffffff20'
: null,
color: 'white',
':active': {
...selectStyles[':active'],
backgroundColor: !isDisabled && '#ffffff40',
@ -102,7 +102,7 @@ export default function NetworkThrottling({
component="span"
onClick={() => setOpen(true)}
>
Customize Profiles
Manage Profiles
</Button>
<Dialog className={cx(styles.profileManagerDialog)} maxWidth="md" fullWidth open={open} scroll="paper" onClose={closeDialog}>
<AppBar className={classes.appBar} color="secondary">

View file

@ -278,13 +278,6 @@ function getDefaultNetworkThrottlingProfiles(): NetworkThrottlingProfileType[] {
downloadKps: 1475,
uploadKps: 675,
latencyMs: 563
},
{
type: 'Custom',
title: 'Modem 56K',
downloadKps: 56,
uploadKps: 56,
latencyMs: 2000
}
]
}