Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion cypress/e2e/NewPolicy.spec.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ describe('Create new policy with form', () => {
cy.byLegacyTestID('review-network-description').should('have.text', testDescription);
cy.contains('button', 'Create network').click();

cy.contains('h1', testPolicyName);
cy.visit('/k8s/cluster/nmstate.io~v1~NodeNetworkConfigurationPolicy');
cy.contains('a', testPolicyName);

deletePolicyFromDetailsPage(testPolicyName);
Comment on lines +52 to 55

@coderabbitai coderabbitai Bot May 14, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Navigate to policy details before calling details-page delete helper.

After visiting the list page, the test only checks the link exists, but then calls deletePolicyFromDetailsPage(...), which expects details-page actions/modal elements. This can break cleanup and fail the test.

Suggested fix
-    cy.visit('/k8s/cluster/nmstate.io~v1~NodeNetworkConfigurationPolicy');
-    cy.contains('a', testPolicyName);
+    cy.visit('/k8s/cluster/nmstate.io~v1~NodeNetworkConfigurationPolicy');
+    cy.contains('a', testPolicyName).should('be.visible').click();

     deletePolicyFromDetailsPage(testPolicyName);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cy.visit('/k8s/cluster/nmstate.io~v1~NodeNetworkConfigurationPolicy');
cy.contains('a', testPolicyName);
deletePolicyFromDetailsPage(testPolicyName);
cy.visit('/k8s/cluster/nmstate.io~v1~NodeNetworkConfigurationPolicy');
cy.contains('a', testPolicyName).should('be.visible').click();
deletePolicyFromDetailsPage(testPolicyName);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cypress/e2e/NewPolicy.spec.cy.ts` around lines 52 - 55, The test visits the
list page and asserts the policy link exists but calls
deletePolicyFromDetailsPage(testPolicyName) which expects to be on the policy
details page; update the flow to navigate into the details view first by
clicking the policy link (use the existing selector cy.contains('a',
testPolicyName) and invoke .click() or an equivalent navigation helper) and wait
for the details page to load before calling
deletePolicyFromDetailsPage(testPolicyName) so the details-page modal/actions
are present.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@pcbailey this needs to be fixed

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

});
Expand Down
3 changes: 3 additions & 0 deletions src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ export const NODE_HOSTNAME_LABEL = 'kubernetes.io/hostname';
export const NO_DATA_DASH = '-';

export const NMSTATE_I18N_NS = 'plugin__nmstate-console-plugin';

export const LINK_AGGREGATION = 'link-aggregation';
export const BASE_IFACE = 'base-iface';
4 changes: 4 additions & 0 deletions src/views/nodenetworkconfiguration/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ export const GROUP = 'group';
export const TOPOLOGY_LOCAL_STORAGE_KEY = 'topologyNodePositions';
export const NODE_POSITIONING_EVENT = 'node-positioned';
export const GRAPH_POSITIONING_EVENT = 'graph-position-change';

export const OVN_K8S_MP0 = 'ovn-k8s-mp0';
export const BR_INT = 'br-int';
export const GENEV_SYS_PREFIX = 'genev_sys_';
21 changes: 15 additions & 6 deletions src/views/nodenetworkconfiguration/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ import {
NodeShape,
NodeStatus,
} from '@patternfly/react-topology';
import { BASE_IFACE, LINK_AGGREGATION } from '@utils/constants';
import { isEmpty } from '@utils/helpers';

import BridgeIcon from '../components/BridgeIcon';

import { GROUP, NODE_DIAMETER } from './constants';
import { BR_INT, GENEV_SYS_PREFIX, GROUP, NODE_DIAMETER, OVN_K8S_MP0 } from './constants';

const statusMap: { [key: string]: NodeStatus } = {
up: NodeStatus.success,
Expand All @@ -27,10 +28,13 @@ const statusMap: { [key: string]: NodeStatus } = {
};

const networkTypeLevelMap = {
[InterfaceType.OVS_INTERFACE]: 1,
[InterfaceType.OVS_BRIDGE]: 2,
[InterfaceType.LINUX_BRIDGE]: 2,
[InterfaceType.VLAN]: 3,
[InterfaceType.BOND]: 4,
[InterfaceType.ETHERNET]: 5,
[InterfaceType.INFINIBAND]: 5,
};

export const networkNodeLevel = new Proxy(networkTypeLevelMap, {
Expand Down Expand Up @@ -58,25 +62,30 @@ const getIcon = (iface: NodeNetworkConfigurationInterface) => {
const createNodes = (
nnsName: string,
interfaces: NodeNetworkConfigurationInterface[],
nnceConfigredInterfaces: NodeNetworkConfigurationInterface[],
nnceConfiguredInterfaces: NodeNetworkConfigurationInterface[],
): NodeModel[] =>
interfaces.map((iface) => {
const isDerivedFromPolicy = findInterfaceByName(nnceConfigredInterfaces, iface.name);
const isDerivedFromPolicy = findInterfaceByName(nnceConfiguredInterfaces, iface.name);
return {
id: `${nnsName}~${iface.name}~${iface.type}`,
type: ModelKind.node,
label: iface.name,
width: NODE_DIAMETER,
height: NODE_DIAMETER,
visible: !iface.patch && iface.type !== InterfaceType.LOOPBACK,
visible:
!iface.patch &&
iface.type !== InterfaceType.LOOPBACK &&
iface.name !== OVN_K8S_MP0 &&
iface.name !== BR_INT &&
!iface.name.startsWith(GENEV_SYS_PREFIX),
shape: isDerivedFromPolicy ? NodeShape.circle : NodeShape.rect,
status: getStatus(iface),
data: {
icon: getIcon(iface),
type: iface.type,
bridgePorts: iface.bridge?.port,
bondPorts: iface['link-aggregation']?.port,
vlanBaseInterface: iface.vlan?.['base-iface'],
bondPorts: iface[LINK_AGGREGATION]?.port,
vlanBaseInterface: iface.vlan?.[BASE_IFACE],
level: networkNodeLevel[iface.type],
isDerivedFromPolicy,
},
Expand Down
8 changes: 6 additions & 2 deletions src/views/policies/list/components/CreatePolicyButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FC } from 'react';
import React, { FC, ReactNode } from 'react';
import { useNavigate } from 'react-router';
import NodeNetworkConfigurationPolicyModel, {
NodeNetworkConfigurationPolicyModelRef,
Expand All @@ -10,7 +10,11 @@ import { useNMStateTranslation } from '@utils/hooks/useNMStateTranslation';
import { NNCP_YAML_EDITOR_OPENED } from '@utils/telemetry/constants';
import { logNMStateEvent } from '@utils/telemetry/telemetry';

const CreatePolicyButtons: FC = ({ children }) => {
type CreatePolicyButtonsProps = {
children: ReactNode;
};

const CreatePolicyButtons: FC<CreatePolicyButtonsProps> = ({ children }) => {
const { t } = useNMStateTranslation();
const navigate = useNavigate();

Expand Down