diff --git a/src/elements/common/types/SidebarNavigation.js.flow b/src/elements/common/types/SidebarNavigation.js.flow index 1dc910587e..065befe845 100644 --- a/src/elements/common/types/SidebarNavigation.js.flow +++ b/src/elements/common/types/SidebarNavigation.js.flow @@ -10,7 +10,6 @@ export const ViewType = Object.freeze({ METADATA_REDESIGN: 'metadata_redesign', SKILLS: 'skills', ACTIVITY: 'activity', - VERSIONS: 'versions', DOCGEN: 'docgen', }); @@ -18,6 +17,7 @@ export const FeedEntryType = Object.freeze({ ANNOTATIONS: 'annotations', COMMENTS: 'comments', TASKS: 'tasks', + VERSIONS: 'versions', }); export type ViewTypeValues = $Values; @@ -27,13 +27,14 @@ export type SidebarNavigation = { activeFeedEntryType?: FeedEntryTypeValues, activeFeedEntryId?: string, fileVersionId?: string, - filteredTemplateIds?: string, - sidebar: ViewTypeValues, + filteredTemplateIds?: string[], + sidebar?: ViewTypeValues, versionId?: string, }; export type InternalSidebarNavigation = SidebarNavigation & { open?: boolean, + silent?: boolean, }; export type SidebarNavigationHandler = (sidebar: SidebarNavigation, replace?: boolean) => void; diff --git a/src/elements/common/types/SidebarNavigation.ts b/src/elements/common/types/SidebarNavigation.ts index b11b2e64e5..dce07c7c3e 100644 --- a/src/elements/common/types/SidebarNavigation.ts +++ b/src/elements/common/types/SidebarNavigation.ts @@ -5,7 +5,6 @@ export enum ViewType { METADATA_REDESIGN = 'metadata_redesign', BOXAI = 'boxai', ACTIVITY = 'activity', - VERSIONS = 'versions', DOCGEN = 'docgen', } @@ -13,16 +12,18 @@ export enum FeedEntryType { ANNOTATIONS = 'annotations', COMMENTS = 'comments', TASKS = 'tasks', + VERSIONS = 'versions', } type VersionSidebarView = { sidebar: ViewType.ACTIVITY | ViewType.DETAILS; - versionId: string; + activeFeedEntryType: FeedEntryType.VERSIONS; + versionId?: string; }; export type MetadataSidebarView = { sidebar: ViewType.METADATA | ViewType.METADATA_REDESIGN; - filteredTemplateIds?: string; + filteredTemplateIds: string[]; }; export type ActivityAnnotationsSidebarView = { @@ -39,7 +40,7 @@ type ActivityCommentsSidebarView = { export type SidebarNavigation = | { - sidebar: ViewType; + sidebar?: ViewType; } | VersionSidebarView | MetadataSidebarView @@ -48,6 +49,7 @@ export type SidebarNavigation = export type InternalSidebarNavigation = SidebarNavigation & { open?: boolean; + silent?: boolean; }; export type SidebarNavigationHandler = (sidebar: SidebarNavigation, replace?: boolean) => void; diff --git a/src/elements/content-sidebar/SidebarPanels.js b/src/elements/content-sidebar/SidebarPanels.js index e860dc8f98..cf7925e132 100644 --- a/src/elements/content-sidebar/SidebarPanels.js +++ b/src/elements/content-sidebar/SidebarPanels.js @@ -1,3 +1,4 @@ +/* eslint-disable max-classes-per-file */ /** * @flow * @file Content Sidebar Panels component @@ -42,6 +43,11 @@ import type { User, BoxItem } from '../../common/types/core'; import type { Errors } from '../common/flowTypes'; import type { FeatureConfig } from '../common/feature-checking'; import type { BoxAISidebarCache } from './types/BoxAISidebarTypes'; +import type { + InternalSidebarNavigation, + InternalSidebarNavigationHandler, +} from '../common/types/SidebarNavigation'; +import { FeedEntryType, ViewType } from '../common/types/SidebarNavigation'; type Props = { activitySidebarProps: ActivitySidebarProps, @@ -64,6 +70,8 @@ type Props = { hasMetadata: boolean, hasSkills: boolean, hasVersions: boolean, + internalSidebarNavigation?: InternalSidebarNavigation, + internalSidebarNavigationHandler?: InternalSidebarNavigationHandler, isOpen: boolean, location: Location, metadataSidebarProps: MetadataSidebarProps, @@ -71,6 +79,7 @@ type Props = { onPanelChange?: (name: string, isInitialState?: boolean) => void, onVersionChange?: Function, onVersionHistoryClick?: Function, + routerDisabled?: boolean, versionsSidebarProps: VersionsSidebarProps, }; @@ -93,7 +102,8 @@ const MARK_NAME_JS_LOADING_METADATA_REDESIGNED = `${ORIGIN_METADATA_SIDEBAR_REDE const MARK_NAME_JS_LOADING_DOCGEN = `${ORIGIN_DOCGEN_SIDEBAR}${BASE_EVENT_NAME}`; const MARK_NAME_JS_LOADING_VERSIONS = `${ORIGIN_VERSIONS_SIDEBAR}${BASE_EVENT_NAME}`; -const URL_TO_FEED_ITEM_TYPE = { annotations: 'annotation', comments: 'comment', tasks: 'task' }; +// `versions` sets undefined value - this situation will never happen, but it's needed to fulfill the type +const URL_TO_FEED_ITEM_TYPE = { annotations: 'annotation', comments: 'comment', tasks: 'task', versions: undefined }; const LoadableDetailsSidebar = SidebarUtils.getAsyncSidebarContent(SIDEBAR_VIEW_DETAILS, MARK_NAME_JS_LOADING_DETAILS); const LoadableActivitySidebar = SidebarUtils.getAsyncSidebarContent( @@ -118,7 +128,7 @@ const LoadableVersionsSidebar = SidebarUtils.getAsyncSidebarContent( const SIDEBAR_PATH_VERSIONS = '/:sidebar(activity|details)/versions/:versionId?'; -class SidebarPanels extends React.Component { +class SidebarPanelsRouter extends React.Component { boxAISidebar: ElementRefType = React.createRef(); activitySidebar: ElementRefType = React.createRef(); @@ -472,7 +482,416 @@ class SidebarPanels extends React.Component { } } -export { SidebarPanels as SidebarPanelsComponent }; +class SidebarPanelsRouterDisabled extends React.Component { + boxAISidebar: ElementRefType = React.createRef(); + + activitySidebar: ElementRefType = React.createRef(); + + detailsSidebar: ElementRefType = React.createRef(); + + initialPanel: { current: null | string } = React.createRef(); + + metadataSidebar: ElementRefType = React.createRef(); + + state: State = { isInitialized: false }; + + versionsSidebar: ElementRefType = React.createRef(); + + boxAiSidebarCache: BoxAISidebarCache = { + agents: { + agents: [], + selectedAgent: null, + requestState: 'not_started', + }, + encodedSession: null, + questions: [], + shouldShowLandingPage: true, + suggestedQuestions: [], + }; + + componentDidMount() { + this.setState({ isInitialized: true }); + } + + componentDidUpdate(prevProps: Props): void { + const { onVersionChange, internalSidebarNavigation } = this.props; + const { internalSidebarNavigation: prevInternalSidebarNavigation } = prevProps; + + // Reset the current version id if the wrapping versions route is no longer active + if (onVersionChange) { + const wasPreviousNavigationVersions = this.isVersionsNavigationPath(prevInternalSidebarNavigation); + const isCurrentNavigationVersions = this.isVersionsNavigationPath(internalSidebarNavigation); + + if (wasPreviousNavigationVersions && !isCurrentNavigationVersions) { + onVersionChange(null); + } + } + } + + isVersionsNavigationPath = (navigation?: InternalSidebarNavigation): boolean => { + if (!navigation) { + return false; + } + const { sidebar, activeFeedEntryType } = navigation; + return (sidebar === ViewType.ACTIVITY || sidebar === ViewType.DETAILS) && + (activeFeedEntryType === FeedEntryType.VERSIONS); + }; + + handlePanelRender = (panel: string): void => { + const { onPanelChange = noop } = this.props; + // Call onPanelChange only once with the initial panel + if (!this.initialPanel.current) { + this.initialPanel.current = panel; + onPanelChange(panel, true); + } + }; + + setBoxAiSidebarCacheValue = (key: 'agents' | 'encodedSession' | 'questions' | 'shouldShowLandingPage' | 'suggestedQuestions', value: any) => { + this.boxAiSidebarCache[key] = value; + }; + + findSidebarToRender = (): string | null => { + const { + defaultPanel, + features, + hasActivity, + hasBoxAI, + hasDetails, + hasDocGen, + hasMetadata, + hasSkills, + hasVersions, + internalSidebarNavigation, + isOpen, + } = this.props; + + + const { shouldBeDefaultPanel: shouldBoxAIBeDefaultPanel, showOnlyNavButton: showOnlyBoxAINavButton } = + getFeatureConfig(features, 'boxai.sidebar'); + + const canShowBoxAISidebarPanel = hasBoxAI && !showOnlyBoxAINavButton; + + const panelsEligibility = { + [SIDEBAR_VIEW_BOXAI]: canShowBoxAISidebarPanel, + [SIDEBAR_VIEW_DOCGEN]: hasDocGen, + [SIDEBAR_VIEW_SKILLS]: hasSkills, + [SIDEBAR_VIEW_ACTIVITY]: hasActivity, + [SIDEBAR_VIEW_DETAILS]: hasDetails, + [SIDEBAR_VIEW_METADATA]: hasMetadata, + }; + + const showDefaultPanel: boolean = !!(defaultPanel && panelsEligibility[defaultPanel]); + + if (!isOpen || (!hasBoxAI && !hasActivity && !hasDetails && !hasMetadata && !hasSkills && !hasVersions)) { + return null; + } + + const currentSidebar = internalSidebarNavigation?.sidebar; + const versionId = internalSidebarNavigation?.versionId; + const activeFeedEntryType = internalSidebarNavigation?.activeFeedEntryType; + + if (currentSidebar === SIDEBAR_VIEW_BOXAI && canShowBoxAISidebarPanel) { + return SIDEBAR_VIEW_BOXAI; + } + + if (currentSidebar === SIDEBAR_VIEW_SKILLS && hasSkills) { + return SIDEBAR_VIEW_SKILLS; + } + + if (currentSidebar === SIDEBAR_VIEW_ACTIVITY && hasActivity) { + if (activeFeedEntryType === undefined || + activeFeedEntryType === FeedEntryType.COMMENTS || + activeFeedEntryType === FeedEntryType.TASKS || + (activeFeedEntryType === FeedEntryType.ANNOTATIONS && internalSidebarNavigation?.fileVersionId) + ) { + return SIDEBAR_VIEW_ACTIVITY; + } + } + + if (currentSidebar === SIDEBAR_VIEW_DETAILS && + hasDetails && + activeFeedEntryType !== FeedEntryType.VERSIONS && + versionId === undefined) + { + return SIDEBAR_VIEW_DETAILS; + } + + if (currentSidebar === SIDEBAR_VIEW_METADATA && hasMetadata) { + return SIDEBAR_VIEW_METADATA; + } + + if (currentSidebar === SIDEBAR_VIEW_DOCGEN && hasDocGen) { + return SIDEBAR_VIEW_DOCGEN; + } + + if (hasVersions && + (currentSidebar === SIDEBAR_VIEW_ACTIVITY || currentSidebar === SIDEBAR_VIEW_DETAILS) && + activeFeedEntryType === FeedEntryType.VERSIONS) + { + return SIDEBAR_VIEW_VERSIONS; + } + + // Determine default sidebar using the same logic as the router version + if (showDefaultPanel) { + return defaultPanel || null; + } if (canShowBoxAISidebarPanel && shouldBoxAIBeDefaultPanel) { + return SIDEBAR_VIEW_BOXAI; + } if (hasDocGen) { + return SIDEBAR_VIEW_DOCGEN; + } if (hasSkills) { + return SIDEBAR_VIEW_SKILLS; + } if (hasActivity) { + return SIDEBAR_VIEW_ACTIVITY; + } if (hasDetails) { + return SIDEBAR_VIEW_DETAILS; + } if (hasMetadata) { + return SIDEBAR_VIEW_METADATA; + } if (canShowBoxAISidebarPanel && !shouldBoxAIBeDefaultPanel) { + return SIDEBAR_VIEW_BOXAI; + } + + return null; + } + + /** + * Refreshes the contents of the active sidebar + * @returns {void} + */ + refresh(shouldRefreshCache: boolean = true): void { + const { current: boxAISidebar } = this.boxAISidebar; + const { current: activitySidebar } = this.activitySidebar; + const { current: detailsSidebar } = this.detailsSidebar; + const { current: metadataSidebar } = this.metadataSidebar; + const { current: versionsSidebar } = this.versionsSidebar; + + if (boxAISidebar) { + boxAISidebar.refresh(); + } + + if (activitySidebar) { + activitySidebar.refresh(shouldRefreshCache); + } + + if (detailsSidebar) { + detailsSidebar.refresh(); + } + + if (metadataSidebar) { + metadataSidebar.refresh(); + } + + if (versionsSidebar) { + versionsSidebar.refresh(); + } + } + + render() { + const { + activitySidebarProps, + boxAISidebarProps, + currentUser, + currentUserError, + detailsSidebarProps, + docGenSidebarProps, + elementId, + features, + file, + fileId, + getPreview, + getViewer, + hasActivity, + hasBoxAI, + hasDetails, + hasMetadata, + hasSkills, + hasVersions, + internalSidebarNavigation, + internalSidebarNavigationHandler, + isOpen, + metadataSidebarProps, + onAnnotationSelect, + onVersionChange, + onVersionHistoryClick, + versionsSidebarProps, + } = this.props; + + const { isInitialized } = this.state; + + if (!isOpen || (!hasBoxAI && !hasActivity && !hasDetails && !hasMetadata && !hasSkills && !hasVersions)) { + return null; + } + + const sidebarToRender = this.findSidebarToRender(); + + if (sidebarToRender) { + if (sidebarToRender === SIDEBAR_VIEW_VERSIONS) { + const parentName = internalSidebarNavigation?.sidebar; + if (parentName) { + this.handlePanelRender(parentName); + } + } else { + this.handlePanelRender(sidebarToRender); + } + } + + // Render the appropriate sidebar based on currentSidebar + if (sidebarToRender === SIDEBAR_VIEW_BOXAI) { + return ( + + ); + } + + if (sidebarToRender === SIDEBAR_VIEW_SKILLS) { + return ( + + ); + } + + if (sidebarToRender === SIDEBAR_VIEW_ACTIVITY) { + // Extract activity-specific params from internal navigation + const activeFeedEntryId = internalSidebarNavigation?.activeFeedEntryId; + const rawActiveFeedEntryType = internalSidebarNavigation?.activeFeedEntryType; + // Convert activeFeedEntryType to match what ActivitySidebar expects (same as router version) + const activeFeedEntryType = rawActiveFeedEntryType + ? URL_TO_FEED_ITEM_TYPE[rawActiveFeedEntryType] || rawActiveFeedEntryType + : undefined; + + return ( + + ); + } + + if (sidebarToRender === SIDEBAR_VIEW_DETAILS) { + return ( + + ); + } + + if (sidebarToRender === SIDEBAR_VIEW_METADATA) { + // Extract metadata-specific params from internal navigation + const filteredTemplateIds = internalSidebarNavigation?.filteredTemplateIds || []; + const isMetadataSidebarRedesignEnabled = isFeatureEnabled(features, 'metadata.redesign.enabled'); + const isMetadataAiSuggestionsEnabled = isFeatureEnabled(features, 'metadata.aiSuggestions.enabled'); + + + return isMetadataSidebarRedesignEnabled ? ( + + ) : ( + + ); + } + + if (sidebarToRender === SIDEBAR_VIEW_DOCGEN) { + return ( + + ); + } + + if (sidebarToRender === SIDEBAR_VIEW_VERSIONS) { + const versionId = internalSidebarNavigation?.versionId; + const parentName = internalSidebarNavigation?.sidebar; // Should be 'activity' or 'details' + return ( + + ); + } + + return null; + } +} + +class SidebarPanels extends React.Component { + render() { + const { routerDisabled, ...otherProps } = this.props; + + if (routerDisabled) { + return ; + } + + return ; + } +} + +export { SidebarPanelsRouter as SidebarPanelsComponent }; +export { SidebarPanelsRouterDisabled as SidebarPanelsRouterDisabledComponent }; export default flow([ withFeatureConsumer, withSidebarAnnotations, diff --git a/src/elements/content-sidebar/__mocks__/SidebarUtils.js b/src/elements/content-sidebar/__mocks__/SidebarUtils.js index ab3494c172..440ab157e9 100644 --- a/src/elements/content-sidebar/__mocks__/SidebarUtils.js +++ b/src/elements/content-sidebar/__mocks__/SidebarUtils.js @@ -24,7 +24,13 @@ export default { }, [SIDEBAR_VIEW_METADATA_REDESIGN]: class MetadataSidebarRedesigned extends React.Component { render() { - return
; + const { filteredTemplateIds } = this.props; + return ( +
+ ); } }, skills: class SkillsSidebar extends React.Component { @@ -34,12 +40,26 @@ export default { }, activity: class ActivitySidebar extends React.Component { render() { - return
; + const { activeFeedEntryType, activeFeedEntryId, hasSidebarInitialized } = this.props; + return ( +
+ ); } }, versions: class VersionsSidebar extends React.Component { render() { - return
; + const { versionId } = this.props; + return ( +
+ ); } }, docgen: class DocGenSidebar extends React.Component { diff --git a/src/elements/content-sidebar/__tests__/SidebarPanels.test.js b/src/elements/content-sidebar/__tests__/SidebarPanels.test.js index 06d31a82f3..77b2c31672 100644 --- a/src/elements/content-sidebar/__tests__/SidebarPanels.test.js +++ b/src/elements/content-sidebar/__tests__/SidebarPanels.test.js @@ -1,41 +1,26 @@ import * as React from 'react'; -import { mount } from 'enzyme/build'; import { MemoryRouter } from 'react-router-dom'; -import { render, screen } from '@testing-library/react'; +import { render, screen } from '../../../test-utils/testing-library'; import { FEED_ITEM_TYPE_ANNOTATION, FEED_ITEM_TYPE_COMMENT, FEED_ITEM_TYPE_TASK } from '../../../constants'; -import { SidebarPanelsComponent as SidebarPanels } from '../SidebarPanels'; +import { + SidebarPanelsComponent as SidebarPanelsRouter, + SidebarPanelsRouterDisabledComponent as SidebarPanelsRouterDisabled, +} from '../SidebarPanels'; // mock lazy imports jest.mock('../SidebarUtils'); describe('elements/content-sidebar/SidebarPanels', () => { - const getWrapper = ({ path = '/', ...rest } = {}) => - mount( - , - { - wrappingComponent: MemoryRouter, - wrappingComponentProps: { - initialEntries: [path], - keyLength: 0, - }, - }, - ); + const onPanelChange = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); const getSidebarPanels = ({ path = '/', ...props }) => ( - { hasSkills hasVersions isOpen + onPanelChange={onPanelChange} {...props} /> - , ); + const renderSidebarPanels = ({ path = '/', ...props } = {}) => render(getSidebarPanels({ path, ...props })); + describe('render', () => { test.each` path | sidebar - ${'/activity'} | ${'ActivitySidebar'} - ${'/activity/comments'} | ${'ActivitySidebar'} - ${'/activity/comments/1234'} | ${'ActivitySidebar'} - ${'/activity/tasks'} | ${'ActivitySidebar'} - ${'/activity/tasks/1234'} | ${'ActivitySidebar'} - ${'/activity/annotations/1234/5678'} | ${'ActivitySidebar'} - ${'/activity/annotations/1234'} | ${'ActivitySidebar'} - ${'/activity/versions'} | ${'VersionsSidebar'} - ${'/activity/versions/1234'} | ${'VersionsSidebar'} - ${'/details'} | ${'DetailsSidebar'} - ${'/details/versions'} | ${'VersionsSidebar'} - ${'/details/versions/1234'} | ${'VersionsSidebar'} - ${'/metadata'} | ${'MetadataSidebar'} - ${'/metadata/filteredTemplates/1,3'} | ${'MetadataSidebar'} - ${'/skills'} | ${'SkillsSidebar'} - ${'/boxai'} | ${'BoxAISidebar'} - ${'/docgen'} | ${'DocGenSidebar'} - ${'/nonsense'} | ${'DocGenSidebar'} - ${'/'} | ${'DocGenSidebar'} + ${'/activity'} | ${'activity-sidebar'} + ${'/activity/comments'} | ${'activity-sidebar'} + ${'/activity/comments/1234'} | ${'activity-sidebar'} + ${'/activity/tasks'} | ${'activity-sidebar'} + ${'/activity/tasks/1234'} | ${'activity-sidebar'} + ${'/activity/annotations/1234/5678'} | ${'activity-sidebar'} + ${'/activity/annotations/1234'} | ${'activity-sidebar'} + ${'/activity/versions'} | ${'versions-sidebar'} + ${'/activity/versions/1234'} | ${'versions-sidebar'} + ${'/details'} | ${'details-sidebar'} + ${'/details/versions'} | ${'versions-sidebar'} + ${'/details/versions/1234'} | ${'versions-sidebar'} + ${'/metadata'} | ${'metadata-sidebar'} + ${'/metadata/filteredTemplates/1,3'} | ${'metadata-sidebar'} + ${'/skills'} | ${'skills-sidebar'} + ${'/boxai'} | ${'boxai-sidebar'} + ${'/docgen'} | ${'docgen-sidebar'} + ${'/nonsense'} | ${'docgen-sidebar'} + ${'/'} | ${'docgen-sidebar'} `('should render $sidebar given the path $path', ({ path, sidebar }) => { - const wrapper = getWrapper({ path }); - expect(wrapper.exists(sidebar)).toBe(true); + renderSidebarPanels({ path }); + expect(screen.getByTestId(sidebar)).toBeInTheDocument(); }); test.each` path | sidebar - ${'/nonsense'} | ${'BoxAISidebar'} - ${'/'} | ${'BoxAISidebar'} + ${'/nonsense'} | ${'boxai-sidebar'} + ${'/'} | ${'boxai-sidebar'} `( 'should render $sidebar given feature boxai.sidebar.shouldBeDefaultPanel = true and the path $path', ({ path, sidebar }) => { - const wrapper = getWrapper({ + renderSidebarPanels({ features: { boxai: { sidebar: { shouldBeDefaultPanel: true } } }, path, }); - expect(wrapper.exists(sidebar)).toBe(true); + expect(screen.getByTestId(sidebar)).toBeInTheDocument(); }, ); @@ -106,13 +93,9 @@ describe('elements/content-sidebar/SidebarPanels', () => { `( 'should render $sidebar and call onPanelChange with $expectedPanelName given the path = "/" and defaultPanel = $defaultPanel', ({ defaultPanel, sidebar, expectedPanelName }) => { - const onPanelChange = jest.fn(); - render( - getSidebarPanels({ + renderSidebarPanels({ defaultPanel, - onPanelChange, - }), - ); + }); expect(screen.getByTestId(sidebar)).toBeInTheDocument(); expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); }, @@ -125,14 +108,10 @@ describe('elements/content-sidebar/SidebarPanels', () => { `( 'should render $sidebar and call onPanelChange with $expectedPanelName given feature boxai.sidebar.shouldBeDefaultPanel = true and the path = "/" and defaultPanel = $defaultPanel', ({ defaultPanel, sidebar, expectedPanelName }) => { - const onPanelChange = jest.fn(); - render( - getSidebarPanels({ + renderSidebarPanels({ defaultPanel, features: { boxai: { sidebar: { shouldBeDefaultPanel: true } } }, - onPanelChange, - }), - ); + }); expect(screen.getByTestId(sidebar)).toBeInTheDocument(); expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); }, @@ -161,9 +140,7 @@ describe('elements/content-sidebar/SidebarPanels', () => { showOnlyBoxAINavButton, expectedPanelName, }) => { - const onPanelChange = jest.fn(); - render( - getSidebarPanels({ + renderSidebarPanels({ features: { boxai: { sidebar: { showOnlyNavButton: showOnlyBoxAINavButton } } }, defaultPanel, hasActivity, @@ -172,9 +149,7 @@ describe('elements/content-sidebar/SidebarPanels', () => { hasSkills, hasDocGen, hasBoxAI, - onPanelChange, - }), - ); + }); expect(screen.getByTestId(expectedSidebar)).toBeInTheDocument(); expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); }, @@ -203,9 +178,7 @@ describe('elements/content-sidebar/SidebarPanels', () => { showOnlyBoxAINavButton, expectedPanelName, }) => { - const onPanelChange = jest.fn(); - render( - getSidebarPanels({ + renderSidebarPanels({ features: { boxai: { sidebar: { @@ -221,9 +194,7 @@ describe('elements/content-sidebar/SidebarPanels', () => { hasSkills, hasDocGen, hasBoxAI, - onPanelChange, - }), - ); + }); expect(screen.getByTestId(expectedSidebar)).toBeInTheDocument(); expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); }, @@ -252,14 +223,10 @@ describe('elements/content-sidebar/SidebarPanels', () => { `( 'should render $sidebar and call onPanelChange with $expectedPanelName given the path = $path and defaultPanel = $defaultPanel', ({ path, sidebar, defaultPanel, expectedPanelName }) => { - const onPanelChange = jest.fn(); - render( - getSidebarPanels({ + renderSidebarPanels({ defaultPanel, - onPanelChange, path, - }), - ); + }); expect(screen.getByTestId(sidebar)).toBeInTheDocument(); expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); }, @@ -288,13 +255,9 @@ describe('elements/content-sidebar/SidebarPanels', () => { ${'/nonsense'} | ${'docgen'} ${'/'} | ${'docgen'} `('should call onPanelChange with $expectedPanelName given the path = $path', ({ path, expectedPanelName }) => { - const onPanelChange = jest.fn(); - render( - getSidebarPanels({ + renderSidebarPanels({ path, - onPanelChange, - }), - ); + }); expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); }); @@ -305,14 +268,10 @@ describe('elements/content-sidebar/SidebarPanels', () => { `( 'should call onPanelChange with $expectedPanelName given feature boxai.sidebar.shouldBeDefaultPanel = true and the path = $path', ({ path, expectedPanelName }) => { - const onPanelChange = jest.fn(); - render( - getSidebarPanels({ + renderSidebarPanels({ features: { boxai: { sidebar: { shouldBeDefaultPanel: true } } }, path, - onPanelChange, - }), - ); + }); expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); }, ); @@ -351,9 +310,7 @@ describe('elements/content-sidebar/SidebarPanels', () => { showOnlyBoxAINavButton, expectedPanelName, }) => { - const onPanelChange = jest.fn(); - render( - getSidebarPanels({ + renderSidebarPanels({ features: { boxai: { sidebar: { showOnlyNavButton: showOnlyBoxAINavButton } } }, hasActivity, hasBoxAI, @@ -362,10 +319,8 @@ describe('elements/content-sidebar/SidebarPanels', () => { hasMetadata, hasSkills, hasVersions, - onPanelChange, path, - }), - ); + }); expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); }, ); @@ -404,9 +359,7 @@ describe('elements/content-sidebar/SidebarPanels', () => { showOnlyBoxAINavButton, expectedPanelName, }) => { - const onPanelChange = jest.fn(); - render( - getSidebarPanels({ + renderSidebarPanels({ features: { boxai: { sidebar: { @@ -422,25 +375,18 @@ describe('elements/content-sidebar/SidebarPanels', () => { hasMetadata, hasSkills, hasVersions, - onPanelChange, path, - }), - ); + }); expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); }, ); test('should call onPanelChange only once with the initial panel value', () => { - const onPanelChange = jest.fn(); - const { rerender } = render( - getSidebarPanels({ - onPanelChange, + const { rerender } = renderSidebarPanels({ path: '/details', - }), - ); + }); rerender( getSidebarPanels({ - onPanelChange, path: '/activity', }), ); @@ -449,14 +395,14 @@ describe('elements/content-sidebar/SidebarPanels', () => { }); test('should render nothing if the sidebar is closed', () => { - const wrapper = getWrapper({ + const { container } = renderSidebarPanels({ isOpen: false, }); - expect(wrapper.isEmptyRender()).toBe(true); + expect(container.firstChild).toBeNull(); }); test('should render nothing if all sidebars are disabled', () => { - const wrapper = getWrapper({ + const { container } = renderSidebarPanels({ hasBoxAI: false, hasActivity: false, hasDetails: false, @@ -464,84 +410,78 @@ describe('elements/content-sidebar/SidebarPanels', () => { hasSkills: false, hasVersions: false, }); - expect(wrapper.isEmptyRender()).toBe(true); + expect(container.firstChild).toBeNull(); }); describe('activity sidebar', () => { test('should render with tasks deeplink', () => { - const wrapper = getWrapper({ path: '/activity/tasks/12345' }); - expect(wrapper.find('ActivitySidebar').props()).toMatchObject({ - activeFeedEntryType: FEED_ITEM_TYPE_TASK, - activeFeedEntryId: '12345', - }); + renderSidebarPanels({ path: '/activity/tasks/12345' }); + const activitySidebar = screen.getByTestId('activity-sidebar'); + expect(activitySidebar).toHaveAttribute('data-active-feed-entry-type', FEED_ITEM_TYPE_TASK); + expect(activitySidebar).toHaveAttribute('data-active-feed-entry-id', '12345'); }); test('should render with comments deeplink', () => { - const wrapper = getWrapper({ path: '/activity/comments/12345' }); - expect(wrapper.find('ActivitySidebar').props()).toMatchObject({ - activeFeedEntryType: FEED_ITEM_TYPE_COMMENT, - activeFeedEntryId: '12345', - }); + renderSidebarPanels({ path: '/activity/comments/12345' }); + const activitySidebar = screen.getByTestId('activity-sidebar'); + expect(activitySidebar).toHaveAttribute('data-active-feed-entry-type', FEED_ITEM_TYPE_COMMENT); + expect(activitySidebar).toHaveAttribute('data-active-feed-entry-id', '12345'); }); test('should render with versions deeplink', () => { - const wrapper = getWrapper({ path: '/activity/versions/12345' }); - expect(wrapper.find('VersionsSidebar').props()).toMatchObject({ - versionId: '12345', - }); + renderSidebarPanels({ path: '/activity/versions/12345' }); + const versionsSidebar = screen.getByTestId('versions-sidebar'); + expect(versionsSidebar).toHaveAttribute('data-version-id', '12345'); }); test('should render with annotations deeplink', () => { - const wrapper = getWrapper({ path: '/activity/annotations/12345/67890' }); - expect(wrapper.find('ActivitySidebar').props()).toMatchObject({ - activeFeedEntryType: FEED_ITEM_TYPE_ANNOTATION, - activeFeedEntryId: '67890', - }); + renderSidebarPanels({ path: '/activity/annotations/12345/67890' }); + const activitySidebar = screen.getByTestId('activity-sidebar'); + expect(activitySidebar).toHaveAttribute('data-active-feed-entry-type', FEED_ITEM_TYPE_ANNOTATION); + expect(activitySidebar).toHaveAttribute('data-active-feed-entry-id', '67890'); }); test('should not pass down activeFeedEntry props with partial annotations deeplink', () => { - const wrapper = getWrapper({ path: '/activity/annotations/12345' }); - expect(wrapper.find('ActivitySidebar').props()).toMatchObject({ - activeFeedEntryType: undefined, - activeFeedEntryId: undefined, - }); + renderSidebarPanels({ path: '/activity/annotations/12345' }); + const activitySidebar = screen.getByTestId('activity-sidebar'); + expect(activitySidebar).not.toHaveAttribute('data-active-feed-entry-type'); + expect(activitySidebar).not.toHaveAttribute('data-active-feed-entry-id'); }); }); describe('metadata sidebar', () => { test('should render with filteredTemplates deeplink', () => { - const wrapper = getWrapper({ + renderSidebarPanels({ path: '/metadata/filteredTemplates/123,124', features: { metadata: { redesign: { enabled: true } } }, }); - expect(wrapper.find('MetadataSidebarRedesigned').props().filteredTemplateIds).toEqual(['123', '124']); + const metadataSidebar = screen.getByTestId('metadata-sidebar-redesigned'); + expect(metadataSidebar).toHaveAttribute('data-filtered-template-ids', JSON.stringify(['123', '124'])); }); - test('should render redesigned sidebar if it is enabled', () => { - const wrapper = getWrapper({ + + test('should render redesigned sidebar if it is enabled', () => { + renderSidebarPanels({ path: '/metadata', features: { metadata: { redesign: { enabled: true } } }, }); - expect(wrapper.exists('MetadataSidebarRedesigned')).toBe(true); + expect(screen.getByTestId('metadata-sidebar-redesigned')).toBeInTheDocument(); }); }); describe('details sidebar', () => { test('should render with versions deeplink', () => { - const wrapper = getWrapper({ path: '/details/versions/12345' }); - expect(wrapper.find('VersionsSidebar').props()).toMatchObject({ - versionId: '12345', - }); + renderSidebarPanels({ path: '/details/versions/12345' }); + const versionsSidebar = screen.getByTestId('versions-sidebar'); + expect(versionsSidebar).toHaveAttribute('data-version-id', '12345'); }); }); describe('boxai sidebar', () => { test('should render, given feature boxai.sidebar.shouldBeDefaultPanel = true and hasBoxAI = true and feature boxai.sidebar.showOnlyNavButton = false', () => { - render( - getSidebarPanels({ + renderSidebarPanels({ features: { boxai: { sidebar: { shouldBeDefaultPanel: true, showOnlyNavButton: false } } }, hasBoxAI: true, - }), - ); + }); expect(screen.getByTestId('boxai-sidebar')).toBeInTheDocument(); }); @@ -553,12 +493,10 @@ describe('elements/content-sidebar/SidebarPanels', () => { `( 'should not render, given hasBoxAI = $hasBoxAI and feature boxai.sidebar.showOnlyNavButton = $showOnlyNavButton', ({ hasBoxAI, showOnlyNavButton }) => { - render( - getSidebarPanels({ + renderSidebarPanels({ features: { boxai: { sidebar: { showOnlyNavButton } } }, hasBoxAI, - }), - ); + }); expect(screen.queryByTestId('boxai-sidebar')).not.toBeInTheDocument(); }, ); @@ -566,35 +504,52 @@ describe('elements/content-sidebar/SidebarPanels', () => { describe('first loaded behavior', () => { test('should update isInitialized state on mount', () => { - const wrapper = getWrapper({ path: '/activity' }); - const sidebarPanels = wrapper.find(SidebarPanels); - expect(sidebarPanels.state('isInitialized')).toBe(true); + renderSidebarPanels({ path: '/activity' }); + const activitySidebar = screen.getByTestId('activity-sidebar'); + expect(activitySidebar).toHaveAttribute('data-has-sidebar-initialized', 'true'); }); }); }); describe('refresh()', () => { test.each([true, false])('should call the sidebars with the appropriate argument', shouldRefreshCache => { - const instance = getWrapper().find(SidebarPanels).instance(); + const sidebarPanelsRef = React.createRef(); - ['boxAISidebar', 'activitySidebar', 'detailsSidebar', 'metadataSidebar', 'versionsSidebar'].forEach( - sidebar => { - instance[sidebar] = { current: { refresh: jest.fn() } }; - }, - ); + renderSidebarPanels({ + path: '/activity', + ref: sidebarPanelsRef, + }); + + // Create mock refresh functions for each sidebar + const mockRefreshFunctions = { + boxAISidebar: jest.fn(), + activitySidebar: jest.fn(), + detailsSidebar: jest.fn(), + metadataSidebar: jest.fn(), + versionsSidebar: jest.fn(), + }; + + // Mock the sidebar refs + Object.keys(mockRefreshFunctions).forEach(sidebarName => { + sidebarPanelsRef.current[sidebarName] = { + current: { refresh: mockRefreshFunctions[sidebarName] }, + }; + }); - instance.refresh(shouldRefreshCache); + // Call the refresh method + sidebarPanelsRef.current.refresh(shouldRefreshCache); - expect(instance.activitySidebar.current.refresh).toHaveBeenCalledWith(shouldRefreshCache); - expect(instance.boxAISidebar.current.refresh).toHaveBeenCalledWith(); - expect(instance.detailsSidebar.current.refresh).toHaveBeenCalledWith(); - expect(instance.metadataSidebar.current.refresh).toHaveBeenCalledWith(); - expect(instance.versionsSidebar.current.refresh).toHaveBeenCalledWith(); + // Verify the calls + expect(mockRefreshFunctions.activitySidebar).toHaveBeenCalledWith(shouldRefreshCache); + expect(mockRefreshFunctions.boxAISidebar).toHaveBeenCalledWith(); + expect(mockRefreshFunctions.detailsSidebar).toHaveBeenCalledWith(); + expect(mockRefreshFunctions.metadataSidebar).toHaveBeenCalledWith(); + expect(mockRefreshFunctions.versionsSidebar).toHaveBeenCalledWith(); }); }); describe('componentDidUpdate', () => { - const onVersionChange = jest.fn(); + const mockOnVersionChange = jest.fn(); test.each([ ['/activity/versions/123', '/activity/versions/456'], @@ -602,15 +557,41 @@ describe('elements/content-sidebar/SidebarPanels', () => { ['/activity/versions', '/activity/versions/123'], ['/activity/versions', '/details/versions'], ])('should not reset the current version if the versions route is still active', (prevPathname, pathname) => { - const wrapper = getWrapper({ location: { pathname: prevPathname }, onVersionChange }); - wrapper.setProps({ location: { pathname } }); - expect(onVersionChange).not.toBeCalled(); + const { rerender } = renderSidebarPanels({ + path: prevPathname, + onVersionChange: mockOnVersionChange, + location: { pathname: prevPathname }, + }); + + rerender( + getSidebarPanels({ + path: pathname, + onVersionChange: mockOnVersionChange, + location: { pathname }, + }), + ); + + expect(mockOnVersionChange).not.toHaveBeenCalled(); }); test.each([true, false])('should not reset the current version if the sidebar is toggled', isOpen => { - const wrapper = getWrapper({ isOpen, location: { pathname: '/details/versions/123' }, onVersionChange }); - wrapper.setProps({ isOpen: !isOpen }); - expect(onVersionChange).not.toBeCalled(); + const { rerender } = renderSidebarPanels({ + path: '/details/versions/123', + isOpen, + onVersionChange: mockOnVersionChange, + location: { pathname: '/details/versions/123' }, + }); + + rerender( + getSidebarPanels({ + path: '/details/versions/123', + isOpen: !isOpen, + onVersionChange: mockOnVersionChange, + location: { pathname: '/details/versions/123' }, + }), + ); + + expect(mockOnVersionChange).not.toHaveBeenCalled(); }); test.each([ @@ -621,9 +602,731 @@ describe('elements/content-sidebar/SidebarPanels', () => { ['/details/versions/123', '/details'], ['/details/versions', '/metadata'], ])('should reset the current version if the versions route is no longer active', (prevPathname, pathname) => { - const wrapper = getWrapper({ location: { pathname: prevPathname }, onVersionChange }); - wrapper.setProps({ location: { pathname } }); - expect(onVersionChange).toBeCalledWith(null); + const { rerender } = renderSidebarPanels({ + path: prevPathname, + onVersionChange: mockOnVersionChange, + location: { pathname: prevPathname }, + }); + + rerender( + getSidebarPanels({ + path: pathname, + onVersionChange: mockOnVersionChange, + location: { pathname }, + }), + ); + + expect(mockOnVersionChange).toHaveBeenCalledWith(null); + }); + }); + + describe('routerDisabled mode', () => { + const mockInternalSidebarNavigationHandler = jest.fn(); + + beforeEach(() => { + mockInternalSidebarNavigationHandler.mockClear(); + }); + + const getSidebarPanelsRouterDisabled = (props = {}) => ( + + ); + + const renderSidebarPanelsRouterDisabled = (props = {}) => render(getSidebarPanelsRouterDisabled(props)); + + describe('render', () => { + test.each` + internalSidebarNavigation | sidebar + ${{ sidebar: 'activity' }} | ${'activity-sidebar'} + ${{ sidebar: 'activity', activeFeedEntryType: 'comments' }} | ${'activity-sidebar'} + ${{ sidebar: 'activity', activeFeedEntryType: 'comments', activeFeedEntryId: '1234' }} | ${'activity-sidebar'} + ${{ sidebar: 'activity', activeFeedEntryType: 'tasks' }} | ${'activity-sidebar'} + ${{ sidebar: 'activity', activeFeedEntryType: 'tasks', activeFeedEntryId: '1234' }} | ${'activity-sidebar'} + ${{ sidebar: 'activity', activeFeedEntryType: 'annotations', activeFeedEntryId: '5678', fileVersionId: '1234' }} | ${'activity-sidebar'} + ${{ sidebar: 'activity', activeFeedEntryType: 'annotations', fileVersionId: '1234' }} | ${'activity-sidebar'} + ${{ sidebar: 'activity', activeFeedEntryType: 'versions' }} | ${'versions-sidebar'} + ${{ sidebar: 'activity', activeFeedEntryType: 'versions', versionId: '1234' }} | ${'versions-sidebar'} + ${{ sidebar: 'details' }} | ${'details-sidebar'} + ${{ sidebar: 'details', activeFeedEntryType: 'versions' }} | ${'versions-sidebar'} + ${{ sidebar: 'details', activeFeedEntryType: 'versions', versionId: '1234' }} | ${'versions-sidebar'} + ${{ sidebar: 'metadata' }} | ${'metadata-sidebar'} + ${{ sidebar: 'metadata', filteredTemplateIds: ['1', '3'] }} | ${'metadata-sidebar'} + ${{ sidebar: 'skills' }} | ${'skills-sidebar'} + ${{ sidebar: 'boxai' }} | ${'boxai-sidebar'} + ${{ sidebar: 'docgen' }} | ${'docgen-sidebar'} + ${undefined} | ${'docgen-sidebar'} + `( + 'should render $sidebar given internalSidebarNavigation = $internalSidebarNavigation', + ({ internalSidebarNavigation, sidebar }) => { + renderSidebarPanelsRouterDisabled({ internalSidebarNavigation }); + expect(screen.getByTestId(sidebar)).toBeInTheDocument(); + }, + ); + + test.each` + internalSidebarNavigation | sidebar + ${undefined} | ${'boxai-sidebar'} + ${{}} | ${'boxai-sidebar'} + `( + 'should render $sidebar given feature boxai.sidebar.shouldBeDefaultPanel = true and internalSidebarNavigation = $internalSidebarNavigation', + ({ internalSidebarNavigation, sidebar }) => { + renderSidebarPanelsRouterDisabled({ + features: { boxai: { sidebar: { shouldBeDefaultPanel: true } } }, + internalSidebarNavigation, + }); + expect(screen.getByTestId(sidebar)).toBeInTheDocument(); + }, + ); + + test.each` + defaultPanel | sidebar | expectedPanelName + ${'activity'} | ${'activity-sidebar'} | ${'activity'} + ${'docgen'} | ${'docgen-sidebar'} | ${'docgen'} + ${'details'} | ${'details-sidebar'} | ${'details'} + ${'metadata'} | ${'metadata-sidebar'} | ${'metadata'} + ${'skills'} | ${'skills-sidebar'} | ${'skills'} + ${'boxai'} | ${'boxai-sidebar'} | ${'boxai'} + ${'nonsense'} | ${'docgen-sidebar'} | ${'docgen'} + ${undefined} | ${'docgen-sidebar'} | ${'docgen'} + `( + 'should render $sidebar and call onPanelChange with $expectedPanelName given internalSidebarNavigation = undefined and defaultPanel = $defaultPanel', + ({ defaultPanel, sidebar, expectedPanelName }) => { + renderSidebarPanelsRouterDisabled({ + defaultPanel, + internalSidebarNavigation: undefined, + }); + expect(screen.getByTestId(sidebar)).toBeInTheDocument(); + expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); + }, + ); + + test.each` + defaultPanel | sidebar | expectedPanelName + ${'nonsense'} | ${'boxai-sidebar'} | ${'boxai'} + ${undefined} | ${'boxai-sidebar'} | ${'boxai'} + `( + 'should render $sidebar and call onPanelChange with $expectedPanelName given feature boxai.sidebar.shouldBeDefaultPanel = true and internalSidebarNavigation = undefined and defaultPanel = $defaultPanel', + ({ defaultPanel, sidebar, expectedPanelName }) => { + renderSidebarPanelsRouterDisabled({ + defaultPanel, + features: { boxai: { sidebar: { shouldBeDefaultPanel: true } } }, + internalSidebarNavigation: undefined, + }); + expect(screen.getByTestId(sidebar)).toBeInTheDocument(); + expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); + }, + ); + + test.each` + defaultPanel | expectedSidebar | hasActivity | hasDetails | hasMetadata | hasSkills | hasDocGen | hasBoxAI | showOnlyBoxAINavButton | expectedPanelName + ${'activity'} | ${'docgen-sidebar'} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${'details'} | ${'docgen-sidebar'} | ${true} | ${false} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${'metadata'} | ${'docgen-sidebar'} | ${true} | ${true} | ${false} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${'skills'} | ${'docgen-sidebar'} | ${true} | ${true} | ${true} | ${false} | ${true} | ${true} | ${false} | ${'docgen'} + ${'docgen'} | ${'activity-sidebar'} | ${true} | ${true} | ${true} | ${false} | ${false} | ${true} | ${false} | ${'activity'} + ${'boxai'} | ${'docgen-sidebar'} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${false} | ${'docgen'} + ${'boxai'} | ${'docgen-sidebar'} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${'docgen'} + `( + 'should render first available panel and call onPanelChange with $expectedPanelName for users without rights to render default panel, given internalSidebarNavigation = undefined and defaultPanel = $defaultPanel', + ({ + defaultPanel, + expectedSidebar, + hasActivity, + hasDetails, + hasMetadata, + hasSkills, + hasDocGen, + hasBoxAI, + showOnlyBoxAINavButton, + expectedPanelName, + }) => { + renderSidebarPanelsRouterDisabled({ + features: { boxai: { sidebar: { showOnlyNavButton: showOnlyBoxAINavButton } } }, + defaultPanel, + hasActivity, + hasDetails, + hasMetadata, + hasSkills, + hasDocGen, + hasBoxAI, + internalSidebarNavigation: undefined, + }); + + expect(screen.getByTestId(expectedSidebar)).toBeInTheDocument(); + expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); + }, + ); + + test.each` + defaultPanel | expectedSidebar | hasActivity | hasDetails | hasMetadata | hasSkills | hasDocGen | hasBoxAI | showOnlyBoxAINavButton | expectedPanelName + ${'activity'} | ${'boxai-sidebar'} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${'details'} | ${'boxai-sidebar'} | ${true} | ${false} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${'metadata'} | ${'boxai-sidebar'} | ${true} | ${true} | ${false} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${'skills'} | ${'boxai-sidebar'} | ${true} | ${true} | ${true} | ${false} | ${true} | ${true} | ${false} | ${'boxai'} + ${'docgen'} | ${'boxai-sidebar'} | ${true} | ${true} | ${true} | ${false} | ${false} | ${true} | ${false} | ${'boxai'} + ${'boxai'} | ${'docgen-sidebar'} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${false} | ${'docgen'} + ${'boxai'} | ${'docgen-sidebar'} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${'docgen'} + `( + 'should render first available panel and call onPanelChange with $expectedPanelName for users without rights to render default panel, given feature boxai.sidebar.shouldBeDefaultPanel = true and internalSidebarNavigation = undefined and defaultPanel = $defaultPanel', + ({ + defaultPanel, + expectedSidebar, + hasActivity, + hasDetails, + hasMetadata, + hasSkills, + hasDocGen, + hasBoxAI, + showOnlyBoxAINavButton, + expectedPanelName, + }) => { + renderSidebarPanelsRouterDisabled({ + features: { + boxai: { + sidebar: { + shouldBeDefaultPanel: true, + showOnlyNavButton: showOnlyBoxAINavButton, + }, + }, + }, + defaultPanel, + hasActivity, + hasDetails, + hasMetadata, + hasSkills, + hasDocGen, + hasBoxAI, + internalSidebarNavigation: undefined, + internalSidebarNavigationHandler: mockInternalSidebarNavigationHandler, + }); + + expect(screen.getByTestId(expectedSidebar)).toBeInTheDocument(); + expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); + }, + ); + + describe('sidebar selected with internalSidebarNavigation should take precedence over default panel', () => { + test.each` + internalSidebarNavigation | sidebar | defaultPanel | expectedPanelName + ${{ sidebar: 'activity' }} | ${'activity-sidebar'} | ${'details'} | ${'activity'} + ${{ sidebar: 'activity', activeFeedEntryType: 'comments' }} | ${'activity-sidebar'} | ${'details'} | ${'activity'} + ${{ sidebar: 'activity', activeFeedEntryType: 'comments', activeFeedEntryId: '1234' }} | ${'activity-sidebar'} | ${'details'} | ${'activity'} + ${{ sidebar: 'activity', activeFeedEntryType: 'tasks' }} | ${'activity-sidebar'} | ${'details'} | ${'activity'} + ${{ sidebar: 'activity', activeFeedEntryType: 'tasks', activeFeedEntryId: '1234' }} | ${'activity-sidebar'} | ${'details'} | ${'activity'} + ${{ sidebar: 'activity', activeFeedEntryType: 'annotations', activeFeedEntryId: '5678', fileVersionId: '1234' }} | ${'activity-sidebar'} | ${'details'} | ${'activity'} + ${{ sidebar: 'activity', activeFeedEntryType: 'annotations', fileVersionId: '1234' }} | ${'activity-sidebar'} | ${'details'} | ${'activity'} + ${{ sidebar: 'activity', activeFeedEntryType: 'versions' }} | ${'versions-sidebar'} | ${'details'} | ${'activity'} + ${{ sidebar: 'activity', activeFeedEntryType: 'versions', versionId: '1234' }} | ${'versions-sidebar'} | ${'details'} | ${'activity'} + ${{ sidebar: 'details' }} | ${'details-sidebar'} | ${'activity'} | ${'details'} + ${{ sidebar: 'details', activeFeedEntryType: 'versions' }} | ${'versions-sidebar'} | ${'activity'} | ${'details'} + ${{ sidebar: 'details', activeFeedEntryType: 'versions', versionId: '1234' }} | ${'versions-sidebar'} | ${'activity'} | ${'details'} + ${{ sidebar: 'metadata' }} | ${'metadata-sidebar'} | ${'details'} | ${'metadata'} + ${{ sidebar: 'metadata', filteredTemplateIds: ['1', '3'] }} | ${'metadata-sidebar'} | ${'details'} | ${'metadata'} + ${{ sidebar: 'skills' }} | ${'skills-sidebar'} | ${'details'} | ${'skills'} + ${{ sidebar: 'boxai' }} | ${'boxai-sidebar'} | ${'details'} | ${'boxai'} + ${{ sidebar: 'docgen' }} | ${'docgen-sidebar'} | ${'details'} | ${'docgen'} + `( + 'should render $sidebar and call onPanelChange with $expectedPanelName given internalSidebarNavigation = $internalSidebarNavigation and defaultPanel = $defaultPanel', + ({ internalSidebarNavigation, sidebar, defaultPanel, expectedPanelName }) => { + renderSidebarPanelsRouterDisabled({ + defaultPanel, + internalSidebarNavigation, + }); + expect(screen.getByTestId(sidebar)).toBeInTheDocument(); + expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); + }, + ); + }); + + test.each` + internalSidebarNavigation | expectedPanelName + ${{ sidebar: 'activity' }} | ${'activity'} + ${{ sidebar: 'activity', activeFeedEntryType: 'comments' }} | ${'activity'} + ${{ sidebar: 'activity', activeFeedEntryType: 'comments', activeFeedEntryId: '1234' }} | ${'activity'} + ${{ sidebar: 'activity', activeFeedEntryType: 'tasks' }} | ${'activity'} + ${{ sidebar: 'activity', activeFeedEntryType: 'tasks', activeFeedEntryId: '1234' }} | ${'activity'} + ${{ sidebar: 'activity', activeFeedEntryType: 'annotations', activeFeedEntryId: '5678', fileVersionId: '1234' }} | ${'activity'} + ${{ sidebar: 'activity', activeFeedEntryType: 'annotations', fileVersionId: '1234' }} | ${'activity'} + ${{ sidebar: 'activity', activeFeedEntryType: 'versions' }} | ${'activity'} + ${{ sidebar: 'activity', activeFeedEntryType: 'versions', versionId: '1234' }} | ${'activity'} + ${{ sidebar: 'details' }} | ${'details'} + ${{ sidebar: 'details', activeFeedEntryType: 'versions' }} | ${'details'} + ${{ sidebar: 'details', activeFeedEntryType: 'versions', versionId: '1234' }} | ${'details'} + ${{ sidebar: 'metadata' }} | ${'metadata'} + ${{ sidebar: 'metadata', filteredTemplateIds: ['1', '3'] }} | ${'metadata'} + ${{ sidebar: 'skills' }} | ${'skills'} + ${{ sidebar: 'boxai' }} | ${'boxai'} + ${{ sidebar: 'docgen' }} | ${'docgen'} + ${undefined} | ${'docgen'} + `( + 'should call onPanelChange with $expectedPanelName given internalSidebarNavigation = $internalSidebarNavigation', + ({ internalSidebarNavigation, expectedPanelName }) => { + renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation, + }); + expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); + }, + ); + + test.each` + internalSidebarNavigation | expectedPanelName + ${undefined} | ${'boxai'} + ${{}} | ${'boxai'} + `( + 'should call onPanelChange with $expectedPanelName given feature boxai.sidebar.shouldBeDefaultPanel = true and internalSidebarNavigation = $internalSidebarNavigation', + ({ internalSidebarNavigation, expectedPanelName }) => { + renderSidebarPanelsRouterDisabled({ + features: { boxai: { sidebar: { shouldBeDefaultPanel: true } } }, + internalSidebarNavigation, + }); + expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); + }, + ); + + test.each` + internalSidebarNavigation | hasActivity | hasDetails | hasVersions | hasMetadata | hasSkills | hasDocGen | hasBoxAI | showOnlyBoxAINavButton | expectedPanelName + ${{ sidebar: 'activity' }} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${{ sidebar: 'activity', activeFeedEntryType: 'comments' }} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${{ sidebar: 'activity', activeFeedEntryType: 'comments', activeFeedEntryId: '1234' }} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${{ sidebar: 'activity', activeFeedEntryType: 'tasks' }} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${{ sidebar: 'activity', activeFeedEntryType: 'tasks', activeFeedEntryId: '1234' }} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${{ sidebar: 'activity', activeFeedEntryType: 'annotations', activeFeedEntryId: '5678', fileVersionId: '1234' }} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${{ sidebar: 'activity', activeFeedEntryType: 'annotations', fileVersionId: '1234' }} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${{ sidebar: 'activity', activeFeedEntryType: 'versions' }} | ${true} | ${true} | ${false} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${{ sidebar: 'activity', activeFeedEntryType: 'versions', versionId: '1234' }} | ${true} | ${true} | ${false} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${{ sidebar: 'details' }} | ${true} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${{ sidebar: 'details', activeFeedEntryType: 'versions' }} | ${true} | ${true} | ${false} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${{ sidebar: 'details', activeFeedEntryType: 'versions', versionId: '1234' }} | ${true} | ${true} | ${false} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${{ sidebar: 'metadata' }} | ${true} | ${true} | ${true} | ${false} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${{ sidebar: 'metadata', filteredTemplateIds: ['1', '3'] }} | ${true} | ${true} | ${true} | ${false} | ${true} | ${true} | ${true} | ${false} | ${'docgen'} + ${{ sidebar: 'skills' }} | ${true} | ${true} | ${true} | ${true} | ${false} | ${true} | ${true} | ${false} | ${'docgen'} + ${{ sidebar: 'docgen' }} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${true} | ${false} | ${'skills'} + ${{ sidebar: 'boxai' }} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${false} | ${'docgen'} + ${{ sidebar: 'boxai' }} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${'docgen'} + `( + 'should call onPanelChange with $expectedPanelName given internalSidebarNavigation = $internalSidebarNavigation for users without rights to render the panel for given navigation', + ({ + internalSidebarNavigation, + hasActivity, + hasDetails, + hasVersions, + hasMetadata, + hasSkills, + hasDocGen, + hasBoxAI, + showOnlyBoxAINavButton, + expectedPanelName, + }) => { + renderSidebarPanelsRouterDisabled({ + features: { boxai: { sidebar: { showOnlyNavButton: showOnlyBoxAINavButton } } }, + hasActivity, + hasBoxAI, + hasDetails, + hasDocGen, + hasMetadata, + hasSkills, + hasVersions, + internalSidebarNavigation, + }); + expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); + }, + ); + + test.each` + internalSidebarNavigation | hasActivity | hasDetails | hasVersions | hasMetadata | hasSkills | hasDocGen | hasBoxAI | showOnlyBoxAINavButton | expectedPanelName + ${{ sidebar: 'activity' }} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${{ sidebar: 'activity', activeFeedEntryType: 'comments' }} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${{ sidebar: 'activity', activeFeedEntryType: 'comments', activeFeedEntryId: '1234' }} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${{ sidebar: 'activity', activeFeedEntryType: 'tasks' }} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${{ sidebar: 'activity', activeFeedEntryType: 'tasks', activeFeedEntryId: '1234' }} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${{ sidebar: 'activity', activeFeedEntryType: 'annotations', activeFeedEntryId: '5678', fileVersionId: '1234' }} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${{ sidebar: 'activity', activeFeedEntryType: 'annotations', fileVersionId: '1234' }} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${{ sidebar: 'activity', activeFeedEntryType: 'versions' }} | ${true} | ${true} | ${false} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${{ sidebar: 'activity', activeFeedEntryType: 'versions', versionId: '1234' }} | ${true} | ${true} | ${false} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${{ sidebar: 'details' }} | ${true} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${{ sidebar: 'details', activeFeedEntryType: 'versions' }} | ${true} | ${true} | ${false} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${{ sidebar: 'details', activeFeedEntryType: 'versions', versionId: '1234' }} | ${true} | ${true} | ${false} | ${true} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${{ sidebar: 'metadata' }} | ${true} | ${true} | ${true} | ${false} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${{ sidebar: 'metadata', filteredTemplateIds: ['1', '3'] }} | ${true} | ${true} | ${true} | ${false} | ${true} | ${true} | ${true} | ${false} | ${'boxai'} + ${{ sidebar: 'skills' }} | ${true} | ${true} | ${true} | ${true} | ${false} | ${true} | ${true} | ${false} | ${'boxai'} + ${{ sidebar: 'docgen' }} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${true} | ${false} | ${'boxai'} + ${{ sidebar: 'boxai' }} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${false} | ${false} | ${'docgen'} + ${{ sidebar: 'boxai' }} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true} | ${'docgen'} + `( + 'should call onPanelChange with $expectedPanelName given feature boxai.sidebar.shouldBeDefaultPanel = true and internalSidebarNavigation = $internalSidebarNavigation for users without rights to render the panel for given navigation', + ({ + internalSidebarNavigation, + hasActivity, + hasDetails, + hasVersions, + hasMetadata, + hasSkills, + hasDocGen, + hasBoxAI, + showOnlyBoxAINavButton, + expectedPanelName, + }) => { + renderSidebarPanelsRouterDisabled({ + features: { + boxai: { + sidebar: { + shouldBeDefaultPanel: true, + showOnlyNavButton: showOnlyBoxAINavButton, + }, + }, + }, + hasActivity, + hasBoxAI, + hasDetails, + hasDocGen, + hasMetadata, + hasSkills, + hasVersions, + internalSidebarNavigation, + }); + expect(onPanelChange).toHaveBeenCalledWith(expectedPanelName, true); + }, + ); + + test('should call onPanelChange only once with the initial panel value', () => { + const { rerender } = renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation: { sidebar: 'details' }, + }); + rerender( + getSidebarPanelsRouterDisabled({ + internalSidebarNavigation: { sidebar: 'activity' }, + }), + ); + expect(onPanelChange).toHaveBeenCalledWith('details', true); + expect(onPanelChange).toHaveBeenCalledTimes(1); + }); + + test('should render nothing if the sidebar is closed', () => { + const { container } = renderSidebarPanelsRouterDisabled({ + isOpen: false, + }); + expect(container.firstChild).toBeNull(); + }); + + test('should render nothing if all sidebars are disabled', () => { + const { container } = renderSidebarPanelsRouterDisabled({ + hasBoxAI: false, + hasActivity: false, + hasDetails: false, + hasMetadata: false, + hasSkills: false, + hasVersions: false, + }); + expect(container.firstChild).toBeNull(); + }); + + describe('activity sidebar', () => { + test('should render with tasks deeplink', () => { + renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation: { + sidebar: 'activity', + activeFeedEntryType: 'tasks', + activeFeedEntryId: '12345', + }, + }); + const activitySidebar = screen.getByTestId('activity-sidebar'); + expect(activitySidebar).toHaveAttribute('data-active-feed-entry-type', FEED_ITEM_TYPE_TASK); + expect(activitySidebar).toHaveAttribute('data-active-feed-entry-id', '12345'); + }); + + test('should render with comments deeplink', () => { + renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation: { + sidebar: 'activity', + activeFeedEntryType: 'comments', + activeFeedEntryId: '12345', + }, + }); + const activitySidebar = screen.getByTestId('activity-sidebar'); + expect(activitySidebar).toHaveAttribute('data-active-feed-entry-type', FEED_ITEM_TYPE_COMMENT); + expect(activitySidebar).toHaveAttribute('data-active-feed-entry-id', '12345'); + }); + + test('should render with versions deeplink', () => { + renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation: { + sidebar: 'activity', + activeFeedEntryType: 'versions', + versionId: '12345', + }, + }); + const versionsSidebar = screen.getByTestId('versions-sidebar'); + expect(versionsSidebar).toHaveAttribute('data-version-id', '12345'); + }); + + test('should render with annotations deeplink', () => { + renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation: { + sidebar: 'activity', + activeFeedEntryType: 'annotations', + fileVersionId: '12345', + activeFeedEntryId: '67890', + }, + }); + const activitySidebar = screen.getByTestId('activity-sidebar'); + expect(activitySidebar).toHaveAttribute('data-active-feed-entry-type', FEED_ITEM_TYPE_ANNOTATION); + expect(activitySidebar).toHaveAttribute('data-active-feed-entry-id', '67890'); + }); + + test('should not pass down activeFeedEntry props with partial annotations deeplink', () => { + renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation: { + sidebar: 'activity', + activeFeedEntryType: 'annotations', + fileVersionId: '12345', + }, + }); + const activitySidebar = screen.getByTestId('activity-sidebar'); + expect(activitySidebar).not.toHaveAttribute('data-active-feed-entry-type'); + expect(activitySidebar).not.toHaveAttribute('data-active-feed-entry-id'); + }); + }); + + describe('metadata sidebar', () => { + test('should render with filteredTemplates deeplink', () => { + renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation: { + sidebar: 'metadata', + filteredTemplateIds: ['123', '124'], + }, + features: { metadata: { redesign: { enabled: true } } }, + }); + const metadataSidebar = screen.getByTestId('metadata-sidebar-redesigned'); + expect(metadataSidebar).toHaveAttribute('data-filtered-template-ids', JSON.stringify(['123', '124'])); + }); + + test('should render redesigned sidebar if it is enabled', () => { + renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation: { + sidebar: 'metadata', + }, + features: { metadata: { redesign: { enabled: true } } }, + }); + expect(screen.getByTestId('metadata-sidebar-redesigned')).toBeInTheDocument(); + }); + }); + + describe('details sidebar', () => { + test('should render with versions deeplink', () => { + renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation: { + sidebar: 'details', + activeFeedEntryType: 'versions', + versionId: '12345', + }, + }); + const versionsSidebar = screen.getByTestId('versions-sidebar'); + expect(versionsSidebar).toHaveAttribute('data-version-id', '12345'); + }); + }); + + describe('boxai sidebar', () => { + test('should render, given feature boxai.sidebar.shouldBeDefaultPanel = true and hasBoxAI = true and feature boxai.sidebar.showOnlyNavButton = false', () => { + renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation: { + sidebar: 'boxai', + }, + features: { boxai: { sidebar: { shouldBeDefaultPanel: true, showOnlyNavButton: false } } }, + hasBoxAI: true, + }); + expect(screen.getByTestId('boxai-sidebar')).toBeInTheDocument(); + }); + + test.each` + hasBoxAI | showOnlyNavButton + ${true} | ${true} + ${false} | ${true} + ${false} | ${false} + `( + 'should not render, given hasBoxAI = $hasBoxAI and feature boxai.sidebar.showOnlyNavButton = $showOnlyNavButton', + ({ hasBoxAI, showOnlyNavButton }) => { + renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation: { + sidebar: 'boxai', + }, + features: { boxai: { sidebar: { showOnlyNavButton } } }, + hasBoxAI, + }); + expect(screen.queryByTestId('boxai-sidebar')).not.toBeInTheDocument(); + }, + ); + }); + + describe('first loaded behavior', () => { + test('should update isInitialized state on mount', () => { + renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation: { + sidebar: 'activity', + }, + }); + const activitySidebar = screen.getByTestId('activity-sidebar'); + expect(activitySidebar).toHaveAttribute('data-has-sidebar-initialized', 'true'); + }); + }); + + describe('refresh()', () => { + test.each([true, false])('should call the sidebars with the appropriate argument', shouldRefreshCache => { + const sidebarPanelsRef = React.createRef(); + + renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation: { + sidebar: 'activity', + }, + ref: sidebarPanelsRef, + }); + + // Create mock refresh functions for each sidebar + const mockRefreshFunctions = { + boxAISidebar: jest.fn(), + activitySidebar: jest.fn(), + detailsSidebar: jest.fn(), + metadataSidebar: jest.fn(), + versionsSidebar: jest.fn(), + }; + + // Mock the sidebar refs + Object.keys(mockRefreshFunctions).forEach(sidebarName => { + sidebarPanelsRef.current[sidebarName] = { + current: { refresh: mockRefreshFunctions[sidebarName] }, + }; + }); + + // Call the refresh method + sidebarPanelsRef.current.refresh(shouldRefreshCache); + + // Verify the calls + expect(mockRefreshFunctions.activitySidebar).toHaveBeenCalledWith(shouldRefreshCache); + expect(mockRefreshFunctions.boxAISidebar).toHaveBeenCalledWith(); + expect(mockRefreshFunctions.detailsSidebar).toHaveBeenCalledWith(); + expect(mockRefreshFunctions.metadataSidebar).toHaveBeenCalledWith(); + expect(mockRefreshFunctions.versionsSidebar).toHaveBeenCalledWith(); + }); + }); + + describe('componentDidUpdate', () => { + const mockOnVersionChange = jest.fn(); + + beforeEach(() => { + mockOnVersionChange.mockClear(); + }); + + test.each([ + [ + { sidebar: 'activity', activeFeedEntryType: 'versions', versionId: '123' }, + { sidebar: 'activity', activeFeedEntryType: 'versions', versionId: '456' }, + ], + [ + { sidebar: 'activity', activeFeedEntryType: 'versions', versionId: '123' }, + { sidebar: 'details', activeFeedEntryType: 'versions', versionId: '456' }, + ], + [ + { sidebar: 'activity', activeFeedEntryType: 'versions' }, + { sidebar: 'activity', activeFeedEntryType: 'versions', versionId: '123' }, + ], + [ + { sidebar: 'activity', activeFeedEntryType: 'versions' }, + { sidebar: 'details', activeFeedEntryType: 'versions' }, + ], + ])('should not reset the current version if the versions route is still active', (prevInternalSidebarNavigation, internalSidebarNavigation) => { + const { rerender } = renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation: prevInternalSidebarNavigation, + onVersionChange: mockOnVersionChange, + }); + + rerender( + getSidebarPanelsRouterDisabled({ + internalSidebarNavigation, + onVersionChange: mockOnVersionChange, + }), + ); + + expect(mockOnVersionChange).not.toHaveBeenCalled(); + }); + + test.each([true, false])('should not reset the current version if the sidebar is toggled', isOpen => { + const { rerender } = renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation: { + sidebar: 'details', + activeFeedEntryType: 'versions', + versionId: '123', + }, + isOpen, + onVersionChange: mockOnVersionChange, + }); + + rerender( + getSidebarPanelsRouterDisabled({ + internalSidebarNavigation: { + sidebar: 'details', + activeFeedEntryType: 'versions', + versionId: '123', + }, + isOpen: !isOpen, + onVersionChange: mockOnVersionChange, + }), + ); + + expect(mockOnVersionChange).not.toHaveBeenCalled(); + }); + + test.each([ + [ + { sidebar: 'activity', activeFeedEntryType: 'versions', versionId: '123' }, + { sidebar: 'metadata' }, + ], + [ + { sidebar: 'activity', activeFeedEntryType: 'versions', versionId: '123' }, + { sidebar: 'activity' }, + ], + [ + { sidebar: 'activity', activeFeedEntryType: 'versions' }, + { sidebar: 'metadata' }, + ], + [ + { sidebar: 'details', activeFeedEntryType: 'versions', versionId: '123' }, + { sidebar: 'metadata' }, + ], + [ + { sidebar: 'details', activeFeedEntryType: 'versions', versionId: '123' }, + { sidebar: 'details' }, + ], + [ + { sidebar: 'details', activeFeedEntryType: 'versions' }, + { sidebar: 'metadata' }, + ], + ])('should reset the current version if the versions route is no longer active', (prevInternalSidebarNavigation, internalSidebarNavigation) => { + const { rerender } = renderSidebarPanelsRouterDisabled({ + internalSidebarNavigation: prevInternalSidebarNavigation, + onVersionChange: mockOnVersionChange, + }); + + rerender( + getSidebarPanelsRouterDisabled({ + internalSidebarNavigation, + onVersionChange: mockOnVersionChange, + }), + ); + + expect(mockOnVersionChange).toHaveBeenCalledWith(null); + }); + }); }); }); });