@@ -12,19 +12,27 @@ import {PanelTable} from 'sentry/components/panels/panelTable';
1212import  SearchBar  from  'sentry/components/searchBar' ; 
1313import  SentryDocumentTitle  from  'sentry/components/sentryDocumentTitle' ; 
1414import  { TabList ,  TabPanels ,  Tabs }  from  'sentry/components/tabs' ; 
15+ import  { Tooltip }  from  'sentry/components/tooltip' ; 
1516import  { DEFAULT_DEBOUNCE_DURATION }  from  'sentry/constants' ; 
17+ import  { IconArrow ,  IconWarning }  from  'sentry/icons' ; 
1618import  { t ,  tct }  from  'sentry/locale' ; 
1719import  { space }  from  'sentry/styles/space' ; 
18- import  type  { MetricMeta ,  Organization ,  Project }  from  'sentry/types' ; 
19- import  { browserHistory }  from  'sentry/utils/browserHistory' ; 
20- import  { METRICS_DOCS_URL }  from  'sentry/utils/metrics/constants' ; 
20+ import  type  { MetricMeta }  from  'sentry/types/metrics' ; 
21+ import  type  { Organization }  from  'sentry/types/organization' ; 
22+ import  type  { Project }  from  'sentry/types/project' ; 
23+ import  { 
24+   DEFAULT_METRICS_CARDINALITY_LIMIT , 
25+   METRICS_DOCS_URL , 
26+ }  from  'sentry/utils/metrics/constants' ; 
2127import  { getReadableMetricType }  from  'sentry/utils/metrics/formatters' ; 
2228import  { formatMRI }  from  'sentry/utils/metrics/mri' ; 
2329import  { useBlockMetric }  from  'sentry/utils/metrics/useBlockMetric' ; 
30+ import  { useMetricsCardinality }  from  'sentry/utils/metrics/useMetricsCardinality' ; 
2431import  { useMetricsMeta }  from  'sentry/utils/metrics/useMetricsMeta' ; 
2532import  { decodeScalar }  from  'sentry/utils/queryString' ; 
2633import  routeTitleGen  from  'sentry/utils/routeTitle' ; 
2734import  { middleEllipsis }  from  'sentry/utils/string/middleEllipsis' ; 
35+ import  { useNavigate }  from  'sentry/utils/useNavigate' ; 
2836import  { useMetricsOnboardingSidebar }  from  'sentry/views/metrics/ddmOnboarding/useMetricsOnboardingSidebar' ; 
2937import  SettingsPageHeader  from  'sentry/views/settings/components/settingsPageHeader' ; 
3038import  TextBlock  from  'sentry/views/settings/components/text/textBlock' ; 
@@ -43,35 +51,68 @@ enum BlockingStatusTab {
4351  DISABLED  =  'disabled' , 
4452} 
4553
54+ type  MetricWithCardinality  =  MetricMeta  &  { cardinality : number } ; 
55+ 
4656function  ProjectMetrics ( { project,  location} : Props )  { 
47-   const  { data :  meta ,  isLoading }  =  useMetricsMeta ( 
57+   const  metricsMeta  =  useMetricsMeta ( 
4858    { projects : [ parseInt ( project . id ,  10 ) ] } , 
4959    [ 'custom' ] , 
5060    false 
5161  ) ; 
62+ 
63+   const  metricsCardinality  =  useMetricsCardinality ( { 
64+     project, 
65+   } ) ; 
66+ 
67+   const  sortedMeta  =  useMemo ( ( )  =>  { 
68+     if  ( ! metricsMeta . data )  { 
69+       return  [ ] ; 
70+     } 
71+ 
72+     if  ( ! metricsCardinality . data )  { 
73+       return  metricsMeta . data . map ( meta  =>  ( { ...meta ,  cardinality : 0 } ) ) ; 
74+     } 
75+ 
76+     return  metricsMeta . data 
77+       . map ( ( { mri,  ...rest } )  =>  { 
78+         return  { 
79+           mri, 
80+           cardinality : metricsCardinality . data [ mri ]  ??  0 , 
81+           ...rest , 
82+         } ; 
83+       } ) 
84+       . sort ( ( a ,  b )  =>  { 
85+         return  b . cardinality  -  a . cardinality ; 
86+       } )  as  MetricWithCardinality [ ] ; 
87+   } ,  [ metricsCardinality . data ,  metricsMeta . data ] ) ; 
88+ 
5289  const  query  =  decodeScalar ( location . query . query ,  '' ) . trim ( ) ; 
53-   const  { activateSidebar}  =  useMetricsOnboardingSidebar ( ) ; 
54-   const  [ selectedTab ,  setSelectedTab ]  =  useState ( BlockingStatusTab . ACTIVE ) ; 
5590
91+   const  metrics  =  sortedMeta . filter ( 
92+     ( { mri,  type,  unit} )  => 
93+       mri . includes ( query )  || 
94+       getReadableMetricType ( type ) . includes ( query )  || 
95+       unit . includes ( query ) 
96+   ) ; 
97+ 
98+   const  isLoading  =  metricsMeta . isLoading  ||  metricsCardinality . isLoading ; 
99+ 
100+   const  navigate  =  useNavigate ( ) ; 
56101  const  debouncedSearch  =  useMemo ( 
57102    ( )  => 
58103      debounce ( 
59104        ( searchQuery : string )  => 
60-           browserHistory . replace ( { 
105+           navigate ( { 
61106            pathname : location . pathname , 
62107            query : { ...location . query ,  query : searchQuery } , 
63108          } ) , 
64109        DEFAULT_DEBOUNCE_DURATION 
65110      ) , 
66-     [ location . pathname ,  location . query ] 
111+     [ location . pathname ,  location . query ,   navigate ] 
67112  ) ; 
68113
69-   const  metrics  =  meta . filter ( 
70-     ( { mri,  type,  unit} )  => 
71-       mri . includes ( query )  || 
72-       getReadableMetricType ( type ) . includes ( query )  || 
73-       unit . includes ( query ) 
74-   ) ; 
114+   const  { activateSidebar}  =  useMetricsOnboardingSidebar ( ) ; 
115+   const  [ selectedTab ,  setSelectedTab ]  =  useState ( BlockingStatusTab . ACTIVE ) ; 
75116
76117  return  ( 
77118    < Fragment > 
@@ -151,21 +192,27 @@ function ProjectMetrics({project, location}: Props) {
151192
152193interface  MetricsTableProps  { 
153194  isLoading : boolean ; 
154-   metrics : MetricMeta [ ] ; 
195+   metrics : MetricWithCardinality [ ] ; 
155196  project : Project ; 
156197  query : string ; 
157198} 
158199
159200function  MetricsTable ( { metrics,  isLoading,  query,  project} : MetricsTableProps )  { 
160201  const  blockMetricMutation  =  useBlockMetric ( project ) ; 
161202  const  { hasAccess}  =  useAccess ( { access : [ 'project:write' ] } ) ; 
203+   const  cardinalityLimit  = 
204+     project . relayCustomMetricCardinalityLimit  ??  DEFAULT_METRICS_CARDINALITY_LIMIT ; 
162205
163206  return  ( 
164207    < StyledPanelTable 
165208      headers = { [ 
166209        t ( 'Metric' ) , 
210+         < Cell  right  key = "cardinality" > 
211+           < IconArrow  size = "xs"  direction = "down"  /> 
212+ 
213+           { t ( 'Cardinality' ) } 
214+         </ Cell > , 
167215        < Cell  right  key = "type" > 
168-           { ' ' } 
169216          { t ( 'Type' ) } 
170217        </ Cell > , 
171218        < Cell  right  key = "unit" > 
@@ -183,8 +230,9 @@ function MetricsTable({metrics, isLoading, query, project}: MetricsTableProps) {
183230      isEmpty = { metrics . length  ===  0 } 
184231      isLoading = { isLoading } 
185232    > 
186-       { metrics . map ( ( { mri,  type,  unit,  blockingStatus} )  =>  { 
233+       { metrics . map ( ( { mri,  type,  unit,  cardinality ,   blockingStatus} )  =>  { 
187234        const  isBlocked  =  blockingStatus [ 0 ] ?. isBlocked ; 
235+         const  isCardinalityLimited  =  cardinality  >=  cardinalityLimit ; 
188236        return  ( 
189237          < Fragment  key = { mri } > 
190238            < Cell > 
@@ -196,6 +244,19 @@ function MetricsTable({metrics, isLoading, query, project}: MetricsTableProps) {
196244                { middleEllipsis ( formatMRI ( mri ) ,  65 ,  / \. | - | _ / ) } 
197245              </ Link > 
198246            </ Cell > 
247+             < Cell  right > 
248+               { isCardinalityLimited  &&  ( 
249+                 < Tooltip 
250+                   title = { tct ( 
251+                     'The tag cardinality of this metric exceeded our limit of [cardinalityLimit], which led to the data being dropped' , 
252+                     { cardinalityLimit} 
253+                   ) } 
254+                 > 
255+                   < StyledIconWarning  size = "sm"  color = "red300"  /> 
256+                 </ Tooltip > 
257+               ) } 
258+               { cardinality } 
259+             </ Cell > 
199260            < Cell  right > 
200261              < Tag > { getReadableMetricType ( type ) } </ Tag > 
201262            </ Cell > 
@@ -241,14 +302,22 @@ const SearchWrapper = styled('div')`
241302` ; 
242303
243304const  StyledPanelTable  =  styled ( PanelTable ) ` 
244-   grid-template-columns: 1fr repeat(3, minmax(115px,  min-content) ); 
305+   grid-template-columns: 1fr repeat(4,  min-content); 
245306` ; 
246307
247308const  Cell  =  styled ( 'div' ) < { right ?: boolean } > ` 
248309  display: flex; 
249310  align-items: center; 
250311  align-self: stretch; 
312+   gap: ${ space ( 0.5 ) }  
251313  justify-content: ${ p  =>  ( p . right  ? 'flex-end'  : 'flex-start' ) }  
252314` ; 
253315
316+ const  StyledIconWarning  =  styled ( IconWarning ) ` 
317+   margin-top: ${ space ( 0.5 ) }  
318+   &:hover { 
319+     cursor: pointer; 
320+   } 
321+ ` ; 
322+ 
254323export  default  ProjectMetrics ; 
0 commit comments