Skip to content

Commit 364c5aa

Browse files
ArthurKnausJesse-Box
authored andcommitted
1 parent c52f9d0 commit 364c5aa

File tree

5 files changed

+178
-65
lines changed

5 files changed

+178
-65
lines changed

static/app/views/explore/tables/columnEditorModal.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ interface ColumnEditorModalProps extends ModalRenderProps {
3232
handleReset?: () => void;
3333
hiddenKeys?: string[];
3434
isDocsButtonHidden?: boolean;
35+
requiredTags?: string[];
3536
}
3637

3738
export function ColumnEditorModal({
@@ -41,6 +42,7 @@ export function ColumnEditorModal({
4142
closeModal,
4243
columns,
4344
onColumnsChange,
45+
requiredTags,
4446
numberTags,
4547
stringTags,
4648
hiddenKeys,
@@ -146,6 +148,7 @@ export function ColumnEditorModal({
146148
<ColumnEditorRow
147149
key={column.id}
148150
canDelete={editableColumns.length > 1}
151+
required={requiredTags?.includes(column.column)}
149152
column={column}
150153
options={tags}
151154
onColumnChange={c => updateColumnAtIndex(i, c)}
@@ -201,11 +204,13 @@ interface ColumnEditorRowProps {
201204
onColumnChange: (column: string) => void;
202205
onColumnDelete: () => void;
203206
options: Array<SelectOption<string>>;
207+
required?: boolean;
204208
}
205209

206210
function ColumnEditorRow({
207211
canDelete,
208212
column,
213+
required,
209214
options,
210215
onColumnChange,
211216
onColumnDelete,
@@ -266,6 +271,7 @@ function ColumnEditorRow({
266271
options={options}
267272
value={column.column ?? ''}
268273
onChange={handleColumnChange}
274+
disabled={required}
269275
searchable
270276
triggerProps={{
271277
children: label,
@@ -278,7 +284,7 @@ function ColumnEditorRow({
278284
<StyledButton
279285
aria-label={t('Remove Column')}
280286
borderless
281-
disabled={!canDelete}
287+
disabled={!canDelete || required}
282288
size="sm"
283289
icon={<IconDelete size="sm" />}
284290
onClick={onColumnDelete}

static/app/views/insights/aiGenerations/views/components/generationsTable.tsx

Lines changed: 72 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import {useCallback} from 'react';
1+
import {useCallback, useMemo} from 'react';
2+
import {useTheme} from '@emotion/react';
23

34
import {Button} from '@sentry/scraps/button';
45
import {Container, Grid} from '@sentry/scraps/layout';
@@ -12,8 +13,11 @@ import {
1213
import TimeSince from 'sentry/components/timeSince';
1314
import {t} from 'sentry/locale';
1415
import {getTimeStampFromTableDateField} from 'sentry/utils/dates';
16+
import {getFieldRenderer} from 'sentry/utils/discover/fieldRenderers';
1517
import type {Sort} from 'sentry/utils/discover/fields';
1618
import {getShortEventId} from 'sentry/utils/events';
19+
import {useLocation} from 'sentry/utils/useLocation';
20+
import useOrganization from 'sentry/utils/useOrganization';
1721
import {useTraceViewDrawer} from 'sentry/views/insights/agents/components/drawer';
1822
import {
1923
HeadSortCell,
@@ -22,27 +26,27 @@ import {
2226
import {ModelName} from 'sentry/views/insights/agents/components/modelName';
2327
import {useCombinedQuery} from 'sentry/views/insights/agents/hooks/useCombinedQuery';
2428
import {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';
2634
import {Referrer} from 'sentry/views/insights/aiGenerations/views/utils/referrer';
35+
import {useFieldsQueryParam} from 'sentry/views/insights/aiGenerations/views/utils/useFieldsQueryParam';
2736
import {TextAlignRight} from 'sentry/views/insights/common/components/textAlign';
2837
import {useSpans} from 'sentry/views/insights/common/queries/useDiscover';
2938
import {PlatformInsightsTable} from 'sentry/views/insights/pages/platform/shared/table';
3039
import {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

4751
const 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+
6681
export 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

Comments
 (0)