Skip to content

Commit a81ea2c

Browse files
authored
Add pre-release check functionality to settings modal (#964)
* Add pre-release check functionality to settings modal * Address copilot review comments
1 parent 61cb292 commit a81ea2c

1 file changed

Lines changed: 101 additions & 2 deletions

File tree

gcs/src/components/settingsModal.jsx

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,26 @@ import {
1010
} from "@mantine/core"
1111
import { useSettings } from "../helpers/settings"
1212

13+
import { ActionIcon, Tooltip } from "@mantine/core"
14+
import { useDisclosure } from "@mantine/hooks"
1315
import {
1416
IconAlertCircle,
1517
IconCheck,
1618
IconRestore,
1719
IconTrash,
1820
} from "@tabler/icons-react"
21+
import { Octokit } from "octokit"
1922
import { memo, useEffect, useState } from "react"
20-
import { ActionIcon, Tooltip } from "@mantine/core"
21-
import { useDisclosure } from "@mantine/hooks"
23+
import semverGt from "semver/functions/gt"
2224
import DefaultSettings from "../../data/default_settings.json"
2325
import {
2426
closeLoadingNotification,
2527
redColor,
2628
showLoadingNotification,
2729
} from "../helpers/notification"
2830

31+
const octokit = new Octokit({})
32+
2933
const isValidNumber = (num, range) => {
3034
return (
3135
num &&
@@ -83,6 +87,96 @@ function BoolSetting({ settingName }) {
8387
)
8488
}
8589

90+
function PrereleaseCheckRow() {
91+
const [checking, setChecking] = useState(false)
92+
const [result, setResult] = useState(null)
93+
94+
const checkNow = async () => {
95+
setChecking(true)
96+
setResult(null)
97+
try {
98+
// Allow manual check in dev and production
99+
const currentVersion = await window.ipcRenderer.invoke("app:get-version")
100+
101+
const releases = await octokit.request(
102+
"GET /repos/{owner}/{repo}/releases",
103+
{
104+
owner: "Avis-Drone-Labs",
105+
repo: "fgcs",
106+
headers: { "X-GitHub-Api-Version": "2022-11-28" },
107+
},
108+
)
109+
110+
if (releases.status !== 200) {
111+
setResult({ error: "Failed to fetch releases" })
112+
return
113+
}
114+
115+
const prereleases = releases.data.filter((r) => r.prerelease)
116+
if (prereleases.length === 0) {
117+
setResult({ found: false })
118+
return
119+
}
120+
121+
// Choose the most recent prerelease by published_at
122+
prereleases.sort(
123+
(a, b) => new Date(b.published_at) - new Date(a.published_at),
124+
)
125+
const latest = prereleases[0]
126+
const latestTag = latest.tag_name
127+
128+
const isNewer = semverGt(latestTag, currentVersion)
129+
setResult({ found: true, latestTag, url: latest.html_url, isNewer })
130+
} catch (err) {
131+
setResult({ error: err.message })
132+
} finally {
133+
setChecking(false)
134+
}
135+
}
136+
137+
return (
138+
<div className="px-10 flex items-center gap-4">
139+
<div className="flex-1">
140+
<div className="text-sm">Pre-release check</div>
141+
<div className="text-xs text-gray-400">
142+
Manually check for pre-release versions on GitHub
143+
</div>
144+
</div>
145+
<div className="flex items-center gap-2">
146+
<Button size="xs" color="blue" onClick={checkNow} loading={checking}>
147+
Check now
148+
</Button>
149+
{result && result.error && (
150+
<div className="text-xs text-red-400">Error: {result.error}</div>
151+
)}
152+
{result && !result.error && !result.found && (
153+
<div className="text-xs text-gray-400">No pre-releases found</div>
154+
)}
155+
{result && result.found && (
156+
<div className="text-xs">
157+
Latest:{" "}
158+
<a
159+
className="text-blue-400 underline"
160+
href={result.url}
161+
target="_blank"
162+
rel="noreferrer"
163+
>
164+
{result.latestTag}
165+
</a>
166+
{result.isNewer ? (
167+
<span className="text-green-400 pl-2">
168+
(Newer than installed)
169+
</span>
170+
) : (
171+
<span className="text-gray-400 pl-2">(Not newer)</span>
172+
)}
173+
</div>
174+
)}
175+
</div>
176+
</div>
177+
)
178+
}
179+
86180
function OptionSetting({ settingName, options }) {
87181
const { getSetting, setSetting } = useSettings()
88182
return (
@@ -640,6 +734,11 @@ function SettingsModal() {
640734
{Object.keys(tabSettings).length === 0 && (
641735
<p className="pl-4 pt-2">No settings available right now.</p>
642736
)}
737+
{tab === "General" && (
738+
<div className="pt-4">
739+
<PrereleaseCheckRow />
740+
</div>
741+
)}
643742
</Tabs.Panel>
644743
)
645744
})}

0 commit comments

Comments
 (0)