@@ -35,6 +35,7 @@ import { openMultipleFilesAndFoldersDialog } from "../../tools/dialog";
3535import { findAvailableFilename , normalizedGlob } from "../../tools/fs" ;
3636import { loadSavedThumbnailsCache } from "../../tools/assets/thumbnail" ;
3737import { assetsCache , saveAssetsCache } from "../../tools/assets/cache" ;
38+ import { assetsAllSupportedExtensions } from "../../tools/assets/extensions" ;
3839import { checkProjectCachedCompressedTextures , processingCompressedTextures } from "../../tools/assets/ktx" ;
3940
4041import { ICommandPaletteType } from "../dialogs/command-palette/command-palette" ;
@@ -44,7 +45,7 @@ import { loadScene } from "../../project/load/scene";
4445import { saveProject , saveProjectConfiguration } from "../../project/save/save" ;
4546import { onProjectConfigurationChangedObservable , projectConfiguration } from "../../project/configuration" ;
4647
47- import { showConfirm , showPrompt } from "../../ui/dialog" ;
48+ import { showAlert , showConfirm , showPrompt } from "../../ui/dialog" ;
4849
4950import { Input } from "../../ui/shadcn/ui/input" ;
5051import { Breadcrumb , BreadcrumbItem , BreadcrumbLink , BreadcrumbList , BreadcrumbSeparator } from "../../ui/shadcn/ui/breadcrumb" ;
@@ -229,6 +230,20 @@ export class EditorAssetsBrowser extends Component<IEditorAssetsBrowserProps, IE
229230 listenParticleAssetsEvents ( this . props . editor ) ;
230231 }
231232
233+ /**
234+ * Returns wether or not the currently browsed folder is the /assets folder.
235+ */
236+ public isAssetsFolder ( ) : boolean {
237+ return this . state . browsedPath ?. startsWith ( join ( dirname ( projectConfiguration . path ! ) , "/assets" ) ) ?? false ;
238+ }
239+
240+ /**
241+ * Returns wether or not the currently browsed folder is the /src folder.
242+ */
243+ public isSrcFolder ( ) : boolean {
244+ return this . state . browsedPath ?. startsWith ( join ( dirname ( projectConfiguration . path ! ) , "/src" ) ) ?? false ;
245+ }
246+
232247 private async _refreshFilesTreeNodes ( path : string ) : Promise < void > {
233248 const files = await normalizedGlob ( join ( dirname ( path ) , "**" ) , {
234249 ignore : {
@@ -732,66 +747,20 @@ export class EditorAssetsBrowser extends Component<IEditorAssetsBrowserProps, IE
732747 Paste
733748 </ ContextMenuItem >
734749
735- < ContextMenuSeparator />
736-
737- < ContextMenuSub >
738- < ContextMenuSubTrigger className = "flex items-center gap-2" >
739- < AiOutlinePlus className = "w-5 h-5" /> Add
740- </ ContextMenuSubTrigger >
741- < ContextMenuSubContent >
742- < ContextMenuItem onClick = { ( ) => this . _handleAddScene ( ) } > Scene</ ContextMenuItem >
750+ { ( this . isAssetsFolder ( ) || this . isSrcFolder ( ) ) && (
751+ < >
743752 < ContextMenuSeparator />
744- { getMaterialCommands ( this . props . editor ) . map ( ( command ) => (
745- < ContextMenuItem key = { command . key } onClick = { ( ) => this . _handleAddMaterial ( command ) } >
746- { command . text }
747- </ ContextMenuItem >
748- ) ) }
749-
750- < ContextMenuSeparator />
751- < ContextMenuItem onClick = { ( ) => this . _handleAddNodeMaterialFromSnippet ( ) } > Node Material From Snippet...</ ContextMenuItem >
752- < ContextMenuSeparator />
753-
754753 < ContextMenuSub >
755- < ContextMenuSubTrigger className = "flex items-center gap-2" > Materials Library</ ContextMenuSubTrigger >
754+ < ContextMenuSubTrigger className = "flex items-center gap-2" >
755+ < AiOutlinePlus className = "w-5 h-5" /> Add
756+ </ ContextMenuSubTrigger >
756757 < ContextMenuSubContent >
757- { getMaterialsLibraryCommands ( this . props . editor ) . map ( ( command ) => (
758- < ContextMenuItem key = { command . key } onClick = { ( ) => this . _handleAddMaterial ( command ) } >
759- { command . text }
760- </ ContextMenuItem >
761- ) ) }
758+ { this . isAssetsFolder ( ) && this . _getAssetsContextMenuItems ( ) }
759+ { this . isSrcFolder ( ) && this . _getSrcContextMenuItems ( ) }
762760 </ ContextMenuSubContent >
763761 </ ContextMenuSub >
764-
765- { this . props . editor . state . enableExperimentalFeatures && (
766- < >
767- < ContextMenuSeparator />
768- < ContextMenuItem onClick = { ( ) => this . _handleAddNodeParticleSystem ( ) } > Node Particle System</ ContextMenuItem >
769- < ContextMenuSeparator />
770- < ContextMenuItem onClick = { ( ) => this . _handleAddCinematic ( ) } > Cinematic</ ContextMenuItem >
771- </ >
772- ) }
773-
774- { this . props . editor . state . enableExperimentalFeatures && (
775- < >
776- < ContextMenuSeparator />
777- < ContextMenuItem onClick = { ( ) => this . _handleAddFullScreenGUI ( ) } > Full Screen GUI</ ContextMenuItem >
778- </ >
779- ) }
780-
781- { this . state . browsedPath ?. startsWith ( join ( dirname ( projectConfiguration . path ! ) , "/src" ) ) && (
782- < >
783- < ContextMenuSeparator />
784- < ContextMenuSub >
785- < ContextMenuSubTrigger className = "flex items-center gap-2" > Script</ ContextMenuSubTrigger >
786- < ContextMenuSubContent >
787- < ContextMenuItem onClick = { ( ) => this . _handleAddScript ( "class" ) } > Class-based</ ContextMenuItem >
788- < ContextMenuItem onClick = { ( ) => this . _handleAddScript ( "function" ) } > Function-based</ ContextMenuItem >
789- </ ContextMenuSubContent >
790- </ ContextMenuSub >
791- </ >
792- ) }
793- </ ContextMenuSubContent >
794- </ ContextMenuSub >
762+ </ >
763+ ) }
795764
796765 < ContextMenuSeparator />
797766
@@ -804,6 +773,60 @@ export class EditorAssetsBrowser extends Component<IEditorAssetsBrowserProps, IE
804773 ) ;
805774 }
806775
776+ private _getAssetsContextMenuItems ( ) : ReactNode {
777+ return (
778+ < >
779+ < ContextMenuItem onClick = { ( ) => this . _handleAddScene ( ) } > Scene</ ContextMenuItem >
780+ < ContextMenuSeparator />
781+ { getMaterialCommands ( this . props . editor ) . map ( ( command ) => (
782+ < ContextMenuItem key = { command . key } onClick = { ( ) => this . _handleAddMaterial ( command ) } >
783+ { command . text }
784+ </ ContextMenuItem >
785+ ) ) }
786+
787+ < ContextMenuSeparator />
788+ < ContextMenuItem onClick = { ( ) => this . _handleAddNodeMaterialFromSnippet ( ) } > Node Material From Snippet...</ ContextMenuItem >
789+ < ContextMenuSeparator />
790+
791+ < ContextMenuSub >
792+ < ContextMenuSubTrigger className = "flex items-center gap-2" > Materials Library</ ContextMenuSubTrigger >
793+ < ContextMenuSubContent >
794+ { getMaterialsLibraryCommands ( this . props . editor ) . map ( ( command ) => (
795+ < ContextMenuItem key = { command . key } onClick = { ( ) => this . _handleAddMaterial ( command ) } >
796+ { command . text }
797+ </ ContextMenuItem >
798+ ) ) }
799+ </ ContextMenuSubContent >
800+ </ ContextMenuSub >
801+
802+ { this . props . editor . state . enableExperimentalFeatures && (
803+ < >
804+ < ContextMenuSeparator />
805+ < ContextMenuItem onClick = { ( ) => this . _handleAddNodeParticleSystem ( ) } > Node Particle System</ ContextMenuItem >
806+ < ContextMenuSeparator />
807+ < ContextMenuItem onClick = { ( ) => this . _handleAddCinematic ( ) } > Cinematic</ ContextMenuItem >
808+ </ >
809+ ) }
810+
811+ { this . props . editor . state . enableExperimentalFeatures && (
812+ < >
813+ < ContextMenuSeparator />
814+ < ContextMenuItem onClick = { ( ) => this . _handleAddFullScreenGUI ( ) } > Full Screen GUI</ ContextMenuItem >
815+ </ >
816+ ) }
817+ </ >
818+ ) ;
819+ }
820+
821+ private _getSrcContextMenuItems ( ) : ReactNode {
822+ return (
823+ < >
824+ < ContextMenuItem onClick = { ( ) => this . _handleAddScript ( "class" ) } > Class-based Script</ ContextMenuItem >
825+ < ContextMenuItem onClick = { ( ) => this . _handleAddScript ( "function" ) } > Function-based Script</ ContextMenuItem >
826+ </ >
827+ ) ;
828+ }
829+
807830 private _getAssetBrowserItem ( filename : string , key : string , selected : boolean ) : ReactNode {
808831 const extension = extname ( filename ) . toLowerCase ( ) ;
809832
@@ -887,6 +910,8 @@ export class EditorAssetsBrowser extends Component<IEditorAssetsBrowserProps, IE
887910 return ;
888911 }
889912
913+ let assetFileNotInAssetsFolder = false ;
914+
890915 const filesToCopy : Record < string , string > = { } ;
891916
892917 for ( let i = 0 , len = event . dataTransfer . files . length ; i < len ; ++ i ) {
@@ -898,9 +923,30 @@ export class EditorAssetsBrowser extends Component<IEditorAssetsBrowserProps, IE
898923 const path = webUtils . getPathForFile ( file ) . replace ( / \\ / g, "/" ) ;
899924 const absolutePath = join ( this . state . browsedPath , basename ( path ) ) ;
900925
926+ if ( ! this . isAssetsFolder ( ) ) {
927+ const extension = extname ( path ) . toLowerCase ( ) ;
928+
929+ if ( assetsAllSupportedExtensions . includes ( extension ) ) {
930+ assetFileNotInAssetsFolder = true ;
931+ continue ;
932+ }
933+ }
934+
901935 filesToCopy [ path ] = absolutePath ;
902936 }
903937
938+ if ( assetFileNotInAssetsFolder ) {
939+ showAlert (
940+ "Warning" ,
941+ < div >
942+ You tried to import assets in a directory not located at least in the root "assets" folder.
943+ < br />
944+ To prevent broken references, these files were not copied. Please drag'n'drop them at least in the /assets folder.
945+ </ div > ,
946+ true
947+ ) ;
948+ }
949+
904950 await Promise . all (
905951 Object . entries ( filesToCopy ) . map ( async ( [ source , destination ] ) => {
906952 const fStat = await stat ( source ) ;
@@ -940,6 +986,8 @@ export class EditorAssetsBrowser extends Component<IEditorAssetsBrowserProps, IE
940986 title : "Import Files & Folders" ,
941987 } ) ;
942988
989+ let assetFileNotInAssetsFolder = false ;
990+
943991 await Promise . all (
944992 files . map ( async ( file ) => {
945993 const destination = join ( this . state . browsedPath ! , basename ( file ) ) ;
@@ -950,11 +998,31 @@ export class EditorAssetsBrowser extends Component<IEditorAssetsBrowserProps, IE
950998 recursive : true ,
951999 } ) ;
9521000 } else {
1001+ if ( ! this . isAssetsFolder ( ) ) {
1002+ const extension = extname ( file ) . toLowerCase ( ) ;
1003+ if ( assetsAllSupportedExtensions . includes ( extension ) ) {
1004+ assetFileNotInAssetsFolder = true ;
1005+ return ;
1006+ }
1007+ }
1008+
9531009 await copyFile ( file , destination ) ;
9541010 }
9551011 } )
9561012 ) ;
9571013
1014+ if ( assetFileNotInAssetsFolder ) {
1015+ showAlert (
1016+ "Warning" ,
1017+ < div >
1018+ You tried to import assets in a directory not located at least in the root "assets" folder.
1019+ < br />
1020+ To prevent broken references, these files were not copied. Please drag'n'drop them at least in the /assets folder.
1021+ </ div > ,
1022+ true
1023+ ) ;
1024+ }
1025+
9581026 this . _refreshItems ( this . state . browsedPath ) ;
9591027 }
9601028
0 commit comments