diff --git a/plugins/pagerduty/src/components/Escalation/EscalationPolicy.tsx b/plugins/pagerduty/src/components/Escalation/EscalationPolicy.tsx
index cbce0ce4a3..ccf70abb0b 100644
--- a/plugins/pagerduty/src/components/Escalation/EscalationPolicy.tsx
+++ b/plugins/pagerduty/src/components/Escalation/EscalationPolicy.tsx
@@ -15,21 +15,47 @@
*/
import React from 'react';
-import { List, ListSubheader } from '@material-ui/core';
-import { User } from '../types';
+import { List, ListSubheader, LinearProgress } from '@material-ui/core';
import { EscalationUsersEmptyState } from './EscalationUsersEmptyState';
import { EscalationUser } from './EscalationUser';
+import { useAsync } from 'react-use';
+import { pagerDutyApiRef } from '../../api';
+import { useApi } from '@backstage/core';
+import { Alert } from '@material-ui/lab';
-type EscalationPolicyProps = {
- users: User[];
+type Props = {
+ policyId: string;
};
-export const EscalationPolicy = ({ users }: EscalationPolicyProps) => (
- ON CALL}>
- {users.length ? (
- users.map((user, index) => )
- ) : (
-
- )}
-
-);
+export const EscalationPolicy = ({ policyId }: Props) => {
+ const api = useApi(pagerDutyApiRef);
+
+ const { value: users, loading, error } = useAsync(async () => {
+ const oncalls = await api.getOnCallByPolicyId(policyId);
+ const users = oncalls.map(oncall => oncall.user);
+
+ return users;
+ });
+
+ if (error) {
+ return (
+
+ Error encountered while fetching information. {error.message}
+
+ );
+ }
+
+ if (loading) {
+ return ;
+ }
+
+ return users!.length ? (
+ ON CALL}>
+ {users!.map((user, index) => (
+
+ ))}
+
+ ) : (
+
+ );
+};
diff --git a/plugins/pagerduty/src/components/Escalation/EscalationUser.tsx b/plugins/pagerduty/src/components/Escalation/EscalationUser.tsx
index adc8d4e6d7..642c9ecd96 100644
--- a/plugins/pagerduty/src/components/Escalation/EscalationUser.tsx
+++ b/plugins/pagerduty/src/components/Escalation/EscalationUser.tsx
@@ -36,8 +36,13 @@ const useStyles = makeStyles({
},
});
-export const EscalationUser = ({ user }: { user: User }) => {
+type Props = {
+ user: User;
+};
+
+export const EscalationUser = ({ user }: Props) => {
const classes = useStyles();
+
return (
diff --git a/plugins/pagerduty/src/components/Incident/IncidentListItem.tsx b/plugins/pagerduty/src/components/Incident/IncidentListItem.tsx
index 6e22ccbbac..7a97dad281 100644
--- a/plugins/pagerduty/src/components/Incident/IncidentListItem.tsx
+++ b/plugins/pagerduty/src/components/Incident/IncidentListItem.tsx
@@ -31,10 +31,6 @@ import moment from 'moment';
import { Incident } from '../types';
import PagerdutyIcon from '../PagerDutyIcon';
-type IncidentListItemProps = {
- incident: Incident;
-};
-
const useStyles = makeStyles({
denseListIcon: {
marginRight: 0,
@@ -51,9 +47,15 @@ const useStyles = makeStyles({
},
});
-export const IncidentListItem = ({ incident }: IncidentListItemProps) => {
+type Props = {
+ incident: Incident;
+};
+
+export const IncidentListItem = ({ incident }: Props) => {
const classes = useStyles();
- const user = incident.assignments[0].assignee;
+ const user = incident.assignments[0]?.assignee;
+ const createdAt = moment(incident.created_at).fromNow();
+
return (
@@ -68,25 +70,28 @@ export const IncidentListItem = ({ incident }: IncidentListItemProps) => {
- {incident.title}
-
- }
+ primary={incident.title}
+ primaryTypographyProps={{
+ variant: 'body1',
+ className: classes.listItemPrimary,
+ }}
secondary={
-
- Created {moment(incident.created_at).fromNow()}, assigned to{' '}
- {(incident?.assignments[0]?.assignee?.summary && (
- {user.summary}
- )) ||
- 'nobody'}
-
+
+ Created {createdAt} and assigned to{' '}
+
+ {user?.summary ?? 'nobody'}
+
+
}
/>
void;
};
-export const Incidents = ({ incidents }: IncidentsProps) => (
- {incidents.length && 'INCIDENTS'}}
- >
- {incidents.length ? (
- incidents.map((incident, index) => (
+export const Incidents = ({
+ serviceId,
+ shouldRefreshIncidents,
+ setShouldRefreshIncidents,
+}: Props) => {
+ const api = useApi(pagerDutyApiRef);
+
+ const [{ value: incidents, loading, error }, getIncidents] = useAsyncFn(
+ async () => {
+ setShouldRefreshIncidents(false);
+ return await api.getIncidentsByServiceId(serviceId);
+ },
+ );
+
+ useEffect(() => {
+ getIncidents();
+ }, [shouldRefreshIncidents, getIncidents]);
+
+ if (error) {
+ return (
+
+ Error encountered while fetching information. {error.message}
+
+ );
+ }
+
+ if (loading) {
+ return ;
+ }
+
+ return incidents?.length ? (
+ INCIDENTS}>
+ {incidents!.map((incident, index) => (
- ))
- ) : (
-
- )}
-
-);
+ ))}
+
+ ) : (
+
+ );
+};
diff --git a/plugins/pagerduty/src/components/PagerdutyCard.tsx b/plugins/pagerduty/src/components/PagerdutyCard.tsx
index 6b6d466850..f24e91a9e0 100644
--- a/plugins/pagerduty/src/components/PagerdutyCard.tsx
+++ b/plugins/pagerduty/src/components/PagerdutyCard.tsx
@@ -13,10 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React from 'react';
+import React, { useState } from 'react';
import { useApi, EmptyState } from '@backstage/core';
import { Entity } from '@backstage/catalog-model';
import {
+ Button,
Card,
CardContent,
CardHeader,
@@ -26,13 +27,13 @@ import {
} from '@material-ui/core';
import { Incidents } from './Incident';
import { EscalationPolicy } from './Escalation';
-import { TriggerButton } from './TriggerButton';
import { useAsync } from 'react-use';
import { Alert } from '@material-ui/lab';
import { pagerDutyApiRef, UnauthorizedError } from '../api';
import { IconLinkVertical } from '@backstage/plugin-catalog';
import PagerDutyIcon from './PagerDutyIcon';
-import ReportProblemIcon from '@material-ui/icons/ReportProblem';
+import AlarmAddIcon from '@material-ui/icons/AlarmAdd';
+import { TriggerDialog } from './TriggerDialog';
const useStyles = makeStyles(theme => ({
links: {
@@ -42,6 +43,19 @@ const useStyles = makeStyles(theme => ({
gridAutoColumns: 'min-content',
gridGap: theme.spacing(3),
},
+ triggerAlarm: {
+ paddingTop: 0,
+ paddingBottom: 0,
+ fontSize: '0.7rem',
+ textTransform: 'uppercase',
+ fontWeight: 600,
+ letterSpacing: 1.2,
+ lineHeight: 1.5,
+ '&:hover, &:focus, &.focus': {
+ backgroundColor: 'transparent',
+ textDecoration: 'none',
+ },
+ },
}));
export const PAGERDUTY_INTEGRATION_KEY = 'pagerduty.com/integration-key';
@@ -56,35 +70,45 @@ type Props = {
export const PagerDutyCard = ({ entity }: Props) => {
const classes = useStyles();
const api = useApi(pagerDutyApiRef);
+ const [showDialog, setShowDialog] = useState(false);
+ const [shouldRefreshIncidents, setShouldRefreshIncidents] = useState(
+ false,
+ );
+ const integrationKey = entity.metadata.annotations![
+ PAGERDUTY_INTEGRATION_KEY
+ ];
- const { value, loading, error } = useAsync(async () => {
- const integrationKey = entity.metadata.annotations![
- PAGERDUTY_INTEGRATION_KEY
- ];
-
+ const { value: service, loading, error } = useAsync(async () => {
const services = await api.getServiceByIntegrationKey(integrationKey);
- const incidents = await api.getIncidentsByServiceId(services[0].id);
- const oncalls = await api.getOnCallByPolicyId(
- services[0].escalation_policy.id,
- );
- const users = oncalls.map(oncall => oncall.user);
return {
- incidents,
- users,
id: services[0].id,
name: services[0].name,
- homepageUrl: services[0].html_url,
+ url: services[0].html_url,
+ policyId: services[0].escalation_policy.id,
};
});
+ const handleDialog = () => {
+ setShowDialog(!showDialog);
+ };
+
if (error) {
if (error instanceof UnauthorizedError) {
return (
+ Read More
+
+ }
/>
);
}
@@ -102,12 +126,21 @@ export const PagerDutyCard = ({ entity }: Props) => {
const pagerdutyLink = {
title: 'View in PagerDuty',
- href: value!.homepageUrl,
+ href: service!.url,
};
const triggerAlarm = {
title: 'Trigger Alarm',
- action: ,
+ action: (
+
+ ),
};
return (
@@ -123,7 +156,7 @@ export const PagerDutyCard = ({ entity }: Props) => {
/>
}
+ icon={}
action={triggerAlarm.action}
/>
@@ -131,8 +164,19 @@ export const PagerDutyCard = ({ entity }: Props) => {
/>
-
-
+
+
+
);
diff --git a/plugins/pagerduty/src/components/TriggerButton/TriggerButton.tsx b/plugins/pagerduty/src/components/TriggerButton/TriggerButton.tsx
deleted file mode 100644
index a4f012ac47..0000000000
--- a/plugins/pagerduty/src/components/TriggerButton/TriggerButton.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2020 Spotify AB
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import React, { useState } from 'react';
-import { Button, makeStyles } from '@material-ui/core';
-import { TriggerDialog } from '../TriggerDialog';
-import { Entity } from '@backstage/catalog-model';
-import { PAGERDUTY_INTEGRATION_KEY } from '../PagerDutyCard';
-
-const useStyles = makeStyles({
- triggerAlarm: {
- paddingTop: 0,
- paddingBottom: 0,
- fontSize: '0.7rem',
- textTransform: 'uppercase',
- fontWeight: 600,
- letterSpacing: 1.2,
- lineHeight: 1.5,
- '&:hover, &:focus, &.focus': {
- backgroundColor: 'transparent',
- textDecoration: 'none',
- },
- },
-});
-
-type Props = {
- entity: Entity;
-};
-
-export const TriggerButton = ({ entity }: Props) => {
- const [showDialog, setShowDialog] = useState(false);
- const classes = useStyles();
-
- const handleDialog = () => {
- setShowDialog(!showDialog);
- };
-
- return (
- <>
-
- {showDialog && (
-
- )}
- >
- );
-};
diff --git a/plugins/pagerduty/src/components/TriggerButton/index.ts b/plugins/pagerduty/src/components/TriggerButton/index.ts
deleted file mode 100644
index 6a58a4f43f..0000000000
--- a/plugins/pagerduty/src/components/TriggerButton/index.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright 2020 Spotify AB
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-export { TriggerButton } from './TriggerButton';
diff --git a/plugins/pagerduty/src/components/TriggerDialog/TriggerDialog.tsx b/plugins/pagerduty/src/components/TriggerDialog/TriggerDialog.tsx
index 4156074460..e6bb6d107d 100644
--- a/plugins/pagerduty/src/components/TriggerDialog/TriggerDialog.tsx
+++ b/plugins/pagerduty/src/components/TriggerDialog/TriggerDialog.tsx
@@ -19,67 +19,61 @@ import {
Dialog,
DialogTitle,
TextField,
- makeStyles,
DialogActions,
Button,
DialogContent,
Typography,
CircularProgress,
} from '@material-ui/core';
-import {
- Progress,
- useApi,
- alertApiRef,
- identityApiRef,
- WarningPanel,
-} from '@backstage/core';
+import { useApi, alertApiRef, identityApiRef } from '@backstage/core';
import { useAsyncFn } from 'react-use';
import { pagerDutyApiRef } from '../../api';
-import { Alert, AlertTitle } from '@material-ui/lab';
-
-const useStyles = makeStyles({
- warningText: {
- border: '1px solid rgba(245, 155, 35, 0.5)',
- backgroundColor: 'rgba(245, 155, 35, 0.2)',
- padding: '0.5em 1em',
- },
-});
+import { Alert } from '@material-ui/lab';
type Props = {
name: string;
integrationKey: string;
- onClose: () => void;
+ showDialog: boolean;
+ handleDialog: () => void;
+ setShouldRefreshIncidents: (shouldRefreshIncidents: boolean) => void;
};
-export const TriggerDialog = ({ name, integrationKey, onClose }: Props) => {
- const classes = useStyles();
- const [description, setDescription] = useState('');
+export const TriggerDialog = ({
+ name,
+ integrationKey,
+ showDialog,
+ handleDialog,
+ setShouldRefreshIncidents,
+}: Props) => {
const alertApi = useApi(alertApiRef);
const identityApi = useApi(identityApiRef);
const userId = identityApi.getUserId();
const api = useApi(pagerDutyApiRef);
-
- const descriptionChanged = (event: any) => {
- setDescription(event.target.value);
- };
+ const [description, setDescription] = useState('');
const [{ value, loading, error }, handleTriggerAlarm] = useAsyncFn(
- async (desc: string) => {
- return await api.triggerAlarm(
+ async (desc: string) =>
+ await api.triggerAlarm(
integrationKey,
window.location.toString(),
desc,
userId,
- );
- },
+ ),
);
+ const descriptionChanged = (
+ event: React.ChangeEvent,
+ ) => {
+ setDescription(event.target.value);
+ };
+
useEffect(() => {
if (value) {
alertApi.post({
message: `Alarm successfully triggered by ${userId}`,
});
- onClose();
+ setShouldRefreshIncidents(true);
+ handleDialog();
}
if (error) {
@@ -88,16 +82,19 @@ export const TriggerDialog = ({ name, integrationKey, onClose }: Props) => {
severity: 'error',
});
}
- }, [value, error, alertApi, onClose, userId]);
+ }, [value, error, alertApi, handleDialog, userId, setShouldRefreshIncidents]);
+
+ if (!showDialog) {
+ return null;
+ }
return (
-