SQL Expressions: Resizable code-editor (#101407)
* Resizeable SQL expressions text-area Generated by an LLM for me - we'll see. It expands quite large on first page-load * Switch to useLayoutEffect to avoid visual flashing * Get the LLM to rewrite the approach, inspired by InfluxDB The Influx DB text-area is also resizable vertically, but that one isn't a Monaco editor (we need to tell Monaco to update its own size when the outer div is resized), so this is necessarily a little more complex than Influx. But still this approach looks simpler: The Javascript here is shorter * Start at 240px, to match the current default size Question: Is there a better approach to achieve this? * Don't clip the bottom border of the Monaco editor * Fix linting errors
This commit is contained in:
@@ -1,10 +1,15 @@
|
||||
import { useMemo } from 'react';
|
||||
import { css } from '@emotion/css';
|
||||
import { useMemo, useRef, useEffect, useState } from 'react';
|
||||
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { SQLEditor } from '@grafana/plugin-ui';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { ExpressionQuery } from '../types';
|
||||
|
||||
// Account for Monaco editor's border to prevent clipping
|
||||
const EDITOR_BORDER_ADJUSTMENT = 2; // 1px border on top and bottom
|
||||
|
||||
interface Props {
|
||||
refIds: Array<SelectableValue<string>>;
|
||||
query: ExpressionQuery;
|
||||
@@ -13,8 +18,10 @@ interface Props {
|
||||
|
||||
export const SqlExpr = ({ onChange, refIds, query }: Props) => {
|
||||
const vars = useMemo(() => refIds.map((v) => v.value!), [refIds]);
|
||||
|
||||
const initialQuery = `select * from ${vars[0]} limit 1`;
|
||||
const styles = useStyles2(getStyles);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [dimensions, setDimensions] = useState({ height: 0 });
|
||||
|
||||
const onEditorChange = (expression: string) => {
|
||||
onChange({
|
||||
@@ -23,5 +30,37 @@ export const SqlExpr = ({ onChange, refIds, query }: Props) => {
|
||||
});
|
||||
};
|
||||
|
||||
return <SQLEditor query={query.expression || initialQuery} onChange={onEditorChange}></SQLEditor>;
|
||||
// Set up resize observer to handle container resizing
|
||||
useEffect(() => {
|
||||
if (!containerRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
const { height } = entries[0].contentRect;
|
||||
setDimensions({ height });
|
||||
});
|
||||
|
||||
resizeObserver.observe(containerRef.current);
|
||||
return () => resizeObserver.disconnect();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className={styles.editorContainer}>
|
||||
<SQLEditor
|
||||
query={query.expression || initialQuery}
|
||||
onChange={onEditorChange}
|
||||
height={dimensions.height - EDITOR_BORDER_ADJUSTMENT}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const getStyles = () => ({
|
||||
editorContainer: css({
|
||||
height: '240px',
|
||||
resize: 'vertical',
|
||||
overflow: 'auto',
|
||||
minHeight: '100px',
|
||||
}),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user