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 :
29 35 : const _ = cockpit.gettext;
30 :
31 35 : const App = () => {
32 35 : const nmService = useObject(() => service.proxy("NetworkManager"),
33 35 : null,
34 35 : []);
35 35 : useEvent(nmService, "changed");
36 :
37 35 : const model = useObject(() => new NetworkManagerModel(), null, []);
38 35 : useEvent(model, "changed");
39 :
40 35 : const nmRunning_ref = useRef(undefined);
41 35 : useEvent(model.client, "owner", (event, owner) => { nmRunning_ref.current = owner !== null });
42 :
43 35 : const { path } = usePageLocation();
44 :
45 35 : useEvent(superuser, "changed");
46 :
47 35 : const usage_monitor = useObject(() => new UsageMonitor(), null, []);
48 35 : const plot_state_main = useObject(() => new PlotState(), null, []);
49 35 : const plot_state_iface = useObject(() => new PlotState(), null, []);
50 :
51 9 : if (model.curtain == 'testing' || model.curtain == 'restoring') {
52 9 : return <EmptyStatePanel loading title={model.curtain == 'testing' ? _("Testing connection") : _("Restoring connection")} />;
53 9 : }
54 :
55 35 : if (model.ready === undefined)
56 35 : return <EmptyStatePanel loading />;
57 :
58 : /* Show EmptyStatePanel when nm is not running */
59 7 : if (!nmRunning_ref.current) {
60 7 : if (nmService.enabled) {
61 7 : return (
62 7 : <div id="networking-nm-crashed">
63 7 : <EmptyStatePanel icon={ ExclamationCircleIcon }
64 7 : title={ _("NetworkManager is not running") }
65 6 : action={nmService.exists ? _("Start service") : null}
66 7 : onAction={ nmService.start }
67 7 : secondary={
68 7 : <Button component="a"
69 7 : variant="secondary"
70 1 : onClick={() => cockpit.jump("/system/services#/NetworkManager.service", cockpit.transport.host)}>
71 7 : {_("Troubleshoot…")}
72 7 : </Button>
73 7 : } />
74 7 : </div>
75 : );
76 7 : } else if (!nmService.exists) {
77 7 : return (
78 7 : <div id="networking-nm-not-found">
79 7 : <EmptyStatePanel icon={ ExclamationCircleIcon }
80 7 : title={ _("NetworkManager is not installed") } />
81 :
82 7 : </div>
83 : );
84 7 : } else {
85 7 : return (
86 7 : <div id="networking-nm-disabled">
87 7 : <EmptyStatePanel icon={ ExclamationCircleIcon }
88 7 : title={ _("Network devices and graphs require NetworkManager") }
89 6 : action={nmService.exists ? _("Enable service") : null}
90 1 : onAction={() => {
91 1 : nmService.enable();
92 1 : nmService.start();
93 1 : }} />
94 :
95 7 : </div>
96 : );
97 7 : }
98 7 : }
99 :
100 35 : const interfaces = model.list_interfaces();
101 :
102 : /* At this point NM is running and the model is ready */
103 34 : if (path.length == 0) {
104 34 : return (
105 34 : <ModelContext.Provider value={model}>
106 34 : <WithDialogs key="1">
107 34 : <NetworkPage privileged={superuser.allowed}
108 34 : operationInProgress={model.operationInProgress}
109 34 : usage_monitor={usage_monitor}
110 34 : plot_state={plot_state_main}
111 34 : interfaces={interfaces} />
112 34 : </WithDialogs>
113 34 : </ModelContext.Provider>
114 : );
115 31 : } else if (path.length == 1) {
116 29 : const iface = interfaces.find(iface => iface.Name == path[0]);
117 :
118 32 : if (iface) {
119 32 : return (
120 32 : <ModelContext.Provider value={model}>
121 32 : <WithDialogs key="2">
122 32 : <NetworkInterfacePage privileged={superuser.allowed}
123 32 : operationInProgress={model.operationInProgress}
124 32 : usage_monitor={usage_monitor}
125 32 : plot_state={plot_state_iface}
126 32 : interfaces={interfaces}
127 32 : iface={iface} />
128 32 : </WithDialogs>
129 32 : </ModelContext.Provider>
130 : );
131 7 : } else {
132 7 : return (
133 7 : <EmptyStatePanel icon={ ExclamationCircleIcon }
134 7 : title={cockpit.format(_("Network interface '$0' not found"), path[0])}
135 7 : action={_("Return to overview page")}
136 7 : actionVariant="link"
137 0 : onAction={() => cockpit.location.go("/")}
138 7 : />
139 : );
140 7 : }
141 32 : }
142 :
143 6 : return null;
144 35 : };
145 :
146 35 : function init() {
147 35 : initDialogs();
148 35 : const root = createRoot(document.getElementById("network-page"));
149 35 : root.render(<App />);
150 35 : }
151 :
152 35 : document.addEventListener("DOMContentLoaded", init);
|