import {CSSProperties, useCallback, useEffect, useState} from 'react'; import {css} from '@emotion/react'; import styled from '@emotion/styled'; import debounce from 'lodash/debounce'; import isEqual from 'lodash/isEqual'; import {TableCell} from 'sentry/components/charts/simpleTableChart'; import Field from 'sentry/components/forms/field'; import SelectControl from 'sentry/components/forms/selectControl'; import {PanelAlert} from 'sentry/components/panels'; import {DEFAULT_DEBOUNCE_DURATION} from 'sentry/constants'; import {t} from 'sentry/locale'; import space from 'sentry/styles/space'; import {Organization, PageFilters, SelectValue} from 'sentry/types'; import usePrevious from 'sentry/utils/usePrevious'; import {DashboardFilters, DisplayType, Widget} from 'sentry/views/dashboardsV2/types'; import WidgetCard, {WidgetCardPanel} from '../../widgetCard'; import {displayTypes} from '../utils'; import {BuildStep} from './buildStep'; interface Props { displayType: DisplayType; onChange: (displayType: DisplayType) => void; organization: Organization; pageFilters: PageFilters; widget: Widget; dashboardFilters?: DashboardFilters; error?: string; noDashboardsMEPProvider?: boolean; } export function VisualizationStep({ organization, pageFilters, displayType, error, onChange, widget, noDashboardsMEPProvider, dashboardFilters, }: Props) { const [debouncedWidget, setDebouncedWidget] = useState(widget); const previousWidget = usePrevious(widget); // Disabling for now because we use debounce to avoid excessively hitting // our endpoints, but useCallback wants an inline function and not one // returned from debounce // eslint-disable-next-line react-hooks/exhaustive-deps const debounceWidget = useCallback( debounce((value: Widget, shouldCancelUpdates: boolean) => { if (shouldCancelUpdates) { return; } setDebouncedWidget(value); }, DEFAULT_DEBOUNCE_DURATION), [] ); useEffect(() => { let shouldCancelUpdates = false; if (!isEqual(previousWidget, widget)) { debounceWidget(widget, shouldCancelUpdates); } return () => { shouldCancelUpdates = true; }; }, [widget, previousWidget, debounceWidget]); const displayOptions = Object.keys(displayTypes).map(value => ({ label: displayTypes[value], value, })); return ( ) => { onChange(option.value); }} styles={{ singleValue: (provided: CSSProperties) => ({ ...provided, width: `calc(100% - ${space(1)})`, }), }} /> typeof errorMessage === 'string' && ( {errorMessage} ) } isSorting={false} currentWidgetDragging={false} noLazyLoad showStoredAlert noDashboardsMEPProvider={noDashboardsMEPProvider} /> ); } const VisualizationWrapper = styled('div')<{displayType: DisplayType}>` padding-right: ${space(2)}; ${WidgetCardPanel} { height: initial; } ${p => p.displayType === DisplayType.TABLE && css` overflow: hidden; ${TableCell} { /* 24px ActorContainer height + 16px top and bottom padding + 1px border = 41px */ height: 41px; } ${WidgetCardPanel} { /* total size of a table, if it would display 5 rows of content */ height: 301px; } `}; `;