Revision 737a6f2e
Added by Jeremy Lenz about 1 month ago
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
Fixes #37313 - Change Content Source form improvements (#10955)