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

[GEN-2176]: fix "ResizeObserver loop" error in UI #2215

Merged
merged 8 commits into from
Jan 14, 2025
7 changes: 3 additions & 4 deletions frontend/webapp/components/overview/add-entity/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import theme from '@/styles/theme';
import { PlusIcon } from '@/assets';
import { useModalStore } from '@/store';
import { getEntityIcon } from '@/utils';
import { useOnClickOutside } from '@/hooks';
import styled, { css } from 'styled-components';
import { useComputePlatform, useOnClickOutside } from '@/hooks';
import { Button, FadeLoader, Text } from '@/reuseable-components';
import { Button, Text } from '@/reuseable-components';
import { type DropdownOption, OVERVIEW_ENTITY_TYPES } from '@/types';

// Styled components for the dropdown UI
Expand Down Expand Up @@ -72,7 +72,6 @@ interface Props {
}

export const AddEntity: React.FC<Props> = ({ options = DEFAULT_OPTIONS, placeholder = 'ADD...' }) => {
const { loading } = useComputePlatform();
const { currentModal, setCurrentModal } = useModalStore();

const [isDropdownOpen, setIsDropdownOpen] = useState(false);
Expand All @@ -92,7 +91,7 @@ export const AddEntity: React.FC<Props> = ({ options = DEFAULT_OPTIONS, placehol
return (
<Container ref={dropdownRef}>
<StyledButton data-id='add-entity' onClick={handleToggle}>
{loading ? <FadeLoader color={theme.colors.primary} /> : <PlusIcon fill={theme.colors.primary} />}
<PlusIcon fill={theme.colors.primary} />
<ButtonText size={14}>{placeholder}</ButtonText>
</StyledButton>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { type Node } from '@xyflow/react';
import nodeConfig from './node-config.json';
import { type EntityCounts } from './get-entity-counts';
import { type NodePositions } from './get-node-positions';
import { getActionIcon, getEntityIcon, getEntityLabel } from '@/utils';
import { NODE_TYPES, OVERVIEW_ENTITY_TYPES, OVERVIEW_NODE_TYPES, STATUSES, type ComputePlatformMapped } from '@/types';
import { type ActionDataParsed, NODE_TYPES, OVERVIEW_ENTITY_TYPES, OVERVIEW_NODE_TYPES, STATUSES } from '@/types';

interface Params {
loading: boolean;
entities: ComputePlatformMapped['computePlatform']['actions'];
entities: ActionDataParsed[];
positions: NodePositions;
unfilteredCounts: EntityCounts;
unfilteredCount: number;
}

const { nodeWidth, nodeHeight, framePadding } = nodeConfig;
Expand All @@ -29,10 +28,9 @@ const mapToNodeData = (entity: Params['entities'][0]) => {
};
};

export const buildActionNodes = ({ loading, entities, positions, unfilteredCounts }: Params) => {
export const buildActionNodes = ({ loading, entities, positions, unfilteredCount }: Params) => {
const nodes: Node[] = [];
const position = positions[OVERVIEW_ENTITY_TYPES.ACTION];
const unfilteredCount = unfilteredCounts[OVERVIEW_ENTITY_TYPES.ACTION];

nodes.push({
id: 'action-header',
Expand All @@ -45,7 +43,7 @@ export const buildActionNodes = ({ loading, entities, positions, unfilteredCount
nodeWidth,
title: 'Actions',
icon: getEntityIcon(OVERVIEW_ENTITY_TYPES.ACTION),
tagValue: unfilteredCounts[OVERVIEW_ENTITY_TYPES.ACTION],
tagValue: unfilteredCount,
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { type Node } from '@xyflow/react';
import nodeConfig from './node-config.json';
import { type EntityCounts } from './get-entity-counts';
import { type NodePositions } from './get-node-positions';
import { extractMonitors, getEntityIcon, getEntityLabel, getHealthStatus } from '@/utils';
import { NODE_TYPES, OVERVIEW_ENTITY_TYPES, OVERVIEW_NODE_TYPES, STATUSES, type ComputePlatformMapped } from '@/types';
import { type ActualDestination, NODE_TYPES, OVERVIEW_ENTITY_TYPES, OVERVIEW_NODE_TYPES, STATUSES } from '@/types';

interface Params {
loading: boolean;
entities: ComputePlatformMapped['computePlatform']['destinations'];
entities: ActualDestination[];
positions: NodePositions;
unfilteredCounts: EntityCounts;
unfilteredCount: number;
}

const { nodeWidth } = nodeConfig;
Expand All @@ -28,10 +27,9 @@ const mapToNodeData = (entity: Params['entities'][0]) => {
};
};

export const buildDestinationNodes = ({ loading, entities, positions, unfilteredCounts }: Params) => {
export const buildDestinationNodes = ({ loading, entities, positions, unfilteredCount }: Params) => {
const nodes: Node[] = [];
const position = positions[OVERVIEW_ENTITY_TYPES.DESTINATION];
const unfilteredCount = unfilteredCounts[OVERVIEW_ENTITY_TYPES.DESTINATION];

nodes.push({
id: 'destination-header',
Expand All @@ -44,7 +42,7 @@ export const buildDestinationNodes = ({ loading, entities, positions, unfiltered
nodeWidth,
title: 'Destinations',
icon: getEntityIcon(OVERVIEW_ENTITY_TYPES.DESTINATION),
tagValue: unfilteredCounts[OVERVIEW_ENTITY_TYPES.DESTINATION],
tagValue: unfilteredCount,
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { type Node } from '@xyflow/react';
import nodeConfig from './node-config.json';
import { type EntityCounts } from './get-entity-counts';
import { type NodePositions } from './get-node-positions';
import { getEntityIcon, getEntityLabel, getRuleIcon } from '@/utils';
import { NODE_TYPES, OVERVIEW_ENTITY_TYPES, OVERVIEW_NODE_TYPES, STATUSES, type ComputePlatformMapped } from '@/types';
import { type InstrumentationRuleSpecMapped, NODE_TYPES, OVERVIEW_ENTITY_TYPES, OVERVIEW_NODE_TYPES, STATUSES } from '@/types';

interface Params {
loading: boolean;
entities: ComputePlatformMapped['computePlatform']['instrumentationRules'];
entities: InstrumentationRuleSpecMapped[];
positions: NodePositions;
unfilteredCounts: EntityCounts;
unfilteredCount: number;
}

const { nodeWidth } = nodeConfig;
Expand All @@ -28,10 +27,9 @@ const mapToNodeData = (entity: Params['entities'][0]) => {
};
};

export const buildRuleNodes = ({ loading, entities, positions, unfilteredCounts }: Params) => {
export const buildRuleNodes = ({ loading, entities, positions, unfilteredCount }: Params) => {
const nodes: Node[] = [];
const position = positions[OVERVIEW_ENTITY_TYPES.RULE];
const unfilteredCount = unfilteredCounts[OVERVIEW_ENTITY_TYPES.RULE];

nodes.push({
id: 'rule-header',
Expand All @@ -44,7 +42,7 @@ export const buildRuleNodes = ({ loading, entities, positions, unfilteredCounts
nodeWidth,
title: 'Instrumentation Rules',
icon: getEntityIcon(OVERVIEW_ENTITY_TYPES.RULE),
tagValue: unfilteredCounts[OVERVIEW_ENTITY_TYPES.RULE],
tagValue: unfilteredCount,
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { type Node } from '@xyflow/react';
import nodeConfig from './node-config.json';
import { type EntityCounts } from './get-entity-counts';
import { type NodePositions } from './get-node-positions';
import { getMainContainerLanguage } from '@/utils/constants/programming-languages';
import { getEntityIcon, getEntityLabel, getHealthStatus, getProgrammingLanguageIcon } from '@/utils';
Expand All @@ -10,7 +9,7 @@ interface Params {
loading: boolean;
entities: K8sActualSource[];
positions: NodePositions;
unfilteredCounts: EntityCounts;
unfilteredCount: number;
containerHeight: number;
onScroll: (params: { clientHeight: number; scrollHeight: number; scrollTop: number }) => void;
}
Expand All @@ -36,10 +35,9 @@ const mapToNodeData = (entity: Params['entities'][0]) => {
};
};

export const buildSourceNodes = ({ loading, entities, positions, unfilteredCounts, containerHeight, onScroll }: Params) => {
export const buildSourceNodes = ({ loading, entities, positions, unfilteredCount, containerHeight, onScroll }: Params) => {
const nodes: Node[] = [];
const position = positions[OVERVIEW_ENTITY_TYPES.SOURCE];
const unfilteredCount = unfilteredCounts[OVERVIEW_ENTITY_TYPES.SOURCE];

nodes.push({
id: 'source-header',
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@ import { NodeDataFlow } from '@/reuseable-components';
import { MultiSourceControl } from '../multi-source-control';
import { OverviewActionsMenu } from '../overview-actions-menu';
import { type Edge, useEdgesState, useNodesState, type Node, applyNodeChanges } from '@xyflow/react';
import { useComputePlatform, useContainerSize, useMetrics, useNodeDataFlowHandlers, useSourceCRUD } from '@/hooks';
import { useActionCRUD, useContainerSize, useDestinationCRUD, useInstrumentationRuleCRUD, useMetrics, useNodeDataFlowHandlers, useSourceCRUD } from '@/hooks';

import { buildEdges } from './build-edges';
import { getEntityCounts } from './get-entity-counts';
import { getNodePositions } from './get-node-positions';
import { buildRuleNodes } from './build-rule-nodes';
import { buildActionNodes } from './build-action-nodes';
import { buildDestinationNodes } from './build-destination-nodes';
import { buildSourceNodes } from './build-source-nodes';
import nodeConfig from './node-config.json';

export * from './get-entity-counts';
export * from './get-node-positions';
export { nodeConfig };

Expand All @@ -35,61 +33,52 @@ export default function OverviewDataFlowContainer() {
const positions = useMemo(() => getNodePositions({ containerWidth }), [containerWidth]);

const { metrics } = useMetrics();
const { sources, filteredSources } = useSourceCRUD();
const { data, filteredData, loading } = useComputePlatform(); // TODO: remove this in favor of CRUD hooks

const unfilteredCounts = useMemo(
() =>
getEntityCounts({
sources,
destinations: data?.computePlatform.destinations,
actions: data?.computePlatform.actions,
instrumentationRules: data?.computePlatform.instrumentationRules,
}),
[sources, data],
);
const { actions, filteredActions, loading: actLoad } = useActionCRUD();
const { sources, filteredSources, loading: srcLoad } = useSourceCRUD();
const { destinations, filteredDestinations, loading: destLoad } = useDestinationCRUD();
const { instrumentationRules, filteredInstrumentationRules, loading: ruleLoad } = useInstrumentationRuleCRUD();

const ruleNodes = useMemo(
() =>
buildRuleNodes({
loading,
entities: filteredData?.computePlatform.instrumentationRules || [],
loading: ruleLoad,
entities: filteredInstrumentationRules,
unfilteredCount: instrumentationRules.length,
positions,
unfilteredCounts,
}),
[loading, filteredData?.computePlatform.instrumentationRules, positions, unfilteredCounts.rule],
[ruleLoad, instrumentationRules, filteredInstrumentationRules, positions],
);
const actionNodes = useMemo(
() =>
buildActionNodes({
loading,
entities: filteredData?.computePlatform.actions || [],
loading: actLoad,
entities: filteredActions,
unfilteredCount: actions.length,
positions,
unfilteredCounts,
}),
[loading, filteredData?.computePlatform.actions, positions, unfilteredCounts.action],
[actLoad, actions, filteredActions, positions],
);
const destinationNodes = useMemo(
() =>
buildDestinationNodes({
loading,
entities: filteredData?.computePlatform.destinations || [],
loading: destLoad,
entities: filteredDestinations,
unfilteredCount: destinations.length,
positions,
unfilteredCounts,
}),
[loading, filteredData?.computePlatform.destinations, positions, unfilteredCounts.destination],
[destLoad, destinations, filteredDestinations, positions],
);
const sourceNodes = useMemo(
() =>
buildSourceNodes({
loading,
loading: srcLoad,
entities: filteredSources,
unfilteredCount: sources.length,
positions,
unfilteredCounts,
containerHeight,
onScroll: ({ scrollTop }) => setScrollYOffset(scrollTop),
}),
[loading, filteredSources, positions, unfilteredCounts.source, containerHeight],
[srcLoad, sources, filteredSources, positions, containerHeight],
);

const [nodes, setNodes, onNodesChange] = useNodesState(([] as Node[]).concat(actionNodes, ruleNodes, sourceNodes, destinationNodes));
Expand Down Expand Up @@ -122,7 +111,13 @@ export default function OverviewDataFlowContainer() {
<Container ref={containerRef}>
<OverviewActionsMenu />
<MultiSourceControl />
<NodeDataFlow nodes={nodes} edges={edges} onNodeClick={handleNodeClick} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} />
<NodeDataFlow
nodes={nodes}
edges={edges}
onNodeClick={handleNodeClick}
onNodesChange={(changes) => setTimeout(() => onNodesChange(changes))} // Timeout is needed to fix this error: "ResizeObserver loop completed with undelivered notifications."
onEdgesChange={(changes) => setTimeout(() => onEdgesChange(changes))} // Timeout is needed to fix this error: "ResizeObserver loop completed with undelivered notifications."
/>
</Container>
);
}
Loading
Loading