diff --git a/backend/src/database/repositories/memberRepository.ts b/backend/src/database/repositories/memberRepository.ts index 38ae2e67dd..2a5e677185 100644 --- a/backend/src/database/repositories/memberRepository.ts +++ b/backend/src/database/repositories/memberRepository.ts @@ -410,6 +410,9 @@ class MemberRepository { return { count: await getTotalCount() } } + const pageLimit = args.limit + const queryLimit = pageLimit + 1 + const mems = await options.database.sequelize.query( ` SELECT @@ -452,7 +455,7 @@ class MemberRepository { { replacements: { segmentIds, - limit: args.limit, + limit: queryLimit, offset: args.offset, displayName: args?.filter?.displayName ? `${args.filter.displayName}%` : undefined, memberId: args?.filter?.memberId, @@ -463,7 +466,10 @@ class MemberRepository { }, ) - if (mems.length > 0) { + const hasMore = mems.length > pageLimit + const pageRows = hasMore ? mems.slice(0, pageLimit) : mems + + if (pageRows.length > 0) { let result if (args.detail) { @@ -522,7 +528,7 @@ class MemberRepository { } } - for (const mem of mems) { + for (const mem of pageRows) { memberPromises.push(findMemberInfo(mem.id)) toMergePromises.push(findMemberInfo(mem.toMergeId)) } @@ -532,10 +538,10 @@ class MemberRepository { result = memberResults.map((i, idx) => ({ members: [i, memberToMergeResults[idx]], - similarity: mems[idx].similarity, + similarity: pageRows[idx].similarity, })) } else { - result = mems.map((i) => ({ + result = pageRows.map((i) => ({ members: [ { id: i.id, @@ -554,12 +560,12 @@ class MemberRepository { })) } - return { rows: result, count: await getTotalCount(), limit: args.limit, offset: args.offset } + return { rows: result, hasMore, limit: args.limit, offset: args.offset } } return { rows: [{ members: [], similarity: 0 }], - count: await getTotalCount(), + hasMore: false, limit: args.limit, offset: args.offset, } diff --git a/backend/src/database/repositories/organizationRepository.ts b/backend/src/database/repositories/organizationRepository.ts index 916701ee22..add23f6a41 100644 --- a/backend/src/database/repositories/organizationRepository.ts +++ b/backend/src/database/repositories/organizationRepository.ts @@ -944,6 +944,9 @@ class OrganizationRepository { return { count: await getTotalCount() } } + const pageLimit = args.limit + const queryLimit = pageLimit + 1 + const orgs = await options.database.sequelize.query( ` SELECT @@ -990,7 +993,7 @@ class OrganizationRepository { { replacements: { segmentIds, - limit: args.limit, + limit: queryLimit, offset: args.offset, displayName: args?.filter?.displayName ? `${args.filter.displayName}%` : undefined, mergeActionType: MergeActionType.ORG, @@ -1001,14 +1004,17 @@ class OrganizationRepository { }, ) - if (orgs.length > 0) { + const hasMore = orgs.length > pageLimit + const pageRows = hasMore ? orgs.slice(0, pageLimit) : orgs + + if (pageRows.length > 0) { let result if (args.detail) { const organizationPromises = [] const toMergePromises = [] - for (const org of orgs) { + for (const org of pageRows) { organizationPromises.push( OrganizationRepository.findById(org.id, options, org.primarySegmentId), ) @@ -1022,10 +1028,10 @@ class OrganizationRepository { result = organizationResults.map((i, idx) => ({ organizations: [i, organizationToMergeResults[idx]], - similarity: orgs[idx].similarity, + similarity: pageRows[idx].similarity, })) } else { - result = orgs.map((o) => ({ + result = pageRows.map((o) => ({ organizations: [ { id: o.id, @@ -1055,7 +1061,7 @@ class OrganizationRepository { return { rows: result, - count: await getTotalCount(), + hasMore, limit: args.limit, offset: args.offset, } @@ -1063,7 +1069,7 @@ class OrganizationRepository { return { rows: [{ organizations: [], similarity: 0 }], - count: await getTotalCount(), + hasMore: false, limit: args.limit, offset: args.offset, } diff --git a/frontend/src/modules/data-quality/components/member/data-quality-member-merge-suggestions.vue b/frontend/src/modules/data-quality/components/member/data-quality-member-merge-suggestions.vue index b63d52486b..3f5ef85569 100644 --- a/frontend/src/modules/data-quality/components/member/data-quality-member-merge-suggestions.vue +++ b/frontend/src/modules/data-quality/components/member/data-quality-member-merge-suggestions.vue @@ -18,7 +18,7 @@ -
+
([]); const isModalOpen = ref(false); @@ -91,7 +91,7 @@ const loadMergeSuggestions = () => { segments: segments.value, }) .then((res) => { - total.value = +res.count; + hasMore.value = Boolean(res.hasMore); const rows = res.rows.filter((s: any) => s.similarity > 0); if (+res.offset > 0) { mergeSuggestions.value = [...mergeSuggestions.value, ...rows]; diff --git a/frontend/src/modules/data-quality/components/organization/data-quality-organization-merge-suggestions.vue b/frontend/src/modules/data-quality/components/organization/data-quality-organization-merge-suggestions.vue index 6e42332e16..0e1cfb9651 100644 --- a/frontend/src/modules/data-quality/components/organization/data-quality-organization-merge-suggestions.vue +++ b/frontend/src/modules/data-quality/components/organization/data-quality-organization-merge-suggestions.vue @@ -15,7 +15,7 @@ -
+
([]); const isModalOpen = ref(false); @@ -84,7 +84,7 @@ const loadMergeSuggestions = () => { orderBy: ['similarity_DESC', 'activityCount_DESC'], }) .then((res) => { - total.value = +res.count; + hasMore.value = Boolean(res.hasMore); const rows = res.rows.filter((s: any) => s.similarity > 0); if (+res.offset > 0) { mergeSuggestions.value = [...mergeSuggestions.value, ...rows]; diff --git a/frontend/src/modules/member/components/member-merge-suggestions.vue b/frontend/src/modules/member/components/member-merge-suggestions.vue index c337504fd4..6f80b0b6f4 100644 --- a/frontend/src/modules/member/components/member-merge-suggestions.vue +++ b/frontend/src/modules/member/components/member-merge-suggestions.vue @@ -7,7 +7,7 @@ @@ -16,7 +16,7 @@ @@ -26,16 +26,10 @@
-
{{ offset + 1 }} of {{ Math.ceil(count) }} suggestions
-
-
-
1 suggestion
+
Suggestion {{ offset + 1 }}
@@ -56,7 +50,7 @@ @@ -66,7 +60,7 @@
-
+
@@ -170,7 +164,8 @@ const { getContributorMergeActions } = useContributorStore(); const membersToMerge = ref([]); const primary = ref(0); const offset = ref(props.offset); -const count = ref(0); +const hasMore = ref(false); +const hasSuggestion = ref(false); const loading = ref(false); const sendingIgnore = ref(false); @@ -204,25 +199,45 @@ const preview = computed(() => { return mergedMembers; }); -const fetch = (page) => { +const updateSuggestionsState = (res) => { + hasMore.value = Boolean(res.hasMore); + const rows = res.rows.filter((suggestion) => suggestion.similarity > 0); + + if (rows.length > 0) { + hasSuggestion.value = true; + [membersToMerge.value] = rows; + } else { + hasSuggestion.value = false; + membersToMerge.value = []; + } +}; + +const fetch = (page, trackNavigation = true) => { if (page > -1) { offset.value = page; } - trackEvent({ - key: FeatureEventKey.NAVIGATE_MEMBERS_MERGE_SUGGESTIONS, - type: EventType.FEATURE, - }); + if (trackNavigation) { + trackEvent({ + key: FeatureEventKey.NAVIGATE_MEMBERS_MERGE_SUGGESTIONS, + type: EventType.FEATURE, + }); + } loading.value = true; - MemberService.fetchMergeSuggestions(1, offset.value, props.query ?? {}) + return MemberService.fetchMergeSuggestions(1, offset.value, props.query ?? {}) .then((res) => { offset.value = +res.offset; - count.value = res.count; - [membersToMerge.value] = res.rows; + + updateSuggestionsState(res); + + if (!hasSuggestion.value && offset.value > 0) { + return fetch(offset.value - 1, false); + } primary.value = 0; + return undefined; }) .catch(() => { ToastStore.error( @@ -252,8 +267,7 @@ const ignoreSuggestion = () => { .then(() => { ToastStore.success('Merging suggestion ignored successfully'); getContributorMergeActions(); - const nextIndex = offset.value >= (count.value - 1) ? Math.max(count.value - 2, 0) : offset.value; - fetch(nextIndex); + fetch(offset.value); changed.value = true; }) .catch((error) => { @@ -304,8 +318,7 @@ const mergeSuggestion = () => { ); primary.value = 0; - const nextIndex = offset.value >= (count.value - 1) ? Math.max(count.value - 2, 0) : offset.value; - fetch(nextIndex); + fetch(offset.value); changed.value = true; }) .catch((error) => { diff --git a/frontend/src/modules/member/pages/member-merge-suggestions-page.vue b/frontend/src/modules/member/pages/member-merge-suggestions-page.vue index b3c6f2a263..4f18c510fe 100644 --- a/frontend/src/modules/member/pages/member-merge-suggestions-page.vue +++ b/frontend/src/modules/member/pages/member-merge-suggestions-page.vue @@ -114,7 +114,7 @@

-
+
Load more @@ -158,7 +158,7 @@ const mergeSuggestions = ref([]); const isModalOpen = ref(false); -const total = ref(0); +const hasMore = ref(false); const limit = ref(10); const page = ref(1); const loading = ref(false); @@ -187,7 +187,7 @@ const loadMergeSuggestions = (sort: boolean = false) => { detail: false, }) .then((res) => { - total.value = +res.count; + hasMore.value = Boolean(res.hasMore); const rows = res.rows.filter((s: any) => s.similarity > 0); if (+res.offset > 0) { mergeSuggestions.value = [...mergeSuggestions.value, ...rows]; diff --git a/frontend/src/modules/organization/components/organization-merge-suggestions.vue b/frontend/src/modules/organization/components/organization-merge-suggestions.vue index 6581b5088e..0461dfef03 100644 --- a/frontend/src/modules/organization/components/organization-merge-suggestions.vue +++ b/frontend/src/modules/organization/components/organization-merge-suggestions.vue @@ -7,7 +7,7 @@ @@ -16,7 +16,7 @@ @@ -26,16 +26,10 @@
-
{{ currentOffset + 1 }} of {{ Math.ceil(count) }} suggestions
-
-
-
1 suggestion
+
Suggestion {{ currentOffset + 1 }}
@@ -56,7 +50,7 @@ @@ -66,7 +60,7 @@
-
+
@@ -175,7 +169,8 @@ const { trackEvent } = useProductTracking(); const organizationsToMerge = ref([]); const primary = ref(0); const currentOffset = ref(0); -const count = ref(0); +const hasMore = ref(false); +const hasSuggestion = ref(false); const loading = ref(false); const sendingIgnore = ref(false); @@ -211,25 +206,45 @@ const preview = computed(() => { return mergedOrganizations; }); -const fetch = (page) => { +const updateSuggestionsState = (res) => { + hasMore.value = Boolean(res.hasMore); + const rows = res.rows.filter((suggestion) => suggestion.similarity > 0); + + if (rows.length > 0) { + hasSuggestion.value = true; + [organizationsToMerge.value] = rows; + } else { + hasSuggestion.value = false; + organizationsToMerge.value = []; + } +}; + +const fetch = (page, trackNavigation = true) => { if (page > -1) { currentOffset.value = page; } - trackEvent({ - key: FeatureEventKey.NAVIGATE_ORGANIZATIONS_MERGE_SUGGESTIONS, - type: EventType.FEATURE, - }); + if (trackNavigation) { + trackEvent({ + key: FeatureEventKey.NAVIGATE_ORGANIZATIONS_MERGE_SUGGESTIONS, + type: EventType.FEATURE, + }); + } loading.value = true; - OrganizationService.fetchMergeSuggestions(1, currentOffset.value, props.query ?? {}) + return OrganizationService.fetchMergeSuggestions(1, currentOffset.value, props.query ?? {}) .then((res) => { currentOffset.value = +res.offset; - count.value = res.count; - [organizationsToMerge.value] = res.rows; + + updateSuggestionsState(res); + + if (!hasSuggestion.value && currentOffset.value > 0) { + return fetch(currentOffset.value - 1, false); + } primary.value = 0; + return undefined; }) .catch(() => { ToastStore.error( @@ -259,8 +274,7 @@ const ignoreSuggestion = () => { .then(() => { ToastStore.success('Merging suggestion ignored successfully'); - const nextIndex = currentOffset.value >= (count.value - 1) ? Math.max(count.value - 2, 0) : currentOffset.value; - fetch(nextIndex); + fetch(currentOffset.value); changed.value = true; }) .catch((error) => { @@ -307,8 +321,7 @@ const mergeSuggestion = () => { loadingMessage(); - const nextIndex = currentOffset.value >= (count.value - 1) ? Math.max(count.value - 2, 0) : currentOffset.value; - fetch(nextIndex); + fetch(currentOffset.value); changed.value = true; }) .catch((error) => { diff --git a/frontend/src/modules/organization/pages/organization-merge-suggestions-page.vue b/frontend/src/modules/organization/pages/organization-merge-suggestions-page.vue index 78f9504fe5..4ef0383ed3 100644 --- a/frontend/src/modules/organization/pages/organization-merge-suggestions-page.vue +++ b/frontend/src/modules/organization/pages/organization-merge-suggestions-page.vue @@ -160,7 +160,7 @@

-
+
Load more @@ -209,7 +209,7 @@ const mergeSuggestions = ref([]); const isModalOpen = ref(false); -const total = ref(0); +const hasMore = ref(false); const limit = ref(10); const page = ref(1); const loading = ref(false); @@ -238,7 +238,7 @@ const loadMergeSuggestions = (sort: boolean = false) => { detail: false, }) .then((res) => { - total.value = +res.count; + hasMore.value = Boolean(res.hasMore); const rows = res.rows.filter((s: any) => s.similarity > 0); if (+res.offset > 0) { mergeSuggestions.value = [...mergeSuggestions.value, ...rows];