added logs list
This commit is contained in:
commit
8659f4be71
|
@ -3,22 +3,19 @@ import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
||||||
import Dashboard from "./pages/Dashboard";
|
import Dashboard from "./pages/Dashboard";
|
||||||
import Project from "./pages/Project";
|
import Project from "./pages/Project";
|
||||||
import UserAuth from "./pages/UserAuth";
|
import UserAuth from "./pages/UserAuth";
|
||||||
import ToastProvider from "./components/templates/ToastProvider";
|
|
||||||
import "./styles/main.scss";
|
import "./styles/main.scss";
|
||||||
import { LoggerProvider } from "./components/ui/log/LoggerContext";
|
import { LoggerProvider } from "./components/ui/log/LoggerContext";
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<LoggerProvider>
|
<LoggerProvider>
|
||||||
<ToastProvider>
|
<Router>
|
||||||
<Router>
|
<Routes>
|
||||||
<Routes>
|
<Route path="/" element={<UserAuth />} />
|
||||||
<Route path="/" element={<UserAuth />} />
|
<Route path="/dashboard" element={<Dashboard />} />
|
||||||
<Route path="/dashboard" element={<Dashboard />} />
|
<Route path="/project" element={<Project />} />
|
||||||
<Route path="/project" element={<Project />} />
|
</Routes>
|
||||||
</Routes>
|
</Router>
|
||||||
</Router>
|
|
||||||
</ToastProvider>
|
|
||||||
</LoggerProvider>
|
</LoggerProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -458,7 +458,7 @@ export function InfoIcon() {
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M5.46289 7.75441C5.46289 7.68342 5.47691 7.6131 5.50422 7.54758C5.53158 7.48201 5.57156 7.42254 5.62201 7.37257C5.67246 7.3226 5.73231 7.2831 5.79807 7.25636C5.86388 7.22963 5.93425 7.21619 6.00529 7.21681C6.11003 7.21873 6.21188 7.25142 6.29814 7.31089C6.38435 7.37036 6.45121 7.45398 6.49019 7.55118C6.52921 7.64843 6.53862 7.75499 6.5174 7.85757C6.49614 7.96014 6.44511 8.05417 6.37071 8.12795C6.29631 8.20168 6.20185 8.25184 6.09908 8.27219C5.99631 8.29254 5.8898 8.28212 5.79294 8.24224C5.69603 8.2024 5.61308 8.13486 5.55438 8.04808C5.49567 7.96134 5.46385 7.8592 5.46289 7.75441ZM5.63564 6.44401L5.56844 3.93842C5.56206 3.87819 5.56844 3.81729 5.58716 3.75968C5.60583 3.70207 5.63641 3.64902 5.67692 3.604C5.71743 3.55897 5.76697 3.52297 5.82227 3.49832C5.87761 3.47368 5.93751 3.46094 5.99804 3.46094C6.05862 3.46094 6.11852 3.47368 6.17387 3.49832C6.22916 3.52297 6.2787 3.55897 6.31921 3.604C6.35972 3.64902 6.3903 3.70207 6.40897 3.75968C6.42769 3.81729 6.43407 3.87819 6.42769 3.93842L6.36529 6.44401C6.36529 6.54073 6.32689 6.63356 6.25844 6.70196C6.19004 6.77036 6.09721 6.80881 6.00049 6.80881C5.90372 6.80881 5.81094 6.77036 5.74254 6.70196C5.67414 6.63356 5.63564 6.54073 5.63564 6.44401Z"
|
d="M5.46289 7.75441C5.46289 7.68342 5.47691 7.6131 5.50422 7.54758C5.53158 7.48201 5.57156 7.42254 5.62201 7.37257C5.67246 7.3226 5.73231 7.2831 5.79807 7.25636C5.86388 7.22963 5.93425 7.21619 6.00529 7.21681C6.11003 7.21873 6.21188 7.25142 6.29814 7.31089C6.38435 7.37036 6.45121 7.45398 6.49019 7.55118C6.52921 7.64843 6.53862 7.75499 6.5174 7.85757C6.49614 7.96014 6.44511 8.05417 6.37071 8.12795C6.29631 8.20168 6.20185 8.25184 6.09908 8.27219C5.99631 8.29254 5.8898 8.28212 5.79294 8.24224C5.69603 8.2024 5.61308 8.13486 5.55438 8.04808C5.49567 7.96134 5.46385 7.8592 5.46289 7.75441ZM5.63564 6.44401L5.56844 3.93842C5.56206 3.87819 5.56844 3.81729 5.58716 3.75968C5.60583 3.70207 5.63641 3.64902 5.67692 3.604C5.71743 3.55897 5.76697 3.52297 5.82227 3.49832C5.87761 3.47368 5.93751 3.46094 5.99804 3.46094C6.05862 3.46094 6.11852 3.47368 6.17387 3.49832C6.22916 3.52297 6.2787 3.55897 6.31921 3.604C6.35972 3.64902 6.3903 3.70207 6.40897 3.75968C6.42769 3.81729 6.43407 3.87819 6.42769 3.93842L6.36529 6.44401C6.36529 6.54073 6.32689 6.63356 6.25844 6.70196C6.19004 6.77036 6.09721 6.80881 6.00049 6.80881C5.90372 6.80881 5.81094 6.77036 5.74254 6.70196C5.67414 6.63356 5.63564 6.54073 5.63564 6.44401Z"
|
||||||
fill="var(--icon-default-color)"
|
fill="var(--text-color)"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M6.00006 10.3175C8.45219 10.3175 10.4401 8.32963 10.4401 5.8775C10.4401 3.42536 8.45219 1.4375 6.00006 1.4375C3.54792 1.4375 1.56006 3.42536 1.56006 5.8775C1.56006 8.32963 3.54792 10.3175 6.00006 10.3175Z"
|
d="M6.00006 10.3175C8.45219 10.3175 10.4401 8.32963 10.4401 5.8775C10.4401 3.42536 8.45219 1.4375 6.00006 1.4375C3.54792 1.4375 1.56006 3.42536 1.56006 5.8775C1.56006 8.32963 3.54792 10.3175 6.00006 10.3175Z"
|
||||||
|
@ -471,7 +471,7 @@ export function InfoIcon() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AI_Icon() {
|
export function AIIcon() {
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
width="20"
|
width="20"
|
||||||
|
|
|
@ -125,21 +125,21 @@ export function ResetIcon() {
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M2.54182 4.09637C3.33333 2.73422 4.80832 1.81836 6.49721 1.81836C9.02194 1.81836 11.0686 3.86506 11.0686 6.38979C11.0686 8.91452 9.02194 10.9612 6.49721 10.9612C3.97248 10.9612 1.92578 8.91452 1.92578 6.38979"
|
d="M2.54182 4.09637C3.33333 2.73422 4.80832 1.81836 6.49721 1.81836C9.02194 1.81836 11.0686 3.86506 11.0686 6.38979C11.0686 8.91452 9.02194 10.9612 6.49721 10.9612C3.97248 10.9612 1.92578 8.91452 1.92578 6.38979"
|
||||||
stroke="var(--icon-default-color-active)"
|
stroke="var(--text-color)"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M7.64118 6.38895C7.64118 7.02013 7.12951 7.53181 6.49833 7.53181C5.86714 7.53181 5.35547 7.02013 5.35547 6.38895C5.35547 5.75777 5.86714 5.24609 6.49833 5.24609C7.12951 5.24609 7.64118 5.75777 7.64118 6.38895Z"
|
d="M7.64118 6.38895C7.64118 7.02013 7.12951 7.53181 6.49833 7.53181C5.86714 7.53181 5.35547 7.02013 5.35547 6.38895C5.35547 5.75777 5.86714 5.24609 6.49833 5.24609C7.12951 5.24609 7.64118 5.75777 7.64118 6.38895Z"
|
||||||
fill="var(--icon-default-color-active)"
|
fill="var(--text-color)"
|
||||||
stroke="var(--icon-default-color-active)"
|
stroke="var(--text-color)"
|
||||||
strokeWidth="0.571429"
|
strokeWidth="0.571429"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M4.78125 4.10407H2.49554V1.81836"
|
d="M4.78125 4.10407H2.49554V1.81836"
|
||||||
stroke="var(--icon-default-color-active)"
|
stroke="var(--text-color)"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
|
@ -158,7 +158,7 @@ export function PlayStopIcon() {
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M8 2.88867V9.88867M11 2.88867V9.88867M2 3.99171V8.78562C2 9.28847 2 9.53987 2.09943 9.65627C2.1857 9.75732 2.31512 9.81092 2.44756 9.80047C2.60019 9.78847 2.77796 9.61072 3.13352 9.25517L5.5305 6.85817C5.69485 6.69382 5.777 6.61167 5.8078 6.51692C5.83485 6.43357 5.83485 6.34377 5.8078 6.26042C5.777 6.16567 5.69485 6.08352 5.5305 5.91917L3.13352 3.52219C2.77796 3.16664 2.60019 2.98886 2.44756 2.97685C2.31512 2.96643 2.1857 3.02004 2.09943 3.12105C2 3.23747 2 3.48888 2 3.99171Z"
|
d="M8 2.88867V9.88867M11 2.88867V9.88867M2 3.99171V8.78562C2 9.28847 2 9.53987 2.09943 9.65627C2.1857 9.75732 2.31512 9.81092 2.44756 9.80047C2.60019 9.78847 2.77796 9.61072 3.13352 9.25517L5.5305 6.85817C5.69485 6.69382 5.777 6.61167 5.8078 6.51692C5.83485 6.43357 5.83485 6.34377 5.8078 6.26042C5.777 6.16567 5.69485 6.08352 5.5305 5.91917L3.13352 3.52219C2.77796 3.16664 2.60019 2.98886 2.44756 2.97685C2.31512 2.96643 2.1857 3.02004 2.09943 3.12105C2 3.23747 2 3.48888 2 3.99171Z"
|
||||||
stroke="var(--icon-default-color-active)"
|
stroke="var(--text-color)"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
|
@ -177,7 +177,7 @@ export function ExitIcon() {
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d="M2.08203 6.34311L5.03647 3.38867M2.08203 6.34311L5.03647 9.29755M2.08203 6.34311H5.9228C7.22276 6.34334 9.34995 7.05241 10.7681 9.88867"
|
d="M2.08203 6.34311L5.03647 3.38867M2.08203 6.34311L5.03647 9.29755M2.08203 6.34311H5.9228C7.22276 6.34334 9.34995 7.05241 10.7681 9.88867"
|
||||||
stroke="var(--icon-default-color-active)"
|
stroke="var(--text-color)"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -19,7 +19,7 @@ const Header: React.FC = () => {
|
||||||
<FileMenu />
|
<FileMenu />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<button
|
||||||
className={`toggle-sidebar-ui-button ${!toggleUI ? "active" : ""}`}
|
className={`toggle-sidebar-ui-button ${!toggleUI ? "active" : ""}`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (activeModule !== "market") {
|
if (activeModule !== "market") {
|
||||||
|
@ -29,7 +29,7 @@ const Header: React.FC = () => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ToggleSidebarIcon />
|
<ToggleSidebarIcon />
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { AI_Icon } from "../../../icons/ExportCommonIcons";
|
import { AIIcon } from "../../../icons/ExportCommonIcons";
|
||||||
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
|
import RegularDropDown from "../../../ui/inputs/RegularDropDown";
|
||||||
import { AnalysisPresetsType } from "../../../../types/analysis";
|
import { AnalysisPresetsType } from "../../../../types/analysis";
|
||||||
import RenderAnalysisInputs from "./RenderAnalysisInputs";
|
import RenderAnalysisInputs from "./RenderAnalysisInputs";
|
||||||
|
@ -13,53 +13,24 @@ const Analysis: React.FC = () => {
|
||||||
|
|
||||||
const AnalysisPresets: AnalysisPresetsType = {
|
const AnalysisPresets: AnalysisPresetsType = {
|
||||||
"Throughput time": [
|
"Throughput time": [
|
||||||
{ type: "default", inputs: { label: "Height", activeOption: "mm" } },
|
{ type: "default", inputs: { label: "Cycle time", activeOption: "s" } },
|
||||||
{ type: "default", inputs: { label: "Width", activeOption: "mm" } },
|
{ type: "default", inputs: { label: "machines / lines", activeOption: "item" } },
|
||||||
{ type: "default", inputs: { label: "Length", activeOption: "mtr" } },
|
{ type: "default", inputs: { label: "Machine uptime", activeOption: "%" } },
|
||||||
{ type: "default", inputs: { label: "Thickness", activeOption: "mm" } },
|
|
||||||
{
|
|
||||||
type: "default",
|
|
||||||
inputs: { label: "Raw Material", activeOption: "mm" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "range",
|
|
||||||
inputs: { label: "Material flow", activeOption: "m/min" },
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
"Production capacity": [
|
"Production capacity": [
|
||||||
{ type: "default", inputs: { label: "Height", activeOption: "mm" } },
|
{ type: "default", inputs: { label: "Shift length", activeOption: "hr" } },
|
||||||
{ type: "default", inputs: { label: "Width", activeOption: "mm" } },
|
{ type: "default", inputs: { label: "Shifts / day", activeOption: "unit" } },
|
||||||
{ type: "default", inputs: { label: "Length", activeOption: "mtr" } },
|
{ type: "default", inputs: { label: "Working days / year", activeOption: "days" } },
|
||||||
{ type: "default", inputs: { label: "Thickness", activeOption: "mm" } },
|
{ type: "default", inputs: { label: "Yield rate", activeOption: "%" } },
|
||||||
{
|
|
||||||
type: "default",
|
|
||||||
inputs: { label: "Raw Material", activeOption: "mm" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "range",
|
|
||||||
inputs: { label: "Material flow", activeOption: "m/min" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "range",
|
|
||||||
inputs: { label: "Shift 1", activeOption: "hr(s)" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "range",
|
|
||||||
inputs: { label: "Shift 2", activeOption: "hr(s)" },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "range",
|
|
||||||
inputs: { label: "Over time", activeOption: "hr(s)" },
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
ROI: [
|
ROI: [
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Equipment Cost", activeOption: "INR" },
|
inputs: { label: "Selling price", activeOption: "INR" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Employee Salary", activeOption: "INR" },
|
inputs: { label: "Material cost", activeOption: "INR" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
|
@ -67,7 +38,7 @@ const Analysis: React.FC = () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Cost per unit", activeOption: "INR" },
|
inputs: { label: "Maintenance cost", activeOption: "INR" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
|
@ -75,20 +46,19 @@ const Analysis: React.FC = () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Upkeep Cost", activeOption: "INR" },
|
inputs: { label: "Fixed costs", activeOption: "INR" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Working Hours", activeOption: "Hrs" },
|
inputs: { label: "Salvage value", activeOption: "Hrs" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Power Usage", activeOption: "KWH" },
|
inputs: { label: "Production period", activeOption: "yrs" },
|
||||||
},
|
},
|
||||||
{ type: "default", inputs: { label: "KWH", activeOption: "Mos" } },
|
|
||||||
{
|
{
|
||||||
type: "default",
|
type: "default",
|
||||||
inputs: { label: "Man Power", activeOption: "Person" },
|
inputs: { label: "Tax rate", activeOption: "%" },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
@ -98,7 +68,7 @@ const Analysis: React.FC = () => {
|
||||||
<div className="analysis-main-container">
|
<div className="analysis-main-container">
|
||||||
<div className="header">Object</div>
|
<div className="header">Object</div>
|
||||||
<div className="generate-report-button">
|
<div className="generate-report-button">
|
||||||
<AI_Icon /> Generate Report
|
<AIIcon /> Generate Report
|
||||||
</div>
|
</div>
|
||||||
<div className="analysis-content-container section">
|
<div className="analysis-content-container section">
|
||||||
<div className="dropdown-header-container">
|
<div className="dropdown-header-container">
|
||||||
|
@ -121,7 +91,7 @@ const Analysis: React.FC = () => {
|
||||||
/>
|
/>
|
||||||
<div className="buttons-container">
|
<div className="buttons-container">
|
||||||
<input type="button" value={"Clear"} className="cancel" />
|
<input type="button" value={"Clear"} className="cancel" />
|
||||||
<input type="button" value={"Calculate"} className="submit" />
|
<input type="button" value={"Update"} className="submit" />
|
||||||
</div>
|
</div>
|
||||||
<div className="create-custom-analysis-container">
|
<div className="create-custom-analysis-container">
|
||||||
<div className="custom-analysis-header">Create Custom Analysis</div>
|
<div className="custom-analysis-header">Create Custom Analysis</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import InputRange from "../../../ui/inputs/InputRange";
|
import InputRange from "../../../ui/inputs/InputRange";
|
||||||
import InputToggle from "../../../ui/inputs/InputToggle";
|
import InputToggle from "../../../ui/inputs/InputToggle";
|
||||||
import { AI_Icon } from "../../../icons/ExportCommonIcons";
|
import { AIIcon } from "../../../icons/ExportCommonIcons";
|
||||||
import LabeledButton from "../../../ui/inputs/LabledButton";
|
import LabeledButton from "../../../ui/inputs/LabledButton";
|
||||||
import {
|
import {
|
||||||
useAzimuth,
|
useAzimuth,
|
||||||
|
@ -225,7 +225,7 @@ const GlobalProperties: React.FC = () => {
|
||||||
<section>
|
<section>
|
||||||
<div className="header">Environment</div>
|
<div className="header">Environment</div>
|
||||||
<div className="optimize-button" onClick={optimizeScene}>
|
<div className="optimize-button" onClick={optimizeScene}>
|
||||||
<AI_Icon />
|
<AIIcon />
|
||||||
Optimize
|
Optimize
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import {
|
import {
|
||||||
useSelectedEventData,
|
useSelectedEventData,
|
||||||
useSelectedEventSphere,
|
useSelectedEventSphere,
|
||||||
useSelectedProduct,
|
useSelectedProduct,
|
||||||
} from "../../../../../store/simulation/useSimulationStore";
|
} 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";
|
||||||
|
@ -15,114 +15,118 @@ import { handleAddEventToProduct } from "../../../../../modules/simulation/event
|
||||||
import { useEventsStore } from "../../../../../store/simulation/useEventsStore";
|
import { useEventsStore } from "../../../../../store/simulation/useEventsStore";
|
||||||
|
|
||||||
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>(
|
||||||
const [assetType, setAssetType] = useState<string | null>(null);
|
null
|
||||||
const { products, addEvent } = useProductStore();
|
);
|
||||||
const { selectedEventSphere } = useSelectedEventSphere();
|
const [assetType, setAssetType] = useState<string | null>(null);
|
||||||
|
const { products, addEvent } = useProductStore();
|
||||||
|
const { selectedEventSphere } = useSelectedEventSphere();
|
||||||
|
|
||||||
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
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [selectedEventData, selectedProduct]);
|
}, [selectedEventData, selectedProduct]);
|
||||||
|
|
||||||
const getCurrentEventData = () => {
|
|
||||||
if (!selectedEventData?.data || !selectedProduct) return null;
|
|
||||||
return (
|
|
||||||
getEventByModelUuid(
|
|
||||||
selectedProduct.productId,
|
|
||||||
selectedEventData.data.modelUuid
|
|
||||||
) ?? null
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const determineAssetType = (event: EventsSchema | null) => {
|
|
||||||
if (!event) return null;
|
|
||||||
|
|
||||||
switch (event.type) {
|
|
||||||
case "transfer":
|
|
||||||
return "conveyor";
|
|
||||||
case "vehicle":
|
|
||||||
return "vehicle";
|
|
||||||
case "roboticArm":
|
|
||||||
return "roboticArm";
|
|
||||||
case "machine":
|
|
||||||
return "machine";
|
|
||||||
case "storageUnit":
|
|
||||||
return "storageUnit";
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
const getCurrentEventData = () => {
|
||||||
|
if (!selectedEventData?.data || !selectedProduct) return null;
|
||||||
return (
|
return (
|
||||||
<div className="event-proprties-wrapper">
|
getEventByModelUuid(
|
||||||
{currentEventData && (
|
selectedProduct.productId,
|
||||||
<>
|
selectedEventData.data.modelUuid
|
||||||
<div className="header">
|
) ?? null
|
||||||
<div className="header-value">
|
|
||||||
{selectedEventData?.data.modelName}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{assetType === "conveyor" && <ConveyorMechanics />}
|
|
||||||
{assetType === "vehicle" && <VehicleMechanics />}
|
|
||||||
{assetType === "roboticArm" && <RoboticArmMechanics />}
|
|
||||||
{assetType === "machine" && <MachineMechanics />}
|
|
||||||
{assetType === "storageUnit" && <StorageMechanics />}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{!currentEventData && selectedEventSphere && (
|
|
||||||
<div className="no-event-selected">
|
|
||||||
<p>
|
|
||||||
<strong>Oops!</strong> It looks like this object doesn't have an
|
|
||||||
event assigned yet. To continue, please link it to one of the
|
|
||||||
products below.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="products-list">
|
|
||||||
<p>
|
|
||||||
<strong>Here are some products you can add it to:</strong>
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
{products.map((product) => (
|
|
||||||
<li key={product.productId}>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
if (selectedEventData) {
|
|
||||||
handleAddEventToProduct({
|
|
||||||
event: useEventsStore.getState().getEventByModelUuid(selectedEventData?.data.modelUuid),
|
|
||||||
addEvent,
|
|
||||||
selectedProduct,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<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 >
|
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const determineAssetType = (event: EventsSchema | null) => {
|
||||||
|
if (!event) return null;
|
||||||
|
|
||||||
|
switch (event.type) {
|
||||||
|
case "transfer":
|
||||||
|
return "conveyor";
|
||||||
|
case "vehicle":
|
||||||
|
return "vehicle";
|
||||||
|
case "roboticArm":
|
||||||
|
return "roboticArm";
|
||||||
|
case "machine":
|
||||||
|
return "machine";
|
||||||
|
case "storageUnit":
|
||||||
|
return "storageUnit";
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="event-proprties-wrapper">
|
||||||
|
{currentEventData && (
|
||||||
|
<>
|
||||||
|
<div className="header">
|
||||||
|
<div className="header-value">
|
||||||
|
{selectedEventData?.data.modelName}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{assetType === "conveyor" && <ConveyorMechanics />}
|
||||||
|
{assetType === "vehicle" && <VehicleMechanics />}
|
||||||
|
{assetType === "roboticArm" && <RoboticArmMechanics />}
|
||||||
|
{assetType === "machine" && <MachineMechanics />}
|
||||||
|
{assetType === "storageUnit" && <StorageMechanics />}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{!currentEventData && selectedEventSphere && (
|
||||||
|
<div className="no-event-selected">
|
||||||
|
<p>
|
||||||
|
<strong>Oops!</strong> It looks like this object doesn't have an
|
||||||
|
event assigned yet. To continue, please link it to one of the
|
||||||
|
products below.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="products-list">
|
||||||
|
<p>
|
||||||
|
<strong>Here are some products you can add it to:</strong>
|
||||||
|
</p>
|
||||||
|
<div className="product-item">
|
||||||
|
{products.map((product) => (
|
||||||
|
<button
|
||||||
|
key={product.productId}
|
||||||
|
onClick={() => {
|
||||||
|
if (selectedEventData) {
|
||||||
|
handleAddEventToProduct({
|
||||||
|
event: useEventsStore
|
||||||
|
.getState()
|
||||||
|
.getEventByModelUuid(
|
||||||
|
selectedEventData?.data.modelUuid
|
||||||
|
),
|
||||||
|
addEvent,
|
||||||
|
selectedProduct,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AddIcon />
|
||||||
|
{product.productName}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</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>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default EventProperties;
|
export default EventProperties;
|
||||||
|
|
|
@ -36,7 +36,6 @@ import {
|
||||||
import useToggleStore from "../../store/useUIToggleStore";
|
import useToggleStore from "../../store/useUIToggleStore";
|
||||||
import {
|
import {
|
||||||
use3DWidget,
|
use3DWidget,
|
||||||
useDroppedObjectsStore,
|
|
||||||
useFloatingWidget,
|
useFloatingWidget,
|
||||||
} from "../../store/visualization/useDroppedObjectsStore";
|
} from "../../store/visualization/useDroppedObjectsStore";
|
||||||
|
|
||||||
|
@ -57,20 +56,18 @@ const Tools: React.FC = () => {
|
||||||
|
|
||||||
const { widgets3D } = use3DWidget();
|
const { widgets3D } = use3DWidget();
|
||||||
|
|
||||||
const zones = useDroppedObjectsStore((state) => state.zones);
|
|
||||||
|
|
||||||
// wall options
|
// wall options
|
||||||
const { toggleView, setToggleView } = useToggleView();
|
const { toggleView, setToggleView } = useToggleView();
|
||||||
const { setDeleteTool } = useDeleteTool();
|
const { setDeleteTool } = useDeleteTool();
|
||||||
const { setAddAction } = useAddAction();
|
const { setAddAction } = useAddAction();
|
||||||
const { setSelectedWallItem } = useSelectedWallItem();
|
const { setSelectedWallItem } = useSelectedWallItem();
|
||||||
|
|
||||||
const { transformMode, setTransformMode } = useTransformMode();
|
const { setTransformMode } = useTransformMode();
|
||||||
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
|
const { setDeletePointOrLine } = useDeletePointOrLine();
|
||||||
const { movePoint, setMovePoint } = useMovePoint();
|
const { setMovePoint } = useMovePoint();
|
||||||
const { toolMode, setToolMode } = useToolMode();
|
const { setToolMode } = useToolMode();
|
||||||
const { activeTool, setActiveTool } = useActiveTool();
|
const { activeTool, setActiveTool } = useActiveTool();
|
||||||
const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
|
const { setRefTextUpdate } = useRefTextUpdate();
|
||||||
|
|
||||||
// Reset activeTool whenever activeModule changes
|
// Reset activeTool whenever activeModule changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -209,268 +206,266 @@ const Tools: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{!isPlaying ? (
|
{!isPlaying ? (
|
||||||
<>
|
<div className="tools-container">
|
||||||
<div className="tools-container">
|
<div className="drop-down-icons">
|
||||||
<div className="drop-down-icons">
|
<div className="activeDropicon">
|
||||||
<div className="activeDropicon">
|
{activeSubTool == "cursor" && (
|
||||||
{activeSubTool == "cursor" && (
|
|
||||||
<div
|
|
||||||
className={`tool-button ${
|
|
||||||
activeTool === "cursor" ? "active" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => {
|
|
||||||
setActiveTool("cursor");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<CursorIcon isActive={activeTool === "cursor"} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{activeSubTool == "free-hand" && (
|
|
||||||
<div
|
|
||||||
className={`tool-button ${
|
|
||||||
activeTool === "free-hand" ? "active" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => {
|
|
||||||
setActiveTool("free-hand");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FreeMoveIcon isActive={activeTool === "free-hand"} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{activeSubTool == "delete" && (
|
|
||||||
<div
|
|
||||||
className={`tool-button ${
|
|
||||||
activeTool === "delete" ? "active" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => {
|
|
||||||
setActiveTool("delete");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DeleteIcon isActive={activeTool === "delete"} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{activeModule !== "visualization" && (
|
|
||||||
<div
|
|
||||||
className="drop-down-option-button"
|
|
||||||
ref={dropdownRef}
|
|
||||||
onClick={() => {
|
|
||||||
setOpenDrop(!openDrop);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ArrowIcon />
|
|
||||||
{openDrop && (
|
|
||||||
<div className="drop-down-container">
|
|
||||||
<div
|
|
||||||
className="option-list"
|
|
||||||
onClick={() => {
|
|
||||||
setOpenDrop(false);
|
|
||||||
setActiveTool("cursor");
|
|
||||||
setActiveSubTool("cursor");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="active-option">
|
|
||||||
{activeSubTool === "cursor" && <TickIcon />}
|
|
||||||
</div>
|
|
||||||
<CursorIcon isActive={false} />
|
|
||||||
<div className="option">Cursor</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="option-list"
|
|
||||||
onClick={() => {
|
|
||||||
setOpenDrop(false);
|
|
||||||
setActiveTool("free-hand");
|
|
||||||
setActiveSubTool("free-hand");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="active-option">
|
|
||||||
{activeSubTool === "free-hand" && <TickIcon />}
|
|
||||||
</div>
|
|
||||||
<FreeMoveIcon isActive={false} />
|
|
||||||
<div className="option">Free Hand</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="option-list"
|
|
||||||
onClick={() => {
|
|
||||||
setOpenDrop(false);
|
|
||||||
setActiveTool("delete");
|
|
||||||
setActiveSubTool("delete");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="active-option">
|
|
||||||
{activeSubTool === "delete" && <TickIcon />}
|
|
||||||
</div>
|
|
||||||
<DeleteIcon isActive={false} />
|
|
||||||
<div className="option">Delete</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{!toggleThreeD && activeModule === "builder" && (
|
|
||||||
<>
|
|
||||||
<div className="split"></div>
|
|
||||||
<div className="draw-tools">
|
|
||||||
<div
|
|
||||||
className={`tool-button ${
|
|
||||||
activeTool === "draw-wall" ? "active" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => {
|
|
||||||
setActiveTool("draw-wall");
|
|
||||||
}}
|
|
||||||
title="Wall"
|
|
||||||
>
|
|
||||||
<WallIcon isActive={activeTool === "draw-wall"} />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`tool-button ${
|
|
||||||
activeTool === "draw-zone" ? "active" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => {
|
|
||||||
setActiveTool("draw-zone");
|
|
||||||
}}
|
|
||||||
title="Zone"
|
|
||||||
>
|
|
||||||
<ZoneIcon isActive={activeTool === "draw-zone"} />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`tool-button ${
|
|
||||||
activeTool === "draw-aisle" ? "active" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => {
|
|
||||||
setActiveTool("draw-aisle");
|
|
||||||
}}
|
|
||||||
title="Aisle"
|
|
||||||
>
|
|
||||||
<AsileIcon isActive={activeTool === "draw-aisle"} />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`tool-button ${
|
|
||||||
activeTool === "draw-floor" ? "active" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => {
|
|
||||||
setActiveTool("draw-floor");
|
|
||||||
}}
|
|
||||||
title="Floor"
|
|
||||||
>
|
|
||||||
<FloorIcon isActive={activeTool === "draw-floor"} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{activeModule === "builder" && (
|
|
||||||
<>
|
|
||||||
<div className="split"></div>
|
|
||||||
<div className="draw-tools">
|
|
||||||
<div
|
|
||||||
className={`tool-button ${
|
|
||||||
activeTool === "measure" ? "active" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => {
|
|
||||||
setActiveTool("measure");
|
|
||||||
}}
|
|
||||||
title="Measure"
|
|
||||||
>
|
|
||||||
<MeasureToolIcon isActive={activeTool === "measure"} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{activeModule === "simulation" && (
|
|
||||||
<>
|
|
||||||
<div className="split"></div>
|
|
||||||
<div className="draw-tools">
|
|
||||||
<div
|
|
||||||
className={`tool-button ${
|
|
||||||
activeTool === "pen" ? "active" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => {
|
|
||||||
setActiveTool("pen");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<PenIcon isActive={activeTool === "pen"} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{activeModule === "visualization" && (
|
|
||||||
<>
|
|
||||||
<div className="split"></div>
|
|
||||||
<div className="draw-tools">
|
|
||||||
<div
|
|
||||||
className={`tool-button`}
|
|
||||||
onClick={() => {
|
|
||||||
handleSaveTemplate({
|
|
||||||
addTemplate,
|
|
||||||
floatingWidget,
|
|
||||||
widgets3D,
|
|
||||||
selectedZone,
|
|
||||||
templates,
|
|
||||||
visualizationSocket,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SaveTemplateIcon isActive={false} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<div className="split"></div>
|
|
||||||
<div className="general-options">
|
|
||||||
<div
|
|
||||||
className={`tool-button ${
|
|
||||||
activeTool === "comment" ? "active" : ""
|
|
||||||
}`}
|
|
||||||
onClick={() => {
|
|
||||||
setActiveTool("comment");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<CommentIcon isActive={activeTool === "comment"} />
|
|
||||||
</div>
|
|
||||||
{toggleThreeD && (
|
|
||||||
<div
|
<div
|
||||||
className={`tool-button ${
|
className={`tool-button ${
|
||||||
activeTool === "play" ? "active" : ""
|
activeTool === "cursor" ? "active" : ""
|
||||||
}`}
|
}`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsPlaying(!isPlaying);
|
setActiveTool("cursor");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PlayIcon isActive={activeTool === "play"} />
|
<CursorIcon isActive={activeTool === "cursor"} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{activeSubTool == "free-hand" && (
|
||||||
|
<div
|
||||||
|
className={`tool-button ${
|
||||||
|
activeTool === "free-hand" ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setActiveTool("free-hand");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FreeMoveIcon isActive={activeTool === "free-hand"} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{activeSubTool == "delete" && (
|
||||||
|
<div
|
||||||
|
className={`tool-button ${
|
||||||
|
activeTool === "delete" ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setActiveTool("delete");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DeleteIcon isActive={activeTool === "delete"} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{activeModule !== "visualization" && (
|
||||||
|
<div
|
||||||
|
className="drop-down-option-button"
|
||||||
|
ref={dropdownRef}
|
||||||
|
onClick={() => {
|
||||||
|
setOpenDrop(!openDrop);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ArrowIcon />
|
||||||
|
{openDrop && (
|
||||||
|
<div className="drop-down-container">
|
||||||
|
<div
|
||||||
|
className="option-list"
|
||||||
|
onClick={() => {
|
||||||
|
setOpenDrop(false);
|
||||||
|
setActiveTool("cursor");
|
||||||
|
setActiveSubTool("cursor");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="active-option">
|
||||||
|
{activeSubTool === "cursor" && <TickIcon />}
|
||||||
|
</div>
|
||||||
|
<CursorIcon isActive={false} />
|
||||||
|
<div className="option">Cursor</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="option-list"
|
||||||
|
onClick={() => {
|
||||||
|
setOpenDrop(false);
|
||||||
|
setActiveTool("free-hand");
|
||||||
|
setActiveSubTool("free-hand");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="active-option">
|
||||||
|
{activeSubTool === "free-hand" && <TickIcon />}
|
||||||
|
</div>
|
||||||
|
<FreeMoveIcon isActive={false} />
|
||||||
|
<div className="option">Free Hand</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="option-list"
|
||||||
|
onClick={() => {
|
||||||
|
setOpenDrop(false);
|
||||||
|
setActiveTool("delete");
|
||||||
|
setActiveSubTool("delete");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="active-option">
|
||||||
|
{activeSubTool === "delete" && <TickIcon />}
|
||||||
|
</div>
|
||||||
|
<DeleteIcon isActive={false} />
|
||||||
|
<div className="option">Delete</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{activeModule === "builder" && (
|
</div>
|
||||||
<>
|
{!toggleThreeD && activeModule === "builder" && (
|
||||||
<div className="split"></div>
|
<>
|
||||||
|
<div className="split"></div>
|
||||||
|
<div className="draw-tools">
|
||||||
<div
|
<div
|
||||||
className={`toggle-threed-button${
|
className={`tool-button ${
|
||||||
toggleThreeD ? " toggled" : ""
|
activeTool === "draw-wall" ? "active" : ""
|
||||||
}`}
|
}`}
|
||||||
onClick={toggleSwitch}
|
onClick={() => {
|
||||||
|
setActiveTool("draw-wall");
|
||||||
|
}}
|
||||||
|
title="Wall"
|
||||||
>
|
>
|
||||||
<div
|
<WallIcon isActive={activeTool === "draw-wall"} />
|
||||||
className={`toggle-option${!toggleThreeD ? " active" : ""}`}
|
|
||||||
>
|
|
||||||
2d
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`toggle-option${toggleThreeD ? " active" : ""}`}
|
|
||||||
>
|
|
||||||
3d
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
<div
|
||||||
|
className={`tool-button ${
|
||||||
|
activeTool === "draw-zone" ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setActiveTool("draw-zone");
|
||||||
|
}}
|
||||||
|
title="Zone"
|
||||||
|
>
|
||||||
|
<ZoneIcon isActive={activeTool === "draw-zone"} />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`tool-button ${
|
||||||
|
activeTool === "draw-aisle" ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setActiveTool("draw-aisle");
|
||||||
|
}}
|
||||||
|
title="Aisle"
|
||||||
|
>
|
||||||
|
<AsileIcon isActive={activeTool === "draw-aisle"} />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`tool-button ${
|
||||||
|
activeTool === "draw-floor" ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setActiveTool("draw-floor");
|
||||||
|
}}
|
||||||
|
title="Floor"
|
||||||
|
>
|
||||||
|
<FloorIcon isActive={activeTool === "draw-floor"} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{activeModule === "builder" && (
|
||||||
|
<>
|
||||||
|
<div className="split"></div>
|
||||||
|
<div className="draw-tools">
|
||||||
|
<div
|
||||||
|
className={`tool-button ${
|
||||||
|
activeTool === "measure" ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setActiveTool("measure");
|
||||||
|
}}
|
||||||
|
title="Measure"
|
||||||
|
>
|
||||||
|
<MeasureToolIcon isActive={activeTool === "measure"} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{activeModule === "simulation" && (
|
||||||
|
<>
|
||||||
|
<div className="split"></div>
|
||||||
|
<div className="draw-tools">
|
||||||
|
<div
|
||||||
|
className={`tool-button ${
|
||||||
|
activeTool === "pen" ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setActiveTool("pen");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PenIcon isActive={activeTool === "pen"} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{activeModule === "visualization" && (
|
||||||
|
<>
|
||||||
|
<div className="split"></div>
|
||||||
|
<div className="draw-tools">
|
||||||
|
<div
|
||||||
|
className={`tool-button`}
|
||||||
|
onClick={() => {
|
||||||
|
handleSaveTemplate({
|
||||||
|
addTemplate,
|
||||||
|
floatingWidget,
|
||||||
|
widgets3D,
|
||||||
|
selectedZone,
|
||||||
|
templates,
|
||||||
|
visualizationSocket,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SaveTemplateIcon isActive={false} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<div className="split"></div>
|
||||||
|
<div className="general-options">
|
||||||
|
<div
|
||||||
|
className={`tool-button ${
|
||||||
|
activeTool === "comment" ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setActiveTool("comment");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CommentIcon isActive={activeTool === "comment"} />
|
||||||
|
</div>
|
||||||
|
{toggleThreeD && (
|
||||||
|
<div
|
||||||
|
className={`tool-button ${
|
||||||
|
activeTool === "play" ? "active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setIsPlaying(!isPlaying);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PlayIcon isActive={activeTool === "play"} />
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
{activeModule === "builder" && (
|
||||||
|
<>
|
||||||
|
<div className="split"></div>
|
||||||
|
<div
|
||||||
|
className={`toggle-threed-button${
|
||||||
|
toggleThreeD ? " toggled" : ""
|
||||||
|
}`}
|
||||||
|
onClick={toggleSwitch}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`toggle-option${!toggleThreeD ? " active" : ""}`}
|
||||||
|
>
|
||||||
|
2d
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`toggle-option${toggleThreeD ? " active" : ""}`}
|
||||||
|
>
|
||||||
|
3d
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{activeModule !== "simulation" && (
|
{activeModule !== "simulation" && (
|
||||||
<div className="exitPlay" onClick={() => setIsPlaying(false)}>
|
<button className="exitPlay" onClick={() => setIsPlaying(false)}>
|
||||||
X
|
X
|
||||||
</div>
|
</button>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,10 +1,28 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { HelpIcon } from "../../icons/DashboardIcon";
|
import { HelpIcon } from "../../icons/DashboardIcon";
|
||||||
import { useLogger } from "../log/LoggerContext";
|
import { useLogger } from "../log/LoggerContext";
|
||||||
|
import {
|
||||||
|
LogInfoIcon,
|
||||||
|
ErrorIcon,
|
||||||
|
WarningIcon,
|
||||||
|
} from "../../icons/ExportCommonIcons"; // Adjust path as needed
|
||||||
|
|
||||||
|
const getLogIcon = (type: string) => {
|
||||||
|
switch (type) {
|
||||||
|
case "info":
|
||||||
|
return <LogInfoIcon />;
|
||||||
|
case "error":
|
||||||
|
return <ErrorIcon />;
|
||||||
|
case "warning":
|
||||||
|
return <WarningIcon />;
|
||||||
|
case "log":
|
||||||
|
default:
|
||||||
|
return <LogInfoIcon />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const Footer = () => {
|
const Footer = () => {
|
||||||
const { logs, setIsLogListVisible } = useLogger();
|
const { logs, setIsLogListVisible } = useLogger();
|
||||||
|
|
||||||
const lastLog = logs.length > 0 ? logs[logs.length - 1] : null;
|
const lastLog = logs.length > 0 ? logs[logs.length - 1] : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -26,9 +44,14 @@ const Footer = () => {
|
||||||
|
|
||||||
<div className="logs-wrapper">
|
<div className="logs-wrapper">
|
||||||
<div className="logs-detail" onClick={() => setIsLogListVisible(true)}>
|
<div className="logs-detail" onClick={() => setIsLogListVisible(true)}>
|
||||||
{lastLog
|
{lastLog ? (
|
||||||
? `[${lastLog.type.toUpperCase()}] ${lastLog.message}`
|
<>
|
||||||
: "No logs yet."}
|
<span className="log-icon">{getLogIcon(lastLog.type)}</span>
|
||||||
|
<span className="log-message">{lastLog.message}</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
"No logs yet."
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="version">
|
<div className="version">
|
||||||
V 0.01
|
V 0.01
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
LogInfoIcon,
|
LogInfoIcon,
|
||||||
WarningIcon,
|
WarningIcon,
|
||||||
ErrorIcon,
|
ErrorIcon,
|
||||||
|
CloseIcon,
|
||||||
} from "../../icons/ExportCommonIcons"; // Adjust path as needed
|
} from "../../icons/ExportCommonIcons"; // Adjust path as needed
|
||||||
import { useLogger } from "./LoggerContext";
|
import { useLogger } from "./LoggerContext";
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ const LogList: React.FC = () => {
|
||||||
<div className="head">Log List</div>
|
<div className="head">Log List</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="close" onClick={() => setIsLogListVisible(false)}>
|
<div className="close" onClick={() => setIsLogListVisible(false)}>
|
||||||
X
|
{/* <CloseIcon /> */}X
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -12,25 +12,31 @@ import {
|
||||||
EndIcon,
|
EndIcon,
|
||||||
ExpandIcon,
|
ExpandIcon,
|
||||||
HourlySimulationIcon,
|
HourlySimulationIcon,
|
||||||
|
InfoIcon,
|
||||||
MonthlyROI,
|
MonthlyROI,
|
||||||
SpeedIcon,
|
SpeedIcon,
|
||||||
StartIcon,
|
StartIcon,
|
||||||
} from "../../icons/ExportCommonIcons";
|
} from "../../icons/ExportCommonIcons";
|
||||||
import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor";
|
import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor";
|
||||||
|
import { useSubModuleStore } from "../../../store/useModuleStore";
|
||||||
|
import ProductionCapacity from "../analysis/ProductionCapacity";
|
||||||
|
import ThroughputSummary from "../analysis/ThroughputSummary";
|
||||||
|
import ROISummary from "../analysis/ROISummary";
|
||||||
|
|
||||||
const SimulationPlayer: React.FC = () => {
|
const SimulationPlayer: React.FC = () => {
|
||||||
const MAX_SPEED = 8; // Maximum speed
|
const MAX_SPEED = 8; // Maximum speed
|
||||||
|
|
||||||
|
const isDragging = useRef(false);
|
||||||
|
const sliderRef = useRef<HTMLDivElement>(null);
|
||||||
const [expand, setExpand] = useState(true);
|
const [expand, setExpand] = useState(true);
|
||||||
|
const [playSimulation, setPlaySimulation] = useState(false);
|
||||||
|
|
||||||
const { speed, setSpeed } = useAnimationPlaySpeed();
|
const { speed, setSpeed } = useAnimationPlaySpeed();
|
||||||
const [playSimulation, setPlaySimulation] = useState(false);
|
|
||||||
const { setIsPlaying } = usePlayButtonStore();
|
const { setIsPlaying } = usePlayButtonStore();
|
||||||
const sliderRef = useRef<HTMLDivElement>(null);
|
|
||||||
const isDragging = useRef(false);
|
|
||||||
const { setActiveTool } = useActiveTool();
|
const { setActiveTool } = useActiveTool();
|
||||||
const { isPaused, setIsPaused } = usePauseButtonStore();
|
const { isPaused, setIsPaused } = usePauseButtonStore();
|
||||||
const { isReset, setReset } = useResetButtonStore();
|
const { isReset, setReset } = useResetButtonStore();
|
||||||
|
const { subModule } = useSubModuleStore();
|
||||||
|
|
||||||
// Button functions
|
// Button functions
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
|
@ -113,6 +119,15 @@ const SimulationPlayer: React.FC = () => {
|
||||||
return color;
|
return color;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Store colors for each process item
|
||||||
|
const [_, setProcessColors] = useState<string[]>([]);
|
||||||
|
|
||||||
|
// Generate colors on mount or when process changes
|
||||||
|
useEffect(() => {
|
||||||
|
const generatedColors = process.map(() => getRandomColor());
|
||||||
|
setProcessColors(generatedColors);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const intervals = [10, 20, 30, 40, 50, 60]; // in minutes
|
const intervals = [10, 20, 30, 40, 50, 60]; // in minutes
|
||||||
const totalSegments = intervals.length;
|
const totalSegments = intervals.length;
|
||||||
const progress = 20; // percent (example)
|
const progress = 20; // percent (example)
|
||||||
|
@ -150,214 +165,236 @@ const SimulationPlayer: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="simulation-player-wrapper">
|
<>
|
||||||
<div className={`simulation-player-container ${expand ? "open" : ""}`}>
|
<div className="simulation-player-wrapper">
|
||||||
<div className="controls-container">
|
<div className={`simulation-player-container ${expand ? "open" : ""}`}>
|
||||||
<div className="production-details">
|
<div className="controls-container">
|
||||||
{/* hourlySimulation */}
|
{subModule === "analysis" && (
|
||||||
<div className="hourly-wrapper production-wrapper">
|
<div className="production-details">
|
||||||
<div className="header">
|
{/* hourlySimulation */}
|
||||||
<div className="icon">
|
<div className="hourly-wrapper production-wrapper">
|
||||||
<HourlySimulationIcon />
|
<div className="header">
|
||||||
|
<div className="icon">
|
||||||
|
<HourlySimulationIcon />
|
||||||
|
</div>
|
||||||
|
<div className="label">Hourly Simulation</div>
|
||||||
|
</div>
|
||||||
|
<div className="progress-wrapper">
|
||||||
|
<div
|
||||||
|
className="progress"
|
||||||
|
style={{ width: hourlySimulation }}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="label">Hourly Simulation</div>
|
{/* dailyProduction */}
|
||||||
</div>
|
<div className="dailyProduction-wrapper production-wrapper">
|
||||||
<div className="progress-wrapper">
|
<div className="header">
|
||||||
<div
|
<div className="icon">
|
||||||
className="progress"
|
<DailyProductionIcon />
|
||||||
style={{ width: hourlySimulation }}
|
</div>
|
||||||
></div>
|
<div className="label">Daily Production</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="progress-wrapper">
|
||||||
{/* dailyProduction */}
|
<div
|
||||||
<div className="dailyProduction-wrapper production-wrapper">
|
className="progress"
|
||||||
<div className="header">
|
style={{ width: dailyProduction }}
|
||||||
<div className="icon">
|
></div>
|
||||||
<DailyProductionIcon />
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="label">Daily Production</div>
|
{/* monthlyROI */}
|
||||||
</div>
|
<div className="monthlyROI-wrapper production-wrapper">
|
||||||
<div className="progress-wrapper">
|
<div className="header">
|
||||||
<div
|
<div className="icon">
|
||||||
className="progress"
|
<MonthlyROI />
|
||||||
style={{ width: dailyProduction }}
|
</div>
|
||||||
></div>
|
<div className="label">Monthly ROI</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="progress-wrapper">
|
||||||
{/* monthlyROI */}
|
<div
|
||||||
<div className="monthlyROI-wrapper production-wrapper">
|
className="progress"
|
||||||
<div className="header">
|
style={{ width: monthlyROI }}
|
||||||
<div className="icon">
|
></div>
|
||||||
<MonthlyROI />
|
</div>{" "}
|
||||||
</div>
|
</div>
|
||||||
<div className="label">Monthly ROI</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="progress-wrapper">
|
)}
|
||||||
<div className="progress" style={{ width: monthlyROI }}></div>
|
{subModule === "simulations" && (
|
||||||
</div>{" "}
|
<div className="header">
|
||||||
</div>
|
<InfoIcon />
|
||||||
</div>
|
{playSimulation
|
||||||
<div className="controls-wrapper">
|
? "Paused - system idle."
|
||||||
<button
|
: "Running simulation..."}
|
||||||
className="simulation-button-container"
|
|
||||||
onClick={() => {
|
|
||||||
handleReset();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ResetIcon />
|
|
||||||
Reset
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="simulation-button-container"
|
|
||||||
onClick={() => {
|
|
||||||
handlePlayStop();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<PlayStopIcon />
|
|
||||||
{playSimulation ? "Play" : "Stop"}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="simulation-button-container"
|
|
||||||
onClick={() => {
|
|
||||||
handleExit();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ExitIcon />
|
|
||||||
Exit
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="expand-icon-container"
|
|
||||||
onClick={() => setExpand(!expand)}
|
|
||||||
>
|
|
||||||
<ExpandIcon isActive={!expand} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="progresser-wrapper">
|
|
||||||
<div className="time-displayer">
|
|
||||||
<div className="start-time-wrappper">
|
|
||||||
<div className="icon">
|
|
||||||
<StartIcon />
|
|
||||||
</div>
|
</div>
|
||||||
<div className="time-wrapper">
|
)}
|
||||||
<div className="date">23 April ,25</div>
|
<div className="controls-wrapper">
|
||||||
<div className="time">04:41 PM</div>
|
<button
|
||||||
</div>
|
className="simulation-button-container"
|
||||||
</div>
|
onClick={() => {
|
||||||
<div className="time-progresser">
|
handleReset();
|
||||||
<div className="timeline">
|
}}
|
||||||
{intervals.map((label, index) => {
|
>
|
||||||
const segmentProgress = (index / totalSegments) * 100;
|
<ResetIcon />
|
||||||
const isFilled = progress >= segmentProgress;
|
Reset
|
||||||
return (
|
</button>
|
||||||
<React.Fragment key={index}>
|
<button
|
||||||
<div className="label-dot-wrapper">
|
className="simulation-button-container"
|
||||||
<div className="label">{label} mins</div>
|
onClick={() => {
|
||||||
<div
|
handlePlayStop();
|
||||||
className={`dot ${isFilled ? "filled" : ""}`}
|
}}
|
||||||
></div>
|
>
|
||||||
</div>
|
<PlayStopIcon />
|
||||||
{index < intervals.length - 1 && (
|
{playSimulation ? "Play" : "Stop"}
|
||||||
<div
|
</button>
|
||||||
className={`line ${
|
<button
|
||||||
progress >= ((index + 1) / totalSegments) * 100
|
className="simulation-button-container"
|
||||||
? "filled"
|
onClick={() => {
|
||||||
: ""
|
handleExit();
|
||||||
}`}
|
}}
|
||||||
></div>
|
>
|
||||||
)}
|
<ExitIcon />
|
||||||
</React.Fragment>
|
Exit
|
||||||
);
|
</button>
|
||||||
})}
|
{subModule === "analysis" && (
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="end-time-wrappper">
|
|
||||||
<div className="time-wrapper">
|
|
||||||
<div className="time">00:10:20</div>
|
|
||||||
</div>
|
|
||||||
<div className="icon">
|
|
||||||
<EndIcon />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="speed-control-container">
|
|
||||||
<div className="min-value">
|
|
||||||
<div className="icon">
|
|
||||||
<SpeedIcon />
|
|
||||||
</div>
|
|
||||||
Speed
|
|
||||||
</div>
|
|
||||||
<div className="slider-container" ref={sliderRef}>
|
|
||||||
<div className="speed-label mix-value">0.5X</div>
|
|
||||||
<div className="marker marker-10"></div>
|
|
||||||
<div className="marker marker-20"></div>
|
|
||||||
<div className="marker marker-30"></div>
|
|
||||||
<div className="marker marker-40"></div>
|
|
||||||
<div className="marker marker-50"></div>
|
|
||||||
<div className="marker marker-60"></div>
|
|
||||||
<div className="marker marker-70"></div>
|
|
||||||
<div className="marker marker-80"></div>
|
|
||||||
<div className="marker marker-90"></div>
|
|
||||||
<div className="custom-slider">
|
|
||||||
<button
|
<button
|
||||||
className={`slider-handle ${isDragging ? "dragging" : ""}`}
|
className="expand-icon-container"
|
||||||
style={{ left: `${calculateHandlePosition()}%` }}
|
onClick={() => setExpand(!expand)}
|
||||||
onMouseDown={handleMouseDown}
|
|
||||||
>
|
>
|
||||||
{speed.toFixed(1)}x
|
<ExpandIcon isActive={!expand} />
|
||||||
</button>
|
</button>
|
||||||
<input
|
)}
|
||||||
type="range"
|
|
||||||
min="0.5"
|
|
||||||
max={MAX_SPEED}
|
|
||||||
step="0.1"
|
|
||||||
value={speed}
|
|
||||||
onChange={handleSpeedChange}
|
|
||||||
className="slider-input"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="speed-label max-value">4x</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="progresser-wrapper">
|
||||||
<div className="processDisplayer">
|
<div className="time-displayer">
|
||||||
<div className="start-displayer timmer">00:00</div>
|
<div className="start-time-wrappper">
|
||||||
<div className="end-displayer timmer">24:00</div>
|
<div className="icon">
|
||||||
<div
|
<StartIcon />
|
||||||
className="process-player"
|
|
||||||
style={{ left: playerPosition, position: "absolute" }}
|
|
||||||
></div>
|
|
||||||
<div
|
|
||||||
className="process-wrapper"
|
|
||||||
style={{ padding: expand ? "0px" : "5px 35px" }}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="process-container"
|
|
||||||
ref={processWrapperRef}
|
|
||||||
onMouseDown={handleProcessMouseDown}
|
|
||||||
>
|
|
||||||
{process.map((item, index) => (
|
|
||||||
<div
|
|
||||||
key={index}
|
|
||||||
className="process"
|
|
||||||
style={{
|
|
||||||
width: `${item.completed}%`,
|
|
||||||
backgroundColor: getAvatarColor(index),
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="process-player"
|
|
||||||
ref={processPlayerRef}
|
|
||||||
style={{ left: playerPosition, position: "absolute" }}
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
<div className="time-wrapper">
|
||||||
|
<div className="date">23 April ,25</div>
|
||||||
|
<div className="time">04:41 PM</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="time-progresser">
|
||||||
|
<div className="timeline">
|
||||||
|
{intervals.map((label, index) => {
|
||||||
|
const segmentProgress = (index / totalSegments) * 100;
|
||||||
|
const isFilled = progress >= segmentProgress;
|
||||||
|
return (
|
||||||
|
<React.Fragment key={index}>
|
||||||
|
<div className="label-dot-wrapper">
|
||||||
|
<div className="label">{label} mins</div>
|
||||||
|
<div
|
||||||
|
className={`dot ${isFilled ? "filled" : ""}`}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
{index < intervals.length - 1 && (
|
||||||
|
<div
|
||||||
|
className={`line ${
|
||||||
|
progress >= ((index + 1) / totalSegments) * 100
|
||||||
|
? "filled"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
></div>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="end-time-wrappper">
|
||||||
|
<div className="time-wrapper">
|
||||||
|
<div className="time">00:10:20</div>
|
||||||
|
</div>
|
||||||
|
<div className="icon">
|
||||||
|
<EndIcon />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="speed-control-container">
|
||||||
|
<div className="min-value">
|
||||||
|
<div className="icon">
|
||||||
|
<SpeedIcon />
|
||||||
|
</div>
|
||||||
|
Speed
|
||||||
|
</div>
|
||||||
|
<div className="slider-container" ref={sliderRef}>
|
||||||
|
<div className="speed-label mix-value">0.5X</div>
|
||||||
|
<div className="marker marker-10"></div>
|
||||||
|
<div className="marker marker-20"></div>
|
||||||
|
<div className="marker marker-30"></div>
|
||||||
|
<div className="marker marker-40"></div>
|
||||||
|
<div className="marker marker-50"></div>
|
||||||
|
<div className="marker marker-60"></div>
|
||||||
|
<div className="marker marker-70"></div>
|
||||||
|
<div className="marker marker-80"></div>
|
||||||
|
<div className="marker marker-90"></div>
|
||||||
|
<div className="custom-slider">
|
||||||
|
<button
|
||||||
|
className={`slider-handle ${isDragging ? "dragging" : ""}`}
|
||||||
|
style={{ left: `${calculateHandlePosition()}%` }}
|
||||||
|
onMouseDown={handleMouseDown}
|
||||||
|
>
|
||||||
|
{speed.toFixed(1)}x
|
||||||
|
</button>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
min="0.5"
|
||||||
|
max={MAX_SPEED}
|
||||||
|
step="0.1"
|
||||||
|
value={speed}
|
||||||
|
onChange={handleSpeedChange}
|
||||||
|
className="slider-input"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="speed-label max-value">4x</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{subModule === "analysis" && (
|
||||||
|
<div className="processDisplayer">
|
||||||
|
<div className="start-displayer timmer">00:00</div>
|
||||||
|
<div className="end-displayer timmer">24:00</div>
|
||||||
|
<div
|
||||||
|
className="process-wrapper"
|
||||||
|
style={{ padding: expand ? "0px" : "5px 35px" }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="process-container"
|
||||||
|
ref={processWrapperRef}
|
||||||
|
onMouseDown={handleProcessMouseDown}
|
||||||
|
>
|
||||||
|
{process.map((item, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="process"
|
||||||
|
style={{
|
||||||
|
width: `${item.completed}%`,
|
||||||
|
backgroundColor: getAvatarColor(index),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="process-player"
|
||||||
|
ref={processPlayerRef}
|
||||||
|
style={{ left: playerPosition, position: "absolute" }}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="analysis">
|
||||||
|
<div className="analysis-wrapper">
|
||||||
|
<ProductionCapacity />
|
||||||
|
<ThroughputSummary />
|
||||||
|
</div>
|
||||||
|
<ROISummary />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -76,8 +76,6 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
const { setSelectedChartId } = useWidgetStore();
|
const { setSelectedChartId } = useWidgetStore();
|
||||||
const [waitingPanels, setWaitingPanels] = useState(null);
|
const [waitingPanels, setWaitingPanels] = useState(null);
|
||||||
|
|
||||||
console.log("waitingPanels: ", waitingPanels);
|
|
||||||
|
|
||||||
OuterClick({
|
OuterClick({
|
||||||
contextClassName: [
|
contextClassName: [
|
||||||
"chart-container",
|
"chart-container",
|
||||||
|
@ -145,109 +143,109 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
});
|
});
|
||||||
}, [selectedZone]);
|
}, [selectedZone]);
|
||||||
|
|
||||||
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");
|
||||||
if (widgetSubOption === "3D") return;
|
// if (widgetSubOption === "3D") return;
|
||||||
if (!data || selectedZone.zoneName === "") return;
|
// if (!data || selectedZone.zoneName === "") return;
|
||||||
|
|
||||||
const droppedData = JSON.parse(data);
|
// const droppedData = JSON.parse(data);
|
||||||
const canvasElement = document.getElementById("real-time-vis-canvas");
|
// const canvasElement = document.getElementById("real-time-vis-canvas");
|
||||||
if (!canvasElement) throw new Error("Canvas element not found");
|
// if (!canvasElement) throw new Error("Canvas element not found");
|
||||||
|
|
||||||
const rect = canvasElement.getBoundingClientRect();
|
// const rect = canvasElement.getBoundingClientRect();
|
||||||
const relativeX = event.clientX - rect.left;
|
// const relativeX = event.clientX - rect.left;
|
||||||
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;
|
||||||
const centerOffsetY = widgetHeight / 2;
|
// const centerOffsetY = widgetHeight / 2;
|
||||||
|
|
||||||
const adjustedX = relativeX - centerOffsetX;
|
// const adjustedX = relativeX - centerOffsetX;
|
||||||
const adjustedY = relativeY - centerOffsetY;
|
// const adjustedY = relativeY - centerOffsetY;
|
||||||
|
|
||||||
const finalPosition = determinePosition(rect, adjustedX, adjustedY);
|
// const finalPosition = determinePosition(rect, adjustedX, adjustedY);
|
||||||
const [activeProp1, activeProp2] = getActiveProperties(finalPosition);
|
// const [activeProp1, activeProp2] = getActiveProperties(finalPosition);
|
||||||
|
|
||||||
let finalY = 0;
|
// let finalY = 0;
|
||||||
let finalX = 0;
|
// let finalX = 0;
|
||||||
|
|
||||||
if (activeProp1 === "top") {
|
// if (activeProp1 === "top") {
|
||||||
finalY = adjustedY;
|
// finalY = adjustedY;
|
||||||
} else {
|
// } else {
|
||||||
finalY = rect.height - (adjustedY + widgetHeight);
|
// finalY = rect.height - (adjustedY + widgetHeight);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (activeProp2 === "left") {
|
// if (activeProp2 === "left") {
|
||||||
finalX = adjustedX;
|
// finalX = adjustedX;
|
||||||
} else {
|
// } else {
|
||||||
finalX = rect.width - (adjustedX + widgetWidth);
|
// finalX = rect.width - (adjustedX + widgetWidth);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Clamp to boundaries
|
// // Clamp to boundaries
|
||||||
finalX = Math.max(0, Math.min(rect.width - widgetWidth, finalX));
|
// finalX = Math.max(0, Math.min(rect.width - widgetWidth, finalX));
|
||||||
finalY = Math.max(0, Math.min(rect.height - widgetHeight, finalY));
|
// finalY = Math.max(0, Math.min(rect.height - widgetHeight, finalY));
|
||||||
|
|
||||||
const boundedPosition = {
|
// const boundedPosition = {
|
||||||
...finalPosition,
|
// ...finalPosition,
|
||||||
[activeProp1]: finalY,
|
// [activeProp1]: finalY,
|
||||||
[activeProp2]: finalX,
|
// [activeProp2]: finalX,
|
||||||
[activeProp1 === "top" ? "bottom" : "top"]: "auto",
|
// [activeProp1 === "top" ? "bottom" : "top"]: "auto",
|
||||||
[activeProp2 === "left" ? "right" : "left"]: "auto",
|
// [activeProp2 === "left" ? "right" : "left"]: "auto",
|
||||||
};
|
// };
|
||||||
|
|
||||||
const newObject = {
|
// const newObject = {
|
||||||
...droppedData,
|
// ...droppedData,
|
||||||
id: generateUniqueId(),
|
// id: generateUniqueId(),
|
||||||
position: boundedPosition,
|
// position: boundedPosition,
|
||||||
};
|
// };
|
||||||
|
|
||||||
const existingZone =
|
// const existingZone =
|
||||||
useDroppedObjectsStore.getState().zones[selectedZone.zoneName];
|
// useDroppedObjectsStore.getState().zones[selectedZone.zoneName];
|
||||||
if (!existingZone) {
|
// if (!existingZone) {
|
||||||
useDroppedObjectsStore
|
// useDroppedObjectsStore
|
||||||
.getState()
|
// .getState()
|
||||||
.setZone(selectedZone.zoneName, selectedZone.zoneId);
|
// .setZone(selectedZone.zoneName, selectedZone.zoneId);
|
||||||
}
|
// }
|
||||||
|
|
||||||
const addFloatingWidget = {
|
// const addFloatingWidget = {
|
||||||
organization,
|
// organization,
|
||||||
widget: newObject,
|
// widget: newObject,
|
||||||
zoneId: selectedZone.zoneId,
|
// zoneId: selectedZone.zoneId,
|
||||||
};
|
// };
|
||||||
|
|
||||||
if (visualizationSocket) {
|
// if (visualizationSocket) {
|
||||||
visualizationSocket.emit("v2:viz-float:add", addFloatingWidget);
|
// visualizationSocket.emit("v2:viz-float:add", addFloatingWidget);
|
||||||
}
|
// }
|
||||||
|
|
||||||
useDroppedObjectsStore
|
// useDroppedObjectsStore
|
||||||
.getState()
|
// .getState()
|
||||||
.addObject(selectedZone.zoneName, newObject);
|
// .addObject(selectedZone.zoneName, newObject);
|
||||||
|
|
||||||
const droppedObjectsStore = useDroppedObjectsStore.getState();
|
// const droppedObjectsStore = useDroppedObjectsStore.getState();
|
||||||
const currentZone = droppedObjectsStore.zones[selectedZone.zoneName];
|
// const currentZone = droppedObjectsStore.zones[selectedZone.zoneName];
|
||||||
|
|
||||||
if (currentZone && currentZone.zoneId === selectedZone.zoneId) {
|
// if (currentZone && currentZone.zoneId === selectedZone.zoneId) {
|
||||||
console.log(
|
// console.log(
|
||||||
`Objects for Zone ${selectedZone.zoneId}:`,
|
// `Objects for Zone ${selectedZone.zoneId}:`,
|
||||||
currentZone.objects
|
// currentZone.objects
|
||||||
);
|
// );
|
||||||
setFloatingWidget(currentZone.objects);
|
// setFloatingWidget(currentZone.objects);
|
||||||
} else {
|
// } else {
|
||||||
console.warn("Zone not found or zoneId mismatch");
|
// console.warn("Zone not found or zoneId mismatch");
|
||||||
}
|
// }
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
console.error("Error in handleDrop:", error);
|
// console.error("Error in handleDrop:", error);
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleClickOutside = (event: MouseEvent) => {
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
|
@ -304,16 +302,7 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
</style>
|
</style>
|
||||||
<div
|
<div ref={containerRef} className="realTime-viz">
|
||||||
ref={containerRef}
|
|
||||||
id="real-time-vis-canvas"
|
|
||||||
className={`realTime-viz canvas ${isPlaying ? "playingFlase" : ""}`}
|
|
||||||
style={{
|
|
||||||
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
|
|
||||||
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
|
|
||||||
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="realTime-viz-wrapper">
|
<div className="realTime-viz-wrapper">
|
||||||
{openConfirmationPopup && (
|
{openConfirmationPopup && (
|
||||||
<RenderOverlay>
|
<RenderOverlay>
|
||||||
|
@ -324,20 +313,6 @@ const RealTimeVisulization: React.FC = () => {
|
||||||
/>
|
/>
|
||||||
</RenderOverlay>
|
</RenderOverlay>
|
||||||
)}
|
)}
|
||||||
<div
|
|
||||||
className="scene-container"
|
|
||||||
style={{
|
|
||||||
height: "100%",
|
|
||||||
width: "100%",
|
|
||||||
borderRadius:
|
|
||||||
isPlaying || activeModule !== "visualization" ? "" : "6px",
|
|
||||||
}}
|
|
||||||
role="application"
|
|
||||||
onDrop={(event) => handleDrop(event)}
|
|
||||||
onDragOver={(event) => event.preventDefault()}
|
|
||||||
>
|
|
||||||
<Scene />
|
|
||||||
</div>
|
|
||||||
{activeModule === "visualization" && selectedZone.zoneName !== "" && (
|
{activeModule === "visualization" && selectedZone.zoneName !== "" && (
|
||||||
<DroppedObjects />
|
<DroppedObjects />
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
import { generateUniqueId } from "../../../functions/generateUniqueId";
|
||||||
|
import { useDroppedObjectsStore } from "../../../store/visualization/useDroppedObjectsStore";
|
||||||
|
import { determinePosition } from "./determinePosition";
|
||||||
|
import { getActiveProperties } from "./getActiveProperties";
|
||||||
|
|
||||||
|
interface HandleDropProps {
|
||||||
|
widgetSubOption: any;
|
||||||
|
visualizationSocket: any;
|
||||||
|
selectedZone: any;
|
||||||
|
setFloatingWidget: (value: any) => void;
|
||||||
|
event: React.DragEvent<HTMLDivElement>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createHandleDrop = ({
|
||||||
|
widgetSubOption,
|
||||||
|
visualizationSocket,
|
||||||
|
selectedZone,
|
||||||
|
setFloatingWidget,
|
||||||
|
event,
|
||||||
|
}: HandleDropProps) => {
|
||||||
|
event.preventDefault();
|
||||||
|
try {
|
||||||
|
const email = localStorage.getItem("email") ?? "";
|
||||||
|
const organization = email?.split("@")[1]?.split(".")[0];
|
||||||
|
|
||||||
|
const data = event.dataTransfer.getData("text/plain");
|
||||||
|
if (widgetSubOption === "3D") return;
|
||||||
|
if (!data || selectedZone.zoneName === "") return;
|
||||||
|
|
||||||
|
const droppedData = JSON.parse(data);
|
||||||
|
const canvasElement = document.getElementById("real-time-vis-canvas");
|
||||||
|
if (!canvasElement) throw new Error("Canvas element not found");
|
||||||
|
|
||||||
|
const rect = canvasElement.getBoundingClientRect();
|
||||||
|
const relativeX = event.clientX - rect.left;
|
||||||
|
const relativeY = event.clientY - rect.top;
|
||||||
|
|
||||||
|
// Widget dimensions
|
||||||
|
const widgetWidth = droppedData.width ?? 125;
|
||||||
|
const widgetHeight = droppedData.height ?? 100;
|
||||||
|
|
||||||
|
// Center the widget at cursor
|
||||||
|
const centerOffsetX = widgetWidth / 2;
|
||||||
|
const centerOffsetY = widgetHeight / 2;
|
||||||
|
|
||||||
|
const adjustedX = relativeX - centerOffsetX;
|
||||||
|
const adjustedY = relativeY - centerOffsetY;
|
||||||
|
|
||||||
|
const finalPosition = determinePosition(rect, adjustedX, adjustedY);
|
||||||
|
const [activeProp1, activeProp2] = getActiveProperties(finalPosition);
|
||||||
|
|
||||||
|
let finalY = 0;
|
||||||
|
let finalX = 0;
|
||||||
|
|
||||||
|
if (activeProp1 === "top") {
|
||||||
|
finalY = adjustedY;
|
||||||
|
} else {
|
||||||
|
finalY = rect.height - (adjustedY + widgetHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeProp2 === "left") {
|
||||||
|
finalX = adjustedX;
|
||||||
|
} else {
|
||||||
|
finalX = rect.width - (adjustedX + widgetWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp to boundaries
|
||||||
|
finalX = Math.max(0, Math.min(rect.width - widgetWidth, finalX));
|
||||||
|
finalY = Math.max(0, Math.min(rect.height - widgetHeight, finalY));
|
||||||
|
|
||||||
|
const boundedPosition = {
|
||||||
|
...finalPosition,
|
||||||
|
[activeProp1]: finalY,
|
||||||
|
[activeProp2]: finalX,
|
||||||
|
[activeProp1 === "top" ? "bottom" : "top"]: "auto",
|
||||||
|
[activeProp2 === "left" ? "right" : "left"]: "auto",
|
||||||
|
};
|
||||||
|
|
||||||
|
const newObject = {
|
||||||
|
...droppedData,
|
||||||
|
id: generateUniqueId(),
|
||||||
|
position: boundedPosition,
|
||||||
|
};
|
||||||
|
|
||||||
|
const existingZone =
|
||||||
|
useDroppedObjectsStore.getState().zones[selectedZone.zoneName];
|
||||||
|
if (!existingZone) {
|
||||||
|
useDroppedObjectsStore
|
||||||
|
.getState()
|
||||||
|
.setZone(selectedZone.zoneName, selectedZone.zoneId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const addFloatingWidget = {
|
||||||
|
organization,
|
||||||
|
widget: newObject,
|
||||||
|
zoneId: selectedZone.zoneId,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (visualizationSocket) {
|
||||||
|
visualizationSocket.emit("v2:viz-float:add", addFloatingWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
useDroppedObjectsStore
|
||||||
|
.getState()
|
||||||
|
.addObject(selectedZone.zoneName, newObject);
|
||||||
|
|
||||||
|
const droppedObjectsStore = useDroppedObjectsStore.getState();
|
||||||
|
const currentZone = droppedObjectsStore.zones[selectedZone.zoneName];
|
||||||
|
|
||||||
|
if (currentZone && currentZone.zoneId === selectedZone.zoneId) {
|
||||||
|
console.log(
|
||||||
|
`Objects for Zone ${selectedZone.zoneId}:`,
|
||||||
|
currentZone.objects
|
||||||
|
);
|
||||||
|
setFloatingWidget(currentZone.objects);
|
||||||
|
} else {
|
||||||
|
console.warn("Zone not found or zoneId mismatch");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in handleDrop:", error);
|
||||||
|
}
|
||||||
|
};
|
|
@ -13,6 +13,7 @@ import {
|
||||||
useWallItems,
|
useWallItems,
|
||||||
useZones,
|
useZones,
|
||||||
useLoadingProgress,
|
useLoadingProgress,
|
||||||
|
useWidgetSubOption,
|
||||||
} from "../store/store";
|
} from "../store/store";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { usePlayButtonStore } from "../store/usePlayButtonStore";
|
import { usePlayButtonStore } from "../store/usePlayButtonStore";
|
||||||
|
@ -22,16 +23,19 @@ import SimulationPlayer from "../components/ui/simulation/simulationPlayer";
|
||||||
import KeyPressListener from "../utils/shortcutkeys/handleShortcutKeys";
|
import KeyPressListener from "../utils/shortcutkeys/handleShortcutKeys";
|
||||||
import { useSelectedUserStore } from "../store/useCollabStore";
|
import { useSelectedUserStore } from "../store/useCollabStore";
|
||||||
import FollowPerson from "../components/templates/FollowPerson";
|
import FollowPerson from "../components/templates/FollowPerson";
|
||||||
import ProductionCapacity from "../components/ui/analysis/ProductionCapacity";
|
import Scene from "../modules/scene/scene";
|
||||||
import ThroughputSummary from "../components/ui/analysis/ThroughputSummary";
|
import { createHandleDrop } from "../modules/visualization/functions/handleUiDrop";
|
||||||
import ROISummary from "../components/ui/analysis/ROISummary";
|
import { useSelectedZoneStore } from "../store/visualization/useZoneStore";
|
||||||
|
import { useFloatingWidget } from "../store/visualization/useDroppedObjectsStore";
|
||||||
|
import { useLogger } from "../components/ui/log/LoggerContext";
|
||||||
import Footer from "../components/ui/footer/Footer";
|
import Footer from "../components/ui/footer/Footer";
|
||||||
import RenderOverlay from "../components/templates/Overlay";
|
import RenderOverlay from "../components/templates/Overlay";
|
||||||
import LogList from "../components/ui/log/LogList";
|
import LogList from "../components/ui/log/LogList";
|
||||||
import { useLogger } from "../components/ui/log/LoggerContext";
|
|
||||||
|
|
||||||
const Project: React.FC = () => {
|
const Project: React.FC = () => {
|
||||||
let navigate = useNavigate();
|
let navigate = useNavigate();
|
||||||
|
const logger = useLogger();
|
||||||
|
|
||||||
const { activeModule, setActiveModule } = useModuleStore();
|
const { activeModule, setActiveModule } = useModuleStore();
|
||||||
const { loadingProgress } = useLoadingProgress();
|
const { loadingProgress } = useLoadingProgress();
|
||||||
const { setUserName } = useUserName();
|
const { setUserName } = useUserName();
|
||||||
|
@ -54,48 +58,78 @@ const Project: React.FC = () => {
|
||||||
setOrganization(Organization);
|
setOrganization(Organization);
|
||||||
setUserName(name);
|
setUserName(name);
|
||||||
}
|
}
|
||||||
|
logger.info("Log in success full");
|
||||||
} else {
|
} else {
|
||||||
navigate("/");
|
navigate("/");
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const { isPlaying } = usePlayButtonStore();
|
// global store
|
||||||
const { toggleThreeD } = useThreeDStore();
|
const { toggleThreeD } = useThreeDStore();
|
||||||
|
|
||||||
|
// simulation store
|
||||||
|
const { isPlaying } = usePlayButtonStore();
|
||||||
|
|
||||||
|
// collaboration store
|
||||||
const { selectedUser } = useSelectedUserStore();
|
const { selectedUser } = useSelectedUserStore();
|
||||||
const { isLogListVisible } = useLogger();
|
const { isLogListVisible } = useLogger();
|
||||||
|
|
||||||
|
// real-time visualization store
|
||||||
|
const { widgetSubOption } = useWidgetSubOption();
|
||||||
|
const { visualizationSocket } = useSocketStore();
|
||||||
|
const { selectedZone } = useSelectedZoneStore();
|
||||||
|
const { setFloatingWidget } = useFloatingWidget();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="project-main">
|
<div className="project-main">
|
||||||
{/* <div className="analysis">
|
{!selectedUser && (
|
||||||
<div className="analysis-wrapper">
|
|
||||||
<ProductionCapacity />
|
|
||||||
<ThroughputSummary />
|
|
||||||
</div>
|
|
||||||
<ROISummary />
|
|
||||||
</div> */}
|
|
||||||
<KeyPressListener />
|
|
||||||
{loadingProgress > 0 && <LoadingPage progress={loadingProgress} />}
|
|
||||||
{!isPlaying && (
|
|
||||||
<>
|
<>
|
||||||
{toggleThreeD && <ModuleToggle />}
|
<KeyPressListener />
|
||||||
<SideBarLeft />
|
{loadingProgress > 0 && <LoadingPage progress={loadingProgress} />}
|
||||||
<SideBarRight />
|
{!isPlaying && (
|
||||||
|
<>
|
||||||
|
{toggleThreeD && <ModuleToggle />}
|
||||||
|
<SideBarLeft />
|
||||||
|
<SideBarRight />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<RealTimeVisulization />
|
||||||
|
{activeModule === "market" && <MarketPlace />}
|
||||||
|
{activeModule !== "market" && <Tools />}
|
||||||
|
{isPlaying && activeModule === "simulation" && <SimulationPlayer />}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{/* <RenderOverlay>
|
<div
|
||||||
<MenuBar setOpenMenu={setOpenMenu} />
|
className="scene-container"
|
||||||
</RenderOverlay> */}
|
id="real-time-vis-canvas"
|
||||||
{activeModule === "market" && <MarketPlace />}
|
style={{
|
||||||
<RealTimeVisulization />
|
height: isPlaying || activeModule !== "visualization" ? "100vh" : "",
|
||||||
{activeModule !== "market" && <Tools />}
|
width: isPlaying || activeModule !== "visualization" ? "100vw" : "",
|
||||||
{isPlaying && activeModule === "simulation" && <SimulationPlayer />}
|
left: isPlaying || activeModule !== "visualization" ? "0%" : "",
|
||||||
{/* {<SimulationPlayer />} */}
|
borderRadius:
|
||||||
|
isPlaying || activeModule !== "visualization" ? "" : "6px",
|
||||||
|
}}
|
||||||
|
role="application"
|
||||||
|
onDrop={(event) =>
|
||||||
|
createHandleDrop({
|
||||||
|
widgetSubOption,
|
||||||
|
visualizationSocket,
|
||||||
|
selectedZone,
|
||||||
|
setFloatingWidget,
|
||||||
|
event,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onDragOver={(event) => event.preventDefault()}
|
||||||
|
>
|
||||||
|
<Scene />
|
||||||
|
</div>
|
||||||
|
{selectedUser && <FollowPerson />}
|
||||||
{isLogListVisible && (
|
{isLogListVisible && (
|
||||||
<RenderOverlay>
|
<RenderOverlay>
|
||||||
<LogList />
|
<LogList />
|
||||||
</RenderOverlay>
|
</RenderOverlay>
|
||||||
)}
|
)}
|
||||||
{selectedUser && <FollowPerson />}
|
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { addingFloatingWidgets } from "../../services/visulization/zone/addFloatingWidgets";
|
|
||||||
import { useSocketStore } from "../store";
|
import { useSocketStore } from "../store";
|
||||||
import useChartStore from "./useChartStore";
|
import useChartStore from "./useChartStore";
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,29 @@
|
||||||
@use "../abstracts/variables" as *;
|
@use "../abstracts/variables" as *;
|
||||||
@use "../abstracts/mixins" as *;
|
@use "../abstracts/mixins" as *;
|
||||||
|
|
||||||
section, .section{
|
section,
|
||||||
padding: 4px;
|
.section {
|
||||||
outline: 1px solid var(--border-color);
|
padding: 4px;
|
||||||
outline-offset: -1px;
|
outline: 1px solid var(--border-color);
|
||||||
border-radius: #{$border-radius-large};
|
outline-offset: -1px;
|
||||||
background: var(--background-color);
|
border-radius: #{$border-radius-large};
|
||||||
margin: 4px 0;
|
background: var(--background-color);
|
||||||
|
margin: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-container {
|
||||||
|
width: calc(100% - (320px + 270px + 90px));
|
||||||
|
height: calc(100% - (250px));
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: calc(270px + 45px);
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 1;
|
||||||
|
transform: translate(0, -50%);
|
||||||
|
transition: all 0.2s;
|
||||||
|
box-shadow: $box-shadow-medium;
|
||||||
|
canvas {
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,3 @@ 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;
|
|
||||||
}
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
@use "../../abstracts/variables" as *;
|
||||||
|
@use "../../abstracts/mixins" as *;
|
||||||
|
|
||||||
.roiSummary-container {
|
.roiSummary-container {
|
||||||
.roiSummary-wrapper {
|
.roiSummary-wrapper {
|
||||||
background-color: var(--background-color);
|
background-color: var(--background-color);
|
||||||
|
@ -64,7 +67,7 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
border: 1px solid #00FF56;
|
border: 1px solid #00FF56;
|
||||||
background: #436D51;
|
background: #17eb5d65;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 4px 6px;
|
padding: 4px 6px;
|
||||||
|
@ -223,12 +226,11 @@
|
||||||
background: none;
|
background: none;
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
background-color: var(--accent-color);
|
color: var(--text-button-color);
|
||||||
color: var(--background-color);
|
background: var(--background-color-button);
|
||||||
padding: 4px 6px;
|
padding: 4px 12px;
|
||||||
border-radius: 5px;
|
border-radius: #{$border-radius-large};
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 14px;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,7 +246,6 @@
|
||||||
height: 250px;
|
height: 250px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: background 0.5s ease;
|
|
||||||
}
|
}
|
||||||
.progress-cover {
|
.progress-cover {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -252,7 +253,6 @@
|
||||||
height: 75%;
|
height: 75%;
|
||||||
top: 12.5%;
|
top: 12.5%;
|
||||||
left: 12.5%;
|
left: 12.5%;
|
||||||
background: #000000cc;
|
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,279 +1,269 @@
|
||||||
.analysis {
|
.analysis {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: start;
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
pointer-events: none;
|
||||||
|
padding: 10px;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
.analysis-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
flex-direction: column;
|
||||||
align-items: start;
|
gap: 12px;
|
||||||
width: 100%;
|
}
|
||||||
height: 100vh;
|
.analysis-card {
|
||||||
// pointer-events: none;
|
|
||||||
z-index: 10000;
|
|
||||||
|
|
||||||
.analysis-wrapper {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.analysis-card {
|
|
||||||
min-width: 333px;
|
min-width: 333px;
|
||||||
background: var(--background-color);
|
background: var(--background-color);
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
|
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
outline: 1px solid var(--border-color);
|
||||||
|
outline-offset: -1px;
|
||||||
|
pointer-events: all;
|
||||||
|
|
||||||
.analysis-card-wrapper {
|
.analysis-card-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: var(--background-color);
|
background: var(--background-color);
|
||||||
border-radius: 14px;
|
border-radius: 14px;
|
||||||
padding: 16px;
|
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;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 14px;
|
|
||||||
|
|
||||||
.card-header {
|
.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: 100%;
|
||||||
|
height: 4px;
|
||||||
|
border-radius: 13px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #fbebd7;
|
||||||
|
|
||||||
|
.bar-fill {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background: #fc9d2f;
|
||||||
|
border-radius: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-fill.full {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
}
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.main-header {
|
.bar-fill.partial {
|
||||||
line-height: 20px;
|
width: 0; // inline style will override this
|
||||||
font-size: var(--font-size-regular);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.process-container {
|
.metrics-section {
|
||||||
display: flex;
|
padding-top: 16px;
|
||||||
flex-direction: column;
|
border-top: 1px solid var(--background-color-gray);
|
||||||
|
|
||||||
.throughput-value {
|
.metric {
|
||||||
font-size: 1rem;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
.value {
|
.label {
|
||||||
font-weight: bold;
|
color: var(--text-color);
|
||||||
font-size: 1.5rem;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar-wrapper {
|
.value {
|
||||||
display: flex;
|
font-weight: bold;
|
||||||
gap: 8px;
|
}
|
||||||
margin-top: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar {
|
|
||||||
position: relative;
|
|
||||||
// width: 36px;
|
|
||||||
width: 100%;
|
|
||||||
height: 4px;
|
|
||||||
border-radius: 13px;
|
|
||||||
overflow: hidden;
|
|
||||||
background: #FBEBD7;
|
|
||||||
|
|
||||||
.bar-fill {
|
|
||||||
position: absolute;
|
|
||||||
height: 100%;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
background: #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 {
|
.throughoutSummary-wrapper {
|
||||||
.process-container {
|
.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: 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;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: end;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.shiftUtilization {
|
||||||
|
.value-container {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
gap: 16px;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.throughput-value {
|
.value {
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-xlarge);
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.value {
|
|
||||||
color: var(--accent-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Let the text take available space */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.lineChart {
|
.progress-wrapper {
|
||||||
max-width: 200px;
|
width: 100%;
|
||||||
height: 100px;
|
display: flex;
|
||||||
position: relative;
|
gap: 6px;
|
||||||
|
|
||||||
.assetUsage {
|
.progress {
|
||||||
text-align: right;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
display: flex;
|
|
||||||
gap: 16px; // Space between cards
|
|
||||||
margin-top: 24px;
|
|
||||||
|
|
||||||
.footer-card {
|
|
||||||
width: 100%;
|
|
||||||
background: var(--background-color-gray);
|
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
padding: 8px;
|
height: 5px;
|
||||||
|
|
||||||
|
&:nth-child(1) {
|
||||||
|
background: #f3c64d;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(2) {
|
||||||
|
background: #67b3f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-child(3) {
|
||||||
|
background: #7981f5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-indicator {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
gap: 6px;
|
||||||
|
|
||||||
|
.shift-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 5px;
|
||||||
|
|
||||||
&:first-child {
|
/* Align items vertically */
|
||||||
width: 85%;
|
&:nth-child(1) {
|
||||||
|
.indicator {
|
||||||
|
background: #f3c64d;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
&:nth-child(2) {
|
||||||
font-size: var(--font-size-regular);
|
.indicator {
|
||||||
|
background: #67b3f4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.value-container {
|
&:nth-child(3) {
|
||||||
display: flex;
|
.indicator {
|
||||||
flex-direction: row;
|
background: #7981f5;
|
||||||
align-items: center;
|
}
|
||||||
justify-content: end;
|
|
||||||
gap: 6px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indicator {
|
||||||
|
display: inline-block;
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.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: #F3C64D;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-child(2) {
|
|
||||||
background: #67B3F4;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-child(3) {
|
|
||||||
background: #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: #F3C64D;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-child(2) {
|
|
||||||
.indicator {
|
|
||||||
|
|
||||||
background: #67B3F4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-child(3) {
|
|
||||||
.indicator {
|
|
||||||
|
|
||||||
background: #7981F5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
font-size: var(--font-size-small);
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.indicator {
|
|
||||||
display: inline-block;
|
|
||||||
width: 5px;
|
|
||||||
height: 5px;
|
|
||||||
border-radius: 50%;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
@use "../abstracts/variables" as *;
|
||||||
|
@use "../abstracts/mixins" as *;
|
||||||
|
|
||||||
|
.labeled-button-container {
|
||||||
|
@include flex-space-between;
|
||||||
|
padding: 6px 12px;
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 2px 32px;
|
||||||
|
border: none;
|
||||||
|
border-radius: #{$border-radius-large};
|
||||||
|
color: var(--text-button-color);
|
||||||
|
background: var(--background-color-button);
|
||||||
|
transition: all 0.2s;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
background: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 6px;
|
padding: 12px 24px;
|
||||||
|
|
||||||
.selection-wrapper {
|
.selection-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -22,8 +22,7 @@
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
|
|
||||||
.selector {
|
.selector {
|
||||||
color: var(--text-button-color);
|
color: var(--text-color);
|
||||||
font-weight: 200;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,13 +33,14 @@
|
||||||
|
|
||||||
.logs-detail,
|
.logs-detail,
|
||||||
.version {
|
.version {
|
||||||
|
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
background: var(--background-color);
|
background: var(--background-color);
|
||||||
padding: 3px 6px;
|
padding: 3px 6px;
|
||||||
color: var(--text-button-color);
|
color: var(--text-color);
|
||||||
font-weight: 200;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logs-detail {
|
.logs-detail {
|
||||||
|
|
|
@ -639,21 +639,6 @@ input[type="number"] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.labeled-button-container {
|
|
||||||
@include flex-space-between;
|
|
||||||
padding: 6px 12px;
|
|
||||||
|
|
||||||
button {
|
|
||||||
padding: 2px 32px;
|
|
||||||
border: none;
|
|
||||||
border-radius: #{$border-radius-large};
|
|
||||||
color: var(--text-button-color);
|
|
||||||
background: var(--background-color-button);
|
|
||||||
transition: all 0.2s;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.value-field-container {
|
.value-field-container {
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
.log-list-container {
|
.log-list-container {
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
background: var(--background-color-secondary);
|
// background: var(--background-color-secondary);
|
||||||
backdrop-filter: blur(2px);
|
// backdrop-filter: blur(2px);
|
||||||
|
|
||||||
.log-list-wrapper {
|
.log-list-wrapper {
|
||||||
height: 50%;
|
height: 50%;
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
|
backdrop-filter: blur(50px);
|
||||||
|
|
||||||
.log-header {
|
.log-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.close {
|
.close {
|
||||||
|
// transform: scale(1.5);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,10 +32,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.controls-container {
|
.controls-container {
|
||||||
@include flex-center;
|
@include flex-space-between;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
.header{
|
||||||
|
@include flex-center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 0 8px;
|
||||||
|
svg{
|
||||||
|
scale: 1.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
.production-details,
|
.production-details,
|
||||||
.controls-wrapper {
|
.controls-wrapper {
|
||||||
@include flex-center;
|
@include flex-center;
|
||||||
|
@ -72,7 +79,7 @@
|
||||||
|
|
||||||
.expand-icon-container {
|
.expand-icon-container {
|
||||||
@include flex-center;
|
@include flex-center;
|
||||||
padding: 6px 8px;
|
padding: 0 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
transition: width 0.2s;
|
transition: width 0.2s;
|
||||||
background: var(--background-color);
|
background: var(--background-color);
|
||||||
backdrop-filter: blur(8px);
|
backdrop-filter: blur(8px);
|
||||||
z-index: #{$z-index-default};
|
z-index: 2;
|
||||||
outline: 1px solid var(--border-color);
|
outline: 1px solid var(--border-color);
|
||||||
outline-offset: -1px;
|
outline-offset: -1px;
|
||||||
|
|
||||||
|
@ -124,6 +124,8 @@
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
border-radius: #{$border-radius-medium};
|
border-radius: #{$border-radius-medium};
|
||||||
background: var(--background-color);
|
background: var(--background-color);
|
||||||
|
outline: 1px solid var(--border-color);
|
||||||
|
outline-offset: -1px;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
|
|
@ -58,12 +58,8 @@
|
||||||
fill: var(--icon-default-color-active);
|
fill: var(--icon-default-color-active);
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
rect {
|
filter: saturate(0.8);
|
||||||
stroke: var(--icon-default-color);
|
background: var(--background-color-accent);
|
||||||
}
|
|
||||||
circle {
|
|
||||||
fill: var(--icon-default-color);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -714,10 +710,10 @@
|
||||||
|
|
||||||
.add-button {
|
.add-button {
|
||||||
@include flex-center;
|
@include flex-center;
|
||||||
padding: 2px 4px;
|
padding: 4px 8px;
|
||||||
background: var(--background-color-button);
|
background: var(--background-color-button);
|
||||||
color: var(--text-button-color);
|
color: var(--text-button-color);
|
||||||
border-radius: #{$border-radius-small};
|
border-radius: #{$border-radius-large};
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
outline: none;
|
outline: none;
|
||||||
border: none;
|
border: none;
|
||||||
|
@ -832,10 +828,10 @@
|
||||||
transform: translateX(4px);
|
transform: translateX(4px);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--accent-color);
|
background: var(--background-color-accent);
|
||||||
|
|
||||||
path {
|
path {
|
||||||
stroke: var(--primary-color);
|
stroke: var(--text-button-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1003,10 +999,10 @@
|
||||||
border-radius: 8px 0 0 8px;
|
border-radius: 8px 0 0 8px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: var(--accent-color);
|
background: var(--background-color-accent);
|
||||||
|
|
||||||
path {
|
path {
|
||||||
stroke: var(--primary-color);
|
stroke: var(--text-button-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1067,7 +1063,13 @@
|
||||||
.dropdown-content-container {
|
.dropdown-content-container {
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
}
|
}
|
||||||
|
.value-field-container {
|
||||||
|
padding: 6px;
|
||||||
|
.dropdown {
|
||||||
|
min-width: 44px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
.input-range-container {
|
.input-range-container {
|
||||||
.input-container {
|
.input-container {
|
||||||
width: 75%;
|
width: 75%;
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
// Main Container
|
// Main Container
|
||||||
.realTime-viz {
|
.realTime-viz {
|
||||||
background: #131313;
|
|
||||||
box-shadow: $box-shadow-medium;
|
|
||||||
width: calc(100% - (320px + 270px + 90px));
|
width: calc(100% - (320px + 270px + 90px));
|
||||||
height: calc(100% - (250px));
|
height: calc(100% - (250px));
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -12,8 +10,8 @@
|
||||||
left: calc(270px + 45px);
|
left: calc(270px + 45px);
|
||||||
transform: translate(0, -50%);
|
transform: translate(0, -50%);
|
||||||
border-radius: #{$border-radius-medium};
|
border-radius: #{$border-radius-medium};
|
||||||
transition: all 0.2s;
|
z-index: 2;
|
||||||
z-index: #{$z-index-default};
|
pointer-events: none;
|
||||||
|
|
||||||
.realTime-viz-wrapper {
|
.realTime-viz-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -39,10 +37,6 @@
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scene-container {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -74,6 +68,8 @@
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
transform: translate(-50%, -10%);
|
transform: translate(-50%, -10%);
|
||||||
transition: transform 0.5s linear;
|
transition: transform 0.5s linear;
|
||||||
|
pointer-events: all;
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -367,6 +363,7 @@
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
transition: transform 0.3s ease;
|
transition: transform 0.3s ease;
|
||||||
box-shadow: #{$box-shadow-medium};
|
box-shadow: #{$box-shadow-medium};
|
||||||
|
pointer-events: all;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
stroke: var(--icon-default-color) !important;
|
stroke: var(--icon-default-color) !important;
|
||||||
|
@ -428,8 +425,6 @@
|
||||||
stroke: #f65648;
|
stroke: #f65648;
|
||||||
strokeWidth: 1.3;
|
strokeWidth: 1.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -778,17 +773,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.panel-content {
|
.panel-content {
|
||||||
background: var(--background-color);
|
background: var(--background-color);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* RIGHT */
|
/* RIGHT */
|
||||||
.panel-content.right-opening {
|
.panel-content.right-opening {
|
||||||
animation: rightExpand 0.5s ease-in-out forwards;
|
animation: rightExpand 0.5s ease-in-out forwards;
|
||||||
|
@ -913,9 +901,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Add button
|
// Add button
|
||||||
|
|
||||||
.extra-Bs-addopening {
|
.extra-Bs-addopening {
|
||||||
|
@ -926,7 +911,6 @@
|
||||||
animation: slideUp 0.3s ease forwards;
|
animation: slideUp 0.3s ease forwards;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@keyframes slideDown {
|
@keyframes slideDown {
|
||||||
from {
|
from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
Loading…
Reference in New Issue