|  | 
| 6 | 6 |  * Copyright Oxide Computer Company | 
| 7 | 7 |  */ | 
| 8 | 8 | 
 | 
|  | 9 | +import { differenceInMinutes } from 'date-fns' | 
| 9 | 10 | import { useMemo } from 'react' | 
| 10 | 11 | import * as R from 'remeda' | 
|  | 12 | +import { lt as semverLt } from 'semver' | 
| 11 | 13 | 
 | 
| 12 | 14 | import { | 
| 13 | 15 |   Images24Icon, | 
| @@ -46,7 +48,29 @@ import { percentage, round } from '~/util/math' | 
| 46 | 48 | 
 | 
| 47 | 49 | export const handle = makeCrumb('System Update') | 
| 48 | 50 | 
 | 
| 49 |  | -const statusQuery = apiq('systemUpdateStatus', {}) | 
|  | 51 | +const SEC = 1000 // ms, obviously | 
|  | 52 | +const POLL_FAST = 20 * SEC | 
|  | 53 | +const POLL_SLOW = 120 * SEC | 
|  | 54 | + | 
|  | 55 | +const statusQuery = apiq( | 
|  | 56 | +  'systemUpdateStatus', | 
|  | 57 | +  {}, | 
|  | 58 | +  { | 
|  | 59 | +    refetchInterval({ state: { data: status } }) { | 
|  | 60 | +      if (!status) return false // should be impossible due to prefetch | 
|  | 61 | + | 
|  | 62 | +      const now = new Date() | 
|  | 63 | +      const minSinceTargetSet = status.targetRelease | 
|  | 64 | +        ? differenceInMinutes(now, status.targetRelease.timeRequested) | 
|  | 65 | +        : null | 
|  | 66 | +      const minSinceLastStepPlanned = differenceInMinutes(now, status.timeLastStepPlanned) | 
|  | 67 | +      return minSinceLastStepPlanned < 30 || | 
|  | 68 | +        (minSinceTargetSet !== null && minSinceTargetSet < 30) | 
|  | 69 | +        ? POLL_FAST | 
|  | 70 | +        : POLL_SLOW | 
|  | 71 | +    }, | 
|  | 72 | +  } | 
|  | 73 | +) | 
| 50 | 74 | const reposQuery = apiq('systemUpdateRepositoryList', { query: { limit: ALL_ISH } }) | 
| 51 | 75 | 
 | 
| 52 | 76 | const refreshData = () => | 
| @@ -175,7 +199,17 @@ export default function UpdatePage() { | 
| 175 | 199 |         <CardBlock.Body> | 
| 176 | 200 |           <ul className="space-y-3"> | 
| 177 | 201 |             {repos.items.map((repo) => { | 
| 178 |  | -              const isTarget = repo.systemVersion === status.targetRelease?.version | 
|  | 202 | +              const targetVersion = status.targetRelease?.version | 
|  | 203 | +              const isTarget = repo.systemVersion === targetVersion | 
|  | 204 | +              // semverLt looks at prerelease meta but not build meta. In prod | 
|  | 205 | +              // it doesn't matter either way because there will be neither. On | 
|  | 206 | +              // dogfood it shouldn't matter because the versions will usually | 
|  | 207 | +              // be the same and with the same prelease meta and only differing | 
|  | 208 | +              // build meta, so semverLt will return false and we don't disable | 
|  | 209 | +              // any. Very important this is | 
|  | 210 | +              const olderThanTarget = targetVersion | 
|  | 211 | +                ? semverLt(repo.systemVersion, targetVersion) | 
|  | 212 | +                : false | 
| 179 | 213 |               return ( | 
| 180 | 214 |                 <li | 
| 181 | 215 |                   key={repo.hash} | 
| @@ -226,10 +260,13 @@ export default function UpdatePage() { | 
| 226 | 260 |                             errorTitle: `Error setting target release to ${repo.systemVersion}`, | 
| 227 | 261 |                           }) | 
| 228 | 262 |                         }} | 
| 229 |  | -                        // TODO: follow API logic, disabling for older releases. | 
| 230 |  | -                        // Or maybe just have the API tell us by adding a field to | 
| 231 |  | -                        // the TufRepo response type. | 
| 232 |  | -                        disabled={isTarget && 'Already set as target'} | 
|  | 263 | +                        disabled={ | 
|  | 264 | +                          isTarget | 
|  | 265 | +                            ? 'Already set as target' | 
|  | 266 | +                            : olderThanTarget | 
|  | 267 | +                              ? 'Cannot set older release as target' | 
|  | 268 | +                              : false | 
|  | 269 | +                        } | 
| 233 | 270 |                       /> | 
| 234 | 271 |                     </MoreActionsMenu> | 
| 235 | 272 |                   </div> | 
|  | 
0 commit comments