# What this PR does - rename utils to helpers - rename types.ts to app-types.ts ## Which issue(s) this PR closes Related to https://raintank-corp.slack.com/archives/C0762D6EUDV/p1725477060488709 https://raintank-corp.slack.com/archives/C0762D6EUDV/p1724936143487849 TL;DR IRM needs imported modules from oncall/incident to have uniq absolute import paths <!-- *Note*: If you want the issue to be auto-closed once the PR is merged, change "Related to" to "Closes" in the line above. If you have more than one GitHub issue that this PR closes, be sure to preface each issue link with a [closing keyword](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests#linking-a-pull-request-to-an-issue). This ensures that the issue(s) are auto-closed once the PR has been merged. --> ## 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.
133 lines
4.3 KiB
TypeScript
133 lines
4.3 KiB
TypeScript
import React, { useState } from 'react';
|
|
|
|
import { Button, Icon, Modal, Tooltip, Stack } from '@grafana/ui';
|
|
import cn from 'classnames/bind';
|
|
import { StackSize } from 'helpers/consts';
|
|
import { openNotification } from 'helpers/helpers';
|
|
import CopyToClipboard from 'react-copy-to-clipboard';
|
|
import Emoji from 'react-emoji-render';
|
|
import { debounce } from 'throttle-debounce';
|
|
|
|
import { MonacoEditor, MonacoLanguage } from 'components/MonacoEditor/MonacoEditor';
|
|
import { MONACO_EDITABLE_CONFIG } from 'components/MonacoEditor/MonacoEditor.config';
|
|
import { PluginLink } from 'components/PluginLink/PluginLink';
|
|
import { Text } from 'components/Text/Text';
|
|
import { AlertReceiveChannelHelper } from 'models/alert_receive_channel/alert_receive_channel.helpers';
|
|
import { ApiSchemas } from 'network/oncall-api/api.types';
|
|
import styles from 'pages/integration/Integration.module.scss';
|
|
import { useStore } from 'state/useStore';
|
|
|
|
const cx = cn.bind(styles);
|
|
|
|
interface IntegrationSendDemoPayloadModalProps {
|
|
isOpen: boolean;
|
|
alertReceiveChannel: ApiSchemas['AlertReceiveChannel'];
|
|
onHideOrCancel: () => void;
|
|
}
|
|
|
|
export const IntegrationSendDemoAlertModal: React.FC<IntegrationSendDemoPayloadModalProps> = ({
|
|
alertReceiveChannel,
|
|
isOpen,
|
|
onHideOrCancel,
|
|
}) => {
|
|
const store = useStore();
|
|
const { alertReceiveChannelStore } = store;
|
|
const initialDemoJSON = JSON.stringify(alertReceiveChannel.demo_alert_payload, null, 2);
|
|
const [demoPayload, setDemoPayload] = useState<string>(initialDemoJSON);
|
|
let onPayloadChangeDebounced = debounce(100, onPayloadChange);
|
|
|
|
return (
|
|
<Modal
|
|
closeOnBackdropClick={false}
|
|
closeOnEscape
|
|
isOpen={isOpen}
|
|
onDismiss={onHideOrCancel}
|
|
title={
|
|
<Stack>
|
|
<Text.Title level={4}>
|
|
Send demo alert to integration: {''}
|
|
<strong>
|
|
<Emoji text={alertReceiveChannel.verbal_name} />
|
|
</strong>
|
|
</Text.Title>
|
|
</Stack>
|
|
}
|
|
>
|
|
<Stack direction="column">
|
|
<Stack gap={StackSize.xs}>
|
|
<Text type={'secondary'}>Alert Payload</Text>
|
|
<Tooltip
|
|
content={
|
|
<>
|
|
Modify the provided payload to test integration routes, templates, and escalations. Enable Debug
|
|
maintenance on the integration to prevent real notifications.
|
|
</>
|
|
}
|
|
placement={'top-start'}
|
|
>
|
|
<Icon name={'info-circle'} />
|
|
</Tooltip>
|
|
</Stack>
|
|
|
|
<div className={cx('integration__payloadInput')}>
|
|
<MonacoEditor
|
|
value={initialDemoJSON}
|
|
disabled={true}
|
|
height={`60vh`}
|
|
useAutoCompleteList={false}
|
|
language={MonacoLanguage.json}
|
|
data={undefined}
|
|
monacoOptions={MONACO_EDITABLE_CONFIG}
|
|
showLineNumbers={false}
|
|
onChange={onPayloadChangeDebounced}
|
|
/>
|
|
</div>
|
|
|
|
<Stack justifyContent={'flex-end'} gap={StackSize.md}>
|
|
<Button variant={'secondary'} onClick={onHideOrCancel}>
|
|
Cancel
|
|
</Button>
|
|
<CopyToClipboard text={getCurlText()} onCopy={() => openNotification('CURL has been copied')}>
|
|
<Button variant={'secondary'}>Copy as CURL</Button>
|
|
</CopyToClipboard>
|
|
<Button variant={'primary'} onClick={onSendAlert} data-testid="submit-send-alert">
|
|
Send Alert
|
|
</Button>
|
|
</Stack>
|
|
</Stack>
|
|
</Modal>
|
|
);
|
|
|
|
function onPayloadChange(value: string) {
|
|
setDemoPayload(value);
|
|
}
|
|
|
|
async function onSendAlert() {
|
|
let parsedPayload = undefined;
|
|
try {
|
|
parsedPayload = JSON.parse(demoPayload);
|
|
} catch (ex) {}
|
|
|
|
await AlertReceiveChannelHelper.sendDemoAlert(alertReceiveChannel.id, parsedPayload);
|
|
alertReceiveChannelStore.fetchCounters();
|
|
openNotification(<DemoNotification />);
|
|
onHideOrCancel();
|
|
}
|
|
|
|
function getCurlText() {
|
|
return `curl -X POST \
|
|
${alertReceiveChannel?.integration_url} \
|
|
-H 'Content-Type: Application/json' \
|
|
-d '${demoPayload}'`;
|
|
}
|
|
};
|
|
|
|
const DemoNotification: React.FC = () => {
|
|
return (
|
|
<div data-testid="demo-alert-sent-notification">
|
|
Demo alert was generated. Find it on the
|
|
<PluginLink query={{ page: 'alert-groups' }}> "Alert Groups" </PluginLink>
|
|
page and make sure it didn't freak out your colleagues 😉
|
|
</div>
|
|
);
|
|
};
|