Added autotune support to speedtest (#1239)

- Also updated tooltip trigger icon size

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>

Co-authored-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
Alex
2021-11-19 02:08:33 -06:00
committed by GitHub
parent 7f5de2d70e
commit 6bacd0a45c
19 changed files with 383 additions and 320 deletions

View File

@@ -24,50 +24,42 @@ const JSONIcon = (props: SVGProps<SVGSVGElement>) => {
className={`min-icon`}
fill={"currentcolor"}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24.726 20.753"
viewBox="0 0 25 25"
>
<g transform="translate(-1649.388 -543.732)">
<g transform="translate(1656.071 552.846)">
<circle
cx="1.5"
cy="1.5"
r="1.5"
transform="translate(-0.329 -0.295)"
<g opacity="1">
<path
d="M6.49106+12.4425C6.49106+11.6141+7.16274+10.9425+7.9913+10.9425C8.81986+10.9425+9.49155+11.6141+9.49155+12.4425C9.49155+13.2709+8.81986+13.9425+7.9913+13.9425C7.16274+13.9425+6.49106+13.2709+6.49106+12.4425Z"
opacity="1"
/>
<path
d="M15.4925+12.4425C15.4925+11.6141+16.1642+10.9425+16.9928+10.9425C17.8213+10.9425+18.493+11.6141+18.493+12.4425C18.493+13.2709+17.8213+13.9425+16.9928+13.9425C16.1642+13.9425+15.4925+13.2709+15.4925+12.4425Z"
opacity="1"
/>
<path
d="M11.4919+12.4425C11.4919+11.6141+12.1636+10.9425+12.9921+10.9425C13.8207+10.9425+14.4924+11.6141+14.4924+12.4425C14.4924+13.2709+13.8207+13.9425+12.9921+13.9425C12.1636+13.9425+11.4919+13.2709+11.4919+12.4425Z"
opacity="1"
/>
</g>
<g opacity="1">
<g opacity="1">
<path
d="M19.0061+2.3235C18.543+2.32366+18.1677+2.69902+18.1677+3.162C18.1677+3.62498+18.543+4.00034+19.0061+4.0005C20.2792+4.00105+21.3113+5.03255+21.3124+6.3055L21.3124+10.7775C21.3122+11.418+21.5574+12.0342+21.9975+12.4995C21.5574+12.9648+21.3122+13.581+21.3124+14.2215L21.3124+18.6935C21.3119+19.9668+20.2796+20.9989+19.0061+20.9995C18.543+20.9997+18.1677+21.375+18.1677+21.838C18.1677+22.301+18.543+22.6763+19.0061+22.6765C21.2047+22.6743+22.9865+20.8928+22.9887+18.6945L22.9887+14.2235C22.9892+13.7609+23.3642+13.3861+23.8268+13.3855C24.2897+13.3855+24.665+13.0103+24.665+12.5475C24.665+12.5325+24.665+12.5175+24.665+12.5015C24.665+12.4855+24.665+12.4715+24.665+12.4555C24.665+11.9927+24.2897+11.6175+23.8268+11.6175C23.3642+11.6169+22.9892+11.2421+22.9887+10.7795L22.9887+6.3055C22.9859+4.10744+21.2045+2.32625+19.0061+2.3235Z"
opacity="1"
/>
<circle
cx="1.5"
cy="1.5"
r="1.5"
transform="translate(8.671 -0.295)"
/>
<circle
cx="1.5"
cy="1.5"
r="1.5"
transform="translate(4.671 -0.295)"
<path
d="M19.0061+2.1235C21.3149+2.12625+23.186+3.99699+23.1887+6.3055L23.1887+10.7775C23.1893+11.1296+23.4746+11.4149+23.8268+11.4155C24.4+11.4161+24.8644+11.8805+24.865+12.4535C24.865+12.4685+24.865+12.4845+24.865+12.4995C24.865+12.5145+24.865+12.5295+24.865+12.5455C24.8644+13.1191+24.3995+13.5839+23.8258+13.5845C23.4736+13.5851+23.1883+13.8704+23.1877+14.2225L23.1877+18.6945C23.185+21.003+21.3139+22.8737+19.0051+22.8765C18.4316+22.8762+17.9669+22.4113+17.9669+21.838C17.9669+21.2647+18.4316+20.7998+19.0051+20.7995C20.1679+20.7984+21.1103+19.8562+21.1114+18.6935L21.1114+14.2235C21.111+13.5949+21.3299+12.986+21.7305+12.5015C21.3299+12.017+21.111+11.4081+21.1114+10.7795L21.1114+6.3055C21.1097+5.14324+20.1675+4.2016+19.0051+4.2005C18.4316+4.20022+17.9669+3.73535+17.9669+3.162C17.9669+2.58865+18.4316+2.12378+19.0051+2.1235L19.0061+2.1235ZM19.0061+22.4765C21.094+22.4737+22.7859+20.7821+22.7887+18.6945L22.7887+14.2235C22.7892+13.6507+23.2529+13.1862+23.8258+13.1845C24.178+13.1839+24.4634+12.8986+24.4639+12.5465C24.4639+12.5345+24.4639+12.5235+24.4639+12.5115L24.4639+12.4905C24.4639+12.4785+24.4639+12.4675+24.4639+12.4555C24.4634+12.1034+24.178+11.8181+23.8258+11.8175C23.2529+11.8164+22.7888+11.3523+22.7877+10.7795L22.7877+6.3055C22.7855+4.21806+21.0938+2.52626+19.0061+2.5235C18.6534+2.5235+18.3674+2.80937+18.3674+3.162C18.3674+3.51463+18.6534+3.8005+19.0061+3.8005C20.3895+3.8016+21.5108+4.92232+21.5125+6.3055L21.5125+10.7775C21.5118+11.3672+21.7378+11.9346+22.1436+12.3625L22.2726+12.4995L22.1436+12.6365C21.7378+13.0644+21.5118+13.6318+21.5125+14.2215L21.5125+18.6935C21.5114+20.0771+20.3898+21.1984+19.0061+21.1995C18.6534+21.1995+18.3674+21.4854+18.3674+21.838C18.3674+22.1906+18.6534+22.4765+19.0061+22.4765Z"
opacity="1"
/>
</g>
<g transform="translate(1649.588 543.932)">
<g transform="translate(17.829 0)">
<path
d="M13.681,0a.838.838,0,0,0,0,1.677,2.307,2.307,0,0,1,2.306,2.305V8.454a2.505,2.505,0,0,0,.685,1.722,2.505,2.505,0,0,0-.685,1.722v4.472a2.307,2.307,0,0,1-2.306,2.306.838.838,0,0,0,0,1.677,3.986,3.986,0,0,0,3.982-3.982V11.9a.839.839,0,0,1,.838-.838.838.838,0,0,0,.838-.838c0-.015,0-.03,0-.046s0-.03,0-.046a.838.838,0,0,0-.838-.838.839.839,0,0,1-.838-.838V3.982A3.987,3.987,0,0,0,13.681,0Z"
transform="translate(-12.843 0)"
/>
<path
d="M13.681-.2a4.187,4.187,0,0,1,4.182,4.182V8.454a.639.639,0,0,0,.638.638,1.039,1.039,0,0,1,1.038,1.038c0,.015,0,.031,0,.046s0,.03,0,.046A1.04,1.04,0,0,1,18.5,11.261a.639.639,0,0,0-.638.638v4.472a4.187,4.187,0,0,1-4.182,4.182,1.038,1.038,0,0,1,0-2.077,2.108,2.108,0,0,0,2.106-2.106V11.9a2.7,2.7,0,0,1,.619-1.722,2.7,2.7,0,0,1-.619-1.722V3.982a2.108,2.108,0,0,0-2.106-2.105,1.038,1.038,0,0,1,0-2.077Zm0,20.353a3.787,3.787,0,0,0,3.782-3.782V11.9A1.04,1.04,0,0,1,18.5,10.861a.639.639,0,0,0,.638-.638c0-.012,0-.023,0-.035v-.021c0-.012,0-.023,0-.035a.639.639,0,0,0-.638-.638,1.04,1.04,0,0,1-1.038-1.038V3.982A3.786,3.786,0,0,0,13.681.2a.638.638,0,0,0,0,1.277,2.508,2.508,0,0,1,2.506,2.505V8.454a2.3,2.3,0,0,0,.631,1.585l.129.137-.129.137a2.3,2.3,0,0,0-.631,1.585v4.472a2.508,2.508,0,0,1-2.506,2.506.638.638,0,0,0,0,1.277Z"
transform="translate(-12.843 0)"
/>
</g>
<g transform="translate(0 0)">
<path
d="M18.5,0a.838.838,0,0,1,0,1.677A2.307,2.307,0,0,0,16.2,3.982V8.454a2.505,2.505,0,0,1-.685,1.722A2.505,2.505,0,0,1,16.2,11.9v4.472A2.307,2.307,0,0,0,18.5,18.676a.838.838,0,0,1,0,1.677,3.986,3.986,0,0,1-3.982-3.982V11.9a.839.839,0,0,0-.838-.838.838.838,0,0,1-.838-.838c0-.015,0-.03,0-.046s0-.03,0-.046a.838.838,0,0,1,.838-.838.839.839,0,0,0,.838-.838V3.982A3.987,3.987,0,0,1,18.5,0Z"
transform="translate(-12.843 0)"
/>
<path
d="M18.5-.2a1.038,1.038,0,0,1,0,2.077A2.108,2.108,0,0,0,16.4,3.982V8.454a2.7,2.7,0,0,1-.619,1.722A2.7,2.7,0,0,1,16.4,11.9v4.472A2.108,2.108,0,0,0,18.5,18.476a1.038,1.038,0,0,1,0,2.077,4.187,4.187,0,0,1-4.182-4.182V11.9a.639.639,0,0,0-.638-.638,1.04,1.04,0,0,1-1.038-1.038c0-.015,0-.031,0-.046s0-.03,0-.046a1.04,1.04,0,0,1,1.038-1.038.639.639,0,0,0,.638-.638V3.982A4.187,4.187,0,0,1,18.5-.2Zm0,20.353a.638.638,0,0,0,0-1.277A2.508,2.508,0,0,1,16,16.371V11.9a2.3,2.3,0,0,0-.631-1.585l-.129-.137.129-.137A2.3,2.3,0,0,0,16,8.454V3.982A2.508,2.508,0,0,1,18.5,1.477.638.638,0,0,0,18.5.2a3.787,3.787,0,0,0-3.782,3.782V8.454a1.04,1.04,0,0,1-1.038,1.038.639.639,0,0,0-.638.638c0,.012,0,.024,0,.035v.021c0,.012,0,.023,0,.035a.639.639,0,0,0,.638.638A1.04,1.04,0,0,1,14.719,11.9v4.472A3.787,3.787,0,0,0,18.5,20.153Z"
transform="translate(-12.843 0)"
/>
</g>
<g opacity="1">
<path
d="M5.99395+2.3235C6.457+2.32366+6.83229+2.69902+6.83229+3.162C6.83229+3.62498+6.457+4.00034+5.99395+4.0005C4.72314+4.00436+3.69467+5.03489+3.69358+6.3055L3.69358+10.7775C3.69377+11.418+3.44861+12.0342+3.00847+12.4995C3.44908+12.9653+3.69429+13.5823+3.69358+14.2235L3.69358+18.6955C3.69522+19.9657+4.72353+20.9956+5.99395+20.9995C6.457+20.9997+6.83229+21.375+6.83229+21.838C6.83229+22.301+6.457+22.6763+5.99395+22.6765C3.79531+22.6743+2.01351+20.8928+2.0113+18.6945L2.0113+14.2235C2.01075+13.7609+1.63583+13.3861+1.17317+13.3855C0.710278+13.3855+0.335032+13.0103+0.335032+12.5475C0.335032+12.5325+0.335032+12.5175+0.335032+12.5015C0.335032+12.4855+0.335032+12.4715+0.335032+12.4555C0.335032+11.9927+0.710278+11.6175+1.17317+11.6175C1.63583+11.6169+2.01075+11.2421+2.0113+10.7795L2.0113+6.3055C2.01406+4.10744+3.79554+2.32625+5.99395+2.3235Z"
opacity="1"
/>
<path
d="M5.99395+2.1235C6.56739+2.12378+7.03211+2.58865+7.03211+3.162C7.03211+3.73535+6.56739+4.20022+5.99395+4.2005C4.83384+4.2049+3.89525+5.14557+3.89361+6.3055L3.89361+10.7775C3.894+11.4061+3.67505+12.015+3.27451+12.4995C3.67549+12.9845+3.89447+13.5943+3.89361+14.2235L3.89361+18.6955C3.8958+19.855+4.83423+20.7951+5.99395+20.7995C6.56739+20.7998+7.03211+21.2646+7.03211+21.838C7.03211+22.4113+6.56739+22.8762+5.99395+22.8765C3.68506+22.8737+1.81403+21.003+1.81127+18.6945L1.81127+14.2235C1.81072+13.8714+1.52535+13.5861+1.17317+13.5855C0.60026+13.5844+0.1361+13.1203+0.135+12.5475C0.135+12.5325+0.135+12.5165+0.135+12.5015C0.135+12.4865+0.135+12.4715+0.135+12.4555C0.1361+11.8827+0.60026+11.4186+1.17317+11.4175C1.52535+11.4169+1.81072+11.1316+1.81127+10.7795L1.81127+6.3055C1.81403+3.99699+3.68506+2.12625+5.99395+2.1235ZM5.99395+22.4765C6.34664+22.4765+6.63255+22.1906+6.63255+21.838C6.63255+21.4854+6.34664+21.1995+5.99395+21.1995C4.61289+21.1951+3.49519+20.0753+3.49354+18.6945L3.49354+14.2235C3.49417+13.6338+3.26825+13.0664+2.86244+12.6385L2.73342+12.5015L2.86244+12.3645C3.26873+11.9361+3.49469+11.3679+3.49354+10.7775L3.49354+6.3055C3.49519+4.92466+4.61289+3.8049+5.99395+3.8005C6.34664+3.8005+6.63255+3.51463+6.63255+3.162C6.63255+2.80937+6.34664+2.5235+5.99395+2.5235C3.90601+2.52625+2.21409+4.2179+2.21134+6.3055L2.21134+10.7775C2.21024+11.3503+1.74608+11.8144+1.17317+11.8155C0.820982+11.8161+0.535616+12.1014+0.535065+12.4535C0.535065+12.4655+0.535065+12.4775+0.535065+12.4885L0.535065+12.5095C0.535065+12.5215+0.535065+12.5325+0.535065+12.5445C0.535616+12.8966+0.820982+13.1819+1.17317+13.1825C1.74764+13.1831+2.21289+13.6491+2.21234+14.2235L2.21234+18.6955C2.21564+20.7823+3.90679+22.4732+5.99395+22.4765Z"
opacity="1"
/>
</g>
</g>
</svg>

View File

@@ -104,8 +104,8 @@ const AutocompleteWrapper = ({
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<div>
<HelpIcon className={classes.tooltip} />
<div className={classes.tooltip}>
<HelpIcon />
</div>
</Tooltip>
</div>

View File

@@ -168,8 +168,8 @@ const CSVMultiSelector = ({
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<div>
<HelpIcon className={classes.tooltip} />
<div className={classes.tooltip}>
<HelpIcon />
</div>
</Tooltip>
</div>

View File

@@ -88,8 +88,8 @@ const CheckboxWrapper = ({
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<div>
<HelpIcon className={classes.tooltip} />
<div className={classes.tooltip}>
<HelpIcon />
</div>
</Tooltip>
</div>

View File

@@ -61,8 +61,8 @@ const CodeMirrorWrapper = ({
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<div>
<HelpIcon className={classes.tooltip} />
<div className={classes.tooltip}>
<HelpIcon />
</div>
</Tooltip>
</div>

View File

@@ -116,8 +116,8 @@ const CommentBoxWrapper = ({
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<div>
<HelpIcon className={classes.tooltip} />
<div className={classes.tooltip}>
<HelpIcon />
</div>
</Tooltip>
</div>

View File

@@ -175,8 +175,8 @@ const DateSelector = forwardRef(
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<div>
<HelpIcon className={classes.tooltip} />
<div className={classes.tooltip}>
<HelpIcon />
</div>
</Tooltip>
</div>

View File

@@ -206,8 +206,8 @@ const DateTimePickerWrapper = ({
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<div>
<HelpIcon className={classes.tooltip} />
<div className={classes.tooltip}>
<HelpIcon />
</div>
</Tooltip>
</div>

View File

@@ -130,8 +130,8 @@ const FileSelector = ({
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<div>
<HelpIcon className={classes.tooltip} />
<div className={classes.tooltip}>
<HelpIcon />
</div>
</Tooltip>
</div>

View File

@@ -234,8 +234,8 @@ const FormSwitchWrapper = ({
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<div>
<HelpIcon className={classes.tooltip} />
<div className={classes.tooltip}>
<HelpIcon />
</div>
</Tooltip>
</div>

View File

@@ -66,6 +66,7 @@ const styles = (theme: Theme) =>
...tooltipHelper,
textBoxContainer: {
flexGrow: 1,
position: "relative",
},
textBoxWithIcon: {
position: "relative",
@@ -163,8 +164,8 @@ const InputBoxWrapper = ({
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<div>
<HelpIcon className={classes.tooltip} />
<div className={classes.tooltip}>
<HelpIcon />
</div>
</Tooltip>
</div>
@@ -189,39 +190,39 @@ const InputBoxWrapper = ({
placeholder={placeholder}
className={classes.inputRebase}
/>
</div>
{overlayIcon && (
<div
className={`${classes.overlayAction} ${
label !== "" ? "withLabel" : ""
}`}
>
<IconButton
onClick={
overlayAction
? () => {
overlayAction();
}
: () => null
}
size={"small"}
disableFocusRipple={false}
disableRipple={false}
disableTouchRipple={false}
{overlayIcon && (
<div
className={`${classes.overlayAction} ${
label !== "" ? "withLabel" : ""
}`}
>
{overlayIcon}
</IconButton>
</div>
)}
{overlayObject && (
<div
className={`${classes.overlayAction} ${
label !== "" ? "withLabel" : ""
}`}
>
{overlayObject}
</div>
)}
<IconButton
onClick={
overlayAction
? () => {
overlayAction();
}
: () => null
}
size={"small"}
disableFocusRipple={false}
disableRipple={false}
disableTouchRipple={false}
>
{overlayIcon}
</IconButton>
</div>
)}
{overlayObject && (
<div
className={`${classes.overlayAction} ${
label !== "" ? "withLabel" : ""
}`}
>
{overlayObject}
</div>
)}
</div>
</Grid>
</React.Fragment>
);

View File

@@ -118,7 +118,7 @@ export const RadioGroupSelector = ({
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<div>
<HelpIcon className={classes.tooltip} />
<HelpIcon />
</div>
</Tooltip>
</div>

View File

@@ -103,8 +103,8 @@ const SelectWrapper = ({
{tooltip !== "" && (
<div className={classes.tooltipContainer}>
<Tooltip title={tooltip} placement="top-start">
<div>
<HelpIcon className={classes.tooltip} />
<div className={classes.tooltip}>
<HelpIcon />
</div>
</Tooltip>
</div>

View File

@@ -50,6 +50,9 @@ export const fieldBasic = {
marginLeft: 5,
display: "flex",
alignItems: "center",
"& .min-icon": {
width: 13,
},
},
switchContainer: {
display: "flex",
@@ -101,7 +104,9 @@ export const modalBasic = {
export const tooltipHelper = {
tooltip: {
fontSize: 16,
"& .min-icon": {
width: 13,
},
},
};

View File

@@ -23,6 +23,7 @@ import LinearProgress, {
interface IProgressBarWrapper {
value: number;
ready: boolean;
indeterminate?: boolean;
}
const BorderLinearProgress = styled(LinearProgress)(() => ({
@@ -36,11 +37,15 @@ const BorderLinearProgress = styled(LinearProgress)(() => ({
},
}));
const ProgressBarWrapper = ({ value, ready }: IProgressBarWrapper) => {
const ProgressBarWrapper = ({
value,
ready,
indeterminate,
}: IProgressBarWrapper) => {
return (
<BorderLinearProgress
variant="determinate"
value={value}
variant={indeterminate && !ready ? "indeterminate" : "determinate"}
value={ready ? 100 : value}
color={ready ? "success" : "primary"}
/>
);

View File

@@ -39,6 +39,8 @@ import { cleanMetrics } from "./utils";
interface ISTResults {
classes: any;
results: SpeedTestResponse[];
start: boolean;
autotune: boolean;
}
const styles = (theme: Theme) =>
@@ -175,11 +177,8 @@ const styles = (theme: Theme) =>
serverIcon: {
width: 55,
},
serverUnit: {
width: 70,
},
serverValue: {
width: 70,
width: 140,
},
serverHost: {
maxWidth: 540,
@@ -194,9 +193,15 @@ const styles = (theme: Theme) =>
objectGeneral: {
marginTop: 15,
},
initialResults: {
fontSize: 20,
fontWeight: "bold",
color: "#000",
textAlign: "center",
},
});
const STResults = ({ classes, results }: ISTResults) => {
const STResults = ({ classes, results, start, autotune }: ISTResults) => {
const [jsonView, setJsonView] = useState<boolean>(false);
const finalRes = results[results.length - 1];
@@ -300,218 +305,238 @@ const STResults = ({ classes, results }: ISTResults) => {
};
const finalResJSON = finalRes ? JSON.stringify(finalRes, null, 4) : "";
const clnMetrics = cleanMetrics(results);
return (
<Fragment>
<Grid container className={classes.objectGeneral}>
<Grid item xs={12} md={6} lg={4}>
<ObjectGeneral
title={
<Fragment>
<DownloadStatIcon />
&nbsp; GET
</Fragment>
}
throughput={getThroughput}
objects={getObjects}
/>
{clnMetrics.length <= 1 && (
<Grid container>
<Grid item xs={12} className={classes.initialResults}>
Please wait while we get {autotune? "the initial" : "the system"} results...
</Grid>
</Grid>
<Grid item xs={12} md={6} lg={4}>
<ObjectGeneral
title={
<Fragment>
<UploadStatIcon />
&nbsp; PUT
</Fragment>
}
throughput={putThroughput}
objects={putObjects}
/>
</Grid>
<Grid item xs={12} md={12} lg={4}>
<ResponsiveContainer width="99%">
<AreaChart data={cleanMetrics(results)}>
<defs>
<linearGradient id="colorPut" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#2781B0" stopOpacity={0.9} />
<stop offset="95%" stopColor="#fff" stopOpacity={0} />
</linearGradient>
<linearGradient id="colorGet" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#4CCB92" stopOpacity={0.9} />
<stop offset="95%" stopColor="#fff" stopOpacity={0} />
</linearGradient>
</defs>
)}
{clnMetrics.length > 1 && (
<Fragment>
<Grid container className={classes.objectGeneral}>
<Grid item xs={12} md={6} lg={4}>
<ObjectGeneral
title={
<Fragment>
<DownloadStatIcon />
&nbsp; GET
</Fragment>
}
throughput={getThroughput}
objects={getObjects}
/>
</Grid>
<Grid item xs={12} md={6} lg={4}>
<ObjectGeneral
title={
<Fragment>
<UploadStatIcon />
&nbsp; PUT
</Fragment>
}
throughput={putThroughput}
objects={putObjects}
/>
</Grid>
<Grid item xs={12} md={12} lg={4}>
<ResponsiveContainer width="99%">
<AreaChart data={clnMetrics}>
<defs>
<linearGradient id="colorPut" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#2781B0" stopOpacity={0.9} />
<stop offset="95%" stopColor="#fff" stopOpacity={0} />
</linearGradient>
<linearGradient id="colorGet" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#4CCB92" stopOpacity={0.9} />
<stop offset="95%" stopColor="#fff" stopOpacity={0} />
</linearGradient>
</defs>
<CartesianGrid
strokeDasharray={"0 0"}
strokeWidth={1}
strokeOpacity={0.5}
stroke={"#F1F1F1"}
vertical={false}
/>
<CartesianGrid
strokeDasharray={"0 0"}
strokeWidth={1}
strokeOpacity={0.5}
stroke={"#F1F1F1"}
vertical={false}
/>
<Area
type="monotone"
dataKey={"get"}
stroke={"#4CCB92"}
fill={"url(#colorGet)"}
fillOpacity={0.3}
strokeWidth={2}
dot={false}
/>
<Area
type="monotone"
dataKey={"put"}
stroke={"#2781B0"}
fill={"url(#colorPut)"}
fillOpacity={0.3}
strokeWidth={2}
dot={false}
/>
</AreaChart>
</ResponsiveContainer>
</Grid>
</Grid>
<br />
<Grid container>
<Grid item xs={12} md={6} className={classes.descriptorLabel}>
{jsonView ? "JSON Results:" : "Detailed Results:"}
</Grid>
<Grid item xs={12} md={6} className={classes.actionButtons}>
<BoxIconButton
aria-label="Download"
onClick={downloadResults}
size="large"
>
<DownloadIcon />
</BoxIconButton>
&nbsp;
<BoxIconButton
aria-label="Download"
onClick={toggleJSONView}
size="large"
>
<JSONIcon />
</BoxIconButton>
</Grid>
</Grid>
<Grid container className={classes.resultsContainer}>
{jsonView ? (
<Fragment>
<CodeMirrorWrapper
value={finalResJSON}
readOnly
onBeforeChange={() => {}}
/>
</Fragment>
) : (
<Fragment>
<Grid
item
xs={12}
sm={12}
md={1}
lg={1}
className={classes.resultsIcon}
alignItems={"flex-end"}
>
<ComputerLineIcon width={45} />
<Area
type="monotone"
dataKey={"get"}
stroke={"#4CCB92"}
fill={"url(#colorGet)"}
fillOpacity={0.3}
strokeWidth={2}
dot={false}
/>
<Area
type="monotone"
dataKey={"put"}
stroke={"#2781B0"}
fill={"url(#colorPut)"}
fillOpacity={0.3}
strokeWidth={2}
dot={false}
/>
</AreaChart>
</ResponsiveContainer>
</Grid>
<Grid
item
xs={12}
sm={6}
md={3}
lg={2}
className={classes.detailedItem}
>
Nodes:&nbsp;<strong>{finalRes.servers}</strong>
</Grid>
<br />
<Grid container>
<Grid item xs={12} md={6} className={classes.descriptorLabel}>
{start ? (
<Fragment>
Preliminar Results:
</Fragment>
) : (
<Fragment>
{jsonView ? "JSON Results:" : "Detailed Results:"}
</Fragment>
)}
</Grid>
<Grid
item
xs={12}
sm={6}
md={3}
lg={2}
className={classes.detailedItem}
>
Drives:&nbsp;<strong>{finalRes.disks}</strong>
<Grid item xs={12} md={6} className={classes.actionButtons}>
{!start && (
<Fragment>
<BoxIconButton
aria-label="Download"
onClick={downloadResults}
size="large"
>
<DownloadIcon />
</BoxIconButton>
&nbsp;
<BoxIconButton
aria-label="Download"
onClick={toggleJSONView}
size="large"
>
<JSONIcon />
</BoxIconButton>
</Fragment>
)}
</Grid>
<Grid
item
xs={12}
sm={6}
md={3}
lg={2}
className={classes.detailedItem}
>
Concurrent:&nbsp;<strong>{finalRes.concurrent}</strong>
</Grid>
<Grid
item
xs={12}
sm={12}
md={12}
lg={5}
className={classes.detailedVersion}
>
<span className={classes.versionIcon}>
<VersionIcon />
</span>{" "}
MinIO VERSION&nbsp;<strong>{finalRes.version}</strong>
</Grid>
<Grid item xs={12} className={classes.tableOverflow}>
<table
className={classes.serversTable}
cellSpacing={0}
cellPadding={0}
>
<thead>
<tr>
<th colSpan={2}>Servers</th>
<th colSpan={2}>GET</th>
<th colSpan={2}>PUT</th>
</tr>
</thead>
<tbody>
{statJoin.map((stats, index) => (
<tr key={`storage-${index.toString()}`}>
<td className={classes.serverIcon}>
<StorageIcon />
</td>
<td className={classes.serverHost}>{stats.host}</td>
{stats.getError && stats.getError !== "" ? (
<td colSpan={2}>{stats.getError}</td>
) : (
<Fragment>
<td className={classes.serverValue}>
{prettyNumber(parseFloat(stats.getValue))}
</Grid>
<Grid container className={classes.resultsContainer}>
{jsonView ? (
<Fragment>
<CodeMirrorWrapper
value={finalResJSON}
readOnly
onBeforeChange={() => {}}
/>
</Fragment>
) : (
<Fragment>
<Grid
item
xs={12}
sm={12}
md={1}
lg={1}
className={classes.resultsIcon}
alignItems={"flex-end"}
>
<ComputerLineIcon width={45} />
</Grid>
<Grid
item
xs={12}
sm={6}
md={3}
lg={2}
className={classes.detailedItem}
>
Nodes:&nbsp;<strong>{finalRes.servers}</strong>
</Grid>
<Grid
item
xs={12}
sm={6}
md={3}
lg={2}
className={classes.detailedItem}
>
Drives:&nbsp;<strong>{finalRes.disks}</strong>
</Grid>
<Grid
item
xs={12}
sm={6}
md={3}
lg={2}
className={classes.detailedItem}
>
Concurrent:&nbsp;<strong>{finalRes.concurrent}</strong>
</Grid>
<Grid
item
xs={12}
sm={12}
md={12}
lg={5}
className={classes.detailedVersion}
>
<span className={classes.versionIcon}>
<VersionIcon />
</span>{" "}
MinIO VERSION&nbsp;<strong>{finalRes.version}</strong>
</Grid>
<Grid item xs={12} className={classes.tableOverflow}>
<table
className={classes.serversTable}
cellSpacing={0}
cellPadding={0}
>
<thead>
<tr>
<th colSpan={2}>Servers</th>
<th>GET</th>
<th>PUT</th>
</tr>
</thead>
<tbody>
{statJoin.map((stats, index) => (
<tr key={`storage-${index.toString()}`}>
<td className={classes.serverIcon}>
<StorageIcon />
</td>
<td className={classes.serverUnit}>
{stats.getUnit}/s.
</td>
</Fragment>
)}
{stats.putError && stats.putError !== "" ? (
<td colSpan={2}>{stats.putError}</td>
) : (
<Fragment>
<td className={classes.serverValue}>
{prettyNumber(parseFloat(stats.putValue))}
</td>
<td className={classes.serverUnit}>
{stats.putUnit}/s.
</td>
</Fragment>
)}
</tr>
))}
</tbody>
</table>
</Grid>
</Fragment>
)}
</Grid>
<td className={classes.serverHost}>{stats.host}</td>
{stats.getError && stats.getError !== "" ? (
<td>{stats.getError}</td>
) : (
<Fragment>
<td className={classes.serverValue}>
{prettyNumber(parseFloat(stats.getValue))}&nbsp;
{stats.getUnit}/s.
</td>
</Fragment>
)}
{stats.putError && stats.putError !== "" ? (
<td>{stats.putError}</td>
) : (
<Fragment>
<td className={classes.serverValue}>
{prettyNumber(parseFloat(stats.putValue))}&nbsp;
{stats.putUnit}/s.
</td>
</Fragment>
)}
</tr>
))}
</tbody>
</table>
</Grid>
</Fragment>
)}
</Grid>
</Fragment>
)}
</Fragment>
);
};

View File

@@ -35,6 +35,7 @@ import InputBoxWrapper from "../Common/FormComponents/InputBoxWrapper/InputBoxWr
import BackLink from "../../../common/BackLink";
import ProgressBarWrapper from "../Common/ProgressBarWrapper/ProgressBarWrapper";
import InputUnitMenu from "../Common/FormComponents/InputUnitMenu/InputUnitMenu";
import CheckboxWrapper from "../Common/FormComponents/CheckboxWrapper/CheckboxWrapper";
interface ISpeedtest {
classes: any;
@@ -79,6 +80,7 @@ const styles = (theme: Theme) =>
justifyContent: "space-between",
"&.open": {
maxHeight: 400,
paddingBottom: 15,
},
},
advancedButton: {
@@ -112,12 +114,13 @@ const Speedtest = ({ classes }: ISpeedtest) => {
const [durationUnit, setDurationUnit] = useState<string>("s");
const [size, setSize] = useState<string>("64");
const [sizeUnit, setSizeUnit] = useState<string>("MB");
const [concurrent, setConcurrent] = useState<string>("");
const [concurrent, setConcurrent] = useState<string>("32");
const [topDate, setTopDate] = useState<number>(0);
const [currentValue, setCurrentValue] = useState<number>(0);
const [totalSeconds, setTotalSeconds] = useState<number>(0);
const [speedometerValue, setSpeedometerValue] = useState<number>(0);
const [advancedOpen, setAdvancedOpen] = useState<boolean>(false);
const [autotune, setAutotune] = useState<boolean>(true);
useEffect(() => {
// begin watch if bucketName in bucketList and start pressed
@@ -128,9 +131,9 @@ const Speedtest = ({ classes }: ISpeedtest) => {
const wsProt = wsProtocol(url.protocol);
const c = new W3CWebSocket(
`${wsProt}://${
url.hostname
}:${port}/ws/speedtest?duration=${duration}${durationUnit}&size=${size}${sizeUnit}${
`${wsProt}://${url.hostname}:${port}/ws/speedtest?${
autotune ? "autotune=true" : ""
}&duration=${duration}${durationUnit}&size=${size}${sizeUnit}${
concurrent.trim() !== "" ? `&concurrent=${concurrent}` : ""
}`
);
@@ -170,7 +173,9 @@ const Speedtest = ({ classes }: ISpeedtest) => {
if (prevStatus) {
prSt = [...prevStatus];
}
return [...prSt, data];
const insertData = data.servers !== 0 ? [data] : [];
return [...prSt, ...insertData];
});
const currTime = moment().unix() / 1000;
@@ -193,7 +198,7 @@ const Speedtest = ({ classes }: ISpeedtest) => {
// reset start status
setStart(false);
}
}, [concurrent, duration, durationUnit, size, sizeUnit, start]);
}, [concurrent, duration, durationUnit, size, sizeUnit, start, autotune]);
useEffect(() => {
const actualSeconds = (topDate - currentValue) / 1000;
@@ -254,6 +259,7 @@ const Speedtest = ({ classes }: ISpeedtest) => {
<ProgressBarWrapper
value={speedometerValue}
ready={currStatus !== null && !start}
indeterminate={autotune && start}
/>
</div>
</Grid>
@@ -281,6 +287,21 @@ const Speedtest = ({ classes }: ISpeedtest) => {
advancedOpen ? "open" : ""
}`}
>
<Grid item xs={12}>
<CheckboxWrapper
checked={autotune}
onChange={(e) => setAutotune(e.target.checked)}
id={"autotune"}
name={"autotune"}
label={"Enable Autotune"}
tooltip={
"Autotune gets the maximum stats for the system by running with multiple configurations at once. \
This configuration is enabled by default and disables the rest of available options"
}
value="true"
disabled={start}
/>
</Grid>
<Grid item xs={12} md={3} className={classes.advancedOption}>
<InputBoxWrapper
id={"duration"}
@@ -290,7 +311,7 @@ const Speedtest = ({ classes }: ISpeedtest) => {
setDuration(e.target.value);
}}
value={duration}
disabled={start}
disabled={start || autotune}
overlayObject={
<InputUnitMenu
id={"duration-unit"}
@@ -300,7 +321,7 @@ const Speedtest = ({ classes }: ISpeedtest) => {
{ label: "miliseconds", value: "ms" },
{ label: "seconds", value: "s" },
]}
disabled={start}
disabled={start || autotune}
/>
}
/>
@@ -314,7 +335,7 @@ const Speedtest = ({ classes }: ISpeedtest) => {
setSize(e.target.value);
}}
value={size}
disabled={start}
disabled={start || autotune}
overlayObject={
<InputUnitMenu
id={"size-unit"}
@@ -325,7 +346,7 @@ const Speedtest = ({ classes }: ISpeedtest) => {
{ label: "MB", value: "MB" },
{ label: "GB", value: "GB" },
]}
disabled={start}
disabled={start || autotune}
/>
}
/>
@@ -341,7 +362,7 @@ const Speedtest = ({ classes }: ISpeedtest) => {
setConcurrent(e.target.value);
}}
value={concurrent}
disabled={start}
disabled={start || autotune}
/>
</Grid>
</Grid>
@@ -349,9 +370,13 @@ const Speedtest = ({ classes }: ISpeedtest) => {
<Grid item xs={12}>
<Fragment>
<Grid item xs={12}>
{!start && currStatus !== null && (
{currStatus !== null && (
<Fragment>
<STResults results={currStatus} />
<STResults
results={currStatus}
start={start}
autotune={autotune}
/>
</Fragment>
)}
</Grid>

View File

@@ -89,6 +89,12 @@ func getSpeedtestOptionsFromReq(req *http.Request) (*madmin.SpeedtestOpts, error
optionsSet.Concurrency = concurrent
autotune := queryPairs.Get("autotune")
if autotune == "true" {
optionsSet.Autotune = true
}
return &optionsSet, nil
}

View File

@@ -116,6 +116,10 @@ func (c wsConn) readMessage() (messageType int, p []byte, err error) {
// on the path.
// Request should come like ws://<host>:<port>/ws/<api>
func serveWS(w http.ResponseWriter, req *http.Request) {
upgrader.CheckOrigin = func(r *http.Request) bool {
return true
}
// Perform authentication before upgrading to a Websocket Connection
// authenticate WS connection with Console
session, err := auth.GetClaimsFromTokenInRequest(req)
@@ -215,7 +219,7 @@ func serveWS(w http.ResponseWriter, req *http.Request) {
}
go wsS3Client.watch(wOptions)
case strings.HasPrefix(wsPath, `/speedtest`):
fmt.Println("Speedtest triggered")
fmt.Println("Speedtest init")
speedtestOpts, err := getSpeedtestOptionsFromReq(req)
if err != nil {