Skip to content

Commit d804fc5

Browse files
committed
feat(web-stack): implement actions and clipboard for VM console
1 parent 86accbf commit d804fc5

File tree

15 files changed

+190
-79
lines changed

15 files changed

+190
-79
lines changed

@xen-orchestra/lite/src/components/RemoteConsole.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ defineExpose({
111111
<style lang="postcss" scoped>
112112
.vm-console {
113113
height: 80rem;
114+
flex: 1;
115+
max-width: 100%;
114116
115117
& > :deep(div) {
116118
background-color: transparent !important;

@xen-orchestra/lite/src/locales/de.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@
9494
"following-hosts-unreachable": "Die folgenden Hosts sind nicht erreichbar",
9595
"force-reboot": "Neustart erzwingen",
9696
"force-shutdown": "Herunterfahren erzwingen",
97-
"fullscreen": "Vollbild",
9897
"fullscreen-leave": "Vollbild schließen",
9998
"gateway": "Gateway",
10099
"n-gb-left": "{n} GB frei",
@@ -137,7 +136,6 @@
137136
"object": "Objekt",
138137
"ok": "OK",
139138
"on-object": "auf {object}",
140-
"open-console-in-new-tab": "Konsole in neuem Reiter öffnen",
141139
"or": "Oder",
142140
"page-not-found": "Diese Seite wurde nicht gefunden…",
143141
"password": "Passwort",
@@ -167,7 +165,6 @@
167165
"select-compression": "Kompression auswählen",
168166
"select-destination-host": "Zielhost auswählen",
169167
"selected-vms-in-execution": "Einige der ausgewählten VMs sind eingeschaltet",
170-
"send-ctrl-alt-del": "Ctrl+Alt+Del senden",
171168
"send-us-feedback": "Gib uns Feedback",
172169

173170
"select.network": "Ein Netzwerk auswählen",

@xen-orchestra/lite/src/locales/en.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@
9696
"following-hosts-unreachable": "The following hosts are unreachable",
9797
"force-reboot": "Force reboot",
9898
"force-shutdown": "Force shutdown",
99-
"fullscreen": "Fullscreen",
10099
"fullscreen-leave": "Leave fullscreen",
101100
"gateway": "Gateway",
102101
"n-gb-left": "{n} GB left",
@@ -139,7 +138,6 @@
139138
"object": "Object",
140139
"ok": "OK",
141140
"on-object": "on {object}",
142-
"open-console-in-new-tab": "Open console in new tab",
143141
"or": "Or",
144142
"page-not-found": "This page is not to be found…",
145143
"password": "Password",
@@ -169,7 +167,6 @@
169167
"select-compression": "Select a compression",
170168
"select-destination-host": "Select a destination host",
171169
"selected-vms-in-execution": "Some selected VMs are running",
172-
"send-ctrl-alt-del": "Send Ctrl+Alt+Del",
173170
"send-us-feedback": "Send us feedback",
174171

175172
"select.network": "Select a network",

@xen-orchestra/lite/src/locales/fa.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@
9595
"following-hosts-unreachable": "میزبان های زیر در دسترس نیستند",
9696
"force-reboot": "راه اندازی مجدد اجباری",
9797
"force-shutdown": "خاموش کردن اجباری",
98-
"fullscreen": "تمام صفحه",
9998
"fullscreen-leave": "خروج از حالت تمام صفحه",
10099
"gateway": "دروازه",
101100
"n-gb-left": "{n} GB باقی مانده است",
@@ -137,7 +136,6 @@
137136
"object-not-found": "شیء {id} پیدا نمی شود…",
138137
"ok": "اوکی",
139138
"on-object": "در {object}",
140-
"open-console-in-new-tab": "باز کردن کنسول در برگه جدید",
141139
"or": "یا",
142140
"page-not-found": "این صفحه پیدا نمی شود…",
143141
"password": "کلمه عبور",
@@ -167,7 +165,6 @@
167165
"select-compression": "یک فشرده سازی انتخاب کنید",
168166
"select-destination-host": "یک میزبان مقصد انتخاب کنید",
169167
"selected-vms-in-execution": "برخی از ماشین های مجازی انتخاب شده در حال اجرا هستند",
170-
"send-ctrl-alt-del": "ارسال کلیدهای Ctrl+Alt+Del",
171168
"send-us-feedback": "برای ما بازخورد ارسال کنید",
172169

173170
"select.network": "یک شبکه انتخاب کنید",

@xen-orchestra/lite/src/locales/fr.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@
9696
"following-hosts-unreachable": "Les hôtes suivants sont inaccessibles",
9797
"force-reboot": "Forcer le redémarrage",
9898
"force-shutdown": "Forcer l'arrêt",
99-
"fullscreen": "Plein écran",
10099
"fullscreen-leave": "Quitter plein écran",
101100
"gateway": "Passerelle",
102101
"n-gb-left": "{n} Go libres",
@@ -139,7 +138,6 @@
139138
"object": "Objet",
140139
"ok": "OK",
141140
"on-object": "sur {object}",
142-
"open-console-in-new-tab": "Ouvrir la console dans un nouvel onglet",
143141
"or": "Ou",
144142
"page-not-found": "Cette page est introuvable…",
145143
"password": "Mot de passe",
@@ -169,7 +167,6 @@
169167
"select-compression": "Sélectionnez une compression",
170168
"select-destination-host": "Sélectionnez un hôte de destination",
171169
"selected-vms-in-execution": "Certaines VMs sélectionnées sont en cours d'exécution",
172-
"send-ctrl-alt-del": "Envoyer Ctrl+Alt+Suppr",
173170
"send-us-feedback": "Envoyez-nous vos commentaires",
174171

175172
"select.network": "Sélectionner un réseau",

@xen-orchestra/lite/src/views/vm/VmConsoleView.vue

Lines changed: 22 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,30 @@
44
<UiSpinner v-else-if="!isReady" class="spinner" />
55
<UiStatusPanel v-else-if="!isVmRunning" :image-source="monitor" :title="$t('power-on-vm-for-console')" />
66
<template v-else-if="vm && vmConsole">
7-
<MenuList horizontal>
8-
<MenuItem v-if="uiStore.hasUi" :icon="faArrowUpRightFromSquare" @click="openInNewTab">
9-
{{ $t('open-console-in-new-tab') }}
10-
</MenuItem>
11-
<MenuItem
12-
:icon="uiStore.hasUi ? faUpRightAndDownLeftFromCenter : faDownLeftAndUpRightToCenter"
13-
@click="toggleFullScreen"
14-
>
15-
{{ $t(uiStore.hasUi ? 'fullscreen' : 'fullscreen-leave') }}
16-
</MenuItem>
17-
<MenuItem :disabled="!consoleElement" :icon="faKeyboard" @click="sendCtrlAltDel">
18-
{{ $t('send-ctrl-alt-del') }}
19-
</MenuItem>
20-
</MenuList>
217
<RemoteConsole
8+
v-if="!uiStore.hasUi"
229
ref="consoleElement"
2310
:is-console-available="isConsoleAvailable"
2411
:location="vmConsole.location"
2512
class="remote-console"
2613
/>
14+
<VtsLayoutConsole v-else>
15+
<RemoteConsole
16+
ref="consoleElement"
17+
:is-console-available="isConsoleAvailable"
18+
:location="vmConsole.location"
19+
class="remote-console"
20+
/>
21+
<template #actions>
22+
<VtsActionsConsole
23+
:open-in-new-tab="openInNewTab"
24+
:send-ctrl-alt-del="sendCtrlAltDel"
25+
:toggle-full-screen="toggleFullScreen"
26+
/>
27+
<VtsDivider type="stretch" />
28+
<VtsClipboardConsole />
29+
</template>
30+
</VtsLayoutConsole>
2731
</template>
2832
</div>
2933
</template>
@@ -39,15 +43,11 @@ import type { XenApiVm } from '@/libs/xen-api/xen-api.types'
3943
import { usePageTitleStore } from '@/stores/page-title.store'
4044
import { useConsoleStore } from '@/stores/xen-api/console.store'
4145
import { useVmStore } from '@/stores/xen-api/vm.store'
42-
import MenuItem from '@core/components/menu/MenuItem.vue'
43-
import MenuList from '@core/components/menu/MenuList.vue'
46+
import VtsActionsConsole from '@core/components/console/VtsActionsConsole.vue'
47+
import VtsClipboardConsole from '@core/components/console/VtsClipboardConsole.vue'
48+
import VtsLayoutConsole from '@core/components/console/VtsLayoutConsole.vue'
49+
import VtsDivider from '@core/components/divider/VtsDivider.vue'
4450
import { useUiStore } from '@core/stores/ui.store'
45-
import {
46-
faArrowUpRightFromSquare,
47-
faDownLeftAndUpRightToCenter,
48-
faKeyboard,
49-
faUpRightAndDownLeftFromCenter,
50-
} from '@fortawesome/free-solid-svg-icons'
5151
import { computed, ref } from 'vue'
5252
import { useI18n } from 'vue-i18n'
5353
import { useRoute, useRouter } from 'vue-router'
@@ -136,46 +136,4 @@ const openInNewTab = () => {
136136
max-width: 100%;
137137
height: 100%;
138138
}
139-
140-
.not-available {
141-
display: flex;
142-
align-items: center;
143-
justify-content: center;
144-
flex-direction: column;
145-
text-align: center;
146-
gap: 4rem;
147-
color: var(--color-info-txt-base);
148-
font-size: 3.6rem;
149-
}
150-
151-
.open-in-new-window {
152-
position: absolute;
153-
top: 0;
154-
right: 0;
155-
overflow: hidden;
156-
157-
& > .link {
158-
display: flex;
159-
align-items: center;
160-
gap: 1rem;
161-
background-color: var(--color-info-txt-base);
162-
color: var(--color-info-txt-item);
163-
text-decoration: none;
164-
padding: 1.5rem;
165-
font-size: 1.6rem;
166-
border-radius: 0 0 0 0.8rem;
167-
white-space: nowrap;
168-
transform: translateX(calc(100% - 4.5rem));
169-
transition: transform 0.2s ease-in-out;
170-
171-
&:hover {
172-
transform: translateX(0);
173-
}
174-
}
175-
}
176-
177-
.vm-console-view:deep(.menu-list) {
178-
background-color: transparent;
179-
align-self: center;
180-
}
181139
</style>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<template>
2+
<UiCardTitle>{{ $t('console-actions') }}</UiCardTitle>
3+
<UiButton
4+
v-tooltip="openInNewTab === undefined ? $t('coming-soon') : undefined"
5+
:disabled="openInNewTab === undefined"
6+
accent="info"
7+
variant="tertiary"
8+
size="medium"
9+
:left-icon="faArrowUpRightFromSquare"
10+
@click="openInNewTab"
11+
>
12+
{{ $t('open-console-in-new-tab') }}
13+
</UiButton>
14+
<UiButton
15+
v-tooltip="toggleFullScreen === undefined ? $t('coming-soon') : undefined"
16+
:disabled="toggleFullScreen === undefined"
17+
accent="info"
18+
variant="tertiary"
19+
size="medium"
20+
:left-icon="faUpRightAndDownLeftFromCenter"
21+
@click="toggleFullScreen"
22+
>
23+
{{ $t('fullscreen') }}
24+
</UiButton>
25+
<UiButton
26+
v-tooltip="sendCtrlAltDel === undefined ? $t('coming-soon') : undefined"
27+
accent="info"
28+
variant="tertiary"
29+
size="medium"
30+
:disabled="sendCtrlAltDel === undefined"
31+
:left-icon="faKeyboard"
32+
@click="sendCtrlAltDel"
33+
>
34+
{{ $t('send-ctrl-alt-del') }}
35+
</UiButton>
36+
</template>
37+
38+
<script lang="ts" setup>
39+
import UiButton from '@core/components/ui/button/UiButton.vue'
40+
import UiCardTitle from '@core/components/ui/card-title/UiCardTitle.vue'
41+
import { vTooltip } from '@core/directives/tooltip.directive'
42+
import { faArrowUpRightFromSquare, faKeyboard, faUpRightAndDownLeftFromCenter } from '@fortawesome/free-solid-svg-icons'
43+
44+
// temporary undefined for xo6
45+
defineProps<{
46+
openInNewTab?: () => void
47+
toggleFullScreen?: () => void
48+
sendCtrlAltDel?: () => void
49+
}>()
50+
</script>
51+
52+
<style lang="postcss" scoped>
53+
.ui-button {
54+
align-self: start;
55+
gap: 0.8rem;
56+
text-align: left;
57+
}
58+
</style>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<template>
2+
<div class="vts-clipboard-console">
3+
<UiCardTitle>{{ $t('console-clipboard') }}</UiCardTitle>
4+
<UiTextarea accent="info" :model-value="modelValue" />
5+
<div class="btn">
6+
<UiButton v-tooltip="$t('coming-soon')" accent="info" variant="primary" size="medium" disabled>
7+
{{ $t('send') }}
8+
</UiButton>
9+
<UiButton v-tooltip="$t('coming-soon')" accent="info" variant="secondary" size="medium" disabled>
10+
{{ $t('receive') }}
11+
</UiButton>
12+
</div>
13+
</div>
14+
</template>
15+
16+
<script setup lang="ts">
17+
import UiButton from '@core/components/ui/button/UiButton.vue'
18+
import UiCardTitle from '@core/components/ui/card-title/UiCardTitle.vue'
19+
import UiTextarea from '@core/components/ui/input/UiTextarea.vue'
20+
import { vTooltip } from '@core/directives/tooltip.directive'
21+
import { ref } from 'vue'
22+
23+
const modelValue = ref('')
24+
</script>
25+
26+
<style lang="postcss" scoped>
27+
.vts-clipboard-console {
28+
display: flex;
29+
flex-direction: column;
30+
gap: 0.8rem;
31+
width: 100%;
32+
}
33+
.btn {
34+
display: flex;
35+
gap: 0.8rem;
36+
}
37+
</style>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<template>
2+
<div :class="uiStore.isMobile ? 'mobile' : undefined" class="vts-layout-console">
3+
<slot />
4+
<UiCard>
5+
<slot name="actions" />
6+
</UiCard>
7+
</div>
8+
</template>
9+
10+
<script lang="ts" setup>
11+
import UiCard from '@core/components/ui/card/UiCard.vue'
12+
import { useUiStore } from '@core/stores/ui.store'
13+
14+
defineSlots<{
15+
default(): any
16+
actions(): any
17+
}>()
18+
19+
const uiStore = useUiStore()
20+
</script>
21+
22+
<style lang="postcss" scoped>
23+
.vts-layout-console {
24+
display: flex;
25+
gap: 2.4rem;
26+
padding: 0.8rem;
27+
28+
&.mobile {
29+
flex-direction: column;
30+
}
31+
}
32+
.ui-card {
33+
height: fit-content;
34+
gap: 1.6rem;
35+
padding: 1.6rem;
36+
width: 43rem;
37+
}
38+
</style>

@xen-orchestra/web-core/lib/components/console/VtsRemoteConsole.vue

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,8 @@ const uiStore = useUiStore()
9797

9898
<style lang="postcss" scoped>
9999
.vts-remote-console {
100-
padding: 0.8rem;
101100
height: 80rem;
102-
width: 100%;
101+
flex-grow: 1;
103102
max-width: 100%;
104103
105104
&.mobile {

@xen-orchestra/web-core/lib/locales/de.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
"dashboard": "Dashboard",
2121
"documentation-name": "{name} Dokumentation",
22+
"fullscreen": "Vollbild",
2223
"hosts": "Hosts",
2324
"learn-more": "Mehr erfahren",
2425
"loading-in-progress": "Ladevorgang läuft…",
@@ -27,10 +28,12 @@
2728
"n-vms": "1 VM | {n} VMs",
2829
"network": "Netzwerk",
2930
"object-not-found": "Objekt {id} wurde nicht gefunden…",
31+
"open-console-in-new-tab": "Konsole in neuem Reiter öffnen",
3032
"patches": "Patches",
3133
"power-on-vm-for-console": "Konsole ist nach Start der VM verfügbar",
3234
"power-on-host-for-console": "Konsole ist nach Start des Hosts verfügbar",
3335
"running-vm": "VM eingeschalten | VMs eingeschalten",
36+
"send-ctrl-alt-del": "Ctrl+Alt+Del senden",
3437
"stats": "Statistiken",
3538
"storage": "Speicher",
3639
"support-name": "{name} pro support",

0 commit comments

Comments
 (0)