From 25b34e05c8b2191a12a46a3057477a4ac9fa9f10 Mon Sep 17 00:00:00 2001 From: Rodrigo Pombo Date: Thu, 7 Feb 2019 13:51:37 -0300 Subject: [PATCH 1/6] Add login button --- package.json | 1 + src/github.js | 36 ++++++++++++++++++++++++++++++++-- src/index.js | 53 +++++++++++++++++++++++++++++++++++++++++---------- yarn.lock | 5 +++++ 4 files changed, 83 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 2c7081c..f63b26e 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "dependencies": { "diff": "^4.0.1", + "netlify-auth-providers": "^1.0.0-alpha5", "prismjs": "^1.15.0", "react": "^16.8.0-alpha.1", "react-dom": "^16.8.0-alpha.1", diff --git a/src/github.js b/src/github.js index 45cf70d..620ced5 100644 --- a/src/github.js +++ b/src/github.js @@ -1,6 +1,19 @@ +import netlify from "netlify-auth-providers"; +const TOKEN_KEY = "github-token"; + +function getHeaders() { + const token = window.localStorage.getItem(TOKEN_KEY); + return token ? { Authorization: `bearer ${token}` } : {}; +} + +export function isLoggedIn() { + return !!window.localStorage.getItem(TOKEN_KEY); +} + async function getContent(repo, sha, path) { const contentResponse = await fetch( - `https://api.github.com/repos/${repo}/contents${path}?ref=${sha}` + `https://api.github.com/repos/${repo}/contents${path}?ref=${sha}`, + { headers: getHeaders() } ); if (!contentResponse.ok) { @@ -13,7 +26,8 @@ async function getContent(repo, sha, path) { export async function getHistory(repo, sha, path, top = 10) { const commitsResponse = await fetch( - `https://api.github.com/repos/${repo}/commits?sha=${sha}&path=${path}` + `https://api.github.com/repos/${repo}/commits?sha=${sha}&path=${path}`, + { headers: getHeaders() } ); if (!commitsResponse.ok) { throw commitsResponse; @@ -48,3 +62,21 @@ export async function getHistory(repo, sha, path, top = 10) { return commits; } + +export function auth() { + return new Promise((resolve, reject) => { + var authenticator = new netlify({ + site_id: "ccf3a0e2-ac06-4f37-9b17-df1dd41fb1a6" + }); + authenticator.authenticate({ provider: "github", scope: "repo" }, function( + err, + data + ) { + if (err) { + reject(err); + } + window.localStorage.setItem(TOKEN_KEY, data.token); + resolve(data); + }); + }); +} diff --git a/src/index.js b/src/index.js index cedbdf8..3274b7f 100755 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ -import { getHistory } from "./github"; +import { getHistory, auth, isLoggedIn } from "./github"; import { getLanguage, getLanguageDependencies } from "./language-detector"; const [repo, sha, path] = getParams(); @@ -20,17 +20,50 @@ if (!repo) { loadLanguage(lang) ]) .then(([commits, app]) => { + if (!commits.length) { + throw new Error("No commits for this file? Maybe the path is wrong"); + } app.render(commits, root, lang); }) - .catch(error => { - if (error.status === 403) { - message.innerHTML = - "

GitHub API rate limit exceeded for your IP (60 requests per hour).

I need to add authentication.

"; - } else { - console.error(error); - message.innerHTML = `

Unexpected error. Check the console.

`; - } - }); + .catch(handleError); +} + +function handleError(error) { + const message = document.getElementById("message"); + if (error.status === 403) { + message.innerHTML = + "

GitHub API rate limit exceeded for your IP (60 requests per hour).

Log in with GitHub for more

"; + const button = document.createElement("button"); + button.textContent = "Login"; + button.onclick = () => { + auth() + .then(data => { + window.location.reload(false); + }) + .catch(console.error); + }; + message.appendChild(button); + } else if (error.status === 404) { + message.innerHTML = `

File not found

${ + isLoggedIn() ? "" : "

Is it from a private repo? Log in with GitHub" + }`; + + if (!isLoggedIn) { + const button = document.createElement("button"); + button.textContent = "Login"; + button.onclick = () => { + auth() + .then(data => { + window.location.reload(false); + }) + .catch(console.error); + }; + message.appendChild(button); + } + } else { + console.error(error); + message.innerHTML = `

Unexpected error. Check the console.

`; + } } function loadLanguage(lang) { diff --git a/yarn.lock b/yarn.lock index dc487e1..6ae15e4 100755 --- a/yarn.lock +++ b/yarn.lock @@ -6439,6 +6439,11 @@ neo-async@^2.5.0: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== +netlify-auth-providers@^1.0.0-alpha5: + version "1.0.0-alpha5" + resolved "https://registry.yarnpkg.com/netlify-auth-providers/-/netlify-auth-providers-1.0.0-alpha5.tgz#f0ce642fe5534f04a1d539ca847c907dd20819c8" + integrity sha512-V4tqW60NEOYdd7QUWotB+XeMbw/kayi4Sbm67hSMWibXHG7xiRUp6+VEB8CmBt7/kb3HTw7+mQSwF7YR9hRaSQ== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" From 1ec578ba25fff8a76221384b879d746fd2a71b7d Mon Sep 17 00:00:00 2001 From: Rodrigo Pombo Date: Thu, 7 Feb 2019 13:51:37 -0300 Subject: [PATCH 2/6] Add login button --- package.json | 1 + src/github.js | 36 ++++++++++++++++++++++++++++++++-- src/index.js | 53 +++++++++++++++++++++++++++++++++++++++++---------- yarn.lock | 5 +++++ 4 files changed, 83 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 0417c73..5063067 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "dependencies": { "diff": "^4.0.1", + "netlify-auth-providers": "^1.0.0-alpha5", "prismjs": "^1.15.0", "react": "^16.8.1", "react-dom": "^16.8.1", diff --git a/src/github.js b/src/github.js index 45cf70d..620ced5 100644 --- a/src/github.js +++ b/src/github.js @@ -1,6 +1,19 @@ +import netlify from "netlify-auth-providers"; +const TOKEN_KEY = "github-token"; + +function getHeaders() { + const token = window.localStorage.getItem(TOKEN_KEY); + return token ? { Authorization: `bearer ${token}` } : {}; +} + +export function isLoggedIn() { + return !!window.localStorage.getItem(TOKEN_KEY); +} + async function getContent(repo, sha, path) { const contentResponse = await fetch( - `https://api.github.com/repos/${repo}/contents${path}?ref=${sha}` + `https://api.github.com/repos/${repo}/contents${path}?ref=${sha}`, + { headers: getHeaders() } ); if (!contentResponse.ok) { @@ -13,7 +26,8 @@ async function getContent(repo, sha, path) { export async function getHistory(repo, sha, path, top = 10) { const commitsResponse = await fetch( - `https://api.github.com/repos/${repo}/commits?sha=${sha}&path=${path}` + `https://api.github.com/repos/${repo}/commits?sha=${sha}&path=${path}`, + { headers: getHeaders() } ); if (!commitsResponse.ok) { throw commitsResponse; @@ -48,3 +62,21 @@ export async function getHistory(repo, sha, path, top = 10) { return commits; } + +export function auth() { + return new Promise((resolve, reject) => { + var authenticator = new netlify({ + site_id: "ccf3a0e2-ac06-4f37-9b17-df1dd41fb1a6" + }); + authenticator.authenticate({ provider: "github", scope: "repo" }, function( + err, + data + ) { + if (err) { + reject(err); + } + window.localStorage.setItem(TOKEN_KEY, data.token); + resolve(data); + }); + }); +} diff --git a/src/index.js b/src/index.js index cedbdf8..3274b7f 100755 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ -import { getHistory } from "./github"; +import { getHistory, auth, isLoggedIn } from "./github"; import { getLanguage, getLanguageDependencies } from "./language-detector"; const [repo, sha, path] = getParams(); @@ -20,17 +20,50 @@ if (!repo) { loadLanguage(lang) ]) .then(([commits, app]) => { + if (!commits.length) { + throw new Error("No commits for this file? Maybe the path is wrong"); + } app.render(commits, root, lang); }) - .catch(error => { - if (error.status === 403) { - message.innerHTML = - "

GitHub API rate limit exceeded for your IP (60 requests per hour).

I need to add authentication.

"; - } else { - console.error(error); - message.innerHTML = `

Unexpected error. Check the console.

`; - } - }); + .catch(handleError); +} + +function handleError(error) { + const message = document.getElementById("message"); + if (error.status === 403) { + message.innerHTML = + "

GitHub API rate limit exceeded for your IP (60 requests per hour).

Log in with GitHub for more

"; + const button = document.createElement("button"); + button.textContent = "Login"; + button.onclick = () => { + auth() + .then(data => { + window.location.reload(false); + }) + .catch(console.error); + }; + message.appendChild(button); + } else if (error.status === 404) { + message.innerHTML = `

File not found

${ + isLoggedIn() ? "" : "

Is it from a private repo? Log in with GitHub" + }`; + + if (!isLoggedIn) { + const button = document.createElement("button"); + button.textContent = "Login"; + button.onclick = () => { + auth() + .then(data => { + window.location.reload(false); + }) + .catch(console.error); + }; + message.appendChild(button); + } + } else { + console.error(error); + message.innerHTML = `

Unexpected error. Check the console.

`; + } } function loadLanguage(lang) { diff --git a/yarn.lock b/yarn.lock index 185a587..441eea2 100755 --- a/yarn.lock +++ b/yarn.lock @@ -6439,6 +6439,11 @@ neo-async@^2.5.0: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== +netlify-auth-providers@^1.0.0-alpha5: + version "1.0.0-alpha5" + resolved "https://registry.yarnpkg.com/netlify-auth-providers/-/netlify-auth-providers-1.0.0-alpha5.tgz#f0ce642fe5534f04a1d539ca847c907dd20819c8" + integrity sha512-V4tqW60NEOYdd7QUWotB+XeMbw/kayi4Sbm67hSMWibXHG7xiRUp6+VEB8CmBt7/kb3HTw7+mQSwF7YR9hRaSQ== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" From a049c272d93360763d2b6d78dab2d9159dcf2c38 Mon Sep 17 00:00:00 2001 From: Rodrigo Pombo Date: Thu, 7 Feb 2019 15:17:26 -0300 Subject: [PATCH 3/6] Move language loading --- src/github.js | 29 +++++++++++++++++++++++++++-- src/index.js | 27 +++------------------------ 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/github.js b/src/github.js index 620ced5..2b06b23 100644 --- a/src/github.js +++ b/src/github.js @@ -1,3 +1,4 @@ +import { getLanguageDependencies } from "./language-detector"; import netlify from "netlify-auth-providers"; const TOKEN_KEY = "github-token"; @@ -24,7 +25,7 @@ async function getContent(repo, sha, path) { return { content, url: contentJson.html_url }; } -export async function getHistory(repo, sha, path, top = 10) { +async function getCommits(repo, sha, path, top = 10) { const commitsResponse = await fetch( `https://api.github.com/repos/${repo}/commits?sha=${sha}&path=${path}`, { headers: getHeaders() } @@ -33,7 +34,7 @@ export async function getHistory(repo, sha, path, top = 10) { throw commitsResponse; } const commitsJson = await commitsResponse.json(); - // console.log(commitsJson); + const commits = commitsJson .slice(0, top) .map(commit => ({ @@ -63,6 +64,12 @@ export async function getHistory(repo, sha, path, top = 10) { return commits; } +export function getHistory(repo, sha, path, lang) { + return Promise.all([getCommits(repo, sha, path), loadLanguage(lang)]).then( + ([commits]) => commits + ); +} + export function auth() { return new Promise((resolve, reject) => { var authenticator = new netlify({ @@ -80,3 +87,21 @@ export function auth() { }); }); } + +function loadLanguage(lang) { + if (["js", "css", "html"].includes(lang)) { + return Promise.resolve(); + } + + const deps = getLanguageDependencies(lang); + + let depPromise = import("prismjs"); + + if (deps) { + depPromise = depPromise.then(() => + Promise.all(deps.map(dep => import(`prismjs/components/prism-${dep}`))) + ); + } + + return depPromise.then(() => import(`prismjs/components/prism-${lang}`)); +} diff --git a/src/index.js b/src/index.js index 3274b7f..f657ceb 100755 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,5 @@ import { getHistory, auth, isLoggedIn } from "./github"; -import { getLanguage, getLanguageDependencies } from "./language-detector"; +import { getLanguage } from "./language-detector"; const [repo, sha, path] = getParams(); const lang = getLanguage(path); @@ -14,15 +14,12 @@ if (!repo) { message.innerHTML = `

Loading ${repo} ${path} history...

`; document.title = `GitHub History - ${path.split("/").pop()}`; - Promise.all([ - getHistory(repo, sha, path), - import("./app"), - loadLanguage(lang) - ]) + Promise.all([getHistory(repo, sha, path, lang), import("./app")]) .then(([commits, app]) => { if (!commits.length) { throw new Error("No commits for this file? Maybe the path is wrong"); } + console.log(commits); app.render(commits, root, lang); }) .catch(handleError); @@ -66,24 +63,6 @@ function handleError(error) { } } -function loadLanguage(lang) { - if (["js", "css", "html"].includes(lang)) { - return Promise.resolve(); - } - - const deps = getLanguageDependencies(lang); - - let depPromise = import("prismjs"); - - if (deps) { - depPromise = depPromise.then(() => - Promise.all(deps.map(dep => import(`prismjs/components/prism-${dep}`))) - ); - } - - return depPromise.then(() => import(`prismjs/components/prism-${lang}`)); -} - function getParams() { const [ , From 01596480117e137aba8fb6f28adb7aafad2abd1c Mon Sep 17 00:00:00 2001 From: Rodrigo Pombo Date: Thu, 7 Feb 2019 15:59:18 -0300 Subject: [PATCH 4/6] Refactor --- public/index.html | 10 +-- src/app.js | 153 ++++++++++++++++++++++++++++++++++++++++++++-- src/index.js | 62 ++----------------- 3 files changed, 152 insertions(+), 73 deletions(-) diff --git a/public/index.html b/public/index.html index 5291fba..c6114af 100755 --- a/public/index.html +++ b/public/index.html @@ -45,14 +45,6 @@ height: 100%; } - #message { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100%; - } - footer { position: fixed; right: 10px; @@ -67,7 +59,7 @@ -
+