Skip to content

Commit 4b1d7c1

Browse files
committed
feat: add message if a newer release is available
1 parent fd62269 commit 4b1d7c1

3 files changed

Lines changed: 84 additions & 6 deletions

File tree

ae/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bolt-cep",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"scripts": {
55
"dev": "vite",
66
"debug": "cross-env DEBUG_REACT=true vite build --watch true",

ae/src/ui/main/main.tsx

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
1-
import { useRef } from "react";
1+
import { useRef, useState } from "react";
22
import * as pkg from "../../../package.json";
33
import { evalTS, openLinkInBrowser } from "../lib/utils/bolt";
44
import { useMonaco } from "../monaco/useMonaco";
55
import "./main.scss";
6+
import { useUpdater } from "./updater";
7+
8+
const baseUrl = "https://github.com/motiondeveloper/editor";
69

710
const Main = () => {
811
const editorRef = useRef<HTMLDivElement>(null);
912

1013
const { setValue, getValue, insertValue, disableErrors } =
1114
useMonaco(editorRef);
1215

13-
const issueUrl = new URL(
14-
"https://github.com/motiondeveloper/editor/issues/new",
15-
);
16-
16+
const issueUrl = new URL(baseUrl + "/issues/new");
1717
issueUrl.searchParams.set("title", `[${pkg.version}] Issue Name`);
1818
issueUrl.searchParams.set("labels", "ae");
1919

20+
const releasesUrl = new URL(baseUrl + "/releases");
21+
const updateAvailable = useUpdater();
22+
// TODO: allow users to dismiss update message
23+
const [showUpdateBanner, setShowUpdateBanner] = useState(updateAvailable);
24+
2025
return (
2126
<div className="app">
2227
<div ref={editorRef} id="monaco" />
@@ -47,6 +52,15 @@ const Main = () => {
4752
File Issue
4853
</button>
4954
</div>
55+
{showUpdateBanner && (
56+
// TODO: show better update banner
57+
<div>
58+
An update is available!{" "}
59+
<button onClick={() => openLinkInBrowser(releasesUrl.toString())}>
60+
Download
61+
</button>
62+
</div>
63+
)}
5064
<div>
5165
<label>
5266
Disable TS Errors

ae/src/ui/main/updater.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { useEffect, useState } from "react";
2+
import { version } from "../../../package.json";
3+
4+
export function useUpdater() {
5+
const [updateAvailable, setUpdateAvailable] = useState(false);
6+
7+
useEffect(() => {
8+
async function checkVersion() {
9+
const latestVersion = await getLatestRelease();
10+
11+
if (latestVersion && versionIsGreater(latestVersion, version)) {
12+
setUpdateAvailable(true);
13+
}
14+
}
15+
checkVersion();
16+
}, []);
17+
18+
return updateAvailable;
19+
}
20+
21+
async function getLatestRelease() {
22+
const url = `https://api.github.com/repos/motiondeveloper/editor/releases/latest`;
23+
const response = await fetch(url, {
24+
headers: {
25+
Accept: "application/vnd.github+json",
26+
"X-GitHub-Api-Version": "2022-11-28",
27+
},
28+
});
29+
30+
if (!response.ok) {
31+
// TODO: handle api failures
32+
return;
33+
}
34+
35+
const data = await response.json();
36+
37+
return data.tag_name;
38+
}
39+
40+
function getVersionParts(versionString: string): number[] {
41+
return versionString.split(".").map((s) => Number(s));
42+
}
43+
44+
function versionIsGreater(versionA: string, versionB: string): boolean {
45+
const partsA = getVersionParts(versionA);
46+
const majorA = partsA[0];
47+
const minorA = partsA[1];
48+
const patchA = partsA[2];
49+
50+
const partsB = getVersionParts(versionB);
51+
const majorB = partsB[0];
52+
const minorB = partsB[1];
53+
const patchB = partsB[2];
54+
55+
if (majorA < majorB) return false;
56+
if (majorA > majorB) return true;
57+
58+
if (minorA < minorB) return false;
59+
if (minorA > minorB) return true;
60+
61+
if (patchA < patchB || patchA === patchB) return false;
62+
63+
return true;
64+
}

0 commit comments

Comments
 (0)