Skip to content

Commit

Permalink
chore: back merge irm (#5111)
Browse files Browse the repository at this point in the history
# What this PR does

Back merge irm

## Checklist

- [ ] Unit, integration, and e2e (if applicable) tests updated
- [x] Documentation added (or `pr:no public docs` PR label added if not
required)
- [x] Added the relevant release notes label (see labels prefixed w/
`release:`). These labels dictate how your PR will
    show up in the autogenerated release notes.
  • Loading branch information
brojd authored Oct 2, 2024
1 parent e9d94eb commit 612c0e5
Show file tree
Hide file tree
Showing 14 changed files with 130 additions and 8 deletions.
12 changes: 12 additions & 0 deletions grafana-plugin/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## [1.9.28](https://github.com/grafana/irm/compare/grafana-oncall-app-v1.9.27...grafana-oncall-app-v1.9.28) (2024-10-01)


### Bug Fixes

* disallow oncall schedule rotation layer/overrides CUD form submissions more than once ([#193](https://github.com/grafana/irm/issues/193)) ([73ae1c7](https://github.com/grafana/irm/commit/73ae1c7d78474b42b9eb4305416828afeb04fa3a))


### Miscellaneous Chores

* implement merged IRM module.tsx ([#182](https://github.com/grafana/irm/issues/182)) ([995b573](https://github.com/grafana/irm/commit/995b5732493aabc226cd62b9ca52a1e582ef5878))

## [1.9.27](https://github.com/grafana/irm/compare/grafana-oncall-app-v1.9.26...grafana-oncall-app-v1.9.27) (2024-09-26)


Expand Down
2 changes: 1 addition & 1 deletion grafana-plugin/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "grafana-oncall-app",
"version": "1.9.27",
"version": "1.9.28",
"description": "Grafana OnCall Plugin",
"scripts": {
"lint": "eslint --ext .js,.jsx,.ts,.tsx --max-warnings=20 ./src ./e2e-tests",
Expand Down
30 changes: 30 additions & 0 deletions grafana-plugin/src/components/Policy/EscalationPolicy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ class _EscalationPolicy extends React.Component<EscalationPolicyProps, any> {
return this.renderNumAlertsInWindow();
case 'num_minutes_in_window':
return this.renderNumMinutesInWindowOptions();
case 'severity':
return this.renderSeverities();
default:
console.warn('Unknown escalation step placeholder');
return '';
Expand Down Expand Up @@ -248,6 +250,34 @@ class _EscalationPolicy extends React.Component<EscalationPolicyProps, any> {
);
}

renderSeverities() {
const {
data,
isDisabled,
theme,
store: { escalationPolicyStore },
} = this.props;
const styles = getEscalationPolicyStyles(theme);
const { severity } = data;

return (
<WithPermissionControlTooltip key="" userAction={UserActions.EscalationChainsWrite}>
<Select
menuShouldPortal
disabled={isDisabled}
placeholder="Severity"
className={cx(styles.select, styles.control)}
value={severity}
onChange={this.getOnSelectChangeHandler('severity')}
options={escalationPolicyStore.severityChoices.map((severity_choice) => ({
value: severity_choice.value,
label: severity_choice.display_name,
}))}
/>
</WithPermissionControlTooltip>
);
}

renderTimeRange() {
const { data, isDisabled, theme } = this.props;
const styles = getEscalationPolicyStyles(theme);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export const EscalationChainSteps = observer((props: EscalationChainStepsProps)

useEffect(() => {
escalationPolicyStore.updateWebEscalationPolicyOptions();
escalationPolicyStore.updateSeverityOptions();
}, []);

const handleSortEnd = useCallback(
Expand Down
9 changes: 7 additions & 2 deletions grafana-plugin/src/containers/RotationForm/RotationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from '@grafana/ui';
import dayjs from 'dayjs';
import { GRAFANA_HEADER_HEIGHT, StackSize } from 'helpers/consts';
import { useDebouncedCallback, useResize } from 'helpers/hooks';
import { useDebouncedCallback, useIsLoading, useResize } from 'helpers/hooks';
import { observer } from 'mobx-react';
import Draggable, { DraggableData, DraggableEvent } from 'react-draggable';

Expand Down Expand Up @@ -51,6 +51,7 @@ import { DeletionModal } from 'containers/RotationForm/parts/DeletionModal';
import { TimeUnitSelector } from 'containers/RotationForm/parts/TimeUnitSelector';
import { UserItem } from 'containers/RotationForm/parts/UserItem';
import { calculateScheduleFormOffset } from 'containers/Rotations/Rotations.helpers';
import { ActionKey } from 'models/loader/action-keys';
import { getShiftName } from 'models/schedule/schedule.helpers';
import { Schedule, Shift } from 'models/schedule/schedule.types';
import { ApiSchemas } from 'network/oncall-api/api.types';
Expand Down Expand Up @@ -114,6 +115,10 @@ export const RotationForm = observer((props: RotationFormProps) => {

const [startRotationFromUserIndex, setStartRotationFromUserIndex] = useState(0);

const isCreating = useIsLoading(ActionKey.CREATE_ONCALL_SHIFT);
const isUpdating = useIsLoading(ActionKey.UPDATE_ONCALL_SHIFT);
const isSubmitting = isCreating || isUpdating;

const [errors, setErrors] = useState<{ [key: string]: string[] }>({});
const [bounds, setDraggableBounds] = useState<{ left: number; right: number; top: number; bottom: number }>(
undefined
Expand Down Expand Up @@ -526,7 +531,7 @@ export const RotationForm = observer((props: RotationFormProps) => {
const hasUpdatedShift = shift && shift.updated_shift;
const ended = shift && shift.until && getDateTime(shift.until).isBefore(dayjs());

const disabled = hasUpdatedShift || ended;
const disabled = hasUpdatedShift || ended || isSubmitting;

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { cx } from '@emotion/css';
import { IconButton, Stack, Field, Button, useTheme2, useStyles2 } from '@grafana/ui';
import dayjs from 'dayjs';
import { StackSize } from 'helpers/consts';
import { useDebouncedCallback, useResize } from 'helpers/hooks';
import { useDebouncedCallback, useIsLoading, useResize } from 'helpers/hooks';
import Draggable, { DraggableData, DraggableEvent } from 'react-draggable';

import { Modal } from 'components/Modal/Modal';
Expand All @@ -13,6 +13,7 @@ import { Text } from 'components/Text/Text';
import { UserGroups } from 'components/UserGroups/UserGroups';
import { WithConfirm } from 'components/WithConfirm/WithConfirm';
import { calculateScheduleFormOffset } from 'containers/Rotations/Rotations.helpers';
import { ActionKey } from 'models/loader/action-keys';
import { getShiftName } from 'models/schedule/schedule.helpers';
import { Schedule, Shift } from 'models/schedule/schedule.types';
import { ApiSchemas } from 'network/oncall-api/api.types';
Expand Down Expand Up @@ -64,6 +65,11 @@ export const ScheduleOverrideForm: FC<RotationFormProps> = (props) => {

const [offsetTop, setOffsetTop] = useState<number>(0);

const isCreating = useIsLoading(ActionKey.CREATE_ONCALL_SHIFT);
const isUpdating = useIsLoading(ActionKey.UPDATE_ONCALL_SHIFT);
const isDeleting = useIsLoading(ActionKey.DELETE_ONCALL_SHIFT);
const isSubmitting = isCreating || isUpdating || isDeleting;

const [isOpen, setIsOpen] = useState<boolean>(false);

const [errors, setErrors] = useState<{ [key: string]: string[] }>({});
Expand Down Expand Up @@ -197,7 +203,7 @@ export const ScheduleOverrideForm: FC<RotationFormProps> = (props) => {
const isFormValid = useMemo(() => !Object.keys(errors).length, [errors]);

const ended = shift && shift.until && getDateTime(shift.until).isBefore(dayjs());
const disabled = ended;
const disabled = ended || isSubmitting;

return (
<Modal
Expand Down Expand Up @@ -230,7 +236,13 @@ export const ScheduleOverrideForm: FC<RotationFormProps> = (props) => {
<Stack>
{shiftId !== 'new' && (
<WithConfirm title="Are you sure you want to delete override?">
<IconButton variant="secondary" tooltip="Delete" name="trash-alt" onClick={handleDeleteClick} />
<IconButton
variant="secondary"
tooltip="Delete"
name="trash-alt"
onClick={handleDeleteClick}
disabled={isSubmitting}
/>
</WithConfirm>
)}
<IconButton aria-label="Drag" variant="secondary" className="drag-handler" name="draggabledots" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import React, { ChangeEvent, useCallback, useState } from 'react';

import { Stack, Modal as GrafanaModal, Button, InlineSwitch, useStyles2 } from '@grafana/ui';
import { StackSize } from 'helpers/consts';
import { useIsLoading } from 'helpers/hooks';

import { Text } from 'components/Text/Text';
import { getRotationFormStyles } from 'containers/RotationForm/RotationForm.styles';
import { ActionKey } from 'models/loader/action-keys';

interface DeletionModalProps {
onHide: () => void;
Expand All @@ -13,6 +15,7 @@ interface DeletionModalProps {

export const DeletionModal = ({ onHide, onConfirm }: DeletionModalProps) => {
const [isForceDelete, setIsForceDelete] = useState<boolean>(false);
const isDeleting = useIsLoading(ActionKey.DELETE_ONCALL_SHIFT);

const styles = useStyles2(getRotationFormStyles);

Expand Down Expand Up @@ -46,7 +49,7 @@ export const DeletionModal = ({ onHide, onConfirm }: DeletionModalProps) => {
<Button variant="secondary" onClick={onHide}>
Cancel
</Button>
<Button variant="destructive" onClick={handleConfirmClick}>
<Button variant="destructive" onClick={handleConfirmClick} disabled={isDeleting}>
Delete
</Button>
</Stack>
Expand Down
14 changes: 14 additions & 0 deletions grafana-plugin/src/models/alertgroup/alertgroup.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export enum TimeLineRealm {
export interface TimeLineItem {
action: string;
author: ApiSchemas['User'] | null;
escalation_chain: TimelineLink | null;
incident: DeclaredIncident | null;
schedule: TimelineLink | null;
webhook: TimelineLink | null;
created_at: string;
realm: TimeLineRealm;
time: string;
Expand Down Expand Up @@ -55,3 +59,13 @@ interface RenderForWeb {
image_url: string;
source_link: string;
}

interface DeclaredIncident {
incident_link: string;
incident_title: string;
}

interface TimelineLink {
pk: string;
title: string;
}
13 changes: 13 additions & 0 deletions grafana-plugin/src/models/escalation_policy/escalation_policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { EscalationPolicy } from 'models/escalation_policy/escalation_policy.typ
import { makeRequest } from 'network/network';
import { move } from 'state/helpers';
import { RootStore } from 'state/rootStore';
import { SelectOption } from 'state/types';

export class EscalationPolicyStore extends BaseStore {
@observable.shallow
Expand All @@ -19,6 +20,9 @@ export class EscalationPolicyStore extends BaseStore {
@observable
escalationChoices: any = [];

@observable
severityChoices: SelectOption[] = [];

@observable
webEscalationChoices: any = [];

Expand All @@ -30,6 +34,15 @@ export class EscalationPolicyStore extends BaseStore {
this.path = '/escalation_policies/';
}

@action.bound
async updateSeverityOptions() {
const response = await makeRequest<SelectOption[]>('/escalation_policies/severity_options/', {});

runInAction(() => {
this.severityChoices = response;
});
}

@action.bound
async updateWebEscalationPolicyOptions() {
const response = await makeRequest('/escalation_policies/escalation_options/', {});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface EscalationPolicy {
important: boolean | null;
num_alerts_in_window: number;
num_minutes_in_window: number;
severity: string | null;
}

export interface EscalationPolicyOption {
Expand Down
3 changes: 3 additions & 0 deletions grafana-plugin/src/models/loader/action-keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@ export enum ActionKey {
FETCH_INTEGRATIONS_AVAILABLE_FOR_CONNECTION = 'FETCH_INTEGRATIONS_AVAILABLE_FOR_CONNECTION',
FETCH_WEBHOOKS = 'FETCH_WEBHOOKS',
TRIGGER_MANUAL_WEBHOOK = 'TRIGGER_MANUAL_WEBHOOK',
CREATE_ONCALL_SHIFT = 'CREATE_ONCALL_SHIFT',
UPDATE_ONCALL_SHIFT = 'UPDATE_ONCALL_SHIFT',
DELETE_ONCALL_SHIFT = 'DELETE_ONCALL_SHIFT',
}
4 changes: 4 additions & 0 deletions grafana-plugin/src/models/schedule/schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ export class ScheduleStore extends BaseStore {
// ------- NEW SCHEDULES API ENDPOINTS ---------

@action.bound
@AutoLoadingState(ActionKey.CREATE_ONCALL_SHIFT)
async createRotation(scheduleId: Schedule['id'], isOverride: boolean, params: Partial<Shift>) {
const type = isOverride ? 3 : 2;

Expand Down Expand Up @@ -364,6 +365,7 @@ export class ScheduleStore extends BaseStore {
}

@action.bound
@AutoLoadingState(ActionKey.UPDATE_ONCALL_SHIFT)
async updateRotation(shiftId: Shift['id'], params: Partial<Shift>) {
const response = await makeRequest(`/oncall_shifts/${shiftId}`, {
params: { force: true },
Expand All @@ -382,6 +384,7 @@ export class ScheduleStore extends BaseStore {
}

@action.bound
@AutoLoadingState(ActionKey.UPDATE_ONCALL_SHIFT)
async updateRotationAsNew(shiftId: Shift['id'], params: Partial<Shift>) {
const response = await makeRequest(`/oncall_shifts/${shiftId}`, {
data: { ...params },
Expand Down Expand Up @@ -489,6 +492,7 @@ export class ScheduleStore extends BaseStore {
return response;
}

@AutoLoadingState(ActionKey.DELETE_ONCALL_SHIFT)
async deleteOncallShift(shiftId: Shift['id'], force?: boolean) {
try {
return await makeRequest(`/oncall_shifts/${shiftId}`, {
Expand Down
24 changes: 24 additions & 0 deletions grafana-plugin/src/pages/incident/Incident.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,30 @@ class _IncidentPage extends React.Component<IncidentPageProps, IncidentPageState
<Text underline>{entity.author?.username}</Text>
</a>
);
case 'escalation_chain':
return (
<a href={`${PLUGIN_ROOT}/escalations/${entity.escalation_chain?.pk}`} target="_blank" rel="noopener noreferrer">
<Text underline>{entity.escalation_chain?.title}</Text>
</a>
);
case 'related_incident':
return (
<a href={entity.incident?.incident_link} target="_blank" rel="noopener noreferrer">
<Text underline>{entity.incident?.incident_title}</Text>
</a>
);
case 'schedule':
return (
<a href={`${PLUGIN_ROOT}/schedules/${entity.schedule?.pk}`} target="_blank" rel="noopener noreferrer">
<Text underline>{entity.schedule?.title}</Text>
</a>
);
case 'webhook':
return (
<a href={`${PLUGIN_ROOT}/outgoing_webhooks/${entity.webhook?.pk}`} target="_blank" rel="noopener noreferrer">
<Text underline>{entity.webhook?.title}</Text>
</a>
);
default:
return '{{' + match + '}}';
}
Expand Down
2 changes: 1 addition & 1 deletion grafana-plugin/src/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
export const GIT_COMMIT = 'dev';

// Declare a constant that will be updated by release-please action
export const CURRENT_VERSION = '1.9.27' as string; // x-release-please-version
export const CURRENT_VERSION = '1.9.28' as string; // x-release-please-version

0 comments on commit 612c0e5

Please sign in to comment.