DynamicLabelsField.tsx 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import { css, cx } from '@emotion/css';
  2. import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api';
  3. import React, { useCallback, useRef } from 'react';
  4. import { CodeEditor, getInputStyles, Monaco, useTheme2 } from '@grafana/ui';
  5. import { DynamicLabelsCompletionItemProvider } from '../dynamic-labels/CompletionItemProvider';
  6. import language from '../dynamic-labels/definition';
  7. import { TRIGGER_SUGGEST } from '../monarch/commands';
  8. import { registerLanguage } from '../monarch/register';
  9. const dynamicLabelsCompletionItemProvider = new DynamicLabelsCompletionItemProvider();
  10. export interface Props {
  11. onChange: (query: string) => void;
  12. onRunQuery: () => void;
  13. label: string;
  14. width: number;
  15. }
  16. export function DynamicLabelsField({ label, width, onChange, onRunQuery }: Props) {
  17. const theme = useTheme2();
  18. const styles = getInputStyles({ theme, width });
  19. const containerRef = useRef<HTMLDivElement>(null);
  20. const onEditorMount = useCallback(
  21. (editor: monacoType.editor.IStandaloneCodeEditor, monaco: Monaco) => {
  22. editor.onDidFocusEditorText(() => editor.trigger(TRIGGER_SUGGEST.id, TRIGGER_SUGGEST.id, {}));
  23. editor.addCommand(monaco.KeyMod.Shift | monaco.KeyCode.Enter, () => {
  24. const text = editor.getValue();
  25. onChange(text);
  26. onRunQuery();
  27. });
  28. const containerDiv = containerRef.current;
  29. containerDiv !== null && editor.layout({ width: containerDiv.clientWidth, height: containerDiv.clientHeight });
  30. },
  31. [onChange, onRunQuery]
  32. );
  33. return (
  34. <div ref={containerRef} className={cx(styles.wrapper)}>
  35. <CodeEditor
  36. containerStyles={css`
  37. border: 1px solid ${theme.colors.action.disabledBackground};
  38. &:hover {
  39. border-color: ${theme.components.input.borderColor};
  40. }
  41. `}
  42. monacoOptions={{
  43. // without this setting, the auto-resize functionality causes an infinite loop, don't remove it!
  44. scrollBeyondLastLine: false,
  45. // These additional options are style focused and are a subset of those in the query editor in Prometheus
  46. fontSize: 14,
  47. lineNumbers: 'off',
  48. renderLineHighlight: 'none',
  49. overviewRulerLanes: 0,
  50. scrollbar: {
  51. vertical: 'hidden',
  52. horizontal: 'hidden',
  53. },
  54. suggestFontSize: 12,
  55. padding: {
  56. top: 6,
  57. },
  58. }}
  59. language={language.id}
  60. value={label}
  61. onBlur={(value) => {
  62. if (value !== label) {
  63. onChange(value);
  64. onRunQuery();
  65. }
  66. }}
  67. onBeforeEditorMount={(monaco: Monaco) =>
  68. registerLanguage(monaco, language, dynamicLabelsCompletionItemProvider)
  69. }
  70. onEditorDidMount={onEditorMount}
  71. />
  72. </div>
  73. );
  74. }