From edc836814ab888a485918b94a1918d750d6f2e88 Mon Sep 17 00:00:00 2001 From: Or Ouziel Date: Sun, 5 Dec 2021 14:39:31 +0200 Subject: [PATCH] Flyout refactor (#29) --- .../pages/findings/rule_flyout.tsx | 243 +++++++++--------- 1 file changed, 116 insertions(+), 127 deletions(-) diff --git a/x-pack/plugins/security_solution/public/cloud_posture/pages/findings/rule_flyout.tsx b/x-pack/plugins/security_solution/public/cloud_posture/pages/findings/rule_flyout.tsx index 75c5ff1b07cb8..c6933b1ea66ca 100644 --- a/x-pack/plugins/security_solution/public/cloud_posture/pages/findings/rule_flyout.tsx +++ b/x-pack/plugins/security_solution/public/cloud_posture/pages/findings/rule_flyout.tsx @@ -4,9 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import React, { useState, useCallback } from 'react'; +import React, { useState } from 'react'; import { + EuiFlexItem, EuiSpacer, EuiCode, EuiDescriptionList, @@ -18,16 +18,23 @@ import { EuiBadge, EuiTabs, EuiTab, + EuiFlexGrid, EuiCard, + PropsOf, } from '@elastic/eui'; import { assertNever } from '@kbn/std'; import { CSPFinding } from './types'; import { CSPEvaluationBadge } from '../../components/csp_evaluation_badge'; -const tabs = ['resource', 'rule', 'overview'] as const; +const tabs = ['result', 'rule', 'resource'] as const; + +type FindingsTab = typeof tabs[number]; + +type EuiListItemsProps = NonNullable['listItems']>[number]; -interface CSPTabProps { - data: CSPFinding; +interface Card { + title: string; + listItems: Array<[EuiListItemsProps['title'], EuiListItemsProps['description']]>; } interface FindingFlyoutProps { @@ -35,25 +42,12 @@ interface FindingFlyoutProps { findings: CSPFinding; } +// TODO: fix scrollbar jumps export const FindingsRuleFlyout = ({ onClose, findings }: FindingFlyoutProps) => { - const [tab, setTab] = useState('resource'); - - const Tab = useCallback(() => { - switch (tab) { - case 'overview': - return ; - case 'rule': - return ; - case 'resource': - return ; - } - - assertNever(tab); - }, [findings, tab]); - + const [tab, setTab] = useState('result'); return ( - +

{'Findings'}

@@ -74,120 +68,115 @@ export const FindingsRuleFlyout = ({ onClose, findings }: FindingFlyoutProps) =>
- +
); }; -const getTagsBadges = (v: string[]) => ( - <> - {v.map((x) => ( - {x} +const Cards = ({ data }: { data: Card[] }) => ( + + {data.map((card) => ( + + + ({ title: v[0], description: v[1] }))} + /> + + ))} - + ); -const OverviewTab = ({ data }: CSPTabProps) => ( - - - - - - - - - - - -); +const FindingsTab = ({ tab, findings }: { findings: CSPFinding; tab: FindingsTab }) => { + switch (tab) { + case 'result': + return ; + case 'rule': + return ; + case 'resource': + return ; + } + assertNever(tab); +}; -const RuleTab = ({ data }: CSPTabProps) => ( - - - {data.rule.remediation} }, - ]} - /> - - -); +const getResourceCards = ({ resource, result }: CSPFinding): Card[] => [ + { + title: 'Resource', + listItems: [ + ['Filename', {resource.filename}], + ['Mode', resource.mode], + ['Path', {resource.path}], + ['Type', resource.type], + ['UID', resource.uid], + ['GID', resource.gid], + ], + }, +]; -const ResourceTab = ({ data }: CSPTabProps) => ( - - - {data.resource.filename} }, - { title: 'Mode', description: data.resource.mode }, - { title: 'Path', description: {data.resource.path} }, - { title: 'Type', description: data.resource.type }, - { title: 'UID', description: data.resource.uid }, - { title: 'GID', description: data.resource.gid }, - ]} - /> - - - , - }, - { - title: 'Evidence', - description: {JSON.stringify(data.result.evidence, null, 2)}, - }, - ]} - /> - - -); +const getRuleCards = ({ rule }: CSPFinding): Card[] => [ + { + title: 'Rule', + listItems: [ + ['Benchmark', rule.benchmark], + ['Name', rule.name], + ['Description', rule.description], + ['Remediation', {rule.remediation}], + [ + 'Tags', + rule.tags.map((t) => ( + + {t} + + )), + ], + ], + }, +]; -const TabWrapper: React.FC = ({ children }) => ( -
{children}
-); +const getResultCards = ({ result, agent, host, ...rest }: CSPFinding): Card[] => [ + { + title: 'Result', + listItems: [ + ['Evaluation', ], + ['Evidence', {JSON.stringify(result.evidence, null, 2)}], + ['Timestamp', rest['@timestamp']], + result.evaluation === 'failed' && ['Remediation', rest.rule.remediation], + ].filter(Boolean) as Card['listItems'], // TODO: is a type guard, + }, + { + title: 'Agent', + listItems: [ + ['Name', agent.name], + ['ID', agent.id], + ['Type', agent.type], + ['Version', agent.version], + ], + }, + { + title: 'Host', + listItems: [ + ['Architecture', host.architecture], + ['Containerized', host.containerized ? 'true' : 'false'], + ['Hostname', host.hostname], + ['ID', host.id], + ['IP', host.ip.join(',')], + ['Mac', host.mac.join(',')], + ['Name', host.name], + ], + }, + { + title: 'OS', + listItems: [ + ['Codename', host.os.codename], + ['Family', host.os.family], + ['Kernel', host.os.kernel], + ['Name', host.os.name], + ['Platform', host.os.platform], + ['Type', host.os.type], + ['Version', host.os.version], + ], + }, +];