From 9002d98d02d161a177964e2eb3528c8182fe8a00 Mon Sep 17 00:00:00 2001 From: Paul Marbach Date: Wed, 3 Dec 2025 16:29:26 -0500 Subject: [PATCH] more add button stuff --- .../PanelDataPane/AddDataItemMenu.tsx | 38 +++++++- .../PanelDataPane/QueryTransformList.tsx | 91 ++++++++++++------- 2 files changed, 95 insertions(+), 34 deletions(-) diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/AddDataItemMenu.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/AddDataItemMenu.tsx index 7f6b318f51e..c59708851b6 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/AddDataItemMenu.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/AddDataItemMenu.tsx @@ -1,8 +1,10 @@ -import { memo, useState } from 'react'; +import { css } from '@emotion/css'; +import { ComponentProps, memo, useState } from 'react'; +import { GrafanaTheme2 } from '@grafana/data'; import { t } from '@grafana/i18n'; import { config } from '@grafana/runtime'; -import { Dropdown, IconButton, Menu } from '@grafana/ui'; +import { Button, Dropdown, IconButton, Menu, useStyles2 } from '@grafana/ui'; import { EXPRESSION_ICON_MAP } from 'app/features/expressions/consts'; import { ExpressionQueryType } from 'app/features/expressions/types'; @@ -14,6 +16,7 @@ interface AddDataItemMenuProps { index?: number; allowedTypes?: Array<'query' | 'transform' | 'expression'>; show?: boolean; + text?: string; } export const AddDataItemMenu = memo( @@ -23,15 +26,37 @@ export const AddDataItemMenu = memo( onAddExpression, onAddFromSavedQueries, index, + text, allowedTypes = ['query', 'expression', 'transform'], show = true, }: AddDataItemMenuProps) => { + const styles = useStyles2(getStyles); const [menuShown, setMenuShown] = useState(false); if (!show && !menuShown) { return; } + const renderButton = (onClick?: ComponentProps['onClick']) => { + return text ? ( + + ) : ( + + ); + }; + + if (allowedTypes.length === 1 && allowedTypes[0] === 'transform') { + return renderButton(() => onAddTransform(index)); + } + const expressionTypes = [ { type: ExpressionQueryType.math, label: t('dashboard-scene.add-data-item-menu.expression-math', 'Math') }, { type: ExpressionQueryType.reduce, label: t('dashboard-scene.add-data-item-menu.expression-reduce', 'Reduce') }, @@ -102,10 +127,17 @@ export const AddDataItemMenu = memo( return ( setMenuShown(shown)}> - + {renderButton()} ); } ); +const getStyles = (theme: GrafanaTheme2) => ({ + textButton: css({ + paddingLeft: 0, + fontFamily: theme.typography.fontFamilyMonospace, + }), +}); + AddDataItemMenu.displayName = 'AddDataItemMenu'; diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/QueryTransformList.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/QueryTransformList.tsx index 53c4e260974..88cdd2c7ea7 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/QueryTransformList.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/QueryTransformList.tsx @@ -191,11 +191,11 @@ export const QueryTransformList = memo(
{/* Data Sources Section (Queries + Expressions) */} - {dataSourceItems.length > 0 && ( - -
- {t('dashboard-scene.query-transform-list.queries-expressions', 'Queries & Expressions')} -
+ +
+ {t('dashboard-scene.query-transform-list.queries-expressions', 'Queries & Expressions')} +
+ {dataSourceItems.length > 0 ? ( {(provided, snapshot) => { // Check if dragging from transformations section @@ -206,7 +206,7 @@ export const QueryTransformList = memo(
{ + onMouseMove={(ev) => { const rect = ev.currentTarget.getBoundingClientRect(); const y = ev.clientY - rect.top; let hoveredIdx = Math.floor(y / CARD_HEIGHT); @@ -216,10 +216,16 @@ export const QueryTransformList = memo( if (hoveredIdx > dataSourceItems.length) { hoveredIdx = dataSourceItems.length; } - const hoveredId = hoveredIdx === dataSourceItems.length ? 'queries-last' : dataSourceItems[hoveredIdx].id; + const hoveredId = + hoveredIdx === dataSourceItems.length + ? 'queries-last' + : dataSourceItems[hoveredIdx].id; setHovered(hoveredId); }} - className={cx(styles.cardList, isDraggingFromOtherSection ? styles.droppableInvalid : undefined)} + className={cx( + styles.cardList, + isDraggingFromOtherSection ? styles.droppableInvalid : undefined + )} > {dataSourceItems.map((item, index) => ( @@ -246,7 +252,7 @@ export const QueryTransformList = memo(
)} -
+
@@ -263,7 +269,7 @@ export const QueryTransformList = memo(
-
+
@@ -279,16 +285,24 @@ export const QueryTransformList = memo( ); }} - - - )} + ) : ( + + )} + {/* Transformations Section */} - {transformItems.length > 0 && ( - -
- {t('dashboard-scene.query-transform-list.transformations', 'Transformations')} -
+ +
+ {t('dashboard-scene.query-transform-list.transformations', 'Transformations')} +
+ {transformItems.length > 0 ? ( {(provided, snapshot) => { // Check if dragging from data sources section @@ -299,18 +313,24 @@ export const QueryTransformList = memo(
{ + className={cx( + styles.cardList, + isDraggingFromOtherSection ? styles.droppableInvalid : undefined + )} + onMouseMove={(ev) => { const rect = ev.currentTarget.getBoundingClientRect(); const y = ev.clientY - rect.top; - let hoveredIdx = Math.floor(((y - 16 + (CARD_HEIGHT / 2)) / CARD_HEIGHT)); + let hoveredIdx = Math.floor((y - 16 + CARD_HEIGHT / 2) / CARD_HEIGHT); if (hoveredIdx < 0) { hoveredIdx = 0; } if (hoveredIdx > transformItems.length) { hoveredIdx = transformItems.length; } - const hoveredId = hoveredIdx === transformItems.length ? 'transformations-last' : transformItems[hoveredIdx].id; + const hoveredId = + hoveredIdx === transformItems.length + ? 'transformations-last' + : transformItems[hoveredIdx].id; setHovered(hoveredId); }} > @@ -339,7 +359,7 @@ export const QueryTransformList = memo(
)} -
+
@@ -355,7 +375,7 @@ export const QueryTransformList = memo( {provided.placeholder}
-
+
@@ -371,8 +391,17 @@ export const QueryTransformList = memo( ); }} - - )} + ) : ( + + )} +
@@ -519,7 +548,7 @@ const getStyles = (theme: GrafanaTheme2) => { cardContainerLast: css({ marginTop: theme.spacing(2), }), - floatingButton: css({ + addButtonFloating: css({ position: 'absolute', top: theme.spacing(-2), left: theme.spacing(-2.5),