diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/DetailView.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/DetailView.tsx
index 66cb7375489..d1b2778d987 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/DetailView.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/DetailView.tsx
@@ -18,67 +18,76 @@ interface DetailViewProps {
selectedItem: QueryTransformItem | undefined;
panel: VizPanel;
tabs: Array<{ tabId: TabId }>;
+ onRemoveTransform?: (index: number) => void;
+ onToggleTransformVisibility?: (index: number) => void;
}
-export const DetailView = memo(({ selectedItem, panel, tabs }: DetailViewProps) => {
- const styles = useStyles2(getStyles);
+export const DetailView = memo(
+ ({ selectedItem, panel, tabs, onRemoveTransform, onToggleTransformVisibility }: DetailViewProps) => {
+ const styles = useStyles2(getStyles);
- const renderContent = useCallback(() => {
- if (!selectedItem) {
- return (
-
-
-
- Select a query or transformation to edit
-
-
-
- );
- }
+ const renderContent = useCallback(() => {
+ if (!selectedItem) {
+ return (
+
+
+
+ Select a query or transformation to edit
+
+
+
+ );
+ }
- if (selectedItem.type === 'query' && 'refId' in selectedItem.data) {
- const query = selectedItem.data;
- return (
- <>
-
-
-
-
- >
- );
- } else if (selectedItem.type === 'expression' && 'refId' in selectedItem.data) {
- const data = selectedItem.data;
- if (isExpressionQuery(data)) {
+ if (selectedItem.type === 'query' && 'refId' in selectedItem.data) {
+ const query = selectedItem.data;
return (
<>
-
+
>
);
+ } else if (selectedItem.type === 'expression' && 'refId' in selectedItem.data) {
+ const data = selectedItem.data;
+ if (isExpressionQuery(data)) {
+ return (
+ <>
+
+
+
+
+ >
+ );
+ }
+ } else {
+ const transformsTab = tabs.find((t): t is PanelDataTransformationsTab => t.tabId === TabId.Transformations);
+ if (transformsTab && 'id' in selectedItem.data) {
+ return (
+ <>
+
+
+
+
+
+
+ >
+ );
+ }
}
- } else {
- const transformsTab = tabs.find((t): t is PanelDataTransformationsTab => t.tabId === TabId.Transformations);
- if (transformsTab && 'id' in selectedItem.data) {
- return (
- <>
-
-
-
-
-
-
- >
- );
- }
- }
- return null;
- }, [selectedItem, panel, tabs, styles.emptyState]);
+ return null;
+ }, [selectedItem, panel, tabs, styles.emptyState, onRemoveTransform, onToggleTransformVisibility]);
- return {renderContent()}
;
-});
+ return {renderContent()}
;
+ }
+);
DetailView.displayName = 'DetailView';
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/DetailViewHeader.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/DetailViewHeader.tsx
index 666851ab22e..58e09e1077c 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/DetailViewHeader.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/DetailViewHeader.tsx
@@ -32,6 +32,8 @@ import { QueryTransformItem } from './QueryTransformList';
interface DetailViewHeaderProps {
selectedItem: QueryTransformItem;
panel: VizPanel;
+ onRemoveTransform?: (index: number) => void;
+ onToggleTransformVisibility?: (index: number) => void;
}
const ITEM_CONFIG = (theme: GrafanaTheme2) => ({
@@ -49,7 +51,12 @@ const ITEM_CONFIG = (theme: GrafanaTheme2) => ({
},
});
-export const DetailViewHeader = ({ selectedItem, panel }: DetailViewHeaderProps) => {
+export const DetailViewHeader = ({
+ selectedItem,
+ panel,
+ onRemoveTransform,
+ onToggleTransformVisibility,
+}: DetailViewHeaderProps) => {
const theme = useTheme2();
const config = useMemo(() => ITEM_CONFIG(theme)[selectedItem.type], [theme, selectedItem.type]);
const styles = useStyles2(getStyles, config);
@@ -243,12 +250,30 @@ export const DetailViewHeader = ({ selectedItem, panel }: DetailViewHeaderProps)
queryRunner?.runQueries();
}, [panel]);
+ // Transformation action handlers
+ const onRemoveTransformation = useCallback(() => {
+ if (selectedItem.type !== 'transform' || selectedItem.index === undefined) {
+ return;
+ }
+ onRemoveTransform?.(selectedItem.index);
+ }, [selectedItem, onRemoveTransform]);
+
+ const onToggleTransformationVisibility = useCallback(() => {
+ if (selectedItem.type !== 'transform' || selectedItem.index === undefined) {
+ return;
+ }
+ onToggleTransformVisibility?.(selectedItem.index);
+ }, [selectedItem, onToggleTransformVisibility]);
+
const refId = 'refId' in selectedItem.data ? selectedItem.data.refId : '';
const isHidden =
(selectedItem.type === 'query' || selectedItem.type === 'expression') &&
'hide' in selectedItem.data &&
selectedItem.data.hide;
+ const isTransformDisabled =
+ selectedItem.type === 'transform' && 'disabled' in selectedItem.data && selectedItem.data.disabled;
+
// Get transformation display name
const transformationName = useMemo(() => {
if (selectedItem.type === 'transform' && 'id' in selectedItem.data) {
@@ -314,7 +339,7 @@ export const DetailViewHeader = ({ selectedItem, panel }: DetailViewHeaderProps)
)}
- {/* Right side: Run Query + Actions Menu */}
+ {/* Right side: Run Query + Actions Menu for queries/expressions */}
{(selectedItem.type === 'query' || selectedItem.type === 'expression') && (
)}
+
+ {/* Right side: Actions Menu for transformations */}
+ {selectedItem.type === 'transform' && (
+
+
+
+
+
+
+ }
+ >
+
+
+
+ )}
);
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx
index 65a17a73df1..2e782b0dd5c 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx
@@ -501,7 +501,13 @@ function PanelDataPaneRendered({ model }: SceneComponentProps) {
style={{ ...splitterProps.style, width: '16px' }}
/>
-
+