feat: add migration plan duration time column (#1005)

* feat: add migration plan duration time column

Signed-off-by: Andy Lee <andy.lee@suse.com>

* feat: allow duration column to be sorted

Signed-off-by: Andy Lee <andy.lee@suse.com>

---------

Signed-off-by: Andy Lee <andy.lee@suse.com>
This commit is contained in:
Andy Lee 2026-07-15 18:42:01 +08:00 committed by GitHub
parent aea53fdd65
commit 44297ada16
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 54 additions and 2 deletions

View File

@ -1947,6 +1947,7 @@ harvester:
plan: Migration Plan
progress: Progress
mappings: Mappings
duration: Duration
progress:
failed: Failed
migration: Migration

View File

@ -97,6 +97,28 @@ const formatPipelineTooltip = (pipeline = []) => {
.join('');
};
const formatDuration = (started, completed) => {
if (!started || !completed) {
return { display: null, seconds: -1 };
}
const startMs = new Date(started).getTime();
const endMs = new Date(completed).getTime();
if (isNaN(startMs) || isNaN(endMs) || endMs < startMs) {
return { display: null, seconds: -1 };
}
const totalSeconds = Math.floor((endMs - startMs) / 1000);
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = totalSeconds % 60;
const display = hours > 0 ? `${ hours }h ${ minutes }m` : `${ minutes }m ${ seconds }s`;
return { display, seconds: totalSeconds };
};
const rows = computed(() => {
return allPlans.value.map((plan) => {
const netMapName = plan.spec?.map?.network?.name;
@ -187,6 +209,11 @@ const rows = computed(() => {
plan.progress = plan.vmProgress.length > 0 ? Math.round(plan.vmProgress.reduce((sum, vm) => sum + vm.progress, 0) / plan.vmProgress.length * 10) / 10 : 0;
const durationResult = formatDuration(plan.status?.migration?.started, plan.status?.migration?.completed);
plan.duration = durationResult.display;
plan.durationSeconds = durationResult.seconds;
return plan;
});
});
@ -210,12 +237,19 @@ const headers = [
name: 'progress',
labelKey: 'harvester.addons.vmMigration.dashboard.columns.progress',
value: 'progress',
width: 500,
width: 450,
},
{
name: 'mappings',
labelKey: 'harvester.addons.vmMigration.dashboard.columns.mappings',
},
{
name: 'duration',
labelKey: 'harvester.addons.vmMigration.dashboard.columns.duration',
value: 'duration',
sort: 'durationSeconds',
width: 120,
},
{ ...AGE },
];
@ -302,7 +336,17 @@ init();
>
<template #cell:name="{ row }">
<div class="plan-name-cell">
<div class="plan-name">
<router-link
v-if="row.detailLocation"
:to="row.detailLocation"
class="plan-name"
>
{{ row.metadata.name }}
</router-link>
<div
v-else
class="plan-name"
>
{{ row.metadata.name }}
</div>
</div>
@ -373,6 +417,13 @@ init();
:storage-entries="row.storageEntries"
/>
</template>
<template #cell:duration="{ row }">
<span v-if="row.duration">{{ row.duration }}</span>
<span
v-else
class="text-muted"
>&mdash;</span>
</template>
</ResourceTable>
</div>
</template>