fix: pagination on get my teams fixes #2106

This commit is contained in:
Andrew Bastin
2022-02-03 16:28:55 +05:30
parent ebfbf44140
commit 9918f42bf9
7 changed files with 129 additions and 157 deletions

View File

@@ -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(

View File

@@ -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(
{

View File

@@ -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
}
}
}

View File

@@ -1,18 +0,0 @@
query MyTeams {
myTeams {
id
name
myRole
ownersCount
teamMembers {
membershipID
user {
photoURL
displayName
email
uid
}
role
}
}
}

View 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)
}
}