URL-less VM view and persistence
This commit is contained in:
parent
61dbe8eed1
commit
e26c5defa4
@ -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) {
|
||||
|
@ -15,7 +15,7 @@
|
||||
v-for="vmName in runningDomains"
|
||||
:key="vmName"
|
||||
class="vm-item"
|
||||
@click="selectVM(vmName)"
|
||||
@click="selectVMAndNavigate(vmName)"
|
||||
>
|
||||
{{ vmName }}
|
||||
</div>
|
||||
@ -26,6 +26,7 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { navigateToVM } from '../../../services/navigation';
|
||||
|
||||
const props = defineProps({
|
||||
vmData: {
|
||||
@ -69,10 +70,9 @@ const runningDomains = computed(() => {
|
||||
return nodeData.value.running_domains;
|
||||
});
|
||||
|
||||
// Navigate to VM details
|
||||
const selectVM = (vmName) => {
|
||||
// Store the VM ID in localStorage so it will be selected when the VMs page loads
|
||||
localStorage.setItem('selectedVMId', vmName);
|
||||
// Navigate to VM details using the navigation service
|
||||
const selectVMAndNavigate = (vmName) => {
|
||||
navigateToVM(vmName, router);
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -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) => {
|
||||
|
27
pvc-vue/src/services/navigation.js
Normal file
27
pvc-vue/src/services/navigation.js
Normal file
@ -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');
|
||||
}
|
32
pvc-vue/src/utils/vmSelection.js
Normal file
32
pvc-vue/src/utils/vmSelection.js
Normal file
@ -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');
|
||||
}
|
@ -11,9 +11,14 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import PageTitle from '../components/general/PageTitle.vue';
|
||||
import VMOverview from '../components/pages/vms/VMOverview.vue';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const props = defineProps({
|
||||
vmData: {
|
||||
type: Array,
|
||||
@ -35,6 +40,9 @@ const props = defineProps({
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
// We'll handle the VM selection in the VMOverview component
|
||||
// This parent component just needs to pass the data
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
Loading…
x
Reference in New Issue
Block a user