bfg-common 1.2.74 → 1.2.75

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,678 +1,681 @@
1
- <template>
2
- <div class="virtual-hardware">
3
- <div class="clr-row clr-justify-content-end">
4
- <atoms-dropdown-tree
5
- :title="localization.addNewDevice"
6
- :items="dropdownItems"
7
- @select="onAddDevice"
8
- />
9
- </div>
10
-
11
- <div class="clr-component">
12
- <div class="stack-view">
13
- <common-vm-actions-common-customize-hardware-virtual-hardware-cpu
14
- :max-cpus="props.maxCpus"
15
- :cpu-models="props.cpuModels"
16
- :cpu="props.cpu"
17
- :is-edit="props.isEdit"
18
- :state="props.state"
19
- :error-validation-fields="props.errorValidationFields"
20
- :vm-cpu-help-text-second="props.vmCpuHelpTextSecond"
21
- @send-data="onSendDataCpuMethod"
22
- @remove-error-by-title="emits('remove-error-by-title', $event)"
23
- @invalid="cpuInvalid = $event"
24
- />
25
- <common-vm-actions-common-customize-hardware-virtual-hardware-memory
26
- :max-memory="props.maxMemory"
27
- :is-edit="props.isEdit"
28
- :memory="props.memory"
29
- :state="props.state"
30
- :error-validation-fields="props.errorValidationFields"
31
- @send-data="onSendDataMemoryMethod"
32
- @invalid="memoryInvalid = $event"
33
- @remove-error-by-title="emits('remove-error-by-title', $event)"
34
- />
35
- <common-vm-actions-common-customize-hardware-virtual-hardware-new-hard-disk
36
- v-for="(item, key) in hardDisks"
37
- :key="hardDisksIndex[key]"
38
- :index="hardDisksIndex[key]"
39
- :type="hardDisksType[key]"
40
- :storage="props.storage"
41
- :hard-disk="item"
42
- :error-validation-fields="props.errorValidationFields"
43
- :get-datastore-table-func="props.getDatastoreTableFunc"
44
- :datastore="props.datastore"
45
- :is-edit="props.isEdit"
46
- :state="props.state"
47
- @remove="onRemoveHardDisk(hardDisksIndex[key], item)"
48
- @roll-back="onRollBackHardDisk(hardDisksIndex[key])"
49
- @send-data="onSendDataNewHardDiskMethod($event, hardDisksIndex[key])"
50
- @invalid="onSetInvalidHardDisk($event, hardDisksIndex[key])"
51
- @remove-error-by-title="emits('remove-error-by-title', $event)"
52
- />
53
- <common-vm-actions-common-customize-hardware-virtual-hardware-new-network
54
- v-for="(item, key) in networks"
55
- :key="networksIndex[key]"
56
- :index="networksIndex[key]"
57
- :type="networksType[key]"
58
- :network="item"
59
- :networks-table="props.networksTable"
60
- :error-validation-fields="props.errorValidationFields"
61
- :is-edit="props.isEdit"
62
- :state="props.state"
63
- @remove="onRemoveNetwork(networksIndex[key])"
64
- @send-data="sendDataNewNetworkMethod($event, networksIndex[key])"
65
- @invalid="onSetInvalidNetwork($event, networksIndex[key])"
66
- @remove-error-by-title="emits('remove-error-by-title', $event)"
67
- @get-networks-table="emits('get-networks-table', $event)"
68
- />
69
- <common-vm-actions-common-customize-hardware-virtual-hardware-cd-dvd-drive
70
- v-for="(item, key) in cdDvdDrives"
71
- :key="cdDvdDrivesIndex[key]"
72
- :index="cdDvdDrivesIndex[key]"
73
- :hard-disks-count="hardDisks.length"
74
- :type="cdDvdDrivesType[key]"
75
- :cd-dvd-drive="item"
76
- :nodes="props.nodes"
77
- :files="props.files"
78
- :error-validation-fields="props.errorValidationFields"
79
- :is-edit="props.isEdit"
80
- :state="props.state"
81
- @remove-error-by-title="emits('remove-error-by-title', $event)"
82
- @get-storage="emits('get-storage', $event)"
83
- @get-folders-or-files="emits('get-folders-or-files', $event)"
84
- @get-active-device-child="emits('get-active-device-child', $event)"
85
- @show-datastore-child="emits('show-datastore-child', $event)"
86
- @remove="onRemoveCdDvdDrive(cdDvdDrivesIndex[key], item)"
87
- @roll-back="onRollBackCdDvdDrive(cdDvdDrivesIndex[key])"
88
- @send-data="
89
- sendDataNewCdDvdDriveMethod($event, cdDvdDrivesIndex[key])
90
- "
91
- />
92
- <common-vm-actions-common-customize-hardware-virtual-hardware-new-usb-controller
93
- :usb-controller="props.usbController"
94
- :is-edit="props.isEdit"
95
- :state="props.state"
96
- @send-data="onSendDataNewUsbControllerMethod"
97
- />
98
- <template v-if="props.passthroughDevices">
99
- <common-vm-actions-common-customize-hardware-virtual-hardware-new-pci-device
100
- v-for="(item, key) in pciDevices"
101
- :key="pciDevicesIndex[key]"
102
- :index="pciDevicesIndex[key]"
103
- :pci-device="item"
104
- :error-validation-fields="props.errorValidationFields"
105
- :passthrough-devices="props.passthroughDevices"
106
- :type="pciDevicesType[key]"
107
- @remove="onRemovePciDevice(pciDevicesIndex[key])"
108
- @send-data="
109
- onSendDataPciDevicesMethod($event, pciDevicesIndex[key])
110
- "
111
- @invalid="onSetInvalidPciDevice($event, pciDevicesIndex[key])"
112
- @remove-error-by-title="emits('remove-error-by-title', $event)"
113
- />
114
- </template>
115
- <common-vm-actions-common-customize-hardware-virtual-hardware-video-card
116
- :is-edit="props.isEdit"
117
- :video-card="props.videoCard"
118
- :error-validation-fields="props.errorValidationFields"
119
- :state="props.state"
120
- @send-data="onSendDataVideoCardMethod"
121
- @invalid="videoCardInvalid = $event"
122
- @remove-error-by-title="emits('remove-error-by-title', $event)"
123
- />
124
- <common-vm-actions-common-customize-hardware-virtual-hardware-other />
125
- </div>
126
- </div>
127
-
128
- <Teleport to="body">
129
- <common-vm-actions-common-customize-hardware-virtual-hardware-browse-view
130
- v-if="isShowFileModal"
131
- :show="isShowFileModal"
132
- :nodes="props.nodes"
133
- :files="props.files"
134
- @submit="onAddExistHardDisk"
135
- @get-storage="emits('get-storage', $event)"
136
- @get-folders-or-files="emits('get-folders-or-files', $event)"
137
- @get-active-device-child="emits('get-active-device-child', $event)"
138
- @show-datastore-child="emits('show-datastore-child', $event)"
139
- @hide="isShowFileModal = false"
140
- />
141
- </Teleport>
142
- </div>
143
- </template>
144
-
145
- <script setup lang="ts">
146
- import { UI_I_DatastoreTableItem } from '~/models/store/storage/interfaces'
147
- import { UI_I_NetworkTableItem } from '~/models/store/network/interfaces'
148
- import { UI_I_TablePayload } from '~/models/store/interfaces'
149
- import { UI_I_FolderOrFileTreePayload } from '~/models/store/storage/interfaces'
150
- import { UI_I_FileTreeNode } from '~/components/models/interfaces'
151
- import {
152
- UI_I_SendDataCpu,
153
- UI_I_SendDataMemory,
154
- UI_I_SendDataNewHardDisk,
155
- UI_I_SendDataNewNetwork,
156
- UI_I_SendDataVideoCard,
157
- UI_I_InvalidKeys,
158
- UI_I_SendDataVirtualHardware,
159
- UI_I_SendDataNewCdDvdDrive,
160
- UI_I_HardDisk,
161
- UI_I_PciDevice,
162
- UI_I_SendDataNewPciDevice,
163
- } from '~/components/common/vm/actions/common/customizeHardware/virtualHardware/models/interfaces'
164
- import { UI_I_ErrorValidationField } from '~/models/store/interfaces'
165
- import {
166
- UI_T_HardDiskType,
167
- UI_T_NetworkType,
168
- UI_T_CdDvdType,
169
- } from '~/components/common/vm/actions/common/customizeHardware/virtualHardware/models/types'
170
- import { UI_I_OptionItem } from '~/components/atoms/models/interfaces'
171
- import {
172
- UI_I_DropdownTreeItem,
173
- UI_I_DropdownTreeItemChild,
174
- } from '~/components/atoms/dropdown/tree/models/interfaces'
175
- import { UI_I_Localization } from '~/models/interfaces'
176
- import { UI_I_ConfigurePciDevicesTable } from '~/models/store/host/interfaces'
177
- import {
178
- API_UI_I_VmEditCpu,
179
- API_UI_I_VmEditMemory,
180
- } from '~/models/store/vm/interfaces'
181
- import { dropdownItemsFunc } from './config/dropdownItems'
182
-
183
- const props = defineProps<{
184
- storage: UI_I_DatastoreTableItem | null
185
- cpuModels: UI_I_OptionItem[]
186
- vmName: string
187
- maxCpus: number
188
- maxMemory: number
189
- isEdit: boolean
190
- isClone: boolean
191
- errorValidationFields: UI_I_ErrorValidationField<string>[]
192
- nodes: UI_I_FileTreeNode[]
193
- files: UI_I_FileTreeNode[]
194
- networksTable: UI_I_NetworkTableItem[]
195
- getDatastoreTableFunc: (payload: UI_I_TablePayload) => Promise<void>
196
- datastore: UI_I_DatastoreTableItem[]
197
- state?: string | number
198
- cpu?: API_UI_I_VmEditCpu
199
- memory?: API_UI_I_VmEditMemory
200
- vmCpuHelpTextSecond?: string
201
- hardDisks?: UI_I_SendDataNewHardDisk[] | null
202
- cdDvdDrives?: UI_I_SendDataNewCdDvdDrive[] | null
203
- networks?: UI_I_SendDataNewNetwork[] | null
204
- videoCard?: UI_I_SendDataVideoCard
205
- usbController?: string
206
- pciDevices?: UI_I_PciDevice[]
207
- passthroughDevices?: UI_I_ConfigurePciDevicesTable | null
208
- }>()
209
- const emits = defineEmits<{
210
- (event: 'send-data', value: UI_I_SendDataVirtualHardware): void
211
- (event: 'invalid', value: string[]): void
212
- (event: 'get-storage', value: UI_I_TablePayload): void
213
- (event: 'get-folders-or-files', value: UI_I_FolderOrFileTreePayload): void
214
- (event: 'get-active-device-child', value: UI_I_FileTreeNode): void
215
- (event: 'show-datastore-child', value: UI_I_FileTreeNode): void
216
- (event: 'remove-error-by-title', value: string): void
217
- (event: 'get-networks-table', value: UI_I_TablePayload): void
218
- (event: 'get-pci-devices'): void
219
- }>()
220
-
221
- const localization = computed<UI_I_Localization>(() => useLocal())
222
- const { $binary } = useNuxtApp()
223
-
224
- const dropdownItems = computed<UI_I_DropdownTreeItem[]>(() =>
225
- dropdownItemsFunc(localization.value)
226
- )
227
-
228
- const hardDisksIndex = ref<number[]>([0])
229
- const hardDisksType = ref<UI_T_HardDiskType[]>(['new'])
230
- const hardDisks = ref<UI_I_SendDataNewHardDisk[]>([
231
- {
232
- create: true,
233
- size: 90,
234
- source: '',
235
- boot_order: -1,
236
- },
237
- ])
238
- watch(
239
- () => props.hardDisks,
240
- (newValue) => {
241
- if ((!props.isEdit && !props.isClone) || !newValue) return
242
-
243
- const count = newValue?.length || 0
244
- hardDisksIndex.value = [...Array(count).keys()]
245
- hardDisks.value = newValue
246
- if (props.isEdit) {
247
- hardDisksType.value = Array(count).fill('edit')
248
- } else if (props.isClone) {
249
- hardDisksType.value = Array(count).fill('new')
250
- hardDisks.value = newValue.map((hardDisk) => {
251
- hardDisk.create = true
252
- return hardDisk
253
- })
254
- }
255
- },
256
- { immediate: true }
257
- )
258
-
259
- const addHardDisk = (
260
- create = true,
261
- size = 90,
262
- source = '',
263
- type: UI_T_HardDiskType = 'new'
264
- ): void => {
265
- const newIndex = (hardDisksIndex.value.at(-1) ?? -1) + 1
266
- hardDisksIndex.value.push(newIndex)
267
- hardDisksType.value.push(type)
268
-
269
- hardDisks.value.push({
270
- create,
271
- size,
272
- source,
273
- attach: true,
274
- boot_order: 0, // Убираем галочку
275
- })
276
- sendData()
277
- }
278
- const onAddExistHardDisk = (hardDisk: UI_I_HardDisk): void => {
279
- addHardDisk(false, $binary.bToGb(hardDisk.size), hardDisk.path, 'exist')
280
- }
281
- const onRemoveHardDisk = (
282
- index: number,
283
- hardDisk: UI_I_SendDataNewHardDisk
284
- ): void => {
285
- const removeIndex = hardDisksIndex.value.indexOf(index)
286
-
287
- if (!hardDisk.create && !hardDisk.attach) {
288
- hardDisksType.value = hardDisksType.value.map((item, key) => {
289
- if (key === removeIndex) return 'removed'
290
- return item
291
- })
292
- sendData()
293
- return
294
- }
295
-
296
- hardDisksIndex.value = hardDisksIndex.value.filter((item) => item !== index)
297
- hardDisksType.value = hardDisksType.value.filter(
298
- (_item, key) => key !== removeIndex
299
- )
300
-
301
- hardDisks.value = hardDisks.value.filter((_hardDisk, key: number) => {
302
- return removeIndex !== key
303
- })
304
-
305
- delete newHardDiskInvalidKeys.value[index]
306
- delete sendDataNewHardDisk.value[index]
307
- sendData()
308
- }
309
- const onRollBackHardDisk = (index: number): void => {
310
- const removeIndex = hardDisksIndex.value.indexOf(index)
311
- hardDisksType.value = hardDisksType.value.map((item, key) => {
312
- if (key === removeIndex) return 'edit'
313
- return item
314
- })
315
- }
316
-
317
- const defaultNetwork = {
318
- network: '',
319
- net_bridge: '',
320
- mac: '',
321
- target: '',
322
- model: '',
323
- boot_order: -1,
324
- }
325
- const networks = ref<UI_I_SendDataNewNetwork[]>([useDeepCopy(defaultNetwork)])
326
- const networksType = ref<UI_T_NetworkType[]>(['new'])
327
- const networksIndex = ref<number[]>([0])
328
- watch(
329
- () => props.networks,
330
- (newValue) => {
331
- if ((!props.isEdit && !props.isClone) || !newValue) return
332
-
333
- // networks.value = newValue
334
- // networksType.value = Array(newValue.length).fill('edit')
335
- const count = newValue?.length || 0
336
- networksIndex.value = [...Array(count).keys()]
337
- networks.value = newValue
338
- if (props.isEdit) {
339
- networksType.value = Array(count).fill('edit')
340
- } else if (props.isClone) {
341
- networksType.value = Array(count).fill('new')
342
- }
343
- },
344
- { immediate: true }
345
- )
346
- const addNetwork = (): void => {
347
- const index = (networksIndex.value.at(-1) || 0) + 1
348
- networksIndex.value.push(index)
349
- networksType.value.push('new')
350
-
351
- networks.value.push({
352
- ...useDeepCopy(defaultNetwork),
353
- boot_order: 0, // Убираем галочку
354
- })
355
- }
356
- const onRemoveNetwork = (index: number): void => {
357
- const removeIndex = networksIndex.value.indexOf(index)
358
- networksIndex.value = networksIndex.value.filter((item) => item !== index)
359
- networksType.value = networksType.value.filter(
360
- (_item, key) => key !== removeIndex
361
- )
362
- networks.value = networks.value.filter(
363
- (_network, key: number) => removeIndex !== key
364
- )
365
-
366
- delete newNetworkInvalidKeys.value[index]
367
- delete sendDataNewNetwork.value[index]
368
- sendData()
369
- }
370
-
371
- const defaultCdDvdDriver: UI_I_SendDataNewCdDvdDrive = {
372
- create: false,
373
- attach: false,
374
- source: '',
375
- bus: '',
376
- device_type: 'cdrom',
377
- boot_order: -1,
378
- }
379
- const cdDvdDrives = ref<UI_I_SendDataNewCdDvdDrive[]>([
380
- useDeepCopy(defaultCdDvdDriver),
381
- ])
382
- const cdDvdDrivesIndex = ref<number[]>([0])
383
- const cdDvdDrivesType = ref<UI_T_CdDvdType[]>(['new'])
384
- watch(
385
- () => props.cdDvdDrives,
386
- (newValue) => {
387
- if ((!props.isEdit && !props.isClone) || !newValue) return
388
-
389
- // cdDvdDrives.value = newValue
390
- // cdDvdDrivesType.value = Array(newValue.length).fill('edit')
391
- const count = newValue?.length || 0
392
- cdDvdDrivesIndex.value = [...Array(count).keys()]
393
- cdDvdDrives.value = newValue
394
- if (props.isEdit) {
395
- cdDvdDrivesType.value = Array(count).fill('edit')
396
- } else if (props.isClone) {
397
- cdDvdDrivesType.value = Array(count).fill('new')
398
- }
399
- },
400
- { immediate: true }
401
- )
402
- const addCdDvdDrive = (): void => {
403
- const value = (cdDvdDrivesIndex.value.at(-1) || 0) + 1
404
- cdDvdDrivesIndex.value.push(value)
405
- cdDvdDrivesType.value.push('new')
406
- cdDvdDrives.value.push({
407
- ...useDeepCopy(defaultCdDvdDriver),
408
- attach: true,
409
- boot_order: 0, // Убираем галочку
410
- })
411
- }
412
- const onRemoveCdDvdDrive = (
413
- index: number,
414
- cdDvdDrive: UI_I_SendDataNewCdDvdDrive
415
- ): void => {
416
- const removeIndex = cdDvdDrivesIndex.value.indexOf(index)
417
-
418
- // if (!cdDvdDrive.create && !cdDvdDrive.attach) {
419
- if (cdDvdDrivesType.value[index] === 'edit' && !cdDvdDrive.attach) {
420
- cdDvdDrivesType.value = cdDvdDrivesType.value.map((item, key) => {
421
- if (key === removeIndex) return 'removed'
422
- return item
423
- })
424
- sendData()
425
- return
426
- }
427
-
428
- cdDvdDrivesIndex.value = cdDvdDrivesIndex.value.filter(
429
- (cdDvdDrive) => cdDvdDrive !== index
430
- )
431
- cdDvdDrivesType.value = cdDvdDrivesType.value.filter(
432
- (_item, key) => key !== index
433
- )
434
- cdDvdDrives.value = cdDvdDrives.value.filter(
435
- (_cdDvdDrive, key: number) => removeIndex !== key
436
- )
437
-
438
- delete sendDataNewCdDvdDrive.value[index]
439
- sendData()
440
- }
441
- const onRollBackCdDvdDrive = (index: number): void => {
442
- const removeIndex = cdDvdDrivesIndex.value.indexOf(index)
443
- cdDvdDrivesType.value = cdDvdDrivesType.value.map((item, key) => {
444
- if (key === removeIndex) return 'edit'
445
- return item
446
- })
447
- }
448
-
449
- const defaultPciDevice: UI_I_PciDevice = {
450
- id: '',
451
- vendor_name: '',
452
- class_name: 'cdrom',
453
- device_name: 'cdrom',
454
- }
455
- const pciDevicesIndex = ref<number[]>([0])
456
- const pciDevicesType = ref<('new' | 'edit')[]>(['new'])
457
- const pciDevices = ref<UI_I_PciDevice[]>([])
458
- watch(
459
- () => props.pciDevices,
460
- (newValue) => {
461
- if ((!props.isEdit && !props.isClone) || !newValue) return
462
-
463
- const count = newValue?.length || 0
464
- pciDevicesIndex.value = [...Array(count).keys()]
465
- pciDevices.value = newValue || []
466
- if (props.isEdit) {
467
- pciDevicesType.value = Array(count).fill('edit')
468
- } else if (props.isClone) {
469
- pciDevicesType.value = Array(count).fill('new')
470
- }
471
- },
472
- { immediate: true }
473
- )
474
-
475
- const addPciDevice = (): void => {
476
- const newIndex = (pciDevicesIndex.value.at(-1) ?? -1) + 1
477
- pciDevicesIndex.value.push(newIndex)
478
- pciDevicesType.value.push('new')
479
-
480
- pciDevices.value.push(useDeepCopy(defaultPciDevice))
481
- }
482
- const onRemovePciDevice = (index: number): void => {
483
- const removeIndex = pciDevicesIndex.value.indexOf(index)
484
- pciDevicesIndex.value = pciDevicesIndex.value.filter((item) => item !== index)
485
- pciDevicesType.value = pciDevicesType.value.filter(
486
- (_item, key) => key !== removeIndex
487
- )
488
-
489
- pciDevices.value = pciDevices.value.filter((_pciDevice, key: number) => {
490
- return removeIndex !== key
491
- })
492
-
493
- delete newPciDeviceInvalidKeys.value[index]
494
- delete sendDataNewPciDevices.value[index]
495
- sendData()
496
- }
497
-
498
- const isShowFileModal = ref<boolean>(false)
499
- const onAddDevice = (item: UI_I_DropdownTreeItemChild): void => {
500
- switch (item.value) {
501
- case 1:
502
- addHardDisk()
503
- break
504
- case 2:
505
- isShowFileModal.value = true
506
- break
507
- case 5:
508
- addCdDvdDrive()
509
- break
510
- case 10:
511
- addPciDevice()
512
- break
513
- case 14:
514
- addNetwork()
515
- break
516
- }
517
- }
518
-
519
- const cpuInvalid = ref<boolean>(false)
520
- const sendDataCpu = ref<UI_I_SendDataCpu | null>(null)
521
- const onSendDataCpuMethod = (data: UI_I_SendDataCpu): void => {
522
- sendDataCpu.value = data
523
- sendData()
524
- }
525
- const sendDataMemory = ref<UI_I_SendDataMemory | null>(null)
526
- const onSendDataMemoryMethod = (data: UI_I_SendDataMemory): void => {
527
- sendDataMemory.value = data
528
- sendData()
529
- }
530
- const sendDataNewHardDisk = ref<UI_I_SendDataNewHardDisk[]>([])
531
- const onSendDataNewHardDiskMethod = (
532
- data: UI_I_SendDataNewHardDisk,
533
- index: number
534
- ): void => {
535
- sendDataNewHardDisk.value[index] = data
536
- sendData()
537
- }
538
- const sendDataNewNetwork = ref<UI_I_SendDataNewNetwork[]>([])
539
- const sendDataNewNetworkMethod = (
540
- data: UI_I_SendDataNewNetwork,
541
- index: number
542
- ): void => {
543
- sendDataNewNetwork.value[index] = data
544
- sendData()
545
- }
546
- const sendDataNewCdDvdDrive = ref<UI_I_SendDataNewCdDvdDrive[]>([])
547
- const sendDataNewCdDvdDriveMethod = (
548
- data: UI_I_SendDataNewCdDvdDrive,
549
- index: number
550
- ): void => {
551
- sendDataNewCdDvdDrive.value[index] = data
552
- sendData()
553
- }
554
- const sendDataNewUsbController = ref<string | null>(null)
555
- const onSendDataNewUsbControllerMethod = (data: string): void => {
556
- sendDataNewUsbController.value = data
557
- sendData()
558
- }
559
- const sendDataNewPciDevices = ref<UI_I_SendDataNewPciDevice[]>([])
560
- const onSendDataPciDevicesMethod = (
561
- data: UI_I_SendDataNewPciDevice,
562
- index: number
563
- ): void => {
564
- sendDataNewPciDevices.value[index] = data
565
- sendData()
566
- }
567
- const sendDataVideoCard = ref<UI_I_SendDataVideoCard | null>(null)
568
- const onSendDataVideoCardMethod = (data: UI_I_SendDataVideoCard): void => {
569
- sendDataVideoCard.value = data
570
- sendData()
571
- }
572
-
573
- const sendData = (): void => {
574
- const cpu = sendDataCpu.value
575
- const memory = sendDataMemory.value
576
- const hardDisks = sendDataNewHardDisk.value.flat(2)
577
- const networks = sendDataNewNetwork.value.flat(2)
578
- const cdDvdDrives = sendDataNewCdDvdDrive.value.flat(2)
579
- const pciDevices = sendDataNewPciDevices.value.flat()
580
- const usbController = sendDataNewUsbController.value
581
- const videoCard = sendDataVideoCard.value
582
-
583
- const sendData: UI_I_SendDataVirtualHardware = {
584
- cpu,
585
- memory,
586
- usbController,
587
- pciDevices,
588
- networks,
589
- hardDisks,
590
- cdDvdDrives,
591
- videoCard,
592
- }
593
- emits('send-data', sendData)
594
- }
595
-
596
- const onSetInvalidHardDisk = (invalid: boolean, index: number): void => {
597
- newHardDiskInvalidKeys.value[index] = invalid
598
- }
599
-
600
- const onSetInvalidNetwork = (invalid: boolean, key: number): void => {
601
- newNetworkInvalidKeys.value[key] = invalid
602
- }
603
-
604
- const onSetInvalidPciDevice = (invalid: boolean, key: number): void => {
605
- newPciDeviceInvalidKeys.value[key] = invalid
606
- }
607
-
608
- const memoryInvalid = ref<boolean>(false)
609
- const videoCardInvalid = ref<boolean>(false)
610
- const newHardDiskInvalidKeys = ref<UI_I_InvalidKeys>({})
611
- const newNetworkInvalidKeys = ref<UI_I_InvalidKeys>({})
612
- const newPciDeviceInvalidKeys = ref<UI_I_InvalidKeys>({})
613
-
614
- watch(
615
- [
616
- cpuInvalid,
617
- memoryInvalid,
618
- newHardDiskInvalidKeys,
619
- newNetworkInvalidKeys,
620
- newPciDeviceInvalidKeys,
621
- videoCardInvalid,
622
- ],
623
- () => {
624
- const cpu = cpuInvalid.value ? localization.value.cpu : ''
625
- const memory = memoryInvalid.value ? localization.value.memory : ''
626
- const videoCard = videoCardInvalid.value ? localization.value.videoCard : ''
627
- let newHardDisk = ''
628
- Object.keys(newHardDiskInvalidKeys.value).forEach((key) => {
629
- if (!newHardDiskInvalidKeys.value[+key]) {
630
- return
631
- }
632
-
633
- newHardDisk +=
634
- (newHardDisk ? ', ' : '') +
635
- localization.value.newHardDisk +
636
- ' ' +
637
- (+key + 1)
638
- })
639
- let newNetwork = ''
640
- Object.keys(newNetworkInvalidKeys.value).forEach((key) => {
641
- if (!newNetworkInvalidKeys.value[+key]) {
642
- return
643
- }
644
-
645
- newNetwork +=
646
- (newNetwork ? ', ' : '') +
647
- localization.value.newNetwork +
648
- ' ' +
649
- (+key + 1)
650
- })
651
- // let pciDevice = ''
652
- // Object.keys(newPciDeviceInvalidKeys.value).forEach((key) => {
653
- // if (!newPciDeviceInvalidKeys.value[+key]) {
654
- // return
655
- // }
656
- //
657
- // pciDevice +=
658
- // (pciDevice ? ', ' : '') +
659
- // localization.value.pciDevice +
660
- // ' ' +
661
- // (+key + 1)
662
- // })
663
-
664
- emits('invalid', [cpu, memory, newHardDisk, newNetwork, videoCard])
665
- },
666
- { deep: true }
667
- )
668
-
669
- emits('get-pci-devices')
670
- </script>
671
-
672
- <style scoped lang="scss">
673
- .virtual-hardware {
674
- .content-dropdown {
675
- width: 200px;
676
- }
677
- }
678
- </style>
1
+ <template>
2
+ <div class="virtual-hardware">
3
+ <div class="clr-row clr-justify-content-end">
4
+ <atoms-dropdown-tree
5
+ :title="localization.addNewDevice"
6
+ :items="dropdownItems"
7
+ @select="onAddDevice"
8
+ />
9
+ </div>
10
+
11
+ <div class="clr-component">
12
+ <div class="stack-view">
13
+ <common-vm-actions-common-customize-hardware-virtual-hardware-cpu
14
+ :max-cpus="props.maxCpus"
15
+ :cpu-models="props.cpuModels"
16
+ :cpu="props.cpu"
17
+ :is-edit="props.isEdit"
18
+ :state="props.state"
19
+ :error-validation-fields="props.errorValidationFields"
20
+ :vm-cpu-help-text-second="props.vmCpuHelpTextSecond"
21
+ @send-data="onSendDataCpuMethod"
22
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
23
+ @invalid="cpuInvalid = $event"
24
+ />
25
+ <common-vm-actions-common-customize-hardware-virtual-hardware-memory
26
+ :max-memory="props.maxMemory"
27
+ :is-edit="props.isEdit"
28
+ :memory="props.memory"
29
+ :state="props.state"
30
+ :error-validation-fields="props.errorValidationFields"
31
+ @send-data="onSendDataMemoryMethod"
32
+ @invalid="memoryInvalid = $event"
33
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
34
+ />
35
+ <common-vm-actions-common-customize-hardware-virtual-hardware-new-hard-disk
36
+ v-for="(item, key) in hardDisks"
37
+ :key="hardDisksIndex[key]"
38
+ :index="hardDisksIndex[key]"
39
+ :type="hardDisksType[key]"
40
+ :storage="props.storage"
41
+ :hard-disk="item"
42
+ :error-validation-fields="props.errorValidationFields"
43
+ :get-datastore-table-func="props.getDatastoreTableFunc"
44
+ :datastore="props.datastore"
45
+ :is-edit="props.isEdit"
46
+ :state="props.state"
47
+ @remove="onRemoveHardDisk(hardDisksIndex[key], item)"
48
+ @roll-back="onRollBackHardDisk(hardDisksIndex[key])"
49
+ @send-data="onSendDataNewHardDiskMethod($event, hardDisksIndex[key])"
50
+ @invalid="onSetInvalidHardDisk($event, hardDisksIndex[key])"
51
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
52
+ />
53
+ <common-vm-actions-common-customize-hardware-virtual-hardware-new-network
54
+ v-for="(item, key) in networks"
55
+ :key="networksIndex[key]"
56
+ :index="networksIndex[key]"
57
+ :type="networksType[key]"
58
+ :network="item"
59
+ :networks-table="props.networksTable"
60
+ :error-validation-fields="props.errorValidationFields"
61
+ :is-edit="props.isEdit"
62
+ :state="props.state"
63
+ @remove="onRemoveNetwork(networksIndex[key])"
64
+ @send-data="sendDataNewNetworkMethod($event, networksIndex[key])"
65
+ @invalid="onSetInvalidNetwork($event, networksIndex[key])"
66
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
67
+ @get-networks-table="emits('get-networks-table', $event)"
68
+ />
69
+ <common-vm-actions-common-customize-hardware-virtual-hardware-cd-dvd-drive
70
+ v-for="(item, key) in cdDvdDrives"
71
+ :key="cdDvdDrivesIndex[key]"
72
+ :index="cdDvdDrivesIndex[key]"
73
+ :hard-disks-count="hardDisks.length"
74
+ :type="cdDvdDrivesType[key]"
75
+ :cd-dvd-drive="item"
76
+ :nodes="props.nodes"
77
+ :files="props.files"
78
+ :error-validation-fields="props.errorValidationFields"
79
+ :is-edit="props.isEdit"
80
+ :state="props.state"
81
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
82
+ @get-storage="emits('get-storage', $event)"
83
+ @get-folders-or-files="emits('get-folders-or-files', $event)"
84
+ @get-active-device-child="emits('get-active-device-child', $event)"
85
+ @show-datastore-child="emits('show-datastore-child', $event)"
86
+ @remove="onRemoveCdDvdDrive(cdDvdDrivesIndex[key], item)"
87
+ @roll-back="onRollBackCdDvdDrive(cdDvdDrivesIndex[key])"
88
+ @send-data="
89
+ sendDataNewCdDvdDriveMethod($event, cdDvdDrivesIndex[key])
90
+ "
91
+ />
92
+ <common-vm-actions-common-customize-hardware-virtual-hardware-new-usb-controller
93
+ :usb-controller="props.usbController"
94
+ :is-edit="props.isEdit"
95
+ :state="props.state"
96
+ @send-data="onSendDataNewUsbControllerMethod"
97
+ />
98
+ <template v-if="props.passthroughDevices">
99
+ <common-vm-actions-common-customize-hardware-virtual-hardware-new-pci-device
100
+ v-for="(item, key) in pciDevices"
101
+ :key="pciDevicesIndex[key]"
102
+ :index="pciDevicesIndex[key]"
103
+ :pci-device="item"
104
+ :error-validation-fields="props.errorValidationFields"
105
+ :passthrough-devices="props.passthroughDevices"
106
+ :type="pciDevicesType[key]"
107
+ @remove="onRemovePciDevice(pciDevicesIndex[key])"
108
+ @send-data="
109
+ onSendDataPciDevicesMethod($event, pciDevicesIndex[key])
110
+ "
111
+ @invalid="onSetInvalidPciDevice($event, pciDevicesIndex[key])"
112
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
113
+ />
114
+ </template>
115
+ <common-vm-actions-common-customize-hardware-virtual-hardware-video-card
116
+ :is-edit="props.isEdit"
117
+ :video-card="props.videoCard"
118
+ :error-validation-fields="props.errorValidationFields"
119
+ :state="props.state"
120
+ @send-data="onSendDataVideoCardMethod"
121
+ @invalid="videoCardInvalid = $event"
122
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
123
+ />
124
+ <common-vm-actions-common-customize-hardware-virtual-hardware-other />
125
+ </div>
126
+ </div>
127
+
128
+ <Teleport to="body">
129
+ <common-vm-actions-common-customize-hardware-virtual-hardware-browse-view
130
+ v-if="isShowFileModal"
131
+ :show="isShowFileModal"
132
+ :nodes="props.nodes"
133
+ :files="props.files"
134
+ @submit="onAddExistHardDisk"
135
+ @get-storage="emits('get-storage', $event)"
136
+ @get-folders-or-files="emits('get-folders-or-files', $event)"
137
+ @get-active-device-child="emits('get-active-device-child', $event)"
138
+ @show-datastore-child="emits('show-datastore-child', $event)"
139
+ @hide="isShowFileModal = false"
140
+ />
141
+ </Teleport>
142
+ </div>
143
+ </template>
144
+
145
+ <script setup lang="ts">
146
+ import { UI_I_DatastoreTableItem } from '~/models/store/storage/interfaces'
147
+ import { UI_I_NetworkTableItem } from '~/models/store/network/interfaces'
148
+ import { UI_I_TablePayload } from '~/models/store/interfaces'
149
+ import { UI_I_FolderOrFileTreePayload } from '~/models/store/storage/interfaces'
150
+ import { UI_I_FileTreeNode } from '~/components/models/interfaces'
151
+ import {
152
+ UI_I_SendDataCpu,
153
+ UI_I_SendDataMemory,
154
+ UI_I_SendDataNewHardDisk,
155
+ UI_I_SendDataNewNetwork,
156
+ UI_I_SendDataVideoCard,
157
+ UI_I_InvalidKeys,
158
+ UI_I_SendDataVirtualHardware,
159
+ UI_I_SendDataNewCdDvdDrive,
160
+ UI_I_HardDisk,
161
+ UI_I_PciDevice,
162
+ UI_I_SendDataNewPciDevice,
163
+ } from '~/components/common/vm/actions/common/customizeHardware/virtualHardware/models/interfaces'
164
+ import { UI_I_ErrorValidationField } from '~/models/store/interfaces'
165
+ import {
166
+ UI_T_HardDiskType,
167
+ UI_T_NetworkType,
168
+ UI_T_CdDvdType,
169
+ } from '~/components/common/vm/actions/common/customizeHardware/virtualHardware/models/types'
170
+ import { UI_I_OptionItem } from '~/components/atoms/models/interfaces'
171
+ import {
172
+ UI_I_DropdownTreeItem,
173
+ UI_I_DropdownTreeItemChild,
174
+ } from '~/components/atoms/dropdown/tree/models/interfaces'
175
+ import { UI_I_Localization } from '~/models/interfaces'
176
+ import { UI_I_ConfigurePciDevicesTable } from '~/models/store/host/interfaces'
177
+ import {
178
+ API_UI_I_VmEditCpu,
179
+ API_UI_I_VmEditMemory,
180
+ } from '~/models/store/vm/interfaces'
181
+ import { dropdownItemsFunc } from './config/dropdownItems'
182
+
183
+ const props = defineProps<{
184
+ storage: UI_I_DatastoreTableItem | null
185
+ cpuModels: UI_I_OptionItem[]
186
+ vmName: string
187
+ maxCpus: number
188
+ maxMemory: number
189
+ isEdit: boolean
190
+ isClone: boolean
191
+ errorValidationFields: UI_I_ErrorValidationField<string>[]
192
+ nodes: UI_I_FileTreeNode[]
193
+ files: UI_I_FileTreeNode[]
194
+ networksTable: UI_I_NetworkTableItem[]
195
+ getDatastoreTableFunc: (payload: UI_I_TablePayload) => Promise<void>
196
+ datastore: UI_I_DatastoreTableItem[]
197
+ state?: string | number
198
+ cpu?: API_UI_I_VmEditCpu
199
+ memory?: API_UI_I_VmEditMemory
200
+ vmCpuHelpTextSecond?: string
201
+ hardDisks?: UI_I_SendDataNewHardDisk[] | null
202
+ cdDvdDrives?: UI_I_SendDataNewCdDvdDrive[] | null
203
+ networks?: UI_I_SendDataNewNetwork[] | null
204
+ videoCard?: UI_I_SendDataVideoCard
205
+ usbController?: string
206
+ pciDevices?: UI_I_PciDevice[]
207
+ passthroughDevices?: UI_I_ConfigurePciDevicesTable | null
208
+ }>()
209
+ const emits = defineEmits<{
210
+ (event: 'send-data', value: UI_I_SendDataVirtualHardware): void
211
+ (event: 'invalid', value: string[]): void
212
+ (event: 'get-storage', value: UI_I_TablePayload): void
213
+ (event: 'get-folders-or-files', value: UI_I_FolderOrFileTreePayload): void
214
+ (event: 'get-active-device-child', value: UI_I_FileTreeNode): void
215
+ (event: 'show-datastore-child', value: UI_I_FileTreeNode): void
216
+ (event: 'remove-error-by-title', value: string): void
217
+ (event: 'get-networks-table', value: UI_I_TablePayload): void
218
+ (event: 'get-pci-devices'): void
219
+ }>()
220
+
221
+ const localization = computed<UI_I_Localization>(() => useLocal())
222
+ const { $binary } = useNuxtApp()
223
+
224
+ const dropdownItems = computed<UI_I_DropdownTreeItem[]>(() =>
225
+ dropdownItemsFunc(localization.value)
226
+ )
227
+
228
+ const hardDisksIndex = ref<number[]>([0])
229
+ const hardDisksType = ref<UI_T_HardDiskType[]>(['new'])
230
+ const hardDisks = ref<UI_I_SendDataNewHardDisk[]>([
231
+ {
232
+ create: true,
233
+ size: 90,
234
+ source: '',
235
+ boot_order: -1,
236
+ },
237
+ ])
238
+ watch(
239
+ () => props.hardDisks,
240
+ (newValue) => {
241
+ if ((!props.isEdit && !props.isClone) || !newValue) return
242
+
243
+ const count = newValue?.length || 0
244
+ hardDisksIndex.value = [...Array(count).keys()]
245
+ hardDisks.value = newValue
246
+ if (props.isEdit) {
247
+ hardDisksType.value = Array(count).fill('edit')
248
+ } else if (props.isClone) {
249
+ hardDisksType.value = Array(count).fill('new')
250
+ hardDisks.value = newValue.map((hardDisk) => {
251
+ hardDisk.create = true
252
+ return hardDisk
253
+ })
254
+ }
255
+ },
256
+ { immediate: true }
257
+ )
258
+
259
+ const addHardDisk = (
260
+ create = true,
261
+ size = 90,
262
+ source = '',
263
+ type: UI_T_HardDiskType = 'new'
264
+ ): void => {
265
+ const newIndex = (hardDisksIndex.value.at(-1) ?? -1) + 1
266
+ hardDisksIndex.value.push(newIndex)
267
+ hardDisksType.value.push(type)
268
+
269
+ hardDisks.value.push({
270
+ create,
271
+ size,
272
+ source,
273
+ attach: true,
274
+ boot_order: 0, // Убираем галочку
275
+ })
276
+ sendData()
277
+ }
278
+ const onAddExistHardDisk = (hardDisk: UI_I_HardDisk): void => {
279
+ addHardDisk(false, $binary.bToGb(hardDisk.size), hardDisk.path, 'exist')
280
+ }
281
+ const onRemoveHardDisk = (
282
+ index: number,
283
+ hardDisk: UI_I_SendDataNewHardDisk
284
+ ): void => {
285
+ const removeIndex = hardDisksIndex.value.indexOf(index)
286
+
287
+ if (!hardDisk.create && !hardDisk.attach) {
288
+ hardDisksType.value = hardDisksType.value.map((item, key) => {
289
+ if (key === removeIndex) return 'removed'
290
+ return item
291
+ })
292
+ sendData()
293
+ return
294
+ }
295
+
296
+ hardDisksIndex.value = hardDisksIndex.value.filter((item) => item !== index)
297
+ hardDisksType.value = hardDisksType.value.filter(
298
+ (_item, key) => key !== removeIndex
299
+ )
300
+
301
+ hardDisks.value = hardDisks.value.filter((_hardDisk, key: number) => {
302
+ return removeIndex !== key
303
+ })
304
+
305
+ delete newHardDiskInvalidKeys.value[index]
306
+ delete sendDataNewHardDisk.value[index]
307
+ sendData()
308
+ }
309
+ const onRollBackHardDisk = (index: number): void => {
310
+ const removeIndex = hardDisksIndex.value.indexOf(index)
311
+ hardDisksType.value = hardDisksType.value.map((item, key) => {
312
+ if (key === removeIndex) return 'edit'
313
+ return item
314
+ })
315
+ }
316
+
317
+ const defaultNetwork = {
318
+ network: '',
319
+ net_bridge: '',
320
+ mac: '',
321
+ target: '',
322
+ model: '',
323
+ boot_order: -1,
324
+ }
325
+ const networks = ref<UI_I_SendDataNewNetwork[]>([useDeepCopy(defaultNetwork)])
326
+ const networksType = ref<UI_T_NetworkType[]>(['new'])
327
+ const networksIndex = ref<number[]>([0])
328
+ watch(
329
+ () => props.networks,
330
+ (newValue) => {
331
+ if ((!props.isEdit && !props.isClone) || !newValue) return
332
+
333
+ // networks.value = newValue
334
+ // networksType.value = Array(newValue.length).fill('edit')
335
+ const count = newValue?.length || 0
336
+ networksIndex.value = [...Array(count).keys()]
337
+ networks.value = newValue
338
+ if (props.isEdit) {
339
+ networksType.value = Array(count).fill('edit')
340
+ } else if (props.isClone) {
341
+ networksType.value = Array(count).fill('new')
342
+ }
343
+ },
344
+ { immediate: true }
345
+ )
346
+ const addNetwork = (): void => {
347
+ const index = (networksIndex.value.at(-1) || 0) + 1
348
+ networksIndex.value.push(index)
349
+ networksType.value.push('new')
350
+
351
+ networks.value.push({
352
+ ...useDeepCopy(defaultNetwork),
353
+ boot_order: 0, // Убираем галочку
354
+ })
355
+ }
356
+ const onRemoveNetwork = (index: number): void => {
357
+ const removeIndex = networksIndex.value.indexOf(index)
358
+ networksIndex.value = networksIndex.value.filter((item) => item !== index)
359
+ networksType.value = networksType.value.filter(
360
+ (_item, key) => key !== removeIndex
361
+ )
362
+ networks.value = networks.value.filter(
363
+ (_network, key: number) => removeIndex !== key
364
+ )
365
+
366
+ delete newNetworkInvalidKeys.value[index]
367
+ delete sendDataNewNetwork.value[index]
368
+ sendData()
369
+ }
370
+
371
+ const defaultCdDvdDriver: UI_I_SendDataNewCdDvdDrive = {
372
+ create: false,
373
+ attach: false,
374
+ source: '',
375
+ bus: '',
376
+ device_type: 'cdrom',
377
+ boot_order: -1,
378
+ }
379
+ const cdDvdDrives = ref<UI_I_SendDataNewCdDvdDrive[]>([
380
+ useDeepCopy(defaultCdDvdDriver),
381
+ ])
382
+ const cdDvdDrivesIndex = ref<number[]>([0])
383
+ const cdDvdDrivesType = ref<UI_T_CdDvdType[]>(['new'])
384
+ watch(
385
+ () => props.cdDvdDrives,
386
+ (newValue) => {
387
+ if ((!props.isEdit && !props.isClone) || !newValue) return
388
+
389
+ // cdDvdDrives.value = newValue
390
+ // cdDvdDrivesType.value = Array(newValue.length).fill('edit')
391
+ const count = newValue?.length || 0
392
+ cdDvdDrivesIndex.value = [...Array(count).keys()]
393
+ cdDvdDrives.value = newValue
394
+ if (props.isEdit) {
395
+ cdDvdDrivesType.value = Array(count).fill('edit')
396
+ } else if (props.isClone) {
397
+ cdDvdDrivesType.value = Array(count).fill('new')
398
+ }
399
+ },
400
+ { immediate: true }
401
+ )
402
+ const addCdDvdDrive = (): void => {
403
+ const value = (cdDvdDrivesIndex.value.at(-1) || 0) + 1
404
+ cdDvdDrivesIndex.value.push(value)
405
+ cdDvdDrivesType.value.push('new')
406
+ cdDvdDrives.value.push({
407
+ ...useDeepCopy(defaultCdDvdDriver),
408
+ attach: true,
409
+ boot_order: 0, // Убираем галочку
410
+ })
411
+ }
412
+ const onRemoveCdDvdDrive = (
413
+ index: number,
414
+ cdDvdDrive: UI_I_SendDataNewCdDvdDrive
415
+ ): void => {
416
+ const removeIndex = cdDvdDrivesIndex.value.indexOf(index)
417
+
418
+ // if (!cdDvdDrive.create && !cdDvdDrive.attach) {
419
+ if (cdDvdDrivesType.value[index] === 'edit' && !cdDvdDrive.attach) {
420
+ cdDvdDrivesType.value = cdDvdDrivesType.value.map((item, key) => {
421
+ if (key === removeIndex) return 'removed'
422
+ return item
423
+ })
424
+ sendData()
425
+ return
426
+ }
427
+
428
+ cdDvdDrivesIndex.value = cdDvdDrivesIndex.value.filter(
429
+ (cdDvdDrive) => cdDvdDrive !== index
430
+ )
431
+ cdDvdDrivesType.value = cdDvdDrivesType.value.filter(
432
+ (_item, key) => key !== index
433
+ )
434
+ cdDvdDrives.value = cdDvdDrives.value.filter(
435
+ (_cdDvdDrive, key: number) => removeIndex !== key
436
+ )
437
+
438
+ delete sendDataNewCdDvdDrive.value[index]
439
+ sendData()
440
+ }
441
+ const onRollBackCdDvdDrive = (index: number): void => {
442
+ const removeIndex = cdDvdDrivesIndex.value.indexOf(index)
443
+ cdDvdDrivesType.value = cdDvdDrivesType.value.map((item, key) => {
444
+ if (key === removeIndex) return 'edit'
445
+ return item
446
+ })
447
+ }
448
+
449
+ const defaultPciDevice: UI_I_PciDevice = {
450
+ id: '',
451
+ vendor_name: '',
452
+ class_name: 'cdrom',
453
+ device_name: 'cdrom',
454
+ }
455
+ const pciDevicesIndex = ref<number[]>([0])
456
+ const pciDevicesType = ref<('new' | 'edit')[]>(['new'])
457
+ const pciDevices = ref<UI_I_PciDevice[]>([])
458
+ watch(
459
+ () => props.pciDevices,
460
+ (newValue) => {
461
+ if ((!props.isEdit && !props.isClone) || !newValue) return
462
+
463
+ const count = newValue?.length || 0
464
+ pciDevicesIndex.value = [...Array(count).keys()]
465
+ pciDevices.value = newValue || []
466
+ if (props.isEdit) {
467
+ pciDevicesType.value = Array(count).fill('edit')
468
+ } else if (props.isClone) {
469
+ pciDevicesType.value = Array(count).fill('new')
470
+ }
471
+ },
472
+ { immediate: true }
473
+ )
474
+
475
+ const addPciDevice = (): void => {
476
+ const newIndex = (pciDevicesIndex.value.at(-1) ?? -1) + 1
477
+ pciDevicesIndex.value.push(newIndex)
478
+ pciDevicesType.value.push('new')
479
+
480
+ pciDevices.value.push(useDeepCopy(defaultPciDevice))
481
+ }
482
+ const onRemovePciDevice = (index: number): void => {
483
+ const removeIndex = pciDevicesIndex.value.indexOf(index)
484
+ pciDevicesIndex.value = pciDevicesIndex.value.filter((item) => item !== index)
485
+ pciDevicesType.value = pciDevicesType.value.filter(
486
+ (_item, key) => key !== removeIndex
487
+ )
488
+
489
+ pciDevices.value = pciDevices.value.filter((_pciDevice, key: number) => {
490
+ return removeIndex !== key
491
+ })
492
+
493
+ delete newPciDeviceInvalidKeys.value[index]
494
+ delete sendDataNewPciDevices.value[index]
495
+ sendData()
496
+ }
497
+
498
+ const isShowFileModal = ref<boolean>(false)
499
+ const onAddDevice = (item: UI_I_DropdownTreeItemChild): void => {
500
+ switch (item.value) {
501
+ case 1:
502
+ addHardDisk()
503
+ break
504
+ case 2:
505
+ isShowFileModal.value = true
506
+ break
507
+ case 5:
508
+ addCdDvdDrive()
509
+ break
510
+ case 10:
511
+ addPciDevice()
512
+ break
513
+ case 14:
514
+ addNetwork()
515
+ break
516
+ }
517
+ }
518
+
519
+ const cpuInvalid = ref<boolean>(false)
520
+ const sendDataCpu = ref<UI_I_SendDataCpu | null>(null)
521
+ const onSendDataCpuMethod = (data: UI_I_SendDataCpu): void => {
522
+ sendDataCpu.value = data
523
+ sendData()
524
+ }
525
+ const sendDataMemory = ref<UI_I_SendDataMemory | null>(null)
526
+ const onSendDataMemoryMethod = (data: UI_I_SendDataMemory): void => {
527
+ sendDataMemory.value = data
528
+ sendData()
529
+ }
530
+ const sendDataNewHardDisk = ref<UI_I_SendDataNewHardDisk[]>([])
531
+ const onSendDataNewHardDiskMethod = (
532
+ data: UI_I_SendDataNewHardDisk,
533
+ index: number
534
+ ): void => {
535
+ sendDataNewHardDisk.value[index] = data
536
+ sendData()
537
+ }
538
+ const sendDataNewNetwork = ref<UI_I_SendDataNewNetwork[]>([])
539
+ const sendDataNewNetworkMethod = (
540
+ data: UI_I_SendDataNewNetwork,
541
+ index: number
542
+ ): void => {
543
+ sendDataNewNetwork.value[index] = data
544
+ sendData()
545
+ }
546
+ const sendDataNewCdDvdDrive = ref<UI_I_SendDataNewCdDvdDrive[]>([])
547
+ const sendDataNewCdDvdDriveMethod = (
548
+ data: UI_I_SendDataNewCdDvdDrive,
549
+ index: number
550
+ ): void => {
551
+ sendDataNewCdDvdDrive.value[index] = data
552
+ sendData()
553
+ }
554
+ const sendDataNewUsbController = ref<string | null>(null)
555
+ const onSendDataNewUsbControllerMethod = (data: string): void => {
556
+ sendDataNewUsbController.value = data
557
+ sendData()
558
+ }
559
+ const sendDataNewPciDevices = ref<UI_I_SendDataNewPciDevice[]>([])
560
+ const onSendDataPciDevicesMethod = (
561
+ data: UI_I_SendDataNewPciDevice,
562
+ index: number
563
+ ): void => {
564
+ sendDataNewPciDevices.value[index] = data
565
+ sendData()
566
+ }
567
+ const sendDataVideoCard = ref<UI_I_SendDataVideoCard | null>(null)
568
+ const onSendDataVideoCardMethod = (data: UI_I_SendDataVideoCard): void => {
569
+ sendDataVideoCard.value = data
570
+ sendData()
571
+ }
572
+
573
+ const sendData = (): void => {
574
+ const cpu = sendDataCpu.value
575
+ const memory = sendDataMemory.value
576
+ const hardDisks = sendDataNewHardDisk.value.flat(2)
577
+ const networks = sendDataNewNetwork.value.flat(2)
578
+ const cdDvdDrives = sendDataNewCdDvdDrive.value.flat(2)
579
+ const pciDevices = sendDataNewPciDevices.value.flat()
580
+ const usbController = sendDataNewUsbController.value
581
+ const videoCard = sendDataVideoCard.value
582
+
583
+ const sendData: UI_I_SendDataVirtualHardware = {
584
+ cpu,
585
+ memory,
586
+ usbController,
587
+ pciDevices,
588
+ networks,
589
+ hardDisks,
590
+ cdDvdDrives,
591
+ videoCard,
592
+ }
593
+ emits('send-data', sendData)
594
+ }
595
+
596
+ const onSetInvalidHardDisk = (invalid: boolean, index: number): void => {
597
+ newHardDiskInvalidKeys.value[index] = invalid
598
+ }
599
+
600
+ const onSetInvalidNetwork = (invalid: boolean, key: number): void => {
601
+ newNetworkInvalidKeys.value[key] = invalid
602
+ }
603
+
604
+ const onSetInvalidPciDevice = (invalid: boolean, key: number): void => {
605
+ newPciDeviceInvalidKeys.value[key] = invalid
606
+ }
607
+
608
+ const memoryInvalid = ref<boolean>(false)
609
+ const videoCardInvalid = ref<boolean>(false)
610
+ const newHardDiskInvalidKeys = ref<UI_I_InvalidKeys>({})
611
+ const newNetworkInvalidKeys = ref<UI_I_InvalidKeys>({})
612
+ const newPciDeviceInvalidKeys = ref<UI_I_InvalidKeys>({})
613
+
614
+ watch(
615
+ [
616
+ cpuInvalid,
617
+ memoryInvalid,
618
+ newHardDiskInvalidKeys,
619
+ newNetworkInvalidKeys,
620
+ newPciDeviceInvalidKeys,
621
+ videoCardInvalid,
622
+ ],
623
+ () => {
624
+ const cpu = cpuInvalid.value ? localization.value.cpu : ''
625
+ const memory = memoryInvalid.value ? localization.value.memory : ''
626
+ const videoCard = videoCardInvalid.value ? localization.value.videoCard : ''
627
+ let newHardDisk = ''
628
+ Object.keys(newHardDiskInvalidKeys.value).forEach((key) => {
629
+ if (!newHardDiskInvalidKeys.value[+key]) {
630
+ return
631
+ }
632
+
633
+ newHardDisk +=
634
+ (newHardDisk ? ', ' : '') +
635
+ localization.value.newHardDisk +
636
+ ' ' +
637
+ (+key + 1)
638
+ })
639
+ let newNetwork = ''
640
+ Object.keys(newNetworkInvalidKeys.value).forEach((key) => {
641
+ if (!newNetworkInvalidKeys.value[+key]) {
642
+ return
643
+ }
644
+
645
+ newNetwork +=
646
+ (newNetwork ? ', ' : '') +
647
+ localization.value.newNetwork +
648
+ ' ' +
649
+ (+key + 1)
650
+ })
651
+ // let pciDevice = ''
652
+ // Object.keys(newPciDeviceInvalidKeys.value).forEach((key) => {
653
+ // if (!newPciDeviceInvalidKeys.value[+key]) {
654
+ // return
655
+ // }
656
+ //
657
+ // pciDevice +=
658
+ // (pciDevice ? ', ' : '') +
659
+ // localization.value.pciDevice +
660
+ // ' ' +
661
+ // (+key + 1)
662
+ // })
663
+
664
+ emits('invalid', [cpu, memory, newHardDisk, newNetwork, videoCard])
665
+ },
666
+ { deep: true }
667
+ )
668
+
669
+ emits('get-pci-devices')
670
+ </script>
671
+
672
+ <style scoped lang="scss">
673
+ .virtual-hardware {
674
+ .content-dropdown {
675
+ width: 200px;
676
+ }
677
+ }
678
+ .stack-view {
679
+ background-color: var(--block-view-bg-color);
680
+ }
681
+ </style>