/*
* Copyright (C) 2021 Red Hat, Inc.
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
import cockpit from "cockpit";
import React, { useCallback, useEffect, useRef, useState } from "react";
import { Page, PageGroup, PageSection, PageSectionTypes } from "@patternfly/react-core/dist/esm/components/Page/index.js";
import { BossClient } from "../apis/boss.js";
import { initialState, reducer, useReducerWithThunk } from "../reducer.js";
import { getInstallerConfValue, parseAnacondaConfBool, readConf } from "../helpers/conf.js";
import { isExiting } from "../helpers/exit.js";
import { debug } from "../helpers/log.js";
import { getAnacondaUIVersion, getAnacondaVersion } from "../helpers/product.js";
import { MainContextWrapper } from "../contexts/Common.jsx";
import { EmptyStatePanel } from "cockpit-components-empty-state";
import { read_os_release as readOsRelease } from "os-release.js";
import { AnacondaHeader } from "./AnacondaHeader.jsx";
import { AnacondaWizard } from "./AnacondaWizard.jsx";
import { ErrorBoundary } from "./Error.jsx";
const _ = cockpit.gettext;
const N_ = cockpit.noop;
export const ApplicationLoading = () => (
);
const ApplicationCompleted = () => (
);
export const Application = ({ conf, dispatch, installationStatus, isFetching, onCritFail, osRelease, reportLinkURL, setShowStorage, showStorage }) => {
const [storeInitialized, setStoreInitialized] = useState(false);
const [currentStepId, setCurrentStepId] = useState();
const address = useAddress(onCritFail);
const automatedInstall = parseAnacondaConfBool(getInstallerConfValue(conf, "Runtime", "automated_install"));
const pauseAtSummary = parseAnacondaConfBool(getInstallerConfValue(conf, "Runtime", "pause_at_summary"));
useEffect(() => {
if (!address) {
return;
}
// Before unload ask the user for verification
const preventExit = () => {
return "";
};
// Attach the beforeunload event handler
window.addEventListener("beforeunload", preventExit);
// Function to temporarily disable beforeunload
const allowExternalNavigation = (event) => {
const link = event.target.closest("a");
if (link && (link.href.startsWith("extlink:") || link.href.startsWith("anaconda-gnome-control-center:"))) {
window.removeEventListener("beforeunload", preventExit);
setTimeout(() => {
window.addEventListener("beforeunload", preventExit);
}, 1000); // Re-enable after 1 second
}
};
// Attach a click event listener to detect external link clicks
document.addEventListener("click", allowExternalNavigation);
new BossClient(address, dispatch).init({ automatedInstall, conf })
.then(() => {
setStoreInitialized(true);
}, onCritFail({ context: N_("Reading information about the computer failed.") }));
}, [address, automatedInstall, conf, dispatch, onCritFail]);
// Postpone rendering anything until we read the dbus address and the default configuration
if (!address || !storeInitialized || !installationStatus) {
if (isExiting()) {
return ;
}
debug("Loading initial data...");
return ;
}
// On live media rebooting the system will actually shut it off
const title = cockpit.format(_("$0 installation"), osRelease.PRETTY_NAME);
return (
<>
>
);
};
const useConf = ({ onCritFail }) => {
const [conf, setConf] = useState();
useEffect(() => {
readConf().then(setConf, onCritFail({ context: N_("Reading installer configuration failed.") }));
}, [onCritFail]);
return conf;
};
const useOsRelease = ({ onCritFail }) => {
const [osRelease, setOsRelease] = useState();
useEffect(() => {
readOsRelease().then(setOsRelease, onCritFail({ context: N_("Reading information about the OS failed.") }));
}, [onCritFail]);
return osRelease;
};
const useAddress = (onCritFail) => {
const [backendReady, setBackendReady] = useState(false);
const [address, setAddress] = useState();
useEffect(() => {
if (!backendReady) {
return;
}
cockpit.file("/run/anaconda/bus.address").watch(address => {
setAddress(address);
});
}, [backendReady]);
const wasReadyRef = useRef(false);
useEffect(() => {
cockpit.file("/run/anaconda/backend_ready").watch(
(content) => {
const isReady = content !== null;
if (isReady) {
wasReadyRef.current = true;
}
setBackendReady(isReady);
if (!isReady && wasReadyRef.current && onCritFail && !isExiting()) {
onCritFail()({
message: _("The Anaconda installation has stopped unexpectedly."),
});
}
}
);
}, [onCritFail]);
return address;
};
const useAppVersion = () => {
const initialState = {
webui: getAnacondaUIVersion(),
};
const [appVersion, setAppVersion] = useState(initialState);
useEffect(() => {
getAnacondaVersion().then(value => setAppVersion(obj => ({ ...obj, backend: value })));
}, []);
return appVersion;
};
export const ApplicationWithErrorBoundary = () => {
const [showStorage, setShowStorage] = useState(false);
const [state, dispatch] = useReducerWithThunk(reducer, initialState);
const [errorBeforeBoundary, setErrorBeforeBoundary] = useState();
const onCritFail = useCallback(
(context) => (exc) => setErrorBeforeBoundary({ contextData: { context }, ...exc }),
[]
);
const conf = useConf({ onCritFail });
const osRelease = useOsRelease({ onCritFail });
const appVersion = useAppVersion();
if (!conf || !osRelease) {
return ;
}
return (
);
};