Skip to content

Commit

Permalink
Behave the same as 1.8.4 on a new migration plan (#1526)
Browse files Browse the repository at this point in the history
The loading behavior was modified in 1.8.5 and
the grid loading was not behaving the same as
1.8.4 when creating a new direct volume migration
plan. The spinner was not covering the grid and
the grid was showing the empty state.

Instead revert to covering the entire grid. And
only show the validating spinner when the grid
selection changed.

Signed-off-by: Alexander Wels <[email protected]>
  • Loading branch information
awels authored Oct 28, 2024
1 parent f78ff94 commit f9dad67
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 16 deletions.
22 changes: 18 additions & 4 deletions src/app/home/pages/PlansPage/components/PlanStatusIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import React from 'react';

import WarningTriangleIcon from '@patternfly/react-icons/dist/js/icons/warning-triangle-icon';
import OutlinedCircleIcon from '@patternfly/react-icons/dist/js/icons/outlined-circle-icon';
import ExclamationCircleIcon from '@patternfly/react-icons/dist/js/icons/exclamation-circle-icon';
import OutlinedCircleIcon from '@patternfly/react-icons/dist/js/icons/outlined-circle-icon';
import ResourcesAlmostEmptyIcon from '@patternfly/react-icons/dist/js/icons/resources-almost-empty-icon';
import ResourcesFullIcon from '@patternfly/react-icons/dist/js/icons/resources-full-icon';

import { Popover, PopoverPosition } from '@patternfly/react-core';

import { Spinner } from '@patternfly/react-core';
import { ICondition, IPlan } from '../../../../plan/duck/types';
import { ExclamationTriangleIcon } from '@patternfly/react-icons/dist/js/icons/exclamation-triangle-icon';
import { IPlan } from '../../../../plan/duck/types';
const styles = require('./PlanStatus.module').default;

interface IProps {
Expand All @@ -29,6 +28,7 @@ const PlanStatusIcon: React.FunctionComponent<IProps> = ({ plan }) => {
hasConflictCondition = null,
latestIsFailed = null,
hasCriticalCondition = null,
hasNotSupportedCondition = null,
hasWarnCondition = null,
hasDVMBlockedCondition = null,
} = plan?.PlanStatus;
Expand All @@ -43,7 +43,21 @@ const PlanStatusIcon: React.FunctionComponent<IProps> = ({ plan }) => {
return (
<Popover
position={PopoverPosition.top}
bodyContent="Migration plan conflicts occur when multiple plans share the same namespace. You cannot stage or migrate a plan with a conflict. Delete one of the plans to resolve the conflict."
bodyContent="Migration plan conflicts occur when multiple plans share the same namespace. You cannot stage or migrate a plan with a conflict. Modify one of the plans to resolve the conflict."
aria-label="warning-details"
closeBtnAriaLabel="close-warning-details"
maxWidth="200rem"
>
<span className={`${styles.planStatusIcon} pf-c-icon pf-m-warning`}>
<ExclamationTriangleIcon />
</span>
</Popover>
);
} else if (hasNotSupportedCondition) {
return (
<Popover
position={PopoverPosition.top}
bodyContent="The installed version of OpenShift Virtualization does support or has not enabled storage live migration. Instead of live migrating the storage, the virtual machine(s) will be shutdown and restarted after migration"
aria-label="warning-details"
closeBtnAriaLabel="close-warning-details"
maxWidth="200rem"
Expand Down
41 changes: 40 additions & 1 deletion src/app/home/pages/PlansPage/components/Wizard/VolumesForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { StatusIcon } from '@konveyor/lib-ui';
import { Grid, GridItem } from '@patternfly/react-core';
import {
Alert,
Bullseye,
EmptyState,
Grid,
GridItem,
Spinner,
Title,
} from '@patternfly/react-core';
import { useFormikContext } from 'formik';
import { isEmpty } from 'lodash';
import React, { useEffect } from 'react';
Expand Down Expand Up @@ -85,6 +93,11 @@ const VolumesForm: React.FunctionComponent<IOtherProps> = (props) => {
};
});
}
const selectedPVs = mappedPVs
.filter((pv) => pv.selection.action !== 'skip')
.map((pv) => pv.name);
setFieldValue('selectedPVs', selectedPVs);

//Set initial PVs from pv discovery
setFieldValue('persistentVolumes', mappedPVs);
}
Expand All @@ -101,6 +114,32 @@ const VolumesForm: React.FunctionComponent<IOtherProps> = (props) => {
</Grid>
);
}
if (
!planState.currentPlan?.spec.persistentVolumes ||
planState.currentPlan.spec.persistentVolumes?.length == 0
) {
return (
<Bullseye>
<EmptyState variant="large">
<div className="pf-c-empty-state__icon">
<Spinner size="xl" />
</div>
<Title headingLevel="h2" size="xl">
Discovering persistent volumes attached to source projects...
</Title>
</EmptyState>
</Bullseye>
);
}
if (planState.currentPlanStatus.state === 'Critical') {
return (
<Bullseye>
<EmptyState variant="large">
<Alert variant="danger" isInline title={planState.currentPlanStatus.errorMessage} />
</EmptyState>
</Bullseye>
);
}
return (
<VolumesTable
isEdit={props.isEdit}
Expand Down
23 changes: 16 additions & 7 deletions src/app/home/pages/PlansPage/components/Wizard/VolumesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -460,17 +460,26 @@ const VolumesTable: React.FunctionComponent<IVolumesTableProps> = ({
: 'Choose to move or copy persistent volumes associated with selected namespaces.'}
</Text>
</TextContent>
{planState.currentPlanStatus.state === 'Critical' && !planState.currentPlan.spec.refresh ? (
{planState.currentPlanStatus?.state === 'Warn' && !planState.currentPlan?.spec.refresh ? (
<Bullseye>
<EmptyState variant="large">
<Alert variant="warning" isInline title={planState.currentPlanStatus.errorMessage} />
</EmptyState>
</Bullseye>
) : null}
{planState.currentPlanStatus?.state === 'Critical' &&
!planState.currentPlan?.spec.refresh ? (
<Bullseye>
<EmptyState variant="large">
<Alert variant="danger" isInline title={planState.currentPlanStatus.errorMessage} />
</EmptyState>
</Bullseye>
) : null}
{planState.isFetchingPVResources ||
planState.isPollingStatus ||
planState.currentPlanStatus.state === 'Pending' ||
planState.currentPlan.spec.refresh ? (
{planState.currentPlan?.spec.persistentVolumes?.length > 0 &&
(planState.isFetchingPVResources ||
planState.isPollingStatus ||
planState.currentPlanStatus.state === 'Pending' ||
planState.currentPlan.spec.refresh) ? (
<Bullseye>
<EmptyState variant="large">
<Spinner size="md" />
Expand All @@ -481,7 +490,7 @@ const VolumesTable: React.FunctionComponent<IVolumesTableProps> = ({
</Bullseye>
) : null}
</GridItem>
{isSCC && values.persistentVolumes.length === 0 ? (
{isSCC && values.persistentVolumes.length === 0 && planState.currentPlan?.spec.refresh ? (
<GridItem>
<Alert
variant="danger"
Expand All @@ -498,7 +507,7 @@ const VolumesTable: React.FunctionComponent<IVolumesTableProps> = ({
</Alert>
</GridItem>
) : null}
{isSCC && storageClasses.length < 2 ? (
{isSCC && storageClasses.length < 2 && planState.currentPlan?.spec.refresh ? (
<GridItem>
<Alert
variant="danger"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ const WizardComponent = (props: IOtherProps) => {

const onMove: WizardStepFunctionType = ({ id, name }, { prevId, prevName }) => {
dispatch(PlanActions.pvUpdatePollStop());
if (stepIdReached < id) {
if (stepIdReached < (id as number)) {
setStepIdReached(id as number);
}

Expand Down Expand Up @@ -348,7 +348,7 @@ const WizardComponent = (props: IOtherProps) => {
!isFetchingPVList &&
currentPlanStatus.state !== 'Pending' &&
currentPlanStatus.state !== 'Critical' &&
!planState.currentPlan.spec.refresh &&
!planState.currentPlan?.spec.refresh &&
(values.migrationType.value !== 'scc' ||
(values.selectedPVs.length > 0 && storageClasses.length > 1))
);
Expand Down
2 changes: 2 additions & 0 deletions src/app/home/pages/PlansPage/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const getPlanStatusText = (plan: IPlan) => {
hasCanceledCondition = null,
hasCancelingCondition = null,
hasCriticalCondition = null,
hasNotSupportedCondition = null,
latestAction = null,
latestIsFailed = null,
hasConflictCondition = null,
Expand All @@ -62,6 +63,7 @@ export const getPlanStatusText = (plan: IPlan) => {
if (hasCanceledCondition) return `${latestActionStr} canceled`;
if (hasNotReadyCondition || !hasReadyCondition) return 'Not Ready';
if (hasSucceededRollback) return 'Rollback succeeded';
if (hasNotSupportedCondition) return 'Storage live migration not supported';
if (hasDVMBlockedCondition) return 'In progress';
if (hasSucceededCutover && hasWarnCondition) return 'Migration completed with warnings';
if (hasSucceededWithWarningsCondition) return `${latestActionStr} completed with warnings`;
Expand Down
6 changes: 5 additions & 1 deletion src/app/plan/duck/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { IPlan, IMigPlan, IMigration, ICondition, IStatus } from '../../plan/duck/types';
import { ICondition } from '../../plan/duck/types';
interface IPlanConditionStatuses {
hasClosedCondition: boolean;
hasReadyCondition: boolean;
hasNotReadyCondition: boolean;
hasConflictCondition: boolean;
hasNotSupportedCondition: boolean;
conflictErrorMsg: string;
hasPODWarnCondition: boolean;
hasPVWarnCondition: boolean;
Expand All @@ -27,6 +28,9 @@ export const filterPlanConditions = (conditions: ICondition[]): IPlanConditionSt
hasReadyCondition: conditions.some((c) => c.type === 'Ready'),
hasNotReadyCondition: conditions.some((c) => c.category === 'Critical'),
hasConflictCondition: conditions.some((c) => c.type === 'PlanConflict'),
hasNotSupportedCondition: conditions.some(
(c) => c.type === 'KubeVirtStorageLiveMigrationNotEnabled'
),
hasPODWarnCondition: conditions.some((c) => c.type === 'PodLimitExceeded'),
hasPVWarnCondition: conditions.some((c) => c.type === 'PVLimitExceeded'),
conflictErrorMsg: conditions.find((c) => c.type === 'PlanConflict')?.message,
Expand Down
20 changes: 19 additions & 1 deletion src/app/plan/duck/sagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,9 @@ function* checkPlanStatus(action: any): any {
const hasConflictCondition = !!updatedPlan.status.conditions.some((cond) => {
return cond.type === 'PlanConflict';
});
const hasNotSupportedCondition = !!updatedPlan.status.conditions.some((cond) => {
return cond.type === 'KubeVirtStorageLiveMigrationNotEnabled';
});
if (hasReadyCondition) {
if (hasWarnCondition) {
const warnCondition = updatedPlan.status.conditions.find((cond) => {
Expand Down Expand Up @@ -595,7 +598,8 @@ function* checkPlanStatus(action: any): any {
});
yield put(
PlanActions.updateCurrentPlanStatus({
state: CurrentPlanState.Critical,
state:
errorCond.reason === 'Conflict' ? CurrentPlanState.Warn : CurrentPlanState.Critical,
errorMessage: errorCond.message,
})
);
Expand All @@ -616,6 +620,20 @@ function* checkPlanStatus(action: any): any {

yield put(PlanActions.stopPlanStatusPolling(action.planName));
}

if (hasNotSupportedCondition) {
const unsupportedCond = updatedPlan.status.conditions.find((cond) => {
return cond.type === 'KubeVirtStorageLiveMigrationNotEnabled';
});
yield put(
PlanActions.updateCurrentPlanStatus({
state: CurrentPlanState.Warn,
errorMessage: unsupportedCond.message,
})
);

yield put(PlanActions.stopPlanStatusPolling(action.planName));
}
}
} else {
planStatusComplete = true;
Expand Down
1 change: 1 addition & 0 deletions src/app/plan/duck/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ export interface IPlan {
conflictErrorMsg?: string;
hasCanceledCondition?: boolean;
hasCriticalCondition?: boolean;
hasNotSupportedCondition?: boolean;
hasCancelingCondition?: boolean;
hasClosedCondition?: boolean;
hasErrorCondition?: boolean;
Expand Down

0 comments on commit f9dad67

Please sign in to comment.