-
Notifications
You must be signed in to change notification settings - Fork 130
Gustav Frid #45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Gustav Frid #45
Changes from all commits
Commits
Show all changes
51 commits
Select commit
Hold shift + click to select a range
42e69d0
fetch repos
gustavfrid e30cc5a
added avatar + link to github from avatar
gustavfrid 155507f
added default branch + updated
gustavfrid 7d533cf
change to promise.all
gustavfrid 10affa1
refactor code
gustavfrid 80b4108
refactor, fetch commits from repo the fetch pull based on commiters (…
gustavfrid 0c59818
re structure code
gustavfrid cc491b8
added pull reqest to list
gustavfrid f5016bc
added fetch collaborators
gustavfrid 7087828
fetch pull requests based on collaborators
gustavfrid 63f4bda
added collaborator avatar
gustavfrid dc11da6
draw and update chart check
gustavfrid c7171a3
chang classes added html comments in js
gustavfrid 8c875cd
remove junk
gustavfrid 84a5d7b
chabge wtyling
gustavfrid 51ab31d
change style
gustavfrid 4ac2be1
change chart labels
gustavfrid 2666991
testing .env
gustavfrid 2f7ae73
created fuction generateProjectCard
gustavfrid a0066ba
added generate Projectcard
gustavfrid 2a12a47
change styling according to test-auth branch
gustavfrid 6d2869b
changed chart according to test-auth
gustavfrid 449bc49
changed index.html according to test-auth
gustavfrid 450c6a7
limit no of repos to limit api calls
gustavfrid a1bc269
style user avatar
gustavfrid ce27f05
Merge branch 'test-auth'
gustavfrid e8426d1
filter collaborators
gustavfrid b55a95d
styling + fix commiter collaborator
gustavfrid a0009b4
added filter
gustavfrid ec449eb
added promise.all code cleanup
gustavfrid 1ac281f
added filter size + filter buttons
gustavfrid 0c4e9b1
added sort for size and update
gustavfrid 3657850
restructure sort func
gustavfrid abb6db3
clean up code
gustavfrid e382e3c
code comments
gustavfrid c475180
added sort by commits
gustavfrid 0a94a1d
change styling
gustavfrid 6ba2d54
change styling
gustavfrid 1a97996
change styling + added filter btn
gustavfrid a5a771b
change style add filter by languages
gustavfrid acf263d
remove consollog
gustavfrid 8b41bda
fix bug in populateCommits
gustavfrid 560f147
remove console log
gustavfrid ee23f2b
change Readme
gustavfrid a0a054d
styling for desktop + tablet
gustavfrid 6d1d426
added porfolio to filter repos
gustavfrid c4c46fb
change styling
gustavfrid 156bb86
remove token from index
gustavfrid 7bcd9ce
fix bug in filter
gustavfrid 67b6080
change indentation
gustavfrid 1bacd98
remove portfolio
gustavfrid File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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