bfg-common 1.2.37 → 1.2.39

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 (81) hide show
  1. package/components/atoms/TheIcon2.vue +0 -1
  2. package/components/atoms/alert/Notification.vue +167 -167
  3. package/components/atoms/autocomplete/Autocomplete.vue +236 -236
  4. package/components/atoms/datepicker/Datepicker.vue +612 -612
  5. package/components/atoms/list/SelectList.vue +62 -62
  6. package/components/atoms/nav/NavBar.vue +116 -116
  7. package/components/atoms/nav/VerticalNavBar.vue +89 -89
  8. package/components/atoms/notificationBar/NotificationBar.vue +175 -175
  9. package/components/atoms/perPage/PerPage.vue +52 -52
  10. package/components/atoms/popup/SimplePopup.vue +90 -90
  11. package/components/atoms/step/VerticalStep.vue +104 -104
  12. package/components/atoms/switch/Switch.vue +107 -107
  13. package/components/atoms/table/dataGrid/DataGridColumnSwitch.vue +206 -206
  14. package/components/atoms/table/dataGrid/DataGridPage.vue +189 -189
  15. package/components/atoms/tabs/Tabs.vue +189 -189
  16. package/components/atoms/tooltip/Signpost.vue +224 -224
  17. package/components/common/BadBrowser.vue +24 -5
  18. package/components/common/adapterManager/AddAdapterWarningModal.vue +82 -82
  19. package/components/common/adapterManager/NoActiveAdaptersModal.vue +62 -62
  20. package/components/common/adapterManager/NoConnectedActiveAdaptersModal.vue +62 -62
  21. package/components/common/browse/Browse.vue +182 -182
  22. package/components/common/browse/blocks/Title.vue +66 -66
  23. package/components/common/diagramMain/Diagram.vue +186 -186
  24. package/components/common/diagramMain/DiagramMain.vue +986 -986
  25. package/components/common/diagramMain/adapter/AdapterItem.vue +227 -227
  26. package/components/common/diagramMain/adapter/AdapterItems.vue +57 -57
  27. package/components/common/diagramMain/modals/editSettings/tabs/port/IpvFourSettings.vue +339 -339
  28. package/components/common/diagramMain/modals/editSettings/tabs/port/PortProperties.vue +202 -202
  29. package/components/common/diagramMain/modals/remove/RemoveModal.vue +226 -226
  30. package/components/common/diagramMain/network/Contents.vue +238 -238
  31. package/components/common/feedback/Buttons.vue +232 -232
  32. package/components/common/feedback/Message.vue +468 -468
  33. package/components/common/feedback/VisitPortal.vue +54 -54
  34. package/components/common/help/navbar/left/Left.vue +159 -159
  35. package/components/common/help/navbar/left/utils/constructAccordion.ts +27 -27
  36. package/components/common/mainNavigationPanel/MainNavigationPanel.vue +359 -359
  37. package/components/common/modals/Rename.vue +165 -165
  38. package/components/common/monitor/advanced/Advanced.vue +235 -235
  39. package/components/common/monitor/advanced/tools/Tools.vue +1 -1
  40. package/components/common/monitor/advanced/tools/chartOptionsModal/ChartOptionsModal.vue +1 -1
  41. package/components/common/monitor/advanced/tools/chartOptionsModal/models/{models.ts → interfaces.ts} +19 -19
  42. package/components/common/perPage/PerPage.vue +51 -51
  43. package/components/common/recursionTree/RecursionTree.vue +201 -201
  44. package/components/common/vm/actions/add/config/capabilities.ts +338 -338
  45. package/components/common/vm/actions/add/customizeHardware/virtualHardware/VirtualHardware.vue +657 -657
  46. package/components/common/vm/actions/add/customizeHardware/virtualHardware/cpu/CoresPerSocket.vue +109 -109
  47. package/components/common/vm/actions/add/customizeHardware/virtualHardware/cpu/Cpu.vue +383 -383
  48. package/components/common/vm/actions/add/customizeHardware/virtualHardware/limit/Limit.vue +234 -234
  49. package/components/common/vm/actions/add/customizeHardware/virtualHardware/limit/config/options.ts +28 -28
  50. package/components/common/vm/actions/add/customizeHardware/virtualHardware/memory/Memory.vue +316 -316
  51. package/components/common/vm/actions/add/customizeHardware/virtualHardware/memory/config/memoryOptions.ts +35 -35
  52. package/components/common/vm/actions/add/customizeHardware/virtualHardware/newHardDisk/NewHardDisk.vue +445 -445
  53. package/components/common/vm/actions/add/customizeHardware/virtualHardware/newNetwork/NewNetwork.vue +288 -288
  54. package/components/common/vm/actions/add/customizeHardware/virtualHardware/reservation/Reservation.vue +235 -235
  55. package/components/common/vm/actions/add/customizeHardware/virtualHardware/videoCard/VideoCard.vue +177 -177
  56. package/components/common/vm/actions/add/customizeHardware/vmoptions/bootOptions/order/Order.vue +197 -197
  57. package/components/common/vm/actions/add/customizeHardware/vmoptions/generalOptions/GeneralOptions.vue +181 -181
  58. package/components/common/vm/actions/add/customizeHardware/vmoptions/remoteConsoleOptions/CopyPaste.vue +51 -51
  59. package/components/common/vm/actions/add/customizeHardware/vmoptions/remoteConsoleOptions/RemoteConsoleOptions.vue +253 -253
  60. package/components/common/vm/actions/add/customizeHardware/vmoptions/remoteConsoleOptions/keymap/Keymap.vue +55 -55
  61. package/components/common/vm/actions/add/select/storage/config/config.ts +154 -154
  62. package/components/common/vm/actions/clone/Clone.vue +544 -544
  63. package/components/common/vm/actions/clone/select/options/Options.vue +65 -65
  64. package/components/common/vm/actions/clone/utils.ts +43 -43
  65. package/components/common/wizards/datastore/add/nfs/Nfs.vue +94 -94
  66. package/components/common/wizards/datastore/add/nfs/configuration/Configuration.vue +377 -377
  67. package/components/common/wizards/datastore/add/nfs/configuration/serversList/ServersList.vue +123 -123
  68. package/components/common/wizards/datastore/add/nfs/kerberosAuthentication/KerberosAuthentication.vue +54 -54
  69. package/components/common/wizards/datastore/add/sharedStorm/deviceSelection/hostTable/HostTable.vue +131 -131
  70. package/components/common/wizards/datastore/add/sharedStorm/partitionConfiguration/PartitionConfiguration.vue +230 -230
  71. package/composables/useLocal.ts +38 -38
  72. package/minify.js +146 -146
  73. package/models/store/interfaces.ts +37 -37
  74. package/models/store/storage/interfaces.ts +32 -32
  75. package/models/store/types.ts +32 -32
  76. package/modules/fixContentBuild/utils/methods.ts +114 -114
  77. package/package.json +1 -1
  78. package/public/spice-console/application/codec.js +257 -257
  79. package/public/spice-console/lib/rasterEngine.js +907 -907
  80. package/public/spice-console/network/spicechannel.js +369 -369
  81. package/utils/contentBuild.ts +34 -34
@@ -1,445 +1,445 @@
1
- <template>
2
- <div class="hardware-cpu">
3
- <atoms-stack-block
4
- :has-children="true"
5
- :is-roll-back="props.type === 'removed'"
6
- :removable="isRemovable"
7
- @remove="onRemoveHardDisk"
8
- @roll-back="onRollBackHardDisk"
9
- >
10
- <template #stackBlockKey>
11
- <div class="vm-wizard-toggle-block-hard-disk flex-align-center">
12
- <span>{{ label }}</span>
13
- <atoms-the-icon
14
- v-show="hardDiskInvalid"
15
- width="24px"
16
- height="24px"
17
- class="is-error tooltip-trigger"
18
- name="info"
19
- />
20
- </div>
21
- </template>
22
- <template #stackBlockContent>
23
- <div class="flex-align-center flex-space-between mr-1">
24
- <template v-if="props.type === 'removed'">
25
- <span>{{ localization.deviceWillRemoved }}</span>
26
- <div @click.stop class="flex-align-center">
27
- <input
28
- :id="`hard-disk-delete-files-from-datastore-${props.index}`"
29
- v-model="deleteFilesFromDatastore"
30
- :disabled="props.disabled"
31
- type="checkbox"
32
- class="pointer"
33
- @click.stop
34
- />
35
- <label
36
- :for="`hard-disk-delete-files-from-datastore-${props.index}`"
37
- :class="[
38
- 'label-text-normal pointer',
39
- props.disabled && 'div-disabled',
40
- ]"
41
- >{{ localization.deleteFilesFromDatastore }}</label
42
- >
43
- </div>
44
- </template>
45
- <template v-else>
46
- <atoms-tooltip-error
47
- :has-error="!!hardDiskLocalAndApiErrorsTexts"
48
- :selector="`#vm-wizard-hard-disk-${props.index}`"
49
- @remove="
50
- emits(
51
- 'remove-error-by-title',
52
- `disk_devices[${props.index}].size`
53
- )
54
- "
55
- >
56
- <template #elem>
57
- <input
58
- :id="`vm-wizard-hard-disk-${props.index}`"
59
- v-model.number="size"
60
- type="number"
61
- :class="[
62
- 'spinfree edit-setting-input input-text-color',
63
- { 'has-error': hardDiskTypeErrorLocalText },
64
- ]"
65
- :disabled="isDisabledSize"
66
- @blur="onValidateSize"
67
- @click.stop
68
- />
69
- </template>
70
- <template #content>
71
- {{ hardDiskLocalAndApiErrorsTexts }}
72
- </template>
73
- </atoms-tooltip-error>
74
- <div class="select ml-1">
75
- <select
76
- :id="`hard-disk-type-select-${props.index}`"
77
- v-model="hardDiskType"
78
- :disabled="props.type === 'exist'"
79
- class="input-text-color"
80
- @change="onValidateSize"
81
- @click.stop
82
- >
83
- <option
84
- v-for="(item, key) in hardDiskTypeOptions"
85
- :key="key"
86
- :value="item.value"
87
- >
88
- {{ item.text }}
89
- </option>
90
- </select>
91
- </div>
92
- </template>
93
- </div>
94
- </template>
95
- <template #stackChildren>
96
- <common-vm-actions-add-customize-hardware-virtual-hardware-new-hard-disk-maximum-size
97
- :free-mb="maxHardDisk"
98
- />
99
- <common-vm-actions-add-customize-hardware-virtual-hardware-new-hard-disk-location
100
- v-if="props.type === 'new'"
101
- :location="location"
102
- :index="props.index"
103
- :error-validation-fields="props.errorValidationFields"
104
- :get-datastore-table-func="props.getDatastoreTableFunc"
105
- :datastore="props.datastore"
106
- @change="onChangeStorage"
107
- @remove-error-by-title="emits('remove-error-by-title', $event)"
108
- />
109
- <common-vm-actions-add-customize-hardware-virtual-hardware-new-hard-disk-file
110
- v-else
111
- :path="props.hardDisk?.source"
112
- />
113
- <common-vm-actions-add-customize-hardware-virtual-hardware-new-hard-disk-provisioning
114
- v-model:disk-provisioning="diskProvisioning"
115
- :index="props.index"
116
- :error-validation-fields="props.errorValidationFields"
117
- :disabled="(props.isEdit && props.type !== 'new') || isRunning"
118
- @remove-error-by-title="emits('remove-error-by-title', $event)"
119
- />
120
- <common-vm-actions-add-customize-hardware-virtual-hardware-new-hard-disk-sharing
121
- v-model:sharing="sharing"
122
- :index="props.index"
123
- :error-validation-fields="props.errorValidationFields"
124
- :disabled="isRunning && props.type !== 'new'"
125
- @remove-error-by-title="emits('remove-error-by-title', $event)"
126
- />
127
- <common-vm-actions-add-customize-hardware-virtual-hardware-new-hard-disk-limit-iops
128
- v-model:limit-iops="limitIops"
129
- v-model:limit-iops-type="limitIopsType"
130
- :index="props.index"
131
- :error-validation-fields="props.errorValidationFields"
132
- @valid="limitIopsInvalid = $event"
133
- @remove-error-by-title="emits('remove-error-by-title', $event)"
134
- />
135
- <common-vm-actions-add-customize-hardware-virtual-hardware-new-hard-disk-mode
136
- v-model:diskMode="diskMode"
137
- :index="props.index"
138
- :error-validation-fields="props.errorValidationFields"
139
- :disabled="isRunning && props.type !== 'new'"
140
- @remove-error-by-title="emits('remove-error-by-title', $event)"
141
- />
142
- <common-vm-actions-add-customize-hardware-virtual-hardware-new-hard-disk-cache
143
- v-model:cache="cache"
144
- :index="props.index"
145
- :error-validation-fields="props.errorValidationFields"
146
- :disabled="(props.isEdit && props.type !== 'new') || isRunning"
147
- @remove-error-by-title="emits('remove-error-by-title', $event)"
148
- />
149
- <common-vm-actions-add-customize-hardware-virtual-hardware-bus
150
- v-model:bus="bus"
151
- :index="props.index"
152
- :error-validation-fields="props.errorValidationFields"
153
- :disabled="isRunning"
154
- component-type="disk_devices"
155
- @remove-error-by-title="emits('remove-error-by-title', $event)"
156
- />
157
- </template>
158
- </atoms-stack-block>
159
- </div>
160
- </template>
161
-
162
- <script setup lang="ts">
163
- import { UI_I_DatastoreTableItem } from '~/models/store/storage/interfaces'
164
- import {
165
- UI_I_SendDataNewHardDisk,
166
- UI_I_SendDataNewHardDiskStorage,
167
- } from '~/components/common/vm/actions/add/customizeHardware/virtualHardware/models/interfaces'
168
- import { UI_T_HardDiskType } from '~/components/common/vm/actions/add/customizeHardware/virtualHardware/models/types'
169
- import { UI_I_Localization } from '~/models/interfaces'
170
- import {
171
- UI_I_ErrorValidationField,
172
- UI_I_TablePayload,
173
- } from '~/models/store/interfaces'
174
- import { UI_I_OptionItem } from '~/components/atoms/models/interfaces'
175
- import { binaryOptionsFunc } from '~/components/common/vm/actions/add/customizeHardware/virtualHardware/config/binaryOptions'
176
-
177
- const props = defineProps<{
178
- storage: UI_I_DatastoreTableItem | null
179
- hardDisk: UI_I_SendDataNewHardDisk
180
- type: UI_T_HardDiskType
181
- index: number
182
- errorValidationFields: UI_I_ErrorValidationField<string>[]
183
- getDatastoreTableFunc: (payload: UI_I_TablePayload) => Promise<void>
184
- datastore: UI_I_DatastoreTableItem[]
185
- isEdit: boolean
186
- state?: string | number
187
- }>()
188
- const emits = defineEmits<{
189
- (event: 'send-data', value: UI_I_SendDataNewHardDisk): void
190
- (event: 'invalid', value: boolean): void
191
- (event: 'remove'): void
192
- (event: 'roll-back'): void
193
- (event: 'remove-error-by-title', value: string): void
194
- }>()
195
-
196
- const localization = computed<UI_I_Localization>(() => useLocal())
197
-
198
- const isRunning = computed<boolean>(() => {
199
- return props.state === 2
200
- })
201
-
202
- const isRemovable = computed<boolean>(() => {
203
- return (
204
- !props.isEdit ||
205
- !isRunning.value ||
206
- (isRunning.value && bus.value === 'virtio')
207
- )
208
- })
209
-
210
- const typeError = computed<string>(() => `disk_devices[${props.index}].size`)
211
-
212
- const apiErrorLocal = computed<string>(() => {
213
- return (
214
- props.errorValidationFields?.find(
215
- (message) => message.field === typeError.value
216
- )?.error_message || ''
217
- )
218
- })
219
-
220
- const { $binary } = useNuxtApp()
221
-
222
- const label = computed<string>(() => {
223
- if (props.type === 'edit' || props.type === 'removed')
224
- return `${localization.value.hardDisk} ${props.index + 1}`
225
-
226
- return `${localization.value.newHardDisk} *`
227
- })
228
-
229
- const maxHardDisk = computed<number>(() => {
230
- if (props.type === 'exist') return $binary.gbToMb(props.hardDisk.size)
231
-
232
- if (!storage.value) return 0
233
-
234
- return storage.value.capacity.free_mb
235
- })
236
- const hardDiskTypeErrorLocalText = computed<string>(() => {
237
- if (
238
- +sizeInMb.value > maxHardDisk.value
239
- ) {
240
- return localization.value.diskCapacitySpecifiedGreater
241
- }
242
-
243
- if (+sizeInMb.value <= 0) {
244
- return localization.value.diskCapacityCannotZero
245
- }
246
-
247
- return ''
248
- })
249
-
250
- const hardDiskLocalAndApiErrorsTexts = computed<string>(() => {
251
- const localError = hardDiskTypeErrorLocalText.value
252
- const apiError = apiErrorLocal.value
253
-
254
- let result = ''
255
- if (localError && !apiError) result = localError
256
- if (!localError && apiError) result = apiError
257
- if (localError && apiError) result = localError + ', ' + apiError
258
- if (!localError && apiError) result = apiError
259
-
260
- return result
261
- })
262
-
263
- const deleteFilesFromDatastore = ref<boolean>(false)
264
-
265
- const hardDiskType = ref<string>('gb')
266
- const hardDiskTypeOptions = ref<UI_I_OptionItem[]>(
267
- binaryOptionsFunc(localization.value)
268
- )
269
-
270
- const size = ref<number>(props.hardDisk.size) // Изначально всегда приходит в gb
271
- const sizeInMb = computed<number>(() => {
272
- if (hardDiskType.value === 'mb') {
273
- return size.value
274
- }
275
-
276
- return $binary.universalFromTo(size.value, hardDiskType.value, 'mb')
277
- })
278
- const onValidateSize = (): void => {
279
- if (props.type !== 'edit') return
280
- if (sizeInMb.value < $binary.gbToMb(props.hardDisk.size)) {
281
- size.value = $binary.universalFromTo(
282
- props.hardDisk.size,
283
- 'gb',
284
- hardDiskType.value
285
- )
286
- }
287
- }
288
-
289
- const isDisabledSize = computed<boolean>(() => {
290
- return props.type === 'exist' || (props.type === 'edit' && readOnly.value)
291
- })
292
-
293
- const onRemoveHardDisk = (): void => {
294
- emits('remove')
295
- }
296
- const onRollBackHardDisk = (): void => {
297
- emits('roll-back')
298
- }
299
-
300
- const location = ref<UI_I_DatastoreTableItem | null>(props.storage || null)
301
- watch(
302
- () => props.storage,
303
- (newValue) => {
304
- location.value = newValue
305
- storage.value = newValue
306
- }
307
- )
308
- const storage = ref<UI_I_DatastoreTableItem | null>(props.storage)
309
- const onChangeStorage = (item: UI_I_DatastoreTableItem): void => {
310
- storage.value = item
311
- }
312
-
313
- const diskProvisioning = ref<string>('thick')
314
- const sharing = ref<string>('')
315
- const shares = ref<number>(0)
316
-
317
- const limitIops = ref<number>(16)
318
- const limitIopsType = ref<string>('unlimited')
319
- const limitIopsInvalid = ref<boolean>(false)
320
-
321
- const diskMode = ref<string>('dependent')
322
-
323
- const cache = ref<string>('none')
324
-
325
- const bus = ref<string>('ide')
326
-
327
- const readOnly = ref<boolean>(false)
328
-
329
- const discard = ref<string>('')
330
-
331
- const io = ref<string>('')
332
-
333
- const target = ref<string>('')
334
-
335
- watch(
336
- [
337
- sizeInMb,
338
- storage,
339
- diskProvisioning,
340
- sharing,
341
- limitIops,
342
- limitIopsType,
343
- diskMode,
344
- cache,
345
- bus,
346
- deleteFilesFromDatastore,
347
- () => props.type,
348
- ],
349
- () => {
350
- const limitIopsLocal =
351
- limitIopsType.value === 'unlimited' ? 0 : limitIops.value
352
- const storageLocal: UI_I_SendDataNewHardDiskStorage = {
353
- id: storage.value?.id || '',
354
- name: storage.value?.name || '',
355
- type: storage.value?.type_text || '',
356
- pool: storage.value?.pool_name || '',
357
- user: '',
358
- endpoint: '',
359
- password: '',
360
- protocol: '',
361
- options: '',
362
- }
363
-
364
- emits('send-data', {
365
- create: props.hardDisk.create,
366
- attach: props.hardDisk.attach,
367
- source: props.hardDisk.source,
368
- size: sizeInMb.value,
369
- bus: bus.value,
370
- target: target.value,
371
- storage: storageLocal,
372
- device_type: 'disk',
373
- provision_type: diskProvisioning.value,
374
- disk_mode: diskMode.value,
375
- sharing: sharing.value === 'yes',
376
- read_only: readOnly.value,
377
- shares: shares.value,
378
- cache: cache.value,
379
- io: io.value,
380
- limit_iops: limitIopsLocal,
381
- discard: discard.value,
382
- capacity: sizeInMb.value,
383
- boot_order: props.hardDisk.boot_order,
384
- detach: props.type === 'removed',
385
- remove: props.type === 'removed' && deleteFilesFromDatastore.value, // Проверяем если удалили диск и указали Delete files from datastore
386
- })
387
- },
388
- { immediate: true }
389
- )
390
-
391
- // Добавляем данные для редактирования
392
- watch(
393
- () => props.hardDisk,
394
- (newValue) => {
395
- if (props.type !== 'edit') return
396
-
397
- diskProvisioning.value = newValue.provision_type || 'thick'
398
- sharing.value = newValue.sharing ? 'yes' : ''
399
- shares.value = newValue.shares || 0
400
- limitIopsType.value = newValue.io === 'native' ? 'unlimited' : 'custom'
401
- limitIops.value = newValue.limit_iops || 16
402
- diskMode.value = newValue.disk_mode || 'dependent'
403
- cache.value = newValue.cache || 'none'
404
- bus.value = newValue.bus || 'ide'
405
- readOnly.value = newValue.read_only || false
406
- discard.value = newValue.discard || ''
407
- io.value = newValue.io || ''
408
- target.value = newValue.target || ''
409
- },
410
- { immediate: true }
411
- )
412
- watch(
413
- isRunning,
414
- (newValue) => {
415
- if (newValue && props.type === 'new') {
416
- bus.value = 'virtio'
417
- }
418
- },
419
- { immediate: true }
420
- )
421
-
422
- const hardDiskInvalid = computed<boolean>(() => {
423
- return !!hardDiskTypeErrorLocalText.value || limitIopsInvalid.value
424
- })
425
- watch(
426
- hardDiskInvalid,
427
- (newValue) => {
428
- emits('invalid', newValue)
429
- },
430
- { immediate: true }
431
- )
432
- </script>
433
-
434
- <style scoped lang="scss">
435
- .hardware-cpu {
436
- #hard-disk {
437
- width: 100px;
438
- -webkit-appearance: none;
439
-
440
- &.has-error {
441
- border: 1px solid #db2100;
442
- }
443
- }
444
- }
445
- </style>
1
+ <template>
2
+ <div class="hardware-cpu">
3
+ <atoms-stack-block
4
+ :has-children="true"
5
+ :is-roll-back="props.type === 'removed'"
6
+ :removable="isRemovable"
7
+ @remove="onRemoveHardDisk"
8
+ @roll-back="onRollBackHardDisk"
9
+ >
10
+ <template #stackBlockKey>
11
+ <div class="vm-wizard-toggle-block-hard-disk flex-align-center">
12
+ <span>{{ label }}</span>
13
+ <atoms-the-icon
14
+ v-show="hardDiskInvalid"
15
+ width="24px"
16
+ height="24px"
17
+ class="is-error tooltip-trigger"
18
+ name="info"
19
+ />
20
+ </div>
21
+ </template>
22
+ <template #stackBlockContent>
23
+ <div class="flex-align-center flex-space-between mr-1">
24
+ <template v-if="props.type === 'removed'">
25
+ <span>{{ localization.deviceWillRemoved }}</span>
26
+ <div @click.stop class="flex-align-center">
27
+ <input
28
+ :id="`hard-disk-delete-files-from-datastore-${props.index}`"
29
+ v-model="deleteFilesFromDatastore"
30
+ :disabled="props.disabled"
31
+ type="checkbox"
32
+ class="pointer"
33
+ @click.stop
34
+ />
35
+ <label
36
+ :for="`hard-disk-delete-files-from-datastore-${props.index}`"
37
+ :class="[
38
+ 'label-text-normal pointer',
39
+ props.disabled && 'div-disabled',
40
+ ]"
41
+ >{{ localization.deleteFilesFromDatastore }}</label
42
+ >
43
+ </div>
44
+ </template>
45
+ <template v-else>
46
+ <atoms-tooltip-error
47
+ :has-error="!!hardDiskLocalAndApiErrorsTexts"
48
+ :selector="`#vm-wizard-hard-disk-${props.index}`"
49
+ @remove="
50
+ emits(
51
+ 'remove-error-by-title',
52
+ `disk_devices[${props.index}].size`
53
+ )
54
+ "
55
+ >
56
+ <template #elem>
57
+ <input
58
+ :id="`vm-wizard-hard-disk-${props.index}`"
59
+ v-model.number="size"
60
+ type="number"
61
+ :class="[
62
+ 'spinfree edit-setting-input input-text-color',
63
+ { 'has-error': hardDiskTypeErrorLocalText },
64
+ ]"
65
+ :disabled="isDisabledSize"
66
+ @blur="onValidateSize"
67
+ @click.stop
68
+ />
69
+ </template>
70
+ <template #content>
71
+ {{ hardDiskLocalAndApiErrorsTexts }}
72
+ </template>
73
+ </atoms-tooltip-error>
74
+ <div class="select ml-1">
75
+ <select
76
+ :id="`hard-disk-type-select-${props.index}`"
77
+ v-model="hardDiskType"
78
+ :disabled="props.type === 'exist'"
79
+ class="input-text-color"
80
+ @change="onValidateSize"
81
+ @click.stop
82
+ >
83
+ <option
84
+ v-for="(item, key) in hardDiskTypeOptions"
85
+ :key="key"
86
+ :value="item.value"
87
+ >
88
+ {{ item.text }}
89
+ </option>
90
+ </select>
91
+ </div>
92
+ </template>
93
+ </div>
94
+ </template>
95
+ <template #stackChildren>
96
+ <common-vm-actions-add-customize-hardware-virtual-hardware-new-hard-disk-maximum-size
97
+ :free-mb="maxHardDisk"
98
+ />
99
+ <common-vm-actions-add-customize-hardware-virtual-hardware-new-hard-disk-location
100
+ v-if="props.type === 'new'"
101
+ :location="location"
102
+ :index="props.index"
103
+ :error-validation-fields="props.errorValidationFields"
104
+ :get-datastore-table-func="props.getDatastoreTableFunc"
105
+ :datastore="props.datastore"
106
+ @change="onChangeStorage"
107
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
108
+ />
109
+ <common-vm-actions-add-customize-hardware-virtual-hardware-new-hard-disk-file
110
+ v-else
111
+ :path="props.hardDisk?.source"
112
+ />
113
+ <common-vm-actions-add-customize-hardware-virtual-hardware-new-hard-disk-provisioning
114
+ v-model:disk-provisioning="diskProvisioning"
115
+ :index="props.index"
116
+ :error-validation-fields="props.errorValidationFields"
117
+ :disabled="(props.isEdit && props.type !== 'new') || isRunning"
118
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
119
+ />
120
+ <common-vm-actions-add-customize-hardware-virtual-hardware-new-hard-disk-sharing
121
+ v-model:sharing="sharing"
122
+ :index="props.index"
123
+ :error-validation-fields="props.errorValidationFields"
124
+ :disabled="isRunning && props.type !== 'new'"
125
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
126
+ />
127
+ <common-vm-actions-add-customize-hardware-virtual-hardware-new-hard-disk-limit-iops
128
+ v-model:limit-iops="limitIops"
129
+ v-model:limit-iops-type="limitIopsType"
130
+ :index="props.index"
131
+ :error-validation-fields="props.errorValidationFields"
132
+ @valid="limitIopsInvalid = $event"
133
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
134
+ />
135
+ <common-vm-actions-add-customize-hardware-virtual-hardware-new-hard-disk-mode
136
+ v-model:diskMode="diskMode"
137
+ :index="props.index"
138
+ :error-validation-fields="props.errorValidationFields"
139
+ :disabled="isRunning && props.type !== 'new'"
140
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
141
+ />
142
+ <common-vm-actions-add-customize-hardware-virtual-hardware-new-hard-disk-cache
143
+ v-model:cache="cache"
144
+ :index="props.index"
145
+ :error-validation-fields="props.errorValidationFields"
146
+ :disabled="(props.isEdit && props.type !== 'new') || isRunning"
147
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
148
+ />
149
+ <common-vm-actions-add-customize-hardware-virtual-hardware-bus
150
+ v-model:bus="bus"
151
+ :index="props.index"
152
+ :error-validation-fields="props.errorValidationFields"
153
+ :disabled="isRunning"
154
+ component-type="disk_devices"
155
+ @remove-error-by-title="emits('remove-error-by-title', $event)"
156
+ />
157
+ </template>
158
+ </atoms-stack-block>
159
+ </div>
160
+ </template>
161
+
162
+ <script setup lang="ts">
163
+ import { UI_I_DatastoreTableItem } from '~/models/store/storage/interfaces'
164
+ import {
165
+ UI_I_SendDataNewHardDisk,
166
+ UI_I_SendDataNewHardDiskStorage,
167
+ } from '~/components/common/vm/actions/add/customizeHardware/virtualHardware/models/interfaces'
168
+ import { UI_T_HardDiskType } from '~/components/common/vm/actions/add/customizeHardware/virtualHardware/models/types'
169
+ import { UI_I_Localization } from '~/models/interfaces'
170
+ import {
171
+ UI_I_ErrorValidationField,
172
+ UI_I_TablePayload,
173
+ } from '~/models/store/interfaces'
174
+ import { UI_I_OptionItem } from '~/components/atoms/models/interfaces'
175
+ import { binaryOptionsFunc } from '~/components/common/vm/actions/add/customizeHardware/virtualHardware/config/binaryOptions'
176
+
177
+ const props = defineProps<{
178
+ storage: UI_I_DatastoreTableItem | null
179
+ hardDisk: UI_I_SendDataNewHardDisk
180
+ type: UI_T_HardDiskType
181
+ index: number
182
+ errorValidationFields: UI_I_ErrorValidationField<string>[]
183
+ getDatastoreTableFunc: (payload: UI_I_TablePayload) => Promise<void>
184
+ datastore: UI_I_DatastoreTableItem[]
185
+ isEdit: boolean
186
+ state?: string | number
187
+ }>()
188
+ const emits = defineEmits<{
189
+ (event: 'send-data', value: UI_I_SendDataNewHardDisk): void
190
+ (event: 'invalid', value: boolean): void
191
+ (event: 'remove'): void
192
+ (event: 'roll-back'): void
193
+ (event: 'remove-error-by-title', value: string): void
194
+ }>()
195
+
196
+ const localization = computed<UI_I_Localization>(() => useLocal())
197
+
198
+ const isRunning = computed<boolean>(() => {
199
+ return props.state === 2
200
+ })
201
+
202
+ const isRemovable = computed<boolean>(() => {
203
+ return (
204
+ !props.isEdit ||
205
+ !isRunning.value ||
206
+ (isRunning.value && bus.value === 'virtio')
207
+ )
208
+ })
209
+
210
+ const typeError = computed<string>(() => `disk_devices[${props.index}].size`)
211
+
212
+ const apiErrorLocal = computed<string>(() => {
213
+ return (
214
+ props.errorValidationFields?.find(
215
+ (message) => message.field === typeError.value
216
+ )?.error_message || ''
217
+ )
218
+ })
219
+
220
+ const { $binary } = useNuxtApp()
221
+
222
+ const label = computed<string>(() => {
223
+ if (props.type === 'edit' || props.type === 'removed')
224
+ return `${localization.value.hardDisk} ${props.index + 1}`
225
+
226
+ return `${localization.value.newHardDisk} *`
227
+ })
228
+
229
+ const maxHardDisk = computed<number>(() => {
230
+ if (props.type === 'exist') return $binary.gbToMb(props.hardDisk.size)
231
+
232
+ if (!storage.value) return 0
233
+
234
+ return storage.value.capacity.free_mb
235
+ })
236
+ const hardDiskTypeErrorLocalText = computed<string>(() => {
237
+ if (
238
+ +sizeInMb.value > maxHardDisk.value
239
+ ) {
240
+ return localization.value.diskCapacitySpecifiedGreater
241
+ }
242
+
243
+ if (+sizeInMb.value <= 0) {
244
+ return localization.value.diskCapacityCannotZero
245
+ }
246
+
247
+ return ''
248
+ })
249
+
250
+ const hardDiskLocalAndApiErrorsTexts = computed<string>(() => {
251
+ const localError = hardDiskTypeErrorLocalText.value
252
+ const apiError = apiErrorLocal.value
253
+
254
+ let result = ''
255
+ if (localError && !apiError) result = localError
256
+ if (!localError && apiError) result = apiError
257
+ if (localError && apiError) result = localError + ', ' + apiError
258
+ if (!localError && apiError) result = apiError
259
+
260
+ return result
261
+ })
262
+
263
+ const deleteFilesFromDatastore = ref<boolean>(false)
264
+
265
+ const hardDiskType = ref<string>('gb')
266
+ const hardDiskTypeOptions = ref<UI_I_OptionItem[]>(
267
+ binaryOptionsFunc(localization.value)
268
+ )
269
+
270
+ const size = ref<number>(props.hardDisk.size) // Изначально всегда приходит в gb
271
+ const sizeInMb = computed<number>(() => {
272
+ if (hardDiskType.value === 'mb') {
273
+ return size.value
274
+ }
275
+
276
+ return $binary.universalFromTo(size.value, hardDiskType.value, 'mb')
277
+ })
278
+ const onValidateSize = (): void => {
279
+ if (props.type !== 'edit') return
280
+ if (sizeInMb.value < $binary.gbToMb(props.hardDisk.size)) {
281
+ size.value = $binary.universalFromTo(
282
+ props.hardDisk.size,
283
+ 'gb',
284
+ hardDiskType.value
285
+ )
286
+ }
287
+ }
288
+
289
+ const isDisabledSize = computed<boolean>(() => {
290
+ return props.type === 'exist' || (props.type === 'edit' && readOnly.value)
291
+ })
292
+
293
+ const onRemoveHardDisk = (): void => {
294
+ emits('remove')
295
+ }
296
+ const onRollBackHardDisk = (): void => {
297
+ emits('roll-back')
298
+ }
299
+
300
+ const location = ref<UI_I_DatastoreTableItem | null>(props.storage || null)
301
+ watch(
302
+ () => props.storage,
303
+ (newValue) => {
304
+ location.value = newValue
305
+ storage.value = newValue
306
+ }
307
+ )
308
+ const storage = ref<UI_I_DatastoreTableItem | null>(props.storage)
309
+ const onChangeStorage = (item: UI_I_DatastoreTableItem): void => {
310
+ storage.value = item
311
+ }
312
+
313
+ const diskProvisioning = ref<string>('thick')
314
+ const sharing = ref<string>('')
315
+ const shares = ref<number>(0)
316
+
317
+ const limitIops = ref<number>(16)
318
+ const limitIopsType = ref<string>('unlimited')
319
+ const limitIopsInvalid = ref<boolean>(false)
320
+
321
+ const diskMode = ref<string>('dependent')
322
+
323
+ const cache = ref<string>('none')
324
+
325
+ const bus = ref<string>('ide')
326
+
327
+ const readOnly = ref<boolean>(false)
328
+
329
+ const discard = ref<string>('')
330
+
331
+ const io = ref<string>('')
332
+
333
+ const target = ref<string>('')
334
+
335
+ watch(
336
+ [
337
+ sizeInMb,
338
+ storage,
339
+ diskProvisioning,
340
+ sharing,
341
+ limitIops,
342
+ limitIopsType,
343
+ diskMode,
344
+ cache,
345
+ bus,
346
+ deleteFilesFromDatastore,
347
+ () => props.type,
348
+ ],
349
+ () => {
350
+ const limitIopsLocal =
351
+ limitIopsType.value === 'unlimited' ? 0 : limitIops.value
352
+ const storageLocal: UI_I_SendDataNewHardDiskStorage = {
353
+ id: storage.value?.id || '',
354
+ name: storage.value?.name || '',
355
+ type: storage.value?.type_text || '',
356
+ pool: storage.value?.pool_name || '',
357
+ user: '',
358
+ endpoint: '',
359
+ password: '',
360
+ protocol: '',
361
+ options: '',
362
+ }
363
+
364
+ emits('send-data', {
365
+ create: props.hardDisk.create,
366
+ attach: props.hardDisk.attach,
367
+ source: props.hardDisk.source,
368
+ size: sizeInMb.value,
369
+ bus: bus.value,
370
+ target: target.value,
371
+ storage: storageLocal,
372
+ device_type: 'disk',
373
+ provision_type: diskProvisioning.value,
374
+ disk_mode: diskMode.value,
375
+ sharing: sharing.value === 'yes',
376
+ read_only: readOnly.value,
377
+ shares: shares.value,
378
+ cache: cache.value,
379
+ io: io.value,
380
+ limit_iops: limitIopsLocal,
381
+ discard: discard.value,
382
+ capacity: sizeInMb.value,
383
+ boot_order: props.hardDisk.boot_order,
384
+ detach: props.type === 'removed',
385
+ remove: props.type === 'removed' && deleteFilesFromDatastore.value, // Проверяем если удалили диск и указали Delete files from datastore
386
+ })
387
+ },
388
+ { immediate: true }
389
+ )
390
+
391
+ // Добавляем данные для редактирования
392
+ watch(
393
+ () => props.hardDisk,
394
+ (newValue) => {
395
+ if (props.type !== 'edit') return
396
+
397
+ diskProvisioning.value = newValue.provision_type || 'thick'
398
+ sharing.value = newValue.sharing ? 'yes' : ''
399
+ shares.value = newValue.shares || 0
400
+ limitIopsType.value = newValue.io === 'native' ? 'unlimited' : 'custom'
401
+ limitIops.value = newValue.limit_iops || 16
402
+ diskMode.value = newValue.disk_mode || 'dependent'
403
+ cache.value = newValue.cache || 'none'
404
+ bus.value = newValue.bus || 'ide'
405
+ readOnly.value = newValue.read_only || false
406
+ discard.value = newValue.discard || ''
407
+ io.value = newValue.io || ''
408
+ target.value = newValue.target || ''
409
+ },
410
+ { immediate: true }
411
+ )
412
+ watch(
413
+ isRunning,
414
+ (newValue) => {
415
+ if (newValue && props.type === 'new') {
416
+ bus.value = 'virtio'
417
+ }
418
+ },
419
+ { immediate: true }
420
+ )
421
+
422
+ const hardDiskInvalid = computed<boolean>(() => {
423
+ return !!hardDiskTypeErrorLocalText.value || limitIopsInvalid.value
424
+ })
425
+ watch(
426
+ hardDiskInvalid,
427
+ (newValue) => {
428
+ emits('invalid', newValue)
429
+ },
430
+ { immediate: true }
431
+ )
432
+ </script>
433
+
434
+ <style scoped lang="scss">
435
+ .hardware-cpu {
436
+ #hard-disk {
437
+ width: 100px;
438
+ -webkit-appearance: none;
439
+
440
+ &.has-error {
441
+ border: 1px solid #db2100;
442
+ }
443
+ }
444
+ }
445
+ </style>