bfg-common 1.5.679 → 1.5.682

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 (117) hide show
  1. package/CODE_STYLE.md +109 -109
  2. package/assets/img/icons/icons-sprite-dark-3.svg +227 -227
  3. package/assets/img/icons/icons-sprite-dark-5.svg +488 -488
  4. package/assets/img/icons/icons-sprite-light-3.svg +227 -227
  5. package/assets/img/icons/icons-sprite-light-5.svg +488 -488
  6. package/components/atoms/TheIcon3.vue +50 -50
  7. package/components/atoms/collapse/CollapseNav.vue +170 -170
  8. package/components/atoms/perPage/PerPage.vue +58 -58
  9. package/components/atoms/table/dataGrid/DataGrid.vue +1718 -1718
  10. package/components/atoms/table/dataGrid/DataGridPagination.vue +97 -97
  11. package/components/atoms/table/dataGrid/lib/config/settingsTable.ts +94 -94
  12. package/components/atoms/table/dataGrid/lib/utils/export.ts +16 -16
  13. package/components/common/backup/storage/actions/add/lib/utils.ts +51 -51
  14. package/components/common/browse/blocks/contents/filesNew/Skeleton.vue +18 -18
  15. package/components/common/diagramMain/modals/lib/config/vCenterModal.ts +48 -48
  16. package/components/common/diagramMain/port/Port.vue +580 -580
  17. package/components/common/layout/theHeader/TheHeaderNew.vue +315 -315
  18. package/components/common/layout/theHeader/TheHeaderOld.vue +262 -262
  19. package/components/common/layout/theHeader/helpMenu/About.vue +79 -79
  20. package/components/common/layout/theHeader/helpMenu/aboutOld/AboutOld.vue +79 -79
  21. package/components/common/layout/theHeader/userMenu/modals/changePassword/ChangePassword.vue +93 -93
  22. package/components/common/layout/theHeader/userMenu/modals/changePassword/New.vue +193 -193
  23. package/components/common/layout/theHeader/userMenu/modals/preferences/PreferencesOld.vue +144 -144
  24. package/components/common/layout/theHeader/userMenu/modals/preferences/lib/models/types.ts +7 -7
  25. package/components/common/layout/theHeader/userMenu/modals/preferences/security/Old.vue +216 -216
  26. package/components/common/layout/theHeader/userMenu/modals/preferences/security/Security.vue +31 -31
  27. package/components/common/pages/backups/DetailView.vue +52 -52
  28. package/components/common/pages/backups/lib/models/interfaces.ts +36 -36
  29. package/components/common/pages/backups/modals/Modals.vue +243 -243
  30. package/components/common/pages/backups/modals/createBackup/configuration/maxBandwidth/lib/config/options.ts +6 -6
  31. package/components/common/pages/backups/modals/createBackup/lib/config/readyToCompleteOptions.ts +69 -69
  32. package/components/common/pages/backups/modals/lib/config/restore.ts +115 -115
  33. package/components/common/pages/backups/modals/lib/models/interfaces.ts +186 -186
  34. package/components/common/pages/backups/modals/restore/name/lib/models/interfaces.ts +6 -6
  35. package/components/common/pages/home/lib/models/interfaces.ts +48 -48
  36. package/components/common/pages/home/widgets/hosts/Hosts.vue +27 -27
  37. package/components/common/pages/home/widgets/hosts/lib/config/items.ts +23 -23
  38. package/components/common/pages/home/widgets/vms/VmsOld.vue +35 -35
  39. package/components/common/pages/home/widgets/vms/lib/config/items.ts +19 -19
  40. package/components/common/pages/scheduledTasks/lib/utils/utils.ts +84 -84
  41. package/components/common/qr/Qr.vue +57 -57
  42. package/components/common/readyToComplete/ReadyToComplete.vue +17 -17
  43. package/components/common/select/radio/RadioGroup.vue +137 -137
  44. package/components/common/spiceConsole/Drawer.vue +420 -420
  45. package/components/common/spiceConsole/SpiceConsole.vue +184 -184
  46. package/components/common/spiceConsole/lib/models/interfaces.ts +5 -5
  47. package/components/common/tools/Actions.vue +207 -207
  48. package/components/common/treeView/TreeView.vue +52 -52
  49. package/components/common/vm/actions/add/New.vue +1 -1
  50. package/components/common/vm/actions/add/Old.vue +1 -1
  51. package/components/common/vm/actions/clone/lib/config/steps.ts +295 -295
  52. package/components/common/vm/actions/clone/new/New.vue +438 -438
  53. package/components/common/vm/actions/common/customizeHardware/virtualHardware/VirtualHardware.vue +698 -698
  54. package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/shares/lib/config/options.ts +28 -28
  55. package/components/common/vm/actions/common/customizeHardware/virtualHardware/memory/Memory.vue +283 -283
  56. package/components/common/vm/actions/common/customizeHardware/virtualHardware/newHardDisk/NewHardDisk.vue +489 -489
  57. package/components/common/vm/actions/common/customizeHardware/vmoptions/bootOptions/order/Order.vue +156 -156
  58. package/components/common/vm/actions/common/select/compatibility/Old.vue +107 -107
  59. package/components/common/vm/actions/common/select/createType/lib/models/interfaces.ts +5 -5
  60. package/components/common/vm/actions/common/select/options/New.vue +264 -264
  61. package/components/common/vm/actions/common/select/options/Old.vue +109 -110
  62. package/components/common/vm/actions/common/select/options/Options.vue +58 -58
  63. package/components/common/vm/actions/common/select/storage/Old.vue +125 -125
  64. package/components/common/vm/actions/common/select/storage/new/New.vue +311 -311
  65. package/components/common/vm/actions/common/select/storage/new/lib/models/interfaces.ts +5 -5
  66. package/components/common/vm/actions/common/select/storage/new/lib/utils/utils.ts +21 -21
  67. package/components/common/vm/actions/common/select/template/old/Old.vue +50 -50
  68. package/components/common/vm/actions/editSettings/new/Skeleton.vue +88 -88
  69. package/components/common/wizards/common/compatibility/Compatibility.vue +35 -35
  70. package/components/common/wizards/common/compatibility/New.vue +99 -99
  71. package/components/common/wizards/common/compatibility/Old.vue +53 -53
  72. package/components/common/wizards/common/steps/computeResource/New.vue +93 -93
  73. package/components/common/wizards/common/steps/name/Name.vue +178 -178
  74. package/components/common/wizards/common/steps/name/New.vue +221 -221
  75. package/components/common/wizards/common/steps/name/Old.vue +121 -121
  76. package/components/common/wizards/common/steps/name/lib/models/interfaces.ts +4 -4
  77. package/components/common/wizards/common/steps/name/location/New.vue +40 -40
  78. package/components/common/wizards/datastore/add/Add.vue +228 -228
  79. package/components/common/wizards/datastore/add/lib/utils.ts +85 -85
  80. package/components/common/wizards/datastore/add/steps/typeMode/lib/config/typeOptions.ts +43 -43
  81. package/composables/useAppVersion.ts +21 -21
  82. package/composables/useEnvLanguage.ts +22 -22
  83. package/composables/useLocal.ts +6 -6
  84. package/composables/useLocalCommon.ts +39 -39
  85. package/lib/models/enums.ts +1 -65
  86. package/package.json +1 -1
  87. package/plugins/console.ts +21 -21
  88. package/plugins/mouse.ts +21 -21
  89. package/plugins/panelStates.ts +70 -70
  90. package/plugins/text.ts +59 -59
  91. package/public/spice-console/application/clientgui.js +854 -854
  92. package/public/spice-console/application/packetfactory.js +211 -211
  93. package/public/spice-console/application/virtualmouse.js +147 -147
  94. package/public/spice-console/lib/images/bitmap.js +203 -203
  95. package/public/spice-console/network/spicechannel.js +440 -440
  96. package/public/spice-console/process/cursorprocess.js +128 -128
  97. package/public/spice-console/process/inputprocess.js +227 -227
  98. package/public/spice-console/process/mainprocess.js +212 -212
  99. package/public/spice-console/run.js +210 -210
  100. package/store/main/mutations.ts +7 -7
  101. package/store/main/state.ts +7 -7
  102. package/store/tasks/actions.ts +165 -165
  103. package/store/tasks/mappers/recentTasks.ts +123 -123
  104. package/store/tasks/mutations.ts +82 -82
  105. package/components/common/layout/bottomPanel/BottomPanel.vue +0 -68
  106. package/components/common/layout/bottomPanel/New.vue +0 -227
  107. package/components/common/layout/bottomPanel/Old.vue +0 -144
  108. package/components/common/layout/bottomPanel/lib/config/statusFilter.ts +0 -19
  109. package/components/common/layout/bottomPanel/lib/models/types.ts +0 -1
  110. package/components/common/layout/bottomPanel/recentTasks/RecentTasks.vue +0 -49
  111. package/components/common/layout/bottomPanel/recentTasks/lib/models/interfaces.ts +0 -14
  112. package/components/common/layout/bottomPanel/recentTasks/new/New.vue +0 -428
  113. package/components/common/layout/bottomPanel/recentTasks/new/lib/config/config.ts +0 -259
  114. package/components/common/layout/bottomPanel/recentTasks/old/Old.vue +0 -277
  115. package/components/common/layout/bottomPanel/recentTasks/old/lib/config/recentTaskTable.ts +0 -240
  116. package/components/common/layout/bottomPanel/recentTasks/old/lib/config/tableKeys.ts +0 -15
  117. package/components/common/layout/bottomPanel/recentTasks/old/lib/models/types.ts +0 -14
@@ -1,698 +1,698 @@
1
- <template>
2
- <component
3
- :is="currentComponent"
4
- v-model="model"
5
- v-model:cpu-invalid="cpuInvalid"
6
- v-model:memory-invalid="memoryInvalid"
7
- v-model:video-card-invalid="videoCardInvalid"
8
- :nodes="props.nodes"
9
- :files="props.files"
10
- :is-edit="props.isEdit"
11
- :storage="props.storage"
12
- :storage-free="storageFree"
13
- :project="props.project"
14
- :max-memory="props.maxMemory"
15
- :cpu-models="props.cpuModels"
16
- :datastore="props.datastore"
17
- :is-datastore-loading="props.isDatastoreLoading"
18
- :networks-type="networksType"
19
- :networks-table="props.networksTable"
20
- :dropdown-items="dropdownItems"
21
- :hard-disks-type="hardDisksType"
22
- :networks-index="networksIndex"
23
- :hard-disks-index="hardDisksIndex"
24
- :pci-devices-type="pciDevicesType"
25
- :is-show-file-modal="isShowFileModal"
26
- :pci-devices-index="pciDevicesIndex"
27
- :cd-dvd-drives-type="cdDvdDrivesType"
28
- :cd-dvd-drives-index="cdDvdDrivesIndex"
29
- :error-validation-fields="errorValidationFields"
30
- :get-datastore-table-func="getDatastoreTableFunc"
31
- :state="state"
32
- :video-card="videoCard"
33
- :pci-devices="pciDevicesLocal"
34
- :guest-machine-type="guestMachineType"
35
- :passthrough-devices="passthroughDevices"
36
- :mediated-devices="mediatedDevices"
37
- :vm-cpu-help-text-second="vmCpuHelpTextSecond"
38
- :compute-resource="props.computeResource"
39
- :compatibility-info="props.compatibilityInfo"
40
- :network-value-prop="networkValueProp"
41
- @add-device="onAddDevice"
42
- @get-storage="emits('get-storage', $event)"
43
- @remove-network="onRemoveNetwork"
44
- @hide-file-modal="isShowFileModal = false"
45
- @remove-hard-disk="onRemoveHardDisk(...$event)"
46
- @remove-pci-device="onRemovePciDevice"
47
- @get-networks-table="emits('get-networks-table', $event)"
48
- @add-exist-hard-disk="onAddExistHardDisk"
49
- @roll-back-hard-disk="onRollBackHardDisk"
50
- @set-invalid-network="onSetInvalidNetwork(...$event)"
51
- @remove-cd-dvd-drive="onRemoveCdDvdDrive(...$event)"
52
- @show-datastore-child="emits('show-datastore-child', $event)"
53
- @get-folders-or-files="emits('get-folders-or-files', $event)"
54
- @set-invalid-hard-disk="onSetInvalidHardDisk(...$event)"
55
- @remove-error-by-title="emits('remove-error-by-title', $event)"
56
- @roll-back-cd-dvd-drive="onRollBackCdDvdDrive"
57
- @set-invalid-pci-device="onSetInvalidPciDevice(...$event)"
58
- @get-active-device-child="emits('get-active-device-child', $event)"
59
- @send-data-pci-devices-method="onSendDataPciDevicesMethod(...$event)"
60
- @send-data-new-hard-disk-method="onSendDataNewHardDiskMethod(...$event)"
61
- @send-data-new-cd-dvd-drive-method="sendDataNewCdDvdDriveMethod(...$event)"
62
- />
63
- </template>
64
-
65
- <script setup lang="ts">
66
- import type { UI_T_Project } from '~/lib/models/types'
67
- import type { UI_I_DatastoreTableItem } from '~/lib/models/store/storage/interfaces'
68
- import type { UI_I_NetworkTableItem } from '~/lib/models/store/network/interfaces'
69
- import type { UI_I_TablePayload } from '~/lib/models/table/interfaces'
70
- import type { UI_I_FolderOrFileTreePayload } from '~/lib/models/store/storage/interfaces'
71
- import type { UI_I_FileTreeNode } from '~/components/lib/models/interfaces'
72
- import type {
73
- UI_I_SendDataNewHardDisk,
74
- UI_I_SendDataVideoCard,
75
- UI_I_InvalidKeys,
76
- UI_I_SendDataNewCdDvdDrive,
77
- // UI_I_HardDisk,
78
- UI_I_SendDataNewPciDevice,
79
- } from '~/components/common/vm/actions/common/customizeHardware/virtualHardware/lib/models/interfaces'
80
- import type { UI_I_ErrorValidationField } from '~/lib/models/store/interfaces'
81
- import type {
82
- UI_T_HardDiskType,
83
- UI_T_NetworkType,
84
- UI_T_CdDvdType,
85
- } from '~/components/common/vm/actions/common/customizeHardware/virtualHardware/lib/models/types'
86
- import type { UI_I_OptionItem } from '~/components/atoms/lib/models/interfaces'
87
- import type {
88
- UI_I_DropdownTreeItem,
89
- UI_I_DropdownTreeItemChild,
90
- } from '~/components/atoms/dropdown/tree/lib/models/interfaces'
91
- import type { UI_I_Localization } from '~/lib/models/interfaces'
92
- import type {
93
- UI_I_MediatedDevice,
94
- UI_I_PciDevice,
95
- } from '~/lib/models/store/vm/interfaces'
96
- import type { UI_I_TreeNode } from '~/components/common/recursionTree/lib/models/interfaces'
97
- import type { UI_I_CreateVmData } from '~/components/common/vm/actions/common/lib/models/interfaces'
98
- import { dropdownItemsFunc } from './lib/config/dropdownItems'
99
-
100
- const model = defineModel<UI_I_CreateVmData>({ required: true })
101
-
102
- const props = withDefaults(
103
- defineProps<{
104
- storage: UI_I_DatastoreTableItem | null
105
- cpuModels: UI_I_OptionItem[]
106
- maxMemory: number
107
- isEdit: boolean
108
- isClone: boolean
109
- errorValidationFields: UI_I_ErrorValidationField[]
110
- nodes: UI_I_FileTreeNode[]
111
- files: UI_I_FileTreeNode[]
112
- networksTable: UI_I_NetworkTableItem[]
113
- getDatastoreTableFunc: (payload: UI_I_TablePayload) => Promise<void>
114
- datastore: UI_I_DatastoreTableItem[]
115
- isDatastoreLoading: boolean
116
- project: UI_T_Project
117
- state?: string | number
118
- vmCpuHelpTextSecond?: string
119
- hardDisks?: UI_I_SendDataNewHardDisk[] | null
120
- cdDvdDrives?: UI_I_SendDataNewCdDvdDrive[] | null
121
- videoCard?: UI_I_SendDataVideoCard
122
- pciDevices?: UI_I_SendDataNewPciDevice[]
123
- passthroughDevices?: UI_I_PciDevice[]
124
- mediatedDevices?: UI_I_MediatedDevice[]
125
- guestMachineType?: UI_I_OptionItem | null
126
- computeResource?: UI_I_TreeNode | null
127
- compatibilityInfo?: string
128
- }>(),
129
- {
130
- state: undefined,
131
- vmCpuHelpTextSecond: undefined,
132
- hardDisks: undefined,
133
- cdDvdDrives: undefined,
134
- videoCard: undefined,
135
- pciDevices: undefined,
136
- passthroughDevices: undefined,
137
- mediatedDevices: undefined,
138
- guestMachineType: undefined,
139
- computeResource: undefined,
140
- compatibilityInfo: undefined,
141
- }
142
- )
143
- const emits = defineEmits<{
144
- (event: 'invalid', value: string[]): void
145
- (event: 'get-storage', value: UI_I_TablePayload): void
146
- (event: 'get-folders-or-files', value: UI_I_FolderOrFileTreePayload): void
147
- (event: 'get-active-device-child', value: UI_I_FileTreeNode): void
148
- (event: 'show-datastore-child', value: UI_I_FileTreeNode): void
149
- (event: 'remove-error-by-title', value: string): void
150
- (event: 'get-networks-table', value: UI_I_TablePayload): void
151
- (event: 'get-pci-devices'): void
152
- }>()
153
-
154
- const { $store, $binary }: any = useNuxtApp()
155
- const isNewView = computed<boolean>(() => $store.getters['main/getIsNewView'])
156
- const currentComponent = computed(() =>
157
- isNewView.value
158
- ? defineAsyncComponent(() => import('./New.vue'))
159
- : defineAsyncComponent(() => import('./Old.vue'))
160
- )
161
-
162
- const localization = computed<UI_I_Localization>(() => useLocal())
163
-
164
- const dropdownItems = computed<UI_I_DropdownTreeItem[]>(() =>
165
- dropdownItemsFunc(
166
- localization.value,
167
- props.state,
168
- props.passthroughDevices,
169
- props.mediatedDevices
170
- )
171
- )
172
-
173
- const hardDisksIndex = ref<number[]>([0])
174
- const hardDisksType = ref<UI_T_HardDiskType[]>(['new'])
175
- // const hardDisksLocal = ref<UI_I_SendDataNewHardDisk[]>([
176
- // {
177
- // create: true,
178
- // size: 90,
179
- // source: '',
180
- // boot_order: -1,
181
- // },
182
- // ])
183
- if (!model.value.disk_devices?.length) {
184
- hardDisksType.value = []
185
- hardDisksIndex.value = []
186
- } else {
187
- model.value.disk_devices
188
- .filter((disk) => disk.device_type !== 'cdrom')
189
- .forEach((_disk, _index, array) => {
190
- if (!props.isEdit && !props.isClone) return
191
-
192
- const count = array.length
193
- hardDisksIndex.value = [...Array(count).keys()]
194
- if (props.isEdit) {
195
- hardDisksType.value = Array(count).fill('edit')
196
- } else if (props.isClone) {
197
- hardDisksType.value = Array(count).fill('clone')
198
- }
199
- })
200
- }
201
-
202
- // watch(
203
- // () => props.hardDisks,
204
- // (newValue) => {
205
- // if ((!props.isEdit && !props.isClone) || !newValue) return
206
- //
207
- // const count = newValue?.length || 0
208
- // hardDisksIndex.value = [...Array(count).keys()]
209
- // hardDisksLocal.value = newValue
210
- // if (props.isEdit) {
211
- // hardDisksType.value = Array(count).fill('edit')
212
- // } else if (props.isClone) {
213
- // hardDisksType.value = Array(count).fill('clone')
214
- // hardDisksLocal.value = newValue.map((hardDisk) => {
215
- // hardDisk.create = true
216
- // return hardDisk
217
- // })
218
- // }
219
- // },
220
- // { immediate: true }
221
- // )
222
-
223
- const getDisksSize = (): number => {
224
- return model.value.disk_devices.reduce(
225
- (acum, disk) => (acum += disk.size || 0),
226
- 0
227
- ) || 0
228
- }
229
- const initialDisksSize = getDisksSize()
230
- const storageFree = computed<number>(() => {
231
- if (!props.storage) return 0
232
- const free = (props.storage.capacity.free_mb || props.storage.free) as number // TODO fix
233
-
234
- const disksSize = getDisksSize()
235
-
236
- return free + initialDisksSize - (disksSize - initialDisksSize)
237
- })
238
-
239
- const addHardDisk = (
240
- create = true,
241
- size = 92_160, // 90GB
242
- source = '',
243
- type: UI_T_HardDiskType = 'new',
244
- provisioned_type?: number // При добавлении существующей
245
- ): void => {
246
- const newIndex = (hardDisksIndex.value.at(-1) ?? -1) + 1
247
- hardDisksIndex.value.push(newIndex)
248
- hardDisksType.value.push(type)
249
-
250
- let provisionType = 'thick'
251
- if (provisioned_type === 1) provisionType = 'thin'
252
-
253
- model.value.disk_devices = [
254
- ...model.value.disk_devices.filter((disk) => disk.device_type !== 'cdrom'),
255
- // {
256
- // create,
257
- // size,
258
- // source,
259
- // attach: true,
260
- // boot_order: 0, // Убираем галочку
261
- // provision_type: provisionType,
262
- // },
263
- {
264
- create,
265
- size,
266
- source,
267
- bus: 'virtio',
268
- storage_id: '',
269
- provision_type: 'thick',
270
- disk_mode: 'dependent',
271
- boot_order: 0, // Убираем галочку
272
- device_type: 'disk',
273
- sharing: false,
274
- shares: 0,
275
- cache: 'none',
276
- io: '',
277
- limit_iops: 0,
278
- attach: true,
279
- },
280
- ...model.value.disk_devices.filter((disk) => disk.device_type === 'cdrom'),
281
- ]
282
- // hardDisksLocal.value.push({
283
- // create,
284
- // size,
285
- // source,
286
- // attach: true,
287
- // boot_order: 0, // Убираем галочку
288
- // provision_type: provisionType,
289
- // })
290
- }
291
- const onAddExistHardDisk = (file: UI_I_FileTreeNode): void => {
292
- addHardDisk(
293
- false,
294
- $binary.bToMb(file.size),
295
- file.path,
296
- 'exist',
297
- file.provisioned_type
298
- )
299
- }
300
- const onRemoveHardDisk = (
301
- index: number,
302
- hardDisk: UI_I_SendDataNewHardDisk
303
- ): void => {
304
- const removeIndex = hardDisksIndex.value.indexOf(index)
305
-
306
- if (!hardDisk.create && !hardDisk.attach) {
307
- hardDisksType.value = hardDisksType.value.map((item, key) => {
308
- if (key === removeIndex) return 'removed'
309
- return item
310
- })
311
- return
312
- }
313
-
314
- hardDisksIndex.value = hardDisksIndex.value.filter((item) => item !== index)
315
- hardDisksType.value = hardDisksType.value.filter(
316
- (_item, key) => key !== removeIndex
317
- )
318
-
319
- model.value.disk_devices = model.value.disk_devices.filter(
320
- (_hardDisk, key: number) => {
321
- return removeIndex !== key
322
- }
323
- )
324
- // hardDisksLocal.value = hardDisksLocal.value.filter(
325
- // (_hardDisk, key: number) => {
326
- // return removeIndex !== key
327
- // }
328
- // )
329
-
330
- delete newHardDiskInvalidKeys.value[index]
331
- }
332
- const onRollBackHardDisk = (index: number): void => {
333
- const removeIndex = hardDisksIndex.value.indexOf(index)
334
- hardDisksType.value = hardDisksType.value.map((item, key) => {
335
- if (key === removeIndex) return 'edit'
336
- return item
337
- })
338
- }
339
-
340
- const networkValueProp = props.project === 'sphere' ? 'network' : 'net_bridge'
341
- const networksType = ref<UI_T_NetworkType[]>(['new'])
342
- const networksIndex = ref<number[]>([0])
343
- if (!model.value.network_devices?.length) {
344
- networksType.value = []
345
- networksIndex.value = []
346
- } else {
347
- model.value.network_devices.forEach(() => {
348
- if (!props.isEdit && !props.isClone) return
349
-
350
- const count = model.value.network_devices.length || 0
351
- networksIndex.value = [...Array(count).keys()]
352
- if (props.isEdit) {
353
- networksType.value = Array(count).fill('edit')
354
- } else if (props.isClone) {
355
- networksType.value = Array(count).fill('clone')
356
- }
357
- })
358
- }
359
-
360
- const defaultNetwork = {
361
- network: '',
362
- net_bridge: '',
363
- mac: '',
364
- target: '',
365
- model: 'virtio',
366
- boot_order: 0,
367
- }
368
- const addNetwork = (): void => {
369
- const index = (networksIndex.value.at(-1) ?? -1) + 1
370
- networksIndex.value.push(index)
371
- networksType.value.push('new')
372
-
373
- model.value.network_devices.push({
374
- ...useDeepCopy(defaultNetwork),
375
- })
376
- }
377
- const onRemoveNetwork = (index: number): void => {
378
- const removeIndex = networksIndex.value.indexOf(index)
379
- networksIndex.value = networksIndex.value.filter((item) => item !== index)
380
- networksType.value = networksType.value.filter(
381
- (_item, key) => key !== removeIndex
382
- )
383
- model.value.network_devices = model.value.network_devices.filter(
384
- (_network, key: number) => removeIndex !== key
385
- )
386
-
387
- delete newNetworkInvalidKeys.value[index]
388
- }
389
-
390
- // const defaultCdDvdDriver: UI_I_SendDataNewCdDvdDrive = {
391
- // create: false,
392
- // attach: false,
393
- // source: '',
394
- // bus: '',
395
- // device_type: 'cdrom',
396
- // boot_order: -1,
397
- // }
398
- const defaultCdDvdDriver: UI_I_SendDataNewCdDvdDrive = {
399
- source: '',
400
- storage_id: '',
401
- device_type: 'cdrom',
402
- bus: '',
403
- target: '',
404
- boot_order: 0,
405
- provision_type: 'thick',
406
- disk_mode: 'dependent',
407
- sharing: false,
408
- read_only: true,
409
- shares: 0,
410
- cache: 'none',
411
- io: 'native',
412
- limit_iops: 0,
413
- discard: 'unmap',
414
- attach: false,
415
- detach: false,
416
- remove: false,
417
- create: false,
418
- }
419
- // const cdDvdDrivesLocal = ref<UI_I_SendDataNewCdDvdDrive[]>([
420
- // useDeepCopy(defaultCdDvdDriver),
421
- // ])
422
- const cdDvdDrivesIndex = ref<number[]>([0])
423
- const cdDvdDrivesType = ref<UI_T_CdDvdType[]>(['new'])
424
- if (!model.value.disk_devices?.length) {
425
- cdDvdDrivesIndex.value = []
426
- cdDvdDrivesType.value = []
427
- } else {
428
- model.value.disk_devices
429
- .filter((disk) => disk.device_type === 'cdrom')
430
- .forEach((_disk, _index, array) => {
431
- if (!props.isEdit && !props.isClone) return
432
-
433
- const count = array.length
434
- cdDvdDrivesIndex.value = [...Array(count).keys()]
435
- if (props.isEdit) {
436
- cdDvdDrivesType.value = Array(count).fill('edit')
437
- } else if (props.isClone) {
438
- cdDvdDrivesType.value = Array(count).fill('clone')
439
- }
440
- })
441
- }
442
- // watch(
443
- // () => props.cdDvdDrives,
444
- // (newValue) => {
445
- // if ((!props.isEdit && !props.isClone) || !newValue) return
446
- //
447
- // // cdDvdDrivesLocal.value = newValue
448
- // // cdDvdDrivesType.value = Array(newValue.length).fill('edit')
449
- // const count = newValue?.length || 0
450
- // cdDvdDrivesIndex.value = [...Array(count).keys()]
451
- // cdDvdDrivesLocal.value = newValue
452
- // if (props.isEdit) {
453
- // cdDvdDrivesType.value = Array(count).fill('edit')
454
- // } else if (props.isClone) {
455
- // cdDvdDrivesType.value = Array(count).fill('new')
456
- // }
457
- // },
458
- // { immediate: true }
459
- // )
460
- const addCdDvdDrive = (): void => {
461
- const value = (cdDvdDrivesIndex.value.at(-1) ?? -1) + 1
462
- cdDvdDrivesIndex.value.push(value)
463
- cdDvdDrivesType.value.push('new')
464
- model.value.disk_devices.push({
465
- ...useDeepCopy(defaultCdDvdDriver),
466
- attach: true,
467
- boot_order: 0, // Убираем галочку
468
- })
469
- // cdDvdDrivesLocal.value.push({
470
- // ...useDeepCopy(defaultCdDvdDriver),
471
- // attach: true,
472
- // boot_order: 0, // Убираем галочку
473
- // })
474
- }
475
- const onRemoveCdDvdDrive = (
476
- index: number,
477
- cdDvdDrive: UI_I_SendDataNewCdDvdDrive
478
- ): void => {
479
- const removeIndex = cdDvdDrivesIndex.value.indexOf(index)
480
-
481
- // if (!cdDvdDrive.create && !cdDvdDrive.attach) {
482
- if (cdDvdDrivesType.value[index] === 'edit' && !cdDvdDrive.attach) {
483
- cdDvdDrivesType.value = cdDvdDrivesType.value.map((item, key) => {
484
- if (key === removeIndex) return 'removed'
485
- return item
486
- })
487
- return
488
- }
489
-
490
- cdDvdDrivesIndex.value = cdDvdDrivesIndex.value.filter(
491
- (cdDvdDrive) => cdDvdDrive !== index
492
- )
493
- cdDvdDrivesType.value = cdDvdDrivesType.value.filter(
494
- (_item, key) => key !== index
495
- )
496
-
497
- const hardDiskCount = hardDisksIndex.value.length
498
- model.value.disk_devices = model.value.disk_devices.filter(
499
- (_cdDvdDrive, key: number) => hardDiskCount + removeIndex !== key
500
- )
501
- // cdDvdDrivesLocal.value = cdDvdDrivesLocal.value.filter(
502
- // (_cdDvdDrive, key: number) => removeIndex !== key
503
- // )
504
- }
505
- const onRollBackCdDvdDrive = (index: number): void => {
506
- const removeIndex = cdDvdDrivesIndex.value.indexOf(index)
507
- cdDvdDrivesType.value = cdDvdDrivesType.value.map((item, key) => {
508
- if (key === removeIndex) return 'edit'
509
- return item
510
- })
511
- }
512
-
513
- const defaultPciDevice: UI_I_SendDataNewPciDevice = {
514
- address: '',
515
- vendor_name: '',
516
- class_name: '',
517
- device_name: '',
518
- }
519
- const pciDevicesIndex = ref<number[]>([0])
520
- const pciDevicesType = ref<('new' | 'edit' | 'removed')[]>(['new'])
521
- const pciDevicesLocal = ref<UI_I_SendDataNewPciDevice[]>([])
522
- watch(
523
- () => props.pciDevices,
524
- (newValue) => {
525
- if ((!props.isEdit && !props.isClone) || !newValue) return
526
-
527
- const count = newValue?.length || 0
528
- pciDevicesIndex.value = [...Array(count).keys()]
529
- pciDevicesLocal.value = newValue || []
530
- if (props.isEdit) {
531
- pciDevicesType.value = Array(count).fill('edit')
532
- } else if (props.isClone) {
533
- pciDevicesType.value = Array(count).fill('new')
534
- }
535
- },
536
- { immediate: true }
537
- )
538
-
539
- const addPciDevice = (): void => {
540
- const newIndex = (pciDevicesIndex.value.at(-1) ?? -1) + 1
541
- pciDevicesIndex.value.push(newIndex)
542
- pciDevicesType.value.push('new')
543
-
544
- pciDevicesLocal.value.push(useDeepCopy(defaultPciDevice))
545
- model.value.passthrough_pci_devices.push(useDeepCopy(defaultPciDevice))
546
- }
547
- const onRemovePciDevice = (index: number): void => {
548
- const removeIndex = pciDevicesIndex.value.indexOf(index)
549
- pciDevicesIndex.value = pciDevicesIndex.value.filter((item) => item !== index)
550
- pciDevicesType.value = pciDevicesType.value.filter(
551
- (_item, key) => key !== removeIndex
552
- )
553
-
554
- model.value.passthrough_pci_devices =
555
- model.value.passthrough_pci_devices.filter((_pciDevice, key: number) => {
556
- return removeIndex !== key
557
- })
558
- pciDevicesLocal.value = pciDevicesLocal.value.filter(
559
- (_pciDevice, key: number) => {
560
- return removeIndex !== key
561
- }
562
- )
563
-
564
- delete newPciDeviceInvalidKeys.value[index]
565
- }
566
-
567
- const isShowFileModal = ref<boolean>(false)
568
- const onAddDevice = (item: UI_I_DropdownTreeItemChild): void => {
569
- switch (item.value) {
570
- case 1:
571
- addHardDisk()
572
- break
573
- case 2:
574
- isShowFileModal.value = true
575
- break
576
- case 5:
577
- addCdDvdDrive()
578
- break
579
- case 10:
580
- addPciDevice()
581
- break
582
- case 14:
583
- addNetwork()
584
- break
585
- }
586
- }
587
-
588
- const cpuInvalid = ref<boolean>(false)
589
- const onSendDataNewHardDiskMethod = (
590
- data: UI_I_SendDataNewHardDisk,
591
- index: number
592
- ): void => {
593
- model.value.disk_devices[index] = {
594
- ...data,
595
- boot_order: model.value.disk_devices[index]?.boot_order || 0,
596
- }
597
- }
598
- const sendDataNewCdDvdDriveMethod = (
599
- data: UI_I_SendDataNewCdDvdDrive,
600
- index: number
601
- ): void => {
602
- const cdromIndexStart = model.value.disk_devices.findIndex(
603
- (disk) => disk.device_type === 'cdrom'
604
- )
605
- model.value.disk_devices[cdromIndexStart + index] = {
606
- ...data,
607
- boot_order:
608
- model.value.disk_devices[cdromIndexStart + index]?.boot_order || 0,
609
- }
610
- }
611
- const onSendDataPciDevicesMethod = (
612
- data: UI_I_SendDataNewPciDevice,
613
- index: number
614
- ): void => {
615
- model.value.passthrough_pci_devices[index] = {
616
- ...data,
617
- }
618
- }
619
-
620
- const onSetInvalidHardDisk = (invalid: boolean, index: number): void => {
621
- newHardDiskInvalidKeys.value[index] = invalid
622
- }
623
-
624
- const onSetInvalidNetwork = (invalid: boolean, key: number): void => {
625
- newNetworkInvalidKeys.value[key] = invalid
626
- }
627
-
628
- const onSetInvalidPciDevice = (invalid: boolean, key: number): void => {
629
- newPciDeviceInvalidKeys.value[key] = invalid
630
- }
631
-
632
- const memoryInvalid = ref<boolean>(false)
633
- const videoCardInvalid = ref<boolean>(false)
634
- const newHardDiskInvalidKeys = ref<UI_I_InvalidKeys>({})
635
- const newNetworkInvalidKeys = ref<UI_I_InvalidKeys>({})
636
- const newPciDeviceInvalidKeys = ref<UI_I_InvalidKeys>({})
637
-
638
- watch(
639
- [
640
- cpuInvalid,
641
- memoryInvalid,
642
- newHardDiskInvalidKeys,
643
- newNetworkInvalidKeys,
644
- newPciDeviceInvalidKeys,
645
- videoCardInvalid,
646
- ],
647
- () => {
648
- const cpu = cpuInvalid.value ? localization.value.common.cpu : ''
649
- const memory = memoryInvalid.value ? localization.value.common.memory : ''
650
- const videoCard = videoCardInvalid.value
651
- ? localization.value.common.videoCard
652
- : ''
653
- let newHardDisk = ''
654
- Object.keys(newHardDiskInvalidKeys.value).forEach((key) => {
655
- if (!newHardDiskInvalidKeys.value[+key]) {
656
- return
657
- }
658
-
659
- newHardDisk +=
660
- (newHardDisk ? ', ' : '') +
661
- localization.value.common.newHardDisk +
662
- ' ' +
663
- (+key + 1)
664
- })
665
- let newNetwork = ''
666
- Object.keys(newNetworkInvalidKeys.value).forEach((key) => {
667
- if (!newNetworkInvalidKeys.value[+key]) {
668
- return
669
- }
670
-
671
- newNetwork +=
672
- (newNetwork ? ', ' : '') +
673
- localization.value.common.newNetwork +
674
- ' ' +
675
- (+key + 1)
676
- })
677
- // let pciDevice = ''
678
- // Object.keys(newPciDeviceInvalidKeys.value).forEach((key) => {
679
- // if (!newPciDeviceInvalidKeys.value[+key]) {
680
- // return
681
- // }
682
- //
683
- // pciDevice +=
684
- // (pciDevice ? ', ' : '') +
685
- // localization.value.common.pciDevice +
686
- // ' ' +
687
- // (+key + 1)
688
- // })
689
-
690
- emits('invalid', [cpu, memory, newHardDisk, newNetwork, videoCard])
691
- },
692
- { deep: true }
693
- )
694
-
695
- emits('get-pci-devices')
696
- </script>
697
-
698
- <style scoped lang="scss"></style>
1
+ <template>
2
+ <component
3
+ :is="currentComponent"
4
+ v-model="model"
5
+ v-model:cpu-invalid="cpuInvalid"
6
+ v-model:memory-invalid="memoryInvalid"
7
+ v-model:video-card-invalid="videoCardInvalid"
8
+ :nodes="props.nodes"
9
+ :files="props.files"
10
+ :is-edit="props.isEdit"
11
+ :storage="props.storage"
12
+ :storage-free="storageFree"
13
+ :project="props.project"
14
+ :max-memory="props.maxMemory"
15
+ :cpu-models="props.cpuModels"
16
+ :datastore="props.datastore"
17
+ :is-datastore-loading="props.isDatastoreLoading"
18
+ :networks-type="networksType"
19
+ :networks-table="props.networksTable"
20
+ :dropdown-items="dropdownItems"
21
+ :hard-disks-type="hardDisksType"
22
+ :networks-index="networksIndex"
23
+ :hard-disks-index="hardDisksIndex"
24
+ :pci-devices-type="pciDevicesType"
25
+ :is-show-file-modal="isShowFileModal"
26
+ :pci-devices-index="pciDevicesIndex"
27
+ :cd-dvd-drives-type="cdDvdDrivesType"
28
+ :cd-dvd-drives-index="cdDvdDrivesIndex"
29
+ :error-validation-fields="errorValidationFields"
30
+ :get-datastore-table-func="getDatastoreTableFunc"
31
+ :state="state"
32
+ :video-card="videoCard"
33
+ :pci-devices="pciDevicesLocal"
34
+ :guest-machine-type="guestMachineType"
35
+ :passthrough-devices="passthroughDevices"
36
+ :mediated-devices="mediatedDevices"
37
+ :vm-cpu-help-text-second="vmCpuHelpTextSecond"
38
+ :compute-resource="props.computeResource"
39
+ :compatibility-info="props.compatibilityInfo"
40
+ :network-value-prop="networkValueProp"
41
+ @add-device="onAddDevice"
42
+ @get-storage="emits('get-storage', $event)"
43
+ @remove-network="onRemoveNetwork"
44
+ @hide-file-modal="isShowFileModal = false"
45
+ @remove-hard-disk="onRemoveHardDisk(...$event)"
46
+ @remove-pci-device="onRemovePciDevice"
47
+ @get-networks-table="emits('get-networks-table', $event)"
48
+ @add-exist-hard-disk="onAddExistHardDisk"
49
+ @roll-back-hard-disk="onRollBackHardDisk"
50
+ @set-invalid-network="onSetInvalidNetwork(...$event)"
51
+ @remove-cd-dvd-drive="onRemoveCdDvdDrive(...$event)"
52
+ @show-datastore-child="emits('show-datastore-child', $event)"
53
+ @get-folders-or-files="emits('get-folders-or-files', $event)"
54
+ @set-invalid-hard-disk="onSetInvalidHardDisk(...$event)"
55
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
56
+ @roll-back-cd-dvd-drive="onRollBackCdDvdDrive"
57
+ @set-invalid-pci-device="onSetInvalidPciDevice(...$event)"
58
+ @get-active-device-child="emits('get-active-device-child', $event)"
59
+ @send-data-pci-devices-method="onSendDataPciDevicesMethod(...$event)"
60
+ @send-data-new-hard-disk-method="onSendDataNewHardDiskMethod(...$event)"
61
+ @send-data-new-cd-dvd-drive-method="sendDataNewCdDvdDriveMethod(...$event)"
62
+ />
63
+ </template>
64
+
65
+ <script setup lang="ts">
66
+ import type { UI_T_Project } from '~/lib/models/types'
67
+ import type { UI_I_DatastoreTableItem } from '~/lib/models/store/storage/interfaces'
68
+ import type { UI_I_NetworkTableItem } from '~/lib/models/store/network/interfaces'
69
+ import type { UI_I_TablePayload } from '~/lib/models/table/interfaces'
70
+ import type { UI_I_FolderOrFileTreePayload } from '~/lib/models/store/storage/interfaces'
71
+ import type { UI_I_FileTreeNode } from '~/components/lib/models/interfaces'
72
+ import type {
73
+ UI_I_SendDataNewHardDisk,
74
+ UI_I_SendDataVideoCard,
75
+ UI_I_InvalidKeys,
76
+ UI_I_SendDataNewCdDvdDrive,
77
+ // UI_I_HardDisk,
78
+ UI_I_SendDataNewPciDevice,
79
+ } from '~/components/common/vm/actions/common/customizeHardware/virtualHardware/lib/models/interfaces'
80
+ import type { UI_I_ErrorValidationField } from '~/lib/models/store/interfaces'
81
+ import type {
82
+ UI_T_HardDiskType,
83
+ UI_T_NetworkType,
84
+ UI_T_CdDvdType,
85
+ } from '~/components/common/vm/actions/common/customizeHardware/virtualHardware/lib/models/types'
86
+ import type { UI_I_OptionItem } from '~/components/atoms/lib/models/interfaces'
87
+ import type {
88
+ UI_I_DropdownTreeItem,
89
+ UI_I_DropdownTreeItemChild,
90
+ } from '~/components/atoms/dropdown/tree/lib/models/interfaces'
91
+ import type { UI_I_Localization } from '~/lib/models/interfaces'
92
+ import type {
93
+ UI_I_MediatedDevice,
94
+ UI_I_PciDevice,
95
+ } from '~/lib/models/store/vm/interfaces'
96
+ import type { UI_I_TreeNode } from '~/components/common/recursionTree/lib/models/interfaces'
97
+ import type { UI_I_CreateVmData } from '~/components/common/vm/actions/common/lib/models/interfaces'
98
+ import { dropdownItemsFunc } from './lib/config/dropdownItems'
99
+
100
+ const model = defineModel<UI_I_CreateVmData>({ required: true })
101
+
102
+ const props = withDefaults(
103
+ defineProps<{
104
+ storage: UI_I_DatastoreTableItem | null
105
+ cpuModels: UI_I_OptionItem[]
106
+ maxMemory: number
107
+ isEdit: boolean
108
+ isClone: boolean
109
+ errorValidationFields: UI_I_ErrorValidationField[]
110
+ nodes: UI_I_FileTreeNode[]
111
+ files: UI_I_FileTreeNode[]
112
+ networksTable: UI_I_NetworkTableItem[]
113
+ getDatastoreTableFunc: (payload: UI_I_TablePayload) => Promise<void>
114
+ datastore: UI_I_DatastoreTableItem[]
115
+ isDatastoreLoading: boolean
116
+ project: UI_T_Project
117
+ state?: string | number
118
+ vmCpuHelpTextSecond?: string
119
+ hardDisks?: UI_I_SendDataNewHardDisk[] | null
120
+ cdDvdDrives?: UI_I_SendDataNewCdDvdDrive[] | null
121
+ videoCard?: UI_I_SendDataVideoCard
122
+ pciDevices?: UI_I_SendDataNewPciDevice[]
123
+ passthroughDevices?: UI_I_PciDevice[]
124
+ mediatedDevices?: UI_I_MediatedDevice[]
125
+ guestMachineType?: UI_I_OptionItem | null
126
+ computeResource?: UI_I_TreeNode | null
127
+ compatibilityInfo?: string
128
+ }>(),
129
+ {
130
+ state: undefined,
131
+ vmCpuHelpTextSecond: undefined,
132
+ hardDisks: undefined,
133
+ cdDvdDrives: undefined,
134
+ videoCard: undefined,
135
+ pciDevices: undefined,
136
+ passthroughDevices: undefined,
137
+ mediatedDevices: undefined,
138
+ guestMachineType: undefined,
139
+ computeResource: undefined,
140
+ compatibilityInfo: undefined,
141
+ }
142
+ )
143
+ const emits = defineEmits<{
144
+ (event: 'invalid', value: string[]): void
145
+ (event: 'get-storage', value: UI_I_TablePayload): void
146
+ (event: 'get-folders-or-files', value: UI_I_FolderOrFileTreePayload): void
147
+ (event: 'get-active-device-child', value: UI_I_FileTreeNode): void
148
+ (event: 'show-datastore-child', value: UI_I_FileTreeNode): void
149
+ (event: 'remove-error-by-title', value: string): void
150
+ (event: 'get-networks-table', value: UI_I_TablePayload): void
151
+ (event: 'get-pci-devices'): void
152
+ }>()
153
+
154
+ const { $store, $binary }: any = useNuxtApp()
155
+ const isNewView = computed<boolean>(() => $store.getters['main/getIsNewView'])
156
+ const currentComponent = computed(() =>
157
+ isNewView.value
158
+ ? defineAsyncComponent(() => import('./New.vue'))
159
+ : defineAsyncComponent(() => import('./Old.vue'))
160
+ )
161
+
162
+ const localization = computed<UI_I_Localization>(() => useLocal())
163
+
164
+ const dropdownItems = computed<UI_I_DropdownTreeItem[]>(() =>
165
+ dropdownItemsFunc(
166
+ localization.value,
167
+ props.state,
168
+ props.passthroughDevices,
169
+ props.mediatedDevices
170
+ )
171
+ )
172
+
173
+ const hardDisksIndex = ref<number[]>([0])
174
+ const hardDisksType = ref<UI_T_HardDiskType[]>(['new'])
175
+ // const hardDisksLocal = ref<UI_I_SendDataNewHardDisk[]>([
176
+ // {
177
+ // create: true,
178
+ // size: 90,
179
+ // source: '',
180
+ // boot_order: -1,
181
+ // },
182
+ // ])
183
+ if (!model.value.disk_devices?.length) {
184
+ hardDisksType.value = []
185
+ hardDisksIndex.value = []
186
+ } else {
187
+ model.value.disk_devices
188
+ .filter((disk) => disk.device_type !== 'cdrom')
189
+ .forEach((_disk, _index, array) => {
190
+ if (!props.isEdit && !props.isClone) return
191
+
192
+ const count = array.length
193
+ hardDisksIndex.value = [...Array(count).keys()]
194
+ if (props.isEdit) {
195
+ hardDisksType.value = Array(count).fill('edit')
196
+ } else if (props.isClone) {
197
+ hardDisksType.value = Array(count).fill('clone')
198
+ }
199
+ })
200
+ }
201
+
202
+ // watch(
203
+ // () => props.hardDisks,
204
+ // (newValue) => {
205
+ // if ((!props.isEdit && !props.isClone) || !newValue) return
206
+ //
207
+ // const count = newValue?.length || 0
208
+ // hardDisksIndex.value = [...Array(count).keys()]
209
+ // hardDisksLocal.value = newValue
210
+ // if (props.isEdit) {
211
+ // hardDisksType.value = Array(count).fill('edit')
212
+ // } else if (props.isClone) {
213
+ // hardDisksType.value = Array(count).fill('clone')
214
+ // hardDisksLocal.value = newValue.map((hardDisk) => {
215
+ // hardDisk.create = true
216
+ // return hardDisk
217
+ // })
218
+ // }
219
+ // },
220
+ // { immediate: true }
221
+ // )
222
+
223
+ const getDisksSize = (): number => {
224
+ return model.value.disk_devices.reduce(
225
+ (acum, disk) => (acum += disk.size || 0),
226
+ 0
227
+ ) || 0
228
+ }
229
+ const initialDisksSize = getDisksSize()
230
+ const storageFree = computed<number>(() => {
231
+ if (!props.storage) return 0
232
+ const free = (props.storage.capacity.free_mb || props.storage.free) as number // TODO fix
233
+
234
+ const disksSize = getDisksSize()
235
+
236
+ return free + initialDisksSize - (disksSize - initialDisksSize)
237
+ })
238
+
239
+ const addHardDisk = (
240
+ create = true,
241
+ size = 92_160, // 90GB
242
+ source = '',
243
+ type: UI_T_HardDiskType = 'new',
244
+ provisioned_type?: number // При добавлении существующей
245
+ ): void => {
246
+ const newIndex = (hardDisksIndex.value.at(-1) ?? -1) + 1
247
+ hardDisksIndex.value.push(newIndex)
248
+ hardDisksType.value.push(type)
249
+
250
+ let provisionType = 'thick'
251
+ if (provisioned_type === 1) provisionType = 'thin'
252
+
253
+ model.value.disk_devices = [
254
+ ...model.value.disk_devices.filter((disk) => disk.device_type !== 'cdrom'),
255
+ // {
256
+ // create,
257
+ // size,
258
+ // source,
259
+ // attach: true,
260
+ // boot_order: 0, // Убираем галочку
261
+ // provision_type: provisionType,
262
+ // },
263
+ {
264
+ create,
265
+ size,
266
+ source,
267
+ bus: 'virtio',
268
+ storage_id: '',
269
+ provision_type: 'thick',
270
+ disk_mode: 'dependent',
271
+ boot_order: 0, // Убираем галочку
272
+ device_type: 'disk',
273
+ sharing: false,
274
+ shares: 0,
275
+ cache: 'none',
276
+ io: '',
277
+ limit_iops: 0,
278
+ attach: true,
279
+ },
280
+ ...model.value.disk_devices.filter((disk) => disk.device_type === 'cdrom'),
281
+ ]
282
+ // hardDisksLocal.value.push({
283
+ // create,
284
+ // size,
285
+ // source,
286
+ // attach: true,
287
+ // boot_order: 0, // Убираем галочку
288
+ // provision_type: provisionType,
289
+ // })
290
+ }
291
+ const onAddExistHardDisk = (file: UI_I_FileTreeNode): void => {
292
+ addHardDisk(
293
+ false,
294
+ $binary.bToMb(file.size),
295
+ file.path,
296
+ 'exist',
297
+ file.provisioned_type
298
+ )
299
+ }
300
+ const onRemoveHardDisk = (
301
+ index: number,
302
+ hardDisk: UI_I_SendDataNewHardDisk
303
+ ): void => {
304
+ const removeIndex = hardDisksIndex.value.indexOf(index)
305
+
306
+ if (!hardDisk.create && !hardDisk.attach) {
307
+ hardDisksType.value = hardDisksType.value.map((item, key) => {
308
+ if (key === removeIndex) return 'removed'
309
+ return item
310
+ })
311
+ return
312
+ }
313
+
314
+ hardDisksIndex.value = hardDisksIndex.value.filter((item) => item !== index)
315
+ hardDisksType.value = hardDisksType.value.filter(
316
+ (_item, key) => key !== removeIndex
317
+ )
318
+
319
+ model.value.disk_devices = model.value.disk_devices.filter(
320
+ (_hardDisk, key: number) => {
321
+ return removeIndex !== key
322
+ }
323
+ )
324
+ // hardDisksLocal.value = hardDisksLocal.value.filter(
325
+ // (_hardDisk, key: number) => {
326
+ // return removeIndex !== key
327
+ // }
328
+ // )
329
+
330
+ delete newHardDiskInvalidKeys.value[index]
331
+ }
332
+ const onRollBackHardDisk = (index: number): void => {
333
+ const removeIndex = hardDisksIndex.value.indexOf(index)
334
+ hardDisksType.value = hardDisksType.value.map((item, key) => {
335
+ if (key === removeIndex) return 'edit'
336
+ return item
337
+ })
338
+ }
339
+
340
+ const networkValueProp = props.project === 'sphere' ? 'network' : 'net_bridge'
341
+ const networksType = ref<UI_T_NetworkType[]>(['new'])
342
+ const networksIndex = ref<number[]>([0])
343
+ if (!model.value.network_devices?.length) {
344
+ networksType.value = []
345
+ networksIndex.value = []
346
+ } else {
347
+ model.value.network_devices.forEach(() => {
348
+ if (!props.isEdit && !props.isClone) return
349
+
350
+ const count = model.value.network_devices.length || 0
351
+ networksIndex.value = [...Array(count).keys()]
352
+ if (props.isEdit) {
353
+ networksType.value = Array(count).fill('edit')
354
+ } else if (props.isClone) {
355
+ networksType.value = Array(count).fill('clone')
356
+ }
357
+ })
358
+ }
359
+
360
+ const defaultNetwork = {
361
+ network: '',
362
+ net_bridge: '',
363
+ mac: '',
364
+ target: '',
365
+ model: 'virtio',
366
+ boot_order: 0,
367
+ }
368
+ const addNetwork = (): void => {
369
+ const index = (networksIndex.value.at(-1) ?? -1) + 1
370
+ networksIndex.value.push(index)
371
+ networksType.value.push('new')
372
+
373
+ model.value.network_devices.push({
374
+ ...useDeepCopy(defaultNetwork),
375
+ })
376
+ }
377
+ const onRemoveNetwork = (index: number): void => {
378
+ const removeIndex = networksIndex.value.indexOf(index)
379
+ networksIndex.value = networksIndex.value.filter((item) => item !== index)
380
+ networksType.value = networksType.value.filter(
381
+ (_item, key) => key !== removeIndex
382
+ )
383
+ model.value.network_devices = model.value.network_devices.filter(
384
+ (_network, key: number) => removeIndex !== key
385
+ )
386
+
387
+ delete newNetworkInvalidKeys.value[index]
388
+ }
389
+
390
+ // const defaultCdDvdDriver: UI_I_SendDataNewCdDvdDrive = {
391
+ // create: false,
392
+ // attach: false,
393
+ // source: '',
394
+ // bus: '',
395
+ // device_type: 'cdrom',
396
+ // boot_order: -1,
397
+ // }
398
+ const defaultCdDvdDriver: UI_I_SendDataNewCdDvdDrive = {
399
+ source: '',
400
+ storage_id: '',
401
+ device_type: 'cdrom',
402
+ bus: '',
403
+ target: '',
404
+ boot_order: 0,
405
+ provision_type: 'thick',
406
+ disk_mode: 'dependent',
407
+ sharing: false,
408
+ read_only: true,
409
+ shares: 0,
410
+ cache: 'none',
411
+ io: 'native',
412
+ limit_iops: 0,
413
+ discard: 'unmap',
414
+ attach: false,
415
+ detach: false,
416
+ remove: false,
417
+ create: false,
418
+ }
419
+ // const cdDvdDrivesLocal = ref<UI_I_SendDataNewCdDvdDrive[]>([
420
+ // useDeepCopy(defaultCdDvdDriver),
421
+ // ])
422
+ const cdDvdDrivesIndex = ref<number[]>([0])
423
+ const cdDvdDrivesType = ref<UI_T_CdDvdType[]>(['new'])
424
+ if (!model.value.disk_devices?.length) {
425
+ cdDvdDrivesIndex.value = []
426
+ cdDvdDrivesType.value = []
427
+ } else {
428
+ model.value.disk_devices
429
+ .filter((disk) => disk.device_type === 'cdrom')
430
+ .forEach((_disk, _index, array) => {
431
+ if (!props.isEdit && !props.isClone) return
432
+
433
+ const count = array.length
434
+ cdDvdDrivesIndex.value = [...Array(count).keys()]
435
+ if (props.isEdit) {
436
+ cdDvdDrivesType.value = Array(count).fill('edit')
437
+ } else if (props.isClone) {
438
+ cdDvdDrivesType.value = Array(count).fill('clone')
439
+ }
440
+ })
441
+ }
442
+ // watch(
443
+ // () => props.cdDvdDrives,
444
+ // (newValue) => {
445
+ // if ((!props.isEdit && !props.isClone) || !newValue) return
446
+ //
447
+ // // cdDvdDrivesLocal.value = newValue
448
+ // // cdDvdDrivesType.value = Array(newValue.length).fill('edit')
449
+ // const count = newValue?.length || 0
450
+ // cdDvdDrivesIndex.value = [...Array(count).keys()]
451
+ // cdDvdDrivesLocal.value = newValue
452
+ // if (props.isEdit) {
453
+ // cdDvdDrivesType.value = Array(count).fill('edit')
454
+ // } else if (props.isClone) {
455
+ // cdDvdDrivesType.value = Array(count).fill('new')
456
+ // }
457
+ // },
458
+ // { immediate: true }
459
+ // )
460
+ const addCdDvdDrive = (): void => {
461
+ const value = (cdDvdDrivesIndex.value.at(-1) ?? -1) + 1
462
+ cdDvdDrivesIndex.value.push(value)
463
+ cdDvdDrivesType.value.push('new')
464
+ model.value.disk_devices.push({
465
+ ...useDeepCopy(defaultCdDvdDriver),
466
+ attach: true,
467
+ boot_order: 0, // Убираем галочку
468
+ })
469
+ // cdDvdDrivesLocal.value.push({
470
+ // ...useDeepCopy(defaultCdDvdDriver),
471
+ // attach: true,
472
+ // boot_order: 0, // Убираем галочку
473
+ // })
474
+ }
475
+ const onRemoveCdDvdDrive = (
476
+ index: number,
477
+ cdDvdDrive: UI_I_SendDataNewCdDvdDrive
478
+ ): void => {
479
+ const removeIndex = cdDvdDrivesIndex.value.indexOf(index)
480
+
481
+ // if (!cdDvdDrive.create && !cdDvdDrive.attach) {
482
+ if (cdDvdDrivesType.value[index] === 'edit' && !cdDvdDrive.attach) {
483
+ cdDvdDrivesType.value = cdDvdDrivesType.value.map((item, key) => {
484
+ if (key === removeIndex) return 'removed'
485
+ return item
486
+ })
487
+ return
488
+ }
489
+
490
+ cdDvdDrivesIndex.value = cdDvdDrivesIndex.value.filter(
491
+ (cdDvdDrive) => cdDvdDrive !== index
492
+ )
493
+ cdDvdDrivesType.value = cdDvdDrivesType.value.filter(
494
+ (_item, key) => key !== index
495
+ )
496
+
497
+ const hardDiskCount = hardDisksIndex.value.length
498
+ model.value.disk_devices = model.value.disk_devices.filter(
499
+ (_cdDvdDrive, key: number) => hardDiskCount + removeIndex !== key
500
+ )
501
+ // cdDvdDrivesLocal.value = cdDvdDrivesLocal.value.filter(
502
+ // (_cdDvdDrive, key: number) => removeIndex !== key
503
+ // )
504
+ }
505
+ const onRollBackCdDvdDrive = (index: number): void => {
506
+ const removeIndex = cdDvdDrivesIndex.value.indexOf(index)
507
+ cdDvdDrivesType.value = cdDvdDrivesType.value.map((item, key) => {
508
+ if (key === removeIndex) return 'edit'
509
+ return item
510
+ })
511
+ }
512
+
513
+ const defaultPciDevice: UI_I_SendDataNewPciDevice = {
514
+ address: '',
515
+ vendor_name: '',
516
+ class_name: '',
517
+ device_name: '',
518
+ }
519
+ const pciDevicesIndex = ref<number[]>([0])
520
+ const pciDevicesType = ref<('new' | 'edit' | 'removed')[]>(['new'])
521
+ const pciDevicesLocal = ref<UI_I_SendDataNewPciDevice[]>([])
522
+ watch(
523
+ () => props.pciDevices,
524
+ (newValue) => {
525
+ if ((!props.isEdit && !props.isClone) || !newValue) return
526
+
527
+ const count = newValue?.length || 0
528
+ pciDevicesIndex.value = [...Array(count).keys()]
529
+ pciDevicesLocal.value = newValue || []
530
+ if (props.isEdit) {
531
+ pciDevicesType.value = Array(count).fill('edit')
532
+ } else if (props.isClone) {
533
+ pciDevicesType.value = Array(count).fill('new')
534
+ }
535
+ },
536
+ { immediate: true }
537
+ )
538
+
539
+ const addPciDevice = (): void => {
540
+ const newIndex = (pciDevicesIndex.value.at(-1) ?? -1) + 1
541
+ pciDevicesIndex.value.push(newIndex)
542
+ pciDevicesType.value.push('new')
543
+
544
+ pciDevicesLocal.value.push(useDeepCopy(defaultPciDevice))
545
+ model.value.passthrough_pci_devices.push(useDeepCopy(defaultPciDevice))
546
+ }
547
+ const onRemovePciDevice = (index: number): void => {
548
+ const removeIndex = pciDevicesIndex.value.indexOf(index)
549
+ pciDevicesIndex.value = pciDevicesIndex.value.filter((item) => item !== index)
550
+ pciDevicesType.value = pciDevicesType.value.filter(
551
+ (_item, key) => key !== removeIndex
552
+ )
553
+
554
+ model.value.passthrough_pci_devices =
555
+ model.value.passthrough_pci_devices.filter((_pciDevice, key: number) => {
556
+ return removeIndex !== key
557
+ })
558
+ pciDevicesLocal.value = pciDevicesLocal.value.filter(
559
+ (_pciDevice, key: number) => {
560
+ return removeIndex !== key
561
+ }
562
+ )
563
+
564
+ delete newPciDeviceInvalidKeys.value[index]
565
+ }
566
+
567
+ const isShowFileModal = ref<boolean>(false)
568
+ const onAddDevice = (item: UI_I_DropdownTreeItemChild): void => {
569
+ switch (item.value) {
570
+ case 1:
571
+ addHardDisk()
572
+ break
573
+ case 2:
574
+ isShowFileModal.value = true
575
+ break
576
+ case 5:
577
+ addCdDvdDrive()
578
+ break
579
+ case 10:
580
+ addPciDevice()
581
+ break
582
+ case 14:
583
+ addNetwork()
584
+ break
585
+ }
586
+ }
587
+
588
+ const cpuInvalid = ref<boolean>(false)
589
+ const onSendDataNewHardDiskMethod = (
590
+ data: UI_I_SendDataNewHardDisk,
591
+ index: number
592
+ ): void => {
593
+ model.value.disk_devices[index] = {
594
+ ...data,
595
+ boot_order: model.value.disk_devices[index]?.boot_order || 0,
596
+ }
597
+ }
598
+ const sendDataNewCdDvdDriveMethod = (
599
+ data: UI_I_SendDataNewCdDvdDrive,
600
+ index: number
601
+ ): void => {
602
+ const cdromIndexStart = model.value.disk_devices.findIndex(
603
+ (disk) => disk.device_type === 'cdrom'
604
+ )
605
+ model.value.disk_devices[cdromIndexStart + index] = {
606
+ ...data,
607
+ boot_order:
608
+ model.value.disk_devices[cdromIndexStart + index]?.boot_order || 0,
609
+ }
610
+ }
611
+ const onSendDataPciDevicesMethod = (
612
+ data: UI_I_SendDataNewPciDevice,
613
+ index: number
614
+ ): void => {
615
+ model.value.passthrough_pci_devices[index] = {
616
+ ...data,
617
+ }
618
+ }
619
+
620
+ const onSetInvalidHardDisk = (invalid: boolean, index: number): void => {
621
+ newHardDiskInvalidKeys.value[index] = invalid
622
+ }
623
+
624
+ const onSetInvalidNetwork = (invalid: boolean, key: number): void => {
625
+ newNetworkInvalidKeys.value[key] = invalid
626
+ }
627
+
628
+ const onSetInvalidPciDevice = (invalid: boolean, key: number): void => {
629
+ newPciDeviceInvalidKeys.value[key] = invalid
630
+ }
631
+
632
+ const memoryInvalid = ref<boolean>(false)
633
+ const videoCardInvalid = ref<boolean>(false)
634
+ const newHardDiskInvalidKeys = ref<UI_I_InvalidKeys>({})
635
+ const newNetworkInvalidKeys = ref<UI_I_InvalidKeys>({})
636
+ const newPciDeviceInvalidKeys = ref<UI_I_InvalidKeys>({})
637
+
638
+ watch(
639
+ [
640
+ cpuInvalid,
641
+ memoryInvalid,
642
+ newHardDiskInvalidKeys,
643
+ newNetworkInvalidKeys,
644
+ newPciDeviceInvalidKeys,
645
+ videoCardInvalid,
646
+ ],
647
+ () => {
648
+ const cpu = cpuInvalid.value ? localization.value.common.cpu : ''
649
+ const memory = memoryInvalid.value ? localization.value.common.memory : ''
650
+ const videoCard = videoCardInvalid.value
651
+ ? localization.value.common.videoCard
652
+ : ''
653
+ let newHardDisk = ''
654
+ Object.keys(newHardDiskInvalidKeys.value).forEach((key) => {
655
+ if (!newHardDiskInvalidKeys.value[+key]) {
656
+ return
657
+ }
658
+
659
+ newHardDisk +=
660
+ (newHardDisk ? ', ' : '') +
661
+ localization.value.common.newHardDisk +
662
+ ' ' +
663
+ (+key + 1)
664
+ })
665
+ let newNetwork = ''
666
+ Object.keys(newNetworkInvalidKeys.value).forEach((key) => {
667
+ if (!newNetworkInvalidKeys.value[+key]) {
668
+ return
669
+ }
670
+
671
+ newNetwork +=
672
+ (newNetwork ? ', ' : '') +
673
+ localization.value.common.newNetwork +
674
+ ' ' +
675
+ (+key + 1)
676
+ })
677
+ // let pciDevice = ''
678
+ // Object.keys(newPciDeviceInvalidKeys.value).forEach((key) => {
679
+ // if (!newPciDeviceInvalidKeys.value[+key]) {
680
+ // return
681
+ // }
682
+ //
683
+ // pciDevice +=
684
+ // (pciDevice ? ', ' : '') +
685
+ // localization.value.common.pciDevice +
686
+ // ' ' +
687
+ // (+key + 1)
688
+ // })
689
+
690
+ emits('invalid', [cpu, memory, newHardDisk, newNetwork, videoCard])
691
+ },
692
+ { deep: true }
693
+ )
694
+
695
+ emits('get-pci-devices')
696
+ </script>
697
+
698
+ <style scoped lang="scss"></style>