From 37cf2e30178b4bd9646e7b3bf8f1eab4fbc9fc91 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Tue, 29 Sep 2020 21:22:08 -0700 Subject: [PATCH] Update version check logic. --- components/common/UpdateNotice.js | 22 +++++++++----- components/pages/Settings.js | 2 +- hooks/useVersion.js | 23 +++++++++----- lang/en-US.json | 2 +- lib/constants.js | 1 + redux/actions/app.js | 50 ++++++++++++++++--------------- 6 files changed, 58 insertions(+), 42 deletions(-) diff --git a/components/common/UpdateNotice.js b/components/common/UpdateNotice.js index 13b0cb59..27ec562a 100644 --- a/components/common/UpdateNotice.js +++ b/components/common/UpdateNotice.js @@ -1,21 +1,27 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; -import semver from 'semver'; import useVersion from 'hooks/useVersion'; import styles from './UpdateNotice.module.css'; import ButtonLayout from '../layout/ButtonLayout'; import Button from './Button'; +import useForceUpdate from '../../hooks/useForceUpdate'; export default function UpdateNotice() { - const versions = useVersion(); + const forceUpdte = useForceUpdate(); + const { hasUpdate, latest, updateCheck } = useVersion(); - if (!versions) { - return null; + function handleViewClick() { + location.href = 'https://github.com/mikecao/umami/releases'; + updateCheck(); + forceUpdte(); } - const { current, latest } = versions; + function handleDismissClick() { + updateCheck(); + forceUpdte(); + } - if (latest && semver.gte(current, latest)) { + if (!hasUpdate) { return null; } @@ -29,10 +35,10 @@ export default function UpdateNotice() { /> - - diff --git a/components/pages/Settings.js b/components/pages/Settings.js index c6e39f2a..35d039df 100644 --- a/components/pages/Settings.js +++ b/components/pages/Settings.js @@ -26,7 +26,7 @@ export default function Settings() { { label: , value: ACCOUNTS, - hidden: !user.is_admin, + hidden: !user?.is_admin, }, { label: , diff --git a/hooks/useVersion.js b/hooks/useVersion.js index 52c53b5a..d8e3d699 100644 --- a/hooks/useVersion.js +++ b/hooks/useVersion.js @@ -1,20 +1,27 @@ -import { useEffect } from 'react'; +import { useEffect, useCallback } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { getItem } from 'lib/web'; +import semver from 'semver'; +import { getItem, setItem } from 'lib/web'; import { checkVersion } from 'redux/actions/app'; - -const CHECK_INTERVAL = 24 * 60 * 60 * 1000; +import { VERSION_CHECK } from 'lib/constants'; export default function useVersion() { const dispatch = useDispatch(); const versions = useSelector(state => state.app.versions); + const lastCheck = getItem(VERSION_CHECK); + + const { current, latest } = versions; + const hasUpdate = latest && semver.gt(latest, current) && lastCheck?.version !== latest; + + const updateCheck = useCallback(() => { + setItem(VERSION_CHECK, { version: latest, time: Date.now() }); + }, [versions]); useEffect(() => { - const lastCheck = getItem('umami.version-check'); - if (!lastCheck || Date.now() - lastCheck > CHECK_INTERVAL) { + if (!versions.latest) { dispatch(checkVersion()); } - }, []); + }, [versions]); - return versions; + return { ...versions, hasUpdate, updateCheck }; } diff --git a/lang/en-US.json b/lang/en-US.json index 15450b4c..7c513b95 100644 --- a/lang/en-US.json +++ b/lang/en-US.json @@ -55,7 +55,7 @@ "message.get-tracking-code": "Get tracking code", "message.go-to-settings": "Go to settings", "message.incorrect-username-password": "Incorrect username/password.", - "message.new-version-available": "Version {latest} available! Current version: {current}", + "message.new-version-available": "A new version of umami {version} is available!", "message.no-data-available": "No data available.", "message.no-websites-configured": "You don't have any websites configured.", "message.page-not-found": "Page not found.", diff --git a/lib/constants.js b/lib/constants.js index 8acbf0b6..b16abdc5 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -3,6 +3,7 @@ export const LOCALE_CONFIG = 'umami.locale'; export const TIMEZONE_CONFIG = 'umami.timezone'; export const DATE_RANGE_CONFIG = 'umami.date-range'; export const THEME_CONFIG = 'umami.theme'; +export const VERSION_CHECK = 'umami.version-check'; export const THEME_COLORS = { light: { diff --git a/redux/actions/app.js b/redux/actions/app.js index 1cc5e7b6..490bd7f1 100644 --- a/redux/actions/app.js +++ b/redux/actions/app.js @@ -1,5 +1,5 @@ import { createSlice } from '@reduxjs/toolkit'; -import { get, getItem } from 'lib/web'; +import { getItem } from 'lib/web'; import { LOCALE_CONFIG, THEME_CONFIG } from 'lib/constants'; const app = createSlice({ @@ -40,30 +40,32 @@ export function checkVersion() { }, } = getState(); - const data = await get('https://api.github.com/repos/mikecao/umami/releases/latest'); - - if (!data || !data['tag_name']) { - return; - } - - const latest = data['tag_name'].startsWith('v') ? data['tag_name'].slice(1) : data['tag_name']; - - if (latest === current) { - return; - } - - const latestArray = latest.split('.'); - const currentArray = current.split('.'); - - for (let i = 0; i < 3; i++) { - if (Number(latestArray[i]) > Number(currentArray[i])) { - return dispatch( - setVersions({ - current, - latest: latest, - }), - ); + const data = await fetch('https://api.github.com/repos/mikecao/umami/releases/latest', { + method: 'get', + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }).then(res => { + if (res.ok) { + return res.json(); } + + return null; + }); + + if (!data) { + return; } + + const { tag_name } = data; + + const latest = tag_name.startsWith('v') ? tag_name.slice(1) : tag_name; + + return dispatch( + setVersions({ + current, + latest, + }), + ); }; }