diff --git a/packages/app/src/components/DBEditTimeChartForm.tsx b/packages/app/src/components/DBEditTimeChartForm.tsx deleted file mode 100644 index 40bdc11885..0000000000 --- a/packages/app/src/components/DBEditTimeChartForm.tsx +++ /dev/null @@ -1,1783 +0,0 @@ -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { - Control, - Controller, - FieldErrors, - Path, - useFieldArray, - useForm, - UseFormClearErrors, - UseFormSetValue, - useWatch, -} from 'react-hook-form'; -import { NativeSelect, NumberInput } from 'react-hook-form-mantine'; -import z from 'zod'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { tcFromSource } from '@hyperdx/common-utils/dist/core/metadata'; -import { - isBuilderChartConfig, - isRawSqlChartConfig, - isRawSqlSavedChartConfig, -} from '@hyperdx/common-utils/dist/guards'; -import { - ChartAlertBaseSchema, - ChartConfigWithDateRange, - ChartConfigWithOptTimestamp, - DateRange, - DisplayType, - Filter, - MetricsDataType, - SavedChartConfig, - SelectList, - SourceKind, - TSource, - validateAlertScheduleOffsetMinutes, -} from '@hyperdx/common-utils/dist/types'; -import { - Accordion, - ActionIcon, - Box, - Button, - Divider, - Flex, - Group, - List, - Menu, - Paper, - SegmentedControl, - Stack, - Switch, - Tabs, - Text, - Textarea, -} from '@mantine/core'; -import { useDisclosure } from '@mantine/hooks'; -import { notifications } from '@mantine/notifications'; -import { - IconArrowDown, - IconArrowUp, - IconBell, - IconChartLine, - IconChartPie, - IconCirclePlus, - IconCode, - IconDotsVertical, - IconLayoutGrid, - IconList, - IconMarkdown, - IconNumbers, - IconPlayerPlay, - IconTable, - IconTrash, - IconX, -} from '@tabler/icons-react'; -import { SortingState } from '@tanstack/react-table'; - -import { - AGG_FNS, - buildTableRowSearchUrl, - convertToNumberChartConfig, - convertToPieChartConfig, - convertToTableChartConfig, - convertToTimeChartConfig, - getPreviousDateRange, -} from '@/ChartUtils'; -import { AlertChannelForm, getAlertReferenceLines } from '@/components/Alerts'; -import ChartSQLPreview from '@/components/ChartSQLPreview'; -import DBTableChart from '@/components/DBTableChart'; -import { DBTimeChart } from '@/components/DBTimeChart'; -import EmptyState from '@/components/EmptyState'; -import SearchWhereInput, { - getStoredLanguage, -} from '@/components/SearchInput/SearchWhereInput'; -import { SQLInlineEditorControlled } from '@/components/SQLEditor/SQLInlineEditor'; -import { TimePicker } from '@/components/TimePicker'; -import { IS_LOCAL_MODE } from '@/config'; -import { GranularityPickerControlled } from '@/GranularityPicker'; -import { useFetchMetricMetadata } from '@/hooks/useFetchMetricMetadata'; -import { - parseAttributeKeysFromSuggestions, - useFetchMetricResourceAttrs, -} from '@/hooks/useFetchMetricResourceAttrs'; -import { getFirstTimestampValueExpression, useSource } from '@/source'; -import { - getMetricTableName, - optionsToSelectData, - orderByStringToSortingState, - sortingStateToOrderByString, -} from '@/utils'; -import { - ALERT_CHANNEL_OPTIONS, - DEFAULT_TILE_ALERT, - extendDateRangeToInterval, - intervalToGranularity, - intervalToMinutes, - normalizeNoOpAlertScheduleFields, - TILE_ALERT_INTERVAL_OPTIONS, - TILE_ALERT_THRESHOLD_TYPE_OPTIONS, -} from '@/utils/alerts'; - -import HDXMarkdownChart from '../HDXMarkdownChart'; - -import RawSqlChartEditor from './ChartEditor/RawSqlChartEditor'; -import { - ChartEditorFormState, - SavedChartConfigWithSelectArray, -} from './ChartEditor/types'; -import { - convertFormStateToChartConfig, - convertFormStateToSavedChartConfig, - convertSavedChartConfigToFormState, - isRawSqlDisplayType, - validateChartForm, -} from './ChartEditor/utils'; -import { ErrorBoundary } from './Error/ErrorBoundary'; -import MVOptimizationIndicator from './MaterializedViews/MVOptimizationIndicator'; -import { AggFnSelectControlled } from './AggFnSelect'; -import { AlertScheduleFields } from './AlertScheduleFields'; -import ChartDisplaySettingsDrawer, { - ChartConfigDisplaySettings, -} from './ChartDisplaySettingsDrawer'; -import DBNumberChart from './DBNumberChart'; -import { DBPieChart } from './DBPieChart'; -import DBSqlRowTableWithSideBar from './DBSqlRowTableWithSidebar'; -import { - CheckBoxControlled, - InputControlled, - TextInputControlled, -} from './InputControlled'; -import { MetricAttributeHelperPanel } from './MetricAttributeHelperPanel'; -import { MetricNameSelect } from './MetricNameSelect'; -import SaveToDashboardModal from './SaveToDashboardModal'; -import SourceSchemaPreview from './SourceSchemaPreview'; -import { SourceSelectControlled } from './SourceSelect'; - -const isQueryReady = (queriedConfig: ChartConfigWithDateRange | undefined) => { - if (!queriedConfig) return false; - if (isRawSqlChartConfig(queriedConfig)) { - return !!(queriedConfig.sqlTemplate && queriedConfig.connection); - } - return ( - ((queriedConfig.select?.length ?? 0) > 0 || - typeof queriedConfig.select === 'string') && - queriedConfig.from?.databaseName && - // tableName is empty for metric sources - (queriedConfig.from?.tableName || queriedConfig.metricTables) && - queriedConfig.timestampValueExpression - ); -}; - -type SeriesItem = NonNullable< - SavedChartConfigWithSelectArray['select'] ->[number]; - -function ChartSeriesEditorComponent({ - control, - databaseName, - dateRange, - connectionId, - index, - namePrefix, - onRemoveSeries, - onSwapSeries, - onSubmit, - setValue, - showGroupBy, - showHaving, - tableName: _tableName, - parentRef, - length, - tableSource, - errors, - clearErrors, -}: { - control: Control; - databaseName: string; - dateRange?: DateRange['dateRange']; - connectionId?: string; - index: number; - namePrefix: `series.${number}.`; - parentRef?: HTMLElement | null; - onRemoveSeries: (index: number) => void; - onSwapSeries: (from: number, to: number) => void; - onSubmit: () => void; - setValue: UseFormSetValue; - showGroupBy: boolean; - showHaving: boolean; - tableName: string; - length: number; - tableSource?: TSource; - errors?: FieldErrors; - clearErrors: UseFormClearErrors; -}) { - const aggFn = useWatch({ control, name: `${namePrefix}aggFn` }); - const aggConditionLanguage = useWatch({ - control, - name: `${namePrefix}aggConditionLanguage`, - defaultValue: 'lucene', - }); - - const metricType = useWatch({ control, name: `${namePrefix}metricType` }); - - // Initialize metricType to 'gauge' when switching to a metric source - // and reset 'custom' aggFn to 'count' since custom is not supported for metrics - useEffect(() => { - if (tableSource?.kind === SourceKind.Metric) { - if (!metricType) { - setValue(`${namePrefix}metricType`, MetricsDataType.Gauge); - } - if (aggFn === 'none') { - setValue(`${namePrefix}aggFn`, 'count'); - } - } - }, [tableSource?.kind, metricType, aggFn, namePrefix, setValue]); - - const tableName = - tableSource?.kind === SourceKind.Metric - ? getMetricTableName(tableSource, metricType) - : _tableName; - - const metricName = useWatch({ control, name: `${namePrefix}metricName` }); - const aggCondition = useWatch({ - control, - name: `${namePrefix}aggCondition`, - }); - const groupBy = useWatch({ control, name: 'groupBy' }); - - const metricTableSource = - tableSource?.kind === SourceKind.Metric ? tableSource : undefined; - - const { data: attributeSuggestions, isLoading: isLoadingAttributes } = - useFetchMetricResourceAttrs({ - databaseName, - metricType, - metricName, - tableSource: metricTableSource, - isSql: aggConditionLanguage === 'sql', - }); - - const attributeKeys = useMemo( - () => parseAttributeKeysFromSuggestions(attributeSuggestions ?? []), - [attributeSuggestions], - ); - - const { data: metricMetadata } = useFetchMetricMetadata({ - databaseName, - metricType, - metricName, - tableSource: metricTableSource, - }); - - const handleAddToWhere = useCallback( - (clause: string) => { - const currentValue = aggCondition || ''; - - const newValue = currentValue ? `${currentValue} AND ${clause}` : clause; - setValue(`${namePrefix}aggCondition`, newValue); - onSubmit(); - }, - [aggCondition, namePrefix, setValue, onSubmit], - ); - - const handleAddToGroupBy = useCallback( - (clause: string) => { - const currentValue = groupBy || ''; - const newValue = currentValue ? `${currentValue}, ${clause}` : clause; - setValue('groupBy', newValue); - onSubmit(); - }, - [groupBy, setValue, onSubmit], - ); - - const showWhere = aggFn !== 'none'; - - const tableConnection = useMemo( - () => ({ - databaseName, - tableName: tableName ?? '', - connectionId: connectionId ?? '', - metricName: - tableSource?.kind === SourceKind.Metric ? metricName : undefined, - }), - [databaseName, tableName, connectionId, metricName, tableSource], - ); - - return ( - <> - - Alias - -
- onSubmit()} - size="xs" - data-testid="series-alias-input" - /> -
- {(index ?? -1) > 0 && ( - - )} - {(index ?? -1) < length - 1 && ( - - )} - {((index ?? -1) > 0 || length > 1) && ( - - )} - - } - labelPosition="right" - mb={8} - mt="sm" - /> - -
- -
- {tableSource?.kind === SourceKind.Metric && metricType && ( -
- { - setValue(`${namePrefix}metricName`, value); - setValue(`${namePrefix}valueExpression`, 'Value'); - }} - setMetricType={value => - setValue(`${namePrefix}metricType`, value) - } - metricSource={tableSource} - data-testid="metric-name-selector" - error={errors?.metricName?.message} - onFocus={() => clearErrors(`${namePrefix}metricName`)} - /> - {metricType === 'gauge' && ( - - - - )} -
- )} - {tableSource?.kind !== SourceKind.Metric && aggFn !== 'count' && ( -
- -
- )} - {(showWhere || showGroupBy || showHaving) && ( -
- {showWhere && ( - <> - Where -
- -
- - )} - {showGroupBy && ( - <> - - Group By - -
- -
- {showHaving && ( - <> - - Having - -
- -
- - )} - - )} -
- )} -
- {tableSource?.kind === SourceKind.Metric && metricName && metricType && ( - - )} - - ); -} -const ChartSeriesEditor = ChartSeriesEditorComponent; - -const ErrorNotificationMessage = ({ - errors, -}: { - errors: { path: Path; message: string }[]; -}) => { - return ( - } - > - {errors.map(({ message }, index) => ( - {message} - ))} - - ); -}; - -const zSavedChartConfig = z - .object({ - // TODO: Chart - alert: ChartAlertBaseSchema.superRefine( - validateAlertScheduleOffsetMinutes, - ).optional(), - }) - .passthrough(); - -export default function EditTimeChartForm({ - dashboardId, - chartConfig, - displayedTimeInputValue, - dateRange, - isSaving, - onTimeRangeSearch, - setChartConfig, - setDisplayedTimeInputValue, - onSave, - onTimeRangeSelect, - onClose, - onDirtyChange, - 'data-testid': dataTestId, - submitRef, - isDashboardForm = false, - autoRun = false, -}: { - dashboardId?: string; - chartConfig: SavedChartConfig; - displayedTimeInputValue?: string; - dateRange: [Date, Date]; - isSaving?: boolean; - onTimeRangeSearch?: (value: string) => void; - setChartConfig?: (chartConfig: SavedChartConfig) => void; - setDisplayedTimeInputValue?: (value: string) => void; - onSave?: (chart: SavedChartConfig) => void; - onClose?: () => void; - onDirtyChange?: (isDirty: boolean) => void; - onTimeRangeSelect?: (start: Date, end: Date) => void; - 'data-testid'?: string; - submitRef?: React.MutableRefObject<(() => void) | undefined>; - isDashboardForm?: boolean; - autoRun?: boolean; -}) { - const formValue: ChartEditorFormState = useMemo( - () => convertSavedChartConfigToFormState(chartConfig), - [chartConfig], - ); - - const { - control, - setValue, - handleSubmit, - register, - setError, - clearErrors, - formState: { errors, isDirty, dirtyFields }, - } = useForm({ - defaultValues: formValue, - values: formValue, - resolver: zodResolver(zSavedChartConfig), - }); - - const { - fields, - append, - remove: removeSeries, - swap: swapSeries, - } = useFieldArray({ - control, - name: 'series', - }); - - useEffect(() => { - onDirtyChange?.(isDirty); - }, [isDirty, onDirtyChange]); - - const [isSampleEventsOpen, setIsSampleEventsOpen] = useState(false); - - const select = useWatch({ control, name: 'select' }); - const sourceId = useWatch({ control, name: 'source' }); - const alert = useWatch({ control, name: 'alert' }); - const seriesReturnType = useWatch({ control, name: 'seriesReturnType' }); - const groupBy = useWatch({ control, name: 'groupBy' }); - const displayType = - useWatch({ control, name: 'displayType' }) ?? DisplayType.Line; - const markdown = useWatch({ control, name: 'markdown' }); - const alertChannelType = useWatch({ control, name: 'alert.channel.type' }); - const alertScheduleOffsetMinutes = useWatch({ - control, - name: 'alert.scheduleOffsetMinutes', - }); - const granularity = useWatch({ control, name: 'granularity' }); - const maxAlertScheduleOffsetMinutes = alert?.interval - ? Math.max(intervalToMinutes(alert.interval) - 1, 0) - : 0; - const alertIntervalLabel = alert?.interval - ? TILE_ALERT_INTERVAL_OPTIONS[alert.interval] - : undefined; - const configType = useWatch({ control, name: 'configType' }); - - const chartConfigAlert = !isRawSqlSavedChartConfig(chartConfig) - ? chartConfig.alert - : undefined; - - const isRawSqlInput = - configType === 'sql' && isRawSqlDisplayType(displayType); - - const { data: tableSource } = useSource({ id: sourceId }); - const databaseName = tableSource?.from.databaseName; - const tableName = tableSource?.from.tableName; - - const activeTab = useMemo(() => { - switch (displayType) { - case DisplayType.Search: - return 'search'; - case DisplayType.Markdown: - return 'markdown'; - case DisplayType.Table: - return 'table'; - case DisplayType.Pie: - return 'pie'; - case DisplayType.Number: - return 'number'; - default: - return 'time'; - } - }, [displayType]); - - useEffect(() => { - if ( - displayType !== DisplayType.Line && - displayType !== DisplayType.Number - ) { - setValue('alert', undefined); - } - }, [displayType, setValue]); - - const showGeneratedSql = ['table', 'time', 'number', 'pie'].includes( - activeTab, - ); - - const showSampleEvents = - tableSource?.kind !== SourceKind.Metric && !isRawSqlInput; - - const [ - alignDateRangeToGranularity, - fillNulls, - compareToPreviousPeriod, - numberFormat, - ] = useWatch({ - control, - name: [ - 'alignDateRangeToGranularity', - 'fillNulls', - 'compareToPreviousPeriod', - 'numberFormat', - ], - }); - - const displaySettings: ChartConfigDisplaySettings = useMemo( - () => ({ - alignDateRangeToGranularity, - fillNulls, - compareToPreviousPeriod, - numberFormat, - }), - [ - alignDateRangeToGranularity, - fillNulls, - compareToPreviousPeriod, - numberFormat, - ], - ); - - const [ - displaySettingsOpened, - { open: openDisplaySettings, close: closeDisplaySettings }, - ] = useDisclosure(false); - - // Only update this on submit, otherwise we'll have issues - // with using the source value from the last submit - // (ex. ignoring local custom source updates) - const [queriedConfig, setQueriedConfig] = useState< - ChartConfigWithDateRange | undefined - >(undefined); - const [queriedSource, setQueriedSource] = useState( - undefined, - ); - - const setQueriedConfigAndSource = useCallback( - (config: ChartConfigWithDateRange, source: TSource | undefined) => { - setQueriedConfig(config); - setQueriedSource(source); - }, - [], - ); - - const dbTimeChartConfig = useMemo(() => { - if (!queriedConfig) { - return undefined; - } - - return { - ...queriedConfig, - granularity: alert - ? intervalToGranularity(alert.interval) - : queriedConfig.granularity, - dateRange: alert - ? extendDateRangeToInterval(queriedConfig.dateRange, alert.interval) - : queriedConfig.dateRange, - }; - }, [queriedConfig, alert]); - - const [saveToDashboardModalOpen, setSaveToDashboardModalOpen] = - useState(false); - - const onSubmit = useCallback( - (suppressErrorNotification: boolean = false) => { - handleSubmit(form => { - const isRawSqlChart = - form.configType === 'sql' && isRawSqlDisplayType(form.displayType); - - const errors = validateChartForm(form, tableSource, setError); - if (errors.length > 0) { - if (!suppressErrorNotification) { - notifications.show({ - id: 'chart-error', - title: 'Invalid Chart', - message: , - color: 'red', - }); - } - return; - } - - const savedConfig = convertFormStateToSavedChartConfig( - form, - tableSource, - ); - const queriedConfig = convertFormStateToChartConfig( - form, - dateRange, - tableSource, - ); - - if (savedConfig && queriedConfig) { - const normalizedSavedConfig = isRawSqlSavedChartConfig(savedConfig) - ? savedConfig - : { - ...savedConfig, - alert: normalizeNoOpAlertScheduleFields( - savedConfig.alert, - chartConfigAlert, - { - preserveExplicitScheduleOffsetMinutes: - dirtyFields.alert?.scheduleOffsetMinutes === true, - preserveExplicitScheduleStartAt: - dirtyFields.alert?.scheduleStartAt === true, - }, - ), - }; - setChartConfig?.(normalizedSavedConfig); - setQueriedConfigAndSource( - queriedConfig, - isRawSqlChart ? undefined : tableSource, - ); - } - })(); - }, - [ - chartConfigAlert, - dirtyFields.alert?.scheduleOffsetMinutes, - dirtyFields.alert?.scheduleStartAt, - handleSubmit, - setChartConfig, - setQueriedConfigAndSource, - tableSource, - dateRange, - setError, - ], - ); - - const onTableSortingChange = useCallback( - (sortState: SortingState | null) => { - setValue('orderBy', sortingStateToOrderByString(sortState) ?? ''); - onSubmit(); - }, - [setValue, onSubmit], - ); - - const tableSortState = useMemo( - () => - queriedConfig != null && - isBuilderChartConfig(queriedConfig) && - queriedConfig.orderBy && - typeof queriedConfig.orderBy === 'string' - ? orderByStringToSortingState(queriedConfig.orderBy) - : undefined, - [queriedConfig], - ); - - useEffect(() => { - if (submitRef) { - submitRef.current = onSubmit; - } - }, [onSubmit, submitRef]); - - const autoRunFired = useRef(false); - useEffect(() => { - if (autoRun && !autoRunFired.current && tableSource) { - autoRunFired.current = true; - onSubmit(true); - } - }, [autoRun, tableSource, onSubmit]); - - const handleSave = useCallback( - (form: ChartEditorFormState) => { - const errors = validateChartForm(form, tableSource, setError); - if (errors.length > 0) { - notifications.show({ - id: 'chart-error', - title: 'Invalid Chart', - message: , - color: 'red', - }); - return; - } - - const savedChartConfig = convertFormStateToSavedChartConfig( - form, - tableSource, - ); - - if (savedChartConfig) { - const normalizedSavedConfig = isRawSqlSavedChartConfig(savedChartConfig) - ? savedChartConfig - : { - ...savedChartConfig, - alert: normalizeNoOpAlertScheduleFields( - savedChartConfig.alert, - chartConfigAlert, - { - preserveExplicitScheduleOffsetMinutes: - dirtyFields.alert?.scheduleOffsetMinutes === true, - preserveExplicitScheduleStartAt: - dirtyFields.alert?.scheduleStartAt === true, - }, - ), - }; - - onSave?.(normalizedSavedConfig); - } - }, - [ - onSave, - tableSource, - setError, - chartConfigAlert, - dirtyFields.alert?.scheduleOffsetMinutes, - dirtyFields.alert?.scheduleStartAt, - ], - ); - - // Track previous values for detecting changes - const prevGranularityRef = useRef(granularity); - const prevDisplayTypeRef = useRef(displayType); - const prevConfigTypeRef = useRef(configType); - - useEffect(() => { - // Emulate the granularity picker auto-searching similar to dashboards - if (granularity !== prevGranularityRef.current) { - prevGranularityRef.current = granularity; - onSubmit(); - } - }, [granularity, onSubmit]); - - useEffect(() => { - const displayTypeChanged = displayType !== prevDisplayTypeRef.current; - const configTypeChanged = configType !== prevConfigTypeRef.current; - - if (displayTypeChanged || configTypeChanged) { - prevDisplayTypeRef.current = displayType; - prevConfigTypeRef.current = configType; - - if (displayType === DisplayType.Search && typeof select !== 'string') { - setValue('select', ''); - setValue('series', []); - } - - if (displayType !== DisplayType.Search && !Array.isArray(select)) { - const defaultSeries: SavedChartConfigWithSelectArray['select'] = [ - { - aggFn: 'count', - aggCondition: '', - aggConditionLanguage: getStoredLanguage() ?? 'lucene', - valueExpression: '', - }, - ]; - setValue('where', ''); - setValue('select', defaultSeries); - setValue('series', defaultSeries); - } - - // Don't auto-submit when config type changes, to avoid clearing form state (like source) - if (displayTypeChanged) { - // true = Suppress error notification (because we're auto-submitting) - onSubmit(true); - } - } - }, [displayType, select, setValue, onSubmit, configType]); - - // Emulate the date range picker auto-searching similar to dashboards - useEffect(() => { - // eslint-disable-next-line react-hooks/set-state-in-effect - setQueriedConfig((config: ChartConfigWithDateRange | undefined) => { - if (config == null) { - return config; - } - - return { - ...config, - dateRange, - }; - }); - }, [dateRange]); - - const queryReady = isQueryReady(queriedConfig); - - // The chart config to use when showing the user the generated SQL - // and explaining whether a MV can be used. - const chartConfigForExplanations: ChartConfigWithOptTimestamp | undefined = - useMemo(() => { - if (queriedConfig && isRawSqlChartConfig(queriedConfig)) - return { ...queriedConfig, dateRange }; - - if (chartConfig && isRawSqlSavedChartConfig(chartConfig)) - return { ...chartConfig, dateRange }; - - const userHasSubmittedQuery = !!queriedConfig; - const queriedSourceMatchesSelectedSource = - queriedSource?.id === tableSource?.id; - const urlParamsSourceMatchesSelectedSource = - chartConfig.source === tableSource?.id; - - const effectiveQueriedConfig = - activeTab === 'time' ? dbTimeChartConfig : queriedConfig; - - const config = - userHasSubmittedQuery && queriedSourceMatchesSelectedSource - ? effectiveQueriedConfig - : chartConfig && urlParamsSourceMatchesSelectedSource && tableSource - ? { - ...chartConfig, - dateRange, - timestampValueExpression: tableSource.timestampValueExpression, - from: tableSource.from, - connection: tableSource.connection, - } - : undefined; - - if (!config || isRawSqlChartConfig(config)) { - return undefined; - } - - // Apply the transformations that child components will apply, - // so that the MV optimization explanation and generated SQL preview - // are accurate. - if (activeTab === 'time') { - return convertToTimeChartConfig(config); - } else if (activeTab === 'number') { - return convertToNumberChartConfig(config); - } else if (activeTab === 'table') { - return convertToTableChartConfig(config); - } else if (activeTab === 'pie') { - return convertToPieChartConfig(config); - } - - return config; - }, [ - queriedConfig, - queriedSource?.id, - tableSource, - chartConfig, - dateRange, - activeTab, - dbTimeChartConfig, - ]); - - const previousDateRange = getPreviousDateRange(dateRange); - - const sampleEventsConfig = useMemo( - () => - tableSource != null && - queriedConfig != null && - isBuilderChartConfig(queriedConfig) && - queryReady - ? { - ...queriedConfig, - orderBy: [ - { - ordering: 'DESC' as const, - valueExpression: getFirstTimestampValueExpression( - tableSource.timestampValueExpression, - ), - }, - ], - dateRange, - timestampValueExpression: tableSource.timestampValueExpression, - connection: tableSource.connection, - from: tableSource.from, - limit: { limit: 200 }, - select: - ((tableSource?.kind === SourceKind.Log || - tableSource?.kind === SourceKind.Trace) && - tableSource.defaultTableSelectExpression) || - '', - filters: seriesToFilters(queriedConfig.select), - filtersLogicalOperator: 'OR' as const, - groupBy: undefined, - granularity: undefined, - having: undefined, - } - : null, - [queriedConfig, tableSource, dateRange, queryReady], - ); - - // Need to force a rerender on change as the modal will not be mounted when initially rendered - const [parentRef, setParentRef] = useState(null); - - const handleUpdateDisplaySettings = useCallback( - ({ - numberFormat, - alignDateRangeToGranularity, - fillNulls, - compareToPreviousPeriod, - }: ChartConfigDisplaySettings) => { - setValue('numberFormat', numberFormat); - setValue('alignDateRangeToGranularity', alignDateRangeToGranularity); - setValue('fillNulls', fillNulls); - setValue('compareToPreviousPeriod', compareToPreviousPeriod); - onSubmit(); - }, - [setValue, onSubmit], - ); - - const tableConnection = useMemo( - () => tcFromSource(tableSource), - [tableSource], - ); - - return ( -
- - ( - - - } - > - Line/Bar - - } - > - Table - - } - > - Number - - } - > - Pie - - } - > - Search - - } - > - Markdown - - - - )} - /> - - - Chart Name - - - {isRawSqlDisplayType(displayType) && ( - ( - - )} - /> - )} - - - {activeTab === 'markdown' ? ( -
-