@@ -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 }) => { |
@@ -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() { |
@@ -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() { |
@@ -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() { |
@@ -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')} |
@@ -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> | |||
</> | |||
); | |||
} |
@@ -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> |
@@ -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 () => { |
@@ -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} />); | |||
} |
@@ -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(); | |||
}); |
@@ -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(); | |||
}); |
@@ -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> | |||
`; |
@@ -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> | |||
`; |
@@ -18,6 +18,9 @@ exports[`should correctly render the webhooks 1`] = ` | |||
<th> | |||
webhooks.url | |||
</th> | |||
<th> | |||
webhooks.last_execution | |||
</th> | |||
<th /> | |||
</tr> | |||
</thead> |
@@ -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. |