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 & {