123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- import { css } from '@emotion/css';
- import React, { ReactElement, useEffect, useState } from 'react';
- import { useAsync } from 'react-use';
- import { GrafanaTheme } from '@grafana/data';
- import { reportInteraction } from '@grafana/runtime';
- import { CollapsableSection, HorizontalGroup, Icon, Spinner, Tooltip, useStyles, VerticalGroup } from '@grafana/ui';
- import { DashboardModel } from '../../dashboard/state';
- import { VariableModel } from '../types';
- import { VariablesUnknownButton } from './VariablesUnknownButton';
- import { getUnknownsNetwork, UsagesToNetwork } from './utils';
- export const SLOW_VARIABLES_EXPANSION_THRESHOLD = 1000;
- export interface VariablesUnknownTableProps {
- variables: VariableModel[];
- dashboard: DashboardModel | null;
- }
- export function VariablesUnknownTable({ variables, dashboard }: VariablesUnknownTableProps): ReactElement {
- const [open, setOpen] = useState(false);
- const [changed, setChanged] = useState(0);
- const [usages, setUsages] = useState<UsagesToNetwork[]>([]);
- const style = useStyles(getStyles);
- useEffect(() => setChanged((prevState) => prevState + 1), [variables, dashboard]);
- const { loading } = useAsync(async () => {
- if (open && changed > 0) {
- // make sure we only fetch when opened and variables or dashboard have changed
- const start = Date.now();
- const unknownsNetwork = await getUnknownsNetwork(variables, dashboard);
- const stop = Date.now();
- const elapsed = stop - start;
- if (elapsed >= SLOW_VARIABLES_EXPANSION_THRESHOLD) {
- reportInteraction('Slow unknown variables expansion', { elapsed });
- }
- setChanged(0);
- setUsages(unknownsNetwork);
- return unknownsNetwork;
- }
- return [];
- }, [variables, dashboard, open, changed]);
- const onToggle = (isOpen: boolean) => {
- if (isOpen) {
- reportInteraction('Unknown variables section expanded');
- }
- setOpen(isOpen);
- };
- return (
- <div className={style.container}>
- <CollapsableSection label={<CollapseLabel />} isOpen={open} onToggle={onToggle}>
- {loading && (
- <VerticalGroup justify="center">
- <HorizontalGroup justify="center">
- <span>Loading...</span>
- <Spinner size={16} />
- </HorizontalGroup>
- </VerticalGroup>
- )}
- {!loading && usages && (
- <>
- {usages.length === 0 && <NoUnknowns />}
- {usages.length > 0 && <UnknownTable usages={usages} />}
- </>
- )}
- </CollapsableSection>
- </div>
- );
- }
- function CollapseLabel(): ReactElement {
- const style = useStyles(getStyles);
- return (
- <h5>
- Renamed or missing variables
- <Tooltip content="Click to expand a list with all variable references that have been renamed or are missing from the dashboard.">
- <Icon name="info-circle" className={style.infoIcon} />
- </Tooltip>
- </h5>
- );
- }
- function NoUnknowns(): ReactElement {
- return <span>No renamed or missing variables found.</span>;
- }
- function UnknownTable({ usages }: { usages: UsagesToNetwork[] }): ReactElement {
- const style = useStyles(getStyles);
- return (
- <table className="filter-table filter-table--hover">
- <thead>
- <tr>
- <th>Variable</th>
- <th colSpan={5} />
- </tr>
- </thead>
- <tbody>
- {usages.map((usage) => {
- const { variable } = usage;
- const { id, name } = variable;
- return (
- <tr key={id}>
- <td className={style.firstColumn}>
- <span>{name}</span>
- </td>
- <td className={style.defaultColumn} />
- <td className={style.defaultColumn} />
- <td className={style.defaultColumn} />
- <td className={style.lastColumn}>
- <VariablesUnknownButton id={variable.id} usages={usages} />
- </td>
- </tr>
- );
- })}
- </tbody>
- </table>
- );
- }
- const getStyles = (theme: GrafanaTheme) => ({
- container: css`
- margin-top: ${theme.spacing.xl};
- padding-top: ${theme.spacing.xl};
- `,
- infoIcon: css`
- margin-left: ${theme.spacing.sm};
- `,
- defaultColumn: css`
- width: 1%;
- `,
- firstColumn: css`
- width: 1%;
- vertical-align: top;
- color: ${theme.colors.textStrong};
- `,
- lastColumn: css`
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- width: 100%;
- text-align: right;
- `,
- });
|