Skip to content
This repository has been archived by the owner on Apr 23, 2022. It is now read-only.

Commit

Permalink
feat: Move rate limit to context menu
Browse files Browse the repository at this point in the history
  • Loading branch information
henry40408 committed Apr 28, 2018
1 parent a53a422 commit 30e6a75
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 35 deletions.
1 change: 1 addition & 0 deletions .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
],
"plugins": [
"transform-class-properties",
"transform-object-rest-spread",
"transform-runtime"
],
"ignore": ["node_modules"]
Expand Down
28 changes: 25 additions & 3 deletions app/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,24 @@
"message": "GitHub documentation",
"description": "Option page string"
},
"menuRateLimit": {
"message": "Rate Limit: $REMAINING$ / $LIMIT$ ($RATIO$)",
"description": "Rate limit on context menu",
"placeholders": {
"remaining": {
"content": "$1",
"example": "5,000"
},
"limit": {
"content": "$2",
"example": "5,000"
},
"ratio": {
"content": "$3",
"example": "100%"
}
}
},
"opHowHotAreThoseStars": {
"message": "How Hot are Those Stars?",
"description": "Option page string"
Expand All @@ -93,13 +111,17 @@
"message": "orange",
"description": "Color"
},
"rateLimit": {
"message": "Rate Limit",
"description": "Option page string"
},
"rateLimitDescription": {
"message": "For requests using Basic Authentication or OAuth (including access token), you can make up to 5,000 requests per hour.",
"description": "Option page string"
},
"pleaseDoNotSelectAnyScopes":{
"message":"Please DO NOT select any scopes!",
"description":"Option page string"
"pleaseDoNotSelectAnyScopes": {
"message": "Please DO NOT select any scopes!",
"description": "Option page string"
},
"setupAccessToken": {
"message": "setup access token",
Expand Down
24 changes: 23 additions & 1 deletion app/_locales/zh_TW/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,24 @@
"message": "GitHub 文件",
"description": "Option page string"
},
"menuRateLimit": {
"message": "請求配額: $REMAINING$ / $LIMIT$ ($RATIO$)",
"description": "Rate limit on context menu",
"placeholders": {
"remaining": {
"content": "$1",
"example": "5,000"
},
"limit": {
"content": "$2",
"example": "5,000"
},
"ratio": {
"content": "$3",
"example": "100%"
}
}
},
"opHowHotAreThoseStars": {
"message": "不同顏色的星星代表什麼意思?",
"description": "Option page string"
Expand All @@ -81,6 +99,10 @@
"message": "橘色",
"description": "Color"
},
"rateLimit": {
"message": "請求配額",
"description": "Option page string"
},
"rateLimitDescription": {
"message": "透過 Basic Auth 或 OAuth(包括 access token),我們一小時內可以可以對 GitHub 送出 5,000 次請求。",
"description": "Option page string"
Expand All @@ -106,7 +128,7 @@
"description": "Option page string"
},
"whyDoYouNeedAnAccessTokenDescription2": {
"message": ",在沒有經過 Basic Auth 或 OAuth 認證的情況下,同一個 IP、一小時內只能送出 60 次 request。單一 awesome list 表列的專案數量往往超過這個數目,因此 Awesome List 需要一組 access token 才能正常運作。",
"message": ",在沒有經過 Basic Auth 或 OAuth 認證的情況下,同一個 IP、一小時內只能發出 60 次請求。一項 awesome list 專案表列的專案數量往往超過這個數目,因此 Awesome Stars 需要一組 access token 才能正常運作。",
"description": "Option page string"
},
"yellow": {
Expand Down
25 changes: 16 additions & 9 deletions app/scripts/background.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import * as awilix from 'awilix'

import { log, updateBadge } from './common'
import { log } from './common'
import DIConstants from './constants'

import { version } from '../../package.json'
import AccessTokenRepository from './background/accessTokenRepository'
import CacheService from './background/cacheService'
import ChromeStorageService from './background/chromeStorageService'
import ContextMenuService from './background/contextMenuService'
import GithubService from './background/githubService'
import MessageRouter from './background/messageRouter'

Expand All @@ -15,20 +16,18 @@ if (process.env.NODE_ENV === 'development') {
require('chromereload/devonly')
}

const MENU_APPLY_ON_GITHUB_ISSUES = 'MENU_APPLY_ON_GITHUB_ISSUES'

/** @type {AwilixContainer} */
const container = awilix.createContainer({
injectionMode: awilix.InjectionMode.PROXY
})

container.register({
[DIConstants.LOG]: awilix.asValue(log),
[DIConstants.UPDATE_BADGE]: awilix.asValue(updateBadge),
[DIConstants.MESSAGE_ROUTER]: awilix.asClass(MessageRouter).singleton(),
[DIConstants.R_ACCESS_TOKEN]: awilix.asClass(AccessTokenRepository).singleton(),
[DIConstants.S_CACHE]: awilix.asClass(CacheService).singleton(),
[DIConstants.S_CHROME_STORAGE]: awilix.asClass(ChromeStorageService),
[DIConstants.S_CONTEXT_MENU]: awilix.asClass(ContextMenuService).singleton(),
[DIConstants.S_GITHUB]: awilix.asClass(GithubService)
})

Expand All @@ -38,12 +37,13 @@ const storageService = container.resolve(DIConstants.S_CHROME_STORAGE)
/** @type {MessageRouter} */
const messageRouter = container.resolve(DIConstants.MESSAGE_ROUTER)

/** @type {ContextMenuService} */
const contextMenuService = container.resolve(DIConstants.S_CONTEXT_MENU)

async function applyOnGithubIssuesClickListener () {
const checked = !await storageService.loadAsync(storageService.KEY_APPLY_ON_GITHUB_ISSUES)
await storageService.saveAsync(storageService.KEY_APPLY_ON_GITHUB_ISSUES, checked)
chrome.contextMenus.update(MENU_APPLY_ON_GITHUB_ISSUES, {
checked
})
contextMenuService.upsert(contextMenuService.MENU_APPLY_ON_GITHUB_ISSUES, {checked})
}

async function initializeExtensionAsync () {
Expand All @@ -65,8 +65,15 @@ async function initializeExtensionAsync () {
})

const checked = !!await storageService.loadAsync(storageService.KEY_APPLY_ON_GITHUB_ISSUES)
chrome.contextMenus.create({
id: MENU_APPLY_ON_GITHUB_ISSUES,

contextMenuService.upsert(contextMenuService.MENU_RATE_LIMIT, {
type: 'normal',
contexts: ['browser_action'],
title: 'Rate Limit: N/A',
enabled: false
})

contextMenuService.upsert(contextMenuService.MENU_APPLY_ON_GITHUB_ISSUES, {
type: 'checkbox',
title: chrome.i18n.getMessage('applyOnGithubIssues'),
contexts: ['browser_action'],
Expand Down
20 changes: 20 additions & 0 deletions app/scripts/background/contextMenuService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import includes from 'lodash/includes'

class ContextMenuService {
MENU_RATE_LIMIT = 'rateLimit'
MENU_APPLY_ON_GITHUB_ISSUES = 'applyOnGithubIssues'

constructor (ctx) {
this.menuIds = []
}

upsert (id, options) {
if (!includes(this.menuIds, id)) {
chrome.contextMenus.create({id, ...options})
this.menuIds.push(id)
}
chrome.contextMenus.update(id, options)
}
}

export default ContextMenuService
21 changes: 15 additions & 6 deletions app/scripts/background/githubService.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ class GithubService {

constructor (ctx) {
this.log = ctx[DIConstants.LOG]
this.updateBadge = ctx[DIConstants.UPDATE_BADGE]

/** @type {AccessTokenRepository} */
this.accessToken = ctx[DIConstants.R_ACCESS_TOKEN]

/** @type {CacheService} */
this.cache = ctx[DIConstants.S_CACHE]

/** @type {ContextMenuService} */
this.contextMenu = ctx[DIConstants.S_CONTEXT_MENU]
}

/**
Expand Down Expand Up @@ -63,20 +65,25 @@ class GithubService {
}

async fetchRateLimitAsync () {
const formatter = new Intl.NumberFormat('en-US', {style: 'percent'})
const numberFormatter = new Intl.NumberFormat('en-US')
const percentFormatter = new Intl.NumberFormat('en-US', {style: 'percent'})
const client = await this.buildClient()

try {
const response = await client.get('/rate_limit')
const {rate: {remaining, limit}} = response.data

this.log('rate limit:', {remaining, limit})
const badgeText = formatter.format(remaining / limit)
this.updateBadge(badgeText)

const title = chrome.i18n.getMessage('menuRateLimit', [
numberFormatter.format(remaining),
numberFormatter.format(limit),
percentFormatter.format(remaining / limit)
])
this.contextMenu.upsert(this.contextMenu.MENU_RATE_LIMIT, {title})

return {remaining, limit}
} catch (e) {
this.updateBadge(null)
return {remaining: -1, limit: -1}
}
}
Expand Down Expand Up @@ -104,7 +111,9 @@ class GithubService {
this.log('🌍 fetch repository from Github', repo)
this.cache.set(cacheKey, repo)
} catch (e) {
this.updateBadge(null)
this.contextMenu.upsert(this.contextMenu.MENU_RATE_LIMIT, {
title: chrome.i18n.getMessage('menuRateLimit', ['?', '?', 'N/A'])
})
return -1
}
} else {
Expand Down
12 changes: 0 additions & 12 deletions app/scripts/common.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@
import format from 'date-fns/format'

import colors from './themes/colors'

export function log (...args) {
if (process.env.NODE_ENV === 'development') {
const timestamp = format(new Date(), 'YYYY-MM-DDTHH:mm:ssZ')
// eslint-disable-next-line no-console
console.log.apply(null, [`[${timestamp}]`, ...args])
}
}

export function updateBadge (maybeText) {
const color = maybeText === null ? colors.red : colors.blue
const text = maybeText === null ? 'N/A' : maybeText

log('badge updated:', {color, text})

chrome.browserAction.setBadgeBackgroundColor({color})
chrome.browserAction.setBadgeText({text})
}
2 changes: 1 addition & 1 deletion app/scripts/components/OptionPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ class OptionPage extends React.Component {
<br />
<AlertText>{this.getMessage('pleaseDoNotSelectAnyScopes')}</AlertText>
</p>
<h3>Rate Limit</h3>
<h3>{this.getMessage('rateLimit')}</h3>
<RateLimit inverse remaining={remaining} total={limit} heightInRem={2.5} />
<p>
<small>{this.getMessage('rateLimitDescription')}</small>
Expand Down
4 changes: 2 additions & 2 deletions app/scripts/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default {
S_CACHE: Symbol('cache service'),
S_CHROME_STORAGE: Symbol('chrome storage service'),
S_COMMON: Symbol('common service'),
S_CONTEXT_MENU: Symbol('context menu service'),
S_GITHUB: Symbol('github service'),
LOG: Symbol('log function'),
UPDATE_BADGE: Symbol('update badge function')
LOG: Symbol('log function')
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"babel-eslint": "7.x.x",
"babel-loader": "7.x.x",
"babel-plugin-transform-class-properties": "~6.24.1",
"babel-plugin-transform-object-rest-spread": "~6.26.0",
"babel-plugin-transform-runtime": "~6.23.0",
"babel-preset-env": "1.x.x",
"babili-webpack-plugin": "0.x.x",
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1508,7 +1508,7 @@ babel-plugin-transform-minify-booleans@^6.8.3:
version "6.9.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.0.tgz#e36ceaa49aadcae70ec98bd9dbccb660719a667a"

babel-plugin-transform-object-rest-spread@6.26.0:
babel-plugin-transform-object-rest-spread@6.26.0, babel-plugin-transform-object-rest-spread@~6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06"
dependencies:
Expand Down

0 comments on commit 30e6a75

Please sign in to comment.