Display collection in search results when searched by URL (#39289)

This commit is contained in:
diondiondion 2026-06-04 16:28:51 +02:00 committed by GitHub
parent 085c91bf12
commit fe4613ba32
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 69 additions and 6 deletions

View File

@ -12,6 +12,11 @@ import {
createAppAsyncThunk,
} from 'mastodon/store/typed_functions';
import {
importAccountsForPreviewCard,
importFetchedCollections,
} from '../reducers/slices/collections';
import { fetchRelationships } from './accounts';
import { importFetchedAccounts, importFetchedStatuses } from './importer';
@ -29,7 +34,7 @@ export const submitSearch = createDataLoadingThunk(
limit: 11,
});
},
(data, { dispatch }) => {
async (data, { dispatch }) => {
if (data.accounts.length > 0) {
dispatch(importFetchedAccounts(data.accounts));
dispatch(fetchRelationships(data.accounts.map((account) => account.id)));
@ -39,6 +44,11 @@ export const submitSearch = createDataLoadingThunk(
dispatch(importFetchedStatuses(data.statuses));
}
if (data.collections.length > 0) {
dispatch(importFetchedCollections(data.collections));
await importAccountsForPreviewCard(data.collections, dispatch);
}
return data;
},
{
@ -60,7 +70,7 @@ export const expandSearch = createDataLoadingThunk(
offset,
});
},
(data, { dispatch }) => {
async (data, { dispatch }) => {
if (data.accounts.length > 0) {
dispatch(importFetchedAccounts(data.accounts));
dispatch(fetchRelationships(data.accounts.map((account) => account.id)));
@ -70,6 +80,11 @@ export const expandSearch = createDataLoadingThunk(
dispatch(importFetchedStatuses(data.statuses));
}
if (data.collections.length > 0) {
dispatch(importFetchedCollections(data.collections));
await importAccountsForPreviewCard(data.collections, dispatch);
}
return data;
},
{

View File

@ -4,6 +4,7 @@ import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
import { Helmet } from '@unhead/react/helmet';
import CollectionsIcon from '@/material-icons/400-24px/category.svg?react';
import FindInPageIcon from '@/material-icons/400-24px/find_in_page.svg?react';
import PeopleIcon from '@/material-icons/400-24px/group.svg?react';
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
@ -23,6 +24,8 @@ import { useSearchParam } from 'mastodon/hooks/useSearchParam';
import type { Hashtag as HashtagType } from 'mastodon/models/tags';
import { useAppDispatch, useAppSelector } from 'mastodon/store';
import { CollectionListItem } from '../collections/components/collection_list_item';
import { SearchSection } from './components/search_section';
const messages = defineMessages({
@ -131,7 +134,8 @@ export const SearchResults: React.FC<{ multiColumn: boolean }> = ({
filteredResults =
results.accounts.length +
results.hashtags.length +
results.statuses.length >
results.statuses.length +
results.collections.length >
0 ? (
<>
{results.accounts.length > 0 && (
@ -154,6 +158,32 @@ export const SearchResults: React.FC<{ multiColumn: boolean }> = ({
</SearchSection>
)}
{results.collections.length > 0 && (
<SearchSection
key='collections'
title={
<>
<Icon id='collections' icon={CollectionsIcon} />
<FormattedMessage
id='search_results.collections'
defaultMessage='Collections'
/>
</>
}
>
{results.collections
.slice(0, INITIAL_DISPLAY)
.map((collection, index, array) => (
<CollectionListItem
key={collection.id}
collection={collection}
listSize={array.length}
positionInList={index + 1}
/>
))}
</SearchSection>
)}
{results.hashtags.length > 0 && (
<SearchSection
key='hashtags'

View File

@ -1199,6 +1199,7 @@
"search_popout.user": "user",
"search_results.accounts": "Profiles",
"search_results.all": "All",
"search_results.collections": "Collections",
"search_results.hashtags": "Hashtags",
"search_results.no_results": "No results.",
"search_results.no_search_yet": "Try searching for posts, profiles or hashtags.",

View File

@ -1,5 +1,6 @@
import type { ApiSearchResultsJSON } from 'mastodon/api_types/search';
import type { ApiHashtagJSON } from 'mastodon/api_types/tags';
import type { ApiCollectionJSON } from '@/mastodon/api_types/collections';
import type { ApiSearchResultsJSON } from '@/mastodon/api_types/search';
import type { ApiHashtagJSON } from '@/mastodon/api_types/tags';
export type SearchType = 'account' | 'hashtag' | 'accounts' | 'statuses';
@ -12,10 +13,12 @@ export interface SearchResults {
accounts: string[];
statuses: string[];
hashtags: ApiHashtagJSON[];
collections: ApiCollectionJSON[];
}
export const createSearchResults = (serverJSON: ApiSearchResultsJSON) => ({
accounts: serverJSON.accounts.map((account) => account.id),
statuses: serverJSON.statuses.map((status) => status.id),
hashtags: serverJSON.hashtags,
collections: serverJSON.collections,
});

View File

@ -49,6 +49,9 @@ export const searchReducer = createReducer(initialState, (builder) => {
hashtags: state.results
? [...state.results.hashtags, ...results.hashtags]
: results.hashtags,
collections: state.results
? [...state.results.collections, ...results.collections]
: results.collections,
};
state.loading = false;
});

View File

@ -121,6 +121,15 @@ const collectionSlice = createSlice({
const { field, value } = action.payload;
state.editor[field] = value;
},
importFetchedCollections(
state,
action: PayloadAction<ApiCollectionJSON[]>,
) {
const collections = action.payload;
collections.forEach((collection) => {
state.collections[collection.id] = collection;
});
},
},
extraReducers(builder) {
/**
@ -328,7 +337,7 @@ const collectionSlice = createSlice({
/**
* Prefetch accounts whose avatars will be displayed in the collection list
*/
async function importAccountsForPreviewCard(
export async function importAccountsForPreviewCard(
collections: ApiCollectionJSON[],
dispatch: AppDispatch,
) {
@ -419,6 +428,8 @@ export const collections = collectionSlice.reducer;
export const collectionEditorActions = collectionSlice.actions;
export const updateCollectionEditorField =
collectionSlice.actions.updateEditorField;
export const importFetchedCollections =
collectionSlice.actions.importFetchedCollections;
/**
* Selectors