Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ struct PageFactory {
? nil : DaemonUpdateBoard.updateRefused
})),
PageRoute(prefix: WebUpdatesPageProvider.prefix, provider: WebUpdatesPageProvider()),
PageRoute(prefix: AppUpdatePageProvider.prefix, provider: AppUpdatePageProvider(updater: services.updater)),
// Chief > Voice input: the home.voiceInput tunable (DEV and NIGHTLY).
PageRoute(prefix: ChiefVoiceInputPageRoute.prefix, provider: ChiefVoiceInputPageRoute()),
// Settings > Menus: right-click menu arrangements (cmux.json contextMenus).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import CmuxNextPages
import CmuxNextSettings
import CmuxNextServer
import CmuxNextSettingsWindow
import CmuxNextUpdater
import CmuxNextWebUpdates

/// What the React Settings page shows beside the schema rows (R82 commit 2): `cmux.settings.host.lists`.
Expand Down Expand Up @@ -66,6 +67,7 @@ extension SettingsWindowService {
"server": services.serverUpdates.settingsPageJSON,
"import_suggestions": ImportSuggestionsCenter.shared.settingsJSON,
"web_updates": WebUpdates.shared.pageJSON,
"app_update": services.updater.settingsPageJSON,
// Chief > Voice input: home.voiceInput, null where the tunable does not exist (Release).
"voice_input": ChiefVoiceInputPageRoute().hostJSON,
// Settings > Menus: every right-click menu's rows and the person's arrangement of it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,10 @@ extension UpdaterService {
// active window's sidebar hidden (or no window) nothing would show, so the sheet
// answers instead (never a check with no visible feedback).
showsIndicator = { [weak services] in (services?.windows.active).map { !$0.state.sidebarHidden } ?? false }
openChangelog = { [weak services] in
return services.map { ChangelogPageTab.open($0) } ?? false
}
openChangelog = { [weak services] in services.map { ChangelogPageTab.open($0) } ?? false }
// "See What's New" on the Updated card: the React changelog page
// for the releases this update crossed (`#/?from=&to=`).
openChangelogSpan = { [weak services] from, to in
return services.map { ChangelogPageTab.open($0, from: from, to: to) } ?? false
}
openChangelogSpan = { [weak services] from, to in services.map { ChangelogPageTab.open($0, from: from, to: to) } ?? false }
openReleaseNotesURL = { [weak services] url in
guard let services, url.scheme == "https" else { return false }
SidebarCardFeed.openUpdateLink(url, services: services)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ public nonisolated struct SettingsPageLayout: Sendable {
case importSuggestions
/// Every release channel's recent builds, with the one this Mac runs (Settings > Updates).
case channels
/// The app update's status: a check, a download's progress and Cancel, Restart to Update, a
/// failure's Try Again (Settings > Updates; the sidebar shows only the staged update).
case appUpdate
/// The web UI served now, its last check and Roll Back (plans/cmux-next/web-ota.md); NIGHTLY only.
case webUpdates
/// Settings > Chief's Voice input row: the Debug toggle home.voiceInput, only where it exists.
Expand Down Expand Up @@ -184,7 +187,7 @@ public nonisolated struct SettingsPageLayout: Sendable {
],
trail: [.spaces], actions: [.general, .rooms], aliases: [.general, .rooms])

// How this Mac updates, then every channel's recent builds (docs/release-rings.md in hq).
// The app update's status, how this Mac updates, then every channel's recent builds (docs/release-rings.md in hq).
private static let updates = CategorySpec(
id: "updates", title: SettingsText.keyed("settings.category.updates", "Updates"), symbol: "icloud.and.arrow.down",
groups: [
Expand All @@ -193,7 +196,7 @@ public nonisolated struct SettingsPageLayout: Sendable {
title: SettingsText.keyed("settings.pageGroup.updatesAdvanced", "Updates: Advanced")),
],
// After the groups: the Web UI card (the web half of Updates; NIGHTLY only), then the channels.
trail: [.webUpdates, .channels])
lead: [.appUpdate], trail: [.webUpdates, .channels])

private static let theme = CategorySpec(
id: "theme", title: SettingsText.keyed("settings.category.theme", "Theme"), symbol: "paintpalette",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27510,6 +27510,268 @@
}
}
}
},
"updater.settings.title": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "App Update"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "アプリのアップデート"
}
},
"ar": {
"stringUnit": {
"state": "translated",
"value": "تحديث التطبيق"
}
},
"bs": {
"stringUnit": {
"state": "needs_review",
"value": "Ažuriranje aplikacije"
}
},
"da": {
"stringUnit": {
"state": "needs_review",
"value": "Appopdatering"
}
},
"de": {
"stringUnit": {
"state": "translated",
"value": "App-Update"
}
},
"es": {
"stringUnit": {
"state": "translated",
"value": "Actualización de la app"
}
},
"fr": {
"stringUnit": {
"state": "translated",
"value": "Mise à jour de l’app"
}
},
"it": {
"stringUnit": {
"state": "needs_review",
"value": "Aggiornamento app"
}
},
"km": {
"stringUnit": {
"state": "needs_review",
"value": "ការធ្វើបច្ចុប្បន្នភាពកម្មវិធី"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "앱 업데이트"
}
},
"nb": {
"stringUnit": {
"state": "needs_review",
"value": "Appoppdatering"
}
},
"pl": {
"stringUnit": {
"state": "needs_review",
"value": "Aktualizacja aplikacji"
}
},
"pt-BR": {
"stringUnit": {
"state": "needs_review",
"value": "Atualização do app"
}
},
"ru": {
"stringUnit": {
"state": "needs_review",
"value": "Обновление приложения"
}
},
"th": {
"stringUnit": {
"state": "needs_review",
"value": "อัปเดตแอป"
}
},
"tr": {
"stringUnit": {
"state": "needs_review",
"value": "Uygulama Güncellemesi"
}
},
"uk": {
"stringUnit": {
"state": "needs_review",
"value": "Оновлення застосунку"
}
},
"vi": {
"stringUnit": {
"state": "needs_review",
"value": "Cập nhật ứng dụng"
}
},
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "App 更新"
}
},
"zh-Hant": {
"stringUnit": {
"state": "translated",
"value": "App 更新"
}
}
}
},
"updater.settings.checkNow": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Check Now"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "今すぐ確認"
}
},
"ar": {
"stringUnit": {
"state": "translated",
"value": "تحقق الآن"
}
},
"bs": {
"stringUnit": {
"state": "needs_review",
"value": "Provjeri sada"
}
},
"da": {
"stringUnit": {
"state": "needs_review",
"value": "Søg nu"
}
},
"de": {
"stringUnit": {
"state": "translated",
"value": "Jetzt suchen"
}
},
"es": {
"stringUnit": {
"state": "translated",
"value": "Buscar ahora"
}
},
"fr": {
"stringUnit": {
"state": "translated",
"value": "Rechercher"
}
},
"it": {
"stringUnit": {
"state": "needs_review",
"value": "Controlla ora"
}
},
"km": {
"stringUnit": {
"state": "needs_review",
"value": "ពិនិត្យឥឡូវ"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "지금 확인"
}
},
"nb": {
"stringUnit": {
"state": "needs_review",
"value": "Se etter nå"
}
},
"pl": {
"stringUnit": {
"state": "needs_review",
"value": "Sprawdź teraz"
}
},
"pt-BR": {
"stringUnit": {
"state": "needs_review",
"value": "Verificar agora"
}
},
"ru": {
"stringUnit": {
"state": "needs_review",
"value": "Проверить"
}
},
"th": {
"stringUnit": {
"state": "needs_review",
"value": "ตรวจสอบเลย"
}
},
"tr": {
"stringUnit": {
"state": "needs_review",
"value": "Şimdi Denetle"
}
},
"uk": {
"stringUnit": {
"state": "needs_review",
"value": "Перевірити"
}
},
"vi": {
"stringUnit": {
"state": "needs_review",
"value": "Kiểm tra ngay"
}
},
"zh-Hans": {
"stringUnit": {
"state": "translated",
"value": "立即检查"
}
},
"zh-Hant": {
"stringUnit": {
"state": "translated",
"value": "立即檢查"
}
}
}
}
},
"version": "1.0"
Expand Down
20 changes: 12 additions & 8 deletions Packages/macOS/CmuxNext/Sources/CmuxNextUpdater/UpdateFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,21 @@ nonisolated public struct UpdateFlow: Equatable, Sendable {
userAsked = false
return installIfStaged()
case .downloading, .checking:
// Installs once staged; the progress shows meanwhile.
// Installs once staged; a check shows meanwhile, a download runs quietly.
installRequested = true
userAsked = true
return []
case .available:
// Downloads, shows its progress, installs once staged.
// Downloads quietly, installs once staged.
installRequested = true
userAsked = true
return [.download]
case .hidden, .installing, .note:
return []
}
case .downloadRequested:
// The answer to the update-found step: download, show the progress, then ask again
// before the relaunch (the staged update card). A held install click keeps its install.
// The answer to the update-found step: download quietly, then ask again before the
// relaunch (the staged update card). A held install click keeps its install.
guard case .available = phase else { return [] }
userAsked = true
return [.download]
Expand Down Expand Up @@ -131,8 +131,13 @@ nonisolated public struct UpdateFlow: Equatable, Sendable {
}

/// The notice card's update status, or nil: what the user asked for (a
/// check, its download, its result), and a found update that waits for
/// a click (`updates.downloadAutomatically` off), which needs no check.
/// check, its result), and a found update that waits for a click
/// (`updates.downloadAutomatically` off), which needs no check. A
/// download never shows here, asked for or not: it runs quietly and the
/// staged update's one-step card asks to restart (Leo 2026-11-03, after
/// ChatGPT: "it's already downloaded you click this button to accept the
/// button and restart"). Its progress, Cancel and a failure's Try Again
/// are Settings > Updates' (``UpdaterService/settingsStatus``).
/// A scheduled check, its download and its result show nothing.
/// A staged update is never this card (the staged update card,
/// ``footerPill(preferences:)``); an install shows here only when the
Expand All @@ -149,10 +154,9 @@ nonisolated public struct UpdateFlow: Equatable, Sendable {
guard userAsked else { return nil }
switch phase {
case .checking: return .checking
case .downloading(let transfer): return .downloading(transfer)
case .installing: return .installing
case .note(let note): return .note(note)
case .hidden, .available, .ready: return nil
case .hidden, .available, .downloading, .ready: return nil
}
}

Expand Down
Loading
Loading