mirror of
https://github.com/mattermost/mattermost.git
synced 2026-09-01 15:00:08 +08:00
Automatic Merge
This commit is contained in:
@@ -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)};
|
||||
|
||||
@@ -21,6 +21,7 @@ function mapStateToProps(state: GlobalState) {
|
||||
pluggableId,
|
||||
title: pluginTitle,
|
||||
pluginId,
|
||||
showPopout: pluginComponent?.showPopout ?? true,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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}) => (
|
||||
<div
|
||||
data-testid='search-results-header'
|
||||
data-has-window-handler={newWindowHandler === undefined ? 'false' : 'true'}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
jest.mock('plugins/pluggable', () => ({
|
||||
__esModule: true,
|
||||
default: () => <div data-testid='pluggable'/>,
|
||||
}));
|
||||
|
||||
jest.mock('utils/popouts/popout_windows', () => ({
|
||||
popoutRhsPlugin: jest.fn(),
|
||||
}));
|
||||
|
||||
const baseState: DeepPartial<GlobalState> = {
|
||||
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(
|
||||
<RhsPlugin
|
||||
showPluggable={true}
|
||||
pluggableId='pluggable-id'
|
||||
title='Test Title'
|
||||
pluginId='plugin-id'
|
||||
showPopout={true}
|
||||
/>,
|
||||
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(
|
||||
<RhsPlugin
|
||||
showPluggable={true}
|
||||
pluggableId='pluggable-id'
|
||||
title='Test Title'
|
||||
pluginId='plugin-id'
|
||||
showPopout={false}
|
||||
/>,
|
||||
baseState,
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('search-results-header')).toHaveAttribute('data-has-window-handler', 'false');
|
||||
});
|
||||
|
||||
it('defaults showPopout to true when the prop is omitted', () => {
|
||||
renderWithContext(
|
||||
<RhsPlugin
|
||||
showPluggable={true}
|
||||
pluggableId='pluggable-id'
|
||||
title='Test Title'
|
||||
pluginId='plugin-id'
|
||||
/>,
|
||||
baseState,
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('search-results-header')).toHaveAttribute('data-has-window-handler', 'true');
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapStateToProps', () => {
|
||||
const pluggableId = 'pluggable-id';
|
||||
|
||||
function stateWithRegisteredComponent(showPopout?: boolean): DeepPartial<GlobalState> {
|
||||
const component: Record<string, unknown> = {
|
||||
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(<ConnectedRhsPlugin/>, 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(<ConnectedRhsPlugin/>, stateWithRegisteredComponent(false));
|
||||
|
||||
expect(screen.getByTestId('search-results-header')).toHaveAttribute('data-has-window-handler', 'false');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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'
|
||||
>
|
||||
<SearchResultsHeader newWindowHandler={newWindowHandler}>
|
||||
<SearchResultsHeader newWindowHandler={showPopout ? newWindowHandler : undefined}>
|
||||
{title}
|
||||
</SearchResultsHeader>
|
||||
{
|
||||
|
||||
@@ -350,6 +350,7 @@ export type PostDropdownMenuItemComponent = PluginComponent & {
|
||||
export type RightHandSidebarComponent = PluginComponent & {
|
||||
title: PluggableText;
|
||||
component: React.ComponentType<BasePluggableProps>;
|
||||
showPopout?: boolean;
|
||||
};
|
||||
|
||||
export type SearchHintsComponent = PluginComponent & {
|
||||
|
||||
Reference in New Issue
Block a user