Skip to content

feat(updates): show pending updates in the title bar and relaunch to install - #3993

Merged
datlechin merged 6 commits into
mainfrom
feat/update-indicator
Nov 2, 2026
Merged

datlechin merged 6 commits into
mainfrom
feat/update-indicator

Conversation

@datlechin

Copy link
Copy Markdown
Member

Summary

  • Connection windows show a button at the trailing end of the title bar while an update is pending. It is a stock NSButton in a trailing NSTitlebarAccessoryViewController, with the glass capsule bezel on macOS 26 and the toolbar bezel before that. It is added only while something is pending, because a hidden accessory keeps its width.
  • Update Available opens Sparkle's own update window.
  • Relaunch to Update opens a popover with the version, release notes, the plugins that also update, and Later / Relaunch Now. It shows for an update Sparkle downloaded on its own, and for staged plugin updates.
  • With the shipped default (download and install automatically), a found update now reaches the user: updater(_:willInstallUpdateOnQuit:immediateInstallationBlock:) keeps Sparkle's install handler. Before, nothing showed until the next quit.
  • One model, UpdateCenter over a pure UpdateStatus, drives the app menu item, Welcome, Settings, the Sync notice and the Plugins pane, so their titles and actions agree.
  • Gentle reminders use Sparkle's documented hooks. ShouldHandleShowingScheduledUpdate no longer records state; WillHandleShowingUpdate does.
  • Relaunch goes through one path, AppRelauncher:
    • It reviews unsaved documents first.
    • It hands off to Sparkle when an update is waiting.
    • Otherwise it quits normally and reopens only after the process exits.
    • The last session reopens once after a relaunch, whatever When TablePro starts says.
  • Settings > General > Software Update:
    • A status row with its version, last check and one action (Check Now, Install Update…, Relaunch).
    • An Update channel picker (Stable, Beta) replaces the Get beta updates switch.
  • Welcome always shows the version and shows an update link only while one is pending. The Show version and updates on the Welcome window setting is removed. Older saved settings still decode and drop the key.
  • Plugins pane:
    • Quit & Reopen becomes Relaunch on the shared path.
    • Staged rows read "Updates when TablePro relaunches".
    • The "needs a newer TablePro" button and the Sync notice use an app-only action, so staged plugins alone never turn them into a plain relaunch.
  • No notification and no Dock badge, per Sparkle's gentle-reminders guidance for Dock apps and the HIG on badges.
Defect on main Fixed by
Default users never see a found update; it installs silently at the next quit willInstallUpdateOnQuit handler, Relaunch to Update
Reminder state is set in a Sparkle hook documented as side-effect free Recorded in standardUserDriverWillHandleShowingUpdate
Sync and Plugins buttons always read Check for Updates… or Update TablePro, whatever the state Titles from UpdateStatus
Quit & Reopen starts a second instance before the quit is approved. Cancelling leaves two running, and a pending Sparkle install replaces the bundle under the new one AppRelauncher reopens after exit, or through Sparkle
Staged plugin updates can only be relaunched from Settings > Plugins Title bar indicator, menu item, Settings row

WelcomeWindowUITests.testTheVersionSettingHidesTheVersionAndTheUpdateCheckOnTheOpenWindow pinned the removed setting. It is replaced by testTheVersionShowsAndAnUpdateLinkWaitsForAPendingUpdate. SparkleUpdatePreferencesTests.deferredUpdateRenamesTheControl moved into UpdateStatusTests.

Test plan

  • New suites: AppUpdatePhaseTests, UpdateStatusTests, UpdateCenterTests, UpdateIndicatorAccessoryTests, AppRelauncherTests.
  • verify.sh test on those plus the window chrome, menu, toolbar, launch and settings suites: 233 passed, 0 failed. After the review fixes, the update suites: 33 passed.
  • verify.sh uitest WelcomeWindowUITests/testTheVersionShowsAndAnUpdateLinkWaitsForAPendingUpdate: passed.
  • Codex adversarial review found three defects, all fixed here: a dead install handler after a Sparkle abort, a document-review cancel leaving a relaunch armed, and app-upgrade notices relaunching for staged plugins only. The second round found nothing.
  • Probe on macOS 27:
    • AppKit sizes a trailing accessory to the toolbar row.
    • Toolbar items overflow into the chevron before the accessory is clipped.
    • isHidden keeps the accessory's width; add and remove reflow the toolbar.
    • The glass capsule at .large matches the toolbar's capsules.
  • Not verified:
    • Sparkle's real download, install and relaunch: Debug builds disable updating.
    • Layout on macOS 13 to 15: no such OS on this machine.

Screenshots

The after shots of the indicator, the popover, Welcome and the Settings row seed a ready update (0.85.0, two staged plugins) through a temporary patch that is not in this PR.

Light Dark
Connection window, after Connection window with Relaunch to Update in the title bar Connection window with Relaunch to Update in the title bar, dark
Relaunch popover, after Popover listing the version, release notes, plugins, Later and Relaunch Now Popover, dark
Welcome, before Welcome with Check for Updates link Welcome with Check for Updates link, dark
Welcome, after Welcome with Relaunch to Update link Welcome with Relaunch to Update link, dark
Settings, before Software Update section with three switches Software Update section, dark
Settings, after Software Update section with status row and channel picker Software Update section with status row, dark

@datlechin
datlechin disabled auto-merge November 2, 2026 18:26
@datlechin
datlechin merged commit 8402100 into main Nov 2, 2026
2 checks passed
@datlechin
datlechin deleted the feat/update-indicator branch November 2, 2026 18:26
datlechin added a commit that referenced this pull request Nov 3, 2026
Brings main's 27 commits, among them one license and sync presentation
(#4005), the Black Friday line (#3995), the update indicator and relaunch
(#3993, #3997), running work (#4009), native notices (#4007) and the
security merges for GHSA-3x6q-h487-r38w, GHSA-3xf7-86qj-4546,
GHSA-6g2g-65r6-v5wh, GHSA-q2hp-vxv3-87fw, GHSA-6p9q-hc7v-cxmx and
GHSA-vg8g-h6xp-6px5.

- #4005: ported onto FeatureAccess. LicensePresentation.gate reads
  AccountState: signed out names a paid plan and offers Sign In beside
  Purchase License, an account without the feature gets Upgrade Plan, the
  device limit opens Settings > Account, and a lapsed or failed check reads
  as Settings > Account words it, with Try Again, so a paying customer is
  never sent to the pricing page. The pane's notice text moved to
  AccountSettingsContent.Notice so both read it. LicenseGateRow replaces
  ProBadge in the Sync, Linked Folders, Data Rewind and connection export
  rows, LicenseGateAlert serves Compare & Sync and Data Rewind, and the
  overlay renders the same notice. Try Again shows a spinner and the
  failed check's reason; Refresh in Settings > Account shows the reason
  too. Welcome shows the pane's first notice as a link (a plan being
  canceled stays in the pane), else Sign In. Dropped: the .suspended
  access, since an entitlement carries no suspended state, and
  LicenseManager's coalesced checks and stale-answer guard, since
  AccountServices already runs one check at a time and drops a refresh
  that lands after sign-out.
- #3995: the Black Friday line shows when FeatureAccess.supportAudience is
  .prospect, the notion the day-30 ask reads.
- #3989: ported before this merge, in e39c309.
- #3993, #3997: merged as main has them; Welcome and the Sync pane keep
  UpdateCenter.
- #4007: a Team Library publish that goes through shows no info alert on
  Welcome or in Favorites; the section shows the items. The queued and
  failed messages stay.
- #4009: merged outside the Team Library. TeamLibraryStore's write
  generation, the shared in-flight pull, the refused second publish and
  the Team Library row in Settings > License are dropped: TeamLibrarySync
  runs syncs and publishes one at a time, bumps a generation on sign-out,
  and the Welcome and Favorites headers show the running sync, the last
  sync and a failure.
- 726a167 (security): LicenseAPIClient and LiveTeamLibraryAPIClient
  follow redirects only on their own origin. Ported by giving the account
  URLSession SameOriginRedirects as its delegate, which covers token
  requests, /v2 calls and the team library. The pulled library keeps a
  connection's sign-in choice for the consent prompt: ported to
  TeamLibraryChange.connection, and its test moved to TeamLibrarySyncTests.
  Publishing needs nothing, since portableSettings keeps the choice by
  default. EnvVarReferenceConsent reads FeatureAccess.
- DatabaseManager+Sessions: main's recovery guard and consent path, with
  Telemetry.connectionAttempted in place of MacAnalyticsProvider.
- project.yml: PostHog stays and zstd goes, as main moved Kafka's codecs
  into TableProCore; the app links main's new products, without
  TableProAnalytics.
- The storage rule, data-sync-storage.md: the paths main listed for the
  deleted TeamLibraryModels, TeamLibraryStore and MacAnalyticsProvider name
  TeamLibraryItem, TeamLibraryState and Telemetry, plus Account's stores.
- Localizable.xcstrings: merged key by key in this branch's order; no key
  changed on both sides. 271 keys come from main; the three SSH host keys
  main removed are gone, as nothing uses them.
- Tests deleted with the code this branch deleted: LicenseManagerDecisionTests,
  LicensePresentationTests and LicenseTierTests under Models,
  TeamLibraryModelsTests, TeamLibrarySyncCoordinatorTests, and the Macs
  link case in SupportLinksTests. New: LicensePresentationTests under
  Views/Settings, the sign-in choice case in TeamLibrarySyncTests and the
  redirect case in AccountConfigurationTests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant