diff --git a/app/components/github/contributorslist.js b/app/components/github/contributorslist.js index 8b265985..fc4b18a5 100644 --- a/app/components/github/contributorslist.js +++ b/app/components/github/contributorslist.js @@ -1,6 +1,9 @@ import Image from 'next/image'; -const ContributorsList = ({ contributors }) => { +const ContributorsList = (props) => { + + let contributors = props.data.contributors.Contributors; + return (
{Array.isArray(contributors) && diff --git a/app/components/github/githubissue.js b/app/components/github/githubissue.js deleted file mode 100644 index deb3405f..00000000 --- a/app/components/github/githubissue.js +++ /dev/null @@ -1,46 +0,0 @@ -import { Col, NavLink, Row } from 'react-bootstrap'; -import MDPreview from '../mdpreview'; -import LikeIcon from '../../public/svg/like'; -import CommentIcon from '../../public/svg/comment'; -import IssueIcon from '../../public/svg/issue'; -import styles from '../../styles/GithubIssuesList.module.css'; - -function truncateUpto(str, noOfWords) { - return str.split(' ').splice(0, noOfWords).join(' '); -} - -const GithubIssue = ({ issue }) => { - return ( - - - {issue.title} - - - - - - - {issue.state} - - #{issue.number} - - - - - {issue.reactions['+1']} - - - - - - {issue.comments} - - - - - - - ); -}; - -export default GithubIssue; diff --git a/app/components/github/githubissueslist.js b/app/components/github/githubissueslist.js index cc300f2c..b1bcce51 100644 --- a/app/components/github/githubissueslist.js +++ b/app/components/github/githubissueslist.js @@ -1,25 +1,54 @@ -import { useEffect, useState } from 'react'; +import { Col, NavLink, Row } from 'react-bootstrap'; +import LikeIcon from '../../public/svg/like'; +import CommentIcon from '../../public/svg/comment'; +import IssueIcon from '../../public/svg/issue'; import styles from '../../styles/GithubIssuesList.module.css'; -import GithubIssue from './githubissue'; -const GithubIssuesList = ({ issues, noOfIssues = 6 }) => { - const [data, setData] = useState([]); - - useEffect(() => { - if (Array.isArray(issues)) { - setData(issues.splice(0, noOfIssues)); - } else { - setData(issues); - } - }, [issues]); +const GithubIssue = ({ issue }) => { + return ( + + + {issue.title} + + + + + + + {issue.state} + + #{issue.number} + + + + + {issue.reactions['+1']} + + + + + + {issue.comments} + + + + ); +}; +const GithubIssuesList = (props) => { + const data = + props.data.issues.Issues.length > 10 + ? props.data.issues.Issues.slice(0, 10) + : props.data.issues.Issues; return (
- {Array.isArray(data) ? data.map((issue) => ( - - )):

{issues}, ERROR :(

} + {Array.isArray(data) ? ( + data.map((issue) => ) + ) : ( +

ERROR

+ )}
); }; diff --git a/app/components/github/githubpullreqeusts.js b/app/components/github/githubpullreqeusts.js new file mode 100644 index 00000000..e215d003 --- /dev/null +++ b/app/components/github/githubpullreqeusts.js @@ -0,0 +1,62 @@ +import { Col, NavLink, Row } from "react-bootstrap"; +import styles from "../../styles/GithubPullRequest.module.css"; +import Image from "next/image"; +import PullsIcon from '../../public/svg/pull'; + +const GithubPullReqeust = ({ pull }) => { + return ( + + + + + + + + + + {pull.user.login} + + + + + {pull.title} + + + + + + + {pull.state} + + + #{pull.number} + + + + ); +}; +const GithubPullRequestsList = (props) => { + const data = + props.data.pulls.pulls.length > 6 + ? props.data.pulls.pulls.slice(0, 6) + : props.data.pulls.pulls; + + return ( +
+ {Array.isArray(data) ? ( + data.map((pull) => ) + ) : ( +

ERROR

+ )} +
+ ); +}; + +export default GithubPullRequestsList; diff --git a/app/components/github/githubrepo.js b/app/components/github/githubrepo.js new file mode 100644 index 00000000..2c8c32b6 --- /dev/null +++ b/app/components/github/githubrepo.js @@ -0,0 +1,61 @@ +import { Col, NavLink, Row , Badge } from 'react-bootstrap'; +import IssueIcon from '../../public/svg/issue'; +import StarIcon from '../../public/svg/star'; +import ForkIcon from '../../public/svg/forks'; +import styles from '../../styles/GithubRepo.module.css'; + +const GithubRepo = ({data}) => { + return ( + +
+ + + {data.full_name} + + + + + + + {data.open_issues_count} + + + + + + {data.stargazers_count} + + + + + + {data.forks_count} + + + { + (Array.isArray(data.topics) && (data.topics.length > 0 )) && + ( + + {data.topics.map((topic) => { + return ( + + {topic} + + ) + })} + + ) + } + + + {data.description} + + + +
+ ); +}; + +export default GithubRepo; diff --git a/app/components/github/index.js b/app/components/github/index.js index 4de3a3d5..dcd757dc 100644 --- a/app/components/github/index.js +++ b/app/components/github/index.js @@ -1,3 +1,17 @@ -export { default as ContributorsList } from './contributorslist' -export { default as GithubIssue } from './githubissue' -export { default as GithubIssuesList } from './githubissueslist' +import GithubIssuesList from "./githubissueslist"; +import ContributorsList from "./contributorslist"; +import GithubPullRequestsList from "./githubpullreqeusts"; +import GithubRepo from "./githubrepo"; + +const Github = (props) => { + if(props.type === 'issues'){ + return (); + }else if(props.type === 'pulls'){ + return() + }else if(props.type === 'contributors'){ + return (); + } + return (); +}; + +export default Github; \ No newline at end of file diff --git a/app/components/mdpreview.js b/app/components/mdpreview.js deleted file mode 100644 index bedcd820..00000000 --- a/app/components/mdpreview.js +++ /dev/null @@ -1,12 +0,0 @@ -import { marked } from 'marked'; -import DOMPurify from 'dompurify'; - -export default function MDPreview(props) { - return ( -
- ); -} diff --git a/app/lib/github.js b/app/lib/github.js index dd7d1836..91298bbd 100644 --- a/app/lib/github.js +++ b/app/lib/github.js @@ -1,32 +1,26 @@ -import { fetchAPI } from './api'; +import { fetchAPI } from "./api"; -export const getIssues = async (owner, repo) => { - let issues = [ - { - id: 1, - title: - 'An error occurred, you can still visit our issues clicking this link', - html_url: `https://github.com/${owner}/${repo}/issues`, - reactions: { '+1': 0 }, - comments: 0, - body: '', - state: 'open', - number: 1, - }, - ]; - const res = await fetchAPI('/ghissues'); - console.log(res); - if (Array.isArray(res) && Array.isArray(res[0].Issues)) { - issues = res[0].Issues; +export const githubKitData = async (owner, name, needed) => { + try { + const res = await fetchAPI("/github-repositories"); + let neededRepository = new Object(); + res.forEach((repo) => { + if (repo.owner === owner && repo.name === name) { + neededRepository["id"] = repo.id; + neededRepository["name"] = repo.name; + neededRepository["owner"] = repo.owner; + neededRepository["repositoryData"] = repo.repositoryData; + if(Array.isArray(needed)){ + needed.forEach((neededData) => { + neededRepository[neededData] = repo[neededData]; + }); + }else if(typeof myVariable !== 'undefined'){ + neededRepository[needed] = repo[needed]; + } + } + }); + return neededRepository; + } catch (error) { + console.log(error); } - return issues; -}; - -export const getContributors = async () => { - let contributors = []; - const res = await fetchAPI('/ghcontributors'); - if (Array.isArray(res) && Array.isArray(res[0].Contributors)) { - contributors = res[0].Contributors; - } - return contributors; }; diff --git a/app/pages/github/index.js b/app/pages/github/index.js new file mode 100644 index 00000000..8d219a7c --- /dev/null +++ b/app/pages/github/index.js @@ -0,0 +1,83 @@ +import Head from "next/head"; +import styles from "../../styles/GithubPage.module.css"; +import { Container, Col } from "react-bootstrap"; +import { getNavItems } from "../../lib/navbar"; +import Github from "../../components/github"; +import { githubKitData } from "../../lib/github"; + +export default function GithubComponentKitPage(props) { + return ( +
+ + Github Components Kit + + + + + + +

+ Github Components Kit +

+

+ Showcase your Github Repositories +

+ +
+

+ Repository Overview +

+ +
+ +
+

+ GitHub Issues +

+ +
+ +
+

+ GitHub Pull Requests +

+ +
+ +
+

+ Contributors ✨ +

+ +
+
+
+ ); +} + +export async function getStaticProps({ params }) { + const topNavItems = await getNavItems(); + const githubData = await githubKitData("RocketChat", "RC4Community", [ + "issues", + "pulls", + "contributors", + ]); + + return { + props: { + topNavItems, + githubData, + }, + revalidate: 120, + }; +} diff --git a/app/pages/index.js b/app/pages/index.js index 0a559d44..d9b3c0a3 100644 --- a/app/pages/index.js +++ b/app/pages/index.js @@ -9,8 +9,6 @@ import Growthcounters from '../components/growthcounters'; import { Container, Col } from 'react-bootstrap'; import { fetchAPI } from '../lib/api'; import { withFirebaseAuthUser } from '../components/auth/firebase'; -import { GithubIssuesList, ContributorsList } from '../components/github'; -import { getContributors, getIssues } from '../lib/github'; import { INFOTILES_DATA } from '../lib/const/infotiles'; function Home(props) { @@ -72,20 +70,6 @@ function Home(props) {
- -
-

- GitHub Issues -

- -
- -
-

- Contributors ✨ -

- -
); @@ -99,11 +83,9 @@ export async function getStaticProps({ params }) { const releaseNotes = await fetchAPI('/release-notes'); const topNavItems = await fetchAPI('/top-nav-item'); const topPosts = await fetchAPI('/discourses'); - const issues = await getIssues('RocketChat', 'RC4Community'); - const contributors = await getContributors(); - + return { - props: { carousels, personas, guides, releaseNotes, topNavItems, topPosts, issues, contributors }, + props: { carousels, personas, guides, releaseNotes, topNavItems, topPosts }, // Next.js will attempt to re-generate the page: // - When a request comes in // - At most once every 1 second diff --git a/app/public/svg/forks.js b/app/public/svg/forks.js new file mode 100644 index 00000000..2c3528d5 --- /dev/null +++ b/app/public/svg/forks.js @@ -0,0 +1,35 @@ +export default function forks() { + return ( + + + + + + + + + ); +} \ No newline at end of file diff --git a/app/public/svg/pull.js b/app/public/svg/pull.js new file mode 100644 index 00000000..1b5b3cae --- /dev/null +++ b/app/public/svg/pull.js @@ -0,0 +1,35 @@ +export default function pull() { + return ( + + + + + + + + + ); +} \ No newline at end of file diff --git a/app/public/svg/star.js b/app/public/svg/star.js new file mode 100644 index 00000000..1ae46960 --- /dev/null +++ b/app/public/svg/star.js @@ -0,0 +1,49 @@ +export default function star() { + return ( + + + + + + + + + + + + + + + ); +} + \ No newline at end of file diff --git a/app/styles/GithubPage.module.css b/app/styles/GithubPage.module.css new file mode 100644 index 00000000..2843ae1f --- /dev/null +++ b/app/styles/GithubPage.module.css @@ -0,0 +1,35 @@ +.redText { + color: #f5455c; + } + + .infotiles { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + max-width: 38rem; + } + + .hero_heading { + color: #030c1a; + } + + .hero_subheading { + color: #87898d; + font-size: clamp(16px, 4.5vw, 20px); + } + + .community_news { + background-color: #f7f8fa; + width: 98vw; + overflow: hidden; + } + + .title { + font-size: clamp(22px, 4.6vw, 30px); + } + + .form { + width: 90%; + } + \ No newline at end of file diff --git a/app/styles/GithubPullRequest.module.css b/app/styles/GithubPullRequest.module.css new file mode 100644 index 00000000..beaeeb47 --- /dev/null +++ b/app/styles/GithubPullRequest.module.css @@ -0,0 +1,30 @@ +.container { + max-width: 90rem; + } + .item_container { + width: 80vw; + } + .numbers { + font-size: clamp(8px, 3.6vw, 16px); + } + .column { + background: transparent; + border: 1px solid #dedede; + max-width: 40rem; + } + .md_container { + width: 80vw; + font-size: 0.87rem; + } + @media (min-width: 768px) { + .item_container { + width: clamp(18rem, 36vw, 36rem); + } + .md_container { + width: clamp(18rem, 36vw, 36rem); + } + } + + .username a{ + text-decoration: none; + } \ No newline at end of file diff --git a/app/styles/GithubRepo.module.css b/app/styles/GithubRepo.module.css new file mode 100644 index 00000000..5f6dce39 --- /dev/null +++ b/app/styles/GithubRepo.module.css @@ -0,0 +1,26 @@ +.container { + max-width: 90rem; + } + .item_container { + width: 80vw; + } + .numbers { + font-size: clamp(8px, 3.6vw, 16px); + } + .column { + border: 1px solid #dedede; + max-width: 40rem; + } + .md_container { + width: 80vw; + font-size: 0.87rem; + } + @media (min-width: 768px) { + .item_container { + width: clamp(18rem, 36vw, 36rem); + } + .md_container { + width: clamp(18rem, 36vw, 36rem); + } + } + \ No newline at end of file diff --git a/cms/.gitignore b/cms/.gitignore index 8e339ee3..9dca901b 100644 --- a/cms/.gitignore +++ b/cms/.gitignore @@ -112,3 +112,6 @@ exports *.cache build .strapi-updater.json + +# lock files +package-lock.json diff --git a/cms/api/ghcontributors/models/ghcontributor.settings.json b/cms/api/ghcontributors/models/ghcontributor.settings.json index 9292809f..dad5b6a6 100644 --- a/cms/api/ghcontributors/models/ghcontributor.settings.json +++ b/cms/api/ghcontributors/models/ghcontributor.settings.json @@ -16,6 +16,10 @@ "type": "json", "required": true, "unique": false + }, + "github_repository": { + "via": "contributors", + "model": "github-repositories" } } } diff --git a/cms/api/ghissues/models/ghissue.settings.json b/cms/api/ghissues/models/ghissue.settings.json index b9ab8c66..2ab0bb6b 100644 --- a/cms/api/ghissues/models/ghissue.settings.json +++ b/cms/api/ghissues/models/ghissue.settings.json @@ -16,6 +16,10 @@ "type": "json", "required": true, "unique": false + }, + "github_repository": { + "via": "issues", + "model": "github-repositories" } } } diff --git a/cms/api/ghpulls/config/routes.json b/cms/api/ghpulls/config/routes.json new file mode 100644 index 00000000..331461f5 --- /dev/null +++ b/cms/api/ghpulls/config/routes.json @@ -0,0 +1,52 @@ +{ + "routes": [ + { + "method": "GET", + "path": "/ghpulls", + "handler": "ghpulls.find", + "config": { + "policies": [] + } + }, + { + "method": "GET", + "path": "/ghpulls/count", + "handler": "ghpulls.count", + "config": { + "policies": [] + } + }, + { + "method": "GET", + "path": "/ghpulls/:id", + "handler": "ghpulls.findOne", + "config": { + "policies": [] + } + }, + { + "method": "POST", + "path": "/ghpulls", + "handler": "ghpulls.create", + "config": { + "policies": [] + } + }, + { + "method": "PUT", + "path": "/ghpulls/:id", + "handler": "ghpulls.update", + "config": { + "policies": [] + } + }, + { + "method": "DELETE", + "path": "/ghpulls/:id", + "handler": "ghpulls.delete", + "config": { + "policies": [] + } + } + ] +} diff --git a/cms/api/ghpulls/controllers/ghpulls.js b/cms/api/ghpulls/controllers/ghpulls.js new file mode 100644 index 00000000..e8608953 --- /dev/null +++ b/cms/api/ghpulls/controllers/ghpulls.js @@ -0,0 +1,8 @@ +'use strict'; + +/** + * Read the documentation (https://strapi.io/documentation/developer-docs/latest/development/backend-customization.html#core-controllers) + * to customize this controller + */ + +module.exports = {}; diff --git a/cms/api/ghpulls/models/ghpulls.js b/cms/api/ghpulls/models/ghpulls.js new file mode 100644 index 00000000..0054d33c --- /dev/null +++ b/cms/api/ghpulls/models/ghpulls.js @@ -0,0 +1,8 @@ +'use strict'; + +/** + * Read the documentation (https://strapi.io/documentation/developer-docs/latest/development/backend-customization.html#lifecycle-hooks) + * to customize this model + */ + +module.exports = {}; diff --git a/cms/api/ghpulls/models/ghpulls.settings.json b/cms/api/ghpulls/models/ghpulls.settings.json new file mode 100644 index 00000000..5469018e --- /dev/null +++ b/cms/api/ghpulls/models/ghpulls.settings.json @@ -0,0 +1,22 @@ +{ + "kind": "collectionType", + "collectionName": "ghpulls", + "info": { + "name": "Ghpulls" + }, + "options": { + "increments": true, + "timestamps": true, + "draftAndPublish": true + }, + "pluginOptions": {}, + "attributes": { + "pulls": { + "type": "json" + }, + "github_repository": { + "via": "pulls", + "model": "github-repositories" + } + } +} diff --git a/cms/api/ghpulls/services/ghpulls.js b/cms/api/ghpulls/services/ghpulls.js new file mode 100644 index 00000000..6538a8c8 --- /dev/null +++ b/cms/api/ghpulls/services/ghpulls.js @@ -0,0 +1,8 @@ +'use strict'; + +/** + * Read the documentation (https://strapi.io/documentation/developer-docs/latest/development/backend-customization.html#core-services) + * to customize this service + */ + +module.exports = {}; diff --git a/cms/api/github-repositories/config/routes.json b/cms/api/github-repositories/config/routes.json new file mode 100644 index 00000000..01978a12 --- /dev/null +++ b/cms/api/github-repositories/config/routes.json @@ -0,0 +1,52 @@ +{ + "routes": [ + { + "method": "GET", + "path": "/github-repositories", + "handler": "github-repositories.find", + "config": { + "policies": [] + } + }, + { + "method": "GET", + "path": "/github-repositories/count", + "handler": "github-repositories.count", + "config": { + "policies": [] + } + }, + { + "method": "GET", + "path": "/github-repositories/:id", + "handler": "github-repositories.findOne", + "config": { + "policies": [] + } + }, + { + "method": "POST", + "path": "/github-repositories", + "handler": "github-repositories.create", + "config": { + "policies": [] + } + }, + { + "method": "PUT", + "path": "/github-repositories/:id", + "handler": "github-repositories.update", + "config": { + "policies": [] + } + }, + { + "method": "DELETE", + "path": "/github-repositories/:id", + "handler": "github-repositories.delete", + "config": { + "policies": [] + } + } + ] +} diff --git a/cms/api/github-repositories/controllers/github-repositories.js b/cms/api/github-repositories/controllers/github-repositories.js new file mode 100644 index 00000000..e8608953 --- /dev/null +++ b/cms/api/github-repositories/controllers/github-repositories.js @@ -0,0 +1,8 @@ +'use strict'; + +/** + * Read the documentation (https://strapi.io/documentation/developer-docs/latest/development/backend-customization.html#core-controllers) + * to customize this controller + */ + +module.exports = {}; diff --git a/cms/api/github-repositories/models/github-repositories.js b/cms/api/github-repositories/models/github-repositories.js new file mode 100644 index 00000000..0054d33c --- /dev/null +++ b/cms/api/github-repositories/models/github-repositories.js @@ -0,0 +1,8 @@ +'use strict'; + +/** + * Read the documentation (https://strapi.io/documentation/developer-docs/latest/development/backend-customization.html#lifecycle-hooks) + * to customize this model + */ + +module.exports = {}; diff --git a/cms/api/github-repositories/models/github-repositories.settings.json b/cms/api/github-repositories/models/github-repositories.settings.json new file mode 100644 index 00000000..b9cbd94e --- /dev/null +++ b/cms/api/github-repositories/models/github-repositories.settings.json @@ -0,0 +1,62 @@ +{ + "kind": "collectionType", + "collectionName": "github_repositories", + "info": { + "name": "GithubRepositories", + "description": "" + }, + "options": { + "increments": true, + "timestamps": true, + "draftAndPublish": true + }, + "pluginOptions": {}, + "attributes": { + "owner": { + "type": "string", + "required": true + }, + "name": { + "type": "string", + "required": true + }, + "repositoryData": { + "type": "json" + }, + "unqiueId": { + "type": "string" + }, + "ID": { + "type": "uid", + "targetField": "unqiueId" + }, + "update_repo_data": { + "type": "boolean", + "default": true + }, + "get_issues": { + "type": "boolean", + "default": false + }, + "get_contributors": { + "type": "boolean", + "default": false + }, + "issues": { + "model": "ghissue", + "via": "github_repository" + }, + "contributors": { + "model": "ghcontributor", + "via": "github_repository" + }, + "pulls": { + "model": "ghpulls", + "via": "github_repository" + }, + "get_pulls": { + "type": "boolean", + "default": false + } + } +} diff --git a/cms/api/github-repositories/services/github-repositories.js b/cms/api/github-repositories/services/github-repositories.js new file mode 100644 index 00000000..6538a8c8 --- /dev/null +++ b/cms/api/github-repositories/services/github-repositories.js @@ -0,0 +1,8 @@ +'use strict'; + +/** + * Read the documentation (https://strapi.io/documentation/developer-docs/latest/development/backend-customization.html#core-services) + * to customize this service + */ + +module.exports = {}; diff --git a/cms/config/functions/cron.js b/cms/config/functions/cron.js index 41a97583..96d9b404 100644 --- a/cms/config/functions/cron.js +++ b/cms/config/functions/cron.js @@ -1,7 +1,7 @@ 'use strict'; const { getLatestCommunityActivity } = require("./fetchTopPosts"); const { getCommunityContributors } = require("./fetchContributors") -const { getGithubIssues, getGithubContributors } = require("./github"); +const { githubKit } = require("./github"); /** * Cron config that gives you an opportunity * to run scheduled jobs. @@ -26,8 +26,7 @@ module.exports = { '*/60 * * * * *': () => { getCommunityContributors('https://gsoc.rocket.chat/api/data','rocketChat','Rocket.Chat'); }, - '*/0 0 1 * * *': () => { - getGithubIssues('RocketChat', 'RC4Community'); - getGithubContributors('RocketChat', 'RC4Community'); + '*/* 10 * * * *': () => { + githubKit('RocketChat','RC4Community',['issues','contributors','pulls']); } }; diff --git a/cms/config/functions/fetchData.js b/cms/config/functions/fetchData.js index 35357a1b..b7caeef3 100644 --- a/cms/config/functions/fetchData.js +++ b/cms/config/functions/fetchData.js @@ -6,7 +6,7 @@ const { carousels, subMenus, topNavItem, forms } = require('../initialData'); -const { getGithubIssues, getGithubContributors } = require('./github'); +const { githubKit } = require('./github'); module.exports = async () => { @@ -19,17 +19,12 @@ module.exports = async () => { var releaseNotesCount = await strapi.query("release-notes").count(); var guidesCount = await strapi.query("guides").count(); var formCount = await strapi.query("form").count(); - - var ghissues = await strapi.query("ghissue").count(); - var ghcontributor = await strapi.query("ghcontributor").count(); - + var ghrepos = await strapi.query("github-repositories").count({}); + // initial fetch - if (!ghissues) { - getGithubIssues('RocketChat', 'RC4Community'); - } - - if (!ghcontributor) { - getGithubContributors('RocketChat', 'RC4Community'); + + if (!ghrepos) { + githubKit('RocketChat','RC4Community',['issues','contributors','pulls']); } forms.map(async (form, index) => { diff --git a/cms/config/functions/github.js b/cms/config/functions/github.js index 82fa01b6..b034bce8 100644 --- a/cms/config/functions/github.js +++ b/cms/config/functions/github.js @@ -2,72 +2,300 @@ const { Octokit } = require("@octokit/core"); const octokit = new Octokit(); -const getIssues = async (owner, repo) => { +const getRepoData = async function (parent, repo) { try { - const res = await octokit.request("GET /repos/{owner}/{repo}/issues", { + let returnedData = await octokit.request("GET /repos/{owner}/{repo}", { + owner: parent, + repo: repo, + }); + const { data } = returnedData; + const { + id, + name, owner, - repo, + full_name, + html_url, + description, + stargazers_count, + forks_count, + open_issues_count, + topics, + } = data; + const ownerName = owner.login; + const compactData = { + id, + full_name, + name, + ownerName, + html_url, + description, + stargazers_count, + forks_count, + open_issues_count, + topics, + }; + return { + success: true, + data: compactData, + }; + } catch (err) { + return { + error_message: err, + success: false, + message: "Internal Server Error!", + }; + } +}; + +const getRepoIssues = async function (owner, repo) { + try { + let returnedData = await octokit.request( + "GET /repos/{owner}/{repo}/issues", + { + owner: owner, + repo: repo, + } + ); + let data = returnedData.data; + let issueList = []; + data.forEach((issue) => { + let newIssue = new Object(); + if (typeof issue.pull_request === "undefined") { + newIssue["id"] = issue.id; + let { login, avatar_url, html_url } = issue.user; + newIssue["user"] = { login, avatar_url, html_url }; + newIssue["title"] = issue.title; + newIssue["number"] = issue.number; + newIssue["html_url"] = issue.html_url; + newIssue["reactions"] = issue.reactions; + newIssue["comments"] = issue.comments; + newIssue["body"] = issue.body; + issueList.push(newIssue); + } }); - let issues = []; - if (res.status === 200) { - issues = res.data.filter((issue) => !issue.pull_request); - } - return issues; + return { + success: true, + data: issueList, + }; + } catch (err) { + return { + error_message: err, + success: false, + message: "Internal Server Error!", + }; + } +}; + +const getRepoPulls = async function (owner, repo) { + try { + let returnedData = await octokit.request( + "GET /repos/{owner}/{repo}/pulls", + { + owner: owner, + repo: repo, + } + ); + let data = returnedData.data; + let pullList = []; + data.forEach((pull) => { + let newPull = new Object(); + newPull["id"] = pull.id; + let { login, avatar_url, html_url } = pull.user; + newPull["user"] = { login, avatar_url, html_url }; + newPull["title"] = pull.title; + newPull["number"] = pull.number; + newPull["state"] = pull.state; + newPull["html_url"] = pull.html_url; + pullList.push(newPull); + }); + return { + success: true, + data: pullList, + }; } catch (err) { - return err; + return { + error_message: err, + success: false, + message: "Internal Server Error!", + }; } }; -const getContributors = async (owner, repo) => { +const getRepoContributors = async function (owner, repo) { try { - const res = await octokit.request( + const contributorData = await octokit.request( "GET /repos/{owner}/{repo}/contributors", { - owner, - repo, - per_page: 100, + owner: owner, + repo: repo, } ); - let contributors = []; - if (res.status === 200) { - contributors = res.data; - } - return contributors; + + const data = contributorData.data; + let contributorList = []; + data.forEach((contributor) => { + let newContributor = new Object(); + newContributor["login"] = contributor.login; + newContributor["html_url"] = contributor.html_url; + newContributor["avatar_url"] = contributor.avatar_url; + newContributor["contributions"] = contributor.contributions; + contributorList.push(newContributor); + }); + + return { + success: true, + data: contributorList, + }; } catch (err) { - return err.message; + return { + error_message: err, + success: false, + message: "Internal Server Error!", + }; } }; -module.exports.getGithubIssues = async (owner, repo) => { - const Issues = await getIssues(owner, repo); - let currentIssues = await strapi.query("ghissue").find(); - if (currentIssues.length !== 0) { - await strapi.query("ghissue").update( - { id: currentIssues[0].id }, - { - Issues +module.exports.githubKit = async function (owner, name, needed) { + try { + let getIssues = false; + let getPulls = false; + let getContributors = false; + if (Array.isArray(needed)) { + needed.forEach((need) => { + if (need === "issues") { + getIssues = true; + } else if (need === "pulls") { + getPulls = true; + } else if (need === "contributors") { + getContributors = true; } - ); + }); } else { - await strapi.query("ghissue").create({ - Issues + if (needed === "issues") { + getIssues = true; + } else if (needed === "pulls") { + getPulls = true; + } else if (needed === "contributors") { + getContributors = true; + } + } + + let repoData = await getRepoData(owner, name); + + let githubRepositoryCount = await strapi + .query("github-repositories") + .count({ + owner: owner, + name: name, }); + let githubRepository = await strapi.query("github-repositories").findOne({ + owner: owner, + name: name, + }); + + if (repoData.success) { + if (githubRepositoryCount === 0) { + githubRepository = await strapi.query("github-repositories").create({ + owner: owner, + name: name, + repositoryData: repoData.data, + unqiueId: repoData.data.id, + }); + } else { + githubRepository.repositoryData = repoData.data; + githubRepository.unqiueId = repoData.data.id; + await strapi.query("github-repositories").update( + { + id: githubRepository.id, + }, + githubRepository + ); + } } -}; -module.exports.getGithubContributors = async (owner, repo) => { - const Contributors = await getContributors(owner, repo); - let currentContributors = await strapi.query("ghcontributor").find(); - if (currentContributors.length !== 0) { - await strapi.query("ghcontributor").update( - { id: currentContributors[0].id }, - { - Contributors + if (getIssues) { + const issuesData = await getRepoIssues(owner, name); + + if (issuesData.success) { + const issueCount = await strapi.query("ghissue").count({ + github_repository: githubRepository.id, + }); + if (issueCount === 0) { + let newissueData = await strapi.query("ghissue").create({ + github_repository: githubRepository.id, + Issues: issuesData.data, + }); + issuesId = newissueData.id; + } else { + await strapi.query("ghissue").update( + { + github_repository: githubRepository.id, + }, + { + github_repository: githubRepository.id, + Issues: issuesData.data, + } + ); + } } - ); - } else { - await strapi.query("ghcontributor").create({ - Contributors - }); + } + + if (getPulls) { + const pullData = await getRepoPulls(owner, name); + if (pullData.success) { + const contributorsDataCount = await strapi.query("ghpulls").count({ + github_repository: githubRepository.id, + }); + if (contributorsDataCount === 0) { + let newPullsData = await strapi.query("ghpulls").create({ + github_repository: githubRepository.id, + pulls: pullData.data, + }); + pullsId = newPullsData.id; + } else { + await strapi.query("ghpulls").update( + { + github_repository: githubRepository.id, + }, + { + github_repository: githubRepository.id, + pulls: pullData.data, + } + ); + } + } + } + + if (getContributors) { + const contributorData = await getRepoContributors(owner, name); + if (contributorData.success) { + const contributorsDataCount = await strapi + .query("ghcontributor") + .count({ + github_repository: githubRepository.id, + }); + + if (contributorsDataCount === 0) { + await strapi + .query("ghcontributor") + .create({ + github_repository: githubRepository.id, + Contributors: contributorData.data, + }); + } else { + await strapi.query("ghcontributor").update( + { + github_repository: githubRepository.id, + }, + { + github_repository: githubRepository.id, + Contributors: contributorData.data, + } + ); + } + } + } + } catch (err) { + console.log(err); } -} \ No newline at end of file +}; diff --git a/docs/components/github/README.md b/docs/components/github/README.md index bf89a1e3..490817aa 100644 --- a/docs/components/github/README.md +++ b/docs/components/github/README.md @@ -1,52 +1,233 @@ -# GitHub Components Kit +# GitHub Component Kit -## GitHub Issues Component +The Github Component kit cane be used by communtiy builders to showcase the progress of their projects. The current github component kit can be usedto showcase the following details of a repository : -![gh-issues-rc4_comm](https://user-images.githubusercontent.com/73601258/152670598-3972804c-4493-4fb1-a066-b12ee8ed0d5d.png) +### 1. Repository Overview -## Contributors List Component +

+ overview +

-![rc4_comm_contributors1](https://user-images.githubusercontent.com/73601258/152670586-1ec2b0cd-d51c-4bc4-97f3-3717bbcce162.png) -## Steps to setup your own GitHub Components: +### 2. Issues -### CMS +

+ crons-example +

-1. We need to add cron jobs to handle the fetch requests to GitHub, as frequent fetch request will forbid the IP address to fetch data. You can find `cron.js` file under `cms/config/functions` folder. - This example means after each 1 hour we will re-fetch and update our data. - ![cms1](https://user-images.githubusercontent.com/73601258/152671447-aeebd701-5ae7-4da8-91c0-2a97cf62ce36.png) -2. These functions exist at `github.js` file under the same functions directory. If you will check, you need to provide `owner` and `repo` to get data. Simply, owner = organisation or the user and repo = repository. -3. Just one more change and we are good to go! As the cron job will populate and re-populate data after 1 hour interval. We can't just wait for the first one hour to work with the data right? So we need an initial fetch! -4. Go to `fetchData.js` file which is also in the same functions directory and change the `owner` and `repo` here so that when we first call `INITIALIZE_DATA=true npm run develop` it will call these functions and populate the data for us! - ![initfetch-gh](https://user-images.githubusercontent.com/73601258/152671919-8a7656f9-1445-47fe-a8f4-e3e88bc0ffcf.png) +### 3. Contributors -### Frontend +

+ crons-example +

+ +### 4. Pull Requests -1. All the GitHub Components reside in the `app/components/github` folder. You can just pull any one of them and use however you like. -2. There are helper functions in `lib/github.js` file, so that you don't worry much about setting up things or handling errors and focus on instant results. -3. Now that you know where stuffs exist, let's get started: -4. While using `getStaticProps` you can fetch data through the helper functions we talked about in _point 2_. So in any page you wish to render them you just need to, +

+ crons-example +

-```javascript -export async function getStaticProps({ params }) { - ... - // owner is (organisation/user), repo is (repository) - const issues = await getIssues('RocketChat', 'RC4Community'); - const contributors = await getContributors(); - return { - props: { issues, contributors } - } + + +All the componets use the same `` tag and the same data fetchig library with additional paramters. + +## Github Tag Props + +We use our helper function `githubKitData(repoName,ownerName,[... needs]);` to fetch the data for the component. The returned object can be directly passed to the component and it will render data based on the passed paramters + +| Prop Name | Description | Type | +| ------------- |------------------------- | -----| +| type | This specifies the `type` of github kit components we wish to use. If `type` is not specified, by default the `repository overview` component is rendered. Type can be set to : `issues` , `pulls` or `contributors` | string | +| githubData | This will contain the data which will be rendered by the component | json | + +# Usage Examples + +## #Example 1 : Using GitHub Repository Overview , Issues, Contributors and Pull Request all at once. + +### Using the component + +``` +import Head from "next/head"; +import { Github } from '../components/github'; +import { githubKitData } from '../lib/github'; + +export default function Leaderboardpage(props){ + return ( +
+ + GSOC2022 LeaderBoard + +
+

+ Repository Overview +

+ +
+
+

+ GitHub Issues +

+ +
+ +
+

+ GitHub Pull Requests +

+ +
+ +
+

+ Contributors ✨ +

+ +
+
+ ); +} + +export async function getStaticProps(){ + + const githubData = await githubKitData('RocketChat','RC4Community',['issues','pulls','contributors']); + const topNavItems = await fetchAPI("/top-nav-item"); + + return { + props: { + leaderboardProps, + githubData + }, + revalidate: 30, + }; } ``` -5. Now use them like any react component (make sure to import them), +### Setting up component data in CMS + +1. Open the your cron.js ( This can be located in the following path : `RC4Community/cms/config/functions/cron.js` ). +2. We need to add cron jobs to handle the fetch requests to GitHub, as frequent fetch request will forbid the IP address to fetch data. + This example means after each 60 seconds we will re-fetch and update our data. + + ![image](https://user-images.githubusercontent.com/70485812/158072721-744b2475-7310-46f2-a3de-0f166bf72324.png) + +3. The `githubKit()` function takes three arguments: + 1. The github user name of the owner of the repostory. + 2. Name of the repository. + 3. The components we wish to use, as it fetches data accordigly. This will be an array of strinng and can take a combinationof values : `issues`, `contributors`,`pulls` depending on our usecase. + +4. Just one more change and we are good to go! As the cron job will populate and re-populate data after some time interval. We can't just wait for the first one hour to work with the data right? So we need an initial fetch! + +5. Go to `fetchData.js` file which is also in the same functions directory and change the `owner` and `repo` here so that when we first call `INITIALIZE_DATA=true npm run develop` it will call these functions and populate the data for us! + +![image](https://user-images.githubusercontent.com/70485812/158073123-6c637835-fc06-46f8-a279-af7003002ae6.png) + +## #Example 2 : Using Contributors and PullRequest components for the Rocket.Chat repository of RocketChat. + +### Using the component -```jsx - -or - ``` +import Head from "next/head"; +import { Github } from '../components/github'; +import { githubKitData } from '../lib/github'; + +export default function Leaderboardpage(props){ + return ( +
+ + GSOC2022 LeaderBoard + +
+

+ GitHub Pull Requests +

+ +
+ +
+

+ Contributors ✨ +

+ +
+
+ ); +} + +export async function getStaticProps(){ + + const githubData = await githubKitData('RocketChat','RC4Community',['contributors','pulls']); + const topNavItems = await fetchAPI("/top-nav-item"); + + return { + props: { + leaderboardProps, + githubData + }, + revalidate: 30, + }; +} +``` + +### Setting up component data in CMS + + +1. Cron Jobs ![image](https://user-images.githubusercontent.com/70485812/158073275-873f47dc-02ff-4998-83e9-71b5b83ff7b4.png) + +2. Initial Fetch ![image](https://user-images.githubusercontent.com/70485812/158073303-054200ed-a6c9-4f15-b527-9e35ba2ac314.png) + + +## #Example 3 : Using Repository Overview Component only. + +Note : the repository overview component can be used by default. We don not need to specify any `type` in Github component or add anything to `needed` in `githubKitData` +or in `githubKit` in the cron job. + +### Using the component + +``` +import Head from "next/head"; +import { Github } from '../components/github'; +import { githubKitData } from '../lib/github'; + +export default function Leaderboardpage(props){ + return ( +
+ + GSOC2022 LeaderBoard + +
+

+ Repository Overview +

+ +
+
+ ); +} + +export async function getStaticProps(){ + + const githubData = await githubKitData('RocketChat','RC4Community'); + const topNavItems = await fetchAPI("/top-nav-item"); + + return { + props: { + leaderboardProps, + githubData + }, + revalidate: 30, + }; +} +``` + +### Setting up component data in CMS + + +1. Cron Jobs ![image](https://user-images.githubusercontent.com/70485812/158336100-165bd60b-2528-47cb-a999-321ddbe325c3.png) + +2. Initial Fetch ![image](https://user-images.githubusercontent.com/70485812/158336345-fd2cfde2-f435-4fd7-92c4-c52a54fc0789.png) + + + ---- -### :arrow_left: Explore More Components +### :arrow_left: Explore More Components \ No newline at end of file