fix(sh-admin): resolve record retrieval limits in pending invites section by implementing pagination (#4624)
This commit is contained in:
parent
d9d656269c
commit
a3912d3ed2
3 changed files with 59 additions and 19 deletions
|
|
@ -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']
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue