Skip to content

Commit

Permalink
Snow polishing (grafana#4136)
Browse files Browse the repository at this point in the history
# What this PR does

- Webhook URL should be template editor + move it after HTTP method
[Frontend] @brojd
- Lack of scrollbar when templates are there in Outgoing webhook details
drawer [Frontend] @brojd
- On outgoing tab "Open ServiceNow configuration" does nothing
[Frontend] @brojd
 - Remove OK tag next to url in outgoing tab [Frontend] @brojd
 
grafana/oncall-private#2615 

<!--
*Note*: 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.
  • Loading branch information
brojd authored Mar 29, 2024
1 parent e95125a commit 9256fbd
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 34 deletions.
22 changes: 17 additions & 5 deletions grafana-plugin/src/pages/integration/Integration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,13 @@ import { ApiSchemas } from 'network/oncall-api/api.types';
import { IntegrationHelper, getIsBidirectionalIntegration } from 'pages/integration/Integration.helper';
import styles from 'pages/integration/Integration.module.scss';
import { AppFeature } from 'state/features';
import { PageProps, SelectOption, WithStoreProps } from 'state/types';
import { PageProps, SelectOption, WithDrawerConfig, WithStoreProps } from 'state/types';
import { useStore } from 'state/useStore';
import { withMobXProviderContext } from 'state/withStore';
import { LocationHelper } from 'utils/LocationHelper';
import { UserActions } from 'utils/authorization/authorization';
import { PLUGIN_ROOT } from 'utils/consts';
import { withDrawer } from 'utils/hoc';
import { useDrawer } from 'utils/hooks';
import { getItem, setItem } from 'utils/localStorage';
import { sanitize } from 'utils/sanitize';
Expand All @@ -77,7 +78,11 @@ import { OutgoingTab } from './OutgoingTab/OutgoingTab';

const cx = cn.bind(styles);

interface IntegrationProps extends WithStoreProps, PageProps, RouteComponentProps<{ id: string }> {}
interface IntegrationProps
extends WithDrawerConfig<IntegrationDrawerKey>,
WithStoreProps,
PageProps,
RouteComponentProps<{ id: string }> {}

interface IntegrationState extends PageBaseState {
isLoading: boolean;
Expand Down Expand Up @@ -138,6 +143,7 @@ class _IntegrationPage extends React.Component<IntegrationProps, IntegrationStat
match: {
params: { id },
},
drawerConfig,
} = this.props;

const { alertReceiveChannelStore } = store;
Expand Down Expand Up @@ -227,6 +233,7 @@ class _IntegrationPage extends React.Component<IntegrationProps, IntegrationStat
alertReceiveChannel={alertReceiveChannel}
changeIsTemplateSettingsOpen={() => this.setState({ isTemplateSettingsOpen: true })}
isLegacyIntegration={isLegacyIntegration}
drawerConfig={drawerConfig}
/>
</div>

Expand Down Expand Up @@ -266,7 +273,10 @@ class _IntegrationPage extends React.Component<IntegrationProps, IntegrationStat
<Tabs
tabs={[
{ label: 'Incoming', content: incomingPart },
{ label: 'Outgoing', content: <OutgoingTab /> },
{
label: 'Outgoing',
content: <OutgoingTab openSnowConfigurationDrawer={() => drawerConfig.openDrawer('servicenow')} />,
},
]}
/>
) : (
Expand Down Expand Up @@ -807,6 +817,7 @@ interface IntegrationActionsProps {
isLegacyIntegration: boolean;
alertReceiveChannel: ApiSchemas['AlertReceiveChannel'];
changeIsTemplateSettingsOpen: () => void;
drawerConfig: ReturnType<typeof useDrawer<IntegrationDrawerKey>>;
}

type IntegrationDrawerKey = 'servicenow' | 'completeConfig';
Expand All @@ -815,6 +826,7 @@ const IntegrationActions: React.FC<IntegrationActionsProps> = ({
alertReceiveChannel,
isLegacyIntegration,
changeIsTemplateSettingsOpen,
drawerConfig,
}) => {
const store = useStore();
const { alertReceiveChannelStore } = store;
Expand Down Expand Up @@ -842,7 +854,7 @@ const IntegrationActions: React.FC<IntegrationActionsProps> = ({
alert_receive_channel_id: ApiSchemas['AlertReceiveChannel']['id'];
}>(undefined);

const { closeDrawer, openDrawer, getIsDrawerOpened } = useDrawer<IntegrationDrawerKey>();
const { closeDrawer, openDrawer, getIsDrawerOpened } = drawerConfig;

const { id } = alertReceiveChannel;

Expand Down Expand Up @@ -1274,4 +1286,4 @@ const IntegrationHeader: React.FC<IntegrationHeaderProps> = ({
}
};

export const IntegrationPage = withRouter(withMobXProviderContext(_IntegrationPage));
export const IntegrationPage = withRouter(withMobXProviderContext(withDrawer<IntegrationDrawerKey>(_IntegrationPage)));
11 changes: 5 additions & 6 deletions grafana-plugin/src/pages/integration/OutgoingTab/OutgoingTab.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';

import { useStyles2, Input, IconButton, Drawer, Badge, HorizontalGroup } from '@grafana/ui';
import { useStyles2, Input, IconButton, Drawer, HorizontalGroup } from '@grafana/ui';
import { observer } from 'mobx-react';

import { Button } from 'components/Button/Button';
Expand All @@ -19,7 +19,7 @@ import { OutgoingTabDrawerKey } from './OutgoingTab.types';
import { OutgoingWebhookDetailsDrawerTabs } from './OutgoingWebhookDetailsDrawerTabs';
import { OutgoingWebhooksTable } from './OutgoingWebhooksTable';

export const OutgoingTab = () => {
export const OutgoingTab = ({ openSnowConfigurationDrawer }: { openSnowConfigurationDrawer: () => void }) => {
const { openDrawer, closeDrawer, getIsDrawerOpened } = useDrawer<OutgoingTabDrawerKey>();
const styles = useStyles2(getStyles);

Expand All @@ -45,7 +45,7 @@ export const OutgoingTab = () => {
{
customIcon: 'plug',
startingElemPosition: '50%',
expandedView: () => <Connection />,
expandedView: () => <Connection openSnowConfigurationDrawer={openSnowConfigurationDrawer} />,
},
{
customIcon: 'plus',
Expand Down Expand Up @@ -79,9 +79,8 @@ export const OutgoingTab = () => {
);
};

const Connection = observer(() => {
const Connection = observer(({ openSnowConfigurationDrawer }: { openSnowConfigurationDrawer: () => void }) => {
const styles = useStyles2(getStyles);

const integration = useCurrentIntegration();
// TODO: remove casting once backend narrows down the types
const url = integration?.additional_settings?.instance_url as string;
Expand All @@ -94,7 +93,6 @@ const Connection = observer(() => {
heading={
<div className={styles.horizontalGroup}>
<IntegrationTag>ServiceNow connection</IntegrationTag>
<Badge text="OK" color="green" />
<Input
value={url}
disabled
Expand All @@ -118,6 +116,7 @@ const Connection = observer(() => {
name="cog"
aria-label="Open ServiceNow configuration"
className={styles.openConfigurationBtn}
onClick={openSnowConfigurationDrawer}
/>
</div>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
Field,
HorizontalGroup,
Icon,
Input,
Label,
Select,
Switch,
Expand All @@ -17,7 +16,7 @@ import cn from 'classnames';
import { Controller, useFormContext } from 'react-hook-form';

import { MonacoEditor } from 'components/MonacoEditor/MonacoEditor';
import { MONACO_READONLY_CONFIG } from 'components/MonacoEditor/MonacoEditor.config';
import { MONACO_EDITABLE_CONFIG, MONACO_READONLY_CONFIG } from 'components/MonacoEditor/MonacoEditor.config';
import { WebhooksTemplateEditor } from 'containers/WebhooksTemplateEditor/WebhooksTemplateEditor';
import { HTTP_METHOD_OPTIONS, WEBHOOK_TRIGGGER_TYPE_OPTIONS } from 'models/outgoing_webhook/outgoing_webhook.types';

Expand All @@ -37,7 +36,7 @@ interface OutgoingWebhookFormFieldsProps {

export const OutgoingWebhookFormFields: FC<OutgoingWebhookFormFieldsProps> = ({ webhookId }) => {
const styles = useStyles2(getStyles);
const { control, watch, formState, register } = useFormContext<OutgoingTabFormValues>();
const { control, watch, formState } = useFormContext<OutgoingTabFormValues>();
const [templateToEdit, setTemplateToEdit] = useState<TemplateToEdit>();

const [showTriggerTemplate] = watch(['triggerTemplateToogle']);
Expand Down Expand Up @@ -83,26 +82,6 @@ export const OutgoingWebhookFormFields: FC<OutgoingWebhookFormFieldsProps> = ({
</Field>
)}
/>
<Field
key="url"
invalid={Boolean(formState.errors.url)}
error={formState.errors.url?.message}
label={
<Label>
<span>Webhook URL</span>&nbsp;
<Tooltip content="Some description" placement="right">
<Icon name="info-circle" className={styles.infoIcon} />
</Tooltip>
</Label>
}
className={styles.selectField}
>
<Input
{...register('url', {
required: 'URL is required',
})}
/>
</Field>
<Controller
control={control}
name="http_method"
Expand Down Expand Up @@ -134,6 +113,52 @@ export const OutgoingWebhookFormFields: FC<OutgoingWebhookFormFieldsProps> = ({
</Field>
)}
/>
<Controller
control={control}
name="url"
render={({ field }) => (
<VerticalGroup>
<HorizontalGroup width="100%" justify="space-between">
<Label>
<span>Webhook URL</span>&nbsp;
<Tooltip content="Some description" placement="right">
<Icon name="info-circle" className={styles.infoIcon} />
</Tooltip>
</Label>
<Button
icon="edit"
variant="secondary"
onClick={() => {
setTemplateToEdit({
value: field.value,
displayName: 'webhook url',
name: field.name,
});
}}
/>
</HorizontalGroup>
<MonacoEditor
{...field}
data={{}} // TODO:update
showLineNumbers={false}
height={30}
monacoOptions={MONACO_EDITABLE_CONFIG}
onChange={field.onChange}
/>
{templateToEdit?.['name'] === field.name && (
<WebhooksTemplateEditor
id={webhookId}
handleSubmit={(value) => {
field.onChange(value);
setTemplateToEdit(undefined);
}}
onHide={() => setTemplateToEdit(undefined)}
template={templateToEdit}
/>
)}
</VerticalGroup>
)}
/>
<Controller
control={control}
name="data"
Expand Down
5 changes: 5 additions & 0 deletions grafana-plugin/src/state/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { AppPluginMeta, KeyValue } from '@grafana/data';

import { RootStore } from 'state/rootStore';
import { useDrawer } from 'utils/hooks';

export interface WithStoreProps {
store: RootStore;
}

export interface WithDrawerConfig<T extends string> {
drawerConfig: ReturnType<typeof useDrawer<T>>;
}

export interface PageProps<T extends KeyValue = KeyValue> {
meta: AppPluginMeta<T>;
query: KeyValue;
Expand Down
11 changes: 11 additions & 0 deletions grafana-plugin/src/utils/hoc.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';

import { useDrawer } from './hooks';

export const withDrawer = <T extends string>(Component: React.ComponentType<any>) => {
const ComponentWithDrawer = (props: any) => {
const drawerConfig = useDrawer<T>();
return <Component {...props} drawerConfig={drawerConfig} />;
};
return ComponentWithDrawer;
};

0 comments on commit 9256fbd

Please sign in to comment.