Skip to content

Commit

Permalink
feat: app updater improvements @avivm (#667)
Browse files Browse the repository at this point in the history
* feat: app updater improvements

* docs(changeset): Improved app updater mechanism
  • Loading branch information
avivm authored Jul 5, 2023
1 parent 58f90d9 commit 41bf060
Showing 14 changed files with 221 additions and 167 deletions.
5 changes: 5 additions & 0 deletions .changeset/orange-planets-hope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@krud-dev/ostara-main": minor
---

Improved app updater mechanism
16 changes: 5 additions & 11 deletions app/src/infra/autoupdate/appUpdater.ts
Original file line number Diff line number Diff line change
@@ -8,11 +8,11 @@ import { scheduleJob } from 'node-schedule';
import semverGt from 'semver/functions/gt';

export class AppUpdater {
constructor(autoUpdate = false) {
constructor() {
if (process.env.NODE_ENV === 'development') {
autoUpdater.updateConfigPath = path.join(__dirname, 'app-dev-update.yml');
}
this.updateAutoUpdate(autoUpdate);
this.updateAutoUpdate(false);
log.transports.file.level = 'info';

autoUpdater.logger = log;
@@ -70,8 +70,8 @@ export class AppUpdater {
return undefined;
}

downloadUpdate() {
autoUpdater.downloadUpdate();
async downloadUpdate(): Promise<void> {
await autoUpdater.downloadUpdate();
}

quitAndInstall() {
@@ -120,10 +120,4 @@ export function initializeAppUpdaterSubscriptions(window: BrowserWindow) {
});
}

configurationStore.onDidChange('autoUpdateEnabled', (newValue) => {
if (newValue !== undefined) {
appUpdater.updateAutoUpdate(newValue);
}
});

export const appUpdater = new AppUpdater(configurationStore.get('autoUpdateEnabled'));
export const appUpdater = new AppUpdater();
2 changes: 1 addition & 1 deletion app/src/infra/autoupdate/main.ts
Original file line number Diff line number Diff line change
@@ -2,5 +2,5 @@ import { ipcMain } from 'electron';
import { appUpdater } from './appUpdater';

ipcMain.handle('appUpdater:checkForUpdates', () => appUpdater.checkForUpdates());
ipcMain.on('appUpdater:downloadUpdate', () => appUpdater.downloadUpdate());
ipcMain.handle('appUpdater:downloadUpdate', () => appUpdater.downloadUpdate());
ipcMain.on('appUpdater:quitAndInstall', () => appUpdater.quitAndInstall());
2 changes: 1 addition & 1 deletion app/src/infra/autoupdate/renderer.ts
Original file line number Diff line number Diff line change
@@ -2,6 +2,6 @@ import { ipcRenderer } from 'electron';

export const appUpdaterBridge: AppUpdaterBridge = {
checkForUpdates: () => ipcRenderer.invoke('appUpdater:checkForUpdates'),
downloadUpdate: () => ipcRenderer.send('appUpdater:downloadUpdate'),
downloadUpdate: () => ipcRenderer.invoke('appUpdater:downloadUpdate'),
quitAndInstall: () => ipcRenderer.send('appUpdater:quitAndInstall'),
};
2 changes: 1 addition & 1 deletion app/src/infra/autoupdate/types.d.ts
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ import { UpdateInfo } from 'electron-updater';
declare global {
type AppUpdaterBridge = {
checkForUpdates(): Promise<UpdateInfo | undefined>;
downloadUpdate(): void;
downloadUpdate(): Promise<void>;
quitAndInstall(): void;
};

6 changes: 0 additions & 6 deletions app/src/infra/store/renderer.ts
Original file line number Diff line number Diff line change
@@ -26,10 +26,4 @@ export const configurationStoreBridge: ConfigurationBridge<keyof Configuration>
setErrorReportingEnabled(enabled: boolean): void {
ipcRenderer.send('configurationStore:set', 'errorReportingEnabled', enabled);
},
isAutoUpdateEnabled(): boolean {
return ipcRenderer.sendSync('configurationStore:get', 'autoUpdateEnabled');
},
setAutoUpdateEnabled(enabled: boolean): void {
ipcRenderer.send('configurationStore:set', 'autoUpdateEnabled', enabled);
},
};
4 changes: 0 additions & 4 deletions app/src/infra/store/store.ts
Original file line number Diff line number Diff line change
@@ -5,10 +5,6 @@ export const defaults = {
* Whether Sentry error reporting is enabled or not.
*/
errorReportingEnabled: true,
/**
* Whether auto-updates are enabled or not.
*/
autoUpdateEnabled: true,

lastUpdateCheckTime: 0,
};
4 changes: 0 additions & 4 deletions app/src/infra/store/types.d.ts
Original file line number Diff line number Diff line change
@@ -10,10 +10,6 @@ declare global {
clear(): void;
isErrorReportingEnabled(): boolean;
setErrorReportingEnabled(enabled: boolean): void;

isAutoUpdateEnabled(): boolean;

setAutoUpdateEnabled(enabled: boolean): void;
};

interface Window {
2 changes: 1 addition & 1 deletion app/src/renderer/apis/requests/crud/entity/entity.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type CrudEntityType = 'CrudFramework' | 'LocalStorage';
export type CrudEntityType = 'CrudFramework' | 'Stub';

export type CrudEntityBase = {
id: string;
86 changes: 38 additions & 48 deletions app/src/renderer/components/managers/AppUpdatesManager.tsx
Original file line number Diff line number Diff line change
@@ -11,12 +11,11 @@ import { notEmpty } from '../../utils/objectUtils';
import { useLocalStorageState } from '../../hooks/useLocalStorageState';
import { useAppUpdatesContext } from '../../contexts/AppUpdatesContext';
import { useSnackbar } from 'notistack';
import semverGte from 'semver/functions/gte';

interface AppUpdatesManagerProps {}

const AppUpdatesManager: FunctionComponent<AppUpdatesManagerProps> = () => {
const { autoUpdateSupported, autoUpdateEnabled, newVersionDownloaded, newVersionInfo } = useAppUpdatesContext();
const { autoUpdateSupported, newVersionDownloaded, newVersionInfo } = useAppUpdatesContext();

const [newVersionDetailsShown, setNewVersionDetailsShown] = useState<string | undefined>(undefined);
const [newVersionDetailsSkipVersion, setNewVersionDetailsSkipVersion] = useLocalStorageState<string | undefined>(
@@ -26,51 +25,41 @@ const AppUpdatesManager: FunctionComponent<AppUpdatesManagerProps> = () => {
const [newVersionDownloadedShown, setNewVersionDownloadedShown] = useState<string | undefined>(undefined);

useEffect(() => {
(async () => {
if (!newVersionInfo) {
return;
}
const appVersion = await window.ui.getAppVersion();
if (semverGte(appVersion, newVersionInfo.version)) {
return;
}
if (newVersionDetailsShown === newVersionInfo.version) {
return;
}
if (newVersionDetailsSkipVersion === newVersionInfo.version) {
return;
}
if (autoUpdateSupported && (autoUpdateEnabled || newVersionDownloaded)) {
return;
}
setNewVersionDetailsShown(newVersionInfo.version);
NiceModal.show<undefined, AppUpdateDetailsDialogProps>(AppUpdateDetailsDialog, {
updateInfo: newVersionInfo,
onSkipVersion: setNewVersionDetailsSkipVersion,
});
})();
if (!newVersionInfo) {
return;
}
if (newVersionDetailsShown === newVersionInfo.version) {
return;
}
if (newVersionDetailsSkipVersion === newVersionInfo.version) {
return;
}
if (autoUpdateSupported && newVersionDownloaded) {
return;
}

setNewVersionDetailsShown(newVersionInfo.version);
NiceModal.show<undefined, AppUpdateDetailsDialogProps>(AppUpdateDetailsDialog, {
updateInfo: newVersionInfo,
onSkipVersion: setNewVersionDetailsSkipVersion,
});
}, [newVersionInfo]);

useEffect(() => {
(async () => {
if (!newVersionDownloaded) {
return;
}
const appVersion = await window.ui.getAppVersion();
if (semverGte(appVersion, newVersionDownloaded.version)) {
return;
}
if (newVersionDownloadedShown === newVersionDownloaded.version) {
return;
}
if (!autoUpdateSupported) {
return;
}
setNewVersionDownloadedShown(newVersionDownloaded.version);
NiceModal.show<undefined, AppUpdateDownloadedDialogProps>(AppUpdateDownloadedDialog, {
updateInfo: newVersionDownloaded,
});
})();
if (!newVersionDownloaded) {
return;
}
if (newVersionDownloadedShown === newVersionDownloaded.version) {
return;
}
if (!autoUpdateSupported) {
return;
}

setNewVersionDownloadedShown(newVersionDownloaded.version);
NiceModal.show<undefined, AppUpdateDownloadedDialogProps>(AppUpdateDownloadedDialog, {
updateInfo: newVersionDownloaded,
});
}, [newVersionDownloaded]);

return null;
@@ -87,7 +76,7 @@ const AppUpdateDetailsDialog: FunctionComponent<AppUpdateDetailsDialogProps> = N
({ updateInfo, onSkipVersion }) => {
const modal = useModal();
const { track } = useAnalyticsContext();
const { downloadUpdate } = useAppUpdatesContext();
const { autoUpdateSupported, downloadUpdate } = useAppUpdatesContext();
const { enqueueSnackbar } = useSnackbar();

const closeHandler = useCallback((): void => {
@@ -116,13 +105,14 @@ const AppUpdateDetailsDialog: FunctionComponent<AppUpdateDetailsDialogProps> = N
const downloadHandler = useCallback((): void => {
track({ name: 'app_update_details_dialog_download' });

const downloadType = downloadUpdate();
if (downloadType === 'internal') {
downloadUpdate();

if (autoUpdateSupported) {
enqueueSnackbar(<FormattedMessage id="downloadStarted" />, { variant: 'info' });
}

closeHandler();
}, [downloadUpdate, closeHandler]);
}, [autoUpdateSupported, downloadUpdate, closeHandler]);

const laterHandler = useCallback((): void => {
track({ name: 'app_update_details_dialog_later' });
Loading

0 comments on commit 41bf060

Please sign in to comment.