feat: Enhance DashboardEditor with element handling and selection management

This commit is contained in:
2025-12-16 12:08:21 +05:30
parent 2f12b35951
commit 0c51c22457
6 changed files with 77 additions and 63 deletions

View File

@@ -27,15 +27,20 @@ const DashboardEditor: React.FC = () => {
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
const { const {
blocks, blocks,
selectedBlock,
setSelectedBlock,
selectedElement,
setSelectedElement,
addBlock,
setBlocks, setBlocks,
updateBlockPosition, updateBlockPosition,
updateElementPosition, updateElementPosition,
updateBlockSize, updateBlockSize,
updateElementSize, updateElementSize,
addBlock,
updateBlockStyle, updateBlockStyle,
updateBlockPositionType, updateBlockPositionType,
updateBlockZIndex, updateBlockZIndex,
addElement,
updateElementStyle, updateElementStyle,
updateElementPositionType, updateElementPositionType,
updateElementZIndex, updateElementZIndex,
@@ -50,8 +55,6 @@ const DashboardEditor: React.FC = () => {
subscribe, subscribe,
} = simulationDashBoardStore(); } = simulationDashBoardStore();
const [selectedBlock, setSelectedBlock] = useState<string | null>(null);
const [selectedElement, setSelectedElement] = useState<string | null>(null);
const [editMode, setEditMode] = useState(false); const [editMode, setEditMode] = useState(false);
const [draggingElement, setDraggingElement] = useState<string | null>(null); const [draggingElement, setDraggingElement] = useState<string | null>(null);
const [resizingElement, setResizingElement] = useState<string | null>(null); const [resizingElement, setResizingElement] = useState<string | null>(null);
@@ -87,7 +90,6 @@ const DashboardEditor: React.FC = () => {
useEffect(() => { useEffect(() => {
if (!projectId || !selectedVersion) return; if (!projectId || !selectedVersion) return;
getDashBoardBlocksApi(projectId, selectedVersion.versionId).then((data) => { getDashBoardBlocksApi(projectId, selectedVersion.versionId).then((data) => {
console.log("data: ", data);
if (data.data?.blocks) { if (data.data?.blocks) {
setBlocks(data.data.blocks); setBlocks(data.data.blocks);
} }
@@ -107,7 +109,6 @@ const DashboardEditor: React.FC = () => {
useEffect(() => { useEffect(() => {
const unsubscribe = subscribe(() => { const unsubscribe = subscribe(() => {
if (!projectId || !selectedVersion) return; if (!projectId || !selectedVersion) return;
console.log("blocks: ", blocks);
updateBackend(blocks); updateBackend(blocks);
}); });
@@ -349,13 +350,16 @@ const DashboardEditor: React.FC = () => {
<div className="block-grid-container"> <div className="block-grid-container">
<BlockGrid <BlockGrid
blocks={blocks} blocks={blocks}
handleAddElement={(blockId, type, graphType) => {
addElement(blockId, type, graphType);
}}
editMode={editMode} editMode={editMode}
selectedBlock={selectedBlock} selectedBlock={selectedBlock}
selectedElement={selectedElement} selectedElement={selectedElement}
showSwapUI={showSwapUI} showSwapUI={showSwapUI}
swapSource={swapSource} swapSource={swapSource}
calculateMinBlockSize={calculateMinBlockSize} calculateMinBlockSize={calculateMinBlockSize}
handleBlockClick={(blockId, event) => handleBlockClick(blockId, event, editMode, setSelectedBlock, setSelectedElement, setShowSwapUI)} handleBlockClick={(blockId, event) => handleBlockClick(blockId, event, editMode, setSelectedBlock, setSelectedElement, setShowSwapUI, setShowElementDropdown, showElementDropdown)}
handleElementClick={(blockId, elementId, event) => handleElementClick={(blockId, elementId, event) =>
handleElementClick(blockId, elementId, event, editMode, setSelectedElement, setSelectedBlock, setShowSwapUI, setShowElementDropdown) handleElementClick(blockId, elementId, event, editMode, setSelectedElement, setSelectedBlock, setShowSwapUI, setShowElementDropdown)
} }
@@ -369,7 +373,9 @@ const DashboardEditor: React.FC = () => {
showElementDropdown={showElementDropdown} showElementDropdown={showElementDropdown}
blockRef={blockRef} blockRef={blockRef}
/> />
{/* BlockEditor */} {/* BlockEditor */}
{selectedBlock && editMode && !selectedElement && currentBlock && ( {selectedBlock && editMode && !selectedElement && currentBlock && (
<BlockEditor <BlockEditor
blockEditorRef={blockEditorRef} blockEditorRef={blockEditorRef}
@@ -384,7 +390,7 @@ const DashboardEditor: React.FC = () => {
const block = getBlockById(blockId); const block = getBlockById(blockId);
if (!block) return; if (!block) return;
deleteDashBoardBlocksApi({ projectId: projectId!, versionId: selectedVersion!.versionId, blocks: [block] }).then((data) => { deleteDashBoardBlocksApi({ projectId: projectId!, versionId: selectedVersion!.versionId, blocks: [block] }).then((data) => {
if (data.blocks.length>0) { if (data.blocks.length > 0) {
data.blocks.forEach((updatedBlock: any) => { data.blocks.forEach((updatedBlock: any) => {
if (updatedBlock.message === "Block deleted successfully") { if (updatedBlock.message === "Block deleted successfully") {
removeBlock(updatedBlock.blockUuid); removeBlock(updatedBlock.blockUuid);
@@ -395,6 +401,7 @@ const DashboardEditor: React.FC = () => {
}} }}
/> />
)} )}
{selectedElement && editMode && selectedBlock && currentElement && ( {selectedElement && editMode && selectedBlock && currentElement && (
<ElementEditor <ElementEditor
elementEditorRef={elementEditorRef} elementEditorRef={elementEditorRef}

View File

@@ -3,10 +3,10 @@ import { Block } from "../../../../types/exportedTypes";
import ElementComponent from "../element/ElementComponent"; import ElementComponent from "../element/ElementComponent";
import { ResizeIcon } from "../../../icons/ExportToolsIcons"; import { ResizeIcon } from "../../../icons/ExportToolsIcons";
import ElementDropdown from "../element/ElementDropdown"; import ElementDropdown from "../element/ElementDropdown";
import { useSceneContext } from "../../../../modules/scene/sceneContext";
interface BlockComponentProps { interface BlockComponentProps {
block: Block; block: Block;
handleAddElement: (blockId: string, type: UIType, graphType?: GraphTypes) => void;
editMode: boolean; editMode: boolean;
selectedBlock: string | null; selectedBlock: string | null;
selectedElement: string | null; selectedElement: string | null;
@@ -28,6 +28,7 @@ interface BlockComponentProps {
const BlockComponent: React.FC<BlockComponentProps> = ({ const BlockComponent: React.FC<BlockComponentProps> = ({
block, block,
handleAddElement,
editMode, editMode,
selectedBlock, selectedBlock,
selectedElement, selectedElement,
@@ -46,9 +47,6 @@ const BlockComponent: React.FC<BlockComponentProps> = ({
blockRef, blockRef,
handleBlockDragStart, handleBlockDragStart,
}) => { }) => {
const { simulationDashBoardStore } = useSceneContext();
const { addElement } = simulationDashBoardStore();
const dropdownRef = useRef<HTMLDivElement>(null); const dropdownRef = useRef<HTMLDivElement>(null);
const minSize = calculateMinBlockSize(block); const minSize = calculateMinBlockSize(block);
@@ -97,7 +95,7 @@ const BlockComponent: React.FC<BlockComponentProps> = ({
<ElementDropdown <ElementDropdown
showElementDropdown={showElementDropdown} showElementDropdown={showElementDropdown}
addElement={(blockId, type, graphType) => addElement(blockId, type as UIType, graphType as GraphTypes)} handleAddElement={(blockId, type, graphType) => handleAddElement(blockId, type as UIType, graphType as GraphTypes)}
dropdownRef={dropdownRef} dropdownRef={dropdownRef}
/> />
</div> </div>

View File

@@ -5,6 +5,7 @@ import BlockComponent from "./BlockComponent";
// components/BlockGrid.tsx - Updated props // components/BlockGrid.tsx - Updated props
interface BlockGridProps { interface BlockGridProps {
blocks: Block[]; blocks: Block[];
handleAddElement: (blockId: string, type: UIType, graphType?: GraphTypes) => void;
editMode: boolean; editMode: boolean;
selectedBlock: string | null; selectedBlock: string | null;
selectedElement: string | null; selectedElement: string | null;
@@ -26,6 +27,7 @@ interface BlockGridProps {
const BlockGrid: React.FC<BlockGridProps> = ({ const BlockGrid: React.FC<BlockGridProps> = ({
blocks, blocks,
handleAddElement,
editMode, editMode,
selectedBlock, selectedBlock,
selectedElement, selectedElement,
@@ -52,6 +54,7 @@ const BlockGrid: React.FC<BlockGridProps> = ({
<BlockComponent <BlockComponent
key={block.blockUuid} key={block.blockUuid}
block={block} block={block}
handleAddElement={handleAddElement}
editMode={editMode} editMode={editMode}
selectedBlock={selectedBlock} selectedBlock={selectedBlock}
selectedElement={selectedElement} selectedElement={selectedElement}

View File

@@ -3,11 +3,11 @@ import React, { type RefObject } from "react";
interface ElementDropdownProps { interface ElementDropdownProps {
showElementDropdown: string | null; showElementDropdown: string | null;
// dropDownPosition: { top: number; left: number }; // dropDownPosition: { top: number; left: number };
addElement: (blockId: string, type: string, graphType?: string | undefined) => void; handleAddElement: (blockId: string, type: string, graphType?: string | undefined) => void;
dropdownRef: RefObject<HTMLDivElement>; dropdownRef: RefObject<HTMLDivElement>;
} }
const ElementDropdown: React.FC<ElementDropdownProps> = ({ showElementDropdown, addElement, dropdownRef }) => { const ElementDropdown: React.FC<ElementDropdownProps> = ({ showElementDropdown, handleAddElement, dropdownRef }) => {
if (!showElementDropdown) return null; if (!showElementDropdown) return null;
const elementTypes = [ const elementTypes = [
{ label: "Label-Value", type: "label-value" }, { label: "Label-Value", type: "label-value" },
@@ -21,12 +21,16 @@ const ElementDropdown: React.FC<ElementDropdownProps> = ({ showElementDropdown,
]; ];
return ( return (
<div <div ref={dropdownRef} className="element-dropdown">
ref={dropdownRef}
className="element-dropdown"
>
{elementTypes.map((elementType) => ( {elementTypes.map((elementType) => (
<button key={elementType.label} onClick={() => addElement(showElementDropdown, elementType.type, elementType.graphType)} className="dropdown-button"> <button
key={elementType.label}
onClick={() => {
handleAddElement(showElementDropdown, elementType.type, elementType.graphType);
console.log('showElementDropdown: ', showElementDropdown);
}}
className="dropdown-button"
>
{elementType.label} {elementType.label}
</button> </button>
))} ))}

View File

@@ -92,11 +92,7 @@ export const handleSwapTarget = (
event: React.MouseEvent, event: React.MouseEvent,
swapSource: string | null, swapSource: string | null,
selectedBlock: string | null, selectedBlock: string | null,
swapElements: ( swapElements: (blockId: string, elementId1: string, elementId2: string) => void
blockId: string,
elementId1: string,
elementId2: string,
) => void,
): void => { ): void => {
event.stopPropagation(); event.stopPropagation();
if (swapSource && swapSource !== elementId && selectedBlock) { if (swapSource && swapSource !== elementId && selectedBlock) {
@@ -110,13 +106,19 @@ export const handleBlockClick = (
editMode: boolean, editMode: boolean,
setSelectedBlock: (blockId: string | null) => void, setSelectedBlock: (blockId: string | null) => void,
setSelectedElement: (elementId: string | null) => void, setSelectedElement: (elementId: string | null) => void,
setShowSwapUI: (show: boolean) => void setShowSwapUI: (show: boolean) => void,
setShowElementDropdown: (blockId: string | null) => void,
showElementDropdown: string | null
): void => { ): void => {
event.stopPropagation(); event.stopPropagation();
if (editMode) { if (editMode) {
setSelectedBlock(blockId); setSelectedBlock(blockId);
setSelectedElement(null); setSelectedElement(null);
setShowSwapUI(false); setShowSwapUI(false);
console.log('showElementDropdown: ', showElementDropdown);
if (showElementDropdown && showElementDropdown !== blockId) {
setShowElementDropdown(blockId);
}
} }
}; };
@@ -135,6 +137,6 @@ export const handleElementClick = (
setSelectedElement(elementId); setSelectedElement(elementId);
setSelectedBlock(blockId); setSelectedBlock(blockId);
setShowSwapUI(false); setShowSwapUI(false);
setShowElementDropdown(null); // setShowElementDropdown(null);
} }
}; };

View File

@@ -6,14 +6,18 @@ import { Block, UIElement, ExtendedCSSProperties } from "../../types/exportedTyp
interface SimulationDashboardStore { interface SimulationDashboardStore {
blocks: Block[]; blocks: Block[];
selectedBlockId: string | null; selectedBlock: string | null;
selectedElementId: string | null; selectedElement: string | null;
// Subscription management // Subscription management
subscribe: (callback: () => void) => () => void; subscribe: (callback: () => void) => () => void;
_notifySubscribers: () => void; _notifySubscribers: () => void;
saveBlocks: () => void; saveBlocks: () => void;
// Selection and hover management
setSelectedBlock: (blockId: string | null) => void;
setSelectedElement: (elementId: string | null) => void;
// Block operations // Block operations
addBlock: () => void; addBlock: () => void;
removeBlock: (blockId: string) => void; removeBlock: (blockId: string) => void;
@@ -46,10 +50,6 @@ interface SimulationDashboardStore {
updateGraphTitle: (blockId: string, elementId: string, title: string) => void; updateGraphTitle: (blockId: string, elementId: string, title: string) => void;
updateGraphType: (blockId: string, elementId: string, graphType: GraphTypes) => void; updateGraphType: (blockId: string, elementId: string, graphType: GraphTypes) => void;
// Selection and hover management
setSelectedBlock: (blockId: string | null) => void;
setSelectedElement: (elementId: string | null) => void;
// Element swapping // Element swapping
swapElements: (blockId: string, elementId1: string, elementId2: string) => void; swapElements: (blockId: string, elementId1: string, elementId2: string) => void;
@@ -68,8 +68,8 @@ export const createSimulationDashboardStore = () => {
return create<SimulationDashboardStore>()( return create<SimulationDashboardStore>()(
immer((set, get) => ({ immer((set, get) => ({
blocks: [], blocks: [],
selectedBlockId: null, selectedBlock: null,
selectedElementId: null, selectedElement: null,
subscribe: (callback: () => void) => { subscribe: (callback: () => void) => {
subscribers.add(callback); subscribers.add(callback);
@@ -92,6 +92,23 @@ export const createSimulationDashboardStore = () => {
get()._notifySubscribers(); get()._notifySubscribers();
}, },
// Selection and hover management
setSelectedBlock: (blockId) => {
set((state) => {
state.selectedBlock = blockId;
// Clear element selection when selecting a block
if (blockId) {
state.selectedElement = null;
}
});
},
setSelectedElement: (elementId) => {
set((state) => {
state.selectedElement = elementId;
});
},
// Block operations // Block operations
addBlock: () => { addBlock: () => {
set((state) => { set((state) => {
@@ -120,8 +137,8 @@ export const createSimulationDashboardStore = () => {
removeBlock: (blockId) => { removeBlock: (blockId) => {
set((state) => { set((state) => {
state.blocks = state.blocks.filter((block) => block.blockUuid !== blockId); state.blocks = state.blocks.filter((block) => block.blockUuid !== blockId);
if (state.selectedBlockId === blockId) { if (state.selectedBlock === blockId) {
state.selectedBlockId = null; state.selectedBlock = null;
} }
}); });
}, },
@@ -138,8 +155,8 @@ export const createSimulationDashboardStore = () => {
clearBlocks: () => { clearBlocks: () => {
set((state) => { set((state) => {
state.blocks = []; state.blocks = [];
state.selectedBlockId = null; state.selectedBlock = null;
state.selectedElementId = null; state.selectedElement = null;
}); });
}, },
@@ -329,8 +346,8 @@ export const createSimulationDashboardStore = () => {
const block = state.blocks.find((b) => b.blockUuid === blockId); const block = state.blocks.find((b) => b.blockUuid === blockId);
if (block) { if (block) {
block.elements = block.elements.filter((el) => el.elementUuid !== elementId); block.elements = block.elements.filter((el) => el.elementUuid !== elementId);
if (state.selectedElementId === elementId) { if (state.selectedElement === elementId) {
state.selectedElementId = null; state.selectedElement = null;
} }
} }
}); });
@@ -461,23 +478,6 @@ export const createSimulationDashboardStore = () => {
}); });
}, },
// Selection and hover management
setSelectedBlock: (blockId) => {
set((state) => {
state.selectedBlockId = blockId;
// Clear element selection when selecting a block
if (blockId) {
state.selectedElementId = null;
}
});
},
setSelectedElement: (elementId) => {
set((state) => {
state.selectedElementId = elementId;
});
},
// Element swapping // Element swapping
swapElements: (blockId, elementId1, elementId2) => { swapElements: (blockId, elementId1, elementId2) => {
set((state) => { set((state) => {
@@ -509,16 +509,16 @@ export const createSimulationDashboardStore = () => {
}, },
getSelectedBlock: () => { getSelectedBlock: () => {
const { selectedBlockId, blocks } = get(); const { selectedBlock, blocks } = get();
return selectedBlockId ? blocks.find((b) => b.blockUuid === selectedBlockId) : undefined; return selectedBlock ? blocks.find((b) => b.blockUuid === selectedBlock) : undefined;
}, },
getSelectedElement: () => { getSelectedElement: () => {
const { selectedElementId, selectedBlockId, blocks } = get(); const { selectedElement, selectedBlock, blocks } = get();
if (!selectedElementId || !selectedBlockId) return undefined; if (!selectedElement || !selectedBlock) return undefined;
const block = blocks.find((b) => b.blockUuid === selectedBlockId); const block = blocks.find((b) => b.blockUuid === selectedBlock);
return block?.elements.find((el) => el.elementUuid === selectedElementId); return block?.elements.find((el) => el.elementUuid === selectedElement);
}, },
hasBlock: (blockId) => { hasBlock: (blockId) => {