* SONAR-10348 Create the webhooks console page * SONAR-10349 Add webhook console at global admin scope * SONAR-10349 Add webhook console at project scope * SONAR-10349 Add webhook console at organization scopetags/7.5
@@ -0,0 +1,43 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { getJSON } from '../helpers/request'; | |||
import throwGlobalError from '../app/utils/throwGlobalError'; | |||
export interface Delivery { | |||
id: string; | |||
at: string; | |||
success: boolean; | |||
httpStatus: number; | |||
durationMs: number; | |||
} | |||
export interface Webhook { | |||
key: string; | |||
name: string; | |||
url: string; | |||
latestDelivery?: Delivery; | |||
} | |||
export function searchWebhooks(data: { | |||
organization: string | undefined; | |||
project?: string; | |||
}): Promise<{ webhooks: Webhook[] }> { | |||
return getJSON('/api/webhooks/search', data).catch(throwGlobalError); | |||
} |
@@ -17,20 +17,22 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import React from 'react'; | |||
import * as React from 'react'; | |||
import handleRequiredAuthorization from '../utils/handleRequiredAuthorization'; | |||
import { Component, Branch } from '../types'; | |||
export default class ProjectAdminContainer extends React.PureComponent { | |||
/*:: | |||
props: { | |||
component: { | |||
configuration?: { | |||
showSettings: boolean | |||
} | |||
} | |||
}; | |||
*/ | |||
interface Props { | |||
children: JSX.Element; | |||
branch?: Branch; | |||
branches: Branch[]; | |||
component: Component; | |||
isInProgress?: boolean; | |||
isPending?: boolean; | |||
onBranchesChange: () => void; | |||
onComponentChange: (changes: {}) => void; | |||
} | |||
export default class ProjectAdminContainer extends React.PureComponent<Props> { | |||
componentDidMount() { | |||
this.checkPermissions(); | |||
} | |||
@@ -39,17 +41,17 @@ export default class ProjectAdminContainer extends React.PureComponent { | |||
this.checkPermissions(); | |||
} | |||
isProjectAdmin() { | |||
const { configuration } = this.props.component; | |||
return configuration != null && configuration.showSettings; | |||
} | |||
checkPermissions() { | |||
if (!this.isProjectAdmin()) { | |||
handleRequiredAuthorization(); | |||
} | |||
} | |||
isProjectAdmin() { | |||
const { configuration } = this.props.component; | |||
return configuration != null && configuration.showSettings; | |||
} | |||
render() { | |||
if (!this.isProjectAdmin()) { | |||
return null; |
@@ -243,6 +243,7 @@ export default class ComponentNavMenu extends React.PureComponent<Props> { | |||
this.renderPermissionsLink(), | |||
this.renderBackgroundTasksLink(), | |||
this.renderUpdateKeyLink(), | |||
this.renderWebhooksLink(), | |||
...this.renderAdminExtensions(), | |||
this.renderDeletionLink() | |||
]; | |||
@@ -394,6 +395,21 @@ export default class ComponentNavMenu extends React.PureComponent<Props> { | |||
); | |||
} | |||
renderWebhooksLink() { | |||
if (!this.getConfiguration().showSettings || !this.isProject()) { | |||
return null; | |||
} | |||
return ( | |||
<li key="webhooks"> | |||
<Link | |||
to={{ pathname: '/project/webhooks', query: { id: this.props.component.key } }} | |||
activeClassName="active"> | |||
{translate('webhooks.page')} | |||
</Link> | |||
</li> | |||
); | |||
} | |||
renderDeletionLink() { | |||
const { qualifier } = this.props.component; | |||
@@ -150,6 +150,25 @@ exports[`should work for all qualifiers 1`] = ` | |||
project_branches.page | |||
</Link> | |||
</li> | |||
<li | |||
key="webhooks" | |||
> | |||
<Link | |||
activeClassName="active" | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
to={ | |||
Object { | |||
"pathname": "/project/webhooks", | |||
"query": Object { | |||
"id": "foo", | |||
}, | |||
} | |||
} | |||
> | |||
webhooks.page | |||
</Link> | |||
</li> | |||
<li | |||
key="project_delete" | |||
> | |||
@@ -1060,6 +1079,25 @@ exports[`should work with extensions 1`] = ` | |||
project_branches.page | |||
</Link> | |||
</li> | |||
<li | |||
key="webhooks" | |||
> | |||
<Link | |||
activeClassName="active" | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
to={ | |||
Object { | |||
"pathname": "/project/webhooks", | |||
"query": Object { | |||
"id": "foo", | |||
}, | |||
} | |||
} | |||
> | |||
webhooks.page | |||
</Link> | |||
</li> | |||
<li | |||
key="foo" | |||
> | |||
@@ -1292,6 +1330,25 @@ exports[`should work with multiple extensions 1`] = ` | |||
project_branches.page | |||
</Link> | |||
</li> | |||
<li | |||
key="webhooks" | |||
> | |||
<Link | |||
activeClassName="active" | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
to={ | |||
Object { | |||
"pathname": "/project/webhooks", | |||
"query": Object { | |||
"id": "foo", | |||
}, | |||
} | |||
} | |||
> | |||
webhooks.page | |||
</Link> | |||
</li> | |||
<li | |||
key="foo" | |||
> |
@@ -117,6 +117,11 @@ export default class SettingsNav extends React.PureComponent<Props> { | |||
{translate('custom_metrics.page')} | |||
</IndexLink> | |||
</li> | |||
<li> | |||
<IndexLink to="/admin/webhooks" activeClassName="active"> | |||
{translate('webhooks.page')} | |||
</IndexLink> | |||
</li> | |||
{extensionsWithoutSupport.map(this.renderExtension)} | |||
</ul> | |||
</li> |
@@ -55,6 +55,14 @@ exports[`should work with extensions 1`] = ` | |||
custom_metrics.page | |||
</IndexLink> | |||
</li> | |||
<li> | |||
<IndexLink | |||
activeClassName="active" | |||
to="/admin/webhooks" | |||
> | |||
webhooks.page | |||
</IndexLink> | |||
</li> | |||
<li | |||
key="foo" | |||
> |
@@ -74,6 +74,7 @@ import settingsRoutes from '../../apps/settings/routes'; | |||
import systemRoutes from '../../apps/system/routes'; | |||
import usersRoutes from '../../apps/users/routes'; | |||
import webAPIRoutes from '../../apps/web-api/routes'; | |||
import webhooksRoutes from '../../apps/webhooks/routes'; | |||
import { maintenanceRoutes, setupRoutes } from '../../apps/maintenance/routes'; | |||
import { globalPermissionsRoutes, projectPermissionsRoutes } from '../../apps/permissions/routes'; | |||
@@ -212,6 +213,7 @@ const startReactApp = () => { | |||
<Route path="project/branches" childRoutes={projectBranchesRoutes} /> | |||
<Route path="project/settings" childRoutes={settingsRoutes} /> | |||
<Route path="project_roles" childRoutes={projectPermissionsRoutes} /> | |||
<Route path="project/webhooks" childRoutes={webhooksRoutes} /> | |||
</Route> | |||
{projectAdminRoutes} | |||
</Route> | |||
@@ -232,6 +234,7 @@ const startReactApp = () => { | |||
<Route path="system" childRoutes={systemRoutes} /> | |||
<Route path="marketplace" childRoutes={marketplaceRoutes} /> | |||
<Route path="users" childRoutes={usersRoutes} /> | |||
<Route path="webhooks" childRoutes={webhooksRoutes} /> | |||
</Route> | |||
</Route> | |||
@@ -92,6 +92,11 @@ export default function OrganizationNavigationAdministration({ location, organiz | |||
{translate('projects_management')} | |||
</Link> | |||
</li> | |||
<li> | |||
<Link to={`/organizations/${organization.key}/webhooks`} activeClassName="active"> | |||
{translate('webhooks.page')} | |||
</Link> | |||
</li> | |||
<li> | |||
<Link to={`/organizations/${organization.key}/edit`} activeClassName="active"> | |||
{translate('edit')} |
@@ -58,6 +58,16 @@ exports[`renders 1`] = ` | |||
projects_management | |||
</Link> | |||
</li> | |||
<li> | |||
<Link | |||
activeClassName="active" | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
to="/organizations/foo/webhooks" | |||
> | |||
webhooks.page | |||
</Link> | |||
</li> | |||
<li> | |||
<Link | |||
activeClassName="active" |
@@ -31,6 +31,7 @@ import ProjectManagementApp from '../projectsManagement/AppContainer'; | |||
import codingRulesRoutes from '../coding-rules/routes'; | |||
import qualityGatesRoutes from '../quality-gates/routes'; | |||
import qualityProfilesRoutes from '../quality-profiles/routes'; | |||
import webhooksRoutes from '../webhooks/routes'; | |||
import Issues from '../issues/components/AppContainer'; | |||
import GroupsApp from '../groups/components/App'; | |||
import OrganizationPageExtension from '../../app/components/extensions/OrganizationPageExtension'; | |||
@@ -88,7 +89,8 @@ const routes = [ | |||
{ path: 'groups', component: GroupsApp }, | |||
{ path: 'permissions', component: GlobalPermissionsApp }, | |||
{ path: 'permission_templates', component: PermissionTemplateApp }, | |||
{ path: 'projects_management', component: ProjectManagementApp } | |||
{ path: 'projects_management', component: ProjectManagementApp }, | |||
{ path: 'webhooks', childRoutes: webhooksRoutes } | |||
] | |||
} | |||
] |
@@ -0,0 +1,84 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { Helmet } from 'react-helmet'; | |||
import PageHeader from './PageHeader'; | |||
import WebhooksList from './WebhooksList'; | |||
import { searchWebhooks, Webhook } from '../../../api/webhooks'; | |||
import { LightComponent, Organization } from '../../../app/types'; | |||
import { translate } from '../../../helpers/l10n'; | |||
interface Props { | |||
organization: Organization | undefined; | |||
component?: LightComponent; | |||
} | |||
interface State { | |||
loading: boolean; | |||
webhooks: Webhook[]; | |||
} | |||
export default class App extends React.PureComponent<Props, State> { | |||
mounted: boolean = false; | |||
state: State = { loading: true, webhooks: [] }; | |||
componentDidMount() { | |||
this.mounted = true; | |||
this.fetchWebhooks(); | |||
} | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
} | |||
fetchWebhooks = ({ organization, component } = this.props) => { | |||
this.setState({ loading: true }); | |||
searchWebhooks({ | |||
organization: organization && organization.key, | |||
project: component && component.key | |||
}).then( | |||
({ webhooks }) => { | |||
if (this.mounted) { | |||
this.setState({ loading: false, webhooks }); | |||
} | |||
}, | |||
() => { | |||
if (this.mounted) { | |||
this.setState({ loading: false }); | |||
} | |||
} | |||
); | |||
}; | |||
render() { | |||
const { loading, webhooks } = this.state; | |||
return ( | |||
<div className="page page-limited"> | |||
<Helmet title={translate('webhooks.page')} /> | |||
<PageHeader loading={loading} /> | |||
{!loading && ( | |||
<div className="boxed-group boxed-group-inner"> | |||
<WebhooksList webhooks={webhooks} /> | |||
</div> | |||
)} | |||
</div> | |||
); | |||
} | |||
} |
@@ -0,0 +1,52 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import { translate } from '../../../helpers/l10n'; | |||
interface Props { | |||
loading: boolean; | |||
} | |||
export default function PageHeader({ loading }: Props) { | |||
return ( | |||
<header className="page-header"> | |||
<h1 className="page-title">{translate('webhooks.page')}</h1> | |||
{loading && <i className="spinner" />} | |||
<p className="page-description"> | |||
<FormattedMessage | |||
defaultMessage={translate('webhooks.description')} | |||
id={'webhooks.description'} | |||
values={{ | |||
url: ( | |||
<a | |||
href="https://redirect.sonarsource.com/doc/webhooks.html" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
{translate('webhooks.documentation_link')} | |||
</a> | |||
) | |||
}} | |||
/> | |||
</p> | |||
</header> | |||
); | |||
} |
@@ -0,0 +1,34 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { Webhook } from '../../../api/webhooks'; | |||
interface Props { | |||
webhook: Webhook; | |||
} | |||
export default function WebhookItem({ webhook }: Props) { | |||
return ( | |||
<tr> | |||
<td>{webhook.name}</td> | |||
<td>{webhook.url}</td> | |||
</tr> | |||
); | |||
} |
@@ -0,0 +1,58 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import WebhookItem from './WebhookItem'; | |||
import { Webhook } from '../../../api/webhooks'; | |||
import { translate } from '../../../helpers/l10n'; | |||
interface Props { | |||
webhooks: Webhook[]; | |||
} | |||
export default class WebhooksList extends React.PureComponent<Props> { | |||
renderHeader = () => ( | |||
<thead> | |||
<tr> | |||
<th>{translate('name')}</th> | |||
<th>{translate('webhooks.url')}</th> | |||
</tr> | |||
</thead> | |||
); | |||
renderNoWebhooks = () => ( | |||
<tr> | |||
<td>{translate('webhooks.no_result')}</td> | |||
</tr> | |||
); | |||
render() { | |||
const { webhooks } = this.props; | |||
return ( | |||
<table className="data zebra"> | |||
{this.renderHeader()} | |||
<tbody> | |||
{webhooks.length > 0 | |||
? webhooks.map(webhook => <WebhookItem key={webhook.key} webhook={webhook} />) | |||
: this.renderNoWebhooks()} | |||
</tbody> | |||
</table> | |||
); | |||
} | |||
} |
@@ -0,0 +1,83 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import App from '../App'; | |||
import { searchWebhooks } from '../../../../api/webhooks'; | |||
import { Visibility } from '../../../../app/types'; | |||
jest.mock('../../../../api/webhooks', () => ({ | |||
searchWebhooks: jest.fn(() => Promise.resolve({ webhooks: [] })) | |||
})); | |||
const organization = { key: 'foo', name: 'Foo', projectVisibility: Visibility.Private }; | |||
const component = { key: 'bar', organization: 'foo', qualifier: 'TRK' }; | |||
beforeEach(() => { | |||
(searchWebhooks as jest.Mock<any>).mockClear(); | |||
}); | |||
it('should be in loading status', () => { | |||
expect(shallow(<App organization={undefined} />)).toMatchSnapshot(); | |||
}); | |||
it('should fetch webhooks and display them', async () => { | |||
const wrapper = shallow(<App organization={organization} />); | |||
expect(wrapper.state('loading')).toBeTruthy(); | |||
await new Promise(setImmediate); | |||
expect(searchWebhooks).toHaveBeenCalledWith({ organization: organization.key }); | |||
wrapper.update(); | |||
expect(wrapper).toMatchSnapshot(); | |||
}); | |||
describe('should correctly fetch webhooks when', () => { | |||
it('on global scope', async () => { | |||
shallow(<App organization={undefined} />); | |||
await new Promise(setImmediate); | |||
expect(searchWebhooks).toHaveBeenCalledWith({ organization: undefined }); | |||
}); | |||
it('on project scope', async () => { | |||
shallow(<App organization={undefined} component={component} />); | |||
await new Promise(setImmediate); | |||
expect(searchWebhooks).toHaveBeenCalledWith({ project: component.key }); | |||
}); | |||
it('on organization scope', async () => { | |||
shallow(<App organization={organization} component={undefined} />); | |||
await new Promise(setImmediate); | |||
expect(searchWebhooks).toHaveBeenCalledWith({ organization: organization.key }); | |||
}); | |||
it('on project scope within an organization', async () => { | |||
shallow(<App organization={organization} component={component} />); | |||
await new Promise(setImmediate); | |||
expect(searchWebhooks).toHaveBeenCalledWith({ | |||
organization: organization.key, | |||
project: component.key | |||
}); | |||
}); | |||
}); |
@@ -0,0 +1,26 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import PageHeader from '../PageHeader'; | |||
it('should render correctly', () => { | |||
expect(shallow(<PageHeader loading={true} />)).toMatchSnapshot(); | |||
}); |
@@ -0,0 +1,28 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import WebhookItem from '../WebhookItem'; | |||
const webhook = { key: '1', name: 'my webhook', url: 'http://webhook.target' }; | |||
it('should render correctly', () => { | |||
expect(shallow(<WebhookItem webhook={webhook} />)).toMatchSnapshot(); | |||
}); |
@@ -0,0 +1,35 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import WebhooksList from '../WebhooksList'; | |||
const webhooks = [ | |||
{ key: '1', name: 'my webhook', url: 'http://webhook.target' }, | |||
{ key: '2', name: 'jenkins webhook', url: 'http://jenkins.target' } | |||
]; | |||
it('should correctly render empty webhook list', () => { | |||
expect(shallow(<WebhooksList webhooks={[]} />)).toMatchSnapshot(); | |||
}); | |||
it('should correctly render the webhooks', () => { | |||
expect(shallow(<WebhooksList webhooks={webhooks} />)).toMatchSnapshot(); | |||
}); |
@@ -0,0 +1,38 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should be in loading status 1`] = ` | |||
<div | |||
className="page page-limited" | |||
> | |||
<HelmetWrapper | |||
defer={true} | |||
encodeSpecialCharacters={true} | |||
title="webhooks.page" | |||
/> | |||
<PageHeader | |||
loading={true} | |||
/> | |||
</div> | |||
`; | |||
exports[`should fetch webhooks and display them 1`] = ` | |||
<div | |||
className="page page-limited" | |||
> | |||
<HelmetWrapper | |||
defer={true} | |||
encodeSpecialCharacters={true} | |||
title="webhooks.page" | |||
/> | |||
<PageHeader | |||
loading={false} | |||
/> | |||
<div | |||
className="boxed-group boxed-group-inner" | |||
> | |||
<WebhooksList | |||
webhooks={Array []} | |||
/> | |||
</div> | |||
</div> | |||
`; |
@@ -0,0 +1,35 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<header | |||
className="page-header" | |||
> | |||
<h1 | |||
className="page-title" | |||
> | |||
webhooks.page | |||
</h1> | |||
<i | |||
className="spinner" | |||
/> | |||
<p | |||
className="page-description" | |||
> | |||
<FormattedMessage | |||
defaultMessage="webhooks.description" | |||
id="webhooks.description" | |||
values={ | |||
Object { | |||
"url": <a | |||
href="https://redirect.sonarsource.com/doc/webhooks.html" | |||
rel="noopener noreferrer" | |||
target="_blank" | |||
> | |||
webhooks.documentation_link | |||
</a>, | |||
} | |||
} | |||
/> | |||
</p> | |||
</header> | |||
`; |
@@ -0,0 +1,12 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<tr> | |||
<td> | |||
my webhook | |||
</td> | |||
<td> | |||
http://webhook.target | |||
</td> | |||
</tr> | |||
`; |
@@ -0,0 +1,46 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should correctly render empty webhook list 1`] = ` | |||
<p> | |||
webhooks.no_result | |||
</p> | |||
`; | |||
exports[`should correctly render the webhooks 1`] = ` | |||
<table | |||
className="data zebra" | |||
> | |||
<thead> | |||
<tr> | |||
<th> | |||
name | |||
</th> | |||
<th> | |||
webhooks.url | |||
</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<WebhookItem | |||
key="1" | |||
webhook={ | |||
Object { | |||
"key": "1", | |||
"name": "my webhook", | |||
"url": "http://webhook.target", | |||
} | |||
} | |||
/> | |||
<WebhookItem | |||
key="2" | |||
webhook={ | |||
Object { | |||
"key": "2", | |||
"name": "jenkins webhook", | |||
"url": "http://jenkins.target", | |||
} | |||
} | |||
/> | |||
</tbody> | |||
</table> | |||
`; |
@@ -0,0 +1,32 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { RouterState, RouteComponent } from 'react-router'; | |||
const routes = [ | |||
{ | |||
indexRoute: { | |||
getComponent(_: RouterState, callback: (err: any, component: RouteComponent) => any) { | |||
import('./components/App').then(i => callback(null, i.default)); | |||
} | |||
} | |||
} | |||
]; | |||
export default routes; |
@@ -2805,3 +2805,16 @@ favorite.current.APP=This application is marked as favorite. | |||
favorite.current.FIL=This file is marked as favorite. | |||
favorite.current.CLA=This file is marked as favorite. | |||
favorite.current.UTS=This test file is marked as favorite. | |||
#------------------------------------------------------------------------------ | |||
# | |||
# WEBHOOKS | |||
# | |||
#------------------------------------------------------------------------------ | |||
webhooks.page=Webhooks | |||
webhooks.description=Webhooks are used to notify external services when a project analysis is done. An HTTP POST request including a JSON payload is sent to each of the provided URLs. Learn more in the {url}. | |||
webhooks.documentation_link=Webhooks documentation | |||
webhooks.no_result=No webhook defined. | |||
webhooks.url=URL |