@@ -2,10 +2,12 @@ import {useEffect, useMemo, useState} from 'react';
22import styled from '@emotion/styled' ;
33import isEqual from 'lodash/isEqual' ;
44
5+ import type { SelectOption } from '@sentry/scraps/compactSelect' ;
56import { Flex } from '@sentry/scraps/layout' ;
67
78import { Button } from 'sentry/components/core/button' ;
89import { HybridFilter } from 'sentry/components/organizations/hybridFilter' ;
10+ import { getPredefinedValues } from 'sentry/components/searchQueryBuilder/tokens/filter/valueCombobox' ;
911import { MutableSearch } from 'sentry/components/searchSyntax/mutableSearch' ;
1012import { t } from 'sentry/locale' ;
1113import { space } from 'sentry/styles/space' ;
@@ -15,6 +17,10 @@ import usePageFilters from 'sentry/utils/usePageFilters';
1517import { type SearchBarData } from 'sentry/views/dashboards/datasetConfig/base' ;
1618import { getDatasetLabel } from 'sentry/views/dashboards/globalFilter/addFilter' ;
1719import FilterSelectorTrigger from 'sentry/views/dashboards/globalFilter/filterSelectorTrigger' ;
20+ import {
21+ getFieldDefinitionForDataset ,
22+ getFilterToken ,
23+ } from 'sentry/views/dashboards/globalFilter/utils' ;
1824import type { GlobalFilter } from 'sentry/views/dashboards/types' ;
1925
2026type FilterSelectorProps = {
@@ -48,6 +54,35 @@ function FilterSelector({
4854 const { dataset, tag} = globalFilter ;
4955 const { selection} = usePageFilters ( ) ;
5056
57+ // Retrieve full tag definition to check if it has predefined values
58+ const datasetFilterKeys = searchBarData . getFilterKeys ( ) ;
59+ const fullTag = datasetFilterKeys [ tag . key ] ;
60+ const fieldDefinition = getFieldDefinitionForDataset ( tag , dataset ) ;
61+
62+ const filterToken = useMemo (
63+ ( ) => getFilterToken ( globalFilter , fieldDefinition ) ,
64+ [ globalFilter , fieldDefinition ]
65+ ) ;
66+
67+ // Retrieve predefined values if the tag has any
68+ const predefinedValues = useMemo ( ( ) => {
69+ if ( ! filterToken ) {
70+ return null ;
71+ }
72+ const filterValue = filterToken . value . text ;
73+ return getPredefinedValues ( {
74+ key : fullTag ,
75+ filterValue,
76+ token : filterToken ,
77+ fieldDefinition,
78+ } ) ;
79+ } , [ fullTag , filterToken , fieldDefinition ] ) ;
80+
81+ // Only fetch values if the tag has no predefined values
82+ const shouldFetchValues = fullTag
83+ ? ! fullTag . predefined && predefinedValues === null
84+ : true ;
85+
5186 const baseQueryKey = useMemo (
5287 ( ) => [ 'global-dashboard-filters-tag-values' , tag , selection , searchQuery ] ,
5388 [ tag , selection , searchQuery ]
@@ -63,33 +98,48 @@ function FilterSelector({
6398 return result ?? [ ] ;
6499 } ,
65100 placeholderData : keepPreviousData ,
66- enabled : true ,
101+ enabled : shouldFetchValues ,
67102 staleTime : 5 * 60 * 1000 ,
68103 } ) ;
69104
70105 const { data : fetchedFilterValues , isFetching} = queryResult ;
71106
72107 const options = useMemo ( ( ) => {
73- const optionMap = new Map < string , { label : string ; value : string } > ( ) ;
74- const addOption = ( value : string ) => optionMap . set ( value , { label : value , value} ) ;
108+ const optionMap = new Map < string , SelectOption < string > > ( ) ;
109+ const fixedOptionMap = new Map < string , SelectOption < string > > ( ) ;
110+ const addOption = ( value : string , map : Map < string , SelectOption < string > > ) =>
111+ map . set ( value , { label : value , value} ) ;
75112
76- // Filter values fetched using getTagValues
77- fetchedFilterValues ?. forEach ( addOption ) ;
78113 // Filter values in the global filter
79- activeFilterValues . forEach ( addOption ) ;
80- // Staged filter values inside the filter selector
81- stagedFilterValues . forEach ( addOption ) ;
114+ activeFilterValues . forEach ( value => addOption ( value , optionMap ) ) ;
115+
116+ // Predefined values
117+ predefinedValues ?. forEach ( suggestionSection => {
118+ suggestionSection . suggestions . forEach ( suggestion =>
119+ addOption ( suggestion . value , optionMap )
120+ ) ;
121+ } ) ;
122+ // Filter values fetched using getTagValues
123+ fetchedFilterValues ?. forEach ( value => addOption ( value , optionMap ) ) ;
82124
83125 // Allow setting a custom filter value based on search input
84- if ( searchQuery ) {
85- addOption ( searchQuery ) ;
126+ if ( searchQuery && ! optionMap . has ( searchQuery ) ) {
127+ addOption ( searchQuery , fixedOptionMap ) ;
86128 }
87-
88- // Reversing the order allows effectively deduplicating the values
89- // and avoid losing their original order from the fetched results
90- // (e.g. without this, all staged values would be grouped at the top of the list)
91- return Array . from ( optionMap . values ( ) ) . reverse ( ) ;
92- } , [ fetchedFilterValues , activeFilterValues , stagedFilterValues , searchQuery ] ) ;
129+ // Staged filter values inside the filter selector
130+ stagedFilterValues . forEach ( value => {
131+ if ( ! optionMap . has ( value ) ) {
132+ addOption ( value , fixedOptionMap ) ;
133+ }
134+ } ) ;
135+ return [ ...Array . from ( fixedOptionMap . values ( ) ) , ...Array . from ( optionMap . values ( ) ) ] ;
136+ } , [
137+ fetchedFilterValues ,
138+ predefinedValues ,
139+ activeFilterValues ,
140+ stagedFilterValues ,
141+ searchQuery ,
142+ ] ) ;
93143
94144 const handleChange = ( opts : string [ ] ) => {
95145 if ( isEqual ( opts , activeFilterValues ) ) {
@@ -126,7 +176,8 @@ function FilterSelector({
126176 onStagedValueChange = { value => {
127177 setStagedFilterValues ( value ) ;
128178 } }
129- sizeLimit = { 10 }
179+ sizeLimit = { 30 }
180+ menuWidth = { 400 }
130181 onClose = { ( ) => {
131182 setSearchQuery ( '' ) ;
132183 setStagedFilterValues ( [ ] ) ;
0 commit comments