Add app update detection and multi-folder project support
Feature 1 - Update Detection: Query Gitea releases API on startup (3s
delay) and every 24h, compare patch versions by platform, show pulsing
"Update" button in TopBar with dialog for release notes/downloads.
Settings: auto-check toggle, manual check, dismiss per-version.
Feature 2 - Multi-Folder Projects: Replace single `path` with
`paths: Vec<ProjectPath>` (host_path + mount_name). Each folder mounts
to `/workspace/{mount_name}`. Auto-migrate old single-path JSON on load.
Container recreation via paths-fingerprint label. AddProjectDialog and
ProjectCard support add/remove/edit of multiple folders.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
72
app/src/hooks/useUpdates.ts
Normal file
72
app/src/hooks/useUpdates.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { useCallback, useRef } from "react";
|
||||
import { useShallow } from "zustand/react/shallow";
|
||||
import { useAppState } from "../store/appState";
|
||||
import * as commands from "../lib/tauri-commands";
|
||||
|
||||
const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
||||
|
||||
export function useUpdates() {
|
||||
const { updateInfo, setUpdateInfo, appVersion, setAppVersion, appSettings } =
|
||||
useAppState(
|
||||
useShallow((s) => ({
|
||||
updateInfo: s.updateInfo,
|
||||
setUpdateInfo: s.setUpdateInfo,
|
||||
appVersion: s.appVersion,
|
||||
setAppVersion: s.setAppVersion,
|
||||
appSettings: s.appSettings,
|
||||
})),
|
||||
);
|
||||
|
||||
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
||||
|
||||
const loadVersion = useCallback(async () => {
|
||||
try {
|
||||
const version = await commands.getAppVersion();
|
||||
setAppVersion(version);
|
||||
} catch (e) {
|
||||
console.error("Failed to load app version:", e);
|
||||
}
|
||||
}, [setAppVersion]);
|
||||
|
||||
const checkForUpdates = useCallback(async () => {
|
||||
try {
|
||||
const info = await commands.checkForUpdates();
|
||||
if (info) {
|
||||
// Respect dismissed version
|
||||
const dismissed = appSettings?.dismissed_update_version;
|
||||
if (dismissed && dismissed === info.version) {
|
||||
setUpdateInfo(null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
setUpdateInfo(info);
|
||||
return info;
|
||||
} catch (e) {
|
||||
console.error("Failed to check for updates:", e);
|
||||
return null;
|
||||
}
|
||||
}, [setUpdateInfo, appSettings?.dismissed_update_version]);
|
||||
|
||||
const startPeriodicCheck = useCallback(() => {
|
||||
if (intervalRef.current) return;
|
||||
intervalRef.current = setInterval(() => {
|
||||
if (appSettings?.auto_check_updates !== false) {
|
||||
checkForUpdates();
|
||||
}
|
||||
}, CHECK_INTERVAL_MS);
|
||||
return () => {
|
||||
if (intervalRef.current) {
|
||||
clearInterval(intervalRef.current);
|
||||
intervalRef.current = null;
|
||||
}
|
||||
};
|
||||
}, [checkForUpdates, appSettings?.auto_check_updates]);
|
||||
|
||||
return {
|
||||
updateInfo,
|
||||
appVersion,
|
||||
loadVersion,
|
||||
checkForUpdates,
|
||||
startPeriodicCheck,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user