bfg-common 1.5.845 → 1.5.847

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.
@@ -4004,5 +4004,11 @@
4004
4004
  "autostart": "Аўтазапуск",
4005
4005
  "enableAutostart": "Уключыць аўтазапуск",
4006
4006
  "disableAutostart": "Адключыць аўтазапуск"
4007
+ },
4008
+ "temp": {
4009
+ "title": "Віртуальны metro storage кластар",
4010
+ "stepTitle": "Выберыце зыходны хост",
4011
+ "serverAddress": "Адрас сервера",
4012
+ "fqdnOrIpAddress": "FQDN або IP-адрас"
4007
4013
  }
4008
4014
  }
@@ -4008,5 +4008,11 @@
4008
4008
  "autostart": "Autostart",
4009
4009
  "enableAutostart": "Enable autostart",
4010
4010
  "disableAutostart": "Disable autostart"
4011
+ },
4012
+ "temp": {
4013
+ "title": "Virtual metro storage cluster",
4014
+ "stepTitle": "Select source host",
4015
+ "serverAddress": "Server Address",
4016
+ "fqdnOrIpAddress": "FQDN or IP address"
4011
4017
  }
4012
4018
  }
@@ -4008,5 +4008,11 @@
4008
4008
  "autostart": "Ավտոմատ մեկնարկ",
4009
4009
  "enableAutostart": "Միացնել ավտոմատ մեկնարկը",
4010
4010
  "disableAutostart": "Անջատել ավտոմատ մեկնարկը"
4011
+ },
4012
+ "temp": {
4013
+ "title": "Վիրտուալ metro storage կլաստեր",
4014
+ "stepTitle": "Ընտրեք աղբյուրի հոստ",
4015
+ "serverAddress": "Սերվերի հասցե",
4016
+ "fqdnOrIpAddress": "FQDN կամ IP հասցե"
4011
4017
  }
4012
4018
  }
@@ -4007,5 +4007,11 @@
4007
4007
  "autostart": "Автожаңғалту",
4008
4008
  "enableAutostart": "Автожаңғалтуды қосу",
4009
4009
  "disableAutostart": "Автожаңғалтуды өшіру"
4010
+ },
4011
+ "temp": {
4012
+ "title": "Виртуалды metro storage кластері",
4013
+ "stepTitle": "Дереккөз хостты таңдаңыз",
4014
+ "serverAddress": "Сервердің мекенжайы",
4015
+ "fqdnOrIpAddress": "FQDN немесе IP-мекенжай"
4010
4016
  }
4011
4017
  }
@@ -4007,5 +4007,11 @@
4007
4007
  "autostart": "Автозапуск",
4008
4008
  "enableAutostart": "Автозапуск вкл",
4009
4009
  "disableAutostart": "Автозапуск выкл"
4010
+ },
4011
+ "temp": {
4012
+ "title": "Виртуальный metro storage кластер",
4013
+ "stepTitle": "Выберите исходный хост",
4014
+ "serverAddress": "Адрес сервера",
4015
+ "fqdnOrIpAddress": "FQDN или IP-адрес"
4010
4016
  }
4011
4017
  }
@@ -4005,5 +4005,11 @@
4005
4005
  "autostart": "自动启动",
4006
4006
  "enableAutostart": "启用自动启动",
4007
4007
  "disableAutostart": "禁用自动启动"
4008
+ },
4009
+ "temp": {
4010
+ "title": "虚拟Metro存储集群",
4011
+ "stepTitle": "选择源主机",
4012
+ "serverAddress": "服务器地址",
4013
+ "fqdnOrIpAddress": "FQDN或IP地址"
4008
4014
  }
4009
4015
  }
@@ -29,7 +29,7 @@
29
29
  >
30
30
  </nuxt-link>
31
31
  </div>
32
- <form>
32
+ <form style="width: 100%; height: 100%" @click="onTemp">
33
33
  <atoms-input-search />
34
34
  </form>
35
35
 
@@ -146,6 +146,10 @@ const onUpdateLanguage = (language: string): void => {
146
146
  }
147
147
 
148
148
  const isShowFeedback = ref<boolean>(false)
149
+
150
+ const onTemp = (): void => {
151
+ useLocalStorage('temp', true)
152
+ }
149
153
  </script>
150
154
 
151
155
  <style scoped lang="scss">
@@ -1,7 +1,7 @@
1
1
  import type { UI_I_AdvancedCounterItem } from '~/components/common/monitor/advanced/tools/chartOptionsModal/counters/table/lib/models/interfaces'
2
2
  import {
3
3
  allowedHostCpuFieldNotObject,
4
- allowedHostNetworkFieldNotObject,
4
+ // allowedHostNetworkFieldNotObject,
5
5
  } from '~/components/common/monitor/advanced/tools/chartOptionsModal/lib/config'
6
6
 
7
7
  export const checkIsDisabledSubmit = (
@@ -59,8 +59,8 @@
59
59
  )"
60
60
  :key="props.hardDisksIndex[key]"
61
61
  >
62
- <!-- TODO 111-->
63
- <!-- v-model:vm-storage-policy="item.vm_storage_policy"-->
62
+ <!-- TODO 111-->
63
+ <!-- v-model:vm-storage-policy="item.vm_storage_policy"-->
64
64
  <common-vm-actions-common-customize-hardware-virtual-hardware-new-hard-disk
65
65
  v-model:size="item.size"
66
66
  v-model:provision-type="item.provision_type"
@@ -37,8 +37,8 @@
37
37
  )"
38
38
  :key="props.hardDisksIndex[key]"
39
39
  >
40
- <!-- TODO 111-->
41
- <!-- v-model:vm-storage-policy="item.vm_storage_policy"-->
40
+ <!-- TODO 111-->
41
+ <!-- v-model:vm-storage-policy="item.vm_storage_policy"-->
42
42
  <common-vm-actions-common-customize-hardware-virtual-hardware-new-hard-disk
43
43
  v-model:size="item.size"
44
44
  v-model:provision-type="item.provision_type"
@@ -1,170 +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>
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>
@@ -1,266 +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
- }
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
+ }
@@ -90,7 +90,7 @@ const props = withDefaults(
90
90
  mediatedDevices: undefined,
91
91
  capabilities: undefined,
92
92
  isVmt: undefined,
93
- nums: []
93
+ nums: null
94
94
  }
95
95
  )
96
96
 
package/lib/utils/nums.ts CHANGED
@@ -1,27 +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
- }
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.845",
4
+ "version": "1.5.847",
5
5
  "scripts": {
6
6
  "build": "nuxt build",
7
7
  "dev": "nuxt dev --port=3002",