Skip to content

Integrate app updater with UI#57491

Merged
gzdunek merged 20 commits intomasterfrom
gzdunek/integrate-app-updater-with-ui
Aug 8, 2025
Merged

Integrate app updater with UI#57491
gzdunek merged 20 commits intomasterfrom
gzdunek/integrate-app-updater-with-ui

Conversation

@gzdunek
Copy link
Copy Markdown
Contributor

@gzdunek gzdunek commented Aug 4, 2025

Part 5 of #50948. RFD.

This PR adds a dialog to check for updates and integrates it with the updater service (the widget will be added in the next PR).

This first commit is most important one. It implements updater methods that will be used by the UI. Unfortunately, I found some bugs in electron-updater, so I had to add extra logic to resolve them. I've left comments in AppUpdater.ts to explain what wasn't working and how those issues were addressed. If anything is unclear, please let me know.

While testing, I also realized that the UI in the multi-cluster scenario may be too complex when we show errors/warning about unreachable clusters (although it seemed fine in Storybook to me). I'll address this separately by reducing alerts and making inline errors more prominent.

How to test it (on macOS)

I prepared two dev builds with different versions (19.0.0-dev.connect.updates.1 and 19.0.0-dev.connect.updates.2) to test the updates.

  1. Globally set the base URL env var: launchctl setenv TELEPORT_CDN_BASE_URL https://cdn.cloud.gravitational.io.
  2. Set your cluster client tools version: tctl autoupdate client-tools target 19.0.0-dev.connect.updates.2.
  3. Download 19.0.0-dev.connect.updates.1 build from https://cdn.cloud.gravitational.io/Teleport%20Connect-19.0.0-dev.connect.updates.1.dmg.
  4. Move the app to Applications and start it -> App menu -> Check for updates.

Comment thread web/packages/teleterm/src/ui/AppUpdater/AppUpdaterContext.tsx
@gzdunek gzdunek requested review from ryanclark and removed request for bl-nero August 4, 2025 10:00
@gzdunek gzdunek force-pushed the gzdunek/integrate-app-updater-with-ui branch from 0ef7892 to 5ca1de6 Compare August 4, 2025 10:16
Comment thread web/packages/teleterm/src/ui/ModalsHost/modals/AppUpdates.tsx
Comment thread web/packages/teleterm/src/services/appUpdater/appUpdater.ts Outdated
Comment thread web/packages/teleterm/src/services/appUpdater/appUpdater.ts Outdated
Comment thread web/packages/teleterm/src/services/appUpdater/appUpdater.ts Outdated
Comment thread web/packages/teleterm/src/services/appUpdater/appUpdater.ts Outdated
@ravicious ravicious self-requested a review August 4, 2025 16:28
Comment thread web/packages/teleterm/src/services/appUpdater/appUpdater.ts Outdated
Copy link
Copy Markdown
Member

@ravicious ravicious left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I managed to look through the new commits and the old ones until "Expose new APIs through Electron IPC", I'll try to finish the review by the end of this day.

Comment thread web/packages/teleterm/src/services/appUpdater/appUpdater.ts
Comment thread web/packages/teleterm/src/services/appUpdater/appUpdater.ts
Comment thread web/packages/teleterm/src/services/appUpdater/appUpdater.ts
Comment thread web/packages/teleterm/src/mainProcess/mainProcessClient.ts
Comment thread web/packages/teleterm/src/mainProcess/mainProcessClient.ts Outdated
@ravicious ravicious self-requested a review August 6, 2025 08:51
Copy link
Copy Markdown
Member

@ravicious ravicious left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do some light QA tomorrow as so far I've mostly just read the code.

Comment thread web/packages/teleterm/src/ui/ModalsHost/modals/AppUpdates.tsx
Comment thread web/packages/teleterm/src/services/appUpdater/appUpdater.ts
// after quitting the app.
// We may revisit this behavior in the future. For example, if we introduce
// a UI notification indicating that there's an update to be installed.
await this.checkForUpdates({ noAutoDownload: true });
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way we can create tests for this? It feels quite brittle, as in we don't directly discard any updates here but rather we depend on this.checkForUpdates doing this somewhere underneath when called with noAutoDownload. It'd be at least nice to cover that it in fact does this when noAutoDownload is used.

Is it possible to mock/fake autoUpdater? The logic in this file is already rather complex and we just don't have any tests for it, meaning that even this edge case here would need to be covered by the test plan.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it would a pain to mock autoUpdater, but it wasn't that bad!
I added tests for updates auto download and discarding them when the latest check returns a new update or no update, as this part feels the most brittle.

Comment thread web/packages/teleterm/src/ui/ClusterLogout/useClusterLogout.ts Outdated
@ravicious ravicious self-requested a review August 6, 2025 16:18
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improvement for the future: It'd be nice if after downloading the update there was a button to abort the update.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was considering it, but I was afraid of making auto updates too complex. Also, I don't think I know any app/system that would allow it 😅
Do you see a specific scenario where this would be useful?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My original comment might have been a result of a developer brain. I was testing the feature and it downloaded an update that I didn't really need, but I couldn't skip it once it's been downloaded.

But this got me thinking: the newest version of my editor is currently broken. The updater fortunately offers a "Skip this update" feature (I think it's supported OOTB in one of the popular macOS updaters). What if we release a bugged version of Connect? The cluster admin would probably need to turn off auto-updates, but why would they need to do that if there's a problem only with Connect and not tsh? Or say the bug affects only a specific platform. As the end user, can I skip it somehow? Is setting an env var the only available workaround?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the CLI tools, the official workaround is the env var:

An environment variable TELEPORT_TOOLS_VERSION can be used as an emergency workaround for a known issue, pinning to a specific version in CI/CD, for debugging, or for manual updates.

The same one will be available in Connect. I know it's a bit inconvenient for desktop apps, but I also feel it's acceptable for the updater v1.
I can open an issue to add a UI option in the future that will allow users to skip an update or maybe even revert to a previous version.

Comment thread web/packages/teleterm/src/services/appUpdater/appUpdater.ts
@gzdunek gzdunek requested a review from ravicious August 7, 2025 14:15
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My original comment might have been a result of a developer brain. I was testing the feature and it downloaded an update that I didn't really need, but I couldn't skip it once it's been downloaded.

But this got me thinking: the newest version of my editor is currently broken. The updater fortunately offers a "Skip this update" feature (I think it's supported OOTB in one of the popular macOS updaters). What if we release a bugged version of Connect? The cluster admin would probably need to turn off auto-updates, but why would they need to do that if there's a problem only with Connect and not tsh? Or say the bug affects only a specific platform. As the end user, can I skip it somehow? Is setting an env var the only available workaround?

@gzdunek gzdunek enabled auto-merge August 7, 2025 16:21
@gzdunek gzdunek added this pull request to the merge queue Aug 8, 2025
Merged via the queue into master with commit 13aa750 Aug 8, 2025
44 of 45 checks passed
@gzdunek gzdunek deleted the gzdunek/integrate-app-updater-with-ui branch August 8, 2025 08:11
@backport-bot-workflows
Copy link
Copy Markdown
Contributor

@gzdunek See the table below for backport results.

Branch Result
branch/v16 Failed
branch/v17 Failed
branch/v18 Failed

gzdunek added a commit that referenced this pull request Aug 22, 2025
* Implement `checkForUpdates`, `download`, `cancelDownload`, `changeManagingCluster` and `quitAndInstall`

* Expose new APIs through Electron IPC

* Add app updater context to store updater state

* Add `AppUpdates` dialog

* Switch "Download" button to "Starting Download..." immediately after clicking it

* Clear managing cluster on logout

* Return correct error in `GetClusterVersions`

* Do not prepend `https://` to file URL, DefaultBaseURL already contains it, trim the checksum value before validating it

* Only try to download an update if it's available

* Remove separate `will-quit` handler

* Clarify comment

* Invert condition in `preventInstallingOutdatedUpdates`

* Add comments

* Move `closeAllConnections()` out of try catch

* Add specialized functions to serialize/deserialize errors

* Add tests

* Leave TODO

* Do not wait for `maybeRemoveAppUpdatesManagingCluster` in `useClusterLogout`

* Hide app updater for .tar.gz which is not supported

* Add missing mock

(cherry picked from commit 13aa750)
gzdunek added a commit that referenced this pull request Aug 22, 2025
* Implement `checkForUpdates`, `download`, `cancelDownload`, `changeManagingCluster` and `quitAndInstall`

* Expose new APIs through Electron IPC

* Add app updater context to store updater state

* Add `AppUpdates` dialog

* Switch "Download" button to "Starting Download..." immediately after clicking it

* Clear managing cluster on logout

* Return correct error in `GetClusterVersions`

* Do not prepend `https://` to file URL, DefaultBaseURL already contains it, trim the checksum value before validating it

* Only try to download an update if it's available

* Remove separate `will-quit` handler

* Clarify comment

* Invert condition in `preventInstallingOutdatedUpdates`

* Add comments

* Move `closeAllConnections()` out of try catch

* Add specialized functions to serialize/deserialize errors

* Add tests

* Leave TODO

* Do not wait for `maybeRemoveAppUpdatesManagingCluster` in `useClusterLogout`

* Hide app updater for .tar.gz which is not supported

* Add missing mock

(cherry picked from commit 13aa750)
github-merge-queue bot pushed a commit that referenced this pull request Sep 2, 2025
* Integrate app updater with UI (#57491)

* Implement `checkForUpdates`, `download`, `cancelDownload`, `changeManagingCluster` and `quitAndInstall`

* Expose new APIs through Electron IPC

* Add app updater context to store updater state

* Add `AppUpdates` dialog

* Switch "Download" button to "Starting Download..." immediately after clicking it

* Clear managing cluster on logout

* Return correct error in `GetClusterVersions`

* Do not prepend `https://` to file URL, DefaultBaseURL already contains it, trim the checksum value before validating it

* Only try to download an update if it's available

* Remove separate `will-quit` handler

* Clarify comment

* Invert condition in `preventInstallingOutdatedUpdates`

* Add comments

* Move `closeAllConnections()` out of try catch

* Add specialized functions to serialize/deserialize errors

* Add tests

* Leave TODO

* Do not wait for `maybeRemoveAppUpdatesManagingCluster` in `useClusterLogout`

* Hide app updater for .tar.gz which is not supported

* Add missing mock

(cherry picked from commit 13aa750)

* Show update widget in login dialog (#57695)

* Add app updates widget to login dialog

* Adjust compatibility warning to app updates

* Simplify widget error state, do not show full error message

* Make the widget take up 100% width both in login modal an in story

* Fix LocalWithPasswordless story

* Use `alignItems="stretch"`

* Use `SpaceProps` instead of redefining `mx` manually

* Infer type

* Display buttons in the bottom of Alert

* Avoid moving content when scrollbar appears

* Destructure `Promise.all` result

* Add comment

---------

Co-authored-by: Rafał Cieślak <rafal.cieslak@goteleport.com>
(cherry picked from commit c59a4e6)

* Simplify auto updates multi-cluster view (#57709)

* Simplify auto updates multi-cluster view

* Improve labels

* Fix tests

(cherry picked from commit b574045)

* Connect: Force focus after a successful SSO login

* Move login functions from ClustersService to useClusterLogin

* Remove no longer used GetResourcesParams

* Remove clusters/types.ts

* Force focus on Connect after successful SSO login

* Update SSO prompt after login but before sync

* Add test for SSO prompts

* Use `Promise.withResolvers`

Co-authored-by: Grzegorz Zdunek <gzdunek@users.noreply.github.com>

* Update wait-for-sync prompt message

---------

Co-authored-by: Grzegorz Zdunek <gzdunek@users.noreply.github.com>

* Hardcode the lowest supported Connect versions that support managed updates (#58348)

* Provide the lowest supported app versions for managed updates

* Deserialize errors in the UI code, not in preload

Otherwise, the error name is lost.

* Bump version in tests

* Lint

* Show exact version in error message

* Do not hide UnsupportedVersionError

* Fix margin

* Make alert take 100% width

(cherry picked from commit d7e1352)

---------

Co-authored-by: Rafał Cieślak <rafal.cieslak@goteleport.com>
github-merge-queue bot pushed a commit that referenced this pull request Sep 2, 2025
* Integrate app updater with UI (#57491)

* Implement `checkForUpdates`, `download`, `cancelDownload`, `changeManagingCluster` and `quitAndInstall`

* Expose new APIs through Electron IPC

* Add app updater context to store updater state

* Add `AppUpdates` dialog

* Switch "Download" button to "Starting Download..." immediately after clicking it

* Clear managing cluster on logout

* Return correct error in `GetClusterVersions`

* Do not prepend `https://` to file URL, DefaultBaseURL already contains it, trim the checksum value before validating it

* Only try to download an update if it's available

* Remove separate `will-quit` handler

* Clarify comment

* Invert condition in `preventInstallingOutdatedUpdates`

* Add comments

* Move `closeAllConnections()` out of try catch

* Add specialized functions to serialize/deserialize errors

* Add tests

* Leave TODO

* Do not wait for `maybeRemoveAppUpdatesManagingCluster` in `useClusterLogout`

* Hide app updater for .tar.gz which is not supported

* Add missing mock

(cherry picked from commit 13aa750)

* Show update widget in login dialog (#57695)

* Add app updates widget to login dialog

* Adjust compatibility warning to app updates

* Simplify widget error state, do not show full error message

* Make the widget take up 100% width both in login modal an in story

* Fix LocalWithPasswordless story

* Use `alignItems="stretch"`

* Use `SpaceProps` instead of redefining `mx` manually

* Infer type

* Display buttons in the bottom of Alert

* Avoid moving content when scrollbar appears

* Destructure `Promise.all` result

* Add comment

---------

Co-authored-by: Rafał Cieślak <rafal.cieslak@goteleport.com>
(cherry picked from commit c59a4e6)

* Simplify auto updates multi-cluster view (#57709)

* Simplify auto updates multi-cluster view

* Improve labels

* Fix tests

(cherry picked from commit b574045)

* Connect: Force focus after a successful SSO login

* Move login functions from ClustersService to useClusterLogin

* Remove no longer used GetResourcesParams

* Remove clusters/types.ts

* Force focus on Connect after successful SSO login

* Update SSO prompt after login but before sync

* Add test for SSO prompts

* Use `Promise.withResolvers`

Co-authored-by: Grzegorz Zdunek <gzdunek@users.noreply.github.com>

* Update wait-for-sync prompt message

---------

Co-authored-by: Grzegorz Zdunek <gzdunek@users.noreply.github.com>

* Hardcode the lowest supported Connect versions that support managed updates (#58348)

* Provide the lowest supported app versions for managed updates

* Deserialize errors in the UI code, not in preload

Otherwise, the error name is lost.

* Bump version in tests

* Lint

* Show exact version in error message

* Do not hide UnsupportedVersionError

* Fix margin

* Make alert take 100% width

(cherry picked from commit d7e1352)

---------

Co-authored-by: Rafał Cieślak <rafal.cieslak@goteleport.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport/branch/v17 backport/branch/v18 no-changelog Indicates that a PR does not require a changelog entry size/md ui

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants