From b04c15f23c47b6e52568722906378eeeb0271493 Mon Sep 17 00:00:00 2001 From: AlexandreS <32449369+AlexandreSi@users.noreply.github.com> Date: Wed, 15 Jan 2025 10:32:15 +0100 Subject: [PATCH] Add objects installed from the asset store in selected folder (#7287) --- .../src/AssetStore/AssetPackInstallDialog.js | 37 ++++++++++++------- newIDE/app/src/AssetStore/NewObjectDialog.js | 7 +++- newIDE/app/src/ObjectsList/index.js | 31 ++++++++++++---- 3 files changed, 52 insertions(+), 23 deletions(-) diff --git a/newIDE/app/src/AssetStore/AssetPackInstallDialog.js b/newIDE/app/src/AssetStore/AssetPackInstallDialog.js index 3e6a3c3460bb..1f53ec08cd51 100644 --- a/newIDE/app/src/AssetStore/AssetPackInstallDialog.js +++ b/newIDE/app/src/AssetStore/AssetPackInstallDialog.js @@ -35,6 +35,7 @@ import { useFetchAssets, } from './NewObjectDialog'; import { type InstallAssetOutput } from './InstallAsset'; +import { type ObjectFolderOrObjectWithContext } from '../ObjectsList/EnumerateObjectFolderOrObject'; // We limit the number of assets that can be installed at once to avoid // timeouts especially with premium packs. @@ -45,10 +46,11 @@ type Props = {| assetShortHeaders: Array, addedAssetIds: Set, onClose: () => void, - onAssetsAdded: () => void, + onAssetsAdded: (createdObjects: gdObject[]) => void, project: gdProject, objectsContainer: ?gdObjectsContainer, resourceManagementProps: ResourceManagementProps, + targetObjectFolderOrObjectWithContext?: ?ObjectFolderOrObjectWithContext, |}; const AssetPackInstallDialog = ({ @@ -60,6 +62,7 @@ const AssetPackInstallDialog = ({ project, objectsContainer, resourceManagementProps, + targetObjectFolderOrObjectWithContext, }: Props) => { const missingAssetShortHeaders = assetShortHeaders.filter( assetShortHeader => !addedAssetIds.has(assetShortHeader.id) @@ -168,20 +171,22 @@ const AssetPackInstallDialog = ({ }); // Use a pool to avoid installing an unbounded amount of assets at the same time. - const { errors } = await PromisePool.withConcurrency(6) + const { errors, results } = await PromisePool.withConcurrency(6) .for(assets) .process(async asset => { - const installOutput = isPrivateAsset(asset) - ? await installPrivateAsset({ - asset, - project, - objectsContainer: targetObjectsContainer, - }) - : await installPublicAsset({ - asset, - project, - objectsContainer: targetObjectsContainer, - }); + const doInstall = isPrivateAsset(asset) + ? installPrivateAsset + : installPublicAsset; + const installOutput = await doInstall({ + asset, + project, + objectsContainer: targetObjectsContainer, + targetObjectFolderOrObject: + targetObjectFolderOrObjectWithContext && + !targetObjectFolderOrObjectWithContext.global + ? targetObjectFolderOrObjectWithContext.objectFolderOrObject + : null, + }); if (!installOutput) { throw new Error('Unable to install the asset.'); @@ -200,7 +205,10 @@ const AssetPackInstallDialog = ({ await resourceManagementProps.onFetchNewlyAddedResources(); setAreAssetsBeingInstalled(false); - onAssetsAdded(); + const createdObjects = results + .map(result => result.createdObjects) + .flat(); + onAssetsAdded(createdObjects); } catch (error) { setAreAssetsBeingInstalled(false); console.error('Error while installing the assets', error); @@ -221,6 +229,7 @@ const AssetPackInstallDialog = ({ onAssetsAdded, installPrivateAsset, targetObjectsContainer, + targetObjectFolderOrObjectWithContext, ] ); diff --git a/newIDE/app/src/AssetStore/NewObjectDialog.js b/newIDE/app/src/AssetStore/NewObjectDialog.js index b33eeea18b04..d70f19e2c7ec 100644 --- a/newIDE/app/src/AssetStore/NewObjectDialog.js +++ b/newIDE/app/src/AssetStore/NewObjectDialog.js @@ -302,6 +302,7 @@ function NewObjectDialog({ project, objectsContainer, resourceManagementProps, + targetObjectFolderOrObjectWithContext, }); const onInstallAsset = React.useCallback( @@ -566,12 +567,16 @@ function NewObjectDialog({ assetShortHeaders={displayedAssetShortHeaders} addedAssetIds={existingAssetStoreIds} onClose={() => setIsAssetPackDialogInstallOpen(false)} - onAssetsAdded={() => { + onAssetsAdded={createdObjects => { setIsAssetPackDialogInstallOpen(false); + onObjectsAddedFromAssets(createdObjects); }} project={project} objectsContainer={objectsContainer} resourceManagementProps={resourceManagementProps} + targetObjectFolderOrObjectWithContext={ + targetObjectFolderOrObjectWithContext + } /> )} diff --git a/newIDE/app/src/ObjectsList/index.js b/newIDE/app/src/ObjectsList/index.js index be0393285f46..f8e610c2a68e 100644 --- a/newIDE/app/src/ObjectsList/index.js +++ b/newIDE/app/src/ObjectsList/index.js @@ -638,27 +638,42 @@ const ObjectsList = React.forwardRef( const onObjectsAddedFromAssets = React.useCallback( (objects: Array) => { + if (objects.length === 0) return; + objects.forEach(object => { onObjectCreated(object); }); - if (treeViewRef.current) - treeViewRef.current.openItems([sceneObjectsRootFolderId]); + // Here, the last object in the array might not be the last object + // in the tree view, given the fact that assets are added in parallel + // See (AssetPackInstallDialog.onInstallAssets). const lastObject = objects[objects.length - 1]; - // A new object is always added to the scene (layout) by default. - const object = objectsContainer - .getRootFolder() - .getObjectChild(lastObject.getName()); + if (newObjectDialogOpen && newObjectDialogOpen.from) { + const { + objectFolderOrObject: selectedObjectFolderOrObject, + } = newObjectDialogOpen.from; + if (treeViewRef.current) { + treeViewRef.current.openItems( + getFoldersAscendanceWithoutRootFolder( + selectedObjectFolderOrObject + ).map(folder => getObjectFolderTreeViewItemId(folder)) + ); + } + } else { + if (treeViewRef.current) { + treeViewRef.current.openItems([sceneObjectsRootFolderId]); + } + } // Scroll to the new object. // Ideally, we'd wait for the list to be updated to scroll, but // to simplify the code, we just wait a few ms for a new render // to be done. setTimeout(() => { - scrollToItem(getObjectTreeViewItemId(object.getObject())); + scrollToItem(getObjectTreeViewItemId(lastObject)); }, 100); // A few ms is enough for a new render to be done. }, - [objectsContainer, onObjectCreated, scrollToItem] + [onObjectCreated, scrollToItem, newObjectDialogOpen] ); const swapObjectAsset = React.useCallback(