mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
131034 format detail panel array values (#131349)
* Refactor detail panel copy and host tab data * Refactor render data for process tab and add test and fix constants * Update process tab tests * Fix CI checks Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
5a7a243069
commit
e3476a168b
20 changed files with 561 additions and 318 deletions
|
@ -819,8 +819,8 @@ export const mockAlerts: ProcessEvent[] = [
|
|||
architecture: 'x86_64',
|
||||
hostname: 'james-fleet-714-2',
|
||||
id: '48c1b3f1ac5da4e0057fc9f60f4d1d5d',
|
||||
ip: '127.0.0.1,::1,10.132.0.50,fe80::7d39:3147:4d9a:f809',
|
||||
mac: '42:01:0a:84:00:32',
|
||||
ip: ['127.0.0.1', '::1', '10.132.0.50', 'fe80::7d39:3147:4d9a:f809'],
|
||||
mac: ['42:01:0a:84:00:32'],
|
||||
name: 'james-fleet-714-2',
|
||||
os: {
|
||||
family: 'centos',
|
||||
|
@ -1006,8 +1006,8 @@ export const mockAlerts: ProcessEvent[] = [
|
|||
architecture: 'x86_64',
|
||||
hostname: 'james-fleet-714-2',
|
||||
id: '48c1b3f1ac5da4e0057fc9f60f4d1d5d',
|
||||
ip: '127.0.0.1,::1,10.132.0.50,fe80::7d39:3147:4d9a:f809',
|
||||
mac: '42:01:0a:84:00:32',
|
||||
ip: ['127.0.0.1', '::1', '10.132.0.50', 'fe80::7d39:3147:4d9a:f809'],
|
||||
mac: ['42:01:0a:84:00:32'],
|
||||
name: 'james-fleet-714-2',
|
||||
os: {
|
||||
family: 'centos',
|
||||
|
@ -1285,8 +1285,8 @@ export const childProcessMock: Process = {
|
|||
architecture: 'x86_64',
|
||||
hostname: 'james-fleet-714-2',
|
||||
id: '48c1b3f1ac5da4e0057fc9f60f4d1d5d',
|
||||
ip: '127.0.0.1,::1,10.132.0.50,fe80::7d39:3147:4d9a:f809',
|
||||
mac: '42:01:0a:84:00:32',
|
||||
ip: ['127.0.0.1', '::1', '10.132.0.50', 'fe80::7d39:3147:4d9a:f809'],
|
||||
mac: ['42:01:0a:84:00:32'],
|
||||
name: 'james-fleet-714-2',
|
||||
os: {
|
||||
family: 'centos',
|
||||
|
@ -1370,8 +1370,8 @@ export const processMock: Process = {
|
|||
architecture: 'x86_64',
|
||||
hostname: 'james-fleet-714-2',
|
||||
id: '48c1b3f1ac5da4e0057fc9f60f4d1d5d',
|
||||
ip: '127.0.0.1,::1,10.132.0.50,fe80::7d39:3147:4d9a:f809',
|
||||
mac: '42:01:0a:84:00:32',
|
||||
ip: ['127.0.0.1', '::1', '10.132.0.50', 'fe80::7d39:3147:4d9a:f809'],
|
||||
mac: ['42:01:0a:84:00:32'],
|
||||
name: 'james-fleet-714-2',
|
||||
os: {
|
||||
family: 'centos',
|
||||
|
|
|
@ -24,8 +24,8 @@ export const sessionViewProcessEventsMock: ProcessEventResults = {
|
|||
architecture: 'x86_64',
|
||||
hostname: 'james-fleet-714-2',
|
||||
id: '48c1b3f1ac5da4e0057fc9f60f4d1d5d',
|
||||
ip: '127.0.0.1,::1,10.132.0.50,fe80::7d39:3147:4d9a:f809',
|
||||
mac: '42:01:0a:84:00:32',
|
||||
ip: ['127.0.0.1', '::1', '10.132.0.50', 'fe80::7d39:3147:4d9a:f809'],
|
||||
mac: ['42:01:0a:84:00:32'],
|
||||
name: 'james-fleet-714-2',
|
||||
os: {
|
||||
Ext: {
|
||||
|
@ -427,8 +427,8 @@ export const sessionViewProcessEventsMock: ProcessEventResults = {
|
|||
architecture: 'x86_64',
|
||||
hostname: 'james-fleet-714-2',
|
||||
id: '48c1b3f1ac5da4e0057fc9f60f4d1d5d',
|
||||
ip: '127.0.0.1,::1,10.132.0.50,fe80::7d39:3147:4d9a:f809',
|
||||
mac: '42:01:0a:84:00:32',
|
||||
ip: ['127.0.0.1', '::1', '10.132.0.50', 'fe80::7d39:3147:4d9a:f809'],
|
||||
mac: ['42:01:0a:84:00:32'],
|
||||
name: 'james-fleet-714-2',
|
||||
os: {
|
||||
Ext: {
|
||||
|
@ -836,8 +836,8 @@ export const sessionViewProcessEventsMock: ProcessEventResults = {
|
|||
architecture: 'x86_64',
|
||||
hostname: 'james-fleet-714-2',
|
||||
id: '48c1b3f1ac5da4e0057fc9f60f4d1d5d',
|
||||
ip: '127.0.0.1,::1,10.132.0.50,fe80::7d39:3147:4d9a:f809',
|
||||
mac: '42:01:0a:84:00:32',
|
||||
ip: ['127.0.0.1', '::1', '10.132.0.50', 'fe80::7d39:3147:4d9a:f809'],
|
||||
mac: ['42:01:0a:84:00:32'],
|
||||
name: 'james-fleet-714-2',
|
||||
os: {
|
||||
Ext: {
|
||||
|
|
|
@ -97,8 +97,8 @@ export interface ProcessEventHost {
|
|||
architecture?: string;
|
||||
hostname?: string;
|
||||
id?: string;
|
||||
ip?: string;
|
||||
mac?: string;
|
||||
ip?: string[];
|
||||
mac?: string[];
|
||||
name?: string;
|
||||
os?: {
|
||||
family?: string;
|
||||
|
|
|
@ -24,7 +24,9 @@ describe('DetailPanelCopy component', () => {
|
|||
describe('When DetailPanelCopy is mounted', () => {
|
||||
it('renders DetailPanelCopy correctly', async () => {
|
||||
renderResult = mockedContext.render(
|
||||
<DetailPanelCopy textToCopy={TEST_TEXT_COPY}>{TEST_CHILD}</DetailPanelCopy>
|
||||
<DetailPanelCopy textToCopy={TEST_TEXT_COPY} tooltipContent={TEST_TEXT_COPY}>
|
||||
{TEST_CHILD}
|
||||
</DetailPanelCopy>
|
||||
);
|
||||
|
||||
expect(renderResult.queryByText(TEST_TEXT_COPY)).toBeVisible();
|
||||
|
|
|
@ -8,12 +8,12 @@ import React, { ReactNode } from 'react';
|
|||
import { EuiButtonIcon, EuiCopy, EuiToolTip } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { DetailPanelListItem } from '../detail_panel_list_item';
|
||||
import { dataOrDash } from '../../utils/data_or_dash';
|
||||
import { useStyles } from './styles';
|
||||
|
||||
interface DetailPanelCopyDeps {
|
||||
children: ReactNode;
|
||||
textToCopy: string;
|
||||
tooltipContent: ReactNode;
|
||||
display?: 'inlineBlock' | 'block' | undefined;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ interface DetailPanelListItemProps {
|
|||
export const DetailPanelCopy = ({
|
||||
children,
|
||||
textToCopy,
|
||||
tooltipContent,
|
||||
display = 'inlineBlock',
|
||||
}: DetailPanelCopyDeps) => {
|
||||
const styles = useStyles();
|
||||
|
@ -57,7 +58,7 @@ export const DetailPanelCopy = ({
|
|||
|
||||
return (
|
||||
<DetailPanelListItem {...props}>
|
||||
<EuiToolTip position="top" content={dataOrDash(textToCopy)}>
|
||||
<EuiToolTip position="top" content={tooltipContent}>
|
||||
<>{children}</>
|
||||
</EuiToolTip>
|
||||
</DetailPanelListItem>
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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 { ProcessEventHost } from '../../../common/types/process_tree';
|
||||
import { DASH } from '../../constants';
|
||||
import { getHostData } from './helpers';
|
||||
|
||||
const MOCK_HOST_DATA: ProcessEventHost = {
|
||||
architecture: 'x86_64',
|
||||
hostname: 'james-fleet-714-2',
|
||||
id: '48c1b3f1ac5da4e0057fc9f60f4d1d5d',
|
||||
ip: ['127.0.0.1', '::1', '10.132.0.50', 'fe80::7d39:3147:4d9a:f809'],
|
||||
mac: ['42:01:0a:84:00:32'],
|
||||
name: 'james-fleet-714-2',
|
||||
os: {
|
||||
family: 'centos',
|
||||
full: 'CentOS 7.9.2009',
|
||||
kernel: '3.10.0-1160.31.1.el7.x86_64 #1 SMP Thu Jun 10 13:32:12 UTC 2021',
|
||||
name: 'Linux',
|
||||
platform: 'centos',
|
||||
version: '7.9.2009',
|
||||
},
|
||||
};
|
||||
|
||||
describe('detail panel host tab helpers tests', () => {
|
||||
it('getHostData returns fields with a dash with undefined host', () => {
|
||||
const result = getHostData(undefined);
|
||||
expect(result.architecture).toEqual(DASH);
|
||||
expect(result.hostname).toEqual(DASH);
|
||||
expect(result.id).toEqual(DASH);
|
||||
expect(result.ip).toEqual(DASH);
|
||||
expect(result.mac).toEqual(DASH);
|
||||
expect(result.name).toEqual(DASH);
|
||||
expect(result.os.family).toEqual(DASH);
|
||||
expect(result.os.full).toEqual(DASH);
|
||||
expect(result.os.kernel).toEqual(DASH);
|
||||
expect(result.os.name).toEqual(DASH);
|
||||
expect(result.os.platform).toEqual(DASH);
|
||||
expect(result.os.version).toEqual(DASH);
|
||||
});
|
||||
|
||||
it('getHostData returns dashes for missing fields', () => {
|
||||
const result = getHostData({
|
||||
...MOCK_HOST_DATA,
|
||||
ip: ['127.0.0.1', '', '', 'fe80::7d39:3147:4d9a:f809'],
|
||||
name: undefined,
|
||||
os: {
|
||||
...MOCK_HOST_DATA.os,
|
||||
full: undefined,
|
||||
platform: undefined,
|
||||
},
|
||||
});
|
||||
expect(result.architecture).toEqual(MOCK_HOST_DATA.architecture);
|
||||
expect(result.hostname).toEqual(MOCK_HOST_DATA.hostname);
|
||||
expect(result.id).toEqual(MOCK_HOST_DATA.id);
|
||||
expect(result.ip).toEqual(['127.0.0.1', DASH, DASH, 'fe80::7d39:3147:4d9a:f809'].join(', '));
|
||||
expect(result.mac).toEqual(MOCK_HOST_DATA.mac?.join(', '));
|
||||
expect(result.name).toEqual(DASH);
|
||||
expect(result.os.family).toEqual(MOCK_HOST_DATA.os?.family);
|
||||
expect(result.os.full).toEqual(DASH);
|
||||
expect(result.os.kernel).toEqual(MOCK_HOST_DATA.os?.kernel);
|
||||
expect(result.os.name).toEqual(MOCK_HOST_DATA.os?.name);
|
||||
expect(result.os.platform).toEqual(DASH);
|
||||
expect(result.os.version).toEqual(MOCK_HOST_DATA.os?.version);
|
||||
});
|
||||
|
||||
it('getHostData returns all data provided', () => {
|
||||
const result = getHostData(MOCK_HOST_DATA);
|
||||
expect(result.architecture).toEqual(MOCK_HOST_DATA.architecture);
|
||||
expect(result.hostname).toEqual(MOCK_HOST_DATA.hostname);
|
||||
expect(result.id).toEqual(MOCK_HOST_DATA.id);
|
||||
expect(result.ip).toEqual(MOCK_HOST_DATA.ip?.join(', '));
|
||||
expect(result.mac).toEqual(MOCK_HOST_DATA.mac?.join(', '));
|
||||
expect(result.name).toEqual(MOCK_HOST_DATA.name);
|
||||
expect(result.os.family).toEqual(MOCK_HOST_DATA.os?.family);
|
||||
expect(result.os.full).toEqual(MOCK_HOST_DATA.os?.full);
|
||||
expect(result.os.kernel).toEqual(MOCK_HOST_DATA.os?.kernel);
|
||||
expect(result.os.name).toEqual(MOCK_HOST_DATA.os?.name);
|
||||
expect(result.os.platform).toEqual(MOCK_HOST_DATA.os?.platform);
|
||||
expect(result.os.version).toEqual(MOCK_HOST_DATA.os?.version);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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 { ProcessEventHost } from '../../../common/types/process_tree';
|
||||
import { DASH } from '../../constants';
|
||||
import { DetailPanelHost } from '../../types';
|
||||
import { dataOrDash } from '../../utils/data_or_dash';
|
||||
|
||||
export const getHostData = (host: ProcessEventHost | undefined): DetailPanelHost => {
|
||||
const detailPanelHost: DetailPanelHost = {
|
||||
architecture: DASH,
|
||||
hostname: DASH,
|
||||
id: DASH,
|
||||
ip: DASH,
|
||||
mac: DASH,
|
||||
name: DASH,
|
||||
os: {
|
||||
family: DASH,
|
||||
full: DASH,
|
||||
kernel: DASH,
|
||||
name: DASH,
|
||||
platform: DASH,
|
||||
version: DASH,
|
||||
},
|
||||
};
|
||||
|
||||
if (!host) {
|
||||
return detailPanelHost;
|
||||
}
|
||||
|
||||
detailPanelHost.hostname = dataOrDash(host.hostname).toString();
|
||||
detailPanelHost.id = dataOrDash(host.id).toString();
|
||||
detailPanelHost.ip = host.ip?.map?.((ip) => dataOrDash(ip)).join(', ') ?? DASH;
|
||||
detailPanelHost.mac = host.mac?.map?.((mac) => dataOrDash(mac)).join(', ') ?? DASH;
|
||||
detailPanelHost.name = dataOrDash(host.name).toString();
|
||||
detailPanelHost.architecture = dataOrDash(host.architecture).toString();
|
||||
detailPanelHost.os.family = dataOrDash(host.os?.family).toString();
|
||||
detailPanelHost.os.full = dataOrDash(host.os?.full).toString();
|
||||
detailPanelHost.os.kernel = dataOrDash(host.os?.kernel).toString();
|
||||
detailPanelHost.os.name = dataOrDash(host.os?.name).toString();
|
||||
detailPanelHost.os.platform = dataOrDash(host.os?.platform).toString();
|
||||
detailPanelHost.os.version = dataOrDash(host.os?.version).toString();
|
||||
|
||||
return detailPanelHost;
|
||||
};
|
|
@ -13,8 +13,8 @@ import { DetailPanelHostTab } from '.';
|
|||
const TEST_ARCHITECTURE = 'x86_64';
|
||||
const TEST_HOSTNAME = 'host-james-fleet-714-2';
|
||||
const TEST_ID = '48c1b3f1ac5da4e0057fc9f60f4d1d5d';
|
||||
const TEST_IP = '127.0.0.1,::1,10.132.0.50,fe80::7d39:3147:4d9a:f809';
|
||||
const TEST_MAC = '42:01:0a:84:00:32';
|
||||
const TEST_IP = ['127.0.0.1', '::1', '10.132.0.50', 'fe80::7d39:3147:4d9a:f809'];
|
||||
const TEST_MAC = ['42:01:0a:84:00:32'];
|
||||
const TEST_NAME = 'name-james-fleet-714-2';
|
||||
const TEST_OS_FAMILY = 'family-centos';
|
||||
const TEST_OS_FULL = 'full-CentOS 7.9.2009';
|
||||
|
@ -62,8 +62,8 @@ describe('DetailPanelHostTab component', () => {
|
|||
expect(renderResult.queryByText(TEST_ARCHITECTURE)).toBeVisible();
|
||||
expect(renderResult.queryByText(TEST_HOSTNAME)).toBeVisible();
|
||||
expect(renderResult.queryByText(TEST_ID)).toBeVisible();
|
||||
expect(renderResult.queryByText(TEST_IP)).toBeVisible();
|
||||
expect(renderResult.queryByText(TEST_MAC)).toBeVisible();
|
||||
expect(renderResult.queryByText(TEST_IP.join(', '))).toBeVisible();
|
||||
expect(renderResult.queryByText(TEST_MAC.join(', '))).toBeVisible();
|
||||
expect(renderResult.queryByText(TEST_NAME)).toBeVisible();
|
||||
|
||||
// expand host os accordion
|
||||
|
|
|
@ -4,15 +4,15 @@
|
|||
* 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 { EuiTextColor } from '@elastic/eui';
|
||||
import { ProcessEventHost } from '../../../common/types/process_tree';
|
||||
import { DetailPanelAccordion } from '../detail_panel_accordion';
|
||||
import { DetailPanelCopy } from '../detail_panel_copy';
|
||||
import { DetailPanelDescriptionList } from '../detail_panel_description_list';
|
||||
import { DetailPanelListItem } from '../detail_panel_list_item';
|
||||
import { dataOrDash } from '../../utils/data_or_dash';
|
||||
import { useStyles } from '../detail_panel_process_tab/styles';
|
||||
import { getHostData } from './helpers';
|
||||
|
||||
interface DetailPanelHostTabDeps {
|
||||
processHost?: ProcessEventHost;
|
||||
|
@ -23,6 +23,7 @@ interface DetailPanelHostTabDeps {
|
|||
*/
|
||||
export const DetailPanelHostTab = ({ processHost }: DetailPanelHostTabDeps) => {
|
||||
const styles = useStyles();
|
||||
const hostData = useMemo(() => getHostData(processHost), [processHost]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -31,9 +32,12 @@ export const DetailPanelHostTab = ({ processHost }: DetailPanelHostTabDeps) => {
|
|||
{
|
||||
title: <DetailPanelListItem>hostname</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy textToCopy={`host.hostname: "${dataOrDash(processHost?.hostname)}"`}>
|
||||
<DetailPanelCopy
|
||||
textToCopy={`host.hostname: "${hostData.hostname}"`}
|
||||
tooltipContent={hostData.hostname}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(processHost?.hostname)}
|
||||
{hostData.hostname}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -41,9 +45,12 @@ export const DetailPanelHostTab = ({ processHost }: DetailPanelHostTabDeps) => {
|
|||
{
|
||||
title: <DetailPanelListItem>id</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy textToCopy={`host.id: "${dataOrDash(processHost?.id)}"`}>
|
||||
<DetailPanelCopy
|
||||
textToCopy={`host.id: "${hostData.id}"`}
|
||||
tooltipContent={hostData.id}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(processHost?.id)}
|
||||
{hostData.id}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -51,9 +58,12 @@ export const DetailPanelHostTab = ({ processHost }: DetailPanelHostTabDeps) => {
|
|||
{
|
||||
title: <DetailPanelListItem>ip</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy textToCopy={`host.ip: "${dataOrDash(processHost?.ip)}"`}>
|
||||
<DetailPanelCopy
|
||||
textToCopy={`host.ip: "${hostData.ip}"`}
|
||||
tooltipContent={hostData.ip}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(processHost?.ip)}
|
||||
{hostData.ip}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -61,9 +71,12 @@ export const DetailPanelHostTab = ({ processHost }: DetailPanelHostTabDeps) => {
|
|||
{
|
||||
title: <DetailPanelListItem>mac</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy textToCopy={`host.mac: "${dataOrDash(processHost?.mac)}"`}>
|
||||
<DetailPanelCopy
|
||||
textToCopy={`host.mac: "${hostData.mac}"`}
|
||||
tooltipContent={hostData.mac}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(processHost?.mac)}
|
||||
{hostData.mac}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -71,9 +84,12 @@ export const DetailPanelHostTab = ({ processHost }: DetailPanelHostTabDeps) => {
|
|||
{
|
||||
title: <DetailPanelListItem>name</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy textToCopy={`host.name: "${dataOrDash(processHost?.name)}"`}>
|
||||
<DetailPanelCopy
|
||||
textToCopy={`host.name: "${hostData.name}"`}
|
||||
tooltipContent={hostData.name}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(processHost?.name)}
|
||||
{hostData.name}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -88,10 +104,11 @@ export const DetailPanelHostTab = ({ processHost }: DetailPanelHostTabDeps) => {
|
|||
title: <DetailPanelListItem>architecture</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`host.architecture: "${dataOrDash(processHost?.architecture)}"`}
|
||||
textToCopy={`host.architecture: "${hostData.architecture}"`}
|
||||
tooltipContent={hostData.architecture}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(processHost?.architecture)}
|
||||
{hostData.architecture}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -100,10 +117,11 @@ export const DetailPanelHostTab = ({ processHost }: DetailPanelHostTabDeps) => {
|
|||
title: <DetailPanelListItem>os.family</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`host.os.family: "${dataOrDash(processHost?.os?.family)}"`}
|
||||
textToCopy={`host.os.family: "${hostData.os.family}"`}
|
||||
tooltipContent={hostData.os.family}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(processHost?.os?.family)}
|
||||
{hostData.os.family}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -111,9 +129,12 @@ export const DetailPanelHostTab = ({ processHost }: DetailPanelHostTabDeps) => {
|
|||
{
|
||||
title: <DetailPanelListItem>os.full</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy textToCopy={`host.os.full: "${dataOrDash(processHost?.os?.full)}"`}>
|
||||
<DetailPanelCopy
|
||||
textToCopy={`host.os.full: "${hostData.os.full}"`}
|
||||
tooltipContent={hostData.os.full}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(processHost?.os?.full)}
|
||||
{hostData.os.full}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -122,10 +143,11 @@ export const DetailPanelHostTab = ({ processHost }: DetailPanelHostTabDeps) => {
|
|||
title: <DetailPanelListItem>os.kernel</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`host.os.kernel: "${dataOrDash(processHost?.os?.kernel)}"`}
|
||||
textToCopy={`host.os.kernel: "${hostData.os.kernel}"`}
|
||||
tooltipContent={hostData.os.kernel}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(processHost?.os?.kernel)}
|
||||
{hostData.os.kernel}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -133,9 +155,12 @@ export const DetailPanelHostTab = ({ processHost }: DetailPanelHostTabDeps) => {
|
|||
{
|
||||
title: <DetailPanelListItem>os.name</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy textToCopy={`host.os.name: "${dataOrDash(processHost?.os?.name)}"`}>
|
||||
<DetailPanelCopy
|
||||
textToCopy={`host.os.name: "${hostData.os.name}"`}
|
||||
tooltipContent={hostData.os.name}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(processHost?.os?.name)}
|
||||
{hostData.os.name}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -144,10 +169,11 @@ export const DetailPanelHostTab = ({ processHost }: DetailPanelHostTabDeps) => {
|
|||
title: <DetailPanelListItem>os.platform</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`host.os.platform: "${dataOrDash(processHost?.os?.platform)}"`}
|
||||
textToCopy={`host.os.platform: "${hostData.os.platform}"`}
|
||||
tooltipContent={hostData.os.platform}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(processHost?.os?.platform)}
|
||||
{hostData.os.platform}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -156,10 +182,11 @@ export const DetailPanelHostTab = ({ processHost }: DetailPanelHostTabDeps) => {
|
|||
title: <DetailPanelListItem>os.version</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`host.os.version: "${dataOrDash(processHost?.os?.version)}"`}
|
||||
textToCopy={`host.os.version: "${hostData.os.version}"`}
|
||||
tooltipContent={hostData.os.version}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(processHost?.os?.version)}
|
||||
{hostData.os.version}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { DASH } from '../../constants';
|
||||
import { getProcessExecutableCopyText, formatProcessArgs, getIsInterativeString } from './helpers';
|
||||
|
||||
describe('detail panel process tab helpers tests', () => {
|
||||
|
@ -36,7 +37,7 @@ describe('detail panel process tab helpers tests', () => {
|
|||
|
||||
it("formatProcessArgs returns '-' when given empty args array", () => {
|
||||
const result = formatProcessArgs([]);
|
||||
expect(result).toEqual('-');
|
||||
expect(result).toEqual(DASH);
|
||||
});
|
||||
|
||||
it('formatProcessArgs returns formatted args string', () => {
|
||||
|
|
|
@ -5,7 +5,29 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { Teletype } from '../../../common/types/process_tree';
|
||||
import { EventAction, Process, ProcessFields, Teletype } from '../../../common/types/process_tree';
|
||||
import { DetailPanelProcess, DetailPanelProcessLeader } from '../../types';
|
||||
import { DASH } from '../../constants';
|
||||
import { dataOrDash } from '../../utils/data_or_dash';
|
||||
|
||||
const FILTER_FORKS_EXECS = [EventAction.fork, EventAction.exec];
|
||||
|
||||
const DEFAULT_PROCESS_DATA: DetailPanelProcessLeader = {
|
||||
id: DASH,
|
||||
name: DASH,
|
||||
start: DASH,
|
||||
end: DASH,
|
||||
exitCode: DASH,
|
||||
userName: DASH,
|
||||
groupName: DASH,
|
||||
workingDirectory: DASH,
|
||||
interactive: DASH,
|
||||
args: DASH,
|
||||
pid: DASH,
|
||||
entryMetaType: DASH,
|
||||
entryMetaSourceIp: DASH,
|
||||
executable: [[DASH]],
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize an array of executable tuples to a copyable text.
|
||||
|
@ -32,11 +54,11 @@ export const getProcessExecutableCopyText = (executable: string[][]): string =>
|
|||
/**
|
||||
* Format an array of args for display.
|
||||
*
|
||||
* @param {String[]} args
|
||||
* @param {String[] | undefined} args
|
||||
* @return {String} formatted string of process args
|
||||
*/
|
||||
export const formatProcessArgs = (args: string[]): string =>
|
||||
args.length ? `[${args.map((arg) => `'${arg}'`).join(', ')}]` : '-';
|
||||
export const formatProcessArgs = (args: string[] | undefined): string =>
|
||||
args && args.length && args.map ? `[${args.map((arg) => `'${arg}'`).join(', ')}]` : DASH;
|
||||
|
||||
/**
|
||||
* Get isInteractive boolean string from tty.
|
||||
|
@ -46,3 +68,86 @@ export const formatProcessArgs = (args: string[]): string =>
|
|||
*/
|
||||
export const getIsInterativeString = (tty: Teletype | undefined): string =>
|
||||
!!tty ? 'True' : 'False';
|
||||
|
||||
const getDetailPanelProcessLeader = (
|
||||
leader: ProcessFields | undefined
|
||||
): DetailPanelProcessLeader => ({
|
||||
...leader,
|
||||
id: leader?.entity_id ?? DEFAULT_PROCESS_DATA.id,
|
||||
name: leader?.name ?? DEFAULT_PROCESS_DATA.name,
|
||||
start: leader?.start ?? DEFAULT_PROCESS_DATA.start,
|
||||
end: leader?.end ?? DEFAULT_PROCESS_DATA.end,
|
||||
exitCode: leader?.exit_code?.toString() ?? DEFAULT_PROCESS_DATA.exitCode,
|
||||
interactive: getIsInterativeString(leader?.tty),
|
||||
userName: leader?.user?.name ?? DEFAULT_PROCESS_DATA.userName,
|
||||
groupName: leader?.group?.name ?? DEFAULT_PROCESS_DATA.groupName,
|
||||
workingDirectory: leader?.working_directory ?? DEFAULT_PROCESS_DATA.workingDirectory,
|
||||
args: formatProcessArgs(leader?.args) ?? DEFAULT_PROCESS_DATA.args,
|
||||
pid: leader?.pid?.toString() ?? DEFAULT_PROCESS_DATA.pid,
|
||||
// TODO: get the event action of leader
|
||||
executable: leader?.executable ? [[leader?.executable]] : DEFAULT_PROCESS_DATA.executable,
|
||||
entryMetaType: leader?.entry_meta?.type ?? DEFAULT_PROCESS_DATA.entryMetaType,
|
||||
entryMetaSourceIp: leader?.entry_meta?.source?.ip ?? DEFAULT_PROCESS_DATA.entryMetaSourceIp,
|
||||
});
|
||||
|
||||
export const getDetailPanelProcess = (process: Process | null): DetailPanelProcess => {
|
||||
const processData = {
|
||||
id: DEFAULT_PROCESS_DATA.id,
|
||||
start: DEFAULT_PROCESS_DATA.start,
|
||||
end: DEFAULT_PROCESS_DATA.end,
|
||||
exitCode: DEFAULT_PROCESS_DATA.exitCode,
|
||||
interactive: DEFAULT_PROCESS_DATA.interactive,
|
||||
userName: DEFAULT_PROCESS_DATA.userName,
|
||||
groupName: DEFAULT_PROCESS_DATA.groupName,
|
||||
args: DEFAULT_PROCESS_DATA.args,
|
||||
pid: DEFAULT_PROCESS_DATA.pid,
|
||||
executable: DEFAULT_PROCESS_DATA.executable,
|
||||
workingDirectory: DEFAULT_PROCESS_DATA.workingDirectory,
|
||||
entryLeader: DEFAULT_PROCESS_DATA,
|
||||
sessionLeader: DEFAULT_PROCESS_DATA,
|
||||
groupLeader: DEFAULT_PROCESS_DATA,
|
||||
parent: DEFAULT_PROCESS_DATA,
|
||||
} as DetailPanelProcess;
|
||||
if (!process) {
|
||||
return processData;
|
||||
}
|
||||
|
||||
const details = process.getDetails();
|
||||
|
||||
processData.id = `${dataOrDash(process.id)}`;
|
||||
processData.start = `${dataOrDash(details.process?.start)}`;
|
||||
processData.end = `${dataOrDash(process.getEndTime())}`;
|
||||
processData.exitCode = `${dataOrDash(details.process?.exit_code)}`;
|
||||
processData.interactive = getIsInterativeString(details.process?.tty);
|
||||
processData.userName = `${dataOrDash(details.process?.user?.name)}`;
|
||||
processData.groupName = `${dataOrDash(details.process?.group?.name)}`;
|
||||
processData.pid = `${dataOrDash(details.process?.pid)}`;
|
||||
processData.workingDirectory = `${dataOrDash(details.process?.working_directory)}`;
|
||||
if (details.process?.args) {
|
||||
processData.args = formatProcessArgs(details.process.args);
|
||||
}
|
||||
|
||||
// we grab the executable from each process lifecycle event to give an indication
|
||||
// of the processes journey. Processes can sometimes exec multiple times, so it's good
|
||||
// information to have.
|
||||
processData.executable = [];
|
||||
process.events.forEach((event) => {
|
||||
if (
|
||||
event.process?.executable &&
|
||||
event.event?.action &&
|
||||
FILTER_FORKS_EXECS.includes(event.event.action)
|
||||
) {
|
||||
processData.executable.push([event.process.executable, `(${event.event.action})`]);
|
||||
}
|
||||
});
|
||||
if (!processData.executable.length) {
|
||||
processData.executable = DEFAULT_PROCESS_DATA.executable;
|
||||
}
|
||||
|
||||
processData.entryLeader = getDetailPanelProcessLeader(details?.process?.entry_leader);
|
||||
processData.sessionLeader = getDetailPanelProcessLeader(details?.process?.session_leader);
|
||||
processData.groupLeader = getDetailPanelProcessLeader(details?.process?.group_leader);
|
||||
processData.parent = getDetailPanelProcessLeader(details?.process?.parent);
|
||||
|
||||
return processData;
|
||||
};
|
||||
|
|
|
@ -7,60 +7,15 @@
|
|||
|
||||
import React from 'react';
|
||||
import { AppContextTestRender, createAppRootMockRenderer } from '../../test';
|
||||
import { DetailPanelProcess, DetailPanelProcessLeader } from '../../types';
|
||||
import { sessionViewBasicProcessMock } from '../../../common/mocks/constants/session_view_process.mock';
|
||||
import { DetailPanelProcessTab } from '.';
|
||||
|
||||
const getLeaderDetail = (leader: string): DetailPanelProcessLeader => ({
|
||||
id: `${leader}-id`,
|
||||
name: `${leader}-name`,
|
||||
start: new Date('2022-02-24').toISOString(),
|
||||
entryMetaType: 'sshd',
|
||||
working_directory: '/home/jack',
|
||||
tty: {
|
||||
char_device: {
|
||||
major: 8,
|
||||
minor: 1,
|
||||
},
|
||||
},
|
||||
args: ['ls'],
|
||||
userName: `${leader}-jack`,
|
||||
groupName: `${leader}-jack-group`,
|
||||
pid: 1234,
|
||||
entryMetaSourceIp: '10.132.0.50',
|
||||
executable: '/usr/bin/bash',
|
||||
});
|
||||
|
||||
const TEST_PROCESS_DETAIL: DetailPanelProcess = {
|
||||
id: 'process-id',
|
||||
start: new Date('2022-02-22').toISOString(),
|
||||
end: new Date('2022-02-23').toISOString(),
|
||||
exit_code: 137,
|
||||
userName: 'process-jack',
|
||||
groupName: 'process-jack-group',
|
||||
args: ['vi', 'test.txt'],
|
||||
executable: [
|
||||
['test-executable-cmd', '(fork)'],
|
||||
['test-executable-cmd', '(exec)'],
|
||||
['test-executable-cmd', '(end)'],
|
||||
],
|
||||
working_directory: '/home/jack',
|
||||
tty: {
|
||||
char_device: {
|
||||
major: 8,
|
||||
minor: 1,
|
||||
},
|
||||
},
|
||||
pid: 1233,
|
||||
entryLeader: getLeaderDetail('entryLeader'),
|
||||
sessionLeader: getLeaderDetail('sessionLeader'),
|
||||
groupLeader: getLeaderDetail('groupLeader'),
|
||||
parent: getLeaderDetail('parent'),
|
||||
};
|
||||
|
||||
describe('DetailPanelProcessTab component', () => {
|
||||
let render: () => ReturnType<AppContextTestRender['render']>;
|
||||
let renderResult: ReturnType<typeof render>;
|
||||
let mockedContext: AppContextTestRender;
|
||||
const processDetail = sessionViewBasicProcessMock.getDetails();
|
||||
const MOCK_PROCESS_END = '2021-11-24T15:25:04.210Z';
|
||||
|
||||
beforeEach(() => {
|
||||
mockedContext = createAppRootMockRenderer();
|
||||
|
@ -69,21 +24,29 @@ describe('DetailPanelProcessTab component', () => {
|
|||
describe('When DetailPanelProcessTab is mounted', () => {
|
||||
it('renders DetailPanelProcessTab correctly', async () => {
|
||||
renderResult = mockedContext.render(
|
||||
<DetailPanelProcessTab processDetail={TEST_PROCESS_DETAIL} />
|
||||
<DetailPanelProcessTab
|
||||
selectedProcess={{
|
||||
...sessionViewBasicProcessMock,
|
||||
getEndTime: () => MOCK_PROCESS_END,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
// Process detail rendered correctly
|
||||
expect(renderResult.queryByText(TEST_PROCESS_DETAIL.id)).toBeVisible();
|
||||
expect(renderResult.queryByText(TEST_PROCESS_DETAIL.start)).toBeVisible();
|
||||
expect(renderResult.queryByText(TEST_PROCESS_DETAIL.end)).toBeVisible();
|
||||
expect(renderResult.queryByText(TEST_PROCESS_DETAIL.exit_code!)).toBeVisible();
|
||||
expect(renderResult.queryByText(TEST_PROCESS_DETAIL.userName)).toBeVisible();
|
||||
expect(renderResult.queryByText(`['vi', 'test.txt']`)).toBeVisible();
|
||||
expect(renderResult.queryAllByText('test-executable-cmd')).toHaveLength(3);
|
||||
expect(renderResult.queryByText(processDetail!.process!.entity_id!)).toBeVisible();
|
||||
expect(renderResult.queryByText(processDetail!.process!.start!)).toBeVisible();
|
||||
expect(renderResult.queryByText(MOCK_PROCESS_END)).toBeVisible();
|
||||
expect(renderResult.queryByText(processDetail!.process!.exit_code!)).toBeVisible();
|
||||
expect(renderResult.queryAllByText(processDetail!.process!.user!.name!)).toHaveLength(10);
|
||||
expect(renderResult.queryAllByText(processDetail!.process!.working_directory!)).toHaveLength(
|
||||
5
|
||||
);
|
||||
expect(renderResult.queryByText(`['bash']`)).toBeVisible();
|
||||
expect(renderResult.queryAllByText('/usr/bin/bash')).toHaveLength(5);
|
||||
expect(renderResult.queryByText('/usr/bin/vi')).toBeVisible();
|
||||
expect(renderResult.queryByText('(fork)')).toBeVisible();
|
||||
expect(renderResult.queryByText('(exec)')).toBeVisible();
|
||||
expect(renderResult.queryByText('(end)')).toBeVisible();
|
||||
expect(renderResult.queryByText(TEST_PROCESS_DETAIL.pid!)).toBeVisible();
|
||||
expect(renderResult.queryByText(processDetail!.process!.pid!)).toBeVisible();
|
||||
|
||||
// Process tab accordions rendered correctly
|
||||
// TODO: revert back when we have jump to leaders button working
|
||||
|
|
|
@ -4,20 +4,20 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import React, { ReactNode } from 'react';
|
||||
import React, { ReactNode, useCallback, useMemo } from 'react';
|
||||
import { EuiTextColor } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { DetailPanelProcess } from '../../types';
|
||||
import { Process } from '../../../common/types/process_tree';
|
||||
import { DetailPanelAccordion } from '../detail_panel_accordion';
|
||||
import { DetailPanelCopy } from '../detail_panel_copy';
|
||||
import { DetailPanelDescriptionList } from '../detail_panel_description_list';
|
||||
import { DetailPanelListItem } from '../detail_panel_list_item';
|
||||
import { dataOrDash } from '../../utils/data_or_dash';
|
||||
import { getProcessExecutableCopyText, formatProcessArgs, getIsInterativeString } from './helpers';
|
||||
import { getProcessExecutableCopyText, getDetailPanelProcess } from './helpers';
|
||||
import { useStyles } from './styles';
|
||||
|
||||
interface DetailPanelProcessTabDeps {
|
||||
processDetail: DetailPanelProcess;
|
||||
selectedProcess: Process | null;
|
||||
}
|
||||
|
||||
type ListItems = Array<{
|
||||
|
@ -70,8 +70,30 @@ const LEADER_FIELD_PREFIX = [
|
|||
/**
|
||||
* Detail panel in the session view.
|
||||
*/
|
||||
export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDeps) => {
|
||||
export const DetailPanelProcessTab = ({ selectedProcess }: DetailPanelProcessTabDeps) => {
|
||||
const styles = useStyles();
|
||||
|
||||
const processDetail = useMemo(() => getDetailPanelProcess(selectedProcess), [selectedProcess]);
|
||||
const renderExecs = useCallback(
|
||||
(executable: string[][]) =>
|
||||
executable.map((execTuple, idx) => {
|
||||
const [exec, eventAction] = execTuple;
|
||||
return (
|
||||
<div key={`executable-${idx}`} css={styles.ellipsis}>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{exec}
|
||||
</EuiTextColor>
|
||||
{eventAction && (
|
||||
<EuiTextColor color="subdued" css={styles.executableAction}>
|
||||
{eventAction}
|
||||
</EuiTextColor>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}),
|
||||
[styles.descriptionSemibold, styles.ellipsis, styles.executableAction]
|
||||
);
|
||||
|
||||
const leaderListItems = [
|
||||
processDetail.entryLeader,
|
||||
processDetail.sessionLeader,
|
||||
|
@ -82,27 +104,29 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
id,
|
||||
start,
|
||||
end,
|
||||
exit_code: exitCode,
|
||||
exitCode,
|
||||
entryMetaType,
|
||||
tty,
|
||||
working_directory: workingDirectory,
|
||||
interactive,
|
||||
workingDirectory,
|
||||
args,
|
||||
executable,
|
||||
pid,
|
||||
userName,
|
||||
groupName,
|
||||
entryMetaSourceIp,
|
||||
} = leader;
|
||||
const leaderArgs = formatProcessArgs(args);
|
||||
const isLeaderInteractive = getIsInterativeString(tty);
|
||||
|
||||
const leaderExecutableText = getProcessExecutableCopyText(executable);
|
||||
const listItems: ListItems = [
|
||||
{
|
||||
title: <DetailPanelListItem>entity_id</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.entity_id: "${dataOrDash(id)}"`}
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.entity_id: "${id}"`}
|
||||
tooltipContent={id}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(id)}
|
||||
{id}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -110,8 +134,22 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
{
|
||||
title: <DetailPanelListItem>args</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy textToCopy={`${LEADER_FIELD_PREFIX[idx]}.args: "${leaderArgs}"`}>
|
||||
{leaderArgs}
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.args: "${args}"`}
|
||||
tooltipContent={args}
|
||||
>
|
||||
{args}
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: <DetailPanelListItem>executable</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.executable: "${leaderExecutableText}"`}
|
||||
tooltipContent={leaderExecutableText}
|
||||
>
|
||||
{renderExecs(executable)}
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
},
|
||||
|
@ -119,10 +157,11 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
title: <DetailPanelListItem>interactive</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.interactive: "${isLeaderInteractive}"`}
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.interactive: "${interactive}"`}
|
||||
tooltipContent={interactive}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{isLeaderInteractive}
|
||||
{interactive}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -131,12 +170,11 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
title: <DetailPanelListItem>working_directory</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.working_directory: "${dataOrDash(
|
||||
workingDirectory
|
||||
)}"`}
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.working_directory: "${workingDirectory}"`}
|
||||
tooltipContent={workingDirectory}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(workingDirectory)}
|
||||
{workingDirectory}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -144,9 +182,12 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
{
|
||||
title: <DetailPanelListItem>pid</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy textToCopy={`${LEADER_FIELD_PREFIX[idx]}.pid: "${dataOrDash(pid)}"`}>
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.pid: "${pid}"`}
|
||||
tooltipContent={pid}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(pid)}
|
||||
{pid}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -154,16 +195,22 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
{
|
||||
title: <DetailPanelListItem>start</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy textToCopy={`${LEADER_FIELD_PREFIX[idx]}.start: "${dataOrDash(start)}"`}>
|
||||
{dataOrDash(start)}
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.start: "${start}"`}
|
||||
tooltipContent={start}
|
||||
>
|
||||
{start}
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: <DetailPanelListItem>end</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy textToCopy={`${LEADER_FIELD_PREFIX[idx]}.end: "${dataOrDash(end)}"`}>
|
||||
{dataOrDash(end)}
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.end: "${end}"`}
|
||||
tooltipContent={end}
|
||||
>
|
||||
{end}
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
},
|
||||
|
@ -171,10 +218,11 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
title: <DetailPanelListItem>exit_code</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.exit_code: "${dataOrDash(exitCode)}"`}
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.exit_code: "${exitCode}"`}
|
||||
tooltipContent={exitCode}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(exitCode)}
|
||||
{exitCode}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -183,9 +231,10 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
title: <DetailPanelListItem>user.name</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.user.name: "${dataOrDash(userName)}"`}
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.user.name: "${userName}"`}
|
||||
tooltipContent={userName}
|
||||
>
|
||||
{dataOrDash(userName)}
|
||||
{userName}
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
},
|
||||
|
@ -193,9 +242,10 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
title: <DetailPanelListItem>group.name</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.group.name: "${dataOrDash(groupName)}"`}
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.group.name: "${groupName}"`}
|
||||
tooltipContent={groupName}
|
||||
>
|
||||
{dataOrDash(groupName)}
|
||||
{groupName}
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
},
|
||||
|
@ -207,12 +257,11 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
title: <DetailPanelListItem>entry_meta.type</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.entry_meta.type: "${dataOrDash(
|
||||
entryMetaType
|
||||
)}"`}
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.entry_meta.type: "${entryMetaType}"`}
|
||||
tooltipContent={entryMetaType}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(entryMetaType)}
|
||||
{entryMetaType}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -221,9 +270,8 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
title: <DetailPanelListItem>entry_meta.source.ip</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.entry_meta.source.ip: "${dataOrDash(
|
||||
entryMetaSourceIp
|
||||
)}"`}
|
||||
textToCopy={`${LEADER_FIELD_PREFIX[idx]}.entry_meta.source.ip: "${entryMetaSourceIp}"`}
|
||||
tooltipContent={entryMetaSourceIp}
|
||||
>
|
||||
{dataOrDash(entryMetaSourceIp)}
|
||||
</DetailPanelCopy>
|
||||
|
@ -244,17 +292,15 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
start,
|
||||
end,
|
||||
executable,
|
||||
exit_code: exitCode,
|
||||
exitCode,
|
||||
pid,
|
||||
working_directory: workingDirectory,
|
||||
tty,
|
||||
workingDirectory,
|
||||
interactive,
|
||||
userName,
|
||||
groupName,
|
||||
args,
|
||||
} = processDetail;
|
||||
|
||||
const isInteractive = getIsInterativeString(tty);
|
||||
const processArgs = formatProcessArgs(args);
|
||||
const executableText = getProcessExecutableCopyText(executable);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -264,10 +310,11 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
title: <DetailPanelListItem>entity_id</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.entity_id: "${dataOrDash(id)}"`}
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.entity_id: "${id}"`}
|
||||
tooltipContent={id}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(id)}
|
||||
{id}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -275,8 +322,11 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
{
|
||||
title: <DetailPanelListItem>args</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy textToCopy={`${PROCESS_FIELD_PREFIX}.args: "${processArgs}"`}>
|
||||
{processArgs}
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.args: "${args}"`}
|
||||
tooltipContent={args}
|
||||
>
|
||||
{args}
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
},
|
||||
|
@ -284,24 +334,11 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
title: <DetailPanelListItem>executable</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.executable: "${getProcessExecutableCopyText(
|
||||
executable
|
||||
)}"`}
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.executable: "${executableText}"`}
|
||||
tooltipContent={executableText}
|
||||
display="block"
|
||||
>
|
||||
{executable.map((execTuple, idx) => {
|
||||
const [exec, eventAction] = execTuple;
|
||||
return (
|
||||
<div key={`executable-${idx}`} css={styles.ellipsis}>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(exec)}
|
||||
</EuiTextColor>
|
||||
<EuiTextColor color="subdued" css={styles.executableAction}>
|
||||
{eventAction}
|
||||
</EuiTextColor>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{renderExecs(executable)}
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
},
|
||||
|
@ -309,10 +346,11 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
title: <DetailPanelListItem>interactive</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.interactive: "${isInteractive}"`}
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.interactive: "${interactive}"`}
|
||||
tooltipContent={interactive}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{isInteractive}
|
||||
{interactive}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -321,12 +359,11 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
title: <DetailPanelListItem>working_directory</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.working_directory: "${dataOrDash(
|
||||
workingDirectory
|
||||
)}"`}
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.working_directory: "${workingDirectory}"`}
|
||||
tooltipContent={workingDirectory}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(workingDirectory)}
|
||||
{workingDirectory}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -334,9 +371,12 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
{
|
||||
title: <DetailPanelListItem>pid</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy textToCopy={`${PROCESS_FIELD_PREFIX}.pid: "${dataOrDash(pid)}"`}>
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.pid: "${pid}"`}
|
||||
tooltipContent={pid}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(pid)}
|
||||
{pid}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -344,16 +384,22 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
{
|
||||
title: <DetailPanelListItem>start</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy textToCopy={`${PROCESS_FIELD_PREFIX}.start: "${dataOrDash(start)}"`}>
|
||||
{dataOrDash(start)}
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.start: "${start}"`}
|
||||
tooltipContent={start}
|
||||
>
|
||||
{start}
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: <DetailPanelListItem>end</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy textToCopy={`${PROCESS_FIELD_PREFIX}.end: "${dataOrDash(end)}"`}>
|
||||
{dataOrDash(end)}
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.end: "${end}"`}
|
||||
tooltipContent={end}
|
||||
>
|
||||
{end}
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
},
|
||||
|
@ -361,10 +407,11 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
title: <DetailPanelListItem>exit_code</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.exit_code: "${dataOrDash(exitCode)}"`}
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.exit_code: "${exitCode}"`}
|
||||
tooltipContent={exitCode}
|
||||
>
|
||||
<EuiTextColor color="subdued" css={styles.descriptionSemibold}>
|
||||
{dataOrDash(exitCode)}
|
||||
{exitCode}
|
||||
</EuiTextColor>
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
|
@ -373,9 +420,10 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
title: <DetailPanelListItem>user.name</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.user.name: "${dataOrDash(userName)}"`}
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.user.name: "${userName}"`}
|
||||
tooltipContent={userName}
|
||||
>
|
||||
{dataOrDash(userName)}
|
||||
{userName}
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
},
|
||||
|
@ -383,9 +431,10 @@ export const DetailPanelProcessTab = ({ processDetail }: DetailPanelProcessTabDe
|
|||
title: <DetailPanelListItem>group.name</DetailPanelListItem>,
|
||||
description: (
|
||||
<DetailPanelCopy
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.group.name: "${dataOrDash(groupName)}"`}
|
||||
textToCopy={`${PROCESS_FIELD_PREFIX}.group.name: "${groupName}"`}
|
||||
tooltipContent={groupName}
|
||||
>
|
||||
{dataOrDash(groupName)}
|
||||
{groupName}
|
||||
</DetailPanelCopy>
|
||||
),
|
||||
},
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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 { getSelectedTabContent } from './helpers';
|
||||
import { EuiTabProps } from '../../types';
|
||||
|
||||
const TABS: EuiTabProps[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Process',
|
||||
content: 'process content',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Host',
|
||||
content: 'host content',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
name: 'Alert',
|
||||
content: 'alert content',
|
||||
},
|
||||
];
|
||||
|
||||
describe('session view detail panel helpers tests', () => {
|
||||
it('getSelectedTabContent works', () => {
|
||||
const result = getSelectedTabContent(TABS, '1');
|
||||
expect(result).toBe(TABS[0].content);
|
||||
});
|
||||
|
||||
it('getSelectedTabContent returns null if tab id not found', () => {
|
||||
const result = getSelectedTabContent(TABS, 'process');
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
|
@ -4,108 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import { EventAction, Process, ProcessFields } from '../../../common/types/process_tree';
|
||||
import { DetailPanelProcess, EuiTabProps } from '../../types';
|
||||
|
||||
const FILTER_FORKS_EXECS = [EventAction.fork, EventAction.exec];
|
||||
|
||||
const DEFAULT_PROCESS_DATA = {
|
||||
id: '',
|
||||
name: '',
|
||||
start: '',
|
||||
end: '',
|
||||
userName: '',
|
||||
groupName: '',
|
||||
working_directory: '',
|
||||
args: [],
|
||||
entryMetaType: '',
|
||||
entryMetaSourceIp: '',
|
||||
executable: '',
|
||||
};
|
||||
|
||||
const getDetailPanelProcessLeader = (leader: ProcessFields | undefined) => ({
|
||||
...leader,
|
||||
name: leader?.name ?? DEFAULT_PROCESS_DATA.name,
|
||||
start: leader?.start ?? DEFAULT_PROCESS_DATA.start,
|
||||
working_directory: leader?.working_directory ?? DEFAULT_PROCESS_DATA.working_directory,
|
||||
args: leader?.args ?? DEFAULT_PROCESS_DATA.args,
|
||||
executable: leader?.executable ?? DEFAULT_PROCESS_DATA.executable,
|
||||
id: leader?.entity_id ?? DEFAULT_PROCESS_DATA.id,
|
||||
entryMetaType: leader?.entry_meta?.type ?? DEFAULT_PROCESS_DATA.entryMetaType,
|
||||
userName: leader?.user?.name ?? DEFAULT_PROCESS_DATA.userName,
|
||||
groupName: leader?.group?.name ?? DEFAULT_PROCESS_DATA.groupName,
|
||||
entryMetaSourceIp: leader?.entry_meta?.source?.ip ?? DEFAULT_PROCESS_DATA.entryMetaSourceIp,
|
||||
});
|
||||
|
||||
export const getDetailPanelProcess = (process: Process | null) => {
|
||||
const processData = {} as DetailPanelProcess;
|
||||
if (!process) {
|
||||
return {
|
||||
id: DEFAULT_PROCESS_DATA.id,
|
||||
start: DEFAULT_PROCESS_DATA.start,
|
||||
end: DEFAULT_PROCESS_DATA.end,
|
||||
userName: DEFAULT_PROCESS_DATA.userName,
|
||||
groupName: DEFAULT_PROCESS_DATA.groupName,
|
||||
args: DEFAULT_PROCESS_DATA.args,
|
||||
executable: [],
|
||||
working_directory: DEFAULT_PROCESS_DATA.working_directory,
|
||||
entryLeader: DEFAULT_PROCESS_DATA,
|
||||
sessionLeader: DEFAULT_PROCESS_DATA,
|
||||
groupLeader: DEFAULT_PROCESS_DATA,
|
||||
parent: DEFAULT_PROCESS_DATA,
|
||||
};
|
||||
}
|
||||
|
||||
const details = process.getDetails();
|
||||
|
||||
processData.id = process.id;
|
||||
processData.start = details.process?.start ?? '';
|
||||
processData.args = [];
|
||||
processData.executable = [];
|
||||
|
||||
if (!processData.userName) {
|
||||
processData.userName = details.process?.user?.name ?? '';
|
||||
}
|
||||
if (!processData.groupName) {
|
||||
processData.groupName = details.process?.group?.name ?? '';
|
||||
}
|
||||
if (!processData.pid) {
|
||||
processData.pid = details.process?.pid;
|
||||
}
|
||||
if (!processData.working_directory) {
|
||||
processData.working_directory = details.process?.working_directory ?? '';
|
||||
}
|
||||
if (!processData.tty) {
|
||||
processData.tty = details.process?.tty;
|
||||
}
|
||||
if (details.process?.args && details.process.args.length > 0) {
|
||||
processData.args = details.process.args;
|
||||
}
|
||||
if (details.process?.exit_code !== undefined) {
|
||||
processData.exit_code = details.process.exit_code;
|
||||
}
|
||||
|
||||
// we grab the executable from each process lifecycle event to give an indication
|
||||
// of the processes journey. Processes can sometimes exec multiple times, so it's good
|
||||
// information to have.
|
||||
process.events.forEach((event) => {
|
||||
if (
|
||||
event.process?.executable &&
|
||||
event.event?.action &&
|
||||
FILTER_FORKS_EXECS.includes(event.event.action)
|
||||
) {
|
||||
processData.executable.push([event.process.executable, `(${event.event.action})`]);
|
||||
}
|
||||
});
|
||||
|
||||
processData.end = process.getEndTime();
|
||||
processData.entryLeader = getDetailPanelProcessLeader(details?.process?.entry_leader);
|
||||
processData.sessionLeader = getDetailPanelProcessLeader(details?.process?.session_leader);
|
||||
processData.groupLeader = getDetailPanelProcessLeader(details?.process?.group_leader);
|
||||
processData.parent = getDetailPanelProcessLeader(details?.process?.parent);
|
||||
|
||||
return processData;
|
||||
};
|
||||
import { EuiTabProps } from '../../types';
|
||||
|
||||
export const getSelectedTabContent = (tabs: EuiTabProps[], selectedTabId: string) => {
|
||||
const selectedTab = tabs.find((tab) => tab.id === selectedTabId);
|
||||
|
|
|
@ -9,7 +9,7 @@ import { EuiTabs, EuiTab, EuiNotificationBadge } from '@elastic/eui';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiTabProps } from '../../types';
|
||||
import { Process, ProcessEvent } from '../../../common/types/process_tree';
|
||||
import { getDetailPanelProcess, getSelectedTabContent } from './helpers';
|
||||
import { getSelectedTabContent } from './helpers';
|
||||
import { DetailPanelProcessTab } from '../detail_panel_process_tab';
|
||||
import { DetailPanelHostTab } from '../detail_panel_host_tab';
|
||||
import { useStyles } from './styles';
|
||||
|
@ -35,7 +35,6 @@ export const SessionViewDetailPanel = ({
|
|||
onShowAlertDetails,
|
||||
}: SessionViewDetailPanelDeps) => {
|
||||
const [selectedTabId, setSelectedTabId] = useState('process');
|
||||
const processDetail = useMemo(() => getDetailPanelProcess(selectedProcess), [selectedProcess]);
|
||||
|
||||
const alertsCount = useMemo(() => {
|
||||
if (!alerts) {
|
||||
|
@ -54,7 +53,7 @@ export const SessionViewDetailPanel = ({
|
|||
name: i18n.translate('xpack.sessionView.detailsPanel.process', {
|
||||
defaultMessage: 'Process',
|
||||
}),
|
||||
content: <DetailPanelProcessTab processDetail={processDetail} />,
|
||||
content: <DetailPanelProcessTab selectedProcess={selectedProcess} />,
|
||||
},
|
||||
{
|
||||
id: 'host',
|
||||
|
@ -85,12 +84,11 @@ export const SessionViewDetailPanel = ({
|
|||
];
|
||||
}, [
|
||||
alerts,
|
||||
selectedProcess,
|
||||
alertsCount,
|
||||
processDetail,
|
||||
selectedProcess?.events,
|
||||
onJumpToEvent,
|
||||
onShowAlertDetails,
|
||||
investigatedAlertId,
|
||||
onJumpToEvent,
|
||||
]);
|
||||
|
||||
const onSelectedTabChanged = useCallback((id: string) => {
|
||||
|
|
8
x-pack/plugins/session_view/public/constants.ts
Normal file
8
x-pack/plugins/session_view/public/constants.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export const DASH = '-';
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
import { ReactNode } from 'react';
|
||||
import { CoreStart } from '@kbn/core/public';
|
||||
import { Teletype } from '../common/types/process_tree';
|
||||
|
||||
export type SessionViewServices = CoreStart;
|
||||
|
||||
|
@ -43,14 +42,14 @@ export interface DetailPanelProcess {
|
|||
id: string;
|
||||
start: string;
|
||||
end: string;
|
||||
exit_code?: number;
|
||||
exitCode: string;
|
||||
userName: string;
|
||||
groupName: string;
|
||||
args: string[];
|
||||
args: string;
|
||||
executable: string[][];
|
||||
working_directory: string;
|
||||
tty?: Teletype;
|
||||
pid?: number;
|
||||
workingDirectory: string;
|
||||
interactive: string;
|
||||
pid: string;
|
||||
entryLeader: DetailPanelProcessLeader;
|
||||
sessionLeader: DetailPanelProcessLeader;
|
||||
groupLeader: DetailPanelProcessLeader;
|
||||
|
@ -61,17 +60,34 @@ export interface DetailPanelProcessLeader {
|
|||
id: string;
|
||||
name: string;
|
||||
start: string;
|
||||
end?: string;
|
||||
exit_code?: number;
|
||||
end: string;
|
||||
exitCode: string;
|
||||
userName: string;
|
||||
groupName: string;
|
||||
working_directory: string;
|
||||
tty?: Teletype;
|
||||
args: string[];
|
||||
pid?: number;
|
||||
workingDirectory: string;
|
||||
interactive: string;
|
||||
args: string;
|
||||
pid: string;
|
||||
entryMetaType: string;
|
||||
entryMetaSourceIp: string;
|
||||
executable: string;
|
||||
executable: string[][];
|
||||
}
|
||||
|
||||
export interface DetailPanelHost {
|
||||
architecture: string;
|
||||
hostname: string;
|
||||
id: string;
|
||||
ip: string;
|
||||
mac: string;
|
||||
name: string;
|
||||
os: {
|
||||
family: string;
|
||||
full: string;
|
||||
kernel: string;
|
||||
name: string;
|
||||
platform: string;
|
||||
version: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface SessionViewStart {
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { DASH } from '../constants';
|
||||
import { dataOrDash } from './data_or_dash';
|
||||
|
||||
const TEST_STRING = '123';
|
||||
const TEST_NUMBER = 123;
|
||||
const DASH = '-';
|
||||
|
||||
describe('dataOrDash(data)', () => {
|
||||
it('works for a valid string', () => {
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { DASH } from '../constants';
|
||||
|
||||
/**
|
||||
* Returns a dash ('-') if data is undefined, and empty string, or a NaN.
|
||||
*
|
||||
|
@ -15,7 +17,7 @@
|
|||
*/
|
||||
export const dataOrDash = (data: string | number | undefined): string | number => {
|
||||
if (data === undefined || data === '' || (typeof data === 'number' && isNaN(data))) {
|
||||
return '-';
|
||||
return DASH;
|
||||
}
|
||||
|
||||
return data;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue