67 lines
1.7 KiB
TypeScript
67 lines
1.7 KiB
TypeScript
import { css } from '@emotion/css';
|
|
|
|
import { Select, HorizontalGroup, Input, useStyles2 } from '@grafana/ui';
|
|
|
|
import { TraceqlFilter } from '../dataquery.gen';
|
|
|
|
import { operatorSelectableValue } from './utils';
|
|
|
|
interface Props {
|
|
filter: TraceqlFilter;
|
|
updateFilter: (f: TraceqlFilter) => void;
|
|
isTagsLoading?: boolean;
|
|
operators: string[];
|
|
}
|
|
|
|
// Support template variables (e.g., `$dur`, `$v_1`) and durations (e.g., `300µs`, `1.2ms`)
|
|
const validationRegex = /^(\$\w+)|(\d+(?:\.\d)?\d*(?:us|µs|ns|ms|s|m|h))$/;
|
|
|
|
const getStyles = () => ({
|
|
noBoxShadow: css({
|
|
boxShadow: 'none',
|
|
'*:focus': {
|
|
boxShadow: 'none',
|
|
},
|
|
}),
|
|
});
|
|
|
|
const DurationInput = ({ filter, operators, updateFilter }: Props) => {
|
|
const styles = useStyles2(getStyles);
|
|
|
|
let invalid = false;
|
|
if (typeof filter.value === 'string') {
|
|
invalid = filter.value ? !validationRegex.test(filter.value.concat('')) : false;
|
|
}
|
|
|
|
return (
|
|
<HorizontalGroup spacing={'none'}>
|
|
<Select
|
|
className={styles.noBoxShadow}
|
|
inputId={`${filter.id}-operator`}
|
|
options={operators.map(operatorSelectableValue)}
|
|
value={filter.operator}
|
|
onChange={(v) => {
|
|
updateFilter({ ...filter, operator: v?.value });
|
|
}}
|
|
isClearable={false}
|
|
aria-label={`select ${filter.id} operator`}
|
|
allowCustomValue={true}
|
|
width={8}
|
|
/>
|
|
<Input
|
|
className={styles.noBoxShadow}
|
|
value={filter.value}
|
|
onChange={(v) => {
|
|
updateFilter({ ...filter, value: v.currentTarget.value });
|
|
}}
|
|
placeholder="e.g. 100ms, 1.2s"
|
|
aria-label={`select ${filter.id} value`}
|
|
invalid={invalid}
|
|
width={18}
|
|
/>
|
|
</HorizontalGroup>
|
|
);
|
|
};
|
|
|
|
export default DurationInput;
|