Skip to content

Commit

Permalink
Merge pull request #21 from crnbrdrck/0.1.8
Browse files Browse the repository at this point in the history
0.1.8
  • Loading branch information
Ciaran Broderick authored Aug 18, 2018
2 parents 9805b63 + 770bf39 commit 8ecbfee
Show file tree
Hide file tree
Showing 12 changed files with 109 additions and 72 deletions.
23 changes: 12 additions & 11 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,37 @@
# GitHub User Languages Changelog
If your browser just opened this page, that means that a new version of the extension has gone live!
# 0.1.8
- Removed the opening of this page when an update is installed
- Fixed issue where requests were being made on pages they shouldn't have been
- Prevented extension from adding anything to a page if the repo data for the account is empty
- Improved design of options page

Take a look at what was added in this update directly below, or take a look at the project's entire history by reading the entire page!

## 0.1.7 (latest)
# 0.1.7
- Added simple settings popup
- Allows for turning on and off the chart legend on all pages
- Allows adding a GitHub personal access token to allow more API usage
- Simply click on the icon in the toolbar to access the settings popup
- Extension now opens a tab briging you here so you can see new changes

## 0.1.6
# 0.1.6
- Added error handling for when querying the API goes wrong

## 0.1.5
# 0.1.5
- New logo courtesy of [ihtiht](https://github.com/ihtiht)!

## 0.1.4
# 0.1.4
- Fixed issues with charts not displaying on Org pages
- Also was an issue where my HTML wasn't correct on Org pages
- Somehow I think the two were related

## 0.1.3
# 0.1.3
- Pie chart now displays on org pages as well as user pages
- The chart is quite large on org pages because Chart.js tries to fill the container width wise and I've set the height to match the width
- If this is a problem, please open an issue and we can discuss this further

## 0.1.2
# 0.1.2
- Added checks to ensure that the extension pulls all of a user's repos using GitHub's pagination
- Previously the extension would only get the first 30 repos created by the user

## 0.1.1
# 0.1.1
- Added caching to avoid over-using the GitHub API
- Currently cache timeout is set to be an hour but will later make this changeable per user
- Due to a difference in ordering between data pulled from cache and from the API, the languages are now drawn in alphabetical order clockwise around the pie chart to keep ordering the same
16 changes: 6 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,12 @@ Also, by clicking on one of the segments, you can be redirected to a list of rep

The same now works for [Orgs](https://github.com/github)

## Roadmap
## Chrome v1 Major Release
As far as I can tell, I think the extension is ready for a full release now.

- [x] Draw the pie chart
- [x] Make it available on the chrome store
- [x] Add storage of data for users to avoid over-using the Github API and getting rate limited
- [x] Add org page handling
- [x] Basic settings
- [ ] Add some control over the cache for users (i.e setting timeouts, force cache invalidation, etc)
- [ ] Give some time for issues in Chrome version to be dealt with
- [ ] Create a version for Firefox browsers
I'm going to give it until the end of August for any bugs to come in (I might post it on Reddit or something) and then I'll mark the release as v1.0.0

After that, I might write a Firefox version too, who knows?

## Want to Contribute?
Contributing doesn't just mean writing code!
Expand All @@ -59,7 +55,7 @@ I'm also not that great at writing READMEs so help with this one would be very w
#### Notes
- Whenever you make changes to the extension, the JS will compile automatically but you'll need to click the little circle arrow on `chrome://extensions` to reload the extension
- It's probably a good idea to turn off the release version while you're doing development so they don't mess with eachother
- If you want to turn off caching while in development, simply uncomment the `return reject();` at line 37 of `data.ts`
- If you want to turn off caching while in development, simply uncomment the `return reject();` at line 50 of `data.ts`

## Boilerplate
Boilerplate used to set up this project can be found at https://github.com/chibat/chrome-extension-typescript-starter
Expand Down
5 changes: 5 additions & 0 deletions bump.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Simple script to handle the versioning for me to ensure I don't miss a version"""

import json
import subprocess

# Get the version to bump
while True:
Expand Down Expand Up @@ -45,3 +46,7 @@
lines = [f'# {new_ver}', '\n', '\n'] + lines
with open('CHANGELOG.md', 'w') as f:
f.write(''.join(lines))

# Also run sed on the popup.html file to change the version in the popup
cmd = ['sed', '-i', f's/v{old_ver}/v{new_ver}/', 'dist/popup.html']
subprocess.run(cmd)
6 changes: 1 addition & 5 deletions dist/manifest.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
{
"author": "crnbrdrck (Ciaran Broderick)",
"background": {
"scripts": ["js/background.js"],
"persistent": false
},
"browser_action": {
"default_icon": "images/github-user-languages.128.png",
"default_popup": "popup.html"
Expand All @@ -30,7 +26,7 @@
"tabs"
],
"short_name": "github-user-languages",
"version": "0.1.7",
"version": "0.1.8",
"web_accessible_resources": [
"colors.json"
]
Expand Down
37 changes: 28 additions & 9 deletions dist/popup.html
Original file line number Diff line number Diff line change
@@ -1,24 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet">
<style>
body {
width: 400px;
}
body, input[type="text"] {
font-family: "Lato", sans-serif;
font-weight: 400;
}
input[type="text"] {
width: 100%;
width: 90%;
}
input[type="checkbox"] {
vertical-align: middle;
}
footer {
text-align: right;
}
</style>
</head>
<body>
<h3>GitHub User Languages Settings</h3>
<hr />
<input type="checkbox" id="show-legend" disabled />
<label for="show-legend">Show Legend In Chart</label>
<hr />
<input type="text" id="personal-access-token" disabled />
<label for="personal-access-token">Personal Access Token <small>Click out of input to save</small>.</label>
<p><a id="get-token" href="#">Click here</a> to generate one. These are used to increase the number of API requests you make.</p>
<header>
<img src="https://github.com/crnbrdrck/github-user-languages/raw/master/img/logotype_horizontal.png" alt="gh-user-langs logo" width="400" height="92" />
</header>
<main>
<h4>Chart Settings</h4>
<input type="checkbox" id="show-legend" disabled />
<label for="show-legend"><span>Show Legend</span></label>

<h4>API Token <small>Click out of input to save</small></h4>
<label for="personal-access-token">Token</label>
<input type="text" id="personal-access-token" disabled />
<p><a id="get-token" href="#">Click here</a> to generate one. These are used to increase the number of API requests you make.</p>
</main>
<footer>
<small>GitHub User Languages v0.1.8</small>
</footer>
<script src="js/popup.js"></script>
</body>
</html>
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@
"build": "webpack --config webpack/webpack.prod.js",
"watch": "webpack --config webpack/webpack.dev.js --watch"
},
"version": "0.1.7"
"version": "0.1.8"
}
8 changes: 0 additions & 8 deletions src/background.ts

This file was deleted.

43 changes: 27 additions & 16 deletions src/content.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// This script is excuted directly from inside the page
import { Chart } from 'chart.js';
import { Data } from './data';
import { Data, ICachedData, IColorData, IRepoData } from './data';

class LanguageDisplay {
private canvas : HTMLCanvasElement;
Expand All @@ -21,7 +21,6 @@ class LanguageDisplay {
// Org page, set the flag as such
this.isOrg = true;
this.parent = document.querySelector('div.col-4.float-right.pl-4');
console.log(this.parent);
}
this.canvas = null;
this.container = null;
Expand All @@ -33,19 +32,23 @@ class LanguageDisplay {
});
}

private async getData(): Promise<any> {
private async getData() {
// Fetch the color data from the json file
// Use the promise provided by the Data class to get all necessary data
try {
const values = await this.data.getData();
// 0 -> color data, 1 -> repo data
const colorData = values[0];
const repoData = values[1];
const colorData: IColorData = values[0];
const repoData: IRepoData = values[1];
// If the repoData is empty, don't go any further
if (this.data.emptyAccount) {
return;
}
// Cache the repoData we just got, if we need to
if (!this.data.repoDataFromCache) {
this.cacheData(repoData);
}
// Build the graph
// Build the graph
this.build(colorData, repoData);
} catch (e) {
// This is where we need to add the error display
Expand All @@ -62,10 +65,10 @@ class LanguageDisplay {
}
}

private cacheData(data : object) {
private cacheData(data : IRepoData) {
// Store the repo data in the cache for the username
const cachedAt = new Date().valueOf();
const value = {
const cachedAt: number = new Date().valueOf();
const value: ICachedData = {
cachedAt,
data,
};
Expand Down Expand Up @@ -112,7 +115,7 @@ class LanguageDisplay {
return canvas;
}

private build(colorData : object, repoData : object) {
private build(colorData : IColorData, repoData : IRepoData) {
this.container = this.createContainer();
this.parent.appendChild(this.container);
// Get the width and height of the container and use it to build the canvas
Expand All @@ -131,7 +134,7 @@ class LanguageDisplay {
});
}

private draw(colorData: object, repoData: object, showLegend: boolean) {
private draw(colorData: IColorData, repoData: IRepoData, showLegend: boolean) {
// Create the pie chart and populate it with the repo data
const counts = [];
const colors = [];
Expand Down Expand Up @@ -184,12 +187,20 @@ class LanguageDisplay {

}

// Get the profile name for the current page, if the current page is an account page
// The profile name will get retrieved from location.pathname
const path = window.location.pathname.substr(1);
// It's the profile page if path.split(/).length is 1 or its 2 but the last item is the empty string
// This is a workaround until I can fix the issue with matching trailing slashes in the manifest file
let profileName : string | null = null;
let path = window.location.pathname.substr(1);
// Trim the trailing slash if there is one
if (path[path.length - 1] === "/") {
path = path.slice(0, -1);
}
// The page is correct if the length of path.split is 1 and the first item isn't the empty string
const splitPath = path.split('/');
if (splitPath.length === 1 || (splitPath.length === 2 && splitPath[1] === '')) {
const profileName = splitPath[0];
if (splitPath.length === 1 && splitPath[0].length !== 0) {
profileName = splitPath[0];
}
// If profileName is not null, draw the chart
if (profileName !== null) {
const graph = new LanguageDisplay(profileName);
}
30 changes: 21 additions & 9 deletions src/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,17 @@

const CACHE_THRESHOLD = 36e5; // 1 hour

interface ICachedData {
export interface IRepoData {
[language: string]: number;
}

export interface IColorData {
[language: string]: string;
}

export interface ICachedData {
cachedAt : number;
data : object;
data : IRepoData;
}

interface IAPIRepoData {
Expand All @@ -14,6 +22,7 @@ interface IAPIRepoData {

export class Data {
public repoDataFromCache : boolean = false;
public emptyAccount : boolean = true;
private isOrg : boolean;
private personalToken : string;
private username : string;
Expand All @@ -24,13 +33,13 @@ export class Data {
this.personalToken = token;
}

public getData() : Promise<object[]> {
public getData() : Promise<[IColorData, IRepoData]> {
// Gets both the color data and repo data and returns a Promise that will resolve to get both of them
// Calling .then on this should get back an array of two values; color and repo data respectively
return Promise.all([this.getColorData(), this.getRepoData()]);
}

private async getColorData() : Promise<JSON> {
private async getColorData() : Promise<IColorData> {
const url = chrome.runtime.getURL('colors.json');
return (await fetch(url)).json();
}
Expand All @@ -46,9 +55,11 @@ export class Data {
return reject();
}
// We have a cached object, so check time of cache
const cachedData = result[this.username];
const cachedData: ICachedData = result[this.username];
if (new Date().valueOf() - cachedData.cachedAt < CACHE_THRESHOLD) {
// We can use the cached version
// Set emptyAccount flag to false here too
this.emptyAccount = false;
return resolve(cachedData);
}

Expand All @@ -58,7 +69,7 @@ export class Data {
}

// Fetches the repo data either from cache or from the API and returns a Promise for the data
private async getRepoData() : Promise<object> {
private async getRepoData() : Promise<IRepoData> {
try {
// Check if the user's data is in the cache
const cachedData = await this.checkCache();
Expand All @@ -70,12 +81,13 @@ export class Data {
}
}

private updateRepoData(repoData : object, json : IAPIRepoData[]) : object {
private updateRepoData(repoData : IRepoData, json : IAPIRepoData[]) : IRepoData {
for (const repo of json) {
if (repo.language === null) { continue; }
let count = repoData[repo.language] || 0;
count++;
repoData[repo.language] = count;
this.emptyAccount = false;
}
return repoData;
}
Expand All @@ -96,11 +108,11 @@ export class Data {
}

// Fetch repository data from the API
private async fetchRepoData() : Promise<object> {
private async fetchRepoData() : Promise<IRepoData> {
const apiSection = this.isOrg ? 'orgs' : 'users';
let url = `https://api.github.com/${apiSection}/${this.username}/repos?page=1&per_page=50`;
let linkHeader : string;
let repoData: object = {};
let repoData: IRepoData = {};
const headers: HeadersInit = {};
if (this.personalToken !== '') { headers.Authorization = `token ${this.personalToken}`; }
const headerRegex = /\<(.*)\>; rel="next"/;
Expand Down
Loading

0 comments on commit 8ecbfee

Please sign in to comment.