bfg-common 1.2.170 → 1.2.172

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 (57) hide show
  1. package/assets/localization/local_be.json +9 -1
  2. package/assets/localization/local_en.json +9 -1
  3. package/assets/localization/local_hy.json +9 -1
  4. package/assets/localization/local_kk.json +9 -1
  5. package/assets/localization/local_ru.json +9 -1
  6. package/assets/localization/local_zh.json +9 -1
  7. package/assets/scss/common/icons/icons-2.scss +222 -222
  8. package/components/atoms/switch/Switch.vue +107 -107
  9. package/components/common/BadBrowser.vue +114 -114
  10. package/components/common/adapterManager/AddAdapterWarningModal.vue +82 -82
  11. package/components/common/adapterManager/NoActiveAdaptersModal.vue +62 -62
  12. package/components/common/adapterManager/NoConnectedActiveAdaptersModal.vue +62 -62
  13. package/components/common/browse/blocks/Title.vue +66 -66
  14. package/components/common/diagramMain/modals/editSettings/tabs/port/IpvFourSettings.vue +339 -339
  15. package/components/common/diagramMain/modals/editSettings/tabs/port/PortProperties.vue +202 -202
  16. package/components/common/diagramMain/modals/remove/RemoveModal.vue +226 -226
  17. package/components/common/feedback/Feedback.vue +261 -261
  18. package/components/common/feedback/VisitPortal.vue +53 -53
  19. package/components/common/help/navbar/left/utils/constructAccordion.ts +27 -27
  20. package/components/common/recursionTree/RecursionTree.vue +201 -201
  21. package/components/common/tools/Actions.vue +164 -164
  22. package/components/common/vm/actions/clone/Clone.vue +545 -545
  23. package/components/common/vm/actions/clone/select/options/Options.vue +65 -65
  24. package/components/common/vm/actions/clone/utils.ts +43 -43
  25. package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/CoresPerSocket.vue +109 -109
  26. package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/Cpu.vue +383 -383
  27. package/components/common/vm/actions/common/customizeHardware/virtualHardware/limit/Limit.vue +234 -234
  28. package/components/common/vm/actions/common/customizeHardware/virtualHardware/limit/config/options.ts +28 -28
  29. package/components/common/vm/actions/common/customizeHardware/virtualHardware/memory/Memory.vue +316 -316
  30. package/components/common/vm/actions/common/customizeHardware/virtualHardware/memory/config/memoryOptions.ts +35 -35
  31. package/components/common/vm/actions/common/customizeHardware/virtualHardware/newHardDisk/NewHardDisk.vue +447 -447
  32. package/components/common/vm/actions/common/customizeHardware/virtualHardware/newUsbController/NewUsbController.vue +12 -3
  33. package/components/common/vm/actions/common/customizeHardware/virtualHardware/reservation/Reservation.vue +235 -235
  34. package/components/common/vm/actions/common/customizeHardware/virtualHardware/videoCard/VideoCard.vue +177 -177
  35. package/components/common/vm/actions/common/customizeHardware/vmoptions/bootOptions/order/Order.vue +197 -197
  36. package/components/common/vm/actions/common/customizeHardware/vmoptions/generalOptions/GeneralOptions.vue +181 -181
  37. package/components/common/vm/actions/common/customizeHardware/vmoptions/remoteConsoleOptions/CopyPaste.vue +51 -51
  38. package/components/common/vm/actions/common/customizeHardware/vmoptions/remoteConsoleOptions/RemoteConsoleOptions.vue +253 -253
  39. package/components/common/vm/actions/common/customizeHardware/vmoptions/remoteConsoleOptions/keymap/Keymap.vue +55 -55
  40. package/components/common/vm/actions/common/select/storage/config/config.ts +154 -154
  41. package/components/common/vm/utils/powerActions.ts +55 -55
  42. package/components/common/wizards/datastore/add/nfs/kerberosAuthentication/KerberosAuthentication.vue +54 -54
  43. package/components/layout/theHeader/utils/localization.ts +32 -32
  44. package/composables/useLocal.ts +38 -38
  45. package/minify.js +146 -146
  46. package/models/composables/useMyFetch/interfaces.ts +25 -25
  47. package/models/interfaces.ts +49 -49
  48. package/models/store/interfaces.ts +37 -37
  49. package/models/store/storage/interfaces.ts +32 -32
  50. package/models/store/types.ts +43 -43
  51. package/modules/fixContentBuild/utils/methods.ts +114 -114
  52. package/package.json +1 -1
  53. package/public/spice-console/application/codec.js +257 -257
  54. package/public/spice-console/lib/rasterEngine.js +907 -907
  55. package/public/spice-console/network/spicechannel.js +369 -369
  56. package/utils/contentBuild.ts +34 -34
  57. package/utils/sendTask.ts +77 -77
@@ -1,447 +1,447 @@
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-common-customize-hardware-virtual-hardware-new-hard-disk-maximum-size
97
- :free-mb="maxHardDisk"
98
- />
99
- <common-vm-actions-common-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-common-customize-hardware-virtual-hardware-new-hard-disk-file
110
- v-else
111
- :path="props.hardDisk?.source"
112
- />
113
- <common-vm-actions-common-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-common-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-common-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-common-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-common-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-common-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/common/customizeHardware/virtualHardware/models/interfaces'
168
- import { UI_T_HardDiskType } from '~/components/common/vm/actions/common/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/common/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
- if (props.isEdit)
235
- return storage.value.capacity.free_mb + $binary.gbToMb(props.hardDisk.size)
236
-
237
- return storage.value.capacity.free_mb
238
- })
239
- const hardDiskTypeErrorLocalText = computed<string>(() => {
240
- if (+sizeInMb.value > maxHardDisk.value) {
241
- return localization.value.diskCapacitySpecifiedGreater
242
- }
243
-
244
- if (+sizeInMb.value <= 0) {
245
- return localization.value.diskCapacityCannotZero
246
- }
247
-
248
- return ''
249
- })
250
-
251
- const hardDiskLocalAndApiErrorsTexts = computed<string>(() => {
252
- const localError = hardDiskTypeErrorLocalText.value
253
- const apiError = apiErrorLocal.value
254
-
255
- let result = ''
256
- if (localError && !apiError) result = localError
257
- if (!localError && apiError) result = apiError
258
- if (localError && apiError) result = localError + ', ' + apiError
259
- if (!localError && apiError) result = apiError
260
-
261
- return result
262
- })
263
-
264
- const deleteFilesFromDatastore = ref<boolean>(false)
265
-
266
- const hardDiskType = ref<string>('gb')
267
- const hardDiskTypeOptions = ref<UI_I_OptionItem[]>(
268
- binaryOptionsFunc(localization.value)
269
- )
270
-
271
- const size = ref<number>(props.hardDisk.size) // Изначально всегда приходит в gb
272
- const sizeInMb = computed<number>(() => {
273
- if (hardDiskType.value === 'mb') {
274
- return size.value
275
- }
276
-
277
- return $binary.universalFromTo(size.value, hardDiskType.value, 'mb')
278
- })
279
- const onValidateSize = (): void => {
280
- if (props.type !== 'edit') return
281
- if (sizeInMb.value < $binary.gbToMb(props.hardDisk.size)) {
282
- size.value = $binary.universalFromTo(
283
- props.hardDisk.size,
284
- 'gb',
285
- hardDiskType.value
286
- )
287
- }
288
- }
289
-
290
- const isDisabledSize = computed<boolean>(() => {
291
- return props.type === 'exist' || (props.type === 'edit' && readOnly.value)
292
- })
293
-
294
- const onRemoveHardDisk = (): void => {
295
- emits('remove')
296
- }
297
- const onRollBackHardDisk = (): void => {
298
- emits('roll-back')
299
- }
300
-
301
- const location = ref<UI_I_DatastoreTableItem | null>(props.storage || null)
302
- watch(
303
- () => props.storage,
304
- (newValue) => {
305
- location.value = newValue
306
- storage.value = newValue
307
- }
308
- )
309
- const storage = ref<UI_I_DatastoreTableItem | null>(props.storage)
310
- const onChangeStorage = (item: UI_I_DatastoreTableItem): void => {
311
- storage.value = item
312
- }
313
-
314
- const diskProvisioning = ref<string>('thick')
315
- const sharing = ref<string>('')
316
- const shares = ref<number>(0)
317
-
318
- const limitIops = ref<number>(16)
319
- const limitIopsType = ref<string>('unlimited')
320
- const limitIopsInvalid = ref<boolean>(false)
321
-
322
- const diskMode = ref<string>('dependent')
323
-
324
- const cache = ref<string>('none')
325
-
326
- const bus = ref<string>('ide')
327
-
328
- const readOnly = ref<boolean>(false)
329
-
330
- const discard = ref<string>('')
331
-
332
- const io = ref<string>('')
333
-
334
- const target = ref<string>('')
335
-
336
- watch(
337
- [
338
- sizeInMb,
339
- storage,
340
- diskProvisioning,
341
- sharing,
342
- limitIops,
343
- limitIopsType,
344
- diskMode,
345
- cache,
346
- bus,
347
- deleteFilesFromDatastore,
348
- () => props.type,
349
- ],
350
- () => {
351
- const limitIopsLocal =
352
- limitIopsType.value === 'unlimited' ? 0 : limitIops.value
353
- const storageLocal: UI_I_SendDataNewHardDiskStorage = {
354
- id: storage.value?.id || '',
355
- name: storage.value?.name || '',
356
- type: storage.value?.type_text || '',
357
- pool: storage.value?.pool_name || '',
358
- user: '',
359
- endpoint: '',
360
- password: '',
361
- protocol: '',
362
- options: '',
363
- }
364
-
365
- emits('send-data', {
366
- create: props.hardDisk.create,
367
- attach: props.hardDisk.attach,
368
- source: props.hardDisk.source,
369
- size: Math.ceil(sizeInMb.value),
370
- bus: bus.value,
371
- target: target.value,
372
- storage: storageLocal,
373
- device_type: 'disk',
374
- provision_type: diskProvisioning.value,
375
- disk_mode: diskMode.value,
376
- sharing: sharing.value === 'yes',
377
- read_only: readOnly.value,
378
- shares: shares.value,
379
- cache: cache.value,
380
- io: io.value,
381
- limit_iops: limitIopsLocal,
382
- discard: discard.value,
383
- capacity: Math.ceil(sizeInMb.value),
384
- boot_order: props.hardDisk.boot_order,
385
- detach: props.type === 'removed',
386
- remove: props.type === 'removed' && deleteFilesFromDatastore.value, // Проверяем если удалили диск и указали Delete files from datastore
387
- })
388
- },
389
- { immediate: true }
390
- )
391
-
392
- // Добавляем данные для редактирования
393
- watch(
394
- () => props.hardDisk,
395
- (newValue) => {
396
- if (props.type !== 'edit') return
397
-
398
- diskProvisioning.value = newValue.provision_type || 'thick'
399
- sharing.value = newValue.sharing ? 'yes' : ''
400
- shares.value = newValue.shares || 0
401
- // limitIopsType.value = newValue.io === 'native' ? 'unlimited' : 'custom'
402
- limitIopsType.value = newValue.limit_iops === 0 ? 'unlimited' : 'custom'
403
- limitIops.value = newValue.limit_iops || 16
404
- diskMode.value = newValue.disk_mode || 'dependent'
405
- cache.value = newValue.cache || 'none'
406
- bus.value = newValue.bus || 'ide'
407
- readOnly.value = newValue.read_only || false
408
- discard.value = newValue.discard || ''
409
- io.value = newValue.io || ''
410
- target.value = newValue.target || ''
411
- },
412
- { immediate: true }
413
- )
414
- watch(
415
- isRunning,
416
- (newValue) => {
417
- if (newValue && props.type === 'new') {
418
- bus.value = 'virtio'
419
- }
420
- },
421
- { immediate: true }
422
- )
423
-
424
- const hardDiskInvalid = computed<boolean>(() => {
425
- return !!hardDiskTypeErrorLocalText.value || limitIopsInvalid.value
426
- })
427
- watch(
428
- hardDiskInvalid,
429
- (newValue) => {
430
- emits('invalid', newValue)
431
- },
432
- { immediate: true }
433
- )
434
- </script>
435
-
436
- <style scoped lang="scss">
437
- .hardware-cpu {
438
- #hard-disk {
439
- width: 100px;
440
- -webkit-appearance: none;
441
-
442
- &.has-error {
443
- border: 1px solid #db2100;
444
- }
445
- }
446
- }
447
- </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-common-customize-hardware-virtual-hardware-new-hard-disk-maximum-size
97
+ :free-mb="maxHardDisk"
98
+ />
99
+ <common-vm-actions-common-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-common-customize-hardware-virtual-hardware-new-hard-disk-file
110
+ v-else
111
+ :path="props.hardDisk?.source"
112
+ />
113
+ <common-vm-actions-common-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-common-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-common-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-common-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-common-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-common-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/common/customizeHardware/virtualHardware/models/interfaces'
168
+ import { UI_T_HardDiskType } from '~/components/common/vm/actions/common/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/common/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
+ if (props.isEdit)
235
+ return storage.value.capacity.free_mb + $binary.gbToMb(props.hardDisk.size)
236
+
237
+ return storage.value.capacity.free_mb
238
+ })
239
+ const hardDiskTypeErrorLocalText = computed<string>(() => {
240
+ if (+sizeInMb.value > maxHardDisk.value) {
241
+ return localization.value.diskCapacitySpecifiedGreater
242
+ }
243
+
244
+ if (+sizeInMb.value <= 0) {
245
+ return localization.value.diskCapacityCannotZero
246
+ }
247
+
248
+ return ''
249
+ })
250
+
251
+ const hardDiskLocalAndApiErrorsTexts = computed<string>(() => {
252
+ const localError = hardDiskTypeErrorLocalText.value
253
+ const apiError = apiErrorLocal.value
254
+
255
+ let result = ''
256
+ if (localError && !apiError) result = localError
257
+ if (!localError && apiError) result = apiError
258
+ if (localError && apiError) result = localError + ', ' + apiError
259
+ if (!localError && apiError) result = apiError
260
+
261
+ return result
262
+ })
263
+
264
+ const deleteFilesFromDatastore = ref<boolean>(false)
265
+
266
+ const hardDiskType = ref<string>('gb')
267
+ const hardDiskTypeOptions = ref<UI_I_OptionItem[]>(
268
+ binaryOptionsFunc(localization.value)
269
+ )
270
+
271
+ const size = ref<number>(props.hardDisk.size) // Изначально всегда приходит в gb
272
+ const sizeInMb = computed<number>(() => {
273
+ if (hardDiskType.value === 'mb') {
274
+ return size.value
275
+ }
276
+
277
+ return $binary.universalFromTo(size.value, hardDiskType.value, 'mb')
278
+ })
279
+ const onValidateSize = (): void => {
280
+ if (props.type !== 'edit') return
281
+ if (sizeInMb.value < $binary.gbToMb(props.hardDisk.size)) {
282
+ size.value = $binary.universalFromTo(
283
+ props.hardDisk.size,
284
+ 'gb',
285
+ hardDiskType.value
286
+ )
287
+ }
288
+ }
289
+
290
+ const isDisabledSize = computed<boolean>(() => {
291
+ return props.type === 'exist' || (props.type === 'edit' && readOnly.value)
292
+ })
293
+
294
+ const onRemoveHardDisk = (): void => {
295
+ emits('remove')
296
+ }
297
+ const onRollBackHardDisk = (): void => {
298
+ emits('roll-back')
299
+ }
300
+
301
+ const location = ref<UI_I_DatastoreTableItem | null>(props.storage || null)
302
+ watch(
303
+ () => props.storage,
304
+ (newValue) => {
305
+ location.value = newValue
306
+ storage.value = newValue
307
+ }
308
+ )
309
+ const storage = ref<UI_I_DatastoreTableItem | null>(props.storage)
310
+ const onChangeStorage = (item: UI_I_DatastoreTableItem): void => {
311
+ storage.value = item
312
+ }
313
+
314
+ const diskProvisioning = ref<string>('thick')
315
+ const sharing = ref<string>('')
316
+ const shares = ref<number>(0)
317
+
318
+ const limitIops = ref<number>(16)
319
+ const limitIopsType = ref<string>('unlimited')
320
+ const limitIopsInvalid = ref<boolean>(false)
321
+
322
+ const diskMode = ref<string>('dependent')
323
+
324
+ const cache = ref<string>('none')
325
+
326
+ const bus = ref<string>('ide')
327
+
328
+ const readOnly = ref<boolean>(false)
329
+
330
+ const discard = ref<string>('')
331
+
332
+ const io = ref<string>('')
333
+
334
+ const target = ref<string>('')
335
+
336
+ watch(
337
+ [
338
+ sizeInMb,
339
+ storage,
340
+ diskProvisioning,
341
+ sharing,
342
+ limitIops,
343
+ limitIopsType,
344
+ diskMode,
345
+ cache,
346
+ bus,
347
+ deleteFilesFromDatastore,
348
+ () => props.type,
349
+ ],
350
+ () => {
351
+ const limitIopsLocal =
352
+ limitIopsType.value === 'unlimited' ? 0 : limitIops.value
353
+ const storageLocal: UI_I_SendDataNewHardDiskStorage = {
354
+ id: storage.value?.id || '',
355
+ name: storage.value?.name || '',
356
+ type: storage.value?.type_text || '',
357
+ pool: storage.value?.pool_name || '',
358
+ user: '',
359
+ endpoint: '',
360
+ password: '',
361
+ protocol: '',
362
+ options: '',
363
+ }
364
+
365
+ emits('send-data', {
366
+ create: props.hardDisk.create,
367
+ attach: props.hardDisk.attach,
368
+ source: props.hardDisk.source,
369
+ size: Math.ceil(sizeInMb.value),
370
+ bus: bus.value,
371
+ target: target.value,
372
+ storage: storageLocal,
373
+ device_type: 'disk',
374
+ provision_type: diskProvisioning.value,
375
+ disk_mode: diskMode.value,
376
+ sharing: sharing.value === 'yes',
377
+ read_only: readOnly.value,
378
+ shares: shares.value,
379
+ cache: cache.value,
380
+ io: io.value,
381
+ limit_iops: limitIopsLocal,
382
+ discard: discard.value,
383
+ capacity: Math.ceil(sizeInMb.value),
384
+ boot_order: props.hardDisk.boot_order,
385
+ detach: props.type === 'removed',
386
+ remove: props.type === 'removed' && deleteFilesFromDatastore.value, // Проверяем если удалили диск и указали Delete files from datastore
387
+ })
388
+ },
389
+ { immediate: true }
390
+ )
391
+
392
+ // Добавляем данные для редактирования
393
+ watch(
394
+ () => props.hardDisk,
395
+ (newValue) => {
396
+ if (props.type !== 'edit') return
397
+
398
+ diskProvisioning.value = newValue.provision_type || 'thick'
399
+ sharing.value = newValue.sharing ? 'yes' : ''
400
+ shares.value = newValue.shares || 0
401
+ // limitIopsType.value = newValue.io === 'native' ? 'unlimited' : 'custom'
402
+ limitIopsType.value = newValue.limit_iops === 0 ? 'unlimited' : 'custom'
403
+ limitIops.value = newValue.limit_iops || 16
404
+ diskMode.value = newValue.disk_mode || 'dependent'
405
+ cache.value = newValue.cache || 'none'
406
+ bus.value = newValue.bus || 'ide'
407
+ readOnly.value = newValue.read_only || false
408
+ discard.value = newValue.discard || ''
409
+ io.value = newValue.io || ''
410
+ target.value = newValue.target || ''
411
+ },
412
+ { immediate: true }
413
+ )
414
+ watch(
415
+ isRunning,
416
+ (newValue) => {
417
+ if (newValue && props.type === 'new') {
418
+ bus.value = 'virtio'
419
+ }
420
+ },
421
+ { immediate: true }
422
+ )
423
+
424
+ const hardDiskInvalid = computed<boolean>(() => {
425
+ return !!hardDiskTypeErrorLocalText.value || limitIopsInvalid.value
426
+ })
427
+ watch(
428
+ hardDiskInvalid,
429
+ (newValue) => {
430
+ emits('invalid', newValue)
431
+ },
432
+ { immediate: true }
433
+ )
434
+ </script>
435
+
436
+ <style scoped lang="scss">
437
+ .hardware-cpu {
438
+ #hard-disk {
439
+ width: 100px;
440
+ -webkit-appearance: none;
441
+
442
+ &.has-error {
443
+ border: 1px solid #db2100;
444
+ }
445
+ }
446
+ }
447
+ </style>