@pagerduty/backstage-plugin
Version:
A Backstage plugin that integrates towards PagerDuty
213 lines (210 loc) • 9.75 kB
JavaScript
import React, { useState, useCallback } from 'react';
import { Card, CardHeader, Grid, Typography, Accordion, AccordionSummary, AccordionDetails } from '@material-ui/core';
import useAsync from 'react-use/lib/useAsync';
import { pagerDutyApiRef, UnauthorizedError } from '../../api/client.esm.js';
import { MissingTokenError } from '../Errors/MissingTokenError.esm.js';
import { ServiceNotFoundError } from '../Errors/ServiceNotFoundError.esm.js';
import PDGreenImage from '../../assets/PD-Green.svg';
import PDWhiteImage from '../../assets/PD-White.svg';
import { useApi } from '@backstage/core-plugin-api';
import { NotFoundError } from '@backstage/errors';
import { Progress, InfoCard } from '@backstage/core-components';
import { ForbiddenError } from '../Errors/ForbiddenError.esm.js';
import IncidentCounterCard from '../PagerDutyCardCommon/InsightsCard.esm.js';
import { OpenServiceButton } from '../PagerDutyCardCommon/OpenServiceButton.esm.js';
import ServiceStandardsCard from '../PagerDutyCardCommon/ServiceStandardsCard.esm.js';
import StatusCard from '../PagerDutyCardCommon/StatusCard.esm.js';
import { TriggerIncidentButton } from '../PagerDutyCardCommon/TriggerIncidentButton.esm.js';
import { makeStyles, createStyles, useTheme } from '@material-ui/core/styles';
import { EscalationPolicy } from '../Escalation/EscalationPolicy.esm.js';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
const useStyles = makeStyles(
(theme) => createStyles({
overviewHeaderTextStyle: {
fontSize: "14px",
fontWeight: 500,
color: theme.palette.type === "light" ? "rgba(0, 0, 0, 0.54)" : "rgba(255, 255, 255, 0.7)"
},
headerStyle: {
marginBottom: "0px",
fontSize: "0px"
},
overviewHeaderContainerStyle: {
display: "flex",
margin: "0px",
padding: "15px",
marginBottom: "5px"
},
headerWithSubheaderContainerStyle: {
display: "flex",
alignItems: "center"
},
subheaderTextStyle: {
fontSize: "10px",
marginLeft: "5px"
},
overviewCardsContainerStyle: {
display: "flex",
margin: "15px",
marginTop: "-15px"
},
onCallAccordionDetails: {
display: "flex",
width: "100%",
marginTop: "-25px",
marginBottom: "-15px"
},
incidentMetricsContainerStyle: {
display: "flex",
height: "100%",
justifyContent: "center",
columnSpan: "all",
margin: "15px",
marginTop: "-15px"
}
})
);
const BasicCard = ({ children }) => /* @__PURE__ */ React.createElement(InfoCard, { title: "PagerDuty" }, children);
const PagerDutySmallCard = (props) => {
const classes = useStyles();
const theme = useTheme();
const { readOnly, disableInsights, disableOnCall } = props;
const api = useApi(pagerDutyApiRef);
const [refreshStatus, setRefreshStatus] = useState(false);
const handleRefresh = useCallback(() => {
setRefreshStatus((x) => !x);
}, []);
const {
value: service,
loading,
error
} = useAsync(async () => {
const { service: foundService } = await api.getServiceByPagerDutyEntity(
props
);
const serviceStandards = await api.getServiceStandardsByServiceId(
foundService.id,
props.account
);
const serviceMetrics = await api.getServiceMetricsByServiceId(
foundService.id,
props.account
);
const result = {
id: foundService.id,
name: foundService.name,
account: props.account,
url: foundService.html_url,
policyId: foundService.escalation_policy.id,
policyLink: foundService.escalation_policy.html_url,
policyName: foundService.escalation_policy.name,
status: foundService.status,
standards: serviceStandards !== void 0 ? serviceStandards.standards : void 0,
metrics: serviceMetrics !== void 0 ? serviceMetrics.metrics : void 0
};
return result;
}, [props]);
if (error) {
let errorNode;
switch (error.constructor) {
case UnauthorizedError:
errorNode = /* @__PURE__ */ React.createElement(MissingTokenError, null);
break;
case NotFoundError:
errorNode = /* @__PURE__ */ React.createElement(ServiceNotFoundError, null);
break;
default:
errorNode = /* @__PURE__ */ React.createElement(ForbiddenError, null);
}
return /* @__PURE__ */ React.createElement(BasicCard, null, errorNode);
}
if (loading) {
return /* @__PURE__ */ React.createElement(BasicCard, null, /* @__PURE__ */ React.createElement(Progress, null));
}
return /* @__PURE__ */ React.createElement(Card, { "data-testid": "pagerduty-card" }, /* @__PURE__ */ React.createElement(
CardHeader,
{
className: classes.headerStyle,
title: theme.palette.type === "dark" ? /* @__PURE__ */ React.createElement("img", { src: PDWhiteImage, alt: "PagerDuty", height: "25" }) : /* @__PURE__ */ React.createElement("img", { src: PDGreenImage, alt: "PagerDuty", height: "25" }),
action: !readOnly && props.integrationKey ? /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
TriggerIncidentButton,
{
compact: true,
"data-testid": "trigger-incident-button",
integrationKey: props.integrationKey,
entityName: props.name,
handleRefresh
}
), /* @__PURE__ */ React.createElement(OpenServiceButton, { compact: true, serviceUrl: service.url })) : /* @__PURE__ */ React.createElement(OpenServiceButton, { compact: true, serviceUrl: service.url })
}
), /* @__PURE__ */ React.createElement(Grid, { item: true, md: 12, className: classes.overviewHeaderContainerStyle }, /* @__PURE__ */ React.createElement(Grid, { item: true, md: 6 }, /* @__PURE__ */ React.createElement(Typography, { className: classes.overviewHeaderTextStyle }, "STATUS")), /* @__PURE__ */ React.createElement(Grid, { item: true, md: 6 }, /* @__PURE__ */ React.createElement(Typography, { className: classes.overviewHeaderTextStyle }, "STANDARDS"))), /* @__PURE__ */ React.createElement(Grid, { item: true, md: 12, className: classes.overviewCardsContainerStyle }, /* @__PURE__ */ React.createElement(Grid, { item: true, md: 6 }, /* @__PURE__ */ React.createElement(StatusCard, { compact: true, serviceId: service.id, refreshStatus, account: service.account })), /* @__PURE__ */ React.createElement(Grid, { item: true, md: 6 }, /* @__PURE__ */ React.createElement(
ServiceStandardsCard,
{
compact: true,
total: service?.standards?.score !== void 0 ? service?.standards?.score?.total : void 0,
completed: service?.standards?.score !== void 0 ? service?.standards?.score?.passing : void 0,
standards: service?.standards !== void 0 ? service?.standards?.standards : void 0
}
))), disableInsights !== true ? /* @__PURE__ */ React.createElement(Accordion, null, /* @__PURE__ */ React.createElement(
AccordionSummary,
{
expandIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, null),
"aria-controls": "panel1a-content",
id: "panel1a-header"
},
/* @__PURE__ */ React.createElement("span", { className: classes.headerWithSubheaderContainerStyle }, /* @__PURE__ */ React.createElement(Typography, { className: classes.overviewHeaderTextStyle }, "INSIGHTS"), /* @__PURE__ */ React.createElement(Typography, { className: classes.subheaderTextStyle }, "(last 30 days)"))
), /* @__PURE__ */ React.createElement(AccordionDetails, null, /* @__PURE__ */ React.createElement(
Grid,
{
item: true,
md: 12,
className: classes.incidentMetricsContainerStyle
},
/* @__PURE__ */ React.createElement(Grid, { item: true, md: 4 }, /* @__PURE__ */ React.createElement(
IncidentCounterCard,
{
compact: true,
count: service?.metrics !== void 0 && service.metrics.length > 0 ? service?.metrics[0].total_interruptions : void 0,
label: "interruptions",
color: theme.palette.textSubtle
}
)),
/* @__PURE__ */ React.createElement(Grid, { item: true, md: 4 }, /* @__PURE__ */ React.createElement(
IncidentCounterCard,
{
compact: true,
count: service?.metrics !== void 0 && service.metrics.length > 0 ? service?.metrics[0].total_high_urgency_incidents : void 0,
label: "high urgency",
color: theme.palette.warning.main
}
)),
/* @__PURE__ */ React.createElement(Grid, { item: true, md: 4 }, /* @__PURE__ */ React.createElement(
IncidentCounterCard,
{
compact: true,
count: service?.metrics !== void 0 && service?.metrics?.length > 0 ? service?.metrics[0].total_incident_count : void 0,
label: "incidents",
color: theme.palette.error.main
}
))
))) : /* @__PURE__ */ React.createElement(React.Fragment, null), disableOnCall !== true ? /* @__PURE__ */ React.createElement(Accordion, null, /* @__PURE__ */ React.createElement(
AccordionSummary,
{
expandIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, null),
"aria-controls": "panel1a-content",
id: "panel1a-header"
},
/* @__PURE__ */ React.createElement(Typography, { className: classes.overviewHeaderTextStyle }, "ON CALL")
), /* @__PURE__ */ React.createElement(AccordionDetails, { className: classes.onCallAccordionDetails }, /* @__PURE__ */ React.createElement(
EscalationPolicy,
{
"data-testid": "oncall-card",
policyId: service.policyId,
policyUrl: service.policyLink,
policyName: service.policyName,
account: service.account
}
))) : /* @__PURE__ */ React.createElement(React.Fragment, null));
};
export { PagerDutySmallCard };
//# sourceMappingURL=index.esm.js.map