Remove drop target from tab and row

This commit is contained in:
Bogdan Matei
2025-11-17 11:14:06 +02:00
parent 9dd8c85448
commit 42bbaf7286
4 changed files with 10 additions and 127 deletions
@@ -1,16 +1,7 @@
import React from 'react';
import { t } from '@grafana/i18n';
import { logWarning } from '@grafana/runtime';
import {
sceneGraph,
SceneObject,
SceneObjectBase,
SceneObjectState,
VariableDependencyConfig,
SceneGridItemLike,
SceneGridLayout,
} from '@grafana/scenes';
import { sceneGraph, SceneObject, SceneObjectBase, SceneObjectState, VariableDependencyConfig } from '@grafana/scenes';
import { RowsLayoutRowKind } from '@grafana/schema/dist/esm/schema/dashboard/v2';
import { appEvents } from 'app/core/app_events';
import { LS_ROW_COPY_KEY } from 'app/core/constants';
@@ -22,15 +13,10 @@ import { ConditionalRenderingGroup } from '../../conditional-rendering/group/Con
import { serializeRow } from '../../serialization/layoutSerializers/RowsLayoutSerializer';
import { getElements } from '../../serialization/layoutSerializers/utils';
import { getDashboardSceneFor } from '../../utils/utils';
import { AutoGridItem } from '../layout-auto-grid/AutoGridItem';
import { AutoGridLayout } from '../layout-auto-grid/AutoGridLayout';
import { AutoGridLayoutManager } from '../layout-auto-grid/AutoGridLayoutManager';
import { DashboardGridItem } from '../layout-default/DashboardGridItem';
import { clearClipboard } from '../layouts-shared/paste';
import { scrollCanvasElementIntoView } from '../layouts-shared/scrollCanvasElementIntoView';
import { BulkActionElement } from '../types/BulkActionElement';
import { DashboardDropTarget } from '../types/DashboardDropTarget';
import { isDashboardLayoutGrid } from '../types/DashboardLayoutGrid';
import { DashboardLayoutManager } from '../types/DashboardLayoutManager';
import { EditableDashboardElement, EditableDashboardElementInfo } from '../types/EditableDashboardElement';
import { LayoutParent } from '../types/LayoutParent';
@@ -56,7 +42,7 @@ export interface RowItemState extends SceneObjectState {
export class RowItem
extends SceneObjectBase<RowItemState>
implements LayoutParent, BulkActionElement, EditableDashboardElement, DashboardDropTarget
implements LayoutParent, BulkActionElement, EditableDashboardElement
{
public static Component = RowItemRenderer;
@@ -168,44 +154,6 @@ export class RowItem
store.set(LS_ROW_COPY_KEY, JSON.stringify({ elements, row: this.serialize() }));
}
public setIsDropTarget(isDropTarget: boolean) {
if (!!this.state.isDropTarget !== isDropTarget) {
this.setState({ isDropTarget });
}
}
public draggedGridItemOutside?(gridItem: SceneGridItemLike): void {
// Remove from source layout
if (gridItem instanceof DashboardGridItem || gridItem instanceof AutoGridItem) {
const layout = gridItem.parent;
if (gridItem instanceof DashboardGridItem && layout instanceof SceneGridLayout) {
const newChildren = layout.state.children.filter((child) => child !== gridItem);
layout.setState({ children: newChildren });
} else if (gridItem instanceof AutoGridItem && layout instanceof AutoGridLayout) {
const newChildren = layout.state.children.filter((child) => child !== gridItem);
layout.setState({ children: newChildren });
} else {
const warningMessage = 'Grid item has unexpected parent type';
console.warn(warningMessage);
logWarning(warningMessage);
}
}
this.setIsDropTarget(false);
}
public draggedGridItemInside(gridItem: SceneGridItemLike): void {
const layout = this.getLayout();
if (isDashboardLayoutGrid(layout)) {
layout.addGridItem(gridItem);
} else {
const warningMessage = 'Layout manager does not support addGridItem';
console.warn(warningMessage);
logWarning(warningMessage);
}
this.setIsDropTarget(false);
}
public onChangeTitle(title: string) {
this.setState({ title });
}
@@ -17,7 +17,7 @@ import { useSoloPanelContext } from '../SoloPanelContext';
import { RowItem } from './RowItem';
export function RowItemRenderer({ model }: SceneComponentProps<RowItem>) {
const { layout, collapse: isCollapsed, fillScreen, hideHeader: isHeaderHidden, isDropTarget, key } = model.useState();
const { layout, collapse: isCollapsed, fillScreen, hideHeader: isHeaderHidden, key } = model.useState();
const isClone = isRepeatCloneOrChildOf(model);
const { isEditing } = useDashboardState(model);
const [isConditionallyHidden, conditionalRenderingClass, conditionalRenderingOverlay] =
@@ -82,7 +82,6 @@ export function RowItemRenderer({ model }: SceneComponentProps<RowItem>) {
dragProvided.innerRef(ref);
model.containerRef.current = ref;
}}
data-dashboard-drop-target-key={model.state.key}
className={cx(
styles.wrapper,
!isCollapsed && styles.wrapperNotCollapsed,
@@ -91,8 +90,7 @@ export function RowItemRenderer({ model }: SceneComponentProps<RowItem>) {
shouldGrow && styles.wrapperGrow,
conditionalRenderingClass,
!isClone && isSelected && 'dashboard-selected-element',
!isClone && !isSelected && selectableHighlight && 'dashboard-selectable-element',
isDropTarget && 'dashboard-drop-target'
!isClone && !isSelected && selectableHighlight && 'dashboard-selectable-element'
)}
onPointerDown={(evt) => {
evt.stopPropagation();
@@ -1,16 +1,7 @@
import React from 'react';
import { t } from '@grafana/i18n';
import { logWarning } from '@grafana/runtime';
import {
SceneObjectState,
SceneObjectBase,
sceneGraph,
VariableDependencyConfig,
SceneObject,
SceneGridItemLike,
SceneGridLayout,
} from '@grafana/scenes';
import { SceneObjectState, SceneObjectBase, sceneGraph, VariableDependencyConfig, SceneObject } from '@grafana/scenes';
import { TabsLayoutTabKind } from '@grafana/schema/dist/esm/schema/dashboard/v2';
import { appEvents } from 'app/core/app_events';
import { LS_TAB_COPY_KEY } from 'app/core/constants';
@@ -22,15 +13,10 @@ import { ConditionalRenderingGroup } from '../../conditional-rendering/group/Con
import { serializeTab } from '../../serialization/layoutSerializers/TabsLayoutSerializer';
import { getElements } from '../../serialization/layoutSerializers/utils';
import { getDashboardSceneFor } from '../../utils/utils';
import { AutoGridItem } from '../layout-auto-grid/AutoGridItem';
import { AutoGridLayout } from '../layout-auto-grid/AutoGridLayout';
import { AutoGridLayoutManager } from '../layout-auto-grid/AutoGridLayoutManager';
import { DashboardGridItem } from '../layout-default/DashboardGridItem';
import { clearClipboard } from '../layouts-shared/paste';
import { scrollCanvasElementIntoView } from '../layouts-shared/scrollCanvasElementIntoView';
import { BulkActionElement } from '../types/BulkActionElement';
import { DashboardDropTarget } from '../types/DashboardDropTarget';
import { isDashboardLayoutGrid } from '../types/DashboardLayoutGrid';
import { DashboardLayoutManager } from '../types/DashboardLayoutManager';
import { EditableDashboardElement, EditableDashboardElementInfo } from '../types/EditableDashboardElement';
import { LayoutParent } from '../types/LayoutParent';
@@ -43,7 +29,6 @@ import { TabsLayoutManager } from './TabsLayoutManager';
export interface TabItemState extends SceneObjectState {
layout: DashboardLayoutManager;
title?: string;
isDropTarget?: boolean;
conditionalRendering?: ConditionalRenderingGroup;
repeatByVariable?: string;
repeatedTabs?: TabItem[];
@@ -53,7 +38,7 @@ export interface TabItemState extends SceneObjectState {
export class TabItem
extends SceneObjectBase<TabItemState>
implements LayoutParent, BulkActionElement, EditableDashboardElement, DashboardDropTarget
implements LayoutParent, BulkActionElement, EditableDashboardElement
{
public static Component = TabItemRenderer;
@@ -186,49 +171,6 @@ export class TabItem
}
}
public setIsDropTarget(isDropTarget: boolean) {
if (!!this.state.isDropTarget !== isDropTarget) {
this.setState({ isDropTarget });
}
}
public draggedGridItemOutside?(gridItem: SceneGridItemLike): void {
// Remove from source layout
if (gridItem instanceof DashboardGridItem || gridItem instanceof AutoGridItem) {
const layout = gridItem.parent;
if (gridItem instanceof DashboardGridItem && layout instanceof SceneGridLayout) {
const newChildren = layout.state.children.filter((child) => child !== gridItem);
layout.setState({ children: newChildren });
} else if (gridItem instanceof AutoGridItem && layout instanceof AutoGridLayout) {
const newChildren = layout.state.children.filter((child) => child !== gridItem);
layout.setState({ children: newChildren });
} else {
const warningMessage = 'Grid item has unexpected parent type';
console.warn(warningMessage);
logWarning(warningMessage);
}
}
this.setIsDropTarget(false);
}
public draggedGridItemInside(gridItem: SceneGridItemLike): void {
const layout = this.getLayout();
if (isDashboardLayoutGrid(layout)) {
layout.addGridItem(gridItem);
} else {
const warningMessage = 'Layout manager does not support addGridItem';
console.warn(warningMessage);
logWarning(warningMessage);
}
this.setIsDropTarget(false);
const parentLayout = this.getParentLayout();
if (parentLayout.state.currentTabSlug !== this.getSlug()) {
parentLayout.setState({ currentTabSlug: this.getSlug() });
}
}
public getParentLayout(): TabsLayoutManager {
return sceneGraph.getAncestor(this, TabsLayoutManager);
}
@@ -15,7 +15,7 @@ import { useSoloPanelContext } from '../SoloPanelContext';
import { TabItem } from './TabItem';
export function TabItemRenderer({ model }: SceneComponentProps<TabItem>) {
const { title, key, isDropTarget, layout } = model.useState();
const { title, key, layout } = model.useState();
const parentLayout = model.getParentLayout();
const { currentTabSlug } = parentLayout.useState();
const titleInterpolated = sceneGraph.interpolate(model, title, undefined, 'text');
@@ -67,8 +67,7 @@ export function TabItemRenderer({ model }: SceneComponentProps<TabItem>) {
className={cx(
isConditionallyHidden && styles.hidden,
isSelected && 'dashboard-selected-element',
isSelectable && !isSelected && 'dashboard-selectable-element',
isDropTarget && 'dashboard-drop-target'
isSelectable && !isSelected && 'dashboard-selectable-element'
)}
active={isActive}
title={titleInterpolated}
@@ -89,7 +88,6 @@ export function TabItemRenderer({ model }: SceneComponentProps<TabItem>) {
onSelect?.(evt);
}}
label={titleInterpolated}
data-dashboard-drop-target-key={model.state.key}
{...titleCollisionProps}
/>
</div>
@@ -114,15 +112,12 @@ interface TabItemLayoutRendererProps {
}
export function TabItemLayoutRenderer({ tab, isEditing }: TabItemLayoutRendererProps) {
const { layout, key } = tab.useState();
const { layout } = tab.useState();
const styles = useStyles2(getStyles);
const [_, conditionalRenderingClass, conditionalRenderingOverlay] = useIsConditionallyHidden(tab);
return (
<TabContent
className={cx(styles.tabContentContainer, isEditing && conditionalRenderingClass)}
data-dashboard-drop-target-key={key}
>
<TabContent className={cx(styles.tabContentContainer, isEditing && conditionalRenderingClass)}>
<layout.Component model={layout} />
{isEditing && conditionalRenderingOverlay}
</TabContent>