diff --git a/assets/vue/components/glossary/GlossaryTermList.vue b/assets/vue/components/glossary/GlossaryTermList.vue index 82f723cdc8..f52b355af7 100644 --- a/assets/vue/components/glossary/GlossaryTermList.vue +++ b/assets/vue/components/glossary/GlossaryTermList.vue @@ -40,7 +40,7 @@ -
  • +
  • {{ t("There is no terms that matches the search: {searchTerm}", { searchTerm: searchTerm }) }}
  • @@ -62,6 +62,10 @@ defineProps({ type: String, required: true, }, + isLoading: { + type: Boolean, + required: true, + }, }) const emit = defineEmits(["edit", "delete"]) diff --git a/assets/vue/views/glossary/GlossaryList.vue b/assets/vue/views/glossary/GlossaryList.vue index be8a0ca029..fa946c8211 100644 --- a/assets/vue/views/glossary/GlossaryList.vue +++ b/assets/vue/views/glossary/GlossaryList.vue @@ -43,9 +43,26 @@ v-model="searchTerm" class="mb-4" :label="t('Search term...')" + @update:model-value="debouncedSearch" /> -
    +
    + + + + +
    + +
    @@ -91,7 +109,7 @@ import EmptyState from "../../components/EmptyState.vue" import BaseButton from "../../components/basecomponents/BaseButton.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 { useRoute, useRouter } from "vue-router" import { useI18n } from "vue-i18n" @@ -104,6 +122,9 @@ import glossaryService from "../../services/glossaryService" import { useNotification } from "../../composables/notification" import BaseDialogDelete from "../../components/basecomponents/BaseDialogDelete.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 route = useRoute() @@ -112,7 +133,10 @@ const notifications = useNotification() const { t } = useI18n() +const isLoading = ref(true) +const isSearchLoading = ref(false) const searchTerm = ref("") +const searchBoxTouched = ref(false) const parentResourceNodeId = ref(Number(route.params.node)) const resourceLinkList = ref( @@ -140,13 +164,16 @@ const termToDeleteString = computed(() => { return termToDelete.value.name }) -watch(searchTerm, () => { +onMounted(() => { + isLoading.value = true fetchGlossaries() }) -onMounted(() => { +const debouncedSearch = debounce(() => { + searchBoxTouched.value = true + isSearchLoading.value = true fetchGlossaries() -}) +}, 500) function addNewTerm() { router.push({ @@ -230,6 +257,9 @@ async function fetchGlossaries() { } catch (error) { console.error("Error fetching links:", error) notifications.showErrorNotification(t("Could not fetch glossary terms")) + } finally { + isLoading.value = false + isSearchLoading.value = false } } diff --git a/package.json b/package.json index c5d45f90c6..ec17ed8166 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "jsplumb": "^2.15.6", "linkifyjs": "3.0.5", "litepicker": "^2.0.12", + "lodash": "^4.17.21", "luxon": "^2.5.2", "mathjax": "^2.7.9", "mediaelement": "^5.1.1", diff --git a/yarn.lock b/yarn.lock index ac4a5755c4..867f67ed97 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3646,6 +3646,7 @@ __metadata: jsplumb: ^2.15.6 linkifyjs: 3.0.5 litepicker: ^2.0.12 + lodash: ^4.17.21 luxon: ^2.5.2 mathjax: ^2.7.9 mediaelement: ^5.1.1