From af8b31d0b7f5a752ad88b9854ff8e521f7204665 Mon Sep 17 00:00:00 2001 From: Michael Olorunnisola Date: Wed, 3 Jun 2020 10:23:02 -0400 Subject: [PATCH] WIP: style changes, renaming --- .../public/resolver/lib/{dates.ts => date.ts} | 0 .../public/resolver/store/data/selectors.ts | 17 +- x-pack/plugins/siem/public/resolver/types.ts | 12 +- .../resolver/view/{defs.tsx => assets.tsx} | 156 ++++++++++++------ .../siem/public/resolver/view/edge_line.tsx | 12 +- .../public/resolver/view/graph_controls.tsx | 4 +- .../siem/public/resolver/view/index.tsx | 6 +- .../resolver/view/process_event_dot.tsx | 44 +++-- .../siem/public/resolver/view/submenu.tsx | 38 +++-- 9 files changed, 194 insertions(+), 95 deletions(-) rename x-pack/plugins/siem/public/resolver/lib/{dates.ts => date.ts} (100%) rename x-pack/plugins/siem/public/resolver/view/{defs.tsx => assets.tsx} (80%) diff --git a/x-pack/plugins/siem/public/resolver/lib/dates.ts b/x-pack/plugins/siem/public/resolver/lib/date.ts similarity index 100% rename from x-pack/plugins/siem/public/resolver/lib/dates.ts rename to x-pack/plugins/siem/public/resolver/lib/date.ts diff --git a/x-pack/plugins/siem/public/resolver/store/data/selectors.ts b/x-pack/plugins/siem/public/resolver/store/data/selectors.ts index b53f56ec8f8aa5a..398f7149ba39684 100644 --- a/x-pack/plugins/siem/public/resolver/store/data/selectors.ts +++ b/x-pack/plugins/siem/public/resolver/store/data/selectors.ts @@ -17,8 +17,9 @@ import { Vector2, RelatedEventData, RelatedEventDataEntryWithStats, + EdgeLineMetadata, } from '../../types'; -import { ResolverEvent } from '../../../../common/endpoint/types'; +import { ResolverEvent, EndpointEvent } from '../../../../common/endpoint/types'; import { eventTimestamp } from '../../../../common/endpoint/models/event'; import { add as vector2Add, applyMatrix3 } from '../../lib/vector2'; import { isGraphableProcess, uniquePidForProcess } from '../../models/process_event'; @@ -29,7 +30,7 @@ import { size, levelOrder, } from '../../models/indexed_process_tree'; -import { getRelativeTimeDifference } from '../../lib/dates'; +import { getRelativeTimeDifference } from '../../lib/date'; const unit = 100; const distanceBetweenNodesInUnits = 2; @@ -157,8 +158,8 @@ function processEdgeLineSegments( positions: ProcessPositions ): EdgeLineSegment[] { const edgeLineSegments: EdgeLineSegment[] = []; - let elapsedTime: string = ''; for (const metadata of levelOrderWithWidths(indexedProcessTree, widths)) { + const edgeLineMetadata: EdgeLineMetadata = {}; /** * We only handle children, drawing lines back to their parents. The root has no parent, so we skip it */ @@ -180,7 +181,7 @@ function processEdgeLineSegments( const parentTime = eventTimestamp(parent); const processTime = eventTimestamp(process); if (parentTime && processTime) { - elapsedTime = getRelativeTimeDifference(parentTime, processTime); + edgeLineMetadata.elapsedTime = getRelativeTimeDifference(parentTime, processTime); } /** @@ -201,7 +202,7 @@ function processEdgeLineSegments( const lineFromProcessToMidwayLine: EdgeLineSegment = [ [position[0], midwayY], position, - elapsedTime, + edgeLineMetadata, ]; const siblings = indexedProcessTreeChildren(indexedProcessTree, parent); @@ -209,7 +210,7 @@ function processEdgeLineSegments( if (metadata.isOnlyChild) { // add a single line segment directly from parent to child. We don't do the 'pitchfork' in this case. - edgeLineSegments.push([parentPosition, position, elapsedTime]); + edgeLineSegments.push([parentPosition, position, edgeLineMetadata]); } else if (isFirstChild) { /** * If the parent has multiple children, we draw the 'midway' line, and the line from the @@ -566,12 +567,12 @@ export const processNodePositionsAndEdgeLineSegments = createSelector( for (const edgeLineSegment of edgeLineSegments) { // const transformedSegment = []; - const [startPoint, endPoint, elapsedTime] = edgeLineSegment; + const [startPoint, endPoint, edgeLineMetadata] = edgeLineSegment; const transformedSegment: EdgeLineSegment = [ applyMatrix3(startPoint, isometricTransformMatrix), applyMatrix3(endPoint, isometricTransformMatrix), - elapsedTime, ]; + if (edgeLineMetadata) transformedSegment.push(edgeLineMetadata); transformedEdgeLineSegments.push(transformedSegment); } diff --git a/x-pack/plugins/siem/public/resolver/types.ts b/x-pack/plugins/siem/public/resolver/types.ts index 27f96e9530591d5..4d1fcc05e7a5981 100644 --- a/x-pack/plugins/siem/public/resolver/types.ts +++ b/x-pack/plugins/siem/public/resolver/types.ts @@ -288,10 +288,18 @@ export type ProcessWidths = Map; * Map of ProcessEvents (representing process nodes) to their positions. Calculated by `processPositions` */ export type ProcessPositions = Map; + +/** + * Values shared between two vertices joined by an edge line. + */ +export interface EdgeLineMetadata { + elapsedTime?: string; +} + /** - * An array of vectors2 forming an polyline. Used to connect process nodes in the graph. + * A tuple of 2 vector2 points and optional EdgeLineMetadata forming a polyline. Used to connect process nodes in the graph and display relevant information. */ -export type EdgeLineSegment = [Vector2, Vector2, string?]; +export type EdgeLineSegment = [Vector2, Vector2, EdgeLineMetadata?]; /** * Used to provide precalculated info from `widthsOfProcessSubtrees`. These 'width' values are used in the layout of the graph. diff --git a/x-pack/plugins/siem/public/resolver/view/defs.tsx b/x-pack/plugins/siem/public/resolver/view/assets.tsx similarity index 80% rename from x-pack/plugins/siem/public/resolver/view/defs.tsx rename to x-pack/plugins/siem/public/resolver/view/assets.tsx index 29f4d43168c0b25..5c92253c74eaa1e 100644 --- a/x-pack/plugins/siem/public/resolver/view/defs.tsx +++ b/x-pack/plugins/siem/public/resolver/view/assets.tsx @@ -24,6 +24,7 @@ type ResolverColorNames = type ColorMap = Record; interface NodeStyleConfig { + backingFill: string; cubeSymbol: string; descriptionFill: string; descriptionText: string; @@ -54,32 +55,9 @@ export const PaintServerIds = { * PaintServers: Where color palettes, grandients, patterns and other similar concerns * are exposed to the component */ -const PaintServers = memo(() => ( + +const PaintServers = memo(({ isDarkMode }: { isDarkMode: boolean }) => ( <> - - - - - - - - ( + {isDarkMode ? ( + <> + + + + + + + + + + ) : ( + <> + + + + + + + + + + )} )); @@ -124,7 +155,7 @@ export const SymbolIds = { /** * Defs entries that define shapes, masks and other spatial elements */ -const SymbolsAndShapes = memo(() => ( +const SymbolsAndShapes = memo(({ isDarkMode }: { isDarkMode: boolean }) => ( <> ( {'Terminated Trigger Process'} - + {isDarkMode && ( + + )} + {!isDarkMode && ( + + )} ( {'resolver active backing'} @@ -340,14 +383,17 @@ SymbolsAndShapes.displayName = 'SymbolsAndShapes'; * 2. Separation of concerns between creative assets and more functional areas of the app * 3. `` elements can be handled by compositor (faster) */ -const SymbolDefinitionsComponent = memo(({ className }: { className?: string }) => ( - - - - - - -)); +const SymbolDefinitionsComponent = memo(({ className }: { className?: string }) => { + const isDarkMode = useUiSetting(DEFAULT_DARK_MODE); + return ( + + + + + + + ); +}); SymbolDefinitionsComponent.displayName = 'SymbolDefinitions'; @@ -363,7 +409,7 @@ export const useResolverTheme = (): { colorMap: ColorMap; nodeAssets: NodeStyleM const isDarkMode = useUiSetting(DEFAULT_DARK_MODE); const theme = isDarkMode ? euiThemeAmsterdamDark : euiThemeAmsterdamLight; - const getColor = (lightOption: string, darkOption: string): string => { + const getThemedOption = (lightOption: string, darkOption: string): string => { return isDarkMode ? darkOption : lightOption; }; @@ -372,13 +418,16 @@ export const useResolverTheme = (): { colorMap: ColorMap; nodeAssets: NodeStyleM full: theme.euiColorFullShade, graphControls: theme.euiColorDarkestShade, graphControlsBackground: theme.euiColorEmptyShade, + processBackingFill: theme.euiColorPrimary, resolverBackground: theme.euiColorEmptyShade, - resolverEdge: getColor(theme.euiColorLightestShade, theme.euiColorDarkestShade), - resolverEdgeText: getColor(theme.euiColorDarkShade, theme.euiColorLightShade), + resolverEdge: getThemedOption(theme.euiColorLightestShade, theme.euiColorLightShade), + resolverEdgeText: getThemedOption(theme.euiColorDarkShade, theme.euiColorFullShade), + triggerBackingFill: theme.euiColorDanger, }; - const nodeAssets = { + const nodeAssets: NodeStyleMap = { runningProcessCube: { + backingFill: colorMap.processBackingFill, cubeSymbol: `#${SymbolIds.runningProcessCube}`, descriptionFill: colorMap.descriptionText, descriptionText: i18n.translate('xpack.siem.endpoint.resolver.runningProcess', { @@ -388,6 +437,7 @@ export const useResolverTheme = (): { colorMap: ColorMap; nodeAssets: NodeStyleM labelButtonFill: 'primary', }, runningTriggerCube: { + backingFill: colorMap.triggerBackingFill, cubeSymbol: `#${SymbolIds.runningTriggerCube}`, descriptionFill: colorMap.descriptionText, descriptionText: i18n.translate('xpack.siem.endpoint.resolver.runningTrigger', { @@ -397,6 +447,7 @@ export const useResolverTheme = (): { colorMap: ColorMap; nodeAssets: NodeStyleM labelButtonFill: 'danger', }, terminatedProcessCube: { + backingFill: colorMap.processBackingFill, cubeSymbol: `#${SymbolIds.terminatedProcessCube}`, descriptionFill: colorMap.descriptionText, descriptionText: i18n.translate('xpack.siem.endpoint.resolver.terminatedProcess', { @@ -406,6 +457,7 @@ export const useResolverTheme = (): { colorMap: ColorMap; nodeAssets: NodeStyleM labelButtonFill: 'primary', }, terminatedTriggerCube: { + backingFill: colorMap.triggerBackingFill, cubeSymbol: `#${SymbolIds.terminatedTriggerCube}`, descriptionFill: colorMap.descriptionText, descriptionText: i18n.translate('xpack.siem.endpoint.resolver.terminatedTrigger', { diff --git a/x-pack/plugins/siem/public/resolver/view/edge_line.tsx b/x-pack/plugins/siem/public/resolver/view/edge_line.tsx index dc84707002c3ab3..c8e77e7351bc1a8 100644 --- a/x-pack/plugins/siem/public/resolver/view/edge_line.tsx +++ b/x-pack/plugins/siem/public/resolver/view/edge_line.tsx @@ -7,8 +7,8 @@ import React from 'react'; import styled from 'styled-components'; import { applyMatrix3, distance, angle } from '../lib/vector2'; -import { Vector2, Matrix3 } from '../types'; -import { useResolverTheme } from './defs'; +import { Vector2, Matrix3, EdgeLineMetadata } from '../types'; +import { useResolverTheme } from './assets'; interface ElapsedTimeProps { readonly scaledTypeSize: number; @@ -36,7 +36,7 @@ const StyledElapsedTime = styled.div` const EdgeLineComponent = React.memo( ({ className, - elapsedTime, + edgeLineMetadata, startPosition, endPosition, projectionMatrix, @@ -48,7 +48,7 @@ const EdgeLineComponent = React.memo( /** * Time elapsed betweeen process nodes */ - elapsedTime?: string; + edgeLineMetadata?: EdgeLineMetadata; /** * The postion of first point in the line segment. In 'world' coordinates. */ @@ -70,6 +70,7 @@ const EdgeLineComponent = React.memo( const screenEnd = applyMatrix3(endPosition, projectionMatrix); const [magFactorX] = projectionMatrix; const { colorMap } = useResolverTheme(); + const elapsedTime = edgeLineMetadata?.elapsedTime; /** * We render the line using a short, long, `div` element. The length of this `div` @@ -98,10 +99,11 @@ const EdgeLineComponent = React.memo( */ transform: `translateY(-50%) rotateZ(${angle(screenStart, screenEnd)}rad)`, }; + const showElapsedTime = elapsedTime && magFactorX >= 0.75 && magFactorX <= 2.25; return (
- {elapsedTime && ( + {showElapsedTime && ( - {edgeLineSegments.map(([startPosition, endPosition, elapsedTime], index) => ( + {edgeLineSegments.map(([startPosition, endPosition, edgeLineMetadata], index) => ( htmlIdGenerator('resolverNode'), []); @@ -405,6 +407,7 @@ const ProcessEventDotComponents = React.memo( @@ -459,7 +462,7 @@ const ProcessEventDotComponents = React.memo( lineHeight: '1', fontWeight: 'bold', fontSize: '0.8rem', - width: '100%', + width: 'fit-content', margin: '0', textAlign: 'left', padding: '0', @@ -468,18 +471,26 @@ const ProcessEventDotComponents = React.memo( > {descriptionText}
- + {eventModel.eventName(event)} - {magFactorX >= 2 && ( + {magFactorX >= 1.3 && ( @@ -525,16 +537,24 @@ export const ProcessEventDot = styled(ProcessEventDotComponents)` & .backing { stroke-dasharray: 500; stroke-dashoffset: 500; + fill-opacity: 0; + } + &:hover:not([aria-current]) .backing { + transition-property: fill-opacity; + transition-duration: 0.25s; + fill-opacity: 0.06; } + &[aria-current] .backing { transition-property: stroke-dashoffset; transition-duration: 1s; stroke-dashoffset: 0; } - & .related-dropdown { - width: 4.5em; + & .euiButton { + width: fit-content; } + & .euiSelectableList-bordered { border-top-right-radius: 0px; border-top-left-radius: 0px; diff --git a/x-pack/plugins/siem/public/resolver/view/submenu.tsx b/x-pack/plugins/siem/public/resolver/view/submenu.tsx index f3dfb1dd70cc93f..725db138cdf5357 100644 --- a/x-pack/plugins/siem/public/resolver/view/submenu.tsx +++ b/x-pack/plugins/siem/public/resolver/view/submenu.tsx @@ -41,6 +41,10 @@ interface ResolverSubmenuOption { export type ResolverSubmenuOptionList = ResolverSubmenuOption[] | string; +const OptionListItem = styled.div` + width: 175px; +`; + const OptionList = React.memo( ({ subMenuOptions, @@ -78,7 +82,7 @@ const OptionList = React.memo( listProps={{ showIcons: true, bordered: true }} isLoading={isLoading} > - {(list) => list} + {(list) => {list}} ), [isLoading, options] @@ -95,7 +99,7 @@ OptionList.displayName = 'OptionList'; */ const NodeSubMenuComponents = React.memo( ({ - buttonColor, + buttonBorderColor, menuTitle, menuAction, optionsWithActions, @@ -104,7 +108,8 @@ const NodeSubMenuComponents = React.memo( menuTitle: string; className?: string; menuAction: () => unknown; - buttonColor: ButtonColor; + buttonBorderColor: ButtonColor; + buttonFill: string; } & { optionsWithActions?: ResolverSubmenuOptionList | string | undefined; }) => { @@ -140,7 +145,12 @@ const NodeSubMenuComponents = React.memo( */ return (
- + {menuTitle}
@@ -156,7 +166,7 @@ const NodeSubMenuComponents = React.memo( onClick={ typeof optionsWithActions === 'object' ? handleMenuOpenClick : handleMenuActionClick } - color={buttonColor} + color={buttonBorderColor} size="s" iconType={menuIsOpen ? 'arrowUp' : 'arrowDown'} iconSide="right" @@ -193,17 +203,23 @@ export const NodeSubMenu = styled(NodeSubMenuComponents)` display: flex; flex-flow: column; - .euiButton { - background-color: transparent; - border-color: ${(props) => props.buttonColor}; + & .euiButton { + background-color: ${(props) => props.buttonFill}; + border-color: ${(props) => props.buttonBorderColor}; border-style: solid; border-width: 1px; - width: 100%; + + &:hover, + &:active, + &:focus { + background-color: ${(props) => props.buttonFill}; + } } - .euiPopover__anchor { + & .euiPopover__anchor { display: flex; - width: 100%; + } + } &.is-open .euiButton {