123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- import { css } from '@emotion/css';
- import React, { ChangeEvent, FC } from 'react';
- import { useToggle } from 'react-use';
- import { GrafanaTheme2 } from '@grafana/data';
- import { Stack } from '@grafana/experimental';
- import { Button, Icon, InlineField, TextArea, useStyles2 } from '@grafana/ui';
- import { ExpressionQuery } from '../types';
- interface Props {
- labelWidth: number;
- query: ExpressionQuery;
- onChange: (query: ExpressionQuery) => void;
- onRunQuery: () => void;
- }
- const mathPlaceholder =
- 'Math operations on one or more queries. You reference the query by ${refId} ie. $A, $B, $C etc\n' +
- 'The sum of two scalar values: $A + $B > 10';
- export const Math: FC<Props> = ({ labelWidth, onChange, query, onRunQuery }) => {
- const [showHelp, toggleShowHelp] = useToggle(false);
- const onExpressionChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
- onChange({ ...query, expression: event.target.value });
- };
- const styles = useStyles2((theme) => getStyles(theme, showHelp));
- const executeQuery = () => {
- if (query.expression) {
- onRunQuery();
- }
- };
- return (
- <Stack direction="row">
- <InlineField
- label="Expression"
- labelWidth={labelWidth}
- grow={true}
- shrink={true}
- className={css`
- align-items: flex-start;
- flex: 0.7;
- `}
- >
- <>
- <TextArea
- value={query.expression}
- onChange={onExpressionChange}
- rows={5}
- placeholder={mathPlaceholder}
- onBlur={executeQuery}
- />
- <Button variant="secondary" size="sm" onClick={toggleShowHelp}>
- {showHelp === false ? 'Show' : 'Hide'} help
- </Button>
- </>
- </InlineField>
- <div className={styles.documentationContainer}>
- <header className={styles.documentationHeader}>
- <Icon name="book-open" /> Math operator
- </header>
- <div>
- Run math operations on one or more queries. You reference the query by {'${refId}'} ie. $A, $B, $C etc.
- <br />
- Example: <code>$A + $B</code>
- </div>
- <header className={styles.documentationHeader}>Available Math functions</header>
- <div className={styles.documentationFunctions}>
- <DocumentedFunction
- name="abs"
- description="returns the absolute value of its argument which can be a number or a series"
- />
- <DocumentedFunction
- name="is_inf"
- description="returns 1 for Inf values (negative or positive) and 0 for other values. It's able to operate on series or scalar values."
- />
- <DocumentedFunction
- name="is_nan"
- description="returns 1 for NaN values and 0 for other values. It's able to operate on series or scalar values."
- />
- <DocumentedFunction
- name="is_null"
- description="returns 1 for null values and 0 for other values. It's able to operate on series or scalar values."
- />
- <DocumentedFunction
- name="is_number"
- description="returns 1 for all real number values and 0 for non-number. It's able to operate on series or scalar values."
- />
- <DocumentedFunction
- name="log"
- description="returns the natural logarithm of its argument, which can be a number or a series"
- />
- <DocumentedFunction
- name="inf, infn, nan, and null"
- description="The inf for infinity positive, infn for infinity negative, nan, and null functions all return a single scalar value that matches its name."
- />
- <DocumentedFunction
- name="round"
- description="returns a rounded integer value. It's able to operate on series or escalar values."
- />
- <DocumentedFunction
- name="ceil"
- description="rounds the number up to the nearest integer value. It's able to operate on series or escalar values."
- />
- <DocumentedFunction
- name="floor"
- description="rounds the number down to the nearest integer value. It's able to operate on series or escalar values."
- />
- </div>
- <div>
- See our additional documentation on{' '}
- <a
- className={styles.documentationLink}
- target="_blank"
- href="https://grafana.com/docs/grafana/latest/panels/query-a-data-source/use-expressions-to-manipulate-data/about-expressions/#math"
- rel="noreferrer"
- >
- <Icon size="xs" name="external-link-alt" /> Math expressions
- </a>
- .
- </div>
- </div>
- </Stack>
- );
- };
- interface DocumentedFunctionProps {
- name: string;
- description: React.ReactNode;
- }
- const DocumentedFunction = ({ name, description }: DocumentedFunctionProps) => {
- const styles = useStyles2(getDocumentedFunctionStyles);
- return (
- <>
- <span className={styles.name}>{name}</span>
- <span className={styles.description}>{description}</span>
- </>
- );
- };
- const getStyles = (theme: GrafanaTheme2, showHelp?: boolean) => ({
- documentationHeader: css`
- font-size: ${theme.typography.h5.fontSize};
- font-weight: ${theme.typography.h5.fontWeight};
- `,
- documentationLink: css`
- color: ${theme.colors.text.link};
- `,
- documentationContainer: css`
- display: ${showHelp ? 'flex' : 'none'};
- flex: 1;
- flex-direction: column;
- gap: ${theme.spacing(2)};
- `,
- documentationFunctions: css`
- display: grid;
- grid-template-columns: max-content auto;
- column-gap: ${theme.spacing(2)};
- `,
- });
- const getDocumentedFunctionStyles = (theme: GrafanaTheme2) => ({
- name: css`
- font-weight: ${theme.typography.fontWeightBold};
- `,
- description: css`
- font-size: ${theme.typography.bodySmall.fontSize};
- color: ${theme.colors.text.disabled};
- `,
- });
|