From f3331b92b4c453923a6e8db0e48a2a4b36a133c8 Mon Sep 17 00:00:00 2001 From: Abdul Wahab Zahid Date: Wed, 21 Sep 2022 15:29:24 +0200 Subject: [PATCH] [Uptime] Fix: Adjust tooltip on Run test button for Private Locations (#138863) * Control popover logic with MouseOver and MouseOut to be able to show popover on a disabled button. * Run "Test now" only on public locations. * Show specific tooltip when only private locations are available. --- .../action_bar/action_bar.tsx | 41 +++++++++++++++--- .../hooks/use_run_once_errors.ts | 12 ++++-- .../monitor_list/columns/test_now_col.tsx | 42 +++---------------- .../overview/monitor_list/translations.ts | 32 ++++++++++++++ 4 files changed, 80 insertions(+), 47 deletions(-) diff --git a/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/action_bar/action_bar.tsx b/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/action_bar/action_bar.tsx index f0e69395f6075..0cae34a05e35b 100644 --- a/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/action_bar/action_bar.tsx +++ b/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/action_bar/action_bar.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useCallback, useContext, useState, useEffect } from 'react'; +import React, { useCallback, useContext, useState, useEffect, useRef } from 'react'; import { useParams, Redirect } from 'react-router-dom'; import { EuiFlexGroup, @@ -38,6 +38,11 @@ import { monitorManagementListSelector } from '../../../state/selectors'; import { kibanaService } from '../../../state/kibana_service'; +import { + PRIVATE_AVAILABLE_LABEL, + TEST_SCHEDULED_LABEL, +} from '../../overview/monitor_list/translations'; + export interface ActionBarProps { monitor: SyntheticsMonitor; isValid: boolean; @@ -63,9 +68,11 @@ export const ActionBar = ({ const [isSaving, setIsSaving] = useState(false); const [isSuccessful, setIsSuccessful] = useState(false); const [isPopoverOpen, setIsPopoverOpen] = useState(undefined); + const mouseMoveTimeoutIds = useRef<[number, number]>([0, 0]); const isReadOnly = monitor[ConfigKey.MONITOR_SOURCE_TYPE] === SourceType.PROJECT; const hasServiceManagedLocation = monitor.locations?.some((loc) => loc.isServiceManaged); + const isOnlyPrivateLocations = !locations.some((loc) => loc.isServiceManaged); const { data, status } = useFetcher(() => { if (!isSaving || !isValid) { @@ -139,11 +146,14 @@ export const ActionBar = ({ {!isValid && hasBeenSubmitted && VALIDATION_ERROR_LABEL} + {onTestNow && ( {/* Popover is used instead of EuiTooltip until the resolution of https://github.com/elastic/eui/issues/5604 */} onTestNow()} - onMouseEnter={() => { - setIsPopoverOpen(true); + onMouseOver={() => { + // We need this custom logic to display a popover even when button is disabled. + clearTimeout(mouseMoveTimeoutIds.current[1]); + if (mouseMoveTimeoutIds.current[0] === 0) { + mouseMoveTimeoutIds.current[0] = setTimeout(() => { + clearTimeout(mouseMoveTimeoutIds.current[1]); + setIsPopoverOpen(true); + }, 250) as unknown as number; + } }} - onMouseLeave={() => { - setIsPopoverOpen(false); + onMouseOut={() => { + // We need this custom logic to display a popover even when button is disabled. + clearTimeout(mouseMoveTimeoutIds.current[1]); + mouseMoveTimeoutIds.current[1] = setTimeout(() => { + clearTimeout(mouseMoveTimeoutIds.current[0]); + setIsPopoverOpen(false); + mouseMoveTimeoutIds.current = [0, 0]; + }, 100) as unknown as number; }} > {testRun ? RE_RUN_TEST_LABEL : RUN_TEST_LABEL} @@ -167,7 +190,13 @@ export const ActionBar = ({ isOpen={isPopoverOpen} > -

{TEST_NOW_DESCRIPTION}

+

+ {isTestRunInProgress + ? TEST_SCHEDULED_LABEL + : isOnlyPrivateLocations || (isValid && !hasServiceManagedLocation) + ? PRIVATE_AVAILABLE_LABEL + : TEST_NOW_DESCRIPTION} +

diff --git a/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/hooks/use_run_once_errors.ts b/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/hooks/use_run_once_errors.ts index 916ca8c00b972..098154f4e20ce 100644 --- a/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/hooks/use_run_once_errors.ts +++ b/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/hooks/use_run_once_errors.ts @@ -22,6 +22,10 @@ export function useRunOnceErrors({ }) { const [locationErrors, setLocationErrors] = useState([]); const [runOnceServiceError, setRunOnceServiceError] = useState(null); + const publicLocations = useMemo( + () => (locations ?? []).filter((loc) => loc.isServiceManaged), + [locations] + ); useEffect(() => { setLocationErrors([]); @@ -43,16 +47,16 @@ export function useRunOnceErrors({ }, [serviceError]); const locationsById: Record = useMemo( - () => (locations as Locations).reduce((acc, cur) => ({ ...acc, [cur.id]: cur }), {}), - [locations] + () => (publicLocations as Locations).reduce((acc, cur) => ({ ...acc, [cur.id]: cur }), {}), + [publicLocations] ); const expectPings = - locations.length - (locationErrors ?? []).filter(({ locationId }) => !!locationId).length; + publicLocations.length - (locationErrors ?? []).filter(({ locationId }) => !!locationId).length; const hasBlockingError = !!runOnceServiceError || - (locationErrors?.length && locationErrors?.length === locations.length); + (locationErrors?.length && locationErrors?.length === publicLocations.length); const errorMessages = useMemo(() => { if (hasBlockingError) { diff --git a/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/monitor_list/columns/test_now_col.tsx b/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/monitor_list/columns/test_now_col.tsx index 425d881e0141e..17e8047ac64c7 100644 --- a/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/monitor_list/columns/test_now_col.tsx +++ b/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/monitor_list/columns/test_now_col.tsx @@ -6,12 +6,12 @@ */ import { EuiButtonIcon, EuiLoadingSpinner, EuiToolTip } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; import React from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { Ping } from '../../../../../../common/runtime_types'; import { testNowMonitorAction } from '../../../../state/actions'; import { testNowRunSelector, TestRunStats } from '../../../../state/reducers/test_now_runs'; +import * as labels from '../translations'; export const TestNowColumn = ({ monitorId, @@ -28,7 +28,7 @@ export const TestNowColumn = ({ if (selectedMonitor.monitor.fleet_managed) { return ( - + <>-- ); @@ -36,7 +36,7 @@ export const TestNowColumn = ({ if (!configId) { return ( - + <>-- ); @@ -54,45 +54,13 @@ export const TestNowColumn = ({ } return ( - + testNowClick()} isDisabled={!isTestNowCompleted} - aria-label={TEST_NOW_ARIA_LABEL} + aria-label={labels.TEST_NOW_ARIA_LABEL} /> ); }; - -export const TEST_NOW_ARIA_LABEL = i18n.translate( - 'xpack.synthetics.monitorList.testNow.AriaLabel', - { - defaultMessage: 'CLick to run test now', - } -); - -export const TEST_NOW_AVAILABLE_LABEL = i18n.translate( - 'xpack.synthetics.monitorList.testNow.available', - { - defaultMessage: 'Test now is only available for monitors added via Monitor Management.', - } -); - -export const PRIVATE_AVAILABLE_LABEL = i18n.translate( - 'xpack.synthetics.monitorList.testNow.available.private', - { - defaultMessage: `You can't currently test monitors running on private locations on demand.`, - } -); - -export const TEST_NOW_LABEL = i18n.translate('xpack.synthetics.monitorList.testNow.label', { - defaultMessage: 'Test now', -}); - -export const TEST_SCHEDULED_LABEL = i18n.translate( - 'xpack.synthetics.monitorList.testNow.scheduled', - { - defaultMessage: 'Test is already scheduled', - } -); diff --git a/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/monitor_list/translations.ts b/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/monitor_list/translations.ts index 402846b16c875..2f3bac51ce887 100644 --- a/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/monitor_list/translations.ts +++ b/x-pack/plugins/synthetics/public/legacy_uptime/components/overview/monitor_list/translations.ts @@ -83,3 +83,35 @@ export const STATUS_ALERT_COLUMN = i18n.translate( export const TEST_NOW_COLUMN = i18n.translate('xpack.synthetics.monitorList.testNow.label', { defaultMessage: 'Test now', }); + +export const TEST_NOW_AVAILABLE_LABEL = i18n.translate( + 'xpack.synthetics.monitorList.testNow.available', + { + defaultMessage: 'Test now is only available for monitors added via Monitor Management.', + } +); + +export const TEST_SCHEDULED_LABEL = i18n.translate( + 'xpack.synthetics.monitorList.testNow.scheduled', + { + defaultMessage: 'Test is already scheduled', + } +); + +export const PRIVATE_AVAILABLE_LABEL = i18n.translate( + 'xpack.synthetics.monitorList.testNow.available.private', + { + defaultMessage: `You can't currently test monitors running on private locations on demand.`, + } +); + +export const TEST_NOW_ARIA_LABEL = i18n.translate( + 'xpack.synthetics.monitorList.testNow.AriaLabel', + { + defaultMessage: 'Click to run test now', + } +); + +export const TEST_NOW_LABEL = i18n.translate('xpack.synthetics.monitorList.testNow.label', { + defaultMessage: 'Test now', +});