diff --git a/ui/package.json b/ui/package.json
index 45efbe5..58957dd 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -13,6 +13,7 @@
"@testing-library/user-event": "^14.5.2",
"axios": "^1.7.7",
"classnames": "^2.5.1",
+ "history": "^4.10.1",
"eslint-config-prettier": "8.5.*",
"eslint-plugin-prettier": "4.2.*",
"eslint-watch": "^7.0.0",
@@ -26,7 +27,7 @@
"react-dom": "^19.0.0",
"react-i18next": "^15.1.1",
"react-redux": "^9.1.2",
- "react-router-dom": "^6.27.0",
+ "react-router-dom": "^5.3.4",
"react-scripts": "5.0.1",
"react-tooltip": "^5.28.0",
"redux": "^5.0.1",
@@ -71,6 +72,8 @@
},
"resolutions": {
"react": "^19.0.0",
- "react-dom": "^19.0.0"
+ "react-dom": "^19.0.0",
+ "react-router-dom": "^5.3.4",
+ "react-router": "^5.3.4"
}
}
diff --git a/ui/src/App.jsx b/ui/src/App.jsx
index d9627f8..491689c 100644
--- a/ui/src/App.jsx
+++ b/ui/src/App.jsx
@@ -1,7 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { withTranslation } from 'react-i18next';
-import { Outlet } from 'react-router-dom';
import {
connect as connectWS,
disconnect as disconnectWS,
@@ -94,7 +93,7 @@ class App extends React.Component {
}
render() {
- const { t, connected } = this.props;
+ const { t, connected, children } = this.props;
const { username, dashboard, dispatchLogout } = this.props;
const cloudOnline = this.getCurrentTimestamp() - dashboard.cloudOnline < 30;
return (
@@ -211,7 +210,7 @@ class App extends React.Component {
)}
-
+ {children}
@@ -247,6 +246,11 @@ App.propTypes = {
connected: PropTypes.bool.isRequired,
dashboard: PropTypes.object.isRequired,
dispatchGetDashboardInformation: PropTypes.func.isRequired,
+ children: PropTypes.node,
+};
+
+App.defaultProps = {
+ children: null,
};
export default withTranslation()(
diff --git a/ui/src/containers/RequireAuth.jsx b/ui/src/containers/RequireAuth.jsx
index 67f477d..2e682f4 100644
--- a/ui/src/containers/RequireAuth.jsx
+++ b/ui/src/containers/RequireAuth.jsx
@@ -1,12 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
-import { Navigate } from 'react-router-dom';
+import { Redirect } from 'react-router-dom';
export default function RequireAuth({ children }) {
const isAuthenticated = useSelector((s) => s.authentication.loggedIn);
if (!isAuthenticated) {
- return ;
+ return ;
}
return children;
}
diff --git a/ui/src/containers/RequireGuest.jsx b/ui/src/containers/RequireGuest.jsx
index 08b22b5..69eedf9 100644
--- a/ui/src/containers/RequireGuest.jsx
+++ b/ui/src/containers/RequireGuest.jsx
@@ -1,16 +1,16 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
-import { Navigate } from 'react-router-dom';
+import { Redirect } from 'react-router-dom';
export default function RequireGuest({ children }) {
const isAuthenticated = useSelector((s) => s.authentication.loggedIn);
const isInstalled = useSelector((s) => s.authentication.installed);
if (!isInstalled) {
- return ;
+ return ;
}
if (isAuthenticated) {
- return ;
+ return ;
}
return children;
}
diff --git a/ui/src/containers/RequireInstall.jsx b/ui/src/containers/RequireInstall.jsx
index 9f3c2d8..1bc39ca 100644
--- a/ui/src/containers/RequireInstall.jsx
+++ b/ui/src/containers/RequireInstall.jsx
@@ -1,13 +1,13 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
-import { Navigate } from 'react-router-dom';
+import { Redirect } from 'react-router-dom';
export default function RequireInstall({ children }) {
const isAuthenticated = useSelector((s) => s.authentication.loggedIn);
const isInstalled = useSelector((s) => s.authentication.installed);
if (isInstalled) {
- return ;
+ return ;
}
return children;
}
diff --git a/ui/src/history.js b/ui/src/history.js
new file mode 100644
index 0000000..997ede5
--- /dev/null
+++ b/ui/src/history.js
@@ -0,0 +1,4 @@
+import { createBrowserHistory } from 'history';
+
+const history = createBrowserHistory();
+export default history;
diff --git a/ui/src/index.jsx b/ui/src/index.jsx
index 0ccf4c3..49e4a0c 100644
--- a/ui/src/index.jsx
+++ b/ui/src/index.jsx
@@ -1,12 +1,6 @@
-import React, { Suspense, useEffect } from 'react';
+import React, { Suspense } from 'react';
import { createRoot } from 'react-dom/client';
-import {
- BrowserRouter,
- Routes,
- Route,
- Navigate,
- useNavigate,
-} from 'react-router-dom';
+import { Router, Switch, Route, Redirect } from 'react-router-dom';
import { createStore, applyMiddleware, compose } from 'redux';
import { Provider } from 'react-redux';
import reduxWebsocket from '@giantmachines/redux-websocket';
@@ -20,7 +14,7 @@ import Media from './pages/Media/Media';
import Settings from './pages/Settings/Settings';
import RequireAuth from './containers/RequireAuth';
import RequireGuest from './containers/RequireGuest';
-import { setNavigator } from './navigation';
+import history from './history';
import './i18n';
// We get the token from the store to initialise the store.
@@ -66,65 +60,45 @@ const store = createStore(
const Loader = () =>
loading...
;
-// Bridges React Router's navigate function into a module-scoped singleton
-// so Redux thunks (e.g. login/logout) can navigate without a hook.
-function NavigationSetup() {
- const nav = useNavigate();
- useEffect(() => {
- setNavigator(nav);
- }, [nav]);
- return null;
-}
-
const container = document.getElementById('root');
const root = createRoot(container);
root.render(
-
-
+
}>
-
-
-
-
- }
- />
- }>
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
);
diff --git a/ui/src/navigation.js b/ui/src/navigation.js
index 9d19d6c..7a48b14 100644
--- a/ui/src/navigation.js
+++ b/ui/src/navigation.js
@@ -1,16 +1,12 @@
// Lightweight navigation singleton so non-React code (Redux thunks) can
-// trigger client-side navigation. The value is set from a component that
-// has access to React Router's `useNavigate` hook (see NavigationSetup in
-// index.jsx).
+// trigger client-side navigation. Backed by the shared `history` instance
+// passed to react-router's .
+import history from './history';
-let navigatorFn = null;
-
-export const setNavigator = (fn) => {
- navigatorFn = fn;
+export const setNavigator = () => {
+ // Kept for API compatibility; no-op since history is module-scoped.
};
-export const navigate = (path, options) => {
- if (navigatorFn) {
- navigatorFn(path, options);
- }
+export const navigate = (path) => {
+ history.push(path);
};