From 1e50fc1376d3be341f45ef74ca7fe45d27f1aa26 Mon Sep 17 00:00:00 2001
From: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com>
Date: Wed, 25 Jun 2025 20:54:07 +0530
Subject: [PATCH] fix(ui): version link and fetch logic with 1 hour wait time
(#21932)
* fix(ui): version link and fetch logic with 1 hour wait time
* fix tests
* fix test
---
.../Modals/WhatsNewModal/whats-new-modal.less | 1 -
.../ui/src/components/NavBar/NavBar.test.tsx | 58 ++++++++++++++++---
.../ui/src/components/NavBar/NavBar.tsx | 42 +++++++++-----
.../ui/src/constants/Navbar.constants.ts | 4 +-
.../ui/src/constants/URL.constants.ts | 3 +
.../resources/ui/src/constants/constants.ts | 5 +-
.../ui/src/utils/NavbarUtilClassBase.test.tsx | 4 +-
.../ui/src/utils/NavbarUtils.test.tsx | 6 +-
.../resources/ui/src/utils/NavbarUtils.tsx | 2 +-
9 files changed, 91 insertions(+), 34 deletions(-)
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Modals/WhatsNewModal/whats-new-modal.less b/openmetadata-ui/src/main/resources/ui/src/components/Modals/WhatsNewModal/whats-new-modal.less
index c83c2d6e73d..07ea434cda7 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Modals/WhatsNewModal/whats-new-modal.less
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Modals/WhatsNewModal/whats-new-modal.less
@@ -124,7 +124,6 @@
.slick-active {
button {
background-color: @primary-color;
- width: inherit;
border-radius: 5px;
}
}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/NavBar/NavBar.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/NavBar/NavBar.test.tsx
index b0ee2238085..1b672f2efcb 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/NavBar/NavBar.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/NavBar/NavBar.test.tsx
@@ -12,7 +12,10 @@
*/
import { act, render, screen } from '@testing-library/react';
import React from 'react';
-import { ONE_HOUR_MS } from '../../constants/constants';
+import {
+ LAST_VERSION_FETCH_TIME_KEY,
+ ONE_HOUR_MS,
+} from '../../constants/constants';
import { HELP_ITEMS_ENUM } from '../../constants/Navbar.constants';
import { getVersion } from '../../rest/miscAPI';
import { getHelpDropdownItems } from '../../utils/NavbarUtils';
@@ -177,13 +180,13 @@ describe('Test NavBar Component', () => {
});
});
-// --- Additional tests for fetchOMVersion one hour threshold ---
-describe('fetchOMVersion one hour threshold', () => {
+// --- Tests for handleDocumentVisibilityChange one hour threshold ---
+describe('handleDocumentVisibilityChange one hour threshold', () => {
const OLD_DATE_NOW = Date.now;
beforeEach(() => {
jest.resetModules();
-
+ jest.clearAllMocks();
global.Date.now = jest.fn();
});
@@ -191,7 +194,7 @@ describe('fetchOMVersion one hour threshold', () => {
global.Date.now = OLD_DATE_NOW;
});
- it('should NOT call getVersion if less than one hour since last fetch', async () => {
+ it('should NOT call getVersion on window focus if less than one hour since last fetch', async () => {
const now = 2000000;
const lastFetch = now - (ONE_HOUR_MS - 1000); // less than 1 hour ago
mockGetItem.mockReturnValue(String(lastFetch));
@@ -200,26 +203,63 @@ describe('fetchOMVersion one hour threshold', () => {
render();
await screen.findByTestId('global-search-bar');
+ // Clear the initial getVersion call from mount
+ jest.clearAllMocks();
+
+ // Simulate window focus event
+ await act(async () => {
+ window.dispatchEvent(new Event('focus'));
+ });
+
expect(getVersion).not.toHaveBeenCalled();
});
- it('should call getVersion and setItem if more than one hour since last fetch', async () => {
+ it('should call getVersion and setItem on window focus if more than one hour since last fetch', async () => {
const now = 3000000;
const lastFetch = now - (ONE_HOUR_MS + 1000); // more than 1 hour ago
mockGetItem.mockReturnValue(String(lastFetch));
(global.Date.now as jest.Mock).mockReturnValue(now);
render();
- await Promise.resolve();
+ await screen.findByTestId('global-search-bar');
+ // Clear the initial getVersion call from mount
+ jest.clearAllMocks();
+
+ // Simulate window focus event
await act(async () => {
- expect(getVersion).toHaveBeenCalled();
+ window.dispatchEvent(new Event('focus'));
});
+ expect(getVersion).toHaveBeenCalled();
expect(mockSetItem).toHaveBeenCalledWith(
- 'versionFetchTime',
+ LAST_VERSION_FETCH_TIME_KEY,
'3000000',
expect.objectContaining({ expires: expect.any(Date) })
);
});
+
+ it('should call getVersion on window focus if no previous fetch time exists', async () => {
+ const now = 4000000;
+ mockGetItem.mockReturnValue(null); // No previous fetch time
+ (global.Date.now as jest.Mock).mockReturnValue(now);
+
+ render();
+ await screen.findByTestId('global-search-bar');
+
+ // Clear the initial getVersion call from mount
+ jest.clearAllMocks();
+
+ // Simulate window focus event
+ await act(async () => {
+ window.dispatchEvent(new Event('focus'));
+ });
+
+ expect(getVersion).toHaveBeenCalled();
+ expect(mockSetItem).toHaveBeenCalledWith(
+ LAST_VERSION_FETCH_TIME_KEY,
+ '4000000',
+ expect.objectContaining({ expires: expect.any(Date) })
+ );
+ });
});
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/NavBar/NavBar.tsx b/openmetadata-ui/src/main/resources/ui/src/components/NavBar/NavBar.tsx
index bf80d818241..b1501f00e2e 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/NavBar/NavBar.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/NavBar/NavBar.tsx
@@ -45,10 +45,10 @@ import { ReactComponent as SidebarCollapsedIcon } from '../../assets/svg/ic-side
import { ReactComponent as SidebarExpandedIcon } from '../../assets/svg/ic-sidebar-expanded.svg';
import {
DEFAULT_DOMAIN_VALUE,
+ LAST_VERSION_FETCH_TIME_KEY,
NOTIFICATION_READ_TIMER,
ONE_HOUR_MS,
SOCKET_EVENTS,
- VERSION_FETCH_TIME_KEY,
} from '../../constants/constants';
import { GlobalSettingsMenuCategory } from '../../constants/GlobalSettings.constants';
import { HELP_ITEMS_ENUM } from '../../constants/Navbar.constants';
@@ -130,22 +130,16 @@ const NavBar = () => {
} = useCurrentUserPreferences();
const fetchOMVersion = async () => {
- // If version fetch happens within an hour, skip fetching
- const lastFetchTime = cookieStorage.getItem(VERSION_FETCH_TIME_KEY);
- const now = Date.now();
-
- if (lastFetchTime && now - Number(lastFetchTime) < ONE_HOUR_MS) {
- // Less than an hour since last fetch, skip fetching
- return;
- }
-
try {
const res = await getVersion();
- setVersion(res.version);
- // Set/update the cookie with current time, expires in 1 hour
- cookieStorage.setItem(VERSION_FETCH_TIME_KEY, String(now), {
- expires: new Date(now + ONE_HOUR_MS),
+
+ const now = Date.now();
+ // Update the cache timestamp
+ cookieStorage.setItem(LAST_VERSION_FETCH_TIME_KEY, String(now), {
+ expires: new Date(Date.now() + ONE_HOUR_MS),
});
+
+ setVersion(res.version);
} catch (err) {
showErrorToast(
err as AxiosError,
@@ -325,7 +319,27 @@ const NavBar = () => {
) {
return;
}
+
+ // Check if we need to fetch based on cache timing
+ // This is to block the API call for 1 hour
+ const lastFetchTime = cookieStorage.getItem(LAST_VERSION_FETCH_TIME_KEY);
+ const now = Date.now();
+
+ if (lastFetchTime) {
+ const timeSinceLastFetch = now - parseInt(lastFetchTime);
+ if (timeSinceLastFetch < ONE_HOUR_MS) {
+ // Less than 1 hour since last fetch, skip API call
+ return;
+ }
+ }
+
const newVersion = await getVersion();
+
+ // Update the cache timestamp
+ cookieStorage.setItem(LAST_VERSION_FETCH_TIME_KEY, String(now), {
+ expires: new Date(Date.now() + ONE_HOUR_MS),
+ });
+
// Compare version only if version is set previously to have fair comparison
if (version && version !== newVersion.version) {
setShowVersionMissMatchAlert(true);
diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/Navbar.constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/Navbar.constants.ts
index 2c290582d6e..ae6f0370172 100644
--- a/openmetadata-ui/src/main/resources/ui/src/constants/Navbar.constants.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/constants/Navbar.constants.ts
@@ -21,7 +21,7 @@ import documentationLinksClassBase from '../utils/DocumentationLinksClassBase';
import i18n from '../utils/i18next/LocalUtil';
import { ROUTES } from './constants';
-import { URL_GITHUB_REPO, URL_JOIN_SLACK } from './URL.constants';
+import { URL_JOIN_SLACK, URL_OM_RELEASE_UPDATES } from './URL.constants';
export enum HELP_ITEMS_ENUM {
TOUR = 'tour',
@@ -80,7 +80,7 @@ export const HELP_ITEMS = [
key: HELP_ITEMS_ENUM.VERSION,
label: i18n.t('label.version'),
icon: IconVersionBlack,
- link: URL_GITHUB_REPO,
+ link: URL_OM_RELEASE_UPDATES,
isExternal: true,
},
];
diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/URL.constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/URL.constants.ts
index c0fce6400c2..b386d1ce42b 100644
--- a/openmetadata-ui/src/main/resources/ui/src/constants/URL.constants.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/constants/URL.constants.ts
@@ -14,3 +14,6 @@
export const URL_JOIN_SLACK = 'https://slack.open-metadata.org';
export const URL_OPEN_METADATA_DOCS = 'https://docs.open-metadata.org/';
export const URL_GITHUB_REPO = 'https://github.com/open-metadata/OpenMetadata';
+
+export const URL_OM_RELEASE_UPDATES =
+ 'https://open-metadata.org/product-updates#{{currentVersion}}';
diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts
index eb8eb6c1519..12b4967773c 100644
--- a/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts
@@ -65,6 +65,8 @@ export const MAX_CHAR_LIMIT_ENTITY_SUMMARY = 130;
export const TEST_CASE_FEED_GRAPH_HEIGHT = 250;
export const ONE_MINUTE_IN_MILLISECOND = 60000;
export const TWO_MINUTE_IN_MILLISECOND = 120000;
+export const ONE_HOUR_MS = 3600000; // 1 hour in milliseconds
+export const LAST_VERSION_FETCH_TIME_KEY = 'versionFetchTime';
export const LOCALSTORAGE_RECENTLY_VIEWED = `recentlyViewedData_${COOKIE_VERSION}`;
export const LOCALSTORAGE_RECENTLY_SEARCHED = `recentlySearchedData_${COOKIE_VERSION}`;
export const REDIRECT_PATHNAME = 'redirectUrlPath';
@@ -432,6 +434,3 @@ export const MAX_VISIBLE_OWNERS_FOR_FEED_TAB = 4;
export const MAX_VISIBLE_OWNERS_FOR_FEED_CARD = 2;
export const BREADCRUMB_SEPARATOR = '/';
-
-export const VERSION_FETCH_TIME_KEY = 'versionFetchTime';
-export const ONE_HOUR_MS = 60 * 60 * 1000;
diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/NavbarUtilClassBase.test.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/NavbarUtilClassBase.test.tsx
index 20becde6baf..c1b7a065200 100644
--- a/openmetadata-ui/src/main/resources/ui/src/utils/NavbarUtilClassBase.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/utils/NavbarUtilClassBase.test.tsx
@@ -13,8 +13,8 @@
import { ROUTES } from '../constants/constants';
import {
- URL_GITHUB_REPO,
URL_JOIN_SLACK,
+ URL_OM_RELEASE_UPDATES,
URL_OPEN_METADATA_DOCS,
} from '../constants/URL.constants';
import navbarUtilClassBase from './NavbarUtilClassBase';
@@ -28,7 +28,7 @@ describe('NavbarUtilClassBase', () => {
expect(stringifyResult).toContain(URL_OPEN_METADATA_DOCS);
expect(stringifyResult).toContain(ROUTES.SWAGGER);
expect(stringifyResult).toContain(URL_JOIN_SLACK);
- expect(stringifyResult).toContain(URL_GITHUB_REPO);
+ expect(stringifyResult).toContain(URL_OM_RELEASE_UPDATES);
expect(stringifyResult).toContain('label.tour');
expect(stringifyResult).toContain('label.doc-plural');
expect(stringifyResult).toContain('label.api-uppercase');
diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/NavbarUtils.test.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/NavbarUtils.test.tsx
index ddb7e3d7d88..1648547e6da 100644
--- a/openmetadata-ui/src/main/resources/ui/src/utils/NavbarUtils.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/utils/NavbarUtils.test.tsx
@@ -13,7 +13,7 @@
import { ROUTES } from '../constants/constants';
import { HELP_ITEMS_ENUM } from '../constants/Navbar.constants';
-import { URL_GITHUB_REPO } from '../constants/URL.constants';
+import { URL_OM_RELEASE_UPDATES } from '../constants/URL.constants';
import { getHelpDropdownItems } from './NavbarUtils';
describe('NavbarUtils test', () => {
@@ -30,7 +30,9 @@ describe('NavbarUtils test', () => {
// Test external link
const externalLink = helpDropdownItems[5].label.props.href;
- expect(externalLink).toBe(URL_GITHUB_REPO);
+ expect(externalLink).toBe(
+ URL_OM_RELEASE_UPDATES.replace('{{currentVersion}}', version)
+ );
expect(helpDropdownItems[5].label.props.target).toBe('_blank');
expect(helpDropdownItems[5].label.props.rel).toBe('noreferrer');
diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/NavbarUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/NavbarUtils.tsx
index d235d4e9267..d132febaa12 100644
--- a/openmetadata-ui/src/main/resources/ui/src/utils/NavbarUtils.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/utils/NavbarUtils.tsx
@@ -56,7 +56,7 @@ const getHelpDropdownLabel = (item: SupportItem, version?: string) => {
return (
{getHelpDropdownLabelContentRenderer(item, version)}