@@ -25,7 +25,11 @@ import {
2525import { apiClient } from "../api" ;
2626import FileTreeSidebar from "../components/FileTreeSidebar" ;
2727
28- const HIDDEN_SYSTEM_FILES = new Set ( [ "workflow_preference.json" ] ) ;
28+ const HIDDEN_SYSTEM_FILES = new Set ( [
29+ "workflow_preference.json" ,
30+ ".ds_store" ,
31+ "thumbs.db" ,
32+ ] ) ;
2933const IMAGE_EXTENSIONS = new Set ( [
3034 ".png" ,
3135 ".jpg" ,
@@ -42,7 +46,8 @@ const transformFiles = (fileList) => {
4246 const folders = [ ] ;
4347 const files = { } ;
4448 fileList . forEach ( ( f ) => {
45- if ( ! f . is_folder && HIDDEN_SYSTEM_FILES . has ( f . name ) ) {
49+ const nameLower = String ( f . name || "" ) . toLowerCase ( ) ;
50+ if ( ! f . is_folder && HIDDEN_SYSTEM_FILES . has ( nameLower ) ) {
4651 return ;
4752 }
4853 if ( f . is_folder ) {
@@ -62,6 +67,7 @@ const transformFiles = (fileList) => {
6267 size : f . size ,
6368 type : f . type ,
6469 is_folder : false ,
70+ physical_path : f . physical_path || null ,
6571 } ) ;
6672 }
6773 } ) ;
@@ -502,14 +508,54 @@ function FilesManager() {
502508 const item = folder || file ;
503509
504510 if ( item ) {
511+ const isMountedFolder =
512+ ! ! folder && folder . parent === "root" && folder . physical_path ;
513+ let descendantFileCount = 0 ;
514+ let descendantFolderCount = 0 ;
515+ let descendantSizeKb = 0 ;
516+
517+ if ( isMountedFolder ) {
518+ const queue = [ folder . key ] ;
519+ while ( queue . length ) {
520+ const parentId = queue . shift ( ) ;
521+ const childFolders = folders . filter ( ( f ) => f . parent === parentId ) ;
522+ descendantFolderCount += childFolders . length ;
523+ childFolders . forEach ( ( f ) => queue . push ( f . key ) ) ;
524+
525+ const childFiles = files [ parentId ] || [ ] ;
526+ descendantFileCount += childFiles . length ;
527+ childFiles . forEach ( ( f ) => {
528+ const sizeStr = String ( f . size || "" ) ;
529+ const match = sizeStr . match ( / ( [ 0 - 9 . ] + ) \s * ( K B | M B | G B | B ) / i) ;
530+ if ( match ) {
531+ const value = parseFloat ( match [ 1 ] ) ;
532+ const unit = match [ 2 ] . toUpperCase ( ) ;
533+ if ( unit === "B" ) descendantSizeKb += value / 1024 ;
534+ if ( unit === "KB" ) descendantSizeKb += value ;
535+ if ( unit === "MB" ) descendantSizeKb += value * 1024 ;
536+ if ( unit === "GB" ) descendantSizeKb += value * 1024 * 1024 ;
537+ }
538+ } ) ;
539+ }
540+ }
541+
542+ const totalSizeStr = isMountedFolder
543+ ? descendantSizeKb > 1024
544+ ? `${ ( descendantSizeKb / 1024 ) . toFixed ( 2 ) } MB`
545+ : `${ descendantSizeKb . toFixed ( 2 ) } KB`
546+ : item . size || "N/A" ;
547+
505548 setPropertiesData ( {
506549 type : "single" ,
507550 name : item . title || item . name ,
508551 isFolder : ! ! folder ,
509- size : item . size || "N/A" ,
552+ size : totalSizeStr ,
510553 fileType : item . type || "Folder" ,
511554 created : new Date ( ) . toLocaleString ( ) , // Backend should provide this
512555 modified : new Date ( ) . toLocaleString ( ) , // Backend should provide this
556+ fileCount : isMountedFolder ? descendantFileCount : undefined ,
557+ folderCount : isMountedFolder ? descendantFolderCount : undefined ,
558+ isMountedFolder,
513559 } ) ;
514560 }
515561 } else {
@@ -921,6 +967,24 @@ function FilesManager() {
921967 ) : (
922968 < div style = { { wordBreak : "break-word" , fontSize : 12 } } >
923969 { item . title || item . name }
970+ { type === "folder" &&
971+ item . parent === "root" &&
972+ item . physical_path && (
973+ < span
974+ style = { {
975+ display : "inline-block" ,
976+ marginLeft : 6 ,
977+ padding : "2px 6px" ,
978+ fontSize : 10 ,
979+ borderRadius : 10 ,
980+ background : "#f0f5ff" ,
981+ color : "#2f54eb" ,
982+ border : "1px solid #adc6ff" ,
983+ } }
984+ >
985+ Mounted
986+ </ span >
987+ ) }
924988 </ div >
925989 ) }
926990 </ div >
@@ -1019,6 +1083,26 @@ function FilesManager() {
10191083 icon : < FolderOpenOutlined /> ,
10201084 } ) ;
10211085 }
1086+ if ( selectedItems . length === 1 ) {
1087+ const selectedFile = Object . values ( files )
1088+ . flat ( )
1089+ . find ( ( f ) => f . key === selectedKey ) ;
1090+ const selectedFolder = folders . find ( ( f ) => f . key === selectedKey ) ;
1091+ const hasPhysicalPath =
1092+ ( selectedFile &&
1093+ selectedFile . physical_path &&
1094+ selectedFile . physical_path . startsWith ( "/" ) ) ||
1095+ ( selectedFolder &&
1096+ selectedFolder . physical_path &&
1097+ selectedFolder . physical_path . startsWith ( "/" ) ) ;
1098+ if ( hasPhysicalPath ) {
1099+ items . push ( {
1100+ key : "reveal_in_finder" ,
1101+ label : "Open in Finder" ,
1102+ icon : < FolderOpenOutlined /> ,
1103+ } ) ;
1104+ }
1105+ }
10221106 items . push (
10231107 {
10241108 key : "rename" ,
@@ -1138,6 +1222,25 @@ function FilesManager() {
11381222 } ) ;
11391223 } ;
11401224
1225+ const handleRevealInFinder = ( key ) => {
1226+ const item =
1227+ folders . find ( ( f ) => f . key === key ) ||
1228+ Object . values ( files )
1229+ . flat ( )
1230+ . find ( ( f ) => f . key === key ) ;
1231+ if ( ! item || ! item . physical_path || ! item . physical_path . startsWith ( "/" ) ) {
1232+ message . warning ( "This item is not linked to a local file." ) ;
1233+ return ;
1234+ }
1235+ try {
1236+ const { ipcRenderer } = window . require ( "electron" ) ;
1237+ ipcRenderer . invoke ( "reveal-in-finder" , item . physical_path ) ;
1238+ } catch ( err ) {
1239+ console . error ( "Reveal in Finder error" , err ) ;
1240+ message . error ( "Failed to open in Finder" ) ;
1241+ }
1242+ } ;
1243+
11411244 return (
11421245 < div
11431246 style = { {
@@ -1425,6 +1528,8 @@ function FilesManager() {
14251528 if ( key === "mount_project" ) handleMountProjectDirectory ( ) ;
14261529 if ( key === "unmount_project" )
14271530 handleUnmountProject ( contextMenu . key ) ;
1531+ if ( key === "reveal_in_finder" )
1532+ handleRevealInFinder ( contextMenu . key ) ;
14281533 if ( key === "rename" ) {
14291534 const item =
14301535 folders . find ( ( f ) => f . key === contextMenu . key ) ||
@@ -1568,6 +1673,30 @@ function FilesManager() {
15681673 < span style = { { fontWeight : 500 } } > Size:</ span >
15691674 < span > { propertiesData . size } </ span >
15701675 </ div >
1676+ { propertiesData . isMountedFolder && (
1677+ < >
1678+ < div
1679+ style = { {
1680+ marginBottom : 12 ,
1681+ display : "flex" ,
1682+ justifyContent : "space-between" ,
1683+ } }
1684+ >
1685+ < span style = { { fontWeight : 500 } } > Folders:</ span >
1686+ < span > { propertiesData . folderCount } </ span >
1687+ </ div >
1688+ < div
1689+ style = { {
1690+ marginBottom : 12 ,
1691+ display : "flex" ,
1692+ justifyContent : "space-between" ,
1693+ } }
1694+ >
1695+ < span style = { { fontWeight : 500 } } > Files:</ span >
1696+ < span > { propertiesData . fileCount } </ span >
1697+ </ div >
1698+ </ >
1699+ ) }
15711700 < div
15721701 style = { {
15731702 marginBottom : 12 ,
0 commit comments