From 2a6717d0595cffd275455f920f06077fe50ae36f Mon Sep 17 00:00:00 2001 From: jorgep Date: Wed, 11 Dec 2024 15:04:31 +0100 Subject: [PATCH 1/2] feat: refs #8113 add mapKey prop to VnPaginate and integrate into useArrayData for enhanced data mapping --- src/components/ui/VnPaginate.vue | 5 +++ src/composables/useArrayData.js | 37 ++++++++++++---- src/pages/Ticket/TicketAdvance.vue | 1 + src/stores/useArrayDataStore.js | 2 + .../__tests__/components/Paginate.spec.js | 43 ++++++++----------- 5 files changed, 54 insertions(+), 34 deletions(-) diff --git a/src/components/ui/VnPaginate.vue b/src/components/ui/VnPaginate.vue index 3649ba8f5..920836a93 100644 --- a/src/components/ui/VnPaginate.vue +++ b/src/components/ui/VnPaginate.vue @@ -74,6 +74,10 @@ const props = defineProps({ type: Boolean, default: false, }, + mapKey: { + type: String, + default: '', + }, }); const emit = defineEmits(['onFetch', 'onPaginate', 'onChange']); @@ -96,6 +100,7 @@ const arrayData = useArrayData(props.dataKey, { exprBuilder: props.exprBuilder, keepOpts: props.keepOpts, searchUrl: props.searchUrl, + mapKey: props.mapKey, }); const store = arrayData.store; diff --git a/src/composables/useArrayData.js b/src/composables/useArrayData.js index da62eee3e..6e685ee20 100644 --- a/src/composables/useArrayData.js +++ b/src/composables/useArrayData.js @@ -49,6 +49,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) { 'exprBuilder', 'searchUrl', 'navigate', + 'mapKey', ]; if (typeof userOptions === 'object') { for (const option in userOptions) { @@ -119,17 +120,12 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) { const { limit } = filter; store.hasMoreData = limit && response.data.length >= limit; - if (append) { - if (!store.data) store.data = []; - for (const row of response.data) store.data.push(row); - } else { - store.data = response.data; - if (!isDialogOpened()) updateRouter && updateStateParams(); - } + processData(response.data, { map: !!store.mapKey, append }); + if (!append && !isDialogOpened()) updateRouter && updateStateParams(); store.isLoading = false; - canceller = null; + return response; } @@ -288,6 +284,31 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) { router.replace(newUrl); } + function processData(data, { map = true, append = true }) { + if (!append) { + store.data = []; + store.map = new Map(); + } + + if (!Array.isArray(data)) store.data = data; + else if (!map && append) for (const row of data) store.data.push(row); + else + for (const row of data) { + const key = row[store.mapKey]; + const val = { ...row, key }; + if (store.map.has(key)) { + const { position } = store.map.get(key); + val.position = position; + store.map.set(key, val); + store.data[position] = val; + } else { + val.position = store.map.size; + store.map.set(key, val); + store.data.push(val); + } + } + } + const totalRows = computed(() => (store.data && store.data.length) || 0); const isLoading = computed(() => store.isLoading || false); diff --git a/src/pages/Ticket/TicketAdvance.vue b/src/pages/Ticket/TicketAdvance.vue index 8de602b37..a867285e7 100644 --- a/src/pages/Ticket/TicketAdvance.vue +++ b/src/pages/Ticket/TicketAdvance.vue @@ -441,6 +441,7 @@ watch( { searchUrl: 'params', navigate: null, page: 1, + mapKey: 'id', }; function get(key) { @@ -46,6 +47,7 @@ export const useArrayDataStore = defineStore('arrayDataStore', () => { function getDefaultState() { return Object.assign(JSON.parse(JSON.stringify(defaultOpts)), { data: ref(), + map: ref(new Map()), }); } diff --git a/test/vitest/__tests__/components/Paginate.spec.js b/test/vitest/__tests__/components/Paginate.spec.js index 345903c1a..a67dfcdc6 100644 --- a/test/vitest/__tests__/components/Paginate.spec.js +++ b/test/vitest/__tests__/components/Paginate.spec.js @@ -4,7 +4,11 @@ import VnPaginate from 'src/components/ui/VnPaginate.vue'; describe('VnPaginate', () => { const expectedUrl = '/api/customers'; - + const defaultData = [ + { id: 1, name: 'Tony Stark' }, + { id: 2, name: 'Jessica Jones' }, + { id: 3, name: 'Bruce Wayne' }, + ]; let vm; beforeAll(() => { const options = { @@ -28,11 +32,7 @@ describe('VnPaginate', () => { describe('paginate()', () => { it('should call to the paginate() method and set the data on the rows property', async () => { vi.spyOn(vm.arrayData, 'loadMore'); - vm.store.data = [ - { id: 1, name: 'Tony Stark' }, - { id: 2, name: 'Jessica Jones' }, - { id: 3, name: 'Bruce Wayne' }, - ]; + vm.store.data = defaultData; await vm.paginate(); @@ -42,26 +42,25 @@ describe('VnPaginate', () => { it('should call to the paginate() method and then call it again to paginate', async () => { vi.spyOn(axios, 'get').mockResolvedValue({ - data: [ - { id: 1, name: 'Tony Stark' }, - { id: 2, name: 'Jessica Jones' }, - { id: 3, name: 'Bruce Wayne' }, - ], + data: defaultData, }); vm.store.hasMoreData = true; await vm.$nextTick(); - vm.store.data = [ - { id: 1, name: 'Tony Stark' }, - { id: 2, name: 'Jessica Jones' }, - { id: 3, name: 'Bruce Wayne' }, - ]; + vm.store.data = defaultData; await vm.paginate(); expect(vm.store.skip).toEqual(3); expect(vm.store.data.length).toEqual(6); + vi.spyOn(axios, 'get').mockResolvedValue({ + data: [ + { id: 4, name: 'Peter Parker' }, + { id: 5, name: 'Clark Kent' }, + { id: 6, name: 'Barry Allen' }, + ], + }); await vm.paginate(); expect(vm.store.skip).toEqual(6); @@ -85,11 +84,7 @@ describe('VnPaginate', () => { const index = 1; const done = vi.fn(); - vm.store.data = [ - { id: 1, name: 'Tony Stark' }, - { id: 2, name: 'Jessica Jones' }, - { id: 3, name: 'Bruce Wayne' }, - ]; + vm.store.data = defaultData; await vm.onLoad(index, done); @@ -105,11 +100,7 @@ describe('VnPaginate', () => { ], }); - vm.store.data = [ - { id: 1, name: 'Tony Stark' }, - { id: 2, name: 'Jessica Jones' }, - { id: 3, name: 'Bruce Wayne' }, - ]; + vm.store.data = defaultData; expect(vm.pagination.page).toEqual(1); From 1e76d5fd3fb45bba11060ea9ab0898e2fc4fa79d Mon Sep 17 00:00:00 2001 From: Jon Date: Mon, 16 Dec 2024 12:03:57 +0100 Subject: [PATCH 2/2] refactor: ignore params when searching by id on searchbar --- src/components/ui/VnSearchbar.vue | 19 +++++++++++++------ src/pages/Order/Card/OrderCatalog.vue | 3 ++- src/pages/Zone/Card/ZoneLocationsTree.vue | 8 +++++++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/components/ui/VnSearchbar.vue b/src/components/ui/VnSearchbar.vue index da2d370fe..92babfcc6 100644 --- a/src/components/ui/VnSearchbar.vue +++ b/src/components/ui/VnSearchbar.vue @@ -51,10 +51,6 @@ const props = defineProps({ type: Object, default: null, }, - staticParams: { - type: Array, - default: () => [], - }, exprBuilder: { type: Function, default: null, @@ -67,6 +63,10 @@ const props = defineProps({ type: Function, default: undefined, }, + searchRemoveParams: { + type: Boolean, + default: true, + }, }); const searchText = ref(); @@ -105,12 +105,18 @@ async function search() { const filter = { params: { - ...Object.fromEntries(staticParams), search: searchText.value, }, - ...{ filter: props.filter }, + filter: props.filter, }; + if (!props.searchRemoveParams || !searchText.value) { + filter.params = { + ...Object.fromEntries(staticParams), + search: searchText.value, + }; + } + if (props.whereFilter) { filter.filter = { where: props.whereFilter(searchText.value), @@ -130,6 +136,7 @@ async function search() { dense standout autofocus + data-cy="vnSearchBar" > - +