improve updating incident list, refactor code, update tests, move types, rename types file
This commit is contained in:
@@ -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
|
||||
}),
|
||||
}),
|
||||
```
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
-25
@@ -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;
|
||||
};
|
||||
Reference in New Issue
Block a user