1- import { useCallback } from 'react' ;
1+ import { useCallback , useMemo } from 'react' ;
2+ import { useTheme } from '@emotion/react' ;
23
34import { Button } from '@sentry/scraps/button' ;
45import { Container , Grid } from '@sentry/scraps/layout' ;
@@ -12,8 +13,11 @@ import {
1213import TimeSince from 'sentry/components/timeSince' ;
1314import { t } from 'sentry/locale' ;
1415import { getTimeStampFromTableDateField } from 'sentry/utils/dates' ;
16+ import { getFieldRenderer } from 'sentry/utils/discover/fieldRenderers' ;
1517import type { Sort } from 'sentry/utils/discover/fields' ;
1618import { getShortEventId } from 'sentry/utils/events' ;
19+ import { useLocation } from 'sentry/utils/useLocation' ;
20+ import useOrganization from 'sentry/utils/useOrganization' ;
1721import { useTraceViewDrawer } from 'sentry/views/insights/agents/components/drawer' ;
1822import {
1923 HeadSortCell ,
@@ -22,27 +26,27 @@ import {
2226import { ModelName } from 'sentry/views/insights/agents/components/modelName' ;
2327import { useCombinedQuery } from 'sentry/views/insights/agents/hooks/useCombinedQuery' ;
2428import { useTableCursor } from 'sentry/views/insights/agents/hooks/useTableCursor' ;
25- import { AI_GENERATIONS_PAGE_FILTER } from 'sentry/views/insights/aiGenerations/views/utils/constants' ;
29+ import {
30+ AI_GENERATIONS_PAGE_FILTER ,
31+ INPUT_OUTPUT_FIELD ,
32+ type GenerationFields ,
33+ } from 'sentry/views/insights/aiGenerations/views/utils/constants' ;
2634import { Referrer } from 'sentry/views/insights/aiGenerations/views/utils/referrer' ;
35+ import { useFieldsQueryParam } from 'sentry/views/insights/aiGenerations/views/utils/useFieldsQueryParam' ;
2736import { TextAlignRight } from 'sentry/views/insights/common/components/textAlign' ;
2837import { useSpans } from 'sentry/views/insights/common/queries/useDiscover' ;
2938import { PlatformInsightsTable } from 'sentry/views/insights/pages/platform/shared/table' ;
3039import { SpanFields } from 'sentry/views/insights/types' ;
3140
32- const INITIAL_COLUMN_ORDER = [
33- { key : SpanFields . SPAN_ID , name : t ( 'Span ID' ) , width : 100 } ,
34- {
35- key : SpanFields . GEN_AI_REQUEST_MESSAGES ,
36- name : t ( 'Input / Output' ) ,
37- width : COL_WIDTH_UNDEFINED ,
38- } ,
39- {
40- key : SpanFields . GEN_AI_REQUEST_MODEL ,
41- name : t ( 'Model' ) ,
42- width : 200 ,
43- } ,
44- { key : SpanFields . TIMESTAMP , name : t ( 'Timestamp' ) } ,
45- ] as const ;
41+ const columnWidths : Partial < Record < GenerationFields , number > > = {
42+ [ SpanFields . ID ] : 100 ,
43+ [ INPUT_OUTPUT_FIELD ] : COL_WIDTH_UNDEFINED ,
44+ [ SpanFields . GEN_AI_REQUEST_MODEL ] : 200 ,
45+ } ;
46+
47+ const prettyFieldNames : Partial < Record < GenerationFields , string > > = {
48+ [ SpanFields . GEN_AI_REQUEST_MODEL ] : t ( 'Model' ) ,
49+ } ;
4650
4751const DEFAULT_SORT : Sort = { field : SpanFields . TIMESTAMP , kind : 'desc' } ;
4852
@@ -63,26 +67,40 @@ function getLastInputMessage(messages?: string) {
6367 }
6468}
6569
70+ const REQUIRED_FIELDS = [
71+ SpanFields . SPAN_STATUS ,
72+ SpanFields . PROJECT ,
73+ SpanFields . TIMESTAMP ,
74+ SpanFields . TRACE ,
75+ SpanFields . ID ,
76+ SpanFields . GEN_AI_REQUEST_MESSAGES ,
77+ SpanFields . GEN_AI_RESPONSE_TEXT ,
78+ SpanFields . GEN_AI_RESPONSE_OBJECT ,
79+ ] ;
80+
6681export function GenerationsTable ( ) {
6782 const { openTraceViewDrawer} = useTraceViewDrawer ( { } ) ;
6883 const query = useCombinedQuery ( AI_GENERATIONS_PAGE_FILTER ) ;
6984 const { cursor} = useTableCursor ( ) ;
7085 const { tableSort} = useTableSort ( DEFAULT_SORT ) ;
86+ const [ fields ] = useFieldsQueryParam ( ) ;
87+ const location = useLocation ( ) ;
88+ const organization = useOrganization ( ) ;
89+ const theme = useTheme ( ) ;
90+
91+ const fieldsToQuery = useMemo ( ( ) => {
92+ return [
93+ ...fields . filter (
94+ ( field ) : field is SpanFields =>
95+ field !== INPUT_OUTPUT_FIELD && ! REQUIRED_FIELDS . includes ( field )
96+ ) ,
97+ ] ;
98+ } , [ fields ] ) ;
7199
72- const { data, isLoading, error, pageLinks, isPlaceholderData} = useSpans (
100+ const { data, meta , isLoading, error, pageLinks, isPlaceholderData} = useSpans (
73101 {
74102 search : query ,
75- fields : [
76- SpanFields . TRACE ,
77- SpanFields . SPAN_ID ,
78- SpanFields . SPAN_STATUS ,
79- SpanFields . SPAN_DESCRIPTION ,
80- SpanFields . GEN_AI_REQUEST_MESSAGES ,
81- SpanFields . GEN_AI_RESPONSE_TEXT ,
82- SpanFields . GEN_AI_RESPONSE_OBJECT ,
83- SpanFields . GEN_AI_REQUEST_MODEL ,
84- SpanFields . TIMESTAMP ,
85- ] ,
103+ fields : [ ...REQUIRED_FIELDS , ...fieldsToQuery ] as any ,
86104 cursor,
87105 sorts : [ tableSort ] ,
88106 keepPreviousData : true ,
@@ -94,27 +112,27 @@ export function GenerationsTable() {
94112 type TableData = ( typeof data ) [ number ] ;
95113
96114 const renderBodyCell = useCallback (
97- ( column : GridColumnOrder < keyof TableData > , dataRow : TableData ) => {
98- if ( column . key === SpanFields . SPAN_ID ) {
115+ ( column : GridColumnOrder < GenerationFields > , dataRow : TableData ) => {
116+ if ( column . key === SpanFields . ID ) {
99117 return (
100118 < div >
101119 < Button
102120 priority = "link"
103121 onClick = { ( ) => {
104122 openTraceViewDrawer (
105- dataRow . trace ,
106- dataRow . span_id ,
123+ dataRow . trace ! ,
124+ dataRow . id ,
107125 getTimeStampFromTableDateField ( dataRow . timestamp )
108126 ) ;
109127 } }
110128 >
111- { getShortEventId ( dataRow . span_id ) }
129+ { getShortEventId ( dataRow . id ! ) }
112130 </ Button >
113131 </ div >
114132 ) ;
115133 }
116134
117- if ( column . key === SpanFields . GEN_AI_REQUEST_MESSAGES ) {
135+ if ( column . key === INPUT_OUTPUT_FIELD ) {
118136 const noValueFallback = < Text variant = "muted" > –</ Text > ;
119137 const statusValue = dataRow [ SpanFields . SPAN_STATUS ] ;
120138 const isError = statusValue && statusValue !== 'ok' && statusValue !== 'unknown' ;
@@ -178,13 +196,19 @@ export function GenerationsTable() {
178196 if ( column . key === SpanFields . TIMESTAMP ) {
179197 return (
180198 < TextAlignRight >
181- < TimeSince unitStyle = "extraShort " date = { new Date ( dataRow . timestamp ) } />
199+ < TimeSince unitStyle = "short " date = { new Date ( dataRow . timestamp ! ) } />
182200 </ TextAlignRight >
183201 ) ;
184202 }
185- return < div > { dataRow [ column . key ] } </ div > ;
203+ const fieldRenderer = getFieldRenderer ( column . key , meta ! ) ;
204+ return fieldRenderer ( dataRow , {
205+ location,
206+ organization,
207+ theme,
208+ projectSlug : dataRow . project ,
209+ } ) ;
186210 } ,
187- [ openTraceViewDrawer ]
211+ [ openTraceViewDrawer , meta , location , organization , theme ]
188212 ) ;
189213
190214 const renderHeadCell = useCallback (
@@ -194,7 +218,7 @@ export function GenerationsTable() {
194218 align = { column . key === SpanFields . TIMESTAMP ? 'right' : 'left' }
195219 currentSort = { tableSort }
196220 sortKey = { column . key }
197- forceCellGrow = { column . key === SpanFields . GEN_AI_REQUEST_MESSAGES }
221+ forceCellGrow = { column . key === INPUT_OUTPUT_FIELD }
198222 >
199223 { column . name }
200224 </ HeadSortCell >
@@ -204,20 +228,27 @@ export function GenerationsTable() {
204228 ) ;
205229
206230 return (
207- < div >
231+ < Container >
208232 < PlatformInsightsTable
233+ key = { fields . join ( ',' ) }
209234 data = { data }
210235 stickyHeader
211236 isLoading = { isLoading }
212237 error = { error }
213- initialColumnOrder = { INITIAL_COLUMN_ORDER as any }
238+ initialColumnOrder = { fields . map (
239+ ( field ) : GridColumnOrder < GenerationFields > => ( {
240+ key : field ,
241+ name : prettyFieldNames [ field ] ?? field ,
242+ width : columnWidths [ field ] ?? COL_WIDTH_UNDEFINED ,
243+ } )
244+ ) }
214245 pageLinks = { pageLinks }
215246 grid = { {
216247 renderBodyCell,
217248 renderHeadCell,
218249 } }
219250 isPlaceholderData = { isPlaceholderData }
220251 />
221- </ div >
252+ </ Container >
222253 ) ;
223254}
0 commit comments