diff --git a/pkg/harvester/components/vm-migration/ConfigureMappingsStep.vue b/pkg/harvester/components/vm-migration/ConfigureMappingsStep.vue
index e2bbb3a1..4184f68d 100644
--- a/pkg/harvester/components/vm-migration/ConfigureMappingsStep.vue
+++ b/pkg/harvester/components/vm-migration/ConfigureMappingsStep.vue
@@ -2,11 +2,10 @@
import { ref, computed, watch } from 'vue';
import { useStore } from 'vuex';
import Loading from '@shell/components/Loading';
-import LabeledSelect from '@shell/components/form/LabeledSelect';
-import { RcItemCard } from '@components/RcItemCard';
import { STORAGE_CLASS, NETWORK_ATTACHMENT } from '@shell/config/types';
import { useI18n } from '@shell/composables/useI18n';
import { HCI } from '../../types';
+import MappingColumn from './MappingColumn.vue';
const props = defineProps({
providerName: { type: String, default: '' },
@@ -268,7 +267,7 @@ const formatStorageDetail = (entry) => {
const buildNetworkMapSpec = (providerRef) => {
return {
- map: networkEntries.value.map((entry) => {
+ map: networkEntries.value.filter((entry) => !!entry.target).map((entry) => {
if (entry.target === 'pod') {
return {
source: { name: entry.name, id: entry.id },
@@ -302,7 +301,7 @@ const buildNetworkMapSpec = (providerRef) => {
const buildStorageMapSpec = (providerRef) => {
return {
- map: storageEntries.value.map((entry) => ({
+ map: storageEntries.value.filter((entry) => !!entry.target).map((entry) => ({
source: { name: entry.name, id: entry.id },
destination: { storageClass: entry.target },
})),
@@ -478,16 +477,23 @@ const init = async() => {
}
}
- if (props.existingNetworkMap?.spec?.map) {
- applyNetworkMapTargets(props.existingNetworkMap.spec.map);
- } else {
- applyDefaultNetworkMap();
+ const hasExistingNetworkTargets = networkEntries.value.some((e) => !!e.target);
+ const hasExistingStorageTargets = storageEntries.value.some((e) => !!e.target);
+
+ if (!hasExistingNetworkTargets) {
+ if (props.existingNetworkMap?.spec?.map) {
+ applyNetworkMapTargets(props.existingNetworkMap.spec.map);
+ } else {
+ applyDefaultNetworkMap();
+ }
}
- if (props.existingStorageMap?.spec?.map) {
- applyStorageMapTargets(props.existingStorageMap.spec.map);
- } else {
- applyDefaultStorageMap();
+ if (!hasExistingStorageTargets) {
+ if (props.existingStorageMap?.spec?.map) {
+ applyStorageMapTargets(props.existingStorageMap.spec.map);
+ } else {
+ applyDefaultStorageMap();
+ }
}
loading.value = false;
@@ -502,114 +508,45 @@ init();
v-else
class="configure-mappings"
>
-
+
{{ t('harvester.addons.vmMigration.configureMappings.description') }}
-
-
-
-
- {{ t('harvester.addons.vmMigration.configureMappings.networkMapping.title') }}
-
-
- {{ t('harvester.addons.vmMigration.configureMappings.networkMapping.description') }}
-
-
+
+
+ VLAN {{ entry.vlanId || '0' }}
+
+
-
-
-
-
-
- {{ entry.name }}
- VLAN {{ entry.vlanId || '0' }}
-
-
-
-
-
-
-
-
-
-
- Used by: {{ entry.usedBy.join(', ') }}
-
-
-
-
-
-
-
-
-
-
-
- {{ t('harvester.addons.vmMigration.configureMappings.storageMapping.title') }}
-
-
- {{ t('harvester.addons.vmMigration.configureMappings.storageMapping.description') }}
-
-
-
-
-
-
-
-
- {{ entry.name }}
- {{ formatStorageDetail(entry) }}
-
-
-
-
-
-
-
-
-
-
- Used by: {{ entry.usedBy.join(', ') }}
-
-
-
-
-
-
+
+
+ {{ formatStorageDetail(entry) }}
+
+
diff --git a/pkg/harvester/components/vm-migration/ConfigureProviderStep.vue b/pkg/harvester/components/vm-migration/ConfigureProviderStep.vue
index 5e5fc309..850f2cc1 100644
--- a/pkg/harvester/components/vm-migration/ConfigureProviderStep.vue
+++ b/pkg/harvester/components/vm-migration/ConfigureProviderStep.vue
@@ -518,7 +518,7 @@ defineExpose({ testConnection, clickTestButton });
@@ -598,7 +598,7 @@ defineExpose({ testConnection, clickTestButton });
:label="t('harvester.addons.vmMigration.configureProvider.skipSsl')"
:disabled="isExistingProvider && !editMode"
/>
-
+
{{ t('harvester.addons.vmMigration.configureProvider.skipSslHint') }}
@@ -670,5 +670,9 @@ defineExpose({ testConnection, clickTestButton });
gap: 20px;
}
}
+
+ :deep(.checkbox-label) {
+ color: var(--body-text);
+ }
}
diff --git a/pkg/harvester/components/vm-migration/MappingColumn.vue b/pkg/harvester/components/vm-migration/MappingColumn.vue
new file mode 100644
index 00000000..f295c878
--- /dev/null
+++ b/pkg/harvester/components/vm-migration/MappingColumn.vue
@@ -0,0 +1,181 @@
+
+
+
+
+
+
+ {{ title }}
+
+
+ {{ description }}
+
+
+
+
+
+
+
+
+ {{ entry.name }}
+
+
+
+
+
+
+
+
+
+
+
+ Used by: {{ entry.usedBy.join(', ') }}
+
+
+
+
+
+
+
+
+
diff --git a/pkg/harvester/components/vm-migration/ReviewMigrationStep.vue b/pkg/harvester/components/vm-migration/ReviewMigrationStep.vue
index c8c761a2..d923d852 100644
--- a/pkg/harvester/components/vm-migration/ReviewMigrationStep.vue
+++ b/pkg/harvester/components/vm-migration/ReviewMigrationStep.vue
@@ -338,7 +338,7 @@ defineExpose({ startMigration: startMigrationAction });
-
{{ vm.os }}
+
{{ vm.os }}
{{ vm.cpus }} vCPU • {{ vm.memGB }} • {{ vm.diskDisplay }}
diff --git a/pkg/harvester/components/vm-migration/SelectVmsStep.vue b/pkg/harvester/components/vm-migration/SelectVmsStep.vue
index 02f6a58e..97e10a61 100644
--- a/pkg/harvester/components/vm-migration/SelectVmsStep.vue
+++ b/pkg/harvester/components/vm-migration/SelectVmsStep.vue
@@ -357,6 +357,8 @@ const refreshVMs = async() => {
emit('complete', { selectedVMs: selectedVMs.value });
refreshing.value = false;
+ await nextTick();
+
const table = sortableTableRef.value;
if (table) {
@@ -366,6 +368,8 @@ const refreshVMs = async() => {
table.update(rowsToReselect, []);
}
}
+
+ skipNextSelectionEvent = false;
};
const init = async() => {
@@ -403,7 +407,7 @@ init();
v-else
class="select-vms-step"
>
-
+
{{ t('harvester.addons.vmMigration.selectVms.discovered', { count: vmCount }) }}
{{ t('harvester.addons.vmMigration.selectVms.availableVms') }}
- {{ selectedCount }} {{ t('harvester.addons.vmMigration.selectVms.selected') }}
+ {{ selectedCount }} {{ t('harvester.addons.vmMigration.selectVms.selected') }}
{{ row.vmName }}
- {{ row.vmId }}
+ {{ row.vmId }}
{{ row.resourcesDisplay }}
- {{ row.resourcesSub }}
+ {{ row.resourcesSub }}
{{ net.name }}
- {{ net.id }}
+ {{ net.id }}
@@ -485,7 +489,7 @@ init();
:class="{ 'mt-4': i > 0 }"
>
{{ ds.name }}
- {{ ds.id }}
+ {{ ds.id }}
@@ -531,7 +535,7 @@ init();
font-weight: 600;
}
- .text-muted {
+ .text-deemphasized {
font-size: 13px;
}
}
diff --git a/pkg/harvester/l10n/en-us.yaml b/pkg/harvester/l10n/en-us.yaml
index b3ab03d8..9c15a809 100644
--- a/pkg/harvester/l10n/en-us.yaml
+++ b/pkg/harvester/l10n/en-us.yaml
@@ -1910,10 +1910,11 @@ harvester:
description: Map VMware networks and datastores to Harvester and Longhorn target resources
save: Save Mappings and Continue
noTemplate: Start from scratch
+ removeMap: Remove Map
networkMapping:
title: Network Mapping
description: Map VMware port groups to Harvester networks
- placeholder: Choose a Harvester network...
+ placeholder: Choose a Harvester network
template: Use existing network mapping as template
storageMapping:
title: Storage Mapping
diff --git a/pkg/harvester/models/forklift.konveyor.io.plan.js b/pkg/harvester/models/forklift.konveyor.io.plan.js
index c909abe8..c06a85d0 100644
--- a/pkg/harvester/models/forklift.konveyor.io.plan.js
+++ b/pkg/harvester/models/forklift.konveyor.io.plan.js
@@ -132,29 +132,29 @@ export default class ForkliftPlan extends HarvesterResource {
}
get _availableActions() {
+ const canStop = this.isMigrating && !this.planCanceled;
+ const canStart = !this.planSucceeded && (!this.isMigrating || this.planFailed || this.planCanceled || this.planCritical);
+ const out = [];
+
+ if (canStart) {
+ out.push({
+ action: 'startMigration',
+ enabled: true,
+ icon: 'icon icon-play',
+ label: this.isForkliftDashboard ? 'Restart' : 'Start',
+ });
+ }
+
+ if (canStop) {
+ out.push({
+ action: 'stopMigration',
+ enabled: true,
+ icon: 'icon icon-pause',
+ label: 'Stop',
+ });
+ }
+
if (this.isForkliftDashboard) {
- const canStop = this.isMigrating && !this.planCanceled;
- const canStart = !this.planSucceeded && (!this.isMigrating || this.planFailed || this.planCanceled || this.planCritical);
- const out = [];
-
- if (canStart) {
- out.push({
- action: 'startMigration',
- enabled: true,
- icon: 'icon icon-play',
- label: 'Start',
- });
- }
-
- if (canStop) {
- out.push({
- action: 'stopMigration',
- enabled: true,
- icon: 'icon icon-pause',
- label: 'Stop',
- });
- }
-
out.push({
action: 'promptRemove',
altAction: 'remove',
@@ -167,9 +167,11 @@ export default class ForkliftPlan extends HarvesterResource {
});
return out;
- }
+ } else {
+ out.push(...super._availableActions);
- return super._availableActions;
+ return out;
+ }
}
async stopMigration() {