Mono repo -> Master (#22553)
Combines the following repositories into one: https://github.com/mattermost/mattermost-server https://github.com/mattermost/mattermost-webapp https://github.com/mattermost/focalboard https://github.com/mattermost/mattermost-plugin-playbooks
Этот коммит содержится в:
@@ -0,0 +1,125 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`components/integrations/EditCommand should have match renderExtra 1`] = `
|
||||
<ConfirmModal
|
||||
confirmButtonClass="btn btn-primary"
|
||||
confirmButtonText={
|
||||
<Memo(MemoizedFormattedMessage)
|
||||
defaultMessage="Update"
|
||||
id="update_command.update"
|
||||
/>
|
||||
}
|
||||
message={
|
||||
<Memo(MemoizedFormattedMessage)
|
||||
defaultMessage="Your changes may break the existing slash command. Are you sure you would like to update it?"
|
||||
id="update_command.question"
|
||||
/>
|
||||
}
|
||||
modalClass=""
|
||||
onCancel={[Function]}
|
||||
onConfirm={[Function]}
|
||||
show={false}
|
||||
title={
|
||||
<Memo(MemoizedFormattedMessage)
|
||||
defaultMessage="Edit Slash Command"
|
||||
id="update_command.confirm"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/integrations/EditCommand should match snapshot 1`] = `
|
||||
<AbstractCommand
|
||||
action={[Function]}
|
||||
footer={
|
||||
Object {
|
||||
"defaultMessage": "Update",
|
||||
"id": "edit_command.update",
|
||||
}
|
||||
}
|
||||
header={
|
||||
Object {
|
||||
"defaultMessage": "Edit",
|
||||
"id": "integrations.edit",
|
||||
}
|
||||
}
|
||||
initialCommand={
|
||||
Object {
|
||||
"auto_complete": true,
|
||||
"auto_complete_desc": "auto_complete_desc",
|
||||
"auto_complete_hint": "auto_complete_hint",
|
||||
"create_at": 1499722850203,
|
||||
"creator_id": "88oybd1dwfdoxpkpw1h5kpbyco",
|
||||
"delete_at": 0,
|
||||
"description": "description",
|
||||
"display_name": "display_name",
|
||||
"icon_url": "https://google.com/icon",
|
||||
"id": "r5tpgt4iepf45jt768jz84djic",
|
||||
"method": "G",
|
||||
"team_id": "m5gix3oye3du8ghk4ko6h9cq7y",
|
||||
"token": "jb6oyqh95irpbx8fo9zmndkp1r",
|
||||
"trigger": "trigger",
|
||||
"update_at": 1504468859001,
|
||||
"url": "https://google.com/command",
|
||||
"username": "username",
|
||||
}
|
||||
}
|
||||
loading={
|
||||
Object {
|
||||
"defaultMessage": "Updating...",
|
||||
"id": "edit_command.updating",
|
||||
}
|
||||
}
|
||||
renderExtra={
|
||||
<ConfirmModal
|
||||
confirmButtonClass="btn btn-primary"
|
||||
confirmButtonText={
|
||||
<Memo(MemoizedFormattedMessage)
|
||||
defaultMessage="Update"
|
||||
id="update_command.update"
|
||||
/>
|
||||
}
|
||||
message={
|
||||
<Memo(MemoizedFormattedMessage)
|
||||
defaultMessage="Your changes may break the existing slash command. Are you sure you would like to update it?"
|
||||
id="update_command.question"
|
||||
/>
|
||||
}
|
||||
modalClass=""
|
||||
onCancel={[Function]}
|
||||
onConfirm={[Function]}
|
||||
show={false}
|
||||
title={
|
||||
<Memo(MemoizedFormattedMessage)
|
||||
defaultMessage="Edit Slash Command"
|
||||
id="update_command.confirm"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
}
|
||||
serverError=""
|
||||
team={
|
||||
Object {
|
||||
"allow_open_invite": false,
|
||||
"allowed_domains": "",
|
||||
"company_name": "",
|
||||
"create_at": 0,
|
||||
"delete_at": 0,
|
||||
"description": "",
|
||||
"display_name": "name",
|
||||
"email": "",
|
||||
"group_constrained": false,
|
||||
"id": "m5gix3oye3du8ghk4ko6h9cq7y",
|
||||
"invite_id": "",
|
||||
"name": "test",
|
||||
"scheme_id": "id",
|
||||
"type": "O",
|
||||
"update_at": 0,
|
||||
}
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`components/integrations/EditCommand should match snapshot when EnableCommands is false 1`] = `<LoadingScreen />`;
|
||||
|
||||
exports[`components/integrations/EditCommand should match snapshot, loading 1`] = `<LoadingScreen />`;
|
||||
@@ -0,0 +1,145 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {shallow} from 'enzyme';
|
||||
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import {Command} from '@mattermost/types/integrations';
|
||||
|
||||
import {TestHelper} from 'utils/test_helper';
|
||||
import EditCommand from 'components/integrations/edit_command/edit_command';
|
||||
|
||||
describe('components/integrations/EditCommand', () => {
|
||||
const getCustomTeamCommands = jest.fn(
|
||||
() => {
|
||||
return new Promise<Command[]>((resolve) => {
|
||||
process.nextTick(() => resolve([]));
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
const commands = {
|
||||
r5tpgt4iepf45jt768jz84djic: TestHelper.getCommandMock({
|
||||
id: 'r5tpgt4iepf45jt768jz84djic',
|
||||
display_name: 'display_name',
|
||||
description: 'description',
|
||||
trigger: 'trigger',
|
||||
auto_complete: true,
|
||||
auto_complete_hint: 'auto_complete_hint',
|
||||
auto_complete_desc: 'auto_complete_desc',
|
||||
token: 'jb6oyqh95irpbx8fo9zmndkp1r',
|
||||
create_at: 1499722850203,
|
||||
creator_id: '88oybd1dwfdoxpkpw1h5kpbyco',
|
||||
delete_at: 0,
|
||||
icon_url: 'https://google.com/icon',
|
||||
method: 'G',
|
||||
team_id: 'm5gix3oye3du8ghk4ko6h9cq7y',
|
||||
update_at: 1504468859001,
|
||||
url: 'https://google.com/command',
|
||||
username: 'username',
|
||||
}),
|
||||
};
|
||||
const team: Team = TestHelper.getTeamMock({
|
||||
name: 'test',
|
||||
id: 'm5gix3oye3du8ghk4ko6h9cq7y',
|
||||
});
|
||||
|
||||
const editCommandRequest = {
|
||||
status: 'not_started',
|
||||
error: null,
|
||||
};
|
||||
|
||||
const baseProps = {
|
||||
team,
|
||||
commandId: 'r5tpgt4iepf45jt768jz84djic',
|
||||
commands,
|
||||
editCommandRequest,
|
||||
actions: {
|
||||
getCustomTeamCommands,
|
||||
editCommand: jest.fn(),
|
||||
},
|
||||
enableCommands: true,
|
||||
};
|
||||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallow(
|
||||
<EditCommand {...baseProps}/>,
|
||||
);
|
||||
|
||||
wrapper.setState({originalCommand: commands.r5tpgt4iepf45jt768jz84djic});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
|
||||
expect(baseProps.actions.getCustomTeamCommands).toHaveBeenCalled();
|
||||
expect(baseProps.actions.getCustomTeamCommands).toHaveBeenCalledWith(team.id);
|
||||
});
|
||||
|
||||
test('should match snapshot, loading', () => {
|
||||
const wrapper = shallow(
|
||||
<EditCommand {...baseProps}/>,
|
||||
);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot when EnableCommands is false', () => {
|
||||
const actions = {
|
||||
getCustomTeamCommands: jest.fn(),
|
||||
editCommand: jest.fn(),
|
||||
};
|
||||
const props = {...baseProps, actions, enableCommands: false};
|
||||
const wrapper = shallow(
|
||||
<EditCommand {...props}/>,
|
||||
);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(actions.getCustomTeamCommands).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should have match state when handleConfirmModal is called', () => {
|
||||
const props = {...baseProps, getCustomTeamCommands};
|
||||
const wrapper = shallow<EditCommand>(
|
||||
<EditCommand {...props}/>,
|
||||
);
|
||||
|
||||
wrapper.setState({showConfirmModal: false});
|
||||
wrapper.instance().handleConfirmModal();
|
||||
expect(wrapper.state('showConfirmModal')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should have match state when confirmModalDismissed is called', () => {
|
||||
const props = {...baseProps, getCustomTeamCommands};
|
||||
const wrapper = shallow<EditCommand>(
|
||||
<EditCommand {...props}/>,
|
||||
);
|
||||
|
||||
wrapper.setState({showConfirmModal: true});
|
||||
wrapper.instance().confirmModalDismissed();
|
||||
expect(wrapper.state('showConfirmModal')).toEqual(false);
|
||||
});
|
||||
|
||||
test('should have match renderExtra', () => {
|
||||
const props = {...baseProps, getCustomTeamCommands};
|
||||
const wrapper = shallow<EditCommand>(
|
||||
<EditCommand {...props}/>,
|
||||
);
|
||||
|
||||
expect(wrapper.instance().renderExtra()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should have match when editCommand is called', () => {
|
||||
const props = {...baseProps, getCustomTeamCommands};
|
||||
const wrapper = shallow<EditCommand>(
|
||||
<EditCommand {...props}/>,
|
||||
);
|
||||
|
||||
wrapper.setState({originalCommand: commands.r5tpgt4iepf45jt768jz84djic});
|
||||
const instance = wrapper.instance();
|
||||
instance.handleConfirmModal = jest.fn();
|
||||
instance.submitCommand = jest.fn();
|
||||
wrapper.instance().editCommand(commands.r5tpgt4iepf45jt768jz84djic);
|
||||
|
||||
expect(instance.handleConfirmModal).not.toBeCalled();
|
||||
expect(instance.submitCommand).toBeCalled();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,182 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import {Command} from '@mattermost/types/integrations';
|
||||
import {RelationOneToOne} from '@mattermost/types/utilities';
|
||||
|
||||
import {getHistory} from 'utils/browser_history';
|
||||
import {t} from 'utils/i18n';
|
||||
import LoadingScreen from 'components/loading_screen';
|
||||
import ConfirmModal from 'components/confirm_modal';
|
||||
import AbstractCommand from '../abstract_command.jsx';
|
||||
|
||||
const HEADER = {id: t('integrations.edit'), defaultMessage: 'Edit'};
|
||||
const FOOTER = {id: t('edit_command.update'), defaultMessage: 'Update'};
|
||||
const LOADING = {id: t('edit_command.updating'), defaultMessage: 'Updating...'};
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The current team
|
||||
*/
|
||||
team: Team;
|
||||
|
||||
/**
|
||||
* The id of the command to edit
|
||||
*/
|
||||
commandId: string | null;
|
||||
|
||||
/**
|
||||
* Installed slash commands to display
|
||||
*/
|
||||
commands: RelationOneToOne<Command, Command>;
|
||||
actions: {
|
||||
|
||||
/**
|
||||
* The function to call to fetch team commands
|
||||
*/
|
||||
getCustomTeamCommands: (teamId: string) => Promise<Command[]>;
|
||||
|
||||
/**
|
||||
* The function to call to edit command
|
||||
*/
|
||||
editCommand: (command?: Command) => Promise<{data?: Command; error?: Error}>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether or not commands are enabled.
|
||||
*/
|
||||
enableCommands: boolean;
|
||||
}
|
||||
|
||||
type State = {
|
||||
originalCommand: Command | null;
|
||||
showConfirmModal: boolean;
|
||||
serverError: string;
|
||||
|
||||
}
|
||||
|
||||
export default class EditCommand extends React.PureComponent<Props, State> {
|
||||
private newCommand?: Command;
|
||||
|
||||
public constructor(props: Props) {
|
||||
super(props);
|
||||
this.newCommand = undefined;
|
||||
|
||||
this.state = {
|
||||
originalCommand: null,
|
||||
showConfirmModal: false,
|
||||
serverError: '',
|
||||
};
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
if (this.props.enableCommands) {
|
||||
this.props.actions.getCustomTeamCommands(this.props.team.id).then(
|
||||
() => {
|
||||
this.setState({
|
||||
originalCommand: Object.values(this.props.commands).filter((command) => command.id === this.props.commandId)[0],
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public editCommand = async (command: Command): Promise<void> => {
|
||||
this.newCommand = command;
|
||||
|
||||
if (this.state.originalCommand?.id) {
|
||||
command.id = this.state.originalCommand.id;
|
||||
}
|
||||
|
||||
if (this.state.originalCommand?.url !== this.newCommand.url ||
|
||||
this.state.originalCommand?.trigger !== this.newCommand.trigger ||
|
||||
this.state.originalCommand?.method !== this.newCommand.method) {
|
||||
this.handleConfirmModal();
|
||||
} else {
|
||||
await this.submitCommand();
|
||||
}
|
||||
}
|
||||
|
||||
public handleConfirmModal = (): void => {
|
||||
this.setState({showConfirmModal: true});
|
||||
}
|
||||
|
||||
public confirmModalDismissed = (): void => {
|
||||
this.setState({showConfirmModal: false});
|
||||
}
|
||||
|
||||
public submitCommand = async (): Promise<void> => {
|
||||
this.setState({serverError: ''});
|
||||
|
||||
const {data, error} = await this.props.actions.editCommand(this.newCommand);
|
||||
|
||||
if (data) {
|
||||
getHistory().push(`/${this.props.team.name}/integrations/commands`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({showConfirmModal: false});
|
||||
|
||||
if (error) {
|
||||
this.setState({serverError: error.message});
|
||||
}
|
||||
}
|
||||
|
||||
public renderExtra = (): JSX.Element => {
|
||||
const confirmButton = (
|
||||
<FormattedMessage
|
||||
id='update_command.update'
|
||||
defaultMessage='Update'
|
||||
/>
|
||||
);
|
||||
|
||||
const confirmTitle = (
|
||||
<FormattedMessage
|
||||
id='update_command.confirm'
|
||||
defaultMessage='Edit Slash Command'
|
||||
/>
|
||||
);
|
||||
|
||||
const confirmMessage = (
|
||||
<FormattedMessage
|
||||
id='update_command.question'
|
||||
defaultMessage='Your changes may break the existing slash command. Are you sure you would like to update it?'
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<ConfirmModal
|
||||
title={confirmTitle}
|
||||
message={confirmMessage}
|
||||
confirmButtonText={confirmButton}
|
||||
show={this.state.showConfirmModal}
|
||||
onConfirm={this.submitCommand}
|
||||
onCancel={this.confirmModalDismissed}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
if (!this.state.originalCommand) {
|
||||
return <LoadingScreen/>;
|
||||
}
|
||||
|
||||
return (
|
||||
<AbstractCommand
|
||||
team={this.props.team}
|
||||
header={HEADER}
|
||||
footer={FOOTER}
|
||||
loading={LOADING}
|
||||
renderExtra={this.renderExtra()}
|
||||
action={this.editCommand}
|
||||
serverError={this.state.serverError}
|
||||
initialCommand={this.state.originalCommand}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators, Dispatch, ActionCreatorsMapObject} from 'redux';
|
||||
|
||||
import {editCommand, getCustomTeamCommands} from 'mattermost-redux/actions/integrations';
|
||||
import {getCommands} from 'mattermost-redux/selectors/entities/integrations';
|
||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||
import {GlobalState} from '@mattermost/types/store';
|
||||
import {GenericAction, ActionFunc} from 'mattermost-redux/types/actions';
|
||||
import {Command} from '@mattermost/types/integrations';
|
||||
|
||||
import EditCommand from './edit_command';
|
||||
|
||||
type Props = {
|
||||
location: Location;
|
||||
}
|
||||
|
||||
type Actions = {
|
||||
getCustomTeamCommands: (teamId: string) => Promise<Command[]>;
|
||||
editCommand: (command?: Command) => Promise<{data?: Command; error?: Error}>;
|
||||
}
|
||||
|
||||
function mapStateToProps(state: GlobalState, ownProps: Props) {
|
||||
const config = getConfig(state);
|
||||
const commandId = (new URLSearchParams(ownProps.location.search)).get('id');
|
||||
const enableCommands = config.EnableCommands === 'true';
|
||||
|
||||
return {
|
||||
commandId,
|
||||
commands: getCommands(state),
|
||||
enableCommands,
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch: Dispatch<GenericAction>) {
|
||||
return {
|
||||
actions: bindActionCreators<ActionCreatorsMapObject<ActionFunc>, Actions>({
|
||||
getCustomTeamCommands,
|
||||
editCommand,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(EditCommand);
|
||||
Ссылка в новой задаче
Block a user