rename all incident entities to alert
Signed-off-by: Marko Simon <marko@ilert.com>
This commit is contained in:
@@ -13,30 +13,30 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { AuthenticationError, ResponseError } from '@backstage/errors';
|
||||
import {
|
||||
ConfigApi,
|
||||
createApiRef,
|
||||
DiscoveryApi,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { AuthenticationError, ResponseError } from '@backstage/errors';
|
||||
import { DateTime as dt } from 'luxon';
|
||||
import {
|
||||
Alert,
|
||||
AlertAction,
|
||||
AlertResponder,
|
||||
AlertSource,
|
||||
EscalationPolicy,
|
||||
Incident,
|
||||
IncidentAction,
|
||||
IncidentResponder,
|
||||
OnCall,
|
||||
Schedule,
|
||||
UptimeMonitor,
|
||||
User,
|
||||
} from '../types';
|
||||
import {
|
||||
ILertApi,
|
||||
GetIncidentsOpts,
|
||||
GetIncidentsCountOpts,
|
||||
EventRequest,
|
||||
GetAlertsCountOpts,
|
||||
GetAlertsOpts,
|
||||
ILertApi,
|
||||
} from './types';
|
||||
import { DateTime as dt } from 'luxon';
|
||||
import {
|
||||
ConfigApi,
|
||||
createApiRef,
|
||||
DiscoveryApi,
|
||||
} from '@backstage/core-plugin-api';
|
||||
|
||||
/** @public */
|
||||
export const ilertApiRef = createApiRef<ILertApi>({
|
||||
@@ -102,7 +102,7 @@ export class ILertClient implements ILertApi {
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
async fetchIncidents(opts?: GetIncidentsOpts): Promise<Incident[]> {
|
||||
async fetchAlerts(opts?: GetAlertsOpts): Promise<Alert[]> {
|
||||
const init = {
|
||||
headers: JSON_HEADERS,
|
||||
};
|
||||
@@ -126,15 +126,12 @@ export class ILertClient implements ILertApi {
|
||||
query.append('state', state);
|
||||
});
|
||||
}
|
||||
const response = await this.fetch(
|
||||
`/api/v1/incidents?${query.toString()}`,
|
||||
init,
|
||||
);
|
||||
const response = await this.fetch(`/api/alerts?${query.toString()}`, init);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
async fetchIncidentsCount(opts?: GetIncidentsCountOpts): Promise<number> {
|
||||
async fetchAlertsCount(opts?: GetAlertsCountOpts): Promise<number> {
|
||||
const init = {
|
||||
headers: JSON_HEADERS,
|
||||
};
|
||||
@@ -145,96 +142,85 @@ export class ILertClient implements ILertApi {
|
||||
});
|
||||
}
|
||||
const response = await this.fetch(
|
||||
`/api/v1/incidents/count?${query.toString()}`,
|
||||
`/api/alerts/count?${query.toString()}`,
|
||||
init,
|
||||
);
|
||||
|
||||
return response && response.count ? response.count : 0;
|
||||
}
|
||||
|
||||
async fetchIncident(id: number): Promise<Incident> {
|
||||
async fetchAlert(id: number): Promise<Alert> {
|
||||
const init = {
|
||||
headers: JSON_HEADERS,
|
||||
};
|
||||
|
||||
const response = await this.fetch(
|
||||
`/api/v1/incidents/${encodeURIComponent(id)}`,
|
||||
`/api/alerts/${encodeURIComponent(id)}`,
|
||||
init,
|
||||
);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
async fetchIncidentResponders(
|
||||
incident: Incident,
|
||||
): Promise<IncidentResponder[]> {
|
||||
async fetchAlertResponders(alert: Alert): Promise<AlertResponder[]> {
|
||||
const init = {
|
||||
headers: JSON_HEADERS,
|
||||
};
|
||||
|
||||
const response = await this.fetch(
|
||||
`/api/v1/incidents/${encodeURIComponent(incident.id)}/responders`,
|
||||
`/api/alerts/${encodeURIComponent(alert.id)}/responders`,
|
||||
init,
|
||||
);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
async fetchIncidentActions(incident: Incident): Promise<IncidentAction[]> {
|
||||
async fetchAlertActions(alert: Alert): Promise<AlertAction[]> {
|
||||
const init = {
|
||||
headers: JSON_HEADERS,
|
||||
};
|
||||
|
||||
const response = await this.fetch(
|
||||
`/api/v1/incidents/${encodeURIComponent(incident.id)}/actions`,
|
||||
`/api/alerts/${encodeURIComponent(alert.id)}/actions`,
|
||||
init,
|
||||
);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
async acceptIncident(
|
||||
incident: Incident,
|
||||
userName: string,
|
||||
): Promise<Incident> {
|
||||
async acceptAlert(alert: Alert, userName: string): Promise<Alert> {
|
||||
const init = {
|
||||
method: 'POST',
|
||||
headers: JSON_HEADERS,
|
||||
body: JSON.stringify({
|
||||
apiKey: incident.alertSource?.integrationKey || '',
|
||||
incidentKey: incident.incidentKey,
|
||||
apiKey: alert.alertSource?.integrationKey || '',
|
||||
alertKey: alert.alertKey,
|
||||
summary: `from ${userName} via Backstage plugin`,
|
||||
eventType: 'ACCEPT',
|
||||
}),
|
||||
};
|
||||
|
||||
await this.fetch('/api/v1/events', init);
|
||||
return this.fetchIncident(incident.id);
|
||||
await this.fetch('/api/events', init);
|
||||
return this.fetchAlert(alert.id);
|
||||
}
|
||||
|
||||
async resolveIncident(
|
||||
incident: Incident,
|
||||
userName: string,
|
||||
): Promise<Incident> {
|
||||
async resolveAlert(alert: Alert, userName: string): Promise<Alert> {
|
||||
const init = {
|
||||
method: 'POST',
|
||||
headers: JSON_HEADERS,
|
||||
body: JSON.stringify({
|
||||
apiKey: incident.alertSource?.integrationKey || '',
|
||||
incidentKey: incident.incidentKey,
|
||||
apiKey: alert.alertSource?.integrationKey || '',
|
||||
alertKey: alert.alertKey,
|
||||
summary: `from ${userName} via Backstage plugin`,
|
||||
eventType: 'RESOLVE',
|
||||
}),
|
||||
};
|
||||
|
||||
await this.fetch('/api/v1/events', init);
|
||||
return this.fetchIncident(incident.id);
|
||||
await this.fetch('/api/events', init);
|
||||
return this.fetchAlert(alert.id);
|
||||
}
|
||||
|
||||
async assignIncident(
|
||||
incident: Incident,
|
||||
responder: IncidentResponder,
|
||||
): Promise<Incident> {
|
||||
async assignAlert(alert: Alert, responder: AlertResponder): Promise<Alert> {
|
||||
const init = {
|
||||
method: 'PUT',
|
||||
headers: JSON_HEADERS,
|
||||
@@ -254,19 +240,14 @@ export class ILertClient implements ILertApi {
|
||||
}
|
||||
|
||||
const response = await this.fetch(
|
||||
`/api/v1/incidents/${encodeURIComponent(
|
||||
incident.id,
|
||||
)}/assign?${query.toString()}`,
|
||||
`/api/alerts/${encodeURIComponent(alert.id)}/assign?${query.toString()}`,
|
||||
init,
|
||||
);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
async triggerIncidentAction(
|
||||
incident: Incident,
|
||||
action: IncidentAction,
|
||||
): Promise<void> {
|
||||
async triggerAlertAction(alert: Alert, action: AlertAction): Promise<void> {
|
||||
const init = {
|
||||
method: 'POST',
|
||||
headers: JSON_HEADERS,
|
||||
@@ -279,12 +260,12 @@ export class ILertClient implements ILertApi {
|
||||
};
|
||||
|
||||
await this.fetch(
|
||||
`/api/v1/incidents/${encodeURIComponent(incident.id)}/actions`,
|
||||
`/api/alerts/${encodeURIComponent(alert.id)}/actions`,
|
||||
init,
|
||||
);
|
||||
}
|
||||
|
||||
async createIncident(eventRequest: EventRequest): Promise<boolean> {
|
||||
async createAlert(eventRequest: EventRequest): Promise<boolean> {
|
||||
const init = {
|
||||
method: 'POST',
|
||||
headers: JSON_HEADERS,
|
||||
@@ -305,7 +286,7 @@ export class ILertClient implements ILertApi {
|
||||
}),
|
||||
};
|
||||
|
||||
const response = await this.fetch('/api/v1/events', init);
|
||||
const response = await this.fetch('/api/events', init);
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -314,7 +295,7 @@ export class ILertClient implements ILertApi {
|
||||
headers: JSON_HEADERS,
|
||||
};
|
||||
|
||||
const response = await this.fetch('/api/v1/uptime-monitors', init);
|
||||
const response = await this.fetch('/api/uptime-monitors', init);
|
||||
|
||||
return response;
|
||||
}
|
||||
@@ -325,7 +306,7 @@ export class ILertClient implements ILertApi {
|
||||
};
|
||||
|
||||
const response: UptimeMonitor = await this.fetch(
|
||||
`/api/v1/uptime-monitors/${encodeURIComponent(id)}`,
|
||||
`/api/uptime-monitors/${encodeURIComponent(id)}`,
|
||||
init,
|
||||
);
|
||||
|
||||
@@ -342,7 +323,7 @@ export class ILertClient implements ILertApi {
|
||||
};
|
||||
|
||||
const response = await this.fetch(
|
||||
`/api/v1/uptime-monitors/${encodeURIComponent(uptimeMonitor.id)}`,
|
||||
`/api/uptime-monitors/${encodeURIComponent(uptimeMonitor.id)}`,
|
||||
init,
|
||||
);
|
||||
|
||||
@@ -359,7 +340,7 @@ export class ILertClient implements ILertApi {
|
||||
};
|
||||
|
||||
const response = await this.fetch(
|
||||
`/api/v1/uptime-monitors/${encodeURIComponent(uptimeMonitor.id)}`,
|
||||
`/api/uptime-monitors/${encodeURIComponent(uptimeMonitor.id)}`,
|
||||
init,
|
||||
);
|
||||
|
||||
@@ -371,7 +352,7 @@ export class ILertClient implements ILertApi {
|
||||
headers: JSON_HEADERS,
|
||||
};
|
||||
|
||||
const response = await this.fetch('/api/v1/alert-sources', init);
|
||||
const response = await this.fetch('/api/alert-sources', init);
|
||||
|
||||
return response;
|
||||
}
|
||||
@@ -384,7 +365,7 @@ export class ILertClient implements ILertApi {
|
||||
};
|
||||
|
||||
const response = await this.fetch(
|
||||
`/api/v1/alert-sources/${encodeURIComponent(idOrIntegrationKey)}`,
|
||||
`/api/alert-sources/${encodeURIComponent(idOrIntegrationKey)}`,
|
||||
init,
|
||||
);
|
||||
|
||||
@@ -397,7 +378,7 @@ export class ILertClient implements ILertApi {
|
||||
};
|
||||
|
||||
const response = await this.fetch(
|
||||
`/api/v1/on-calls?policies=${encodeURIComponent(
|
||||
`/api/on-calls?policies=${encodeURIComponent(
|
||||
alertSource.escalationPolicy.id,
|
||||
)}&expand=user&expand=escalationPolicy&timezone=${dt.local().zoneName}`,
|
||||
init,
|
||||
@@ -414,7 +395,7 @@ export class ILertClient implements ILertApi {
|
||||
};
|
||||
|
||||
const response = await this.fetch(
|
||||
`/api/v1/alert-sources/${encodeURIComponent(alertSource.id)}`,
|
||||
`/api/alert-sources/${encodeURIComponent(alertSource.id)}`,
|
||||
init,
|
||||
);
|
||||
|
||||
@@ -429,7 +410,7 @@ export class ILertClient implements ILertApi {
|
||||
};
|
||||
|
||||
const response = await this.fetch(
|
||||
`/api/v1/alert-sources/${encodeURIComponent(alertSource.id)}`,
|
||||
`/api/alert-sources/${encodeURIComponent(alertSource.id)}`,
|
||||
init,
|
||||
);
|
||||
|
||||
@@ -453,7 +434,7 @@ export class ILertClient implements ILertApi {
|
||||
}),
|
||||
};
|
||||
|
||||
const response = await this.fetch('/api/v1/maintenance-windows', init);
|
||||
const response = await this.fetch('/api/maintenance-windows', init);
|
||||
|
||||
return response;
|
||||
}
|
||||
@@ -463,7 +444,7 @@ export class ILertClient implements ILertApi {
|
||||
headers: JSON_HEADERS,
|
||||
};
|
||||
|
||||
const response = await this.fetch('/api/v1/schedules', init);
|
||||
const response = await this.fetch('/api/schedules', init);
|
||||
|
||||
return response;
|
||||
}
|
||||
@@ -473,7 +454,7 @@ export class ILertClient implements ILertApi {
|
||||
headers: JSON_HEADERS,
|
||||
};
|
||||
|
||||
const response = await this.fetch('/api/v1/users', init);
|
||||
const response = await this.fetch('/api/users', init);
|
||||
|
||||
return response;
|
||||
}
|
||||
@@ -491,17 +472,15 @@ export class ILertClient implements ILertApi {
|
||||
};
|
||||
|
||||
const response = await this.fetch(
|
||||
`/api/v1/schedules/${encodeURIComponent(scheduleId)}/overrides`,
|
||||
`/api/schedules/${encodeURIComponent(scheduleId)}/overrides`,
|
||||
init,
|
||||
);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
getIncidentDetailsURL(incident: Incident): string {
|
||||
return `${this.baseUrl}/incident/view.jsf?id=${encodeURIComponent(
|
||||
incident.id,
|
||||
)}`;
|
||||
getAlertDetailsURL(alert: Alert): string {
|
||||
return `${this.baseUrl}/alert/view.jsf?id=${encodeURIComponent(alert.id)}`;
|
||||
}
|
||||
|
||||
getAlertSourceDetailsURL(alertSource: AlertSource | null): string {
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { ILertClient, ilertApiRef } from './client';
|
||||
export { ilertApiRef, ILertClient } from './client';
|
||||
export type {
|
||||
ILertApi,
|
||||
EventRequest,
|
||||
GetIncidentsCountOpts,
|
||||
GetIncidentsOpts,
|
||||
GetAlertsCountOpts,
|
||||
GetAlertsOpts,
|
||||
ILertApi,
|
||||
TableState,
|
||||
} from './types';
|
||||
|
||||
@@ -15,16 +15,16 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
Alert,
|
||||
AlertAction,
|
||||
AlertResponder,
|
||||
AlertSource,
|
||||
Incident,
|
||||
User,
|
||||
IncidentStatus,
|
||||
UptimeMonitor,
|
||||
AlertStatus,
|
||||
EscalationPolicy,
|
||||
Schedule,
|
||||
IncidentResponder,
|
||||
IncidentAction,
|
||||
OnCall,
|
||||
Schedule,
|
||||
UptimeMonitor,
|
||||
User,
|
||||
} from '../types';
|
||||
|
||||
/** @public */
|
||||
@@ -34,16 +34,16 @@ export type TableState = {
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export type GetIncidentsOpts = {
|
||||
export type GetAlertsOpts = {
|
||||
maxResults?: number;
|
||||
startIndex?: number;
|
||||
states?: IncidentStatus[];
|
||||
states?: AlertStatus[];
|
||||
alertSources?: number[];
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export type GetIncidentsCountOpts = {
|
||||
states?: IncidentStatus[];
|
||||
export type GetAlertsCountOpts = {
|
||||
states?: AlertStatus[];
|
||||
};
|
||||
|
||||
/** @public */
|
||||
@@ -57,22 +57,16 @@ export type EventRequest = {
|
||||
|
||||
/** @public */
|
||||
export interface ILertApi {
|
||||
fetchIncidents(opts?: GetIncidentsOpts): Promise<Incident[]>;
|
||||
fetchIncidentsCount(opts?: GetIncidentsCountOpts): Promise<number>;
|
||||
fetchIncident(id: number): Promise<Incident>;
|
||||
fetchIncidentResponders(incident: Incident): Promise<IncidentResponder[]>;
|
||||
fetchIncidentActions(incident: Incident): Promise<IncidentAction[]>;
|
||||
acceptIncident(incident: Incident, userName: string): Promise<Incident>;
|
||||
resolveIncident(incident: Incident, userName: string): Promise<Incident>;
|
||||
assignIncident(
|
||||
incident: Incident,
|
||||
responder: IncidentResponder,
|
||||
): Promise<Incident>;
|
||||
createIncident(eventRequest: EventRequest): Promise<boolean>;
|
||||
triggerIncidentAction(
|
||||
incident: Incident,
|
||||
action: IncidentAction,
|
||||
): Promise<void>;
|
||||
fetchAlerts(opts?: GetAlertsOpts): Promise<Alert[]>;
|
||||
fetchAlertsCount(opts?: GetAlertsCountOpts): Promise<number>;
|
||||
fetchAlert(id: number): Promise<Alert>;
|
||||
fetchAlertResponders(alert: Alert): Promise<AlertResponder[]>;
|
||||
fetchAlertActions(alert: Alert): Promise<AlertAction[]>;
|
||||
acceptAlert(alert: Alert, userName: string): Promise<Alert>;
|
||||
resolveAlert(alert: Alert, userName: string): Promise<Alert>;
|
||||
assignAlert(alert: Alert, responder: AlertResponder): Promise<Alert>;
|
||||
createAlert(eventRequest: EventRequest): Promise<boolean>;
|
||||
triggerAlertAction(alert: Alert, action: AlertAction): Promise<void>;
|
||||
|
||||
fetchUptimeMonitors(): Promise<UptimeMonitor[]>;
|
||||
pauseUptimeMonitor(uptimeMonitor: UptimeMonitor): Promise<UptimeMonitor>;
|
||||
@@ -100,7 +94,7 @@ export interface ILertApi {
|
||||
end: string,
|
||||
): Promise<Schedule>;
|
||||
|
||||
getIncidentDetailsURL(incident: Incident): string;
|
||||
getAlertDetailsURL(alert: Alert): string;
|
||||
getAlertSourceDetailsURL(alertSource: AlertSource | null): string;
|
||||
getEscalationPolicyDetailsURL(escalationPolicy: EscalationPolicy): string;
|
||||
getUptimeMonitorDetailsURL(uptimeMonitor: UptimeMonitor): string;
|
||||
|
||||
+37
-39
@@ -13,42 +13,42 @@
|
||||
* 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 React from 'react';
|
||||
import { ilertApiRef } from '../../api';
|
||||
import { Incident, IncidentAction } from '../../types';
|
||||
import { IncidentAssignModal } from './IncidentAssignModal';
|
||||
import { useIncidentActions } from '../../hooks/useIncidentActions';
|
||||
import { useAlertActions } from '../../hooks/useAlertActions';
|
||||
import { Alert, AlertAction } from '../../types';
|
||||
import { AlertAssignModal } from './AlertAssignModal';
|
||||
|
||||
import { DEFAULT_NAMESPACE, parseEntityRef } from '@backstage/catalog-model';
|
||||
import { Link, Progress } from '@backstage/core-components';
|
||||
import {
|
||||
alertApiRef,
|
||||
useApi,
|
||||
identityApiRef,
|
||||
useApi,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { Progress, Link } from '@backstage/core-components';
|
||||
import { DEFAULT_NAMESPACE, parseEntityRef } from '@backstage/catalog-model';
|
||||
|
||||
export const IncidentActionsMenu = ({
|
||||
incident,
|
||||
onIncidentChanged,
|
||||
export const AlertActionsMenu = ({
|
||||
alert,
|
||||
onAlertChanged,
|
||||
setIsLoading,
|
||||
}: {
|
||||
incident: Incident;
|
||||
onIncidentChanged?: (incident: Incident) => void;
|
||||
alert: Alert;
|
||||
onAlertChanged?: (alert: Alert) => void;
|
||||
setIsLoading?: (isLoading: boolean) => void;
|
||||
}) => {
|
||||
const ilertApi = useApi(ilertApiRef);
|
||||
const alertApi = useApi(alertApiRef);
|
||||
const identityApi = useApi(identityApiRef);
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
const callback = onIncidentChanged || ((_: Incident): void => {});
|
||||
const callback = onAlertChanged || ((_: Alert): void => {});
|
||||
const setProcessing = setIsLoading || ((_: boolean): void => {});
|
||||
const [isAssignIncidentModalOpened, setIsAssignIncidentModalOpened] =
|
||||
const [isAssignAlertModalOpened, setIsAssignAlertModalOpened] =
|
||||
React.useState(false);
|
||||
|
||||
const [{ incidentActions, isLoading }] = useIncidentActions(
|
||||
incident,
|
||||
const [{ alertActions, isLoading }] = useAlertActions(
|
||||
alert,
|
||||
Boolean(anchorEl),
|
||||
);
|
||||
|
||||
@@ -70,10 +70,10 @@ export const IncidentActionsMenu = ({
|
||||
defaultKind: 'User',
|
||||
defaultNamespace: DEFAULT_NAMESPACE,
|
||||
});
|
||||
const newIncident = await ilertApi.acceptIncident(incident, userName);
|
||||
alertApi.post({ message: 'Incident accepted.' });
|
||||
const newAlert = await ilertApi.acceptAlert(alert, userName);
|
||||
alertApi.post({ message: 'Alert accepted.' });
|
||||
|
||||
callback(newIncident);
|
||||
callback(newAlert);
|
||||
setProcessing(false);
|
||||
} catch (err) {
|
||||
setProcessing(false);
|
||||
@@ -90,10 +90,10 @@ export const IncidentActionsMenu = ({
|
||||
defaultKind: 'User',
|
||||
defaultNamespace: DEFAULT_NAMESPACE,
|
||||
});
|
||||
const newIncident = await ilertApi.resolveIncident(incident, userName);
|
||||
alertApi.post({ message: 'Incident resolved.' });
|
||||
const newAlert = await ilertApi.resolveAlert(alert, userName);
|
||||
alertApi.post({ message: 'Alert resolved.' });
|
||||
|
||||
callback(newIncident);
|
||||
callback(newAlert);
|
||||
setProcessing(false);
|
||||
} catch (err) {
|
||||
setProcessing(false);
|
||||
@@ -103,15 +103,15 @@ export const IncidentActionsMenu = ({
|
||||
|
||||
const handleAssign = () => {
|
||||
handleCloseMenu();
|
||||
setIsAssignIncidentModalOpened(true);
|
||||
setIsAssignAlertModalOpened(true);
|
||||
};
|
||||
|
||||
const handleTriggerAction = (action: IncidentAction) => async () => {
|
||||
const handleTriggerAction = (action: AlertAction) => async () => {
|
||||
try {
|
||||
handleCloseMenu();
|
||||
setProcessing(true);
|
||||
await ilertApi.triggerIncidentAction(incident, action);
|
||||
alertApi.post({ message: 'Incident action triggered.' });
|
||||
await ilertApi.triggerAlertAction(alert, action);
|
||||
alertApi.post({ message: 'Alert action triggered.' });
|
||||
setProcessing(false);
|
||||
} catch (err) {
|
||||
setProcessing(false);
|
||||
@@ -119,7 +119,7 @@ export const IncidentActionsMenu = ({
|
||||
}
|
||||
};
|
||||
|
||||
const actions: React.ReactNode[] = incidentActions.map(a => {
|
||||
const actions: React.ReactNode[] = alertActions.map(a => {
|
||||
const successTrigger = a.history
|
||||
? a.history.find(h => h.success)
|
||||
: undefined;
|
||||
@@ -152,7 +152,7 @@ export const IncidentActionsMenu = ({
|
||||
<MoreVertIcon />
|
||||
</IconButton>
|
||||
<Menu
|
||||
id={`incident-actions-menu-${incident.id}`}
|
||||
id={`alert-actions-menu-${alert.id}`}
|
||||
anchorEl={anchorEl}
|
||||
keepMounted
|
||||
open={Boolean(anchorEl)}
|
||||
@@ -161,7 +161,7 @@ export const IncidentActionsMenu = ({
|
||||
style: { maxHeight: 48 * 5.5 },
|
||||
}}
|
||||
>
|
||||
{incident.status === 'PENDING' ? (
|
||||
{alert.status === 'PENDING' ? (
|
||||
<MenuItem key="ack" onClick={handleAccept}>
|
||||
<Typography variant="inherit" noWrap>
|
||||
Accept
|
||||
@@ -169,7 +169,7 @@ export const IncidentActionsMenu = ({
|
||||
</MenuItem>
|
||||
) : null}
|
||||
|
||||
{incident.status !== 'RESOLVED' ? (
|
||||
{alert.status !== 'RESOLVED' ? (
|
||||
<MenuItem key="close" onClick={handleResolve}>
|
||||
<Typography variant="inherit" noWrap>
|
||||
Resolve
|
||||
@@ -177,7 +177,7 @@ export const IncidentActionsMenu = ({
|
||||
</MenuItem>
|
||||
) : null}
|
||||
|
||||
{incident.status !== 'RESOLVED' ? (
|
||||
{alert.status !== 'RESOLVED' ? (
|
||||
<MenuItem key="assign" onClick={handleAssign}>
|
||||
<Typography variant="inherit" noWrap>
|
||||
Assign
|
||||
@@ -195,17 +195,15 @@ export const IncidentActionsMenu = ({
|
||||
|
||||
<MenuItem key="details" onClick={handleCloseMenu}>
|
||||
<Typography variant="inherit" noWrap>
|
||||
<Link to={ilertApi.getIncidentDetailsURL(incident)}>
|
||||
View in iLert
|
||||
</Link>
|
||||
<Link to={ilertApi.getAlertDetailsURL(alert)}>View in iLert</Link>
|
||||
</Typography>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<IncidentAssignModal
|
||||
incident={incident}
|
||||
setIsModalOpened={setIsAssignIncidentModalOpened}
|
||||
isModalOpened={isAssignIncidentModalOpened}
|
||||
onIncidentChanged={onIncidentChanged}
|
||||
<AlertAssignModal
|
||||
alert={alert}
|
||||
setIsModalOpened={setIsAssignAlertModalOpened}
|
||||
isModalOpened={isAssignAlertModalOpened}
|
||||
onAlertChanged={onAlertChanged}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
+32
-35
@@ -13,21 +13,21 @@
|
||||
* 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 Alert from '@material-ui/lab/Alert';
|
||||
import { alertApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import { Typography } from '@material-ui/core';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
import DialogContent from '@material-ui/core/DialogContent';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import MUIAlert from '@material-ui/lab/Alert';
|
||||
import Autocomplete from '@material-ui/lab/Autocomplete';
|
||||
import { useAssignIncident } from '../../hooks/useAssignIncident';
|
||||
import { Typography } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { ilertApiRef } from '../../api';
|
||||
import { Incident } from '../../types';
|
||||
import { alertApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import { useAssignAlert } from '../../hooks/useAssignAlert';
|
||||
import { Alert } from '../../types';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
container: {
|
||||
@@ -55,45 +55,42 @@ const useStyles = makeStyles(() => ({
|
||||
},
|
||||
}));
|
||||
|
||||
export const IncidentAssignModal = ({
|
||||
incident,
|
||||
export const AlertAssignModal = ({
|
||||
alert,
|
||||
isModalOpened,
|
||||
setIsModalOpened,
|
||||
onIncidentChanged,
|
||||
onAlertChanged,
|
||||
}: {
|
||||
incident: Incident | null;
|
||||
alert: Alert | null;
|
||||
isModalOpened: boolean;
|
||||
setIsModalOpened: (open: boolean) => void;
|
||||
onIncidentChanged?: (incident: Incident) => void;
|
||||
onAlertChanged?: (alert: Alert) => void;
|
||||
}) => {
|
||||
const [
|
||||
{ incidentRespondersList, incidentResponder, isLoading },
|
||||
{ setIsLoading, setIncidentResponder, setIncidentRespondersList },
|
||||
] = useAssignIncident(incident, isModalOpened);
|
||||
const callback = onIncidentChanged || ((_: Incident): void => {});
|
||||
{ alertRespondersList, alertResponder, isLoading },
|
||||
{ setIsLoading, setAlertResponder, setAlertRespondersList },
|
||||
] = useAssignAlert(alert, isModalOpened);
|
||||
const callback = onAlertChanged || ((_: Alert): void => {});
|
||||
const ilertApi = useApi(ilertApiRef);
|
||||
const alertApi = useApi(alertApiRef);
|
||||
const classes = useStyles();
|
||||
|
||||
const handleClose = () => {
|
||||
setIncidentRespondersList([]);
|
||||
setAlertRespondersList([]);
|
||||
setIsModalOpened(false);
|
||||
};
|
||||
|
||||
const handleAssign = () => {
|
||||
if (!incident || !incidentResponder) {
|
||||
if (!alert || !alertResponder) {
|
||||
return;
|
||||
}
|
||||
setIsLoading(true);
|
||||
setIncidentRespondersList([]);
|
||||
setAlertRespondersList([]);
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
const newIncident = await ilertApi.assignIncident(
|
||||
incident,
|
||||
incidentResponder,
|
||||
);
|
||||
callback(newIncident);
|
||||
alertApi.post({ message: 'Incident assigned.' });
|
||||
const newAlert = await ilertApi.assignAlert(alert, alertResponder);
|
||||
callback(newAlert);
|
||||
alertApi.post({ message: 'Alert assigned.' });
|
||||
} catch (err) {
|
||||
alertApi.post({ message: err, severity: 'error' });
|
||||
}
|
||||
@@ -102,33 +99,33 @@ export const IncidentAssignModal = ({
|
||||
}, 250);
|
||||
};
|
||||
|
||||
const canAssign = !!incidentResponder;
|
||||
const canAssign = !!alertResponder;
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={isModalOpened}
|
||||
onClose={handleClose}
|
||||
aria-labelledby="assign-incident-form-title"
|
||||
aria-labelledby="assign-alert-form-title"
|
||||
>
|
||||
<DialogTitle id="assign-incident-form-title">
|
||||
<DialogTitle id="assign-alert-form-title">
|
||||
Select responder to assign
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Alert severity="info">
|
||||
<MUIAlert severity="info">
|
||||
<Typography variant="body1" gutterBottom align="justify">
|
||||
This action will assign the incident to the selected responder.
|
||||
This action will assign the alert to the selected responder.
|
||||
</Typography>
|
||||
</Alert>
|
||||
</MUIAlert>
|
||||
<Autocomplete
|
||||
disabled={isLoading}
|
||||
options={incidentRespondersList}
|
||||
value={incidentResponder}
|
||||
options={alertRespondersList}
|
||||
value={alertResponder}
|
||||
classes={{
|
||||
root: classes.formControl,
|
||||
option: classes.option,
|
||||
}}
|
||||
onChange={(_event: any, newValue: any) => {
|
||||
setIncidentResponder(newValue);
|
||||
setAlertResponder(newValue);
|
||||
}}
|
||||
autoHighlight
|
||||
groupBy={option => {
|
||||
+7
-10
@@ -13,13 +13,13 @@
|
||||
* 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 { Incident } from '../../types';
|
||||
import React from 'react';
|
||||
import { ilertApiRef } from '../../api';
|
||||
import { Alert } from '../../types';
|
||||
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { Link } from '@backstage/core-components';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
link: {
|
||||
@@ -27,20 +27,17 @@ const useStyles = makeStyles({
|
||||
},
|
||||
});
|
||||
|
||||
export const IncidentLink = ({ incident }: { incident: Incident | null }) => {
|
||||
export const AlertLink = ({ alert }: { alert: Alert | null }) => {
|
||||
const ilertApi = useApi(ilertApiRef);
|
||||
const classes = useStyles();
|
||||
|
||||
if (!incident) {
|
||||
if (!alert) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Link
|
||||
className={classes.link}
|
||||
to={ilertApi.getIncidentDetailsURL(incident)}
|
||||
>
|
||||
#{incident.id}
|
||||
<Link className={classes.link} to={ilertApi.getAlertDetailsURL(alert)}>
|
||||
#{alert.id}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
+26
-26
@@ -13,27 +13,27 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { DEFAULT_NAMESPACE, parseEntityRef } from '@backstage/catalog-model';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
import DialogContent from '@material-ui/core/DialogContent';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import Autocomplete from '@material-ui/lab/Autocomplete';
|
||||
import { useNewIncident } from '../../hooks/useNewIncident';
|
||||
import { Typography } from '@material-ui/core';
|
||||
import useMediaQuery from '@material-ui/core/useMediaQuery';
|
||||
import { ilertApiRef } from '../../api';
|
||||
import { AlertSource } from '../../types';
|
||||
import {
|
||||
alertApiRef,
|
||||
identityApiRef,
|
||||
useApi,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { Typography } from '@material-ui/core';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
import DialogContent from '@material-ui/core/DialogContent';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import useMediaQuery from '@material-ui/core/useMediaQuery';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import Autocomplete from '@material-ui/lab/Autocomplete';
|
||||
import React from 'react';
|
||||
import { ilertApiRef } from '../../api';
|
||||
import { useNewAlert } from '../../hooks/useNewAlert';
|
||||
import { AlertSource } from '../../types';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
container: {
|
||||
@@ -61,23 +61,23 @@ const useStyles = makeStyles(() => ({
|
||||
},
|
||||
}));
|
||||
|
||||
export const IncidentNewModal = ({
|
||||
export const AlertNewModal = ({
|
||||
isModalOpened,
|
||||
setIsModalOpened,
|
||||
refetchIncidents,
|
||||
refetchAlerts,
|
||||
initialAlertSource,
|
||||
entityName,
|
||||
}: {
|
||||
isModalOpened: boolean;
|
||||
setIsModalOpened: (open: boolean) => void;
|
||||
refetchIncidents: () => void;
|
||||
refetchAlerts: () => void;
|
||||
initialAlertSource?: AlertSource | null;
|
||||
entityName?: string;
|
||||
}) => {
|
||||
const [
|
||||
{ alertSources, alertSource, summary, details, isLoading },
|
||||
{ setAlertSource, setSummary, setDetails, setIsLoading },
|
||||
] = useNewIncident(isModalOpened, initialAlertSource);
|
||||
] = useNewAlert(isModalOpened, initialAlertSource);
|
||||
const ilertApi = useApi(ilertApiRef);
|
||||
const alertApi = useApi(alertApiRef);
|
||||
const identityApi = useApi(identityApiRef);
|
||||
@@ -107,15 +107,15 @@ export const IncidentNewModal = ({
|
||||
defaultKind: 'User',
|
||||
defaultNamespace: DEFAULT_NAMESPACE,
|
||||
});
|
||||
await ilertApi.createIncident({
|
||||
await ilertApi.createAlert({
|
||||
integrationKey,
|
||||
summary,
|
||||
details,
|
||||
userName,
|
||||
source,
|
||||
});
|
||||
alertApi.post({ message: 'Incident created.' });
|
||||
refetchIncidents();
|
||||
alertApi.post({ message: 'Alert created.' });
|
||||
refetchAlerts();
|
||||
} catch (err) {
|
||||
alertApi.post({ message: err, severity: 'error' });
|
||||
}
|
||||
@@ -129,16 +129,16 @@ export const IncidentNewModal = ({
|
||||
<Dialog
|
||||
open={isModalOpened}
|
||||
onClose={handleClose}
|
||||
aria-labelledby="create-incident-form-title"
|
||||
aria-labelledby="create-alert-form-title"
|
||||
>
|
||||
<DialogTitle id="create-incident-form-title">
|
||||
<DialogTitle id="create-alert-form-title">
|
||||
{entityName ? (
|
||||
<div>
|
||||
This action will trigger an incident for{' '}
|
||||
This action will trigger an alert for{' '}
|
||||
<strong>"{entityName}"</strong>.
|
||||
</div>
|
||||
) : (
|
||||
'New incident'
|
||||
'New alert'
|
||||
)}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
+7
-7
@@ -13,11 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { StatusError, StatusOK } from '@backstage/core-components';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import { ACCEPTED, Incident, PENDING, RESOLVED } from '../../types';
|
||||
import { StatusError, StatusOK } from '@backstage/core-components';
|
||||
import React from 'react';
|
||||
import { ACCEPTED, Alert, PENDING, RESOLVED } from '../../types';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
denseListIcon: {
|
||||
@@ -29,19 +29,19 @@ const useStyles = makeStyles({
|
||||
},
|
||||
});
|
||||
|
||||
export const incidentStatusLabels = {
|
||||
export const alertStatusLabels = {
|
||||
[RESOLVED]: 'Resolved',
|
||||
[ACCEPTED]: 'Accepted',
|
||||
[PENDING]: 'Pending',
|
||||
} as Record<string, string>;
|
||||
|
||||
export const IncidentStatus = ({ incident }: { incident: Incident }) => {
|
||||
export const AlertStatus = ({ alert }: { alert: Alert }) => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<Tooltip title={incident.status} placement="top">
|
||||
<Tooltip title={alert.status} placement="top">
|
||||
<div className={classes.denseListIcon}>
|
||||
{incident.status === 'PENDING' ? <StatusError /> : <StatusOK />}
|
||||
{alert.status === 'PENDING' ? <StatusError /> : <StatusOK />}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
+2
-2
@@ -13,5 +13,5 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './IncidentsPage';
|
||||
export * from './IncidentsTable';
|
||||
export * from './AlertActionsMenu';
|
||||
export * from './AlertStatus';
|
||||
+26
-26
@@ -13,37 +13,37 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { AuthenticationError } from '@backstage/errors';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import AddIcon from '@material-ui/icons/Add';
|
||||
import { IncidentsTable } from './IncidentsTable';
|
||||
import { MissingAuthorizationHeaderError } from '../Errors';
|
||||
import { useIncidents } from '../../hooks/useIncidents';
|
||||
import { IncidentNewModal } from '../Incident/IncidentNewModal';
|
||||
import {
|
||||
Content,
|
||||
ContentHeader,
|
||||
SupportButton,
|
||||
ResponseErrorPanel,
|
||||
SupportButton,
|
||||
} from '@backstage/core-components';
|
||||
import { AuthenticationError } from '@backstage/errors';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import AddIcon from '@material-ui/icons/Add';
|
||||
import React from 'react';
|
||||
import { useAlerts } from '../../hooks/useAlerts';
|
||||
import { AlertNewModal } from '../Alert/AlertNewModal';
|
||||
import { MissingAuthorizationHeaderError } from '../Errors';
|
||||
import { AlertsTable } from './AlertsTable';
|
||||
|
||||
export const IncidentsPage = () => {
|
||||
export const AlertsPage = () => {
|
||||
const [
|
||||
{ tableState, states, incidents, incidentsCount, isLoading, error },
|
||||
{ tableState, states, alerts, alertsCount, isLoading, error },
|
||||
{
|
||||
onIncidentStatesChange,
|
||||
onAlertStatesChange,
|
||||
onChangePage,
|
||||
onChangeRowsPerPage,
|
||||
onIncidentChanged,
|
||||
refetchIncidents,
|
||||
onAlertChanged,
|
||||
refetchAlerts,
|
||||
setIsLoading,
|
||||
},
|
||||
] = useIncidents(true);
|
||||
] = useAlerts(true);
|
||||
|
||||
const [isModalOpened, setIsModalOpened] = React.useState(false);
|
||||
|
||||
const handleCreateNewIncidentClick = () => {
|
||||
const handleCreateNewAlertClick = () => {
|
||||
setIsModalOpened(true);
|
||||
};
|
||||
|
||||
@@ -65,32 +65,32 @@ export const IncidentsPage = () => {
|
||||
|
||||
return (
|
||||
<Content>
|
||||
<ContentHeader title="Incidents">
|
||||
<ContentHeader title="Alerts">
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
size="small"
|
||||
startIcon={<AddIcon />}
|
||||
onClick={handleCreateNewIncidentClick}
|
||||
onClick={handleCreateNewAlertClick}
|
||||
>
|
||||
Create Incident
|
||||
Create Alert
|
||||
</Button>
|
||||
<IncidentNewModal
|
||||
<AlertNewModal
|
||||
isModalOpened={isModalOpened}
|
||||
setIsModalOpened={setIsModalOpened}
|
||||
refetchIncidents={refetchIncidents}
|
||||
refetchAlerts={refetchAlerts}
|
||||
/>
|
||||
<SupportButton>
|
||||
This helps you to bring iLert into your developer portal.
|
||||
</SupportButton>
|
||||
</ContentHeader>
|
||||
<IncidentsTable
|
||||
incidents={incidents}
|
||||
incidentsCount={incidentsCount}
|
||||
<AlertsTable
|
||||
alerts={alerts}
|
||||
alertsCount={alertsCount}
|
||||
tableState={tableState}
|
||||
states={states}
|
||||
onIncidentChanged={onIncidentChanged}
|
||||
onIncidentStatesChange={onIncidentStatesChange}
|
||||
onAlertChanged={onAlertChanged}
|
||||
onAlertStatesChange={onAlertStatesChange}
|
||||
onChangePage={onChangePage}
|
||||
onChangeRowsPerPage={onChangeRowsPerPage}
|
||||
isLoading={isLoading}
|
||||
+37
-37
@@ -13,18 +13,18 @@
|
||||
* 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 { ilertApiRef, TableState } from '../../api';
|
||||
import { Incident, IncidentStatus } from '../../types';
|
||||
import { StatusChip } from './StatusChip';
|
||||
import { AlertSourceLink } from '../AlertSource/AlertSourceLink';
|
||||
import { TableTitle } from './TableTitle';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { DateTime as dt, Interval } from 'luxon';
|
||||
import humanizeDuration from 'humanize-duration';
|
||||
import { IncidentActionsMenu } from '../Incident/IncidentActionsMenu';
|
||||
import { IncidentLink } from '../Incident/IncidentLink';
|
||||
import { DateTime as dt, Interval } from 'luxon';
|
||||
import React from 'react';
|
||||
import { ilertApiRef, TableState } from '../../api';
|
||||
import { Alert, AlertStatus } from '../../types';
|
||||
import { AlertActionsMenu } from '../Alert/AlertActionsMenu';
|
||||
import { AlertLink } from '../Alert/AlertLink';
|
||||
import { AlertSourceLink } from '../AlertSource/AlertSourceLink';
|
||||
import { StatusChip } from './StatusChip';
|
||||
import { TableTitle } from './TableTitle';
|
||||
|
||||
import { Table, TableColumn } from '@backstage/core-components';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
@@ -37,27 +37,27 @@ const useStyles = makeStyles(theme => ({
|
||||
},
|
||||
}));
|
||||
|
||||
export const IncidentsTable = ({
|
||||
incidents,
|
||||
incidentsCount,
|
||||
export const AlertsTable = ({
|
||||
alerts,
|
||||
alertsCount,
|
||||
tableState,
|
||||
states,
|
||||
isLoading,
|
||||
onIncidentChanged,
|
||||
onAlertChanged,
|
||||
setIsLoading,
|
||||
onIncidentStatesChange,
|
||||
onAlertStatesChange,
|
||||
onChangePage,
|
||||
onChangeRowsPerPage,
|
||||
compact,
|
||||
}: {
|
||||
incidents: Incident[];
|
||||
incidentsCount: number;
|
||||
alerts: Alert[];
|
||||
alertsCount: number;
|
||||
tableState: TableState;
|
||||
states: IncidentStatus[];
|
||||
states: AlertStatus[];
|
||||
isLoading: boolean;
|
||||
onIncidentChanged: (incident: Incident) => void;
|
||||
onAlertChanged: (alert: Alert) => void;
|
||||
setIsLoading: (isLoading: boolean) => void;
|
||||
onIncidentStatesChange: (states: IncidentStatus[]) => void;
|
||||
onAlertStatesChange: (states: AlertStatus[]) => void;
|
||||
onChangePage: (page: number) => void;
|
||||
onChangeRowsPerPage: (pageSize: number) => void;
|
||||
compact?: boolean;
|
||||
@@ -92,14 +92,14 @@ export const IncidentsTable = ({
|
||||
highlight: true,
|
||||
cellStyle: smColumnStyle,
|
||||
headerStyle: smColumnStyle,
|
||||
render: rowData => <IncidentLink incident={rowData as Incident} />,
|
||||
render: rowData => <AlertLink alert={rowData as Alert} />,
|
||||
};
|
||||
const summaryColumn: TableColumn = {
|
||||
title: 'Summary',
|
||||
field: 'summary',
|
||||
cellStyle: !compact ? xlColumnStyle : undefined,
|
||||
headerStyle: !compact ? xlColumnStyle : undefined,
|
||||
render: rowData => <Typography>{(rowData as Incident).summary}</Typography>,
|
||||
render: rowData => <Typography>{(rowData as Alert).summary}</Typography>,
|
||||
};
|
||||
const sourceColumn: TableColumn = {
|
||||
title: 'Source',
|
||||
@@ -107,7 +107,7 @@ export const IncidentsTable = ({
|
||||
cellStyle: mdColumnStyle,
|
||||
headerStyle: mdColumnStyle,
|
||||
render: rowData => (
|
||||
<AlertSourceLink alertSource={(rowData as Incident).alertSource} />
|
||||
<AlertSourceLink alertSource={(rowData as Alert).alertSource} />
|
||||
),
|
||||
};
|
||||
const durationColumn: TableColumn = {
|
||||
@@ -118,10 +118,10 @@ export const IncidentsTable = ({
|
||||
headerStyle: smColumnStyle,
|
||||
render: rowData => (
|
||||
<Typography noWrap>
|
||||
{(rowData as Incident).status !== 'RESOLVED'
|
||||
{(rowData as Alert).status !== 'RESOLVED'
|
||||
? humanizeDuration(
|
||||
Interval.fromDateTimes(
|
||||
dt.fromISO((rowData as Incident).reportTime),
|
||||
dt.fromISO((rowData as Alert).reportTime),
|
||||
dt.now(),
|
||||
)
|
||||
.toDuration()
|
||||
@@ -130,8 +130,8 @@ export const IncidentsTable = ({
|
||||
)
|
||||
: humanizeDuration(
|
||||
Interval.fromDateTimes(
|
||||
dt.fromISO((rowData as Incident).reportTime),
|
||||
dt.fromISO((rowData as Incident).resolvedOn),
|
||||
dt.fromISO((rowData as Alert).reportTime),
|
||||
dt.fromISO((rowData as Alert).resolvedOn),
|
||||
)
|
||||
.toDuration()
|
||||
.valueOf(),
|
||||
@@ -147,7 +147,7 @@ export const IncidentsTable = ({
|
||||
headerStyle: !compact ? mdColumnStyle : lgColumnStyle,
|
||||
render: rowData => (
|
||||
<Typography noWrap>
|
||||
{ilertApi.getUserInitials((rowData as Incident).assignedTo)}
|
||||
{ilertApi.getUserInitials((rowData as Alert).assignedTo)}
|
||||
</Typography>
|
||||
),
|
||||
};
|
||||
@@ -158,7 +158,7 @@ export const IncidentsTable = ({
|
||||
headerStyle: smColumnStyle,
|
||||
render: rowData => (
|
||||
<Typography noWrap>
|
||||
{(rowData as Incident).priority === 'HIGH' ? 'High' : 'Low'}
|
||||
{(rowData as Alert).priority === 'HIGH' ? 'High' : 'Low'}
|
||||
</Typography>
|
||||
),
|
||||
};
|
||||
@@ -167,7 +167,7 @@ export const IncidentsTable = ({
|
||||
field: 'status',
|
||||
cellStyle: xsColumnStyle,
|
||||
headerStyle: xsColumnStyle,
|
||||
render: rowData => <StatusChip incident={rowData as Incident} />,
|
||||
render: rowData => <StatusChip alert={rowData as Alert} />,
|
||||
};
|
||||
const actionsColumn: TableColumn = {
|
||||
title: '',
|
||||
@@ -175,9 +175,9 @@ export const IncidentsTable = ({
|
||||
cellStyle: xsColumnStyle,
|
||||
headerStyle: xsColumnStyle,
|
||||
render: rowData => (
|
||||
<IncidentActionsMenu
|
||||
incident={rowData as Incident}
|
||||
onIncidentChanged={onIncidentChanged}
|
||||
<AlertActionsMenu
|
||||
alert={rowData as Alert}
|
||||
onAlertChanged={onAlertChanged}
|
||||
setIsLoading={setIsLoading}
|
||||
/>
|
||||
),
|
||||
@@ -236,14 +236,14 @@ export const IncidentsTable = ({
|
||||
}}
|
||||
emptyContent={
|
||||
<Typography color="textSecondary" className={classes.empty}>
|
||||
No incidents right now
|
||||
No alerts right now
|
||||
</Typography>
|
||||
}
|
||||
title={
|
||||
!compact ? (
|
||||
<TableTitle
|
||||
incidentStates={states}
|
||||
onIncidentStatesChange={onIncidentStatesChange}
|
||||
alertStates={states}
|
||||
onAlertStatesChange={onAlertStatesChange}
|
||||
/>
|
||||
) : (
|
||||
<Typography variant="button" color="textSecondary">
|
||||
@@ -252,12 +252,12 @@ export const IncidentsTable = ({
|
||||
)
|
||||
}
|
||||
page={tableState.page}
|
||||
totalCount={incidentsCount}
|
||||
totalCount={alertsCount}
|
||||
onPageChange={onChangePage}
|
||||
onRowsPerPageChange={onChangeRowsPerPage}
|
||||
// localization={{ header: { actions: undefined } }}
|
||||
columns={columns}
|
||||
data={incidents}
|
||||
data={alerts}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
);
|
||||
+6
-6
@@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { Chip, withStyles } from '@material-ui/core';
|
||||
import { Incident, PENDING, ACCEPTED, RESOLVED } from '../../types';
|
||||
import { incidentStatusLabels } from '../Incident/IncidentStatus';
|
||||
import React from 'react';
|
||||
import { ACCEPTED, Alert, PENDING, RESOLVED } from '../../types';
|
||||
import { alertStatusLabels } from '../Alert/AlertStatus';
|
||||
|
||||
const ResolvedChip = withStyles({
|
||||
root: {
|
||||
@@ -41,10 +41,10 @@ const PendingChip = withStyles({
|
||||
},
|
||||
})(Chip);
|
||||
|
||||
export const StatusChip = ({ incident }: { incident: Incident }) => {
|
||||
const label = `${incidentStatusLabels[incident.status]}`;
|
||||
export const StatusChip = ({ alert }: { alert: Alert }) => {
|
||||
const label = `${alertStatusLabels[alert.status]}`;
|
||||
|
||||
switch (incident.status) {
|
||||
switch (alert.status) {
|
||||
case RESOLVED:
|
||||
return <ResolvedChip label={label} size="small" />;
|
||||
case ACCEPTED:
|
||||
+17
-17
@@ -13,16 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { PENDING, ACCEPTED, RESOLVED, IncidentStatus } from '../../types';
|
||||
import { incidentStatusLabels } from '../Incident/IncidentStatus';
|
||||
import Checkbox from '@material-ui/core/Checkbox';
|
||||
import FormControl from '@material-ui/core/FormControl';
|
||||
import ListItemText from '@material-ui/core/ListItemText';
|
||||
import Select from '@material-ui/core/Select';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import MenuItem from '@material-ui/core/MenuItem';
|
||||
import Checkbox from '@material-ui/core/Checkbox';
|
||||
import Select from '@material-ui/core/Select';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import React from 'react';
|
||||
import { ACCEPTED, AlertStatus, PENDING, RESOLVED } from '../../types';
|
||||
import { alertStatusLabels } from '../Alert/AlertStatus';
|
||||
|
||||
const ITEM_HEIGHT = 48;
|
||||
const ITEM_PADDING_TOP = 8;
|
||||
@@ -53,15 +53,15 @@ const useStyles = makeStyles({
|
||||
});
|
||||
|
||||
export const TableTitle = ({
|
||||
incidentStates,
|
||||
onIncidentStatesChange,
|
||||
alertStates,
|
||||
onAlertStatesChange,
|
||||
}: {
|
||||
incidentStates: IncidentStatus[];
|
||||
onIncidentStatesChange: (states: IncidentStatus[]) => void;
|
||||
alertStates: AlertStatus[];
|
||||
onAlertStatesChange: (states: AlertStatus[]) => void;
|
||||
}) => {
|
||||
const classes = useStyles();
|
||||
const handleIncidentStatusSelectChange = (event: any) => {
|
||||
onIncidentStatesChange(event.target.value);
|
||||
const handleAlertStatusSelectChange = (event: any) => {
|
||||
onAlertStatesChange(event.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -75,19 +75,19 @@ export const TableTitle = ({
|
||||
size="small"
|
||||
>
|
||||
<Select
|
||||
id="incidents-status-select"
|
||||
id="alerts-status-select"
|
||||
multiple
|
||||
value={incidentStates}
|
||||
onChange={handleIncidentStatusSelectChange}
|
||||
value={alertStates}
|
||||
onChange={handleAlertStatusSelectChange}
|
||||
renderValue={(selected: any) => selected.join(', ')}
|
||||
MenuProps={MenuProps}
|
||||
>
|
||||
{[PENDING, ACCEPTED, RESOLVED].map(state => (
|
||||
<MenuItem key={state} value={state}>
|
||||
<Checkbox
|
||||
checked={incidentStates.indexOf(state as IncidentStatus) > -1}
|
||||
checked={alertStates.indexOf(state as AlertStatus) > -1}
|
||||
/>
|
||||
<ListItemText primary={incidentStatusLabels[state]} />
|
||||
<ListItemText primary={alertStatusLabels[state]} />
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
+2
-2
@@ -13,5 +13,5 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './IncidentActionsMenu';
|
||||
export * from './IncidentStatus';
|
||||
export * from './AlertsPage';
|
||||
export * from './AlertsTable';
|
||||
@@ -13,27 +13,27 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { ResponseErrorPanel } from '@backstage/core-components';
|
||||
import { AuthenticationError } from '@backstage/errors';
|
||||
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 React from 'react';
|
||||
import { ILERT_INTEGRATION_KEY_ANNOTATION } from '../../constants';
|
||||
import { MissingAuthorizationHeaderError } from '../Errors';
|
||||
import { useIncidents } from '../../hooks/useIncidents';
|
||||
import { IncidentsTable } from '../IncidentsPage';
|
||||
import { IncidentNewModal } from '../Incident/IncidentNewModal';
|
||||
import { ILertCardActionsHeader } from './ILertCardActionsHeader';
|
||||
import { useAlertSource } from '../../hooks/useAlertSource';
|
||||
import { useILertEntity } from '../../hooks';
|
||||
import { useAlerts } from '../../hooks/useAlerts';
|
||||
import { useAlertSource } from '../../hooks/useAlertSource';
|
||||
import { AlertNewModal } from '../Alert/AlertNewModal';
|
||||
import { AlertsTable } from '../AlertsPage';
|
||||
import { MissingAuthorizationHeaderError } from '../Errors';
|
||||
import { ILertCardActionsHeader } from './ILertCardActionsHeader';
|
||||
import { ILertCardEmptyState } from './ILertCardEmptyState';
|
||||
import { ILertCardHeaderStatus } from './ILertCardHeaderStatus';
|
||||
import { ILertCardMaintenanceModal } from './ILertCardMaintenanceModal';
|
||||
import { ILertCardEmptyState } from './ILertCardEmptyState';
|
||||
import { ILertCardOnCall } from './ILertCardOnCall';
|
||||
import { ResponseErrorPanel } from '@backstage/core-components';
|
||||
|
||||
/** @public */
|
||||
export const isPluginApplicableToEntity = (entity: Entity) =>
|
||||
@@ -60,18 +60,18 @@ export const ILertCard = () => {
|
||||
{ setAlertSource, refetchAlertSource },
|
||||
] = useAlertSource(integrationKey);
|
||||
const [
|
||||
{ tableState, states, incidents, incidentsCount, isLoading, error },
|
||||
{ tableState, states, alerts, alertsCount, isLoading, error },
|
||||
{
|
||||
onIncidentStatesChange,
|
||||
onAlertStatesChange,
|
||||
onChangePage,
|
||||
onChangeRowsPerPage,
|
||||
onIncidentChanged,
|
||||
refetchIncidents,
|
||||
onAlertChanged,
|
||||
refetchAlerts,
|
||||
setIsLoading,
|
||||
},
|
||||
] = useIncidents(false, true, alertSource);
|
||||
] = useAlerts(false, true, alertSource);
|
||||
|
||||
const [isNewIncidentModalOpened, setIsNewIncidentModalOpened] =
|
||||
const [isNewAlertModalOpened, setIsNewAlertModalOpened] =
|
||||
React.useState(false);
|
||||
const [isMaintenanceModalOpened, setIsMaintenanceModalOpened] =
|
||||
React.useState(false);
|
||||
@@ -97,7 +97,7 @@ export const ILertCard = () => {
|
||||
<ILertCardActionsHeader
|
||||
alertSource={alertSource}
|
||||
setAlertSource={setAlertSource}
|
||||
setIsNewIncidentModalOpened={setIsNewIncidentModalOpened}
|
||||
setIsNewAlertModalOpened={setIsNewAlertModalOpened}
|
||||
setIsMaintenanceModalOpened={setIsMaintenanceModalOpened}
|
||||
uptimeMonitor={uptimeMonitor}
|
||||
/>
|
||||
@@ -107,13 +107,13 @@ export const ILertCard = () => {
|
||||
<Divider />
|
||||
<CardContent className={classes.content}>
|
||||
<ILertCardOnCall alertSource={alertSource} />
|
||||
<IncidentsTable
|
||||
incidents={incidents}
|
||||
incidentsCount={incidentsCount}
|
||||
<AlertsTable
|
||||
alerts={alerts}
|
||||
alertsCount={alertsCount}
|
||||
tableState={tableState}
|
||||
states={states}
|
||||
onIncidentChanged={onIncidentChanged}
|
||||
onIncidentStatesChange={onIncidentStatesChange}
|
||||
onAlertChanged={onAlertChanged}
|
||||
onAlertStatesChange={onAlertStatesChange}
|
||||
onChangePage={onChangePage}
|
||||
onChangeRowsPerPage={onChangeRowsPerPage}
|
||||
isLoading={isLoading}
|
||||
@@ -122,10 +122,10 @@ export const ILertCard = () => {
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<IncidentNewModal
|
||||
isModalOpened={isNewIncidentModalOpened}
|
||||
setIsModalOpened={setIsNewIncidentModalOpened}
|
||||
refetchIncidents={refetchIncidents}
|
||||
<AlertNewModal
|
||||
isModalOpened={isNewAlertModalOpened}
|
||||
setIsModalOpened={setIsNewAlertModalOpened}
|
||||
refetchAlerts={refetchAlerts}
|
||||
initialAlertSource={alertSource}
|
||||
entityName={name}
|
||||
/>
|
||||
|
||||
@@ -13,20 +13,20 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
import DialogContent from '@material-ui/core/DialogContent';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import AlarmAddIcon from '@material-ui/icons/AlarmAdd';
|
||||
import BuildIcon from '@material-ui/icons/Build';
|
||||
import PauseIcon from '@material-ui/icons/Pause';
|
||||
import PlayArrowIcon from '@material-ui/icons/PlayArrow';
|
||||
import TimelineIcon from '@material-ui/icons/Timeline';
|
||||
import WebIcon from '@material-ui/icons/Web';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import React from 'react';
|
||||
import { ilertApiRef } from '../../api';
|
||||
import { AlertSource, UptimeMonitor } from '../../types';
|
||||
|
||||
@@ -34,18 +34,18 @@ import {
|
||||
HeaderIconLinkRow,
|
||||
IconLinkVerticalProps,
|
||||
} from '@backstage/core-components';
|
||||
import { useApi, alertApiRef } from '@backstage/core-plugin-api';
|
||||
import { alertApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
|
||||
export const ILertCardActionsHeader = ({
|
||||
alertSource,
|
||||
setAlertSource,
|
||||
setIsNewIncidentModalOpened,
|
||||
setIsNewAlertModalOpened,
|
||||
setIsMaintenanceModalOpened,
|
||||
uptimeMonitor,
|
||||
}: {
|
||||
alertSource: AlertSource | null;
|
||||
setAlertSource: (alertSource: AlertSource) => void;
|
||||
setIsNewIncidentModalOpened: (isOpen: boolean) => void;
|
||||
setIsNewAlertModalOpened: (isOpen: boolean) => void;
|
||||
setIsMaintenanceModalOpened: (isOpen: boolean) => void;
|
||||
uptimeMonitor: UptimeMonitor | null;
|
||||
}) => {
|
||||
@@ -54,8 +54,8 @@ export const ILertCardActionsHeader = ({
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
const [isDisableModalOpened, setIsDisableModalOpened] = React.useState(false);
|
||||
|
||||
const handleCreateNewIncident = () => {
|
||||
setIsNewIncidentModalOpened(true);
|
||||
const handleCreateNewAlert = () => {
|
||||
setIsNewAlertModalOpened(true);
|
||||
};
|
||||
|
||||
const handleEnableAlertSource = async () => {
|
||||
@@ -108,9 +108,9 @@ export const ILertCardActionsHeader = ({
|
||||
icon: <WebIcon />,
|
||||
};
|
||||
|
||||
const createIncidentLink: IconLinkVerticalProps = {
|
||||
label: 'Create Incident',
|
||||
onClick: handleCreateNewIncident,
|
||||
const createAlertLink: IconLinkVerticalProps = {
|
||||
label: 'Create Alert',
|
||||
onClick: handleCreateNewAlert,
|
||||
icon: <AlarmAddIcon />,
|
||||
color: 'secondary',
|
||||
disabled:
|
||||
@@ -149,7 +149,7 @@ export const ILertCardActionsHeader = ({
|
||||
|
||||
const links: IconLinkVerticalProps[] = [
|
||||
alertSourceLink,
|
||||
createIncidentLink,
|
||||
createAlertLink,
|
||||
alertSource && alertSource.active
|
||||
? disableAlertSourceLink
|
||||
: enableAlertSourceLink,
|
||||
@@ -178,7 +178,7 @@ export const ILertCardActionsHeader = ({
|
||||
<Alert severity="info">
|
||||
<Typography variant="body1" align="justify">
|
||||
Do you really want to disable this alert source? A disabled alert
|
||||
source cannot create new incidents.
|
||||
source cannot create new alerts.
|
||||
</Typography>
|
||||
</Alert>
|
||||
</DialogContent>
|
||||
|
||||
@@ -13,24 +13,24 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { IncidentsPage } from '../IncidentsPage';
|
||||
import { UptimeMonitorsPage } from '../UptimeMonitorsPage';
|
||||
import { OnCallSchedulesPage } from '../OnCallSchedulesPage';
|
||||
import {
|
||||
Page,
|
||||
Header,
|
||||
HeaderTabs,
|
||||
HeaderLabel,
|
||||
Content,
|
||||
Header,
|
||||
HeaderLabel,
|
||||
HeaderTabs,
|
||||
Page,
|
||||
} from '@backstage/core-components';
|
||||
import React from 'react';
|
||||
import { AlertsPage } from '../AlertsPage';
|
||||
import { OnCallSchedulesPage } from '../OnCallSchedulesPage';
|
||||
import { UptimeMonitorsPage } from '../UptimeMonitorsPage';
|
||||
|
||||
/** @public */
|
||||
export const ILertPage = () => {
|
||||
const [selectedTab, setSelectedTab] = React.useState<number>(0);
|
||||
const tabs = [
|
||||
{ label: 'Who is on call?' },
|
||||
{ label: 'Incidents' },
|
||||
{ label: 'Alerts' },
|
||||
{ label: 'Uptime Monitors' },
|
||||
];
|
||||
const renderTab = () => {
|
||||
@@ -38,7 +38,7 @@ export const ILertPage = () => {
|
||||
case 0:
|
||||
return <OnCallSchedulesPage />;
|
||||
case 1:
|
||||
return <IncidentsPage />;
|
||||
return <AlertsPage />;
|
||||
case 2:
|
||||
return <UptimeMonitorsPage />;
|
||||
default:
|
||||
|
||||
+14
-17
@@ -13,48 +13,45 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { ilertApiRef } from '../api';
|
||||
import { errorApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import { AuthenticationError } from '@backstage/errors';
|
||||
import React from 'react';
|
||||
import useAsyncRetry from 'react-use/lib/useAsyncRetry';
|
||||
import { Incident, IncidentAction } from '../types';
|
||||
import { useApi, errorApiRef } from '@backstage/core-plugin-api';
|
||||
import { ilertApiRef } from '../api';
|
||||
import { Alert, AlertAction } from '../types';
|
||||
|
||||
export const useIncidentActions = (
|
||||
incident: Incident | null,
|
||||
open: boolean,
|
||||
) => {
|
||||
export const useAlertActions = (alert: Alert | null, open: boolean) => {
|
||||
const ilertApi = useApi(ilertApiRef);
|
||||
const errorApi = useApi(errorApiRef);
|
||||
|
||||
const [incidentActionsList, setIncidentActionsList] = React.useState<
|
||||
IncidentAction[]
|
||||
>([]);
|
||||
const [alertActionsList, setAlertActionsList] = React.useState<AlertAction[]>(
|
||||
[],
|
||||
);
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
|
||||
const { error, retry } = useAsyncRetry(async () => {
|
||||
try {
|
||||
if (!incident || !open) {
|
||||
if (!alert || !open) {
|
||||
return;
|
||||
}
|
||||
const data = await ilertApi.fetchIncidentActions(incident);
|
||||
setIncidentActionsList(data);
|
||||
const data = await ilertApi.fetchAlertActions(alert);
|
||||
setAlertActionsList(data);
|
||||
} catch (e) {
|
||||
if (!(e instanceof AuthenticationError)) {
|
||||
errorApi.post(e);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}, [incident, open]);
|
||||
}, [alert, open]);
|
||||
|
||||
return [
|
||||
{
|
||||
incidentActions: incidentActionsList,
|
||||
alertActions: alertActionsList,
|
||||
error,
|
||||
isLoading,
|
||||
},
|
||||
{
|
||||
setIncidentActionsList,
|
||||
setAlertActionsList,
|
||||
setIsLoading,
|
||||
retry,
|
||||
},
|
||||
@@ -13,12 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { ilertApiRef } from '../api';
|
||||
import { errorApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import { AuthenticationError } from '@backstage/errors';
|
||||
import React from 'react';
|
||||
import useAsyncRetry from 'react-use/lib/useAsyncRetry';
|
||||
import { ilertApiRef } from '../api';
|
||||
import { AlertSource, UptimeMonitor } from '../types';
|
||||
import { useApi, errorApiRef } from '@backstage/core-plugin-api';
|
||||
|
||||
export const useAlertSource = (integrationKey: string) => {
|
||||
const ilertApi = useApi(ilertApiRef);
|
||||
|
||||
@@ -13,12 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { ilertApiRef } from '../api';
|
||||
import { errorApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import { AuthenticationError } from '@backstage/errors';
|
||||
import React from 'react';
|
||||
import useAsyncRetry from 'react-use/lib/useAsyncRetry';
|
||||
import { ilertApiRef } from '../api';
|
||||
import { AlertSource, OnCall } from '../types';
|
||||
import { useApi, errorApiRef } from '@backstage/core-plugin-api';
|
||||
|
||||
export const useAlertSourceOnCalls = (alertSource?: AlertSource | null) => {
|
||||
const ilertApi = useApi(ilertApiRef);
|
||||
|
||||
@@ -13,20 +13,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { GetIncidentsOpts, ilertApiRef, TableState } from '../api';
|
||||
import { errorApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import { AuthenticationError } from '@backstage/errors';
|
||||
import React from 'react';
|
||||
import useAsyncRetry from 'react-use/lib/useAsyncRetry';
|
||||
import {
|
||||
ACCEPTED,
|
||||
PENDING,
|
||||
Incident,
|
||||
IncidentStatus,
|
||||
AlertSource,
|
||||
} from '../types';
|
||||
import { useApi, errorApiRef } from '@backstage/core-plugin-api';
|
||||
import { GetAlertsOpts, ilertApiRef, TableState } from '../api';
|
||||
import { ACCEPTED, Alert, AlertSource, AlertStatus, PENDING } from '../types';
|
||||
|
||||
export const useIncidents = (
|
||||
export const useAlerts = (
|
||||
paging: boolean,
|
||||
singleSource?: boolean,
|
||||
alertSource?: AlertSource | null,
|
||||
@@ -38,21 +32,21 @@ export const useIncidents = (
|
||||
page: 0,
|
||||
pageSize: 10,
|
||||
});
|
||||
const [states, setStates] = React.useState<IncidentStatus[]>([
|
||||
const [states, setStates] = React.useState<AlertStatus[]>([
|
||||
ACCEPTED,
|
||||
PENDING,
|
||||
]);
|
||||
const [incidentsList, setIncidentsList] = React.useState<Incident[]>([]);
|
||||
const [incidentsCount, setIncidentsCount] = React.useState(0);
|
||||
const [alertsList, setAlertsList] = React.useState<Alert[]>([]);
|
||||
const [alertsCount, setAlertsCount] = React.useState(0);
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
|
||||
const fetchIncidentsCall = async () => {
|
||||
const fetchAlertsCall = async () => {
|
||||
try {
|
||||
if (singleSource && !alertSource) {
|
||||
return;
|
||||
}
|
||||
setIsLoading(true);
|
||||
const opts: GetIncidentsOpts = {
|
||||
const opts: GetAlertsOpts = {
|
||||
states,
|
||||
alertSources: alertSource ? [alertSource.id] : [],
|
||||
};
|
||||
@@ -60,8 +54,8 @@ export const useIncidents = (
|
||||
opts.maxResults = tableState.pageSize;
|
||||
opts.startIndex = tableState.page * tableState.pageSize;
|
||||
}
|
||||
const data = await ilertApi.fetchIncidents(opts);
|
||||
setIncidentsList(data || []);
|
||||
const data = await ilertApi.fetchAlerts(opts);
|
||||
setAlertsList(data || []);
|
||||
setIsLoading(false);
|
||||
} catch (e) {
|
||||
if (!(e instanceof AuthenticationError)) {
|
||||
@@ -72,10 +66,10 @@ export const useIncidents = (
|
||||
}
|
||||
};
|
||||
|
||||
const fetchIncidentsCountCall = async () => {
|
||||
const fetchAlertsCountCall = async () => {
|
||||
try {
|
||||
const count = await ilertApi.fetchIncidentsCount({ states });
|
||||
setIncidentsCount(count || 0);
|
||||
const count = await ilertApi.fetchAlertsCount({ states });
|
||||
setAlertsCount(count || 0);
|
||||
} catch (e) {
|
||||
if (!(e instanceof AuthenticationError)) {
|
||||
errorApi.post(e);
|
||||
@@ -83,44 +77,44 @@ export const useIncidents = (
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
const fetchIncidents = useAsyncRetry(fetchIncidentsCall, [
|
||||
const fetchAlerts = useAsyncRetry(fetchAlertsCall, [
|
||||
tableState,
|
||||
states,
|
||||
singleSource,
|
||||
alertSource,
|
||||
]);
|
||||
|
||||
const refetchIncidents = () => {
|
||||
const refetchAlerts = () => {
|
||||
setTableState({ ...tableState, page: 0 });
|
||||
Promise.all([fetchIncidentsCall(), fetchIncidentsCountCall()]);
|
||||
Promise.all([fetchAlertsCall(), fetchAlertsCountCall()]);
|
||||
};
|
||||
|
||||
const fetchIncidentsCount = useAsyncRetry(fetchIncidentsCountCall, [states]);
|
||||
const fetchAlertsCount = useAsyncRetry(fetchAlertsCountCall, [states]);
|
||||
|
||||
const error = fetchIncidents.error || fetchIncidentsCount.error;
|
||||
const error = fetchAlerts.error || fetchAlertsCount.error;
|
||||
const retry = () => {
|
||||
fetchIncidents.retry();
|
||||
fetchIncidentsCount.retry();
|
||||
fetchAlerts.retry();
|
||||
fetchAlertsCount.retry();
|
||||
};
|
||||
|
||||
const onIncidentChanged = (newIncident: Incident) => {
|
||||
let shouldRefetchIncidents = false;
|
||||
setIncidentsList(
|
||||
incidentsList.reduce((acc: Incident[], incident: Incident) => {
|
||||
if (newIncident.id === incident.id) {
|
||||
if (states.includes(newIncident.status)) {
|
||||
acc.push(newIncident);
|
||||
const onAlertChanged = (newAlert: Alert) => {
|
||||
let shouldRefetchAlerts = false;
|
||||
setAlertsList(
|
||||
alertsList.reduce((acc: Alert[], alert: Alert) => {
|
||||
if (newAlert.id === alert.id) {
|
||||
if (states.includes(newAlert.status)) {
|
||||
acc.push(newAlert);
|
||||
} else {
|
||||
shouldRefetchIncidents = true;
|
||||
shouldRefetchAlerts = true;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
acc.push(incident);
|
||||
acc.push(alert);
|
||||
return acc;
|
||||
}, []),
|
||||
);
|
||||
if (shouldRefetchIncidents) {
|
||||
refetchIncidents();
|
||||
if (shouldRefetchAlerts) {
|
||||
refetchAlerts();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -130,7 +124,7 @@ export const useIncidents = (
|
||||
const onChangeRowsPerPage = (p: number) => {
|
||||
setTableState({ ...tableState, pageSize: p });
|
||||
};
|
||||
const onIncidentStatesChange = (s: IncidentStatus[]) => {
|
||||
const onAlertStatesChange = (s: AlertStatus[]) => {
|
||||
setStates(s);
|
||||
};
|
||||
|
||||
@@ -138,22 +132,22 @@ export const useIncidents = (
|
||||
{
|
||||
tableState,
|
||||
states,
|
||||
incidents: incidentsList,
|
||||
incidentsCount,
|
||||
alerts: alertsList,
|
||||
alertsCount,
|
||||
error,
|
||||
isLoading,
|
||||
},
|
||||
{
|
||||
setTableState,
|
||||
setStates,
|
||||
setIncidentsList,
|
||||
setAlertsList,
|
||||
setIsLoading,
|
||||
retry,
|
||||
onIncidentChanged,
|
||||
refetchIncidents,
|
||||
onAlertChanged,
|
||||
refetchAlerts,
|
||||
onChangePage,
|
||||
onChangeRowsPerPage,
|
||||
onIncidentStatesChange,
|
||||
onAlertStatesChange,
|
||||
},
|
||||
] as const;
|
||||
};
|
||||
+17
-17
@@ -13,30 +13,30 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { ilertApiRef } from '../api';
|
||||
import { errorApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import { AuthenticationError } from '@backstage/errors';
|
||||
import React from 'react';
|
||||
import useAsyncRetry from 'react-use/lib/useAsyncRetry';
|
||||
import { Incident, IncidentResponder } from '../types';
|
||||
import { useApi, errorApiRef } from '@backstage/core-plugin-api';
|
||||
import { ilertApiRef } from '../api';
|
||||
import { Alert, AlertResponder } from '../types';
|
||||
|
||||
export const useAssignIncident = (incident: Incident | null, open: boolean) => {
|
||||
export const useAssignAlert = (alert: Alert | null, open: boolean) => {
|
||||
const ilertApi = useApi(ilertApiRef);
|
||||
const errorApi = useApi(errorApiRef);
|
||||
|
||||
const [incidentRespondersList, setIncidentRespondersList] = React.useState<
|
||||
IncidentResponder[]
|
||||
const [alertRespondersList, setAlertRespondersList] = React.useState<
|
||||
AlertResponder[]
|
||||
>([]);
|
||||
const [incidentResponder, setIncidentResponder] =
|
||||
React.useState<IncidentResponder | null>(null);
|
||||
const [alertResponder, setAlertResponder] =
|
||||
React.useState<AlertResponder | null>(null);
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
|
||||
const { error, retry } = useAsyncRetry(async () => {
|
||||
try {
|
||||
if (!incident || !open) {
|
||||
if (!alert || !open) {
|
||||
return;
|
||||
}
|
||||
const data = await ilertApi.fetchIncidentResponders(incident);
|
||||
const data = await ilertApi.fetchAlertResponders(alert);
|
||||
if (data && Array.isArray(data)) {
|
||||
const groups = [
|
||||
'SUGGESTED',
|
||||
@@ -45,7 +45,7 @@ export const useAssignIncident = (incident: Incident | null, open: boolean) => {
|
||||
'ON_CALL_SCHEDULE',
|
||||
];
|
||||
data.sort((a, b) => groups.indexOf(a.group) - groups.indexOf(b.group));
|
||||
setIncidentRespondersList(data);
|
||||
setAlertRespondersList(data);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!(e instanceof AuthenticationError)) {
|
||||
@@ -53,18 +53,18 @@ export const useAssignIncident = (incident: Incident | null, open: boolean) => {
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}, [incident, open]);
|
||||
}, [alert, open]);
|
||||
|
||||
return [
|
||||
{
|
||||
incidentRespondersList,
|
||||
incidentResponder,
|
||||
alertRespondersList,
|
||||
alertResponder,
|
||||
error,
|
||||
isLoading,
|
||||
},
|
||||
{
|
||||
setIncidentRespondersList,
|
||||
setIncidentResponder,
|
||||
setAlertRespondersList,
|
||||
setAlertResponder,
|
||||
setIsLoading,
|
||||
retry,
|
||||
},
|
||||
@@ -13,14 +13,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { ilertApiRef } from '../api';
|
||||
import { errorApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import { AuthenticationError } from '@backstage/errors';
|
||||
import React from 'react';
|
||||
import useAsyncRetry from 'react-use/lib/useAsyncRetry';
|
||||
import { ilertApiRef } from '../api';
|
||||
import { AlertSource } from '../types';
|
||||
import { useApi, errorApiRef } from '@backstage/core-plugin-api';
|
||||
|
||||
export const useNewIncident = (
|
||||
export const useNewAlert = (
|
||||
open: boolean,
|
||||
initialAlertSource?: AlertSource | null,
|
||||
) => {
|
||||
+22
-22
@@ -15,15 +15,15 @@
|
||||
*/
|
||||
|
||||
/** @public */
|
||||
export interface Incident {
|
||||
export interface Alert {
|
||||
id: number;
|
||||
summary: string;
|
||||
details: string;
|
||||
reportTime: string;
|
||||
resolvedOn: string;
|
||||
status: IncidentStatus;
|
||||
priority: IncidentPriority;
|
||||
incidentKey: string;
|
||||
status: AlertStatus;
|
||||
priority: AlertPriority;
|
||||
alertKey: string;
|
||||
alertSource: AlertSource | null;
|
||||
assignedTo: User | null;
|
||||
logEntries: LogEntry[];
|
||||
@@ -42,10 +42,10 @@ export const ACCEPTED = 'ACCEPTED';
|
||||
export const RESOLVED = 'RESOLVED';
|
||||
|
||||
/** @public */
|
||||
export type IncidentStatus = typeof PENDING | typeof ACCEPTED | typeof RESOLVED;
|
||||
export type AlertStatus = typeof PENDING | typeof ACCEPTED | typeof RESOLVED;
|
||||
|
||||
/** @public */
|
||||
export type IncidentPriority = 'HIGH' | 'LOW';
|
||||
export type AlertPriority = 'HIGH' | 'LOW';
|
||||
|
||||
/** @public */
|
||||
export interface Link {
|
||||
@@ -76,7 +76,7 @@ export interface LogEntry {
|
||||
timestamp: string;
|
||||
logEntryType: string;
|
||||
text: string;
|
||||
incidentId?: number;
|
||||
alertId?: number;
|
||||
iconName?: string;
|
||||
iconClass?: string;
|
||||
filterTypes?: string[];
|
||||
@@ -125,8 +125,8 @@ export interface AlertSource {
|
||||
iconUrl?: string;
|
||||
lightIconUrl?: string;
|
||||
darkIconUrl?: string;
|
||||
incidentCreation?: AlertSourceIncidentCreation;
|
||||
incidentPriorityRule?: AlertSourceIncidentPriorityRule;
|
||||
alertCreation?: AlertSourceAlertCreation;
|
||||
alertPriorityRule?: AlertSourceAlertPriorityRule;
|
||||
emailFiltered?: boolean;
|
||||
emailResolveFiltered?: boolean;
|
||||
active?: boolean;
|
||||
@@ -209,16 +209,16 @@ export type AlertSourceIntegrationType =
|
||||
| 'CORTEXXSOAR'
|
||||
| string;
|
||||
/** @public */
|
||||
export type AlertSourceIncidentCreation =
|
||||
| 'ONE_INCIDENT_PER_EMAIL'
|
||||
| 'ONE_INCIDENT_PER_EMAIL_SUBJECT'
|
||||
| 'ONE_PENDING_INCIDENT_ALLOWED'
|
||||
| 'ONE_OPEN_INCIDENT_ALLOWED'
|
||||
export type AlertSourceAlertCreation =
|
||||
| 'ONE_ALERT_PER_EMAIL'
|
||||
| 'ONE_ALERT_PER_EMAIL_SUBJECT'
|
||||
| 'ONE_PENDING_ALERT_ALLOWED'
|
||||
| 'ONE_OPEN_ALERT_ALLOWED'
|
||||
| 'OPEN_RESOLVE_ON_EXTRACTION';
|
||||
/** @public */
|
||||
export type AlertSourceFilterOperator = 'AND' | 'OR';
|
||||
/** @public */
|
||||
export type AlertSourceIncidentPriorityRule =
|
||||
export type AlertSourceAlertPriorityRule =
|
||||
| 'HIGH'
|
||||
| 'LOW'
|
||||
| 'HIGH_DURING_SUPPORT_HOURS'
|
||||
@@ -251,7 +251,7 @@ export interface AlertSourceSupportDay {
|
||||
/** @public */
|
||||
export interface AlertSourceSupportHours {
|
||||
timezone: AlertSourceTimeZone;
|
||||
autoRaiseIncidents: boolean;
|
||||
autoRaiseAlerts: boolean;
|
||||
supportDays: {
|
||||
MONDAY: AlertSourceSupportDay;
|
||||
TUESDAY: AlertSourceSupportDay;
|
||||
@@ -324,7 +324,7 @@ export interface UptimeMonitor {
|
||||
checkParams: UptimeMonitorCheckParams;
|
||||
intervalSec: number;
|
||||
timeoutMs: number;
|
||||
createIncidentAfterFailedChecks: number;
|
||||
createAlertAfterFailedChecks: number;
|
||||
paused: boolean;
|
||||
embedUrl: string;
|
||||
shareUrl: string;
|
||||
@@ -342,7 +342,7 @@ export interface UptimeMonitorCheckParams {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface IncidentResponder {
|
||||
export interface AlertResponder {
|
||||
group: 'SUGGESTED' | 'USER' | 'ESCALATION_POLICY' | 'ON_CALL_SCHEDULE';
|
||||
id: number;
|
||||
name: string;
|
||||
@@ -350,19 +350,19 @@ export interface IncidentResponder {
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface IncidentAction {
|
||||
export interface AlertAction {
|
||||
name: string;
|
||||
type: string;
|
||||
webhookId: string;
|
||||
extensionId?: string;
|
||||
history?: IncidentActionHistory[];
|
||||
history?: AlertActionHistory[];
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface IncidentActionHistory {
|
||||
export interface AlertActionHistory {
|
||||
id: string;
|
||||
webhookId: string;
|
||||
incidentId: number;
|
||||
alertId: number;
|
||||
actor: User;
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user