upgrade to react router 7

This commit is contained in:
weakmap@gmail.com
2025-09-02 20:18:37 +02:00
parent 9db1ffd8eb
commit 9774989eeb
13 changed files with 180 additions and 257 deletions

View File

@@ -7,14 +7,13 @@ import JobMutation from './views/jobs/mutation/JobMutation';
import UserMutator from './views/user/mutation/UserMutator';
import JobInsight from './views/jobs/insights/JobInsight.jsx';
import { useDispatch, useSelector } from 'react-redux';
import { Switch, Redirect } from 'react-router-dom';
import { Routes, Route, Navigate } from 'react-router-dom';
import Logout from './components/logout/Logout';
import Logo from './components/logo/Logo';
import Menu from './components/menu/Menu';
import Login from './views/login/Login';
import Users from './views/user/Users';
import Jobs from './views/jobs/Jobs';
import { Route } from 'react-router';
import './App.less';
import TrackingModal from './components/tracking/TrackingModal.jsx';
@@ -49,10 +48,10 @@ export default function FredyApp() {
const isAdmin = () => currentUser != null && currentUser.isAdmin;
const login = () => (
<Switch>
<Route name="Login" path={'/login'} component={Login} />
<Redirect from="*" to={'/login'} />
</Switch>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="*" element={<Navigate to="/login" replace />} />
</Routes>
);
return loading ? null : needsLogin() ? (
@@ -77,34 +76,49 @@ export default function FredyApp() {
</>
)}
{settings.analyticsEnabled === null && !settings.demoMode && <TrackingModal />}
<Switch>
<Route name="Insufficient Permission" path={'/403'} component={InsufficientPermission} />
<Route name="Create new Job" path={'/jobs/new'} component={JobMutation} />
<Route name="Edit a Job" path={'/jobs/edit/:jobId'} component={JobMutation} />
<Route name="Insights into a Job" path={'/jobs/insights/:jobId'} component={JobInsight} />
<Route name="Job overview" path={'/jobs'} component={Jobs} />
<PermissionAwareRoute
name="Create new User"
<Routes>
<Route path="/403" element={<InsufficientPermission />} />
<Route path="/jobs/new" element={<JobMutation />} />
<Route path="/jobs/edit/:jobId" element={<JobMutation />} />
<Route path="/jobs/insights/:jobId" element={<JobInsight />} />
<Route path="/jobs" element={<Jobs />} />
{/* Permission-aware routes */}
<Route
path="/users/new"
component={<UserMutator />}
currentUser={currentUser}
element={
<PermissionAwareRoute currentUser={currentUser}>
<UserMutator />
</PermissionAwareRoute>
}
/>
<PermissionAwareRoute
name="Edit a user"
<Route
path="/users/edit/:userId"
component={<UserMutator />}
currentUser={currentUser}
element={
<PermissionAwareRoute currentUser={currentUser}>
<UserMutator />
</PermissionAwareRoute>
}
/>
<PermissionAwareRoute name="Users" path="/users" component={<Users />} currentUser={currentUser} />
<PermissionAwareRoute
name="General Settings"
<Route
path="/users"
element={
<PermissionAwareRoute currentUser={currentUser}>
<Users />
</PermissionAwareRoute>
}
/>
<Route
path="/generalSettings"
component={<GeneralSettings />}
currentUser={currentUser}
element={
<PermissionAwareRoute currentUser={currentUser}>
<GeneralSettings />
</PermissionAwareRoute>
}
/>
<Redirect from="/" to={'/jobs'} />
</Switch>
<Route path="/" element={<Navigate to="/jobs" replace />} />
</Routes>
</div>
</div>
);

View File

@@ -2,7 +2,6 @@ import React from 'react';
import { reduxStore } from './services/rematch/store';
import { HashRouter } from 'react-router-dom';
import { createHashHistory } from 'history';
import { Provider } from 'react-redux';
import { createRoot } from 'react-dom/client';
import en_US from '@douyinfe/semi-ui/lib/es/locale/source/en_US';
@@ -10,15 +9,13 @@ import { LocaleProvider } from '@douyinfe/semi-ui';
const container = document.getElementById('fredy');
const root = createRoot(container);
const history = createHashHistory();
import App from './App';
import './Index.less';
root.render(
<Provider store={reduxStore}>
<HashRouter history={history}>
<HashRouter>
<LocaleProvider locale={en_US}>
<App />
</LocaleProvider>

View File

@@ -1,8 +1,8 @@
import React from 'react';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { Tabs, TabPane } from '@douyinfe/semi-ui';
import { useLocation } from 'react-router';
import { useLocation } from 'react-router-dom';
import { IconUser, IconTerminal, IconSetting } from '@douyinfe/semi-icons';
import './Menu.less';
@@ -12,15 +12,10 @@ function parsePathName(name) {
}
const TopMenu = function TopMenu({ isAdmin }) {
const history = useHistory();
const navigate = useNavigate();
const location = useLocation();
return (
<Tabs
className="menu"
type="line"
activeKey={parsePathName(location.pathname)}
onTabClick={(key) => history.push(key)}
>
<Tabs className="menu" type="line" activeKey={parsePathName(location.pathname)} onTabClick={(key) => navigate(key)}>
<TabPane
itemKey="/jobs"
tab={

View File

@@ -1,21 +1,8 @@
import React from 'react';
import { Redirect } from 'react-router-dom';
import { Route } from 'react-router';
import { Navigate } from 'react-router-dom';
export default function PermissionAwareRoute({ currentUser, name, path, component }) {
/**
* Checks if given component should be rendered if current user has given permission enabled. If that's not the case,
* user is redirected to '/403'.
*
* @param permission
* @param component
* @param path
* @returns {*}
*/
const checkIfAdmin = (component, path) => {
return currentUser != null && currentUser.isAdmin ? component : <Redirect from={path} to="/403" />;
};
return <Route name={name} path={path} render={() => checkIfAdmin(component, path)} />;
export default function PermissionAwareRoute({ currentUser, children }) {
const isAdmin = currentUser != null && currentUser.isAdmin;
return isAdmin ? children : <Navigate to="/403" replace />;
}

View File

@@ -3,7 +3,7 @@ import React from 'react';
import JobTable from '../../components/table/JobTable';
import { useSelector, useDispatch } from 'react-redux';
import { xhrDelete, xhrPut } from '../../services/xhr';
import { useHistory } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import ProcessingTimes from './ProcessingTimes';
import { Button, Toast } from '@douyinfe/semi-ui';
import { IconPlusCircle } from '@douyinfe/semi-icons';
@@ -12,7 +12,7 @@ import './Jobs.less';
export default function Jobs() {
const jobs = useSelector((state) => state.jobs.jobs);
const processingTimes = useSelector((state) => state.jobs.processingTimes);
const history = useHistory();
const navigate = useNavigate();
const dispatch = useDispatch();
const onJobRemoval = async (jobId) => {
@@ -43,7 +43,7 @@ export default function Jobs() {
type="primary"
icon={<IconPlusCircle />}
className="jobs__newButton"
onClick={() => history.push('/jobs/new')}
onClick={() => navigate('/jobs/new')}
>
New Job
</Button>
@@ -53,8 +53,8 @@ export default function Jobs() {
jobs={jobs || []}
onJobRemoval={onJobRemoval}
onJobStatusChanged={onJobStatusChanged}
onJobInsight={(jobId) => history.push(`/jobs/insights/${jobId}`)}
onJobEdit={(jobId) => history.push(`/jobs/edit/${jobId}`)}
onJobInsight={(jobId) => navigate(`/jobs/insights/${jobId}`)}
onJobEdit={(jobId) => navigate(`/jobs/edit/${jobId}`)}
/>
</div>
);

View File

@@ -3,7 +3,7 @@ import React from 'react';
import { roundToNext5Minute } from '../../../services/time/timeService';
import Headline from '../../../components/headline/Headline';
import { useDispatch, useSelector } from 'react-redux';
import { useParams } from 'react-router';
import { useParams } from 'react-router-dom';
import Linechart from './Linechart';
const JobInsight = function JobInsight() {

View File

@@ -7,8 +7,7 @@ import ProviderMutator from './components/provider/ProviderMutator';
import Headline from '../../../components/headline/Headline';
import { useDispatch, useSelector } from 'react-redux';
import { xhrPost } from '../../../services/xhr';
import { useHistory } from 'react-router-dom';
import { useParams } from 'react-router';
import { useNavigate, useParams } from 'react-router-dom';
import { Divider, Input, Switch, Button, TagInput, Toast } from '@douyinfe/semi-ui';
import './JobMutation.less';
import { SegmentPart } from '../../../components/segment/SegmentPart';
@@ -34,7 +33,7 @@ export default function JobMutator() {
const [blacklist, setBlacklist] = useState(defaultBlacklist);
const [notificationAdapterData, setNotificationAdapterData] = useState(defaultNotificationAdapter);
const [enabled, setEnabled] = useState(defaultEnabled);
const history = useHistory();
const navigate = useNavigate();
const dispatch = useDispatch();
const isSavingEnabled = () => {
@@ -53,7 +52,7 @@ export default function JobMutator() {
});
await dispatch.jobs.getJobs();
Toast.success('Job successfully saved...');
history.push('/jobs');
navigate('/jobs');
} catch (Exception) {
console.error(Exception.json.message);
Toast.error(Exception.json != null ? Exception.json.message : Exception);
@@ -177,7 +176,7 @@ export default function JobMutator() {
<Switch className="jobMutation__spaceTop" onChange={(checked) => setEnabled(checked)} checked={enabled} />
</SegmentPart>
<Divider margin="1rem" />
<Button type="danger" style={{ marginRight: '1rem' }} onClick={() => history.push('/jobs')}>
<Button type="danger" style={{ marginRight: '1rem' }} onClick={() => navigate('/jobs')}>
Cancel
</Button>
<Button type="primary" icon={<IconPlusCircle />} disabled={!isSavingEnabled()} onClick={mutateJob}>

View File

@@ -3,7 +3,7 @@ import React, { useEffect } from 'react';
import cityBackground from '../../assets/city_background.jpg';
import Logo from '../../components/logo/Logo';
import { xhrPost } from '../../services/xhr';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { Input, Button, Banner, Toast } from '@douyinfe/semi-ui';
@@ -16,7 +16,7 @@ export default function Login() {
const [password, setPassword] = React.useState('');
const [error, setError] = React.useState(null);
const demoMode = useSelector((state) => state.demoMode.demoMode || false);
const history = useHistory();
const navigate = useNavigate();
useEffect(() => {
async function init() {
@@ -46,7 +46,7 @@ export default function Login() {
Toast.success('Login successful!');
await dispatch.user.getCurrentUser();
history.push('/jobs');
navigate('/jobs');
};
return (

View File

@@ -7,7 +7,7 @@ import { IconPlus } from '@douyinfe/semi-icons';
import { Button } from '@douyinfe/semi-ui';
import UserRemovalModal from './UserRemovalModal';
import { xhrDelete } from '../../services/xhr';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router-dom';
import './Users.less';
@@ -16,7 +16,7 @@ const Users = function Users() {
const [loading, setLoading] = React.useState(true);
const users = useSelector((state) => state.user.users);
const [userIdToBeRemoved, setUserIdToBeRemoved] = React.useState(null);
const history = useHistory();
const navigate = useNavigate();
React.useEffect(() => {
async function init() {
@@ -50,7 +50,7 @@ const Users = function Users() {
type="primary"
className="users__newButton"
icon={<IconPlus />}
onClick={() => history.push('/users/new')}
onClick={() => navigate('/users/new')}
>
Create new User
</Button>
@@ -58,7 +58,7 @@ const Users = function Users() {
<UserTable
user={users}
onUserEdit={(userId) => {
history.push(`/users/edit/${userId}`);
navigate(`/users/edit/${userId}`);
}}
onUserRemoval={(userId) => {
setUserIdToBeRemoved(userId);

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { xhrGet, xhrPost } from '../../../services/xhr';
import { useHistory, useParams } from 'react-router';
import { useNavigate, useParams } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { Divider, Input, Switch, Button, Toast } from '@douyinfe/semi-ui';
import './UserMutator.less';
@@ -15,7 +15,7 @@ const UserMutator = function UserMutator() {
const [password2, setPassword2] = React.useState('');
const [isAdmin, setIsAdmin] = React.useState(false);
const history = useHistory();
const navigate = useNavigate();
const dispatch = useDispatch();
React.useEffect(() => {
@@ -50,7 +50,7 @@ const UserMutator = function UserMutator() {
});
await dispatch.user.getUsers();
Toast.success('User successfully saved...');
history.push('/users');
navigate('/users');
} catch (error) {
console.error(error);
Toast.error(error.json.message);
@@ -98,7 +98,7 @@ const UserMutator = function UserMutator() {
<Switch checked={isAdmin} onChange={(checked) => setIsAdmin(checked)} />
</SegmentPart>
<Divider margin="1rem" />
<Button type="danger" style={{ marginRight: '1rem' }} onClick={() => history.push('/users')}>
<Button type="danger" style={{ marginRight: '1rem' }} onClick={() => navigate('/users')}>
Cancel
</Button>
<Button type="primary" icon={<IconPlusCircle />} onClick={saveUser}>