hyperdx/packages/app/src/hooks/useChartConfig.tsx
Spencer Torres 25f77aa7d9
Team query timeout setting (#1072)
Closes HDX-2023

# Behavior
Adds `queryTimeout` to the team settings page. If the setting is greater than `0`, a `max_execution_time` setting is added to all queries executed by the `ClickhouseClient`. The timeout is in seconds, with `60` seconds being the default. `0` would be unlimited.

# Images

Settings page:
<img width="598" height="501" alt="settings page" src="https://github.com/user-attachments/assets/5483d5a7-c1c2-4bb5-a0d9-e23fa06cc5ec" />

Network log:
<img width="542" height="100" alt="network log" src="https://github.com/user-attachments/assets/08ed2ea1-4038-4c67-b493-ef591a226b59" />
2025-08-30 02:42:05 +00:00

100 lines
2.9 KiB
TypeScript

import { useEffect } from 'react';
import objectHash from 'object-hash';
import {
ChSql,
chSqlToAliasMap,
ClickHouseQueryError,
inferNumericColumn,
inferTimestampColumn,
parameterizedQueryToSql,
ResponseJSON,
} from '@hyperdx/common-utils/dist/clickhouse';
import { renderChartConfig } from '@hyperdx/common-utils/dist/renderChartConfig';
import { format } from '@hyperdx/common-utils/dist/sqlFormatter';
import { ChartConfigWithOptDateRange } from '@hyperdx/common-utils/dist/types';
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
import { useClickhouseClient } from '@/clickhouse';
import { IS_MTVIEWS_ENABLED } from '@/config';
import { buildMTViewSelectQuery } from '@/hdxMTViews';
import { getMetadata } from '@/metadata';
interface AdditionalUseQueriedChartConfigOptions {
onError?: (error: Error | ClickHouseQueryError) => void;
}
// used for charting
export function useQueriedChartConfig(
config: ChartConfigWithOptDateRange,
options?: Partial<UseQueryOptions<ResponseJSON<any>>> &
AdditionalUseQueriedChartConfigOptions,
) {
const clickhouseClient = useClickhouseClient();
const query = useQuery<ResponseJSON<any>, ClickHouseQueryError | Error>({
queryKey: [config],
queryFn: async ({ signal }) => {
let query = null;
if (IS_MTVIEWS_ENABLED) {
const { dataTableDDL, mtViewDDL, renderMTViewConfig } =
await buildMTViewSelectQuery(config);
// TODO: show the DDLs in the UI so users can run commands manually
// eslint-disable-next-line no-console
console.log('dataTableDDL:', dataTableDDL);
// eslint-disable-next-line no-console
console.log('mtViewDDL:', mtViewDDL);
query = await renderMTViewConfig();
}
return clickhouseClient.queryChartConfig({
config,
metadata: getMetadata(),
opts: {
abort_signal: signal,
},
});
},
retry: 1,
refetchOnWindowFocus: false,
...options,
});
if (query.isError && options?.onError) {
options.onError(query.error);
}
return query;
}
export function useRenderedSqlChartConfig(
config: ChartConfigWithOptDateRange,
options?: UseQueryOptions<string>,
) {
return useQuery<string>({
queryKey: ['renderedSql', config],
queryFn: async () => {
const query = await renderChartConfig(config, getMetadata());
return format(parameterizedQueryToSql(query));
},
...options,
});
}
export function useAliasMapFromChartConfig(
config: ChartConfigWithOptDateRange | undefined,
options?: UseQueryOptions<Record<string, string>>,
) {
return useQuery<Record<string, string>>({
queryKey: ['aliasMap', config],
queryFn: async () => {
if (config == null) {
return {};
}
const query = await renderChartConfig(config, getMetadata());
const aliasMap = chSqlToAliasMap(query);
return aliasMap;
},
enabled: config != null,
...options,
});
}