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
177 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)?,
The desktop app has developer tools: a Developer tools setting, off unless someone turns it on under Window in the app's settings, lets F12 on the page, Ctrl+Shift+I (⌥⌘I on macOS) and the View menu's new Developer tools row open the web inspector for the site's page, so a page that says something went wrong can be looked into from its console. Release builds have the inspector through Tauri's devtools feature, which on macOS reaches it through WebKit's private API, so the app could not go in the Mac App Store; it ships from g1t.sh. With the setting off none of these open it, and the menu row is greyed out. On Windows the setting takes effect at once, WebView2's own F12, Ctrl+Shift+I and Inspect following it; WebKit on macOS and Linux keeps what the page's web view was made with, so there the settings offer Restart now, as they do for the title bar. The site can open it too, through window.g1tDesktop.devtools.open(), a new open_devtools command that answers only the server's page in the window and only while the setting is on, granted to the server's origin alone. The settings window and the Runner window keep the setting when they save, and the desktop app guide says how to turn it on and open it.51 &separator()?,
52 &crate::devtools::item(app)?,
Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r953 ],
54 )?;
55 let go = Submenu::with_items(
56 app,
57 "Go",
58 true,
59 &[
60 &item("back", "Back", Some(if cfg!(target_os = "macos") { "Cmd+[" } else { "Alt+Left" }))?,
61 &item("forward", "Forward", Some(if cfg!(target_os = "macos") { "Cmd+]" } else { "Alt+Right" }))?,
62 &separator()?,
63 &item("home", "Home", None)?,
64 &item("notifications", "Notifications", None)?,
65 ],
66 )?;
67 let window = Submenu::with_items(
68 app,
69 "Window",
70 true,
71 &[&PredefinedMenuItem::minimize(app, None)?, &PredefinedMenuItem::maximize(app, None)?],
72 )?;
73 let help = Submenu::with_items(
74 app,
75 "Help",
76 true,
77 &[&item("docs", "Desktop app guide", None)?, &item("status", "g1t.sh status", None)?, &separator()?, &check, &tray::restart_item(app)?],
78 )?;
79 // macOS keeps About in g1t's own menu; elsewhere it closes Help.
80 #[cfg(not(target_os = "macos"))]
81 {
82 help.append(&separator()?)?;
83 help.append(&PredefinedMenuItem::about(app, Some("About g1t"), Some(about()))?)?;
84 }
85
86 #[cfg(target_os = "macos")]
87 {
88 let g1t = Submenu::with_items(
89 app,
90 "g1t",
91 true,
92 &[
93 &PredefinedMenuItem::about(app, Some("About g1t"), Some(about()))?,
94 &separator()?,
95 &settings_item,
96 &server,
97 &separator()?,
98 &PredefinedMenuItem::services(app, None)?,
99 &separator()?,
100 &PredefinedMenuItem::hide(app, None)?,
101 &PredefinedMenuItem::hide_others(app, None)?,
102 &PredefinedMenuItem::show_all(app, None)?,
103 &separator()?,
104 &quit,
105 ],
106 )?;
107 let file = Submenu::with_items(app, "File", true, &[&PredefinedMenuItem::close_window(app, None)?])?;
108 Menu::with_items(app, &[&g1t, &file, &edit, &view, &go, &window, &help])
109 }
110 #[cfg(not(target_os = "macos"))]
111 {
112 let file = Submenu::with_items(
113 app,
114 "File",
115 true,
116 &[&settings_item, &server, &separator()?, &item("close", "Close window", Some("CmdOrCtrl+W"))?, &quit],
117 )?;
118 Menu::with_items(app, &[&file, &edit, &view, &go, &window, &help])
119 }
120}
121
122fn about() -> AboutMetadata<'static> {
123 AboutMetadata {
124 name: Some("g1t".into()),
125 version: Some(env!("CARGO_PKG_VERSION").into()),
126 copyright: Some("Flagon, Inc.".into()),
127 website: Some("https://g1t.sh".into()),
128 website_label: Some("g1t.sh".into()),
129 ..Default::default()
130 }
131}
132
133/// Runs the script on the main window's page.
134fn eval(app: &AppHandle, script: &str) {
135 if let Some(site) = crate::frame::site(app) {
136 let _ = site.eval(script);
137 }
138}
139
140/// A menu row was chosen, from the app's menu or the tray's.
141pub fn handle(app: &AppHandle, id: &str) {
142 match id {
143 "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.144 "settings" => settings::open(app),
Merge branch 'main' into rm-agents145 "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.146 "runner-toggle" => crate::runner::toggle(app),
Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9147 "server" => tray::launcher(app, "change"),
Merge branch 'main' into rm-agents148 // 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-7nm8r9149 "check" => settings::open_and_check(app),
150 "restart" => updates::restart(app),
151 "quit" => updates::quit(app),
152 "close" => tray::close(app),
153 "reload" => {
154 if let Some(site) = crate::frame::site(app) {
155 let _ = site.reload();
156 }
157 }
158 "zoom-in" => settings::zoom(app, 1),
159 "zoom-out" => settings::zoom(app, -1),
160 "zoom-reset" => settings::zoom(app, 0),
The desktop app has developer tools: a Developer tools setting, off unless someone turns it on under Window in the app's settings, lets F12 on the page, Ctrl+Shift+I (⌥⌘I on macOS) and the View menu's new Developer tools row open the web inspector for the site's page, so a page that says something went wrong can be looked into from its console. Release builds have the inspector through Tauri's devtools feature, which on macOS reaches it through WebKit's private API, so the app could not go in the Mac App Store; it ships from g1t.sh. With the setting off none of these open it, and the menu row is greyed out. On Windows the setting takes effect at once, WebView2's own F12, Ctrl+Shift+I and Inspect following it; WebKit on macOS and Linux keeps what the page's web view was made with, so there the settings offer Restart now, as they do for the title bar. The site can open it too, through window.g1tDesktop.devtools.open(), a new open_devtools command that answers only the server's page in the window and only while the setting is on, granted to the server's origin alone. The settings window and the Runner window keep the setting when they save, and the desktop app guide says how to turn it on and open it.161 // Off with the setting, as the row is.
162 "devtools" => {
163 let _ = crate::devtools::toggle(app);
164 }
Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9165 "back" => eval(app, "history.back()"),
166 "forward" => eval(app, "history.forward()"),
167 "home" => links::go(app, "/"),
168 "notifications" => links::go(app, "/notifications"),
169 "docs" => {
170 let _ = app.opener().open_url(DOCS, None::<&str>);
171 }
172 "status" => {
173 let _ = app.opener().open_url(STATUS, None::<&str>);
174 }
175 _ => {}
176 }
177}

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