From 5747d7a280b65360c91d3d7f9b7b1133e46f9c2c Mon Sep 17 00:00:00 2001 From: Katerina Koukiou Date: Thu, 12 Dec 2024 13:30:44 +0100 Subject: [PATCH] Parse new 'hidden_screen' configuration file options Previously we would be using the ISO variant (Boot, Live) from Anaconda configuration file and we would conditionalize the page visibility in the Web UI code according to that. With this commit, the pages can be hidden per-new option of the configuration file [1]. [1] https://github.com/rhinstaller/anaconda/pull/6047 --- src/components/AnacondaPage.jsx | 28 ++++++++++++++-- src/components/AnacondaWizard.jsx | 8 +++-- .../localization/InstallationLanguage.jsx | 11 ++----- src/components/review/ReviewConfiguration.jsx | 13 ++++---- src/components/steps.js | 32 +++++++++++++++++-- .../storage/InstallationDestination.jsx | 6 ++-- src/components/storage/InstallationMethod.jsx | 13 +++----- .../storage/InstallationScenario.jsx | 5 ++- src/components/users/Accounts.jsx | 4 +-- src/contexts/Common.jsx | 5 ++- test/check-language | 2 +- test/helpers/utils.py | 1 + 12 files changed, 85 insertions(+), 43 deletions(-) diff --git a/src/components/AnacondaPage.jsx b/src/components/AnacondaPage.jsx index a05efc853..54f12aabd 100644 --- a/src/components/AnacondaPage.jsx +++ b/src/components/AnacondaPage.jsx @@ -14,10 +14,24 @@ * You should have received a copy of the GNU Lesser General Public License * along with This program; If not, see . */ -import React, { cloneElement, useEffect, useRef, useState } from "react"; +import cockpit from "cockpit"; + +import React, { cloneElement, useContext, useEffect, useRef, useState } from "react"; import { Alert, Stack, Title } from "@patternfly/react-core"; -export const AnacondaPage = ({ children, isFormDisabled, setIsFormDisabled, step, title, usePageInit }) => { +import { OsReleaseContext } from "../contexts/Common.jsx"; + +const _ = cockpit.gettext; + +export const AnacondaPage = ({ + children, + isFirstScreen, + isFormDisabled, + setIsFormDisabled, + step, + title, + usePageInit, +}) => { const [stepNotification, setStepNotification] = useState(); const [showPage, setShowPage] = useState(!isFormDisabled); const showPageRef = useRef(showPage); @@ -43,9 +57,11 @@ export const AnacondaPage = ({ children, isFormDisabled, setIsFormDisabled, step return null; } + const titleElem = isFirstScreen ? : title; + return ( - {title && {title}} + {titleElem && {titleElem}} {stepNotification?.step === step && ); }; + +const InitialPageTitle = () => { + const osRelease = useContext(OsReleaseContext); + + return cockpit.format(_("Welcome. Let's install $0 now."), osRelease.REDHAT_SUPPORT_PRODUCT); +}; diff --git a/src/components/AnacondaWizard.jsx b/src/components/AnacondaWizard.jsx index ab2c36c93..5c8717c93 100644 --- a/src/components/AnacondaWizard.jsx +++ b/src/components/AnacondaWizard.jsx @@ -27,7 +27,7 @@ import { WizardStep, } from "@patternfly/react-core"; -import { FooterContext, StorageContext, SystemTypeContext } from "../contexts/Common.jsx"; +import { FooterContext, StorageContext, SystemTypeContext, UserInterfaceContext } from "../contexts/Common.jsx"; import { AnacondaPage } from "./AnacondaPage.jsx"; import { AnacondaWizardFooter } from "./AnacondaWizardFooter.jsx"; @@ -42,6 +42,7 @@ export const AnacondaWizard = ({ currentStepId, dispatch, isFetching, onCritFail const [isFormValid, setIsFormValid] = useState(false); const { storageScenarioId } = useContext(StorageContext); const isBootIso = useContext(SystemTypeContext) === "BOOT_ISO"; + const userInterfaceConfig = useContext(UserInterfaceContext); const { path } = usePageLocation(); const componentProps = { @@ -53,7 +54,7 @@ export const AnacondaWizard = ({ currentStepId, dispatch, isFetching, onCritFail showStorage, }; - const stepsOrder = getSteps(isBootIso, storageScenarioId); + const stepsOrder = getSteps(userInterfaceConfig, isBootIso, storageScenarioId); const firstStepId = stepsOrder.filter(s => !s.isHidden)[0].id; const createSteps = (stepsOrder, componentProps) => { @@ -76,8 +77,9 @@ export const AnacondaWizard = ({ currentStepId, dispatch, isFetching, onCritFail setIsFormDisabled={setIsFormDisabled} step={s.id} title={s.title} + isFirstScreen={s.isFirstScreen} usePageInit={s.usePageInit}> - + ), ...stepProps diff --git a/src/components/localization/InstallationLanguage.jsx b/src/components/localization/InstallationLanguage.jsx index 6c860580d..61a81df49 100644 --- a/src/components/localization/InstallationLanguage.jsx +++ b/src/components/localization/InstallationLanguage.jsx @@ -45,7 +45,7 @@ import { setLangCookie } from "../../helpers/language.js"; -import { LanguageContext, OsReleaseContext } from "../../contexts/Common.jsx"; +import { LanguageContext } from "../../contexts/Common.jsx"; import "./InstallationLanguage.scss"; @@ -326,17 +326,10 @@ const InstallationLanguage = ({ idPrefix, setIsFormValid, setStepNotification }) ); }; -const PageTitle = () => { - const osRelease = useContext(OsReleaseContext); - return cockpit.format(_("Welcome to $0"), osRelease.NAME); -}; - export class Page { - constructor (isBootIso) { + constructor () { this.component = InstallationLanguage; this.id = "installation-language"; - this.isHidden = !isBootIso; this.label = _("Welcome"); - this.title = ; } } diff --git a/src/components/review/ReviewConfiguration.jsx b/src/components/review/ReviewConfiguration.jsx index f31621324..24f45fdbb 100644 --- a/src/components/review/ReviewConfiguration.jsx +++ b/src/components/review/ReviewConfiguration.jsx @@ -27,7 +27,7 @@ import { import { getDeviceChildren } from "../../helpers/storage.js"; -import { LanguageContext, OsReleaseContext, StorageContext, SystemTypeContext, UsersContext } from "../../contexts/Common.jsx"; +import { LanguageContext, OsReleaseContext, StorageContext, SystemTypeContext, UserInterfaceContext, UsersContext } from "../../contexts/Common.jsx"; import { useOriginalDevices, usePlannedActions } from "../../hooks/Storage.jsx"; @@ -65,6 +65,8 @@ const ReviewConfiguration = ({ setIsFormValid }) => { const localizationData = useContext(LanguageContext); const accounts = useContext(UsersContext); const { label: scenarioLabel } = useScenario(); + const userInterfaceConfig = useContext(UserInterfaceContext); + const hiddenScreens = userInterfaceConfig.hidden_screens || []; const isBootIso = useContext(SystemTypeContext) === "BOOT_ISO"; // Display custom footer @@ -103,19 +105,18 @@ const ReviewConfiguration = ({ setIsFormValid }) => { description={language ? language["native-name"].v : localizationData.language} /> - {isBootIso && - <> + {!hiddenScreens.includes("accounts") && - + } + {isBootIso && - - } + } diff --git a/src/components/steps.js b/src/components/steps.js index 92e30c432..86bfa6bc8 100644 --- a/src/components/steps.js +++ b/src/components/steps.js @@ -1,5 +1,7 @@ import cockpit from "cockpit"; +import { debug } from "../helpers/log.js"; + import { Page as PageProgress } from "./installation/InstallationProgress.jsx"; import { Page as PageInstallationLanguage } from "./localization/InstallationLanguage.jsx"; import { Page as PageReviewConfiguration } from "./review/ReviewConfiguration.jsx"; @@ -10,8 +12,9 @@ import { Page as PageAccounts } from "./users/Accounts.jsx"; const _ = cockpit.gettext; -export const getSteps = (...args) => { +export const getSteps = (userInterfaceConfig, ...args) => { const mountPointMappingStep = new PageMountPointMapping(...args); + const hiddenScreens = userInterfaceConfig.hidden_screens || []; const stepsOrder = [ new PageInstallationLanguage(...args), new PageInstallationMethod(...args), @@ -26,5 +29,30 @@ export const getSteps = (...args) => { new PageReviewConfiguration(...args), new PageProgress(...args), ]; - return stepsOrder; + + /* Screens can be hidden in two ways: + * 1. Dynamically: Controlled by the 'Page.isHidden' method in individual components, + * e.g., see 'MountPointMapping.jsx'. + * 2. Statically: Configured via the 'hidden_screens' key in the 'anaconda.conf' + * For example, the 'Account Creation' screen is hidden in the 'Workstation' ISO + * because this step is handled by the 'Gnome Initial Setup' tool during the first boot. + */ + return stepsOrder + .filter(s => { + const isHidden = hiddenScreens.includes(s.id); + + if (isHidden) { + debug( + `Screen '${s.id}' will not be displayed because it is hidden by the Anaconda configuration file.` + ); + } + + return !isHidden; + }) + .map((s, i) => { + if (i === 0) { + s.isFirstScreen = true; + } + return s; + }); }; diff --git a/src/components/storage/InstallationDestination.jsx b/src/components/storage/InstallationDestination.jsx index 80b693bd1..c63ee6120 100644 --- a/src/components/storage/InstallationDestination.jsx +++ b/src/components/storage/InstallationDestination.jsx @@ -47,7 +47,7 @@ import { debug } from "../../helpers/log.js"; import { getDeviceChildren } from "../../helpers/storage.js"; import { checkIfArraysAreEqual } from "../../helpers/utils.js"; -import { StorageContext, SystemTypeContext } from "../../contexts/Common.jsx"; +import { StorageContext } from "../../contexts/Common.jsx"; import { useOriginalDevices, useOriginalExistingSystems } from "../../hooks/Storage.jsx"; @@ -237,11 +237,11 @@ const rescanDisks = (setIsRescanningDisks, dispatch, errorHandler) => { export const InstallationDestination = ({ dispatch, idPrefix, + isFirstScreen, onCritFail, setIsFormValid, }) => { const refUsableDisks = useRef(); - const isBootIso = useContext(SystemTypeContext) === "BOOT_ISO"; const { diskSelection } = useContext(StorageContext); const devices = useOriginalDevices(); @@ -276,7 +276,7 @@ export const InstallationDestination = ({ setIsFormValid(selectedDisksCnt > 0); }, [selectedDisksCnt, setIsFormValid]); - const headingLevel = isBootIso ? "h2" : "h3"; + const headingLevel = isFirstScreen ? "h3" : "h2"; return ( { }, [needsReset, setIsFormDisabled]); }; -const PageTitle = () => { - const osRelease = useContext(OsReleaseContext); - - return cockpit.format(_("Welcome. Let's install $0 now."), osRelease.REDHAT_SUPPORT_PRODUCT); -}; - export class Page { - constructor (isBootIso) { + constructor () { this.component = InstallationMethod; this.id = "installation-method"; this.label = _("Installation method"); - this.title = !isBootIso ? : null; this.usePageInit = usePageInit; } } diff --git a/src/components/storage/InstallationScenario.jsx b/src/components/storage/InstallationScenario.jsx index 8c16e971b..6c8d367c9 100644 --- a/src/components/storage/InstallationScenario.jsx +++ b/src/components/storage/InstallationScenario.jsx @@ -41,7 +41,6 @@ import { DialogsContext, StorageContext, StorageDefaultsContext, - SystemTypeContext } from "../../contexts/Common.jsx"; import { @@ -516,12 +515,12 @@ const InstallationScenarioSelector = ({ export const InstallationScenario = ({ dispatch, idPrefix, + isFirstScreen, isFormDisabled, setIsFormValid, showStorage, }) => { - const isBootIso = useContext(SystemTypeContext) === "BOOT_ISO"; - const headingLevel = isBootIso ? "h2" : "h3"; + const headingLevel = isFirstScreen ? "h3" : "h2"; const { diskSelection, storageScenarioId } = useContext(StorageContext); const devices = useOriginalDevices(); diff --git a/src/components/users/Accounts.jsx b/src/components/users/Accounts.jsx index ca8e8ca1b..745f3851f 100644 --- a/src/components/users/Accounts.jsx +++ b/src/components/users/Accounts.jsx @@ -352,11 +352,9 @@ const CustomFooter = () => { }; export class Page { - constructor (isBootIso) { + constructor () { this.component = Accounts; this.id = "accounts"; - this.isHidden = !isBootIso; this.label = _("Create Account"); - this.title = null; } } diff --git a/src/contexts/Common.jsx b/src/contexts/Common.jsx index 2ab6117a0..b29651cda 100644 --- a/src/contexts/Common.jsx +++ b/src/contexts/Common.jsx @@ -29,6 +29,7 @@ export const StorageDefaultsContext = createContext(null); export const SystemTypeContext = createContext(null); export const TargetSystemRootContext = createContext(null); export const UsersContext = createContext(null); +export const UserInterfaceContext = createContext(null); export const NetworkContext = createContext(null); export const DialogsContext = createContext(null); @@ -74,7 +75,9 @@ const SystemInfoContextWrapper = ({ children, conf, osRelease }) => { - {children} + + {children} + diff --git a/test/check-language b/test/check-language index b6efeb49c..e4a7324fc 100755 --- a/test/check-language +++ b/test/check-language @@ -90,7 +90,7 @@ class TestLanguage(VirtInstallMachineCase): i.open() # Expect the default language - this is en at this point - adjust the test when better guess is implemented - b.wait_in_text("h2", "Welcome to Fedora Linux") + b.wait_in_text("h2", "Welcome. Let's install Fedora now.") l.check_selected_locale("en_US") diff --git a/test/helpers/utils.py b/test/helpers/utils.py index 4acd47da2..9a0801b45 100644 --- a/test/helpers/utils.py +++ b/test/helpers/utils.py @@ -30,6 +30,7 @@ def pretend_live_iso(test, installer): installer.steps.hidden_steps.extend([installer.steps.ACCOUNTS, installer.steps.WELCOME]) test.restore_file('/run/anaconda/anaconda.conf') test.machine.execute("sed -i 's/type = BOOT_ISO/type = LIVE_OS/g' /run/anaconda/anaconda.conf") + test.machine.execute("sed -i '/[anaconda]/a hidden_screens = installation-language accounts' /run/anaconda/anaconda.conf") def pretend_default_scheme(test, scheme): test.restore_file('/run/anaconda/anaconda.conf')