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},
}}
/>
);
};
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: '',
};