improve updating incident list, refactor code, update tests, move types, rename types file

This commit is contained in:
Samira Mokaram
2020-11-30 18:31:35 +01:00
parent d2f716d640
commit 49938595bc
12 changed files with 71 additions and 78 deletions
+2 -1
View File
@@ -57,7 +57,8 @@ createApiFactory({
deps: { discoveryApi: discoveryApiRef },
factory: ({ discoveryApi }) =>
new PagerDutyClientApi({
discoveryApi: discoveryApi
discoveryApi: discoveryApi,
eventUrl: "https://events.pagerduty.com/v2" //to override the default value
}),
}),
```
+6 -7
View File
@@ -15,17 +15,16 @@
*/
import { createApiRef } from '@backstage/core';
import { Service, Incident, OnCall } from '../components/types';
import {
Service,
Incident,
RequestOptions,
ClientApiConfig,
PagerDutyClient,
TriggerAlarmRequest,
ServicesResponse,
IncidentsResponse,
OnCallsResponse,
OnCall,
} from '../components/types';
import { PagerDutyClient, TriggerAlarmRequest } from './types';
ClientApiConfig,
RequestOptions,
} from './types';
export class UnauthorizedError extends Error {}
+24
View File
@@ -15,6 +15,7 @@
*/
import { Incident, OnCall, Service } from '../components/types';
import { DiscoveryApi } from '@backstage/core';
export type TriggerAlarmRequest = {
integrationKey: string;
@@ -47,3 +48,26 @@ export interface PagerDutyClient {
*/
triggerAlarm(request: TriggerAlarmRequest): Promise<Response>;
}
export type ServicesResponse = {
services: Service[];
};
export type IncidentsResponse = {
incidents: Incident[];
};
export type OnCallsResponse = {
oncalls: OnCall[];
};
export type ClientApiConfig = {
eventsUrl?: string;
discoveryApi: DiscoveryApi;
};
export type RequestOptions = {
method: string;
headers: HeadersInit;
body?: BodyInit;
};
@@ -27,7 +27,7 @@ import {
} from '@material-ui/core';
import Avatar from '@material-ui/core/Avatar';
import EmailIcon from '@material-ui/icons/Email';
import PagerdutyIcon from '../PagerDutyIcon';
import { PagerDutyIcon } from '../PagerDutyIcon';
import { User } from '../types';
const useStyles = makeStyles({
@@ -69,7 +69,7 @@ export const EscalationUser = ({ user }: Props) => {
rel="noopener noreferrer"
color="primary"
>
<PagerdutyIcon viewBox="0 0 100 100" />
<PagerDutyIcon viewBox="0 0 100 100" />
</IconButton>
</Tooltip>
</ListItemSecondaryAction>
@@ -29,7 +29,7 @@ import {
import { StatusError, StatusWarning } from '@backstage/core';
import moment from 'moment';
import { Incident } from '../types';
import PagerdutyIcon from '../PagerDutyIcon';
import { PagerDutyIcon } from '../PagerDutyIcon';
const useStyles = makeStyles({
denseListIcon: {
@@ -96,7 +96,7 @@ export const IncidentListItem = ({ incident }: Props) => {
rel="noopener noreferrer"
color="primary"
>
<PagerdutyIcon viewBox="0 0 100 100" />
<PagerDutyIcon viewBox="0 0 100 100" />
</IconButton>
</Tooltip>
</ListItemSecondaryAction>
@@ -37,7 +37,7 @@ describe('Incidents', () => {
<ApiProvider apis={apis}>
<Incidents
serviceId="abc"
shouldRefreshIncidents={false}
onTriggerRefresh={false}
setShouldRefreshIncidents={() => {}}
/>
</ApiProvider>,
@@ -101,7 +101,7 @@ describe('Incidents', () => {
<ApiProvider apis={apis}>
<Incidents
serviceId="abc"
shouldRefreshIncidents={false}
onTriggerRefresh={false}
setShouldRefreshIncidents={() => {}}
/>
</ApiProvider>,
@@ -131,7 +131,7 @@ describe('Incidents', () => {
<ApiProvider apis={apis}>
<Incidents
serviceId="abc"
shouldRefreshIncidents={false}
onTriggerRefresh={false}
setShouldRefreshIncidents={() => {}}
/>
</ApiProvider>,
@@ -25,27 +25,21 @@ import { Alert } from '@material-ui/lab';
type Props = {
serviceId: string;
shouldRefreshIncidents: boolean;
setShouldRefreshIncidents: (shouldRefreshIncidents: boolean) => void;
refreshIncidents: Boolean;
};
export const Incidents = ({
serviceId,
shouldRefreshIncidents,
setShouldRefreshIncidents,
}: Props) => {
export const Incidents = ({ serviceId, refreshIncidents }: Props) => {
const api = useApi(pagerDutyApiRef);
const [{ value: incidents, loading, error }, getIncidents] = useAsyncFn(
async () => {
setShouldRefreshIncidents(false);
return await api.getIncidentsByServiceId(serviceId);
},
);
useEffect(() => {
getIncidents();
}, [shouldRefreshIncidents, getIncidents]);
}, [refreshIncidents, getIncidents]);
if (error) {
return (
@@ -17,7 +17,7 @@
import React from 'react';
import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon';
const SvgPd = (props: SvgIconProps) =>
export const PagerDutyIcon = (props: SvgIconProps) =>
React.createElement(
SvgIcon,
props,
@@ -25,5 +25,3 @@ const SvgPd = (props: SvgIconProps) =>
<path d="M10.442 84.98H0V32.57c0-5.381 2.209-8.634 4.056-10.442 4.097-4.016 9.639-4.136 10.562-4.136h16.426c5.863 0 9.237 2.37 11.084 4.377 3.655 3.976 3.695 9.117 3.615 10.482v19.76c0 5.702-2.33 9.075-4.257 10.883-3.976 3.734-9.237 3.815-10.482 3.775H10.442v17.71zm20.963-28.193c.563 0 2.129-.16 2.972-.964.643-.602.964-1.687.964-3.253V32.289c0-.562-.12-2.048-.924-2.892-.763-.803-2.249-.963-3.373-.963H14.538c-4.096 0-4.096 3.092-4.096 4.136v24.217h20.963zM89.236.2h10.442v52.45c0 5.382-2.209 8.635-4.056 10.442-4.097 4.016-9.639 4.136-10.562 4.136H68.634c-5.863 0-9.237-2.369-11.084-4.377-3.655-3.976-3.695-9.116-3.615-10.482V32.65c0-5.702 2.33-9.076 4.257-10.883 3.976-3.735 9.237-3.815 10.482-3.775h20.562V.2zM68.273 28.435c-.563 0-2.129.16-2.972.963-.643.603-.964 1.687-.964 3.253v20.281c0 .563.12 2.049.924 2.892.763.803 2.249.964 3.373.964H85.14c4.137-.04 4.137-3.133 4.137-4.177V28.434H68.273z" />
</g>,
);
export default SvgPd;
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React, { useState } from 'react';
import { useApi } from '@backstage/core';
import { useApi, Progress } from '@backstage/core';
import { Entity } from '@backstage/catalog-model';
import {
Button,
@@ -34,7 +34,6 @@ import { PagerDutyIcon } from './PagerDutyIcon';
import AlarmAddIcon from '@material-ui/icons/AlarmAdd';
import { TriggerDialog } from './TriggerDialog';
import { MissingTokenError } from './MissingTokenError';
import { Progress } from '@backstage/core';
const useStyles = makeStyles(theme => ({
links: {
@@ -72,9 +71,7 @@ export const PagerDutyCard = ({ entity }: Props) => {
const classes = useStyles();
const api = useApi(pagerDutyApiRef);
const [showDialog, setShowDialog] = useState<boolean>(false);
const [shouldRefreshIncidents, setShouldRefreshIncidents] = useState<boolean>(
false,
);
const [refreshIncidents, setRefreshIncidents] = useState<boolean>(false);
const integrationKey = entity.metadata.annotations![
PAGERDUTY_INTEGRATION_KEY
];
@@ -129,6 +126,10 @@ export const PagerDutyCard = ({ entity }: Props) => {
),
};
const onTriggerRefresh = () => {
setRefreshIncidents(true);
};
return (
<Card>
<CardHeader
@@ -152,8 +153,7 @@ export const PagerDutyCard = ({ entity }: Props) => {
<CardContent>
<Incidents
serviceId={service!.id}
shouldRefreshIncidents={shouldRefreshIncidents}
setShouldRefreshIncidents={setShouldRefreshIncidents}
refreshIncidents={refreshIncidents}
/>
<EscalationPolicy policyId={service!.policyId} />
<TriggerDialog
@@ -161,7 +161,7 @@ export const PagerDutyCard = ({ entity }: Props) => {
handleDialog={handleDialog}
name={entity.metadata.name}
integrationKey={integrationKey}
setShouldRefreshIncidents={setShouldRefreshIncidents}
onTriggerRefresh={onTriggerRefresh}
/>
</CardContent>
</Card>
@@ -71,7 +71,7 @@ describe('TriggerDialog', () => {
handleDialog={() => {}}
name={entity.metadata.name}
integrationKey="abc123"
setShouldRefreshIncidents={() => {}}
onTriggerRefresh={() => {}}
/>
</ApiProvider>,
),
@@ -93,11 +93,13 @@ describe('TriggerDialog', () => {
fireEvent.click(triggerButton);
});
expect(mockTriggerAlarmFn).toHaveBeenCalled();
expect(mockTriggerAlarmFn).toHaveBeenCalledWith(
entity!.metadata!.annotations!['pagerduty.com/integration-key'],
window.location.toString(),
expect(mockTriggerAlarmFn).toHaveBeenCalledWith({
integrationKey: entity!.metadata!.annotations![
'pagerduty.com/integration-key'
],
source: window.location.toString(),
description,
'guest@example.com',
);
userName: 'guest@example.com',
});
});
});
@@ -35,7 +35,7 @@ type Props = {
integrationKey: string;
showDialog: boolean;
handleDialog: () => void;
setShouldRefreshIncidents: (shouldRefreshIncidents: boolean) => void;
onTriggerRefresh: () => void;
};
export const TriggerDialog = ({
@@ -43,22 +43,22 @@ export const TriggerDialog = ({
integrationKey,
showDialog,
handleDialog,
setShouldRefreshIncidents,
onTriggerRefresh,
}: Props) => {
const alertApi = useApi(alertApiRef);
const identityApi = useApi(identityApiRef);
const userId = identityApi.getUserId();
const userName = identityApi.getUserId();
const api = useApi(pagerDutyApiRef);
const [description, setDescription] = useState<string>('');
const [{ value, loading, error }, handleTriggerAlarm] = useAsyncFn(
async (desc: string) =>
await api.triggerAlarm(
async (description: string) =>
await api.triggerAlarm({
integrationKey,
window.location.toString(),
desc,
userId,
),
source: window.location.toString(),
description,
userName,
}),
);
const descriptionChanged = (
@@ -70,9 +70,9 @@ export const TriggerDialog = ({
useEffect(() => {
if (value) {
alertApi.post({
message: `Alarm successfully triggered by ${userId}`,
message: `Alarm successfully triggered by ${userName}`,
});
setShouldRefreshIncidents(true);
onTriggerRefresh();
handleDialog();
}
@@ -82,7 +82,7 @@ export const TriggerDialog = ({
severity: 'error',
});
}
}, [value, error, alertApi, handleDialog, userId, setShouldRefreshIncidents]);
}, [value, error, alertApi, handleDialog, userName, onTriggerRefresh]);
if (!showDialog) {
return null;
@@ -14,8 +14,6 @@
* limitations under the License.
*/
import { DiscoveryApi } from '@backstage/core';
export type Incident = {
id: string;
title: string;
@@ -58,26 +56,3 @@ export type User = {
html_url: string;
name: string;
};
export type ServicesResponse = {
services: Service[];
};
export type IncidentsResponse = {
incidents: Incident[];
};
export type OnCallsResponse = {
oncalls: OnCall[];
};
export type RequestOptions = {
method: string;
headers: HeadersInit;
body?: BodyInit;
};
export type ClientApiConfig = {
eventsUrl?: string;
discoveryApi: DiscoveryApi;
};