address comments

This commit is contained in:
Eva Ho 2025-12-19 15:27:15 -05:00
parent 391fb88bce
commit 9a5c14c58b
10 changed files with 45 additions and 165 deletions

View File

@ -267,15 +267,12 @@ func main() {
},
Store: st,
ToolRegistry: toolRegistry,
Dev: devMode,
Logger: slog.Default(),
Updater: upd,
Dev: devMode,
Logger: slog.Default(),
Updater: upd,
UpdateAvailableFunc: func() {
UpdateAvailable("")
},
ClearUpdateAvailableFunc: func() {
ClearUpdateAvailable()
},
}
srv := &http.Server{
@ -295,6 +292,12 @@ func main() {
upd.StartBackgroundUpdaterChecker(ctx, UpdateAvailable)
// Check for pending updates on startup (show tray notification if update is ready)
if updater.IsUpdatePending() {
slog.Debug("update pending on startup, showing tray notification")
UpdateAvailable("")
}
hasCompletedFirstRun, err := st.HasCompletedFirstRun()
if err != nil {
slog.Error("failed to load has completed first run", "error", err)
@ -356,13 +359,15 @@ func startHiddenTasks() {
// CLI triggered app startup use-case
slog.Info("deferring pending update for fast startup")
} else {
// Check if auto-update is enabled before upgrading
// Check if auto-update is enabled before automatically upgrading
st := &store.Store{}
settings, err := st.Settings()
if err != nil {
slog.Warn("failed to load settings for upgrade check", "error", err)
} else if !settings.AutoUpdateEnabled {
slog.Info("auto-update disabled, skipping automatic upgrade at startup")
// Still show tray notification so user knows update is ready
UpdateAvailable("")
return
}

View File

@ -172,14 +172,6 @@ func UpdateAvailable(ver string) error {
return nil
}
func ClearUpdateAvailable() error {
slog.Debug("clearing update notification")
if updater.BundlePath != "" {
C.clearUpdateAvailable()
}
return nil
}
func osRun(_ func(), hasCompletedFirstRun, startHidden bool) {
registerLaunchAgent(hasCompletedFirstRun)

View File

@ -30,7 +30,6 @@ void StartUpdate();
void darwinStartHiddenTasks();
void launchApp(const char *appPath);
void updateAvailable();
void clearUpdateAvailable();
void quit();
void uiRequest(char *path);
void registerSelfAsLoginItem(bool firstTimeRun);

View File

@ -241,12 +241,6 @@ bool firstTimeRun,startHidden; // Set in run before initialization
[self showIcon];
}
- (void)clearUpdateAvailable {
self.updateAvailable = NO;
[self.statusItem.menu.itemArray[3] setHidden:YES];
[self.statusItem.menu.itemArray[4] setHidden:YES];
}
- (void)aboutOllama {
[[NSApplication sharedApplication] orderFrontStandardAboutPanel:nil];
[NSApp activateIgnoringOtherApps:YES];
@ -979,12 +973,6 @@ void updateAvailable() {
});
}
void clearUpdateAvailable() {
dispatch_async(dispatch_get_main_queue(), ^{
[appDelegate clearUpdateAvailable];
});
}
void quit() {
dispatch_async(dispatch_get_main_queue(), ^{
[appDelegate quit];

View File

@ -453,20 +453,6 @@ export async function checkForUpdate(): Promise<{
return data.updateInfo;
}
export async function downloadUpdate(version: string): Promise<void> {
const response = await fetch(`${API_BASE}/api/v1/update/download`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ version }),
});
if (!response.ok) {
const error = await response.text();
throw new Error(error || "Failed to download update");
}
}
export async function installUpdate(): Promise<void> {
const response = await fetch(`${API_BASE}/api/v1/update/install`, {
method: "POST",

View File

@ -375,14 +375,14 @@ export default function Settings() {
<Description>
{settings.AutoUpdateEnabled ? (
<>
Automatically downloads updates and restarts the app.
Automatically downloads updates when available.
<div className="mt-2 text-xs text-zinc-600 dark:text-zinc-400">
Current version: {updateInfo?.currentVersion || "Loading..."}
</div>
</>
) : (
<>
You must manually check for updates.
Manually download updates.
<div className="mt-3 p-3 bg-zinc-50 dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800">
<div className="space-y-2 text-sm">
<div className="flex justify-between">

View File

@ -109,15 +109,13 @@ type Server struct {
Dev bool
// Updater for checking and downloading updates
Updater UpdaterInterface
UpdateAvailableFunc func()
ClearUpdateAvailableFunc func()
Updater UpdaterInterface
UpdateAvailableFunc func()
}
// UpdaterInterface defines the methods we need from the updater
type UpdaterInterface interface {
CheckForUpdate(ctx context.Context) (bool, string, error)
DownloadUpdate(ctx context.Context, updateVersion string) error
InstallAndRestart() error
CancelOngoingDownload()
TriggerImmediateCheck()
@ -300,7 +298,6 @@ func (s *Server) Handler() http.Handler {
mux.Handle("GET /api/v1/settings", handle(s.getSettings))
mux.Handle("POST /api/v1/settings", handle(s.settings))
mux.Handle("GET /api/v1/update/check", handle(s.checkForUpdate))
mux.Handle("POST /api/v1/update/download", handle(s.downloadUpdate))
mux.Handle("POST /api/v1/update/install", handle(s.installUpdate))
// Ollama proxy endpoints
@ -1469,13 +1466,10 @@ func (s *Server) settings(w http.ResponseWriter, r *http.Request) error {
// Handle auto-update toggle changes
if old.AutoUpdateEnabled != settings.AutoUpdateEnabled {
if !settings.AutoUpdateEnabled {
// Auto-update disabled: cancel any ongoing download and clear tray notification
// Auto-update disabled: cancel any ongoing download
if s.Updater != nil {
s.Updater.CancelOngoingDownload()
}
if s.ClearUpdateAvailableFunc != nil {
s.ClearUpdateAvailableFunc()
}
} else {
// Auto-update re-enabled: show notification if update is already staged, or trigger immediate check
if (updater.IsUpdatePending() || updater.UpdateDownloaded) && s.UpdateAvailableFunc != nil {
@ -1589,41 +1583,6 @@ func (s *Server) checkForUpdate(w http.ResponseWriter, r *http.Request) error {
return json.NewEncoder(w).Encode(response)
}
func (s *Server) downloadUpdate(w http.ResponseWriter, r *http.Request) error {
if r.Method != "POST" {
return fmt.Errorf("method not allowed")
}
if s.Updater == nil {
return fmt.Errorf("updater not available")
}
var req struct {
Version string `json:"version"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return fmt.Errorf("invalid request body: %w", err)
}
if req.Version == "" {
return fmt.Errorf("version is required")
}
err := s.Updater.DownloadUpdate(r.Context(), req.Version)
if err != nil {
s.log().Error("failed to download update", "error", err, "version", req.Version)
return fmt.Errorf("failed to download update: %w", err)
}
response := map[string]any{
"success": true,
"message": "Update downloaded successfully",
}
w.Header().Set("Content-Type", "application/json")
return json.NewEncoder(w).Encode(response)
}
func (s *Server) installUpdate(w http.ResponseWriter, r *http.Request) error {
if r.Method != "POST" {
return fmt.Errorf("method not allowed")

View File

@ -303,35 +303,37 @@ func (u *Updater) StartBackgroundUpdaterChecker(ctx context.Context, cb func(str
// Regular interval check
}
// Always check for updates
available, resp := u.checkForUpdate(ctx)
if !available {
continue
}
// Always check for updates
available, resp := u.checkForUpdate(ctx)
if !available {
continue
}
// Update is available - check if auto-update is enabled
settings, err := u.Store.Settings()
if err != nil {
slog.Error("failed to load settings", "error", err)
continue
}
// Update is available - check if auto-update is enabled for downloading
settings, err := u.Store.Settings()
if err != nil {
slog.Error("failed to load settings", "error", err)
continue
}
if !settings.AutoUpdateEnabled {
// Auto-update disabled - don't download, just log
slog.Debug("update available but auto-update disabled", "version", resp.UpdateVersion)
continue
}
if !settings.AutoUpdateEnabled {
// Auto-update disabled - don't download, just log
slog.Debug("update available but auto-update disabled", "version", resp.UpdateVersion)
continue
}
// Auto-update is enabled - download and notify
err = u.DownloadNewRelease(ctx, resp)
if err != nil {
slog.Error("failed to download new release", "error", err)
} else {
err = cb(resp.UpdateVersion)
if err != nil {
slog.Warn("failed to register update available with tray", "error", err)
}
}
// Auto-update is enabled - download
err = u.DownloadNewRelease(ctx, resp)
if err != nil {
slog.Error("failed to download new release", "error", err)
continue
}
// Download successful - show tray notification (regardless of toggle state)
err = cb(resp.UpdateVersion)
if err != nil {
slog.Warn("failed to register update available with tray", "error", err)
}
}
}()
}
@ -341,28 +343,6 @@ func (u *Updater) CheckForUpdate(ctx context.Context) (bool, string, error) {
return available, resp.UpdateVersion, nil
}
func (u *Updater) DownloadUpdate(ctx context.Context, updateVersion string) error {
// First check for update to get the actual download URL
available, updateResp := u.checkForUpdate(ctx)
if !available {
return fmt.Errorf("no update available")
}
if updateResp.UpdateVersion != updateVersion {
slog.Error("version mismatch", "requested", updateVersion, "available", updateResp.UpdateVersion)
return fmt.Errorf("version mismatch: requested %s, available %s", updateVersion, updateResp.UpdateVersion)
}
slog.Info("downloading update", "version", updateVersion)
err := u.DownloadNewRelease(ctx, updateResp)
if err != nil {
return err
}
slog.Info("update downloaded successfully", "version", updateVersion)
return nil
}
func (u *Updater) InstallAndRestart() error {
if !UpdateDownloaded {
return fmt.Errorf("no update downloaded")

View File

@ -47,34 +47,6 @@ func (t *winTray) initMenus() error {
return nil
}
func (t *winTray) ClearUpdateAvailable() error {
if t.updateNotified {
slog.Debug("clearing update notification and menu items")
if err := t.removeMenuItem(updateSeparatorMenuID, 0); err != nil {
return fmt.Errorf("unable to remove menu entries %w", err)
}
if err := t.removeMenuItem(updateAvailableMenuID, 0); err != nil {
return fmt.Errorf("unable to remove menu entries %w", err)
}
if err := t.removeMenuItem(updateMenuID, 0); err != nil {
return fmt.Errorf("unable to remove menu entries %w", err)
}
if err := t.removeMenuItem(separatorMenuID, 0); err != nil {
return fmt.Errorf("unable to remove menu entries %w", err)
}
iconFilePath, err := iconBytesToFilePath(wt.normalIcon)
if err != nil {
return fmt.Errorf("unable to write icon data to temp file: %w", err)
}
if err := t.setIcon(iconFilePath); err != nil {
return fmt.Errorf("unable to set icon: %w", err)
}
t.updateNotified = false
t.pendingUpdate = false
}
return nil
}
func (t *winTray) UpdateAvailable(ver string) error {
if !t.updateNotified {
slog.Debug("updating menu and sending notification for new update")

View File

@ -41,7 +41,6 @@ type TrayCallbacks interface {
Quit()
TrayRun()
UpdateAvailable(ver string) error
ClearUpdateAvailable() error
GetIconHandle() windows.Handle
}