From 806b0e3b23ba21bc23b8083273a35d72a089b6b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 10 Mar 2022 09:38:53 +0100 Subject: [PATCH] Prometheus/Loki: Improve operations header UX (#46346) * Prometheus/Loki: Improve operations header UX * More tweaks * Rename file to match compponent --- .../querybuilder/shared/OperationEditor.tsx | 51 ++------ .../querybuilder/shared/OperationHeader.tsx | 115 ++++++++++++++++++ .../querybuilder/shared/OperationName.tsx | 92 -------------- 3 files changed, 126 insertions(+), 132 deletions(-) create mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/OperationHeader.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/OperationName.tsx diff --git a/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationEditor.tsx b/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationEditor.tsx index ecf4683714d..f464cf9786c 100644 --- a/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationEditor.tsx +++ b/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationEditor.tsx @@ -1,6 +1,6 @@ import { css } from '@emotion/css'; import { DataSourceApi, GrafanaTheme2 } from '@grafana/data'; -import { FlexItem, Stack } from '@grafana/experimental'; +import { Stack } from '@grafana/experimental'; import { Button, useStyles2 } from '@grafana/ui'; import React from 'react'; import { Draggable } from 'react-beautiful-dnd'; @@ -11,8 +11,7 @@ import { QueryBuilderOperationDef, QueryBuilderOperationParamDef, } from '../shared/types'; -import { OperationInfoButton } from './OperationInfoButton'; -import { OperationName } from './OperationName'; +import { OperationHeader } from './OperationHeader'; import { getOperationParamEditor } from './OperationParamEditor'; import { getOperationParamId } from './operationUtils'; @@ -121,27 +120,15 @@ export function OperationEditor({ {...provided.draggableProps} data-testid={`operations.${index}.wrapper`} > -
- - -
- -
-
+
{operationElements}
{restParam} {index < query.operations.length - 1 && ( @@ -205,16 +192,6 @@ const getStyles = (theme: GrafanaTheme2) => { marginBottom: theme.spacing(1), position: 'relative', }), - header: css({ - borderBottom: `1px solid ${theme.colors.border.medium}`, - padding: theme.spacing(0.5, 0.5, 0.5, 1), - gap: theme.spacing(1), - display: 'flex', - alignItems: 'center', - '&:hover .operation-header-show-on-hover': css({ - opacity: 1, - }), - }), infoIcon: css({ color: theme.colors.text.secondary, }), @@ -234,12 +211,6 @@ const getStyles = (theme: GrafanaTheme2) => { verticalAlign: 'middle', height: '32px', }), - operationHeaderButtons: css({ - opacity: 0, - transition: theme.transitions.create(['opacity'], { - duration: theme.transitions.duration.short, - }), - }), paramValue: css({ display: 'table-cell', paddingBottom: theme.spacing(0.5), diff --git a/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationHeader.tsx b/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationHeader.tsx new file mode 100644 index 00000000000..0f5e723c76f --- /dev/null +++ b/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationHeader.tsx @@ -0,0 +1,115 @@ +import { css } from '@emotion/css'; +import { GrafanaTheme2, SelectableValue } from '@grafana/data'; +import { FlexItem } from '@grafana/experimental'; +import { Button, Select, useStyles2 } from '@grafana/ui'; +import React, { useState } from 'react'; +import { OperationInfoButton } from './OperationInfoButton'; +import { VisualQueryModeller, QueryBuilderOperation, QueryBuilderOperationDef } from './types'; + +export interface Props { + operation: QueryBuilderOperation; + def: QueryBuilderOperationDef; + index: number; + queryModeller: VisualQueryModeller; + dragHandleProps: any; + onChange: (index: number, update: QueryBuilderOperation) => void; + onRemove: (index: number) => void; +} + +interface State { + isOpen?: boolean; + alternatives?: Array>; +} + +export const OperationHeader = React.memo( + ({ operation, def, index, onChange, onRemove, queryModeller, dragHandleProps }) => { + const styles = useStyles2(getStyles); + const [state, setState] = useState({}); + + const onToggleSwitcher = () => { + if (state.isOpen) { + setState({ ...state, isOpen: false }); + } else { + const alternatives = queryModeller + .getAlternativeOperations(def.alternativesKey!) + .map((alt) => ({ label: alt.name, value: alt })); + setState({ isOpen: true, alternatives }); + } + }; + + return ( +
+ {!state.isOpen && ( + <> +
{def.name ?? def.id}
+ +
+
+ + )} + {state.isOpen && ( +
+ { - if (value.value) { - // Operation should exist if it is selectable - const newDef = queryModeller.getOperationDef(value.value.id)!; - let changedOp = { ...operation, id: value.value.id }; - onChange(index, def.changeTypeHandler ? def.changeTypeHandler(changedOp, newDef) : changedOp); - } - }} - /> - )} - - ); -}); - -OperationName.displayName = 'OperationName'; - -const getStyles = (theme: GrafanaTheme2) => { - return { - wrapper: css({ - display: 'inline-block', - background: 'transparent', - padding: 0, - border: 'none', - boxShadow: 'none', - cursor: 'pointer', - }), - dropdown: css({ - opacity: 0, - color: theme.colors.text.secondary, - }), - }; -};