feat(lite/pool/VMs): ability to copy selected VMs (#6847)
This commit is contained in:
committed by
GitHub
parent
55b2e0292f
commit
27b5737f65
@@ -16,6 +16,7 @@
|
||||
- Display an error message if the data cannot be fetched (PR [#6525](https://github.com/vatesfr/xen-orchestra/pull/6525))
|
||||
- Add "Under Construction" views (PR [#6673](https://github.com/vatesfr/xen-orchestra/pull/6673))
|
||||
- Ability to change the state of selected VMs from the pool's list of VMs (PR [#6782](https://github.com/vatesfr/xen-orchestra/pull/6782))
|
||||
- Ability to copy selected VMs from the pool's list of VMs (PR [#6847](https://github.com/vatesfr/xen-orchestra/pull/6847))
|
||||
|
||||
## **0.1.0**
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<MenuItem
|
||||
v-tooltip="!areAllSelectedVmsHalted && $t('selected-vms-in-execution')"
|
||||
:busy="areSomeSelectedVmsCloning"
|
||||
:disabled="!areAllSelectedVmsHalted"
|
||||
:icon="faCopy"
|
||||
@click="handleCopy"
|
||||
>
|
||||
{{ $t("copy") }}
|
||||
</MenuItem>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import MenuItem from "@/components/menu/MenuItem.vue";
|
||||
import { vTooltip } from "@/directives/tooltip.directive";
|
||||
import { isOperationsPending } from "@/libs/utils";
|
||||
import { POWER_STATE, VM_OPERATION, type XenApiVm } from "@/libs/xen-api";
|
||||
import { useVmStore } from "@/stores/vm.store";
|
||||
import { useXenApiStore } from "@/stores/xen-api.store";
|
||||
import { faCopy } from "@fortawesome/free-solid-svg-icons";
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
selectedRefs: string[];
|
||||
}>();
|
||||
|
||||
const { getByOpaqueRef } = useVmStore().subscribe();
|
||||
|
||||
const selectedVms = computed(() =>
|
||||
props.selectedRefs
|
||||
.map((vmRef) => getByOpaqueRef(vmRef))
|
||||
.filter((vm): vm is XenApiVm => vm !== undefined)
|
||||
);
|
||||
|
||||
const areAllSelectedVmsHalted = computed(() =>
|
||||
selectedVms.value.every(
|
||||
(selectedVm) => selectedVm.power_state === POWER_STATE.HALTED
|
||||
)
|
||||
);
|
||||
|
||||
const areSomeSelectedVmsCloning = computed(() =>
|
||||
selectedVms.value.some((vm) => isOperationsPending(vm, VM_OPERATION.CLONE))
|
||||
);
|
||||
|
||||
const handleCopy = async () => {
|
||||
const xapiStore = useXenApiStore();
|
||||
|
||||
const vmRefsToClone = Object.fromEntries(
|
||||
selectedVms.value.map((vm) => [vm.$ref, `${vm.name_label} (COPY)`])
|
||||
);
|
||||
|
||||
await xapiStore.getXapi().vm.clone(vmRefsToClone);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="postcss" scoped></style>
|
||||
@@ -9,7 +9,7 @@
|
||||
<UiIcon :icon="faAngleDown" />
|
||||
</UiButton>
|
||||
</template>
|
||||
<VmsPowerActionsMenu :vm-refs="[vm.$ref]" />
|
||||
<VmActionPowerStateItems :vm-refs="[vm.$ref]" />
|
||||
</AppMenu>
|
||||
</template>
|
||||
</TitleBar>
|
||||
@@ -21,7 +21,7 @@ import TitleBar from "@/components/TitleBar.vue";
|
||||
import UiIcon from "@/components/ui/icon/UiIcon.vue";
|
||||
import UiButton from "@/components/ui/UiButton.vue";
|
||||
import { useVmStore } from "@/stores/vm.store";
|
||||
import VmsPowerActionsMenu from "@/components/vm/VmsPowerActionsMenu.vue";
|
||||
import VmActionPowerStateItems from "@/components/vm/VmActionItems/VmActionPowerStateItems.vue";
|
||||
import {
|
||||
faAngleDown,
|
||||
faDisplay,
|
||||
|
||||
@@ -12,15 +12,13 @@
|
||||
<MenuItem :icon="faPowerOff">
|
||||
{{ $t("change-power-state") }}
|
||||
<template #submenu>
|
||||
<VmsPowerActionsMenu :vm-refs="selectedRefs" />
|
||||
<VmActionPowerStateItems :vm-refs="selectedRefs" />
|
||||
</template>
|
||||
</MenuItem>
|
||||
<MenuItem v-tooltip="$t('coming-soon')" :icon="faRoute">
|
||||
{{ $t("migrate") }}
|
||||
</MenuItem>
|
||||
<MenuItem v-tooltip="$t('coming-soon')" :icon="faCopy">
|
||||
{{ $t("copy") }}
|
||||
</MenuItem>
|
||||
<VmActionCopyItem :selected-refs="selectedRefs" />
|
||||
<MenuItem v-tooltip="$t('coming-soon')" :icon="faEdit">
|
||||
{{ $t("edit-config") }}
|
||||
</MenuItem>
|
||||
@@ -60,13 +58,13 @@
|
||||
import AppMenu from "@/components/menu/AppMenu.vue";
|
||||
import MenuItem from "@/components/menu/MenuItem.vue";
|
||||
import UiButton from "@/components/ui/UiButton.vue";
|
||||
import VmActionCopyItem from "@/components/vm/VmActionItems/VmActionCopyItem.vue";
|
||||
import { useUiStore } from "@/stores/ui.store";
|
||||
import VmsPowerActionsMenu from "@/components/vm/VmsPowerActionsMenu.vue";
|
||||
import VmActionPowerStateItems from "@/components/vm/VmActionItems/VmActionPowerStateItems.vue";
|
||||
import { vTooltip } from "@/directives/tooltip.directive";
|
||||
import {
|
||||
faCamera,
|
||||
faCode,
|
||||
faCopy,
|
||||
faDisplay,
|
||||
faEdit,
|
||||
faEllipsis,
|
||||
|
||||
@@ -333,6 +333,7 @@ export default class XenApi {
|
||||
XenApiVm["$ref"],
|
||||
XenApiVm["power_state"]
|
||||
>;
|
||||
type VmRefsToClone = Record<XenApiVm["$ref"], /* Cloned VM name */ string>;
|
||||
|
||||
return {
|
||||
start: (vmRefs: VmRefs) =>
|
||||
@@ -383,6 +384,15 @@ export default class XenApi {
|
||||
)
|
||||
);
|
||||
},
|
||||
clone: (vmRefsToClone: VmRefsToClone) => {
|
||||
const vmRefs = Object.keys(vmRefsToClone);
|
||||
|
||||
return Promise.all(
|
||||
vmRefs.map((vmRef) =>
|
||||
this._call("VM.clone", [vmRef, vmRefsToClone[vmRef]])
|
||||
)
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
},
|
||||
"resume": "Resume",
|
||||
"save": "Save",
|
||||
"selected-vms-in-execution": "Some selected VMs are running",
|
||||
"send-us-feedback": "Send us feedback",
|
||||
"settings": "Settings",
|
||||
"shutdown": "Shutdown",
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
},
|
||||
"resume": "Reprendre",
|
||||
"save": "Enregistrer",
|
||||
"selected-vms-in-execution": "Certaines VMs sélectionnées sont en cours d'exécution",
|
||||
"send-us-feedback": "Envoyez-nous vos commentaires",
|
||||
"settings": "Paramètres",
|
||||
"shutdown": "Arrêter",
|
||||
|
||||
Reference in New Issue
Block a user