Offline Work mode + Reconcile Offline Work dialog, menu tooltips, spinner fix; v0.3.0
- Explicit Work Offline toggle (P4V-style): stops server polling, calm offline banner, persisted - Reconcile Offline Work dialog: preview adds/edits/deletes with per-file checkboxes, opens picked into a changelist - Make writable (offline edit) context action; backend p4_reconcile_preview/apply + p4_set_writable - Tooltips (title) on every top-menu item, 5 languages - Fix .ldr spinner rendering (inline-block + box-sizing) so it's a clean circle everywhere Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "exbyte-depot"
|
||||
version = "0.2.4"
|
||||
version = "0.3.0"
|
||||
description = "Exbyte Depot — native Perforce client by Exbyte Studios"
|
||||
authors = ["Exbyte Studios"]
|
||||
edition = "2021"
|
||||
|
||||
@ -1943,6 +1943,73 @@ async fn p4_clean_apply(state: State<'_, AppState>, scope: String) -> Result<Str
|
||||
Ok(if msg.is_empty() { "Workspace already matches the depot.".into() } else { msg })
|
||||
}
|
||||
|
||||
/// Preview offline work (`p4 reconcile -n -e -a -d`): scan the workspace on disk
|
||||
/// and report what changed while disconnected — files edited (writable but not
|
||||
/// opened), added (present locally, unknown to the depot) or deleted (in the
|
||||
/// depot but missing locally). Non-destructive (`-n`): nothing is opened yet.
|
||||
/// This is P4V's "Reconcile Offline Work". Returns one object per file with an
|
||||
/// `action` field (edit / add / delete).
|
||||
#[tauri::command]
|
||||
async fn p4_reconcile_preview(state: State<'_, AppState>, scope: String) -> Result<Vec<Value>, String> {
|
||||
let conn = current(&state)?;
|
||||
run_json(&conn, &["reconcile", "-n", "-e", "-a", "-d", &scope_spec(&scope)]).or_else(|e| {
|
||||
let l = e.to_lowercase();
|
||||
if l.contains("no file") || l.contains("up-to-date") || l.contains("no such") || l.contains("no differing") || l.contains("- no ") {
|
||||
Ok(Vec::new())
|
||||
} else {
|
||||
Err(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Apply the offline reconcile for the picked files only (`p4 reconcile -e -a -d
|
||||
/// file…`): opens the selected edits/adds/deletes into the pending changelist so
|
||||
/// they can be reviewed and submitted. Paths are the depot paths from the preview.
|
||||
#[tauri::command]
|
||||
async fn p4_reconcile_apply(state: State<'_, AppState>, paths: Vec<String>) -> Result<Vec<Value>, String> {
|
||||
let conn = current(&state)?;
|
||||
let clean: Vec<String> = paths.into_iter().map(|p| p.trim().to_string()).filter(|p| !p.is_empty()).collect();
|
||||
if clean.is_empty() {
|
||||
return Err("No files selected".into());
|
||||
}
|
||||
let mut args: Vec<&str> = vec!["reconcile", "-e", "-a", "-d"];
|
||||
for p in &clean {
|
||||
args.push(p.as_str());
|
||||
}
|
||||
run_json(&conn, &args).or_else(|e| {
|
||||
let l = e.to_lowercase();
|
||||
if l.contains("no file") || l.contains("up-to-date") || l.contains("no differing") {
|
||||
Ok(Vec::new())
|
||||
} else {
|
||||
Err(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Toggle the read-only attribute on local working files so they can be edited
|
||||
/// while offline (Perforce syncs files read-only; clearing the flag lets an
|
||||
/// editor save into them before a checkout is possible). Confined to the
|
||||
/// workspace root. Reports how many files were changed.
|
||||
#[tauri::command]
|
||||
async fn p4_set_writable(state: State<'_, AppState>, paths: Vec<String>, writable: bool) -> Result<String, String> {
|
||||
let conn = current(&state)?;
|
||||
let mut done = 0usize;
|
||||
for p in paths.iter().map(|p| p.trim()).filter(|p| !p.is_empty()) {
|
||||
ensure_under_root(&conn, p)?;
|
||||
let meta = std::fs::metadata(p).map_err(|e| format!("File not found: {e}"))?;
|
||||
let mut perms = meta.permissions();
|
||||
#[allow(clippy::permissions_set_readonly_false)]
|
||||
perms.set_readonly(!writable);
|
||||
std::fs::set_permissions(p, perms).map_err(|e| format!("Cannot change {p}: {e}"))?;
|
||||
done += 1;
|
||||
}
|
||||
Ok(if writable {
|
||||
format!("{done} file(s) made writable")
|
||||
} else {
|
||||
format!("{done} file(s) set read-only")
|
||||
})
|
||||
}
|
||||
|
||||
/// Full revision history of a single file (`p4 filelog -l`), including
|
||||
/// per-revision changelist, action, user, time and description. Returns the
|
||||
/// tagged object with rev0/change0/action0/… arrays.
|
||||
@ -2301,6 +2368,9 @@ pub fn run() {
|
||||
p4_filelog,
|
||||
p4_clean_preview,
|
||||
p4_clean_apply,
|
||||
p4_reconcile_preview,
|
||||
p4_reconcile_apply,
|
||||
p4_set_writable,
|
||||
p4_submit_shelved,
|
||||
p4_submit_opts,
|
||||
p4_ignore_read,
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "Exbyte Depot",
|
||||
"mainBinaryName": "Exbyte Depot",
|
||||
"version": "0.2.4",
|
||||
"version": "0.3.0",
|
||||
"identifier": "com.bonchellon.exbyte-depot",
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
|
||||
Reference in New Issue
Block a user