address comments
This commit is contained in:
parent
391fb88bce
commit
9a5c14c58b
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
47
app/ui/ui.go
47
app/ui/ui.go
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ type TrayCallbacks interface {
|
|||
Quit()
|
||||
TrayRun()
|
||||
UpdateAvailable(ver string) error
|
||||
ClearUpdateAvailable() error
|
||||
GetIconHandle() windows.Handle
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue