Skip to content

Commit 577cdff

Browse files
authored
Improve lists page performance (#1734)
1 parent 0f8e527 commit 577cdff

File tree

12 files changed

+924
-638
lines changed

12 files changed

+924
-638
lines changed

frontend/src/assets/scss/layout.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ hr {
7272
}
7373
}
7474

75+
.custom-spinner::before {
76+
@apply border-2 border-gray-100 border-b-gray-900 border-x-gray-900 rounded-full h-8 w-8 absolute;
77+
top: 10%;
78+
left: 10%;
79+
transform: translate3d(-50%, -50%, 0);
80+
content: "";
81+
}
82+
7583
.el-loading-spinner .path {
7684
stroke: #e94f2e;
7785
}

frontend/src/modules/activity/components/activity-list.vue

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
/>
1010
<div
1111
v-if="loading && !activities.length"
12-
v-loading="loading"
13-
class="app-page-spinner h-16 !relative !min-h-5"
14-
/>
12+
class="h-16 !relative !min-h-5 flex justify-center items-center"
13+
>
14+
<div class="animate-spin w-fit">
15+
<div class="custom-spinner" />
16+
</div>
17+
</div>
1518
<div v-else>
1619
<!-- Empty State -->
1720
<app-empty-state-cta

frontend/src/modules/conversation/components/conversation-list.vue

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
/>
1010
<div
1111
v-if="loading && !conversations.length"
12-
v-loading="loading"
13-
class="app-page-spinner h-16 !relative !min-h-5"
14-
/>
12+
class="h-16 !relative !min-h-5 flex justify-center items-center"
13+
>
14+
<div class="animate-spin w-fit">
15+
<div class="custom-spinner" />
16+
</div>
17+
</div>
1518
<div v-else>
1619
<!-- Empty state -->
1720
<app-empty-state-cta

frontend/src/modules/member/components/list/member-list-table.vue

Lines changed: 84 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
<div>
33
<div
44
v-if="loading"
5-
v-loading="loading"
6-
class="app-page-spinner h-16 !relative !min-h-5"
7-
/>
5+
class="h-16 !relative !min-h-5 flex justify-center items-center"
6+
>
7+
<div class="animate-spin w-fit">
8+
<div class="custom-spinner" />
9+
</div>
10+
</div>
811
<div v-else>
912
<!-- Empty State -->
1013
<app-empty-state-cta
@@ -408,10 +411,18 @@
408411
class="block w-full"
409412
>
410413
<div class="h-full flex items-center justify-center w-full">
411-
<app-member-dropdown
412-
:member="scope.row"
413-
@merge="isMergeDialogOpen = scope.row"
414-
/>
414+
<button
415+
:id="`buttonRef-${scope.row.id}`"
416+
:ref="(el) => setActionBtnsRef(el, scope.row.id)"
417+
class="el-dropdown-link btn p-1.5 rounder-md hover:bg-gray-200 text-gray-600"
418+
type="button"
419+
@click.prevent.stop="() => onActionBtnClick(scope.row)"
420+
>
421+
<i
422+
:id="`buttonRefIcon-${scope.row.id}`"
423+
class="text-xl ri-more-fill"
424+
/>
425+
</button>
415426
</div>
416427
</router-link>
417428
</template>
@@ -432,6 +443,25 @@
432443
</div>
433444
</div>
434445
</div>
446+
<el-popover
447+
ref="memberDropdownPopover"
448+
placement="bottom-end"
449+
popper-class="popover-dropdown"
450+
:virtual-ref="actionBtnRefs[selectedActionMember?.id]"
451+
trigger="click"
452+
:visible="showMemberDropdownPopover"
453+
virtual-triggering
454+
@hide="onHide"
455+
>
456+
<div v-click-outside="onClickOutside">
457+
<app-member-dropdown-content
458+
v-if="selectedActionMember"
459+
:member="selectedActionMember"
460+
@merge="isMergeDialogOpen = selectedActionMember"
461+
@close-dropdown="closeDropdown"
462+
/>
463+
</div>
464+
</el-popover>
435465
<app-member-merge-dialog v-model="isMergeDialogOpen" />
436466
<app-tag-popover v-model="isEditTagsDialogOpen" :member="editTagMember" @reload="fetchMembers({ reload: true })" />
437467
</div>
@@ -443,6 +473,7 @@ import { useRouter } from 'vue-router';
443473
import {
444474
computed, onMounted, onUnmounted, ref, defineProps, watch,
445475
} from 'vue';
476+
import { ClickOutside as vClickOutside } from 'element-plus';
446477
import { storeToRefs } from 'pinia';
447478
import { i18n } from '@/i18n';
448479
import AppMemberListToolbar from '@/modules/member/components/list/member-list-toolbar.vue';
@@ -456,7 +487,7 @@ import AppMemberMergeDialog from '@/modules/member/components/member-merge-dialo
456487
import AppTagPopover from '@/modules/tag/components/tag-popover.vue';
457488
import AppPagination from '@/shared/pagination/pagination.vue';
458489
import AppMemberBadge from '../member-badge.vue';
459-
import AppMemberDropdown from '../member-dropdown.vue';
490+
import AppMemberDropdownContent from '../member-dropdown-content.vue';
460491
import AppMemberIdentities from '../member-identities.vue';
461492
import AppMemberReach from '../member-reach.vue';
462493
import AppMemberEngagementLevel from '../member-engagement-level.vue';
@@ -477,6 +508,11 @@ const isMergeDialogOpen = ref(null);
477508
const isEditTagsDialogOpen = ref(false);
478509
const editTagMember = ref(null);
479510
511+
const showMemberDropdownPopover = ref(false);
512+
const memberDropdownPopover = ref(null);
513+
const actionBtnRefs = ref({});
514+
const selectedActionMember = ref(null);
515+
480516
const props = defineProps({
481517
hasIntegrations: {
482518
type: Boolean,
@@ -578,6 +614,39 @@ document.onmouseup = () => {
578614
isCursorDown.value = false;
579615
};
580616
617+
const setActionBtnsRef = (el, id) => {
618+
if (el) {
619+
actionBtnRefs.value[id] = el;
620+
}
621+
};
622+
623+
const onActionBtnClick = (member) => {
624+
if (selectedActionMember.value?.id === member.id) {
625+
showMemberDropdownPopover.value = false;
626+
627+
setTimeout(() => {
628+
selectedActionMember.value = null;
629+
}, 200);
630+
} else {
631+
showMemberDropdownPopover.value = true;
632+
selectedActionMember.value = member;
633+
}
634+
};
635+
636+
const closeDropdown = () => {
637+
showMemberDropdownPopover.value = false;
638+
639+
setTimeout(() => {
640+
selectedActionMember.value = null;
641+
}, 200);
642+
};
643+
644+
const onClickOutside = (el) => {
645+
if (!el.target?.id.includes('buttonRef')) {
646+
closeDropdown();
647+
}
648+
};
649+
581650
function handleEditTagsDialog(member) {
582651
isEditTagsDialogOpen.value = true;
583652
editTagMember.value = member;
@@ -695,9 +764,9 @@ const doExport = () => MemberService.export({
695764
offset: null,
696765
});
697766
698-
onMounted(async () => {
767+
onMounted(() => {
699768
if (store.state.integration.count === 0) {
700-
await store.dispatch('integration/doFetch');
769+
store.dispatch('integration/doFetch');
701770
}
702771
});
703772
@@ -746,4 +815,9 @@ export default {
746815
.el-table__body {
747816
height: 1px;
748817
}
818+
819+
.popover-dropdown {
820+
padding: 0.5rem !important;
821+
width: fit-content !important;
822+
}
749823
</style>

0 commit comments

Comments
 (0)