refactor code an structure

This commit is contained in:
Samira Mokaram
2020-11-16 16:09:45 +01:00
parent f9c971b3f7
commit 00a2ead383
15 changed files with 186 additions and 199 deletions
@@ -37,7 +37,7 @@ describe('Escalation', () => {
expect(getByText('Empty escalation policy')).toBeInTheDocument();
});
it('render Escalation list', () => {
it('render escalation list', () => {
const { getByText } = render(
wrapInTestApp(<EscalationPolicy users={escalations} />),
);
@@ -29,7 +29,6 @@ export const EscalationPolicy = ({ users }: EscalationPolicyProps) => (
{users.length ? (
users.map((user, index) => <EscalationUser key={index} user={user} />)
) : (
// TODO: how does it look if we used an EmptyState component here
<EscalationUsersEmptyState />
)}
</List>
@@ -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 '../Pd';
import PagerdutyIcon from '../PagerDutyIcon';
import { User } from '../types';
const useStyles = makeStyles({
@@ -0,0 +1,17 @@
/*
* 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 { EscalationPolicy } from './EscalationPolicy';
@@ -29,7 +29,7 @@ import {
import { StatusError, StatusWarning } from '@backstage/core';
import moment from 'moment';
import { Incident } from '../types';
import PagerdutyIcon from '../Pd';
import PagerdutyIcon from '../PagerDutyIcon';
type IncidentListItemProps = {
incident: Incident;
@@ -0,0 +1,17 @@
/*
* 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 { Incidents } from './Incidents';
@@ -1,97 +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 from 'react';
import { useApi } from '@backstage/core';
import { Entity } from '@backstage/catalog-model';
import { LinearProgress } from '@material-ui/core';
import { Incidents } from './Incident/Incidents';
import { EscalationPolicy } from './Escalation/EscalationPolicy';
import { TriggerButton } from './TriggerButton';
import { useAsync } from 'react-use';
import { Alert } from '@material-ui/lab';
import { pagerDutyApiRef } from '../api/pagerDutyClient';
import { PagerdutyCard } from './PagerdutyCard';
export const PAGERDUTY_INTEGRATION_KEY = 'pagerduty.com/integration-key';
export const isPluginApplicableToEntity = (entity: Entity) =>
Boolean(entity.metadata.annotations?.[PAGERDUTY_INTEGRATION_KEY]);
type Props = {
entity: Entity;
};
export const PagerDutyServiceCard = ({ entity }: Props) => {
const api = useApi(pagerDutyApiRef);
const { value, loading, error } = useAsync(async () => {
const integrationKey = entity.metadata.annotations![
PAGERDUTY_INTEGRATION_KEY
];
const services = await api.getServiceByIntegrationKey(integrationKey);
// TODO check services length
const service = services[0];
const incidents = await api.getIncidentsByServiceId(service.id);
const oncalls = await api.getOnCallByPolicyId(service.escalation_policy.id);
const users = oncalls.map(item => item.user);
return {
incidents,
users,
id: service.id,
name: service.name,
homepageUrl: service.html_url,
};
});
if (error) {
return (
<div>
<Alert severity="error">
Error encountered while fetching information. {error.message}
</Alert>
</div>
);
}
if (loading) {
return <LinearProgress />;
}
const pagerdutyLink = {
title: 'View in PagerDuty',
href: value!.homepageUrl,
};
const triggerAlarm = {
title: 'Trigger Alarm',
action: <TriggerButton entity={entity} />,
};
return (
<PagerdutyCard
title="Pagerduty"
subheader={{ ViewPagerduty: pagerdutyLink, TriggerAlarm: triggerAlarm }}
content={
<>
<Incidents incidents={value!.incidents} />
<EscalationPolicy users={value!.users} />
</>
}
/>
);
};
@@ -1,18 +1,38 @@
/*
* 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 from 'react';
import { useApi, EmptyState } from '@backstage/core';
import { Entity } from '@backstage/catalog-model';
import {
Card,
CardHeader,
CardContent,
CardHeader,
Divider,
Link,
LinearProgress,
makeStyles,
} from '@material-ui/core';
import LinkIcon from '@material-ui/icons/Link';
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 classnames from 'classnames';
import PagerdutyIcon from './Pd';
// TODO: create a general component to use it in pagerduty and aboutCard
const useStyles = makeStyles(theme => ({
links: {
@@ -22,102 +42,98 @@ const useStyles = makeStyles(theme => ({
gridAutoColumns: 'min-content',
gridGap: theme.spacing(3),
},
link: {
display: 'grid',
justifyItems: 'center',
gridGap: 4,
textAlign: 'center',
},
label: {
fontSize: '0.7rem',
textTransform: 'uppercase',
fontWeight: 600,
letterSpacing: 1.2,
},
trigger: {
color: theme.palette.secondary.main,
},
svgButtonImage: {
height: '1.5em',
color: theme.palette.primary.main,
},
}));
type SubHeaderProps = {
ViewPagerduty: { title: string; href: string };
TriggerAlarm: { title: string; action: React.ReactNode };
export const PAGERDUTY_INTEGRATION_KEY = 'pagerduty.com/integration-key';
export const isPluginApplicableToEntity = (entity: Entity) =>
Boolean(entity.metadata.annotations?.[PAGERDUTY_INTEGRATION_KEY]);
type Props = {
entity: Entity;
};
type PagerdutyCardProps = {
title: string;
subheader: SubHeaderProps;
content: React.ReactNode;
};
type VerticalIconProps = {
label: string;
href?: string;
action?: React.ReactNode;
icon?: React.ReactNode;
};
const VerticalIcon = ({
label,
href,
icon = <LinkIcon />,
action,
}: VerticalIconProps) => {
export const PagerDutyCard = ({ entity }: Props) => {
const classes = useStyles();
if (action) {
const api = useApi(pagerDutyApiRef);
const { value, loading, error } = useAsync(async () => {
const integrationKey = entity.metadata.annotations![
PAGERDUTY_INTEGRATION_KEY
];
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,
};
});
if (error) {
if (error instanceof UnauthorizedError) {
return (
<EmptyState
missing="info"
title="Missing or invalid PagerDuty Token"
description="The request to fetch data need a valid token. See README for more details."
/>
);
}
return (
<>
<Link className={classnames(classes.link, classes.trigger)} href={href}>
{icon}
{action}
</Link>
</>
<Alert severity="error">
Error encountered while fetching information. {error.message}
</Alert>
);
}
return (
<>
<Link className={classes.link} href={href}>
{icon}
<span className={classes.label}>{label}</span>
</Link>
</>
);
};
export const PagerdutyCard = ({
title,
subheader,
content,
}: PagerdutyCardProps) => {
const classes = useStyles();
const getSubheader = ({ ViewPagerduty, TriggerAlarm }: SubHeaderProps) => {
return (
<nav className={classes.links}>
<VerticalIcon
label={ViewPagerduty.title}
href={ViewPagerduty.href}
icon={<PagerdutyIcon viewBox="0 0 100 100" />}
></VerticalIcon>
<VerticalIcon
label={TriggerAlarm.title}
icon={<ReportProblemIcon />}
action={TriggerAlarm.action}
></VerticalIcon>
</nav>
);
if (loading) {
return <LinearProgress />;
}
const pagerdutyLink = {
title: 'View in PagerDuty',
href: value!.homepageUrl,
};
const triggerAlarm = {
title: 'Trigger Alarm',
action: <TriggerButton entity={entity} />,
};
return (
<Card>
<CardHeader
title={title}
subheader={getSubheader(subheader)}
></CardHeader>
title="PagerDuty"
subheader={
<nav className={classes.links}>
<IconLinkVertical
label={pagerdutyLink.title}
href={pagerdutyLink.href}
icon={<PagerDutyIcon viewBox="0 0 100 100" />}
/>
<IconLinkVertical
label={triggerAlarm.title}
icon={<ReportProblemIcon />}
action={triggerAlarm.action}
/>
</nav>
}
/>
<Divider />
<CardContent>{content}</CardContent>
<CardContent>
<Incidents incidents={value!.incidents} />
<EscalationPolicy users={value!.users} />
</CardContent>
</Card>
);
};
@@ -16,9 +16,9 @@
import React, { useState } from 'react';
import { Button, makeStyles } from '@material-ui/core';
import { TriggerDialog } from './TriggerDialog';
import { TriggerDialog } from '../TriggerDialog';
import { Entity } from '@backstage/catalog-model';
import { PAGERDUTY_INTEGRATION_KEY } from './PagerDutyServiceCard';
import { PAGERDUTY_INTEGRATION_KEY } from '../PagerDutyCard';
const useStyles = makeStyles({
triggerAlarm: {
@@ -0,0 +1,17 @@
/*
* 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';
@@ -24,8 +24,8 @@ import {
IdentityApi,
identityApiRef,
} from '@backstage/core';
import { pagerDutyApiRef } from '../api/pagerDutyClient';
import { TriggerButton } from './TriggerButton';
import { pagerDutyApiRef } from '../../api';
import { TriggerButton } from '../TriggerButton';
import { Entity } from '@backstage/catalog-model';
import { act } from 'react-dom/test-utils';
@@ -26,7 +26,7 @@ import {
} from '@material-ui/core';
import { Progress, useApi, alertApiRef, identityApiRef } from '@backstage/core';
import { useAsyncFn } from 'react-use';
import { pagerDutyApiRef } from '../api/pagerDutyClient';
import { pagerDutyApiRef } from '../../api';
const useStyles = makeStyles({
warningText: {
@@ -0,0 +1,17 @@
/*
* 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 { TriggerDialog } from './TriggerDialog';
+5 -4
View File
@@ -51,10 +51,6 @@ export type User = {
name: string;
};
export type ClientApiConfig = {
token?: string;
};
export type ServicesResponse = {
services: Service[];
};
@@ -72,3 +68,8 @@ export type RequestOptions = {
headers: HeadersInit;
body?: BodyInit;
};
export type ClientApiConfig = {
api_url: string;
events_url: string;
};