mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-06-27 04:22:05 +00:00
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
This commit is contained in:
parent
693292406d
commit
1e50fc1376
@ -124,7 +124,6 @@
|
|||||||
.slick-active {
|
.slick-active {
|
||||||
button {
|
button {
|
||||||
background-color: @primary-color;
|
background-color: @primary-color;
|
||||||
width: inherit;
|
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,10 @@
|
|||||||
*/
|
*/
|
||||||
import { act, render, screen } from '@testing-library/react';
|
import { act, render, screen } from '@testing-library/react';
|
||||||
import React from '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 { HELP_ITEMS_ENUM } from '../../constants/Navbar.constants';
|
||||||
import { getVersion } from '../../rest/miscAPI';
|
import { getVersion } from '../../rest/miscAPI';
|
||||||
import { getHelpDropdownItems } from '../../utils/NavbarUtils';
|
import { getHelpDropdownItems } from '../../utils/NavbarUtils';
|
||||||
@ -177,13 +180,13 @@ describe('Test NavBar Component', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- Additional tests for fetchOMVersion one hour threshold ---
|
// --- Tests for handleDocumentVisibilityChange one hour threshold ---
|
||||||
describe('fetchOMVersion one hour threshold', () => {
|
describe('handleDocumentVisibilityChange one hour threshold', () => {
|
||||||
const OLD_DATE_NOW = Date.now;
|
const OLD_DATE_NOW = Date.now;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.resetModules();
|
jest.resetModules();
|
||||||
|
jest.clearAllMocks();
|
||||||
global.Date.now = jest.fn();
|
global.Date.now = jest.fn();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -191,7 +194,7 @@ describe('fetchOMVersion one hour threshold', () => {
|
|||||||
global.Date.now = OLD_DATE_NOW;
|
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 now = 2000000;
|
||||||
const lastFetch = now - (ONE_HOUR_MS - 1000); // less than 1 hour ago
|
const lastFetch = now - (ONE_HOUR_MS - 1000); // less than 1 hour ago
|
||||||
mockGetItem.mockReturnValue(String(lastFetch));
|
mockGetItem.mockReturnValue(String(lastFetch));
|
||||||
@ -200,26 +203,63 @@ describe('fetchOMVersion one hour threshold', () => {
|
|||||||
render(<NavBarComponent />);
|
render(<NavBarComponent />);
|
||||||
await screen.findByTestId('global-search-bar');
|
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();
|
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 now = 3000000;
|
||||||
const lastFetch = now - (ONE_HOUR_MS + 1000); // more than 1 hour ago
|
const lastFetch = now - (ONE_HOUR_MS + 1000); // more than 1 hour ago
|
||||||
mockGetItem.mockReturnValue(String(lastFetch));
|
mockGetItem.mockReturnValue(String(lastFetch));
|
||||||
(global.Date.now as jest.Mock).mockReturnValue(now);
|
(global.Date.now as jest.Mock).mockReturnValue(now);
|
||||||
|
|
||||||
render(<NavBarComponent />);
|
render(<NavBarComponent />);
|
||||||
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 () => {
|
await act(async () => {
|
||||||
expect(getVersion).toHaveBeenCalled();
|
window.dispatchEvent(new Event('focus'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expect(getVersion).toHaveBeenCalled();
|
||||||
expect(mockSetItem).toHaveBeenCalledWith(
|
expect(mockSetItem).toHaveBeenCalledWith(
|
||||||
'versionFetchTime',
|
LAST_VERSION_FETCH_TIME_KEY,
|
||||||
'3000000',
|
'3000000',
|
||||||
expect.objectContaining({ expires: expect.any(Date) })
|
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(<NavBarComponent />);
|
||||||
|
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) })
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -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 { ReactComponent as SidebarExpandedIcon } from '../../assets/svg/ic-sidebar-expanded.svg';
|
||||||
import {
|
import {
|
||||||
DEFAULT_DOMAIN_VALUE,
|
DEFAULT_DOMAIN_VALUE,
|
||||||
|
LAST_VERSION_FETCH_TIME_KEY,
|
||||||
NOTIFICATION_READ_TIMER,
|
NOTIFICATION_READ_TIMER,
|
||||||
ONE_HOUR_MS,
|
ONE_HOUR_MS,
|
||||||
SOCKET_EVENTS,
|
SOCKET_EVENTS,
|
||||||
VERSION_FETCH_TIME_KEY,
|
|
||||||
} from '../../constants/constants';
|
} from '../../constants/constants';
|
||||||
import { GlobalSettingsMenuCategory } from '../../constants/GlobalSettings.constants';
|
import { GlobalSettingsMenuCategory } from '../../constants/GlobalSettings.constants';
|
||||||
import { HELP_ITEMS_ENUM } from '../../constants/Navbar.constants';
|
import { HELP_ITEMS_ENUM } from '../../constants/Navbar.constants';
|
||||||
@ -130,22 +130,16 @@ const NavBar = () => {
|
|||||||
} = useCurrentUserPreferences();
|
} = useCurrentUserPreferences();
|
||||||
|
|
||||||
const fetchOMVersion = async () => {
|
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 {
|
try {
|
||||||
const res = await getVersion();
|
const res = await getVersion();
|
||||||
setVersion(res.version);
|
|
||||||
// Set/update the cookie with current time, expires in 1 hour
|
const now = Date.now();
|
||||||
cookieStorage.setItem(VERSION_FETCH_TIME_KEY, String(now), {
|
// Update the cache timestamp
|
||||||
expires: new Date(now + ONE_HOUR_MS),
|
cookieStorage.setItem(LAST_VERSION_FETCH_TIME_KEY, String(now), {
|
||||||
|
expires: new Date(Date.now() + ONE_HOUR_MS),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setVersion(res.version);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorToast(
|
showErrorToast(
|
||||||
err as AxiosError,
|
err as AxiosError,
|
||||||
@ -325,7 +319,27 @@ const NavBar = () => {
|
|||||||
) {
|
) {
|
||||||
return;
|
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();
|
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
|
// Compare version only if version is set previously to have fair comparison
|
||||||
if (version && version !== newVersion.version) {
|
if (version && version !== newVersion.version) {
|
||||||
setShowVersionMissMatchAlert(true);
|
setShowVersionMissMatchAlert(true);
|
||||||
|
@ -21,7 +21,7 @@ import documentationLinksClassBase from '../utils/DocumentationLinksClassBase';
|
|||||||
|
|
||||||
import i18n from '../utils/i18next/LocalUtil';
|
import i18n from '../utils/i18next/LocalUtil';
|
||||||
import { ROUTES } from './constants';
|
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 {
|
export enum HELP_ITEMS_ENUM {
|
||||||
TOUR = 'tour',
|
TOUR = 'tour',
|
||||||
@ -80,7 +80,7 @@ export const HELP_ITEMS = [
|
|||||||
key: HELP_ITEMS_ENUM.VERSION,
|
key: HELP_ITEMS_ENUM.VERSION,
|
||||||
label: i18n.t('label.version'),
|
label: i18n.t('label.version'),
|
||||||
icon: IconVersionBlack,
|
icon: IconVersionBlack,
|
||||||
link: URL_GITHUB_REPO,
|
link: URL_OM_RELEASE_UPDATES,
|
||||||
isExternal: true,
|
isExternal: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -14,3 +14,6 @@
|
|||||||
export const URL_JOIN_SLACK = 'https://slack.open-metadata.org';
|
export const URL_JOIN_SLACK = 'https://slack.open-metadata.org';
|
||||||
export const URL_OPEN_METADATA_DOCS = 'https://docs.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_GITHUB_REPO = 'https://github.com/open-metadata/OpenMetadata';
|
||||||
|
|
||||||
|
export const URL_OM_RELEASE_UPDATES =
|
||||||
|
'https://open-metadata.org/product-updates#{{currentVersion}}';
|
||||||
|
@ -65,6 +65,8 @@ export const MAX_CHAR_LIMIT_ENTITY_SUMMARY = 130;
|
|||||||
export const TEST_CASE_FEED_GRAPH_HEIGHT = 250;
|
export const TEST_CASE_FEED_GRAPH_HEIGHT = 250;
|
||||||
export const ONE_MINUTE_IN_MILLISECOND = 60000;
|
export const ONE_MINUTE_IN_MILLISECOND = 60000;
|
||||||
export const TWO_MINUTE_IN_MILLISECOND = 120000;
|
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_VIEWED = `recentlyViewedData_${COOKIE_VERSION}`;
|
||||||
export const LOCALSTORAGE_RECENTLY_SEARCHED = `recentlySearchedData_${COOKIE_VERSION}`;
|
export const LOCALSTORAGE_RECENTLY_SEARCHED = `recentlySearchedData_${COOKIE_VERSION}`;
|
||||||
export const REDIRECT_PATHNAME = 'redirectUrlPath';
|
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 MAX_VISIBLE_OWNERS_FOR_FEED_CARD = 2;
|
||||||
|
|
||||||
export const BREADCRUMB_SEPARATOR = '/';
|
export const BREADCRUMB_SEPARATOR = '/';
|
||||||
|
|
||||||
export const VERSION_FETCH_TIME_KEY = 'versionFetchTime';
|
|
||||||
export const ONE_HOUR_MS = 60 * 60 * 1000;
|
|
||||||
|
@ -13,8 +13,8 @@
|
|||||||
|
|
||||||
import { ROUTES } from '../constants/constants';
|
import { ROUTES } from '../constants/constants';
|
||||||
import {
|
import {
|
||||||
URL_GITHUB_REPO,
|
|
||||||
URL_JOIN_SLACK,
|
URL_JOIN_SLACK,
|
||||||
|
URL_OM_RELEASE_UPDATES,
|
||||||
URL_OPEN_METADATA_DOCS,
|
URL_OPEN_METADATA_DOCS,
|
||||||
} from '../constants/URL.constants';
|
} from '../constants/URL.constants';
|
||||||
import navbarUtilClassBase from './NavbarUtilClassBase';
|
import navbarUtilClassBase from './NavbarUtilClassBase';
|
||||||
@ -28,7 +28,7 @@ describe('NavbarUtilClassBase', () => {
|
|||||||
expect(stringifyResult).toContain(URL_OPEN_METADATA_DOCS);
|
expect(stringifyResult).toContain(URL_OPEN_METADATA_DOCS);
|
||||||
expect(stringifyResult).toContain(ROUTES.SWAGGER);
|
expect(stringifyResult).toContain(ROUTES.SWAGGER);
|
||||||
expect(stringifyResult).toContain(URL_JOIN_SLACK);
|
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.tour');
|
||||||
expect(stringifyResult).toContain('label.doc-plural');
|
expect(stringifyResult).toContain('label.doc-plural');
|
||||||
expect(stringifyResult).toContain('label.api-uppercase');
|
expect(stringifyResult).toContain('label.api-uppercase');
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
import { ROUTES } from '../constants/constants';
|
import { ROUTES } from '../constants/constants';
|
||||||
import { HELP_ITEMS_ENUM } from '../constants/Navbar.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';
|
import { getHelpDropdownItems } from './NavbarUtils';
|
||||||
|
|
||||||
describe('NavbarUtils test', () => {
|
describe('NavbarUtils test', () => {
|
||||||
@ -30,7 +30,9 @@ describe('NavbarUtils test', () => {
|
|||||||
// Test external link
|
// Test external link
|
||||||
const externalLink = helpDropdownItems[5].label.props.href;
|
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.target).toBe('_blank');
|
||||||
expect(helpDropdownItems[5].label.props.rel).toBe('noreferrer');
|
expect(helpDropdownItems[5].label.props.rel).toBe('noreferrer');
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ const getHelpDropdownLabel = (item: SupportItem, version?: string) => {
|
|||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
className="no-underline"
|
className="no-underline"
|
||||||
href={item.link}
|
href={item.link?.replace('{{currentVersion}}', version ?? '')}
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
target="_blank">
|
target="_blank">
|
||||||
{getHelpDropdownLabelContentRenderer(item, version)}
|
{getHelpDropdownLabelContentRenderer(item, version)}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user