diff --git a/x-pack/plugins/graph/public/apps/workspace_route.tsx b/x-pack/plugins/graph/public/apps/workspace_route.tsx index 9087c2ce601cb..79f687d789fb7 100644 --- a/x-pack/plugins/graph/public/apps/workspace_route.tsx +++ b/x-pack/plugins/graph/public/apps/workspace_route.tsx @@ -115,13 +115,20 @@ export const WorkspaceRoute = ({ }) ); - const { savedWorkspace, indexPatterns, sharingSavedObjectProps } = useWorkspaceLoader({ + const loaded = useWorkspaceLoader({ workspaceRef, store, savedObjectsClient, - toastNotifications, + spaces, + coreStart, }); + if (!loaded) { + return null; + } + + const { savedWorkspace, indexPatterns, sharingSavedObjectProps } = loaded; + if (!savedWorkspace || !indexPatterns) { return null; } diff --git a/x-pack/plugins/graph/public/components/workspace_layout/workspace_layout.test.tsx b/x-pack/plugins/graph/public/components/workspace_layout/workspace_layout.test.tsx index 20dea4322b601..ae1a726464be5 100644 --- a/x-pack/plugins/graph/public/components/workspace_layout/workspace_layout.test.tsx +++ b/x-pack/plugins/graph/public/components/workspace_layout/workspace_layout.test.tsx @@ -52,17 +52,4 @@ describe('workspace_layout', () => { otherObjectPath: '#/workspace/conflictId', }); }); - - it('should redirect if outcome is aliasMatch', () => { - shallow( - - ); - expect(defaultProps.spaces.ui.redirectLegacyUrl).toHaveBeenCalledWith( - '#/workspace/aliasMatchId', - 'Graph' - ); - }); }); diff --git a/x-pack/plugins/graph/public/components/workspace_layout/workspace_layout.tsx b/x-pack/plugins/graph/public/components/workspace_layout/workspace_layout.tsx index 9299b6c8ba1f9..4bb04264bb520 100644 --- a/x-pack/plugins/graph/public/components/workspace_layout/workspace_layout.tsx +++ b/x-pack/plugins/graph/public/components/workspace_layout/workspace_layout.tsx @@ -180,19 +180,6 @@ export const WorkspaceLayoutComponent = ({ return null; }, [savedWorkspace.id, sharingSavedObjectProps, spaces, coreStart.http]); - if (spaces && sharingSavedObjectProps?.outcome === 'aliasMatch') { - // We found this object by a legacy URL alias from its old ID; redirect the user to the page with its new ID, preserving any URL hash - const newObjectId = sharingSavedObjectProps?.aliasTargetId!; // This is always defined if outcome === 'aliasMatch' - const newPath = getEditUrl(coreStart.http.basePath.prepend, { id: newObjectId }); - spaces.ui.redirectLegacyUrl( - newPath, - i18n.translate('xpack.graph.legacyUrlConflict.objectNoun', { - defaultMessage: 'Graph', - }) - ); - return null; - } - return ( ({ + useHistory: () => ({ + replace: jest.fn(), + }), + useLocation: () => ({ + location: jest.fn(), + }), + useParams: () => ({ + id: jest.fn(), + }), +})); + +jest.mock('React', () => ({ + ...jest.requireActual('React'), + useEffect: jest.fn(), +})); + +const mockSavedObjectsClient = ({ + resolve: jest.fn().mockResolvedValue({ + saved_object: { id: 10, _version: '7.15.0', attributes: { wsState: '{}' } }, + outcome: 'aliasMatch', + alias_target_id: 'aliasTargetId', + }), + find: jest.fn().mockResolvedValue({ title: 'test' }), +} as unknown) as SavedObjectsClientCommon; + +async function setup(props: UseWorkspaceLoaderProps) { + const returnVal = {}; + function TestComponent() { + Object.assign(returnVal, useWorkspaceLoader(props)); + return null; + } + await act(async () => { + const promise = Promise.resolve(); + mount(); + await act(() => promise); + }); + return returnVal; +} + +describe('use_workspace_loader', () => { + const defaultProps = { + workspaceRef: { current: {} as Workspace }, + store: createMockGraphStore({}).store, + savedObjectsClient: mockSavedObjectsClient, + coreStart: coreMock.createStart(), + spaces: spacesPluginMock.createStartContract(), + }; + + it('should redirect if outcome is aliasMatch', async () => { + await act(async () => { + await setup((defaultProps as unknown) as UseWorkspaceLoaderProps); + }); + expect(defaultProps.spaces.ui.redirectLegacyUrl).toHaveBeenCalledWith( + '#/workspace/aliasTargetId', + 'Graph' + ); + }); +}); diff --git a/x-pack/plugins/graph/public/helpers/use_workspace_loader.ts b/x-pack/plugins/graph/public/helpers/use_workspace_loader.ts index 05a53ff23bfd9..74ba2f3bfbbd3 100644 --- a/x-pack/plugins/graph/public/helpers/use_workspace_loader.ts +++ b/x-pack/plugins/graph/public/helpers/use_workspace_loader.ts @@ -5,19 +5,22 @@ * 2.0. */ -import { SavedObjectsClientContract, ToastsStart } from 'kibana/public'; +import { SavedObjectsClientContract } from 'kibana/public'; import { useEffect, useState } from 'react'; import { useHistory, useLocation, useParams } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; +import { CoreStart } from 'kibana/public'; import { GraphStore } from '../state_management'; import { GraphWorkspaceSavedObject, IndexPatternSavedObject, Workspace } from '../types'; import { getEmptyWorkspace, getSavedWorkspace } from './saved_workspace_utils'; - -interface UseWorkspaceLoaderProps { +import { getEditUrl } from '../services/url'; +import { SpacesApi } from '../../../spaces/public'; +export interface UseWorkspaceLoaderProps { store: GraphStore; workspaceRef: React.MutableRefObject; savedObjectsClient: SavedObjectsClientContract; - toastNotifications: ToastsStart; + spaces: SpacesApi; + coreStart: CoreStart; } interface WorkspaceUrlParams { @@ -29,10 +32,11 @@ export interface SharingSavedObjectProps { } export const useWorkspaceLoader = ({ + coreStart, + spaces, workspaceRef, store, savedObjectsClient, - toastNotifications, }: UseWorkspaceLoaderProps) => { const [indexPatterns, setIndexPatterns] = useState(); const [savedWorkspace, setSavedWorkspace] = useState(); @@ -82,7 +86,7 @@ export const useWorkspaceLoader = ({ }> { return id ? await getSavedWorkspace(savedObjectsClient, id).catch(function (e) { - toastNotifications.addError(e, { + coreStart.notifications.toasts.addError(e, { title: i18n.translate('xpack.graph.missingWorkspaceErrorMessage', { defaultMessage: "Couldn't load graph with ID", }), @@ -101,6 +105,19 @@ export const useWorkspaceLoader = ({ sharingSavedObjectProps: fetchedSharingSavedObjectProps, } = await fetchSavedWorkspace(); + if (spaces && fetchedSharingSavedObjectProps?.outcome === 'aliasMatch') { + // We found this object by a legacy URL alias from its old ID; redirect the user to the page with its new ID, preserving any URL hash + const newObjectId = fetchedSharingSavedObjectProps?.aliasTargetId!; // This is always defined if outcome === 'aliasMatch' + const newPath = getEditUrl(coreStart.http.basePath.prepend, { id: newObjectId }); + spaces.ui.redirectLegacyUrl( + newPath, + i18n.translate('xpack.graph.legacyUrlConflict.objectNoun', { + defaultMessage: 'Graph', + }) + ); + return null; + } + /** * Deal with situation of request to open saved workspace. Otherwise clean up store, * when navigating to a new workspace from existing one. @@ -124,8 +141,9 @@ export const useWorkspaceLoader = ({ history, savedObjectsClient, setSavedWorkspace, - toastNotifications, + coreStart, workspaceRef, + spaces, ]); return { savedWorkspace, indexPatterns, sharingSavedObjectProps };