From 8f09fe258bc33997beb2aeed9004bc7ae6f59660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juliana=20Pe=C3=B1a?= Date: Thu, 19 Nov 2020 11:45:28 -0800 Subject: [PATCH] search: remove all GraphQL dependencies from SearchResultsInfoBar (#15991) This is part of the work to refactor search results UI components for streaming search. SearchResultsInfoBar will now receive its stats/progress as a JSX element property. Created a new component for the GQL search stats. --- client/shared/src/util/searchTestHelpers.ts | 4 +- .../search/results/SearchResultsInfoBar.tsx | 232 +++++------------- .../src/search/results/SearchResultsList.tsx | 10 +- .../src/search/results/SearchResultsStats.tsx | 94 +++++++ 4 files changed, 170 insertions(+), 170 deletions(-) create mode 100644 client/web/src/search/results/SearchResultsStats.tsx diff --git a/client/shared/src/util/searchTestHelpers.ts b/client/shared/src/util/searchTestHelpers.ts index bb6e20f0f53..df09832e122 100644 --- a/client/shared/src/util/searchTestHelpers.ts +++ b/client/shared/src/util/searchTestHelpers.ts @@ -119,7 +119,7 @@ export const MULTIPLE_MATCH_RESULT = { export const SEARCH_RESULT = { __typename: 'SearchResults' as const, limitHit: false, - resultCount: 1, + matchCount: 1, approximateResultCount: '1', missing: [] as IRepository[], cloning: [] as IRepository[], @@ -144,7 +144,7 @@ export const SEARCH_RESULT = { export const MULTIPLE_SEARCH_RESULT = { ...SEARCH_RESULT, limitHit: false, - resultCount: 136, + matchCount: 136, approximateResultCount: '136', results: [ RESULT, diff --git a/client/web/src/search/results/SearchResultsInfoBar.tsx b/client/web/src/search/results/SearchResultsInfoBar.tsx index 95cd8fe9e09..84990abf67b 100644 --- a/client/web/src/search/results/SearchResultsInfoBar.tsx +++ b/client/web/src/search/results/SearchResultsInfoBar.tsx @@ -1,25 +1,17 @@ -import * as GQL from '../../../../shared/src/graphql/schema' import * as H from 'history' import * as React from 'react' -import AlertCircleIcon from 'mdi-react/AlertCircleIcon' import ArrowCollapseVerticalIcon from 'mdi-react/ArrowCollapseVerticalIcon' import ArrowExpandVerticalIcon from 'mdi-react/ArrowExpandVerticalIcon' -import CalculatorIcon from 'mdi-react/CalculatorIcon' import CheckIcon from 'mdi-react/CheckIcon' import classNames from 'classnames' -import CloudDownloadIcon from 'mdi-react/CloudDownloadIcon' import DownloadIcon from 'mdi-react/DownloadIcon' import FormatQuoteOpenIcon from 'mdi-react/FormatQuoteOpenIcon' -import MapSearchIcon from 'mdi-react/MapSearchIcon' -import TimerSandIcon from 'mdi-react/TimerSandIcon' import { AuthenticatedUser } from '../../auth' import { ContributableMenu } from '../../../../shared/src/api/protocol' import { ExtensionsControllerProps } from '../../../../shared/src/extensions/controller' -import { PatternTypeProps, SearchStreamingProps } from '..' +import { PatternTypeProps } from '..' import { PlatformContextProps } from '../../../../shared/src/platform/context' -import { pluralize } from '../../../../shared/src/util/strings' import { SearchPatternType } from '../../graphql-operations' -import { StreamingProgress } from './streaming-progress/StreamingProgress' import { TelemetryProps } from '../../../../shared/src/telemetry/telemetryService' import { WebActionsNavItems as ActionsNavItems } from '../../components/shared' @@ -27,21 +19,18 @@ interface SearchResultsInfoBarProps extends ExtensionsControllerProps<'executeCommand' | 'services'>, PlatformContextProps<'forceUpdateTooltip' | 'settings'>, TelemetryProps, - PatternTypeProps, - SearchStreamingProps { + PatternTypeProps { /** The currently authenticated user or null */ authenticatedUser: AuthenticatedUser | null - /** The loaded search results and metadata */ + /** The search query and if any results were found */ query?: string - results: GQL.ISearchResults - onShowMoreResultsClick?: () => void + resultsFound: boolean // Expand all feature allExpanded: boolean onExpandAllResultsToggle: () => void - showDotComMarketing: boolean // Saved queries showSavedQueryButton?: boolean onDidCreateSavedQuery: () => void @@ -51,6 +40,8 @@ interface SearchResultsInfoBarProps location: H.Location className?: string + + stats: JSX.Element } /** @@ -76,158 +67,67 @@ const QuotesInterpretedLiterallyNotice: React.FunctionComponent = props => { - const excludeForksFilter = props.results.dynamicFilters.find(filter => filter.value === 'fork:yes') - const excludedForksCount = excludeForksFilter?.count || 0 - const excludeArchivedFilter = props.results.dynamicFilters.find(filter => filter.value === 'archived:yes') - const excludedArchivedCount = excludeArchivedFilter?.count || 0 - return ( -
- - {!props.searchStreaming && ( -
-
- - {props.results.approximateResultCount}{' '} - {pluralize('result', props.results.matchCount)} in{' '} - {(props.results.elapsedMilliseconds / 1000).toFixed(2)} seconds - {props.results.indexUnavailable && ' (index unavailable)'} - {props.results.limitHit && String.fromCharCode(160)} - +export const SearchResultsInfoBar: React.FunctionComponent = props => ( +
+ +
+ {props.stats} + +
- {props.results.limitHit && props.onShowMoreResultsClick && ( - +
    + + + {props.resultsFound && ( +
  • +
- - {excludedForksCount > 0 && ( -
- - {excludedForksCount} forked{' '} - {pluralize('repository', excludedForksCount, 'repositories')} excluded - -
- )} - - {excludedArchivedCount > 0 && ( -
- - {excludedArchivedCount} archived{' '} - {pluralize('repository', excludedArchivedCount, 'repositories')} excluded - -
- )} - - {props.results.missing.length > 0 && ( -
repo.name).join('\n')} - > - - {props.results.missing.length}{' '} - {pluralize('repository', props.results.missing.length, 'repositories')} not found - -
- )} - - {props.results.timedout.length > 0 && ( -
repo.name).join('\n')} - > - - {props.results.timedout.length}{' '} - {pluralize('repository', props.results.timedout.length, 'repositories')} timed out - (reload to try again, or specify a longer "timeout:" in your query) - -
- )} - - {props.results.cloning.length > 0 && ( -
repo.name).join('\n')} - > - - {props.results.cloning.length}{' '} - {pluralize('repository', props.results.cloning.length, 'repositories')} cloning - (reload to try again) - -
- )} - - -
+ + )} - {props.searchStreaming && } - -
    - - - {props.results.results.length > 0 && ( -
  • - -
  • - )} - - {props.showSavedQueryButton !== false && props.authenticatedUser && ( -
  • - -
  • - )} -
-
-
- ) -} + {props.showSavedQueryButton !== false && props.authenticatedUser && ( +
  • + +
  • + )} + +
    +
    +) diff --git a/client/web/src/search/results/SearchResultsList.tsx b/client/web/src/search/results/SearchResultsList.tsx index 673b569216b..7b4eba13cfc 100644 --- a/client/web/src/search/results/SearchResultsList.tsx +++ b/client/web/src/search/results/SearchResultsList.tsx @@ -40,6 +40,7 @@ import { AuthenticatedUser } from '../../auth' import { SearchResultTypeTabs } from './SearchResultTypeTabs' import { QueryState } from '../helpers' import { PerformanceWarningAlert } from '../../site/PerformanceWarningAlert' +import { SearchResultsStats } from './SearchResultsStats' const isSearchResults = (value: unknown): value is GQL.ISearchResults => typeof value === 'object' && @@ -377,9 +378,14 @@ export class SearchResultsList extends React.PureComponent 0} className="border-bottom flex-grow-1" + stats={ + + } /> diff --git a/client/web/src/search/results/SearchResultsStats.tsx b/client/web/src/search/results/SearchResultsStats.tsx new file mode 100644 index 00000000000..1bb7ff02f94 --- /dev/null +++ b/client/web/src/search/results/SearchResultsStats.tsx @@ -0,0 +1,94 @@ +import AlertCircleIcon from 'mdi-react/AlertCircleIcon' +import CalculatorIcon from 'mdi-react/CalculatorIcon' +import CloudDownloadIcon from 'mdi-react/CloudDownloadIcon' +import MapSearchIcon from 'mdi-react/MapSearchIcon' +import TimerSandIcon from 'mdi-react/TimerSandIcon' +import React from 'react' +import * as GQL from '../../../../shared/src/graphql/schema' +import { pluralize } from '../../../../shared/src/util/strings' + +/** Search result statistics for GraphQL searches */ +export const SearchResultsStats: React.FunctionComponent<{ + results: GQL.ISearchResults + onShowMoreResultsClick?: () => void +}> = ({ results, onShowMoreResultsClick }) => { + const excludeForksFilter = results.dynamicFilters.find(filter => filter.value === 'fork:yes') + const excludedForksCount = excludeForksFilter?.count || 0 + const excludeArchivedFilter = results.dynamicFilters.find(filter => filter.value === 'archived:yes') + const excludedArchivedCount = excludeArchivedFilter?.count || 0 + + return ( + <> +
    + + {results.approximateResultCount}{' '} + {pluralize('result', results.matchCount)} in {(results.elapsedMilliseconds / 1000).toFixed(2)}{' '} + seconds + {results.indexUnavailable && ' (index unavailable)'} + {results.limitHit && String.fromCharCode(160)} + + + {results.limitHit && onShowMoreResultsClick && ( + + )} +
    + + {excludedForksCount > 0 && ( +
    + + {excludedForksCount} forked{' '} + {pluralize('repository', excludedForksCount, 'repositories')} excluded + +
    + )} + + {excludedArchivedCount > 0 && ( +
    + + {excludedArchivedCount} archived{' '} + {pluralize('repository', excludedArchivedCount, 'repositories')} excluded + +
    + )} + + {results.missing.length > 0 && ( +
    repo.name).join('\n')} + > + + {results.missing.length}{' '} + {pluralize('repository', results.missing.length, 'repositories')} not found + +
    + )} + + {results.timedout.length > 0 && ( +
    repo.name).join('\n')} + > + + {results.timedout.length}{' '} + {pluralize('repository', results.timedout.length, 'repositories')} timed out (reload to try + again, or specify a longer "timeout:" in your query) + +
    + )} + + {results.cloning.length > 0 && ( +
    repo.name).join('\n')} + > + + {results.cloning.length}{' '} + {pluralize('repository', results.cloning.length, 'repositories')} cloning (reload to try again) + +
    + )} + + ) +}