Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
42e69d0
fetch repos
gustavfrid Sep 27, 2021
e30cc5a
added avatar + link to github from avatar
gustavfrid Sep 28, 2021
155507f
added default branch + updated
gustavfrid Sep 28, 2021
7d533cf
change to promise.all
gustavfrid Sep 29, 2021
10affa1
refactor code
gustavfrid Sep 29, 2021
80b4108
refactor, fetch commits from repo the fetch pull based on commiters (…
gustavfrid Sep 29, 2021
0c59818
re structure code
gustavfrid Sep 29, 2021
cc491b8
added pull reqest to list
gustavfrid Sep 30, 2021
f5016bc
added fetch collaborators
gustavfrid Sep 30, 2021
7087828
fetch pull requests based on collaborators
gustavfrid Sep 30, 2021
63f4bda
added collaborator avatar
gustavfrid Sep 30, 2021
dc11da6
draw and update chart check
gustavfrid Sep 30, 2021
c7171a3
chang classes added html comments in js
gustavfrid Sep 30, 2021
8c875cd
remove junk
gustavfrid Sep 30, 2021
84a5d7b
chabge wtyling
gustavfrid Sep 30, 2021
51ab31d
change style
gustavfrid Sep 30, 2021
4ac2be1
change chart labels
gustavfrid Oct 1, 2021
2666991
testing .env
gustavfrid Oct 2, 2021
2f7ae73
created fuction generateProjectCard
gustavfrid Oct 2, 2021
a0066ba
added generate Projectcard
gustavfrid Oct 2, 2021
2a12a47
change styling according to test-auth branch
gustavfrid Oct 2, 2021
6d2869b
changed chart according to test-auth
gustavfrid Oct 2, 2021
449bc49
changed index.html according to test-auth
gustavfrid Oct 2, 2021
450c6a7
limit no of repos to limit api calls
gustavfrid Oct 2, 2021
a1bc269
style user avatar
gustavfrid Oct 2, 2021
ce27f05
Merge branch 'test-auth'
gustavfrid Oct 2, 2021
e8426d1
filter collaborators
gustavfrid Oct 2, 2021
b55a95d
styling + fix commiter collaborator
gustavfrid Oct 2, 2021
a0009b4
added filter
gustavfrid Oct 2, 2021
ec449eb
added promise.all code cleanup
gustavfrid Oct 2, 2021
1ac281f
added filter size + filter buttons
gustavfrid Oct 2, 2021
0c4e9b1
added sort for size and update
gustavfrid Oct 2, 2021
3657850
restructure sort func
gustavfrid Oct 2, 2021
abb6db3
clean up code
gustavfrid Oct 2, 2021
e382e3c
code comments
gustavfrid Oct 2, 2021
c475180
added sort by commits
gustavfrid Oct 2, 2021
0a94a1d
change styling
gustavfrid Oct 3, 2021
6ba2d54
change styling
gustavfrid Oct 3, 2021
1a97996
change styling + added filter btn
gustavfrid Oct 3, 2021
a5a771b
change style add filter by languages
gustavfrid Oct 3, 2021
acf263d
remove consollog
gustavfrid Oct 3, 2021
8b41bda
fix bug in populateCommits
gustavfrid Oct 3, 2021
560f147
remove console log
gustavfrid Oct 3, 2021
ee23f2b
change Readme
gustavfrid Oct 3, 2021
a0a054d
styling for desktop + tablet
gustavfrid Oct 4, 2021
6d1d426
added porfolio to filter repos
gustavfrid Oct 4, 2021
c4c46fb
change styling
gustavfrid Oct 4, 2021
156bb86
remove token from index
gustavfrid Oct 4, 2021
7bcd9ce
fix bug in filter
gustavfrid Oct 4, 2021
67b6080
change indentation
gustavfrid Oct 12, 2021
1bacd98
remove portfolio
gustavfrid Nov 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
# GitHub Tracker

Replace this readme with your own information about your project.

Start by briefly describing the assignment in a sentence or two. Keep it short and to the point.
Week 7 of bootcamp, this is a github tracker tracking projects from the Technigo bootcamp using github api. The site is built mainly using JavaScript, its a heading with the github user avatars and a project list with all repos linked to the Technigo bootcamp. The project card shows some info regarding the status of the project. At the bottom there is a pie chart showing the progress in the bootcamp. The project/repo list os possible to sort and filter.

## The problem

Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next?
The challenge this week was to get the asynchronous nature of fetch to work with multiple fetches within a fetch, for this I used Promise.All. It was also a challenge to get the filters and sort working.

## View it live

Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about.
https://gustav-week7-github-tracker.netlify.app/
47 changes: 47 additions & 0 deletions code/chart.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,50 @@
const ctx = document.getElementById('chart').getContext('2d')

//"Draw" the chart here 👇

const pieData = {
labels: ['Projects to go', 'Projects done'],
datasets: [
{
label: 'Technigo project progress',
data: [19, 0],
backgroundColor: ['RGB(22, 27, 33)', 'RGB(37, 166, 65)'],
borderColor: '#21262c',
hoverOffset: 4,
},
],
}

const pieConfig = {
type: 'doughnut',
data: pieData,
}

const pieChart = new Chart(ctx, pieConfig)

const updatePieChart = (chart, newData) => {
chart.data.datasets.forEach(dataset => {
dataset.data.pop()
dataset.data.push(newData)
})
chart.update()
}

// const lineData = {
// // labels: ['Soon', 'Done'],
// datasets: [
// {
// label: 'Technigo project progress',
// data: [19, 0],
// backgroundColor: ['rgb(255, 99, 132)', 'rgb(255, 205, 86)'],
// hoverOffset: 4,
// },
// ],
// };

// const lineConfig = {
// type: 'line',
// data: lineData,
// };

// let lineChart = (ctx) => new Chart(ctx, lineConfig);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this out commented? :D

56 changes: 39 additions & 17 deletions code/index.html
Original file line number Diff line number Diff line change
@@ -1,21 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Project GitHub Tracker</title>
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<h1>GitHub Tracker</h1>
<h2>Projects:</h2>
<main id="projects"></main>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Project GitHub Tracker</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300;500;700&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="./style.css" />
</head>
<body class="body">
<h1 class="header">GitHub Tracker</h1>
<section class="user-data" id="userData"></section>
<h2 class="project-header">Projects:</h2>
<section class="filters-sorting">
<p class="filters-sorting-heading">Sort by:</p>
<button class="sort-btn" id="sortSizeBtn">size</button>
<button class="sort-btn" id="sortUpdateBtn">last update</button>
<button class="sort-btn" id="sortCreatedBtn">created</button>
<button class="sort-btn" id="sortCommitsBtn">commits</button>
<button class="sort-btn" id="sortNameBtn">name</button>
</section>
<section class="filters-sorting">
<p class="filters-sorting-heading">Filter by:</p>
<button class="sort-btn" id="filterLangJsBtn">JavaScript</button>
<button class="sort-btn" id="filterLangHtmlBtn">HTML</button>
<button class="sort-btn" id="filterAllBtn">All</button>
</section>
<main class="projects" id="projects"></main>

<!-- This will be used to draw the chart 👇 -->
<canvas id="chart"></canvas>
<!-- This will be used to draw the chart 👇 -->
<canvas class="chart" id="chart"></canvas>

<script src="./script.js"></script>
<script src="./chart.js"></script>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="./chart.js"></script>
<script src="./script.js"></script>
</body>
</html>
222 changes: 222 additions & 0 deletions code/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
const projects = document.getElementById('projects')
const userData = document.getElementById('userData')
const sortSizeBtn = document.getElementById('sortSizeBtn')
const sortUpdateBtn = document.getElementById('sortUpdateBtn')
const sortCreatedBtn = document.getElementById('sortCreatedBtn')
const sortCommitsBtn = document.getElementById('sortCommitsBtn')
const sortNameBtn = document.getElementById('sortNameBtn')
const filterAllBtn = document.getElementById('filterAllBtn')
const filterLangJsBtn = document.getElementById('filterLangJsBtn')
const filterLangHtmlBtn = document.getElementById('filterLangHtmlBtn')

const USER = 'gustavfrid'
const PARENT_OWNER = 'Technigo'
const REPOS_URL = `https://api.github.com/users/${USER}/repos`
const USER_URL = `https://api.github.com/users/${USER}`

let reposArr = []
let reposData = {}

const pullReqData = {
total: 19,
done: 0,
}

const fetchAllReposFromUser = () => {
// fetch all repos from user
fetch(REPOS_URL)
.then(res => res.json())
.then(allRepos => {
// filter forked repos
let filteredRepos = allRepos.filter(
repo => repo.name.includes('project-') && repo.fork
// || (repo.name.includes('portfolio') && repo.fork)
)
sortRepos(filteredRepos, 'pushed_at', true)
fetchFullRepo(filteredRepos)
})
.catch(err => alert('fetchAllReposFromUser error: ', err))
}

const fetchFullRepo = repos => {
// fetch all data from each repo
Promise.all(repos.map(repo => fetch(repo.url)))
.then(res => Promise.all(res.map(res => res.json())))
.then(repos => {
repos.forEach(repo => {
if (repo.parent.owner.login === PARENT_OWNER) {
// push data to store for use when sorting projects
reposArr.push(repo)
reposData[repo.name] = { pullRequest: '', authors: '', commits: '' }

generateProjectCard(repo)
const COMMITS_URL = `https://api.github.com/repos/${USER}/${repo.name}/commits?per_page=100`
fetchCommits(COMMITS_URL, repo)
}
})
})
.catch(err => alert('fetchFullRepo error:', err))
}

const generateProjectCard = repo => {
// generating project cards
projects.innerHTML += /*html*/ `
<div class="repo-info">
<div class="repo-heading">
<p class="repo"><a href=${repo.html_url} target="_blank">${repo.name}</a></p>
<p class="lang ${repo.language}">${repo.language}</p>
</div>
<p class="info">From ${repo.parent.owner.login}, default branch: ${repo.default_branch}</p>
<p class="pull" id="pull-${repo.name}">Pull request</p>
<div class="numbers">
<p class="commit" id="commit-${repo.name}">Commits: </p>
<p class="size">Size: ${repo.size}</p>
</div>
<p class="update">Updated: ${new Date(repo.pushed_at).toDateString()}</p>
<p class="collaboration" id="collaborators-${repo.name}">Commit authors:</p>
</div>
`
}

const fetchCommits = (myCommitsUrl, repo) => {
// fetch all commits from repo
fetch(myCommitsUrl)
.then(res => res.json())
.then(data => {
// filter only commits done after repo was forked
const commitsSinceFork = data.filter(commit => commit.commit.author.date > repo.created_at)
// storing necessary data for later sorting
reposData[repo.name].commits = commitsSinceFork
populateCommits(repo, commitsSinceFork)
getCollaborators(commitsSinceFork, repo)
})
.catch(err => alert('fetchCommits error: ', repo.name, err))
}

const populateCommits = (repo, commits) => {
document.getElementById(`commit-${repo.name}`).innerHTML += ` ${commits.length}, `
}

const getCollaborators = (commits, repo) => {
// filter out each commit author and stor for later sort
let authors = {}
commits.forEach(commit => {
if (!Object.keys(authors).includes(commit.author.login)) {
authors[commit.author.login] = {
avatar_url: commit.author.avatar_url,
html_url: commit.author.html_url,
}
}
})
reposData[repo.name].authors = authors
populateCollaborators(authors, repo)
fetchPullRequestsArray(repo, Object.keys(authors))
}

const populateCollaborators = (authors, repo) => {
for (const author in authors) {
if (Object.keys(authors).length > 1) {
document.getElementById(
`collaborators-${repo.name}`
).innerHTML += /*html*/ `<a href="${authors[author].html_url}" target="_blank"><img class="avatar-collaborator" src="${authors[author].avatar_url}"></a>`
} else {
document.getElementById(`collaborators-${repo.name}`).innerHTML =
/*html*/ 'Individual project'
}
}
}

const fetchPullRequestsArray = (repo, authors) => {
// fetch all pull requests from repo
const PULL_URL = `https://api.github.com/repos/${PARENT_OWNER}/${repo.name}/pulls?per_page=100`
fetch(PULL_URL)
.then(res => res.json())
.then(data => {
// only pick pull requests connected to user
const myPullReq = data.find(pull => authors.includes(pull.user.login))
if (myPullReq) {
pullReqData.done++
reposData[repo.name].pullRequest = myPullReq
updatePieChart(pieChart, pullReqData.done)
}
populatePullRequest(myPullReq, repo)
})
.catch(err => alert('fetchPullRequestsArray error:', err))
}

const populatePullRequest = (myPullReq, repo) => {
if (myPullReq) {
document.getElementById(
`pull-${repo.name}`
).innerHTML = /*html*/ `<a href=${myPullReq.html_url} target="_blank">Pull request</a>`
} else {
document.getElementById(`pull-${repo.name}`).innerHTML = /*html*/ 'No pull request done :('
}
}

const fetchUser = () => {
fetch(USER_URL)
.then(res => res.json())
.then(data => {
userData.innerHTML += /*html*/ `<a href="${data.html_url}" target="_blank"><img class="avatar-user" src="${data.avatar_url}"></a><p class="user-name">${data.login}</p>`
})
.catch(err => alert('fetchCommits error: ', err))
}

const sortRepos = (array, param, init) => {
array.sort((a, b) => {
if (a[param] > b[param]) {
return -1
} else if (a[param] < b[param]) {
return 1
} else {
return 0
}
})
if (param === 'name') array.reverse()
if (!init) regenerateProjectCards(reposArr)
}

const sortReposByCommit = (array, param) => {
array.sort((a, b) => {
if (reposData[a[param]].commits > reposData[b[param]].commits) {
return -1
} else if (reposData[a[param]].commits < reposData[b[param]].commits) {
return 1
} else {
return 0
}
})
regenerateProjectCards(reposArr)
}

const filterRepos = (array, lang) => {
if (lang !== 'All') {
const filteredReposArr = array.filter(repo => repo.language === lang)
regenerateProjectCards(filteredReposArr)
} else {
regenerateProjectCards(array)
}
}

const regenerateProjectCards = repos => {
projects.innerHTML = ''
repos.forEach(repo => {
generateProjectCard(repo)
populateCommits(repo, reposData[repo.name].commits)
populateCollaborators(reposData[repo.name].authors, repo)
populatePullRequest(reposData[repo.name].pullRequest, repo)
})
}

sortSizeBtn.addEventListener('click', () => sortRepos(reposArr, 'size', false))
sortUpdateBtn.addEventListener('click', () => sortRepos(reposArr, 'updated_at', false))
sortCreatedBtn.addEventListener('click', () => sortRepos(reposArr, 'created_at', false))
sortCommitsBtn.addEventListener('click', () => sortReposByCommit(reposArr, 'name'))
sortNameBtn.addEventListener('click', () => sortRepos(reposArr, 'name', false))
filterLangJsBtn.addEventListener('click', () => filterRepos(reposArr, 'JavaScript'))
filterLangHtmlBtn.addEventListener('click', () => filterRepos(reposArr, 'HTML'))
filterAllBtn.addEventListener('click', () => filterRepos(reposArr, 'All'))

fetchAllReposFromUser()
fetchUser()
Loading