MathExpressionQueryField.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api';
  2. import React, { useCallback, useRef } from 'react';
  3. import { CodeEditor, Monaco } from '@grafana/ui';
  4. import { CloudWatchDatasource } from '../datasource';
  5. import language from '../metric-math/definition';
  6. import { TRIGGER_SUGGEST } from '../monarch/commands';
  7. import { registerLanguage } from '../monarch/register';
  8. export interface Props {
  9. onChange: (query: string) => void;
  10. onRunQuery: () => void;
  11. expression: string;
  12. datasource: CloudWatchDatasource;
  13. }
  14. export function MathExpressionQueryField({
  15. expression: query,
  16. onChange,
  17. onRunQuery,
  18. datasource,
  19. }: React.PropsWithChildren<Props>) {
  20. const containerRef = useRef<HTMLDivElement>(null);
  21. const onEditorMount = useCallback(
  22. (editor: monacoType.editor.IStandaloneCodeEditor, monaco: Monaco) => {
  23. editor.onDidFocusEditorText(() => editor.trigger(TRIGGER_SUGGEST.id, TRIGGER_SUGGEST.id, {}));
  24. editor.addCommand(monaco.KeyMod.Shift | monaco.KeyCode.Enter, () => {
  25. const text = editor.getValue();
  26. onChange(text);
  27. onRunQuery();
  28. });
  29. // auto resizes the editor to be the height of the content it holds
  30. // this code comes from the Prometheus query editor.
  31. // We may wish to consider abstracting it into the grafana/ui repo in the future
  32. const updateElementHeight = () => {
  33. const containerDiv = containerRef.current;
  34. if (containerDiv !== null && editor.getContentHeight() < 200) {
  35. const pixelHeight = Math.max(32, editor.getContentHeight());
  36. containerDiv.style.height = `${pixelHeight}px`;
  37. containerDiv.style.width = '100%';
  38. const pixelWidth = containerDiv.clientWidth;
  39. editor.layout({ width: pixelWidth, height: pixelHeight });
  40. }
  41. };
  42. editor.onDidContentSizeChange(updateElementHeight);
  43. updateElementHeight();
  44. },
  45. [onChange, onRunQuery]
  46. );
  47. return (
  48. <div ref={containerRef}>
  49. <CodeEditor
  50. monacoOptions={{
  51. // without this setting, the auto-resize functionality causes an infinite loop, don't remove it!
  52. scrollBeyondLastLine: false,
  53. // These additional options are style focused and are a subset of those in the query editor in Prometheus
  54. fontSize: 14,
  55. lineNumbers: 'off',
  56. renderLineHighlight: 'none',
  57. scrollbar: {
  58. vertical: 'hidden',
  59. horizontal: 'hidden',
  60. },
  61. suggestFontSize: 12,
  62. wordWrap: 'on',
  63. padding: {
  64. top: 6,
  65. },
  66. }}
  67. language={language.id}
  68. value={query}
  69. onBlur={(value) => {
  70. if (value !== query) {
  71. onChange(value);
  72. onRunQuery();
  73. }
  74. }}
  75. onBeforeEditorMount={(monaco: Monaco) =>
  76. registerLanguage(monaco, language, datasource.metricMathCompletionItemProvider)
  77. }
  78. onEditorDidMount={onEditorMount}
  79. />
  80. </div>
  81. );
  82. }