import {useState} from 'react'; import styled from '@emotion/styled'; import type {Location} from 'history'; import GridEditable, { COL_WIDTH_UNDEFINED, GridColumn, } from 'sentry/components/gridEditable'; import type {Alignments} from 'sentry/components/gridEditable/sortLink'; import Link from 'sentry/components/links/link'; import type {Organization, Project} from 'sentry/types'; import DiscoverQuery, { TableData, TableDataRow, } from 'sentry/utils/discover/discoverQuery'; import {getFieldRenderer} from 'sentry/utils/discover/fieldRenderers'; import {fieldAlignment} from 'sentry/utils/discover/fields'; import type {MetricRule} from 'sentry/views/alerts/rules/metric/types'; import {getMetricRuleDiscoverQuery} from 'sentry/views/alerts/utils/getMetricRuleDiscoverUrl'; import type {TableColumn} from 'sentry/views/discover/table/types'; import {transactionSummaryRouteWithQuery} from 'sentry/views/performance/transactionSummary/utils'; import {getProjectID} from 'sentry/views/performance/utils'; import type {TimePeriodType} from './constants'; interface RelatedTransactionsProps { filter: string; location: Location; organization: Organization; projects: Project[]; rule: MetricRule; timePeriod: TimePeriodType; } function RelatedTransactions({ organization, projects, timePeriod, rule, filter, location, }: RelatedTransactionsProps) { const [widths, setWidths] = useState([]); const eventView = getMetricRuleDiscoverQuery({ rule, timePeriod, projects, }); const summaryConditions = `${rule.query} ${filter}`; function renderBodyCell( tableData: TableData | null, column: TableColumn, dataRow: TableDataRow ): React.ReactNode { if (!tableData || !tableData.meta) { return dataRow[column.key]; } const tableMeta = tableData.meta; const field = String(column.key); const fieldRenderer = getFieldRenderer(field, tableMeta, false); const rendered = fieldRenderer(dataRow, {organization, location}); if (field === 'transaction') { const projectID = getProjectID(dataRow, projects); const summaryView = eventView!.clone(); summaryView.query = summaryConditions; const target = transactionSummaryRouteWithQuery({ orgSlug: organization.slug, transaction: String(dataRow.transaction) || '', query: summaryView.generateQueryStringObject(), projectID, }); return {rendered}; } return rendered; } const renderBodyCellWithData = (tableData: TableData | null) => { return ( column: TableColumn, dataRow: TableDataRow ): React.ReactNode => renderBodyCell(tableData, column, dataRow); }; function renderHeadCell( tableMeta: TableData['meta'], column: TableColumn, title: React.ReactNode ): React.ReactNode { const align = fieldAlignment(column.name, column.type, tableMeta); const field = {field: column.name, width: column.width}; return {title || field.field}; } const renderHeadCellWithMeta = (tableMeta: TableData['meta'], columnName: string) => { const columnTitles = ['transactions', 'project', columnName, 'users', 'user misery']; return (column: TableColumn, index: number): React.ReactNode => renderHeadCell(tableMeta, column, columnTitles[index]); }; const handleResizeColumn = (columnIndex: number, nextColumn: GridColumn) => { const newWidths: number[] = [...widths]; newWidths[columnIndex] = nextColumn.width ? Number(nextColumn.width) : COL_WIDTH_UNDEFINED; setWidths(newWidths); }; if (!eventView) { return null; } const columnOrder = eventView .getColumns() .map((col: TableColumn, i: number) => { if (typeof widths[i] === 'number') { return {...col, width: widths[i]}; } return col; }); const sortedEventView = eventView.withSorts([...eventView.sorts]); const columnSortBy = sortedEventView.getSorts(); return ( {({isLoading, tableData}) => ( )} ); } export default RelatedTransactions; const HeaderCell = styled('div')<{align: Alignments}>` display: block; width: 100%; white-space: nowrap; ${(p: {align: Alignments}) => (p.align ? `text-align: ${p.align};` : '')} `;