Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
171 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r91//! The app's menu: File, Edit, View, Go, Window and Help, as a desktop app
2//! has. On macOS it is the menu bar at the top of the screen, with g1t's
3//! own menu first; on Windows and Linux it sits under the window's title,
4//! and settings can hide it. The tray's menu (tray.rs) shares its ids, and
5//! every menu event, from either, comes to `handle`.
6
7use tauri::menu::{AboutMetadata, Menu, MenuItem, PredefinedMenuItem, Submenu};
8use tauri::{AppHandle, Wry};
9use tauri_plugin_opener::OpenerExt;
10
11use crate::{links, settings, tray, updates};
12
13const DOCS: &str = "https://docs.g1t.sh/guides/desktop/";
14const STATUS: &str = "https://status.g1t.sh/";
15
16pub fn build(app: &AppHandle) -> tauri::Result<Menu<Wry>> {
17 let separator = || PredefinedMenuItem::separator(app);
18 let item = |id: &str, text: &str, accelerator: Option<&str>| MenuItem::with_id(app, id, text, true, accelerator);
19
20 let settings_item = item("settings", if cfg!(target_os = "macos") { "Settings…" } else { "Settings" }, Some("CmdOrCtrl+,"))?;
21 let check = item("check", "Check for updates…", None)?;
22 let server = item("server", "Use another g1t…", None)?;
23 let quit = item("quit", "Quit g1t", Some("CmdOrCtrl+Q"))?;
24
25 let edit = Submenu::with_items(
26 app,
27 "Edit",
28 true,
29 &[
30 &PredefinedMenuItem::undo(app, None)?,
31 &PredefinedMenuItem::redo(app, None)?,
32 &separator()?,
33 &PredefinedMenuItem::cut(app, None)?,
34 &PredefinedMenuItem::copy(app, None)?,
35 &PredefinedMenuItem::paste(app, None)?,
36 &PredefinedMenuItem::select_all(app, None)?,
37 ],
38 )?;
39 let view = Submenu::with_items(
40 app,
41 "View",
42 true,
43 &[
44 &item("reload", "Reload", Some("CmdOrCtrl+R"))?,
45 &separator()?,
46 &item("zoom-reset", "Actual size", Some("CmdOrCtrl+0"))?,
47 &item("zoom-in", "Zoom in", Some("CmdOrCtrl+="))?,
48 &item("zoom-out", "Zoom out", Some("CmdOrCtrl+-"))?,
49 &separator()?,
50 &PredefinedMenuItem::fullscreen(app, None)?,
51 ],
52 )?;
53 let go = Submenu::with_items(
54 app,
55 "Go",
56 true,
57 &[
58 &item("back", "Back", Some(if cfg!(target_os = "macos") { "Cmd+[" } else { "Alt+Left" }))?,
59 &item("forward", "Forward", Some(if cfg!(target_os = "macos") { "Cmd+]" } else { "Alt+Right" }))?,
60 &separator()?,
61 &item("home", "Home", None)?,
62 &item("notifications", "Notifications", None)?,
63 ],
64 )?;
65 let window = Submenu::with_items(
66 app,
67 "Window",
68 true,
69 &[&PredefinedMenuItem::minimize(app, None)?, &PredefinedMenuItem::maximize(app, None)?],
70 )?;
71 let help = Submenu::with_items(
72 app,
73 "Help",
74 true,
75 &[&item("docs", "Desktop app guide", None)?, &item("status", "g1t.sh status", None)?, &separator()?, &check, &tray::restart_item(app)?],
76 )?;
77 // macOS keeps About in g1t's own menu; elsewhere it closes Help.
78 #[cfg(not(target_os = "macos"))]
79 {
80 help.append(&separator()?)?;
81 help.append(&PredefinedMenuItem::about(app, Some("About g1t"), Some(about()))?)?;
82 }
83
84 #[cfg(target_os = "macos")]
85 {
86 let g1t = Submenu::with_items(
87 app,
88 "g1t",
89 true,
90 &[
91 &PredefinedMenuItem::about(app, Some("About g1t"), Some(about()))?,
92 &separator()?,
93 &settings_item,
94 &server,
95 &separator()?,
96 &PredefinedMenuItem::services(app, None)?,
97 &separator()?,
98 &PredefinedMenuItem::hide(app, None)?,
99 &PredefinedMenuItem::hide_others(app, None)?,
100 &PredefinedMenuItem::show_all(app, None)?,
101 &separator()?,
102 &quit,
103 ],
104 )?;
105 let file = Submenu::with_items(app, "File", true, &[&PredefinedMenuItem::close_window(app, None)?])?;
106 Menu::with_items(app, &[&g1t, &file, &edit, &view, &go, &window, &help])
107 }
108 #[cfg(not(target_os = "macos"))]
109 {
110 let file = Submenu::with_items(
111 app,
112 "File",
113 true,
114 &[&settings_item, &server, &separator()?, &item("close", "Close window", Some("CmdOrCtrl+W"))?, &quit],
115 )?;
116 Menu::with_items(app, &[&file, &edit, &view, &go, &window, &help])
117 }
118}
119
120fn about() -> AboutMetadata<'static> {
121 AboutMetadata {
122 name: Some("g1t".into()),
123 version: Some(env!("CARGO_PKG_VERSION").into()),
124 copyright: Some("Flagon, Inc.".into()),
125 website: Some("https://g1t.sh".into()),
126 website_label: Some("g1t.sh".into()),
127 ..Default::default()
128 }
129}
130
131/// Runs the script on the main window's page.
132fn eval(app: &AppHandle, script: &str) {
133 if let Some(site) = crate::frame::site(app) {
134 let _ = site.eval(script);
135 }
136}
137
138/// A menu row was chosen, from the app's menu or the tray's.
139pub fn handle(app: &AppHandle, id: &str) {
140 match id {
141 "open" => tray::show(app),
The desktop app is 0.3.4, and the runner has a window of its own. Beside the title bar's Settings button a chip says what the runner is doing, live, with a dot in its colour (Runner running, Running a job, Running 2 jobs, Runner starting, Runner updating, Runner stopped, Runner offline, Runner needs you), as Docker Desktop shows its engine; in a narrow window only the dot shows. It opens the Runner window, as the tray's runner row now does: at its top what the whole runner is doing, with what it is running, its version and workspace, and its own Stop or Start; then each kind of job's card as before; then its setup (running jobs here at all, how jobs run, the workspace, the computer with Check for runner updates and View on g1t); and its log, open and following along as it is written. Settings keeps the runner as one line, what it is doing with Open runner, and each window saves only its own settings over what the app has now, so neither undoes the other's. The chip's words are diagnosis.rs's, the Runner window is made off the main thread as Settings now is, and it has a capability of its own with only the commands it uses; the title bar may now ask the runner's status. Two things fixed on the way: a settings row hidden until it applies, Restart to change the title bar, showed all the time, since its row's display beat the hidden attribute; and in a narrow window the title bar's buttons ran over the search, which now shrinks instead. The desktop guide describes the chip, the Runner window and where each runner setting now is.142 "settings" => settings::open(app),
Merge branch 'main' into rm-agents143 "runner-status" => settings::runner_menu(app, false, None),
Merge the desktop app's runner: it starts with the app for the signed-in person, sandboxed by default and running nothing where no sandbox is available yet, registers through the site, keeps itself up to date, and says everywhere what it is doing, why it is not, and how to fix it.144 "runner-toggle" => crate::runner::toggle(app),
Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9145 "server" => tray::launcher(app, "change"),
Merge branch 'main' into rm-agents146 // The settings ask, and show the answer where it cannot be missed.
Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9147 "check" => settings::open_and_check(app),
148 "restart" => updates::restart(app),
149 "quit" => updates::quit(app),
150 "close" => tray::close(app),
151 "reload" => {
152 if let Some(site) = crate::frame::site(app) {
153 let _ = site.reload();
154 }
155 }
156 "zoom-in" => settings::zoom(app, 1),
157 "zoom-out" => settings::zoom(app, -1),
158 "zoom-reset" => settings::zoom(app, 0),
159 "back" => eval(app, "history.back()"),
160 "forward" => eval(app, "history.forward()"),
161 "home" => links::go(app, "/"),
162 "notifications" => links::go(app, "/notifications"),
163 "docs" => {
164 let _ = app.opener().open_url(DOCS, None::<&str>);
165 }
166 "status" => {
167 let _ = app.opener().open_url(STATUS, None::<&str>);
168 }
169 _ => {}
170 }
171}

This file's history is long; its oldest lines are credited to the oldest commit read.