diff --git a/pvc-vue/src/components/general/VMSearchBar.vue b/pvc-vue/src/components/general/VMSearchBar.vue index 2d52b63..9223d6b 100644 --- a/pvc-vue/src/components/general/VMSearchBar.vue +++ b/pvc-vue/src/components/general/VMSearchBar.vue @@ -184,6 +184,9 @@ onMounted(() => { // Set up click outside handler document.addEventListener('click', handleClickOutside); + // Get the selected VM from localStorage + const savedVMId = localStorage.getItem('selectedVMId'); + // Restore search text from localStorage if available const savedSearchText = localStorage.getItem('vmSearchText'); if (savedSearchText) { @@ -194,9 +197,20 @@ onMounted(() => { loadFiltersFromLocalStorage(); // Initialize input value based on selected VM - if (!props.showList && (props.selectedVM || props.vmFromUrl)) { - inputValue.value = props.selectedVM || props.vmFromUrl; + if (!props.showList) { + // If list is closed, show the selected VM name in the input + const effectiveVM = props.selectedVM || props.vmFromUrl || savedVMId; + if (effectiveVM) { + // Find the VM in the list to get its full name + const vm = props.vmList.find(v => v.name === effectiveVM); + if (vm) { + inputValue.value = vm.name; + } else { + inputValue.value = effectiveVM; + } + } } else if (props.showList && props.modelValue) { + // If list is open and there's a search query, show that inputValue.value = props.modelValue; searchText.value = props.modelValue; // Save to localStorage @@ -204,7 +218,7 @@ onMounted(() => { } // If the list is visible on mount, scroll to selected VM - if (props.showList && (props.selectedVM || props.vmFromUrl)) { + if (props.showList && (props.selectedVM || props.vmFromUrl || savedVMId)) { scrollToSelectedVM(); } }); @@ -351,6 +365,9 @@ const clearSearch = () => { const handleVMSelect = (vm) => { console.log('Selecting VM:', vm); + // Update the input value to show the selected VM + inputValue.value = vm.name; + // Save the current search text before selecting a VM if (props.modelValue) { searchText.value = props.modelValue; @@ -358,6 +375,9 @@ const handleVMSelect = (vm) => { localStorage.setItem('vmSearchText', props.modelValue); } + // Save selected VM to localStorage + localStorage.setItem('selectedVMId', vm.name); + emit('select-vm', vm); }; @@ -539,7 +559,7 @@ const getStateClass = (state) => { watch(() => props.showList, (isVisible) => { if (!isVisible) { // When list is closed, show selected VM - const effectiveVM = props.selectedVM || props.vmFromUrl; + const effectiveVM = props.selectedVM || props.vmFromUrl || localStorage.getItem('selectedVMId'); if (effectiveVM) { inputValue.value = effectiveVM; @@ -569,7 +589,7 @@ watch(() => props.showList, (isVisible) => { // Watch for changes in selectedVM or vmFromUrl watch([() => props.selectedVM, () => props.vmFromUrl], ([selectedVM, vmFromUrl]) => { if (!props.showList) { - const effectiveVM = selectedVM || vmFromUrl; + const effectiveVM = selectedVM || vmFromUrl || localStorage.getItem('selectedVMId'); if (effectiveVM) { inputValue.value = effectiveVM; } @@ -579,7 +599,7 @@ watch([() => props.selectedVM, () => props.vmFromUrl], ([selectedVM, vmFromUrl]) // Add a function to scroll to the selected VM const scrollToSelectedVM = () => { nextTick(() => { - const selectedVMName = props.selectedVM || props.vmFromUrl; + const selectedVMName = props.selectedVM || props.vmFromUrl || localStorage.getItem('selectedVMId'); if (selectedVMName && vmListContainer.value) { const activeElement = vmListContainer.value.querySelector(`[data-vm-name="${selectedVMName}"]`); if (activeElement) { diff --git a/pvc-vue/src/components/pages/nodes/NodeVMList.vue b/pvc-vue/src/components/pages/nodes/NodeVMList.vue index 9b11b45..440ff70 100644 --- a/pvc-vue/src/components/pages/nodes/NodeVMList.vue +++ b/pvc-vue/src/components/pages/nodes/NodeVMList.vue @@ -15,7 +15,7 @@ v-for="vmName in runningDomains" :key="vmName" class="vm-item" - @click="selectVM(vmName)" + @click="selectVMAndNavigate(vmName)" > {{ vmName }} @@ -26,6 +26,7 @@ diff --git a/pvc-vue/src/components/pages/vms/VMOverview.vue b/pvc-vue/src/components/pages/vms/VMOverview.vue index ff80a55..898c14d 100644 --- a/pvc-vue/src/components/pages/vms/VMOverview.vue +++ b/pvc-vue/src/components/pages/vms/VMOverview.vue @@ -147,7 +147,7 @@ const props = defineProps({ }); // Use ref and sync with route -const selectedVM = ref(route.query.vm || ''); +const selectedVM = ref(''); const searchQuery = ref(''); const showVMList = ref(true); const searchActive = ref(false); @@ -211,8 +211,10 @@ const selectVM = (vm) => { // Close the VM list showVMList.value = false; - // Update the URL - router.push({ query: { vm: vm.name } }); + // Save to localStorage + localStorage.setItem('selectedVMId', vm.name); + + // No URL parameter update }; // Clear search @@ -224,7 +226,13 @@ const clearSearch = () => { // Lifecycle hooks onMounted(() => { - console.log('VMOverview mounted, route.query.vm:', route.query.vm); + console.log('VMOverview mounted'); + isLoading.value = true; + + // Check sources in priority order: + // 1. localStorage (for returning to the page or navigating from other pages) + // 2. URL query parameter (for backward compatibility) + const savedVMId = localStorage.getItem('selectedVMId'); const vmFromQuery = route.query.vm; // Restore previous search query from localStorage if available @@ -233,64 +241,69 @@ onMounted(() => { searchQuery.value = savedSearch; } - if (vmFromQuery) { - console.log('Setting selectedVM to:', vmFromQuery); - selectedVM.value = vmFromQuery; - isLoading.value = true; - showVMList.value = false; + let vmToSelect = null; + + // Determine which VM to select + if (savedVMId) { + console.log('VM from localStorage:', savedVMId); + vmToSelect = savedVMId; + } else if (vmFromQuery) { + console.log('VM from URL query:', vmFromQuery); + vmToSelect = vmFromQuery; + // Save to localStorage for persistence + localStorage.setItem('selectedVMId', vmFromQuery); - // If we have data, verify the VM exists - if (props.vmData.length) { - const vmExists = props.vmData.some(v => v.name === vmFromQuery); - invalidVMSelected.value = !vmExists; + // Remove the VM ID from the URL without reloading the page + router.replace({ path: '/vms' }, { replace: true }); + } + + // If we have a VM to select and data is available + if (vmToSelect && props.vmData.length > 0) { + // Check if the VM exists + const vmExists = props.vmData.some(v => v.name === vmToSelect); + + if (vmExists) { + selectedVM.value = vmToSelect; + showVMList.value = false; + + // Set the search query to the VM name for display in the search bar + searchQuery.value = vmToSelect; + } else { + console.log('Selected VM does not exist:', vmToSelect); + invalidVMSelected.value = true; + localStorage.removeItem('selectedVMId'); } - isLoading.value = false; - } else if (props.vmData.length > 0) { + } else if (!vmToSelect && props.vmData.length > 0) { + // No VM selected, show the list showVMList.value = true; - invalidVMSelected.value = false; + } + + isLoading.value = false; +}); + +// Watch for changes in the selected VM +watch(selectedVM, (newValue) => { + if (newValue) { + // Save to localStorage whenever it changes + localStorage.setItem('selectedVMId', newValue); + } else { + localStorage.removeItem('selectedVMId'); } }); -onUnmounted(() => { - // Remove event listeners and clean up resources -}); - -// Watch for route changes to update selectedVM -watch(() => route.query.vm, (newVm) => { - // Explicitly update the ref when route changes - selectedVM.value = newVm || ''; - if (newVm) { - // Just update UI state, don't trigger another route change - invalidVMSelected.value = false; - showVMList.value = false; - } else if (props.vmData.length > 0) { - showVMList.value = true; - invalidVMSelected.value = false; - } -}, { immediate: true }); - -// Watch for changes in the VM list visibility -watch(() => showVMList.value, (isVisible) => { - if (isVisible && selectedVM.value) { - // Scroll to selected VM when the list becomes visible - nextTick(() => { - // Scroll to selected VM logic - }); - } -}); - -// Add watcher for vmData to handle loading state +// Watch for changes in the VM data watch(() => props.vmData, (newData) => { - if (selectedVM.value && newData.length) { + if (selectedVM.value && newData.length > 0) { + // Verify the VM still exists const vmExists = newData.some(vm => vm.name === selectedVM.value); invalidVMSelected.value = !vmExists; + + if (!vmExists) { + // If VM no longer exists, clear localStorage + localStorage.removeItem('selectedVMId'); + } } -}, { immediate: true }); - -// Add debug watcher -watch(() => selectedVM.value, (newVal) => { - console.log('VMOverview selectedVM changed:', newVal); -}, { immediate: true }); +}, { deep: true }); // Helper functions const getStateColor = (state) => { diff --git a/pvc-vue/src/services/navigation.js b/pvc-vue/src/services/navigation.js new file mode 100644 index 0000000..c17b039 --- /dev/null +++ b/pvc-vue/src/services/navigation.js @@ -0,0 +1,27 @@ +import { useRouter } from 'vue-router'; + +/** + * Navigate to a VM without using URL parameters + * @param {string} vmId - The ID of the VM to navigate to + * @param {import('vue-router').Router} router - Vue Router instance + */ +export function navigateToVM(vmId, router) { + // Save the VM ID to localStorage + localStorage.setItem('selectedVMId', vmId); + + // Navigate to the VMs page + router.push('/vms'); +} + +/** + * Navigate to a node without using URL parameters + * @param {string} nodeId - The ID of the node to navigate to + * @param {import('vue-router').Router} router - Vue Router instance + */ +export function navigateToNode(nodeId, router) { + // Save the node ID to localStorage + localStorage.setItem('selectedNodeId', nodeId); + + // Navigate to the Nodes page + router.push('/nodes'); +} \ No newline at end of file diff --git a/pvc-vue/src/utils/vmSelection.js b/pvc-vue/src/utils/vmSelection.js new file mode 100644 index 0000000..23377aa --- /dev/null +++ b/pvc-vue/src/utils/vmSelection.js @@ -0,0 +1,32 @@ +/** + * Selects a VM and saves the selection to localStorage + * @param {string} vmId - The ID of the VM to select + * @param {import('vue-router').Router} router - Vue Router instance (optional) + */ +export function selectVM(vmId, router = null) { + // Save to localStorage + localStorage.setItem('selectedVMId', vmId); + + // Optionally update URL if router is provided + if (router) { + router.push({ + path: '/vms', + query: { vm: vmId } + }); + } +} + +/** + * Gets the currently selected VM from localStorage + * @returns {string|null} The selected VM ID or null if none is selected + */ +export function getSelectedVM() { + return localStorage.getItem('selectedVMId'); +} + +/** + * Clears the selected VM from localStorage + */ +export function clearSelectedVM() { + localStorage.removeItem('selectedVMId'); +} \ No newline at end of file diff --git a/pvc-vue/src/views/VMs.vue b/pvc-vue/src/views/VMs.vue index cf34c34..f0b9740 100644 --- a/pvc-vue/src/views/VMs.vue +++ b/pvc-vue/src/views/VMs.vue @@ -11,9 +11,14 @@