1<template>
2  <div class="IVSH_REGIONS" v-if="defaultVal && defaultVal.length>0">
3    <div class="IVSH_REGION" v-for="(IVSHMEM_VMO, index) in defaultVal">
4      <div class="IVSH_REGION_CONTENT">
5        <b style="margin-bottom: 2rem">InterVM shared memory region</b>
6
7        <b-row class="align-items-center my-2 mt-4">
8          <b-col md="2">
9            <label>
10              <n-popover trigger="hover" placement="top-start">
11              <template #trigger>
12                  <IconInfo/>
13              </template>
14              <span v-html="this.IVSHMEMRegionType.properties.NAME.description"></span>
15            </n-popover>Region name:
16            </label>
17          </b-col>
18          <b-col md="4">
19              <b-form-input :state="validateIvshrgName(IVSHMEM_VMO.NAME)" v-model="IVSHMEM_VMO.NAME" placeholder="Must be 1-27 characters and only letters, digits and '_'."/>
20              <b-form-invalid-feedback>
21                Name must be between 1-27 characters and contain only letters, digits and "_".
22              </b-form-invalid-feedback>
23          </b-col>
24        </b-row>
25
26        <b-row class="align-items-center my-2">
27          <b-col md="2">
28            <label>
29              <n-popover trigger="hover" placement="top-start">
30                <template #trigger>
31                    <IconInfo/>
32                </template>
33                <span v-html="this.IVSHMEMRegionType.properties.PROVIDED_BY.description"></span>
34              </n-popover>Emulated by:
35            </label>
36          </b-col>
37          <b-col md="4">
38            <b-form-select v-model="IVSHMEM_VMO.PROVIDED_BY" :options="providerType"></b-form-select>
39          </b-col>
40        </b-row>
41
42        <b-row class="align-items-center my-2">
43          <b-col md="2">
44            <label>
45              <n-popover trigger="hover" placement="top-start">
46                <template #trigger>
47                    <IconInfo/>
48                </template>
49                <span v-html="this.IVSHMEMRegionType.properties.IVSHMEM_SIZE.description"></span>
50              </n-popover>Size (MB):
51            </label>
52          </b-col>
53          <b-col md="4">
54            <b-form-select v-model="IVSHMEM_VMO.IVSHMEM_SIZE" :options="IVSHMEMSize"></b-form-select>
55          </b-col>
56        </b-row>
57
58        <b-row class="align-items-center my-2">
59          <b-col md="2">
60            <label>
61              <n-popover trigger="hover" placement="top-start">
62                <template #trigger>
63                    <IconInfo/>
64                </template>
65                <span v-html="this.IVSHMEMRegionType.properties.IVSHMEM_REGION_ID.description"></span>
66              </n-popover>IVSHMEM Region ID:
67            </label>
68          </b-col>
69          <b-col md="4">
70            <b-form-input v-model="IVSHMEM_VMO.IVSHMEM_REGION_ID"/>
71          </b-col>
72        </b-row>
73
74        <div class="m-3 mt-4 d-flex flex-column gap-2">
75          <b>Shared VMs</b>
76          <p>Select all VMs that will use this shared memory region</p>
77          <b-row>
78            <b-col sm="2" offset-sm="6">
79              <n-popover trigger="hover" placement="top-start">
80                <template #trigger>
81                    <IconInfo/>
82                </template>
83                <span v-html="this.IVSHMEM_VM.properties.VBDF.description"></span>
84              </n-popover>Virtual BDF:
85            </b-col>
86          </b-row>
87          <b-row class="justify-content-between align-items-center"
88                 v-for="(IVSHMEM_VM,index) in IVSHMEM_VMO.IVSHMEM_VMS.IVSHMEM_VM">
89            <b-col sm="2">
90              <label>
91                <n-popover trigger="hover" placement="top-start">
92                  <template #trigger>
93                      <IconInfo/>
94                  </template>
95                  <span v-html="this.IVSHMEM_VM.properties.VM_NAME.description"></span>
96                </n-popover>VM name:
97              </label>
98            </b-col>
99            <b-col sm="3">
100              <b-form-select :state="validation(IVSHMEM_VM.VM_NAME)" v-model="IVSHMEM_VM.VM_NAME" :options="vmNames"></b-form-select>
101              <b-form-invalid-feedback>
102                must have value
103              </b-form-invalid-feedback>
104            </b-col>
105            <b-col sm="3">
106              <b-form-input :state="validateVBDF(IVSHMEM_VM.VBDF)" v-model="IVSHMEM_VM.VBDF" placeholder="00:[device].[function], e.g. 00:0c.0. All fields are in hexadecimal."/>
107              <b-form-invalid-feedback>
108                {{ this.VBDFType["err:pattern"] }}
109              </b-form-invalid-feedback>
110            </b-col>
111            <b-col sm="3">
112              <div class="ToolSet">
113                <div @click="removeSharedVM(IVSHMEM_VMO.IVSHMEM_VMS.IVSHMEM_VM,index)">
114                  <Icon size="18px">
115                    <Minus/>
116                  </Icon>
117                </div>
118                <div @click="addSharedVM(IVSHMEM_VMO.IVSHMEM_VMS.IVSHMEM_VM,index)">
119                  <Icon size="18px">
120                    <Plus/>
121                  </Icon>
122                </div>
123              </div>
124            </b-col>
125          </b-row>
126
127        </div>
128      </div>
129      <div class="ToolSet">
130        <div @click="removeIVSHMEM_VMO(index)">
131          <Icon size="18px">
132            <Minus/>
133          </Icon>
134        </div>
135        <div @click="addIVSHMEM_VMO(index)">
136          <Icon size="18px">
137            <Plus/>
138          </Icon>
139        </div>
140      </div>
141
142    </div>
143
144  </div>
145  <div v-else>
146    <div class="ToolSet">
147      <div @click="addIVSHMEM_VMO">
148        <Icon size="18px">
149          <Plus/>
150        </Icon>
151      </div>
152    </div>
153  </div>
154</template>
155
156<script>
157import _ from 'lodash';
158import {Icon} from "@vicons/utils";
159import {Plus, Minus} from '@vicons/fa'
160import {fieldProps, vueUtils} from '@lljj/vue3-form-naive';
161import IconInfo from '@lljj/vjsf-utils/icons/IconInfo.vue';
162
163export default {
164  name: 'IVSHMEM_REGION',
165  components: {Icon, Plus, Minus, IconInfo},
166  props: {
167    ...fieldProps,
168    // Todo: use ui:fieldProps to pass getScenarioData function
169    fieldProps: {
170      type: null,
171      default: null
172    }
173  },
174  computed: {
175    vmNames() {
176      let currentScenarioData = window.getCurrentScenarioData()
177      let vmNames = []
178      for (let i = 0; i < currentScenarioData.vm.length; i++) {
179        vmNames.push(currentScenarioData.vm[i].name)
180      }
181      return vmNames
182    }
183  },
184  data() {
185    return {
186      providerType: this.rootSchema.definitions['ProviderType']['enum'],
187      IVSHMEMSize: this.rootSchema.definitions['IVSHMEMSize']['enum'],
188      IVSHMEMRegionType: this.rootSchema.definitions['IVSHMEMRegionType'],
189      IVSHMEM_VM: this.rootSchema.definitions['IVSHMEMVM'],
190      VBDFType: this.rootSchema.definitions['VBDFType'],
191      defaultVal: vueUtils.getPathVal(this.rootFormData, this.curNodePath)
192    };
193  },
194  watch: {
195    rootFormData: {
196      handler(newValue, oldValue) {
197        this.defaultVal = vueUtils.getPathVal(newValue, this.curNodePath)
198      },
199      deep: true
200    },
201    defaultVal: {
202      handler(newValue, oldValue) {
203        // Note: `newValue` will be equal to `oldValue` here
204        // on nested mutations as long as the object itself
205        // hasn't been replaced.
206        vueUtils.setPathVal(this.rootFormData, this.curNodePath, newValue);
207      },
208      deep: true
209    }
210  },
211  methods: {
212    validateIvshrgName(value) {
213      var regexp = new RegExp(this.IVSHMEMRegionType.properties.NAME.pattern);
214      return (value != null) && regexp.test(value);
215    },
216    validateVBDF(value) {
217      var regexp = new RegExp(this.VBDFType.pattern);
218      return (value != null) && regexp.test(value);
219    },
220    validation(value) {
221      return (value != null) && (value.length !== 0);
222    },
223    addSharedVM(vms, index) {
224      // add new item after current item
225      vms.splice(index + 1, 0, {
226        "VM_NAME": "",
227        "VBDF": ""
228      })
229    },
230    removeSharedVM(vms, index) {
231      if (vms.length <= 2) {
232        return
233      }
234      vms.splice(index, 1)
235    },
236    removeIVSHMEM_VMO(index) {
237      this.defaultVal.splice(index, 1);
238    },
239    addIVSHMEM_VMO(index) {
240      if (!_.isArray(this.defaultVal)) {
241        this.defaultVal = []
242      }
243      this.defaultVal.splice(index + 1, 0, {
244        "NAME": "",
245        "PROVIDED_BY": "Hypervisor",
246        "IVSHMEM_SIZE": "2",
247        "IVSHMEM_VMS": {
248          "IVSHMEM_VM": [
249            {
250              "VM_NAME": "",
251              "VBDF": ""
252            },
253            {
254              "VM_NAME": "",
255              "VBDF": ""
256            }
257          ]
258        }
259      })
260    }
261  }
262};
263</script>
264
265<!--suppress CssUnusedSymbol -->
266<style scoped>
267label:before {
268  content: '*';
269  color: red;
270  margin-right: 3px;
271}
272
273.form-control {
274  line-height: 2;
275}
276
277.IVSH_REGIONS {
278  display: flex;
279  flex-direction: column;
280  width: 100%;
281  gap: 2rem;
282}
283
284.IVSH_REGION {
285  display: flex;
286  align-items: start;
287  gap: 1rem;
288  width: 100%;
289}
290
291.IVSH_REGION_CONTENT {
292  border: 1px solid gray;
293  border-radius: 5px;
294  padding: 25px;
295  width: 100%;
296}
297
298.ToolSet {
299  display: flex;
300  justify-content: space-around;
301  gap: 0.5rem;
302  max-width: 5rem;
303  width: 100%;
304}
305
306.ToolSet div {
307  cursor: pointer;
308  border: 1px solid gray;
309  border-radius: 3px;
310  background: #f9f9f9;
311  padding: 5px 5px 3px;
312}
313</style>
314