import React, { useState, useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { isEqual } from 'lodash'; import PropTypes from 'prop-types'; import { STATUS } from 'foremanReact/constants'; import { propsToCamelCase } from 'foremanReact/common/helpers'; import { Modal, Button, Form, FormGroup, FormSelect, FormSelectOption, Select, SelectOption, SelectVariant, } from '@patternfly/react-core'; import { FormattedMessage } from 'react-intl'; import { translate as __ } from 'foremanReact/common/I18n'; import { selectOrganizationStatus, selectOrganization, selectAvailableReleaseVersions, selectAvailableReleaseVersionsStatus } from './SystemPurposeSelectors'; import { getAvailableReleaseVersions, getOrganization, updateSystemPurposeAttributes } from './SystemPurposeActions'; import HOST_DETAILS_KEY from '../../HostDetailsConstants'; import { defaultUsages, defaultRoles, defaultServiceLevels } from './SystemPurposeConstants'; const SystemPurposeEditModal = ({ closeModal, hostName, purposeRole, purposeUsage, purposeAddons, serviceLevel, releaseVersion, isOpen, orgId, hostId, }) => { const initialPurposeRole = purposeRole ?? ''; const initialServiceLevel = serviceLevel ?? ''; const initialPurposeUsage = purposeUsage ?? ''; const initialReleaseVersion = releaseVersion ?? ''; const initialPurposeAddons = purposeAddons ?? []; const [selectedRole, setSelectedRole] = useState(initialPurposeRole); const [selectedServiceLevel, setSelectedServiceLevel] = useState(initialServiceLevel); const [selectedUsage, setSelectedUsage] = useState(initialPurposeUsage); const [addonSelectOpen, setAddonSelectOpen] = useState(false); const [selectedAddons, setSelectedAddons] = useState(initialPurposeAddons); const [selectedReleaseVersion, setSelectedReleaseVersion] = useState(initialReleaseVersion); const unmodified = ( selectedRole === initialPurposeRole && selectedServiceLevel === initialServiceLevel && selectedUsage === initialPurposeUsage && selectedReleaseVersion === initialReleaseVersion && isEqual(selectedAddons, initialPurposeAddons) ); const dispatch = useDispatch(); const orgStatus = useSelector(state => selectOrganizationStatus(state, orgId)); const organizationDetails = useSelector(state => selectOrganization(state, orgId)); const orgDetails = propsToCamelCase(organizationDetails ?? { systemPurposes: {} }); const availableSyspurposeAttributes = orgDetails?.systemPurposes ?? {}; const availableServiceLevels = orgDetails?.serviceLevels ?? []; const { addons: availableAddons, roles: availableRoles, usage: availableUsages } = availableSyspurposeAttributes; const availableReleaseVersionsStatus = useSelector(state => selectAvailableReleaseVersionsStatus(state, orgId)); const availableReleaseVersions = useSelector(state => selectAvailableReleaseVersions(state, hostId))?.results ?? []; useEffect(() => { if (orgId && orgStatus !== STATUS.RESOLVED) { dispatch(getOrganization({ orgId })); } }, [orgId, orgStatus, dispatch]); useEffect(() => { if (hostId && availableReleaseVersionsStatus !== STATUS.RESOLVED) { dispatch(getAvailableReleaseVersions({ hostId })); } }, [hostId, availableReleaseVersionsStatus, dispatch]); const toggleAddonSelect = isOpenState => setAddonSelectOpen(isOpenState); const onAddonSelect = (_event, selected) => { const newSelectedAddons = new Set(selectedAddons); if (!selected) return; if (newSelectedAddons.has(selected)) { newSelectedAddons.delete(selected); } else { newSelectedAddons.add(selected); } setSelectedAddons([...newSelectedAddons]); }; const refreshHostDetails = () => dispatch({ type: 'API_GET', payload: { key: HOST_DETAILS_KEY, url: `/api/hosts/${hostName}`, }, }); // Building the dropdown options is a bit complex because they come from several sources: // 1. The hard-coded set of default values (defaultOptions) // 2. The set of available values from the API (additionalOptions) // 3. The value actually set on the host (initialOption - this need not be a value from 1 or 2) // We then need to combine these values into a single set of options, and ensure that // (a) (unset) appears first; // (b) there are no duplicate options; // (c) that the currently selected option always appears (currentSelected); and // (d) that the order of the items doesn't change unexpectedly. const buildOptions = (defaultOptions, additionalOptions, currentSelected, initialOption) => { const optionToObject = option => ({ label: option || __('(unset)'), value: option }); const uniqOptions = new Set(['', ...defaultOptions ?? [], ...additionalOptions ?? [], currentSelected, initialOption]); uniqOptions.delete(null); uniqOptions.delete(undefined); return [...[...uniqOptions]?.map(optionToObject)]; }; const roleOptions = buildOptions(defaultRoles, availableRoles, selectedRole, purposeRole); const usageOptions = buildOptions(defaultUsages, availableUsages, selectedUsage, purposeUsage); // addons may be present on the host but not available from subscriptions, // so we combine the options here const addonToObject = addon => ({ label: addon, value: addon }); const addonsOptions = [...new Set([ // don't repeat addons if they are already selected ...purposeAddons.map(addonToObject), ...availableAddons?.map(addonToObject) ?? [], ])]; const serviceLevelOptions = buildOptions(defaultServiceLevels, availableServiceLevels, selectedServiceLevel, serviceLevel); const releaseVersionOptions = buildOptions([], availableReleaseVersions, selectedReleaseVersion, releaseVersion); const handleSave = (event) => { event.preventDefault(); closeModal(); const optionsToValue = (options, stateValue) => options.find(option => option.value === stateValue)?.value; dispatch(updateSystemPurposeAttributes({ hostId, attributes: { autoheal: true, purpose_role: optionsToValue(roleOptions, selectedRole), purpose_usage: optionsToValue(usageOptions, selectedUsage), purpose_addons: selectedAddons, release_version: optionsToValue(releaseVersionOptions, selectedReleaseVersion), service_level: optionsToValue(serviceLevelOptions, selectedServiceLevel), }, refreshHostDetails, })); }; const handleCancel = () => { setSelectedRole(initialPurposeRole); setSelectedServiceLevel(initialServiceLevel); setSelectedUsage(initialPurposeUsage); setSelectedAddons(initialPurposeAddons); setSelectedReleaseVersion(initialReleaseVersion); closeModal(); }; const modalActions = ([ , , ]); return ( {hostName}, }} />
{roleOptions.map(option => ( ))} {serviceLevelOptions.map(option => ( ))} {usageOptions.map(option => ( ))} {releaseVersionOptions.map(option => ( ))}
); }; export default SystemPurposeEditModal; SystemPurposeEditModal.propTypes = { closeModal: PropTypes.func.isRequired, hostName: PropTypes.string, purposeRole: PropTypes.string.isRequired, purposeUsage: PropTypes.string.isRequired, purposeAddons: PropTypes.arrayOf(PropTypes.string).isRequired, serviceLevel: PropTypes.string.isRequired, releaseVersion: PropTypes.string, isOpen: PropTypes.bool.isRequired, orgId: PropTypes.number, hostId: PropTypes.number, }; SystemPurposeEditModal.defaultProps = { hostName: '', orgId: null, hostId: null, releaseVersion: '', };