import {useCallback, useMemo} from 'react'; import orderBy from 'lodash/orderBy'; // eslint-disable-next-line no-restricted-imports import {fetchTagValues} from 'sentry/actionCreators/tags'; import { SearchQueryBuilder, type SearchQueryBuilderProps, } from 'sentry/components/searchQueryBuilder'; import type {FilterKeySection} from 'sentry/components/searchQueryBuilder/types'; import {t} from 'sentry/locale'; import {SavedSearchType, type Tag, type TagCollection} from 'sentry/types/group'; import type {Organization} from 'sentry/types/organization'; import {getUtcDateString} from 'sentry/utils/dates'; import {FieldKind} from 'sentry/utils/fields'; import useApi from 'sentry/utils/useApi'; import usePageFilters from 'sentry/utils/usePageFilters'; import {Dataset} from 'sentry/views/alerts/rules/metric/types'; import {mergeAndSortTagValues} from 'sentry/views/issueDetails/utils'; import {makeGetIssueTagValues} from 'sentry/views/issueList/utils/getIssueTagValues'; import {useIssueListFilterKeys} from 'sentry/views/issueList/utils/useIssueListFilterKeys'; const getFilterKeySections = (tags: TagCollection): FilterKeySection[] => { const allTags: Tag[] = Object.values(tags).filter( tag => !EXCLUDED_TAGS.includes(tag.key) ); const issueFields = orderBy( allTags.filter(tag => tag.kind === FieldKind.ISSUE_FIELD), ['key'] ).map(tag => tag.key); const eventFields = orderBy( allTags.filter(tag => tag.kind === FieldKind.EVENT_FIELD), ['key'] ).map(tag => tag.key); const eventTags = orderBy( allTags.filter(tag => tag.kind === FieldKind.TAG), ['totalValues', 'key'], ['desc', 'asc'] ).map(tag => tag.key); return [ { value: FieldKind.ISSUE_FIELD, label: t('Issues'), children: issueFields, }, { value: FieldKind.EVENT_FIELD, label: t('Event Filters'), children: eventFields, }, { value: FieldKind.TAG, label: t('Event Tags'), children: eventTags, }, ]; }; interface Props extends Partial { organization: Organization; } const EXCLUDED_TAGS = ['environment']; function IssueListSearchBar({ organization, searchSource = 'issues', initialQuery = '', ...props }: Props) { const api = useApi(); const {selection: pageFilters} = usePageFilters(); const filterKeys = useIssueListFilterKeys(); const tagValueLoader = useCallback( async (key: string, search: string) => { const orgSlug = organization.slug; const projectIds = pageFilters.projects.map(id => id.toString()); const endpointParams = { start: pageFilters.datetime.start ? getUtcDateString(pageFilters.datetime.start) : undefined, end: pageFilters.datetime.end ? getUtcDateString(pageFilters.datetime.end) : undefined, statsPeriod: pageFilters.datetime.period, }; const fetchTagValuesPayload = { api, orgSlug, tagKey: key, search, projectIds, endpointParams, sort: '-count' as const, }; const [eventsDatasetValues, issuePlatformDatasetValues] = await Promise.all([ fetchTagValues({ ...fetchTagValuesPayload, dataset: Dataset.ERRORS, }), fetchTagValues({ ...fetchTagValuesPayload, dataset: Dataset.ISSUE_PLATFORM, }), ]); return mergeAndSortTagValues( eventsDatasetValues, issuePlatformDatasetValues, 'count' ); }, [ api, organization.slug, pageFilters.datetime.end, pageFilters.datetime.period, pageFilters.datetime.start, pageFilters.projects, ] ); const getTagValues = useMemo( () => makeGetIssueTagValues(tagValueLoader), [tagValueLoader] ); const filterKeySections = useMemo(() => { return getFilterKeySections(filterKeys); }, [filterKeys]); return ( ); } export default IssueListSearchBar;