Skip to content

Commit eb33ad6

Browse files
authored
UPDATE: Open the release page for launcher updates on macOS and Windows (#2322)
1 parent 14ba708 commit eb33ad6

7 files changed

Lines changed: 98 additions & 18 deletions

File tree

‎launcher/src/StereumUpdater.js‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { autoUpdater } from "electron-updater";
2-
import { app, BrowserWindow } from "electron";
2+
import { app, BrowserWindow, shell } from "electron";
3+
4+
// unsigned macOS and Windows builds can't replace themselves, so the user downloads the release
5+
export const RELEASES_URL = "https://github.com/stereum-dev/ethereum-node/releases/latest";
36

47
export class StereumUpdater {
58
constructor(logger, createWindow) {
@@ -9,6 +12,7 @@ export class StereumUpdater {
912
this.createWindow = createWindow;
1013
this.newVersion = null;
1114
this.dryRun = false;
15+
this.manual = process.platform === "darwin" || process.platform === "win32";
1216
}
1317

1418
checkForUpdates() {
@@ -20,6 +24,11 @@ export class StereumUpdater {
2024
return this.newVersion;
2125
}
2226

27+
// how the update window offers the update: in place, or as a download from the release page
28+
getUpdateMode() {
29+
return { manual: this.manual, url: RELEASES_URL };
30+
}
31+
2332
initUpdater() {
2433
this.updater.logger = this.logger;
2534
this.updater.logger.transports.file.level = "debug";
@@ -73,6 +82,11 @@ export class StereumUpdater {
7382
}
7483

7584
async downloadUpdate() {
85+
if (this.manual) {
86+
this.logger.info(`Opening ${RELEASES_URL} to download ${this.newVersion}.`);
87+
await shell.openExternal(RELEASES_URL);
88+
return this.ignoreUpdate();
89+
}
7690
this.dryRun ? this.runDebugDownload() : this.updater.downloadUpdate();
7791
this.logger.info("Downloading update...");
7892
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
jest.mock("electron", () => ({
2+
app: {},
3+
BrowserWindow: { getAllWindows: () => [] },
4+
shell: { openExternal: jest.fn(() => Promise.resolve()) },
5+
}));
6+
jest.mock("electron-updater", () => ({ autoUpdater: { on: jest.fn(), downloadUpdate: jest.fn(), checkForUpdates: jest.fn() } }));
7+
8+
import { shell } from "electron";
9+
import { autoUpdater } from "electron-updater";
10+
import { StereumUpdater, RELEASES_URL } from "../../../StereumUpdater";
11+
12+
const logger = { info: jest.fn(), error: jest.fn() };
13+
const platform = Object.getOwnPropertyDescriptor(process, "platform");
14+
const updaterOn = (name) => {
15+
Object.defineProperty(process, "platform", { value: name });
16+
const updater = new StereumUpdater(logger, jest.fn());
17+
updater.updateWindow = { close: jest.fn(() => Promise.resolve()) };
18+
return updater;
19+
};
20+
21+
afterEach(() => {
22+
Object.defineProperty(process, "platform", platform);
23+
jest.clearAllMocks();
24+
});
25+
26+
test.each(["darwin", "win32"])("on %s the update opens the release page and continues into the app", async (name) => {
27+
const updater = updaterOn(name);
28+
expect(updater.getUpdateMode()).toEqual({ manual: true, url: RELEASES_URL });
29+
await updater.downloadUpdate();
30+
expect(shell.openExternal).toHaveBeenCalledWith(RELEASES_URL);
31+
expect(autoUpdater.downloadUpdate).not.toHaveBeenCalled();
32+
expect(updater.updateWindow.close).toHaveBeenCalled();
33+
expect(updater.createWindow).toHaveBeenCalledWith();
34+
});
35+
36+
test("on Linux the update still downloads and installs itself", async () => {
37+
const updater = updaterOn("linux");
38+
expect(updater.getUpdateMode().manual).toBe(false);
39+
await updater.downloadUpdate();
40+
expect(autoUpdater.downloadUpdate).toHaveBeenCalled();
41+
expect(shell.openExternal).not.toHaveBeenCalled();
42+
});

‎launcher/src/background.js‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,10 @@ ipcMain.handle("getNewLauncherVersion", async () => {
766766
return stereumUpdater.getNewLauncherVersion();
767767
});
768768

769+
ipcMain.handle("getLauncherUpdateMode", async () => {
770+
return stereumUpdater.getUpdateMode();
771+
});
772+
769773
ipcMain.handle("deleteSlasherVolume", async (event, args) => {
770774
return await serviceManager.deleteSlasherVolume(args);
771775
});

‎launcher/src/components/UI/server-management/components/modals/UpdateModal.vue‎

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,21 @@
88
@close-window="closeWindow"
99
>
1010
<template #content>
11-
<div class="update-content-parent w-full h-full grid grid-cols-24 grid-rows-12 items-center">
12-
<span class="col-start-5 col-end-21 row-start-2 row-end-4 text-md text-center text-gray-300">{{ t("updateModal.updateQ") }}</span>
13-
<div
14-
class="btn-modal col-start-3 col-end-10 row-start-8 row-span-4 h-full rounded-2xl px-2 font-semibold text-xl text-gray-700 bg-[#70E763] flex items-center justify-center uppercase cursor-pointer"
15-
@click="submitUpdate"
16-
>
17-
<span>{{ t("updateModal.acc") }}</span>
18-
</div>
19-
<div
20-
class="btn-modal col-start-16 col-end-23 row-start-8 row-span-4 h-full rounded-2xl px-2 font-semibold text-xl text-gray-100 bg-[#EB5353] flex items-center justify-center uppercase cursor-pointer"
21-
@click="closeWindow"
22-
>
23-
<span>{{ t("updateModal.deny") }}</span>
11+
<div class="update-content-parent w-full flex flex-col items-center gap-10 py-6">
12+
<span class="w-2/3 text-md text-center text-gray-300">{{ manual ? t("updateModal.manualQ") : t("updateModal.updateQ") }}</span>
13+
<div class="w-full flex justify-around">
14+
<div
15+
class="btn-modal w-[30%] h-12 rounded-2xl px-2 font-semibold text-xl text-gray-700 bg-[#70E763] flex items-center justify-center uppercase cursor-pointer"
16+
@click="submitUpdate"
17+
>
18+
<span>{{ manual ? t("updateModal.download") : t("updateModal.acc") }}</span>
19+
</div>
20+
<div
21+
class="btn-modal w-[30%] h-12 rounded-2xl px-2 font-semibold text-xl text-gray-100 bg-[#EB5353] flex items-center justify-center uppercase cursor-pointer"
22+
@click="closeWindow"
23+
>
24+
<span>{{ manual ? t("updateModal.later") : t("updateModal.deny") }}</span>
25+
</div>
2426
</div>
2527
</div>
2628
</template>
@@ -33,6 +35,8 @@ import i18n from "@/includes/i18n";
3335
const t = i18n.global.t;
3436
defineProps({
3537
version: String,
38+
// the update is downloaded from the release page instead of installed in place
39+
manual: { type: Boolean, default: false },
3640
});
3741
3842
const emit = defineEmits(["update", "close-window"]);

‎launcher/src/languages/en.json‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1062,7 +1062,10 @@
10621062
"updateQ": "Do you want to update now?",
10631063
"acc": "accept",
10641064
"deny": "deny",
1065-
"updateTo": "Updating Stereum Launcher to {version}"
1065+
"updateTo": "Updating Stereum Launcher to {version}",
1066+
"manualQ": "Stereum can't update itself on this system. Download the new version from GitHub and install it over this one. Your settings are kept.",
1067+
"download": "download",
1068+
"later": "later"
10661069
},
10671070
"setupServicesWidget": {
10681071
"text": "total services on setup"

‎launcher/src/pages/UpdateHandler.vue‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,19 @@
1515
<div class="update-text h-1/6 w-full flex justify-center items-center text-2xl text-gray-50 font-semibold">
1616
<span>{{ `${updateState.message}${updateState.MBps ? "" + updateState.MBps.toFixed(2) + " MBps" : ""}` }}</span>
1717
</div>
18-
<UpdateModal v-if="updateModel" :version="serviceStore?.launcherVersion" @update="runUpdate" @close-window="closeUpdateModal" />
18+
<UpdateModal
19+
v-if="updateModel"
20+
:version="updateState.version"
21+
:manual="updateMode.manual"
22+
@update="runUpdate"
23+
@close-window="closeUpdateModal"
24+
/>
1925
</div>
2026
</template>
2127
<script setup>
2228
import UpdateModal from "../components/UI/server-management/components/modals/UpdateModal.vue";
2329
import ControlService from "@/store/ControlService";
2430
import { ref, onMounted, onUnmounted } from "vue";
25-
import { useServices } from "@/store/services";
2631
import i18n from "@/includes/i18n";
2732
const t = i18n.global.t;
2833
@@ -34,13 +39,17 @@ const updateState = ref({
3439
version: "-",
3540
});
3641
37-
const serviceStore = useServices();
3842
const updateModel = ref(true);
43+
// manual: this system can't update in place, so the update opens the release page
44+
const updateMode = ref({ manual: false, url: "" });
3945
4046
onMounted(() => {
4147
ControlService.getNewLauncherVersion().then((version) => {
4248
updateState.value.version = version;
4349
});
50+
ControlService.getLauncherUpdateMode().then((mode) => {
51+
if (mode) updateMode.value = mode;
52+
});
4453
ControlService.addListener("UpdateEvents", updateHandler);
4554
});
4655

‎launcher/src/store/ControlService.js‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,10 @@ class ControlService extends EventEmitter {
642642
return this.promiseIpc.send("getNewLauncherVersion");
643643
}
644644

645+
async getLauncherUpdateMode() {
646+
return this.promiseIpc.send("getLauncherUpdateMode");
647+
}
648+
645649
async getSubnetSubs() {
646650
return this.promiseIpc.send("getSubnetSubs");
647651
}

0 commit comments

Comments
 (0)