Remove markdown editor, lazy load most of the components (#366)

This commit is contained in:
Piotr Rogowski 2022-01-09 16:33:08 +01:00 committed by GitHub
parent bb84f85ef6
commit 808590e81e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1671 additions and 222 deletions

1675
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -37,18 +37,17 @@
"@speedy-tuner/ini": "^0.2.2",
"@speedy-tuner/types": "^0.2.1",
"antd": "^4.18.2",
"easymde": "^2.15.0",
"firebase": "^9.6.1",
"mlg-converter": "^0.5.1",
"nanoid": "^3.1.30",
"pako": "^2.0.4",
"react": "^17.0.1",
"react-dom": "^17.0.2",
"react-markdown": "^7.1.2",
"react-perfect-scrollbar": "^1.5.8",
"react-redux": "^7.2.6",
"react-router-dom": "^5.2.1",
"react-scripts": "^4.0.3",
"react-simplemde-editor": "^5.0.2",
"uplot": "^1.6.18",
"uplot-react": "^1.1.1"
},

View File

@ -154,3 +154,12 @@ select:-webkit-autofill:focus {
.CodeMirror-wrap {
background-color: @main-light !important;
}
.markdown-preview {
background-color: @main-light;
padding: 5px 11px;
border-style: solid;
border-width: 1px;
border-radius: @border-radius-base;
border-color: @main-dark;
}

View File

@ -1,44 +1,46 @@
import {
useLocation,
Switch,
Route,
matchPath,
Redirect,
generatePath,
} from 'react-router-dom';
import {
Layout,
Result,
Skeleton,
} from 'antd';
import { connect } from 'react-redux';
import {
lazy,
ReactNode,
Suspense,
useCallback,
useEffect,
useMemo,
} from 'react';
import {
AppState,
UIState,
Config as ConfigType,
} from '@speedy-tuner/types';
import Dialog from './components/Dialog';
import { loadAll } from './utils/api';
import SideBar, { DialogMatchedPathType } from './components/SideBar';
import TopBar from './components/TopBar';
import StatusBar from './components/StatusBar';
import { Routes } from './routes';
import useStorage from './hooks/useStorage';
import { loadAll } from './utils/api';
import Log from './pages/Log';
import 'react-perfect-scrollbar/dist/css/styles.css';
import './App.less';
import { Routes } from './routes';
import Log from './pages/Log';
import Diagnose from './pages/Diagnose';
import useStorage from './hooks/useStorage';
import useConfig from './hooks/useConfig';
import Login from './pages/auth/Login';
import SignUp from './pages/auth/SignUp';
import ResetPassword from './pages/auth/ResetPassword';
import Upload from './pages/Upload';
// TODO: fix this
// lazy loading this component causes a weird Curve canvas scaling
// const Log = lazy(() => import('./pages/Log'));
const Tune = lazy(() => import('./pages/Tune'));
const Diagnose = lazy(() => import('./pages/Diagnose'));
const Login = lazy(() => import('./pages/auth/Login'));
const SignUp = lazy(() => import('./pages/auth/SignUp'));
const ResetPassword = lazy(() => import('./pages/auth/ResetPassword'));
const Upload = lazy(() => import('./pages/Upload'));
const { Content } = Layout;
@ -51,24 +53,8 @@ const mapStateToProps = (state: AppState) => ({
const App = ({ ui, config }: { ui: UIState, config: ConfigType }) => {
const margin = ui.sidebarCollapsed ? 80 : 250;
// const [lastDialogPath, setLastDialogPath] = useState<string|null>();
const { pathname } = useLocation();
const { storageGetSync } = useStorage();
const { isConfigReady } = useConfig(config);
const lastDialogPath = storageGetSync('lastDialog');
const dialogMatchedPath: DialogMatchedPathType = useMemo(() => matchPath(pathname, {
path: Routes.DIALOG,
exact: true,
}) || { url: '', params: { category: '', dialog: '' } }, [pathname]);
const firstDialogPath = useMemo(() => {
if (!isConfigReady) {
return null;
}
const firstCategory = Object.keys(config.menus)[0];
const firstDialog = Object.keys(config.menus[firstCategory].subMenus)[0];
return generatePath(Routes.DIALOG, { category: firstCategory, dialog: firstDialog });
}, [config.menus, isConfigReady]);
useEffect(() => {
loadAll();
@ -90,7 +76,16 @@ const App = ({ ui, config }: { ui: UIState, config: ConfigType }) => {
<Layout style={{ marginLeft }}>
<Layout className="app-content">
<Content>
{children}
<Suspense fallback={<Skeleton
active
style={{
maxWidth: 600,
margin: '0 auto',
padding: 20,
}}
/>}>
{children}
</Suspense>
</Content>
</Layout>
</Layout>
@ -106,20 +101,9 @@ const App = ({ ui, config }: { ui: UIState, config: ConfigType }) => {
<Redirect to={lastDialogPath || Routes.TUNE} />
</Route>
<Route path={Routes.TUNE}>
<Route path={Routes.TUNE} exact>
{firstDialogPath && <Redirect to={lastDialogPath || firstDialogPath} />}
</Route>
<Layout style={{ marginLeft: margin }}>
<SideBar matchedPath={dialogMatchedPath} />
<Layout className="app-content">
<Content>
<Dialog
name={dialogMatchedPath.params.dialog}
url={dialogMatchedPath.url}
/>
</Content>
</Layout>
</Layout>
<ContentFor marginLeft={margin}>
<Tune />
</ContentFor>
</Route>
<Route path={Routes.LOG}>
<ContentFor marginLeft={margin}>

View File

@ -14,7 +14,7 @@ import {
colorHsl,
formatNumber,
} from '../../utils/number';
import LandscapeNotice from '../Dialog/LandscapeNotice';
import LandscapeNotice from '../Tune/Dialog/LandscapeNotice';
import { Colors } from '../../utils/colors';
import touchZoomPlugin from '../../utils/uPlot/touchZoomPlugin';

View File

@ -6,7 +6,7 @@ import { Grid } from 'antd';
import UplotReact from 'uplot-react';
import uPlot from 'uplot';
import touchZoomPlugin from '../../utils/uPlot/touchZoomPlugin';
import LandscapeNotice from '../Dialog/LandscapeNotice';
import LandscapeNotice from '../Tune/Dialog/LandscapeNotice';
import { CompositeLogEntry } from '../../utils/logs/TriggerLogsParser';
import { Colors } from '../../utils/colors';

View File

@ -6,7 +6,7 @@ import { Grid } from 'antd';
import UplotReact from 'uplot-react';
import uPlot from 'uplot';
import touchZoomPlugin from '../../utils/uPlot/touchZoomPlugin';
import LandscapeNotice from '../Dialog/LandscapeNotice';
import LandscapeNotice from '../Tune/Dialog/LandscapeNotice';
import {
ToothLogEntry,
EntryType,

View File

@ -36,11 +36,11 @@ import Curve from './Dialog/Curve';
import {
parseXy,
parseZ,
} from '../utils/tune/table';
} from '../../utils/tune/table';
import Map from './Dialog/Map';
import { evaluateExpression } from '../utils/tune/expression';
import useStorage from '../hooks/useStorage';
import useConfig from '../hooks/useConfig';
import { evaluateExpression } from '../../utils/tune/expression';
import useStorage from '../../hooks/useStorage';
import useConfig from '../../hooks/useConfig';
interface DialogsAndCurves {
[name: string]: DialogType | CurveType | TableType,
@ -358,7 +358,7 @@ const Dialog = ({
if (isDataReady) {
setPanelsComponents(generatePanelsComponents());
}
// eslint-disable-next-line react-hooks/exhaustive-deps
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isDataReady, url, ui.sidebarCollapsed]);
if (!isDataReady) {

View File

@ -10,7 +10,7 @@ import {
} from 'react';
import UplotReact from 'uplot-react';
import uPlot from 'uplot';
import { Colors } from '../../utils/colors';
import { Colors } from '../../../utils/colors';
import LandscapeNotice from './LandscapeNotice';
import Table from './Curve/Table';

View File

@ -1,7 +1,7 @@
/* eslint-disable react/no-array-index-key */
import { useCallback } from 'react';
import { colorHsl } from '../../../utils/number';
import { colorHsl } from '../../../../utils/number';
const titleProps = { disabled: true };

View File

@ -2,7 +2,7 @@
import { Grid } from 'antd';
import LandscapeNotice from './LandscapeNotice';
import { colorHsl } from '../../utils/number';
import { colorHsl } from '../../../utils/number';
const { useBreakpoint } = Grid;

View File

@ -121,10 +121,7 @@ const Log = ({
'afr',
'dwell',
]);
const {
isConfigReady,
findOutputChannel,
} = useConfig(config);
const { isConfigReady, findOutputChannel } = useConfig(config);
const prepareSelectedFields = useCallback((selectedFields: CheckboxValueType[]) => {
if (!isConfigReady) {
return [];

61
src/pages/Tune.tsx Normal file
View File

@ -0,0 +1,61 @@
import {
useLocation,
Route,
matchPath,
Redirect,
generatePath,
} from 'react-router-dom';
import { connect } from 'react-redux';
import { useMemo } from 'react';
import {
AppState,
UIState,
Config as ConfigType,
} from '@speedy-tuner/types';
import Dialog from '../components/Tune/Dialog';
import SideBar, { DialogMatchedPathType } from '../components/SideBar';
import { Routes } from '../routes';
import useStorage from '../hooks/useStorage';
import useConfig from '../hooks/useConfig';
const mapStateToProps = (state: AppState) => ({
ui: state.ui,
status: state.status,
config: state.config,
});
const Tune = ({ ui, config }: { ui: UIState, config: ConfigType }) => {
const { pathname } = useLocation();
const { storageGetSync } = useStorage();
const lastDialogPath = storageGetSync('lastDialog');
const { isConfigReady } = useConfig(config);
const dialogMatchedPath: DialogMatchedPathType = useMemo(() => matchPath(pathname, {
path: Routes.DIALOG,
exact: true,
}) || { url: '', params: { category: '', dialog: '' } }, [pathname]);
const firstDialogPath = useMemo(() => {
if (!isConfigReady) {
return null;
}
const firstCategory = Object.keys(config.menus)[0];
const firstDialog = Object.keys(config.menus[firstCategory].subMenus)[0];
return generatePath(Routes.DIALOG, { category: firstCategory, dialog: firstDialog });
}, [config.menus, isConfigReady]);
return (
<>
<Route path={Routes.TUNE} exact>
{firstDialogPath && <Redirect to={lastDialogPath || firstDialogPath} />}
</Route>
<SideBar matchedPath={dialogMatchedPath} />
<Dialog
name={dialogMatchedPath.params.dialog}
url={dialogMatchedPath.url}
/>
</>
);
};
export default connect(mapStateToProps)(Tune);

View File

@ -1,7 +1,6 @@
import {
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
import {
@ -13,6 +12,7 @@ import {
Skeleton,
Space,
Switch,
Tabs,
Tooltip,
Typography,
Upload,
@ -30,12 +30,12 @@ import { INI } from '@speedy-tuner/ini';
import { UploadRequestOption } from 'rc-upload/lib/interface';
import { UploadFile } from 'antd/lib/upload/interface';
import { useHistory } from 'react-router-dom';
import ReactMarkdown from 'react-markdown';
import pako from 'pako';
import {
customAlphabet,
nanoid,
} from 'nanoid';
import SimpleMdeReact from 'react-simplemde-editor';
import {
emailNotVerified,
restrictedPage,
@ -54,8 +54,6 @@ import {
} from '../firebase';
import useStorage from '../hooks/useStorage';
import TuneParser from '../utils/tune/TuneParser';
import 'easymde/dist/easymde.min.css';
import TriggerLogsParser from '../utils/logs/TriggerLogsParser';
import LogParser from '../utils/logs/LogParser';
@ -124,7 +122,7 @@ const UploadPage = () => {
const [isPublished, setIsPublished] = useState(false);
const [isPublic, setIsPublic] = useState(true);
const [isListed, setIsListed] = useState(true);
const [description, setDescription] = useState('# My Tune \ndescription');
const [description, setDescription] = useState('# My Tune\n\ndescription');
const [tuneFile, setTuneFile] = useState<UploadedFile | null | false>(null);
const [logFiles, setLogFiles] = useState<UploadedFile>({});
const [toothLogFiles, setToothLogFiles] = useState<UploadedFile>({});
@ -134,7 +132,7 @@ const UploadPage = () => {
const history = useHistory();
const { storageSet, storageGet, storageDelete } = useStorage();
const noop = () => {};
const noop = () => { };
const copyToClipboard = async () => {
if (navigator.clipboard) {
@ -146,11 +144,6 @@ const UploadPage = () => {
const genericError = (error: Error) => notification.error({ message: 'Error', description: error.message });
const editorOptions = useMemo(() => ({
toolbar: false,
autofocus: true,
}), []);
const updateDbData = (tuneId: string, dbData: TuneDbData) => {
try {
return setDoc(fireStoreDoc(db, 'tunes', tuneId), dbData, { merge: true });
@ -559,11 +552,24 @@ const UploadPage = () => {
<Typography.Text type="secondary">(markdown)</Typography.Text>
</Space>
</Divider>
<SimpleMdeReact
onChange={setDescription}
value={description}
options={editorOptions}
/>
<Tabs defaultActiveKey="source">
<Tabs.TabPane tab="Edit" key="source">
<Input.TextArea
rows={10}
showCount
value={description}
onChange={(e) => setDescription(e.target.value)}
maxLength={3_000}
/>
</Tabs.TabPane>
<Tabs.TabPane tab="Preview" key="preview">
<div className="markdown-preview" style={{ minHeight: 230 }}>
<ReactMarkdown>
{description}
</ReactMarkdown>
</div>
</Tabs.TabPane>
</Tabs>
<Space style={{ marginTop: 30 }}>
Show more:
<Switch checked={showOptions} onChange={setShowOptions} />