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.
| preparing for cloud work | 1 | //! What the site may ask of the app: the commands behind `window.g1tDesktop` |
| 2 | //! (bridge.js), and the launcher's own. | |
| 3 | //! | |
| 4 | //! Every command checks who is asking. The site's commands answer only a | |
| 5 | //! page of the configured server; the launcher's only the page bundled | |
| 6 | //! with the app. A page from anywhere else gets nothing, whatever it | |
| 7 | //! loads. | |
| 8 | ||
| 9 | use serde::Serialize; | |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 10 | use tauri::{AppHandle, Manager, UserAttentionType, Webview}; |
| preparing for cloud work | 11 | use tauri_plugin_notification::NotificationExt; |
| 12 | use tauri_plugin_opener::OpenerExt; | |
| 13 | use url::Url; | |
| 14 | ||
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 15 | use crate::settings::{self, Settings}; |
| 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. | 16 | use crate::{badge, config, frame, runner, updates}; |
| preparing for cloud work | 17 | |
| 18 | const SCRIPT: &str = include_str!("bridge.js"); | |
| 19 | ||
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 20 | /// The bridge, run at the start of every page the site's web view loads: |
| 21 | /// `custom` is whether g1t's title bar is above it (frame.rs). | |
| 22 | pub fn script(custom: bool) -> String { | |
| 23 | SCRIPT | |
| 24 | .replace("__FRAME__", if custom { "custom" } else { "system" }) | |
| 25 | .replace("__VERSION__", env!("CARGO_PKG_VERSION")) | |
| 26 | .replace("__PLATFORM__", std::env::consts::OS) | |
| 27 | .replace("\"__OUTSIDE__\"", &serde_json::to_string(crate::navigation::OUTSIDE).expect("a list of paths is JSON")) | |
| preparing for cloud work | 28 | } |
| 29 | ||
| 30 | /// What the site and the launcher learn about the app. | |
| 31 | #[derive(Serialize)] | |
| 32 | pub struct Info { | |
| 33 | pub version: String, | |
| 34 | pub platform: String, | |
| 35 | pub server: String, | |
| 36 | /// The version downloaded and waiting for a restart, if one is. | |
| 37 | pub update_ready: Option<String>, | |
| 38 | } | |
| 39 | ||
| 40 | fn caller(webview: &Webview) -> Result<Url, String> { | |
| 41 | webview.url().map_err(|error| error.to_string()) | |
| 42 | } | |
| 43 | ||
| 44 | /// The page asking is one of the server's. | |
| 45 | fn from_site(app: &AppHandle, webview: &Webview) -> Result<(), String> { | |
| 46 | let url = caller(webview)?; | |
| 47 | if config::is_server(app, &url) { Ok(()) } else { Err("only g1t's own pages may ask that".into()) } | |
| 48 | } | |
| 49 | ||
| 50 | /// The page asking is the launcher. | |
| 51 | fn from_launcher(webview: &Webview) -> Result<(), String> { | |
| 52 | let url = caller(webview)?; | |
| 53 | if config::is_launcher(&url) { Ok(()) } else { Err("only the launcher may ask that".into()) } | |
| 54 | } | |
| 55 | ||
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 56 | /// The page asking is the settings window's, bundled with the app. |
| 57 | fn from_settings(webview: &Webview) -> Result<(), String> { | |
| 58 | from_launcher(webview)?; | |
| 59 | if webview.label() == settings::SETTINGS { Ok(()) } else { Err("only the settings window may ask that".into()) } | |
| 60 | } | |
| 61 | ||
| 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. | 62 | /// The Runner window, a page bundled with the app (launcher/runner.html). |
| 63 | fn from_runner(webview: &Webview) -> Result<(), String> { | |
| 64 | from_launcher(webview)?; | |
| 65 | if webview.label() == settings::RUNNER { Ok(()) } else { Err("only the Runner window may ask that".into()) } | |
| 66 | } | |
| 67 | ||
| 68 | /// The settings window, or the Runner window, which keeps the runner's settings. | |
| 69 | fn from_settings_or_runner(webview: &Webview) -> Result<(), String> { | |
| 70 | from_settings(webview).or_else(|_| from_runner(webview)) | |
| 71 | } | |
| 72 | ||
| preparing for cloud work | 73 | fn from_either(app: &AppHandle, webview: &Webview) -> Result<(), String> { |
| 74 | from_site(app, webview).or_else(|_| from_launcher(webview)) | |
| 75 | } | |
| 76 | ||
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 77 | /// The page asking is the one under the title bar, whichever it is: the |
| 78 | /// site's, the launcher, or GitHub's while signing in. | |
| 79 | fn from_page(app: &AppHandle, webview: &Webview) -> Result<(), String> { | |
| 80 | let url = caller(webview)?; | |
| 81 | let shown = config::is_server(app, &url) || config::is_launcher(&url) || crate::navigation::signing_in(&url); | |
| 82 | if webview.label() == frame::SITE && shown { Ok(()) } else { Err("only the page in the window may ask that".into()) } | |
| 83 | } | |
| 84 | ||
| 85 | /// The page asking is the title bar's, bundled with the app. | |
| 86 | fn from_bar(webview: &Webview) -> Result<(), String> { | |
| 87 | from_launcher(webview)?; | |
| 88 | if webview.label() == frame::BAR { Ok(()) } else { Err("only the title bar may ask that".into()) } | |
| 89 | } | |
| 90 | ||
| 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. | 91 | /// The page asking has window buttons: the title bar, or the settings or Runner window's own. |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 92 | fn from_frame(webview: &Webview) -> Result<(), String> { |
| 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. | 93 | from_bar(webview).or_else(|_| from_settings_or_runner(webview)) |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 94 | } |
| 95 | ||
| preparing for cloud work | 96 | #[tauri::command] |
| 97 | pub fn desktop_info(app: AppHandle, webview: Webview) -> Result<Info, String> { | |
| 98 | from_either(&app, &webview)?; | |
| 99 | Ok(Info { | |
| 100 | version: env!("CARGO_PKG_VERSION").into(), | |
| 101 | platform: std::env::consts::OS.into(), | |
| 102 | server: config::server(&app).to_string(), | |
| 103 | update_ready: updates::ready(&app), | |
| 104 | }) | |
| 105 | } | |
| 106 | ||
| 107 | /// A notification from the system: the site asks for one when a message | |
| 108 | /// is for the person and the window is behind another. | |
| 109 | #[tauri::command] | |
| 110 | pub fn notify(app: AppHandle, webview: Webview, title: String, body: String) -> Result<(), String> { | |
| 111 | from_site(&app, &webview)?; | |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 112 | let settings = config::settings(&app); |
| 113 | if let Some(window) = crate::frame::window(&app).filter(|window| settings.flash && !window.is_focused().unwrap_or(false)) { | |
| 114 | let _ = window.request_user_attention(Some(UserAttentionType::Informational)); | |
| 115 | } | |
| 116 | if !settings.notifications { | |
| 117 | return Ok(()); | |
| 118 | } | |
| preparing for cloud work | 119 | app.notification().builder().title(title).body(body).show().map_err(|error| error.to_string()) |
| 120 | } | |
| 121 | ||
| 122 | /// What needs the person, on the icon and the tray; 0 clears it. | |
| 123 | #[tauri::command] | |
| 124 | pub fn set_badge(app: AppHandle, webview: Webview, count: i64) -> Result<(), String> { | |
| 125 | from_site(&app, &webview)?; | |
| 126 | badge::set(&app, count.max(0)); | |
| 127 | Ok(()) | |
| 128 | } | |
| 129 | ||
| 130 | /// A link to somewhere else, opened in the browser the system uses. | |
| 131 | #[tauri::command] | |
| 132 | pub fn open_url(app: AppHandle, webview: Webview, url: String) -> Result<(), String> { | |
| 133 | from_either(&app, &webview)?; | |
| 134 | let parsed = Url::parse(&url).map_err(|error| error.to_string())?; | |
| 135 | if !matches!(parsed.scheme(), "http" | "https" | "mailto") { | |
| 136 | return Err(format!("{} links stay in the app", parsed.scheme())); | |
| 137 | } | |
| 138 | app.opener().open_url(parsed.as_str(), None::<&str>).map_err(|error| error.to_string()) | |
| 139 | } | |
| 140 | ||
| 141 | /// Whether a server answers at all: the launcher asks before the window | |
| 142 | /// goes there, so a machine with no network sees a page of ours, not the | |
| 143 | /// web view's own error. | |
| 144 | #[tauri::command] | |
| 145 | pub async fn reachable(app: AppHandle, webview: Webview, url: Option<String>) -> Result<bool, String> { | |
| 146 | from_launcher(&webview)?; | |
| 147 | let target = match url { | |
| 148 | Some(text) => config::parse(&text).ok_or("That is not a web address.")?, | |
| 149 | None => config::server(&app), | |
| 150 | }; | |
| 151 | let client = reqwest::Client::builder() | |
| 152 | .timeout(std::time::Duration::from_secs(6)) | |
| 153 | .build() | |
| 154 | .map_err(|error| error.to_string())?; | |
| 155 | Ok(client.head(target).send().await.is_ok()) | |
| 156 | } | |
| 157 | ||
| 158 | /// The launcher chose a server: it is kept, and the window goes there next. | |
| 159 | #[tauri::command] | |
| 160 | pub fn set_server(app: AppHandle, webview: Webview, url: String) -> Result<String, String> { | |
| 161 | from_launcher(&webview)?; | |
| 162 | config::set_server(&app, &url).map(|server| server.to_string()) | |
| 163 | } | |
| 164 | ||
| 165 | /// Looks for an update now: `current`, `ready:<version>`, or an error. | |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 166 | /// The settings window shows the answer itself; anyone else asking is also |
| 167 | /// told with a notification. | |
| preparing for cloud work | 168 | #[tauri::command] |
| 169 | pub async fn check_for_updates(app: AppHandle, webview: Webview) -> Result<String, String> { | |
| 170 | from_either(&app, &webview)?; | |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 171 | updates::check(&app, webview.label() != settings::SETTINGS).await |
| 172 | } | |
| 173 | ||
| 174 | /// A title bar button: `minimize`, `maximize` (which toggles), `close`, | |
| 175 | /// `drag`, or `maximized` to ask. Answers whether the window is maximized. | |
| 176 | #[tauri::command] | |
| 177 | pub fn window_control(app: AppHandle, webview: Webview, action: String) -> Result<bool, String> { | |
| 178 | from_frame(&webview)?; | |
| 179 | crate::frame::control(&app, &webview.window(), &action) | |
| 180 | } | |
| 181 | ||
| 182 | /// The title bar's menu button: the app's menu, at that place in the window. | |
| 183 | #[tauri::command] | |
| 184 | pub fn window_menu(webview: Webview, x: f64, y: f64) -> Result<(), String> { | |
| 185 | from_bar(&webview)?; | |
| 186 | crate::frame::menu(&webview.window(), x, y) | |
| 187 | } | |
| 188 | ||
| 189 | /// The page under the title bar says what it is: its title, its search, | |
| 190 | /// whether there is a way back, its colours (frame.rs). | |
| 191 | #[tauri::command] | |
| 192 | pub fn title_bar_page(app: AppHandle, webview: Webview, page: frame::Page) -> Result<(), String> { | |
| 193 | from_page(&app, &webview)?; | |
| 194 | frame::page(&app, page); | |
| 195 | Ok(()) | |
| 196 | } | |
| 197 | ||
| 198 | /// What the title bar shows now: it asks as it loads. | |
| 199 | #[tauri::command] | |
| 200 | pub fn title_bar_current(app: AppHandle, webview: Webview) -> Result<frame::Page, String> { | |
| 201 | from_bar(&webview)?; | |
| 202 | Ok(frame::current(&app)) | |
| 203 | } | |
| 204 | ||
| 205 | /// A title bar button that acts on the page: `back`, `forward`, `search`, `focus`. | |
| 206 | #[tauri::command] | |
| 207 | pub fn title_bar_act(app: AppHandle, webview: Webview, action: String) -> Result<(), String> { | |
| 208 | from_bar(&webview)?; | |
| 209 | frame::act(&app, &action) | |
| 210 | } | |
| 211 | ||
| 212 | /// Restarts g1t, installing a downloaded update on the way: the settings | |
| 213 | /// window offers it after a change that needs one. | |
| 214 | #[tauri::command] | |
| 215 | pub fn restart(app: AppHandle, webview: Webview) -> Result<(), String> { | |
| 216 | from_settings(&webview)?; | |
| 217 | if updates::ready(&app).is_some() { | |
| 218 | updates::restart(&app); | |
| 219 | } | |
| 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. | 220 | runner::shutdown(&app); |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 221 | app.restart() |
| 222 | } | |
| 223 | ||
| 224 | /// The settings window's "Restart now": installs the downloaded update and starts it. | |
| 225 | #[tauri::command] | |
| 226 | pub fn restart_to_update(app: AppHandle, webview: Webview) -> Result<(), String> { | |
| 227 | from_settings(&webview)?; | |
| 228 | updates::restart(&app); | |
| 229 | Ok(()) | |
| 230 | } | |
| 231 | ||
| 232 | /// Opens the app's settings window: the site's account menu asks for it. | |
| 233 | #[tauri::command] | |
| 234 | pub fn open_settings(app: AppHandle, webview: Webview) -> Result<(), String> { | |
| 235 | from_either(&app, &webview)?; | |
| 236 | settings::open(&app); | |
| 237 | Ok(()) | |
| 238 | } | |
| 239 | ||
| 240 | /// What the settings window shows. | |
| 241 | #[tauri::command] | |
| 242 | pub fn get_settings(app: AppHandle, webview: Webview) -> Result<settings::View, String> { | |
| 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. | 243 | from_settings_or_runner(&webview)?; |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 244 | Ok(settings::view(&app)) |
| 245 | } | |
| 246 | ||
| 247 | /// The settings window changed something: everything but opening at sign-in. | |
| 248 | #[tauri::command] | |
| 249 | pub fn save_settings(app: AppHandle, webview: Webview, settings: Settings) -> Result<settings::View, String> { | |
| 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. | 250 | from_settings_or_runner(&webview)?; |
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 251 | settings::apply(&app, settings)?; |
| 252 | Ok(settings::view(&app)) | |
| 253 | } | |
| 254 | ||
| 255 | /// Opening at sign-in, which the system keeps. | |
| 256 | #[tauri::command] | |
| 257 | pub fn set_open_at_login(app: AppHandle, webview: Webview, on: bool) -> Result<settings::View, String> { | |
| 258 | from_settings(&webview)?; | |
| 259 | settings::open_at_login(&app, on)?; | |
| 260 | Ok(settings::view(&app)) | |
| 261 | } | |
| 262 | ||
| 263 | /// The settings window's "Change…": the main window goes to the launcher's choice of server. | |
| 264 | #[tauri::command] | |
| 265 | pub fn change_server(app: AppHandle, webview: Webview) -> Result<(), String> { | |
| 266 | from_settings(&webview)?; | |
| 267 | if let Some(window) = app.get_webview_window(settings::SETTINGS) { | |
| 268 | let _ = window.close(); | |
| 269 | } | |
| 270 | crate::tray::launcher(&app, "change"); | |
| 271 | Ok(()) | |
| 272 | } | |
| 273 | ||
| 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. | 274 | /// The runner's state, diagnosis and recent log: for the site's card for |
| 275 | /// this computer and the settings window. | |
| 276 | #[tauri::command] | |
| 277 | pub fn runner_status(app: AppHandle, webview: Webview) -> Result<runner::View, String> { | |
| 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. | 278 | from_site(&app, &webview).or_else(|_| from_settings_or_runner(&webview)).or_else(|_| from_bar(&webview))?; |
| 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. | 279 | Ok(runner::view(&app)) |
| 280 | } | |
| 281 | ||
| 282 | /// The site, on every page: whether someone is signed in, the workspaces | |
| 283 | /// they own (the only ones they can add runners to), and the one they are | |
| 284 | /// in. Answers the workspace a registration token is wanted for, if one is. | |
| 285 | #[tauri::command] | |
| 286 | pub fn runner_offer(app: AppHandle, webview: Webview, signed_in: bool, workspaces: Vec<runner::Offered>, current: Option<String>) -> Result<Option<String>, String> { | |
| 287 | from_site(&app, &webview)?; | |
| 288 | runner::offer(&app, signed_in, workspaces, current); | |
| 289 | Ok(runner::wanted(&app)) | |
| 290 | } | |
| 291 | ||
| 292 | /// The site made a registration token for the workspace the app asked | |
| 293 | /// for, or says why not: `allowed` is false when the person may not add | |
| 294 | /// runners there. The token goes to the runner and nowhere else. | |
| 295 | #[tauri::command] | |
| 296 | pub fn runner_register(app: AppHandle, webview: Webview, workspace: String, token: Option<String>, allowed: bool, error: Option<String>) -> Result<(), String> { | |
| 297 | from_site(&app, &webview)?; | |
| 298 | runner::register(&app, workspace, token, allowed, error); | |
| 299 | Ok(()) | |
| 300 | } | |
| 301 | ||
| 302 | /// A button for the runner: Start, Stop, or a diagnosis's fix | |
| Merge the desktop runner's settings: a card for each kind of job, Linux and Windows, each with its state, job, cause and fix, and its own Start and Stop; an honest wait for a release's sandbox images, checked again by itself; and the same on the Runners page. | 303 | /// (runner/diagnosis.rs), from settings or the site's card. With a kind |
| 304 | /// of job (`capability`: `linux`, `windows`), Start and Stop are its alone. | |
| 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. | 305 | #[tauri::command] |
| Merge the desktop runner's settings: a card for each kind of job, Linux and Windows, each with its state, job, cause and fix, and its own Start and Stop; an honest wait for a release's sandbox images, checked again by itself; and the same on the Runners page. | 306 | pub fn runner_control(app: AppHandle, webview: Webview, action: String, capability: Option<String>) -> Result<(), String> { |
| 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. | 307 | from_site(&app, &webview).or_else(|_| from_settings_or_runner(&webview))?; |
| Merge the desktop runner's settings: a card for each kind of job, Linux and Windows, each with its state, job, cause and fix, and its own Start and Stop; an honest wait for a release's sandbox images, checked again by itself; and the same on the Runners page. | 308 | runner::act(&app, &action, capability.as_deref()) |
| 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. | 309 | } |
| 310 | ||
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 311 | #[cfg(test)] |
| 312 | mod tests { | |
| 313 | #[test] | |
| 314 | fn the_bridge_has_nothing_left_to_fill_in() { | |
| 315 | let script = super::script(true); | |
| 316 | for placeholder in ["__VERSION__", "__PLATFORM__", "__OUTSIDE__", "__FRAME__"] { | |
| 317 | assert!(!script.contains(placeholder), "{placeholder} is left in the bridge"); | |
| 318 | } | |
| 319 | assert!(script.contains(r#"var FRAME = "custom";"#)); | |
| 320 | assert!(super::script(false).contains(r#"var FRAME = "system";"#)); | |
| 321 | assert!(script.contains(r#"var OUTSIDE = ["/pricing""#)); | |
| 322 | } | |
| preparing for cloud work | 323 | } |
This file's history is long; its oldest lines are credited to the oldest commit read.