Move search bar into dedicated component
This commit is contained in:
parent
037ea7fe8e
commit
c467b92384
94
pvc-vue/src/components/general/VMSearchBar.vue
Normal file
94
pvc-vue/src/components/general/VMSearchBar.vue
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<template>
|
||||||
|
<div class="search-box">
|
||||||
|
<i class="fas fa-search search-icon"></i>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Search VMs..."
|
||||||
|
:value="modelValue"
|
||||||
|
@input="handleSearch"
|
||||||
|
@focus="handleFocus"
|
||||||
|
@blur="handleBlur"
|
||||||
|
class="form-control search-input"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
v-if="modelValue && showList && showClearButton"
|
||||||
|
class="btn-clear"
|
||||||
|
@click="clearSearch"
|
||||||
|
>
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { defineProps, defineEmits } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
showList: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
showClearButton: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue', 'search', 'focus', 'blur', 'clear']);
|
||||||
|
|
||||||
|
const handleSearch = (event) => {
|
||||||
|
emit('update:modelValue', event.target.value);
|
||||||
|
emit('search', event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFocus = (event) => {
|
||||||
|
emit('focus', event);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBlur = (event) => {
|
||||||
|
emit('blur', event);
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearSearch = () => {
|
||||||
|
emit('update:modelValue', '');
|
||||||
|
emit('clear');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.search-box {
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
position: absolute;
|
||||||
|
left: 10px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
color: #6c757d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
padding-left: 30px;
|
||||||
|
padding-right: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-clear {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #6c757d;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
</style>
|
@ -11,25 +11,15 @@
|
|||||||
<i class="fas fa-list"></i> List VMs
|
<i class="fas fa-list"></i> List VMs
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="search-box">
|
<VMSearchBar
|
||||||
<i class="fas fa-search search-icon"></i>
|
:model-value="showVMList ? searchQuery : selectedVMData?.name || ''"
|
||||||
<input
|
:show-list="showVMList"
|
||||||
type="text"
|
:show-clear-button="showVMList"
|
||||||
placeholder="Search VMs..."
|
@search="handleSearch"
|
||||||
:value="showVMList ? searchQuery : (selectedVMData?.name || '')"
|
@focus="handleSearchFocus"
|
||||||
@input="handleSearch"
|
@blur="handleSearchBlur"
|
||||||
@focus="handleSearchFocus"
|
@clear="clearSearch"
|
||||||
@blur="handleSearchBlur"
|
/>
|
||||||
class="form-control search-input"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
v-if="searchQuery && showVMList"
|
|
||||||
class="btn-clear"
|
|
||||||
@click="clearSearch"
|
|
||||||
>
|
|
||||||
<i class="fas fa-times"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="filter-dropdown">
|
<div class="filter-dropdown">
|
||||||
<button
|
<button
|
||||||
@ -217,6 +207,7 @@ import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue';
|
|||||||
import { useRouter, useRoute } from 'vue-router';
|
import { useRouter, useRoute } from 'vue-router';
|
||||||
import CollapsibleSection from '../../general/CollapsibleSection.vue';
|
import CollapsibleSection from '../../general/CollapsibleSection.vue';
|
||||||
import ValueCard from '../../general/ValueCard.vue';
|
import ValueCard from '../../general/ValueCard.vue';
|
||||||
|
import VMSearchBar from '../../general/VMSearchBar.vue';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@ -428,8 +419,8 @@ const getStatusClass = (state) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Handle search input
|
// Handle search input
|
||||||
const handleSearch = (event) => {
|
const handleSearch = (value) => {
|
||||||
searchQuery.value = event.target.value;
|
searchQuery.value = value;
|
||||||
searchActive.value = true;
|
searchActive.value = true;
|
||||||
filterVMs();
|
filterVMs();
|
||||||
};
|
};
|
||||||
@ -637,6 +628,13 @@ const formatStorage = (sizeGB) => {
|
|||||||
if (sizeGB < 1024) return sizeGB + ' GB';
|
if (sizeGB < 1024) return sizeGB + ' GB';
|
||||||
return (sizeGB / 1024).toFixed(1) + ' TB';
|
return (sizeGB / 1024).toFixed(1) + ' TB';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Clear search
|
||||||
|
const clearSearch = () => {
|
||||||
|
searchQuery.value = '';
|
||||||
|
searchActive.value = false;
|
||||||
|
filterVMs();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -687,39 +685,6 @@ const formatStorage = (sizeGB) => {
|
|||||||
margin-left: 0.5rem;
|
margin-left: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search box styles */
|
|
||||||
.search-box {
|
|
||||||
position: relative;
|
|
||||||
flex: 1;
|
|
||||||
min-width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-icon {
|
|
||||||
position: absolute;
|
|
||||||
left: 10px;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
color: #6c757d;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-input {
|
|
||||||
padding-left: 30px;
|
|
||||||
padding-right: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-clear {
|
|
||||||
position: absolute;
|
|
||||||
right: 10px;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
color: #6c757d;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* VM List styles */
|
/* VM List styles */
|
||||||
.vm-list-container {
|
.vm-list-container {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user