Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
Make all callouts optional on batch action modals (#230)
Browse files Browse the repository at this point in the history
  • Loading branch information
ohltyler authored Jun 18, 2020
1 parent f494640 commit 04eb664
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ interface ListActionsProps {
onStopDetectors(): void;
onDeleteDetectors(): void;
isActionsDisabled: boolean;
isStartDisabled: boolean;
isStopDisabled: boolean;
}

export const ListActions = (props: ListActionsProps) => {
Expand Down Expand Up @@ -57,6 +59,7 @@ export const ListActions = (props: ListActionsProps) => {
<EuiContextMenuItem
key="startDetectors"
data-test-subj="startDetectors"
disabled={props.isStartDisabled}
onClick={props.onStartDetectors}
>
Start
Expand All @@ -65,6 +68,7 @@ export const ListActions = (props: ListActionsProps) => {
<EuiContextMenuItem
key="stopDetectors"
data-test-subj="stopDetectors"
disabled={props.isStopDisabled}
onClick={props.onStopDetectors}
>
Stop
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ import {
} from '@elastic/eui';
// @ts-ignore
import { toastNotifications } from 'ui/notify';
import { get, isEmpty } from 'lodash';
//@ts-ignore
import chrome from 'ui/chrome';
import { Monitor } from '../../../../models/interfaces';
import { DetectorListItem } from '../../../../models/interfaces';
import { Listener } from '../../../../utils/utils';
import { EuiSpacer } from '@elastic/eui';
import { DETECTOR_STATE } from '../../../../utils/constants';
import {
getNamesAndMonitorsAndStatesGrid,
containsEnabledDetectors,
Expand All @@ -55,10 +57,27 @@ interface ConfirmDeleteDetectorsModalProps {
export const ConfirmDeleteDetectorsModal = (
props: ConfirmDeleteDetectorsModalProps
) => {
const containsMonitors = !isEmpty(props.monitors);
const containsEnabled = containsEnabledDetectors(props.detectors);
const detectorsToDisplay = containsEnabled
? props.detectors
.sort(detector =>
detector.curState === DETECTOR_STATE.INIT ||
detector.curState === DETECTOR_STATE.RUNNING
? -1
: 1
)
.sort(detector => (get(props.monitors, `${detector.id}`) ? -1 : 1))
: containsMonitors
? props.detectors.sort(detector =>
get(props.monitors, `${detector.id}`) ? -1 : 1
)
: props.detectors;

const [deleteTyped, setDeleteTyped] = useState<boolean>(false);
const [isModalLoading, setIsModalLoading] = useState<boolean>(false);
const isLoading = isModalLoading || props.isListLoading;

return (
<EuiOverlayMask>
<EuiModal onClose={props.onHide}>
Expand All @@ -68,28 +87,35 @@ export const ConfirmDeleteDetectorsModal = (
</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody>
<EuiCallOut
title="The following detectors and feature configurations will be permanently removed. Any associated monitors will
not be able to receive any anomaly results to generate alerts."
color="warning"
iconType="alert"
></EuiCallOut>
{containsMonitors ? (
<EuiCallOut
title="The monitors associated with these detectors will not receive any anomaly results."
color="warning"
iconType="alert"
></EuiCallOut>
) : null}
{containsMonitors && containsEnabled ? <EuiSpacer size="s" /> : null}
{containsEnabled ? (
<div>
<EuiSpacer size="s" />
<EuiCallOut
title="Some of the selected detectors are currently running."
color="warning"
iconType="alert"
></EuiCallOut>
</div>
<EuiCallOut
title="Some of the selected detectors are currently running."
color="warning"
iconType="alert"
></EuiCallOut>
) : null}
{containsMonitors || containsEnabled ? <EuiSpacer size="s" /> : null}
<EuiText>
The following detectors and feature configurations will be
permanently removed. This action is irreversible.
</EuiText>
<EuiSpacer size="s" />
<div>
{isLoading ? (
<EuiLoadingSpinner size="xl" />
) : (
getNamesAndMonitorsAndStatesGrid(props.detectors, props.monitors)
getNamesAndMonitorsAndStatesGrid(
detectorsToDisplay,
props.monitors
)
)}
</div>
</EuiModalBody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@

import React, { useState } from 'react';
import {
EuiText,
EuiOverlayMask,
EuiCallOut,
EuiButton,
EuiButtonEmpty,
EuiModal,
Expand Down Expand Up @@ -56,11 +56,7 @@ export const ConfirmStartDetectorsModal = (
</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody>
<EuiCallOut
title="The following detectors will begin initializing:"
color="success"
iconType="play"
></EuiCallOut>
<EuiText>The following detectors will begin initializing.</EuiText>
<EuiSpacer size="s" />
<div>
{isLoading ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import React, { useState } from 'react';
import {
EuiText,
EuiOverlayMask,
EuiCallOut,
EuiButton,
Expand All @@ -35,6 +36,7 @@ import { DetectorListItem } from '../../../../models/interfaces';
import { Listener } from '../../../../utils/utils';
import { EuiSpacer } from '@elastic/eui';
import { getNamesAndMonitorsGrid } from './utils/helpers';
import { get, isEmpty } from 'lodash';

interface ConfirmStopDetectorsModalProps {
detectors: DetectorListItem[];
Expand All @@ -48,8 +50,16 @@ interface ConfirmStopDetectorsModalProps {
export const ConfirmStopDetectorsModal = (
props: ConfirmStopDetectorsModalProps
) => {
const containsMonitors = !isEmpty(props.monitors);
const detectorsToDisplay = containsMonitors
? props.detectors.sort(detector =>
get(props.monitors, `${detector.id}`) ? -1 : 1
)
: props.detectors;

const [isModalLoading, setIsModalLoading] = useState<boolean>(false);
const isLoading = isModalLoading || props.isListLoading;

return (
<EuiOverlayMask>
<EuiModal onClose={props.onHide}>
Expand All @@ -59,18 +69,23 @@ export const ConfirmStopDetectorsModal = (
</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody>
<EuiCallOut
title="The following detectors will be stopped. Any associated monitors will
not be able to receive any anomaly results to generate alerts."
color="warning"
iconType="alert"
></EuiCallOut>
{containsMonitors ? (
<div>
<EuiCallOut
title="The monitors associated with these detectors will not receive any anomaly results."
color="warning"
iconType="alert"
></EuiCallOut>
<EuiSpacer size="s" />
</div>
) : null}
<EuiText>The following detectors will be stopped.</EuiText>
<EuiSpacer size="s" />
<div>
{isLoading ? (
<EuiLoadingSpinner size="xl" />
) : (
getNamesAndMonitorsGrid(props.detectors, props.monitors)
getNamesAndMonitorsGrid(detectorsToDisplay, props.monitors)
)}
</div>
</EuiModalBody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,10 @@ const testDetectors = [

let testMonitor = {} as { [key: string]: Monitor };
//@ts-ignore
testMonitor['detector-id-0'] = [
{
id: 'monitor-id-0',
name: 'monitor-0',
},
];
testMonitor['detector-id-0'] = {
id: 'monitor-id-0',
name: 'monitor-0',
};

const defaultDeleteProps = {
detectors: testDetectors,
Expand Down Expand Up @@ -74,6 +72,9 @@ describe('<ConfirmDeleteDetectorsModal /> spec', () => {
/>
);
getByText('Are you sure you want to delete the selected detectors?');
getByText(
'The monitors associated with these detectors will not receive any anomaly results.'
);
getByText('Delete detectors');
getByText('detector-0');
getByText('detector-1');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,10 @@ const testDetectors = [

let testMonitor = {} as { [key: string]: Monitor };
//@ts-ignore
testMonitor['detector-id-0'] = [
{
id: 'monitor-id-0',
name: 'monitor-0',
},
];
testMonitor['detector-id-0'] = {
id: 'monitor-id-0',
name: 'monitor-0',
};

const defaultStopProps = {
detectors: testDetectors,
Expand Down Expand Up @@ -71,6 +69,9 @@ describe('<ConfirmStopDetectorsModal /> spec', () => {
/>
);
getByText('Are you sure you want to stop the selected detectors?');
getByText(
'The monitors associated with these detectors will not receive any anomaly results.'
);
getByText('Stop detectors');
getByText('detector-0');
getByText('detector-1');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const getNamesAndMonitors = (
) => {
let data = [];
for (let i = 0; i < detectors.length; i++) {
const relatedMonitor = get(monitors, `${detectors[i].id}.0`);
const relatedMonitor = get(monitors, `${detectors[i].id}`);
if (relatedMonitor) {
data.push({
Detector: (
Expand Down Expand Up @@ -92,7 +92,7 @@ const getNamesAndMonitorsAndStates = (
) => {
let data = [];
for (let i = 0; i < detectors.length; i++) {
const relatedMonitor = get(monitors, `${detectors[i].id}.0`);
const relatedMonitor = get(monitors, `${detectors[i].id}`);
const isRunning =
detectors[i].curState === DETECTOR_STATE.INIT ||
detectors[i].curState === DETECTOR_STATE.RUNNING;
Expand Down
37 changes: 32 additions & 5 deletions public/pages/DetectorsList/containers/List/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,11 @@ import {
ALL_INDICES,
} from '../../../utils/constants';
import { BREADCRUMBS } from '../../../../utils/constants';
import { getURLQueryParams, getDetectorsForAction } from '../../utils/helpers';
import {
getURLQueryParams,
getDetectorsForAction,
getMonitorsForAction,
} from '../../utils/helpers';
import {
filterAndSortDetectors,
getDetectorsToDisplay,
Expand Down Expand Up @@ -103,6 +107,11 @@ interface ConfirmModalState {
affectedDetectors: DetectorListItem[];
affectedMonitors: { [key: string]: Monitor };
}
interface ListActionsState {
isDisabled: boolean;
isStartDisabled: boolean;
isStopDisabled: boolean;
}

export const DetectorList = (props: ListProps) => {
const dispatch = useDispatch();
Expand All @@ -128,7 +137,6 @@ export const DetectorList = (props: ListProps) => {
[] as DetectorListItem[]
);
const isLoading = isRequestingFromES || isLoadingFinalDetectors;

const [confirmModalState, setConfirmModalState] = useState<ConfirmModalState>(
{
isOpen: false,
Expand All @@ -140,6 +148,11 @@ export const DetectorList = (props: ListProps) => {
affectedMonitors: {},
}
);
const [listActionsState, setListActionsState] = useState<ListActionsState>({
isDisabled: true,
isStartDisabled: false,
isStopDisabled: false,
});

// Getting all initial indices
const [indexQuery, setIndexQuery] = useState('');
Expand Down Expand Up @@ -346,6 +359,16 @@ export const DetectorList = (props: ListProps) => {

const handleSelectionChange = (currentSelected: DetectorListItem[]) => {
setSelectedDetectorsForAction(currentSelected);
setListActionsState({
...listActionsState,
isDisabled: isEmpty(currentSelected),
isStartDisabled: isEmpty(
getDetectorsForAction(currentSelected, DETECTOR_ACTION.START)
),
isStopDisabled: isEmpty(
getDetectorsForAction(currentSelected, DETECTOR_ACTION.STOP)
),
});
};

const handleStartDetectorsAction = () => {
Expand Down Expand Up @@ -376,13 +399,14 @@ export const DetectorList = (props: ListProps) => {
DETECTOR_ACTION.STOP
);
if (!isEmpty(validDetectors)) {
const validMonitors = getMonitorsForAction(validDetectors, allMonitors);
setConfirmModalState({
isOpen: true,
action: DETECTOR_ACTION.STOP,
isListLoading: false,
isRequestingToClose: false,
affectedDetectors: validDetectors,
affectedMonitors: allMonitors,
affectedMonitors: validMonitors,
});
} else {
toastNotifications.addWarning(
Expand All @@ -398,13 +422,14 @@ export const DetectorList = (props: ListProps) => {
DETECTOR_ACTION.DELETE
);
if (!isEmpty(validDetectors)) {
const validMonitors = getMonitorsForAction(validDetectors, allMonitors);
setConfirmModalState({
isOpen: true,
action: DETECTOR_ACTION.DELETE,
isListLoading: false,
isRequestingToClose: false,
affectedDetectors: validDetectors,
affectedMonitors: allMonitors,
affectedMonitors: validMonitors,
});
} else {
toastNotifications.addWarning(
Expand Down Expand Up @@ -599,7 +624,9 @@ export const DetectorList = (props: ListProps) => {
onStartDetectors={handleStartDetectorsAction}
onStopDetectors={handleStopDetectorsAction}
onDeleteDetectors={handleDeleteDetectorsAction}
isActionsDisabled={selectedDetectorsForAction.length === 0}
isActionsDisabled={listActionsState.isDisabled}
isStartDisabled={listActionsState.isStartDisabled}
isStopDisabled={listActionsState.isStopDisabled}
/>,
<EuiButton fill href={`${PLUGIN_NAME}#${APP_PATH.CREATE_DETECTOR}`}>
Create detector
Expand Down
Loading

0 comments on commit 04eb664

Please sign in to comment.