bfg-common 1.3.124 → 1.3.125

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