UNPKG

@pagerduty/backstage-plugin

Version:

A Backstage plugin that integrates towards PagerDuty

206 lines (203 loc) 9.88 kB
import React, { useState, useCallback } from 'react'; import { Card, CardHeader, Grid, Typography, Divider, CardContent } from '@material-ui/core'; import { Incidents } from '../Incident/Incidents.esm.js'; import { EscalationPolicy } from '../Escalation/EscalationPolicy.esm.js'; 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 { ChangeEvents } from '../ChangeEvents/ChangeEvents.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, TabbedCard, CardTab, 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'; 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)" }, oncallHeaderTextStyle: { fontSize: "14px", fontWeight: 500, marginTop: "10px", 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: "15px", marginBottom: "20px" }, headerWithSubheaderContainerStyle: { display: "flex", alignItems: "center" }, subheaderTextStyle: { fontSize: "10px", marginLeft: "5px" }, overviewCardsContainerStyle: { display: "flex", margin: "15px", marginTop: "-15px" }, incidentMetricsContainerStyle: { display: "flex", height: "100%", justifyContent: "center", columnSpan: "all" } }) ); const BasicCard = ({ children }) => /* @__PURE__ */ React.createElement(InfoCard, { title: "PagerDuty" }, children); const PagerDutyCard = (props) => { const classes = useStyles(); const theme = useTheme(); const { readOnly, disableChangeEvents, disableOnCall } = props; const api = useApi(pagerDutyApiRef); const [refreshIncidents, setRefreshIncidents] = useState(false); const [refreshChangeEvents, setRefreshChangeEvents] = useState(false); const [refreshStatus, setRefreshStatus] = useState(false); const handleRefresh = useCallback(() => { setRefreshIncidents((x) => !x); setRefreshChangeEvents((x) => !x); 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, account: props.account, name: foundService.name, 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: "35" }) : /* @__PURE__ */ React.createElement("img", { src: PDGreenImage, alt: "PagerDuty", height: "35" }), action: !readOnly && props.integrationKey ? /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement( TriggerIncidentButton, { "data-testid": "trigger-incident-button", integrationKey: props.integrationKey, entityName: props.name, handleRefresh } ), /* @__PURE__ */ React.createElement(OpenServiceButton, { serviceUrl: service.url })) : /* @__PURE__ */ React.createElement(OpenServiceButton, { serviceUrl: service.url }) } ), /* @__PURE__ */ React.createElement(Grid, { item: true, md: 12, className: classes.overviewHeaderContainerStyle }, /* @__PURE__ */ React.createElement(Grid, { item: true, md: 3 }, /* @__PURE__ */ React.createElement(Typography, { className: classes.overviewHeaderTextStyle }, "STATUS")), /* @__PURE__ */ React.createElement(Grid, { item: true, md: 6 }, /* @__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(Grid, { item: true, md: 3 }, /* @__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: 3 }, /* @__PURE__ */ React.createElement( StatusCard, { serviceId: service.id, account: service.account, refreshStatus } )), /* @__PURE__ */ React.createElement(Grid, { item: true, md: 6, className: classes.incidentMetricsContainerStyle }, /* @__PURE__ */ React.createElement(Grid, { item: true, md: 4 }, /* @__PURE__ */ React.createElement( IncidentCounterCard, { 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, { 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, { 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(Grid, { item: true, md: 3 }, /* @__PURE__ */ React.createElement( ServiceStandardsCard, { 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 } ))), /* @__PURE__ */ React.createElement(Divider, null), /* @__PURE__ */ React.createElement(CardContent, null, /* @__PURE__ */ React.createElement(TabbedCard, null, /* @__PURE__ */ React.createElement(CardTab, { label: "Incidents" }, /* @__PURE__ */ React.createElement( Incidents, { serviceId: service.id, refreshIncidents, account: service.account } )), disableChangeEvents !== true ? /* @__PURE__ */ React.createElement(CardTab, { label: "Change Events" }, /* @__PURE__ */ React.createElement( ChangeEvents, { "data-testid": "change-events", serviceId: service.id, refreshEvents: refreshChangeEvents, account: service.account } )) : /* @__PURE__ */ React.createElement(React.Fragment, null)), disableOnCall !== true ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Typography, { className: classes.oncallHeaderTextStyle }, "ON CALL"), /* @__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 { PagerDutyCard }; //# sourceMappingURL=index.esm.js.map