From caf6a359b47d9fa5534f26c0ad43f7bfaceff278 Mon Sep 17 00:00:00 2001 From: Piotr Rogowski Date: Sun, 26 Dec 2021 20:57:00 +0100 Subject: [PATCH] Performance improvements (#352) * Optimize Sidebar performance * Optimize Dialog --- src/components/Dialog.tsx | 118 ++++++++++++++++---------------- src/components/Dialog/Curve.tsx | 28 ++++---- src/components/Log.tsx | 31 ++++++--- src/components/SideBar.tsx | 26 ++++--- 4 files changed, 113 insertions(+), 90 deletions(-) diff --git a/src/components/Dialog.tsx b/src/components/Dialog.tsx index 3ee0e99..f973243 100644 --- a/src/components/Dialog.tsx +++ b/src/components/Dialog.tsx @@ -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([]); const containerRef = useRef(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 && ); - 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 ( ); - }; + }, [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} /> ; - }; - - 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 ( -
- {curveConfig.title} - {renderCurve(curveConfig)} -
- ); - } - - if (tableConfig) { - return ( -
- {renderHelp(tableConfig.help)} - {tableConfig.title} - {renderTable(tableConfig)} -
- ); - } - - return ( - - ); - } + }, [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)} ); - }); + }), [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 ( +
+ {curveConfig.title} + {renderCurve(curveConfig)} +
+ ); + } + + if (tableConfig) { + return ( +
+ {renderHelp(tableConfig.help)} + {tableConfig.title} + {renderTable(tableConfig)} +
+ ); + } + + return ( + + ); + } return (
@@ -411,7 +409,7 @@ const Dialog = ({ wrapperCol={{ span: 10 }} > - {isDataReady && panelsComponents()} + {panelsComponents} {burnButton} diff --git a/src/components/Dialog/Curve.tsx b/src/components/Dialog/Curve.tsx index 37caf58..ca56ae0 100644 --- a/src/components/Dialog/Curve.tsx +++ b/src/components/Dialog/Curve.tsx @@ -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(null); const { sm } = useBreakpoint(); const [options, setOptions] = useState(); const [plotData, setPlotData] = useState(); @@ -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 ; @@ -88,15 +88,17 @@ const Curve = ({ {help} - +
+
+ ); }; diff --git a/src/components/Log.tsx b/src/components/Log.tsx index e885e71..07d85ad 100644 --- a/src/components/Log.tsx +++ b/src/components/Log.tsx @@ -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) => ( - {field.label} - {/* {field.units && ` (${field.units})`} */} + {isExpression(field.label) ? stripExpression(field.label) : field.label} ))} @@ -230,8 +244,7 @@ const Log = ({ ui, config, loadedLogs }: { ui: UIState, config: Config, loadedLo {fields.map((field) => ( - {field.label} - {/* {field.units && ` (${field.units})`} */} + {isExpression(field.label) ? stripExpression(field.label) : field.label} ))} diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx index c3e8f4d..3d90ad4 100644 --- a/src/components/SideBar.tsx +++ b/src/components/SideBar.tsx @@ -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([]); - 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 = ({ } - 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 ; } @@ -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 ( @@ -148,7 +158,7 @@ const SideBar = ({ style={{ height: '100%' }} key={matchedPath.url} > - {Object.keys(tune.constants).length && menusList(config.menus)} + {menus}