← All changes
|
js/components/ManageMenu/CommunityCloud/CloudSearch.tsx
+51
-30
3.10.2
→
4.0.0-beta.2
View file →
| @@ -1,6 +1,6 @@ | ||
| 1 | 1 | import { __ } from '@wordpress/i18n' |
| 2 | -import React, { useId, useState } from 'react' | |
| 2 | +import React, { useEffect, useId, useState } from 'react' | |
| 3 | 3 | import classnames from 'classnames' |
| 4 | 4 | import { Spinner } from '@wordpress/components' |
| 5 | 5 | import { useRestAPI } from '../../../hooks/useRestAPI' |
| 6 | 6 | import { REST_BASES } from '../../../utils/restAPI' |
| @@ -7,10 +7,10 @@ | ||
| 7 | 7 | import { isCloudSnippetDownloadable } from '../../../utils/snippets/snippets' |
| 8 | 8 | import { TableNav } from '../../common/ListTable/TableNavigation' |
| 9 | 9 | import { LoadingStatusNotices } from '../../common/LoadingStatusNotices' |
| 10 | 10 | import { SnippetViewToggle } from '../../common/SnippetViewToggle' |
| 11 | +import { CloudSnippetAuthor, CloudSnippetCard } from '../../common/cloud/CloudSnippetCard' | |
| 11 | 12 | import { CloudSnippetsTable } from './CloudSnippetsTable' |
| 12 | -import { CloudSnippetAuthor, SearchResult } from './SearchResult' | |
| 13 | 13 | import { useCloudSearch } from './WithCloudSearchContext' |
| 14 | 14 | import { SearchFilters } from './SearchFilters' |
| 15 | 15 | import type { CloudSearchResults } from './WithCloudSearchContext' |
| 16 | 16 | import type { TableNavProps } from '../../common/ListTable/TableNavigation' |
| @@ -75,38 +75,44 @@ | ||
| 75 | 75 | selected: Set<CloudSnippetSchema['id']> |
| 76 | 76 | setSelected: Dispatch<SetStateAction<Set<CloudSnippetSchema['id']>>> |
| 77 | 77 | } |
| 78 | 78 | |
| 79 | -const SearchResultsGrid: React.FC<SearchResultsGridProps> = ({ snippets, selected, setSelected }) => | |
| 80 | - <ul | |
| 81 | - className={classnames('cloud-search-results', 'code-snippets-cards', { | |
| 82 | - 'has-selection': snippets.some(snippet => selected.has(snippet.id)) | |
| 83 | - })} | |
| 84 | - > | |
| 85 | - {snippets.map(result => | |
| 86 | - <SearchResult | |
| 87 | - key={result.id} | |
| 88 | - snippet={result} | |
| 89 | - author={<CloudSnippetAuthor codevaultSlug={result.codevault} />} | |
| 90 | - isSelected={selected.has(result.id)} | |
| 91 | - onSelectedChange={isCloudSnippetDownloadable(result) | |
| 92 | - ? isSelected => { | |
| 93 | - setSelected(previous => { | |
| 94 | - const updated = new Set(previous) | |
| 79 | +const SearchResultsGrid: React.FC<SearchResultsGridProps> = ({ snippets, selected, setSelected }) => { | |
| 80 | + const { doSearch } = useCloudSearch() | |
| 95 | 81 | |
| 96 | - if (isSelected) { | |
| 97 | - updated.add(result.id) | |
| 98 | - } else { | |
| 99 | - updated.delete(result.id) | |
| 100 | - } | |
| 82 | + return ( | |
| 83 | + <ul | |
| 84 | + className={classnames('cloud-search-results', 'code-snippets-cards', { | |
| 85 | + 'has-selection': snippets.some(snippet => selected.has(snippet.id)) | |
| 86 | + })} | |
| 87 | + > | |
| 88 | + {snippets.map(result => | |
| 89 | + <CloudSnippetCard | |
| 90 | + key={result.id} | |
| 91 | + snippet={result} | |
| 92 | + author={<CloudSnippetAuthor codevaultSlug={result.codevault} />} | |
| 93 | + isSelected={selected.has(result.id)} | |
| 94 | + onSnippetDownloaded={() => doSearch()} | |
| 95 | + onSelectedChange={isCloudSnippetDownloadable(result) | |
| 96 | + ? isSelected => { | |
| 97 | + setSelected(previous => { | |
| 98 | + const updated = new Set(previous) | |
| 101 | 99 | |
| 102 | - return updated | |
| 103 | - }) | |
| 104 | - } | |
| 105 | - : undefined} | |
| 106 | - />)} | |
| 107 | - </ul> | |
| 100 | + if (isSelected) { | |
| 101 | + updated.add(result.id) | |
| 102 | + } else { | |
| 103 | + updated.delete(result.id) | |
| 104 | + } | |
| 108 | 105 | |
| 106 | + return updated | |
| 107 | + }) | |
| 108 | + } | |
| 109 | + : undefined} | |
| 110 | + />)} | |
| 111 | + </ul> | |
| 112 | + ) | |
| 113 | +} | |
| 114 | + | |
| 109 | 115 | interface SearchResultsViewProps { |
| 110 | 116 | snippetView: SnippetView |
| 111 | 117 | setSnippetView: (view: SnippetView) => void |
| 112 | 118 | } |
| @@ -153,12 +159,27 @@ | ||
| 153 | 159 | setCurrentPage={page => doSearch({ page })} |
| 154 | 160 | {...props} |
| 155 | 161 | /> |
| 156 | 162 | |
| 163 | +/** | |
| 164 | + * Bulk selection for the current page of results. A new set of results replaces | |
| 165 | + * the rows the selection referred to, so nothing carries over: a stale | |
| 166 | + * selection would let a bulk action act on snippets no longer on screen. | |
| 167 | + */ | |
| 168 | +const useResultsSelection = (snippets: CloudSnippetSchema[] | undefined) => { | |
| 169 | + const [selected, setSelected] = useState<Set<CloudSnippetSchema['id']>>(new Set()) | |
| 170 | + | |
| 171 | + useEffect(() => { | |
| 172 | + setSelected(new Set()) | |
| 173 | + }, [snippets]) | |
| 174 | + | |
| 175 | + return { selected, setSelected } | |
| 176 | +} | |
| 177 | + | |
| 157 | 178 | const SearchResultsTable: React.FC<SearchResultsViewProps> = ({ snippetView, setSnippetView }) => { |
| 158 | 179 | const { api } = useRestAPI() |
| 159 | 180 | const { searchResults, isSearching, doSearch } = useCloudSearch() |
| 160 | - const [selected, setSelected] = useState<Set<CloudSnippetSchema['id']>>(new Set()) | |
| 181 | + const { selected, setSelected } = useResultsSelection(searchResults?.snippets) | |
| 161 | 182 | |
| 162 | 183 | if (!searchResults) { |
| 163 | 184 | return null |
| 164 | 185 | } |