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 is contained in:
commit
ad833cc8e3
|
@ -42,44 +42,46 @@ export function FlipXAxisIcon() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FlipYAxisIcon() {
|
export function FlipYAxisIcon() {
|
||||||
<svg
|
return (
|
||||||
width="12"
|
<svg
|
||||||
height="12"
|
width="12"
|
||||||
viewBox="0 0 12 12"
|
height="12"
|
||||||
fill="none"
|
viewBox="0 0 12 12"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
fill="none"
|
||||||
>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
<path
|
>
|
||||||
d="M9.0568 11H2.94321C2.09213 11 1.6666 11 1.52703 10.7288C1.38746 10.4576 1.6348 10.1113 2.12947 9.41877L2.6942 8.62814C2.91415 8.32021 3.02413 8.16625 3.18565 8.08313C3.34718 8 3.53639 8 3.9148 8H8.08525C8.46365 8 8.65285 8 8.8144 8.08313C8.9759 8.16625 9.0859 8.32021 9.30585 8.62814L9.87055 9.41876C10.3653 10.1113 10.6126 10.4576 10.473 10.7288C10.3335 11 9.9079 11 9.0568 11Z"
|
<path
|
||||||
fill="var(--text-color)"
|
d="M9.0568 11H2.94321C2.09213 11 1.6666 11 1.52703 10.7288C1.38746 10.4576 1.6348 10.1113 2.12947 9.41877L2.6942 8.62814C2.91415 8.32021 3.02413 8.16625 3.18565 8.08313C3.34718 8 3.53639 8 3.9148 8H8.08525C8.46365 8 8.65285 8 8.8144 8.08313C8.9759 8.16625 9.0859 8.32021 9.30585 8.62814L9.87055 9.41876C10.3653 10.1113 10.6126 10.4576 10.473 10.7288C10.3335 11 9.9079 11 9.0568 11Z"
|
||||||
/>
|
fill="var(--text-color)"
|
||||||
<path
|
/>
|
||||||
d="M2.99935 3.15388L2.99936 3.1539C3.11318 3.31326 3.18452 3.41252 3.2461 3.48409C3.30271 3.54989 3.33407 3.57152 3.3572 3.58344L2.99935 3.15388ZM2.99935 3.15388L2.43462 2.36329C2.43462 2.36329 2.43462 2.36328 2.43462 2.36328C2.17987 2.00663 2.01464 1.7736 1.92406 1.59704C1.88093 1.51299 1.86801 1.46687 1.86465 1.44495C1.88444 1.43495 1.92948 1.41866 2.02293 1.4049C2.21925 1.37599 2.50491 1.375 2.94321 1.375L9.0568 1.375C9.49511 1.375 9.78078 1.37599 9.9771 1.4049C10.0705 1.41866 10.1156 1.43494 10.1354 1.44495C10.132 1.46687 10.1191 1.51299 10.076 1.59705C9.98539 1.7736 9.82016 2.00663 9.5654 2.36328L9.5654 2.36329L9.0007 3.15389L9.00069 3.15389M2.99935 3.15388L9.00069 3.15389M9.00069 3.15389C8.88688 3.31325 8.81553 3.41252 8.75395 3.48409C8.69737 3.54985 8.666 3.5715 8.64287 3.58343C8.61972 3.59534 8.5839 3.60831 8.49735 3.61614C8.40331 3.62465 8.28108 3.625 8.08525 3.625L3.9148 3.625C3.71896 3.625 3.59672 3.62465 3.50269 3.61614M9.00069 3.15389L3.50269 3.61614M3.50269 3.61614C3.41623 3.60832 3.38041 3.59537 3.35729 3.58348L3.50269 3.61614ZM1.86435 1.42845C1.86468 1.42867 1.86476 1.43108 1.86363 1.43501C1.86345 1.4302 1.86402 1.42823 1.86435 1.42845ZM1.85597 1.4499C1.85343 1.45311 1.85142 1.45444 1.85105 1.4543C1.85068 1.45416 1.85195 1.45255 1.85597 1.4499ZM10.149 1.45429C10.1486 1.45443 10.1466 1.4531 10.1441 1.44989C10.1481 1.45254 10.1493 1.45415 10.149 1.45429ZM10.1364 1.435C10.1353 1.43107 10.1353 1.42867 10.1357 1.42845C10.136 1.42823 10.1366 1.4302 10.1364 1.435Z"
|
<path
|
||||||
stroke="var(--text-color)"
|
d="M2.99935 3.15388L2.99936 3.1539C3.11318 3.31326 3.18452 3.41252 3.2461 3.48409C3.30271 3.54989 3.33407 3.57152 3.3572 3.58344L2.99935 3.15388ZM2.99935 3.15388L2.43462 2.36329C2.43462 2.36329 2.43462 2.36328 2.43462 2.36328C2.17987 2.00663 2.01464 1.7736 1.92406 1.59704C1.88093 1.51299 1.86801 1.46687 1.86465 1.44495C1.88444 1.43495 1.92948 1.41866 2.02293 1.4049C2.21925 1.37599 2.50491 1.375 2.94321 1.375L9.0568 1.375C9.49511 1.375 9.78078 1.37599 9.9771 1.4049C10.0705 1.41866 10.1156 1.43494 10.1354 1.44495C10.132 1.46687 10.1191 1.51299 10.076 1.59705C9.98539 1.7736 9.82016 2.00663 9.5654 2.36328L9.5654 2.36329L9.0007 3.15389L9.00069 3.15389M2.99935 3.15388L9.00069 3.15389M9.00069 3.15389C8.88688 3.31325 8.81553 3.41252 8.75395 3.48409C8.69737 3.54985 8.666 3.5715 8.64287 3.58343C8.61972 3.59534 8.5839 3.60831 8.49735 3.61614C8.40331 3.62465 8.28108 3.625 8.08525 3.625L3.9148 3.625C3.71896 3.625 3.59672 3.62465 3.50269 3.61614M9.00069 3.15389L3.50269 3.61614M3.50269 3.61614C3.41623 3.60832 3.38041 3.59537 3.35729 3.58348L3.50269 3.61614ZM1.86435 1.42845C1.86468 1.42867 1.86476 1.43108 1.86363 1.43501C1.86345 1.4302 1.86402 1.42823 1.86435 1.42845ZM1.85597 1.4499C1.85343 1.45311 1.85142 1.45444 1.85105 1.4543C1.85068 1.45416 1.85195 1.45255 1.85597 1.4499ZM10.149 1.45429C10.1486 1.45443 10.1466 1.4531 10.1441 1.44989C10.1481 1.45254 10.1493 1.45415 10.149 1.45429ZM10.1364 1.435C10.1353 1.43107 10.1353 1.42867 10.1357 1.42845C10.136 1.42823 10.1366 1.4302 10.1364 1.435Z"
|
||||||
strokeWidth="0.75"
|
stroke="var(--text-color)"
|
||||||
/>
|
strokeWidth="0.75"
|
||||||
<path
|
/>
|
||||||
opacity="0.5"
|
<path
|
||||||
d="M7 6H5"
|
opacity="0.5"
|
||||||
stroke="var(--text-color)"
|
d="M7 6H5"
|
||||||
strokeWidth="0.75"
|
stroke="var(--text-color)"
|
||||||
strokeLinecap="round"
|
strokeWidth="0.75"
|
||||||
/>
|
strokeLinecap="round"
|
||||||
<path
|
/>
|
||||||
opacity="0.5"
|
<path
|
||||||
d="M3 6H1"
|
opacity="0.5"
|
||||||
stroke="var(--text-color)"
|
d="M3 6H1"
|
||||||
strokeWidth="0.75"
|
stroke="var(--text-color)"
|
||||||
strokeLinecap="round"
|
strokeWidth="0.75"
|
||||||
/>
|
strokeLinecap="round"
|
||||||
<path
|
/>
|
||||||
opacity="0.5"
|
<path
|
||||||
d="M11 6H9"
|
opacity="0.5"
|
||||||
stroke="var(--text-color)"
|
d="M11 6H9"
|
||||||
strokeWidth="0.75"
|
stroke="var(--text-color)"
|
||||||
strokeLinecap="round"
|
strokeWidth="0.75"
|
||||||
/>
|
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();
|
||||||
|
useEffect(() => {
|
||||||
|
const event = getCurrentEventData();
|
||||||
|
setCurrentEventData(event);
|
||||||
|
|
||||||
|
const type = determineAssetType(event);
|
||||||
|
setAssetType(type);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [selectedEventData, selectedProduct]);
|
||||||
|
|
||||||
|
const getCurrentEventData = () => {
|
||||||
|
if (!selectedEventData?.data || !selectedProduct) return null;
|
||||||
|
return (
|
||||||
|
getEventByModelUuid(
|
||||||
|
selectedProduct.productId,
|
||||||
|
selectedEventData.data.modelUuid
|
||||||
|
) ?? null
|
||||||
|
);
|
||||||
};
|
};
|
||||||
selectedItem: {
|
|
||||||
item: {
|
|
||||||
uuid: string;
|
|
||||||
name: string;
|
|
||||||
} | null;
|
|
||||||
};
|
|
||||||
setSelectedPoint: (value: string) => void;
|
|
||||||
selectedActionSphere: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const EventProperties: React.FC<EventPropertiesProps> = ({
|
const determineAssetType = (event: EventsSchema | null) => {
|
||||||
assetType,
|
if (!event) return null;
|
||||||
selectedPoint,
|
|
||||||
selectedItem,
|
|
||||||
setSelectedPoint,
|
|
||||||
selectedActionSphere,
|
|
||||||
}) => {
|
|
||||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
const [activeOption, setActiveOption] = useState("default");
|
switch (event.type) {
|
||||||
const [dummyactiveOption, setTypeOption] = useState("default");
|
case "transfer":
|
||||||
|
return "conveyor";
|
||||||
const getAvailableActions = () => {
|
case "vehicle":
|
||||||
if (assetType === "conveyor") {
|
return "vehicle";
|
||||||
return {
|
case "roboticArm":
|
||||||
defaultOption: "default",
|
return "roboticArm";
|
||||||
options: ["default", "spawn", "swap", "despawn"],
|
case "machine":
|
||||||
};
|
return "machine";
|
||||||
}
|
case "storageUnit":
|
||||||
if (assetType === "vehicle") {
|
return "storageUnit";
|
||||||
return {
|
default:
|
||||||
defaultOption: "travel",
|
return null;
|
||||||
options: ["travel"],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (assetType === "roboticArm") {
|
|
||||||
return {
|
|
||||||
defaultOption: "pickAndPlace",
|
|
||||||
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">
|
||||||
<div className="header">
|
{currentEventData && (
|
||||||
<div className="header-value">{selectedPoint.name}</div>
|
<>
|
||||||
</div>
|
|
||||||
<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 className="actions-list-container">
|
|
||||||
<div className="actions">
|
|
||||||
<div className="header">
|
<div className="header">
|
||||||
<div className="header-value">Actions</div>
|
<div className="header-value">
|
||||||
<div className="add-button" onClick={() => {}}>
|
{selectedEventData?.data.modelName}
|
||||||
<AddIcon /> Add
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
{assetType === "conveyor" && <ConveyorMechanics />}
|
||||||
className="lists-main-container"
|
{assetType === "vehicle" && <VehicleMechanics />}
|
||||||
ref={actionsContainerRef}
|
{assetType === "roboticArm" && <RoboticArmMechanics />}
|
||||||
style={{ height: "120px" }}
|
{assetType === "machine" && <MachineMechanics />}
|
||||||
>
|
{assetType === "storageUnit" && <StorageMechanics />}
|
||||||
<div className="list-container">
|
</>
|
||||||
{selectedPoint?.actions.map((action) => (
|
)}
|
||||||
<div
|
{!currentEventData && selectedEventSphere && (
|
||||||
key={action.uuid}
|
<div className="no-event-selected">
|
||||||
className={`list-item ${
|
<p>
|
||||||
selectedItem.item?.uuid === action.uuid ? "active" : ""
|
<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.
|
||||||
<div
|
</p>
|
||||||
className="value"
|
|
||||||
onClick={() => handleActionToggle(action.uuid)}
|
<div className="products-list">
|
||||||
>
|
<p>
|
||||||
<RenameInput value={action.name} />
|
<strong>Here are some products you can add it to:</strong>
|
||||||
</div>
|
</p>
|
||||||
{selectedPoint?.actions.length > 1 && (
|
<ul>
|
||||||
<div
|
{products.map((product) => (
|
||||||
className="remove-button"
|
<li key={product.productId}>
|
||||||
onClick={() => handleDeleteAction(action.uuid)}
|
<button>
|
||||||
>
|
<AddIcon />
|
||||||
<RemoveIcon />
|
{product.productName}
|
||||||
</div>
|
</button>
|
||||||
)}
|
</li>
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</ul>
|
||||||
<div
|
|
||||||
className="resize-icon"
|
|
||||||
id="action-resize"
|
|
||||||
onMouseDown={(e) => handleResize(e, actionsContainerRef)}
|
|
||||||
>
|
|
||||||
<ResizeHeightIcon />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
<div className="selected-actions-details">
|
{!selectedEventSphere && (
|
||||||
<div className="selected-actions-header">
|
<div className="no-event-selected">
|
||||||
<RenameInput value="Action Name" />
|
<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 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,13 +1,25 @@
|
||||||
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 {
|
||||||
return (
|
pickPointValue: string;
|
||||||
<>
|
pickPointOnChange: (value: string) => void;
|
||||||
<EyeDropInput label="Pick Point" value="na" onChange={() => {}} />
|
placePointValue: string;
|
||||||
<EyeDropInput label="Unload Point" value="na" onChange={() => {}} />
|
placePointOnChange: (value: string) => void;
|
||||||
</>
|
}
|
||||||
);
|
|
||||||
|
const PickAndPlaceAction: React.FC<PickAndPlaceActionProps> = ({
|
||||||
|
pickPointValue,
|
||||||
|
pickPointOnChange,
|
||||||
|
placePointValue,
|
||||||
|
placePointOnChange,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<EyeDropInput label="Pick Point" value={pickPointValue} onChange={pickPointOnChange} />
|
||||||
|
<EyeDropInput label="Unload Point" value={placePointValue} onChange={placePointOnChange} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default PickAndPlaceAction;
|
export default PickAndPlaceAction;
|
||||||
|
|
|
@ -2,23 +2,47 @@ 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 {
|
||||||
return (
|
value: string;
|
||||||
<>
|
min: number;
|
||||||
<InputWithDropDown
|
max: number;
|
||||||
label="Process Time"
|
defaultValue: string;
|
||||||
value="6"
|
onChange: (value: string) => void;
|
||||||
min={0}
|
swapOptions: string[];
|
||||||
step={1}
|
swapDefaultOption: string;
|
||||||
max={10}
|
onSwapSelect: (value: string) => void;
|
||||||
defaultValue="0"
|
}
|
||||||
activeOption="s"
|
|
||||||
onClick={() => {}}
|
const ProcessAction: React.FC<ProcessActionProps> = ({
|
||||||
onChange={(value) => console.log(value)}
|
value,
|
||||||
/>
|
min,
|
||||||
<SwapAction />
|
max,
|
||||||
</>
|
defaultValue,
|
||||||
);
|
onChange,
|
||||||
|
swapOptions,
|
||||||
|
swapDefaultOption,
|
||||||
|
onSwapSelect,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<InputWithDropDown
|
||||||
|
label="Process Time"
|
||||||
|
value={value}
|
||||||
|
min={min}
|
||||||
|
step={1}
|
||||||
|
max={max}
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
activeOption="s"
|
||||||
|
onClick={() => { }}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
<SwapAction
|
||||||
|
options={swapOptions}
|
||||||
|
defaultOption={swapDefaultOption}
|
||||||
|
onSelect={onSwapSelect}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ProcessAction;
|
export default ProcessAction;
|
||||||
|
|
|
@ -1,35 +1,72 @@
|
||||||
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 {
|
||||||
return (
|
onChangeInterval: (value: string) => void;
|
||||||
<>
|
onChangeCount: (value: string) => void;
|
||||||
<InputWithDropDown
|
defaultOption: string;
|
||||||
label="Spawn interval"
|
options: string[];
|
||||||
value="0"
|
onSelect: (option: string) => void;
|
||||||
min={0}
|
intervalValue: string;
|
||||||
step={1}
|
countValue: string;
|
||||||
defaultValue="0"
|
intervalMin: number;
|
||||||
max={10}
|
intervalMax: number;
|
||||||
activeOption="s"
|
intervalDefaultValue: string;
|
||||||
onClick={() => {}}
|
countMin: number;
|
||||||
onChange={(value) => console.log(value)}
|
countMax: number;
|
||||||
/>
|
countDefaultValue: string;
|
||||||
<InputWithDropDown
|
}
|
||||||
label="Spawn count"
|
|
||||||
value="0"
|
const SpawnAction: React.FC<SpawnActionProps> = ({
|
||||||
min={0}
|
onChangeInterval,
|
||||||
step={1}
|
onChangeCount,
|
||||||
defaultValue="0"
|
defaultOption,
|
||||||
max={10}
|
options,
|
||||||
activeOption="s"
|
onSelect,
|
||||||
onClick={() => {}}
|
intervalValue,
|
||||||
onChange={(value) => console.log(value)}
|
countValue,
|
||||||
/>
|
intervalMin,
|
||||||
<PreviewSelectionWithUpload />
|
intervalMax,
|
||||||
</>
|
intervalDefaultValue,
|
||||||
);
|
countMin,
|
||||||
|
countMax,
|
||||||
|
countDefaultValue,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<InputWithDropDown
|
||||||
|
label="Spawn interval"
|
||||||
|
value={intervalValue}
|
||||||
|
min={intervalMin}
|
||||||
|
step={1}
|
||||||
|
defaultValue={intervalDefaultValue}
|
||||||
|
max={intervalMax}
|
||||||
|
activeOption="s"
|
||||||
|
onClick={() => { }}
|
||||||
|
onChange={onChangeInterval}
|
||||||
|
/>
|
||||||
|
<InputWithDropDown
|
||||||
|
label="Spawn count"
|
||||||
|
value={countValue}
|
||||||
|
min={countMin}
|
||||||
|
step={1}
|
||||||
|
defaultValue={countDefaultValue}
|
||||||
|
max={countMax}
|
||||||
|
activeOption="s"
|
||||||
|
onClick={() => { }}
|
||||||
|
onChange={onChangeCount}
|
||||||
|
/>
|
||||||
|
{/* <PreviewSelectionWithUpload /> */}
|
||||||
|
<LabledDropdown
|
||||||
|
label="Presets"
|
||||||
|
defaultOption={defaultOption}
|
||||||
|
options={options}
|
||||||
|
onSelect={onSelect}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SpawnAction;
|
export default SpawnAction;
|
||||||
|
|
|
@ -1,20 +1,28 @@
|
||||||
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 {
|
||||||
return (
|
value: string;
|
||||||
<InputWithDropDown
|
min: number;
|
||||||
label="Storage Capacity"
|
max: number;
|
||||||
value=""
|
defaultValue: string;
|
||||||
min={0}
|
onChange: (value: string) => void;
|
||||||
step={0.1}
|
}
|
||||||
max={10}
|
|
||||||
defaultValue="0"
|
const StorageAction: React.FC<StorageActionProps> = ({ value, min, max, defaultValue, onChange }) => {
|
||||||
activeOption="s"
|
return (
|
||||||
onClick={() => {}}
|
<InputWithDropDown
|
||||||
onChange={(value) => console.log(value)}
|
label="Storage Capacity"
|
||||||
/>
|
value={value}
|
||||||
);
|
min={min}
|
||||||
|
step={1}
|
||||||
|
max={max}
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
activeOption="s"
|
||||||
|
onClick={() => { }}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default StorageAction;
|
export default StorageAction;
|
||||||
|
|
|
@ -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,35 +2,77 @@ 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 {
|
||||||
return (
|
loadCapacity: {
|
||||||
<>
|
value: string;
|
||||||
<InputWithDropDown
|
min: number;
|
||||||
label="Load Capacity"
|
max: number;
|
||||||
value=""
|
defaultValue: string;
|
||||||
min={0}
|
onChange: (value: string) => void;
|
||||||
step={0.1}
|
};
|
||||||
max={10}
|
unloadDuration: {
|
||||||
defaultValue="0"
|
value: string;
|
||||||
activeOption="s"
|
min: number;
|
||||||
onClick={() => {}}
|
max: number;
|
||||||
onChange={(value) => console.log(value)}
|
defaultValue: string;
|
||||||
/>
|
onChange: (value: string) => void;
|
||||||
<InputWithDropDown
|
};
|
||||||
label="Unload Duration"
|
pickPoint?: {
|
||||||
value=""
|
value: string;
|
||||||
min={0}
|
onChange: (value: string) => void;
|
||||||
step={0.1}
|
};
|
||||||
max={10}
|
unloadPoint?: {
|
||||||
defaultValue="0"
|
value: string;
|
||||||
activeOption="s"
|
onChange: (value: string) => void;
|
||||||
onClick={() => {}}
|
};
|
||||||
onChange={(value) => console.log(value)}
|
}
|
||||||
/>
|
|
||||||
<EyeDropInput label="Pick Point" value="na" onChange={() => {}} />
|
const TravelAction: React.FC<TravelActionProps> = ({
|
||||||
<EyeDropInput label="Unload Point" value="na" onChange={() => {}} />
|
loadCapacity,
|
||||||
</>
|
unloadDuration,
|
||||||
);
|
pickPoint,
|
||||||
|
unloadPoint,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<InputWithDropDown
|
||||||
|
label="Load Capacity"
|
||||||
|
value={loadCapacity.value}
|
||||||
|
min={loadCapacity.min}
|
||||||
|
max={loadCapacity.max}
|
||||||
|
defaultValue={loadCapacity.defaultValue}
|
||||||
|
step={0.1}
|
||||||
|
activeOption="s"
|
||||||
|
onClick={() => { }}
|
||||||
|
onChange={loadCapacity.onChange}
|
||||||
|
/>
|
||||||
|
<InputWithDropDown
|
||||||
|
label="Unload Duration"
|
||||||
|
value={unloadDuration.value}
|
||||||
|
min={unloadDuration.min}
|
||||||
|
max={unloadDuration.max}
|
||||||
|
defaultValue={unloadDuration.defaultValue}
|
||||||
|
step={0.1}
|
||||||
|
activeOption="s"
|
||||||
|
onClick={() => { }}
|
||||||
|
onChange={unloadDuration.onChange}
|
||||||
|
/>
|
||||||
|
{pickPoint && (
|
||||||
|
<EyeDropInput
|
||||||
|
label="Pick Point"
|
||||||
|
value={pickPoint.value}
|
||||||
|
onChange={pickPoint.onChange}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{unloadPoint && (
|
||||||
|
<EyeDropInput
|
||||||
|
label="Unload Point"
|
||||||
|
value={unloadPoint.value}
|
||||||
|
onChange={unloadPoint.onChange}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TravelAction;
|
export default TravelAction;
|
||||||
|
|
|
@ -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,70 +43,94 @@ 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 */}
|
<div
|
||||||
{triggers.map((trigger, index) => (
|
className="lists-main-container"
|
||||||
<div key={index} className="trigger-item">
|
ref={triggersContainerRef}
|
||||||
<div className="trigger-name">
|
style={{ height: "120px" }}
|
||||||
{trigger}
|
>
|
||||||
|
<div className="list-container">
|
||||||
|
{triggers.map((trigger: any, index: number) => (
|
||||||
<div
|
<div
|
||||||
className="remove-button"
|
key={index}
|
||||||
onClick={() => removeTrigger(index)}
|
className={`list-item ${
|
||||||
style={{ cursor: "pointer" }}
|
selectedTrigger === trigger ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => setSelectedTrigger(trigger)}
|
||||||
>
|
>
|
||||||
<RemoveIcon />
|
<button className="value" onClick={() => {}}>
|
||||||
|
<RenameInput value={trigger} onRename={() => {}} />
|
||||||
|
</button>
|
||||||
|
{triggers.length > 1 && (
|
||||||
|
<button
|
||||||
|
className="remove-button"
|
||||||
|
onClick={() => removeTrigger(index)}
|
||||||
|
>
|
||||||
|
<RemoveIcon />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</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
|
||||||
|
defaultOption={activeOption}
|
||||||
|
options={["onComplete", "onStart", "onStop", "delay"]}
|
||||||
|
onSelect={(option) => setActiveOption(option)}
|
||||||
|
/>
|
||||||
|
<div className="trigger-options">
|
||||||
|
<div>
|
||||||
|
<LabledDropdown
|
||||||
|
defaultOption={triggeredModel[0] || "Select Model"}
|
||||||
|
options={["Model 1", "Model 2", "Model 3"]}
|
||||||
|
onSelect={(option) => {
|
||||||
|
const newModel = [...triggeredModel];
|
||||||
|
newModel[0] = option;
|
||||||
|
setTriggeredModel(newModel);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<LabledDropdown
|
<div>
|
||||||
defaultOption={activeOption}
|
<LabledDropdown
|
||||||
options={["onComplete", "onStart", "onStop", "delay"]}
|
defaultOption={triggeredPoint[0] || "Select Point"}
|
||||||
onSelect={(option) => setActiveOption(option)}
|
options={["Point 1", "Point 2", "Point 3"]}
|
||||||
/>
|
onSelect={(option) => {
|
||||||
<div className="trigger-options">
|
const newPoint = [...triggeredPoint];
|
||||||
<div>
|
newPoint[0] = option;
|
||||||
<LabledDropdown
|
setTriggeredPoint(newPoint);
|
||||||
defaultOption={triggeredModel[index] || "Select Model"}
|
}}
|
||||||
options={["Model 1", "Model 2", "Model 3"]}
|
/>
|
||||||
onSelect={(option) => {
|
</div>
|
||||||
const newModel = [...triggeredModel];
|
<div>
|
||||||
newModel[index] = option;
|
<LabledDropdown
|
||||||
setTriggeredModel(newModel);
|
defaultOption={triggeredAction[0] || "Select Action"}
|
||||||
}}
|
options={["Action 1", "Action 2", "Action 3"]}
|
||||||
/>
|
onSelect={(option) => {
|
||||||
</div>
|
const newAction = [...triggeredAction];
|
||||||
<div>
|
newAction[0] = option;
|
||||||
<LabledDropdown
|
setTriggeredAction(newAction);
|
||||||
defaultOption={triggeredPoint[index] || "Select Point"}
|
}}
|
||||||
options={["Point 1", "Point 2", "Point 3"]}
|
/>
|
||||||
onSelect={(option) => {
|
|
||||||
const newPoint = [...triggeredPoint];
|
|
||||||
newPoint[index] = option;
|
|
||||||
setTriggeredPoint(newPoint);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<LabledDropdown
|
|
||||||
defaultOption={triggeredAction[index] || "Select Action"}
|
|
||||||
options={["Action 1", "Action 2", "Action 3"]}
|
|
||||||
onSelect={(option) => {
|
|
||||||
const newAction = [...triggeredAction];
|
|
||||||
newAction[index] = option;
|
|
||||||
setTriggeredAction(newAction);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,147 +1,204 @@
|
||||||
import React, { useRef, useState } from "react";
|
import React, { useEffect, useRef } from "react";
|
||||||
import {
|
import {
|
||||||
AddIcon,
|
AddIcon,
|
||||||
ArrowIcon,
|
ArrowIcon,
|
||||||
RemoveIcon,
|
RemoveIcon,
|
||||||
ResizeHeightIcon,
|
ResizeHeightIcon,
|
||||||
} 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 className="value">
|
||||||
<div
|
{val.pathName}
|
||||||
className="value"
|
|
||||||
onClick={() => {
|
|
||||||
setOpenDrop(!openDrop);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{val.pathName}
|
|
||||||
<div className={`arrow-container${openDrop ? " active" : ""}`}>
|
|
||||||
<ArrowIcon />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{val.Children && openDrop && (
|
|
||||||
<div className="children-drop">
|
|
||||||
{val.Children.map((child, index) => (
|
|
||||||
<div key={index} className="value">
|
|
||||||
{child}
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
|
||||||
</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 Value = [
|
const updatedProducts = products.filter(p => p.productId !== productId);
|
||||||
{ pathName: "Path 1", Children: ["Point 1", "Point 2"] },
|
|
||||||
{ pathName: "Path 2", Children: ["Point 1", "Point 2"] },
|
|
||||||
{ pathName: "Path 3", Children: ["Point 1", "Point 2"] },
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
if (isSelected) {
|
||||||
<div className="simulations-container">
|
if (updatedProducts.length > 0) {
|
||||||
<div className="header">Simulations</div>
|
let newSelectedIndex = currentIndex;
|
||||||
<div className="add-product-container">
|
if (currentIndex >= updatedProducts.length) {
|
||||||
<div className="actions">
|
newSelectedIndex = updatedProducts.length - 1;
|
||||||
<div className="header">
|
}
|
||||||
<div className="header-value">Products</div>
|
setSelectedProduct(
|
||||||
<div className="add-button" onClick={handleAddAction}>
|
updatedProducts[newSelectedIndex].productId,
|
||||||
<AddIcon /> Add
|
updatedProducts[newSelectedIndex].productName
|
||||||
</div>
|
);
|
||||||
</div>
|
} else {
|
||||||
<div
|
setSelectedProduct('', '');
|
||||||
className="lists-main-container"
|
}
|
||||||
ref={productsContainerRef}
|
}
|
||||||
style={{ height: "120px" }}
|
|
||||||
>
|
removeProduct(productId);
|
||||||
<div className="list-container">
|
};
|
||||||
{productsList.map((action, index) => (
|
|
||||||
<div
|
const handleRenameProduct = (productId: string, newName: string) => {
|
||||||
key={index}
|
renameProduct(productId, newName);
|
||||||
className={`list-item ${
|
if (selectedProduct.productId === productId) {
|
||||||
selectedItem === action ? "active" : ""
|
setSelectedProduct(productId, newName);
|
||||||
}`}
|
}
|
||||||
>
|
};
|
||||||
<div
|
|
||||||
className="value"
|
const handleAddEventToProduct = () => {
|
||||||
onClick={() => setSelectedItem(action)}
|
if (selectedAsset) {
|
||||||
>
|
addEvent(selectedProduct.productId, selectedAsset);
|
||||||
<input type="radio" name="products" id="products" />
|
// upsertProductOrEventApi({
|
||||||
<RenameInput value={action} />
|
// productName: selectedProduct.productName,
|
||||||
</div>
|
// productId: selectedProduct.productId,
|
||||||
<div
|
// eventDatas: selectedAsset
|
||||||
className="remove-button"
|
// });
|
||||||
onClick={() => handleRemoveAction(index)}
|
clearSelectedAsset();
|
||||||
>
|
}
|
||||||
<RemoveIcon />
|
};
|
||||||
</div>
|
|
||||||
|
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 (
|
||||||
|
<div className="simulations-container">
|
||||||
|
<div className="header">Simulations</div>
|
||||||
|
<div className="add-product-container">
|
||||||
|
<div className="actions">
|
||||||
|
<div className="header">
|
||||||
|
<div className="header-value">Products</div>
|
||||||
|
<div className="add-button" onClick={handleAddProduct}>
|
||||||
|
<AddIcon /> Add
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="lists-main-container"
|
||||||
|
ref={productsContainerRef}
|
||||||
|
style={{ height: "120px" }}
|
||||||
|
>
|
||||||
|
<div className="list-container">
|
||||||
|
{products.map((product, index) => (
|
||||||
|
<div
|
||||||
|
key={product.productId}
|
||||||
|
className={`list-item ${selectedProduct.productId === product.productId ? "active" : ""}`}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="value"
|
||||||
|
onClick={() => setSelectedProduct(product.productId, product.productName)}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="products"
|
||||||
|
checked={selectedProduct.productId === product.productId}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
<RenameInput
|
||||||
|
value={product.productName}
|
||||||
|
onRename={(newName) => handleRenameProduct(product.productId, newName)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{products.length > 1 && (
|
||||||
|
<div
|
||||||
|
className="remove-button"
|
||||||
|
onClick={() => handleRemoveProduct(product.productId)}
|
||||||
|
>
|
||||||
|
<RemoveIcon />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="resize-icon"
|
||||||
|
id="action-resize"
|
||||||
|
onMouseDown={(e) => handleResize(e, productsContainerRef)}
|
||||||
|
>
|
||||||
|
<ResizeHeightIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="simulation-process">
|
||||||
|
<div className="collapse-header-container">
|
||||||
|
<div className="header">Events</div>
|
||||||
|
<div className="arrow-container">
|
||||||
|
<ArrowIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{events.map((event, index) => (
|
||||||
|
<List key={index} val={event} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="compare-simulations-container">
|
||||||
|
<div className="compare-simulations-header">
|
||||||
|
Need to Compare Layout?
|
||||||
|
</div>
|
||||||
|
<div className="content">
|
||||||
|
Click <span>'Compare'</span> to review and analyze the layout differences between them.
|
||||||
|
</div>
|
||||||
|
<div className="input">
|
||||||
|
<input type="button" value={"Compare"} className="submit" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
className="resize-icon"
|
{selectedAsset &&
|
||||||
id="action-resize"
|
<RenderOverlay>
|
||||||
onMouseDown={(e) => handleResize(e, productsContainerRef)}
|
<EditWidgetOption
|
||||||
>
|
options={['Add to Product', 'Remove from Product']}
|
||||||
<ResizeHeightIcon />
|
onClick={(option) => {
|
||||||
</div>
|
if (option === 'Add to Product') {
|
||||||
</div>
|
handleAddEventToProduct();
|
||||||
|
} else {
|
||||||
|
handleRemoveEventFromProduct();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</RenderOverlay>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className="simulation-process">
|
);
|
||||||
<div className="collapse-header-container">
|
|
||||||
<div className="header">Operations</div>
|
|
||||||
<div className="arrow-container">
|
|
||||||
<ArrowIcon />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{Value.map((val, index) => (
|
|
||||||
<DropList key={index} val={val} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div className="compare-simulations-container">
|
|
||||||
<div className="compare-simulations-header">
|
|
||||||
Need to Compare Layout?
|
|
||||||
</div>
|
|
||||||
<div className="content">
|
|
||||||
Click <span>'Compare'</span> to review and analyze the layout
|
|
||||||
differences between them.
|
|
||||||
</div>
|
|
||||||
<div className="input">
|
|
||||||
<input type="button" value={"Compare"} className="submit" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Simulations;
|
export default Simulations;
|
||||||
|
|
|
@ -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,47 +1,72 @@
|
||||||
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 && (
|
||||||
className="input-header-container"
|
<>
|
||||||
onClick={() => setSetshowPreview(!showPreview)}
|
<button
|
||||||
>
|
className="input-header-container"
|
||||||
<div className="input-header">Preview</div>
|
onClick={() => setShowPreview(!showPreview)}
|
||||||
<div
|
>
|
||||||
className="arrow-container"
|
<div className="input-header">Preview</div>
|
||||||
style={{ rotate: showPreview ? "0deg" : "90deg" }}
|
<div
|
||||||
>
|
className="arrow-container"
|
||||||
<ArrowIcon />
|
style={{ rotate: showPreview ? "0deg" : "90deg" }}
|
||||||
</div>
|
>
|
||||||
</div>
|
<ArrowIcon />
|
||||||
{showPreview && (
|
</div>
|
||||||
<div className="canvas-wrapper">
|
</button>
|
||||||
<div className="canvas-container"></div>
|
{showPreview && (
|
||||||
|
<div className="canvas-wrapper">
|
||||||
|
<div className="canvas-container"></div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{upload && (
|
||||||
|
<div className="asset-selection-container">
|
||||||
|
<div className="upload-custom-asset-button">
|
||||||
|
<div className="title">Upload Product</div>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
accept=".glb, .gltf"
|
||||||
|
id="simulation-product-upload"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
className="upload-button"
|
||||||
|
htmlFor="simulation-product-upload"
|
||||||
|
>
|
||||||
|
Upload here
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="asset-selection-container">
|
<LabledDropdown
|
||||||
<div className="upload-custom-asset-button">
|
label={label}
|
||||||
<div className="title">Upload Product</div>
|
defaultOption={defaultOption}
|
||||||
<input
|
options={options}
|
||||||
type="file"
|
onSelect={onSelect}
|
||||||
accept=".glb, .gltf"
|
/>
|
||||||
id="simulation-product-upload"
|
|
||||||
/>
|
|
||||||
<label className="upload-button" htmlFor="simulation-product-upload">
|
|
||||||
Upload here
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<LabledDropdown
|
|
||||||
label="Presets"
|
|
||||||
defaultOption={"Default material"}
|
|
||||||
options={["Default material", "Product 1", "Product 2"]}
|
|
||||||
onSelect={(option) => console.log(option)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,90 +2,107 @@ import * as THREE from "three";
|
||||||
import { EffectComposer, N8AO, Outline } from "@react-three/postprocessing";
|
import { EffectComposer, N8AO, Outline } from "@react-three/postprocessing";
|
||||||
import { BlendFunction } from "postprocessing";
|
import { BlendFunction } from "postprocessing";
|
||||||
import {
|
import {
|
||||||
useDeletableFloorItem,
|
useDeletableFloorItem,
|
||||||
useSelectedWallItem,
|
useSelectedWallItem,
|
||||||
useSelectedFloorItem,
|
useSelectedFloorItem,
|
||||||
} from "../../../store/store";
|
} from "../../../store/store";
|
||||||
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[] = [];
|
||||||
children.forEach((child) => {
|
children.forEach((child) => {
|
||||||
allChildren.push(child);
|
allChildren.push(child);
|
||||||
if (child.children && child.children.length > 0) {
|
if (child.children && child.children.length > 0) {
|
||||||
allChildren.push(...flattenChildren(child.children));
|
allChildren.push(...flattenChildren(child.children));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return allChildren;
|
return allChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<EffectComposer autoClear={false}>
|
<EffectComposer autoClear={false}>
|
||||||
<N8AO
|
<N8AO
|
||||||
color="black"
|
color="black"
|
||||||
aoRadius={20}
|
aoRadius={20}
|
||||||
intensity={7}
|
intensity={7}
|
||||||
distanceFalloff={4}
|
distanceFalloff={4}
|
||||||
aoSamples={32}
|
aoSamples={32}
|
||||||
denoiseRadius={6}
|
denoiseRadius={6}
|
||||||
denoiseSamples={16}
|
denoiseSamples={16}
|
||||||
/>
|
/>
|
||||||
{deletableFloorItem && (
|
{deletableFloorItem && (
|
||||||
<Outline
|
<Outline
|
||||||
selection={flattenChildren(deletableFloorItem.children)}
|
selection={flattenChildren(deletableFloorItem.children)}
|
||||||
selectionLayer={10}
|
selectionLayer={10}
|
||||||
width={3000}
|
width={3000}
|
||||||
blendFunction={BlendFunction.ALPHA}
|
blendFunction={BlendFunction.ALPHA}
|
||||||
edgeStrength={5}
|
edgeStrength={5}
|
||||||
resolutionScale={2}
|
resolutionScale={2}
|
||||||
pulseSpeed={0}
|
pulseSpeed={0}
|
||||||
visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor}
|
visibleEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor}
|
||||||
hiddenEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor}
|
hiddenEdgeColor={CONSTANTS.outlineConfig.assetDeleteColor}
|
||||||
blur={true}
|
blur={true}
|
||||||
xRay={true}
|
xRay={true}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{selectedWallItem && (
|
{selectedWallItem && (
|
||||||
<Outline
|
<Outline
|
||||||
selection={selectedWallItem.children[1].children[0].children.filter(
|
selection={selectedWallItem.children[1].children[0].children.filter(
|
||||||
(child: Types.Mesh) => child.name !== "CSG_REF"
|
(child: Types.Mesh) => child.name !== "CSG_REF"
|
||||||
)}
|
)}
|
||||||
selectionLayer={10}
|
selectionLayer={10}
|
||||||
width={3000}
|
width={3000}
|
||||||
blendFunction={BlendFunction.ALPHA}
|
blendFunction={BlendFunction.ALPHA}
|
||||||
edgeStrength={5}
|
edgeStrength={5}
|
||||||
resolutionScale={2}
|
resolutionScale={2}
|
||||||
pulseSpeed={0}
|
pulseSpeed={0}
|
||||||
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
||||||
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
||||||
blur={true}
|
blur={true}
|
||||||
xRay={true}
|
xRay={true}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{selectedFloorItem && (
|
{selectedFloorItem && (
|
||||||
<Outline
|
<Outline
|
||||||
selection={flattenChildren(selectedFloorItem.children)}
|
selection={flattenChildren(selectedFloorItem.children)}
|
||||||
selectionLayer={10}
|
selectionLayer={10}
|
||||||
width={3000}
|
width={3000}
|
||||||
blendFunction={BlendFunction.ALPHA}
|
blendFunction={BlendFunction.ALPHA}
|
||||||
edgeStrength={5}
|
edgeStrength={5}
|
||||||
resolutionScale={2}
|
resolutionScale={2}
|
||||||
pulseSpeed={0}
|
pulseSpeed={0}
|
||||||
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
visibleEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
||||||
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
hiddenEdgeColor={CONSTANTS.outlineConfig.assetSelectColor}
|
||||||
blur={true}
|
blur={true}
|
||||||
xRay={true}
|
xRay={true}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</EffectComposer>
|
{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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,28 +9,35 @@ 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: "backward", keys: ["ArrowDown", "s", "S"] },
|
{ name: "forward", keys: ["ArrowUp", "w", "W"] },
|
||||||
{ name: "left", keys: ["ArrowLeft", "a", "A"] },
|
{ name: "backward", keys: ["ArrowDown", "s", "S"] },
|
||||||
{ name: "right", keys: ["ArrowRight", "d", "D"] },],
|
{ name: "left", keys: ["ArrowLeft", "a", "A"] },
|
||||||
[]);
|
{ 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 />
|
<Builder />
|
||||||
|
|
||||||
<Builder />
|
<Simulation />
|
||||||
|
|
||||||
<Simulation />
|
<Visualization />
|
||||||
|
</Canvas>
|
||||||
<Visualization />
|
</KeyboardControls>
|
||||||
|
);
|
||||||
</Canvas>
|
|
||||||
</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
|
|
@ -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
|
|
@ -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();
|
||||||
|
|
||||||
|
@ -21,16 +29,36 @@ function Simulation() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<Points />
|
{activeModule === 'simulation' &&
|
||||||
|
|
||||||
<Vehicles />
|
<>
|
||||||
|
|
||||||
<RoboticArm />
|
<Points />
|
||||||
|
|
||||||
<Conveyor />
|
<Products />
|
||||||
|
|
||||||
|
<Materials />
|
||||||
|
|
||||||
|
<Trigger />
|
||||||
|
|
||||||
|
<Conveyor />
|
||||||
|
|
||||||
|
<Vehicles />
|
||||||
|
|
||||||
|
<RoboticArm />
|
||||||
|
|
||||||
|
<Machine />
|
||||||
|
|
||||||
|
<StorageUnit />
|
||||||
|
|
||||||
|
<Simulator />
|
||||||
|
|
||||||
|
</>
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Simulation
|
export default Simulation;
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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) {
|
||||||
|
const { decrementVehicleLoad, vehicles } = useVehicleStore();
|
||||||
|
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 { 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;
|
||||||
|
|
||||||
function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid }: VehicleAnimatorProps) {
|
useEffect(() => {
|
||||||
const [progress, setProgress] = useState<number>(0)
|
if (currentPhase === 'stationed-pickup' && path.length > 0) {
|
||||||
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
|
setCurrentPath(path);
|
||||||
const { scene } = useThree();
|
} else if (currentPhase === 'pickup-drop' && path.length > 0) {
|
||||||
|
setCurrentPath(path);
|
||||||
|
} else if (currentPhase === 'drop-pickup' && path.length > 0) {
|
||||||
|
setCurrentPath(path);
|
||||||
|
}
|
||||||
|
}, [currentPhase, path]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setProgress(0);
|
||||||
|
completedRef.current = false;
|
||||||
|
}, [currentPath]);
|
||||||
|
|
||||||
if (currentPhase === 'stationed-pickup' && path.length > 0) {
|
useFrame((_, delta) => {
|
||||||
setCurrentPath(path);
|
const object = scene.getObjectByProperty('uuid', agvUuid);
|
||||||
|
if (!object || currentPath.length < 2) return;
|
||||||
|
if (isPaused) return;
|
||||||
|
|
||||||
|
let totalDistance = 0;
|
||||||
|
const distances = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < currentPath.length - 1; i++) {
|
||||||
|
const start = new THREE.Vector3(...currentPath[i]);
|
||||||
|
const end = new THREE.Vector3(...currentPath[i + 1]);
|
||||||
|
const segmentDistance = start.distanceTo(end);
|
||||||
|
distances.push(segmentDistance);
|
||||||
|
totalDistance += segmentDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}, [currentPhase, path])
|
if (progressRef.current >= totalDistance) {
|
||||||
|
setRestingRotation(true);
|
||||||
|
progressRef.current = 0;
|
||||||
|
movingForward.current = !movingForward.current;
|
||||||
|
setCurrentPath([]);
|
||||||
|
handleCallBack();
|
||||||
|
if (currentPhase === 'pickup-drop') {
|
||||||
|
requestAnimationFrame(firstFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
useFrame((_, delta) => {
|
function firstFrame() {
|
||||||
if (!path || path.length < 2) return;
|
const unLoadDuration = agvDetail.point.action.unLoadDuration;
|
||||||
|
const droppedMaterial = agvDetail.currentLoad;
|
||||||
|
fixedInterval = (unLoadDuration / droppedMaterial) * 1000;
|
||||||
|
startTime = performance.now();
|
||||||
|
step(droppedMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
const object = scene.getObjectByProperty("uuid", agvUuid)
|
function step(droppedMaterial: number) {
|
||||||
if (!object) return;
|
const elapsedTime = performance.now() - startTime;
|
||||||
|
|
||||||
setProgress(prev => {
|
if (elapsedTime >= fixedInterval) {
|
||||||
const next = prev + delta * 0.1; // speed
|
console.log('fixedInterval: ', fixedInterval);
|
||||||
return next >= 1 ? 1 : next;
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const totalSegments = path.length - 1;
|
return (
|
||||||
const segmentIndex = Math.floor(progress * totalSegments);
|
<>
|
||||||
const t = progress * totalSegments - segmentIndex;
|
{currentPath.length > 0 && (
|
||||||
|
|
||||||
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 (
|
|
||||||
<>
|
<>
|
||||||
|
<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
|
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 {
|
||||||
|
const navMeshQuery = new NavMeshQuery(navMesh);
|
||||||
|
const { path: segmentPath } = navMeshQuery.computePath(start, end);
|
||||||
|
return (
|
||||||
|
segmentPath?.map(({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]) || []
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[navMesh]
|
||||||
|
);
|
||||||
|
|
||||||
|
function vehicleStatus(modelid: string, status: string) {
|
||||||
|
// console.log(`AGV ${modelid}: ${status}`);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
useEffect(() => {
|
||||||
const navMeshQuery = new NavMeshQuery(navMesh);
|
if (isPlaying) {
|
||||||
const { path: segmentPath } = navMeshQuery.computePath(start, end);
|
if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') {
|
||||||
return (
|
const toPickupPath = computePath(
|
||||||
segmentPath?.map(
|
new THREE.Vector3(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]),
|
||||||
({ x, y, z }) => [x, y + 0.1, z] as [number, number, number]
|
agvDetail.point.action.pickUpPoint
|
||||||
) || []
|
);
|
||||||
);
|
setPath(toPickupPath);
|
||||||
} catch {
|
setVehicleActive(agvDetail.modelUuid, true);
|
||||||
return [];
|
setVehicleState(agvDetail.modelUuid, 'running');
|
||||||
}
|
setCurrentPhase('stationed-pickup');
|
||||||
}, [navMesh]);
|
vehicleStatus(agvDetail.modelUuid, 'Started from station, heading to pickup');
|
||||||
|
return;
|
||||||
useEffect(() => {
|
} else if (
|
||||||
|
!agvDetail.isActive &&
|
||||||
|
agvDetail.state === 'idle' &&
|
||||||
if (isPlaying) {
|
currentPhase === 'picking'
|
||||||
if (!agvDetails.isActive && agvDetails.state == "idle" && currentPhase == "stationed") {
|
) {
|
||||||
const toPickupPath = computePath(new THREE.Vector3(agvDetails.position[0], agvDetails.position[1], agvDetails.position[2]), agvDetails.point.action.pickUpPoint);
|
|
||||||
setPath(toPickupPath)
|
setTimeout(() => {
|
||||||
setVehicleActive(agvDetails.modelUuid, true)
|
incrementVehicleLoad(agvDetail.modelUuid, 2);
|
||||||
setVehicleState(agvDetails.modelUuid, "running")
|
}, 5000);
|
||||||
setCurrentPhase("stationed-pickup")
|
|
||||||
//
|
if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) {
|
||||||
}
|
const toDrop = computePath(
|
||||||
}
|
agvDetail.point.action.pickUpPoint,
|
||||||
}, [agvDetails, currentPhase, path, isPlaying])
|
agvDetail.point.action.unLoadPoint
|
||||||
|
);
|
||||||
function handleCallBack() {
|
setPath(toDrop);
|
||||||
if (currentPhase === "stationed-pickup") {
|
setVehicleActive(agvDetail.modelUuid, true);
|
||||||
setVehicleActive(agvDetails.modelUuid, false)
|
setVehicleState(agvDetail.modelUuid, 'running');
|
||||||
setVehicleState(agvDetails.modelUuid, "idle")
|
setCurrentPhase('pickup-drop');
|
||||||
setCurrentPhase("picking")
|
vehicleStatus(agvDetail.modelUuid, 'Started from pickup point, heading to drop point');
|
||||||
setPath([])
|
|
||||||
}
|
}
|
||||||
|
} 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');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}, [vehicles, currentPhase, path, isPlaying]);
|
||||||
|
|
||||||
|
function handleCallBack() {
|
||||||
|
if (currentPhase === 'stationed-pickup') {
|
||||||
|
setVehicleActive(agvDetail.modelUuid, false);
|
||||||
|
setVehicleState(agvDetail.modelUuid, 'idle');
|
||||||
|
setCurrentPhase('picking');
|
||||||
|
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);
|
||||||
|
|
||||||
|
@ -39,7 +43,7 @@ const UserAuth: React.FC = () => {
|
||||||
} else if (res.message === "User Not Found!!! Kindly signup...") {
|
} else if (res.message === "User Not Found!!! Kindly signup...") {
|
||||||
setError("Account not found");
|
setError("Account not found");
|
||||||
}
|
}
|
||||||
} catch (error) { }
|
} catch (error) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRegister = async (e: FormEvent) => {
|
const handleRegister = async (e: FormEvent) => {
|
||||||
|
@ -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") {
|
||||||
|
@ -56,123 +60,121 @@ const UserAuth: React.FC = () => {
|
||||||
if (res.message === "User already exists") {
|
if (res.message === "User already exists") {
|
||||||
setError("User already exists");
|
setError("User already exists");
|
||||||
}
|
}
|
||||||
} catch (error) { }
|
} catch (error) {}
|
||||||
} else {
|
} else {
|
||||||
setError("Please fill all the fields!");
|
setError("Please fill all the fields!");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="auth-container">
|
||||||
<div className="auth-container">
|
<div className="logo-icon">
|
||||||
<div className="logo-icon">
|
<LogoIconLarge />
|
||||||
<LogoIconLarge />
|
</div>
|
||||||
</div>
|
<h1>Welcome to Dwinzo</h1>
|
||||||
<h1>Welcome to Dwinzo</h1>
|
<p>
|
||||||
<p>
|
{isSignIn ? (
|
||||||
{isSignIn ? (
|
<>
|
||||||
<>
|
Don’t have an account?{" "}
|
||||||
Don’t have an account?{" "}
|
<span
|
||||||
<span
|
className="link"
|
||||||
className="link"
|
onClick={() => setIsSignIn(false)}
|
||||||
onClick={() => setIsSignIn(false)}
|
style={{ cursor: "pointer" }}
|
||||||
style={{ cursor: "pointer" }}
|
>
|
||||||
>
|
Register here!
|
||||||
Register here!
|
</span>
|
||||||
</span>
|
</>
|
||||||
</>
|
) : (
|
||||||
) : (
|
<>
|
||||||
<>
|
Already have an account?{" "}
|
||||||
Already have an account?{" "}
|
<span
|
||||||
<span
|
className="link"
|
||||||
className="link"
|
onClick={() => setIsSignIn(true)}
|
||||||
onClick={() => setIsSignIn(true)}
|
style={{ cursor: "pointer" }}
|
||||||
style={{ cursor: "pointer" }}
|
>
|
||||||
>
|
Login here!
|
||||||
Login here!
|
</span>
|
||||||
</span>
|
</>
|
||||||
</>
|
)}
|
||||||
)}
|
</p>
|
||||||
</p>
|
|
||||||
|
|
||||||
<button className="google-login">
|
<button className="google-login">
|
||||||
<span className="google-icon">G</span> Continue with Google
|
<span className="google-icon">G</span> Continue with Google
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{error && <div className="error-message">🛈 {error}</div>}
|
{error && <div className="error-message">🛈 {error}</div>}
|
||||||
|
|
||||||
<form
|
<form
|
||||||
onSubmit={isSignIn ? handleLogin : handleRegister}
|
onSubmit={isSignIn ? handleLogin : handleRegister}
|
||||||
className="auth-form"
|
className="auth-form"
|
||||||
>
|
>
|
||||||
{!isSignIn && (
|
{!isSignIn && (
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={userName}
|
|
||||||
placeholder="Username"
|
|
||||||
onChange={(e) => setUserName(e.target.value)}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="text"
|
||||||
name="email"
|
value={userName}
|
||||||
value={email}
|
placeholder="Username"
|
||||||
placeholder="Email"
|
onChange={(e) => setUserName(e.target.value)}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<div className="password-container">
|
)}
|
||||||
<input
|
<input
|
||||||
name="password"
|
type="email"
|
||||||
type={showPassword ? "text" : "password"}
|
name="email"
|
||||||
value={password}
|
value={email}
|
||||||
placeholder="Password"
|
placeholder="Email"
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<button
|
<div className="password-container">
|
||||||
type="button"
|
<input
|
||||||
className="toggle-password"
|
name="password"
|
||||||
onClick={() => setShowPassword(!showPassword)}
|
type={showPassword ? "text" : "password"}
|
||||||
>
|
value={password}
|
||||||
<EyeIcon isClosed={showPassword} />
|
placeholder="Password"
|
||||||
</button>
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
</div>
|
required
|
||||||
{!isSignIn && (
|
/>
|
||||||
<div className="policy-checkbox">
|
<button
|
||||||
<input type="checkbox" name="" id="" required />
|
type="button"
|
||||||
<div className="label">
|
className="toggle-password"
|
||||||
I have read and agree to the terms of service
|
onClick={() => setShowPassword(!showPassword)}
|
||||||
</div>
|
>
|
||||||
</div>
|
<EyeIcon isClosed={showPassword} />
|
||||||
)}
|
|
||||||
<button type="submit" className="continue-button">
|
|
||||||
{isSignIn ? "Continue" : "Register"}
|
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</div>
|
||||||
<p className="policy">
|
{!isSignIn && (
|
||||||
By signing up for, or logging into, an account, you agree to our{" "}
|
<div className="policy-checkbox">
|
||||||
<span
|
<input type="checkbox" name="" id="" required />
|
||||||
className="link"
|
<div className="label">
|
||||||
onClick={() => navigate("/privacy")}
|
I have read and agree to the terms of service
|
||||||
style={{ cursor: "pointer" }}
|
</div>
|
||||||
>
|
</div>
|
||||||
privacy policy
|
)}
|
||||||
</span>{" "}
|
<button type="submit" className="continue-button">
|
||||||
&{" "}
|
{isSignIn ? "Continue" : "Register"}
|
||||||
<span
|
</button>
|
||||||
className="link"
|
</form>
|
||||||
onClick={() => navigate("/terms")}
|
<p className="policy">
|
||||||
style={{ cursor: "pointer" }}
|
By signing up for, or logging into, an account, you agree to our{" "}
|
||||||
>
|
<span
|
||||||
terms of service
|
className="link"
|
||||||
</span>{" "}
|
onClick={() => navigate("/privacy")}
|
||||||
whether you read them or not. You can also find these terms on our
|
style={{ cursor: "pointer" }}
|
||||||
website.
|
>
|
||||||
</p>
|
privacy policy
|
||||||
</div>
|
</span>{" "}
|
||||||
</>
|
&{" "}
|
||||||
|
<span
|
||||||
|
className="link"
|
||||||
|
onClick={() => navigate("/terms")}
|
||||||
|
style={{ cursor: "pointer" }}
|
||||||
|
>
|
||||||
|
terms of service
|
||||||
|
</span>{" "}
|
||||||
|
whether you read them or not. You can also find these terms on our
|
||||||
|
website.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -706,7 +761,7 @@
|
||||||
}
|
}
|
||||||
.selected-actions-list {
|
.selected-actions-list {
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
.eye-dropper-input-container{
|
.eye-dropper-input-container {
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
.regularDropdown-container {
|
.regularDropdown-container {
|
||||||
padding: 5px 8px;
|
padding: 5px 8px;
|
||||||
|
@ -747,19 +802,21 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 2px 0;
|
margin: 2px 0;
|
||||||
border-radius: #{$border-radius-small};
|
border-radius: #{$border-radius-small};
|
||||||
}
|
.value {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 80%;
|
||||||
|
gap: 6px;
|
||||||
|
.input-value {
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
|
||||||
.value {
|
input {
|
||||||
display: flex;
|
width: fit-content;
|
||||||
justify-content: flex-start;
|
outline: none;
|
||||||
align-items: center;
|
accent-color: var(--accent-color);
|
||||||
min-width: 80%;
|
}
|
||||||
gap: 6px;
|
|
||||||
|
|
||||||
input {
|
|
||||||
width: fit-content;
|
|
||||||
outline: none;
|
|
||||||
accent-color: var(--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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
@ -168,4 +170,17 @@ interface StorageUnitStatus extends StorageEventSchema {
|
||||||
idleTime: number;
|
idleTime: number;
|
||||||
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[];
|
Loading…
Reference in New Issue