diff --git a/changelogs/fragments/8834.yml b/changelogs/fragments/8834.yml new file mode 100644 index 000000000000..78796507a6e4 --- /dev/null +++ b/changelogs/fragments/8834.yml @@ -0,0 +1,2 @@ +refactor: +- [Workspace] Add unit tests for inspect page url ([#8834](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/8834)) \ No newline at end of file diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.test.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.test.tsx new file mode 100644 index 000000000000..cc3b785344df --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.test.tsx @@ -0,0 +1,163 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { createOpenSearchDashboardsReactContext } from '../../../../../opensearch_dashboards_react/public'; +import { coreMock, workspacesServiceMock } from '../../../../../../core/public/mocks'; +import { BehaviorSubject } from 'rxjs'; +import { WorkspaceObject } from 'opensearch-dashboards/public'; +import { IntlProvider } from 'react-intl'; +import { IndexHeader } from './index_header'; + +describe('IndexHeader at new home page', () => { + const indexPattern = { id: 'default-index', title: 'Test Index Pattern', fields: [] }; + const mockCoreStart = coreMock.createStart(); + const workspaceObject = { + id: 'foo_id', + name: 'foo', + }; + const getIndexHeader = (props: any) => { + const mockHeaderControl = + (props?.header as Function) || + (() => { + return null; + }); + + const setDefault = jest.fn(); + const refreshFields = jest.fn(); + const deleteIndexPatternClick = jest.fn(); + const { Provider } = createOpenSearchDashboardsReactContext({ + ...mockCoreStart, + ...{ + application: { + ...mockCoreStart.application, + capabilities: { + ...mockCoreStart.application.capabilities, + workspaces: { enabled: props.workspaceEnabled }, + }, + }, + uiSettings: { ...mockCoreStart.uiSettings, get: jest.fn().mockReturnValue(true) }, + workspaces: { + ...workspacesServiceMock.createStartContract(), + currentWorkspace$: new BehaviorSubject(props?.workspace), + }, + navigationUI: { + HeaderControl: mockHeaderControl, + }, + }, + }); + + return ( + + + + + + ); + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders the set default button when index is not default and workspace is disabled', () => { + const mockHeaderControl = ({ controls }) => { + return controls?.[1]?.label ?? null; + }; + const { getByText } = render( + getIndexHeader({ + header: mockHeaderControl, + defaultIndex: 'no-default-index', + workspaceEnabled: false, + }) + ); + + expect(getByText('Set as default index')).toBeInTheDocument(); + }); + + it('does not render the set default button when index is default and workspace is disabled', () => { + const mockHeaderControl = ({ controls }) => { + return controls?.[1]?.label ?? null; + }; + const { queryByText } = render( + getIndexHeader({ + header: mockHeaderControl, + defaultIndex: 'default-index', + workspaceEnabled: false, + }) + ); + + expect(queryByText('Set as default index')).toBeNull(); + }); + + it('renders the set default button when index is not default and user is in workspace', () => { + const mockHeaderControl = ({ controls }) => { + return controls?.[1]?.label ?? null; + }; + const { getByText } = render( + getIndexHeader({ + header: mockHeaderControl, + defaultIndex: 'no-default-index', + workspace: workspaceObject, + workspaceEnabled: true, + }) + ); + + expect(getByText('Set as default index')).toBeInTheDocument(); + }); + + it('does not render the set default button when index is default and user is in workspace', () => { + const mockHeaderControl = ({ controls }) => { + return controls?.[1]?.label ?? null; + }; + const { queryByText } = render( + getIndexHeader({ + header: mockHeaderControl, + defaultIndex: 'default-index', + workspace: workspaceObject, + workspaceEnabled: true, + }) + ); + + expect(queryByText('Set as default index')).toBeNull(); + }); + + it('does not render the set default button when index is not default and user is not in workspace', () => { + const mockHeaderControl = ({ controls }) => { + return controls?.[1]?.label ?? null; + }; + const { queryByText } = render( + getIndexHeader({ + header: mockHeaderControl, + defaultIndex: 'no-default-index', + workspaceEnabled: true, + }) + ); + + expect(queryByText('Set as default index')).toBeNull(); + }); + + it('does not render the set default button when index is default and user is not in workspace', () => { + const mockHeaderControl = ({ controls }) => { + return controls?.[1]?.label ?? null; + }; + const { queryByText } = render( + getIndexHeader({ + header: mockHeaderControl, + defaultIndex: 'default-index', + workspaceEnabled: true, + }) + ); + + expect(queryByText('Set as default index')).toBeNull(); + }); +}); diff --git a/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx b/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx index 772d33199583..0b32dfdfffce 100644 --- a/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx +++ b/src/plugins/saved_objects_management/public/management_section/saved_objects_table_page.tsx @@ -43,7 +43,7 @@ import { } from '../services'; import { SavedObjectsTable } from './objects_table'; import { NavigationPublicPluginStart } from '../../../navigation/public'; -import { formatUrlWithWorkspaceId } from '../../../../core/public/utils'; +import { formatInspectUrl } from '../utils'; const SavedObjectsTablePage = ({ coreStart, @@ -76,8 +76,6 @@ const SavedObjectsTablePage = ({ const itemsPerPage = coreStart.uiSettings.get('savedObjects:perPage', 50); const dateFormat = coreStart.uiSettings.get('dateFormat'); const currentWorkspace = useObservable(coreStart.workspaces.currentWorkspace$); - const basePath = coreStart.http.basePath; - const visibleWsIds = useObservable(coreStart.workspaces.workspaceList$)?.map((ws) => ws.id) || []; useEffect(() => { setBreadcrumbs([ @@ -119,26 +117,8 @@ const SavedObjectsTablePage = ({ workspaces={coreStart.workspaces} perPageConfig={itemsPerPage} goInspectObject={(savedObject) => { - const { editUrl } = savedObject.meta; - let finalEditUrl = editUrl; - if (useUpdatedUX && finalEditUrl) { - finalEditUrl = finalEditUrl.replace(/^\/management\/opensearch-dashboards/, '/app'); - } - if (finalEditUrl) { - let inAppUrl = basePath.prepend(finalEditUrl); - if (savedObject.workspaces?.length) { - if (currentWorkspace) { - inAppUrl = formatUrlWithWorkspaceId(finalEditUrl, currentWorkspace.id, basePath); - } else { - // find first workspace user have permission - const workspaceId = savedObject.workspaces.find((wsId) => - visibleWsIds.includes(wsId) - ); - if (workspaceId) { - inAppUrl = formatUrlWithWorkspaceId(finalEditUrl, workspaceId, basePath); - } - } - } + const inAppUrl = formatInspectUrl(savedObject, coreStart); + if (inAppUrl) { return coreStart.application.navigateToUrl(inAppUrl); } }} diff --git a/src/plugins/saved_objects_management/public/utils.test.ts b/src/plugins/saved_objects_management/public/utils.test.ts index eebfdec8f61d..bcaed2bb9417 100644 --- a/src/plugins/saved_objects_management/public/utils.test.ts +++ b/src/plugins/saved_objects_management/public/utils.test.ts @@ -3,7 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { formatWorkspaceIdParams } from './utils'; +import { coreMock } from '../../../core/public/mocks'; +import { formatInspectUrl, formatWorkspaceIdParams } from './utils'; +import { CoreStart } from 'opensearch-dashboards/public'; describe('Utils', () => { it('formatWorkspaceIdParams with workspace null/undefined', async () => { @@ -41,4 +43,84 @@ describe('Utils', () => { }); expect(obj).toEqual({ foo: 'bar', availableWorkspaces: ['foo', 'bar'], workspaces: ['foo'] }); }); + + describe('formatInspectUrl', () => { + let mockCoreStart: CoreStart; + const savedObject = { + type: 'dashboard', + id: 'dashboard', + attributes: {}, + references: [], + meta: { + editUrl: '/management/opensearch-dashboards/objects/savedDashboards/ID1', + }, + }; + const savedObjectWithWorkspaces = { + ...savedObject, + workspaces: ['workspace1'], + }; + + beforeEach(() => { + jest.clearAllMocks(); + mockCoreStart = coreMock.createStart(); + mockCoreStart.application.capabilities = { + ...mockCoreStart.application.capabilities, + workspaces: { + ...mockCoreStart.application.capabilities.workspaces, + enabled: true, + }, + }; + mockCoreStart.uiSettings = { + ...mockCoreStart.uiSettings, + get: jest.fn().mockReturnValue(true), + }; + }); + + it('formats URL correctly when useUpdatedUX is false and workspace is disabled', () => { + mockCoreStart.application.capabilities = { + ...mockCoreStart.application.capabilities, + workspaces: { + ...mockCoreStart.application.capabilities.workspaces, + enabled: false, + }, + }; + mockCoreStart.uiSettings = { + ...mockCoreStart.uiSettings, + get: jest.fn().mockReturnValue(false), + }; + const result = formatInspectUrl(savedObject, mockCoreStart); + expect(result).toBe('/management/opensearch-dashboards/objects/savedDashboards/ID1'); + }); + + it('formats URL correctly when useUpdatedUX is false, saved object does not belong to certain workspaces and not in current workspace', () => { + mockCoreStart.uiSettings = { + ...mockCoreStart.uiSettings, + get: jest.fn().mockReturnValue(false), + }; + const result = formatInspectUrl(savedObject, mockCoreStart); + expect(result).toBe('/management/opensearch-dashboards/objects/savedDashboards/ID1'); + }); + + it('formats URL correctly when useUpdatedUX is true and in current workspace', () => { + const currentWorkspace = { id: 'workspace1', name: 'workspace1' }; + mockCoreStart.workspaces.currentWorkspace$.next(currentWorkspace); + const result = formatInspectUrl(savedObjectWithWorkspaces, mockCoreStart); + + expect(result).toBe('http://localhost/w/workspace1/app/objects/savedDashboards/ID1'); + }); + + it('formats URL correctly when useUpdatedUX is true and saved object belongs to certain workspaces', () => { + mockCoreStart.workspaces.workspaceList$.next([{ id: 'workspace1', name: 'workspace1' }]); + const result = formatInspectUrl(savedObjectWithWorkspaces, mockCoreStart); + + expect(result).toBe('http://localhost/w/workspace1/app/objects/savedDashboards/ID1'); + }); + + it('formats URL correctly when useUpdatedUX is true and the object does not belong to any workspace', () => { + mockCoreStart.workspaces.workspaceList$.next([{ id: 'workspace2', name: 'workspace2' }]); + const result = formatInspectUrl(savedObjectWithWorkspaces, mockCoreStart); + + expect(result).toBe('/app/objects/savedDashboards/ID1'); + }); + }); }); diff --git a/src/plugins/saved_objects_management/public/utils.ts b/src/plugins/saved_objects_management/public/utils.ts index 937e7767702d..9dada18e8711 100644 --- a/src/plugins/saved_objects_management/public/utils.ts +++ b/src/plugins/saved_objects_management/public/utils.ts @@ -3,6 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { CoreStart } from 'opensearch-dashboards/public'; +import { formatUrlWithWorkspaceId } from '../../../core/public/utils'; +import { SavedObjectWithMetadata } from './types'; + export function formatWorkspaceIdParams< T extends { workspaces?: string[] | null; availableWorkspaces?: string[] | null } >(obj: T): T | Omit { @@ -12,3 +16,35 @@ export function formatWorkspaceIdParams< } return others; } + +export function formatInspectUrl( + savedObject: SavedObjectWithMetadata, + coreStart: CoreStart +): string | undefined { + const { editUrl } = savedObject.meta; + const useUpdatedUX = !!coreStart.uiSettings.get('home:useNewHomePage'); + let finalEditUrl = editUrl; + if (useUpdatedUX && finalEditUrl) { + finalEditUrl = finalEditUrl.replace(/^\/management\/opensearch-dashboards/, '/app'); + } + if (finalEditUrl) { + const basePath = coreStart.http.basePath; + let inAppUrl = basePath.prepend(finalEditUrl); + const workspaceEnabled = coreStart.application.capabilities.workspaces.enabled; + if (workspaceEnabled) { + const currentWorkspace = coreStart.workspaces.currentWorkspace$.value; + if (currentWorkspace) { + inAppUrl = formatUrlWithWorkspaceId(finalEditUrl, currentWorkspace.id, basePath); + } else { + const visibleWsIds = coreStart.workspaces.workspaceList$.value?.map((ws) => ws.id) || []; + + // find first workspace user have permission + const workspaceId = savedObject?.workspaces?.find((wsId) => visibleWsIds.includes(wsId)); + if (workspaceId) { + inAppUrl = formatUrlWithWorkspaceId(finalEditUrl, workspaceId, basePath); + } + } + } + return inAppUrl; + } +}