mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-05-02 12:07:02 +00:00
use emsesp.org/versions.json
This commit is contained in:
@@ -58,11 +58,5 @@ export const alovaInstance = createAlova({
|
||||
}
|
||||
});
|
||||
|
||||
export const alovaInstanceGH = createAlova({
|
||||
baseURL:
|
||||
process.env.NODE_ENV === 'development'
|
||||
? '/gh'
|
||||
: 'https://api.github.com/repos/emsesp/EMS-ESP32/releases',
|
||||
statesHook: ReactHook,
|
||||
requestAdapter: xhrRequestAdapter()
|
||||
});
|
||||
export const DOCS_BASE_URL =
|
||||
process.env.NODE_ENV === 'development' ? '/emsesp.org' : 'https://emsesp.org';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { LogSettings, SystemStatus } from 'types';
|
||||
|
||||
import { alovaInstance, alovaInstanceGH } from './endpoints';
|
||||
import { DOCS_BASE_URL, alovaInstance } from './endpoints';
|
||||
|
||||
// systemStatus - also used to ping in System Monitor for pinging
|
||||
export const readSystemStatus = () =>
|
||||
@@ -13,28 +13,13 @@ export const updateLogSettings = (data: LogSettings) =>
|
||||
alovaInstance.Post('/rest/logSettings', data);
|
||||
export const fetchLogES = () => alovaInstance.Get('/es/log');
|
||||
|
||||
// Get versions from GitHub
|
||||
// cache for 10 minutes to stop getting the IP blocked by GitHub
|
||||
export const getStableVersion = () =>
|
||||
alovaInstanceGH.Get('latest', {
|
||||
cacheFor: 60 * 10 * 1000,
|
||||
transform(response: { data: { name: string; published_at: string } }) {
|
||||
return {
|
||||
name: response.data.name.substring(1),
|
||||
published_at: response.data.published_at
|
||||
};
|
||||
}
|
||||
});
|
||||
export const getDevVersion = () =>
|
||||
alovaInstanceGH.Get('tags/latest', {
|
||||
cacheFor: 60 * 10 * 1000,
|
||||
transform(response: { data: { name: string; published_at: string } }) {
|
||||
return {
|
||||
name: response.data.name.split(/\s+/).splice(-1)[0]?.substring(1) || '',
|
||||
published_at: response.data.published_at
|
||||
};
|
||||
}
|
||||
});
|
||||
// get versions from emsesp.org/versions.json
|
||||
// uses native fetch (no custom headers) to keep this as a "simple" CORS
|
||||
export const getVersions = async <T = unknown>(): Promise<T> => {
|
||||
const res = await fetch(`${DOCS_BASE_URL}/versions.json`);
|
||||
if (!res.ok) throw new Error(res.statusText);
|
||||
return res.json() as Promise<T>;
|
||||
};
|
||||
|
||||
const UPLOAD_TIMEOUT = 60000; // 1 minute
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
|
||||
import * as SystemApi from 'api/system';
|
||||
import { API, callAction } from 'api/app';
|
||||
import { getDevVersion, getStableVersion } from 'api/system';
|
||||
import { getVersions } from 'api/system';
|
||||
|
||||
import { dialogStyle } from 'CustomTheme';
|
||||
import { useRequest } from 'alova/client';
|
||||
@@ -86,8 +86,14 @@ interface UpgradeCheckData {
|
||||
}
|
||||
|
||||
interface VersionInfo {
|
||||
name: string;
|
||||
published_at?: string;
|
||||
version: string;
|
||||
date: string;
|
||||
}
|
||||
|
||||
interface Versions {
|
||||
stable: VersionInfo;
|
||||
dev: VersionInfo;
|
||||
last_updated: string;
|
||||
}
|
||||
|
||||
// Memoized components for better performance
|
||||
@@ -156,8 +162,8 @@ const VersionInfoDialog = memo(
|
||||
{isPartition
|
||||
? typeof version === 'string'
|
||||
? version
|
||||
: version?.name
|
||||
: version?.name}
|
||||
: version?.version
|
||||
: version?.version}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow sx={{ height: 24, borderBottom: 'none' }}>
|
||||
@@ -224,7 +230,7 @@ const VersionInfoDialog = memo(
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
{version?.published_at && (
|
||||
{version.date && (
|
||||
<TableRow sx={{ height: 24, borderBottom: 'none' }}>
|
||||
<TableCell
|
||||
component="th"
|
||||
@@ -240,7 +246,7 @@ const VersionInfoDialog = memo(
|
||||
{isPartition ? 'Install Date' : 'Build Date'}
|
||||
</TableCell>
|
||||
<TableCell sx={{ borderBottom: 'none', py: 0.5, fontSize: 13 }}>
|
||||
{prettyDateTime(locale, new Date(version.published_at))}
|
||||
{prettyDateTime(locale, new Date(version.date))}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
@@ -296,11 +302,11 @@ const InstallDialog = memo(
|
||||
if (!latestVersion || !latestDevVersion) return '';
|
||||
|
||||
const version = fetchDevVersion ? latestDevVersion : latestVersion;
|
||||
const filename = `EMS-ESP-${version.name.replaceAll('.', '_')}-${platform}.bin`;
|
||||
const filename = `EMS-ESP-${version.version.replaceAll('.', '_')}-${platform}.bin`;
|
||||
|
||||
return fetchDevVersion
|
||||
? `${DEV_URL}${filename}`
|
||||
: `${STABLE_URL}v${version.name}/${filename}`;
|
||||
: `${STABLE_URL}v${version.version}/${filename}`;
|
||||
}, [fetchDevVersion, latestVersion, latestDevVersion, platform]);
|
||||
|
||||
return (
|
||||
@@ -312,7 +318,7 @@ const InstallDialog = memo(
|
||||
<Typography sx={{ mb: 2 }}>
|
||||
{LL.INSTALL_VERSION(
|
||||
downloadOnly ? LL.DOWNLOAD(1) : LL.INSTALL(),
|
||||
fetchDevVersion ? latestDevVersion?.name : latestVersion?.name
|
||||
fetchDevVersion ? latestDevVersion?.version : latestVersion?.version
|
||||
)}
|
||||
</Typography>
|
||||
{upgradeImportantMessageType === 2 && LL.UPGRADE_IMPORTANT_MESSAGES_2()}
|
||||
@@ -436,7 +442,9 @@ const Version = () => {
|
||||
const { LL, locale } = useI18nContext();
|
||||
const { me } = useContext(AuthenticatedContext);
|
||||
|
||||
// State management
|
||||
const [latestVersion, setLatestVersion] = useState<VersionInfo>();
|
||||
const [latestDevVersion, setLatestDevVersion] = useState<VersionInfo>();
|
||||
|
||||
const [restarting, setRestarting] = useState<boolean>(false);
|
||||
const [openInstallDialog, setOpenInstallDialog] = useState<boolean>(false);
|
||||
|
||||
@@ -490,8 +498,32 @@ const Version = () => {
|
||||
{ immediate: false }
|
||||
);
|
||||
|
||||
const { data: latestVersion } = useRequest(getStableVersion);
|
||||
const { data: latestDevVersion } = useRequest(getDevVersion);
|
||||
// Fetch versions.json from emsesp.org once on mount.
|
||||
// Uses plain fetch (not alova) so the request stays a "simple" CORS request and avoids a preflight that emsesp.org rejects.
|
||||
// sendCheckUpgrade is stored in a ref because alova's useRequest returns a new function reference each render
|
||||
const sendCheckUpgradeRef = useRef(sendCheckUpgrade);
|
||||
sendCheckUpgradeRef.current = sendCheckUpgrade;
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
getVersions<Versions>()
|
||||
.then((versions) => {
|
||||
if (cancelled) return;
|
||||
setLatestVersion(versions.stable);
|
||||
setLatestDevVersion(versions.dev);
|
||||
sendCheckUpgradeRef.current(
|
||||
`${versions.stable.version},${versions.dev.version}`
|
||||
);
|
||||
setInternetLive(true);
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
if (cancelled) return;
|
||||
toast.error(error instanceof Error ? error.message : 'An error occurred');
|
||||
setInternetLive(false);
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const { send: sendAPI } = useRequest((data: APIcall) => API(data), {
|
||||
immediate: false
|
||||
@@ -517,10 +549,8 @@ const Version = () => {
|
||||
toast.error(String(error.error?.message || 'An error occurred'));
|
||||
});
|
||||
|
||||
// Memoized values
|
||||
const platform = useMemo(() => (data ? getPlatform(data) : ''), [data]);
|
||||
|
||||
// Memoize filtered partitions to avoid recomputing on every render
|
||||
const otherPartitions = useMemo(
|
||||
() => data?.partitions.filter((p) => p.partition !== data.partition) ?? [],
|
||||
[data]
|
||||
@@ -534,8 +564,8 @@ const Version = () => {
|
||||
const partitionData = data?.partitions.find((p) => p.partition === partition);
|
||||
if (partitionData) {
|
||||
setPartitionVersion({
|
||||
name: partitionData.version,
|
||||
published_at: partitionData.install_date ?? ''
|
||||
version: partitionData.version,
|
||||
date: partitionData.install_date ?? ''
|
||||
});
|
||||
setPartition(partitionData.partition);
|
||||
setFirmwareSize(partitionData.size);
|
||||
@@ -576,7 +606,7 @@ const Version = () => {
|
||||
const showPartitionDialog = useCallback(
|
||||
(version: string, partition: string, install_date: string) => {
|
||||
setOpenInstallPartitionDialog(true);
|
||||
setPartitionVersion({ name: version, published_at: install_date });
|
||||
setPartitionVersion({ version: version, date: install_date });
|
||||
setPartition(partition);
|
||||
},
|
||||
[]
|
||||
@@ -586,7 +616,7 @@ const Version = () => {
|
||||
(useDevVersion: boolean) => {
|
||||
setFetchDevVersion(useDevVersion);
|
||||
void checkUpgradeImportantMessages(
|
||||
useDevVersion ? latestDevVersion?.name : latestVersion?.name
|
||||
useDevVersion ? latestDevVersion?.version : latestVersion?.version
|
||||
);
|
||||
setOpenInstallDialog(true);
|
||||
},
|
||||
@@ -607,25 +637,8 @@ const Version = () => {
|
||||
setPartition('');
|
||||
}, []);
|
||||
|
||||
// check upgrades - only once when both versions are available
|
||||
const upgradeCheckedRef = useRef(false);
|
||||
useEffect(() => {
|
||||
if (latestVersion && latestDevVersion && !upgradeCheckedRef.current) {
|
||||
upgradeCheckedRef.current = true;
|
||||
const versions = `${latestDevVersion.name},${latestVersion.name}`;
|
||||
sendCheckUpgrade(versions)
|
||||
.catch((error: Error) => {
|
||||
toast.error(`Failed to check for upgrades: ${error.message}`);
|
||||
})
|
||||
.finally(() => {
|
||||
setInternetLive(true);
|
||||
});
|
||||
}
|
||||
}, [latestVersion, latestDevVersion, sendCheckUpgrade]);
|
||||
|
||||
useLayoutTitle('EMS-ESP Firmware');
|
||||
|
||||
// Memoized button rendering logic
|
||||
const showButtons = useCallback(
|
||||
(showingDev: boolean) => {
|
||||
const choice = showingDev
|
||||
@@ -818,7 +831,7 @@ const Version = () => {
|
||||
</Grid>
|
||||
<Grid size={{ xs: 8, md: 10 }}>
|
||||
<Typography>
|
||||
{latestVersion?.name}
|
||||
{latestVersion?.version}
|
||||
<IconButton
|
||||
onClick={() => setShowVersionInfo(1)}
|
||||
aria-label={LL.FIRMWARE_VERSION_INFO()}
|
||||
@@ -834,7 +847,7 @@ const Version = () => {
|
||||
</Grid>
|
||||
<Grid size={{ xs: 8, md: 10 }}>
|
||||
<Typography>
|
||||
{latestDevVersion?.name}
|
||||
{latestDevVersion?.version}
|
||||
<IconButton
|
||||
onClick={() => setShowVersionInfo(2)}
|
||||
aria-label={LL.FIRMWARE_VERSION_INFO()}
|
||||
@@ -880,7 +893,7 @@ const Version = () => {
|
||||
/>
|
||||
<InstallPartitionDialog
|
||||
openInstallPartitionDialog={openInstallPartitionDialog}
|
||||
version={partitionVersion?.name || ''}
|
||||
version={partitionVersion?.version || ''}
|
||||
partition={partition}
|
||||
LL={LL}
|
||||
onClose={closeInstallPartitionDialog}
|
||||
|
||||
Reference in New Issue
Block a user