diff --git a/web/src/components/netflow-topology/__tests__/netflow-topology.spec.tsx b/web/src/components/netflow-topology/__tests__/netflow-topology.spec.tsx
index 834985aa5..acf474f09 100644
--- a/web/src/components/netflow-topology/__tests__/netflow-topology.spec.tsx
+++ b/web/src/components/netflow-topology/__tests__/netflow-topology.spec.tsx
@@ -1,7 +1,7 @@
import { EmptyState, EmptyStateBody, Spinner } from '@patternfly/react-core';
import { shallow } from 'enzyme';
import * as React from 'react';
-import { MetricFunction, MetricType, Match } from '../../../model/flow-query';
+import { MetricFunction, MetricType } from '../../../model/flow-query';
import { TopologyMetrics } from '../../../api/loki';
import { DefaultOptions, LayoutName } from '../../../model/topology';
import { defaultTimeRange } from '../../../utils/router';
@@ -14,8 +14,6 @@ describe('', () => {
range: defaultTimeRange,
metricFunction: 'sum' as MetricFunction,
metricType: 'bytes' as MetricType,
- match: 'any' as Match,
- limit: 100,
metrics: [] as TopologyMetrics[],
layout: LayoutName.Cola,
options: DefaultOptions,
diff --git a/web/src/components/netflow-topology/netflow-topology.tsx b/web/src/components/netflow-topology/netflow-topology.tsx
index b5e3e925f..7118d40ff 100644
--- a/web/src/components/netflow-topology/netflow-topology.tsx
+++ b/web/src/components/netflow-topology/netflow-topology.tsx
@@ -16,6 +16,7 @@ import {
defaultControlButtonsOptions,
GraphElement,
Model,
+ Node,
SelectionEventListener,
SELECTION_EVENT,
TopologyControlBar,
@@ -33,7 +34,7 @@ import { saveSvgAsPng } from 'save-svg-as-png';
import { findFilter } from '../../utils/filter-definitions';
import { TopologyMetrics } from '../../api/loki';
import { Filter, FilterDefinition } from '../../model/filters';
-import { Match, MetricFunction, MetricType } from '../../model/flow-query';
+import { MetricFunction, MetricType } from '../../model/flow-query';
import { generateDataModel, LayoutName, TopologyOptions } from '../../model/topology';
import { TimeRange } from '../../utils/datetime';
import { usePrevious } from '../../utils/previous-hook';
@@ -55,8 +56,6 @@ const TopologyContent: React.FC<{
range: number | TimeRange;
metricFunction?: MetricFunction;
metricType?: MetricType;
- match: Match;
- limit: number;
metrics: TopologyMetrics[];
options: TopologyOptions;
layout: LayoutName;
@@ -69,8 +68,6 @@ const TopologyContent: React.FC<{
range,
metricFunction,
metricType,
- match,
- limit,
metrics,
layout,
options,
@@ -86,10 +83,7 @@ const TopologyContent: React.FC<{
const prevLayout = usePrevious(layout);
const prevMetricFunction = usePrevious(metricFunction);
const prevMetricType = usePrevious(metricType);
- const prevMatch = usePrevious(match);
- const prevLimit = usePrevious(limit);
const prevOptions = usePrevious(options);
- const prevFilters = usePrevious(filters);
const [selectedIds, setSelectedIds] = React.useState([]);
const [hoveredId, setHoveredId] = React.useState('');
@@ -284,17 +278,32 @@ const TopologyContent: React.FC<{
highlightedId = selectedIds[0];
}
- const currentModel = controller.toModel();
- const mergedModel = generateDataModel(
- metrics,
- getOptions(),
- searchValue,
- highlightedId,
- filters,
- currentModel.nodes,
- currentModel.edges
- );
- controller.fromModel(mergedModel);
+ const updatedModel = generateDataModel(metrics, getOptions(), searchValue, highlightedId, filters);
+ const allIds = [...(updatedModel.nodes || []), ...(updatedModel.edges || [])].map(item => item.id);
+ controller.getElements().forEach(e => {
+ if (e.getType() !== 'graph') {
+ if (allIds.includes(e.getId())) {
+ //keep previous data
+ switch (e.getType()) {
+ case 'node':
+ const updatedNode = updatedModel.nodes?.find(n => n.id === e.getId());
+ if (updatedNode) {
+ updatedNode.data = { ...e.getData(), ...updatedNode.data };
+ }
+ break;
+ case 'group':
+ const updatedGroup = updatedModel.nodes?.find(n => n.id === e.getId());
+ if (updatedGroup) {
+ updatedGroup.collapsed = (e as Node).isCollapsed();
+ }
+ break;
+ }
+ } else {
+ controller.removeElement(e);
+ }
+ }
+ });
+ controller.fromModel(updatedModel);
}, [controller, hoveredId, selectedIds, metrics, getOptions, searchValue, filters]);
//update model on layout / options / metrics / filters change
@@ -307,38 +316,19 @@ const TopologyContent: React.FC<{
updateModel();
}, [controller, metrics, filters, layout, options, prevLayout, prevOptions, resetGraph, updateModel]);
- //clear existing elements on query change before getting new metrics
+ //clear existing edge tags on query change before getting new metrics
React.useEffect(() => {
- if (prevFilters !== filters || (prevMatch && prevMatch !== match) || (prevLimit && prevLimit > limit)) {
- //remove all elements except graph
- if (controller && controller.hasGraph()) {
+ if (controller && controller.hasGraph()) {
+ if (prevMetricFunction !== metricFunction || prevMetricType !== metricType) {
+ //remove edge tags on metrics change
controller.getElements().forEach(e => {
- if (e.getType() !== 'graph') {
- controller.removeElement(e);
+ if (e.getType() === 'edge') {
+ e.setData({ ...e.getData(), tag: undefined });
}
});
}
- } else if (prevMetricFunction !== metricFunction || prevMetricType !== metricType) {
- //remove edge tags on metrics change
- controller.getElements().forEach(e => {
- if (e.getType() === 'edge') {
- e.setData({ ...e.getData(), tag: undefined });
- }
- });
}
- }, [
- controller,
- filters,
- limit,
- match,
- metricFunction,
- metricType,
- prevFilters,
- prevLimit,
- prevMatch,
- prevMetricFunction,
- prevMetricType
- ]);
+ }, [controller, metricFunction, metricType, prevMetricFunction, prevMetricType]);
//refresh UI selected items
React.useEffect(() => {
@@ -469,8 +459,6 @@ const NetflowTopology: React.FC<{
range: number | TimeRange;
metricFunction?: MetricFunction;
metricType?: MetricType;
- match: Match;
- limit: number;
metrics: TopologyMetrics[];
options: TopologyOptions;
layout: LayoutName;
@@ -485,8 +473,6 @@ const NetflowTopology: React.FC<{
range,
metricFunction,
metricType,
- match,
- limit,
metrics,
layout,
options,
@@ -531,8 +517,6 @@ const NetflowTopology: React.FC<{
range={range}
metricFunction={metricFunction}
metricType={metricType}
- match={match}
- limit={limit}
metrics={metrics}
layout={layout}
options={options}
diff --git a/web/src/components/netflow-traffic.tsx b/web/src/components/netflow-traffic.tsx
index 2c6c13776..cfc00ad7b 100644
--- a/web/src/components/netflow-traffic.tsx
+++ b/web/src/components/netflow-traffic.tsx
@@ -452,8 +452,6 @@ export const NetflowTraffic: React.FC<{
range={range}
metricFunction={metricFunction}
metricType={metricType}
- match={match}
- limit={limit}
metrics={metrics}
layout={layout}
options={topologyOptions}
diff --git a/web/src/model/topology.ts b/web/src/model/topology.ts
index e212c47f2..3df489079 100644
--- a/web/src/model/topology.ts
+++ b/web/src/model/topology.ts
@@ -89,9 +89,7 @@ export const generateNode = (
options: TopologyOptions,
searchValue: string,
highlightedId: string,
- filters: Filter[],
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- previousDatas?: any
+ filters: Filter[]
): NodeModel => {
const id = `${type}.${namespace}.${name}.${addr}`;
const label = name ? name : addr;
@@ -110,8 +108,6 @@ export const generateNode = (
status: NodeStatus.default,
style: { padding: 20 },
data: {
- //keep previous datas between draws like isPinned, setPosition and point
- ...previousDatas,
namespace,
type,
name,
@@ -240,42 +236,14 @@ export const generateDataModel = (
options: TopologyOptions,
searchValue: string,
highlightedId: string,
- filters: Filter[],
- nodes: NodeModel[] = [],
- edges: EdgeModel[] = []
+ filters: Filter[]
): Model => {
+ let nodes: NodeModel[] = [];
+ const edges: EdgeModel[] = [];
const opts = { ...DefaultOptions, ...options };
//ensure each child to have single parent
const childIds: string[] = [];
- //refresh existing items
- nodes = nodes.map(node =>
- node.type === 'group'
- ? //clear group children
- { ...node, children: [] }
- : {
- ...node,
- //update options and filter indicators
- ...generateNode(
- node.data.namespace,
- node.data.type,
- node.data.name,
- node.data.addr,
- node.data.host,
- opts,
- searchValue,
- highlightedId,
- filters,
- node.data
- )
- }
- );
- edges = edges.map(edge => ({
- ...edge,
- //update options and reset counter
- ...generateEdge(edge.source!, edge.target!, 0, opts, edge.data.shadowed, highlightedId)
- }));
-
function addGroup(name: string, type: string, parent?: NodeModel, secondaryLabelPadding = false) {
let group = nodes.find(g => g.type === 'group' && g.data.type === type && g.data.name === name);
if (!group) {