@@ -21,6 +21,7 @@ import {
21
21
currentFileFromContent ,
22
22
CurrentTextFile ,
23
23
exportedUris ,
24
+ getWsFolder ,
24
25
handleError ,
25
26
isClassDeployed ,
26
27
isClassOrRtn ,
@@ -746,162 +747,150 @@ interface XMLQuickPickItem extends vscode.QuickPickItem {
746
747
export async function importXMLFiles ( ) : Promise < any > {
747
748
try {
748
749
// 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 ;
764
773
}
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" ) {
769
780
vscode . window . showErrorMessage (
770
- "'Import XML Files...' command requires an active server connection ." ,
781
+ "'Import XML Files...' command is not supported for unsaved workspaces ." ,
771
782
"Dismiss"
772
783
) ;
773
784
return ;
774
785
}
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 ]
780
817
) ;
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 ;
794
837
}
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 ) =>
854
849
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 ) } ` : "" } `,
857
855
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
+ ) ;
899
858
}
900
- return file . imported ;
859
+ return items ;
901
860
} ) ;
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 ;
904
869
}
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 ) ;
905
894
} catch ( error ) {
906
895
handleError ( error , "Error executing 'Import XML Files...' command." ) ;
907
896
}
0 commit comments