bfg-common 1.3.393 → 1.3.395
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 +5 -1
- package/assets/localization/local_en.json +5 -1
- package/assets/localization/local_hy.json +5 -1
- package/assets/localization/local_kk.json +5 -1
- package/assets/localization/local_ru.json +5 -1
- package/assets/localization/local_zh.json +5 -1
- package/components/common/split/horizontal/Horizontal.vue +40 -277
- package/components/common/split/horizontal/HorizontalOld.vue +307 -0
- package/components/common/vm/actions/common/customizeHardware/virtualHardware/bus/Bus.vue +9 -4
- package/components/common/vm/actions/common/customizeHardware/virtualHardware/cdDvdDrive/CdDvdDrive.vue +2 -1
- package/components/common/vm/actions/common/customizeHardware/virtualHardware/newHardDisk/NewHardDisk.vue +1 -0
- package/package.json +1 -1
|
@@ -2361,5 +2361,9 @@
|
|
|
2361
2361
|
"authBgTextSphere": "Лёгка кантраляваць віртуалізацыю вузлы $*і$ кіраваць імі",
|
|
2362
2362
|
"alert": "Трывога",
|
|
2363
2363
|
"noTargetToScanIsSelected": "Мэта для сканавання не абраная.",
|
|
2364
|
-
"protectNewVolumes": "Абарона новых тамоў"
|
|
2364
|
+
"protectNewVolumes": "Абарона новых тамоў",
|
|
2365
|
+
"hostsCount": "Хасты ({0})",
|
|
2366
|
+
"vmsCount": "Віртуальныя машыны ({0})",
|
|
2367
|
+
"datastoresCount": "Сховішчы даных ({0})",
|
|
2368
|
+
"networksCount": "Сеткі ({0})"
|
|
2365
2369
|
}
|
|
@@ -2365,5 +2365,9 @@
|
|
|
2365
2365
|
"authBgTextSphere": "Monitor $*and$ control virtualization hosts $*with$ ease",
|
|
2366
2366
|
"alert": "Alert",
|
|
2367
2367
|
"noTargetToScanIsSelected": "No target to scan is selected.",
|
|
2368
|
-
"protectNewVolumes": "Protect new volumes"
|
|
2368
|
+
"protectNewVolumes": "Protect new volumes",
|
|
2369
|
+
"hostsCount": "Hosts ({0})",
|
|
2370
|
+
"vmsCount": "VMs ({0})",
|
|
2371
|
+
"datastoresCount": "Datastores ({0})",
|
|
2372
|
+
"networksCount": "Networks ({0})"
|
|
2369
2373
|
}
|
|
@@ -2365,5 +2365,9 @@
|
|
|
2365
2365
|
"authBgTextSphere": "Հեշտությամբ վերահսկեք $*և$ Կառավարեք վիրտուալացման հանգույցները",
|
|
2366
2366
|
"alert": "Անհանգստություն",
|
|
2367
2367
|
"noTargetToScanIsSelected": "Սկանավորման թիրախը ընտրված չէ:",
|
|
2368
|
-
"protectNewVolumes": "Նոր ծավալների պաշտպանություն"
|
|
2368
|
+
"protectNewVolumes": "Նոր ծավալների պաշտպանություն",
|
|
2369
|
+
"hostsCount": "Հոսթեր ({0})",
|
|
2370
|
+
"vmsCount": "VM-ներ ({0})",
|
|
2371
|
+
"datastoresCount": "Տվյալների պահեստներ ({0})",
|
|
2372
|
+
"networksCount": "Ցանցեր ({0})"
|
|
2369
2373
|
}
|
|
@@ -2364,5 +2364,9 @@
|
|
|
2364
2364
|
"authBgTextSphere": "Виртуализация $*хосттарын$ оңай бақылаңыз $*және$ басқарыңыз",
|
|
2365
2365
|
"alert": "Ескерту",
|
|
2366
2366
|
"noTargetToScanIsSelected": "Сканерлеуге арналған мақсат таңдалмаған.",
|
|
2367
|
-
"protectNewVolumes": "Жаңа томдарды қорғау"
|
|
2367
|
+
"protectNewVolumes": "Жаңа томдарды қорғау",
|
|
2368
|
+
"hostsCount": "Хосттар ({0})",
|
|
2369
|
+
"vmsCount": "VM ({0})",
|
|
2370
|
+
"datastoresCount": "Деректер қоймалары ({0})",
|
|
2371
|
+
"networksCount": "Желілер ({0})"
|
|
2368
2372
|
}
|
|
@@ -2370,5 +2370,9 @@
|
|
|
2370
2370
|
"authBgTextSphere": "Легко контролируйте узлы виртуализации $*и$ управляйте ими",
|
|
2371
2371
|
"alert": "Тревога",
|
|
2372
2372
|
"noTargetToScanIsSelected": "Цель для сканирования не выбрана.",
|
|
2373
|
-
"protectNewVolumes": "Защитить новые тома"
|
|
2373
|
+
"protectNewVolumes": "Защитить новые тома",
|
|
2374
|
+
"hostsCount": "Хосты ({0})",
|
|
2375
|
+
"vmsCount": "Виртуальные машины ({0})",
|
|
2376
|
+
"datastoresCount": "Хранилища данных ({0})",
|
|
2377
|
+
"networksCount": "Сети ({0})"
|
|
2374
2378
|
}
|
|
@@ -2364,5 +2364,9 @@
|
|
|
2364
2364
|
"authBgTextSphere": "轻松 $*监$ 控和控制虚拟 $*化$ 主机",
|
|
2365
2365
|
"alert": "警报",
|
|
2366
2366
|
"noTargetToScanIsSelected": "未选择要扫描的目标。",
|
|
2367
|
-
"protectNewVolumes": "保护新卷"
|
|
2367
|
+
"protectNewVolumes": "保护新卷",
|
|
2368
|
+
"hostsCount": "主机 ({0})",
|
|
2369
|
+
"vmsCount": "虚拟机 ({0})",
|
|
2370
|
+
"datastoresCount": "数据存储 ({0})",
|
|
2371
|
+
"networksCount": "网络 ({0})"
|
|
2368
2372
|
}
|
|
@@ -1,45 +1,45 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
:
|
|
2
|
+
<common-split-horizontal-new
|
|
3
|
+
v-if="props.isNewView"
|
|
4
|
+
:parent-element-selector="props.parentElementSelector"
|
|
5
|
+
:left-panel-w="props.leftPanelW"
|
|
6
|
+
:left-panel-min-width="props.leftPanelMinWidth"
|
|
7
|
+
:right-panel-min-width="props.rightPanelMinWidth"
|
|
8
|
+
:show-toggle-button="props.showToggleButton"
|
|
9
|
+
:hide-left-panel="props.hideLeftPanel"
|
|
10
|
+
@dragend="emits('dragend', $event)"
|
|
5
11
|
>
|
|
6
|
-
<
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
v-if="showToggleButton"
|
|
10
|
-
:class="['panel-toggle', { collapsed: leftPanelCollapsed }]"
|
|
11
|
-
>
|
|
12
|
-
<button
|
|
13
|
-
id="collapse-left-panel-button"
|
|
14
|
-
data-id="collapse-left-panel-button"
|
|
15
|
-
class="btn-trigger"
|
|
16
|
-
@click="collapseLeftPanel"
|
|
17
|
-
>
|
|
18
|
-
<atoms-the-icon class="trigger-icon" name="angle" />
|
|
19
|
-
</button>
|
|
20
|
-
</div>
|
|
12
|
+
<template #toggleContent>
|
|
13
|
+
<slot name="toggleContent" />
|
|
14
|
+
</template>
|
|
21
15
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
</div>
|
|
26
|
-
</div>
|
|
27
|
-
<div
|
|
28
|
-
v-show="!leftPanelCollapsed"
|
|
29
|
-
:id="`gutter-${elementId}`"
|
|
30
|
-
class="gutter gutter-horizontal"
|
|
31
|
-
tabindex="0"
|
|
32
|
-
@mousedown="isGrab = true"
|
|
33
|
-
@focus="isFocus = true"
|
|
34
|
-
@blur="isFocus = false"
|
|
35
|
-
>
|
|
36
|
-
<div class="gutter-horizontal-handler"></div>
|
|
37
|
-
</div>
|
|
16
|
+
<template #firstPanel>
|
|
17
|
+
<slot name="firstPanel" />
|
|
18
|
+
</template>
|
|
38
19
|
|
|
39
|
-
<
|
|
20
|
+
<template #secondPanel>
|
|
40
21
|
<slot name="secondPanel" />
|
|
41
|
-
</
|
|
42
|
-
</
|
|
22
|
+
</template>
|
|
23
|
+
</common-split-horizontal-new>
|
|
24
|
+
|
|
25
|
+
<common-split-horizontal-old
|
|
26
|
+
v-else
|
|
27
|
+
:parent-element-selector="props.parentElementSelector"
|
|
28
|
+
:left-panel-w="props.leftPanelW"
|
|
29
|
+
:left-panel-min-width="props.leftPanelMinWidth"
|
|
30
|
+
:right-panel-min-width="props.rightPanelMinWidth"
|
|
31
|
+
:show-toggle-button="props.showToggleButton"
|
|
32
|
+
:hide-left-panel="props.hideLeftPanel"
|
|
33
|
+
@dragend="emits('dragend', $event)"
|
|
34
|
+
>
|
|
35
|
+
<template #firstPanel>
|
|
36
|
+
<slot name="firstPanel" />
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<template #secondPanel>
|
|
40
|
+
<slot name="secondPanel" />
|
|
41
|
+
</template>
|
|
42
|
+
</common-split-horizontal-old>
|
|
43
43
|
</template>
|
|
44
44
|
|
|
45
45
|
<script setup lang="ts">
|
|
@@ -51,6 +51,7 @@ const props = withDefaults(
|
|
|
51
51
|
rightPanelMinWidth?: number
|
|
52
52
|
showToggleButton?: boolean
|
|
53
53
|
hideLeftPanel?: boolean
|
|
54
|
+
isNewView?: boolean
|
|
54
55
|
}>(),
|
|
55
56
|
{
|
|
56
57
|
leftPanelMinWidth: 200, // 200px
|
|
@@ -58,250 +59,12 @@ const props = withDefaults(
|
|
|
58
59
|
leftPanelW: undefined,
|
|
59
60
|
showToggleButton: true,
|
|
60
61
|
hideLeftPanel: false,
|
|
62
|
+
isNewView: false,
|
|
61
63
|
}
|
|
62
64
|
)
|
|
63
65
|
const emits = defineEmits<{
|
|
64
66
|
(event: 'dragend', value: number): void
|
|
65
67
|
}>()
|
|
66
|
-
|
|
67
|
-
const leftPanelStyle = computed(() => {
|
|
68
|
-
let width = `calc(${leftPanelW.value}% - 1.5px)`
|
|
69
|
-
if (props.showToggleButton && leftPanelCollapsed.value) {
|
|
70
|
-
width = '20px'
|
|
71
|
-
}
|
|
72
|
-
if (props.hideLeftPanel && leftPanelCollapsed.value) width = '0px'
|
|
73
|
-
|
|
74
|
-
return { width }
|
|
75
|
-
})
|
|
76
|
-
const rightPanelStyle = computed(() => {
|
|
77
|
-
let width = `calc(${100 - leftPanelW.value}% - 1.5px)`
|
|
78
|
-
if (props.showToggleButton && leftPanelCollapsed.value) {
|
|
79
|
-
width = 'calc(100% - 20px)'
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (props.hideLeftPanel && leftPanelCollapsed.value)
|
|
83
|
-
width = 'calc(100% - 0px)'
|
|
84
|
-
|
|
85
|
-
return { width }
|
|
86
|
-
})
|
|
87
|
-
const leftPanelCollapsed = ref<boolean>(false)
|
|
88
|
-
const collapseLeftPanel = (): void => {
|
|
89
|
-
leftPanelCollapsed.value = !leftPanelCollapsed.value
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const isGrab = ref<boolean>(false)
|
|
93
|
-
const isFocus = ref<boolean>(false)
|
|
94
|
-
const isDrag = ref<boolean>(false)
|
|
95
|
-
const leftPanelW = ref<number>(20) // 0%
|
|
96
|
-
watch(
|
|
97
|
-
() => props.leftPanelW,
|
|
98
|
-
(newValue) => {
|
|
99
|
-
if (newValue === undefined) return
|
|
100
|
-
leftPanelW.value = newValue
|
|
101
|
-
},
|
|
102
|
-
{ immediate: true }
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
watch(
|
|
106
|
-
() => props.hideLeftPanel,
|
|
107
|
-
() => {
|
|
108
|
-
collapseLeftPanel()
|
|
109
|
-
}
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
let parentElem: HTMLElement | null
|
|
113
|
-
const mouseup = (): void => {
|
|
114
|
-
if (!isGrab.value) {
|
|
115
|
-
return
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
isGrab.value = false
|
|
119
|
-
isDrag.value = false
|
|
120
|
-
|
|
121
|
-
emits('dragend', leftPanelW.value)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
let mousemove = (e: MouseEvent): void => {
|
|
125
|
-
if (!isGrab.value) return
|
|
126
|
-
|
|
127
|
-
e.preventDefault()
|
|
128
|
-
isDrag.value = true
|
|
129
|
-
doDrag(e.clientX)
|
|
130
|
-
}
|
|
131
|
-
mousemove = useThrottle(mousemove)
|
|
132
|
-
|
|
133
|
-
const doDrag = (clientX: number): void => {
|
|
134
|
-
const parentElemRect = parentElem?.getBoundingClientRect()
|
|
135
|
-
const parentElemWidth = parentElemRect?.width || 0
|
|
136
|
-
const parentElemLeft = parentElemRect?.left || 0
|
|
137
|
-
const onePercent = parentElemWidth / 100
|
|
138
|
-
const layerX = clientX - parentElemLeft
|
|
139
|
-
|
|
140
|
-
const leftLimit = layerX <= props.leftPanelMinWidth
|
|
141
|
-
const rightLimit = parentElemWidth - layerX <= props.rightPanelMinWidth
|
|
142
|
-
if (leftLimit || rightLimit) return
|
|
143
|
-
|
|
144
|
-
leftPanelW.value = layerX / onePercent
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const elementId = `horizontal${useUniqueId()}`
|
|
148
|
-
|
|
149
|
-
const keydown = (e: KeyboardEvent): void => {
|
|
150
|
-
if (!isFocus.value) return
|
|
151
|
-
|
|
152
|
-
const gutter = document.getElementById(`gutter-${elementId}`)
|
|
153
|
-
|
|
154
|
-
if (!gutter) return
|
|
155
|
-
|
|
156
|
-
const gutterLeft = ~~(gutter.getBoundingClientRect().left + 1.5)
|
|
157
|
-
|
|
158
|
-
if (e.keyCode === 39) {
|
|
159
|
-
doDrag(gutterLeft + 10)
|
|
160
|
-
}
|
|
161
|
-
if (e.keyCode === 37) {
|
|
162
|
-
doDrag(gutterLeft - 10)
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
onMounted(() => {
|
|
166
|
-
parentElem = document.querySelector(props.parentElementSelector)
|
|
167
|
-
|
|
168
|
-
window.addEventListener('mousemove', mousemove)
|
|
169
|
-
window.addEventListener('mouseup', mouseup)
|
|
170
|
-
window.addEventListener('keydown', keydown)
|
|
171
|
-
})
|
|
172
|
-
onUnmounted(() => {
|
|
173
|
-
window.removeEventListener('mouseup', mouseup)
|
|
174
|
-
window.removeEventListener('mousemove', mousemove)
|
|
175
|
-
window.removeEventListener('keydown', keydown)
|
|
176
|
-
})
|
|
177
68
|
</script>
|
|
178
69
|
|
|
179
|
-
<style scoped lang="scss">
|
|
180
|
-
@import '@/assets/scss/common/mixins';
|
|
181
|
-
.horizontal {
|
|
182
|
-
&.dragging {
|
|
183
|
-
.gutter-horizontal.gutter {
|
|
184
|
-
background-color: var(--gutter-active-bg-color);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
.firstPanel {
|
|
188
|
-
width: calc(50% - 1.5px);
|
|
189
|
-
|
|
190
|
-
.left-panel {
|
|
191
|
-
@include flex($dir: column);
|
|
192
|
-
width: 100%;
|
|
193
|
-
height: 100%;
|
|
194
|
-
|
|
195
|
-
.panel-toggle {
|
|
196
|
-
border-bottom: 1px solid var(--global-border-color);
|
|
197
|
-
|
|
198
|
-
&.collapsed {
|
|
199
|
-
border-right: 1px solid var(--global-border-color);
|
|
200
|
-
|
|
201
|
-
.btn-trigger {
|
|
202
|
-
.trigger-icon {
|
|
203
|
-
transform: rotate(90deg);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
.btn-trigger {
|
|
209
|
-
@include flex($align: center);
|
|
210
|
-
width: 100%;
|
|
211
|
-
height: 36px;
|
|
212
|
-
flex: 0 0 36px;
|
|
213
|
-
border: 0;
|
|
214
|
-
padding: 0;
|
|
215
|
-
background-color: transparent;
|
|
216
|
-
outline: none;
|
|
217
|
-
cursor: pointer;
|
|
218
|
-
|
|
219
|
-
.trigger-icon {
|
|
220
|
-
width: 16px;
|
|
221
|
-
height: 16px;
|
|
222
|
-
transform: rotate(-90deg);
|
|
223
|
-
margin-left: auto;
|
|
224
|
-
fill: var(--triger-icon-color);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
.navigator {
|
|
229
|
-
overflow: hidden;
|
|
230
|
-
height: 100%;
|
|
231
|
-
|
|
232
|
-
.panel-inner {
|
|
233
|
-
position: relative;
|
|
234
|
-
height: 100%;
|
|
235
|
-
background: var(--horizontal-panel-bg-color);
|
|
236
|
-
border-radius: 0;
|
|
237
|
-
border: 0;
|
|
238
|
-
|
|
239
|
-
&.inventory-tree {
|
|
240
|
-
padding-left: 4px;
|
|
241
|
-
padding-top: 6px;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
.gutter-horizontal {
|
|
248
|
-
position: relative;
|
|
249
|
-
width: 3px;
|
|
250
|
-
background-color: var(--gutter-bg-color);
|
|
251
|
-
transition-delay: 0.25s;
|
|
252
|
-
transition-duration: 0.25s;
|
|
253
|
-
|
|
254
|
-
&-handler {
|
|
255
|
-
position: absolute;
|
|
256
|
-
height: 100%;
|
|
257
|
-
width: 10px;
|
|
258
|
-
background: transparent;
|
|
259
|
-
top: 0;
|
|
260
|
-
left: -3.5px;
|
|
261
|
-
z-index: 2;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
&:focus {
|
|
265
|
-
background-color: var(--gutter-active-bg-color);
|
|
266
|
-
outline: none;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
&:hover {
|
|
270
|
-
background-color: var(--gutter-hover-bg-color);
|
|
271
|
-
cursor: col-resize;
|
|
272
|
-
&:before {
|
|
273
|
-
background-color: hsla(0, 0%, 100%, 0.5);
|
|
274
|
-
box-shadow: inset 0 0 0 1px rgb(0 0 0 / 10%);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
&:before {
|
|
279
|
-
content: '';
|
|
280
|
-
position: relative;
|
|
281
|
-
display: block;
|
|
282
|
-
background: rgba(0, 0, 0, 0.1);
|
|
283
|
-
transition-delay: 0.25s;
|
|
284
|
-
transition-duration: 0.25s;
|
|
285
|
-
width: 100%;
|
|
286
|
-
height: 25px;
|
|
287
|
-
top: calc(50% - 12.5px);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
.secondPanel {
|
|
291
|
-
width: calc(50% - 1.5px);
|
|
292
|
-
&.right {
|
|
293
|
-
overflow: hidden;
|
|
294
|
-
height: 100%;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
</style>
|
|
299
|
-
|
|
300
|
-
<style>
|
|
301
|
-
:root {
|
|
302
|
-
--horizontal-panel-bg-color: #fff;
|
|
303
|
-
}
|
|
304
|
-
:root.dark-theme {
|
|
305
|
-
--horizontal-panel-bg-color: #1b2a32;
|
|
306
|
-
}
|
|
307
|
-
</style>
|
|
70
|
+
<style scoped lang="scss"></style>
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:id="elementId"
|
|
4
|
+
:class="['fill-parent horizontal', { dragging: isDrag }]"
|
|
5
|
+
>
|
|
6
|
+
<div class="firstPanel" :style="leftPanelStyle">
|
|
7
|
+
<div class="left-panel">
|
|
8
|
+
<div
|
|
9
|
+
v-if="showToggleButton"
|
|
10
|
+
:class="['panel-toggle', { collapsed: leftPanelCollapsed }]"
|
|
11
|
+
>
|
|
12
|
+
<button
|
|
13
|
+
id="collapse-left-panel-button"
|
|
14
|
+
data-id="collapse-left-panel-button"
|
|
15
|
+
class="btn-trigger"
|
|
16
|
+
@click="collapseLeftPanel"
|
|
17
|
+
>
|
|
18
|
+
<atoms-the-icon class="trigger-icon" name="angle" />
|
|
19
|
+
</button>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div v-show="!leftPanelCollapsed" class="navigator">
|
|
23
|
+
<slot name="firstPanel" />
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
<div
|
|
28
|
+
v-show="!leftPanelCollapsed"
|
|
29
|
+
:id="`gutter-${elementId}`"
|
|
30
|
+
class="gutter gutter-horizontal"
|
|
31
|
+
tabindex="0"
|
|
32
|
+
@mousedown="isGrab = true"
|
|
33
|
+
@focus="isFocus = true"
|
|
34
|
+
@blur="isFocus = false"
|
|
35
|
+
>
|
|
36
|
+
<div class="gutter-horizontal-handler"></div>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<div class="secondPanel right" :style="rightPanelStyle">
|
|
40
|
+
<slot name="secondPanel" />
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<script setup lang="ts">
|
|
46
|
+
const props = withDefaults(
|
|
47
|
+
defineProps<{
|
|
48
|
+
parentElementSelector: string
|
|
49
|
+
leftPanelW?: number
|
|
50
|
+
leftPanelMinWidth?: number
|
|
51
|
+
rightPanelMinWidth?: number
|
|
52
|
+
showToggleButton?: boolean
|
|
53
|
+
hideLeftPanel?: boolean
|
|
54
|
+
}>(),
|
|
55
|
+
{
|
|
56
|
+
leftPanelMinWidth: 200, // 200px
|
|
57
|
+
rightPanelMinWidth: 200, // 200px
|
|
58
|
+
leftPanelW: undefined,
|
|
59
|
+
showToggleButton: true,
|
|
60
|
+
hideLeftPanel: false,
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
const emits = defineEmits<{
|
|
64
|
+
(event: 'dragend', value: number): void
|
|
65
|
+
}>()
|
|
66
|
+
|
|
67
|
+
const leftPanelStyle = computed(() => {
|
|
68
|
+
let width = `calc(${leftPanelW.value}% - 1.5px)`
|
|
69
|
+
if (props.showToggleButton && leftPanelCollapsed.value) {
|
|
70
|
+
width = '20px'
|
|
71
|
+
}
|
|
72
|
+
if (props.hideLeftPanel && leftPanelCollapsed.value) width = '0px'
|
|
73
|
+
|
|
74
|
+
return { width }
|
|
75
|
+
})
|
|
76
|
+
const rightPanelStyle = computed(() => {
|
|
77
|
+
let width = `calc(${100 - leftPanelW.value}% - 1.5px)`
|
|
78
|
+
if (props.showToggleButton && leftPanelCollapsed.value) {
|
|
79
|
+
width = 'calc(100% - 20px)'
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (props.hideLeftPanel && leftPanelCollapsed.value)
|
|
83
|
+
width = 'calc(100% - 0px)'
|
|
84
|
+
|
|
85
|
+
return { width }
|
|
86
|
+
})
|
|
87
|
+
const leftPanelCollapsed = ref<boolean>(false)
|
|
88
|
+
const collapseLeftPanel = (): void => {
|
|
89
|
+
leftPanelCollapsed.value = !leftPanelCollapsed.value
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const isGrab = ref<boolean>(false)
|
|
93
|
+
const isFocus = ref<boolean>(false)
|
|
94
|
+
const isDrag = ref<boolean>(false)
|
|
95
|
+
const leftPanelW = ref<number>(20) // 0%
|
|
96
|
+
watch(
|
|
97
|
+
() => props.leftPanelW,
|
|
98
|
+
(newValue) => {
|
|
99
|
+
if (newValue === undefined) return
|
|
100
|
+
leftPanelW.value = newValue
|
|
101
|
+
},
|
|
102
|
+
{ immediate: true }
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
watch(
|
|
106
|
+
() => props.hideLeftPanel,
|
|
107
|
+
() => {
|
|
108
|
+
collapseLeftPanel()
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
let parentElem: HTMLElement | null
|
|
113
|
+
const mouseup = (): void => {
|
|
114
|
+
if (!isGrab.value) {
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
isGrab.value = false
|
|
119
|
+
isDrag.value = false
|
|
120
|
+
|
|
121
|
+
emits('dragend', leftPanelW.value)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let mousemove = (e: MouseEvent): void => {
|
|
125
|
+
if (!isGrab.value) return
|
|
126
|
+
|
|
127
|
+
e.preventDefault()
|
|
128
|
+
isDrag.value = true
|
|
129
|
+
doDrag(e.clientX)
|
|
130
|
+
}
|
|
131
|
+
mousemove = useThrottle(mousemove)
|
|
132
|
+
|
|
133
|
+
const doDrag = (clientX: number): void => {
|
|
134
|
+
const parentElemRect = parentElem?.getBoundingClientRect()
|
|
135
|
+
const parentElemWidth = parentElemRect?.width || 0
|
|
136
|
+
const parentElemLeft = parentElemRect?.left || 0
|
|
137
|
+
const onePercent = parentElemWidth / 100
|
|
138
|
+
const layerX = clientX - parentElemLeft
|
|
139
|
+
|
|
140
|
+
const leftLimit = layerX <= props.leftPanelMinWidth
|
|
141
|
+
const rightLimit = parentElemWidth - layerX <= props.rightPanelMinWidth
|
|
142
|
+
if (leftLimit || rightLimit) return
|
|
143
|
+
|
|
144
|
+
leftPanelW.value = layerX / onePercent
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const elementId = `horizontal${useUniqueId()}`
|
|
148
|
+
|
|
149
|
+
const keydown = (e: KeyboardEvent): void => {
|
|
150
|
+
if (!isFocus.value) return
|
|
151
|
+
|
|
152
|
+
const gutter = document.getElementById(`gutter-${elementId}`)
|
|
153
|
+
|
|
154
|
+
if (!gutter) return
|
|
155
|
+
|
|
156
|
+
const gutterLeft = ~~(gutter.getBoundingClientRect().left + 1.5)
|
|
157
|
+
|
|
158
|
+
if (e.keyCode === 39) {
|
|
159
|
+
doDrag(gutterLeft + 10)
|
|
160
|
+
}
|
|
161
|
+
if (e.keyCode === 37) {
|
|
162
|
+
doDrag(gutterLeft - 10)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
onMounted(() => {
|
|
166
|
+
parentElem = document.querySelector(props.parentElementSelector)
|
|
167
|
+
|
|
168
|
+
window.addEventListener('mousemove', mousemove)
|
|
169
|
+
window.addEventListener('mouseup', mouseup)
|
|
170
|
+
window.addEventListener('keydown', keydown)
|
|
171
|
+
})
|
|
172
|
+
onUnmounted(() => {
|
|
173
|
+
window.removeEventListener('mouseup', mouseup)
|
|
174
|
+
window.removeEventListener('mousemove', mousemove)
|
|
175
|
+
window.removeEventListener('keydown', keydown)
|
|
176
|
+
})
|
|
177
|
+
</script>
|
|
178
|
+
|
|
179
|
+
<style scoped lang="scss">
|
|
180
|
+
@import '@/assets/scss/common/mixins';
|
|
181
|
+
.horizontal {
|
|
182
|
+
&.dragging {
|
|
183
|
+
.gutter-horizontal.gutter {
|
|
184
|
+
background-color: var(--gutter-active-bg-color);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
.firstPanel {
|
|
188
|
+
width: calc(50% - 1.5px);
|
|
189
|
+
|
|
190
|
+
.left-panel {
|
|
191
|
+
@include flex($dir: column);
|
|
192
|
+
width: 100%;
|
|
193
|
+
height: 100%;
|
|
194
|
+
|
|
195
|
+
.panel-toggle {
|
|
196
|
+
border-bottom: 1px solid var(--global-border-color);
|
|
197
|
+
|
|
198
|
+
&.collapsed {
|
|
199
|
+
border-right: 1px solid var(--global-border-color);
|
|
200
|
+
|
|
201
|
+
.btn-trigger {
|
|
202
|
+
.trigger-icon {
|
|
203
|
+
transform: rotate(90deg);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.btn-trigger {
|
|
209
|
+
@include flex($align: center);
|
|
210
|
+
width: 100%;
|
|
211
|
+
height: 36px;
|
|
212
|
+
flex: 0 0 36px;
|
|
213
|
+
border: 0;
|
|
214
|
+
padding: 0;
|
|
215
|
+
background-color: transparent;
|
|
216
|
+
outline: none;
|
|
217
|
+
cursor: pointer;
|
|
218
|
+
|
|
219
|
+
.trigger-icon {
|
|
220
|
+
width: 16px;
|
|
221
|
+
height: 16px;
|
|
222
|
+
transform: rotate(-90deg);
|
|
223
|
+
margin-left: auto;
|
|
224
|
+
fill: var(--triger-icon-color);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
.navigator {
|
|
229
|
+
overflow: hidden;
|
|
230
|
+
height: 100%;
|
|
231
|
+
|
|
232
|
+
.panel-inner {
|
|
233
|
+
position: relative;
|
|
234
|
+
height: 100%;
|
|
235
|
+
background: var(--horizontal-panel-bg-color);
|
|
236
|
+
border-radius: 0;
|
|
237
|
+
border: 0;
|
|
238
|
+
|
|
239
|
+
&.inventory-tree {
|
|
240
|
+
padding-left: 4px;
|
|
241
|
+
padding-top: 6px;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
.gutter-horizontal {
|
|
248
|
+
position: relative;
|
|
249
|
+
width: 3px;
|
|
250
|
+
background-color: var(--gutter-bg-color);
|
|
251
|
+
transition-delay: 0.25s;
|
|
252
|
+
transition-duration: 0.25s;
|
|
253
|
+
|
|
254
|
+
&-handler {
|
|
255
|
+
position: absolute;
|
|
256
|
+
height: 100%;
|
|
257
|
+
width: 10px;
|
|
258
|
+
background: transparent;
|
|
259
|
+
top: 0;
|
|
260
|
+
left: -3.5px;
|
|
261
|
+
z-index: 2;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
&:focus {
|
|
265
|
+
background-color: var(--gutter-active-bg-color);
|
|
266
|
+
outline: none;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
&:hover {
|
|
270
|
+
background-color: var(--gutter-hover-bg-color);
|
|
271
|
+
cursor: col-resize;
|
|
272
|
+
&:before {
|
|
273
|
+
background-color: hsla(0, 0%, 100%, 0.5);
|
|
274
|
+
box-shadow: inset 0 0 0 1px rgb(0 0 0 / 10%);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
&:before {
|
|
279
|
+
content: '';
|
|
280
|
+
position: relative;
|
|
281
|
+
display: block;
|
|
282
|
+
background: rgba(0, 0, 0, 0.1);
|
|
283
|
+
transition-delay: 0.25s;
|
|
284
|
+
transition-duration: 0.25s;
|
|
285
|
+
width: 100%;
|
|
286
|
+
height: 25px;
|
|
287
|
+
top: calc(50% - 12.5px);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
.secondPanel {
|
|
291
|
+
width: calc(50% - 1.5px);
|
|
292
|
+
&.right {
|
|
293
|
+
overflow: hidden;
|
|
294
|
+
height: 100%;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
</style>
|
|
299
|
+
|
|
300
|
+
<style>
|
|
301
|
+
:root {
|
|
302
|
+
--horizontal-panel-bg-color: #fff;
|
|
303
|
+
}
|
|
304
|
+
:root.dark-theme {
|
|
305
|
+
--horizontal-panel-bg-color: #1b2a32;
|
|
306
|
+
}
|
|
307
|
+
</style>
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<select
|
|
17
17
|
:id="`vm-wizard-${props.componentType}-bus-field-${props.index}`"
|
|
18
18
|
v-model="busLocal"
|
|
19
|
-
:data-id="
|
|
19
|
+
:data-id="`${props.testId}-select`"
|
|
20
20
|
:class="`vm-wizard-${props.componentType}-bus-field-${props.index}`"
|
|
21
21
|
:disabled="props.disabled"
|
|
22
22
|
>
|
|
@@ -32,9 +32,13 @@
|
|
|
32
32
|
</template>
|
|
33
33
|
<template #content>{{ apiError }}</template>
|
|
34
34
|
</atoms-tooltip-error>
|
|
35
|
-
<div
|
|
35
|
+
<div
|
|
36
|
+
v-if="props.helpText"
|
|
37
|
+
:id="helpId"
|
|
38
|
+
class="content-signpost relative"
|
|
39
|
+
>
|
|
36
40
|
<atoms-the-icon
|
|
37
|
-
:data-id="
|
|
41
|
+
:data-id="`${props.testId}-show-help-icon`"
|
|
38
42
|
class="icon-show-help"
|
|
39
43
|
fill="#0072a3"
|
|
40
44
|
width="24px"
|
|
@@ -50,7 +54,7 @@
|
|
|
50
54
|
@hide="isShowHelp = false"
|
|
51
55
|
>
|
|
52
56
|
<p>
|
|
53
|
-
<!-- {{ localization.busVirtioHelpDesc }}-->
|
|
57
|
+
<!-- {{ localization.busVirtioHelpDesc }}-->
|
|
54
58
|
{{ props.helpText }}
|
|
55
59
|
</p>
|
|
56
60
|
</atoms-tooltip-signpost>
|
|
@@ -74,6 +78,7 @@ const props = defineProps<{
|
|
|
74
78
|
bus: string
|
|
75
79
|
index: number
|
|
76
80
|
componentType: string
|
|
81
|
+
testId: string
|
|
77
82
|
errorValidationFields: UI_I_ErrorValidationField<string>[]
|
|
78
83
|
disabled?: boolean
|
|
79
84
|
shortOptions?: boolean
|
|
@@ -72,10 +72,11 @@
|
|
|
72
72
|
<!-- :short-options="props.type === 'edit'" // поменял из-за задачки PNCWEB-384-->
|
|
73
73
|
<common-vm-actions-common-customize-hardware-virtual-hardware-bus
|
|
74
74
|
v-model:bus="bus"
|
|
75
|
-
:index="
|
|
75
|
+
:index="indexByHardDisks"
|
|
76
76
|
:validation-type="busValidationType"
|
|
77
77
|
:error-validation-fields="props.errorValidationFields"
|
|
78
78
|
:disabled="isRunning"
|
|
79
|
+
:test-id="`vm-wizard-cd-dvd-bus-field-${props.index}`"
|
|
79
80
|
short-options
|
|
80
81
|
component-type="disk_devices"
|
|
81
82
|
@remove-error-by-title="emits('remove-error-by-title', $event)"
|
|
@@ -159,6 +159,7 @@
|
|
|
159
159
|
:error-validation-fields="props.errorValidationFields"
|
|
160
160
|
:disabled="isRunning"
|
|
161
161
|
:help-text="localization.busVirtioHelpDesc"
|
|
162
|
+
:test-id="`vm-wizard-disk-bus-field-${props.index}`"
|
|
162
163
|
component-type="disk_devices"
|
|
163
164
|
@remove-error-by-title="emits('remove-error-by-title', $event)"
|
|
164
165
|
/>
|