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

[Cloud Security] Added graph visualization in alert's flyout #196034

Merged
merged 45 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
977874c
Created Graph component
kfirpeled Oct 13, 2024
8456abf
Ensure target has an id
kfirpeled Oct 13, 2024
2203f65
Added graph preview to alerts flyout
kfirpeled Oct 13, 2024
431e59f
Hides react flow attribution
kfirpeled Oct 13, 2024
c97c18c
Added cloud security storybook to kibana's storybook website
kfirpeled Oct 13, 2024
f856800
Experimental feature disabled by default
kfirpeled Oct 13, 2024
edebaf6
fixed unknown target's label
kfirpeled Oct 13, 2024
ff920d6
code cleanup
kfirpeled Oct 13, 2024
832ddf4
Disable controls, dragging and zoom when in preview
kfirpeled Oct 13, 2024
bc189ee
Removed panel's
kfirpeled Oct 13, 2024
94c22d4
Enhanced experience
kfirpeled Oct 13, 2024
47dc47a
Merge branch 'main' into cspm/cdr-alerts-flyout2
kfirpeled Oct 15, 2024
8876474
Refactor cloud-security-posture storybook folder structure
kfirpeled Oct 15, 2024
6545761
Refactored graph data types
kfirpeled Oct 15, 2024
652652e
Renamed stories
kfirpeled Oct 15, 2024
8d0d79a
Added FTR test that check it is being rendered
kfirpeled Oct 15, 2024
81bc3d2
Refactoring
kfirpeled Oct 15, 2024
e8f03b0
Fixed API type, removing redundant properties. Fixed dragging that st…
kfirpeled Oct 15, 2024
11f1565
[CI] Auto-commit changed files from 'node scripts/generate codeowners'
kibanamachine Oct 15, 2024
e06bbdf
[CI] Auto-commit changed files from 'node scripts/notice'
kibanamachine Oct 15, 2024
e8597da
Added graph UT
kfirpeled Oct 15, 2024
eeddc65
Updated readme
kfirpeled Oct 15, 2024
e1cfbe8
skipped failing test
kfirpeled Oct 15, 2024
e70e48e
Fixed behaviour when changing focus using tab
kfirpeled Oct 15, 2024
63329eb
Build fixes
kfirpeled Oct 15, 2024
1151e7b
Jest fix
kfirpeled Oct 15, 2024
d54c371
Merge branch 'main' into cspm/cdr-alerts-flyout2
kfirpeled Oct 15, 2024
85c75ba
[CI] Auto-commit changed files from 'node scripts/notice'
kibanamachine Oct 15, 2024
78b1f99
[CI] Auto-commit changed files from 'node scripts/yarn_deduplicate'
kibanamachine Oct 15, 2024
33c7ce6
Revert changes tsconfig.json
kfirpeled Oct 15, 2024
16de019
Fixed graph interactivity
kfirpeled Oct 16, 2024
7952ce7
Code review fixes
kfirpeled Oct 16, 2024
48f3d88
fixed UT
kfirpeled Oct 16, 2024
e2db7c9
import fix
kfirpeled Oct 16, 2024
9a7d02e
Lazy loading graph component
kfirpeled Oct 16, 2024
7eb5c49
[CI] Auto-commit changed files from 'node scripts/notice'
kibanamachine Oct 16, 2024
7ce77b2
Merge branch 'main' into cspm/cdr-alerts-flyout2
kfirpeled Oct 17, 2024
04c2c8b
Refactoring, auto fitview on resize when not interactive.
kfirpeled Oct 17, 2024
9b3dc3c
webpack refactoring - usage of babel preset
kfirpeled Oct 18, 2024
e4e07c6
Removed packaging of storybook config
kfirpeled Oct 18, 2024
049b4c0
Merge branch 'main' into cspm/cdr-alerts-flyout2
kfirpeled Oct 21, 2024
0c0594d
Enhancing graph behavior in preview - max zoom is set to 1.3
kfirpeled Oct 22, 2024
9aa0863
Memorizing graph's data
kfirpeled Oct 25, 2024
2a0b590
Merge branch 'main' into cspm/cdr-alerts-flyout2
kfirpeled Oct 25, 2024
db07ec1
refactored shapes
kfirpeled Oct 25, 2024
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
17 changes: 9 additions & 8 deletions .buildkite/scripts/steps/storybooks/build_and_upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,42 +18,43 @@ const STORYBOOKS = [
'canvas',
'cases',
'cell_actions',
'coloring',
'chart_icons',
'cloud_security_posture_packages',
'coloring',
'content_management_examples',
'custom_integrations',
'dashboard_enhanced',
'dashboard',
'data',
'logs_explorer',
'embeddable',
'esql_editor',
'expression_error',
'expression_image',
'expression_metric',
'expression_repeat_image',
'expression_reveal_image',
'expression_shape',
'expression_tagcloud',
'management',
'fleet',
'grouping',
'home',
'infra',
'kibana_react',
'language_documentation_popover',
'lists',
'observability',
'logs_explorer',
'management',
'observability_ai_assistant',
'observability',
'presentation',
'security_solution',
'random_sampling',
'security_solution_packages',
'security_solution',
'serverless',
'shared_ux',
'triggers_actions_ui',
'ui_actions_enhanced',
'language_documentation_popover',
'unified_search',
'random_sampling',
'esql_editor',
];

const GITHUB_CONTEXT = 'Build and Publish Storybooks';
Expand Down
23 changes: 23 additions & 0 deletions packages/kbn-optimizer/src/worker/webpack.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,29 @@ export function getWebpackConfig(
},
},
},
{
test: /\.js$/,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

required when using @kbn/cloud-security-posture-graph which depends on dagrejs and xyflow packages

include: /node_modules[\\\/]@dagrejs/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-proposal-class-properties'],
},
},
},
{
test: /node_modules[\/\\]@?xyflow[\/\\].*.js$/,
loaders: 'babel-loader',
options: {
presets: [['@babel/preset-env', { modules: false }], '@babel/preset-react'],
plugins: [
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-proposal-nullish-coalescing-operator',
'@babel/plugin-transform-logical-assignment-operators',
],
},
},
{
test: /\.(html|md|txt|tmpl)$/,
use: {
Expand Down
2 changes: 2 additions & 0 deletions x-pack/packages/kbn-cloud-security-posture/graph/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

export * from './src/components';
Original file line number Diff line number Diff line change
Expand Up @@ -7,59 +7,21 @@

import React from 'react';
import { ThemeProvider } from '@emotion/react';
import {
ReactFlow,
Controls,
Background,
Node,
Edge,
Position,
useNodesState,
useEdgesState,
} from '@xyflow/react';
import { Story } from '@storybook/react';
import type {
EdgeDataModel,
LabelNodeDataModel,
NodeDataModel,
} from '@kbn/cloud-security-posture-common/types/graph/latest';
import { Writable } from '@kbn/utility-types';
import {
HexagonNode,
PentagonNode,
EllipseNode,
RectangleNode,
DiamondNode,
LabelNode,
EdgeGroupNode,
} from './node';
import type { NodeViewModel } from './types';
import { DefaultEdge } from './edge';
import { SvgDefsMarker } from './edge/styles';
import { GroupStyleOverride } from './node/styles';

import '@xyflow/react/dist/style.css';
import { layoutGraph } from './graph/layout_graph';
import { css } from '@emotion/react';
import { Graph } from './graph/graph';

export default {
title: 'Components/Graph Components/Dagree Layout Graph',
description: 'CDR - Graph visualization',
};

const nodeTypes = {
hexagon: HexagonNode,
pentagon: PentagonNode,
ellipse: EllipseNode,
rectangle: RectangleNode,
diamond: DiamondNode,
label: LabelNode,
group: EdgeGroupNode,
};

const edgeTypes = {
default: DefaultEdge,
};

interface GraphData {
nodes: NodeDataModel[];
edges: EdgeDataModel[];
Expand Down Expand Up @@ -189,28 +151,18 @@ const extractEdges = (
return { nodes: Object.values(nodes).reverse(), edges };
};

const Template: Story<GraphData> = ({ nodes, edges }: GraphData) => {
const { initialNodes, initialEdges } = processGraph(nodes, edges);

const [nodesState, _setNodes, onNodesChange] = useNodesState(initialNodes);
const [edgesState, _setEdges, onEdgesChange] = useEdgesState(initialEdges);

const Template: Story<GraphData> = ({ nodes, edges, interactive }: GraphData) => {
return (
<ThemeProvider theme={{ darkMode: false }}>
<SvgDefsMarker />
<ReactFlow
fitView
attributionPosition={undefined}
nodeTypes={nodeTypes}
edgeTypes={edgeTypes}
nodes={nodesState}
edges={edgesState}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
>
<Controls />
<Background />
</ReactFlow>
<Graph
css={css`
height: 100%;
width: 100%;
`}
nodes={nodes}
edges={edges}
interactive={interactive ?? true}
/>
</ThemeProvider>
);
};
Expand Down Expand Up @@ -359,7 +311,7 @@ GroupWithWarningAPIMock.args = {
],
};

export const Graph = Template.bind({});
export const LargeGraph = Template.bind({});
const baseGraph: NodeDataModel[] = [
{
id: 'siem-windows',
Expand Down Expand Up @@ -483,7 +435,7 @@ const baseGraph: NodeDataModel[] = [
},
];

Graph.args = {
LargeGraph.args = {
...extractEdges(baseGraph),
};

Expand Down Expand Up @@ -541,67 +493,3 @@ GraphStackedEdgeCases.args = {
},
]),
};

function processGraph(
nodesModel: NodeDataModel[],
edgesModel: EdgeDataModel[]
): {
initialNodes: Node[];
initialEdges: Edge[];
} {
const { nodes: nodesViewModel } = layoutGraph(nodesModel, edgesModel);

const nodesById: { [key: string]: NodeViewModel } = {};

const initialNodes = nodesViewModel.map((nodeData) => {
nodesById[nodeData.id] = nodeData;

const node: Node = {
id: nodeData.id,
type: nodeData.shape,
data: { ...nodeData, interactive: true },
position: nodeData.position,
draggable: true,
};

if (node.type === 'group' && nodeData.shape === 'group') {
node.sourcePosition = Position.Right;
node.targetPosition = Position.Left;
node.resizing = false;
node.style = GroupStyleOverride({
width: nodeData.size?.width ?? 0,
height: nodeData.size?.height ?? 0,
});
} else if (nodeData.shape === 'label' && nodeData.parentId) {
node.parentId = nodeData.parentId;
node.extent = 'parent';
node.expandParent = false;
node.draggable = false;
}

return node;
});

const initialEdges: Edge[] = edgesModel.map((edgeData) => {
const isIn =
nodesById[edgeData.source].shape !== 'label' && nodesById[edgeData.target].shape === 'group';
const isInside =
nodesById[edgeData.source].shape === 'group' && nodesById[edgeData.target].shape === 'label';
const isOut =
nodesById[edgeData.source].shape === 'label' && nodesById[edgeData.target].shape === 'group';
const isOutside =
nodesById[edgeData.source].shape === 'group' && nodesById[edgeData.target].shape !== 'label';

return {
id: edgeData.id,
type: 'default',
source: edgeData.source,
sourceHandle: isInside ? 'inside' : isOutside ? 'outside' : undefined,
target: edgeData.target,
targetHandle: isIn ? 'in' : isOut ? 'out' : undefined,
data: { ...edgeData },
};
});

return { initialNodes, initialEdges };
}
Loading