@@ -20,7 +20,7 @@ use serde_json::json;
2020use std:: collections:: { HashMap , HashSet } ;
2121use std:: sync:: Mutex ;
2222use std:: time:: { SystemTime , UNIX_EPOCH } ;
23- use tauri:: menu:: { MenuBuilder , MenuItem , SubmenuBuilder } ;
23+ use tauri:: menu:: { AboutMetadata , MenuBuilder , MenuItem , PredefinedMenuItem , SubmenuBuilder } ;
2424use tauri:: plugin:: { Builder as PluginBuilder , TauriPlugin } ;
2525use tauri:: webview:: { PageLoadEvent , Webview } ;
2626use tauri:: {
@@ -42,6 +42,7 @@ use std::os::windows::ffi::OsStrExt;
4242use windows_sys:: Win32 :: UI :: Shell :: SetCurrentProcessExplicitAppUserModelID ;
4343
4444const ZOOM_STEP : f64 = 0.1 ;
45+ const RELEASES_URL : & str = "https://github.com/NeuralNomadsAI/CodeNomad/releases/latest" ;
4546const LOCAL_WINDOW_CONTEXT_SCRIPT : & str = "window.__CODENOMAD_WINDOW_CONTEXT__ = 'local';" ;
4647const REMOTE_WINDOW_CONTEXT_SCRIPT : & str = "window.__CODENOMAD_WINDOW_CONTEXT__ = 'remote';" ;
4748
@@ -722,11 +723,15 @@ fn main() {
722723 }
723724 }
724725
725- // App menu (macOS)
726- "about" => {
727- // TODO: Implement about dialog
728- println ! ( "About menu item clicked" ) ;
726+ "get_updates" => {
727+ if let Err ( err) = app_handle
728+ . opener ( )
729+ . open_url ( RELEASES_URL , None :: < & str > )
730+ {
731+ eprintln ! ( "[tauri] failed to open the CodeNomad releases page: {err}" ) ;
732+ }
729733 }
734+ // App menu (macOS)
730735 "hide" => {
731736 if let Some ( window) = app_handle. get_webview_window ( "main" ) {
732737 let _ = window. hide ( ) ;
@@ -827,11 +832,24 @@ fn build_menu(app: &AppHandle) -> tauri::Result<()> {
827832
828833 // Create submenus
829834 let mut submenus = Vec :: new ( ) ;
835+ let about_item = PredefinedMenuItem :: about (
836+ app,
837+ Some ( "About CodeNomad" ) ,
838+ Some ( build_about_metadata ( & app. package_info ( ) . version . to_string ( ) ) ) ,
839+ ) ?;
840+ let get_updates_item = MenuItem :: with_id (
841+ app,
842+ "get_updates" ,
843+ "Get Updates..." ,
844+ true ,
845+ None :: < & str > ,
846+ ) ?;
830847
831848 // App menu (macOS only)
832849 if is_mac {
833850 let app_menu = SubmenuBuilder :: new ( app, "CodeNomad" )
834- . text ( "about" , "About CodeNomad" )
851+ . item ( & about_item)
852+ . item ( & get_updates_item)
835853 . separator ( )
836854 . text ( "hide" , "Hide CodeNomad" )
837855 . text ( "hide_others" , "Hide Others" )
@@ -969,6 +987,15 @@ fn build_menu(app: &AppHandle) -> tauri::Result<()> {
969987 } ;
970988 submenus. push ( window_menu) ;
971989
990+ if !is_mac {
991+ let help_menu = SubmenuBuilder :: new ( app, "Help" )
992+ . item ( & get_updates_item)
993+ . separator ( )
994+ . item ( & about_item)
995+ . build ( ) ?;
996+ submenus. push ( help_menu) ;
997+ }
998+
972999 // Build the main menu with all submenus
9731000 let submenu_refs: Vec < & dyn tauri:: menu:: IsMenuItem < _ > > = submenus
9741001 . iter ( )
@@ -979,3 +1006,31 @@ fn build_menu(app: &AppHandle) -> tauri::Result<()> {
9791006 app. set_menu ( menu) ?;
9801007 Ok ( ( ) )
9811008}
1009+
1010+ fn build_about_metadata ( version : & str ) -> AboutMetadata < ' static > {
1011+ AboutMetadata {
1012+ name : Some ( "CodeNomad" . to_string ( ) ) ,
1013+ version : Some ( version. to_string ( ) ) ,
1014+ authors : Some ( vec ! [ "Neural Nomads AI" . to_string( ) ] ) ,
1015+ comments : Some ( "A desktop workspace for OpenCode." . to_string ( ) ) ,
1016+ license : Some ( "MIT" . to_string ( ) ) ,
1017+ website : Some ( RELEASES_URL . to_string ( ) ) ,
1018+ website_label : Some ( "Get updates" . to_string ( ) ) ,
1019+ ..Default :: default ( )
1020+ }
1021+ }
1022+
1023+ #[ cfg( test) ]
1024+ mod about_tests {
1025+ use super :: { build_about_metadata, RELEASES_URL } ;
1026+
1027+ #[ test]
1028+ fn about_metadata_includes_version_and_update_link ( ) {
1029+ let metadata = build_about_metadata ( "1.2.3" ) ;
1030+
1031+ assert_eq ! ( metadata. name. as_deref( ) , Some ( "CodeNomad" ) ) ;
1032+ assert_eq ! ( metadata. version. as_deref( ) , Some ( "1.2.3" ) ) ;
1033+ assert_eq ! ( metadata. website. as_deref( ) , Some ( RELEASES_URL ) ) ;
1034+ assert_eq ! ( metadata. website_label. as_deref( ) , Some ( "Get updates" ) ) ;
1035+ }
1036+ }
0 commit comments