PLT-2698 Integrations improvements (#2883)
* Fixed Integrations link to show up for non-admins (when enabled) and when only slash commands are enabled * Updated BackstageSidebar to only show enabled integrations * Added placeholder to integrations list when none exist * Added loading spinner to integrations pages when they're loading
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
fcb5b70eb3
Коммит
2c92540471
@@ -40,6 +40,10 @@ export default class BackstageCategory extends React.Component {
|
|||||||
<ul className='sections'>
|
<ul className='sections'>
|
||||||
{
|
{
|
||||||
React.Children.map(children, (child) => {
|
React.Children.map(children, (child) => {
|
||||||
|
if (!child) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
return React.cloneElement(child, {
|
return React.cloneElement(child, {
|
||||||
parentLink: link
|
parentLink: link
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,6 +10,51 @@ import {FormattedMessage} from 'react-intl';
|
|||||||
|
|
||||||
export default class BackstageSidebar extends React.Component {
|
export default class BackstageSidebar extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
|
let incomingWebhooks = null;
|
||||||
|
if (window.mm_config.EnableIncomingWebhooks === 'true') {
|
||||||
|
incomingWebhooks = (
|
||||||
|
<BackstageSection
|
||||||
|
name='incoming_webhooks'
|
||||||
|
title={(
|
||||||
|
<FormattedMessage
|
||||||
|
id='backstage_sidebar.integrations.incoming_webhooks'
|
||||||
|
defaultMessage='Incoming Webhooks'
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let outgoingWebhooks = null;
|
||||||
|
if (window.mm_config.EnableOutgoingWebhooks === 'true') {
|
||||||
|
outgoingWebhooks = (
|
||||||
|
<BackstageSection
|
||||||
|
name='outgoing_webhooks'
|
||||||
|
title={(
|
||||||
|
<FormattedMessage
|
||||||
|
id='backstage_sidebar.integrations.outgoing_webhooks'
|
||||||
|
defaultMessage='Outgoing Webhooks'
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let commands = null;
|
||||||
|
if (window.mm_config.EnableCommands === 'true') {
|
||||||
|
commands = (
|
||||||
|
<BackstageSection
|
||||||
|
name='commands'
|
||||||
|
title={(
|
||||||
|
<FormattedMessage
|
||||||
|
id='backstage_sidebar.integrations.commands'
|
||||||
|
defaultMessage='Slash Commands'
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='backstage-sidebar'>
|
<div className='backstage-sidebar'>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -24,33 +69,9 @@ export default class BackstageSidebar extends React.Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<BackstageSection
|
{incomingWebhooks}
|
||||||
name='incoming_webhooks'
|
{outgoingWebhooks}
|
||||||
title={(
|
{commands}
|
||||||
<FormattedMessage
|
|
||||||
id='backstage_sidebar.integrations.incoming_webhooks'
|
|
||||||
defaultMessage='Incoming Webhooks'
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<BackstageSection
|
|
||||||
name='outgoing_webhooks'
|
|
||||||
title={(
|
|
||||||
<FormattedMessage
|
|
||||||
id='backstage_sidebar.integrations.outgoing_webhooks'
|
|
||||||
defaultMessage='Outgoing Webhooks'
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<BackstageSection
|
|
||||||
name='commands'
|
|
||||||
title={(
|
|
||||||
<FormattedMessage
|
|
||||||
id='backstage_sidebar.integrations.commands'
|
|
||||||
defaultMessage='Slash Commands'
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</BackstageCategory>
|
</BackstageCategory>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -21,21 +21,16 @@ export default class InstalledCommands extends React.Component {
|
|||||||
this.deleteCommand = this.deleteCommand.bind(this);
|
this.deleteCommand = this.deleteCommand.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
commands: []
|
commands: IntegrationStore.getCommands(),
|
||||||
|
loading: !IntegrationStore.hasReceivedCommands()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
IntegrationStore.addChangeListener(this.handleIntegrationChange);
|
IntegrationStore.addChangeListener(this.handleIntegrationChange);
|
||||||
|
|
||||||
if (window.mm_config.EnableCommands === 'true') {
|
if (window.mm_config.EnableCommands === 'true' && this.state.loading) {
|
||||||
if (IntegrationStore.hasReceivedCommands()) {
|
AsyncClient.listTeamCommands();
|
||||||
this.setState({
|
|
||||||
commands: IntegrationStore.getCommands()
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
AsyncClient.listTeamCommands();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,10 +39,9 @@ export default class InstalledCommands extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleIntegrationChange() {
|
handleIntegrationChange() {
|
||||||
const commands = IntegrationStore.getCommands();
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
commands
|
commands: IntegrationStore.getCommands(),
|
||||||
|
loading: !IntegrationStore.hasReceivedCommands()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +80,13 @@ export default class InstalledCommands extends React.Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
addLink={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/commands/add'}
|
addLink={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/commands/add'}
|
||||||
|
emptyText={
|
||||||
|
<FormattedMessage
|
||||||
|
id='installed_commands.empty'
|
||||||
|
defaultMessage='No slash commands found'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
loading={this.state.loading}
|
||||||
>
|
>
|
||||||
{commands}
|
{commands}
|
||||||
</InstalledIntegrations>
|
</InstalledIntegrations>
|
||||||
|
|||||||
@@ -20,21 +20,16 @@ export default class InstalledIncomingWebhooks extends React.Component {
|
|||||||
this.deleteIncomingWebhook = this.deleteIncomingWebhook.bind(this);
|
this.deleteIncomingWebhook = this.deleteIncomingWebhook.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
incomingWebhooks: []
|
incomingWebhooks: IntegrationStore.getIncomingWebhooks(),
|
||||||
|
loading: !IntegrationStore.hasReceivedIncomingWebhooks()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
IntegrationStore.addChangeListener(this.handleIntegrationChange);
|
IntegrationStore.addChangeListener(this.handleIntegrationChange);
|
||||||
|
|
||||||
if (window.mm_config.EnableIncomingWebhooks === 'true') {
|
if (window.mm_config.EnableIncomingWebhooks === 'true' && this.state.loading) {
|
||||||
if (IntegrationStore.hasReceivedIncomingWebhooks()) {
|
AsyncClient.listIncomingHooks();
|
||||||
this.setState({
|
|
||||||
incomingWebhooks: IntegrationStore.getIncomingWebhooks()
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
AsyncClient.listIncomingHooks();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +39,8 @@ export default class InstalledIncomingWebhooks extends React.Component {
|
|||||||
|
|
||||||
handleIntegrationChange() {
|
handleIntegrationChange() {
|
||||||
this.setState({
|
this.setState({
|
||||||
incomingWebhooks: IntegrationStore.getIncomingWebhooks()
|
incomingWebhooks: IntegrationStore.getIncomingWebhooks(),
|
||||||
|
loading: !IntegrationStore.hasReceivedIncomingWebhooks()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,6 +74,13 @@ export default class InstalledIncomingWebhooks extends React.Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
addLink={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/incoming_webhooks/add'}
|
addLink={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/incoming_webhooks/add'}
|
||||||
|
emptyText={
|
||||||
|
<FormattedMessage
|
||||||
|
id='installed_incoming_webhooks.empty'
|
||||||
|
defaultMessage='No incoming webhooks found'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
loading={this.state.loading}
|
||||||
>
|
>
|
||||||
{incomingWebhooks}
|
{incomingWebhooks}
|
||||||
</InstalledIntegrations>
|
</InstalledIntegrations>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import React from 'react';
|
|||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
|
|
||||||
import {Link} from 'react-router';
|
import {Link} from 'react-router';
|
||||||
|
import LoadingScreen from 'components/loading_screen.jsx';
|
||||||
|
|
||||||
export default class InstalledIntegrations extends React.Component {
|
export default class InstalledIntegrations extends React.Component {
|
||||||
static get propTypes() {
|
static get propTypes() {
|
||||||
@@ -13,7 +14,9 @@ export default class InstalledIntegrations extends React.Component {
|
|||||||
children: React.PropTypes.node,
|
children: React.PropTypes.node,
|
||||||
header: React.PropTypes.node.isRequired,
|
header: React.PropTypes.node.isRequired,
|
||||||
addLink: React.PropTypes.string.isRequired,
|
addLink: React.PropTypes.string.isRequired,
|
||||||
addText: React.PropTypes.node.isRequired
|
addText: React.PropTypes.node.isRequired,
|
||||||
|
emptyText: React.PropTypes.node.isRequired,
|
||||||
|
loading: React.PropTypes.bool.isRequired
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,9 +39,23 @@ export default class InstalledIntegrations extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
const filter = this.state.filter.toLowerCase();
|
const filter = this.state.filter.toLowerCase();
|
||||||
|
|
||||||
const children = React.Children.map(this.props.children, (child) => {
|
let children;
|
||||||
return React.cloneElement(child, {filter});
|
|
||||||
});
|
if (this.props.loading) {
|
||||||
|
children = <LoadingScreen/>;
|
||||||
|
} else {
|
||||||
|
children = React.Children.map(this.props.children, (child) => {
|
||||||
|
return React.cloneElement(child, {filter});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (children.length === 0) {
|
||||||
|
children = (
|
||||||
|
<span className='backstage-list__item backstage-list_empty'>
|
||||||
|
{this.props.emptyText}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='backstage-content'>
|
<div className='backstage-content'>
|
||||||
|
|||||||
@@ -21,21 +21,16 @@ export default class InstalledOutgoingWebhooks extends React.Component {
|
|||||||
this.deleteOutgoingWebhook = this.deleteOutgoingWebhook.bind(this);
|
this.deleteOutgoingWebhook = this.deleteOutgoingWebhook.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
outgoingWebhooks: []
|
outgoingWebhooks: IntegrationStore.getOutgoingWebhooks(),
|
||||||
|
loading: !IntegrationStore.hasReceivedOutgoingWebhooks()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
IntegrationStore.addChangeListener(this.handleIntegrationChange);
|
IntegrationStore.addChangeListener(this.handleIntegrationChange);
|
||||||
|
|
||||||
if (window.mm_config.EnableOutgoingWebhooks === 'true') {
|
if (window.mm_config.EnableOutgoingWebhooks === 'true' && this.state.loading) {
|
||||||
if (IntegrationStore.hasReceivedOutgoingWebhooks()) {
|
AsyncClient.listOutgoingHooks();
|
||||||
this.setState({
|
|
||||||
outgoingWebhooks: IntegrationStore.getOutgoingWebhooks()
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
AsyncClient.listOutgoingHooks();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +40,8 @@ export default class InstalledOutgoingWebhooks extends React.Component {
|
|||||||
|
|
||||||
handleIntegrationChange() {
|
handleIntegrationChange() {
|
||||||
this.setState({
|
this.setState({
|
||||||
outgoingWebhooks: IntegrationStore.getOutgoingWebhooks()
|
outgoingWebhooks: IntegrationStore.getOutgoingWebhooks(),
|
||||||
|
loading: !IntegrationStore.hasReceivedOutgoingWebhooks()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +80,13 @@ export default class InstalledOutgoingWebhooks extends React.Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
addLink={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/outgoing_webhooks/add'}
|
addLink={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/outgoing_webhooks/add'}
|
||||||
|
emptyText={
|
||||||
|
<FormattedMessage
|
||||||
|
id='installed_outgoing_webhooks.empty'
|
||||||
|
defaultMessage='No outgoing webhooks found'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
loading={this.state.loading}
|
||||||
>
|
>
|
||||||
{outgoingWebhooks}
|
{outgoingWebhooks}
|
||||||
</InstalledIntegrations>
|
</InstalledIntegrations>
|
||||||
|
|||||||
@@ -143,19 +143,21 @@ export default class NavbarDropdown extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.mm_config.EnableIncomingWebhooks === 'true' || window.mm_config.EnableOutgoingWebhooks === 'true') {
|
const integrationsEnabled =
|
||||||
if (isAdmin || window.EnableAdminOnlyIntegrations !== 'true') {
|
window.mm_config.EnableIncomingWebhooks === 'true' ||
|
||||||
integrationsLink = (
|
window.mm_config.EnableOutgoingWebhooks === 'true' ||
|
||||||
<li>
|
window.mm_config.EnableCommands === 'true';
|
||||||
<Link to={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations'}>
|
if (integrationsEnabled && (isAdmin || window.EnableOnlyAdminIntegrations !== 'true')) {
|
||||||
<FormattedMessage
|
integrationsLink = (
|
||||||
id='navbar_dropdown.integrations'
|
<li>
|
||||||
defaultMessage='Integrations'
|
<Link to={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations'}>
|
||||||
/>
|
<FormattedMessage
|
||||||
</Link>
|
id='navbar_dropdown.integrations'
|
||||||
</li>
|
defaultMessage='Integrations'
|
||||||
);
|
/>
|
||||||
}
|
</Link>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSystemAdmin) {
|
if (isSystemAdmin) {
|
||||||
|
|||||||
@@ -902,8 +902,10 @@
|
|||||||
"get_team_invite_link_modal.helpDisabled": "User creation has been disabled for your team. Please ask your team administrator for details.",
|
"get_team_invite_link_modal.helpDisabled": "User creation has been disabled for your team. Please ask your team administrator for details.",
|
||||||
"get_team_invite_link_modal.title": "Team Invite Link",
|
"get_team_invite_link_modal.title": "Team Invite Link",
|
||||||
"installed_commands.add": "Add Slash Command",
|
"installed_commands.add": "Add Slash Command",
|
||||||
|
"installed_commands.empty": "No commands found",
|
||||||
"installed_commands.header": "Slash Commands",
|
"installed_commands.header": "Slash Commands",
|
||||||
"installed_incoming_webhooks.add": "Add Incoming Webhook",
|
"installed_incoming_webhooks.add": "Add Incoming Webhook",
|
||||||
|
"installed_incoming_webhooks.empty": "No incoming webhooks found",
|
||||||
"installed_incoming_webhooks.header": "Incoming Webhooks",
|
"installed_incoming_webhooks.header": "Incoming Webhooks",
|
||||||
"installed_integrations.creation": "Created by {creator} on {createAt, date, full}",
|
"installed_integrations.creation": "Created by {creator} on {createAt, date, full}",
|
||||||
"installed_integrations.delete": "Delete",
|
"installed_integrations.delete": "Delete",
|
||||||
@@ -912,6 +914,7 @@
|
|||||||
"installed_integrations.token": "Token: {token}",
|
"installed_integrations.token": "Token: {token}",
|
||||||
"installed_integrations.url": "URL: {url}",
|
"installed_integrations.url": "URL: {url}",
|
||||||
"installed_outgoing_webhooks.add": "Add Outgoing Webhook",
|
"installed_outgoing_webhooks.add": "Add Outgoing Webhook",
|
||||||
|
"installed_outgoing_webhooks.empty": "No outgoing webhooks found",
|
||||||
"installed_outgoing_webhooks.header": "Outgoing Webhooks",
|
"installed_outgoing_webhooks.header": "Outgoing Webhooks",
|
||||||
"integrations.command.description": "Slash commands send events to external integrations",
|
"integrations.command.description": "Slash commands send events to external integrations",
|
||||||
"integrations.command.title": "Slash Command",
|
"integrations.command.title": "Slash Command",
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user