fix(desktop): change updater endpoint and some UX improvements (#4794)
fix: change updater endpoint and better UX
This commit is contained in:
parent
af604ab392
commit
a1e581632d
6 changed files with 92 additions and 50 deletions
|
|
@ -29,13 +29,6 @@ pub fn run() {
|
|||
.plugin(tauri_plugin_updater::Builder::new().build())?;
|
||||
Ok(())
|
||||
})
|
||||
.setup(|app| {
|
||||
let handle = app.handle().clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
updater::check_and_install_updates(&handle).await;
|
||||
});
|
||||
Ok(())
|
||||
})
|
||||
.setup(|app| {
|
||||
let handle = app.handle().clone();
|
||||
tracing::info!(app_name = %app.package_info().name, "Configuring deep link handler");
|
||||
|
|
@ -78,7 +71,8 @@ pub fn run() {
|
|||
.plugin(tauri_plugin_relay::init())
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
hopp_auth_port,
|
||||
updater::check_updates_and_wait
|
||||
updater::check_updates_available,
|
||||
updater::install_updates_and_restart
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
|
|
|||
|
|
@ -2,19 +2,40 @@ use tauri_plugin_dialog::DialogExt;
|
|||
use tauri_plugin_updater::UpdaterExt;
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn check_updates_and_wait(app: tauri::AppHandle) -> Result<String, String> {
|
||||
check_and_install_updates(&app).await;
|
||||
Ok("Update check completed".to_string())
|
||||
}
|
||||
|
||||
pub async fn check_and_install_updates(app: &tauri::AppHandle) {
|
||||
pub async fn check_updates_available(app: tauri::AppHandle) -> Result<bool, String> {
|
||||
tracing::info!("Checking for updates...");
|
||||
|
||||
let updater = match app.updater() {
|
||||
Ok(updater) => updater,
|
||||
Err(e) => {
|
||||
tracing::error!(error = %e, "Failed to initialize updater");
|
||||
return;
|
||||
return Ok(false);
|
||||
}
|
||||
};
|
||||
|
||||
match updater.check().await {
|
||||
Ok(Some(_update)) => {
|
||||
tracing::info!("Update available");
|
||||
Ok(true)
|
||||
}
|
||||
Ok(None) => {
|
||||
tracing::info!("No updates available");
|
||||
Ok(false)
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!(error = %e, "Failed to check for updates");
|
||||
Err(format!("Failed to check for updates: {}", e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn install_updates_and_restart(app: tauri::AppHandle) -> Result<(), String> {
|
||||
tracing::info!("Installing updates...");
|
||||
let updater = match app.updater() {
|
||||
Ok(updater) => updater,
|
||||
Err(e) => {
|
||||
tracing::error!(error = %e, "Failed to initialize updater");
|
||||
return Err(format!("Failed to initialize updater: {}", e));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -23,7 +44,7 @@ pub async fn check_and_install_updates(app: &tauri::AppHandle) {
|
|||
tracing::info!(
|
||||
current_version = app.package_info().version.to_string(),
|
||||
update_version = update.version.to_string(),
|
||||
"Update available"
|
||||
"Installing update"
|
||||
);
|
||||
|
||||
let dialog = app.dialog();
|
||||
|
|
@ -40,32 +61,35 @@ pub async fn check_and_install_updates(app: &tauri::AppHandle) {
|
|||
|
||||
if should_update {
|
||||
tracing::info!("User agreed to update, starting download...");
|
||||
|
||||
match update.download_and_install(|_, _| {}, || {}).await {
|
||||
Ok(_) => {
|
||||
tracing::info!("Update installed successfully, restarting app");
|
||||
app.restart();
|
||||
Err("Unreachable - app should have restarted".to_string())
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!(error = %e, "Failed to download or install update");
|
||||
|
||||
let _ = app
|
||||
.dialog()
|
||||
.message(format!("Failed to install update: {}", e))
|
||||
.title("Update Error")
|
||||
.kind(tauri_plugin_dialog::MessageDialogKind::Error)
|
||||
.blocking_show();
|
||||
Err(format!("Failed to download or install update: {}", e))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tracing::info!("User declined the update");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
tracing::info!("No updates available");
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!(error = %e, "Failed to check for updates");
|
||||
Err(format!("Failed to check for updates: {}", e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
"plugins": {
|
||||
"updater": {
|
||||
"active": true,
|
||||
"endpoints": ["https://releases.hoppscotch.com/hoppscotch-desktop.json"],
|
||||
"endpoints": ["https://releases.hoppscotch.com/hoppscotch-selfhost-desktop.json"],
|
||||
"dialog": true,
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDYwOURFNEY4RDRGMDQxNTgKUldSWVFmRFUrT1NkWUc1RDM0Z2ZjTHE2dG52Q3ZlYzg3ZXVpZU9KaENPWTBMd3MwY0hWa1lreDcK"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<template>
|
||||
<div class="flex h-screen overflow-hidden bg-primary text-secondary">
|
||||
<LayoutSidebar v-model:expanded="sidebarExpanded" v-model:open="sidebarOpen" />
|
||||
<div class="flex-1 flex flex-col overflow-hidden">
|
||||
<main class="flex-1 overflow-y-auto bg-primary">
|
||||
<div class="container mx-auto flex items-center justify-center">
|
||||
|
|
@ -15,10 +14,5 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue"
|
||||
import { Toaster } from "@hoppscotch/ui"
|
||||
import LayoutSidebar from "~/components/layout/LayoutSidebar.vue"
|
||||
|
||||
const sidebarOpen = ref(false)
|
||||
const sidebarExpanded = ref(true)
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ export {}
|
|||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary']
|
||||
HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem']
|
||||
HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner']
|
||||
LayoutHeader: typeof import('./components/layout/LayoutHeader.vue')['default']
|
||||
LayoutSidebar: typeof import('./components/layout/LayoutSidebar.vue')['default']
|
||||
Tippy: typeof import('vue-tippy')['Tippy']
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@
|
|||
</div>
|
||||
|
||||
<div v-if="isLoading" class="flex flex-col items-center space-y-4">
|
||||
<div class="loading-spinner w-10 h-10 border-4 border-t-purple-500 rounded-full animate-spin"></div>
|
||||
<p class="text-secondary">Loading Hoppscotch...</p>
|
||||
<HoppSmartSpinner />
|
||||
</div>
|
||||
|
||||
<div v-else-if="error" class="flex flex-col items-center space-y-4">
|
||||
|
|
@ -153,13 +152,17 @@ const migrateFromLocalStorage = async () => {
|
|||
console.log(`Migration complete. Migrated ${migratedCount} items.`);
|
||||
};
|
||||
|
||||
interface UpdateCheckResult {
|
||||
status: "completed" | "timeout";
|
||||
hasUpdates?: boolean;
|
||||
}
|
||||
|
||||
const loadVendored = async () => {
|
||||
isLoading.value = true;
|
||||
error.value = "";
|
||||
|
||||
try {
|
||||
console.log("Initializing home_store and starting migration process");
|
||||
|
||||
await home_store.init();
|
||||
await app_store.init();
|
||||
|
||||
|
|
@ -173,36 +176,63 @@ const loadVendored = async () => {
|
|||
console.error("Migration error:", migrationError);
|
||||
}
|
||||
|
||||
let shouldProceedWithLoad = true;
|
||||
|
||||
try {
|
||||
console.log("Checking for updates before loading app...");
|
||||
await invoke('check_updates_and_wait');
|
||||
console.log("Update check completed");
|
||||
|
||||
const timeoutPromise: Promise<UpdateCheckResult> = new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
console.log("Update check timeout reached, proceeding with app load");
|
||||
resolve({ status: "timeout" });
|
||||
}, 2000); // TODO: 2s shoud be good?
|
||||
});
|
||||
|
||||
const result = await Promise.race([
|
||||
invoke('check_updates_available').then(hasUpdates => ({ status: "completed", hasUpdates })),
|
||||
timeoutPromise
|
||||
]);
|
||||
|
||||
console.log("Update check result:", result);
|
||||
|
||||
if (result.status === "completed" && result.hasUpdates) {
|
||||
console.log("Updates available, handling before loading app");
|
||||
shouldProceedWithLoad = false;
|
||||
|
||||
await invoke('install_updates_and_restart');
|
||||
// This point would only be reached if install_updates_and_restart
|
||||
// doesn't actually restart the app
|
||||
return;
|
||||
}
|
||||
} catch (updateError) {
|
||||
console.error("Update check error:", updateError);
|
||||
// Continue with loading the app despite update check errors
|
||||
}
|
||||
|
||||
const vendoredInstance: VendoredInstance = {
|
||||
type: "vendored",
|
||||
displayName: "Vendored",
|
||||
version: "vendored"
|
||||
};
|
||||
if (shouldProceedWithLoad) {
|
||||
const vendoredInstance: VendoredInstance = {
|
||||
type: "vendored",
|
||||
displayName: "Vendored",
|
||||
version: "vendored"
|
||||
};
|
||||
|
||||
await saveConnectionState({
|
||||
status: "connected",
|
||||
instance: vendoredInstance
|
||||
});
|
||||
await saveConnectionState({
|
||||
status: "connected",
|
||||
instance: vendoredInstance
|
||||
});
|
||||
|
||||
console.log("Loading vendored app...");
|
||||
const loadResp = await load({
|
||||
bundleName: "Hoppscotch",
|
||||
window: { title: "Hoppscotch" }
|
||||
});
|
||||
console.log("Loading vendored app...");
|
||||
const loadResp = await load({
|
||||
bundleName: "Hoppscotch",
|
||||
window: { title: "Hoppscotch" }
|
||||
});
|
||||
|
||||
if (!loadResp.success) {
|
||||
throw new Error("Failed to load Hoppscotch Vendored");
|
||||
if (!loadResp.success) {
|
||||
throw new Error("Failed to load Hoppscotch Vendored");
|
||||
}
|
||||
|
||||
console.log("Vendored app loaded successfully");
|
||||
}
|
||||
|
||||
console.log("Vendored app loaded successfully");
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : String(err);
|
||||
console.error("Error loading vendored app:", errorMessage);
|
||||
|
|
|
|||
Loading…
Reference in a new issue