bfg-common 1.3.257 → 1.3.259

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.
Files changed (38) hide show
  1. package/components/atoms/dropdown/tree/lib/models/interfaces.ts +1 -1
  2. package/components/atoms/switch/Switch.vue +111 -111
  3. package/components/atoms/table/compact/Compact.vue +526 -526
  4. package/components/common/diagramMain/modals/editSettings/tabs/NetworkProperties.vue +1 -0
  5. package/components/common/diagramMain/modals/migrateVmkernelAdapter/steps/ConnectionSettings.vue +1 -0
  6. package/components/common/resource/progressBlock/ProgressBlock.vue +142 -142
  7. package/components/common/vm/actions/clone/Clone.vue +518 -518
  8. package/components/common/vm/actions/common/customizeHardware/virtualHardware/VirtualHardware.vue +694 -693
  9. package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/Cpu.vue +1 -0
  10. package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/MaxCpu.vue +1 -0
  11. package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/lib/config/cpuOptions.ts +2 -0
  12. package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/shares/Shares.vue +1 -0
  13. package/components/common/vm/actions/common/customizeHardware/virtualHardware/lib/config/dropdownItems.ts +66 -59
  14. package/components/common/vm/actions/common/customizeHardware/virtualHardware/limit/Limit.vue +2 -1
  15. package/components/common/vm/actions/common/customizeHardware/virtualHardware/memory/Memory.vue +1 -0
  16. package/components/common/vm/actions/common/customizeHardware/virtualHardware/memory/lib/config/memoryOptions.ts +3 -3
  17. package/components/common/vm/actions/common/customizeHardware/virtualHardware/newHardDisk/limitIops/LimitIops.vue +1 -0
  18. package/components/common/vm/actions/common/customizeHardware/virtualHardware/newPciDevice/NewPciDevice.vue +165 -165
  19. package/components/common/vm/actions/common/customizeHardware/virtualHardware/reservation/Reservation.vue +1 -0
  20. package/components/common/vm/actions/editSettings/EditSettings.vue +313 -313
  21. package/components/common/weekSelect/lib/config/options.ts +10 -10
  22. package/components/common/wizards/datastore/add/types/lib/config/typeOptions.ts +3 -0
  23. package/components/common/wizards/network/add/modals/SelectNetwork.vue +1 -0
  24. package/components/common/wizards/network/add/steps/ConnectionSettings.vue +1 -0
  25. package/composables/useAppVersion.ts +21 -21
  26. package/composables/useEnvLanguage.ts +20 -20
  27. package/lib/utils/sendTask.ts +72 -72
  28. package/minify.js +146 -146
  29. package/package.json +1 -1
  30. package/public/spice-console/application/codec.js +257 -257
  31. package/public/spice-console/lib/rasterEngine.js +907 -907
  32. package/public/spice-console/network/spicechannel.js +369 -369
  33. package/store/main/lib/interfaces.ts +9 -9
  34. package/store/tasks/actions.ts +133 -133
  35. package/store/tasks/getters.ts +25 -25
  36. package/store/tasks/lib/models/interfaces.ts +18 -18
  37. package/store/tasks/mutations.ts +58 -58
  38. package/store/tasks/state.ts +16 -16
@@ -1,693 +1,694 @@
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, props.passthroughDevices)
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
- provisioned_type?: number // При добавлении существующей
266
- ): void => {
267
- const newIndex = (hardDisksIndex.value.at(-1) ?? -1) + 1
268
- hardDisksIndex.value.push(newIndex)
269
- hardDisksType.value.push(type)
270
-
271
- let provisionType = 'thick'
272
- if (provisioned_type === 1) provisionType = 'thin'
273
-
274
- hardDisks.value.push({
275
- create,
276
- size,
277
- source,
278
- attach: true,
279
- boot_order: 0, // Убираем галочку
280
- provision_type: provisionType,
281
- })
282
- sendData()
283
- }
284
- const onAddExistHardDisk = (file: UI_I_FileTreeNode): void => {
285
- addHardDisk(
286
- false,
287
- $binary.bToGb(file.size),
288
- file.path,
289
- 'exist',
290
- file.provisioned_type
291
- )
292
- }
293
- const onRemoveHardDisk = (
294
- index: number,
295
- hardDisk: UI_I_SendDataNewHardDisk
296
- ): void => {
297
- const removeIndex = hardDisksIndex.value.indexOf(index)
298
-
299
- if (!hardDisk.create && !hardDisk.attach) {
300
- hardDisksType.value = hardDisksType.value.map((item, key) => {
301
- if (key === removeIndex) return 'removed'
302
- return item
303
- })
304
- sendData()
305
- return
306
- }
307
-
308
- hardDisksIndex.value = hardDisksIndex.value.filter((item) => item !== index)
309
- hardDisksType.value = hardDisksType.value.filter(
310
- (_item, key) => key !== removeIndex
311
- )
312
-
313
- hardDisks.value = hardDisks.value.filter((_hardDisk, key: number) => {
314
- return removeIndex !== key
315
- })
316
-
317
- delete newHardDiskInvalidKeys.value[index]
318
- delete sendDataNewHardDisk.value[index]
319
- sendData()
320
- }
321
- const onRollBackHardDisk = (index: number): void => {
322
- const removeIndex = hardDisksIndex.value.indexOf(index)
323
- hardDisksType.value = hardDisksType.value.map((item, key) => {
324
- if (key === removeIndex) return 'edit'
325
- return item
326
- })
327
- }
328
-
329
- const defaultNetwork = {
330
- network: '',
331
- net_bridge: '',
332
- mac: '',
333
- target: '',
334
- model: '',
335
- boot_order: -1,
336
- }
337
- const networks = ref<UI_I_SendDataNewNetwork[]>([useDeepCopy(defaultNetwork)])
338
- const networksType = ref<UI_T_NetworkType[]>(['new'])
339
- const networksIndex = ref<number[]>([0])
340
- watch(
341
- () => props.networks,
342
- (newValue) => {
343
- if ((!props.isEdit && !props.isClone) || !newValue) return
344
-
345
- // networks.value = newValue
346
- // networksType.value = Array(newValue.length).fill('edit')
347
- const count = newValue?.length || 0
348
- networksIndex.value = [...Array(count).keys()]
349
- networks.value = newValue
350
- if (props.isEdit) {
351
- networksType.value = Array(count).fill('edit')
352
- } else if (props.isClone) {
353
- networksType.value = Array(count).fill('new')
354
- }
355
- },
356
- { immediate: true }
357
- )
358
- const addNetwork = (): void => {
359
- const index = (networksIndex.value.at(-1) || 0) + 1
360
- networksIndex.value.push(index)
361
- networksType.value.push('new')
362
-
363
- networks.value.push({
364
- ...useDeepCopy(defaultNetwork),
365
- boot_order: 0, // Убираем галочку
366
- })
367
- }
368
- const onRemoveNetwork = (index: number): void => {
369
- const removeIndex = networksIndex.value.indexOf(index)
370
- networksIndex.value = networksIndex.value.filter((item) => item !== index)
371
- networksType.value = networksType.value.filter(
372
- (_item, key) => key !== removeIndex
373
- )
374
- networks.value = networks.value.filter(
375
- (_network, key: number) => removeIndex !== key
376
- )
377
-
378
- delete newNetworkInvalidKeys.value[index]
379
- delete sendDataNewNetwork.value[index]
380
- sendData()
381
- }
382
-
383
- const defaultCdDvdDriver: UI_I_SendDataNewCdDvdDrive = {
384
- create: false,
385
- attach: false,
386
- source: '',
387
- bus: '',
388
- device_type: 'cdrom',
389
- boot_order: -1,
390
- }
391
- const cdDvdDrives = ref<UI_I_SendDataNewCdDvdDrive[]>([
392
- useDeepCopy(defaultCdDvdDriver),
393
- ])
394
- const cdDvdDrivesIndex = ref<number[]>([0])
395
- const cdDvdDrivesType = ref<UI_T_CdDvdType[]>(['new'])
396
- watch(
397
- () => props.cdDvdDrives,
398
- (newValue) => {
399
- if ((!props.isEdit && !props.isClone) || !newValue) return
400
-
401
- // cdDvdDrives.value = newValue
402
- // cdDvdDrivesType.value = Array(newValue.length).fill('edit')
403
- const count = newValue?.length || 0
404
- cdDvdDrivesIndex.value = [...Array(count).keys()]
405
- cdDvdDrives.value = newValue
406
- if (props.isEdit) {
407
- cdDvdDrivesType.value = Array(count).fill('edit')
408
- } else if (props.isClone) {
409
- cdDvdDrivesType.value = Array(count).fill('new')
410
- }
411
- },
412
- { immediate: true }
413
- )
414
- const addCdDvdDrive = (): void => {
415
- const value = (cdDvdDrivesIndex.value.at(-1) || 0) + 1
416
- cdDvdDrivesIndex.value.push(value)
417
- cdDvdDrivesType.value.push('new')
418
- cdDvdDrives.value.push({
419
- ...useDeepCopy(defaultCdDvdDriver),
420
- attach: true,
421
- boot_order: 0, // Убираем галочку
422
- })
423
- }
424
- const onRemoveCdDvdDrive = (
425
- index: number,
426
- cdDvdDrive: UI_I_SendDataNewCdDvdDrive
427
- ): void => {
428
- const removeIndex = cdDvdDrivesIndex.value.indexOf(index)
429
-
430
- // if (!cdDvdDrive.create && !cdDvdDrive.attach) {
431
- if (cdDvdDrivesType.value[index] === 'edit' && !cdDvdDrive.attach) {
432
- cdDvdDrivesType.value = cdDvdDrivesType.value.map((item, key) => {
433
- if (key === removeIndex) return 'removed'
434
- return item
435
- })
436
- sendData()
437
- return
438
- }
439
-
440
- cdDvdDrivesIndex.value = cdDvdDrivesIndex.value.filter(
441
- (cdDvdDrive) => cdDvdDrive !== index
442
- )
443
- cdDvdDrivesType.value = cdDvdDrivesType.value.filter(
444
- (_item, key) => key !== index
445
- )
446
- cdDvdDrives.value = cdDvdDrives.value.filter(
447
- (_cdDvdDrive, key: number) => removeIndex !== key
448
- )
449
-
450
- delete sendDataNewCdDvdDrive.value[index]
451
- sendData()
452
- }
453
- const onRollBackCdDvdDrive = (index: number): void => {
454
- const removeIndex = cdDvdDrivesIndex.value.indexOf(index)
455
- cdDvdDrivesType.value = cdDvdDrivesType.value.map((item, key) => {
456
- if (key === removeIndex) return 'edit'
457
- return item
458
- })
459
- }
460
-
461
- const defaultPciDevice: UI_I_SendDataNewPciDevice = {
462
- address: '',
463
- vendor_name: '',
464
- class_name: 'cdrom',
465
- device_name: 'cdrom',
466
- }
467
- const pciDevicesIndex = ref<number[]>([0])
468
- const pciDevicesType = ref<('new' | 'edit' | 'removed')[]>(['new'])
469
- const pciDevices = ref<UI_I_SendDataNewPciDevice[]>([])
470
- watch(
471
- () => props.pciDevices,
472
- (newValue) => {
473
- if ((!props.isEdit && !props.isClone) || !newValue) return
474
-
475
- const count = newValue?.length || 0
476
- pciDevicesIndex.value = [...Array(count).keys()]
477
- pciDevices.value = newValue || []
478
- if (props.isEdit) {
479
- pciDevicesType.value = Array(count).fill('edit')
480
- } else if (props.isClone) {
481
- pciDevicesType.value = Array(count).fill('new')
482
- }
483
- },
484
- { immediate: true }
485
- )
486
-
487
- const addPciDevice = (): void => {
488
- const newIndex = (pciDevicesIndex.value.at(-1) ?? -1) + 1
489
- pciDevicesIndex.value.push(newIndex)
490
- pciDevicesType.value.push('new')
491
-
492
- pciDevices.value.push(useDeepCopy(defaultPciDevice))
493
- }
494
- const onRemovePciDevice = (index: number): void => {
495
- const removeIndex = pciDevicesIndex.value.indexOf(index)
496
- pciDevicesIndex.value = pciDevicesIndex.value.filter((item) => item !== index)
497
- pciDevicesType.value = pciDevicesType.value.filter(
498
- (_item, key) => key !== removeIndex
499
- )
500
-
501
- pciDevices.value = pciDevices.value.filter((_pciDevice, key: number) => {
502
- return removeIndex !== key
503
- })
504
-
505
- delete newPciDeviceInvalidKeys.value[index]
506
- delete sendDataNewPciDevices.value[index]
507
- sendData()
508
- }
509
-
510
- const isShowFileModal = ref<boolean>(false)
511
- const onAddDevice = (item: UI_I_DropdownTreeItemChild): void => {
512
- switch (item.value) {
513
- case 1:
514
- addHardDisk()
515
- break
516
- case 2:
517
- isShowFileModal.value = true
518
- break
519
- case 5:
520
- addCdDvdDrive()
521
- break
522
- case 10:
523
- addPciDevice()
524
- break
525
- case 14:
526
- addNetwork()
527
- break
528
- }
529
- }
530
-
531
- const cpuInvalid = ref<boolean>(false)
532
- const sendDataCpu = ref<UI_I_SendDataCpu | null>(null)
533
- const onSendDataCpuMethod = (data: UI_I_SendDataCpu): void => {
534
- sendDataCpu.value = data
535
- sendData()
536
- }
537
- const sendDataMemory = ref<UI_I_SendDataMemory | null>(null)
538
- const onSendDataMemoryMethod = (data: UI_I_SendDataMemory): void => {
539
- sendDataMemory.value = data
540
- sendData()
541
- }
542
- const sendDataNewHardDisk = ref<UI_I_SendDataNewHardDisk[]>([])
543
- const onSendDataNewHardDiskMethod = (
544
- data: UI_I_SendDataNewHardDisk,
545
- index: number
546
- ): void => {
547
- sendDataNewHardDisk.value[index] = data
548
- sendData()
549
- }
550
- const sendDataNewNetwork = ref<UI_I_SendDataNewNetwork[]>([])
551
- const sendDataNewNetworkMethod = (
552
- data: UI_I_SendDataNewNetwork,
553
- index: number
554
- ): void => {
555
- sendDataNewNetwork.value[index] = data
556
- sendData()
557
- }
558
- const sendDataNewCdDvdDrive = ref<UI_I_SendDataNewCdDvdDrive[]>([])
559
- const sendDataNewCdDvdDriveMethod = (
560
- data: UI_I_SendDataNewCdDvdDrive,
561
- index: number
562
- ): void => {
563
- sendDataNewCdDvdDrive.value[index] = data
564
- sendData()
565
- }
566
- const sendDataNewUsbController = ref<string | null>(null)
567
- const onSendDataNewUsbControllerMethod = (data: string): void => {
568
- sendDataNewUsbController.value = data
569
- sendData()
570
- }
571
- const sendDataNewPciDevices = ref<UI_I_SendDataNewPciDevice[]>([])
572
- const onSendDataPciDevicesMethod = (
573
- data: UI_I_SendDataNewPciDevice,
574
- index: number
575
- ): void => {
576
- sendDataNewPciDevices.value[index] = data
577
- sendData()
578
- }
579
- const sendDataVideoCard = ref<UI_I_SendDataVideoCard | null>(null)
580
- const onSendDataVideoCardMethod = (data: UI_I_SendDataVideoCard): void => {
581
- sendDataVideoCard.value = data
582
- sendData()
583
- }
584
-
585
- const sendData = (): void => {
586
- const cpu = sendDataCpu.value
587
- const memory = sendDataMemory.value
588
- const hardDisks = sendDataNewHardDisk.value.flat(2)
589
- const networks = sendDataNewNetwork.value.flat(2)
590
- const cdDvdDrives = sendDataNewCdDvdDrive.value.flat(2)
591
- const pciDevices = sendDataNewPciDevices.value.flat()
592
- const usbController = sendDataNewUsbController.value
593
- const videoCard = sendDataVideoCard.value
594
-
595
- const sendData: UI_I_SendDataVirtualHardware = {
596
- cpu,
597
- memory,
598
- usbController,
599
- pciDevices,
600
- networks,
601
- hardDisks,
602
- cdDvdDrives,
603
- videoCard,
604
- }
605
- emits('send-data', sendData)
606
- }
607
-
608
- const onSetInvalidHardDisk = (invalid: boolean, index: number): void => {
609
- newHardDiskInvalidKeys.value[index] = invalid
610
- }
611
-
612
- const onSetInvalidNetwork = (invalid: boolean, key: number): void => {
613
- newNetworkInvalidKeys.value[key] = invalid
614
- }
615
-
616
- const onSetInvalidPciDevice = (invalid: boolean, key: number): void => {
617
- newPciDeviceInvalidKeys.value[key] = invalid
618
- }
619
-
620
- const memoryInvalid = ref<boolean>(false)
621
- const videoCardInvalid = ref<boolean>(false)
622
- const newHardDiskInvalidKeys = ref<UI_I_InvalidKeys>({})
623
- const newNetworkInvalidKeys = ref<UI_I_InvalidKeys>({})
624
- const newPciDeviceInvalidKeys = ref<UI_I_InvalidKeys>({})
625
-
626
- watch(
627
- [
628
- cpuInvalid,
629
- memoryInvalid,
630
- newHardDiskInvalidKeys,
631
- newNetworkInvalidKeys,
632
- newPciDeviceInvalidKeys,
633
- videoCardInvalid,
634
- ],
635
- () => {
636
- const cpu = cpuInvalid.value ? localization.value.cpu : ''
637
- const memory = memoryInvalid.value ? localization.value.memory : ''
638
- const videoCard = videoCardInvalid.value ? localization.value.videoCard : ''
639
- let newHardDisk = ''
640
- Object.keys(newHardDiskInvalidKeys.value).forEach((key) => {
641
- if (!newHardDiskInvalidKeys.value[+key]) {
642
- return
643
- }
644
-
645
- newHardDisk +=
646
- (newHardDisk ? ', ' : '') +
647
- localization.value.newHardDisk +
648
- ' ' +
649
- (+key + 1)
650
- })
651
- let newNetwork = ''
652
- Object.keys(newNetworkInvalidKeys.value).forEach((key) => {
653
- if (!newNetworkInvalidKeys.value[+key]) {
654
- return
655
- }
656
-
657
- newNetwork +=
658
- (newNetwork ? ', ' : '') +
659
- localization.value.newNetwork +
660
- ' ' +
661
- (+key + 1)
662
- })
663
- // let pciDevice = ''
664
- // Object.keys(newPciDeviceInvalidKeys.value).forEach((key) => {
665
- // if (!newPciDeviceInvalidKeys.value[+key]) {
666
- // return
667
- // }
668
- //
669
- // pciDevice +=
670
- // (pciDevice ? ', ' : '') +
671
- // localization.value.pciDevice +
672
- // ' ' +
673
- // (+key + 1)
674
- // })
675
-
676
- emits('invalid', [cpu, memory, newHardDisk, newNetwork, videoCard])
677
- },
678
- { deep: true }
679
- )
680
-
681
- emits('get-pci-devices')
682
- </script>
683
-
684
- <style scoped lang="scss">
685
- .virtual-hardware {
686
- .content-dropdown {
687
- width: 200px;
688
- }
689
- }
690
- .stack-view {
691
- background-color: var(--block-view-bg-color);
692
- }
693
- </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
+ test-id="add-device-dropdown"
8
+ @select="onAddDevice"
9
+ />
10
+ </div>
11
+
12
+ <div class="clr-component">
13
+ <div class="stack-view">
14
+ <common-vm-actions-common-customize-hardware-virtual-hardware-cpu
15
+ :max-cpus="props.maxCpus"
16
+ :cpu-models="props.cpuModels"
17
+ :cpu="props.cpu"
18
+ :is-edit="props.isEdit"
19
+ :state="props.state"
20
+ :error-validation-fields="props.errorValidationFields"
21
+ :vm-cpu-help-text-second="props.vmCpuHelpTextSecond"
22
+ @send-data="onSendDataCpuMethod"
23
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
24
+ @invalid="cpuInvalid = $event"
25
+ />
26
+ <common-vm-actions-common-customize-hardware-virtual-hardware-memory
27
+ :max-memory="props.maxMemory"
28
+ :is-edit="props.isEdit"
29
+ :memory="props.memory"
30
+ :state="props.state"
31
+ :error-validation-fields="props.errorValidationFields"
32
+ @send-data="onSendDataMemoryMethod"
33
+ @invalid="memoryInvalid = $event"
34
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
35
+ />
36
+ <common-vm-actions-common-customize-hardware-virtual-hardware-new-hard-disk
37
+ v-for="(item, key) in hardDisks"
38
+ :key="hardDisksIndex[key]"
39
+ :index="hardDisksIndex[key]"
40
+ :type="hardDisksType[key]"
41
+ :storage="props.storage"
42
+ :hard-disk="item"
43
+ :error-validation-fields="props.errorValidationFields"
44
+ :get-datastore-table-func="props.getDatastoreTableFunc"
45
+ :datastore="props.datastore"
46
+ :is-edit="props.isEdit"
47
+ :state="props.state"
48
+ @remove="onRemoveHardDisk(hardDisksIndex[key], item)"
49
+ @roll-back="onRollBackHardDisk(hardDisksIndex[key])"
50
+ @send-data="onSendDataNewHardDiskMethod($event, hardDisksIndex[key])"
51
+ @invalid="onSetInvalidHardDisk($event, hardDisksIndex[key])"
52
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
53
+ />
54
+ <common-vm-actions-common-customize-hardware-virtual-hardware-new-network
55
+ v-for="(item, key) in networks"
56
+ :key="networksIndex[key]"
57
+ :index="networksIndex[key]"
58
+ :type="networksType[key]"
59
+ :network="item"
60
+ :networks-table="props.networksTable"
61
+ :error-validation-fields="props.errorValidationFields"
62
+ :is-edit="props.isEdit"
63
+ :state="props.state"
64
+ @remove="onRemoveNetwork(networksIndex[key])"
65
+ @send-data="sendDataNewNetworkMethod($event, networksIndex[key])"
66
+ @invalid="onSetInvalidNetwork($event, networksIndex[key])"
67
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
68
+ @get-networks-table="emits('get-networks-table', $event)"
69
+ />
70
+ <common-vm-actions-common-customize-hardware-virtual-hardware-cd-dvd-drive
71
+ v-for="(item, key) in cdDvdDrives"
72
+ :key="cdDvdDrivesIndex[key]"
73
+ :index="cdDvdDrivesIndex[key]"
74
+ :hard-disks-count="hardDisks.length"
75
+ :type="cdDvdDrivesType[key]"
76
+ :cd-dvd-drive="item"
77
+ :nodes="props.nodes"
78
+ :files="props.files"
79
+ :error-validation-fields="props.errorValidationFields"
80
+ :is-edit="props.isEdit"
81
+ :state="props.state"
82
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
83
+ @get-storage="emits('get-storage', $event)"
84
+ @get-folders-or-files="emits('get-folders-or-files', $event)"
85
+ @get-active-device-child="emits('get-active-device-child', $event)"
86
+ @show-datastore-child="emits('show-datastore-child', $event)"
87
+ @remove="onRemoveCdDvdDrive(cdDvdDrivesIndex[key], item)"
88
+ @roll-back="onRollBackCdDvdDrive(cdDvdDrivesIndex[key])"
89
+ @send-data="
90
+ sendDataNewCdDvdDriveMethod($event, cdDvdDrivesIndex[key])
91
+ "
92
+ />
93
+ <common-vm-actions-common-customize-hardware-virtual-hardware-new-usb-controller
94
+ :usb-controller="props.usbController"
95
+ :is-edit="props.isEdit"
96
+ :state="props.state"
97
+ @send-data="onSendDataNewUsbControllerMethod"
98
+ />
99
+ <template v-if="props.passthroughDevices">
100
+ <common-vm-actions-common-customize-hardware-virtual-hardware-new-pci-device
101
+ v-for="(item, key) in pciDevices"
102
+ :key="pciDevicesIndex[key]"
103
+ :index="pciDevicesIndex[key]"
104
+ :pci-device="item"
105
+ :error-validation-fields="props.errorValidationFields"
106
+ :passthrough-devices="props.passthroughDevices"
107
+ :type="pciDevicesType[key]"
108
+ :is-edit="props.isEdit"
109
+ :state="props.state"
110
+ @remove="onRemovePciDevice(pciDevicesIndex[key])"
111
+ @send-data="
112
+ onSendDataPciDevicesMethod($event, pciDevicesIndex[key])
113
+ "
114
+ @invalid="onSetInvalidPciDevice($event, pciDevicesIndex[key])"
115
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
116
+ />
117
+ </template>
118
+ <common-vm-actions-common-customize-hardware-virtual-hardware-video-card
119
+ :is-edit="props.isEdit"
120
+ :video-card="props.videoCard"
121
+ :error-validation-fields="props.errorValidationFields"
122
+ :state="props.state"
123
+ @send-data="onSendDataVideoCardMethod"
124
+ @invalid="videoCardInvalid = $event"
125
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
126
+ />
127
+ <common-vm-actions-common-customize-hardware-virtual-hardware-other />
128
+ </div>
129
+ </div>
130
+
131
+ <Teleport to="body">
132
+ <common-vm-actions-common-customize-hardware-virtual-hardware-browse-view
133
+ v-if="isShowFileModal"
134
+ :show="isShowFileModal"
135
+ :nodes="props.nodes"
136
+ :files="props.files"
137
+ @submit="onAddExistHardDisk"
138
+ @get-storage="emits('get-storage', $event)"
139
+ @get-folders-or-files="emits('get-folders-or-files', $event)"
140
+ @get-active-device-child="emits('get-active-device-child', $event)"
141
+ @show-datastore-child="emits('show-datastore-child', $event)"
142
+ @hide="isShowFileModal = false"
143
+ />
144
+ </Teleport>
145
+ </div>
146
+ </template>
147
+
148
+ <script setup lang="ts">
149
+ import { UI_I_DatastoreTableItem } from '~/lib/models/store/storage/interfaces'
150
+ import { UI_I_NetworkTableItem } from '~/lib/models/store/network/interfaces'
151
+ import { UI_I_TablePayload } from '~/lib/models/table/interfaces'
152
+ import { UI_I_FolderOrFileTreePayload } from '~/lib/models/store/storage/interfaces'
153
+ import { UI_I_FileTreeNode } from '~/components/lib/models/interfaces'
154
+ import {
155
+ UI_I_SendDataCpu,
156
+ UI_I_SendDataMemory,
157
+ UI_I_SendDataNewHardDisk,
158
+ UI_I_SendDataNewNetwork,
159
+ UI_I_SendDataVideoCard,
160
+ UI_I_InvalidKeys,
161
+ UI_I_SendDataVirtualHardware,
162
+ UI_I_SendDataNewCdDvdDrive,
163
+ // UI_I_HardDisk,
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 {
179
+ API_UI_I_VmEditCpu,
180
+ API_UI_I_VmEditMemory,
181
+ UI_I_PciDevice,
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_SendDataNewPciDevice[]
209
+ passthroughDevices?: UI_I_PciDevice[]
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, props.passthroughDevices)
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
+ provisioned_type?: number // При добавлении существующей
267
+ ): void => {
268
+ const newIndex = (hardDisksIndex.value.at(-1) ?? -1) + 1
269
+ hardDisksIndex.value.push(newIndex)
270
+ hardDisksType.value.push(type)
271
+
272
+ let provisionType = 'thick'
273
+ if (provisioned_type === 1) provisionType = 'thin'
274
+
275
+ hardDisks.value.push({
276
+ create,
277
+ size,
278
+ source,
279
+ attach: true,
280
+ boot_order: 0, // Убираем галочку
281
+ provision_type: provisionType,
282
+ })
283
+ sendData()
284
+ }
285
+ const onAddExistHardDisk = (file: UI_I_FileTreeNode): void => {
286
+ addHardDisk(
287
+ false,
288
+ $binary.bToGb(file.size),
289
+ file.path,
290
+ 'exist',
291
+ file.provisioned_type
292
+ )
293
+ }
294
+ const onRemoveHardDisk = (
295
+ index: number,
296
+ hardDisk: UI_I_SendDataNewHardDisk
297
+ ): void => {
298
+ const removeIndex = hardDisksIndex.value.indexOf(index)
299
+
300
+ if (!hardDisk.create && !hardDisk.attach) {
301
+ hardDisksType.value = hardDisksType.value.map((item, key) => {
302
+ if (key === removeIndex) return 'removed'
303
+ return item
304
+ })
305
+ sendData()
306
+ return
307
+ }
308
+
309
+ hardDisksIndex.value = hardDisksIndex.value.filter((item) => item !== index)
310
+ hardDisksType.value = hardDisksType.value.filter(
311
+ (_item, key) => key !== removeIndex
312
+ )
313
+
314
+ hardDisks.value = hardDisks.value.filter((_hardDisk, key: number) => {
315
+ return removeIndex !== key
316
+ })
317
+
318
+ delete newHardDiskInvalidKeys.value[index]
319
+ delete sendDataNewHardDisk.value[index]
320
+ sendData()
321
+ }
322
+ const onRollBackHardDisk = (index: number): void => {
323
+ const removeIndex = hardDisksIndex.value.indexOf(index)
324
+ hardDisksType.value = hardDisksType.value.map((item, key) => {
325
+ if (key === removeIndex) return 'edit'
326
+ return item
327
+ })
328
+ }
329
+
330
+ const defaultNetwork = {
331
+ network: '',
332
+ net_bridge: '',
333
+ mac: '',
334
+ target: '',
335
+ model: '',
336
+ boot_order: -1,
337
+ }
338
+ const networks = ref<UI_I_SendDataNewNetwork[]>([useDeepCopy(defaultNetwork)])
339
+ const networksType = ref<UI_T_NetworkType[]>(['new'])
340
+ const networksIndex = ref<number[]>([0])
341
+ watch(
342
+ () => props.networks,
343
+ (newValue) => {
344
+ if ((!props.isEdit && !props.isClone) || !newValue) return
345
+
346
+ // networks.value = newValue
347
+ // networksType.value = Array(newValue.length).fill('edit')
348
+ const count = newValue?.length || 0
349
+ networksIndex.value = [...Array(count).keys()]
350
+ networks.value = newValue
351
+ if (props.isEdit) {
352
+ networksType.value = Array(count).fill('edit')
353
+ } else if (props.isClone) {
354
+ networksType.value = Array(count).fill('new')
355
+ }
356
+ },
357
+ { immediate: true }
358
+ )
359
+ const addNetwork = (): void => {
360
+ const index = (networksIndex.value.at(-1) || 0) + 1
361
+ networksIndex.value.push(index)
362
+ networksType.value.push('new')
363
+
364
+ networks.value.push({
365
+ ...useDeepCopy(defaultNetwork),
366
+ boot_order: 0, // Убираем галочку
367
+ })
368
+ }
369
+ const onRemoveNetwork = (index: number): void => {
370
+ const removeIndex = networksIndex.value.indexOf(index)
371
+ networksIndex.value = networksIndex.value.filter((item) => item !== index)
372
+ networksType.value = networksType.value.filter(
373
+ (_item, key) => key !== removeIndex
374
+ )
375
+ networks.value = networks.value.filter(
376
+ (_network, key: number) => removeIndex !== key
377
+ )
378
+
379
+ delete newNetworkInvalidKeys.value[index]
380
+ delete sendDataNewNetwork.value[index]
381
+ sendData()
382
+ }
383
+
384
+ const defaultCdDvdDriver: UI_I_SendDataNewCdDvdDrive = {
385
+ create: false,
386
+ attach: false,
387
+ source: '',
388
+ bus: '',
389
+ device_type: 'cdrom',
390
+ boot_order: -1,
391
+ }
392
+ const cdDvdDrives = ref<UI_I_SendDataNewCdDvdDrive[]>([
393
+ useDeepCopy(defaultCdDvdDriver),
394
+ ])
395
+ const cdDvdDrivesIndex = ref<number[]>([0])
396
+ const cdDvdDrivesType = ref<UI_T_CdDvdType[]>(['new'])
397
+ watch(
398
+ () => props.cdDvdDrives,
399
+ (newValue) => {
400
+ if ((!props.isEdit && !props.isClone) || !newValue) return
401
+
402
+ // cdDvdDrives.value = newValue
403
+ // cdDvdDrivesType.value = Array(newValue.length).fill('edit')
404
+ const count = newValue?.length || 0
405
+ cdDvdDrivesIndex.value = [...Array(count).keys()]
406
+ cdDvdDrives.value = newValue
407
+ if (props.isEdit) {
408
+ cdDvdDrivesType.value = Array(count).fill('edit')
409
+ } else if (props.isClone) {
410
+ cdDvdDrivesType.value = Array(count).fill('new')
411
+ }
412
+ },
413
+ { immediate: true }
414
+ )
415
+ const addCdDvdDrive = (): void => {
416
+ const value = (cdDvdDrivesIndex.value.at(-1) || 0) + 1
417
+ cdDvdDrivesIndex.value.push(value)
418
+ cdDvdDrivesType.value.push('new')
419
+ cdDvdDrives.value.push({
420
+ ...useDeepCopy(defaultCdDvdDriver),
421
+ attach: true,
422
+ boot_order: 0, // Убираем галочку
423
+ })
424
+ }
425
+ const onRemoveCdDvdDrive = (
426
+ index: number,
427
+ cdDvdDrive: UI_I_SendDataNewCdDvdDrive
428
+ ): void => {
429
+ const removeIndex = cdDvdDrivesIndex.value.indexOf(index)
430
+
431
+ // if (!cdDvdDrive.create && !cdDvdDrive.attach) {
432
+ if (cdDvdDrivesType.value[index] === 'edit' && !cdDvdDrive.attach) {
433
+ cdDvdDrivesType.value = cdDvdDrivesType.value.map((item, key) => {
434
+ if (key === removeIndex) return 'removed'
435
+ return item
436
+ })
437
+ sendData()
438
+ return
439
+ }
440
+
441
+ cdDvdDrivesIndex.value = cdDvdDrivesIndex.value.filter(
442
+ (cdDvdDrive) => cdDvdDrive !== index
443
+ )
444
+ cdDvdDrivesType.value = cdDvdDrivesType.value.filter(
445
+ (_item, key) => key !== index
446
+ )
447
+ cdDvdDrives.value = cdDvdDrives.value.filter(
448
+ (_cdDvdDrive, key: number) => removeIndex !== key
449
+ )
450
+
451
+ delete sendDataNewCdDvdDrive.value[index]
452
+ sendData()
453
+ }
454
+ const onRollBackCdDvdDrive = (index: number): void => {
455
+ const removeIndex = cdDvdDrivesIndex.value.indexOf(index)
456
+ cdDvdDrivesType.value = cdDvdDrivesType.value.map((item, key) => {
457
+ if (key === removeIndex) return 'edit'
458
+ return item
459
+ })
460
+ }
461
+
462
+ const defaultPciDevice: UI_I_SendDataNewPciDevice = {
463
+ address: '',
464
+ vendor_name: '',
465
+ class_name: 'cdrom',
466
+ device_name: 'cdrom',
467
+ }
468
+ const pciDevicesIndex = ref<number[]>([0])
469
+ const pciDevicesType = ref<('new' | 'edit' | 'removed')[]>(['new'])
470
+ const pciDevices = ref<UI_I_SendDataNewPciDevice[]>([])
471
+ watch(
472
+ () => props.pciDevices,
473
+ (newValue) => {
474
+ if ((!props.isEdit && !props.isClone) || !newValue) return
475
+
476
+ const count = newValue?.length || 0
477
+ pciDevicesIndex.value = [...Array(count).keys()]
478
+ pciDevices.value = newValue || []
479
+ if (props.isEdit) {
480
+ pciDevicesType.value = Array(count).fill('edit')
481
+ } else if (props.isClone) {
482
+ pciDevicesType.value = Array(count).fill('new')
483
+ }
484
+ },
485
+ { immediate: true }
486
+ )
487
+
488
+ const addPciDevice = (): void => {
489
+ const newIndex = (pciDevicesIndex.value.at(-1) ?? -1) + 1
490
+ pciDevicesIndex.value.push(newIndex)
491
+ pciDevicesType.value.push('new')
492
+
493
+ pciDevices.value.push(useDeepCopy(defaultPciDevice))
494
+ }
495
+ const onRemovePciDevice = (index: number): void => {
496
+ const removeIndex = pciDevicesIndex.value.indexOf(index)
497
+ pciDevicesIndex.value = pciDevicesIndex.value.filter((item) => item !== index)
498
+ pciDevicesType.value = pciDevicesType.value.filter(
499
+ (_item, key) => key !== removeIndex
500
+ )
501
+
502
+ pciDevices.value = pciDevices.value.filter((_pciDevice, key: number) => {
503
+ return removeIndex !== key
504
+ })
505
+
506
+ delete newPciDeviceInvalidKeys.value[index]
507
+ delete sendDataNewPciDevices.value[index]
508
+ sendData()
509
+ }
510
+
511
+ const isShowFileModal = ref<boolean>(false)
512
+ const onAddDevice = (item: UI_I_DropdownTreeItemChild): void => {
513
+ switch (item.value) {
514
+ case 1:
515
+ addHardDisk()
516
+ break
517
+ case 2:
518
+ isShowFileModal.value = true
519
+ break
520
+ case 5:
521
+ addCdDvdDrive()
522
+ break
523
+ case 10:
524
+ addPciDevice()
525
+ break
526
+ case 14:
527
+ addNetwork()
528
+ break
529
+ }
530
+ }
531
+
532
+ const cpuInvalid = ref<boolean>(false)
533
+ const sendDataCpu = ref<UI_I_SendDataCpu | null>(null)
534
+ const onSendDataCpuMethod = (data: UI_I_SendDataCpu): void => {
535
+ sendDataCpu.value = data
536
+ sendData()
537
+ }
538
+ const sendDataMemory = ref<UI_I_SendDataMemory | null>(null)
539
+ const onSendDataMemoryMethod = (data: UI_I_SendDataMemory): void => {
540
+ sendDataMemory.value = data
541
+ sendData()
542
+ }
543
+ const sendDataNewHardDisk = ref<UI_I_SendDataNewHardDisk[]>([])
544
+ const onSendDataNewHardDiskMethod = (
545
+ data: UI_I_SendDataNewHardDisk,
546
+ index: number
547
+ ): void => {
548
+ sendDataNewHardDisk.value[index] = data
549
+ sendData()
550
+ }
551
+ const sendDataNewNetwork = ref<UI_I_SendDataNewNetwork[]>([])
552
+ const sendDataNewNetworkMethod = (
553
+ data: UI_I_SendDataNewNetwork,
554
+ index: number
555
+ ): void => {
556
+ sendDataNewNetwork.value[index] = data
557
+ sendData()
558
+ }
559
+ const sendDataNewCdDvdDrive = ref<UI_I_SendDataNewCdDvdDrive[]>([])
560
+ const sendDataNewCdDvdDriveMethod = (
561
+ data: UI_I_SendDataNewCdDvdDrive,
562
+ index: number
563
+ ): void => {
564
+ sendDataNewCdDvdDrive.value[index] = data
565
+ sendData()
566
+ }
567
+ const sendDataNewUsbController = ref<string | null>(null)
568
+ const onSendDataNewUsbControllerMethod = (data: string): void => {
569
+ sendDataNewUsbController.value = data
570
+ sendData()
571
+ }
572
+ const sendDataNewPciDevices = ref<UI_I_SendDataNewPciDevice[]>([])
573
+ const onSendDataPciDevicesMethod = (
574
+ data: UI_I_SendDataNewPciDevice,
575
+ index: number
576
+ ): void => {
577
+ sendDataNewPciDevices.value[index] = data
578
+ sendData()
579
+ }
580
+ const sendDataVideoCard = ref<UI_I_SendDataVideoCard | null>(null)
581
+ const onSendDataVideoCardMethod = (data: UI_I_SendDataVideoCard): void => {
582
+ sendDataVideoCard.value = data
583
+ sendData()
584
+ }
585
+
586
+ const sendData = (): void => {
587
+ const cpu = sendDataCpu.value
588
+ const memory = sendDataMemory.value
589
+ const hardDisks = sendDataNewHardDisk.value.flat(2)
590
+ const networks = sendDataNewNetwork.value.flat(2)
591
+ const cdDvdDrives = sendDataNewCdDvdDrive.value.flat(2)
592
+ const pciDevices = sendDataNewPciDevices.value.flat()
593
+ const usbController = sendDataNewUsbController.value
594
+ const videoCard = sendDataVideoCard.value
595
+
596
+ const sendData: UI_I_SendDataVirtualHardware = {
597
+ cpu,
598
+ memory,
599
+ usbController,
600
+ pciDevices,
601
+ networks,
602
+ hardDisks,
603
+ cdDvdDrives,
604
+ videoCard,
605
+ }
606
+ emits('send-data', sendData)
607
+ }
608
+
609
+ const onSetInvalidHardDisk = (invalid: boolean, index: number): void => {
610
+ newHardDiskInvalidKeys.value[index] = invalid
611
+ }
612
+
613
+ const onSetInvalidNetwork = (invalid: boolean, key: number): void => {
614
+ newNetworkInvalidKeys.value[key] = invalid
615
+ }
616
+
617
+ const onSetInvalidPciDevice = (invalid: boolean, key: number): void => {
618
+ newPciDeviceInvalidKeys.value[key] = invalid
619
+ }
620
+
621
+ const memoryInvalid = ref<boolean>(false)
622
+ const videoCardInvalid = ref<boolean>(false)
623
+ const newHardDiskInvalidKeys = ref<UI_I_InvalidKeys>({})
624
+ const newNetworkInvalidKeys = ref<UI_I_InvalidKeys>({})
625
+ const newPciDeviceInvalidKeys = ref<UI_I_InvalidKeys>({})
626
+
627
+ watch(
628
+ [
629
+ cpuInvalid,
630
+ memoryInvalid,
631
+ newHardDiskInvalidKeys,
632
+ newNetworkInvalidKeys,
633
+ newPciDeviceInvalidKeys,
634
+ videoCardInvalid,
635
+ ],
636
+ () => {
637
+ const cpu = cpuInvalid.value ? localization.value.cpu : ''
638
+ const memory = memoryInvalid.value ? localization.value.memory : ''
639
+ const videoCard = videoCardInvalid.value ? localization.value.videoCard : ''
640
+ let newHardDisk = ''
641
+ Object.keys(newHardDiskInvalidKeys.value).forEach((key) => {
642
+ if (!newHardDiskInvalidKeys.value[+key]) {
643
+ return
644
+ }
645
+
646
+ newHardDisk +=
647
+ (newHardDisk ? ', ' : '') +
648
+ localization.value.newHardDisk +
649
+ ' ' +
650
+ (+key + 1)
651
+ })
652
+ let newNetwork = ''
653
+ Object.keys(newNetworkInvalidKeys.value).forEach((key) => {
654
+ if (!newNetworkInvalidKeys.value[+key]) {
655
+ return
656
+ }
657
+
658
+ newNetwork +=
659
+ (newNetwork ? ', ' : '') +
660
+ localization.value.newNetwork +
661
+ ' ' +
662
+ (+key + 1)
663
+ })
664
+ // let pciDevice = ''
665
+ // Object.keys(newPciDeviceInvalidKeys.value).forEach((key) => {
666
+ // if (!newPciDeviceInvalidKeys.value[+key]) {
667
+ // return
668
+ // }
669
+ //
670
+ // pciDevice +=
671
+ // (pciDevice ? ', ' : '') +
672
+ // localization.value.pciDevice +
673
+ // ' ' +
674
+ // (+key + 1)
675
+ // })
676
+
677
+ emits('invalid', [cpu, memory, newHardDisk, newNetwork, videoCard])
678
+ },
679
+ { deep: true }
680
+ )
681
+
682
+ emits('get-pci-devices')
683
+ </script>
684
+
685
+ <style scoped lang="scss">
686
+ .virtual-hardware {
687
+ .content-dropdown {
688
+ width: 200px;
689
+ }
690
+ }
691
+ .stack-view {
692
+ background-color: var(--block-view-bg-color);
693
+ }
694
+ </style>