webpack/scenes/Hosts/ChangeContentSource/index.js
import React, { useState, useEffect, useMemo } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { Alert, Grid, GridItem, PageSection, Title, Text, TextContent } from '@patternfly/react-core';
import { translate as __ } from 'foremanReact/common/I18n';
import { foremanUrl } from 'foremanReact/common/helpers';
import { STATUS } from 'foremanReact/constants';
import BreadcrumbBar from 'foremanReact/components/BreadcrumbBar';
import Head from 'foremanReact/components/Head';
import { useForemanHostsPageUrl } from 'foremanReact/Root/Context/ForemanContext';
import { useUrlParams } from 'foremanReact/components/PF4/TableIndexPage/Table/TableHooks';
import { selectApiDataStatus,
selectApiContentViewStatus,
selectApiChangeContentStatus,
selectContentHosts,
selectContentHostsWithoutContent,
selectContentSources,
selectContentViews,
selectTemplate } from './selectors';
import { getHostIds, formIsLoading } from './helpers';
import {
getFormData,
getProxy,
changeContentSource,
getContentViews,
} from './actions';
import ContentSourceForm from './components/ContentSourceForm';
import ContentSourceTemplate from './components/ContentSourceTemplate';
import Hosts from './components/Hosts';
import './styles.scss';
const ChangeContentSourcePage = () => {
const dispatch = useDispatch();
const urlParams = useUrlParams();
const apiDataStatus = useSelector(selectApiDataStatus);
const apiContentViewStatus = useSelector(selectApiContentViewStatus);
const apiChangeStatus = useSelector(selectApiChangeContentStatus);
const isLoading = formIsLoading(apiDataStatus, apiContentViewStatus, apiChangeStatus);
const contentHosts = useSelector(selectContentHosts);
const hostsWithoutContent = useSelector(selectContentHostsWithoutContent);
const contentSources = useSelector(selectContentSources);
const template = useSelector(selectTemplate);
const contentViews = useSelector(selectContentViews);
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('');
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 handleSuccess = ({ redirectTo = '' }) => {
if (redirectTo) {
setRedirect(redirectTo);
}
};
const handleSubmit = (e, { redirectTo = '', showSuccessToast = false } = {}) => {
e.preventDefault();
dispatch(changeContentSource(
environmentId,
contentViewId,
contentSourceId,
contentHosts.map(h => h.id),
() => handleSuccess({ redirectTo }),
showSuccessToast ? () => __('Host content view environment(s) updated') : undefined,
));
};
const handleContentSource = (id) => {
setCapsuleId(id);
setSelectedEnvironment([]);
setContentViewName('');
if (id) {
dispatch(getProxy(id));
}
};
const showTemplate = (e) => {
handleSubmit(e);
setShouldShowTemplate(true);
};
const hostIndexUrl = useForemanHostsPageUrl();
const breadcrumbItems = () => {
const linkHosts = { caption: __('Hosts'), url: hostIndexUrl };
const linkContent = { caption: __('Change host content source') };
if (urlParams.host_id) {
const hostName = contentHosts.concat(hostsWithoutContent)
.find(h => `${h.id}` === urlParams.host_id)?.name;
return ([linkHosts, { caption: hostName, url: foremanUrl(`/new/hosts/${hostName}`) }, linkContent]);
}
return ([linkHosts, linkContent]);
};
const handleEnvironment = (selection) => {
setSelectedEnvironment(selection);
setContentViewName('');
if (selection[0].id) {
dispatch(getContentViews(selection[0].id));
}
};
useEffect(() => {
dispatch(getFormData(hostIds, urlParams.searchParam));
}, [dispatch, hostIds, urlParams.searchParam]);
if (redirect && redirect !== '') {
window.location.assign(redirect);
}
return (
<>
<Head>
<title>{__('Change host content source')}</title>
</Head>
<PageSection
isFilled
variant="light"
>
<div className="margin-left-20">
<BreadcrumbBar
breadcrumbItems={breadcrumbItems()}
/>
</div>
<Grid className="margin-left-20">
<GridItem span={7}>
<Title
ouiaId="change-cs-title"
headingLevel="h5"
size="2xl"
className="margin-top-20"
>
{__('Change host content source')}
</Title>
<TextContent>
<Text ouiaId="change-content-source-description" id="ccs-description">
{__('Changing a host\'s content source will change the Smart Proxy from which the host gets its content.')}
</Text>
</TextContent>
</GridItem>
{noHostSpecified &&
<GridItem span={7}>
<Alert
ouiaId="no-host-alert"
variant="danger"
className="margin-top-20"
title={__('No hosts were specified')}
/>
</GridItem>
}
{ !noHostSpecified &&
<>
<Hosts
contentHosts={contentHosts}
hostsWithoutContent={hostsWithoutContent}
/>
<ContentSourceForm
handleSubmit={handleSubmit}
handleEnvironment={handleEnvironment}
environments={selectedEnvironment}
contentViews={contentViews}
handleContentView={setContentViewName}
contentViewName={contentViewName}
contentSources={contentSources}
contentSourceId={contentSourceId}
showCVOnlyAlert={showCVOnlyAlert}
hostDetailsPath={hostDetailsPath}
hostEditPath={hostEditPath}
handleContentSource={handleContentSource}
contentHosts={contentHosts}
isLoading={isLoading}
hostsUpdated={apiChangeStatus === STATUS.RESOLVED || shouldShowTemplate}
showTemplate={showTemplate}
/>
</> }
{ (apiChangeStatus === STATUS.RESOLVED && shouldShowTemplate) &&
<ContentSourceTemplate template={template} hostCount={contentHosts.length} /> }
</Grid>
</PageSection>
</>
);
};
export default ChangeContentSourcePage;