NestedQuery.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import { css } from '@emotion/css';
  2. import React from 'react';
  3. import { GrafanaTheme2, toOption } from '@grafana/data';
  4. import { EditorRows, FlexItem } from '@grafana/experimental';
  5. import { IconButton, Select, useStyles2 } from '@grafana/ui';
  6. import { PrometheusDatasource } from '../../datasource';
  7. import { binaryScalarDefs } from '../binaryScalarOperations';
  8. import { AutoSizeInput } from '../shared/AutoSizeInput';
  9. import { PromVisualQueryBinary } from '../types';
  10. import { PromQueryBuilder } from './PromQueryBuilder';
  11. export interface Props {
  12. nestedQuery: PromVisualQueryBinary;
  13. datasource: PrometheusDatasource;
  14. index: number;
  15. onChange: (index: number, update: PromVisualQueryBinary) => void;
  16. onRemove: (index: number) => void;
  17. onRunQuery: () => void;
  18. }
  19. export const NestedQuery = React.memo<Props>(({ nestedQuery, index, datasource, onChange, onRemove, onRunQuery }) => {
  20. const styles = useStyles2(getStyles);
  21. return (
  22. <div className={styles.card}>
  23. <div className={styles.header}>
  24. <div className={styles.name}>Operator</div>
  25. <Select
  26. width="auto"
  27. options={operators}
  28. value={toOption(nestedQuery.operator)}
  29. onChange={(value) => {
  30. onChange(index, {
  31. ...nestedQuery,
  32. operator: value.value!,
  33. });
  34. }}
  35. />
  36. <div className={styles.name}>Vector matches</div>
  37. <div className={styles.vectorMatchWrapper}>
  38. <Select<PromVisualQueryBinary['vectorMatchesType']>
  39. width="auto"
  40. value={nestedQuery.vectorMatchesType || 'on'}
  41. allowCustomValue
  42. options={[
  43. { value: 'on', label: 'on' },
  44. { value: 'ignoring', label: 'ignoring' },
  45. ]}
  46. onChange={(val) => {
  47. onChange(index, {
  48. ...nestedQuery,
  49. vectorMatchesType: val.value,
  50. });
  51. }}
  52. />
  53. <AutoSizeInput
  54. className={styles.vectorMatchInput}
  55. minWidth={20}
  56. defaultValue={nestedQuery.vectorMatches}
  57. onCommitChange={(evt) => {
  58. onChange(index, {
  59. ...nestedQuery,
  60. vectorMatches: evt.currentTarget.value,
  61. vectorMatchesType: nestedQuery.vectorMatchesType || 'on',
  62. });
  63. }}
  64. />
  65. </div>
  66. <FlexItem grow={1} />
  67. <IconButton name="times" size="sm" onClick={() => onRemove(index)} />
  68. </div>
  69. <div className={styles.body}>
  70. <EditorRows>
  71. <PromQueryBuilder
  72. query={nestedQuery.query}
  73. datasource={datasource}
  74. nested={true}
  75. onRunQuery={onRunQuery}
  76. onChange={(update) => {
  77. onChange(index, { ...nestedQuery, query: update });
  78. }}
  79. />
  80. </EditorRows>
  81. </div>
  82. </div>
  83. );
  84. });
  85. const operators = binaryScalarDefs.map((def) => ({ label: def.sign, value: def.sign }));
  86. NestedQuery.displayName = 'NestedQuery';
  87. const getStyles = (theme: GrafanaTheme2) => {
  88. return {
  89. card: css({
  90. label: 'card',
  91. display: 'flex',
  92. flexDirection: 'column',
  93. gap: theme.spacing(0.5),
  94. }),
  95. header: css({
  96. label: 'header',
  97. padding: theme.spacing(0.5, 0.5, 0.5, 1),
  98. gap: theme.spacing(1),
  99. display: 'flex',
  100. alignItems: 'center',
  101. }),
  102. name: css({
  103. label: 'name',
  104. whiteSpace: 'nowrap',
  105. }),
  106. body: css({
  107. label: 'body',
  108. paddingLeft: theme.spacing(2),
  109. }),
  110. vectorMatchInput: css({
  111. label: 'vectorMatchInput',
  112. marginLeft: -1,
  113. }),
  114. vectorMatchWrapper: css({
  115. label: 'vectorMatchWrapper',
  116. display: 'flex',
  117. }),
  118. };
  119. };