Merge branch 'autoupgrade'

This commit is contained in:
SPRINX0\prochazka
2024-09-10 08:49:58 +02:00
17 changed files with 200 additions and 33 deletions

View File

@@ -102,6 +102,7 @@ jobs:
mv app/dist/*.deb artifacts/ || true mv app/dist/*.deb artifacts/ || true
mv app/dist/*.snap artifacts/ || true mv app/dist/*.snap artifacts/ || true
mv app/dist/*.dmg artifacts/ || true mv app/dist/*.dmg artifacts/ || true
mv app/dist/*.blockmap artifacts/ || true
mv app/dist/*.yml artifacts/ || true mv app/dist/*.yml artifacts/ || true
rm artifacts/builder-debug.yml rm artifacts/builder-debug.yml

View File

@@ -132,6 +132,7 @@ jobs:
mv ../dbgate-merged/app/dist/*.deb artifacts/ || true mv ../dbgate-merged/app/dist/*.deb artifacts/ || true
mv ../dbgate-merged/app/dist/*.snap artifacts/ || true mv ../dbgate-merged/app/dist/*.snap artifacts/ || true
mv ../dbgate-merged/app/dist/*.dmg artifacts/ || true mv ../dbgate-merged/app/dist/*.dmg artifacts/ || true
mv ../dbgate-merged/app/dist/*.blockmap artifacts/ || true
mv ../dbgate-merged/app/dist/*.yml artifacts/ || true mv ../dbgate-merged/app/dist/*.yml artifacts/ || true
rm artifacts/builder-debug.yml rm artifacts/builder-debug.yml

View File

@@ -135,6 +135,7 @@ jobs:
mv ../dbgate-merged/app/dist/*.AppImage artifacts/ || true mv ../dbgate-merged/app/dist/*.AppImage artifacts/ || true
mv ../dbgate-merged/app/dist/*.deb artifacts/ || true mv ../dbgate-merged/app/dist/*.deb artifacts/ || true
mv ../dbgate-merged/app/dist/*.dmg artifacts/ || true mv ../dbgate-merged/app/dist/*.dmg artifacts/ || true
mv ../dbgate-merged/app/dist/*.blockmap artifacts/ || true
mv ../dbgate-merged/app/dist/*.yml artifacts/ || true mv ../dbgate-merged/app/dist/*.yml artifacts/ || true
rm artifacts/builder-debug.yml rm artifacts/builder-debug.yml

View File

@@ -109,6 +109,7 @@ jobs:
mv app/dist/*.deb artifacts/ || true mv app/dist/*.deb artifacts/ || true
mv app/dist/*.dmg artifacts/ || true mv app/dist/*.dmg artifacts/ || true
mv app/dist/*.snap artifacts/dbgate-latest.snap || true mv app/dist/*.snap artifacts/dbgate-latest.snap || true
mv app/dist/*.blockmap artifacts/ || true
mv app/dist/*.yml artifacts/ || true mv app/dist/*.yml artifacts/ || true
rm artifacts/builder-debug.yml rm artifacts/builder-debug.yml

View File

@@ -18,7 +18,6 @@ const url = require('url');
const mainMenuDefinition = require('./mainMenuDefinition'); const mainMenuDefinition = require('./mainMenuDefinition');
const { isProApp } = require('./proTools'); const { isProApp } = require('./proTools');
const updaterChannel = require('./updaterChannel'); const updaterChannel = require('./updaterChannel');
let disableAutoUpgrade = false;
// require('@electron/remote/main').initialize(); // require('@electron/remote/main').initialize();
@@ -29,6 +28,8 @@ let apiLoaded = false;
let mainModule; let mainModule;
// let getLogger; // let getLogger;
// let loadLogsContent; // let loadLogsContent;
let appUpdateStatus = '';
let settingsJson = {};
process.on('uncaughtException', function (error) { process.on('uncaughtException', function (error) {
console.error('uncaughtException', error); console.error('uncaughtException', error);
@@ -52,21 +53,11 @@ const isMac = () => os.platform() == 'darwin';
try { try {
initialConfig = JSON.parse(fs.readFileSync(configRootPath, { encoding: 'utf-8' })); initialConfig = JSON.parse(fs.readFileSync(configRootPath, { encoding: 'utf-8' }));
disableAutoUpgrade = initialConfig['disableAutoUpgrade'] || false;
} catch (err) { } catch (err) {
console.log('Error loading config-root:', err.message); console.log('Error loading config-root:', err.message);
initialConfig = {}; initialConfig = {};
} }
if (process.argv.includes('--disable-auto-upgrade')) {
console.log('Disabling auto-upgrade');
disableAutoUpgrade = true;
}
if (process.argv.includes('--enable-auto-upgrade')) {
console.log('Enabling auto-upgrade');
disableAutoUpgrade = false;
}
// Keep a global reference of the window object, if you don't, the window will // Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected. // be closed automatically when the JavaScript object is garbage collected.
let mainWindow; let mainWindow;
@@ -212,6 +203,15 @@ ipcMain.on('app-started', async (event, arg) => {
if (initialConfig['winIsMaximized']) { if (initialConfig['winIsMaximized']) {
mainWindow.webContents.send('setIsMaximized', true); mainWindow.webContents.send('setIsMaximized', true);
} }
if (autoUpdater.isUpdaterActive()) {
mainWindow.webContents.send('setAppUpdaterActive');
}
if (!process.env.DEVMODE) {
if (settingsJson['app.autoUpdateMode'] != 'skip') {
autoUpdater.autoDownload = settingsJson['app.autoUpdateMode'] == 'download';
autoUpdater.checkForUpdates();
}
}
}); });
ipcMain.on('window-action', async (event, arg) => { ipcMain.on('window-action', async (event, arg) => {
if (!mainWindow) { if (!mainWindow) {
@@ -285,6 +285,20 @@ ipcMain.handle('showItemInFolder', async (event, path) => {
ipcMain.handle('openExternal', async (event, url) => { ipcMain.handle('openExternal', async (event, url) => {
electron.shell.openExternal(url); electron.shell.openExternal(url);
}); });
ipcMain.handle('downloadUpdate', async (event, url) => {
autoUpdater.downloadUpdate();
changeAppUpdateStatus({
icon: 'icon loading',
message: `Downloading update...`,
});
});
ipcMain.on('applyUpdate', async (event, url) => {
autoUpdater.quitAndInstall(false, true);
});
ipcMain.on('check-for-updates', async (event, url) => {
autoUpdater.autoDownload = false;
autoUpdater.checkForUpdates();
});
function fillMissingSettings(value) { function fillMissingSettings(value) {
const res = { const res = {
@@ -322,8 +336,6 @@ function ensureBoundsVisible(bounds) {
function createWindow() { function createWindow() {
const datadir = path.join(os.homedir(), '.dbgate'); const datadir = path.join(os.homedir(), '.dbgate');
let settingsJson = {};
let licenseKey = null;
try { try {
settingsJson = fillMissingSettings( settingsJson = fillMissingSettings(
JSON.parse(fs.readFileSync(path.join(datadir, 'settings.json'), { encoding: 'utf-8' })) JSON.parse(fs.readFileSync(path.join(datadir, 'settings.json'), { encoding: 'utf-8' }))
@@ -332,14 +344,6 @@ function createWindow() {
console.log('Error loading settings.json:', err.message); console.log('Error loading settings.json:', err.message);
settingsJson = fillMissingSettings({}); settingsJson = fillMissingSettings({});
} }
if (isProApp()) {
try {
licenseKey = fs.readFileSync(path.join(datadir, 'license.key'), { encoding: 'utf-8' });
} catch (err) {
console.log('Error loading license.key:', err.message);
licenseKey = null;
}
}
let bounds = initialConfig['winBounds']; let bounds = initialConfig['winBounds'];
if (bounds) { if (bounds) {
@@ -355,7 +359,7 @@ function createWindow() {
titleBarStyle: useNativeMenu ? undefined : 'hidden', titleBarStyle: useNativeMenu ? undefined : 'hidden',
...bounds, ...bounds,
icon: os.platform() == 'win32' ? 'icon.ico' : path.resolve(__dirname, '../icon.png'), icon: os.platform() == 'win32' ? 'icon.ico' : path.resolve(__dirname, '../icon.png'),
partition: 'persist:dbgate', partition: isProApp() ? 'persist:dbgate-premium' : 'persist:dbgate',
webPreferences: { webPreferences: {
nodeIntegration: true, nodeIntegration: true,
contextIsolation: false, contextIsolation: false,
@@ -389,7 +393,6 @@ function createWindow() {
JSON.stringify({ JSON.stringify({
winBounds: mainWindow.getBounds(), winBounds: mainWindow.getBounds(),
winIsMaximized: mainWindow.isMaximized(), winIsMaximized: mainWindow.isMaximized(),
disableAutoUpgrade,
}), }),
'utf-8' 'utf-8'
); );
@@ -459,13 +462,61 @@ function createWindow() {
}); });
} }
function changeAppUpdateStatus(status) {
appUpdateStatus = status;
mainWindow.webContents.send('app-update-status', appUpdateStatus);
}
autoUpdater.on('checking-for-update', () => {
console.log('Checking for updates');
changeAppUpdateStatus({
icon: 'icon loading',
message: 'Checking for updates...',
});
});
autoUpdater.on('update-available', info => {
console.log('Update available', info);
if (autoUpdater.autoDownload) {
changeAppUpdateStatus({
icon: 'icon loading',
message: `Downloading update...`,
});
} else {
mainWindow.webContents.send('update-available', info.version);
changeAppUpdateStatus({
icon: 'icon download',
message: `New version ${info.version} available`,
});
}
});
autoUpdater.on('update-not-available', info => {
console.log('Update not available', info);
changeAppUpdateStatus({
icon: 'icon check',
message: `No new updates`,
});
});
autoUpdater.on('update-downloaded', info => {
console.log('Update downloaded from', info);
changeAppUpdateStatus({
icon: 'icon download',
message: `Downloaded new version ${info.version}`,
});
mainWindow.webContents.send('downloaded-new-version', info.version);
});
autoUpdater.on('error', error => {
changeAppUpdateStatus({
icon: 'icon error',
message: `Autoupdate error`,
});
console.error('Update error', error);
});
function onAppReady() { function onAppReady() {
if (disableAutoUpgrade) {
console.log('Auto-upgrade is disabled, run dbgate --enable-auto-upgrade to enable');
}
if (!process.env.DEVMODE && !disableAutoUpgrade) {
autoUpdater.checkForUpdatesAndNotify();
}
createWindow(); createWindow();
} }

View File

@@ -105,6 +105,8 @@ module.exports = ({ editMenu }) => [
{ command: 'settings.commands', hideDisabled: true }, { command: 'settings.commands', hideDisabled: true },
{ command: 'tabs.changelog', hideDisabled: true }, { command: 'tabs.changelog', hideDisabled: true },
{ command: 'about.show', hideDisabled: true }, { command: 'about.show', hideDisabled: true },
{ divider: true },
{ command: 'file.checkForUpdates', hideDisabled: true },
], ],
}, },
]; ];

View File

@@ -1,6 +1,6 @@
{ {
"private": true, "private": true,
"version": "5.4.4-premium-beta.5", "version": "5.4.4-beta.10",
"name": "dbgate-all", "name": "dbgate-all",
"workspaces": [ "workspaces": [
"packages/*", "packages/*",

View File

@@ -5,6 +5,14 @@ function checkLicense() {
}; };
} }
function checkLicenseKey(key) {
return {
status: 'ok',
type: 'community',
};
}
module.exports = { module.exports = {
checkLicense, checkLicense,
checkLicenseKey,
}; };

View File

@@ -21,6 +21,7 @@
import AppStartInfo from './widgets/AppStartInfo.svelte'; import AppStartInfo from './widgets/AppStartInfo.svelte';
import SettingsListener from './utility/SettingsListener.svelte'; import SettingsListener from './utility/SettingsListener.svelte';
import { handleAuthOnStartup } from './clientAuth'; import { handleAuthOnStartup } from './clientAuth';
import { initializeAppUpdates } from './utility/appUpdate';
export let isAdminPage = false; export let isAdminPage = false;
@@ -49,6 +50,7 @@
subscribeConnectionPingers(); subscribeConnectionPingers();
subscribePermissionCompiler(); subscribePermissionCompiler();
installNewVolatileConnectionListener(); installNewVolatileConnectionListener();
initializeAppUpdates();
} }
loadedApi = loadedApiValue; loadedApi = loadedApiValue;

View File

@@ -3,6 +3,7 @@ import {
currentTheme, currentTheme,
emptyConnectionGroupNames, emptyConnectionGroupNames,
extensions, extensions,
getAppUpdaterActive,
getExtensions, getExtensions,
getVisibleToolbar, getVisibleToolbar,
visibleToolbar, visibleToolbar,
@@ -585,6 +586,17 @@ registerCommand({
onClick: () => disconnectServerConnection(getCurrentConfig()?.singleConnection?._id), onClick: () => disconnectServerConnection(getCurrentConfig()?.singleConnection?._id),
}); });
registerCommand({
id: 'file.checkForUpdates',
category: 'App',
name: 'Check for updates',
// testEnabled: () => true,
testEnabled: () => getAppUpdaterActive(),
onClick: () => getElectron().send('check-for-updates'),
});
export function registerFileCommands({ export function registerFileCommands({
idPrefix, idPrefix,
category, category,

View File

@@ -140,6 +140,7 @@
'icon custom-join': 'mdi mdi-arrow-left-right-bold', 'icon custom-join': 'mdi mdi-arrow-left-right-bold',
'icon parent-filter': 'mdi mdi-home-alert', 'icon parent-filter': 'mdi mdi-home-alert',
'icon parent-filter-outline': 'mdi mdi-home-alert-outline', 'icon parent-filter-outline': 'mdi mdi-home-alert-outline',
'icon download': 'mdi mdi-download',
'icon run': 'mdi mdi-play', 'icon run': 'mdi mdi-play',
'icon chevron-down': 'mdi mdi-chevron-down', 'icon chevron-down': 'mdi mdi-chevron-down',

View File

@@ -342,6 +342,18 @@ ORDER BY
<div class="heading">Other</div> <div class="heading">Other</div>
<FormTextField name="other.gistCreateToken" label="API token for creating error gists" defaultValue="" /> <FormTextField name="other.gistCreateToken" label="API token for creating error gists" defaultValue="" />
<FormSelectField
label="Auto update application"
name="app.autoUpdateMode"
isNative
defaultValue=""
options={[
{ value: 'skip', label: 'Do not check for new versions' },
{ value: '', label: 'Check for new versions' },
{ value: 'download', label: 'Check and download new versions' },
]}
/>
</svelte:fragment> </svelte:fragment>
<svelte:fragment slot="7"> <svelte:fragment slot="7">

View File

@@ -123,6 +123,8 @@ export const commandsCustomized = derived([commands, commandsSettings], ([$comma
...$commandsSettings[k], ...$commandsSettings[k],
})) }))
); );
export const appUpdateStatus = writable(null);
export const appUpdaterActive = writable(false);
export const draggingTab = writable(null); export const draggingTab = writable(null);
export const draggingTabTarget = writable(null); export const draggingTabTarget = writable(null);
@@ -303,3 +305,9 @@ currentArchive.subscribe(value => {
currentArchiveValue = value; currentArchiveValue = value;
}); });
export const getCurrentArchive = () => currentArchiveValue; export const getCurrentArchive = () => currentArchiveValue;
let appUpdaterActiveValue = false;
appUpdaterActive.subscribe(value => {
appUpdaterActiveValue = value;
});
export const getAppUpdaterActive = () => appUpdaterActiveValue;

View File

@@ -0,0 +1,52 @@
import invalidateCommands from '../commands/invalidateCommands';
import { appUpdaterActive, appUpdateStatus } from '../stores';
import getElectron from './getElectron';
import { showSnackbar } from './snackbar';
export function initializeAppUpdates() {
const electron = getElectron();
if (!electron) {
return;
}
electron.addEventListener('update-available', (e, version) => {
showSnackbar({
message: `Update available: ${version}`,
allowClose: true,
buttons: [
{
label: 'Download',
onClick: () => {
electron.send('downloadUpdate');
},
autoClose: true,
},
],
});
});
electron.addEventListener('app-update-status', (e, value) => {
appUpdateStatus.set(value);
});
electron.addEventListener('downloaded-new-version', (e, version) => {
showSnackbar({
message: `New version ${version} downloaded`,
allowClose: true,
buttons: [
{
label: 'Restart',
onClick: () => {
electron.send('applyUpdate');
},
autoClose: true,
},
],
});
});
electron.addEventListener('setAppUpdaterActive', (e, error) => {
appUpdaterActive.set(true);
invalidateCommands();
});
}

View File

@@ -3,6 +3,7 @@ import { openedSnackbars } from '../stores';
export interface SnackbarButton { export interface SnackbarButton {
label: string; label: string;
onClick: Function; onClick: Function;
autoClose?: boolean;
} }
export interface SnackbarInfo { export interface SnackbarInfo {

View File

@@ -18,7 +18,6 @@
onMount(() => { onMount(() => {
if (autoClose) setTimeout(handleClose, 3000); if (autoClose) setTimeout(handleClose, 3000);
}); });
</script> </script>
<div class="wrapper"> <div class="wrapper">
@@ -37,7 +36,15 @@
<div class="buttons"> <div class="buttons">
{#each buttons as button} {#each buttons as button}
<div class="button"> <div class="button">
<FormStyledButton value={button.label} on:click={button.onClick} /> <FormStyledButton
value={button.label}
on:click={() => {
if (button.autoClose) {
handleClose();
}
button.onClick?.();
}}
/>
</div> </div>
{/each} {/each}
</div> </div>
@@ -76,5 +83,4 @@
.button { .button {
margin: 5px; margin: 5px;
} }
</style> </style>

View File

@@ -8,6 +8,7 @@
import { import {
activeTabId, activeTabId,
appUpdateStatus,
currentArchive, currentArchive,
currentDatabase, currentDatabase,
currentThemeDefinition, currentThemeDefinition,
@@ -169,6 +170,13 @@
{item.text} {item.text}
</div> </div>
{/each} {/each}
{#if $appUpdateStatus}
<div class="item">
<FontIcon icon={$appUpdateStatus.icon} padRight />
{$appUpdateStatus.message}
</div>
{/if}
</div> </div>
</div> </div>