Debounce input events to search in glossary

* Add lodash as dependency
pull/4795/head
Daniel Gayoso González 1 year ago
parent 8740a22f0e
commit 3efe62bf4f
  1. 6
      assets/vue/components/glossary/GlossaryTermList.vue
  2. 40
      assets/vue/views/glossary/GlossaryList.vue
  3. 1
      package.json
  4. 1
      yarn.lock

@ -40,7 +40,7 @@
</div> </div>
</BaseCard> </BaseCard>
</li> </li>
<li v-if="glossaries.length == 0"> <li v-if="!isLoading && glossaries.length === 0">
{{ t("There is no terms that matches the search: {searchTerm}", { searchTerm: searchTerm }) }} {{ t("There is no terms that matches the search: {searchTerm}", { searchTerm: searchTerm }) }}
</li> </li>
</ul> </ul>
@ -62,6 +62,10 @@ defineProps({
type: String, type: String,
required: true, required: true,
}, },
isLoading: {
type: Boolean,
required: true,
},
}) })
const emit = defineEmits(["edit", "delete"]) const emit = defineEmits(["edit", "delete"])

@ -43,9 +43,26 @@
v-model="searchTerm" v-model="searchTerm"
class="mb-4" class="mb-4"
:label="t('Search term...')" :label="t('Search term...')"
@update:model-value="debouncedSearch"
/> />
<div v-if="glossaries.length === 0 && searchTerm === ''"> <div v-if="isLoading">
<BaseCard
v-for="i in 4"
:key="i"
class="mb-4 bg-white"
plain
>
<template #header>
<div class="-mb-2 bg-gray-15 px-4 py-2">
<Skeleton class="my-2 h-6 w-52" />
</div>
</template>
<Skeleton class="h-6 w-64" />
</BaseCard>
</div>
<div v-if="glossaries.length === 0 && !searchBoxTouched && !isLoading">
<!-- Render the image and create button --> <!-- Render the image and create button -->
<EmptyState <EmptyState
icon="glossary" icon="glossary"
@ -66,6 +83,7 @@
v-if="view === 'list'" v-if="view === 'list'"
:glossaries="glossaries" :glossaries="glossaries"
:search-term="searchTerm" :search-term="searchTerm"
:is-loading="isLoading"
@edit="editTerm($event)" @edit="editTerm($event)"
@delete="confirmDeleteTerm($event)" @delete="confirmDeleteTerm($event)"
/> />
@ -91,7 +109,7 @@
import EmptyState from "../../components/EmptyState.vue" import EmptyState from "../../components/EmptyState.vue"
import BaseButton from "../../components/basecomponents/BaseButton.vue" import BaseButton from "../../components/basecomponents/BaseButton.vue"
import ButtonToolbar from "../../components/basecomponents/ButtonToolbar.vue" import ButtonToolbar from "../../components/basecomponents/ButtonToolbar.vue"
import { computed, onMounted, ref, watch } from "vue" import { computed, onMounted, ref } from "vue"
import { useStore } from "vuex" import { useStore } from "vuex"
import { useRoute, useRouter } from "vue-router" import { useRoute, useRouter } from "vue-router"
import { useI18n } from "vue-i18n" import { useI18n } from "vue-i18n"
@ -104,6 +122,9 @@ import glossaryService from "../../services/glossaryService"
import { useNotification } from "../../composables/notification" import { useNotification } from "../../composables/notification"
import BaseDialogDelete from "../../components/basecomponents/BaseDialogDelete.vue" import BaseDialogDelete from "../../components/basecomponents/BaseDialogDelete.vue"
import StudentViewButton from "../../components/StudentViewButton.vue" import StudentViewButton from "../../components/StudentViewButton.vue"
import { debounce } from "lodash"
import BaseCard from "../../components/basecomponents/BaseCard.vue"
import Skeleton from "primevue/skeleton"
const store = useStore() const store = useStore()
const route = useRoute() const route = useRoute()
@ -112,7 +133,10 @@ const notifications = useNotification()
const { t } = useI18n() const { t } = useI18n()
const isLoading = ref(true)
const isSearchLoading = ref(false)
const searchTerm = ref("") const searchTerm = ref("")
const searchBoxTouched = ref(false)
const parentResourceNodeId = ref(Number(route.params.node)) const parentResourceNodeId = ref(Number(route.params.node))
const resourceLinkList = ref( const resourceLinkList = ref(
@ -140,13 +164,16 @@ const termToDeleteString = computed(() => {
return termToDelete.value.name return termToDelete.value.name
}) })
watch(searchTerm, () => { onMounted(() => {
isLoading.value = true
fetchGlossaries() fetchGlossaries()
}) })
onMounted(() => { const debouncedSearch = debounce(() => {
searchBoxTouched.value = true
isSearchLoading.value = true
fetchGlossaries() fetchGlossaries()
}) }, 500)
function addNewTerm() { function addNewTerm() {
router.push({ router.push({
@ -230,6 +257,9 @@ async function fetchGlossaries() {
} catch (error) { } catch (error) {
console.error("Error fetching links:", error) console.error("Error fetching links:", error)
notifications.showErrorNotification(t("Could not fetch glossary terms")) notifications.showErrorNotification(t("Could not fetch glossary terms"))
} finally {
isLoading.value = false
isSearchLoading.value = false
} }
} }
</script> </script>

@ -65,6 +65,7 @@
"jsplumb": "^2.15.6", "jsplumb": "^2.15.6",
"linkifyjs": "3.0.5", "linkifyjs": "3.0.5",
"litepicker": "^2.0.12", "litepicker": "^2.0.12",
"lodash": "^4.17.21",
"luxon": "^2.5.2", "luxon": "^2.5.2",
"mathjax": "^2.7.9", "mathjax": "^2.7.9",
"mediaelement": "^5.1.1", "mediaelement": "^5.1.1",

@ -3646,6 +3646,7 @@ __metadata:
jsplumb: ^2.15.6 jsplumb: ^2.15.6
linkifyjs: 3.0.5 linkifyjs: 3.0.5
litepicker: ^2.0.12 litepicker: ^2.0.12
lodash: ^4.17.21
luxon: ^2.5.2 luxon: ^2.5.2
mathjax: ^2.7.9 mathjax: ^2.7.9
mediaelement: ^5.1.1 mediaelement: ^5.1.1

Loading…
Cancel
Save