Merge remote-tracking branch 'origin/main' into feature/thread-comments
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -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 ? (
|
||||
<>
|
||||
Don’t 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 ?
|
||||
|
||||
Reference in New Issue
Block a user