bfg-common 1.5.452 → 1.5.454
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 +4 -2
- package/assets/localization/local_en.json +4 -2
- package/assets/localization/local_hy.json +4 -2
- package/assets/localization/local_kk.json +4 -2
- package/assets/localization/local_ru.json +4 -2
- package/assets/localization/local_zh.json +4 -2
- package/assets/scss/clarity/local_ar.json +2 -1
- package/components/atoms/table/dataGrid/DataGrid.vue +15 -0
- package/components/atoms/window/Window.vue +143 -63
- 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/monitor/overview/filters/customIntervalModal/CustomIntervalModalOld.vue +6 -6
- package/components/common/pages/backups/Backups.vue +102 -102
- package/components/common/pages/backups/modals/Modals.vue +5 -2
- package/components/common/pages/backups/modals/createBackup/CreateBackup.vue +1 -1
- package/components/common/pages/backups/modals/createBackup/datastores/Datastores.vue +59 -59
- package/components/common/spiceConsole/Drawer.vue +89 -81
- package/components/common/spiceConsole/SpiceConsole.vue +41 -0
- package/package.json +1 -1
@@ -2749,7 +2749,8 @@
|
|
2749
2749
|
"template": "Шаблон",
|
2750
2750
|
"convertToTemplate": "Пераўтварыць у шаблон",
|
2751
2751
|
"newTemplate": "Новы шаблон",
|
2752
|
-
"createTemplateFromVM": "Стварыць шаблон з ВМ"
|
2752
|
+
"createTemplateFromVM": "Стварыць шаблон з ВМ",
|
2753
|
+
"actionsNumObjects": "Дзеянні – {0} аб’ектаў"
|
2753
2754
|
},
|
2754
2755
|
"networks": {
|
2755
2756
|
"active_ports": "Актыўныя Парты",
|
@@ -3252,7 +3253,8 @@
|
|
3252
3253
|
"channels": "Каналы ({0})",
|
3253
3254
|
"metricsNotFound": "Паказчыкі не знойдзены",
|
3254
3255
|
"uploadFolder": "Тэчка загрузкі",
|
3255
|
-
"uploadFiles": "Запампаваць файлы"
|
3256
|
+
"uploadFiles": "Запампаваць файлы",
|
3257
|
+
"clickForUse": "Націсніце для выкарыстання"
|
3256
3258
|
},
|
3257
3259
|
"vmWizard": {
|
3258
3260
|
"selectCreationType": "Выберыце тып стварэння",
|
@@ -2753,7 +2753,8 @@
|
|
2753
2753
|
"template": "Template",
|
2754
2754
|
"convertToTemplate": "Convert to Template",
|
2755
2755
|
"newTemplate": "New Template",
|
2756
|
-
"createTemplateFromVM": "Create Template from VM"
|
2756
|
+
"createTemplateFromVM": "Create Template from VM",
|
2757
|
+
"actionsNumObjects": "Actions - {0} Objects"
|
2757
2758
|
},
|
2758
2759
|
"networks": {
|
2759
2760
|
"active_ports": "Active ports",
|
@@ -3256,7 +3257,8 @@
|
|
3256
3257
|
"channels": "Channels ({0})",
|
3257
3258
|
"metricsNotFound": "Metrics not found",
|
3258
3259
|
"uploadFolder": "Upload folder",
|
3259
|
-
"uploadFiles": "Upload files"
|
3260
|
+
"uploadFiles": "Upload files",
|
3261
|
+
"clickForUse": "Click for use"
|
3260
3262
|
},
|
3261
3263
|
"vmWizard": {
|
3262
3264
|
"selectCreationType": "Select a Creation Type",
|
@@ -2753,7 +2753,8 @@
|
|
2753
2753
|
"template": "Ձևանմուշ",
|
2754
2754
|
"convertToTemplate": "Վերափոխել ձևանմուշի",
|
2755
2755
|
"newTemplate": "Նոր ձևանմուշ",
|
2756
|
-
"createTemplateFromVM": "Ստեղծել ձևանմուշ ՎՄ-ից"
|
2756
|
+
"createTemplateFromVM": "Ստեղծել ձևանմուշ ՎՄ-ից",
|
2757
|
+
"actionsNumObjects": "Գործողություններ – {0} օբյեկտ"
|
2757
2758
|
},
|
2758
2759
|
"networks": {
|
2759
2760
|
"active_ports": "Ակտիվ պորտեր",
|
@@ -3256,7 +3257,8 @@
|
|
3256
3257
|
"channels": "Ալիքներ ({0})",
|
3257
3258
|
"metricsNotFound": "Չափանիշները չեն գտնվել",
|
3258
3259
|
"uploadFolder": "Վերբեռնեք թղթապանակը",
|
3259
|
-
"uploadFiles": "Վերբեռնեք ֆայլեր"
|
3260
|
+
"uploadFiles": "Վերբեռնեք ֆայլեր",
|
3261
|
+
"clickForUse": "Կտտացրեք օգտագործման համար"
|
3260
3262
|
},
|
3261
3263
|
"vmWizard": {
|
3262
3264
|
"selectCreationType": "Ընտրեք ստեղծման տեսակը",
|
@@ -2752,7 +2752,8 @@
|
|
2752
2752
|
"template": "Үлгі",
|
2753
2753
|
"convertToTemplate": "Үлгіге айналдыру",
|
2754
2754
|
"newTemplate": "Жаңа үлгі",
|
2755
|
-
"createTemplateFromVM": "ВМ негізінде үлгі жасау"
|
2755
|
+
"createTemplateFromVM": "ВМ негізінде үлгі жасау",
|
2756
|
+
"actionsNumObjects": "Әрекеттер – {0} нысан"
|
2756
2757
|
},
|
2757
2758
|
"networks": {
|
2758
2759
|
"active_ports": "Белсенді порттар",
|
@@ -3255,7 +3256,8 @@
|
|
3255
3256
|
"channels": "Арналар ({0})",
|
3256
3257
|
"metricsNotFound": "Көрсеткіштер табылмады",
|
3257
3258
|
"uploadFolder": "Қалтаны жүктеп салу",
|
3258
|
-
"uploadFiles": "Файлдарды жүктеп салу"
|
3259
|
+
"uploadFiles": "Файлдарды жүктеп салу",
|
3260
|
+
"clickForUse": "Пайдалану үшін басыңыз"
|
3259
3261
|
},
|
3260
3262
|
"vmWizard": {
|
3261
3263
|
"selectCreationType": "Жасау түрін таңдаңыз",
|
@@ -2752,7 +2752,8 @@
|
|
2752
2752
|
"template": "Шаблон",
|
2753
2753
|
"convertToTemplate": "Преобразовать в шаблон",
|
2754
2754
|
"newTemplate": "Новый шаблон",
|
2755
|
-
"createTemplateFromVM": "Создать шаблон из ВМ"
|
2755
|
+
"createTemplateFromVM": "Создать шаблон из ВМ",
|
2756
|
+
"actionsNumObjects": "Действия – {0} объектов"
|
2756
2757
|
},
|
2757
2758
|
"networks": {
|
2758
2759
|
"active_ports": "Активные порты",
|
@@ -3255,7 +3256,8 @@
|
|
3255
3256
|
"channels": "Каналы ({0})",
|
3256
3257
|
"metricsNotFound": "Метрики не найдены",
|
3257
3258
|
"uploadFolder": "Загрузить папку",
|
3258
|
-
"uploadFiles": "Загрузить файлы"
|
3259
|
+
"uploadFiles": "Загрузить файлы",
|
3260
|
+
"clickForUse": "Нажмите для использования"
|
3259
3261
|
},
|
3260
3262
|
"vmWizard": {
|
3261
3263
|
"selectCreationType": "Выбор типа создания",
|
@@ -2750,7 +2750,8 @@
|
|
2750
2750
|
"template": "模板",
|
2751
2751
|
"convertToTemplate": "转换为模板",
|
2752
2752
|
"newTemplate": "新模板",
|
2753
|
-
"createTemplateFromVM": "从虚拟机创建模板"
|
2753
|
+
"createTemplateFromVM": "从虚拟机创建模板",
|
2754
|
+
"actionsNumObjects": "操作 – {0} 个对象"
|
2754
2755
|
},
|
2755
2756
|
"networks": {
|
2756
2757
|
"active_ports": "活动端口",
|
@@ -3253,7 +3254,8 @@
|
|
3253
3254
|
"channels": "频道 ({0})",
|
3254
3255
|
"metricsNotFound": "未找到指标",
|
3255
3256
|
"uploadFolder": "上传文件夹",
|
3256
|
-
"uploadFiles": "上传文件"
|
3257
|
+
"uploadFiles": "上传文件",
|
3258
|
+
"clickForUse": "点击使用"
|
3257
3259
|
},
|
3258
3260
|
"vmWizard": {
|
3259
3261
|
"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})",
|
@@ -211,6 +211,7 @@
|
|
211
211
|
:data-id="`${item[0].testId}-select-row`"
|
212
212
|
class="datagrid-row-master datagrid-row-flex"
|
213
213
|
@click.stop="selectRowById(item[0])"
|
214
|
+
@contextmenu.prevent="onShowContextMenu($event, item[0])"
|
214
215
|
>
|
215
216
|
<div
|
216
217
|
v-if="props.type || $slots.toggleBlock"
|
@@ -601,6 +602,7 @@ const emits = defineEmits<{
|
|
601
602
|
(event: 'sorting', value: [string, boolean]): void
|
602
603
|
(event: 'change', value: any): void
|
603
604
|
(event: 'row-detail', value: number): void
|
605
|
+
(event: 'show-context-menu', value: Event): void
|
604
606
|
}>()
|
605
607
|
|
606
608
|
const localization = computed<UI_I_Localization>(() => useLocal())
|
@@ -1086,6 +1088,19 @@ const exportSelected = (): void => {
|
|
1086
1088
|
generateCsvAndDownload([header, ...Array.from(rows)])
|
1087
1089
|
}
|
1088
1090
|
|
1091
|
+
const onShowContextMenu = (event: Event, item: UI_I_BodyItem): void => {
|
1092
|
+
const { id } = item
|
1093
|
+
let has = false
|
1094
|
+
if (props.type === 'checkbox' && Array.isArray(selectedRowLocal.value)) {
|
1095
|
+
has = selectedRowLocal.value.includes(id)
|
1096
|
+
} else {
|
1097
|
+
has = selectedRowLocal.value === id
|
1098
|
+
}
|
1099
|
+
if (!has) selectRowById(item)
|
1100
|
+
|
1101
|
+
emits('show-context-menu', event)
|
1102
|
+
}
|
1103
|
+
|
1089
1104
|
onMounted(() => {
|
1090
1105
|
window.addEventListener('mousemove', mousemove)
|
1091
1106
|
window.addEventListener('mouseup', mouseup)
|
@@ -1,27 +1,37 @@
|
|
1
1
|
<template>
|
2
2
|
<div
|
3
|
-
class="window-container"
|
3
|
+
:class="['window-container', { loading: props.loading }]"
|
4
4
|
:style="{
|
5
|
-
left:
|
6
|
-
top:
|
7
|
-
width:
|
8
|
-
height:
|
5
|
+
left: leftLocal + 'px',
|
6
|
+
top: topLocal + 'px',
|
7
|
+
width: widthLocal + 'px',
|
8
|
+
height: heightLocal + 'px',
|
9
9
|
}"
|
10
10
|
>
|
11
11
|
<div ref="headerEl" class="window-header">
|
12
|
-
<
|
13
|
-
|
14
|
-
|
15
|
-
|
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>
|
16
27
|
</div>
|
17
28
|
|
18
29
|
<div class="window-content">
|
30
|
+
<div v-show="props.loading" class="absolute-center">
|
31
|
+
<ui-icon name="spinner" />
|
32
|
+
</div>
|
19
33
|
<slot></slot>
|
20
|
-
<div
|
21
|
-
v-show="isShowContentBlocker"
|
22
|
-
:style="{}"
|
23
|
-
class="content-blocker"
|
24
|
-
></div>
|
34
|
+
<div v-show="isShowContentBlocker" class="content-blocker"></div>
|
25
35
|
</div>
|
26
36
|
|
27
37
|
<!-- Ручки для ресайза -->
|
@@ -62,14 +72,27 @@
|
|
62
72
|
|
63
73
|
<script setup lang="ts">
|
64
74
|
import { useDraggable } from '@vueuse/core'
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
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
|
+
)
|
73
96
|
const emits = defineEmits<{
|
74
97
|
(event: 'hide'): void
|
75
98
|
}>()
|
@@ -77,20 +100,34 @@ const emits = defineEmits<{
|
|
77
100
|
const headerEl = ref(null)
|
78
101
|
const isShowContentBlocker = ref<boolean>(false)
|
79
102
|
|
80
|
-
const
|
81
|
-
const
|
82
|
-
const
|
83
|
-
const
|
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
|
+
})
|
84
115
|
|
85
116
|
// Используем vueuse для перетаскивания
|
86
117
|
useDraggable(headerEl, {
|
87
|
-
initialValue: { x:
|
118
|
+
initialValue: { x: leftLocal.value, y: topLocal.value },
|
88
119
|
onMove({ x: newX, y: newY }) {
|
89
|
-
|
90
|
-
|
120
|
+
leftLocal.value = newX
|
121
|
+
topLocal.value = newY
|
91
122
|
},
|
92
123
|
onStart() {
|
93
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
|
+
}
|
94
131
|
},
|
95
132
|
onEnd() {
|
96
133
|
isShowContentBlocker.value = false
|
@@ -102,35 +139,48 @@ const fixSize = (): void => {
|
|
102
139
|
const globalWindowWidth = window.innerWidth
|
103
140
|
const globalWindowHeight = window.innerHeight
|
104
141
|
|
105
|
-
|
106
|
-
|
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
|
+
)
|
107
150
|
}
|
108
151
|
const fixPosition = (): void => {
|
109
152
|
const globalWindowWidth = window.innerWidth
|
110
153
|
const globalWindowHeight = window.innerHeight
|
111
|
-
let newX =
|
112
|
-
let newY =
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
newX = 8
|
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
|
119
161
|
}
|
120
162
|
|
121
|
-
if (
|
122
|
-
newY = globalWindowHeight -
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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
|
127
177
|
}
|
128
178
|
|
129
179
|
smoothMove(newX, newY)
|
130
180
|
}
|
131
181
|
const smoothMove = (newX: number, newY: number, duration = 100): void => {
|
132
|
-
const startX =
|
133
|
-
const startY =
|
182
|
+
const startX = leftLocal.value
|
183
|
+
const startY = topLocal.value
|
134
184
|
|
135
185
|
// Время начала анимации
|
136
186
|
const startTime = performance.now()
|
@@ -144,8 +194,8 @@ const smoothMove = (newX: number, newY: number, duration = 100): void => {
|
|
144
194
|
const progress = Math.min(elapsedTime / duration, 1)
|
145
195
|
|
146
196
|
// Вычисляем новые координаты с помощью линейной интерполяции
|
147
|
-
|
148
|
-
|
197
|
+
leftLocal.value = startX + (newX - startX) * progress
|
198
|
+
topLocal.value = startY + (newY - startY) * progress
|
149
199
|
|
150
200
|
// Если анимация не завершена, продолжаем
|
151
201
|
if (progress < 1) {
|
@@ -157,39 +207,65 @@ const smoothMove = (newX: number, newY: number, duration = 100): void => {
|
|
157
207
|
requestAnimationFrame(animate)
|
158
208
|
}
|
159
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
|
+
|
160
236
|
// Функция для ресайза
|
161
237
|
const startResize = (e: any, direction: any): void => {
|
162
238
|
e.preventDefault()
|
163
239
|
|
164
240
|
const startX = e.clientX
|
165
241
|
const startY = e.clientY
|
166
|
-
const startWidth =
|
167
|
-
const startHeight =
|
168
|
-
const startLeft =
|
169
|
-
const startTop =
|
242
|
+
const startWidth = widthLocal.value
|
243
|
+
const startHeight = heightLocal.value
|
244
|
+
const startLeft = leftLocal.value
|
245
|
+
const startTop = topLocal.value
|
170
246
|
|
171
247
|
const onMouseMove = (e: any): void => {
|
172
248
|
const deltaX = e.clientX - startX
|
173
249
|
const deltaY = e.clientY - startY
|
174
250
|
|
175
251
|
if (direction.includes('right')) {
|
176
|
-
|
252
|
+
widthLocal.value = Math.max(minWidth, startWidth + deltaX)
|
177
253
|
}
|
178
254
|
if (direction.includes('bottom')) {
|
179
|
-
|
255
|
+
heightLocal.value = Math.max(minHeight, startHeight + deltaY)
|
180
256
|
}
|
181
257
|
if (direction.includes('left')) {
|
182
|
-
const newWidth = Math.max(
|
183
|
-
if (newWidth !==
|
184
|
-
|
185
|
-
|
258
|
+
const newWidth = Math.max(minWidth, startWidth - deltaX)
|
259
|
+
if (newWidth !== widthLocal.value) {
|
260
|
+
leftLocal.value = startLeft + deltaX
|
261
|
+
widthLocal.value = newWidth
|
186
262
|
}
|
187
263
|
}
|
188
264
|
if (direction.includes('top')) {
|
189
|
-
const newHeight = Math.max(
|
190
|
-
if (newHeight !==
|
191
|
-
|
192
|
-
|
265
|
+
const newHeight = Math.max(minHeight, startHeight - deltaY)
|
266
|
+
if (newHeight !== heightLocal.value) {
|
267
|
+
topLocal.value = startTop + deltaY
|
268
|
+
heightLocal.value = newHeight
|
193
269
|
}
|
194
270
|
}
|
195
271
|
fixSize()
|
@@ -241,6 +317,10 @@ const onHide = (): void => {
|
|
241
317
|
min-height: 200px;
|
242
318
|
z-index: var(--z-toast);
|
243
319
|
|
320
|
+
&.loading {
|
321
|
+
opacity: 0.5;
|
322
|
+
}
|
323
|
+
|
244
324
|
.window-header {
|
245
325
|
background-color: #314351;
|
246
326
|
color: white;
|
@@ -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
|
package/components/common/monitor/overview/filters/customIntervalModal/CustomIntervalModalOld.vue
CHANGED
@@ -107,12 +107,12 @@
|
|
107
107
|
import type { UI_I_Localization } from '~/lib/models/interfaces'
|
108
108
|
|
109
109
|
const alertShow = defineModel<boolean>('alert-show')
|
110
|
-
const currentDateFrom = defineModel<
|
111
|
-
const dateFrom = defineModel<
|
112
|
-
const currentTimeFrom = defineModel<
|
113
|
-
const currentDateTo = defineModel<
|
114
|
-
const dateTo = defineModel<
|
115
|
-
const currentTimeTo = defineModel<
|
110
|
+
const currentDateFrom = defineModel<string>('current-date-from')
|
111
|
+
const dateFrom = defineModel<number>('date-from')
|
112
|
+
const currentTimeFrom = defineModel<string>('current-time-from')
|
113
|
+
const currentDateTo = defineModel<string>('current-date-to')
|
114
|
+
const dateTo = defineModel<number>('date-to')
|
115
|
+
const currentTimeTo = defineModel<string>('current-time-to')
|
116
116
|
|
117
117
|
const props = defineProps<{
|
118
118
|
titleIntervalModal: string
|
@@ -1,102 +1,102 @@
|
|
1
|
-
<template>
|
2
|
-
<div class="main-content-backups h-full overflow-hidden">
|
3
|
-
<common-pages-backups-tools
|
4
|
-
:project="props.project"
|
5
|
-
:backups-count="backupsTree.length"
|
6
|
-
:backups-loading="backupsLoading"
|
7
|
-
:selected-node="selectedNode"
|
8
|
-
:target-type="typeFromRoute"
|
9
|
-
@select="onShowModal"
|
10
|
-
/>
|
11
|
-
|
12
|
-
<atoms-loader-pre-loader
|
13
|
-
v-show="backupsLoading"
|
14
|
-
id="loader"
|
15
|
-
:show="true"
|
16
|
-
class="backups-loading w-full h-full flex items-center justify-center"
|
17
|
-
test-id="backups-tree-spinner"
|
18
|
-
/>
|
19
|
-
<div class="fill-parent w-full h-full">
|
20
|
-
<div v-if="backupsTree.length" class="backup-view mt-1 flex w-full">
|
21
|
-
<common-tree-view
|
22
|
-
:loading="backupsLoading"
|
23
|
-
:nodes="backupsTree"
|
24
|
-
@select-node="onSelectNode"
|
25
|
-
@show-nodes="onShowNodes"
|
26
|
-
/>
|
27
|
-
<common-pages-backups-detail-view :detail="detailData" />
|
28
|
-
</div>
|
29
|
-
<div v-else class="empty-block flex justify-center items-center w-full">
|
30
|
-
{{ localization.common.noBackupAvailable }}
|
31
|
-
</div>
|
32
|
-
</div>
|
33
|
-
</div>
|
34
|
-
</template>
|
35
|
-
|
36
|
-
<script setup lang="ts">
|
37
|
-
import type { UI_T_Project } from '~/lib/models/types'
|
38
|
-
import type { UI_I_Localization } from '~/lib/models/interfaces'
|
39
|
-
import type {
|
40
|
-
UI_T_TargetType,
|
41
|
-
UI_T_BackupActionType,
|
42
|
-
} from '~/components/common/pages/backups/lib/models/types'
|
43
|
-
import type {
|
44
|
-
UI_I_Backup,
|
45
|
-
UI_I_BackupsTreeNode,
|
46
|
-
} from '~/components/common/pages/backups/lib/models/interfaces'
|
47
|
-
|
48
|
-
const props = defineProps<{
|
49
|
-
project: UI_T_Project
|
50
|
-
backups: UI_I_Backup[]
|
51
|
-
backupsTree: UI_I_BackupsTreeNode[]
|
52
|
-
backupsLoading: boolean
|
53
|
-
selectedNode: UI_I_BackupsTreeNode
|
54
|
-
}>()
|
55
|
-
const emits = defineEmits<{
|
56
|
-
(event: 'select-node', value: string | number): void
|
57
|
-
(event: 'show-nodes', value: string | number): void
|
58
|
-
(event: 'set-action', value: UI_T_BackupActionType): void
|
59
|
-
}>()
|
60
|
-
|
61
|
-
const localization = computed<UI_I_Localization>(() => useLocal())
|
62
|
-
const { $recursion }: any = useNuxtApp()
|
63
|
-
|
64
|
-
const typeFromRoute = computed<UI_T_TargetType>(
|
65
|
-
() => useRoute().params.type.toString() as UI_T_TargetType
|
66
|
-
)
|
67
|
-
|
68
|
-
const detailData = computed<UI_I_BackupsTreeNode | null>(() => {
|
69
|
-
const node =
|
70
|
-
$recursion.find(props.backupsTree, true, 'isActive', 'nodes') || null
|
71
|
-
return node?.type === 'backup' ? node : null
|
72
|
-
})
|
73
|
-
|
74
|
-
const onSelectNode = (item: UI_I_BackupsTreeNode): void => {
|
75
|
-
emits('select-node', item.id)
|
76
|
-
if (item.type === 'group') {
|
77
|
-
onShowNodes(item.id.toString())
|
78
|
-
}
|
79
|
-
}
|
80
|
-
const onShowNodes = (id: string | number): void => {
|
81
|
-
emits('show-nodes', id)
|
82
|
-
}
|
83
|
-
|
84
|
-
const onShowModal = (action: UI_T_BackupActionType): void => {
|
85
|
-
emits('set-action', action)
|
86
|
-
}
|
87
|
-
</script>
|
88
|
-
|
89
|
-
<style scoped lang="scss">
|
90
|
-
.main-content-backups {
|
91
|
-
padding: 10px 5px 10px 0;
|
92
|
-
|
93
|
-
.fill-parent {
|
94
|
-
overflow: visible;
|
95
|
-
|
96
|
-
.backup-view {
|
97
|
-
// TODO fix
|
98
|
-
height: calc(90% - 24px);
|
99
|
-
}
|
100
|
-
}
|
101
|
-
}
|
102
|
-
</style>
|
1
|
+
<template>
|
2
|
+
<div class="main-content-backups h-full overflow-hidden">
|
3
|
+
<common-pages-backups-tools
|
4
|
+
:project="props.project"
|
5
|
+
:backups-count="backupsTree.length"
|
6
|
+
:backups-loading="backupsLoading"
|
7
|
+
:selected-node="selectedNode"
|
8
|
+
:target-type="typeFromRoute"
|
9
|
+
@select="onShowModal"
|
10
|
+
/>
|
11
|
+
|
12
|
+
<atoms-loader-pre-loader
|
13
|
+
v-show="backupsLoading"
|
14
|
+
id="loader"
|
15
|
+
:show="true"
|
16
|
+
class="backups-loading w-full h-full flex items-center justify-center"
|
17
|
+
test-id="backups-tree-spinner"
|
18
|
+
/>
|
19
|
+
<div class="fill-parent w-full h-full">
|
20
|
+
<div v-if="backupsTree.length" class="backup-view mt-1 flex w-full">
|
21
|
+
<common-tree-view
|
22
|
+
:loading="backupsLoading"
|
23
|
+
:nodes="backupsTree"
|
24
|
+
@select-node="onSelectNode"
|
25
|
+
@show-nodes="onShowNodes"
|
26
|
+
/>
|
27
|
+
<common-pages-backups-detail-view :detail="detailData" />
|
28
|
+
</div>
|
29
|
+
<div v-else class="empty-block flex justify-center items-center w-full">
|
30
|
+
{{ localization.common.noBackupAvailable }}
|
31
|
+
</div>
|
32
|
+
</div>
|
33
|
+
</div>
|
34
|
+
</template>
|
35
|
+
|
36
|
+
<script setup lang="ts">
|
37
|
+
import type { UI_T_Project } from '~/lib/models/types'
|
38
|
+
import type { UI_I_Localization } from '~/lib/models/interfaces'
|
39
|
+
import type {
|
40
|
+
UI_T_TargetType,
|
41
|
+
UI_T_BackupActionType,
|
42
|
+
} from '~/components/common/pages/backups/lib/models/types'
|
43
|
+
import type {
|
44
|
+
UI_I_Backup,
|
45
|
+
UI_I_BackupsTreeNode,
|
46
|
+
} from '~/components/common/pages/backups/lib/models/interfaces'
|
47
|
+
|
48
|
+
const props = defineProps<{
|
49
|
+
project: UI_T_Project
|
50
|
+
backups: UI_I_Backup[]
|
51
|
+
backupsTree: UI_I_BackupsTreeNode[]
|
52
|
+
backupsLoading: boolean
|
53
|
+
selectedNode: UI_I_BackupsTreeNode | null
|
54
|
+
}>()
|
55
|
+
const emits = defineEmits<{
|
56
|
+
(event: 'select-node', value: string | number): void
|
57
|
+
(event: 'show-nodes', value: string | number): void
|
58
|
+
(event: 'set-action', value: UI_T_BackupActionType): void
|
59
|
+
}>()
|
60
|
+
|
61
|
+
const localization = computed<UI_I_Localization>(() => useLocal())
|
62
|
+
const { $recursion }: any = useNuxtApp()
|
63
|
+
|
64
|
+
const typeFromRoute = computed<UI_T_TargetType>(
|
65
|
+
() => useRoute().params.type.toString() as UI_T_TargetType
|
66
|
+
)
|
67
|
+
|
68
|
+
const detailData = computed<UI_I_BackupsTreeNode | null>(() => {
|
69
|
+
const node =
|
70
|
+
$recursion.find(props.backupsTree, true, 'isActive', 'nodes') || null
|
71
|
+
return node?.type === 'backup' ? node : null
|
72
|
+
})
|
73
|
+
|
74
|
+
const onSelectNode = (item: UI_I_BackupsTreeNode): void => {
|
75
|
+
emits('select-node', item.id)
|
76
|
+
if (item.type === 'group') {
|
77
|
+
onShowNodes(item.id.toString())
|
78
|
+
}
|
79
|
+
}
|
80
|
+
const onShowNodes = (id: string | number): void => {
|
81
|
+
emits('show-nodes', id)
|
82
|
+
}
|
83
|
+
|
84
|
+
const onShowModal = (action: UI_T_BackupActionType): void => {
|
85
|
+
emits('set-action', action)
|
86
|
+
}
|
87
|
+
</script>
|
88
|
+
|
89
|
+
<style scoped lang="scss">
|
90
|
+
.main-content-backups {
|
91
|
+
padding: 10px 5px 10px 0;
|
92
|
+
|
93
|
+
.fill-parent {
|
94
|
+
overflow: visible;
|
95
|
+
|
96
|
+
.backup-view {
|
97
|
+
// TODO fix
|
98
|
+
height: calc(90% - 24px);
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
</style>
|
@@ -43,7 +43,10 @@
|
|
43
43
|
<script lang="ts" setup>
|
44
44
|
import type { UI_I_WizardStep } from '~/node_modules/bfg-uikit/components/ui/wizard/lib/models/interfaces'
|
45
45
|
import type { UI_T_Project } from '~/lib/models/types'
|
46
|
-
import type {
|
46
|
+
import type {
|
47
|
+
UI_I_SendTaskParams,
|
48
|
+
UI_I_ModalPayload,
|
49
|
+
} from '~/lib/models/interfaces'
|
47
50
|
import type { UI_I_ScheduleNewTasksForm } from '~/components/common/pages/scheduledTasks/modals/lib/models/interfaces'
|
48
51
|
import type {
|
49
52
|
UI_I_BackupDatastoreTable,
|
@@ -69,7 +72,7 @@ const props = defineProps<{
|
|
69
72
|
selectedVmName: string
|
70
73
|
disks: UI_I_Pvm['disk_devices']
|
71
74
|
disksLoading: boolean
|
72
|
-
datastoreTable: UI_I_BackupDatastoreTable
|
75
|
+
datastoreTable: UI_I_BackupDatastoreTable | null
|
73
76
|
datastoreTableLoading: boolean
|
74
77
|
restoreDatastore: UI_I_DatastoreTableItem[]
|
75
78
|
isRestoreDatastoreLoading: boolean
|
@@ -101,7 +101,7 @@ const props = defineProps<{
|
|
101
101
|
selectedVmName: string
|
102
102
|
disks: UI_I_Pvm['disk_devices']
|
103
103
|
disksLoading: boolean
|
104
|
-
datastoreTable: UI_I_BackupDatastoreTable
|
104
|
+
datastoreTable: UI_I_BackupDatastoreTable | null
|
105
105
|
datastoreTableLoading: boolean
|
106
106
|
}>()
|
107
107
|
|
@@ -1,59 +1,59 @@
|
|
1
|
-
<template>
|
2
|
-
<div class="datastores h-full">
|
3
|
-
<common-pages-backups-modals-create-backup-datastores-table-view
|
4
|
-
v-model:selected="model.backup_storage"
|
5
|
-
:data-table="props.datastoreTable?.items"
|
6
|
-
:total-items="props.datastoreTable?.total_items || 0"
|
7
|
-
:total-pages="props.datastoreTable?.total_pages || 1"
|
8
|
-
:loading="props.datastoreTableLoading"
|
9
|
-
/>
|
10
|
-
</div>
|
11
|
-
</template>
|
12
|
-
|
13
|
-
<script lang="ts" setup>
|
14
|
-
import type {
|
15
|
-
UI_I_BackupDatastoreTable,
|
16
|
-
UI_I_CreateBackupForm
|
17
|
-
} from '~/components/common/pages/backups/modals/lib/models/interfaces'
|
18
|
-
|
19
|
-
const props = defineProps<{
|
20
|
-
datastoreTable: UI_I_BackupDatastoreTable
|
21
|
-
datastoreTableLoading: boolean
|
22
|
-
}>()
|
23
|
-
const emits = defineEmits<{
|
24
|
-
(event: 'change', value: string[]): void
|
25
|
-
}>()
|
26
|
-
|
27
|
-
const model = defineModel<UI_I_CreateBackupForm>({ required: true })
|
28
|
-
|
29
|
-
const selectedKeys = ref<string[]>([])
|
30
|
-
|
31
|
-
watch(
|
32
|
-
() => props.datastoreTable,
|
33
|
-
() => {
|
34
|
-
selectedKeys.value = []
|
35
|
-
},
|
36
|
-
{ deep: true, immediate: true }
|
37
|
-
)
|
38
|
-
|
39
|
-
watch(
|
40
|
-
() => model.value.backup_storage,
|
41
|
-
(newValue: string) => {
|
42
|
-
const selectedNames: string[] = []
|
43
|
-
|
44
|
-
props.datastoreTable?.items.forEach((item) => {
|
45
|
-
if (newValue === item.id) selectedNames.push(item.name)
|
46
|
-
})
|
47
|
-
|
48
|
-
emits('change', selectedNames)
|
49
|
-
},
|
50
|
-
{ deep: true, immediate: true }
|
51
|
-
)
|
52
|
-
</script>
|
53
|
-
|
54
|
-
<style lang="scss" scoped>
|
55
|
-
.backups-table-content {
|
56
|
-
height: 100%;
|
57
|
-
padding: 0 10px 10px 10px;
|
58
|
-
}
|
59
|
-
</style>
|
1
|
+
<template>
|
2
|
+
<div class="datastores h-full">
|
3
|
+
<common-pages-backups-modals-create-backup-datastores-table-view
|
4
|
+
v-model:selected="model.backup_storage"
|
5
|
+
:data-table="props.datastoreTable?.items || []"
|
6
|
+
:total-items="props.datastoreTable?.total_items || 0"
|
7
|
+
:total-pages="props.datastoreTable?.total_pages || 1"
|
8
|
+
:loading="props.datastoreTableLoading"
|
9
|
+
/>
|
10
|
+
</div>
|
11
|
+
</template>
|
12
|
+
|
13
|
+
<script lang="ts" setup>
|
14
|
+
import type {
|
15
|
+
UI_I_BackupDatastoreTable,
|
16
|
+
UI_I_CreateBackupForm
|
17
|
+
} from '~/components/common/pages/backups/modals/lib/models/interfaces'
|
18
|
+
|
19
|
+
const props = defineProps<{
|
20
|
+
datastoreTable: UI_I_BackupDatastoreTable | null
|
21
|
+
datastoreTableLoading: boolean
|
22
|
+
}>()
|
23
|
+
const emits = defineEmits<{
|
24
|
+
(event: 'change', value: string[]): void
|
25
|
+
}>()
|
26
|
+
|
27
|
+
const model = defineModel<UI_I_CreateBackupForm>({ required: true })
|
28
|
+
|
29
|
+
const selectedKeys = ref<string[]>([])
|
30
|
+
|
31
|
+
watch(
|
32
|
+
() => props.datastoreTable,
|
33
|
+
() => {
|
34
|
+
selectedKeys.value = []
|
35
|
+
},
|
36
|
+
{ deep: true, immediate: true }
|
37
|
+
)
|
38
|
+
|
39
|
+
watch(
|
40
|
+
() => model.value.backup_storage,
|
41
|
+
(newValue: string) => {
|
42
|
+
const selectedNames: string[] = []
|
43
|
+
|
44
|
+
props.datastoreTable?.items.forEach((item) => {
|
45
|
+
if (newValue === item.id) selectedNames.push(item.name)
|
46
|
+
})
|
47
|
+
|
48
|
+
emits('change', selectedNames)
|
49
|
+
},
|
50
|
+
{ deep: true, immediate: true }
|
51
|
+
)
|
52
|
+
</script>
|
53
|
+
|
54
|
+
<style lang="scss" scoped>
|
55
|
+
.backups-table-content {
|
56
|
+
height: 100%;
|
57
|
+
padding: 0 10px 10px 10px;
|
58
|
+
}
|
59
|
+
</style>
|
@@ -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>
|