The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/features/dashboard-scene/settings/variables/VariableSetEditableElement.tsx

171 lines
5.9 KiB

import { css } from '@emotion/css';
import { useMemo } from 'react';
import { useToggle } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { SceneVariable, SceneVariableSet } from '@grafana/scenes';
import { Stack, Button, useStyles2, Text, Box, Card } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { OptionsPaneCategoryDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor';
import { OptionsPaneItemDescriptor } from 'app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor';
import { NewObjectAddedToCanvasEvent } from '../../edit-pane/shared';
import { DashboardScene } from '../../scene/DashboardScene';
import { EditableDashboardElement, EditableDashboardElementInfo } from '../../scene/types/EditableDashboardElement';
import { getDashboardSceneFor } from '../../utils/utils';
import { EditableVariableType, getNextAvailableId, getVariableScene, getVariableTypeSelectOptions } from './utils';
export class VariableSetEditableElement implements EditableDashboardElement {
public readonly isEditableDashboardElement = true;
public readonly typeName = 'Variable';
public constructor(private set: SceneVariableSet) {}
public getEditableElementInfo(): EditableDashboardElementInfo {
return {
typeName: t('dashboard.edit-pane.elements.variable-set', 'Variables'),
icon: 'x',
instanceName: t('dashboard.edit-pane.elements.variable-set', 'Variables'),
isContainer: true,
};
}
public useEditPaneOptions(): OptionsPaneCategoryDescriptor[] {
const set = this.set;
const options = useMemo(() => {
return new OptionsPaneCategoryDescriptor({ title: '', id: 'variables' }).addItem(
new OptionsPaneItemDescriptor({
title: '',
skipField: true,
render: () => <VariableList set={set} />,
})
);
}, [set]);
return [options];
}
}
function VariableList({ set }: { set: SceneVariableSet }) {
const { variables } = set.useState();
const styles = useStyles2(getStyles);
const [isAdding, setIsAdding] = useToggle(false);
const canAdd = set.parent instanceof DashboardScene;
const onEditVariable = (variable: SceneVariable) => {
const { editPane } = getDashboardSceneFor(set).state;
editPane.selectObject(variable, variable.state.key!);
};
const onAddVariable = (type: EditableVariableType) => {
const { variables } = set.state;
const nextName = getNextAvailableId(type, variables);
const newVar = getVariableScene(type, { name: nextName });
set.setState({ variables: [...variables, newVar] });
set.publishEvent(new NewObjectAddedToCanvasEvent(newVar), true);
setIsAdding(false);
};
if (isAdding) {
return <VariableTypeSelection onAddVariable={onAddVariable} />;
}
return (
<Stack direction="column" gap={0}>
{variables.map((variable) => (
// TODO fix keyboard a11y here
// eslint-disable-next-line jsx-a11y/no-static-element-interactions,jsx-a11y/click-events-have-key-events
<div className={styles.variableItem} key={variable.state.name} onClick={() => onEditVariable(variable)}>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
<Text>${variable.state.name}</Text>
<Stack direction="row" gap={1} alignItems="center">
<Button variant="primary" size="sm" fill="outline">
<Trans i18nKey="dashboard.edit-pane.variables.select-variable">Select</Trans>
</Button>
</Stack>
</div>
))}
{canAdd && (
<Box paddingBottom={1} display={'flex'}>
<Button
fullWidth
icon="plus"
size="sm"
variant="secondary"
onClick={setIsAdding}
data-testid={selectors.components.PanelEditor.ElementEditPane.addVariableButton}
>
<Trans i18nKey="dashboard.edit-pane.variables.add-variable">Add variable</Trans>
</Button>
</Box>
)}
</Stack>
);
}
interface VariableTypeSelectionProps {
onAddVariable: (type: EditableVariableType) => void;
}
function VariableTypeSelection({ onAddVariable }: VariableTypeSelectionProps) {
const options = getVariableTypeSelectOptions();
const styles = useStyles2(getStyles);
return (
<Stack direction={'column'} gap={0}>
<Box paddingBottom={1} display={'flex'}>
<Trans i18nKey="dashboard.edit-pane.variables.select-type">Choose variable type</Trans>
</Box>
{options.map((option) => (
<Card
isCompact
onClick={() => onAddVariable(option.value!)}
key={option.value}
title={t('dashboard.edit-pane.variables.select-type-card-tooltip', 'Click to select type')}
data-testid={selectors.components.PanelEditor.ElementEditPane.variableType(option.value!)}
>
<Card.Heading>{option.label}</Card.Heading>
<Card.Description className={styles.cardDescription}>{option.description}</Card.Description>
</Card>
))}
</Stack>
);
}
function getStyles(theme: GrafanaTheme2) {
return {
variableItem: css({
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
gap: theme.spacing(1),
padding: theme.spacing(0.5),
borderRadius: theme.shape.radius.default,
cursor: 'pointer',
[theme.transitions.handleMotion('no-preference', 'reduce')]: {
transition: theme.transitions.create(['color'], {
duration: theme.transitions.duration.short,
}),
},
'&:last-child': {
marginBottom: theme.spacing(2),
},
button: {
visibility: 'hidden',
},
'&:hover': {
color: theme.colors.text.link,
button: {
visibility: 'visible',
},
},
}),
cardDescription: css({
fontSize: theme.typography.bodySmall.fontSize,
marginTop: theme.spacing(0),
}),
};
}