Fix: Change server settings and discussion page to usePaginatedQuery (#2527)
This commit is contained in:
Родитель
46314bcc71
Коммит
1462c7aadd
|
@ -3,29 +3,23 @@
|
|||
<template v-if="hasItems">
|
||||
<ProjectPageLatestItemsCommentsGrid
|
||||
v-if="gridOrList === GridListToggleValue.Grid"
|
||||
:threads="extraPagesResult"
|
||||
/>
|
||||
<ProjectPageLatestItemsCommentsList v-else :threads="extraPagesResult" />
|
||||
<InfiniteLoading
|
||||
:settings="{ identifier: infiniteLoaderId }"
|
||||
@infinite="infiniteLoad"
|
||||
:threads="result"
|
||||
/>
|
||||
<ProjectPageLatestItemsCommentsList v-else :threads="result" />
|
||||
<InfiniteLoading :settings="{ identifier }" @infinite="onInfiniteLoad" />
|
||||
</template>
|
||||
|
||||
<div v-else class="mt-8">
|
||||
<ProjectPageLatestItemsCommentsEmptyState />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { graphql } from '~~/lib/common/generated/gql'
|
||||
import type {
|
||||
ProjectCommentsFilter,
|
||||
ProjectDiscussionsPageResults_ProjectFragment
|
||||
} from '~~/lib/common/generated/gql/graphql'
|
||||
import type { InfiniteLoaderState } from '~~/lib/global/helpers/components'
|
||||
import type { ProjectDiscussionsPageResults_ProjectFragment } from '~~/lib/common/generated/gql/graphql'
|
||||
import { GridListToggleValue } from '~~/lib/layout/helpers/components'
|
||||
import { latestCommentThreadsQuery } from '~~/lib/projects/graphql/queries'
|
||||
import { usePaginatedQuery } from '~/lib/common/composables/graphql'
|
||||
|
||||
graphql(`
|
||||
fragment ProjectDiscussionsPageResults_Project on Project {
|
||||
|
@ -39,61 +33,28 @@ const props = defineProps<{
|
|||
includeArchived: boolean
|
||||
}>()
|
||||
|
||||
const logger = useLogger()
|
||||
|
||||
const queryFilterVariables = computed(
|
||||
(): ProjectCommentsFilter => ({
|
||||
includeArchived: !!props.includeArchived
|
||||
})
|
||||
)
|
||||
|
||||
const infiniteLoaderId = ref('')
|
||||
const {
|
||||
result: extraPagesResult,
|
||||
fetchMore: fetchMorePages,
|
||||
variables: resultVariables,
|
||||
onResult
|
||||
} = useQuery(latestCommentThreadsQuery, () => ({
|
||||
projectId: props.project.id,
|
||||
filter: queryFilterVariables.value
|
||||
}))
|
||||
identifier,
|
||||
onInfiniteLoad,
|
||||
query: { result }
|
||||
} = usePaginatedQuery({
|
||||
query: latestCommentThreadsQuery,
|
||||
baseVariables: computed(() => ({
|
||||
projectId: props.project.id,
|
||||
filter: { includeArchived: !!props.includeArchived }
|
||||
})),
|
||||
resolveKey: (vars) => {
|
||||
return { projectId: vars.projectId, ...vars.filter }
|
||||
},
|
||||
resolveCurrentResult: (res) => res?.project.commentThreads,
|
||||
resolveNextPageVariables: (baseVars, cursor) => ({
|
||||
...baseVars,
|
||||
cursor
|
||||
}),
|
||||
resolveCursorFromVariables: (vars) => vars.cursor
|
||||
})
|
||||
|
||||
const hasItems = computed(
|
||||
() => !!(extraPagesResult.value?.project?.commentThreads.items || []).length
|
||||
() => !!(result.value?.project?.commentThreads.items || []).length
|
||||
)
|
||||
|
||||
const moreToLoad = computed(
|
||||
() =>
|
||||
!extraPagesResult.value?.project ||
|
||||
extraPagesResult.value.project.commentThreads.items.length <
|
||||
extraPagesResult.value.project.commentThreads.totalCount
|
||||
)
|
||||
|
||||
const infiniteLoad = async (state: InfiniteLoaderState) => {
|
||||
const cursor = extraPagesResult.value?.project?.commentThreads.cursor || null
|
||||
if (!moreToLoad.value || !cursor) return state.complete()
|
||||
|
||||
try {
|
||||
await fetchMorePages({
|
||||
variables: {
|
||||
cursor
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
logger.error(e)
|
||||
state.error()
|
||||
return
|
||||
}
|
||||
|
||||
state.loaded()
|
||||
if (!moreToLoad.value) {
|
||||
state.complete()
|
||||
}
|
||||
}
|
||||
|
||||
const calculateLoaderId = () => {
|
||||
infiniteLoaderId.value = JSON.stringify(resultVariables.value?.filter || {})
|
||||
}
|
||||
|
||||
onResult(calculateLoaderId)
|
||||
</script>
|
||||
|
|
|
@ -77,19 +77,16 @@
|
|||
</template>
|
||||
</LayoutTable>
|
||||
|
||||
<CommonLoadingBar v-if="loading && !users?.length" loading />
|
||||
|
||||
<InfiniteLoading
|
||||
v-if="users?.length"
|
||||
:settings="{ identifier: infiniteLoaderId }"
|
||||
class="-mt-24 -mb-24"
|
||||
@infinite="infiniteLoad"
|
||||
:settings="{ identifier }"
|
||||
class="py-4"
|
||||
@infinite="onInfiniteLoad"
|
||||
/>
|
||||
|
||||
<SettingsServerUserDeleteDialog
|
||||
v-model:open="showUserDeleteDialog"
|
||||
:user="userToModify"
|
||||
:result-variables="resultVariables"
|
||||
/>
|
||||
|
||||
<SettingsServerUserChangeRoleDialog
|
||||
|
@ -106,10 +103,7 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { isArray } from 'lodash-es'
|
||||
import { useLogger } from '~~/composables/logging'
|
||||
import type { InfiniteLoaderState } from '~~/lib/global/helpers/components'
|
||||
import type { Nullable, ServerRoles, Optional } from '@speckle/shared'
|
||||
import { getUsersQuery } from '~~/lib/server-management/graphql/queries'
|
||||
import type { ItemType, UserItem } from '~~/lib/server-management/helpers/types'
|
||||
|
@ -124,45 +118,39 @@ import {
|
|||
} from '@heroicons/vue/24/outline'
|
||||
import { useServerInfo } from '~~/lib/core/composables/server'
|
||||
import { useDebouncedTextInput } from '@speckle/ui-components'
|
||||
import { usePaginatedQuery } from '~/lib/common/composables/graphql'
|
||||
|
||||
const search = defineModel<string>('search')
|
||||
|
||||
const logger = useLogger()
|
||||
const { activeUser } = useActiveUser()
|
||||
const { isGuestMode } = useServerInfo()
|
||||
const { on, bind } = useDebouncedTextInput({ model: search })
|
||||
const { on, bind, value: search } = useDebouncedTextInput()
|
||||
|
||||
const userToModify: Ref<Nullable<UserItem>> = ref(null)
|
||||
|
||||
const showUserDeleteDialog = ref(false)
|
||||
const showChangeUserRoleDialog = ref(false)
|
||||
const newRole = ref<ServerRoles>()
|
||||
const infiniteLoaderId = ref('')
|
||||
const showInviteDialog = ref(false)
|
||||
|
||||
const queryVariables = computed(() => ({
|
||||
limit: 50,
|
||||
query: search.value
|
||||
}))
|
||||
|
||||
const {
|
||||
result: extraPagesResult,
|
||||
fetchMore: fetchMorePages,
|
||||
variables: resultVariables,
|
||||
onResult,
|
||||
loading
|
||||
} = useQuery(getUsersQuery, queryVariables)
|
||||
identifier,
|
||||
onInfiniteLoad,
|
||||
query: { result }
|
||||
} = usePaginatedQuery({
|
||||
query: getUsersQuery,
|
||||
baseVariables: computed(() => ({
|
||||
query: search.value?.length ? search.value : null,
|
||||
limit: 50
|
||||
})),
|
||||
resolveKey: (vars) => [vars.query || ''],
|
||||
resolveCurrentResult: (res) => res?.admin.userList,
|
||||
resolveNextPageVariables: (baseVars, cursor) => ({
|
||||
...baseVars,
|
||||
cursor
|
||||
}),
|
||||
resolveCursorFromVariables: (vars) => vars.cursor
|
||||
})
|
||||
|
||||
const oldRole = computed(() => userToModify.value?.role as Optional<ServerRoles>)
|
||||
|
||||
const moreToLoad = computed(
|
||||
() =>
|
||||
!extraPagesResult.value?.admin?.userList ||
|
||||
extraPagesResult.value.admin.userList.items.length <
|
||||
extraPagesResult.value.admin.userList.totalCount
|
||||
)
|
||||
|
||||
const users = computed(() => extraPagesResult.value?.admin.userList.items || [])
|
||||
const users = computed(() => result.value?.admin.userList.items || [])
|
||||
|
||||
const isCurrentUser = (userItem: UserItem) => {
|
||||
return userItem.id === activeUser.value?.id
|
||||
|
@ -184,35 +172,7 @@ const openChangeUserRoleDialog = (user: UserItem, newRoleValue: ServerRoles) =>
|
|||
showChangeUserRoleDialog.value = true
|
||||
}
|
||||
|
||||
const infiniteLoad = async (state: InfiniteLoaderState) => {
|
||||
const cursor = extraPagesResult.value?.admin?.userList.cursor || null
|
||||
if (!moreToLoad.value || !cursor) return state.complete()
|
||||
|
||||
try {
|
||||
await fetchMorePages({
|
||||
variables: {
|
||||
cursor
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
logger.error(e)
|
||||
state.error()
|
||||
return
|
||||
}
|
||||
|
||||
state.loaded()
|
||||
if (!moreToLoad.value) {
|
||||
state.complete()
|
||||
}
|
||||
}
|
||||
|
||||
const calculateLoaderId = () => {
|
||||
infiniteLoaderId.value = resultVariables.value?.query || ''
|
||||
}
|
||||
|
||||
const toggleInviteDialog = () => {
|
||||
showInviteDialog.value = true
|
||||
}
|
||||
|
||||
onResult(calculateLoaderId)
|
||||
</script>
|
||||
|
|
|
@ -5,19 +5,21 @@
|
|||
title="Pending invitations"
|
||||
text="And overview of all your pending invititations"
|
||||
/>
|
||||
<div class="flex flex-col-reverse md:flex-row">
|
||||
<FormTextInput
|
||||
name="search"
|
||||
:custom-icon="MagnifyingGlassIcon"
|
||||
color="foundation"
|
||||
full-width
|
||||
search
|
||||
:show-clear="!!search"
|
||||
placeholder="Search invitations"
|
||||
class="rounded-md border border-outline-3 md:max-w-md mt-6 md:mt-0"
|
||||
:model-value="bind.modelValue.value"
|
||||
v-on="on"
|
||||
/>
|
||||
<div class="flex flex-col-reverse md:justify-between md:flex-row md:gap-x-4">
|
||||
<div class="relative w-full md:max-w-md mt-6 md:mt-0">
|
||||
<FormTextInput
|
||||
name="search"
|
||||
:custom-icon="MagnifyingGlassIcon"
|
||||
color="foundation"
|
||||
full-width
|
||||
search
|
||||
:show-clear="!!search"
|
||||
placeholder="Search invitations"
|
||||
class="rounded-md border border-outline-3"
|
||||
:model-value="bind.modelValue.value"
|
||||
v-on="on"
|
||||
/>
|
||||
</div>
|
||||
<FormButton :icon-left="UserPlusIcon" @click="toggleInviteDialog">
|
||||
Invite
|
||||
</FormButton>
|
||||
|
@ -71,17 +73,15 @@
|
|||
<SettingsServerPendingInvitationsDeleteDialog
|
||||
v-model:open="showDeleteInvitationDialog"
|
||||
:invite="inviteToModify"
|
||||
:result-variables="resultVariables"
|
||||
/>
|
||||
|
||||
<CommonLoadingBar v-if="loading && !invites?.length" loading />
|
||||
|
||||
<InfiniteLoading
|
||||
v-if="invites?.length"
|
||||
:settings="{ identifier: infiniteLoaderId }"
|
||||
:settings="{ identifier }"
|
||||
class="py-4"
|
||||
@infinite="infiniteLoad"
|
||||
@infinite="onInfiniteLoad"
|
||||
/>
|
||||
|
||||
<SettingsServerUserInviteDialog v-model:open="showInviteDialog" />
|
||||
</div>
|
||||
</section>
|
||||
|
@ -89,11 +89,9 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { useQuery, useMutation } from '@vue/apollo-composable'
|
||||
import { useMutation } from '@vue/apollo-composable'
|
||||
import { MagnifyingGlassIcon, TrashIcon, UserPlusIcon } from '@heroicons/vue/24/outline'
|
||||
import type { ItemType, InviteItem } from '~~/lib/server-management/helpers/types'
|
||||
import type { InfiniteLoaderState } from '~~/lib/global/helpers/components'
|
||||
import { getInvitesQuery } from '~~/lib/server-management/graphql/queries'
|
||||
import { adminResendInviteMutation } from '~~/lib/server-management/graphql/mutations'
|
||||
import { isInvite } from '~~/lib/server-management/helpers/utils'
|
||||
import { useGlobalToast, ToastNotificationType } from '~~/lib/common/composables/toast'
|
||||
|
@ -102,39 +100,38 @@ import {
|
|||
getFirstErrorMessage
|
||||
} from '~~/lib/common/helpers/graphql'
|
||||
import { useDebouncedTextInput } from '@speckle/ui-components'
|
||||
import { usePaginatedQuery } from '~/lib/common/composables/graphql'
|
||||
import { getInvitesQuery } from '~~/lib/server-management/graphql/queries'
|
||||
|
||||
const search = defineModel<string>('search')
|
||||
|
||||
const logger = useLogger()
|
||||
const { triggerNotification } = useGlobalToast()
|
||||
const { mutate: resendInvitationMutation } = useMutation(adminResendInviteMutation)
|
||||
const { on, bind } = useDebouncedTextInput({ model: search })
|
||||
const { on, bind, value: search } = useDebouncedTextInput()
|
||||
|
||||
const inviteToModify = ref<InviteItem | null>(null)
|
||||
const showDeleteInvitationDialog = ref(false)
|
||||
const infiniteLoaderId = ref('')
|
||||
const successfullyResentInvites = ref<string[]>([])
|
||||
const showInviteDialog = ref(false)
|
||||
|
||||
const {
|
||||
result: extraPagesResult,
|
||||
fetchMore: fetchMorePages,
|
||||
variables: resultVariables,
|
||||
onResult,
|
||||
loading
|
||||
} = useQuery(getInvitesQuery, () => ({
|
||||
limit: 50,
|
||||
query: search.value
|
||||
}))
|
||||
identifier,
|
||||
onInfiniteLoad,
|
||||
query: { result }
|
||||
} = usePaginatedQuery({
|
||||
query: getInvitesQuery,
|
||||
baseVariables: computed(() => ({
|
||||
query: search.value?.length ? search.value : null,
|
||||
limit: 50
|
||||
})),
|
||||
resolveKey: (vars) => [vars.query || ''],
|
||||
resolveCurrentResult: (res) => res?.admin.inviteList,
|
||||
resolveNextPageVariables: (baseVars, cursor) => ({
|
||||
...baseVars,
|
||||
cursor
|
||||
}),
|
||||
resolveCursorFromVariables: (vars) => vars.cursor
|
||||
})
|
||||
|
||||
const moreToLoad = computed(
|
||||
() =>
|
||||
!extraPagesResult.value?.admin?.inviteList ||
|
||||
extraPagesResult.value.admin.inviteList.items.length <
|
||||
extraPagesResult.value.admin.inviteList.totalCount
|
||||
)
|
||||
|
||||
const invites = computed(() => extraPagesResult.value?.admin.inviteList.items || [])
|
||||
const invites = computed(() => result.value?.admin.inviteList.items || [])
|
||||
|
||||
const openDeleteInvitationDialog = (item: ItemType) => {
|
||||
if (isInvite(item)) {
|
||||
|
@ -168,35 +165,7 @@ const resendInvitation = async (item: InviteItem) => {
|
|||
}
|
||||
}
|
||||
|
||||
const infiniteLoad = async (state: InfiniteLoaderState) => {
|
||||
const cursor = extraPagesResult.value?.admin?.inviteList.cursor || null
|
||||
if (!moreToLoad.value || !cursor) return state.complete()
|
||||
|
||||
try {
|
||||
await fetchMorePages({
|
||||
variables: {
|
||||
cursor
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
logger.error(e)
|
||||
state.error()
|
||||
return
|
||||
}
|
||||
|
||||
state.loaded()
|
||||
if (!moreToLoad.value) {
|
||||
state.complete()
|
||||
}
|
||||
}
|
||||
|
||||
const calculateLoaderId = () => {
|
||||
infiniteLoaderId.value = resultVariables.value?.query || ''
|
||||
}
|
||||
|
||||
const toggleInviteDialog = () => {
|
||||
showInviteDialog.value = true
|
||||
}
|
||||
|
||||
onResult(calculateLoaderId)
|
||||
</script>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
search
|
||||
:show-clear="!!search"
|
||||
placeholder="Search projects"
|
||||
class="rounded-md border border-outline-3 md:max-w-md mt-6 md:mt-0"
|
||||
class="rounded-md border border-outline-3"
|
||||
:model-value="bind.modelValue.value"
|
||||
v-on="on"
|
||||
/>
|
||||
|
@ -83,20 +83,17 @@
|
|||
</template>
|
||||
</LayoutTable>
|
||||
|
||||
<CommonLoadingBar v-if="loading && !projects?.length" loading />
|
||||
|
||||
<InfiniteLoading
|
||||
v-if="projects?.length"
|
||||
:settings="{ identifier: infiniteLoaderId }"
|
||||
:settings="{ identifier }"
|
||||
class="py-4"
|
||||
@infinite="infiniteLoad"
|
||||
@infinite="onInfiniteLoad"
|
||||
/>
|
||||
|
||||
<SettingsServerProjectDeleteDialog
|
||||
v-model:open="showProjectDeleteDialog"
|
||||
:project="projectToModify"
|
||||
title="Delete project"
|
||||
:result-variables="resultVariables"
|
||||
/>
|
||||
|
||||
<ProjectsAddDialog v-model:open="openNewProject" />
|
||||
|
@ -106,44 +103,40 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { useQuery } from '@vue/apollo-composable'
|
||||
import { MagnifyingGlassIcon, TrashIcon, PlusIcon } from '@heroicons/vue/24/outline'
|
||||
import { getProjectsQuery } from '~~/lib/server-management/graphql/queries'
|
||||
import type { ItemType, ProjectItem } from '~~/lib/server-management/helpers/types'
|
||||
import type { InfiniteLoaderState } from '~~/lib/global/helpers/components'
|
||||
import { isProject } from '~~/lib/server-management/helpers/utils'
|
||||
import { useDebouncedTextInput } from '@speckle/ui-components'
|
||||
import { usePaginatedQuery } from '~/lib/common/composables/graphql'
|
||||
|
||||
const search = defineModel<string>('search')
|
||||
|
||||
const { on, bind } = useDebouncedTextInput({ model: search })
|
||||
const logger = useLogger()
|
||||
const { on, bind, value: search } = useDebouncedTextInput()
|
||||
const router = useRouter()
|
||||
|
||||
const projectToModify = ref<ProjectItem | null>(null)
|
||||
const showProjectDeleteDialog = ref(false)
|
||||
const infiniteLoaderId = ref('')
|
||||
const openNewProject = ref(false)
|
||||
|
||||
const {
|
||||
result: extraPagesResult,
|
||||
fetchMore: fetchMorePages,
|
||||
variables: resultVariables,
|
||||
onResult,
|
||||
loading
|
||||
} = useQuery(getProjectsQuery, () => ({
|
||||
limit: 50,
|
||||
query: search.value
|
||||
}))
|
||||
identifier,
|
||||
onInfiniteLoad,
|
||||
query: { result }
|
||||
} = usePaginatedQuery({
|
||||
query: getProjectsQuery,
|
||||
baseVariables: computed(() => ({
|
||||
query: search.value?.length ? search.value : null,
|
||||
limit: 50
|
||||
})),
|
||||
resolveKey: (vars) => [vars.query || ''],
|
||||
resolveCurrentResult: (res) => res?.admin.projectList,
|
||||
resolveNextPageVariables: (baseVars, cursor) => ({
|
||||
...baseVars,
|
||||
cursor
|
||||
}),
|
||||
resolveCursorFromVariables: (vars) => vars.cursor
|
||||
})
|
||||
|
||||
const moreToLoad = computed(
|
||||
() =>
|
||||
!extraPagesResult.value?.admin?.projectList ||
|
||||
extraPagesResult.value.admin.projectList.items.length <
|
||||
extraPagesResult.value.admin.projectList.totalCount
|
||||
)
|
||||
|
||||
const projects = computed(() => extraPagesResult.value?.admin.projectList.items || [])
|
||||
const projects = computed(() => result.value?.admin.projectList.items || [])
|
||||
|
||||
const openProjectDeleteDialog = (item: ItemType) => {
|
||||
if (isProject(item)) {
|
||||
|
@ -155,32 +148,4 @@ const openProjectDeleteDialog = (item: ItemType) => {
|
|||
const handleProjectClick = (item: ItemType) => {
|
||||
router.push(`/projects/${item.id}`)
|
||||
}
|
||||
|
||||
const infiniteLoad = async (state: InfiniteLoaderState) => {
|
||||
const cursor = extraPagesResult.value?.admin?.projectList.cursor || null
|
||||
if (!moreToLoad.value || !cursor) return state.complete()
|
||||
|
||||
try {
|
||||
await fetchMorePages({
|
||||
variables: {
|
||||
cursor
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
logger.error(e)
|
||||
state.error()
|
||||
return
|
||||
}
|
||||
|
||||
state.loaded()
|
||||
if (!moreToLoad.value) {
|
||||
state.complete()
|
||||
}
|
||||
}
|
||||
|
||||
const calculateLoaderId = () => {
|
||||
infiniteLoaderId.value = resultVariables.value?.query || ''
|
||||
}
|
||||
|
||||
onResult(calculateLoaderId)
|
||||
</script>
|
||||
|
|
Загрузка…
Ссылка в новой задаче