Project

General

Profile

« Previous | Next » 

Revision 737a6f2e

Added by Jeremy Lenz about 1 month ago

Fixes #37313 - Change Content Source form improvements (#10955)

View differences:

app/views/overrides/activation_keys/_host_environment_select.html.erb
<% if edit_action? && !using_hostgroups_page? && !using_discovered_hosts_page? %>
<div style="margin-left: 270px">
<%= link_to _("Change content source"), "/change_host_content_source?host_id=#{@host.id}" %>
<%= link_to _("Change content source"), "/change_host_content_source?fromPage=hostEdit&host_id=#{@host.id}&initialContentSourceId=#{@host.content_source_id}" %>
</div>
<% end %>
webpack/components/extensions/HostDetails/ActionsBar/index.js
<DropdownItem
ouiaId="katello-change-host-content-source"
key="katello-change-host-content-source"
href={foremanUrl(`/change_host_content_source?host_id=${hostDetails?.id}`)}
href={foremanUrl(`/change_host_content_source?host_id=${hostDetails?.id}&initialContentSourceId=${hostDetails?.content_facet_attributes?.content_source_id}`)}
icon={<CubeIcon />}
>
{__('Change content source')}
webpack/scenes/Hosts/ChangeContentSource/actions.js
}));
export const changeContentSource =
(environmentId, contentViewId, contentSourceId, hostIds, handleSuccess) =>
(environmentId, contentViewId, contentSourceId, hostIds, handleSuccess, successToast) =>
put({
key: CHANGE_CONTENT_SOURCE,
url: foremanUrl('/api/v2/hosts/bulk/change_content_source'),
......
host_ids: hostIds,
},
errorToast: () => __('Something went wrong while updating the content source. See the logs for more information'),
successToast,
handleSuccess,
});
webpack/scenes/Hosts/ChangeContentSource/components/ContentSourceForm.js
import EnvironmentPaths from '../../../../scenes/ContentViews/components/EnvironmentPaths/EnvironmentPaths';
import ContentViewSelect from '../../../../scenes/ContentViews/components/ContentViewSelect/ContentViewSelect';
import ContentViewSelectOption from '../../../../scenes/ContentViews/components/ContentViewSelect/ContentViewSelectOption';
import { selectContentViewsStatus } from '../selectors';
import { selectContentViewsStatus, selectJobInvocationPath } from '../selectors';
import { getCVPlaceholderText, shouldDisableCVSelect } from '../../../ContentViews/components/ContentViewSelect/helpers';
import { selectEnvironmentPaths } from '../../../ContentViews/components/EnvironmentPaths/EnvironmentPathSelectors';
......
contentSources,
handleContentSource,
contentSourceId,
showCVOnlyAlert,
hostDetailsPath,
hostEditPath,
contentHosts,
isLoading,
hostsUpdated,
......
);
const contentViewsStatus = useSelector(selectContentViewsStatus);
const environmentPathResponse = useSelector(selectEnvironmentPaths);
const jobInvocationPath = useSelector(selectJobInvocationPath);
const envList = environmentPathResponse?.results?.map(path => path.environments).flat();
const [csSelectOpen, setCSSelectOpen] = useState(false);
const [cvSelectOpen, setCVSelectOpen] = useState(false);
......
!!contentViewName &&
!!contentSourceId &&
hostCount !== 0);
const contentSourcesIsDisabled = (isLoading || contentSources.length === 0 ||
hostCount === 0);
const environmentIsDisabled = (isLoading || environments === [] ||
const environmentIsDisabled = (isLoading ||
contentSourceId === '');
const viewIsDisabled = (isLoading || contentViews.length === 0 ||
contentSourceId === '' || environments === []);
contentSourceId === '');
const cvPlaceholderText = getCVPlaceholderText({
contentSourceId,
......
env={environments[0]}
/>))}
</ContentViewSelect>
{showCVOnlyAlert &&
<Alert
ouiaId="cv-only-alert"
variant="info"
className="margin-top-20"
title={__('Host content source will remain the same. Click Save below to update the host\'s content view environment.')}
/>
}
{!showCVOnlyAlert &&
<TextContent>
<Text
ouiaId="ccs-options-description"
......
/>
</Text>
</TextContent>
}
<ActionGroup style={{ display: 'block' }}>
<Button
variant="primary"
id="generate_btn"
ouiaId="update-source-button"
onClick={e => handleSubmit(e, { shouldRedirect: true })}
isDisabled={isLoading || !formIsValid() || hostsUpdated}
isLoading={isLoading}
>
{__('Run job invocation')}
</Button>
<Button
variant="secondary"
id="generate_btn"
ouiaId="update-source-button"
onClick={showTemplate}
isDisabled={isLoading || !formIsValid() || hostsUpdated}
isLoading={isLoading}
>
{__('Update hosts manually')}
</Button>
{!showCVOnlyAlert &&
<>
<Button
variant="primary"
id="generate_btn"
ouiaId="run-job-invocation-button"
onClick={e => handleSubmit(e, { redirectTo: jobInvocationPath })}
isDisabled={isLoading || !formIsValid() || hostsUpdated}
isLoading={isLoading}
>
{__('Run job invocation')}
</Button>
<Button
variant="secondary"
id="generate_btn"
ouiaId="update-source-button"
onClick={showTemplate}
isDisabled={isLoading || !formIsValid() || hostsUpdated}
isLoading={isLoading}
>
{__('Update hosts manually')}
</Button>
</>
}
{showCVOnlyAlert &&
<Button
variant="primary"
id="generate_btn"
ouiaId="change-cv-button"
onClick={e =>
handleSubmit(e, {
redirectTo: hostEditPath || hostDetailsPath,
showSuccessToast: true,
})
}
isDisabled={isLoading || !formIsValid() || hostsUpdated}
isLoading={isLoading}
>
{__('Save')}
</Button>
}
</ActionGroup>
</Form>);
......
contentSources: PropTypes.arrayOf(PropTypes.shape({})),
handleContentSource: PropTypes.func.isRequired,
contentSourceId: PropTypes.string,
showCVOnlyAlert: PropTypes.bool,
hostDetailsPath: PropTypes.string.isRequired,
hostEditPath: PropTypes.string.isRequired,
contentHosts: PropTypes.arrayOf(PropTypes.shape({})),
isLoading: PropTypes.bool,
hostsUpdated: PropTypes.bool,
......
contentViewName: '',
contentSources: [],
contentSourceId: '',
showCVOnlyAlert: false,
contentHosts: [],
isLoading: false,
hostsUpdated: false,
webpack/scenes/Hosts/ChangeContentSource/index.js
selectContentHosts,
selectContentHostsWithoutContent,
selectContentSources,
selectJobInvocationPath,
selectContentViews,
selectTemplate } from './selectors';
......
const contentHosts = useSelector(selectContentHosts);
const hostsWithoutContent = useSelector(selectContentHostsWithoutContent);
const contentSources = useSelector(selectContentSources);
const jobInvocationPath = useSelector(selectJobInvocationPath);
const template = useSelector(selectTemplate);
const contentViews = useSelector(selectContentViews);
const [contentSourceId, setCapsuleId] = useState('');
const { initialContentSourceId } = urlParams;
const [contentSourceId, setCapsuleId] = useState(initialContentSourceId ?? '');
// if this matches, we'll trust you that initialContentSourceId is the host's content source
const showCVOnlyAlert = (contentHosts.length === 1 &&
hostsWithoutContent.length === 0 &&
!!initialContentSourceId &&
initialContentSourceId === contentSourceId
);
const hostDetailsPath = showCVOnlyAlert ? `new/hosts/${contentHosts[0].name}` : '';
const hostEditPath = urlParams.fromPage === 'hostEdit' ? foremanUrl(`/hosts/${contentHosts[0]?.name}/edit`) : '';
const [selectedEnvironment, setSelectedEnvironment] = useState([]);
const [contentViewName, setContentViewName] = useState('');
const [shouldShowTemplate, setShouldShowTemplate] = useState(false);
const [redirect, setRedirect] = useState(false);
const [redirect, setRedirect] = useState('');
const contentViewId = contentViews?.find(cv => cv.name === contentViewName)?.id;
const hostIds = useMemo(() => getHostIds(urlParams.host_id), [urlParams.host_id]);
const noHostSpecified = (hostIds.length === 0 && urlParams.searchParam === '');
const environmentId = selectedEnvironment[0]?.id;
const redirectToJobInvocationForm = () => setRedirect(true);
const handleSuccess = ({ shouldRedirect }) => {
if (shouldRedirect) {
redirectToJobInvocationForm();
const handleSuccess = ({ redirectTo = '' }) => {
if (redirectTo) {
setRedirect(redirectTo);
}
};
const handleSubmit = (e, { shouldRedirect = false }) => {
const handleSubmit = (e, { redirectTo = '', showSuccessToast = false } = {}) => {
e.preventDefault();
dispatch(changeContentSource(
......
contentViewId,
contentSourceId,
contentHosts.map(h => h.id),
() => handleSuccess({ shouldRedirect }),
() => handleSuccess({ redirectTo }),
showSuccessToast ? () => __('Host content view environment(s) updated') : undefined,
));
};
......
};
const showTemplate = (e) => {
handleSubmit(e, { shouldRedirect: false });
handleSubmit(e);
setShouldShowTemplate(true);
};
......
dispatch(getFormData(hostIds, urlParams.searchParam));
}, [dispatch, hostIds, urlParams.searchParam]);
if (redirect && jobInvocationPath) {
window.location.assign(jobInvocationPath); // redirect to job invocation wizard
if (redirect && redirect !== '') {
window.location.assign(redirect);
}
return (
......
title={__('No hosts were specified')}
/>
</GridItem>
}
}
{ !noHostSpecified &&
<>
<Hosts
......
contentViewName={contentViewName}
contentSources={contentSources}
contentSourceId={contentSourceId}
showCVOnlyAlert={showCVOnlyAlert}
hostDetailsPath={hostDetailsPath}
hostEditPath={hostEditPath}
handleContentSource={handleContentSource}
contentHosts={contentHosts}
isLoading={isLoading}

Also available in: Unified diff