refactor 4
This commit is contained in:
@@ -64,6 +64,18 @@ pub struct ResolvedPostInstall {
|
|||||||
pub steps: Vec<PostInstallStep>,
|
pub steps: Vec<PostInstallStep>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct TaskEventPayload {
|
||||||
|
pub task_id: String,
|
||||||
|
pub software_id: String,
|
||||||
|
pub task_type: String,
|
||||||
|
pub status: String,
|
||||||
|
pub stage: String,
|
||||||
|
pub progress: f32,
|
||||||
|
pub target_version: Option<String>,
|
||||||
|
pub message: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct EssentialsStatusItem {
|
pub struct EssentialsStatusItem {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
|||||||
@@ -11,17 +11,19 @@ use tokio::sync::mpsc;
|
|||||||
use winreg::enums::*;
|
use winreg::enums::*;
|
||||||
use winreg::RegKey;
|
use winreg::RegKey;
|
||||||
|
|
||||||
use crate::domain::models::{InstallProgress, InstallTask};
|
use crate::domain::models::{InstallProgress, InstallTask, TaskEventPayload};
|
||||||
use crate::services::essentials_service;
|
use crate::services::essentials_service;
|
||||||
use crate::services::log_service::emit_log;
|
use crate::services::log_service::emit_log;
|
||||||
use crate::winget::PostInstallStep;
|
use crate::winget::PostInstallStep;
|
||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
pub install_tx: mpsc::Sender<InstallTask>,
|
pub install_tx: mpsc::Sender<InstallTask>,
|
||||||
|
pub app_handle: AppHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_install_state(handle: AppHandle) -> AppState {
|
pub fn create_install_state(handle: AppHandle) -> AppState {
|
||||||
let (tx, mut rx) = mpsc::channel::<InstallTask>(100);
|
let (tx, mut rx) = mpsc::channel::<InstallTask>(100);
|
||||||
|
let runtime_handle = handle.clone();
|
||||||
|
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
let perc_re = Regex::new(r"(\d+)\s*%").unwrap();
|
let perc_re = Regex::new(r"(\d+)\s*%").unwrap();
|
||||||
@@ -35,14 +37,16 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
|||||||
let enable_post_install_flag = task.enable_post_install;
|
let enable_post_install_flag = task.enable_post_install;
|
||||||
|
|
||||||
let log_id = format!("install-{}", task_id);
|
let log_id = format!("install-{}", task_id);
|
||||||
|
emit_task_event(
|
||||||
let _ = handle.emit(
|
&runtime_handle,
|
||||||
"install-status",
|
&log_id,
|
||||||
InstallProgress {
|
&task_id,
|
||||||
id: task_id.clone(),
|
"install",
|
||||||
status: "installing".to_string(),
|
"running",
|
||||||
progress: 0.0,
|
"installing",
|
||||||
},
|
0.0,
|
||||||
|
task_version.clone(),
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut args = vec!["install".to_string()];
|
let mut args = vec!["install".to_string()];
|
||||||
@@ -52,8 +56,19 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
|||||||
if use_manifest && manifest_url.is_some() {
|
if use_manifest && manifest_url.is_some() {
|
||||||
let url = manifest_url.unwrap();
|
let url = manifest_url.unwrap();
|
||||||
display_cmd = format!("Winget Install (Manifest): {} from {}", task_id, url);
|
display_cmd = format!("Winget Install (Manifest): {} from {}", task_id, url);
|
||||||
|
emit_task_event(
|
||||||
|
&runtime_handle,
|
||||||
|
&log_id,
|
||||||
|
&task_id,
|
||||||
|
"install",
|
||||||
|
"running",
|
||||||
|
"downloading_manifest",
|
||||||
|
0.0,
|
||||||
|
task_version.clone(),
|
||||||
|
Some("Downloading remote manifest".to_string()),
|
||||||
|
);
|
||||||
emit_log(
|
emit_log(
|
||||||
&handle,
|
&runtime_handle,
|
||||||
&log_id,
|
&log_id,
|
||||||
&display_cmd,
|
&display_cmd,
|
||||||
"Downloading remote manifest...",
|
"Downloading remote manifest...",
|
||||||
@@ -85,19 +100,22 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
|||||||
|
|
||||||
if temp_manifest_path.is_none() {
|
if temp_manifest_path.is_none() {
|
||||||
emit_log(
|
emit_log(
|
||||||
&handle,
|
&runtime_handle,
|
||||||
&log_id,
|
&log_id,
|
||||||
"Error",
|
"Error",
|
||||||
"Failed to download or save manifest.",
|
"Failed to download or save manifest.",
|
||||||
"error",
|
"error",
|
||||||
);
|
);
|
||||||
let _ = handle.emit(
|
emit_task_event(
|
||||||
"install-status",
|
&runtime_handle,
|
||||||
InstallProgress {
|
&log_id,
|
||||||
id: task_id.clone(),
|
&task_id,
|
||||||
status: "error".to_string(),
|
"install",
|
||||||
progress: 0.0,
|
"failed",
|
||||||
},
|
"manifest_error",
|
||||||
|
0.0,
|
||||||
|
task_version.clone(),
|
||||||
|
Some("Failed to download or save manifest".to_string()),
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -128,12 +146,23 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
|||||||
|
|
||||||
let full_command = format!("winget {}", args.join(" "));
|
let full_command = format!("winget {}", args.join(" "));
|
||||||
emit_log(
|
emit_log(
|
||||||
&handle,
|
&runtime_handle,
|
||||||
&log_id,
|
&log_id,
|
||||||
&display_cmd,
|
&display_cmd,
|
||||||
&format!("Executing: {}\n---", full_command),
|
&format!("Executing: {}\n---", full_command),
|
||||||
"info",
|
"info",
|
||||||
);
|
);
|
||||||
|
emit_task_event(
|
||||||
|
&runtime_handle,
|
||||||
|
&log_id,
|
||||||
|
&task_id,
|
||||||
|
"install",
|
||||||
|
"running",
|
||||||
|
"invoking_winget",
|
||||||
|
0.0,
|
||||||
|
task_version.clone(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
let child = Command::new("winget")
|
let child = Command::new("winget")
|
||||||
.args(&args)
|
.args(&args)
|
||||||
@@ -147,7 +176,7 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
|||||||
let stdout_handle = child_proc.stdout.take().map(|stdout| {
|
let stdout_handle = child_proc.stdout.take().map(|stdout| {
|
||||||
spawn_install_stream_reader(
|
spawn_install_stream_reader(
|
||||||
stdout,
|
stdout,
|
||||||
handle.clone(),
|
runtime_handle.clone(),
|
||||||
log_id.clone(),
|
log_id.clone(),
|
||||||
task_id.clone(),
|
task_id.clone(),
|
||||||
"stdout",
|
"stdout",
|
||||||
@@ -158,7 +187,7 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
|||||||
let stderr_handle = child_proc.stderr.take().map(|stderr| {
|
let stderr_handle = child_proc.stderr.take().map(|stderr| {
|
||||||
spawn_install_stream_reader(
|
spawn_install_stream_reader(
|
||||||
stderr,
|
stderr,
|
||||||
handle.clone(),
|
runtime_handle.clone(),
|
||||||
log_id.clone(),
|
log_id.clone(),
|
||||||
task_id.clone(),
|
task_id.clone(),
|
||||||
"stderr",
|
"stderr",
|
||||||
@@ -177,7 +206,7 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
|||||||
let status_result = if exit_status { "success" } else { "error" };
|
let status_result = if exit_status { "success" } else { "error" };
|
||||||
|
|
||||||
if status_result == "success" && enable_post_install_flag {
|
if status_result == "success" && enable_post_install_flag {
|
||||||
let software_info = essentials_service::get_essentials(&handle)
|
let software_info = essentials_service::get_essentials(&runtime_handle)
|
||||||
.and_then(|repo| repo.essentials.into_iter().find(|s| s.id == task_id));
|
.and_then(|repo| repo.essentials.into_iter().find(|s| s.id == task_id));
|
||||||
|
|
||||||
if let Some(sw) = software_info {
|
if let Some(sw) = software_info {
|
||||||
@@ -188,7 +217,7 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
|||||||
}
|
}
|
||||||
} else if let Some(url) = sw.post_install_url {
|
} else if let Some(url) = sw.post_install_url {
|
||||||
emit_log(
|
emit_log(
|
||||||
&handle,
|
&runtime_handle,
|
||||||
&log_id,
|
&log_id,
|
||||||
"Post-Install",
|
"Post-Install",
|
||||||
"Local config not found, fetching remote config...",
|
"Local config not found, fetching remote config...",
|
||||||
@@ -206,7 +235,7 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
|||||||
match serde_json::from_str::<Vec<PostInstallStep>>(&text) {
|
match serde_json::from_str::<Vec<PostInstallStep>>(&text) {
|
||||||
Ok(steps) => {
|
Ok(steps) => {
|
||||||
emit_log(
|
emit_log(
|
||||||
&handle,
|
&runtime_handle,
|
||||||
&log_id,
|
&log_id,
|
||||||
"Post-Install",
|
"Post-Install",
|
||||||
&format!(
|
&format!(
|
||||||
@@ -219,7 +248,7 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
|||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
emit_log(
|
emit_log(
|
||||||
&handle,
|
&runtime_handle,
|
||||||
&log_id,
|
&log_id,
|
||||||
"Post-Install Error",
|
"Post-Install Error",
|
||||||
&format!("JSON Parse Error: {}. Raw Content: {}", e, text),
|
&format!("JSON Parse Error: {}. Raw Content: {}", e, text),
|
||||||
@@ -230,7 +259,7 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
emit_log(
|
emit_log(
|
||||||
&handle,
|
&runtime_handle,
|
||||||
&log_id,
|
&log_id,
|
||||||
"Post-Install Error",
|
"Post-Install Error",
|
||||||
&format!("Remote config HTTP Error: {}", resp.status()),
|
&format!("Remote config HTTP Error: {}", resp.status()),
|
||||||
@@ -241,26 +270,29 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(steps) = final_steps {
|
if let Some(steps) = final_steps {
|
||||||
let _ = handle.emit(
|
emit_task_event(
|
||||||
"install-status",
|
&runtime_handle,
|
||||||
InstallProgress {
|
&log_id,
|
||||||
id: task_id.clone(),
|
&task_id,
|
||||||
status: "configuring".to_string(),
|
"install",
|
||||||
progress: 1.0,
|
"running",
|
||||||
},
|
"configuring",
|
||||||
|
1.0,
|
||||||
|
task_version.clone(),
|
||||||
|
Some("Starting post-installation configuration".to_string()),
|
||||||
);
|
);
|
||||||
emit_log(
|
emit_log(
|
||||||
&handle,
|
&runtime_handle,
|
||||||
&log_id,
|
&log_id,
|
||||||
"Post-Install",
|
"Post-Install",
|
||||||
"Starting post-installation configuration...",
|
"Starting post-installation configuration...",
|
||||||
"info",
|
"info",
|
||||||
);
|
);
|
||||||
if let Err(e) = execute_post_install(&handle, &log_id, steps).await {
|
if let Err(e) = execute_post_install(&runtime_handle, &log_id, steps).await {
|
||||||
emit_log(&handle, &log_id, "Post-Install Error", &e, "error");
|
emit_log(&runtime_handle, &log_id, "Post-Install Error", &e, "error");
|
||||||
} else {
|
} else {
|
||||||
emit_log(
|
emit_log(
|
||||||
&handle,
|
&runtime_handle,
|
||||||
&log_id,
|
&log_id,
|
||||||
"Post-Install",
|
"Post-Install",
|
||||||
"Post-installation configuration completed.",
|
"Post-installation configuration completed.",
|
||||||
@@ -273,21 +305,35 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
|||||||
status_result
|
status_result
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
emit_log(&handle, &log_id, "Fatal Error", &e.to_string(), "error");
|
emit_log(&runtime_handle, &log_id, "Fatal Error", &e.to_string(), "error");
|
||||||
|
emit_task_event(
|
||||||
|
&runtime_handle,
|
||||||
|
&log_id,
|
||||||
|
&task_id,
|
||||||
|
"install",
|
||||||
|
"failed",
|
||||||
|
"spawn_error",
|
||||||
|
0.0,
|
||||||
|
task_version.clone(),
|
||||||
|
Some(e.to_string()),
|
||||||
|
);
|
||||||
"error"
|
"error"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = handle.emit(
|
emit_task_event(
|
||||||
"install-status",
|
&runtime_handle,
|
||||||
InstallProgress {
|
&log_id,
|
||||||
id: task_id.clone(),
|
&task_id,
|
||||||
status: status_result.to_string(),
|
"install",
|
||||||
progress: 1.0,
|
if status_result == "success" { "completed" } else { "failed" },
|
||||||
},
|
status_result,
|
||||||
|
1.0,
|
||||||
|
task_version.clone(),
|
||||||
|
Some(format!("Execution finished: {}", status_result)),
|
||||||
);
|
);
|
||||||
emit_log(
|
emit_log(
|
||||||
&handle,
|
&runtime_handle,
|
||||||
&log_id,
|
&log_id,
|
||||||
"Result",
|
"Result",
|
||||||
&format!("Execution finished: {}", status_result),
|
&format!("Execution finished: {}", status_result),
|
||||||
@@ -304,7 +350,7 @@ pub fn create_install_state(handle: AppHandle) -> AppState {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AppState { install_tx: tx }
|
AppState { install_tx: tx, app_handle: handle }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -312,6 +358,18 @@ pub async fn install_software(
|
|||||||
task: InstallTask,
|
task: InstallTask,
|
||||||
state: State<'_, AppState>,
|
state: State<'_, AppState>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
|
let log_id = format!("install-{}", task.id);
|
||||||
|
emit_task_event(
|
||||||
|
&state.app_handle,
|
||||||
|
&log_id,
|
||||||
|
&task.id,
|
||||||
|
"install",
|
||||||
|
"queued",
|
||||||
|
"queued",
|
||||||
|
0.0,
|
||||||
|
task.version.clone(),
|
||||||
|
None,
|
||||||
|
);
|
||||||
state.install_tx.send(task).await.map_err(|e| e.to_string())
|
state.install_tx.send(task).await.map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,6 +404,19 @@ fn spawn_install_stream_reader<R: Read + Send + 'static>(
|
|||||||
progress: p_val / 100.0,
|
progress: p_val / 100.0,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
let _ = handle.emit(
|
||||||
|
"task-event",
|
||||||
|
TaskEventPayload {
|
||||||
|
task_id: log_id.clone(),
|
||||||
|
software_id: task_id.clone(),
|
||||||
|
task_type: "install".to_string(),
|
||||||
|
status: "running".to_string(),
|
||||||
|
stage: "installing".to_string(),
|
||||||
|
progress: p_val / 100.0,
|
||||||
|
target_version: None,
|
||||||
|
message: None,
|
||||||
|
},
|
||||||
|
);
|
||||||
is_progress = true;
|
is_progress = true;
|
||||||
}
|
}
|
||||||
} else if let Some(caps) = size_re.captures(clean_line) {
|
} else if let Some(caps) = size_re.captures(clean_line) {
|
||||||
@@ -360,6 +431,19 @@ fn spawn_install_stream_reader<R: Read + Send + 'static>(
|
|||||||
progress: (current / total).min(1.0),
|
progress: (current / total).min(1.0),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
let _ = handle.emit(
|
||||||
|
"task-event",
|
||||||
|
TaskEventPayload {
|
||||||
|
task_id: log_id.clone(),
|
||||||
|
software_id: task_id.clone(),
|
||||||
|
task_type: "install".to_string(),
|
||||||
|
status: "running".to_string(),
|
||||||
|
stage: "installing".to_string(),
|
||||||
|
progress: (current / total).min(1.0),
|
||||||
|
target_version: None,
|
||||||
|
message: None,
|
||||||
|
},
|
||||||
|
);
|
||||||
is_progress = true;
|
is_progress = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -375,6 +459,48 @@ fn spawn_install_stream_reader<R: Read + Send + 'static>(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn emit_task_event(
|
||||||
|
handle: &AppHandle,
|
||||||
|
task_id: &str,
|
||||||
|
software_id: &str,
|
||||||
|
task_type: &str,
|
||||||
|
status: &str,
|
||||||
|
stage: &str,
|
||||||
|
progress: f32,
|
||||||
|
target_version: Option<String>,
|
||||||
|
message: Option<String>,
|
||||||
|
) {
|
||||||
|
let _ = handle.emit(
|
||||||
|
"task-event",
|
||||||
|
TaskEventPayload {
|
||||||
|
task_id: task_id.to_string(),
|
||||||
|
software_id: software_id.to_string(),
|
||||||
|
task_type: task_type.to_string(),
|
||||||
|
status: status.to_string(),
|
||||||
|
stage: stage.to_string(),
|
||||||
|
progress,
|
||||||
|
target_version: target_version.clone(),
|
||||||
|
message,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let legacy_status = match status {
|
||||||
|
"queued" => "pending".to_string(),
|
||||||
|
"completed" => "success".to_string(),
|
||||||
|
"failed" => "error".to_string(),
|
||||||
|
_ => stage.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = handle.emit(
|
||||||
|
"install-status",
|
||||||
|
InstallProgress {
|
||||||
|
id: software_id.to_string(),
|
||||||
|
status: legacy_status,
|
||||||
|
progress,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn expand_win_path(path: &str) -> PathBuf {
|
fn expand_win_path(path: &str) -> PathBuf {
|
||||||
let mut expanded = path.to_string();
|
let mut expanded = path.to_string();
|
||||||
let env_vars = [
|
let env_vars = [
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ import { invoke } from '@tauri-apps/api/core'
|
|||||||
import { listen } from '@tauri-apps/api/event'
|
import { listen } from '@tauri-apps/api/event'
|
||||||
|
|
||||||
import { useCatalogStore } from './catalog'
|
import { useCatalogStore } from './catalog'
|
||||||
import type { ActiveTaskState, LogEntry } from './types'
|
import type { ActiveTaskState, LogEntry, TaskEventPayload, TaskRecord } from './types'
|
||||||
|
|
||||||
export const useTaskRuntimeStore = defineStore('task-runtime', {
|
export const useTaskRuntimeStore = defineStore('task-runtime', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
activeTasks: {} as Record<string, ActiveTaskState>,
|
taskRecords: {} as Record<string, TaskRecord>,
|
||||||
selectedEssentialIds: [] as string[],
|
selectedEssentialIds: [] as string[],
|
||||||
selectedUpdateIds: [] as string[],
|
selectedUpdateIds: [] as string[],
|
||||||
logs: [] as LogEntry[],
|
logs: [] as LogEntry[],
|
||||||
@@ -16,9 +16,21 @@ export const useTaskRuntimeStore = defineStore('task-runtime', {
|
|||||||
postInstallPrefs: {} as Record<string, boolean>
|
postInstallPrefs: {} as Record<string, boolean>
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
isTaskBusy: (state) => Object.values(state.activeTasks).some(task =>
|
activeTasks: (state): Record<string, ActiveTaskState> => {
|
||||||
task.status === 'pending' || task.status === 'installing'
|
return Object.values(state.taskRecords).reduce<Record<string, ActiveTaskState>>((acc, task) => {
|
||||||
|
acc[task.softwareId] = {
|
||||||
|
status: mapTaskToLegacyStatus(task),
|
||||||
|
progress: task.progress,
|
||||||
|
targetVersion: task.targetVersion
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
},
|
||||||
|
isTaskBusy(): boolean {
|
||||||
|
return Object.values(this.taskRecords).some(task =>
|
||||||
|
task.status === 'queued' || task.status === 'running'
|
||||||
)
|
)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
toggleSelection(id: string, type: 'essential' | 'update') {
|
toggleSelection(id: string, type: 'essential' | 'update') {
|
||||||
@@ -48,7 +60,6 @@ export const useTaskRuntimeStore = defineStore('task-runtime', {
|
|||||||
if (!software) return
|
if (!software) return
|
||||||
|
|
||||||
const enablePostInstall = this.postInstallPrefs[id] !== false
|
const enablePostInstall = this.postInstallPrefs[id] !== false
|
||||||
this.activeTasks[id] = { status: 'pending', progress: 0, targetVersion }
|
|
||||||
try {
|
try {
|
||||||
await invoke('install_software', {
|
await invoke('install_software', {
|
||||||
task: {
|
task: {
|
||||||
@@ -61,7 +72,16 @@ export const useTaskRuntimeStore = defineStore('task-runtime', {
|
|||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Invoke install failed:', err)
|
console.error('Invoke install failed:', err)
|
||||||
this.activeTasks[id] = { status: 'error', progress: 0 }
|
this.taskRecords[`install-${id}`] = {
|
||||||
|
taskId: `install-${id}`,
|
||||||
|
softwareId: id,
|
||||||
|
taskType: 'install',
|
||||||
|
status: 'failed',
|
||||||
|
stage: 'invoke_error',
|
||||||
|
progress: 0,
|
||||||
|
targetVersion,
|
||||||
|
message: String(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -71,10 +91,10 @@ export const useTaskRuntimeStore = defineStore('task-runtime', {
|
|||||||
|
|
||||||
this.refreshTimer = setTimeout(async () => {
|
this.refreshTimer = setTimeout(async () => {
|
||||||
await catalog.fetchAllData()
|
await catalog.fetchAllData()
|
||||||
Object.keys(this.activeTasks).forEach(id => {
|
Object.keys(this.taskRecords).forEach(taskId => {
|
||||||
const status = this.activeTasks[id].status
|
const status = this.taskRecords[taskId].status
|
||||||
if (status === 'success' || status === 'error') {
|
if (status === 'completed' || status === 'failed') {
|
||||||
delete this.activeTasks[id]
|
delete this.taskRecords[taskId]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.refreshTimer = null
|
this.refreshTimer = null
|
||||||
@@ -85,19 +105,28 @@ export const useTaskRuntimeStore = defineStore('task-runtime', {
|
|||||||
if ((window as Window & { __tauri_listener_init?: boolean }).__tauri_listener_init) return
|
if ((window as Window & { __tauri_listener_init?: boolean }).__tauri_listener_init) return
|
||||||
;(window as Window & { __tauri_listener_init?: boolean }).__tauri_listener_init = true
|
;(window as Window & { __tauri_listener_init?: boolean }).__tauri_listener_init = true
|
||||||
|
|
||||||
listen('install-status', async (event: { payload: { id: string, status: string, progress: number } }) => {
|
listen('task-event', async (event: { payload: TaskEventPayload }) => {
|
||||||
const catalog = useCatalogStore()
|
const catalog = useCatalogStore()
|
||||||
const { id, status, progress } = event.payload
|
const payload = event.payload
|
||||||
const task = this.activeTasks[id]
|
const taskRecord: TaskRecord = {
|
||||||
|
taskId: payload.task_id,
|
||||||
|
softwareId: payload.software_id,
|
||||||
|
taskType: payload.task_type,
|
||||||
|
status: payload.status,
|
||||||
|
stage: payload.stage,
|
||||||
|
progress: payload.progress,
|
||||||
|
targetVersion: payload.target_version ?? undefined,
|
||||||
|
message: payload.message ?? undefined
|
||||||
|
}
|
||||||
|
|
||||||
this.activeTasks[id] = { status, progress, targetVersion: task?.targetVersion }
|
this.taskRecords[payload.task_id] = taskRecord
|
||||||
|
|
||||||
if (status === 'success' || status === 'error') {
|
if (payload.status === 'completed' || payload.status === 'failed') {
|
||||||
if (status === 'success') {
|
if (payload.status === 'completed') {
|
||||||
try {
|
try {
|
||||||
const latestInfo = await invoke('get_software_info', { id }) as Record<string, unknown> | null
|
const latestInfo = await invoke('get_software_info', { id: payload.software_id }) as Record<string, unknown> | null
|
||||||
if (latestInfo) {
|
if (latestInfo) {
|
||||||
const index = catalog.allSoftware.findIndex(s => s.id.toLowerCase() === id.toLowerCase())
|
const index = catalog.allSoftware.findIndex(s => s.id.toLowerCase() === payload.software_id.toLowerCase())
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
catalog.allSoftware[index] = { ...catalog.allSoftware[index], ...latestInfo }
|
catalog.allSoftware[index] = { ...catalog.allSoftware[index], ...latestInfo }
|
||||||
} else {
|
} else {
|
||||||
@@ -108,17 +137,17 @@ export const useTaskRuntimeStore = defineStore('task-runtime', {
|
|||||||
console.error('Partial refresh failed:', err)
|
console.error('Partial refresh failed:', err)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.selectedEssentialIds = this.selectedEssentialIds.filter(item => item !== id)
|
this.selectedEssentialIds = this.selectedEssentialIds.filter(item => item !== payload.software_id)
|
||||||
this.selectedUpdateIds = this.selectedUpdateIds.filter(item => item !== id)
|
this.selectedUpdateIds = this.selectedUpdateIds.filter(item => item !== payload.software_id)
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (this.activeTasks[id]?.status === 'success') {
|
if (this.taskRecords[payload.task_id]?.status === 'completed') {
|
||||||
delete this.activeTasks[id]
|
delete this.taskRecords[payload.task_id]
|
||||||
}
|
}
|
||||||
}, 3000)
|
}, 3000)
|
||||||
}
|
}
|
||||||
|
|
||||||
const index = this.batchQueue.indexOf(id)
|
const index = this.batchQueue.indexOf(payload.software_id)
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
this.batchQueue.splice(index, 1)
|
this.batchQueue.splice(index, 1)
|
||||||
if (this.batchQueue.length === 0) {
|
if (this.batchQueue.length === 0) {
|
||||||
@@ -128,6 +157,11 @@ export const useTaskRuntimeStore = defineStore('task-runtime', {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
listen('install-status', () => {
|
||||||
|
// Compatibility event is still emitted by the backend, but task-runtime
|
||||||
|
// now derives runtime state from the richer task-event stream.
|
||||||
|
})
|
||||||
|
|
||||||
listen('log-event', (event: { payload: LogEntry }) => {
|
listen('log-event', (event: { payload: LogEntry }) => {
|
||||||
const payload = event.payload
|
const payload = event.payload
|
||||||
const existingLog = this.logs.find(item => item.id === payload.id)
|
const existingLog = this.logs.find(item => item.id === payload.id)
|
||||||
@@ -142,3 +176,11 @@ export const useTaskRuntimeStore = defineStore('task-runtime', {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function mapTaskToLegacyStatus(task: TaskRecord): string {
|
||||||
|
if (task.status === 'queued') return 'pending'
|
||||||
|
if (task.status === 'completed') return 'success'
|
||||||
|
if (task.status === 'failed') return 'error'
|
||||||
|
if (task.stage === 'configuring') return 'configuring'
|
||||||
|
return 'installing'
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,6 +47,28 @@ export interface ActiveTaskState {
|
|||||||
targetVersion?: string
|
targetVersion?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TaskRecord {
|
||||||
|
taskId: string
|
||||||
|
softwareId: string
|
||||||
|
taskType: string
|
||||||
|
status: string
|
||||||
|
stage: string
|
||||||
|
progress: number
|
||||||
|
targetVersion?: string
|
||||||
|
message?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TaskEventPayload {
|
||||||
|
task_id: string
|
||||||
|
software_id: string
|
||||||
|
task_type: string
|
||||||
|
status: string
|
||||||
|
stage: string
|
||||||
|
progress: number
|
||||||
|
target_version?: string | null
|
||||||
|
message?: string | null
|
||||||
|
}
|
||||||
|
|
||||||
export interface AppSettings {
|
export interface AppSettings {
|
||||||
repo_url: string
|
repo_url: string
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user