Compare commits

...

2 Commits

Author SHA1 Message Date
Thierry
72454ac593 add changelog 2023-05-12 09:30:44 +02:00
Thierry
4a45e78c1c feat(lite/console): add ability to open console in new window 2023-05-12 09:26:40 +02:00
6 changed files with 71 additions and 18 deletions

View File

@@ -1,5 +1,9 @@
# ChangeLog # ChangeLog
## **next**
- Add ability to open VM console in new window (PR [#6827](https://github.com/vatesfr/xen-orchestra/pull/6827))
## **0.2.0** ## **0.2.0**
- Invalidate sessionId token after logout (PR [#6480](https://github.com/vatesfr/xen-orchestra/pull/6480)) - Invalidate sessionId token after logout (PR [#6480](https://github.com/vatesfr/xen-orchestra/pull/6480))

View File

@@ -24,9 +24,9 @@
<AppLogin /> <AppLogin />
</div> </div>
<div v-else> <div v-else>
<AppHeader /> <AppHeader v-if="uiStore.hasUi" />
<div style="display: flex"> <div style="display: flex">
<AppNavigation /> <AppNavigation v-if="uiStore.hasUi" />
<main class="main"> <main class="main">
<RouterView /> <RouterView />
</main> </main>

View File

@@ -1,5 +1,5 @@
<template> <template>
<div ref="vmConsoleContainer" class="vm-console" /> <div ref="consoleContainer" class="remote-console" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@@ -19,7 +19,7 @@ const props = defineProps<{
isConsoleAvailable: boolean; isConsoleAvailable: boolean;
}>(); }>();
const vmConsoleContainer = ref<HTMLDivElement>(); const consoleContainer = ref<HTMLDivElement>();
const xenApiStore = useXenApiStore(); const xenApiStore = useXenApiStore();
const url = computed(() => { const url = computed(() => {
if (xenApiStore.currentSessionId == null) { if (xenApiStore.currentSessionId == null) {
@@ -78,7 +78,7 @@ const createVncConnection = async () => {
await promiseTimeout(FIBONACCI_MS_ARRAY[nConnectionAttempts - 1]); await promiseTimeout(FIBONACCI_MS_ARRAY[nConnectionAttempts - 1]);
} }
vncClient = new VncClient(vmConsoleContainer.value!, url.value!.toString(), { vncClient = new VncClient(consoleContainer.value!, url.value!.toString(), {
wsProtocols: ["binary"], wsProtocols: ["binary"],
}); });
vncClient.scaleViewport = true; vncClient.scaleViewport = true;
@@ -91,7 +91,7 @@ watch(url, clearVncClient);
watchEffect(() => { watchEffect(() => {
if ( if (
url.value === undefined || url.value === undefined ||
vmConsoleContainer.value === undefined || consoleContainer.value === undefined ||
!props.isConsoleAvailable !props.isConsoleAvailable
) { ) {
return; return;
@@ -107,8 +107,8 @@ onBeforeUnmount(() => {
</script> </script>
<style lang="postcss" scoped> <style lang="postcss" scoped>
.vm-console { .remote-console {
height: 80rem; height: 100%;
& > :deep(div) { & > :deep(div) {
background-color: transparent !important; background-color: transparent !important;

View File

@@ -1,6 +1,7 @@
import { useBreakpoints, useColorMode } from "@vueuse/core"; import { useBreakpoints, useColorMode } from "@vueuse/core";
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { computed, ref } from "vue"; import { computed, ref } from "vue";
import { useRoute } from "vue-router";
export const useUiStore = defineStore("ui", () => { export const useUiStore = defineStore("ui", () => {
const currentHostOpaqueRef = ref(); const currentHostOpaqueRef = ref();
@@ -13,10 +14,15 @@ export const useUiStore = defineStore("ui", () => {
const isMobile = computed(() => !isDesktop.value); const isMobile = computed(() => !isDesktop.value);
const route = useRoute();
const hasUi = computed(() => route.query.ui !== "0");
return { return {
colorMode, colorMode,
currentHostOpaqueRef, currentHostOpaqueRef,
isDesktop, isDesktop,
isMobile, isMobile,
hasUi,
}; };
}); });

View File

@@ -1,20 +1,34 @@
<template> <template>
<div v-if="!isReady">Loading...</div> <div v-if="!isReady">Loading...</div>
<div v-else-if="!isVmRunning">Console is only available for running VMs.</div> <div v-else-if="!isVmRunning">Console is only available for running VMs.</div>
<RemoteConsole <template v-else-if="vm && vmConsole">
v-else-if="vm && vmConsole" <RemoteConsole
:location="vmConsole.location" :is-console-available="!isOperationsPending(vm, STOP_OPERATIONS)"
:is-console-available="!isOperationsPending(vm, STOP_OPERATIONS)" :location="vmConsole.location"
/> class="remote-console"
/>
<RouterLink
v-if="uiStore.hasUi"
:to="{ query: { ui: '0' } }"
class="open-link"
target="_blank"
>
<UiIcon :icon="faArrowUpRightFromSquare" />
Open in new window
</RouterLink>
</template>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import RemoteConsole from "@/components/RemoteConsole.vue";
import UiIcon from "@/components/ui/icon/UiIcon.vue";
import { isOperationsPending } from "@/libs/utils";
import { useConsoleStore } from "@/stores/console.store";
import { useUiStore } from "@/stores/ui.store";
import { useVmStore } from "@/stores/vm.store";
import { faArrowUpRightFromSquare } from "@fortawesome/free-solid-svg-icons";
import { computed } from "vue"; import { computed } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import RemoteConsole from "@/components/RemoteConsole.vue";
import { useConsoleStore } from "@/stores/console.store";
import { useVmStore } from "@/stores/vm.store";
import { isOperationsPending } from "@/libs/utils";
const STOP_OPERATIONS = [ const STOP_OPERATIONS = [
"shutdown", "shutdown",
@@ -26,6 +40,7 @@ const STOP_OPERATIONS = [
"suspend", "suspend",
]; ];
const uiStore = useUiStore();
const route = useRoute(); const route = useRoute();
const { isReady: isVmReady, getByUuid: getVmByUuid } = useVmStore().subscribe(); const { isReady: isVmReady, getByUuid: getVmByUuid } = useVmStore().subscribe();
@@ -49,3 +64,31 @@ const vmConsole = computed(() => {
return getConsoleByOpaqueRef(consoleOpaqueRef); return getConsoleByOpaqueRef(consoleOpaqueRef);
}); });
</script> </script>
<style lang="postcss" scoped>
.open-link {
display: flex;
align-items: center;
gap: 1rem;
background-color: var(--color-extra-blue-base);
color: var(--color-blue-scale-500);
text-decoration: none;
padding: 1.5rem;
font-size: 1.6rem;
border-radius: 0 0 0 0.8rem;
position: absolute;
top: 8rem;
right: 0;
white-space: nowrap;
transform: translateX(calc(100% - 4.5rem));
transition: transform 0.2s ease-in-out;
&:hover {
transform: translateX(0);
}
}
.remote-console {
height: calc(100% - 8rem);
}
</style>

View File

@@ -1,6 +1,6 @@
<template> <template>
<ObjectNotFoundWrapper :is-ready="isReady" :uuid-checker="hasUuid"> <ObjectNotFoundWrapper :is-ready="isReady" :uuid-checker="hasUuid">
<VmHeader /> <VmHeader v-if="uiStore.hasUi" />
<RouterView /> <RouterView />
</ObjectNotFoundWrapper> </ObjectNotFoundWrapper>
</template> </template>