From 7c9a9f7dac45308a54462f91794889fa1c80e6a6 Mon Sep 17 00:00:00 2001 From: Sharon Gratch Date: Wed, 27 Nov 2024 21:28:17 +0200 Subject: [PATCH 1/9] Avoid removing VMs from an archived/archiving plans. Reference: https://issues.redhat.com/browse/MTV-1713 Avoid removing VMs from an archived/archiving plans. If a plan's status is either archiving or archived, block the option to remove VMs for that plan. Signed-off-by: Sharon Gratch --- .../en/plugin__forklift-console-plugin.json | 1 + .../Plans/utils/helpers/getPlanPhase.ts | 6 ++++ .../MigrationVirtualMachinesList.tsx | 7 +++-- .../modals/PlanVMsDeleteModal.tsx | 28 +++++++++---------- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json b/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json index 701b473ba..62f7d9ce1 100644 --- a/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json +++ b/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json @@ -128,6 +128,7 @@ "Delete Provider": "Delete Provider", "Delete StorageMap": "Delete StorageMap", "Delete virtual machines from migration plan": "Delete virtual machines from migration plan", + "Deleting virtual machines from an archived migration plan is not allowed.": "Deleting virtual machines from an archived migration plan is not allowed.", "Description": "Description", "Details": "Details", "Determines the frequency with which the system checks the status of snapshot creation or removal during oVirt warm migration. The default value is 10 seconds.": "Determines the frequency with which the system checks the status of snapshot creation or removal during oVirt warm migration. The default value is 10 seconds.", diff --git a/packages/forklift-console-plugin/src/modules/Plans/utils/helpers/getPlanPhase.ts b/packages/forklift-console-plugin/src/modules/Plans/utils/helpers/getPlanPhase.ts index 44dd18a5b..c5712f3c8 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/utils/helpers/getPlanPhase.ts +++ b/packages/forklift-console-plugin/src/modules/Plans/utils/helpers/getPlanPhase.ts @@ -117,5 +117,11 @@ export const isPlanEditable = (plan: V1beta1Plan) => { ); }; +export const isPlanArchived = (plan: V1beta1Plan) => { + const planStatus = getPlanPhase({ obj: plan }); + + return planStatus === 'Archiving' || planStatus === 'Archived'; +}; + const getConditions = (obj: V1beta1Plan) => obj?.status?.conditions?.filter((c) => c.status === 'True').map((c) => c.type); diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/details/tabs/VirtualMachines/Migration/MigrationVirtualMachinesList.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/details/tabs/VirtualMachines/Migration/MigrationVirtualMachinesList.tsx index 194f69b65..abfc0ed6a 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/details/tabs/VirtualMachines/Migration/MigrationVirtualMachinesList.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/details/tabs/VirtualMachines/Migration/MigrationVirtualMachinesList.tsx @@ -5,7 +5,7 @@ import { StandardPageWithSelectionProps, } from 'src/components/page/StandardPageWithSelection'; import { usePlanMigration } from 'src/modules/Plans/hooks/usePlanMigration'; -import { isPlanExecuting } from 'src/modules/Plans/utils'; +import { isPlanArchived, isPlanExecuting } from 'src/modules/Plans/utils'; import { useForkliftTranslation } from 'src/utils/i18n'; import { loadUserSettings, ResourceFieldFactory } from '@kubev2v/common'; @@ -244,10 +244,11 @@ export const MigrationVirtualMachinesList: FC<{ obj: PlanData }> = ({ obj }) => })); const isExecuting = isPlanExecuting(plan); + const isArchived = isPlanArchived(plan); - // If plan executing allow to cancel vms, o/w remove from plan + // If plan executing and not archived (happens when archiving a running plan), allow to cancel vms, o/w remove from plan let actions: PageGlobalActions; - if (isExecuting) { + if (isExecuting && !isArchived) { actions = [ ({ selectedIds }) => ( diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/details/tabs/VirtualMachines/modals/PlanVMsDeleteModal.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/details/tabs/VirtualMachines/modals/PlanVMsDeleteModal.tsx index bae968dd8..ffd8b8054 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/details/tabs/VirtualMachines/modals/PlanVMsDeleteModal.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/details/tabs/VirtualMachines/modals/PlanVMsDeleteModal.tsx @@ -1,4 +1,5 @@ import React, { ReactNode, useCallback, useState } from 'react'; +import { isPlanArchived } from 'src/modules/Plans/utils'; import { useToggle } from 'src/modules/Providers/hooks'; import { AlertMessageForModals, useModal } from 'src/modules/Providers/modals'; import { useForkliftTranslation } from 'src/utils/i18n'; @@ -23,17 +24,20 @@ export const PlanVMsDeleteModal: React.FC = ({ plan, se const vms = (plan?.spec?.vms || []).filter((vm) => !selected.includes(vm.id)) || []; React.useEffect(() => { + if (isPlanArchived(plan)) { + setAlertMessage( + t('Deleting virtual machines from an archived migration plan is not allowed.'), + ); + return; + } if (vms.length < 1) { setAlertMessage( - , + t( + 'All virtual machines planned for migration are selected for deletion, deleting all virtual machines from a migration plan is not allowed.', + ), ); } - }, [vms]); + }, [vms, plan]); const handleSave = useCallback(async () => { toggleIsLoading(); @@ -51,10 +55,7 @@ export const PlanVMsDeleteModal: React.FC = ({ plan, se toggleModal(); } catch (err) { toggleIsLoading(); - - setAlertMessage( - , - ); + setAlertMessage(err.message || err.toString()); } }, [selected]); @@ -63,7 +64,7 @@ export const PlanVMsDeleteModal: React.FC = ({ plan, se key="confirm" onClick={handleSave} variant="danger" - isDisabled={vms.length < 1} + isDisabled={vms.length < 1 || isPlanArchived(plan)} isLoading={isLoading} > {t('Delete')} @@ -86,8 +87,7 @@ export const PlanVMsDeleteModal: React.FC = ({ plan, se
{t('Are you sure you want to delete this virtual machines from the migration plan?')}
- - {alertMessage} + {alertMessage && } ); }; From 052d6766157fb94890a2cfad03d7ff3afa32c35b Mon Sep 17 00:00:00 2001 From: Sharon Gratch Date: Wed, 27 Nov 2024 19:33:23 +0200 Subject: [PATCH 2/9] Allow editing plan hooks and mappings only for specific plan's statuses Reference: https://issues.redhat.com/browse/MTV-1713 Enable editing of plan hooks (under Hooks tab) or plan mappings (under Mappings tab) fields only for the following plan statuses: 'Unknown', 'Canceled', 'Error', 'Failed', 'vmError', 'Warning', 'Ready ' Disable the edit option for those Hooks, Mappings tabs fields for all other plan statuses. Signed-off-by: Sharon Gratch --- .../en/plugin__forklift-console-plugin.json | 6 +++-- .../views/details/tabs/Hooks/PlanHooks.tsx | 25 +++++++++++++------ .../tabs/Mappings/PlanMappingsSection.tsx | 7 +++--- ...itable.ts => hasSomeCompleteRunningVMs.ts} | 4 +-- .../Plans/views/details/utils/index.ts | 2 +- 5 files changed, 28 insertions(+), 16 deletions(-) rename packages/forklift-console-plugin/src/modules/Plans/views/details/utils/{hasPlanEditable.ts => hasSomeCompleteRunningVMs.ts} (75%) diff --git a/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json b/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json index 701b473ba..7227c3c8d 100644 --- a/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json +++ b/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json @@ -58,6 +58,8 @@ "Boot from the second hard drive": "Boot from the second hard drive", "Boot from the second partition on the first hard drive": "Boot from the second partition on the first hard drive", "Boot from the second partition on the second hard drive": "Boot from the second partition on the second hard drive", + "Button is disabled since the plan status does not enable editing.": "Button is disabled since the plan status does not enable editing.", + "Button is disabled until a change is detected.": "Button is disabled until a change is detected.", "CA certificate": "CA certificate", "CA certificate - disabled when 'Skip certificate validation' is selected": "CA certificate - disabled when 'Skip certificate validation' is selected", "CA certificate - leave empty to use system CA certificates": "CA certificate - leave empty to use system CA certificates", @@ -74,7 +76,7 @@ "Clear all filters": "Clear all filters", "Click the pencil for setting provider web UI link": "Click the pencil for setting provider web UI link", "Click the update credentials button to save your changes, button is disabled until a change is detected.": "Click the update credentials button to save your changes, button is disabled until a change is detected.", - "Click the update hooks button to save your changes, button is disabled until a change is detected.": "Click the update hooks button to save your changes, button is disabled until a change is detected.", + "Click the update hooks button to save your changes.": "Click the update hooks button to save your changes.", "Click the update mappings button to save your changes, button is disabled until a change is detected.": "Click the update mappings button to save your changes, button is disabled until a change is detected.", "Click to select a different provider from the list.": "Click to select a different provider from the list.", "Click to unselect.": "Click to unselect.", @@ -481,7 +483,7 @@ "The certificate is not a valid PEM-encoded X.509 certificate": "The certificate is not a valid PEM-encoded X.509 certificate", "The chosen provider is no longer available.": "The chosen provider is no longer available.", "The current certificate does not match the certificate fetched from URL. Manually validate the fingerprint before proceeding.": "The current certificate does not match the certificate fetched from URL. Manually validate the fingerprint before proceeding.", - "The edit mappings button is disabled if the plan started running and at least one virtual machine was migrated successfully.": "The edit mappings button is disabled if the plan started running and at least one virtual machine was migrated successfully.", + "The edit mappings button is disabled if the plan started running and at least one virtual machine was migrated successfully or when the plan status does not enable editing.": "The edit mappings button is disabled if the plan started running and at least one virtual machine was migrated successfully or when the plan status does not enable editing.", "The interval in minutes for precopy. Default value is 60.": "The interval in minutes for precopy. Default value is 60.", "The interval in seconds for snapshot pooling. Default value is 10.": "The interval in seconds for snapshot pooling. Default value is 10.", "The limit for CPU usage by the controller, specified in milliCPU. Default value is 500m.": "The limit for CPU usage by the controller, specified in milliCPU. Default value is 500m.", diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/details/tabs/Hooks/PlanHooks.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/details/tabs/Hooks/PlanHooks.tsx index 2a9e747b5..c648a1c49 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/details/tabs/Hooks/PlanHooks.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/details/tabs/Hooks/PlanHooks.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useReducer } from 'react'; import { Base64 } from 'js-base64'; import SectionHeading from 'src/components/headers/SectionHeading'; +import { isPlanEditable } from 'src/modules/Plans/utils'; import { AlertMessageForModals } from 'src/modules/Providers/modals'; import { useForkliftTranslation } from 'src/utils/i18n'; @@ -58,6 +59,19 @@ export const PlanHooks: React.FC<{ name: string; namespace: string }> = ({ name, }); }; + const buttonHelperMsg = () => { + let updateButtonDisabledMsg = ''; + + if (!isPlanEditable(plan)) + updateButtonDisabledMsg = t( + 'Button is disabled since the plan status does not enable editing.', + ); + else if (!state.hasChanges) + updateButtonDisabledMsg = t('Button is disabled until a change is detected.'); + + return t('Click the update hooks button to save your changes.') + ' ' + updateButtonDisabledMsg; + }; + const HooksTabAction = ( <> @@ -65,7 +79,7 @@ export const PlanHooks: React.FC<{ name: string; namespace: string }> = ({ name, - - - {t( - 'Click the update hooks button to save your changes, button is disabled until a change is detected.', - )} - + {buttonHelperMsg()} @@ -231,7 +240,7 @@ export const PlanHooks: React.FC<{ name: string; namespace: string }> = ({ name, value={state.postHook?.spec?.image} type="url" onChange={(e, v) => onChangePostHookImage(v, e)} - aria-label="pre hook image" + aria-label="post hook image" /> diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/details/tabs/Mappings/PlanMappingsSection.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/details/tabs/Mappings/PlanMappingsSection.tsx index 66e001cea..5bf78ae11 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/details/tabs/Mappings/PlanMappingsSection.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/details/tabs/Mappings/PlanMappingsSection.tsx @@ -1,4 +1,5 @@ import React, { ReactNode, useReducer, useState } from 'react'; +import { isPlanEditable } from 'src/modules/Plans/utils'; import { InventoryNetwork } from 'src/modules/Providers/hooks/useNetworks'; import { InventoryStorage } from 'src/modules/Providers/hooks/useStorages'; import { useForkliftTranslation } from 'src/utils/i18n'; @@ -35,8 +36,8 @@ import Pencil from '@patternfly/react-icons/dist/esm/icons/pencil-alt-icon'; import { Mapping, MappingList } from '../../components'; import { canDeleteAndPatchPlanHooks, - hasPlanEditable, hasPlanMappingsChanged, + hasSomeCompleteRunningVMs, mapSourceNetworksIdsToLabels, mapSourceStoragesIdsToLabels, mapTargetNetworksIdsToLabels, @@ -564,7 +565,7 @@ export const PlanMappingsSection: React.FC = ({ const PlanMappingsSectionViewMode: React.FC = () => { const { t } = useForkliftTranslation(); - const DisableEditMappings = !hasPlanEditable(plan); + const DisableEditMappings = hasSomeCompleteRunningVMs(plan) || !isPlanEditable(plan); return ( <> @@ -583,7 +584,7 @@ export const PlanMappingsSection: React.FC = ({ {t( - 'The edit mappings button is disabled if the plan started running and at least one virtual machine was migrated successfully.', + 'The edit mappings button is disabled if the plan started running and at least one virtual machine was migrated successfully or when the plan status does not enable editing.', )} diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/details/utils/hasPlanEditable.ts b/packages/forklift-console-plugin/src/modules/Plans/views/details/utils/hasSomeCompleteRunningVMs.ts similarity index 75% rename from packages/forklift-console-plugin/src/modules/Plans/views/details/utils/hasPlanEditable.ts rename to packages/forklift-console-plugin/src/modules/Plans/views/details/utils/hasSomeCompleteRunningVMs.ts index ef1b85dc4..50ca64360 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/details/utils/hasPlanEditable.ts +++ b/packages/forklift-console-plugin/src/modules/Plans/views/details/utils/hasSomeCompleteRunningVMs.ts @@ -1,6 +1,6 @@ import { V1beta1Plan } from '@kubev2v/types'; -export const hasPlanEditable = (plan: V1beta1Plan) => { +export const hasSomeCompleteRunningVMs = (plan: V1beta1Plan) => { const planHasNeverStarted = !plan.status?.migration?.started ? true : false; const migrationHasSomeCompleteRunningVMs = @@ -10,5 +10,5 @@ export const hasPlanEditable = (plan: V1beta1Plan) => { vm.phase !== 'Completed', ).length > 0 || false; - return planHasNeverStarted || !migrationHasSomeCompleteRunningVMs; + return !planHasNeverStarted && migrationHasSomeCompleteRunningVMs; }; diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/details/utils/index.ts b/packages/forklift-console-plugin/src/modules/Plans/views/details/utils/index.ts index 0af5f24d7..46a7383f7 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/details/utils/index.ts +++ b/packages/forklift-console-plugin/src/modules/Plans/views/details/utils/index.ts @@ -4,8 +4,8 @@ export * from './constants'; export * from './getInventoryApiUrl'; export * from './getValueByJsonPath'; export * from './hasPipelineCompleted'; -export * from './hasPlanEditable'; export * from './hasPlanMappingsChanged'; +export * from './hasSomeCompleteRunningVMs'; export * from './hasTaskCompleted'; export * from './mapMappingsIdsToLabels'; export * from './patchPlanMappingsData'; From ab7a45ae6b042ac445f2a8cd403fa6e3b976c818 Mon Sep 17 00:00:00 2001 From: Sharon Gratch Date: Wed, 4 Dec 2024 00:57:02 +0200 Subject: [PATCH 3/9] Avoid displaying alert messages for successfully completed plans Reference: https://issues.redhat.com/browse/MTV-1730 If plan was completed succesfully, it's irrelevant to display critical errors or warnings alerts in page header. Signed-off-by: Sharon Gratch --- .../details/components/PlanPageHeadings.tsx | 52 +++++++++++-------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/details/components/PlanPageHeadings.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/details/components/PlanPageHeadings.tsx index 9f1f399d4..07a966258 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/details/components/PlanPageHeadings.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/details/components/PlanPageHeadings.tsx @@ -79,27 +79,35 @@ export const PlanPageHeadings: React.FC<{ name: string; namespace: string }> = ( return isPreserveStaticIPs && isMapToPod; }; - if (criticalCondition) { - alerts.push( - , - ); - } else if (preserveIpsWithPodMapCondition()) { - alerts.push( - , - ); - } + const handleAlerts = () => { + // alerts are not relevant to display if plan was completed successfully + if (planStatus === 'Succeeded') return; + + if (criticalCondition) { + alerts.push( + , + ); + return; + } + + if (preserveIpsWithPodMapCondition()) { + alerts.push( + , + ); + } + }; const onClick = () => { showModal( @@ -123,6 +131,8 @@ export const PlanPageHeadings: React.FC<{ name: string; namespace: string }> = ( ); + handleAlerts(); + return ( <> Date: Wed, 4 Dec 2024 18:40:41 +0100 Subject: [PATCH 4/9] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix typo Signed-off-by: George Gaál --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8104588be..a2c3b7e52 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ yarn start The cluster address will be the part of the address after the `apps.` or `api.` in the cluster services or API service address. -For example, if your cluter API address is `api.example.com:6443`, the cluster address will be `example.com`, and +For example, if your cluster API address is `api.example.com:6443`, the cluster address will be `example.com`, and the inventory service address will be: ``` bash From b43aae524f65789f0c9a0d95d8592c2c06f9f513 Mon Sep 17 00:00:00 2001 From: "red-hat-konflux[bot]" <126015336+red-hat-konflux[bot]@users.noreply.github.com> Date: Sat, 7 Dec 2024 08:16:28 +0000 Subject: [PATCH 5/9] chore(deps): update konflux references Signed-off-by: red-hat-konflux <126015336+red-hat-konflux[bot]@users.noreply.github.com> --- .../forklift-console-plugin-pull-request.yaml | 16 ++++++++-------- .tekton/forklift-console-plugin-push.yaml | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.tekton/forklift-console-plugin-pull-request.yaml b/.tekton/forklift-console-plugin-pull-request.yaml index 2c4ac3a3d..46e918968 100644 --- a/.tekton/forklift-console-plugin-pull-request.yaml +++ b/.tekton/forklift-console-plugin-pull-request.yaml @@ -155,7 +155,7 @@ spec: - name: name value: git-clone-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.1@sha256:4bf48d038ff12d25bdeb5ab3e98dc2271818056f454c83d7393ebbd413028147 + value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.1@sha256:8ab0c7a7ac4a4c59740a24304e17cc64fe8745376d19396c4660fc0e1a957a1b - name: kind value: task resolver: bundles @@ -184,7 +184,7 @@ spec: - name: name value: prefetch-dependencies-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-prefetch-dependencies-oci-ta:0.1@sha256:4072f732119864d12ec8e2ff075f01487aaee9df4440166dbe85fdd447865161 + value: quay.io/konflux-ci/tekton-catalog/task-prefetch-dependencies-oci-ta:0.1@sha256:3e51d7c477ba00bd0c7de2d8f89269131646d2582e631b9aee91fb4b022d4555 - name: kind value: task resolver: bundles @@ -225,7 +225,7 @@ spec: - name: name value: buildah-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-buildah-oci-ta:0.2@sha256:ee8a91b85cd51394489ec09c9d5e8742328ef9f64a692716449a166519f4b948 + value: quay.io/konflux-ci/tekton-catalog/task-buildah-oci-ta:0.2@sha256:decef0e000a05daad9dd43b707c8b3a96b6125ff5a4ee096fd3e8c23a2881b9e - name: kind value: task resolver: bundles @@ -254,7 +254,7 @@ spec: - name: name value: build-image-index - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-build-image-index:0.1@sha256:7b2c5ab5d711d1d487693072dec6a10ede0076290dabc673bc6ccde9a322674a + value: quay.io/konflux-ci/tekton-catalog/task-build-image-index:0.1@sha256:a89c141c8d35b2e9d9904c92c9b128f7ccf36681adac7f7422b4537b8bb077e7 - name: kind value: task resolver: bundles @@ -278,7 +278,7 @@ spec: - name: name value: source-build-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-source-build-oci-ta:0.1@sha256:24dba7b4eb207592e4a24710a24a01b57e9477bc37bdb2f2d04bff5d4fb7ccec + value: quay.io/konflux-ci/tekton-catalog/task-source-build-oci-ta:0.1@sha256:26278e5373a726594975a9ec2f177a67e3674bbf905d7d317b9ea60ca7993978 - name: kind value: task resolver: bundles @@ -372,7 +372,7 @@ spec: - name: name value: sast-snyk-check-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-sast-snyk-check-oci-ta:0.3@sha256:65a213322ea7c64159e37071d369d74b6378b23403150e29537865cada90f022 + value: quay.io/konflux-ci/tekton-catalog/task-sast-snyk-check-oci-ta:0.3@sha256:1119722a2d31b831d1aa336fd8cced0a5016c95466b6b59a58bbf3585735850f - name: kind value: task resolver: bundles @@ -394,7 +394,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-clamav-scan:0.1@sha256:b4f450f1447b166da671f1d5819ab5a1485083e5c27ab91f7d8b7a2ff994c8c2 + value: quay.io/konflux-ci/tekton-catalog/task-clamav-scan:0.2@sha256:6e08cf608240f57442ca5458f3c0dade3558f4f2953be8ea939232f5d5378d58 - name: kind value: task resolver: bundles @@ -437,7 +437,7 @@ spec: - name: name value: push-dockerfile-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-push-dockerfile-oci-ta:0.1@sha256:80d48a1b9d2707490309941ec9f79338533938f959ca9a207b481b0e8a5e7a93 + value: quay.io/konflux-ci/tekton-catalog/task-push-dockerfile-oci-ta:0.1@sha256:08ef41d6a98608bd5f1de75d77f015f520911a278d1875e174b88b9d04db2441 - name: kind value: task resolver: bundles diff --git a/.tekton/forklift-console-plugin-push.yaml b/.tekton/forklift-console-plugin-push.yaml index f8b808a85..9d0a46460 100644 --- a/.tekton/forklift-console-plugin-push.yaml +++ b/.tekton/forklift-console-plugin-push.yaml @@ -154,7 +154,7 @@ spec: - name: name value: git-clone-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.1@sha256:4bf48d038ff12d25bdeb5ab3e98dc2271818056f454c83d7393ebbd413028147 + value: quay.io/konflux-ci/tekton-catalog/task-git-clone-oci-ta:0.1@sha256:8ab0c7a7ac4a4c59740a24304e17cc64fe8745376d19396c4660fc0e1a957a1b - name: kind value: task resolver: bundles @@ -183,7 +183,7 @@ spec: - name: name value: prefetch-dependencies-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-prefetch-dependencies-oci-ta:0.1@sha256:4072f732119864d12ec8e2ff075f01487aaee9df4440166dbe85fdd447865161 + value: quay.io/konflux-ci/tekton-catalog/task-prefetch-dependencies-oci-ta:0.1@sha256:3e51d7c477ba00bd0c7de2d8f89269131646d2582e631b9aee91fb4b022d4555 - name: kind value: task resolver: bundles @@ -224,7 +224,7 @@ spec: - name: name value: buildah-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-buildah-oci-ta:0.2@sha256:ee8a91b85cd51394489ec09c9d5e8742328ef9f64a692716449a166519f4b948 + value: quay.io/konflux-ci/tekton-catalog/task-buildah-oci-ta:0.2@sha256:decef0e000a05daad9dd43b707c8b3a96b6125ff5a4ee096fd3e8c23a2881b9e - name: kind value: task resolver: bundles @@ -253,7 +253,7 @@ spec: - name: name value: build-image-index - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-build-image-index:0.1@sha256:7b2c5ab5d711d1d487693072dec6a10ede0076290dabc673bc6ccde9a322674a + value: quay.io/konflux-ci/tekton-catalog/task-build-image-index:0.1@sha256:a89c141c8d35b2e9d9904c92c9b128f7ccf36681adac7f7422b4537b8bb077e7 - name: kind value: task resolver: bundles @@ -277,7 +277,7 @@ spec: - name: name value: source-build-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-source-build-oci-ta:0.1@sha256:24dba7b4eb207592e4a24710a24a01b57e9477bc37bdb2f2d04bff5d4fb7ccec + value: quay.io/konflux-ci/tekton-catalog/task-source-build-oci-ta:0.1@sha256:26278e5373a726594975a9ec2f177a67e3674bbf905d7d317b9ea60ca7993978 - name: kind value: task resolver: bundles @@ -371,7 +371,7 @@ spec: - name: name value: sast-snyk-check-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-sast-snyk-check-oci-ta:0.3@sha256:65a213322ea7c64159e37071d369d74b6378b23403150e29537865cada90f022 + value: quay.io/konflux-ci/tekton-catalog/task-sast-snyk-check-oci-ta:0.3@sha256:1119722a2d31b831d1aa336fd8cced0a5016c95466b6b59a58bbf3585735850f - name: kind value: task resolver: bundles @@ -393,7 +393,7 @@ spec: - name: name value: clamav-scan - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-clamav-scan:0.1@sha256:b4f450f1447b166da671f1d5819ab5a1485083e5c27ab91f7d8b7a2ff994c8c2 + value: quay.io/konflux-ci/tekton-catalog/task-clamav-scan:0.2@sha256:6e08cf608240f57442ca5458f3c0dade3558f4f2953be8ea939232f5d5378d58 - name: kind value: task resolver: bundles @@ -436,7 +436,7 @@ spec: - name: name value: push-dockerfile-oci-ta - name: bundle - value: quay.io/konflux-ci/tekton-catalog/task-push-dockerfile-oci-ta:0.1@sha256:80d48a1b9d2707490309941ec9f79338533938f959ca9a207b481b0e8a5e7a93 + value: quay.io/konflux-ci/tekton-catalog/task-push-dockerfile-oci-ta:0.1@sha256:08ef41d6a98608bd5f1de75d77f015f520911a278d1875e174b88b9d04db2441 - name: kind value: task resolver: bundles From ed60f789a4fd325ff4de00440cbe4ccc9cbc8ba9 Mon Sep 17 00:00:00 2001 From: Sharon Gratch Date: Mon, 9 Dec 2024 11:44:59 +0200 Subject: [PATCH 6/9] Rephrase the preserve static IPs warning message Reference: https://issues.redhat.com/browse/MTV-1503 Based on Doc's review, rephrase the warning message for preserving static IPs while using Pod networking. Change the PlanWarningCondition component to enable flexible formatting of the suggested section. Signed-off-by: Sharon Gratch --- .../en/plugin__forklift-console-plugin.json | 7 +++---- .../details/components/PlanPageHeadings.tsx | 17 +++++++++++------ .../details/components/PlanWarningCondition.tsx | 4 ++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json b/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json index bbbd50982..dbe3d2f99 100644 --- a/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json +++ b/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json @@ -72,6 +72,7 @@ "Cannot retrieve certificate": "Cannot retrieve certificate", "Category": "Category", "Certificate change detected": "Certificate change detected", + "choose a different mapping for your migration plan": "choose a different mapping for your migration plan", "Choose the root filesystem to be converted.": "Choose the root filesystem to be converted.", "Clear all filters": "Clear all filters", "Click the pencil for setting provider web UI link": "Click the pencil for setting provider web UI link", @@ -200,7 +201,6 @@ "First root device": "First root device", "Flavor": "Flavor", "Folder": "Folder", - "For fixing, update the destination network mappings to avoid using the 'Pod Networking' type.": "For fixing, update the destination network mappings to avoid using the 'Pod Networking' type.", "GPUs/Host Devices": "GPUs/Host Devices", "Hide from view": "Hide from view", "Hide values": "Hide values", @@ -378,7 +378,6 @@ "Preserve static IPs": "Preserve static IPs", "Preserve the CPU model and flags the VM runs with in its oVirt cluster.": "Preserve the CPU model and flags the VM runs with in its oVirt cluster.", "Preserve the static IPs of virtual machines migrated from vSphere.": "Preserve the static IPs of virtual machines migrated from vSphere.", - "Preserving static IPs of VMs might fail": "Preserving static IPs of VMs might fail", "Product": "Product", "Progress": "Progress", "Project": "Project", @@ -495,7 +494,6 @@ "The Manager CA certificate unless it was replaced by a third-party certificate, in which case, enter the Manager Apache CA certificate.": "The Manager CA certificate unless it was replaced by a third-party certificate, in which case, enter the Manager Apache CA certificate.", "The password for the ESXi host admin": "The password for the ESXi host admin", "The plan is not ready": "The plan is not ready", - "The plan is set to preserve the static IPs of VMs mapped to a Pod network type. This is not supported and therefore VM IPs can be changed during the migration process.": "The plan is set to preserve the static IPs of VMs mapped to a Pod network type. This is not supported and therefore VM IPs can be changed during the migration process.", "The plan migration might not work as expected": "The plan migration might not work as expected", "The provider is not ready": "The provider is not ready", "The provider is not ready.": "The provider is not ready.", @@ -579,5 +577,6 @@ "You can select a migration network for a source provider to reduce risk to the source environment and to improve performance.": "You can select a migration network for a source provider to reduce risk to the source environment and to improve performance.", "You can select a migration network. If you do not select a migration network,\n the default migration network is set to the providers default transfer network.": "You can select a migration network. If you do not select a migration network,\n the default migration network is set to the providers default transfer network.", "You can select a migration target namespace for the migration virtual machines.": "You can select a migration target namespace for the migration virtual machines.", - "You don't have access to this section due to cluster policy.": "You don't have access to this section due to cluster policy." + "You don't have access to this section due to cluster policy.": "You don't have access to this section due to cluster policy.", + "Your migration plan preserves the static IPs of VMs and uses Pod Networking target network mapping. This combination isn't supported, because VM IPs aren't preserved in Pod Networking migrations.": "Your migration plan preserves the static IPs of VMs and uses Pod Networking target network mapping. This combination isn't supported, because VM IPs aren't preserved in Pod Networking migrations." } diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/details/components/PlanPageHeadings.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/details/components/PlanPageHeadings.tsx index 07a966258..b69cdda74 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/details/components/PlanPageHeadings.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/details/components/PlanPageHeadings.tsx @@ -5,7 +5,7 @@ import { canPlanReStart, canPlanStart, getPlanPhase } from 'src/modules/Plans/ut import { useGetDeleteAndEditAccessReview } from 'src/modules/Providers/hooks'; import { useModal } from 'src/modules/Providers/modals'; import { PageHeadings } from 'src/modules/Providers/utils'; -import { useForkliftTranslation } from 'src/utils'; +import { ForkliftTrans, useForkliftTranslation } from 'src/utils'; import { NetworkMapModelGroupVersionKind, @@ -97,13 +97,18 @@ export const PlanPageHeadings: React.FC<{ name: string; namespace: string }> = ( if (preserveIpsWithPodMapCondition()) { alerts.push( + If your VMs use static IPs, click the Mappings tab of your plan, and choose a + different target network mapping. +
+ If your VMs don't use static IPs, you can ignore this message. + + } />, ); } diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/details/components/PlanWarningCondition.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/details/components/PlanWarningCondition.tsx index be643f94f..0a742b0ca 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/details/components/PlanWarningCondition.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/details/components/PlanWarningCondition.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { ReactNode } from 'react'; import { useTranslation } from 'react-i18next'; import Linkify from 'react-linkify'; import { EMPTY_MSG } from 'src/utils/constants'; @@ -8,7 +8,7 @@ import { Alert, AlertVariant, Text, TextContent, TextVariants } from '@patternfl const PlanWarningCondition: React.FC<{ type: string; message: string; - suggestion: string; + suggestion: ReactNode; }> = ({ type, message, suggestion }) => { const { t } = useTranslation(); return ( From ea4f80daab23cdd1c391b3214270d06a70d20c0d Mon Sep 17 00:00:00 2001 From: Sharon Gratch Date: Tue, 10 Dec 2024 20:09:53 +0200 Subject: [PATCH 7/9] Exclude the 'Edit Provider Credentials' dropdown item for OVA Reference: https://issues.redhat.com/browse/MTV-1766 Since editing the OVA provider cresentials is not supported, exclude this option from the providers dropdown menu items. Signed-off-by: Sharon Gratch --- .../Providers/actions/ProviderActionsDropdownItems.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/forklift-console-plugin/src/modules/Providers/actions/ProviderActionsDropdownItems.tsx b/packages/forklift-console-plugin/src/modules/Providers/actions/ProviderActionsDropdownItems.tsx index 66c7d2948..28aade4d8 100644 --- a/packages/forklift-console-plugin/src/modules/Providers/actions/ProviderActionsDropdownItems.tsx +++ b/packages/forklift-console-plugin/src/modules/Providers/actions/ProviderActionsDropdownItems.tsx @@ -24,7 +24,7 @@ export const ProviderActionsDropdownItems = ({ data }: ProviderActionsDropdownIt showModal(); }; - return [ + const dropdownItems = [ {t('Edit Provider')} , @@ -38,6 +38,11 @@ export const ProviderActionsDropdownItems = ({ data }: ProviderActionsDropdownIt {t('Delete Provider')} , ]; + + // excluding the EditCredentials options since not supported for OVA + const ovaDropdownItems = dropdownItems.filter((item) => item.key !== 'EditCredentials'); + + return provider?.spec?.type === 'ova' ? ovaDropdownItems : dropdownItems; }; interface ProviderActionsDropdownItemsProps { From f5e85a024f892ab84ef3e6e5aaee3165268c3893 Mon Sep 17 00:00:00 2001 From: Jeff Puzzo Date: Thu, 12 Dec 2024 20:12:15 -0500 Subject: [PATCH 8/9] [MTV-1786] Add tooltip to Create plan wizard's Target namespace field Signed-off-by: Jeff Puzzo --- .../HelpIconPopover/HelpIconPopover.tsx | 22 ++++++++++++++++ .../src/components/HelpIconPopover/index.ts | 3 +++ packages/common/src/components/index.ts | 1 + .../migrate/components/PlansCreateForm.tsx | 26 +++++++++++++++++-- 4 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 packages/common/src/components/HelpIconPopover/HelpIconPopover.tsx create mode 100644 packages/common/src/components/HelpIconPopover/index.ts diff --git a/packages/common/src/components/HelpIconPopover/HelpIconPopover.tsx b/packages/common/src/components/HelpIconPopover/HelpIconPopover.tsx new file mode 100644 index 000000000..d1e571b6f --- /dev/null +++ b/packages/common/src/components/HelpIconPopover/HelpIconPopover.tsx @@ -0,0 +1,22 @@ +import React from 'react'; + +import { Popover, PopoverProps } from '@patternfly/react-core'; +import HelpIcon from '@patternfly/react-icons/dist/esm/icons/help-icon'; + +interface HelpIconPopoverProps { + children: React.ReactNode; + header?: string; + popoverProps?: Omit; +} + +export const HelpIconPopover: React.FC = ({ + children, + header, + popoverProps, +}) => ( + + + +); diff --git a/packages/common/src/components/HelpIconPopover/index.ts b/packages/common/src/components/HelpIconPopover/index.ts new file mode 100644 index 000000000..1ffc1fefa --- /dev/null +++ b/packages/common/src/components/HelpIconPopover/index.ts @@ -0,0 +1,3 @@ +// @index(['./*', /__/g], f => `export * from '${f.path}';`) +export * from './HelpIconPopover'; +// @endindex diff --git a/packages/common/src/components/index.ts b/packages/common/src/components/index.ts index 3657960e2..e561934ae 100644 --- a/packages/common/src/components/index.ts +++ b/packages/common/src/components/index.ts @@ -4,6 +4,7 @@ export * from './ExternalLink'; export * from './Filter'; export * from './FilterGroup'; export * from './FormGroupWithHelpText'; +export * from './HelpIconPopover'; export * from './Icons'; export * from './LoadingDots'; export * from './Page'; diff --git a/packages/forklift-console-plugin/src/modules/Providers/views/migrate/components/PlansCreateForm.tsx b/packages/forklift-console-plugin/src/modules/Providers/views/migrate/components/PlansCreateForm.tsx index 12c4fe6eb..bb61cdf2a 100644 --- a/packages/forklift-console-plugin/src/modules/Providers/views/migrate/components/PlansCreateForm.tsx +++ b/packages/forklift-console-plugin/src/modules/Providers/views/migrate/components/PlansCreateForm.tsx @@ -1,9 +1,9 @@ import React, { ReactNode, useState } from 'react'; import { FilterableSelect } from 'src/components'; import SectionHeading from 'src/components/headers/SectionHeading'; -import { useForkliftTranslation } from 'src/utils/i18n'; +import { ForkliftTrans, useForkliftTranslation } from 'src/utils/i18n'; -import { FormGroupWithHelpText } from '@kubev2v/common'; +import { FormGroupWithHelpText, HelpIconPopover } from '@kubev2v/common'; import { NetworkMapModelGroupVersionKind, ProviderModelGroupVersionKind, @@ -19,6 +19,8 @@ import { Form, FormSelect, FormSelectOption, + Stack, + StackItem, TextInput, } from '@patternfly/react-core'; @@ -275,6 +277,26 @@ export const PlansCreateForm = ({ id="targetNamespace" validated={validation.targetNamespace} placeholder={t('Select a namespace')} + labelIcon={ + + + + + Namespaces, also known as projects, separate resources within clusters. + + + + + + The target namespace is the namespace within your selected target provider + that your virtual machines will be migrated to. This is different from the + namespace that your migration plan will be created in and where your provider + was created. + + + + + } > ({ From f866925d20f5a635e6b44200e3c03a86dbf41061 Mon Sep 17 00:00:00 2001 From: Jeff Puzzo Date: Thu, 12 Dec 2024 22:42:29 -0500 Subject: [PATCH 9/9] [MTV-1686] Simplify/update migration plan status cell Signed-off-by: Jeff Puzzo --- .../en/plugin__forklift-console-plugin.json | 11 +- .../modules/Plans/hooks/usePlanMigration.ts | 4 +- .../components/StatusDetailsItem.tsx | 4 +- .../src/modules/Plans/views/list/PlanRow.tsx | 4 +- .../Plans/views/list/PlansListPage.tsx | 4 +- .../views/list/components/ActionsCell.tsx | 42 +----- .../views/list/components/PlanStatusCell.tsx | 130 ++++++++++++++++++ .../list/components/PlanStatusVmCount.tsx | 43 ++++++ .../views/list/components/StatusCell.tsx | 29 ---- .../Plans/views/list/components/VMsCell.tsx | 12 +- .../views/list/components/VMsProgressCell.tsx | 104 -------------- .../Plans/views/list/components/index.ts | 3 +- 12 files changed, 197 insertions(+), 193 deletions(-) create mode 100644 packages/forklift-console-plugin/src/modules/Plans/views/list/components/PlanStatusCell.tsx create mode 100644 packages/forklift-console-plugin/src/modules/Plans/views/list/components/PlanStatusVmCount.tsx delete mode 100644 packages/forklift-console-plugin/src/modules/Plans/views/list/components/StatusCell.tsx delete mode 100644 packages/forklift-console-plugin/src/modules/Plans/views/list/components/VMsProgressCell.tsx diff --git a/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json b/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json index dbe3d2f99..5826254a1 100644 --- a/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json +++ b/packages/forklift-console-plugin/locales/en/plugin__forklift-console-plugin.json @@ -1,17 +1,15 @@ { "{{Canceled}} canceled": "{{Canceled}} canceled", - "{{canceled}} VMs canceled": "{{canceled}} VMs canceled", "{{completed}} / {{total}}": "{{completed}} / {{total}}", "{{dateLabel}} Failed: {{value}}": "{{dateLabel}} Failed: {{value}}", "{{dateLabel}} Running: {{value}}": "{{dateLabel}} Running: {{value}}", "{{dateLabel}} Succeeded: {{value}}": "{{dateLabel}} Succeeded: {{value}}", - "{{error}} VMs failed": "{{error}} VMs failed", "{{label}} field is missing from the secret data.": "{{label}} field is missing from the secret data.", "{{name}} Details": "{{name}} Details", "{{selectedLength}} hosts selected.": "{{selectedLength}} hosts selected.", "{{success}} of {{total}} VMs migrated": "{{success}} of {{total}} VMs migrated", - "{{success}} VMs succeeded": "{{success}} VMs succeeded", - "{{total}} VMs": "{{total}} VMs", + "{{total}} VM": "{{total}} VM", + "{{total}} VM_plural": "{{total}} VMs", "{{vmCount}} VMs selected ": "{{vmCount}} VMs selected ", "{children}": "{children}", "24 hours": "24 hours", @@ -253,6 +251,7 @@ "Migration plan state information and progress": "Migration plan state information and progress", "Migration plans are used to plan migration or virtualization workloads from source providers to target providers.": "Migration plans are used to plan migration or virtualization workloads from source providers to target providers.", "Migration started": "Migration started", + "Migration status": "Migration status", "Migration Toolkit for Virtualization": "Migration Toolkit for Virtualization", "Migrations": "Migrations", "Migrations (last 24 hours)": "Migrations (last 24 hours)", @@ -401,7 +400,6 @@ "Remove virtual machines": "Remove virtual machines", "Reorder": "Reorder", "Resources": "Resources", - "Restart": "Restart", "Restart migration": "Restart migration", "Restore default columns": "Restore default columns", "Return to the providers list page": "Return to the providers list page", @@ -456,7 +454,6 @@ "Start migration": "Start migration", "Started at": "Started at", "Status": "Status", - "Status details": "Status details", "Storage": "Storage", "Storage classes": "Storage classes", "Storage domains": "Storage domains", @@ -511,7 +508,6 @@ "Token": "Token", "Total CPU count:": "Total CPU count:", "Total memory:": "Total memory:", - "Total of {{total}} VMs are planned for migration:": "Total of {{total}} VMs are planned for migration:", "Total virtual machines": "Total virtual machines", "Total: {{length}}": "Total: {{length}}", "Transfer Network": "Transfer Network", @@ -536,6 +532,7 @@ "URL of the providers API endpoint. The URL must be a valid endpoint for the provider type, see\n the documentation for each provider type to learn more about the URL format.": "URL of the providers API endpoint. The URL must be a valid endpoint for the provider type, see\n the documentation for each provider type to learn more about the URL format.", "User ID": "User ID", "Username": "Username", + "Validating...": "Validating...", "Validation Failed": "Validation Failed", "vCenter": "vCenter", "VDDK init image": "VDDK init image", diff --git a/packages/forklift-console-plugin/src/modules/Plans/hooks/usePlanMigration.ts b/packages/forklift-console-plugin/src/modules/Plans/hooks/usePlanMigration.ts index ac185e98e..1a5f90f4c 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/hooks/usePlanMigration.ts +++ b/packages/forklift-console-plugin/src/modules/Plans/hooks/usePlanMigration.ts @@ -1,7 +1,7 @@ import { MigrationModelGroupVersionKind, V1beta1Migration, V1beta1Plan } from '@kubev2v/types'; -import { useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk'; +import { useK8sWatchResource, WatchK8sResult } from '@openshift-console/dynamic-plugin-sdk'; -export const usePlanMigration = (plan: V1beta1Plan) => { +export const usePlanMigration = (plan: V1beta1Plan): WatchK8sResult => { const [migrations, migrationLoaded, migrationLoadError] = useK8sWatchResource( { groupVersionKind: MigrationModelGroupVersionKind, diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/details/components/DetailsSection/components/StatusDetailsItem.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/details/components/DetailsSection/components/StatusDetailsItem.tsx index 273c47345..75cb5952c 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/details/components/DetailsSection/components/StatusDetailsItem.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/details/components/DetailsSection/components/StatusDetailsItem.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { StatusCell } from 'src/modules/Plans/views/list'; +import { PlanStatusCell } from 'src/modules/Plans/views/list'; import { DetailsItem } from 'src/modules/Providers/utils'; import { useForkliftTranslation } from 'src/utils/i18n'; @@ -12,7 +12,7 @@ export const StatusDetailsItem: React.FC = ({ resource }) } + content={} /> ); }; diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/list/PlanRow.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/list/PlanRow.tsx index 127d712fb..afa782c19 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/list/PlanRow.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/list/PlanRow.tsx @@ -12,8 +12,8 @@ import { CellProps, NamespaceCell, PlanCell, + PlanStatusCell, ProviderLinkCell, - StatusCell, VMsCell, } from './components'; @@ -47,7 +47,7 @@ const cellRenderers: Record> = { }, ['destination']: ProviderLinkCell, ['source']: ProviderLinkCell, - ['phase']: StatusCell, + ['phase']: PlanStatusCell, ['vms']: VMsCell, ['description']: ({ data }: CellProps) => {data?.obj?.spec?.description}, ['actions']: ActionsCell, diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/list/PlansListPage.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/list/PlansListPage.tsx index 814b510ae..ff932b781 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/list/PlansListPage.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/list/PlansListPage.tsx @@ -74,12 +74,12 @@ export const fieldsMetadataFactory: ResourceFieldFactory = (t) => [ { resourceFieldId: 'phase', jsonPath: getPlanPhase, - label: t('Status'), + label: t('Migration status'), isVisible: true, filter: { type: 'enum', primary: true, - placeholderLabel: t('Status'), + placeholderLabel: t('Migration status'), values: planPhases, }, sortable: true, diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/list/components/ActionsCell.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/list/components/ActionsCell.tsx index 8a9fe3527..c9bcd791f 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/list/components/ActionsCell.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/list/components/ActionsCell.tsx @@ -1,20 +1,12 @@ import React from 'react'; import { PlanActionsDropdown } from 'src/modules/Plans/actions'; -import { PlanCutoverMigrationModal, PlanStartMigrationModal } from 'src/modules/Plans/modals'; -import { - canPlanReStart, - canPlanStart, - isPlanArchived, - isPlanExecuting, -} from 'src/modules/Plans/utils'; +import { PlanCutoverMigrationModal } from 'src/modules/Plans/modals'; +import { isPlanArchived, isPlanExecuting } from 'src/modules/Plans/utils'; import { useModal } from 'src/modules/Providers/modals'; import { useForkliftTranslation } from 'src/utils/i18n'; -import { PlanModel } from '@kubev2v/types'; import { Button, Flex, FlexItem } from '@patternfly/react-core'; import CutoverIcon from '@patternfly/react-icons/dist/esm/icons/migration-icon'; -import StartIcon from '@patternfly/react-icons/dist/esm/icons/play-icon'; -import ReStartIcon from '@patternfly/react-icons/dist/esm/icons/redo-icon'; import { CellProps } from './CellProps'; @@ -23,46 +15,20 @@ export const ActionsCell = ({ data }: CellProps) => { const { showModal } = useModal(); const plan = data.obj; - - const canStart = canPlanStart(plan); - const canReStart = canPlanReStart(plan); - const isWarmAndExecuting = plan?.spec?.warm && isPlanExecuting(plan); const isArchived = isPlanArchived(plan); - const buttonStartLabel = canReStart ? t('Restart') : t('Start'); - const buttonStartIcon = canReStart ? : ; - const buttonCutoverIcon = ; - - const onClickPlanStartMigration = () => { - showModal( - , - ); - }; - const onClickPlanCutoverMigration = () => { - showModal(); + showModal(); }; return ( - {canStart && ( - - - - )} - {isWarmAndExecuting && !isArchived && ( - diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/list/components/PlanStatusCell.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/list/components/PlanStatusCell.tsx new file mode 100644 index 000000000..b023cd402 --- /dev/null +++ b/packages/forklift-console-plugin/src/modules/Plans/views/list/components/PlanStatusCell.tsx @@ -0,0 +1,130 @@ +import React from 'react'; +import { usePlanMigration } from 'src/modules/Plans/hooks'; +import { PlanStartMigrationModal } from 'src/modules/Plans/modals'; +import { + getMigrationVmsCounts, + getPlanPhase, + isPlanArchived, + isPlanExecuting, +} from 'src/modules/Plans/utils'; +import { useModal } from 'src/modules/Providers/modals'; +import { getResourceUrl } from 'src/modules/Providers/utils'; +import { useForkliftTranslation } from 'src/utils/i18n'; + +import { PlanModel, PlanModelRef } from '@kubev2v/types'; +import { Button, Flex, FlexItem, Label, Spinner, Split, SplitItem } from '@patternfly/react-core'; +import StartIcon from '@patternfly/react-icons/dist/esm/icons/play-icon'; + +import { CellProps } from './CellProps'; +import { PlanStatusVmCount } from './PlanStatusVmCount'; + +type VmPipelineTask = { + vmName: string; + task: string; + status: string; +}; + +export const PlanStatusCell: React.FC = ({ data }) => { + const { t } = useForkliftTranslation(); + const { showModal } = useModal(); + const plan = data?.obj; + + const vms = plan?.spec?.vms; + const vmStatuses = plan?.status?.migration?.vms; + const [lastMigration] = usePlanMigration(plan); + + const isWarmAndExecuting = plan.spec?.warm && isPlanExecuting(plan); + const isWaitingForCutover = isWarmAndExecuting && !isPlanArchived(plan); + + const vmPipelineTasks = lastMigration?.status.vms?.reduce( + (acc: VmPipelineTask[], migrationVm) => { + migrationVm.pipeline.forEach((pipelineStep) => { + acc.push({ vmName: migrationVm.name, task: pipelineStep.name, status: pipelineStep.phase }); + }); + + return acc; + }, + [], + ); + + const phase = getPlanPhase(data); + const isPlanLoading = !isWaitingForCutover && (phase === 'Running' || phase === 'Archiving'); + const planURL = getResourceUrl({ + reference: PlanModelRef, + name: plan?.metadata?.name, + namespace: plan?.metadata?.namespace, + }); + + // All VM count links point to the same place for now, + // but will be updated to target only affected VMs in the future. + // Could possibly use a querystring to dictate a table filter for the list of VMs. + const vmCountLinkPath = `${planURL}/vms`; + + if (phase === 'Ready') { + return ( + + ); + } + + const vmCount = getMigrationVmsCounts(vmStatuses); + const completedVmPipelineTasks = vmPipelineTasks?.filter( + (pipelineTask) => pipelineTask.status === 'Completed', + ); + const progressValue = vmPipelineTasks?.length + ? (100 * completedVmPipelineTasks.length) / vmPipelineTasks.length + : 0; + + return ( + + {isPlanLoading ? ( + + ) : phase === 'NotReady' ? ( + t('Validating...') + ) : ( + + )} + + {progressValue !== 0 && isPlanLoading && ( + {Math.trunc(progressValue)}% + )} + + + {vmCount?.success > 0 && ( + + + + )} + + {phase !== 'Running' && + phase !== 'NotReady' && + vms?.length && + !vmCount?.error && + !vmCount.success && ( + + + + )} + + {vmCount?.error > 0 && ( + + + + )} + + + ); +}; diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/list/components/PlanStatusVmCount.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/list/components/PlanStatusVmCount.tsx new file mode 100644 index 000000000..0fcfe21ff --- /dev/null +++ b/packages/forklift-console-plugin/src/modules/Plans/views/list/components/PlanStatusVmCount.tsx @@ -0,0 +1,43 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { useForkliftTranslation } from 'src/utils'; + +import { Flex, FlexItem, Icon, IconComponentProps } from '@patternfly/react-core'; +import CheckCircleIcon from '@patternfly/react-icons/dist/esm/icons/check-circle-icon'; +import ExclamationCircleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon'; +import ExclamationTriangleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-triangle-icon'; + +interface PlanStatusVmCountProps { + count: number; + status: IconComponentProps['status']; + linkPath: string; +} + +export const PlanStatusVmCount: React.FC = ({ + count, + status, + linkPath, +}) => { + const { t } = useForkliftTranslation(); + + const statusIcon = React.useMemo(() => { + switch (status) { + case 'success': + return ; + case 'warning': + return ; + case 'danger': + return ; + } + }, [status]); + + return ( + + {statusIcon} + + + {t('{{total}} VM', { count, total: count })} + + + ); +}; diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/list/components/StatusCell.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/list/components/StatusCell.tsx deleted file mode 100644 index 2a53170e7..000000000 --- a/packages/forklift-console-plugin/src/modules/Plans/views/list/components/StatusCell.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import { getPhaseLabel, getPlanPhase } from 'src/modules/Plans/utils'; -import { TableIconCell } from 'src/modules/Providers/utils'; - -import { CellProps } from './CellProps'; -import { ErrorStatusCell } from './ErrorStatusCell'; -import { PlanStatusIcon } from './PlanStatusIcon'; -import { VMsProgressCell } from './VMsProgressCell'; - -export const StatusCell: React.FC = (props) => { - const { data } = props; - - const phase = getPlanPhase(data); - const phaseLabel = getPhaseLabel(phase); - - switch (phase) { - case 'Error': - case 'Warning': - return ErrorStatusCell(props); - case 'Failed': - case 'Canceled': - case 'Running': - case 'Succeeded': - case 'vmError': - return VMsProgressCell(props); - } - - return }>{phaseLabel}; -}; diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/list/components/VMsCell.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/list/components/VMsCell.tsx index 4075a312b..a287dedd5 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/list/components/VMsCell.tsx +++ b/packages/forklift-console-plugin/src/modules/Plans/views/list/components/VMsCell.tsx @@ -11,13 +11,13 @@ import { CellProps } from './CellProps'; export const VMsCell: React.FC = ({ data }) => { const { t } = useForkliftTranslation(); - - const specVms = data?.obj?.spec?.vms; + const plan = data?.obj; + const specVms = plan?.spec?.vms; const planURL = getResourceUrl({ reference: PlanModelRef, - name: data?.obj?.metadata?.name, - namespace: data?.obj?.metadata?.namespace, + name: plan?.metadata?.name, + namespace: plan?.metadata?.namespace, }); return ( @@ -26,7 +26,9 @@ export const VMsCell: React.FC = ({ data }) => { - {t('{{total}} VMs', { total: specVms?.length })} + + {t('{{total}} VM', { count: specVms?.length, total: specVms?.length })} + ); diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/list/components/VMsProgressCell.tsx b/packages/forklift-console-plugin/src/modules/Plans/views/list/components/VMsProgressCell.tsx deleted file mode 100644 index a566d8978..000000000 --- a/packages/forklift-console-plugin/src/modules/Plans/views/list/components/VMsProgressCell.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import React from 'react'; -import { Link } from 'react-router-dom'; -import { - getMigrationVmsCounts, - getPhaseLabel, - getPlanPhase, - getPlanProgressVariant, - MigrationVmsCounts, -} from 'src/modules/Plans/utils'; -import { getResourceUrl } from 'src/modules/Providers/utils'; -import { useForkliftTranslation } from 'src/utils/i18n'; - -import { PlanModelRef } from '@kubev2v/types'; -import { - Button, - Popover, - Progress, - ProgressMeasureLocation, - ProgressSize, - Split, - SplitItem, -} from '@patternfly/react-core'; -import { HelpIcon, VirtualMachineIcon } from '@patternfly/react-icons'; - -import { CellProps } from './CellProps'; - -type PlanStatusDetailsProps = { - counters: MigrationVmsCounts; -}; - -const PlanStatusDetails: React.FC = (props) => { - const { t } = useForkliftTranslation(); - - return ( -
- {t('Total of {{total}} VMs are planned for migration:', props.counters)} -
- {t('{{success}} VMs succeeded', props.counters)} -
- {t('{{error}} VMs failed', props.counters)} -
- {t('{{canceled}} VMs canceled', props.counters)} -
-
- ); -}; - -export const VMsProgressCell: React.FC = ({ data }) => { - const { t } = useForkliftTranslation(); - - const specVms = data?.obj?.spec?.vms; - const vms = data?.obj?.status?.migration?.vms; - - const phase = getPlanPhase(data); - const phaseLabel = t(getPhaseLabel(phase)); - - const planURL = getResourceUrl({ - reference: PlanModelRef, - name: data?.obj?.metadata?.name, - namespace: data?.obj?.metadata?.namespace, - }); - - if (!vms) { - return ( - - - - - - {t('{{total}} VMs', { total: specVms?.length || 0 })} - - - ); - } - - const counters = getMigrationVmsCounts(vms); - const progressVariant = getPlanProgressVariant(phase); - - return ( -
- {t('{{success}} of {{total}} VMs migrated', counters)} - } - valueText={t('{{success}} of {{total}} VMs migrated', counters)} - value={counters?.total > 0 ? (100 * counters?.success) / counters?.total : 0} - title={ - {t('Status details')}
} - bodyContent={} - > - - - } - size={ProgressSize.sm} - measureLocation={ProgressMeasureLocation.top} - variant={progressVariant} - /> - - ); -}; diff --git a/packages/forklift-console-plugin/src/modules/Plans/views/list/components/index.ts b/packages/forklift-console-plugin/src/modules/Plans/views/list/components/index.ts index 3f8035961..f95b2466e 100644 --- a/packages/forklift-console-plugin/src/modules/Plans/views/list/components/index.ts +++ b/packages/forklift-console-plugin/src/modules/Plans/views/list/components/index.ts @@ -5,9 +5,8 @@ export * from './ErrorStatusCell'; export * from './NamespaceCell'; export * from './NetworkMapLinkCell'; export * from './PlanCell'; +export * from './PlanStatusCell'; export * from './PlanStatusIcon'; export * from './ProviderLinkCell'; -export * from './StatusCell'; export * from './VMsCell'; -export * from './VMsProgressCell'; // @endindex