LCOV - code coverage report
Current view: top level - dashql-app/src/platform/version - electron_version_check.tsx Coverage Total Hit
Test: DashQL 915828b Lines: 55.7 % 115 64
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : import * as React from 'react';
       2              : 
       3              : import { DASHQL_LATEST_RELEASE_MANIFEST, DASHQL_STABLE_RELEASE_MANIFEST } from '../../globals.js';
       4              : import { RESULT_ERROR, RESULT_OK, Result } from '../../utils/result.js';
       5              : import { useLogger } from '../logger/logger_provider.js';
       6              : import {
       7              :     LATEST_RELEASE_MANIFEST_CTX,
       8              :     LATEST_UPDATE_MANIFEST_CTX,
       9              :     INSTALLATION_STATUS_CTX,
      10              :     InstallableUpdate,
      11              :     InstallationState,
      12              :     InstallationStatusCode,
      13              :     STABLE_RELEASE_MANIFEST_CTX,
      14              :     STABLE_UPDATE_MANIFEST_CTX,
      15              :     VERSION_CHECK_CTX,
      16              :     VERSION_CHECK_REFRESH_CTX,
      17              :     VersionCheckStatusCode,
      18              :     useVersionCheckRefreshState,
      19              : } from './version_check.js';
      20              : import { detectReleaseChannel, loadReleaseManifest, ReleaseChannel, ReleaseManifest } from './web_version_check.js';
      21              : import { DASHQL_VERSION } from '../../globals.js';
      22              : 
      23              : type Props = {children: React.ReactElement};
      24              : 
      25            1 : export const ElectronVersionCheck: React.FC<Props> = ({children}) => {
      26            1 :     const logger = useLogger();
      27            1 :     const bridge = globalThis.dashqlElectron!.updates;
      28            1 :     const activeChannel = detectReleaseChannel(DASHQL_VERSION);
      29            1 :     const [status, setStatus] = React.useState<VersionCheckStatusCode>(VersionCheckStatusCode.Unknown);
      30            1 :     const [installation, setInstallation] = React.useState<InstallationState | null>(null);
      31            1 :     const [stableRelease, setStableRelease] = React.useState<Result<ReleaseManifest> | null>(null);
      32            1 :     const [latestRelease, setLatestRelease] = React.useState<Result<ReleaseManifest> | null>(null);
      33            1 :     const updateRef = React.useRef<Record<ReleaseChannel, InstallableUpdate> | null>(null);
      34              : 
      35            1 :     if (updateRef.current === null) {
      36            1 :         updateRef.current = {
      37            1 :             stable: {download: async () => await bridge.download('stable')},
      38            1 :             latest: {download: async () => await bridge.download('latest')},
      39            1 :         };
      40              :     }
      41            1 :     const updates = updateRef.current;
      42            1 :     const [stableUpdate, setStableUpdate] = React.useState<Result<InstallableUpdate | null> | null>(null);
      43            1 :     const [latestUpdate, setLatestUpdate] = React.useState<Result<InstallableUpdate | null> | null>(null);
      44              : 
      45            1 :     const applyStatus = React.useEffectEvent((next: DashQLElectronUpdateStatus) => {
      46            1 :         switch (next.status) {
      47            0 :             case 'disabled':
      48            0 :                 setStatus(VersionCheckStatusCode.Disabled);
      49            0 :                 if (activeChannel === 'latest') {
      50            0 :                     setLatestUpdate({type: RESULT_OK, value: null});
      51              :                 } else {
      52            0 :                     setStableUpdate({type: RESULT_OK, value: null});
      53              :                 }
      54            0 :                 break;
      55            0 :             case 'checking':
      56            0 :                 setStatus(VersionCheckStatusCode.Unknown);
      57            0 :                 break;
      58            1 :             case 'up-to-date':
      59            1 :                 setStatus(VersionCheckStatusCode.UpToDate);
      60            1 :                 if (next.channel === 'latest') {
      61            0 :                     setLatestUpdate({type: RESULT_OK, value: null});
      62              :                 } else {
      63            1 :                     setStableUpdate({type: RESULT_OK, value: null});
      64              :                 }
      65            1 :                 break;
      66            0 :             case 'available':
      67            0 :                 setStatus(VersionCheckStatusCode.UpdateAvailable);
      68            0 :                 if (next.channel === 'latest') {
      69            0 :                     setLatestUpdate({type: RESULT_OK, value: updates.latest});
      70              :                 } else {
      71            0 :                     setStableUpdate({type: RESULT_OK, value: updates.stable});
      72              :                 }
      73            0 :                 break;
      74            0 :             case 'downloading':
      75            0 :                 setStatus(VersionCheckStatusCode.UpdateInstalling);
      76            0 :                 setInstallation({
      77            0 :                     update: updates[next.channel],
      78            0 :                     statusCode: InstallationStatusCode.InProgress,
      79            0 :                     totalBytes: next.total,
      80            0 :                     loadedBytes: next.transferred,
      81            0 :                     inProgressBytes: 0,
      82            0 :                     error: null,
      83            0 :                 });
      84            0 :                 break;
      85            0 :             case 'downloaded':
      86            0 :                 setStatus(VersionCheckStatusCode.RestartPending);
      87            0 :                 setInstallation({
      88            0 :                     update: updates[next.channel],
      89            0 :                     statusCode: InstallationStatusCode.RestartPending,
      90            0 :                     totalBytes: null,
      91            0 :                     loadedBytes: 0,
      92            0 :                     inProgressBytes: 0,
      93            0 :                     error: null,
      94            0 :                 });
      95            0 :                 break;
      96            0 :             case 'error': {
      97            0 :                 const error = new Error(next.message);
      98            0 :                 setStatus(VersionCheckStatusCode.UpdateFailed);
      99            0 :                 if (next.channel === 'latest') {
     100            0 :                     setLatestUpdate({type: RESULT_ERROR, error});
     101              :                 } else {
     102            0 :                     setStableUpdate({type: RESULT_ERROR, error});
     103              :                 }
     104            0 :                 setInstallation((current) => current === null ? null : {
     105            0 :                     ...current,
     106            0 :                     statusCode: InstallationStatusCode.Failed,
     107            0 :                     error,
     108            0 :                 });
     109            0 :                 break;
     110            0 :             }
     111            1 :         }
     112            1 :     });
     113              : 
     114            1 :     const check = React.useCallback(async () => {
     115            1 :         await Promise.all([
     116            1 :             loadReleaseManifest('stable', DASHQL_STABLE_RELEASE_MANIFEST, logger)
     117            1 :                 .then(value => setStableRelease({type: RESULT_OK, value}))
     118            1 :                 .catch(error => setStableRelease({type: RESULT_ERROR, error})),
     119            1 :             loadReleaseManifest('latest', DASHQL_LATEST_RELEASE_MANIFEST, logger)
     120            1 :                 .then(value => setLatestRelease({type: RESULT_OK, value}))
     121            1 :                 .catch(error => setLatestRelease({type: RESULT_ERROR, error})),
     122            1 :             bridge.check(activeChannel)
     123            1 :                 .then(applyStatus)
     124            1 :                 .catch(error => applyStatus({status: 'error', channel: activeChannel, message: String(error)})),
     125            1 :         ]);
     126            1 :     }, [bridge, logger]);
     127            1 :     const refresh = useVersionCheckRefreshState(check);
     128              : 
     129            1 :     React.useEffect(() => {
     130            1 :         const unsubscribe = bridge.onStatus(applyStatus);
     131            1 :         void bridge.getStatus().then(applyStatus);
     132            1 :         return unsubscribe;
     133            1 :     }, [bridge]);
     134              : 
     135            1 :     const stableInstallableUpdate = stableUpdate ?? (activeChannel === 'latest' ? {type: RESULT_OK, value: updates.stable} as const : null);
     136            1 :     const latestInstallableUpdate = latestUpdate ?? (activeChannel === 'stable' ? {type: RESULT_OK, value: updates.latest} as const : null);
     137            1 :     return (
     138            1 :         <VERSION_CHECK_CTX.Provider value={status}>
     139            1 :             <VERSION_CHECK_REFRESH_CTX.Provider value={refresh}>
     140            1 :                 <INSTALLATION_STATUS_CTX.Provider value={installation}>
     141            1 :                     <STABLE_RELEASE_MANIFEST_CTX.Provider value={stableRelease}>
     142            1 :                         <STABLE_UPDATE_MANIFEST_CTX.Provider value={stableInstallableUpdate}>
     143            1 :                             <LATEST_RELEASE_MANIFEST_CTX.Provider value={latestRelease}>
     144            1 :                                 <LATEST_UPDATE_MANIFEST_CTX.Provider value={latestInstallableUpdate}>
     145            1 :                                     {children}
     146            1 :                                 </LATEST_UPDATE_MANIFEST_CTX.Provider>
     147            1 :                             </LATEST_RELEASE_MANIFEST_CTX.Provider>
     148            1 :                         </STABLE_UPDATE_MANIFEST_CTX.Provider>
     149            1 :                     </STABLE_RELEASE_MANIFEST_CTX.Provider>
     150            1 :                 </INSTALLATION_STATUS_CTX.Provider>
     151            1 :             </VERSION_CHECK_REFRESH_CTX.Provider>
     152            1 :         </VERSION_CHECK_CTX.Provider>
     153              :     );
     154            1 : };
        

Generated by: LCOV version 2.0-1