bfg-common 1.5.450 → 1.5.452
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.
@@ -0,0 +1,360 @@
|
|
1
|
+
<template>
|
2
|
+
<div
|
3
|
+
class="window-container"
|
4
|
+
:style="{
|
5
|
+
left: x + 'px',
|
6
|
+
top: y + 'px',
|
7
|
+
width: width + 'px',
|
8
|
+
height: height + 'px',
|
9
|
+
}"
|
10
|
+
>
|
11
|
+
<div ref="headerEl" class="window-header">
|
12
|
+
<div class="window-title">{{ props.title }}</div>
|
13
|
+
<button class="window-close" @click="onHide">
|
14
|
+
<ui-icon name="close" class="close-icon" />
|
15
|
+
</button>
|
16
|
+
</div>
|
17
|
+
|
18
|
+
<div class="window-content">
|
19
|
+
<slot></slot>
|
20
|
+
<div
|
21
|
+
v-show="isShowContentBlocker"
|
22
|
+
:style="{}"
|
23
|
+
class="content-blocker"
|
24
|
+
></div>
|
25
|
+
</div>
|
26
|
+
|
27
|
+
<!-- Ручки для ресайза -->
|
28
|
+
<div
|
29
|
+
class="resize-handle resize-top"
|
30
|
+
@mousedown="startResize($event, 'top')"
|
31
|
+
></div>
|
32
|
+
<div
|
33
|
+
class="resize-handle resize-right"
|
34
|
+
@mousedown="startResize($event, 'right')"
|
35
|
+
></div>
|
36
|
+
<div
|
37
|
+
class="resize-handle resize-bottom"
|
38
|
+
@mousedown="startResize($event, 'bottom')"
|
39
|
+
></div>
|
40
|
+
<div
|
41
|
+
class="resize-handle resize-left"
|
42
|
+
@mousedown="startResize($event, 'left')"
|
43
|
+
></div>
|
44
|
+
<div
|
45
|
+
class="resize-handle resize-top-left"
|
46
|
+
@mousedown="startResize($event, 'top-left')"
|
47
|
+
></div>
|
48
|
+
<div
|
49
|
+
class="resize-handle resize-top-right"
|
50
|
+
@mousedown="startResize($event, 'top-right')"
|
51
|
+
></div>
|
52
|
+
<div
|
53
|
+
class="resize-handle resize-bottom-left"
|
54
|
+
@mousedown="startResize($event, 'bottom-left')"
|
55
|
+
></div>
|
56
|
+
<div
|
57
|
+
class="resize-handle resize-bottom-right"
|
58
|
+
@mousedown="startResize($event, 'bottom-right')"
|
59
|
+
></div>
|
60
|
+
</div>
|
61
|
+
</template>
|
62
|
+
|
63
|
+
<script setup lang="ts">
|
64
|
+
import { useDraggable } from '@vueuse/core'
|
65
|
+
|
66
|
+
const props = defineProps<{
|
67
|
+
top: number
|
68
|
+
left: number
|
69
|
+
width: number
|
70
|
+
height: number
|
71
|
+
title: string
|
72
|
+
}>()
|
73
|
+
const emits = defineEmits<{
|
74
|
+
(event: 'hide'): void
|
75
|
+
}>()
|
76
|
+
|
77
|
+
const headerEl = ref(null)
|
78
|
+
const isShowContentBlocker = ref<boolean>(false)
|
79
|
+
|
80
|
+
const x = ref(props.left)
|
81
|
+
const y = ref(props.top)
|
82
|
+
const width = ref(props.width)
|
83
|
+
const height = ref(props.height)
|
84
|
+
|
85
|
+
// Используем vueuse для перетаскивания
|
86
|
+
useDraggable(headerEl, {
|
87
|
+
initialValue: { x: props.left, y: props.top },
|
88
|
+
onMove({ x: newX, y: newY }) {
|
89
|
+
x.value = newX
|
90
|
+
y.value = newY
|
91
|
+
},
|
92
|
+
onStart() {
|
93
|
+
isShowContentBlocker.value = true
|
94
|
+
},
|
95
|
+
onEnd() {
|
96
|
+
isShowContentBlocker.value = false
|
97
|
+
fixPosition()
|
98
|
+
},
|
99
|
+
})
|
100
|
+
|
101
|
+
const fixSize = (): void => {
|
102
|
+
const globalWindowWidth = window.innerWidth
|
103
|
+
const globalWindowHeight = window.innerHeight
|
104
|
+
|
105
|
+
width.value = Math.min(globalWindowWidth - 8 * 2, width.value)
|
106
|
+
height.value = Math.min(globalWindowHeight - 8 * 2, height.value)
|
107
|
+
}
|
108
|
+
const fixPosition = (): void => {
|
109
|
+
const globalWindowWidth = window.innerWidth
|
110
|
+
const globalWindowHeight = window.innerHeight
|
111
|
+
let newX = x.value
|
112
|
+
let newY = y.value
|
113
|
+
if (x.value + width.value / 2 > globalWindowWidth) {
|
114
|
+
newX = globalWindowWidth - 20
|
115
|
+
} else if (x.value + width.value > globalWindowWidth - 8) {
|
116
|
+
newX = globalWindowWidth - width.value - 8
|
117
|
+
} else if (x.value < 8) {
|
118
|
+
newX = 8
|
119
|
+
}
|
120
|
+
|
121
|
+
if (y.value + height.value / 2 > globalWindowHeight) {
|
122
|
+
newY = globalWindowHeight - 20
|
123
|
+
} else if (y.value + height.value > globalWindowHeight - 8) {
|
124
|
+
newY = globalWindowHeight - height.value - 8
|
125
|
+
} else if (y.value < 8) {
|
126
|
+
newY = 8
|
127
|
+
}
|
128
|
+
|
129
|
+
smoothMove(newX, newY)
|
130
|
+
}
|
131
|
+
const smoothMove = (newX: number, newY: number, duration = 100): void => {
|
132
|
+
const startX = x.value
|
133
|
+
const startY = y.value
|
134
|
+
|
135
|
+
// Время начала анимации
|
136
|
+
const startTime = performance.now()
|
137
|
+
|
138
|
+
// Функция анимации
|
139
|
+
const animate = (currentTime: number): void => {
|
140
|
+
// Прошедшее время с начала анимации
|
141
|
+
const elapsedTime = currentTime - startTime
|
142
|
+
|
143
|
+
// Прогресс анимации (от 0 до 1)
|
144
|
+
const progress = Math.min(elapsedTime / duration, 1)
|
145
|
+
|
146
|
+
// Вычисляем новые координаты с помощью линейной интерполяции
|
147
|
+
x.value = startX + (newX - startX) * progress
|
148
|
+
y.value = startY + (newY - startY) * progress
|
149
|
+
|
150
|
+
// Если анимация не завершена, продолжаем
|
151
|
+
if (progress < 1) {
|
152
|
+
requestAnimationFrame(animate)
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
// Запускаем анимацию
|
157
|
+
requestAnimationFrame(animate)
|
158
|
+
}
|
159
|
+
|
160
|
+
// Функция для ресайза
|
161
|
+
const startResize = (e: any, direction: any): void => {
|
162
|
+
e.preventDefault()
|
163
|
+
|
164
|
+
const startX = e.clientX
|
165
|
+
const startY = e.clientY
|
166
|
+
const startWidth = width.value
|
167
|
+
const startHeight = height.value
|
168
|
+
const startLeft = x.value
|
169
|
+
const startTop = y.value
|
170
|
+
|
171
|
+
const onMouseMove = (e: any): void => {
|
172
|
+
const deltaX = e.clientX - startX
|
173
|
+
const deltaY = e.clientY - startY
|
174
|
+
|
175
|
+
if (direction.includes('right')) {
|
176
|
+
width.value = Math.max(200, startWidth + deltaX)
|
177
|
+
}
|
178
|
+
if (direction.includes('bottom')) {
|
179
|
+
height.value = Math.max(150, startHeight + deltaY)
|
180
|
+
}
|
181
|
+
if (direction.includes('left')) {
|
182
|
+
const newWidth = Math.max(200, startWidth - deltaX)
|
183
|
+
if (newWidth !== width.value) {
|
184
|
+
x.value = startLeft + deltaX
|
185
|
+
width.value = newWidth
|
186
|
+
}
|
187
|
+
}
|
188
|
+
if (direction.includes('top')) {
|
189
|
+
const newHeight = Math.max(150, startHeight - deltaY)
|
190
|
+
if (newHeight !== height.value) {
|
191
|
+
y.value = startTop + deltaY
|
192
|
+
height.value = newHeight
|
193
|
+
}
|
194
|
+
}
|
195
|
+
fixSize()
|
196
|
+
}
|
197
|
+
|
198
|
+
const onMouseUp = (): void => {
|
199
|
+
document.removeEventListener('mousemove', onMouseMove)
|
200
|
+
document.removeEventListener('mouseup', onMouseUp)
|
201
|
+
isShowContentBlocker.value = false
|
202
|
+
fixPosition()
|
203
|
+
}
|
204
|
+
|
205
|
+
document.addEventListener('mousemove', onMouseMove)
|
206
|
+
document.addEventListener('mouseup', onMouseUp)
|
207
|
+
isShowContentBlocker.value = true
|
208
|
+
}
|
209
|
+
|
210
|
+
let resizeTimer: any = null
|
211
|
+
const globalWindowResize = (): void => {
|
212
|
+
clearTimeout(resizeTimer)
|
213
|
+
|
214
|
+
resizeTimer = setTimeout(() => {
|
215
|
+
fixSize()
|
216
|
+
fixPosition()
|
217
|
+
}, 250)
|
218
|
+
}
|
219
|
+
onMounted(() => {
|
220
|
+
window.addEventListener('resize', globalWindowResize)
|
221
|
+
})
|
222
|
+
onUnmounted(() => {
|
223
|
+
window.removeEventListener('resize', globalWindowResize)
|
224
|
+
})
|
225
|
+
|
226
|
+
const onHide = (): void => {
|
227
|
+
emits('hide')
|
228
|
+
}
|
229
|
+
</script>
|
230
|
+
|
231
|
+
<style lang="scss">
|
232
|
+
.window-container {
|
233
|
+
position: absolute;
|
234
|
+
border-radius: 8px;
|
235
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
236
|
+
overflow: hidden;
|
237
|
+
background-color: #fff;
|
238
|
+
display: flex;
|
239
|
+
flex-direction: column;
|
240
|
+
min-width: 300px;
|
241
|
+
min-height: 200px;
|
242
|
+
z-index: var(--z-toast);
|
243
|
+
|
244
|
+
.window-header {
|
245
|
+
background-color: #314351;
|
246
|
+
color: white;
|
247
|
+
padding: 6px 12px;
|
248
|
+
cursor: move;
|
249
|
+
user-select: none;
|
250
|
+
display: flex;
|
251
|
+
justify-content: space-between;
|
252
|
+
align-items: center;
|
253
|
+
|
254
|
+
.window-title {
|
255
|
+
font-weight: 500;
|
256
|
+
font-size: 16px;
|
257
|
+
}
|
258
|
+
|
259
|
+
.window-close {
|
260
|
+
background: none;
|
261
|
+
border: none;
|
262
|
+
color: #e4e4e4;
|
263
|
+
cursor: pointer;
|
264
|
+
width: 20px;
|
265
|
+
height: 20px;
|
266
|
+
display: flex;
|
267
|
+
justify-content: center;
|
268
|
+
align-items: center;
|
269
|
+
|
270
|
+
&:hover {
|
271
|
+
color: #ffffff;
|
272
|
+
}
|
273
|
+
}
|
274
|
+
}
|
275
|
+
|
276
|
+
.window-content {
|
277
|
+
position: relative;
|
278
|
+
flex-grow: 1;
|
279
|
+
|
280
|
+
.content-blocker {
|
281
|
+
position: absolute;
|
282
|
+
top: 0;
|
283
|
+
left: 0;
|
284
|
+
width: 100%;
|
285
|
+
height: 100%;
|
286
|
+
z-index: 1;
|
287
|
+
}
|
288
|
+
}
|
289
|
+
|
290
|
+
.resize-handle {
|
291
|
+
position: absolute;
|
292
|
+
background: transparent;
|
293
|
+
z-index: 10;
|
294
|
+
|
295
|
+
&.resize-top {
|
296
|
+
top: -3px;
|
297
|
+
left: 0;
|
298
|
+
right: 0;
|
299
|
+
height: 6px;
|
300
|
+
cursor: n-resize;
|
301
|
+
}
|
302
|
+
|
303
|
+
&.resize-right {
|
304
|
+
top: 0;
|
305
|
+
right: -3px;
|
306
|
+
bottom: 0;
|
307
|
+
width: 6px;
|
308
|
+
cursor: e-resize;
|
309
|
+
}
|
310
|
+
|
311
|
+
&.resize-bottom {
|
312
|
+
bottom: -3px;
|
313
|
+
left: 0;
|
314
|
+
right: 0;
|
315
|
+
height: 6px;
|
316
|
+
cursor: s-resize;
|
317
|
+
}
|
318
|
+
|
319
|
+
&.resize-left {
|
320
|
+
top: 0;
|
321
|
+
left: -3px;
|
322
|
+
bottom: 0;
|
323
|
+
width: 6px;
|
324
|
+
cursor: w-resize;
|
325
|
+
}
|
326
|
+
|
327
|
+
&.resize-top-left {
|
328
|
+
top: -6px;
|
329
|
+
left: -6px;
|
330
|
+
width: 12px;
|
331
|
+
height: 12px;
|
332
|
+
cursor: nw-resize;
|
333
|
+
}
|
334
|
+
|
335
|
+
&.resize-top-right {
|
336
|
+
top: -6px;
|
337
|
+
right: -6px;
|
338
|
+
width: 12px;
|
339
|
+
height: 12px;
|
340
|
+
cursor: ne-resize;
|
341
|
+
}
|
342
|
+
|
343
|
+
&.resize-bottom-left {
|
344
|
+
bottom: -6px;
|
345
|
+
left: -6px;
|
346
|
+
width: 12px;
|
347
|
+
height: 12px;
|
348
|
+
cursor: sw-resize;
|
349
|
+
}
|
350
|
+
|
351
|
+
&.resize-bottom-right {
|
352
|
+
bottom: -6px;
|
353
|
+
right: -6px;
|
354
|
+
width: 12px;
|
355
|
+
height: 12px;
|
356
|
+
cursor: se-resize;
|
357
|
+
}
|
358
|
+
}
|
359
|
+
}
|
360
|
+
</style>
|
@@ -12,12 +12,12 @@ export const vmMigrateSelectPriorityTypesFunc = (
|
|
12
12
|
disabled: vmState !== 2,
|
13
13
|
description: localization.migrateVm.liveMigrationDesc,
|
14
14
|
},
|
15
|
-
{
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
},
|
15
|
+
// {
|
16
|
+
// label: localization.migrateVm.ramSuspendMigration,
|
17
|
+
// value: 'ram-suspend',
|
18
|
+
// disabled: vmState !== 2,
|
19
|
+
// description: localization.migrateVm.ramSuspendMigrationDesc,
|
20
|
+
// },
|
21
21
|
{
|
22
22
|
label: localization.migrateVm.offlineMigration,
|
23
23
|
value: 'offline',
|