* Copyright (C) 2021 Red Hat, Inc.
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
import '../lib/patternfly/patternfly-6-cockpit.scss';
import "./anaconda/network-anaconda.scss";
import cockpit from "cockpit";
import 'cockpit-dark-theme';
import React, { useRef } from 'react';
import { createRoot } from "react-dom/client";
import { Button } from "@patternfly/react-core/dist/esm/components/Button/index.js";
import { ExclamationCircleIcon } from "@patternfly/react-icons";
import { EmptyStatePanel } from "cockpit-components-empty-state.jsx";
import { ModelContext } from './model-context.jsx';
import { NetworkInterfacePage } from './network-interface.jsx';
import { NetworkPage } from './network-main.jsx';
import { UsageMonitor } from './helpers.js';
import * as service from 'service.js';
import { init as initDialogs, NetworkManagerModel } from './interfaces.js';
import { superuser } from 'superuser';
import { PlotState } from 'plot';
import { useObject, useEvent, usePageLocation } from "hooks";
import { WithDialogs } from "dialogs.jsx";
import { AnacondaNetworkPage } from "./anaconda/anaconda-main";
import { in_anaconda_mode } from "utils";
const _ = cockpit.gettext;
const App = () => {
const nmService = useObject(() => service.proxy("NetworkManager"),
null,
[]);
useEvent(nmService, "changed");
const model = useObject(() => new NetworkManagerModel(), null, []);
useEvent(model, "changed");
const nmRunning_ref = useRef(undefined);
useEvent(model.client, "owner", (event, owner) => { nmRunning_ref.current = owner !== null });
useEvent(superuser, "changed");
if (model.curtain === 'testing' || model.curtain === 'restoring') {
return <EmptyStatePanel loading title={model.curtain === 'testing' ? _("Testing connection") : _("Restoring connection")} />;
}
if (model.ready === undefined)
return <EmptyStatePanel loading />;
const anaconda_mode = in_anaconda_mode();
const emptyStateSecondary = anaconda_mode
? null
: (<Button component="a"
variant="secondary"
onClick={() => cockpit.jump("/system/services#/NetworkManager.service", cockpit.transport.host)}>
{_("Troubleshootβ¦")}
</Button>);
if (!nmRunning_ref.current) {
if (nmService.enabled) {
return (
<div id="networking-nm-crashed">
<EmptyStatePanel icon={ ExclamationCircleIcon }
title={ _("NetworkManager is not running") }
action={nmService.exists ? _("Start service") : null}
onAction={ nmService.start }
secondary={emptyStateSecondary}
/>
</div>
);
} else if (!nmService.exists) {
return (
<div id="networking-nm-not-found">
<EmptyStatePanel icon={ ExclamationCircleIcon }
title={ _("NetworkManager is not installed") } />
</div>
);
} else {
return (
<div id="networking-nm-disabled">
<EmptyStatePanel icon={ ExclamationCircleIcon }
title={ _("Network devices and graphs require NetworkManager") }
action={nmService.exists ? _("Enable service") : null}
onAction={() => {
nmService.enable();
nmService.start();
}} />
</div>
);
}
}
if (anaconda_mode) {
return (
<ModelContext.Provider value={model}>
<WithDialogs key="networking-anaconda">
<AnacondaNetworkPage privileged={superuser.allowed}
operationInProgress={model.operationInProgress}
interfaces={model.list_interfaces()} />
</WithDialogs>
</ModelContext.Provider>
);
}
return (
<CockpitNetworkPage model={model} />
);
};
const CockpitNetworkPage = ({ model }) => {
const { path } = usePageLocation();
const usage_monitor = useObject(() => new UsageMonitor(), null, []);
const plot_state_main = useObject(() => new PlotState(), null, []);
const plot_state_iface = useObject(() => new PlotState(), null, []);
const interfaces = model.list_interfaces();
if (path.length === 0) {
return (
<ModelContext.Provider value={model}>
<WithDialogs key="networking">
<NetworkPage privileged={superuser.allowed}
operationInProgress={model.operationInProgress}
usage_monitor={usage_monitor}
plot_state={plot_state_main}
interfaces={interfaces} />
</WithDialogs>
</ModelContext.Provider>
);
} else if (path.length === 1) {
const iface = interfaces.find(iface => iface.Name === path[0]);
if (iface) {
return (
<ModelContext.Provider value={model}>
<WithDialogs key="networking-interface">
<NetworkInterfacePage privileged={superuser.allowed}
operationInProgress={model.operationInProgress}
usage_monitor={usage_monitor}
plot_state={plot_state_iface}
interfaces={interfaces}
iface={iface} />
</WithDialogs>
</ModelContext.Provider>
);
} else {
return (
<EmptyStatePanel icon={ ExclamationCircleIcon }
title={cockpit.format(_("Network interface '$0' not found"), path[0])}
action={_("Return to overview page")}
actionVariant="link"
onAction={() => cockpit.location.go("/")}
/>
);
}
}
return null;
};
function init() {
initDialogs();
const root = createRoot(document.getElementById("network-page"));
root.render(<App />);
}
document.addEventListener("DOMContentLoaded", init);