diff --git a/ui/webui/src/actions/network-actions.js b/ui/webui/src/actions/network-actions.js
new file mode 100644
index 00000000000..f270db51047
--- /dev/null
+++ b/ui/webui/src/actions/network-actions.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with This program; If not, see .
+ */
+
+import {
+ getConnected,
+} from "../apis/network.js";
+
+export const getConnectedAction = () => {
+ return async (dispatch) => {
+ const connected = await getConnected();
+
+ return dispatch({
+ type: "GET_NETWORK_CONNECTED",
+ payload: { connected }
+ });
+ };
+};
diff --git a/ui/webui/src/apis/network.js b/ui/webui/src/apis/network.js
new file mode 100644
index 00000000000..7954aceedea
--- /dev/null
+++ b/ui/webui/src/apis/network.js
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with This program; If not, see .
+ */
+
+import cockpit from "cockpit";
+
+import { getConnectedAction } from "../actions/network-actions.js";
+import { debug } from "../helpers/log.js";
+
+export class NetworkClient {
+ constructor (address) {
+ if (NetworkClient.instance && (!address || NetworkClient.instance.address === address)) {
+ return NetworkClient.instance;
+ }
+
+ NetworkClient.instance?.client.close();
+
+ NetworkClient.instance = this;
+
+ this.client = cockpit.dbus(
+ "org.fedoraproject.Anaconda.Modules.Network",
+ { superuser: "try", bus: "none", address }
+ );
+ this.address = address;
+ }
+
+ init () {
+ this.client.addEventListener("close", () => console.error("Network client closed"));
+ }
+}
+
+/**
+ * @returns {Promise} The bool state of the network connection
+ */
+export const getConnected = () => {
+ return (
+ new NetworkClient().client.call(
+ "/org/fedoraproject/Anaconda/Modules/Network",
+ "org.freedesktop.DBus.Properties",
+ "Get",
+ ["org.fedoraproject.Anaconda.Modules.Network", "Connected"]
+ )
+ .then(res => res[0].v)
+ );
+};
+
+export const startEventMonitorNetwork = ({ dispatch }) => {
+ return new NetworkClient().client.subscribe(
+ { },
+ (path, iface, signal, args) => {
+ switch (signal) {
+ case "PropertiesChanged":
+ if (args[0] === "org.fedoraproject.Anaconda.Modules.Network" && Object.hasOwn(args[1], "Connected")) {
+ dispatch(getConnectedAction());
+ } else {
+ debug(`Unhandled signal on ${path}: ${iface}.${signal}`, JSON.stringify(args));
+ }
+ break;
+ default:
+ debug(`Unhandled signal on ${path}: ${iface}.${signal}`, JSON.stringify(args));
+ }
+ }
+ );
+};
+
+export const initDataNetwork = ({ dispatch }) => {
+ return Promise.all([
+ dispatch(getConnectedAction())
+ ]);
+};
diff --git a/ui/webui/src/components/AnacondaHeader.jsx b/ui/webui/src/components/AnacondaHeader.jsx
index b1610935a16..f3d722ed040 100644
--- a/ui/webui/src/components/AnacondaHeader.jsx
+++ b/ui/webui/src/components/AnacondaHeader.jsx
@@ -31,7 +31,7 @@ import { HeaderKebab } from "./HeaderKebab.jsx";
const _ = cockpit.gettext;
-export const AnacondaHeader = ({ beta, title, reportLinkURL }) => {
+export const AnacondaHeader = ({ beta, title, reportLinkURL, isConnected }) => {
const prerelease = _("Pre-release");
const betanag = beta
? (
@@ -68,7 +68,7 @@ export const AnacondaHeader = ({ beta, title, reportLinkURL }) => {
{title}
{betanag}
-
+
);
diff --git a/ui/webui/src/components/Error.jsx b/ui/webui/src/components/Error.jsx
index bbe2629a051..3e353d015f8 100644
--- a/ui/webui/src/components/Error.jsx
+++ b/ui/webui/src/components/Error.jsx
@@ -27,12 +27,14 @@ import {
HelperTextItem,
Modal,
ModalVariant,
+ Stack,
+ StackItem,
TextArea,
TextContent,
TextVariants,
Text,
} from "@patternfly/react-core";
-import { ExternalLinkAltIcon } from "@patternfly/react-icons";
+import { ExternalLinkAltIcon, DisconnectedIcon } from "@patternfly/react-icons";
import { exitGui } from "../helpers/exit.js";
@@ -62,7 +64,8 @@ export const BZReportModal = ({
logFile,
detailsLabel,
detailsContent,
- buttons
+ buttons,
+ isConnected
}) => {
const [logContent, setLogContent] = useState();
const [preparingReport, setPreparingReport] = useState(false);
@@ -92,18 +95,27 @@ export const BZReportModal = ({
titleIconVariant={titleIconVariant}
variant={ModalVariant.large}
footer={
- <>
- }
- onClick={() => openBZIssue(reportLinkURL)}
- component="a">
- {preparingReport ? _("Preparing report") : _("Report issue")}
-
- {buttons}
- >
+
+
+
+ {isConnected
+ ? {_("Reporting an issue will send information over the network. Please review and edit the attached log to remove any sensitive information.")}
+ : }> {_("Network not available. Configure the network in the top bar menu to report the issue.")} }
+
+
+
+ }
+ onClick={() => openBZIssue(reportLinkURL)}
+ component="a">
+ {preparingReport ? _("Preparing report") : _("Report issue")}
+
+ {buttons}
+
+
}>