Merge remote-tracking branch 'origin/main' into feature/thread-comments

This commit is contained in:
2025-11-27 10:32:04 +05:30
3 changed files with 276 additions and 41 deletions

View File

@@ -1,3 +1,4 @@
<<<<<<< HEAD
{
"name": "aalai-beta",
"version": "0.1.0",
@@ -88,3 +89,92 @@
"ts-node": "^10.9.2"
}
}
=======
{
"name": "aalai-beta",
"version": "0.1.0",
"private": true,
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
"@fingerprintjs/fingerprintjs": "^4.6.2",
"@fingerprintjs/fingerprintjs-pro-react": "^2.6.3",
"@react-three/csg": "^3.2.0",
"@react-three/drei": "^9.113.0",
"@react-three/fiber": "^8.17.7",
"@react-three/postprocessing": "^2.16.3",
"@recast-navigation/core": "^0.39.0",
"@recast-navigation/three": "^0.39.0",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@turf/helpers": "^7.2.0",
"@turf/turf": "^7.2.0",
"@types/jest": "^27.5.2",
"@types/react": "^18.3.5",
"@types/react-dom": "^18.3.0",
"@use-gesture/react": "^10.3.1",
"chart.js": "^4.4.8",
"chartjs-plugin-annotation": "^3.1.0",
"dxf-parser": "^1.1.2",
"glob": "^11.0.0",
"gsap": "^3.12.5",
"html2canvas": "^1.4.1",
"immer": "^9.0.21",
"leva": "^0.10.0",
"mqtt": "^5.10.4",
"postprocessing": "^6.36.4",
"prompt-sync": "^4.2.0",
"react": "^18.3.1",
"react-chartjs-2": "^5.3.0",
"react-dom": "^18.3.1",
"react-router-dom": "^7.4.0",
"react-scripts": "5.0.1",
"react-toastify": "^10.0.5",
"sass": "^1.78.0",
"socket.io-client": "^4.8.1",
"three": "^0.168.0",
"three-viewport-gizmo": "^2.2.0",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4",
"zustand": "^5.0.0-rc.2"
},
"scripts": {
"prepare": "husky",
"prestart": "tsc scripts/git-prompt.ts && node scripts/git-prompt.js",
"start": "react-scripts start",
"build": "cross-env GENERATE_SOURCEMAP=false react-scripts build",
"test": "jest",
"cypress:open": "cypress open",
"cypress:run": "cypress run"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/html2canvas": "^1.0.0",
"@types/node": "^22.9.1",
"@types/three": "^0.169.0",
"axios": "^1.8.4",
"cypress": "^13.14.2",
"dotenv": "^16.4.5",
"husky": "^9.1.6",
"ts-node": "^10.9.2"
}
}
>>>>>>> origin/main

View File

@@ -1,6 +1,17 @@
import { useState, useRef, DragEvent, useCallback, useMemo } from "react";
import { useParams } from "react-router-dom";
import { EyeIcon, LockIcon, FolderIcon, ChevronIcon, CubeIcon, AddIcon, KebebIcon, CollapseAllIcon, FocusIcon, DeleteIcon } from "../../../icons/ExportCommonIcons";
import {
EyeIcon,
LockIcon,
FolderIcon,
ChevronIcon,
CubeIcon,
AddIcon,
KebebIcon,
CollapseAllIcon,
FocusIcon,
DeleteIcon,
} from "../../../icons/ExportCommonIcons";
import RenameInput from "../../inputs/RenameInput";
import clsx from "clsx";
import { useSceneContext } from "../../../../modules/scene/sceneContext";
@@ -10,7 +21,8 @@ import useZoomMesh from "../../../../modules/builder/hooks/useZoomMesh";
import { getUserData } from "../../../../functions/getUserData";
import { useOuterClick } from "../../../../utils/useOuterClick";
import { GCodeLoader } from "three/examples/jsm/Addons";
import { PDBLoader } from "three/examples/jsm/Addons";
import { setAssetsApi } from "../../../../services/builder/asset/floorAsset/setAssetsApi";
interface DragState {
@@ -57,7 +69,9 @@ const TreeNode = ({
const isLocked = item.isLocked;
const isExpanded = isGroupNode ? item.isExpanded : false;
const isSelected = isGroupNode ? hasSelectedGroup(item.groupUuid) : hasSelectedAsset(item.modelUuid);
const isSelected = isGroupNode
? hasSelectedGroup(item.groupUuid)
: hasSelectedAsset(item.modelUuid);
const getMultiSelectionState = (item: AssetGroupChild) => {
const totalSelectedItems = selectedGroups.length + selectedAssets.length;
@@ -111,7 +125,12 @@ const TreeNode = ({
const shouldShowHighlight = isDropTarget();
return (
<div key={itemId} className={`tree-node ${shouldShowHighlight ? "drop-target-highlight" : ""} ${isGroupNode && isSelected ? "group-selected" : ""}`}>
<div
key={itemId}
className={`tree-node ${shouldShowHighlight ? "drop-target-highlight" : ""} ${
isGroupNode && isSelected ? "group-selected" : ""
}`}
>
<div
className={clsx("tree-node-content", {
"group-node": isGroupNode,
@@ -131,12 +150,17 @@ const TreeNode = ({
onClick={handleNodeClick}
>
{isGroupNode && (
<button className="expand-button" onClick={() => onToggleExpand(item.groupUuid, !isExpanded)}>
<button
className="expand-button"
onClick={() => onToggleExpand(item.groupUuid, !isExpanded)}
>
<ChevronIcon isOpen={isExpanded} />
</button>
)}
<div className="node-icon">{isGroupNode ? <FolderIcon isOpen={isExpanded} /> : <CubeIcon />}</div>
<div className="node-icon">
{isGroupNode ? <FolderIcon isOpen={isExpanded} /> : <CubeIcon />}
</div>
<RenameInput
value={itemName}
@@ -147,17 +171,32 @@ const TreeNode = ({
/>
<div className="node-controls">
<button className="control-button" title={isVisible ? "Visible" : "Hidden"} onClick={(e) => handleOptionClick(e, "visibility")}>
<button
className="control-button"
title={isVisible ? "Visible" : "Hidden"}
onClick={(e) => handleOptionClick(e, "visibility")}
>
<EyeIcon isClosed={!isVisible} />
</button>
<button className="control-button" title="Focus" onClick={(e) => handleOptionClick(e, "focus")}>
<button
className="control-button"
title="Focus"
onClick={(e) => handleOptionClick(e, "focus")}
>
<FocusIcon />
</button>
<button className="control-button" title={isLocked ? "Locked" : "Unlocked"} onClick={(e) => handleOptionClick(e, "lock")}>
<button
className="control-button"
title={isLocked ? "Locked" : "Unlocked"}
onClick={(e) => handleOptionClick(e, "lock")}
>
<LockIcon isLocked={isLocked} />
</button>
{isGroupNode && (
<button className="control-button" onClick={(e) => handleOptionClick(e, "kebab")}>
<button
className="control-button"
onClick={(e) => handleOptionClick(e, "kebab")}
>
<KebebIcon />
</button>
)}
@@ -200,7 +239,16 @@ export const AssetOutline = () => {
});
const [_, forceUpdate] = useState({});
const { scene, assetGroupStore, assetStore, versionStore, undoRedo3DStore } = useSceneContext();
const { addSelectedAsset, clearSelectedAssets, getAssetById, peekToggleVisibility, peekToggleLock, toggleSelectedAsset, selectedAssets, setSelectedAssets } = assetStore();
const {
addSelectedAsset,
clearSelectedAssets,
getAssetById,
peekToggleVisibility,
peekToggleLock,
toggleSelectedAsset,
selectedAssets,
setSelectedAssets,
} = assetStore();
const {
groupHierarchy,
isGroup,
@@ -335,7 +383,11 @@ export const AssetOutline = () => {
})
.then((data) => {
if (!data.message || !data.data) {
echo.error(`Error ${asset.isVisible ? "hiding" : "unhiding"} asset: ${asset.modelName}`);
echo.error(
`Error ${asset.isVisible ? "hiding" : "unhiding"} asset: ${
asset.modelName
}`
);
return;
}
if (data.message === "Model updated successfully" && data.data) {
@@ -354,14 +406,22 @@ export const AssetOutline = () => {
};
updateAssetInScene(model, () => {
echo.info(`${asset.isVisible ? "Hid" : "Unhid"} asset: ${model.modelName}`);
echo.info(
`${asset.isVisible ? "Hid" : "Unhid"} asset: ${model.modelName}`
);
});
} else {
echo.error(`Error ${asset.isVisible ? "hiding" : "unhiding"} asset: ${asset.modelName}`);
echo.error(
`Error ${asset.isVisible ? "hiding" : "unhiding"} asset: ${
asset.modelName
}`
);
}
})
.catch(() => {
echo.error(`Error ${asset.isVisible ? "hiding" : "unhiding"} asset: ${asset.modelName}`);
echo.error(
`Error ${asset.isVisible ? "hiding" : "unhiding"} asset: ${asset.modelName}`
);
});
} else {
const data = {
@@ -406,7 +466,11 @@ export const AssetOutline = () => {
})
.then((data) => {
if (!data.message || !data.data) {
echo.error(`Error ${asset.isVisible ? "locking" : "unlocking"} asset: ${asset.modelName}`);
echo.error(
`Error ${asset.isVisible ? "locking" : "unlocking"} asset: ${
asset.modelName
}`
);
return;
}
if (data.message === "Model updated successfully" && data.data) {
@@ -425,14 +489,26 @@ export const AssetOutline = () => {
};
updateAssetInScene(model, () => {
echo.info(`${asset.isVisible ? "Locked" : "Unlocked"} asset: ${model.modelName}`);
echo.info(
`${asset.isVisible ? "Locked" : "Unlocked"} asset: ${
model.modelName
}`
);
});
} else {
echo.error(`Error ${asset.isVisible ? "locking" : "unlocking"} asset: ${asset.modelName}`);
echo.error(
`Error ${asset.isVisible ? "locking" : "unlocking"} asset: ${
asset.modelName
}`
);
}
})
.catch(() => {
echo.error(`Error ${asset.isVisible ? "locking" : "unlocking"} asset: ${asset.modelName}`);
echo.error(
`Error ${asset.isVisible ? "locking" : "unlocking"} asset: ${
asset.modelName
}`
);
});
} else {
const data = {
@@ -464,13 +540,16 @@ export const AssetOutline = () => {
[setGroupExpanded]
);
const handleDragStart = useCallback((e: DragEvent, item: AssetGroupChild, parentGroupUuid: string | null) => {
dragStateRef.current.draggedItem = item;
dragStateRef.current.draggedItemParentGroupUuid = parentGroupUuid;
const handleDragStart = useCallback(
(e: DragEvent, item: AssetGroupChild, parentGroupUuid: string | null) => {
dragStateRef.current.draggedItem = item;
dragStateRef.current.draggedItemParentGroupUuid = parentGroupUuid;
e.dataTransfer.effectAllowed = "move";
forceUpdate({});
}, []);
e.dataTransfer.effectAllowed = "move";
forceUpdate({});
},
[]
);
const handleDragOver = useCallback(
(e: DragEvent, targetItem: AssetGroupChild) => {
@@ -540,7 +619,10 @@ export const AssetOutline = () => {
}
// Update target group
if (dragStateRef.current.targetGroupUuid !== targetGroupUuid || dragStateRef.current.isRootTarget !== false) {
if (
dragStateRef.current.targetGroupUuid !== targetGroupUuid ||
dragStateRef.current.isRootTarget !== false
) {
dragStateRef.current.targetGroupUuid = targetGroupUuid;
dragStateRef.current.isRootTarget = false;
forceUpdate({});
@@ -895,7 +977,9 @@ export const AssetOutline = () => {
if (asset) {
const itemId = getItemId(item);
const flattened = getFlattenedHierarchy();
const clickedIndex = flattened.findIndex((flatItem) => getItemId(flatItem) === itemId);
const clickedIndex = flattened.findIndex(
(flatItem) => getItemId(flatItem) === itemId
);
addSelectedAsset(asset);
lastSelectedRef.current = { item, index: clickedIndex };
zoomMeshes([itemId]);
@@ -910,7 +994,11 @@ export const AssetOutline = () => {
[selectedVersion, builderSocket, projectId, userId, organization]
);
const handleAddGroup = useCallback(() => {}, [assetGroupStore, clearSelectedGroups, addSelectedGroup]);
const handleAddGroup = useCallback(() => {}, [
assetGroupStore,
clearSelectedGroups,
addSelectedGroup,
]);
const handleCollapseAll = useCallback(() => {}, [assetGroupStore, setGroupExpanded]);
@@ -920,7 +1008,9 @@ export const AssetOutline = () => {
const totalSelectedGroups = selectedGroups.length;
if (totalSelectedGroups > 0 && totalSelectedAssets > 0) {
return `${totalSelectedGroups} group${totalSelectedGroups > 1 ? "s" : ""} and ${totalSelectedAssets} asset${totalSelectedAssets > 1 ? "s" : ""} selected`;
return `${totalSelectedGroups} group${
totalSelectedGroups > 1 ? "s" : ""
} and ${totalSelectedAssets} asset${totalSelectedAssets > 1 ? "s" : ""} selected`;
} else if (totalSelectedGroups > 0) {
return `${totalSelectedGroups} group${totalSelectedGroups > 1 ? "s" : ""} selected`;
} else if (totalSelectedAssets > 0) {
@@ -943,10 +1033,18 @@ export const AssetOutline = () => {
<p>Assets</p>
</div>
<div className="outline-toolbar">
<button className="toolbar-button" title="Add Group" onClick={handleAddGroup}>
<button
className="toolbar-button"
title="Add Group"
onClick={handleAddGroup}
>
<AddIcon />
</button>
<button className="toolbar-button" title="Collapse All" onClick={handleCollapseAll}>
<button
className="toolbar-button"
title="Collapse All"
onClick={handleCollapseAll}
>
<CollapseAllIcon />
</button>
<button className="close-button" onClick={() => setIsOpen(!isOpen)}>
@@ -956,7 +1054,13 @@ export const AssetOutline = () => {
</div>
{isOpen && (
<div className={`outline-content ${dragStateRef.current.isRootTarget ? "root-drop-target" : ""}`} onDragOver={handleRootDragOver} onDrop={handleDrop}>
<div
className={`outline-content ${
dragStateRef.current.isRootTarget ? "root-drop-target" : ""
}`}
onDragOver={handleRootDragOver}
onDrop={handleDrop}
>
{groupHierarchy.map((item) => (
<TreeNode
key={isGroup(item) ? item.groupUuid : item.modelUuid}
@@ -977,7 +1081,13 @@ export const AssetOutline = () => {
</div>
</div>
<div className="outline-footer">
<span className={`footer-stats ${selectedAssets.length + selectedGroups.length > 1 ? "multi-selection" : ""}`}>{selectionStats}</span>
<span
className={`footer-stats ${
selectedAssets.length + selectedGroups.length > 1 ? "multi-selection" : ""
}`}
>
{selectionStats}
</span>
</div>
</>
);

View File

@@ -51,8 +51,14 @@ const UserAuth: React.FC = () => {
const projects = await recentlyViewedApi();
if (res.message.isShare) {
if (Object.values(projects.RecentlyViewed).length > 0) {
const recent_opend_projectID = (Object.values(projects?.RecentlyViewed || {})[0] as any)?._id;
if (Object.values(projects?.RecentlyViewed).filter((val: any) => val._id == recent_opend_projectID)) {
const recent_opend_projectID = (
Object.values(projects?.RecentlyViewed || {})[0] as any
)?._id;
if (
Object.values(projects?.RecentlyViewed).filter(
(val: any) => val._id == recent_opend_projectID
)
) {
setLoadingProgress(1);
navigate(`/projects/${recent_opend_projectID}`);
} else {
@@ -115,14 +121,22 @@ const UserAuth: React.FC = () => {
{isSignIn ? (
<>
Dont have an account?{" "}
<span className="link" onClick={() => setIsSignIn(false)} style={{ cursor: "pointer" }}>
<span
className="link"
onClick={() => setIsSignIn(false)}
style={{ cursor: "pointer" }}
>
Register here!
</span>
</>
) : (
<>
Already have an account?{" "}
<span className="link" onClick={() => setIsSignIn(true)} style={{ cursor: "pointer" }}>
<span
className="link"
onClick={() => setIsSignIn(true)}
style={{ cursor: "pointer" }}
>
Login here!
</span>
</>
@@ -136,8 +150,24 @@ const UserAuth: React.FC = () => {
{error && <div className="error-message">🛈 {error}</div>}
<form onSubmit={isSignIn ? handleLogin : handleRegister} className="auth-form">
{!isSignIn && <input type="text" value={name} placeholder="Username" onChange={(e) => setName(e.target.value)} required />}
<input type="email" name="email" value={email} placeholder="Email" autoComplete="email" onChange={(e) => setEmail(e.target.value)} required />
{!isSignIn && (
<input
type="text"
value={name}
placeholder="Username"
onChange={(e) => setName(e.target.value)}
required
/>
)}
<input
type="email"
name="email"
value={email}
placeholder="Email"
autoComplete="email"
onChange={(e) => setEmail(e.target.value)}
required
/>
<div className="password-container">
<input
name="password"
@@ -148,11 +178,16 @@ const UserAuth: React.FC = () => {
onChange={(e) => setPassword(e.target.value)}
required
/>
<button id="toogle-password" type="button" className="toggle-password" onClick={() => setShowPassword(!showPassword)}>
<button
id="toogle-password"
type="button"
className="toggle-password"
onClick={() => setShowPassword(!showPassword)}
>
<EyeIcon isClosed={showPassword} />
</button>
</div>
<button>Check</button>
{isSignIn && (
<a href="forgot" className="forgot-password">
Forgot password ?