bfg-common 1.5.843 → 1.5.845
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.
- package/assets/localization/local_be.json +9 -1
- package/assets/localization/local_en.json +9 -1
- package/assets/localization/local_hy.json +9 -1
- package/assets/localization/local_kk.json +9 -1
- package/assets/localization/local_ru.json +9 -1
- package/assets/localization/local_zh.json +9 -1
- package/components/common/vm/actions/add/Add.vue +3 -0
- package/components/common/vm/actions/add/New.vue +4 -0
- package/components/common/vm/actions/add/Old.vue +4 -0
- package/components/common/vm/actions/clone/Clone.vue +3 -0
- package/components/common/vm/actions/clone/new/New.vue +3 -0
- package/components/common/vm/actions/clone/old/Old.vue +3 -0
- package/components/common/vm/actions/common/customizeHardware/CustomizeHardware.vue +3 -0
- package/components/common/vm/actions/common/customizeHardware/New.vue +3 -0
- package/components/common/vm/actions/common/customizeHardware/Old.vue +3 -0
- package/components/common/vm/actions/common/customizeHardware/virtualHardware/New.vue +3 -0
- package/components/common/vm/actions/common/customizeHardware/virtualHardware/Old.vue +3 -0
- package/components/common/vm/actions/common/customizeHardware/virtualHardware/VirtualHardware.vue +3 -0
- package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/Cpu.vue +7 -0
- package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/New.vue +12 -3
- package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/Old.vue +12 -3
- package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/sa/Sa.vue +170 -0
- package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/sa/lib/utils/validation.ts +266 -0
- package/components/common/vm/actions/editSettings/EditSettings.vue +3 -0
- package/components/common/vm/actions/editSettings/Old.vue +3 -0
- package/components/common/vm/actions/lib/utils.ts +1 -0
- package/lib/utils/nums.ts +27 -0
- package/package.json +1 -1
- package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/Sa.vue +0 -106
|
@@ -3591,7 +3591,15 @@
|
|
|
3591
3591
|
"configureOptionsForCloneVm": "Наладзьце параметры запуску, аперацыйнай сістэмы і абсталявання новай віртуальнай машыны.",
|
|
3592
3592
|
"vmStoragePolicy": "Палітыка захоўвання ВМ",
|
|
3593
3593
|
"hostUsbDevice": "USB-прылада хоста",
|
|
3594
|
-
"newHostUsbDevice": "Новая USB-прылада хоста"
|
|
3594
|
+
"newHostUsbDevice": "Новая USB-прылада хоста",
|
|
3595
|
+
"emptyElement": "Пусты элемент у пазіцыі {0}",
|
|
3596
|
+
"cpuOutOfRange": "Працэсар {0} па-за дапушчальным дыяпазонам (0-{1})",
|
|
3597
|
+
"cpuDuplicate": "Працэсар {0} пазначаны больш за адзін раз",
|
|
3598
|
+
"invalidRange": "Няправільны дыяпазон: {0} (пачатковае значэнне большае за канчатковае)",
|
|
3599
|
+
"rangeStartOutOfRange": "Пачатак дыяпазону {0} па-за дапушчальным дыяпазонам (0-{1})",
|
|
3600
|
+
"rangeEndOutOfRange": "Канец дыяпазону {0} па-за дапушчальным дыяпазонам (0-{1})",
|
|
3601
|
+
"rangeDuplicate": "Працэсар {0} пазначаны больш за адзін раз",
|
|
3602
|
+
"invalidFormat": "Няправільны фармат: \"{0}\". Выкарыстоўвайце лікі (напрыклад, \"0\") або дыяпазоны (напрыклад, \"0-3\")"
|
|
3595
3603
|
},
|
|
3596
3604
|
"feedback": {
|
|
3597
3605
|
"additionalDetailsHelp": "Даведка па дадатковых звестках",
|
|
@@ -3595,7 +3595,15 @@
|
|
|
3595
3595
|
"configureOptionsForCloneVm": "Configure startup parameters, operating system, and hardware for the new virtual machine.",
|
|
3596
3596
|
"vmStoragePolicy": "VM storage policy",
|
|
3597
3597
|
"hostUsbDevice": "Host USB Device",
|
|
3598
|
-
"newHostUsbDevice": "New Host USB Device"
|
|
3598
|
+
"newHostUsbDevice": "New Host USB Device",
|
|
3599
|
+
"emptyElement": "Empty element at position {0}",
|
|
3600
|
+
"cpuOutOfRange": "Processor {0} is out of valid range (0-{1})",
|
|
3601
|
+
"cpuDuplicate": "Processor {0} is specified more than once",
|
|
3602
|
+
"invalidRange": "Invalid range: {0} (start value is greater than end value)",
|
|
3603
|
+
"rangeStartOutOfRange": "Range start {0} is out of valid range (0-{1})",
|
|
3604
|
+
"rangeEndOutOfRange": "Range end {0} is out of valid range (0-{1})",
|
|
3605
|
+
"rangeDuplicate": "Processor {0} is specified more than once",
|
|
3606
|
+
"invalidFormat": "Invalid format: \"{0}\". Use numbers (e.g., \"0\") or ranges (e.g., \"0-3\")"
|
|
3599
3607
|
},
|
|
3600
3608
|
"feedback": {
|
|
3601
3609
|
"additionalDetailsHelp": "Additional Details Help",
|
|
@@ -3595,7 +3595,15 @@
|
|
|
3595
3595
|
"configureOptionsForCloneVm": "Կարգավորեք նոր վիրտուալ մեքենայի մեկնարկային պարամետրերը, օպերացիոն համակարգը և սարքավորումները:",
|
|
3596
3596
|
"vmStoragePolicy": "ՎՄ պահպանման քաղաքականություն",
|
|
3597
3597
|
"hostUsbDevice": "Հոստի USB սարք",
|
|
3598
|
-
"newHostUsbDevice": "Հոստի նոր USB սարք"
|
|
3598
|
+
"newHostUsbDevice": "Հոստի նոր USB սարք",
|
|
3599
|
+
"emptyElement": "Դատարկ տարր {0} դիրքում",
|
|
3600
|
+
"cpuOutOfRange": "Պրոցեսոր {0} թույլատրելի տիրույթից դուրս է (0-{1})",
|
|
3601
|
+
"cpuDuplicate": "Պրոցեսոր {0}-ը նշված է մեկից ավելի անգամ",
|
|
3602
|
+
"invalidRange": "Անվավեր տիրույթ: {0} (սկզբնական արժեքը մեծ է վերջնականից)",
|
|
3603
|
+
"rangeStartOutOfRange": "Տիրույթի սկիզբ {0} թույլատրելի տիրույթից դուրս է (0-{1})",
|
|
3604
|
+
"rangeEndOutOfRange": "Տիրույթի վերջ {0} թույլատրելի տիրույթից դուրս է (0-{1})",
|
|
3605
|
+
"rangeDuplicate": "Պրոցեսոր {0}-ը նշված է մեկից ավելի անգամ",
|
|
3606
|
+
"invalidFormat": "Անվավեր ձևաչափ: \"{0}\". Օգտագործեք թվեր (օրինակ՝ \"0\") կամ տիրույթներ (օրինակ՝ \"0-3\")"
|
|
3599
3607
|
},
|
|
3600
3608
|
"feedback": {
|
|
3601
3609
|
"additionalDetailsHelp": "Լրացուցիչ մանրամասներ Օգնություն",
|
|
@@ -3594,7 +3594,15 @@
|
|
|
3594
3594
|
"configureOptionsForCloneVm": "Жаңа виртуалды машинаның іске қосу параметрлерін, операциялық жүйесін және жабдықтарын баптаңыз.",
|
|
3595
3595
|
"vmStoragePolicy": "ВМ сақтау саясаты",
|
|
3596
3596
|
"hostUsbDevice": "Хосттың USB құрылғысы",
|
|
3597
|
-
"newHostUsbDevice": "Хосттың жаңа USB құрылғысы"
|
|
3597
|
+
"newHostUsbDevice": "Хосттың жаңа USB құрылғысы",
|
|
3598
|
+
"emptyElement": "{0} позициясында бос элемент",
|
|
3599
|
+
"cpuOutOfRange": "{0} процессоры рұқсат етілген ауқымнан тыс (0-{1})",
|
|
3600
|
+
"cpuDuplicate": "{0} процессоры бірнеше рет көрсетілген",
|
|
3601
|
+
"invalidRange": "Қате ауқым: {0} (бастапқы мәні соңғы мәннен үлкен)",
|
|
3602
|
+
"rangeStartOutOfRange": "Ауқымның басы {0} рұқсат етілген ауқымнан тыс (0-{1})",
|
|
3603
|
+
"rangeEndOutOfRange": "Ауқымның соңы {0} рұқсат етілген ауқымнан тыс (0-{1})",
|
|
3604
|
+
"rangeDuplicate": "{0} процессоры бірнеше рет көрсетілген",
|
|
3605
|
+
"invalidFormat": "Қате пішім: \"{0}\". Сандарды (мысалы, \"0\") немесе ауқымдарды (мысалы, \"0-3\") пайдаланыңыз"
|
|
3598
3606
|
},
|
|
3599
3607
|
"feedback": {
|
|
3600
3608
|
"additionalDetailsHelp": "Қосымша мәліметтер анықтамасы",
|
|
@@ -3594,7 +3594,15 @@
|
|
|
3594
3594
|
"configureOptionsForCloneVm": "Настройте параметры запуска, операционной системы и оборудования новой виртуальной машины.",
|
|
3595
3595
|
"vmStoragePolicy": "Политика хранения ВМ",
|
|
3596
3596
|
"hostUsbDevice": "USB-устройство хоста",
|
|
3597
|
-
"newHostUsbDevice": "Новое USB-устройство хоста"
|
|
3597
|
+
"newHostUsbDevice": "Новое USB-устройство хоста",
|
|
3598
|
+
"emptyElement": "Пустой элемент в позиции {0}",
|
|
3599
|
+
"cpuOutOfRange": "Процессор {0} вне допустимого диапазона (0-{1})",
|
|
3600
|
+
"cpuDuplicate": "Процессор {0} указан более одного раза",
|
|
3601
|
+
"invalidRange": "Неверный диапазон: {0} (начальное значение больше конечного)",
|
|
3602
|
+
"rangeStartOutOfRange": "Начало диапазона {0} вне допустимого диапазона (0-{1})",
|
|
3603
|
+
"rangeEndOutOfRange": "Конец диапазона {0} вне допустимого диапазона (0-{1})",
|
|
3604
|
+
"rangeDuplicate": "Процессор {0} указан более одного раза",
|
|
3605
|
+
"invalidFormat": "Неверный формат: \"{0}\". Используйте числа (например, \"0\") или диапазоны (например, \"0-3\")"
|
|
3598
3606
|
},
|
|
3599
3607
|
"feedback": {
|
|
3600
3608
|
"additionalDetailsHelp": "Дополнительная информация Помощь",
|
|
@@ -3592,7 +3592,15 @@
|
|
|
3592
3592
|
"configureOptionsForCloneVm": "配置新虚拟机的启动参数、操作系统和硬件。",
|
|
3593
3593
|
"vmStoragePolicy": "虚拟机存储策略",
|
|
3594
3594
|
"hostUsbDevice": "主机USB设备",
|
|
3595
|
-
"newHostUsbDevice": "新主机USB设备"
|
|
3595
|
+
"newHostUsbDevice": "新主机USB设备",
|
|
3596
|
+
"emptyElement": "位置 {0} 处的空元素",
|
|
3597
|
+
"cpuOutOfRange": "处理器 {0} 超出有效范围 (0-{1})",
|
|
3598
|
+
"cpuDuplicate": "处理器 {0} 被多次指定",
|
|
3599
|
+
"invalidRange": "无效范围: {0} (起始值大于结束值)",
|
|
3600
|
+
"rangeStartOutOfRange": "范围起始值 {0} 超出有效范围 (0-{1})",
|
|
3601
|
+
"rangeEndOutOfRange": "范围结束值 {0} 超出有效范围 (0-{1})",
|
|
3602
|
+
"rangeDuplicate": "处理器 {0} 被多次指定",
|
|
3603
|
+
"invalidFormat": "无效格式: \"{0}\"。请使用数字(例如 \"0\")或范围(例如 \"0-3\")"
|
|
3596
3604
|
},
|
|
3597
3605
|
"feedback": {
|
|
3598
3606
|
"additionalDetailsHelp": "其他详细信息帮助",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
:is-loading="isLoading"
|
|
49
49
|
:selected-template-id="props.selectedTemplateId"
|
|
50
50
|
:validate-empty-name="props.validateEmptyName"
|
|
51
|
+
:nums="props.nums"
|
|
51
52
|
:title="title"
|
|
52
53
|
:name-request-url="props.nameRequestUrl"
|
|
53
54
|
:validation-description="validationDescription"
|
|
@@ -153,6 +154,7 @@ const props = withDefaults(
|
|
|
153
154
|
capabilities?: UI_I_Capabilities
|
|
154
155
|
vmtSettings?: UI_I_VmSettings | null
|
|
155
156
|
validateEmptyName?: boolean
|
|
157
|
+
nums?: any // для прокуратора
|
|
156
158
|
dataCenter?: UI_I_TreeNode // для сферы
|
|
157
159
|
computeResource?: UI_I_TreeNode // для сферы
|
|
158
160
|
computeResourceTree?: UI_I_TreeNode[] // для сферы
|
|
@@ -165,6 +167,7 @@ const props = withDefaults(
|
|
|
165
167
|
capabilities: undefined,
|
|
166
168
|
vmtSettings: undefined,
|
|
167
169
|
validateEmptyName: false,
|
|
170
|
+
nums: null, // для прокуратора
|
|
168
171
|
dataCenter: null,
|
|
169
172
|
computeResource: null,
|
|
170
173
|
computeResourceTree: undefined,
|
|
@@ -274,6 +274,7 @@
|
|
|
274
274
|
:mediated-devices="props.mediatedDevices"
|
|
275
275
|
:compute-resource="computeResource"
|
|
276
276
|
:compatibility-info="props.compatibilityInfo"
|
|
277
|
+
:nums="props.nums"
|
|
277
278
|
@get-storage="emits('get-storage', $event)"
|
|
278
279
|
@get-folders-or-files="emits('get-folders-or-files', $event)"
|
|
279
280
|
@get-active-device-child="
|
|
@@ -335,6 +336,7 @@
|
|
|
335
336
|
:mediated-devices="props.mediatedDevices"
|
|
336
337
|
:compute-resource="computeResource"
|
|
337
338
|
:compatibility-info="props.compatibilityInfo"
|
|
339
|
+
:nums="props.nums"
|
|
338
340
|
is-clone
|
|
339
341
|
@get-storage="emits('get-storage', $event)"
|
|
340
342
|
@get-folders-or-files="emits('get-folders-or-files', $event)"
|
|
@@ -488,6 +490,7 @@ const props = withDefaults(
|
|
|
488
490
|
validateEmptyName: boolean
|
|
489
491
|
validationDescription: string
|
|
490
492
|
nameExistValidation: string
|
|
493
|
+
nums?: any // для прокуратора
|
|
491
494
|
isShowSelectTemplate: boolean
|
|
492
495
|
title: string
|
|
493
496
|
nameRequestUrl: string
|
|
@@ -505,6 +508,7 @@ const props = withDefaults(
|
|
|
505
508
|
selectedTemplateId?: string
|
|
506
509
|
}>(),
|
|
507
510
|
{
|
|
511
|
+
nums: null,
|
|
508
512
|
isLoadingComputeTree: false,
|
|
509
513
|
computeResourceAlert: () => [],
|
|
510
514
|
compatibilityText: () => ['none', ''],
|
|
@@ -122,6 +122,7 @@
|
|
|
122
122
|
:passthrough-devices="props.passthroughDevices"
|
|
123
123
|
:mediated-devices="props.mediatedDevices"
|
|
124
124
|
:compute-resource="computeResource"
|
|
125
|
+
:nums="props.nums"
|
|
125
126
|
@get-storage="emits('get-storage', $event)"
|
|
126
127
|
@get-folders-or-files="emits('get-folders-or-files', $event)"
|
|
127
128
|
@get-active-device-child="emits('get-active-device-child', $event)"
|
|
@@ -161,6 +162,7 @@
|
|
|
161
162
|
:passthrough-devices="props.passthroughDevices"
|
|
162
163
|
:mediated-devices="props.mediatedDevices"
|
|
163
164
|
:compute-resource="computeResource"
|
|
165
|
+
:nums="props.nums"
|
|
164
166
|
is-clone
|
|
165
167
|
@get-storage="emits('get-storage', $event)"
|
|
166
168
|
@get-folders-or-files="emits('get-folders-or-files', $event)"
|
|
@@ -287,6 +289,7 @@ const props = withDefaults(
|
|
|
287
289
|
nameExistValidation: string
|
|
288
290
|
isShowPowerOn: boolean
|
|
289
291
|
validateEmptyName: boolean
|
|
292
|
+
nums?: any // для прокуратора
|
|
290
293
|
title: string
|
|
291
294
|
nameRequestUrl: string
|
|
292
295
|
nameTestIds: UI_I_NameTestIds
|
|
@@ -305,6 +308,7 @@ const props = withDefaults(
|
|
|
305
308
|
isLoadingComputeTree: false,
|
|
306
309
|
computeResourceAlert: () => [],
|
|
307
310
|
compatibilityText: () => ['none', ''],
|
|
311
|
+
nums: null,
|
|
308
312
|
dataCenter: null,
|
|
309
313
|
computeResourceTree: undefined,
|
|
310
314
|
locationNodes: () => [],
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
:compatibility-info="compatibilityInfo"
|
|
47
47
|
:max-memory="maxMemory"
|
|
48
48
|
:cpu-models="cpuModels"
|
|
49
|
+
:nums="props.nums"
|
|
49
50
|
@get-folders-or-files="emits('get-folders-or-files', $event)"
|
|
50
51
|
@change-name="onChangeName"
|
|
51
52
|
@change-storage="onChangeStorage"
|
|
@@ -137,6 +138,7 @@ const props = withDefaults(
|
|
|
137
138
|
computeResource?: UI_I_TreeNode // для сферы
|
|
138
139
|
computeResourceTree?: UI_I_TreeNode[] // для сферы
|
|
139
140
|
locationNodes?: UI_I_TreeNode[] // для сферы
|
|
141
|
+
nums: any // TODO
|
|
140
142
|
}>(),
|
|
141
143
|
{
|
|
142
144
|
capabilities: undefined,
|
|
@@ -147,6 +149,7 @@ const props = withDefaults(
|
|
|
147
149
|
computeResource: null,
|
|
148
150
|
computeResourceTree: undefined,
|
|
149
151
|
locationNodes: () => [],
|
|
152
|
+
nums: null
|
|
150
153
|
}
|
|
151
154
|
)
|
|
152
155
|
|
|
@@ -181,6 +181,7 @@
|
|
|
181
181
|
:datastore="props.datastore"
|
|
182
182
|
:is-datastore-loading="props.isDatastoreLoading"
|
|
183
183
|
:project="props.project"
|
|
184
|
+
:nums="props.nums"
|
|
184
185
|
is-clone
|
|
185
186
|
@get-storage="emits('get-storage', $event)"
|
|
186
187
|
@get-folders-or-files="emits('get-folders-or-files', $event)"
|
|
@@ -345,11 +346,13 @@ const props = withDefaults(
|
|
|
345
346
|
computeResourceAlert?: string[] // для сферы
|
|
346
347
|
compatibilityText?: [UI_T_CompatibilityStatus, string] // для сферы
|
|
347
348
|
compatibilityInfo?: string
|
|
349
|
+
nums?: any
|
|
348
350
|
}>(),
|
|
349
351
|
{
|
|
350
352
|
isLoadingComputeTree: false,
|
|
351
353
|
computeResourceAlert: () => [],
|
|
352
354
|
compatibilityText: () => ['none', ''],
|
|
355
|
+
nums: null
|
|
353
356
|
}
|
|
354
357
|
)
|
|
355
358
|
|
|
@@ -110,6 +110,7 @@
|
|
|
110
110
|
:datastore="props.datastore"
|
|
111
111
|
:is-datastore-loading="props.isDatastoreLoading"
|
|
112
112
|
:project="props.project"
|
|
113
|
+
:nums="props.nums"
|
|
113
114
|
is-clone
|
|
114
115
|
@get-storage="emits('get-storage', $event)"
|
|
115
116
|
@get-folders-or-files="emits('get-folders-or-files', $event)"
|
|
@@ -207,11 +208,13 @@ const props = withDefaults(
|
|
|
207
208
|
isLoadingComputeTree?: boolean // для сферы
|
|
208
209
|
computeResourceAlert?: string[] // для сферы
|
|
209
210
|
compatibilityText?: [UI_T_CompatibilityStatus, string] // для сферы
|
|
211
|
+
nums?: any // TODO
|
|
210
212
|
}>(),
|
|
211
213
|
{
|
|
212
214
|
isLoadingComputeTree: false,
|
|
213
215
|
computeResourceAlert: () => [],
|
|
214
216
|
compatibilityText: () => ['none', ''],
|
|
217
|
+
nums: null
|
|
215
218
|
}
|
|
216
219
|
)
|
|
217
220
|
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
:compute-resource="props.computeResource"
|
|
33
33
|
:compatibility-info="props.compatibilityInfo"
|
|
34
34
|
:is-vmt="props.isVmt"
|
|
35
|
+
:nums="props.nums"
|
|
35
36
|
@next="emits('next')"
|
|
36
37
|
@get-storage="emits('get-storage', $event)"
|
|
37
38
|
@get-folders-or-files="emits('get-folders-or-files', $event)"
|
|
@@ -109,6 +110,7 @@ const props = withDefaults(
|
|
|
109
110
|
computeResource?: UI_I_TreeNode | null
|
|
110
111
|
compatibilityInfo?: string
|
|
111
112
|
isVmt?: boolean
|
|
113
|
+
nums?: any // для прокуратора
|
|
112
114
|
}>(),
|
|
113
115
|
{
|
|
114
116
|
vmCpuHelpTextSecond: undefined,
|
|
@@ -128,6 +130,7 @@ const props = withDefaults(
|
|
|
128
130
|
computeResource: undefined,
|
|
129
131
|
compatibilityInfo: undefined,
|
|
130
132
|
isVmt: undefined,
|
|
133
|
+
nums: null
|
|
131
134
|
}
|
|
132
135
|
)
|
|
133
136
|
const emits = defineEmits<{
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
:guest-machine-type="model.machine_type"
|
|
53
53
|
:computeResource="props.computeResource"
|
|
54
54
|
:compatibility-info="props.compatibilityInfo"
|
|
55
|
+
:nums="props.nums"
|
|
55
56
|
@get-storage="emits('get-storage', $event)"
|
|
56
57
|
@get-folders-or-files="emits('get-folders-or-files', $event)"
|
|
57
58
|
@get-active-device-child="emits('get-active-device-child', $event)"
|
|
@@ -145,6 +146,7 @@ const props = withDefaults(
|
|
|
145
146
|
computeResource?: UI_I_TreeNode | null
|
|
146
147
|
compatibilityInfo?: string
|
|
147
148
|
isVmt?: boolean
|
|
149
|
+
nums?: any // для прокуратора
|
|
148
150
|
}>(),
|
|
149
151
|
{
|
|
150
152
|
state: undefined,
|
|
@@ -163,6 +165,7 @@ const props = withDefaults(
|
|
|
163
165
|
computeResource: undefined,
|
|
164
166
|
compatibilityInfo: undefined,
|
|
165
167
|
isVmt: false,
|
|
168
|
+
nums: null
|
|
166
169
|
}
|
|
167
170
|
)
|
|
168
171
|
const emits = defineEmits<{
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
:project="props.project"
|
|
38
38
|
:guest-machine-type="model.machine_type"
|
|
39
39
|
:compute-resource="props.computeResource"
|
|
40
|
+
:nums="props.nums"
|
|
40
41
|
@get-storage="emits('get-storage', $event)"
|
|
41
42
|
@get-folders-or-files="emits('get-folders-or-files', $event)"
|
|
42
43
|
@get-active-device-child="emits('get-active-device-child', $event)"
|
|
@@ -126,6 +127,7 @@ const props = withDefaults(
|
|
|
126
127
|
getDatastoreTableFunc?: (payload: UI_I_TablePayload) => Promise<void>
|
|
127
128
|
computeResource?: UI_I_TreeNode | null
|
|
128
129
|
isVmt?: boolean
|
|
130
|
+
nums?: any // для прокуратора
|
|
129
131
|
}>(),
|
|
130
132
|
{
|
|
131
133
|
state: undefined,
|
|
@@ -143,6 +145,7 @@ const props = withDefaults(
|
|
|
143
145
|
getDatastoreTableFunc: undefined,
|
|
144
146
|
computeResource: undefined,
|
|
145
147
|
isVmt: false,
|
|
148
|
+
nums: null
|
|
146
149
|
}
|
|
147
150
|
)
|
|
148
151
|
const emits = defineEmits<{
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
:state="props.state"
|
|
41
41
|
:error-validation-fields="props.errorValidationFields"
|
|
42
42
|
:vm-cpu-help-text-second="props.vmCpuHelpTextSecond"
|
|
43
|
+
:nums="props.nums"
|
|
43
44
|
@remove-error-by-title="emits('remove-error-by-title', $event)"
|
|
44
45
|
@invalid="cpuInvalid = $event"
|
|
45
46
|
/>
|
|
@@ -357,6 +358,7 @@ const props = withDefaults(
|
|
|
357
358
|
vmCpuHelpTextSecond?: string
|
|
358
359
|
computeResource?: UI_I_TreeNode | null
|
|
359
360
|
compatibilityInfo?: string
|
|
361
|
+
nums?: any // для прокуратора
|
|
360
362
|
}>(),
|
|
361
363
|
{
|
|
362
364
|
cpu: undefined,
|
|
@@ -368,6 +370,7 @@ const props = withDefaults(
|
|
|
368
370
|
vmCpuHelpTextSecond: undefined,
|
|
369
371
|
computeResource: undefined,
|
|
370
372
|
compatibilityInfo: undefined,
|
|
373
|
+
nums: null
|
|
371
374
|
}
|
|
372
375
|
)
|
|
373
376
|
const emits = defineEmits<{
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
:state="props.state"
|
|
19
19
|
:error-validation-fields="props.errorValidationFields"
|
|
20
20
|
:vm-cpu-help-text-second="props.vmCpuHelpTextSecond"
|
|
21
|
+
:nums="props.nums"
|
|
21
22
|
@remove-error-by-title="emits('remove-error-by-title', $event)"
|
|
22
23
|
@invalid="cpuInvalid = $event"
|
|
23
24
|
/>
|
|
@@ -330,6 +331,7 @@ const props = withDefaults(
|
|
|
330
331
|
mediatedDevices?: UI_I_MediatedDevice[]
|
|
331
332
|
vmCpuHelpTextSecond?: string
|
|
332
333
|
computeResource?: UI_I_TreeNode | null
|
|
334
|
+
nums?: any // для прокуратора
|
|
333
335
|
}>(),
|
|
334
336
|
{
|
|
335
337
|
cpu: undefined,
|
|
@@ -340,6 +342,7 @@ const props = withDefaults(
|
|
|
340
342
|
mediatedDevices: () => [],
|
|
341
343
|
vmCpuHelpTextSecond: undefined,
|
|
342
344
|
computeResource: undefined,
|
|
345
|
+
nums: null
|
|
343
346
|
}
|
|
344
347
|
)
|
|
345
348
|
const emits = defineEmits<{
|
package/components/common/vm/actions/common/customizeHardware/virtualHardware/VirtualHardware.vue
CHANGED
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
:compute-resource="props.computeResource"
|
|
41
41
|
:compatibility-info="props.compatibilityInfo"
|
|
42
42
|
:network-value-prop="networkValueProp"
|
|
43
|
+
:nums="props.nums"
|
|
43
44
|
@add-device="onAddDevice"
|
|
44
45
|
@get-storage="emits('get-storage', $event)"
|
|
45
46
|
@remove-network="onRemoveNetwork"
|
|
@@ -128,6 +129,7 @@ const props = withDefaults(
|
|
|
128
129
|
guestMachineType?: UI_I_OptionItem | null
|
|
129
130
|
computeResource?: UI_I_TreeNode | null
|
|
130
131
|
compatibilityInfo?: string
|
|
132
|
+
nums?: any // для прокуратора
|
|
131
133
|
}>(),
|
|
132
134
|
{
|
|
133
135
|
state: undefined,
|
|
@@ -142,6 +144,7 @@ const props = withDefaults(
|
|
|
142
144
|
guestMachineType: undefined,
|
|
143
145
|
computeResource: undefined,
|
|
144
146
|
compatibilityInfo: undefined,
|
|
147
|
+
nums: null
|
|
145
148
|
}
|
|
146
149
|
)
|
|
147
150
|
const emits = defineEmits<{
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
v-model:cpu-model="cpuModel"
|
|
12
12
|
v-model:passthrough-host-cpu="passthroughHostCpu"
|
|
13
13
|
v-model:host-model-cpu="hostModelCpu"
|
|
14
|
+
v-model:scheduling-affinity="model.cpu.scheduling_affinity"
|
|
14
15
|
:cpu-models="props.cpuModels"
|
|
15
16
|
:is-edit="props.isEdit"
|
|
16
17
|
:error-validation-fields="props.errorValidationFields"
|
|
@@ -23,12 +24,14 @@
|
|
|
23
24
|
:enable-cpu-hot-add-disabled="enableCpuHotAddDisabled"
|
|
24
25
|
:max-cpu-options="maxCpuOptions"
|
|
25
26
|
:vm-cpu-help-text-second="vmCpuHelpTextSecond"
|
|
27
|
+
:nums="props.nums"
|
|
26
28
|
@remove-error-by-title="emits('remove-error-by-title', $event)"
|
|
27
29
|
@remove-validation-error="onRemoveValidationError"
|
|
28
30
|
@max-cpu-invalid="maxCpuInvalid = $event"
|
|
29
31
|
@reservation-invalid="reservationInvalid = $event"
|
|
30
32
|
@limit-invalid="limitInvalid = $event"
|
|
31
33
|
@shares-invalid="sharesInvalid = $event"
|
|
34
|
+
@sa-invalid="saInvalid = $event"
|
|
32
35
|
/>
|
|
33
36
|
</template>
|
|
34
37
|
|
|
@@ -49,9 +52,11 @@ const props = withDefaults(
|
|
|
49
52
|
errorValidationFields: UI_I_ErrorValidationField[]
|
|
50
53
|
vmCpuHelpTextSecond?: string
|
|
51
54
|
state?: string | number
|
|
55
|
+
nums?: any // для прокуратора
|
|
52
56
|
}>(),
|
|
53
57
|
{
|
|
54
58
|
state: undefined,
|
|
59
|
+
nums: null
|
|
55
60
|
}
|
|
56
61
|
)
|
|
57
62
|
const emits = defineEmits<{
|
|
@@ -192,6 +197,7 @@ const vcpusLocalAndApiErrorsTexts = computed<string>(() => {
|
|
|
192
197
|
const reservationInvalid = ref<boolean>(false)
|
|
193
198
|
const limitInvalid = ref<boolean>(false)
|
|
194
199
|
const sharesInvalid = ref<boolean>(false)
|
|
200
|
+
const saInvalid = ref<boolean>(false)
|
|
195
201
|
const maxCpuInvalid = ref<boolean>(false)
|
|
196
202
|
const cpuInvalid = computed<boolean>(
|
|
197
203
|
() =>
|
|
@@ -199,6 +205,7 @@ const cpuInvalid = computed<boolean>(
|
|
|
199
205
|
reservationInvalid.value ||
|
|
200
206
|
limitInvalid.value ||
|
|
201
207
|
sharesInvalid.value ||
|
|
208
|
+
saInvalid.value ||
|
|
202
209
|
(model.value.cpu.hotplug &&
|
|
203
210
|
// model.value.cpu.vcpus < model.value.cpu.max_vcpus && // pc-1766
|
|
204
211
|
maxCpuInvalid.value)
|
|
@@ -125,9 +125,12 @@
|
|
|
125
125
|
<!-- <common-vm-actions-common-customize-hardware-virtual-hardware-cpu-pc-->
|
|
126
126
|
<!-- v-models:performanceCounters="performanceCounters"-->
|
|
127
127
|
<!-- />-->
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
<common-vm-actions-common-customize-hardware-virtual-hardware-cpu-sa
|
|
129
|
+
v-model="schedulingAffinity"
|
|
130
|
+
:nums="props.nums"
|
|
131
|
+
@invalid="emits('sa-invalid', $event)"
|
|
132
|
+
@remove-error-by-title="emits('remove-error-by-title', $event)"
|
|
133
|
+
/>
|
|
131
134
|
<!-- <common-vm-actions-common-customize-hardware-virtual-hardware-cpu-iommu-->
|
|
132
135
|
<!-- v-models:iommu="iommu"-->
|
|
133
136
|
<!-- />-->
|
|
@@ -162,6 +165,9 @@ const limit = defineModel<string>('limit', { required: true })
|
|
|
162
165
|
const limitType = defineModel<string>('limitType', { required: true })
|
|
163
166
|
const shares = defineModel<string>('shares', { required: true })
|
|
164
167
|
const sharesType = defineModel<string>('sharesType', { required: true })
|
|
168
|
+
const schedulingAffinity = defineModel<string>('schedulingAffinity', {
|
|
169
|
+
required: true,
|
|
170
|
+
})
|
|
165
171
|
const cpuModel = defineModel<string>('cpuModel', { required: true })
|
|
166
172
|
const passthroughHostCpu = defineModel<boolean>('passthroughHostCpu', {
|
|
167
173
|
required: true,
|
|
@@ -183,9 +189,11 @@ const props = withDefaults(
|
|
|
183
189
|
enableCpuHotAddDisabled: boolean
|
|
184
190
|
maxCpuOptions: UI_I_OptionItem[]
|
|
185
191
|
vmCpuHelpTextSecond?: string
|
|
192
|
+
nums?: any // для прокуратора
|
|
186
193
|
}>(),
|
|
187
194
|
{
|
|
188
195
|
vmCpuHelpTextSecond: undefined,
|
|
196
|
+
nums: null
|
|
189
197
|
}
|
|
190
198
|
)
|
|
191
199
|
const emits = defineEmits<{
|
|
@@ -195,6 +203,7 @@ const emits = defineEmits<{
|
|
|
195
203
|
(event: 'reservation-invalid', value: boolean): void
|
|
196
204
|
(event: 'limit-invalid', value: boolean): void
|
|
197
205
|
(event: 'shares-invalid', value: boolean): void
|
|
206
|
+
(event: 'sa-invalid', value: boolean): void
|
|
198
207
|
}>()
|
|
199
208
|
|
|
200
209
|
const localization = computed<UI_I_Localization>(() => useLocal())
|
|
@@ -103,9 +103,12 @@
|
|
|
103
103
|
<!-- <common-vm-actions-common-customize-hardware-virtual-hardware-cpu-pc-->
|
|
104
104
|
<!-- v-models:performanceCounters="performanceCounters"-->
|
|
105
105
|
<!-- />-->
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
<common-vm-actions-common-customize-hardware-virtual-hardware-cpu-sa
|
|
107
|
+
v-model="schedulingAffinity"
|
|
108
|
+
:nums="props.nums"
|
|
109
|
+
@invalid="emits('sa-invalid', $event)"
|
|
110
|
+
@remove-error-by-title="emits('remove-error-by-title', $event)"
|
|
111
|
+
/>
|
|
109
112
|
<!-- <common-vm-actions-common-customize-hardware-virtual-hardware-cpu-iommu-->
|
|
110
113
|
<!-- v-models:iommu="iommu"-->
|
|
111
114
|
<!-- />-->
|
|
@@ -141,6 +144,9 @@ const limit = defineModel<string>('limit', { required: true })
|
|
|
141
144
|
const limitType = defineModel<string>('limitType', { required: true })
|
|
142
145
|
const shares = defineModel<string>('shares', { required: true })
|
|
143
146
|
const sharesType = defineModel<string>('sharesType', { required: true })
|
|
147
|
+
const schedulingAffinity = defineModel<string>('schedulingAffinity', {
|
|
148
|
+
required: true,
|
|
149
|
+
})
|
|
144
150
|
const cpuModel = defineModel<string>('cpuModel', { required: true })
|
|
145
151
|
const passthroughHostCpu = defineModel<boolean>('passthroughHostCpu', {
|
|
146
152
|
required: true,
|
|
@@ -162,9 +168,11 @@ const props = withDefaults(
|
|
|
162
168
|
enableCpuHotAddDisabled: boolean
|
|
163
169
|
maxCpuOptions: UI_I_OptionItem[]
|
|
164
170
|
vmCpuHelpTextSecond?: string
|
|
171
|
+
nums?: any // для прокуратора
|
|
165
172
|
}>(),
|
|
166
173
|
{
|
|
167
174
|
vmCpuHelpTextSecond: undefined,
|
|
175
|
+
nums: null
|
|
168
176
|
}
|
|
169
177
|
)
|
|
170
178
|
const emits = defineEmits<{
|
|
@@ -174,6 +182,7 @@ const emits = defineEmits<{
|
|
|
174
182
|
(event: 'reservation-invalid', value: boolean): void
|
|
175
183
|
(event: 'limit-invalid', value: boolean): void
|
|
176
184
|
(event: 'shares-invalid', value: boolean): void
|
|
185
|
+
(event: 'sa-invalid', value: boolean): void
|
|
177
186
|
}>()
|
|
178
187
|
|
|
179
188
|
const localization = computed<UI_I_Localization>(() => useLocal())
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="">
|
|
3
|
+
<atoms-stack-block :has-children="false">
|
|
4
|
+
<template #stackBlockKey>
|
|
5
|
+
{{ localization.common.schedulingAffinity }}
|
|
6
|
+
</template>
|
|
7
|
+
<template #stackBlockContent>
|
|
8
|
+
<div class="flex-space-between">
|
|
9
|
+
<div class="flex-align-center">
|
|
10
|
+
<atoms-tooltip-error
|
|
11
|
+
:has-error="!!errorText"
|
|
12
|
+
selector="#sa-edit-setting-input"
|
|
13
|
+
@remove="onRemoveValidationError"
|
|
14
|
+
>
|
|
15
|
+
<template #elem>
|
|
16
|
+
<input
|
|
17
|
+
id="sa-edit-setting-input"
|
|
18
|
+
v-model="schedulingAffinity"
|
|
19
|
+
data-id="sa-edit-setting-input"
|
|
20
|
+
type="text"
|
|
21
|
+
class="edit-setting-input"
|
|
22
|
+
@blur="onBlur"
|
|
23
|
+
/>
|
|
24
|
+
</template>
|
|
25
|
+
<template #content>{{ errorText }}</template>
|
|
26
|
+
</atoms-tooltip-error>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<div id="sa-help-icon">
|
|
30
|
+
<atoms-the-icon
|
|
31
|
+
fill="#0072a3"
|
|
32
|
+
width="24px"
|
|
33
|
+
height="24px"
|
|
34
|
+
name="info-circle"
|
|
35
|
+
data-id="show-sa-help-icon"
|
|
36
|
+
@click.stop="isShowSaHelp = !isShowSaHelp"
|
|
37
|
+
/>
|
|
38
|
+
<Teleport to="body">
|
|
39
|
+
<atoms-tooltip-signpost
|
|
40
|
+
v-if="isShowSaHelp"
|
|
41
|
+
elem-id="sa-help-icon"
|
|
42
|
+
@hide="isShowSaHelp = false"
|
|
43
|
+
>
|
|
44
|
+
<h3 class="sa-help-title">
|
|
45
|
+
{{ localization.mainNavigation.help }}
|
|
46
|
+
</h3>
|
|
47
|
+
|
|
48
|
+
<p class="sa-help-text">
|
|
49
|
+
{{ localization.common.schedulingAffinityHelpDescription1 }}
|
|
50
|
+
</p>
|
|
51
|
+
<p class="sa-help-text">
|
|
52
|
+
{{ localization.common.schedulingAffinityHelpDescription2 }}
|
|
53
|
+
</p>
|
|
54
|
+
<p class="sa-help-text">
|
|
55
|
+
{{ localization.common.schedulingAffinityHelpDescription3 }}
|
|
56
|
+
</p>
|
|
57
|
+
<p class="sa-help-text">
|
|
58
|
+
<strong
|
|
59
|
+
>{{ localization.common.hyperthreadingStatus }}:
|
|
60
|
+
</strong>
|
|
61
|
+
{{ localization.common.inactive }}
|
|
62
|
+
</p>
|
|
63
|
+
<!-- <p class="sa-help-text">-->
|
|
64
|
+
<!-- <strong>{{ localization.common.availableCpus }}: </strong>-->
|
|
65
|
+
<!-- 8({{ localization.common.physicalCpus }})-->
|
|
66
|
+
<!-- </p>-->
|
|
67
|
+
<div
|
|
68
|
+
v-for="item in numsLocal"
|
|
69
|
+
:key="item.label"
|
|
70
|
+
class="sa-help-text"
|
|
71
|
+
>
|
|
72
|
+
<strong>{{ item.label }} </strong>
|
|
73
|
+
<p>{{ item.value }}</p>
|
|
74
|
+
</div>
|
|
75
|
+
</atoms-tooltip-signpost>
|
|
76
|
+
</Teleport>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</template>
|
|
80
|
+
</atoms-stack-block>
|
|
81
|
+
</div>
|
|
82
|
+
</template>
|
|
83
|
+
|
|
84
|
+
<script setup lang="ts">
|
|
85
|
+
import type { UI_I_Localization } from '~/lib/models/interfaces'
|
|
86
|
+
import { validateAffinityInput } from '~/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/sa/lib/utils/validation'
|
|
87
|
+
import { groupConsecutiveNumbers } from '~/lib/utils/nums'
|
|
88
|
+
|
|
89
|
+
const localization = computed<UI_I_Localization>(() => useLocal())
|
|
90
|
+
|
|
91
|
+
const schedulingAffinity = defineModel<string>({
|
|
92
|
+
required: true,
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const props = defineProps<{
|
|
96
|
+
nums: any // для прокуратора
|
|
97
|
+
}>()
|
|
98
|
+
const emits = defineEmits<{
|
|
99
|
+
(event: 'invalid', value: boolean): void
|
|
100
|
+
(event: 'remove-error-by-title', value: string): void
|
|
101
|
+
}>()
|
|
102
|
+
|
|
103
|
+
const isShowSaHelp = ref<boolean>(false)
|
|
104
|
+
|
|
105
|
+
const numsLocal = computed<any>(() => {
|
|
106
|
+
const cpuTopology = []
|
|
107
|
+
for (const key in props.nums.cpu) {
|
|
108
|
+
cpuTopology.push({
|
|
109
|
+
label: `CPU NUMA ${+key + 1}`,
|
|
110
|
+
value:
|
|
111
|
+
'cores: ' +
|
|
112
|
+
groupConsecutiveNumbers(props.nums.cpu[key]) +
|
|
113
|
+
'; memory: ' +
|
|
114
|
+
props.nums.ram[key],
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
return cpuTopology
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
const errorText = ref<string>('')
|
|
121
|
+
const onBlur = (): void => {
|
|
122
|
+
const cpuNums = []
|
|
123
|
+
for (const key in props.nums.cpu) {
|
|
124
|
+
cpuNums.push(...props.nums.cpu[key])
|
|
125
|
+
}
|
|
126
|
+
const validation = validateAffinityInput(
|
|
127
|
+
schedulingAffinity.value,
|
|
128
|
+
localization.value,
|
|
129
|
+
cpuNums
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
errorText.value = ''
|
|
133
|
+
|
|
134
|
+
if (!validation.isValid) {
|
|
135
|
+
errorText.value = validation.error
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const isInvalid = computed<boolean>(() => !!errorText.value)
|
|
140
|
+
watch(
|
|
141
|
+
isInvalid,
|
|
142
|
+
(newValue) => {
|
|
143
|
+
emits('invalid', newValue)
|
|
144
|
+
},
|
|
145
|
+
{ immediate: true }
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
const onRemoveValidationError = (): void => {
|
|
149
|
+
emits('remove-error-by-title', 'cpu.temp') // TODO
|
|
150
|
+
}
|
|
151
|
+
</script>
|
|
152
|
+
|
|
153
|
+
<style scoped lang="scss">
|
|
154
|
+
h3.sa-help-title {
|
|
155
|
+
margin-top: 7px;
|
|
156
|
+
font-size: 22px;
|
|
157
|
+
color: #565656;
|
|
158
|
+
}
|
|
159
|
+
p.sa-help-text {
|
|
160
|
+
width: 310px;
|
|
161
|
+
margin-top: 24px;
|
|
162
|
+
font-size: 14px;
|
|
163
|
+
color: #565656;
|
|
164
|
+
}
|
|
165
|
+
p.sa-help-text strong {
|
|
166
|
+
font-size: 14px;
|
|
167
|
+
font-weight: bold;
|
|
168
|
+
color: #565656;
|
|
169
|
+
}
|
|
170
|
+
</style>
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
// import type { UI_I_Localization } from '~/lib/models/interfaces'
|
|
2
|
+
//
|
|
3
|
+
// export const validateAffinityInput = (
|
|
4
|
+
// inputValue: string,
|
|
5
|
+
// localization: UI_I_Localization,
|
|
6
|
+
// availableCPUs = 8
|
|
7
|
+
// ): any => {
|
|
8
|
+
// // Очищаем строку от пробелов
|
|
9
|
+
// const cleanedInput = inputValue.trim()
|
|
10
|
+
//
|
|
11
|
+
// // Если строка пустая - привязка очищается (валидно)
|
|
12
|
+
// if (cleanedInput === '') {
|
|
13
|
+
// return {
|
|
14
|
+
// isValid: true,
|
|
15
|
+
// processors: [],
|
|
16
|
+
// error: null,
|
|
17
|
+
// }
|
|
18
|
+
// }
|
|
19
|
+
//
|
|
20
|
+
// // Разделяем по запятым
|
|
21
|
+
// const parts = cleanedInput.split(',')
|
|
22
|
+
// const processors = new Set()
|
|
23
|
+
// const errors = []
|
|
24
|
+
//
|
|
25
|
+
// // Регулярное выражение для проверки формата
|
|
26
|
+
// const singleRegex = /^\s*\d+\s*$/
|
|
27
|
+
// const rangeRegex = /^\s*(\d+)\s*-\s*(\d+)\s*$/
|
|
28
|
+
//
|
|
29
|
+
// for (let i = 0; i < parts.length; i++) {
|
|
30
|
+
// const part = parts[i].trim()
|
|
31
|
+
//
|
|
32
|
+
// if (part === '') {
|
|
33
|
+
// errors.push(localization.vmWizard.emptyElement.replace('{0}', `${i + 1}`))
|
|
34
|
+
// continue
|
|
35
|
+
// }
|
|
36
|
+
//
|
|
37
|
+
// // Проверяем, является ли часть одиночным числом
|
|
38
|
+
// if (singleRegex.test(part)) {
|
|
39
|
+
// const cpuNum = parseInt(part, 10)
|
|
40
|
+
//
|
|
41
|
+
// if (cpuNum < 0 || cpuNum >= availableCPUs) {
|
|
42
|
+
// errors.push(
|
|
43
|
+
// localization.vmWizard.cpuOutOfRange
|
|
44
|
+
// .replace('{0}', `${cpuNum}`)
|
|
45
|
+
// .replace('{1}', `${availableCPUs - 1}`)
|
|
46
|
+
// )
|
|
47
|
+
// continue
|
|
48
|
+
// }
|
|
49
|
+
//
|
|
50
|
+
// if (processors.has(cpuNum)) {
|
|
51
|
+
// errors.push(
|
|
52
|
+
// localization.vmWizard.cpuDuplicate.replace('{0}', `${cpuNum}`)
|
|
53
|
+
// )
|
|
54
|
+
// continue
|
|
55
|
+
// }
|
|
56
|
+
//
|
|
57
|
+
// processors.add(cpuNum)
|
|
58
|
+
// }
|
|
59
|
+
// // Проверяем, является ли часть диапазоном
|
|
60
|
+
// else if (rangeRegex.test(part)) {
|
|
61
|
+
// const match = part.match(rangeRegex)
|
|
62
|
+
// const start = parseInt(match[1], 10)
|
|
63
|
+
// const end = parseInt(match[2], 10)
|
|
64
|
+
//
|
|
65
|
+
// if (start > end) {
|
|
66
|
+
// errors.push(
|
|
67
|
+
// localization.vmWizard.invalidRange.replace('{0}', `${part}`)
|
|
68
|
+
// )
|
|
69
|
+
// continue
|
|
70
|
+
// }
|
|
71
|
+
//
|
|
72
|
+
// if (start < 0 || start >= availableCPUs) {
|
|
73
|
+
// errors.push(
|
|
74
|
+
// localization.vmWizard.rangeStartOutOfRange
|
|
75
|
+
// .replace('{0}', `${start}`)
|
|
76
|
+
// .replace('{1}', `${availableCPUs - 1}`)
|
|
77
|
+
// )
|
|
78
|
+
// continue
|
|
79
|
+
// }
|
|
80
|
+
//
|
|
81
|
+
// if (end < 0 || end >= availableCPUs) {
|
|
82
|
+
// errors.push(
|
|
83
|
+
// localization.vmWizard.rangeEndOutOfRange
|
|
84
|
+
// .replace('{0}', `${end}`)
|
|
85
|
+
// .replace('{1}', `${availableCPUs - 1}`)
|
|
86
|
+
// )
|
|
87
|
+
// continue
|
|
88
|
+
// }
|
|
89
|
+
//
|
|
90
|
+
// // Добавляем все процессоры из диапазона
|
|
91
|
+
// for (let cpu = start; cpu <= end; cpu++) {
|
|
92
|
+
// if (processors.has(cpu)) {
|
|
93
|
+
// errors.push(
|
|
94
|
+
// localization.vmWizard.rangeDuplicate.replace('{0}', `${cpu}`)
|
|
95
|
+
// )
|
|
96
|
+
// } else {
|
|
97
|
+
// processors.add(cpu)
|
|
98
|
+
// }
|
|
99
|
+
// }
|
|
100
|
+
// }
|
|
101
|
+
// // Неизвестный формат
|
|
102
|
+
// else {
|
|
103
|
+
// errors.push(localization.vmWizard.invalidFormat.replace('{0}', `${part}`))
|
|
104
|
+
// }
|
|
105
|
+
// }
|
|
106
|
+
//
|
|
107
|
+
// return {
|
|
108
|
+
// processors, // TODO remove this one
|
|
109
|
+
// isValid: errors.length === 0,
|
|
110
|
+
// error: errors.length > 0 ? errors.join('; ') : null,
|
|
111
|
+
// }
|
|
112
|
+
// }
|
|
113
|
+
|
|
114
|
+
import type { UI_I_Localization } from '~/lib/models/interfaces'
|
|
115
|
+
import {groupConsecutiveNumbers} from "~/lib/utils/nums";
|
|
116
|
+
|
|
117
|
+
export const validateAffinityInput = (
|
|
118
|
+
inputValue: string,
|
|
119
|
+
localization: UI_I_Localization,
|
|
120
|
+
availableCPUs: number[] = []
|
|
121
|
+
): any => {
|
|
122
|
+
const cleanedInput = inputValue?.trim() || ''
|
|
123
|
+
|
|
124
|
+
if (cleanedInput === '') {
|
|
125
|
+
return {
|
|
126
|
+
isValid: true,
|
|
127
|
+
processors: [],
|
|
128
|
+
error: null,
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const availableCPUSet = new Set(availableCPUs)
|
|
133
|
+
// const maxAvailableCPU = availableCPUs.length > 0
|
|
134
|
+
// ? Math.max(...availableCPUs)
|
|
135
|
+
// : 0
|
|
136
|
+
|
|
137
|
+
const parts = cleanedInput.split(',')
|
|
138
|
+
const processors = new Set()
|
|
139
|
+
const errors = []
|
|
140
|
+
|
|
141
|
+
const singleRegex = /^\s*\d+\s*$/
|
|
142
|
+
const rangeRegex = /^\s*(\d+)\s*-\s*(\d+)\s*$/
|
|
143
|
+
|
|
144
|
+
for (let i = 0; i < parts.length; i++) {
|
|
145
|
+
const part = parts[i].trim()
|
|
146
|
+
|
|
147
|
+
if (part === '') {
|
|
148
|
+
errors.push(localization.vmWizard.emptyElement.replace('{0}', `${i + 1}`))
|
|
149
|
+
continue
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (singleRegex.test(part)) {
|
|
153
|
+
const cpuNum = parseInt(part, 10)
|
|
154
|
+
|
|
155
|
+
if (!availableCPUSet.has(cpuNum)) {
|
|
156
|
+
const availableList =
|
|
157
|
+
availableCPUs.length > 0
|
|
158
|
+
? groupConsecutiveNumbers(availableCPUs.sort((a, b) => a - b))
|
|
159
|
+
: 'нет доступных'
|
|
160
|
+
|
|
161
|
+
errors.push(
|
|
162
|
+
localization.vmWizard.cpuOutOfRange
|
|
163
|
+
.replace('{0}', `${cpuNum}`)
|
|
164
|
+
.replace('{1}', availableList)
|
|
165
|
+
)
|
|
166
|
+
continue
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (processors.has(cpuNum)) {
|
|
170
|
+
errors.push(
|
|
171
|
+
localization.vmWizard.cpuDuplicate.replace('{0}', `${cpuNum}`)
|
|
172
|
+
)
|
|
173
|
+
continue
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
processors.add(cpuNum)
|
|
177
|
+
}
|
|
178
|
+
// Проверяем, является ли часть диапазоном
|
|
179
|
+
else if (rangeRegex.test(part)) {
|
|
180
|
+
const match = part.match(rangeRegex)
|
|
181
|
+
const start = parseInt(match[1], 10)
|
|
182
|
+
const end = parseInt(match[2], 10)
|
|
183
|
+
|
|
184
|
+
if (start > end) {
|
|
185
|
+
errors.push(
|
|
186
|
+
localization.vmWizard.invalidRange.replace('{0}', `${part}`)
|
|
187
|
+
)
|
|
188
|
+
continue
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Проверяем доступность начала диапазона
|
|
192
|
+
if (!availableCPUSet.has(start)) {
|
|
193
|
+
const availableList =
|
|
194
|
+
availableCPUs.length > 0
|
|
195
|
+
? availableCPUs.sort((a, b) => a - b).join(', ')
|
|
196
|
+
: 'нет доступных'
|
|
197
|
+
|
|
198
|
+
errors.push(
|
|
199
|
+
localization.vmWizard.rangeStartOutOfRange
|
|
200
|
+
.replace('{0}', `${start}`)
|
|
201
|
+
.replace('{1}', availableList)
|
|
202
|
+
)
|
|
203
|
+
continue
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Проверяем доступность конца диапазона
|
|
207
|
+
if (!availableCPUSet.has(end)) {
|
|
208
|
+
const availableList =
|
|
209
|
+
availableCPUs.length > 0
|
|
210
|
+
? availableCPUs.sort((a, b) => a - b).join(', ')
|
|
211
|
+
: 'нет доступных'
|
|
212
|
+
|
|
213
|
+
errors.push(
|
|
214
|
+
localization.vmWizard.rangeEndOutOfRange
|
|
215
|
+
.replace('{0}', `${end}`)
|
|
216
|
+
.replace('{1}', availableList)
|
|
217
|
+
)
|
|
218
|
+
continue
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Проверяем все процессоры в диапазоне
|
|
222
|
+
let hasInvalidInRange = false
|
|
223
|
+
for (let cpu = start; cpu <= end; cpu++) {
|
|
224
|
+
if (!availableCPUSet.has(cpu)) {
|
|
225
|
+
const availableList =
|
|
226
|
+
availableCPUs.length > 0
|
|
227
|
+
? availableCPUs.sort((a, b) => a - b).join(', ')
|
|
228
|
+
: 'нет доступных'
|
|
229
|
+
|
|
230
|
+
errors.push(
|
|
231
|
+
localization.vmWizard.cpuOutOfRange
|
|
232
|
+
.replace('{0}', `${cpu}`)
|
|
233
|
+
.replace('{1}', availableList)
|
|
234
|
+
)
|
|
235
|
+
hasInvalidInRange = true
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Если в диапазоне есть недоступные CPU, пропускаем добавление
|
|
240
|
+
if (hasInvalidInRange) {
|
|
241
|
+
continue
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Добавляем все процессоры из диапазона
|
|
245
|
+
for (let cpu = start; cpu <= end; cpu++) {
|
|
246
|
+
if (processors.has(cpu)) {
|
|
247
|
+
errors.push(
|
|
248
|
+
localization.vmWizard.rangeDuplicate.replace('{0}', `${cpu}`)
|
|
249
|
+
)
|
|
250
|
+
} else {
|
|
251
|
+
processors.add(cpu)
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// Неизвестный формат
|
|
256
|
+
else {
|
|
257
|
+
errors.push(localization.vmWizard.invalidFormat.replace('{0}', `${part}`))
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
processors: Array.from(processors), // Конвертируем Set в массив
|
|
263
|
+
isValid: errors.length === 0,
|
|
264
|
+
error: errors.length > 0 ? errors.join('; ') : null,
|
|
265
|
+
}
|
|
266
|
+
}
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
:is-vmt="props.isVmt"
|
|
23
23
|
:max-memory="maxMemory"
|
|
24
24
|
:cpu-models="cpuModels"
|
|
25
|
+
:nums="props.nums"
|
|
25
26
|
@hide="emits('hide')"
|
|
26
27
|
@validate="validateSendData"
|
|
27
28
|
@get-storage="emits('get-storage', $event)"
|
|
@@ -79,6 +80,7 @@ const props = withDefaults(
|
|
|
79
80
|
mediatedDevices?: UI_I_MediatedDevice[]
|
|
80
81
|
capabilities?: UI_I_Capabilities
|
|
81
82
|
isVmt?: boolean
|
|
83
|
+
nums?: any // TODO
|
|
82
84
|
}>(),
|
|
83
85
|
{
|
|
84
86
|
getDatastoreTableFunc: undefined,
|
|
@@ -88,6 +90,7 @@ const props = withDefaults(
|
|
|
88
90
|
mediatedDevices: undefined,
|
|
89
91
|
capabilities: undefined,
|
|
90
92
|
isVmt: undefined,
|
|
93
|
+
nums: []
|
|
91
94
|
}
|
|
92
95
|
)
|
|
93
96
|
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
:is-datastore-loading="props.isDatastoreLoading"
|
|
45
45
|
:customize-hardware-submit="props.customizeHardwareSubmit"
|
|
46
46
|
:is-vmt="props.isVmt"
|
|
47
|
+
:nums="props.nums"
|
|
47
48
|
is-edit
|
|
48
49
|
@get-storage="emits('get-storage', $event)"
|
|
49
50
|
@get-folders-or-files="emits('get-folders-or-files', $event)"
|
|
@@ -102,6 +103,7 @@ const props = withDefaults(
|
|
|
102
103
|
getDatastoreTableFunc?: (payload: UI_I_TablePayload) => Promise<void>
|
|
103
104
|
customizeHardwareSubmit?: null | Function
|
|
104
105
|
isVmt?: boolean
|
|
106
|
+
nums?: any // TODO
|
|
105
107
|
}>(),
|
|
106
108
|
{
|
|
107
109
|
state: undefined,
|
|
@@ -112,6 +114,7 @@ const props = withDefaults(
|
|
|
112
114
|
getDatastoreTableFunc: undefined,
|
|
113
115
|
customizeHardwareSubmit: undefined,
|
|
114
116
|
isVmt: undefined,
|
|
117
|
+
nums: null
|
|
115
118
|
}
|
|
116
119
|
)
|
|
117
120
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const groupConsecutiveNumbers = (numbers: number[]): string => {
|
|
2
|
+
if (!numbers || numbers.length === 0) {
|
|
3
|
+
return ''
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const sorted = [...new Set(numbers)].sort((a, b) => a - b)
|
|
7
|
+
|
|
8
|
+
const result = sorted.reduce((acc, num, index, arr) => {
|
|
9
|
+
if (index === 0) {
|
|
10
|
+
acc.push([num])
|
|
11
|
+
} else if (num === arr[index - 1] + 1) {
|
|
12
|
+
acc[acc.length - 1].push(num)
|
|
13
|
+
} else {
|
|
14
|
+
acc.push([num])
|
|
15
|
+
}
|
|
16
|
+
return acc
|
|
17
|
+
}, [])
|
|
18
|
+
|
|
19
|
+
return result
|
|
20
|
+
.map((range) => {
|
|
21
|
+
if (range.length === 1) {
|
|
22
|
+
return range[0].toString()
|
|
23
|
+
}
|
|
24
|
+
return `${range[0]}-${range[range.length - 1]}`
|
|
25
|
+
})
|
|
26
|
+
.join(', ')
|
|
27
|
+
}
|
package/package.json
CHANGED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
<!--<template>-->
|
|
2
|
-
<!-- <div class="">-->
|
|
3
|
-
<!-- <atoms-stack-block :has-children="false">-->
|
|
4
|
-
<!-- <template #stackBlockKey>-->
|
|
5
|
-
<!-- {{ localization.common.schedulingAffinity }}-->
|
|
6
|
-
<!-- </template>-->
|
|
7
|
-
<!-- <template #stackBlockContent>-->
|
|
8
|
-
<!-- <div class="flex-space-between">-->
|
|
9
|
-
<!-- <div class="flex-align-center">-->
|
|
10
|
-
<!-- <input-->
|
|
11
|
-
<!-- id="sa-edit-setting-input"-->
|
|
12
|
-
<!-- v-model="schedulingAffinityLocal"-->
|
|
13
|
-
<!-- data-id="sa-edit-setting-input"-->
|
|
14
|
-
<!-- type="text"-->
|
|
15
|
-
<!-- class="edit-setting-input"-->
|
|
16
|
-
<!-- disabled-->
|
|
17
|
-
<!-- />-->
|
|
18
|
-
<!-- </div>-->
|
|
19
|
-
|
|
20
|
-
<!-- <div id="sa-help-icon">-->
|
|
21
|
-
<!-- <atoms-the-icon-->
|
|
22
|
-
<!-- fill="#0072a3"-->
|
|
23
|
-
<!-- width="24px"-->
|
|
24
|
-
<!-- height="24px"-->
|
|
25
|
-
<!-- name="info-circle"-->
|
|
26
|
-
<!-- data-id="show-sa-help-icon"-->
|
|
27
|
-
<!-- @click.stop="isShowSaHelp = !isShowSaHelp"-->
|
|
28
|
-
<!-- />-->
|
|
29
|
-
<!-- <Teleport to="body">-->
|
|
30
|
-
<!-- <atoms-tooltip-signpost-->
|
|
31
|
-
<!-- v-if="isShowSaHelp"-->
|
|
32
|
-
<!-- elem-id="sa-help-icon"-->
|
|
33
|
-
<!-- @hide="isShowSaHelp = false"-->
|
|
34
|
-
<!-- >-->
|
|
35
|
-
<!-- <h3 class="sa-help-title">-->
|
|
36
|
-
<!-- {{ localization.mainNavigation.help }}-->
|
|
37
|
-
<!-- </h3>-->
|
|
38
|
-
|
|
39
|
-
<!-- <p class="sa-help-text">-->
|
|
40
|
-
<!-- {{ localization.common.schedulingAffinityHelpDescription1 }}-->
|
|
41
|
-
<!-- </p>-->
|
|
42
|
-
<!-- <p class="sa-help-text">-->
|
|
43
|
-
<!-- {{ localization.common.schedulingAffinityHelpDescription2 }}-->
|
|
44
|
-
<!-- </p>-->
|
|
45
|
-
<!-- <p class="sa-help-text">-->
|
|
46
|
-
<!-- {{ localization.common.schedulingAffinityHelpDescription3 }}-->
|
|
47
|
-
<!-- </p>-->
|
|
48
|
-
<!-- <p class="sa-help-text">-->
|
|
49
|
-
<!-- <strong>{{ localization.common.hyperthreadingStatus }}: </strong>-->
|
|
50
|
-
<!-- {{ localization.common.inactive }}-->
|
|
51
|
-
<!-- </p>-->
|
|
52
|
-
<!-- <p class="sa-help-text">-->
|
|
53
|
-
<!-- <strong>{{ localization.common.availableCpus }}: </strong>-->
|
|
54
|
-
<!-- 8({{ localization.common.physicalCpus }})-->
|
|
55
|
-
<!-- </p>-->
|
|
56
|
-
<!-- </atoms-tooltip-signpost>-->
|
|
57
|
-
<!-- </Teleport>-->
|
|
58
|
-
<!-- </div>-->
|
|
59
|
-
<!-- </div>-->
|
|
60
|
-
<!-- </template>-->
|
|
61
|
-
<!-- </atoms-stack-block>-->
|
|
62
|
-
<!-- </div>-->
|
|
63
|
-
<!--</template>-->
|
|
64
|
-
|
|
65
|
-
<!--<script setup lang="ts">-->
|
|
66
|
-
<!--import type { UI_I_Localization } from '~/lib/models/interfaces'-->
|
|
67
|
-
|
|
68
|
-
<!--const localization = computed<UI_I_Localization>(() => useLocal())-->
|
|
69
|
-
|
|
70
|
-
<!--const props = defineProps<{-->
|
|
71
|
-
<!-- schedulingAffinity: string-->
|
|
72
|
-
<!--}>()-->
|
|
73
|
-
<!--const emits = defineEmits<{-->
|
|
74
|
-
<!-- (event: 'update:scheduling-affinity', value: string): void-->
|
|
75
|
-
<!--}>()-->
|
|
76
|
-
|
|
77
|
-
<!--const schedulingAffinityLocal = computed<string>({-->
|
|
78
|
-
<!-- get() {-->
|
|
79
|
-
<!-- return props.schedulingAffinity-->
|
|
80
|
-
<!-- },-->
|
|
81
|
-
<!-- set(newValue) {-->
|
|
82
|
-
<!-- emits('update:scheduling-affinity', newValue)-->
|
|
83
|
-
<!-- },-->
|
|
84
|
-
<!--})-->
|
|
85
|
-
|
|
86
|
-
<!--const isShowSaHelp = ref<boolean>(false)-->
|
|
87
|
-
<!--</script>-->
|
|
88
|
-
|
|
89
|
-
<!--<style scoped lang="scss">-->
|
|
90
|
-
<!--h3.sa-help-title {-->
|
|
91
|
-
<!-- margin-top: 7px;-->
|
|
92
|
-
<!-- font-size: 22px;-->
|
|
93
|
-
<!-- color: #565656;-->
|
|
94
|
-
<!--}-->
|
|
95
|
-
<!--p.sa-help-text {-->
|
|
96
|
-
<!-- width: 310px;-->
|
|
97
|
-
<!-- margin-top: 24px;-->
|
|
98
|
-
<!-- font-size: 14px;-->
|
|
99
|
-
<!-- color: #565656;-->
|
|
100
|
-
<!--}-->
|
|
101
|
-
<!--p.sa-help-text strong {-->
|
|
102
|
-
<!-- font-size: 14px;-->
|
|
103
|
-
<!-- font-weight: bold;-->
|
|
104
|
-
<!-- color: #565656;-->
|
|
105
|
-
<!--}-->
|
|
106
|
-
<!--</style>-->
|