@@ -21,6 +21,7 @@ import {
2121 currentFileFromContent ,
2222 CurrentTextFile ,
2323 exportedUris ,
24+ getWsFolder ,
2425 handleError ,
2526 isClassDeployed ,
2627 isClassOrRtn ,
@@ -746,162 +747,150 @@ interface XMLQuickPickItem extends vscode.QuickPickItem {
746747export async function importXMLFiles ( ) : Promise < any > {
747748 try {
748749 // Use the server connection from a workspace folder
749- let connectionUri : vscode . Uri ;
750- const workspaceFolders = vscode . workspace . workspaceFolders || [ ] ;
751- if ( workspaceFolders . length == 0 ) {
752- vscode . window . showErrorMessage ( "'Import XML Files...' command requires an open workspace." , "Dismiss" ) ;
753- } else if ( workspaceFolders . length == 1 ) {
754- // Use the current connection
755- connectionUri = workspaceFolders [ 0 ] . uri ;
756- } else {
757- // Pick from the workspace folders
758- connectionUri = (
759- await vscode . window . showWorkspaceFolderPick ( {
760- ignoreFocusOut : true ,
761- placeHolder : "Pick a workspace folder. Server-side folders import from the local file system." ,
762- } )
763- ) ?. uri ;
750+ const wsFolder = await getWsFolder (
751+ "Pick a workspace folder. Server-side folders import from the local file system."
752+ ) ;
753+ if ( ! wsFolder ) {
754+ if ( wsFolder === undefined ) {
755+ // Strict equality needed because undefined == null
756+ vscode . window . showErrorMessage ( "'Import XML Files...' command requires an open workspace." , "Dismiss" ) ;
757+ }
758+ return ;
759+ }
760+ const api = new AtelierAPI ( wsFolder . uri ) ;
761+ // Make sure the server connection is active
762+ if ( ! api . active || api . ns == "" ) {
763+ vscode . window . showErrorMessage ( "'Import XML Files...' command requires an active server connection." , "Dismiss" ) ;
764+ return ;
765+ }
766+ // Make sure the server has the xml endpoints
767+ if ( api . config . apiVersion < 7 ) {
768+ vscode . window . showErrorMessage (
769+ "'Import XML Files...' command requires InterSystems IRIS version 2023.2 or above." ,
770+ "Dismiss"
771+ ) ;
772+ return ;
764773 }
765- if ( connectionUri ) {
766- const api = new AtelierAPI ( connectionUri ) ;
767- // Make sure the server connection is active
768- if ( ! api . active || api . ns == "" ) {
774+ let defaultUri = wsFolder . uri ;
775+ if ( defaultUri . scheme == FILESYSTEM_SCHEMA ) {
776+ // Need a default URI without the isfs scheme or the open dialog
777+ // will show the server-side files instead of local ones
778+ defaultUri = vscode . workspace . workspaceFile ;
779+ if ( defaultUri . scheme != "file" ) {
769780 vscode . window . showErrorMessage (
770- "'Import XML Files...' command requires an active server connection ." ,
781+ "'Import XML Files...' command is not supported for unsaved workspaces ." ,
771782 "Dismiss"
772783 ) ;
773784 return ;
774785 }
775- // Make sure the server has the xml endpoints
776- if ( api . config . apiVersion < 7 ) {
777- vscode . window . showErrorMessage (
778- "'Import XML Files...' command requires InterSystems IRIS version 2023.2 or above." ,
779- "Dismiss"
786+ // Remove the file name from the URI
787+ defaultUri = defaultUri . with ( { path : defaultUri . path . split ( "/" ) . slice ( 0 , - 1 ) . join ( "/" ) } ) ;
788+ }
789+ // Prompt the user the file to import
790+ let uris = await vscode . window . showOpenDialog ( {
791+ canSelectFiles : true ,
792+ canSelectFolders : false ,
793+ canSelectMany : true ,
794+ openLabel : "Import" ,
795+ filters : {
796+ "XML Files" : [ "xml" ] ,
797+ } ,
798+ defaultUri,
799+ } ) ;
800+ if ( ! Array . isArray ( uris ) || uris . length == 0 ) {
801+ // No file to import
802+ return ;
803+ }
804+ // Filter out non-XML files
805+ uris = uris . filter ( ( uri ) => uri . path . split ( "." ) . pop ( ) . toLowerCase ( ) == "xml" ) ;
806+ if ( uris . length == 0 ) {
807+ vscode . window . showErrorMessage ( "No XML files were selected." , "Dismiss" ) ;
808+ return ;
809+ }
810+ // Read the XML files
811+ const fileTimestamps : Map < string , string > = new Map ( ) ;
812+ const filesToList = await Promise . allSettled (
813+ uris . map ( async ( uri ) => {
814+ fileTimestamps . set (
815+ uri . fsPath ,
816+ new Date ( ( await vscode . workspace . fs . stat ( uri ) ) . mtime ) . toISOString ( ) . replace ( "T" , " " ) . split ( "." ) [ 0 ]
780817 ) ;
781- return ;
782- }
783- let defaultUri = vscode . workspace . getWorkspaceFolder ( connectionUri ) ?. uri ?? connectionUri ;
784- if ( defaultUri . scheme == FILESYSTEM_SCHEMA ) {
785- // Need a default URI without the isfs scheme or the open dialog
786- // will show the server-side files instead of local ones
787- defaultUri = vscode . workspace . workspaceFile ;
788- if ( defaultUri . scheme != "file" ) {
789- vscode . window . showErrorMessage (
790- "'Import XML Files...' command is not supported for unsaved workspaces." ,
791- "Dismiss"
792- ) ;
793- return ;
818+ return {
819+ file : uri . fsPath ,
820+ content : new TextDecoder ( ) . decode ( await vscode . workspace . fs . readFile ( uri ) ) . split ( / \r ? \n / ) ,
821+ } ;
822+ } )
823+ ) . then ( ( results ) => results . map ( ( result ) => ( result . status == "fulfilled" ? result . value : null ) ) . filter ( notNull ) ) ;
824+ if ( filesToList . length == 0 ) {
825+ return ;
826+ }
827+ // List the documents in the XML files
828+ const documentsPerFile = await api . actionXMLList ( filesToList ) . then ( ( data ) => data . result . content ) ;
829+ // Prompt the user to select documents to import
830+ const quickPickItems = documentsPerFile
831+ . filter ( ( file ) => {
832+ if ( file . status != "" ) {
833+ outputChannel . appendLine ( `Failed to list documents in file '${ file . file } ': ${ file . status } ` ) ;
834+ return false ;
835+ } else {
836+ return true ;
794837 }
795- // Remove the file name from the URI
796- defaultUri = defaultUri . with ( { path : defaultUri . path . split ( "/" ) . slice ( 0 , - 1 ) . join ( "/" ) } ) ;
797- }
798- // Prompt the user the file to import
799- let uris = await vscode . window . showOpenDialog ( {
800- canSelectFiles : true ,
801- canSelectFolders : false ,
802- canSelectMany : true ,
803- openLabel : "Import" ,
804- filters : {
805- "XML Files" : [ "xml" ] ,
806- } ,
807- defaultUri,
808- } ) ;
809- if ( ! Array . isArray ( uris ) || uris . length == 0 ) {
810- // No file to import
811- return ;
812- }
813- // Filter out non-XML files
814- uris = uris . filter ( ( uri ) => uri . path . split ( "." ) . pop ( ) . toLowerCase ( ) == "xml" ) ;
815- if ( uris . length == 0 ) {
816- vscode . window . showErrorMessage ( "No XML files were selected." , "Dismiss" ) ;
817- return ;
818- }
819- // Read the XML files
820- const fileTimestamps : Map < string , string > = new Map ( ) ;
821- const filesToList = await Promise . allSettled (
822- uris . map ( async ( uri ) => {
823- fileTimestamps . set (
824- uri . fsPath ,
825- new Date ( ( await vscode . workspace . fs . stat ( uri ) ) . mtime ) . toISOString ( ) . replace ( "T" , " " ) . split ( "." ) [ 0 ]
826- ) ;
827- return {
828- file : uri . fsPath ,
829- content : new TextDecoder ( ) . decode ( await vscode . workspace . fs . readFile ( uri ) ) . split ( / \r ? \n / ) ,
830- } ;
831- } )
832- ) . then ( ( results ) =>
833- results . map ( ( result ) => ( result . status == "fulfilled" ? result . value : null ) ) . filter ( notNull )
834- ) ;
835- if ( filesToList . length == 0 ) {
836- return ;
837- }
838- // List the documents in the XML files
839- const documentsPerFile = await api . actionXMLList ( filesToList ) . then ( ( data ) => data . result . content ) ;
840- // Prompt the user to select documents to import
841- const quickPickItems = documentsPerFile
842- . filter ( ( file ) => {
843- if ( file . status != "" ) {
844- outputChannel . appendLine ( `Failed to list documents in file '${ file . file } ': ${ file . status } ` ) ;
845- return false ;
846- } else {
847- return true ;
848- }
849- } )
850- . flatMap ( ( file ) => {
851- const items : XMLQuickPickItem [ ] = [ ] ;
852- if ( file . documents . length > 0 ) {
853- // Add a separator for this file
838+ } )
839+ . flatMap ( ( file ) => {
840+ const items : XMLQuickPickItem [ ] = [ ] ;
841+ if ( file . documents . length > 0 ) {
842+ // Add a separator for this file
843+ items . push ( {
844+ label : file . file ,
845+ kind : vscode . QuickPickItemKind . Separator ,
846+ file : file . file ,
847+ } ) ;
848+ file . documents . forEach ( ( doc ) =>
854849 items . push ( {
855- label : file . file ,
856- kind : vscode . QuickPickItemKind . Separator ,
850+ label : doc . name ,
851+ picked : true ,
852+ detail : `${
853+ doc . ts . toString ( ) != "-1" ? `Server timestamp: ${ doc . ts . split ( "." ) [ 0 ] } ` : "Does not exist on server"
854+ } , ${ fileTimestamps . has ( file . file ) ? `File timestamp: ${ fileTimestamps . get ( file . file ) } ` : "" } `,
857855 file : file . file ,
858- } ) ;
859- file . documents . forEach ( ( doc ) =>
860- items . push ( {
861- label : doc . name ,
862- picked : true ,
863- detail : `${
864- doc . ts . toString ( ) != "-1" ? `Server timestamp: ${ doc . ts . split ( "." ) [ 0 ] } ` : "Does not exist on server"
865- } , ${ fileTimestamps . has ( file . file ) ? `File timestamp: ${ fileTimestamps . get ( file . file ) } ` : "" } `,
866- file : file . file ,
867- } )
868- ) ;
869- }
870- return items ;
871- } ) ;
872- // Prompt the user for documents to import
873- const docsToImport = await vscode . window . showQuickPick ( quickPickItems , {
874- canPickMany : true ,
875- ignoreFocusOut : true ,
876- title : `Select the documents to import into namespace '${ api . ns . toUpperCase ( ) } ' on server '${ api . serverId } '` ,
877- } ) ;
878- if ( docsToImport == undefined || docsToImport . length == 0 ) {
879- return ;
880- }
881- if ( filesystemSchemas . includes ( connectionUri . scheme ) ) {
882- // The user is importing into a server-side folder, so fire source control hook
883- await new StudioActions ( ) . fireImportUserAction ( api , [ ...new Set ( docsToImport . map ( ( qpi ) => qpi . label ) ) ] ) ;
884- }
885- // Import the selected documents
886- const filesToLoad : { file : string ; content : string [ ] ; selected : string [ ] } [ ] = filesToList . map ( ( f ) => {
887- return { selected : [ ] , ...f } ;
888- } ) ;
889- docsToImport . forEach ( ( qpi ) =>
890- // This is safe because every document came from a file
891- filesToLoad [ filesToLoad . findIndex ( ( f ) => f . file == qpi . file ) ] . selected . push ( qpi . label )
892- ) ;
893- const importedPerFile = await api
894- . actionXMLLoad ( filesToLoad . filter ( ( f ) => f . selected . length > 0 ) )
895- . then ( ( data ) => data . result . content ) ;
896- const imported = importedPerFile . flatMap ( ( file ) => {
897- if ( file . status != "" ) {
898- outputChannel . appendLine ( `Importing documents from file '${ file . file } ' produced error: ${ file . status } ` ) ;
856+ } )
857+ ) ;
899858 }
900- return file . imported ;
859+ return items ;
901860 } ) ;
902- // Prompt the user for compilation
903- promptForCompile ( [ ...new Set ( imported ) ] , api , filesystemSchemas . includes ( connectionUri . scheme ) ) ;
861+ // Prompt the user for documents to import
862+ const docsToImport = await vscode . window . showQuickPick ( quickPickItems , {
863+ canPickMany : true ,
864+ ignoreFocusOut : true ,
865+ title : `Select the documents to import into namespace '${ api . ns . toUpperCase ( ) } ' on server '${ api . serverId } '` ,
866+ } ) ;
867+ if ( docsToImport == undefined || docsToImport . length == 0 ) {
868+ return ;
904869 }
870+ const isIsfs = filesystemSchemas . includes ( wsFolder . uri . scheme ) ;
871+ if ( isIsfs ) {
872+ // The user is importing into a server-side folder, so fire source control hook
873+ await new StudioActions ( ) . fireImportUserAction ( api , [ ...new Set ( docsToImport . map ( ( qpi ) => qpi . label ) ) ] ) ;
874+ }
875+ // Import the selected documents
876+ const filesToLoad : { file : string ; content : string [ ] ; selected : string [ ] } [ ] = filesToList . map ( ( f ) => {
877+ return { selected : [ ] , ...f } ;
878+ } ) ;
879+ docsToImport . forEach ( ( qpi ) =>
880+ // This is safe because every document came from a file
881+ filesToLoad [ filesToLoad . findIndex ( ( f ) => f . file == qpi . file ) ] . selected . push ( qpi . label )
882+ ) ;
883+ const importedPerFile = await api
884+ . actionXMLLoad ( filesToLoad . filter ( ( f ) => f . selected . length > 0 ) )
885+ . then ( ( data ) => data . result . content ) ;
886+ const imported = importedPerFile . flatMap ( ( file ) => {
887+ if ( file . status != "" ) {
888+ outputChannel . appendLine ( `Importing documents from file '${ file . file } ' produced error: ${ file . status } ` ) ;
889+ }
890+ return file . imported ;
891+ } ) ;
892+ // Prompt the user for compilation
893+ promptForCompile ( [ ...new Set ( imported ) ] , api , isIsfs ) ;
905894 } catch ( error ) {
906895 handleError ( error , "Error executing 'Import XML Files...' command." ) ;
907896 }
0 commit comments