LCOV - code coverage report
Current view: top level - lcov - github-pr.diff Coverage Total Hit
Test: cockpit Lines: 63.5 % 189 120
Test Date: 2026-08-05 13:21:05

            Line data    Source code
       1              : diff --git a/pkg/lib/anaconda/_anaconda.scss b/pkg/lib/anaconda/_anaconda.scss
       2              : index 06b99354f..0e4bb8768 100644
       3              : --- a/pkg/lib/anaconda/_anaconda.scss
       4              : +++ b/pkg/lib/anaconda/_anaconda.scss
       5              : @@ -30,9 +30,9 @@
       6              :      --pf-v6-c-page--BackgroundColor: var(--pf-t--global--background--color--primary--default);
       7              :    }
       8              :  
       9              : -  .pf-v6-c-card {
      10              : -    --pf-v6-c-card--BorderColor: transparent;
      11              : -  }
      12              : +  // .pf-v6-c-card {
      13              : +    // --pf-v6-c-card--BorderColor: transparent;
      14              : +  // }
      15              :  
      16              :    // Approximates PageSection padding={{ default: "noPadding" }} isFilled={false} (PF .pf-m-no-padding / .pf-m-no-fill)
      17              :    .pf-v6-c-page__main-section {
      18              : diff --git a/pkg/networkmanager/anaconda-main.css b/pkg/networkmanager/anaconda-main.css
      19              : new file mode 100644
      20              : index 000000000..b32fa5fa5
      21              : --- /dev/null
      22              : +++ b/pkg/networkmanager/anaconda-main.css
      23              : @@ -0,0 +1,5 @@
      24              : +#network-interface {
      25              : +  .pf-v6-c-card.pf-m-plain .pf-v6-c-card__header, .pf-v6-c-card.pf-m-plain > .pf-v6-c-card__title {
      26              : +    padding-block-start: 0;
      27              : +  }
      28              : +}
      29              : diff --git a/pkg/networkmanager/anaconda-main.tsx b/pkg/networkmanager/anaconda-main.tsx
      30              : new file mode 100644
      31              : index 000000000..a8876d3cb
      32              : --- /dev/null
      33              : +++ b/pkg/networkmanager/anaconda-main.tsx
      34              : @@ -0,0 +1,122 @@
      35              : +/*
      36              : + * Copyright (C) 2026 Red Hat, Inc.
      37              : + * SPDX-License-Identifier: LGPL-2.1-or-later
      38              : + */
      39              : +
      40           37 : +import cockpit from "cockpit";
      41           37 : +import React, { useState } from 'react';
      42              : +
      43              : +import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js";
      44              : +import { Page, } from "@patternfly/react-core/dist/esm/components/Page/index.js";
      45              : +
      46              : +import {
      47              : +    has_group,
      48              : +    is_loopback,
      49              : +    is_managed,
      50              : +    is_wireless,
      51              : +    render_active_connection,
      52              : +} from './interfaces.js';
      53              : +import { Content, ContentVariants, SimpleList, SimpleListGroup, SimpleListItem, Split, SplitItem } from "@patternfly/react-core";
      54              : +import { NetworkInterfacePage } from "./network-interface.jsx";
      55              : +import "./anaconda-main.css";
      56              : +import { EmptyStatePanel } from "cockpit-components-empty-state.js";
      57              : +
      58           37 : +const _ = cockpit.gettext;
      59              : +
      60              : +interface AnacondaNetworkPageProps {
      61              : +    privileged: boolean;
      62              : +    operationInProgress: boolean;
      63              : +    usage_monitor: any;
      64              : +    interfaces: any[];
      65              : +    iface?: any;
      66              : +}
      67              : +
      68              : +interface AnacondaActiveNetwork {
      69              : +    isWireless?: boolean;
      70              : +    iface: any;
      71              : +}
      72              : +
      73            0 : +export const AnacondaNetworkPage = ({ privileged, operationInProgress, usage_monitor, interfaces }: AnacondaNetworkPageProps) => {
      74            0 : +    const [active, setActive] = useState<AnacondaActiveNetwork>();
      75              : +
      76            0 : +    const managedWired: React.ReactNode[] = [];
      77            0 : +    const managedWireless: React.ReactNode[] = [];
      78              : +
      79            0 : +    interfaces.forEach(iface => {
      80              : +        // Skip loopback
      81            0 : +        if (is_loopback(iface))
      82            0 : +            return;
      83              : +
      84              : +        // Skip members
      85            0 : +        else if (has_group(iface))
      86            0 : +            return;
      87              : +
      88            0 : +        const dev = iface.Device;
      89              : +
      90            0 : +        const activeConnection = render_active_connection(dev, false, true);
      91            0 : +        const isWireless = is_wireless(iface);
      92              : +
      93            0 : +        let connectionStatus;
      94            0 : +        if (activeConnection) {
      95            0 : +            connectionStatus = _("Connected")
      96            0 : +        } else {
      97            0 : +            connectionStatus = _("Disconnected")
      98            0 : +        }
      99              : +
     100            0 : +        const row = (
     101            0 : +            <SimpleListItem key={iface.name} onClick={() => {setActive({isWireless, iface})}}>
     102            0 : +                <Flex
     103            0 : +                    direction={{ default: 'row' }}
     104            0 : +                    justifyContent={{ default: 'justifyContentSpaceBetween' }}
     105            0 : +                    flexWrap={{ default: 'nowrap' }}
     106              : +                >
     107            0 : +                    <FlexItem flex={{ default: 'flex_1' }}>{iface.Name}</FlexItem>
     108            0 : +                    <FlexItem>
     109            0 : +                        <Content component={ContentVariants.small}>{connectionStatus}</Content>
     110            0 : +                    </FlexItem>
     111            0 : +                </Flex>
     112            0 : +            </SimpleListItem>
     113              : +        )
     114              : +
     115            0 : +        if (!dev || is_managed(dev)) {
     116            0 : +            isWireless ? managedWireless.push(row) : managedWired.push(row);
     117            0 : +        }
     118            0 : +    });
     119              : +
     120            0 : +    return (
     121            0 : +        <Page data-test-wait={operationInProgress} id="networking" className="pf-m-no-sidebar anaconda">
     122            0 : +            <Content component="h1">{_("Networks")}</Content>
     123            0 : +            <Split hasGutter>
     124            0 : +                <SplitItem>
     125            0 : +                    <SimpleList>
     126            0 : +                        {managedWireless.length !== 0 && (
     127            0 : +                            <SimpleListGroup title={_("Wireless")} id="wireless-connections">{...managedWireless}</SimpleListGroup>
     128              : +                        )}
     129            0 : +                        {managedWired.length !== 0 && (
     130            0 : +                            <SimpleListGroup title={_("Wired")} id="wired-connections">{...managedWired}</SimpleListGroup>
     131              : +                        )}
     132            0 : +                        {(managedWireless.length === 0 && managedWired.length === 0) && (
     133            0 : +                            <SimpleListItem key="not-found">{_("No networks found")}</SimpleListItem>
     134              : +                        )}
     135            0 : +                    </SimpleList>
     136            0 : +                </SplitItem>
     137            0 : +                <SplitItem isFilled>
     138            0 : +                    {active?.iface ?
     139            0 : +                        <NetworkInterfacePage
     140            0 : +                            privileged={privileged}
     141            0 : +                            operationInProgress={operationInProgress}
     142            0 : +                            usage_monitor={usage_monitor}
     143            0 : +                            plot_state={undefined}
     144            0 : +                            interfaces={interfaces}
     145            0 : +                            iface={active.iface} /> :
     146            0 : +                        <EmptyStatePanel
     147            0 : +                            title={_("No network selected.")}
     148            0 : +                            paragraph={_("Select a network interface to configure the connection.")}
     149            0 : +                        />
     150              : +                    }
     151            0 : +                </SplitItem>
     152            0 : +            </Split>
     153              : +
     154            0 : +        </Page>
     155              : +    );
     156            0 : +};
     157              : diff --git a/pkg/networkmanager/interfaces.js b/pkg/networkmanager/interfaces.js
     158              : index 73f641f41..72045084d 100644
     159              : --- a/pkg/networkmanager/interfaces.js
     160              : +++ b/pkg/networkmanager/interfaces.js
     161              : @@ -2105,6 +2105,24 @@ export function apply_group_member(choices, model, apply_group, group_connection
     162              :      });
     163              :  }
     164              :  
     165           36 : +export function is_loopback(iface) {
     166           36 : +    return iface.Name == "lo" || (iface.Device && iface.Device.DeviceType == "loopback");
     167           36 : +}
     168              : +
     169           36 : +export function has_group(iface) {
     170           36 : +    return (
     171           36 : +        (iface.Device &&
     172           36 : +            iface.Device.ActiveConnection &&
     173           36 : +            iface.Device.ActiveConnection.Group &&
     174            7 : +            iface.Device.ActiveConnection.Group.Members.length > 0) ||
     175           36 : +        (iface.MainConnection && iface.MainConnection.Groups.length > 0)
     176              : +    );
     177           36 : +}
     178              : +
     179            0 : +export function is_wireless(iface) {
     180            0 : +    return iface.Device?.DeviceType === '802-11-wireless';
     181            0 : +}
     182              : +
     183              :  export function init() {
     184              :      cockpit.translate();
     185              :  }
     186              : diff --git a/pkg/networkmanager/network-interface.jsx b/pkg/networkmanager/network-interface.jsx
     187              : index 43aa0dcb1..ee8c2a1ca 100644
     188              : --- a/pkg/networkmanager/network-interface.jsx
     189              : +++ b/pkg/networkmanager/network-interface.jsx
     190              : @@ -21,7 +21,7 @@ import { SearchInput } from "@patternfly/react-core/dist/esm/components/SearchIn
     191              :  import { Spinner } from "@patternfly/react-core/dist/esm/components/Spinner/index.js";
     192              :  import { Switch } from "@patternfly/react-core/dist/esm/components/Switch/index.js";
     193              :  import { Tooltip } from "@patternfly/react-core/dist/esm/components/Tooltip/index.js";
     194              : -import { SortByDirection } from '@patternfly/react-table';
     195              : +import { ActionsColumn, SortByDirection } from '@patternfly/react-table';
     196              :  import {
     197              :      ConnectedIcon,
     198              :      DisconnectedIcon,
     199              : @@ -225,6 +225,8 @@ export const NetworkInterfacePage = ({
     200              :      const [prevAPCount, setPrevAPCount] = useState(0);
     201              :      const [networkSearch, setNetworkSearch] = useState("");
     202              :  
     203           31 : +    const anaconda = in_anaconda_mode();
     204              : +
     205              :      const dev_name = iface.Name;
     206              :      const dev = iface.Device;
     207              :      const isManaged = iface && (!dev || is_managed(dev));
     208              : @@ -432,7 +434,14 @@ export const NetworkInterfacePage = ({
     209              :              mac_desc = mac;
     210              :          }
     211              :  
     212              : -        return mac_desc;
     213           31 : +        return (
     214           31 : +            <DescriptionListGroup id="network-interface-mac">
     215           31 : +                <DescriptionListTerm>{_("MAC")}</DescriptionListTerm>
     216           31 : +                <DescriptionListDescription data-label="Carrier">
     217           31 : +                    { mac_desc }
     218           31 : +                </DescriptionListDescription>
     219           31 : +            </DescriptionListGroup>
     220              : +        );
     221              :      }
     222              :  
     223              :      function renderCarrierStatusRow() {
     224              : @@ -980,47 +989,49 @@ export const NetworkInterfacePage = ({
     225              :                  );
     226              :              } else {
     227              :                  actionColumn = (
     228              : -                    <>
     229              : -                        <Privileged allowed={privileged}
     230              : -                                    tooltipId={"wifi-connect-" + index}
     231              : -                                    excuse={_("Not permitted to connect to network")}>
     232              : -                            <Button variant="secondary"
     233              : -                                    size="sm"
     234              : -                                    icon={<ConnectedIcon />}
     235              : -                                    isDisabled={!privileged}
     236              : -                                    onClick={() => connectToAP(ap)}
     237              : -                                    aria-label={_("Connect")}>
     238              : -                                {_("Connect")}
     239              : -                            </Button>
     240              : -                        </Privileged>
     241              : -                        {ap.Connection && (
     242              : -                            <>
     243              : -                                {" "}
     244              : -                                <KebabDropdown
     245              : -                                    toggleButtonId={"wifi-kebab-" + index}
     246              : -                                    isDisabled={!privileged}
     247              : -                                    dropdownItems={[
     248              : -                                        <DropdownItem key="forget"
     249              : -                                                      className="pf-m-danger"
     250              : -                                                      onClick={() => forgetNetwork(ap)}
     251              : -                                                      aria-label={_("Forget")}>
     252              : -                                            {_("Forget")}
     253              : -                                        </DropdownItem>
     254              : -                                    ]} />
     255              : -                            </>
     256              : -                        )}
     257              : -                    </>
     258            2 : +                    <Privileged allowed={privileged}
     259            2 : +                                tooltipId={"wifi-connect-" + index}
     260            2 : +                                excuse={_("Not permitted to connect to network")}>
     261            2 : +                        <Button variant="secondary"
     262            2 : +                                size="sm"
     263            2 : +                                icon={<ConnectedIcon />}
     264            2 : +                                isDisabled={!privileged}
     265            1 : +                                onClick={() => connectToAP(ap)}
     266            2 : +                                aria-label={_("Connect")}>
     267            2 : +                            {_("Connect")}
     268            2 : +                        </Button>
     269            2 : +                    </Privileged>
     270              :                  );
     271              :              }
     272            2 : +            let rowActions = <></>;
     273            2 : +            if (ap.Connection) {
     274            2 : +                rowActions = <ActionsColumn
     275            2 : +                    items={[
     276            2 : +                        {
     277            2 : +                            title: _("Forget"),
     278            2 : +                            onClick: () => forgetNetwork(ap),
     279            2 : +                            isDanger: true,
     280            2 : +                            "aria-label": _("Forget")
     281            2 : +                        }
     282            2 : +                    ]}
     283            2 : +                    isDisabled={!privileged}
     284            2 : +                />;
     285            2 : +            }
     286              : +
     287            2 : +            const networkColumns = [
     288            2 : +                { title: nameColumn, sortKey: ap.Ssid, header: true },
     289            2 : +                { title: <>{securityIcon} {ap.Mode}</>, sortKey: ap.Mode },
     290            2 : +                { title: signalColumn, sortKey: String(ap.Strength).padStart(3, '0') },
     291            2 : +            ];
     292            2 : +            if (!anaconda) {
     293            2 : +                networkColumns.push({ title: cockpit.format_bits_per_sec(ap.MaxBitrate * 1000) });
     294            2 : +            }
     295            2 : +            networkColumns.push({ title: <Flex justifyContent={{ default: 'justifyContentFlexEnd' }}><FlexItem>{actionColumn}</FlexItem></Flex>, props: { hasAction: true } });
     296            2 : +            networkColumns.push({ title: rowActions, props: { isActionCell: true } });
     297              : +
     298              :  
     299              :              return {
     300              : -                columns: [
     301              : -                    { title: nameColumn, sortKey: ap.Ssid, header: true },
     302              : -                    { title: <>{securityIcon} {ap.Mode}</>, sortKey: ap.Mode },
     303              : -                    { title: signalColumn, sortKey: String(ap.Strength).padStart(3, '0') },
     304              : -                    { title: cockpit.format_bits_per_sec(ap.MaxBitrate * 1000) },
     305              : -                    { title: actionColumn },
     306              : -                ],
     307            2 : +                columns: networkColumns,
     308              :                  props: { key: ap.HwAddress, "data-ssid": ap.Ssid, "data-known": !!ap.Connection }
     309              :              };
     310              :          });
     311              : @@ -1028,18 +1039,38 @@ export const NetworkInterfacePage = ({
     312              :          // Add aggregated hidden access points row at the bottom
     313              :          if (dev.hiddenAPCount > 0) {
     314              :              const hiddenLabel = cockpit.ngettext("$0 hidden network", "$0 hidden networks", dev.hiddenAPCount);
     315              : +
     316            5 : +            const networkHiddenColumns = [
     317            5 : +                { title: cockpit.format(hiddenLabel, dev.hiddenAPCount), sortKey: "zzz-hidden", header: true },
     318            5 : +                { title: "" },
     319            5 : +                { title: "" },
     320            5 : +                { title: "" },
     321            5 : +                { title: "" },
     322            5 : +            ];
     323              : +
     324            5 : +            if (!anaconda) {
     325            5 : +                networkHiddenColumns.push({ title: "" });
     326            5 : +            }
     327            5 : +            networkHiddenColumns.push({ title: "" });
     328              : +
     329              : +
     330              :              rows.push({
     331              : -                columns: [
     332              : -                    { title: cockpit.format(hiddenLabel, dev.hiddenAPCount), sortKey: "zzz-hidden", header: true },
     333              : -                    { title: "" },
     334              : -                    { title: "" },
     335              : -                    { title: "" },
     336              : -                    { title: "" },
     337              : -                ],
     338            5 : +                columns: networkHiddenColumns,
     339              :                  props: { key: "hidden-networks", "data-hidden": true }
     340              :              });
     341              :          }
     342              :  
     343            5 : +        const listingColumns = [
     344            5 : +            { title: _("Network"), header: true, sortable: true },
     345            5 : +            { title: _("Mode") },
     346            5 : +            { title: _("Signal"), sortable: true },
     347            5 : +        ];
     348              : +
     349            5 : +        if (!anaconda) {
     350            5 : +            listingColumns.push({ title: _("Rate") });
     351            5 : +        }
     352            5 : +        listingColumns.push({ title: "", props: { screenReaderText: _("Actions") } });
     353              : +
     354              :          return (
     355              :              <Card isPlain id="network-interface-wifi-networks">
     356              :                  <CardHeader actions={{
     357              : @@ -1077,13 +1108,7 @@ export const NetworkInterfacePage = ({
     358              :                  </CardHeader>
     359              :                  <ListingTable aria-label={_("Available networks")}
     360              :                                variant='compact'
     361              : -                              columns={[
     362              : -                                  { title: _("Network"), header: true, sortable: true },
     363              : -                                  { title: _("Mode") },
     364              : -                                  { title: _("Signal"), sortable: true },
     365              : -                                  { title: _("Rate") },
     366              : -                                  { title: "", props: { screenReaderText: _("Actions") } },
     367              : -                              ]}
     368           31 : +                              columns={listingColumns}
     369              :                                sortBy={{ index: 2, direction: SortByDirection.asc }}
     370              :                                sortMethod={networkSort}
     371              :                                rows={rows} />
     372              : @@ -1112,7 +1137,7 @@ export const NetworkInterfacePage = ({
     373              :          };
     374              :  
     375              :          const cs = con && connection_settings(con);
     376              : -        if (!con || (cs.type != "bond" && cs.type != "team" && cs.type != "bridge")) {
     377           22 : +        if (plot_state && (!con || (cs.type != "bond" && cs.type != "team" && cs.type != "bridge"))) {
     378              :              plot_state.plot_instances('rx', rx_plot_data, [dev_name], true);
     379              :              plot_state.plot_instances('tx', tx_plot_data, [dev_name], true);
     380              :              return null;
     381              : @@ -1120,7 +1145,7 @@ export const NetworkInterfacePage = ({
     382              :  
     383              :          const plot_ifaces = [];
     384              :  
     385              : -        con.Members.forEach(member_con => {
     386           13 : +        con && con.Members.forEach(member_con => {
     387              :              member_con.Interfaces.forEach(iface => {
     388              :                  if (iface.MainConnection != member_con)
     389              :                      return;
     390              : @@ -1140,8 +1165,10 @@ export const NetworkInterfacePage = ({
     391              :              });
     392              :          });
     393              :  
     394              : -        plot_state.plot_instances('rx', rx_plot_data, plot_ifaces, true);
     395              : -        plot_state.plot_instances('tx', tx_plot_data, plot_ifaces, true);
     396           16 : +        if (plot_state) {
     397           16 : +            plot_state.plot_instances('rx', rx_plot_data, plot_ifaces, true);
     398           16 : +            plot_state.plot_instances('tx', tx_plot_data, plot_ifaces, true);
     399           16 : +        }
     400              :  
     401              :          const sorted_members = Object.keys(members).sort()
     402              :                  .map(name => members[name]);
     403              : @@ -1208,12 +1235,11 @@ export const NetworkInterfacePage = ({
     404              :      const settingsRows = renderConnectionSettingsRows(iface.MainConnection, connectionSettings)
     405              :              .map((component, idx) => <React.Fragment key={idx}>{component}</React.Fragment>);
     406              :  
     407              : -    const anaconda = in_anaconda_mode();
     408              : -
     409              :      return (
     410              :          <Page id="network-interface"
     411              :                data-test-wait={operationInProgress}
     412              :                className={"pf-m-no-sidebar" + (anaconda ? " anaconda" : "")}>
     413           31 : +            { !anaconda ? (
     414              :              <PageBreadcrumb hasBodyWrapper={false} stickyOnBreakpoint={{ default: "top" }}>
     415              :                  <Breadcrumb>
     416              :                      <BreadcrumbItem to='#/'>
     417              : @@ -1224,9 +1250,12 @@ export const NetworkInterfacePage = ({
     418              :                      </BreadcrumbItem>
     419              :                  </Breadcrumb>
     420              :              </PageBreadcrumb>
     421              : -            <PageSection hasBodyWrapper={false}>
     422              : -                <NetworkPlots plot_state={plot_state} />
     423              : -            </PageSection>
     424            4 : +            ) : <></> }
     425           31 : +            { plot_state &&
     426           31 : +                <PageSection hasBodyWrapper={false}>
     427           31 : +                    <NetworkPlots plot_state={plot_state} />
     428           31 : +                </PageSection>
     429              : +            }
     430              :              <PageSection hasBodyWrapper={false}>
     431              :                  <Gallery hasGutter>
     432              :                      <Card isPlain className="network-interface-details">
     433              : @@ -1246,12 +1275,12 @@ export const NetworkInterfacePage = ({
     434              :                              <CardTitle className="network-interface-details-title">
     435              :                                  <span id="network-interface-name">{dev_name}</span>
     436              :                                  <span id="network-interface-hw">{renderDesc()}</span>
     437              : -                                <span id="network-interface-mac">{renderMac()}</span>
     438              :                              </CardTitle>
     439              :                          </CardHeader>
     440              :                          <CardBody>
     441              :                              <DescriptionList id="network-interface-settings" className="network-interface-settings pf-m-horizontal-on-sm">
     442              :                                  {renderActiveStatusRow()}
     443           31 : +                                {renderMac()}
     444              :                                  {renderCarrierStatusRow()}
     445              :                                  {settingsRows}
     446              :                              </DescriptionList>
     447              : @@ -1264,7 +1293,7 @@ export const NetworkInterfacePage = ({
     448              :                          }
     449              :                      </Card>
     450              :                      {renderWiFiNetworks()}
     451              : -                    {renderConnectionMembers(iface.MainConnection)}
     452           31 : +                    { !anaconda && renderConnectionMembers(iface.MainConnection)}
     453              :                  </Gallery>
     454              :              </PageSection>
     455              :          </Page>
     456              : diff --git a/pkg/networkmanager/network-main.jsx b/pkg/networkmanager/network-main.jsx
     457              : index d2870f684..1b75ec3f4 100644
     458              : --- a/pkg/networkmanager/network-main.jsx
     459              : +++ b/pkg/networkmanager/network-main.jsx
     460              : @@ -25,6 +25,8 @@ import { in_anaconda_mode } from "utils";
     461              :  import firewall from './firewall-client.js';
     462              :  import {
     463              :      device_state_text,
     464              : +    has_group,
     465              : +    is_loopback,
     466              :      is_managed,
     467              :      render_active_connection,
     468              :  } from './interfaces.js';
     469              : @@ -39,23 +41,17 @@ export const NetworkPage = ({ privileged, operationInProgress, usage_monitor, pl
     470              :      const unmanaged = [];
     471              :      const plot_ifaces = [];
     472              :      let hasDetails = false;
     473           36 : +    const anaconda_mode = JSON.parse(window.sessionStorage.getItem("cockpit_anaconda"));
     474              : +
     475              :  
     476              :      interfaces.forEach(iface => {
     477              : -        function hasGroup(iface) {
     478              : -            return ((iface.Device &&
     479              : -                     iface.Device.ActiveConnection &&
     480              : -                     iface.Device.ActiveConnection.Group &&
     481              : -                     iface.Device.ActiveConnection.Group.Members.length > 0) ||
     482              : -                    (iface.MainConnection &&
     483              : -                     iface.MainConnection.Groups.length > 0));
     484              : -        }
     485              :  
     486              :          // Skip loopback
     487              : -        if (iface.Name == "lo" || (iface.Device && iface.Device.DeviceType == 'loopback'))
     488           36 : +        if (is_loopback(iface))
     489              :              return;
     490              :  
     491              :          // Skip members
     492              : -        if (hasGroup(iface))
     493           36 : +        else if (has_group(iface))
     494              :              return;
     495              :  
     496              :          const dev = iface.Device;
     497              : diff --git a/pkg/networkmanager/networking.scss b/pkg/networkmanager/networking.scss
     498              : index bf340a515..823e383d2 100644
     499              : --- a/pkg/networkmanager/networking.scss
     500              : +++ b/pkg/networkmanager/networking.scss
     501              : @@ -323,3 +323,10 @@ th {
     502              :  }
     503              :  
     504              :  /* End Firewall specific CSS */
     505              : +
     506              : +#networking.anaconda .pf-v6-c-page__main-container {
     507              : +  border-radius: 0;
     508              : +  margin: 0;
     509              : +  border: 0;
     510              : +  max-block-size: 100%;
     511              : +}
     512              : diff --git a/pkg/networkmanager/networkmanager.jsx b/pkg/networkmanager/networkmanager.jsx
     513              : index 56bf87476..4dee79f4c 100644
     514              : --- a/pkg/networkmanager/networkmanager.jsx
     515              : +++ b/pkg/networkmanager/networkmanager.jsx
     516              : @@ -25,6 +25,7 @@ import { PlotState } from 'plot';
     517              :  
     518              :  import { useObject, useEvent, usePageLocation } from "hooks";
     519              :  import { WithDialogs } from "dialogs.jsx";
     520              : +import { AnacondaNetworkPage } from './anaconda-main';
     521              :  
     522              :  const _ = cockpit.gettext;
     523              :  
     524              : @@ -99,11 +100,29 @@ const App = () => {
     525              :  
     526              :      const interfaces = model.list_interfaces();
     527              :  
     528           37 : +    const anaconda_mode = JSON.parse(window.sessionStorage.getItem("cockpit_anaconda"));
     529              : +
     530            7 : +    if (anaconda_mode) {
     531            0 : +        const iface = path.length == 1 ? interfaces.find(iface => iface.Name == path[0]) : undefined;
     532              : +
     533            7 : +        return (
     534            7 : +            <ModelContext.Provider value={model}>
     535            7 : +                <WithDialogs key="networking-anaconda">
     536            7 : +                    <AnacondaNetworkPage privileged={superuser.allowed}
     537            7 : +                                         operationInProgress={model.operationInProgress}
     538            7 : +                                         usage_monitor={usage_monitor}
     539            7 : +                                         interfaces={interfaces}
     540            7 : +                                         iface={iface} />
     541            7 : +                </WithDialogs>
     542            7 : +            </ModelContext.Provider>
     543              : +        );
     544            7 : +    }
     545              : +
     546              :      /* At this point NM is running and the model is ready */
     547              :      if (path.length == 0) {
     548              :          return (
     549              :              <ModelContext.Provider value={model}>
     550              : -                <WithDialogs key="1">
     551           36 : +                <WithDialogs key="networking">
     552              :                      <NetworkPage privileged={superuser.allowed}
     553              :                                   operationInProgress={model.operationInProgress}
     554              :                                   usage_monitor={usage_monitor}
     555              : @@ -118,7 +137,7 @@ const App = () => {
     556              :          if (iface) {
     557              :              return (
     558              :                  <ModelContext.Provider value={model}>
     559              : -                    <WithDialogs key="2">
     560           34 : +                    <WithDialogs key="networking-interface">
     561              :                          <NetworkInterfacePage privileged={superuser.allowed}
     562              :                                                operationInProgress={model.operationInProgress}
     563              :                                                usage_monitor={usage_monitor}
     564              : diff --git a/pkg/packagekit/updates.jsx b/pkg/packagekit/updates.jsx
     565              : index 68b40fcf1..3d3cceebd 100644
     566              : --- a/pkg/packagekit/updates.jsx
     567              : +++ b/pkg/packagekit/updates.jsx
     568              : @@ -1212,12 +1212,17 @@ class OsUpdates extends React.Component {
     569              :          try {
     570              :              const seconds = await this.state.packageManager.get_last_refresh_time();
     571              :              this.setState({ timeSinceRefresh: seconds });
     572           18 : +            console.log("seconds", seconds)
     573              :  
     574              :              // automatically trigger refresh for ≥ 1 day or if never refreshed
     575              : -            if (seconds >= 24 * 3600 || seconds < 0)
     576            2 : +            if (seconds >= 60 * 5 || seconds < 0) {
     577            7 : +                console.log("refreshing")
     578              :                  this.handleRefresh();
     579              : -            else if (always_load)
     580            7 : +            }
     581           10 : +            else if (always_load) {
     582           10 : +                console.log("always refresh")
     583              :                  this.loadUpdates();
     584           10 : +            }
     585              :          } catch (exc) {
     586              :              this.handleLoadError(exc);
     587              :          }
     588              : diff --git a/test/verify/check-networkmanager-wifi b/test/verify/check-networkmanager-wifi
     589              : index d104e1b10..8322e5a63 100755
     590              : --- a/test/verify/check-networkmanager-wifi
     591              : +++ b/test/verify/check-networkmanager-wifi
     592              : @@ -108,6 +108,7 @@ wpa_passphrase=hidden99""")
     593              :          # detects our three visible wifis (plus one hidden)
     594              :          b.wait_in_text("table[aria-label='Available networks'] tbody:first-of-type", "ZE WIFI!")
     595              :          b.wait_text("tr[data-ssid='ZE WIFI!'] th", "ZE WIFI!")
     596              : +        testlib.sit()
     597              :          self.assertEqual(b.get_pf_progress_value("tr[data-ssid='ZE WIFI!'] [data-label='Signal']"), 100)
     598              :          # sadly, mac80211_hwsim's data rate reporting is flaky, so just ensure at least one of our networks is correct
     599              :          b.wait_in_text("table[aria-label='Available networks']", "54 Mbps")
        

Generated by: LCOV version 2.0-1