This is an automated email from the ASF dual-hosted git repository.
adoroszlai pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new f9552d0bb58 HDDS-15148. Prevent 404 when toggling between Old/New UI
on UI-exclusive routes (#10168)
f9552d0bb58 is described below
commit f9552d0bb5818f3a15b90ee58b06a45c3631ae11
Author: Chi-Hsuan Huang <[email protected]>
AuthorDate: Fri Jun 19 15:48:32 2026 +0800
HDDS-15148. Prevent 404 when toggling between Old/New UI on UI-exclusive
routes (#10168)
---
.../webapps/recon/ozone-recon-web/src/app.tsx | 65 ++++++++++++++++++----
.../src/v2/constants/breadcrumbs.constants.tsx | 1 +
2 files changed, 54 insertions(+), 12 deletions(-)
diff --git
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/app.tsx
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/app.tsx
index b3c8f764a62..7dd64c1ae8a 100644
---
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/app.tsx
+++
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/app.tsx
@@ -18,7 +18,7 @@
import React, { Suspense } from 'react';
-import { Switch as AntDSwitch, Layout } from 'antd';
+import { Switch as AntDSwitch, Layout, message } from 'antd';
import NavBar from './components/navBar/navBar';
import NavBarV2 from '@/v2/components/navBar/navBar';
import Breadcrumbs from './components/breadcrumbs/breadcrumbs';
@@ -26,6 +26,8 @@ import BreadcrumbsV2 from
'@/v2/components/breadcrumbs/breadcrumbs';
import { HashRouter as Router, Switch, Route, Redirect, useLocation } from
'react-router-dom';
import { routes } from '@/routes';
import { routesV2 } from '@/v2/routes-v2';
+import { breadcrumbNameMap as breadcrumbNameMapV1 } from
'@/constants/breadcrumbs.constants';
+import { breadcrumbNameMap as breadcrumbNameMapV2 } from
'@/v2/constants/breadcrumbs.constants';
import { MakeRouteWithSubRoutes } from '@/makeRouteWithSubRoutes';
import classNames from 'classnames';
@@ -38,6 +40,18 @@ const {
Header, Content, Footer
} = Layout;
+const FALLBACK_PATH = '/Overview';
+const TOAST_DURATION_SECONDS = 4;
+type BreadcrumbNameMap = typeof breadcrumbNameMapV1;
+
+// Strict membership check that ignores parameterized/catch-all entries
+// (the v1 routes table ends with `/:NotFound`, which would otherwise match
anything).
+const pathExistsIn = (path: string, table: ReadonlyArray<{ path: string }>):
boolean =>
+ table.some((r) => !r.path.includes(':') && r.path === path);
+
+const getViewName = (path: string, preferredMap: BreadcrumbNameMap): string =>
+ preferredMap[path] ?? path;
+
interface IAppState {
collapsed: boolean;
enableOldUI: boolean;
@@ -109,26 +123,53 @@ class App extends React.Component<Record<string, object>,
IAppState> {
this.setState({ collapsed });
};
+ handleUIToggle = (enableOldUI: boolean) => {
+ const currentPath = window.location.hash.slice(1).split('?')[0] ||
FALLBACK_PATH;
+ const targetTable = enableOldUI ? routes : routesV2;
+ const sourceTable = enableOldUI ? routesV2 : routes;
+ const shouldRedirect = !pathExistsIn(currentPath, targetTable);
+ let redirectMessage: string | undefined;
+
+ if (shouldRedirect) {
+ window.location.hash = FALLBACK_PATH;
+ // Only explain the redirect when the user came from a real page in the
source UI;
+ // a typo'd path otherwise produces a misleading "only available in..."
message.
+ if (pathExistsIn(currentPath, sourceTable)) {
+ const sourceMap = enableOldUI ? breadcrumbNameMapV2 :
breadcrumbNameMapV1;
+ const targetMap = enableOldUI ? breadcrumbNameMapV1 :
breadcrumbNameMapV2;
+ const friendly = getViewName(currentPath, sourceMap);
+ const fallbackViewName = getViewName(FALLBACK_PATH, targetMap);
+ const sourceUiName = enableOldUI ? 'New UI' : 'Old UI';
+ redirectMessage =
+ `The '${friendly}' view is only available in the ${sourceUiName}.
We've returned you to the ${fallbackViewName} dashboard.`;
+ }
+ }
+
+ this.setState({ enableOldUI }, () => {
+ // This is to persist the state of the UI between refreshes.
+ // While using session storage to store state is an anti-pattern,
provided the size of the data stored in this case
+ // and the plan to deprecate UI v1 (old UI) in the future - this is the
simplest approach/fix for persisting state.
+ sessionStorage.setItem('enableOldUI', JSON.stringify(enableOldUI));
+ if (redirectMessage) {
+ message.info(redirectMessage, TOAST_DURATION_SECONDS);
+ }
+ });
+ };
+
render() {
const { collapsed, enableOldUI } = this.state;
return (
<Router>
- <AppLayout
- enableOldUI={enableOldUI}
- collapsed={collapsed}
+ <AppLayout
+ enableOldUI={enableOldUI}
+ collapsed={collapsed}
onCollapse={this.onCollapse}
- onToggleUI={(checked: boolean) => {
- this.setState({
- enableOldUI: checked
- }, () => {
- sessionStorage.setItem('enableOldUI', JSON.stringify(checked));
- });
- }}
+ onToggleUI={this.handleUIToggle}
/>
</Router>
);
}
}
-export default App;
\ No newline at end of file
+export default App;
diff --git
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/constants/breadcrumbs.constants.tsx
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/constants/breadcrumbs.constants.tsx
index 6f4f04d439a..7d867b482fc 100644
---
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/constants/breadcrumbs.constants.tsx
+++
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/constants/breadcrumbs.constants.tsx
@@ -31,5 +31,6 @@ export const breadcrumbNameMap: BreadcrumbNameMap = {
'/NamespaceUsage': 'Namespace Usage',
'/Heatmap': 'Heatmap',
'/Om': 'OM DB Insights',
+ '/Capacity': 'Cluster Capacity',
'/Assistant': 'Recon AI'
};
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]