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.
17 files+247−100/17 viewed
| 450 | 450 | ||
| 451 | 451 | // Every setting, as the app has it now (the settings window changes the | |
| 452 | 452 | // rest), with the runner's own as they are on the page. | |
| 453 | − | var KEPT = ["startHidden", "closeToTray", "notifications", "flash", "badge", "systemTitleBar", "autoUpdate", "zoom", "runner", "runnerBackend", "runnerWorkspace", "runnerCapabilities"]; | |
| 453 | + | var KEPT = ["startHidden", "closeToTray", "notifications", "flash", "badge", "systemTitleBar", "autoUpdate", "zoom", "developerTools", "runner", "runnerBackend", "runnerWorkspace", "runnerCapabilities"]; | |
| 454 | 454 | function save() { | |
| 455 | 455 | invoke("get_settings") | |
| 456 | 456 | .then(function (fresh) { |
| 8 | 8 | (function () { | |
| 9 | 9 | var SWITCHES = ["startHidden", "closeToTray", "notifications", "flash", "badge", "systemTitleBar", "autoUpdate"]; | |
| 10 | 10 | // The settings the app keeps (src/settings.rs Settings); a save sends them all. | |
| 11 | − | var KEPT = SWITCHES.concat(["zoom", "runner", "runnerBackend", "runnerWorkspace", "runnerCapabilities"]); | |
| 11 | + | var KEPT = SWITCHES.concat(["zoom", "developerTools", "runner", "runnerBackend", "runnerWorkspace", "runnerCapabilities"]); | |
| 12 | 12 | var current = null; | |
| 13 | 13 | ||
| 14 | 14 | function byId(id) { |
| 1350 | 1350 | "tauri-plugin-window-state", | |
| 1351 | 1351 | "tokio", | |
| 1352 | 1352 | "url", | |
| 1353 | + | "webview2-com", | |
| 1353 | 1354 | ] | |
| 1354 | 1355 | ||
| 1355 | 1356 | [[package]] |
| 17 | 17 | ||
| 18 | 18 | [dependencies] | |
| 19 | 19 | # `unstable`: a window holding more than one web view, so the title bar | |
| 20 | − | # and the site sit one above the other (src/frame.rs). | |
| 21 | − | tauri = { version = "2", features = ["tray-icon", "image-png", "unstable"] } | |
| 20 | + | # and the site sit one above the other (src/frame.rs). `devtools`: the web | |
| 21 | + | # inspector in release builds too, which the Developer tools setting turns | |
| 22 | + | # on (src/devtools.rs). On macOS it reaches it through WebKit's private | |
| 23 | + | # API, which the Mac App Store refuses; g1t ships from g1t.sh, not there. | |
| 24 | + | tauri = { version = "2", features = ["tray-icon", "image-png", "unstable", "devtools"] } | |
| 22 | 25 | # Updates: a signed manifest at g1t.sh/downloads/desktop/latest.json. | |
| 23 | 26 | tauri-plugin-updater = "2" | |
| 24 | 27 | # Native notifications, from the site's live feed. | |
| ⋯ | |||
| 51 | 54 | [target.'cfg(target_os = "linux")'.dependencies] | |
| 52 | 55 | gtk = "0.18" | |
| 53 | 56 | ||
| 57 | + | # Turning WebView2's own inspector on and off while g1t runs | |
| 58 | + | # (src/devtools.rs); the same WebView2 bindings that Tauri brings. | |
| 59 | + | [target.'cfg(windows)'.dependencies] | |
| 60 | + | webview2-com = "0.39" | |
| 61 | + | ||
| 54 | 62 | [profile.release] | |
| 55 | 63 | strip = "debuginfo" | |
| 56 | 64 | lto = "thin" | |
| 29 | 29 | "runner_register", | |
| 30 | 30 | "runner_control", | |
| 31 | 31 | "site_ready", | |
| 32 | + | "open_devtools", | |
| 32 | 33 | ]))) | |
| 33 | 34 | .expect("the app's build could not be prepared"); | |
| 34 | 35 | } |
| 160 | 160 | report(); | |
| 161 | 161 | }, | |
| 162 | 162 | }), | |
| 163 | + | // The web inspector for this page, while Developer tools is on in the | |
| 164 | + | // app's settings (src/devtools.rs); rejects with where to turn it on | |
| 165 | + | // while it is off. | |
| 166 | + | devtools: Object.freeze({ | |
| 167 | + | open: function () { | |
| 168 | + | return invoke("open_devtools"); | |
| 169 | + | }, | |
| 170 | + | }), | |
| 163 | 171 | // The title bar's search, in its middle: the site hands it a label | |
| 164 | 172 | // ("Search Flagon") and what opens its search. Returns what takes it away. | |
| 165 | 173 | setSearch: function (label, open) { | |
| ⋯ | |||
| 271 | 279 | return typeof open === "function" ? open.call(window, href, target, features) : null; | |
| 272 | 280 | }; | |
| 273 | 281 | ||
| 282 | + | // F12 opens the web inspector, or closes it, while Developer tools is on; | |
| 283 | + | // the View menu's row has Ctrl+Shift+I (⌥⌘I on macOS). With it off, or | |
| 284 | + | // on a page that isn't the site's, the app says no and the key is the | |
| 285 | + | // page's as ever. | |
| 286 | + | document.addEventListener( | |
| 287 | + | "keydown", | |
| 288 | + | function (event) { | |
| 289 | + | if (event.key !== "F12" || event.ctrlKey || event.metaKey || event.altKey || event.shiftKey) return; | |
| 290 | + | invoke("open_devtools", { toggle: true }).catch(function () {}); | |
| 291 | + | }, | |
| 292 | + | true, | |
| 293 | + | ); | |
| 294 | + | ||
| 274 | 295 | // ── The title bar ───────────────────────────────────────────────────── | |
| 275 | 296 | // What the bar above the page shows of it: the title, the search the | |
| 276 | 297 | // site handed over (`setSearch`), whether there is a page to go back or | |
| 13 | 13 | use url::Url; | |
| 14 | 14 | ||
| 15 | 15 | use crate::settings::{self, Settings}; | |
| 16 | − | use crate::{badge, config, frame, runner, updates}; | |
| 16 | + | use crate::{badge, config, devtools, frame, runner, updates}; | |
| 17 | 17 | ||
| 18 | 18 | const SCRIPT: &str = include_str!("bridge.js"); | |
| 19 | 19 | ||
| ⋯ | |||
| 259 | 259 | Ok(()) | |
| 260 | 260 | } | |
| 261 | 261 | ||
| 262 | + | /// The web inspector for the page asking, the site's in the window: | |
| 263 | + | /// opened, or with `toggle` opened or closed (F12, from bridge.js). Only | |
| 264 | + | /// while Developer tools is on in settings (devtools.rs); otherwise an | |
| 265 | + | /// error that says where to turn it on. | |
| 266 | + | #[tauri::command] | |
| 267 | + | pub fn open_devtools(app: AppHandle, webview: Webview, toggle: Option<bool>) -> Result<(), String> { | |
| 268 | + | from_site_page(&app, &webview)?; | |
| 269 | + | if toggle == Some(true) { devtools::toggle(&app) } else { devtools::open(&app) } | |
| 270 | + | } | |
| 271 | + | ||
| 262 | 272 | /// What the settings show. | |
| 263 | 273 | #[tauri::command] | |
| 264 | 274 | pub fn get_settings(app: AppHandle, webview: Webview) -> Result<settings::View, String> { | |
| 182 | 182 | "allow-restart", | |
| 183 | 183 | "allow-restart-to-update", | |
| 184 | 184 | "allow-change-server", | |
| 185 | + | // The web inspector, which answers only while Developer tools is on. | |
| 186 | + | "allow-open-devtools", | |
| 185 | 187 | ]; | |
| 186 | 188 | ||
| 187 | 189 | /// What GitHub's pages may call while someone signs in: telling the title bar their title. |
| 1 | + | //! The web inspector, for the site's page in the window: off unless | |
| 2 | + | //! someone turns on Developer tools in settings, for when a page goes | |
| 3 | + | //! wrong and they want its console. With it on, View › Developer tools | |
| 4 | + | //! (Ctrl+Shift+I, or ⌥⌘I on macOS), F12 on the page (bridge.js), and the | |
| 5 | + | //! site's own `g1tDesktop.devtools.open()` open it; with it off, none of | |
| 6 | + | //! them do anything. | |
| 7 | + | //! | |
| 8 | + | //! Release builds have the inspector only through Tauri's `devtools` | |
| 9 | + | //! feature (Cargo.toml). Whether a web view has it at all is decided when | |
| 10 | + | //! the web view is made. On Windows, WebView2 lets it change while running, | |
| 11 | + | //! its own F12, Ctrl+Shift+I and Inspect with it, so the setting takes | |
| 12 | + | //! effect at once. WebKit, on macOS and Linux, keeps what it was made with, | |
| 13 | + | //! and its Inspect Element with it, until g1t restarts; the settings then | |
| 14 | + | //! offer the restart, as they do for the title bar. | |
| 15 | + | ||
| 16 | + | use std::sync::Mutex; | |
| 17 | + | ||
| 18 | + | use tauri::menu::MenuItem; | |
| 19 | + | use tauri::{AppHandle, Webview, Wry}; | |
| 20 | + | ||
| 21 | + | use crate::config; | |
| 22 | + | ||
| 23 | + | /// Whether the setting is on now. | |
| 24 | + | pub fn on(app: &AppHandle) -> bool { | |
| 25 | + | config::settings(app).developer_tools | |
| 26 | + | } | |
| 27 | + | ||
| 28 | + | /// Whether the site's web view was made with the inspector, which WebKit | |
| 29 | + | /// keeps until g1t restarts: decided once, as it is made. | |
| 30 | + | static STARTED: std::sync::OnceLock<bool> = std::sync::OnceLock::new(); | |
| 31 | + | ||
| 32 | + | /// Whether this run's site web view has the inspector. | |
| 33 | + | pub fn started(app: &AppHandle) -> bool { | |
| 34 | + | *STARTED.get_or_init(|| on(app)) | |
| 35 | + | } | |
| 36 | + | ||
| 37 | + | /// The setting differs from what the site's web view was made with, and | |
| 38 | + | /// only a restart changes that: never on Windows, where it changes at once. | |
| 39 | + | pub fn changed(app: &AppHandle) -> bool { | |
| 40 | + | !cfg!(windows) && started(app) != on(app) | |
| 41 | + | } | |
| 42 | + | ||
| 43 | + | /// The menu's Developer tools rows, kept so a change of the setting can | |
| 44 | + | /// turn them on or off; a row that is off has no shortcut either. | |
| 45 | + | static ITEMS: Mutex<Vec<MenuItem<Wry>>> = Mutex::new(Vec::new()); | |
| 46 | + | ||
| 47 | + | /// The menu row, with its shortcut: Ctrl+Shift+I, or ⌥⌘I on macOS. | |
| 48 | + | pub fn item(app: &AppHandle) -> tauri::Result<MenuItem<Wry>> { | |
| 49 | + | let shortcut = if cfg!(target_os = "macos") { "Cmd+Alt+I" } else { "Ctrl+Shift+I" }; | |
| 50 | + | let item = MenuItem::with_id(app, "devtools", "Developer tools", on(app), Some(shortcut))?; | |
| 51 | + | ITEMS.lock().unwrap().push(item.clone()); | |
| 52 | + | Ok(item) | |
| 53 | + | } | |
| 54 | + | ||
| 55 | + | /// Whether the inspector opens now: the setting is on, and the site's web | |
| 56 | + | /// view was made with it, or is WebView2's, which takes it at once. | |
| 57 | + | pub fn usable(app: &AppHandle) -> bool { | |
| 58 | + | on(app) && !changed(app) | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | /// The setting changed: the menu rows follow it, and so does WebView2's | |
| 62 | + | /// own way in. Turned off, an inspector that is open closes where the | |
| 63 | + | /// system can close it (not on Windows, whose WebView2 has no way to). | |
| 64 | + | pub fn setting_changed(app: &AppHandle) { | |
| 65 | + | let on = on(app); | |
| 66 | + | for item in ITEMS.lock().unwrap().iter() { | |
| 67 | + | let _ = item.set_enabled(usable(app)); | |
| 68 | + | } | |
| 69 | + | allow(app, on); | |
| 70 | + | if !on && let Some(site) = crate::frame::site(app) { | |
| 71 | + | site.close_devtools(); | |
| 72 | + | } | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | /// Lets WebView2 open the inspector, from its own F12, Ctrl+Shift+I and | |
| 76 | + | /// Inspect as well as when g1t asks, or not. WebKit keeps what its web | |
| 77 | + | /// view was made with. | |
| 78 | + | #[cfg(windows)] | |
| 79 | + | pub fn allow(app: &AppHandle, on: bool) { | |
| 80 | + | let Some(site) = crate::frame::site(app) else { return }; | |
| 81 | + | let _ = site.with_webview(move |webview| { | |
| 82 | + | // SAFETY: the controller is the site's, alive while the web view is, | |
| 83 | + | // and this runs on the thread that owns it. | |
| 84 | + | let _ = unsafe { webview.controller().CoreWebView2().and_then(|core| core.Settings()).and_then(|settings| settings.SetAreDevToolsEnabled(on)) }; | |
| 85 | + | }); | |
| 86 | + | } | |
| 87 | + | ||
| 88 | + | #[cfg(not(windows))] | |
| 89 | + | pub fn allow(_app: &AppHandle, _on: bool) {} | |
| 90 | + | ||
| 91 | + | /// The site's web view, while the inspector opens: an error otherwise, | |
| 92 | + | /// which the site's `devtools.open()` sees. | |
| 93 | + | fn site_if_on(app: &AppHandle) -> Result<Webview, String> { | |
| 94 | + | if !on(app) { | |
| 95 | + | return Err("Developer tools are off. Turn them on in the app's settings, under Window.".into()); | |
| 96 | + | } | |
| 97 | + | if changed(app) { | |
| 98 | + | return Err("Developer tools turn on when g1t restarts.".into()); | |
| 99 | + | } | |
| 100 | + | crate::frame::site(app).ok_or_else(|| "g1t's page is not open".into()) | |
| 101 | + | } | |
| 102 | + | ||
| 103 | + | /// Opens the inspector for the site's page. | |
| 104 | + | pub fn open(app: &AppHandle) -> Result<(), String> { | |
| 105 | + | site_if_on(app)?.open_devtools(); | |
| 106 | + | Ok(()) | |
| 107 | + | } | |
| 108 | + | ||
| 109 | + | /// The menu row and the shortcuts: opens the inspector, or closes it if it | |
| 110 | + | /// is open. WebView2 can't tell whether it is, nor close it, so on | |
| 111 | + | /// Windows it only opens, and the inspector's own window closes it. | |
| 112 | + | pub fn toggle(app: &AppHandle) -> Result<(), String> { | |
| 113 | + | let site = site_if_on(app)?; | |
| 114 | + | if site.is_devtools_open() { site.close_devtools() } else { site.open_devtools() } | |
| 115 | + | Ok(()) | |
| 116 | + | } |
| 16 | 16 | mod badge; | |
| 17 | 17 | mod bridge; | |
| 18 | 18 | mod config; | |
| 19 | + | mod devtools; | |
| 19 | 20 | mod frame; | |
| 20 | 21 | mod links; | |
| 21 | 22 | mod menu; | |
| ⋯ | |||
| 88 | 89 | bridge::runner_register, | |
| 89 | 90 | bridge::runner_control, | |
| 90 | 91 | bridge::site_ready, | |
| 92 | + | bridge::open_devtools, | |
| 91 | 93 | ]) | |
| 92 | 94 | .on_menu_event(|app, event| menu::handle(app, event.id().as_ref())) | |
| 93 | 95 | .setup(|app| { | |
| ⋯ | |||
| 101 | 103 | // The site's web view: the launcher first, which goes on to the server. | |
| 102 | 104 | let site = WebviewBuilder::new(frame::SITE, WebviewUrl::App("index.html".into())) | |
| 103 | 105 | .initialization_script(bridge::script(custom)) | |
| 106 | + | // The web inspector, as the Developer tools setting has it now (devtools.rs). | |
| 107 | + | .devtools(devtools::started(&handle)) | |
| 104 | 108 | .on_navigation({ | |
| 105 | 109 | let handle = handle.clone(); | |
| 106 | 110 | move |url| navigation::allowed(&handle, url) | |
| 48 | 48 | &item("zoom-out", "Zoom out", Some("CmdOrCtrl+-"))?, | |
| 49 | 49 | &separator()?, | |
| 50 | 50 | &PredefinedMenuItem::fullscreen(app, None)?, | |
| 51 | + | &separator()?, | |
| 52 | + | &crate::devtools::item(app)?, | |
| 51 | 53 | ], | |
| 52 | 54 | )?; | |
| 53 | 55 | let go = Submenu::with_items( | |
| ⋯ | |||
| 156 | 158 | "zoom-in" => settings::zoom(app, 1), | |
| 157 | 159 | "zoom-out" => settings::zoom(app, -1), | |
| 158 | 160 | "zoom-reset" => settings::zoom(app, 0), | |
| 161 | + | // Off with the setting, as the row is. | |
| 162 | + | "devtools" => { | |
| 163 | + | let _ = crate::devtools::toggle(app); | |
| 164 | + | } | |
| 159 | 165 | "back" => eval(app, "history.back()"), | |
| 160 | 166 | "forward" => eval(app, "history.forward()"), | |
| 161 | 167 | "home" => links::go(app, "/"), | |
| 1 | 1 | //! The app's own settings: how it starts, what closing the window does, | |
| 2 | − | //! how it tells the person something arrived, its title bar, zoom, | |
| 3 | − | //! updates, and the runner. They open as a dialog over the site, which the | |
| 2 | + | //! how it tells the person something arrived, its title bar, zoom, the | |
| 3 | + | //! web inspector, updates, and the runner. They open as a dialog over the site, which the | |
| 4 | 4 | //! site's page draws (apps/web components/desktop-settings.tsx), from the | |
| 5 | 5 | //! title bar, the menu, the tray, or the site's account menu. While the | |
| 6 | 6 | //! window shows no page of the site's (the launcher, the offline page, | |
| ⋯ | |||
| 48 | 48 | pub system_title_bar: bool, | |
| 49 | 49 | /// The site's zoom, 1 for as it is. | |
| 50 | 50 | pub zoom: f64, | |
| 51 | + | /// The web inspector for the site's page, from the View menu, F12 and | |
| 52 | + | /// Ctrl+Shift+I (⌥⌘I on macOS); off unless someone turns it on | |
| 53 | + | /// (devtools.rs). On macOS and Linux it takes effect when g1t restarts. | |
| 54 | + | pub developer_tools: bool, | |
| 51 | 55 | /// Updates download by themselves; a person can still check from the menu. | |
| 52 | 56 | /// The runner's own updates follow it too (runner/mod.rs). | |
| 53 | 57 | pub auto_update: bool, | |
| ⋯ | |||
| 113 | 117 | badge: true, | |
| 114 | 118 | system_title_bar: false, | |
| 115 | 119 | zoom: 1.0, | |
| 120 | + | developer_tools: false, | |
| 116 | 121 | auto_update: true, | |
| 117 | 122 | runner: true, | |
| 118 | 123 | runner_backend: crate::runner::Backend::Sandboxed, | |
| ⋯ | |||
| 147 | 152 | pub title_bar_changed: bool, | |
| 148 | 153 | /// Whether this window draws g1t's own title bar, which the page then draws (settings.html). | |
| 149 | 154 | pub custom_frame: bool, | |
| 155 | + | /// The developer tools setting differs from the one the site's page | |
| 156 | + | /// has, on macOS and Linux: a restart applies it (devtools.rs). | |
| 157 | + | pub developer_tools_changed: bool, | |
| 150 | 158 | /// The runner's state, diagnosis and recent log. | |
| 151 | 159 | pub runner_view: crate::runner::View, | |
| 152 | 160 | } | |
| ⋯ | |||
| 162 | 170 | checked_at: crate::updates::checked_at(app), | |
| 163 | 171 | title_bar_changed: crate::frame::started(app) != crate::frame::custom(app), | |
| 164 | 172 | custom_frame: crate::frame::started(app), | |
| 173 | + | developer_tools_changed: crate::devtools::changed(app), | |
| 165 | 174 | runner_view: crate::runner::view(app), | |
| 166 | 175 | } | |
| 167 | 176 | } | |
| ⋯ | |||
| 177 | 186 | if before.badge != settings.badge { | |
| 178 | 187 | crate::badge::refresh(app); | |
| 179 | 188 | } | |
| 189 | + | if before.developer_tools != settings.developer_tools { | |
| 190 | + | crate::devtools::setting_changed(app); | |
| 191 | + | } | |
| 180 | 192 | let runner = |s: &Settings| (s.runner, s.runner_backend, s.runner_workspace.clone(), s.runner_capabilities.clone()); | |
| 181 | 193 | if runner(&before) != runner(&settings) { | |
| 182 | 194 | crate::runner::settings_changed(app); | |
| ⋯ | |||
| 369 | 381 | assert!(!settings.close_to_tray); | |
| 370 | 382 | assert!(settings.notifications); | |
| 371 | 383 | assert_eq!(settings.zoom, 1.0); | |
| 384 | + | // The web inspector is off for someone who never turned it on. | |
| 385 | + | assert!(!settings.developer_tools); | |
| 386 | + | let developer: Settings = serde_json::from_str(r#"{"developerTools":true}"#).unwrap(); | |
| 387 | + | assert!(developer.developer_tools); | |
| 372 | 388 | // The runner is on, and sandboxed, for someone who never chose. | |
| 373 | 389 | assert!(settings.runner); | |
| 374 | 390 | assert_eq!(settings.runner_backend, crate::runner::Backend::Sandboxed); | |
| 21 | 21 | computer runs the workspace's `runs-on: self-hosted` jobs while g1t is | |
| 22 | 22 | open, with nothing to install or register. See [the runner](#the-runner). | |
| 23 | 23 | - **Settings of its own**: opening when you sign in to your computer, | |
| 24 | − | what closing the window does, notifications, the badge, zoom, updates | |
| 25 | − | and the runner. | |
| 24 | + | what closing the window does, notifications, the badge, zoom, | |
| 25 | + | developer tools, updates and the runner. | |
| 26 | 26 | ||
| 27 | 27 | Get it at [g1t.sh/download](https://g1t.sh/download), or from your account | |
| 28 | 28 | menu, **Get the desktop app**. The page opens on the system you visit it | |
| ⋯ | |||
| 117 | 117 | | --- | --- | | |
| 118 | 118 | | **File** (**g1t** on macOS) | **Settings** (Ctrl+, or ⌘,), **Use another g1t…**, **Close window** (Ctrl+W), **Quit g1t** (Ctrl+Q or ⌘Q) | | |
| 119 | 119 | | **Edit** | Undo, redo, cut, copy, paste and select all | | |
| 120 | − | | **View** | **Reload** (Ctrl+R), **Actual size** (Ctrl+0), **Zoom in** (Ctrl+=), **Zoom out** (Ctrl+-), full screen | | |
| 120 | + | | **View** | **Reload** (Ctrl+R), **Actual size** (Ctrl+0), **Zoom in** (Ctrl+=), **Zoom out** (Ctrl+-), full screen, **Developer tools** (Ctrl+Shift+I, or ⌥⌘I), once [turned on](#developer-tools) | | |
| 121 | 121 | | **Go** | **Back** (Alt+Left, or ⌘[), **Forward** (Alt+Right, or ⌘]), **Home**, **Notifications** | | |
| 122 | 122 | | **Window** | Minimize and maximize | | |
| 123 | 123 | | **Help** | **Desktop app guide** and **g1t.sh status**, in your browser; **Check for updates…**; **Restart to update**, once one is downloaded; **About g1t** | | |
| ⋯ | |||
| 151 | 151 | | **Show a badge on the icon** | On | The count, or the dot on Windows. Off, the icon stays clean; the tray's hover text still counts. | | |
| 152 | 152 | | **Use the system's title bar** | Off | The system's title bar in place of [g1t's own](#the-title-bar), with the menu bar under it on Windows and Linux. Takes effect when g1t restarts. | | |
| 153 | 153 | | **Zoom** | 100% | How large g1t is drawn, from 67% to 200%. The View menu changes it too. | | |
| 154 | + | | **Developer tools** | Off | F12 or Ctrl+Shift+I (⌥⌘I on macOS), and **Developer tools** in the View menu, open the web inspector for the page. See [Developer tools](#developer-tools). | | |
| 154 | 155 | | **Download updates by themselves** | On | Off, the app never checks on its own; **Check for updates** still does. The runner's updates follow it too: off, only **Check for runner updates** looks for a newer runner. | | |
| 155 | 156 | ||
| 156 | 157 | **Updates** also shows the app's version and whether it is up to date, | |
| ⋯ | |||
| 165 | 166 | changes, the answer comes, or, after 20 seconds with no change, it is | |
| 166 | 167 | yours to press again. If the app couldn't do it, the settings say why. | |
| 167 | 168 | ||
| 169 | + | ### Developer tools | |
| 170 | + | ||
| 171 | + | When a page goes wrong, such as one that says *Something went wrong*, the | |
| 172 | + | web inspector shows why: the page's console, its network requests and its | |
| 173 | + | code. It is off unless you turn on **Developer tools** in the settings' | |
| 174 | + | **Window** section. Then any of these opens it for the page in the window: | |
| 175 | + | ||
| 176 | + | - **F12**, on the page. | |
| 177 | + | - **Ctrl+Shift+I** on Windows and Linux, **⌥⌘I** (Cmd+Option+I) on macOS. | |
| 178 | + | - **Developer tools** in the View menu. | |
| 179 | + | ||
| 180 | + | On macOS and Linux the same keys, or the menu row, close it again; on | |
| 181 | + | Windows, close the inspector's own window. With the setting off, none of | |
| 182 | + | them open it, and the View menu's row is greyed out. On Windows the change | |
| 183 | + | takes effect at once; on macOS and Linux it takes effect when g1t | |
| 184 | + | restarts, and the settings offer **Restart now**. | |
| 185 | + | ||
| 186 | + | g1t's pages can open it too, from `window.g1tDesktop.devtools.open()`, | |
| 187 | + | which works only while the setting is on and only for g1t's own pages. | |
| 188 | + | ||
| 168 | 189 | ## The runner | |
| 169 | 190 | ||
| 170 | 191 | The app runs a [self-hosted runner](/guides/self-hosted-runners/) for | |
| 309 | 309 | const words = platformWords(view.platform); | |
| 310 | 310 | const zoomId = useId(); | |
| 311 | 311 | const restart = useBusy(String(view.titleBarChanged), fail); | |
| 312 | + | const restartForTools = useBusy(String(view.developerToolsChanged), fail); | |
| 312 | 313 | return ( | |
| 313 | 314 | <> | |
| 314 | 315 | <SwitchCard title="Use the system's title bar" checked={view.systemTitleBar} onCheckedChange={(on) => change({ systemTitleBar: on })}> | |
| ⋯ | |||
| 343 | 344 | > | |
| 344 | 345 | {words.zoom} | |
| 345 | 346 | </SettingCard> | |
| 347 | + | {/* An app from before Developer tools has no such setting to change. */} | |
| 348 | + | {typeof view.developerTools === "boolean" && ( | |
| 349 | + | <SwitchCard title="Developer tools" checked={view.developerTools} onCheckedChange={(on) => change({ developerTools: on })}> | |
| 350 | + | {words.developerTools} | |
| 351 | + | </SwitchCard> | |
| 352 | + | )} | |
| 353 | + | {view.developerToolsChanged && !view.titleBarChanged && ( | |
| 354 | + | <SettingCard | |
| 355 | + | title={view.developerTools ? "Restart to turn on developer tools" : "Restart to turn off developer tools"} | |
| 356 | + | control={ | |
| 357 | + | <Button size="sm" variant="accent" busy={restartForTools.busy} onClick={() => restartForTools.run(() => desktopSettings()?.restart())}> | |
| 358 | + | Restart now | |
| 359 | + | </Button> | |
| 360 | + | } | |
| 361 | + | > | |
| 362 | + | g1t opens again where you were. | |
| 363 | + | </SettingCard> | |
| 364 | + | )} | |
| 346 | 365 | </> | |
| 347 | 366 | ); | |
| 348 | 367 | } | |
| 12 | 12 | badge: true, | |
| 13 | 13 | systemTitleBar: false, | |
| 14 | 14 | zoom: 1.1, | |
| 15 | + | developerTools: false, | |
| 15 | 16 | autoUpdate: true, | |
| 16 | 17 | runner: true, | |
| 17 | 18 | runnerBackend: "sandboxed", | |
| ⋯ | |||
| 25 | 26 | checkedAt: null, | |
| 26 | 27 | titleBarChanged: false, | |
| 27 | 28 | customFrame: true, | |
| 29 | + | developerToolsChanged: false, | |
| 28 | 30 | runnerView: {} as DesktopSettingsView["runnerView"], | |
| 29 | 31 | ...over, | |
| 30 | 32 | }; | |
| 25 | 25 | badge: boolean; | |
| 26 | 26 | systemTitleBar: boolean; | |
| 27 | 27 | zoom: number; | |
| 28 | + | /** The web inspector for the page, from F12, Ctrl+Shift+I (⌥⌘I on macOS) and the View menu (src/devtools.rs). */ | |
| 29 | + | developerTools: boolean; | |
| 28 | 30 | autoUpdate: boolean; | |
| 29 | 31 | runner: boolean; | |
| 30 | 32 | runnerBackend: DesktopBackend; | |
| ⋯ | |||
| 45 | 47 | /** The title bar setting differs from the one the window has: a restart applies it. */ | |
| 46 | 48 | titleBarChanged: boolean; | |
| 47 | 49 | customFrame: boolean; | |
| 50 | + | /** The developer tools setting differs from the one the page has, on macOS and Linux: a restart applies it. */ | |
| 51 | + | developerToolsChanged: boolean; | |
| 48 | 52 | runnerView: DesktopRunnerView; | |
| 49 | 53 | }; | |
| 50 | 54 | ||
| ⋯ | |||
| 89 | 93 | "badge", | |
| 90 | 94 | "systemTitleBar", | |
| 91 | 95 | "zoom", | |
| 96 | + | "developerTools", | |
| 92 | 97 | "autoUpdate", | |
| 93 | 98 | "runner", | |
| 94 | 99 | "runnerBackend", | |
| ⋯ | |||
| 139 | 144 | flash: mac ? "Bounce the dock icon" : platform === "windows" ? "Flash the taskbar icon" : "Ask for attention", | |
| 140 | 145 | systemTitleBar: mac ? "In place of g1t's own, which sits under the window's buttons." : "In place of g1t's own, with the menu bar under it.", | |
| 141 | 146 | zoom: mac ? "The View menu changes it too: ⌘+, ⌘− and ⌘0." : "The View menu changes it too: Ctrl+=, Ctrl+− and Ctrl+0.", | |
| 147 | + | developerTools: `F12 or ${mac ? "⌥⌘I" : "Ctrl+Shift+I"} opens the web inspector for the page, with its console, for when something goes wrong. So does Developer tools in the View menu.`, | |
| 142 | 148 | }; | |
| 143 | 149 | } | |
| 144 | 150 | ||
| 94 | 94 | * // diagnosis, who to register for, its token, and its fixes | |
| 95 | 95 | * // (lib/desktop-runner.ts has the details). | |
| 96 | 96 | * runner: { status, offer, register, act, onWanted, onStatus }, | |
| 97 | + | * // The web inspector for this page, while Developer tools is on in the | |
| 98 | + | * // app's settings; rejects, saying where to turn it on, while it is off. | |
| 99 | + | * devtools: { open() { return Promise.resolve() } }, | |
| 97 | 100 | * }; | |
| 98 | 101 | * | |
| 99 | 102 | * The app also opens the site's pages for reading about g1t (pricing, | |
| ⋯ | |||
| 113 | 116 | openSettings?(): void; | |
| 114 | 117 | setSearch?(label: string, open: () => void): () => void; | |
| 115 | 118 | titleBarHeight?: number; | |
| 119 | + | devtools?: { open(): Promise<void> }; | |
| 116 | 120 | runner?: DesktopRunnerBridge; | |
| 117 | 121 | settings?: DesktopSettingsBridge; | |
| 118 | 122 | }; | |
Comments
Sign in to comment.