Update USB devices

- Add columns and filters
- Filter other vm devices in pci and usb devices pages when selecting devices

Signed-off-by: Francesco Torchia <francesco.torchia@suse.com>
This commit is contained in:
Francesco Torchia
2024-10-23 17:01:18 +02:00
parent 6959cee050
commit 7c04b1417a
7 changed files with 149 additions and 29 deletions
@@ -55,10 +55,13 @@ export default {
const selectedDevices = [];
const oldFormatDevices = [];
(this.value?.domain?.devices?.hostDevices || []).forEach(({ name, deviceName }) => {
const vmDevices = this.value?.domain?.devices?.hostDevices || [];
const otherDevices = this.otherDevices(vmDevices).map(({name}) => name);
vmDevices.forEach(({ name, deviceName }) => {
const checkName = (deviceName || '').split('/')?.[1];
if (checkName && name.includes(checkName)) {
if (checkName && name.includes(checkName) && !otherDevices.includes(name)) {
oldFormatDevices.push(name);
} else if (this.enabledDevices.find(device => device?.metadata?.name === name)) {
selectedDevices.push(name);
@@ -96,7 +99,12 @@ export default {
};
});
set(this.value.domain.devices, 'hostDevices', formatted);
const devices = [
...this.otherDevices(this.value.domain.devices.hostDevices),
...formatted,
];
set(this.value.domain.devices, 'hostDevices', devices);
}
},
@@ -187,6 +195,10 @@ export default {
},
methods: {
otherDevices(vmDevices) {
return vmDevices.filter((device) => !this.pciDevices.find((pci) => device.name === pci.name));
},
nodeNameFromUid(uid) {
for (const deviceUid in this.uniqueDevices) {
const nodes = this.uniqueDevices[deviceUid].nodes;
@@ -34,6 +34,36 @@ export default {
const headers = [
{ ...STATE },
SIMPLE_NAME,
{
name: 'description',
labelKey: 'tableHeaders.description',
value: 'status.description',
sort: ['status.description']
},
{
name: 'node',
labelKey: 'tableHeaders.node',
value: 'status.nodeName',
sort: ['status.nodeName']
},
{
name: 'pciAddress',
label: 'Address',
value: 'status.pciAddress',
sort: ['status.pciAddress']
},
{
name: 'vendorID',
label: 'Vendor ID',
value: 'status.vendorID',
sort: ['status.vendorID', 'status.productID']
},
{
name: 'productID',
label: 'Product ID',
value: 'status.productID',
sort: ['status.productID', 'status.vendorID']
},
];
if (!isSingleProduct) {
@@ -58,12 +88,32 @@ export default {
handler(v) {
this.rows = v;
this.filterRows = this.rows;
console.log(this.filterRows)
},
immediate: true,
},
},
methods: {
enableGroup(rows = []) {
const row = rows[0];
if (row) {
row.enablePassthroughBulk(rows);
}
},
disableGroup(rows = []) {
rows.forEach((row) => {
if (row.passthroughClaim) {
row.disablePassthrough();
}
});
},
groupIsAllEnabled(rows = []) {
return !rows.find(device => !device.passthroughClaim);
},
changeRows(filterRows) {
this.$set(this, 'filterRows', filterRows);
},
@@ -94,6 +144,17 @@ export default {
:sort-generation-fn="sortGenerationFn"
:rows-per-page="10"
>
<template #group-by="{group}">
<div :ref="group.key" v-trim-whitespace class="group-tab">
<button v-if="groupIsAllEnabled(group.rows)" type="button" class="btn btn-sm role-secondary mr-5" @click="e=>{disableGroup(group.rows); e.target.blur()}">
{{ t('harvester.usb.disableGroup') }}
</button>
<button v-else type="button" class="btn btn-sm role-secondary mr-5" @click="e=>{enableGroup(group.rows); e.target.blur()}">
{{ t('harvester.usb.enableGroup') }}
</button>
<span v-clean-html="group.key" />
</div>
</template>
<template #cell:claimed="{row}">
<span v-if="row.isEnabled">{{ row.claimedBy }}</span>
<span v-else class="text-muted">&mdash;</span>
@@ -8,6 +8,9 @@ import Banner from '@components/Banner/Banner.vue';
import CompatibilityMatrix from '../CompatibilityMatrix';
import DeviceList from './DeviceList';
import remove from 'lodash/remove';
import { get, set } from '@shell/utils/object';
export default {
name: 'VirtualMachineUSBDevices',
components: {
@@ -44,6 +47,10 @@ export default {
for (const key in res) {
this[key] = res[key];
}
this.selectedDevices = (this.value?.domain?.devices?.hostDevices || [])
.map(({ name }) => name)
.filter((name) => this.enabledDevices.find(device => device?.metadata?.name === name));
},
data() {
@@ -60,13 +67,34 @@ export default {
};
},
watch: {
selectedDevices(neu) {
const formatted = neu.map((selectedDevice) => {
const deviceCRD = this.enabledDevices.find(device => device.metadata.name === selectedDevice);
const deviceName = deviceCRD?.status?.resourceName;
return {
deviceName,
name: deviceCRD?.metadata.name,
};
});
const devices = [
...this.otherDevices(this.value.domain.devices.hostDevices),
...formatted,
];
set(this.value.domain.devices, 'hostDevices', devices);
}
},
computed: {
deviceOpts() {
const filteredOptions = this.enabledDevices.filter((deviceCRD) => {
if (this.selectedDevices.length > 0) {
const selectedDevice = this.enabledDevices.find(device => device.metadata.name === this.selectedDevices[0]);
return !this.devicesInUse[deviceCRD?.metadata.name] && deviceCRD.status.nodeName === selectedDevice.status.nodeName;
return !this.devicesInUse[deviceCRD?.metadata.name] && deviceCRD.status.nodeName === selectedDevice?.status.nodeName;
}
return !this.devicesInUse[deviceCRD?.metadata.name];
@@ -76,14 +104,14 @@ export default {
return {
value: deviceCRD?.metadata.name,
label: deviceCRD?.metadata.name,
displayLabel: deviceCRD?.status?.resourceName,
displayLabel: deviceCRD?.status?.description,
};
});
},
enabledDevices() {
return this.devices.filter((device) => {
return device.isEnabled;
return device.status.enabled;
}) || [];
},
@@ -108,7 +136,7 @@ export default {
const out = {};
this.enabledDevices.forEach((deviceCRD) => {
const nodeName = deviceCRD.spec?.nodeName;
const nodeName = deviceCRD.status?.nodeName;
if (!out[nodeName]) {
out[nodeName] = [deviceCRD];
@@ -127,13 +155,19 @@ export default {
remove(out, (nodeName) => {
const device = this.enabledDevices.find(deviceCRD => deviceCRD.metadata.name === deviceUid);
return device.spec.nodeName !== nodeName;
return device?.status.nodeName !== nodeName;
});
});
return out;
},
},
methods: {
otherDevices(vmDevices) {
return vmDevices.filter((device) => !this.devices.find((usb) => device.name === usb.name));
}
}
};
</script>