Skip to content

Commit

Permalink
[Synthetics] Monitor list add bulk delete (elastic#190674)
Browse files Browse the repository at this point in the history
## Summary

 Monitor list add bulk delete !!
 
 
<img width="1727" alt="image"
src="https://github.com/user-attachments/assets/4a9fddd2-9ce4-43ee-9024-c3dfc3511657">
  • Loading branch information
shahzad31 authored Aug 20, 2024
1 parent c4f135e commit 09fc4bf
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ journey('AlertingDefaults', async ({ page, params }) => {
await page.click('.euiForm');
await page.click('text=To: Email is required for selected email connector');
});

step('Fill email fields', async () => {
await page
.getByTestId('toEmailAddressInput')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ journey('ProjectMonitorReadOnly', async ({ page, params }) => {
step('Monitor can be deleted', async () => {
await page.click('text="Delete monitor"');
await page.click('[data-test-subj="confirmModalConfirmButton"]');
await page.waitForSelector(`text='Deleted "${monitorName}"'`);
await page.waitForSelector(`text='Deleted "${monitorName}" monitor successfully.'`);
});

after(async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ export const ActionBar = ({
formState: { defaultValues, isValid },
} = useFormContext();

const [monitorPendingDeletion, setMonitorPendingDeletion] = useState<SyntheticsMonitor | null>(
null
);
const [monitorsPendingDeletion, setMonitorsPendingDeletion] = useState<string[]>([]);

const [monitorData, setMonitorData] = useState<SyntheticsMonitor | undefined>(undefined);

Expand Down Expand Up @@ -66,7 +64,7 @@ export const ActionBar = ({
data-test-subj="syntheticsActionBarButton"
color="danger"
onClick={() => {
setMonitorPendingDeletion(defaultValues as SyntheticsMonitor);
setMonitorsPendingDeletion([monitorId]);
}}
isDisabled={!canEditSynthetics || !canUsePublicLocations}
>
Expand Down Expand Up @@ -107,14 +105,14 @@ export const ActionBar = ({
</NoPermissionsTooltip>
</EuiFlexItem>
</EuiFlexGroup>
{monitorPendingDeletion && (
{monitorsPendingDeletion.length > 0 && (
<DeleteMonitor
configId={monitorId}
configIds={monitorsPendingDeletion}
name={defaultValues?.[ConfigKey.NAME] ?? ''}
reloadPage={() => {
history.push(MONITORS_ROUTE);
}}
setMonitorPendingDeletion={setMonitorPendingDeletion}
setMonitorPendingDeletion={setMonitorsPendingDeletion}
isProjectMonitor={defaultValues?.[ConfigKey.MONITOR_SOURCE_TYPE] === SourceType.PROJECT}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { i18n } from '@kbn/i18n';
import { EuiButtonEmpty } from '@elastic/eui';
import {
ConfigKey,
EncryptedSyntheticsSavedMonitor,
} from '../../../../../../../common/runtime_types';

export const BulkOperations = ({
selectedItems,
setMonitorPendingDeletion,
}: {
selectedItems: EncryptedSyntheticsSavedMonitor[];
setMonitorPendingDeletion: (val: string[]) => void;
}) => {
const onDeleted = () => {
setMonitorPendingDeletion(selectedItems.map((item) => item[ConfigKey.CONFIG_ID]));
};

if (selectedItems.length === 0) {
return null;
}

return (
<EuiButtonEmpty
data-test-subj="syntheticsBulkOperationPopoverClickMeToLoadAContextMenuButton"
iconType="trash"
iconSide="left"
onClick={onDeleted}
color="danger"
>
{i18n.translate('xpack.synthetics.bulkOperationPopover.clickMeToLoadButtonLabel', {
defaultMessage:
'Delete {monitorCount, number} selected {monitorCount, plural, one {monitor} other {monitors}}',
values: { monitorCount: selectedItems.length },
})}
</EuiButtonEmpty>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export function useMonitorListColumns({
}: {
loading: boolean;
overviewStatus: OverviewStatusState | null;
setMonitorPendingDeletion: (config: EncryptedSyntheticsSavedMonitor) => void;
setMonitorPendingDeletion: (configs: string[]) => void;
}): Array<EuiBasicTableColumn<EncryptedSyntheticsSavedMonitor>> {
const history = useHistory();
const { http } = useKibana().services;
Expand Down Expand Up @@ -239,7 +239,7 @@ export function useMonitorListColumns({
enabled: (fields) =>
canEditSynthetics && !isActionLoading(fields) && isPublicLocationsAllowed(fields),
onClick: (fields) => {
setMonitorPendingDeletion(fields);
setMonitorPendingDeletion([fields[ConfigKey.CONFIG_ID]]);
},
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ import * as labels from './labels';
export const DeleteMonitor = ({
name,
reloadPage,
configId,
configIds,
isProjectMonitor,
setMonitorPendingDeletion,
}: {
configId: string;
configIds: string[];
name: string;
isProjectMonitor: boolean;
reloadPage: () => void;
setMonitorPendingDeletion: (val: null) => void;
setMonitorPendingDeletion: (val: string[]) => void;
}) => {
const [isDeleting, setIsDeleting] = useState<boolean>(false);

Expand All @@ -37,9 +37,9 @@ export const DeleteMonitor = ({

const { status: monitorDeleteStatus } = useFetcher(() => {
if (isDeleting) {
return fetchDeleteMonitor({ configId });
return fetchDeleteMonitor({ configIds });
}
}, [configId, isDeleting]);
}, [configIds, isDeleting]);

useEffect(() => {
const { coreStart, toasts } = kibanaService;
Expand All @@ -64,13 +64,19 @@ export const DeleteMonitor = ({
{
title: toMountPoint(
<p data-test-subj="uptimeDeleteMonitorSuccess">
{i18n.translate(
'xpack.synthetics.monitorManagement.monitorDeleteSuccessMessage.name',
{
defaultMessage: 'Deleted "{name}"',
values: { name },
}
)}
{configIds.length === 1
? i18n.translate(
'xpack.synthetics.monitorManagement.monitorDeleteSuccessMessage.name',
{
defaultMessage: 'Deleted "{name}" monitor successfully.',
values: { name },
}
)
: i18n.translate('xpack.synthetics.monitorManagement.successDeletion', {
defaultMessage:
'Deleted {monitorCount, number} {monitorCount, plural, one {monitor} other {monitors}} successfully.',
values: { monitorCount: configIds.length },
})}
</p>,
coreStart
),
Expand All @@ -83,17 +89,33 @@ export const DeleteMonitor = ({
monitorDeleteStatus === FETCH_STATUS.FAILURE
) {
setIsDeleting(false);
setMonitorPendingDeletion(null);
setMonitorPendingDeletion([]);
}
}, [setIsDeleting, isDeleting, reloadPage, monitorDeleteStatus, setMonitorPendingDeletion, name]);
}, [
setIsDeleting,
isDeleting,
reloadPage,
monitorDeleteStatus,
setMonitorPendingDeletion,
name,
configIds.length,
]);

return (
<EuiConfirmModal
title={i18n.translate('xpack.synthetics.monitorManagement.deleteMonitorNameLabel', {
defaultMessage: 'Delete "{name}" monitor?',
values: { name },
})}
onCancel={() => setMonitorPendingDeletion(null)}
title={
configIds.length === 1
? i18n.translate('xpack.synthetics.monitorManagement.deleteMonitorNameLabel', {
defaultMessage: 'Delete "{name}" monitor?',
values: { name },
})
: i18n.translate('xpack.synthetics.monitorManagement.deleteMonitorNameLabel', {
defaultMessage:
'Delete {monitorCount, number} selected {monitorCount, plural, one {monitor} other {monitors}}?',
values: { monitorCount: configIds.length },
})
}
onCancel={() => setMonitorPendingDeletion([])}
onConfirm={handleConfirmDelete}
cancelButtonText={labels.NO_LABEL}
confirmButtonText={labels.YES_LABEL}
Expand All @@ -118,7 +140,7 @@ export const DeleteMonitor = ({
export const PROJECT_MONITOR_TITLE = i18n.translate(
'xpack.synthetics.monitorManagement.monitorList.disclaimer.title',
{
defaultMessage: 'Deleting this monitor will not remove it from the project source',
defaultMessage: 'Deleting project monitor will not remove it from the project source',
}
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
useIsWithinMinBreakpoint,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { EuiTableSelectionType } from '@elastic/eui/src/components/basic_table/table_types';
import { MonitorListHeader } from './monitor_list_header';
import type { MonitorListSortField } from '../../../../../../../common/runtime_types/monitor_management/sort_field';
import { DeleteMonitor } from './delete_monitor';
import { IHttpSerializedFetchError } from '../../../../state/utils/http_error';
Expand Down Expand Up @@ -51,8 +53,7 @@ export const MonitorList = ({
}: Props) => {
const isXl = useIsWithinMinBreakpoint('xxl');

const [monitorPendingDeletion, setMonitorPendingDeletion] =
useState<EncryptedSyntheticsSavedMonitor | null>(null);
const [monitorPendingDeletion, setMonitorPendingDeletion] = useState<string[]>([]);

const handleOnChange = useCallback(
({
Expand Down Expand Up @@ -98,34 +99,55 @@ export const MonitorList = ({
setMonitorPendingDeletion,
});

const [selectedItems, setSelectedItems] = useState<EncryptedSyntheticsSavedMonitor[]>([]);
const onSelectionChange = (selItems: EncryptedSyntheticsSavedMonitor[]) => {
setSelectedItems(selItems);
};

const selection: EuiTableSelectionType<EncryptedSyntheticsSavedMonitor> = {
onSelectionChange,
initialSelected: selectedItems,
};

return (
<>
<EuiPanel hasBorder={false} hasShadow={false} paddingSize="none">
{recordRangeLabel}
<MonitorListHeader
recordRangeLabel={recordRangeLabel}
selectedItems={selectedItems}
setMonitorPendingDeletion={setMonitorPendingDeletion}
/>
<EuiHorizontalRule margin="s" />
<EuiBasicTable
aria-label={i18n.translate('xpack.synthetics.management.monitorList.title', {
defaultMessage: 'Synthetics monitors list',
})}
error={error?.body?.message}
loading={loading}
itemId="monitor_id"
itemId="config_id"
items={syntheticsMonitors}
columns={columns}
tableLayout={isXl ? 'auto' : 'fixed'}
pagination={pagination}
sorting={sorting}
onChange={handleOnChange}
noItemsMessage={loading ? labels.LOADING : labels.NO_DATA_MESSAGE}
selection={selection}
/>
</EuiPanel>
{monitorPendingDeletion && (
{monitorPendingDeletion.length > 0 && (
<DeleteMonitor
configId={monitorPendingDeletion[ConfigKey.CONFIG_ID]}
name={monitorPendingDeletion[ConfigKey.NAME] ?? ''}
configIds={monitorPendingDeletion}
name={
syntheticsMonitors.find(
(mon) => mon[ConfigKey.CONFIG_ID] === monitorPendingDeletion[0]
)?.[ConfigKey.NAME] ?? ''
}
setMonitorPendingDeletion={setMonitorPendingDeletion}
isProjectMonitor={
monitorPendingDeletion[ConfigKey.MONITOR_SOURCE_TYPE] === SourceType.PROJECT
syntheticsMonitors.find(
(mon) => mon[ConfigKey.CONFIG_ID] === monitorPendingDeletion[0]
)?.[ConfigKey.MONITOR_SOURCE_TYPE] === SourceType.PROJECT
}
reloadPage={reloadPage}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';

import React from 'react';
import { BulkOperations } from './bulk_operations';
import { EncryptedSyntheticsSavedMonitor } from '../../../../../../../common/runtime_types';

export const MonitorListHeader = ({
selectedItems,
recordRangeLabel,
setMonitorPendingDeletion,
}: {
recordRangeLabel: JSX.Element;
selectedItems: EncryptedSyntheticsSavedMonitor[];
setMonitorPendingDeletion: (val: string[]) => void;
}) => {
return (
<EuiFlexGroup alignItems="center">
<EuiFlexItem grow={false}>
<span>{recordRangeLabel}</span>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<BulkOperations
selectedItems={selectedItems}
setMonitorPendingDeletion={setMonitorPendingDeletion}
/>
</EuiFlexItem>
</EuiFlexGroup>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ export const fetchMonitorManagementList = async (
});
};

export const fetchDeleteMonitor = async ({ configId }: { configId: string }): Promise<void> => {
export const fetchDeleteMonitor = async ({ configIds }: { configIds: string[] }): Promise<void> => {
return await apiService.delete(
SYNTHETICS_API_URLS.SYNTHETICS_MONITORS,
{ version: INITIAL_REST_VERSION },
{
ids: [configId],
ids: configIds,
}
);
};
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -44939,7 +44939,6 @@
"xpack.synthetics.monitorManagement.deleteLocation": "Supprimer l’emplacement",
"xpack.synthetics.monitorManagement.deleteLocationLabel": "Supprimer l’emplacement",
"xpack.synthetics.monitorManagement.deleteLocationName": "Supprimer \"{location}\"",
"xpack.synthetics.monitorManagement.deleteMonitorNameLabel": "Supprimer le moniteur \"{name}\"",
"xpack.synthetics.monitorManagement.disabled.label": "Désactivé",
"xpack.synthetics.monitorManagement.discardLabel": "Annuler",
"xpack.synthetics.monitorManagement.editMonitorCrumb": "Modifier le moniteur",
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -44921,7 +44921,6 @@
"xpack.synthetics.monitorManagement.deleteLocation": "場所を削除",
"xpack.synthetics.monitorManagement.deleteLocationLabel": "場所を削除",
"xpack.synthetics.monitorManagement.deleteLocationName": "\"{location}\"を削除",
"xpack.synthetics.monitorManagement.deleteMonitorNameLabel": "\"{name}\"モニターを削除しますか?",
"xpack.synthetics.monitorManagement.disabled.label": "無効",
"xpack.synthetics.monitorManagement.discardLabel": "キャンセル",
"xpack.synthetics.monitorManagement.editMonitorCrumb": "モニターを編集",
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -44969,7 +44969,6 @@
"xpack.synthetics.monitorManagement.deleteLocation": "删除位置",
"xpack.synthetics.monitorManagement.deleteLocationLabel": "删除位置",
"xpack.synthetics.monitorManagement.deleteLocationName": "删除“{location}”",
"xpack.synthetics.monitorManagement.deleteMonitorNameLabel": "删除“{name}”监测?",
"xpack.synthetics.monitorManagement.disabled.label": "已禁用",
"xpack.synthetics.monitorManagement.discardLabel": "取消",
"xpack.synthetics.monitorManagement.editMonitorCrumb": "编辑监测",
Expand Down

0 comments on commit 09fc4bf

Please sign in to comment.