Skip to content
Draft
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
6 changes: 3 additions & 3 deletions pkg/lib/anaconda/_anaconda.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
--pf-v6-c-page--BackgroundColor: var(--pf-t--global--background--color--primary--default);
}

.pf-v6-c-card {
--pf-v6-c-card--BorderColor: transparent;
}
// .pf-v6-c-card {
// --pf-v6-c-card--BorderColor: transparent;
// }

// Approximates PageSection padding={{ default: "noPadding" }} isFilled={false} (PF .pf-m-no-padding / .pf-m-no-fill)
.pf-v6-c-page__main-section {
Expand Down
5 changes: 5 additions & 0 deletions pkg/networkmanager/anaconda-main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#network-interface {
.pf-v6-c-card.pf-m-plain .pf-v6-c-card__header, .pf-v6-c-card.pf-m-plain > .pf-v6-c-card__title {
padding-block-start: 0;
}
}
122 changes: 122 additions & 0 deletions pkg/networkmanager/anaconda-main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright (C) 2026 Red Hat, Inc.
* SPDX-License-Identifier: LGPL-2.1-or-later
*/

import cockpit from "cockpit";
import React, { useState } from 'react';

import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js";
import { Page, } from "@patternfly/react-core/dist/esm/components/Page/index.js";

import {
has_group,
is_loopback,
is_managed,
is_wireless,
render_active_connection,
} from './interfaces.js';
import { Content, ContentVariants, SimpleList, SimpleListGroup, SimpleListItem, Split, SplitItem } from "@patternfly/react-core";
import { NetworkInterfacePage } from "./network-interface.jsx";
import "./anaconda-main.css";
import { EmptyStatePanel } from "cockpit-components-empty-state.js";

const _ = cockpit.gettext;

interface AnacondaNetworkPageProps {
privileged: boolean;
operationInProgress: boolean;
usage_monitor: any;
interfaces: any[];
iface?: any;
}

interface AnacondaActiveNetwork {
isWireless?: boolean;
iface: any;
}

export const AnacondaNetworkPage = ({ privileged, operationInProgress, usage_monitor, interfaces }: AnacondaNetworkPageProps) => {
const [active, setActive] = useState<AnacondaActiveNetwork>();
Comment on lines +39 to +40

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These 2 added lines are not executed by any test. Details


const managedWired: React.ReactNode[] = [];
const managedWireless: React.ReactNode[] = [];
Comment on lines +42 to +43

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These 2 added lines are not executed by any test. Details


interfaces.forEach(iface => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This added line is not executed by any test. Details

// Skip loopback
if (is_loopback(iface))
return;
Comment on lines +47 to +48

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These 2 added lines are not executed by any test. Details


// Skip members
else if (has_group(iface))
return;
Comment on lines +51 to +52

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These 2 added lines are not executed by any test. Details


const dev = iface.Device;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This added line is not executed by any test. Details


const activeConnection = render_active_connection(dev, false, true);
const isWireless = is_wireless(iface);
Comment on lines +56 to +57

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These 2 added lines are not executed by any test. Details


let connectionStatus;
if (activeConnection) {
connectionStatus = _("Connected")
Comment on lines +59 to +61

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These 3 added lines are not executed by any test. Details

} else {
connectionStatus = _("Disconnected")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This added line is not executed by any test. Details

}

const row = (
<SimpleListItem key={iface.name} onClick={() => {setActive({isWireless, iface})}}>
<Flex
direction={{ default: 'row' }}
justifyContent={{ default: 'justifyContentSpaceBetween' }}
flexWrap={{ default: 'nowrap' }}
Comment on lines +66 to +71

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These 6 added lines are not executed by any test. Details

>
<FlexItem flex={{ default: 'flex_1' }}>{iface.Name}</FlexItem>
<FlexItem>
<Content component={ContentVariants.small}>{connectionStatus}</Content>
</FlexItem>
</Flex>
</SimpleListItem>
)

if (!dev || is_managed(dev)) {
isWireless ? managedWireless.push(row) : managedWired.push(row);
}
});

return (
<Page data-test-wait={operationInProgress} id="networking" className="pf-m-no-sidebar anaconda">
<Content component="h1">{_("Networks")}</Content>
<Split hasGutter>
<SplitItem>
<SimpleList>
{managedWireless.length !== 0 && (
<SimpleListGroup title={_("Wireless")} id="wireless-connections">{...managedWireless}</SimpleListGroup>
)}
{managedWired.length !== 0 && (
<SimpleListGroup title={_("Wired")} id="wired-connections">{...managedWired}</SimpleListGroup>
)}
{(managedWireless.length === 0 && managedWired.length === 0) && (
<SimpleListItem key="not-found">{_("No networks found")}</SimpleListItem>
)}
</SimpleList>
</SplitItem>
<SplitItem isFilled>
{active?.iface ?
<NetworkInterfacePage
privileged={privileged}
operationInProgress={operationInProgress}
usage_monitor={usage_monitor}
plot_state={undefined}
interfaces={interfaces}
iface={active.iface} /> :
<EmptyStatePanel
title={_("No network selected.")}
paragraph={_("Select a network interface to configure the connection.")}
/>
}
</SplitItem>
</Split>

</Page>
);
};
18 changes: 18 additions & 0 deletions pkg/networkmanager/interfaces.js
Original file line number Diff line number Diff line change
Expand Up @@ -2105,6 +2105,24 @@ export function apply_group_member(choices, model, apply_group, group_connection
});
}

export function is_loopback(iface) {
return iface.Name == "lo" || (iface.Device && iface.Device.DeviceType == "loopback");
}

export function has_group(iface) {
return (
(iface.Device &&
iface.Device.ActiveConnection &&
iface.Device.ActiveConnection.Group &&
iface.Device.ActiveConnection.Group.Members.length > 0) ||
(iface.MainConnection && iface.MainConnection.Groups.length > 0)
);
}

export function is_wireless(iface) {
return iface.Device?.DeviceType === '802-11-wireless';
}

export function init() {
cockpit.translate();
}
Loading
Loading