fix(sh-admin): resolve record retrieval limits in pending invites section by implementing pagination (#4624)

This commit is contained in:
Joel Jacob Stephen 2024-12-19 11:18:14 -06:00 committed by GitHub
parent d9d656269c
commit a3912d3ed2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 59 additions and 19 deletions

View file

@ -45,6 +45,7 @@ declare module 'vue' {
SettingsAuthProvider: typeof import('./components/settings/AuthProvider.vue')['default'] SettingsAuthProvider: typeof import('./components/settings/AuthProvider.vue')['default']
SettingsConfigurations: typeof import('./components/settings/Configurations.vue')['default'] SettingsConfigurations: typeof import('./components/settings/Configurations.vue')['default']
SettingsDataSharing: typeof import('./components/settings/DataSharing.vue')['default'] SettingsDataSharing: typeof import('./components/settings/DataSharing.vue')['default']
SettingsHistoryConfiguration: typeof import('./components/settings/HistoryConfiguration.vue')['default']
SettingsReset: typeof import('./components/settings/Reset.vue')['default'] SettingsReset: typeof import('./components/settings/Reset.vue')['default']
SettingsServerRestart: typeof import('./components/settings/ServerRestart.vue')['default'] SettingsServerRestart: typeof import('./components/settings/ServerRestart.vue')['default']
SettingsSmtpConfiguration: typeof import('./components/settings/SmtpConfiguration.vue')['default'] SettingsSmtpConfiguration: typeof import('./components/settings/SmtpConfiguration.vue')['default']

View file

@ -1,6 +1,6 @@
query InvitedUsers { query InvitedUsers($skip: Int, $take: Int) {
infra { infra {
invitedUsers { invitedUsers(skip: $skip, take: $take) {
adminUid adminUid
adminEmail adminEmail
inviteeEmail inviteeEmail

View file

@ -87,6 +87,15 @@
</template> </template>
</HoppSmartTable> </HoppSmartTable>
<div
v-if="hasNextPage"
class="flex items-center w-28 px-3 py-2 mt-5 mx-auto font-semibold text-secondaryDark bg-divider hover:bg-dividerDark rounded-3xl cursor-pointer"
@click="fetchNextInvites"
>
<span>{{ t('users.show_more') }}</span>
<icon-lucide-chevron-down class="ml-2" />
</div>
<div <div
v-if="selectedRows.length" v-if="selectedRows.length"
class="fixed m-2 bottom-0 left-40 right-0 w-min mx-auto shadow-2xl" class="fixed m-2 bottom-0 left-40 right-0 w-min mx-auto shadow-2xl"
@ -124,13 +133,14 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useMutation, useQuery } from '@urql/vue'; import { useMutation } from '@urql/vue';
import { breakpointsTailwind, useBreakpoints } from '@vueuse/core'; import { breakpointsTailwind, useBreakpoints } from '@vueuse/core';
import { format } from 'date-fns'; import { format } from 'date-fns';
import { computed, ref } from 'vue'; import { computed, ref, watch } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { useI18n } from '~/composables/i18n'; import { useI18n } from '~/composables/i18n';
import { useToast } from '~/composables/toast'; import { useToast } from '~/composables/toast';
import { usePagedQuery } from '~/composables/usePagedQuery';
import { copyToClipboard } from '~/helpers/utils/clipboard'; import { copyToClipboard } from '~/helpers/utils/clipboard';
import IconTrash from '~icons/lucide/trash'; import IconTrash from '~icons/lucide/trash';
import { import {
@ -146,16 +156,13 @@ const router = useRouter();
const breakpoints = useBreakpoints(breakpointsTailwind); const breakpoints = useBreakpoints(breakpointsTailwind);
const lgAndLarger = breakpoints.greater('lg'); const lgAndLarger = breakpoints.greater('lg');
const invitesPerPage = 10;
const page = ref(1);
// Get Proper Date Formats // Get Proper Date Formats
const getCreatedDate = (date: string) => format(new Date(date), 'dd-MMMM-yyyy'); const getCreatedDate = (date: string) => format(new Date(date), 'dd-MMMM-yyyy');
const getCreatedTime = (date: string) => format(new Date(date), 'hh:mm a'); const getCreatedTime = (date: string) => format(new Date(date), 'hh:mm a');
// Get Invited Users
const { fetching, error, data } = useQuery({
query: InvitedUsersDocument,
variables: {},
});
// Table Headings // Table Headings
const headings = [ const headings = [
{ key: 'inviteeEmail', label: t('users.invitee_email') }, { key: 'inviteeEmail', label: t('users.invitee_email') },
@ -164,18 +171,50 @@ const headings = [
{ key: 'action', label: 'Action' }, { key: 'action', label: 'Action' },
]; ];
// Fetch Invites
const {
fetching,
error,
refetch,
list: invitesList,
} = usePagedQuery(
InvitedUsersDocument,
(x) => x.infra.invitedUsers,
invitesPerPage,
{ take: invitesPerPage, skip: (page.value - 1) * invitesPerPage }
);
const pendingInvites = ref<InvitedUsersQuery['infra']['invitedUsers']>([]);
// Populate pending invites
watch(
invitesList,
(newInvitesList) => {
if (!newInvitesList) return;
const newInvites = newInvitesList.filter(
(newInvite) =>
!pendingInvites.value.some(
(existingInvite) =>
existingInvite.inviteeEmail === newInvite.inviteeEmail
)
);
pendingInvites.value.push(...newInvites);
},
{ immediate: true, deep: true }
);
// Pagination
const hasNextPage = computed(() => invitesList.value.length === invitesPerPage);
const fetchNextInvites = () => {
page.value += 1;
refetch({ take: invitesPerPage, skip: (page.value - 1) * invitesPerPage });
};
// Selected Rows // Selected Rows
const selectedRows = ref<InvitedUsersQuery['infra']['invitedUsers']>([]); const selectedRows = ref<InvitedUsersQuery['infra']['invitedUsers']>([]);
// Invited Users
const pendingInvites = computed({
get: () => data.value?.infra.invitedUsers,
set: (value) => {
if (!value) return;
data.value!.infra.invitedUsers = value;
},
});
// Delete Invite // Delete Invite
const confirmDeletion = ref(false); const confirmDeletion = ref(false);
const inviteToBeDeleted = ref<string | null>(null); const inviteToBeDeleted = ref<string | null>(null);