diff --git a/static/app/views/insights/aiGenerations/views/components/generationsChart.tsx b/static/app/views/insights/aiGenerations/views/components/generationsChart.tsx index a56fe54bd3f72b..4faaba8c9339fb 100644 --- a/static/app/views/insights/aiGenerations/views/components/generationsChart.tsx +++ b/static/app/views/insights/aiGenerations/views/components/generationsChart.tsx @@ -2,10 +2,10 @@ import {Fragment, useMemo} from 'react'; import {CompactSelect} from '@sentry/scraps/compactSelect'; +import {useCaseInsensitivity} from 'sentry/components/searchQueryBuilder/hooks'; import {IconClock} from 'sentry/icons/iconClock'; import {IconGraph} from 'sentry/icons/iconGraph'; import {t} from 'sentry/locale'; -import {useFetchSpanTimeSeries} from 'sentry/utils/timeSeries/useFetchEventsTimeSeries'; import type {TimeSeries} from 'sentry/views/dashboards/widgets/common/types'; import {Area} from 'sentry/views/dashboards/widgets/timeSeriesWidget/plottables/area'; import {Bars} from 'sentry/views/dashboards/widgets/timeSeriesWidget/plottables/bars'; @@ -14,18 +14,16 @@ import type {Plottable} from 'sentry/views/dashboards/widgets/timeSeriesWidget/p import {TimeSeriesWidgetVisualization} from 'sentry/views/dashboards/widgets/timeSeriesWidget/timeSeriesWidgetVisualization'; import {Widget} from 'sentry/views/dashboards/widgets/widget/widget'; import {useChartInterval} from 'sentry/views/explore/hooks/useChartInterval'; +import {useExploreTimeseries} from 'sentry/views/explore/hooks/useExploreTimeseries'; import { - useQueryParamsGroupBys, useQueryParamsVisualizes, useSetQueryParamsVisualizes, } from 'sentry/views/explore/queryParams/context'; import type {Visualize} from 'sentry/views/explore/queryParams/visualize'; import {useCombinedQuery} from 'sentry/views/insights/agents/hooks/useCombinedQuery'; import {AI_GENERATIONS_PAGE_FILTER} from 'sentry/views/insights/aiGenerations/views/utils/constants'; -import {Referrer} from 'sentry/views/insights/aiGenerations/views/utils/referrer'; import {ChartType} from 'sentry/views/insights/common/components/chart'; import {WidgetVisualizationStates} from 'sentry/views/insights/pages/platform/laravel/widgetVisualizationStates'; -import type {SpanFields} from 'sentry/views/insights/types'; const CHART_TYPE_OPTIONS = [ { @@ -67,6 +65,15 @@ function prettifyAggregation(aggregation: string): string { export function GenerationsChart() { const visualizes = useQueryParamsVisualizes(); const setVisualizes = useSetQueryParamsVisualizes(); + const [caseInsensitive] = useCaseInsensitivity(); + + const {result: timeseriesResult} = useExploreTimeseries({ + query: useCombinedQuery(AI_GENERATIONS_PAGE_FILTER), + enabled: true, + queryExtras: { + caseInsensitive, + }, + }); function handleChartTypeChange(index: number, chartType: ChartType) { const newVisualizes = visualizes.map((visualize, i) => { @@ -86,6 +93,7 @@ export function GenerationsChart() { key={index} visualize={visualize} onChartTypeChange={chartType => handleChartTypeChange(index, chartType)} + timeseriesResult={timeseriesResult} /> ); })} @@ -96,40 +104,19 @@ export function GenerationsChart() { function ChartWidget({ visualize, onChartTypeChange, + timeseriesResult, }: { onChartTypeChange: (chartType: ChartType) => void; + timeseriesResult: ReturnType['result']; visualize: Visualize; }) { - const groupBys = useQueryParamsGroupBys().filter(Boolean); const [interval, setInterval, intervalOptions] = useChartInterval(); const chartType = visualize.chartType; - const query = useCombinedQuery(AI_GENERATIONS_PAGE_FILTER); - const {data, isLoading, error} = useFetchSpanTimeSeries( - { - query, - yAxis: [visualize.yAxis] as any, - groupBy: groupBys as SpanFields[], - interval, - sort: - groupBys.length > 0 && groupBys[0] - ? { - field: groupBys[0], - kind: 'desc' as const, - } - : undefined, - topEvents: groupBys.length > 0 ? 5 : undefined, - }, - Referrer.GENERATIONS_CHART - ); - const plottables = useMemo(() => { - return ( - data?.timeSeries.map( - timeSeries => new plottableConstructors[chartType](timeSeries) - ) ?? [] - ); - }, [chartType, data?.timeSeries]); + const timeSeries = timeseriesResult.data[visualize.yAxis] ?? []; + return timeSeries.map(series => new plottableConstructors[chartType](series)) ?? []; + }, [chartType, timeseriesResult.data, visualize.yAxis]); const isEmpty = useMemo( () => plottables.every(plottable => plottable.isEmpty), @@ -170,8 +157,8 @@ function ChartWidget({ revealActions="always" Visualization={ { return [ @@ -97,22 +104,44 @@ export function GenerationsTable() { ]; }, [fields]); - const {data, meta, isLoading, error, pageLinks, isPlaceholderData} = useSpans( - { - search: query, - fields: [...REQUIRED_FIELDS, ...fieldsToQuery] as any, - cursor, - sorts: [tableSort], - keepPreviousData: true, - limit: 20, - }, - Referrer.GENERATIONS_TABLE - ); + const eventView = useMemo(() => { + const queryFields = [...REQUIRED_FIELDS, ...fieldsToQuery]; + + const discoverQuery: NewQuery = { + id: undefined, + name: 'AI Generations', + fields: queryFields, + orderby: [`${tableSort.kind === 'desc' ? '-' : ''}${tableSort.field}`], + query, + version: 2, + dataset: DiscoverDatasets.SPANS, + }; + + return EventView.fromNewQueryWithPageFilters(discoverQuery, selection); + }, [fieldsToQuery, query, selection, tableSort.field, tableSort.kind]); + + const { + data = [], + meta, + isLoading, + error, + pageLinks, + isPlaceholderData, + } = useSpansQuery>>({ + eventView, + cursor, + limit: 20, + referrer: Referrer.GENERATIONS_TABLE, + initialData: [], + allowAggregateConditions: false, + trackResponseAnalytics: false, + queryExtras: {caseInsensitive}, + }); - type TableData = (typeof data)[number]; + type TableData = Record; const renderBodyCell = useCallback( - (column: GridColumnOrder, dataRow: TableData) => { + (column: GridColumnOrder, dataRow: TableData) => { if (column.key === SpanFields.ID) { return (
@@ -120,13 +149,13 @@ export function GenerationsTable() { priority="link" onClick={() => { openTraceViewDrawer( - dataRow.trace!, + dataRow.trace, dataRow.id, getTimeStampFromTableDateField(dataRow.timestamp) ); }} > - {getShortEventId(dataRow.id!)} + {getShortEventId(dataRow.id)}
); @@ -196,7 +225,7 @@ export function GenerationsTable() { if (column.key === SpanFields.TIMESTAMP) { return ( - + ); } @@ -212,7 +241,7 @@ export function GenerationsTable() { ); const renderHeadCell = useCallback( - (column: GridColumnOrder) => { + (column: GridColumnOrder) => { return ( => ({ + (field): GridColumnOrder => ({ key: field, name: prettyFieldNames[field] ?? field, width: columnWidths[field] ?? COL_WIDTH_UNDEFINED, diff --git a/static/app/views/insights/aiGenerations/views/overview.tsx b/static/app/views/insights/aiGenerations/views/overview.tsx index e4116aba4b21cf..376706104b2631 100644 --- a/static/app/views/insights/aiGenerations/views/overview.tsx +++ b/static/app/views/insights/aiGenerations/views/overview.tsx @@ -14,6 +14,7 @@ import { useEAPSpanSearchQueryBuilderProps, } from 'sentry/components/performance/spanSearchQueryBuilder'; import {SearchQueryBuilderProvider} from 'sentry/components/searchQueryBuilder/context'; +import {useCaseInsensitivity} from 'sentry/components/searchQueryBuilder/hooks'; import {IconChevron, IconEdit} from 'sentry/icons'; import {t} from 'sentry/locale'; import {getSelectedProjectList} from 'sentry/utils/project/useSelectedProjectsHaveField'; @@ -58,6 +59,7 @@ function AIGenerationsPage() { const [sidebarOpen, setSidebarOpen] = useState(true); const showOnboarding = useShowOnboarding(); const datePageFilterProps = limitMaxPickableDays(organization); + const [caseInsensitive, setCaseInsensitive] = useCaseInsensitivity(); const [searchQuery, setSearchQuery] = useQueryState( 'query', @@ -93,12 +95,16 @@ function AIGenerationsPage() { {key: 'trace', valuePattern: /^[0-9a-fA-F]{32}$/}, {key: 'id', valuePattern: /^[0-9a-fA-F]{16}$/}, ], + caseInsensitive, + onCaseInsensitiveClick: setCaseInsensitive, }), [ + caseInsensitive, hasRawSearchReplacement, numberSecondaryAliases, numberTags, searchQuery, + setCaseInsensitive, setSearchQuery, stringSecondaryAliases, stringTags,