bfg-common 1.5.451 → 1.5.453
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 +2 -1
- package/assets/localization/local_en.json +2 -1
- package/assets/localization/local_hy.json +2 -1
- package/assets/localization/local_kk.json +2 -1
- package/assets/localization/local_ru.json +2 -1
- package/assets/localization/local_zh.json +2 -1
- package/assets/scss/clarity/local_ar.json +2 -1
- package/components/atoms/window/Window.vue +440 -0
- package/components/atoms/window/lib/config/config.ts +4 -0
- package/components/atoms/window/lib/models/interfaces.ts +7 -0
- package/components/common/monitor/advanced/AdvancedOld.vue +1 -1
- package/components/common/spiceConsole/Drawer.vue +89 -81
- package/components/common/spiceConsole/SpiceConsole.vue +41 -0
- package/package.json +1 -1
@@ -3252,7 +3252,8 @@
|
|
3252
3252
|
"channels": "Каналы ({0})",
|
3253
3253
|
"metricsNotFound": "Паказчыкі не знойдзены",
|
3254
3254
|
"uploadFolder": "Тэчка загрузкі",
|
3255
|
-
"uploadFiles": "Запампаваць файлы"
|
3255
|
+
"uploadFiles": "Запампаваць файлы",
|
3256
|
+
"clickForUse": "Націсніце для выкарыстання"
|
3256
3257
|
},
|
3257
3258
|
"vmWizard": {
|
3258
3259
|
"selectCreationType": "Выберыце тып стварэння",
|
@@ -3256,7 +3256,8 @@
|
|
3256
3256
|
"channels": "Channels ({0})",
|
3257
3257
|
"metricsNotFound": "Metrics not found",
|
3258
3258
|
"uploadFolder": "Upload folder",
|
3259
|
-
"uploadFiles": "Upload files"
|
3259
|
+
"uploadFiles": "Upload files",
|
3260
|
+
"clickForUse": "Click for use"
|
3260
3261
|
},
|
3261
3262
|
"vmWizard": {
|
3262
3263
|
"selectCreationType": "Select a Creation Type",
|
@@ -3256,7 +3256,8 @@
|
|
3256
3256
|
"channels": "Ալիքներ ({0})",
|
3257
3257
|
"metricsNotFound": "Չափանիշները չեն գտնվել",
|
3258
3258
|
"uploadFolder": "Վերբեռնեք թղթապանակը",
|
3259
|
-
"uploadFiles": "Վերբեռնեք ֆայլեր"
|
3259
|
+
"uploadFiles": "Վերբեռնեք ֆայլեր",
|
3260
|
+
"clickForUse": "Կտտացրեք օգտագործման համար"
|
3260
3261
|
},
|
3261
3262
|
"vmWizard": {
|
3262
3263
|
"selectCreationType": "Ընտրեք ստեղծման տեսակը",
|
@@ -3255,7 +3255,8 @@
|
|
3255
3255
|
"channels": "Арналар ({0})",
|
3256
3256
|
"metricsNotFound": "Көрсеткіштер табылмады",
|
3257
3257
|
"uploadFolder": "Қалтаны жүктеп салу",
|
3258
|
-
"uploadFiles": "Файлдарды жүктеп салу"
|
3258
|
+
"uploadFiles": "Файлдарды жүктеп салу",
|
3259
|
+
"clickForUse": "Пайдалану үшін басыңыз"
|
3259
3260
|
},
|
3260
3261
|
"vmWizard": {
|
3261
3262
|
"selectCreationType": "Жасау түрін таңдаңыз",
|
@@ -3255,7 +3255,8 @@
|
|
3255
3255
|
"channels": "Каналы ({0})",
|
3256
3256
|
"metricsNotFound": "Метрики не найдены",
|
3257
3257
|
"uploadFolder": "Загрузить папку",
|
3258
|
-
"uploadFiles": "Загрузить файлы"
|
3258
|
+
"uploadFiles": "Загрузить файлы",
|
3259
|
+
"clickForUse": "Нажмите для использования"
|
3259
3260
|
},
|
3260
3261
|
"vmWizard": {
|
3261
3262
|
"selectCreationType": "Выбор типа создания",
|
@@ -2906,7 +2906,8 @@
|
|
2906
2906
|
"channels": "القنوات ({0})",
|
2907
2907
|
"metricsNotFound": "لم يتم العثور على المقاييس",
|
2908
2908
|
"uploadFolder": "تحميل مجلد",
|
2909
|
-
"uploadFiles": "تحميل ملفات"
|
2909
|
+
"uploadFiles": "تحميل ملفات",
|
2910
|
+
"clickForUse": "انقر للاستخدام"
|
2910
2911
|
},
|
2911
2912
|
"vmWizard": {
|
2912
2913
|
"devices": "الأجهزة ({0})",
|
@@ -0,0 +1,440 @@
|
|
1
|
+
<template>
|
2
|
+
<div
|
3
|
+
:class="['window-container', { loading: props.loading }]"
|
4
|
+
:style="{
|
5
|
+
left: leftLocal + 'px',
|
6
|
+
top: topLocal + 'px',
|
7
|
+
width: widthLocal + 'px',
|
8
|
+
height: heightLocal + 'px',
|
9
|
+
}"
|
10
|
+
>
|
11
|
+
<div ref="headerEl" class="window-header">
|
12
|
+
<slot name="header">
|
13
|
+
<div class="window-title">{{ props.title }}</div>
|
14
|
+
</slot>
|
15
|
+
|
16
|
+
<div class="flex-align-center">
|
17
|
+
<button class="window-close" @click="onCollapse">
|
18
|
+
<ui-icon
|
19
|
+
:name="collapseData.isCollapsed ? 'arrow' : 'check-line'"
|
20
|
+
class="hide-icon"
|
21
|
+
/>
|
22
|
+
</button>
|
23
|
+
<button class="window-close ml-1" @click="onHide">
|
24
|
+
<ui-icon name="close" class="close-icon" />
|
25
|
+
</button>
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
|
29
|
+
<div class="window-content">
|
30
|
+
<div v-show="props.loading" class="absolute-center">
|
31
|
+
<ui-icon name="spinner" />
|
32
|
+
</div>
|
33
|
+
<slot></slot>
|
34
|
+
<div v-show="isShowContentBlocker" class="content-blocker"></div>
|
35
|
+
</div>
|
36
|
+
|
37
|
+
<!-- Ручки для ресайза -->
|
38
|
+
<div
|
39
|
+
class="resize-handle resize-top"
|
40
|
+
@mousedown="startResize($event, 'top')"
|
41
|
+
></div>
|
42
|
+
<div
|
43
|
+
class="resize-handle resize-right"
|
44
|
+
@mousedown="startResize($event, 'right')"
|
45
|
+
></div>
|
46
|
+
<div
|
47
|
+
class="resize-handle resize-bottom"
|
48
|
+
@mousedown="startResize($event, 'bottom')"
|
49
|
+
></div>
|
50
|
+
<div
|
51
|
+
class="resize-handle resize-left"
|
52
|
+
@mousedown="startResize($event, 'left')"
|
53
|
+
></div>
|
54
|
+
<div
|
55
|
+
class="resize-handle resize-top-left"
|
56
|
+
@mousedown="startResize($event, 'top-left')"
|
57
|
+
></div>
|
58
|
+
<div
|
59
|
+
class="resize-handle resize-top-right"
|
60
|
+
@mousedown="startResize($event, 'top-right')"
|
61
|
+
></div>
|
62
|
+
<div
|
63
|
+
class="resize-handle resize-bottom-left"
|
64
|
+
@mousedown="startResize($event, 'bottom-left')"
|
65
|
+
></div>
|
66
|
+
<div
|
67
|
+
class="resize-handle resize-bottom-right"
|
68
|
+
@mousedown="startResize($event, 'bottom-right')"
|
69
|
+
></div>
|
70
|
+
</div>
|
71
|
+
</template>
|
72
|
+
|
73
|
+
<script setup lang="ts">
|
74
|
+
import { useDraggable } from '@vueuse/core'
|
75
|
+
import type { UI_I_WindowCollapsedData } from '~/components/atoms/window/lib/models/interfaces'
|
76
|
+
import {
|
77
|
+
minWidth,
|
78
|
+
minHeight,
|
79
|
+
headerHeight,
|
80
|
+
windowPadding,
|
81
|
+
} from '~/components/atoms/window/lib/config/config'
|
82
|
+
|
83
|
+
const props = withDefaults(
|
84
|
+
defineProps<{
|
85
|
+
top: number
|
86
|
+
left: number
|
87
|
+
width: number
|
88
|
+
height: number
|
89
|
+
title: string
|
90
|
+
loading?: boolean
|
91
|
+
}>(),
|
92
|
+
{
|
93
|
+
loading: false,
|
94
|
+
}
|
95
|
+
)
|
96
|
+
const emits = defineEmits<{
|
97
|
+
(event: 'hide'): void
|
98
|
+
}>()
|
99
|
+
|
100
|
+
const headerEl = ref(null)
|
101
|
+
const isShowContentBlocker = ref<boolean>(false)
|
102
|
+
|
103
|
+
const leftLocal = ref<number>(props.left)
|
104
|
+
const topLocal = ref<number>(props.top)
|
105
|
+
const widthLocal = ref<number>(Math.max(minWidth, props.width))
|
106
|
+
const heightLocal = ref<number>(Math.max(minHeight, props.height))
|
107
|
+
|
108
|
+
const collapseData = ref<UI_I_WindowCollapsedData>({
|
109
|
+
isCollapsed: false,
|
110
|
+
cashTop: -1,
|
111
|
+
cashLeft: -1,
|
112
|
+
cashWidth: -1,
|
113
|
+
cashHeight: -1,
|
114
|
+
})
|
115
|
+
|
116
|
+
// Используем vueuse для перетаскивания
|
117
|
+
useDraggable(headerEl, {
|
118
|
+
initialValue: { x: leftLocal.value, y: topLocal.value },
|
119
|
+
onMove({ x: newX, y: newY }) {
|
120
|
+
leftLocal.value = newX
|
121
|
+
topLocal.value = newY
|
122
|
+
},
|
123
|
+
onStart() {
|
124
|
+
isShowContentBlocker.value = true
|
125
|
+
if (!collapseData.value.isCollapsed) {
|
126
|
+
collapseData.value.cashTop = topLocal.value
|
127
|
+
collapseData.value.cashLeft = leftLocal.value
|
128
|
+
collapseData.value.cashWidth = widthLocal.value
|
129
|
+
collapseData.value.cashHeight = heightLocal.value
|
130
|
+
}
|
131
|
+
},
|
132
|
+
onEnd() {
|
133
|
+
isShowContentBlocker.value = false
|
134
|
+
fixPosition()
|
135
|
+
},
|
136
|
+
})
|
137
|
+
|
138
|
+
const fixSize = (): void => {
|
139
|
+
const globalWindowWidth = window.innerWidth
|
140
|
+
const globalWindowHeight = window.innerHeight
|
141
|
+
|
142
|
+
widthLocal.value = Math.min(
|
143
|
+
globalWindowWidth - windowPadding * 2,
|
144
|
+
widthLocal.value
|
145
|
+
)
|
146
|
+
heightLocal.value = Math.min(
|
147
|
+
globalWindowHeight - windowPadding * 2,
|
148
|
+
heightLocal.value
|
149
|
+
)
|
150
|
+
}
|
151
|
+
const fixPosition = (): void => {
|
152
|
+
const globalWindowWidth = window.innerWidth
|
153
|
+
const globalWindowHeight = window.innerHeight
|
154
|
+
let newX = leftLocal.value
|
155
|
+
let newY = topLocal.value
|
156
|
+
|
157
|
+
if (leftLocal.value + widthLocal.value > globalWindowWidth - windowPadding) {
|
158
|
+
newX = globalWindowWidth - widthLocal.value - windowPadding
|
159
|
+
} else if (leftLocal.value < windowPadding) {
|
160
|
+
newX = windowPadding
|
161
|
+
}
|
162
|
+
|
163
|
+
if (topLocal.value + heightLocal.value / 2 > globalWindowHeight) {
|
164
|
+
newY = globalWindowHeight - headerHeight
|
165
|
+
collapseData.value.isCollapsed = true
|
166
|
+
} else if (
|
167
|
+
topLocal.value + heightLocal.value >
|
168
|
+
globalWindowHeight - windowPadding
|
169
|
+
) {
|
170
|
+
newY = globalWindowHeight - heightLocal.value - windowPadding
|
171
|
+
collapseData.value.isCollapsed = false
|
172
|
+
} else if (topLocal.value < windowPadding) {
|
173
|
+
newY = windowPadding
|
174
|
+
collapseData.value.isCollapsed = false
|
175
|
+
} else {
|
176
|
+
collapseData.value.isCollapsed = false
|
177
|
+
}
|
178
|
+
|
179
|
+
smoothMove(newX, newY)
|
180
|
+
}
|
181
|
+
const smoothMove = (newX: number, newY: number, duration = 100): void => {
|
182
|
+
const startX = leftLocal.value
|
183
|
+
const startY = topLocal.value
|
184
|
+
|
185
|
+
// Время начала анимации
|
186
|
+
const startTime = performance.now()
|
187
|
+
|
188
|
+
// Функция анимации
|
189
|
+
const animate = (currentTime: number): void => {
|
190
|
+
// Прошедшее время с начала анимации
|
191
|
+
const elapsedTime = currentTime - startTime
|
192
|
+
|
193
|
+
// Прогресс анимации (от 0 до 1)
|
194
|
+
const progress = Math.min(elapsedTime / duration, 1)
|
195
|
+
|
196
|
+
// Вычисляем новые координаты с помощью линейной интерполяции
|
197
|
+
leftLocal.value = startX + (newX - startX) * progress
|
198
|
+
topLocal.value = startY + (newY - startY) * progress
|
199
|
+
|
200
|
+
// Если анимация не завершена, продолжаем
|
201
|
+
if (progress < 1) {
|
202
|
+
requestAnimationFrame(animate)
|
203
|
+
}
|
204
|
+
}
|
205
|
+
|
206
|
+
// Запускаем анимацию
|
207
|
+
requestAnimationFrame(animate)
|
208
|
+
}
|
209
|
+
|
210
|
+
const onCollapse = (): void => {
|
211
|
+
collapseData.value.isCollapsed = !collapseData.value.isCollapsed
|
212
|
+
|
213
|
+
if (collapseData.value.isCollapsed) {
|
214
|
+
collapseData.value.cashTop = topLocal.value
|
215
|
+
collapseData.value.cashLeft = leftLocal.value
|
216
|
+
collapseData.value.cashWidth = widthLocal.value
|
217
|
+
collapseData.value.cashHeight = heightLocal.value
|
218
|
+
|
219
|
+
const globalWindowWidth = window.innerWidth
|
220
|
+
const globalWindowHeight = window.innerHeight
|
221
|
+
|
222
|
+
widthLocal.value = minWidth
|
223
|
+
heightLocal.value = minHeight
|
224
|
+
leftLocal.value = globalWindowWidth - widthLocal.value - windowPadding
|
225
|
+
topLocal.value = globalWindowHeight - headerHeight
|
226
|
+
fixPosition()
|
227
|
+
} else {
|
228
|
+
leftLocal.value = collapseData.value.cashLeft
|
229
|
+
topLocal.value = collapseData.value.cashTop
|
230
|
+
widthLocal.value = collapseData.value.cashWidth
|
231
|
+
heightLocal.value = collapseData.value.cashHeight
|
232
|
+
fixPosition()
|
233
|
+
}
|
234
|
+
}
|
235
|
+
|
236
|
+
// Функция для ресайза
|
237
|
+
const startResize = (e: any, direction: any): void => {
|
238
|
+
e.preventDefault()
|
239
|
+
|
240
|
+
const startX = e.clientX
|
241
|
+
const startY = e.clientY
|
242
|
+
const startWidth = widthLocal.value
|
243
|
+
const startHeight = heightLocal.value
|
244
|
+
const startLeft = leftLocal.value
|
245
|
+
const startTop = topLocal.value
|
246
|
+
|
247
|
+
const onMouseMove = (e: any): void => {
|
248
|
+
const deltaX = e.clientX - startX
|
249
|
+
const deltaY = e.clientY - startY
|
250
|
+
|
251
|
+
if (direction.includes('right')) {
|
252
|
+
widthLocal.value = Math.max(minWidth, startWidth + deltaX)
|
253
|
+
}
|
254
|
+
if (direction.includes('bottom')) {
|
255
|
+
heightLocal.value = Math.max(minHeight, startHeight + deltaY)
|
256
|
+
}
|
257
|
+
if (direction.includes('left')) {
|
258
|
+
const newWidth = Math.max(minWidth, startWidth - deltaX)
|
259
|
+
if (newWidth !== widthLocal.value) {
|
260
|
+
leftLocal.value = startLeft + deltaX
|
261
|
+
widthLocal.value = newWidth
|
262
|
+
}
|
263
|
+
}
|
264
|
+
if (direction.includes('top')) {
|
265
|
+
const newHeight = Math.max(minHeight, startHeight - deltaY)
|
266
|
+
if (newHeight !== heightLocal.value) {
|
267
|
+
topLocal.value = startTop + deltaY
|
268
|
+
heightLocal.value = newHeight
|
269
|
+
}
|
270
|
+
}
|
271
|
+
fixSize()
|
272
|
+
}
|
273
|
+
|
274
|
+
const onMouseUp = (): void => {
|
275
|
+
document.removeEventListener('mousemove', onMouseMove)
|
276
|
+
document.removeEventListener('mouseup', onMouseUp)
|
277
|
+
isShowContentBlocker.value = false
|
278
|
+
fixPosition()
|
279
|
+
}
|
280
|
+
|
281
|
+
document.addEventListener('mousemove', onMouseMove)
|
282
|
+
document.addEventListener('mouseup', onMouseUp)
|
283
|
+
isShowContentBlocker.value = true
|
284
|
+
}
|
285
|
+
|
286
|
+
let resizeTimer: any = null
|
287
|
+
const globalWindowResize = (): void => {
|
288
|
+
clearTimeout(resizeTimer)
|
289
|
+
|
290
|
+
resizeTimer = setTimeout(() => {
|
291
|
+
fixSize()
|
292
|
+
fixPosition()
|
293
|
+
}, 250)
|
294
|
+
}
|
295
|
+
onMounted(() => {
|
296
|
+
window.addEventListener('resize', globalWindowResize)
|
297
|
+
})
|
298
|
+
onUnmounted(() => {
|
299
|
+
window.removeEventListener('resize', globalWindowResize)
|
300
|
+
})
|
301
|
+
|
302
|
+
const onHide = (): void => {
|
303
|
+
emits('hide')
|
304
|
+
}
|
305
|
+
</script>
|
306
|
+
|
307
|
+
<style lang="scss">
|
308
|
+
.window-container {
|
309
|
+
position: absolute;
|
310
|
+
border-radius: 8px;
|
311
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
|
312
|
+
overflow: hidden;
|
313
|
+
background-color: #fff;
|
314
|
+
display: flex;
|
315
|
+
flex-direction: column;
|
316
|
+
min-width: 300px;
|
317
|
+
min-height: 200px;
|
318
|
+
z-index: var(--z-toast);
|
319
|
+
|
320
|
+
&.loading {
|
321
|
+
opacity: 0.5;
|
322
|
+
}
|
323
|
+
|
324
|
+
.window-header {
|
325
|
+
background-color: #314351;
|
326
|
+
color: white;
|
327
|
+
padding: 6px 12px;
|
328
|
+
cursor: move;
|
329
|
+
user-select: none;
|
330
|
+
display: flex;
|
331
|
+
justify-content: space-between;
|
332
|
+
align-items: center;
|
333
|
+
|
334
|
+
.window-title {
|
335
|
+
font-weight: 500;
|
336
|
+
font-size: 16px;
|
337
|
+
}
|
338
|
+
|
339
|
+
.window-close {
|
340
|
+
background: none;
|
341
|
+
border: none;
|
342
|
+
color: #e4e4e4;
|
343
|
+
cursor: pointer;
|
344
|
+
width: 20px;
|
345
|
+
height: 20px;
|
346
|
+
display: flex;
|
347
|
+
justify-content: center;
|
348
|
+
align-items: center;
|
349
|
+
|
350
|
+
&:hover {
|
351
|
+
color: #ffffff;
|
352
|
+
}
|
353
|
+
}
|
354
|
+
}
|
355
|
+
|
356
|
+
.window-content {
|
357
|
+
position: relative;
|
358
|
+
flex-grow: 1;
|
359
|
+
|
360
|
+
.content-blocker {
|
361
|
+
position: absolute;
|
362
|
+
top: 0;
|
363
|
+
left: 0;
|
364
|
+
width: 100%;
|
365
|
+
height: 100%;
|
366
|
+
z-index: 1;
|
367
|
+
}
|
368
|
+
}
|
369
|
+
|
370
|
+
.resize-handle {
|
371
|
+
position: absolute;
|
372
|
+
background: transparent;
|
373
|
+
z-index: 10;
|
374
|
+
|
375
|
+
&.resize-top {
|
376
|
+
top: -3px;
|
377
|
+
left: 0;
|
378
|
+
right: 0;
|
379
|
+
height: 6px;
|
380
|
+
cursor: n-resize;
|
381
|
+
}
|
382
|
+
|
383
|
+
&.resize-right {
|
384
|
+
top: 0;
|
385
|
+
right: -3px;
|
386
|
+
bottom: 0;
|
387
|
+
width: 6px;
|
388
|
+
cursor: e-resize;
|
389
|
+
}
|
390
|
+
|
391
|
+
&.resize-bottom {
|
392
|
+
bottom: -3px;
|
393
|
+
left: 0;
|
394
|
+
right: 0;
|
395
|
+
height: 6px;
|
396
|
+
cursor: s-resize;
|
397
|
+
}
|
398
|
+
|
399
|
+
&.resize-left {
|
400
|
+
top: 0;
|
401
|
+
left: -3px;
|
402
|
+
bottom: 0;
|
403
|
+
width: 6px;
|
404
|
+
cursor: w-resize;
|
405
|
+
}
|
406
|
+
|
407
|
+
&.resize-top-left {
|
408
|
+
top: -6px;
|
409
|
+
left: -6px;
|
410
|
+
width: 12px;
|
411
|
+
height: 12px;
|
412
|
+
cursor: nw-resize;
|
413
|
+
}
|
414
|
+
|
415
|
+
&.resize-top-right {
|
416
|
+
top: -6px;
|
417
|
+
right: -6px;
|
418
|
+
width: 12px;
|
419
|
+
height: 12px;
|
420
|
+
cursor: ne-resize;
|
421
|
+
}
|
422
|
+
|
423
|
+
&.resize-bottom-left {
|
424
|
+
bottom: -6px;
|
425
|
+
left: -6px;
|
426
|
+
width: 12px;
|
427
|
+
height: 12px;
|
428
|
+
cursor: sw-resize;
|
429
|
+
}
|
430
|
+
|
431
|
+
&.resize-bottom-right {
|
432
|
+
bottom: -6px;
|
433
|
+
right: -6px;
|
434
|
+
width: 12px;
|
435
|
+
height: 12px;
|
436
|
+
cursor: se-resize;
|
437
|
+
}
|
438
|
+
}
|
439
|
+
}
|
440
|
+
</style>
|
@@ -53,7 +53,7 @@
|
|
53
53
|
@submit-options="emits('submit-options', $event)"
|
54
54
|
/>
|
55
55
|
|
56
|
-
<div v-show="!props.data" class="empty-container">
|
56
|
+
<div v-show="!props.data && !props.advancedLoading" class="empty-container">
|
57
57
|
{{
|
58
58
|
localization.inventoryMonitor
|
59
59
|
.noPerformanceCurrentlySelectedMetrics
|
@@ -16,90 +16,92 @@
|
|
16
16
|
<atoms-the-icon2 name="drag" class="vmw-drawer__drag-icon" />
|
17
17
|
</div>
|
18
18
|
|
19
|
-
<div class="
|
20
|
-
<
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
19
|
+
<div class="drawer-content">
|
20
|
+
<div class="vmw-drawer-header">
|
21
|
+
<h3>{{ localization.common.consolePanel }}</h3>
|
22
|
+
<atoms-the-icon
|
23
|
+
class="vmw-drawer-header__close"
|
24
|
+
data-id="spice-console-drawer-toggle-icon"
|
25
|
+
name="close"
|
26
|
+
@click="toggleDrawer"
|
27
|
+
/>
|
28
|
+
</div>
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
>
|
35
|
-
{{ localization.common.toggleFullscreenMode }}
|
36
|
-
</button>
|
37
|
-
<button
|
38
|
-
class="vmw-drawer-body__btn animation toggle-fullscreen"
|
39
|
-
@click="emits('send-alt-command')"
|
40
|
-
>
|
41
|
-
{{ localization.common.sendAltCommand }}
|
42
|
-
</button>
|
43
|
-
<label
|
44
|
-
v-development="true"
|
45
|
-
class="vmw-drawer-body__btn animation relative"
|
46
|
-
>
|
47
|
-
{{ localization.remoteConsole.uploadFolder }}
|
48
|
-
<input type="file" webkitdirectory directory multiple />
|
49
|
-
</label>
|
50
|
-
<label
|
51
|
-
v-development="true"
|
52
|
-
class="vmw-drawer-body__btn animation relative"
|
53
|
-
>
|
54
|
-
{{ localization.remoteConsole.uploadFiles }}
|
55
|
-
<input type="file" multiple />
|
56
|
-
</label>
|
57
|
-
|
58
|
-
<select
|
59
|
-
v-model="usbDevice"
|
60
|
-
v-development="true"
|
61
|
-
@mouseenter="hover = true"
|
62
|
-
@mouseleave="hover = false"
|
63
|
-
@change="onChangeUsbDevice"
|
64
|
-
>
|
65
|
-
<option
|
66
|
-
v-for="item in usbDevices"
|
67
|
-
:key="item.value"
|
68
|
-
:value="item.value"
|
69
|
-
:disabled="item.disabled"
|
30
|
+
<div class="vmw-drawer-body">
|
31
|
+
<button
|
32
|
+
class="vmw-drawer-body__btn animation toggle-fullscreen"
|
33
|
+
data-id="spice-console-drawer-toggle-fullscreen"
|
34
|
+
@click="emits('toggle-fullscreen')"
|
70
35
|
>
|
71
|
-
{{
|
72
|
-
</
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
36
|
+
{{ localization.common.toggleFullscreenMode }}
|
37
|
+
</button>
|
38
|
+
<button
|
39
|
+
class="vmw-drawer-body__btn animation toggle-fullscreen"
|
40
|
+
@click="emits('send-alt-command')"
|
41
|
+
>
|
42
|
+
{{ localization.common.sendAltCommand }}
|
43
|
+
</button>
|
44
|
+
<label
|
45
|
+
v-development="true"
|
46
|
+
class="vmw-drawer-body__btn animation relative"
|
47
|
+
>
|
48
|
+
{{ localization.remoteConsole.uploadFolder }}
|
49
|
+
<input type="file" webkitdirectory directory multiple />
|
50
|
+
</label>
|
51
|
+
<label
|
52
|
+
v-development="true"
|
53
|
+
class="vmw-drawer-body__btn animation relative"
|
54
|
+
>
|
55
|
+
{{ localization.remoteConsole.uploadFiles }}
|
56
|
+
<input type="file" multiple />
|
57
|
+
</label>
|
58
|
+
|
59
|
+
<select
|
60
|
+
v-model="usbDevice"
|
61
|
+
v-development="true"
|
62
|
+
@mouseenter="hover = true"
|
63
|
+
@mouseleave="hover = false"
|
64
|
+
@change="onChangeUsbDevice"
|
65
|
+
>
|
66
|
+
<option
|
67
|
+
v-for="item in usbDevices"
|
68
|
+
:key="item.value"
|
69
|
+
:value="item.value"
|
70
|
+
:disabled="item.disabled"
|
71
|
+
>
|
72
|
+
{{ item.label }}
|
73
|
+
</option>
|
74
|
+
</select>
|
75
|
+
|
76
|
+
<select
|
77
|
+
:value="codec"
|
78
|
+
@mouseenter="hover = true"
|
79
|
+
@mouseleave="hover = false"
|
80
|
+
@change="onChangeCodec"
|
81
|
+
>
|
82
|
+
<option :value="1">MJPEG</option>
|
83
|
+
<option :value="2">VP8</option>
|
84
|
+
<option :value="3">H264</option>
|
85
|
+
<option :value="4" disabled>VP9</option>
|
86
|
+
<option :value="5">H265</option>
|
87
|
+
</select>
|
88
|
+
|
89
|
+
<hr />
|
90
|
+
<button
|
91
|
+
class="vmw-drawer-body__btn animation show-keyboard"
|
92
|
+
@click="onToggleKeyboard"
|
93
|
+
>
|
94
|
+
{{ showOrHideKeyboard }}
|
95
|
+
</button>
|
96
|
+
</div>
|
96
97
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
98
|
+
<div class="vmw-drawer-footer">
|
99
|
+
<div class="size-info">
|
100
|
+
<p class="size-info-text">View size: {{ viewSize }}</p>
|
101
|
+
<p class="size-info-text">Canvas size: {{ canvasSize }}</p>
|
102
|
+
</div>
|
103
|
+
<div id="debug-stream"></div>
|
101
104
|
</div>
|
102
|
-
<div id="debug-stream"></div>
|
103
105
|
</div>
|
104
106
|
<div v-if="isKeyboardShown">
|
105
107
|
<common-spice-console-keyboard />
|
@@ -256,7 +258,9 @@ setDefaultDevices()
|
|
256
258
|
right: -300px;
|
257
259
|
width: 300px;
|
258
260
|
height: 100vh;
|
259
|
-
|
261
|
+
display: flex;
|
262
|
+
flex-direction: column;
|
263
|
+
padding: 20px 0 20px 20px;
|
260
264
|
z-index: var(--z-modal);
|
261
265
|
|
262
266
|
&.show {
|
@@ -306,6 +310,10 @@ setDefaultDevices()
|
|
306
310
|
}
|
307
311
|
}
|
308
312
|
|
313
|
+
.drawer-content {
|
314
|
+
overflow: auto;
|
315
|
+
padding-right: 20px;
|
316
|
+
}
|
309
317
|
.vmw-drawer-header {
|
310
318
|
& h3 {
|
311
319
|
color: #fff;
|
@@ -1,6 +1,14 @@
|
|
1
1
|
<template>
|
2
2
|
<div ref="fullScreen" class="spice-console">
|
3
3
|
<div id="vmw" ref="vmScreen" @scroll="onConsoleScroll"></div>
|
4
|
+
<div
|
5
|
+
v-if="isWindow"
|
6
|
+
v-show="isShowBlocker"
|
7
|
+
class="blocker"
|
8
|
+
@click="onFocus"
|
9
|
+
>
|
10
|
+
<p class="blocker-text">{{ localization.remoteConsole.clickForUse }}</p>
|
11
|
+
</div>
|
4
12
|
<common-spice-console-drawer
|
5
13
|
@toggle-fullscreen="toggle"
|
6
14
|
@send-alt-command="onSendAltCommand"
|
@@ -11,6 +19,7 @@
|
|
11
19
|
import { useFullscreen } from '@vueuse/core'
|
12
20
|
import RFB from '@novnc/novnc/core/rfb.js'
|
13
21
|
import SpiceConsole from '~/plugins/spice-console/spice.console'
|
22
|
+
import type { UI_I_Localization } from '~/lib/models/interfaces'
|
14
23
|
|
15
24
|
const props = defineProps<{
|
16
25
|
wsUrl: string
|
@@ -20,6 +29,8 @@ const props = defineProps<{
|
|
20
29
|
port: number
|
21
30
|
}>()
|
22
31
|
|
32
|
+
const localization = computed<UI_I_Localization>(() => useLocal())
|
33
|
+
|
23
34
|
let rfb: any
|
24
35
|
const vmScreen = ref<any>(null)
|
25
36
|
const fullScreen = ref<any>(null)
|
@@ -100,14 +111,28 @@ const blockCtrlOrCmdCommands = (e): void => {
|
|
100
111
|
// return false;
|
101
112
|
// }
|
102
113
|
}
|
114
|
+
|
115
|
+
const isWindow = computed<boolean>(() => useRoute().query.window === 'true')
|
116
|
+
const isShowBlocker = ref<boolean>(true)
|
117
|
+
const onFocus = (): void => {
|
118
|
+
document.getElementById('inputmanager')?.focus()
|
119
|
+
isShowBlocker.value = false
|
120
|
+
}
|
121
|
+
|
122
|
+
const inputManagerBlur = (): void => {
|
123
|
+
isShowBlocker.value = true
|
124
|
+
}
|
125
|
+
|
103
126
|
onMounted(() => {
|
104
127
|
connectWS()
|
105
128
|
document.addEventListener('keydown', blockCtrlOrCmdCommands)
|
129
|
+
window.addEventListener('blur', inputManagerBlur)
|
106
130
|
})
|
107
131
|
|
108
132
|
onBeforeUnmount(() => {
|
109
133
|
vmDisconnect()
|
110
134
|
document.removeEventListener('keydown', blockCtrlOrCmdCommands)
|
135
|
+
window.removeEventListener('blur', inputManagerBlur)
|
111
136
|
})
|
112
137
|
</script>
|
113
138
|
<style scoped lang="scss">
|
@@ -124,4 +149,20 @@ onBeforeUnmount(() => {
|
|
124
149
|
height: 100vh;
|
125
150
|
background-color: #000;
|
126
151
|
}
|
152
|
+
.blocker {
|
153
|
+
position: fixed;
|
154
|
+
top: 0;
|
155
|
+
left: 0;
|
156
|
+
width: 100%;
|
157
|
+
height: 100%;
|
158
|
+
display: flex;
|
159
|
+
justify-content: center;
|
160
|
+
align-items: center;
|
161
|
+
background-color: rgba(0, 0, 0, 0.5);
|
162
|
+
z-index: 9999;
|
163
|
+
|
164
|
+
.blocker-text {
|
165
|
+
color: #e4e4e4;
|
166
|
+
}
|
167
|
+
}
|
127
168
|
</style>
|