remove uptime monitors

Signed-off-by: Marko Simon <marko@ilert.com>
This commit is contained in:
Marko Simon
2022-10-20 16:07:13 +02:00
parent 0b89ebf6ad
commit b2adf21bda
13 changed files with 1 additions and 767 deletions
-64
View File
@@ -30,7 +30,6 @@ import {
Schedule,
Service,
StatusPage,
UptimeMonitor,
User,
} from '../types';
import {
@@ -293,63 +292,6 @@ export class ILertClient implements ILertApi {
return response;
}
async fetchUptimeMonitors(): Promise<UptimeMonitor[]> {
const init = {
headers: JSON_HEADERS,
};
const response = await this.fetch('/api/uptime-monitors', init);
return response;
}
async fetchUptimeMonitor(id: number): Promise<UptimeMonitor> {
const init = {
headers: JSON_HEADERS,
};
const response: UptimeMonitor = await this.fetch(
`/api/uptime-monitors/${encodeURIComponent(id)}`,
init,
);
return response;
}
async pauseUptimeMonitor(
uptimeMonitor: UptimeMonitor,
): Promise<UptimeMonitor> {
const init = {
method: 'PUT',
headers: JSON_HEADERS,
body: JSON.stringify({ ...uptimeMonitor, paused: true }),
};
const response = await this.fetch(
`/api/uptime-monitors/${encodeURIComponent(uptimeMonitor.id)}`,
init,
);
return response;
}
async resumeUptimeMonitor(
uptimeMonitor: UptimeMonitor,
): Promise<UptimeMonitor> {
const init = {
method: 'PUT',
headers: JSON_HEADERS,
body: JSON.stringify({ ...uptimeMonitor, paused: false }),
};
const response = await this.fetch(
`/api/uptime-monitors/${encodeURIComponent(uptimeMonitor.id)}`,
init,
);
return response;
}
async fetchAlertSources(): Promise<AlertSource[]> {
const init = {
headers: JSON_HEADERS,
@@ -546,12 +488,6 @@ export class ILertClient implements ILertApi {
)}`;
}
getUptimeMonitorDetailsURL(uptimeMonitor: UptimeMonitor): string {
return `${this.baseUrl}/uptime/view.jsf?id=${encodeURIComponent(
uptimeMonitor.id,
)}`;
}
getScheduleDetailsURL(schedule: Schedule): string {
return `${this.baseUrl}/schedule/view.jsf?id=${encodeURIComponent(
schedule.id,
+1 -8
View File
@@ -25,8 +25,7 @@ import {
Schedule,
Service,
StatusPage,
UptimeMonitor,
User,
User
} from '../types';
/** @public */
@@ -82,11 +81,6 @@ export interface ILertApi {
createAlert(eventRequest: EventRequest): Promise<boolean>;
triggerAlertAction(alert: Alert, action: AlertAction): Promise<void>;
fetchUptimeMonitors(): Promise<UptimeMonitor[]>;
pauseUptimeMonitor(uptimeMonitor: UptimeMonitor): Promise<UptimeMonitor>;
resumeUptimeMonitor(uptimeMonitor: UptimeMonitor): Promise<UptimeMonitor>;
fetchUptimeMonitor(id: number): Promise<UptimeMonitor>;
fetchAlertSources(): Promise<AlertSource[]>;
fetchAlertSource(idOrIntegrationKey: number | string): Promise<AlertSource>;
fetchAlertSourceOnCalls(alertSource: AlertSource): Promise<OnCall[]>;
@@ -115,7 +109,6 @@ export interface ILertApi {
getAlertDetailsURL(alert: Alert): string;
getAlertSourceDetailsURL(alertSource: AlertSource | null): string;
getEscalationPolicyDetailsURL(escalationPolicy: EscalationPolicy): string;
getUptimeMonitorDetailsURL(uptimeMonitor: UptimeMonitor): string;
getScheduleDetailsURL(schedule: Schedule): string;
getServiceDetailsURL(service: Service): string;
getStatusPageDetailsURL(statusPage: StatusPage): string;
@@ -25,7 +25,6 @@ import { AlertsPage } from '../AlertsPage';
import { OnCallSchedulesPage } from '../OnCallSchedulesPage';
import { ServicesPage } from '../ServicesPage';
import { StatusPagesPage } from '../StatusPagePage';
import { UptimeMonitorsPage } from '../UptimeMonitorsPage';
/** @public */
export const ILertPage = () => {
@@ -35,7 +34,6 @@ export const ILertPage = () => {
{ label: 'Alerts' },
{ label: 'Services' },
{ label: 'Status pages' },
{ label: 'Uptime Monitors' },
];
const renderTab = () => {
switch (selectedTab) {
@@ -47,8 +45,6 @@ export const ILertPage = () => {
return <ServicesPage />;
case 3:
return <StatusPagesPage />;
case 4:
return <UptimeMonitorsPage />;
default:
return null;
}
@@ -1,137 +0,0 @@
/*
* Copyright 2021 The Backstage Authors
*
* 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 { IconButton, Menu, MenuItem, Typography } from '@material-ui/core';
import MoreVertIcon from '@material-ui/icons/MoreVert';
import { ilertApiRef } from '../../api';
import { UptimeMonitor } from '../../types';
import { alertApiRef, useApi } from '@backstage/core-plugin-api';
import { Link } from '@backstage/core-components';
export const UptimeMonitorActionsMenu = ({
uptimeMonitor,
onUptimeMonitorChanged,
}: {
uptimeMonitor: UptimeMonitor;
onUptimeMonitorChanged?: (uptimeMonitor: UptimeMonitor) => void;
}) => {
const ilertApi = useApi(ilertApiRef);
const alertApi = useApi(alertApiRef);
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const callback = onUptimeMonitorChanged || ((_: UptimeMonitor): void => {});
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleCloseMenu = () => {
setAnchorEl(null);
};
const handlePause = async (): Promise<void> => {
try {
const newUptimeMonitor = await ilertApi.pauseUptimeMonitor(uptimeMonitor);
handleCloseMenu();
alertApi.post({ message: 'Uptime monitor paused.' });
callback(newUptimeMonitor);
} catch (err) {
alertApi.post({ message: err, severity: 'error' });
}
};
const handleResume = async (): Promise<void> => {
try {
const newUptimeMonitor = await ilertApi.resumeUptimeMonitor(
uptimeMonitor,
);
handleCloseMenu();
alertApi.post({ message: 'Uptime monitor resumed.' });
callback(newUptimeMonitor);
} catch (err) {
alertApi.post({ message: err, severity: 'error' });
}
};
const handleOpenReport = async (): Promise<void> => {
try {
const um = await ilertApi.fetchUptimeMonitor(uptimeMonitor.id);
handleCloseMenu();
window.open(um.shareUrl, '_blank');
} catch (err) {
alertApi.post({ message: err, severity: 'error' });
}
};
return (
<>
<IconButton
aria-label="more"
aria-controls="long-menu"
aria-haspopup="true"
onClick={handleClick}
size="small"
>
<MoreVertIcon />
</IconButton>
<Menu
id={`uptime-monitor-actions-menu-${uptimeMonitor.id}`}
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleCloseMenu}
PaperProps={{
style: { maxHeight: 48 * 4.5 },
}}
>
{uptimeMonitor.paused ? (
<MenuItem key="ack" onClick={handleResume}>
<Typography variant="inherit" noWrap>
Resume
</Typography>
</MenuItem>
) : null}
{!uptimeMonitor.paused ? (
<MenuItem key="close" onClick={handlePause}>
<Typography variant="inherit" noWrap>
Pause
</Typography>
</MenuItem>
) : null}
<MenuItem key="report" onClick={handleCloseMenu}>
<Typography variant="inherit" noWrap>
<Link to="#" onClick={handleOpenReport}>
View Report
</Link>
</Typography>
</MenuItem>
<MenuItem key="details" onClick={handleCloseMenu}>
<Typography variant="inherit" noWrap>
<Link to={ilertApi.getUptimeMonitorDetailsURL(uptimeMonitor)}>
View in iLert
</Link>
</Typography>
</MenuItem>
</Menu>
</>
);
};
@@ -1,50 +0,0 @@
/*
* Copyright 2021 The Backstage Authors
*
* 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 { makeStyles } from '@material-ui/core/styles';
import { UptimeMonitor } from '../../types';
import { ilertApiRef } from '../../api';
import { useApi } from '@backstage/core-plugin-api';
import { Link } from '@backstage/core-components';
const useStyles = makeStyles({
link: {
lineHeight: '22px',
},
});
export const UptimeMonitorLink = ({
uptimeMonitor,
}: {
uptimeMonitor: UptimeMonitor | null;
}) => {
const ilertApi = useApi(ilertApiRef);
const classes = useStyles();
if (!uptimeMonitor) {
return null;
}
return (
<Link
className={classes.link}
to={ilertApi.getUptimeMonitorDetailsURL(uptimeMonitor)}
>
#{uptimeMonitor.id}
</Link>
);
};
@@ -1,16 +0,0 @@
/*
* Copyright 2021 The Backstage Authors
*
* 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 * from './UptimeMonitorActionsMenu';
@@ -1,73 +0,0 @@
/*
* Copyright 2021 The Backstage Authors
*
* 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 Chip from '@material-ui/core/Chip';
import { withStyles } from '@material-ui/core/styles';
import { UptimeMonitor } from '../../types';
const UpChip = withStyles({
root: {
backgroundColor: '#4caf50',
color: 'white',
margin: 0,
},
})(Chip);
const DownChip = withStyles({
root: {
backgroundColor: '#d32f2f',
color: 'white',
margin: 0,
},
})(Chip);
const UnknownChip = withStyles({
root: {
backgroundColor: '#92949c',
color: 'white',
margin: 0,
},
})(Chip);
export const uptimeMonitorStatusLabels = {
['up']: 'Up',
['down']: 'Down',
['unknown']: 'Unknown',
} as Record<string, string>;
export const StatusChip = ({
uptimeMonitor,
}: {
uptimeMonitor: UptimeMonitor;
}) => {
let label = `${uptimeMonitorStatusLabels[uptimeMonitor.status]}`;
if (uptimeMonitor.paused) {
label = 'Paused';
return <UnknownChip label={label} size="small" />;
}
switch (uptimeMonitor.status) {
case 'up':
return <UpChip label={label} size="small" />;
case 'down':
return <DownChip label={label} size="small" />;
case 'unknown':
return <UnknownChip label={label} size="small" />;
default:
return <Chip label={label} size="small" />;
}
};
@@ -1,42 +0,0 @@
/*
* Copyright 2021 The Backstage Authors
*
* 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 { UptimeMonitor } from '../../types';
import Typography from '@material-ui/core/Typography';
export const UptimeMonitorCheckType = ({
uptimeMonitor,
}: {
uptimeMonitor: UptimeMonitor;
}) => {
switch (uptimeMonitor.region) {
case 'EU':
return (
<Typography
noWrap
// eslint-disable-next-line no-restricted-syntax
>{`${uptimeMonitor.checkType.toUpperCase()} 🇩🇪`}</Typography>
);
default:
return (
<Typography
noWrap
// eslint-disable-next-line no-restricted-syntax
>{`${uptimeMonitor.checkType.toUpperCase()} 🇺🇸`}</Typography>
);
}
};
@@ -1,67 +0,0 @@
/*
* Copyright 2021 The Backstage Authors
*
* 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 { AuthenticationError } from '@backstage/errors';
import { UptimeMonitorsTable } from './UptimeMonitorsTable';
import { MissingAuthorizationHeaderError } from '../Errors';
import { useUptimeMonitors } from '../../hooks/useUptimeMonitors';
import {
Content,
ContentHeader,
SupportButton,
ResponseErrorPanel,
} from '@backstage/core-components';
export const UptimeMonitorsPage = () => {
const [
{ tableState, uptimeMonitors, isLoading, error },
{ onChangePage, onChangeRowsPerPage, onUptimeMonitorChanged },
] = useUptimeMonitors();
if (error) {
if (error instanceof AuthenticationError) {
return (
<Content>
<MissingAuthorizationHeaderError />
</Content>
);
}
return (
<Content>
<ResponseErrorPanel error={error} />
</Content>
);
}
return (
<Content>
<ContentHeader title="Uptime Monitors">
<SupportButton>
This helps you to bring iLert into your developer portal.
</SupportButton>
</ContentHeader>
<UptimeMonitorsTable
uptimeMonitors={uptimeMonitors}
tableState={tableState}
isLoading={isLoading}
onChangePage={onChangePage}
onChangeRowsPerPage={onChangeRowsPerPage}
onUptimeMonitorChanged={onUptimeMonitorChanged}
/>
</Content>
);
};
@@ -1,176 +0,0 @@
/*
* Copyright 2021 The Backstage Authors
*
* 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 { makeStyles } from '@material-ui/core/styles';
import { TableState } from '../../api';
import { UptimeMonitor } from '../../types';
import { StatusChip } from './StatusChip';
import Typography from '@material-ui/core/Typography';
import { DateTime as dt, Interval } from 'luxon';
import humanizeDuration from 'humanize-duration';
import { EscalationPolicyLink } from '../EscalationPolicy/EscalationPolicyLink';
import { UptimeMonitorCheckType } from './UptimeMonitorCheckType';
import { UptimeMonitorActionsMenu } from '../UptimeMonitor/UptimeMonitorActionsMenu';
import { UptimeMonitorLink } from '../UptimeMonitor/UptimeMonitorLink';
import { Table, TableColumn } from '@backstage/core-components';
const useStyles = makeStyles(theme => ({
empty: {
padding: theme.spacing(2),
display: 'flex',
justifyContent: 'center',
},
}));
export const UptimeMonitorsTable = ({
uptimeMonitors,
tableState,
isLoading,
onChangePage,
onChangeRowsPerPage,
onUptimeMonitorChanged,
}: {
uptimeMonitors: UptimeMonitor[];
tableState: TableState;
isLoading: boolean;
onChangePage: (page: number) => void;
onChangeRowsPerPage: (pageSize: number) => void;
onUptimeMonitorChanged: (uptimeMonitor: UptimeMonitor) => void;
}) => {
const classes = useStyles();
const smColumnStyle = {
width: '5%',
maxWidth: '5%',
};
const mdColumnStyle = {
width: '10%',
maxWidth: '10%',
};
const lgColumnStyle = {
width: '15%',
maxWidth: '15%',
};
const columns: TableColumn[] = [
{
title: 'ID',
field: 'id',
highlight: true,
cellStyle: mdColumnStyle,
headerStyle: mdColumnStyle,
render: rowData => (
<UptimeMonitorLink uptimeMonitor={rowData as UptimeMonitor} />
),
},
{
title: 'Name',
field: 'name',
render: rowData => (
<Typography>{(rowData as UptimeMonitor).name}</Typography>
),
},
{
title: 'Check Type',
field: 'checkType',
cellStyle: lgColumnStyle,
headerStyle: lgColumnStyle,
render: rowData => (
<UptimeMonitorCheckType uptimeMonitor={rowData as UptimeMonitor} />
),
},
{
title: 'Last state change',
field: 'lastStatusChange',
type: 'datetime',
cellStyle: mdColumnStyle,
headerStyle: mdColumnStyle,
render: rowData => (
<Typography noWrap>
{humanizeDuration(
Interval.fromDateTimes(
dt.fromISO((rowData as UptimeMonitor).lastStatusChange),
dt.now(),
)
.toDuration()
.valueOf(),
{ units: ['h', 'm', 's'], largest: 2, round: true },
)}
</Typography>
),
},
{
title: 'Escalation policy',
field: 'assignedTo',
cellStyle: lgColumnStyle,
headerStyle: lgColumnStyle,
render: rowData => (
<EscalationPolicyLink
escalationPolicy={(rowData as UptimeMonitor).escalationPolicy}
/>
),
},
{
title: 'Status',
field: 'status',
cellStyle: smColumnStyle,
headerStyle: smColumnStyle,
render: rowData => (
<StatusChip uptimeMonitor={rowData as UptimeMonitor} />
),
},
{
title: '',
field: '',
cellStyle: smColumnStyle,
headerStyle: smColumnStyle,
render: rowData => (
<UptimeMonitorActionsMenu
uptimeMonitor={rowData as UptimeMonitor}
onUptimeMonitorChanged={onUptimeMonitorChanged}
/>
),
},
];
return (
<Table
options={{
sorting: true,
search: true,
paging: true,
actionsColumnIndex: -1,
pageSize: tableState.pageSize,
pageSizeOptions: [10, 20, 50, 100],
padding: 'dense',
loadingType: 'overlay',
showEmptyDataSourceMessage: !isLoading,
}}
emptyContent={
<Typography color="textSecondary" className={classes.empty}>
No uptime monitor
</Typography>
}
page={tableState.page}
onPageChange={onChangePage}
onRowsPerPageChange={onChangeRowsPerPage}
localization={{ header: { actions: undefined } }}
isLoading={isLoading}
columns={columns}
data={uptimeMonitors}
/>
);
};
@@ -1,17 +0,0 @@
/*
* Copyright 2021 The Backstage Authors
*
* 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 * from './UptimeMonitorsPage';
export * from './UptimeMonitorsTable';
@@ -1,87 +0,0 @@
/*
* Copyright 2021 The Backstage Authors
*
* 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 { ilertApiRef, TableState } from '../api';
import { AuthenticationError } from '@backstage/errors';
import useAsyncRetry from 'react-use/lib/useAsyncRetry';
import { UptimeMonitor } from '../types';
import { useApi, errorApiRef } from '@backstage/core-plugin-api';
export const useUptimeMonitors = () => {
const ilertApi = useApi(ilertApiRef);
const errorApi = useApi(errorApiRef);
const [tableState, setTableState] = React.useState<TableState>({
page: 0,
pageSize: 10,
});
const [uptimeMonitorsList, setUptimeMonitorsList] = React.useState<
UptimeMonitor[]
>([]);
const [isLoading, setIsLoading] = React.useState(false);
const { error, retry } = useAsyncRetry(async () => {
try {
setIsLoading(true);
const data = await ilertApi.fetchUptimeMonitors();
setUptimeMonitorsList(data || []);
setIsLoading(false);
} catch (e) {
setIsLoading(false);
if (!(e instanceof AuthenticationError)) {
errorApi.post(e);
}
throw e;
}
}, [tableState]);
const onUptimeMonitorChanged = (newUptimeMonitor: UptimeMonitor) => {
setUptimeMonitorsList(
uptimeMonitorsList.map((uptimeMonitor: UptimeMonitor): UptimeMonitor => {
if (newUptimeMonitor.id === uptimeMonitor.id) {
return newUptimeMonitor;
}
return uptimeMonitor;
}),
);
};
const onChangePage = (page: number) => {
setTableState({ ...tableState, page });
};
const onChangeRowsPerPage = (pageSize: number) => {
setTableState({ ...tableState, pageSize });
};
return [
{
tableState,
uptimeMonitors: uptimeMonitorsList,
error,
isLoading,
},
{
setTableState,
setUptimeMonitorsList,
retry,
onUptimeMonitorChanged,
onChangePage,
onChangeRowsPerPage,
setIsLoading,
},
] as const;
};
-26
View File
@@ -351,32 +351,6 @@ export interface Shift {
end: string;
}
/** @public */
export interface UptimeMonitor {
id: number;
name: string;
region: 'EU' | 'US';
checkType: 'http' | 'tcp' | 'udp' | 'ping';
checkParams: UptimeMonitorCheckParams;
intervalSec: number;
timeoutMs: number;
createAlertAfterFailedChecks: number;
paused: boolean;
embedUrl: string;
shareUrl: string;
status: string;
lastStatusChange: string;
escalationPolicy: EscalationPolicy;
teams: TeamShort[];
}
/** @public */
export interface UptimeMonitorCheckParams {
host?: string;
port?: number;
url?: string;
}
/** @public */
export interface AlertResponder {
group: 'SUGGESTED' | 'USER' | 'ESCALATION_POLICY' | 'ON_CALL_SCHEDULE';