From fe14ec30ef0c4e5e349e09018a5676305a38916f Mon Sep 17 00:00:00 2001 From: nsdeschenes Date: Thu, 19 Feb 2026 14:06:13 -0400 Subject: [PATCH 01/10] chore(explore): Replace useTraceItemAttributesWithConfig with useTraceItemAttributes Rename deprecated useTraceItemAttributesWithConfig calls to useTraceItemAttributes in all consumers and remove the deprecated export. These callers already pass config objects directly. --- static/app/components/preprod/preprodSearchBar.tsx | 8 ++++---- static/app/views/dashboards/datasetConfig/logs.tsx | 11 ++++------- .../app/views/dashboards/datasetConfig/spans.tsx | 8 ++++---- .../dashboards/datasetConfig/traceMetrics.tsx | 14 +++++++------- .../explore/contexts/traceItemAttributeContext.tsx | 12 ------------ 5 files changed, 19 insertions(+), 34 deletions(-) diff --git a/static/app/components/preprod/preprodSearchBar.tsx b/static/app/components/preprod/preprodSearchBar.tsx index 386def1f835c8f..537eeff4996ecb 100644 --- a/static/app/components/preprod/preprodSearchBar.tsx +++ b/static/app/components/preprod/preprodSearchBar.tsx @@ -4,7 +4,7 @@ import type {TagCollection} from 'sentry/types/group'; import useOrganization from 'sentry/utils/useOrganization'; import {TraceItemSearchQueryBuilder} from 'sentry/views/explore/components/traceItemSearchQueryBuilder'; import {HIDDEN_PREPROD_ATTRIBUTES} from 'sentry/views/explore/constants'; -import {useTraceItemAttributesWithConfig} from 'sentry/views/explore/contexts/traceItemAttributeContext'; +import {useTraceItemAttributes} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {TraceItemDataset} from 'sentry/views/explore/types'; interface PreprodSearchBarProps { @@ -80,11 +80,11 @@ export function PreprodSearchBar({ const hiddenKeys = allowedKeys ? undefined : HIDDEN_PREPROD_ATTRIBUTES; const {attributes: rawStringAttributes, secondaryAliases: rawStringSecondaryAliases} = - useTraceItemAttributesWithConfig(traceItemAttributeConfig, 'string', hiddenKeys); + useTraceItemAttributes(traceItemAttributeConfig, 'string', hiddenKeys); const {attributes: rawNumberAttributes, secondaryAliases: rawNumberSecondaryAliases} = - useTraceItemAttributesWithConfig(traceItemAttributeConfig, 'number', hiddenKeys); + useTraceItemAttributes(traceItemAttributeConfig, 'number', hiddenKeys); const {attributes: rawBooleanAttributes, secondaryAliases: rawBooleanSecondaryAliases} = - useTraceItemAttributesWithConfig(traceItemAttributeConfig, 'boolean', hiddenKeys); + useTraceItemAttributes(traceItemAttributeConfig, 'boolean', hiddenKeys); const stringAttributes = useMemo( () => diff --git a/static/app/views/dashboards/datasetConfig/logs.tsx b/static/app/views/dashboards/datasetConfig/logs.tsx index 62642221f9fff8..3946fd9ba6b645 100644 --- a/static/app/views/dashboards/datasetConfig/logs.tsx +++ b/static/app/views/dashboards/datasetConfig/logs.tsx @@ -39,10 +39,7 @@ import { TraceItemSearchQueryBuilder, useTraceItemSearchQueryBuilderProps, } from 'sentry/views/explore/components/traceItemSearchQueryBuilder'; -import { - useTraceItemAttributes, - useTraceItemAttributesWithConfig, -} from 'sentry/views/explore/contexts/traceItemAttributeContext'; +import {useTraceItemAttributes} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {isLogsEnabled} from 'sentry/views/explore/logs/isLogsEnabled'; import {LOG_AGGREGATES} from 'sentry/views/explore/logs/logsToolbar'; import {TraceItemDataset} from 'sentry/views/explore/types'; @@ -160,11 +157,11 @@ function useLogsSearchBarDataProvider(props: SearchBarDataProviderProps): Search }; const {attributes: stringAttributes, secondaryAliases: stringSecondaryAliases} = - useTraceItemAttributesWithConfig(traceItemAttributeConfig, 'string'); + useTraceItemAttributes(traceItemAttributeConfig, 'string'); const {attributes: numberAttributes, secondaryAliases: numberSecondaryAliases} = - useTraceItemAttributesWithConfig(traceItemAttributeConfig, 'number'); + useTraceItemAttributes(traceItemAttributeConfig, 'number'); const {attributes: booleanAttributes, secondaryAliases: booleanSecondaryAliases} = - useTraceItemAttributesWithConfig(traceItemAttributeConfig, 'boolean'); + useTraceItemAttributes(traceItemAttributeConfig, 'boolean'); const {filterKeys, filterKeySections, getTagValues} = useTraceItemSearchQueryBuilderProps({ diff --git a/static/app/views/dashboards/datasetConfig/spans.tsx b/static/app/views/dashboards/datasetConfig/spans.tsx index fafd5daf17793f..0f6d4202812bbb 100644 --- a/static/app/views/dashboards/datasetConfig/spans.tsx +++ b/static/app/views/dashboards/datasetConfig/spans.tsx @@ -59,7 +59,7 @@ import { import type {FieldValueOption} from 'sentry/views/discover/table/queryField'; import {FieldValueKind} from 'sentry/views/discover/table/types'; import {useTraceItemSearchQueryBuilderProps} from 'sentry/views/explore/components/traceItemSearchQueryBuilder'; -import {useTraceItemAttributesWithConfig} from 'sentry/views/explore/contexts/traceItemAttributeContext'; +import {useTraceItemAttributes} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {TraceItemDataset} from 'sentry/views/explore/types'; import {SpanFields} from 'sentry/views/insights/types'; import {TraceViewSources} from 'sentry/views/performance/newTraceDetails/traceHeader/breadcrumbs'; @@ -143,11 +143,11 @@ function useSpansSearchBarDataProvider(props: SearchBarDataProviderProps): Searc }; const {attributes: stringAttributes, secondaryAliases: stringSecondaryAliases} = - useTraceItemAttributesWithConfig(traceItemAttributeConfig, 'string'); + useTraceItemAttributes(traceItemAttributeConfig, 'string'); const {attributes: numberAttributes, secondaryAliases: numberSecondaryAliases} = - useTraceItemAttributesWithConfig(traceItemAttributeConfig, 'number'); + useTraceItemAttributes(traceItemAttributeConfig, 'number'); const {attributes: booleanAttributes, secondaryAliases: booleanSecondaryAliases} = - useTraceItemAttributesWithConfig(traceItemAttributeConfig, 'boolean'); + useTraceItemAttributes(traceItemAttributeConfig, 'boolean'); const {filterKeys, filterKeySections, getTagValues} = useTraceItemSearchQueryBuilderProps({ diff --git a/static/app/views/dashboards/datasetConfig/traceMetrics.tsx b/static/app/views/dashboards/datasetConfig/traceMetrics.tsx index 793e32f59bf8cf..aa1e08a6defe04 100644 --- a/static/app/views/dashboards/datasetConfig/traceMetrics.tsx +++ b/static/app/views/dashboards/datasetConfig/traceMetrics.tsx @@ -42,7 +42,7 @@ import { TraceItemSearchQueryBuilder, useTraceItemSearchQueryBuilderProps, } from 'sentry/views/explore/components/traceItemSearchQueryBuilder'; -import {useTraceItemAttributesWithConfig} from 'sentry/views/explore/contexts/traceItemAttributeContext'; +import {useTraceItemAttributes} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {HiddenTraceMetricSearchFields} from 'sentry/views/explore/metrics/constants'; import {createTraceMetricFilter} from 'sentry/views/explore/metrics/utils'; import {TraceItemDataset} from 'sentry/views/explore/types'; @@ -90,19 +90,19 @@ function TraceMetricsSearchBar({ }; const {attributes: stringAttributes, secondaryAliases: stringSecondaryAliases} = - useTraceItemAttributesWithConfig( + useTraceItemAttributes( traceItemAttributeConfig, 'string', HiddenTraceMetricSearchFields ); const {attributes: numberAttributes, secondaryAliases: numberSecondaryAliases} = - useTraceItemAttributesWithConfig( + useTraceItemAttributes( traceItemAttributeConfig, 'number', HiddenTraceMetricSearchFields ); const {attributes: booleanAttributes, secondaryAliases: booleanSecondaryAliases} = - useTraceItemAttributesWithConfig( + useTraceItemAttributes( traceItemAttributeConfig, 'boolean', HiddenTraceMetricSearchFields @@ -146,11 +146,11 @@ function useTraceMetricsSearchBarDataProvider( }; const {attributes: stringAttributes, secondaryAliases: stringSecondaryAliases} = - useTraceItemAttributesWithConfig(traceItemAttributeConfig, 'string'); + useTraceItemAttributes(traceItemAttributeConfig, 'string'); const {attributes: numberAttributes, secondaryAliases: numberSecondaryAliases} = - useTraceItemAttributesWithConfig(traceItemAttributeConfig, 'number'); + useTraceItemAttributes(traceItemAttributeConfig, 'number'); const {attributes: booleanAttributes, secondaryAliases: booleanSecondaryAliases} = - useTraceItemAttributesWithConfig(traceItemAttributeConfig, 'boolean'); + useTraceItemAttributes(traceItemAttributeConfig, 'boolean'); const {filterKeys, filterKeySections, getTagValues} = useTraceItemSearchQueryBuilderProps({ diff --git a/static/app/views/explore/contexts/traceItemAttributeContext.tsx b/static/app/views/explore/contexts/traceItemAttributeContext.tsx index 540083bd9dcd42..44c37cf0fe98c4 100644 --- a/static/app/views/explore/contexts/traceItemAttributeContext.tsx +++ b/static/app/views/explore/contexts/traceItemAttributeContext.tsx @@ -336,18 +336,6 @@ export function useTraceItemAttributes( return processTraceItemAttributes(typedAttributesResult, args.type, args.hiddenKeys); } -/** - * @deprecated Use `useTraceItemAttributes` with a config argument instead. - */ -export function useTraceItemAttributesWithConfig( - config: TraceItemAttributeConfig, - type?: TraceItemAttributeType, - hiddenKeys?: string[] -) { - const typedAttributesResult = useTraceItemAttributeConfig(config); - return processTraceItemAttributes(typedAttributesResult, type, hiddenKeys); -} - function getDefaultStringAttributes(itemType: TraceItemDataset) { if (itemType === TraceItemDataset.SPANS) { return SENTRY_SPAN_STRING_TAGS; From 1c0b605acecce8db36102ec958981bea549f918e Mon Sep 17 00:00:00 2001 From: nsdeschenes Date: Thu, 19 Feb 2026 14:10:39 -0400 Subject: [PATCH 02/10] chore(explore): Migrate useTraceItemAttributes callers to pass config directly Migrate callers that relied on TraceItemAttributeProvider context to pass TraceItemAttributeConfig directly. Move search state into toolbar components. Remove provider wrappers that only existed to serve these callers. --- .../events/ourlogs/ourlogsDrawer.tsx | 11 ++- .../events/ourlogs/ourlogsSection.tsx | 28 ++++---- .../views/alerts/rules/metric/eapField.tsx | 20 +++++- .../rules/metric/ruleConditionsForm.tsx | 29 ++++---- .../views/dashboards/datasetConfig/logs.tsx | 11 ++- .../datasetConfig/mobileAppSize.tsx | 13 +++- static/app/views/explore/logs/logsTab.tsx | 16 +++-- static/app/views/explore/logs/logsToolbar.tsx | 72 +++++++++---------- .../views/replays/detail/ourlogs/index.tsx | 26 ++++--- 9 files changed, 131 insertions(+), 95 deletions(-) diff --git a/static/app/components/events/ourlogs/ourlogsDrawer.tsx b/static/app/components/events/ourlogs/ourlogsDrawer.tsx index 8cbafe343914e7..c89db1aba1af8d 100644 --- a/static/app/components/events/ourlogs/ourlogsDrawer.tsx +++ b/static/app/components/events/ourlogs/ourlogsDrawer.tsx @@ -61,12 +61,17 @@ export function OurlogsDrawer({ const setLogsQuery = useSetQueryParamsQuery(); const logsSearch = useQueryParamsSearch(); + const logsAttributeConfig = useMemo( + () => ({traceItemType: TraceItemDataset.LOGS, enabled: true}), + [] + ); + const {attributes: stringAttributes, secondaryAliases: stringSecondaryAliases} = - useTraceItemAttributes('string'); + useTraceItemAttributes(logsAttributeConfig, 'string'); const {attributes: numberAttributes, secondaryAliases: numberSecondaryAliases} = - useTraceItemAttributes('number'); + useTraceItemAttributes(logsAttributeConfig, 'number'); const {attributes: booleanAttributes, secondaryAliases: booleanSecondaryAliases} = - useTraceItemAttributes('boolean'); + useTraceItemAttributes(logsAttributeConfig, 'boolean'); const tracesItemSearchQueryBuilderProps = { initialQuery: logsSearch.formatString(), diff --git a/static/app/components/events/ourlogs/ourlogsSection.tsx b/static/app/components/events/ourlogs/ourlogsSection.tsx index 3a9a890816cd36..f2dfec562beb8a 100644 --- a/static/app/components/events/ourlogs/ourlogsSection.tsx +++ b/static/app/components/events/ourlogs/ourlogsSection.tsx @@ -21,12 +21,10 @@ import { LogsPageDataProvider, useLogsPageDataQueryResult, } from 'sentry/views/explore/contexts/logs/logsPageData'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {LOGS_DRAWER_QUERY_PARAM} from 'sentry/views/explore/logs/constants'; import {LogsQueryParamsProvider} from 'sentry/views/explore/logs/logsQueryParamsProvider'; import {LogRowContent} from 'sentry/views/explore/logs/tables/logsTableRow'; import {useQueryParamsSearch} from 'sentry/views/explore/queryParams/context'; -import {TraceItemDataset} from 'sentry/views/explore/types'; import {SectionKey} from 'sentry/views/issueDetails/streamline/context'; import {InterimSection} from 'sentry/views/issueDetails/streamline/interimSection'; @@ -116,20 +114,18 @@ function OurlogsSectionContent({ freeze={traceId ? {traceId} : undefined} > - - - + ), diff --git a/static/app/views/alerts/rules/metric/eapField.tsx b/static/app/views/alerts/rules/metric/eapField.tsx index 7d5af166c25fe3..ad1a84dbb45a9d 100644 --- a/static/app/views/alerts/rules/metric/eapField.tsx +++ b/static/app/views/alerts/rules/metric/eapField.tsx @@ -84,9 +84,23 @@ function EAPField({aggregate, onChange, eventTypes}: Props) { arguments: undefined, }; - const {attributes: storedNumberTags} = useTraceItemAttributes('number'); - const {attributes: storedStringTags} = useTraceItemAttributes('string'); - const {attributes: storedBooleanTags} = useTraceItemAttributes('boolean'); + const traceItemAttributeConfig = useMemo( + () => ({traceItemType, enabled: true}), + [traceItemType] + ); + + const {attributes: storedNumberTags} = useTraceItemAttributes( + traceItemAttributeConfig, + 'number' + ); + const {attributes: storedStringTags} = useTraceItemAttributes( + traceItemAttributeConfig, + 'string' + ); + const {attributes: storedBooleanTags} = useTraceItemAttributes( + traceItemAttributeConfig, + 'boolean' + ); const storedTags = useMemo(() => { return aggregation === AggregationKey.COUNT_UNIQUE diff --git a/static/app/views/alerts/rules/metric/ruleConditionsForm.tsx b/static/app/views/alerts/rules/metric/ruleConditionsForm.tsx index 29e8f1cae901b8..750708f87f3c37 100644 --- a/static/app/views/alerts/rules/metric/ruleConditionsForm.tsx +++ b/static/app/views/alerts/rules/metric/ruleConditionsForm.tsx @@ -1,4 +1,4 @@ -import {Fragment, PureComponent} from 'react'; +import {Fragment, PureComponent, useMemo} from 'react'; import {css} from '@emotion/react'; import styled from '@emotion/styled'; import omit from 'lodash/omit'; @@ -71,10 +71,7 @@ import { import {getTraceItemTypeForDatasetAndEventType} from 'sentry/views/alerts/wizard/utils'; import {SESSIONS_FILTER_TAGS} from 'sentry/views/dashboards/widgetBuilder/releaseWidget/fields'; import {TraceItemSearchQueryBuilder} from 'sentry/views/explore/components/traceItemSearchQueryBuilder'; -import { - TraceItemAttributeProvider, - useTraceItemAttributes, -} from 'sentry/views/explore/contexts/traceItemAttributeContext'; +import {useTraceItemAttributes} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {TraceItemDataset} from 'sentry/views/explore/types'; import { deprecateTransactionAlerts, @@ -651,14 +648,7 @@ class RuleConditionsForm extends PureComponent { ) : ( - + {isExtrapolatedChartData && ( { }} - + )} @@ -868,12 +858,17 @@ function EAPSearchQueryBuilderWithContext({ project, traceItemType, }: EAPSearchQueryBuilderWithContextProps) { + const traceItemAttributeConfig = useMemo( + () => ({traceItemType, enabled: true, projects: [project]}), + [traceItemType, project] + ); + const {attributes: numberAttributes, secondaryAliases: numberSecondaryAliases} = - useTraceItemAttributes('number'); + useTraceItemAttributes(traceItemAttributeConfig, 'number'); const {attributes: stringAttributes, secondaryAliases: stringSecondaryAliases} = - useTraceItemAttributes('string'); + useTraceItemAttributes(traceItemAttributeConfig, 'string'); const {attributes: booleanAttributes, secondaryAliases: booleanSecondaryAliases} = - useTraceItemAttributes('boolean'); + useTraceItemAttributes(traceItemAttributeConfig, 'boolean'); const tracesItemSearchQueryBuilderProps = { initialQuery, diff --git a/static/app/views/dashboards/datasetConfig/logs.tsx b/static/app/views/dashboards/datasetConfig/logs.tsx index 3946fd9ba6b645..4554c68bde47e5 100644 --- a/static/app/views/dashboards/datasetConfig/logs.tsx +++ b/static/app/views/dashboards/datasetConfig/logs.tsx @@ -117,15 +117,20 @@ function LogsSearchBar({ WidgetBuilderSearchBarProps, 'widgetQuery' | 'onSearch' | 'portalTarget' | 'onClose' >) { + const organization = useOrganization(); const { selection: {projects}, } = usePageFilters(); + const logsAttributeConfig = { + traceItemType: TraceItemDataset.LOGS, + enabled: isLogsEnabled(organization), + }; const {attributes: stringAttributes, secondaryAliases: stringSecondaryAliases} = - useTraceItemAttributes('string'); + useTraceItemAttributes(logsAttributeConfig, 'string'); const {attributes: numberAttributes, secondaryAliases: numberSecondaryAliases} = - useTraceItemAttributes('number'); + useTraceItemAttributes(logsAttributeConfig, 'number'); const {attributes: booleanAttributes, secondaryAliases: booleanSecondaryAliases} = - useTraceItemAttributes('boolean'); + useTraceItemAttributes(logsAttributeConfig, 'boolean'); return ( ({traceItemType: TraceItemDataset.LOGS, enabled: true}), + [] + ); + const { attributes: stringAttributes, isLoading: stringAttributesLoading, secondaryAliases: stringSecondaryAliases, - } = useTraceItemAttributes('string', HiddenLogSearchFields); + } = useTraceItemAttributes(logsAttributeConfig, 'string', HiddenLogSearchFields); const { attributes: numberAttributes, isLoading: numberAttributesLoading, secondaryAliases: numberSecondaryAliases, - } = useTraceItemAttributes('number', HiddenLogSearchFields); + } = useTraceItemAttributes(logsAttributeConfig, 'number', HiddenLogSearchFields); const { attributes: booleanAttributes, isLoading: booleanAttributesLoading, secondaryAliases: booleanSecondaryAliases, - } = useTraceItemAttributes('boolean', HiddenLogSearchFields); + } = useTraceItemAttributes(logsAttributeConfig, 'boolean', HiddenLogSearchFields); const averageLogsPerSecond = calculateAverageLogsPerSecond(timeseriesResult); diff --git a/static/app/views/explore/logs/logsToolbar.tsx b/static/app/views/explore/logs/logsToolbar.tsx index 3b7c4db0c253fb..24cff369e2a9ca 100644 --- a/static/app/views/explore/logs/logsToolbar.tsx +++ b/static/app/views/explore/logs/logsToolbar.tsx @@ -24,10 +24,7 @@ import { } from 'sentry/views/explore/components/toolbar/toolbarVisualize'; import {TypeBadge} from 'sentry/views/explore/components/typeBadge'; import {DragNDropContext} from 'sentry/views/explore/contexts/dragNDropContext'; -import { - TraceItemAttributeProvider, - useTraceItemAttributes, -} from 'sentry/views/explore/contexts/traceItemAttributeContext'; +import {useTraceItemAttributes} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import { OurLogKnownFieldKey, type OurLogsAggregate, @@ -99,59 +96,44 @@ export const LOG_AGGREGATES: Array> = [ export function LogsToolbar() { return ( - - + + ); } -function LogsToolbarVisualizeWrapper() { +function ToolbarVisualize() { const [search, setSearch] = useState(undefined); const debouncedSearch = useDebouncedValue(search, 200); - return ( - - setSearch(undefined)} /> - - ); -} -function LogsToolbarGroupByWrapper() { - const [search, setSearch] = useState(undefined); - const debouncedSearch = useDebouncedValue(search, 200); - return ( - - setSearch(undefined)} /> - + const logsAttributeConfig = useMemo( + () => ({ + traceItemType: TraceItemDataset.LOGS, + enabled: true, + search: debouncedSearch, + }), + [debouncedSearch] ); -} -interface LogsToolbarProps { - onClose: () => void; - onSearch: (search: string) => void; -} - -function ToolbarVisualize({onSearch, onClose}: LogsToolbarProps) { const {attributes: stringTags, isLoading: stringTagsLoading} = useTraceItemAttributes( + logsAttributeConfig, 'string', HiddenLogSearchFields ); const {attributes: numberTags, isLoading: numberTagsLoading} = useTraceItemAttributes( + logsAttributeConfig, 'number', HiddenLogSearchFields ); const {attributes: booleanTags, isLoading: booleanTagsLoading} = useTraceItemAttributes( + logsAttributeConfig, 'boolean', HiddenLogSearchFields ); + const onSearch = setSearch; + const onClose = useCallback(() => setSearch(undefined), []); + const sortedNumberKeys: string[] = useMemo(() => { const keys = Object.keys(numberTags); keys.sort(); @@ -404,20 +386,38 @@ function VisualizeDropdown({ ); } -function ToolbarGroupBy({onSearch, onClose}: LogsToolbarProps) { +function ToolbarGroupBy() { + const [search, setSearch] = useState(undefined); + const debouncedSearch = useDebouncedValue(search, 200); + + const logsAttributeConfig = useMemo( + () => ({ + traceItemType: TraceItemDataset.LOGS, + enabled: true, + search: debouncedSearch, + }), + [debouncedSearch] + ); + const {attributes: numberTags, isLoading: numberTagsLoading} = useTraceItemAttributes( + logsAttributeConfig, 'number', HiddenLogSearchFields ); const {attributes: stringTags, isLoading: stringTagsLoading} = useTraceItemAttributes( + logsAttributeConfig, 'string', HiddenLogSearchFields ); const {attributes: booleanTags, isLoading: booleanTagsLoading} = useTraceItemAttributes( + logsAttributeConfig, 'boolean', HiddenLogSearchFields ); + const onSearch = setSearch; + const onClose = useCallback(() => setSearch(undefined), []); + const groupBys = useQueryParamsGroupBys(); const setGroupBys = useSetQueryParamsGroupBys(); diff --git a/static/app/views/replays/detail/ourlogs/index.tsx b/static/app/views/replays/detail/ourlogs/index.tsx index 7b18c658bb1c46..3079704d0f95e8 100644 --- a/static/app/views/replays/detail/ourlogs/index.tsx +++ b/static/app/views/replays/detail/ourlogs/index.tsx @@ -15,10 +15,7 @@ import { useLogsPageData, } from 'sentry/views/explore/contexts/logs/logsPageData'; import {logsTimestampAscendingSortBy} from 'sentry/views/explore/contexts/logs/sortBys'; -import { - TraceItemAttributeProvider, - useTraceItemAttributes, -} from 'sentry/views/explore/contexts/traceItemAttributeContext'; +import {useTraceItemAttributes} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {LogsQueryParamsProvider} from 'sentry/views/explore/logs/logsQueryParamsProvider'; import { LoadingRenderer, @@ -62,9 +59,7 @@ export default function OurLogs() { }} > - - - + ); @@ -75,10 +70,21 @@ interface OurLogsContentProps { startTimestampMs: number; } +const logsAttributeConfig = {traceItemType: TraceItemDataset.LOGS, enabled: true}; + function OurLogsContent({replayId, startTimestampMs}: OurLogsContentProps) { - const {attributes: stringAttributes} = useTraceItemAttributes('string'); - const {attributes: numberAttributes} = useTraceItemAttributes('number'); - const {attributes: booleanAttributes} = useTraceItemAttributes('boolean'); + const {attributes: stringAttributes} = useTraceItemAttributes( + logsAttributeConfig, + 'string' + ); + const {attributes: numberAttributes} = useTraceItemAttributes( + logsAttributeConfig, + 'number' + ); + const {attributes: booleanAttributes} = useTraceItemAttributes( + logsAttributeConfig, + 'boolean' + ); const scrollContainerRef = useRef(null); const {currentTime, setCurrentTime} = useReplayContext(); From 36d78a8be986f0747d225ecff1131a2e0dcd2215 Mon Sep 17 00:00:00 2001 From: nsdeschenes Date: Thu, 19 Feb 2026 14:21:50 -0400 Subject: [PATCH 03/10] chore(explore): Update useTraceItemTags to require config, migrate explore callers Update spanTagsContext's useTraceItemTags to accept a TraceItemAttributeConfig as the first argument. Migrate all explore callers to pass config directly instead of relying on the context provider. Key changes: - spanTagsContext.tsx: require config param, pass through to useTraceItemAttributes - useSortByFields.tsx: accept config param, callers pass it - toolbar components (visualize, groupBy): move search state into component, remove TraceItemAttributeProvider wrapper - spansTabSearchSection.tsx: pass config to all useTraceItemTags calls, remove provider wrapper for cross-event search bars - tables, multiquery, and other explore callers: pass spansConfig --- .../performance/spanSearchQueryBuilder.tsx | 7 ++- .../toolbarVisualize/visualizeEquation.tsx | 8 ++- .../explore/contexts/spanTagsContext.tsx | 7 ++- .../views/explore/hooks/useSortByFields.tsx | 10 ++-- .../queryConstructors/groupBy.tsx | 7 ++- .../queryConstructors/sortBy.tsx | 13 +++- .../queryConstructors/visualize.tsx | 7 ++- .../queryVisualizations/table.tsx | 15 +++-- .../explore/spans/spansTabSearchSection.tsx | 55 ++++++++++------- .../views/explore/tables/aggregatesTable.tsx | 8 ++- static/app/views/explore/tables/index.tsx | 8 ++- .../app/views/explore/tables/spansTable.tsx | 8 ++- .../views/explore/toolbar/toolbarGroupBy.tsx | 60 +++++++------------ .../views/explore/toolbar/toolbarSortBy.tsx | 7 +++ .../explore/toolbar/toolbarVisualize.tsx | 54 +++++++---------- .../insights/pages/conversations/overview.tsx | 19 ++++-- 16 files changed, 162 insertions(+), 131 deletions(-) diff --git a/static/app/components/performance/spanSearchQueryBuilder.tsx b/static/app/components/performance/spanSearchQueryBuilder.tsx index 10bedfcd73e5c5..a6abb159ddea31 100644 --- a/static/app/components/performance/spanSearchQueryBuilder.tsx +++ b/static/app/components/performance/spanSearchQueryBuilder.tsx @@ -67,12 +67,13 @@ export function useSpanSearchQueryBuilderProps(props: UseSpanSearchQueryBuilderP spanSearchQueryBuilderProps: TraceItemSearchQueryBuilderProps; spanSearchQueryBuilderProviderProps: UseTraceItemSearchQueryBuilderPropsReturnType; } { + const spansConfig = {traceItemType: TraceItemDataset.SPANS, enabled: true}; const {tags: numberAttributes, secondaryAliases: numberSecondaryAliases} = - useTraceItemTags('number'); + useTraceItemTags(spansConfig, 'number'); const {tags: stringAttributes, secondaryAliases: stringSecondaryAliases} = - useTraceItemTags('string'); + useTraceItemTags(spansConfig, 'string'); const {tags: booleanAttributes, secondaryAliases: booleanSecondaryAliases} = - useTraceItemTags('boolean'); + useTraceItemTags(spansConfig, 'boolean'); const stringAttributesWithSemver = useMemo(() => { if (SpanFields.RELEASE in stringAttributes) { diff --git a/static/app/views/explore/components/toolbar/toolbarVisualize/visualizeEquation.tsx b/static/app/views/explore/components/toolbar/toolbarVisualize/visualizeEquation.tsx index 5b125f82adce8c..143495835b334f 100644 --- a/static/app/views/explore/components/toolbar/toolbarVisualize/visualizeEquation.tsx +++ b/static/app/views/explore/components/toolbar/toolbarVisualize/visualizeEquation.tsx @@ -18,6 +18,7 @@ import {ToolbarRow} from 'sentry/views/explore/components/toolbar/styles'; import {useTraceItemTags} from 'sentry/views/explore/contexts/spanTagsContext'; import {useExploreSuggestedAttribute} from 'sentry/views/explore/hooks/useExploreSuggestedAttribute'; import {Visualize} from 'sentry/views/explore/queryParams/visualize'; +import {TraceItemDataset} from 'sentry/views/explore/types'; interface VisualizeEquationProps { onDelete: () => void; @@ -34,9 +35,10 @@ export function VisualizeEquation({ }: VisualizeEquationProps) { const expression = stripEquationPrefix(visualize.yAxis); - const {tags: numberTags} = useTraceItemTags('number'); - const {tags: stringTags} = useTraceItemTags('string'); - const {tags: booleanTags} = useTraceItemTags('boolean'); + const spansConfig = {traceItemType: TraceItemDataset.SPANS, enabled: true}; + const {tags: numberTags} = useTraceItemTags(spansConfig, 'number'); + const {tags: stringTags} = useTraceItemTags(spansConfig, 'string'); + const {tags: booleanTags} = useTraceItemTags(spansConfig, 'boolean'); const functionArguments: FunctionArgument[] = useMemo(() => { return [ diff --git a/static/app/views/explore/contexts/spanTagsContext.tsx b/static/app/views/explore/contexts/spanTagsContext.tsx index 060fd55dab1f42..acc5eeb551ee39 100644 --- a/static/app/views/explore/contexts/spanTagsContext.tsx +++ b/static/app/views/explore/contexts/spanTagsContext.tsx @@ -1,10 +1,15 @@ -import {useTraceItemAttributes} from 'sentry/views/explore/contexts/traceItemAttributeContext'; +import { + useTraceItemAttributes, + type TraceItemAttributeConfig, +} from 'sentry/views/explore/contexts/traceItemAttributeContext'; export function useTraceItemTags( + config: TraceItemAttributeConfig, type?: 'number' | 'string' | 'boolean', hiddenKeys?: string[] ) { const {attributes, isLoading, secondaryAliases} = useTraceItemAttributes( + config, type, hiddenKeys ); diff --git a/static/app/views/explore/hooks/useSortByFields.tsx b/static/app/views/explore/hooks/useSortByFields.tsx index 07fed505a0f496..2b2f184f1cfe3d 100644 --- a/static/app/views/explore/hooks/useSortByFields.tsx +++ b/static/app/views/explore/hooks/useSortByFields.tsx @@ -7,18 +7,20 @@ import {classifyTagKey, prettifyTagKey} from 'sentry/utils/fields'; import {TypeBadge} from 'sentry/views/explore/components/typeBadge'; import {Mode} from 'sentry/views/explore/contexts/pageParamsContext/mode'; import {useTraceItemTags} from 'sentry/views/explore/contexts/spanTagsContext'; +import type {TraceItemAttributeConfig} from 'sentry/views/explore/contexts/traceItemAttributeContext'; interface Props { + config: TraceItemAttributeConfig; fields: readonly string[]; groupBys: readonly string[]; mode: Mode; yAxes: string[]; } -export function useSortByFields({fields, yAxes, groupBys, mode}: Props) { - const {tags: numberTags} = useTraceItemTags('number'); - const {tags: stringTags} = useTraceItemTags('string'); - const {tags: booleanTags} = useTraceItemTags('boolean'); +export function useSortByFields({config, fields, yAxes, groupBys, mode}: Props) { + const {tags: numberTags} = useTraceItemTags(config, 'number'); + const {tags: stringTags} = useTraceItemTags(config, 'string'); + const {tags: booleanTags} = useTraceItemTags(config, 'boolean'); const fieldOptions: Array> = useMemo(() => { const uniqueOptions: string[] = []; diff --git a/static/app/views/explore/multiQueryMode/queryConstructors/groupBy.tsx b/static/app/views/explore/multiQueryMode/queryConstructors/groupBy.tsx index b6f29d399ca8e1..7458c66ee2b1aa 100644 --- a/static/app/views/explore/multiQueryMode/queryConstructors/groupBy.tsx +++ b/static/app/views/explore/multiQueryMode/queryConstructors/groupBy.tsx @@ -20,9 +20,10 @@ import {TraceItemDataset} from 'sentry/views/explore/types'; type Props = {index: number; query: ReadableExploreQueryParts}; export function GroupBySection({query, index}: Props) { - const {tags: numberTags} = useTraceItemTags('number'); - const {tags: stringTags} = useTraceItemTags('string'); - const {tags: booleanTags} = useTraceItemTags('boolean'); + const spansConfig = {traceItemType: TraceItemDataset.SPANS, enabled: true}; + const {tags: numberTags} = useTraceItemTags(spansConfig, 'number'); + const {tags: stringTags} = useTraceItemTags(spansConfig, 'string'); + const {tags: booleanTags} = useTraceItemTags(spansConfig, 'boolean'); const updateGroupBys = useUpdateQueryAtIndex(index); diff --git a/static/app/views/explore/multiQueryMode/queryConstructors/sortBy.tsx b/static/app/views/explore/multiQueryMode/queryConstructors/sortBy.tsx index 2c87bfd58a9d23..246a1b873af555 100644 --- a/static/app/views/explore/multiQueryMode/queryConstructors/sortBy.tsx +++ b/static/app/views/explore/multiQueryMode/queryConstructors/sortBy.tsx @@ -18,6 +18,7 @@ import { SectionHeader, SectionLabel, } from 'sentry/views/explore/multiQueryMode/queryConstructors/styles'; +import {TraceItemDataset} from 'sentry/views/explore/types'; type Props = { index: number; @@ -30,7 +31,17 @@ export function SortBySection({query, index}: Props) { const groupBys = query.groupBys; const yAxes = query.yAxes; - const fieldOptions = useSortByFields({fields, yAxes, groupBys, mode}); + const spansConfig = useMemo( + () => ({traceItemType: TraceItemDataset.SPANS, enabled: true}), + [] + ); + const fieldOptions = useSortByFields({ + config: spansConfig, + fields, + yAxes, + groupBys, + mode, + }); const updateSort = useUpdateQueryAtIndex(index); const kindOptions: Array> = useMemo(() => { diff --git a/static/app/views/explore/multiQueryMode/queryConstructors/visualize.tsx b/static/app/views/explore/multiQueryMode/queryConstructors/visualize.tsx index 22a34b487d44d2..f3ddac9eafecc5 100644 --- a/static/app/views/explore/multiQueryMode/queryConstructors/visualize.tsx +++ b/static/app/views/explore/multiQueryMode/queryConstructors/visualize.tsx @@ -30,9 +30,10 @@ type Props = { }; export function VisualizeSection({query, index}: Props) { - const {tags: stringTags} = useTraceItemTags('string'); - const {tags: numberTags} = useTraceItemTags('number'); - const {tags: booleanTags} = useTraceItemTags('boolean'); + const spansConfig = {traceItemType: TraceItemDataset.SPANS, enabled: true}; + const {tags: stringTags} = useTraceItemTags(spansConfig, 'string'); + const {tags: numberTags} = useTraceItemTags(spansConfig, 'number'); + const {tags: booleanTags} = useTraceItemTags(spansConfig, 'boolean'); const parsedFunction = findFirstFunction(query.yAxes); diff --git a/static/app/views/explore/multiQueryMode/queryVisualizations/table.tsx b/static/app/views/explore/multiQueryMode/queryVisualizations/table.tsx index 67f433c43d169c..83f32e38ef50f2 100644 --- a/static/app/views/explore/multiQueryMode/queryVisualizations/table.tsx +++ b/static/app/views/explore/multiQueryMode/queryVisualizations/table.tsx @@ -46,6 +46,7 @@ import { type ReadableExploreQueryParts, } from 'sentry/views/explore/multiQueryMode/locationUtils'; import {MultiQueryFieldRenderer} from 'sentry/views/explore/tables/fieldRenderer'; +import {TraceItemDataset} from 'sentry/views/explore/types'; const TABLE_HEIGHT = 258; @@ -96,9 +97,10 @@ function AggregatesTable({ const columns = useMemo(() => eventView.getColumns(), [eventView]); - const {tags: numberTags} = useTraceItemTags('number'); - const {tags: stringTags} = useTraceItemTags('string'); - const {tags: booleanTags} = useTraceItemTags('boolean'); + const spansConfig = {traceItemType: TraceItemDataset.SPANS, enabled: true}; + const {tags: numberTags} = useTraceItemTags(spansConfig, 'number'); + const {tags: stringTags} = useTraceItemTags(spansConfig, 'string'); + const {tags: booleanTags} = useTraceItemTags(spansConfig, 'boolean'); const tableRef = useRef(null); const {initialTableStyles} = useTableStyles(fields, tableRef, { @@ -234,9 +236,10 @@ function SpansTable({spansTableResult, query: queryParts, index}: SampleTablePro [fields] ); - const {tags: numberTags} = useTraceItemTags('number'); - const {tags: stringTags} = useTraceItemTags('string'); - const {tags: booleanTags} = useTraceItemTags('boolean'); + const spansConfig = {traceItemType: TraceItemDataset.SPANS, enabled: true}; + const {tags: numberTags} = useTraceItemTags(spansConfig, 'number'); + const {tags: stringTags} = useTraceItemTags(spansConfig, 'string'); + const {tags: booleanTags} = useTraceItemTags(spansConfig, 'boolean'); const tableRef = useRef(null); const {initialTableStyles} = useTableStyles(visibleFields, tableRef, { diff --git a/static/app/views/explore/spans/spansTabSearchSection.tsx b/static/app/views/explore/spans/spansTabSearchSection.tsx index 4ddda427d09aa6..b9fa641d480ec9 100644 --- a/static/app/views/explore/spans/spansTabSearchSection.tsx +++ b/static/app/views/explore/spans/spansTabSearchSection.tsx @@ -43,7 +43,6 @@ import { import {MAX_CROSS_EVENT_QUERIES} from 'sentry/views/explore/constants'; import {Mode} from 'sentry/views/explore/contexts/pageParamsContext/mode'; import {useTraceItemTags} from 'sentry/views/explore/contexts/spanTagsContext'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import { useQueryParamsCrossEvents, useQueryParamsFields, @@ -127,17 +126,20 @@ const SpansTabCrossEventSearchBar = memo( const crossEvents = useQueryParamsCrossEvents(); const setCrossEvents = useSetQueryParamsCrossEvents(); + const traceItemType = + type === 'logs' ? TraceItemDataset.LOGS : TraceItemDataset.SPANS; + + const crossEventConfig = useMemo( + () => ({traceItemType, enabled: true}), + [traceItemType] + ); + const {tags: numberAttributes, secondaryAliases: numberSecondaryAliases} = - useTraceItemTags('number'); + useTraceItemTags(crossEventConfig, 'number'); const {tags: stringAttributes, secondaryAliases: stringSecondaryAliases} = - useTraceItemTags('string'); + useTraceItemTags(crossEventConfig, 'string'); const {tags: booleanAttributes, secondaryAliases: booleanSecondaryAliases} = - useTraceItemTags('boolean'); - - let traceItemType = TraceItemDataset.SPANS; - if (type === 'logs') { - traceItemType = TraceItemDataset.LOGS; - } + useTraceItemTags(crossEventConfig, 'boolean'); const eapSpanSearchQueryBuilderProps = useMemo( () => ({ @@ -308,13 +310,11 @@ function SpansTabCrossEventSearchBars() { /> ) : ( - - - + )} - - - - - + + + + + + + ); } diff --git a/static/app/views/insights/common/views/spanSummaryPage/sampleList/index.tsx b/static/app/views/insights/common/views/spanSummaryPage/sampleList/index.tsx index 3fd1de38ffbc9a..442e89b949e49f 100644 --- a/static/app/views/insights/common/views/spanSummaryPage/sampleList/index.tsx +++ b/static/app/views/insights/common/views/spanSummaryPage/sampleList/index.tsx @@ -30,7 +30,6 @@ import type { import DurationChart from 'sentry/views/insights/common/views/spanSummaryPage/sampleList/durationChart'; import SampleInfo from 'sentry/views/insights/common/views/spanSummaryPage/sampleList/sampleInfo'; import SampleTable from 'sentry/views/insights/common/views/spanSummaryPage/sampleList/sampleTable/sampleTable'; -import {InsightsSpanTagProvider} from 'sentry/views/insights/pages/insightsSpanTagProvider'; import {useDomainViewFilters} from 'sentry/views/insights/pages/useFilters'; import {ModuleName, SpanFields} from 'sentry/views/insights/types'; import {getTransactionSummaryBaseUrl} from 'sentry/views/performance/transactionSummary/utils'; @@ -171,63 +170,61 @@ export function SampleList({groupId, moduleName, transactionRoute, referrer}: Pr return ( - - - - - - - - - - - - - - - - - setHighlightedSpanId(undefined)} - onMouseOverSample={sample => setHighlightedSpanId(sample.span_id)} - groupId={groupId} + + + + + + + + + + + + + - - + + + setHighlightedSpanId(undefined)} + onMouseOverSample={sample => setHighlightedSpanId(sample.span_id)} + groupId={groupId} + moduleName={moduleName} + transactionName={transactionName} + subregions={subregions} + spanSearch={spanSearch} + columnOrder={columnOrder} + additionalFields={additionalFields} + referrer={referrer} + /> + ); } diff --git a/static/app/views/insights/http/components/httpSamplesPanel.tsx b/static/app/views/insights/http/components/httpSamplesPanel.tsx index df001f8ef45bc3..0b3153107295b0 100644 --- a/static/app/views/insights/http/components/httpSamplesPanel.tsx +++ b/static/app/views/insights/http/components/httpSamplesPanel.tsx @@ -53,7 +53,6 @@ import {Referrer} from 'sentry/views/insights/http/referrers'; import {BASE_FILTERS} from 'sentry/views/insights/http/settings'; import decodePanel from 'sentry/views/insights/http/utils/queryParameterDecoders/panel'; import decodeResponseCodeClass from 'sentry/views/insights/http/utils/queryParameterDecoders/responseCodeClass'; -import {InsightsSpanTagProvider} from 'sentry/views/insights/pages/insightsSpanTagProvider'; import { ModuleName, SpanFields, @@ -361,208 +360,203 @@ export function HTTPSamplesPanel() { return ( - - - - - - - - - - + + + + + + + + + - + - + - + - + - + + + + + + + + {t('By Duration')} + + + {t('By Response Code')} + + + + ( + + )} + /> + + + + {query.panel === 'duration' && ( + + + - - - - - - + + )} + + {query.panel === 'status' && ( + + + + + + )} + + + + + + {query.panel === 'duration' && ( + + + setHighlightedSpanId(sample.span_id)} + onSampleMouseOut={() => setHighlightedSpanId(undefined)} + error={durationSamplesDataError} + // TODO: The samples endpoint doesn't provide its own meta, so we need to create it manually + meta={{ + fields: { + 'span.response_code': 'number', + }, + units: {}, + }} + referrer={TraceViewSources.REQUESTS_MODULE} + /> + + + + + + + )} + + {query.panel === 'status' && ( + + + - - - - {query.panel === 'duration' && ( - - - - - - )} - - {query.panel === 'status' && ( - - - - - - )} - - - - - - {query.panel === 'duration' && ( - - - setHighlightedSpanId(sample.span_id)} - onSampleMouseOut={() => setHighlightedSpanId(undefined)} - error={durationSamplesDataError} - // TODO: The samples endpoint doesn't provide its own meta, so we need to create it manually - meta={{ - fields: { - 'span.response_code': 'number', - }, - units: {}, - }} - referrer={TraceViewSources.REQUESTS_MODULE} - /> - - - - - - - )} - - {query.panel === 'status' && ( - - - - - - - - - - )} - - - + + + + + + + )} + + ); } diff --git a/static/app/views/insights/mcp-prompts/views/mcpPromptsLandingPage.tsx b/static/app/views/insights/mcp-prompts/views/mcpPromptsLandingPage.tsx index be2c5935246539..a0134398f53ad3 100644 --- a/static/app/views/insights/mcp-prompts/views/mcpPromptsLandingPage.tsx +++ b/static/app/views/insights/mcp-prompts/views/mcpPromptsLandingPage.tsx @@ -11,8 +11,6 @@ import {DataCategory} from 'sentry/types/core'; import {useDatePageFilterProps} from 'sentry/utils/useDatePageFilterProps'; import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import {TraceItemSearchQueryBuilder} from 'sentry/views/explore/components/traceItemSearchQueryBuilder'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; -import {TraceItemDataset} from 'sentry/views/explore/types'; import {InsightsEnvironmentSelector} from 'sentry/views/insights/common/components/enviornmentSelector'; import {ModuleFeature} from 'sentry/views/insights/common/components/moduleFeature'; import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLayout'; @@ -103,9 +101,7 @@ function PageWithProviders() { analyticEventName="insight.page_loads.mcp_prompts" maxPickableDays={datePageFilterProps.maxPickableDays} > - - - + ); } diff --git a/static/app/views/insights/mcp-resources/views/mcpResourcesLandingPage.tsx b/static/app/views/insights/mcp-resources/views/mcpResourcesLandingPage.tsx index 5bd52d4433b908..d587c0e69051e3 100644 --- a/static/app/views/insights/mcp-resources/views/mcpResourcesLandingPage.tsx +++ b/static/app/views/insights/mcp-resources/views/mcpResourcesLandingPage.tsx @@ -11,8 +11,6 @@ import {DataCategory} from 'sentry/types/core'; import {useDatePageFilterProps} from 'sentry/utils/useDatePageFilterProps'; import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import {TraceItemSearchQueryBuilder} from 'sentry/views/explore/components/traceItemSearchQueryBuilder'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; -import {TraceItemDataset} from 'sentry/views/explore/types'; import {InsightsEnvironmentSelector} from 'sentry/views/insights/common/components/enviornmentSelector'; import {ModuleFeature} from 'sentry/views/insights/common/components/moduleFeature'; import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLayout'; @@ -103,9 +101,7 @@ function PageWithProviders() { analyticEventName="insight.page_loads.mcp_resources" maxPickableDays={datePageFilterProps.maxPickableDays} > - - - + ); } diff --git a/static/app/views/insights/mcp-tools/views/mcpToolsLandingPage.tsx b/static/app/views/insights/mcp-tools/views/mcpToolsLandingPage.tsx index 3b0ad812f053b6..22d49023019baf 100644 --- a/static/app/views/insights/mcp-tools/views/mcpToolsLandingPage.tsx +++ b/static/app/views/insights/mcp-tools/views/mcpToolsLandingPage.tsx @@ -11,8 +11,6 @@ import {DataCategory} from 'sentry/types/core'; import {useDatePageFilterProps} from 'sentry/utils/useDatePageFilterProps'; import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import {TraceItemSearchQueryBuilder} from 'sentry/views/explore/components/traceItemSearchQueryBuilder'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; -import {TraceItemDataset} from 'sentry/views/explore/types'; import {InsightsEnvironmentSelector} from 'sentry/views/insights/common/components/enviornmentSelector'; import {ModuleFeature} from 'sentry/views/insights/common/components/moduleFeature'; import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLayout'; @@ -103,9 +101,7 @@ function PageWithProviders() { analyticEventName="insight.page_loads.mcp_tools" maxPickableDays={datePageFilterProps.maxPickableDays} > - - - + ); } diff --git a/static/app/views/insights/mobile/common/components/spanSamplesPanelContainer.tsx b/static/app/views/insights/mobile/common/components/spanSamplesPanelContainer.tsx index 4814f01684ec49..1370936f116f64 100644 --- a/static/app/views/insights/mobile/common/components/spanSamplesPanelContainer.tsx +++ b/static/app/views/insights/mobile/common/components/spanSamplesPanelContainer.tsx @@ -28,7 +28,6 @@ import {DataTitles} from 'sentry/views/insights/common/views/spans/types'; import DurationChart from 'sentry/views/insights/common/views/spanSummaryPage/sampleList/durationChart'; import SampleTable from 'sentry/views/insights/common/views/spanSummaryPage/sampleList/sampleTable/sampleTable'; import useCrossPlatformProject from 'sentry/views/insights/mobile/common/queries/useCrossPlatformProject'; -import {InsightsSpanTagProvider} from 'sentry/views/insights/pages/insightsSpanTagProvider'; import {useDomainViewFilters} from 'sentry/views/insights/pages/useFilters'; import { SpanFields, @@ -181,99 +180,97 @@ export function SpanSamplesContainer({ return ( - - - {release && ( - - - - {formatVersionAndCenterTruncate(release)} - - - - )} - + + {release && ( + + + + {formatVersionAndCenterTruncate(release)} + + + + )} + - - - - - - + + + - - - + - setHighlightedSpanId(undefined)} - onMouseOverSample={sample => setHighlightedSpanId(sample.span_id)} - groupId={groupId} - transactionName={transactionName} + + - + + + setHighlightedSpanId(undefined)} + onMouseOverSample={sample => setHighlightedSpanId(sample.span_id)} + groupId={groupId} + transactionName={transactionName} + moduleName={moduleName} + release={release} + columnOrder={[ + { + key: 'span_id', + name: t('Span ID'), + width: COL_WIDTH_UNDEFINED, + }, + { + key: 'profile_id', + name: t('Profile'), + width: COL_WIDTH_UNDEFINED, + }, + { + key: 'avg_comparison', + name: t('Compared to Average'), + width: COL_WIDTH_UNDEFINED, + }, + ]} + additionalFields={[SpanFields.PROFILER_ID]} + /> ); } diff --git a/static/app/views/insights/pages/agents/overview.tsx b/static/app/views/insights/pages/agents/overview.tsx index c1565d09788563..d31685ef664b15 100644 --- a/static/app/views/insights/pages/agents/overview.tsx +++ b/static/app/views/insights/pages/agents/overview.tsx @@ -22,8 +22,6 @@ import {useIsSentryEmployee} from 'sentry/utils/useIsSentryEmployee'; import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import useOrganization from 'sentry/utils/useOrganization'; import {TraceItemSearchQueryBuilder} from 'sentry/views/explore/components/traceItemSearchQueryBuilder'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; -import {TraceItemDataset} from 'sentry/views/explore/types'; import {AgentSelector} from 'sentry/views/insights/common/components/agentSelector'; import {InsightsEnvironmentSelector} from 'sentry/views/insights/common/components/enviornmentSelector'; import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLayout'; @@ -213,9 +211,7 @@ function PageWithProviders() { return ( - - - + ); } diff --git a/static/app/views/insights/pages/conversations/overview.tsx b/static/app/views/insights/pages/conversations/overview.tsx index 3c48cb86db34ac..e092e65bcaae79 100644 --- a/static/app/views/insights/pages/conversations/overview.tsx +++ b/static/app/views/insights/pages/conversations/overview.tsx @@ -22,7 +22,6 @@ import SchemaHintsList from 'sentry/views/explore/components/schemaHints/schemaH import {SchemaHintsSources} from 'sentry/views/explore/components/schemaHints/schemaHintsUtils'; import {TraceItemSearchQueryBuilder} from 'sentry/views/explore/components/traceItemSearchQueryBuilder'; import {useTraceItemTags} from 'sentry/views/explore/contexts/spanTagsContext'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {TraceItemDataset} from 'sentry/views/explore/types'; import {AgentSelector} from 'sentry/views/insights/common/components/agentSelector'; import {InsightsEnvironmentSelector} from 'sentry/views/insights/common/components/enviornmentSelector'; @@ -199,9 +198,7 @@ function PageWithProviders() { return ( - - - + ); } diff --git a/static/app/views/insights/pages/frontend/frontendOverviewPage.tsx b/static/app/views/insights/pages/frontend/frontendOverviewPage.tsx index 90aaeb51959083..65a52b0f7d5661 100644 --- a/static/app/views/insights/pages/frontend/frontendOverviewPage.tsx +++ b/static/app/views/insights/pages/frontend/frontendOverviewPage.tsx @@ -59,7 +59,6 @@ import { } from 'sentry/views/insights/pages/frontend/settings'; import {useFrontendQuery} from 'sentry/views/insights/pages/frontend/useFrontendQuery'; import useHasPlatformizedFrontendOverview from 'sentry/views/insights/pages/frontend/utils/useHasPlatformizedFrontendOverview'; -import {InsightsSpanTagProvider} from 'sentry/views/insights/pages/insightsSpanTagProvider'; import {NextJsOverviewPage} from 'sentry/views/insights/pages/platform/nextjs'; import {useIsNextJsInsightsAvailable} from 'sentry/views/insights/pages/platform/nextjs/features'; import {PlatformizedNextJsOverviewPage} from 'sentry/views/insights/pages/platform/nextjs/platformizedNextJsOverviewPage'; @@ -167,7 +166,7 @@ function FrontendOverviewPage({datePageFilterProps}: FrontendOverviewPageProps) {!showOnboarding && ( - + - + )} diff --git a/static/app/views/insights/pages/insightsSpanTagProvider.tsx b/static/app/views/insights/pages/insightsSpanTagProvider.tsx deleted file mode 100644 index 3ebde8d8085847..00000000000000 --- a/static/app/views/insights/pages/insightsSpanTagProvider.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; -import {TraceItemDataset} from 'sentry/views/explore/types'; - -export function InsightsSpanTagProvider({children}: {children: React.ReactNode}) { - return ( - - {children} - - ); -} diff --git a/static/app/views/insights/pages/mcp/overview.tsx b/static/app/views/insights/pages/mcp/overview.tsx index 8ce8c49b1f07a1..7b5d8d9781cf09 100644 --- a/static/app/views/insights/pages/mcp/overview.tsx +++ b/static/app/views/insights/pages/mcp/overview.tsx @@ -15,8 +15,6 @@ import {useDatePageFilterProps} from 'sentry/utils/useDatePageFilterProps'; import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import useOrganization from 'sentry/utils/useOrganization'; import {TraceItemSearchQueryBuilder} from 'sentry/views/explore/components/traceItemSearchQueryBuilder'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; -import {TraceItemDataset} from 'sentry/views/explore/types'; import {InsightsEnvironmentSelector} from 'sentry/views/insights/common/components/enviornmentSelector'; import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLayout'; import {InsightsProjectSelector} from 'sentry/views/insights/common/components/projectSelector'; @@ -131,9 +129,7 @@ function PageWithProviders() { return ( - - - + ); } diff --git a/static/app/views/insights/queues/components/messageSpanSamplesPanel.tsx b/static/app/views/insights/queues/components/messageSpanSamplesPanel.tsx index 5ad25f914bd37b..8e5b3df4c598e1 100644 --- a/static/app/views/insights/queues/components/messageSpanSamplesPanel.tsx +++ b/static/app/views/insights/queues/components/messageSpanSamplesPanel.tsx @@ -36,7 +36,6 @@ import {SampleDrawerBody} from 'sentry/views/insights/common/components/sampleDr import {SampleDrawerHeaderTransaction} from 'sentry/views/insights/common/components/sampleDrawerHeaderTransaction'; import {getDurationChartTitle} from 'sentry/views/insights/common/views/spans/types'; import {useSpanSamples} from 'sentry/views/insights/http/queries/useSpanSamples'; -import {InsightsSpanTagProvider} from 'sentry/views/insights/pages/insightsSpanTagProvider'; import {MessageSpanSamplesTable} from 'sentry/views/insights/queues/components/tables/messageSpanSamplesTable'; import {useQueuesMetricsQuery} from 'sentry/views/insights/queues/queries/useQueuesMetricsQuery'; import {Referrer} from 'sentry/views/insights/queues/referrers'; @@ -290,121 +289,117 @@ export function MessageSpanSamplesPanel() { return ( - - - - - - - - - - {messageActorType === MessageActorType.PRODUCER ? ( - - ) : ( - + + + + + + + + + {messageActorType === MessageActorType.PRODUCER ? ( + + ) : ( + + )} + + + + + + ( + )} - - - - - + /> + {messageActorType === MessageActorType.CONSUMER && ( ( - + )} /> - {messageActorType === MessageActorType.CONSUMER && ( - ( - - )} - /> - )} - - - - - - - - - - - - - setHighlightedSpanId(sample.span_id)} - onSampleMouseOut={() => setHighlightedSpanId(undefined)} - error={durationSamplesDataError} - // Samples endpoint doesn't provide meta data, so we need to provide it here - meta={{ - fields: { - [SpanFields.SPAN_DURATION]: 'duration', - [SpanFields.MESSAGING_MESSAGE_BODY_SIZE]: 'size', - [SpanFields.MESSAGING_MESSAGE_RETRY_COUNT]: 'number', - }, - units: { - [SpanFields.SPAN_DURATION]: DurationUnit.MILLISECOND, - [SpanFields.MESSAGING_MESSAGE_BODY_SIZE]: SizeUnit.BYTE, - }, - }} - type={messageActorType} - /> - - - - - - - - + )} + + + + + + + + + + + + + setHighlightedSpanId(sample.span_id)} + onSampleMouseOut={() => setHighlightedSpanId(undefined)} + error={durationSamplesDataError} + // Samples endpoint doesn't provide meta data, so we need to provide it here + meta={{ + fields: { + [SpanFields.SPAN_DURATION]: 'duration', + [SpanFields.MESSAGING_MESSAGE_BODY_SIZE]: 'size', + [SpanFields.MESSAGING_MESSAGE_RETRY_COUNT]: 'number', + }, + units: { + [SpanFields.SPAN_DURATION]: DurationUnit.MILLISECOND, + [SpanFields.MESSAGING_MESSAGE_BODY_SIZE]: SizeUnit.BYTE, + }, + }} + type={messageActorType} + /> + + + + + + + ); } From 8b4d13b2e655bf57d09fbfbad898b7cd4b5754fa Mon Sep 17 00:00:00 2001 From: nsdeschenes Date: Thu, 19 Feb 2026 15:05:18 -0400 Subject: [PATCH 06/10] chore(explore): Update tests to remove TraceItemAttributeProvider wrappers Remove TraceItemAttributeProvider from test wrappers across all spec files. Tests already mock the /trace-items/attributes/ API endpoint, so the components' internal useTraceItemAttributes calls with config will hit those mocks directly. Also update useTraceItemTags mock signatures to match the new (config, type?, hiddenKeys?) signature. --- .../alerts/rules/metric/eapField.spec.tsx | 152 ++++++--------- .../filterResultsStep/spansSearchBar.spec.tsx | 6 +- .../components/groupBySelector.spec.tsx | 30 +-- .../components/sortBySelector.spec.tsx | 54 ++--- .../components/visualize/index.spec.tsx | 184 +++++++++--------- .../explore/hooks/useSortByFields.spec.tsx | 8 +- .../explore/hooks/useVisualizeFields.spec.tsx | 15 +- .../app/views/explore/logs/logsTab.spec.tsx | 6 +- .../views/explore/metrics/metricsTab.spec.tsx | 10 +- .../explore/multiQueryMode/content.spec.tsx | 10 +- .../app/views/explore/spans/spansTab.spec.tsx | 12 +- .../app/views/explore/toolbar/index.spec.tsx | 10 +- 12 files changed, 187 insertions(+), 310 deletions(-) diff --git a/static/app/views/alerts/rules/metric/eapField.spec.tsx b/static/app/views/alerts/rules/metric/eapField.spec.tsx index e3ab8ebb6bf540..30f7ba9cf320b7 100644 --- a/static/app/views/alerts/rules/metric/eapField.spec.tsx +++ b/static/app/views/alerts/rules/metric/eapField.spec.tsx @@ -5,8 +5,6 @@ import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrar import EAPField from 'sentry/views/alerts/rules/metric/eapField'; import {EventTypes} from 'sentry/views/alerts/rules/metric/types'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; -import {TraceItemDataset} from 'sentry/views/explore/types'; describe('EAPField', () => { const organization = OrganizationFixture(); @@ -21,13 +19,11 @@ describe('EAPField', () => { it('renders', () => { render( - - {}} - eventTypes={[EventTypes.TRACE_ITEM_SPAN]} - /> - + {}} + eventTypes={[EventTypes.TRACE_ITEM_SPAN]} + /> ); expect(fieldsMock).toHaveBeenCalledWith( `/organizations/${organization.slug}/trace-items/attributes/`, @@ -54,13 +50,11 @@ describe('EAPField', () => { it('renders epm with argument disabled', () => { render( - - {}} - eventTypes={[EventTypes.TRACE_ITEM_SPAN]} - /> - + {}} + eventTypes={[EventTypes.TRACE_ITEM_SPAN]} + /> ); expect(fieldsMock).toHaveBeenCalledWith( `/organizations/${organization.slug}/trace-items/attributes/`, @@ -81,13 +75,11 @@ describe('EAPField', () => { it('renders failure_rate with argument disabled', () => { render( - - {}} - eventTypes={[EventTypes.TRACE_ITEM_SPAN]} - /> - + {}} + eventTypes={[EventTypes.TRACE_ITEM_SPAN]} + /> ); expect(fieldsMock).toHaveBeenCalledWith( `/organizations/${organization.slug}/trace-items/attributes/`, @@ -115,13 +107,11 @@ describe('EAPField', () => { it('should call onChange with the new aggregate string when switching aggregates', async () => { const onChange = jest.fn(); render( - - - + ); expect(fieldsMock).toHaveBeenCalledWith( `/organizations/${organization.slug}/trace-items/attributes/`, @@ -144,13 +134,11 @@ describe('EAPField', () => { function Component() { const [aggregate, setAggregate] = useState('count(span.duration)'); return ( - - - + ); } @@ -177,13 +165,11 @@ describe('EAPField', () => { function Component() { const [aggregate, setAggregate] = useState('count(span.duration)'); return ( - - - + ); } @@ -212,13 +198,11 @@ describe('EAPField', () => { it('renders count with argument disabled for logs', () => { render( - - {}} - eventTypes={[EventTypes.TRACE_ITEM_LOG]} - /> - + {}} + eventTypes={[EventTypes.TRACE_ITEM_LOG]} + /> ); expect(fieldsMock).toHaveBeenCalledWith( `/organizations/${organization.slug}/trace-items/attributes/`, @@ -246,13 +230,11 @@ describe('EAPField', () => { function Component() { const [aggregate, setAggregate] = useState('count(message)'); return ( - - - + ); } @@ -281,13 +263,11 @@ describe('EAPField', () => { function Component() { const [aggregate, setAggregate] = useState('count(message)'); return ( - - - + ); } @@ -316,13 +296,11 @@ describe('EAPField', () => { function Component() { const [aggregate, setAggregate] = useState('count(span.duration)'); return ( - - - + ); } @@ -345,13 +323,11 @@ describe('EAPField', () => { it('should call onChange with correct apdex aggregate when switching to apdex', async () => { const onChange = jest.fn(); render( - - - + ); await userEvent.click(screen.getByText('count')); @@ -368,16 +344,14 @@ describe('EAPField', () => { function Component() { const [aggregate, setAggregate] = useState('apdex(span.duration,300)'); return ( - - { - setAggregate(newAggregate); - onChange(newAggregate, {}); - }} - eventTypes={[EventTypes.TRACE_ITEM_SPAN]} - /> - + { + setAggregate(newAggregate); + onChange(newAggregate, {}); + }} + eventTypes={[EventTypes.TRACE_ITEM_SPAN]} + /> ); } diff --git a/static/app/views/dashboards/widgetBuilder/buildSteps/filterResultsStep/spansSearchBar.spec.tsx b/static/app/views/dashboards/widgetBuilder/buildSteps/filterResultsStep/spansSearchBar.spec.tsx index b11e467b2d5fef..ba8db390d8e582 100644 --- a/static/app/views/dashboards/widgetBuilder/buildSteps/filterResultsStep/spansSearchBar.spec.tsx +++ b/static/app/views/dashboards/widgetBuilder/buildSteps/filterResultsStep/spansSearchBar.spec.tsx @@ -6,8 +6,6 @@ import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrar import {WildcardOperators} from 'sentry/components/searchSyntax/parser'; import type {TagValue} from 'sentry/types/group'; import SpansSearchBar from 'sentry/views/dashboards/widgetBuilder/buildSteps/filterResultsStep/spansSearchBar'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; -import {TraceItemDataset} from 'sentry/views/explore/types'; // The endpoint seems to just return these fields, but the original TagValue type // has extra fields related to user information that we don't seem to need. @@ -22,9 +20,7 @@ function renderWithProvider({ onClose, }: ComponentProps) { return render( - - - , + , {organization: {features: ['search-query-builder-input-flow-changes']}} ); } diff --git a/static/app/views/dashboards/widgetBuilder/components/groupBySelector.spec.tsx b/static/app/views/dashboards/widgetBuilder/components/groupBySelector.spec.tsx index 23398992a73979..d8824e24d2ca50 100644 --- a/static/app/views/dashboards/widgetBuilder/components/groupBySelector.spec.tsx +++ b/static/app/views/dashboards/widgetBuilder/components/groupBySelector.spec.tsx @@ -5,8 +5,6 @@ import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrar import {DisplayType, WidgetType} from 'sentry/views/dashboards/types'; import WidgetBuilderGroupBySelector from 'sentry/views/dashboards/widgetBuilder/components/groupBySelector'; import {WidgetBuilderProvider} from 'sentry/views/dashboards/widgetBuilder/contexts/widgetBuilderContext'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; -import {TraceItemDataset} from 'sentry/views/explore/types'; const organization = OrganizationFixture({ features: [], @@ -23,9 +21,7 @@ describe('WidgetBuilderGroupBySelector', () => { it('renders', async () => { render( - - - + , { organization, @@ -40,9 +36,7 @@ describe('WidgetBuilderGroupBySelector', () => { it('renders the group by field and works for spans', async () => { render( - - - + , { organization, @@ -73,9 +67,7 @@ describe('WidgetBuilderGroupBySelector', () => { it('renders the group by field and works for logs', async () => { render( - - - + , { organization, @@ -110,9 +102,7 @@ describe('WidgetBuilderGroupBySelector', () => { render( - - - + , { initialRouterConfig: { @@ -144,9 +134,7 @@ describe('WidgetBuilderGroupBySelector', () => { render( - - - + , { initialRouterConfig: { @@ -177,9 +165,7 @@ describe('WidgetBuilderGroupBySelector', () => { render( - - - + , { initialRouterConfig: { @@ -216,9 +202,7 @@ describe('WidgetBuilderGroupBySelector', () => { render( - - - + , { organization, diff --git a/static/app/views/dashboards/widgetBuilder/components/sortBySelector.spec.tsx b/static/app/views/dashboards/widgetBuilder/components/sortBySelector.spec.tsx index 072c895788e84c..312e7ff6bbfa72 100644 --- a/static/app/views/dashboards/widgetBuilder/components/sortBySelector.spec.tsx +++ b/static/app/views/dashboards/widgetBuilder/components/sortBySelector.spec.tsx @@ -8,8 +8,6 @@ import {ELLIPSIS} from 'sentry/utils/string/unicode'; import {useNavigate} from 'sentry/utils/useNavigate'; import WidgetBuilderSortBySelector from 'sentry/views/dashboards/widgetBuilder/components/sortBySelector'; import {WidgetBuilderProvider} from 'sentry/views/dashboards/widgetBuilder/contexts/widgetBuilderContext'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; -import {TraceItemDataset} from 'sentry/views/explore/types'; jest.mock('sentry/utils/useNavigate', () => ({ useNavigate: jest.fn(), @@ -44,9 +42,7 @@ describe('WidgetBuilderSortBySelector', () => { it('renders for spans', async () => { render( - - - + , { organization, @@ -63,9 +59,7 @@ describe('WidgetBuilderSortBySelector', () => { it('renders for logs', async () => { render( - - - + , { organization, @@ -82,9 +76,7 @@ describe('WidgetBuilderSortBySelector', () => { it('renders correct fields for table widgets', async () => { render( - - - + , { organization, @@ -112,9 +104,7 @@ describe('WidgetBuilderSortBySelector', () => { render( - - - + , { organization, @@ -150,9 +140,7 @@ describe('WidgetBuilderSortBySelector', () => { it('renders the correct limit options', async () => { render( - - - + , { organization, @@ -165,9 +153,7 @@ describe('WidgetBuilderSortBySelector', () => { render( - - - + , { organization, @@ -194,9 +180,7 @@ describe('WidgetBuilderSortBySelector', () => { render( - - - + , { organization, @@ -231,9 +215,7 @@ describe('WidgetBuilderSortBySelector', () => { render( - - - + , { organization, @@ -280,9 +262,7 @@ describe('WidgetBuilderSortBySelector', () => { render( - - - + , { organization: organizationWithFlag, @@ -328,9 +308,7 @@ describe('WidgetBuilderSortBySelector', () => { it('renders a limit selector for categorical bar widgets', async () => { render( - - - + , { organization, @@ -355,9 +333,7 @@ describe('WidgetBuilderSortBySelector', () => { it('does not render a limit selector for table widgets', async () => { render( - - - + , { organization, @@ -384,9 +360,7 @@ describe('WidgetBuilderSortBySelector', () => { render( - - - + , { organization, @@ -431,9 +405,7 @@ describe('WidgetBuilderSortBySelector', () => { render( - - - + , { organization: organizationWithFlag, diff --git a/static/app/views/dashboards/widgetBuilder/components/visualize/index.spec.tsx b/static/app/views/dashboards/widgetBuilder/components/visualize/index.spec.tsx index 59ba084ecdf9df..60d2c0e9e0aece 100644 --- a/static/app/views/dashboards/widgetBuilder/components/visualize/index.spec.tsx +++ b/static/app/views/dashboards/widgetBuilder/components/visualize/index.spec.tsx @@ -36,57 +36,55 @@ describe('Visualize', () => { jest.mocked(useCustomMeasurements).mockReturnValue({customMeasurements: {}}); - jest - .mocked(useTraceItemTags) - .mockImplementation((type?: 'number' | 'string' | 'boolean') => { - if (type === 'number') { - const tags: TagCollection = { - 'span.duration': { - key: 'span.duration', - name: 'span.duration', - kind: FieldKind.MEASUREMENT, - secondaryAliases: [], - }, - 'span.self_time': { - key: 'span.self_time', - name: 'span.self_time', - kind: FieldKind.MEASUREMENT, - secondaryAliases: [], - }, - }; - return {tags, isLoading: false, secondaryAliases: {}}; - } - - if (type === 'boolean') { - const tags: TagCollection = { - 'span.status': { - key: 'span.status', - name: 'span.status', - kind: FieldKind.BOOLEAN, - }, - }; - return {tags, isLoading: false, secondaryAliases: {}}; - } - + jest.mocked(useTraceItemTags).mockImplementation((_config, type?) => { + if (type === 'number') { const tags: TagCollection = { - 'span.op': { - key: 'span.op', - name: 'span.op', - kind: FieldKind.TAG, + 'span.duration': { + key: 'span.duration', + name: 'span.duration', + kind: FieldKind.MEASUREMENT, + secondaryAliases: [], }, - 'span.description': { - key: 'span.description', - name: 'span.description', - kind: FieldKind.TAG, + 'span.self_time': { + key: 'span.self_time', + name: 'span.self_time', + kind: FieldKind.MEASUREMENT, + secondaryAliases: [], }, }; + return {tags, isLoading: false, secondaryAliases: {}}; + } - return { - tags, - secondaryAliases: {}, - isLoading: false, + if (type === 'boolean') { + const tags: TagCollection = { + 'span.status': { + key: 'span.status', + name: 'span.status', + kind: FieldKind.BOOLEAN, + }, }; - }); + return {tags, isLoading: false, secondaryAliases: {}}; + } + + const tags: TagCollection = { + 'span.op': { + key: 'span.op', + name: 'span.op', + kind: FieldKind.TAG, + }, + 'span.description': { + key: 'span.description', + name: 'span.description', + kind: FieldKind.TAG, + }, + }; + + return { + tags, + secondaryAliases: {}, + isLoading: false, + }; + }); mockNavigate = jest.fn(); jest.mocked(useNavigate).mockReturnValue(mockNavigate); @@ -1259,44 +1257,42 @@ describe('Visualize', () => { describe('spans', () => { beforeEach(() => { - jest - .mocked(useTraceItemTags) - .mockImplementation((type?: 'string' | 'number' | 'boolean') => { - if (type === 'number') { - return { - tags: { - 'span.duration': { - key: 'span.duration', - name: 'span.duration', - kind: 'measurement', - }, - 'tags[anotherNumericTag,number]': { - key: 'anotherNumericTag', - name: 'anotherNumericTag', - kind: 'measurement', - }, - } as TagCollection, - secondaryAliases: {}, - isLoading: false, - }; - } - - if (type === 'boolean') { - return {tags: {}, isLoading: false, secondaryAliases: {}}; - } - + jest.mocked(useTraceItemTags).mockImplementation((_config, type?) => { + if (type === 'number') { return { tags: { - 'span.description': { - key: 'span.description', - name: 'span.description', - kind: 'tag', + 'span.duration': { + key: 'span.duration', + name: 'span.duration', + kind: 'measurement', + }, + 'tags[anotherNumericTag,number]': { + key: 'anotherNumericTag', + name: 'anotherNumericTag', + kind: 'measurement', }, } as TagCollection, secondaryAliases: {}, isLoading: false, }; - }); + } + + if (type === 'boolean') { + return {tags: {}, isLoading: false, secondaryAliases: {}}; + } + + return { + tags: { + 'span.description': { + key: 'span.description', + name: 'span.description', + kind: 'tag', + }, + } as TagCollection, + secondaryAliases: {}, + isLoading: false, + }; + }); }); it('shows numeric tags as primary options for chart widgets', async () => { @@ -1432,29 +1428,27 @@ describe('Visualize', () => { }); it('differentiates between function and column values in selection', async () => { - jest - .mocked(useTraceItemTags) - .mockImplementation((type?: 'string' | 'number' | 'boolean') => { - if (type === 'number') { - return { - tags: { - 'tags[count,number]': {key: 'count', name: 'count', kind: 'measurement'}, - } as TagCollection, - secondaryAliases: {}, - isLoading: false, - }; - } - - if (type === 'boolean') { - return {tags: {}, secondaryAliases: {}, isLoading: false}; - } - + jest.mocked(useTraceItemTags).mockImplementation((_config, type?) => { + if (type === 'number') { return { - tags: {count: {key: 'count', name: 'count', kind: 'tag'}} as TagCollection, + tags: { + 'tags[count,number]': {key: 'count', name: 'count', kind: 'measurement'}, + } as TagCollection, secondaryAliases: {}, isLoading: false, }; - }); + } + + if (type === 'boolean') { + return {tags: {}, secondaryAliases: {}, isLoading: false}; + } + + return { + tags: {count: {key: 'count', name: 'count', kind: 'tag'}} as TagCollection, + secondaryAliases: {}, + isLoading: false, + }; + }); render( diff --git a/static/app/views/explore/hooks/useSortByFields.spec.tsx b/static/app/views/explore/hooks/useSortByFields.spec.tsx index d5543347b3d706..3036ac687d5c3a 100644 --- a/static/app/views/explore/hooks/useSortByFields.spec.tsx +++ b/static/app/views/explore/hooks/useSortByFields.spec.tsx @@ -8,9 +8,7 @@ import type {Organization} from 'sentry/types/organization'; import {QueryClientProvider} from 'sentry/utils/queryClient'; import {useLocation} from 'sentry/utils/useLocation'; import {Mode} from 'sentry/views/explore/contexts/pageParamsContext/mode'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {useSortByFields} from 'sentry/views/explore/hooks/useSortByFields'; -import {TraceItemDataset} from 'sentry/views/explore/types'; import {OrganizationContext} from 'sentry/views/organizationContext'; jest.mock('sentry/utils/useLocation'); @@ -20,11 +18,7 @@ function createWrapper(organization: Organization) { return function ({children}: {children?: React.ReactNode}) { return ( - - - {children} - - + {children} ); }; diff --git a/static/app/views/explore/hooks/useVisualizeFields.spec.tsx b/static/app/views/explore/hooks/useVisualizeFields.spec.tsx index 3a18049ace4309..76e2b589ade9cd 100644 --- a/static/app/views/explore/hooks/useVisualizeFields.spec.tsx +++ b/static/app/views/explore/hooks/useVisualizeFields.spec.tsx @@ -9,7 +9,6 @@ import {parseFunction} from 'sentry/utils/discover/fields'; import {QueryClientProvider} from 'sentry/utils/queryClient'; import {useLocation} from 'sentry/utils/useLocation'; import {useTraceItemTags} from 'sentry/views/explore/contexts/spanTagsContext'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {useVisualizeFields} from 'sentry/views/explore/hooks/useVisualizeFields'; import {TraceItemDataset} from 'sentry/views/explore/types'; import {OrganizationContext} from 'sentry/views/organizationContext'; @@ -17,24 +16,22 @@ import {OrganizationContext} from 'sentry/views/organizationContext'; jest.mock('sentry/utils/useLocation'); const mockedUsedLocation = jest.mocked(useLocation); +const spanConfig = {traceItemType: TraceItemDataset.SPANS, enabled: true}; + function createWrapper(organization: Organization) { return function ({children}: {children?: React.ReactNode}) { return ( - - - {children} - - + {children} ); }; } function useWrapper(yAxis: string) { - const {tags: stringTags} = useTraceItemTags('string'); - const {tags: numberTags} = useTraceItemTags('number'); - const {tags: booleanTags} = useTraceItemTags('boolean'); + const {tags: stringTags} = useTraceItemTags(spanConfig, 'string'); + const {tags: numberTags} = useTraceItemTags(spanConfig, 'number'); + const {tags: booleanTags} = useTraceItemTags(spanConfig, 'boolean'); return useVisualizeFields({ numberTags, stringTags, diff --git a/static/app/views/explore/logs/logsTab.spec.tsx b/static/app/views/explore/logs/logsTab.spec.tsx index edcede579d09b9..11c230a5ee92ff 100644 --- a/static/app/views/explore/logs/logsTab.spec.tsx +++ b/static/app/views/explore/logs/logsTab.spec.tsx @@ -12,12 +12,10 @@ import { LOGS_QUERY_KEY, } from 'sentry/views/explore/contexts/logs/logsPageParams'; import {LOGS_SORT_BYS_KEY} from 'sentry/views/explore/contexts/logs/sortBys'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {AlwaysPresentLogFields} from 'sentry/views/explore/logs/constants'; import {LogsQueryParamsProvider} from 'sentry/views/explore/logs/logsQueryParamsProvider'; import {LogsTabContent} from 'sentry/views/explore/logs/logsTab'; import {OurLogKnownFieldKey} from 'sentry/views/explore/logs/types'; -import {TraceItemDataset} from 'sentry/views/explore/types'; const datePageFilterProps: DatePageFilterProps = { defaultPeriod: '7d' as const, @@ -42,9 +40,7 @@ describe('LogsTabContent', () => { analyticsPageSource={LogsAnalyticsPageSource.EXPLORE_LOGS} source="location" > - - {children} - + {children} ); } diff --git a/static/app/views/explore/metrics/metricsTab.spec.tsx b/static/app/views/explore/metrics/metricsTab.spec.tsx index 7d199775a18206..db82add11e74aa 100644 --- a/static/app/views/explore/metrics/metricsTab.spec.tsx +++ b/static/app/views/explore/metrics/metricsTab.spec.tsx @@ -14,10 +14,8 @@ import { import type {DatePageFilterProps} from 'sentry/components/pageFilters/date/datePageFilter'; import {trackAnalytics} from 'sentry/utils/analytics'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {MetricsTabContent} from 'sentry/views/explore/metrics/metricsTab'; import {MultiMetricsQueryParamsProvider} from 'sentry/views/explore/metrics/multiMetricsQueryParams'; -import {TraceItemDataset} from 'sentry/views/explore/types'; jest.mock('sentry/utils/analytics'); const trackAnalyticsMock = jest.mocked(trackAnalytics); @@ -52,13 +50,7 @@ describe('MetricsTabContent', () => { }); function ProviderWrapper({children}: {children: React.ReactNode}) { - return ( - - - {children} - - - ); + return {children}; } const initialRouterConfig = { diff --git a/static/app/views/explore/multiQueryMode/content.spec.tsx b/static/app/views/explore/multiQueryMode/content.spec.tsx index 8821381a8be63d..b403cda960db89 100644 --- a/static/app/views/explore/multiQueryMode/content.spec.tsx +++ b/static/app/views/explore/multiQueryMode/content.spec.tsx @@ -1,4 +1,4 @@ -import {type ReactNode} from 'react'; +import {Fragment, type ReactNode} from 'react'; import {AutofixSetupFixture} from 'sentry-fixture/autofixSetupFixture'; import {TimeSeriesFixture} from 'sentry-fixture/timeSeries'; @@ -12,10 +12,8 @@ import { } from 'sentry-test/reactTestingLibrary'; import PageFiltersStore from 'sentry/components/pageFilters/store'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {MultiQueryModeContent} from 'sentry/views/explore/multiQueryMode/content'; import {useReadQueriesFromLocation} from 'sentry/views/explore/multiQueryMode/locationUtils'; -import {TraceItemDataset} from 'sentry/views/explore/types'; jest.mock('sentry/components/lazyRender', () => ({ LazyRender: ({children}: {children: React.ReactNode}) => children, @@ -23,11 +21,7 @@ jest.mock('sentry/components/lazyRender', () => ({ function Wrapper() { return function ({children}: {children: ReactNode}) { - return ( - - {children} - - ); + return {children}; }; } diff --git a/static/app/views/explore/spans/spansTab.spec.tsx b/static/app/views/explore/spans/spansTab.spec.tsx index dae29ef96ca299..2f08113f69b854 100644 --- a/static/app/views/explore/spans/spansTab.spec.tsx +++ b/static/app/views/explore/spans/spansTab.spec.tsx @@ -16,23 +16,15 @@ import type {TagCollection} from 'sentry/types/group'; import {trackAnalytics} from 'sentry/utils/analytics'; import {FieldKind} from 'sentry/utils/fields'; import * as spanTagsModule from 'sentry/views/explore/contexts/spanTagsContext'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import { useQueryParamsFields, useQueryParamsGroupBys, } from 'sentry/views/explore/queryParams/context'; import {SpansQueryParamsProvider} from 'sentry/views/explore/spans/spansQueryParamsProvider'; import {SpansTabContent} from 'sentry/views/explore/spans/spansTab'; -import {TraceItemDataset} from 'sentry/views/explore/types'; function Wrapper({children}: {children: ReactNode}) { - return ( - - - {children} - - - ); + return {children}; } jest.mock('sentry/utils/analytics'); @@ -332,7 +324,7 @@ describe('SpansTabContent', () => { beforeEach(() => { const useSpanTagsSpy = jest .spyOn(spanTagsModule, 'useTraceItemTags') - .mockImplementation(type => { + .mockImplementation((_config, type) => { switch (type) { case 'number': return {tags: mockNumberTags, isLoading: false, secondaryAliases: {}}; diff --git a/static/app/views/explore/toolbar/index.spec.tsx b/static/app/views/explore/toolbar/index.spec.tsx index 4e3ae92905f956..b5710957008149 100644 --- a/static/app/views/explore/toolbar/index.spec.tsx +++ b/static/app/views/explore/toolbar/index.spec.tsx @@ -14,7 +14,6 @@ import { import {openAddToDashboardModal} from 'sentry/actionCreators/modal'; import ProjectsStore from 'sentry/stores/projectsStore'; import {Mode} from 'sentry/views/explore/contexts/pageParamsContext/mode'; -import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import { useQueryParamsAggregateFields, useQueryParamsAggregateSortBys, @@ -28,16 +27,9 @@ import { import {VisualizeFunction} from 'sentry/views/explore/queryParams/visualize'; import {SpansQueryParamsProvider} from 'sentry/views/explore/spans/spansQueryParamsProvider'; import {ExploreToolbar} from 'sentry/views/explore/toolbar'; -import {TraceItemDataset} from 'sentry/views/explore/types'; function Wrapper({children}: {children: ReactNode}) { - return ( - - - {children} - - - ); + return {children}; } jest.mock('sentry/actionCreators/modal'); From f9d9e52bb42a5e978c3a575948601ff9e295661a Mon Sep 17 00:00:00 2001 From: nsdeschenes Date: Thu, 19 Feb 2026 15:08:41 -0400 Subject: [PATCH 07/10] fix(explore): Fix missing TraceItemDataset import and test config param - Add back TraceItemDataset import to logsTab.tsx (needed for config) - Add config param to useSortByFields.spec.tsx test calls --- static/app/views/explore/hooks/useSortByFields.spec.tsx | 8 ++++++++ static/app/views/explore/logs/logsTab.tsx | 1 + 2 files changed, 9 insertions(+) diff --git a/static/app/views/explore/hooks/useSortByFields.spec.tsx b/static/app/views/explore/hooks/useSortByFields.spec.tsx index 3036ac687d5c3a..3f5e34a7df0037 100644 --- a/static/app/views/explore/hooks/useSortByFields.spec.tsx +++ b/static/app/views/explore/hooks/useSortByFields.spec.tsx @@ -8,7 +8,9 @@ import type {Organization} from 'sentry/types/organization'; import {QueryClientProvider} from 'sentry/utils/queryClient'; import {useLocation} from 'sentry/utils/useLocation'; import {Mode} from 'sentry/views/explore/contexts/pageParamsContext/mode'; +import type {TraceItemAttributeConfig} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {useSortByFields} from 'sentry/views/explore/hooks/useSortByFields'; +import {TraceItemDataset} from 'sentry/views/explore/types'; import {OrganizationContext} from 'sentry/views/organizationContext'; jest.mock('sentry/utils/useLocation'); @@ -26,6 +28,10 @@ function createWrapper(organization: Organization) { describe('useSortByFields', () => { const organization = OrganizationFixture(); + const spansConfig: TraceItemAttributeConfig = { + traceItemType: TraceItemDataset.SPANS, + enabled: true, + }; beforeEach(() => { MockApiClient.clearMockResponses(); @@ -42,6 +48,7 @@ describe('useSortByFields', () => { const {result} = renderHook( () => useSortByFields({ + config: spansConfig, fields: [ 'id', 'span.op', @@ -73,6 +80,7 @@ describe('useSortByFields', () => { const {result} = renderHook( () => useSortByFields({ + config: spansConfig, fields: ['span.op', 'span.description'], groupBys: ['span.op'], yAxes: ['avg(span.duration)'], diff --git a/static/app/views/explore/logs/logsTab.tsx b/static/app/views/explore/logs/logsTab.tsx index 458b9ee4f3e80e..167c3461d4eb3c 100644 --- a/static/app/views/explore/logs/logsTab.tsx +++ b/static/app/views/explore/logs/logsTab.tsx @@ -91,6 +91,7 @@ import { useSetQueryParamsMode, } from 'sentry/views/explore/queryParams/context'; import {ColumnEditorModal} from 'sentry/views/explore/tables/columnEditorModal'; +import {TraceItemDataset} from 'sentry/views/explore/types'; import {useRawCounts} from 'sentry/views/explore/useRawCounts'; // eslint-disable-next-line boundaries/element-types From ea18d2740634e012e08dd3adb855b7851c42ec7f Mon Sep 17 00:00:00 2001 From: nsdeschenes Date: Thu, 19 Feb 2026 15:37:58 -0400 Subject: [PATCH 08/10] fix(alerts): Preserve EAP attribute project scope Pass the selected alert project into EAPField and include it in trace item attribute config so aggregate options stay scoped to the alert project. Also remove the now-unnecessary EAPField wrapper export. Co-authored-by: Cursor --- static/app/views/alerts/rules/metric/eapField.tsx | 14 +++++--------- .../app/views/alerts/rules/metric/wizardField.tsx | 1 + 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/static/app/views/alerts/rules/metric/eapField.tsx b/static/app/views/alerts/rules/metric/eapField.tsx index ad1a84dbb45a9d..2e29b36b5d6efe 100644 --- a/static/app/views/alerts/rules/metric/eapField.tsx +++ b/static/app/views/alerts/rules/metric/eapField.tsx @@ -6,6 +6,7 @@ import {Flex} from '@sentry/scraps/layout'; import {Select} from '@sentry/scraps/select'; import {t} from 'sentry/locale'; +import type {Project} from 'sentry/types/project'; import {defined} from 'sentry/utils'; import {parseFunction} from 'sentry/utils/discover/fields'; import { @@ -38,6 +39,7 @@ interface Props { aggregate: string; eventTypes: EventTypes[]; onChange: (value: string, meta: Record) => void; + project?: Project; } const SUPPORTED_MULTI_PARAM_AGGREGATES = [ @@ -69,11 +71,7 @@ const LOG_OPERATIONS = [ value: aggregate as OurLogsAggregate, })) satisfies Array<{label: string; value: OurLogsAggregate}>; -function EAPFieldWrapper({aggregate, onChange, eventTypes}: Props) { - return ; -} - -function EAPField({aggregate, onChange, eventTypes}: Props) { +export default function EAPField({aggregate, onChange, eventTypes, project}: Props) { const traceItemType = getTraceItemTypeForDatasetAndEventType( Dataset.EVENTS_ANALYTICS_PLATFORM, @@ -85,8 +83,8 @@ function EAPField({aggregate, onChange, eventTypes}: Props) { }; const traceItemAttributeConfig = useMemo( - () => ({traceItemType, enabled: true}), - [traceItemType] + () => ({traceItemType, enabled: true, projects: project ? [project] : undefined}), + [traceItemType, project] ); const {attributes: storedNumberTags} = useTraceItemAttributes( @@ -322,8 +320,6 @@ function EAPField({aggregate, onChange, eventTypes}: Props) { ); } -export default EAPFieldWrapper; - const FlexWrapper = styled('div')` flex: 1; `; diff --git a/static/app/views/alerts/rules/metric/wizardField.tsx b/static/app/views/alerts/rules/metric/wizardField.tsx index 97f2b7bdfaaea1..4c729b7e8b22ed 100644 --- a/static/app/views/alerts/rules/metric/wizardField.tsx +++ b/static/app/views/alerts/rules/metric/wizardField.tsx @@ -280,6 +280,7 @@ export default function WizardField({ { return onChange(newAggregate, {}); }} From cb432a9216c9fb9dbca2b7e41831c37fb416e528 Mon Sep 17 00:00:00 2001 From: nsdeschenes Date: Thu, 19 Feb 2026 15:43:00 -0400 Subject: [PATCH 09/10] chore(explore): Remove redundant fragment wrappers Clean up unnecessary React Fragment wrappers in metric rule conditions and multi-query mode tests to simplify render trees without behavior changes. Co-authored-by: Cursor --- .../rules/metric/ruleConditionsForm.tsx | 358 +++++++++--------- .../explore/multiQueryMode/content.spec.tsx | 46 +-- 2 files changed, 195 insertions(+), 209 deletions(-) diff --git a/static/app/views/alerts/rules/metric/ruleConditionsForm.tsx b/static/app/views/alerts/rules/metric/ruleConditionsForm.tsx index 750708f87f3c37..57ada48d6ff098 100644 --- a/static/app/views/alerts/rules/metric/ruleConditionsForm.tsx +++ b/static/app/views/alerts/rules/metric/ruleConditionsForm.tsx @@ -648,196 +648,192 @@ class RuleConditionsForm extends PureComponent { ) : ( - - {isExtrapolatedChartData && ( - + )} + {confidenceEnabled && isLowConfidenceChartData && ( + + + {t( + 'Your low sample count may impact the accuracy of this alert. Edit your query or increase your sampling rate.' )} - /> - )} - {confidenceEnabled && isLowConfidenceChartData && ( - - - {t( - 'Your low sample count may impact the accuracy of this alert. Edit your query or increase your sampling rate.' - )} - - - )} - {!isErrorMigration && this.renderInterval()} - {t('Filter events')} - - - {this.renderProjectSelector()} - ({ - ...base, - }), - option: (base: any) => ({ - ...base, - }), - }} - options={environmentOptions} - isDisabled={ - disabled || - this.state.environments === null || - isErrorMigration || - this.disableTransactionAlertType - } - isClearable - inline={false} - flexibleControlStateSize - /> - {allowChangeEventTypes && this.renderEventTypeFilter()} - - - - + + )} + {!isErrorMigration && this.renderInterval()} + {t('Filter events')} + + + {this.renderProjectSelector()} + ({ + ...base, + }), + option: (base: any) => ({ + ...base, + }), }} + options={environmentOptions} + isDisabled={ + disabled || + this.state.environments === null || + isErrorMigration || + this.disableTransactionAlertType + } + isClearable + inline={false} flexibleControlStateSize - > - {({onChange, onBlur, initialData, value}: any) => { - return isEapAlertType(alertType) ? ( - { - onFilterSearch(query, parsedQuery); + /> + {allowChangeEventTypes && this.renderEventTypeFilter()} + + + + + {({onChange, onBlur, initialData, value}: any) => { + return isEapAlertType(alertType) ? ( + { + onFilterSearch(query, parsedQuery); + onChange(query, {}); + }} + project={project} + traceItemType={traceItemType ?? TraceItemDataset.SPANS} + /> + ) : ( + + { + onFilterSearch(query, true); onChange(query, {}); }} - project={project} - traceItemType={traceItemType ?? TraceItemDataset.SPANS} + onBlur={(query, {parsedQuery}) => { + onFilterSearch(query, parsedQuery); + onBlur(query); + }} + // We only need strict validation for Transaction queries, everything else is fine + disallowUnsupportedFilters={ + organization.features.includes('alert-allow-indexed') || + (hasOnDemandMetricAlertFeature(organization) && + isOnDemandQueryString(value)) + ? false + : dataset === Dataset.GENERIC_METRICS + } + /> + {isExtrapolatedChartData && + isOnDemandQueryString(value) && + (isOnDemandLimitReached ? ( + + {getOnDemandKeys(value) + .map(key => `"${key}"`) + .join(', ')} + + ), + docLink: ( + + ), + } + )} + isHoverable + /> + ) : ( + + {getOnDemandKeys(value) + .map(key => `"${key}"`) + .join(', ')} + + ), + strong: , + } + )} + /> + ))} + + ); + }} + + + + + {(args: any) => { + if ( + args.value?.includes('is:unresolved') && + comparisonType === AlertRuleComparisonType.DYNAMIC + ) { + return ( + - ) : ( - - { - onFilterSearch(query, true); - onChange(query, {}); - }} - onBlur={(query, {parsedQuery}) => { - onFilterSearch(query, parsedQuery); - onBlur(query); - }} - // We only need strict validation for Transaction queries, everything else is fine - disallowUnsupportedFilters={ - organization.features.includes('alert-allow-indexed') || - (hasOnDemandMetricAlertFeature(organization) && - isOnDemandQueryString(value)) - ? false - : dataset === Dataset.GENERIC_METRICS - } - /> - {isExtrapolatedChartData && - isOnDemandQueryString(value) && - (isOnDemandLimitReached ? ( - - {getOnDemandKeys(value) - .map(key => `"${key}"`) - .join(', ')} - - ), - docLink: ( - - ), - } - )} - isHoverable - /> - ) : ( - - {getOnDemandKeys(value) - .map(key => `"${key}"`) - .join(', ')} - - ), - strong: , - } - )} - /> - ))} - ); - }} - - - - - {(args: any) => { - if ( - args.value?.includes('is:unresolved') && - comparisonType === AlertRuleComparisonType.DYNAMIC - ) { - return ( - - ); - } - return null; - }} - - - + } + return null; + }} + + )} diff --git a/static/app/views/explore/multiQueryMode/content.spec.tsx b/static/app/views/explore/multiQueryMode/content.spec.tsx index b403cda960db89..3a9fa812f15a55 100644 --- a/static/app/views/explore/multiQueryMode/content.spec.tsx +++ b/static/app/views/explore/multiQueryMode/content.spec.tsx @@ -1,4 +1,3 @@ -import {Fragment, type ReactNode} from 'react'; import {AutofixSetupFixture} from 'sentry-fixture/autofixSetupFixture'; import {TimeSeriesFixture} from 'sentry-fixture/timeSeries'; @@ -19,12 +18,6 @@ jest.mock('sentry/components/lazyRender', () => ({ LazyRender: ({children}: {children: React.ReactNode}) => children, })); -function Wrapper() { - return function ({children}: {children: ReactNode}) { - return {children}; - }; -} - describe('MultiQueryModeContent', () => { const {organization, project} = initializeOrg(); let eventsRequest: any; @@ -108,7 +101,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); const section = await screen.findByTestId('section-visualize-0'); expect(within(section).getByRole('button', {name: 'spans'})).toBeDisabled(); @@ -121,7 +114,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); const section = await screen.findByTestId('section-visualize-0'); @@ -184,7 +177,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); const section = await screen.findByTestId('section-visualize-0'); await userEvent.click(within(section).getByRole('button', {name: 'count'})); @@ -199,7 +192,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); const section = await screen.findByTestId('section-visualize-0'); @@ -264,7 +257,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); const section = await screen.findByTestId('section-visualize-0'); @@ -327,7 +320,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); const section = await screen.findByTestId('section-visualize-0'); await userEvent.click(within(section).getByRole('button', {name: 'count'})); @@ -342,7 +335,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); const section = await screen.findByTestId('section-visualize-0'); @@ -425,7 +418,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); expect(await screen.findByRole('button', {name: 'Bar'})).toBeInTheDocument(); @@ -473,7 +466,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); await userEvent.click(await screen.findByRole('button', {name: 'Bar'})); await userEvent.click(screen.getByRole('option', {name: 'Area'})); @@ -509,7 +502,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); expect(queries).toEqual([ { @@ -551,7 +544,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); expect(queries).toEqual([ { @@ -593,7 +586,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); expect(queries).toEqual([ { @@ -638,7 +631,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); expect(queries).toEqual([ { @@ -680,7 +673,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); expect(queries).toEqual([ { @@ -734,7 +727,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); expect(queries).toEqual([ { @@ -795,7 +788,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); expect(queries).toEqual([ { @@ -899,7 +892,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); expect(queries).toEqual([ { @@ -1050,7 +1043,7 @@ describe('MultiQueryModeContent', () => { return ; } - render(, {additionalWrapper: Wrapper()}); + render(); expect(queries).toEqual([ { @@ -1094,7 +1087,6 @@ describe('MultiQueryModeContent', () => { it('sets interval correctly', async () => { const {router} = render(, { organization, - additionalWrapper: Wrapper(), initialRouterConfig: { location: { pathname: '/traces/compare', @@ -1125,7 +1117,6 @@ describe('MultiQueryModeContent', () => { it('renders a save query button', async () => { render(, { organization, - additionalWrapper: Wrapper(), }); expect(await screen.findByLabelText('Save')).toBeInTheDocument(); await userEvent.click(screen.getByLabelText('Save')); @@ -1169,7 +1160,6 @@ describe('MultiQueryModeContent', () => { render(, { organization, - additionalWrapper: Wrapper(), initialRouterConfig: { location: { pathname: '/traces/compare', From 771e88c052fc298e7dffa1e62130ad001c5f362c Mon Sep 17 00:00:00 2001 From: nsdeschenes Date: Fri, 20 Feb 2026 07:31:50 -0400 Subject: [PATCH 10/10] :fire: Remove extra useMemo --- .../events/ourlogs/ourlogsDrawer.tsx | 5 +- .../views/alerts/rules/metric/eapField.tsx | 9 +-- .../rules/metric/ruleConditionsForm.tsx | 7 +-- .../hooks/useWidgetBuilderTraceItemConfig.ts | 60 +++++++++---------- static/app/views/explore/logs/logsTab.tsx | 8 +-- static/app/views/explore/logs/logsToolbar.tsx | 26 ++++---- .../queryConstructors/sortBy.tsx | 5 +- .../explore/spans/spansTabSearchSection.tsx | 12 +--- .../views/explore/toolbar/toolbarGroupBy.tsx | 15 ++--- .../views/explore/toolbar/toolbarSortBy.tsx | 5 +- .../explore/toolbar/toolbarVisualize.tsx | 13 ++-- 11 files changed, 65 insertions(+), 100 deletions(-) diff --git a/static/app/components/events/ourlogs/ourlogsDrawer.tsx b/static/app/components/events/ourlogs/ourlogsDrawer.tsx index c89db1aba1af8d..383ea8a53ebedb 100644 --- a/static/app/components/events/ourlogs/ourlogsDrawer.tsx +++ b/static/app/components/events/ourlogs/ourlogsDrawer.tsx @@ -61,10 +61,7 @@ export function OurlogsDrawer({ const setLogsQuery = useSetQueryParamsQuery(); const logsSearch = useQueryParamsSearch(); - const logsAttributeConfig = useMemo( - () => ({traceItemType: TraceItemDataset.LOGS, enabled: true}), - [] - ); + const logsAttributeConfig = {traceItemType: TraceItemDataset.LOGS, enabled: true}; const {attributes: stringAttributes, secondaryAliases: stringSecondaryAliases} = useTraceItemAttributes(logsAttributeConfig, 'string'); diff --git a/static/app/views/alerts/rules/metric/eapField.tsx b/static/app/views/alerts/rules/metric/eapField.tsx index 2e29b36b5d6efe..f0383436d0f621 100644 --- a/static/app/views/alerts/rules/metric/eapField.tsx +++ b/static/app/views/alerts/rules/metric/eapField.tsx @@ -82,10 +82,11 @@ export default function EAPField({aggregate, onChange, eventTypes, project}: Pro arguments: undefined, }; - const traceItemAttributeConfig = useMemo( - () => ({traceItemType, enabled: true, projects: project ? [project] : undefined}), - [traceItemType, project] - ); + const traceItemAttributeConfig = { + traceItemType, + enabled: true, + projects: project ? [project] : undefined, + }; const {attributes: storedNumberTags} = useTraceItemAttributes( traceItemAttributeConfig, diff --git a/static/app/views/alerts/rules/metric/ruleConditionsForm.tsx b/static/app/views/alerts/rules/metric/ruleConditionsForm.tsx index 57ada48d6ff098..9cd2d9c5249023 100644 --- a/static/app/views/alerts/rules/metric/ruleConditionsForm.tsx +++ b/static/app/views/alerts/rules/metric/ruleConditionsForm.tsx @@ -1,4 +1,4 @@ -import {Fragment, PureComponent, useMemo} from 'react'; +import {Fragment, PureComponent} from 'react'; import {css} from '@emotion/react'; import styled from '@emotion/styled'; import omit from 'lodash/omit'; @@ -854,10 +854,7 @@ function EAPSearchQueryBuilderWithContext({ project, traceItemType, }: EAPSearchQueryBuilderWithContextProps) { - const traceItemAttributeConfig = useMemo( - () => ({traceItemType, enabled: true, projects: [project]}), - [traceItemType, project] - ); + const traceItemAttributeConfig = {traceItemType, enabled: true, projects: [project]}; const {attributes: numberAttributes, secondaryAliases: numberSecondaryAliases} = useTraceItemAttributes(traceItemAttributeConfig, 'number'); diff --git a/static/app/views/dashboards/widgetBuilder/hooks/useWidgetBuilderTraceItemConfig.ts b/static/app/views/dashboards/widgetBuilder/hooks/useWidgetBuilderTraceItemConfig.ts index 72896df64b2173..41bc5163b1d0d3 100644 --- a/static/app/views/dashboards/widgetBuilder/hooks/useWidgetBuilderTraceItemConfig.ts +++ b/static/app/views/dashboards/widgetBuilder/hooks/useWidgetBuilderTraceItemConfig.ts @@ -1,5 +1,3 @@ -import {useMemo} from 'react'; - import useOrganization from 'sentry/utils/useOrganization'; import {useHasTraceMetricsDashboards} from 'sentry/views/dashboards/hooks/useHasTraceMetricsDashboards'; import {WidgetType} from 'sentry/views/dashboards/types'; @@ -14,39 +12,37 @@ export function useWidgetBuilderTraceItemConfig(): TraceItemAttributeConfig { const organization = useOrganization(); const hasTraceMetricsDashboards = useHasTraceMetricsDashboards(); - return useMemo(() => { - if (state.dataset === WidgetType.SPANS) { - return { - traceItemType: TraceItemDataset.SPANS, - enabled: organization.features.includes('visibility-explore-view'), - }; - } - - if (state.dataset === WidgetType.LOGS) { - return { - traceItemType: TraceItemDataset.LOGS, - enabled: isLogsEnabled(organization), - }; - } + if (state.dataset === WidgetType.SPANS) { + return { + traceItemType: TraceItemDataset.SPANS, + enabled: organization.features.includes('visibility-explore-view'), + }; + } - if (state.dataset === WidgetType.TRACEMETRICS && state.traceMetric) { - return { - traceItemType: TraceItemDataset.TRACEMETRICS, - enabled: hasTraceMetricsDashboards, - query: createTraceMetricFilter(state.traceMetric), - }; - } + if (state.dataset === WidgetType.LOGS) { + return { + traceItemType: TraceItemDataset.LOGS, + enabled: isLogsEnabled(organization), + }; + } - if (state.dataset === WidgetType.PREPROD_APP_SIZE) { - return { - traceItemType: TraceItemDataset.PREPROD, - enabled: organization.features.includes('preprod-app-size-dashboard'), - }; - } + if (state.dataset === WidgetType.TRACEMETRICS && state.traceMetric) { + return { + traceItemType: TraceItemDataset.TRACEMETRICS, + enabled: hasTraceMetricsDashboards, + query: createTraceMetricFilter(state.traceMetric), + }; + } + if (state.dataset === WidgetType.PREPROD_APP_SIZE) { return { - traceItemType: TraceItemDataset.SPANS, - enabled: false, + traceItemType: TraceItemDataset.PREPROD, + enabled: organization.features.includes('preprod-app-size-dashboard'), }; - }, [state.dataset, state.traceMetric, organization, hasTraceMetricsDashboards]); + } + + return { + traceItemType: TraceItemDataset.SPANS, + enabled: false, + }; } diff --git a/static/app/views/explore/logs/logsTab.tsx b/static/app/views/explore/logs/logsTab.tsx index 167c3461d4eb3c..8c882e3beb127a 100644 --- a/static/app/views/explore/logs/logsTab.tsx +++ b/static/app/views/explore/logs/logsTab.tsx @@ -172,10 +172,10 @@ export function LogsTabContent({datePageFilterProps}: LogsTabProps) { limit: 50, }); - const logsAttributeConfig: TraceItemAttributeConfig = useMemo( - () => ({traceItemType: TraceItemDataset.LOGS, enabled: true}), - [] - ); + const logsAttributeConfig: TraceItemAttributeConfig = { + traceItemType: TraceItemDataset.LOGS, + enabled: true, + }; const { attributes: stringAttributes, diff --git a/static/app/views/explore/logs/logsToolbar.tsx b/static/app/views/explore/logs/logsToolbar.tsx index 24cff369e2a9ca..a4957b95025ad6 100644 --- a/static/app/views/explore/logs/logsToolbar.tsx +++ b/static/app/views/explore/logs/logsToolbar.tsx @@ -106,14 +106,11 @@ function ToolbarVisualize() { const [search, setSearch] = useState(undefined); const debouncedSearch = useDebouncedValue(search, 200); - const logsAttributeConfig = useMemo( - () => ({ - traceItemType: TraceItemDataset.LOGS, - enabled: true, - search: debouncedSearch, - }), - [debouncedSearch] - ); + const logsAttributeConfig = { + traceItemType: TraceItemDataset.LOGS, + enabled: true, + search: debouncedSearch, + }; const {attributes: stringTags, isLoading: stringTagsLoading} = useTraceItemAttributes( logsAttributeConfig, @@ -390,14 +387,11 @@ function ToolbarGroupBy() { const [search, setSearch] = useState(undefined); const debouncedSearch = useDebouncedValue(search, 200); - const logsAttributeConfig = useMemo( - () => ({ - traceItemType: TraceItemDataset.LOGS, - enabled: true, - search: debouncedSearch, - }), - [debouncedSearch] - ); + const logsAttributeConfig = { + traceItemType: TraceItemDataset.LOGS, + enabled: true, + search: debouncedSearch, + }; const {attributes: numberTags, isLoading: numberTagsLoading} = useTraceItemAttributes( logsAttributeConfig, diff --git a/static/app/views/explore/multiQueryMode/queryConstructors/sortBy.tsx b/static/app/views/explore/multiQueryMode/queryConstructors/sortBy.tsx index 246a1b873af555..d865966cf0ed2b 100644 --- a/static/app/views/explore/multiQueryMode/queryConstructors/sortBy.tsx +++ b/static/app/views/explore/multiQueryMode/queryConstructors/sortBy.tsx @@ -31,10 +31,7 @@ export function SortBySection({query, index}: Props) { const groupBys = query.groupBys; const yAxes = query.yAxes; - const spansConfig = useMemo( - () => ({traceItemType: TraceItemDataset.SPANS, enabled: true}), - [] - ); + const spansConfig = {traceItemType: TraceItemDataset.SPANS, enabled: true}; const fieldOptions = useSortByFields({ config: spansConfig, fields, diff --git a/static/app/views/explore/spans/spansTabSearchSection.tsx b/static/app/views/explore/spans/spansTabSearchSection.tsx index b9fa641d480ec9..bc21201dae6f46 100644 --- a/static/app/views/explore/spans/spansTabSearchSection.tsx +++ b/static/app/views/explore/spans/spansTabSearchSection.tsx @@ -129,11 +129,7 @@ const SpansTabCrossEventSearchBar = memo( const traceItemType = type === 'logs' ? TraceItemDataset.LOGS : TraceItemDataset.SPANS; - const crossEventConfig = useMemo( - () => ({traceItemType, enabled: true}), - [traceItemType] - ); - + const crossEventConfig = {traceItemType, enabled: true}; const {tags: numberAttributes, secondaryAliases: numberSecondaryAliases} = useTraceItemTags(crossEventConfig, 'number'); const {tags: stringAttributes, secondaryAliases: stringSecondaryAliases} = @@ -380,11 +376,7 @@ export function SpanTabSearchSection({datePageFilterProps}: SpanTabSearchSection const hasCrossEvents = hasCrossEventQueryingFlag && defined(crossEvents) && crossEvents.length > 0; - const spansConfig = useMemo( - () => ({traceItemType: TraceItemDataset.SPANS, enabled: true}), - [] - ); - + const spansConfig = {traceItemType: TraceItemDataset.SPANS, enabled: true}; const {tags: numberAttributes, isLoading: numberAttributesLoading} = useTraceItemTags( spansConfig, 'number' diff --git a/static/app/views/explore/toolbar/toolbarGroupBy.tsx b/static/app/views/explore/toolbar/toolbarGroupBy.tsx index b5d1b40c775c9f..3422592d02e186 100644 --- a/static/app/views/explore/toolbar/toolbarGroupBy.tsx +++ b/static/app/views/explore/toolbar/toolbarGroupBy.tsx @@ -1,4 +1,4 @@ -import {useCallback, useMemo, useState} from 'react'; +import {useCallback, useState} from 'react'; import type {SelectOption} from '@sentry/scraps/compactSelect'; @@ -79,14 +79,11 @@ function ToolbarGroupByItem({ const [search, setSearch] = useState(undefined); const debouncedSearch = useDebouncedValue(search, 200); - const spansConfig = useMemo( - () => ({ - traceItemType: TraceItemDataset.SPANS, - enabled: true, - search: debouncedSearch, - }), - [debouncedSearch] - ); + const spansConfig = { + traceItemType: TraceItemDataset.SPANS, + enabled: true, + search: debouncedSearch, + }; const {tags: numberTags, isLoading: numberTagsLoading} = useTraceItemTags( spansConfig, diff --git a/static/app/views/explore/toolbar/toolbarSortBy.tsx b/static/app/views/explore/toolbar/toolbarSortBy.tsx index dba7ae39f3d4d9..6bcf7dc02b5896 100644 --- a/static/app/views/explore/toolbar/toolbarSortBy.tsx +++ b/static/app/views/explore/toolbar/toolbarSortBy.tsx @@ -48,10 +48,7 @@ export function ToolbarSortBy() { // traces table is only sorted by timestamp so disable the sort by const disabled = mode === Mode.SAMPLES && tab === Tab.TRACE; - const spansConfig = useMemo( - () => ({traceItemType: TraceItemDataset.SPANS, enabled: true}), - [] - ); + const spansConfig = {traceItemType: TraceItemDataset.SPANS, enabled: true}; const fieldOptions = useSortByFields({ config: spansConfig, diff --git a/static/app/views/explore/toolbar/toolbarVisualize.tsx b/static/app/views/explore/toolbar/toolbarVisualize.tsx index 59999f76ec7026..670d3e2852a2ad 100644 --- a/static/app/views/explore/toolbar/toolbarVisualize.tsx +++ b/static/app/views/explore/toolbar/toolbarVisualize.tsx @@ -170,14 +170,11 @@ function ToolbarVisualizeItem({ const [search, setSearch] = useState(undefined); const debouncedSearch = useDebouncedValue(search, 200); - const spansConfig = useMemo( - () => ({ - traceItemType: TraceItemDataset.SPANS, - enabled: true, - search: debouncedSearch, - }), - [debouncedSearch] - ); + const spansConfig = { + traceItemType: TraceItemDataset.SPANS, + enabled: true, + search: debouncedSearch, + }; const {tags: stringTags, isLoading: stringTagsLoading} = useTraceItemTags( spansConfig,