Merge pull request 'v2-ui' (#69) from v2-ui into main
Reviewed-on: http://185.100.212.76:7776/Dwinzo-Beta/Dwinzo_dev/pulls/69
This commit was merged in pull request #69.
This commit is contained in:
@@ -42,6 +42,7 @@ export function FlipXAxisIcon() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function FlipYAxisIcon() {
|
export function FlipYAxisIcon() {
|
||||||
|
return (
|
||||||
<svg
|
<svg
|
||||||
width="12"
|
width="12"
|
||||||
height="12"
|
height="12"
|
||||||
@@ -79,7 +80,8 @@ export function FlipYAxisIcon() {
|
|||||||
strokeWidth="0.75"
|
strokeWidth="0.75"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
/>
|
/>
|
||||||
</svg>;
|
</svg>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
export function FlipZAxisIcon() {
|
export function FlipZAxisIcon() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -168,20 +168,6 @@ export function AddIcon() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RmoveIcon() {
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
width="12"
|
|
||||||
height="12"
|
|
||||||
viewBox="0 0 12 12"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path d="M3 6.5H9" stroke="var(--text-color)" strokeLinecap="round" />
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function CloseIcon() {
|
export function CloseIcon() {
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
|
|||||||
@@ -124,7 +124,6 @@ export function LogoIconLarge() {
|
|||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
>
|
>
|
||||||
<circle cx="45" cy="45" r="45" fill="#FCFDFD" />
|
|
||||||
<circle
|
<circle
|
||||||
cx="45.1957"
|
cx="45.1957"
|
||||||
cy="45.1957"
|
cy="45.1957"
|
||||||
|
|||||||
@@ -23,16 +23,16 @@ const MarketPlaceBanner = () => {
|
|||||||
<path
|
<path
|
||||||
d="M167.189 2C154.638 36.335 104.466 106.204 4.18872 111"
|
d="M167.189 2C154.638 36.335 104.466 106.204 4.18872 111"
|
||||||
stroke="white"
|
stroke="white"
|
||||||
stroke-width="3"
|
strokeWidth="3"
|
||||||
stroke-linecap="round"
|
strokeLinecap="round"
|
||||||
stroke-linejoin="round"
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M10.662 118.326L1.59439 111.524L9.47334 103.374"
|
d="M10.662 118.326L1.59439 111.524L9.47334 103.374"
|
||||||
stroke="white"
|
stroke="white"
|
||||||
stroke-width="3"
|
strokeWidth="3"
|
||||||
stroke-linecap="round"
|
strokeLinecap="round"
|
||||||
stroke-linejoin="round"
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
import { SettingsIcon, TrashIcon } from "../../icons/ExportCommonIcons";
|
import { SettingsIcon, TrashIcon } from "../../icons/ExportCommonIcons";
|
||||||
|
|
||||||
const SidePannel: React.FC = () => {
|
const SidePannel: React.FC = () => {
|
||||||
const userName = localStorage.getItem("userName") || "Anonymous";
|
const userName = localStorage.getItem("userName") ?? "Anonymous";
|
||||||
return (
|
return (
|
||||||
<div className="side-pannel-container">
|
<div className="side-pannel-container">
|
||||||
<div className="side-pannel-header">
|
<div className="side-pannel-header">
|
||||||
|
|||||||
@@ -17,12 +17,12 @@ const ConfirmationPopup: React.FC<ConfirmationPopupProps> = ({
|
|||||||
<div className="confirmation-modal">
|
<div className="confirmation-modal">
|
||||||
<p className="message">{message}</p>
|
<p className="message">{message}</p>
|
||||||
<div className="buttton-wrapper">
|
<div className="buttton-wrapper">
|
||||||
<div className="confirmation-button" onClick={onConfirm}>
|
<button className="confirmation-button" onClick={onConfirm}>
|
||||||
OK
|
OK
|
||||||
</div>
|
</button>
|
||||||
<div className="confirmation-button" onClick={onCancel}>
|
<button className="confirmation-button" onClick={onCancel}>
|
||||||
Cancel
|
Cancel
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import Header from "./Header";
|
|||||||
import useToggleStore from "../../../store/useUIToggleStore";
|
import useToggleStore from "../../../store/useUIToggleStore";
|
||||||
import Assets from "./Assets";
|
import Assets from "./Assets";
|
||||||
import useModuleStore from "../../../store/useModuleStore";
|
import useModuleStore from "../../../store/useModuleStore";
|
||||||
import Widgets from ".//visualization/widgets/Widgets";
|
import Widgets from "./visualization/widgets/Widgets";
|
||||||
import Templates from "../../../modules//visualization/template/Templates";
|
import Templates from "../../../modules/visualization/template/Templates";
|
||||||
import Search from "../../ui/inputs/Search";
|
import Search from "../../ui/inputs/Search";
|
||||||
|
|
||||||
const SideBarLeft: React.FC = () => {
|
const SideBarLeft: React.FC = () => {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import React, { useEffect, useRef, useMemo } from "react";
|
import React, { useEffect, useRef, useMemo } from "react";
|
||||||
import { Chart } from "chart.js/auto";
|
import { Chart } from "chart.js/auto";
|
||||||
// import { useThemeStore } from "../../../../../store/useThemeStore";
|
|
||||||
|
|
||||||
// Define Props Interface
|
// Define Props Interface
|
||||||
interface ChartComponentProps {
|
interface ChartComponentProps {
|
||||||
@@ -29,7 +28,6 @@ const ChartComponent = ({
|
|||||||
data: propsData,
|
data: propsData,
|
||||||
}: ChartComponentProps) => {
|
}: ChartComponentProps) => {
|
||||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||||
// const { themeColor } = useThemeStore();
|
|
||||||
|
|
||||||
// Memoize Theme Colors to Prevent Unnecessary Recalculations
|
// Memoize Theme Colors to Prevent Unnecessary Recalculations
|
||||||
// const buttonActionColor = useMemo(
|
// const buttonActionColor = useMemo(
|
||||||
@@ -66,7 +64,7 @@ const ChartComponent = ({
|
|||||||
// Memoize Chart Font Style
|
// Memoize Chart Font Style
|
||||||
const chartFontStyle = useMemo(
|
const chartFontStyle = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
family: fontFamily || "Arial",
|
family: fontFamily ?? "Arial",
|
||||||
size: fontSizeValue,
|
size: fontSizeValue,
|
||||||
weight: fontWeightValue,
|
weight: fontWeightValue,
|
||||||
color: "#2B3344",
|
color: "#2B3344",
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { useState } from "react";
|
|
||||||
import ToggleHeader from "../../../../ui/inputs/ToggleHeader";
|
import ToggleHeader from "../../../../ui/inputs/ToggleHeader";
|
||||||
import Widgets2D from "./Widgets2D";
|
import Widgets2D from "./Widgets2D";
|
||||||
import Widgets3D from "./Widgets3D";
|
import Widgets3D from "./Widgets3D";
|
||||||
@@ -6,7 +5,6 @@ import WidgetsFloating from "./WidgetsFloating";
|
|||||||
import { useWidgetSubOption } from "../../../../../store/store";
|
import { useWidgetSubOption } from "../../../../../store/store";
|
||||||
|
|
||||||
const Widgets = () => {
|
const Widgets = () => {
|
||||||
const [activeOption, setActiveOption] = useState("2D");
|
|
||||||
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
|
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
|
||||||
|
|
||||||
const handleToggleClick = (option: string) => {
|
const handleToggleClick = (option: string) => {
|
||||||
|
|||||||
@@ -5,45 +5,14 @@ import {
|
|||||||
GlobeIcon,
|
GlobeIcon,
|
||||||
WalletIcon,
|
WalletIcon,
|
||||||
} from "../../../../icons/3dChartIcons";
|
} from "../../../../icons/3dChartIcons";
|
||||||
import SimpleCard from "../../../../../modules//visualization/widgets/floating/cards/SimpleCard";
|
import SimpleCard from "../../../../../modules/visualization/widgets/floating/cards/SimpleCard";
|
||||||
|
|
||||||
import WarehouseThroughput from "../../../../../modules//visualization/widgets/floating/cards/WarehouseThroughput";
|
import WarehouseThroughput from "../../../../../modules//visualization/widgets/floating/cards/WarehouseThroughput";
|
||||||
import ProductivityDashboard from "../../../../../modules//visualization/widgets/floating/cards/ProductivityDashboard";
|
|
||||||
import FleetEfficiency from "../../../../../modules//visualization/widgets/floating/cards/FleetEfficiency";
|
import FleetEfficiency from "../../../../../modules//visualization/widgets/floating/cards/FleetEfficiency";
|
||||||
|
|
||||||
interface Widget {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const WidgetsFloating = () => {
|
const WidgetsFloating = () => {
|
||||||
// const [widgets, setWidgets] = useState<Widget[]>([
|
|
||||||
// { id: "1", name: "Working State Widget" },
|
|
||||||
// { id: "2", name: "Floating Widget 2" },
|
|
||||||
// { id: "3", name: "Floating Widget 3" },
|
|
||||||
// { id: "4", name: "Floating Widget 4" },
|
|
||||||
// ]);
|
|
||||||
|
|
||||||
// Function to handle drag start
|
|
||||||
const handleDragStart = (
|
|
||||||
e: React.DragEvent<HTMLDivElement>,
|
|
||||||
widget: Widget
|
|
||||||
) => {
|
|
||||||
e.dataTransfer.setData("application/json", JSON.stringify(widget));
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="floatingWidgets-wrapper widgets-wrapper">
|
<div className="floatingWidgets-wrapper widgets-wrapper">
|
||||||
{/* {widgets.map((widget) => (
|
|
||||||
<div
|
|
||||||
key={widget.id}
|
|
||||||
className="floating"
|
|
||||||
draggable
|
|
||||||
onDragStart={(e) => handleDragStart(e, widget)}
|
|
||||||
>
|
|
||||||
{widget.name}
|
|
||||||
</div>
|
|
||||||
))} */}
|
|
||||||
{/* Floating 1 */}
|
{/* Floating 1 */}
|
||||||
<SimpleCard
|
<SimpleCard
|
||||||
header={"Today’s Earnings"}
|
header={"Today’s Earnings"}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect } from "react";
|
||||||
import Header from "./Header";
|
import Header from "./Header";
|
||||||
import useModuleStore, {
|
import useModuleStore, {
|
||||||
useSubModuleStore,
|
useSubModuleStore,
|
||||||
@@ -14,6 +14,10 @@ import Visualization from "./visualization/Visualization";
|
|||||||
import Analysis from "./analysis/Analysis";
|
import Analysis from "./analysis/Analysis";
|
||||||
import Simulations from "./simulation/Simulations";
|
import Simulations from "./simulation/Simulations";
|
||||||
import { useSelectedFloorItem } from "../../../store/store";
|
import { useSelectedFloorItem } from "../../../store/store";
|
||||||
|
import {
|
||||||
|
useSelectedEventData,
|
||||||
|
useSelectedEventSphere,
|
||||||
|
} from "../../../store/simulation/useSimulationStore";
|
||||||
import GlobalProperties from "./properties/GlobalProperties";
|
import GlobalProperties from "./properties/GlobalProperties";
|
||||||
import AsstePropertiies from "./properties/AssetProperties";
|
import AsstePropertiies from "./properties/AssetProperties";
|
||||||
import ZoneProperties from "./properties/ZoneProperties";
|
import ZoneProperties from "./properties/ZoneProperties";
|
||||||
@@ -24,88 +28,70 @@ const SideBarRight: React.FC = () => {
|
|||||||
const { toggleUI } = useToggleStore();
|
const { toggleUI } = useToggleStore();
|
||||||
const { subModule, setSubModule } = useSubModuleStore();
|
const { subModule, setSubModule } = useSubModuleStore();
|
||||||
const { selectedFloorItem } = useSelectedFloorItem();
|
const { selectedFloorItem } = useSelectedFloorItem();
|
||||||
|
const { selectedEventData } = useSelectedEventData();
|
||||||
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
|
|
||||||
// Reset activeList whenever activeModule changes
|
// Reset activeList whenever activeModule changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeModule !== "simulation") setSubModule("properties");
|
if (activeModule !== "simulation") setSubModule("properties");
|
||||||
if (activeModule === "simulation") setSubModule("mechanics");
|
if (activeModule === "simulation") setSubModule("simulations");
|
||||||
}, [activeModule]);
|
}, [activeModule, setSubModule]);
|
||||||
|
|
||||||
// romove late
|
useEffect(() => {
|
||||||
const dummyData = {
|
if (
|
||||||
assetType: "store",
|
activeModule !== "mechanics" &&
|
||||||
selectedPoint: {
|
selectedEventData &&
|
||||||
name: "Point A",
|
selectedEventSphere
|
||||||
uuid: "123e4567-e89b-12d3-a456-426614174000",
|
) {
|
||||||
actions: [
|
setSubModule("mechanics");
|
||||||
{
|
} else if (!selectedEventData && !selectedEventSphere) {
|
||||||
uuid: "action-1",
|
if (activeModule === "simulation") {
|
||||||
name: "Action One",
|
setSubModule("simulations");
|
||||||
},
|
}
|
||||||
{
|
}
|
||||||
uuid: "action-2",
|
}, [activeModule, selectedEventData, selectedEventSphere, setSubModule]);
|
||||||
name: "Action Two",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
uuid: "action-3",
|
|
||||||
name: "Action Three",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
selectedItem: {
|
|
||||||
item: {
|
|
||||||
uuid: "item-1",
|
|
||||||
name: "Item One",
|
|
||||||
isUsed: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setSelectedPoint: (value: string) => {
|
|
||||||
console.log(`Selected point updated to: ${value}`);
|
|
||||||
},
|
|
||||||
selectedActionSphere: "Sphere A",
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="sidebar-right-wrapper">
|
<div className="sidebar-right-wrapper">
|
||||||
<Header />
|
<Header />
|
||||||
{toggleUI && (
|
{toggleUI && (
|
||||||
<div className="sidebar-actions-container">
|
<div className="sidebar-actions-container">
|
||||||
{/* {activeModule === "builder" && ( */}
|
{activeModule !== "simulation" && (
|
||||||
<div
|
<button
|
||||||
className={`sidebar-action-list ${
|
className={`sidebar-action-list ${
|
||||||
subModule === "properties" ? "active" : ""
|
subModule === "properties" ? "active" : ""
|
||||||
}`}
|
}`}
|
||||||
onClick={() => setSubModule("properties")}
|
onClick={() => setSubModule("properties")}
|
||||||
>
|
>
|
||||||
<PropertiesIcon isActive={subModule === "properties"} />
|
<PropertiesIcon isActive={subModule === "properties"} />
|
||||||
</div>
|
</button>
|
||||||
{/* )} */}
|
)}
|
||||||
{activeModule === "simulation" && (
|
{activeModule === "simulation" && (
|
||||||
<>
|
<>
|
||||||
<div
|
<button
|
||||||
className={`sidebar-action-list ${
|
|
||||||
subModule === "mechanics" ? "active" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => setSubModule("mechanics")}
|
|
||||||
>
|
|
||||||
<MechanicsIcon isActive={subModule === "mechanics"} />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`sidebar-action-list ${
|
className={`sidebar-action-list ${
|
||||||
subModule === "simulations" ? "active" : ""
|
subModule === "simulations" ? "active" : ""
|
||||||
}`}
|
}`}
|
||||||
onClick={() => setSubModule("simulations")}
|
onClick={() => setSubModule("simulations")}
|
||||||
>
|
>
|
||||||
<SimulationIcon isActive={subModule === "simulations"} />
|
<SimulationIcon isActive={subModule === "simulations"} />
|
||||||
</div>
|
</button>
|
||||||
<div
|
<button
|
||||||
|
className={`sidebar-action-list ${
|
||||||
|
subModule === "mechanics" ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => setSubModule("mechanics")}
|
||||||
|
>
|
||||||
|
<MechanicsIcon isActive={subModule === "mechanics"} />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
className={`sidebar-action-list ${
|
className={`sidebar-action-list ${
|
||||||
subModule === "analysis" ? "active" : ""
|
subModule === "analysis" ? "active" : ""
|
||||||
}`}
|
}`}
|
||||||
onClick={() => setSubModule("analysis")}
|
onClick={() => setSubModule("analysis")}
|
||||||
>
|
>
|
||||||
<AnalysisIcon isActive={subModule === "analysis"} />
|
<AnalysisIcon isActive={subModule === "analysis"} />
|
||||||
</div>
|
</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -141,13 +127,19 @@ const SideBarRight: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{/* simulation */}
|
{/* simulation */}
|
||||||
|
|
||||||
{toggleUI && activeModule === "simulation" && (
|
{toggleUI && activeModule === "simulation" && (
|
||||||
<>
|
<>
|
||||||
|
{subModule === "simulations" && (
|
||||||
|
<div className="sidebar-right-container">
|
||||||
|
<div className="sidebar-right-content-container">
|
||||||
|
<Simulations />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{subModule === "mechanics" && (
|
{subModule === "mechanics" && (
|
||||||
<div className="sidebar-right-container">
|
<div className="sidebar-right-container">
|
||||||
<div className="sidebar-right-content-container">
|
<div className="sidebar-right-content-container">
|
||||||
<EventProperties {...dummyData} />
|
<EventProperties />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -158,16 +150,8 @@ const SideBarRight: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{subModule === "simulations" && (
|
|
||||||
<div className="sidebar-right-container">
|
|
||||||
<div className="sidebar-right-content-container">
|
|
||||||
<Simulations />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* realtime visualization */}
|
{/* realtime visualization */}
|
||||||
{toggleUI && activeModule === "visualization" && <Visualization />}
|
{toggleUI && activeModule === "visualization" && <Visualization />}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,208 +1,114 @@
|
|||||||
import React, { useRef, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import InputWithDropDown from "../../../../ui/inputs/InputWithDropDown";
|
|
||||||
import LabledDropdown from "../../../../ui/inputs/LabledDropdown";
|
|
||||||
import {
|
import {
|
||||||
AddIcon,
|
useSelectedEventData,
|
||||||
RemoveIcon,
|
useSelectedEventSphere,
|
||||||
ResizeHeightIcon,
|
useSelectedProduct,
|
||||||
} from "../../../../icons/ExportCommonIcons";
|
} from "../../../../../store/simulation/useSimulationStore";
|
||||||
import RenameInput from "../../../../ui/inputs/RenameInput";
|
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
||||||
import { handleResize } from "../../../../../functions/handleResizePannel";
|
import ConveyorMechanics from "./mechanics/conveyorMechanics";
|
||||||
import { handleActionToggle } from "./functions/handleActionToggle";
|
import VehicleMechanics from "./mechanics/vehicleMechanics";
|
||||||
import { handleDeleteAction } from "./functions/handleDeleteAction";
|
import RoboticArmMechanics from "./mechanics/roboticArmMechanics";
|
||||||
import DefaultAction from "./actions/DefaultAction";
|
import MachineMechanics from "./mechanics/machineMechanics";
|
||||||
import SpawnAction from "./actions/SpawnAction";
|
import StorageMechanics from "./mechanics/storageMechanics";
|
||||||
import SwapAction from "./actions/SwapAction";
|
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||||
import DespawnAction from "./actions/DespawnAction";
|
|
||||||
import TravelAction from "./actions/TravelAction";
|
|
||||||
import PickAndPlaceAction from "./actions/PickAndPlaceAction";
|
|
||||||
import ProcessAction from "./actions/ProcessAction";
|
|
||||||
import StorageAction from "./actions/StorageAction";
|
|
||||||
import Trigger from "./trigger/Trigger";
|
|
||||||
|
|
||||||
interface EventPropertiesProps {
|
const EventProperties: React.FC = () => {
|
||||||
assetType: string;
|
const { selectedEventData } = useSelectedEventData();
|
||||||
selectedPoint: {
|
const { getEventByModelUuid } = useProductStore();
|
||||||
name: string;
|
const { selectedProduct } = useSelectedProduct();
|
||||||
uuid: string;
|
const [currentEventData, setCurrentEventData] = useState<EventsSchema | null>(
|
||||||
actions: {
|
null
|
||||||
uuid: string;
|
);
|
||||||
name: string;
|
const [assetType, setAssetType] = useState<string | null>(null);
|
||||||
}[];
|
const { products } = useProductStore();
|
||||||
};
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
selectedItem: {
|
useEffect(() => {
|
||||||
item: {
|
const event = getCurrentEventData();
|
||||||
uuid: string;
|
setCurrentEventData(event);
|
||||||
name: string;
|
|
||||||
} | null;
|
|
||||||
};
|
|
||||||
setSelectedPoint: (value: string) => void;
|
|
||||||
selectedActionSphere: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const EventProperties: React.FC<EventPropertiesProps> = ({
|
const type = determineAssetType(event);
|
||||||
assetType,
|
setAssetType(type);
|
||||||
selectedPoint,
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
selectedItem,
|
}, [selectedEventData, selectedProduct]);
|
||||||
setSelectedPoint,
|
|
||||||
selectedActionSphere,
|
|
||||||
}) => {
|
|
||||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
const [activeOption, setActiveOption] = useState("default");
|
const getCurrentEventData = () => {
|
||||||
const [dummyactiveOption, setTypeOption] = useState("default");
|
if (!selectedEventData?.data || !selectedProduct) return null;
|
||||||
|
return (
|
||||||
|
getEventByModelUuid(
|
||||||
|
selectedProduct.productId,
|
||||||
|
selectedEventData.data.modelUuid
|
||||||
|
) ?? null
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const getAvailableActions = () => {
|
const determineAssetType = (event: EventsSchema | null) => {
|
||||||
if (assetType === "conveyor") {
|
if (!event) return null;
|
||||||
return {
|
|
||||||
defaultOption: "default",
|
switch (event.type) {
|
||||||
options: ["default", "spawn", "swap", "despawn"],
|
case "transfer":
|
||||||
};
|
return "conveyor";
|
||||||
}
|
case "vehicle":
|
||||||
if (assetType === "vehicle") {
|
return "vehicle";
|
||||||
return {
|
case "roboticArm":
|
||||||
defaultOption: "travel",
|
return "roboticArm";
|
||||||
options: ["travel"],
|
case "machine":
|
||||||
};
|
return "machine";
|
||||||
}
|
case "storageUnit":
|
||||||
if (assetType === "roboticArm") {
|
return "storageUnit";
|
||||||
return {
|
default:
|
||||||
defaultOption: "pickAndPlace",
|
return null;
|
||||||
options: ["pickAndPlace"],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (assetType === "machine") {
|
|
||||||
return {
|
|
||||||
defaultOption: "process",
|
|
||||||
options: ["process"],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (assetType === "store") {
|
|
||||||
return {
|
|
||||||
defaultOption: "store",
|
|
||||||
options: ["store", "spawn"],
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
defaultOption: "default",
|
|
||||||
options: ["default"],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="event-proprties-wrapper">
|
<div className="event-proprties-wrapper">
|
||||||
|
{currentEventData && (
|
||||||
|
<>
|
||||||
<div className="header">
|
<div className="header">
|
||||||
<div className="header-value">{selectedPoint.name}</div>
|
<div className="header-value">
|
||||||
</div>
|
{selectedEventData?.data.modelName}
|
||||||
<div className="global-props">
|
|
||||||
<div className="property-list-container">
|
|
||||||
{/* <div className="property-item">
|
|
||||||
<LabledDropdown
|
|
||||||
defaultOption={assetType}
|
|
||||||
options={[]}
|
|
||||||
onSelect={(option) => setTypeOption(option)}
|
|
||||||
/>
|
|
||||||
</div> */}
|
|
||||||
<div className="property-item">
|
|
||||||
<InputWithDropDown
|
|
||||||
label="Speed"
|
|
||||||
value="0.5"
|
|
||||||
min={0}
|
|
||||||
step={0.1}
|
|
||||||
defaultValue="0.5"
|
|
||||||
max={10}
|
|
||||||
activeOption="s"
|
|
||||||
onClick={() => {}}
|
|
||||||
onChange={(value) => console.log(value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="property-item">
|
|
||||||
<InputWithDropDown
|
|
||||||
label="Delay"
|
|
||||||
value="0.5"
|
|
||||||
min={0}
|
|
||||||
step={0.1}
|
|
||||||
defaultValue="0.5"
|
|
||||||
max={10}
|
|
||||||
activeOption="s"
|
|
||||||
onClick={() => {}}
|
|
||||||
onChange={(value) => console.log(value)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{assetType === "conveyor" && <ConveyorMechanics />}
|
||||||
|
{assetType === "vehicle" && <VehicleMechanics />}
|
||||||
|
{assetType === "roboticArm" && <RoboticArmMechanics />}
|
||||||
|
{assetType === "machine" && <MachineMechanics />}
|
||||||
|
{assetType === "storageUnit" && <StorageMechanics />}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{!currentEventData && selectedEventSphere && (
|
||||||
|
<div className="no-event-selected">
|
||||||
|
<p>
|
||||||
|
<strong>Oops!</strong> It looks like this object doesn't have an
|
||||||
|
event assigned yet. To continue, please link it to one of the
|
||||||
|
products below.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="products-list">
|
||||||
|
<p>
|
||||||
|
<strong>Here are some products you can add it to:</strong>
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
{products.map((product) => (
|
||||||
|
<li key={product.productId}>
|
||||||
|
<button>
|
||||||
|
<AddIcon />
|
||||||
|
{product.productName}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div className="actions-list-container">
|
|
||||||
<div className="actions">
|
|
||||||
<div className="header">
|
|
||||||
<div className="header-value">Actions</div>
|
|
||||||
<div className="add-button" onClick={() => {}}>
|
|
||||||
<AddIcon /> Add
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="lists-main-container"
|
|
||||||
ref={actionsContainerRef}
|
|
||||||
style={{ height: "120px" }}
|
|
||||||
>
|
|
||||||
<div className="list-container">
|
|
||||||
{selectedPoint?.actions.map((action) => (
|
|
||||||
<div
|
|
||||||
key={action.uuid}
|
|
||||||
className={`list-item ${
|
|
||||||
selectedItem.item?.uuid === action.uuid ? "active" : ""
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="value"
|
|
||||||
onClick={() => handleActionToggle(action.uuid)}
|
|
||||||
>
|
|
||||||
<RenameInput value={action.name} />
|
|
||||||
</div>
|
|
||||||
{selectedPoint?.actions.length > 1 && (
|
|
||||||
<div
|
|
||||||
className="remove-button"
|
|
||||||
onClick={() => handleDeleteAction(action.uuid)}
|
|
||||||
>
|
|
||||||
<RemoveIcon />
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{!selectedEventSphere && (
|
||||||
|
<div className="no-event-selected">
|
||||||
|
<p>
|
||||||
|
<strong>Oops!</strong> It looks like you haven't selected an event
|
||||||
|
point yet. Please select an event to view its properties.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
))}
|
)}
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="resize-icon"
|
|
||||||
id="action-resize"
|
|
||||||
onMouseDown={(e) => handleResize(e, actionsContainerRef)}
|
|
||||||
>
|
|
||||||
<ResizeHeightIcon />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="selected-actions-details">
|
|
||||||
<div className="selected-actions-header">
|
|
||||||
<RenameInput value="Action Name" />
|
|
||||||
</div>
|
|
||||||
<div className="selected-actions-list">
|
|
||||||
<LabledDropdown
|
|
||||||
defaultOption={getAvailableActions().defaultOption}
|
|
||||||
options={getAvailableActions().options}
|
|
||||||
onSelect={(option) => setActiveOption(option)}
|
|
||||||
/>
|
|
||||||
{activeOption === "default" && <DefaultAction />} {/* done */}
|
|
||||||
{activeOption === "spawn" && <SpawnAction />} {/* done */}
|
|
||||||
{activeOption === "swap" && <SwapAction />} {/* done */}
|
|
||||||
{activeOption === "despawn" && <DespawnAction />} {/* done */}
|
|
||||||
{activeOption === "travel" && <TravelAction />} {/* done */}
|
|
||||||
{activeOption === "pickAndPlace" && <PickAndPlaceAction />} {/* done */}
|
|
||||||
{activeOption === "process" && <ProcessAction />} {/* done */}
|
|
||||||
{activeOption === "store" && <StorageAction />} {/* done */}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="tirgger">
|
|
||||||
<Trigger />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import React from "react";
|
||||||
|
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||||
|
|
||||||
|
interface DelayActionProps {
|
||||||
|
value: string;
|
||||||
|
defaultValue: string;
|
||||||
|
min: number;
|
||||||
|
max: number;
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DelayAction: React.FC<DelayActionProps> = ({
|
||||||
|
value,
|
||||||
|
defaultValue,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
onChange,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<InputWithDropDown
|
||||||
|
label="Delay"
|
||||||
|
value={value}
|
||||||
|
min={min}
|
||||||
|
step={0.1}
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
max={max}
|
||||||
|
activeOption="s"
|
||||||
|
onClick={() => {}}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DelayAction;
|
||||||
@@ -1,20 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
|
||||||
|
|
||||||
const DespawnAction: React.FC = () => {
|
const DespawnAction: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<InputWithDropDown
|
|
||||||
label="Delay"
|
|
||||||
value=""
|
|
||||||
min={0}
|
|
||||||
step={0.1}
|
|
||||||
max={10}
|
|
||||||
defaultValue="0"
|
|
||||||
activeOption="s"
|
|
||||||
onClick={() => {}}
|
|
||||||
onChange={(value) => console.log(value)}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,11 +1,23 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import EyeDropInput from "../../../../../ui/inputs/EyeDropInput";
|
import EyeDropInput from "../../../../../ui/inputs/EyeDropInput";
|
||||||
|
|
||||||
const PickAndPlaceAction: React.FC = () => {
|
interface PickAndPlaceActionProps {
|
||||||
|
pickPointValue: string;
|
||||||
|
pickPointOnChange: (value: string) => void;
|
||||||
|
placePointValue: string;
|
||||||
|
placePointOnChange: (value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PickAndPlaceAction: React.FC<PickAndPlaceActionProps> = ({
|
||||||
|
pickPointValue,
|
||||||
|
pickPointOnChange,
|
||||||
|
placePointValue,
|
||||||
|
placePointOnChange,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<EyeDropInput label="Pick Point" value="na" onChange={() => {}} />
|
<EyeDropInput label="Pick Point" value={pickPointValue} onChange={pickPointOnChange} />
|
||||||
<EyeDropInput label="Unload Point" value="na" onChange={() => {}} />
|
<EyeDropInput label="Unload Point" value={placePointValue} onChange={placePointOnChange} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,21 +2,45 @@ import React from "react";
|
|||||||
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||||
import SwapAction from "./SwapAction";
|
import SwapAction from "./SwapAction";
|
||||||
|
|
||||||
const ProcessAction: React.FC = () => {
|
interface ProcessActionProps {
|
||||||
|
value: string;
|
||||||
|
min: number;
|
||||||
|
max: number;
|
||||||
|
defaultValue: string;
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
swapOptions: string[];
|
||||||
|
swapDefaultOption: string;
|
||||||
|
onSwapSelect: (value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProcessAction: React.FC<ProcessActionProps> = ({
|
||||||
|
value,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
defaultValue,
|
||||||
|
onChange,
|
||||||
|
swapOptions,
|
||||||
|
swapDefaultOption,
|
||||||
|
onSwapSelect,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
label="Process Time"
|
label="Process Time"
|
||||||
value="6"
|
value={value}
|
||||||
min={0}
|
min={min}
|
||||||
step={1}
|
step={1}
|
||||||
max={10}
|
max={max}
|
||||||
defaultValue="0"
|
defaultValue={defaultValue}
|
||||||
activeOption="s"
|
activeOption="s"
|
||||||
onClick={() => { }}
|
onClick={() => { }}
|
||||||
onChange={(value) => console.log(value)}
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
<SwapAction
|
||||||
|
options={swapOptions}
|
||||||
|
defaultOption={swapDefaultOption}
|
||||||
|
onSelect={onSwapSelect}
|
||||||
/>
|
/>
|
||||||
<SwapAction />
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,33 +1,70 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload";
|
import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload";
|
||||||
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||||
|
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||||
|
|
||||||
const SpawnAction: React.FC = () => {
|
interface SpawnActionProps {
|
||||||
|
onChangeInterval: (value: string) => void;
|
||||||
|
onChangeCount: (value: string) => void;
|
||||||
|
defaultOption: string;
|
||||||
|
options: string[];
|
||||||
|
onSelect: (option: string) => void;
|
||||||
|
intervalValue: string;
|
||||||
|
countValue: string;
|
||||||
|
intervalMin: number;
|
||||||
|
intervalMax: number;
|
||||||
|
intervalDefaultValue: string;
|
||||||
|
countMin: number;
|
||||||
|
countMax: number;
|
||||||
|
countDefaultValue: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SpawnAction: React.FC<SpawnActionProps> = ({
|
||||||
|
onChangeInterval,
|
||||||
|
onChangeCount,
|
||||||
|
defaultOption,
|
||||||
|
options,
|
||||||
|
onSelect,
|
||||||
|
intervalValue,
|
||||||
|
countValue,
|
||||||
|
intervalMin,
|
||||||
|
intervalMax,
|
||||||
|
intervalDefaultValue,
|
||||||
|
countMin,
|
||||||
|
countMax,
|
||||||
|
countDefaultValue,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
label="Spawn interval"
|
label="Spawn interval"
|
||||||
value="0"
|
value={intervalValue}
|
||||||
min={0}
|
min={intervalMin}
|
||||||
step={1}
|
step={1}
|
||||||
defaultValue="0"
|
defaultValue={intervalDefaultValue}
|
||||||
max={10}
|
max={intervalMax}
|
||||||
activeOption="s"
|
activeOption="s"
|
||||||
onClick={() => { }}
|
onClick={() => { }}
|
||||||
onChange={(value) => console.log(value)}
|
onChange={onChangeInterval}
|
||||||
/>
|
/>
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
label="Spawn count"
|
label="Spawn count"
|
||||||
value="0"
|
value={countValue}
|
||||||
min={0}
|
min={countMin}
|
||||||
step={1}
|
step={1}
|
||||||
defaultValue="0"
|
defaultValue={countDefaultValue}
|
||||||
max={10}
|
max={countMax}
|
||||||
activeOption="s"
|
activeOption="s"
|
||||||
onClick={() => { }}
|
onClick={() => { }}
|
||||||
onChange={(value) => console.log(value)}
|
onChange={onChangeCount}
|
||||||
|
/>
|
||||||
|
{/* <PreviewSelectionWithUpload /> */}
|
||||||
|
<LabledDropdown
|
||||||
|
label="Presets"
|
||||||
|
defaultOption={defaultOption}
|
||||||
|
options={options}
|
||||||
|
onSelect={onSelect}
|
||||||
/>
|
/>
|
||||||
<PreviewSelectionWithUpload />
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,18 +1,26 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||||
|
|
||||||
const StorageAction: React.FC = () => {
|
interface StorageActionProps {
|
||||||
|
value: string;
|
||||||
|
min: number;
|
||||||
|
max: number;
|
||||||
|
defaultValue: string;
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StorageAction: React.FC<StorageActionProps> = ({ value, min, max, defaultValue, onChange }) => {
|
||||||
return (
|
return (
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
label="Storage Capacity"
|
label="Storage Capacity"
|
||||||
value=""
|
value={value}
|
||||||
min={0}
|
min={min}
|
||||||
step={0.1}
|
step={1}
|
||||||
max={10}
|
max={max}
|
||||||
defaultValue="0"
|
defaultValue={defaultValue}
|
||||||
activeOption="s"
|
activeOption="s"
|
||||||
onClick={() => { }}
|
onClick={() => { }}
|
||||||
onChange={(value) => console.log(value)}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,11 +1,24 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload";
|
import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload";
|
||||||
|
|
||||||
const SwapAction: React.FC = () => {
|
interface SwapActionProps {
|
||||||
|
onSelect: (option: string) => void;
|
||||||
|
defaultOption: string;
|
||||||
|
options: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const SwapAction: React.FC<SwapActionProps> = ({
|
||||||
|
onSelect,
|
||||||
|
defaultOption,
|
||||||
|
options,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<PreviewSelectionWithUpload
|
||||||
<PreviewSelectionWithUpload />
|
label="Presets"
|
||||||
</>
|
defaultOption={defaultOption}
|
||||||
|
options={options}
|
||||||
|
onSelect={onSelect}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,33 +2,75 @@ import React from "react";
|
|||||||
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||||
import EyeDropInput from "../../../../../ui/inputs/EyeDropInput";
|
import EyeDropInput from "../../../../../ui/inputs/EyeDropInput";
|
||||||
|
|
||||||
const TravelAction: React.FC = () => {
|
interface TravelActionProps {
|
||||||
|
loadCapacity: {
|
||||||
|
value: string;
|
||||||
|
min: number;
|
||||||
|
max: number;
|
||||||
|
defaultValue: string;
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
};
|
||||||
|
unloadDuration: {
|
||||||
|
value: string;
|
||||||
|
min: number;
|
||||||
|
max: number;
|
||||||
|
defaultValue: string;
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
};
|
||||||
|
pickPoint?: {
|
||||||
|
value: string;
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
};
|
||||||
|
unloadPoint?: {
|
||||||
|
value: string;
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const TravelAction: React.FC<TravelActionProps> = ({
|
||||||
|
loadCapacity,
|
||||||
|
unloadDuration,
|
||||||
|
pickPoint,
|
||||||
|
unloadPoint,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
label="Load Capacity"
|
label="Load Capacity"
|
||||||
value=""
|
value={loadCapacity.value}
|
||||||
min={0}
|
min={loadCapacity.min}
|
||||||
|
max={loadCapacity.max}
|
||||||
|
defaultValue={loadCapacity.defaultValue}
|
||||||
step={0.1}
|
step={0.1}
|
||||||
max={10}
|
|
||||||
defaultValue="0"
|
|
||||||
activeOption="s"
|
activeOption="s"
|
||||||
onClick={() => { }}
|
onClick={() => { }}
|
||||||
onChange={(value) => console.log(value)}
|
onChange={loadCapacity.onChange}
|
||||||
/>
|
/>
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
label="Unload Duration"
|
label="Unload Duration"
|
||||||
value=""
|
value={unloadDuration.value}
|
||||||
min={0}
|
min={unloadDuration.min}
|
||||||
|
max={unloadDuration.max}
|
||||||
|
defaultValue={unloadDuration.defaultValue}
|
||||||
step={0.1}
|
step={0.1}
|
||||||
max={10}
|
|
||||||
defaultValue="0"
|
|
||||||
activeOption="s"
|
activeOption="s"
|
||||||
onClick={() => { }}
|
onClick={() => { }}
|
||||||
onChange={(value) => console.log(value)}
|
onChange={unloadDuration.onChange}
|
||||||
/>
|
/>
|
||||||
<EyeDropInput label="Pick Point" value="na" onChange={() => {}} />
|
{pickPoint && (
|
||||||
<EyeDropInput label="Unload Point" value="na" onChange={() => {}} />
|
<EyeDropInput
|
||||||
|
label="Pick Point"
|
||||||
|
value={pickPoint.value}
|
||||||
|
onChange={pickPoint.onChange}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{unloadPoint && (
|
||||||
|
<EyeDropInput
|
||||||
|
label="Unload Point"
|
||||||
|
value={unloadPoint.value}
|
||||||
|
onChange={unloadPoint.onChange}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,202 @@
|
|||||||
|
import React, { useRef } from "react";
|
||||||
|
import {
|
||||||
|
AddIcon,
|
||||||
|
RemoveIcon,
|
||||||
|
ResizeHeightIcon,
|
||||||
|
} from "../../../../../icons/ExportCommonIcons";
|
||||||
|
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||||
|
import { handleResize } from "../../../../../../functions/handleResizePannel";
|
||||||
|
import {
|
||||||
|
useSelectedAction,
|
||||||
|
useSelectedEventData,
|
||||||
|
useSelectedProduct,
|
||||||
|
} from "../../../../../../store/simulation/useSimulationStore";
|
||||||
|
import { MathUtils } from "three";
|
||||||
|
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||||
|
|
||||||
|
interface ActionsListProps {
|
||||||
|
setSelectedPointData: (data: any) => void; // You can replace `any` with a more specific type if you have one
|
||||||
|
selectedPointData: any; // You can replace `any` with a more specific type if you have one
|
||||||
|
// ui control props
|
||||||
|
multipleAction?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ActionsList: React.FC<ActionsListProps> = ({
|
||||||
|
setSelectedPointData,
|
||||||
|
selectedPointData,
|
||||||
|
multipleAction = false,
|
||||||
|
}) => {
|
||||||
|
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
// store
|
||||||
|
const { selectedEventData } = useSelectedEventData();
|
||||||
|
const { updateAction, addAction, removeAction } = useProductStore();
|
||||||
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
const { selectedAction, setSelectedAction, clearSelectedAction } =
|
||||||
|
useSelectedAction();
|
||||||
|
|
||||||
|
const handleAddAction = () => {
|
||||||
|
if (!selectedEventData || !selectedPointData) return;
|
||||||
|
|
||||||
|
const newAction = {
|
||||||
|
actionUuid: MathUtils.generateUUID(),
|
||||||
|
actionName: `Action ${selectedPointData.actions.length + 1}`,
|
||||||
|
actionType: "pickAndPlace" as const,
|
||||||
|
process: {
|
||||||
|
startPoint: null,
|
||||||
|
endPoint: null,
|
||||||
|
},
|
||||||
|
triggers: [] as TriggerSchema[],
|
||||||
|
};
|
||||||
|
|
||||||
|
addAction(
|
||||||
|
selectedProduct.productId,
|
||||||
|
selectedEventData.data.modelUuid,
|
||||||
|
selectedEventData.selectedPoint,
|
||||||
|
newAction
|
||||||
|
);
|
||||||
|
|
||||||
|
const updatedPoint = {
|
||||||
|
...selectedPointData,
|
||||||
|
actions: [...selectedPointData.actions, newAction],
|
||||||
|
};
|
||||||
|
setSelectedPointData(updatedPoint);
|
||||||
|
setSelectedAction(newAction.actionUuid, newAction.actionName);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDeleteAction = (actionUuid: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
|
||||||
|
removeAction(actionUuid);
|
||||||
|
const newActions = selectedPointData.actions.filter(
|
||||||
|
(a: any) => a.actionUuid !== actionUuid
|
||||||
|
);
|
||||||
|
|
||||||
|
const updatedPoint = {
|
||||||
|
...selectedPointData,
|
||||||
|
actions: newActions,
|
||||||
|
};
|
||||||
|
setSelectedPointData(updatedPoint);
|
||||||
|
|
||||||
|
if (selectedAction.actionId === actionUuid) {
|
||||||
|
if (newActions.length > 0) {
|
||||||
|
setSelectedAction(newActions[0].actionUuid, newActions[0].actionName);
|
||||||
|
} else {
|
||||||
|
clearSelectedAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRenameAction = (newName: string) => {
|
||||||
|
if (!selectedAction.actionId) return;
|
||||||
|
updateAction(selectedAction.actionId, { actionName: newName });
|
||||||
|
|
||||||
|
if (selectedPointData?.actions) {
|
||||||
|
const updatedActions = selectedPointData.actions.map((action: any) =>
|
||||||
|
action.actionUuid === selectedAction.actionId
|
||||||
|
? { ...action, actionName: newName }
|
||||||
|
: action
|
||||||
|
);
|
||||||
|
setSelectedPointData({
|
||||||
|
...selectedPointData,
|
||||||
|
actions: updatedActions,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// write logic for single action
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleActionSelect = (actionUuid: string, actionName: string) => {
|
||||||
|
setSelectedAction(actionUuid, actionName);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="actions-list-container">
|
||||||
|
<div className="actions">
|
||||||
|
<div className="header">
|
||||||
|
<div className="header-value">Actions</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="add-button"
|
||||||
|
onClick={() => handleAddAction()}
|
||||||
|
disabled={!multipleAction}
|
||||||
|
>
|
||||||
|
<AddIcon /> Add
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="lists-main-container"
|
||||||
|
ref={actionsContainerRef}
|
||||||
|
style={{ height: "120px" }}
|
||||||
|
>
|
||||||
|
<div className="list-container">
|
||||||
|
{multipleAction &&
|
||||||
|
selectedPointData.actions.map((action: any) => (
|
||||||
|
<div
|
||||||
|
key={action.actionUuid}
|
||||||
|
className={`list-item ${
|
||||||
|
selectedAction.actionId === action.actionUuid
|
||||||
|
? "active"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
className="value"
|
||||||
|
onClick={() =>
|
||||||
|
handleActionSelect(action.actionUuid, action.actionName)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<RenameInput
|
||||||
|
value={action.actionName}
|
||||||
|
onRename={handleRenameAction}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
{selectedPointData.actions.length > 1 && (
|
||||||
|
<button
|
||||||
|
className="remove-button"
|
||||||
|
onClick={() => handleDeleteAction(action.actionUuid)}
|
||||||
|
>
|
||||||
|
<RemoveIcon />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{!multipleAction && selectedPointData && (
|
||||||
|
<div
|
||||||
|
key={selectedPointData.action.actionUuid}
|
||||||
|
className={`list-item active`}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
className="value"
|
||||||
|
onClick={() =>
|
||||||
|
handleActionSelect(
|
||||||
|
selectedPointData.action.actionUuid,
|
||||||
|
selectedPointData.action.actionName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<RenameInput
|
||||||
|
value={selectedPointData.action.actionName}
|
||||||
|
onRename={handleRenameAction}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{multipleAction && (
|
||||||
|
<button
|
||||||
|
className="resize-icon"
|
||||||
|
id="action-resize"
|
||||||
|
onMouseDown={(e: any) => handleResize(e, actionsContainerRef)}
|
||||||
|
>
|
||||||
|
<ResizeHeightIcon />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ActionsList;
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||||
|
import DelayAction from "../actions/DelayAction";
|
||||||
|
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||||
|
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||||
|
import DespawnAction from "../actions/DespawnAction";
|
||||||
|
import SwapAction from "../actions/SwapAction";
|
||||||
|
import SpawnAction from "../actions/SpawnAction";
|
||||||
|
import DefaultAction from "../actions/DefaultAction";
|
||||||
|
import Trigger from "../trigger/Trigger";
|
||||||
|
import {
|
||||||
|
useSelectedEventData,
|
||||||
|
useSelectedProduct,
|
||||||
|
} from "../../../../../../store/simulation/useSimulationStore";
|
||||||
|
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||||
|
import ActionsList from "../components/ActionsList";
|
||||||
|
|
||||||
|
function ConveyorMechanics() {
|
||||||
|
const [activeOption, setActiveOption] = useState<
|
||||||
|
"default" | "spawn" | "swap" | "delay" | "despawn"
|
||||||
|
>("default");
|
||||||
|
const [selectedPointData, setSelectedPointData] = useState<
|
||||||
|
ConveyorPointSchema | undefined
|
||||||
|
>();
|
||||||
|
const { selectedEventData } = useSelectedEventData();
|
||||||
|
const { getPointByUuid, updateEvent, updateAction } = useProductStore();
|
||||||
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedEventData) {
|
||||||
|
const point = getPointByUuid(
|
||||||
|
selectedProduct.productId,
|
||||||
|
selectedEventData?.data.modelUuid,
|
||||||
|
selectedEventData?.selectedPoint
|
||||||
|
) as ConveyorPointSchema | undefined;
|
||||||
|
if (point && "action" in point) {
|
||||||
|
setSelectedPointData(point);
|
||||||
|
setActiveOption(
|
||||||
|
point.action.actionType as
|
||||||
|
| "default"
|
||||||
|
| "spawn"
|
||||||
|
| "swap"
|
||||||
|
| "delay"
|
||||||
|
| "despawn"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [selectedProduct, selectedEventData, getPointByUuid]);
|
||||||
|
|
||||||
|
const handleSpeedChange = (value: string) => {
|
||||||
|
if (!selectedEventData) return;
|
||||||
|
updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, {
|
||||||
|
speed: parseFloat(value),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleActionTypeChange = (option: string) => {
|
||||||
|
if (!selectedEventData || !selectedPointData) return;
|
||||||
|
const validOption = option as
|
||||||
|
| "default"
|
||||||
|
| "spawn"
|
||||||
|
| "swap"
|
||||||
|
| "delay"
|
||||||
|
| "despawn";
|
||||||
|
setActiveOption(validOption);
|
||||||
|
|
||||||
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
|
actionType: validOption,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRenameAction = (newName: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
updateAction(selectedPointData.action.actionUuid, { actionName: newName });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSpawnCountChange = (value: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
|
spawnCount: value === "inherit" ? "inherit" : parseFloat(value),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSpawnIntervalChange = (value: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
|
spawnInterval: value === "inherit" ? "inherit" : parseFloat(value),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMaterialSelect = (material: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
updateAction(selectedPointData.action.actionUuid, { material });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelayChange = (value: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
|
delay: value === "inherit" ? "inherit" : parseFloat(value),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const availableActions = {
|
||||||
|
defaultOption: "default",
|
||||||
|
options: ["default", "spawn", "swap", "delay", "despawn"],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get current values from store
|
||||||
|
const currentSpeed =
|
||||||
|
selectedEventData?.data.type === "transfer"
|
||||||
|
? selectedEventData.data.speed.toString()
|
||||||
|
: "0.5";
|
||||||
|
|
||||||
|
const currentActionName = selectedPointData
|
||||||
|
? selectedPointData.action.actionName
|
||||||
|
: "Action Name";
|
||||||
|
|
||||||
|
const currentMaterial = selectedPointData
|
||||||
|
? selectedPointData.action.material
|
||||||
|
: "Default material";
|
||||||
|
|
||||||
|
const currentSpawnCount = selectedPointData
|
||||||
|
? selectedPointData.action.spawnCount?.toString() || "1"
|
||||||
|
: "1";
|
||||||
|
|
||||||
|
const currentSpawnInterval = selectedPointData
|
||||||
|
? selectedPointData.action.spawnInterval?.toString() || "1"
|
||||||
|
: "1";
|
||||||
|
|
||||||
|
const currentDelay = selectedPointData
|
||||||
|
? selectedPointData.action.delay?.toString() || "0"
|
||||||
|
: "0";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{selectedEventData && (
|
||||||
|
<>
|
||||||
|
<div key={selectedPointData?.uuid} className="global-props">
|
||||||
|
<div className="property-list-container">
|
||||||
|
<div className="property-item">
|
||||||
|
<InputWithDropDown
|
||||||
|
label="Speed"
|
||||||
|
value={currentSpeed}
|
||||||
|
min={0}
|
||||||
|
step={0.1}
|
||||||
|
defaultValue={"0.5"}
|
||||||
|
max={10}
|
||||||
|
activeOption="m/s"
|
||||||
|
onClick={() => {}}
|
||||||
|
onChange={handleSpeedChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ActionsList
|
||||||
|
setSelectedPointData={setSelectedPointData}
|
||||||
|
selectedPointData={selectedPointData}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="selected-actions-details">
|
||||||
|
<div className="selected-actions-header">
|
||||||
|
<RenameInput
|
||||||
|
value={currentActionName}
|
||||||
|
onRename={handleRenameAction}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="selected-actions-list">
|
||||||
|
<LabledDropdown
|
||||||
|
defaultOption={
|
||||||
|
selectedPointData
|
||||||
|
? selectedPointData.action.actionType
|
||||||
|
: "default"
|
||||||
|
}
|
||||||
|
options={availableActions.options}
|
||||||
|
onSelect={handleActionTypeChange}
|
||||||
|
/>
|
||||||
|
{activeOption === "default" && <DefaultAction />}
|
||||||
|
{activeOption === "spawn" && (
|
||||||
|
<SpawnAction
|
||||||
|
onChangeCount={handleSpawnCountChange}
|
||||||
|
options={["Default material", "Material 1", "Material 2"]}
|
||||||
|
defaultOption={currentMaterial}
|
||||||
|
onSelect={handleMaterialSelect}
|
||||||
|
onChangeInterval={handleSpawnIntervalChange}
|
||||||
|
intervalValue={currentSpawnInterval}
|
||||||
|
countValue={currentSpawnCount}
|
||||||
|
intervalMin={1}
|
||||||
|
intervalMax={60}
|
||||||
|
intervalDefaultValue="1"
|
||||||
|
countMin={1}
|
||||||
|
countMax={100}
|
||||||
|
countDefaultValue="1"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{activeOption === "swap" && (
|
||||||
|
<SwapAction
|
||||||
|
options={["Default material", "Material 1", "Material 2"]}
|
||||||
|
defaultOption={currentMaterial}
|
||||||
|
onSelect={handleMaterialSelect}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{activeOption === "despawn" && <DespawnAction />}
|
||||||
|
{activeOption === "delay" && (
|
||||||
|
<DelayAction
|
||||||
|
value={currentDelay}
|
||||||
|
defaultValue="0"
|
||||||
|
min={0}
|
||||||
|
max={60}
|
||||||
|
onChange={handleDelayChange}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="tirgger">
|
||||||
|
<Trigger />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ConveyorMechanics;
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||||
|
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||||
|
import Trigger from "../trigger/Trigger";
|
||||||
|
import {
|
||||||
|
useSelectedEventData,
|
||||||
|
useSelectedProduct,
|
||||||
|
} from "../../../../../../store/simulation/useSimulationStore";
|
||||||
|
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||||
|
import ProcessAction from "../actions/ProcessAction";
|
||||||
|
import ActionsList from "../components/ActionsList";
|
||||||
|
|
||||||
|
function MachineMechanics() {
|
||||||
|
const [activeOption, setActiveOption] = useState<"default" | "process">(
|
||||||
|
"default"
|
||||||
|
);
|
||||||
|
const [selectedPointData, setSelectedPointData] = useState<
|
||||||
|
MachinePointSchema | undefined
|
||||||
|
>();
|
||||||
|
const { selectedEventData } = useSelectedEventData();
|
||||||
|
const { getPointByUuid, updateAction } = useProductStore();
|
||||||
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedEventData) {
|
||||||
|
const point = getPointByUuid(
|
||||||
|
selectedProduct.productId,
|
||||||
|
selectedEventData?.data.modelUuid,
|
||||||
|
selectedEventData?.selectedPoint
|
||||||
|
) as MachinePointSchema | undefined;
|
||||||
|
if (point && "action" in point) {
|
||||||
|
setSelectedPointData(point);
|
||||||
|
setActiveOption(point.action.actionType as "process");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [selectedProduct, selectedEventData, getPointByUuid]);
|
||||||
|
|
||||||
|
const handleActionTypeChange = (option: string) => {
|
||||||
|
if (!selectedEventData || !selectedPointData) return;
|
||||||
|
const validOption = option as "process";
|
||||||
|
setActiveOption(validOption);
|
||||||
|
|
||||||
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
|
actionType: validOption,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRenameAction = (newName: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
updateAction(selectedPointData.action.actionUuid, { actionName: newName });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleProcessTimeChange = (value: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
|
processTime: parseFloat(value),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMaterialSelect = (material: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
|
swapMaterial: material,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get current values from store
|
||||||
|
const currentActionName = selectedPointData
|
||||||
|
? selectedPointData.action.actionName
|
||||||
|
: "Action Name";
|
||||||
|
|
||||||
|
const currentProcessTime = selectedPointData
|
||||||
|
? selectedPointData.action.processTime.toString()
|
||||||
|
: "1";
|
||||||
|
|
||||||
|
const currentMaterial = selectedPointData
|
||||||
|
? selectedPointData.action.swapMaterial
|
||||||
|
: "Default material";
|
||||||
|
|
||||||
|
const availableActions = {
|
||||||
|
defaultOption: "process",
|
||||||
|
options: ["process"],
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{selectedEventData && (
|
||||||
|
<>
|
||||||
|
<div className="selected-actions-details">
|
||||||
|
<div className="selected-actions-header">
|
||||||
|
<RenameInput
|
||||||
|
value={currentActionName}
|
||||||
|
onRename={handleRenameAction}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ActionsList
|
||||||
|
setSelectedPointData={setSelectedPointData}
|
||||||
|
selectedPointData={selectedPointData}
|
||||||
|
/>
|
||||||
|
<div className="selected-actions-list">
|
||||||
|
<LabledDropdown
|
||||||
|
defaultOption="process"
|
||||||
|
options={availableActions.options}
|
||||||
|
onSelect={handleActionTypeChange}
|
||||||
|
/>
|
||||||
|
{activeOption === "process" && (
|
||||||
|
<ProcessAction
|
||||||
|
value={currentProcessTime}
|
||||||
|
min={0.1}
|
||||||
|
max={60}
|
||||||
|
defaultValue="1"
|
||||||
|
onChange={handleProcessTimeChange}
|
||||||
|
swapOptions={["Default material", "Material 1", "Material 2"]}
|
||||||
|
swapDefaultOption={currentMaterial}
|
||||||
|
onSwapSelect={handleMaterialSelect}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="tirgger">
|
||||||
|
<Trigger />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MachineMechanics;
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||||
|
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||||
|
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||||
|
import Trigger from "../trigger/Trigger";
|
||||||
|
import {
|
||||||
|
useSelectedEventData,
|
||||||
|
useSelectedProduct,
|
||||||
|
useSelectedAction,
|
||||||
|
} from "../../../../../../store/simulation/useSimulationStore";
|
||||||
|
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||||
|
import PickAndPlaceAction from "../actions/PickAndPlaceAction";
|
||||||
|
import ActionsList from "../components/ActionsList";
|
||||||
|
|
||||||
|
function RoboticArmMechanics() {
|
||||||
|
const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">(
|
||||||
|
"default"
|
||||||
|
);
|
||||||
|
const [selectedPointData, setSelectedPointData] = useState<
|
||||||
|
RoboticArmPointSchema | undefined
|
||||||
|
>();
|
||||||
|
const { selectedEventData } = useSelectedEventData();
|
||||||
|
const { getPointByUuid, updateEvent, updateAction } = useProductStore();
|
||||||
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
const { selectedAction, setSelectedAction, clearSelectedAction } =
|
||||||
|
useSelectedAction();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedEventData) {
|
||||||
|
const point = getPointByUuid(
|
||||||
|
selectedProduct.productId,
|
||||||
|
selectedEventData.data.modelUuid,
|
||||||
|
selectedEventData.selectedPoint
|
||||||
|
) as RoboticArmPointSchema | undefined;
|
||||||
|
if (point?.actions) {
|
||||||
|
setSelectedPointData(point);
|
||||||
|
setActiveOption(
|
||||||
|
point.actions[0].actionType as "default" | "pickAndPlace"
|
||||||
|
);
|
||||||
|
if (point.actions.length > 0 && !selectedAction.actionId) {
|
||||||
|
setSelectedAction(
|
||||||
|
point.actions[0].actionUuid,
|
||||||
|
point.actions[0].actionName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clearSelectedAction();
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
clearSelectedAction,
|
||||||
|
getPointByUuid,
|
||||||
|
selectedAction.actionId,
|
||||||
|
selectedEventData,
|
||||||
|
selectedProduct,
|
||||||
|
setSelectedAction,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const handleRenameAction = (newName: string) => {
|
||||||
|
if (!selectedAction.actionId) return;
|
||||||
|
updateAction(selectedAction.actionId, { actionName: newName });
|
||||||
|
|
||||||
|
if (selectedPointData) {
|
||||||
|
const updatedActions = selectedPointData.actions.map((action) =>
|
||||||
|
action.actionUuid === selectedAction.actionId
|
||||||
|
? { ...action, actionName: newName }
|
||||||
|
: action
|
||||||
|
);
|
||||||
|
setSelectedPointData({
|
||||||
|
...selectedPointData,
|
||||||
|
actions: updatedActions,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSpeedChange = (value: string) => {
|
||||||
|
if (!selectedEventData) return;
|
||||||
|
updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, {
|
||||||
|
speed: parseFloat(value),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePickPointChange = (value: string) => {
|
||||||
|
if (!selectedAction.actionId || !selectedPointData) return;
|
||||||
|
const [x, y, z] = value.split(",").map(Number);
|
||||||
|
|
||||||
|
updateAction(selectedAction.actionId, {
|
||||||
|
process: {
|
||||||
|
startPoint: [x, y, z] as [number, number, number],
|
||||||
|
endPoint:
|
||||||
|
selectedPointData.actions.find(
|
||||||
|
(a) => a.actionUuid === selectedAction.actionId
|
||||||
|
)?.process.endPoint || null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePlacePointChange = (value: string) => {
|
||||||
|
if (!selectedAction.actionId || !selectedPointData) return;
|
||||||
|
const [x, y, z] = value.split(",").map(Number);
|
||||||
|
|
||||||
|
updateAction(selectedAction.actionId, {
|
||||||
|
process: {
|
||||||
|
startPoint:
|
||||||
|
selectedPointData.actions.find(
|
||||||
|
(a) => a.actionUuid === selectedAction.actionId
|
||||||
|
)?.process.startPoint || null,
|
||||||
|
endPoint: [x, y, z] as [number, number, number],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const availableActions = {
|
||||||
|
defaultOption: "pickAndPlace",
|
||||||
|
options: ["pickAndPlace"],
|
||||||
|
};
|
||||||
|
|
||||||
|
const currentSpeed =
|
||||||
|
selectedEventData?.data.type === "roboticArm"
|
||||||
|
? selectedEventData.data.speed.toString()
|
||||||
|
: "0.5";
|
||||||
|
|
||||||
|
const currentAction = selectedPointData?.actions.find(
|
||||||
|
(a) => a.actionUuid === selectedAction.actionId
|
||||||
|
);
|
||||||
|
const currentPickPoint = currentAction?.process.startPoint
|
||||||
|
? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}`
|
||||||
|
: "";
|
||||||
|
const currentPlacePoint = currentAction?.process.endPoint
|
||||||
|
? `${currentAction.process.endPoint[0]},${currentAction.process.endPoint[1]},${currentAction.process.endPoint[2]}`
|
||||||
|
: "";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{selectedEventData && selectedPointData && (
|
||||||
|
<>
|
||||||
|
<div className="global-props">
|
||||||
|
<div className="property-list-container">
|
||||||
|
<div className="property-item">
|
||||||
|
<InputWithDropDown
|
||||||
|
label="Speed"
|
||||||
|
value={currentSpeed}
|
||||||
|
min={0}
|
||||||
|
step={0.1}
|
||||||
|
defaultValue={"0.5"}
|
||||||
|
max={10}
|
||||||
|
activeOption="m/s"
|
||||||
|
onClick={() => {}}
|
||||||
|
onChange={handleSpeedChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ActionsList
|
||||||
|
setSelectedPointData={setSelectedPointData}
|
||||||
|
selectedPointData={selectedPointData}
|
||||||
|
multipleAction
|
||||||
|
/>
|
||||||
|
|
||||||
|
{selectedAction.actionId && currentAction && (
|
||||||
|
<div className="selected-actions-details">
|
||||||
|
<div className="selected-actions-header">
|
||||||
|
<RenameInput
|
||||||
|
value={selectedAction.actionName}
|
||||||
|
onRename={handleRenameAction}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="selected-actions-list">
|
||||||
|
<LabledDropdown
|
||||||
|
defaultOption={activeOption}
|
||||||
|
options={availableActions.options}
|
||||||
|
onSelect={() => {}}
|
||||||
|
disabled={true}
|
||||||
|
/>
|
||||||
|
<PickAndPlaceAction
|
||||||
|
pickPointValue={currentPickPoint}
|
||||||
|
pickPointOnChange={handlePickPointChange}
|
||||||
|
placePointValue={currentPlacePoint}
|
||||||
|
placePointOnChange={handlePlacePointChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="tirgger">
|
||||||
|
<Trigger />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RoboticArmMechanics;
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||||
|
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||||
|
import Trigger from "../trigger/Trigger";
|
||||||
|
import {
|
||||||
|
useSelectedEventData,
|
||||||
|
useSelectedProduct,
|
||||||
|
} from "../../../../../../store/simulation/useSimulationStore";
|
||||||
|
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||||
|
import StorageAction from "../actions/StorageAction";
|
||||||
|
import ActionsList from "../components/ActionsList";
|
||||||
|
|
||||||
|
function StorageMechanics() {
|
||||||
|
const [activeOption, setActiveOption] = useState<
|
||||||
|
"default" | "store" | "spawn"
|
||||||
|
>("default");
|
||||||
|
const [selectedPointData, setSelectedPointData] = useState<
|
||||||
|
StoragePointSchema | undefined
|
||||||
|
>();
|
||||||
|
const { selectedEventData } = useSelectedEventData();
|
||||||
|
const { getPointByUuid, updateAction } = useProductStore();
|
||||||
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedEventData) {
|
||||||
|
const point = getPointByUuid(
|
||||||
|
selectedProduct.productId,
|
||||||
|
selectedEventData?.data.modelUuid,
|
||||||
|
selectedEventData?.selectedPoint
|
||||||
|
) as StoragePointSchema | undefined;
|
||||||
|
if (point && "action" in point) {
|
||||||
|
setSelectedPointData(point);
|
||||||
|
setActiveOption(point.action.actionType as "store" | "spawn");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [selectedProduct, selectedEventData, getPointByUuid]);
|
||||||
|
|
||||||
|
const handleActionTypeChange = (option: string) => {
|
||||||
|
if (!selectedEventData || !selectedPointData) return;
|
||||||
|
const validOption = option as "store" | "spawn";
|
||||||
|
setActiveOption(validOption);
|
||||||
|
|
||||||
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
|
actionType: validOption,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRenameAction = (newName: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
updateAction(selectedPointData.action.actionUuid, { actionName: newName });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCapacityChange = (value: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
|
storageCapacity: parseInt(value),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get current values from store
|
||||||
|
const currentActionName = selectedPointData
|
||||||
|
? selectedPointData.action.actionName
|
||||||
|
: "Action Name";
|
||||||
|
|
||||||
|
const currentCapacity = selectedPointData
|
||||||
|
? selectedPointData.action.storageCapacity.toString()
|
||||||
|
: "0";
|
||||||
|
|
||||||
|
const availableActions = {
|
||||||
|
defaultOption: "store",
|
||||||
|
options: ["store", "spawn"],
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{selectedEventData && (
|
||||||
|
<>
|
||||||
|
<ActionsList
|
||||||
|
setSelectedPointData={setSelectedPointData}
|
||||||
|
selectedPointData={selectedPointData}
|
||||||
|
/>
|
||||||
|
<div className="selected-actions-details">
|
||||||
|
<div className="selected-actions-header">
|
||||||
|
<RenameInput
|
||||||
|
value={currentActionName}
|
||||||
|
onRename={handleRenameAction}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="selected-actions-list">
|
||||||
|
<LabledDropdown
|
||||||
|
defaultOption={activeOption}
|
||||||
|
options={availableActions.options}
|
||||||
|
onSelect={handleActionTypeChange}
|
||||||
|
/>
|
||||||
|
{activeOption === "store" && (
|
||||||
|
<StorageAction
|
||||||
|
value={currentCapacity}
|
||||||
|
defaultValue="0"
|
||||||
|
min={0}
|
||||||
|
max={20}
|
||||||
|
onChange={handleCapacityChange}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{activeOption === "spawn" && (
|
||||||
|
<div className="spawn-options">
|
||||||
|
<p>Spawn configuration options would go here</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="tirgger">
|
||||||
|
<Trigger />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StorageMechanics;
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||||
|
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||||
|
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||||
|
import Trigger from "../trigger/Trigger";
|
||||||
|
import {
|
||||||
|
useSelectedEventData,
|
||||||
|
useSelectedProduct,
|
||||||
|
} from "../../../../../../store/simulation/useSimulationStore";
|
||||||
|
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||||
|
import TravelAction from "../actions/TravelAction";
|
||||||
|
import ActionsList from "../components/ActionsList";
|
||||||
|
|
||||||
|
function VehicleMechanics() {
|
||||||
|
const [activeOption, setActiveOption] = useState<"default" | "travel">(
|
||||||
|
"default"
|
||||||
|
);
|
||||||
|
const [selectedPointData, setSelectedPointData] = useState<
|
||||||
|
VehiclePointSchema | undefined
|
||||||
|
>();
|
||||||
|
const { selectedEventData } = useSelectedEventData();
|
||||||
|
const { getPointByUuid, updateEvent, updateAction } = useProductStore();
|
||||||
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedEventData) {
|
||||||
|
const point = getPointByUuid(
|
||||||
|
selectedProduct.productId,
|
||||||
|
selectedEventData.data.modelUuid,
|
||||||
|
selectedEventData.selectedPoint
|
||||||
|
) as VehiclePointSchema | undefined;
|
||||||
|
|
||||||
|
if (point) {
|
||||||
|
setSelectedPointData(point);
|
||||||
|
setActiveOption(point.action.actionType as "travel");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [selectedProduct, selectedEventData, getPointByUuid]);
|
||||||
|
|
||||||
|
const handleSpeedChange = (value: string) => {
|
||||||
|
if (!selectedEventData) return;
|
||||||
|
updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, {
|
||||||
|
speed: parseFloat(value),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleActionTypeChange = (option: string) => {
|
||||||
|
if (!selectedEventData || !selectedPointData) return;
|
||||||
|
const validOption = option as "travel";
|
||||||
|
setActiveOption(validOption);
|
||||||
|
|
||||||
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
|
actionType: validOption,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRenameAction = (newName: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
updateAction(selectedPointData.action.actionUuid, { actionName: newName });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLoadCapacityChange = (value: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
|
loadCapacity: parseFloat(value),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUnloadDurationChange = (value: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
|
unLoadDuration: parseFloat(value),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePickPointChange = (value: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
const [x, y, z] = value.split(",").map(Number);
|
||||||
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
|
pickUpPoint: { x, y, z },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUnloadPointChange = (value: string) => {
|
||||||
|
if (!selectedPointData) return;
|
||||||
|
const [x, y, z] = value.split(",").map(Number);
|
||||||
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
|
unLoadPoint: { x, y, z },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get current values from store
|
||||||
|
const currentSpeed =
|
||||||
|
selectedEventData?.data.type === "vehicle"
|
||||||
|
? selectedEventData.data.speed.toString()
|
||||||
|
: "0.5";
|
||||||
|
|
||||||
|
const currentActionName = selectedPointData
|
||||||
|
? selectedPointData.action.actionName
|
||||||
|
: "Action Name";
|
||||||
|
|
||||||
|
const currentLoadCapacity = selectedPointData
|
||||||
|
? selectedPointData.action.loadCapacity.toString()
|
||||||
|
: "1";
|
||||||
|
|
||||||
|
const currentUnloadDuration = selectedPointData
|
||||||
|
? selectedPointData.action.unLoadDuration.toString()
|
||||||
|
: "1";
|
||||||
|
|
||||||
|
const currentPickPoint = selectedPointData?.action.pickUpPoint
|
||||||
|
? `${selectedPointData.action.pickUpPoint.x},${selectedPointData.action.pickUpPoint.y},${selectedPointData.action.pickUpPoint.z}`
|
||||||
|
: "";
|
||||||
|
|
||||||
|
const currentUnloadPoint = selectedPointData?.action.unLoadPoint
|
||||||
|
? `${selectedPointData.action.unLoadPoint.x},${selectedPointData.action.unLoadPoint.y},${selectedPointData.action.unLoadPoint.z}`
|
||||||
|
: "";
|
||||||
|
|
||||||
|
const availableActions = {
|
||||||
|
defaultOption: "travel",
|
||||||
|
options: ["travel"],
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{selectedEventData && (
|
||||||
|
<>
|
||||||
|
<div className="global-props">
|
||||||
|
<div className="property-list-container">
|
||||||
|
<div className="property-item">
|
||||||
|
<InputWithDropDown
|
||||||
|
label="Speed"
|
||||||
|
value={currentSpeed}
|
||||||
|
min={0}
|
||||||
|
step={0.1}
|
||||||
|
defaultValue={"0.5"}
|
||||||
|
max={10}
|
||||||
|
activeOption="m/s"
|
||||||
|
onClick={() => {}}
|
||||||
|
onChange={handleSpeedChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ActionsList
|
||||||
|
setSelectedPointData={setSelectedPointData}
|
||||||
|
selectedPointData={selectedPointData}
|
||||||
|
/>
|
||||||
|
<div className="selected-actions-details">
|
||||||
|
<div className="selected-actions-header">
|
||||||
|
<RenameInput
|
||||||
|
value={currentActionName}
|
||||||
|
onRename={handleRenameAction}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="selected-actions-list">
|
||||||
|
<LabledDropdown
|
||||||
|
defaultOption="travel"
|
||||||
|
options={availableActions.options}
|
||||||
|
onSelect={handleActionTypeChange}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{activeOption === "travel" && (
|
||||||
|
<TravelAction
|
||||||
|
loadCapacity={{
|
||||||
|
value: currentLoadCapacity,
|
||||||
|
min: 1,
|
||||||
|
max: 100,
|
||||||
|
defaultValue: "1",
|
||||||
|
onChange: handleLoadCapacityChange,
|
||||||
|
}}
|
||||||
|
unloadDuration={{
|
||||||
|
value: currentUnloadDuration,
|
||||||
|
min: 1,
|
||||||
|
max: 60,
|
||||||
|
defaultValue: "1",
|
||||||
|
onChange: handleUnloadDurationChange,
|
||||||
|
}}
|
||||||
|
// pickPoint={{
|
||||||
|
// value: currentPickPoint,
|
||||||
|
// onChange: handlePickPointChange,
|
||||||
|
// }}
|
||||||
|
// unloadPoint={{
|
||||||
|
// value: currentUnloadPoint,
|
||||||
|
// onChange: handleUnloadPointChange,
|
||||||
|
// }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="tirgger">
|
||||||
|
<Trigger />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default VehicleMechanics;
|
||||||
@@ -1,11 +1,19 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useRef, useState } from "react";
|
||||||
import { AddIcon, RemoveIcon } from "../../../../../icons/ExportCommonIcons";
|
import {
|
||||||
|
AddIcon,
|
||||||
|
RemoveIcon,
|
||||||
|
ResizeHeightIcon,
|
||||||
|
} from "../../../../../icons/ExportCommonIcons";
|
||||||
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||||
|
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||||
|
import { handleResize } from "../../../../../../functions/handleResizePannel";
|
||||||
|
|
||||||
const Trigger: React.FC = () => {
|
const Trigger: React.FC = () => {
|
||||||
// State to hold the list of triggers
|
// State to hold the list of triggers
|
||||||
const [triggers, setTriggers] = useState<string[]>([]);
|
const [triggers, setTriggers] = useState<string[]>(["Trigger 1"]);
|
||||||
|
const [selectedTrigger, setSelectedTrigger] = useState<string>("Trigger 1");
|
||||||
const [activeOption, setActiveOption] = useState("onComplete");
|
const [activeOption, setActiveOption] = useState("onComplete");
|
||||||
|
const triggersContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
// States for dropdowns
|
// States for dropdowns
|
||||||
const [triggeredModel, setTriggeredModel] = useState<string[]>([]);
|
const [triggeredModel, setTriggeredModel] = useState<string[]>([]);
|
||||||
@@ -35,28 +43,53 @@ const Trigger: React.FC = () => {
|
|||||||
<div className="trigger-wrapper">
|
<div className="trigger-wrapper">
|
||||||
<div className="header">
|
<div className="header">
|
||||||
<div className="title">Trigger</div>
|
<div className="title">Trigger</div>
|
||||||
<div
|
<button
|
||||||
className="add-button"
|
className="add-button"
|
||||||
onClick={addTrigger}
|
onClick={addTrigger}
|
||||||
style={{ cursor: "pointer" }}
|
style={{ cursor: "pointer" }}
|
||||||
>
|
>
|
||||||
<AddIcon /> Add
|
<AddIcon /> Add
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="trigger-list">
|
<div className="trigger-list">
|
||||||
{/* Map over triggers and render them */}
|
|
||||||
{triggers.map((trigger, index) => (
|
|
||||||
<div key={index} className="trigger-item">
|
|
||||||
<div className="trigger-name">
|
|
||||||
{trigger}
|
|
||||||
<div
|
<div
|
||||||
|
className="lists-main-container"
|
||||||
|
ref={triggersContainerRef}
|
||||||
|
style={{ height: "120px" }}
|
||||||
|
>
|
||||||
|
<div className="list-container">
|
||||||
|
{triggers.map((trigger: any, index: number) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={`list-item ${
|
||||||
|
selectedTrigger === trigger ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => setSelectedTrigger(trigger)}
|
||||||
|
>
|
||||||
|
<button className="value" onClick={() => {}}>
|
||||||
|
<RenameInput value={trigger} onRename={() => {}} />
|
||||||
|
</button>
|
||||||
|
{triggers.length > 1 && (
|
||||||
|
<button
|
||||||
className="remove-button"
|
className="remove-button"
|
||||||
onClick={() => removeTrigger(index)}
|
onClick={() => removeTrigger(index)}
|
||||||
style={{ cursor: "pointer" }}
|
|
||||||
>
|
>
|
||||||
<RemoveIcon />
|
<RemoveIcon />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<button
|
||||||
|
className="resize-icon"
|
||||||
|
id="action-resize"
|
||||||
|
onMouseDown={(e: any) => handleResize(e, triggersContainerRef)}
|
||||||
|
>
|
||||||
|
<ResizeHeightIcon />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="trigger-item">
|
||||||
|
<div className="trigger-name">{selectedTrigger}</div>
|
||||||
<LabledDropdown
|
<LabledDropdown
|
||||||
defaultOption={activeOption}
|
defaultOption={activeOption}
|
||||||
options={["onComplete", "onStart", "onStop", "delay"]}
|
options={["onComplete", "onStart", "onStop", "delay"]}
|
||||||
@@ -65,40 +98,39 @@ const Trigger: React.FC = () => {
|
|||||||
<div className="trigger-options">
|
<div className="trigger-options">
|
||||||
<div>
|
<div>
|
||||||
<LabledDropdown
|
<LabledDropdown
|
||||||
defaultOption={triggeredModel[index] || "Select Model"}
|
defaultOption={triggeredModel[0] || "Select Model"}
|
||||||
options={["Model 1", "Model 2", "Model 3"]}
|
options={["Model 1", "Model 2", "Model 3"]}
|
||||||
onSelect={(option) => {
|
onSelect={(option) => {
|
||||||
const newModel = [...triggeredModel];
|
const newModel = [...triggeredModel];
|
||||||
newModel[index] = option;
|
newModel[0] = option;
|
||||||
setTriggeredModel(newModel);
|
setTriggeredModel(newModel);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<LabledDropdown
|
<LabledDropdown
|
||||||
defaultOption={triggeredPoint[index] || "Select Point"}
|
defaultOption={triggeredPoint[0] || "Select Point"}
|
||||||
options={["Point 1", "Point 2", "Point 3"]}
|
options={["Point 1", "Point 2", "Point 3"]}
|
||||||
onSelect={(option) => {
|
onSelect={(option) => {
|
||||||
const newPoint = [...triggeredPoint];
|
const newPoint = [...triggeredPoint];
|
||||||
newPoint[index] = option;
|
newPoint[0] = option;
|
||||||
setTriggeredPoint(newPoint);
|
setTriggeredPoint(newPoint);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<LabledDropdown
|
<LabledDropdown
|
||||||
defaultOption={triggeredAction[index] || "Select Action"}
|
defaultOption={triggeredAction[0] || "Select Action"}
|
||||||
options={["Action 1", "Action 2", "Action 3"]}
|
options={["Action 1", "Action 2", "Action 3"]}
|
||||||
onSelect={(option) => {
|
onSelect={(option) => {
|
||||||
const newAction = [...triggeredAction];
|
const newAction = [...triggeredAction];
|
||||||
newAction[index] = option;
|
newAction[0] = option;
|
||||||
setTriggeredAction(newAction);
|
setTriggeredAction(newAction);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useRef, useState } from "react";
|
import React, { useEffect, useRef } from "react";
|
||||||
import {
|
import {
|
||||||
AddIcon,
|
AddIcon,
|
||||||
ArrowIcon,
|
ArrowIcon,
|
||||||
@@ -7,65 +7,98 @@ import {
|
|||||||
} from "../../../icons/ExportCommonIcons";
|
} from "../../../icons/ExportCommonIcons";
|
||||||
import RenameInput from "../../../ui/inputs/RenameInput";
|
import RenameInput from "../../../ui/inputs/RenameInput";
|
||||||
import { handleResize } from "../../../../functions/handleResizePannel";
|
import { handleResize } from "../../../../functions/handleResizePannel";
|
||||||
|
import { useSelectedAsset, useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
|
||||||
|
import { useProductStore } from "../../../../store/simulation/useProductStore";
|
||||||
|
import { generateUUID } from "three/src/math/MathUtils";
|
||||||
|
import RenderOverlay from "../../../templates/Overlay";
|
||||||
|
import EditWidgetOption from "../../../ui/menu/EditWidgetOption";
|
||||||
|
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
|
||||||
|
|
||||||
interface Path {
|
interface Event {
|
||||||
pathName: string; // Represents the name of the path
|
pathName: string;
|
||||||
Children: string[]; // Represents the list of child points
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DropListProps {
|
interface ListProps {
|
||||||
val: Path; // Use the Path interface for the val prop
|
val: Event;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DropList: React.FC<DropListProps> = ({ val }) => {
|
const List: React.FC<ListProps> = ({ val }) => {
|
||||||
const [openDrop, setOpenDrop] = useState(false);
|
|
||||||
return (
|
return (
|
||||||
<div className="process-container">
|
<div className="process-container">
|
||||||
<div
|
<div className="value">
|
||||||
className="value"
|
|
||||||
onClick={() => {
|
|
||||||
setOpenDrop(!openDrop);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{val.pathName}
|
{val.pathName}
|
||||||
<div className={`arrow-container${openDrop ? " active" : ""}`}>
|
|
||||||
<ArrowIcon />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{val.Children && openDrop && (
|
|
||||||
<div className="children-drop">
|
|
||||||
{val.Children.map((child, index) => (
|
|
||||||
<div key={index} className="value">
|
|
||||||
{child}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Simulations: React.FC = () => {
|
const Simulations: React.FC = () => {
|
||||||
const productsContainerRef = useRef<HTMLDivElement>(null);
|
const productsContainerRef = useRef<HTMLDivElement>(null);
|
||||||
const [productsList, setProductsList] = useState<string[]>([]);
|
const { products, addProduct, removeProduct, renameProduct, addEvent, removeEvent } = useProductStore();
|
||||||
const [selectedItem, setSelectedItem] = useState<string>();
|
const { selectedProduct, setSelectedProduct } = useSelectedProduct();
|
||||||
|
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||||
|
|
||||||
const handleAddAction = () => {
|
const handleAddProduct = () => {
|
||||||
setProductsList([...productsList, `Product ${productsList.length + 1}`]);
|
addProduct(`Product ${products.length + 1}`, generateUUID());
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveAction = (index: number) => {
|
const handleRemoveProduct = (productId: string) => {
|
||||||
setProductsList(productsList.filter((_, i) => i !== index));
|
const currentIndex = products.findIndex(p => p.productId === productId);
|
||||||
if (selectedItem === productsList[index]) {
|
const isSelected = selectedProduct.productId === productId;
|
||||||
setSelectedItem("");
|
|
||||||
|
const updatedProducts = products.filter(p => p.productId !== productId);
|
||||||
|
|
||||||
|
if (isSelected) {
|
||||||
|
if (updatedProducts.length > 0) {
|
||||||
|
let newSelectedIndex = currentIndex;
|
||||||
|
if (currentIndex >= updatedProducts.length) {
|
||||||
|
newSelectedIndex = updatedProducts.length - 1;
|
||||||
|
}
|
||||||
|
setSelectedProduct(
|
||||||
|
updatedProducts[newSelectedIndex].productId,
|
||||||
|
updatedProducts[newSelectedIndex].productName
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setSelectedProduct('', '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeProduct(productId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRenameProduct = (productId: string, newName: string) => {
|
||||||
|
renameProduct(productId, newName);
|
||||||
|
if (selectedProduct.productId === productId) {
|
||||||
|
setSelectedProduct(productId, newName);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const Value = [
|
const handleAddEventToProduct = () => {
|
||||||
{ pathName: "Path 1", Children: ["Point 1", "Point 2"] },
|
if (selectedAsset) {
|
||||||
{ pathName: "Path 2", Children: ["Point 1", "Point 2"] },
|
addEvent(selectedProduct.productId, selectedAsset);
|
||||||
{ pathName: "Path 3", Children: ["Point 1", "Point 2"] },
|
// upsertProductOrEventApi({
|
||||||
];
|
// productName: selectedProduct.productName,
|
||||||
|
// productId: selectedProduct.productId,
|
||||||
|
// eventDatas: selectedAsset
|
||||||
|
// });
|
||||||
|
clearSelectedAsset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemoveEventFromProduct = () => {
|
||||||
|
if (selectedAsset) {
|
||||||
|
removeEvent(selectedProduct.productId, selectedAsset.modelUuid);
|
||||||
|
clearSelectedAsset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectedProductData = products.find(
|
||||||
|
(product) => product.productId === selectedProduct.productId
|
||||||
|
);
|
||||||
|
|
||||||
|
const events: Event[] = selectedProductData?.eventDatas.map((event) => ({
|
||||||
|
pathName: event.modelName,
|
||||||
|
})) || [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="simulations-container">
|
<div className="simulations-container">
|
||||||
@@ -74,7 +107,7 @@ const Simulations: React.FC = () => {
|
|||||||
<div className="actions">
|
<div className="actions">
|
||||||
<div className="header">
|
<div className="header">
|
||||||
<div className="header-value">Products</div>
|
<div className="header-value">Products</div>
|
||||||
<div className="add-button" onClick={handleAddAction}>
|
<div className="add-button" onClick={handleAddProduct}>
|
||||||
<AddIcon /> Add
|
<AddIcon /> Add
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -84,26 +117,34 @@ const Simulations: React.FC = () => {
|
|||||||
style={{ height: "120px" }}
|
style={{ height: "120px" }}
|
||||||
>
|
>
|
||||||
<div className="list-container">
|
<div className="list-container">
|
||||||
{productsList.map((action, index) => (
|
{products.map((product, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={product.productId}
|
||||||
className={`list-item ${
|
className={`list-item ${selectedProduct.productId === product.productId ? "active" : ""}`}
|
||||||
selectedItem === action ? "active" : ""
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="value"
|
className="value"
|
||||||
onClick={() => setSelectedItem(action)}
|
onClick={() => setSelectedProduct(product.productId, product.productName)}
|
||||||
>
|
>
|
||||||
<input type="radio" name="products" id="products" />
|
<input
|
||||||
<RenameInput value={action} />
|
type="radio"
|
||||||
|
name="products"
|
||||||
|
checked={selectedProduct.productId === product.productId}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
<RenameInput
|
||||||
|
value={product.productName}
|
||||||
|
onRename={(newName) => handleRenameProduct(product.productId, newName)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{products.length > 1 && (
|
||||||
<div
|
<div
|
||||||
className="remove-button"
|
className="remove-button"
|
||||||
onClick={() => handleRemoveAction(index)}
|
onClick={() => handleRemoveProduct(product.productId)}
|
||||||
>
|
>
|
||||||
<RemoveIcon />
|
<RemoveIcon />
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -116,30 +157,46 @@ const Simulations: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="simulation-process">
|
<div className="simulation-process">
|
||||||
<div className="collapse-header-container">
|
<div className="collapse-header-container">
|
||||||
<div className="header">Operations</div>
|
<div className="header">Events</div>
|
||||||
<div className="arrow-container">
|
<div className="arrow-container">
|
||||||
<ArrowIcon />
|
<ArrowIcon />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{Value.map((val, index) => (
|
{events.map((event, index) => (
|
||||||
<DropList key={index} val={val} />
|
<List key={index} val={event} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="compare-simulations-container">
|
<div className="compare-simulations-container">
|
||||||
<div className="compare-simulations-header">
|
<div className="compare-simulations-header">
|
||||||
Need to Compare Layout?
|
Need to Compare Layout?
|
||||||
</div>
|
</div>
|
||||||
<div className="content">
|
<div className="content">
|
||||||
Click <span>'Compare'</span> to review and analyze the layout
|
Click <span>'Compare'</span> to review and analyze the layout differences between them.
|
||||||
differences between them.
|
|
||||||
</div>
|
</div>
|
||||||
<div className="input">
|
<div className="input">
|
||||||
<input type="button" value={"Compare"} className="submit" />
|
<input type="button" value={"Compare"} className="submit" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{selectedAsset &&
|
||||||
|
<RenderOverlay>
|
||||||
|
<EditWidgetOption
|
||||||
|
options={['Add to Product', 'Remove from Product']}
|
||||||
|
onClick={(option) => {
|
||||||
|
if (option === 'Add to Product') {
|
||||||
|
handleAddEventToProduct();
|
||||||
|
} else {
|
||||||
|
handleRemoveEventFromProduct();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</RenderOverlay>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { useState, useEffect, useRef } from "react";
|
import { useState, useEffect, useRef } from "react";
|
||||||
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
import { useWidgetStore } from "../../../../../store/useWidgetStore";
|
||||||
import ChartComponent from "../../../sidebarLeft//visualization/widgets/ChartComponent";
|
import ChartComponent from "../../../sidebarLeft/visualization/widgets/ChartComponent";
|
||||||
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
import RegularDropDown from "../../../../ui/inputs/RegularDropDown";
|
||||||
import { WalletIcon } from "../../../../icons/3dChartIcons";
|
import { WalletIcon } from "../../../../icons/3dChartIcons";
|
||||||
import SimpleCard from "../../../../../modules//visualization/widgets/floating/cards/SimpleCard";
|
import SimpleCard from "../../../../../modules/visualization/widgets/floating/cards/SimpleCard";
|
||||||
|
|
||||||
interface Widget {
|
interface Widget {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
} from "../icons/ExportToolsIcons";
|
} from "../icons/ExportToolsIcons";
|
||||||
import { ArrowIcon, TickIcon } from "../icons/ExportCommonIcons";
|
import { ArrowIcon, TickIcon } from "../icons/ExportCommonIcons";
|
||||||
import useModuleStore, { useThreeDStore } from "../../store/useModuleStore";
|
import useModuleStore, { useThreeDStore } from "../../store/useModuleStore";
|
||||||
import { handleSaveTemplate } from "../../modules//visualization/functions/handleSaveTemplate";
|
import { handleSaveTemplate } from "../../modules/visualization/functions/handleSaveTemplate";
|
||||||
import { usePlayButtonStore } from "../../store/usePlayButtonStore";
|
import { usePlayButtonStore } from "../../store/usePlayButtonStore";
|
||||||
import useTemplateStore from "../../store/useTemplateStore";
|
import useTemplateStore from "../../store/useTemplateStore";
|
||||||
import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
|
import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
|
||||||
|
|||||||
@@ -1,14 +1,32 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import LabledDropdown from "./LabledDropdown";
|
|
||||||
import { ArrowIcon } from "../../icons/ExportCommonIcons";
|
import { ArrowIcon } from "../../icons/ExportCommonIcons";
|
||||||
|
import LabledDropdown from "./LabledDropdown";
|
||||||
|
|
||||||
const PreviewSelectionWithUpload: React.FC = () => {
|
interface PreviewSelectionWithUploadProps {
|
||||||
const [showPreview, setSetshowPreview] = useState(false);
|
preview?: boolean;
|
||||||
|
upload?: boolean;
|
||||||
|
label?: string;
|
||||||
|
onSelect: (option: string) => void;
|
||||||
|
defaultOption: string;
|
||||||
|
options: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const PreviewSelectionWithUpload: React.FC<PreviewSelectionWithUploadProps> = ({
|
||||||
|
preview = false,
|
||||||
|
upload = false,
|
||||||
|
onSelect,
|
||||||
|
label,
|
||||||
|
defaultOption,
|
||||||
|
options,
|
||||||
|
}) => {
|
||||||
|
const [showPreview, setShowPreview] = useState(false);
|
||||||
return (
|
return (
|
||||||
<div className="preview-selection-with-upload-wrapper">
|
<div className="preview-selection-with-upload-wrapper">
|
||||||
<div
|
{preview && (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
className="input-header-container"
|
className="input-header-container"
|
||||||
onClick={() => setSetshowPreview(!showPreview)}
|
onClick={() => setShowPreview(!showPreview)}
|
||||||
>
|
>
|
||||||
<div className="input-header">Preview</div>
|
<div className="input-header">Preview</div>
|
||||||
<div
|
<div
|
||||||
@@ -17,12 +35,15 @@ const PreviewSelectionWithUpload: React.FC = () => {
|
|||||||
>
|
>
|
||||||
<ArrowIcon />
|
<ArrowIcon />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</button>
|
||||||
{showPreview && (
|
{showPreview && (
|
||||||
<div className="canvas-wrapper">
|
<div className="canvas-wrapper">
|
||||||
<div className="canvas-container"></div>
|
<div className="canvas-container"></div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{upload && (
|
||||||
<div className="asset-selection-container">
|
<div className="asset-selection-container">
|
||||||
<div className="upload-custom-asset-button">
|
<div className="upload-custom-asset-button">
|
||||||
<div className="title">Upload Product</div>
|
<div className="title">Upload Product</div>
|
||||||
@@ -31,17 +52,21 @@ const PreviewSelectionWithUpload: React.FC = () => {
|
|||||||
accept=".glb, .gltf"
|
accept=".glb, .gltf"
|
||||||
id="simulation-product-upload"
|
id="simulation-product-upload"
|
||||||
/>
|
/>
|
||||||
<label className="upload-button" htmlFor="simulation-product-upload">
|
<label
|
||||||
|
className="upload-button"
|
||||||
|
htmlFor="simulation-product-upload"
|
||||||
|
>
|
||||||
Upload here
|
Upload here
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<LabledDropdown
|
|
||||||
label="Presets"
|
|
||||||
defaultOption={"Default material"}
|
|
||||||
options={["Default material", "Product 1", "Product 2"]}
|
|
||||||
onSelect={(option) => console.log(option)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
<LabledDropdown
|
||||||
|
label={label}
|
||||||
|
defaultOption={defaultOption}
|
||||||
|
options={options}
|
||||||
|
onSelect={onSelect}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
ArrowIcon,
|
ArrowIcon,
|
||||||
EyeIcon,
|
EyeIcon,
|
||||||
LockIcon,
|
LockIcon,
|
||||||
RmoveIcon,
|
RemoveIcon,
|
||||||
} from "../../icons/ExportCommonIcons";
|
} from "../../icons/ExportCommonIcons";
|
||||||
import { useThree } from "@react-three/fiber";
|
import { useThree } from "@react-three/fiber";
|
||||||
import { useFloorItems, useZoneAssetId, useZones } from "../../../store/store";
|
import { useFloorItems, useZoneAssetId, useZones } from "../../../store/store";
|
||||||
@@ -142,9 +142,6 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('newName: ', newName);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
const checkZoneNameDuplicate = (name: string) => {
|
const checkZoneNameDuplicate = (name: string) => {
|
||||||
return zones.some(
|
return zones.some(
|
||||||
@@ -184,7 +181,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
|||||||
</div>
|
</div>
|
||||||
{remove && (
|
{remove && (
|
||||||
<div className="remove option">
|
<div className="remove option">
|
||||||
<RmoveIcon />
|
<RemoveIcon />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{item.assets && item.assets.length > 0 && (
|
{item.assets && item.assets.length > 0 && (
|
||||||
@@ -221,7 +218,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => {
|
|||||||
</div>
|
</div>
|
||||||
{remove && (
|
{remove && (
|
||||||
<div className="remove option">
|
<div className="remove option">
|
||||||
<RmoveIcon />
|
<RemoveIcon />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,23 +1,20 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import {
|
import {
|
||||||
useEditWidgetOptionsStore,
|
|
||||||
useLeftData,
|
useLeftData,
|
||||||
useRightClickSelected,
|
|
||||||
useRightSelected,
|
|
||||||
useTopData,
|
useTopData,
|
||||||
} from "../../../store/visualization/useZone3DWidgetStore";
|
} from "../../../store/visualization/useZone3DWidgetStore";
|
||||||
|
|
||||||
interface EditWidgetOptionProps {
|
interface EditWidgetOptionProps {
|
||||||
options: string[];
|
options: string[];
|
||||||
|
onClick: (option: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EditWidgetOption: React.FC<EditWidgetOptionProps> = ({
|
const EditWidgetOption: React.FC<EditWidgetOptionProps> = ({
|
||||||
options,
|
options,
|
||||||
|
onClick
|
||||||
}) => {
|
}) => {
|
||||||
const { top } = useTopData();
|
const { top } = useTopData();
|
||||||
const { left } = useLeftData();
|
const { left } = useLeftData();
|
||||||
const { setRightSelect } = useRightSelected();
|
|
||||||
const { setEditWidgetOptions } = useEditWidgetOptionsStore();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
@@ -38,10 +35,7 @@ const EditWidgetOption: React.FC<EditWidgetOptionProps> = ({
|
|||||||
<div
|
<div
|
||||||
className="option"
|
className="option"
|
||||||
key={index}
|
key={index}
|
||||||
onClick={(e) => {
|
onClick={() => onClick(option)}
|
||||||
setRightSelect(option);
|
|
||||||
setEditWidgetOptions(false);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{option}
|
{option}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,10 +8,13 @@ import * as Types from "../../../types/world/worldTypes";
|
|||||||
import { initializeDB, retrieveGLTF, storeGLTF } from '../../../utils/indexDB/idbUtils';
|
import { initializeDB, retrieveGLTF, storeGLTF } from '../../../utils/indexDB/idbUtils';
|
||||||
import { getCamera } from '../../../services/factoryBuilder/camera/getCameraApi';
|
import { getCamera } from '../../../services/factoryBuilder/camera/getCameraApi';
|
||||||
import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
|
import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi';
|
||||||
|
import PointsCalculator from '../../simulation/events/points/functions/pointsCalculator';
|
||||||
|
|
||||||
async function loadInitialFloorItems(
|
async function loadInitialFloorItems(
|
||||||
itemsGroup: Types.RefGroup,
|
itemsGroup: Types.RefGroup,
|
||||||
setFloorItems: Types.setFloorItemSetState,
|
setFloorItems: Types.setFloorItemSetState,
|
||||||
|
addEvent: (event: EventsSchema) => void,
|
||||||
|
renderDistance: number
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!itemsGroup.current) return;
|
if (!itemsGroup.current) return;
|
||||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;
|
||||||
@@ -63,14 +66,14 @@ async function loadInitialFloorItems(
|
|||||||
|
|
||||||
const cameraPosition = new THREE.Vector3(storedPosition.x, storedPosition.y, storedPosition.z);
|
const cameraPosition = new THREE.Vector3(storedPosition.x, storedPosition.y, storedPosition.z);
|
||||||
|
|
||||||
if (cameraPosition.distanceTo(itemPosition) < 50) {
|
if (cameraPosition.distanceTo(itemPosition) < renderDistance) {
|
||||||
await new Promise<void>(async (resolve) => {
|
await new Promise<void>(async (resolve) => {
|
||||||
|
|
||||||
// Check Three.js Cache
|
// Check Three.js Cache
|
||||||
const cachedModel = THREE.Cache.get(item.modelfileID!);
|
const cachedModel = THREE.Cache.get(item.modelfileID!);
|
||||||
if (cachedModel) {
|
if (cachedModel) {
|
||||||
// console.log(`[Cache] Fetching ${item.modelname}`);
|
// console.log(`[Cache] Fetching ${item.modelname}`);
|
||||||
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems);
|
processLoadedModel(cachedModel.scene.clone(), item, itemsGroup, setFloorItems, addEvent);
|
||||||
modelsLoaded++;
|
modelsLoaded++;
|
||||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||||
return;
|
return;
|
||||||
@@ -85,7 +88,7 @@ async function loadInitialFloorItems(
|
|||||||
URL.revokeObjectURL(blobUrl);
|
URL.revokeObjectURL(blobUrl);
|
||||||
THREE.Cache.remove(blobUrl);
|
THREE.Cache.remove(blobUrl);
|
||||||
THREE.Cache.add(item.modelfileID!, gltf);
|
THREE.Cache.add(item.modelfileID!, gltf);
|
||||||
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems);
|
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, addEvent);
|
||||||
modelsLoaded++;
|
modelsLoaded++;
|
||||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||||
},
|
},
|
||||||
@@ -106,7 +109,7 @@ async function loadInitialFloorItems(
|
|||||||
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
const modelBlob = await fetch(modelUrl).then((res) => res.blob());
|
||||||
await storeGLTF(item.modelfileID!, modelBlob);
|
await storeGLTF(item.modelfileID!, modelBlob);
|
||||||
THREE.Cache.add(item.modelfileID!, gltf);
|
THREE.Cache.add(item.modelfileID!, gltf);
|
||||||
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems);
|
processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, addEvent);
|
||||||
modelsLoaded++;
|
modelsLoaded++;
|
||||||
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve);
|
||||||
},
|
},
|
||||||
@@ -148,8 +151,9 @@ function processLoadedModel(
|
|||||||
item: Types.FloorItemType,
|
item: Types.FloorItemType,
|
||||||
itemsGroup: Types.RefGroup,
|
itemsGroup: Types.RefGroup,
|
||||||
setFloorItems: Types.setFloorItemSetState,
|
setFloorItems: Types.setFloorItemSetState,
|
||||||
|
addEvent: (event: EventsSchema) => void,
|
||||||
) {
|
) {
|
||||||
const model = gltf;
|
const model = gltf.clone();
|
||||||
model.uuid = item.modeluuid;
|
model.uuid = item.modeluuid;
|
||||||
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);
|
||||||
model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid };
|
model.userData = { name: item.modelname, modelId: item.modelfileID, modeluuid: item.modeluuid };
|
||||||
@@ -182,6 +186,242 @@ function processLoadedModel(
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if (item.modelfileID === "a1ee92554935007b10b3eb05") {
|
||||||
|
const data = PointsCalculator(
|
||||||
|
'Vehicle',
|
||||||
|
gltf.clone(),
|
||||||
|
new THREE.Vector3(...model.rotation)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!data || !data.points) return;
|
||||||
|
|
||||||
|
const vehicleEvent: VehicleEventSchema = {
|
||||||
|
modelUuid: item.modeluuid,
|
||||||
|
modelName: item.modelname,
|
||||||
|
position: item.position,
|
||||||
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||||
|
state: "idle",
|
||||||
|
type: "vehicle",
|
||||||
|
speed: 1,
|
||||||
|
point: {
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
action: {
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: "Vehicle Action",
|
||||||
|
actionType: "travel",
|
||||||
|
unLoadDuration: 5,
|
||||||
|
loadCapacity: 10,
|
||||||
|
pickUpPoint: null,
|
||||||
|
unLoadPoint: null,
|
||||||
|
triggers: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
addEvent(vehicleEvent);
|
||||||
|
} else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") {
|
||||||
|
const data = PointsCalculator(
|
||||||
|
'Conveyor',
|
||||||
|
gltf.clone(),
|
||||||
|
new THREE.Vector3(...model.rotation)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!data || !data.points) return;
|
||||||
|
|
||||||
|
const ConveyorEvent: ConveyorEventSchema = {
|
||||||
|
modelUuid: item.modeluuid,
|
||||||
|
modelName: item.modelname,
|
||||||
|
position: item.position,
|
||||||
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||||
|
state: "idle",
|
||||||
|
type: "transfer",
|
||||||
|
speed: 1,
|
||||||
|
points: data.points.map((point: THREE.Vector3, index: number) => ({
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
position: [point.x, point.y, point.z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
action: {
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: `Action ${index + 1}`,
|
||||||
|
actionType: 'default',
|
||||||
|
material: 'Default material',
|
||||||
|
delay: 0,
|
||||||
|
spawnInterval: 5,
|
||||||
|
spawnCount: 1,
|
||||||
|
triggers: []
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
addEvent(ConveyorEvent);
|
||||||
|
} else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") {
|
||||||
|
// const data = PointsCalculator(
|
||||||
|
// 'Conveyor',
|
||||||
|
// gltf.clone(),
|
||||||
|
// new THREE.Vector3(...model.rotation)
|
||||||
|
// );
|
||||||
|
|
||||||
|
// if (!data || !data.points) return;
|
||||||
|
|
||||||
|
// const points: ConveyorPointSchema[] = data.points.map((point: THREE.Vector3, index: number) => {
|
||||||
|
// const actionUuid = THREE.MathUtils.generateUUID();
|
||||||
|
// return {
|
||||||
|
// uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
// position: [point.x, point.y, point.z],
|
||||||
|
// rotation: [0, 0, 0],
|
||||||
|
// action: {
|
||||||
|
// actionUuid,
|
||||||
|
// actionName: `Action ${index}`,
|
||||||
|
// actionType: 'default',
|
||||||
|
// material: 'inherit',
|
||||||
|
// delay: 0,
|
||||||
|
// spawnInterval: 5,
|
||||||
|
// spawnCount: 1,
|
||||||
|
// triggers: []
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// });
|
||||||
|
|
||||||
|
// points.forEach((point, index) => {
|
||||||
|
// if (index < points.length - 1) {
|
||||||
|
// const nextPoint = points[index + 1];
|
||||||
|
// point.action.triggers.push({
|
||||||
|
// triggerUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
// triggerName: `Trigger 1`,
|
||||||
|
// triggerType: "onComplete",
|
||||||
|
// delay: 0,
|
||||||
|
// triggeredAsset: {
|
||||||
|
// triggeredModel: {
|
||||||
|
// modelName: item.modelname,
|
||||||
|
// modelUuid: item.modeluuid
|
||||||
|
// },
|
||||||
|
// triggeredPoint: {
|
||||||
|
// pointName: `Point ${index + 1}`,
|
||||||
|
// pointUuid: nextPoint.uuid
|
||||||
|
// },
|
||||||
|
// triggeredAction: {
|
||||||
|
// actionName: nextPoint.action.actionName,
|
||||||
|
// actionUuid: nextPoint.action.actionUuid
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const ConveyorEvent: ConveyorEventSchema = {
|
||||||
|
// modelUuid: item.modeluuid,
|
||||||
|
// modelName: item.modelname,
|
||||||
|
// position: item.position,
|
||||||
|
// rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||||
|
// state: "idle",
|
||||||
|
// type: "transfer",
|
||||||
|
// speed: 1,
|
||||||
|
// points
|
||||||
|
// };
|
||||||
|
// addEvent(ConveyorEvent);
|
||||||
|
} else if (item.modelfileID === "7dc04e36882e4debbc1a8e3d") {
|
||||||
|
const data = PointsCalculator(
|
||||||
|
'Conveyor',
|
||||||
|
gltf.clone(),
|
||||||
|
new THREE.Vector3(...model.rotation)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!data || !data.points) return;
|
||||||
|
|
||||||
|
const ConveyorEvent: ConveyorEventSchema = {
|
||||||
|
modelUuid: item.modeluuid,
|
||||||
|
modelName: item.modelname,
|
||||||
|
position: item.position,
|
||||||
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||||
|
state: "idle",
|
||||||
|
type: "transfer",
|
||||||
|
speed: 1,
|
||||||
|
points: data.points.map((point: THREE.Vector3, index: number) => ({
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
position: [point.x, point.y, point.z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
action: {
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: `Action ${index}`,
|
||||||
|
actionType: 'default',
|
||||||
|
material: 'inherit',
|
||||||
|
delay: 0,
|
||||||
|
spawnInterval: 5,
|
||||||
|
spawnCount: 1,
|
||||||
|
triggers: []
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
addEvent(ConveyorEvent);
|
||||||
|
} else if (item.modelfileID === "29dee78715ad5b853f5c346d") {
|
||||||
|
const data = PointsCalculator(
|
||||||
|
'StaticMachine',
|
||||||
|
gltf.clone(),
|
||||||
|
new THREE.Vector3(...model.rotation)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!data || !data.points) return;
|
||||||
|
|
||||||
|
const machineEvent: MachineEventSchema = {
|
||||||
|
modelUuid: item.modeluuid,
|
||||||
|
modelName: item.modelname,
|
||||||
|
position: item.position,
|
||||||
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||||
|
state: "idle",
|
||||||
|
type: "machine",
|
||||||
|
point: {
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
action: {
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: "Process Action",
|
||||||
|
actionType: "process",
|
||||||
|
processTime: 10,
|
||||||
|
swapMaterial: "material-id",
|
||||||
|
triggers: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
addEvent(machineEvent);
|
||||||
|
} else if (item.modelfileID === "52e6681fbb743a890d96c914") {
|
||||||
|
const data = PointsCalculator(
|
||||||
|
'ArmBot',
|
||||||
|
gltf.clone(),
|
||||||
|
new THREE.Vector3(...model.rotation)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!data || !data.points) return;
|
||||||
|
|
||||||
|
const roboticArmEvent: RoboticArmEventSchema = {
|
||||||
|
modelUuid: item.modeluuid,
|
||||||
|
modelName: item.modelname,
|
||||||
|
position: item.position,
|
||||||
|
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||||
|
state: "idle",
|
||||||
|
type: "roboticArm",
|
||||||
|
speed: 1,
|
||||||
|
point: {
|
||||||
|
uuid: THREE.MathUtils.generateUUID(),
|
||||||
|
position: [data.points[0].x, data.points[0].y, data.points[0].z],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
|
actionName: "Pick and Place",
|
||||||
|
actionType: "pickAndPlace",
|
||||||
|
process: {
|
||||||
|
startPoint: [0, 0, 0],
|
||||||
|
endPoint: [0, 0, 0]
|
||||||
|
},
|
||||||
|
triggers: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
addEvent(roboticArmEvent);
|
||||||
|
}
|
||||||
|
|
||||||
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' });
|
gsap.to(model.position, { y: item.position[1], duration: 1.5, ease: 'power2.out' });
|
||||||
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' });
|
gsap.to(model.scale, { x: 1, y: 1, z: 1, duration: 1.5, ease: 'power2.out' });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ import Ground from "../scene/environment/ground";
|
|||||||
// import ZoneGroup from "../groups/zoneGroup1";
|
// import ZoneGroup from "../groups/zoneGroup1";
|
||||||
import { findEnvironment } from "../../services/factoryBuilder/environment/findEnvironment";
|
import { findEnvironment } from "../../services/factoryBuilder/environment/findEnvironment";
|
||||||
import Layer2DVisibility from "./geomentries/layers/layer2DVisibility";
|
import Layer2DVisibility from "./geomentries/layers/layer2DVisibility";
|
||||||
import DrieHtmlTemp from "..//visualization/mqttTemp/drieHtmlTemp";
|
import DrieHtmlTemp from "../visualization/mqttTemp/drieHtmlTemp";
|
||||||
import ZoneGroup from "./groups/zoneGroup";
|
import ZoneGroup from "./groups/zoneGroup";
|
||||||
import useModuleStore from "../../store/useModuleStore";
|
import useModuleStore from "../../store/useModuleStore";
|
||||||
import MeasurementTool from "../scene/tools/measurementTool";
|
import MeasurementTool from "../scene/tools/measurementTool";
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils';
|
|||||||
import { Socket } from 'socket.io-client';
|
import { Socket } from 'socket.io-client';
|
||||||
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
import * as CONSTANTS from '../../../../types/world/worldConstants';
|
||||||
import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi';
|
||||||
import PointsCalculator from '../../../simulation/events/points/pointsCalculator';
|
import PointsCalculator from '../../../simulation/events/points/functions/pointsCalculator';
|
||||||
|
|
||||||
async function addAssetModel(
|
async function addAssetModel(
|
||||||
raycaster: THREE.Raycaster,
|
raycaster: THREE.Raycaster,
|
||||||
@@ -202,7 +202,7 @@ async function handleModelLoad(
|
|||||||
actionUuid: THREE.MathUtils.generateUUID(),
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
actionName: `Action ${index}`,
|
actionName: `Action ${index}`,
|
||||||
actionType: 'default',
|
actionType: 'default',
|
||||||
material: 'inherit',
|
material: 'Default Material',
|
||||||
delay: 0,
|
delay: 0,
|
||||||
spawnInterval: 5,
|
spawnInterval: 5,
|
||||||
spawnCount: 1,
|
spawnCount: 1,
|
||||||
@@ -226,9 +226,8 @@ async function handleModelLoad(
|
|||||||
rotation: [0, 0, 0],
|
rotation: [0, 0, 0],
|
||||||
action: {
|
action: {
|
||||||
actionUuid: THREE.MathUtils.generateUUID(),
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
actionName: "Vehicle Action",
|
actionName: "Action 1",
|
||||||
actionType: "travel",
|
actionType: "travel",
|
||||||
material: null,
|
|
||||||
unLoadDuration: 5,
|
unLoadDuration: 5,
|
||||||
loadCapacity: 10,
|
loadCapacity: 10,
|
||||||
pickUpPoint: null,
|
pickUpPoint: null,
|
||||||
@@ -254,11 +253,11 @@ async function handleModelLoad(
|
|||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
actionUuid: THREE.MathUtils.generateUUID(),
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
actionName: "Pick and Place",
|
actionName: "Action 1",
|
||||||
actionType: "pickAndPlace",
|
actionType: "pickAndPlace",
|
||||||
process: {
|
process: {
|
||||||
startPoint: [0, 0, 0],
|
startPoint: null,
|
||||||
endPoint: [0, 0, 0]
|
endPoint: null
|
||||||
},
|
},
|
||||||
triggers: []
|
triggers: []
|
||||||
}
|
}
|
||||||
@@ -266,7 +265,7 @@ async function handleModelLoad(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
addEvent(roboticArmEvent);
|
addEvent(roboticArmEvent);
|
||||||
} else if (selectedItem.type === "Machine") {
|
} else if (selectedItem.type === "StaticMachine") {
|
||||||
const machineEvent: MachineEventSchema = {
|
const machineEvent: MachineEventSchema = {
|
||||||
modelUuid: newFloorItem.modeluuid,
|
modelUuid: newFloorItem.modeluuid,
|
||||||
modelName: newFloorItem.modelname,
|
modelName: newFloorItem.modelname,
|
||||||
@@ -280,10 +279,10 @@ async function handleModelLoad(
|
|||||||
rotation: [0, 0, 0],
|
rotation: [0, 0, 0],
|
||||||
action: {
|
action: {
|
||||||
actionUuid: THREE.MathUtils.generateUUID(),
|
actionUuid: THREE.MathUtils.generateUUID(),
|
||||||
actionName: "Process Action",
|
actionName: "Action 1",
|
||||||
actionType: "process",
|
actionType: "process",
|
||||||
processTime: 10,
|
processTime: 10,
|
||||||
swapMaterial: "material-id",
|
swapMaterial: "Default Material",
|
||||||
triggers: []
|
triggers: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
|
|||||||
gltfLoaderWorker.postMessage({ floorItems: data });
|
gltfLoaderWorker.postMessage({ floorItems: data });
|
||||||
} else {
|
} else {
|
||||||
gltfLoaderWorker.postMessage({ floorItems: [] });
|
gltfLoaderWorker.postMessage({ floorItems: [] });
|
||||||
loadInitialFloorItems(itemsGroup, setFloorItems);
|
loadInitialFloorItems(itemsGroup, setFloorItems, addEvent, renderDistance);
|
||||||
updateLoadingProgress(100);
|
updateLoadingProgress(100);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -94,7 +94,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject
|
|||||||
updateLoadingProgress(progress);
|
updateLoadingProgress(progress);
|
||||||
|
|
||||||
if (loadedAssets === totalAssets) {
|
if (loadedAssets === totalAssets) {
|
||||||
loadInitialFloorItems(itemsGroup, setFloorItems);
|
loadInitialFloorItems(itemsGroup, setFloorItems, addEvent, renderDistance);
|
||||||
updateLoadingProgress(100);
|
updateLoadingProgress(100);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ import {
|
|||||||
import * as Types from "../../../types/world/worldTypes";
|
import * as Types from "../../../types/world/worldTypes";
|
||||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
import { useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
|
||||||
|
|
||||||
export default function PostProcessing() {
|
export default function PostProcessing() {
|
||||||
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem();
|
||||||
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
|
const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
|
||||||
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
const { selectedFloorItem, setSelectedFloorItem } = useSelectedFloorItem();
|
||||||
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
|
|
||||||
function flattenChildren(children: any[]) {
|
function flattenChildren(children: any[]) {
|
||||||
const allChildren: any[] = [];
|
const allChildren: any[] = [];
|
||||||
@@ -85,6 +87,21 @@ export default function PostProcessing() {
|
|||||||
xRay={true}
|
xRay={true}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{selectedEventSphere && (
|
||||||
|
<Outline
|
||||||
|
selection={[selectedEventSphere]}
|
||||||
|
selectionLayer={10}
|
||||||
|
width={1000}
|
||||||
|
blendFunction={BlendFunction.ALPHA}
|
||||||
|
edgeStrength={10}
|
||||||
|
resolutionScale={2}
|
||||||
|
pulseSpeed={0}
|
||||||
|
visibleEdgeColor={0x6f42c1}
|
||||||
|
hiddenEdgeColor={0x6f42c1}
|
||||||
|
blur={true}
|
||||||
|
xRay={true}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</EffectComposer>
|
</EffectComposer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,17 +9,25 @@ import Simulation from "../simulation/simulation";
|
|||||||
import Collaboration from "../collaboration/collaboration";
|
import Collaboration from "../collaboration/collaboration";
|
||||||
|
|
||||||
export default function Scene() {
|
export default function Scene() {
|
||||||
const map = useMemo(() => [
|
const map = useMemo(
|
||||||
|
() => [
|
||||||
{ name: "forward", keys: ["ArrowUp", "w", "W"] },
|
{ name: "forward", keys: ["ArrowUp", "w", "W"] },
|
||||||
{ name: "backward", keys: ["ArrowDown", "s", "S"] },
|
{ name: "backward", keys: ["ArrowDown", "s", "S"] },
|
||||||
{ name: "left", keys: ["ArrowLeft", "a", "A"] },
|
{ name: "left", keys: ["ArrowLeft", "a", "A"] },
|
||||||
{ name: "right", keys: ["ArrowRight", "d", "D"] },],
|
{ name: "right", keys: ["ArrowRight", "d", "D"] },
|
||||||
[]);
|
],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<KeyboardControls map={map}>
|
<KeyboardControls map={map}>
|
||||||
<Canvas eventPrefix="client" gl={{ powerPreference: "high-performance", antialias: true }} onContextMenu={(e) => { e.preventDefault(); }}>
|
<Canvas
|
||||||
|
eventPrefix="client"
|
||||||
|
gl={{ powerPreference: "high-performance", antialias: true }}
|
||||||
|
onContextMenu={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Setup />
|
<Setup />
|
||||||
|
|
||||||
<Collaboration />
|
<Collaboration />
|
||||||
@@ -29,7 +37,6 @@ export default function Scene() {
|
|||||||
<Simulation />
|
<Simulation />
|
||||||
|
|
||||||
<Visualization />
|
<Visualization />
|
||||||
|
|
||||||
</Canvas>
|
</Canvas>
|
||||||
</KeyboardControls>
|
</KeyboardControls>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,20 +4,37 @@ import { useEventsStore } from '../../../../../store/simulation/useEventsStore';
|
|||||||
import useModuleStore from '../../../../../store/useModuleStore';
|
import useModuleStore from '../../../../../store/useModuleStore';
|
||||||
import { TransformControls } from '@react-three/drei';
|
import { TransformControls } from '@react-three/drei';
|
||||||
import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys';
|
import { detectModifierKeys } from '../../../../../utils/shortcutkeys/detectModifierKeys';
|
||||||
|
import { useSelectedEventSphere, useSelectedEventData } from '../../../../../store/simulation/useSimulationStore';
|
||||||
|
|
||||||
function PointsCreator() {
|
function PointsCreator() {
|
||||||
const { events, updatePoint, getPointByUuid } = useEventsStore();
|
const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const transformRef = useRef<any>(null);
|
const transformRef = useRef<any>(null);
|
||||||
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
|
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
|
||||||
const [selectedPoint, setSelectedPoint] = useState<THREE.Mesh | null>(null);
|
|
||||||
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
||||||
|
const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere } = useSelectedEventSphere();
|
||||||
|
const { setSelectedEventData, clearSelectedEventData } = useSelectedEventData();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedEventSphere) {
|
||||||
|
const eventData = getEventByModelUuid(selectedEventSphere.userData.modelUuid);
|
||||||
|
if (eventData) {
|
||||||
|
setSelectedEventData(
|
||||||
|
eventData,
|
||||||
|
selectedEventSphere.userData.pointUuid
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
clearSelectedEventData();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clearSelectedEventData();
|
||||||
|
}
|
||||||
|
}, [selectedEventSphere]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTransformMode(null);
|
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
const keyCombination = detectModifierKeys(e);
|
const keyCombination = detectModifierKeys(e);
|
||||||
if (!selectedPoint) return;
|
if (!selectedEventSphere) return;
|
||||||
if (keyCombination === "G") {
|
if (keyCombination === "G") {
|
||||||
setTransformMode((prev) => (prev === "translate" ? null : "translate"));
|
setTransformMode((prev) => (prev === "translate" ? null : "translate"));
|
||||||
}
|
}
|
||||||
@@ -28,13 +45,13 @@ function PointsCreator() {
|
|||||||
|
|
||||||
window.addEventListener("keydown", handleKeyDown);
|
window.addEventListener("keydown", handleKeyDown);
|
||||||
return () => window.removeEventListener("keydown", handleKeyDown);
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
||||||
}, [selectedPoint]);
|
}, [selectedEventSphere]);
|
||||||
|
|
||||||
const updatePointToState = (selectedPoint: THREE.Mesh) => {
|
const updatePointToState = (selectedEventSphere: THREE.Mesh) => {
|
||||||
let point = JSON.parse(JSON.stringify(getPointByUuid(selectedPoint.userData.modelUuid, selectedPoint.userData.pointUuid)));
|
let point = JSON.parse(JSON.stringify(getPointByUuid(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid)));
|
||||||
if (point) {
|
if (point) {
|
||||||
point.position = [selectedPoint.position.x, selectedPoint.position.y, selectedPoint.position.z];
|
point.position = [selectedEventSphere.position.x, selectedEventSphere.position.y, selectedEventSphere.position.z];
|
||||||
updatePoint(selectedPoint.userData.modelUuid, selectedPoint.userData.pointUuid, point)
|
updatePoint(selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid, point)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,14 +66,16 @@ function PointsCreator() {
|
|||||||
<group key={i} position={new THREE.Vector3(...event.position)}>
|
<group key={i} position={new THREE.Vector3(...event.position)}>
|
||||||
{event.points.map((point, j) => (
|
{event.points.map((point, j) => (
|
||||||
<mesh
|
<mesh
|
||||||
|
name='Event-Sphere'
|
||||||
uuid={point.uuid}
|
uuid={point.uuid}
|
||||||
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
|
ref={(el) => (sphereRefs.current[point.uuid] = el!)}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setSelectedPoint(sphereRefs.current[point.uuid]);
|
setSelectedEventSphere(sphereRefs.current[point.uuid]);
|
||||||
}}
|
}}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedPoint(null);
|
clearSelectedEventSphere();
|
||||||
|
setTransformMode(null);
|
||||||
}}
|
}}
|
||||||
key={`${i}-${j}`}
|
key={`${i}-${j}`}
|
||||||
position={new THREE.Vector3(...point.position)}
|
position={new THREE.Vector3(...point.position)}
|
||||||
@@ -72,14 +91,16 @@ function PointsCreator() {
|
|||||||
return (
|
return (
|
||||||
<group key={i} position={new THREE.Vector3(...event.position)}>
|
<group key={i} position={new THREE.Vector3(...event.position)}>
|
||||||
<mesh
|
<mesh
|
||||||
|
name='Event-Sphere'
|
||||||
uuid={event.point.uuid}
|
uuid={event.point.uuid}
|
||||||
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setSelectedPoint(sphereRefs.current[event.point.uuid]);
|
setSelectedEventSphere(sphereRefs.current[event.point.uuid]);
|
||||||
}}
|
}}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedPoint(null);
|
clearSelectedEventSphere();
|
||||||
|
setTransformMode(null);
|
||||||
}}
|
}}
|
||||||
position={new THREE.Vector3(...event.point.position)}
|
position={new THREE.Vector3(...event.point.position)}
|
||||||
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
|
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
|
||||||
@@ -93,14 +114,16 @@ function PointsCreator() {
|
|||||||
return (
|
return (
|
||||||
<group key={i} position={new THREE.Vector3(...event.position)}>
|
<group key={i} position={new THREE.Vector3(...event.position)}>
|
||||||
<mesh
|
<mesh
|
||||||
|
name='Event-Sphere'
|
||||||
uuid={event.point.uuid}
|
uuid={event.point.uuid}
|
||||||
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setSelectedPoint(sphereRefs.current[event.point.uuid]);
|
setSelectedEventSphere(sphereRefs.current[event.point.uuid]);
|
||||||
}}
|
}}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedPoint(null);
|
clearSelectedEventSphere();
|
||||||
|
setTransformMode(null);
|
||||||
}}
|
}}
|
||||||
position={new THREE.Vector3(...event.point.position)}
|
position={new THREE.Vector3(...event.point.position)}
|
||||||
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
|
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
|
||||||
@@ -114,14 +137,16 @@ function PointsCreator() {
|
|||||||
return (
|
return (
|
||||||
<group key={i} position={new THREE.Vector3(...event.position)}>
|
<group key={i} position={new THREE.Vector3(...event.position)}>
|
||||||
<mesh
|
<mesh
|
||||||
|
name='Event-Sphere'
|
||||||
uuid={event.point.uuid}
|
uuid={event.point.uuid}
|
||||||
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
ref={(el) => (sphereRefs.current[event.point.uuid] = el!)}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setSelectedPoint(sphereRefs.current[event.point.uuid]);
|
setSelectedEventSphere(sphereRefs.current[event.point.uuid]);
|
||||||
}}
|
}}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
setSelectedPoint(null);
|
clearSelectedEventSphere();
|
||||||
|
setTransformMode(null);
|
||||||
}}
|
}}
|
||||||
position={new THREE.Vector3(...event.point.position)}
|
position={new THREE.Vector3(...event.point.position)}
|
||||||
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
|
userData={{ modelUuid: event.modelUuid, pointUuid: event.point.uuid }}
|
||||||
@@ -136,8 +161,8 @@ function PointsCreator() {
|
|||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
</group>
|
</group>
|
||||||
{(selectedPoint && transformMode) &&
|
{(selectedEventSphere && transformMode) &&
|
||||||
<TransformControls ref={transformRef} object={selectedPoint} mode={transformMode} onMouseUp={(e) => { updatePointToState(selectedPoint) }} />
|
<TransformControls ref={transformRef} object={selectedEventSphere} mode={transformMode} onMouseUp={(e) => { updatePointToState(selectedEventSphere) }} />
|
||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { Group } from '../../../../types/world/worldTypes';
|
import { Group } from '../../../../../types/world/worldTypes';
|
||||||
|
|
||||||
function PointsCalculator(
|
function PointsCalculator(
|
||||||
type: string,
|
type: string,
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
function MachineInstance() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MachineInstance
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import MachineInstance from './machineInstance/machineInstance'
|
||||||
|
|
||||||
|
function MachineInstances() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<MachineInstance />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MachineInstances
|
||||||
14
app/src/modules/simulation/machine/machine.tsx
Normal file
14
app/src/modules/simulation/machine/machine.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import MachineInstances from './instances/machineInstances'
|
||||||
|
|
||||||
|
function Machine() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<MachineInstances />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Machine
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
import { useThree } from '@react-three/fiber'
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
import { Object3D } from 'three';
|
||||||
|
import { useSubModuleStore } from '../../../../store/useModuleStore';
|
||||||
|
import { useLeftData, useTopData } from '../../../../store/visualization/useZone3DWidgetStore';
|
||||||
|
import { useEventsStore } from '../../../../store/simulation/useEventsStore';
|
||||||
|
import { useProductStore } from '../../../../store/simulation/useProductStore';
|
||||||
|
import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
|
||||||
|
import { useSelectedAsset } from '../../../../store/simulation/useSimulationStore';
|
||||||
|
|
||||||
|
function AddOrRemoveEventsInProducts() {
|
||||||
|
const { gl, raycaster, scene } = useThree();
|
||||||
|
const { subModule } = useSubModuleStore();
|
||||||
|
const { setTop } = useTopData();
|
||||||
|
const { setLeft } = useLeftData();
|
||||||
|
const { getIsEventInProduct } = useProductStore();
|
||||||
|
const { getEventByModelUuid } = useEventsStore();
|
||||||
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
const { selectedAsset, setSelectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
const canvasElement = gl.domElement;
|
||||||
|
|
||||||
|
let drag = false;
|
||||||
|
let isRightMouseDown = false;
|
||||||
|
|
||||||
|
const onMouseDown = (evt: MouseEvent) => {
|
||||||
|
if (selectedAsset) {
|
||||||
|
clearSelectedAsset();
|
||||||
|
}
|
||||||
|
if (evt.button === 2) {
|
||||||
|
isRightMouseDown = true;
|
||||||
|
drag = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMouseUp = (evt: MouseEvent) => {
|
||||||
|
if (evt.button === 2) {
|
||||||
|
isRightMouseDown = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onMouseMove = () => {
|
||||||
|
if (isRightMouseDown) {
|
||||||
|
drag = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRightClick = (evt: MouseEvent) => {
|
||||||
|
if (drag) return;
|
||||||
|
evt.preventDefault();
|
||||||
|
const canvasElement = gl.domElement;
|
||||||
|
if (!canvasElement) return;
|
||||||
|
|
||||||
|
let intersects = raycaster.intersectObjects(scene.children, true);
|
||||||
|
if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) {
|
||||||
|
let currentObject = intersects[0].object;
|
||||||
|
|
||||||
|
while (currentObject) {
|
||||||
|
if (currentObject.name === "Scene") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
currentObject = currentObject.parent as Object3D;
|
||||||
|
}
|
||||||
|
if (currentObject) {
|
||||||
|
const isInProduct = getIsEventInProduct(selectedProduct.productId, currentObject.uuid);
|
||||||
|
|
||||||
|
if (isInProduct) {
|
||||||
|
const event = getEventByModelUuid(currentObject.uuid);
|
||||||
|
if (event) {
|
||||||
|
setSelectedAsset(event)
|
||||||
|
const canvasRect = canvasElement.getBoundingClientRect();
|
||||||
|
const relativeX = evt.clientX - canvasRect.left;
|
||||||
|
const relativeY = evt.clientY - canvasRect.top;
|
||||||
|
|
||||||
|
setTop(relativeY);
|
||||||
|
setLeft(relativeX);
|
||||||
|
} else {
|
||||||
|
clearSelectedAsset()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const event = getEventByModelUuid(currentObject.uuid);
|
||||||
|
if (event) {
|
||||||
|
setSelectedAsset(event)
|
||||||
|
const canvasRect = canvasElement.getBoundingClientRect();
|
||||||
|
const relativeX = evt.clientX - canvasRect.left;
|
||||||
|
const relativeY = evt.clientY - canvasRect.top;
|
||||||
|
|
||||||
|
setTop(relativeY);
|
||||||
|
setLeft(relativeX);
|
||||||
|
} else {
|
||||||
|
clearSelectedAsset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clearSelectedAsset()
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
if (subModule === 'simulations') {
|
||||||
|
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||||
|
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||||
|
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||||
|
canvasElement.addEventListener('contextmenu', handleRightClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||||
|
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||||
|
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||||
|
canvasElement.removeEventListener('contextmenu', handleRightClick);
|
||||||
|
};
|
||||||
|
|
||||||
|
}, [gl, subModule, selectedProduct, selectedAsset]);
|
||||||
|
return (
|
||||||
|
<></>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AddOrRemoveEventsInProducts
|
||||||
43
app/src/modules/simulation/products/products.tsx
Normal file
43
app/src/modules/simulation/products/products.tsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import * as THREE from 'three';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useProductStore } from '../../../store/simulation/useProductStore';
|
||||||
|
import { useSelectedProduct } from '../../../store/simulation/useSimulationStore';
|
||||||
|
import AddOrRemoveEventsInProducts from './events/addOrRemoveEventsInProducts';
|
||||||
|
import { upsertProductOrEventApi } from '../../../services/simulation/UpsertProductOrEventApi';
|
||||||
|
import { getAllProductsApi } from '../../../services/simulation/getallProductsApi';
|
||||||
|
|
||||||
|
function Products() {
|
||||||
|
const { products, addProduct } = useProductStore();
|
||||||
|
const { setSelectedProduct } = useSelectedProduct();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (products.length === 0) {
|
||||||
|
const id = THREE.MathUtils.generateUUID();
|
||||||
|
const name = 'Product 1';
|
||||||
|
addProduct(name, id);
|
||||||
|
// upsertProductOrEventApi({ productName: name, productId: id }).then((data) => {
|
||||||
|
// console.log('data: ', data);
|
||||||
|
// });
|
||||||
|
setSelectedProduct(id, name);
|
||||||
|
}
|
||||||
|
}, [products])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// const email = localStorage.getItem('email')
|
||||||
|
// const organization = (email!.split("@")[1]).split(".")[0];
|
||||||
|
// console.log(organization);
|
||||||
|
// getAllProductsApi(organization).then((data) => {
|
||||||
|
// console.log('data: ', data);
|
||||||
|
// })
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<AddOrRemoveEventsInProducts />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Products
|
||||||
@@ -1,6 +1,64 @@
|
|||||||
import React from 'react'
|
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
|
import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore';
|
||||||
|
import { useFrame, useThree } from '@react-three/fiber';
|
||||||
|
import * as THREE from "three"
|
||||||
|
import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||||
|
|
||||||
|
function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase, ikSolver, targetBone, robot, logStatus, groupRef, processes, armBotCurveRef, path }: any) {
|
||||||
|
const { armBots } = useArmBotStore();
|
||||||
|
const { scene } = useThree();
|
||||||
|
const restSpeed = 0.1;
|
||||||
|
const restPosition = new THREE.Vector3(0, 2, 1.6);
|
||||||
|
const initialCurveRef = useRef<THREE.CatmullRomCurve3 | null>(null);
|
||||||
|
const initialStartPositionRef = useRef<THREE.Vector3 | null>(null);
|
||||||
|
const [initialProgress, setInitialProgress] = useState(0);
|
||||||
|
const [progress, setProgress] = useState(0);
|
||||||
|
const [needsInitialMovement, setNeedsInitialMovement] = useState(true);
|
||||||
|
const [isInitializing, setIsInitializing] = useState(true);
|
||||||
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
const statusRef = useRef("idle");
|
||||||
|
// Create a ref for initialProgress
|
||||||
|
const initialProgressRef = useRef(0);
|
||||||
|
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setCurrentPath(path)
|
||||||
|
}, [path])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
}, [currentPath])
|
||||||
|
|
||||||
|
useFrame((_, delta) => {
|
||||||
|
if (!ikSolver || !currentPath || currentPath.length === 0) return;
|
||||||
|
|
||||||
|
const bone = ikSolver.mesh.skeleton.bones.find(
|
||||||
|
(b: any) => b.name === targetBone
|
||||||
|
);
|
||||||
|
if (!bone) return;
|
||||||
|
|
||||||
|
// Ensure currentPath is a valid array of 3D points, create a CatmullRomCurve3 from it
|
||||||
|
const curve = new THREE.CatmullRomCurve3(
|
||||||
|
currentPath.map(point => new THREE.Vector3(point[0], point[1], point[2]))
|
||||||
|
);
|
||||||
|
|
||||||
|
const next = initialProgressRef.current + delta * 0.5;
|
||||||
|
if (next >= 1) {
|
||||||
|
bone.position.copy(restPosition);
|
||||||
|
HandleCallback(); // Call the callback when the path is completed
|
||||||
|
initialProgressRef.current = 0; // Set ref to 1 when done
|
||||||
|
} else {
|
||||||
|
|
||||||
|
const point = curve.getPoint(next); // Get the interpolated point from the curve
|
||||||
|
bone.position.copy(point); // Update the bone position along the curve
|
||||||
|
initialProgressRef.current = next; // Update progress
|
||||||
|
}
|
||||||
|
|
||||||
|
ikSolver.update();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function RoboticArmAnimator() {
|
|
||||||
return (
|
return (
|
||||||
<></>
|
<></>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,14 +1,179 @@
|
|||||||
import React from 'react'
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
import IKInstance from '../ikInstance/ikInstance';
|
import IKInstance from '../ikInstance/ikInstance';
|
||||||
import RoboticArmAnimator from '../animator/roboticArmAnimator';
|
import RoboticArmAnimator from '../animator/roboticArmAnimator';
|
||||||
|
import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||||
|
import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore';
|
||||||
|
import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_4.glb";
|
||||||
|
import { useThree } from "@react-three/fiber";
|
||||||
|
import { useFloorItems } from '../../../../../store/store';
|
||||||
|
import useModuleStore from '../../../../../store/useModuleStore';
|
||||||
|
import { Vector3 } from "three";
|
||||||
|
import * as THREE from "three";
|
||||||
|
|
||||||
|
interface Process {
|
||||||
|
triggerId: string;
|
||||||
|
startPoint?: Vector3;
|
||||||
|
endPoint?: Vector3;
|
||||||
|
speed: number;
|
||||||
|
}
|
||||||
|
function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) {
|
||||||
|
|
||||||
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
const [currentPhase, setCurrentPhase] = useState<(string)>("init");
|
||||||
|
const { scene } = useThree();
|
||||||
|
const targetBone = "Target";
|
||||||
|
const { activeModule } = useModuleStore();
|
||||||
|
const [ikSolver, setIkSolver] = useState<any>(null);
|
||||||
|
const { addCurrentAction, setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore();
|
||||||
|
const { floorItems } = useFloorItems();
|
||||||
|
const groupRef = useRef<any>(null);
|
||||||
|
const [processes, setProcesses] = useState<Process[]>([]);
|
||||||
|
const [armBotCurvePoints, setArmBotCurvePoints] = useState({ start: [], end: [] })
|
||||||
|
const restPosition = new THREE.Vector3(0, 2, 1.6);
|
||||||
|
let armBotCurveRef = useRef<THREE.CatmullRomCurve3 | null>(null)
|
||||||
|
const [path, setPath] = useState<[number, number, number][]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let armItems = floorItems?.filter((val: any) =>
|
||||||
|
val.modeluuid === "3abf5d46-b59e-4e6b-9c02-a4634b64b82d"
|
||||||
|
);
|
||||||
|
// Get the first matching item
|
||||||
|
let armItem = armItems?.[0];
|
||||||
|
if (armItem) {
|
||||||
|
const targetMesh = scene?.getObjectByProperty("uuid", armItem.modeluuid);
|
||||||
|
if (targetMesh) {
|
||||||
|
targetMesh.visible = activeModule !== "simulation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const targetBones = ikSolver?.mesh.skeleton.bones.find(
|
||||||
|
(b: any) => b.name === targetBone
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isPlaying) {
|
||||||
|
//Moving armBot from initial point to rest position.
|
||||||
|
if (!robot?.isActive && robot?.state == "idle" && currentPhase == "init") {
|
||||||
|
|
||||||
|
setArmBotActive(robot.modelUuid, true)
|
||||||
|
setArmBotState(robot.modelUuid, "running")
|
||||||
|
setCurrentPhase("init-to-rest");
|
||||||
|
if (targetBones) {
|
||||||
|
let curve = createCurveBetweenTwoPoints(targetBones.position, restPosition)
|
||||||
|
if (curve) {
|
||||||
|
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logStatus(robot.modelUuid, "Starting from init to rest")
|
||||||
|
}
|
||||||
|
//Waiting for trigger.
|
||||||
|
else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "rest" && !robot.currentAction) {
|
||||||
|
console.log("trigger");
|
||||||
|
setTimeout(() => {
|
||||||
|
addCurrentAction(robot.modelUuid, 'action-003');
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "rest" && robot.currentAction) {
|
||||||
|
if (robot.currentAction) {
|
||||||
|
setArmBotActive(robot.modelUuid, true);
|
||||||
|
setArmBotState(robot.modelUuid, "running");
|
||||||
|
setCurrentPhase("rest-to-start");
|
||||||
|
const startPoint = robot.point.actions[0].process.startPoint;
|
||||||
|
if (startPoint) {
|
||||||
|
let curve = createCurveBetweenTwoPoints(restPosition, new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2]));
|
||||||
|
if (curve) {
|
||||||
|
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logStatus(robot.modelUuid, "Starting from rest to start")
|
||||||
|
}
|
||||||
|
else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "picking" && robot.currentAction) {
|
||||||
|
setArmBotActive(robot.modelUuid, true);
|
||||||
|
setArmBotState(robot.modelUuid, "running");
|
||||||
|
setCurrentPhase("start-to-end");
|
||||||
|
const startPoint = robot.point.actions[0].process.startPoint;
|
||||||
|
const endPoint = robot.point.actions[0].process.endPoint;
|
||||||
|
if (startPoint && endPoint) {
|
||||||
|
let curve = createCurveBetweenTwoPoints(
|
||||||
|
new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2]),
|
||||||
|
new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2])
|
||||||
|
);
|
||||||
|
if (curve) {
|
||||||
|
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logStatus(robot.modelUuid, "Starting from start to end")
|
||||||
|
}
|
||||||
|
else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "dropping" && robot.currentAction) {
|
||||||
|
setArmBotActive(robot.modelUuid, true);
|
||||||
|
setArmBotState(robot.modelUuid, "running");
|
||||||
|
setCurrentPhase("end-to-rest");
|
||||||
|
const endPoint = robot.point.actions[0].process.endPoint;
|
||||||
|
if (endPoint) {
|
||||||
|
let curve = createCurveBetweenTwoPoints(new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]), restPosition
|
||||||
|
);
|
||||||
|
if (curve) {
|
||||||
|
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logStatus(robot.modelUuid, "Starting from end to rest")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [currentPhase, robot, isPlaying, ikSolver])
|
||||||
|
|
||||||
|
|
||||||
|
function createCurveBetweenTwoPoints(p1: any, p2: any) {
|
||||||
|
const mid = new THREE.Vector3().addVectors(p1, p2).multiplyScalar(0.5);
|
||||||
|
mid.y += 0.5;
|
||||||
|
|
||||||
|
const points = [p1, mid, p2];
|
||||||
|
return new THREE.CatmullRomCurve3(points);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const HandleCallback = () => {
|
||||||
|
if (robot.isActive && robot.state == "running" && currentPhase == "init-to-rest") {
|
||||||
|
console.log("Callback triggered: rest");
|
||||||
|
setArmBotActive(robot.modelUuid, false)
|
||||||
|
setArmBotState(robot.modelUuid, "idle")
|
||||||
|
setCurrentPhase("rest");
|
||||||
|
setPath([])
|
||||||
|
}
|
||||||
|
else if (robot.isActive && robot.state == "running" && currentPhase == "rest-to-start") {
|
||||||
|
console.log("Callback triggered: pick.");
|
||||||
|
setArmBotActive(robot.modelUuid, false)
|
||||||
|
setArmBotState(robot.modelUuid, "idle")
|
||||||
|
setCurrentPhase("picking");
|
||||||
|
setPath([])
|
||||||
|
}
|
||||||
|
else if (robot.isActive && robot.state == "running" && currentPhase == "start-to-end") {
|
||||||
|
console.log("Callback triggered: drop.");
|
||||||
|
setArmBotActive(robot.modelUuid, false)
|
||||||
|
setArmBotState(robot.modelUuid, "idle")
|
||||||
|
setCurrentPhase("dropping");
|
||||||
|
setPath([])
|
||||||
|
}
|
||||||
|
else if (robot.isActive && robot.state == "running" && currentPhase == "end-to-rest") {
|
||||||
|
console.log("Callback triggered: rest, cycle completed.");
|
||||||
|
setArmBotActive(robot.modelUuid, false)
|
||||||
|
setArmBotState(robot.modelUuid, "idle")
|
||||||
|
setCurrentPhase("rest");
|
||||||
|
setPath([])
|
||||||
|
removeCurrentAction(robot.modelUuid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const logStatus = (id: string, status: string) => {
|
||||||
|
console.log(id +","+ status);
|
||||||
|
}
|
||||||
|
|
||||||
function RoboticArmInstance() {
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<IKInstance />
|
<IKInstance modelUrl={armModel} setIkSolver={setIkSolver} ikSolver={ikSolver} robot={robot} groupRef={groupRef} processes={processes}
|
||||||
|
setArmBotCurvePoints={setArmBotCurvePoints} />
|
||||||
<RoboticArmAnimator />
|
<RoboticArmAnimator armUuid={robot?.modelUuid} HandleCallback={HandleCallback}
|
||||||
|
currentPhase={currentPhase} targetBone={targetBone} ikSolver={ikSolver} robot={robot}
|
||||||
|
logStatus={logStatus} groupRef={groupRef} processes={processes} armBotCurveRef={armBotCurveRef} path={path} />
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +1,87 @@
|
|||||||
import React from 'react'
|
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
|
import * as THREE from "three";
|
||||||
|
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
|
||||||
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
||||||
|
import { clone } from "three/examples/jsm/utils/SkeletonUtils";
|
||||||
|
import { useFrame, useLoader, useThree } from "@react-three/fiber";
|
||||||
|
import { CCDIKSolver, CCDIKHelper, } from "three/examples/jsm/animation/CCDIKSolver";
|
||||||
|
type IKInstanceProps = {
|
||||||
|
modelUrl: string;
|
||||||
|
ikSolver: any;
|
||||||
|
setIkSolver: any
|
||||||
|
robot: any;
|
||||||
|
groupRef: React.RefObject<THREE.Group>;
|
||||||
|
processes: any;
|
||||||
|
setArmBotCurvePoints: any
|
||||||
|
};
|
||||||
|
function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processes, setArmBotCurvePoints }: IKInstanceProps) {
|
||||||
|
const { scene } = useThree();
|
||||||
|
const gltf = useLoader(GLTFLoader, modelUrl, (loader) => {
|
||||||
|
const draco = new DRACOLoader();
|
||||||
|
draco.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/");
|
||||||
|
loader.setDRACOLoader(draco);
|
||||||
|
});
|
||||||
|
const cloned = useMemo(() => clone(gltf?.scene), [gltf]);
|
||||||
|
const targetBoneName = "Target";
|
||||||
|
const skinnedMeshName = "link_0";
|
||||||
|
useEffect(() => {
|
||||||
|
if (!gltf) return;
|
||||||
|
const OOI: any = {};
|
||||||
|
cloned.traverse((n: any) => {
|
||||||
|
if (n.name === targetBoneName) OOI.Target_Bone = n;
|
||||||
|
if (n.name === skinnedMeshName) OOI.Skinned_Mesh = n;
|
||||||
|
});
|
||||||
|
if (!OOI.Target_Bone || !OOI.Skinned_Mesh) return;
|
||||||
|
const iks = [
|
||||||
|
{
|
||||||
|
target: 7,
|
||||||
|
effector: 6,
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
index: 5,
|
||||||
|
enabled: true,
|
||||||
|
rotationMin: new THREE.Vector3(-Math.PI / 2, 0, 0),
|
||||||
|
rotationMax: new THREE.Vector3(Math.PI / 2, 0, 0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 4,
|
||||||
|
enabled: true,
|
||||||
|
rotationMin: new THREE.Vector3(-Math.PI / 2, 0, 0),
|
||||||
|
rotationMax: new THREE.Vector3(0, 0, 0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
index: 3,
|
||||||
|
enabled: true,
|
||||||
|
rotationMin: new THREE.Vector3(0, 0, 0),
|
||||||
|
rotationMax: new THREE.Vector3(2, 0, 0),
|
||||||
|
},
|
||||||
|
{ index: 1, enabled: true, limitation: new THREE.Vector3(0, 1, 0) },
|
||||||
|
{ index: 0, enabled: false, limitation: new THREE.Vector3(0, 0, 0) },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const solver = new CCDIKSolver(OOI.Skinned_Mesh, iks);
|
||||||
|
setIkSolver(solver);
|
||||||
|
|
||||||
|
const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05);
|
||||||
|
|
||||||
|
// scene.add(groupRef.current)
|
||||||
|
|
||||||
|
|
||||||
|
}, [gltf]);
|
||||||
|
|
||||||
function IKInstance() {
|
|
||||||
return (
|
return (
|
||||||
<></>
|
<>
|
||||||
|
<group ref={groupRef} position={robot.position}>
|
||||||
|
<primitive
|
||||||
|
uuid={"ArmBot-X200"}
|
||||||
|
object={cloned}
|
||||||
|
scale={[1, 1, 1]}
|
||||||
|
name={`arm-bot11`}
|
||||||
|
/>
|
||||||
|
</group>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import IKInstance from './ikInstance/ikInstance';
|
|
||||||
|
|
||||||
function IkInstances() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
|
|
||||||
<IKInstance />
|
|
||||||
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default IkInstances;
|
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import RoboticArmInstance from './armInstance/roboticArmInstance';
|
import RoboticArmInstance from './armInstance/roboticArmInstance';
|
||||||
|
import { useArmBotStore } from '../../../../store/simulation/useArmBotStore';
|
||||||
|
|
||||||
function RoboticArmInstances() {
|
function RoboticArmInstances() {
|
||||||
|
const { armBots } = useArmBotStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{armBots?.map((robot: ArmBotStatus) => (
|
||||||
<RoboticArmInstance />
|
<RoboticArmInstance key={robot.modelUuid} robot={robot} />
|
||||||
|
))}
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,15 +1,166 @@
|
|||||||
import React from 'react'
|
import { useEffect } from "react";
|
||||||
import RoboticArmInstances from './instances/roboticArmInstances';
|
import RoboticArmInstances from "./instances/roboticArmInstances";
|
||||||
import IkInstances from './instances/ikInstances';
|
import { useArmBotStore } from "../../../store/simulation/useArmBotStore";
|
||||||
|
import { useFloorItems } from "../../../store/store";
|
||||||
|
|
||||||
function RoboticArm() {
|
function RoboticArm() {
|
||||||
|
const { armBots, addArmBot, removeArmBot } = useArmBotStore();
|
||||||
|
const { floorItems } = useFloorItems();
|
||||||
|
|
||||||
|
const armBotStatusSample: RoboticArmEventSchema[] = [
|
||||||
|
{
|
||||||
|
state: "idle",
|
||||||
|
modelUuid: "armbot-xyz-001",
|
||||||
|
modelName: "ArmBot-X200",
|
||||||
|
position: [91.94347308985614, 0, 6.742905194869091],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
type: "roboticArm",
|
||||||
|
speed: 1.5,
|
||||||
|
point: {
|
||||||
|
uuid: "point-123",
|
||||||
|
position: [0, 1.5, 0],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionUuid: "action-003",
|
||||||
|
actionName: "Pick Component",
|
||||||
|
actionType: "pickAndPlace",
|
||||||
|
process: {
|
||||||
|
startPoint: [5.52543010919071, 1, -8.433681161200905],
|
||||||
|
endPoint: [10.52543010919071, 1, -12.433681161200905],
|
||||||
|
},
|
||||||
|
triggers: [
|
||||||
|
{
|
||||||
|
triggerUuid: "trigger-001",
|
||||||
|
triggerName: "Start Trigger",
|
||||||
|
triggerType: "onStart",
|
||||||
|
delay: 0,
|
||||||
|
triggeredAsset: {
|
||||||
|
triggeredModel: {
|
||||||
|
modelName: "Conveyor A1",
|
||||||
|
modelUuid: "conveyor-01",
|
||||||
|
},
|
||||||
|
triggeredPoint: {
|
||||||
|
pointName: "Start Point",
|
||||||
|
pointUuid: "conveyor-01-point-001",
|
||||||
|
},
|
||||||
|
triggeredAction: {
|
||||||
|
actionName: "Move Forward",
|
||||||
|
actionUuid: "conveyor-action-01",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
triggerUuid: "trigger-002",
|
||||||
|
triggerName: "Complete Trigger",
|
||||||
|
triggerType: "onComplete",
|
||||||
|
delay: 0,
|
||||||
|
triggeredAsset: {
|
||||||
|
triggeredModel: {
|
||||||
|
modelName: "StaticMachine B2",
|
||||||
|
modelUuid: "machine-02",
|
||||||
|
},
|
||||||
|
triggeredPoint: {
|
||||||
|
pointName: "Receive Point",
|
||||||
|
pointUuid: "machine-02-point-001",
|
||||||
|
},
|
||||||
|
triggeredAction: {
|
||||||
|
actionName: "Process Part",
|
||||||
|
actionUuid: "machine-action-01",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
state: "idle",
|
||||||
|
modelUuid: "armbot-xyz-002",
|
||||||
|
modelName: "ArmBot-X200",
|
||||||
|
position: [95.94347308985614, 0, 6.742905194869091],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
type: "roboticArm",
|
||||||
|
speed: 1.5,
|
||||||
|
point: {
|
||||||
|
uuid: "point-123",
|
||||||
|
position: [0, 1.5, 0],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionUuid: "action-001",
|
||||||
|
actionName: "Pick Component",
|
||||||
|
actionType: "pickAndPlace",
|
||||||
|
process: {
|
||||||
|
startPoint: [2.52543010919071, 0, 8.433681161200905],
|
||||||
|
endPoint: [95.3438373267953, 0, 9.0279187421610025],
|
||||||
|
},
|
||||||
|
triggers: [
|
||||||
|
{
|
||||||
|
triggerUuid: "trigger-001",
|
||||||
|
triggerName: "Start Trigger",
|
||||||
|
triggerType: "onStart",
|
||||||
|
delay: 0,
|
||||||
|
triggeredAsset: {
|
||||||
|
triggeredModel: {
|
||||||
|
modelName: "Conveyor A1",
|
||||||
|
modelUuid: "conveyor-01",
|
||||||
|
},
|
||||||
|
triggeredPoint: {
|
||||||
|
pointName: "Start Point",
|
||||||
|
pointUuid: "conveyor-01-point-001",
|
||||||
|
},
|
||||||
|
triggeredAction: {
|
||||||
|
actionName: "Move Forward",
|
||||||
|
actionUuid: "conveyor-action-01",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
triggerUuid: "trigger-002",
|
||||||
|
triggerName: "Complete Trigger",
|
||||||
|
triggerType: "onComplete",
|
||||||
|
delay: 0,
|
||||||
|
triggeredAsset: {
|
||||||
|
triggeredModel: {
|
||||||
|
modelName: "StaticMachine B2",
|
||||||
|
modelUuid: "machine-02",
|
||||||
|
},
|
||||||
|
triggeredPoint: {
|
||||||
|
pointName: "Receive Point",
|
||||||
|
pointUuid: "machine-02-point-001",
|
||||||
|
},
|
||||||
|
triggeredAction: {
|
||||||
|
actionName: "Process Part",
|
||||||
|
actionUuid: "machine-action-01",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
removeArmBot(armBotStatusSample[0].modelUuid);
|
||||||
|
addArmBot('123', armBotStatusSample[0]);
|
||||||
|
// addArmBot('123', armBotStatusSample[1]);
|
||||||
|
// addCurrentAction('armbot-xyz-001', 'action-001');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
//
|
||||||
|
}, [armBots]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<RoboticArmInstances />
|
<RoboticArmInstances />
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RoboticArm;
|
export default RoboticArm;
|
||||||
@@ -5,8 +5,16 @@ import Vehicles from './vehicle/vehicles';
|
|||||||
import Points from './events/points/points';
|
import Points from './events/points/points';
|
||||||
import Conveyor from './conveyor/conveyor';
|
import Conveyor from './conveyor/conveyor';
|
||||||
import RoboticArm from './roboticArm/roboticArm';
|
import RoboticArm from './roboticArm/roboticArm';
|
||||||
|
import Materials from './materials/materials';
|
||||||
|
import Machine from './machine/machine';
|
||||||
|
import StorageUnit from './storageUnit/storageUnit';
|
||||||
|
import Simulator from './simulator/simulator';
|
||||||
|
import Products from './products/products';
|
||||||
|
import Trigger from './triggers/trigger';
|
||||||
|
import useModuleStore from '../../store/useModuleStore';
|
||||||
|
|
||||||
function Simulation() {
|
function Simulation() {
|
||||||
|
const { activeModule } = useModuleStore();
|
||||||
const { events } = useEventsStore();
|
const { events } = useEventsStore();
|
||||||
const { products } = useProductStore();
|
const { products } = useProductStore();
|
||||||
|
|
||||||
@@ -19,18 +27,38 @@ function Simulation() {
|
|||||||
}, [products])
|
}, [products])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
{activeModule === 'simulation' &&
|
||||||
|
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<Points />
|
<Points />
|
||||||
|
|
||||||
|
<Products />
|
||||||
|
|
||||||
|
<Materials />
|
||||||
|
|
||||||
|
<Trigger />
|
||||||
|
|
||||||
|
<Conveyor />
|
||||||
|
|
||||||
<Vehicles />
|
<Vehicles />
|
||||||
|
|
||||||
<RoboticArm />
|
<RoboticArm />
|
||||||
|
|
||||||
<Conveyor />
|
<Machine />
|
||||||
|
|
||||||
|
<StorageUnit />
|
||||||
|
|
||||||
|
<Simulator />
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Simulation
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Simulation;
|
||||||
|
|||||||
18
app/src/modules/simulation/simulator/simulator.tsx
Normal file
18
app/src/modules/simulation/simulator/simulator.tsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { useEffect } from 'react'
|
||||||
|
import { useProductStore } from '../../../store/simulation/useProductStore'
|
||||||
|
|
||||||
|
function Simulator() {
|
||||||
|
const { products } = useProductStore();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// console.log('products: ', products);
|
||||||
|
}, [products])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Simulator
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
function storageUnitInstance() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default storageUnitInstance
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import StorageUnitInstance from './storageUnitInstance/storageUnitInstance'
|
||||||
|
|
||||||
|
function StorageUnitInstances() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<StorageUnitInstance />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StorageUnitInstances
|
||||||
14
app/src/modules/simulation/storageUnit/storageUnit.tsx
Normal file
14
app/src/modules/simulation/storageUnit/storageUnit.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import StorageUnitInstances from './instances/storageUnitInstances'
|
||||||
|
|
||||||
|
function StorageUnit() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<StorageUnitInstances />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StorageUnit
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
import { useThree } from "@react-three/fiber";
|
||||||
|
import { useSubModuleStore } from "../../../../store/useModuleStore";
|
||||||
|
import { useSelectedAsset } from "../../../../store/simulation/useSimulationStore";
|
||||||
|
import { useProductStore } from "../../../../store/simulation/useProductStore";
|
||||||
|
import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
|
||||||
|
|
||||||
|
function TriggerConnector() {
|
||||||
|
const { gl, raycaster, scene } = useThree();
|
||||||
|
const { subModule } = useSubModuleStore();
|
||||||
|
const { getPointByUuid, getIsEventInProduct } = useProductStore();
|
||||||
|
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||||
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
const canvasElement = gl.domElement;
|
||||||
|
|
||||||
|
let drag = false;
|
||||||
|
let isRightMouseDown = false;
|
||||||
|
|
||||||
|
const onMouseDown = (evt: MouseEvent) => {
|
||||||
|
if (selectedAsset) {
|
||||||
|
clearSelectedAsset();
|
||||||
|
}
|
||||||
|
if (evt.button === 2) {
|
||||||
|
isRightMouseDown = true;
|
||||||
|
drag = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onMouseUp = (evt: MouseEvent) => {
|
||||||
|
if (evt.button === 2) {
|
||||||
|
isRightMouseDown = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onMouseMove = () => {
|
||||||
|
if (isRightMouseDown) {
|
||||||
|
drag = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRightClick = (evt: MouseEvent) => {
|
||||||
|
if (drag) return;
|
||||||
|
evt.preventDefault();
|
||||||
|
const canvasElement = gl.domElement;
|
||||||
|
if (!canvasElement) return;
|
||||||
|
|
||||||
|
let intersects = raycaster.intersectObjects(scene.children, true);
|
||||||
|
if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) {
|
||||||
|
let currentObject = intersects[0].object;
|
||||||
|
|
||||||
|
if (currentObject && currentObject.name === 'Event-Sphere') {
|
||||||
|
|
||||||
|
const isInProduct = getIsEventInProduct(
|
||||||
|
selectedProduct.productId,
|
||||||
|
currentObject.userData.modelUuid
|
||||||
|
);
|
||||||
|
|
||||||
|
// You left Here
|
||||||
|
|
||||||
|
if (isInProduct) {
|
||||||
|
|
||||||
|
const event = getPointByUuid(
|
||||||
|
selectedProduct.productId,
|
||||||
|
currentObject.userData.modelUuid,
|
||||||
|
currentObject.userData.pointUuid
|
||||||
|
);
|
||||||
|
console.log('event: ', event);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (subModule === 'simulations') {
|
||||||
|
canvasElement.addEventListener("mousedown", onMouseDown);
|
||||||
|
canvasElement.addEventListener("mouseup", onMouseUp);
|
||||||
|
canvasElement.addEventListener("mousemove", onMouseMove);
|
||||||
|
canvasElement.addEventListener('contextmenu', handleRightClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
canvasElement.removeEventListener("mousedown", onMouseDown);
|
||||||
|
canvasElement.removeEventListener("mouseup", onMouseUp);
|
||||||
|
canvasElement.removeEventListener("mousemove", onMouseMove);
|
||||||
|
canvasElement.removeEventListener('contextmenu', handleRightClick);
|
||||||
|
};
|
||||||
|
|
||||||
|
}, [gl, subModule]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TriggerConnector
|
||||||
14
app/src/modules/simulation/triggers/trigger.tsx
Normal file
14
app/src/modules/simulation/triggers/trigger.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import TriggerConnector from './connector/triggerConnector'
|
||||||
|
|
||||||
|
function Trigger() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
|
||||||
|
<TriggerConnector />
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Trigger
|
||||||
@@ -1,62 +1,172 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { useFrame, useThree } from '@react-three/fiber';
|
import { useFrame, useThree } from '@react-three/fiber';
|
||||||
|
import { useFloorItems } from '../../../../../store/store';
|
||||||
|
import * as THREE from 'three';
|
||||||
|
import { Line } from '@react-three/drei';
|
||||||
|
import { useAnimationPlaySpeed, usePauseButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||||
|
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
|
||||||
|
|
||||||
interface VehicleAnimatorProps {
|
interface VehicleAnimatorProps {
|
||||||
path: [number, number, number][];
|
path: [number, number, number][];
|
||||||
handleCallBack: () => void;
|
handleCallBack: () => void;
|
||||||
currentPhase: string;
|
currentPhase: string;
|
||||||
agvUuid: number
|
agvUuid: number;
|
||||||
|
agvDetail: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail }: VehicleAnimatorProps) {
|
||||||
function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid }: VehicleAnimatorProps) {
|
const { decrementVehicleLoad, vehicles } = useVehicleStore();
|
||||||
const [progress, setProgress] = useState<number>(0)
|
const { isPaused } = usePauseButtonStore();
|
||||||
|
const { speed } = useAnimationPlaySpeed();
|
||||||
|
const { isReset } = useResetButtonStore();
|
||||||
|
const [restRotation, setRestingRotation] = useState<boolean>(true);
|
||||||
|
const [progress, setProgress] = useState<number>(0);
|
||||||
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
|
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
|
||||||
const { scene } = useThree();
|
const { scene } = useThree();
|
||||||
|
const progressRef = useRef<number>(0);
|
||||||
|
const movingForward = useRef<boolean>(true);
|
||||||
|
const completedRef = useRef<boolean>(false);
|
||||||
|
let startTime: number;
|
||||||
|
let pausedTime: number;
|
||||||
|
let fixedInterval: number;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
if (currentPhase === 'stationed-pickup' && path.length > 0) {
|
if (currentPhase === 'stationed-pickup' && path.length > 0) {
|
||||||
setCurrentPath(path);
|
setCurrentPath(path);
|
||||||
|
} else if (currentPhase === 'pickup-drop' && path.length > 0) {
|
||||||
|
setCurrentPath(path);
|
||||||
|
} else if (currentPhase === 'drop-pickup' && path.length > 0) {
|
||||||
|
setCurrentPath(path);
|
||||||
}
|
}
|
||||||
|
}, [currentPhase, path]);
|
||||||
|
|
||||||
}, [currentPhase, path])
|
useEffect(() => {
|
||||||
|
setProgress(0);
|
||||||
|
completedRef.current = false;
|
||||||
|
}, [currentPath]);
|
||||||
|
|
||||||
useFrame((_, delta) => {
|
useFrame((_, delta) => {
|
||||||
if (!path || path.length < 2) return;
|
const object = scene.getObjectByProperty('uuid', agvUuid);
|
||||||
|
if (!object || currentPath.length < 2) return;
|
||||||
|
if (isPaused) return;
|
||||||
|
|
||||||
const object = scene.getObjectByProperty("uuid", agvUuid)
|
let totalDistance = 0;
|
||||||
if (!object) return;
|
const distances = [];
|
||||||
|
|
||||||
setProgress(prev => {
|
for (let i = 0; i < currentPath.length - 1; i++) {
|
||||||
const next = prev + delta * 0.1; // speed
|
const start = new THREE.Vector3(...currentPath[i]);
|
||||||
return next >= 1 ? 1 : next;
|
const end = new THREE.Vector3(...currentPath[i + 1]);
|
||||||
});
|
const segmentDistance = start.distanceTo(end);
|
||||||
|
distances.push(segmentDistance);
|
||||||
const totalSegments = path.length - 1;
|
totalDistance += segmentDistance;
|
||||||
const segmentIndex = Math.floor(progress * totalSegments);
|
|
||||||
const t = progress * totalSegments - segmentIndex;
|
|
||||||
|
|
||||||
const start = path[segmentIndex];
|
|
||||||
const end = path[segmentIndex + 1] || start;
|
|
||||||
|
|
||||||
// Directly set position without creating a new Vector3
|
|
||||||
object.position.x = start[0] + (end[0] - start[0]) * t;
|
|
||||||
object.position.y = start[1] + (end[1] - start[1]) * t;
|
|
||||||
object.position.z = start[2] + (end[2] - start[2]) * t;
|
|
||||||
});
|
|
||||||
// useFrame(() => {
|
|
||||||
// if (currentPath.length === 0) return;
|
|
||||||
// const object = scene.getObjectByProperty("uuid", agvUuid);
|
|
||||||
// if (!object) return;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// })
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default VehicleAnimator
|
let coveredDistance = progressRef.current;
|
||||||
|
let accumulatedDistance = 0;
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
|
while (
|
||||||
|
index < distances.length &&
|
||||||
|
coveredDistance > accumulatedDistance + distances[index]
|
||||||
|
) {
|
||||||
|
accumulatedDistance += distances[index];
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < distances.length) {
|
||||||
|
const start = new THREE.Vector3(...currentPath[index]);
|
||||||
|
const end = new THREE.Vector3(...currentPath[index + 1]);
|
||||||
|
const segmentDistance = distances[index];
|
||||||
|
|
||||||
|
const currentDirection = new THREE.Vector3().subVectors(end, start).normalize();
|
||||||
|
const targetAngle = Math.atan2(currentDirection.x, currentDirection.z);
|
||||||
|
const rotationSpeed = 2.0;
|
||||||
|
const currentAngle = object.rotation.y;
|
||||||
|
|
||||||
|
let angleDifference = targetAngle - currentAngle;
|
||||||
|
if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI;
|
||||||
|
if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI;
|
||||||
|
|
||||||
|
const maxRotationStep = rotationSpeed * delta;
|
||||||
|
object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep);
|
||||||
|
|
||||||
|
const isAligned = Math.abs(angleDifference) < 0.01;
|
||||||
|
|
||||||
|
if (isAligned) {
|
||||||
|
progressRef.current += delta * (speed * agvDetail.speed);
|
||||||
|
coveredDistance = progressRef.current;
|
||||||
|
|
||||||
|
const t = (coveredDistance - accumulatedDistance) / segmentDistance;
|
||||||
|
const position = start.clone().lerp(end, t);
|
||||||
|
object.position.copy(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progressRef.current >= totalDistance) {
|
||||||
|
if (restRotation) {
|
||||||
|
const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0));
|
||||||
|
object.quaternion.slerp(targetQuaternion, delta * 2);
|
||||||
|
const angleDiff = object.quaternion.angleTo(targetQuaternion);
|
||||||
|
if (angleDiff < 0.01) {
|
||||||
|
let objectRotation = agvDetail.point.rotation
|
||||||
|
object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]);
|
||||||
|
setRestingRotation(false);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progressRef.current >= totalDistance) {
|
||||||
|
setRestingRotation(true);
|
||||||
|
progressRef.current = 0;
|
||||||
|
movingForward.current = !movingForward.current;
|
||||||
|
setCurrentPath([]);
|
||||||
|
handleCallBack();
|
||||||
|
if (currentPhase === 'pickup-drop') {
|
||||||
|
requestAnimationFrame(firstFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function firstFrame() {
|
||||||
|
const unLoadDuration = agvDetail.point.action.unLoadDuration;
|
||||||
|
const droppedMaterial = agvDetail.currentLoad;
|
||||||
|
fixedInterval = (unLoadDuration / droppedMaterial) * 1000;
|
||||||
|
startTime = performance.now();
|
||||||
|
step(droppedMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
|
function step(droppedMaterial: number) {
|
||||||
|
const elapsedTime = performance.now() - startTime;
|
||||||
|
|
||||||
|
if (elapsedTime >= fixedInterval) {
|
||||||
|
console.log('fixedInterval: ', fixedInterval);
|
||||||
|
console.log('elapsedTime: ', elapsedTime);
|
||||||
|
let droppedMat = droppedMaterial - 1;
|
||||||
|
decrementVehicleLoad(agvDetail.modelUuid, 1);
|
||||||
|
if (droppedMat === 0) return;
|
||||||
|
startTime = performance.now();
|
||||||
|
requestAnimationFrame(() => step(droppedMat));
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(() => step(droppedMaterial));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{currentPath.length > 0 && (
|
||||||
|
<>
|
||||||
|
<Line points={currentPath} color="blue" lineWidth={3} />
|
||||||
|
{currentPath.map((point, index) => (
|
||||||
|
<mesh key={index} position={point}>
|
||||||
|
<sphereGeometry args={[0.1, 16, 16]} />
|
||||||
|
<meshStandardMaterial color="red" />
|
||||||
|
</mesh>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default VehicleAnimator;
|
||||||
@@ -1,66 +1,123 @@
|
|||||||
import React, { useCallback, useEffect, useState } from 'react'
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import VehicleAnimator from '../animator/vehicleAnimator'
|
import VehicleAnimator from '../animator/vehicleAnimator';
|
||||||
import * as THREE from "three";
|
import * as THREE from 'three';
|
||||||
import { NavMeshQuery } from '@recast-navigation/core';
|
import { NavMeshQuery } from '@recast-navigation/core';
|
||||||
import { useNavMesh } from '../../../../../store/store';
|
import { useNavMesh } from '../../../../../store/store';
|
||||||
import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
import { usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
|
||||||
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
|
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
|
||||||
|
|
||||||
function VehicleInstance({ agvDetails }: any) {
|
function VehicleInstance({ agvDetail }: any) {
|
||||||
const { navMesh } = useNavMesh();
|
const { navMesh } = useNavMesh();
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { setVehicleActive, setVehicleState } = useVehicleStore();
|
const { vehicles, setVehicleActive, setVehicleState, incrementVehicleLoad } = useVehicleStore();
|
||||||
const [currentPhase, setCurrentPhase] = useState<(string)>("stationed");
|
const [currentPhase, setCurrentPhase] = useState<string>('stationed');
|
||||||
const [path, setPath] = useState<[number, number, number][]>([]);
|
const [path, setPath] = useState<[number, number, number][]>([]);
|
||||||
|
|
||||||
const computePath = useCallback((start: any, end: any) => {
|
const computePath = useCallback(
|
||||||
|
(start: any, end: any) => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const navMeshQuery = new NavMeshQuery(navMesh);
|
const navMeshQuery = new NavMeshQuery(navMesh);
|
||||||
const { path: segmentPath } = navMeshQuery.computePath(start, end);
|
const { path: segmentPath } = navMeshQuery.computePath(start, end);
|
||||||
return (
|
return (
|
||||||
segmentPath?.map(
|
segmentPath?.map(({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]) || []
|
||||||
({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]
|
|
||||||
) || []
|
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}, [navMesh]);
|
},
|
||||||
|
[navMesh]
|
||||||
|
);
|
||||||
|
|
||||||
|
function vehicleStatus(modelid: string, status: string) {
|
||||||
|
// console.log(`AGV ${modelid}: ${status}`);
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
|
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
if (!agvDetails.isActive && agvDetails.state == "idle" && currentPhase == "stationed") {
|
if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') {
|
||||||
const toPickupPath = computePath(new THREE.Vector3(agvDetails.position[0], agvDetails.position[1], agvDetails.position[2]), agvDetails.point.action.pickUpPoint);
|
const toPickupPath = computePath(
|
||||||
setPath(toPickupPath)
|
new THREE.Vector3(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]),
|
||||||
setVehicleActive(agvDetails.modelUuid, true)
|
agvDetail.point.action.pickUpPoint
|
||||||
setVehicleState(agvDetails.modelUuid, "running")
|
);
|
||||||
setCurrentPhase("stationed-pickup")
|
setPath(toPickupPath);
|
||||||
//
|
setVehicleActive(agvDetail.modelUuid, true);
|
||||||
|
setVehicleState(agvDetail.modelUuid, 'running');
|
||||||
|
setCurrentPhase('stationed-pickup');
|
||||||
|
vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup');
|
||||||
|
return;
|
||||||
|
} else if (
|
||||||
|
!agvDetail.isActive &&
|
||||||
|
agvDetail.state === 'idle' &&
|
||||||
|
currentPhase === 'picking'
|
||||||
|
) {
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
incrementVehicleLoad(agvDetail.modelUuid, 2);
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) {
|
||||||
|
const toDrop = computePath(
|
||||||
|
agvDetail.point.action.pickUpPoint,
|
||||||
|
agvDetail.point.action.unLoadPoint
|
||||||
|
);
|
||||||
|
setPath(toDrop);
|
||||||
|
setVehicleActive(agvDetail.modelUuid, true);
|
||||||
|
setVehicleState(agvDetail.modelUuid, 'running');
|
||||||
|
setCurrentPhase('pickup-drop');
|
||||||
|
vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point');
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
!agvDetail.isActive &&
|
||||||
|
agvDetail.state === 'idle' &&
|
||||||
|
currentPhase === 'dropping' &&
|
||||||
|
agvDetail.currentLoad === 0
|
||||||
|
) {
|
||||||
|
const dropToPickup = computePath(
|
||||||
|
agvDetail.point.action.unLoadPoint,
|
||||||
|
agvDetail.point.action.pickUpPoint
|
||||||
|
);
|
||||||
|
setPath(dropToPickup);
|
||||||
|
setVehicleActive(agvDetail.modelUuid, true);
|
||||||
|
setVehicleState(agvDetail.modelUuid, 'running');
|
||||||
|
setCurrentPhase('drop-pickup');
|
||||||
|
vehicleStatus(agvDetail.modelUuid, 'Started from dropping point, heading to pickup point');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [agvDetails, currentPhase, path, isPlaying])
|
}, [vehicles, currentPhase, path, isPlaying]);
|
||||||
|
|
||||||
function handleCallBack() {
|
function handleCallBack() {
|
||||||
if (currentPhase === "stationed-pickup") {
|
if (currentPhase === 'stationed-pickup') {
|
||||||
setVehicleActive(agvDetails.modelUuid, false)
|
setVehicleActive(agvDetail.modelUuid, false);
|
||||||
setVehicleState(agvDetails.modelUuid, "idle")
|
setVehicleState(agvDetail.modelUuid, 'idle');
|
||||||
setCurrentPhase("picking")
|
setCurrentPhase('picking');
|
||||||
setPath([])
|
vehicleStatus(agvDetail.modelUuid, 'Reached pickup point, waiting for material');
|
||||||
|
setPath([]);
|
||||||
|
} else if (currentPhase === 'pickup-drop') {
|
||||||
|
setVehicleActive(agvDetail.modelUuid, false);
|
||||||
|
setVehicleState(agvDetail.modelUuid, 'idle');
|
||||||
|
setCurrentPhase('dropping');
|
||||||
|
vehicleStatus(agvDetail.modelUuid, 'Reached drop point');
|
||||||
|
setPath([]);
|
||||||
|
} else if (currentPhase === 'drop-pickup') {
|
||||||
|
setVehicleActive(agvDetail.modelUuid, false);
|
||||||
|
setVehicleState(agvDetail.modelUuid, 'idle');
|
||||||
|
setCurrentPhase('picking');
|
||||||
|
setPath([]);
|
||||||
|
vehicleStatus(agvDetail.modelUuid, 'Reached pickup point again, cycle complete');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<VehicleAnimator
|
||||||
<VehicleAnimator path={path} handleCallBack={handleCallBack} currentPhase={currentPhase} agvUuid={agvDetails?.modelUuid} />
|
path={path}
|
||||||
|
handleCallBack={handleCallBack}
|
||||||
|
currentPhase={currentPhase}
|
||||||
|
agvUuid={agvDetail?.modelUuid}
|
||||||
|
agvDetail={agvDetail}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default VehicleInstance
|
export default VehicleInstance;
|
||||||
@@ -1,15 +1,14 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import VehicleInstance from './instance/vehicleInstance'
|
import VehicleInstance from './instance/vehicleInstance'
|
||||||
import { useVehicleStore } from '../../../../store/simulation/useVehicleStore';
|
import { useVehicleStore } from '../../../../store/simulation/useVehicleStore'
|
||||||
|
|
||||||
function VehicleInstances() {
|
function VehicleInstances() {
|
||||||
const { vehicles } = useVehicleStore();
|
const { vehicles } = useVehicleStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
{vehicles.map((val: any, i: any) =>
|
{vehicles.map((val: any, i: any) =>
|
||||||
<VehicleInstance agvDetails={val} key={i} />
|
<VehicleInstance agvDetail={val} key={i} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export default function PolygonGenerator({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let allLines = arrayLinesToObject(lines.current);
|
let allLines = arrayLinesToObject(lines.current);
|
||||||
const wallLines = allLines?.filter((line) => line?.type === "WallLine");
|
const wallLines = allLines?.filter((line) => line?.type === "WallLine");
|
||||||
const aisleLines = allLines?.filter((line) => line?.type === "AisleLine");
|
const aisleLines = allLines?.filter((line) => line?.type === "AisleLine")
|
||||||
|
|
||||||
const wallPoints = wallLines
|
const wallPoints = wallLines
|
||||||
.map((pair) => pair?.line.map((vals) => vals.position))
|
.map((pair) => pair?.line.map((vals) => vals.position))
|
||||||
@@ -39,9 +39,10 @@ export default function PolygonGenerator({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
|
const polygons = turf.polygonize(turf.featureCollection(lineFeatures));
|
||||||
|
|
||||||
renderWallGeometry(wallPoints);
|
renderWallGeometry(wallPoints);
|
||||||
|
|
||||||
if (polygons.features.length > 1) {
|
if (polygons.features.length > 0) {
|
||||||
polygons.features.forEach((feature) => {
|
polygons.features.forEach((feature) => {
|
||||||
if (feature.geometry.type === "Polygon") {
|
if (feature.geometry.type === "Polygon") {
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import VehicleInstances from './instances/vehicleInstances';
|
import VehicleInstances from './instances/vehicleInstances';
|
||||||
|
|
||||||
import { useVehicleStore } from '../../../store/simulation/useVehicleStore';
|
import { useVehicleStore } from '../../../store/simulation/useVehicleStore';
|
||||||
|
import { useFloorItems } from '../../../store/store';
|
||||||
|
|
||||||
function Vehicles() {
|
function Vehicles() {
|
||||||
|
|
||||||
const { vehicles, addVehicle } = useVehicleStore();
|
const { vehicles, addVehicle } = useVehicleStore();
|
||||||
|
|
||||||
|
const { floorItems } = useFloorItems();
|
||||||
|
|
||||||
const vehicleStatusSample: VehicleEventSchema[] = [
|
const vehicleStatusSample: VehicleEventSchema[] = [
|
||||||
{
|
{
|
||||||
modelUuid: "veh-123",
|
modelUuid: "9356f710-4727-4b50-bdb2-9c1e747ecc74",
|
||||||
modelName: "Autonomous Truck A1",
|
modelName: "AGV",
|
||||||
position: [10, 0, 5],
|
position: [97.9252965204558, 0, 37.96138815638661],
|
||||||
rotation: [0, 0, 0],
|
rotation: [0, 0, 0],
|
||||||
state: "idle",
|
state: "idle",
|
||||||
type: "vehicle",
|
type: "vehicle",
|
||||||
@@ -24,11 +26,10 @@ function Vehicles() {
|
|||||||
actionUuid: "action-456",
|
actionUuid: "action-456",
|
||||||
actionName: "Deliver to Zone A",
|
actionName: "Deliver to Zone A",
|
||||||
actionType: "travel",
|
actionType: "travel",
|
||||||
material: "crate",
|
unLoadDuration: 10,
|
||||||
unLoadDuration: 15,
|
loadCapacity: 2,
|
||||||
loadCapacity: 5,
|
pickUpPoint: { x: 98.71483985219794, y: 0, z: 28.66321267938962 },
|
||||||
pickUpPoint: { x: 5, y: 0, z: 3 },
|
unLoadPoint: { x: 105.71483985219794, y: 0, z: 28.66321267938962 },
|
||||||
unLoadPoint: { x: 20, y: 0, z: 10 },
|
|
||||||
triggers: [
|
triggers: [
|
||||||
{
|
{
|
||||||
triggerUuid: "trig-001",
|
triggerUuid: "trig-001",
|
||||||
@@ -53,9 +54,51 @@ function Vehicles() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
modelUuid: "veh-123",
|
modelUuid: "b06960bb-3d2e-41f7-a646-335f389c68b4",
|
||||||
modelName: "Autonomous Truck A1",
|
modelName: "AGV",
|
||||||
position: [10, 0, 5],
|
position: [89.61609306554463, 0, 33.634136622267356],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
state: "idle",
|
||||||
|
type: "vehicle",
|
||||||
|
speed: 2.5,
|
||||||
|
point: {
|
||||||
|
uuid: "point-789",
|
||||||
|
position: [0, 1, 0],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
action: {
|
||||||
|
actionUuid: "action-456",
|
||||||
|
actionName: "Deliver to Zone A",
|
||||||
|
actionType: "travel",
|
||||||
|
unLoadDuration: 10,
|
||||||
|
loadCapacity: 2,
|
||||||
|
pickUpPoint: { x: 90, y: 0, z: 28 },
|
||||||
|
unLoadPoint: { x: 20, y: 0, z: 10 },
|
||||||
|
triggers: [
|
||||||
|
{
|
||||||
|
triggerUuid: "trig-001",
|
||||||
|
triggerName: "Start Travel",
|
||||||
|
triggerType: "onStart",
|
||||||
|
delay: 0,
|
||||||
|
triggeredAsset: {
|
||||||
|
triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" },
|
||||||
|
triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" },
|
||||||
|
triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
triggerUuid: "trig-002",
|
||||||
|
triggerName: "Complete Travel",
|
||||||
|
triggerType: "onComplete",
|
||||||
|
delay: 2,
|
||||||
|
triggeredAsset: null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
modelUuid: "e729a4f1-11d2-4778-8d6a-468f1b4f6b79",
|
||||||
|
modelName: "forklift",
|
||||||
|
position: [98.85729337188162, 0, 38.36616546567653],
|
||||||
rotation: [0, 0, 0],
|
rotation: [0, 0, 0],
|
||||||
state: "idle",
|
state: "idle",
|
||||||
type: "vehicle",
|
type: "vehicle",
|
||||||
@@ -68,10 +111,9 @@ function Vehicles() {
|
|||||||
actionUuid: "action-456",
|
actionUuid: "action-456",
|
||||||
actionName: "Deliver to Zone A",
|
actionName: "Deliver to Zone A",
|
||||||
actionType: "travel",
|
actionType: "travel",
|
||||||
material: "crate",
|
|
||||||
unLoadDuration: 15,
|
unLoadDuration: 15,
|
||||||
loadCapacity: 5,
|
loadCapacity: 5,
|
||||||
pickUpPoint: { x: 5, y: 0, z: 3 },
|
pickUpPoint: { x: 98.71483985219794, y: 0, z: 28.66321267938962 },
|
||||||
unLoadPoint: { x: 20, y: 0, z: 10 },
|
unLoadPoint: { x: 20, y: 0, z: 10 },
|
||||||
triggers: [
|
triggers: [
|
||||||
{
|
{
|
||||||
@@ -101,19 +143,18 @@ function Vehicles() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
addVehicle('123', vehicleStatusSample[0]);
|
addVehicle('123', vehicleStatusSample[0]);
|
||||||
addVehicle('123', vehicleStatusSample[1]);
|
// addVehicle('123', vehicleStatusSample[1]);
|
||||||
|
// addVehicle('123', vehicleStatusSample[2]);
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// console.log('vehicles: ', vehicles);
|
console.log('vehicles: ', vehicles);
|
||||||
}, [vehicles])
|
}, [vehicles])
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<VehicleInstances />
|
<VehicleInstances />
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,15 +12,12 @@ import {
|
|||||||
useFloatingWidget,
|
useFloatingWidget,
|
||||||
} from "../../store/visualization/useDroppedObjectsStore";
|
} from "../../store/visualization/useDroppedObjectsStore";
|
||||||
import {
|
import {
|
||||||
useAsset3dWidget,
|
|
||||||
useSocketStore,
|
useSocketStore,
|
||||||
useWidgetSubOption,
|
useWidgetSubOption,
|
||||||
useZones,
|
|
||||||
} from "../../store/store";
|
} from "../../store/store";
|
||||||
import { getZone2dData } from "../../services/visulization/zone/getZoneData";
|
import { getZone2dData } from "../../services/visulization/zone/getZoneData";
|
||||||
import { generateUniqueId } from "../../functions/generateUniqueId";
|
import { generateUniqueId } from "../../functions/generateUniqueId";
|
||||||
import { determinePosition } from "./functions/determinePosition";
|
import { determinePosition } from "./functions/determinePosition";
|
||||||
import { addingFloatingWidgets } from "../../services/visulization/zone/addFloatingWidgets";
|
|
||||||
import SocketRealTimeViz from "./socket/realTimeVizSocket.dev";
|
import SocketRealTimeViz from "./socket/realTimeVizSocket.dev";
|
||||||
import RenderOverlay from "../../components/templates/Overlay";
|
import RenderOverlay from "../../components/templates/Overlay";
|
||||||
import ConfirmationPopup from "../../components/layout/confirmationPopup/ConfirmationPopup";
|
import ConfirmationPopup from "../../components/layout/confirmationPopup/ConfirmationPopup";
|
||||||
@@ -68,20 +65,15 @@ const RealTimeVisulization: React.FC = () => {
|
|||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const [droppedObjects, setDroppedObjects] = useState<any[]>([]);
|
|
||||||
const [zonesData, setZonesData] = useState<FormattedZoneData>({});
|
const [zonesData, setZonesData] = useState<FormattedZoneData>({});
|
||||||
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
|
||||||
|
|
||||||
const { rightSelect, setRightSelect } = useRightSelected();
|
const { 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 { setFloatingWidget } = useFloatingWidget();
|
||||||
// const [floatingWidgets, setFloatingWidgets] = useState<Record<string, { zoneName: string; zoneId: string; objects: any[] }>>({});
|
const { widgetSubOption } = useWidgetSubOption();
|
||||||
const { floatingWidget, setFloatingWidget } = useFloatingWidget();
|
|
||||||
const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
|
|
||||||
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
|
|
||||||
const { visualizationSocket } = useSocketStore();
|
const { visualizationSocket } = useSocketStore();
|
||||||
const { setSelectedChartId } = useWidgetStore();
|
const { setSelectedChartId } = useWidgetStore();
|
||||||
|
|
||||||
@@ -99,11 +91,10 @@ const RealTimeVisulization: React.FC = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function GetZoneData() {
|
async function GetZoneData() {
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") ?? "";
|
||||||
const organization = email?.split("@")[1]?.split(".")[0];
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
try {
|
try {
|
||||||
const response = await getZone2dData(organization);
|
const response = await getZone2dData(organization);
|
||||||
// console.log('response: ', response);
|
|
||||||
|
|
||||||
if (!Array.isArray(response)) {
|
if (!Array.isArray(response)) {
|
||||||
return;
|
return;
|
||||||
@@ -125,7 +116,9 @@ const RealTimeVisulization: React.FC = () => {
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
setZonesData(formattedData);
|
setZonesData(formattedData);
|
||||||
} catch (error) {}
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GetZoneData();
|
GetZoneData();
|
||||||
@@ -151,12 +144,10 @@ const RealTimeVisulization: React.FC = () => {
|
|||||||
});
|
});
|
||||||
}, [selectedZone]);
|
}, [selectedZone]);
|
||||||
|
|
||||||
// useEffect(() => {}, [floatingWidgets]);
|
|
||||||
|
|
||||||
const handleDrop = async (event: React.DragEvent<HTMLDivElement>) => {
|
const handleDrop = async (event: React.DragEvent<HTMLDivElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
try {
|
try {
|
||||||
const email = localStorage.getItem("email") || "";
|
const email = localStorage.getItem("email") ?? "";
|
||||||
const organization = email?.split("@")[1]?.split(".")[0];
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
|
|
||||||
const data = event.dataTransfer.getData("text/plain");
|
const data = event.dataTransfer.getData("text/plain");
|
||||||
@@ -172,8 +163,8 @@ const RealTimeVisulization: React.FC = () => {
|
|||||||
const relativeY = event.clientY - rect.top;
|
const relativeY = event.clientY - rect.top;
|
||||||
|
|
||||||
// Widget dimensions
|
// Widget dimensions
|
||||||
const widgetWidth = droppedData.width || 125;
|
const widgetWidth = droppedData.width ?? 125;
|
||||||
const widgetHeight = droppedData.height || 100;
|
const widgetHeight = droppedData.height ?? 100;
|
||||||
|
|
||||||
// Center the widget at cursor
|
// Center the widget at cursor
|
||||||
const centerOffsetX = widgetWidth / 2;
|
const centerOffsetX = widgetWidth / 2;
|
||||||
@@ -275,7 +266,7 @@ const RealTimeVisulization: React.FC = () => {
|
|||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener("mousedown", handleClickOutside);
|
document.removeEventListener("mousedown", handleClickOutside);
|
||||||
};
|
};
|
||||||
}, [setRightClickSelected]);
|
}, [setRightClickSelected, setRightSelect]);
|
||||||
|
|
||||||
const [canvasDimensions, setCanvasDimensions] = useState({
|
const [canvasDimensions, setCanvasDimensions] = useState({
|
||||||
width: 0,
|
width: 0,
|
||||||
@@ -340,6 +331,7 @@ const RealTimeVisulization: React.FC = () => {
|
|||||||
borderRadius:
|
borderRadius:
|
||||||
isPlaying || activeModule !== "visualization" ? "" : "6px",
|
isPlaying || activeModule !== "visualization" ? "" : "6px",
|
||||||
}}
|
}}
|
||||||
|
role="application"
|
||||||
onDrop={(event) => handleDrop(event)}
|
onDrop={(event) => handleDrop(event)}
|
||||||
onDragOver={(event) => event.preventDefault()}
|
onDragOver={(event) => event.preventDefault()}
|
||||||
>
|
>
|
||||||
@@ -362,6 +354,10 @@ const RealTimeVisulization: React.FC = () => {
|
|||||||
"RotateY",
|
"RotateY",
|
||||||
"Delete",
|
"Delete",
|
||||||
]}
|
]}
|
||||||
|
onClick={(e) => {
|
||||||
|
setRightSelect(e);
|
||||||
|
setEditWidgetOptions(false);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,8 @@ import Dropped3dWidgets from './widgets/3d/Dropped3dWidget'
|
|||||||
import ZoneCentreTarget from './zone/zoneCameraTarget'
|
import ZoneCentreTarget from './zone/zoneCameraTarget'
|
||||||
import ZoneAssets from './zone/zoneAssets'
|
import ZoneAssets from './zone/zoneAssets'
|
||||||
import MqttEvents from '../../services/factoryBuilder/mqtt/mqttEvents'
|
import MqttEvents from '../../services/factoryBuilder/mqtt/mqttEvents'
|
||||||
import DrieHtmlTemp from './mqttTemp/drieHtmlTemp'
|
|
||||||
|
|
||||||
const Visualization = () => {
|
const Visualization:React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ import React, { useState, FormEvent } from "react";
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { LogoIconLarge } from "../components/icons/Logo";
|
import { LogoIconLarge } from "../components/icons/Logo";
|
||||||
import { EyeIcon } from "../components/icons/ExportCommonIcons";
|
import { EyeIcon } from "../components/icons/ExportCommonIcons";
|
||||||
import { useLoadingProgress, useOrganization, useUserName } from "../store/store";
|
import {
|
||||||
|
useLoadingProgress,
|
||||||
|
useOrganization,
|
||||||
|
useUserName,
|
||||||
|
} from "../store/store";
|
||||||
import { signInApi } from "../services/factoryBuilder/signInSignUp/signInApi";
|
import { signInApi } from "../services/factoryBuilder/signInSignUp/signInApi";
|
||||||
import { signUpApi } from "../services/factoryBuilder/signInSignUp/signUpApi";
|
import { signUpApi } from "../services/factoryBuilder/signInSignUp/signUpApi";
|
||||||
|
|
||||||
@@ -21,7 +25,7 @@ const UserAuth: React.FC = () => {
|
|||||||
const handleLogin = async (e: FormEvent<HTMLFormElement>) => {
|
const handleLogin = async (e: FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const organization = (email.split("@")[1]).split(".")[0];
|
const organization = email.split("@")[1].split(".")[0];
|
||||||
try {
|
try {
|
||||||
const res = await signInApi(email, password, organization);
|
const res = await signInApi(email, password, organization);
|
||||||
|
|
||||||
@@ -47,7 +51,7 @@ const UserAuth: React.FC = () => {
|
|||||||
if (email && password && userName) {
|
if (email && password && userName) {
|
||||||
setError("");
|
setError("");
|
||||||
try {
|
try {
|
||||||
const organization = (email.split("@")[1]).split(".")[0];
|
const organization = email.split("@")[1].split(".")[0];
|
||||||
const res = await signUpApi(userName, email, password, organization);
|
const res = await signUpApi(userName, email, password, organization);
|
||||||
|
|
||||||
if (res.message === "New User created") {
|
if (res.message === "New User created") {
|
||||||
@@ -63,7 +67,6 @@ const UserAuth: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<div className="auth-container">
|
<div className="auth-container">
|
||||||
<div className="logo-icon">
|
<div className="logo-icon">
|
||||||
<LogoIconLarge />
|
<LogoIconLarge />
|
||||||
@@ -172,7 +175,6 @@ const UserAuth: React.FC = () => {
|
|||||||
website.
|
website.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
26
app/src/services/simulation/UpsertProductOrEventApi.ts
Normal file
26
app/src/services/simulation/UpsertProductOrEventApi.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
|
||||||
|
export const upsertProductOrEventApi = async (body: any) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${url_Backend_dwinzo}/api/v2/UpsertProductOrEvent`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Failed to add product or event");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(error.message);
|
||||||
|
} else {
|
||||||
|
throw new Error("An unknown error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
26
app/src/services/simulation/deleteEventDataApi.ts
Normal file
26
app/src/services/simulation/deleteEventDataApi.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
|
||||||
|
export const deleteEventDataApi = async (body: any) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${url_Backend_dwinzo}/api/v2/EventDataDelete`, {
|
||||||
|
method: "PATCH",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Failed to delete event data");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(error.message);
|
||||||
|
} else {
|
||||||
|
throw new Error("An unknown error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
25
app/src/services/simulation/deleteProductDataApi.ts
Normal file
25
app/src/services/simulation/deleteProductDataApi.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
|
||||||
|
export const deleteProductDataApi = async (productId: string, organization: string) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${url_Backend_dwinzo}/api/v2/productDataDelete?productId=${productId}&organization=${organization}`, {
|
||||||
|
method: "PATCH",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Failed to delete product data");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(error.message);
|
||||||
|
} else {
|
||||||
|
throw new Error("An unknown error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
25
app/src/services/simulation/getProductApi.ts
Normal file
25
app/src/services/simulation/getProductApi.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
|
||||||
|
export const getProductApi = async (productId: string, organization: string) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${url_Backend_dwinzo}/api/v2/productDatas?productId=${productId}&organization=${organization}`, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Failed to fetch product data");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(error.message);
|
||||||
|
} else {
|
||||||
|
throw new Error("An unknown error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
25
app/src/services/simulation/getallProductsApi.ts
Normal file
25
app/src/services/simulation/getallProductsApi.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||||
|
|
||||||
|
export const getAllProductsApi = async ( organization: string) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${url_Backend_dwinzo}/api/v2/AllProducts/${organization}`, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Failed to fetch all products data");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
throw new Error(error.message);
|
||||||
|
} else {
|
||||||
|
throw new Error("An unknown error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -7,7 +7,7 @@ export const getSelect2dZoneData = async (
|
|||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${url_Backend_dwinzo}/api/v2/Zone/visualization/${ZoneId}?organization=${organization}`,
|
`${url_Backend_dwinzo}/api/v2/ZoneVisualization/${ZoneId}?organization=${organization}`,
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -17,8 +17,11 @@ interface ArmBotStore {
|
|||||||
addAction: (modelUuid: string, action: RoboticArmPointSchema['actions'][number]) => void;
|
addAction: (modelUuid: string, action: RoboticArmPointSchema['actions'][number]) => void;
|
||||||
removeAction: (modelUuid: string, actionUuid: string) => void;
|
removeAction: (modelUuid: string, actionUuid: string) => void;
|
||||||
|
|
||||||
setArmBotActive: (modelUuid: string, isActive: boolean) => void;
|
updateStartPoint: (modelUuid: string, actionUuid: string, startPoint: [number, number, number] | null) => void;
|
||||||
|
updateEndPoint: (modelUuid: string, actionUuid: string, endPoint: [number, number, number] | null) => void;
|
||||||
|
|
||||||
|
setArmBotActive: (modelUuid: string, isActive: boolean) => void;
|
||||||
|
setArmBotState: (modelUuid: string, newState: ArmBotStatus['state']) => void;
|
||||||
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
|
||||||
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
|
||||||
|
|
||||||
@@ -72,7 +75,6 @@ export const useArmBotStore = create<ArmBotStore>()(
|
|||||||
actionUuid: action.actionUuid,
|
actionUuid: action.actionUuid,
|
||||||
actionName: action.actionName,
|
actionName: action.actionName,
|
||||||
};
|
};
|
||||||
armBot.isActive = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -83,7 +85,6 @@ export const useArmBotStore = create<ArmBotStore>()(
|
|||||||
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
|
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
|
||||||
if (armBot) {
|
if (armBot) {
|
||||||
armBot.currentAction = undefined;
|
armBot.currentAction = undefined;
|
||||||
armBot.isActive = false;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -106,6 +107,30 @@ export const useArmBotStore = create<ArmBotStore>()(
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateStartPoint: (modelUuid, actionUuid, startPoint) => {
|
||||||
|
set((state) => {
|
||||||
|
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
|
||||||
|
if (armBot) {
|
||||||
|
const action = armBot.point.actions.find(a => a.actionUuid === actionUuid);
|
||||||
|
if (action) {
|
||||||
|
action.process.startPoint = startPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
updateEndPoint: (modelUuid, actionUuid, endPoint) => {
|
||||||
|
set((state) => {
|
||||||
|
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
|
||||||
|
if (armBot) {
|
||||||
|
const action = armBot.point.actions.find(a => a.actionUuid === actionUuid);
|
||||||
|
if (action) {
|
||||||
|
action.process.endPoint = endPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
setArmBotActive: (modelUuid, isActive) => {
|
setArmBotActive: (modelUuid, isActive) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
|
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
|
||||||
@@ -115,6 +140,15 @@ export const useArmBotStore = create<ArmBotStore>()(
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setArmBotState: (modelUuid, newState) => {
|
||||||
|
set((state) => {
|
||||||
|
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
|
||||||
|
if (armBot) {
|
||||||
|
armBot.state = newState;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
incrementActiveTime: (modelUuid, incrementBy) => {
|
incrementActiveTime: (modelUuid, incrementBy) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
|
const armBot = state.armBots.find(a => a.modelUuid === modelUuid);
|
||||||
|
|||||||
76
app/src/store/simulation/useMaterialStore.ts
Normal file
76
app/src/store/simulation/useMaterialStore.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
import { immer } from 'zustand/middleware/immer';
|
||||||
|
|
||||||
|
type MaterialsStore = {
|
||||||
|
materials: MaterialsSchema;
|
||||||
|
|
||||||
|
addMaterial: (material: MaterialSchema) => void;
|
||||||
|
removeMaterial: (materialId: string) => void;
|
||||||
|
updateMaterial: (materialId: string, updates: Partial<MaterialSchema>) => void;
|
||||||
|
|
||||||
|
setStartTime: (materialId: string, startTime: string) => void;
|
||||||
|
setEndTime: (materialId: string, endTime: string) => void;
|
||||||
|
setCost: (materialId: string, cost: number) => void;
|
||||||
|
setWeight: (materialId: string, weight: number) => void;
|
||||||
|
|
||||||
|
getMaterialById: (materialId: string) => MaterialSchema | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMaterialStore = create<MaterialsStore>()(
|
||||||
|
immer((set, get) => ({
|
||||||
|
materials: [],
|
||||||
|
|
||||||
|
addMaterial: (material) => {
|
||||||
|
set((state) => {
|
||||||
|
state.materials.push(material);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
removeMaterial: (materialId) => {
|
||||||
|
set((state) => {
|
||||||
|
state.materials = state.materials.filter(m => m.materialId !== materialId);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
updateMaterial: (materialId, updates) => {
|
||||||
|
set((state) => {
|
||||||
|
const material = state.materials.find(m => m.materialId === materialId);
|
||||||
|
if (material) {
|
||||||
|
Object.assign(material, updates);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setStartTime: (materialId, startTime) => {
|
||||||
|
set((state) => {
|
||||||
|
const material = state.materials.find(m => m.materialId === materialId);
|
||||||
|
if (material) material.startTime = startTime;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setEndTime: (materialId, endTime) => {
|
||||||
|
set((state) => {
|
||||||
|
const material = state.materials.find(m => m.materialId === materialId);
|
||||||
|
if (material) material.endTime = endTime;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setCost: (materialId, cost) => {
|
||||||
|
set((state) => {
|
||||||
|
const material = state.materials.find(m => m.materialId === materialId);
|
||||||
|
if (material) material.cost = cost;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setWeight: (materialId, weight) => {
|
||||||
|
set((state) => {
|
||||||
|
const material = state.materials.find(m => m.materialId === materialId);
|
||||||
|
if (material) material.weight = weight;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getMaterialById: (materialId) => {
|
||||||
|
return get().materials.find(m => m.materialId === materialId);
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
);
|
||||||
@@ -7,7 +7,7 @@ type ProductsStore = {
|
|||||||
// Product-level actions
|
// Product-level actions
|
||||||
addProduct: (productName: string, productId: string) => void;
|
addProduct: (productName: string, productId: string) => void;
|
||||||
removeProduct: (productId: string) => void;
|
removeProduct: (productId: string) => void;
|
||||||
updateProduct: (productId: string, updates: Partial<{ productName: string; eventsData: EventsSchema[] }>) => void;
|
updateProduct: (productId: string, updates: Partial<{ productName: string; eventDatas: EventsSchema[] }>) => void;
|
||||||
|
|
||||||
// Event-level actions
|
// Event-level actions
|
||||||
addEvent: (productId: string, event: EventsSchema) => void;
|
addEvent: (productId: string, event: EventsSchema) => void;
|
||||||
@@ -48,8 +48,18 @@ type ProductsStore = {
|
|||||||
updates: Partial<TriggerSchema>
|
updates: Partial<TriggerSchema>
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
|
// Renaming functions
|
||||||
|
renameProduct: (productId: string, newName: string) => void;
|
||||||
|
renameAction: (actionUuid: string, newName: string) => void;
|
||||||
|
renameTrigger: (triggerUuid: string, newName: string) => void;
|
||||||
|
|
||||||
// Helper functions
|
// Helper functions
|
||||||
getProductById: (productId: string) => { productName: string; productId: string; eventsData: EventsSchema[] } | undefined;
|
getProductById: (productId: string) => { productName: string; productId: string; eventDatas: EventsSchema[] } | undefined;
|
||||||
|
getEventByModelUuid: (productId: string, modelUuid: string) => EventsSchema | undefined;
|
||||||
|
getPointByUuid: (productId: string, modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined;
|
||||||
|
getActionByUuid: (productId: string, actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined;
|
||||||
|
getTriggerByUuid: (productId: string, triggerUuid: string) => TriggerSchema | undefined;
|
||||||
|
getIsEventInProduct: (productId: string, modelUuid: string) => boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useProductStore = create<ProductsStore>()(
|
export const useProductStore = create<ProductsStore>()(
|
||||||
@@ -62,7 +72,7 @@ export const useProductStore = create<ProductsStore>()(
|
|||||||
const newProduct = {
|
const newProduct = {
|
||||||
productName,
|
productName,
|
||||||
productId: productId,
|
productId: productId,
|
||||||
eventsData: []
|
eventDatas: []
|
||||||
};
|
};
|
||||||
state.products.push(newProduct);
|
state.products.push(newProduct);
|
||||||
});
|
});
|
||||||
@@ -88,7 +98,7 @@ export const useProductStore = create<ProductsStore>()(
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
const product = state.products.find(p => p.productId === productId);
|
const product = state.products.find(p => p.productId === productId);
|
||||||
if (product) {
|
if (product) {
|
||||||
product.eventsData.push(event);
|
product.eventDatas.push(event);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -97,7 +107,7 @@ export const useProductStore = create<ProductsStore>()(
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
const product = state.products.find(p => p.productId === productId);
|
const product = state.products.find(p => p.productId === productId);
|
||||||
if (product) {
|
if (product) {
|
||||||
product.eventsData = product.eventsData.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid);
|
product.eventDatas = product.eventDatas.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -106,7 +116,7 @@ export const useProductStore = create<ProductsStore>()(
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
const product = state.products.find(p => p.productId === productId);
|
const product = state.products.find(p => p.productId === productId);
|
||||||
if (product) {
|
if (product) {
|
||||||
const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||||
if (event) {
|
if (event) {
|
||||||
Object.assign(event, updates);
|
Object.assign(event, updates);
|
||||||
}
|
}
|
||||||
@@ -119,7 +129,7 @@ export const useProductStore = create<ProductsStore>()(
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
const product = state.products.find(p => p.productId === productId);
|
const product = state.products.find(p => p.productId === productId);
|
||||||
if (product) {
|
if (product) {
|
||||||
const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||||
if (event && 'points' in event) {
|
if (event && 'points' in event) {
|
||||||
(event as ConveyorEventSchema).points.push(point as ConveyorPointSchema);
|
(event as ConveyorEventSchema).points.push(point as ConveyorPointSchema);
|
||||||
} else if (event && 'point' in event) {
|
} else if (event && 'point' in event) {
|
||||||
@@ -133,7 +143,7 @@ export const useProductStore = create<ProductsStore>()(
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
const product = state.products.find(p => p.productId === productId);
|
const product = state.products.find(p => p.productId === productId);
|
||||||
if (product) {
|
if (product) {
|
||||||
const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||||
if (event && 'points' in event) {
|
if (event && 'points' in event) {
|
||||||
(event as ConveyorEventSchema).points = (event as ConveyorEventSchema).points.filter(p => p.uuid !== pointUuid);
|
(event as ConveyorEventSchema).points = (event as ConveyorEventSchema).points.filter(p => p.uuid !== pointUuid);
|
||||||
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
|
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
|
||||||
@@ -147,7 +157,7 @@ export const useProductStore = create<ProductsStore>()(
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
const product = state.products.find(p => p.productId === productId);
|
const product = state.products.find(p => p.productId === productId);
|
||||||
if (product) {
|
if (product) {
|
||||||
const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||||
if (event && 'points' in event) {
|
if (event && 'points' in event) {
|
||||||
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
|
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
|
||||||
if (point) {
|
if (point) {
|
||||||
@@ -165,7 +175,7 @@ export const useProductStore = create<ProductsStore>()(
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
const product = state.products.find(p => p.productId === productId);
|
const product = state.products.find(p => p.productId === productId);
|
||||||
if (product) {
|
if (product) {
|
||||||
const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||||
if (event && 'points' in event) {
|
if (event && 'points' in event) {
|
||||||
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
|
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
|
||||||
if (point) {
|
if (point) {
|
||||||
@@ -185,7 +195,7 @@ export const useProductStore = create<ProductsStore>()(
|
|||||||
removeAction: (actionUuid: string) => {
|
removeAction: (actionUuid: string) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
for (const product of state.products) {
|
for (const product of state.products) {
|
||||||
for (const event of product.eventsData) {
|
for (const event of product.eventDatas) {
|
||||||
if ('points' in event) {
|
if ('points' in event) {
|
||||||
// Handle ConveyorEventSchema
|
// Handle ConveyorEventSchema
|
||||||
for (const point of (event as ConveyorEventSchema).points) {
|
for (const point of (event as ConveyorEventSchema).points) {
|
||||||
@@ -209,7 +219,7 @@ export const useProductStore = create<ProductsStore>()(
|
|||||||
updateAction: (actionUuid, updates) => {
|
updateAction: (actionUuid, updates) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
for (const product of state.products) {
|
for (const product of state.products) {
|
||||||
for (const event of product.eventsData) {
|
for (const event of product.eventDatas) {
|
||||||
if ('points' in event) {
|
if ('points' in event) {
|
||||||
for (const point of (event as ConveyorEventSchema).points) {
|
for (const point of (event as ConveyorEventSchema).points) {
|
||||||
if (point.action && point.action.actionUuid === actionUuid) {
|
if (point.action && point.action.actionUuid === actionUuid) {
|
||||||
@@ -239,7 +249,7 @@ export const useProductStore = create<ProductsStore>()(
|
|||||||
addTrigger: (actionUuid, trigger) => {
|
addTrigger: (actionUuid, trigger) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
for (const product of state.products) {
|
for (const product of state.products) {
|
||||||
for (const event of product.eventsData) {
|
for (const event of product.eventDatas) {
|
||||||
if ('points' in event) {
|
if ('points' in event) {
|
||||||
for (const point of (event as ConveyorEventSchema).points) {
|
for (const point of (event as ConveyorEventSchema).points) {
|
||||||
if (point.action && point.action.actionUuid === actionUuid) {
|
if (point.action && point.action.actionUuid === actionUuid) {
|
||||||
@@ -268,7 +278,7 @@ export const useProductStore = create<ProductsStore>()(
|
|||||||
removeTrigger: (triggerUuid) => {
|
removeTrigger: (triggerUuid) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
for (const product of state.products) {
|
for (const product of state.products) {
|
||||||
for (const event of product.eventsData) {
|
for (const event of product.eventDatas) {
|
||||||
if ('points' in event) {
|
if ('points' in event) {
|
||||||
for (const point of (event as ConveyorEventSchema).points) {
|
for (const point of (event as ConveyorEventSchema).points) {
|
||||||
if (point.action && 'triggers' in point.action) {
|
if (point.action && 'triggers' in point.action) {
|
||||||
@@ -295,7 +305,7 @@ export const useProductStore = create<ProductsStore>()(
|
|||||||
updateTrigger: (triggerUuid, updates) => {
|
updateTrigger: (triggerUuid, updates) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
for (const product of state.products) {
|
for (const product of state.products) {
|
||||||
for (const event of product.eventsData) {
|
for (const event of product.eventDatas) {
|
||||||
if ('points' in event) {
|
if ('points' in event) {
|
||||||
for (const point of (event as ConveyorEventSchema).points) {
|
for (const point of (event as ConveyorEventSchema).points) {
|
||||||
if (point.action && 'triggers' in point.action) {
|
if (point.action && 'triggers' in point.action) {
|
||||||
@@ -331,9 +341,170 @@ export const useProductStore = create<ProductsStore>()(
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Renaming functions
|
||||||
|
renameProduct: (productId, newName) => {
|
||||||
|
set((state) => {
|
||||||
|
const product = state.products.find(p => p.productId === productId);
|
||||||
|
if (product) {
|
||||||
|
product.productName = newName;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
renameAction: (actionUuid, newName) => {
|
||||||
|
set((state) => {
|
||||||
|
for (const product of state.products) {
|
||||||
|
for (const event of product.eventDatas) {
|
||||||
|
if ('points' in event) {
|
||||||
|
for (const point of (event as ConveyorEventSchema).points) {
|
||||||
|
if (point.action && point.action.actionUuid === actionUuid) {
|
||||||
|
point.action.actionName = newName;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ('point' in event) {
|
||||||
|
const point = (event as any).point;
|
||||||
|
if ('action' in point && point.action.actionUuid === actionUuid) {
|
||||||
|
point.action.actionName = newName;
|
||||||
|
return;
|
||||||
|
} else if ('actions' in point) {
|
||||||
|
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||||
|
if (action) {
|
||||||
|
action.actionName = newName;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
renameTrigger: (triggerUuid, newName) => {
|
||||||
|
set((state) => {
|
||||||
|
for (const product of state.products) {
|
||||||
|
for (const event of product.eventDatas) {
|
||||||
|
if ('points' in event) {
|
||||||
|
for (const point of (event as ConveyorEventSchema).points) {
|
||||||
|
if (point.action && 'triggers' in point.action) {
|
||||||
|
const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid);
|
||||||
|
if (trigger) {
|
||||||
|
trigger.triggerName = newName;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ('point' in event) {
|
||||||
|
const point = (event as any).point;
|
||||||
|
if ('action' in point && 'triggers' in point.action) {
|
||||||
|
const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||||
|
if (trigger) {
|
||||||
|
trigger.triggerName = newName;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if ('actions' in point) {
|
||||||
|
for (const action of point.actions) {
|
||||||
|
if ('triggers' in action) {
|
||||||
|
const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||||
|
if (trigger) {
|
||||||
|
trigger.triggerName = newName;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// Helper functions
|
// Helper functions
|
||||||
getProductById: (productId) => {
|
getProductById: (productId) => {
|
||||||
return get().products.find(p => p.productId === productId);
|
return get().products.find(p => p.productId === productId);
|
||||||
|
},
|
||||||
|
|
||||||
|
getEventByModelUuid: (productId, modelUuid) => {
|
||||||
|
const product = get().getProductById(productId);
|
||||||
|
if (!product) return undefined;
|
||||||
|
return product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||||
|
},
|
||||||
|
|
||||||
|
getPointByUuid: (productId, modelUuid, pointUuid) => {
|
||||||
|
const event = get().getEventByModelUuid(productId, modelUuid);
|
||||||
|
if (!event) return undefined;
|
||||||
|
|
||||||
|
if ('points' in event) {
|
||||||
|
return (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
|
||||||
|
} else if ('point' in event && (event as any).point.uuid === pointUuid) {
|
||||||
|
return (event as VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema).point;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
|
||||||
|
getActionByUuid: (productId, actionUuid) => {
|
||||||
|
const product = get().products.find(p => p.productId === productId);
|
||||||
|
if (!product) return undefined;
|
||||||
|
|
||||||
|
for (const event of product.eventDatas) {
|
||||||
|
if ('points' in event) {
|
||||||
|
for (const point of (event as ConveyorEventSchema).points) {
|
||||||
|
if (point.action?.actionUuid === actionUuid) {
|
||||||
|
return point.action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ('point' in event) {
|
||||||
|
const point = (event as any).point;
|
||||||
|
if ('action' in point && point.action?.actionUuid === actionUuid) {
|
||||||
|
return point.action;
|
||||||
|
} else if ('actions' in point) {
|
||||||
|
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||||
|
if (action) return action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
|
||||||
|
getTriggerByUuid: (productId, triggerUuid) => {
|
||||||
|
const product = get().products.find(p => p.productId === productId);
|
||||||
|
if (!product) return undefined;
|
||||||
|
|
||||||
|
for (const event of product.eventDatas) {
|
||||||
|
if ('points' in event) {
|
||||||
|
for (const point of (event as ConveyorEventSchema).points) {
|
||||||
|
for (const trigger of point.action?.triggers || []) {
|
||||||
|
if (trigger.triggerUuid === triggerUuid) {
|
||||||
|
return trigger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ('point' in event) {
|
||||||
|
const point = (event as any).point;
|
||||||
|
if ('action' in point) {
|
||||||
|
for (const trigger of point.action?.triggers || []) {
|
||||||
|
if (trigger.triggerUuid === triggerUuid) {
|
||||||
|
return trigger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ('actions' in point) {
|
||||||
|
for (const action of point.actions) {
|
||||||
|
for (const trigger of action.triggers || []) {
|
||||||
|
if (trigger.triggerUuid === triggerUuid) {
|
||||||
|
return trigger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
|
||||||
|
getIsEventInProduct: (productId, modelUuid) => {
|
||||||
|
const product = get().getProductById(productId);
|
||||||
|
if (!product) return false;
|
||||||
|
return product.eventDatas.some(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|||||||
117
app/src/store/simulation/useSimulationStore.ts
Normal file
117
app/src/store/simulation/useSimulationStore.ts
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
import { immer } from 'zustand/middleware/immer';
|
||||||
|
import * as THREE from 'three';
|
||||||
|
|
||||||
|
interface SelectedEventSphereState {
|
||||||
|
selectedEventSphere: THREE.Mesh | null;
|
||||||
|
setSelectedEventSphere: (mesh: THREE.Mesh | null) => void;
|
||||||
|
clearSelectedEventSphere: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSelectedEventSphere = create<SelectedEventSphereState>()(
|
||||||
|
immer((set) => ({
|
||||||
|
selectedEventSphere: null,
|
||||||
|
setSelectedEventSphere: (mesh) => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedEventSphere = mesh;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clearSelectedEventSphere: () => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedEventSphere = null;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
interface SelectedEventDataState {
|
||||||
|
selectedEventData: { data: EventsSchema; selectedPoint: string } | undefined;
|
||||||
|
setSelectedEventData: (data: EventsSchema, selectedPoint: string) => void;
|
||||||
|
clearSelectedEventData: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSelectedEventData = create<SelectedEventDataState>()(
|
||||||
|
immer((set) => ({
|
||||||
|
selectedEventData: undefined,
|
||||||
|
setSelectedEventData: (data, selectedPoint) => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedEventData = { data, selectedPoint };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clearSelectedEventData: () => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedEventData = undefined;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
interface SelectedAssetState {
|
||||||
|
selectedAsset: EventsSchema | undefined;
|
||||||
|
setSelectedAsset: (EventData: EventsSchema) => void;
|
||||||
|
clearSelectedAsset: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSelectedAsset = create<SelectedAssetState>()(
|
||||||
|
immer((set) => ({
|
||||||
|
selectedAsset: undefined,
|
||||||
|
setSelectedAsset: (EventData) => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedAsset = EventData;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clearSelectedAsset: () => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedAsset = undefined;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
interface SelectedProductState {
|
||||||
|
selectedProduct: { productId: string; productName: string };
|
||||||
|
setSelectedProduct: (productId: string, productName: string) => void;
|
||||||
|
clearSelectedProduct: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSelectedProduct = create<SelectedProductState>()(
|
||||||
|
immer((set) => ({
|
||||||
|
selectedProduct: { productId: '', productName: '' },
|
||||||
|
setSelectedProduct: (productId, productName) => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedProduct.productId = productId;
|
||||||
|
state.selectedProduct.productName = productName;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clearSelectedProduct: () => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedProduct.productId = '';
|
||||||
|
state.selectedProduct.productName = '';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
interface SelectedActionState {
|
||||||
|
selectedAction: { actionId: string; actionName: string };
|
||||||
|
setSelectedAction: (actionId: string, actionName: string) => void;
|
||||||
|
clearSelectedAction: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSelectedAction = create<SelectedActionState>()(
|
||||||
|
immer((set) => ({
|
||||||
|
selectedAction: { actionId: '', actionName: '' },
|
||||||
|
setSelectedAction: (actionId, actionName) => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedAction.actionId = actionId;
|
||||||
|
state.selectedAction.actionName = actionName;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clearSelectedAction: () => {
|
||||||
|
set((state) => {
|
||||||
|
state.selectedAction.actionId = '';
|
||||||
|
state.selectedAction.actionName = '';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
);
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { immer } from 'zustand/middleware/immer';
|
import { immer } from 'zustand/middleware/immer';
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ export const useVehicleStore = create<VehiclesStore>()(
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
|
||||||
if (vehicle) {
|
if (vehicle) {
|
||||||
vehicle.currentLoad = decrementBy;
|
vehicle.currentLoad -= decrementBy;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,14 +13,17 @@ const useModuleStore = create<ModuleStore>((set) => ({
|
|||||||
export default useModuleStore;
|
export default useModuleStore;
|
||||||
|
|
||||||
// New store for subModule
|
// New store for subModule
|
||||||
|
|
||||||
|
type SubModule = 'properties' | 'simulations' | 'mechanics' | 'analysis' | 'zoneProperties';
|
||||||
|
|
||||||
interface SubModuleStore {
|
interface SubModuleStore {
|
||||||
subModule: string;
|
subModule: SubModule;
|
||||||
setSubModule: (subModule: string) => void;
|
setSubModule: (subModule: SubModule) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useSubModuleStore = create<SubModuleStore>((set) => ({
|
const useSubModuleStore = create<SubModuleStore>((set) => ({
|
||||||
subModule: "properties", // Initial subModule state
|
subModule: "properties", // Initial subModule state
|
||||||
setSubModule: (subModule) => set({ subModule }), // Update subModule state
|
setSubModule: (value) => set({ subModule: value }), // Update subModule state
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export { useSubModuleStore };
|
export { useSubModuleStore };
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
// center a element
|
|
||||||
%centered {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
@@ -1,123 +1,132 @@
|
|||||||
/* ========================================================================
|
|
||||||
Global SCSS Variables
|
|
||||||
========================================================================
|
|
||||||
This file contains the global variables used across the project for
|
|
||||||
colors, typography, spacing, shadows, and other design tokens.
|
|
||||||
======================================================================== */
|
|
||||||
|
|
||||||
@use "functions";
|
@use "functions";
|
||||||
|
|
||||||
// ========================================================================
|
|
||||||
// Font Imports
|
|
||||||
// ========================================================================
|
|
||||||
@import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Josefin+Sans:ital,wght@0,100..700;1,100..700&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto:ital,wght@0,100..900;1,100..900&display=swap");
|
@import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Josefin+Sans:ital,wght@0,100..700;1,100..700&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto:ital,wght@0,100..900;1,100..900&display=swap");
|
||||||
|
|
||||||
// ========================================================================
|
// new variables
|
||||||
// Colors
|
|
||||||
// ========================================================================
|
|
||||||
|
|
||||||
// Text colors
|
// text colors
|
||||||
$text-color: #2b3344; // Primary text color
|
// ---------- light mode ----------
|
||||||
$text-disabled: #b7b7c6; // Disabled text color
|
$text-color: #2b3344;
|
||||||
$input-text-color: #595965; // Input field text color
|
$text-disabled: #b7b7c6;
|
||||||
|
$input-text-color: #595965;
|
||||||
|
$highlight-text-color: #6f42c1;
|
||||||
|
|
||||||
$text-color-dark: #f3f3fd; // Primary text color for dark mode
|
// ---------- dark mode ----------
|
||||||
$text-disabled-dark: #6f6f7a; // Disabled text color for dark mode
|
$text-color-dark: #f3f3fd;
|
||||||
$input-text-color-dark: #b5b5c8; // Input field text color for dark mode
|
$text-disabled-dark: #6f6f7a;
|
||||||
|
$input-text-color-dark: #b5b5c8;
|
||||||
|
$highlight-text-color-dark: #B392F0;
|
||||||
|
|
||||||
// Accent colors
|
// background colors
|
||||||
$accent-color: #6f42c1; // Primary accent color
|
// ---------- light mode ----------
|
||||||
$accent-color-dark: #c4abf1; // Primary accent color for dark mode
|
$background-color: linear-gradient(-45deg, #FCFDFDCC 0%, #FCFDFD99 100%);
|
||||||
$highlight-accent-color: #e0dfff; // Highlighted accent for light mode
|
$background-color-secondary: #FCFDFD4D;
|
||||||
$highlight-accent-color-dark: #403e6a; // Highlighted accent for dark mode
|
$background-color-accent: #6f42c1;
|
||||||
|
$background-color-button: #6f42c1;
|
||||||
|
$background-color-drop-down: #6F42C14D;
|
||||||
|
$background-color-input: #FFFFFF4D;
|
||||||
|
$background-color-input-focus: #F2F2F7;
|
||||||
|
$background-color-drop-down-gradient: linear-gradient(-45deg, #75649366 0%, #40257266 100%);
|
||||||
|
$background-color-selected: #E0DFFF;
|
||||||
|
$background-radial-gray-gradient: radial-gradient(circle, #bfe0f8 0%, #e9ebff 46%, #e2acff 100%);
|
||||||
|
|
||||||
// Background colors
|
// ---------- dark mode ----------
|
||||||
$background-color: #fcfdfd; // Main background color
|
$background-color-dark: linear-gradient(-45deg, #333333B3 0%, #2D2437B3 100%);
|
||||||
$background-color-dark: #19191d; // Main background color for dark mode
|
$background-color-secondary-dark: #19191D99;
|
||||||
$background-color-secondary: #e1e0ff80; // Secondary background color
|
$background-color-accent-dark: #6f42c1;
|
||||||
$background-color-secondary-dark: #39394f99; // Secondary background color for dark mode
|
$background-color-button-dark: #6f42c1;
|
||||||
$background-color-gray: #f3f3f3; // Main background color
|
$background-color-drop-down-dark: #50505080;
|
||||||
$background-color-gray-dark: #232323; // Main background color for dark mode
|
$background-color-input-dark: #FFFFFF33;
|
||||||
|
$background-color-input-focus-dark: #333333;
|
||||||
|
$background-color-drop-down-gradient-dark: linear-gradient(-45deg, #8973B166 0%, #53427366 100%);
|
||||||
|
$background-color-selected-dark: #403E66;
|
||||||
|
$background-radial-gray-gradient-dark: radial-gradient(circle, #31373b 0%, #48494b 46%, #52415c 100%);
|
||||||
|
|
||||||
// Border colors
|
// border colors
|
||||||
$border-color: #e0dfff; // Default border color
|
// ---------- light mode ----------
|
||||||
$border-color-dark: #403e6a; // Border color for dark mode
|
$border-color: #E0DFFF;
|
||||||
|
$border-color-accent: #6F42C1;
|
||||||
|
|
||||||
// Shadow color
|
// ---------- dark mode ----------
|
||||||
$shadow-color: #3c3c431a; // Shadow base color for light and dark mode
|
$border-color-dark: #564B69;
|
||||||
$shadow-color-dark: #8f8f8f1a; // Shadow base color for light and dark mode
|
$border-color-accent-dark: #6F42C1;
|
||||||
|
|
||||||
// Gradients
|
// highlight colors
|
||||||
$acent-gradient-dark: linear-gradient(
|
// ---------- light mode ----------
|
||||||
90deg,
|
$highlight-accent-color: #E0DFFF;
|
||||||
#b392f0 0%,
|
$highlight-secondary-color: #6F42C1;
|
||||||
#a676ff 100%
|
|
||||||
); // Dark mode accent gradient
|
// ---------- dark mode ----------
|
||||||
$acent-gradient: linear-gradient(
|
$highlight-accent-color-dark: #403E6A;
|
||||||
90deg,
|
$highlight-secondary-color-dark: #C4ABF1;
|
||||||
#6f42c1 0%,
|
|
||||||
#925df3 100%
|
// colors
|
||||||
); // Light mode accent gradient
|
$color1: #A392CD;
|
||||||
|
$color2: #7b4cd3;
|
||||||
|
$color3: #B186FF;
|
||||||
|
$color4: #8752E8;
|
||||||
|
$color5: #C7A8FF;
|
||||||
|
|
||||||
|
|
||||||
|
// old variables
|
||||||
|
$accent-color: #6f42c1;
|
||||||
|
$accent-color-dark: #c4abf1;
|
||||||
|
$highlight-accent-color: #e0dfff;
|
||||||
|
$highlight-accent-color-dark: #403e6a;
|
||||||
|
|
||||||
|
$background-color: #fcfdfd;
|
||||||
|
$background-color-dark: #19191d;
|
||||||
|
$background-color-secondary: #e1e0ff80;
|
||||||
|
$background-color-secondary-dark: #39394f99;
|
||||||
|
$background-color-gray: #f3f3f3;
|
||||||
|
$background-color-gray-dark: #232323;
|
||||||
|
|
||||||
|
$border-color: #e0dfff;
|
||||||
|
$border-color-dark: #403e6a;
|
||||||
|
|
||||||
|
$shadow-color: #3c3c431a;
|
||||||
|
$shadow-color-dark: #8f8f8f1a;
|
||||||
|
|
||||||
|
$acent-gradient-dark: linear-gradient(90deg, #b392f0 0%, #a676ff 100%);
|
||||||
|
$acent-gradient: linear-gradient(90deg, #6f42c1 0%, #925df3 100%);
|
||||||
|
|
||||||
$faint-gradient: radial-gradient(circle, #bfe0f8 0%, #e9ebff 46%, #e2acff 100%);
|
$faint-gradient: radial-gradient(circle, #bfe0f8 0%, #e9ebff 46%, #e2acff 100%);
|
||||||
$faint-gradient-dark: radial-gradient(circle, #31373b 0%, #48494b 46%, #52415c 100%);
|
$faint-gradient-dark: radial-gradient(circle, #31373b 0%, #48494b 46%, #52415c 100%);
|
||||||
|
|
||||||
// ========================================================================
|
$font-inter: "Inter", sans-serif;
|
||||||
// Typography
|
$font-josefin-sans: "Josefin Sans", sans-serif;
|
||||||
// ========================================================================
|
$font-poppins: "Poppins", sans-serif;
|
||||||
|
$font-roboto: "Roboto", sans-serif;
|
||||||
|
|
||||||
// Font Family Variables
|
$tiny: 0.625rem;
|
||||||
$font-inter: "Inter", sans-serif; // Inter font
|
$small: 0.75rem;
|
||||||
$font-josefin-sans: "Josefin Sans", sans-serif; // Josefin Sans font
|
$regular: 0.8rem;
|
||||||
$font-poppins: "Poppins", sans-serif; // Poppins font
|
$large: 1rem;
|
||||||
$font-roboto: "Roboto", sans-serif; // Roboto font
|
$xlarge: 1.125rem;
|
||||||
|
$xxlarge: 1.5rem;
|
||||||
|
$xxxlarge: 2rem;
|
||||||
|
|
||||||
// Font sizes (converted to rem using a utility function)
|
$thin-weight: 300;
|
||||||
$tiny: 0.625rem; // Extra small text (10px)
|
$regular-weight: 400;
|
||||||
$small: 0.75rem; // Small text (12px)
|
$medium-weight: 500;
|
||||||
$regular: 0.8rem; // Default text size (14px)
|
$bold-weight: 600;
|
||||||
$large: 1rem; // Large text size (16px)
|
|
||||||
$xlarge: 1.125rem; // Extra large text size (18px)
|
|
||||||
$xxlarge: 1.5rem; // Double extra large text size (24px)
|
|
||||||
$xxxlarge: 2rem; // Triple extra large text size (32px)
|
|
||||||
|
|
||||||
// Font weights
|
$z-index-drei-html: 1;
|
||||||
$thin-weight: 300; // Regular font weight
|
$z-index-default: 1;
|
||||||
$regular-weight: 400; // Regular font weight
|
$z-index-marketplace: 2;
|
||||||
$medium-weight: 500; // Medium font weight
|
$z-index-tools: 3;
|
||||||
$bold-weight: 600; // Bold font weight
|
$z-index-negative: -1;
|
||||||
|
$z-index-ui-base: 10;
|
||||||
|
$z-index-ui-overlay: 20;
|
||||||
|
$z-index-ui-popup: 30;
|
||||||
|
$z-index-ui-highest: 50;
|
||||||
|
|
||||||
// ========================================================================
|
$box-shadow-light: 0px 2px 4px $shadow-color;
|
||||||
// Z-Index Levels
|
$box-shadow-medium: 0px 4px 8px $shadow-color;
|
||||||
// ========================================================================
|
$box-shadow-heavy: 0px 8px 16px $shadow-color;
|
||||||
|
|
||||||
// Z-index variables for layering
|
$border-radius-small: 4px;
|
||||||
$z-index-drei-html: 1; // For drei's Html components
|
$border-radius-medium: 6px;
|
||||||
$z-index-default: 1; // For drei's Html components
|
$border-radius-large: 12px;
|
||||||
$z-index-marketplace: 2; // For drei's Html components
|
$border-radius-circle: 50%;
|
||||||
$z-index-tools: 3; // For drei's Html components
|
$border-radius-extra-large: 20px;
|
||||||
$z-index-negative: -1; // For drei's Html components
|
|
||||||
$z-index-ui-base: 10; // Base UI elements
|
|
||||||
$z-index-ui-overlay: 20; // Overlay UI elements (e.g., modals, tooltips)
|
|
||||||
$z-index-ui-popup: 30; // Popups, dialogs, or higher-priority UI elements
|
|
||||||
$z-index-ui-highest: 50; // Highest priority elements (e.g., notifications, loading screens)
|
|
||||||
|
|
||||||
// ========================================================================
|
|
||||||
// Shadows
|
|
||||||
// ========================================================================
|
|
||||||
|
|
||||||
// Box shadow variables
|
|
||||||
$box-shadow-light: 0px 2px 4px $shadow-color; // Light shadow
|
|
||||||
$box-shadow-medium: 0px 4px 8px $shadow-color; // Medium shadow
|
|
||||||
$box-shadow-heavy: 0px 8px 16px $shadow-color; // Heavy shadow
|
|
||||||
|
|
||||||
// ========================================================================
|
|
||||||
// Border Radius
|
|
||||||
// ========================================================================
|
|
||||||
|
|
||||||
// Border radius variables
|
|
||||||
$border-radius-small: 4px; // Small rounded corners
|
|
||||||
$border-radius-medium: 6px; // Medium rounded corners
|
|
||||||
$border-radius-large: 12px; // Large rounded corners
|
|
||||||
$border-radius-circle: 50%; // Fully circular
|
|
||||||
$border-radius-extra-large: 20px; // Extra-large rounded corners
|
|
||||||
|
|||||||
5
app/src/styles/base/global.scss
Normal file
5
app/src/styles/base/global.scss
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
section, .section{
|
||||||
|
padding: 12px;
|
||||||
|
outline: 1px solid var(--border-color);
|
||||||
|
border-radius: 16px;
|
||||||
|
}
|
||||||
@@ -12,3 +12,10 @@ input[type="password"]::-webkit-clear-button, /* For Chrome/Safari clear button
|
|||||||
input[type="password"]::-webkit-inner-spin-button { /* Just in case */
|
input[type="password"]::-webkit-inner-spin-button { /* Just in case */
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button{
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
background: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
@@ -366,15 +366,66 @@
|
|||||||
min-height: 50vh;
|
min-height: 50vh;
|
||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
overflow: auto;
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.sidebar-right-content-container {
|
.sidebar-right-content-container {
|
||||||
border-bottom: 1px solid var(--border-color);
|
border-bottom: 1px solid var(--border-color);
|
||||||
// flex: 1;
|
|
||||||
height: calc(100% - 36px);
|
height: calc(100% - 36px);
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: auto;
|
width: 320px;
|
||||||
|
.no-event-selected {
|
||||||
|
color: #666;
|
||||||
|
padding: 1.8rem 1rem;
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
.products-list {
|
||||||
|
padding-top: 1rem;
|
||||||
|
.products-list-title {
|
||||||
|
text-align: start;
|
||||||
|
color: var(--accent-color);
|
||||||
|
font-size: var(--font-size-regular);
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
li {
|
||||||
|
text-align: start;
|
||||||
|
margin: 8px 0;
|
||||||
|
padding: 2px 0;
|
||||||
|
text-decoration: none;
|
||||||
|
&::marker {
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
width: fit-content;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
@include flex-center;
|
||||||
|
gap: 4px;
|
||||||
|
&:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: -4px;
|
||||||
|
background: var(--accent-color);
|
||||||
|
height: 1px;
|
||||||
|
width: 0%;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
button {
|
||||||
|
path {
|
||||||
|
stroke: var(--accent-color);
|
||||||
|
stroke-width: 1.5px;
|
||||||
|
}
|
||||||
|
color: var(--accent-color);
|
||||||
|
&:before {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -675,10 +726,14 @@
|
|||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
border-radius: #{$border-radius-small};
|
border-radius: #{$border-radius-small};
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
path {
|
path {
|
||||||
stroke: var(--primary-color);
|
stroke: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
&:disabled {
|
||||||
|
background-color: var(--text-disabled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -747,14 +802,15 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 2px 0;
|
margin: 2px 0;
|
||||||
border-radius: #{$border-radius-small};
|
border-radius: #{$border-radius-small};
|
||||||
}
|
|
||||||
|
|
||||||
.value {
|
.value {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-width: 80%;
|
min-width: 80%;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
.input-value {
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
@@ -762,6 +818,7 @@
|
|||||||
accent-color: var(--accent-color);
|
accent-color: var(--accent-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.active {
|
.active {
|
||||||
background: var(--highlight-accent-color);
|
background: var(--highlight-accent-color);
|
||||||
@@ -797,6 +854,7 @@
|
|||||||
@include flex-center;
|
@include flex-center;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
cursor: grabbing;
|
cursor: grabbing;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
// abstracts
|
// abstracts
|
||||||
@use 'abstracts/variables';
|
@use 'abstracts/variables';
|
||||||
@use 'abstracts/mixins';
|
@use 'abstracts/mixins';
|
||||||
@use 'abstracts/placeholders';
|
|
||||||
@use 'abstracts/functions';
|
@use 'abstracts/functions';
|
||||||
|
|
||||||
// base
|
// base
|
||||||
@use 'base/reset';
|
@use 'base/reset';
|
||||||
@use 'base/typography';
|
@use 'base/typography';
|
||||||
|
@use 'base/global';
|
||||||
@use 'base/base';
|
@use 'base/base';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
|
|||||||
@@ -776,13 +776,13 @@
|
|||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
|
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
|
|
||||||
.option {
|
.option {
|
||||||
padding: 4px 10px;
|
padding: 4px 10px;
|
||||||
border-radius: #{$border-radius-small};
|
border-radius: #{$border-radius-small};
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
|
text-wrap: nowrap;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
@@ -794,8 +794,8 @@
|
|||||||
color: #f65648;
|
color: #f65648;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #f65648;
|
background-color: #f657484d;
|
||||||
color: white;
|
color: #f65648;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
21
app/src/types/simulationTypes.d.ts
vendored
21
app/src/types/simulationTypes.d.ts
vendored
@@ -25,7 +25,7 @@ interface ConveyorPointSchema {
|
|||||||
action: {
|
action: {
|
||||||
actionUuid: string;
|
actionUuid: string;
|
||||||
actionName: string;
|
actionName: string;
|
||||||
actionType: "default" | "spawn" | "swap" | "despawn";
|
actionType: "default" | "spawn" | "swap" | "delay" | "despawn";
|
||||||
material: string;
|
material: string;
|
||||||
delay: number | "inherit";
|
delay: number | "inherit";
|
||||||
spawnInterval: number | "inherit";
|
spawnInterval: number | "inherit";
|
||||||
@@ -42,7 +42,6 @@ interface VehiclePointSchema {
|
|||||||
actionUuid: string;
|
actionUuid: string;
|
||||||
actionName: string;
|
actionName: string;
|
||||||
actionType: "travel";
|
actionType: "travel";
|
||||||
material: string | null;
|
|
||||||
unLoadDuration: number;
|
unLoadDuration: number;
|
||||||
loadCapacity: number;
|
loadCapacity: number;
|
||||||
pickUpPoint: { x: number; y: number, z: number } | null;
|
pickUpPoint: { x: number; y: number, z: number } | null;
|
||||||
@@ -119,12 +118,14 @@ interface StorageEventSchema extends AssetEventSchema {
|
|||||||
point: StoragePointSchema;
|
point: StoragePointSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PointsScheme = ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema;
|
||||||
|
|
||||||
type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema;
|
type EventsSchema = ConveyorEventSchema | VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema;
|
||||||
|
|
||||||
type productsSchema = {
|
type productsSchema = {
|
||||||
productName: string;
|
productName: string;
|
||||||
productId: string;
|
productId: string;
|
||||||
eventsData: EventsSchema[];
|
eventDatas: EventsSchema[];
|
||||||
}[]
|
}[]
|
||||||
|
|
||||||
|
|
||||||
@@ -133,6 +134,7 @@ interface ConveyorStatus extends ConveyorEventSchema {
|
|||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
idleTime: number;
|
idleTime: number;
|
||||||
activeTime: number;
|
activeTime: number;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MachineStatus extends MachineEventSchema {
|
interface MachineStatus extends MachineEventSchema {
|
||||||
@@ -169,3 +171,16 @@ interface StorageUnitStatus extends StorageEventSchema {
|
|||||||
activeTime: number;
|
activeTime: number;
|
||||||
currentLoad: number;
|
currentLoad: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface MaterialSchema {
|
||||||
|
materialId: string;
|
||||||
|
materialName: string;
|
||||||
|
materialType: string;
|
||||||
|
isActive: boolean;
|
||||||
|
startTime?: string;
|
||||||
|
endTime?: string;
|
||||||
|
cost?: number;
|
||||||
|
weight?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type MaterialsSchema = MaterialSchema[];
|
||||||
Reference in New Issue
Block a user