/* * Copyright (C) 2025 Red Hat, Inc. * SPDX-License-Identifier: LGPL-2.1-or-later */ import cockpit from "cockpit"; import React, { useContext, useEffect, useMemo } from "react"; import { Form, FormGroup } from "@patternfly/react-core/dist/esm/components/Form/index.js"; import { Flex } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js"; import { getDefaultEnvironment, resolveEnvironment, setPackagesSelection } from "../../apis/payload_dnf.js"; import { PageContext, PayloadContext } from "../../contexts/Common.jsx"; import { MenuSearch } from "../common/MenuSearch.jsx"; import "./SoftwareSelection.scss"; const _ = cockpit.gettext; const SCREEN_ID = "anaconda-screen-software-selection"; const EnvironmentSelection = () => { const { environments, selection } = useContext(PayloadContext); const environment = selection?.environment; useEffect(() => { (async () => { if (!environment) { const defaultEnv = await getDefaultEnvironment(); await setPackagesSelection({ environment: defaultEnv, groups: [] }); } })(); }, [environment]); const options = useMemo(() => { if (!environments) { return []; } return environments.map((env) => ({ id: `${SCREEN_ID}-environment-${env.id}`, itemDescription: env.description, itemId: env.id, itemText: env.name, itemType: "menu-item", key: `environment-${env.id}`, onSearch: (search) => { const searchLower = search.toLowerCase(); return env.name.toLowerCase().includes(searchLower) || (env.description && env.description.toLowerCase().includes(searchLower)); }, })); }, [environments]); const handleOnSelect = (_ev, itemId) => { // Reset groups selection when changing environment setPackagesSelection({ environment: itemId, groups: [] }); }; return ( ); }; const GroupPackagesSelection = () => { const { groups, selection } = useContext(PayloadContext); const selectedGroups = selection?.groups || []; const groupOptions = useMemo(() => { if (!groups) { return []; } const optionalGroups = groups.filter(group => group.isOptional); const visibleGroups = groups.filter(group => !group.isOptional); const optionalGroupItems = optionalGroups.map((group) => ({ id: `${SCREEN_ID}-group-${group.id}`, itemDescription: group.description, itemId: group.id, itemText: group.name, itemType: "menu-item", key: `group-${group.id}`, onSearch: (search) => { const searchLower = search.toLowerCase(); return group.name.toLowerCase().includes(searchLower) || (group.description && group.description.toLowerCase().includes(searchLower)); }, })); const visibleGroupItems = visibleGroups.map((group) => ({ id: `${SCREEN_ID}-group-${group.id}`, itemDescription: group.description, itemId: group.id, itemText: group.name, itemType: "menu-item", key: `group-${group.id}`, onSearch: (search) => { const searchLower = search.toLowerCase(); return group.name.toLowerCase().includes(searchLower) || (group.description && group.description.toLowerCase().includes(searchLower)); }, })); const options = []; if (optionalGroupItems.length > 0) { options.push({ id: `${SCREEN_ID}-optional-groups`, itemChildren: optionalGroupItems, itemLabel: _("Add-ons for your chosen environment"), itemType: "menu-group", key: "optional-groups", }); } if (visibleGroupItems.length > 0) { options.push({ id: `${SCREEN_ID}-visible-groups`, itemChildren: visibleGroupItems, itemLabel: _("Add-ons not specific to your environment"), itemType: "menu-group", key: "visible-groups", }); } return options; }, [groups]); const handleGroupSelect = async (_ev, groupId) => { // Toggle selection let newSelectedGroups; if (selectedGroups.includes(groupId)) { newSelectedGroups = selectedGroups.filter(id => id !== groupId); } else { newSelectedGroups = [...selectedGroups, groupId]; } // Update packages selection await setPackagesSelection({ groups: newSelectedGroups }); }; return ( ); }; export const SoftwareSelection = ({ automatedInstall }) => { const { setIsFormValid } = useContext(PageContext) ?? {}; const { packagesKickstarted, selection } = useContext(PayloadContext); const environment = selection?.environment; /* * Match pyanaconda.ui.lib.software.is_software_selection_complete (and GTK spoke `completed`). * kickstarted=True in Anaconda means flags.automatedInstall and payload PackagesKickstarted. */ useEffect(() => { const kickstarted = packagesKickstarted === true && automatedInstall === true; (async () => { if (kickstarted && !environment) { setIsFormValid(true); return; } if (!environment) { setIsFormValid(false); return; } const resolved = await resolveEnvironment(environment); setIsFormValid(Boolean(resolved)); })(); }, [environment, packagesKickstarted, automatedInstall, setIsFormValid]); return (
); };