Update RemoteDesktopModal.vue

This commit is contained in:
Baobhan Sith
2025-04-28 10:19:21 +08:00
parent 2a598837af
commit 98e4516d25
@@ -15,23 +15,26 @@ const props = defineProps<{
const emit = defineEmits(['close']); const emit = defineEmits(['close']);
const rdpDisplayRef = ref<HTMLDivElement | null>(null); const rdpDisplayRef = ref<HTMLDivElement | null>(null);
const rdpContainerRef = ref<HTMLDivElement | null>(null); // Added ref for the container
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const guacClient = ref<any | null>(null); const guacClient = ref<any | null>(null);
const connectionStatus = ref<'disconnected' | 'connecting' | 'connected' | 'error'>('disconnected'); const connectionStatus = ref<'disconnected' | 'connecting' | 'connected' | 'error'>('disconnected');
const statusMessage = ref(''); const statusMessage = ref('');
const keyboard = ref<any | null>(null); const keyboard = ref<any | null>(null);
const mouse = ref<any | null>(null); const mouse = ref<any | null>(null);
const inputWidth = ref(1024); // const inputWidth = ref(1024); // Removed, size determined by container
const inputHeight = ref(768); // const inputHeight = ref(768); // Removed, size determined by container
// const modalStyle = ref({}); // Replaced by computedModalStyle // const modalStyle = ref({}); // Replaced by computedModalStyle
const rdpContainerStyle = ref<{ height?: string }>({}); // Only height is needed now // const rdpContainerStyle = ref<{ height?: string }>({}); // Removed, size determined by flex-1
const modalWidth = ref(1064); // Initial default based on 1024 + padding const desiredModalWidth = ref(1064); // User sets the desired TOTAL modal width (1024 + 40 padding)
const modalHeight = ref(858); // Initial default based on 768 + padding const desiredModalHeight = ref(858); // User sets the desired TOTAL modal height (768 + chrome)
const RDP_BACKEND_API_BASE = 'http://localhost:9090'; const RDP_BACKEND_API_BASE = 'http://localhost:9090';
const RDP_BACKEND_WEBSOCKET_URL = 'ws://localhost:8081'; const RDP_BACKEND_WEBSOCKET_URL = 'ws://localhost:8081';
const LOCAL_STORAGE_MODAL_WIDTH_KEY = 'rdpModalWidth'; // Reverted key name
const LOCAL_STORAGE_MODAL_HEIGHT_KEY = 'rdpModalHeight'; // Reverted key name
const connectRdp = async (useInputValues = false) => { const connectRdp = async () => { // Removed useInputValues parameter
if (!props.connection || !rdpDisplayRef.value) { if (!props.connection || !rdpDisplayRef.value) {
statusMessage.value = t('remoteDesktopModal.errors.missingInfo'); statusMessage.value = t('remoteDesktopModal.errors.missingInfo');
connectionStatus.value = 'error'; connectionStatus.value = 'error';
@@ -57,39 +60,26 @@ const connectRdp = async (useInputValues = false) => {
} }
statusMessage.value = t('remoteDesktopModal.status.connectingWs'); statusMessage.value = t('remoteDesktopModal.status.connectingWs');
let widthToSend = 1024; // Get RDP container dimensions after DOM update
let heightToSend = 768; await nextTick();
let widthToSend = 800; // Default/fallback width
let heightToSend = 600; // Default/fallback height
const dpiToSend = 96; const dpiToSend = 96;
if (useInputValues) { if (rdpContainerRef.value) {
widthToSend = parseInt(String(inputWidth.value), 10) || widthToSend; // Use clientWidth/clientHeight as they represent the inner dimensions available for content
heightToSend = parseInt(String(inputHeight.value), 10) || heightToSend; widthToSend = rdpContainerRef.value.clientWidth;
heightToSend = rdpContainerRef.value.clientHeight + 1; // Subtract 1 based on feedback
// Ensure minimum dimensions, adjust if necessary based on backend requirements
widthToSend = Math.max(100, widthToSend);
heightToSend = Math.max(100, heightToSend);
console.log(`Calculated RDP dimensions: ${widthToSend}x${heightToSend}`);
} else { } else {
if (rdpDisplayRef.value && rdpDisplayRef.value.clientWidth > 0 && rdpDisplayRef.value.clientHeight > 0) { console.warn("RDP container ref not available to get dimensions. Using defaults.");
widthToSend = rdpDisplayRef.value.clientWidth; // Consider setting an error state or notifying the user
heightToSend = rdpDisplayRef.value.clientHeight;
} else {
widthToSend = parseInt(String(inputWidth.value), 10) || widthToSend;
heightToSend = parseInt(String(inputHeight.value), 10) || heightToSend;
}
} }
inputWidth.value = widthToSend;
inputHeight.value = heightToSend;
const extraWidth = 40;
const headerHeight = 45;
const footerHeight = 35;
// Update modal size refs based on RDP size + padding
modalWidth.value = widthToSend + extraWidth;
modalHeight.value = heightToSend + headerHeight + footerHeight + 10;
rdpContainerStyle.value = {
// width: `${widthToSend}px`, // Remove width setting
height: `${heightToSend}px`,
};
const tunnelUrl = `${RDP_BACKEND_WEBSOCKET_URL}/?token=${encodeURIComponent(token)}&width=${widthToSend}&height=${heightToSend}&dpi=${dpiToSend}`; const tunnelUrl = `${RDP_BACKEND_WEBSOCKET_URL}/?token=${encodeURIComponent(token)}&width=${widthToSend}&height=${heightToSend}&dpi=${dpiToSend}`;
// @ts-ignore // @ts-ignore
const tunnel = new Guacamole.WebSocketTunnel(tunnelUrl); const tunnel = new Guacamole.WebSocketTunnel(tunnelUrl);
@@ -214,7 +204,10 @@ const removeInputListeners = () => {
}; };
// Removed stopResizeObserver as ResizeObserver is no longer used
const disconnectRdp = () => { const disconnectRdp = () => {
// stopResizeObserver(); // Removed
removeInputListeners(); removeInputListeners();
if (guacClient.value) { if (guacClient.value) {
guacClient.value.disconnect(); guacClient.value.disconnect();
@@ -232,40 +225,44 @@ const disconnectRdp = () => {
}; };
const reconnectWithNewSize = () => { // Removed reconnectWithNewSize function
const width = parseInt(String(inputWidth.value), 10);
const height = parseInt(String(inputHeight.value), 10);
if (!width || width <= 0 || !height || height <= 0) {
statusMessage.value = t('remoteDesktopModal.errors.invalidSize');
return;
}
disconnectRdp();
nextTick(() => {
connectRdp(true);
const headerHeight = 45;
const footerHeight = 35;
const extraWidth = 40;
rdpContainerStyle.value = {
// width: `${width}px`, // Remove width setting
height: `${height}px`,
};
// Update modal size refs based on new RDP size + padding
modalWidth.value = width + extraWidth;
modalHeight.value = height + headerHeight + footerHeight + 10;
});
};
const closeModal = () => { const closeModal = () => {
disconnectRdp(); disconnectRdp();
emit('close'); emit('close');
}; };
// Removed setupResizeObserver as ResizeObserver is no longer used
// Load desired MODAL size from localStorage on mount
const loadDesiredModalSize = () => {
const savedWidth = localStorage.getItem(LOCAL_STORAGE_MODAL_WIDTH_KEY);
const savedHeight = localStorage.getItem(LOCAL_STORAGE_MODAL_HEIGHT_KEY);
if (savedWidth) {
desiredModalWidth.value = parseInt(savedWidth, 10) || desiredModalWidth.value;
}
if (savedHeight) {
desiredModalHeight.value = parseInt(savedHeight, 10) || desiredModalHeight.value;
}
};
// Save desired MODAL size to localStorage when changed
watch(desiredModalWidth, (newWidth) => {
localStorage.setItem(LOCAL_STORAGE_MODAL_WIDTH_KEY, String(newWidth));
});
watch(desiredModalHeight, (newHeight) => {
localStorage.setItem(LOCAL_STORAGE_MODAL_HEIGHT_KEY, String(newHeight));
});
onMounted(() => { onMounted(() => {
loadDesiredModalSize(); // Load saved size first
if (props.connection) { if (props.connection) {
nextTick(() => { nextTick(async () => {
connectRdp(false); await connectRdp(); // Connect using initial size
// No need to setup observer anymore
}); });
} else { } else {
statusMessage.value = t('remoteDesktopModal.errors.noConnection'); statusMessage.value = t('remoteDesktopModal.errors.noConnection');
@@ -274,13 +271,14 @@ onMounted(() => {
}); });
onUnmounted(() => { onUnmounted(() => {
disconnectRdp(); disconnectRdp(); // This already calls stopResizeObserver
}); });
watch(() => props.connection, (newConnection, oldConnection) => { watch(() => props.connection, (newConnection, oldConnection) => {
if (newConnection && newConnection.id !== oldConnection?.id) { if (newConnection && newConnection.id !== oldConnection?.id) {
nextTick(() => { nextTick(async () => {
connectRdp(false); await connectRdp(); // Connect using initial size
// No need to setup observer anymore
}); });
} else if (!newConnection) { } else if (!newConnection) {
disconnectRdp(); disconnectRdp();
@@ -289,10 +287,18 @@ watch(() => props.connection, (newConnection, oldConnection) => {
} }
}); });
const computedModalStyle = computed(() => ({ // Use the desired modal size directly for the style
width: `${modalWidth.value}px`, const computedModalStyle = computed(() => {
height: `${modalHeight.value}px`, // const extraWidth = 40; // Removed from here as well
})); // const headerHeight = 45; // Defined in connectRdp
// const footerHeight = 35; // Defined in connectRdp
// const extraHeight = headerHeight + footerHeight + 10; // Defined in connectRdp
return {
width: `${desiredModalWidth.value}px`, // Width is direct
height: `${desiredModalHeight.value}px`, // Height is direct
};
});
</script> </script>
<template> <template>
@@ -326,7 +332,7 @@ const computedModalStyle = computed(() => ({
</div> </div>
</div> </div>
<div class="relative bg-black overflow-hidden flex-1" :style="rdpContainerStyle"> <div ref="rdpContainerRef" class="relative bg-black overflow-hidden flex-1">
<div ref="rdpDisplayRef" class="rdp-display-container w-full h-full"> <div ref="rdpDisplayRef" class="rdp-display-container w-full h-full">
</div> </div>
<div v-if="connectionStatus === 'connecting' || connectionStatus === 'error'" <div v-if="connectionStatus === 'connecting' || connectionStatus === 'error'"
@@ -336,7 +342,7 @@ const computedModalStyle = computed(() => ({
<i v-else class="fas fa-exclamation-triangle fa-2x mb-3 text-red-400"></i> <i v-else class="fas fa-exclamation-triangle fa-2x mb-3 text-red-400"></i>
<p class="text-sm">{{ statusMessage }}</p> <p class="text-sm">{{ statusMessage }}</p>
<button v-if="connectionStatus === 'error'" <button v-if="connectionStatus === 'error'"
@click="() => connectRdp(false)" @click="() => connectRdp()"
class="mt-4 px-3 py-1 bg-primary text-white rounded text-xs hover:bg-primary-dark"> class="mt-4 px-3 py-1 bg-primary text-white rounded text-xs hover:bg-primary-dark">
{{ t('common.retry') }} {{ t('common.retry') }}
</button> </button>
@@ -347,56 +353,26 @@ const computedModalStyle = computed(() => ({
<div class="p-2 border-t border-border flex-shrink-0 text-xs text-text-secondary bg-header flex items-center justify-between"> <div class="p-2 border-t border-border flex-shrink-0 text-xs text-text-secondary bg-header flex items-center justify-between">
<span>{{ statusMessage }}</span> <span>{{ statusMessage }}</span>
<div class="flex items-center space-x-2 flex-wrap gap-y-1"> <div class="flex items-center space-x-2 flex-wrap gap-y-1">
<label for="modal-width" class="text-xs ml-2">Modal W:</label> <label for="modal-width" class="text-xs ml-2">Modal W:</label> <!-- Changed label back -->
<input <input
id="modal-width" id="modal-width"
type="number" type="number"
v-model="modalWidth" v-model="desiredModalWidth"
min="200" min="200"
step="10" step="10"
class="w-16 px-1 py-0.5 text-xs border border-border rounded bg-input text-foreground focus:outline-none focus:ring-1 focus:ring-primary" class="w-16 px-1 py-0.5 text-xs border border-border rounded bg-input text-foreground focus:outline-none focus:ring-1 focus:ring-primary"
/> />
<label for="modal-height" class="text-xs">Modal H:</label> <label for="modal-height" class="text-xs">Modal H:</label> <!-- Changed label back -->
<input <input
id="modal-height" id="modal-height"
type="number" type="number"
v-model="modalHeight" v-model="desiredModalHeight"
min="200" min="200"
step="10" step="10"
class="w-16 px-1 py-0.5 text-xs border border-border rounded bg-input text-foreground focus:outline-none focus:ring-1 focus:ring-primary" class="w-16 px-1 py-0.5 text-xs border border-border rounded bg-input text-foreground focus:outline-none focus:ring-1 focus:ring-primary"
/> />
<span class="border-l border-border h-4 mx-2"></span> <!-- RDP Width/Height inputs and Reconnect button removed -->
<label for="rdp-width" class="text-xs">RDP W:</label>
<input
id="rdp-width"
type="number"
v-model="inputWidth"
min="100"
step="10"
class="w-16 px-1 py-0.5 text-xs border border-border rounded bg-input text-foreground focus:outline-none focus:ring-1 focus:ring-primary"
@keyup.enter="reconnectWithNewSize"
/>
<label for="rdp-height" class="text-xs">H:</label>
<input
id="rdp-height"
type="number"
v-model="inputHeight"
min="100"
step="10"
class="w-16 px-1 py-0.5 text-xs border border-border rounded bg-input text-foreground focus:outline-none focus:ring-1 focus:ring-primary"
@keyup.enter="reconnectWithNewSize"
/>
<button
@click="reconnectWithNewSize"
:disabled="connectionStatus === 'connecting'"
class="px-2 py-0.5 text-xs bg-primary text-white rounded hover:bg-primary-dark disabled:opacity-50 disabled:cursor-not-allowed"
:title="t('remoteDesktopModal.reconnectTooltip')"
>
<i class="fas fa-sync-alt mr-1"></i>
{{ t('remoteDesktopModal.reconnect') }}
</button>
</div> </div>
</div> </div>
</div> </div>