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