grafana/public/app/features/plugins/sql/components/QueryEditor.tsx

130 lines
3.5 KiB
TypeScript

import React, { useCallback, useEffect, useState } from 'react';
import { useAsync } from 'react-use';
import { QueryEditorProps } from '@grafana/data';
import { EditorMode, Space } from '@grafana/experimental';
import { SqlDatasource } from '../datasource/SqlDatasource';
import { applyQueryDefaults } from '../defaults';
import { SQLQuery, QueryRowFilter, SQLOptions } from '../types';
import { haveColumns } from '../utils/sql.utils';
import { QueryHeader } from './QueryHeader';
import { RawEditor } from './query-editor-raw/RawEditor';
import { VisualEditor } from './visual-query-builder/VisualEditor';
type Props<TSQLQuery extends SQLQuery, TSQLOptions extends SQLOptions> = QueryEditorProps<
SqlDatasource<TSQLQuery, TSQLOptions>,
TSQLQuery,
TSQLOptions
>;
export function SqlQueryEditor<TSQLQuery extends SQLQuery, TSQLOptions extends SQLOptions>({
datasource,
query,
onChange,
onRunQuery,
range,
}: Props<TSQLQuery, TSQLOptions>) {
const [isQueryRunnable, setIsQueryRunnable] = useState(true);
const db = datasource.getDB();
const { loading, error } = useAsync(async () => {
return () => {
if (datasource.getDB(datasource.id).init !== undefined) {
datasource.getDB(datasource.id).init!();
}
};
}, [datasource]);
const queryWithDefaults = applyQueryDefaults(query);
const [queryRowFilter, setQueryRowFilter] = useState<QueryRowFilter>({
filter: !!queryWithDefaults.sql?.whereString,
group: !!queryWithDefaults.sql?.groupBy?.[0]?.property.name,
order: !!queryWithDefaults.sql?.orderBy?.property.name,
preview: true,
});
const [queryToValidate, setQueryToValidate] = useState(queryWithDefaults);
useEffect(() => {
return () => {
if (datasource.getDB(datasource.id).dispose !== undefined) {
datasource.getDB(datasource.id).dispose!();
}
};
}, [datasource]);
const processQuery = useCallback(
(q: SQLQuery) => {
if (isQueryValid(q) && onRunQuery) {
onRunQuery();
}
},
[onRunQuery]
);
const onQueryChange = (q: TSQLQuery, process = true) => {
setQueryToValidate(q);
onChange(q);
if (haveColumns(q.sql?.columns) && q.sql?.columns.some((c) => c.name) && !queryRowFilter.group) {
setQueryRowFilter({ ...queryRowFilter, group: true });
}
if (process) {
processQuery(q);
}
};
const onQueryHeaderChange = (q: TSQLQuery) => {
setQueryToValidate(q);
onChange(q);
};
if (loading || error) {
return null;
}
return (
<>
<QueryHeader<TSQLQuery>
db={db}
onChange={onQueryHeaderChange}
onRunQuery={onRunQuery}
onQueryRowChange={setQueryRowFilter}
queryRowFilter={queryRowFilter}
query={queryWithDefaults}
isQueryRunnable={isQueryRunnable}
/>
<Space v={0.5} />
{queryWithDefaults.editorMode !== EditorMode.Code && (
<VisualEditor
db={db}
query={queryWithDefaults}
onChange={(q: TSQLQuery) => onQueryChange(q, false)}
queryRowFilter={queryRowFilter}
onValidate={setIsQueryRunnable}
range={range}
/>
)}
{queryWithDefaults.editorMode === EditorMode.Code && (
<RawEditor
db={db}
query={queryWithDefaults}
queryToValidate={queryToValidate}
onChange={onQueryChange}
onRunQuery={onRunQuery}
onValidate={setIsQueryRunnable}
range={range}
/>
)}
</>
);
}
const isQueryValid = (q: SQLQuery) => {
return Boolean(q.rawSql);
};