From 6916850d85fae44aab2fa203e82167c2b5499c18 Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Sat, 27 Oct 2018 19:05:31 +0800 Subject: [PATCH] feat: handle API rate limit --- src/components/SettingsBar.js | 74 +++++++++++++++++++++++------------ src/components/SideBar.js | 43 ++++++++++++++++---- src/driver/core/SideBar.js | 6 +-- src/utils/GitHubHelper.js | 14 +++++-- 4 files changed, 97 insertions(+), 40 deletions(-) diff --git a/src/components/SettingsBar.js b/src/components/SettingsBar.js index 9fcf448..c36cdb2 100644 --- a/src/components/SettingsBar.js +++ b/src/components/SettingsBar.js @@ -89,7 +89,14 @@ export default class SettingsBar extends React.PureComponent { onAccessTokenChange(accessToken) this.setState({ accessToken: '', - accessTokenHint: window.location.reload()}>Reload to activate!, + accessTokenHint: ( + + window.location.reload()}> + Reload + {' '} + to activate! + + ), }) } } @@ -126,38 +133,44 @@ export default class SettingsBar extends React.PureComponent { const { setCompressSingleton } = this.props setCompressSingleton(compress) this.setState({ - compressHint: Saved, window.location.reload()}>reload to apply., + compressHint: ( + + Saved,{' '} + window.location.reload()}> + reload + {' '} + to apply. + + ), }) } render() { - const { accessTokenHint, toggleShowSideBarShortcut, compressSingletonFolder, shortcutHint, accessToken, compressHint } = this.state + const { + accessTokenHint, + toggleShowSideBarShortcut, + compressSingletonFolder, + shortcutHint, + accessToken, + compressHint, + } = this.state const { toggleShowSettings, activated, accessToken: hasAccessToken } = this.props return (
{activated && ( -

- Settings -

+

Settings

Access Token

- With access token provided, Gitako can access more repositories. -
- - Help: how to create access token? + + Why & how to create it?
- - Gitako stores the token in  - - chrome local storage - -  locally and safely. - -

Compress singleton folder  - (?) + + (?) +

{compressHint &&
{compressHint}
} @@ -220,7 +241,12 @@ export default class SettingsBar extends React.PureComponent { )}
- + v{version} {activated ? ( @@ -230,11 +256,7 @@ export default class SettingsBar extends React.PureComponent { onClick={toggleShowSettings} /> ) : ( - + )}
diff --git a/src/components/SideBar.js b/src/components/SideBar.js index c43c8d7..e1d995c 100644 --- a/src/components/SideBar.js +++ b/src/components/SideBar.js @@ -79,23 +79,46 @@ export default class Gitako extends React.PureComponent {
Access Denied

- Gitako needs access token with proper scopes (recommended: repo) to access this - repository. Please save it in the settings below. + Due to{' '} + + limitation of GitHub + {' '} + or{' '} + + auth needs + + , Gitako needs access token to continue. Please follow the instructions in the settings + panel below.

) } renderContent() { - const { errorDueToAuth, metaData, treeData, showSettings, accessToken, compressSingletonFolder, toggleShowSettings } = this.props + const { + errorDueToAuth, + metaData, + treeData, + showSettings, + accessToken, + compressSingletonFolder, + toggleShowSettings, + } = this.props return (
{metaData && } {errorDueToAuth ? this.renderAccessDeniedError() - : metaData && - - } + : metaData && ( + + )}
) } @@ -119,7 +142,11 @@ export default class Gitako extends React.PureComponent { return (
- +
@@ -133,7 +160,7 @@ export default class Gitako extends React.PureComponent { compressSingletonFolder={compressSingletonFolder} toggleShowSideBarShortcut={toggleShowSideBarShortcut} setCompressSingleton={setCompressSingleton} - /> + />
diff --git a/src/driver/core/SideBar.js b/src/driver/core/SideBar.js index 6ec6415..bad4925 100644 --- a/src/driver/core/SideBar.js +++ b/src/driver/core/SideBar.js @@ -1,5 +1,5 @@ import DOMHelper, { REPO_TYPE_PRIVATE } from 'utils/DOMHelper' -import GitHubHelper, { NOT_FOUND, BAD_CREDENTIALS } from 'utils/GitHubHelper' +import GitHubHelper, { NOT_FOUND, BAD_CREDENTIALS, API_RATE_LIMIT } from 'utils/GitHubHelper' import configHelper from 'utils/configHelper' import URLHelper from 'utils/URLHelper' import keyHelper from 'utils/keyHelper' @@ -53,9 +53,9 @@ const init = dispatch => async () => { const handleError = dispatch => async (err) => { // TODO: detect request time exceeds limit - if (err.message === NOT_FOUND || err.message === BAD_CREDENTIALS) { + if (err.message === NOT_FOUND || err.message === BAD_CREDENTIALS || err.message === API_RATE_LIMIT ) { const repoPageType = await DOMHelper.getRepoPageType() - const errorDueToAuth = repoPageType === REPO_TYPE_PRIVATE || err.message === BAD_CREDENTIALS + const errorDueToAuth = repoPageType === REPO_TYPE_PRIVATE || err.message === BAD_CREDENTIALS || err.message === API_RATE_LIMIT dispatch({ errorDueToAuth }) dispatch(setShowSettings, true) dispatch(setShouldShow, errorDueToAuth) diff --git a/src/utils/GitHubHelper.js b/src/utils/GitHubHelper.js index 25bd775..5b11313 100644 --- a/src/utils/GitHubHelper.js +++ b/src/utils/GitHubHelper.js @@ -1,6 +1,11 @@ import { raiseError } from 'analytics' export const NOT_FOUND = 'Repo Not Found' export const BAD_CREDENTIALS = 'Bad credentials' +export const API_RATE_LIMIT = `API rate limit` + +function apiRateLimitExceeded(content) { + return content && content['documentation_url'] === 'https://developer.github.com/v3/#rate-limiting' +} async function request(url, { accessToken } = {}) { const headers = {} @@ -11,9 +16,12 @@ async function request(url, { accessToken } = {}) { if (res.status === 200) return res.json() // for private repo, GitHub api also responses with 404 when unauthorized else if (res.status === 404) throw new Error(NOT_FOUND) - else if (!res.ok) raiseError(new Error(`Got ${res.statusText} when requesting ${url}`)) - const content = await res.json() - throw new Error(content && content.message) + else { + const content = await res.json() + if (apiRateLimitExceeded(content)) throw new Error(API_RATE_LIMIT) + else if (!res.ok) raiseError(new Error(`Got ${res.statusText} when requesting ${url}`)) + throw new Error(content && content.message) + } } async function getRepoMeta({ userName, repoName, accessToken }) {