Merge pull request 'ui' (#57) from ui into main
Reviewed-on: http://185.100.212.76:7776/Dwinzo-Beta/Dwinzo_dev/pulls/57
This commit is contained in:
commit
8ed035b969
|
@ -88,22 +88,22 @@ const Templates = () => {
|
|||
return (
|
||||
<div className="template-list">
|
||||
{templates.map((template, index) => (
|
||||
<div key={template.id} className="template-item">
|
||||
<div
|
||||
key={template.id}
|
||||
className="template-item"
|
||||
onClick={() => handleLoadTemplate(template)}
|
||||
>
|
||||
{template?.snapshot && (
|
||||
<div className="template-image-container">
|
||||
<img
|
||||
src={template.snapshot}
|
||||
alt={`${template.name} preview`}
|
||||
className="template-image"
|
||||
onClick={() => handleLoadTemplate(template)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="template-details">
|
||||
<div
|
||||
onClick={() => handleLoadTemplate(template)}
|
||||
className="template-name"
|
||||
>
|
||||
<div className="template-name">
|
||||
{/* {`Template ${index + 1}`} */}
|
||||
<RenameInput value={`Template ${index + 1}`} />
|
||||
</div>
|
||||
|
|
|
@ -104,7 +104,7 @@ const ProgressBarWidget = ({
|
|||
|
||||
const Widgets2D = () => {
|
||||
return (
|
||||
<div className="widget2D">
|
||||
<div className="widget2D widgets-wrapper">
|
||||
<div className="chart-container">
|
||||
{chartTypes.map((type, index) => {
|
||||
const widgetTitle = `Widget ${index + 1}`;
|
||||
|
|
|
@ -12,22 +12,21 @@ const Widgets3D = () => {
|
|||
];
|
||||
const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
|
||||
|
||||
|
||||
return (
|
||||
<div className="widgets-container widget3D">
|
||||
<div className="widgets-container widgets-wrapper widget3D">
|
||||
{widgets?.map((widget, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="widget-item"
|
||||
draggable
|
||||
onDragStart={(e) => {
|
||||
let name = widget.name
|
||||
let crt = e.target
|
||||
let name = widget.name;
|
||||
let crt = e.target;
|
||||
if (crt instanceof HTMLElement) {
|
||||
const widget = crt.cloneNode(true) as HTMLElement;
|
||||
e.dataTransfer.setDragImage(widget, 0, 0)
|
||||
e.dataTransfer.effectAllowed = "move"
|
||||
e.dataTransfer.setData("text/plain", "ui-" + name)
|
||||
e.dataTransfer.setDragImage(widget, 0, 0);
|
||||
e.dataTransfer.effectAllowed = "move";
|
||||
e.dataTransfer.setData("text/plain", "ui-" + name);
|
||||
}
|
||||
}}
|
||||
onPointerDown={() => {
|
||||
|
|
|
@ -122,7 +122,6 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
// // Update the selectedZone state
|
||||
// setSelectedZone(updatedZone);
|
||||
// }
|
||||
|
||||
};
|
||||
|
||||
// Function to clean all widgets from a panel
|
||||
|
@ -170,6 +169,7 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
// Function to handle "+" button click
|
||||
const handlePlusButtonClick = async (side: Side) => {
|
||||
if (selectedZone.activeSides.includes(side)) {
|
||||
console.log("open");
|
||||
// Panel already exists: Remove widgets from that side and update activeSides
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value
|
||||
|
@ -254,7 +254,7 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
// } else {
|
||||
//
|
||||
// }
|
||||
} catch (error) { }
|
||||
} catch (error) {}
|
||||
}
|
||||
};
|
||||
return (
|
||||
|
@ -264,7 +264,8 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
<div key={side} className={`side-button-container ${side}`}>
|
||||
{/* "+" Button */}
|
||||
<button
|
||||
className={`side-button ${side}${selectedZone.activeSides.includes(side) ? " active" : ""
|
||||
className={`side-button ${side}${
|
||||
selectedZone.activeSides.includes(side) ? " active" : ""
|
||||
}`}
|
||||
onClick={() => handlePlusButtonClick(side)}
|
||||
title={
|
||||
|
@ -314,7 +315,8 @@ const AddButtons: React.FC<ButtonsProps> = ({
|
|||
|
||||
{/* Lock/Unlock Panel */}
|
||||
<div
|
||||
className={`icon ${selectedZone.lockedPanels.includes(side) ? "active" : ""
|
||||
className={`icon ${
|
||||
selectedZone.lockedPanels.includes(side) ? "active" : ""
|
||||
}`}
|
||||
title={
|
||||
selectedZone.lockedPanels.includes(side)
|
||||
|
|
|
@ -13,6 +13,10 @@ import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zone
|
|||
// Define the type for `Side`
|
||||
type Side = "top" | "bottom" | "left" | "right";
|
||||
|
||||
interface HiddenPanels {
|
||||
[zoneId: string]: Side[];
|
||||
}
|
||||
|
||||
interface DisplayZoneProps {
|
||||
zonesData: {
|
||||
[key: string]: {
|
||||
|
@ -62,12 +66,15 @@ interface DisplayZoneProps {
|
|||
}[];
|
||||
}>
|
||||
>;
|
||||
hiddenPanels: HiddenPanels; // Updated prop type
|
||||
setHiddenPanels: React.Dispatch<React.SetStateAction<HiddenPanels>>; // Updated prop type
|
||||
}
|
||||
|
||||
const DisplayZone: React.FC<DisplayZoneProps> = ({
|
||||
zonesData,
|
||||
selectedZone,
|
||||
setSelectedZone,
|
||||
hiddenPanels,
|
||||
}) => {
|
||||
// Ref for the container element
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
|
@ -155,7 +162,7 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
|||
if (selectedZone?.zoneId === zoneId) {
|
||||
return;
|
||||
}
|
||||
setSelectedChartId(null)
|
||||
setSelectedChartId(null);
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
let response = await getSelect2dZoneData(zoneId, organization);
|
||||
|
@ -191,7 +198,12 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
|||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className={`zone-wrapper ${selectedZone?.activeSides?.includes("bottom") ? "bottom" : ""}`}
|
||||
className={`zone-wrapper ${
|
||||
selectedZone?.activeSides?.includes("bottom") &&
|
||||
!hiddenPanels[selectedZone.zoneId]?.includes("bottom")
|
||||
? "bottom"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{/* Left Arrow */}
|
||||
{showLeftArrow && (
|
||||
|
@ -211,8 +223,12 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({
|
|||
{Object.keys(zonesData).map((zoneName, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`zone ${selectedZone.zoneName === zoneName ? "active" : ""}`}
|
||||
onClick={() => handleSelect2dZoneData(zonesData[zoneName]?.zoneId, zoneName)}
|
||||
className={`zone ${
|
||||
selectedZone.zoneName === zoneName ? "active" : ""
|
||||
}`}
|
||||
onClick={() =>
|
||||
handleSelect2dZoneData(zonesData[zoneName]?.zoneId, zoneName)
|
||||
}
|
||||
>
|
||||
{zoneName}
|
||||
</div>
|
||||
|
|
|
@ -95,6 +95,7 @@ export const DraggableWidget = ({
|
|||
"floating",
|
||||
"sidebar-right-wrapper",
|
||||
"card",
|
||||
"dropdown-menu",
|
||||
],
|
||||
setMenuVisible: () => setSelectedChartId(null),
|
||||
});
|
||||
|
|
|
@ -49,6 +49,7 @@ const DroppedObjects: React.FC = () => {
|
|||
const { visualizationSocket } = useSocketStore();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const zones = useDroppedObjectsStore((state) => state.zones);
|
||||
|
||||
const [openKebabId, setOpenKebabId] = useState<string | null>(null);
|
||||
const updateObjectPosition = useDroppedObjectsStore(
|
||||
(state) => state.updateObjectPosition
|
||||
|
@ -70,6 +71,7 @@ const DroppedObjects: React.FC = () => {
|
|||
vertical: "top" | "bottom";
|
||||
horizontal: "left" | "right";
|
||||
} | null>(null); // State to track active edges for distance lines
|
||||
|
||||
const [currentPosition, setCurrentPosition] = useState<{
|
||||
top: number | "auto";
|
||||
left: number | "auto";
|
||||
|
@ -143,7 +145,7 @@ const DroppedObjects: React.FC = () => {
|
|||
// if (res.message === "FloatingWidget deleted successfully") {
|
||||
// deleteObject(zoneName, id, index); // Call the deleteObject method from the store
|
||||
// }
|
||||
} catch (error) { }
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
const handlePointerDown = (event: React.PointerEvent, index: number) => {
|
||||
|
@ -519,7 +521,8 @@ const DroppedObjects: React.FC = () => {
|
|||
{zone.objects.map((obj, index) => {
|
||||
const topPosition =
|
||||
typeof obj.position.top === "number"
|
||||
? `calc(${obj.position.top}px + ${isPlaying && selectedZone.activeSides.includes("top")
|
||||
? `calc(${obj.position.top}px + ${
|
||||
isPlaying && selectedZone.activeSides.includes("top")
|
||||
? `${heightMultiplier - 55}px`
|
||||
: "0px"
|
||||
})`
|
||||
|
@ -527,7 +530,8 @@ const DroppedObjects: React.FC = () => {
|
|||
|
||||
const leftPosition =
|
||||
typeof obj.position.left === "number"
|
||||
? `calc(${obj.position.left}px + ${isPlaying && selectedZone.activeSides.includes("left")
|
||||
? `calc(${obj.position.left}px + ${
|
||||
isPlaying && selectedZone.activeSides.includes("left")
|
||||
? `${widthMultiplier - 100}px`
|
||||
: "0px"
|
||||
})`
|
||||
|
@ -535,7 +539,8 @@ const DroppedObjects: React.FC = () => {
|
|||
|
||||
const rightPosition =
|
||||
typeof obj.position.right === "number"
|
||||
? `calc(${obj.position.right}px + ${isPlaying && selectedZone.activeSides.includes("right")
|
||||
? `calc(${obj.position.right}px + ${
|
||||
isPlaying && selectedZone.activeSides.includes("right")
|
||||
? `${widthMultiplier - 100}px`
|
||||
: "0px"
|
||||
})`
|
||||
|
@ -543,7 +548,8 @@ const DroppedObjects: React.FC = () => {
|
|||
|
||||
const bottomPosition =
|
||||
typeof obj.position.bottom === "number"
|
||||
? `calc(${obj.position.bottom}px + ${isPlaying && selectedZone.activeSides.includes("bottom")
|
||||
? `calc(${obj.position.bottom}px + ${
|
||||
isPlaying && selectedZone.activeSides.includes("bottom")
|
||||
? `${heightMultiplier - 55}px`
|
||||
: "0px"
|
||||
})`
|
||||
|
@ -552,7 +558,8 @@ const DroppedObjects: React.FC = () => {
|
|||
return (
|
||||
<div
|
||||
key={`${zoneName}-${index}`}
|
||||
className={`${obj.className} ${selectedChartId?.id === obj.id && "activeChart"
|
||||
className={`${obj.className} ${
|
||||
selectedChartId?.id === obj.id && "activeChart"
|
||||
}`}
|
||||
ref={chartWidget}
|
||||
style={{
|
||||
|
@ -561,6 +568,7 @@ const DroppedObjects: React.FC = () => {
|
|||
left: leftPosition,
|
||||
right: rightPosition,
|
||||
bottom: bottomPosition,
|
||||
pointerEvents: isPlaying ? "none" : "auto",
|
||||
minHeight: `${obj.className === "warehouseThroughput" && "150px !important"} `
|
||||
}}
|
||||
onPointerDown={(event) => {
|
||||
|
|
|
@ -166,8 +166,8 @@ const Panel: React.FC<PanelProps> = ({
|
|||
|
||||
// Calculate panel capacity
|
||||
const calculatePanelCapacity = (panel: Side) => {
|
||||
const CHART_WIDTH = panelSize;
|
||||
const CHART_HEIGHT = panelSize;
|
||||
const CHART_WIDTH = panelSize - 10;
|
||||
const CHART_HEIGHT = panelSize - 10;
|
||||
|
||||
const dimensions = panelDimensions[panel];
|
||||
if (!dimensions) {
|
||||
|
|
|
@ -298,6 +298,8 @@ const RealTimeVisulization: React.FC = () => {
|
|||
zonesData={zonesData}
|
||||
selectedZone={selectedZone}
|
||||
setSelectedZone={setSelectedZone}
|
||||
hiddenPanels={hiddenPanels}
|
||||
setHiddenPanels={setHiddenPanels}
|
||||
/>
|
||||
|
||||
{!isPlaying && selectedZone?.zoneName !== "" && (
|
||||
|
|
|
@ -1,29 +1,26 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import { Line } from 'react-chartjs-2'
|
||||
import useChartStore from '../../../../store/useChartStore';
|
||||
import { useWidgetStore } from '../../../../store/useWidgetStore';
|
||||
import axios from 'axios';
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Line } from "react-chartjs-2";
|
||||
import useChartStore from "../../../../store/useChartStore";
|
||||
import { useWidgetStore } from "../../../../store/useWidgetStore";
|
||||
import axios from "axios";
|
||||
import io from "socket.io-client";
|
||||
import { WalletIcon } from '../../../icons/3dChartIcons';
|
||||
import { WalletIcon } from "../../../icons/3dChartIcons";
|
||||
|
||||
|
||||
const TotalCardComponent = ({
|
||||
object
|
||||
}: any) => {
|
||||
|
||||
const [ progress, setProgress ] = useState<any>(0)
|
||||
const TotalCardComponent = ({ object }: any) => {
|
||||
const [progress, setProgress] = useState<any>(0);
|
||||
const [measurements, setmeasurements] = useState<any>({});
|
||||
const [duration, setDuration] = useState("1h")
|
||||
const [name, setName] = useState(object.header ? object.header : '')
|
||||
const [duration, setDuration] = useState("1h");
|
||||
const [name, setName] = useState(object.header ? object.header : "");
|
||||
const email = localStorage.getItem("email") || "";
|
||||
const organization = email?.split("@")[1]?.split(".")[0]
|
||||
const organization = email?.split("@")[1]?.split(".")[0];
|
||||
const { header, flotingDuration, flotingMeasurements } = useChartStore();
|
||||
const { selectedChartId } = useWidgetStore();
|
||||
|
||||
const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL;
|
||||
|
||||
useEffect(() => {
|
||||
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return;
|
||||
if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0)
|
||||
return;
|
||||
|
||||
const socket = io(`http://${iotApiUrl}`);
|
||||
|
||||
|
@ -33,7 +30,6 @@ const TotalCardComponent = ({
|
|||
interval: 1000,
|
||||
};
|
||||
|
||||
|
||||
const startStream = () => {
|
||||
socket.emit("lastInput", inputData);
|
||||
};
|
||||
|
@ -55,23 +51,21 @@ const TotalCardComponent = ({
|
|||
};
|
||||
}, [measurements, duration, iotApiUrl]);
|
||||
|
||||
const fetchSavedInputes = async() => {
|
||||
|
||||
const fetchSavedInputes = async () => {
|
||||
if (object?.id !== "") {
|
||||
try {
|
||||
const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${object?.id}/${organization}`);
|
||||
const response = await axios.get(
|
||||
`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${object?.id}/${organization}`
|
||||
);
|
||||
if (response.status === 200) {
|
||||
setmeasurements(response.data.Data.measurements)
|
||||
setDuration(response.data.Data.duration)
|
||||
setName(response.data.header)
|
||||
setmeasurements(response.data.Data.measurements);
|
||||
setDuration(response.data.Data.duration);
|
||||
setName(response.data.header);
|
||||
} else {
|
||||
console.log("Unexpected response:", response);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("There was an error!", error);
|
||||
}
|
||||
}
|
||||
} catch (error) {}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchSavedInputes();
|
||||
|
@ -81,12 +75,11 @@ const TotalCardComponent = ({
|
|||
if (selectedChartId?.id === object?.id) {
|
||||
fetchSavedInputes();
|
||||
}
|
||||
}
|
||||
,[header, flotingDuration, flotingMeasurements])
|
||||
}, [header, flotingDuration, flotingMeasurements]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="header-wrapper" >
|
||||
<div className="header-wrapper">
|
||||
<div className="header">{name}</div>
|
||||
<div className="data-values">
|
||||
<div className="value">{progress}</div>
|
||||
|
@ -97,7 +90,7 @@ const TotalCardComponent = ({
|
|||
<WalletIcon />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default TotalCardComponent
|
||||
export default TotalCardComponent;
|
||||
|
|
|
@ -1,20 +1,31 @@
|
|||
// import html2canvas from "html2canvas";
|
||||
import html2canvas from "html2canvas";
|
||||
|
||||
export const captureVisualization = async (): Promise<string | null> => {
|
||||
const container = document.getElementById("real-time-vis-canvas");
|
||||
if (!container) return null;
|
||||
if (!container) {
|
||||
console.error("Container element not found");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// Use html2canvas to capture the container
|
||||
// const canvas = await html2canvas(container, {
|
||||
// scale: 1, // Adjust scale for higher/lower resolution
|
||||
// });
|
||||
// Hide any elements you don't want in the screenshot
|
||||
const originalVisibility = container.style.visibility;
|
||||
container.style.visibility = 'visible';
|
||||
|
||||
// // Convert the canvas to a data URL (PNG format)
|
||||
// const dataUrl = canvas.toDataURL("image/png");
|
||||
// return dataUrl;
|
||||
const canvas = await html2canvas(container, {
|
||||
scale: 2, // Higher scale for better quality
|
||||
logging: false, // Disable console logging
|
||||
useCORS: true, // Handle cross-origin images
|
||||
allowTaint: true, // Allow tainted canvas
|
||||
backgroundColor: '#ffffff', // Set white background
|
||||
removeContainer: true // Clean up temporary containers
|
||||
});
|
||||
|
||||
return null;
|
||||
// Restore original visibility
|
||||
container.style.visibility = originalVisibility;
|
||||
|
||||
// Convert to PNG with highest quality
|
||||
return canvas.toDataURL('image/png', 1.0);
|
||||
} catch (error) {
|
||||
console.error("Error capturing visualization:", error);
|
||||
return null;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import { saveTemplateApi } from "../../services/realTimeVisulization/zoneData/saveTempleteApi";
|
||||
import { useSocketStore } from "../../store/store";
|
||||
import { Template } from "../../store/useTemplateStore";
|
||||
import { captureVisualization } from "./captureVisualization";
|
||||
|
||||
|
@ -28,7 +26,7 @@ export const handleSaveTemplate = async ({
|
|||
templates = [],
|
||||
visualizationSocket,
|
||||
}: HandleSaveTemplateProps): Promise<void> => {
|
||||
console.log('floatingWidget: ', floatingWidget);
|
||||
console.log("floatingWidget: ", floatingWidget);
|
||||
try {
|
||||
// Check if the selected zone has any widgets
|
||||
if (!selectedZone.panelOrder || selectedZone.panelOrder.length === 0) {
|
||||
|
@ -49,12 +47,12 @@ export const handleSaveTemplate = async ({
|
|||
}
|
||||
|
||||
// Capture visualization snapshot
|
||||
// const snapshot = await captureVisualization();
|
||||
const snapshot = null;
|
||||
const snapshot = await captureVisualization();
|
||||
|
||||
if (!snapshot) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if (!snapshot) {
|
||||
// return;
|
||||
// }
|
||||
// Create a new template
|
||||
const newTemplate: Template = {
|
||||
id: generateUniqueId(),
|
||||
|
|
|
@ -59,6 +59,7 @@ input {
|
|||
.toggle-header-container {
|
||||
@include flex-center;
|
||||
padding: 6px 12px;
|
||||
margin: 6px 0;
|
||||
|
||||
.toggle-header-item {
|
||||
width: 100%;
|
||||
|
@ -567,6 +568,7 @@ input {
|
|||
.input-value {
|
||||
width: 42px;
|
||||
text-align: center;
|
||||
|
||||
&::-webkit-inner-spin-button,
|
||||
&::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
|
|
|
@ -66,9 +66,9 @@
|
|||
.sidebar-left-content-container {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
// flex: 1;
|
||||
height: calc(100% - 36px);
|
||||
// height: calc(100% - 36px);
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
// overflow: auto;
|
||||
|
||||
.template-list {
|
||||
display: flex;
|
||||
|
@ -131,8 +131,12 @@
|
|||
}
|
||||
|
||||
.widget-left-sideBar {
|
||||
.widgets-wrapper {
|
||||
|
||||
min-height: 50vh;
|
||||
max-height: 60vh;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.widget2D {
|
||||
overflow: auto;
|
||||
|
|
|
@ -365,7 +365,7 @@
|
|||
|
||||
.panel.hidePanel {
|
||||
pointer-events: none;
|
||||
opacity: 0.1;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue