From edc7c44d9f25cd347c175269f7d9bdb6f341c802 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 13 Jun 2024 21:26:32 +0000 Subject: [PATCH 1/5] fix: use custom cached debounce function to use individual debounce function for each filter --- .../nc-gui/composables/useDebounceFnCached.ts | 45 +++++++++++++++++++ packages/nc-gui/composables/useViewFilters.ts | 33 ++++++++------ 2 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 packages/nc-gui/composables/useDebounceFnCached.ts diff --git a/packages/nc-gui/composables/useDebounceFnCached.ts b/packages/nc-gui/composables/useDebounceFnCached.ts new file mode 100644 index 0000000000..31b101fa23 --- /dev/null +++ b/packages/nc-gui/composables/useDebounceFnCached.ts @@ -0,0 +1,45 @@ +import type { DebounceFilterOptions, MaybeRefOrGetter } from '@vueuse/core' + +type FunctionArgs = (...args: any[]) => any + +// Cache to store debounced functions based on a unique key +const debounceCache = new Map() + +// Default function to generate a cache key +function defaultGetCacheKey(): string { + return 'default' +} + +/** + * Creates a cached debounced version of the given function. + * + * @param fn - The function to debounce. + * @param ms - The debounce delay in milliseconds. Default is 500ms. + * @param getCacheKey - Function to generate a unique cache key based on the arguments. + * @param options - Additional options for debouncing. + * + * @returns A debounced version of the input function with caching. + */ +export function useCachedDebouncedFunction( + fn: T, + ms: MaybeRefOrGetter = 500, + getCacheKey: (...args: Parameters) => string | number = defaultGetCacheKey, + options: DebounceFilterOptions = {}, +): (...args: Parameters) => ReturnType { + return function (...args: Parameters): ReturnType { + // Generate a unique key for the given arguments + const key = getCacheKey(args) + + // If the debounced function for the given key is not in the cache, create and cache it + if (!debounceCache.has(key)) { + const debouncedFn = useDebounceFn(fn, ms, options) + debounceCache.set(key, debouncedFn) + } + + // Retrieve the cached debounced function + const debouncedFn = debounceCache.get(key) + + // Call and return the result of the debounced function + return debouncedFn!(...args) + } +} diff --git a/packages/nc-gui/composables/useViewFilters.ts b/packages/nc-gui/composables/useViewFilters.ts index dca8d9b391..681bb12bad 100644 --- a/packages/nc-gui/composables/useViewFilters.ts +++ b/packages/nc-gui/composables/useViewFilters.ts @@ -338,7 +338,9 @@ export function useViewFilters( } } - const saveOrUpdate = async (filter: Filter, i: number, force = false, undo = false, skipDataReload = false) => { + const saveOrUpdateDebounced = useCachedDebouncedFunction(saveOrUpdate, 500, (_filter: Filter, i: number) => i) + + async function saveOrUpdate(filter: Filter, i: number, force = false, undo = false, skipDataReload = false) { // if already in progress the debounced function which will call this function again with 500ms delay until it's not saving if (savingStatus[i]) { return saveOrUpdateDebounced(filter, i, force, undo, skipDataReload) @@ -386,7 +388,7 @@ export function useViewFilters( filters.value = [...filters.value] } else if (!autoApply?.value && !force) { filter.status = filter.id ? 'update' : 'create' - } else if (filters.value[i]?.id && filter.status !== 'create') { + } else if (filters.value[i]?.id && filters.value[i]?.status !== 'create') { await $api.dbTableFilter.update(filters.value[i].id!, { ...filter, fk_parent_id: parentId.value, @@ -399,15 +401,23 @@ export function useViewFilters( }) } else { if (linkColId?.value) { - filters.value[i] = await $api.dbTableLinkFilter.create(linkColId.value, { - ...filter, - fk_parent_id: parentId, - }) + // set value with current value of filter since user can change value while saving + filters.value[i] = { + ...((await $api.dbTableLinkFilter.create(linkColId.value, { + ...filter, + fk_parent_id: parentId, + })) || {}), + value: (filters.value[i] || filter).value, + } } else { - filters.value[i] = await $api.dbTableFilter.create(view.value.id!, { - ...filter, - fk_parent_id: parentId.value, - }) + // set value with current value of filter since user can change value while saving + filters.value[i] = { + ...((await $api.dbTableFilter.create(view.value.id!, { + ...filter, + fk_parent_id: parentId.value, + })) || {}), + value: (filters.value[i] || filter).value, + } } if (!isLink && !isWebhook) allFilters.value.push(filters.value[+i]) } @@ -496,9 +506,6 @@ export function useViewFilters( if (!isLink && !isWebhook) allFilters.value = allFilters.value.filter((f) => f.id !== filter.id) } } - - const saveOrUpdateDebounced = useDebounceFn(saveOrUpdate, 500) - const addFilter = async (undo = false, draftFilter: Partial = {}) => { filters.value.push(draftFilter?.fk_column_id ? { ...placeholderFilter(), ...draftFilter } : placeholderFilter()) if (!undo) { From a2b81dc73c1423889e918e6600cc75762d035799 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 13 Jun 2024 21:26:32 +0000 Subject: [PATCH 2/5] fix: keep any local state value of filter after sync --- packages/nc-gui/composables/useViewFilters.ts | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/packages/nc-gui/composables/useViewFilters.ts b/packages/nc-gui/composables/useViewFilters.ts index 681bb12bad..b22f42b26d 100644 --- a/packages/nc-gui/composables/useViewFilters.ts +++ b/packages/nc-gui/composables/useViewFilters.ts @@ -401,22 +401,26 @@ export function useViewFilters( }) } else { if (linkColId?.value) { - // set value with current value of filter since user can change value while saving + const savedFilter = await $api.dbTableLinkFilter.create(linkColId.value, { + ...filter, + fk_parent_id: parentId, + }) + // override any local changes with saved filter since user can change value while saving filters.value[i] = { - ...((await $api.dbTableLinkFilter.create(linkColId.value, { - ...filter, - fk_parent_id: parentId, - })) || {}), - value: (filters.value[i] || filter).value, + ...(savedFilter || {}), + ...filters.value[i], + status: undefined, } } else { - // set value with current value of filter since user can change value while saving + const savedFilter = await $api.dbTableFilter.create(view.value.id!, { + ...filter, + fk_parent_id: parentId.value, + }) + // override any local changes with saved filter since user can change value while saving filters.value[i] = { - ...((await $api.dbTableFilter.create(view.value.id!, { - ...filter, - fk_parent_id: parentId.value, - })) || {}), - value: (filters.value[i] || filter).value, + ...(savedFilter || {}), + ...filters.value[i], + status: undefined, } } if (!isLink && !isWebhook) allFilters.value.push(filters.value[+i]) From 8dbda1cb99a94d6308033752677a1e1f5d3b8a0e Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 13 Jun 2024 21:26:33 +0000 Subject: [PATCH 3/5] fix: move cache reference within clossure since each instance should have its own cache --- packages/nc-gui/composables/useDebounceFnCached.ts | 6 +++--- packages/nc-gui/composables/useViewFilters.ts | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/nc-gui/composables/useDebounceFnCached.ts b/packages/nc-gui/composables/useDebounceFnCached.ts index 31b101fa23..d01c1aab5e 100644 --- a/packages/nc-gui/composables/useDebounceFnCached.ts +++ b/packages/nc-gui/composables/useDebounceFnCached.ts @@ -2,9 +2,6 @@ import type { DebounceFilterOptions, MaybeRefOrGetter } from '@vueuse/core' type FunctionArgs = (...args: any[]) => any -// Cache to store debounced functions based on a unique key -const debounceCache = new Map() - // Default function to generate a cache key function defaultGetCacheKey(): string { return 'default' @@ -26,6 +23,9 @@ export function useCachedDebouncedFunction( getCacheKey: (...args: Parameters) => string | number = defaultGetCacheKey, options: DebounceFilterOptions = {}, ): (...args: Parameters) => ReturnType { + // Cache to store debounced functions based on a unique key + const debounceCache = new Map() + return function (...args: Parameters): ReturnType { // Generate a unique key for the given arguments const key = getCacheKey(args) diff --git a/packages/nc-gui/composables/useViewFilters.ts b/packages/nc-gui/composables/useViewFilters.ts index b22f42b26d..ecd59224a2 100644 --- a/packages/nc-gui/composables/useViewFilters.ts +++ b/packages/nc-gui/composables/useViewFilters.ts @@ -381,7 +381,6 @@ export function useViewFilters( } } } - try { if (nestedMode.value) { filters.value[i] = { ...filter } @@ -407,19 +406,22 @@ export function useViewFilters( }) // override any local changes with saved filter since user can change value while saving filters.value[i] = { - ...(savedFilter || {}), ...filters.value[i], + fk_parent_id: parentId, + id: savedFilter.id, status: undefined, } } else { + console.log(parentId.value) const savedFilter = await $api.dbTableFilter.create(view.value.id!, { ...filter, fk_parent_id: parentId.value, }) // override any local changes with saved filter since user can change value while saving filters.value[i] = { - ...(savedFilter || {}), ...filters.value[i], + fk_parent_id: parentId, + id: savedFilter.id, status: undefined, } } From 78614619778a68602aaf7f660cdfb8dd03d15177 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 13 Jun 2024 21:26:33 +0000 Subject: [PATCH 4/5] fix: coderabbit suggestion and passing args correctly --- packages/nc-gui/composables/useDebounceFnCached.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nc-gui/composables/useDebounceFnCached.ts b/packages/nc-gui/composables/useDebounceFnCached.ts index d01c1aab5e..20137331bf 100644 --- a/packages/nc-gui/composables/useDebounceFnCached.ts +++ b/packages/nc-gui/composables/useDebounceFnCached.ts @@ -26,9 +26,9 @@ export function useCachedDebouncedFunction( // Cache to store debounced functions based on a unique key const debounceCache = new Map() - return function (...args: Parameters): ReturnType { + return (...args: Parameters): ReturnType => { // Generate a unique key for the given arguments - const key = getCacheKey(args) + const key = getCacheKey(...args) // If the debounced function for the given key is not in the cache, create and cache it if (!debounceCache.has(key)) { From 9c3dfe9ea24f700f648d27d749110980f2ec79b6 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 13 Jun 2024 21:26:33 +0000 Subject: [PATCH 5/5] refactor: review suggestions --- packages/nc-gui/composables/useViewFilters.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/nc-gui/composables/useViewFilters.ts b/packages/nc-gui/composables/useViewFilters.ts index ecd59224a2..51e905bd01 100644 --- a/packages/nc-gui/composables/useViewFilters.ts +++ b/packages/nc-gui/composables/useViewFilters.ts @@ -404,7 +404,8 @@ export function useViewFilters( ...filter, fk_parent_id: parentId, }) - // override any local changes with saved filter since user can change value while saving + // extract id from saved filter and update the filter object + // avoiding whole object update to prevent overwriting of current filter object changes filters.value[i] = { ...filters.value[i], fk_parent_id: parentId, @@ -417,7 +418,8 @@ export function useViewFilters( ...filter, fk_parent_id: parentId.value, }) - // override any local changes with saved filter since user can change value while saving + // extract id from saved filter and update the filter object + // avoiding whole object update to prevent overwriting of current filter object changes filters.value[i] = { ...filters.value[i], fk_parent_id: parentId,