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.
Files changed (29) 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/components/common/vm/actions/add/Add.vue +3 -0
  8. package/components/common/vm/actions/add/New.vue +4 -0
  9. package/components/common/vm/actions/add/Old.vue +4 -0
  10. package/components/common/vm/actions/clone/Clone.vue +3 -0
  11. package/components/common/vm/actions/clone/new/New.vue +3 -0
  12. package/components/common/vm/actions/clone/old/Old.vue +3 -0
  13. package/components/common/vm/actions/common/customizeHardware/CustomizeHardware.vue +3 -0
  14. package/components/common/vm/actions/common/customizeHardware/New.vue +3 -0
  15. package/components/common/vm/actions/common/customizeHardware/Old.vue +3 -0
  16. package/components/common/vm/actions/common/customizeHardware/virtualHardware/New.vue +3 -0
  17. package/components/common/vm/actions/common/customizeHardware/virtualHardware/Old.vue +3 -0
  18. package/components/common/vm/actions/common/customizeHardware/virtualHardware/VirtualHardware.vue +3 -0
  19. package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/Cpu.vue +7 -0
  20. package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/New.vue +12 -3
  21. package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/Old.vue +12 -3
  22. package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/sa/Sa.vue +170 -0
  23. package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/sa/lib/utils/validation.ts +266 -0
  24. package/components/common/vm/actions/editSettings/EditSettings.vue +3 -0
  25. package/components/common/vm/actions/editSettings/Old.vue +3 -0
  26. package/components/common/vm/actions/lib/utils.ts +1 -0
  27. package/lib/utils/nums.ts +27 -0
  28. package/package.json +1 -1
  29. 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<{
@@ -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
- <!-- <common-vm-actions-common-customize-hardware-virtual-hardware-cpu-sa-->
129
- <!-- v-models:schedulingAffinity="schedulingAffinity"-->
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
- <!-- <common-vm-actions-common-customize-hardware-virtual-hardware-cpu-sa-->
107
- <!-- v-models:schedulingAffinity="schedulingAffinity"-->
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
 
@@ -180,6 +180,7 @@ export const constructSendDataForm = (
180
180
  limit_mhz: +cpu.limit_mhz,
181
181
  shares: cpu.shares,
182
182
  hotplug: cpu.hotplug,
183
+ scheduling_affinity: cpu.scheduling_affinity,
183
184
  },
184
185
  memory: {
185
186
  size_mb: +memory.size_mb,
@@ -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,7 +1,7 @@
1
1
  {
2
2
  "name": "bfg-common",
3
3
  "private": false,
4
- "version": "1.5.843",
4
+ "version": "1.5.845",
5
5
  "scripts": {
6
6
  "build": "nuxt build",
7
7
  "dev": "nuxt dev --port=3002",
@@ -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>-->