mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Security Solution] Refactor to have one NoPrivileges
component in security solution (#144886)
## Summary There were 3 occurrences of very similar `NoPrivileges` components in the Security Solution plugin. The PR https://github.com/elastic/kibana/pull/144821 added a 4th, universal one, with the intention that it can be reused in the other 3 places. This PR does this refactor. Also, it gets rid of the deprecated `EuiPageTemplate` in `NoPrivilegesPage`, while keeping an (almost) identical look. <img width="633" alt="image" src="https://user-images.githubusercontent.com/39014407/201884047-7f9aabf0-3f6c-4bb7-bf6d-ded6744fc2d2.png"> ## How to test the scenarios <details> <summary><b>1️⃣ Hiding Security Solution paths</b></summary> by <code>security_solution/public/helpers.tsx</code> <br><br> 1. Create a non-superuser user [with the correct cluster privileges](https://www.elastic.co/guide/en/security/master/detections-permissions-section.html), but without Kibana privileges for the Security Solution <img width="717" alt="image" src="https://user-images.githubusercontent.com/39014407/201885331-5d314f06-5a0a-45eb-9e39-ef7ccded8878.png"> 2. Try to open any Security Solution path, like: http://localhost:5601/app/security/timelines or http://localhost:5601/app/security/administration/trusted_apps <img width="789" alt="image" src="https://user-images.githubusercontent.com/39014407/201886156-1227d493-39a1-47c9-a45e-0c318184a7fd.png"> </details> <details> <summary><b>2️⃣ Hiding Detection and Response</b></summary> by <code>security_solution/public/overview/pages/detection_response.tsx</code> <br><br> 1. Create a non-superuser user, with Kibana privilege for Security, but not for Cases, and remove the <code>read</code> index privilege. <img width="721" alt="image" src="https://user-images.githubusercontent.com/39014407/201893652-86f148bb-2080-41a2-89bc-ea4db92c2027.png"> <img width="434" alt="image" src="https://user-images.githubusercontent.com/39014407/201893537-cda1eab6-c165-4c80-8fc6-461091ea0a60.png"> 2. Open Security / Dashboards / Detection & Response: <img width="847" alt="image" src="https://user-images.githubusercontent.com/39014407/201893877-7bcd4f9d-de3f-48d9-a98f-a667a5e8e0b5.png"> </details> <details> <summary><b>3️⃣ Hiding Alerts</b></summary> by <code>security_solution/public/detections/pages/detection_engine/detection_engine.tsx</code> <br> 1. Use the same settings as for 2️⃣: enabled Security solution Kibana privileges, but removed <code>read</code> index privilege. 2. Open Security / Alerts: <img width="800" alt="image" src="https://user-images.githubusercontent.com/39014407/201899277-e12d3134-a246-46de-b89e-ed0733170ede.png"> </details> ### Checklist Delete any items that are not applicable to this PR. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
a152bf98b7
commit
72db89a777
17 changed files with 82 additions and 208 deletions
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* 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, { useMemo } from 'react';
|
||||
|
||||
import { EuiPageTemplate_Deprecated as EuiPageTemplate } from '@elastic/eui';
|
||||
import { SecuritySolutionPageWrapper } from '../common/components/page_wrapper';
|
||||
import { EmptyPage } from '../common/components/empty_page';
|
||||
import { useKibana } from '../common/lib/kibana';
|
||||
import * as i18n from './translations';
|
||||
|
||||
interface NoPrivilegesPageProps {
|
||||
subPluginKey: string;
|
||||
}
|
||||
|
||||
export const NoPrivilegesPage = React.memo<NoPrivilegesPageProps>(({ subPluginKey }) => {
|
||||
const { docLinks } = useKibana().services;
|
||||
const emptyPageActions = useMemo(
|
||||
() => ({
|
||||
feature: {
|
||||
icon: 'documents',
|
||||
label: i18n.GO_TO_DOCUMENTATION,
|
||||
url: `${docLinks.links.siem.privileges}`,
|
||||
target: '_blank',
|
||||
},
|
||||
}),
|
||||
[docLinks]
|
||||
);
|
||||
return (
|
||||
<SecuritySolutionPageWrapper>
|
||||
<EuiPageTemplate template="centeredContent">
|
||||
<EmptyPage
|
||||
actions={emptyPageActions}
|
||||
message={i18n.NO_PERMISSIONS_MSG(subPluginKey)}
|
||||
data-test-subj="no_feature_permissions-alerts"
|
||||
title={i18n.NO_PERMISSIONS_TITLE}
|
||||
/>
|
||||
</EuiPageTemplate>
|
||||
</SecuritySolutionPageWrapper>
|
||||
);
|
||||
});
|
||||
|
||||
NoPrivilegesPage.displayName = 'NoPrivilegePage';
|
|
@ -131,24 +131,6 @@ export const CREATE_NEW_RULE = i18n.translate('xpack.securitySolution.navigation
|
|||
defaultMessage: 'Create new rule',
|
||||
});
|
||||
|
||||
export const GO_TO_DOCUMENTATION = i18n.translate(
|
||||
'xpack.securitySolution.goToDocumentationButton',
|
||||
{
|
||||
defaultMessage: 'View documentation',
|
||||
}
|
||||
);
|
||||
|
||||
export const NO_PERMISSIONS_MSG = (subPluginKey: string) =>
|
||||
i18n.translate('xpack.securitySolution.noPermissionsMessage', {
|
||||
values: { subPluginKey },
|
||||
defaultMessage:
|
||||
'To view {subPluginKey}, you must update privileges. For more information, contact your Kibana administrator.',
|
||||
});
|
||||
|
||||
export const NO_PERMISSIONS_TITLE = i18n.translate('xpack.securitySolution.noPermissionsTitle', {
|
||||
defaultMessage: 'Privileges required',
|
||||
});
|
||||
|
||||
export const THREAT_INTELLIGENCE = i18n.translate(
|
||||
'xpack.securitySolution.navigation.threatIntelligence',
|
||||
{
|
||||
|
|
|
@ -34,9 +34,11 @@ exports[`EmptyPage component renders actions with descriptions 1`] = `
|
|||
}
|
||||
iconType="logoSecurity"
|
||||
title={
|
||||
<h2>
|
||||
My Super Title
|
||||
</h2>
|
||||
<EuiText>
|
||||
<h2>
|
||||
My Super Title
|
||||
</h2>
|
||||
</EuiText>
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
@ -68,9 +70,11 @@ exports[`EmptyPage component renders actions without descriptions 1`] = `
|
|||
}
|
||||
iconType="logoSecurity"
|
||||
title={
|
||||
<h2>
|
||||
My Super Title
|
||||
</h2>
|
||||
<EuiText>
|
||||
<h2>
|
||||
My Super Title
|
||||
</h2>
|
||||
</EuiText>
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
|
|
@ -6,7 +6,14 @@
|
|||
*/
|
||||
|
||||
import type { IconType } from '@elastic/eui';
|
||||
import { EuiButton, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiCard } from '@elastic/eui';
|
||||
import {
|
||||
EuiButton,
|
||||
EuiEmptyPrompt,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiCard,
|
||||
EuiText,
|
||||
} from '@elastic/eui';
|
||||
import type { MouseEventHandler, ReactNode } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
@ -99,7 +106,11 @@ const EmptyPageComponent = React.memo<EmptyPageProps>(({ actions, message, title
|
|||
return (
|
||||
<EmptyPrompt
|
||||
iconType="logoSecurity"
|
||||
title={<h2>{title}</h2>}
|
||||
title={
|
||||
<EuiText>
|
||||
<h2>{title}</h2>
|
||||
</EuiText>
|
||||
}
|
||||
body={message && <p>{message}</p>}
|
||||
actions={<EuiFlexGroup justifyContent="center">{renderActions}</EuiFlexGroup>}
|
||||
{...rest}
|
||||
|
|
|
@ -7,40 +7,53 @@
|
|||
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { EuiPageTemplate_Deprecated as EuiPageTemplate } from '@elastic/eui';
|
||||
import { EuiPageTemplate, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import type { DocLinks } from '@kbn/doc-links';
|
||||
import styled from 'styled-components';
|
||||
import { useKibana } from '../../lib/kibana';
|
||||
import { SecuritySolutionPageWrapper } from '../page_wrapper';
|
||||
import type { EmptyPageActionsProps } from '../empty_page';
|
||||
import { EmptyPage } from '../empty_page';
|
||||
import * as i18n from './translations';
|
||||
|
||||
interface NoPrivilegesPageProps {
|
||||
documentationUrl: string;
|
||||
docLinkSelector: (links: DocLinks) => string;
|
||||
pageName?: string;
|
||||
}
|
||||
|
||||
const SizedEuiFlexItem = styled(EuiFlexItem)`
|
||||
min-height: 460px;
|
||||
font-size: 1.1rem;
|
||||
`;
|
||||
|
||||
export const NoPrivilegesPage = React.memo<NoPrivilegesPageProps>(
|
||||
({ pageName, documentationUrl }) => {
|
||||
return (
|
||||
<SecuritySolutionPageWrapper>
|
||||
<EuiPageTemplate template="centeredContent">
|
||||
<NoPrivileges pageName={pageName} documentationUrl={documentationUrl} />
|
||||
</EuiPageTemplate>
|
||||
</SecuritySolutionPageWrapper>
|
||||
);
|
||||
}
|
||||
({ pageName, docLinkSelector }) => (
|
||||
<SecuritySolutionPageWrapper>
|
||||
<EuiFlexGroup>
|
||||
<SizedEuiFlexItem>
|
||||
<EuiPageTemplate.EmptyPrompt>
|
||||
<NoPrivileges pageName={pageName} docLinkSelector={docLinkSelector} />
|
||||
</EuiPageTemplate.EmptyPrompt>
|
||||
</SizedEuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</SecuritySolutionPageWrapper>
|
||||
)
|
||||
);
|
||||
NoPrivilegesPage.displayName = 'NoPrivilegePage';
|
||||
|
||||
export const NoPrivileges = React.memo<NoPrivilegesPageProps>(({ pageName, documentationUrl }) => {
|
||||
const emptyPageActions = useMemo(
|
||||
export const NoPrivileges = React.memo<NoPrivilegesPageProps>(({ pageName, docLinkSelector }) => {
|
||||
const { docLinks } = useKibana().services;
|
||||
|
||||
const emptyPageActions = useMemo<EmptyPageActionsProps>(
|
||||
() => ({
|
||||
feature: {
|
||||
icon: 'documents',
|
||||
label: i18n.GO_TO_DOCUMENTATION,
|
||||
url: documentationUrl,
|
||||
url: docLinkSelector(docLinks.links),
|
||||
target: '_blank',
|
||||
},
|
||||
}),
|
||||
[documentationUrl]
|
||||
[docLinkSelector, docLinks.links]
|
||||
);
|
||||
|
||||
const message = pageName
|
||||
|
|
|
@ -25,6 +25,7 @@ import { connect, useDispatch } from 'react-redux';
|
|||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { isTab } from '@kbn/timelines-plugin/public';
|
||||
import type { DocLinks } from '@kbn/doc-links';
|
||||
import { FILTER_OPEN, TableId } from '../../../../common/types';
|
||||
import { tableDefaults } from '../../../common/store/data_table/defaults';
|
||||
import { dataTableActions, dataTableSelectors } from '../../../common/store/data_table';
|
||||
|
@ -71,7 +72,7 @@ import { NeedAdminForUpdateRulesCallOut } from '../../components/callouts/need_a
|
|||
import { MissingPrivilegesCallOut } from '../../components/callouts/missing_privileges_callout';
|
||||
import { useKibana } from '../../../common/lib/kibana';
|
||||
import { AlertsTableFilterGroup } from '../../components/alerts_table/alerts_filter_group';
|
||||
import { EmptyPage } from '../../../common/components/empty_page';
|
||||
import { NoPrivileges } from '../../../common/components/no_privileges';
|
||||
import { HeaderPage } from '../../../common/components/header_page';
|
||||
import { LandingPageComponent } from '../../../common/components/landing_page';
|
||||
|
||||
|
@ -141,7 +142,6 @@ const DetectionEnginePageComponent: React.FC<DetectionEngineComponentProps> = ({
|
|||
application: { navigateToUrl },
|
||||
timelines: timelinesUi,
|
||||
data,
|
||||
docLinks,
|
||||
} = useKibana().services;
|
||||
const [filterGroup, setFilterGroup] = useState<Status>(FILTER_OPEN);
|
||||
|
||||
|
@ -258,18 +258,6 @@ const DetectionEnginePageComponent: React.FC<DetectionEngineComponentProps> = ({
|
|||
[containerElement, onSkipFocusBeforeEventsTable, onSkipFocusAfterEventsTable]
|
||||
);
|
||||
|
||||
const emptyPageActions = useMemo(
|
||||
() => ({
|
||||
feature: {
|
||||
icon: 'documents',
|
||||
label: i18n.GO_TO_DOCUMENTATION,
|
||||
url: `${docLinks.links.siem.privileges}`,
|
||||
target: '_blank',
|
||||
},
|
||||
}),
|
||||
[docLinks]
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<SecuritySolutionPageWrapper>
|
||||
|
@ -307,11 +295,9 @@ const DetectionEnginePageComponent: React.FC<DetectionEngineComponentProps> = ({
|
|||
<NeedAdminForUpdateRulesCallOut />
|
||||
<MissingPrivilegesCallOut />
|
||||
{!signalIndexNeedsInit && (hasIndexRead === false || canUserREAD === false) ? (
|
||||
<EmptyPage
|
||||
actions={emptyPageActions}
|
||||
message={i18n.ALERTS_FEATURE_NO_PERMISSIONS_MSG}
|
||||
data-test-subj="no_feature_permissions-alerts"
|
||||
title={i18n.FEATURE_NO_PERMISSIONS_TITLE}
|
||||
<NoPrivileges
|
||||
pageName={i18n.PAGE_TITLE.toLowerCase()}
|
||||
docLinkSelector={(docLinks: DocLinks) => docLinks.siem.privileges}
|
||||
/>
|
||||
) : !signalIndexNeedsInit && hasIndexRead && canUserREAD ? (
|
||||
<StyledFullHeightContainer onKeyDown={onKeyDown} ref={containerElement}>
|
||||
|
|
|
@ -95,18 +95,3 @@ export const ML_RULES_UNAVAILABLE = (totalRules: number) =>
|
|||
defaultMessage:
|
||||
'{totalRules} {totalRules, plural, =1 {rule requires} other {rules require}} Machine Learning to enable.',
|
||||
});
|
||||
|
||||
export const FEATURE_NO_PERMISSIONS_TITLE = i18n.translate(
|
||||
'xpack.securitySolution.detectionEngine.noPermissionsTitle',
|
||||
{
|
||||
defaultMessage: 'Privileges required',
|
||||
}
|
||||
);
|
||||
|
||||
export const ALERTS_FEATURE_NO_PERMISSIONS_MSG = i18n.translate(
|
||||
'xpack.securitySolution.detectionEngine.noPermissionsMessage',
|
||||
{
|
||||
defaultMessage:
|
||||
'To view alerts, you must update privileges. For more information, contact your Kibana administrator.',
|
||||
}
|
||||
);
|
||||
|
|
|
@ -88,7 +88,8 @@ describe('#getSubPluginRoutesByCapabilities', () => {
|
|||
const CasesView = (casesRoute?.component ?? mockRender) as React.ComponentType<any>;
|
||||
expect(shallow(<CasesView />)).toMatchInlineSnapshot(`
|
||||
<NoPrivilegePage
|
||||
subPluginKey="cases"
|
||||
docLinkSelector={[Function]}
|
||||
pageName="cases"
|
||||
/>
|
||||
`);
|
||||
});
|
||||
|
@ -103,7 +104,8 @@ describe('#getSubPluginRoutesByCapabilities', () => {
|
|||
const AlertsView = (alertsRoute?.component ?? mockRender) as React.ComponentType<any>;
|
||||
expect(shallow(<AlertsView />)).toMatchInlineSnapshot(`
|
||||
<NoPrivilegePage
|
||||
subPluginKey="alerts"
|
||||
docLinkSelector={[Function]}
|
||||
pageName="alerts"
|
||||
/>
|
||||
`);
|
||||
});
|
||||
|
@ -123,12 +125,14 @@ describe('#getSubPluginRoutesByCapabilities', () => {
|
|||
|
||||
expect(shallow(<AlertsView />)).toMatchInlineSnapshot(`
|
||||
<NoPrivilegePage
|
||||
subPluginKey="alerts"
|
||||
docLinkSelector={[Function]}
|
||||
pageName="alerts"
|
||||
/>
|
||||
`);
|
||||
expect(shallow(<CasesView />)).toMatchInlineSnapshot(`
|
||||
<NoPrivilegePage
|
||||
subPluginKey="cases"
|
||||
docLinkSelector={[Function]}
|
||||
pageName="cases"
|
||||
/>
|
||||
`);
|
||||
});
|
||||
|
|
|
@ -12,6 +12,7 @@ import type { RouteProps } from 'react-router-dom';
|
|||
import { matchPath, Redirect } from 'react-router-dom';
|
||||
|
||||
import type { Capabilities, CoreStart } from '@kbn/core/public';
|
||||
import type { DocLinks } from '@kbn/doc-links';
|
||||
import {
|
||||
ALERTS_PATH,
|
||||
APP_UI_ID,
|
||||
|
@ -29,7 +30,7 @@ import type {
|
|||
StrategyResponseType,
|
||||
} from '../common/search_strategy/security_solution';
|
||||
import type { TimelineEqlResponse } from '../common/search_strategy/timeline';
|
||||
import { NoPrivilegesPage } from './app/no_privileges';
|
||||
import { NoPrivilegesPage } from './common/components/no_privileges';
|
||||
import { SecurityPageName } from './app/types';
|
||||
import type { InspectResponse, StartedSubPlugins } from './types';
|
||||
import { CASES_SUB_PLUGIN_KEY } from './types';
|
||||
|
@ -200,11 +201,13 @@ export const getSubPluginRoutesByCapabilities = (
|
|||
if (isSubPluginAvailable(key, capabilities)) {
|
||||
return [...acc, ...value.routes];
|
||||
}
|
||||
const docLinkSelector = (docLinks: DocLinks) => docLinks.siem.privileges;
|
||||
|
||||
return [
|
||||
...acc,
|
||||
...value.routes.map((route: RouteProps) => ({
|
||||
path: route.path,
|
||||
component: () => <NoPrivilegesPage subPluginKey={key} />,
|
||||
component: () => <NoPrivilegesPage pageName={key} docLinkSelector={docLinkSelector} />,
|
||||
})),
|
||||
];
|
||||
}, []),
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
import type { ComponentType } from 'react';
|
||||
import React, { memo } from 'react';
|
||||
import { Route } from '@kbn/kibana-react-plugin/public';
|
||||
import type { DocLinks } from '@kbn/doc-links';
|
||||
import { NoPrivilegesPage } from '../../../common/components/no_privileges';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features';
|
||||
import { NoPermissions } from '../no_permissons';
|
||||
import { useKibana } from '../../../common/lib/kibana';
|
||||
import { MANAGEMENT_ROUTING_RESPONSE_ACTIONS_HISTORY_PATH } from '../../common/constants';
|
||||
|
||||
export interface PrivilegedRouteProps {
|
||||
|
@ -20,10 +20,11 @@ export interface PrivilegedRouteProps {
|
|||
}
|
||||
|
||||
export const PrivilegedRoute = memo(({ component, hasPrivilege, path }: PrivilegedRouteProps) => {
|
||||
const { docLinks } = useKibana().services;
|
||||
const isEndpointRbacEnabled = useIsExperimentalFeatureEnabled('endpointRbacEnabled');
|
||||
const isEndpointRbacV1Enabled = useIsExperimentalFeatureEnabled('endpointRbacV1Enabled');
|
||||
|
||||
const docLinkSelector = (docLinks: DocLinks) => docLinks.securitySolution.privileges;
|
||||
|
||||
let componentToRender = component;
|
||||
|
||||
if (!hasPrivilege) {
|
||||
|
@ -32,7 +33,7 @@ export const PrivilegedRoute = memo(({ component, hasPrivilege, path }: Privileg
|
|||
(isEndpointRbacV1Enabled && path === MANAGEMENT_ROUTING_RESPONSE_ACTIONS_HISTORY_PATH);
|
||||
|
||||
componentToRender = shouldUseMissingPrivilegesScreen
|
||||
? () => <NoPrivilegesPage documentationUrl={docLinks.links.securitySolution.privileges} />
|
||||
? () => <NoPrivilegesPage docLinkSelector={docLinkSelector} />
|
||||
: NoPermissions;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import { EuiSpacer, EuiLoadingSpinner, EuiFlexGroup, EuiFlexItem } from '@elasti
|
|||
import type { PackageCustomExtensionComponentProps } from '@kbn/fleet-plugin/public';
|
||||
import { NoPrivileges } from '../../../../../../common/components/no_privileges';
|
||||
import { useCanAccessSomeArtifacts } from '../hooks/use_can_access_some_artifacts';
|
||||
import { useHttp, useKibana } from '../../../../../../common/lib/kibana';
|
||||
import { useHttp } from '../../../../../../common/lib/kibana';
|
||||
import { TrustedAppsApiClient } from '../../../../trusted_apps/service/api_client';
|
||||
import { EventFiltersApiClient } from '../../../../event_filters/service/api_client';
|
||||
import { HostIsolationExceptionsApiClient } from '../../../../host_isolation_exceptions/host_isolation_exceptions_api_client';
|
||||
|
@ -116,7 +116,6 @@ export const EndpointPackageCustomExtension = memo<PackageCustomExtensionCompone
|
|||
canReadTrustedApplications,
|
||||
canReadHostIsolationExceptions,
|
||||
} = useEndpointPrivileges();
|
||||
const { docLinks } = useKibana().services;
|
||||
|
||||
const userCanAccessContent = useCanAccessSomeArtifacts();
|
||||
|
||||
|
@ -126,7 +125,7 @@ export const EndpointPackageCustomExtension = memo<PackageCustomExtensionCompone
|
|||
}
|
||||
|
||||
if (!userCanAccessContent) {
|
||||
return <NoPrivileges documentationUrl={docLinks.links.securitySolution.privileges} />;
|
||||
return <NoPrivileges docLinkSelector={(links) => links.securitySolution.privileges} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -160,7 +159,6 @@ export const EndpointPackageCustomExtension = memo<PackageCustomExtensionCompone
|
|||
canReadEventFilters,
|
||||
canReadTrustedApplications,
|
||||
canReadHostIsolationExceptions,
|
||||
docLinks.links.securitySolution.privileges,
|
||||
loading,
|
||||
props,
|
||||
userCanAccessContent,
|
||||
|
|
|
@ -227,6 +227,6 @@ describe('DetectionResponse', () => {
|
|||
);
|
||||
|
||||
expect(result.queryByTestId('detectionResponsePage')).not.toBeInTheDocument();
|
||||
expect(result.queryByTestId('noPermissionPage')).toBeInTheDocument();
|
||||
expect(result.queryByTestId('noPrivilegesPage')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import React, { useMemo } from 'react';
|
||||
import React from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui';
|
||||
import type { DocLinks } from '@kbn/doc-links';
|
||||
import { InputsModelId } from '../../common/store/inputs/constants';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features';
|
||||
import { SocTrends } from '../components/detection_response/soc_trends';
|
||||
|
@ -17,9 +18,8 @@ import { useSourcererDataView } from '../../common/containers/sourcerer';
|
|||
import { useSignalIndex } from '../../detections/containers/detection_engine/alerts/use_signal_index';
|
||||
import { useAlertsPrivileges } from '../../detections/containers/detection_engine/alerts/use_alerts_privileges';
|
||||
import { HeaderPage } from '../../common/components/header_page';
|
||||
import { useKibana, useGetUserCasesPermissions } from '../../common/lib/kibana';
|
||||
import { useGetUserCasesPermissions } from '../../common/lib/kibana';
|
||||
|
||||
import { EmptyPage } from '../../common/components/empty_page';
|
||||
import { LandingPageComponent } from '../../common/components/landing_page';
|
||||
import { AlertsByStatus } from '../components/detection_response/alerts_by_status';
|
||||
import { HostAlertsTable } from '../components/detection_response/host_alerts_table';
|
||||
|
@ -28,29 +28,7 @@ import { UserAlertsTable } from '../components/detection_response/user_alerts_ta
|
|||
import * as i18n from './translations';
|
||||
import { CasesTable } from '../components/detection_response/cases_table';
|
||||
import { CasesByStatus } from '../components/detection_response/cases_by_status';
|
||||
|
||||
const NoPrivilegePage: React.FC = () => {
|
||||
const { docLinks } = useKibana().services;
|
||||
const emptyPageActions = useMemo(
|
||||
() => ({
|
||||
feature: {
|
||||
icon: 'documents',
|
||||
label: i18n.GO_TO_DOCUMENTATION,
|
||||
url: `${docLinks.links.siem.privileges}`,
|
||||
target: '_blank',
|
||||
},
|
||||
}),
|
||||
[docLinks]
|
||||
);
|
||||
return (
|
||||
<EmptyPage
|
||||
data-test-subj="noPermissionPage"
|
||||
actions={emptyPageActions}
|
||||
title={i18n.NO_PERMISSIONS_TITLE}
|
||||
message={i18n.NO_PERMISSIONS_MSG}
|
||||
/>
|
||||
);
|
||||
};
|
||||
import { NoPrivileges } from '../../common/components/no_privileges';
|
||||
|
||||
const DetectionResponseComponent = () => {
|
||||
const { indicesExist, indexPattern, loading: isSourcererLoading } = useSourcererDataView();
|
||||
|
@ -60,7 +38,7 @@ const DetectionResponseComponent = () => {
|
|||
const canReadAlerts = hasKibanaREAD && hasIndexRead;
|
||||
const isSocTrendsEnabled = useIsExperimentalFeatureEnabled('socTrendsEnabled');
|
||||
if (!canReadAlerts && !canReadCases) {
|
||||
return <NoPrivilegePage />;
|
||||
return <NoPrivileges docLinkSelector={(docLinks: DocLinks) => docLinks.siem.privileges} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -58,26 +58,6 @@ export const ENTITY_ANALYTICS_LICENSE_DESC = i18n.translate(
|
|||
}
|
||||
);
|
||||
|
||||
export const NO_PERMISSIONS_MSG = i18n.translate(
|
||||
'xpack.securitySolution.detectionResponse.noPagePermissionsMessage',
|
||||
{
|
||||
defaultMessage:
|
||||
'To view this page you must update privileges. For more information, contact your Kibana administrator.',
|
||||
}
|
||||
);
|
||||
export const NO_PERMISSIONS_TITLE = i18n.translate(
|
||||
'xpack.securitySolution.detectionResponse.noPermissionsTitle',
|
||||
{
|
||||
defaultMessage: 'Privileges required',
|
||||
}
|
||||
);
|
||||
export const GO_TO_DOCUMENTATION = i18n.translate(
|
||||
'xpack.securitySolution.detectionResponse.goToDocumentationButton',
|
||||
{
|
||||
defaultMessage: 'View documentation',
|
||||
}
|
||||
);
|
||||
|
||||
export const TECHNICAL_PREVIEW = i18n.translate(
|
||||
'xpack.securitySolution.entityAnalytics.technicalPreviewLabel',
|
||||
{
|
||||
|
|
|
@ -27205,7 +27205,7 @@
|
|||
"xpack.securitySolution.networkTopCountriesTable.rows": "{numRows} {numRows, plural, =0 {ligne} =1 {ligne} other {lignes}}",
|
||||
"xpack.securitySolution.networkTopNFlowTable.rows": "{numRows} {numRows, plural, =0 {ligne} =1 {ligne} other {lignes}}",
|
||||
"xpack.securitySolution.networkTopNFlowTable.unit": "{totalCount, plural, other {IP}}",
|
||||
"xpack.securitySolution.noPermissionsMessage": "Pour afficher {subPluginKey}, vous devez mettre à jour les privilèges. Pour en savoir plus, contactez votre administrateur Kibana.",
|
||||
"xpack.securitySolution.noPrivilegesDefaultMessage": "Pour afficher cette page, vous devez mettre à jour les privilèges. Pour en savoir plus, contactez votre administrateur Kibana.",
|
||||
"xpack.securitySolution.noPrivilegesPerPageMessage": "Pour afficher {pageName}, vous devez mettre à jour les privilèges. Pour en savoir plus, contactez votre administrateur Kibana.",
|
||||
"xpack.securitySolution.notes.youAreViewingNotesScreenReaderOnly": "Vous visualisez des notes pour l'événement de la ligne {row}. Appuyez sur la touche fléchée vers le haut lorsque vous aurez terminé pour revenir à l'événement.",
|
||||
"xpack.securitySolution.open.timeline.deleteTimelineModalTitle": "Supprimer \"{title}\" ?",
|
||||
|
@ -28911,8 +28911,6 @@
|
|||
"xpack.securitySolution.detectionEngine.noApiIntegrationKeyCallOutMsg": "Une nouvelle clé de chiffrement est générée pour les objets enregistrés chaque fois que vous démarrez Kibana. Sans clé persistante, vous ne pouvez pas supprimer ou modifier des règles après le redémarrage de Kibana. Pour définir une clé persistante, ajoutez le paramètre xpack.encryptedSavedObjects.encryptionKey avec n'importe quelle valeur texte de 32 caractères ou plus au fichier kibana.yml.",
|
||||
"xpack.securitySolution.detectionEngine.noApiIntegrationKeyCallOutTitle": "Clé d'intégration d'API requise",
|
||||
"xpack.securitySolution.detectionEngine.noIndexTitle": "Configurons votre moteur de détection",
|
||||
"xpack.securitySolution.detectionEngine.noPermissionsMessage": "Pour afficher les alertes, vous devez mettre à jour les privilèges. Pour en savoir plus, contactez votre administrateur Kibana.",
|
||||
"xpack.securitySolution.detectionEngine.noPermissionsTitle": "Privilèges requis",
|
||||
"xpack.securitySolution.detectionEngine.pageTitle": "Moteur de détection",
|
||||
"xpack.securitySolution.detectionEngine.queryPreview.actions": "Actions",
|
||||
"xpack.securitySolution.detectionEngine.queryPreview.histogramDisclaimer": "Remarque : Les alertes ayant plusieurs valeurs event.category seront comptées plusieurs fois.",
|
||||
|
@ -29180,15 +29178,12 @@
|
|||
"xpack.securitySolution.detectionResponse.criticalAlerts": "Alertes critiques ouvertes",
|
||||
"xpack.securitySolution.detectionResponse.criticalAlertsDescription": "Nombre d'alertes critiques ouvertes pour la plage temporelle actuelle",
|
||||
"xpack.securitySolution.detectionResponse.errorMessage": "Erreur lors de la récupération des données de cas",
|
||||
"xpack.securitySolution.detectionResponse.goToDocumentationButton": "Afficher la documentation",
|
||||
"xpack.securitySolution.detectionResponse.hostAlertsHostName": "Nom d'hôte",
|
||||
"xpack.securitySolution.detectionResponse.hostAlertsSectionTitle": "Hôtes par sévérité d'alerte",
|
||||
"xpack.securitySolution.detectionResponse.hostSectionTooltip": "Maximum de 100 hôtes. Veuillez consulter la page Alertes pour plus d'informations.",
|
||||
"xpack.securitySolution.detectionResponse.investigateInTimeline": "Investiguer dans la chronologie",
|
||||
"xpack.securitySolution.detectionResponse.mttr": "Temps de réponse moyenne pour les cas",
|
||||
"xpack.securitySolution.detectionResponse.mttrDescription": "La durée moyenne (de la création à la clôture) de vos cas en cours",
|
||||
"xpack.securitySolution.detectionResponse.noPagePermissionsMessage": "Pour afficher cette page, vous devez mettre à jour les privilèges. Pour en savoir plus, contactez votre administrateur Kibana.",
|
||||
"xpack.securitySolution.detectionResponse.noPermissionsTitle": "Privilèges requis",
|
||||
"xpack.securitySolution.detectionResponse.noRecentCases": "Aucun cas à afficher",
|
||||
"xpack.securitySolution.detectionResponse.noRuleAlerts": "Aucune alerte à afficher",
|
||||
"xpack.securitySolution.detectionResponse.openAllAlertsButton": "Afficher toutes les alertes ouvertes",
|
||||
|
@ -30487,7 +30482,6 @@
|
|||
"xpack.securitySolution.newsFeed.noNewsMessage": "Votre URL de fil d'actualités en cours n'a renvoyé aucune nouvelle récente.",
|
||||
"xpack.securitySolution.newsFeed.noNewsMessageForAdmin": "Votre URL de fil d'actualités en cours n'a renvoyé aucune nouvelle récente. Vous pouvez mettre à jour l'URL ou désactiver les nouvelles de sécurité via",
|
||||
"xpack.securitySolution.noPermissionsTitle": "Privilèges requis",
|
||||
"xpack.securitySolution.noPrivilegesDefaultMessage": "Pour afficher cette page, vous devez mettre à jour les privilèges. Pour en savoir plus, contactez votre administrateur Kibana.",
|
||||
"xpack.securitySolution.notes.addNoteButtonLabel": "Ajouter la note",
|
||||
"xpack.securitySolution.notes.cancelButtonLabel": "Annuler",
|
||||
"xpack.securitySolution.notes.createdByLabel": "Créé par",
|
||||
|
|
|
@ -27179,7 +27179,6 @@
|
|||
"xpack.securitySolution.networkTopCountriesTable.rows": "{numRows} {numRows, plural, other {行}}",
|
||||
"xpack.securitySolution.networkTopNFlowTable.rows": "{numRows} {numRows, plural, other {行}}",
|
||||
"xpack.securitySolution.networkTopNFlowTable.unit": "{totalCount, plural, other {IP}}",
|
||||
"xpack.securitySolution.noPermissionsMessage": "{subPluginKey}を表示するには、権限を更新する必要があります。詳細については、Kibana管理者に連絡してください。",
|
||||
"xpack.securitySolution.noPrivilegesPerPageMessage": "{pageName}を表示するには、権限を更新する必要があります。詳細については、Kibana管理者に連絡してください。",
|
||||
"xpack.securitySolution.notes.youAreViewingNotesScreenReaderOnly": "行 {row} のイベントのメモを表示しています。完了したら上矢印キーを押して、イベントに戻ります。",
|
||||
"xpack.securitySolution.open.timeline.deleteTimelineModalTitle": "「{title}」を削除しますか?",
|
||||
|
@ -28885,8 +28884,6 @@
|
|||
"xpack.securitySolution.detectionEngine.noApiIntegrationKeyCallOutMsg": "Kibanaを起動するごとに保存されたオブジェクトの新しい暗号化キーを作成します。永続キーがないと、Kibanaの再起動後にルールを削除または修正することができません。永続キーを設定するには、kibana.ymlファイルに32文字以上のテキスト値を付けてxpack.encryptedSavedObjects.encryptionKey設定を追加してください。",
|
||||
"xpack.securitySolution.detectionEngine.noApiIntegrationKeyCallOutTitle": "API統合キーが必要です",
|
||||
"xpack.securitySolution.detectionEngine.noIndexTitle": "検出エンジンを設定しましょう",
|
||||
"xpack.securitySolution.detectionEngine.noPermissionsMessage": "アラートを表示するには、権限を更新する必要があります。詳細については、Kibana管理者に連絡してください。",
|
||||
"xpack.securitySolution.detectionEngine.noPermissionsTitle": "権限が必要です",
|
||||
"xpack.securitySolution.detectionEngine.pageTitle": "検出エンジン",
|
||||
"xpack.securitySolution.detectionEngine.queryPreview.actions": "アクション",
|
||||
"xpack.securitySolution.detectionEngine.queryPreview.histogramDisclaimer": "注:複数のevent.category値のアラートは2回以上カウントされます。",
|
||||
|
@ -29154,15 +29151,9 @@
|
|||
"xpack.securitySolution.detectionResponse.criticalAlerts": "重大アラートを開く",
|
||||
"xpack.securitySolution.detectionResponse.criticalAlertsDescription": "現在の時間範囲で未解決の重大なアラートの件数",
|
||||
"xpack.securitySolution.detectionResponse.errorMessage": "ケースデータの取得エラー",
|
||||
"xpack.securitySolution.detectionResponse.goToDocumentationButton": "ドキュメンテーションを表示",
|
||||
"xpack.securitySolution.detectionResponse.hostAlertsHostName": "ホスト名",
|
||||
"xpack.securitySolution.detectionResponse.hostAlertsSectionTitle": "アラート重要度別ホスト",
|
||||
"xpack.securitySolution.detectionResponse.hostSectionTooltip": "最大100ホスト。詳細については、「アラート」ページを参照してください。",
|
||||
"xpack.securitySolution.detectionResponse.investigateInTimeline": "タイムラインで調査",
|
||||
"xpack.securitySolution.detectionResponse.mttr": "平均ケース応答時間",
|
||||
"xpack.securitySolution.detectionResponse.mttrDescription": "現在のアセットの平均期間(作成から終了まで)",
|
||||
"xpack.securitySolution.detectionResponse.noPagePermissionsMessage": "このページを表示するには、権限を更新する必要があります。詳細については、Kibana管理者に連絡してください。",
|
||||
"xpack.securitySolution.detectionResponse.noPermissionsTitle": "権限が必要です",
|
||||
"xpack.securitySolution.detectionResponse.noRecentCases": "表示するケースがありません。",
|
||||
"xpack.securitySolution.detectionResponse.noRuleAlerts": "表示するアラートがありません",
|
||||
"xpack.securitySolution.detectionResponse.openAllAlertsButton": "すべての未解決のアラートを表示",
|
||||
|
|
|
@ -27213,7 +27213,6 @@
|
|||
"xpack.securitySolution.networkTopCountriesTable.rows": "{numRows} {numRows, plural, other {行}}",
|
||||
"xpack.securitySolution.networkTopNFlowTable.rows": "{numRows} {numRows, plural, other {行}}",
|
||||
"xpack.securitySolution.networkTopNFlowTable.unit": "{totalCount, plural, other {个 IP}}",
|
||||
"xpack.securitySolution.noPermissionsMessage": "要查看 {subPluginKey},必须更新权限。有关详细信息,请联系您的 Kibana 管理员。",
|
||||
"xpack.securitySolution.noPrivilegesPerPageMessage": "要查看 {pageName},必须更新权限。有关详细信息,请联系您的 Kibana 管理员。",
|
||||
"xpack.securitySolution.notes.youAreViewingNotesScreenReaderOnly": "您正在查看事件在第 {row} 行的备注。完成后,按向上箭头键可返回到事件。",
|
||||
"xpack.securitySolution.open.timeline.deleteTimelineModalTitle": "删除“{title}”?",
|
||||
|
@ -28918,8 +28917,6 @@
|
|||
"xpack.securitySolution.detectionEngine.noApiIntegrationKeyCallOutMsg": "每次启动 Kibana,都会为已保存对象生成新的加密密钥。没有持久性密钥,在 Kibana 重新启动后,将无法删除或修改规则。要设置持久性密钥,请将文本值为 32 个或更多任意字符的 xpack.encryptedSavedObjects.encryptionKey 设置添加到 kibana.yml 文件。",
|
||||
"xpack.securitySolution.detectionEngine.noApiIntegrationKeyCallOutTitle": "需要 API 集成密钥",
|
||||
"xpack.securitySolution.detectionEngine.noIndexTitle": "让我们来设置您的检测引擎",
|
||||
"xpack.securitySolution.detectionEngine.noPermissionsMessage": "要查看告警,必须更新权限。有关详细信息,请联系您的 Kibana 管理员。",
|
||||
"xpack.securitySolution.detectionEngine.noPermissionsTitle": "需要权限",
|
||||
"xpack.securitySolution.detectionEngine.pageTitle": "检测引擎",
|
||||
"xpack.securitySolution.detectionEngine.queryPreview.actions": "操作",
|
||||
"xpack.securitySolution.detectionEngine.queryPreview.histogramDisclaimer": "注意:具有多个 event.category 值的告警会计算多次。",
|
||||
|
@ -29187,15 +29184,9 @@
|
|||
"xpack.securitySolution.detectionResponse.criticalAlerts": "打开的紧急告警",
|
||||
"xpack.securitySolution.detectionResponse.criticalAlertsDescription": "当前时间范围内打开的紧急告警的数量",
|
||||
"xpack.securitySolution.detectionResponse.errorMessage": "提取案例数据时出错",
|
||||
"xpack.securitySolution.detectionResponse.goToDocumentationButton": "查看文档",
|
||||
"xpack.securitySolution.detectionResponse.hostAlertsHostName": "主机名",
|
||||
"xpack.securitySolution.detectionResponse.hostAlertsSectionTitle": "主机(按告警严重性排列)",
|
||||
"xpack.securitySolution.detectionResponse.hostSectionTooltip": "最多 100 个主机。请访问“告警”页面获取更多信息。",
|
||||
"xpack.securitySolution.detectionResponse.investigateInTimeline": "在时间线中调查",
|
||||
"xpack.securitySolution.detectionResponse.mttr": "平均案例响应时间",
|
||||
"xpack.securitySolution.detectionResponse.mttrDescription": "当前案例的平均持续时间(从创建到关闭)",
|
||||
"xpack.securitySolution.detectionResponse.noPagePermissionsMessage": "要查看此页面,必须更新权限。有关详细信息,请联系您的 Kibana 管理员。",
|
||||
"xpack.securitySolution.detectionResponse.noPermissionsTitle": "需要权限",
|
||||
"xpack.securitySolution.detectionResponse.noRecentCases": "没有可显示的案例",
|
||||
"xpack.securitySolution.detectionResponse.noRuleAlerts": "没有可显示的告警",
|
||||
"xpack.securitySolution.detectionResponse.openAllAlertsButton": "查看所有打开的告警",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue