diff options
author | Grégoire Aubert <gregoire.aubert@sonarsource.com> | 2018-02-09 17:20:04 +0100 |
---|---|---|
committer | Guillaume Jambet <guillaume.jambet@gmail.com> | 2018-03-01 15:21:05 +0100 |
commit | a7cdf1a94281ea4f49db4635682d29e990e8801c (patch) | |
tree | 68c49435de14a0c0205b68eac248218fb361b291 | |
parent | 277349697f2e672ae8c5f438f734cfb9b6223d46 (diff) | |
download | sonarqube-a7cdf1a94281ea4f49db4635682d29e990e8801c.tar.gz sonarqube-a7cdf1a94281ea4f49db4635682d29e990e8801c.zip |
SONAR-10346 Display webhook latest delivery status
15 files changed, 166 insertions, 20 deletions
diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/App.tsx b/server/sonar-web/src/main/js/apps/webhooks/components/App.tsx index 68a8f9d42bd..9d33f1486e9 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/webhooks/components/App.tsx @@ -37,7 +37,7 @@ interface State { } export default class App extends React.PureComponent<Props, State> { - mounted: boolean = false; + mounted = false; state: State = { loading: true, webhooks: [] }; componentDidMount() { @@ -65,7 +65,11 @@ export default class App extends React.PureComponent<Props, State> { }; getScopeParams = ({ organization, component } = this.props) => { - return { organization: organization && organization.key, project: component && component.key }; + const organizationKey = organization && organization.key; + return { + organization: component ? component.organization : organizationKey, + project: component && component.key + }; }; handleCreate = (data: { name: string; url: string }) => { diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/DeliveriesForm.tsx b/server/sonar-web/src/main/js/apps/webhooks/components/DeliveriesForm.tsx index 33c0439d38e..ce12280de2f 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/DeliveriesForm.tsx +++ b/server/sonar-web/src/main/js/apps/webhooks/components/DeliveriesForm.tsx @@ -40,7 +40,7 @@ interface State { const PAGE_SIZE = 10; export default class DeliveriesForm extends React.PureComponent<Props, State> { - mounted: boolean = false; + mounted = false; state: State = { deliveries: [], loading: true }; componentDidMount() { diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/DeliveryItem.tsx b/server/sonar-web/src/main/js/apps/webhooks/components/DeliveryItem.tsx index 6eb15b3bc8b..cd75390ec0f 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/DeliveryItem.tsx +++ b/server/sonar-web/src/main/js/apps/webhooks/components/DeliveryItem.tsx @@ -40,7 +40,7 @@ interface State { } export default class DeliveryItem extends React.PureComponent<Props, State> { - mounted: boolean = false; + mounted = false; state: State = { loading: false, open: false }; componentDidMount() { diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/PageActions.tsx b/server/sonar-web/src/main/js/apps/webhooks/components/PageActions.tsx index 3968f8bdfbe..78e045ea959 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/PageActions.tsx +++ b/server/sonar-web/src/main/js/apps/webhooks/components/PageActions.tsx @@ -35,7 +35,7 @@ interface State { const WEBHOOKS_LIMIT = 10; export default class PageActions extends React.PureComponent<Props, State> { - mounted: boolean = false; + mounted = false; state: State = { openCreate: false }; componentDidMount() { diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/WebhookActions.tsx b/server/sonar-web/src/main/js/apps/webhooks/components/WebhookActions.tsx index 42351e01a1f..0027720ad60 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/WebhookActions.tsx +++ b/server/sonar-web/src/main/js/apps/webhooks/components/WebhookActions.tsx @@ -40,7 +40,7 @@ interface State { } export default class WebhookActions extends React.PureComponent<Props, State> { - mounted: boolean = false; + mounted = false; state: State = { deliveries: false, updating: false }; componentDidMount() { @@ -77,18 +77,19 @@ export default class WebhookActions extends React.PureComponent<Props, State> { render() { const { webhook } = this.props; - // TODO Disable "Show deliveries" if there is no lastDelivery return ( <> <ActionsDropdown className="big-spacer-left"> <ActionsDropdownItem className="js-webhook-update" onClick={this.handleUpdateClick}> {translate('update_verb')} </ActionsDropdownItem> - <ActionsDropdownItem - className="js-webhook-deliveries" - onClick={this.handleDeliveriesClick}> - {translate('webhooks.deliveries.show')} - </ActionsDropdownItem> + {webhook.latestDelivery && ( + <ActionsDropdownItem + className="js-webhook-deliveries" + onClick={this.handleDeliveriesClick}> + {translate('webhooks.deliveries.show')} + </ActionsDropdownItem> + )} <ActionsDropdownDivider /> <ConfirmButton confirmButtonText={translate('delete')} diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/WebhookItem.tsx b/server/sonar-web/src/main/js/apps/webhooks/components/WebhookItem.tsx index b51ceb085af..5016508e13c 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/WebhookItem.tsx +++ b/server/sonar-web/src/main/js/apps/webhooks/components/WebhookItem.tsx @@ -19,7 +19,11 @@ */ import * as React from 'react'; import WebhookActions from './WebhookActions'; -import { Webhook } from '../../../app/types'; +import AlertErrorIcon from '../../../components/icons-components/AlertErrorIcon'; +import AlertSuccessIcon from '../../../components/icons-components/AlertSuccessIcon'; +import DateTimeFormatter from '../../../components/intl/DateTimeFormatter'; +import { Webhook, WebhookDelivery } from '../../../app/types'; +import { translate } from '../../../helpers/l10n'; interface Props { onDelete: (webhook: string) => Promise<void>; @@ -32,9 +36,26 @@ export default function WebhookItem({ onDelete, onUpdate, webhook }: Props) { <tr> <td>{webhook.name}</td> <td>{webhook.url}</td> + <td> + <LatestDelivery latestDelivery={webhook.latestDelivery} /> + </td> <td className="thin nowrap text-right"> <WebhookActions onDelete={onDelete} onUpdate={onUpdate} webhook={webhook} /> </td> </tr> ); } + +export function LatestDelivery({ latestDelivery }: { latestDelivery?: WebhookDelivery }) { + if (!latestDelivery) { + return <span>{translate('webhooks.last_execution.none')}</span>; + } + return ( + <> + {latestDelivery.success ? <AlertSuccessIcon /> : <AlertErrorIcon />} + <span className="spacer-left"> + <DateTimeFormatter date={latestDelivery.at} /> + </span> + </> + ); +} diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/WebhooksList.tsx b/server/sonar-web/src/main/js/apps/webhooks/components/WebhooksList.tsx index 57f33ffe151..92e8f191c29 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/WebhooksList.tsx +++ b/server/sonar-web/src/main/js/apps/webhooks/components/WebhooksList.tsx @@ -35,6 +35,7 @@ export default class WebhooksList extends React.PureComponent<Props> { <tr> <th>{translate('name')}</th> <th>{translate('webhooks.url')}</th> + <th>{translate('webhooks.last_execution')}</th> <th /> </tr> </thead> diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/App-test.tsx index 62d45726d81..756f3830852 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/App-test.tsx +++ b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/App-test.tsx @@ -81,7 +81,10 @@ describe('should correctly fetch webhooks when', () => { shallow(<App component={component} organization={undefined} />); await new Promise(setImmediate); - expect(searchWebhooks).toHaveBeenCalledWith({ project: component.key }); + expect(searchWebhooks).toHaveBeenCalledWith({ + project: component.key, + organization: component.organization + }); }); it('on organization scope', async () => { diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/PageActions-test.tsx b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/PageActions-test.tsx index f50a9b062a4..e5a6e374120 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/PageActions-test.tsx +++ b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/PageActions-test.tsx @@ -47,5 +47,5 @@ it('should display the create form', () => { }); function getWrapper(props = {}) { - return shallow(<PageActions onCreate={jest.fn()} loading={false} webhooksCount={5} {...props} />); + return shallow(<PageActions loading={false} onCreate={jest.fn()} webhooksCount={5} {...props} />); } diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/WebhookActions-test.tsx b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/WebhookActions-test.tsx index b4331ce8ce8..70fe2bc5c77 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/WebhookActions-test.tsx +++ b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/WebhookActions-test.tsx @@ -22,7 +22,19 @@ import { shallow } from 'enzyme'; import WebhookActions from '../WebhookActions'; import { click } from '../../../../helpers/testUtils'; -const webhook = { key: '1', name: 'foo', url: 'http://foo.bar' }; +const webhook = { + key: '1', + name: 'foo', + url: 'http://foo.bar' +}; + +const delivery = { + at: '12.02.2018', + durationMs: 20, + httpStatus: 200, + id: '2', + success: true +}; it('should render correctly', () => { expect(getWrapper()).toMatchSnapshot(); @@ -55,7 +67,8 @@ it('should display the delete webhook form', () => { }); it('should display the deliveries form', () => { - const wrapper = getWrapper(); + const wrapper = getWrapper({ webhook: { ...webhook, latestDelivery: delivery } }); + expect(wrapper).toMatchSnapshot(); click(wrapper.find('.js-webhook-deliveries')); expect(wrapper.find('DeliveriesForm').exists()).toBeTruthy(); }); diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/WebhookItem-test.tsx b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/WebhookItem-test.tsx index 9322cf58e0a..6861daae1d2 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/WebhookItem-test.tsx +++ b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/WebhookItem-test.tsx @@ -19,9 +19,22 @@ */ import * as React from 'react'; import { shallow } from 'enzyme'; -import WebhookItem from '../WebhookItem'; +import WebhookItem, { LatestDelivery } from '../WebhookItem'; -const webhook = { key: '1', name: 'my webhook', url: 'http://webhook.target' }; +const latestDelivery = { + at: '12.02.2018', + durationMs: 20, + httpStatus: 200, + id: '2', + success: true +}; + +const webhook = { + key: '1', + name: 'my webhook', + url: 'http://webhook.target', + latestDelivery +}; it('should render correctly', () => { expect( @@ -34,3 +47,13 @@ it('should render correctly', () => { ) ).toMatchSnapshot(); }); + +it('should render correctly the latest delivery', () => { + expect(shallow(<LatestDelivery latestDelivery={undefined} />)).toMatchSnapshot(); + expect(shallow(<LatestDelivery latestDelivery={latestDelivery} />)).toMatchSnapshot(); + expect( + shallow( + <LatestDelivery latestDelivery={{ ...latestDelivery, httpStatus: 500, success: false }} /> + ) + ).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/WebhookActions-test.tsx.snap b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/WebhookActions-test.tsx.snap index e3d35952ba5..7079ff776af 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/WebhookActions-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/WebhookActions-test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`should render correctly 1`] = ` +exports[`should display the deliveries form 1`] = ` <React.Fragment> <ActionsDropdown className="big-spacer-left" @@ -28,3 +28,26 @@ exports[`should render correctly 1`] = ` </ActionsDropdown> </React.Fragment> `; + +exports[`should render correctly 1`] = ` +<React.Fragment> + <ActionsDropdown + className="big-spacer-left" + > + <ActionsDropdownItem + className="js-webhook-update" + onClick={[Function]} + > + update_verb + </ActionsDropdownItem> + <ActionsDropdownDivider /> + <ConfirmButton + confirmButtonText="delete" + isDestructive={true} + modalBody="webhooks.delete.confirm.foo" + modalHeader="webhooks.delete" + onConfirm={[Function]} + /> + </ActionsDropdown> +</React.Fragment> +`; diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/WebhookItem-test.tsx.snap b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/WebhookItem-test.tsx.snap index 7f45d646e0a..99338c1907f 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/WebhookItem-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/WebhookItem-test.tsx.snap @@ -8,6 +8,19 @@ exports[`should render correctly 1`] = ` <td> http://webhook.target </td> + <td> + <LatestDelivery + latestDelivery={ + Object { + "at": "12.02.2018", + "durationMs": 20, + "httpStatus": 200, + "id": "2", + "success": true, + } + } + /> + </td> <td className="thin nowrap text-right" > @@ -17,6 +30,13 @@ exports[`should render correctly 1`] = ` webhook={ Object { "key": "1", + "latestDelivery": Object { + "at": "12.02.2018", + "durationMs": 20, + "httpStatus": 200, + "id": "2", + "success": true, + }, "name": "my webhook", "url": "http://webhook.target", } @@ -25,3 +45,35 @@ exports[`should render correctly 1`] = ` </td> </tr> `; + +exports[`should render correctly the latest delivery 1`] = ` +<span> + webhooks.last_execution.none +</span> +`; + +exports[`should render correctly the latest delivery 2`] = ` +<React.Fragment> + <AlertSuccessIcon /> + <span + className="spacer-left" + > + <DateTimeFormatter + date="12.02.2018" + /> + </span> +</React.Fragment> +`; + +exports[`should render correctly the latest delivery 3`] = ` +<React.Fragment> + <AlertErrorIcon /> + <span + className="spacer-left" + > + <DateTimeFormatter + date="12.02.2018" + /> + </span> +</React.Fragment> +`; diff --git a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/WebhooksList-test.tsx.snap b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/WebhooksList-test.tsx.snap index ff8401ea461..1f4b340e35e 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/WebhooksList-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/webhooks/components/__tests__/__snapshots__/WebhooksList-test.tsx.snap @@ -18,6 +18,9 @@ exports[`should correctly render the webhooks 1`] = ` <th> webhooks.url </th> + <th> + webhooks.last_execution + </th> <th /> </tr> </thead> diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index daf129eab20..f8b475cabd6 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -2824,6 +2824,8 @@ webhooks.delivery.duration_x=Duration: {0} webhooks.delivery.payload=Payload: webhooks.delivery.response_x=Response: {0} webhooks.documentation_link=Webhooks documentation +webhooks.last_execution=Last execution +webhooks.last_execution.none=Never webhooks.maximum_reached=You reached your maximum number of {0} webhooks. You can still update or delete an existing one. webhooks.name=Name webhooks.name.required=Name is required. |