added ui for changing position of vehicles pickup-point and unloadPoint
This commit is contained in:
commit
9574d70b56
app/src
assets/gltf-glb
components
icons
layout
Dashboard
confirmationPopup
sidebarLeft/visualization/widgets
sidebarRight
SideBarRight.tsx
properties/eventProperties
EventProperties.tsx
actions
components
mechanics
conveyorMechanics.tsxmachineMechanics.tsxroboticArmMechanics.tsxstorageMechanics.tsxvehicleMechanics.tsx
trigger
simulation
ui
modules
pages
styles
types
Binary file not shown.
Binary file not shown.
|
@ -42,6 +42,7 @@ export function FlipXAxisIcon() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FlipYAxisIcon() {
|
export function FlipYAxisIcon() {
|
||||||
|
return (
|
||||||
<svg
|
<svg
|
||||||
width="12"
|
width="12"
|
||||||
height="12"
|
height="12"
|
||||||
|
@ -79,7 +80,8 @@ export function FlipYAxisIcon() {
|
||||||
strokeWidth="0.75"
|
strokeWidth="0.75"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
/>
|
/>
|
||||||
</svg>;
|
</svg>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
export function FlipZAxisIcon() {
|
export function FlipZAxisIcon() {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -168,20 +168,6 @@ export function AddIcon() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RmoveIcon() {
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
width="12"
|
|
||||||
height="12"
|
|
||||||
viewBox="0 0 12 12"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path d="M3 6.5H9" stroke="var(--text-color)" strokeLinecap="round" />
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function CloseIcon() {
|
export function CloseIcon() {
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
|
|
|
@ -124,7 +124,6 @@ export function LogoIconLarge() {
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
>
|
>
|
||||||
<circle cx="45" cy="45" r="45" fill="#FCFDFD" />
|
|
||||||
<circle
|
<circle
|
||||||
cx="45.1957"
|
cx="45.1957"
|
||||||
cy="45.1957"
|
cy="45.1957"
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
export function ThroughputSummaryIcon() {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="26"
|
||||||
|
height="27"
|
||||||
|
viewBox="0 0 26 27"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<circle cx="13.3457" cy="13.498" r="12.6543" fill="#FC9D2F" />
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M13.9063 12.9046L14.2265 13.86L14.4378 14.5073C14.9906 16.2239 15.2594 17.2662 15.2594 17.7299C15.2594 18.8219 14.3742 19.7072 13.2822 19.7072C12.1902 19.7072 11.305 18.8219 11.305 17.7299C11.305 17.2106 11.6422 15.9654 12.3379 13.86L12.658 12.9046C12.8604 12.3082 13.704 12.3082 13.9063 12.9046ZM13.2822 7.84375C16.9222 7.84375 19.873 10.7945 19.873 14.4345C19.873 15.7565 19.4823 17.0219 18.7621 18.0974C18.5596 18.3999 18.1502 18.4809 17.8478 18.2784C17.5453 18.0758 17.4643 17.6665 17.6668 17.364C18.2428 16.5038 18.5548 15.4933 18.5548 14.4345C18.5548 11.5225 16.1942 9.16191 13.2822 9.16191C10.3702 9.16191 8.00956 11.5225 8.00956 14.4345C8.00956 15.4933 8.32153 16.5038 8.89752 17.364C9.10005 17.6665 9.01904 18.0758 8.71659 18.2784C8.41414 18.4809 8.00477 18.3999 7.80224 18.0974C7.08206 17.0219 6.69141 15.7565 6.69141 14.4345C6.69141 10.7945 9.6422 7.84375 13.2822 7.84375ZM13.2822 15.2247L13.0657 15.9238L12.9161 16.4319C12.7219 17.111 12.6231 17.5509 12.6231 17.7299C12.6231 18.0939 12.9182 18.389 13.2822 18.389C13.6462 18.389 13.9413 18.0939 13.9413 17.7299C13.9413 17.511 13.7936 16.9022 13.5044 15.9428L13.2822 15.2247Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export function ProductionCapacityIcon() {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="26"
|
||||||
|
height="27"
|
||||||
|
viewBox="0 0 26 27"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<circle cx="13.3457" cy="13.498" r="12.6543" fill="#FC9D2F" />
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M13.9063 12.9046L14.2265 13.86L14.4378 14.5073C14.9906 16.2239 15.2594 17.2662 15.2594 17.7299C15.2594 18.8219 14.3742 19.7072 13.2822 19.7072C12.1902 19.7072 11.305 18.8219 11.305 17.7299C11.305 17.2106 11.6422 15.9654 12.3379 13.86L12.658 12.9046C12.8604 12.3082 13.704 12.3082 13.9063 12.9046ZM13.2822 7.84375C16.9222 7.84375 19.873 10.7945 19.873 14.4345C19.873 15.7565 19.4823 17.0219 18.7621 18.0974C18.5596 18.3999 18.1502 18.4809 17.8478 18.2784C17.5453 18.0758 17.4643 17.6665 17.6668 17.364C18.2428 16.5038 18.5548 15.4933 18.5548 14.4345C18.5548 11.5225 16.1942 9.16191 13.2822 9.16191C10.3702 9.16191 8.00956 11.5225 8.00956 14.4345C8.00956 15.4933 8.32153 16.5038 8.89752 17.364C9.10005 17.6665 9.01904 18.0758 8.71659 18.2784C8.41414 18.4809 8.00477 18.3999 7.80224 18.0974C7.08206 17.0219 6.69141 15.7565 6.69141 14.4345C6.69141 10.7945 9.6422 7.84375 13.2822 7.84375ZM13.2822 15.2247L13.0657 15.9238L12.9161 16.4319C12.7219 17.111 12.6231 17.5509 12.6231 17.7299C12.6231 18.0939 12.9182 18.389 13.2822 18.389C13.6462 18.389 13.9413 18.0939 13.9413 17.7299C13.9413 17.511 13.7936 16.9022 13.5044 15.9428L13.2822 15.2247Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export function ROISummaryIcon() {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="25"
|
||||||
|
height="26"
|
||||||
|
viewBox="0 0 25 26"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<rect y="0.515625" width="25" height="25" rx="12.5" fill="#28B9F3" />
|
||||||
|
<path
|
||||||
|
d="M6.00015 7.51562V19.0974H19.0002"
|
||||||
|
stroke="white"
|
||||||
|
stroke-linecap="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M6.50037 15.0553L10.3102 11.847C10.6984 11.52 11.2701 11.5358 11.6397 11.8837L15.0095 15.0553L19.5004 11.2734"
|
||||||
|
stroke="white"
|
||||||
|
stroke-linecap="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export function PowerIcon() {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="21"
|
||||||
|
height="21"
|
||||||
|
viewBox="0 0 21 21"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g clip-path="url(#clip0_4107_3144)">
|
||||||
|
<path
|
||||||
|
d="M12.1277 1.76564L10.7174 9.17535L15.8265 9.19254L8.87213 19.2375L10.2824 11.0856L5.17369 11.0678L12.1277 1.76564ZM12.1287 0.515664C12.0949 0.515664 12.0612 0.516895 12.0281 0.519375C11.8075 0.537207 11.6612 0.610957 11.4878 0.72752C11.3901 0.792624 11.3021 0.871096 11.2262 0.960645C11.2034 0.987526 11.1819 1.01547 11.1618 1.04439L4.15775 10.3141C3.88119 10.6931 3.84056 11.1935 4.05306 11.6116C4.26525 12.0297 4.69431 12.2947 5.16463 12.2982L8.77275 12.3244L7.63838 19.0079C7.53056 19.5822 7.83681 20.1547 8.37588 20.3854C8.53254 20.4527 8.70128 20.4873 8.87179 20.4872C9.26461 20.4872 9.58742 20.3035 9.82963 19.9716L16.8424 9.92658C17.119 9.5475 17.1593 9.04656 16.9471 8.62906C16.7349 8.21094 16.3059 7.94592 15.8356 7.9425L12.2274 7.93625L13.3496 2.05969C13.3734 1.96348 13.3854 1.86473 13.3853 1.76562C13.3853 1.08938 12.8468 0.538125 12.1731 0.51625C12.1581 0.515625 12.1434 0.515625 12.1287 0.515625L12.1287 0.515664Z"
|
||||||
|
fill="#F3C64D"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M4.875 11.125L12.375 1.125L11.125 8.625H16.125L8.625 19.875L9.875 11.125H4.875Z"
|
||||||
|
fill="#F3C64D"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_4107_3144">
|
||||||
|
<rect
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
fill="white"
|
||||||
|
transform="translate(0.5 0.5)"
|
||||||
|
/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
|
@ -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>
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -7,43 +7,12 @@ import {
|
||||||
} 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"}
|
||||||
|
|
|
@ -14,7 +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 {
|
||||||
|
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";
|
||||||
|
@ -32,53 +35,63 @@ const SideBarRight: React.FC = () => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeModule !== "simulation") setSubModule("properties");
|
if (activeModule !== "simulation") setSubModule("properties");
|
||||||
if (activeModule === "simulation") setSubModule("simulations");
|
if (activeModule === "simulation") setSubModule("simulations");
|
||||||
}, [activeModule]);
|
}, [activeModule, setSubModule]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeModule !== "mechanics" && selectedEventData && selectedEventSphere) {
|
if (
|
||||||
|
activeModule !== "mechanics" &&
|
||||||
|
selectedEventData &&
|
||||||
|
selectedEventSphere
|
||||||
|
) {
|
||||||
setSubModule("mechanics");
|
setSubModule("mechanics");
|
||||||
} else if (!selectedEventData && !selectedEventSphere) {
|
} else if (!selectedEventData && !selectedEventSphere) {
|
||||||
if (activeModule === 'simulation') {
|
if (activeModule === "simulation") {
|
||||||
setSubModule("simulations");
|
setSubModule("simulations");
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}, [activeModule, selectedEventData, selectedEventSphere])
|
}, [activeModule, selectedEventData, selectedEventSphere, setSubModule]);
|
||||||
|
|
||||||
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">
|
||||||
<div
|
{activeModule !== "simulation" && (
|
||||||
className={`sidebar-action-list ${subModule === "properties" ? "active" : ""
|
<button
|
||||||
|
className={`sidebar-action-list ${
|
||||||
|
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" : ""
|
className={`sidebar-action-list ${
|
||||||
}`}
|
subModule === "simulations" ? "active" : ""
|
||||||
onClick={() => setSubModule("mechanics")}
|
|
||||||
>
|
|
||||||
<MechanicsIcon isActive={subModule === "mechanics"} />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`sidebar-action-list ${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 === "analysis" ? "active" : ""
|
className={`sidebar-action-list ${
|
||||||
|
subModule === "mechanics" ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => setSubModule("mechanics")}
|
||||||
|
>
|
||||||
|
<MechanicsIcon isActive={subModule === "mechanics"} />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`sidebar-action-list ${
|
||||||
|
subModule === "analysis" ? "active" : ""
|
||||||
}`}
|
}`}
|
||||||
onClick={() => setSubModule("analysis")}
|
onClick={() => setSubModule("analysis")}
|
||||||
>
|
>
|
||||||
<AnalysisIcon isActive={subModule === "analysis"} />
|
<AnalysisIcon isActive={subModule === "analysis"} />
|
||||||
</div>
|
</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,63 +1,131 @@
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useSelectedEventData, useSelectedProduct } from "../../../../../store/simulation/useSimulationStore";
|
import {
|
||||||
|
useSelectedAsset,
|
||||||
|
useSelectedEventData,
|
||||||
|
useSelectedEventSphere,
|
||||||
|
useSelectedProduct,
|
||||||
|
} from "../../../../../store/simulation/useSimulationStore";
|
||||||
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
||||||
import ConveyorMechanics from "./mechanics/conveyorMechanics";
|
import ConveyorMechanics from "./mechanics/conveyorMechanics";
|
||||||
import VehicleMechanics from "./mechanics/vehicleMechanics";
|
import VehicleMechanics from "./mechanics/vehicleMechanics";
|
||||||
import RoboticArmMechanics from "./mechanics/roboticArmMechanics";
|
import RoboticArmMechanics from "./mechanics/roboticArmMechanics";
|
||||||
import MachineMechanics from "./mechanics/machineMechanics";
|
import MachineMechanics from "./mechanics/machineMechanics";
|
||||||
import StorageMechanics from "./mechanics/storageMechanics";
|
import StorageMechanics from "./mechanics/storageMechanics";
|
||||||
|
import { AddIcon } from "../../../../icons/ExportCommonIcons";
|
||||||
|
import { handleAddEventToProduct } from "../../../../../modules/simulation/events/points/functions/handleAddEventToProduct";
|
||||||
|
|
||||||
const EventProperties: React.FC = () => {
|
const EventProperties: React.FC = () => {
|
||||||
const { selectedEventData } = useSelectedEventData();
|
const { selectedEventData } = useSelectedEventData();
|
||||||
const { getEventByModelUuid } = useProductStore();
|
const { getEventByModelUuid } = useProductStore();
|
||||||
const { selectedProduct } = useSelectedProduct();
|
const { selectedProduct } = useSelectedProduct();
|
||||||
const [currentEventData, setCurrentEventData] = useState<EventsSchema | null>(null);
|
const [currentEventData, setCurrentEventData] = useState<EventsSchema | null>(
|
||||||
|
null
|
||||||
|
);
|
||||||
const [assetType, setAssetType] = useState<string | null>(null);
|
const [assetType, setAssetType] = useState<string | null>(null);
|
||||||
|
const { products, addEvent } = useProductStore();
|
||||||
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
|
|
||||||
|
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const event = getCurrentEventData();
|
const event = getCurrentEventData();
|
||||||
setCurrentEventData(event);
|
setCurrentEventData(event);
|
||||||
|
|
||||||
const type = determineAssetType(event);
|
const type = determineAssetType(event);
|
||||||
setAssetType(type);
|
setAssetType(type);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [selectedEventData, selectedProduct]);
|
}, [selectedEventData, selectedProduct]);
|
||||||
|
|
||||||
const getCurrentEventData = () => {
|
const getCurrentEventData = () => {
|
||||||
if (!selectedEventData?.data || !selectedProduct) return null;
|
if (!selectedEventData?.data || !selectedProduct) return null;
|
||||||
return getEventByModelUuid(selectedProduct.productId, selectedEventData.data.modelUuid) || null;
|
return (
|
||||||
|
getEventByModelUuid(
|
||||||
|
selectedProduct.productId,
|
||||||
|
selectedEventData.data.modelUuid
|
||||||
|
) ?? null
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const determineAssetType = (event: EventsSchema | null) => {
|
const determineAssetType = (event: EventsSchema | null) => {
|
||||||
if (!event) return null;
|
if (!event) return null;
|
||||||
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case 'transfer': return 'conveyor';
|
case "transfer":
|
||||||
case 'vehicle': return 'vehicle';
|
return "conveyor";
|
||||||
case 'roboticArm': return 'roboticArm';
|
case "vehicle":
|
||||||
case 'machine': return 'machine';
|
return "vehicle";
|
||||||
case 'storageUnit': return 'storageUnit';
|
case "roboticArm":
|
||||||
default: return null;
|
return "roboticArm";
|
||||||
|
case "machine":
|
||||||
|
return "machine";
|
||||||
|
case "storageUnit":
|
||||||
|
return "storageUnit";
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<div className="event-proprties-wrapper">
|
<div className="event-proprties-wrapper">
|
||||||
{currentEventData &&
|
{currentEventData && (
|
||||||
<>
|
<>
|
||||||
<div className="header">
|
<div className="header">
|
||||||
<div className="header-value">{selectedEventData?.data.modelName}</div>
|
<div className="header-value">
|
||||||
|
{selectedEventData?.data.modelName}
|
||||||
</div>
|
</div>
|
||||||
{assetType === 'conveyor' && <ConveyorMechanics />}
|
</div>
|
||||||
{assetType === 'vehicle' && <VehicleMechanics />}
|
{assetType === "conveyor" && <ConveyorMechanics />}
|
||||||
{assetType === 'roboticArm' && <RoboticArmMechanics />}
|
{assetType === "vehicle" && <VehicleMechanics />}
|
||||||
{assetType === 'machine' && <MachineMechanics />}
|
{assetType === "roboticArm" && <RoboticArmMechanics />}
|
||||||
{assetType === 'storageUnit' && <StorageMechanics />}
|
{assetType === "machine" && <MachineMechanics />}
|
||||||
|
{assetType === "storageUnit" && <StorageMechanics />}
|
||||||
</>
|
</>
|
||||||
|
)}
|
||||||
|
{!currentEventData && selectedEventSphere && (
|
||||||
|
<div className="no-event-selected">
|
||||||
|
<p>
|
||||||
|
<strong>Oops!</strong> It looks like this object doesn't have an
|
||||||
|
event assigned yet. To continue, please link it to one of the
|
||||||
|
products below.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="products-list">
|
||||||
|
<p>
|
||||||
|
<strong>Here are some products you can add it to:</strong>
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
{products.map((product) => (
|
||||||
|
<li key={product.productId}>
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
handleAddEventToProduct({
|
||||||
|
selectedAsset,
|
||||||
|
addEvent,
|
||||||
|
selectedProduct: {
|
||||||
|
productId: product.productId,
|
||||||
|
productName: product.productName,
|
||||||
|
},
|
||||||
|
clearSelectedAsset,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
>
|
||||||
|
<AddIcon />
|
||||||
|
{product.productName}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!selectedEventSphere && (
|
||||||
|
<div className="no-event-selected">
|
||||||
|
<p>
|
||||||
|
<strong>Oops!</strong> It looks like you haven't selected an event
|
||||||
|
point yet. Please select an event to view its properties.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,14 @@ interface DelayActionProps {
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DelayAction: React.FC<DelayActionProps> = ({ value, defaultValue, min, max, onChange }) => {
|
const DelayAction: React.FC<DelayActionProps> = ({
|
||||||
|
value,
|
||||||
|
defaultValue,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
onChange,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<InputWithDropDown
|
<InputWithDropDown
|
||||||
label="Delay"
|
label="Delay"
|
||||||
value={value}
|
value={value}
|
||||||
|
@ -23,7 +28,6 @@ const DelayAction: React.FC<DelayActionProps> = ({ value, defaultValue, min, max
|
||||||
onClick={() => {}}
|
onClick={() => {}}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
|
||||||
|
|
||||||
const DespawnAction: React.FC = () => {
|
const DespawnAction: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload";
|
import PreviewSelectionWithUpload from "../../../../../ui/inputs/PreviewSelectionWithUpload";
|
||||||
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
|
||||||
|
|
||||||
interface SwapActionProps {
|
interface SwapActionProps {
|
||||||
onSelect: (option: string) => void;
|
onSelect: (option: string) => void;
|
||||||
|
@ -8,19 +7,18 @@ interface SwapActionProps {
|
||||||
options: string[];
|
options: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const SwapAction: React.FC<SwapActionProps> = ({ onSelect, defaultOption, options }) => {
|
const SwapAction: React.FC<SwapActionProps> = ({
|
||||||
|
onSelect,
|
||||||
|
defaultOption,
|
||||||
|
options,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<PreviewSelectionWithUpload
|
||||||
{/* <PreviewSelectionWithUpload /> */}
|
|
||||||
|
|
||||||
<LabledDropdown
|
|
||||||
label="Presets"
|
label="Presets"
|
||||||
defaultOption={defaultOption}
|
defaultOption={defaultOption}
|
||||||
options={options}
|
options={options}
|
||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
/>
|
/>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
@ -1,19 +1,27 @@
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from "react";
|
||||||
import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown'
|
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||||
import DelayAction from '../actions/DelayAction'
|
import DelayAction from "../actions/DelayAction";
|
||||||
import RenameInput from '../../../../../ui/inputs/RenameInput'
|
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||||
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown'
|
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||||
import DespawnAction from '../actions/DespawnAction'
|
import DespawnAction from "../actions/DespawnAction";
|
||||||
import SwapAction from '../actions/SwapAction'
|
import SwapAction from "../actions/SwapAction";
|
||||||
import SpawnAction from '../actions/SpawnAction'
|
import SpawnAction from "../actions/SpawnAction";
|
||||||
import DefaultAction from '../actions/DefaultAction'
|
import DefaultAction from "../actions/DefaultAction";
|
||||||
import Trigger from '../trigger/Trigger'
|
import Trigger from "../trigger/Trigger";
|
||||||
import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";
|
import {
|
||||||
|
useSelectedEventData,
|
||||||
|
useSelectedProduct,
|
||||||
|
} from "../../../../../../store/simulation/useSimulationStore";
|
||||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||||
|
import ActionsList from "../components/ActionsList";
|
||||||
|
|
||||||
function ConveyorMechanics() {
|
function ConveyorMechanics() {
|
||||||
const [activeOption, setActiveOption] = useState<"default" | "spawn" | "swap" | "delay" | "despawn">("default");
|
const [activeOption, setActiveOption] = useState<
|
||||||
const [selectedPointData, setSelectedPointData] = useState<ConveyorPointSchema | undefined>();
|
"default" | "spawn" | "swap" | "delay" | "despawn"
|
||||||
|
>("default");
|
||||||
|
const [selectedPointData, setSelectedPointData] = useState<
|
||||||
|
ConveyorPointSchema | undefined
|
||||||
|
>();
|
||||||
const { selectedEventData } = useSelectedEventData();
|
const { selectedEventData } = useSelectedEventData();
|
||||||
const { getPointByUuid, updateEvent, updateAction } = useProductStore();
|
const { getPointByUuid, updateEvent, updateAction } = useProductStore();
|
||||||
const { selectedProduct } = useSelectedProduct();
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
@ -25,71 +33,71 @@ function ConveyorMechanics() {
|
||||||
selectedEventData?.data.modelUuid,
|
selectedEventData?.data.modelUuid,
|
||||||
selectedEventData?.selectedPoint
|
selectedEventData?.selectedPoint
|
||||||
) as ConveyorPointSchema | undefined;
|
) as ConveyorPointSchema | undefined;
|
||||||
if (point && 'action' in point) {
|
if (point && "action" in point) {
|
||||||
setSelectedPointData(point);
|
setSelectedPointData(point);
|
||||||
setActiveOption(point.action.actionType as "default" | "spawn" | "swap" | "delay" | "despawn");
|
setActiveOption(
|
||||||
|
point.action.actionType as
|
||||||
|
| "default"
|
||||||
|
| "spawn"
|
||||||
|
| "swap"
|
||||||
|
| "delay"
|
||||||
|
| "despawn"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [selectedProduct, selectedEventData])
|
}, [selectedProduct, selectedEventData, getPointByUuid]);
|
||||||
|
|
||||||
const handleSpeedChange = (value: string) => {
|
const handleSpeedChange = (value: string) => {
|
||||||
if (!selectedEventData) return;
|
if (!selectedEventData) return;
|
||||||
updateEvent(
|
updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, {
|
||||||
selectedProduct.productId,
|
speed: parseFloat(value),
|
||||||
selectedEventData.data.modelUuid,
|
});
|
||||||
{ speed: parseFloat(value) }
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleActionTypeChange = (option: string) => {
|
const handleActionTypeChange = (option: string) => {
|
||||||
if (!selectedEventData || !selectedPointData) return;
|
if (!selectedEventData || !selectedPointData) return;
|
||||||
const validOption = option as "default" | "spawn" | "swap" | "delay" | "despawn";
|
const validOption = option as
|
||||||
|
| "default"
|
||||||
|
| "spawn"
|
||||||
|
| "swap"
|
||||||
|
| "delay"
|
||||||
|
| "despawn";
|
||||||
setActiveOption(validOption);
|
setActiveOption(validOption);
|
||||||
|
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
selectedPointData.action.actionUuid,
|
actionType: validOption,
|
||||||
{ actionType: validOption }
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRenameAction = (newName: string) => {
|
const handleRenameAction = (newName: string) => {
|
||||||
if (!selectedPointData) return;
|
if (!selectedPointData) return;
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, { actionName: newName });
|
||||||
selectedPointData.action.actionUuid,
|
|
||||||
{ actionName: newName }
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSpawnCountChange = (value: string) => {
|
const handleSpawnCountChange = (value: string) => {
|
||||||
if (!selectedPointData) return;
|
if (!selectedPointData) return;
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
selectedPointData.action.actionUuid,
|
spawnCount: value === "inherit" ? "inherit" : parseFloat(value),
|
||||||
{ spawnCount: value === "inherit" ? "inherit" : parseFloat(value) }
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSpawnIntervalChange = (value: string) => {
|
const handleSpawnIntervalChange = (value: string) => {
|
||||||
if (!selectedPointData) return;
|
if (!selectedPointData) return;
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
selectedPointData.action.actionUuid,
|
spawnInterval: value === "inherit" ? "inherit" : parseFloat(value),
|
||||||
{ spawnInterval: value === "inherit" ? "inherit" : parseFloat(value) }
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMaterialSelect = (material: string) => {
|
const handleMaterialSelect = (material: string) => {
|
||||||
if (!selectedPointData) return;
|
if (!selectedPointData) return;
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, { material });
|
||||||
selectedPointData.action.actionUuid,
|
|
||||||
{ material }
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelayChange = (value: string) => {
|
const handleDelayChange = (value: string) => {
|
||||||
if (!selectedPointData) return;
|
if (!selectedPointData) return;
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
selectedPointData.action.actionUuid,
|
delay: value === "inherit" ? "inherit" : parseFloat(value),
|
||||||
{ delay: value === "inherit" ? "inherit" : parseFloat(value) }
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const availableActions = {
|
const availableActions = {
|
||||||
|
@ -98,7 +106,8 @@ function ConveyorMechanics() {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get current values from store
|
// Get current values from store
|
||||||
const currentSpeed = selectedEventData?.data.type === "transfer"
|
const currentSpeed =
|
||||||
|
selectedEventData?.data.type === "transfer"
|
||||||
? selectedEventData.data.speed.toString()
|
? selectedEventData.data.speed.toString()
|
||||||
: "0.5";
|
: "0.5";
|
||||||
|
|
||||||
|
@ -124,7 +133,7 @@ function ConveyorMechanics() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{selectedEventData &&
|
{selectedEventData && (
|
||||||
<>
|
<>
|
||||||
<div key={selectedPointData?.uuid} className="global-props">
|
<div key={selectedPointData?.uuid} className="global-props">
|
||||||
<div className="property-list-container">
|
<div className="property-list-container">
|
||||||
|
@ -144,6 +153,11 @@ function ConveyorMechanics() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ActionsList
|
||||||
|
setSelectedPointData={setSelectedPointData}
|
||||||
|
selectedPointData={selectedPointData}
|
||||||
|
/>
|
||||||
|
|
||||||
<div className="selected-actions-details">
|
<div className="selected-actions-details">
|
||||||
<div className="selected-actions-header">
|
<div className="selected-actions-header">
|
||||||
<RenameInput
|
<RenameInput
|
||||||
|
@ -153,16 +167,16 @@ function ConveyorMechanics() {
|
||||||
</div>
|
</div>
|
||||||
<div className="selected-actions-list">
|
<div className="selected-actions-list">
|
||||||
<LabledDropdown
|
<LabledDropdown
|
||||||
defaultOption={selectedPointData
|
defaultOption={
|
||||||
|
selectedPointData
|
||||||
? selectedPointData.action.actionType
|
? selectedPointData.action.actionType
|
||||||
: "default"}
|
: "default"
|
||||||
|
}
|
||||||
options={availableActions.options}
|
options={availableActions.options}
|
||||||
onSelect={handleActionTypeChange}
|
onSelect={handleActionTypeChange}
|
||||||
/>
|
/>
|
||||||
{activeOption === "default" &&
|
{activeOption === "default" && <DefaultAction />}
|
||||||
<DefaultAction />
|
{activeOption === "spawn" && (
|
||||||
}
|
|
||||||
{activeOption === "spawn" &&
|
|
||||||
<SpawnAction
|
<SpawnAction
|
||||||
onChangeCount={handleSpawnCountChange}
|
onChangeCount={handleSpawnCountChange}
|
||||||
options={["Default material", "Material 1", "Material 2"]}
|
options={["Default material", "Material 1", "Material 2"]}
|
||||||
|
@ -178,18 +192,16 @@ function ConveyorMechanics() {
|
||||||
countMax={100}
|
countMax={100}
|
||||||
countDefaultValue="1"
|
countDefaultValue="1"
|
||||||
/>
|
/>
|
||||||
}
|
)}
|
||||||
{activeOption === "swap" &&
|
{activeOption === "swap" && (
|
||||||
<SwapAction
|
<SwapAction
|
||||||
options={["Default material", "Material 1", "Material 2"]}
|
options={["Default material", "Material 1", "Material 2"]}
|
||||||
defaultOption={currentMaterial}
|
defaultOption={currentMaterial}
|
||||||
onSelect={handleMaterialSelect}
|
onSelect={handleMaterialSelect}
|
||||||
/>
|
/>
|
||||||
}
|
)}
|
||||||
{activeOption === "despawn" &&
|
{activeOption === "despawn" && <DespawnAction />}
|
||||||
<DespawnAction />
|
{activeOption === "delay" && (
|
||||||
}
|
|
||||||
{activeOption === "delay" &&
|
|
||||||
<DelayAction
|
<DelayAction
|
||||||
value={currentDelay}
|
value={currentDelay}
|
||||||
defaultValue="0"
|
defaultValue="0"
|
||||||
|
@ -197,16 +209,16 @@ function ConveyorMechanics() {
|
||||||
max={60}
|
max={60}
|
||||||
onChange={handleDelayChange}
|
onChange={handleDelayChange}
|
||||||
/>
|
/>
|
||||||
}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="tirgger">
|
<div className="tirgger">
|
||||||
<Trigger />
|
<Trigger />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ConveyorMechanics
|
export default ConveyorMechanics;
|
||||||
|
|
|
@ -1,14 +1,22 @@
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from "react";
|
||||||
import RenameInput from '../../../../../ui/inputs/RenameInput'
|
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||||
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown'
|
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||||
import Trigger from '../trigger/Trigger'
|
import Trigger from "../trigger/Trigger";
|
||||||
import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";
|
import {
|
||||||
|
useSelectedEventData,
|
||||||
|
useSelectedProduct,
|
||||||
|
} from "../../../../../../store/simulation/useSimulationStore";
|
||||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||||
import ProcessAction from '../actions/ProcessAction'
|
import ProcessAction from "../actions/ProcessAction";
|
||||||
|
import ActionsList from "../components/ActionsList";
|
||||||
|
|
||||||
function MachineMechanics() {
|
function MachineMechanics() {
|
||||||
const [activeOption, setActiveOption] = useState<"default" | "process">("default");
|
const [activeOption, setActiveOption] = useState<"default" | "process">(
|
||||||
const [selectedPointData, setSelectedPointData] = useState<MachinePointSchema | undefined>();
|
"default"
|
||||||
|
);
|
||||||
|
const [selectedPointData, setSelectedPointData] = useState<
|
||||||
|
MachinePointSchema | undefined
|
||||||
|
>();
|
||||||
const { selectedEventData } = useSelectedEventData();
|
const { selectedEventData } = useSelectedEventData();
|
||||||
const { getPointByUuid, updateAction } = useProductStore();
|
const { getPointByUuid, updateAction } = useProductStore();
|
||||||
const { selectedProduct } = useSelectedProduct();
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
@ -20,46 +28,40 @@ function MachineMechanics() {
|
||||||
selectedEventData?.data.modelUuid,
|
selectedEventData?.data.modelUuid,
|
||||||
selectedEventData?.selectedPoint
|
selectedEventData?.selectedPoint
|
||||||
) as MachinePointSchema | undefined;
|
) as MachinePointSchema | undefined;
|
||||||
if (point && 'action' in point) {
|
if (point && "action" in point) {
|
||||||
setSelectedPointData(point);
|
setSelectedPointData(point);
|
||||||
setActiveOption(point.action.actionType as "process");
|
setActiveOption(point.action.actionType as "process");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [selectedProduct, selectedEventData])
|
}, [selectedProduct, selectedEventData, getPointByUuid]);
|
||||||
|
|
||||||
const handleActionTypeChange = (option: string) => {
|
const handleActionTypeChange = (option: string) => {
|
||||||
if (!selectedEventData || !selectedPointData) return;
|
if (!selectedEventData || !selectedPointData) return;
|
||||||
const validOption = option as "process";
|
const validOption = option as "process";
|
||||||
setActiveOption(validOption);
|
setActiveOption(validOption);
|
||||||
|
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
selectedPointData.action.actionUuid,
|
actionType: validOption,
|
||||||
{ actionType: validOption }
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRenameAction = (newName: string) => {
|
const handleRenameAction = (newName: string) => {
|
||||||
if (!selectedPointData) return;
|
if (!selectedPointData) return;
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, { actionName: newName });
|
||||||
selectedPointData.action.actionUuid,
|
|
||||||
{ actionName: newName }
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleProcessTimeChange = (value: string) => {
|
const handleProcessTimeChange = (value: string) => {
|
||||||
if (!selectedPointData) return;
|
if (!selectedPointData) return;
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
selectedPointData.action.actionUuid,
|
processTime: parseFloat(value),
|
||||||
{ processTime: parseFloat(value) }
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMaterialSelect = (material: string) => {
|
const handleMaterialSelect = (material: string) => {
|
||||||
if (!selectedPointData) return;
|
if (!selectedPointData) return;
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
selectedPointData.action.actionUuid,
|
swapMaterial: material,
|
||||||
{ swapMaterial: material }
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get current values from store
|
// Get current values from store
|
||||||
|
@ -82,7 +84,7 @@ function MachineMechanics() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{selectedEventData &&
|
{selectedEventData && (
|
||||||
<>
|
<>
|
||||||
<div className="selected-actions-details">
|
<div className="selected-actions-details">
|
||||||
<div className="selected-actions-header">
|
<div className="selected-actions-header">
|
||||||
|
@ -91,13 +93,17 @@ function MachineMechanics() {
|
||||||
onRename={handleRenameAction}
|
onRename={handleRenameAction}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<ActionsList
|
||||||
|
setSelectedPointData={setSelectedPointData}
|
||||||
|
selectedPointData={selectedPointData}
|
||||||
|
/>
|
||||||
<div className="selected-actions-list">
|
<div className="selected-actions-list">
|
||||||
<LabledDropdown
|
<LabledDropdown
|
||||||
defaultOption="process"
|
defaultOption="process"
|
||||||
options={availableActions.options}
|
options={availableActions.options}
|
||||||
onSelect={handleActionTypeChange}
|
onSelect={handleActionTypeChange}
|
||||||
/>
|
/>
|
||||||
{activeOption === "process" &&
|
{activeOption === "process" && (
|
||||||
<ProcessAction
|
<ProcessAction
|
||||||
value={currentProcessTime}
|
value={currentProcessTime}
|
||||||
min={0.1}
|
min={0.1}
|
||||||
|
@ -108,16 +114,16 @@ function MachineMechanics() {
|
||||||
swapDefaultOption={currentMaterial}
|
swapDefaultOption={currentMaterial}
|
||||||
onSwapSelect={handleMaterialSelect}
|
onSwapSelect={handleMaterialSelect}
|
||||||
/>
|
/>
|
||||||
}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="tirgger">
|
<div className="tirgger">
|
||||||
<Trigger />
|
<Trigger />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MachineMechanics
|
export default MachineMechanics;
|
||||||
|
|
|
@ -1,23 +1,29 @@
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useState } from "react";
|
||||||
import * as THREE from 'three';
|
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||||
import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown'
|
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||||
import RenameInput from '../../../../../ui/inputs/RenameInput'
|
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||||
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown'
|
import Trigger from "../trigger/Trigger";
|
||||||
import Trigger from '../trigger/Trigger'
|
import {
|
||||||
import { useSelectedEventData, useSelectedProduct, useSelectedAction } from "../../../../../../store/simulation/useSimulationStore";
|
useSelectedEventData,
|
||||||
|
useSelectedProduct,
|
||||||
|
useSelectedAction,
|
||||||
|
} from "../../../../../../store/simulation/useSimulationStore";
|
||||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||||
import { AddIcon, RemoveIcon, ResizeHeightIcon } from '../../../../../icons/ExportCommonIcons'
|
import PickAndPlaceAction from "../actions/PickAndPlaceAction";
|
||||||
import { handleResize } from '../../../../../../functions/handleResizePannel'
|
import ActionsList from "../components/ActionsList";
|
||||||
import PickAndPlaceAction from '../actions/PickAndPlaceAction'
|
|
||||||
|
|
||||||
function RoboticArmMechanics() {
|
function RoboticArmMechanics() {
|
||||||
const actionsContainerRef = useRef<HTMLDivElement>(null);
|
const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">(
|
||||||
const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">("default");
|
"default"
|
||||||
const [selectedPointData, setSelectedPointData] = useState<RoboticArmPointSchema | undefined>();
|
);
|
||||||
|
const [selectedPointData, setSelectedPointData] = useState<
|
||||||
|
RoboticArmPointSchema | undefined
|
||||||
|
>();
|
||||||
const { selectedEventData } = useSelectedEventData();
|
const { selectedEventData } = useSelectedEventData();
|
||||||
const { getPointByUuid, updateEvent, updateAction, addAction, removeAction } = useProductStore();
|
const { getPointByUuid, updateEvent, updateAction } = useProductStore();
|
||||||
const { selectedProduct } = useSelectedProduct();
|
const { selectedProduct } = useSelectedProduct();
|
||||||
const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction();
|
const { selectedAction, setSelectedAction, clearSelectedAction } =
|
||||||
|
useSelectedAction();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedEventData) {
|
if (selectedEventData) {
|
||||||
|
@ -26,129 +32,82 @@ function RoboticArmMechanics() {
|
||||||
selectedEventData.data.modelUuid,
|
selectedEventData.data.modelUuid,
|
||||||
selectedEventData.selectedPoint
|
selectedEventData.selectedPoint
|
||||||
) as RoboticArmPointSchema | undefined;
|
) as RoboticArmPointSchema | undefined;
|
||||||
if (point) {
|
if (point?.actions) {
|
||||||
setSelectedPointData(point);
|
setSelectedPointData(point);
|
||||||
setActiveOption(point.actions[0].actionType as "default" | "pickAndPlace");
|
setActiveOption(
|
||||||
if (point.actions.length > 0 && !selectedAction.actionId) {
|
point.actions[0].actionType as "default" | "pickAndPlace"
|
||||||
setSelectedAction(point.actions[0].actionUuid, point.actions[0].actionName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
clearSelectedAction();
|
|
||||||
}
|
|
||||||
}, [selectedEventData, selectedProduct]);
|
|
||||||
|
|
||||||
const handleActionSelect = (actionUuid: string, actionName: string) => {
|
|
||||||
setSelectedAction(actionUuid, actionName);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleAddAction = () => {
|
|
||||||
if (!selectedEventData || !selectedPointData) return;
|
|
||||||
|
|
||||||
const newAction = {
|
|
||||||
actionUuid: THREE.MathUtils.generateUUID(),
|
|
||||||
actionName: `Action ${selectedPointData.actions.length + 1}`,
|
|
||||||
actionType: "pickAndPlace" as "pickAndPlace",
|
|
||||||
process: {
|
|
||||||
startPoint: null,
|
|
||||||
endPoint: null
|
|
||||||
},
|
|
||||||
triggers: [] as TriggerSchema[]
|
|
||||||
};
|
|
||||||
|
|
||||||
addAction(
|
|
||||||
selectedProduct.productId,
|
|
||||||
selectedEventData.data.modelUuid,
|
|
||||||
selectedEventData.selectedPoint,
|
|
||||||
newAction
|
|
||||||
);
|
);
|
||||||
|
if (point.actions.length > 0 && !selectedAction.actionId) {
|
||||||
const updatedPoint = {
|
setSelectedAction(
|
||||||
...selectedPointData,
|
point.actions[0].actionUuid,
|
||||||
actions: [...selectedPointData.actions, newAction]
|
point.actions[0].actionName
|
||||||
};
|
);
|
||||||
setSelectedPointData(updatedPoint);
|
}
|
||||||
setSelectedAction(newAction.actionUuid, newAction.actionName);
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteAction = (actionUuid: string) => {
|
|
||||||
if (!selectedPointData) return;
|
|
||||||
|
|
||||||
removeAction(actionUuid);
|
|
||||||
const newActions = selectedPointData.actions.filter(a => 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 {
|
} else {
|
||||||
clearSelectedAction();
|
clearSelectedAction();
|
||||||
}
|
}
|
||||||
}
|
}, [
|
||||||
};
|
clearSelectedAction,
|
||||||
|
getPointByUuid,
|
||||||
|
selectedAction.actionId,
|
||||||
|
selectedEventData,
|
||||||
|
selectedProduct,
|
||||||
|
setSelectedAction,
|
||||||
|
]);
|
||||||
|
|
||||||
const handleRenameAction = (newName: string) => {
|
const handleRenameAction = (newName: string) => {
|
||||||
if (!selectedAction.actionId) return;
|
if (!selectedAction.actionId) return;
|
||||||
updateAction(
|
updateAction(selectedAction.actionId, { actionName: newName });
|
||||||
selectedAction.actionId,
|
|
||||||
{ actionName: newName }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (selectedPointData) {
|
if (selectedPointData) {
|
||||||
const updatedActions = selectedPointData.actions.map(action =>
|
const updatedActions = selectedPointData.actions.map((action) =>
|
||||||
action.actionUuid === selectedAction.actionId
|
action.actionUuid === selectedAction.actionId
|
||||||
? { ...action, actionName: newName }
|
? { ...action, actionName: newName }
|
||||||
: action
|
: action
|
||||||
);
|
);
|
||||||
setSelectedPointData({
|
setSelectedPointData({
|
||||||
...selectedPointData,
|
...selectedPointData,
|
||||||
actions: updatedActions
|
actions: updatedActions,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSpeedChange = (value: string) => {
|
const handleSpeedChange = (value: string) => {
|
||||||
if (!selectedEventData) return;
|
if (!selectedEventData) return;
|
||||||
updateEvent(
|
updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, {
|
||||||
selectedProduct.productId,
|
speed: parseFloat(value),
|
||||||
selectedEventData.data.modelUuid,
|
});
|
||||||
{ speed: parseFloat(value) }
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePickPointChange = (value: string) => {
|
const handlePickPointChange = (value: string) => {
|
||||||
if (!selectedAction.actionId || !selectedPointData) return;
|
if (!selectedAction.actionId || !selectedPointData) return;
|
||||||
const [x, y, z] = value.split(',').map(Number);
|
const [x, y, z] = value.split(",").map(Number);
|
||||||
|
|
||||||
updateAction(
|
updateAction(selectedAction.actionId, {
|
||||||
selectedAction.actionId,
|
|
||||||
{
|
|
||||||
process: {
|
process: {
|
||||||
startPoint: [x, y, z] as [number, number, number],
|
startPoint: [x, y, z] as [number, number, number],
|
||||||
endPoint: selectedPointData.actions.find(a => a.actionUuid === selectedAction.actionId)?.process.endPoint || null
|
endPoint:
|
||||||
}
|
selectedPointData.actions.find(
|
||||||
}
|
(a) => a.actionUuid === selectedAction.actionId
|
||||||
);
|
)?.process.endPoint || null,
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePlacePointChange = (value: string) => {
|
const handlePlacePointChange = (value: string) => {
|
||||||
if (!selectedAction.actionId || !selectedPointData) return;
|
if (!selectedAction.actionId || !selectedPointData) return;
|
||||||
const [x, y, z] = value.split(',').map(Number);
|
const [x, y, z] = value.split(",").map(Number);
|
||||||
|
|
||||||
updateAction(
|
updateAction(selectedAction.actionId, {
|
||||||
selectedAction.actionId,
|
|
||||||
{
|
|
||||||
process: {
|
process: {
|
||||||
startPoint: selectedPointData.actions.find(a => a.actionUuid === selectedAction.actionId)?.process.startPoint || null,
|
startPoint:
|
||||||
endPoint: [x, y, z] as [number, number, number]
|
selectedPointData.actions.find(
|
||||||
}
|
(a) => a.actionUuid === selectedAction.actionId
|
||||||
}
|
)?.process.startPoint || null,
|
||||||
);
|
endPoint: [x, y, z] as [number, number, number],
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const availableActions = {
|
const availableActions = {
|
||||||
|
@ -156,11 +115,14 @@ function RoboticArmMechanics() {
|
||||||
options: ["pickAndPlace"],
|
options: ["pickAndPlace"],
|
||||||
};
|
};
|
||||||
|
|
||||||
const currentSpeed = selectedEventData?.data.type === "roboticArm"
|
const currentSpeed =
|
||||||
|
selectedEventData?.data.type === "roboticArm"
|
||||||
? selectedEventData.data.speed.toString()
|
? selectedEventData.data.speed.toString()
|
||||||
: "0.5";
|
: "0.5";
|
||||||
|
|
||||||
const currentAction = selectedPointData?.actions.find(a => a.actionUuid === selectedAction.actionId);
|
const currentAction = selectedPointData?.actions.find(
|
||||||
|
(a) => a.actionUuid === selectedAction.actionId
|
||||||
|
);
|
||||||
const currentPickPoint = currentAction?.process.startPoint
|
const currentPickPoint = currentAction?.process.startPoint
|
||||||
? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}`
|
? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}`
|
||||||
: "";
|
: "";
|
||||||
|
@ -190,55 +152,11 @@ function RoboticArmMechanics() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="actions-list-container">
|
<ActionsList
|
||||||
<div className="actions">
|
setSelectedPointData={setSelectedPointData}
|
||||||
<div className="header">
|
selectedPointData={selectedPointData}
|
||||||
<div className="header-value">Actions</div>
|
multipleAction
|
||||||
<div className="add-button" onClick={handleAddAction}>
|
|
||||||
<AddIcon /> Add
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="lists-main-container"
|
|
||||||
ref={actionsContainerRef}
|
|
||||||
style={{ height: "120px" }}
|
|
||||||
>
|
|
||||||
<div className="list-container">
|
|
||||||
{selectedPointData.actions.map((action) => (
|
|
||||||
<div
|
|
||||||
key={action.actionUuid}
|
|
||||||
className={`list-item ${selectedAction.actionId === action.actionUuid ? "active" : ""}`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="value"
|
|
||||||
onClick={() => handleActionSelect(action.actionUuid, action.actionName)}
|
|
||||||
>
|
|
||||||
<RenameInput
|
|
||||||
value={action.actionName}
|
|
||||||
onRename={handleRenameAction}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
{selectedPointData.actions.length > 1 && (
|
|
||||||
<div
|
|
||||||
className="remove-button"
|
|
||||||
onClick={() => handleDeleteAction(action.actionUuid)}
|
|
||||||
>
|
|
||||||
<RemoveIcon />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="resize-icon"
|
|
||||||
id="action-resize"
|
|
||||||
onMouseDown={(e) => handleResize(e, actionsContainerRef)}
|
|
||||||
>
|
|
||||||
<ResizeHeightIcon />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{selectedAction.actionId && currentAction && (
|
{selectedAction.actionId && currentAction && (
|
||||||
<div className="selected-actions-details">
|
<div className="selected-actions-details">
|
||||||
|
@ -270,7 +188,7 @@ function RoboticArmMechanics() {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RoboticArmMechanics
|
export default RoboticArmMechanics;
|
||||||
|
|
|
@ -1,14 +1,22 @@
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from "react";
|
||||||
import RenameInput from '../../../../../ui/inputs/RenameInput'
|
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||||
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown'
|
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||||
import Trigger from '../trigger/Trigger'
|
import Trigger from "../trigger/Trigger";
|
||||||
import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";
|
import {
|
||||||
|
useSelectedEventData,
|
||||||
|
useSelectedProduct,
|
||||||
|
} from "../../../../../../store/simulation/useSimulationStore";
|
||||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||||
import StorageAction from '../actions/StorageAction';
|
import StorageAction from "../actions/StorageAction";
|
||||||
|
import ActionsList from "../components/ActionsList";
|
||||||
|
|
||||||
function StorageMechanics() {
|
function StorageMechanics() {
|
||||||
const [activeOption, setActiveOption] = useState<"default" | "store" | "spawn">("default");
|
const [activeOption, setActiveOption] = useState<
|
||||||
const [selectedPointData, setSelectedPointData] = useState<StoragePointSchema | undefined>();
|
"default" | "store" | "spawn"
|
||||||
|
>("default");
|
||||||
|
const [selectedPointData, setSelectedPointData] = useState<
|
||||||
|
StoragePointSchema | undefined
|
||||||
|
>();
|
||||||
const { selectedEventData } = useSelectedEventData();
|
const { selectedEventData } = useSelectedEventData();
|
||||||
const { getPointByUuid, updateAction } = useProductStore();
|
const { getPointByUuid, updateAction } = useProductStore();
|
||||||
const { selectedProduct } = useSelectedProduct();
|
const { selectedProduct } = useSelectedProduct();
|
||||||
|
@ -20,38 +28,33 @@ function StorageMechanics() {
|
||||||
selectedEventData?.data.modelUuid,
|
selectedEventData?.data.modelUuid,
|
||||||
selectedEventData?.selectedPoint
|
selectedEventData?.selectedPoint
|
||||||
) as StoragePointSchema | undefined;
|
) as StoragePointSchema | undefined;
|
||||||
if (point && 'action' in point) {
|
if (point && "action" in point) {
|
||||||
setSelectedPointData(point);
|
setSelectedPointData(point);
|
||||||
setActiveOption(point.action.actionType as "store" | "spawn");
|
setActiveOption(point.action.actionType as "store" | "spawn");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [selectedProduct, selectedEventData])
|
}, [selectedProduct, selectedEventData, getPointByUuid]);
|
||||||
|
|
||||||
const handleActionTypeChange = (option: string) => {
|
const handleActionTypeChange = (option: string) => {
|
||||||
if (!selectedEventData || !selectedPointData) return;
|
if (!selectedEventData || !selectedPointData) return;
|
||||||
const validOption = option as "store" | "spawn";
|
const validOption = option as "store" | "spawn";
|
||||||
setActiveOption(validOption);
|
setActiveOption(validOption);
|
||||||
|
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
selectedPointData.action.actionUuid,
|
actionType: validOption,
|
||||||
{ actionType: validOption }
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRenameAction = (newName: string) => {
|
const handleRenameAction = (newName: string) => {
|
||||||
if (!selectedPointData) return;
|
if (!selectedPointData) return;
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, { actionName: newName });
|
||||||
selectedPointData.action.actionUuid,
|
|
||||||
{ actionName: newName }
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCapacityChange = (value: string) => {
|
const handleCapacityChange = (value: string) => {
|
||||||
if (!selectedPointData) return;
|
if (!selectedPointData) return;
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
selectedPointData.action.actionUuid,
|
storageCapacity: parseInt(value),
|
||||||
{ storageCapacity: parseInt(value) }
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get current values from store
|
// Get current values from store
|
||||||
|
@ -70,8 +73,12 @@ function StorageMechanics() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{selectedEventData &&
|
{selectedEventData && (
|
||||||
<>
|
<>
|
||||||
|
<ActionsList
|
||||||
|
setSelectedPointData={setSelectedPointData}
|
||||||
|
selectedPointData={selectedPointData}
|
||||||
|
/>
|
||||||
<div className="selected-actions-details">
|
<div className="selected-actions-details">
|
||||||
<div className="selected-actions-header">
|
<div className="selected-actions-header">
|
||||||
<RenameInput
|
<RenameInput
|
||||||
|
@ -85,7 +92,7 @@ function StorageMechanics() {
|
||||||
options={availableActions.options}
|
options={availableActions.options}
|
||||||
onSelect={handleActionTypeChange}
|
onSelect={handleActionTypeChange}
|
||||||
/>
|
/>
|
||||||
{activeOption === "store" &&
|
{activeOption === "store" && (
|
||||||
<StorageAction
|
<StorageAction
|
||||||
value={currentCapacity}
|
value={currentCapacity}
|
||||||
defaultValue="0"
|
defaultValue="0"
|
||||||
|
@ -93,7 +100,7 @@ function StorageMechanics() {
|
||||||
max={20}
|
max={20}
|
||||||
onChange={handleCapacityChange}
|
onChange={handleCapacityChange}
|
||||||
/>
|
/>
|
||||||
}
|
)}
|
||||||
{activeOption === "spawn" && (
|
{activeOption === "spawn" && (
|
||||||
<div className="spawn-options">
|
<div className="spawn-options">
|
||||||
<p>Spawn configuration options would go here</p>
|
<p>Spawn configuration options would go here</p>
|
||||||
|
@ -105,9 +112,9 @@ function StorageMechanics() {
|
||||||
<Trigger />
|
<Trigger />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default StorageMechanics
|
export default StorageMechanics;
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from "react";
|
||||||
import InputWithDropDown from '../../../../../ui/inputs/InputWithDropDown'
|
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
|
||||||
import RenameInput from '../../../../../ui/inputs/RenameInput'
|
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||||
import LabledDropdown from '../../../../../ui/inputs/LabledDropdown'
|
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||||
import Trigger from '../trigger/Trigger'
|
import Trigger from "../trigger/Trigger";
|
||||||
import { useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore";
|
import {
|
||||||
|
useSelectedEventData,
|
||||||
|
useSelectedProduct,
|
||||||
|
} from "../../../../../../store/simulation/useSimulationStore";
|
||||||
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
import { useProductStore } from "../../../../../../store/simulation/useProductStore";
|
||||||
import TravelAction from '../actions/TravelAction'
|
import TravelAction from "../actions/TravelAction";
|
||||||
|
import ActionsList from "../components/ActionsList";
|
||||||
|
|
||||||
function VehicleMechanics() {
|
function VehicleMechanics() {
|
||||||
const [activeOption, setActiveOption] = useState<"default" | "travel">("default");
|
const [activeOption, setActiveOption] = useState<"default" | "travel">(
|
||||||
|
"default"
|
||||||
|
);
|
||||||
const [selectedPointData, setSelectedPointData] = useState<VehiclePointSchema | undefined>();
|
const [selectedPointData, setSelectedPointData] = useState<VehiclePointSchema | undefined>();
|
||||||
const { selectedEventData } = useSelectedEventData();
|
const { selectedEventData } = useSelectedEventData();
|
||||||
const { getPointByUuid, updateEvent, updateAction } = useProductStore();
|
const { getPointByUuid, updateEvent, updateAction } = useProductStore();
|
||||||
|
@ -27,15 +33,13 @@ function VehicleMechanics() {
|
||||||
setActiveOption(point.action.actionType as "travel");
|
setActiveOption(point.action.actionType as "travel");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [selectedProduct, selectedEventData])
|
}, [selectedProduct, selectedEventData, getPointByUuid]);
|
||||||
|
|
||||||
const handleSpeedChange = (value: string) => {
|
const handleSpeedChange = (value: string) => {
|
||||||
if (!selectedEventData) return;
|
if (!selectedEventData) return;
|
||||||
updateEvent(
|
updateEvent(selectedProduct.productId, selectedEventData.data.modelUuid, {
|
||||||
selectedProduct.productId,
|
speed: parseFloat(value),
|
||||||
selectedEventData.data.modelUuid,
|
});
|
||||||
{ speed: parseFloat(value) }
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleActionTypeChange = (option: string) => {
|
const handleActionTypeChange = (option: string) => {
|
||||||
|
@ -43,56 +47,41 @@ function VehicleMechanics() {
|
||||||
const validOption = option as "travel";
|
const validOption = option as "travel";
|
||||||
setActiveOption(validOption);
|
setActiveOption(validOption);
|
||||||
|
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
selectedPointData.action.actionUuid,
|
actionType: validOption,
|
||||||
{ actionType: validOption }
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRenameAction = (newName: string) => {
|
const handleRenameAction = (newName: string) => {
|
||||||
if (!selectedPointData) return;
|
if (!selectedPointData) return;
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, { actionName: newName });
|
||||||
selectedPointData.action.actionUuid,
|
|
||||||
{ actionName: newName }
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLoadCapacityChange = (value: string) => {
|
const handleLoadCapacityChange = (value: string) => {
|
||||||
if (!selectedPointData) return;
|
if (!selectedPointData) return;
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
selectedPointData.action.actionUuid,
|
loadCapacity: parseFloat(value),
|
||||||
{ loadCapacity: parseFloat(value) }
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUnloadDurationChange = (value: string) => {
|
const handleUnloadDurationChange = (value: string) => {
|
||||||
if (!selectedPointData) return;
|
if (!selectedPointData) return;
|
||||||
updateAction(
|
updateAction(selectedPointData.action.actionUuid, {
|
||||||
selectedPointData.action.actionUuid,
|
unLoadDuration: parseFloat(value),
|
||||||
{ unLoadDuration: parseFloat(value) }
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePickPointChange = (value: string) => {
|
const handlePickPointChange = (value: string) => {
|
||||||
if (!selectedPointData) return;
|
if (!selectedPointData) return;
|
||||||
const [x, y, z] = value.split(',').map(Number);
|
|
||||||
updateAction(
|
|
||||||
selectedPointData.action.actionUuid,
|
|
||||||
{ pickUpPoint: { x, y, z } }
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUnloadPointChange = (value: string) => {
|
const handleUnloadPointChange = (value: string) => {
|
||||||
if (!selectedPointData) return;
|
if (!selectedPointData) return;
|
||||||
const [x, y, z] = value.split(',').map(Number);
|
|
||||||
updateAction(
|
|
||||||
selectedPointData.action.actionUuid,
|
|
||||||
{ unLoadPoint: { x, y, z } }
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get current values from store
|
// Get current values from store
|
||||||
const currentSpeed = selectedEventData?.data.type === "vehicle"
|
const currentSpeed =
|
||||||
|
selectedEventData?.data.type === "vehicle"
|
||||||
? selectedEventData.data.speed.toString()
|
? selectedEventData.data.speed.toString()
|
||||||
: "0.5";
|
: "0.5";
|
||||||
|
|
||||||
|
@ -108,13 +97,9 @@ function VehicleMechanics() {
|
||||||
? selectedPointData.action.unLoadDuration.toString()
|
? selectedPointData.action.unLoadDuration.toString()
|
||||||
: "1";
|
: "1";
|
||||||
|
|
||||||
const currentPickPoint = selectedPointData?.action.pickUpPoint
|
const currentPickPoint = selectedPointData?.action.pickUpPoint;
|
||||||
? `${selectedPointData.action.pickUpPoint.x},${selectedPointData.action.pickUpPoint.y},${selectedPointData.action.pickUpPoint.z}`
|
|
||||||
: "";
|
|
||||||
|
|
||||||
const currentUnloadPoint = selectedPointData?.action.unLoadPoint
|
const currentUnloadPoint = selectedPointData?.action.unLoadPoint;
|
||||||
? `${selectedPointData.action.unLoadPoint.x},${selectedPointData.action.unLoadPoint.y},${selectedPointData.action.unLoadPoint.z}`
|
|
||||||
: "";
|
|
||||||
|
|
||||||
const availableActions = {
|
const availableActions = {
|
||||||
defaultOption: "travel",
|
defaultOption: "travel",
|
||||||
|
@ -123,7 +108,7 @@ function VehicleMechanics() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{selectedEventData &&
|
{selectedEventData && (
|
||||||
<>
|
<>
|
||||||
<div className="global-props">
|
<div className="global-props">
|
||||||
<div className="property-list-container">
|
<div className="property-list-container">
|
||||||
|
@ -142,7 +127,10 @@ function VehicleMechanics() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ActionsList
|
||||||
|
setSelectedPointData={setSelectedPointData}
|
||||||
|
selectedPointData={selectedPointData}
|
||||||
|
/>
|
||||||
<div className="selected-actions-details">
|
<div className="selected-actions-details">
|
||||||
<div className="selected-actions-header">
|
<div className="selected-actions-header">
|
||||||
<RenameInput
|
<RenameInput
|
||||||
|
@ -157,7 +145,7 @@ function VehicleMechanics() {
|
||||||
onSelect={handleActionTypeChange}
|
onSelect={handleActionTypeChange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{activeOption === 'travel' &&
|
{activeOption === "travel" && (
|
||||||
<TravelAction
|
<TravelAction
|
||||||
loadCapacity={{
|
loadCapacity={{
|
||||||
value: currentLoadCapacity,
|
value: currentLoadCapacity,
|
||||||
|
@ -182,16 +170,16 @@ function VehicleMechanics() {
|
||||||
// onChange: handleUnloadPointChange,
|
// onChange: handleUnloadPointChange,
|
||||||
// }}
|
// }}
|
||||||
/>
|
/>
|
||||||
}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="tirgger">
|
<div className="tirgger">
|
||||||
<Trigger />
|
<Trigger />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default VehicleMechanics
|
export default VehicleMechanics;
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
import React, { useState } from "react";
|
import React, { useRef, useState } from "react";
|
||||||
import { AddIcon, RemoveIcon } from "../../../../../icons/ExportCommonIcons";
|
import {
|
||||||
|
AddIcon,
|
||||||
|
RemoveIcon,
|
||||||
|
ResizeHeightIcon,
|
||||||
|
} from "../../../../../icons/ExportCommonIcons";
|
||||||
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
|
||||||
|
import RenameInput from "../../../../../ui/inputs/RenameInput";
|
||||||
|
import { handleResize } from "../../../../../../functions/handleResizePannel";
|
||||||
|
|
||||||
const Trigger: React.FC = () => {
|
const Trigger: React.FC = () => {
|
||||||
// State to hold the list of triggers
|
// State to hold the list of triggers
|
||||||
const [triggers, setTriggers] = useState<string[]>([]);
|
const [triggers, setTriggers] = useState<string[]>(["Trigger 1"]);
|
||||||
|
const [selectedTrigger, setSelectedTrigger] = useState<string>("Trigger 1");
|
||||||
const [activeOption, setActiveOption] = useState("onComplete");
|
const [activeOption, setActiveOption] = useState("onComplete");
|
||||||
|
const triggersContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
// States for dropdowns
|
// States for dropdowns
|
||||||
const [triggeredModel, setTriggeredModel] = useState<string[]>([]);
|
const [triggeredModel, setTriggeredModel] = useState<string[]>([]);
|
||||||
|
@ -35,28 +43,53 @@ const Trigger: React.FC = () => {
|
||||||
<div className="trigger-wrapper">
|
<div className="trigger-wrapper">
|
||||||
<div className="header">
|
<div className="header">
|
||||||
<div className="title">Trigger</div>
|
<div className="title">Trigger</div>
|
||||||
<div
|
<button
|
||||||
className="add-button"
|
className="add-button"
|
||||||
onClick={addTrigger}
|
onClick={addTrigger}
|
||||||
style={{ cursor: "pointer" }}
|
style={{ cursor: "pointer" }}
|
||||||
>
|
>
|
||||||
<AddIcon /> Add
|
<AddIcon /> Add
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="trigger-list">
|
<div className="trigger-list">
|
||||||
{/* Map over triggers and render them */}
|
|
||||||
{triggers.map((trigger, index) => (
|
|
||||||
<div key={index} className="trigger-item">
|
|
||||||
<div className="trigger-name">
|
|
||||||
{trigger}
|
|
||||||
<div
|
<div
|
||||||
|
className="lists-main-container"
|
||||||
|
ref={triggersContainerRef}
|
||||||
|
style={{ height: "120px" }}
|
||||||
|
>
|
||||||
|
<div className="list-container">
|
||||||
|
{triggers.map((trigger: any, index: number) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={`list-item ${
|
||||||
|
selectedTrigger === trigger ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => setSelectedTrigger(trigger)}
|
||||||
|
>
|
||||||
|
<button className="value" onClick={() => {}}>
|
||||||
|
<RenameInput value={trigger} onRename={() => {}} />
|
||||||
|
</button>
|
||||||
|
{triggers.length > 1 && (
|
||||||
|
<button
|
||||||
className="remove-button"
|
className="remove-button"
|
||||||
onClick={() => removeTrigger(index)}
|
onClick={() => removeTrigger(index)}
|
||||||
style={{ cursor: "pointer" }}
|
|
||||||
>
|
>
|
||||||
<RemoveIcon />
|
<RemoveIcon />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<button
|
||||||
|
className="resize-icon"
|
||||||
|
id="action-resize"
|
||||||
|
onMouseDown={(e: any) => handleResize(e, triggersContainerRef)}
|
||||||
|
>
|
||||||
|
<ResizeHeightIcon />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="trigger-item">
|
||||||
|
<div className="trigger-name">{selectedTrigger}</div>
|
||||||
<LabledDropdown
|
<LabledDropdown
|
||||||
defaultOption={activeOption}
|
defaultOption={activeOption}
|
||||||
options={["onComplete", "onStart", "onStop", "delay"]}
|
options={["onComplete", "onStart", "onStop", "delay"]}
|
||||||
|
@ -65,40 +98,39 @@ const Trigger: React.FC = () => {
|
||||||
<div className="trigger-options">
|
<div className="trigger-options">
|
||||||
<div>
|
<div>
|
||||||
<LabledDropdown
|
<LabledDropdown
|
||||||
defaultOption={triggeredModel[index] || "Select Model"}
|
defaultOption={triggeredModel[0] || "Select Model"}
|
||||||
options={["Model 1", "Model 2", "Model 3"]}
|
options={["Model 1", "Model 2", "Model 3"]}
|
||||||
onSelect={(option) => {
|
onSelect={(option) => {
|
||||||
const newModel = [...triggeredModel];
|
const newModel = [...triggeredModel];
|
||||||
newModel[index] = option;
|
newModel[0] = option;
|
||||||
setTriggeredModel(newModel);
|
setTriggeredModel(newModel);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<LabledDropdown
|
<LabledDropdown
|
||||||
defaultOption={triggeredPoint[index] || "Select Point"}
|
defaultOption={triggeredPoint[0] || "Select Point"}
|
||||||
options={["Point 1", "Point 2", "Point 3"]}
|
options={["Point 1", "Point 2", "Point 3"]}
|
||||||
onSelect={(option) => {
|
onSelect={(option) => {
|
||||||
const newPoint = [...triggeredPoint];
|
const newPoint = [...triggeredPoint];
|
||||||
newPoint[index] = option;
|
newPoint[0] = option;
|
||||||
setTriggeredPoint(newPoint);
|
setTriggeredPoint(newPoint);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<LabledDropdown
|
<LabledDropdown
|
||||||
defaultOption={triggeredAction[index] || "Select Action"}
|
defaultOption={triggeredAction[0] || "Select Action"}
|
||||||
options={["Action 1", "Action 2", "Action 3"]}
|
options={["Action 1", "Action 2", "Action 3"]}
|
||||||
onSelect={(option) => {
|
onSelect={(option) => {
|
||||||
const newAction = [...triggeredAction];
|
const newAction = [...triggeredAction];
|
||||||
newAction[index] = option;
|
newAction[0] = option;
|
||||||
setTriggeredAction(newAction);
|
setTriggeredAction(newAction);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -7,12 +7,16 @@ import {
|
||||||
} from "../../../icons/ExportCommonIcons";
|
} from "../../../icons/ExportCommonIcons";
|
||||||
import RenameInput from "../../../ui/inputs/RenameInput";
|
import RenameInput from "../../../ui/inputs/RenameInput";
|
||||||
import { handleResize } from "../../../../functions/handleResizePannel";
|
import { handleResize } from "../../../../functions/handleResizePannel";
|
||||||
import { useSelectedAsset, useSelectedProduct } from "../../../../store/simulation/useSimulationStore";
|
import {
|
||||||
|
useSelectedAsset,
|
||||||
|
useSelectedProduct,
|
||||||
|
} from "../../../../store/simulation/useSimulationStore";
|
||||||
import { useProductStore } from "../../../../store/simulation/useProductStore";
|
import { useProductStore } from "../../../../store/simulation/useProductStore";
|
||||||
import { generateUUID } from "three/src/math/MathUtils";
|
import { generateUUID } from "three/src/math/MathUtils";
|
||||||
import RenderOverlay from "../../../templates/Overlay";
|
import RenderOverlay from "../../../templates/Overlay";
|
||||||
import EditWidgetOption from "../../../ui/menu/EditWidgetOption";
|
import EditWidgetOption from "../../../ui/menu/EditWidgetOption";
|
||||||
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
|
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
|
||||||
|
import { handleAddEventToProduct } from "../../../../modules/simulation/events/points/functions/handleAddEventToProduct";
|
||||||
|
|
||||||
interface Event {
|
interface Event {
|
||||||
pathName: string;
|
pathName: string;
|
||||||
|
@ -25,16 +29,21 @@ interface ListProps {
|
||||||
const List: React.FC<ListProps> = ({ val }) => {
|
const List: React.FC<ListProps> = ({ val }) => {
|
||||||
return (
|
return (
|
||||||
<div className="process-container">
|
<div className="process-container">
|
||||||
<div className="value">
|
<div className="value">{val.pathName}</div>
|
||||||
{val.pathName}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Simulations: React.FC = () => {
|
const Simulations: React.FC = () => {
|
||||||
const productsContainerRef = useRef<HTMLDivElement>(null);
|
const productsContainerRef = useRef<HTMLDivElement>(null);
|
||||||
const { products, addProduct, removeProduct, renameProduct, addEvent, removeEvent } = useProductStore();
|
const {
|
||||||
|
products,
|
||||||
|
addProduct,
|
||||||
|
removeProduct,
|
||||||
|
renameProduct,
|
||||||
|
addEvent,
|
||||||
|
removeEvent,
|
||||||
|
} = useProductStore();
|
||||||
const { selectedProduct, setSelectedProduct } = useSelectedProduct();
|
const { selectedProduct, setSelectedProduct } = useSelectedProduct();
|
||||||
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
|
const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
|
||||||
|
|
||||||
|
@ -43,10 +52,10 @@ const Simulations: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveProduct = (productId: string) => {
|
const handleRemoveProduct = (productId: string) => {
|
||||||
const currentIndex = products.findIndex(p => p.productId === productId);
|
const currentIndex = products.findIndex((p) => p.productId === productId);
|
||||||
const isSelected = selectedProduct.productId === productId;
|
const isSelected = selectedProduct.productId === productId;
|
||||||
|
|
||||||
const updatedProducts = products.filter(p => p.productId !== productId);
|
const updatedProducts = products.filter((p) => p.productId !== productId);
|
||||||
|
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
if (updatedProducts.length > 0) {
|
if (updatedProducts.length > 0) {
|
||||||
|
@ -59,7 +68,7 @@ const Simulations: React.FC = () => {
|
||||||
updatedProducts[newSelectedIndex].productName
|
updatedProducts[newSelectedIndex].productName
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
setSelectedProduct('', '');
|
setSelectedProduct("", "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,18 +82,6 @@ const Simulations: React.FC = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddEventToProduct = () => {
|
|
||||||
if (selectedAsset) {
|
|
||||||
addEvent(selectedProduct.productId, selectedAsset);
|
|
||||||
// upsertProductOrEventApi({
|
|
||||||
// productName: selectedProduct.productName,
|
|
||||||
// productId: selectedProduct.productId,
|
|
||||||
// eventDatas: selectedAsset
|
|
||||||
// });
|
|
||||||
clearSelectedAsset();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRemoveEventFromProduct = () => {
|
const handleRemoveEventFromProduct = () => {
|
||||||
if (selectedAsset) {
|
if (selectedAsset) {
|
||||||
removeEvent(selectedProduct.productId, selectedAsset.modelUuid);
|
removeEvent(selectedProduct.productId, selectedAsset.modelUuid);
|
||||||
|
@ -96,7 +93,8 @@ const Simulations: React.FC = () => {
|
||||||
(product) => product.productId === selectedProduct.productId
|
(product) => product.productId === selectedProduct.productId
|
||||||
);
|
);
|
||||||
|
|
||||||
const events: Event[] = selectedProductData?.eventDatas.map((event) => ({
|
const events: Event[] =
|
||||||
|
selectedProductData?.eventDatas.map((event) => ({
|
||||||
pathName: event.modelName,
|
pathName: event.modelName,
|
||||||
})) || [];
|
})) || [];
|
||||||
|
|
||||||
|
@ -120,11 +118,17 @@ const Simulations: React.FC = () => {
|
||||||
{products.map((product, index) => (
|
{products.map((product, index) => (
|
||||||
<div
|
<div
|
||||||
key={product.productId}
|
key={product.productId}
|
||||||
className={`list-item ${selectedProduct.productId === product.productId ? "active" : ""}`}
|
className={`list-item ${
|
||||||
|
selectedProduct.productId === product.productId
|
||||||
|
? "active"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="value"
|
className="value"
|
||||||
onClick={() => setSelectedProduct(product.productId, product.productName)}
|
onClick={() =>
|
||||||
|
setSelectedProduct(product.productId, product.productName)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
|
@ -134,7 +138,9 @@ const Simulations: React.FC = () => {
|
||||||
/>
|
/>
|
||||||
<RenameInput
|
<RenameInput
|
||||||
value={product.productName}
|
value={product.productName}
|
||||||
onRename={(newName) => handleRenameProduct(product.productId, newName)}
|
onRename={(newName) =>
|
||||||
|
handleRenameProduct(product.productId, newName)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{products.length > 1 && (
|
{products.length > 1 && (
|
||||||
|
@ -175,7 +181,8 @@ const Simulations: React.FC = () => {
|
||||||
Need to Compare Layout?
|
Need to Compare Layout?
|
||||||
</div>
|
</div>
|
||||||
<div className="content">
|
<div className="content">
|
||||||
Click <span>'Compare'</span> to review and analyze the layout differences between them.
|
Click <span>'Compare'</span> to review and analyze the layout
|
||||||
|
differences between them.
|
||||||
</div>
|
</div>
|
||||||
<div className="input">
|
<div className="input">
|
||||||
<input type="button" value={"Compare"} className="submit" />
|
<input type="button" value={"Compare"} className="submit" />
|
||||||
|
@ -183,20 +190,25 @@ const Simulations: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{selectedAsset &&
|
{selectedAsset && (
|
||||||
<RenderOverlay>
|
<RenderOverlay>
|
||||||
<EditWidgetOption
|
<EditWidgetOption
|
||||||
options={['Add to Product', 'Remove from Product']}
|
options={["Add to Product", "Remove from Product"]}
|
||||||
onClick={(option) => {
|
onClick={(option) => {
|
||||||
if (option === 'Add to Product') {
|
if (option === "Add to Product") {
|
||||||
handleAddEventToProduct();
|
handleAddEventToProduct({
|
||||||
|
selectedAsset,
|
||||||
|
addEvent,
|
||||||
|
selectedProduct,
|
||||||
|
clearSelectedAsset,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
handleRemoveEventFromProduct();
|
handleRemoveEventFromProduct();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</RenderOverlay>
|
</RenderOverlay>
|
||||||
}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
import React from "react";
|
||||||
|
import { ProductionCapacityIcon } from "../../icons/analysis";
|
||||||
|
|
||||||
|
const ProductionCapacity = () => {
|
||||||
|
const totalBars = 6;
|
||||||
|
const progressPercent = 50;
|
||||||
|
|
||||||
|
const barsToFill = Math.floor((progressPercent / 100) * totalBars);
|
||||||
|
const partialFillPercent =
|
||||||
|
((progressPercent / 100) * totalBars - barsToFill) * 100;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="productionCapacity-container analysis-card">
|
||||||
|
<div className="productionCapacity-wrapper analysis-card-wrapper">
|
||||||
|
<div className="card-header">
|
||||||
|
<div className="header">
|
||||||
|
<div className="main-header">Throughput Summary</div>
|
||||||
|
<div className="sub-header">08:00 - 09:00 AM</div>
|
||||||
|
</div>
|
||||||
|
<div className="icon-wrapper">
|
||||||
|
<ProductionCapacityIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="process-container">
|
||||||
|
<div className="throughput-value">
|
||||||
|
<span className="value">128</span> Units/hour
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Progress Bar */}
|
||||||
|
<div className="progress-bar-wrapper">
|
||||||
|
{[...Array(totalBars)].map((_, i) => (
|
||||||
|
<div className="progress-bar" key={i}>
|
||||||
|
{i < barsToFill ? (
|
||||||
|
<div className="bar-fill full" />
|
||||||
|
) : i === barsToFill ? (
|
||||||
|
<div
|
||||||
|
className="bar-fill partial"
|
||||||
|
style={{ width: `${partialFillPercent}%` }}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="metrics-section">
|
||||||
|
<div className="metric">
|
||||||
|
<span className="label">Avg. Process Time</span>
|
||||||
|
<span className="value">28.4 Secs/unit</span>
|
||||||
|
</div>
|
||||||
|
<div className="metric">
|
||||||
|
<span className="label">Machine Utilization</span>
|
||||||
|
<span className="value">78%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProductionCapacity;
|
|
@ -0,0 +1,22 @@
|
||||||
|
import React from "react";
|
||||||
|
import { ROISummaryIcon } from "../../icons/analysis";
|
||||||
|
|
||||||
|
const ROISummary = () => {
|
||||||
|
return (
|
||||||
|
<div className="analysis-card">
|
||||||
|
<div className="throughoutSummary-wrapper analysis-card-wrapper">
|
||||||
|
<div className="card-header">
|
||||||
|
<div className="header">
|
||||||
|
<div className="main-header">ROI Summary</div>
|
||||||
|
<div className="sub-header">From 24 November, 2025</div>
|
||||||
|
</div>
|
||||||
|
<div className="icon-wrapper">
|
||||||
|
<ROISummaryIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ROISummary;
|
|
@ -0,0 +1,146 @@
|
||||||
|
import React from "react";
|
||||||
|
import { Line } from "react-chartjs-2";
|
||||||
|
import {
|
||||||
|
Chart as ChartJS,
|
||||||
|
LineElement,
|
||||||
|
CategoryScale,
|
||||||
|
LinearScale,
|
||||||
|
PointElement,
|
||||||
|
} from "chart.js";
|
||||||
|
import { PowerIcon, ThroughputSummaryIcon } from "../../icons/analysis";
|
||||||
|
|
||||||
|
ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement);
|
||||||
|
|
||||||
|
const ThroughputSummary = () => {
|
||||||
|
const data = {
|
||||||
|
labels: ["08:00", "08:10", "08:20", "08:30", "08:40", "08:50", "09:00"],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: "Units/hour",
|
||||||
|
data: [100, 120, 110, 130, 125, 128, 132],
|
||||||
|
borderColor: "#B392F0",
|
||||||
|
tension: 0.4,
|
||||||
|
pointRadius: 0, // hide points
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
responsive: true,
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
grid: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
display: false,
|
||||||
|
color: "#fff",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
grid: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
display: false,
|
||||||
|
color: "#fff",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const shiftUtilization = {
|
||||||
|
"shift 1": 25,
|
||||||
|
"shift 2": 45,
|
||||||
|
"shift 3": 15,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="throughoutSummary analysis-card">
|
||||||
|
<div className="throughoutSummary-wrapper analysis-card-wrapper">
|
||||||
|
<div className="card-header">
|
||||||
|
<div className="header">
|
||||||
|
<div className="main-header">Throughput Summary</div>
|
||||||
|
<div className="sub-header">08:00 - 09:00 AM</div>
|
||||||
|
</div>
|
||||||
|
<div className="icon-wrapper">
|
||||||
|
<ThroughputSummaryIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="process-container">
|
||||||
|
<div className="throughput-value">
|
||||||
|
<span className="value">1240</span> Units/hour
|
||||||
|
</div>
|
||||||
|
<div className="lineChart">
|
||||||
|
<div className="assetUsage">
|
||||||
|
<div className="key">Asset usage</div>
|
||||||
|
<div className="value">85%</div>
|
||||||
|
</div>
|
||||||
|
<Line data={data} options={options} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="footer">
|
||||||
|
<div className="energyConsumption footer-card">
|
||||||
|
<div className="header">Energy Consumption</div>
|
||||||
|
<div className="value-container">
|
||||||
|
<div className="energy-icon">
|
||||||
|
<PowerIcon />
|
||||||
|
</div>
|
||||||
|
<div className="value-wrapper">
|
||||||
|
<div className="value">456</div>
|
||||||
|
<div className="unit">KWH</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="shiftUtilization footer-card">
|
||||||
|
<div className="header">Shift Utilization</div>
|
||||||
|
<div className="value-container">
|
||||||
|
<div className="value">85%</div>
|
||||||
|
|
||||||
|
<div className="progress-wrapper">
|
||||||
|
<div
|
||||||
|
className="progress shift-1"
|
||||||
|
style={{ width: "30%" }}
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
className="progress shift-2"
|
||||||
|
style={{ width: "40%" }}
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
className="progress shift-3"
|
||||||
|
style={{ width: "30%" }}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
<div className="progress-indicator">
|
||||||
|
<div className="shift-wrapper">
|
||||||
|
<span className="indicator shift-1"></span>
|
||||||
|
<label>Shift 1</label>
|
||||||
|
</div>
|
||||||
|
<div className="shift-wrapper">
|
||||||
|
<span className="indicator shift-2"></span>
|
||||||
|
<label>Shift 2</label>
|
||||||
|
</div>
|
||||||
|
<div className="shift-wrapper">
|
||||||
|
<span className="indicator shift-3"></span>
|
||||||
|
<label>Shift 3</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ThroughputSummary;
|
|
@ -1,14 +1,32 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import LabledDropdown from "./LabledDropdown";
|
|
||||||
import { ArrowIcon } from "../../icons/ExportCommonIcons";
|
import { ArrowIcon } from "../../icons/ExportCommonIcons";
|
||||||
|
import LabledDropdown from "./LabledDropdown";
|
||||||
|
|
||||||
const PreviewSelectionWithUpload: React.FC = () => {
|
interface PreviewSelectionWithUploadProps {
|
||||||
const [showPreview, setSetshowPreview] = useState(false);
|
preview?: boolean;
|
||||||
|
upload?: boolean;
|
||||||
|
label?: string;
|
||||||
|
onSelect: (option: string) => void;
|
||||||
|
defaultOption: string;
|
||||||
|
options: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const PreviewSelectionWithUpload: React.FC<PreviewSelectionWithUploadProps> = ({
|
||||||
|
preview = false,
|
||||||
|
upload = false,
|
||||||
|
onSelect,
|
||||||
|
label,
|
||||||
|
defaultOption,
|
||||||
|
options,
|
||||||
|
}) => {
|
||||||
|
const [showPreview, setShowPreview] = useState(false);
|
||||||
return (
|
return (
|
||||||
<div className="preview-selection-with-upload-wrapper">
|
<div className="preview-selection-with-upload-wrapper">
|
||||||
<div
|
{preview && (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
className="input-header-container"
|
className="input-header-container"
|
||||||
onClick={() => setSetshowPreview(!showPreview)}
|
onClick={() => setShowPreview(!showPreview)}
|
||||||
>
|
>
|
||||||
<div className="input-header">Preview</div>
|
<div className="input-header">Preview</div>
|
||||||
<div
|
<div
|
||||||
|
@ -17,12 +35,15 @@ const PreviewSelectionWithUpload: React.FC = () => {
|
||||||
>
|
>
|
||||||
<ArrowIcon />
|
<ArrowIcon />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</button>
|
||||||
{showPreview && (
|
{showPreview && (
|
||||||
<div className="canvas-wrapper">
|
<div className="canvas-wrapper">
|
||||||
<div className="canvas-container"></div>
|
<div className="canvas-container"></div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{upload && (
|
||||||
<div className="asset-selection-container">
|
<div className="asset-selection-container">
|
||||||
<div className="upload-custom-asset-button">
|
<div className="upload-custom-asset-button">
|
||||||
<div className="title">Upload Product</div>
|
<div className="title">Upload Product</div>
|
||||||
|
@ -31,11 +52,21 @@ const PreviewSelectionWithUpload: React.FC = () => {
|
||||||
accept=".glb, .gltf"
|
accept=".glb, .gltf"
|
||||||
id="simulation-product-upload"
|
id="simulation-product-upload"
|
||||||
/>
|
/>
|
||||||
<label className="upload-button" htmlFor="simulation-product-upload">
|
<label
|
||||||
|
className="upload-button"
|
||||||
|
htmlFor="simulation-product-upload"
|
||||||
|
>
|
||||||
Upload here
|
Upload here
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
<LabledDropdown
|
||||||
|
label={label}
|
||||||
|
defaultOption={defaultOption}
|
||||||
|
options={options}
|
||||||
|
onSelect={onSelect}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
ArrowIcon,
|
ArrowIcon,
|
||||||
EyeIcon,
|
EyeIcon,
|
||||||
LockIcon,
|
LockIcon,
|
||||||
RmoveIcon,
|
RemoveIcon,
|
||||||
} from "../../icons/ExportCommonIcons";
|
} from "../../icons/ExportCommonIcons";
|
||||||
import { useThree } from "@react-three/fiber";
|
import { useThree } from "@react-three/fiber";
|
||||||
import { useFloorItems, useZoneAssetId, useZones } from "../../../store/store";
|
import { useFloorItems, useZoneAssetId, useZones } from "../../../store/store";
|
||||||
|
@ -181,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 && (
|
||||||
|
@ -218,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>
|
||||||
|
|
|
@ -56,6 +56,7 @@ 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";
|
||||||
import NavMesh from "../simulation/vehicle/navMesh/navMesh";
|
import NavMesh from "../simulation/vehicle/navMesh/navMesh";
|
||||||
|
import ProductionCapacity from "../../components/ui/analysis/ProductionCapacity";
|
||||||
|
|
||||||
export default function Builder() {
|
export default function Builder() {
|
||||||
const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
|
const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
|
||||||
|
@ -110,7 +111,8 @@ export default function Builder() {
|
||||||
|
|
||||||
const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position.
|
const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position.
|
||||||
|
|
||||||
const [selectedItemsIndex, setSelectedItemsIndex] = useState<Types.Number | null>(null); // State for tracking the index of the selected item.
|
const [selectedItemsIndex, setSelectedItemsIndex] =
|
||||||
|
useState<Types.Number | null>(null); // State for tracking the index of the selected item.
|
||||||
const { activeLayer, setActiveLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx.
|
const { activeLayer, setActiveLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx.
|
||||||
const { toggleView, setToggleView } = useToggleView(); // State for toggling between 2D and 3D.
|
const { toggleView, setToggleView } = useToggleView(); // State for toggling between 2D and 3D.
|
||||||
const { toolMode, setToolMode } = useToolMode();
|
const { toolMode, setToolMode } = useToolMode();
|
||||||
|
@ -349,7 +351,6 @@ export default function Builder() {
|
||||||
<MeasurementTool />
|
<MeasurementTool />
|
||||||
|
|
||||||
<NavMesh lines={lines} />
|
<NavMesh lines={lines} />
|
||||||
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,21 +10,13 @@ import {
|
||||||
} from "../../../../../store/simulation/useSimulationStore";
|
} from "../../../../../store/simulation/useSimulationStore";
|
||||||
|
|
||||||
function PointsCreator() {
|
function PointsCreator() {
|
||||||
const { events, updatePoint, getPointByUuid, getEventByModelUuid } =
|
const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore();
|
||||||
useEventsStore();
|
|
||||||
const { activeModule } = useModuleStore();
|
const { activeModule } = useModuleStore();
|
||||||
const transformRef = useRef<any>(null);
|
const transformRef = useRef<any>(null);
|
||||||
const [transformMode, setTransformMode] = useState<
|
const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
|
||||||
"translate" | "rotate" | null
|
|
||||||
>(null);
|
|
||||||
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({});
|
||||||
const {
|
const { selectedEventSphere, setSelectedEventSphere, clearSelectedEventSphere, } = useSelectedEventSphere();
|
||||||
selectedEventSphere,
|
const { selectedEventData, setSelectedEventData, clearSelectedEventData } = useSelectedEventData();
|
||||||
setSelectedEventSphere,
|
|
||||||
clearSelectedEventSphere,
|
|
||||||
} = useSelectedEventSphere();
|
|
||||||
const { setSelectedEventData, clearSelectedEventData } =
|
|
||||||
useSelectedEventData();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedEventSphere) {
|
if (selectedEventSphere) {
|
||||||
|
@ -104,7 +96,9 @@ function PointsCreator() {
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
onPointerMissed={() => {
|
onPointerMissed={() => {
|
||||||
|
if (selectedEventData?.data.type !== 'vehicle') {
|
||||||
// clearSelectedEventSphere();
|
// clearSelectedEventSphere();
|
||||||
|
}
|
||||||
setTransformMode(null);
|
setTransformMode(null);
|
||||||
}}
|
}}
|
||||||
key={`${i}-${j}`}
|
key={`${i}-${j}`}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
interface HandleAddEventToProductParams {
|
||||||
|
selectedAsset: any; // Replace `any` with specific type if you have it
|
||||||
|
addEvent: (productId: string, asset: any) => void;
|
||||||
|
selectedProduct: {
|
||||||
|
productId: string;
|
||||||
|
productName: string;
|
||||||
|
// Add other fields if needed
|
||||||
|
};
|
||||||
|
clearSelectedAsset: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const handleAddEventToProduct = ({
|
||||||
|
selectedAsset,
|
||||||
|
addEvent,
|
||||||
|
selectedProduct,
|
||||||
|
clearSelectedAsset,
|
||||||
|
}: HandleAddEventToProductParams) => {
|
||||||
|
console.log('selectedProduct: ', selectedProduct);
|
||||||
|
if (selectedAsset) {
|
||||||
|
addEvent(selectedProduct.productId, selectedAsset);
|
||||||
|
// upsertProductOrEventApi({
|
||||||
|
// productName: selectedProduct.productName,
|
||||||
|
// productId: selectedProduct.productId,
|
||||||
|
// eventDatas: selectedAsset
|
||||||
|
// });
|
||||||
|
clearSelectedAsset();
|
||||||
|
}
|
||||||
|
};
|
|
@ -8,7 +8,7 @@ function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase, ikSolver, t
|
||||||
const { armBots } = useArmBotStore();
|
const { armBots } = useArmBotStore();
|
||||||
const { scene } = useThree();
|
const { scene } = useThree();
|
||||||
const restSpeed = 0.1;
|
const restSpeed = 0.1;
|
||||||
const restPosition = new THREE.Vector3(0, 2, 1.6);
|
const restPosition = new THREE.Vector3(0, 1, -1.6);
|
||||||
const initialCurveRef = useRef<THREE.CatmullRomCurve3 | null>(null);
|
const initialCurveRef = useRef<THREE.CatmullRomCurve3 | null>(null);
|
||||||
const initialStartPositionRef = useRef<THREE.Vector3 | null>(null);
|
const initialStartPositionRef = useRef<THREE.Vector3 | null>(null);
|
||||||
const [initialProgress, setInitialProgress] = useState(0);
|
const [initialProgress, setInitialProgress] = useState(0);
|
||||||
|
@ -22,6 +22,7 @@ function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase, ikSolver, t
|
||||||
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
|
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
setCurrentPath(path)
|
setCurrentPath(path)
|
||||||
}, [path])
|
}, [path])
|
||||||
|
|
||||||
|
@ -42,13 +43,13 @@ function RoboticArmAnimator({ armUuid, HandleCallback, currentPhase, ikSolver, t
|
||||||
currentPath.map(point => new THREE.Vector3(point[0], point[1], point[2]))
|
currentPath.map(point => new THREE.Vector3(point[0], point[1], point[2]))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const next = initialProgressRef.current + delta * 0.5;
|
const next = initialProgressRef.current + delta * 0.5;
|
||||||
if (next >= 1) {
|
if (next >= 1) {
|
||||||
bone.position.copy(restPosition);
|
// bone.position.copy(restPosition);
|
||||||
HandleCallback(); // Call the callback when the path is completed
|
HandleCallback(); // Call the callback when the path is completed
|
||||||
initialProgressRef.current = 0; // Set ref to 1 when done
|
initialProgressRef.current = 0; // Set ref to 1 when done
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const point = curve.getPoint(next); // Get the interpolated point from the curve
|
const point = curve.getPoint(next); // Get the interpolated point from the curve
|
||||||
bone.position.copy(point); // Update the bone position along the curve
|
bone.position.copy(point); // Update the bone position along the curve
|
||||||
initialProgressRef.current = next; // Update progress
|
initialProgressRef.current = next; // Update progress
|
||||||
|
|
|
@ -16,6 +16,7 @@ interface Process {
|
||||||
endPoint?: Vector3;
|
endPoint?: Vector3;
|
||||||
speed: number;
|
speed: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) {
|
function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) {
|
||||||
|
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
@ -29,7 +30,7 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) {
|
||||||
const groupRef = useRef<any>(null);
|
const groupRef = useRef<any>(null);
|
||||||
const [processes, setProcesses] = useState<Process[]>([]);
|
const [processes, setProcesses] = useState<Process[]>([]);
|
||||||
const [armBotCurvePoints, setArmBotCurvePoints] = useState({ start: [], end: [] })
|
const [armBotCurvePoints, setArmBotCurvePoints] = useState({ start: [], end: [] })
|
||||||
const restPosition = new THREE.Vector3(0, 2, 1.6);
|
const restPosition = new THREE.Vector3(0, 1, -1.6);
|
||||||
let armBotCurveRef = useRef<THREE.CatmullRomCurve3 | null>(null)
|
let armBotCurveRef = useRef<THREE.CatmullRomCurve3 | null>(null)
|
||||||
const [path, setPath] = useState<[number, number, number][]>([]);
|
const [path, setPath] = useState<[number, number, number][]>([]);
|
||||||
|
|
||||||
|
@ -62,11 +63,11 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) {
|
||||||
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logStatus(robot.modelUuid, "Starting from init to rest")
|
logStatus(robot.modelUuid, "Moving armBot from initial point to rest position.")
|
||||||
}
|
}
|
||||||
//Waiting for trigger.
|
//Waiting for trigger.
|
||||||
else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "rest" && !robot.currentAction) {
|
else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "rest" && !robot.currentAction) {
|
||||||
|
logStatus(robot.modelUuid, "Waiting to trigger CurrentAction")
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
addCurrentAction(robot.modelUuid, 'action-003');
|
addCurrentAction(robot.modelUuid, 'action-003');
|
||||||
}, 3000);
|
}, 3000);
|
||||||
|
@ -84,7 +85,7 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logStatus(robot.modelUuid, "Starting from rest to start")
|
logStatus(robot.modelUuid, "Moving armBot from rest point to start position.")
|
||||||
}
|
}
|
||||||
else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "picking" && robot.currentAction) {
|
else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "picking" && robot.currentAction) {
|
||||||
setArmBotActive(robot.modelUuid, true);
|
setArmBotActive(robot.modelUuid, true);
|
||||||
|
@ -98,10 +99,13 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) {
|
||||||
new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2])
|
new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2])
|
||||||
);
|
);
|
||||||
if (curve) {
|
if (curve) {
|
||||||
|
setTimeout(() => {
|
||||||
|
logStatus(robot.modelUuid, "picking the object");
|
||||||
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
||||||
|
}, 1500)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logStatus(robot.modelUuid, "Starting from start to end")
|
logStatus(robot.modelUuid, "Moving armBot from start point to end position.")
|
||||||
}
|
}
|
||||||
else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "dropping" && robot.currentAction) {
|
else if (robot && !robot.isActive && robot.state === "idle" && currentPhase === "dropping" && robot.currentAction) {
|
||||||
setArmBotActive(robot.modelUuid, true);
|
setArmBotActive(robot.modelUuid, true);
|
||||||
|
@ -112,10 +116,13 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) {
|
||||||
let curve = createCurveBetweenTwoPoints(new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]), restPosition
|
let curve = createCurveBetweenTwoPoints(new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]), restPosition
|
||||||
);
|
);
|
||||||
if (curve) {
|
if (curve) {
|
||||||
|
setTimeout(() => {
|
||||||
|
logStatus(robot.modelUuid, "dropping the object");
|
||||||
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
setPath(curve.points.map(point => [point.x, point.y, point.z]));
|
||||||
|
}, 1500)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logStatus(robot.modelUuid, "Starting from end to rest")
|
logStatus(robot.modelUuid, "Moving armBot from end point to rest position.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,28 +140,28 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) {
|
||||||
|
|
||||||
const HandleCallback = () => {
|
const HandleCallback = () => {
|
||||||
if (robot.isActive && robot.state == "running" && currentPhase == "init-to-rest") {
|
if (robot.isActive && robot.state == "running" && currentPhase == "init-to-rest") {
|
||||||
|
logStatus(robot.modelUuid, "Callback triggered: rest");
|
||||||
setArmBotActive(robot.modelUuid, false)
|
setArmBotActive(robot.modelUuid, false)
|
||||||
setArmBotState(robot.modelUuid, "idle")
|
setArmBotState(robot.modelUuid, "idle")
|
||||||
setCurrentPhase("rest");
|
setCurrentPhase("rest");
|
||||||
setPath([])
|
setPath([])
|
||||||
}
|
}
|
||||||
else if (robot.isActive && robot.state == "running" && currentPhase == "rest-to-start") {
|
else if (robot.isActive && robot.state == "running" && currentPhase == "rest-to-start") {
|
||||||
|
logStatus(robot.modelUuid, "Callback triggered: pick.");
|
||||||
setArmBotActive(robot.modelUuid, false)
|
setArmBotActive(robot.modelUuid, false)
|
||||||
setArmBotState(robot.modelUuid, "idle")
|
setArmBotState(robot.modelUuid, "idle")
|
||||||
setCurrentPhase("picking");
|
setCurrentPhase("picking");
|
||||||
setPath([])
|
setPath([])
|
||||||
}
|
}
|
||||||
else if (robot.isActive && robot.state == "running" && currentPhase == "start-to-end") {
|
else if (robot.isActive && robot.state == "running" && currentPhase == "start-to-end") {
|
||||||
|
logStatus(robot.modelUuid, "Callback triggered: drop.");
|
||||||
setArmBotActive(robot.modelUuid, false)
|
setArmBotActive(robot.modelUuid, false)
|
||||||
setArmBotState(robot.modelUuid, "idle")
|
setArmBotState(robot.modelUuid, "idle")
|
||||||
setCurrentPhase("dropping");
|
setCurrentPhase("dropping");
|
||||||
setPath([])
|
setPath([])
|
||||||
}
|
}
|
||||||
else if (robot.isActive && robot.state == "running" && currentPhase == "end-to-rest") {
|
else if (robot.isActive && robot.state == "running" && currentPhase == "end-to-rest") {
|
||||||
|
logStatus(robot.modelUuid, "Callback triggered: rest, cycle completed.");
|
||||||
setArmBotActive(robot.modelUuid, false)
|
setArmBotActive(robot.modelUuid, false)
|
||||||
setArmBotState(robot.modelUuid, "idle")
|
setArmBotState(robot.modelUuid, "idle")
|
||||||
setCurrentPhase("rest");
|
setCurrentPhase("rest");
|
||||||
|
@ -163,12 +170,12 @@ function RoboticArmInstance({ robot }: { robot: ArmBotStatus }) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const logStatus = (id: string, status: string) => {
|
const logStatus = (id: string, status: string) => {
|
||||||
|
// console.log(id + "," + status);
|
||||||
|
console.log( status);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<IKInstance modelUrl={armModel} setIkSolver={setIkSolver} ikSolver={ikSolver} robot={robot} groupRef={groupRef} processes={processes}
|
<IKInstance modelUrl={armModel} setIkSolver={setIkSolver} ikSolver={ikSolver} robot={robot} groupRef={groupRef} processes={processes}
|
||||||
setArmBotCurvePoints={setArmBotCurvePoints} />
|
setArmBotCurvePoints={setArmBotCurvePoints} />
|
||||||
<RoboticArmAnimator armUuid={robot?.modelUuid} HandleCallback={HandleCallback}
|
<RoboticArmAnimator armUuid={robot?.modelUuid} HandleCallback={HandleCallback}
|
||||||
|
|
|
@ -15,6 +15,7 @@ type IKInstanceProps = {
|
||||||
setArmBotCurvePoints: any
|
setArmBotCurvePoints: any
|
||||||
};
|
};
|
||||||
function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processes, setArmBotCurvePoints }: IKInstanceProps) {
|
function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processes, setArmBotCurvePoints }: IKInstanceProps) {
|
||||||
|
|
||||||
const { scene } = useThree();
|
const { scene } = useThree();
|
||||||
const gltf = useLoader(GLTFLoader, modelUrl, (loader) => {
|
const gltf = useLoader(GLTFLoader, modelUrl, (loader) => {
|
||||||
const draco = new DRACOLoader();
|
const draco = new DRACOLoader();
|
||||||
|
@ -64,16 +65,16 @@ function IKInstance({ modelUrl, setIkSolver, ikSolver, robot, groupRef, processe
|
||||||
const solver = new CCDIKSolver(OOI.Skinned_Mesh, iks);
|
const solver = new CCDIKSolver(OOI.Skinned_Mesh, iks);
|
||||||
setIkSolver(solver);
|
setIkSolver(solver);
|
||||||
|
|
||||||
const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05);
|
const helper = new CCDIKHelper(OOI.Skinned_Mesh, iks, 0.05)
|
||||||
|
|
||||||
// scene.add(groupRef.current)
|
// scene.add(helper)
|
||||||
|
|
||||||
|
|
||||||
}, [gltf]);
|
}, [gltf]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<group ref={groupRef} position={robot.position}>
|
<group ref={groupRef} position={robot.position} rotation={robot.rotation}>
|
||||||
<primitive
|
<primitive
|
||||||
uuid={"ArmBot-X200"}
|
uuid={"ArmBot-X200"}
|
||||||
object={cloned}
|
object={cloned}
|
||||||
|
|
|
@ -7,18 +7,19 @@ function RoboticArm() {
|
||||||
const { armBots, addArmBot, removeArmBot } = useArmBotStore();
|
const { armBots, addArmBot, removeArmBot } = useArmBotStore();
|
||||||
const { floorItems } = useFloorItems();
|
const { floorItems } = useFloorItems();
|
||||||
|
|
||||||
|
|
||||||
const armBotStatusSample: RoboticArmEventSchema[] = [
|
const armBotStatusSample: RoboticArmEventSchema[] = [
|
||||||
{
|
{
|
||||||
state: "idle",
|
state: "idle",
|
||||||
modelUuid: "armbot-xyz-001",
|
modelUuid: "3abf5d46-b59e-4e6b-9c02-a4634b64b82d",
|
||||||
modelName: "ArmBot-X200",
|
modelName: "ArmBot-X200",
|
||||||
position: [91.94347308985614, 0, 6.742905194869091],
|
position: [0.20849215906958463, 0, 0.32079278127773675],
|
||||||
rotation: [0, 0, 0],
|
rotation: [-1.3768690876192207e-15, 1.4883085074751308, 1.5407776675834467e-15],
|
||||||
type: "roboticArm",
|
type: "roboticArm",
|
||||||
speed: 1.5,
|
speed: 1.5,
|
||||||
point: {
|
point: {
|
||||||
uuid: "point-123",
|
uuid: "point-123",
|
||||||
position: [0, 1.5, 0],
|
position: [0, 2.6, 0],
|
||||||
rotation: [0, 0, 0],
|
rotation: [0, 0, 0],
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
|
@ -26,9 +27,21 @@ function RoboticArm() {
|
||||||
actionName: "Pick Component",
|
actionName: "Pick Component",
|
||||||
actionType: "pickAndPlace",
|
actionType: "pickAndPlace",
|
||||||
process: {
|
process: {
|
||||||
startPoint: [5.52543010919071, 1, -8.433681161200905],
|
startPoint: [-1, 2, 1],
|
||||||
endPoint: [10.52543010919071, 1, -12.433681161200905],
|
endPoint: [-2, 1, -1],
|
||||||
},
|
},
|
||||||
|
// process: {
|
||||||
|
// "startPoint": [
|
||||||
|
// 0.37114476008711866,
|
||||||
|
// 1.9999999999999998,
|
||||||
|
// 1.8418816116721384
|
||||||
|
// ],
|
||||||
|
// "endPoint": [
|
||||||
|
// -0.42197069459490777,
|
||||||
|
// 1,
|
||||||
|
// -3.159515927851809
|
||||||
|
// ]
|
||||||
|
// },
|
||||||
triggers: [
|
triggers: [
|
||||||
{
|
{
|
||||||
triggerUuid: "trigger-001",
|
triggerUuid: "trigger-001",
|
||||||
|
@ -153,7 +166,7 @@ function RoboticArm() {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
//
|
|
||||||
}, [armBots]);
|
}, [armBots]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
import React, { useRef } from "react";
|
||||||
|
import * as THREE from "three";
|
||||||
|
import { ThreeEvent } from "@react-three/fiber";
|
||||||
|
|
||||||
|
interface PickDropProps {
|
||||||
|
position: number[];
|
||||||
|
modelUuid: string;
|
||||||
|
pointUuid: string;
|
||||||
|
actionType: "pick" | "drop";
|
||||||
|
actionUuid: string;
|
||||||
|
gltfScene: THREE.Group;
|
||||||
|
selectedPoint: THREE.Mesh | null;
|
||||||
|
handlePointerDown: (e: ThreeEvent<PointerEvent>) => void;
|
||||||
|
isSelected: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PickDropPoints: React.FC<PickDropProps> = ({
|
||||||
|
position,
|
||||||
|
modelUuid,
|
||||||
|
pointUuid,
|
||||||
|
actionType,
|
||||||
|
actionUuid,
|
||||||
|
gltfScene,
|
||||||
|
selectedPoint,
|
||||||
|
handlePointerDown,
|
||||||
|
isSelected,
|
||||||
|
}) => {
|
||||||
|
const groupRef = useRef<THREE.Group>(null);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group
|
||||||
|
ref={groupRef}
|
||||||
|
position={
|
||||||
|
Array.isArray(position) && position.length === 3
|
||||||
|
? new THREE.Vector3(...position)
|
||||||
|
: new THREE.Vector3(0, 0, 0)
|
||||||
|
}
|
||||||
|
onPointerDown={(e) => {
|
||||||
|
e.stopPropagation(); // Important to prevent event bubbling
|
||||||
|
if (!isSelected) return;
|
||||||
|
handlePointerDown(e);
|
||||||
|
}}
|
||||||
|
userData={{ modelUuid, pointUuid, actionType, actionUuid }}
|
||||||
|
>
|
||||||
|
<primitive
|
||||||
|
object={gltfScene.clone()}
|
||||||
|
position={[0, 0, 0]} // Ensure this stays at origin
|
||||||
|
scale={[0.5, 0.5, 0.5]}
|
||||||
|
/>
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PickDropPoints;
|
|
@ -0,0 +1,131 @@
|
||||||
|
import { useRef } from "react";
|
||||||
|
import * as THREE from "three";
|
||||||
|
import { ThreeEvent, useThree } from "@react-three/fiber";
|
||||||
|
|
||||||
|
type OnUpdateCallback = (object: THREE.Object3D) => void;
|
||||||
|
|
||||||
|
export default function useDraggableGLTF(onUpdate: OnUpdateCallback) {
|
||||||
|
const { camera, gl, controls, scene } = useThree();
|
||||||
|
const activeObjRef = useRef<THREE.Object3D | null>(null);
|
||||||
|
const planeRef = useRef<THREE.Plane>(
|
||||||
|
new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)
|
||||||
|
);
|
||||||
|
const offsetRef = useRef<THREE.Vector3>(new THREE.Vector3());
|
||||||
|
const initialPositionRef = useRef<THREE.Vector3>(new THREE.Vector3());
|
||||||
|
|
||||||
|
const raycaster = new THREE.Raycaster();
|
||||||
|
const pointer = new THREE.Vector2();
|
||||||
|
|
||||||
|
const handlePointerDown = (e: ThreeEvent<PointerEvent>) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
let obj: THREE.Object3D | null = e.object;
|
||||||
|
|
||||||
|
// Traverse up until we find modelUuid in userData
|
||||||
|
while (obj && !obj.userData?.modelUuid) {
|
||||||
|
obj = obj.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!obj) return;
|
||||||
|
|
||||||
|
// Disable orbit controls while dragging
|
||||||
|
if (controls) (controls as any).enabled = false;
|
||||||
|
|
||||||
|
activeObjRef.current = obj;
|
||||||
|
initialPositionRef.current.copy(obj.position);
|
||||||
|
|
||||||
|
// Get world position
|
||||||
|
const objectWorldPos = new THREE.Vector3();
|
||||||
|
obj.getWorldPosition(objectWorldPos);
|
||||||
|
|
||||||
|
// Set plane at the object's Y level
|
||||||
|
planeRef.current.set(new THREE.Vector3(0, 1, 0), -objectWorldPos.y);
|
||||||
|
|
||||||
|
// Convert pointer to NDC
|
||||||
|
const rect = gl.domElement.getBoundingClientRect();
|
||||||
|
pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
|
||||||
|
pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
|
||||||
|
|
||||||
|
// Raycast to intersection
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const intersection = new THREE.Vector3();
|
||||||
|
raycaster.ray.intersectPlane(planeRef.current, intersection);
|
||||||
|
|
||||||
|
// Calculate offset
|
||||||
|
offsetRef.current.copy(objectWorldPos).sub(intersection);
|
||||||
|
|
||||||
|
// Start listening for drag
|
||||||
|
gl.domElement.addEventListener("pointermove", handlePointerMove);
|
||||||
|
gl.domElement.addEventListener("pointerup", handlePointerUp);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePointerMove = (e: PointerEvent) => {
|
||||||
|
if (!activeObjRef.current) return;
|
||||||
|
|
||||||
|
// Check if Shift key is pressed
|
||||||
|
const isShiftKeyPressed = e.shiftKey;
|
||||||
|
|
||||||
|
// Get the mouse position relative to the canvas
|
||||||
|
const rect = gl.domElement.getBoundingClientRect();
|
||||||
|
pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
|
||||||
|
pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
|
||||||
|
|
||||||
|
// Update raycaster to point to the mouse position
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
|
||||||
|
// Create a vector to store intersection point
|
||||||
|
const intersection = new THREE.Vector3();
|
||||||
|
const intersects = raycaster.ray.intersectPlane(planeRef.current, intersection);
|
||||||
|
if (!intersects) return;
|
||||||
|
|
||||||
|
// Add offset for dragging
|
||||||
|
intersection.add(offsetRef.current);
|
||||||
|
console.log('intersection: ', intersection);
|
||||||
|
|
||||||
|
// Get the parent's world matrix if exists
|
||||||
|
const parent = activeObjRef.current.parent;
|
||||||
|
const targetPosition = new THREE.Vector3();
|
||||||
|
|
||||||
|
if (isShiftKeyPressed) {
|
||||||
|
console.log('isShiftKeyPressed: ', isShiftKeyPressed);
|
||||||
|
// For Y-axis only movement, maintain original X and Z
|
||||||
|
console.log('initialPositionRef: ', initialPositionRef);
|
||||||
|
console.log('intersection.y: ', intersection);
|
||||||
|
targetPosition.set(
|
||||||
|
initialPositionRef.current.x,
|
||||||
|
intersection.y,
|
||||||
|
initialPositionRef.current.z
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// For free movement
|
||||||
|
targetPosition.copy(intersection);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert world position to local if object is nested inside a parent
|
||||||
|
if (parent) {
|
||||||
|
parent.worldToLocal(targetPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update object position
|
||||||
|
activeObjRef.current.position.copy(targetPosition);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePointerUp = () => {
|
||||||
|
if (controls) (controls as any).enabled = true;
|
||||||
|
|
||||||
|
if (activeObjRef.current) {
|
||||||
|
// Pass the updated position to the onUpdate callback to persist it
|
||||||
|
onUpdate(activeObjRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
gl.domElement.removeEventListener("pointermove", handlePointerMove);
|
||||||
|
gl.domElement.removeEventListener("pointerup", handlePointerUp);
|
||||||
|
|
||||||
|
activeObjRef.current = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
return { handlePointerDown };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,302 +1,230 @@
|
||||||
import React, { useRef, useEffect, useState } from "react";
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import startPoint from "../../../../assets/gltf-glb/arrow_green.glb";
|
import startPoint from "../../../../assets/gltf-glb/arrow_green.glb";
|
||||||
import startEnd from "../../../../assets/gltf-glb/arrow_red.glb";
|
import startEnd from "../../../../assets/gltf-glb/arrow_red.glb";
|
||||||
import { useGLTF } from "@react-three/drei";
|
|
||||||
import { useSelectedEventSphere } from "../../../../store/simulation/useSimulationStore";
|
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useThree } from "@react-three/fiber";
|
import { useGLTF } from '@react-three/drei';
|
||||||
import { useVehicleStore } from "../../../../store/simulation/useVehicleStore";
|
import { useFrame, useThree } from '@react-three/fiber';
|
||||||
|
import { useSelectedEventSphere } from '../../../../store/simulation/useSimulationStore';
|
||||||
type VehicleUIProps = {
|
import { useVehicleStore } from '../../../../store/simulation/useVehicleStore';
|
||||||
vehicleStatusSample: VehicleEventSchema[];
|
import * as Types from "../../../../types/world/worldTypes";
|
||||||
setVehicleStatusSample: React.Dispatch<
|
const VehicleUI = () => {
|
||||||
React.SetStateAction<VehicleEventSchema[]>
|
|
||||||
>;
|
|
||||||
vehicle: any
|
|
||||||
};
|
|
||||||
|
|
||||||
const VehicleUI: React.FC<VehicleUIProps> = ({
|
|
||||||
vehicleStatusSample,
|
|
||||||
setVehicleStatusSample,
|
|
||||||
vehicle
|
|
||||||
}) => {
|
|
||||||
const { scene: startScene } = useGLTF(startPoint) as any;
|
const { scene: startScene } = useGLTF(startPoint) as any;
|
||||||
const { scene: endScene } = useGLTF(startEnd) as any;
|
const { scene: endScene } = useGLTF(startEnd) as any;
|
||||||
const { camera, gl, controls } = useThree();
|
|
||||||
const { selectedEventSphere } = useSelectedEventSphere();
|
|
||||||
const { updateVehicle } = useVehicleStore();
|
|
||||||
const startMarker = useRef<THREE.Group>(null);
|
const startMarker = useRef<THREE.Group>(null);
|
||||||
const endMarker = useRef<THREE.Group>(null);
|
const endMarker = useRef<THREE.Group>(null);
|
||||||
const hasInitialized = useRef<boolean>(false);
|
|
||||||
const raycaster = useRef(new THREE.Raycaster());
|
|
||||||
const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); // Y = 0 plane
|
|
||||||
const mouse = useRef(new THREE.Vector2());
|
|
||||||
const prevMousePos = useRef({ x: 0, y: 0 });
|
const prevMousePos = useRef({ x: 0, y: 0 });
|
||||||
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
|
const { vehicles, updateVehicle } = useVehicleStore();
|
||||||
|
const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 0, 0]);
|
||||||
|
const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 0, 0]);
|
||||||
|
const [startRotation, setStartRotation] = useState<[number, number, number]>([0, 0, 0]);
|
||||||
|
const [endRotation, setEndRotation] = useState<[number, number, number]>([0, 0, 0]);
|
||||||
|
const [isDragging, setIsDragging] = useState<"start" | "end" | null>(null);
|
||||||
|
const [isRotating, setIsRotating] = useState<"start" | "end" | null>(null);
|
||||||
|
const { raycaster } = useThree();
|
||||||
|
const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0));
|
||||||
|
const state: Types.ThreeState = useThree();
|
||||||
|
const controls: any = state.controls;
|
||||||
|
|
||||||
const [draggedMarker, setDraggedMarker] = useState<"start" | "end" | null>(
|
|
||||||
null
|
|
||||||
);
|
|
||||||
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
|
||||||
const [isRotating, setIsRotating] = useState<boolean>(false);
|
|
||||||
|
|
||||||
|
|
||||||
// Initialize start/end markers
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (!selectedEventSphere) return;
|
||||||
selectedEventSphere &&
|
const selectedVehicle = vehicles.find(
|
||||||
startMarker.current &&
|
(vehicle: any) => vehicle.modelUuid === selectedEventSphere.userData.modelUuid
|
||||||
endMarker.current &&
|
|
||||||
!hasInitialized.current
|
|
||||||
) {
|
|
||||||
startMarker.current.clear();
|
|
||||||
endMarker.current.clear();
|
|
||||||
|
|
||||||
const startClone = startScene.clone();
|
|
||||||
const endClone = endScene.clone();
|
|
||||||
|
|
||||||
startClone.name = "start-marker";
|
|
||||||
endClone.name = "end-marker";
|
|
||||||
|
|
||||||
startClone.traverse((child: any) => {
|
|
||||||
if (child.isMesh && child.name.toLowerCase().includes("handle")) {
|
|
||||||
child.name = "handle";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
endClone.traverse((child: any) => {
|
|
||||||
if (child.isMesh && child.name.toLowerCase().includes("handle")) {
|
|
||||||
child.name = "handle";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
startMarker.current.add(startClone);
|
|
||||||
endMarker.current.add(endClone);
|
|
||||||
|
|
||||||
hasInitialized.current = true;
|
|
||||||
}
|
|
||||||
}, [selectedEventSphere, startScene, endScene]);
|
|
||||||
|
|
||||||
// Position start/end markers
|
|
||||||
useEffect(() => {
|
|
||||||
if (!selectedEventSphere || !startMarker.current || !endMarker.current)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const selectedVehicle = vehicleStatusSample.find(
|
|
||||||
(vehicle) => vehicle.modelUuid === selectedEventSphere.userData.modelUuid
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (selectedVehicle?.point?.action) {
|
if (selectedVehicle?.point?.action) {
|
||||||
const { pickUpPoint, unLoadPoint } = selectedVehicle.point.action;
|
const { pickUpPoint, unLoadPoint } = selectedVehicle.point.action;
|
||||||
|
|
||||||
// Update start marker position
|
|
||||||
if (pickUpPoint) {
|
if (pickUpPoint) {
|
||||||
const localPos = new THREE.Vector3(
|
const pickupPosition = new THREE.Vector3(
|
||||||
pickUpPoint.x,
|
pickUpPoint.position.x,
|
||||||
pickUpPoint.y,
|
pickUpPoint.position.y,
|
||||||
pickUpPoint.z
|
pickUpPoint.position.z
|
||||||
);
|
);
|
||||||
localPos.y = 0; // Force y to 0
|
const pickupRotation = new THREE.Vector3(
|
||||||
startMarker.current.position.copy(localPos);
|
pickUpPoint.rotation.x,
|
||||||
|
pickUpPoint.rotation.y,
|
||||||
|
pickUpPoint.rotation.z
|
||||||
|
);
|
||||||
|
pickupPosition.y = 0; // Force y to 0
|
||||||
|
setStartPosition([pickupPosition.x, 0, pickupPosition.z]);
|
||||||
|
setStartRotation([pickupRotation.x, pickupRotation.y, pickupRotation.z]);
|
||||||
} else {
|
} else {
|
||||||
const defaultLocal = new THREE.Vector3(0, 0, 1.5);
|
const defaultLocal = new THREE.Vector3(0, 0, 1.5);
|
||||||
const defaultWorld = selectedEventSphere.localToWorld(defaultLocal);
|
const defaultWorld = selectedEventSphere.localToWorld(defaultLocal);
|
||||||
defaultWorld.y = 0; // Force y to 0
|
defaultWorld.y = 0; // Force y to 0
|
||||||
startMarker.current.position.copy(defaultWorld);
|
setStartPosition([defaultWorld.x, 0, defaultWorld.z]);
|
||||||
|
setStartRotation([0, 0, 0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update end marker position
|
// Initialize end marker position and rotation
|
||||||
if (unLoadPoint) {
|
if (unLoadPoint) {
|
||||||
const localPos = new THREE.Vector3(
|
const unLoadPosition = new THREE.Vector3(
|
||||||
unLoadPoint.x,
|
unLoadPoint.position.x,
|
||||||
unLoadPoint.y,
|
unLoadPoint.position.y,
|
||||||
unLoadPoint.z
|
unLoadPoint.position.z
|
||||||
);
|
);
|
||||||
|
const unLoadRotation = new THREE.Vector3(
|
||||||
|
unLoadPoint.rotation.x,
|
||||||
localPos.y = 0; // Force y to 0
|
unLoadPoint.rotation.y,
|
||||||
endMarker.current.position.copy(localPos);
|
unLoadPoint.position.z
|
||||||
|
);
|
||||||
|
unLoadPosition.y = 0; // Force y to 0
|
||||||
|
setEndPosition([unLoadPosition.x, 0, unLoadPosition.z]);
|
||||||
|
setEndRotation([unLoadRotation.x, unLoadRotation.y, unLoadRotation.z]);
|
||||||
} else {
|
} else {
|
||||||
const defaultLocal = new THREE.Vector3(0, 0, -1.5);
|
const defaultLocal = new THREE.Vector3(0, 0, -1.5);
|
||||||
const defaultWorld = selectedEventSphere.localToWorld(defaultLocal);
|
const defaultWorld = selectedEventSphere.localToWorld(defaultLocal);
|
||||||
defaultWorld.y = 0; // Force y to 0
|
defaultWorld.y = 0; // Force y to 0
|
||||||
endMarker.current.position.copy(defaultWorld);
|
setEndPosition([defaultWorld.x, 0, defaultWorld.z]);
|
||||||
|
setEndRotation([0, 0, 0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [selectedEventSphere, vehicleStatusSample]);
|
}, [selectedEventSphere]);
|
||||||
|
|
||||||
// Handle dragging and rotation
|
|
||||||
const handlePointerDown = (e: any, markerType: "start" | "end") => {
|
|
||||||
if (!selectedEventSphere) return;
|
|
||||||
|
|
||||||
if (e.object.name === "handle") {
|
|
||||||
setIsRotating(true);
|
|
||||||
prevMousePos.current = { x: e.clientX, y: e.clientY };
|
|
||||||
if (controls) (controls as any).enabled = false;
|
|
||||||
e.stopPropagation();
|
|
||||||
setDraggedMarker(markerType);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setDraggedMarker(markerType);
|
|
||||||
if (controls) (controls as any).enabled = false;
|
|
||||||
|
|
||||||
const marker =
|
|
||||||
markerType === "start" ? startMarker.current : endMarker.current;
|
|
||||||
if (!marker) return;
|
|
||||||
|
|
||||||
mouse.current.x = (e.clientX / gl.domElement.clientWidth) * 2 - 1;
|
|
||||||
mouse.current.y = -(e.clientY / gl.domElement.clientHeight) * 2 + 1;
|
|
||||||
|
|
||||||
raycaster.current.setFromCamera(mouse.current, camera);
|
|
||||||
|
|
||||||
|
useFrame(() => {
|
||||||
|
if (!isDragging) return;
|
||||||
const intersectPoint = new THREE.Vector3();
|
const intersectPoint = new THREE.Vector3();
|
||||||
raycaster.current.ray.intersectPlane(plane.current, intersectPoint);
|
const intersects = raycaster.ray.intersectPlane(plane.current, intersectPoint);
|
||||||
|
|
||||||
const offset = new THREE.Vector3().subVectors(
|
if (intersects) {
|
||||||
marker.position,
|
intersectPoint.y = 0; // Force y to 0
|
||||||
intersectPoint
|
if (isDragging === "start") {
|
||||||
);
|
setStartPosition([intersectPoint.x, 0, intersectPoint.z]);
|
||||||
setDragOffset(offset);
|
}
|
||||||
};
|
if (isDragging === "end") {
|
||||||
|
setEndPosition([intersectPoint.x, 0, intersectPoint.z]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const handlePointerMove = (e: PointerEvent) => {
|
useFrame((state) => {
|
||||||
if (!selectedEventSphere) return;
|
if (!isRotating) return;
|
||||||
|
|
||||||
if (isRotating) {
|
const currentPointerX = state.pointer.x;
|
||||||
const deltaX = e.clientX - prevMousePos.current.x;
|
const deltaX = currentPointerX - prevMousePos.current.x;
|
||||||
prevMousePos.current = { x: e.clientX, y: e.clientY };
|
prevMousePos.current.x = currentPointerX;
|
||||||
|
|
||||||
const rotationSpeed = 0.01;
|
const marker = isRotating === "start" ? startMarker.current : endMarker.current;
|
||||||
const marker =
|
|
||||||
draggedMarker === "start" ? startMarker.current : endMarker.current;
|
|
||||||
|
|
||||||
if (marker) {
|
if (marker) {
|
||||||
|
const rotationSpeed = 10;
|
||||||
marker.rotation.y -= deltaX * rotationSpeed;
|
marker.rotation.y -= deltaX * rotationSpeed;
|
||||||
|
|
||||||
}
|
}
|
||||||
return;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (!draggedMarker || !dragOffset) return;
|
|
||||||
|
|
||||||
mouse.current.x = (e.clientX / gl.domElement.clientWidth) * 2 - 1;
|
|
||||||
mouse.current.y = -(e.clientY / gl.domElement.clientHeight) * 2 + 1;
|
|
||||||
|
|
||||||
raycaster.current.setFromCamera(mouse.current, camera);
|
|
||||||
|
|
||||||
const intersectPoint = new THREE.Vector3();
|
|
||||||
raycaster.current.ray.intersectPlane(plane.current, intersectPoint);
|
|
||||||
|
|
||||||
if (!intersectPoint) return;
|
|
||||||
|
|
||||||
const newPos = {
|
|
||||||
x: intersectPoint.x + dragOffset.x,
|
|
||||||
y: 0,
|
|
||||||
z: intersectPoint.z + dragOffset.z,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
if (draggedMarker === "start" && startMarker.current) {
|
const handlePointerDown = (e: any, state: "start" | "end", rotation: "start" | "end") => {
|
||||||
startMarker.current.position.set(newPos.x, newPos.y, newPos.z);
|
|
||||||
} else if (draggedMarker === "end" && endMarker.current) {
|
if (e.object.name === "handle") {
|
||||||
endMarker.current.position.set(newPos.x, newPos.y, newPos.z);
|
const normalizedX = (e.clientX / window.innerWidth) * 2 - 1;
|
||||||
|
const normalizedY = -(e.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
prevMousePos.current = { x: normalizedX, y: normalizedY };
|
||||||
|
setIsRotating(rotation);
|
||||||
|
if (controls) controls.enabled = false;
|
||||||
|
setIsDragging(null);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
setIsDragging(state);
|
||||||
|
setIsRotating(null);
|
||||||
|
if (controls) controls.enabled = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePointerUp = () => {
|
const handlePointerUp = () => {
|
||||||
if (isRotating) {
|
console.log("nulll");
|
||||||
setIsRotating(false);
|
controls.enabled = true;
|
||||||
if (controls) (controls as any).enabled = true;
|
setIsDragging(null);
|
||||||
return;
|
setIsRotating(null);
|
||||||
}
|
|
||||||
|
|
||||||
if (!selectedEventSphere || !draggedMarker || !dragOffset) {
|
if (selectedEventSphere?.userData.modelUuid) {
|
||||||
if (controls) (controls as any).enabled = true;
|
const updatedVehicle = vehicles.find(
|
||||||
return;
|
(vehicle) => vehicle.modelUuid === selectedEventSphere.userData.modelUuid
|
||||||
}
|
);
|
||||||
|
|
||||||
if (controls) (controls as any).enabled = true;
|
|
||||||
|
|
||||||
const marker =
|
|
||||||
draggedMarker === "start" ? startMarker.current : endMarker.current;
|
|
||||||
if (!marker) return;
|
|
||||||
|
|
||||||
const worldPos = marker.position;
|
|
||||||
|
|
||||||
const updatedLocalPos = { x: worldPos.x, y: 0, z: worldPos.z };
|
|
||||||
console.log('updatedLocalPos: ', updatedLocalPos);
|
|
||||||
|
|
||||||
|
|
||||||
console.log('draggedMarker: ', draggedMarker);
|
|
||||||
// setVehicleStatusSample((prev) =>
|
|
||||||
// prev.map((vehicle) => {
|
|
||||||
// if (
|
|
||||||
// vehicle.modelUuid === selectedEventSphere.userData.modelUuid &&
|
|
||||||
// selectedEventSphere
|
|
||||||
// ) {
|
|
||||||
// const updatedVehicle = {
|
|
||||||
// ...vehicle,
|
|
||||||
// point: {
|
|
||||||
// ...vehicle.point,
|
|
||||||
// action: {
|
|
||||||
// ...vehicle.point?.action,
|
|
||||||
// ...(draggedMarker === "start"
|
|
||||||
// ? { pickUpPoint: updatedLocalPos }
|
|
||||||
// : { unLoadPoint: updatedLocalPos }),
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
// return updatedVehicle;
|
|
||||||
// }
|
|
||||||
// return vehicle;
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
|
|
||||||
|
if (updatedVehicle) {
|
||||||
updateVehicle(selectedEventSphere.userData.modelUuid, {
|
updateVehicle(selectedEventSphere.userData.modelUuid, {
|
||||||
point: {
|
point: {
|
||||||
...vehicle?.point,
|
...updatedVehicle.point,
|
||||||
action: {
|
action: {
|
||||||
...vehicle?.point?.action,
|
...updatedVehicle.point?.action,
|
||||||
...(draggedMarker === "start"
|
pickUpPoint: {
|
||||||
? { pickUpPoint: updatedLocalPos }
|
position: {
|
||||||
: { unLoadPoint: updatedLocalPos }),
|
x: startPosition[0],
|
||||||
|
y: startPosition[1],
|
||||||
|
z: startPosition[2],
|
||||||
|
},
|
||||||
|
rotation: {
|
||||||
|
x: startRotation[0],
|
||||||
|
y: startRotation[1],
|
||||||
|
z: startRotation[2],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
unLoadPoint: {
|
||||||
|
position: {
|
||||||
|
x: endPosition[0],
|
||||||
|
y: endPosition[1],
|
||||||
|
z: endPosition[2],
|
||||||
|
},
|
||||||
|
rotation: {
|
||||||
|
x: endRotation[0],
|
||||||
|
y: endRotation[1],
|
||||||
|
z: endRotation[2],
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setDraggedMarker(null);
|
|
||||||
setDragOffset(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
window.addEventListener("pointermove", handlePointerMove);
|
|
||||||
window.addEventListener("pointerup", handlePointerUp);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener("pointermove", handlePointerMove);
|
|
||||||
window.removeEventListener("pointerup", handlePointerUp);
|
|
||||||
};
|
|
||||||
}, [draggedMarker, dragOffset, isRotating]);
|
|
||||||
|
|
||||||
if (!selectedEventSphere) {
|
|
||||||
hasInitialized.current = false;
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<group>
|
startPosition.length > 0 && endPosition.length > 0 ? (
|
||||||
<group
|
<mesh>
|
||||||
|
<primitive
|
||||||
|
name="start"
|
||||||
|
object={startScene}
|
||||||
ref={startMarker}
|
ref={startMarker}
|
||||||
scale={draggedMarker === "start" ? [1.1, 1.1, 1.1] : [1, 1, 1]}
|
position={startPosition}
|
||||||
onPointerDown={(e) => handlePointerDown(e, "start")}
|
onPointerDown={(e: any) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handlePointerDown(e, "start", "start");
|
||||||
|
}}
|
||||||
|
onPointerUp={() => {
|
||||||
|
handlePointerUp();
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
console.log("start pointermissed");
|
||||||
|
handlePointerUp();
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<group
|
|
||||||
ref={endMarker}
|
|
||||||
scale={draggedMarker === "end" ? [1.1, 1.1, 1.1] : [1, 1, 1]}
|
|
||||||
onPointerDown={(e) => handlePointerDown(e, "end")}
|
|
||||||
/>
|
|
||||||
</group>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
<primitive
|
||||||
|
name="end"
|
||||||
|
object={endScene}
|
||||||
|
ref={endMarker}
|
||||||
|
position={endPosition}
|
||||||
|
onPointerDown={(e: any) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handlePointerDown(e, "end", "end");
|
||||||
|
}}
|
||||||
|
onPointerUp={() => {
|
||||||
|
console.log("up");
|
||||||
|
handlePointerUp();
|
||||||
|
}}
|
||||||
|
onPointerMissed={() => {
|
||||||
|
console.log("end pointermissed");
|
||||||
|
handlePointerUp();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
) : null
|
||||||
|
);
|
||||||
|
}
|
||||||
export default VehicleUI;
|
export default VehicleUI;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ interface VehicleAnimatorProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset }: VehicleAnimatorProps) {
|
function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail, reset }: VehicleAnimatorProps) {
|
||||||
// console.log('path: ', path);
|
|
||||||
const { decrementVehicleLoad } = useVehicleStore();
|
const { decrementVehicleLoad } = useVehicleStore();
|
||||||
const { isPaused } = usePauseButtonStore();
|
const { isPaused } = usePauseButtonStore();
|
||||||
const { isPlaying } = usePlayButtonStore();
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
@ -193,7 +192,6 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{currentPath.length > 0 && (
|
{currentPath.length > 0 && (
|
||||||
|
|
|
@ -51,10 +51,11 @@ function VehicleInstance({ agvDetail }: any) {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
|
|
||||||
if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') {
|
if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') {
|
||||||
const toPickupPath = computePath(
|
const toPickupPath = computePath(
|
||||||
new THREE.Vector3(agvDetail.position[0], agvDetail.position[1], agvDetail.position[2]),
|
new THREE.Vector3(agvDetail?.position[0], agvDetail?.position[1], agvDetail?.position[2]),
|
||||||
agvDetail.point.action.pickUpPoint
|
agvDetail?.point?.action?.pickUpPoint?.position
|
||||||
);
|
);
|
||||||
setPath(toPickupPath);
|
setPath(toPickupPath);
|
||||||
setCurrentPhase('stationed-pickup');
|
setCurrentPhase('stationed-pickup');
|
||||||
|
@ -70,8 +71,8 @@ function VehicleInstance({ agvDetail }: any) {
|
||||||
|
|
||||||
if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) {
|
if (agvDetail.currentLoad === agvDetail.point.action.loadCapacity) {
|
||||||
const toDrop = computePath(
|
const toDrop = computePath(
|
||||||
agvDetail.point.action.pickUpPoint,
|
agvDetail.point.action.pickUpPoint.position,
|
||||||
agvDetail.point.action.unLoadPoint
|
agvDetail.point.action.unLoadPoint.position
|
||||||
);
|
);
|
||||||
setPath(toDrop);
|
setPath(toDrop);
|
||||||
setCurrentPhase('pickup-drop');
|
setCurrentPhase('pickup-drop');
|
||||||
|
@ -81,8 +82,8 @@ function VehicleInstance({ agvDetail }: any) {
|
||||||
}
|
}
|
||||||
} else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'dropping' && agvDetail.currentLoad === 0) {
|
} else if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'dropping' && agvDetail.currentLoad === 0) {
|
||||||
const dropToPickup = computePath(
|
const dropToPickup = computePath(
|
||||||
agvDetail.point.action.unLoadPoint,
|
agvDetail.point.action.unLoadPoint.position,
|
||||||
agvDetail.point.action.pickUpPoint
|
agvDetail.point.action.pickUpPoint.position
|
||||||
);
|
);
|
||||||
setPath(dropToPickup);
|
setPath(dropToPickup);
|
||||||
setCurrentPhase('drop-pickup');
|
setCurrentPhase('drop-pickup');
|
||||||
|
|
|
@ -1,17 +1,8 @@
|
||||||
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'
|
||||||
import VehicleUI from '../../ui/vehicle/vehicleUI';
|
|
||||||
type VehicleUIProps = {
|
function VehicleInstances() {
|
||||||
vehicleStatusSample: VehicleEventSchema[];
|
|
||||||
setVehicleStatusSample: React.Dispatch<
|
|
||||||
React.SetStateAction<VehicleEventSchema[]>
|
|
||||||
>;
|
|
||||||
};
|
|
||||||
const VehicleInstances: React.FC<VehicleUIProps> = ({
|
|
||||||
vehicleStatusSample,
|
|
||||||
setVehicleStatusSample,
|
|
||||||
}) => {
|
|
||||||
|
|
||||||
const { vehicles } = useVehicleStore();
|
const { vehicles } = useVehicleStore();
|
||||||
|
|
||||||
|
@ -19,14 +10,9 @@ const VehicleInstances: React.FC<VehicleUIProps> = ({
|
||||||
<>
|
<>
|
||||||
|
|
||||||
{vehicles.map((val: any, i: any) =>
|
{vehicles.map((val: any, i: any) =>
|
||||||
<>
|
|
||||||
<VehicleInstance agvDetail={val} key={i} />
|
<VehicleInstance agvDetail={val} key={i} />
|
||||||
<VehicleUI
|
|
||||||
setVehicleStatusSample={setVehicleStatusSample}
|
|
||||||
vehicleStatusSample={vehicleStatusSample}
|
|
||||||
vehicle={val}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -2,13 +2,16 @@ import React, { useEffect, useState } 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";
|
import { useFloorItems } from "../../../store/store";
|
||||||
import { useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
|
import { useSelectedEventData, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
|
||||||
import VehicleUI from "../ui/vehicle/vehicleUI";
|
import VehicleUI from "../ui/vehicle/vehicleUI";
|
||||||
|
import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
|
||||||
function Vehicles() {
|
function Vehicles() {
|
||||||
|
|
||||||
const { vehicles, addVehicle } = useVehicleStore();
|
const { vehicles, addVehicle } = useVehicleStore();
|
||||||
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
const { floorItems } = useFloorItems()
|
const { selectedEventData } = useSelectedEventData();
|
||||||
|
const { floorItems } = useFloorItems();
|
||||||
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
|
||||||
const [vehicleStatusSample, setVehicleStatusSample] = useState<
|
const [vehicleStatusSample, setVehicleStatusSample] = useState<
|
||||||
VehicleEventSchema[]
|
VehicleEventSchema[]
|
||||||
|
@ -31,8 +34,8 @@ function Vehicles() {
|
||||||
actionType: "travel",
|
actionType: "travel",
|
||||||
unLoadDuration: 10,
|
unLoadDuration: 10,
|
||||||
loadCapacity: 2,
|
loadCapacity: 2,
|
||||||
pickUpPoint: { x: 98.71483985219794, y: 0, z: 28.66321267938962 },
|
pickUpPoint: { position: { x: 98.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } },
|
||||||
unLoadPoint: { x: 105.71483985219794, y: 0, z: 28.66321267938962 },
|
unLoadPoint: { position: { x: 105.71483985219794, y: 0, z: 28.66321267938962 }, rotation: { x: 0, y: 0, z: 0 } },
|
||||||
triggers: [
|
triggers: [
|
||||||
{
|
{
|
||||||
triggerUuid: "trig-001",
|
triggerUuid: "trig-001",
|
||||||
|
@ -99,49 +102,49 @@ function Vehicles() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
modelUuid: "cd7d0584-0684-42b4-b051-9e882c1914aa",
|
// modelUuid: "cd7d0584-0684-42b4-b051-9e882c1914aa",
|
||||||
modelName: "AGV",
|
// modelName: "AGV",
|
||||||
position: [105.90938758014703, 0, 31.584209911095215],
|
// position: [105.90938758014703, 0, 31.584209911095215],
|
||||||
rotation: [0, 0, 0],
|
// rotation: [0, 0, 0],
|
||||||
state: "idle",
|
// state: "idle",
|
||||||
type: "vehicle",
|
// type: "vehicle",
|
||||||
speed: 2.5,
|
// speed: 2.5,
|
||||||
point: {
|
// point: {
|
||||||
uuid: "point-789",
|
// uuid: "point-789",
|
||||||
position: [0, 1, 0],
|
// position: [0, 1, 0],
|
||||||
rotation: [0, 0, 0],
|
// rotation: [0, 0, 0],
|
||||||
action: {
|
// action: {
|
||||||
actionUuid: "action-456",
|
// actionUuid: "action-456",
|
||||||
actionName: "Deliver to Zone A",
|
// actionName: "Deliver to Zone A",
|
||||||
actionType: "travel",
|
// actionType: "travel",
|
||||||
unLoadDuration: 10,
|
// unLoadDuration: 10,
|
||||||
loadCapacity: 2,
|
// loadCapacity: 2,
|
||||||
pickUpPoint: null,
|
// pickUpPoint: null,
|
||||||
unLoadPoint: null,
|
// unLoadPoint: null,
|
||||||
triggers: [
|
// triggers: [
|
||||||
{
|
// {
|
||||||
triggerUuid: "trig-001",
|
// triggerUuid: "trig-001",
|
||||||
triggerName: "Start Travel",
|
// triggerName: "Start Travel",
|
||||||
triggerType: "onStart",
|
// triggerType: "onStart",
|
||||||
delay: 0,
|
// delay: 0,
|
||||||
triggeredAsset: {
|
// triggeredAsset: {
|
||||||
triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" },
|
// triggeredModel: { modelName: "ArmBot-X", modelUuid: "arm-001" },
|
||||||
triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" },
|
// triggeredPoint: { pointName: "Pickup Arm Point", pointUuid: "arm-point-01" },
|
||||||
triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" }
|
// triggeredAction: { actionName: "Grab Widget", actionUuid: "grab-001" }
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
triggerUuid: "trig-002",
|
// triggerUuid: "trig-002",
|
||||||
triggerName: "Complete Travel",
|
// triggerName: "Complete Travel",
|
||||||
triggerType: "onComplete",
|
// triggerType: "onComplete",
|
||||||
delay: 2,
|
// delay: 2,
|
||||||
triggeredAsset: null
|
// triggeredAsset: null
|
||||||
}
|
// }
|
||||||
]
|
// ]
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
// {
|
// {
|
||||||
// modelUuid: "e729a4f1-11d2-4778-8d6a-468f1b4f6b79",
|
// modelUuid: "e729a4f1-11d2-4778-8d6a-468f1b4f6b79",
|
||||||
// modelName: "forklift",
|
// modelName: "forklift",
|
||||||
|
@ -189,20 +192,20 @@ function Vehicles() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("vehicles", vehicles);
|
console.log("vehicles", vehicles);
|
||||||
}, [vehicles])
|
}, [vehicles])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
addVehicle("123", vehicleStatusSample[0]);
|
addVehicle("123", vehicleStatusSample[0]);
|
||||||
addVehicle('123', vehicleStatusSample[1]);
|
addVehicle('123', vehicleStatusSample[1]);
|
||||||
addVehicle('123', vehicleStatusSample[2]);
|
// addVehicle('123', vehicleStatusSample[2]);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<VehicleInstances setVehicleStatusSample={setVehicleStatusSample}
|
<VehicleInstances />
|
||||||
vehicleStatusSample={vehicleStatusSample} />
|
{selectedEventSphere && selectedEventData?.data.type === "vehicle" && !isPlaying &&
|
||||||
{/* <VehicleUI
|
< VehicleUI />
|
||||||
setVehicleStatusSample={setVehicleStatusSample}
|
}
|
||||||
vehicleStatusSample={vehicles}
|
|
||||||
/> */}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()}
|
||||||
>
|
>
|
||||||
|
|
|
@ -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 (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,9 @@ import SimulationPlayer from "../components/ui/simulation/simulationPlayer";
|
||||||
import RenderOverlay from "../components/templates/Overlay";
|
import RenderOverlay from "../components/templates/Overlay";
|
||||||
import MenuBar from "../components/ui/menu/menu";
|
import MenuBar from "../components/ui/menu/menu";
|
||||||
import KeyPressListener from "../utils/shortcutkeys/handleShortcutKeys";
|
import KeyPressListener from "../utils/shortcutkeys/handleShortcutKeys";
|
||||||
|
import ProductionCapacity from "../components/ui/analysis/ProductionCapacity";
|
||||||
|
import ThroughputSummary from "../components/ui/analysis/ThroughputSummary";
|
||||||
|
import ROISummary from "../components/ui/analysis/ROISummary";
|
||||||
|
|
||||||
const Project: React.FC = () => {
|
const Project: React.FC = () => {
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
|
@ -38,7 +41,7 @@ const Project: React.FC = () => {
|
||||||
setFloorItems([]);
|
setFloorItems([]);
|
||||||
setWallItems([]);
|
setWallItems([]);
|
||||||
setZones([]);
|
setZones([]);
|
||||||
setActiveModule('builder')
|
setActiveModule("builder");
|
||||||
const email = localStorage.getItem("email");
|
const email = localStorage.getItem("email");
|
||||||
if (email) {
|
if (email) {
|
||||||
const Organization = email!.split("@")[1].split(".")[0];
|
const Organization = email!.split("@")[1].split(".")[0];
|
||||||
|
@ -57,6 +60,11 @@ const Project: React.FC = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="project-main">
|
<div className="project-main">
|
||||||
|
{/* <div className="analysis">
|
||||||
|
<ProductionCapacity />
|
||||||
|
<ThroughputSummary />
|
||||||
|
<ROISummary />
|
||||||
|
</div> */}
|
||||||
<KeyPressListener />
|
<KeyPressListener />
|
||||||
{loadingProgress && <LoadingPage progress={loadingProgress} />}
|
{loadingProgress && <LoadingPage progress={loadingProgress} />}
|
||||||
{!isPlaying && (
|
{!isPlaying && (
|
||||||
|
|
|
@ -2,7 +2,11 @@ import React, { useState, FormEvent } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { LogoIconLarge } from "../components/icons/Logo";
|
import { LogoIconLarge } from "../components/icons/Logo";
|
||||||
import { EyeIcon } from "../components/icons/ExportCommonIcons";
|
import { EyeIcon } from "../components/icons/ExportCommonIcons";
|
||||||
import { useLoadingProgress, useOrganization, useUserName } from "../store/store";
|
import {
|
||||||
|
useLoadingProgress,
|
||||||
|
useOrganization,
|
||||||
|
useUserName,
|
||||||
|
} from "../store/store";
|
||||||
import { signInApi } from "../services/factoryBuilder/signInSignUp/signInApi";
|
import { signInApi } from "../services/factoryBuilder/signInSignUp/signInApi";
|
||||||
import { signUpApi } from "../services/factoryBuilder/signInSignUp/signUpApi";
|
import { signUpApi } from "../services/factoryBuilder/signInSignUp/signUpApi";
|
||||||
|
|
||||||
|
@ -21,7 +25,7 @@ const UserAuth: React.FC = () => {
|
||||||
const handleLogin = async (e: FormEvent<HTMLFormElement>) => {
|
const handleLogin = async (e: FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const organization = (email.split("@")[1]).split(".")[0];
|
const organization = email.split("@")[1].split(".")[0];
|
||||||
try {
|
try {
|
||||||
const res = await signInApi(email, password, organization);
|
const res = await signInApi(email, password, organization);
|
||||||
|
|
||||||
|
@ -47,7 +51,7 @@ const UserAuth: React.FC = () => {
|
||||||
if (email && password && userName) {
|
if (email && password && userName) {
|
||||||
setError("");
|
setError("");
|
||||||
try {
|
try {
|
||||||
const organization = (email.split("@")[1]).split(".")[0];
|
const organization = email.split("@")[1].split(".")[0];
|
||||||
const res = await signUpApi(userName, email, password, organization);
|
const res = await signUpApi(userName, email, password, organization);
|
||||||
|
|
||||||
if (res.message === "New User created") {
|
if (res.message === "New User created") {
|
||||||
|
@ -63,7 +67,6 @@ const UserAuth: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<div className="auth-container">
|
<div className="auth-container">
|
||||||
<div className="logo-icon">
|
<div className="logo-icon">
|
||||||
<LogoIconLarge />
|
<LogoIconLarge />
|
||||||
|
@ -172,7 +175,6 @@ const UserAuth: React.FC = () => {
|
||||||
website.
|
website.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -0,0 +1,270 @@
|
||||||
|
.analysis {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
z-index: 100000000000000000000000000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.analysis-card {
|
||||||
|
min-width: 333px;
|
||||||
|
// background: var(--primary-color);
|
||||||
|
border-radius: 20px;
|
||||||
|
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
.analysis-card-wrapper {
|
||||||
|
background: var(--background-color);
|
||||||
|
border-radius: 14px;
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 14px;
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.main-header {
|
||||||
|
line-height: 20px;
|
||||||
|
font-size: var(--font-size-regular);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.process-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.throughput-value {
|
||||||
|
font-size: 1rem;
|
||||||
|
|
||||||
|
.value {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar-wrapper {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
position: relative;
|
||||||
|
width: 36px;
|
||||||
|
height: 4px;
|
||||||
|
border-radius: 13px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #FBEBD7;
|
||||||
|
|
||||||
|
.bar-fill {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background-color: #FC9D2F;
|
||||||
|
border-radius: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-fill.full {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-fill.partial {
|
||||||
|
width: 0; // inline style will override this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.metrics-section {
|
||||||
|
padding-top: 16px;
|
||||||
|
border-top: 1px solid var(--background-color-gray);
|
||||||
|
|
||||||
|
.metric {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.throughoutSummary {
|
||||||
|
.throughoutSummary-wrapper {
|
||||||
|
.process-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 16px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.throughput-value {
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.value {
|
||||||
|
color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let the text take available space */
|
||||||
|
}
|
||||||
|
|
||||||
|
.lineChart {
|
||||||
|
max-width: 200px;
|
||||||
|
height: 100px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.assetUsage {
|
||||||
|
text-align: right;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px; // Space between cards
|
||||||
|
margin-top: 24px;
|
||||||
|
|
||||||
|
.footer-card {
|
||||||
|
width: 100%;
|
||||||
|
background: var(--background-color-gray);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
width: 85%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
font-size: var(--font-size-regular);
|
||||||
|
}
|
||||||
|
|
||||||
|
.value-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: end;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.shiftUtilization {
|
||||||
|
.value-container {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
.value {
|
||||||
|
font-size: var(--font-size-xlarge);
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
border-radius: 6px;
|
||||||
|
height: 5px;
|
||||||
|
|
||||||
|
&:nth-child(1) {
|
||||||
|
background-color: #F3C64D;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(2) {
|
||||||
|
background-color: #67B3F4;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(3) {
|
||||||
|
background-color: #7981F5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-indicator {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
gap: 6px;
|
||||||
|
|
||||||
|
.shift-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
|
||||||
|
/* Align items vertically */
|
||||||
|
&:nth-child(1) {
|
||||||
|
.indicator {
|
||||||
|
|
||||||
|
background-color: #F3C64D;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(2) {
|
||||||
|
.indicator {
|
||||||
|
|
||||||
|
background-color: #67B3F4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(3) {
|
||||||
|
.indicator {
|
||||||
|
|
||||||
|
background-color: #7981F5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indicator {
|
||||||
|
display: inline-block;
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -366,15 +366,66 @@
|
||||||
min-height: 50vh;
|
min-height: 50vh;
|
||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
overflow: auto;
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.sidebar-right-content-container {
|
.sidebar-right-content-container {
|
||||||
border-bottom: 1px solid var(--border-color);
|
border-bottom: 1px solid var(--border-color);
|
||||||
// flex: 1;
|
|
||||||
height: calc(100% - 36px);
|
height: calc(100% - 36px);
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: auto;
|
width: 320px;
|
||||||
|
.no-event-selected {
|
||||||
|
color: #666;
|
||||||
|
padding: 1.8rem 1rem;
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
.products-list {
|
||||||
|
padding-top: 1rem;
|
||||||
|
.products-list-title {
|
||||||
|
text-align: start;
|
||||||
|
color: var(--accent-color);
|
||||||
|
font-size: var(--font-size-regular);
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
li {
|
||||||
|
text-align: start;
|
||||||
|
margin: 8px 0;
|
||||||
|
padding: 2px 0;
|
||||||
|
text-decoration: none;
|
||||||
|
&::marker {
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
width: fit-content;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
@include flex-center;
|
||||||
|
gap: 4px;
|
||||||
|
&:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: -4px;
|
||||||
|
background: var(--accent-color);
|
||||||
|
height: 1px;
|
||||||
|
width: 0%;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
button {
|
||||||
|
path {
|
||||||
|
stroke: var(--accent-color);
|
||||||
|
stroke-width: 1.5px;
|
||||||
|
}
|
||||||
|
color: var(--accent-color);
|
||||||
|
&:before {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -675,10 +726,14 @@
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
border-radius: #{$border-radius-small};
|
border-radius: #{$border-radius-small};
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
path {
|
path {
|
||||||
stroke: var(--primary-color);
|
stroke: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
&:disabled {
|
||||||
|
background-color: var(--text-disabled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -747,14 +802,15 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 2px 0;
|
margin: 2px 0;
|
||||||
border-radius: #{$border-radius-small};
|
border-radius: #{$border-radius-small};
|
||||||
}
|
|
||||||
|
|
||||||
.value {
|
.value {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-width: 80%;
|
min-width: 80%;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
.input-value {
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
|
@ -762,6 +818,7 @@
|
||||||
accent-color: var(--accent-color);
|
accent-color: var(--accent-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.active {
|
.active {
|
||||||
background: var(--highlight-accent-color);
|
background: var(--highlight-accent-color);
|
||||||
|
@ -797,6 +854,7 @@
|
||||||
@include flex-center;
|
@include flex-center;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
cursor: grabbing;
|
cursor: grabbing;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
// abstracts
|
// abstracts
|
||||||
@use 'abstracts/variables';
|
@use 'abstracts/variables';
|
||||||
@use 'abstracts/mixins';
|
@use 'abstracts/mixins';
|
||||||
@use 'abstracts/placeholders';
|
|
||||||
@use 'abstracts/functions';
|
@use 'abstracts/functions';
|
||||||
|
|
||||||
// base
|
// base
|
||||||
@use 'base/reset';
|
@use 'base/reset';
|
||||||
@use 'base/typography';
|
@use 'base/typography';
|
||||||
|
@use 'base/global';
|
||||||
@use 'base/base';
|
@use 'base/base';
|
||||||
|
|
||||||
// components
|
// components
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
@use 'components/simulation/simulation';
|
@use 'components/simulation/simulation';
|
||||||
@use 'components/menu/menu';
|
@use 'components/menu/menu';
|
||||||
@use 'components/confirmationPopUp';
|
@use 'components/confirmationPopUp';
|
||||||
|
@use 'components/analysis/analysis';
|
||||||
|
|
||||||
// layout
|
// layout
|
||||||
@use 'layout/loading';
|
@use 'layout/loading';
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,8 +44,8 @@ interface VehiclePointSchema {
|
||||||
actionType: "travel";
|
actionType: "travel";
|
||||||
unLoadDuration: number;
|
unLoadDuration: number;
|
||||||
loadCapacity: number;
|
loadCapacity: number;
|
||||||
pickUpPoint: { x: number; y: number, z: number } | null;
|
pickUpPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null;
|
||||||
unLoadPoint: { x: number; y: number, z: number } | null;
|
unLoadPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null;
|
||||||
triggers: TriggerSchema[];
|
triggers: TriggerSchema[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue