Skip to content

Commit

Permalink
[8.6] [Security Solution][List Details Page]: Fix `exception list det…
Browse files Browse the repository at this point in the history
…ails` page route and adding breadcrumb (#145605) (#145960)

# Backport

This will backport the following commits from `main` to `8.6`:
- [[Security Solution][List Details Page]: Fix `exception list details`
page route and adding breadcrumb
(#145605)](#145605)

<!--- Backport version: 8.9.7 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Wafaa
Nasr","email":"wafaa.nasr@elastic.co"},"sourceCommit":{"committedDate":"2022-11-21T15:38:33Z","message":"[Security
Solution][List Details Page]: Fix `exception list details` page route
and adding breadcrumb (#145605)\n\n## Summary\r\n\r\nAs per
this\r\n[discussion](https://github.com/elastic/kibana/pull/145605#pullrequestreview-1186305242)\r\n\r\n-
Remove the `Exception-List-details` definition from the
[management\r\nlinks](https://github.com/elastic/kibana/blob/bb775883505bc0d81e487261244feab0a2011f6f/x-pack/plugins/security_solution/public/management/links.ts)\r\nand\r\n[deep_links](https://github.com/elastic/kibana/blob/bb775883505bc0d81e487261244feab0a2011f6f/x-pack/plugins/security_solution/public/app/deep_links/index.ts)\r\nbecause
it is a dynamic route\r\n\r\n- Use the `Rule Exceptions` page title for
list details\r\n- Add breadcrumb for the details list
page\r\n\r\nCo-authored-by: Kibana Machine
<42973632+kibanamachine@users.noreply.github.com>","sha":"62d9dffbb2d806f35e76dff361fcf9df0b9ce90b","branchLabelMapping":{"^v8.7.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","Team:Security
Solution
Platform","backport:prev-minor","v8.6.0","v8.7.0"],"number":145605,"url":"https://github.com/elastic/kibana/pull/145605","mergeCommit":{"message":"[Security
Solution][List Details Page]: Fix `exception list details` page route
and adding breadcrumb (#145605)\n\n## Summary\r\n\r\nAs per
this\r\n[discussion](https://github.com/elastic/kibana/pull/145605#pullrequestreview-1186305242)\r\n\r\n-
Remove the `Exception-List-details` definition from the
[management\r\nlinks](https://github.com/elastic/kibana/blob/bb775883505bc0d81e487261244feab0a2011f6f/x-pack/plugins/security_solution/public/management/links.ts)\r\nand\r\n[deep_links](https://github.com/elastic/kibana/blob/bb775883505bc0d81e487261244feab0a2011f6f/x-pack/plugins/security_solution/public/app/deep_links/index.ts)\r\nbecause
it is a dynamic route\r\n\r\n- Use the `Rule Exceptions` page title for
list details\r\n- Add breadcrumb for the details list
page\r\n\r\nCo-authored-by: Kibana Machine
<42973632+kibanamachine@users.noreply.github.com>","sha":"62d9dffbb2d806f35e76dff361fcf9df0b9ce90b"}},"sourceBranch":"main","suggestedTargetBranches":["8.6"],"targetPullRequestStates":[{"branch":"8.6","label":"v8.6.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.7.0","labelRegex":"^v8.7.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/145605","number":145605,"mergeCommit":{"message":"[Security
Solution][List Details Page]: Fix `exception list details` page route
and adding breadcrumb (#145605)\n\n## Summary\r\n\r\nAs per
this\r\n[discussion](https://github.com/elastic/kibana/pull/145605#pullrequestreview-1186305242)\r\n\r\n-
Remove the `Exception-List-details` definition from the
[management\r\nlinks](https://github.com/elastic/kibana/blob/bb775883505bc0d81e487261244feab0a2011f6f/x-pack/plugins/security_solution/public/management/links.ts)\r\nand\r\n[deep_links](https://github.com/elastic/kibana/blob/bb775883505bc0d81e487261244feab0a2011f6f/x-pack/plugins/security_solution/public/app/deep_links/index.ts)\r\nbecause
it is a dynamic route\r\n\r\n- Use the `Rule Exceptions` page title for
list details\r\n- Add breadcrumb for the details list
page\r\n\r\nCo-authored-by: Kibana Machine
<42973632+kibanamachine@users.noreply.github.com>","sha":"62d9dffbb2d806f35e76dff361fcf9df0b9ce90b"}}]}]
BACKPORT-->
  • Loading branch information
WafaaNasr authored Nov 22, 2022
1 parent db96bd0 commit acd9091
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 62 deletions.
2 changes: 1 addition & 1 deletion x-pack/plugins/security_solution/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ export enum SecurityPageName {
endpoints = 'endpoints',
eventFilters = 'event_filters',
exceptions = 'exceptions',
sharedExceptionListDetails = 'shared-exception-list-details',
exploreLanding = 'explore',
hostIsolationExceptions = 'host_isolation_exceptions',
hosts = 'hosts',
Expand Down Expand Up @@ -150,6 +149,7 @@ export const ALERTS_PATH = '/alerts' as const;
export const RULES_PATH = '/rules' as const;
export const RULES_CREATE_PATH = `${RULES_PATH}/create` as const;
export const EXCEPTIONS_PATH = '/exceptions' as const;
export const EXCEPTION_LIST_DETAIL_PATH = `${EXCEPTIONS_PATH}/details/:detailName` as const;
export const HOSTS_PATH = '/hosts' as const;
export const USERS_PATH = '/users' as const;
export const KUBERNETES_PATH = '/kubernetes' as const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,15 +234,6 @@ export const securitySolutionsDeepLinks: SecuritySolutionDeepLink[] = [
defaultMessage: 'Exception lists',
}),
],
deepLinks: [
{
id: SecurityPageName.sharedExceptionListDetails,
title: 'List Details',
path: '/exceptions/shared/:exceptionListId',
navLinkStatus: AppNavLinkStatus.hidden,
searchable: false,
},
],
},
],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ const rulesBReadcrumb = {
href: 'securitySolutionUI/rules',
};

const exceptionsBReadcrumb = {
text: 'Rule Exceptions',
href: 'securitySolutionUI/exceptions',
};

const manageBreadcrumbs = {
text: 'Manage',
href: 'securitySolutionUI/administration',
Expand Down Expand Up @@ -433,6 +438,32 @@ describe('Navigation Breadcrumbs', () => {
},
]);
});

test('should return Exceptions breadcrumbs when supplied exception Details pageName', () => {
const mockListName = 'new shared list';
const breadcrumbs = getBreadcrumbsForRoute(
{
...getMockObject(
SecurityPageName.exceptions,
`/exceptions/details/${mockListName}`,
undefined
),
state: {
listName: mockListName,
},
},
getSecuritySolutionUrl,
false
);
expect(breadcrumbs).toEqual([
securityBreadCrumb,
exceptionsBReadcrumb,
{
text: mockListName,
href: ``,
},
]);
});
});

describe('setBreadcrumbs()', () => {
Expand Down Expand Up @@ -773,6 +804,31 @@ describe('Navigation Breadcrumbs', () => {
},
]);
});
test('should return Exceptions breadcrumbs when supplied exception Details pageName', () => {
const mockListName = 'new shared list';
const breadcrumbs = getBreadcrumbsForRoute(
{
...getMockObject(
SecurityPageName.exceptions,
`/exceptions/details/${mockListName}`,
undefined
),
state: {
listName: mockListName,
},
},
getSecuritySolutionUrl,
false
);
expect(breadcrumbs).toEqual([
securityBreadCrumb,
exceptionsBReadcrumb,
{
text: mockListName,
href: ``,
},
]);
});
});

describe('setBreadcrumbs()', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { StartServices } from '../../../../types';
import { getTrailingBreadcrumbs as getHostDetailsBreadcrumbs } from '../../../../hosts/pages/details/utils';
import { getTrailingBreadcrumbs as getIPDetailsBreadcrumbs } from '../../../../network/pages/details';
import { getTrailingBreadcrumbs as getDetectionRulesBreadcrumbs } from '../../../../detections/pages/detection_engine/rules/utils';
import { getTrailingBreadcrumbs as geExceptionsBreadcrumbs } from '../../../../exceptions/utils/pages.utils';
import { getTrailingBreadcrumbs as getUsersBreadcrumbs } from '../../../../users/pages/details/utils';
import { getTrailingBreadcrumbs as getKubernetesBreadcrumbs } from '../../../../kubernetes/pages/utils/breadcrumbs';
import { getTrailingBreadcrumbs as getAlertDetailBreadcrumbs } from '../../../../detections/pages/alert_details/utils/breadcrumbs';
Expand Down Expand Up @@ -131,6 +132,8 @@ const getTrailingBreadcrumbsForRoutes = (
return getDetectionRulesBreadcrumbs(spyState, getSecuritySolutionUrl);
}

if (isExceptionRoutes(spyState)) return geExceptionsBreadcrumbs(spyState, getSecuritySolutionUrl);

if (isKubernetesRoutes(spyState)) {
return getKubernetesBreadcrumbs(spyState, getSecuritySolutionUrl);
}
Expand Down Expand Up @@ -162,6 +165,9 @@ const isRulesRoutes = (spyState: RouteSpyState): spyState is AdministrationRoute
spyState.pageName === SecurityPageName.rules ||
spyState.pageName === SecurityPageName.rulesCreate;

const isExceptionRoutes = (spyState: RouteSpyState) =>
spyState.pageName === SecurityPageName.exceptions;

const isCloudSecurityPostureManagedRoutes = (spyState: RouteSpyState) =>
spyState.pageName === SecurityPageName.cloudSecurityPostureRules;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ export const useExceptionsListCard = ({

// routes to x-pack/plugins/security_solution/public/exceptions/routes.tsx
const { onClick: goToExceptionDetail } = useGetSecuritySolutionLinkProps()({
deepLinkId: SecurityPageName.sharedExceptionListDetails,
path: `/exceptions/shared/${exceptionsList.list_id}`,
deepLinkId: SecurityPageName.exceptions,
path: `/details/${exceptionsList.list_id}`,
});
return {
listId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ export const useListDetailsView = () => {

const { exportExceptionList, deleteExceptionList } = useApi(http);

const { exceptionListId } = useParams<{
exceptionListId: string;
const { detailName: exceptionListId } = useParams<{
detailName: string;
}>();

const [{ loading: userInfoLoading, canUserCRUD, canUserREAD }] = useUserData();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import React, { useMemo } from 'react';
import type { FC } from 'react';

import {
Expand All @@ -13,6 +13,8 @@ import {
ViewerStatus,
} from '@kbn/securitysolution-exception-list-components';
import { EuiLoadingContent } from '@elastic/eui';
import { SecurityPageName } from '../../../../common/constants';
import { SpyRoute } from '../../../common/utils/route/spy_routes';
import { ReferenceErrorModal } from '../../../detections/components/value_lists_management_flyout/reference_error_modal';
import type { Rule } from '../../../detection_engine/rule_management/logic/types';
import { MissingPrivilegesCallOut } from '../../../detections/components/callouts/missing_privileges_callout';
Expand Down Expand Up @@ -53,53 +55,90 @@ export const ListsDetailViewComponent: FC = () => {
handleReferenceDelete,
} = useListDetailsView();

if (viewerStatus === ViewerStatus.ERROR)
return <EmptyViewerState isReadOnly={isReadOnly} viewerStatus={viewerStatus} />;
const detailsViewContent = useMemo(() => {
if (viewerStatus === ViewerStatus.ERROR)
return <EmptyViewerState isReadOnly={isReadOnly} viewerStatus={viewerStatus} />;

if (isLoading) return <EuiLoadingContent lines={4} data-test-subj="loading" />;
if (isLoading) return <EuiLoadingContent lines={4} data-test-subj="loading" />;

if (invalidListId || !listName || !list) return <NotFoundPage />;
return (
<>
<MissingPrivilegesCallOut />
<ExceptionListHeader
name={listName}
description={listDescription}
listId={listId}
linkedRules={linkedRules}
isReadonly={isReadOnly}
canUserEditList={canUserEditList}
backOptions={headerBackOptions}
securityLinkAnchorComponent={ListDetailsLinkAnchor}
onEditListDetails={onEditListDetails}
onExportList={onExportList}
onDeleteList={handleDelete}
onManageRules={onManageRules}
/>
if (invalidListId || !listName || !list) return <NotFoundPage />;
return (
<>
<MissingPrivilegesCallOut />
<ExceptionListHeader
name={listName}
description={listDescription}
listId={listId}
linkedRules={linkedRules}
isReadonly={isReadOnly}
canUserEditList={canUserEditList}
backOptions={headerBackOptions}
securityLinkAnchorComponent={ListDetailsLinkAnchor}
onEditListDetails={onEditListDetails}
onExportList={onExportList}
onDeleteList={handleDelete}
onManageRules={onManageRules}
/>

<AutoDownload blob={exportedList} name={listId} />
<ListWithSearch list={list} refreshExceptions={refreshExceptions} isReadOnly={isReadOnly} />
<ReferenceErrorModal
cancelText={i18n.REFERENCE_MODAL_CANCEL_BUTTON}
confirmText={i18n.REFERENCE_MODAL_CONFIRM_BUTTON}
contentText={referenceModalState.contentText}
onCancel={handleCloseReferenceErrorModal}
onClose={handleCloseReferenceErrorModal}
onConfirm={handleReferenceDelete}
references={referenceModalState.rulesReferences}
showModal={showReferenceErrorModal}
titleText={i18n.REFERENCE_MODAL_TITLE}
/>
{showManageRulesFlyout ? (
<ManageRules
linkedRules={linkedRules as Rule[]}
showButtonLoader={showManageButtonLoader}
saveIsDisabled={disableManageButton}
onSave={onSaveManageRules}
onCancel={onCancelManageRules}
onRuleSelectionChange={onRuleSelectionChange}
<AutoDownload blob={exportedList} name={listId} />
<ListWithSearch list={list} refreshExceptions={refreshExceptions} isReadOnly={isReadOnly} />
<ReferenceErrorModal
cancelText={i18n.REFERENCE_MODAL_CANCEL_BUTTON}
confirmText={i18n.REFERENCE_MODAL_CONFIRM_BUTTON}
contentText={referenceModalState.contentText}
onCancel={handleCloseReferenceErrorModal}
onClose={handleCloseReferenceErrorModal}
onConfirm={handleReferenceDelete}
references={referenceModalState.rulesReferences}
showModal={showReferenceErrorModal}
titleText={i18n.REFERENCE_MODAL_TITLE}
/>
) : null}
{showManageRulesFlyout ? (
<ManageRules
linkedRules={linkedRules as Rule[]}
showButtonLoader={showManageButtonLoader}
saveIsDisabled={disableManageButton}
onSave={onSaveManageRules}
onCancel={onCancelManageRules}
onRuleSelectionChange={onRuleSelectionChange}
/>
) : null}
</>
);
}, [
canUserEditList,
disableManageButton,
exportedList,
headerBackOptions,
invalidListId,
isLoading,
isReadOnly,
linkedRules,
list,
listDescription,
listId,
listName,
referenceModalState.contentText,
referenceModalState.rulesReferences,
refreshExceptions,
showManageButtonLoader,
showManageRulesFlyout,
showReferenceErrorModal,
viewerStatus,
onCancelManageRules,
onEditListDetails,
onExportList,
onManageRules,
onRuleSelectionChange,
onSaveManageRules,
handleCloseReferenceErrorModal,
handleDelete,
handleReferenceDelete,
]);
return (
<>
<SpyRoute pageName={SecurityPageName.exceptions} state={{ listName }} />
{detailsViewContent}
</>
);
};
Expand Down
11 changes: 7 additions & 4 deletions x-pack/plugins/security_solution/public/exceptions/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import { Route } from '@kbn/kibana-react-plugin/public';

import { TrackApplicationView } from '@kbn/usage-collection-plugin/public';
import * as i18n from './translations';
import { EXCEPTIONS_PATH, SecurityPageName } from '../../common/constants';
import {
EXCEPTIONS_PATH,
SecurityPageName,
EXCEPTION_LIST_DETAIL_PATH,
} from '../../common/constants';

import { SharedLists, ListsDetailView } from './pages';
import { SpyRoute } from '../common/utils/route/spy_routes';
Expand All @@ -29,9 +33,8 @@ const ExceptionsRoutes = () => (

const ExceptionsListDetailRoute = () => (
<PluginTemplateWrapper>
<TrackApplicationView viewId={SecurityPageName.sharedExceptionListDetails}>
<TrackApplicationView viewId={SecurityPageName.exceptions}>
<ListsDetailView />
<SpyRoute pageName={SecurityPageName.sharedExceptionListDetails} />
</TrackApplicationView>
</PluginTemplateWrapper>
);
Expand All @@ -42,7 +45,7 @@ const ExceptionsContainerComponent: React.FC = () => {
return (
<Switch>
<Route path={EXCEPTIONS_PATH} exact component={ExceptionsRoutes} />
<Route path={'/exceptions/shared/:exceptionListId'} component={ExceptionsListDetailRoute} />
<Route path={EXCEPTION_LIST_DETAIL_PATH} component={ExceptionsListDetailRoute} />
<Route component={NotFoundPage} />
</Switch>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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 type { ChromeBreadcrumb } from '@kbn/core/public';
import { EXCEPTIONS_PATH } from '../../../common/constants';
import type { GetSecuritySolutionUrl } from '../../common/components/link_to';
import type { RouteSpyState } from '../../common/utils/route/types';

const isListDetailPage = (pathname: string) =>
pathname.includes(EXCEPTIONS_PATH) && pathname.includes('/details');

export const getTrailingBreadcrumbs = (
params: RouteSpyState,
getSecuritySolutionUrl: GetSecuritySolutionUrl
): ChromeBreadcrumb[] => {
let breadcrumb: ChromeBreadcrumb[] = [];

if (isListDetailPage(params.pathName) && params.state?.listName) {
breadcrumb = [
...breadcrumb,
{
text: params.state.listName,
},
];
}
return breadcrumb;
};

0 comments on commit acd9091

Please sign in to comment.