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")
|