DerivedField.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import { css } from '@emotion/css';
  2. import React, { useEffect, useState } from 'react';
  3. import { usePrevious } from 'react-use';
  4. import { VariableSuggestion } from '@grafana/data';
  5. import { DataSourcePicker } from '@grafana/runtime';
  6. import { Button, DataLinkInput, stylesFactory, LegacyForms } from '@grafana/ui';
  7. import { DerivedFieldConfig } from '../types';
  8. const { Switch, FormField } = LegacyForms;
  9. const getStyles = stylesFactory(() => ({
  10. row: css`
  11. display: flex;
  12. align-items: baseline;
  13. `,
  14. nameField: css`
  15. flex: 2;
  16. `,
  17. regexField: css`
  18. flex: 3;
  19. `,
  20. urlField: css`
  21. flex: 1;
  22. `,
  23. urlDisplayLabelField: css`
  24. flex: 1;
  25. `,
  26. }));
  27. type Props = {
  28. value: DerivedFieldConfig;
  29. onChange: (value: DerivedFieldConfig) => void;
  30. onDelete: () => void;
  31. suggestions: VariableSuggestion[];
  32. className?: string;
  33. };
  34. export const DerivedField = (props: Props) => {
  35. const { value, onChange, onDelete, suggestions, className } = props;
  36. const styles = getStyles();
  37. const [showInternalLink, setShowInternalLink] = useState(!!value.datasourceUid);
  38. const previousUid = usePrevious(value.datasourceUid);
  39. // Force internal link visibility change if uid changed outside of this component.
  40. useEffect(() => {
  41. if (!previousUid && value.datasourceUid && !showInternalLink) {
  42. setShowInternalLink(true);
  43. }
  44. if (previousUid && !value.datasourceUid && showInternalLink) {
  45. setShowInternalLink(false);
  46. }
  47. }, [previousUid, value.datasourceUid, showInternalLink]);
  48. const handleChange = (field: keyof typeof value) => (event: React.ChangeEvent<HTMLInputElement>) => {
  49. onChange({
  50. ...value,
  51. [field]: event.currentTarget.value,
  52. });
  53. };
  54. return (
  55. <div className={className}>
  56. <div className={styles.row}>
  57. <FormField
  58. className={styles.nameField}
  59. labelWidth={5}
  60. // A bit of a hack to prevent using default value for the width from FormField
  61. inputWidth={null}
  62. label="Name"
  63. type="text"
  64. value={value.name}
  65. onChange={handleChange('name')}
  66. />
  67. <FormField
  68. className={styles.regexField}
  69. inputWidth={null}
  70. label="Regex"
  71. type="text"
  72. value={value.matcherRegex}
  73. onChange={handleChange('matcherRegex')}
  74. tooltip={
  75. 'Use to parse and capture some part of the log message. You can use the captured groups in the template.'
  76. }
  77. />
  78. <Button
  79. variant="destructive"
  80. title="Remove field"
  81. icon="times"
  82. onClick={(event) => {
  83. event.preventDefault();
  84. onDelete();
  85. }}
  86. className={css`
  87. margin-left: 8px;
  88. `}
  89. />
  90. </div>
  91. <div className={styles.row}>
  92. <FormField
  93. label={showInternalLink ? 'Query' : 'URL'}
  94. inputEl={
  95. <DataLinkInput
  96. placeholder={showInternalLink ? '${__value.raw}' : 'http://example.com/${__value.raw}'}
  97. value={value.url || ''}
  98. onChange={(newValue) =>
  99. onChange({
  100. ...value,
  101. url: newValue,
  102. })
  103. }
  104. suggestions={suggestions}
  105. />
  106. }
  107. className={styles.urlField}
  108. />
  109. <FormField
  110. className={styles.urlDisplayLabelField}
  111. inputWidth={null}
  112. label="URL Label"
  113. type="text"
  114. value={value.urlDisplayLabel}
  115. onChange={handleChange('urlDisplayLabel')}
  116. tooltip={'Use to override the button label when this derived field is found in a log.'}
  117. />
  118. </div>
  119. <div className={styles.row}>
  120. <Switch
  121. label="Internal link"
  122. checked={showInternalLink}
  123. onChange={() => {
  124. if (showInternalLink) {
  125. onChange({
  126. ...value,
  127. datasourceUid: undefined,
  128. });
  129. }
  130. setShowInternalLink(!showInternalLink);
  131. }}
  132. />
  133. {showInternalLink && (
  134. <DataSourcePicker
  135. tracing={true}
  136. onChange={(ds) =>
  137. onChange({
  138. ...value,
  139. datasourceUid: ds.uid,
  140. })
  141. }
  142. current={value.datasourceUid}
  143. />
  144. )}
  145. </div>
  146. </div>
  147. );
  148. };