Update `react-router` (#397)

This commit is contained in:
Piotr Rogowski 2022-01-25 21:18:04 +01:00 committed by GitHub
parent 20299b9998
commit 0899383750
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 132 additions and 243 deletions

165
package-lock.json generated
View File

@ -26,7 +26,7 @@
"react-markdown": "^8.0.0", "react-markdown": "^8.0.0",
"react-perfect-scrollbar": "^1.5.8", "react-perfect-scrollbar": "^1.5.8",
"react-redux": "^7.2.6", "react-redux": "^7.2.6",
"react-router-dom": "^5.3.0", "react-router-dom": "^6.2.1",
"react-scripts": "^5.0.0", "react-scripts": "^5.0.0",
"uplot": "^1.6.18", "uplot": "^1.6.18",
"uplot-react": "^1.1.1" "uplot-react": "^1.1.1"
@ -10012,16 +10012,11 @@
} }
}, },
"node_modules/history": { "node_modules/history": {
"version": "4.10.1", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", "resolved": "https://registry.npmjs.org/history/-/history-5.2.0.tgz",
"integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", "integrity": "sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.1.2", "@babel/runtime": "^7.7.6"
"loose-envify": "^1.2.0",
"resolve-pathname": "^3.0.0",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0",
"value-equal": "^1.0.1"
} }
}, },
"node_modules/hoist-non-react-statics": { "node_modules/hoist-non-react-statics": {
@ -10755,11 +10750,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
},
"node_modules/isexe": { "node_modules/isexe": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@ -13758,19 +13748,6 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/mini-create-react-context": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz",
"integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==",
"dependencies": {
"@babel/runtime": "^7.12.1",
"tiny-warning": "^1.0.3"
},
"peerDependencies": {
"prop-types": "^15.0.0",
"react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
}
},
"node_modules/mini-css-extract-plugin": { "node_modules/mini-css-extract-plugin": {
"version": "2.5.3", "version": "2.5.3",
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz",
@ -14459,14 +14436,6 @@
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
}, },
"node_modules/path-to-regexp": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
"integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
"dependencies": {
"isarray": "0.0.1"
}
},
"node_modules/path-type": { "node_modules/path-type": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
@ -16868,40 +16837,27 @@
} }
}, },
"node_modules/react-router": { "node_modules/react-router": {
"version": "5.2.1", "version": "6.2.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.1.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz",
"integrity": "sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ==", "integrity": "sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.12.13", "history": "^5.2.0"
"history": "^4.9.0",
"hoist-non-react-statics": "^3.1.0",
"loose-envify": "^1.3.1",
"mini-create-react-context": "^0.4.0",
"path-to-regexp": "^1.7.0",
"prop-types": "^15.6.2",
"react-is": "^16.6.0",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"react": ">=15" "react": ">=16.8"
} }
}, },
"node_modules/react-router-dom": { "node_modules/react-router-dom": {
"version": "5.3.0", "version": "6.2.1",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.0.tgz", "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz",
"integrity": "sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ==", "integrity": "sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.12.13", "history": "^5.2.0",
"history": "^4.9.0", "react-router": "6.2.1"
"loose-envify": "^1.3.1",
"prop-types": "^15.6.2",
"react-router": "5.2.1",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"react": ">=15" "react": ">=16.8",
"react-dom": ">=16.8"
} }
}, },
"node_modules/react-scripts": { "node_modules/react-scripts": {
@ -17284,11 +17240,6 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/resolve-pathname": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
"integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
},
"node_modules/resolve-url-loader": { "node_modules/resolve-url-loader": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz",
@ -19299,11 +19250,6 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/value-equal": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",
"integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="
},
"node_modules/vary": { "node_modules/vary": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@ -27657,16 +27603,11 @@
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
}, },
"history": { "history": {
"version": "4.10.1", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", "resolved": "https://registry.npmjs.org/history/-/history-5.2.0.tgz",
"integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", "integrity": "sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig==",
"requires": { "requires": {
"@babel/runtime": "^7.1.2", "@babel/runtime": "^7.7.6"
"loose-envify": "^1.2.0",
"resolve-pathname": "^3.0.0",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0",
"value-equal": "^1.0.1"
} }
}, },
"hoist-non-react-statics": { "hoist-non-react-statics": {
@ -28155,11 +28096,6 @@
"is-docker": "^2.0.0" "is-docker": "^2.0.0"
} }
}, },
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
},
"isexe": { "isexe": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@ -30289,15 +30225,6 @@
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
}, },
"mini-create-react-context": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz",
"integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==",
"requires": {
"@babel/runtime": "^7.12.1",
"tiny-warning": "^1.0.3"
}
},
"mini-css-extract-plugin": { "mini-css-extract-plugin": {
"version": "2.5.3", "version": "2.5.3",
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz",
@ -30807,14 +30734,6 @@
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
}, },
"path-to-regexp": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
"integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
"requires": {
"isarray": "0.0.1"
}
},
"path-type": { "path-type": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
@ -32415,34 +32334,20 @@
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==" "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A=="
}, },
"react-router": { "react-router": {
"version": "5.2.1", "version": "6.2.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.1.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz",
"integrity": "sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ==", "integrity": "sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==",
"requires": { "requires": {
"@babel/runtime": "^7.12.13", "history": "^5.2.0"
"history": "^4.9.0",
"hoist-non-react-statics": "^3.1.0",
"loose-envify": "^1.3.1",
"mini-create-react-context": "^0.4.0",
"path-to-regexp": "^1.7.0",
"prop-types": "^15.6.2",
"react-is": "^16.6.0",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0"
} }
}, },
"react-router-dom": { "react-router-dom": {
"version": "5.3.0", "version": "6.2.1",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.0.tgz", "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz",
"integrity": "sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ==", "integrity": "sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA==",
"requires": { "requires": {
"@babel/runtime": "^7.12.13", "history": "^5.2.0",
"history": "^4.9.0", "react-router": "6.2.1"
"loose-envify": "^1.3.1",
"prop-types": "^15.6.2",
"react-router": "5.2.1",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0"
} }
}, },
"react-scripts": { "react-scripts": {
@ -32741,11 +32646,6 @@
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
}, },
"resolve-pathname": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
"integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
},
"resolve-url-loader": { "resolve-url-loader": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz",
@ -34226,11 +34126,6 @@
} }
} }
}, },
"value-equal": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",
"integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="
},
"vary": { "vary": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",

View File

@ -48,7 +48,7 @@
"react-markdown": "^8.0.0", "react-markdown": "^8.0.0",
"react-perfect-scrollbar": "^1.5.8", "react-perfect-scrollbar": "^1.5.8",
"react-redux": "^7.2.6", "react-redux": "^7.2.6",
"react-router-dom": "^5.3.0", "react-router-dom": "^6.2.1",
"react-scripts": "^5.0.0", "react-scripts": "^5.0.0",
"uplot": "^1.6.18", "uplot": "^1.6.18",
"uplot-react": "^1.1.1" "uplot-react": "^1.1.1"

View File

@ -1,8 +1,7 @@
import { import {
Switch, Routes as ReactRoutes,
Route, Route,
useLocation, useMatch,
matchPath,
} from 'react-router-dom'; } from 'react-router-dom';
import { import {
Layout, Layout,
@ -16,7 +15,6 @@ import {
Suspense, Suspense,
useCallback, useCallback,
useEffect, useEffect,
useMemo,
} from 'react'; } from 'react';
import TopBar from './components/TopBar'; import TopBar from './components/TopBar';
import StatusBar from './components/StatusBar'; import StatusBar from './components/StatusBar';
@ -64,12 +62,8 @@ const App = ({ ui, navigation }: { ui: UIState, navigation: NavigationState }) =
// const [lastDialogPath, setLastDialogPath] = useState<string|null>(); // const [lastDialogPath, setLastDialogPath] = useState<string|null>();
// const lastDialogPath = storageGetSync('lastDialog'); // const lastDialogPath = storageGetSync('lastDialog');
const { pathname } = useLocation(); const tunePathMatch = useMatch(`${Routes.TUNE_ROOT}/*`);
const matchedTunePath = useMemo(() => matchPath(pathname, { const tuneId = tunePathMatch?.params.tuneId;
path: Routes.TUNE_ROOT,
}), [pathname]);
const tuneId = (matchedTunePath?.params as any)?.tuneId;
useEffect(() => { useEffect(() => {
if (tuneId) { if (tuneId) {
@ -125,53 +119,53 @@ const App = ({ ui, navigation }: { ui: UIState, navigation: NavigationState }) =
<> <>
<Layout> <Layout>
<TopBar tuneId={navigation.tuneId} /> <TopBar tuneId={navigation.tuneId} />
<Switch> <ReactRoutes>
<Route path={Routes.ROOT} exact> <Route path={Routes.ROOT} element={
<ContentFor> <ContentFor>
<Hub /> <Hub />
</ContentFor> </ContentFor>
</Route> } />
<Route path={Routes.TUNE_ROOT} exact> <Route path={Routes.TUNE_ROOT} element={
<ContentFor> <ContentFor>
<Info /> <Info />
</ContentFor> </ContentFor>
</Route> } />
<Route path={Routes.TUNE_TUNE}> <Route path={`${Routes.TUNE_TUNE}/*`} element={
<ContentFor marginLeft={margin}> <ContentFor marginLeft={margin}>
<Tune /> <Tune />
</ContentFor> </ContentFor>
</Route> } />
<Route path={Routes.TUNE_LOGS} exact> <Route path={Routes.TUNE_LOGS} element={
<ContentFor marginLeft={margin}> <ContentFor marginLeft={margin}>
<Logs /> <Logs />
</ContentFor> </ContentFor>
</Route> } />
<Route path={Routes.TUNE_DIAGNOSE} exact> <Route path={Routes.TUNE_DIAGNOSE} element={
<ContentFor marginLeft={margin}> <ContentFor marginLeft={margin}>
<Diagnose /> <Diagnose />
</ContentFor> </ContentFor>
</Route> } />
<Route path={Routes.LOGIN} exact> <Route path={Routes.LOGIN} element={
<ContentFor> <ContentFor>
<Login /> <Login />
</ContentFor> </ContentFor>
</Route> } />
<Route path={Routes.SIGN_UP} exact> <Route path={Routes.SIGN_UP} element={
<ContentFor> <ContentFor>
<SignUp /> <SignUp />
</ContentFor> </ContentFor>
</Route> } />
<Route path={Routes.RESET_PASSWORD} exact> <Route path={Routes.RESET_PASSWORD} element={
<ContentFor> <ContentFor>
<ResetPassword /> <ResetPassword />
</ContentFor> </ContentFor>
</Route> } />
<Route path={Routes.UPLOAD} exact> <Route path={Routes.UPLOAD} element={
<ContentFor> <ContentFor>
<Upload /> <Upload />
</ContentFor> </ContentFor>
</Route> } />
</Switch> </ReactRoutes>
<Result <Result
status="warning" status="warning"
title="Page not found" title="Page not found"

View File

@ -33,7 +33,7 @@ import {
CarOutlined, CarOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import { import {
useHistory, useNavigate,
generatePath, generatePath,
} from 'react-router'; } from 'react-router';
import { import {
@ -231,7 +231,7 @@ const buildTuneUrl = (tuneId: string, route: string) => generatePath(route, { tu
const ActionsProvider = (props: CommandPaletteProps) => { const ActionsProvider = (props: CommandPaletteProps) => {
const { config, tune, navigation } = props; const { config, tune, navigation } = props;
const { query } = useKBar(); const { query } = useKBar();
const history = useHistory(); const navigate = useNavigate();
const generateActions = useCallback((types: MenusType) => { const generateActions = useCallback((types: MenusType) => {
const newActions: Action[] = [ const newActions: Action[] = [
@ -241,7 +241,7 @@ const ActionsProvider = (props: CommandPaletteProps) => {
name: 'Info', name: 'Info',
subtitle: 'Basic information about this tune.', subtitle: 'Basic information about this tune.',
icon: <InfoCircleOutlined />, icon: <InfoCircleOutlined />,
perform: () => history.push(buildTuneUrl(navigation.tuneId!, Routes.TUNE_ROOT)), perform: () => navigate(buildTuneUrl(navigation.tuneId!, Routes.TUNE_ROOT)),
}, },
{ {
id: 'LogsAction', id: 'LogsAction',
@ -249,7 +249,7 @@ const ActionsProvider = (props: CommandPaletteProps) => {
name: 'Logs', name: 'Logs',
subtitle: 'Log viewer.', subtitle: 'Log viewer.',
icon: <FundOutlined />, icon: <FundOutlined />,
perform: () => history.push(buildTuneUrl(navigation.tuneId!, Routes.TUNE_LOGS)), perform: () => navigate(buildTuneUrl(navigation.tuneId!, Routes.TUNE_LOGS)),
}, },
{ {
id: 'DiagnoseAction', id: 'DiagnoseAction',
@ -257,7 +257,7 @@ const ActionsProvider = (props: CommandPaletteProps) => {
name: 'Diagnose', name: 'Diagnose',
subtitle: 'Tooth and composite logs viewer.', subtitle: 'Tooth and composite logs viewer.',
icon: <SettingOutlined />, icon: <SettingOutlined />,
perform: () => history.push(buildTuneUrl(navigation.tuneId!, Routes.TUNE_DIAGNOSE)), perform: () => navigate(buildTuneUrl(navigation.tuneId!, Routes.TUNE_DIAGNOSE)),
}, },
]; ];
@ -281,16 +281,17 @@ const ActionsProvider = (props: CommandPaletteProps) => {
section: types[menuName].title, section: types[menuName].title,
name: subMenu.title, name: subMenu.title,
icon: <Icon name={subMenuName} />, icon: <Icon name={subMenuName} />,
perform: () => history.push(buildUrl(navigation.tuneId!, menuName, subMenuName)), perform: () => navigate(buildUrl(navigation.tuneId!, menuName, subMenuName)),
}); });
}); });
}); });
return newActions; return newActions;
}, [history, navigation.tuneId]); }, [navigate, navigation.tuneId]);
useEffect(() => { useEffect(() => {
if (Object.keys(tune.constants).length) { if (Object.keys(tune.constants).length) {
// TODO: unregister old actions
query.registerActions(generateActions(config.menus)); query.registerActions(generateActions(config.menus));
} }
}, [config.menus, generateActions, query, tune.constants]); }, [config.menus, generateActions, query, tune.constants]);
@ -301,7 +302,7 @@ const ActionsProvider = (props: CommandPaletteProps) => {
const CommandPalette = (props: CommandPaletteProps) => { const CommandPalette = (props: CommandPaletteProps) => {
const { children, config, tune, navigation } = props; const { children, config, tune, navigation } = props;
const { logout } = useAuth(); const { logout } = useAuth();
const history = useHistory(); const navigate = useNavigate();
const logoutAction = useCallback(async () => { const logoutAction = useCallback(async () => {
try { try {
@ -320,7 +321,7 @@ const CommandPalette = (props: CommandPaletteProps) => {
name: 'Hub', name: 'Hub',
subtitle: 'Public tunes and logs.', subtitle: 'Public tunes and logs.',
icon: <CarOutlined />, icon: <CarOutlined />,
perform: () => history.push(Routes.ROOT), perform: () => navigate(Routes.ROOT),
}, },
{ {
id: 'ToggleSidebar', id: 'ToggleSidebar',
@ -334,7 +335,7 @@ const CommandPalette = (props: CommandPaletteProps) => {
name: 'Upload', name: 'Upload',
subtitle: 'Upload tune and logs.', subtitle: 'Upload tune and logs.',
icon: <CloudUploadOutlined />, icon: <CloudUploadOutlined />,
perform: () => history.push(Routes.UPLOAD), perform: () => navigate(Routes.UPLOAD),
}, },
{ {
id: 'LoginAction', id: 'LoginAction',
@ -342,7 +343,7 @@ const CommandPalette = (props: CommandPaletteProps) => {
name: 'Login', name: 'Login',
subtitle: 'Login using email, Google or GitHub account.', subtitle: 'Login using email, Google or GitHub account.',
icon: <LoginOutlined />, icon: <LoginOutlined />,
perform: () => history.push(Routes.LOGIN), perform: () => navigate(Routes.LOGIN),
}, },
{ {
id: 'SignUpAction', id: 'SignUpAction',
@ -350,7 +351,7 @@ const CommandPalette = (props: CommandPaletteProps) => {
name: 'Sign-up', name: 'Sign-up',
subtitle: 'Create new account.', subtitle: 'Create new account.',
icon: <UserAddOutlined />, icon: <UserAddOutlined />,
perform: () => history.push(Routes.SIGN_UP), perform: () => navigate(Routes.SIGN_UP),
}, },
{ {
id: 'LogoutAction', id: 'LogoutAction',

View File

@ -1,16 +1,13 @@
import { import {
useCallback, useCallback,
useEffect, useEffect,
useMemo,
} from 'react'; } from 'react';
import { import {
matchPath,
useLocation, useLocation,
useHistory, useNavigate,
} from 'react-router';
import {
Link, Link,
generatePath, generatePath,
useMatch,
} from 'react-router-dom'; } from 'react-router-dom';
import { import {
Layout, Layout,
@ -72,18 +69,14 @@ const TopBar = ({ tuneId }: { tuneId: string | null }) => {
const { sm, lg } = useBreakpoint(); const { sm, lg } = useBreakpoint();
const { pathname } = useLocation(); const { pathname } = useLocation();
const { currentUser, logout } = useAuth(); const { currentUser, logout } = useAuth();
const history = useHistory(); const navigate = useNavigate();
const { query } = useKBar(); const { query } = useKBar();
const buildTuneUrl = (route: string) => tuneId ? generatePath(route, { tuneId }) : null; const buildTuneUrl = (route: string) => tuneId ? generatePath(route, { tuneId }) : null;
const matchedRootPath = useMemo(() => matchPath(pathname, { const rootPathMatch = useMatch(Routes.ROOT);
path: Routes.ROOT, const tuneRootMatch = useMatch(`${Routes.TUNE_ROOT}/*`);
}), [pathname]); const tuneTuneMatch = useMatch(`${Routes.TUNE_TUNE}/*`);
const matchedTuneRootPath = useMemo(() => matchPath(pathname, { const tabMatch = useMatch(`${Routes.TUNE_TAB}/*`);
path: Routes.TUNE_ROOT, const uploadMatch = useMatch(Routes.UPLOAD);
}), [pathname]);
const matchedTabPath = useMemo(() => matchPath(pathname, {
path: Routes.TUNE_TAB,
}), [pathname]);
const logoutClick = useCallback(async () => { const logoutClick = useCallback(async () => {
try { try {
await logout(); await logout();
@ -118,10 +111,10 @@ const TopBar = ({ tuneId }: { tuneId: string | null }) => {
<Col span={14} md={12} sm={16} style={{ textAlign: 'center' }}> <Col span={14} md={12} sm={16} style={{ textAlign: 'center' }}>
<Radio.Group <Radio.Group
key={pathname} key={pathname}
defaultValue={matchedTabPath?.url || matchedTuneRootPath?.url || matchedRootPath?.url || ''} defaultValue={tuneTuneMatch?.pathnameBase || tabMatch?.pathname || tuneRootMatch?.pathname || rootPathMatch?.pathname}
optionType="button" optionType="button"
buttonStyle="solid" buttonStyle="solid"
onChange={(e) => history.push(e.target.value)} onChange={(e) => navigate(e.target.value)}
> >
<Radio.Button value={buildTuneUrl(Routes.ROOT)}> <Radio.Button value={buildTuneUrl(Routes.ROOT)}>
<Space> <Space>
@ -190,7 +183,7 @@ const TopBar = ({ tuneId }: { tuneId: string | null }) => {
<Button icon={<SearchOutlined />} onClick={toggleCommandPalette} /> <Button icon={<SearchOutlined />} onClick={toggleCommandPalette} />
</Tooltip>} </Tooltip>}
<Link to={Routes.UPLOAD}> <Link to={Routes.UPLOAD}>
<Button icon={<CloudUploadOutlined />} type={matchedTabPath?.url === Routes.UPLOAD ? 'primary' : 'default'}> <Button icon={<CloudUploadOutlined />} type={uploadMatch ? 'primary' : 'default'}>
{lg && 'Upload'} {lg && 'Upload'}
</Button> </Button>
</Link> </Link>

View File

@ -7,6 +7,7 @@ import { connect } from 'react-redux';
import { import {
generatePath, generatePath,
Link, Link,
PathMatch,
} from 'react-router-dom'; } from 'react-router-dom';
import PerfectScrollbar from 'react-perfect-scrollbar'; import PerfectScrollbar from 'react-perfect-scrollbar';
import { import {
@ -52,14 +53,6 @@ export const buildUrl = (tuneId: string, main: string, sub: string) => generateP
dialog: sub, dialog: sub,
}); });
export interface DialogMatchedPathType {
url: string;
params: {
category: string;
dialog: string;
};
}
const mapStateToProps = (state: AppState) => ({ const mapStateToProps = (state: AppState) => ({
config: state.config, config: state.config,
tune: state.tune, tune: state.tune,
@ -72,7 +65,7 @@ interface SideBarProps {
tune: TuneType; tune: TuneType;
ui: UIState; ui: UIState;
navigation: NavigationState; navigation: NavigationState;
matchedPath: DialogMatchedPathType; matchedPath: PathMatch<'dialog' | 'tuneId' | 'category'>;
}; };
const SideBar = ({ config, tune, ui, navigation, matchedPath }: SideBarProps) => { const SideBar = ({ config, tune, ui, navigation, matchedPath }: SideBarProps) => {
@ -148,11 +141,11 @@ const SideBar = ({ config, tune, ui, navigation, matchedPath }: SideBarProps) =>
<Sider {...siderProps} className="app-sidebar"> <Sider {...siderProps} className="app-sidebar">
<PerfectScrollbar options={{ suppressScrollX: true }}> <PerfectScrollbar options={{ suppressScrollX: true }}>
<Menu <Menu
defaultSelectedKeys={[matchedPath.url]} defaultSelectedKeys={[matchedPath.pathname]}
defaultOpenKeys={ui.sidebarCollapsed ? [] : [`/${matchedPath.params.category}`]} defaultOpenKeys={ui.sidebarCollapsed ? [] : [`/${matchedPath.params.category}`]}
mode="inline" mode="inline"
style={{ height: '100%' }} style={{ height: '100%' }}
key={matchedPath.url} key={matchedPath.pathname}
> >
{menus} {menus}
</Menu> </Menu>

View File

@ -18,7 +18,7 @@ import {
} from 'react'; } from 'react';
import { import {
generatePath, generatePath,
useHistory, useNavigate,
} from 'react-router'; } from 'react-router';
import useDb from '../hooks/useDb'; import useDb from '../hooks/useDb';
import { TuneDbData } from '../types/dbData'; import { TuneDbData } from '../types/dbData';
@ -48,10 +48,10 @@ const loadingCards = (
const Hub = () => { const Hub = () => {
const [tunes, setTunes] = useState<TuneDbData[]>([]); const [tunes, setTunes] = useState<TuneDbData[]>([]);
const { listTunes } = useDb(); const { listTunes } = useDb();
const history = useHistory(); const navigate = useNavigate();
const [copied, setCopied] = useState(false); const [copied, setCopied] = useState(false);
const goToTune = (tuneId: string) => history.push(generatePath(Routes.TUNE_ROOT, { tuneId })); const goToTune = (tuneId: string) => navigate(generatePath(Routes.TUNE_ROOT, { tuneId }));
const copyToClipboard = async (shareUrl: string) => { const copyToClipboard = async (shareUrl: string) => {
if (navigator.clipboard) { if (navigator.clipboard) {

View File

@ -1,15 +1,17 @@
import { Skeleton } from 'antd';
import { import {
useLocation,
Route,
matchPath,
Redirect,
generatePath, generatePath,
useMatch,
useNavigate,
} from 'react-router-dom'; } from 'react-router-dom';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { useMemo } from 'react'; import {
useEffect,
useMemo,
} from 'react';
import { Config as ConfigType } from '@speedy-tuner/types'; import { Config as ConfigType } from '@speedy-tuner/types';
import Dialog from '../components/Tune/Dialog'; import Dialog from '../components/Tune/Dialog';
import SideBar, { DialogMatchedPathType } from '../components/Tune/SideBar'; import SideBar from '../components/Tune/SideBar';
import { Routes } from '../routes'; import { Routes } from '../routes';
import useConfig from '../hooks/useConfig'; import useConfig from '../hooks/useConfig';
import { import {
@ -24,14 +26,12 @@ const mapStateToProps = (state: AppState) => ({
}); });
const Tune = ({ navigation, config }: { navigation: NavigationState, config: ConfigType }) => { const Tune = ({ navigation, config }: { navigation: NavigationState, config: ConfigType }) => {
const { pathname } = useLocation(); const dialogMatch = useMatch(Routes.TUNE_DIALOG);
const tuneRootMatch = useMatch(Routes.TUNE_TUNE);
// const { storageGetSync } = useBrowserStorage(); // const { storageGetSync } = useBrowserStorage();
// const lastDialogPath = storageGetSync('lastDialog'); // const lastDialogPath = storageGetSync('lastDialog');
const { isConfigReady } = useConfig(config); const { isConfigReady } = useConfig(config);
const dialogMatchedPath: DialogMatchedPathType = useMemo(() => matchPath(pathname, { const navigate = useNavigate();
path: Routes.TUNE_DIALOG,
exact: true,
}) || { url: '', params: { category: '', dialog: '' } }, [pathname]);
const firstDialogPath = useMemo(() => { const firstDialogPath = useMemo(() => {
if (!isConfigReady) { if (!isConfigReady) {
@ -40,6 +40,7 @@ const Tune = ({ navigation, config }: { navigation: NavigationState, config: Con
const firstCategory = Object.keys(config.menus)[0]; const firstCategory = Object.keys(config.menus)[0];
const firstDialog = Object.keys(config.menus[firstCategory].subMenus)[0]; const firstDialog = Object.keys(config.menus[firstCategory].subMenus)[0];
return generatePath(Routes.TUNE_DIALOG, { return generatePath(Routes.TUNE_DIALOG, {
tuneId: navigation.tuneId!, tuneId: navigation.tuneId!,
category: firstCategory, category: firstCategory,
@ -47,15 +48,27 @@ const Tune = ({ navigation, config }: { navigation: NavigationState, config: Con
}); });
}, [config.menus, isConfigReady, navigation.tuneId]); }, [config.menus, isConfigReady, navigation.tuneId]);
useEffect(() => {
if (tuneRootMatch && firstDialogPath) {
navigate(firstDialogPath, { replace: true });
}
}, [firstDialogPath, navigate, tuneRootMatch, isConfigReady]);
// TODO: unify loading indicators across the app
if (!isConfigReady || !dialogMatch) {
return (
<div>
<Skeleton active />
</div>
);
}
return ( return (
<> <>
<Route path={Routes.TUNE_TUNE} exact> <SideBar matchedPath={dialogMatch!} />
{firstDialogPath && <Redirect to={firstDialogPath} />}
</Route>
<SideBar matchedPath={dialogMatchedPath} />
<Dialog <Dialog
name={dialogMatchedPath.params.dialog} name={dialogMatch?.params.dialog!}
url={dialogMatchedPath.url} url={dialogMatch?.pathname || ''}
/> />
</> </>
); );

View File

@ -36,7 +36,7 @@ import { UploadRequestOption } from 'rc-upload/lib/interface';
import { UploadFile } from 'antd/lib/upload/interface'; import { UploadFile } from 'antd/lib/upload/interface';
import { import {
generatePath, generatePath,
useHistory, useNavigate,
} from 'react-router-dom'; } from 'react-router-dom';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import pako from 'pako'; import pako from 'pako';
@ -114,7 +114,7 @@ const UploadPage = () => {
const [customIniFile, setCustomIniFile] = useState<UploadedFile | null>(null); const [customIniFile, setCustomIniFile] = useState<UploadedFile | null>(null);
const hasNavigatorShare = navigator.share !== undefined; const hasNavigatorShare = navigator.share !== undefined;
const { currentUser, refreshToken } = useAuth(); const { currentUser, refreshToken } = useAuth();
const history = useHistory(); const navigate = useNavigate();
const { removeFile, uploadFile, basePathForFile } = useServerStorage(); const { removeFile, uploadFile, basePathForFile } = useServerStorage();
const { updateData } = useDb(); const { updateData } = useDb();
const requiredRules = [{ required: true, message: 'This field is required!' }]; const requiredRules = [{ required: true, message: 'This field is required!' }];
@ -122,7 +122,7 @@ const UploadPage = () => {
const noop = () => { }; const noop = () => { };
const goToNewTune = () => history.push(generatePath(Routes.TUNE_ROOT, { const goToNewTune = () => navigate(generatePath(Routes.TUNE_ROOT, {
tuneId: newTuneId!, tuneId: newTuneId!,
})); }));
@ -409,7 +409,7 @@ const UploadPage = () => {
const prepareData = useCallback(async () => { const prepareData = useCallback(async () => {
if (!currentUser) { if (!currentUser) {
restrictedPage(); restrictedPage();
history.push(Routes.LOGIN); navigate(Routes.LOGIN);
return; return;
} }
@ -418,7 +418,7 @@ const UploadPage = () => {
await refreshToken(); await refreshToken();
if (!currentUser.emailVerified) { if (!currentUser.emailVerified) {
emailNotVerified(); emailNotVerified();
history.push(Routes.LOGIN); navigate(Routes.LOGIN);
return; return;
} }
@ -432,11 +432,11 @@ const UploadPage = () => {
const tuneId = nanoidCustom(); const tuneId = nanoidCustom();
setNewTuneId(tuneId); setNewTuneId(tuneId);
console.log('New tuneId:', tuneId); console.log('New tuneId:', tuneId);
}, [currentUser, history, refreshToken]); }, [currentUser, navigate, refreshToken]);
useEffect(() => { useEffect(() => {
prepareData(); prepareData();
}, [currentUser, history, prepareData, refreshToken]); }, [currentUser, prepareData, refreshToken]);
const uploadButton = ( const uploadButton = (
<Space direction="vertical"> <Space direction="vertical">

View File

@ -17,7 +17,7 @@ import {
} from '@ant-design/icons'; } from '@ant-design/icons';
import { import {
Link, Link,
useHistory, useNavigate,
} from 'react-router-dom'; } from 'react-router-dom';
import { useAuth } from '../../contexts/AuthContext'; import { useAuth } from '../../contexts/AuthContext';
import { Routes } from '../../routes'; import { Routes } from '../../routes';
@ -37,9 +37,9 @@ const Login = () => {
const [isGoogleLoading, setIsGoogleLoading] = useState(false); const [isGoogleLoading, setIsGoogleLoading] = useState(false);
const [isGithubLoading, setIsGithubLoading] = useState(false); const [isGithubLoading, setIsGithubLoading] = useState(false);
const { login, googleAuth, githubAuth } = useAuth(); const { login, googleAuth, githubAuth } = useAuth();
const history = useHistory(); const navigate = useNavigate();
const isAnythingLoading = isEmailLoading || isGoogleLoading || isGithubLoading; const isAnythingLoading = isEmailLoading || isGoogleLoading || isGithubLoading;
const redirectAfterLogin = useCallback(() => history.push(Routes.UPLOAD), [history]); const redirectAfterLogin = useCallback(() => navigate(Routes.UPLOAD), [navigate]);
const googleLogin = useCallback(async () => { const googleLogin = useCallback(async () => {
setIsGoogleLoading(true); setIsGoogleLoading(true);

View File

@ -8,7 +8,7 @@ import {
import { MailOutlined } from '@ant-design/icons'; import { MailOutlined } from '@ant-design/icons';
import { import {
Link, Link,
useHistory, useNavigate,
} from 'react-router-dom'; } from 'react-router-dom';
import { useAuth } from '../../contexts/AuthContext'; import { useAuth } from '../../contexts/AuthContext';
import { Routes } from '../../routes'; import { Routes } from '../../routes';
@ -25,14 +25,14 @@ const ResetPassword = () => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const { resetPassword } = useAuth(); const { resetPassword } = useAuth();
const history = useHistory(); const navigate = useNavigate();
const onFinish = async ({ email }: { form: any, email: string }) => { const onFinish = async ({ email }: { form: any, email: string }) => {
setIsLoading(true); setIsLoading(true);
try { try {
await resetPassword(email); await resetPassword(email);
resetSuccessful(); resetSuccessful();
history.push(Routes.LOGIN); navigate(Routes.LOGIN);
} catch (error) { } catch (error) {
form.resetFields(); form.resetFields();
console.warn(error); console.warn(error);

View File

@ -11,7 +11,7 @@ import {
} from '@ant-design/icons'; } from '@ant-design/icons';
import { import {
Link, Link,
useHistory, useNavigate,
} from 'react-router-dom'; } from 'react-router-dom';
import { useAuth } from '../../contexts/AuthContext'; import { useAuth } from '../../contexts/AuthContext';
import { Routes } from '../../routes'; import { Routes } from '../../routes';
@ -31,7 +31,7 @@ const SignUp = () => {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const { signUp } = useAuth(); const { signUp } = useAuth();
const history = useHistory(); const navigate = useNavigate();
const onFinish = async ({ email, password }: { email: string, password: string }) => { const onFinish = async ({ email, password }: { email: string, password: string }) => {
setIsLoading(true); setIsLoading(true);
@ -39,7 +39,7 @@ const SignUp = () => {
await signUp(email, password); await signUp(email, password);
signUpSuccessful(); signUpSuccessful();
emailNotVerified(); emailNotVerified();
history.push(Routes.ROOT); navigate(Routes.ROOT);
} catch (error) { } catch (error) {
form.resetFields(); form.resetFields();
console.warn(error); console.warn(error);