mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-11 02:12:21 -05:00
Updated thread implementation to work with posts in admin-x-activitypub
(#22301)
refs [AP-721](https://linear.app/ghost/issue/AP-721/update-getactivitythread-to-work-with-posts-instead-of-activities) Updated thread implementation to work with posts instead of activities in `admin-x-activitypub` as part of the posts migration
This commit is contained in:
parent
b5f1a414b6
commit
b1c496f46d
4 changed files with 22 additions and 19 deletions
|
@ -38,8 +38,8 @@ export interface SearchResults {
|
||||||
accounts: AccountSearchResult[];
|
accounts: AccountSearchResult[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ActivityThread {
|
export interface Thread {
|
||||||
items: Activity[];
|
posts: Post[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ActivityPubCollectionResponse<T> = {data: T[], next: string | null};
|
export type ActivityPubCollectionResponse<T> = {data: T[], next: string | null};
|
||||||
|
@ -426,10 +426,10 @@ export class ActivityPubAPI {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async getThread(id: string): Promise<ActivityThread> {
|
async getThread(id: string): Promise<Thread> {
|
||||||
const url = new URL(`.ghost/activitypub/thread/${encodeURIComponent(id)}`, this.apiUrl);
|
const url = new URL(`.ghost/activitypub/thread/${encodeURIComponent(id)}`, this.apiUrl);
|
||||||
const json = await this.fetchJSON(url);
|
const json = await this.fetchJSON(url);
|
||||||
return json as ActivityThread;
|
return json as Thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
get accountApiUrl() {
|
get accountApiUrl() {
|
||||||
|
|
|
@ -379,10 +379,10 @@ const ArticleModal: React.FC<ArticleModalProps> = ({
|
||||||
const [isFocused] = useState(focusReply ? 1 : 0);
|
const [isFocused] = useState(focusReply ? 1 : 0);
|
||||||
|
|
||||||
const {threadQuery, addToThread} = useThreadForUser('index', activityId);
|
const {threadQuery, addToThread} = useThreadForUser('index', activityId);
|
||||||
const {data: activityThread, isLoading: isLoadingThread} = threadQuery;
|
const {data: thread, isLoading: isLoadingThread} = threadQuery;
|
||||||
const activtyThreadActivityIdx = (activityThread?.items ?? []).findIndex(item => item.object.id === activityId);
|
const threadPostIdx = (thread?.posts ?? []).findIndex(item => item.object.id === activityId);
|
||||||
const activityThreadChildren = (activityThread?.items ?? []).slice(activtyThreadActivityIdx + 1);
|
const threadChildren = (thread?.posts ?? []).slice(threadPostIdx + 1);
|
||||||
const activityThreadParents = (activityThread?.items ?? []).slice(0, activtyThreadActivityIdx);
|
const threadParents = (thread?.posts ?? []).slice(0, threadPostIdx);
|
||||||
|
|
||||||
const modalSize = width === 'narrow' ? MODAL_SIZE_SM : MODAL_SIZE_LG;
|
const modalSize = width === 'narrow' ? MODAL_SIZE_SM : MODAL_SIZE_LG;
|
||||||
const modal = useModal();
|
const modal = useModal();
|
||||||
|
@ -720,7 +720,7 @@ const ArticleModal: React.FC<ArticleModalProps> = ({
|
||||||
gridTemplateColumns: `1fr minmax(0,${currentGridWidth}) 1fr`
|
gridTemplateColumns: `1fr minmax(0,${currentGridWidth}) 1fr`
|
||||||
} : undefined}
|
} : undefined}
|
||||||
>
|
>
|
||||||
{(canNavigateBack || (activityThreadParents.length > 0)) ? (
|
{(canNavigateBack || (threadParents.length > 0)) ? (
|
||||||
<div className='col-[1/2] flex items-center justify-between'>
|
<div className='col-[1/2] flex items-center justify-between'>
|
||||||
<Button className='transition-color flex h-10 w-10 items-center justify-center rounded-full bg-white hover:bg-gray-100' icon='arrow-left' size='sm' unstyled onClick={navigateBack}/>
|
<Button className='transition-color flex h-10 w-10 items-center justify-center rounded-full bg-white hover:bg-gray-100' icon='arrow-left' size='sm' unstyled onClick={navigateBack}/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -853,7 +853,7 @@ const ArticleModal: React.FC<ArticleModalProps> = ({
|
||||||
)}
|
)}
|
||||||
<div className='grow overflow-y-auto'>
|
<div className='grow overflow-y-auto'>
|
||||||
<div className={`mx-auto px-8 pb-10 pt-5`} style={{maxWidth: currentMaxWidth}}>
|
<div className={`mx-auto px-8 pb-10 pt-5`} style={{maxWidth: currentMaxWidth}}>
|
||||||
{activityThreadParents.map((item) => {
|
{threadParents.map((item) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<FeedItem
|
<FeedItem
|
||||||
|
@ -883,7 +883,7 @@ const ArticleModal: React.FC<ArticleModalProps> = ({
|
||||||
layout={'modal'}
|
layout={'modal'}
|
||||||
object={object}
|
object={object}
|
||||||
repostCount={object.repostCount ?? 0}
|
repostCount={object.repostCount ?? 0}
|
||||||
showHeader={(canNavigateBack || (activityThreadParents.length > 0))}
|
showHeader={(canNavigateBack || (threadParents.length > 0))}
|
||||||
type='Note'
|
type='Note'
|
||||||
onCommentClick={() => {
|
onCommentClick={() => {
|
||||||
repliesRef.current?.scrollIntoView({
|
repliesRef.current?.scrollIntoView({
|
||||||
|
@ -938,8 +938,8 @@ const ArticleModal: React.FC<ArticleModalProps> = ({
|
||||||
{isLoadingThread && <LoadingIndicator size='lg' />}
|
{isLoadingThread && <LoadingIndicator size='lg' />}
|
||||||
|
|
||||||
<div ref={repliesRef}>
|
<div ref={repliesRef}>
|
||||||
{activityThreadChildren.map((item, index) => {
|
{threadChildren.map((item, index) => {
|
||||||
const showDivider = index !== activityThreadChildren.length - 1;
|
const showDivider = index !== threadChildren.length - 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={item.id}>
|
<React.Fragment key={item.id}>
|
||||||
|
|
|
@ -3,7 +3,6 @@ import {
|
||||||
type AccountSearchResult,
|
type AccountSearchResult,
|
||||||
ActivityPubAPI,
|
ActivityPubAPI,
|
||||||
ActivityPubCollectionResponse,
|
ActivityPubCollectionResponse,
|
||||||
ActivityThread,
|
|
||||||
FollowAccount,
|
FollowAccount,
|
||||||
type GetAccountFollowsResponse,
|
type GetAccountFollowsResponse,
|
||||||
type Profile,
|
type Profile,
|
||||||
|
@ -591,19 +590,23 @@ export function useThreadForUser(handle: string, id: string) {
|
||||||
const siteUrl = await getSiteUrl();
|
const siteUrl = await getSiteUrl();
|
||||||
const api = createActivityPubAPI(handle, siteUrl);
|
const api = createActivityPubAPI(handle, siteUrl);
|
||||||
|
|
||||||
return api.getThread(id);
|
return api.getThread(id).then((response) => {
|
||||||
|
return {
|
||||||
|
posts: response.posts.map(mapPostToActivity)
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const addToThread = (activity: Activity) => {
|
const addToThread = (activity: Activity) => {
|
||||||
// Add the activity to the thread stored in the thread query cache
|
// Add the activity to the thread stored in the thread query cache
|
||||||
queryClient.setQueryData(queryKey, (current: ActivityThread | undefined) => {
|
queryClient.setQueryData(queryKey, (current: {posts: Activity[]} | undefined) => {
|
||||||
if (!current) {
|
if (!current) {
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
items: [...current.items, activity]
|
posts: [...current.posts, activity]
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,7 +30,7 @@ const Inbox: React.FC = () => {
|
||||||
const activities = (data?.pages.flatMap(page => page.posts) ?? Array.from({length: 5}, (_, index) => ({id: `placeholder-${index}`, object: {}})));
|
const activities = (data?.pages.flatMap(page => page.posts) ?? Array.from({length: 5}, (_, index) => ({id: `placeholder-${index}`, object: {}})));
|
||||||
|
|
||||||
const observerRef = useRef<IntersectionObserver | null>(null);
|
const observerRef = useRef<IntersectionObserver | null>(null);
|
||||||
const loadMoreRef = useRef<HTMLLIElement | null>(null);
|
const loadMoreRef = useRef<HTMLDivElement | null>(null);
|
||||||
const endLoadMoreRef = useRef<HTMLDivElement | null>(null);
|
const endLoadMoreRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -103,7 +103,7 @@ const Inbox: React.FC = () => {
|
||||||
<Separator />
|
<Separator />
|
||||||
)}
|
)}
|
||||||
{index === loadMoreIndex && (
|
{index === loadMoreIndex && (
|
||||||
<li ref={loadMoreRef} className='h-1'></li>
|
<div ref={loadMoreRef} className='h-1'></div>
|
||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
|
Loading…
Add table
Reference in a new issue