/* * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ import React, { useCallback, useContext, useEffect, useState } from "react"; import { CoreStart } from "opensearch-dashboards/public"; import { CatIndex, DataStream } from "../../../server/models/interfaces"; import { IAlias } from "../../pages/Aliases/interface"; import { ServicesContext } from "../../services"; import { CoreServicesContext } from "../../components/core_services"; import { INDEX_OP_BLOCKS_TYPE, INDEX_OP_TARGET_TYPE } from "../../utils/constants"; import { getErrorMessage, filterBlockedItems } from "../../utils/helpers"; import { EuiButton, EuiButtonEmpty, EuiCallOut, EuiModal, EuiModalBody, EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, EuiSpacer, } from "@elastic/eui"; export interface ClearCacheModalProps { selectedItems: CatIndex[] | DataStream[] | IAlias[]; visible: boolean; onClose: () => void; type: string; } export default function ClearCacheModal(props: ClearCacheModalProps) { const { onClose, visible, selectedItems, type } = props; const [hint, setHint] = useState(""); const [blockHint, setBlockHint] = useState(""); const [unBlockedItems, setUnBlockedItems] = useState([] as string[]); const [blockedItems, setBlockedItems] = useState([] as string[]); const [loading, setLoading] = useState(true); const services = useContext(ServicesContext); const coreServices = useContext(CoreServicesContext) as CoreStart; useEffect(() => { const indexBlocksTypes = [ INDEX_OP_BLOCKS_TYPE.CLOSED, INDEX_OP_BLOCKS_TYPE.META_DATA, INDEX_OP_BLOCKS_TYPE.READ_ONLY, INDEX_OP_BLOCKS_TYPE.READ_ONLY_ALLOW_DELETE, ]; if (!!services && visible) { switch (type) { case INDEX_OP_TARGET_TYPE.DATA_STREAM: setHint("Cache will be cleared for the following data streams."); setBlockHint( "Cache will not be cleared for the following data streams because one or more backing indexes are closed or blocked." ); filterBlockedItems(services, selectedItems, indexBlocksTypes, INDEX_OP_TARGET_TYPE.DATA_STREAM, false) .then((filteredDataStreamsResult) => { setUnBlockedItems(filteredDataStreamsResult.unBlockedItems); setBlockedItems(filteredDataStreamsResult.blockedItems); }) .catch(() => { // set unBlockedItems to all when filter is failed setUnBlockedItems((selectedItems as DataStream[]).map((item) => item.name)); }) .finally(() => { setLoading(false); }); break; case INDEX_OP_TARGET_TYPE.ALIAS: setHint("Cache will be cleared for the following aliases."); setBlockHint("Cache will not be cleared for the following aliases because one or more indexes are closed or blocked."); filterBlockedItems(services, selectedItems as IAlias[], indexBlocksTypes, INDEX_OP_TARGET_TYPE.ALIAS, false) .then((filteredAliasesResult) => { setUnBlockedItems(filteredAliasesResult.unBlockedItems); setBlockedItems(filteredAliasesResult.blockedItems); }) .catch(() => { // set unBlockedItems to all when filter is failed setUnBlockedItems((selectedItems as IAlias[]).map((item) => item.alias)); }) .finally(() => { setLoading(false); }); break; default: setHint("Cache will be cleared for the following indexes."); setBlockHint("Cache will not be cleared for the following indexes because they may be closed or blocked."); filterBlockedItems(services, selectedItems as CatIndex[], indexBlocksTypes, INDEX_OP_TARGET_TYPE.INDEX, false) .then((filteredIndexesResult) => { setUnBlockedItems(filteredIndexesResult.unBlockedItems); setBlockedItems(filteredIndexesResult.blockedItems); }) .catch(() => { // set unBlockedItems to all when filter is failed setUnBlockedItems((selectedItems as CatIndex[]).map((item) => item.index)); }) .finally(() => { setLoading(false); }); } } else if (!visible) { setUnBlockedItems([] as string[]); setBlockedItems([] as string[]); setLoading(true); } }, [services, visible, type, selectedItems]); const onConfirm = useCallback(async () => { if (!!services) { try { const result = await services.commonService.apiCaller({ endpoint: "indices.clearCache", data: { index: unBlockedItems.join(","), }, }); if (result && result.ok) { onClose(); let toast = ""; if (unBlockedItems.length > 1) { toast = `Cache for ${unBlockedItems.length} ${type} [${unBlockedItems.join(", ")}] have been successfully cleared.`; } else if (unBlockedItems.length == 1) { toast = `Cache for ${unBlockedItems[0]} has been successfully cleared.`; } if (!selectedItems || selectedItems.length == 0) { toast = "Cache for all open indexes have been successfully cleared."; } coreServices.notifications.toasts.addSuccess(toast); } else { if (result.error.includes("cluster_block_exception")) { coreServices.notifications.toasts.addError(new Error(result.error), { title: "Clear cache failed.", toastMessage: "One or more indexes are blocked.", }); } else { coreServices.notifications.toasts.addError(new Error(result.error), { title: "Clear cache failed.", }); } } } catch (err) { coreServices.notifications.toasts.addDanger({ title: "Unable to clear cache", text: getErrorMessage(err, "There was a problem clearing cache."), }); } } }, [services, coreServices, onClose, unBlockedItems, selectedItems, type]); useEffect(() => { if (visible && selectedItems.length > 0 && selectedItems.length == blockedItems.length) { if (selectedItems.length == 1) { coreServices.notifications.toasts.addDanger({ title: "Unable to clear cache", text: `Cache cannot be cleared for ${blockedItems[0]} because it is closed or blocked.`, }); } else { coreServices.notifications.toasts.addDanger({ title: "Unable to clear cache", text: `Cache cannot be cleared for the selected ${type} because they are closed or blocked.`, }); } onClose(); } }, [visible, unBlockedItems, blockedItems, coreServices, onClose, type]); if (!visible || loading) { return null; } const specificIndexesChildren: React.ReactChild = ( <>
{unBlockedItems.length > 0 && ( <>

{hint}

)}
); const noSpecificIndexesChildren: React.ReactChild = ( <>

Cache will be cleared for all open indexes.

); return ( Clear cache for {type} {!!selectedItems && selectedItems.length > 0 ? specificIndexesChildren : noSpecificIndexesChildren} Cancel 0 && unBlockedItems.length == 0} > Clear cache ); }