Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow routing via labels on the Integration page (#3850)
Browse files Browse the repository at this point in the history
# What this PR does

Adds label routing on the UI


![image](https://github.com/user-attachments/assets/f63c11f0-595d-40bf-80be-4e6cbc10a6ea)


![image](https://github.com/user-attachments/assets/2bbdc8b9-0f0d-447d-a4e4-9e9768ed98bf)

## Which issue(s) this PR fixes

Related to grafana/oncall-private#2461

---------

Co-authored-by: Matias Bordese <[email protected]>
teodosii and matiasb authored Jul 15, 2024
1 parent df9494a commit ff7ffa9
Showing 33 changed files with 557 additions and 155 deletions.
8 changes: 0 additions & 8 deletions src/assets/style/utils.css
Original file line number Diff line number Diff line change
@@ -138,14 +138,6 @@
padding-bottom: 24px;
}

/* -----
* Icons
*/

.icon-exclamation {
color: var(--error-text-color);
}

.loadingPlaceholder {
margin-bottom: 0;
margin-right: 4px;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { COLORS } from 'styles/utils.styles';
import { Colors } from 'styles/utils.styles';

export const getIntegrationCollapsibleTreeStyles = (theme: GrafanaTheme2) => {
return {
@@ -54,7 +54,7 @@ export const getIntegrationCollapsibleTreeStyles = (theme: GrafanaTheme2) => {
position: absolute;
top: 0;
left: -30px;
color: ${COLORS.ALWAYS_GREY};
color: ${Colors.ALWAYS_GREY};
width: 28px;
height: 28px;
text-align: center;
@@ -70,7 +70,7 @@ export const getIntegrationCollapsibleTreeStyles = (theme: GrafanaTheme2) => {
path {
// this will overwrite all icons below to be gray
fill: ${COLORS.ALWAYS_GREY};
fill: ${Colors.ALWAYS_GREY};
}
`,

Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ import CopyToClipboard from 'react-copy-to-clipboard';
import Emoji from 'react-emoji-render';
import { debounce } from 'throttle-debounce';

import { MonacoEditor, MONACO_LANGUAGE } from 'components/MonacoEditor/MonacoEditor';
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';
@@ -74,7 +74,7 @@ export const IntegrationSendDemoAlertModal: React.FC<IntegrationSendDemoPayloadM
disabled={true}
height={`60vh`}
useAutoCompleteList={false}
language={MONACO_LANGUAGE.json}
language={MonacoLanguage.json}
data={undefined}
monacoOptions={MONACO_EDITABLE_CONFIG}
showLineNumbers={false}
33 changes: 32 additions & 1 deletion src/components/LabelsTooltipBadge/LabelsTooltipBadge.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React, { FC } from 'react';

import { LabelTag } from '@grafana/labels';
import { VerticalGroup, HorizontalGroup, Button } from '@grafana/ui';
import { VerticalGroup, HorizontalGroup, Button, Tooltip } from '@grafana/ui';

import { RenderConditionally } from 'components/RenderConditionally/RenderConditionally';
import { TooltipBadge } from 'components/TooltipBadge/TooltipBadge';
import { LabelKeyValue } from 'models/label/label.types';
import { components } from 'network/oncall-api/autogenerated-api.types';

interface LabelsTooltipBadgeProps {
labels: LabelKeyValue[];
@@ -36,3 +38,32 @@ export const LabelsTooltipBadge: FC<LabelsTooltipBadgeProps> = ({ labels, onClic
}
/>
) : null;

interface LabelBadgesProps {
labels: Array<components['schemas']['LabelPair']>;
maxCount?: number;
}

export const LabelBadges: React.FC<LabelBadgesProps> = ({ labels = [], maxCount = 3 }) => {
const renderer = (values: LabelBadgesProps['labels']) => {
return (
<HorizontalGroup>
{values.map((label) => (
<LabelTag key={label.key.id} label={label.key.name} value={label.value.name} />
))}
</HorizontalGroup>
);
};

return (
<HorizontalGroup spacing="sm">
{renderer(labels.slice(0, maxCount))}

<RenderConditionally shouldRender={labels.length > maxCount}>
<Tooltip content={renderer(labels.slice(maxCount))}>
<div>{labels.length > maxCount ? `+ ${labels.length - maxCount}` : ``}</div>
</Tooltip>
</RenderConditionally>
</HorizontalGroup>
);
};
8 changes: 4 additions & 4 deletions src/components/MonacoEditor/MonacoEditor.tsx
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ interface MonacoEditorProps {
data: any;
showLineNumbers?: boolean;
useAutoCompleteList?: boolean;
language?: MONACO_LANGUAGE;
language?: MonacoLanguage;
onChange?: (value: string) => void;
loading?: boolean;
monacoOptions?: any;
@@ -26,7 +26,7 @@ interface MonacoEditorProps {
codeEditorProps?: Partial<ComponentProps<typeof CodeEditor>>;
}

export enum MONACO_LANGUAGE {
export enum MonacoLanguage {
json = 'json',
jinja2 = 'jinja2',
}
@@ -46,7 +46,7 @@ export const MonacoEditor: FC<MonacoEditorProps> = (props) => {
onChange,
disabled,
data,
language = MONACO_LANGUAGE.jinja2,
language = MonacoLanguage.jinja2,
useAutoCompleteList = true,
focus = true,
height = '130px',
@@ -79,7 +79,7 @@ export const MonacoEditor: FC<MonacoEditorProps> = (props) => {
editor.focus();
}

if (language === MONACO_LANGUAGE.jinja2) {
if (language === MonacoLanguage.jinja2) {
const jinja2Lang = monaco.languages.getLanguages().find((l: { id: string }) => l.id === 'jinja2');
if (!jinja2Lang) {
monaco.languages.register({ id: 'jinja2' });
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { COLORS } from 'styles/utils.styles';
import { Colors } from 'styles/utils.styles';

const radius = '2px' as string;

@@ -30,7 +30,7 @@ export const getScheduleQualityProgressBarStyles = (theme: GrafanaTheme2) => {
`,

row: css`
background-color: ${COLORS.GRAY_8};
background-color: ${Colors.GRAY_8};
&:first-child,
&:first-child > .bar {
4 changes: 2 additions & 2 deletions src/components/Text/Text.styles.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { COLORS } from 'styles/utils.styles';
import { Colors } from 'styles/utils.styles';

export const getTextStyles = (theme: GrafanaTheme2) => {
return {
@@ -38,7 +38,7 @@ export const getTextStyles = (theme: GrafanaTheme2) => {
}
&--success {
color: ${COLORS.GREEN_5};
color: ${Colors.GREEN_5};
}
&--strong {
4 changes: 2 additions & 2 deletions src/components/UserGroups/UserGroups.styles.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { COLORS } from 'styles/utils.styles';
import { Colors } from 'styles/utils.styles';

export const getUserGroupStyles = (theme: GrafanaTheme2) => {
return {
@@ -59,7 +59,7 @@ export const getUserGroupStyles = (theme: GrafanaTheme2) => {

icon: css`
display: block;
color: ${COLORS.ALWAYS_GREY};
color: ${Colors.ALWAYS_GREY};
&:hover {
color: #fff;
2 changes: 1 addition & 1 deletion src/containers/ColumnsSelectorWrapper/ColumnsModal.tsx
Original file line number Diff line number Diff line change
@@ -159,7 +159,7 @@ export const ColumnsModal: React.FC<ColumnsModalProps> = observer(
{values.slice(0, 2).map((val) => (
<LabelTag label={keyName} value={val.name} key={val.id} />
))}
<div className={styles.totalValuesCount}>{values.length > 2 ? `+ ${values.length - 2}` : ``}</div>
<div>{values.length > 2 ? `+ ${values.length - 2}` : ``}</div>
</HorizontalGroup>
);
}
Original file line number Diff line number Diff line change
@@ -21,9 +21,6 @@ export const getColumnsSelectorWrapperStyles = (theme: GrafanaTheme2) => {
removalModal: css`
max-width: 500px;
`,
totalValuesCount: css`
margin-left: 16px;
`,
valuesBlock: css`
margin-bottom: 12px;
`,
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@
display: flex;
white-space: nowrap;
flex-direction: row;
gap: 4px;
gap: 8px;
}

&__item--large {
Original file line number Diff line number Diff line change
@@ -7,9 +7,9 @@ import { observer } from 'mobx-react';
import { IntegrationBlock } from 'components/Integrations/IntegrationBlock';
import { PluginLink } from 'components/PluginLink/PluginLink';
import { Text } from 'components/Text/Text';
import { TooltipBadge } from 'components/TooltipBadge/TooltipBadge';
import styles from 'containers/IntegrationContainers/CollapsedIntegrationRouteDisplay/CollapsedIntegrationRouteDisplay.module.scss';
import { RouteButtonsDisplay } from 'containers/IntegrationContainers/ExpandedIntegrationRouteDisplay/ExpandedIntegrationRouteDisplay';
import { RouteHeading } from 'containers/IntegrationContainers/RouteHeading';
import { ChannelFilter } from 'models/channel_filter/channel_filter.types';
import { ApiSchemas } from 'network/oncall-api/api.types';
import { CommonIntegrationHelper } from 'pages/integration/CommonIntegration.helper';
@@ -70,34 +70,13 @@ export const CollapsedIntegrationRouteDisplay: React.FC<CollapsedIntegrationRout
toggle={toggle}
heading={
<div className={cx('heading-container')}>
<div className={cx('heading-container__item', 'heading-container__item--large')}>
<TooltipBadge
borderType="success"
text={routeWording}
tooltipTitle={CommonIntegrationHelper.getRouteConditionTooltipWording(
alertReceiveChannelStore.channelFilterIds[alertReceiveChannelId],
routeIndex
)}
className={cx('u-margin-right-xs')}
tooltipContent={undefined}
/>
{routeWording === 'Default' && <Text type="secondary">Unmatched alerts routed to default route</Text>}
{routeWording !== 'Default' &&
(channelFilter.filtering_term ? (
<Text type="primary" className={cx('heading-container__text')}>
{channelFilter.filtering_term}
</Text>
) : (
<>
<div className={cx('icon-exclamation')}>
<Icon name="exclamation-triangle" />
</div>
<Text type="primary" className={cx('heading-container__text')}>
Routing template not set
</Text>
</>
))}
</div>
<RouteHeading
className={cx('heading-container__item', 'heading-container__item--large')}
routeWording={routeWording}
routeIndex={routeIndex}
channelFilter={channelFilter}
channelFilterIds={alertReceiveChannelStore.channelFilterIds[alertReceiveChannelId]}
/>

<div className={cx('heading-container__item')}>
<RouteButtonsDisplay
Original file line number Diff line number Diff line change
@@ -6,6 +6,10 @@
}
}

.field {
margin-bottom: 0;
}

.routing-alert {
width: 765px;
}
@@ -47,3 +51,42 @@
.default-route-view {
min-height: 40px;
}

.block {
width: 100%;
background-color: var(--background-secondary);
border: var(--border-medium) !important;
}

.labels-panel {
display: flex;
width: 100%;
justify-content: space-between;
}

.heading-container {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
overflow: hidden;
gap: 12px;

&__item {
display: flex;
white-space: nowrap;
flex-direction: row;
gap: 8px;
}

&__item--large {
flex-grow: 1;
overflow: hidden;
}

&__text {
overflow: hidden;
max-width: calc(100% - 48px);
text-overflow: ellipsis;
}
}
Loading

0 comments on commit ff7ffa9

Please sign in to comment.