Merge remote-tracking branch 'origin/ui' into simulation

This commit is contained in:
2025-04-07 18:20:27 +05:30
10 changed files with 399 additions and 177 deletions

View File

@@ -42,16 +42,19 @@ const Design = () => {
const [elementColor, setElementColor] = useState("#6f42c1"); const [elementColor, setElementColor] = useState("#6f42c1");
const [showColorPicker, setShowColorPicker] = useState(false); const [showColorPicker, setShowColorPicker] = useState(false);
const [chartElements, setChartElements] = useState<ChartElement[]>([]); const [chartElements, setChartElements] = useState<ChartElement[]>([]);
const [selectedElementToStyle, setSelectedElementToStyle] = useState<string | null>(null); const [selectedElementToStyle, setSelectedElementToStyle] = useState<
string | null
>(null);
const [nameInput, setNameInput] = useState(""); const [nameInput, setNameInput] = useState("");
const chartRef = useRef<HTMLDivElement>(null); const chartRef = useRef<HTMLDivElement>(null);
const { selectedChartId, setSelectedChartId, widgets, setWidgets } = useWidgetStore(); const { selectedChartId, setSelectedChartId, widgets, setWidgets } =
useWidgetStore();
// Initialize name input and extract elements when selectedChartId changes // Initialize name input and extract elements when selectedChartId changes
useEffect(() => { useEffect(() => {
setNameInput(selectedChartId?.header || selectedChartId?.title || ""); setNameInput(selectedChartId?.header || selectedChartId?.title || "");
if (!chartRef.current) return; if (!chartRef.current) return;
const timer = setTimeout(() => { const timer = setTimeout(() => {
@@ -65,13 +68,16 @@ const Design = () => {
}) })
.map((el, index) => { .map((el, index) => {
const tagName = el.tagName.toLowerCase(); const tagName = el.tagName.toLowerCase();
const className = typeof el.className === "string" ? el.className : ""; const className =
typeof el.className === "string" ? el.className : "";
const textContent = el.textContent?.trim() || ""; const textContent = el.textContent?.trim() || "";
let selector = tagName; let selector = tagName;
if (className && typeof className === "string") { if (className && typeof className === "string") {
const classList = className.split(/\s+/).filter((c) => c.length > 0); const classList = className
.split(/\s+/)
.filter((c) => c.length > 0);
if (classList.length > 0) { if (classList.length > 0) {
selector += "." + classList.join("."); selector += "." + classList.join(".");
} }
@@ -126,7 +132,13 @@ const Design = () => {
useEffect(() => { useEffect(() => {
applyStyles(); applyStyles();
}, [selectedFont, selectedSize, selectedWeight, elementColor, selectedElementToStyle]); }, [
selectedFont,
selectedSize,
selectedWeight,
elementColor,
selectedElementToStyle,
]);
const handleUpdateWidget = (updatedProperties: Partial<Widget>) => { const handleUpdateWidget = (updatedProperties: Partial<Widget>) => {
if (!selectedChartId) return; if (!selectedChartId) return;
@@ -138,7 +150,9 @@ const Design = () => {
setSelectedChartId(updatedChartId); setSelectedChartId(updatedChartId);
const updatedWidgets = widgets.map((widget) => const updatedWidgets = widgets.map((widget) =>
widget.id === selectedChartId.id ? { ...widget, ...updatedProperties } : widget widget.id === selectedChartId.id
? { ...widget, ...updatedProperties }
: widget
); );
setWidgets(updatedWidgets); setWidgets(updatedWidgets);
}; };
@@ -146,7 +160,7 @@ const Design = () => {
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newName = e.target.value; const newName = e.target.value;
setNameInput(newName); setNameInput(newName);
if (selectedChartId?.title) { if (selectedChartId?.title) {
handleUpdateWidget({ title: newName }); handleUpdateWidget({ title: newName });
} else if (selectedChartId?.header) { } else if (selectedChartId?.header) {
@@ -155,12 +169,12 @@ const Design = () => {
}; };
const defaultChartData = { const defaultChartData = {
labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"], labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [ datasets: [
{ {
data: [65, 59, 80, 81, 56, 55, 40], data: [65, 59, 80, 81, 56, 55, 40],
backgroundColor: elementColor, backgroundColor: "#6f42c1",
borderColor: "#ffffff", borderColor: "#b392f0",
borderWidth: 1, borderWidth: 1,
}, },
], ],
@@ -311,4 +325,4 @@ const Design = () => {
); );
}; };
export default Design; export default Design;

View File

@@ -59,7 +59,6 @@ const AddButtons: React.FC<ButtonsProps> = ({
setHiddenPanels, setHiddenPanels,
hiddenPanels, hiddenPanels,
}) => { }) => {
const { visualizationSocket } = useSocketStore(); const { visualizationSocket } = useSocketStore();
// Local state to track hidden panels // Local state to track hidden panels
@@ -132,25 +131,27 @@ const AddButtons: React.FC<ButtonsProps> = ({
let deletePanel = { let deletePanel = {
organization: organization, organization: organization,
panelName: side, panelName: side,
zoneId: selectedZone.zoneId zoneId: selectedZone.zoneId,
} };
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-panel:delete", deletePanel) visualizationSocket.emit("v2:viz-panel:delete", deletePanel);
} }
setSelectedZone(updatedZone); setSelectedZone(updatedZone);
// API call to delete the panel // API call to delete the panel
// try { // try {
// const response = await deletePanelApi(selectedZone.zoneId, side, organization); // const response = await deletePanelApi(selectedZone.zoneId, side, organization);
// //
// if (response.message === "Panel deleted successfully") { // if (response.message === "Panel deleted successfully") {
// } else { // } else {
// //
// } // }
// } catch (error) { // } catch (error) {
// //
// } // }
} else { } else {
setHiddenPanels(hiddenPanels.filter((panel) => panel !== side));
// Panel does not exist: Create panel // Panel does not exist: Create panel
try { try {
// Get email and organization safely with a default fallback // Get email and organization safely with a default fallback
@@ -170,27 +171,24 @@ const AddButtons: React.FC<ButtonsProps> = ({
let addPanel = { let addPanel = {
organization: organization, organization: organization,
zoneId: selectedZone.zoneId, zoneId: selectedZone.zoneId,
panelOrder: newActiveSides panelOrder: newActiveSides,
} };
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-panel:add", addPanel) visualizationSocket.emit("v2:viz-panel:add", addPanel);
} }
setSelectedZone(updatedZone); setSelectedZone(updatedZone);
// API call to create panels // API call to create panels
// const response = await panelData(organization, selectedZone.zoneId, newActiveSides); // const response = await panelData(organization, selectedZone.zoneId, newActiveSides);
// //
// if (response.message === "Panels created successfully") { // if (response.message === "Panels created successfully") {
// } else { // } else {
// //
// } // }
} catch (error) { } catch (error) {}
}
} }
}; };
return ( return (
<> <>
<div> <div>
@@ -198,8 +196,9 @@ const AddButtons: React.FC<ButtonsProps> = ({
<div key={side} className={`side-button-container ${side}`}> <div key={side} className={`side-button-container ${side}`}>
{/* "+" Button */} {/* "+" Button */}
<button <button
className={`side-button ${side}${selectedZone.activeSides.includes(side) ? " active" : "" className={`side-button ${side}${
}`} selectedZone.activeSides.includes(side) ? " active" : ""
}`}
onClick={() => handlePlusButtonClick(side)} onClick={() => handlePlusButtonClick(side)}
title={ title={
selectedZone.activeSides.includes(side) selectedZone.activeSides.includes(side)
@@ -217,15 +216,20 @@ const AddButtons: React.FC<ButtonsProps> = ({
<div className="extra-Bs"> <div className="extra-Bs">
{/* Hide Panel */} {/* Hide Panel */}
<div <div
className={`icon ${hiddenPanels.includes(side) ? "active" : "" className={`icon ${
}`} hiddenPanels.includes(side) ? "active" : ""
}`}
title={ title={
hiddenPanels.includes(side) ? "Show Panel" : "Hide Panel" hiddenPanels.includes(side) ? "Show Panel" : "Hide Panel"
} }
onClick={() => toggleVisibility(side)} onClick={() => toggleVisibility(side)}
> >
<EyeIcon <EyeIcon
fill={hiddenPanels.includes(side) ? "var(--primary-color)" : "var(--text-color)"} fill={
hiddenPanels.includes(side)
? "var(--primary-color)"
: "var(--text-color)"
}
/> />
</div> </div>
@@ -240,8 +244,9 @@ const AddButtons: React.FC<ButtonsProps> = ({
{/* Lock/Unlock Panel */} {/* Lock/Unlock Panel */}
<div <div
className={`icon ${selectedZone.lockedPanels.includes(side) ? "active" : "" className={`icon ${
}`} selectedZone.lockedPanels.includes(side) ? "active" : ""
}`}
title={ title={
selectedZone.lockedPanels.includes(side) selectedZone.lockedPanels.includes(side)
? "Unlock Panel" ? "Unlock Panel"

View File

@@ -96,16 +96,16 @@ export const DraggableWidget = ({
let deleteWidget = { let deleteWidget = {
zoneId: selectedZone.zoneId, zoneId: selectedZone.zoneId,
widgetID: widget.id, widgetID: widget.id,
organization: organization organization: organization,
} };
console.log('deleteWidget: ', deleteWidget); console.log("deleteWidget: ", deleteWidget);
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-widget:delete", deleteWidget) visualizationSocket.emit("v2:viz-widget:delete", deleteWidget);
} }
const updatedWidgets = selectedZone.widgets.filter( const updatedWidgets = selectedZone.widgets.filter(
(w: Widget) => w.id !== widget.id (w: Widget) => w.id !== widget.id
); );
console.log('updatedWidgets: ', updatedWidgets); console.log("updatedWidgets: ", updatedWidgets);
setSelectedZone((prevZone: any) => ({ setSelectedZone((prevZone: any) => ({
...prevZone, ...prevZone,
widgets: updatedWidgets, widgets: updatedWidgets,
@@ -168,10 +168,10 @@ export const DraggableWidget = ({
let duplicateWidget = { let duplicateWidget = {
organization: organization, organization: organization,
zoneId: selectedZone.zoneId, zoneId: selectedZone.zoneId,
widget: duplicatedWidget widget: duplicatedWidget,
} };
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-widget:add", duplicateWidget) visualizationSocket.emit("v2:viz-widget:add", duplicateWidget);
} }
setSelectedZone((prevZone: any) => ({ setSelectedZone((prevZone: any) => ({
...prevZone, ...prevZone,
@@ -245,21 +245,89 @@ export const DraggableWidget = ({
// }); // });
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const [canvasDimensions, setCanvasDimensions] = useState({
width: 0,
height: 0,
});
// Track canvas dimensions
useEffect(() => {
const canvas = document.getElementById("real-time-vis-canvas");
if (!canvas) return;
const updateCanvasDimensions = () => {
const rect = canvas.getBoundingClientRect();
setCanvasDimensions({
width: rect.width,
height: rect.height,
});
};
// Initial measurement
updateCanvasDimensions();
// Set up ResizeObserver to track changes
const resizeObserver = new ResizeObserver(updateCanvasDimensions);
resizeObserver.observe(canvas);
return () => {
resizeObserver.unobserve(canvas);
};
}, []);
useEffect(() => {
const canvas = document.getElementById("real-time-vis-canvas");
if (!canvas) return;
const updateCanvasDimensions = () => {
const rect = canvas.getBoundingClientRect();
setCanvasDimensions({
width: rect.width,
height: rect.height,
});
};
// Initial measurement
updateCanvasDimensions();
// Set up ResizeObserver to track changes
const resizeObserver = new ResizeObserver(updateCanvasDimensions);
resizeObserver.observe(canvas);
return () => {
resizeObserver.unobserve(canvas);
};
}, []);
console.log("selectedChartId: ", widget);
return ( return (
<> <>
<style>
{`
:root {
--realTimeViz-container-width: ${canvasDimensions.width * 0.25}px;
--realTimeViz-container-height: ${canvasDimensions.height}px;
}
`}
</style>
<div <div
draggable draggable
key={widget.id} key={widget.id}
className={`chart-container ${(selectedChartId?.id === widget.id) && !isPlaying && "activeChart" className={`chart-container ${
}`} selectedChartId?.id === widget.id && !isPlaying && "activeChart"
}`}
onPointerDown={handlePointerDown} onPointerDown={handlePointerDown}
onDragStart={handleDragStart} onDragStart={handleDragStart}
onDragEnter={handleDragEnter} onDragEnter={handleDragEnter}
onDragOver={handleDragOver} onDragOver={handleDragOver}
onDrop={handleDrop} onDrop={handleDrop}
style={{ style={{
pointerEvents: isPanelHidden ? "none" : "auto", // Apply styles based on panel position
width: ["top", "bottom"].includes(widget.panel)
? `calc(${canvasDimensions.width * 0.16}px - 2px)` // For top/bottom panels, set width
: undefined, // Don't set width if it's left or right
height: ["left", "right"].includes(widget.panel)
? `calc(${canvasDimensions.height * 0.25}px - 2px)` // For left/right panels, set height
: undefined, // Don't set height if it's top or bottom
}} }}
ref={chartWidget} ref={chartWidget}
onClick={() => setSelectedChartId(widget)} onClick={() => setSelectedChartId(widget)}
@@ -273,8 +341,9 @@ export const DraggableWidget = ({
{openKebabId === widget.id && ( {openKebabId === widget.id && (
<div className="kebab-options" ref={widgetRef}> <div className="kebab-options" ref={widgetRef}>
<div <div
className={`edit btn ${isPanelFull(widget.panel) ? "btn-blur" : "" className={`edit btn ${
}`} isPanelFull(widget.panel) ? "btn-blur" : ""
}`}
onClick={isPanelFull(widget.panel) ? undefined : duplicateWidget} onClick={isPanelFull(widget.panel) ? undefined : duplicateWidget}
> >
<div className="icon"> <div className="icon">
@@ -348,3 +417,5 @@ export const DraggableWidget = ({
</> </>
); );
}; };
// in style if widget .panel is top or bottom set width if left or right set height

View File

@@ -65,6 +65,7 @@ const DroppedObjects: React.FC = () => {
); );
const [offset, setOffset] = useState<[number, number] | null>(null); const [offset, setOffset] = useState<[number, number] | null>(null);
const { selectedChartId, setSelectedChartId } = useWidgetStore(); const { selectedChartId, setSelectedChartId } = useWidgetStore();
const [activeEdges, setActiveEdges] = useState<{ const [activeEdges, setActiveEdges] = useState<{
vertical: "top" | "bottom"; vertical: "top" | "bottom";
horizontal: "left" | "right"; horizontal: "left" | "right";
@@ -84,7 +85,6 @@ const DroppedObjects: React.FC = () => {
// }); // });
const kebabRef = useRef<HTMLDivElement>(null); const kebabRef = useRef<HTMLDivElement>(null);
// Clean up animation frame on unmount // Clean up animation frame on unmount
useEffect(() => { useEffect(() => {
return () => { return () => {
@@ -95,7 +95,10 @@ const DroppedObjects: React.FC = () => {
}, []); }, []);
useEffect(() => { useEffect(() => {
const handleClickOutside = (event: MouseEvent) => { const handleClickOutside = (event: MouseEvent) => {
if (kebabRef.current && !kebabRef.current.contains(event.target as Node)) { if (
kebabRef.current &&
!kebabRef.current.contains(event.target as Node)
) {
setOpenKebabId(null); setOpenKebabId(null);
} }
}; };
@@ -113,7 +116,6 @@ const DroppedObjects: React.FC = () => {
if (zoneEntries.length === 0) return null; if (zoneEntries.length === 0) return null;
const [zoneName, zone] = zoneEntries[0]; const [zoneName, zone] = zoneEntries[0];
function handleDuplicate(zoneName: string, index: number) { function handleDuplicate(zoneName: string, index: number) {
setOpenKebabId(null); setOpenKebabId(null);
duplicateObject(zoneName, index); // Call the duplicateObject method from the store duplicateObject(zoneName, index); // Call the duplicateObject method from the store
@@ -132,7 +134,7 @@ const DroppedObjects: React.FC = () => {
} }
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-float:delete", deleteFloatingWidget) visualizationSocket.emit("v2:viz-float:delete", deleteFloatingWidget);
} }
deleteObject(zoneName, id); deleteObject(zoneName, id);
@@ -148,7 +150,10 @@ const DroppedObjects: React.FC = () => {
} }
const handlePointerDown = (event: React.PointerEvent, index: number) => { const handlePointerDown = (event: React.PointerEvent, index: number) => {
if ((event.target as HTMLElement).closest(".kebab-options") || (event.target as HTMLElement).closest(".kebab")) { if (
(event.target as HTMLElement).closest(".kebab-options") ||
(event.target as HTMLElement).closest(".kebab")
) {
return; // Prevent dragging when clicking on the kebab menu or its options return; // Prevent dragging when clicking on the kebab menu or its options
} }
const obj = zone.objects[index]; const obj = zone.objects[index];
@@ -449,7 +454,6 @@ const DroppedObjects: React.FC = () => {
// position: boundedPosition, // position: boundedPosition,
// }); // });
let updateFloatingWidget = { let updateFloatingWidget = {
organization: organization, organization: organization,
widget: { widget: {
@@ -460,7 +464,7 @@ const DroppedObjects: React.FC = () => {
zoneId: zone.zoneId zoneId: zone.zoneId
} }
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-float:add", updateFloatingWidget) visualizationSocket.emit("v2:viz-float:add", updateFloatingWidget);
} }
// if (response.message === "Widget updated successfully") { // if (response.message === "Widget updated successfully") {
@@ -479,7 +483,6 @@ const DroppedObjects: React.FC = () => {
// animationRef.current = null; // animationRef.current = null;
// } // }
} catch (error) { } catch (error) {
} finally { } finally {
// Clean up regardless of success or failure // Clean up regardless of success or failure
setDraggingIndex(null); setDraggingIndex(null);
@@ -565,26 +568,32 @@ const DroppedObjects: React.FC = () => {
ref={kebabRef} ref={kebabRef}
onClick={(event) => { onClick={(event) => {
event.stopPropagation(); event.stopPropagation();
handleKebabClick(obj.id, event) handleKebabClick(obj.id, event);
}} }}
> >
<KebabIcon /> <KebabIcon />
</div> </div>
{openKebabId === obj.id && ( {openKebabId === obj.id && (
<div className="kebab-options" ref={kebabRef}> <div className="kebab-options" ref={kebabRef}>
<div className="dublicate btn" onClick={(event) => { <div
event.stopPropagation(); className="dublicate btn"
handleDuplicate(zoneName, index); // Call the duplicate handler onClick={(event) => {
}}> event.stopPropagation();
handleDuplicate(zoneName, index); // Call the duplicate handler
}}
>
<div className="icon"> <div className="icon">
<DublicateIcon /> <DublicateIcon />
</div> </div>
<div className="label">Duplicate</div> <div className="label">Duplicate</div>
</div> </div>
<div className="edit btn" onClick={(event) => { <div
event.stopPropagation(); className="edit btn"
handleDelete(zoneName, obj.id); // Call the delete handler onClick={(event) => {
}}> event.stopPropagation();
handleDelete(zoneName, obj.id); // Call the delete handler
}}
>
<div className="icon"> <div className="icon">
<DeleteIcon /> <DeleteIcon />
</div> </div>
@@ -592,7 +601,6 @@ const DroppedObjects: React.FC = () => {
</div> </div>
</div> </div>
)} )}
</div> </div>
))} ))}
@@ -630,5 +638,3 @@ const DroppedObjects: React.FC = () => {
}; };
export default DroppedObjects; export default DroppedObjects;

View File

@@ -63,6 +63,59 @@ const Panel: React.FC<PanelProps> = ({
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const { visualizationSocket } = useSocketStore(); const { visualizationSocket } = useSocketStore();
const [canvasDimensions, setCanvasDimensions] = useState({
width: 0,
height: 0,
});
// Track canvas dimensions
useEffect(() => {
const canvas = document.getElementById("real-time-vis-canvas");
if (!canvas) return;
const updateCanvasDimensions = () => {
const rect = canvas.getBoundingClientRect();
setCanvasDimensions({
width: rect.width,
height: rect.height,
});
};
// Initial measurement
updateCanvasDimensions();
// Set up ResizeObserver to track changes
const resizeObserver = new ResizeObserver(updateCanvasDimensions);
resizeObserver.observe(canvas);
return () => {
resizeObserver.unobserve(canvas);
};
}, []);
useEffect(() => {
const canvas = document.getElementById("real-time-vis-canvas");
if (!canvas) return;
const updateCanvasDimensions = () => {
const rect = canvas.getBoundingClientRect();
setCanvasDimensions({
width: rect.width,
height: rect.height,
});
};
// Initial measurement
updateCanvasDimensions();
// Set up ResizeObserver to track changes
const resizeObserver = new ResizeObserver(updateCanvasDimensions);
resizeObserver.observe(canvas);
return () => {
resizeObserver.unobserve(canvas);
};
}, []);
const getPanelStyle = useMemo( const getPanelStyle = useMemo(
() => (side: Side) => { () => (side: Side) => {
const currentIndex = selectedZone.panelOrder.indexOf(side); const currentIndex = selectedZone.panelOrder.indexOf(side);
@@ -71,36 +124,52 @@ const Panel: React.FC<PanelProps> = ({
const rightActive = previousPanels.includes("right"); const rightActive = previousPanels.includes("right");
const topActive = previousPanels.includes("top"); const topActive = previousPanels.includes("top");
const bottomActive = previousPanels.includes("bottom"); const bottomActive = previousPanels.includes("bottom");
const panelSize = isPlaying ? 300 : 210;
// Dynamic panel sizes based on canvas width
const panelSizeWidth = Math.max(canvasDimensions.width * 0.165, 200); // Ensure minimum width of 200px
const panelSizeHeight = Math.max(canvasDimensions.width * 0.13, 200); // Ensure minimum height of 200px
switch (side) { switch (side) {
case "top": case "top":
case "bottom": case "bottom":
return { return {
// minWidth: "200px", // Minimum width constraint
width: `calc(100% - ${ width: `calc(100% - ${
(leftActive ? panelSize : 0) + (rightActive ? panelSize : 0) (leftActive ? panelSizeWidth : 0) +
(rightActive ? panelSizeWidth : 0)
}px)`, }px)`,
height: `${panelSize - 2}px`, minHeight: "200px", // Minimum height constraint
left: leftActive ? `${panelSize}px` : "0", height: `${panelSizeHeight - 2}px`, // Subtracting for border or margin
right: rightActive ? `${panelSize}px` : "0", left: leftActive ? `${panelSizeWidth}px` : "0",
right: rightActive ? `${panelSizeWidth}px` : "0",
[side]: "0", [side]: "0",
}; };
case "left": case "left":
case "right": case "right":
return { return {
width: `${panelSize - 2}px`, minWidth: "200px", // Minimum width constraint
width: `${panelSizeWidth - 2}px`, // Subtracting for border or margin
// minHeight: "200px", // Minimum height constraint
height: `calc(100% - ${ height: `calc(100% - ${
(topActive ? panelSize : 0) + (bottomActive ? panelSize : 0) (topActive ? panelSizeHeight : 0) +
(bottomActive ? panelSizeHeight : 0)
}px)`, }px)`,
top: topActive ? `${panelSize}px` : "0", top: topActive ? `${panelSizeHeight}px` : "0",
bottom: bottomActive ? `${panelSize}px` : "0", bottom: bottomActive ? `${panelSizeHeight}px` : "0",
[side]: "0", [side]: "0",
}; };
default: default:
return {}; return {};
} }
}, },
[selectedZone.panelOrder, isPlaying] [
selectedZone.panelOrder,
isPlaying,
canvasDimensions.width,
canvasDimensions.height,
]
); );
const handleDrop = (e: React.DragEvent, panel: Side) => { const handleDrop = (e: React.DragEvent, panel: Side) => {
@@ -152,10 +221,10 @@ const Panel: React.FC<PanelProps> = ({
let addWidget = { let addWidget = {
organization: organization, organization: organization,
zoneId: selectedZone.zoneId, zoneId: selectedZone.zoneId,
widget: newWidget widget: newWidget,
} };
if (visualizationSocket) { if (visualizationSocket) {
visualizationSocket.emit("v2:viz-widget:add", addWidget) visualizationSocket.emit("v2:viz-widget:add", addWidget);
} }
setSelectedZone((prev) => ({ setSelectedZone((prev) => ({
...prev, ...prev,
@@ -164,7 +233,6 @@ const Panel: React.FC<PanelProps> = ({
try { try {
// let response = await addingWidgets(selectedZone.zoneId, organization, newWidget); // let response = await addingWidgets(selectedZone.zoneId, organization, newWidget);
// if (response.message === "Widget created successfully") { // if (response.message === "Widget created successfully") {
// setSelectedZone((prev) => ({ // setSelectedZone((prev) => ({
// ...prev, // ...prev,
@@ -174,7 +242,6 @@ const Panel: React.FC<PanelProps> = ({
} catch (error) { } catch (error) {
console.error("Error adding widget:", error); console.error("Error adding widget:", error);
} }
}; };
useEffect(() => { useEffect(() => {
@@ -280,3 +347,5 @@ const Panel: React.FC<PanelProps> = ({
}; };
export default Panel; export default Panel;
// canvasDimensions.width as percent

View File

@@ -23,8 +23,11 @@ import RenderOverlay from "../../templates/Overlay";
import ConfirmationPopup from "../../layout/confirmationPopup/ConfirmationPopup"; import ConfirmationPopup from "../../layout/confirmationPopup/ConfirmationPopup";
import DroppedObjects from "./DroppedFloatingWidgets"; import DroppedObjects from "./DroppedFloatingWidgets";
import EditWidgetOption from "../menu/EditWidgetOption"; import EditWidgetOption from "../menu/EditWidgetOption";
import { useEditWidgetOptionsStore, useRightClickSelected, useRightSelected } from "../../../store/useZone3DWidgetStore"; import {
useEditWidgetOptionsStore,
useRightClickSelected,
useRightSelected,
} from "../../../store/useZone3DWidgetStore";
type Side = "top" | "bottom" | "left" | "right"; type Side = "top" | "bottom" | "left" | "right";
@@ -58,10 +61,10 @@ const RealTimeVisulization: React.FC = () => {
const [zonesData, setZonesData] = useState<FormattedZoneData>({}); const [zonesData, setZonesData] = useState<FormattedZoneData>({});
const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { selectedZone, setSelectedZone } = useSelectedZoneStore();
const { rightSelect, setRightSelect } = useRightSelected();
const { rightSelect, setRightSelect } = useRightSelected() const { editWidgetOptions, setEditWidgetOptions } =
const { editWidgetOptions, setEditWidgetOptions } = useEditWidgetOptionsStore() useEditWidgetOptionsStore();
const { rightClickSelected, setRightClickSelected } = useRightClickSelected() const { rightClickSelected, setRightClickSelected } = useRightClickSelected();
const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false); const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false);
const [floatingWidgets, setFloatingWidgets] = useState<Record<string, { zoneName: string; zoneId: string; objects: any[] }>>({}); const [floatingWidgets, setFloatingWidgets] = useState<Record<string, { zoneName: string; zoneId: string; objects: any[] }>>({});
@@ -96,7 +99,7 @@ const RealTimeVisulization: React.FC = () => {
{} {}
); );
setZonesData(formattedData); setZonesData(formattedData);
} catch (error) { } } catch (error) {}
} }
GetZoneData(); GetZoneData();
@@ -194,7 +197,7 @@ const RealTimeVisulization: React.FC = () => {
], ],
}, },
})); }));
} catch (error) { } } catch (error) {}
}; };
useEffect(() => { useEffect(() => {
const handleClickOutside = (event: MouseEvent) => { const handleClickOutside = (event: MouseEvent) => {
@@ -238,84 +241,90 @@ const RealTimeVisulization: React.FC = () => {
}, [setRightClickSelected]); }, [setRightClickSelected]);
return ( return (
<div <>
ref={containerRef}
id="real-time-vis-canvas"
className={`realTime-viz canvas ${isPlaying ? "playingFlase" : ""}`}
style={{
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
}}
>
{openConfirmationPopup && (
<RenderOverlay>
<ConfirmationPopup
message={"Are you sure want to delete?"}
onConfirm={() => console.log("confirm")}
onCancel={() => setOpenConfirmationPopup(false)}
/>
</RenderOverlay>
)}
<div <div
ref={containerRef}
id="real-time-vis-canvas"
className={`realTime-viz canvas ${isPlaying ? "playingFlase" : ""}`}
style={{
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
}}
>
<div className="realTime-viz-wrapper">
{openConfirmationPopup && (
<RenderOverlay>
<ConfirmationPopup
message={"Are you sure want to delete?"}
onConfirm={() => console.log("confirm")}
onCancel={() => setOpenConfirmationPopup(false)}
/>
</RenderOverlay>
)}
{/* <div
className="scene-container" className="scene-container"
style={{ style={{
height: "100%", height: "100%",
width: "100%", width: "100%",
borderRadius: borderRadius:
isPlaying || activeModule !== "visualization" ? "" : "6px", isPlaying || activeModule !== "visualization" ? "" : "6px",
}} }}
onDrop={(event) => handleDrop(event)} onDrop={(event) => handleDrop(event)}
onDragOver={(event) => event.preventDefault()} onDragOver={(event) => event.preventDefault()}
> >
<Scene /> <Scene />
</div> </div> */}
{activeModule === "visualization" && selectedZone.zoneName !== "" && ( {activeModule === "visualization" && selectedZone.zoneName !== "" && (
<DroppedObjects /> <DroppedObjects />
)}
{activeModule === "visualization" && <SocketRealTimeViz />}
{activeModule === "visualization" &&
editWidgetOptions &&
rightClickSelected && (
<EditWidgetOption
options={[
"Duplicate",
"Vertical Move",
"Horizontal Move",
"RotateX",
"RotateY",
"Delete",
]}
/>
)}
{activeModule === "visualization" && (
<>
<DisplayZone
zonesData={zonesData}
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
{!isPlaying && selectedZone?.zoneName !== "" && (
<AddButtons
hiddenPanels={hiddenPanels}
setHiddenPanels={setHiddenPanels}
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
)} )}
{activeModule === "visualization" && <SocketRealTimeViz />}
<Panel {activeModule === "visualization" &&
selectedZone={selectedZone} editWidgetOptions &&
setSelectedZone={setSelectedZone} rightClickSelected && (
hiddenPanels={hiddenPanels} <EditWidgetOption
setZonesData={setZonesData} options={[
/> "Duplicate",
</> "Vertical Move",
)} "Horizontal Move",
</div> "RotateX",
"RotateY",
"Delete",
]}
/>
)}
{activeModule === "visualization" && (
<>
<DisplayZone
zonesData={zonesData}
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
{!isPlaying && selectedZone?.zoneName !== "" && (
<AddButtons
hiddenPanels={hiddenPanels}
setHiddenPanels={setHiddenPanels}
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
/>
)}
<Panel
selectedZone={selectedZone}
setSelectedZone={setSelectedZone}
hiddenPanels={hiddenPanels}
setZonesData={setZonesData}
/>
</>
)}
</div>
</div>
</>
); );
}; };

View File

@@ -56,7 +56,7 @@ const Project: React.FC = () => {
return ( return (
<div className="project-main"> <div className="project-main">
{loadingProgress && <LoadingPage progress={loadingProgress} />} {/* {loadingProgress && <LoadingPage progress={loadingProgress} />} */}
{!isPlaying && ( {!isPlaying && (
<> <>
{toggleThreeD && <ModuleToggle />} {toggleThreeD && <ModuleToggle />}

View File

@@ -4,7 +4,7 @@
.tools-container { .tools-container {
@include flex-center; @include flex-center;
position: fixed; position: fixed;
bottom: 50px; bottom: 32px;
left: 50%; left: 50%;
transform: translate(-50%, 0); transform: translate(-50%, 0);
padding: 8px; padding: 8px;

View File

@@ -472,6 +472,15 @@
font-size: var(--font-weight-regular); font-size: var(--font-weight-regular);
color: #4a4a4a; color: #4a4a4a;
.reviewChart {
width: 100%;
.floating {
width: 100%;
}
}
.selectedWidget { .selectedWidget {
padding: 6px 12px; padding: 6px 12px;
border-top: 1px solid var(--border-color); border-top: 1px solid var(--border-color);

View File

@@ -7,7 +7,7 @@
border-radius: 20px; border-radius: 20px;
box-shadow: $box-shadow-medium; box-shadow: $box-shadow-medium;
width: calc(100% - (320px + 270px + 90px)); width: calc(100% - (320px + 270px + 90px));
height: calc(100% - (200px + 80px)); height: calc(100% - (250px));
position: absolute; position: absolute;
top: 50%; top: 50%;
left: calc(270px + 45px); left: calc(270px + 45px);
@@ -16,6 +16,13 @@
transition: all 0.2s; transition: all 0.2s;
z-index: #{$z-index-default}; z-index: #{$z-index-default};
.realTime-viz-wrapper {
width: 100%;
height: 100%;
position: relative;
z-index: -1;
}
.floating { .floating {
width: 100%; width: 100%;
max-width: 250px; max-width: 250px;
@@ -62,6 +69,7 @@
max-width: 80%; max-width: 80%;
overflow: auto; overflow: auto;
max-width: calc(100% - 500px); max-width: calc(100% - 500px);
z-index: 3;
&::-webkit-scrollbar { &::-webkit-scrollbar {
display: none; display: none;
@@ -108,7 +116,7 @@
} }
.zone-wrapper.bottom { .zone-wrapper.bottom {
bottom: 210px; bottom: calc(var(--realTimeViz-container-height) * 0.27);
} }
.content-container { .content-container {
@@ -173,12 +181,15 @@
overflow: auto; overflow: auto;
z-index: $z-index-tools; z-index: $z-index-tools;
overflow: auto; overflow: auto;
&::-webkit-scrollbar { &::-webkit-scrollbar {
display: none; display: none;
} }
.panel-content { .panel-content {
position: relative; position: relative;
height: 100%; height: 100%;
width: 100%;
padding: 10px; padding: 10px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -191,7 +202,6 @@
.chart-container { .chart-container {
width: 100%; width: 100%;
height: 25% !important;
min-height: 150px; min-height: 150px;
max-height: 100%; max-height: 100%;
// border: 1px dashed var(--background-color-gray); // border: 1px dashed var(--background-color-gray);
@@ -200,6 +210,7 @@
padding: 6px 0; padding: 6px 0;
background-color: var(--background-color); background-color: var(--background-color);
position: relative; position: relative;
padding: 0 10px;
.kebab { .kebab {
width: 30px; width: 30px;
@@ -284,15 +295,17 @@
&.bottom-panel { &.bottom-panel {
left: 0; left: 0;
right: 0; right: 0;
min-height: 150px;
.panel-content { .panel-content {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
height: 100%; height: 100%;
width: 100%;
min-height: 150px;
.chart-container { .chart-container {
height: 100% !important;
width: 20%;
min-width: 150px; min-width: 150px;
} }
} }
@@ -311,28 +324,53 @@
top: 0; top: 0;
bottom: 0; bottom: 0;
.chart-container {
width: 100%;
height: 180px;
}
} }
&.right-panel { &.right-panel {
right: 0; right: 0;
top: 0; top: 0;
bottom: 0; bottom: 0
}
&.left-panel,
&.right-panel {
min-width: 150px;
.panel-content {
flex-direction: column;
width: 100%;
gap: 6px;
.chart-container {
width: 100%;
min-height: 150px;
max-height: 100%;
// border: 1px dashed var(--background-color-gray);
border-radius: 8px;
box-shadow: var(--box-shadow-medium);
padding: 6px 0;
background-color: var(--background-color);
position: relative;
}
}
} }
} }
.panel.hidePanel { .panel.hidePanel {
opacity: 0; opacity: 0.1;
} }
} }
.playingFlase { .playingFlase {
.zone-wrapper.bottom { .zone-wrapper.bottom {
bottom: 300px; bottom: calc(var(--realTimeViz-container-height) * 0.25);
} }
} }
@@ -739,7 +777,8 @@
border-radius: 6px; border-radius: 6px;
overflow: hidden; overflow: hidden;
min-width: 150px; min-width: 150px;
.option { .option {
padding: 8px 10px; padding: 8px 10px;
color: var(--text-color); color: var(--text-color);