0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00

Fixed suggested accounts not rendering in admin-x-activitypub (#21655)

refs
[AP-606](https://linear.app/ghost/issue/AP-606/suggested-accounts-not-rendering-due-to-404)

Some of the suggested accounts in `admin-x-activitypub` were not
rendering due to the requests for the data returning a 404. This was due
to incorrect account handles being used. This commit fixes the issue by
ensuring the correct handles are being used. This commit also adds a new
hook to handle the fetching of suggested accounts that also limits and
randomizes the accounts returned.
This commit is contained in:
Michael Barrett 2024-11-20 14:07:05 +00:00 committed by GitHub
parent 46bdbaa3b8
commit 2e9dbd3ef0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 113 additions and 15 deletions

View file

@ -1,6 +1,6 @@
{
"name": "@tryghost/admin-x-activitypub",
"version": "0.3.20",
"version": "0.3.21",
"license": "MIT",
"repository": {
"type": "git",

View file

@ -9,9 +9,10 @@ import Separator from './global/Separator';
import ViewProfileModal from './global/ViewProfileModal';
import getName from '../utils/get-name';
import getUsername from '../utils/get-username';
import useSuggestedProfiles from '../hooks/useSuggestedProfiles';
import {Button, Heading, LoadingIndicator} from '@tryghost/admin-x-design-system';
import {handleViewContent} from '../utils/content-handlers';
import {useActivitiesForUser, useSuggestedProfiles} from '../hooks/useActivityPubQueries';
import {useActivitiesForUser} from '../hooks/useActivityPubQueries';
import {useRouting} from '@tryghost/admin-x-framework/routing';
type Layout = 'inbox' | 'feed';
@ -37,8 +38,7 @@ const Inbox: React.FC<InboxProps> = ({layout}) => {
const {updateRoute} = useRouting();
const {suggestedProfilesQuery} = useSuggestedProfiles('index', ['@index@activitypub.ghost.org', '@index@john.onolan.org', '@index@coffeecomplex.ghost.io', '@index@codename-jimmy.ghost.io', '@index@syphoncontinuity.ghost.io']);
const {data: suggested = [], isLoading: isLoadingSuggested} = suggestedProfilesQuery;
const {suggested, isLoadingSuggested} = useSuggestedProfiles();
const activities = (data?.pages.flatMap(page => page.data) ?? []).filter((activity) => {
return !activity.object.inReplyTo;

View file

@ -13,7 +13,8 @@ import NiceModal from '@ebay/nice-modal-react';
import ViewProfileModal from './global/ViewProfileModal';
import Separator from './global/Separator';
import {useSearchForUser, useSuggestedProfiles} from '../hooks/useActivityPubQueries';
import useSuggestedProfiles from '../hooks/useSuggestedProfiles';
import {useSearchForUser} from '../hooks/useActivityPubQueries';
interface SearchResultItem {
actor: ActorProperties;
@ -122,8 +123,7 @@ const SuggestedAccounts: React.FC<{
const Search: React.FC<SearchProps> = ({}) => {
// Initialise suggested profiles
const {suggestedProfilesQuery, updateSuggestedProfile} = useSuggestedProfiles('index', ['@index@activitypub.ghost.org', '@index@john.onolan.org', '@index@coffeecomplex.ghost.io', '@index@codename-jimmy.ghost.io', '@index@syphoncontinuity.ghost.io']);
const {data: suggested = [], isLoading: isLoadingSuggested} = suggestedProfilesQuery;
const {suggested, isLoadingSuggested, updateSuggestedProfile} = useSuggestedProfiles(6);
// Initialise search query
const queryInputRef = useRef<HTMLInputElement>(null);

View file

@ -0,0 +1,27 @@
import {useMemo} from 'react';
import {useSuggestedProfiles as useSuggestedProfilesQuery} from '../hooks/useActivityPubQueries';
export const SUGGESTED_HANDLES = [
'@index@activitypub.ghost.org',
'@index@john.onolan.org',
'@index@www.coffeeandcomplexity.com',
'@index@ghost.codenamejimmy.com',
'@index@www.syphoncontinuity.com',
'@index@www.cosmico.org',
'@index@silverhuang.com'
];
const useSuggestedProfiles = (limit = 3) => {
const handles = useMemo(() => {
return SUGGESTED_HANDLES
.sort(() => Math.random() - 0.5)
.slice(0, limit);
}, [limit]);
const {suggestedProfilesQuery, updateSuggestedProfile} = useSuggestedProfilesQuery('index', handles);
const {data: suggested = [], isLoading: isLoadingSuggested} = suggestedProfilesQuery;
return {suggested, isLoadingSuggested, updateSuggestedProfile};
};
export default useSuggestedProfiles;

View file

@ -0,0 +1,71 @@
import {Mock, vi} from 'vitest';
import {renderHook} from '@testing-library/react';
import type {UseQueryResult} from '@tanstack/react-query';
import * as useActivityPubQueries from '../../../src/hooks/useActivityPubQueries';
import useSuggestedProfiles, {SUGGESTED_HANDLES} from '../../../src/hooks/useSuggestedProfiles';
import type{Profile} from '../../../src/api/activitypub';
vi.mock('../../../src/hooks/useActivityPubQueries');
describe('useSuggestedProfiles', function () {
let mockUpdateSuggestedProfile: Mock;
beforeEach(function () {
mockUpdateSuggestedProfile = vi.fn();
vi.mocked(useActivityPubQueries.useSuggestedProfiles).mockImplementation((handle, handles) => {
// We expect the handle to be 'index', throw if anything else
if (handle !== 'index') {
throw new Error(`Expected handle to be: [index], got: [${handle}]`);
}
// Return the mocked query result making sure that the data is the
// same as the handles passed in. For the purposes of this test,
// we don't need to test the internals of useSuggestedProfilesQuery
return {
suggestedProfilesQuery: {
data: handles,
isLoading: false
} as unknown as UseQueryResult<Profile[], unknown>,
updateSuggestedProfile: mockUpdateSuggestedProfile
};
});
});
it('should return the default number of suggested profiles', function () {
const {result} = renderHook(() => useSuggestedProfiles());
// Check that the correct number of suggested profiles are returned
expect(result.current.suggested.length).toEqual(3);
// Check that the suggested profiles are in the SUGGESTED_HANDLES array
result.current.suggested.forEach((suggested) => {
expect(SUGGESTED_HANDLES).toContain(suggested);
});
});
it('should return the specified number of suggested profiles', function () {
const {result} = renderHook(() => useSuggestedProfiles(5));
// Assert that the correct number of suggested profiles are returned
expect(result.current.suggested.length).toEqual(5);
// Assert that the suggested profiles are in the SUGGESTED_HANDLES array
result.current.suggested.forEach((suggested) => {
expect(SUGGESTED_HANDLES).toContain(suggested);
});
});
it('should return a loading state', function () {
const {result} = renderHook(() => useSuggestedProfiles());
expect(result.current.isLoadingSuggested).toEqual(false);
});
it('should return a function to update a suggested profile', function () {
const {result} = renderHook(() => useSuggestedProfiles());
expect(result.current.updateSuggestedProfile).toEqual(mockUpdateSuggestedProfile);
});
});