GH-6452 Migrate installed_command.jsx to be pure and use Redux (#6903)
* Migrate installed_command.jsx to be pure and use Redux * Add test for InstalledCommand component * Fix failing test and typo * Whoops. Revert back deleted filter * Add filter test * Remove commands related code from /stores/integration_store.jsx
Этот коммит содержится в:
коммит произвёл
Harrison Healey
родитель
b54d134299
Коммит
ea095d6206
@@ -33,7 +33,7 @@ export default class CommandsContainer extends React.PureComponent {
|
|||||||
users: PropTypes.object,
|
users: PropTypes.object,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installed splash commands to display
|
* Installed slash commands to display
|
||||||
*/
|
*/
|
||||||
commands: PropTypes.array,
|
commands: PropTypes.array,
|
||||||
|
|
||||||
|
|||||||
@@ -1,43 +1,59 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import {Link} from 'react-router';
|
import {Link} from 'react-router';
|
||||||
import {FormattedMessage} from 'react-intl';
|
import {FormattedMessage} from 'react-intl';
|
||||||
|
|
||||||
import DeleteIntegration from './delete_integration.jsx';
|
import DeleteIntegration from './delete_integration.jsx';
|
||||||
|
|
||||||
export default class InstalledCommand extends React.Component {
|
export default class InstalledCommand extends React.PureComponent {
|
||||||
static get propTypes() {
|
static propTypes = {
|
||||||
return {
|
|
||||||
team: PropTypes.object.isRequired,
|
/**
|
||||||
command: PropTypes.object.isRequired,
|
* The team data
|
||||||
onRegenToken: PropTypes.func.isRequired,
|
*/
|
||||||
onDelete: PropTypes.func.isRequired,
|
team: PropTypes.object.isRequired,
|
||||||
filter: PropTypes.string,
|
|
||||||
creator: PropTypes.object.isRequired,
|
/**
|
||||||
canChange: PropTypes.bool.isRequired
|
* Installed slash command to display
|
||||||
};
|
*/
|
||||||
|
command: PropTypes.object.isRequired,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function to call when Regenerate Token link is clicked
|
||||||
|
*/
|
||||||
|
onRegenToken: PropTypes.func.isRequired,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The function to call when Delete link is clicked
|
||||||
|
*/
|
||||||
|
onDelete: PropTypes.func.isRequired,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to filter command, comes from BackstageList
|
||||||
|
*/
|
||||||
|
filter: PropTypes.string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The creator user data
|
||||||
|
*/
|
||||||
|
creator: PropTypes.object.isRequired,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to show edit link
|
||||||
|
*/
|
||||||
|
canChange: PropTypes.bool.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
handleRegenToken = (e) => {
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.handleRegenToken = this.handleRegenToken.bind(this);
|
|
||||||
this.handleDelete = this.handleDelete.bind(this);
|
|
||||||
|
|
||||||
this.matchesFilter = this.matchesFilter.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleRegenToken(e) {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
this.props.onRegenToken(this.props.command);
|
this.props.onRegenToken(this.props.command);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDelete() {
|
handleDelete = () => {
|
||||||
this.props.onDelete(this.props.command);
|
this.props.onDelete(this.props.command);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +76,7 @@ export default class InstalledCommand extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let name;
|
let name;
|
||||||
|
|
||||||
if (command.display_name) {
|
if (command.display_name) {
|
||||||
name = command.display_name;
|
name = command.display_name;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export default class InstalledCommands extends React.PureComponent {
|
|||||||
users: PropTypes.object,
|
users: PropTypes.object,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installed splash commands to display
|
* Installed slash commands to display
|
||||||
*/
|
*/
|
||||||
commands: PropTypes.array,
|
commands: PropTypes.array,
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ export default class InstalledCommands extends React.PureComponent {
|
|||||||
loading: PropTypes.bool,
|
loading: PropTypes.bool,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set to allow changes to installed splash commands
|
* Set to allow changes to installed slash commands
|
||||||
*/
|
*/
|
||||||
isAdmin: PropTypes.bool,
|
isAdmin: PropTypes.bool,
|
||||||
|
|
||||||
|
|||||||
@@ -91,36 +91,6 @@ class IntegrationStore extends EventEmitter {
|
|||||||
return store.getState().entities.integrations.outgoingHooks[id];
|
return store.getState().entities.integrations.outgoingHooks[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
hasReceivedCommands(teamId) {
|
|
||||||
const commands = store.getState().entities.integrations.commands;
|
|
||||||
|
|
||||||
let hasTeam = false;
|
|
||||||
Object.values(commands).forEach((command) => {
|
|
||||||
if (command.team_id === teamId) {
|
|
||||||
hasTeam = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return hasTeam;
|
|
||||||
}
|
|
||||||
|
|
||||||
getCommands(teamId) {
|
|
||||||
const commands = store.getState().entities.integrations.commands;
|
|
||||||
|
|
||||||
const teamCommands = [];
|
|
||||||
Object.values(commands).forEach((command) => {
|
|
||||||
if (command.team_id === teamId) {
|
|
||||||
teamCommands.push(command);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return teamCommands;
|
|
||||||
}
|
|
||||||
|
|
||||||
getCommand(teamId, id) {
|
|
||||||
return store.getState().entities.integrations.commands[id];
|
|
||||||
}
|
|
||||||
|
|
||||||
hasReceivedOAuthApps() {
|
hasReceivedOAuthApps() {
|
||||||
return Object.keys(store.getState().entities.integrations.oauthApps).length > 0;
|
return Object.keys(store.getState().entities.integrations.oauthApps).length > 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`components/integrations/InstalledCommand should filter out command 1`] = `null`;
|
||||||
|
|
||||||
|
exports[`components/integrations/InstalledCommand should match snapshot 1`] = `
|
||||||
|
<div
|
||||||
|
className="backstage-list__item"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="item-details"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="item-details__row"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="item-details__name"
|
||||||
|
>
|
||||||
|
test
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="item-details__trigger"
|
||||||
|
>
|
||||||
|
- /trigger test
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="item-details__row"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="item-details__description"
|
||||||
|
>
|
||||||
|
test
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="item-details__row"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="item-details__token"
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Token: {token}"
|
||||||
|
id="installed_integrations.token"
|
||||||
|
values={
|
||||||
|
Object {
|
||||||
|
"token": "testToken",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="item-details__row"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="item-details__creation"
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Created by {creator} on {createAt, date, full}"
|
||||||
|
id="installed_integrations.creation"
|
||||||
|
values={
|
||||||
|
Object {
|
||||||
|
"createAt": "1499722850203",
|
||||||
|
"creator": "test",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="item-actions"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
onClick={[Function]}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Regenerate Token"
|
||||||
|
id="installed_integrations.regenToken"
|
||||||
|
values={Object {}}
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
-
|
||||||
|
<Link
|
||||||
|
onlyActiveOnIndex={false}
|
||||||
|
style={Object {}}
|
||||||
|
to="/test/integrations/commands/edit?id=r5tpgt4iepf45jt768jz84djic"
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Edit"
|
||||||
|
id="installed_integrations.edit"
|
||||||
|
values={Object {}}
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
-
|
||||||
|
<DeleteIntegration
|
||||||
|
messageId="installed_commands.delete.confirm"
|
||||||
|
onDelete={[Function]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
83
webapp/tests/components/integrations/installed_command.test.jsx
Обычный файл
83
webapp/tests/components/integrations/installed_command.test.jsx
Обычный файл
@@ -0,0 +1,83 @@
|
|||||||
|
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {shallow} from 'enzyme';
|
||||||
|
|
||||||
|
import InstalledCommand from 'components/integrations/components/installed_command.jsx';
|
||||||
|
|
||||||
|
describe('components/integrations/InstalledCommand', () => {
|
||||||
|
const emptyFunction = jest.fn();
|
||||||
|
const command = {
|
||||||
|
id: 'r5tpgt4iepf45jt768jz84djic',
|
||||||
|
display_name: 'test',
|
||||||
|
description: 'test',
|
||||||
|
trigger: 'trigger',
|
||||||
|
auto_complete: 'test',
|
||||||
|
auto_complete_hint: 'test',
|
||||||
|
token: 'testToken',
|
||||||
|
create_at: '1499722850203'
|
||||||
|
};
|
||||||
|
|
||||||
|
test('should match snapshot', () => {
|
||||||
|
const wrapper = shallow(
|
||||||
|
<InstalledCommand
|
||||||
|
team={{
|
||||||
|
name: 'test'
|
||||||
|
}}
|
||||||
|
command={command}
|
||||||
|
onRegenToken={emptyFunction}
|
||||||
|
onDelete={emptyFunction}
|
||||||
|
filter={'trigger'}
|
||||||
|
creator={{
|
||||||
|
username: 'test'
|
||||||
|
}}
|
||||||
|
canChange={true}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call onRegenToken function', () => {
|
||||||
|
const onRegenToken = jest.fn();
|
||||||
|
const wrapper = shallow(
|
||||||
|
<InstalledCommand
|
||||||
|
team={{
|
||||||
|
name: 'test'
|
||||||
|
}}
|
||||||
|
command={command}
|
||||||
|
onRegenToken={onRegenToken}
|
||||||
|
onDelete={emptyFunction}
|
||||||
|
filter={''}
|
||||||
|
creator={{
|
||||||
|
username: 'test'
|
||||||
|
}}
|
||||||
|
canChange={true}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
wrapper.find('div.item-actions a').first().simulate('click', {preventDefault() {
|
||||||
|
return jest.fn();
|
||||||
|
}});
|
||||||
|
|
||||||
|
expect(onRegenToken).toBeCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should filter out command', () => {
|
||||||
|
const wrapper = shallow(
|
||||||
|
<InstalledCommand
|
||||||
|
team={{
|
||||||
|
name: 'test'
|
||||||
|
}}
|
||||||
|
command={command}
|
||||||
|
onRegenToken={emptyFunction}
|
||||||
|
onDelete={emptyFunction}
|
||||||
|
filter={'filter'}
|
||||||
|
creator={{
|
||||||
|
username: 'test'
|
||||||
|
}}
|
||||||
|
canChange={true}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
Ссылка в новой задаче
Block a user