@@ -1040,6 +1040,14 @@ pub async fn show_item_in_folder(args: Args) -> Value {
10401040// come back as Ok(Value::String("error_code")) the renderer can
10411041// display.
10421042
1043+ fn export_file_name_for ( now : chrono:: DateTime < chrono:: Local > ) -> String {
1044+ format ! ( "switchhosts_{}.json" , now. format( "%Y%m%d_%H%M%S%.3f" ) )
1045+ }
1046+
1047+ fn default_export_file_name ( ) -> String {
1048+ export_file_name_for ( chrono:: Local :: now ( ) )
1049+ }
1050+
10431051#[ tauri:: command]
10441052pub async fn export_data < R : Runtime > (
10451053 app : AppHandle < R > ,
@@ -1050,7 +1058,7 @@ pub async fn export_data<R: Runtime>(
10501058 . dialog ( )
10511059 . file ( )
10521060 . add_filter ( "JSON" , & [ "json" ] )
1053- . set_file_name ( "swh_data.json" )
1061+ . set_file_name ( & default_export_file_name ( ) )
10541062 . blocking_save_file ( ) ;
10551063
10561064 let Some ( dest) = picked else {
@@ -1070,6 +1078,28 @@ pub async fn export_data<R: Runtime>(
10701078 Ok ( Value :: String ( dest_path. display ( ) . to_string ( ) ) )
10711079}
10721080
1081+ #[ cfg( test) ]
1082+ mod export_file_name_tests {
1083+ use chrono:: { TimeZone , Timelike } ;
1084+
1085+ use super :: export_file_name_for;
1086+
1087+ #[ test]
1088+ fn includes_millisecond_timestamp ( ) {
1089+ let now = chrono:: Local
1090+ . with_ymd_and_hms ( 2026 , 5 , 9 , 12 , 14 , 36 )
1091+ . single ( )
1092+ . expect ( "test timestamp should be representable" )
1093+ . with_nanosecond ( 789_000_000 )
1094+ . expect ( "test nanosecond should be valid" ) ;
1095+
1096+ assert_eq ! (
1097+ export_file_name_for( now) ,
1098+ "switchhosts_20260509_121436.789.json"
1099+ ) ;
1100+ }
1101+ }
1102+
10731103#[ tauri:: command]
10741104pub async fn import_data < R : Runtime > (
10751105 app : AppHandle < R > ,
0 commit comments