Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes #38116 - Handle version removal for multi-CV hosts
Browse files Browse the repository at this point in the history
pavanshekar committed Jan 22, 2025
1 parent 527df0a commit c9c6b5a
Showing 4 changed files with 112 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -5,7 +5,12 @@ class ReassignObjects < Actions::Base
def plan(content_view_environment, options)
concurrence do
content_view_environment.hosts.each do |host|
plan_action(Host::Reassign, host, options[:system_content_view_id], options[:system_environment_id])
content_facet_attributes = host.content_facet
if content_facet_attributes.multi_content_view_environment?
content_facet_attributes.content_view_environments -= [content_view_environment]
else
plan_action(Host::Reassign, host, options[:system_content_view_id], options[:system_environment_id])
end
end

content_view_environment.activation_keys.each do |key|
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React, { useState, useContext } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import useDeepCompareEffect from 'use-deep-compare-effect';
import { ExpandableSection, SelectOption } from '@patternfly/react-core';
import { ExpandableSection, SelectOption, Alert, AlertActionCloseButton } from '@patternfly/react-core';
import { STATUS } from 'foremanReact/constants';
import { translate as __ } from 'foremanReact/common/I18n';
import EnvironmentPaths from '../../../../components/EnvironmentPaths/EnvironmentPaths';
import getContentViews from '../../../../ContentViewsActions';
import { selectContentViewError, selectContentViews, selectContentViewStatus } from '../../../../ContentViewSelectors';
import { selectCVHosts } from '../../../ContentViewDetailSelectors';
import AffectedHosts from '../affectedHosts';
import DeleteContext from '../DeleteContext';
import ContentViewSelect from '../../../../components/ContentViewSelect/ContentViewSelect';
@@ -25,6 +26,13 @@ const CVReassignHostsForm = () => {
cvId, versionEnvironments, selectedEnvSet, selectedEnvForHost, setSelectedEnvForHost,
currentStep, selectedCVForHosts, setSelectedCVNameForHosts, setSelectedCVForHosts,
} = useContext(DeleteContext);
const [alertDismissed, setAlertDismissed] = useState(false);
const hostResponse = useSelector(selectCVHosts);

const multiCVWarning = hostResponse?.results?.some?.(host =>
host.content_facet_attributes?.multi_content_view_environment);

const multiCVRemovalInfo = __('This content view version is used in one or more multi-environment hosts. The version will simply be removed from the multi-environment hosts. The content view and lifecycle environment you select here will only apply to single-environment hosts. See hammer activation-key --help for more details.');

// Fetch content views for selected environment to reassign hosts to.
useDeepCompareEffect(
@@ -103,6 +111,17 @@ const CVReassignHostsForm = () => {

return (
<>
{!alertDismissed && multiCVWarning && (
<Alert
ouiaId="multi-cv-warning-alert"
variant="warning"
isInline
title={__('Warning')}
actionClose={<AlertActionCloseButton onClose={() => setAlertDismissed(true)} />}
>
<p>{multiCVRemovalInfo}</p>
</Alert>
)}
<EnvironmentPaths
userCheckedItems={selectedEnvForHost}
setUserCheckedItems={setSelectedEnvForHost}
Original file line number Diff line number Diff line change
@@ -2,10 +2,10 @@ import React, { useContext, useState } from 'react';
import { useSelector } from 'react-redux';
import { Alert, Flex, FlexItem, Label, AlertActionCloseButton } from '@patternfly/react-core';
import { ExclamationTriangleIcon } from '@patternfly/react-icons';
import { FormattedMessage } from 'react-intl';
import { translate as __ } from 'foremanReact/common/I18n';
import { selectCVActivationKeys, selectCVHosts } from '../../../ContentViewDetailSelectors';
import DeleteContext from '../DeleteContext';
import { pluralize } from '../../../../../../utils/helpers';
import WizardHeader from '../../../../components/WizardHeader';

const CVVersionRemoveReview = () => {
@@ -17,13 +17,19 @@ const CVVersionRemoveReview = () => {
} = useContext(DeleteContext);
const activationKeysResponse = useSelector(state => selectCVActivationKeys(state, cvId));
const hostsResponse = useSelector(state => selectCVHosts(state, cvId));
const { results: hostResponse } = hostsResponse;
const { results: hostResponse = [] } = hostsResponse || {};
const { results: akResponse = [] } = activationKeysResponse || {};
const selectedEnv = versionEnvironments.filter(env => selectedEnvSet.has(env.id));
const versionDeleteInfo = __(`Version ${versionNameToRemove} will be deleted from all environments. It will no longer be available for promotion.`);
const removalNotice = __(`Version ${versionNameToRemove} will be removed from the environments listed below, and will remain available for later promotion. ` +
'Changes listed below will be effective after clicking Remove.');

const multiCVHosts = hostResponse?.filter(host =>
host.content_facet_attributes?.multi_content_view_environment) || [];
const multiCVHostsCount = multiCVHosts.length;

const singleCVHostsCount = (hostResponse?.length || 0) - multiCVHostsCount;

const multiCVActivationKeys = akResponse.filter(key => key.multi_content_view_environment);
const multiCVActivationKeysCount = multiCVActivationKeys.length;

@@ -58,29 +64,91 @@ const CVVersionRemoveReview = () => {
{affectedHosts &&
<>
<h3>{__('Content hosts')}</h3>
<Flex>
<FlexItem><ExclamationTriangleIcon /></FlexItem>
<FlexItem><p>{__(`${pluralize(hostResponse.length, 'host')} will be moved to content view ${selectedCVNameForHosts} in `)}</p></FlexItem>
<FlexItem><Label isTruncated color="purple" href={`/lifecycle_environments/${selectedEnvForHost[0].id}`}>{selectedEnvForHost[0].name}</Label></FlexItem>
</Flex>
{singleCVHostsCount > 0 && (
<Flex>
<FlexItem><ExclamationTriangleIcon /></FlexItem>
<FlexItem>
<FormattedMessage
id="single-cv-hosts-remove"
defaultMessage="{count, plural, one {{singular}} other {# {plural}}} will be moved to content view {cvName} in {envName}."
values={{
count: singleCVHostsCount,
singular: __('host'),
plural: __('hosts'),
cvName: selectedCVNameForHosts,
envName: selectedEnvForHost[0] && (
<Label isTruncated color="purple" href={`/lifecycle_environments/${selectedEnvForHost[0].id}`}>
{selectedEnvForHost[0].name}
</Label>
),
}}
/>
</FlexItem>
</Flex>
)}
{multiCVHostsCount > 0 && (
<Flex>
<FlexItem><ExclamationTriangleIcon /></FlexItem>
<FlexItem>
<FormattedMessage
id="multi-cv-hosts-remove"
defaultMessage="Content view {envSingularOrPlural} {envCV} will be removed from {count, plural, one {# {hostSingular}} other {# {hostPlural}}}."
values={{
envSingularOrPlural: selectedEnv?.length === 1 ? __('environment') : __('environments'),
envCV: selectedEnv
?.map(({ name }) => `${name}/${multiCVHosts[0]?.content_facet_attributes?.content_view?.name}`)
.join(', '),
count: multiCVHostsCount,
hostSingular: __('multi-environment host'),
hostPlural: __('multi-environment hosts'),
}}
/>
</FlexItem>
</Flex>
)}
</>}
{affectedActivationKeys &&
<>
<h3>{__('Activation keys')}</h3>
{singleCVActivationKeysCount > 0 && (
<Flex>
<FlexItem><ExclamationTriangleIcon /></FlexItem>
<FlexItem><p>{__(`${pluralize(singleCVActivationKeysCount, 'activation key')} will be moved to content view ${selectedCVNameForAK} in `)}</p></FlexItem>
<FlexItem><Label isTruncated color="purple" href={`/lifecycle_environments/${selectedEnvForAK[0].id}`}>{selectedEnvForAK[0].name}</Label></FlexItem>
<FlexItem>
<FormattedMessage
id="single-cv-activation-keys-remove"
defaultMessage="{count, plural, one {{singular}} other {# {plural}}} will be moved to content view {cvName} in {envName}."
values={{
count: singleCVActivationKeysCount,
singular: __('activation key'),
plural: __('activation keys'),
cvName: selectedCVNameForAK,
envName: selectedEnvForAK[0] && (
<Label isTruncated color="purple" href={`/lifecycle_environments/${selectedEnvForAK[0].id}`}>
{selectedEnvForAK[0].name}
</Label>
),
}}
/>
</FlexItem>
</Flex>
)}
{multiCVActivationKeysCount > 0 && (
<Flex>
<FlexItem><ExclamationTriangleIcon /></FlexItem>
<FlexItem>
<p>
{__(`Content view environment will be removed from ${pluralize(multiCVActivationKeysCount, 'multi-environment activation key')}.`)}
</p>
<FormattedMessage
id="multi-cv-activation-keys-remove"
defaultMessage="Content view {envSingularOrPlural} {envCV} will be removed from {count, plural, one {# {keySingular}} other {# {keyPlural}}}."
values={{
envSingularOrPlural: selectedEnv?.length === 1 ? __('environment') : __('environments'),
envCV: selectedEnv
?.map(({ name }) => `${name}/${multiCVActivationKeys[0]?.content_view?.name}`)
.join(', '),
count: multiCVActivationKeysCount,
keySingular: __('multi-environment activation key'),
keyPlural: __('multi-environment activation keys'),
}}
/>
</FlexItem>
</Flex>
)}
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@ const AffectedHosts = ({
const columnHeaders = [
__('Name'),
__('Environment'),
__('Multi Content View Environment'),
];
const emptyContentTitle = __('No matching hosts found.');
const emptyContentBody = __("Given criteria doesn't match any hosts. Try changing your rule.");
@@ -63,13 +64,17 @@ const AffectedHosts = ({
{results?.map(({
name,
id,
content_facet_attributes: { lifecycle_environment: environment },
content_facet_attributes: {
lifecycle_environment: environment,
multi_content_view_environment: multiContentViewEnvironment,
},
}) => (
<Tr ouiaId={id} key={id}>
<Td>
<a rel="noreferrer" target="_blank" href={urlBuilder(`new/hosts/${id}`, '')}>{name}</a>
</Td>
<Td><EnvironmentLabels environments={environment} /></Td>
<Td>{ multiContentViewEnvironment ? __('Yes') : __('No') }</Td>
</Tr>
))
}

0 comments on commit c9c6b5a

Please sign in to comment.