bfg-common 1.3.403 → 1.3.404

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