[PATCH 2/2] config_tools: add virtio devices widget


Kunhui Li
 

This patch adds virtio devices widget according to the new design.

Tracked-On: #6690
Signed-off-by: Kunhui-Li <kunhuix.li@...>
---
.../src/pages/Config/ConfigForm.vue | 17 ++
.../CustomWidget/Virtio/Console.vue | 168 ++++++++++++++++++
.../ConfigForm/CustomWidget/Virtio/Input.vue | 140 +++++++++++++++
.../CustomWidget/Virtio/Network.vue | 141 +++++++++++++++
4 files changed, 466 insertions(+)
create mode 100644 misc/config_tools/configurator/packages/configurator/src/pages/Config/ConfigForm/CustomWidget/Virtio/Console.vue
create mode 100644 misc/config_tools/configurator/packages/configurator/src/pages/Config/ConfigForm/CustomWidget/Virtio/Input.vue
create mode 100644 misc/config_tools/configurator/packages/configurator/src/pages/Config/ConfigForm/CustomWidget/Virtio/Network.vue

diff --git a/misc/config_tools/configurator/packages/configurator/src/pages/Config/ConfigForm.vue b/misc/config_tools/configurator/packages/configurator/src/pages/Config/ConfigForm.vue
index ff59d9812..4f05abc09 100644
--- a/misc/config_tools/configurator/packages/configurator/src/pages/Config/ConfigForm.vue
+++ b/misc/config_tools/configurator/packages/configurator/src/pages/Config/ConfigForm.vue
@@ -59,6 +59,9 @@ import localizeEn from 'ajv-i18n/localize/en';
import IVSHMEM_REGION from "./ConfigForm/CustomWidget/IVSHMEM_REGION.vue";
import cpu_affinity from "./ConfigForm/CustomWidget/cpu_affinity.vue";
import VUART from "./ConfigForm/CustomWidget/VUART.vue";
+import Network from "./ConfigForm/CustomWidget/Virtio/Network.vue";
+import Console from "./ConfigForm/CustomWidget/Virtio/Console.vue";
+import Input from "./ConfigForm/CustomWidget/Virtio/Input.vue";

i18n.useLocal(localizeEn);
export default {
@@ -80,6 +83,20 @@ export default {
"labelSuffix": ":"
},
uiSchema: {
+ "virtio_devices": {
+ "network": {
+ "ui:title": "",
+ 'ui:field': Network,
+ },
+ "console": {
+ "ui:title": "",
+ 'ui:field': Console,
+ },
+ "input": {
+ "ui:title": "",
+ 'ui:field': Input,
+ },
+ },
"cpu_affinity": {
'ui:field': cpu_affinity
},
diff --git a/misc/config_tools/configurator/packages/configurator/src/pages/Config/ConfigForm/CustomWidget/Virtio/Console.vue b/misc/config_tools/configurator/packages/configurator/src/pages/Config/ConfigForm/CustomWidget/Virtio/Console.vue
new file mode 100644
index 000000000..bf4943cdd
--- /dev/null
+++ b/misc/config_tools/configurator/packages/configurator/src/pages/Config/ConfigForm/CustomWidget/Virtio/Console.vue
@@ -0,0 +1,168 @@
+<template>
+ <div class="virtio_consoles" v-if="defaultVal && defaultVal.length>0">
+ <div class="virtio_console" v-for="(console, index) in defaultVal">
+ <div class="virtio_console_demo">
+ <b style="margin-bottom: 2rem">Virtio console device</b>
+ <b-row class="align-items-center my-2 mt-4">
+ <b-col md="2">
+ <label>Use type: </label>
+ </b-col>
+ <b-col md="4">
+ <b-form-select v-model="console.use_type" :options="ConsoleUseType"/>
+ </b-col>
+ </b-row>
+
+ <b-row class="align-items-center">
+ <b-col md="2">
+ <label>Backend type: </label>
+ </b-col>
+ <b-col md="4">
+ <b-form-select v-model="console.backend_type" :options="ConsoleBackendType"/>
+ </b-col>
+ </b-row>
+
+ <b-row class="align-items-center my-2" v-if="console.backend_type === 'file'">
+ <b-col md="2">
+ <label>Output file path: </label>
+ </b-col>
+ <b-col md="4">
+ <b-form-input v-model="console.output_file_path"/>
+ </b-col>
+ </b-row>
+
+ <b-row class="align-items-center my-2" v-else-if="console.backend_type === 'tty'">
+ <b-col md="2">
+ <label>TTY device path: </label>
+ </b-col>
+ <b-col md="4">
+ <b-form-input v-model="console.tty_device_path"/>
+ </b-col>
+ </b-row>
+
+ <b-row class="align-items-center my-2" v-else-if="console.backend_type === 'sock client' || console.backend_type === 'sock server'">
+ <b-col md="2">
+ <label>Sock file path: </label>
+ </b-col>
+ <b-col md="4">
+ <b-form-input v-model="console.sock_file_path"/>
+ </b-col>
+ </b-row>
+
+ </div>
+ <div class="ToolSet">
+ <div>
+ <Icon size="18px" color="rgb(60,60,60)" @click="removeVirtioConsole(index)">
+ <Minus/>
+ </Icon>
+ </div>
+ <div>
+ <Icon size="18px" color="rgb(60,60,60)" @click="addVirtioConsole">
+ <Plus/>
+ </Icon>
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+ <div v-else>
+ <b style="margin-bottom: 2rem">Virtio console device</b>
+ <div class="ToolSet">
+ <div @click="addVirtioConsole">
+ <Icon size="18px">
+ <Plus/>
+ </Icon>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import _ from "lodash";
+import {Icon} from "@vicons/utils";
+import {Plus, Minus} from '@vicons/fa'
+import {fieldProps, vueUtils} from '@lljj/vue3-form-naive';
+
+export default {
+ name: "Console",
+ components: {Icon, Plus, Minus},
+ props: {
+ ...fieldProps,
+ fieldProps: {
+ type: null,
+ default: null
+ }
+ },
+ data() {
+ return {
+ ConsoleUseType: this.rootSchema.definitions['VirtioConsoleUseType']['enum'],
+ ConsoleBackendType: this.rootSchema.definitions['VirtioConsoleBackendType']['enum'],
+ defaultVal: vueUtils.getPathVal(this.rootFormData, this.curNodePath)
+ };
+ },
+ watch: {
+ rootFormData: {
+ handler(newValue, oldValue) {
+ this.defaultVal = vueUtils.getPathVal(newValue, this.curNodePath)
+ },
+ deep: true
+ },
+ defaultVal: {
+ handler(newValue, oldValue) {
+ // Note: `newValue` will be equal to `oldValue` here
+ // on nested mutations as long as the object itself
+ // hasn't been replaced.
+ vueUtils.setPathVal(this.rootFormData, this.curNodePath, newValue);
+ },
+ deep: true
+ }
+ },
+ methods: {
+ removeVirtioConsole(index) {
+ this.defaultVal.splice(index, 1);
+ },
+ addVirtioConsole() {
+ if (!_.isArray(this.defaultVal)) {
+ this.defaultVal = []
+ }
+ this.defaultVal.push({
+ "use_type": this.ConsoleUseType,
+ "backend_type": this.ConsoleBackendType,
+ "output_file_path": "",
+ "sock_file_path": "",
+ "tty_device_path": "",
+ })
+ }
+ }
+}
+</script>
+
+<style scoped>
+.ToolSet {
+ display: flex;
+ flex-direction: row-reverse;
+ gap: 8px;
+}
+.ToolSet div{
+ padding: 8px;
+ border: 1px solid rgb(193,193,193);
+ border-radius: 5px;
+}
+.virtio_consoles{
+ width: 100%;
+}
+.virtio_console {
+ width: 100%;
+ display: flex;
+ gap: 2rem;
+ align-items: end;
+}
+
+.virtio_console_demo {
+ width: 100%;
+ border: 2px solid #cccccc;
+ padding: 8px 2px 12px 6px;
+ border-radius: 5px;
+ margin-bottom: 1rem;
+}
+</style>
\ No newline at end of file
diff --git a/misc/config_tools/configurator/packages/configurator/src/pages/Config/ConfigForm/CustomWidget/Virtio/Input.vue b/misc/config_tools/configurator/packages/configurator/src/pages/Config/ConfigForm/CustomWidget/Virtio/Input.vue
new file mode 100644
index 000000000..ec7ac3f4c
--- /dev/null
+++ b/misc/config_tools/configurator/packages/configurator/src/pages/Config/ConfigForm/CustomWidget/Virtio/Input.vue
@@ -0,0 +1,140 @@
+<template>
+ <div class="virtio_inputs" v-if="defaultVal && defaultVal.length>0">
+ <div class="virtio_input" v-for="(input, index) in defaultVal">
+ <div class="virtio_input_demo">
+ <b style="margin-bottom: 2rem">Virtio input device</b>
+ <b-row class="align-items-center my-2 mt-4">
+ <b-col md="2">
+ <label>Backend device file: </label>
+ </b-col>
+ <b-col md="8">
+ <b-form-select v-model="input.backend_device_file" :options="BackendDeviceFileType"/>
+ </b-col>
+ </b-row>
+
+ <b-row class="align-items-center my-2">
+ <b-col md="2">
+ Guest virtio input device unique identifier:
+ </b-col>
+ <b-col md="4">
+ <b-form-input v-model="input.id"/>
+ </b-col>
+ </b-row>
+ </div>
+ <div class="ToolSet">
+ <div>
+ <Icon size="18px" color="rgb(60,60,60)" @click="removeVirtioInput(index)">
+ <Minus/>
+ </Icon>
+ </div>
+ <div>
+ <Icon size="18px" color="rgb(60,60,60)" @click="addVirtioInput">
+ <Plus/>
+ </Icon>
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+ <div v-else>
+ <b style="margin-bottom: 2rem">Virtio input device</b>
+ <div class="ToolSet">
+ <div @click="addVirtioInput">
+ <Icon size="18px">
+ <Plus/>
+ </Icon>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import _ from "lodash";
+import {Icon} from "@vicons/utils";
+import {Plus, Minus} from '@vicons/fa'
+import {fieldProps, vueUtils} from '@lljj/vue3-form-naive';
+
+export default {
+ name: "Input",
+ components: {Icon, Plus, Minus},
+ props: {
+ ...fieldProps,
+ fieldProps: {
+ type: null,
+ default: null
+ }
+ },
+ data() {
+ return {
+ BackendDeviceFileType: this.rootSchema.definitions['VirtioInputConfiguration']['properties']['backend_device_file']['enum'],
+ defaultVal: vueUtils.getPathVal(this.rootFormData, this.curNodePath)
+ };
+ },
+ watch: {
+ rootFormData: {
+ handler(newValue, oldValue) {
+ this.defaultVal = vueUtils.getPathVal(newValue, this.curNodePath)
+ },
+ deep: true
+ },
+ defaultVal: {
+ handler(newValue, oldValue) {
+ // Note: `newValue` will be equal to `oldValue` here
+ // on nested mutations as long as the object itself
+ // hasn't been replaced.
+ vueUtils.setPathVal(this.rootFormData, this.curNodePath, newValue);
+ },
+ deep: true
+ }
+ },
+ methods: {
+ removeVirtioInput(index) {
+ this.defaultVal.splice(index, 1);
+ },
+ addVirtioInput() {
+ if (!_.isArray(this.defaultVal)) {
+ this.defaultVal = []
+ }
+ this.defaultVal.push({
+ "backend_device_file": "",
+ "id": "",
+ })
+ }
+ }
+}
+</script>
+
+<style scoped>
+label:after{
+ content: '*';
+ color: red;
+}
+.ToolSet {
+ display: flex;
+ flex-direction: row-reverse;
+ gap: 8px;
+}
+.ToolSet div{
+ padding: 8px;
+ border: 1px solid rgb(193,193,193);
+ border-radius: 5px;
+}
+.virtio_inputs{
+ width: 100%;
+}
+.virtio_input {
+ width: 100%;
+ display: flex;
+ gap: 2rem;
+ align-items: end;
+}
+
+.virtio_input_demo {
+ width: 100%;
+ border: 2px solid #cccccc;
+ padding: 8px 0 12px 6px;
+ border-radius: 5px;
+ margin-bottom: 1rem;
+}
+</style>
\ No newline at end of file
diff --git a/misc/config_tools/configurator/packages/configurator/src/pages/Config/ConfigForm/CustomWidget/Virtio/Network.vue b/misc/config_tools/configurator/packages/configurator/src/pages/Config/ConfigForm/CustomWidget/Virtio/Network.vue
new file mode 100644
index 000000000..c29145d15
--- /dev/null
+++ b/misc/config_tools/configurator/packages/configurator/src/pages/Config/ConfigForm/CustomWidget/Virtio/Network.vue
@@ -0,0 +1,141 @@
+<template>
+ <div class="virtio_networks" v-if="defaultVal && defaultVal.length>0">
+ <div class="virtio_network" v-for="(network, index) in defaultVal">
+ <div class="virtio_network_demo">
+ <b style="margin-bottom: 2rem">Virtio network device</b>
+ <b-row class="align-items-center my-2 mt-4">
+ <b-col md="2">
+ <label>Virtio framework: </label>
+ </b-col>
+ <b-col md="4">
+ <b-form-select v-model="network.virtio_framework" :options="NetworkFrameworkType"/>
+ </b-col>
+ </b-row>
+
+ <b-row class="align-items-center my-2">
+ <b-col md="2">
+ <label>Network interface name: </label>
+ </b-col>
+ <b-col md="4">
+ <b-form-input v-model="network.interface_name"/>
+ </b-col>
+ </b-row>
+ </div>
+ <div class="ToolSet">
+ <div>
+ <Icon size="18px" color="rgb(60,60,60)" @click="removeVirtioNetwork(index)">
+ <Minus/>
+ </Icon>
+ </div>
+ <div>
+ <Icon size="18px" color="rgb(60,60,60)" @click="addVirtioNetwork">
+ <Plus/>
+ </Icon>
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+ <div v-else>
+ <b style="margin-bottom: 2rem">Virtio network device</b>
+ <div class="ToolSet">
+ <div @click="addVirtioNetwork">
+ <Icon size="18px">
+ <Plus/>
+ </Icon>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import _ from "lodash";
+import {Icon} from "@vicons/utils";
+import {Plus, Minus} from '@vicons/fa'
+import {fieldProps, vueUtils} from '@lljj/vue3-form-naive';
+
+export default {
+ name: "Network",
+ components: {Icon, Plus, Minus},
+ props: {
+ ...fieldProps,
+ fieldProps: {
+ type: null,
+ default: null
+ }
+ },
+ data() {
+ return {
+ NetworkFrameworkType: this.rootSchema.definitions['VirtioNetworkFrameworkType']['enum'],
+ NetworkFrameworkDefault: this.rootSchema.definitions['VirtioNetworkConfiguration']['properties']['virtio_framework']['default'],
+ defaultVal: vueUtils.getPathVal(this.rootFormData, this.curNodePath)
+ };
+ },
+ watch: {
+ rootFormData: {
+ handler(newValue, oldValue) {
+ this.defaultVal = vueUtils.getPathVal(newValue, this.curNodePath)
+ },
+ deep: true
+ },
+ defaultVal: {
+ handler(newValue, oldValue) {
+ // Note: `newValue` will be equal to `oldValue` here
+ // on nested mutations as long as the object itself
+ // hasn't been replaced.
+ vueUtils.setPathVal(this.rootFormData, this.curNodePath, newValue);
+ },
+ deep: true
+ }
+ },
+ methods: {
+ removeVirtioNetwork(index) {
+ this.defaultVal.splice(index, 1);
+ },
+ addVirtioNetwork() {
+ if (!_.isArray(this.defaultVal)) {
+ this.defaultVal = []
+ }
+ this.defaultVal.push({
+ "virtio_framework": this.NetworkFrameworkDefault,
+ "interface_name": "",
+ })
+ }
+ }
+}
+</script>
+
+<style scoped>
+label:after{
+ content: '*';
+ color: red;
+}
+.ToolSet {
+ display: flex;
+ flex-direction: row-reverse;
+ gap: 8px;
+}
+.ToolSet div{
+ padding: 8px;
+ border: 1px solid rgb(193,193,193);
+ border-radius: 5px;
+}
+.virtio_networks{
+ width: 100%;
+}
+.virtio_network {
+ width: 100%;
+ display: flex;
+ gap: 2rem;
+ align-items: end;
+}
+
+.virtio_network_demo {
+ width: 100%;
+ border: 2px solid #cccccc;
+ padding: 8px 0 12px 6px;
+ border-radius: 5px;
+ margin-bottom: 1rem;
+}
+</style>
\ No newline at end of file
--
2.25.1