From 9992da3cc8227d815bb3a5700ce4fa34a905ef50 Mon Sep 17 00:00:00 2001 From: oscarkilhed Date: Tue, 13 Jan 2026 09:07:55 +0100 Subject: [PATCH] Refactor dashboard drop target attributes to use constants for improved maintainability - Introduced constants for data attributes used to identify auto grid items and dashboard layout elements as drop targets. - Updated references throughout the AutoGridLayout, AutoGridItemRenderer, DashboardLayoutOrchestrator, and other related components to utilize the new constants. - This change enhances code readability and reduces the risk of errors related to hardcoded strings. --- .../scene/DashboardLayoutOrchestrator.tsx | 23 +++++++++++-------- .../layout-auto-grid/AutoGridItemRenderer.tsx | 5 ++-- .../scene/layout-auto-grid/AutoGridLayout.tsx | 5 ++-- .../AutoGridLayoutRenderer.tsx | 3 ++- .../scene/layout-rows/RowItemRenderer.tsx | 3 ++- .../layout-rows/RowsLayoutManagerRenderer.tsx | 3 ++- .../scene/layout-tabs/TabItemRenderer.tsx | 3 ++- .../scene/types/DashboardDropTarget.ts | 6 +++++ 8 files changed, 34 insertions(+), 17 deletions(-) diff --git a/public/app/features/dashboard-scene/scene/DashboardLayoutOrchestrator.tsx b/public/app/features/dashboard-scene/scene/DashboardLayoutOrchestrator.tsx index e18ae74f8d5..a8369bcbb4f 100644 --- a/public/app/features/dashboard-scene/scene/DashboardLayoutOrchestrator.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardLayoutOrchestrator.tsx @@ -21,7 +21,12 @@ import { RowItem } from './layout-rows/RowItem'; import { RowsLayoutManager } from './layout-rows/RowsLayoutManager'; import { TabItem } from './layout-tabs/TabItem'; import { TabsLayoutManager } from './layout-tabs/TabsLayoutManager'; -import { DashboardDropTarget, isDashboardDropTarget } from './types/DashboardDropTarget'; +import { + AUTO_GRID_ITEM_DROP_TARGET_ATTR, + DASHBOARD_DROP_TARGET_KEY_ATTR, + DashboardDropTarget, + isDashboardDropTarget, +} from './types/DashboardDropTarget'; const TAB_ACTIVATION_DELAY_MS = 600; @@ -389,8 +394,8 @@ export class DashboardLayoutOrchestrator extends SceneObjectBase el.getAttribute('data-auto-grid-item-drop-target')); - const targetKey = targetElement?.getAttribute('data-auto-grid-item-drop-target'); + const targetElement = elementsUnderPoint?.find((el) => el.getAttribute(AUTO_GRID_ITEM_DROP_TARGET_ATTR)); + const targetKey = targetElement?.getAttribute(AUTO_GRID_ITEM_DROP_TARGET_ATTR); const children = dropTarget.state.layout.state.children; @@ -658,7 +663,7 @@ export class DashboardLayoutOrchestrator extends SceneObjectBase el.getAttribute('data-dashboard-drop-target-key') === this._sourceDropTarget?.state.key + (el) => el.getAttribute(DASHBOARD_DROP_TARGET_KEY_ATTR) === this._sourceDropTarget?.state.key ); if (cursorIsInSourceTarget) { @@ -666,8 +671,8 @@ export class DashboardLayoutOrchestrator extends SceneObjectBase element.getAttribute('data-dashboard-drop-target-key')) - ?.getAttribute('data-dashboard-drop-target-key'); + ?.find((element) => element.getAttribute(DASHBOARD_DROP_TARGET_KEY_ATTR)) + ?.getAttribute(DASHBOARD_DROP_TARGET_KEY_ATTR); if (!key) { return null; diff --git a/public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridItemRenderer.tsx b/public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridItemRenderer.tsx index 0eec56a1f80..60758dcdff2 100644 --- a/public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridItemRenderer.tsx +++ b/public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridItemRenderer.tsx @@ -9,8 +9,9 @@ import { ConditionalRenderingGroup } from '../../conditional-rendering/group/Con import { useIsConditionallyHidden } from '../../conditional-rendering/hooks/useIsConditionallyHidden'; import { useDashboardState } from '../../utils/utils'; import { SoloPanelContextValueWithSearchStringFilter } from '../PanelSearchLayout'; -import { renderMatchingSoloPanels, useSoloPanelContext } from '../SoloPanelContext'; +import { useSoloPanelContext, renderMatchingSoloPanels } from '../SoloPanelContext'; import { getIsLazy } from '../layouts-shared/utils'; +import { AUTO_GRID_ITEM_DROP_TARGET_ATTR } from '../types/DashboardDropTarget'; import { AutoGridItem } from './AutoGridItem'; import { AutoGridLayoutManager } from './AutoGridLayoutManager'; @@ -53,7 +54,7 @@ export function AutoGridItemRenderer({ model }: SceneComponentProps diff --git a/public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridLayout.tsx b/public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridLayout.tsx index 64fae8a4a75..46b1f4830ec 100644 --- a/public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridLayout.tsx +++ b/public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridLayout.tsx @@ -4,6 +4,7 @@ import { SceneLayout, SceneObjectBase, SceneObjectState, VizPanel, SceneGridItem import { isRepeatCloneOrChildOf } from '../../utils/clone'; import { getLayoutOrchestratorFor } from '../../utils/utils'; +import { AUTO_GRID_ITEM_DROP_TARGET_ATTR } from '../types/DashboardDropTarget'; import { AutoGridItem } from './AutoGridItem'; import { AutoGridLayoutRenderer } from './AutoGridLayoutRenderer'; @@ -229,11 +230,11 @@ export class AutoGridLayout extends SceneObjectBase impleme const dropTargetGridItemKey = document .elementsFromPoint(evt.clientX, evt.clientY) ?.find((element) => { - const key = element.getAttribute('data-auto-grid-item-drop-target'); + const key = element.getAttribute(AUTO_GRID_ITEM_DROP_TARGET_ATTR); return !!key && key !== this._draggedGridItem!.state.key; }) - ?.getAttribute('data-auto-grid-item-drop-target'); + ?.getAttribute(AUTO_GRID_ITEM_DROP_TARGET_ATTR); if (dropTargetGridItemKey && dropTargetGridItemKey !== this._lastDropTargetGridItemKey) { this._onDragOverItem(dropTargetGridItemKey); diff --git a/public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridLayoutRenderer.tsx b/public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridLayoutRenderer.tsx index e4d685c074f..f5f17473e9c 100644 --- a/public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridLayoutRenderer.tsx +++ b/public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridLayoutRenderer.tsx @@ -9,6 +9,7 @@ import { useDashboardState } from '../../utils/utils'; import { useSoloPanelContext } from '../SoloPanelContext'; import { CanvasGridAddActions } from '../layouts-shared/CanvasGridAddActions'; import { dashboardCanvasAddButtonHoverStyles } from '../layouts-shared/styles'; +import { DASHBOARD_DROP_TARGET_KEY_ATTR } from '../types/DashboardDropTarget'; import { AutoGridLayout, AutoGridLayoutState } from './AutoGridLayout'; import { AutoGridLayoutManager } from './AutoGridLayoutManager'; @@ -57,7 +58,7 @@ export function AutoGridLayoutRenderer({ model }: SceneComponentProps {renderChildren()} {showCanvasActions && } diff --git a/public/app/features/dashboard-scene/scene/layout-rows/RowItemRenderer.tsx b/public/app/features/dashboard-scene/scene/layout-rows/RowItemRenderer.tsx index 027e6f69323..aaca60352e8 100644 --- a/public/app/features/dashboard-scene/scene/layout-rows/RowItemRenderer.tsx +++ b/public/app/features/dashboard-scene/scene/layout-rows/RowItemRenderer.tsx @@ -13,6 +13,7 @@ import { isRepeatCloneOrChildOf } from '../../utils/clone'; import { useDashboardState, useInterpolatedTitle } from '../../utils/utils'; import { DashboardScene } from '../DashboardScene'; import { useSoloPanelContext } from '../SoloPanelContext'; +import { DASHBOARD_DROP_TARGET_KEY_ATTR } from '../types/DashboardDropTarget'; import { isDashboardLayoutGrid } from '../types/DashboardLayoutGrid'; import { RowItem } from './RowItem'; @@ -85,7 +86,7 @@ export function RowItemRenderer({ model }: SceneComponentProps) { dragProvided.innerRef(ref); model.containerRef.current = ref; }} - data-dashboard-drop-target-key={isDashboardLayoutGrid(layout) ? model.state.key : undefined} + {...{ [DASHBOARD_DROP_TARGET_KEY_ATTR]: isDashboardLayoutGrid(layout) ? model.state.key : undefined }} className={cx( styles.wrapper, !isCollapsed && styles.wrapperNotCollapsed, diff --git a/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx b/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx index 0b74f45504d..de6b28c9365 100644 --- a/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx +++ b/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx @@ -12,6 +12,7 @@ import { isRepeatCloneOrChildOf } from '../../utils/clone'; import { useDashboardState, getLayoutOrchestratorFor } from '../../utils/utils'; import { useSoloPanelContext } from '../SoloPanelContext'; import { useClipboardState } from '../layouts-shared/useClipboardState'; +import { DASHBOARD_DROP_TARGET_KEY_ATTR } from '../types/DashboardDropTarget'; import { RowItem } from './RowItem'; import { RowItemRepeater } from './RowItemRepeater'; @@ -74,7 +75,7 @@ export function RowLayoutManagerRenderer({ model }: SceneComponentProps {rows.map((row) => ( diff --git a/public/app/features/dashboard-scene/scene/layout-tabs/TabItemRenderer.tsx b/public/app/features/dashboard-scene/scene/layout-tabs/TabItemRenderer.tsx index 1d241ec2605..9b374e5a5eb 100644 --- a/public/app/features/dashboard-scene/scene/layout-tabs/TabItemRenderer.tsx +++ b/public/app/features/dashboard-scene/scene/layout-tabs/TabItemRenderer.tsx @@ -11,6 +11,7 @@ import { useIsConditionallyHidden } from '../../conditional-rendering/hooks/useI import { isRepeatCloneOrChildOf } from '../../utils/clone'; import { useDashboardState } from '../../utils/utils'; import { useSoloPanelContext } from '../SoloPanelContext'; +import { DASHBOARD_DROP_TARGET_KEY_ATTR } from '../types/DashboardDropTarget'; import { TabItem } from './TabItem'; @@ -125,7 +126,7 @@ export function TabItemLayoutRenderer({ tab, isEditing }: TabItemLayoutRendererP return ( {isEditing && conditionalRenderingOverlay} diff --git a/public/app/features/dashboard-scene/scene/types/DashboardDropTarget.ts b/public/app/features/dashboard-scene/scene/types/DashboardDropTarget.ts index 1d97b638d5f..66d286b3161 100644 --- a/public/app/features/dashboard-scene/scene/types/DashboardDropTarget.ts +++ b/public/app/features/dashboard-scene/scene/types/DashboardDropTarget.ts @@ -1,5 +1,11 @@ import { SceneObject, SceneGridItemLike } from '@grafana/scenes'; +/** Data attribute used to identify auto grid items as drop targets */ +export const AUTO_GRID_ITEM_DROP_TARGET_ATTR = 'data-auto-grid-item-drop-target'; + +/** Data attribute used to identify dashboard layout elements as drop targets */ +export const DASHBOARD_DROP_TARGET_KEY_ATTR = 'data-dashboard-drop-target-key'; + export interface DashboardDropTarget extends SceneObject { isDashboardDropTarget: Readonly; setIsDropTarget?(isDropTarget: boolean): void;