fix(stage1): initialize default working directory and add safe backend fallback (v0.1.12) #72

Merged
gronod merged 1 commits from fix/issue-59-empty-working-directory into development 2026-08-25 10:09:02 +01:00
6 changed files with 61 additions and 44 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "iccery", "name": "iccery",
"private": true, "private": true,
"version": "0.1.11", "version": "0.1.12",
"type": "module", "type": "module",
"scripts": { "scripts": {
"tauri": "tauri" "tauri": "tauri"
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "iccery" name = "iccery"
version = "0.1.11" version = "0.1.12"
description = "A Tauri App" description = "A Tauri App"
authors = ["you"] authors = ["you"]
edition = "2021" edition = "2021"
+26 -32
View File
@@ -75,6 +75,27 @@ pub fn get_app_info() -> AppInfo {
} }
} }
pub fn resolve_safe_cwd(app: &AppHandle, cwd_input: &str) -> Result<String, String> {
if !cwd_input.trim().is_empty() {
let p = std::path::Path::new(cwd_input.trim());
if p.is_dir() {
return Ok(p.to_string_lossy().to_string());
}
}
app.path()
.document_dir()
.or_else(|_| app.path().home_dir())
.or_else(|_| app.path().app_data_dir())
.map(|p| p.to_string_lossy().to_string())
.map_err(|e| format!("Failed to resolve default working directory: {}", e))
}
#[tauri::command]
pub fn get_default_working_dir(app: AppHandle) -> Result<String, String> {
resolve_safe_cwd(&app, "")
}
#[tauri::command] #[tauri::command]
pub async fn detect_instruments(app: AppHandle, state: State<'_, ProcessManager>) -> Result<(), String> { pub async fn detect_instruments(app: AppHandle, state: State<'_, ProcessManager>) -> Result<(), String> {
let binary = resolve_binary(app.clone(), "instlist".to_string()).await?; let binary = resolve_binary(app.clone(), "instlist".to_string()).await?;
@@ -197,14 +218,7 @@ pub async fn run_targen(
let binary = resolve_binary(app.clone(), "targen".to_string()).await?; let binary = resolve_binary(app.clone(), "targen".to_string()).await?;
let args = build_targen_args(&config); let args = build_targen_args(&config);
let id = format!("targen_{}", config.basename); let id = format!("targen_{}", config.basename);
let cwd = Some(resolve_safe_cwd(&app, &config.cwd)?);
let cwd = if config.cwd.trim().is_empty() {
None
} else {
Some(config.cwd.clone())
};
println!("DEBUG RUN_TARGEN: binary='{}' args={:?} cwd={:?}", binary, args, cwd);
state.spawn(app, id, binary, args, cwd).await state.spawn(app, id, binary, args, cwd).await
} }
@@ -218,12 +232,7 @@ pub async fn run_printtarg(
let binary = resolve_binary(app.clone(), "printtarg".to_string()).await?; let binary = resolve_binary(app.clone(), "printtarg".to_string()).await?;
let args = build_printtarg_args(&config); let args = build_printtarg_args(&config);
let id = format!("printtarg_{}", config.basename); let id = format!("printtarg_{}", config.basename);
let cwd = Some(resolve_safe_cwd(&app, &config.cwd)?);
let cwd = if config.cwd.trim().is_empty() {
None
} else {
Some(config.cwd.clone())
};
state.spawn(app, id, binary, args, cwd).await state.spawn(app, id, binary, args, cwd).await
} }
@@ -259,12 +268,7 @@ pub async fn run_chartread(
let binary = resolve_binary(app.clone(), "chartread".to_string()).await?; let binary = resolve_binary(app.clone(), "chartread".to_string()).await?;
let args = build_chartread_args(&config); let args = build_chartread_args(&config);
let id = format!("chartread_{}", config.basename); let id = format!("chartread_{}", config.basename);
let cwd = Some(resolve_safe_cwd(&app, &config.cwd)?);
let cwd = if config.cwd.trim().is_empty() {
None
} else {
Some(config.cwd.clone())
};
state.spawn(app, id, binary, args, cwd).await state.spawn(app, id, binary, args, cwd).await
} }
@@ -323,12 +327,7 @@ pub async fn run_colprof(
let binary = resolve_binary(app.clone(), "colprof".to_string()).await?; let binary = resolve_binary(app.clone(), "colprof".to_string()).await?;
let args = build_colprof_args(&config); let args = build_colprof_args(&config);
let id = format!("colprof_{}", config.basename); let id = format!("colprof_{}", config.basename);
let cwd = Some(resolve_safe_cwd(&app, &config.cwd)?);
let cwd = if config.cwd.trim().is_empty() {
None
} else {
Some(config.cwd.clone())
};
state.spawn(app, id, binary, args, cwd).await state.spawn(app, id, binary, args, cwd).await
} }
@@ -359,12 +358,7 @@ pub async fn run_profcheck(
let binary = resolve_binary(app.clone(), "profcheck".to_string()).await?; let binary = resolve_binary(app.clone(), "profcheck".to_string()).await?;
let args = build_profcheck_args(&config); let args = build_profcheck_args(&config);
let id = format!("profcheck_{}", config.ti3_path); let id = format!("profcheck_{}", config.ti3_path);
let cwd = Some(resolve_safe_cwd(&app, &config.cwd)?);
let cwd = if config.cwd.trim().is_empty() {
None
} else {
Some(config.cwd.clone())
};
state.spawn(app, id, binary, args, cwd).await state.spawn(app, id, binary, args, cwd).await
} }
+1
View File
@@ -13,6 +13,7 @@ pub fn run() {
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
commands::spawn_process, commands::spawn_process,
commands::get_app_info, commands::get_app_info,
commands::get_default_working_dir,
commands::send_stdin, commands::send_stdin,
commands::kill_process, commands::kill_process,
commands::resolve_binary, commands::resolve_binary,
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "ICCery", "productName": "ICCery",
"version": "0.1.11", "version": "0.1.12",
"identifier": "com.gronod.iccery", "identifier": "com.gronod.iccery",
"build": { "build": {
"frontendDist": "../src" "frontendDist": "../src"
+31 -9
View File
@@ -19,6 +19,25 @@ export function initTargen() {
let currentWorkingDir = ""; let currentWorkingDir = "";
let currentBasename = ""; let currentBasename = "";
function updateGenerateButton() {
const hasBasename = targetBasename.value.trim().length > 0;
const hasCwd = currentWorkingDir.trim().length > 0;
btnGenerate.disabled = !(hasBasename && hasCwd);
}
// Load sensible default working directory on startup
invoke("get_default_working_dir")
.then((defaultDir) => {
if (defaultDir && !currentWorkingDir) {
currentWorkingDir = defaultDir;
selectedPathDisplay.textContent = `Directory: ${currentWorkingDir}`;
updateGenerateButton();
}
})
.catch((err) => {
console.warn("Could not retrieve default working directory:", err);
});
// Handle patch count preset changes // Handle patch count preset changes
patchCountPreset.addEventListener("change", (e) => { patchCountPreset.addEventListener("change", (e) => {
if (e.target.value === "custom") { if (e.target.value === "custom") {
@@ -28,13 +47,9 @@ export function initTargen() {
} }
}); });
// Enable generate button if text is entered manually // Enable generate button only when both basename and directory are valid
targetBasename.addEventListener("input", () => { targetBasename.addEventListener("input", () => {
if (targetBasename.value.trim() !== "") { updateGenerateButton();
btnGenerate.disabled = false;
} else {
btnGenerate.disabled = true;
}
}); });
// Browse button opens save dialog // Browse button opens save dialog
@@ -65,9 +80,7 @@ export function initTargen() {
targetBasename.value = basename; targetBasename.value = basename;
selectedPathDisplay.textContent = `Directory: ${currentWorkingDir}`; selectedPathDisplay.textContent = `Directory: ${currentWorkingDir}`;
updateGenerateButton();
// Enable generate button
btnGenerate.disabled = false;
} }
} catch (err) { } catch (err) {
console.error("Failed to open save dialog:", err); console.error("Failed to open save dialog:", err);
@@ -76,6 +89,15 @@ export function initTargen() {
// Generate button clicks // Generate button clicks
btnGenerate.addEventListener("click", async () => { btnGenerate.addEventListener("click", async () => {
const basename = targetBasename.value.trim();
if (!currentWorkingDir || !basename) {
logPre.textContent = "[ERROR] Please specify both a target basename and a working directory.\n";
logContainer.open = true;
logContainer.classList.remove("hidden");
btnGenerate.disabled = false;
return;
}
logPre.textContent = ""; logPre.textContent = "";
logContainer.open = false; logContainer.open = false;
logContainer.classList.remove("hidden"); logContainer.classList.remove("hidden");