2026-03-12 21:23:56 +00:00
|
|
|
import { useEffect, useMemo } from 'react';
|
2026-03-06 16:05:34 +00:00
|
|
|
import { Control, UseFormSetValue, useWatch } from 'react-hook-form';
|
2026-03-12 21:23:56 +00:00
|
|
|
import {
|
|
|
|
|
TableConnection,
|
|
|
|
|
tcFromSource,
|
|
|
|
|
} from '@hyperdx/common-utils/dist/core/metadata';
|
2026-03-17 17:23:14 +00:00
|
|
|
import { MACRO_SUGGESTIONS } from '@hyperdx/common-utils/dist/macros';
|
|
|
|
|
import { QUERY_PARAMS_BY_DISPLAY_TYPE } from '@hyperdx/common-utils/dist/rawSqlParams';
|
2026-03-12 21:23:56 +00:00
|
|
|
import { DisplayType, SourceKind } from '@hyperdx/common-utils/dist/types';
|
2026-03-10 18:05:47 +00:00
|
|
|
import { Box, Button, Group, Stack, Text } from '@mantine/core';
|
2026-03-05 20:30:58 +00:00
|
|
|
|
2026-03-12 21:23:56 +00:00
|
|
|
import { SQLEditorControlled } from '@/components/SQLEditor/SQLEditor';
|
2026-03-17 17:23:14 +00:00
|
|
|
import { type SQLCompletion } from '@/components/SQLEditor/utils';
|
2026-03-05 20:30:58 +00:00
|
|
|
import useResizable from '@/hooks/useResizable';
|
2026-03-06 16:05:34 +00:00
|
|
|
import { useSources } from '@/source';
|
2026-03-12 21:23:56 +00:00
|
|
|
import { getAllMetricTables } from '@/utils';
|
2026-03-05 20:30:58 +00:00
|
|
|
|
|
|
|
|
import { ConnectionSelectControlled } from '../ConnectionSelect';
|
|
|
|
|
|
2026-03-06 16:05:34 +00:00
|
|
|
import { SQL_PLACEHOLDERS } from './constants';
|
2026-03-10 18:05:47 +00:00
|
|
|
import { RawSqlChartInstructions } from './RawSqlChartInstructions';
|
2026-03-05 20:30:58 +00:00
|
|
|
import { ChartEditorFormState } from './types';
|
|
|
|
|
|
|
|
|
|
import resizeStyles from '@/../styles/ResizablePanel.module.scss';
|
|
|
|
|
|
|
|
|
|
export default function RawSqlChartEditor({
|
|
|
|
|
control,
|
2026-03-06 16:05:34 +00:00
|
|
|
setValue,
|
2026-03-05 20:30:58 +00:00
|
|
|
onOpenDisplaySettings,
|
|
|
|
|
}: {
|
|
|
|
|
control: Control<ChartEditorFormState>;
|
2026-03-06 16:05:34 +00:00
|
|
|
setValue: UseFormSetValue<ChartEditorFormState>;
|
2026-03-05 20:30:58 +00:00
|
|
|
onOpenDisplaySettings: () => void;
|
|
|
|
|
}) {
|
|
|
|
|
const { size, startResize } = useResizable(20, 'bottom');
|
|
|
|
|
|
2026-03-06 16:05:34 +00:00
|
|
|
const { data: sources } = useSources();
|
|
|
|
|
|
|
|
|
|
const displayType = useWatch({ control, name: 'displayType' });
|
|
|
|
|
const connection = useWatch({ control, name: 'connection' });
|
|
|
|
|
const source = useWatch({ control, name: 'source' });
|
|
|
|
|
|
|
|
|
|
// Set a default connection
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (sources && !connection) {
|
|
|
|
|
const defaultConnection =
|
|
|
|
|
sources.find(s => s.id === source)?.connection ??
|
|
|
|
|
sources[0]?.connection;
|
|
|
|
|
if (defaultConnection && defaultConnection !== connection) {
|
|
|
|
|
setValue('connection', defaultConnection);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}, [connection, setValue, source, sources]);
|
|
|
|
|
|
|
|
|
|
const placeholderSQl = SQL_PLACEHOLDERS[displayType ?? DisplayType.Table];
|
|
|
|
|
|
2026-03-17 17:23:14 +00:00
|
|
|
const additionalCompletions: SQLCompletion[] = useMemo(() => {
|
|
|
|
|
const effectiveDisplayType = displayType ?? DisplayType.Table;
|
|
|
|
|
const params = QUERY_PARAMS_BY_DISPLAY_TYPE[effectiveDisplayType];
|
|
|
|
|
|
|
|
|
|
const paramCompletions: SQLCompletion[] = params.map(({ name, type }) => ({
|
|
|
|
|
label: `{${name}:${type}}`,
|
|
|
|
|
apply: `{${name}:${type}`, // Omit the closing } because the editor will have added it when the user types {
|
|
|
|
|
detail: 'param',
|
|
|
|
|
type: 'variable',
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
const macroCompletions: SQLCompletion[] = MACRO_SUGGESTIONS.map(
|
|
|
|
|
({ name, argCount }) => ({
|
|
|
|
|
label: `$__${name}`,
|
|
|
|
|
apply: argCount > 0 ? `$__${name}(` : `$__${name}`,
|
|
|
|
|
detail: 'macro',
|
|
|
|
|
type: 'function',
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return [...paramCompletions, ...macroCompletions];
|
|
|
|
|
}, [displayType]);
|
|
|
|
|
|
2026-03-12 21:23:56 +00:00
|
|
|
const tableConnections: TableConnection[] = useMemo(() => {
|
|
|
|
|
if (!sources) return [];
|
|
|
|
|
return sources
|
|
|
|
|
.filter(s => s.connection === connection)
|
|
|
|
|
.flatMap(source => {
|
|
|
|
|
const tables: TableConnection[] = getAllMetricTables(source);
|
|
|
|
|
|
|
|
|
|
if (source.kind !== SourceKind.Metric) {
|
|
|
|
|
tables.push(tcFromSource(source));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (source.materializedViews) {
|
|
|
|
|
tables.push(
|
|
|
|
|
...source.materializedViews.map(mv => ({
|
|
|
|
|
databaseName: mv.databaseName,
|
|
|
|
|
tableName: mv.tableName,
|
|
|
|
|
connectionId: source.connection,
|
|
|
|
|
})),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tables;
|
|
|
|
|
});
|
|
|
|
|
}, [sources, connection]);
|
|
|
|
|
|
2026-03-05 20:30:58 +00:00
|
|
|
return (
|
|
|
|
|
<Stack>
|
2026-03-06 16:05:34 +00:00
|
|
|
<Group align="center">
|
2026-03-05 20:30:58 +00:00
|
|
|
<Text pe="md" size="sm">
|
|
|
|
|
Connection
|
|
|
|
|
</Text>
|
|
|
|
|
<ConnectionSelectControlled
|
|
|
|
|
control={control}
|
|
|
|
|
name="connection"
|
|
|
|
|
size="xs"
|
|
|
|
|
/>
|
|
|
|
|
</Group>
|
2026-03-10 18:05:47 +00:00
|
|
|
<RawSqlChartInstructions displayType={displayType ?? DisplayType.Table} />
|
2026-03-05 20:30:58 +00:00
|
|
|
<Box style={{ position: 'relative' }}>
|
|
|
|
|
<SQLEditorControlled
|
|
|
|
|
control={control}
|
|
|
|
|
name="sqlTemplate"
|
|
|
|
|
height={`${size}vh`}
|
|
|
|
|
enableLineWrapping
|
2026-03-06 16:05:34 +00:00
|
|
|
placeholder={placeholderSQl}
|
2026-03-12 21:23:56 +00:00
|
|
|
tableConnections={tableConnections}
|
2026-03-17 17:23:14 +00:00
|
|
|
additionalCompletions={additionalCompletions}
|
2026-03-05 20:30:58 +00:00
|
|
|
/>
|
|
|
|
|
<div className={resizeStyles.resizeYHandle} onMouseDown={startResize} />
|
|
|
|
|
</Box>
|
|
|
|
|
<Group justify="flex-end">
|
|
|
|
|
<Button
|
|
|
|
|
onClick={onOpenDisplaySettings}
|
|
|
|
|
size="compact-sm"
|
|
|
|
|
variant="secondary"
|
|
|
|
|
>
|
|
|
|
|
Display Settings
|
|
|
|
|
</Button>
|
|
|
|
|
</Group>
|
|
|
|
|
</Stack>
|
|
|
|
|
);
|
|
|
|
|
}
|