Line data Source code
1 : /*
2 : * Copyright (C) 2021 Red Hat, Inc.
3 : * SPDX-License-Identifier: LGPL-2.1-or-later
4 : */
5 : import '../lib/patternfly/patternfly-6-cockpit.scss';
6 : import "./network-anaconda.scss";
7 35 : import cockpit from "cockpit";
8 : import 'cockpit-dark-theme'; // once per page
9 35 : import React, { useRef } from 'react';
10 35 : import { createRoot } from "react-dom/client";
11 :
12 : import { Button } from "@patternfly/react-core/dist/esm/components/Button/index.js";
13 : import { ExclamationCircleIcon } from "@patternfly/react-icons";
14 :
15 : import { EmptyStatePanel } from "cockpit-components-empty-state.jsx";
16 : import { ModelContext } from './model-context.jsx';
17 : import { NetworkInterfacePage } from './network-interface.jsx';
18 : import { NetworkPage } from './network-main.jsx';
19 : import { UsageMonitor } from './helpers.js';
20 :
21 : import * as service from 'service.js';
22 : import { init as initDialogs, NetworkManagerModel } from './interfaces.js';
23 : import { superuser } from 'superuser';
24 : import { PlotState } from 'plot';
25 :
26 : import { useObject, useEvent, usePageLocation } from "hooks";
27 : import { WithDialogs } from "dialogs.jsx";
28 : import { AnacondaNetworkPage } from './anaconda-main';
29 :
30 35 : const _ = cockpit.gettext;
31 :
32 35 : const App = () => {
33 35 : const nmService = useObject(() => service.proxy("NetworkManager"),
34 35 : null,
35 35 : []);
36 35 : useEvent(nmService, "changed");
37 :
38 35 : const model = useObject(() => new NetworkManagerModel(), null, []);
39 35 : useEvent(model, "changed");
40 :
41 35 : const nmRunning_ref = useRef(undefined);
42 35 : useEvent(model.client, "owner", (event, owner) => { nmRunning_ref.current = owner !== null });
43 :
44 35 : const { path } = usePageLocation();
45 :
46 35 : useEvent(superuser, "changed");
47 :
48 35 : const usage_monitor = useObject(() => new UsageMonitor(), null, []);
49 35 : const plot_state_main = useObject(() => new PlotState(), null, []);
50 35 : const plot_state_iface = useObject(() => new PlotState(), null, []);
51 :
52 9 : if (model.curtain == 'testing' || model.curtain == 'restoring') {
53 9 : return <EmptyStatePanel loading title={model.curtain == 'testing' ? _("Testing connection") : _("Restoring connection")} />;
54 9 : }
55 :
56 35 : if (model.ready === undefined)
57 35 : return <EmptyStatePanel loading />;
58 :
59 : /* Show EmptyStatePanel when nm is not running */
60 7 : if (!nmRunning_ref.current) {
61 7 : if (nmService.enabled) {
62 7 : return (
63 7 : <div id="networking-nm-crashed">
64 7 : <EmptyStatePanel icon={ ExclamationCircleIcon }
65 7 : title={ _("NetworkManager is not running") }
66 6 : action={nmService.exists ? _("Start service") : null}
67 7 : onAction={ nmService.start }
68 7 : secondary={
69 7 : <Button component="a"
70 7 : variant="secondary"
71 1 : onClick={() => cockpit.jump("/system/services#/NetworkManager.service", cockpit.transport.host)}>
72 7 : {_("Troubleshoot…")}
73 7 : </Button>
74 7 : } />
75 7 : </div>
76 : );
77 7 : } else if (!nmService.exists) {
78 7 : return (
79 7 : <div id="networking-nm-not-found">
80 7 : <EmptyStatePanel icon={ ExclamationCircleIcon }
81 7 : title={ _("NetworkManager is not installed") } />
82 :
83 7 : </div>
84 : );
85 7 : } else {
86 7 : return (
87 7 : <div id="networking-nm-disabled">
88 7 : <EmptyStatePanel icon={ ExclamationCircleIcon }
89 7 : title={ _("Network devices and graphs require NetworkManager") }
90 6 : action={nmService.exists ? _("Enable service") : null}
91 1 : onAction={() => {
92 1 : nmService.enable();
93 1 : nmService.start();
94 1 : }} />
95 :
96 7 : </div>
97 : );
98 7 : }
99 7 : }
100 :
101 35 : const interfaces = model.list_interfaces();
102 :
103 35 : const anaconda_mode = JSON.parse(window.sessionStorage.getItem("cockpit_anaconda"));
104 :
105 6 : if (anaconda_mode) {
106 0 : const iface = path.length == 1 ? interfaces.find(iface => iface.Name == path[0]) : undefined;
107 :
108 6 : return (
109 6 : <ModelContext.Provider value={model}>
110 6 : <WithDialogs key="networking-anaconda">
111 6 : <AnacondaNetworkPage privileged={superuser.allowed}
112 6 : operationInProgress={model.operationInProgress}
113 6 : usage_monitor={usage_monitor}
114 6 : interfaces={interfaces}
115 6 : iface={iface} />
116 6 : </WithDialogs>
117 6 : </ModelContext.Provider>
118 : );
119 6 : }
120 :
121 : /* At this point NM is running and the model is ready */
122 34 : if (path.length == 0) {
123 34 : return (
124 34 : <ModelContext.Provider value={model}>
125 34 : <WithDialogs key="networking">
126 34 : <NetworkPage privileged={superuser.allowed}
127 34 : operationInProgress={model.operationInProgress}
128 34 : usage_monitor={usage_monitor}
129 34 : plot_state={plot_state_main}
130 34 : interfaces={interfaces} />
131 34 : </WithDialogs>
132 34 : </ModelContext.Provider>
133 : );
134 31 : } else if (path.length == 1) {
135 29 : const iface = interfaces.find(iface => iface.Name == path[0]);
136 :
137 32 : if (iface) {
138 32 : return (
139 32 : <ModelContext.Provider value={model}>
140 32 : <WithDialogs key="networking-interface">
141 32 : <NetworkInterfacePage privileged={superuser.allowed}
142 32 : operationInProgress={model.operationInProgress}
143 32 : usage_monitor={usage_monitor}
144 32 : plot_state={plot_state_iface}
145 32 : interfaces={interfaces}
146 32 : iface={iface} />
147 32 : </WithDialogs>
148 32 : </ModelContext.Provider>
149 : );
150 32 : }
151 32 : }
152 :
153 7 : return null;
154 35 : };
155 :
156 35 : function init() {
157 35 : initDialogs();
158 35 : const root = createRoot(document.getElementById("network-page"));
159 35 : root.render(<App />);
160 35 : }
161 :
162 35 : document.addEventListener("DOMContentLoaded", init);
|