fix: pagination on get my teams fixes #2106
This commit is contained in:
@@ -167,7 +167,9 @@ export const runGQLQuery = <DocType, DocVarType, DocErrorType extends string>(
|
||||
args: RunQueryOptions<DocType, DocVarType>
|
||||
): Promise<E.Either<GQLError<DocErrorType>, DocType>> => {
|
||||
const request = createRequest<DocType, DocVarType>(args.query, args.variables)
|
||||
const source = client.value.executeQuery(request)
|
||||
const source = client.value.executeQuery(request, {
|
||||
requestPolicy: "network-only",
|
||||
})
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const sub = wonkaPipe(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { gql } from "@urql/core"
|
||||
import { GraphCacheUpdaters, MyTeamsDocument } from "../graphql"
|
||||
import { GraphCacheUpdaters } from "../graphql"
|
||||
|
||||
export const updatesDef: GraphCacheUpdaters = {
|
||||
Subscription: {
|
||||
@@ -58,71 +58,6 @@ export const updatesDef: GraphCacheUpdaters = {
|
||||
},
|
||||
},
|
||||
Mutation: {
|
||||
deleteTeam: (_r, { teamID }, cache, _info) => {
|
||||
cache.updateQuery(
|
||||
{
|
||||
query: MyTeamsDocument,
|
||||
},
|
||||
(data) => {
|
||||
if (data) {
|
||||
data.myTeams = data.myTeams.filter((x) => x.id !== teamID)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
)
|
||||
|
||||
cache.invalidate({
|
||||
__typename: "Team",
|
||||
id: teamID,
|
||||
})
|
||||
},
|
||||
leaveTeam: (_r, { teamID }, cache, _info) => {
|
||||
cache.updateQuery(
|
||||
{
|
||||
query: MyTeamsDocument,
|
||||
},
|
||||
(data) => {
|
||||
if (data) {
|
||||
data.myTeams = data.myTeams.filter((x) => x.id !== teamID)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
)
|
||||
|
||||
cache.invalidate({
|
||||
__typename: "Team",
|
||||
id: teamID,
|
||||
})
|
||||
},
|
||||
createTeam: (result, _args, cache, _info) => {
|
||||
cache.updateQuery(
|
||||
{
|
||||
query: MyTeamsDocument,
|
||||
},
|
||||
(data) => {
|
||||
if (data) data.myTeams.push(result.createTeam as any)
|
||||
return data
|
||||
}
|
||||
)
|
||||
},
|
||||
removeTeamMember: (_result, { teamID, userUid }, cache) => {
|
||||
const newMembers = (
|
||||
(cache.resolve(
|
||||
{
|
||||
__typename: "Team",
|
||||
id: teamID,
|
||||
},
|
||||
"teamMembers"
|
||||
) as string[]) ?? []
|
||||
)
|
||||
.map((x) => [x, cache.resolve(x, "user") as string])
|
||||
.map(([key, userKey]) => [key, cache.resolve(userKey, "uid") as string])
|
||||
.filter(([_key, uid]) => uid !== userUid)
|
||||
.map(([key]) => key)
|
||||
cache.link({ __typename: "Team", id: teamID }, "teamMembers", newMembers)
|
||||
},
|
||||
createTeamInvitation: (result, _args, cache, _info) => {
|
||||
cache.invalidate(
|
||||
{
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
query GetMyTeams {
|
||||
myTeams {
|
||||
query GetMyTeams($cursor: ID) {
|
||||
myTeams(cursor: $cursor) {
|
||||
id
|
||||
name
|
||||
myRole
|
||||
ownersCount
|
||||
teamMembers {
|
||||
membershipID
|
||||
user {
|
||||
photoURL
|
||||
displayName
|
||||
email
|
||||
uid
|
||||
}
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
query MyTeams {
|
||||
myTeams {
|
||||
id
|
||||
name
|
||||
myRole
|
||||
ownersCount
|
||||
teamMembers {
|
||||
membershipID
|
||||
user {
|
||||
photoURL
|
||||
displayName
|
||||
email
|
||||
uid
|
||||
}
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
77
packages/hoppscotch-app/helpers/teams/TeamListAdapter.ts
Normal file
77
packages/hoppscotch-app/helpers/teams/TeamListAdapter.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import * as E from "fp-ts/Either"
|
||||
import { BehaviorSubject } from "rxjs"
|
||||
import { GQLError, runGQLQuery } from "../backend/GQLClient"
|
||||
import { GetMyTeamsDocument, GetMyTeamsQuery } from "../backend/graphql"
|
||||
|
||||
const BACKEND_PAGE_SIZE = 10
|
||||
const POLL_DURATION = 10000
|
||||
|
||||
export default class TeamListAdapter {
|
||||
error$: BehaviorSubject<GQLError<string> | null>
|
||||
loading$: BehaviorSubject<boolean>
|
||||
teamList$: BehaviorSubject<GetMyTeamsQuery["myTeams"]>
|
||||
|
||||
private timeoutHandle: ReturnType<typeof setTimeout> | null
|
||||
private isDispose: boolean
|
||||
|
||||
constructor(deferInit: boolean = false) {
|
||||
this.error$ = new BehaviorSubject<GQLError<string> | null>(null)
|
||||
this.loading$ = new BehaviorSubject<boolean>(false)
|
||||
this.teamList$ = new BehaviorSubject<GetMyTeamsQuery["myTeams"]>([])
|
||||
this.timeoutHandle = null
|
||||
this.isDispose = false
|
||||
|
||||
if (!deferInit) this.initialize()
|
||||
}
|
||||
|
||||
initialize() {
|
||||
if (this.timeoutHandle) throw new Error(`Adapter already initialized`)
|
||||
if (this.isDispose) throw new Error(`Adapter has been disposed`)
|
||||
|
||||
const func = async () => {
|
||||
await this.fetchList()
|
||||
|
||||
if (!this.isDispose) {
|
||||
this.timeoutHandle = setTimeout(() => func(), POLL_DURATION)
|
||||
}
|
||||
}
|
||||
|
||||
func()
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
this.isDispose = true
|
||||
clearTimeout(this.timeoutHandle as any)
|
||||
this.timeoutHandle = null
|
||||
}
|
||||
|
||||
async fetchList() {
|
||||
this.loading$.next(true)
|
||||
|
||||
const results: GetMyTeamsQuery["myTeams"] = []
|
||||
|
||||
while (true) {
|
||||
const result = await runGQLQuery({
|
||||
query: GetMyTeamsDocument,
|
||||
variables: {
|
||||
cursor:
|
||||
results.length > 0 ? results[results.length - 1].id : undefined,
|
||||
},
|
||||
})
|
||||
|
||||
if (E.isLeft(result)) {
|
||||
this.error$.next(result.left)
|
||||
throw new Error(`Failed fetching teams list: ${result.left}`)
|
||||
}
|
||||
|
||||
results.push(...result.right.myTeams)
|
||||
|
||||
// If we don't have full elements in the list, then the list is done usually, so lets stop
|
||||
if (result.right.myTeams.length !== BACKEND_PAGE_SIZE) break
|
||||
}
|
||||
|
||||
this.teamList$.next(results)
|
||||
|
||||
this.loading$.next(false)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user