Skip to content

Commit

Permalink
[Enterprise Search] Confirmation modal for deleting Crawler domains i…
Browse files Browse the repository at this point in the history
…n Kibana Content app (#136481)
  • Loading branch information
Byron Hulcher authored Jul 18, 2022
1 parent 7f55a1a commit fef8e72
Show file tree
Hide file tree
Showing 8 changed files with 276 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,19 @@ import { HttpLogic } from '../../../shared/http';

import { CrawlerDomain } from './types';

export interface GetCrawlerDomainsArgs {
export interface DeleteCrawlerDomainArgs {
domain: CrawlerDomain;
indexName: string;
}

export const deleteCrawlerDomain = async ({ domain, indexName }: GetCrawlerDomainsArgs) => {
export interface DeleteCrawlerDomainResponse {
domain: CrawlerDomain;
}

export const deleteCrawlerDomain = async ({
domain,
indexName,
}: DeleteCrawlerDomainArgs): Promise<DeleteCrawlerDomainResponse> => {
await HttpLogic.values.http.delete(
`/internal/enterprise_search/indices/${indexName}/crawler/domains/${domain.id}`
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import { EnterpriseSearchContentPageTemplate } from '../layout/page_template';
import { CrawlCustomSettingsFlyout } from '../search_index/crawler/crawl_custom_settings_flyout/crawl_custom_settings_flyout';
import { CrawlerStatusIndicator } from '../search_index/crawler/crawler_status_indicator/crawler_status_indicator';
import { CrawlerStatusBanner } from '../search_index/crawler/domain_management/crawler_status_banner';
import { getDeleteDomainConfirmationMessage } from '../search_index/crawler/utils';
import { DeleteDomainModal } from '../search_index/crawler/domain_management/delete_domain_modal';
import { DeleteDomainModalLogic } from '../search_index/crawler/domain_management/delete_domain_modal_logic';
import { IndexNameLogic } from '../search_index/index_name_logic';
import { SearchIndexTabId } from '../search_index/search_index';
import { baseBreadcrumbs } from '../search_indices';
Expand All @@ -40,8 +41,9 @@ export const CrawlerDomainDetail: React.FC = () => {

const { indexName } = useValues(IndexNameLogic);
const crawlerDomainDetailLogic = CrawlerDomainDetailLogic({ domainId });
const { deleteLoading, domain, getLoading } = useValues(crawlerDomainDetailLogic);
const { fetchDomainData, deleteDomain } = useActions(crawlerDomainDetailLogic);
const { domain, getLoading } = useValues(crawlerDomainDetailLogic);
const { fetchDomainData } = useActions(crawlerDomainDetailLogic);
const { showModal } = useActions(DeleteDomainModalLogic);

useEffect(() => {
fetchDomainData(domainId);
Expand All @@ -58,11 +60,11 @@ export const CrawlerDomainDetail: React.FC = () => {
rightSideItems: [
<CrawlerStatusIndicator />,
<EuiButton
isLoading={getLoading || deleteLoading}
isLoading={getLoading}
color="danger"
onClick={() => {
if (window.confirm(getDeleteDomainConfirmationMessage(domainUrl))) {
deleteDomain();
if (domain) {
showModal(domain);
}
}}
>
Expand Down Expand Up @@ -110,6 +112,7 @@ export const CrawlerDomainDetail: React.FC = () => {
<DeduplicationPanel />
</>
)}
<DeleteDomainModal />
<CrawlCustomSettingsFlyout />
</EnterpriseSearchContentPageTemplate>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,19 @@ import { kea, MakeLogicType } from 'kea';

import { i18n } from '@kbn/i18n';

import { HttpError, Status } from '../../../../../common/types/api';

import { generateEncodedPath } from '../../../shared/encode_path_params';

import { flashAPIErrors, flashSuccessToast } from '../../../shared/flash_messages';

import { HttpLogic } from '../../../shared/http';
import { KibanaLogic } from '../../../shared/kibana';
import {
DeleteCrawlerDomainApiLogic,
DeleteCrawlerDomainArgs,
DeleteCrawlerDomainResponse,
} from '../../api/crawler/delete_crawler_domain_api_logic';
import {
CrawlerDomain,
CrawlerDomainFromServer,
Expand All @@ -33,14 +40,17 @@ export interface CrawlerDomainDetailProps {

export interface CrawlerDomainDetailValues {
deleteLoading: boolean;
deleteStatus: Status;
domain: CrawlerDomain | null;
domainId: string;
getLoading: boolean;
}

interface CrawlerDomainDetailActions {
deleteApiError(error: HttpError): HttpError;
deleteApiSuccess(response: DeleteCrawlerDomainResponse): DeleteCrawlerDomainResponse;
deleteDomain(): void;
deleteDomainComplete(): void;
deleteMakeRequest(args: DeleteCrawlerDomainArgs): DeleteCrawlerDomainArgs;
fetchDomainData(domainId: string): { domainId: string };
receiveDomainData(domain: CrawlerDomain): { domain: CrawlerDomain };
submitDeduplicationUpdate(payload: { enabled?: boolean; fields?: string[] }): {
Expand All @@ -56,6 +66,17 @@ export const CrawlerDomainDetailLogic = kea<
MakeLogicType<CrawlerDomainDetailValues, CrawlerDomainDetailActions>
>({
path: ['enterprise_search', 'crawler', 'crawler_domain_detail_logic'],
connect: {
actions: [
DeleteCrawlerDomainApiLogic,
[
'apiError as deleteApiError',
'apiSuccess as deleteApiSuccess',
'makeRequest as deleteMakeRequest',
],
],
values: [DeleteCrawlerDomainApiLogic, ['status as deleteStatus']],
},
actions: {
deleteDomain: () => true,
deleteDomainComplete: () => true,
Expand All @@ -67,13 +88,6 @@ export const CrawlerDomainDetailLogic = kea<
updateSitemaps: (sitemaps) => ({ sitemaps }),
},
reducers: ({ props }) => ({
deleteLoading: [
false,
{
deleteDomain: () => true,
deleteDomainComplete: () => false,
},
],
domain: [
null,
{
Expand All @@ -94,34 +108,44 @@ export const CrawlerDomainDetailLogic = kea<
},
],
}),
selectors: ({ selectors }) => ({
deleteLoading: [
() => [selectors.deleteStatus],
(deleteStatus: Status) => deleteStatus === Status.LOADING,
],
}),
listeners: ({ actions, values }) => ({
deleteDomain: async () => {
const { http } = HttpLogic.values;
const { domain, domainId } = values;
const { domain } = values;
const { indexName } = IndexNameLogic.values;
try {
await http.delete(
`/internal/enterprise_search/indices/${indexName}/crawler/domains/${domainId}`
);
flashSuccessToast(
i18n.translate('xpack.enterpriseSearch.crawler.action.deleteDomain.successMessage', {
defaultMessage: "Domain '{domainUrl}' was deleted",
values: {
domainUrl: domain?.url,
},
})
);
KibanaLogic.values.navigateToUrl(
generateEncodedPath(SEARCH_INDEX_TAB_PATH, {
indexName,
tabId: SearchIndexTabId.DOMAIN_MANAGEMENT,
})
);
} catch (e) {
flashAPIErrors(e);
if (domain) {
actions.deleteMakeRequest({
domain,
indexName,
});
}
actions.deleteDomainComplete();
},
deleteApiSuccess: ({ domain }) => {
const { indexName } = IndexNameLogic.values;
flashSuccessToast(
i18n.translate('xpack.enterpriseSearch.crawler.action.deleteDomain.successMessage', {
defaultMessage: "Domain '{domainUrl}' was deleted",
values: {
domainUrl: domain?.url,
},
})
);
KibanaLogic.values.navigateToUrl(
generateEncodedPath(SEARCH_INDEX_TAB_PATH, {
indexName,
tabId: SearchIndexTabId.DOMAIN_MANAGEMENT,
})
);
},
deleteApiError: (error) => {
flashAPIErrors(error);
},

fetchDomainData: async ({ domainId }) => {
const { http } = HttpLogic.values;
const { indexName } = IndexNameLogic.values;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* 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 { useActions, useValues } from 'kea';

import {
EuiButton,
EuiButtonEmpty,
EuiModal,
EuiModalBody,
EuiModalFooter,
EuiModalHeader,
EuiModalHeaderTitle,
EuiText,
} from '@elastic/eui';

import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';

import { CANCEL_BUTTON_LABEL } from '../../../../../shared/constants';

import { DeleteCrawlerDomainApiLogic } from '../../../../api/crawler/delete_crawler_domain_api_logic';

import { DeleteDomainModalLogic } from './delete_domain_modal_logic';

export const DeleteDomainModal: React.FC = () => {
DeleteCrawlerDomainApiLogic.mount();
const { deleteDomain, hideModal } = useActions(DeleteDomainModalLogic);
const { domain, isLoading, isHidden } = useValues(DeleteDomainModalLogic);

if (isHidden) {
return null;
}

return (
<EuiModal
onClose={hideModal}
aria-label={i18n.translate('xpack.enterpriseSearch.crawler.deleteDomainModal.title', {
defaultMessage: 'Delete domain',
})}
>
<EuiModalHeader>
<EuiModalHeaderTitle>
{i18n.translate('xpack.enterpriseSearch.crawler.deleteDomainModal.title', {
defaultMessage: 'Delete domain',
})}
</EuiModalHeaderTitle>
</EuiModalHeader>
<EuiModalBody>
<EuiText>
<FormattedMessage
id="xpack.enterpriseSearch.crawler.deleteDomainModal.description"
defaultMessage="Remove the domain {domainUrl} from your crawler. This will also delete all entry points and crawl rules you have set up. Any documents related to this domain will be removed on the next crawl. {thisCannotBeUndoneMessage}"
values={{
domainUrl: <strong>{domain?.url}</strong>,
thisCannotBeUndoneMessage: (
<strong>
{i18n.translate(
'xpack.enterpriseSearch.crawler.deleteDomainModal.thisCannotBeUndoneMessage',
{
defaultMessage: 'This cannot be undone.',
}
)}
</strong>
),
}}
/>
</EuiText>
</EuiModalBody>
<EuiModalFooter>
<EuiButtonEmpty onClick={hideModal}>{CANCEL_BUTTON_LABEL}</EuiButtonEmpty>
<EuiButton onClick={deleteDomain} isLoading={isLoading} color="danger" fill>
{i18n.translate(
'xpack.enterpriseSearch.crawler.deleteDomainModal.deleteDomainButtonLabel',
{
defaultMessage: 'Delete domain',
}
)}
</EuiButton>
</EuiModalFooter>
</EuiModal>
);
};
Loading

0 comments on commit fef8e72

Please sign in to comment.