Templates&grouping tweaks&fixes (#2147)
# What this PR does Templates&grouping tweaks \ fixes - responsiveness fixes - changed new route default template to be comment instead - some other minor changes
This commit is contained in:
parent
1a6e30c249
commit
a3d9b181c3
13 changed files with 140 additions and 130 deletions
|
|
@ -1,19 +0,0 @@
|
|||
.hamburger-menu {
|
||||
cursor: pointer;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
||||
.hamburger-menu-withBackground {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
vertical-align: middle;
|
||||
justify-content: center;
|
||||
background-color: rgba(204, 204, 220, 0.16);
|
||||
border: 1px solid transparent;
|
||||
height: 32px;
|
||||
width: 30px;
|
||||
padding: 4px;
|
||||
cursor: pointer;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
.hamburgerMenu {
|
||||
cursor: pointer;
|
||||
color: var(--primary-text-color);
|
||||
|
||||
&--withBackground {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
vertical-align: middle;
|
||||
justify-content: center;
|
||||
background-color: rgba(204, 204, 220, 0.16);
|
||||
border: 1px solid transparent;
|
||||
height: 32px;
|
||||
width: 30px;
|
||||
padding: 4px;
|
||||
cursor: pointer;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
||||
&--small {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
vertical-align: middle;
|
||||
justify-content: center;
|
||||
background-color: rgba(204, 204, 220, 0.16);
|
||||
color: var(--secondary-background);
|
||||
border: 1px solid transparent;
|
||||
height: 24px;
|
||||
width: 22px;
|
||||
padding: 4px;
|
||||
cursor: pointer;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,12 +3,13 @@ import React, { useRef } from 'react';
|
|||
import { Icon } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
|
||||
import styles from './HamburgerMenu.module.css';
|
||||
import styles from './HamburgerMenu.module.scss';
|
||||
|
||||
interface HamburgerMenuProps {
|
||||
openMenu: React.MouseEventHandler<HTMLElement>;
|
||||
listWidth: number;
|
||||
listBorder: number;
|
||||
stopPropagation?: boolean;
|
||||
withBackground?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
|
@ -17,12 +18,16 @@ const cx = cn.bind(styles);
|
|||
|
||||
const HamburgerMenu: React.FC<HamburgerMenuProps> = (props) => {
|
||||
const ref = useRef<HTMLDivElement>();
|
||||
const { openMenu, listBorder, listWidth, withBackground, className } = props;
|
||||
const { openMenu, listBorder, listWidth, withBackground, className, stopPropagation = false } = props;
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={withBackground ? cx('hamburger-menu-withBackground') : cx('hamburger-menu', className)}
|
||||
onClick={() => {
|
||||
className={withBackground ? cx('hamburgerMenu--withBackground') : cx('hamburgerMenu', className)}
|
||||
onClick={(e) => {
|
||||
if (stopPropagation) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
const boundingRect = ref.current.getBoundingClientRect();
|
||||
|
||||
openMenu({
|
||||
|
|
|
|||
|
|
@ -29,13 +29,9 @@ const CollapsedIntegrationRouteDisplay: React.FC<CollapsedIntegrationRouteDispla
|
|||
const store = useStore();
|
||||
const { escalationChainStore, alertReceiveChannelStore, telegramChannelStore } = store;
|
||||
const [routeIdForDeletion, setRouteIdForDeletion] = useState<ChannelFilter['id']>(undefined);
|
||||
const [telegramInfo, setTelegramInfo] = useState<Array<{ id: string; channel_name: string }>>([]);
|
||||
|
||||
useEffect(() => {
|
||||
(async function () {
|
||||
const telegram = await telegramChannelStore.getAll();
|
||||
setTelegramInfo(telegram);
|
||||
})();
|
||||
telegramChannelStore.updateItems();
|
||||
}, [channelFilterId]);
|
||||
|
||||
const channelFilter = alertReceiveChannelStore.channelFilters[channelFilterId];
|
||||
|
|
@ -91,7 +87,7 @@ const CollapsedIntegrationRouteDisplay: React.FC<CollapsedIntegrationRouteDispla
|
|||
content={
|
||||
<div className={cx('spacing')}>
|
||||
<VerticalGroup>
|
||||
{IntegrationHelper.getChatOpsChannels(channelFilter, telegramInfo, store)
|
||||
{IntegrationHelper.getChatOpsChannels(channelFilter, store)
|
||||
.filter((it) => it)
|
||||
.map((chatOpsChannel, key) => (
|
||||
<HorizontalGroup key={key}>
|
||||
|
|
|
|||
|
|
@ -32,19 +32,3 @@
|
|||
background: var(--gray-9);
|
||||
}
|
||||
}
|
||||
|
||||
.hamburgerMenu-small {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
vertical-align: middle;
|
||||
justify-content: center;
|
||||
background-color: rgba(204, 204, 220, 0.16);
|
||||
color: var(--secondary-background);
|
||||
border: 1px solid transparent;
|
||||
height: 24px;
|
||||
width: 22px;
|
||||
padding: 4px;
|
||||
cursor: pointer;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ import { UserActions } from 'utils/authorization';
|
|||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
const ACTIONS_LIST_WIDTH = 200;
|
||||
const ACTIONS_LIST_BORDER = 2;
|
||||
|
||||
interface ExpandedIntegrationRouteDisplayProps {
|
||||
alertReceiveChannelId: AlertReceiveChannel['id'];
|
||||
channelFilterId: ChannelFilter['id'];
|
||||
|
|
@ -83,7 +86,7 @@ const ExpandedIntegrationRouteDisplay: React.FC<ExpandedIntegrationRouteDisplayP
|
|||
|
||||
useEffect(() => {
|
||||
setIsLoading(true);
|
||||
Promise.all([escalationChainStore.updateItems(), telegramChannelStore.updateTelegramChannels()]).then(() =>
|
||||
Promise.all([escalationChainStore.updateItems(), telegramChannelStore.updateItems()]).then(() =>
|
||||
setIsLoading(false)
|
||||
);
|
||||
}, []);
|
||||
|
|
@ -168,12 +171,14 @@ const ExpandedIntegrationRouteDisplay: React.FC<ExpandedIntegrationRouteDisplayP
|
|||
</IntegrationBlockItem>
|
||||
)}
|
||||
|
||||
<IntegrationBlockItem>
|
||||
<VerticalGroup spacing="md">
|
||||
<Text type="primary">Publish to ChatOps</Text>
|
||||
<ChatOpsConnectors channelFilterId={channelFilterId} showLineNumber={false} />
|
||||
</VerticalGroup>
|
||||
</IntegrationBlockItem>
|
||||
{IntegrationHelper.hasChatopsInstalled(store) && (
|
||||
<IntegrationBlockItem>
|
||||
<VerticalGroup spacing="md">
|
||||
<Text type="primary">Publish to ChatOps</Text>
|
||||
<ChatOpsConnectors channelFilterId={channelFilterId} showLineNumber={false} />
|
||||
</VerticalGroup>
|
||||
</IntegrationBlockItem>
|
||||
)}
|
||||
|
||||
<IntegrationBlockItem>
|
||||
<VerticalGroup>
|
||||
|
|
@ -363,15 +368,20 @@ export const RouteButtonsDisplay: React.FC<RouteButtonsDisplayProps> = ({
|
|||
)}
|
||||
>
|
||||
{({ openMenu }) => (
|
||||
<HamburgerMenu openMenu={openMenu} listBorder={2} listWidth={200} className={cx('hamburgerMenu-small')} />
|
||||
<HamburgerMenu
|
||||
openMenu={openMenu}
|
||||
listBorder={ACTIONS_LIST_BORDER}
|
||||
listWidth={ACTIONS_LIST_WIDTH}
|
||||
className={'hamburgerMenu--small'}
|
||||
stopPropagation={true}
|
||||
/>
|
||||
)}
|
||||
</WithContextMenu>
|
||||
)}
|
||||
</HorizontalGroup>
|
||||
);
|
||||
|
||||
function onDelete(e: React.SyntheticEvent) {
|
||||
e.stopPropagation();
|
||||
function onDelete() {
|
||||
setRouteIdForDeletion();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,23 +32,32 @@
|
|||
min-width: min-content;
|
||||
}
|
||||
|
||||
.template-block-list,
|
||||
.template-block-codeeditor {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.template-block-list,
|
||||
.template-block-codeeditor,
|
||||
.template-block-result,
|
||||
.result {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.template-block-list {
|
||||
width: 30%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.template-block-codeeditor {
|
||||
width: 40%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.template-block-result {
|
||||
width: 30%;
|
||||
height: 100%;
|
||||
overflow-y: scroll !important;
|
||||
}
|
||||
|
||||
.result {
|
||||
padding-left: 16px;
|
||||
padding-bottom: 60px;
|
||||
}
|
||||
|
||||
.template-block-codeeditor div[aria-label='Code editor container'] {
|
||||
|
|
@ -25,7 +25,7 @@ import { openErrorNotification } from 'utils';
|
|||
import { waitForElement } from 'utils/DOM';
|
||||
import LocationHelper from 'utils/LocationHelper';
|
||||
|
||||
import styles from './IntegrationTemplate.module.css';
|
||||
import styles from './IntegrationTemplate.module.scss';
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
.template-block-list {
|
||||
width: 30%;
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.alert-group-payload-view {
|
||||
|
|
|
|||
|
|
@ -41,13 +41,13 @@ const TemplatesAlertGroupsList = (props: TemplatesAlertGroupsListProps) => {
|
|||
}, []);
|
||||
|
||||
const getCodeEditorHeight = () => {
|
||||
const mainDiv = document.getElementById('content-container-id');
|
||||
const mainDiv = document.getElementById('alerts-content-container-id');
|
||||
const height = mainDiv?.getBoundingClientRect().height - HEADER_OF_CONTAINER_HEIGHT;
|
||||
return `${height}px`;
|
||||
};
|
||||
|
||||
const getCodeEditorHeightWithBadge = () => {
|
||||
const mainDiv = document.getElementById('content-container-id');
|
||||
const mainDiv = document.getElementById('alerts-content-container-id');
|
||||
const height = mainDiv?.getBoundingClientRect().height - HEADER_OF_CONTAINER_HEIGHT - BADGE_WITH_PADDINGS_HEIGHT;
|
||||
return `${height}px`;
|
||||
};
|
||||
|
|
@ -80,7 +80,7 @@ const TemplatesAlertGroupsList = (props: TemplatesAlertGroupsListProps) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className={cx('template-block-list')} id="content-container-id">
|
||||
<div className={cx('template-block-list')} id="alerts-content-container-id">
|
||||
{selectedAlertPayload ? (
|
||||
<>
|
||||
{isEditMode ? (
|
||||
|
|
|
|||
|
|
@ -72,23 +72,30 @@ const IntegrationHelper = {
|
|||
return totalDiffString;
|
||||
},
|
||||
|
||||
getChatOpsChannels(
|
||||
channelFilter: ChannelFilter,
|
||||
telegramInfo: Array<{ id: string; channel_name: string }>,
|
||||
store: RootStore
|
||||
): Array<{ name: string; icon: IconName }> {
|
||||
const channels: Array<{ name: string; icon: IconName }> = [];
|
||||
hasChatopsInstalled(store: RootStore) {
|
||||
const hasSlack = Boolean(store.teamStore.currentTeam?.slack_team_identity);
|
||||
const hasTelegram =
|
||||
store.hasFeature(AppFeature.Telegram) && store.telegramChannelStore.currentTeamToTelegramChannel?.length > 0;
|
||||
return hasSlack || hasTelegram;
|
||||
},
|
||||
|
||||
if (
|
||||
store.hasFeature(AppFeature.Slack) &&
|
||||
channelFilter.notify_in_slack &&
|
||||
channelFilter.notify_in_slack &&
|
||||
channelFilter.slack_channel?.display_name
|
||||
) {
|
||||
channels.push({ name: channelFilter.slack_channel.display_name, icon: 'slack' });
|
||||
getChatOpsChannels(channelFilter: ChannelFilter, store: RootStore): Array<{ name: string; icon: IconName }> {
|
||||
const channels: Array<{ name: string; icon: IconName }> = [];
|
||||
const telegram = Object.keys(store.telegramChannelStore.items).map((k) => store.telegramChannelStore.items[k]);
|
||||
|
||||
if (store.hasFeature(AppFeature.Slack) && channelFilter.notify_in_slack) {
|
||||
const matchingSlackChannel = store.teamStore.currentTeam?.slack_channel?.id
|
||||
? store.slackChannelStore.items[store.teamStore.currentTeam.slack_channel?.id]
|
||||
: undefined;
|
||||
if (channelFilter.slack_channel?.display_name || matchingSlackChannel?.display_name) {
|
||||
channels.push({
|
||||
name: channelFilter.slack_channel?.display_name || matchingSlackChannel?.display_name,
|
||||
icon: 'slack',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const matchingTelegram = telegramInfo?.find((t) => t.id === channelFilter.telegram_channel);
|
||||
const matchingTelegram = telegram.find((t) => t.id === channelFilter.telegram_channel);
|
||||
|
||||
if (
|
||||
store.hasFeature(AppFeature.Telegram) &&
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ import { openNotification, openErrorNotification } from 'utils';
|
|||
import { getVar } from 'utils/DOM';
|
||||
import LocationHelper from 'utils/LocationHelper';
|
||||
import { UserActions } from 'utils/authorization';
|
||||
import { DATASOURCE_GRAFANA, PLUGIN_ROOT } from 'utils/consts';
|
||||
import { PLUGIN_ROOT } from 'utils/consts';
|
||||
import sanitize from 'utils/sanitize';
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
|
@ -86,7 +86,7 @@ interface Integration2State extends PageBaseState {
|
|||
|
||||
const ACTIONS_LIST_WIDTH = 200;
|
||||
const ACTIONS_LIST_BORDER = 2;
|
||||
const NEW_ROUTE_DEFAULT = '{{ (payload.severity == "foo" and "bar" in payload.region) or True }}';
|
||||
const NEW_ROUTE_DEFAULT = '{# (payload.severity == "foo" and "bar" in payload.region) or True #}';
|
||||
|
||||
@observer
|
||||
class Integration2 extends React.Component<Integration2Props, Integration2State> {
|
||||
|
|
@ -603,9 +603,8 @@ const IntegrationSendDemoPayloadModal: React.FC<IntegrationSendDemoPayloadModalP
|
|||
}) => {
|
||||
const store = useStore();
|
||||
const { alertReceiveChannelStore } = store;
|
||||
const stringifiedJson = JSON.stringify(alertReceiveChannel.demo_alert_payload, null, 2);
|
||||
const initialDemoJSON = stringifiedJson.substring(1, stringifiedJson.length - 1);
|
||||
const [demoPayload, setDemoPayload] = useState<string>(alertReceiveChannel.demo_alert_payload);
|
||||
const initialDemoJSON = JSON.stringify(alertReceiveChannel.demo_alert_payload, null, 2);
|
||||
const [demoPayload, setDemoPayload] = useState<string>(initialDemoJSON);
|
||||
let onPayloadChangeDebounced = debounce(100, onPayloadChange);
|
||||
|
||||
return (
|
||||
|
|
@ -916,8 +915,6 @@ const IntegrationActions: React.FC<IntegrationActionsProps> = ({ alertReceiveCha
|
|||
const HowToConnectComponent: React.FC<{ id: AlertReceiveChannel['id'] }> = ({ id }) => {
|
||||
const { alertReceiveChannelStore } = useStore();
|
||||
const alertReceiveChannelCounter = alertReceiveChannelStore.counters[id];
|
||||
const alertReceiveChannel = alertReceiveChannelStore.items[id];
|
||||
const isGrafanaDatasource = alertReceiveChannel.integration === DATASOURCE_GRAFANA;
|
||||
const hasAlerts = !!alertReceiveChannelCounter?.alerts_count;
|
||||
|
||||
return (
|
||||
|
|
@ -949,7 +946,7 @@ const HowToConnectComponent: React.FC<{ id: AlertReceiveChannel['id'] }> = ({ id
|
|||
</a>
|
||||
</div>
|
||||
}
|
||||
content={isGrafanaDatasource || !hasAlerts ? renderContent() : null}
|
||||
content={hasAlerts ? null : renderContent()}
|
||||
/>
|
||||
);
|
||||
|
||||
|
|
@ -963,20 +960,6 @@ const HowToConnectComponent: React.FC<{ id: AlertReceiveChannel['id'] }> = ({ id
|
|||
<Text type={'primary'}>No alerts yet; try to send a demo alert</Text>
|
||||
</HorizontalGroup>
|
||||
)}
|
||||
|
||||
{isGrafanaDatasource && (
|
||||
<HorizontalGroup spacing={'xs'}>
|
||||
<Icon name="list-ui-alt" size="md" />
|
||||
<a href={`/alerting/notifications?alertmanager=grafana`} target="_blank" rel="noreferrer">
|
||||
<Text type={'link'}>Contact Point</Text>
|
||||
</a>
|
||||
<Text type={'secondary'}>and</Text>
|
||||
<a href="/alerting/routes?alertmanager=grafana" target="_blank">
|
||||
<Text type={'link'}>Notification Policy</Text>
|
||||
</a>
|
||||
<Text type={'secondary'}>created in Grafana Alerting</Text>
|
||||
</HorizontalGroup>
|
||||
)}
|
||||
</VerticalGroup>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -414,36 +414,34 @@ class Integrations extends React.Component<IntegrationsProps, IntegrationsState>
|
|||
<div className="thin-line-break" />
|
||||
|
||||
<WithPermissionControlTooltip key="delete" userAction={UserActions.IntegrationsWrite}>
|
||||
<>
|
||||
<div className={cx('integrations-actionItem')}>
|
||||
<div
|
||||
onClick={() => {
|
||||
this.setState({
|
||||
confirmationModal: {
|
||||
isOpen: true,
|
||||
confirmText: 'Delete',
|
||||
dismissText: 'Cancel',
|
||||
onConfirm: () => this.handleDeleteAlertReceiveChannel(item.id),
|
||||
title: 'Delete integration',
|
||||
body: (
|
||||
<Text type="primary">
|
||||
Are you sure you want to delete <Emoji text={item.verbal_name} /> integration?
|
||||
</Text>
|
||||
),
|
||||
},
|
||||
});
|
||||
}}
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
<Text type="danger">
|
||||
<HorizontalGroup spacing={'xs'}>
|
||||
<Icon name="trash-alt" />
|
||||
<span>Delete Integration</span>
|
||||
</HorizontalGroup>
|
||||
</Text>
|
||||
</div>
|
||||
<div className={cx('integrations-actionItem')}>
|
||||
<div
|
||||
onClick={() => {
|
||||
this.setState({
|
||||
confirmationModal: {
|
||||
isOpen: true,
|
||||
confirmText: 'Delete',
|
||||
dismissText: 'Cancel',
|
||||
onConfirm: () => this.handleDeleteAlertReceiveChannel(item.id),
|
||||
title: 'Delete integration',
|
||||
body: (
|
||||
<Text type="primary">
|
||||
Are you sure you want to delete <Emoji text={item.verbal_name} /> integration?
|
||||
</Text>
|
||||
),
|
||||
},
|
||||
});
|
||||
}}
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
<Text type="danger">
|
||||
<HorizontalGroup spacing={'xs'}>
|
||||
<Icon name="trash-alt" />
|
||||
<span>Delete Integration</span>
|
||||
</HorizontalGroup>
|
||||
</Text>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
</WithPermissionControlTooltip>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue