# Canvas Panel - Known Issues and TODOs This document catalogs all known issues, limitations, and TODO items found in the Canvas panel codebase. ## Critical/High Priority TODOs ### Dashboard Scenes Migration **Location:** `public/app/features/canvas/runtime/scene.tsx:117` ```typescript // TODO: Will need to update this approach for dashboard scenes // migration (new dashboard edit experience) const dashboard = getDashboardSrv().getCurrent(); ``` **Impact:** The Canvas panel's editing detection relies on the legacy dashboard service. This will need updating for the new dashboard scenes architecture. ### Connection Anchor Stacking Context **Location:** `public/app/features/canvas/runtime/scene.tsx:239-242` ```typescript // TODO: This is a workaround to apply styles to the elements after the size update. // Remove this after dealing with the connection anchors stacking context issue. if (this.connections.connectionAnchorDiv) { this.connections.connectionAnchorDiv.style.display = 'none'; } ``` **Impact:** Connection anchors are hidden during size updates as a workaround. This affects UX during panel resize. ### Frame Functionality **Location:** `public/app/plugins/panel/canvas/editor/layer/TreeNavigationEditor.tsx:128` ```typescript // TODO: This functionality is currently kinda broken / no way to decouple / delete created frames at this time const onFrameSelection = () => { ``` **Impact:** Users cannot properly manage frame (group) elements. This limits the nested element feature. --- ## Medium Priority TODOs ### Rotation with Constraints **Location:** `public/app/features/canvas/runtime/element.tsx:415` ```typescript // For elements with rotation, a delta needs to be applied to account for bounding box rotation // TODO: Fix behavior for top+bottom, left+right, center, and scale constraints ``` **Impact:** Elements with rotation behave unexpectedly when using non-simple constraints. ### SVG Element Style Handling **Location:** `public/app/features/canvas/runtime/element.tsx:242, 368` ```typescript // TODO: This is a hack, we should have a better way to handle this const elementType = this.options.type; if (!SVGElements.has(elementType)) { applyStyles(this.dataStyle, this.div); } else { removeStyles(this.dataStyle, this.div); } ``` **Impact:** SVG and non-SVG elements require different style handling, leading to maintenance burden. ### Connection Vertex Cleanup **Location:** `public/app/plugins/panel/canvas/components/connections/Connections.tsx:444` ```typescript // TODO for vertex removal, clear out originals? if (deleteVertex) { currentVertices.splice(vertexIndex, 1); } ``` **Impact:** When vertices are removed, the original source/target coordinates may become stale. ### Connection Coordinate Utility **Location:** `public/app/plugins/panel/canvas/components/connections/Connections.tsx:245` ```typescript // Convert from DOM coords to connection coords // TODO: Break this out into util function and add tests ``` **Impact:** Coordinate conversion logic is duplicated and untested. ### Move Event Optimization **Location:** `public/app/features/canvas/runtime/sceneAbleManagement.ts:312, 331` ```typescript scene.moved.next(Date.now()); // TODO only on end ``` **Impact:** The `moved` event fires during resize, not just at the end, potentially causing excessive updates. --- ## Low Priority TODOs ### Element-Specific Icons **Location:** `public/app/plugins/panel/canvas/editor/layer/TreeNavigationEditor.tsx:100` ```typescript // TODO: Implement element specific icons return <></>; ``` **Impact:** Tree navigation shows generic icons instead of element-type-specific ones. ### Non-Root Navigation **Location:** `public/app/plugins/panel/canvas/editor/layer/layerEditor.tsx:69` ```typescript if (currentLayer && !currentLayer.isRoot()) { // TODO: the non-root nav option } ``` **Impact:** Navigation within nested frames is incomplete. ### Action Variables **Location:** `public/app/features/canvas/runtime/element.tsx:1047` ```typescript body={action.confirmation(/** TODO: implement actionVars */)} ``` **Impact:** Action confirmation doesn't display variable values. ### Division by Zero **Location:** `public/app/plugins/panel/canvas/utils.ts:194` ```typescript // TODO look into a better way to avoid division by zero if (x2 - x1 === 0) { x2 += 1; } ``` **Impact:** Edge case handling is simplistic; could affect connection rendering in edge cases. ### Style Parsing **Location:** `public/app/plugins/panel/canvas/utils.ts:243` ```typescript // TODO: there sould be a better way than parseFloat const width = parseFloat(style.width); ``` **Impact:** Minor - style parsing could be more robust. ### Row Index **Location:** `public/app/plugins/panel/canvas/utils.ts:325` ```typescript // @TODO revisit, currently returning last row index for field export const getRowIndex = (fieldName: string | undefined, scene: Scene) => { ``` **Impact:** Data links may use unexpected row index for fields. ### Pan Workaround **Location:** `public/app/features/canvas/runtime/sceneAbleManagement.ts:460` ```typescript // TODO: It was implemented as a workaround to unblock left click metricsValue dropdown, // but it should be replaced with a more robust solution that doesn't interfere with left click interactions. function startPanning(e: MouseEvent) { ``` **Impact:** Panning gesture conflicts with element interactions. ### Selection Clear on Zoom **Location:** `public/app/features/canvas/runtime/sceneAbleManagement.ts:541` ```typescript // TODO: clear current selection is default behaviour on zoom-in or zoom-out, // but looks like we prevented this event to trigger at some point scene.clearCurrentSelection(true); ``` **Impact:** Selection behavior during zoom may be inconsistent. --- ## Accessibility TODOs ### Reduced Motion **Locations:** - `public/app/features/canvas/elements/droneTop.tsx:184-189` - `public/app/features/canvas/elements/droneSide.tsx:125` - `public/app/features/canvas/elements/droneFront.tsx:126` ```typescript // TODO: figure out what styles to apply when prefers-reduced-motion is set // eslint-disable-next-line @grafana/no-unreduced-motion animationDirection: 'normal', ``` **Impact:** Animated elements don't respect user preference for reduced motion. --- ## Schema TODOs ### Element Config Type **Location:** `public/app/plugins/panel/canvas/panelcfg.gen.ts:100` ```typescript /** * TODO: figure out how to define this (element config(s)) */ config?: unknown; ``` **Impact:** Element configs are not properly typed in the schema, reducing type safety. ### Default Root Value **Location:** `public/app/plugins/panel/canvas/panelcfg.gen.ts:130` ```typescript /** * The root element of canvas (frame), where all canvas elements are nested * TODO: Figure out how to define a default value for this */ root: {...} ``` **Impact:** No schema-level default for root element structure. --- ## Legacy Migration TODOs ### Color String Migration **Location:** `public/app/plugins/panel/canvas/utils.ts:117` ```typescript // @TODO Remove after v10.x if (isString(c.color)) { c.color = { fixed: c.color }; } ``` **Impact:** Legacy data format still being converted at runtime. Should be removed in future version. --- ## Workarounds in Place ### Size Update Styles **Location:** `public/app/features/canvas/runtime/scene.tsx:234-238` ```typescript // TODO: This is a workaround to apply styles to the elements after the size update. // It's a good to go approach used by movable creator, but maybe we can find a better way. this.root.elements.forEach((el) => { el.applyLayoutStylesToDiv(false); }); ``` **Status:** Working workaround, but could be improved. ### Connection Type Unknown **Location:** `public/app/plugins/panel/canvas/editor/connectionEditor.tsx:27` ```typescript // TODO: Fix this unknown (maybe a dimension supplier?) onChange: (path: string, value: unknown) => { ``` **Status:** Type safety issue in connection editor. --- ## Feature Limitations ### Not Implemented 1. **Curved Connections:** Only straight-line paths supported 2. **Orthogonal Connections:** No auto-routing around elements 3. **Frame Duplication:** Cannot duplicate frame (group) elements 4. **Undo/Redo:** No history for canvas changes 5. **Copy/Paste Between Panels:** Cannot copy elements across panels 6. **Element Grouping UX:** Frame creation/deletion is limited ### Partially Implemented 1. **Nested Frames:** Feature-flagged, incomplete functionality 2. **Pan/Zoom + Selection:** Some interaction conflicts 3. **Rotation + Constraints:** Works but has edge cases ### Known Bugs 1. **Selection on Resize:** Selection may clear unexpectedly during panel resize 2. **Connection Anchors:** May display incorrectly after element rotation 3. **SVG Icon Blinking:** Fixed in #99941 but was a streaming data issue --- ## Performance Concerns ### Identified Issues 1. **Constraint Recalculation:** All elements recalculate position on resize 2. **Connection Updates:** All connections recalculate on any element move 3. **Streaming Data:** Frequent updates can cause excessive re-renders 4. **Large Element Count:** No virtualization for many elements ### Recommendations 1. Debounce resize calculations 2. Only update affected connections 3. Add element virtualization for large canvases 4. Consider caching constraint calculations --- ## Testing Gaps Based on code analysis, the following areas lack or have minimal testing: 1. Coordinate conversion functions 2. Constraint calculations with rotation 3. Connection vertex manipulation 4. Pan/zoom interactions 5. Multi-element selection operations 6. Frame/nesting operations --- ## Priority Matrix | Issue | Impact | Effort | Priority | |-------|--------|--------|----------| | Dashboard Scenes Migration | High | High | **P0** | | Frame Functionality | High | Medium | **P1** | | Rotation + Constraints | Medium | High | **P2** | | Accessibility (reduced motion) | Medium | Low | **P2** | | Connection Anchor Stacking | Low | Medium | **P3** | | Legacy Migration Cleanup | Low | Low | **P3** | | Element Icons in Tree | Low | Low | **P4** |