Loki: Add placeholder to the loki query editor (#62773)

* fix: add placeholder to loki query editor

* fix: use original placeholder

* refactor: extract set placeholder into seperate function

* fix: use correct monaco types

* revert: unwanted change from merge
This commit is contained in:
Gareth Dawson 2023-02-06 15:38:19 +00:00 committed by GitHub
parent cf272186fb
commit ac942d5e72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 46 additions and 4 deletions

View File

@ -66,6 +66,7 @@ export class LokiQueryField extends React.PureComponent<LokiQueryFieldProps, Lok
render() { render() {
const { ExtraFieldElement, query, app, datasource, history, onRunQuery } = this.props; const { ExtraFieldElement, query, app, datasource, history, onRunQuery } = this.props;
const placeholder = this.props.placeholder ?? 'Enter a Loki query (run with Shift+Enter)';
return ( return (
<> <>
@ -81,6 +82,7 @@ export class LokiQueryField extends React.PureComponent<LokiQueryFieldProps, Lok
onChange={this.onChangeQuery} onChange={this.onChangeQuery}
onRunQuery={onRunQuery} onRunQuery={onRunQuery}
initialValue={query.expr ?? ''} initialValue={query.expr ?? ''}
placeholder={placeholder}
/> />
</div> </div>
</div> </div>

View File

@ -21,6 +21,7 @@ function renderComponent({
onChange={onChange} onChange={onChange}
onRunQuery={onRunQuery} onRunQuery={onRunQuery}
runQueryOnBlur={runQueryOnBlur} runQueryOnBlur={runQueryOnBlur}
placeholder="Enter a Loki query (run with Shift+Enter)"
/> />
); );
} }

View File

@ -16,6 +16,7 @@ function renderComponent({ initialValue = '', onRunQuery = jest.fn(), onBlur = j
history={[]} history={[]}
onRunQuery={onRunQuery} onRunQuery={onRunQuery}
onBlur={onBlur} onBlur={onBlur}
placeholder="Enter a Loki query (run with Shift+Enter)"
/> />
); );
} }

View File

@ -6,7 +6,7 @@ import { v4 as uuidv4 } from 'uuid';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
import { languageConfiguration, monarchlanguage } from '@grafana/monaco-logql'; import { languageConfiguration, monarchlanguage } from '@grafana/monaco-logql';
import { useTheme2, ReactMonacoEditor, Monaco, monacoTypes } from '@grafana/ui'; import { useTheme2, ReactMonacoEditor, Monaco, monacoTypes, MonacoEditor } from '@grafana/ui';
import { Props } from './MonacoQueryFieldProps'; import { Props } from './MonacoQueryFieldProps';
import { getOverrideServices } from './getOverrideServices'; import { getOverrideServices } from './getOverrideServices';
@ -70,17 +70,24 @@ function ensureLogQL(monaco: Monaco) {
} }
} }
const getStyles = (theme: GrafanaTheme2) => { const getStyles = (theme: GrafanaTheme2, placeholder: string) => {
return { return {
container: css` container: css`
border-radius: ${theme.shape.borderRadius()}; border-radius: ${theme.shape.borderRadius()};
border: 1px solid ${theme.components.input.borderColor}; border: 1px solid ${theme.components.input.borderColor};
width: 100%; width: 100%;
`, `,
placeholder: css`
::after {
content: '${placeholder}';
font-family: ${theme.typography.fontFamilyMonospace};
opacity: 0.3;
}
`,
}; };
}; };
const MonacoQueryField = ({ history, onBlur, onRunQuery, initialValue, datasource }: Props) => { const MonacoQueryField = ({ history, onBlur, onRunQuery, initialValue, datasource, placeholder }: Props) => {
const id = uuidv4(); const id = uuidv4();
// we need only one instance of `overrideServices` during the lifetime of the react component // we need only one instance of `overrideServices` during the lifetime of the react component
const overrideServicesRef = useRef(getOverrideServices()); const overrideServicesRef = useRef(getOverrideServices());
@ -94,7 +101,7 @@ const MonacoQueryField = ({ history, onBlur, onRunQuery, initialValue, datasourc
const autocompleteCleanupCallback = useRef<(() => void) | null>(null); const autocompleteCleanupCallback = useRef<(() => void) | null>(null);
const theme = useTheme2(); const theme = useTheme2();
const styles = getStyles(theme); const styles = getStyles(theme, placeholder);
useEffect(() => { useEffect(() => {
// when we unmount, we unregister the autocomplete-function, if it was registered // when we unmount, we unregister the autocomplete-function, if it was registered
@ -103,6 +110,34 @@ const MonacoQueryField = ({ history, onBlur, onRunQuery, initialValue, datasourc
}; };
}, []); }, []);
const setPlaceholder = (monaco: Monaco, editor: MonacoEditor) => {
const placeholderDecorators = [
{
range: new monaco.Range(1, 1, 1, 1),
options: {
className: styles.placeholder,
isWholeLine: true,
},
},
];
let decorators: string[] = [];
const checkDecorators: () => void = () => {
const model = editor.getModel();
if (!model) {
return;
}
const newDecorators = model.getValueLength() === 0 ? placeholderDecorators : [];
decorators = model.deltaDecorations(decorators, newDecorators);
};
checkDecorators();
editor.onDidChangeModelContent(checkDecorators);
};
return ( return (
<div <div
aria-label={selectors.components.QueryField.container} aria-label={selectors.components.QueryField.container}
@ -206,6 +241,8 @@ const MonacoQueryField = ({ history, onBlur, onRunQuery, initialValue, datasourc
editor.trigger('', 'editor.action.triggerSuggest', {}); editor.trigger('', 'editor.action.triggerSuggest', {});
} }
}); });
setPlaceholder(monaco, editor);
}} }}
/> />
</div> </div>

View File

@ -12,5 +12,6 @@ export type Props = {
history: Array<HistoryItem<LokiQuery>>; history: Array<HistoryItem<LokiQuery>>;
onRunQuery: (value: string) => void; onRunQuery: (value: string) => void;
onBlur: (value: string) => void; onBlur: (value: string) => void;
placeholder: string;
datasource: LokiDatasource; datasource: LokiDatasource;
}; };