mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Security Solution][Notes] - move notes management page under manage section instead of timeline (#194250)
This commit is contained in:
parent
8eceb0db4d
commit
39ac875b76
29 changed files with 372 additions and 211 deletions
|
@ -87,5 +87,5 @@ export enum SecurityPageName {
|
|||
entityAnalyticsManagement = 'entity_analytics-management',
|
||||
entityAnalyticsAssetClassification = 'entity_analytics-asset-classification',
|
||||
coverageOverview = 'coverage-overview',
|
||||
notesManagement = 'notes-management',
|
||||
notes = 'notes',
|
||||
}
|
||||
|
|
|
@ -133,7 +133,7 @@ export const APP_HOST_ISOLATION_EXCEPTIONS_PATH =
|
|||
export const APP_BLOCKLIST_PATH = `${APP_PATH}${BLOCKLIST_PATH}` as const;
|
||||
export const APP_RESPONSE_ACTIONS_HISTORY_PATH =
|
||||
`${APP_PATH}${RESPONSE_ACTIONS_HISTORY_PATH}` as const;
|
||||
export const NOTES_MANAGEMENT_PATH = `/notes_management` as const;
|
||||
export const NOTES_PATH = `${MANAGEMENT_PATH}/notes` as const;
|
||||
|
||||
// cloud logs to exclude from default index pattern
|
||||
export const EXCLUDE_ELASTIC_CLOUD_INDICES = ['-*elastic-cloud-logs-*'];
|
||||
|
|
|
@ -6,9 +6,13 @@
|
|||
*/
|
||||
|
||||
import { SecurityPageName } from '@kbn/security-solution-navigation';
|
||||
import { cloneDeep, remove } from 'lodash';
|
||||
import { cloneDeep, remove, find } from 'lodash';
|
||||
import type { AppLinkItems, LinkItem } from '../../../common/links/types';
|
||||
import { createInvestigationsLinkFromTimeline } from './sections/investigations_links';
|
||||
import {
|
||||
createInvestigationsLinkFromNotes,
|
||||
createInvestigationsLinkFromTimeline,
|
||||
updateInvestigationsLinkFromNotes,
|
||||
} from './sections/investigations_links';
|
||||
import { mlAppLink } from './sections/ml_links';
|
||||
import { createAssetsLinkFromManage } from './sections/assets_links';
|
||||
import { createSettingsLinksFromManage } from './sections/settings_links';
|
||||
|
@ -26,6 +30,19 @@ export const solutionAppLinksSwitcher = (appLinks: AppLinkItems): AppLinkItems =
|
|||
solutionAppLinks.push(createInvestigationsLinkFromTimeline(timelineLinkItem));
|
||||
}
|
||||
|
||||
// Remove note link
|
||||
const investigationsLinkItem = find(solutionAppLinks, { id: SecurityPageName.investigations });
|
||||
const [noteLinkItem] = remove(solutionAppLinks, { id: SecurityPageName.notes });
|
||||
if (noteLinkItem) {
|
||||
if (!investigationsLinkItem) {
|
||||
solutionAppLinks.push(createInvestigationsLinkFromNotes(noteLinkItem));
|
||||
} else {
|
||||
solutionAppLinks.push(
|
||||
updateInvestigationsLinkFromNotes(investigationsLinkItem, noteLinkItem)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove manage link
|
||||
const [manageLinkItem] = remove(solutionAppLinks, { id: SecurityPageName.administration });
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import { ExternalPageName, SecurityPageName } from '@kbn/security-solution-navigation';
|
||||
import IconFilebeatChart from './icons/filebeat_chart';
|
||||
import { INVESTIGATIONS_PATH } from '../../../../../common/constants';
|
||||
import { SERVER_APP_ID } from '../../../../../common';
|
||||
import type { LinkItem } from '../../../../common/links/types';
|
||||
|
@ -21,7 +22,7 @@ const investigationsAppLink: LinkItem = {
|
|||
capabilities: [`${SERVER_APP_ID}.show`],
|
||||
hideTimeline: true,
|
||||
skipUrlState: true,
|
||||
links: [], // timeline link are added in createInvestigationsLinkFromTimeline
|
||||
links: [], // timeline and note links are added via the methods below
|
||||
};
|
||||
|
||||
export const createInvestigationsLinkFromTimeline = (timelineLink: LinkItem): LinkItem => {
|
||||
|
@ -33,6 +34,29 @@ export const createInvestigationsLinkFromTimeline = (timelineLink: LinkItem): Li
|
|||
};
|
||||
};
|
||||
|
||||
export const createInvestigationsLinkFromNotes = (noteLink: LinkItem): LinkItem => {
|
||||
return {
|
||||
...investigationsAppLink,
|
||||
links: [{ ...noteLink, description: i18n.NOTE_DESCRIPTION, landingIcon: IconTimelineLazy }],
|
||||
};
|
||||
};
|
||||
|
||||
export const updateInvestigationsLinkFromNotes = (
|
||||
investigationsLink: LinkItem,
|
||||
noteLink: LinkItem
|
||||
): LinkItem => {
|
||||
const currentLinks = investigationsLink.links ?? [];
|
||||
currentLinks.push({
|
||||
...noteLink,
|
||||
description: i18n.NOTE_DESCRIPTION,
|
||||
landingIcon: IconFilebeatChart,
|
||||
});
|
||||
return {
|
||||
...investigationsLink,
|
||||
links: currentLinks,
|
||||
};
|
||||
};
|
||||
|
||||
// navLinks define the navigation links for the Security Solution pages and External pages as well
|
||||
export const investigationsNavLinks: SolutionNavLink[] = [
|
||||
{
|
||||
|
|
|
@ -21,6 +21,13 @@ export const TIMELINE_DESCRIPTION = i18n.translate(
|
|||
}
|
||||
);
|
||||
|
||||
export const NOTE_DESCRIPTION = i18n.translate(
|
||||
'xpack.securitySolution.navLinks.investigations.note.title',
|
||||
{
|
||||
defaultMessage: 'Oversee, revise and revisit the annotations within each document and timeline',
|
||||
}
|
||||
);
|
||||
|
||||
export const OSQUERY_TITLE = i18n.translate(
|
||||
'xpack.securitySolution.navLinks.investigations.osquery.title',
|
||||
{
|
||||
|
|
|
@ -25,7 +25,7 @@ export const ENTITY_ANALYTICS_RISK_SCORE = i18n.translate(
|
|||
}
|
||||
);
|
||||
|
||||
export const NOTES = i18n.translate('xpack.securitySolution.navigation.notesManagement', {
|
||||
export const NOTES = i18n.translate('xpack.securitySolution.navigation.notes', {
|
||||
defaultMessage: 'Notes',
|
||||
});
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
import type { CoreStart } from '@kbn/core/public';
|
||||
|
||||
import { links as notesLink } from './notes/links';
|
||||
import { links as attackDiscoveryLinks } from './attack_discovery/links';
|
||||
import type { AppLinkItems } from './common/links/types';
|
||||
import { indicatorsLinks } from './threat_intelligence/links';
|
||||
|
@ -35,6 +36,7 @@ export const appLinks: AppLinkItems = Object.freeze([
|
|||
rulesLinks,
|
||||
gettingStartedLinks,
|
||||
managementLinks,
|
||||
notesLink,
|
||||
]);
|
||||
|
||||
export const getFilteredLinks = async (
|
||||
|
@ -55,5 +57,6 @@ export const getFilteredLinks = async (
|
|||
rulesLinks,
|
||||
gettingStartedLinks,
|
||||
managementFilteredLinks,
|
||||
notesLink,
|
||||
]);
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@ import { isEmpty } from 'lodash/fp';
|
|||
import type { TimelineType } from '../../../../common/api/timeline';
|
||||
import { appendSearch } from './helpers';
|
||||
|
||||
export const getTimelineTabsUrl = (tabName: TimelineType | 'notes', search?: string) =>
|
||||
export const getTimelineTabsUrl = (tabName: TimelineType, search?: string) =>
|
||||
`/${tabName}${appendSearch(search)}`;
|
||||
|
||||
export const getTimelineUrl = (id: string, graphEventId?: string) =>
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
BLOCKLIST,
|
||||
RESPONSE_ACTIONS_HISTORY,
|
||||
PROTECTION_UPDATES,
|
||||
NOTES,
|
||||
} from '../../app/translations';
|
||||
|
||||
const TabNameMappedToI18nKey: Record<AdministrationSubTab, string> = {
|
||||
|
@ -25,6 +26,7 @@ const TabNameMappedToI18nKey: Record<AdministrationSubTab, string> = {
|
|||
[AdministrationSubTab.blocklist]: BLOCKLIST,
|
||||
[AdministrationSubTab.responseActionsHistory]: RESPONSE_ACTIONS_HISTORY,
|
||||
[AdministrationSubTab.protectionUpdates]: PROTECTION_UPDATES,
|
||||
[AdministrationSubTab.notes]: NOTES,
|
||||
};
|
||||
|
||||
export function getTrailingBreadcrumbs(params: AdministrationRouteSpyState): ChromeBreadcrumb[] {
|
||||
|
|
|
@ -18,6 +18,7 @@ export const MANAGEMENT_ROUTING_POLICY_DETAILS_EVENT_FILTERS_PATH = `${MANAGEMEN
|
|||
export const MANAGEMENT_ROUTING_POLICY_DETAILS_HOST_ISOLATION_EXCEPTIONS_PATH = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.policies})/:policyId/hostIsolationExceptions`;
|
||||
export const MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.policies})/:policyId/blocklists`;
|
||||
export const MANAGEMENT_ROUTING_POLICY_DETAILS_PROTECTION_UPDATES_PATH = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.policies})/:policyId/protectionUpdates`;
|
||||
export const MANAGEMENT_ROUTING_NOTES_PATH = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.notes})`;
|
||||
/** @deprecated use the paths defined above instead */
|
||||
export const MANAGEMENT_ROUTING_POLICY_DETAILS_PATH_OLD = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.policies})/:policyId`;
|
||||
export const MANAGEMENT_ROUTING_TRUSTED_APPS_PATH = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.trustedApps})`;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import type { CoreStart } from '@kbn/core/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import IconFilebeatChart from '../app/solution_navigation/links/sections/icons/filebeat_chart';
|
||||
import { checkArtifactHasData } from './services/exceptions_list/check_artifact_has_data';
|
||||
import {
|
||||
calculateEndpointAuthz,
|
||||
|
@ -22,6 +23,7 @@ import {
|
|||
EVENT_FILTERS_PATH,
|
||||
HOST_ISOLATION_EXCEPTIONS_PATH,
|
||||
MANAGE_PATH,
|
||||
NOTES_PATH,
|
||||
POLICIES_PATH,
|
||||
RESPONSE_ACTIONS_HISTORY_PATH,
|
||||
SecurityPageName,
|
||||
|
@ -39,6 +41,7 @@ import {
|
|||
TRUSTED_APPLICATIONS,
|
||||
ENTITY_ANALYTICS_RISK_SCORE,
|
||||
ASSET_CRITICALITY,
|
||||
NOTES,
|
||||
} from '../app/translations';
|
||||
import { licenseService } from '../common/hooks/use_license';
|
||||
import type { LinkItem } from '../common/links/types';
|
||||
|
@ -85,6 +88,12 @@ const categories = [
|
|||
}),
|
||||
linkIds: [SecurityPageName.cloudDefendPolicies],
|
||||
},
|
||||
{
|
||||
label: i18n.translate('xpack.securitySolution.appLinks.category.investigations', {
|
||||
defaultMessage: 'Investigations',
|
||||
}),
|
||||
linkIds: [SecurityPageName.notes],
|
||||
},
|
||||
];
|
||||
|
||||
export const links: LinkItem = {
|
||||
|
@ -215,6 +224,19 @@ export const links: LinkItem = {
|
|||
hideTimeline: true,
|
||||
},
|
||||
cloudDefendLink,
|
||||
{
|
||||
id: SecurityPageName.notes,
|
||||
title: NOTES,
|
||||
description: i18n.translate('xpack.securitySolution.appLinks.notesDescription', {
|
||||
defaultMessage:
|
||||
'Oversee, revise and revisit the annotations within each document and timeline.',
|
||||
}),
|
||||
landingIcon: IconFilebeatChart,
|
||||
path: NOTES_PATH,
|
||||
skipUrlState: true,
|
||||
hideTimeline: true,
|
||||
experimentalKey: 'securitySolutionNotesEnabled',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ import { Routes, Route } from '@kbn/shared-ux-router';
|
|||
import { TrackApplicationView } from '@kbn/usage-collection-plugin/public';
|
||||
import { EuiEmptyPrompt, EuiLoadingLogo } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features';
|
||||
import { NotesContainer } from './notes';
|
||||
import { ManagementEmptyStateWrapper } from '../components/management_empty_state_wrapper';
|
||||
import {
|
||||
MANAGEMENT_ROUTING_ENDPOINTS_PATH,
|
||||
|
@ -20,6 +22,7 @@ import {
|
|||
MANAGEMENT_ROUTING_TRUSTED_APPS_PATH,
|
||||
MANAGEMENT_ROUTING_BLOCKLIST_PATH,
|
||||
MANAGEMENT_ROUTING_RESPONSE_ACTIONS_HISTORY_PATH,
|
||||
MANAGEMENT_ROUTING_NOTES_PATH,
|
||||
} from '../common/constants';
|
||||
import { NotFoundPage } from '../../app/404';
|
||||
import { EndpointsContainer } from './endpoint_hosts';
|
||||
|
@ -77,7 +80,18 @@ const ResponseActionsTelemetry = () => (
|
|||
</TrackApplicationView>
|
||||
);
|
||||
|
||||
const NotesTelemetry = () => (
|
||||
<TrackApplicationView viewId={SecurityPageName.notes}>
|
||||
<NotesContainer />
|
||||
<SpyRoute pageName={SecurityPageName.notes} />
|
||||
</TrackApplicationView>
|
||||
);
|
||||
|
||||
export const ManagementContainer = memo(() => {
|
||||
const securitySolutionNotesEnabled = useIsExperimentalFeatureEnabled(
|
||||
'securitySolutionNotesEnabled'
|
||||
);
|
||||
|
||||
const {
|
||||
loading,
|
||||
canReadPolicyManagement,
|
||||
|
@ -148,6 +162,10 @@ export const ManagementContainer = memo(() => {
|
|||
hasPrivilege={canReadActionsLogManagement}
|
||||
/>
|
||||
|
||||
{securitySolutionNotesEnabled && (
|
||||
<Route path={MANAGEMENT_ROUTING_NOTES_PATH} component={NotesTelemetry} />
|
||||
)}
|
||||
|
||||
{canReadEndpointList && (
|
||||
<Route path={MANAGEMENT_PATH} exact>
|
||||
<Redirect to={getEndpointListPath({ name: 'endpointList' })} />
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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 { Routes, Route } from '@kbn/shared-ux-router';
|
||||
import React from 'react';
|
||||
import { NoteManagementPage } from '../../../notes';
|
||||
import { NotFoundPage } from '../../../app/404';
|
||||
import { MANAGEMENT_ROUTING_NOTES_PATH } from '../../common/constants';
|
||||
|
||||
export const NotesContainer = () => {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path={MANAGEMENT_ROUTING_NOTES_PATH} exact component={NoteManagementPage} />
|
||||
<Route path="*" component={NotFoundPage} />
|
||||
</Routes>
|
||||
);
|
||||
};
|
|
@ -33,6 +33,7 @@ export enum AdministrationSubTab {
|
|||
blocklist = 'blocklist',
|
||||
responseActionsHistory = 'response_actions_history',
|
||||
protectionUpdates = 'protection_updates',
|
||||
notes = 'notes',
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,56 +14,10 @@ export const BATCH_ACTIONS = i18n.translate(
|
|||
}
|
||||
);
|
||||
|
||||
export const CREATED_COLUMN = i18n.translate(
|
||||
'xpack.securitySolution.notes.management.createdColumnTitle',
|
||||
{
|
||||
defaultMessage: 'Created',
|
||||
}
|
||||
);
|
||||
|
||||
export const CREATED_BY_COLUMN = i18n.translate(
|
||||
'xpack.securitySolution.notes.management.createdByColumnTitle',
|
||||
{
|
||||
defaultMessage: 'Created by',
|
||||
}
|
||||
);
|
||||
|
||||
export const EVENT_ID_COLUMN = i18n.translate(
|
||||
'xpack.securitySolution.notes.management.eventIdColumnTitle',
|
||||
{
|
||||
defaultMessage: 'View Document',
|
||||
}
|
||||
);
|
||||
|
||||
export const TIMELINE_ID_COLUMN = i18n.translate(
|
||||
'xpack.securitySolution.notes.management.timelineColumnTitle',
|
||||
{
|
||||
defaultMessage: 'Timeline',
|
||||
}
|
||||
);
|
||||
|
||||
export const NOTE_CONTENT_COLUMN = i18n.translate(
|
||||
'xpack.securitySolution.notes.management.noteContentColumnTitle',
|
||||
{
|
||||
defaultMessage: 'Note content',
|
||||
}
|
||||
);
|
||||
|
||||
export const DELETE = i18n.translate('xpack.securitySolution.notes.management.deleteAction', {
|
||||
defaultMessage: 'Delete',
|
||||
});
|
||||
|
||||
export const DELETE_SINGLE_NOTE_DESCRIPTION = i18n.translate(
|
||||
'xpack.securitySolution.notes.management.deleteDescription',
|
||||
{
|
||||
defaultMessage: 'Delete this note',
|
||||
}
|
||||
);
|
||||
|
||||
export const TABLE_ERROR = i18n.translate('xpack.securitySolution.notes.management.tableError', {
|
||||
defaultMessage: 'Unable to load notes',
|
||||
});
|
||||
|
||||
export const DELETE_NOTES_MODAL_TITLE = i18n.translate(
|
||||
'xpack.securitySolution.notes.management.deleteNotesModalTitle',
|
||||
{
|
||||
|
@ -96,13 +50,6 @@ export const REFRESH = i18n.translate('xpack.securitySolution.notes.management.r
|
|||
defaultMessage: 'Refresh',
|
||||
});
|
||||
|
||||
export const OPEN_TIMELINE = i18n.translate(
|
||||
'xpack.securitySolution.notes.management.openTimeline',
|
||||
{
|
||||
defaultMessage: 'Open timeline',
|
||||
}
|
||||
);
|
||||
|
||||
export const VIEW_EVENT_IN_TIMELINE = i18n.translate(
|
||||
'xpack.securitySolution.notes.management.viewEventInTimeline',
|
||||
{
|
||||
|
|
25
x-pack/plugins/security_solution/public/notes/links.ts
Normal file
25
x-pack/plugins/security_solution/public/notes/links.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
import { NOTES_PATH, SecurityPageName, SERVER_APP_ID } from '../../common/constants';
|
||||
import { NOTES } from '../app/translations';
|
||||
import type { LinkItem } from '../common/links/types';
|
||||
|
||||
export const links: LinkItem = {
|
||||
id: SecurityPageName.notes,
|
||||
title: NOTES,
|
||||
path: NOTES_PATH,
|
||||
capabilities: [`${SERVER_APP_ID}.show`],
|
||||
globalSearchKeywords: [
|
||||
i18n.translate('xpack.securitySolution.appLinks.notes', {
|
||||
defaultMessage: 'Notes',
|
||||
}),
|
||||
],
|
||||
links: [],
|
||||
experimentalKey: 'securitySolutionNotesEnabled',
|
||||
};
|
|
@ -7,8 +7,11 @@
|
|||
|
||||
import React, { useCallback, useMemo, useEffect } from 'react';
|
||||
import type { DefaultItemAction, EuiBasicTableColumn } from '@elastic/eui';
|
||||
import { EuiBasicTable, EuiEmptyPrompt, EuiLink } from '@elastic/eui';
|
||||
import { EuiBasicTable, EuiEmptyPrompt, EuiLink, EuiSpacer } from '@elastic/eui';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features';
|
||||
import { useQueryTimelineById } from '../../timelines/components/open_timeline/helpers';
|
||||
import { Title } from '../../common/components/header_page/title';
|
||||
// TODO unify this type from the api with the one in public/common/lib/note
|
||||
import type { Note } from '../../../common/api/timeline';
|
||||
import { FormattedRelativePreferenceDate } from '../../common/components/formatted_date';
|
||||
|
@ -32,12 +35,11 @@ import type { NotesState } from '..';
|
|||
import { SearchRow } from '../components/search_row';
|
||||
import { NotesUtilityBar } from '../components/utility_bar';
|
||||
import { DeleteConfirmModal } from '../components/delete_confirm_modal';
|
||||
import * as i18n from '../components/translations';
|
||||
import type { OpenTimelineProps } from '../../timelines/components/open_timeline/types';
|
||||
import * as i18n from './translations';
|
||||
import { OpenEventInTimeline } from '../components/open_event_in_timeline';
|
||||
|
||||
const columns: (
|
||||
onOpenTimeline: OpenTimelineProps['onOpenTimeline']
|
||||
onOpenTimeline: (timelineId: string) => void
|
||||
) => Array<EuiBasicTableColumn<Note>> = (onOpenTimeline) => {
|
||||
return [
|
||||
{
|
||||
|
@ -61,9 +63,7 @@ const columns: (
|
|||
name: i18n.TIMELINE_ID_COLUMN,
|
||||
render: (timelineId: Note['timelineId']) =>
|
||||
timelineId ? (
|
||||
<EuiLink onClick={() => onOpenTimeline({ timelineId, duplicate: false })}>
|
||||
{i18n.OPEN_TIMELINE}
|
||||
</EuiLink>
|
||||
<EuiLink onClick={() => onOpenTimeline(timelineId)}>{i18n.OPEN_TIMELINE}</EuiLink>
|
||||
) : null,
|
||||
},
|
||||
{
|
||||
|
@ -80,11 +80,7 @@ const pageSizeOptions = [10, 25, 50, 100];
|
|||
* This component uses the same slices of state as the notes functionality of the rest of the Security Solution applicaiton.
|
||||
* Therefore, changes made in this page (like fetching or deleting notes) will have an impact everywhere.
|
||||
*/
|
||||
export const NoteManagementPage = ({
|
||||
onOpenTimeline,
|
||||
}: {
|
||||
onOpenTimeline: OpenTimelineProps['onOpenTimeline'];
|
||||
}) => {
|
||||
export const NoteManagementPage = () => {
|
||||
const dispatch = useDispatch();
|
||||
const notes = useSelector(selectAllNotes);
|
||||
const pagination = useSelector(selectNotesPagination);
|
||||
|
@ -152,6 +148,19 @@ export const NoteManagementPage = ({
|
|||
return item.noteId;
|
||||
}, []);
|
||||
|
||||
const unifiedComponentsInTimelineDisabled = useIsExperimentalFeatureEnabled(
|
||||
'unifiedComponentsInTimelineDisabled'
|
||||
);
|
||||
const queryTimelineById = useQueryTimelineById();
|
||||
const openTimeline = useCallback(
|
||||
(timelineId: string) =>
|
||||
queryTimelineById({
|
||||
timelineId,
|
||||
unifiedComponentsInTimelineDisabled,
|
||||
}),
|
||||
[queryTimelineById, unifiedComponentsInTimelineDisabled]
|
||||
);
|
||||
|
||||
const columnWithActions = useMemo(() => {
|
||||
const actions: Array<DefaultItemAction<Note>> = [
|
||||
{
|
||||
|
@ -164,13 +173,13 @@ export const NoteManagementPage = ({
|
|||
},
|
||||
];
|
||||
return [
|
||||
...columns(onOpenTimeline),
|
||||
...columns(openTimeline),
|
||||
{
|
||||
name: 'actions',
|
||||
actions,
|
||||
},
|
||||
];
|
||||
}, [selectRowForDeletion, onOpenTimeline]);
|
||||
}, [selectRowForDeletion, openTimeline]);
|
||||
|
||||
const currentPagination = useMemo(() => {
|
||||
return {
|
||||
|
@ -207,6 +216,8 @@ export const NoteManagementPage = ({
|
|||
|
||||
return (
|
||||
<>
|
||||
<Title title={i18n.NOTES} />
|
||||
<EuiSpacer size="m" />
|
||||
<SearchRow />
|
||||
<NotesUtilityBar />
|
||||
<EuiBasicTable
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
|
||||
export const NOTES = i18n.translate('xpack.securitySolution.notes.management.title', {
|
||||
defaultMessage: 'Notes',
|
||||
});
|
||||
|
||||
export const CREATED_COLUMN = i18n.translate(
|
||||
'xpack.securitySolution.notes.management.createdColumnTitle',
|
||||
{
|
||||
defaultMessage: 'Created',
|
||||
}
|
||||
);
|
||||
|
||||
export const CREATED_BY_COLUMN = i18n.translate(
|
||||
'xpack.securitySolution.notes.management.createdByColumnTitle',
|
||||
{
|
||||
defaultMessage: 'Created by',
|
||||
}
|
||||
);
|
||||
|
||||
export const EVENT_ID_COLUMN = i18n.translate(
|
||||
'xpack.securitySolution.notes.management.eventIdColumnTitle',
|
||||
{
|
||||
defaultMessage: 'View Document',
|
||||
}
|
||||
);
|
||||
|
||||
export const TIMELINE_ID_COLUMN = i18n.translate(
|
||||
'xpack.securitySolution.notes.management.timelineColumnTitle',
|
||||
{
|
||||
defaultMessage: 'Timeline',
|
||||
}
|
||||
);
|
||||
|
||||
export const NOTE_CONTENT_COLUMN = i18n.translate(
|
||||
'xpack.securitySolution.notes.management.noteContentColumnTitle',
|
||||
{
|
||||
defaultMessage: 'Note content',
|
||||
}
|
||||
);
|
||||
|
||||
export const DELETE = i18n.translate('xpack.securitySolution.notes.management.deleteAction', {
|
||||
defaultMessage: 'Delete',
|
||||
});
|
||||
|
||||
export const DELETE_SINGLE_NOTE_DESCRIPTION = i18n.translate(
|
||||
'xpack.securitySolution.notes.management.deleteDescription',
|
||||
{
|
||||
defaultMessage: 'Delete this note',
|
||||
}
|
||||
);
|
||||
|
||||
export const TABLE_ERROR = i18n.translate('xpack.securitySolution.notes.management.tableError', {
|
||||
defaultMessage: 'Unable to load notes',
|
||||
});
|
||||
|
||||
export const REFRESH = i18n.translate('xpack.securitySolution.notes.management.refresh', {
|
||||
defaultMessage: 'Refresh',
|
||||
});
|
||||
|
||||
export const OPEN_TIMELINE = i18n.translate(
|
||||
'xpack.securitySolution.notes.management.openTimeline',
|
||||
{
|
||||
defaultMessage: 'Open timeline',
|
||||
}
|
||||
);
|
42
x-pack/plugins/security_solution/public/notes/routes.tsx
Normal file
42
x-pack/plugins/security_solution/public/notes/routes.tsx
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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 { Switch } from 'react-router-dom';
|
||||
import { Route } from '@kbn/shared-ux-router';
|
||||
import { TrackApplicationView } from '@kbn/usage-collection-plugin/public';
|
||||
import { NoteManagementPage } from './pages/note_management_page';
|
||||
import { SpyRoute } from '../common/utils/route/spy_routes';
|
||||
import { NotFoundPage } from '../app/404';
|
||||
import { NOTES_PATH, SecurityPageName } from '../../common/constants';
|
||||
import { PluginTemplateWrapper } from '../common/components/plugin_template_wrapper';
|
||||
|
||||
const NotesManagementTelemetry = () => (
|
||||
<PluginTemplateWrapper>
|
||||
<TrackApplicationView viewId={SecurityPageName.notes}>
|
||||
<NoteManagementPage />
|
||||
<SpyRoute pageName={SecurityPageName.notes} />
|
||||
</TrackApplicationView>
|
||||
</PluginTemplateWrapper>
|
||||
);
|
||||
|
||||
const NotesManagementContainer: React.FC = React.memo(() => {
|
||||
return (
|
||||
<Switch>
|
||||
<Route path={NOTES_PATH} exact component={NotesManagementTelemetry} />
|
||||
<Route component={NotFoundPage} />
|
||||
</Switch>
|
||||
);
|
||||
});
|
||||
NotesManagementContainer.displayName = 'NotesManagementContainer';
|
||||
|
||||
export const routes = [
|
||||
{
|
||||
path: NOTES_PATH,
|
||||
component: NotesManagementContainer,
|
||||
},
|
||||
];
|
|
@ -70,7 +70,7 @@ interface OwnProps<TCache = object> {
|
|||
export type OpenTimelineOwnProps = OwnProps &
|
||||
Pick<
|
||||
OpenTimelineProps,
|
||||
'defaultPageSize' | 'title' | 'importDataModalToggle' | 'setImportDataModalToggle' | 'tabName'
|
||||
'defaultPageSize' | 'title' | 'importDataModalToggle' | 'setImportDataModalToggle'
|
||||
>;
|
||||
|
||||
/** Returns a collection of selected timeline ids */
|
||||
|
@ -131,7 +131,6 @@ export const StatefulOpenTimelineComponent = React.memo<OpenTimelineOwnProps>(
|
|||
importDataModalToggle,
|
||||
onOpenTimeline,
|
||||
setImportDataModalToggle,
|
||||
tabName,
|
||||
title,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
|
@ -423,7 +422,6 @@ export const StatefulOpenTimelineComponent = React.memo<OpenTimelineOwnProps>(
|
|||
selectedItems={selectedItems}
|
||||
sortDirection={sortDirection}
|
||||
sortField={sortField}
|
||||
tabName={tabName}
|
||||
templateTimelineFilter={templateTimelineFilter}
|
||||
timelineType={timelineType}
|
||||
timelineStatus={timelineStatus}
|
||||
|
|
|
@ -30,7 +30,6 @@ import { TimelinesTable } from './timelines_table';
|
|||
import * as i18n from './translations';
|
||||
import { OPEN_TIMELINE_CLASS_NAME } from './helpers';
|
||||
import type { OpenTimelineProps, ActionTimelineToShow, OpenTimelineResult } from './types';
|
||||
import { NoteManagementPage } from '../../../notes';
|
||||
|
||||
const QueryText = styled.span`
|
||||
white-space: normal;
|
||||
|
@ -64,7 +63,6 @@ export const OpenTimeline = React.memo<OpenTimelineProps>(
|
|||
sortDirection,
|
||||
setImportDataModalToggle,
|
||||
sortField,
|
||||
tabName,
|
||||
timelineType = TimelineTypeEnum.default,
|
||||
timelineStatus,
|
||||
timelineFilter,
|
||||
|
@ -228,92 +226,86 @@ export const OpenTimeline = React.memo<OpenTimelineProps>(
|
|||
|
||||
<div data-test-subj="timelines-page-container" className={OPEN_TIMELINE_CLASS_NAME}>
|
||||
{!!timelineFilter && timelineFilter}
|
||||
{tabName !== 'notes' ? (
|
||||
<>
|
||||
<SearchRow
|
||||
data-test-subj="search-row"
|
||||
favoriteCount={favoriteCount}
|
||||
onlyFavorites={onlyFavorites}
|
||||
onQueryChange={onQueryChange}
|
||||
onToggleOnlyFavorites={onToggleOnlyFavorites}
|
||||
query={query}
|
||||
timelineType={timelineType}
|
||||
>
|
||||
{SearchRowContent}
|
||||
</SearchRow>
|
||||
<>
|
||||
<SearchRow
|
||||
data-test-subj="search-row"
|
||||
favoriteCount={favoriteCount}
|
||||
onlyFavorites={onlyFavorites}
|
||||
onQueryChange={onQueryChange}
|
||||
onToggleOnlyFavorites={onToggleOnlyFavorites}
|
||||
query={query}
|
||||
timelineType={timelineType}
|
||||
>
|
||||
{SearchRowContent}
|
||||
</SearchRow>
|
||||
|
||||
<UtilityBar border>
|
||||
<UtilityBarSection>
|
||||
<UtilityBarGroup>
|
||||
<UtilityBarText data-test-subj="query-message">
|
||||
<>
|
||||
{i18n.SHOWING}{' '}
|
||||
{timelineType === TimelineTypeEnum.template ? nTemplates : nTimelines}
|
||||
</>
|
||||
</UtilityBarText>
|
||||
</UtilityBarGroup>
|
||||
<UtilityBarGroup>
|
||||
{timelineStatus !== TimelineStatusEnum.immutable && (
|
||||
<>
|
||||
<UtilityBarText data-test-subj="selected-count">
|
||||
{timelineType === TimelineTypeEnum.template
|
||||
? i18n.SELECTED_TEMPLATES((selectedItems || []).length)
|
||||
: i18n.SELECTED_TIMELINES((selectedItems || []).length)}
|
||||
</UtilityBarText>
|
||||
<UtilityBarAction
|
||||
dataTestSubj="batchActions"
|
||||
iconSide="right"
|
||||
iconType="arrowDown"
|
||||
popoverContent={getBatchItemsPopoverContent}
|
||||
data-test-subj="utility-bar-action"
|
||||
>
|
||||
<span data-test-subj="utility-bar-action-button">
|
||||
{i18n.BATCH_ACTIONS}
|
||||
</span>
|
||||
</UtilityBarAction>
|
||||
</>
|
||||
)}
|
||||
<UtilityBarAction
|
||||
dataTestSubj="refreshButton"
|
||||
iconSide="right"
|
||||
iconType="refresh"
|
||||
onClick={onRefreshBtnClick}
|
||||
>
|
||||
{i18n.REFRESH}
|
||||
</UtilityBarAction>
|
||||
</UtilityBarGroup>
|
||||
</UtilityBarSection>
|
||||
</UtilityBar>
|
||||
<UtilityBar border>
|
||||
<UtilityBarSection>
|
||||
<UtilityBarGroup>
|
||||
<UtilityBarText data-test-subj="query-message">
|
||||
<>
|
||||
{i18n.SHOWING}{' '}
|
||||
{timelineType === TimelineTypeEnum.template ? nTemplates : nTimelines}
|
||||
</>
|
||||
</UtilityBarText>
|
||||
</UtilityBarGroup>
|
||||
<UtilityBarGroup>
|
||||
{timelineStatus !== TimelineStatusEnum.immutable && (
|
||||
<>
|
||||
<UtilityBarText data-test-subj="selected-count">
|
||||
{timelineType === TimelineTypeEnum.template
|
||||
? i18n.SELECTED_TEMPLATES((selectedItems || []).length)
|
||||
: i18n.SELECTED_TIMELINES((selectedItems || []).length)}
|
||||
</UtilityBarText>
|
||||
<UtilityBarAction
|
||||
dataTestSubj="batchActions"
|
||||
iconSide="right"
|
||||
iconType="arrowDown"
|
||||
popoverContent={getBatchItemsPopoverContent}
|
||||
data-test-subj="utility-bar-action"
|
||||
>
|
||||
<span data-test-subj="utility-bar-action-button">{i18n.BATCH_ACTIONS}</span>
|
||||
</UtilityBarAction>
|
||||
</>
|
||||
)}
|
||||
<UtilityBarAction
|
||||
dataTestSubj="refreshButton"
|
||||
iconSide="right"
|
||||
iconType="refresh"
|
||||
onClick={onRefreshBtnClick}
|
||||
>
|
||||
{i18n.REFRESH}
|
||||
</UtilityBarAction>
|
||||
</UtilityBarGroup>
|
||||
</UtilityBarSection>
|
||||
</UtilityBar>
|
||||
|
||||
<TimelinesTable
|
||||
actionTimelineToShow={actionTimelineToShow}
|
||||
data-test-subj="timelines-table"
|
||||
deleteTimelines={deleteTimelines}
|
||||
defaultPageSize={defaultPageSize}
|
||||
loading={isLoading}
|
||||
itemIdToExpandedNotesRowMap={itemIdToExpandedNotesRowMap}
|
||||
enableExportTimelineDownloader={enableExportTimelineDownloader}
|
||||
onCreateRule={onCreateRule}
|
||||
onCreateRuleFromEql={onCreateRuleFromEql}
|
||||
onOpenDeleteTimelineModal={onOpenDeleteTimelineModal}
|
||||
onOpenTimeline={onOpenTimeline}
|
||||
onSelectionChange={onSelectionChange}
|
||||
onTableChange={onTableChange}
|
||||
onToggleShowNotes={onToggleShowNotes}
|
||||
pageIndex={pageIndex}
|
||||
pageSize={pageSize}
|
||||
searchResults={searchResults}
|
||||
showExtendedColumns={true}
|
||||
sortDirection={sortDirection}
|
||||
sortField={sortField}
|
||||
timelineType={timelineType}
|
||||
totalSearchResultsCount={totalSearchResultsCount}
|
||||
tableRef={tableRef}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<NoteManagementPage onOpenTimeline={onOpenTimeline} />
|
||||
)}
|
||||
<TimelinesTable
|
||||
actionTimelineToShow={actionTimelineToShow}
|
||||
data-test-subj="timelines-table"
|
||||
deleteTimelines={deleteTimelines}
|
||||
defaultPageSize={defaultPageSize}
|
||||
loading={isLoading}
|
||||
itemIdToExpandedNotesRowMap={itemIdToExpandedNotesRowMap}
|
||||
enableExportTimelineDownloader={enableExportTimelineDownloader}
|
||||
onCreateRule={onCreateRule}
|
||||
onCreateRuleFromEql={onCreateRuleFromEql}
|
||||
onOpenDeleteTimelineModal={onOpenDeleteTimelineModal}
|
||||
onOpenTimeline={onOpenTimeline}
|
||||
onSelectionChange={onSelectionChange}
|
||||
onTableChange={onTableChange}
|
||||
onToggleShowNotes={onToggleShowNotes}
|
||||
pageIndex={pageIndex}
|
||||
pageSize={pageSize}
|
||||
searchResults={searchResults}
|
||||
showExtendedColumns={true}
|
||||
sortDirection={sortDirection}
|
||||
sortField={sortField}
|
||||
timelineType={timelineType}
|
||||
totalSearchResultsCount={totalSearchResultsCount}
|
||||
tableRef={tableRef}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -206,7 +206,6 @@ export interface OpenTimelineProps {
|
|||
totalSearchResultsCount: number;
|
||||
/** Hide action on timeline if needed it */
|
||||
hideActions?: ActionTimelineToShow[];
|
||||
tabName?: string;
|
||||
}
|
||||
|
||||
export interface ResolveTimelineConfig {
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
import React, { useState, useCallback, useMemo } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { EuiTabs, EuiTab, EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import { noop } from 'lodash/fp';
|
||||
import { type TimelineType, TimelineTypeEnum } from '../../../../common/api/timeline';
|
||||
import { SecurityPageName } from '../../../app/types';
|
||||
|
@ -17,7 +16,7 @@ import * as i18n from './translations';
|
|||
import type { TimelineTab } from './types';
|
||||
import { TimelineTabsStyle } from './types';
|
||||
import { useKibana } from '../../../common/lib/kibana';
|
||||
import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features';
|
||||
|
||||
export interface UseTimelineTypesArgs {
|
||||
defaultTimelineCount?: number | null;
|
||||
templateTimelineCount?: number | null;
|
||||
|
@ -42,8 +41,6 @@ export const useTimelineTypes = ({
|
|||
: TimelineTypeEnum.default
|
||||
);
|
||||
|
||||
const notesEnabled = useIsExperimentalFeatureEnabled('securitySolutionNotesEnabled');
|
||||
|
||||
const timelineUrl = useMemo(() => {
|
||||
return formatUrl(getTimelineTabsUrl(TimelineTypeEnum.default, urlSearch));
|
||||
}, [formatUrl, urlSearch]);
|
||||
|
@ -51,10 +48,6 @@ export const useTimelineTypes = ({
|
|||
return formatUrl(getTimelineTabsUrl(TimelineTypeEnum.template, urlSearch));
|
||||
}, [formatUrl, urlSearch]);
|
||||
|
||||
const notesUrl = useMemo(() => {
|
||||
return formatUrl(getTimelineTabsUrl('notes', urlSearch));
|
||||
}, [formatUrl, urlSearch]);
|
||||
|
||||
const goToTimeline = useCallback(
|
||||
(ev: React.SyntheticEvent) => {
|
||||
ev.preventDefault();
|
||||
|
@ -71,14 +64,6 @@ export const useTimelineTypes = ({
|
|||
[navigateToUrl, templateUrl]
|
||||
);
|
||||
|
||||
const goToNotes = useCallback(
|
||||
(ev: React.SyntheticEvent) => {
|
||||
ev.preventDefault();
|
||||
navigateToUrl(notesUrl);
|
||||
},
|
||||
[navigateToUrl, notesUrl]
|
||||
);
|
||||
|
||||
const getFilterOrTabs: (timelineTabsStyle: TimelineTabsStyle) => TimelineTab[] = useCallback(
|
||||
(timelineTabsStyle: TimelineTabsStyle) => [
|
||||
{
|
||||
|
@ -132,17 +117,6 @@ export const useTimelineTypes = ({
|
|||
{tab.name}
|
||||
</EuiTab>
|
||||
))}
|
||||
{notesEnabled && (
|
||||
<EuiTab
|
||||
data-test-subj="timeline-notes"
|
||||
isSelected={tabName === 'notes'}
|
||||
key="timeline-notes"
|
||||
href={notesUrl}
|
||||
onClick={goToNotes}
|
||||
>
|
||||
{'Notes'}
|
||||
</EuiTab>
|
||||
)}
|
||||
</EuiTabs>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { SecurityPageName, SERVER_APP_ID, TIMELINES_PATH } from '../../common/constants';
|
||||
import { TIMELINES, NOTES } from '../app/translations';
|
||||
import { TIMELINES } from '../app/translations';
|
||||
import type { LinkItem } from '../common/links/types';
|
||||
|
||||
export const links: LinkItem = {
|
||||
|
@ -30,14 +30,5 @@ export const links: LinkItem = {
|
|||
path: `${TIMELINES_PATH}/template`,
|
||||
sideNavDisabled: true,
|
||||
},
|
||||
{
|
||||
id: SecurityPageName.notesManagement,
|
||||
title: NOTES,
|
||||
description: i18n.translate('xpack.securitySolution.appLinks.notesManagementDescription', {
|
||||
defaultMessage: 'Visualize and delete notes.',
|
||||
}),
|
||||
path: `${TIMELINES_PATH}/notes`,
|
||||
experimentalKey: 'securitySolutionNotesEnabled',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@ import { appendSearch } from '../../common/components/link_to/helpers';
|
|||
|
||||
import { TIMELINES_PATH } from '../../../common/constants';
|
||||
|
||||
const timelinesPagePath = `${TIMELINES_PATH}/:tabName(${TimelineTypeEnum.default}|${TimelineTypeEnum.template}|notes)`;
|
||||
const timelinesPagePath = `${TIMELINES_PATH}/:tabName(${TimelineTypeEnum.default}|${TimelineTypeEnum.template})`;
|
||||
const timelinesDefaultPath = `${TIMELINES_PATH}/${TimelineTypeEnum.default}`;
|
||||
|
||||
export const Timelines = React.memo(() => (
|
||||
|
|
|
@ -41,7 +41,7 @@ export const TimelinesPage = React.memo(() => {
|
|||
{indicesExist ? (
|
||||
<SecuritySolutionPageWrapper>
|
||||
<HeaderPage title={i18n.PAGE_TITLE}>
|
||||
{capabilitiesCanUserCRUD && tabName !== 'notes' ? (
|
||||
{capabilitiesCanUserCRUD && (
|
||||
<EuiFlexGroup gutterSize="s" alignItems="center">
|
||||
<EuiFlexItem>
|
||||
<EuiButton
|
||||
|
@ -56,7 +56,7 @@ export const TimelinesPage = React.memo(() => {
|
|||
<NewTimelineButton type={timelineType} />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
) : null}
|
||||
)}
|
||||
</HeaderPage>
|
||||
|
||||
<StatefulOpenTimeline
|
||||
|
@ -66,7 +66,6 @@ export const TimelinesPage = React.memo(() => {
|
|||
setImportDataModalToggle={setImportDataModal}
|
||||
title={i18n.ALL_TIMELINES_PANEL_TITLE}
|
||||
data-test-subj="stateful-open-timeline"
|
||||
tabName={tabName}
|
||||
/>
|
||||
</SecuritySolutionPageWrapper>
|
||||
) : (
|
||||
|
|
|
@ -35253,7 +35253,6 @@
|
|||
"xpack.securitySolution.appLinks.network.flows": "Flux",
|
||||
"xpack.securitySolution.appLinks.network.http": "HTTP",
|
||||
"xpack.securitySolution.appLinks.network.tls": "TLS",
|
||||
"xpack.securitySolution.appLinks.notesManagementDescription": "Visualisez et supprimez des notes.",
|
||||
"xpack.securitySolution.appLinks.overview": "Aperçu",
|
||||
"xpack.securitySolution.appLinks.overviewDescription": "Résumé de votre activité d'environnement de sécurité, y compris les alertes, les événements, les éléments récents et un fil d'actualités !",
|
||||
"xpack.securitySolution.appLinks.policiesDescription": "Utilisez les politiques pour personnaliser les protections des points de terminaison et de charge de travail cloud, et d'autres configurations.",
|
||||
|
@ -39508,7 +39507,6 @@
|
|||
"xpack.securitySolution.navigation.manage": "Gérer",
|
||||
"xpack.securitySolution.navigation.network": "Réseau",
|
||||
"xpack.securitySolution.navigation.newRuleTitle": "Créer une nouvelle règle",
|
||||
"xpack.securitySolution.navigation.notesManagement": "Notes",
|
||||
"xpack.securitySolution.navigation.overview": "Aperçu",
|
||||
"xpack.securitySolution.navigation.protectionUpdates": "Mises à jour de la protection",
|
||||
"xpack.securitySolution.navigation.responseActionsHistory": "Historique des actions de réponse",
|
||||
|
|
|
@ -34997,7 +34997,6 @@
|
|||
"xpack.securitySolution.appLinks.network.flows": "Flow",
|
||||
"xpack.securitySolution.appLinks.network.http": "HTTP",
|
||||
"xpack.securitySolution.appLinks.network.tls": "TLS",
|
||||
"xpack.securitySolution.appLinks.notesManagementDescription": "メモを可視化して、削除します。",
|
||||
"xpack.securitySolution.appLinks.overview": "概要",
|
||||
"xpack.securitySolution.appLinks.overviewDescription": "アラート、イベント、最近のアイテム、ニュースフィードを含む、セキュリティ環境アクティビティの概要。",
|
||||
"xpack.securitySolution.appLinks.policiesDescription": "ポリシーを使用して、エンドポイントおよびクラウドワークロード保護、ならびに他の構成をカスタマイズします。",
|
||||
|
@ -39251,7 +39250,6 @@
|
|||
"xpack.securitySolution.navigation.manage": "管理",
|
||||
"xpack.securitySolution.navigation.network": "ネットワーク",
|
||||
"xpack.securitySolution.navigation.newRuleTitle": "新規ルールを作成",
|
||||
"xpack.securitySolution.navigation.notesManagement": "メモ",
|
||||
"xpack.securitySolution.navigation.overview": "概要",
|
||||
"xpack.securitySolution.navigation.protectionUpdates": "保護更新",
|
||||
"xpack.securitySolution.navigation.responseActionsHistory": "対応アクション履歴",
|
||||
|
|
|
@ -35041,7 +35041,6 @@
|
|||
"xpack.securitySolution.appLinks.network.flows": "流",
|
||||
"xpack.securitySolution.appLinks.network.http": "HTTP",
|
||||
"xpack.securitySolution.appLinks.network.tls": "TLS",
|
||||
"xpack.securitySolution.appLinks.notesManagementDescription": "可视化并删除备注。",
|
||||
"xpack.securitySolution.appLinks.overview": "概览",
|
||||
"xpack.securitySolution.appLinks.overviewDescription": "您的安全环境活动摘要,包括告警、事件、最近项和新闻源!",
|
||||
"xpack.securitySolution.appLinks.policiesDescription": "使用策略定制终端和云工作负载防护及其他配置。",
|
||||
|
@ -39297,7 +39296,6 @@
|
|||
"xpack.securitySolution.navigation.manage": "管理",
|
||||
"xpack.securitySolution.navigation.network": "网络",
|
||||
"xpack.securitySolution.navigation.newRuleTitle": "创建新规则",
|
||||
"xpack.securitySolution.navigation.notesManagement": "备注",
|
||||
"xpack.securitySolution.navigation.overview": "概览",
|
||||
"xpack.securitySolution.navigation.protectionUpdates": "防护更新",
|
||||
"xpack.securitySolution.navigation.responseActionsHistory": "响应操作历史记录",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue