diff --git a/.changeset/blue-sloths-camp.md b/.changeset/blue-sloths-camp.md deleted file mode 100644 index f05326831f..0000000000 --- a/.changeset/blue-sloths-camp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-ilert': minor ---- - -Add iLert plugin diff --git a/plugins/ilert/README.md b/plugins/ilert/README.md index c6b7a94731..da019d6bb6 100644 --- a/plugins/ilert/README.md +++ b/plugins/ilert/README.md @@ -31,12 +31,6 @@ cd packages/app yarn add @backstage/plugin-ilert ``` -Then make sure to export the plugin in your app's [`plugins.ts`](https://github.com/backstage/backstage/blob/master/packages/app/src/plugins.ts) to enable the plugin: - -```js -export { plugin as ILert } from '@backstage/plugin-ilert'; -``` - Add it to the `EntityPage.tsx`: ```ts @@ -44,13 +38,16 @@ import { isPluginApplicableToEntity as isILertAvailable, EntityILertCard, } from '@backstage/plugin-ilert'; -{ - isILertAvailable(entity) && ( - + +// ... + + + - ); -} + +; +// ... ``` > To force an iLert card for each entity just add the `` component. An instruction card will appear if no integration key is set. @@ -61,11 +58,11 @@ Modify your app routes in [`App.tsx`](https://github.com/backstage/backstage/blo ```tsx import { ILertPage } from '@backstage/plugin-ilert'; - + // ... } /> // ... -; +; ``` Modify your sidebar in [`Root.tsx`](https://github.com/backstage/backstage/blob/master/packages/app/src/components/Root/Root.tsx) to include the icon component exported by the plugin - for example: @@ -104,14 +101,13 @@ proxy: allowedMethods: ['GET', 'POST', 'PUT'] allowedHeaders: ['Authorization'] headers: - Authorization: - $env: ILERT_AUTH_HEADER + Authorization: ${ILERT_AUTH_HEADER} ``` -Then start the backend, passing the token as environment variable: +Then start the backend, passing the authorization header (bearer token or basic auth) as environment variable: ```bash -$ ILERT_AUTH_HEADER='Basic ' yarn start +$ ILERT_AUTH_HEADER='' yarn start ``` ## Integration Key @@ -123,6 +119,10 @@ The information displayed for each entity is based on the alert source integrati If you want to use this plugin for an entity, you need to label it with the below annotation: ```yml -annotations: - ilert.com/integration-key: [INTEGRATION_KEY] +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: example + annotations: + ilert.com/integration-key: [INTEGRATION_KEY] ``` diff --git a/plugins/ilert/config.d.ts b/plugins/ilert/config.d.ts new file mode 100644 index 0000000000..52712454e8 --- /dev/null +++ b/plugins/ilert/config.d.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2021 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 interface Config { + ilert: { + /** + * Domain used by users to access iLert web UI. + * Example: https://my-app.ilert.com/ + * @visibility frontend + */ + baseUrl: string; + + /** + * Path to use for requests via the proxy, defaults to /ilert/api + * @visibility frontend + */ + proxyPath?: string; + }; +} diff --git a/plugins/ilert/package.json b/plugins/ilert/package.json index 9a16960233..31eff40dee 100644 --- a/plugins/ilert/package.json +++ b/plugins/ilert/package.json @@ -22,16 +22,16 @@ "dependencies": { "@backstage/catalog-model": "^0.7.6", "@backstage/core": "^0.7.7", + "@backstage/errors": "^0.1.1", "@backstage/plugin-catalog-react": "^0.1.4", "@backstage/theme": "^0.2.6", - "@date-io/date-fns": "1.x", + "@date-io/luxon": "1.x", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "@material-ui/pickers": "^3.3.10", - "date-fns": "^2.20.2", - "moment": "^2.29.1", - "moment-timezone": "^0.5.33", + "humanize-duration": "^3.26.0", + "luxon": "^1.26.0", "react": "^16.13.1", "react-dom": "^16.13.1", "react-use": "^15.3.3" @@ -49,6 +49,8 @@ "msw": "^0.21.2" }, "files": [ - "dist" - ] + "dist", + "config.d.ts" + ], + "configSchema": "config.d.ts" } diff --git a/plugins/ilert/src/api/client.ts b/plugins/ilert/src/api/client.ts index f3c263e9e7..e635d76b99 100644 --- a/plugins/ilert/src/api/client.ts +++ b/plugins/ilert/src/api/client.ts @@ -14,6 +14,7 @@ * limitations under the License. */ import { ConfigApi, createApiRef, DiscoveryApi } from '@backstage/core'; +import { AuthenticationError, ResponseError } from '@backstage/errors'; import { AlertSource, EscalationPolicy, @@ -32,8 +33,7 @@ import { Options, EventRequest, } from './types'; -import moment from 'moment'; -import momentTimezone from 'moment-timezone'; +import { DateTime as dt } from 'luxon'; export const ilertApiRef = createApiRef({ id: 'plugin.ilert.service', @@ -41,7 +41,10 @@ export const ilertApiRef = createApiRef({ }); const DEFAULT_PROXY_PATH = '/ilert'; -export class UnauthorizedError extends Error {} +const JSON_HEADERS = { + 'Content-Type': 'application/json', + Accept: 'application/json', +}; export class ILertClient implements ILertApi { private readonly discoveryApi: DiscoveryApi; @@ -55,14 +58,15 @@ export class ILertClient implements ILertApi { return new ILertClient({ discoveryApi: discoveryApi, baseUrl, - proxyPath: configApi.getOptionalString('ilert.proxyPath'), + proxyPath: + configApi.getOptionalString('ilert.proxyPath') ?? DEFAULT_PROXY_PATH, }); } constructor(opts: Options) { this.discoveryApi = opts.discoveryApi; this.baseUrl = opts.baseUrl; - this.proxyPath = opts.proxyPath ?? DEFAULT_PROXY_PATH; + this.proxyPath = opts.proxyPath; } private async fetch(input: string, init?: RequestInit): Promise { @@ -70,40 +74,37 @@ export class ILertClient implements ILertApi { const response = await fetch(`${apiUrl}${input}`, init); if (response.status === 401) { - throw new UnauthorizedError(''); - } - if (!response.ok) { - throw new Error( - `Request failed with ${response.status} ${response.statusText}`, + throw new AuthenticationError( + 'This request requires HTTP authentication.', ); } + if (!response.ok || response.status >= 400) { + throw await ResponseError.fromResponse(response); + } return await response.json(); } async fetchIncidents(opts?: GetIncidentsOpts): Promise { const init = { - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, }; const query = new URLSearchParams(); - if (opts && opts.maxResults) { - query.append('max-results', `${opts.maxResults}`); + if (opts?.maxResults !== undefined) { + query.append('max-results', String(opts.maxResults)); } - if (opts && opts.startIndex) { - query.append('start-index', `${opts.startIndex}`); + if (opts?.startIndex !== undefined) { + query.append('start-index', String(opts.startIndex)); } - if (opts && opts.alertSources) { + if (opts?.alertSources !== undefined && Array.isArray(opts.alertSources)) { opts.alertSources.forEach((a: number) => { if (a) { - query.append('alert-source', `${a}`); + query.append('alert-source', String(a)); } }); } - if (opts && opts.states && Array.isArray(opts.states)) { + if (opts?.states !== undefined && Array.isArray(opts.states)) { opts.states.forEach(state => { query.append('state', state); }); @@ -118,10 +119,7 @@ export class ILertClient implements ILertApi { async fetchIncidentsCount(opts?: GetIncidentsCountOpts): Promise { const init = { - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, }; const query = new URLSearchParams(); if (opts && opts.states && Array.isArray(opts.states)) { @@ -137,14 +135,21 @@ export class ILertClient implements ILertApi { return response && response.count ? response.count : 0; } + async fetchIncident(id: number): Promise { + const init = { + headers: JSON_HEADERS, + }; + + const response = await this.fetch(`/api/v1/incidents/${id}`, init); + + return response; + } + async fetchIncidentResponders( incident: Incident, ): Promise { const init = { - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, }; const response = await this.fetch( @@ -157,10 +162,7 @@ export class ILertClient implements ILertApi { async fetchIncidentActions(incident: Incident): Promise { const init = { - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, }; const response = await this.fetch( @@ -171,40 +173,42 @@ export class ILertClient implements ILertApi { return response; } - async acceptIncident(incident: Incident): Promise { + async acceptIncident( + incident: Incident, + userName: string, + ): Promise { const init = { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - body: JSON.stringify({ summary: 'Backstage — iLert plugin' }), + method: 'POST', + headers: JSON_HEADERS, + body: JSON.stringify({ + apiKey: incident.alertSource?.integrationKey || '', + incidentKey: incident.incidentKey, + summary: `from ${userName} via Backstage plugin`, + eventType: 'ACCEPT', + }), }; - const response = await this.fetch( - `/api/v1/incidents/${incident.id}/accept`, - init, - ); - - return response; + await this.fetch('/api/v1/events', init); + return this.fetchIncident(incident.id); } - async resolveIncident(incident: Incident): Promise { + async resolveIncident( + incident: Incident, + userName: string, + ): Promise { const init = { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - body: JSON.stringify({ summary: 'Backstage — iLert plugin' }), + method: 'POST', + headers: JSON_HEADERS, + body: JSON.stringify({ + apiKey: incident.alertSource?.integrationKey || '', + incidentKey: incident.incidentKey, + summary: `from ${userName} via Backstage plugin`, + eventType: 'RESOLVE', + }), }; - const response = await this.fetch( - `/api/v1/incidents/${incident.id}/resolve`, - init, - ); - - return response; + await this.fetch('/api/v1/events', init); + return this.fetchIncident(incident.id); } async assignIncident( @@ -213,22 +217,19 @@ export class ILertClient implements ILertApi { ): Promise { const init = { method: 'PUT', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, }; const query = new URLSearchParams(); switch (responder.group) { case 'ESCALATION_POLICY': - query.append('policy-id', `${responder.id}`); + query.append('policy-id', String(responder.id)); break; case 'ON_CALL_SCHEDULE': - query.append('schedule-id', `${responder.id}`); + query.append('schedule-id', String(responder.id)); break; default: - query.append('user-id', `${responder.id}`); + query.append('user-id', String(responder.id)); break; } @@ -246,10 +247,7 @@ export class ILertClient implements ILertApi { ): Promise { const init = { method: 'POST', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, body: JSON.stringify({ webhookId: action.webhookId, extensionId: action.extensionId, @@ -264,10 +262,7 @@ export class ILertClient implements ILertApi { async createIncident(eventRequest: EventRequest): Promise { const init = { method: 'POST', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, body: JSON.stringify({ apiKey: eventRequest.integrationKey, summary: eventRequest.summary, @@ -286,15 +281,12 @@ export class ILertClient implements ILertApi { }; const response = await this.fetch('/api/v1/events', init); - return response.responseCode === 'NEW_INCIDENT_CREATED'; + return response; } async fetchUptimeMonitors(): Promise { const init = { - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, }; const response = await this.fetch('/api/v1/uptime-monitors', init); @@ -304,10 +296,7 @@ export class ILertClient implements ILertApi { async fetchUptimeMonitor(id: number): Promise { const init = { - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, }; const response: UptimeMonitor = await this.fetch( @@ -323,10 +312,7 @@ export class ILertClient implements ILertApi { ): Promise { const init = { method: 'PUT', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, body: JSON.stringify({ ...uptimeMonitor, paused: true }), }; @@ -343,10 +329,7 @@ export class ILertClient implements ILertApi { ): Promise { const init = { method: 'PUT', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, body: JSON.stringify({ ...uptimeMonitor, paused: false }), }; @@ -360,10 +343,7 @@ export class ILertClient implements ILertApi { async fetchAlertSources(): Promise { const init = { - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, }; const response = await this.fetch('/api/v1/alert-sources', init); @@ -375,10 +355,7 @@ export class ILertClient implements ILertApi { idOrIntegrationKey: number | string, ): Promise { const init = { - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, }; const response = await this.fetch( @@ -391,16 +368,13 @@ export class ILertClient implements ILertApi { async fetchAlertSourceOnCalls(alertSource: AlertSource): Promise { const init = { - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, }; const response = await this.fetch( `/api/v1/on-calls?policies=${ alertSource.escalationPolicy.id - }&expand=user&expand=escalationPolicy&timezone=${momentTimezone.tz.guess()}`, + }&expand=user&expand=escalationPolicy&timezone=${dt.local().zoneName}`, init, ); @@ -410,10 +384,7 @@ export class ILertClient implements ILertApi { async enableAlertSource(alertSource: AlertSource): Promise { const init = { method: 'PUT', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, body: JSON.stringify({ ...alertSource, active: true }), }; @@ -428,10 +399,7 @@ export class ILertClient implements ILertApi { async disableAlertSource(alertSource: AlertSource): Promise { const init = { method: 'PUT', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, body: JSON.stringify({ ...alertSource, active: false }), }; @@ -449,16 +417,13 @@ export class ILertClient implements ILertApi { ): Promise { const init = { method: 'POST', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, body: JSON.stringify({ - start: moment().utc().toISOString(), - end: moment().add(minutes, 'minutes').utc().toISOString(), + start: dt.utc().toISO(), + end: dt.utc().plus({ minutes }).toISO(), description: `Immediate maintenance window for ${minutes} minutes. Backstage — iLert plugin.`, createdBy: 'Backstage', - timezone: momentTimezone.tz.guess(), + timezone: dt.local().zoneName, alertSources: [{ id: alertSourceId }], }), }; @@ -470,10 +435,7 @@ export class ILertClient implements ILertApi { async fetchOnCallSchedules(): Promise { const init = { - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, }; const response = await this.fetch('/api/v1/schedules', init); @@ -483,10 +445,7 @@ export class ILertClient implements ILertApi { async fetchUsers(): Promise { const init = { - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, }; const response = await this.fetch('/api/v1/users', init); @@ -502,10 +461,7 @@ export class ILertClient implements ILertApi { ): Promise { const init = { method: 'PUT', - headers: { - 'Content-Type': 'application/json', - Accept: 'application/json', - }, + headers: JSON_HEADERS, body: JSON.stringify({ user: { id: userId }, start, end }), }; @@ -541,17 +497,7 @@ export class ILertClient implements ILertApi { } getUserPhoneNumber(user: User | null) { - if (!user) { - return ''; - } - if (user.mobile) { - return user.mobile.number; - } - - if (user.landline) { - return user.landline.number; - } - return ''; + return user?.mobile?.number || user?.landline?.number || ''; } getUserInitials(user: User | null) { diff --git a/plugins/ilert/src/api/index.ts b/plugins/ilert/src/api/index.ts index 128856ebdf..65c3571bff 100644 --- a/plugins/ilert/src/api/index.ts +++ b/plugins/ilert/src/api/index.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -export { ILertClient, ilertApiRef, UnauthorizedError } from './client'; +export { ILertClient, ilertApiRef } from './client'; export type { ILertApi, GetIncidentsCountOpts, diff --git a/plugins/ilert/src/api/types.ts b/plugins/ilert/src/api/types.ts index 84b4ecf654..ab9cca3dc6 100644 --- a/plugins/ilert/src/api/types.ts +++ b/plugins/ilert/src/api/types.ts @@ -54,10 +54,11 @@ export type EventRequest = { export interface ILertApi { fetchIncidents(opts?: GetIncidentsOpts): Promise; fetchIncidentsCount(opts?: GetIncidentsCountOpts): Promise; + fetchIncident(id: number): Promise; fetchIncidentResponders(incident: Incident): Promise; fetchIncidentActions(incident: Incident): Promise; - acceptIncident(incident: Incident): Promise; - resolveIncident(incident: Incident): Promise; + acceptIncident(incident: Incident, userName: string): Promise; + resolveIncident(incident: Incident, userName: string): Promise; assignIncident( incident: Incident, responder: IncidentResponder, @@ -115,5 +116,5 @@ export type Options = { /** * Path to use for requests via the proxy, defaults to /ilert/api */ - proxyPath?: string; + proxyPath: string; }; diff --git a/plugins/ilert/src/components/AlertSource/AlertSourceLink.tsx b/plugins/ilert/src/components/AlertSource/AlertSourceLink.tsx index d94a9b0039..f7f6dbb78c 100644 --- a/plugins/ilert/src/components/AlertSource/AlertSourceLink.tsx +++ b/plugins/ilert/src/components/AlertSource/AlertSourceLink.tsx @@ -14,8 +14,7 @@ * limitations under the License. */ import React from 'react'; -import { useApi } from '@backstage/core'; -import Link from '@material-ui/core/Link'; +import { useApi, Link } from '@backstage/core'; import Grid from '@material-ui/core/Grid'; import { AlertSource } from '../../types'; import { ilertApiRef } from '../../api'; @@ -61,7 +60,7 @@ export const AlertSourceLink = ({ {alertSource.name} diff --git a/plugins/ilert/src/components/EscalationPolicy/EscalationPolicyLink.tsx b/plugins/ilert/src/components/EscalationPolicy/EscalationPolicyLink.tsx index 7f1e3524ff..9e7ff102f8 100644 --- a/plugins/ilert/src/components/EscalationPolicy/EscalationPolicyLink.tsx +++ b/plugins/ilert/src/components/EscalationPolicy/EscalationPolicyLink.tsx @@ -14,8 +14,7 @@ * limitations under the License. */ import React from 'react'; -import { useApi } from '@backstage/core'; -import Link from '@material-ui/core/Link'; +import { useApi, Link } from '@backstage/core'; import { makeStyles } from '@material-ui/core/styles'; import { EscalationPolicy } from '../../types'; import { ilertApiRef } from '../../api'; @@ -41,7 +40,7 @@ export const EscalationPolicyLink = ({ return ( {escalationPolicy.name} diff --git a/plugins/ilert/src/components/ILertCard/ILertCard.tsx b/plugins/ilert/src/components/ILertCard/ILertCard.tsx index dd4bdde3cf..bbc82c2b2d 100644 --- a/plugins/ilert/src/components/ILertCard/ILertCard.tsx +++ b/plugins/ilert/src/components/ILertCard/ILertCard.tsx @@ -15,14 +15,14 @@ */ import React from 'react'; import { Entity } from '@backstage/catalog-model'; -import { UnauthorizedError } from '../../api'; -import Alert from '@material-ui/lab/Alert'; +import { AuthenticationError } from '@backstage/errors'; +import { ResponseErrorPanel } from '@backstage/core'; import Card from '@material-ui/core/Card'; import CardContent from '@material-ui/core/CardContent'; import CardHeader from '@material-ui/core/CardHeader'; import Divider from '@material-ui/core/Divider'; import { makeStyles } from '@material-ui/core/styles'; -import { ILERT_INTEGRATION_KEY } from '../../constants'; +import { ILERT_INTEGRATION_KEY_ANNOTATION } from '../../constants'; import { MissingAuthorizationHeaderError } from '../Errors'; import { useIncidents } from '../../hooks/useIncidents'; import { IncidentsTable } from '../IncidentsPage'; @@ -36,7 +36,7 @@ import { ILertCardEmptyState } from './ILertCardEmptyState'; import { ILertCardOnCall } from './ILertCardOnCall'; export const isPluginApplicableToEntity = (entity: Entity) => - Boolean(entity.metadata.annotations?.[ILERT_INTEGRATION_KEY]); + Boolean(entity.metadata.annotations?.[ILERT_INTEGRATION_KEY_ANNOTATION]); const useStyles = makeStyles({ content: { @@ -79,15 +79,11 @@ export const ILertCard = () => { ] = React.useState(false); if (error) { - if (error instanceof UnauthorizedError) { + if (error instanceof AuthenticationError) { return ; } - return ( - - {error.message} - - ); + return ; } if (!integrationKey) { diff --git a/plugins/ilert/src/components/ILertCard/ILertCardEmptyState.tsx b/plugins/ilert/src/components/ILertCard/ILertCardEmptyState.tsx index 42dc140696..955d514564 100644 --- a/plugins/ilert/src/components/ILertCard/ILertCardEmptyState.tsx +++ b/plugins/ilert/src/components/ILertCard/ILertCardEmptyState.tsx @@ -40,14 +40,12 @@ spec: const useStyles = makeStyles(theme => ({ code: { borderRadius: 6, - margin: `${theme.spacing(2)}px 0px`, + margin: theme.spacing(2, 0), background: theme.palette.type === 'dark' ? '#444' : '#fff', }, header: { display: 'inline-block', - padding: `${theme.spacing(2)}px ${theme.spacing(2)}px ${theme.spacing( - 2, - )}px ${theme.spacing(2.5)}px`, + padding: theme.spacing(2, 2, 2, 2.5), }, })); diff --git a/plugins/ilert/src/components/ILertCard/ILertCardOnCallItem.tsx b/plugins/ilert/src/components/ILertCard/ILertCardOnCallItem.tsx index 69ceb0ad55..994666084b 100644 --- a/plugins/ilert/src/components/ILertCard/ILertCardOnCallItem.tsx +++ b/plugins/ilert/src/components/ILertCard/ILertCardOnCallItem.tsx @@ -29,7 +29,7 @@ import { makeStyles } from '@material-ui/core/styles'; import { OnCall } from '../../types'; import { useApi } from '@backstage/core'; import { ilertApiRef } from '../../api'; -import moment from 'moment'; +import { DateTime as dt } from 'luxon'; const useStyles = makeStyles({ listItemPrimary: { @@ -123,8 +123,8 @@ export const ILertCardOnCallItem = ({ diff --git a/plugins/ilert/src/components/Incident/IncidentActionsMenu.tsx b/plugins/ilert/src/components/Incident/IncidentActionsMenu.tsx index 0a1ae95ded..5b06cc4eb6 100644 --- a/plugins/ilert/src/components/Incident/IncidentActionsMenu.tsx +++ b/plugins/ilert/src/components/Incident/IncidentActionsMenu.tsx @@ -14,9 +14,14 @@ * limitations under the License. */ import React from 'react'; -import { alertApiRef, Progress, useApi } from '@backstage/core'; +import { + alertApiRef, + Progress, + useApi, + identityApiRef, + Link, +} from '@backstage/core'; import { IconButton, Menu, MenuItem, Typography } from '@material-ui/core'; -import Link from '@material-ui/core/Link'; import MoreVertIcon from '@material-ui/icons/MoreVert'; import { ilertApiRef } from '../../api'; import { Incident, IncidentAction } from '../../types'; @@ -34,6 +39,8 @@ export const IncidentActionsMenu = ({ }) => { const ilertApi = useApi(ilertApiRef); const alertApi = useApi(alertApiRef); + const identityApi = useApi(identityApiRef); + const userName = identityApi.getUserId(); const [anchorEl, setAnchorEl] = React.useState(null); const callback = onIncidentChanged || ((_: Incident): void => {}); const setProcessing = setIsLoading || ((_: boolean): void => {}); @@ -59,7 +66,7 @@ export const IncidentActionsMenu = ({ try { handleCloseMenu(); setProcessing(true); - const newIncident = await ilertApi.acceptIncident(incident); + const newIncident = await ilertApi.acceptIncident(incident, userName); alertApi.post({ message: 'Incident accepted.' }); callback(newIncident); @@ -74,7 +81,7 @@ export const IncidentActionsMenu = ({ try { handleCloseMenu(); setProcessing(true); - const newIncident = await ilertApi.resolveIncident(incident); + const newIncident = await ilertApi.resolveIncident(incident, userName); alertApi.post({ message: 'Incident resolved.' }); callback(newIncident); @@ -179,7 +186,7 @@ export const IncidentActionsMenu = ({ - + View in iLert diff --git a/plugins/ilert/src/components/Incident/IncidentLink.tsx b/plugins/ilert/src/components/Incident/IncidentLink.tsx index 87818f363a..7bfe08b7a9 100644 --- a/plugins/ilert/src/components/Incident/IncidentLink.tsx +++ b/plugins/ilert/src/components/Incident/IncidentLink.tsx @@ -14,8 +14,7 @@ * limitations under the License. */ import React from 'react'; -import { useApi } from '@backstage/core'; -import Link from '@material-ui/core/Link'; +import { useApi, Link } from '@backstage/core'; import { makeStyles } from '@material-ui/core/styles'; import { Incident } from '../../types'; import { ilertApiRef } from '../../api'; @@ -37,7 +36,7 @@ export const IncidentLink = ({ incident }: { incident: Incident | null }) => { return ( #{incident.id} diff --git a/plugins/ilert/src/components/Incident/IncidentNewModal.tsx b/plugins/ilert/src/components/Incident/IncidentNewModal.tsx index 3fae62bf0c..8ff33e6319 100644 --- a/plugins/ilert/src/components/Incident/IncidentNewModal.tsx +++ b/plugins/ilert/src/components/Incident/IncidentNewModal.tsx @@ -98,17 +98,15 @@ export const IncidentNewModal = ({ setIsLoading(true); setTimeout(async () => { try { - const success = await ilertApi.createIncident({ + await ilertApi.createIncident({ integrationKey, summary, details, userName, source, }); - if (success) { - alertApi.post({ message: 'Incident created.' }); - refetchIncidents(); - } + alertApi.post({ message: 'Incident created.' }); + refetchIncidents(); } catch (err) { alertApi.post({ message: err, severity: 'error' }); } diff --git a/plugins/ilert/src/components/IncidentsPage/IncidentsPage.tsx b/plugins/ilert/src/components/IncidentsPage/IncidentsPage.tsx index e552ce7d26..782848645e 100644 --- a/plugins/ilert/src/components/IncidentsPage/IncidentsPage.tsx +++ b/plugins/ilert/src/components/IncidentsPage/IncidentsPage.tsx @@ -14,11 +14,15 @@ * limitations under the License. */ import React from 'react'; -import { Content, ContentHeader, SupportButton } from '@backstage/core'; +import { + Content, + ContentHeader, + SupportButton, + ResponseErrorPanel, +} from '@backstage/core'; +import { AuthenticationError } from '@backstage/errors'; import Button from '@material-ui/core/Button'; import AddIcon from '@material-ui/icons/Add'; -import { UnauthorizedError } from '../../api'; -import Alert from '@material-ui/lab/Alert'; import { IncidentsTable } from './IncidentsTable'; import { MissingAuthorizationHeaderError } from '../Errors'; import { useIncidents } from '../../hooks/useIncidents'; @@ -44,14 +48,18 @@ export const IncidentsPage = () => { }; if (error) { - if (error instanceof UnauthorizedError) { - return ; + if (error instanceof AuthenticationError) { + return ( + + + + ); } return ( - - {error.message} - + + + ); } diff --git a/plugins/ilert/src/components/IncidentsPage/IncidentsTable.tsx b/plugins/ilert/src/components/IncidentsPage/IncidentsTable.tsx index b7ee298062..087b2bfd40 100644 --- a/plugins/ilert/src/components/IncidentsPage/IncidentsTable.tsx +++ b/plugins/ilert/src/components/IncidentsPage/IncidentsTable.tsx @@ -22,7 +22,8 @@ import { StatusChip } from './StatusChip'; import { AlertSourceLink } from '../AlertSource/AlertSourceLink'; import { TableTitle } from './TableTitle'; import Typography from '@material-ui/core/Typography'; -import moment from 'moment'; +import { DateTime as dt, Interval } from 'luxon'; +import humanizeDuration from 'humanize-duration'; import { IncidentActionsMenu } from '../Incident/IncidentActionsMenu'; import { IncidentLink } from '../Incident/IncidentLink'; @@ -116,16 +117,24 @@ export const IncidentsTable = ({ render: rowData => ( {(rowData as Incident).status !== 'RESOLVED' - ? moment - .duration(moment((rowData as Incident).reportTime).diff(moment())) - .humanize() - : moment - .duration( - moment((rowData as Incident).reportTime).diff( - moment((rowData as Incident).resolvedOn), - ), + ? humanizeDuration( + Interval.fromDateTimes( + dt.fromISO((rowData as Incident).reportTime), + dt.now(), ) - .humanize()} + .toDuration() + .valueOf(), + { units: ['h', 'm', 's'], largest: 2, round: true }, + ) + : humanizeDuration( + Interval.fromDateTimes( + dt.fromISO((rowData as Incident).reportTime), + dt.fromISO((rowData as Incident).resolvedOn), + ) + .toDuration() + .valueOf(), + { units: ['h', 'm', 's'], largest: 2, round: true }, + )} ), }; diff --git a/plugins/ilert/src/components/OnCallSchedulesPage/OnCallSchedulesGrid.tsx b/plugins/ilert/src/components/OnCallSchedulesPage/OnCallSchedulesGrid.tsx index c84e0a7b8d..31da9c1097 100644 --- a/plugins/ilert/src/components/OnCallSchedulesPage/OnCallSchedulesGrid.tsx +++ b/plugins/ilert/src/components/OnCallSchedulesPage/OnCallSchedulesGrid.tsx @@ -14,13 +14,12 @@ * limitations under the License. */ import React from 'react'; -import { useApi, ItemCardGrid, Progress } from '@backstage/core'; +import { useApi, ItemCardGrid, Progress, Link } from '@backstage/core'; import { makeStyles } from '@material-ui/core/styles'; import Card from '@material-ui/core/Card'; import CardContent from '@material-ui/core/CardContent'; import CardHeader from '@material-ui/core/CardHeader'; import Typography from '@material-ui/core/Typography'; -import Link from '@material-ui/core/Link'; import { Schedule } from '../../types'; import { ilertApiRef } from '../../api'; import { OnCallShiftItem } from './OnCallShiftItem'; @@ -132,7 +131,7 @@ export const OnCallSchedulesGrid = ({ classes={{ content: classes.cardHeader }} title={ {schedule.name} diff --git a/plugins/ilert/src/components/OnCallSchedulesPage/OnCallSchedulesPage.tsx b/plugins/ilert/src/components/OnCallSchedulesPage/OnCallSchedulesPage.tsx index 09c2f2fc63..bb0cd0218e 100644 --- a/plugins/ilert/src/components/OnCallSchedulesPage/OnCallSchedulesPage.tsx +++ b/plugins/ilert/src/components/OnCallSchedulesPage/OnCallSchedulesPage.tsx @@ -14,9 +14,13 @@ * limitations under the License. */ import React from 'react'; -import { Content, ContentHeader, SupportButton } from '@backstage/core'; -import { UnauthorizedError } from '../../api'; -import Alert from '@material-ui/lab/Alert'; +import { + Content, + ContentHeader, + SupportButton, + ResponseErrorPanel, +} from '@backstage/core'; +import { AuthenticationError } from '@backstage/errors'; import { OnCallSchedulesGrid } from './OnCallSchedulesGrid'; import { MissingAuthorizationHeaderError } from '../Errors'; import { useOnCallSchedules } from '../../hooks/useOnCallSchedules'; @@ -28,14 +32,18 @@ export const OnCallSchedulesPage = () => { ] = useOnCallSchedules(); if (error) { - if (error instanceof UnauthorizedError) { - return ; + if (error instanceof AuthenticationError) { + return ( + + + + ); } return ( - - {error.message} - + + + ); } diff --git a/plugins/ilert/src/components/OnCallSchedulesPage/OnCallShiftItem.tsx b/plugins/ilert/src/components/OnCallSchedulesPage/OnCallShiftItem.tsx index c636609781..46f6963445 100644 --- a/plugins/ilert/src/components/OnCallSchedulesPage/OnCallShiftItem.tsx +++ b/plugins/ilert/src/components/OnCallSchedulesPage/OnCallShiftItem.tsx @@ -19,7 +19,7 @@ import Grid from '@material-ui/core/Grid'; import Typography from '@material-ui/core/Typography'; import RepeatIcon from '@material-ui/icons/Repeat'; import { Shift } from '../../types'; -import moment from 'moment'; +import { DateTime as dt } from 'luxon'; import { makeStyles } from '@material-ui/core/styles'; import { ShiftOverrideModal } from '../Shift/ShiftOverrideModal'; @@ -77,9 +77,9 @@ export const OnCallShiftItem = ({ ) : null} - {`${moment(shift.start).format('D MMM, HH:mm')} - ${moment( - shift.end, - ).format('D MMM, HH:mm')}`} + {`${dt.fromISO(shift.start).toFormat('D MMM, HH:mm')} - ${dt + .fromISO(shift.end) + .toFormat('D MMM, HH:mm')}`} diff --git a/plugins/ilert/src/components/Shift/ShiftOverrideModal.tsx b/plugins/ilert/src/components/Shift/ShiftOverrideModal.tsx index 1fdd05cb4c..47e13f9b7e 100644 --- a/plugins/ilert/src/components/Shift/ShiftOverrideModal.tsx +++ b/plugins/ilert/src/components/Shift/ShiftOverrideModal.tsx @@ -28,7 +28,7 @@ import { ilertApiRef } from '../../api'; import { useShiftOverride } from '../../hooks/useShiftOverride'; import { Shift } from '../../types'; import { DateTimePicker, MuiPickersUtilsProvider } from '@material-ui/pickers'; -import DateFnsUtils from '@date-io/date-fns'; +import LuxonUtils from '@date-io/luxon'; const useStyles = makeStyles(() => ({ container: { @@ -120,7 +120,7 @@ export const ShiftOverrideModal = ({ > Shift override - + { - setStart(date ? date.toISOString() : ''); + setStart(date ? date.toISO() : ''); }} /> { - setEnd(date ? date.toISOString() : ''); + setEnd(date ? date.toISO() : ''); }} /> diff --git a/plugins/ilert/src/components/UptimeMonitor/UptimeMonitorActionsMenu.tsx b/plugins/ilert/src/components/UptimeMonitor/UptimeMonitorActionsMenu.tsx index efd69a4acf..36671bff90 100644 --- a/plugins/ilert/src/components/UptimeMonitor/UptimeMonitorActionsMenu.tsx +++ b/plugins/ilert/src/components/UptimeMonitor/UptimeMonitorActionsMenu.tsx @@ -14,9 +14,8 @@ * limitations under the License. */ import React from 'react'; -import { alertApiRef, useApi } from '@backstage/core'; +import { alertApiRef, useApi, Link } from '@backstage/core'; import { IconButton, Menu, MenuItem, Typography } from '@material-ui/core'; -import Link from '@material-ui/core/Link'; import MoreVertIcon from '@material-ui/icons/MoreVert'; import { ilertApiRef } from '../../api'; @@ -117,13 +116,15 @@ export const UptimeMonitorActionsMenu = ({ - View Report + + View Report + - + View in iLert diff --git a/plugins/ilert/src/components/UptimeMonitor/UptimeMonitorLink.tsx b/plugins/ilert/src/components/UptimeMonitor/UptimeMonitorLink.tsx index 0af5cd89df..507e0208e2 100644 --- a/plugins/ilert/src/components/UptimeMonitor/UptimeMonitorLink.tsx +++ b/plugins/ilert/src/components/UptimeMonitor/UptimeMonitorLink.tsx @@ -14,8 +14,7 @@ * limitations under the License. */ import React from 'react'; -import { useApi } from '@backstage/core'; -import Link from '@material-ui/core/Link'; +import { useApi, Link } from '@backstage/core'; import { makeStyles } from '@material-ui/core/styles'; import { UptimeMonitor } from '../../types'; import { ilertApiRef } from '../../api'; @@ -41,7 +40,7 @@ export const UptimeMonitorLink = ({ return ( #{uptimeMonitor.id} diff --git a/plugins/ilert/src/components/UptimeMonitorsPage/UptimeMonitorsPage.tsx b/plugins/ilert/src/components/UptimeMonitorsPage/UptimeMonitorsPage.tsx index dc7ea77a6c..9769fa408d 100644 --- a/plugins/ilert/src/components/UptimeMonitorsPage/UptimeMonitorsPage.tsx +++ b/plugins/ilert/src/components/UptimeMonitorsPage/UptimeMonitorsPage.tsx @@ -14,9 +14,13 @@ * limitations under the License. */ import React from 'react'; -import { Content, ContentHeader, SupportButton } from '@backstage/core'; -import { UnauthorizedError } from '../../api'; -import Alert from '@material-ui/lab/Alert'; +import { + Content, + ContentHeader, + SupportButton, + ResponseErrorPanel, +} from '@backstage/core'; +import { AuthenticationError } from '@backstage/errors'; import { UptimeMonitorsTable } from './UptimeMonitorsTable'; import { MissingAuthorizationHeaderError } from '../Errors'; import { useUptimeMonitors } from '../../hooks/useUptimeMonitors'; @@ -28,14 +32,18 @@ export const UptimeMonitorsPage = () => { ] = useUptimeMonitors(); if (error) { - if (error instanceof UnauthorizedError) { - return ; + if (error instanceof AuthenticationError) { + return ( + + + + ); } return ( - - {error.message} - + + + ); } diff --git a/plugins/ilert/src/components/UptimeMonitorsPage/UptimeMonitorsTable.tsx b/plugins/ilert/src/components/UptimeMonitorsPage/UptimeMonitorsTable.tsx index bd55310ad7..2173f8e1b7 100644 --- a/plugins/ilert/src/components/UptimeMonitorsPage/UptimeMonitorsTable.tsx +++ b/plugins/ilert/src/components/UptimeMonitorsPage/UptimeMonitorsTable.tsx @@ -20,7 +20,8 @@ import { TableState } from '../../api'; import { UptimeMonitor } from '../../types'; import { StatusChip } from './StatusChip'; import Typography from '@material-ui/core/Typography'; -import moment from 'moment'; +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'; @@ -99,13 +100,15 @@ export const UptimeMonitorsTable = ({ headerStyle: mdColumnStyle, render: rowData => ( - {moment - .duration( - moment((rowData as UptimeMonitor).lastStatusChange).diff( - moment(), - ), + {humanizeDuration( + Interval.fromDateTimes( + dt.fromISO((rowData as UptimeMonitor).lastStatusChange), + dt.now(), ) - .humanize()} + .toDuration() + .valueOf(), + { units: ['h', 'm', 's'], largest: 2, round: true }, + )} ), }, diff --git a/plugins/ilert/src/hooks/index.ts b/plugins/ilert/src/hooks/index.ts index e21c9584d2..6e7e207112 100644 --- a/plugins/ilert/src/hooks/index.ts +++ b/plugins/ilert/src/hooks/index.ts @@ -16,13 +16,16 @@ import { useEntity } from '@backstage/plugin-catalog-react'; -import { ILERT_INTEGRATION_KEY } from '../constants'; +import { ILERT_INTEGRATION_KEY_ANNOTATION } from '../constants'; export function useILertEntity() { const { entity } = useEntity(); const integrationKey = - entity.metadata.annotations?.[ILERT_INTEGRATION_KEY] || ''; + entity.metadata.annotations?.[ILERT_INTEGRATION_KEY_ANNOTATION] || ''; const name = entity.metadata.name; + const identifier = `${entity.kind}:${ + entity.metadata.namespace || 'default' + }/${entity.metadata.name}`; - return { integrationKey, name }; + return { integrationKey, name, identifier }; } diff --git a/plugins/ilert/src/hooks/useAlertSource.ts b/plugins/ilert/src/hooks/useAlertSource.ts index 950f8f41c6..15cc213b48 100644 --- a/plugins/ilert/src/hooks/useAlertSource.ts +++ b/plugins/ilert/src/hooks/useAlertSource.ts @@ -14,8 +14,9 @@ * limitations under the License. */ import React from 'react'; -import { ilertApiRef, UnauthorizedError } from '../api'; +import { ilertApiRef } from '../api'; import { useApi, errorApiRef } from '@backstage/core'; +import { AuthenticationError } from '@backstage/errors'; import { useAsyncRetry } from 'react-use'; import { AlertSource, UptimeMonitor } from '../types'; @@ -46,7 +47,7 @@ export const useAlertSource = (integrationKey: string) => { setIsAlertSourceLoading(false); } catch (e) { setIsAlertSourceLoading(false); - if (!(e instanceof UnauthorizedError)) { + if (!(e instanceof AuthenticationError)) { errorApi.post(e); } throw e; @@ -69,7 +70,7 @@ export const useAlertSource = (integrationKey: string) => { setIsUptimeMonitorLoading(false); } catch (e) { setIsUptimeMonitorLoading(false); - if (!(e instanceof UnauthorizedError)) { + if (!(e instanceof AuthenticationError)) { errorApi.post(e); } throw e; diff --git a/plugins/ilert/src/hooks/useAlertSourceOnCalls.ts b/plugins/ilert/src/hooks/useAlertSourceOnCalls.ts index ac36c70097..0fbb190a02 100644 --- a/plugins/ilert/src/hooks/useAlertSourceOnCalls.ts +++ b/plugins/ilert/src/hooks/useAlertSourceOnCalls.ts @@ -14,8 +14,9 @@ * limitations under the License. */ import React from 'react'; -import { ilertApiRef, UnauthorizedError } from '../api'; +import { ilertApiRef } from '../api'; import { useApi, errorApiRef } from '@backstage/core'; +import { AuthenticationError } from '@backstage/errors'; import { useAsyncRetry } from 'react-use'; import { AlertSource, OnCall } from '../types'; @@ -37,7 +38,7 @@ export const useAlertSourceOnCalls = (alertSource?: AlertSource | null) => { setIsLoading(false); } catch (e) { setIsLoading(false); - if (!(e instanceof UnauthorizedError)) { + if (!(e instanceof AuthenticationError)) { errorApi.post(e); } throw e; diff --git a/plugins/ilert/src/hooks/useAssignIncident.ts b/plugins/ilert/src/hooks/useAssignIncident.ts index 1671acdc51..8f0f663d2b 100644 --- a/plugins/ilert/src/hooks/useAssignIncident.ts +++ b/plugins/ilert/src/hooks/useAssignIncident.ts @@ -14,8 +14,9 @@ * limitations under the License. */ import React from 'react'; -import { ilertApiRef, UnauthorizedError } from '../api'; +import { ilertApiRef } from '../api'; import { useApi, errorApiRef } from '@backstage/core'; +import { AuthenticationError } from '@backstage/errors'; import { useAsyncRetry } from 'react-use'; import { Incident, IncidentResponder } from '../types'; @@ -49,7 +50,7 @@ export const useAssignIncident = (incident: Incident | null, open: boolean) => { setIncidentRespondersList(data); } } catch (e) { - if (!(e instanceof UnauthorizedError)) { + if (!(e instanceof AuthenticationError)) { errorApi.post(e); } throw e; diff --git a/plugins/ilert/src/hooks/useIncidentActions.ts b/plugins/ilert/src/hooks/useIncidentActions.ts index d8dd08e17a..e23341ed9e 100644 --- a/plugins/ilert/src/hooks/useIncidentActions.ts +++ b/plugins/ilert/src/hooks/useIncidentActions.ts @@ -14,8 +14,9 @@ * limitations under the License. */ import React from 'react'; -import { ilertApiRef, UnauthorizedError } from '../api'; +import { ilertApiRef } from '../api'; import { useApi, errorApiRef } from '@backstage/core'; +import { AuthenticationError } from '@backstage/errors'; import { useAsyncRetry } from 'react-use'; import { Incident, IncidentAction } from '../types'; @@ -39,7 +40,7 @@ export const useIncidentActions = ( const data = await ilertApi.fetchIncidentActions(incident); setIncidentActionsList(data); } catch (e) { - if (!(e instanceof UnauthorizedError)) { + if (!(e instanceof AuthenticationError)) { errorApi.post(e); } throw e; diff --git a/plugins/ilert/src/hooks/useIncidents.ts b/plugins/ilert/src/hooks/useIncidents.ts index 2f3d12cf17..5f130fb20c 100644 --- a/plugins/ilert/src/hooks/useIncidents.ts +++ b/plugins/ilert/src/hooks/useIncidents.ts @@ -14,13 +14,9 @@ * limitations under the License. */ import React from 'react'; -import { - GetIncidentsOpts, - ilertApiRef, - TableState, - UnauthorizedError, -} from '../api'; +import { GetIncidentsOpts, ilertApiRef, TableState } from '../api'; import { useApi, errorApiRef } from '@backstage/core'; +import { AuthenticationError } from '@backstage/errors'; import { useAsyncRetry } from 'react-use'; import { ACCEPTED, @@ -68,7 +64,7 @@ export const useIncidents = ( setIncidentsList(data || []); setIsLoading(false); } catch (e) { - if (!(e instanceof UnauthorizedError)) { + if (!(e instanceof AuthenticationError)) { errorApi.post(e); } setIsLoading(false); @@ -81,7 +77,7 @@ export const useIncidents = ( const count = await ilertApi.fetchIncidentsCount({ states }); setIncidentsCount(count || 0); } catch (e) { - if (!(e instanceof UnauthorizedError)) { + if (!(e instanceof AuthenticationError)) { errorApi.post(e); } throw e; diff --git a/plugins/ilert/src/hooks/useNewIncident.ts b/plugins/ilert/src/hooks/useNewIncident.ts index 669fa74b63..6fbcfbb5a5 100644 --- a/plugins/ilert/src/hooks/useNewIncident.ts +++ b/plugins/ilert/src/hooks/useNewIncident.ts @@ -14,8 +14,9 @@ * limitations under the License. */ import React from 'react'; -import { ilertApiRef, UnauthorizedError } from '../api'; +import { ilertApiRef } from '../api'; import { useApi, errorApiRef } from '@backstage/core'; +import { AuthenticationError } from '@backstage/errors'; import { useAsyncRetry } from 'react-use'; import { AlertSource } from '../types'; @@ -44,7 +45,7 @@ export const useNewIncident = ( const count = await ilertApi.fetchAlertSources(); setAlertSourcesList(count || 0); } catch (e) { - if (!(e instanceof UnauthorizedError)) { + if (!(e instanceof AuthenticationError)) { errorApi.post(e); } throw e; diff --git a/plugins/ilert/src/hooks/useOnCallSchedules.ts b/plugins/ilert/src/hooks/useOnCallSchedules.ts index 5e0538a370..ce76a0770c 100644 --- a/plugins/ilert/src/hooks/useOnCallSchedules.ts +++ b/plugins/ilert/src/hooks/useOnCallSchedules.ts @@ -14,8 +14,9 @@ * limitations under the License. */ import React from 'react'; -import { ilertApiRef, UnauthorizedError } from '../api'; +import { ilertApiRef } from '../api'; import { useApi, errorApiRef } from '@backstage/core'; +import { AuthenticationError } from '@backstage/errors'; import { useAsyncRetry } from 'react-use'; import { Schedule } from '../types'; @@ -36,7 +37,7 @@ export const useOnCallSchedules = () => { setIsLoading(false); } catch (e) { setIsLoading(false); - if (!(e instanceof UnauthorizedError)) { + if (!(e instanceof AuthenticationError)) { errorApi.post(e); } throw e; diff --git a/plugins/ilert/src/hooks/useShiftOverride.ts b/plugins/ilert/src/hooks/useShiftOverride.ts index fd1da7423b..136d20d286 100644 --- a/plugins/ilert/src/hooks/useShiftOverride.ts +++ b/plugins/ilert/src/hooks/useShiftOverride.ts @@ -14,8 +14,9 @@ * limitations under the License. */ import React from 'react'; -import { ilertApiRef, UnauthorizedError } from '../api'; +import { ilertApiRef } from '../api'; import { useApi, errorApiRef } from '@backstage/core'; +import { AuthenticationError } from '@backstage/errors'; import { useAsyncRetry } from 'react-use'; import { User, Shift } from '../types'; @@ -38,7 +39,7 @@ export const useShiftOverride = (s: Shift, isModalOpened: boolean) => { setIsLoading(false); } catch (e) { setIsLoading(false); - if (!(e instanceof UnauthorizedError)) { + if (!(e instanceof AuthenticationError)) { errorApi.post(e); } throw e; diff --git a/plugins/ilert/src/hooks/useUptimeMonitors.ts b/plugins/ilert/src/hooks/useUptimeMonitors.ts index 02cd5aaa2f..fa1576642a 100644 --- a/plugins/ilert/src/hooks/useUptimeMonitors.ts +++ b/plugins/ilert/src/hooks/useUptimeMonitors.ts @@ -14,8 +14,9 @@ * limitations under the License. */ import React from 'react'; -import { ilertApiRef, TableState, UnauthorizedError } from '../api'; +import { ilertApiRef, TableState } from '../api'; import { useApi, errorApiRef } from '@backstage/core'; +import { AuthenticationError } from '@backstage/errors'; import { useAsyncRetry } from 'react-use'; import { UptimeMonitor } from '../types'; @@ -40,7 +41,7 @@ export const useUptimeMonitors = () => { setIsLoading(false); } catch (e) { setIsLoading(false); - if (!(e instanceof UnauthorizedError)) { + if (!(e instanceof AuthenticationError)) { errorApi.post(e); } throw e;