Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(app, app-shell): add download progress to robot update flows #13915

Merged
merged 3 commits into from
Nov 8, 2023

Conversation

mjhuff
Copy link
Contributor

@mjhuff mjhuff commented Nov 3, 2023

Closes RAUT-789, RAUT-827

Overview

If the robot update cache files are still downloading, no longer is an error thrown. Instead, the update modal renders and a downloading stage of the update flow begins. Additionally, release files are downloaded and returned to the browser layer separately from system files, so users may see release notes as soon as they are downloaded.

What's Changed

The substantive changes are in app-shell/src/robot-update/index & release-files and app/src/redux/robot-update/epic & reducer. I've left comments to help explain what's happening.

Before

before.mov

After

after.mov

Test Plan

  • Build the app with make -C app-shell package. Failing the signing step is expected (and fine for testing purposes).
  • Before opening the app, clear out the robot-update-cache files (located in Users/username/.Library/Application Support/opentrons/robot-update-cache).
  • Perform the next step quickly if you have a good downlink. If you want to throttle your bandwidth, you can use the Network Link Conditioner offered by Mac.
  • Follow the video flow, testing on a Flex. You may need to downgrade a robot first via zip-file (via USB if you're feeling bold).
  • Repeat testing flow on an OT-2 (although there should be no functional difference).

Changelog

  • Initiating a robot update while the files are still downloading no longer throws an error.

Review requests

  • Let me know if you need help testing!

Risk assessment

Medium - Getting the logic right is important, but it's relatively (keyword) straightforward as far as update flows are concerned...

If the robot update cache files are still downloading, no longer is an error thrown. Instead, the
update modal renders and a downloading stage of the update flow begins. Additionally, release files
are downloaded and returned to the browser layer separately from system files, so users may see
release notes as soon as they are downloaded.
@mjhuff mjhuff requested review from sfoster1, shlokamin and a team November 3, 2023 19:57
Copy link

codecov bot commented Nov 3, 2023

Codecov Report

Merging #13915 (ccc3c07) into edge (f2d6005) will increase coverage by 0.00%.
Report is 2 commits behind head on edge.
The diff coverage is 46.42%.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             edge   #13915   +/-   ##
=======================================
  Coverage   70.66%   70.67%           
=======================================
  Files        2508     2508           
  Lines       70738    70835   +97     
  Branches     8688     8736   +48     
=======================================
+ Hits        49985    50060   +75     
- Misses      18634    18641    +7     
- Partials     2119     2134   +15     
Flag Coverage Δ
app 68.12% <46.42%> (+0.03%) ⬆️
components 63.21% <ø> (ø)
labware-library 49.17% <ø> (ø)
protocol-designer 45.63% <ø> (ø)
step-generation 84.95% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files Coverage Δ
app/src/redux/robot-update/constants.ts 100.00% <100.00%> (ø)
app/src/redux/robot-update/epic.ts 72.38% <100.00%> (+1.07%) ⬆️
app/src/redux/robot-update/hooks.ts 100.00% <ø> (ø)
app/src/redux/robot-update/reducer.ts 61.90% <85.71%> (+4.76%) ⬆️
...obotSettings/UpdateBuildroot/useRobotUpdateInfo.ts 81.81% <71.42%> (+1.04%) ⬆️
app-shell/src/robot-update/index.ts 0.00% <0.00%> (ø)
...tings/UpdateBuildroot/RobotUpdateProgressModal.tsx 69.23% <55.55%> (-1.66%) ⬇️
app-shell/src/http.ts 16.98% <0.00%> (-1.02%) ⬇️
app-shell/src/robot-update/release-files.ts 15.68% <0.00%> (-0.65%) ⬇️

... and 4 files with indirect coverage changes

Comment on lines +148 to +153
if (checkingForUpdates) {
dispatch({
type: 'robotUpdate:CHECKING_FOR_UPDATE',
payload: target,
})
} else {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This condition is hit if a user actively starts a robot update, but the file has not yet been downloaded. The CHECKING_FOR_UPDATE action creates an update session for the robot with a downloadFile stage. The UI layer uses this session to alert the user that the file is downloading.

Comment on lines +54 to +64
return Promise.all([
downloadAndNotify(true, urls.releaseNotes, directory, dispatch, target),
downloadAndNotify(
false,
urls.system,
directory,
dispatch,
target,
onProgress
),
]).then(([releaseNotes, system]) => ({ releaseNotes, system }))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If a user clicks an the robot update banner while the file is still downloading, there will not be release notes (as seen in the before vide). Let's separate the release notes from the system file download.

If a user somehow navigates to the robot update banner before 20kb have been downloaded, they won't see the notes, but this won't prevent the download.

}
// This action will only have an effect if the user is actively waiting for the download to complete.
else {
return dispatch({
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This dispatch occurs after the system files are downloaded but not yet cleaned up. The redux store will update the robot's session from "waiting on download to finish" to done if the robot is of the same version as the file that finished downloading.

All the file cleanup can happen asynchronously without any problem.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All the changes here are a refactor. I'll revisit this again in the future as it's still obtuse.

The guarded transitions can be safely removed now, since the app-shell guards the transitions safely.

@@ -144,6 +145,19 @@ export const startUpdateEpic: Epic = (action$, state$) =>
})
)

export const startUpdateAfterFileDownload: Epic = (_, state$) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

After the robot update file download completes, this pipe sends us back to the app-shell to kick off the installation process.

This time on READ_SYSTEM_FILE in app-shell, the filename will not be null. Note that the process isn't recursive (checkingForUpdates can never occur more than 1x unless the app is hard restarted. If the file doesn't exist the second time we get here, we'll throw the UNEXPECTED_ERROR.


const { target, ...session } = state.session
const isThisRobotDownloadDone =
session?.step === Constants.DOWNLOAD_FILE && target === action.payload
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This check prevents us initiating an update session when the user isn't actively engaged in the robot update flows, and it makes sure the correct system file update has completed (ex, the OT-2 file completing download won't trigger a Flex waiting for download to register as "done").

@mjhuff mjhuff marked this pull request as ready for review November 3, 2023 20:22
@mjhuff mjhuff requested a review from a team as a code owner November 3, 2023 20:22
Copy link
Member

@sfoster1 sfoster1 left a comment

Choose a reason for hiding this comment

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

Looks good to me, some small nits


function handleSuccess(): void {
resolve(readStream)
readStream.removeListener('error', handleError)
Copy link
Member

Choose a reason for hiding this comment

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

this technically has the same pitfall that #13923 fixes on the odd side (errors from the read stream will be lost) but here I think those errors would only happen if the user deleted the cached file while the update was running

@@ -105,7 +98,9 @@ export function RobotUpdateProgressModal({
progressPercent
)

let modalBodyText = t('installing_update')
let modalBodyText = ''
Copy link
Member

Choose a reason for hiding this comment

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

unless we can prove exhaustion in the if cases after this I think we should give this a meaningful default value

let modalBodyText = t('downloading_update')
if (updateStep === 'install') modalBodyText = t('downloading_update')

or even const it and do a chained ternay assign, or have a function that takes the step and returns the text

@mjhuff mjhuff merged commit 8a565c0 into edge Nov 8, 2023
34 of 35 checks passed
@mjhuff mjhuff deleted the app_download-progress-robot-updates branch November 8, 2023 12:46
ncdiehl11 pushed a commit that referenced this pull request Nov 14, 2023
…3915)

* feat(app): add download progress to robot update flows

If the robot update cache files are still downloading, no longer is an error thrown. Instead, the
update modal renders and a downloading stage of the update flow begins. Additionally, release files
are downloaded and returned to the browser layer separately from system files, so users may see
release notes as soon as they are downloaded.
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.

2 participants