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 @@