mirror of
https://github.com/Unleash/unleash.git
synced 2025-06-18 01:18:23 +02:00
Fix/redirect woes (#2899)
This PR fixes two problems: (1) The initial redirect put us into an infinite loop when redirecting, because trying to go back to the root would always trigger the initial redirect component. Throwing you back to project screen. (2) Using UI config in the useLastViewedProject to get the basePath introduced a race condition where you needed data from the uiConfig in order to fetch the correct key from local storage. The fix here was to use the basePath coded into the HTML file, so we can synchronously retrieve the correct key at startup. Co-authored-by: kwasniew <kwasniewski.mateusz@gmail.com>
This commit is contained in:
parent
801e31dc4e
commit
1f6db91fde
@ -14,7 +14,8 @@
|
|||||||
"start": "vite",
|
"start": "vite",
|
||||||
"start:prod": "vite build && vite preview",
|
"start:prod": "vite build && vite preview",
|
||||||
"start:sandbox": "UNLEASH_API=https://sandbox.getunleash.io/ospro yarn run start",
|
"start:sandbox": "UNLEASH_API=https://sandbox.getunleash.io/ospro yarn run start",
|
||||||
"start:enterprise": "UNLEASH_API=https://unleash.herokuapp.com yarn run start",
|
"start:demo2": "UNLEASH_API=https://sandbox.getunleash.io/ UNLEASH_BASE_PATH=/demo2/ yarn run start",
|
||||||
|
"start:enterprise": "UNLEASH_API=https://unleash.herokuapp.com VITE_TEST_REDIRECT=true yarn run start",
|
||||||
"start:demo": "UNLEASH_BASE_PATH=/demo/ yarn start",
|
"start:demo": "UNLEASH_BASE_PATH=/demo/ yarn start",
|
||||||
"test": "tsc && vitest run",
|
"test": "tsc && vitest run",
|
||||||
"test:snapshot": "yarn test -u",
|
"test:snapshot": "yarn test -u",
|
||||||
@ -111,7 +112,9 @@
|
|||||||
"resolutions": {
|
"resolutions": {
|
||||||
"@codemirror/state": "6.2.0",
|
"@codemirror/state": "6.2.0",
|
||||||
"@xmldom/xmldom": "^0.8.4",
|
"@xmldom/xmldom": "^0.8.4",
|
||||||
"json5": "^2.2.2"
|
"json5": "^2.2.2",
|
||||||
|
"@types/react": "17.0.52",
|
||||||
|
"@types/react-dom": "17.0.18"
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"moduleNameMapper": {
|
"moduleNameMapper": {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Suspense, useCallback, useEffect, useState } from 'react';
|
import { Suspense, useCallback, useEffect, useState, useRef } from 'react';
|
||||||
import { Navigate, Route, Routes } from 'react-router-dom';
|
import { Route, Routes, useNavigate } from 'react-router-dom';
|
||||||
import { ErrorBoundary } from 'react-error-boundary';
|
import { ErrorBoundary } from 'react-error-boundary';
|
||||||
import { Error } from 'component/layout/Error/Error';
|
import { Error } from 'component/layout/Error/Error';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
@ -24,9 +24,10 @@ import { styled } from '@mui/material';
|
|||||||
const InitialRedirect = () => {
|
const InitialRedirect = () => {
|
||||||
const { lastViewed } = useLastViewedProject();
|
const { lastViewed } = useLastViewedProject();
|
||||||
const { projects, loading } = useProjects();
|
const { projects, loading } = useProjects();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const ref = useRef<{ redirected: boolean }>({ redirected: false });
|
||||||
|
|
||||||
const [redirectTo, setRedirectTo] = useState<string | undefined>();
|
// Redirect based on project and last viewed
|
||||||
|
|
||||||
const getRedirect = useCallback(() => {
|
const getRedirect = useCallback(() => {
|
||||||
if (projects && lastViewed) {
|
if (projects && lastViewed) {
|
||||||
return `/projects/${lastViewed}`;
|
return `/projects/${lastViewed}`;
|
||||||
@ -39,17 +40,22 @@ const InitialRedirect = () => {
|
|||||||
return '/projects';
|
return '/projects';
|
||||||
}, [lastViewed, projects]);
|
}, [lastViewed, projects]);
|
||||||
|
|
||||||
useEffect(() => {
|
const redirect = () => {
|
||||||
if (!loading) {
|
ref.current = { redirected: true };
|
||||||
setRedirectTo(getRedirect());
|
navigate(getRedirect(), { replace: true });
|
||||||
}
|
};
|
||||||
}, [loading, getRedirect]);
|
|
||||||
|
|
||||||
if (loading || !redirectTo) {
|
useEffect(() => {
|
||||||
|
if (ref.current?.redirected === true) return;
|
||||||
|
|
||||||
|
redirect();
|
||||||
|
}, [getRedirect]);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
return <Loader />;
|
return <Loader />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Navigate to={redirectTo} />;
|
return <></>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledContainer = styled('div')(() => ({
|
const StyledContainer = styled('div')(() => ({
|
||||||
@ -109,16 +115,25 @@ export const App = () => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
<Route
|
|
||||||
path="/"
|
|
||||||
element={<InitialRedirect />}
|
|
||||||
/>
|
|
||||||
<Route
|
<Route
|
||||||
path="*"
|
path="*"
|
||||||
element={<NotFound />}
|
element={<NotFound />}
|
||||||
/>
|
/>
|
||||||
</Routes>
|
</Routes>
|
||||||
|
{/* Only redirect if we are not in test mode */}
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={
|
||||||
|
!(
|
||||||
|
import.meta.env
|
||||||
|
.VITE_TEST_REDIRECT ===
|
||||||
|
'true'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
show={<InitialRedirect />}
|
||||||
|
/>
|
||||||
|
|
||||||
<FeedbackNPS openUrl="http://feedback.unleash.run" />
|
<FeedbackNPS openUrl="http://feedback.unleash.run" />
|
||||||
|
|
||||||
<SplashPageRedirect />
|
<SplashPageRedirect />
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
</>
|
</>
|
||||||
|
@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
exports[`returns all baseRoutes 1`] = `
|
exports[`returns all baseRoutes 1`] = `
|
||||||
[
|
[
|
||||||
|
{
|
||||||
|
"component": [Function],
|
||||||
|
"menu": {},
|
||||||
|
"path": "/",
|
||||||
|
"title": "Unleash",
|
||||||
|
"type": "protected",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"component": [Function],
|
"component": [Function],
|
||||||
"isStandalone": true,
|
"isStandalone": true,
|
||||||
|
@ -45,6 +45,13 @@ import { LazyProject } from 'component/project/Project/LazyProject';
|
|||||||
import { AdminRedirect } from 'component/admin/AdminRedirect';
|
import { AdminRedirect } from 'component/admin/AdminRedirect';
|
||||||
|
|
||||||
export const routes: IRoute[] = [
|
export const routes: IRoute[] = [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
title: 'Unleash',
|
||||||
|
component: ProjectListNew,
|
||||||
|
type: 'protected',
|
||||||
|
menu: {},
|
||||||
|
},
|
||||||
// Splash
|
// Splash
|
||||||
{
|
{
|
||||||
path: '/splash/:splashId',
|
path: '/splash/:splashId',
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { getLocalStorageItem, setLocalStorageItem } from '../utils/storage';
|
import { getLocalStorageItem, setLocalStorageItem } from '../utils/storage';
|
||||||
import useUiConfig from './api/getters/useUiConfig/useUiConfig';
|
import { basePath } from 'utils/formatPath';
|
||||||
|
|
||||||
export const useLastViewedProject = () => {
|
export const useLastViewedProject = () => {
|
||||||
const { uiConfig } = useUiConfig();
|
const key = `${basePath}:unleash-lastViewedProject`;
|
||||||
const key = `${uiConfig.baseUriPath}:unleash-lastViewedProject`;
|
|
||||||
|
|
||||||
const [lastViewed, setLastViewed] = useState(() => {
|
const [lastViewed, setLastViewed] = useState(() => {
|
||||||
return getLocalStorageItem(key);
|
return getLocalStorageItem(key);
|
||||||
|
4020
frontend/yarn.lock
4020
frontend/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user