Performance improvements (#352)
* Optimize Sidebar performance * Optimize Dialog
This commit is contained in:
parent
25228fba25
commit
caf6a359b4
|
@ -111,19 +111,8 @@ const Dialog = ({
|
|||
const isDataReady = Object.keys(tune.constants).length && Object.keys(config.constants).length;
|
||||
const { storageSet } = useStorage();
|
||||
const { findConstantOnPage } = useConfig(config);
|
||||
const [canvasWidth, setCanvasWidth] = useState(0);
|
||||
const [panelsComponents, setPanelsComponents] = useState<any[]>([]);
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
const calculateCanvasWidth = useCallback(() => {
|
||||
setCanvasWidth((containerRef.current?.clientWidth || 0) - 20);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
storageSet('lastDialog', url);
|
||||
calculateCanvasWidth();
|
||||
window.addEventListener('resize', calculateCanvasWidth);
|
||||
|
||||
return () => window.removeEventListener('resize', calculateCanvasWidth);
|
||||
}, [calculateCanvasWidth, storageSet, url, ui.sidebarCollapsed]);
|
||||
|
||||
const renderHelp = (link?: string) => (link &&
|
||||
<Popover
|
||||
|
@ -142,7 +131,7 @@ const Dialog = ({
|
|||
</Popover>
|
||||
);
|
||||
|
||||
const renderCurve = (curve: CurveType) => {
|
||||
const renderCurve = useCallback((curve: CurveType) => {
|
||||
const x = tune.constants[curve.xBins[0]];
|
||||
const y = tune.constants[curve.yBins[0]];
|
||||
const xConstant = findConstantOnPage(curve.xBins[0]) as ScalarConstantType;
|
||||
|
@ -150,7 +139,6 @@ const Dialog = ({
|
|||
|
||||
return (
|
||||
<Curve
|
||||
width={canvasWidth}
|
||||
key={curve.yBins[0]}
|
||||
disabled={false} // TODO: evaluate condition
|
||||
help={config.help[curve.yBins[0]]}
|
||||
|
@ -162,9 +150,9 @@ const Dialog = ({
|
|||
yData={parseXy(y.value as string)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
}, [config.help, findConstantOnPage, tune.constants]);
|
||||
|
||||
const renderTable = (table: TableType | RenderedPanel) => {
|
||||
const renderTable = useCallback((table: TableType | RenderedPanel) => {
|
||||
const x = tune.constants[table.xBins[0]];
|
||||
const y = tune.constants[table.yBins[0]];
|
||||
const z = tune.constants[table.zBins[0]];
|
||||
|
@ -181,45 +169,7 @@ const Dialog = ({
|
|||
yUnits={y.units as string}
|
||||
/>
|
||||
</div>;
|
||||
};
|
||||
|
||||
if (!isDataReady) {
|
||||
return skeleton;
|
||||
}
|
||||
|
||||
const dialogConfig = config.dialogs[name];
|
||||
const curveConfig = config.curves[name];
|
||||
const tableConfig = config.tables[name];
|
||||
|
||||
// standalone dialog / page
|
||||
if (!dialogConfig) {
|
||||
if (curveConfig) {
|
||||
return (
|
||||
<div ref={containerRef} style={containerStyle}>
|
||||
<Divider>{curveConfig.title}</Divider>
|
||||
{renderCurve(curveConfig)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (tableConfig) {
|
||||
return (
|
||||
<div ref={containerRef} style={containerStyle}>
|
||||
{renderHelp(tableConfig.help)}
|
||||
<Divider>{tableConfig.title}</Divider>
|
||||
{renderTable(tableConfig)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Result
|
||||
status="warning"
|
||||
title="Dialog not found"
|
||||
style={{ marginTop: 50 }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}, [tune.constants]);
|
||||
|
||||
const calculateSpan = (type: PanelTypes, dialogsCount: number) => {
|
||||
let xxl = 24;
|
||||
|
@ -283,8 +233,9 @@ const Dialog = ({
|
|||
});
|
||||
};
|
||||
|
||||
// TODO: refactor this
|
||||
resolveDialogs(config.dialogs, name);
|
||||
if (config.dialogs) {
|
||||
resolveDialogs(config.dialogs, name);
|
||||
}
|
||||
|
||||
// remove dummy dialogs and flatten to array
|
||||
const panels = Object.keys(resolvedDialogs).map((dialogName: string): RenderedPanel => {
|
||||
|
@ -324,7 +275,7 @@ const Dialog = ({
|
|||
};
|
||||
});
|
||||
|
||||
const panelsComponents = () => panels.map((panel: RenderedPanel) => {
|
||||
const generatePanelsComponents = useCallback(() => panels.map((panel: RenderedPanel) => {
|
||||
if (panel.type === PanelTypes.FIELDS && panel.fields.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
@ -401,7 +352,54 @@ const Dialog = ({
|
|||
{panel.type === PanelTypes.TABLE && renderTable(panel)}
|
||||
</Col>
|
||||
);
|
||||
});
|
||||
}), [config, findConstantOnPage, panels, renderCurve, renderTable, tune.constants]);
|
||||
|
||||
useEffect(() => {
|
||||
storageSet('lastDialog', url);
|
||||
|
||||
if (isDataReady) {
|
||||
setPanelsComponents(generatePanelsComponents());
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isDataReady, url, ui.sidebarCollapsed]);
|
||||
|
||||
if (!isDataReady) {
|
||||
return skeleton;
|
||||
}
|
||||
|
||||
const dialogConfig = config.dialogs[name];
|
||||
const curveConfig = config.curves[name];
|
||||
const tableConfig = config.tables[name];
|
||||
|
||||
// standalone dialog / page
|
||||
if (!dialogConfig) {
|
||||
if (curveConfig) {
|
||||
return (
|
||||
<div ref={containerRef} style={containerStyle}>
|
||||
<Divider>{curveConfig.title}</Divider>
|
||||
{renderCurve(curveConfig)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (tableConfig) {
|
||||
return (
|
||||
<div ref={containerRef} style={containerStyle}>
|
||||
{renderHelp(tableConfig.help)}
|
||||
<Divider>{tableConfig.title}</Divider>
|
||||
{renderTable(tableConfig)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Result
|
||||
status="warning"
|
||||
title="Dialog not found"
|
||||
style={{ marginTop: 50 }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={containerRef} style={containerStyle}>
|
||||
|
@ -411,7 +409,7 @@ const Dialog = ({
|
|||
wrapperCol={{ span: 10 }}
|
||||
>
|
||||
<Row gutter={20}>
|
||||
{isDataReady && panelsComponents()}
|
||||
{panelsComponents}
|
||||
</Row>
|
||||
<Form.Item>
|
||||
{burnButton}
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
} from 'antd';
|
||||
import {
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import UplotReact from 'uplot-react';
|
||||
|
@ -15,7 +16,6 @@ import Table from './Curve/Table';
|
|||
const { useBreakpoint } = Grid;
|
||||
|
||||
const Curve = ({
|
||||
width,
|
||||
xLabel,
|
||||
yLabel,
|
||||
xData,
|
||||
|
@ -25,7 +25,6 @@ const Curve = ({
|
|||
xUnits = '',
|
||||
yUnits = '',
|
||||
}: {
|
||||
width: number,
|
||||
xLabel: string,
|
||||
yLabel: string,
|
||||
xData: number[],
|
||||
|
@ -35,6 +34,7 @@ const Curve = ({
|
|||
xUnits?: string,
|
||||
yUnits?: string,
|
||||
}) => {
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
const { sm } = useBreakpoint();
|
||||
const [options, setOptions] = useState<uPlot.Options>();
|
||||
const [plotData, setPlotData] = useState<uPlot.AlignedData>();
|
||||
|
@ -42,7 +42,7 @@ const Curve = ({
|
|||
useEffect(() => {
|
||||
setPlotData([xData, yData]);
|
||||
setOptions({
|
||||
width,
|
||||
width: containerRef.current?.clientWidth || 0,
|
||||
height: 350,
|
||||
scales: {
|
||||
x: { time: false },
|
||||
|
@ -76,7 +76,7 @@ const Curve = ({
|
|||
points: { size: 9 },
|
||||
},
|
||||
});
|
||||
}, [width, xData, xLabel, xUnits, yData, yLabel, yUnits, sm]);
|
||||
}, [xData, xLabel, xUnits, yData, yLabel, yUnits, sm]);
|
||||
|
||||
if (!sm) {
|
||||
return <LandscapeNotice />;
|
||||
|
@ -88,15 +88,17 @@ const Curve = ({
|
|||
<Typography.Text type="secondary">{help}</Typography.Text>
|
||||
</Typography.Paragraph>
|
||||
<UplotReact options={options!} data={plotData!} />
|
||||
<Table
|
||||
xLabel={xLabel}
|
||||
yLabel={yLabel}
|
||||
xData={xData}
|
||||
yData={yData}
|
||||
disabled={disabled}
|
||||
xUnits={xUnits}
|
||||
yUnits={yUnits}
|
||||
/>
|
||||
<div ref={containerRef}>
|
||||
<Table
|
||||
xLabel={xLabel}
|
||||
yLabel={yLabel}
|
||||
xData={xData}
|
||||
yData={yData}
|
||||
disabled={disabled}
|
||||
xUnits={xUnits}
|
||||
yUnits={yUnits}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -35,6 +35,7 @@ import {
|
|||
OutputChannel,
|
||||
Logs,
|
||||
DatalogEntry,
|
||||
Tune as TuneType,
|
||||
} from '@speedy-tuner/types';
|
||||
import { loadLogs } from '../utils/api';
|
||||
import LogCanvas from './Log/LogCanvas';
|
||||
|
@ -44,24 +45,38 @@ import {
|
|||
msToTime,
|
||||
} from '../utils/number';
|
||||
import useConfig from '../hooks/useConfig';
|
||||
import {
|
||||
isExpression,
|
||||
stripExpression,
|
||||
} from '../utils/tune/expression';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
const { Content } = Layout;
|
||||
const { Step } = Steps;
|
||||
const edgeUnknown = 'Unknown';
|
||||
const margin = 30;
|
||||
const sidebarWidth = 250;
|
||||
const minCanvasHeightInner = 600;
|
||||
|
||||
const mapStateToProps = (state: AppState) => ({
|
||||
ui: state.ui,
|
||||
tune: state.tune,
|
||||
status: state.status,
|
||||
config: state.config,
|
||||
loadedLogs: state.logs,
|
||||
});
|
||||
|
||||
const margin = 30;
|
||||
const sidebarWidth = 250;
|
||||
const minCanvasHeightInner = 600;
|
||||
|
||||
const Log = ({ ui, config, loadedLogs }: { ui: UIState, config: Config, loadedLogs: Logs }) => {
|
||||
const Log = ({
|
||||
ui,
|
||||
config,
|
||||
tune,
|
||||
loadedLogs,
|
||||
}: {
|
||||
ui: UIState,
|
||||
tune: TuneType,
|
||||
config: Config,
|
||||
loadedLogs: Logs,
|
||||
}) => {
|
||||
const { lg } = useBreakpoint();
|
||||
const { Sider } = Layout;
|
||||
const [progress, setProgress] = useState(0);
|
||||
|
@ -215,8 +230,7 @@ const Log = ({ ui, config, loadedLogs }: { ui: UIState, config: Config, loadedLo
|
|||
{fields.map((field) => (
|
||||
<Row key={field.name}>
|
||||
<Checkbox key={field.name} value={field.name}>
|
||||
{field.label}
|
||||
{/* {field.units && ` (${field.units})`} */}
|
||||
{isExpression(field.label) ? stripExpression(field.label) : field.label}
|
||||
</Checkbox>
|
||||
</Row>
|
||||
))}
|
||||
|
@ -230,8 +244,7 @@ const Log = ({ ui, config, loadedLogs }: { ui: UIState, config: Config, loadedLo
|
|||
{fields.map((field) => (
|
||||
<Row key={field.name}>
|
||||
<Checkbox key={field.name} value={field.name}>
|
||||
{field.label}
|
||||
{/* {field.units && ` (${field.units})`} */}
|
||||
{isExpression(field.label) ? stripExpression(field.label) : field.label}
|
||||
</Checkbox>
|
||||
</Row>
|
||||
))}
|
||||
|
|
|
@ -9,7 +9,11 @@ import {
|
|||
Link,
|
||||
} from 'react-router-dom';
|
||||
import PerfectScrollbar from 'react-perfect-scrollbar';
|
||||
import { useCallback } from 'react';
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
import {
|
||||
Config as ConfigType,
|
||||
Menus as MenusType,
|
||||
|
@ -79,9 +83,10 @@ const SideBar = ({
|
|||
category: main,
|
||||
dialog: sub,
|
||||
}), []);
|
||||
const [menus, setMenus] = useState<any[]>([]);
|
||||
|
||||
const menusList = useCallback((menus: MenusType) => (
|
||||
Object.keys(menus).map((menuName: string) => {
|
||||
const menusList = useCallback((types: MenusType) => (
|
||||
Object.keys(types).map((menuName: string) => {
|
||||
if (SKIP_MENUS.includes(menuName)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -90,9 +95,9 @@ const SideBar = ({
|
|||
<SubMenu
|
||||
key={`/${menuName}`}
|
||||
icon={<Icon name={menuName} />}
|
||||
title={menus[menuName].title}
|
||||
title={types[menuName].title}
|
||||
>
|
||||
{Object.keys(menus[menuName].subMenus).map((subMenuName: string) => {
|
||||
{Object.keys(types[menuName].subMenus).map((subMenuName: string) => {
|
||||
if (subMenuName === 'std_separator') {
|
||||
return <Menu.Divider key={buildLink(menuName, subMenuName)} />;
|
||||
}
|
||||
|
@ -101,10 +106,9 @@ const SideBar = ({
|
|||
return null;
|
||||
}
|
||||
|
||||
const subMenu = menus[menuName].subMenus[subMenuName];
|
||||
const subMenu = types[menuName].subMenus[subMenuName];
|
||||
let enabled = true;
|
||||
|
||||
// TODO: optimize this!
|
||||
if (subMenu.condition) {
|
||||
enabled = checkCondition(subMenu.condition);
|
||||
}
|
||||
|
@ -124,6 +128,12 @@ const SideBar = ({
|
|||
})
|
||||
), [buildLink, checkCondition]);
|
||||
|
||||
useEffect(() => {
|
||||
if (Object.keys(tune.constants).length) {
|
||||
setMenus(menusList(config.menus));
|
||||
}
|
||||
}, [config.menus, menusList, tune.constants]);
|
||||
|
||||
if (!isConfigReady) {
|
||||
return (
|
||||
<Sider {...siderProps} className="app-sidebar" >
|
||||
|
@ -148,7 +158,7 @@ const SideBar = ({
|
|||
style={{ height: '100%' }}
|
||||
key={matchedPath.url}
|
||||
>
|
||||
{Object.keys(tune.constants).length && menusList(config.menus)}
|
||||
{menus}
|
||||
</Menu>
|
||||
</PerfectScrollbar>
|
||||
</Sider>
|
||||
|
|
Loading…
Reference in New Issue