From a3d9b181c349eb996fcb504ba64f604524ef47d2 Mon Sep 17 00:00:00 2001 From: Rares Mardare Date: Fri, 9 Jun 2023 12:56:21 +0300 Subject: [PATCH] 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 --- .../HamburgerMenu/HamburgerMenu.module.css | 19 ------- .../HamburgerMenu/HamburgerMenu.module.scss | 35 ++++++++++++ .../HamburgerMenu/HamburgerMenu.tsx | 13 +++-- .../CollapsedIntegrationRouteDisplay.tsx | 8 +-- ...xpandedIntegrationRouteDisplay.module.scss | 16 ------ .../ExpandedIntegrationRouteDisplay.tsx | 30 ++++++---- ...le.css => IntegrationTemplate.module.scss} | 21 +++++-- .../IntegrationTemplate.tsx | 2 +- .../TemplatesAlertGroupsList.module.css | 2 + .../TemplatesAlertGroupsList.tsx | 6 +- .../integration_2/Integration2.helper.ts | 35 +++++++----- .../src/pages/integration_2/Integration2.tsx | 27 ++------- .../pages/integrations_2/Integrations2.tsx | 56 +++++++++---------- 13 files changed, 140 insertions(+), 130 deletions(-) delete mode 100644 grafana-plugin/src/components/HamburgerMenu/HamburgerMenu.module.css create mode 100644 grafana-plugin/src/components/HamburgerMenu/HamburgerMenu.module.scss rename grafana-plugin/src/containers/IntegrationTemplate/{IntegrationTemplate.module.css => IntegrationTemplate.module.scss} (77%) diff --git a/grafana-plugin/src/components/HamburgerMenu/HamburgerMenu.module.css b/grafana-plugin/src/components/HamburgerMenu/HamburgerMenu.module.css deleted file mode 100644 index 0a753b7d..00000000 --- a/grafana-plugin/src/components/HamburgerMenu/HamburgerMenu.module.css +++ /dev/null @@ -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); -} diff --git a/grafana-plugin/src/components/HamburgerMenu/HamburgerMenu.module.scss b/grafana-plugin/src/components/HamburgerMenu/HamburgerMenu.module.scss new file mode 100644 index 00000000..2331838b --- /dev/null +++ b/grafana-plugin/src/components/HamburgerMenu/HamburgerMenu.module.scss @@ -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); + } +} diff --git a/grafana-plugin/src/components/HamburgerMenu/HamburgerMenu.tsx b/grafana-plugin/src/components/HamburgerMenu/HamburgerMenu.tsx index 7b7c1b48..02937ad6 100644 --- a/grafana-plugin/src/components/HamburgerMenu/HamburgerMenu.tsx +++ b/grafana-plugin/src/components/HamburgerMenu/HamburgerMenu.tsx @@ -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; listWidth: number; listBorder: number; + stopPropagation?: boolean; withBackground?: boolean; className?: string; } @@ -17,12 +18,16 @@ const cx = cn.bind(styles); const HamburgerMenu: React.FC = (props) => { const ref = useRef(); - const { openMenu, listBorder, listWidth, withBackground, className } = props; + const { openMenu, listBorder, listWidth, withBackground, className, stopPropagation = false } = props; return (
{ + className={withBackground ? cx('hamburgerMenu--withBackground') : cx('hamburgerMenu', className)} + onClick={(e) => { + if (stopPropagation) { + e.stopPropagation(); + } + const boundingRect = ref.current.getBoundingClientRect(); openMenu({ diff --git a/grafana-plugin/src/containers/IntegrationContainers/CollapsedIntegrationRouteDisplay/CollapsedIntegrationRouteDisplay.tsx b/grafana-plugin/src/containers/IntegrationContainers/CollapsedIntegrationRouteDisplay/CollapsedIntegrationRouteDisplay.tsx index 3c9fd4af..2a712ec1 100644 --- a/grafana-plugin/src/containers/IntegrationContainers/CollapsedIntegrationRouteDisplay/CollapsedIntegrationRouteDisplay.tsx +++ b/grafana-plugin/src/containers/IntegrationContainers/CollapsedIntegrationRouteDisplay/CollapsedIntegrationRouteDisplay.tsx @@ -29,13 +29,9 @@ const CollapsedIntegrationRouteDisplay: React.FC(undefined); - const [telegramInfo, setTelegramInfo] = useState>([]); 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 - {IntegrationHelper.getChatOpsChannels(channelFilter, telegramInfo, store) + {IntegrationHelper.getChatOpsChannels(channelFilter, store) .filter((it) => it) .map((chatOpsChannel, key) => ( diff --git a/grafana-plugin/src/containers/IntegrationContainers/ExpandedIntegrationRouteDisplay/ExpandedIntegrationRouteDisplay.module.scss b/grafana-plugin/src/containers/IntegrationContainers/ExpandedIntegrationRouteDisplay/ExpandedIntegrationRouteDisplay.module.scss index 72c5715b..e28cf7d1 100644 --- a/grafana-plugin/src/containers/IntegrationContainers/ExpandedIntegrationRouteDisplay/ExpandedIntegrationRouteDisplay.module.scss +++ b/grafana-plugin/src/containers/IntegrationContainers/ExpandedIntegrationRouteDisplay/ExpandedIntegrationRouteDisplay.module.scss @@ -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); -} diff --git a/grafana-plugin/src/containers/IntegrationContainers/ExpandedIntegrationRouteDisplay/ExpandedIntegrationRouteDisplay.tsx b/grafana-plugin/src/containers/IntegrationContainers/ExpandedIntegrationRouteDisplay/ExpandedIntegrationRouteDisplay.tsx index d57242dc..2569d2f0 100644 --- a/grafana-plugin/src/containers/IntegrationContainers/ExpandedIntegrationRouteDisplay/ExpandedIntegrationRouteDisplay.tsx +++ b/grafana-plugin/src/containers/IntegrationContainers/ExpandedIntegrationRouteDisplay/ExpandedIntegrationRouteDisplay.tsx @@ -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 { 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 )} - - - Publish to ChatOps - - - + {IntegrationHelper.hasChatopsInstalled(store) && ( + + + Publish to ChatOps + + + + )} @@ -363,15 +368,20 @@ export const RouteButtonsDisplay: React.FC = ({ )} > {({ openMenu }) => ( - + )} )} ); - function onDelete(e: React.SyntheticEvent) { - e.stopPropagation(); + function onDelete() { setRouteIdForDeletion(); } diff --git a/grafana-plugin/src/containers/IntegrationTemplate/IntegrationTemplate.module.css b/grafana-plugin/src/containers/IntegrationTemplate/IntegrationTemplate.module.scss similarity index 77% rename from grafana-plugin/src/containers/IntegrationTemplate/IntegrationTemplate.module.css rename to grafana-plugin/src/containers/IntegrationTemplate/IntegrationTemplate.module.scss index e7a7639c..6fdee1ab 100644 --- a/grafana-plugin/src/containers/IntegrationTemplate/IntegrationTemplate.module.css +++ b/grafana-plugin/src/containers/IntegrationTemplate/IntegrationTemplate.module.scss @@ -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'] { diff --git a/grafana-plugin/src/containers/IntegrationTemplate/IntegrationTemplate.tsx b/grafana-plugin/src/containers/IntegrationTemplate/IntegrationTemplate.tsx index 0919c6fd..dbdd67d9 100644 --- a/grafana-plugin/src/containers/IntegrationTemplate/IntegrationTemplate.tsx +++ b/grafana-plugin/src/containers/IntegrationTemplate/IntegrationTemplate.tsx @@ -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); diff --git a/grafana-plugin/src/containers/TemplatesAlertGroupsList/TemplatesAlertGroupsList.module.css b/grafana-plugin/src/containers/TemplatesAlertGroupsList/TemplatesAlertGroupsList.module.css index cc05ca2c..237640a8 100644 --- a/grafana-plugin/src/containers/TemplatesAlertGroupsList/TemplatesAlertGroupsList.module.css +++ b/grafana-plugin/src/containers/TemplatesAlertGroupsList/TemplatesAlertGroupsList.module.css @@ -7,6 +7,8 @@ .template-block-list { width: 30%; height: 100%; + max-width: 100%; + overflow-y: hidden; } .alert-group-payload-view { diff --git a/grafana-plugin/src/containers/TemplatesAlertGroupsList/TemplatesAlertGroupsList.tsx b/grafana-plugin/src/containers/TemplatesAlertGroupsList/TemplatesAlertGroupsList.tsx index 1033a26d..3b96fc9a 100644 --- a/grafana-plugin/src/containers/TemplatesAlertGroupsList/TemplatesAlertGroupsList.tsx +++ b/grafana-plugin/src/containers/TemplatesAlertGroupsList/TemplatesAlertGroupsList.tsx @@ -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 ( -
+
{selectedAlertPayload ? ( <> {isEditMode ? ( diff --git a/grafana-plugin/src/pages/integration_2/Integration2.helper.ts b/grafana-plugin/src/pages/integration_2/Integration2.helper.ts index ef7c6e53..4fff8ea5 100644 --- a/grafana-plugin/src/pages/integration_2/Integration2.helper.ts +++ b/grafana-plugin/src/pages/integration_2/Integration2.helper.ts @@ -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) && diff --git a/grafana-plugin/src/pages/integration_2/Integration2.tsx b/grafana-plugin/src/pages/integration_2/Integration2.tsx index 20500b75..6ce84e0f 100644 --- a/grafana-plugin/src/pages/integration_2/Integration2.tsx +++ b/grafana-plugin/src/pages/integration_2/Integration2.tsx @@ -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 { @@ -603,9 +603,8 @@ const IntegrationSendDemoPayloadModal: React.FC { 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(alertReceiveChannel.demo_alert_payload); + const initialDemoJSON = JSON.stringify(alertReceiveChannel.demo_alert_payload, null, 2); + const [demoPayload, setDemoPayload] = useState(initialDemoJSON); let onPayloadChangeDebounced = debounce(100, onPayloadChange); return ( @@ -916,8 +915,6 @@ const IntegrationActions: React.FC = ({ 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
} - content={isGrafanaDatasource || !hasAlerts ? renderContent() : null} + content={hasAlerts ? null : renderContent()} /> ); @@ -963,20 +960,6 @@ const HowToConnectComponent: React.FC<{ id: AlertReceiveChannel['id'] }> = ({ id No alerts yet; try to send a demo alert )} - - {isGrafanaDatasource && ( - - - - Contact Point - - and - - Notification Policy - - created in Grafana Alerting - - )}
); diff --git a/grafana-plugin/src/pages/integrations_2/Integrations2.tsx b/grafana-plugin/src/pages/integrations_2/Integrations2.tsx index 1de27eb1..2f293129 100644 --- a/grafana-plugin/src/pages/integrations_2/Integrations2.tsx +++ b/grafana-plugin/src/pages/integrations_2/Integrations2.tsx @@ -414,36 +414,34 @@ class Integrations extends React.Component
- <> -
-
{ - this.setState({ - confirmationModal: { - isOpen: true, - confirmText: 'Delete', - dismissText: 'Cancel', - onConfirm: () => this.handleDeleteAlertReceiveChannel(item.id), - title: 'Delete integration', - body: ( - - Are you sure you want to delete integration? - - ), - }, - }); - }} - style={{ width: '100%' }} - > - - - - Delete Integration - - -
+
+
{ + this.setState({ + confirmationModal: { + isOpen: true, + confirmText: 'Delete', + dismissText: 'Cancel', + onConfirm: () => this.handleDeleteAlertReceiveChannel(item.id), + title: 'Delete integration', + body: ( + + Are you sure you want to delete integration? + + ), + }, + }); + }} + style={{ width: '100%' }} + > + + + + Delete Integration + +
- +
)}