Skip to content

Commit

Permalink
add endpoint to list substantive and non-substantive contributors in …
Browse files Browse the repository at this point in the history
…a given repository
  • Loading branch information
deniak committed Nov 15, 2024
1 parent 34742fa commit e8818a4
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 37 deletions.
2 changes: 2 additions & 0 deletions app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import LoginWelcome from "./application/login.jsx";
import LogoutButton from "./application/logout-button.jsx";
import RepoManager from "./application/repo-manager.jsx";
import RepoList from "./application/repo-list.jsx";
import ContributorsList from "./application/contributors-list.jsx";
import AdminUsers from "./application/admin/users.jsx";
import AdminGroups from "./application/admin/groups.jsx";
import EditUser from "./application/admin/edit-user.jsx";
Expand Down Expand Up @@ -142,6 +143,7 @@ ReactDOM.render(
<Route path="repo/:owner/:shortname/:mode" component={RepoManager}/>
<Route path="repo/:mode" component={RepoManager}/>
<Route path="repos" component={RepoList} public="true"/>
<Route path="repos/:owner/:shortName/contributors" component={ContributorsList} public="true"/>
<Route path="pr/id/:owner/:shortName/:num" component={PRViewer} public="true"/>
<Route path="pr/open" component={PROpen} public="true"/>
<Route path="pr/last-week" component={PRLastWeek} public="true"/>
Expand Down
158 changes: 158 additions & 0 deletions application/contributors-list.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@

import React from "react";
import Spinner from "../components/spinner.jsx";

require("isomorphic-fetch");
let utils = require("./utils")
, pp = utils.pathPrefix()
;

export default class ContributorsList extends React.Component {
constructor (props) {
super(props);
this.state = {
status: "loading"
, owner: null
, shortName: null
, substantiveContributors: []
, nonSubstantiveContributors: []
};
}
componentDidMount () {
let owner = this.props.params.owner
, shortName = this.props.params.shortName;
fetch(pp + `api/repos/${owner}/${shortName}/contributors`, { credentials: "include" })
.then(utils.jsonHandler)
.then((data) => {
this.setState({
substantiveContributors: data.substantiveContributors
, nonSubstantiveContributors: data.nonSubstantiveContributors
, owner: owner
, shortName: shortName
, status: "ready"
});
})
.catch(utils.catchHandler)
;
}

render () {
let st = this.state
, content
, repositoryLink = ""
, substantiveKeys
, nonSubstantiveKeys
;
if (st.status === "loading") {
content = <Spinner prefix={pp}/>;
}
else if (st.status === "ready") {
repositoryLink = <a href={`https://github.com/${st.owner}/${st.shortName}`}>{`${st.owner}/${st.shortName}`}</a>;
substantiveKeys = Object.keys(st.substantiveContributors);
nonSubstantiveKeys = Object.keys(st.nonSubstantiveContributors);
content = (
<div>
{[substantiveKeys, nonSubstantiveKeys].map((type) => {
if (type.length > 0) {
return (
<div>
<h3>{type === substantiveKeys ? "Substantive" : "Non-substantive"} contributions</h3>
<table className={`${type}-contributors-list`}>
<thead>
<tr>
<th>Contributor</th>
<th>PR</th>
</tr>
</thead>
<tbody>
{
type.map((i) => {
return <tr key={(type === substantiveKeys ? st.substantiveContributors : st.nonSubstantiveContributors)[i].name}>
<td>{(type === substantiveKeys ? st.substantiveContributors : st.nonSubstantiveContributors)[i].name}</td>
<td>
<ul>
{(type === substantiveKeys ? st.substantiveContributors : st.nonSubstantiveContributors)[i].prs.map((pr) => {
return <li key={pr}><a href={`${pp}pr/id/${st.owner}/${st.shortName}/${pr}`}>PR #{pr}</a></li>
})}
</ul>
</td>
</tr>
})
}
</tbody>
</table>
</div>
);
}
}
)}
</div>
// {substantiveKeys.length > 0 && (
// <div>
// <h3>Substantive contributions</h3>
// <table className="substantive-contributors-list">
// <thead>
// <tr>
// <th>Contributor</th>
// <th>PR</th>
// </tr>
// </thead>
// <tbody>
// {
// substantiveKeys.map((i) => {
// return <tr key={st.substantiveContributors[i].name}>
// <td>{st.substantiveContributors[i].name}</td>
// <td>
// <ul>
// {st.substantiveContributors[i].prs.map((pr) => {
// return <li key={pr}><a href={`${pp}pr/id/${st.owner}/${st.shortName}/${pr}`}>PR #{pr}</a></li>
// })}
// </ul>
// </td>
// </tr>
// })
// }
// </tbody>
// </table>
// </div>
// )}
// {nonSubstantiveKeys.length > 0 && (
// <div>
// <h3>Non-substantive contributions</h3>
// <table className="non-substantive-contributors-list">
// <thead>
// <tr>
// <th>Contributor</th>
// <th>PR</th>
// </tr>
// </thead>
// <tbody>
// {
// nonSubstantiveKeys.map((i) => {
// return <tr key={st.nonSubstantiveContributors[i].name}>
// <td>{st.nonSubstantiveContributors[i].name}</td>
// <td>
// <ul>
// {st.nonSubstantiveContributors[i].prs.map((pr) => {
// return <li key={pr}><a href={`${pp}pr/id/${st.owner}/${st.shortName}/${pr}`}>PR #{pr}</a></li>
// })}
// </ul>
// </td>
// </tr>
// })
// }
// </tbody>
// </table>
// </div>
// )}
// </div>
// );
)}

return <div className="primary-app">
<h2>List of contributors on {repositoryLink}</h2>
{content}
</div>
;
}
}
2 changes: 2 additions & 0 deletions application/repo-list.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export default class RepoList extends React.Component {
<tr>
<th>Full name</th>
<th>Groups</th>
<th>Contributors list</th>
</tr>
</thead>
{
Expand All @@ -49,6 +50,7 @@ export default class RepoList extends React.Component {
return <tr key={r.id} style={{paddingLeft: "20px"}}>
<td><a href={`https://github.com/${r.fullName}`} target="_blank">{r.fullName}</a></td>
<td>{r.groups.map((g) => { return g.name; }).join(", ")}</td>
<td><a href={`repos/${r.fullName}/contributors`}>Contributors</a></td>
{admin}
</tr>
;
Expand Down
27 changes: 15 additions & 12 deletions public/js/app.js

Large diffs are not rendered by default.

51 changes: 26 additions & 25 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -660,33 +660,33 @@ router.get("/api/repos", function (req, res) {
});
});

// list substantive contributors to a repo
// list contributors to a repo
router.get("/api/repos/:owner/:shortName/contributors", function (req, res) {
res.setHeader("Access-Control-Allow-Origin", "*");
const prms = req.params;
store.getPRsByRepo(prms.owner + "/" + prms.shortName, function (err, docs) {
if (err) return error(res, err);
const substantiveContributors = {};
const nonSubstantiveContributors = {};
docs.forEach(function (doc) {
if (doc.markedAsNonSubstantiveBy) {
for (const contributor of doc.contributors) {
if (!nonSubstantiveContributors[contributor]) {
nonSubstantiveContributors[contributor] = { prs: []};
}
nonSubstantiveContributors[contributor].prs.push(doc.num);
}
} else {
for (const affiliationId in doc.affiliations) {
if (!substantiveContributors[affiliationId]) {
substantiveContributors[affiliationId] = { name: doc.affiliations[affiliationId], prs: []};
}
substantiveContributors[affiliationId].prs.push(doc.num);
}
}
res.setHeader("Access-Control-Allow-Origin", "*");
const prms = req.params;
store.getPRsByRepo(prms.owner + "/" + prms.shortName, function (err, docs) {
if (err) return error(res, err);
const substantiveContributors = {};
const nonSubstantiveContributors = {};
docs.forEach(function (doc) {
if (doc.markedAsNonSubstantiveBy) {
for (const contributor of doc.contributors) {
if (!nonSubstantiveContributors[contributor]) {
nonSubstantiveContributors[contributor] = { name: contributor, prs: []};
}
nonSubstantiveContributors[contributor].prs.push(doc.num);
}
} else {
for (const affiliationId in doc.affiliations) {
if (!substantiveContributors[affiliationId]) {
substantiveContributors[affiliationId] = { name: doc.affiliations[affiliationId], prs: []};
}
substantiveContributors[affiliationId].prs.push(doc.num);
}
}
});
res.json({substantiveContributors, nonSubstantiveContributors});
});
res.json({substantiveContributors, nonSubstantiveContributors});
});
});


Expand Down Expand Up @@ -747,6 +747,7 @@ function addClientSideRoutes(app) {
app.get("/login", showIndex);
app.get("/repo/*", showIndex);
app.get("/repos", showIndex);
app.get("/repos/*", showIndex);
app.get("/admin/*", ensureAdmin, showIndex);
app.get("/pr/*", showIndex);
}
Expand Down

0 comments on commit e8818a4

Please sign in to comment.