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.
- package/assets/localization/local_be.json +6 -0
- package/assets/localization/local_en.json +6 -0
- package/assets/localization/local_hy.json +6 -0
- package/assets/localization/local_kk.json +6 -0
- package/assets/localization/local_ru.json +6 -0
- package/assets/localization/local_zh.json +6 -0
- package/components/common/layout/theHeader/Old.vue +5 -1
- package/components/common/monitor/advanced/tools/chartOptionsModal/lib/utils/checkSubmit.ts +1 -1
- package/components/common/vm/actions/common/customizeHardware/virtualHardware/New.vue +2 -2
- package/components/common/vm/actions/common/customizeHardware/virtualHardware/Old.vue +2 -2
- package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/sa/Sa.vue +170 -170
- package/components/common/vm/actions/common/customizeHardware/virtualHardware/cpu/sa/lib/utils/validation.ts +266 -266
- package/components/common/vm/actions/editSettings/EditSettings.vue +1 -1
- package/lib/utils/nums.ts +27 -27
- package/package.json +1 -1
|
@@ -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
|
-
|
|
63
|
-
|
|
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
|
-
|
|
41
|
-
|
|
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
|
+
}
|
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
|
+
}
|