feat(versioning): add version history management functionality

- Introduced Version and VersionHistory types for version management.
- Enhanced shortcut key handling to create new versions and manage version visibility.
- Implemented API calls for creating and retrieving version history.
- Added Zustand store for managing version history state, including version selection and updates.
This commit is contained in:
2025-06-19 14:59:53 +05:30
parent 663ef63f6d
commit 8c6c068b17
93 changed files with 2697 additions and 2648 deletions

View File

@@ -58,7 +58,6 @@ const DashboardHome: React.FC = () => {
};
const handleDeleteProject = async (projectId: any) => {
console.log("projectId:delete ", projectId);
try {
//API for delete project
// const deletedProject = await deleteProject(
@@ -109,7 +108,6 @@ const DashboardHome: React.FC = () => {
projectUuid: projectId,
projectName,
};
console.log('projectId: ', projectId);
projectSocket.emit("v1:project:Duplicate", duplicateRecentProjectData);
};

View File

@@ -22,9 +22,7 @@ interface DiscardedProjects {
}
const DashboardTrash: React.FC = () => {
const [discardedProjects, setDiscardedProjects] = useState<DiscardedProjects>(
{}
);
const [discardedProjects, setDiscardedProjects] = useState<DiscardedProjects>({});
const [isSearchActive, setIsSearchActive] = useState(false);
const { userId, organization } = getUserData();
const { projectSocket } = useSocketStore();

View File

@@ -8,15 +8,21 @@ import {
CurserRightIcon,
} from "../icons/LogIcons";
import ShortcutHelper from "./shortcutHelper";
import { useShortcutStore } from "../../store/builder/store";
import useVersionHistoryVisibleStore, { useShortcutStore } from "../../store/builder/store";
import { usePlayButtonStore } from "../../store/usePlayButtonStore";
import { useVersionHistoryStore } from "../../store/builder/useVersionHistoryStore";
import useModuleStore, { useSubModuleStore } from "../../store/useModuleStore";
const Footer: React.FC = () => {
const { logs, setIsLogListVisible } = useLogger();
const lastLog = logs.length > 0 ? logs[logs.length - 1] : null;
const { setActiveModule } = useModuleStore();
const { setSubModule } = useSubModuleStore();
const { setVersionHistoryVisible } = useVersionHistoryVisibleStore();
const { isPlaying } = usePlayButtonStore();
const { showShortcuts, setShowShortcuts } = useShortcutStore();
const { selectedVersion } = useVersionHistoryStore();
return (
<div className="footer-container">
@@ -61,8 +67,12 @@ const Footer: React.FC = () => {
)}
</button>
</div>
<div className="version">
V 0.01
<div className="version" onClick={() => {
setVersionHistoryVisible(true);
setSubModule("properties");
setActiveModule('builder');
}}>
{(selectedVersion?.version) ?? 'v 0.0.0'}
<div className="icon">
<HelpIcon />
</div>
@@ -72,11 +82,10 @@ const Footer: React.FC = () => {
{!isPlaying && (
<div
className={`shortcut-helper-overlay ${
showShortcuts ? "visible" : ""
}`}
className={`shortcut-helper-overlay ${showShortcuts ? "visible" : ""
}`}
>
<ShortcutHelper setShowShortcuts={setShowShortcuts}/>
<ShortcutHelper setShowShortcuts={setShowShortcuts} />
</div>
)}
</div>

View File

@@ -13,7 +13,7 @@ import { useToggleStore } from "../../../store/useUIToggleStore";
import Visualization from "./visualization/Visualization";
import Analysis from "./analysis/Analysis";
import Simulations from "./simulation/Simulations";
import useVersionHistoryStore, {
import useVersionHistoryVisibleStore, {
useSaveVersion,
useSelectedFloorItem,
useToolMode,
@@ -38,7 +38,7 @@ const SideBarRight: React.FC = () => {
const { selectedFloorItem } = useSelectedFloorItem();
const { selectedEventData } = useSelectedEventData();
const { selectedEventSphere } = useSelectedEventSphere();
const { viewVersionHistory, setVersionHistory } = useVersionHistoryStore();
const { viewVersionHistory, setVersionHistoryVisible } = useVersionHistoryVisibleStore();
const { isVersionSaved } = useSaveVersion();
// Reset activeList whenever activeModule changes
@@ -81,7 +81,7 @@ const SideBarRight: React.FC = () => {
}`}
onClick={() => {
setSubModule("properties");
setVersionHistory(false);
setVersionHistoryVisible(false);
}}
>
<div className="tooltip">properties</div>
@@ -96,7 +96,7 @@ const SideBarRight: React.FC = () => {
}`}
onClick={() => {
setSubModule("simulations");
setVersionHistory(false);
setVersionHistoryVisible(false);
}}
>
<div className="tooltip">simulations</div>
@@ -108,7 +108,7 @@ const SideBarRight: React.FC = () => {
}`}
onClick={() => {
setSubModule("mechanics");
setVersionHistory(false);
setVersionHistoryVisible(false);
}}
>
<div className="tooltip">mechanics</div>
@@ -120,7 +120,7 @@ const SideBarRight: React.FC = () => {
}`}
onClick={() => {
setSubModule("analysis");
setVersionHistory(false);
setVersionHistoryVisible(false);
}}
>
<div className="tooltip">analysis</div>

View File

@@ -1,148 +1,125 @@
import React, { useState } from "react";
import {
AddIcon,
ArrowIcon,
CloseIcon,
KebabIcon,
LocationIcon,
AddIcon,
ArrowIcon,
CloseIcon,
KebabIcon,
LocationIcon,
} from "../../../icons/ExportCommonIcons";
import RenameInput from "../../../ui/inputs/RenameInput";
import { useVersionStore } from "../../../../store/builder/store";
import { generateUniqueId } from "../../../../functions/generateUniqueId";
import { getUserData } from "../../../../functions/getUserData";
import { useParams } from "react-router-dom";
import { useVersionHistoryStore } from "../../../../store/builder/useVersionHistoryStore";
import { useSubModuleStore } from "../../../../store/useModuleStore";
import useVersionHistoryVisibleStore from "../../../../store/builder/store";
const VersionHistory = () => {
const { userName, userId, organization, email } = getUserData();
const { versions, addVersion, setVersions, updateVersion } =
useVersionStore();
const [selectedVersion, setSelectedVersion] = useState(
versions.length > 0 ? versions[0] : null
);
const { userName } = getUserData();
const { setSubModule } = useSubModuleStore();
const { setVersionHistoryVisible } = useVersionHistoryVisibleStore();
const { versionHistory, addVersion, selectedVersion, setSelectedVersion, setCreateNewVersion } = useVersionHistoryStore();
const { projectId } = useParams();
const addNewVersion = () => {
const newVersion = {
id: generateUniqueId(),
versionLabel: `v${versions.length + 1}.0`,
versionName: "",
timestamp: new Date().toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "2-digit",
}),
savedBy: userName ?? "Anonymous",
const addNewVersion = () => {
setCreateNewVersion(true);
};
const newVersions = [newVersion, ...versions];
addVersion(newVersion);
setSelectedVersion(newVersion);
setVersions(newVersions);
};
const handleSelectVersion = (version: any) => {
const handleSelectVersion = (version: any) => {
setSelectedVersion(version);
const reordered = [version, ...versions.filter((v) => v.id !== version.id)];
setVersions(reordered);
};
};
const handleVersionNameChange = (newName: string, versionId: string) => {
const updated = versions.map((v) =>
v.id === versionId ? { ...v, versionName: newName } : v
);
setVersions(updated);
updateVersion(versionId, { versionName: newName });
};
const handleVersionNameChange = (newName: string, versionId: string) => {
return (
<div className="version-history-container">
{/* Header */}
<div className="version-history-header">
<div className="version-history-title">Version History</div>
<div className="version-history-icons">
<button
id="add-version"
className="icon add-icon"
onClick={addNewVersion}
>
<AddIcon />
</button>
<div id="version-kebab" className="icon kebab-icon">
<KebabIcon />
</div>
<div id="version-close" className="icon close-icon">
<CloseIcon />
</div>
</div>
</div>
};
{/* Shortcut Info */}
<div className="version-history-shortcut-info">
<div className="info-icon">i</div>
<div className="shortcut-text">
Press Ctrl + Alt + S to add to version history while editing
</div>
</div>
{/* Current Version Display */}
{selectedVersion && (
<div className="version-history-location">
<div className="location-label">
<LocationIcon />
</div>
<div className="location-details">
<div className="current-version">
Current Version ({selectedVersion.versionLabel})
</div>
<div className="saved-history-count">
{versions.length} Saved History
</div>
</div>
</div>
)}
{/* Versions List */}
<div className="saved-versions-list">
{versions.length === 0 ? (
<div className="no-versions-message">No saved versions</div>
) : (
versions.map((version) => (
<button
key={version.id}
className="saved-version"
onClick={() => handleSelectVersion(version)}
>
<div className="version-name">{version.versionLabel}</div>
<div className="version-details">
<div className="details">
<span className="timestamp">
{version.versionName ? (
<RenameInput
value={version.versionName}
onRename={(newName) =>
handleVersionNameChange(newName, version.id)
}
/>
) : (
<RenameInput
value={version.timestamp}
onRename={(newName) =>
handleVersionNameChange(newName, version.id)
}
/>
)}
</span>
<span className="saved-by">
<div className="user-profile">{version.savedBy[0]}</div>
<div className="user-name">{version.savedBy}</div>
</span>
return (
<div className="version-history-container">
{/* Header */}
<div className="version-history-header">
<div className="version-history-title">Version History</div>
<div className="version-history-icons">
<button
id="add-version"
className="icon add-icon"
onClick={addNewVersion}
>
<AddIcon />
</button>
<div id="version-kebab" className="icon kebab-icon">
<KebabIcon />
</div>
<div
id="version-close"
className="icon close-icon"
onClick={() => {
setSubModule("properties");
setVersionHistoryVisible(false);
}}
>
<CloseIcon />
</div>
</div>
<ArrowIcon />
</div>
</button>
))
)}
</div>
</div>
);
</div>
{/* Shortcut Info */}
<div className="version-history-shortcut-info">
<div className="info-icon">i</div>
<div className="shortcut-text">
Press Ctrl + Alt + S to add to version history while editing
</div>
</div>
{/* Current Version Display */}
{selectedVersion && (
<div className="version-history-location">
<div className="location-label">
<LocationIcon />
</div>
<div className="location-details">
<div className="current-version">
Current Version ({selectedVersion.version})
</div>
<div className="saved-history-count">
{versionHistory.length} Saved History
</div>
</div>
</div>
)}
{/* Versions List */}
<div className="saved-versions-list">
{versionHistory.length === 0 ? (
<div className="no-versions-message">No saved versions</div>
) : (
versionHistory.map((version) => (
<button
key={version.versionId}
className="saved-version"
onClick={() => handleSelectVersion(version)}
>
<div className="version-name">v {version.version}</div>
<div className="version-details">
<div className="details">
<span className="timestamp">
<RenameInput
value={version.versionName ? version.versionName : version.timeStamp}
onRename={(newName) =>
handleVersionNameChange(newName, version.versionId)
}
/>
</span>
<span className="saved-by">
<div className="user-profile">{version.createdBy[0]}</div>
<div className="user-name">{version.createdBy}</div>
</span>
</div>
<ArrowIcon />
</div>
</button>
))
)}
</div>
</div>
);
};
export default VersionHistory;

View File

@@ -1,148 +1,88 @@
import React, { useState, useEffect, useRef } from "react";
import { useVersionStore } from "../../../../store/builder/store";
import { useEffect, useState } from "react";
import {
CloseIcon,
FinishEditIcon,
RenameVersionIcon,
SaveIcon,
SaveVersionIcon,
} from "../../../icons/ExportCommonIcons";
import RenderOverlay from "../../../templates/Overlay";
import { useVersionHistoryStore } from "../../../../store/builder/useVersionHistoryStore";
import { createVersionApi } from "../../../../services/factoryBuilder/versionControl/addVersionApi";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../../functions/getUserData";
const VersionSaved = () => {
const { versions, updateVersion } = useVersionStore();
const [isEditing, setIsEditing] = useState(false);
const [shouldDismiss, setShouldDismiss] = useState(false);
const [showNotification, setShowNotification] = useState(false);
const [newName, setNewName] = useState("");
const { versionHistory, addVersion, createNewVersion, setCreateNewVersion } = useVersionHistoryStore();
const [newName, setNewName] = useState(new Date().toLocaleString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
hour: "numeric",
minute: "2-digit",
}));
const [description, setDescription] = useState("");
const [showEditedFinish, setShowEditedFinish] = useState(false);
const [editedVersionName, setEditedVersionName] = useState("");
const prevVersionCount = useRef(versions.length);
const dismissTimerRef = useRef<NodeJS.Timeout | null>(null);
const [showSaveFinish, setSaveFinish] = useState(false);
const { projectId } = useParams();
const { userId } = getUserData();
const latestVersion = versions?.[0];
const latestVersion = versionHistory?.[0];
useEffect(() => {
return () => {
if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current);
};
}, []);
useEffect(() => {
if (versions.length > prevVersionCount.current && latestVersion) {
setShowNotification(true);
setShouldDismiss(false);
setIsEditing(false);
setNewName(latestVersion.versionName ?? "");
setDescription(latestVersion.description ?? "");
setEditedVersionName(latestVersion.versionName ?? ""); // Initialize editedVersionName
if (!isEditing) {
startDismissTimer();
}
prevVersionCount.current = versions.length;
} else if (versions.length < prevVersionCount.current) {
prevVersionCount.current = versions.length;
if (createNewVersion) {
const defaultName = new Date().toLocaleString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
hour: "numeric",
minute: "2-digit",
});
setNewName(defaultName);
setDescription("");
}
}, [versions, isEditing, latestVersion]);
}, [createNewVersion]);
const startDismissTimer = (delay = 5000) => {
if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current);
dismissTimerRef.current = setTimeout(() => {
setShouldDismiss(true);
}, delay);
};
const handleSave = () => {
if (!latestVersion || !projectId) return;
useEffect(() => {
if (shouldDismiss) {
const timer = setTimeout(() => setShowNotification(false), 200);
return () => clearTimeout(timer);
}
}, [shouldDismiss]);
const updatedName = (newName.trim() || latestVersion.versionName) ?? latestVersion.timeStamp;
const updatedDescription = (description.trim() || latestVersion.versionName) ?? latestVersion.timeStamp;
const handleEditName = () => {
if (!latestVersion) return;
createVersionApi(projectId, userId, latestVersion.versionId, updatedName, updatedDescription).then((data) => {
setSaveFinish(true);
setCreateNewVersion(false);
setIsEditing(true);
setNewName(latestVersion.versionName ?? "");
setDescription(latestVersion.description ?? "");
if (dismissTimerRef.current) {
clearTimeout(dismissTimerRef.current);
dismissTimerRef.current = null;
}
};
addVersion({
version: data.version,
versionId: data.versionId,
versionName: data.versionName,
versionDescription: data.description,
timeStamp: data.createdAt,
createdBy: data.createdBy.userName
})
const handleFinishEdit = () => {
if (!latestVersion) return;
const updatedName =
(newName.trim() || latestVersion.versionName) ?? latestVersion.timestamp;
updateVersion(latestVersion.id, {
versionName: updatedName,
description,
});
setEditedVersionName(updatedName);
setIsEditing(false);
setShowEditedFinish(true);
setTimeout(() => {
setShowEditedFinish(false);
}, 5000);
startDismissTimer();
setTimeout(() => {
setSaveFinish(false);
}, 3000);
}).catch((err) => {
setSaveFinish(false);
setCreateNewVersion(false);
})
};
const handleCancel = () => {
setIsEditing(false);
startDismissTimer();
setSaveFinish(false);
setCreateNewVersion(false);
};
const handleClose = () => {
setShouldDismiss(true);
if (dismissTimerRef.current) clearTimeout(dismissTimerRef.current);
};
if (!showNotification || !latestVersion) return null;
if (!latestVersion) return null;
return (
<div className={`versionSaved ${shouldDismiss ? "dismissing" : ""}`}>
{!isEditing && !showEditedFinish && (
<div className="versionSaved-wrapper">
<div className="version-header">
<div className="header-wrapper">
<div className="icon">
<SaveIcon />
</div>
<span>Saved New Version</span>
</div>
<button className="close-btn" onClick={handleClose}>
<CloseIcon />
</button>
</div>
<div className="version-details">
<SaveVersionIcon />
<div className="details">
<div className="details-wrapper">
New Version Created {latestVersion.versionLabel}{" "}
{latestVersion.timestamp.toUpperCase()}
</div>
<button onClick={handleEditName}>Edit name</button>
</div>
</div>
</div>
)}
{isEditing && (
<div className={`versionSaved`}>
{createNewVersion &&
<RenderOverlay>
<div className="edit-version-popup-wrapper">
<div className="details-wrapper-popup-container">
<div className="header-wrapper">
<RenameVersionIcon />
<div className="label">Rename Version</div>
<div className="label">Create Version</div>
</div>
<div className="details-wrapper">
<div className="version-name">
@@ -153,13 +93,10 @@ const VersionSaved = () => {
placeholder="Enter new version name"
/>
<div className="label">
by @{latestVersion.savedBy}{" "}
{new Date(latestVersion.timestamp).toLocaleString("en-US", {
month: "short",
day: "numeric",
year: "2-digit",
hour: "numeric",
minute: "2-digit",
by @{latestVersion.createdBy}{" "}{new Date(latestVersion.timeStamp).toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "2-digit",
})}
</div>
</div>
@@ -176,16 +113,16 @@ const VersionSaved = () => {
<button className="cancel" onClick={handleCancel}>
Cancel
</button>
<button className="save" onClick={handleFinishEdit}>
<button className="save" onClick={handleSave}>
Save
</button>
</div>
</div>
</div>
</RenderOverlay>
)}
}
{showEditedFinish && (
{showSaveFinish && (
<RenderOverlay>
<div className="finishEdit-version-popup-wrapper">
<div className="finishEdit-wrapper-popup-container">
@@ -193,7 +130,7 @@ const VersionSaved = () => {
<FinishEditIcon />
</div>
<div className="versionname">
{editedVersionName || latestVersion.versionName}
{newName.trim()}
</div>
<div className="success-message">Saved Successfully!</div>
</div>

View File

@@ -10,114 +10,99 @@ import { updateProject } from "../../services/dashboard/updateProject";
import { getUserData } from "../../functions/getUserData";
const FileMenu: React.FC = () => {
const [openMenu, setOpenMenu] = useState(false);
const containerRef = useRef<HTMLButtonElement>(null);
let clickTimeout: NodeJS.Timeout | null = null;
const { projectName, setProjectName } = useProjectName();
const { dashBoardSocket } = useSocketStore();
const { projectId } = useParams();
const { userId, organization, email } = getUserData();
const [openMenu, setOpenMenu] = useState(false);
const containerRef = useRef<HTMLButtonElement>(null);
let clickTimeout: NodeJS.Timeout | null = null;
const { projectName, setProjectName } = useProjectName();
const { dashBoardSocket } = useSocketStore();
const { projectId } = useParams();
const { userId, organization, email } = getUserData();
const handleClick = () => {
if (clickTimeout) return;
setOpenMenu((prev) => !prev);
clickTimeout = setTimeout(() => {
clickTimeout = null;
}, 800);
};
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (
containerRef.current &&
!containerRef.current.contains(event.target as Node)
) {
setOpenMenu(false);
}
const handleClick = () => {
if (clickTimeout) return;
setOpenMenu((prev) => !prev);
clickTimeout = setTimeout(() => {
clickTimeout = null;
}, 800);
};
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (
containerRef.current &&
!containerRef.current.contains(event.target as Node)
) {
setOpenMenu(false);
}
};
// project
// const [projectName, setProjectName] = useState("Demo Project");
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
// Load project name from localStorage on mount
// useEffect(() => {
// const savedName = localStorage.getItem("projectName");
// if (savedName) {
// setProjectName(savedName);
// }
// }, []);
const handleProjectRename = async (projectName: string) => {
setProjectName(projectName);
if (!projectId) return
// const handleProjectRename = (newName: string) => {
// setProjectName(newName);
// localStorage.setItem("projectName", newName);
// };
const handleProjectRename = async (projectName: string) => {
setProjectName(projectName);
if (!projectId) return
// localStorage.setItem("projectName", newName);
try {
// localStorage.setItem("projectName", newName);
if (!email || !userId) {
try {
return;
}
const projects = await getAllProjects(
userId, organization
);
// console.log('projects: ', projects);
let projectUuid = projects.Projects.find((val: any) => val.projectUuid === projectId || val._id
=== projectId)
const updateProjects = {
projectId: projectUuid,
organization,
userId,
projectName,
thumbnail: undefined
}
if (!email || !userId) return;
// if (dashBoardSocket) {
// const handleResponse = (data: any) => {
// console.log('Project update response:', data);
// dashBoardSocket.off("v1-project:response:update", handleResponse); // Clean up
// };
// dashBoardSocket.on("v1-project:response:update", handleResponse);
// dashBoardSocket.emit("v1:project:update", updateProjects);
// }
const projects = await getAllProjects(userId, organization);
// console.log('projects: ', projects);
let projectUuid = projects.Projects.find((val: any) => val.projectUuid === projectId || val._id === projectId)
//API for projects rename
const updatedProjectName = await updateProject(
projectId,
userId,
organization,
undefined,
projectName
);
//
} catch (error) { }
};
return (
<button
id="project-dropdown-button"
className="project-dropdowm-container"
ref={containerRef}
onClick={handleClick}
>
<div className="project-name">
<div className="icon">
<ProjectIcon />
</div>
<RenameInput value={projectName} onRename={handleProjectRename} />
</div>
<div className="more-options-button">
<ArrowIcon />
{openMenu && <MenuBar setOpenMenu={setOpenMenu} />}
</div>
</button>
);
const updateProjects = {
projectId: projectUuid,
organization,
userId,
projectName,
thumbnail: undefined
}
// if (dashBoardSocket) {
// const handleResponse = (data: any) => {
// console.log('Project update response:', data);
// dashBoardSocket.off("v1-project:response:update", handleResponse); // Clean up
// };
// dashBoardSocket.on("v1-project:response:update", handleResponse);
// dashBoardSocket.emit("v1:project:update", updateProjects);
// }
//API for projects rename
const updatedProjectName = await updateProject(
projectId,
userId,
organization,
undefined,
projectName
);
//
} catch (error) {
console.error("Error updating project name:", error);
}
};
return (
<button
id="project-dropdown-button"
className="project-dropdowm-container"
ref={containerRef}
onClick={handleClick}
>
<div className="project-name">
<div className="icon">
<ProjectIcon />
</div>
<RenameInput value={projectName} onRename={handleProjectRename} />
</div>
<div className="more-options-button">
<ArrowIcon />
{openMenu && <MenuBar setOpenMenu={setOpenMenu} />}
</div>
</button>
);
};
export default FileMenu;

View File

@@ -12,7 +12,7 @@ import useVersionHistoryStore from "../../store/builder/store";
const ModuleToggle: React.FC = () => {
const { activeModule, setActiveModule } = useModuleStore();
const { setToggleUI } = useToggleStore();
const { setVersionHistory } = useVersionHistoryStore();
const { setVersionHistoryVisible } = useVersionHistoryStore();
return (
<div className="module-toggle-container">
@@ -21,7 +21,7 @@ const ModuleToggle: React.FC = () => {
className={`module-list ${activeModule === "builder" ? "active" : ""}`}
onClick={() => {
setActiveModule("builder");
setVersionHistory(false);
setVersionHistoryVisible(false);
setToggleUI(
localStorage.getItem("navBarUiLeft")
? localStorage.getItem("navBarUiLeft") === "true"
@@ -44,7 +44,7 @@ const ModuleToggle: React.FC = () => {
}`}
onClick={() => {
setActiveModule("simulation");
setVersionHistory(false);
setVersionHistoryVisible(false);
setToggleUI(
localStorage.getItem("navBarUiLeft")
? localStorage.getItem("navBarUiLeft") === "true"
@@ -67,7 +67,7 @@ const ModuleToggle: React.FC = () => {
}`}
onClick={() => {
setActiveModule("visualization");
setVersionHistory(false);
setVersionHistoryVisible(false);
setToggleUI(
localStorage.getItem("navBarUiLeft")
? localStorage.getItem("navBarUiLeft") === "true"
@@ -88,7 +88,7 @@ const ModuleToggle: React.FC = () => {
className={`module-list ${activeModule === "market" ? "active" : ""}`}
onClick={() => {
setActiveModule("market");
setVersionHistory(false);
setVersionHistoryVisible(false);
setToggleUI(false, false);
}}
>

View File

@@ -2,13 +2,12 @@ import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import { ArrowIcon } from "../../icons/ExportCommonIcons";
import { toggleTheme } from "../../../utils/theme";
import useVersionHistoryStore, {
import useVersionHistoryVisibleStore, {
useShortcutStore,
useVersionStore,
} from "../../../store/builder/store";
import { useSubModuleStore } from "../../../store/useModuleStore";
import { generateUniqueId } from "../../../functions/generateUniqueId";
import useModuleStore, { useSubModuleStore } from "../../../store/useModuleStore";
import { getUserData } from "../../../functions/getUserData";
import { useVersionHistoryStore } from "../../../store/builder/useVersionHistoryStore";
interface MenuBarProps {
setOpenMenu: (isOpen: boolean) => void;
@@ -28,11 +27,11 @@ const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
const navigate = useNavigate();
const [activeMenu, setActiveMenu] = useState<string | null>(null);
const [activeSubMenu, setActiveSubMenu] = useState<string | null>(null);
const [selectedItems, setSelectedItems] = useState<Record<string, boolean>>(
{}
);
const [selectedItems, setSelectedItems] = useState<Record<string, boolean>>({});
const { setVersionHistory } = useVersionHistoryStore();
const { setCreateNewVersion } = useVersionHistoryStore();
const { setVersionHistoryVisible } = useVersionHistoryVisibleStore();
const { setActiveModule } = useModuleStore();
const { setSubModule } = useSubModuleStore();
const { showShortcuts, setShowShortcuts } = useShortcutStore();
@@ -60,35 +59,21 @@ const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
setShowShortcuts(!showShortcuts);
}
function handleVersionCreation() {
setCreateNewVersion(true);
setVersionHistoryVisible(true);
setSubModule("properties");
setActiveModule('builder');
}
const menus: Record<string, MenuItem[]> = {
File: [
{ label: "New File", shortcut: "Ctrl + N" },
{ label: "Open Local File", shortcut: "Ctrl + O" },
{
label: "Save Version",
action: () => {
const versionStore = useVersionStore.getState();
const versionCount = versionStore.versions.length;
const newVersion = {
id: generateUniqueId(),
versionLabel: `v${versionCount + 1}.0`,
timestamp: `${new Date().toLocaleTimeString("en-US", {
hour: "numeric",
minute: "2-digit",
hour12: true,
})} ${new Date().toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "2-digit",
})}`,
savedBy: userName ?? "Anonymous",
};
console.log("newVersion: ", newVersion);
versionStore.addVersion(newVersion);
},
shortcut: "Ctrl + Alt + S",
action: handleVersionCreation,
},
{ label: "Make a Copy" },
{ label: "Share" },
@@ -237,8 +222,9 @@ const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
setActiveSubMenu(null);
}}
onClick={() => {
setVersionHistory(true);
setVersionHistoryVisible(true);
setSubModule("properties");
setActiveModule('builder');
}}
>
<div className="menu-button">Version history</div>

View File

@@ -105,7 +105,7 @@ export default function Builder() {
const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
const { projectId } = useParams();
const { setHoveredPoint } = useBuilderStore();
const { userId, organization, email } = getUserData();
const { userId, organization } = getUserData();
// const loader = new GLTFLoader();
// const dracoLoader = new DRACOLoader();

View File

@@ -50,7 +50,6 @@ const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoin
// Load data from localStorage if available
getLines(organization, projectId).then((data) => {
// console.log('data: ', data);
const Lines: Types.Lines = objectLinesToArray(data);

View File

@@ -23,10 +23,6 @@ const MarketPlace = () => {
const [filteredModels, setFilteredModels] = useState<ModelData[]>([]);
const [isLoading, setisLoading] = useState<boolean>(false); // Loading state
useEffect(() => {
echo.log("opend market place");
}, []);
useEffect(() => {
const filteredAssets = async () => {
setisLoading(true);

View File

@@ -44,7 +44,6 @@ function Products() {
const id = THREE.MathUtils.generateUUID();
const name = 'Product 1';
addProduct(name, id);
console.log(name, id, projectId);
upsertProductOrEventApi({
productName: name,
productUuid: id,

View File

@@ -14,7 +14,7 @@ import { useEventsStore } from "../store/simulation/useEventsStore";
const Dashboard: React.FC = () => {
const [activeTab, setActiveTab] = useState<string>("Home");
const { socket } = useSocketStore();
const { userId, organization, email, userName } = getUserData();
const { organization, email } = getUserData();
const { clearProducts } = useProductStore();
const { clearEvents } = useEventsStore();

View File

@@ -25,6 +25,8 @@ import ComparisonSceneProvider from "../components/layout/scenes/ComparisonScene
import MainSceneProvider from "../components/layout/scenes/MainSceneProvider";
import { getUserData } from "../functions/getUserData";
import { SceneProvider } from "../modules/scene/sceneContext";
import { getVersionHistoryApi } from "../services/factoryBuilder/versionControl/getVersionHistoryApi";
import { useVersionHistoryStore } from "../store/builder/useVersionHistoryStore";
const Project: React.FC = () => {
let navigate = useNavigate();
@@ -42,6 +44,7 @@ const Project: React.FC = () => {
const { userId, email, organization, userName } = getUserData();
const { selectedUser } = useSelectedUserStore();
const { isLogListVisible } = useLogger();
const { setVersions, setSelectedVersion } = useVersionHistoryStore();
useEffect(() => {
if (!email || !userId) {
@@ -52,14 +55,31 @@ const Project: React.FC = () => {
getAllProjects(userId, organization).then((projects) => {
const filterProject = projects?.Projects.find((val: any) => val.projectUuid === projectId || val._id === projectId)
setProjectName(filterProject.projectName)
viewProject(organization, filterProject._id, userId).then((viewedProject) => {
});
});
}, []);
useEffect(() => {
if (!projectId) return;
getVersionHistoryApi(projectId).then((data) => {
const versions: VersionHistory = [];
data.versions.forEach((version: any) => {
versions.push({
version: version.version,
versionId: version.versionId,
versionName: version.versionName,
versionDescription: version.description,
timeStamp: version.createdAt,
createdBy: version.createdBy.userName
})
})
setVersions(versions);
setSelectedVersion(versions[0])
})
}, [projectId])
useEffect(() => {
if (!isVersionSaved) {
setToggleUI(true, true);

View File

@@ -22,9 +22,9 @@ export const createProject = async (projectUuid: string, userId: string, thumbna
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -31,9 +31,9 @@ export const deleteProject = async (
} catch (error) {
echo.error("Failed to clean pannel");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -30,9 +30,9 @@ export const duplicateProject = async (
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -22,6 +22,6 @@ export const getAllProjects = async (userId: string, organization: string) => {
return await response.json();
} catch (error: any) {
echo.error("Failed to get asset image");
throw new Error(error.message);
console.log(error.message);
}
};

View File

@@ -19,9 +19,9 @@ export const projectTutorial = async () => {
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -22,6 +22,6 @@ export const recentlyViewed = async (organization: string, userId: string) => {
return await response.json();
} catch (error: any) {
console.error("Failed to get project");
throw new Error(error.message);
console.log(error.message);
}
};

View File

@@ -30,9 +30,9 @@ export const searchProject = async (
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -28,9 +28,9 @@ export const trashSearchProject = async (
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -1,5 +1,4 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
// let url_Backend_dwinzo = `http://192.168.0.102:5000`;
export const updateProject = async (
projectId: string,
@@ -40,9 +39,9 @@ export const updateProject = async (
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -26,6 +26,6 @@ export const viewProject = async (
return await response.json();
} catch (error: any) {
console.error("Failed to get asset image:", error);
throw new Error(error.message);
console.log(error.message);
}
};

View File

@@ -27,9 +27,9 @@ export const createAisleApi = async (
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -21,9 +21,9 @@ export const deleteAisleApi = async (aisleUuid: string, projectId: string) => {
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -23,6 +23,6 @@ export const getAisleApi = async (projectId: string) => {
return await response.json();
} catch (error: any) {
console.error("Failed to get asset image:", error);
throw new Error(error.message);
console.log(error.message);
}
};

View File

@@ -19,6 +19,6 @@ export const getAssetImages = async (cursor?: string) => {
return await response.json();
} catch (error: any) {
echo.error("Failed to get asset image");
throw new Error(error.message);
console.log(error.message);
}
};

View File

@@ -21,9 +21,9 @@ export const getAssetModel = async (modelId: string) => {
} catch (error) {
echo.error("Failed to get asset model");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -15,6 +15,6 @@ export const getCategoryAsset = async (categoryName: any) => {
return result;
} catch (error: any) {
echo.error("Failed to get category asset");
throw new Error(error.message);
console.log(error.message);
}
};

View File

@@ -26,9 +26,9 @@ export const deleteFloorItem = async (
} catch (error) {
echo.error("Failed to delete floor item");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -27,9 +27,9 @@ export const getFloorAssets = async (organization: string, projectId?: string) =
} catch (error) {
echo.error("Failed to get floor asset");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -42,9 +42,9 @@ export const setFloorItemApi = async (
} catch (error) {
echo.error("Failed to set floor items");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -26,9 +26,9 @@ export const deleteWallItem = async (
} catch (error) {
echo.error("Failed to delete wall items");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -25,9 +25,9 @@ export const getWallItems = async (organization: string,projectId?:string) => {
} catch (error) {
echo.error("Failed to get wall items");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -39,9 +39,9 @@ export const setWallItem = async (
} catch (error) {
echo.error("Failed to set wall items");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -28,9 +28,9 @@ export const getCamera = async (organization: string, userId: string, projectId?
} catch (error) {
echo.error("Failed to get camera");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -31,9 +31,9 @@ export const setCamera = async (
} catch (error) {
echo.error("Failed to set camera");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -24,9 +24,9 @@ export default async function getActiveUsersData(organization: string) {
} catch (error) {
echo.error("Failed to get active users");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
}

View File

@@ -24,9 +24,9 @@ export default async function fetchShareUsers(organization: string) {
} catch (error) {
echo.error("Failed to get user API");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
}

View File

@@ -23,9 +23,9 @@ export default async function giveCollabAccess(
} catch (error) {
echo.error("Failed to give collab access");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
}

View File

@@ -26,9 +26,9 @@ export const findEnvironment = async (organization: string, userId: string, proj
} catch (error) {
echo.error("Failed to find env");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -46,9 +46,9 @@ export const setEnvironment = async (
} catch (error) {
echo.error("Failed to set env");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -19,9 +19,9 @@ export const deleteLayer = async (organization: string, layer: number) => {
} catch (error) {
echo.error("Failed to delete line");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -19,9 +19,9 @@ export const deleteLineApi = async (organization: string, line: Object) => {
} catch (error) {
echo.error("Failed to delete line");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -19,9 +19,9 @@ export const deletePointApi = async (organization: string, uuid: string) => {
} catch (error) {
echo.error("Failed to delete point");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -1,6 +1,6 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const getLines = async (organization: string,projectId?:string) => {
export const getLines = async (organization: string, projectId?: string) => {
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/V1/lines/${projectId}`,
@@ -25,9 +25,9 @@ export const getLines = async (organization: string,projectId?:string) => {
} catch (error) {
echo.error("Failed to get Lines");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -24,9 +24,9 @@ export const setLine = async (
} catch (error) {
echo.error("Failed to set line");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -23,9 +23,9 @@ export const updatePoint = async (
} catch (error) {
echo.error("Failed to update point");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -22,9 +22,9 @@ export const signUpApi = async (
} catch (error) {
echo.error("Failed to sign-up");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -0,0 +1,39 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const createVersionApi = async (projectId: string, createdBy: string, hierarchyVersion: string, versionName: string, description: string) => {
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/V1/generateVersion`,
{
method: "POST",
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json",
token: localStorage.getItem("token") || "",
refresh_token: localStorage.getItem("refreshToken") || "",
},
body: JSON.stringify({
projectId,
createdBy,
hierarchyVersion,
versionName,
description
})
}
);
if (!response.ok) {
throw new Error("Failed to create Version History");
}
const result = await response.json();
return result;
} catch (error) {
echo.error("Failed to create Version History");
if (error instanceof Error) {
console.log(error.message);
} else {
console.log("An unknown error occurred");
}
}
};

View File

@@ -0,0 +1,32 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
export const getVersionHistoryApi = async (projectId: string, page?: number, limit?: number) => {
try {
const response = await fetch(
`${url_Backend_dwinzo}/api/V1/${projectId}/versions`,
{
method: "GET",
headers: {
Authorization: "Bearer <access_token>",
"Content-Type": "application/json",
token: localStorage.getItem("token") || "",
refresh_token: localStorage.getItem("refreshToken") || "",
},
}
);
if (!response.ok) {
throw new Error("Failed to get Version History");
}
const result = await response.json();
return result;
} catch (error) {
echo.error("Failed to get Version History");
if (error instanceof Error) {
console.log(error.message);
} else {
console.log("An unknown error occurred");
}
}
};

View File

@@ -24,9 +24,9 @@ export const deleteZonesApi = async (
} catch (error) {
echo.error("Failed to delete zone");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -27,9 +27,9 @@ export const getZonesApi = async (organization: string, projectId?: string) => {
} catch (error) {
echo.error("Failed to get zone data");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -23,9 +23,9 @@ export const setZonesApi = async (
} catch (error) {
echo.error("Failed to zone data");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -19,6 +19,6 @@ export const getAssetDetails = async (filename: string) => {
} catch (error: any) {
echo.error("Failed to fetch assetg details");
// console.error("Error fetching category:", error.message);
throw new Error(error.message);
console.log(error.message);
}
};

View File

@@ -12,6 +12,6 @@ export const fetchAssets = async () => {
} catch (error) {
echo.error("Failed to fetch assets");
console.log("error: ", error);
// throw new Error(error.message);
// console.log(error.message);
}
};

View File

@@ -21,6 +21,6 @@ export const fetchGltfUrl = async (filename: string, AssetID: string) => {
return result;
} catch (error: any) {
//
throw new Error(error.message);
console.log(error.message);
}
}

View File

@@ -21,6 +21,6 @@ export const getSortedAssets = async (category: any, orders: any) => {
} catch (error: any) {
echo.error("Failed to fetching category");
console.error("Error fetching category:", error.message);
throw new Error(error.message);
console.log(error.message);
}
};

View File

@@ -25,9 +25,9 @@ export const upsertProductOrEventApi = async (body: any) => {
} catch (error) {
echo.error("Failed to upsert product Or eventApi");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -25,9 +25,9 @@ export const deleteEventDataApi = async (body: any) => {
} catch (error) {
echo.error("Failed to delete event data API");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -25,9 +25,9 @@ export const deleteProductApi = async (body: any) => {
} catch (error) {
echo.error("Failed to delete product API");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -27,9 +27,9 @@ export const getProductApi = async (
} catch (error) {
echo.error("Failed to get product asset");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -24,9 +24,9 @@ export const getAllProductsApi = async (projectId: string) => {
} catch (error) {
echo.error("Failed to get all product API");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -28,9 +28,9 @@ export const renameProductApi = async (body: {
echo.error("Failed to rename product Api");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -26,9 +26,9 @@ export const adding3dWidgets = async (
} catch (error) {
echo.error("Failed to add 3d widget");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -32,9 +32,9 @@ export const addingFloatingWidgets = async (
} catch (error) {
echo.error("Failed to add floating");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -29,9 +29,9 @@ export const addingWidgets = async (
} catch (error) {
echo.error("Failed to add widget");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -26,9 +26,9 @@ export const clearPanel = async (
} catch (error) {
echo.error("Failed to clean pannel");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -30,9 +30,9 @@ export const delete3dWidgetApi = async (
} catch (error) {
echo.error("Failed to delete 3d widget");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -29,9 +29,9 @@ export const deleteFloatingWidgetApi = async (
} catch (error) {
echo.error("Failed to delete floating widget");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -27,9 +27,9 @@ export const deletePanelApi = async (
} catch (error) {
echo.error("Failed to delete pannel");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -28,9 +28,9 @@ export const deleteTemplateApi = async (
} catch (error) {
echo.error("Failed to delete widget");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -26,9 +26,9 @@ export const deleteWidgetApi = async (
} catch (error) {
echo.error("Failed to delete widget");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -26,9 +26,9 @@ export const duplicateWidgetApi = async (
} catch (error) {
echo.error("Failed to dublicate widget");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -27,6 +27,6 @@ export const get3dWidgetZoneData = async (
return await response.json();
} catch (error: any) {
echo.error("Failed to fetch 3d data");
throw new Error(error.message);
console.log(error.message);
}
};

View File

@@ -26,6 +26,6 @@ export const getFloatingZoneData = async (
return await response.json();
} catch (error: any) {
echo.error("Failed to fetch floating data");
throw new Error(error.message);
console.log(error.message);
}
};

View File

@@ -23,6 +23,6 @@ export const getSelect2dZoneData = async (zoneUuid?: string, organization?: stri
return await response.json();
} catch (error: any) {
echo.error("Failed to fetch 2d widget data");
throw new Error(error.message);
console.log(error.message);
}
};

View File

@@ -22,6 +22,6 @@ export const getTemplateData = async (organization?: string, projectId?: string)
return await response.json();
} catch (error: any) {
echo.error("Failed to template data");
throw new Error(error.message);
console.log(error.message);
}
};

View File

@@ -21,6 +21,6 @@ export const getZone2dData = async (organization?: string, projectId?: string) =
return await response.json();
} catch (error: any) {
echo.error("Failed to fetch 2d zone data");
throw new Error(error.message);
console.log(error.message);
}
};

View File

@@ -23,6 +23,6 @@ export const getZoneData = async (zoneUuid: string, organization: string, projec
return await response.json();
} catch (error: any) {
echo.error("Failed to fetch zone data");
throw new Error(error.message);
console.log(error.message);
}
};

View File

@@ -29,9 +29,9 @@ export const loadTempleteApi = async (
} catch (error) {
echo.error("Failed to load template");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -26,9 +26,9 @@ export const lockPanel = async (
} catch (error) {
echo.error("Failed to fetch locked panel data");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -27,9 +27,9 @@ export const panelData = async (
} catch (error) {
echo.error("Failed to fetch panel data");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -23,9 +23,9 @@ export const saveTemplateApi = async (organization: string, template: {}) => {
} catch (error) {
echo.error("Failed to save template");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -36,9 +36,9 @@ export const update3dWidget = async (
return result;
} catch (error) {
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};
@@ -78,9 +78,9 @@ export const update3dWidgetRotation = async (
} catch (error) {
echo.error("Failed to rotate 3d widget");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -23,9 +23,9 @@ export const zoneCameraUpdate = async (zoneData: {}, organization: string, proje
} catch (error) {
echo.error("Failed to update zone camera");
if (error instanceof Error) {
throw new Error(error.message);
console.log(error.message);
} else {
throw new Error("An unknown error occurred");
console.log("An unknown error occurred");
}
}
};

View File

@@ -515,15 +515,15 @@ export const useZoneAssetId = create<ZoneAssetState>((set) => ({
// version visible hidden
interface VersionHistoryState {
viewVersionHistory: boolean;
setVersionHistory: (value: boolean) => void;
setVersionHistoryVisible: (value: boolean) => void;
}
const useVersionHistoryStore = create<VersionHistoryState>((set) => ({
const useVersionHistoryVisibleStore = create<VersionHistoryState>((set) => ({
viewVersionHistory: false,
setVersionHistory: (value) => set({ viewVersionHistory: value }),
setVersionHistoryVisible: (value) => set({ viewVersionHistory: value }),
}));
export default useVersionHistoryStore;
export default useVersionHistoryVisibleStore;
interface ShortcutStore {
showShortcuts: boolean;
@@ -647,47 +647,6 @@ export const useSaveVersion = create<SaveVersionStore>((set) => ({
setIsVersionSaved: (value: boolean) => set({ isVersionSaved: value }),
}));
// Version object type
export interface Version {
id: string;
versionLabel: string;
versionName?: string;
timestamp: string;
savedBy: string;
description?: string;
}
// Version list store
interface VersionListStore {
versions: Version[];
addVersion: (version: Version) => void;
clearVersions: () => void;
setVersions: (newVersions: Version[]) => void;
updateVersion: (id: string, data: Partial<Version>) => void; // ✅ Added
}
export const useVersionStore = create<VersionListStore>((set) => ({
versions: [],
addVersion: (newVersion) =>
set((state) => ({
versions: [newVersion, ...state.versions],
})),
clearVersions: () => set({ versions: [] }),
setVersions: (newVersions) => set({ versions: newVersions }),
updateVersion: (id, data) =>
set((state) => ({
versions: state.versions.map((version) =>
version.id === id ? { ...version, ...data } : version
),
})),
}));
interface ViewSceneState {
viewSceneLabels: boolean;
setViewSceneLabels: (value: boolean | ((prev: boolean) => boolean)) => void;

View File

@@ -0,0 +1,84 @@
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
interface VersionHistoryStore {
versionHistory: VersionHistory;
selectedVersion: Version | null;
createNewVersion: boolean;
setSelectedVersion: (version: Version | null) => void;
setCreateNewVersion: (createNewVersion: boolean) => void;
addVersion: (version: Version) => void;
setVersions: (versions: Version[]) => void;
clearVersions: () => void;
setVersionName: (versionId: string, versionName: string) => void;
updateVersion: (versionId: string, versionName: string, versionDescription: string) => void;
getVersionById: (versionId: string) => Version | undefined;
}
export const useVersionHistoryStore = create<VersionHistoryStore>()(
immer((set, get) => ({
versionHistory: [],
selectedVersion: null,
createNewVersion: false,
setSelectedVersion: (version: Version | null) => {
set((state) => {
state.selectedVersion = version;
})
},
setCreateNewVersion: (createNewVersion: boolean) => {
set((state) => {
state.createNewVersion = createNewVersion;
})
},
addVersion: (version: Version) => {
set((state) => {
state.versionHistory.unshift(version);
})
},
setVersions: (versions: Version[]) => {
set((state) => {
state.versionHistory = versions;
})
},
clearVersions: () => {
set((state) => {
state.versionHistory = [];
})
},
setVersionName: (versionId: string, versionName: string) => {
set((state) => {
const version = state.versionHistory.find((v) => v.versionId === versionId);
if (version) {
version.versionName = versionName;
}
})
},
updateVersion: (versionId: string, versionName: string, versionDescription: string) => {
set((state) => {
const version = state.versionHistory.find((v) => v.versionId === versionId);
if (version) {
version.versionName = versionName;
version.versionDescription = versionDescription;
}
})
},
getVersionById: (versionId: string) => {
return get().versionHistory.find((v) => {
return v.versionId === versionId
})
}
}))
);

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,15 @@
// Version History
interface Version {
version: number;
versionId: string;
versionName: string;
versionDescription: string;
timeStamp: string;
createdBy: string;
}
type VersionHistory = Version[];
// Asset
interface Asset {

View File

@@ -1,7 +1,7 @@
import React, { useEffect } from "react";
import useModuleStore, { useThreeDStore } from "../../store/useModuleStore";
import useModuleStore, { useSubModuleStore, useThreeDStore } from "../../store/useModuleStore";
import { usePlayerStore, useToggleStore } from "../../store/useUIToggleStore";
import {
import useVersionHistoryVisibleStore, {
useActiveSubTool,
useActiveTool,
useAddAction,
@@ -21,10 +21,12 @@ import { detectModifierKeys } from "./detectModifierKeys";
import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
import { useLogger } from "../../components/ui/log/LoggerContext";
import { useComparisonProduct } from "../../store/simulation/useSimulationStore";
import { useVersionHistoryStore } from "../../store/builder/useVersionHistoryStore";
const KeyPressListener: React.FC = () => {
const { comparisonProduct, clearComparisonProduct } = useComparisonProduct();
const { activeModule, setActiveModule } = useModuleStore();
const { setSubModule } = useSubModuleStore();
const { setActiveSubTool } = useActiveSubTool();
const { toggleUILeft, toggleUIRight, setToggleUI } = useToggleStore();
const { setToggleThreeD } = useThreeDStore();
@@ -40,9 +42,11 @@ const KeyPressListener: React.FC = () => {
const { setIsVersionSaved } = useSaveVersion();
const { isLogListVisible, setIsLogListVisible } = useLogger();
const { hidePlayer, setHidePlayer } = usePlayerStore();
const { viewSceneLabels, setViewSceneLabels } = useViewSceneStore();
const { setViewSceneLabels } = useViewSceneStore();
const { isRenameMode, setIsRenameMode } = useRenameModeStore();
const { selectedFloorItem } = useSelectedFloorItem();
const { setCreateNewVersion } = useVersionHistoryStore();
const { setVersionHistoryVisible } = useVersionHistoryVisibleStore();
const isTextInput = (element: Element | null): boolean =>
element instanceof HTMLInputElement ||
@@ -150,6 +154,13 @@ const KeyPressListener: React.FC = () => {
updateLocalStorage(!toggleUILeft, toggleUIRight);
break;
case "Ctrl+Alt+S":
setCreateNewVersion(true);
setVersionHistoryVisible(true);
setSubModule("properties");
setActiveModule('builder');
break;
default:
break;
}