feat(splunk-on-call-plugin): docs + display team and user
This commit is contained in:
@@ -46,6 +46,7 @@ configmaps
|
||||
configs
|
||||
const
|
||||
cookiecutter
|
||||
cors
|
||||
css
|
||||
dariddler
|
||||
dataflow
|
||||
|
||||
@@ -60,6 +60,15 @@ splunkoncall:
|
||||
|
||||
The user supplied must be a valid Splunk On-Call user and a member of your organization.
|
||||
|
||||
In order to be able to make certain API calls you need to add the `PATCH` method to the backend cors methods list.
|
||||
|
||||
```yaml
|
||||
backend:
|
||||
# ...
|
||||
cors:
|
||||
methods: [GET, POST, PUT, DELETE, PATCH]
|
||||
```
|
||||
|
||||
### Adding your team name to the entity annotation
|
||||
|
||||
The information displayed for each entity is based on the team name.
|
||||
|
||||
@@ -52,6 +52,10 @@ export class SplunkOnCallClient implements SplunkOnCallApi {
|
||||
}
|
||||
constructor(private readonly config: ClientApiConfig) {}
|
||||
|
||||
getUsername(): string | undefined {
|
||||
return this.config.username as string;
|
||||
}
|
||||
|
||||
async getIncidents(): Promise<Incident[]> {
|
||||
const url = `${await this.config.discoveryApi.getBaseUrl(
|
||||
'proxy',
|
||||
|
||||
@@ -18,7 +18,6 @@ import {
|
||||
EscalationPolicyInfo,
|
||||
Incident,
|
||||
OnCall,
|
||||
Service,
|
||||
Team,
|
||||
User,
|
||||
} from '../components/types';
|
||||
@@ -84,6 +83,11 @@ export interface SplunkOnCallApi {
|
||||
* Get a list of escalation policies for your organization.
|
||||
*/
|
||||
getEscalationPolicies(): Promise<EscalationPolicyInfo[]>;
|
||||
|
||||
/**
|
||||
* Get the current user username.
|
||||
*/
|
||||
getUsername(): string | undefined;
|
||||
}
|
||||
|
||||
export type PatchIncidentRequest = {
|
||||
@@ -101,10 +105,6 @@ export type ListUserResponse = {
|
||||
_selfUrl?: string;
|
||||
};
|
||||
|
||||
export type ServicesResponse = {
|
||||
services: Service[];
|
||||
};
|
||||
|
||||
export type IncidentsResponse = {
|
||||
incidents: Incident[];
|
||||
};
|
||||
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
alertApiRef,
|
||||
} from '@backstage/core';
|
||||
import { formatDistanceToNowStrict } from 'date-fns';
|
||||
import { Incident } from '../types';
|
||||
import { Incident, IncidentPhase } from '../types';
|
||||
import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser';
|
||||
import { splunkOnCallApiRef } from '../../api/client';
|
||||
import { useAsyncFn } from 'react-use';
|
||||
@@ -66,7 +66,11 @@ type Props = {
|
||||
onIncidentAction: () => void;
|
||||
};
|
||||
|
||||
const IncidentPhase = ({ currentPhase }: { currentPhase: string }) => {
|
||||
const IncidentPhaseStatus = ({
|
||||
currentPhase,
|
||||
}: {
|
||||
currentPhase: IncidentPhase;
|
||||
}) => {
|
||||
switch (currentPhase) {
|
||||
case 'UNACKED':
|
||||
return <StatusError />;
|
||||
@@ -77,6 +81,17 @@ const IncidentPhase = ({ currentPhase }: { currentPhase: string }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const incidentPhaseTooltip = (currentPhase: IncidentPhase) => {
|
||||
switch (currentPhase) {
|
||||
case 'UNACKED':
|
||||
return 'Triggered';
|
||||
case 'ACKED':
|
||||
return 'Acknowledged';
|
||||
default:
|
||||
return 'Resolved';
|
||||
}
|
||||
};
|
||||
|
||||
const IncidentAction = ({
|
||||
currentPhase,
|
||||
userName,
|
||||
@@ -190,9 +205,12 @@ export const IncidentListItem = ({ incident, onIncidentAction }: Props) => {
|
||||
return (
|
||||
<ListItem dense key={incident.entityId}>
|
||||
<ListItemIcon className={classes.listItemIcon}>
|
||||
<Tooltip title={incident.currentPhase || ''} placement="top">
|
||||
<Tooltip
|
||||
title={incidentPhaseTooltip(incident.currentPhase)}
|
||||
placement="top"
|
||||
>
|
||||
<div className={classes.denseListIcon}>
|
||||
<IncidentPhase currentPhase={incident.currentPhase || ''} />
|
||||
<IncidentPhaseStatus currentPhase={incident.currentPhase} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</ListItemIcon>
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
CardHeader,
|
||||
Divider,
|
||||
CardContent,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import { Incidents } from './Incident';
|
||||
import { EscalationPolicy } from './Escalation';
|
||||
@@ -122,8 +123,11 @@ export const SplunkOnCallCard = ({ entity }: Props) => {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader
|
||||
title="Incidents"
|
||||
subheader={<HeaderIconLinkRow links={[triggerLink]} />}
|
||||
title="Splunk On-Call"
|
||||
subheader={[
|
||||
<Typography key="team_name">Team: {team}</Typography>,
|
||||
<HeaderIconLinkRow key="incident_trigger" links={[triggerLink]} />,
|
||||
]}
|
||||
/>
|
||||
<Divider />
|
||||
<CardContent>
|
||||
|
||||
@@ -118,6 +118,10 @@ export const TriggerDialog = ({
|
||||
}),
|
||||
);
|
||||
|
||||
const username = api.getUsername();
|
||||
|
||||
const currentUser = users.find(user => user.username === username);
|
||||
|
||||
const {
|
||||
value: policies,
|
||||
loading: policiesLoaading,
|
||||
@@ -180,6 +184,12 @@ export const TriggerDialog = ({
|
||||
<Dialog maxWidth="md" open={showDialog} onClose={handleDialog} fullWidth>
|
||||
<DialogTitle>This action will trigger an incident.</DialogTitle>
|
||||
<DialogContent>
|
||||
<Typography variant="subtitle1" gutterBottom align="justify">
|
||||
Created by:{' '}
|
||||
<b>
|
||||
{currentUser?.firstName} {currentUser?.lastName}
|
||||
</b>
|
||||
</Typography>
|
||||
<Alert severity="info">
|
||||
<Typography variant="body1" align="justify">
|
||||
If the issue you are seeing does not need urgent attention, please
|
||||
|
||||
@@ -16,31 +16,6 @@
|
||||
|
||||
import { IncidentTarget } from '../api/types';
|
||||
|
||||
export type Service = {
|
||||
id: string;
|
||||
name: string;
|
||||
html_url: string;
|
||||
integrationKey: string;
|
||||
escalation_policy: {
|
||||
id: string;
|
||||
user: User;
|
||||
};
|
||||
};
|
||||
|
||||
export type Assignee = {
|
||||
id: string;
|
||||
summary: string;
|
||||
html_url: string;
|
||||
};
|
||||
|
||||
export type SubHeaderLink = {
|
||||
title: string;
|
||||
href?: string;
|
||||
icon: React.ReactNode;
|
||||
action?: React.ReactNode;
|
||||
};
|
||||
|
||||
// GET Teams
|
||||
export type Team = {
|
||||
name?: string;
|
||||
slug?: string;
|
||||
@@ -53,7 +28,6 @@ export type Team = {
|
||||
_adminsUrl?: string;
|
||||
};
|
||||
|
||||
// GET oncall
|
||||
export type OnCall = {
|
||||
team?: OnCallTeamResource;
|
||||
oncallNow?: OnCallNowResource[];
|
||||
@@ -82,7 +56,6 @@ export type OnCallUser = {
|
||||
username?: string;
|
||||
};
|
||||
|
||||
// GET /api-public/v2/user
|
||||
export type User = {
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
@@ -95,7 +68,6 @@ export type User = {
|
||||
_selfUrl?: string;
|
||||
};
|
||||
|
||||
// Incident creation
|
||||
export type CreateIncidentRequest = {
|
||||
summary: string;
|
||||
details: string;
|
||||
@@ -104,11 +76,12 @@ export type CreateIncidentRequest = {
|
||||
isMultiResponder: boolean;
|
||||
};
|
||||
|
||||
// GET incidents
|
||||
export type IncidentPhase = 'UNACKED' | 'ACKED' | 'RESOLVED';
|
||||
|
||||
export type Incident = {
|
||||
incidentNumber?: string;
|
||||
startTime?: string;
|
||||
currentPhase?: string;
|
||||
currentPhase: IncidentPhase;
|
||||
entityState?: string;
|
||||
entityType?: string;
|
||||
routingKey?: string;
|
||||
|
||||
Reference in New Issue
Block a user