Incidents mapped to /alert-groups (#1678)

# What this PR does

Reopened old reverted PR that @Ukochka worked on. In addition it has
fixed the redirect from `?page=incident` to `/alert-groups`

---------

Co-authored-by: Yulia Shanyrova <yulia.shanyrova@grafana.com>
Co-authored-by: Joey Orlando <joey.orlando@grafana.com>
This commit is contained in:
Rares Mardare 2023-03-31 12:54:01 +03:00 committed by GitHub
parent 2b3e269e28
commit 0acac58af0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 79 additions and 45 deletions

View file

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
### Changes
- Renamed routes from /incidents to /alert-groups ([#1678](https://github.com/grafana/oncall/pull/1678))
### Fixed
- Fix team search when filtering resources by @vadimkerr ([#1680](https://github.com/grafana/oncall/pull/1680))

View file

@ -66,7 +66,7 @@ const Tutorial: FC<TutorialProps> = (props) => {
</div>
<Arrow />
<div className={cx('step')}>
<PluginLink query={{ page: 'incidents' }}>
<PluginLink query={{ page: 'alert-groups' }}>
<div className={cx('icon', { icon_active: step === TutorialStep.Incidents })}>
<img src={bellIcon} />
</div>

View file

@ -65,7 +65,7 @@ const AlertReceiveChannelCard = observer((props: AlertReceiveChannelCardProps) =
</Text>
{alertReceiveChannelCounter && (
<PluginLink
query={{ page: 'incidents', integration: alertReceiveChannel.id }}
query={{ page: 'alert-groups', integration: alertReceiveChannel.id }}
className={cx('alertsInfoText')}
>
<Badge

View file

@ -70,7 +70,7 @@ interface AlertRulesState {
const Notification: React.FC = () => (
<div>
Demo alert was generated. Find it on the
<PluginLink query={{ page: 'incidents' }}> "Alert Groups" </PluginLink>
<PluginLink query={{ page: 'alert-groups' }}> "Alert Groups" </PluginLink>
page and make sure it didn't freak out your colleagues 😉
</div>
);

View file

@ -63,15 +63,15 @@ const AttachIncidentForm = observer(({ id, onUpdate, onHide }: AttachIncidentFor
title={
<HorizontalGroup>
<Icon size="lg" name="link" />
<Text.Title level={4}>Attach to another incident</Text.Title>
<Text.Title level={4}>Attach to another alert group</Text.Title>
</HorizontalGroup>
}
className={cx('root')}
onDismiss={onHide}
>
<Field
label="Incident to be attached with"
description="Linking incidents together can help the team investigate the underlying issue."
label="Alert group to be attached with"
description="Linking alert groups together can help the team investigate the underlying issue."
>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<GSelect

View file

@ -101,7 +101,7 @@ const IncidentMatcher = observer((props: IncidentMatcherProps) => {
{selectedAlertItem ? (
<SourceCode noMaxHeight>{JSON.stringify(selectedAlertItem, null, 2)}</SourceCode>
) : (
<Text type="secondary"> Select incident first</Text>
<Text type="secondary"> Select alert group first</Text>
)}
</div>
</div>

View file

@ -59,6 +59,7 @@ const IntegrationSettings = observer((props: IntegrationSettingsProps) => {
const [expanded, _setExpanded] = useState(false);
const handleSwitchToTemplate = (templateName: string) => {
setActiveTab(IntegrationSettingsTab.Templates);
setSelectedTemplate(templateName);
};

View file

@ -34,7 +34,12 @@
padding: 4px 8px;
margin-top: 8px;
min-width: 500px;
width: 520px;
width: 620px;
}
.autoresolve-div {
display: flex;
align-items: baseline;
}
.warning-icon-color {

View file

@ -150,7 +150,7 @@ const Autoresolve = ({ alertReceiveChannelId, onSwitchToTemplate, alertGroupId }
<Label>
<div className={cx('settings-label')}>
Autoresolve
<Text type="secondary">How should this integration resolve incidents?</Text>
<Text type="secondary">How should this integration resolve alert groups?</Text>
</div>
</Label>
<div className={cx('team-select')}>
@ -172,9 +172,9 @@ const Autoresolve = ({ alertReceiveChannelId, onSwitchToTemplate, alertGroupId }
{autoresolveSelected && (
<>
<Block shadowed bordered className={cx('autoresolve-block')}>
<div>
<div className={cx('autoresolve-div')}>
<Text type="secondary" size="small">
<Icon name="info-circle" /> Incident will be automatically resolved when it matches{' '}
<Icon name="info-circle" /> Alert group will be automatically resolved when it matches{' '}
</Text>
<Button fill="text" size="sm" onClick={handleGoToTemplateSettingsCllick}>
autoresolve condition

View file

@ -36,7 +36,7 @@ export const form: { name: string; fields: FormItem[] } = {
},
{
value: MaintenanceMode.Maintenance,
label: 'Maintenance (collect everything in one incident)',
label: 'Maintenance (collect everything in one alert group)',
},
],
},

View file

@ -12,7 +12,8 @@
}
.draggable {
top: 0;
top: 10%;
position: absolute;
/* transition: transform 300ms ease; */
}

View file

@ -72,6 +72,7 @@ class EscalationChainsPage extends React.Component<EscalationChainsPageProps, Es
.loadItem(id, true)
.catch((error) => this.setState({ errorData: { ...getWrongTeamResponseInfo(error) } }));
await escalationChainStore.updateEscalationChainDetails(id);
if (!escalationChain) {
return;
}

View file

@ -144,7 +144,7 @@ class IncidentPage extends React.Component<IncidentPageProps, IncidentPageState>
<VerticalGroup spacing="lg" align="center">
<Text.Title level={1}>404</Text.Title>
<Text.Title level={4}>Alert group not found</Text.Title>
<PluginLink query={{ page: 'incidents', cursor, start, perpage }}>
<PluginLink query={{ page: 'alert-groups', cursor, start, perpage }}>
<Button variant="secondary" icon="arrow-left" size="md">
Go to Alert Groups page
</Button>
@ -244,7 +244,7 @@ class IncidentPage extends React.Component<IncidentPageProps, IncidentPageState>
<VerticalGroup>
<HorizontalGroup justify="space-between">
<HorizontalGroup className={cx('title')}>
<PluginLink query={{ page: 'incidents', cursor, start, perpage }}>
<PluginLink query={{ page: 'alert-groups', cursor, start, perpage }}>
<IconButton name="arrow-left" size="xxl" />
</PluginLink>
{/* @ts-ignore*/}
@ -256,12 +256,12 @@ class IncidentPage extends React.Component<IncidentPageProps, IncidentPageState>
{incident.root_alert_group && (
<Text type="secondary">
Attached to{' '}
<PluginLink query={{ page: 'incident', id: incident.root_alert_group.pk }}>
<PluginLink query={{ page: 'alert-groups', id: incident.root_alert_group.pk }}>
#{incident.root_alert_group.inside_organization_number}{' '}
{incident.root_alert_group.render_for_web.title}
</PluginLink>{' '}
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>
<Button variant="secondary" onClick={this.getUnattachClickHandler(incident.pk)} size="sm">
<Button variant="secondary" onClick={() => this.getUnattachClickHandler(incident.pk)} size="sm">
Unattach
</Button>
</WithPermissionControlTooltip>
@ -421,9 +421,7 @@ class IncidentPage extends React.Component<IncidentPageProps, IncidentPageState>
getUnattachClickHandler = (pk: Alert['pk']) => {
const { store } = this.props;
return () => {
store.alertGroupStore.unattachAlert(pk).then(this.update);
};
return store.alertGroupStore.unattachAlert(pk).then(this.update);
};
renderTimeline = () => {
@ -762,7 +760,7 @@ function AttachedIncidentsList({
{alerts.map((incident) => {
return (
<HorizontalGroup key={incident.pk} justify={'space-between'}>
<PluginLink query={{ page: 'incident', id: incident.pk }}>
<PluginLink query={{ page: 'alert-groups', id: incident.pk }}>
#{incident.inside_organization_number} {incident.render_for_web.title}
</PluginLink>
<WithPermissionControlTooltip userAction={UserActions.AlertGroupsWrite}>

View file

@ -127,7 +127,7 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
this.setState({ showAddAlertGroupForm: false });
}}
onCreate={(id: Alert['pk']) => {
history.push(`${PLUGIN_ROOT}/incidents/${id}`);
history.push(`${PLUGIN_ROOT}/alert-groups/${id}`);
}}
/>
)}
@ -557,7 +557,13 @@ class Incidents extends React.Component<IncidentsPageProps, IncidentsPageState>
<VerticalGroup spacing="none" justify="center">
<div className={'table__wrap-column'}>
<PluginLink
query={{ page: 'incidents', id: record.pk, cursor: incidentsCursor, perpage: incidentsItemsPerPage, start }}
query={{
page: 'alert-groups',
id: record.pk,
cursor: incidentsCursor,
perpage: incidentsItemsPerPage,
start,
}}
>
<Tooltip placement="top" content={record.render_for_web.title}>
<span>{record.render_for_web.title}</span>

View file

@ -27,24 +27,11 @@ function getPath(name = '') {
export const pages: { [id: string]: PageDefinition } = [
{
icon: 'bell',
id: 'incidents',
id: 'alert-groups',
hideFromBreadcrumbs: true,
text: 'Alert Groups',
hideTitle: true,
path: getPath('incidents'),
action: UserActions.AlertGroupsRead,
},
{
icon: 'bell',
id: 'incident',
text: '',
hideFromTabs: true,
hideFromBreadcrumbs: true,
parentItem: {
text: 'Incident',
url: `${PLUGIN_ROOT}/incidents`,
},
path: getPath('incident'),
path: getPath('alert-groups'),
action: UserActions.AlertGroupsRead,
},
{
@ -189,8 +176,8 @@ export const pages: { [id: string]: PageDefinition } = [
}, {});
export const ROUTES = {
incidents: ['incidents'],
incident: ['incidents/:id'],
'alert-groups': ['alert-groups'],
'alert-group': ['alert-groups/:id'],
users: ['users', 'users/:id'],
integrations: ['integrations', 'integrations/:id'],
escalations: ['escalations', 'escalations/:id'],
@ -205,6 +192,10 @@ export const ROUTES = {
'live-settings': ['live-settings'],
cloud: ['cloud'],
test: ['test'],
// backwards compatible to redirect to new alert-groups
incident: ['incidents/:id'],
incidents: ['incidents'],
};
export const getRoutesForPage = (name: string) => {

View file

@ -41,7 +41,7 @@
{
"type": "page",
"name": "Alert Groups",
"path": "/a/grafana-oncall-app/incidents",
"path": "/a/grafana-oncall-app/alert-groups",
"role": "Viewer",
"action": "grafana-oncall-app.alert-groups:read",
"addToNav": true

View file

@ -14,7 +14,7 @@ import weekday from 'dayjs/plugin/weekday';
import { observer, Provider } from 'mobx-react';
import Header from 'navbar/Header/Header';
import LegacyNavTabsBar from 'navbar/LegacyNavTabsBar';
import { Route, Switch, useLocation } from 'react-router-dom';
import { Redirect, Route, Switch, useLocation } from 'react-router-dom';
import { AppRootProps } from 'types';
import Unauthorized from 'components/Unauthorized';
@ -138,10 +138,10 @@ export const Root = observer((props: AppRootProps) => {
>
{userHasAccess ? (
<Switch>
<Route path={getRoutesForPage('incidents')} exact>
<Route path={getRoutesForPage('alert-groups')} exact>
<Incidents query={query} />
</Route>
<Route path={getRoutesForPage('incident')} exact>
<Route path={getRoutesForPage('alert-group')} exact>
<Incident query={query} />
</Route>
<Route path={getRoutesForPage('users')} exact>
@ -183,6 +183,33 @@ export const Root = observer((props: AppRootProps) => {
<Route path={getRoutesForPage('cloud')} exact>
<CloudPage />
</Route>
{/* Backwards compatibility redirect routes */}
<Route
path={getRoutesForPage('incident')}
exact
render={({ location }) => (
<Redirect
to={{
...location,
pathname: location.pathname.replace(/incident/, 'alert-group'),
}}
></Redirect>
)}
></Route>
<Route
path={getRoutesForPage('incidents')}
exact
render={({ location }) => (
<Redirect
to={{
...location,
pathname: location.pathname.replace(/incidents/, 'alert-groups'),
}}
></Redirect>
)}
></Route>
<Route path="*">
<NoMatch />
</Route>

View file

@ -11,7 +11,7 @@ export const GRAFANA_LICENSE_OSS = 'OpenSource';
export const BREAKPOINT_TABS = 1024;
// Default redirect page
export const DEFAULT_PAGE = 'incidents';
export const DEFAULT_PAGE = 'alert-groups';
export const PLUGIN_ROOT = '/a/grafana-oncall-app';