Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UX improvements for correlation engine #561

Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions public/pages/Correlations/Correlations.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@

.correlation_rule_field_condition .euiButtonGroup__buttons {
box-shadow: none;
}

#sa-correlations-network .vis-tooltip {
background-color: #535353;
padding: 0px;
}
34 changes: 29 additions & 5 deletions public/pages/Correlations/components/CorrelationGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,41 @@
*/

import React from 'react';
import Graph from 'react-graph-vis';
import Graph, { Edge, GraphEvents, Network, Node, Options } from 'react-graph-vis';
import 'vis-network/dist/dist/vis-network.min.css';
import { EuiLoadingChart } from '@elastic/eui';

export const CorrelationGraph = ({ graph: { nodes, edges }, options, events }) => {
return (
interface CorrelationGraphProps {
loadingData: boolean;
graph: {
nodes: Node[];
edges: Edge[];
};
options: Options;
events: GraphEvents;
getNetwork: (network: Network) => void;
}

export const CorrelationGraph: React.FC<CorrelationGraphProps> = ({
graph: { nodes, edges },
options,
events,
loadingData,
getNetwork,
}) => {
return loadingData ? (
<div style={{ margin: '75px 47%' }}>
<EuiLoadingChart size="xl" className="chart-view-container-loading" />
</div>
) : (
<Graph
key={`network`}
identifier={`network`}
identifier={`sa-correlations-network`}
graph={{ nodes, edges }}
options={options}
events={events}
style={{ border: '1px solid' }}
style={{ border: '1px solid', backgroundColor: '#ffffff' }}
getNetwork={getNetwork}
/>
);
};
102 changes: 66 additions & 36 deletions public/pages/Correlations/containers/CorrelationsContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import {
defaultSeverityFilterItemOptions,
emptyGraphData,
getAbbrFromLogType,
getLabelFromLogType,
getSeverityColor,
getSeverityLabel,
graphRenderOptions,
} from '../utils/constants';
import {
Expand All @@ -29,6 +31,7 @@ import {
EuiText,
EuiEmptyPrompt,
EuiButton,
EuiBadge,
} from '@elastic/eui';
import { CorrelationsExperimentalBanner } from '../components/ExperimentalBanner';
import { FilterItem, FilterGroup } from '../components/FilterGroup';
Expand All @@ -45,6 +48,8 @@ import { DataStore } from '../../../store/DataStore';
import { FindingItemType } from '../../Findings/containers/Findings/Findings';
import datemath from '@elastic/datemath';
import { ruleSeverity } from '../../Rules/utils/constants';
import { renderToStaticMarkup } from 'react-dom/server';
import { Network } from 'react-graph-vis';

interface CorrelationsProps
extends RouteComponentProps<
Expand All @@ -68,10 +73,13 @@ interface CorrelationsState {
specificFindingInfo?: SpecificFindingCorrelations;
logTypeFilterOptions: FilterItem[];
severityFilterOptions: FilterItem[];
loadingGraphData: boolean;
}

export class Correlations extends React.Component<CorrelationsProps, CorrelationsState> {
static contextType = CoreServicesContext;
private correlationGraphNetwork?: Network;

constructor(props: CorrelationsProps) {
super(props);
this.state = {
Expand All @@ -80,6 +88,7 @@ export class Correlations extends React.Component<CorrelationsProps, Correlation
logTypeFilterOptions: [...defaultLogTypeFilterItemOptions],
severityFilterOptions: [...defaultSeverityFilterItemOptions],
specificFindingInfo: undefined,
loadingGraphData: false,
};
}

Expand Down Expand Up @@ -153,10 +162,12 @@ export class Correlations extends React.Component<CorrelationsProps, Correlation
const end = datemath.parse(this.endTime);
const startTime = start?.valueOf() || Date.now();
const endTime = end?.valueOf() || Date.now();
this.setState({ loadingGraphData: true });
let allCorrelations = await DataStore.correlationsStore.getAllCorrelationsInWindow(
startTime.toString(),
endTime.toString()
);
this.setState({ loadingGraphData: false });
allCorrelations = allCorrelations.filter((corr) => {
return this.shouldShowFinding(corr.finding1) && this.shouldShowFinding(corr.finding2);
});
Expand Down Expand Up @@ -256,6 +267,7 @@ export class Correlations extends React.Component<CorrelationsProps, Correlation
multi: 'html',
size: 12,
},
chosen: true,
});
}

Expand All @@ -264,23 +276,34 @@ export class Correlations extends React.Component<CorrelationsProps, Correlation
from: f1.id,
to: f2.id,
id: `${f1.id}:${f2.id}`,
chosen: false,
});
}

private createNodeTooltip = (finding: CorrelationFinding) => {
const tooltip = document.createElement('div');
private createNodeTooltip = ({ detectionRule, timestamp, logType }: CorrelationFinding) => {
const tooltipContent = (
<div style={{ backgroundColor: '#535353', color: '#ffffff', padding: '8px' }}>
<EuiFlexGroup alignItems="center">
<EuiFlexItem grow={false}>
<EuiBadge color={getSeverityColor(detectionRule.severity)}>
{getSeverityLabel(detectionRule.severity)}
</EuiBadge>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<strong>{getLabelFromLogType(logType)}</strong>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<EuiText>{timestamp}</EuiText>
</div>
);

function createRow(text: string) {
const row = document.createElement('p');
row.innerText = text;
row.style.padding = '5px';
return row;
}
const tooltipContentHTML = renderToStaticMarkup(tooltipContent);

tooltip.appendChild(createRow(`Log type: ${finding.logType}`));
tooltip.appendChild(createRow(finding.timestamp));
const tooltip = document.createElement('div');
tooltip.innerHTML = tooltipContentHTML;

return tooltip;
return tooltip.firstElementChild;
};

private onTimeChange = ({ start, end }: { start: string; end: string }) => {
Expand Down Expand Up @@ -327,6 +350,7 @@ export class Correlations extends React.Component<CorrelationsProps, Correlation
);
this.setState({ specificFindingInfo });
this.updateGraphDataState(specificFindingInfo);
this.correlationGraphNetwork?.selectNodes([id], false);
};

resetFilters = () => {
Expand All @@ -342,6 +366,36 @@ export class Correlations extends React.Component<CorrelationsProps, Correlation
});
};

setNetwork = (network: Network) => {
this.correlationGraphNetwork = network;
};

renderCorrelationsGraph(loadingData: boolean) {
return this.state.graphData.graph.nodes.length > 0 || loadingData ? (
<CorrelationGraph
loadingData={loadingData}
graph={this.state.graphData.graph}
options={{ ...graphRenderOptions }}
events={this.state.graphData.events}
getNetwork={this.setNetwork}
/>
) : (
<EuiEmptyPrompt
title={
<EuiTitle>
<h1>No correlations found</h1>
</EuiTitle>
}
body={<p>There are no correlated findings in the system.</p>}
actions={[
<EuiButton fill={true} color="primary" href={`#${ROUTES.CORRELATION_RULE_CREATE}`}>
Create correlation rule
</EuiButton>,
]}
/>
);
}

render() {
const findingCardsData = this.state.specificFindingInfo;

Expand Down Expand Up @@ -476,31 +530,7 @@ export class Correlations extends React.Component<CorrelationsProps, Correlation
</EuiFlexGroup>

<EuiSpacer />
{this.state.graphData.graph.nodes.length > 0 ? (
<CorrelationGraph
graph={this.state.graphData.graph}
options={{ ...graphRenderOptions }}
events={this.state.graphData.events}
/>
) : (
<EuiEmptyPrompt
title={
<EuiTitle>
<h1>No correlations found</h1>
</EuiTitle>
}
body={<p>There are no correlated findings in the system.</p>}
actions={[
<EuiButton
fill={true}
color="primary"
href={`#${ROUTES.CORRELATION_RULE_CREATE}`}
>
Create correlation rule
</EuiButton>,
]}
/>
)}
{this.renderCorrelationsGraph(this.state.loadingGraphData)}
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
Expand Down
1 change: 1 addition & 0 deletions public/pages/Correlations/utils/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const graphRenderOptions = {
dragNodes: false,
multiselect: true,
tooltipDelay: 50,
hover: true,
},
};

Expand Down