import {useMemo} from 'react'; import {useSortable} from '@dnd-kit/sortable'; import {CSS} from '@dnd-kit/utilities'; import styled from '@emotion/styled'; import {Button} from 'sentry/components/button'; import type {SelectKey, SelectOption} from 'sentry/components/compactSelect'; import {CompactSelect} from 'sentry/components/compactSelect'; import {Tooltip} from 'sentry/components/tooltip'; import {IconAdd} from 'sentry/icons/iconAdd'; import {IconDelete} from 'sentry/icons/iconDelete'; import {IconGrabbable} from 'sentry/icons/iconGrabbable'; import {t} from 'sentry/locale'; import {defined} from 'sentry/utils'; import { useExploreGroupBys, useExploreMode, useSetExploreGroupBys, } from 'sentry/views/explore/contexts/pageParamsContext'; import {UNGROUPED} from 'sentry/views/explore/contexts/pageParamsContext/groupBys'; import {Mode} from 'sentry/views/explore/contexts/pageParamsContext/mode'; import {DragNDropContext} from '../contexts/dragNDropContext'; import {useSpanTags} from '../contexts/spanTagsContext'; import type {Column} from '../hooks/useDragNDropColumns'; import { ToolbarHeader, ToolbarHeaderButton, ToolbarLabel, ToolbarRow, ToolbarSection, } from './styles'; interface ToolbarGroupByProps { disabled?: boolean; } export function ToolbarGroupBy({disabled}: ToolbarGroupByProps) { const tags = useSpanTags(); const mode = useExploreMode(); const groupBys = useExploreGroupBys(); const setGroupBys = useSetExploreGroupBys(); const disabledOptions: Array> = useMemo(() => { return [ { label: {t('Samples not grouped')}, value: UNGROUPED, textValue: t('none'), }, ]; }, []); const enabledOptions: Array> = useMemo(() => { const potentialOptions = [ // We do not support grouping by span id, we have a dedicated sample mode for that ...Object.keys(tags).filter(key => key !== 'id'), // These options aren't known to exist on this project but it was inserted into // the group bys somehow so it should be a valid options in the group bys. // // One place this may come from is when switching projects/environment/date range, // a tag may disappear based on the selection. ...groupBys.filter(groupBy => groupBy && !tags.hasOwnProperty(groupBy)), ]; potentialOptions.sort(); return [ // hard code in an empty option { label: {t('None')}, value: UNGROUPED, textValue: t('none'), }, ...potentialOptions.map(key => ({ label: key, value: key, textValue: key, })), ]; }, [groupBys, tags]); return ( {({editableColumns, insertColumn, updateColumnAtIndex, deleteColumnAtIndex}) => { return ( {t('Group By')} } /> {disabled ? ( {}} onColumnDelete={() => {}} /> ) : ( editableColumns.map((column, i) => ( 1 || !['', undefined].includes(column.column) } column={column} options={enabledOptions} onColumnChange={c => updateColumnAtIndex(i, c)} onColumnDelete={() => deleteColumnAtIndex(i)} /> )) )} ); }} ); } interface ColumnEditorRowProps { canDelete: boolean; column: Column; onColumnChange: (column: string) => void; onColumnDelete: () => void; options: Array>; disabled?: boolean; } function ColumnEditorRow({ canDelete, column, options, onColumnChange, onColumnDelete, disabled = false, }: ColumnEditorRowProps) { const {attributes, listeners, setNodeRef, transform, transition} = useSortable({ id: column.id, }); function handleColumnChange(option: SelectOption) { if (defined(option) && typeof option.value === 'string') { onColumnChange(option.value); } } const label = useMemo(() => { const tag = options.find(option => option.value === column.column); return {tag?.label ?? t('None')}; }, [column.column, options]); return (