Compare commits

...

4 Commits

7 changed files with 109 additions and 9 deletions

View File

@ -1,6 +1,7 @@
<script setup>
import { onMounted } from 'vue';
import axios from 'axios';
import { useStateQuery } from 'src/composables/useStateQuery';
const $props = defineProps({
autoLoad: {
@ -32,7 +33,7 @@ const $props = defineProps({
default: null,
},
});
const stateQuery = useStateQuery();
const emit = defineEmits(['onFetch']);
defineExpose({ fetch });
@ -43,6 +44,7 @@ onMounted(async () => {
});
async function fetch(fetchFilter = {}) {
const hash = stateQuery.add();
try {
const filter = { ...fetchFilter, ...$props.filter }; // eslint-disable-line vue/no-dupe-keys
if ($props.where && !fetchFilter.where) filter.where = $props.where;
@ -55,8 +57,8 @@ async function fetch(fetchFilter = {}) {
emit('onFetch', data);
return data;
} catch (e) {
//
} finally {
stateQuery.remove(hash);
}
}
</script>

View File

@ -3,6 +3,7 @@ import { onMounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useState } from 'src/composables/useState';
import { useStateStore } from 'stores/useStateStore';
import { useStateQuery } from 'src/composables/useStateQuery';
import { useQuasar } from 'quasar';
import PinnedModules from './PinnedModules.vue';
import UserPanel from 'components/UserPanel.vue';
@ -12,6 +13,7 @@ import VnAvatar from './ui/VnAvatar.vue';
const { t } = useI18n();
const stateStore = useStateStore();
const quasar = useQuasar();
const stateQuery = useStateQuery();
const state = useState();
const user = state.getUser();
const appName = 'Lilium';
@ -50,6 +52,14 @@ const pinnedModulesRef = ref();
</QBtn>
</RouterLink>
<VnBreadcrumbs v-if="$q.screen.gt.sm" />
<QSpinner
color="primary"
class="q-ml-md"
:class="{
'no-visible': !stateQuery.isLoading().value,
}"
size="xs"
/>
<QSpace />
<div id="searchbar" class="searchbar"></div>
<QSpace />
@ -104,6 +114,9 @@ const pinnedModulesRef = ref();
.q-header {
background-color: var(--vn-section-color);
}
.no-visible {
visibility: hidden;
}
</style>
<i18n>
en:

View File

@ -3,8 +3,10 @@ import { useRouter, useRoute } from 'vue-router';
import axios from 'axios';
import { useArrayDataStore } from 'stores/useArrayDataStore';
import { buildFilter } from 'filters/filterPanel';
import { useStateQuery } from 'src/composables/useStateQuery';
const arrayDataStore = useArrayDataStore();
const stateQuery = useStateQuery();
export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
if (!key) throw new Error('ArrayData: A key is required to use this composable');
@ -99,11 +101,18 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
params.filter = JSON.stringify(params.filter);
store.currentFilter = params;
store.isLoading = true;
const response = await axios.get(store.url, {
const hash = stateQuery.add();
let response;
try {
response = await axios.get(store.url, {
signal: canceller.signal,
params,
});
} finally {
stateQuery.remove(hash);
}
const { limit } = filter;
store.hasMoreData = limit && response.data.length >= limit;

View File

@ -0,0 +1,33 @@
import { ref, computed } from 'vue';
const queries = ref(new Set());
export function useStateQuery() {
function add() {
const min = 100000;
const max = 999999;
const hash = String(Math.floor(Math.random() * (max - min + 1)) + min);
queries.value.add(hash);
return hash;
}
function isLoading() {
return computed(() => queries.value.size);
}
function remove(hash) {
queries.value.delete(hash);
}
function reset() {
queries.value = new Set();
}
return {
add,
isLoading,
remove,
queries,
reset,
};
}

View File

@ -0,0 +1,42 @@
import { describe, expect, it, beforeEach } from 'vitest';
import { useStateQuery } from 'src/composables/useStateQuery';
describe('useStateQuery', () => {
const { add, isLoading, remove, reset, queries } = useStateQuery();
beforeEach(() => {
reset();
expect(queries.value.size).toBeFalsy();
});
it('should add two queries', async () => {
expect(queries.value.size).toBeFalsy();
const hash = add();
expect(queries.value.size).toBeTruthy();
expect(queries.value.has(hash)).toBeTruthy();
add();
expect(queries.value.size).toBe(2);
});
it('should add and remove loading state', async () => {
expect(isLoading().value).toBeFalsy();
const hash = add();
expect(isLoading().value).toBeTruthy();
remove(hash);
expect(isLoading().value).toBeFalsy();
});
it('should add and remove hash', async () => {
add();
add();
add();
const beforeCount = queries.value.size;
const hash = add();
expect(queries.value.has(hash)).toBeTruthy();
remove(hash);
expect(queries.value.has(hash)).toBeFalsy();
expect(queries.value.size).toBe(beforeCount);
});
});

View File

@ -6,6 +6,7 @@ describe('InvoiceInIntrastat', () => {
let vm;
beforeAll(() => {
vi.spyOn(axios, 'get').mockResolvedValue({ data: [{}] });
vm = createWrapper(InvoiceInIntrastat, {
global: {
stubs: ['vnPaginate'],
@ -14,7 +15,6 @@ describe('InvoiceInIntrastat', () => {
},
},
}).vm;
vi.spyOn(axios, 'get').mockResolvedValue({ data: [{}] });
});
describe('getTotal()', () => {

View File

@ -1,11 +1,12 @@
import { vi, describe, expect, it, beforeAll } from 'vitest';
import { createWrapper } from 'app/test/vitest/helper';
import { createWrapper, axios } from 'app/test/vitest/helper';
import InvoiceInVat from 'src/pages/InvoiceIn/Card/InvoiceInVat.vue';
describe('InvoiceInVat', () => {
let vm;
beforeAll(() => {
vi.spyOn(axios, 'get').mockResolvedValue({ data: [{}] });
vm = createWrapper(InvoiceInVat, {
global: {
stubs: [],