diff --git a/webapp/channels/src/plugins/registry.ts b/webapp/channels/src/plugins/registry.ts index d406e85a517..bedf19d27b8 100644 --- a/webapp/channels/src/plugins/registry.ts +++ b/webapp/channels/src/plugins/registry.ts @@ -1095,6 +1095,7 @@ export default class PluginRegistry { * Accepts the following: * - component - A react component to display in the Right-Hand Sidebar. * - title - A string or JSX element to display as a title for the RHS. + * - showPopout - Optional boolean (default: true). Set to false to hide the "Open in new window" button in the RHS header. * Returns: * - id: a unique identifier * - showRHSPlugin: the action to dispatch that will open the RHS. @@ -1104,12 +1105,15 @@ export default class PluginRegistry { registerRightHandSidebarComponent = reArg([ 'component', 'title', + 'showPopout', ], ({ component, title, + showPopout = true, }: { component: RightHandSidebarComponent['component']; title: ReactResolvable; + showPopout?: boolean; }) => { const id = generateId(); @@ -1118,6 +1122,7 @@ export default class PluginRegistry { pluginId: this.id, component, title: resolveReactElement(title), + showPopout, }); return {id, showRHSPlugin: showRHSPlugin(id), hideRHSPlugin: hideRHSPlugin(id), toggleRHSPlugin: toggleRHSPlugin(id)}; diff --git a/webapp/channels/src/plugins/rhs_plugin/index.ts b/webapp/channels/src/plugins/rhs_plugin/index.ts index 88756fa1cc4..2fe78f81291 100644 --- a/webapp/channels/src/plugins/rhs_plugin/index.ts +++ b/webapp/channels/src/plugins/rhs_plugin/index.ts @@ -21,6 +21,7 @@ function mapStateToProps(state: GlobalState) { pluggableId, title: pluginTitle, pluginId, + showPopout: pluginComponent?.showPopout ?? true, }; } diff --git a/webapp/channels/src/plugins/rhs_plugin/rhs_plugin.test.tsx b/webapp/channels/src/plugins/rhs_plugin/rhs_plugin.test.tsx new file mode 100644 index 00000000000..dfe30113499 --- /dev/null +++ b/webapp/channels/src/plugins/rhs_plugin/rhs_plugin.test.tsx @@ -0,0 +1,146 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; + +import type {DeepPartial} from '@mattermost/types/utilities'; + +import {renderWithContext, screen} from 'tests/react_testing_utils'; + +import type {GlobalState} from 'types/store'; + +import RhsPlugin from './rhs_plugin'; + +import ConnectedRhsPlugin from '.'; + +jest.mock('components/search_results_header', () => ({ + __esModule: true, + default: ({children, newWindowHandler}: {children: React.ReactNode; newWindowHandler?: () => void}) => ( +
+ {children} +
+ ), +})); + +jest.mock('plugins/pluggable', () => ({ + __esModule: true, + default: () =>
, +})); + +jest.mock('utils/popouts/popout_windows', () => ({ + popoutRhsPlugin: jest.fn(), +})); + +const baseState: DeepPartial = { + entities: { + general: {config: {}}, + teams: { + currentTeamId: 'team-id', + teams: {'team-id': {id: 'team-id', name: 'test-team'}}, + }, + channels: { + currentChannelId: 'channel-id', + channels: {'channel-id': {id: 'channel-id', name: 'test-channel'}}, + }, + preferences: {myPreferences: {}}, + }, + plugins: { + plugins: {'plugin-id': {name: 'Test Plugin'}}, + components: { + RightHandSidebarComponent: [], + }, + }, + views: { + rhs: {pluggableId: ''}, + }, +}; + +describe('RhsPlugin', () => { + describe('component', () => { + it('passes newWindowHandler to SearchResultsHeader when showPopout is true', () => { + renderWithContext( + , + baseState, + ); + + expect(screen.getByTestId('search-results-header')).toHaveAttribute('data-has-window-handler', 'true'); + }); + + it('passes undefined for newWindowHandler to SearchResultsHeader when showPopout is false', () => { + renderWithContext( + , + baseState, + ); + + expect(screen.getByTestId('search-results-header')).toHaveAttribute('data-has-window-handler', 'false'); + }); + + it('defaults showPopout to true when the prop is omitted', () => { + renderWithContext( + , + baseState, + ); + + expect(screen.getByTestId('search-results-header')).toHaveAttribute('data-has-window-handler', 'true'); + }); + }); + + describe('mapStateToProps', () => { + const pluggableId = 'pluggable-id'; + + function stateWithRegisteredComponent(showPopout?: boolean): DeepPartial { + const component: Record = { + id: pluggableId, + pluginId: 'plugin-id', + title: 'Test Title', + }; + if (showPopout !== undefined) { + component.showPopout = showPopout; + } + return { + ...baseState, + plugins: { + ...baseState.plugins, + components: { + RightHandSidebarComponent: [component as any], + }, + }, + views: { + rhs: {pluggableId}, + }, + }; + } + + it('defaults showPopout to true when component showPopout field is undefined', () => { + renderWithContext(, stateWithRegisteredComponent(undefined)); + + expect(screen.getByTestId('search-results-header')).toHaveAttribute('data-has-window-handler', 'true'); + }); + + it('passes showPopout: false through to hide the popout button', () => { + renderWithContext(, stateWithRegisteredComponent(false)); + + expect(screen.getByTestId('search-results-header')).toHaveAttribute('data-has-window-handler', 'false'); + }); + }); +}); diff --git a/webapp/channels/src/plugins/rhs_plugin/rhs_plugin.tsx b/webapp/channels/src/plugins/rhs_plugin/rhs_plugin.tsx index bb378dcfa6f..9e7bd2a3b3d 100644 --- a/webapp/channels/src/plugins/rhs_plugin/rhs_plugin.tsx +++ b/webapp/channels/src/plugins/rhs_plugin/rhs_plugin.tsx @@ -21,9 +21,10 @@ export type Props = { pluggableId: string; title: React.ReactNode; pluginId?: string; + showPopout?: boolean; }; -const RhsPlugin = ({showPluggable, pluggableId, title, pluginId}: Props) => { +const RhsPlugin = ({showPluggable, pluggableId, title, pluginId, showPopout = true}: Props) => { const intl = useIntl(); const currentTeam = useSelector(getCurrentTeam); const currentChannel = useSelector(getCurrentChannel); @@ -51,7 +52,7 @@ const RhsPlugin = ({showPluggable, pluggableId, title, pluginId}: Props) => { id='rhsContainer' className='sidebar-right__body' > - + {title} { diff --git a/webapp/channels/src/types/store/plugins.ts b/webapp/channels/src/types/store/plugins.ts index c3ccdbe2f77..d94251af7b4 100644 --- a/webapp/channels/src/types/store/plugins.ts +++ b/webapp/channels/src/types/store/plugins.ts @@ -350,6 +350,7 @@ export type PostDropdownMenuItemComponent = PluginComponent & { export type RightHandSidebarComponent = PluginComponent & { title: PluggableText; component: React.ComponentType; + showPopout?: boolean; }; export type SearchHintsComponent = PluginComponent & {