import {Fragment, useMemo, useState} from 'react'; import {useSortable} from '@dnd-kit/sortable'; import {CSS} from '@dnd-kit/utilities'; import styled from '@emotion/styled'; import type {ModalRenderProps} from 'sentry/actionCreators/modal'; import {Button, LinkButton} from 'sentry/components/button'; import ButtonBar from 'sentry/components/buttonBar'; import type {SelectKey, SelectOption} from 'sentry/components/compactSelect'; import {CompactSelect} from 'sentry/components/compactSelect'; import {SPAN_PROPS_DOCS_URL} from 'sentry/constants'; import {IconAdd} from 'sentry/icons/iconAdd'; import {IconDelete} from 'sentry/icons/iconDelete'; import {IconGrabbable} from 'sentry/icons/iconGrabbable'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import type {TagCollection} from 'sentry/types/group'; import {defined} from 'sentry/utils'; import {TypeBadge} from 'sentry/views/explore/components/typeBadge'; import {DragNDropContext} from '../contexts/dragNDropContext'; import type {Column} from '../hooks/useDragNDropColumns'; interface ColumnEditorModalProps extends ModalRenderProps { columns: string[]; numberTags: TagCollection; onColumnsChange: (fields: string[]) => void; stringTags: TagCollection; } export function ColumnEditorModal({ Header, Body, Footer, closeModal, columns, onColumnsChange, numberTags, stringTags, }: ColumnEditorModalProps) { const tags: SelectOption[] = useMemo(() => { const allTags = [ ...Object.values(stringTags).map(tag => { return { label: tag.name, value: tag.key, textValue: tag.name, trailingItems: , }; }), ...Object.values(numberTags).map(tag => { return { label: tag.name, value: tag.key, textValue: tag.name, trailingItems: , }; }), ]; allTags.sort((a, b) => { if (a.label < b.label) { return -1; } if (a.label > b.label) { return 1; } return 0; }); return allTags; }, [stringTags, numberTags]); // We keep a temporary state for the columns so that we can apply the changes // only when the user clicks on the apply button. const [tempColumns, setTempColumns] = useState(columns); function handleApply() { onColumnsChange(tempColumns.filter(Boolean)); closeModal(); } return ( {({insertColumn, updateColumnAtIndex, deleteColumnAtIndex, editableColumns}) => (

{t('Edit Table')}

{editableColumns.map((column, i) => { return ( 1} column={column} options={tags} onColumnChange={c => updateColumnAtIndex(i, c)} onColumnDelete={() => deleteColumnAtIndex(i)} /> ); })}
{t('Read the Docs')}
)}
); } interface ColumnEditorRowProps { canDelete: boolean; column: Column; onColumnChange: (column: string) => void; onColumnDelete: () => void; options: SelectOption[]; } function ColumnEditorRow({ canDelete, column, options, onColumnChange, onColumnDelete, }: 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); } } // The compact select component uses the option label to render the current // selection. This overrides it to render in a trailing item showing the type. const label = useMemo(() => { if (defined(column.column)) { const tag = options.find(option => option.value === column.column); if (defined(tag)) { return ( {tag.label} {tag.trailingItems && (typeof tag.trailingItems === 'function' ? tag.trailingItems({ disabled: false, isFocused: false, isSelected: false, }) : tag.trailingItems)} ); } } return {!column.column && t('None')}; }, [column.column, options]); return (