Ensure deletes are coming through

This commit is contained in:
Eric Bailey
2025-05-20 20:50:31 -05:00
parent f8d5ad88c5
commit 7d4ce438ca
4 changed files with 82 additions and 66 deletions
+4
View File
@@ -14,6 +14,7 @@ import {findAllPostsInQueryData as findAllPostsInFeedQueryData} from '#/state/qu
import {findAllPostsInQueryData as findAllPostsInQuoteQueryData} from '#/state/queries/post-quotes'
import {findAllPostsInQueryData as findAllPostsInThreadQueryData} from '#/state/queries/post-thread'
import {findAllPostsInQueryData as findAllPostsInSearchQueryData} from '#/state/queries/search-posts'
import {findAllPostsInQueryData as findAllPostsInThreadV2QueryData} from '#/state/queries/usePostThread/queryCache'
import {useProfileShadow} from './profile-shadow'
import {castAsShadow, type Shadow} from './types'
export type {Shadow} from './types'
@@ -157,6 +158,9 @@ function* findPostsInCache(
yield node.post
}
}
for (let post of findAllPostsInThreadV2QueryData(queryClient, uri)) {
yield post
}
for (let post of findAllPostsInSearchQueryData(queryClient, uri)) {
yield post
}
-1
View File
@@ -74,7 +74,6 @@ export function usePostThread({
const items = flatten(
sort(query.data?.thread || [], {
view: params.view,
threadgateHiddenReplies: mergeThreadgateHiddenReplies(
query.data?.threadgate?.record,
),
+72 -36
View File
@@ -1,4 +1,9 @@
import {type $Typed, AppBskyUnspeccedGetPostThreadV2, AtUri} from '@atproto/api'
import {
type $Typed,
type AppBskyFeedDefs,
AppBskyUnspeccedGetPostThreadV2,
AtUri,
} from '@atproto/api'
import {type QueryClient} from '@tanstack/react-query'
import {findAllPostsInQueryData as findAllPostsInExploreFeedPreviewsQueryData} from '#/state/queries/explore-feed-previews'
@@ -13,11 +18,9 @@ import {
postThreadQueryKeyRoot,
} from '#/state/queries/usePostThread/types'
import {getRootPostAtUri} from '#/state/queries/usePostThread/utils'
import {
embedViewToThreadPlaceholder,
postViewToThreadPlaceholder,
} from '#/state/queries/usePostThread/views'
import {postViewToThreadPlaceholder} from '#/state/queries/usePostThread/views'
import {didOrHandleUriMatches, getEmbeddedPost} from '#/state/queries/util'
import {embedViewRecordToPostView} from '#/state/queries/util'
export function createCacheMutator({
params,
@@ -113,7 +116,37 @@ export function createCacheMutator({
},
)
},
deletePost(_post: AppBskyUnspeccedGetPostThreadV2.ThreadItem) {},
/**
* Unused atm, post shadow does the trick, but it would be nice to clean up
* the whole sub-tree on deletes.
*/
deletePost(post: AppBskyUnspeccedGetPostThreadV2.ThreadItem) {
queryClient.setQueryData<AppBskyUnspeccedGetPostThreadV2.OutputSchema>(
queryKey,
queryData => {
if (!queryData) return
const thread = [...queryData.thread]
for (let i = 0; i < thread.length; i++) {
const existingPost = thread[i]
if (!AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(post.value))
continue
if (existingPost.uri === post.uri) {
const branch = getBranch(thread, i, existingPost.depth)
thread.splice(branch.start, branch.length)
break
}
}
return {
...queryData,
thread,
}
},
)
},
}
}
@@ -153,38 +186,11 @@ export function* getThreadPlaceholderCandidates(
>,
void
> {
const atUri = new AtUri(uri)
/*
* Check this thread in the cache first.
* TODO extract just this for shadowing
* Check post thread queries first
*/
const queryDatas =
queryClient.getQueriesData<AppBskyUnspeccedGetPostThreadV2.OutputSchema>({
queryKey: [postThreadQueryKeyRoot],
})
for (const [_queryKey, queryData] of queryDatas) {
if (!queryData) continue
const {thread} = queryData
for (const item of thread) {
if (AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(item.value)) {
if (didOrHandleUriMatches(atUri, item.value.post)) {
yield {
$type: 'app.bsky.unspecced.getPostThreadV2#threadItem',
...item,
depth: 0,
value: item.value,
}
}
const qp = getEmbeddedPost(item.value.post.embed)
if (qp && didOrHandleUriMatches(atUri, qp)) {
yield embedViewToThreadPlaceholder(qp)
}
}
}
for (const post of findAllPostsInQueryData(queryClient, uri)) {
yield postViewToThreadPlaceholder(post)
}
/*
@@ -212,3 +218,33 @@ export function* getThreadPlaceholderCandidates(
yield postViewToThreadPlaceholder(post)
}
}
export function* findAllPostsInQueryData(
queryClient: QueryClient,
uri: string,
): Generator<AppBskyFeedDefs.PostView, void> {
const atUri = new AtUri(uri)
const queryDatas =
queryClient.getQueriesData<AppBskyUnspeccedGetPostThreadV2.OutputSchema>({
queryKey: [postThreadQueryKeyRoot],
})
for (const [_queryKey, queryData] of queryDatas) {
if (!queryData) continue
const {thread} = queryData
for (const item of thread) {
if (AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(item.value)) {
if (didOrHandleUriMatches(atUri, item.value.post)) {
yield item.value.post
}
const qp = getEmbeddedPost(item.value.post.embed)
if (qp && didOrHandleUriMatches(atUri, qp)) {
yield embedViewRecordToPostView(qp)
}
}
}
}
}
+6 -29
View File
@@ -1,6 +1,5 @@
import {
type $Typed,
type AppBskyEmbedRecord,
type AppBskyFeedDefs,
type AppBskyFeedPost,
type AppBskyUnspeccedGetPostThreadV2,
@@ -9,7 +8,6 @@ import {
} from '@atproto/api'
import {type Slice} from '#/state/queries/usePostThread/types'
import {embedViewRecordToPostView} from '#/state/queries/util'
export function threadPostNoUnauthenticated({
uri,
@@ -84,9 +82,12 @@ export function threadPost({
depth,
value: {
...value,
post: {
...value.post,
record: value.post.record as AppBskyFeedPost.Record,
/*
* Do not spread anything here, load bearing for post shadow strict
* equality checks.
*/
post: value.post as Omit<AppBskyFeedDefs.PostView, 'record'> & {
record: AppBskyFeedPost.Record
},
},
moderation: moderatePost(value.post, moderationOpts),
@@ -123,27 +124,3 @@ export function postViewToThreadPlaceholder(
},
}
}
export function embedViewToThreadPlaceholder(
record: AppBskyEmbedRecord.ViewRecord,
): $Typed<
Omit<AppBskyUnspeccedGetPostThreadV2.ThreadItem, 'value'> & {
value: $Typed<AppBskyUnspeccedGetPostThreadV2.ThreadItemPost>
}
> {
return {
$type: 'app.bsky.unspecced.getPostThreadV2#threadItem',
uri: record.uri,
depth: 0, // reset to 0 for highlighted post
value: {
$type: 'app.bsky.unspecced.getPostThreadV2#threadItemPost',
post: embedViewRecordToPostView(record),
isOPThread: false, // unknown
hasOPLike: false, // unknown
// @ts-expect-error
hasUnhydratedReplies: false, // unknown
// TODO test
hasUnhydratedParents: !!(record.value as AppBskyFeedPost.Record).reply, // unknown
},
}
}