feat(plugins/pagerduty): lookup by service-id if that is available

* prefer integration-key value over service-id
* disable creation of incidents if integration-key is not available

Signed-off-by: Alec Jacobs <cajacobs5401@gmail.com>
This commit is contained in:
Alec Jacobs
2022-05-27 11:03:06 -07:00
parent 02c2978b79
commit 707191bf6f
2 changed files with 158 additions and 12 deletions
@@ -252,4 +252,134 @@ describe('PageDutyCard', () => {
});
expect(getByRole('dialog')).toBeInTheDocument();
});
describe('when entity has the pagerduty.com/service-id annotation', () => {
it('Renders PagerDuty service information', async () => {
mockPagerDutyApi.getServiceByServiceId = jest
.fn()
.mockImplementationOnce(async () => service);
const { getByText, queryByTestId } = render(
wrapInTestApp(
<ApiProvider apis={apis}>
<EntityProvider entity={entityWithServiceId}>
<PagerDutyCard />
</EntityProvider>
</ApiProvider>,
),
);
await waitFor(() => !queryByTestId('progress'));
expect(getByText('Service Directory')).toBeInTheDocument();
expect(getByText('Create Incident')).toBeInTheDocument();
expect(getByText('Nice! No incidents found!')).toBeInTheDocument();
expect(getByText('Empty escalation policy')).toBeInTheDocument();
});
it('Handles custom error for missing token', async () => {
mockPagerDutyApi.getServiceByServiceId = jest
.fn()
.mockRejectedValueOnce(new UnauthorizedError());
const { getByText, queryByTestId } = render(
wrapInTestApp(
<ApiProvider apis={apis}>
<EntityProvider entity={entityWithServiceId}>
<PagerDutyCard />
</EntityProvider>
</ApiProvider>,
),
);
await waitFor(() => !queryByTestId('progress'));
expect(
getByText('Missing or invalid PagerDuty Token'),
).toBeInTheDocument();
});
it('Handles custom NotFoundError', async () => {
mockPagerDutyApi.getServiceByServiceId = jest
.fn()
.mockRejectedValueOnce(new NotFoundError());
const { getByText, queryByTestId } = render(
wrapInTestApp(
<ApiProvider apis={apis}>
<EntityProvider entity={entityWithServiceId}>
<PagerDutyCard />
</EntityProvider>
</ApiProvider>,
),
);
await waitFor(() => !queryByTestId('progress'));
expect(getByText('PagerDuty Service Not Found')).toBeInTheDocument();
});
it('handles general error', async () => {
mockPagerDutyApi.getServiceByServiceId = jest
.fn()
.mockRejectedValueOnce(new Error('An error occurred'));
const { getByText, queryByTestId } = render(
wrapInTestApp(
<ApiProvider apis={apis}>
<EntityProvider entity={entityWithServiceId}>
<PagerDutyCard />
</EntityProvider>
</ApiProvider>,
),
);
await waitFor(() => !queryByTestId('progress'));
expect(
getByText(
'Error encountered while fetching information. An error occurred',
),
).toBeInTheDocument();
});
it('disables the Create Incident button', async () => {
mockPagerDutyApi.getServiceByServiceId = jest
.fn()
.mockImplementationOnce(async () => service);
const { queryByTestId, getByTitle } = render(
wrapInTestApp(
<ApiProvider apis={apis}>
<EntityProvider entity={entityWithServiceId}>
<PagerDutyCard />
</EntityProvider>
</ApiProvider>,
),
);
await waitFor(() => !queryByTestId('progress'));
expect(queryByTestId('trigger-dialoger')).not.toBeInTheDocument();
expect(
getByTitle('Must provide an integration-key to create incidents')
.className,
).toMatch('disabled');
});
});
describe('when entity has all annotations', () => {
it('queries by integration key', async () => {
mockPagerDutyApi.getServiceByIntegrationKey = jest
.fn()
.mockImplementationOnce(async () => [service]);
mockPagerDutyApi.getServiceByServiceId = jest.fn();
const { getByText, queryByTestId } = render(
wrapInTestApp(
<ApiProvider apis={apis}>
<EntityProvider entity={entity}>
<PagerDutyCard />
</EntityProvider>
</ApiProvider>,
),
);
await waitFor(() => !queryByTestId('progress'));
expect(mockPagerDutyApi.getServiceByServiceId).not.toHaveBeenCalled();
expect(getByText('Service Directory')).toBeInTheDocument();
expect(getByText('Create Incident')).toBeInTheDocument();
expect(getByText('Nice! No incidents found!')).toBeInTheDocument();
expect(getByText('Empty escalation policy')).toBeInTheDocument();
});
});
});
@@ -52,7 +52,7 @@ export const isPluginApplicableToEntity = (entity: Entity) =>
);
export const PagerDutyCard = () => {
const { integrationKey } = usePagerdutyEntity();
const { integrationKey, serviceId } = usePagerdutyEntity();
const api = useApi(pagerDutyApiRef);
const [refreshIncidents, setRefreshIncidents] = useState<boolean>(false);
const [refreshChangeEvents, setRefreshChangeEvents] =
@@ -77,12 +77,16 @@ export const PagerDutyCard = () => {
error,
} = useAsync(async () => {
let service: Service;
const services = await api.getServiceByIntegrationKey(
integrationKey as string,
);
service = services[0];
if (!service) throw new NotFoundError();
if (integrationKey) {
const services = await api.getServiceByIntegrationKey(
integrationKey as string,
);
service = services[0];
if (!service) throw new NotFoundError();
} else {
service = await api.getServiceByServiceId(serviceId);
}
return {
id: service.id,
@@ -128,11 +132,21 @@ export const PagerDutyCard = () => {
icon: <WebIcon />,
};
/**
* In order to create incidents using the REST API, a valid user email address must be present.
* There is no guarantee the current user entity has a valid email association, so instead just
* only allow triggering incidents when an integration key is present.
*/
const createIncidentDisabled = !integrationKey;
const triggerLink: IconLinkVerticalProps = {
label: 'Create Incident',
onClick: showDialog,
icon: <AlarmAddIcon />,
color: 'secondary',
disabled: createIncidentDisabled,
title: createIncidentDisabled
? 'Must provide an integration-key to create incidents'
: '',
};
const escalationPolicyLink: IconLinkVerticalProps = {
@@ -171,12 +185,14 @@ export const PagerDutyCard = () => {
<EscalationPolicy policyId={service!.policyId} />
</CardContent>
</Card>
<TriggerDialog
data-testid="trigger-dialog"
showDialog={dialogShown}
handleDialog={hideDialog}
onIncidentCreated={handleRefresh}
/>
{!createIncidentDisabled && (
<TriggerDialog
data-testid="trigger-dialog"
showDialog={dialogShown}
handleDialog={hideDialog}
onIncidentCreated={handleRefresh}
/>
)}
</>
);
};