Skip to content

Commit

Permalink
Add an action indicator for review requests, #2
Browse files Browse the repository at this point in the history
  • Loading branch information
javiertuya committed Feb 21, 2024
1 parent 6403526 commit 75689b6
Show file tree
Hide file tree
Showing 18 changed files with 274 additions and 8 deletions.
12 changes: 10 additions & 2 deletions dashgit-web/app/GitHubAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ const gitHubAdapter = {
for (let assignee of item.assignees)
assignees += assignee.login + " ";
let iidstr = "#" + item.number;
let actions = item.custom_actions == undefined ? {} : item.custom_actions;
m.addItem({
repo_name: repoName, type: type, iid: item.number,
title: item.title,
title: item.title, actions: actions,
author: item.user.login, assignees: assignees, created_at: item.created_at, updated_at: item.updated_at,
iidstr: iidstr, url: item.html_url, repo_url: repoUrl,
labels: []
Expand All @@ -32,6 +33,13 @@ const gitHubAdapter = {
}
return m;
},
addActionToPullRequestItems: function(responseItems, action) {
for (let item of responseItems) {
if (item.custom_actions==undefined) //create if does not exist
item["custom_actions"] = {};
item.custom_actions[action]=true;
}
},

notifications2model: function (response) {
let model = [];
Expand Down Expand Up @@ -101,7 +109,7 @@ const gitHubAdapter = {
m.addItem({
repo_name: repoName, type: type, iid: iid,
branch_name: branch, status: status,
title: title,
title: title, actions: {},
author: "", assignees: "", created_at: createdAt, updated_at: updatedAt,
iidstr: iid != "" ? "#" + iid : "", url: url, branch_url: branchUrl, repo_url: repoUrl,
labels: []
Expand Down
10 changes: 9 additions & 1 deletion dashgit-web/app/GitHubApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ const gitHubApi = {
if (target == "assigned")
promises = [
octokit.rest.search.issuesAndPullRequests({ q: assigned, }),
octokit.rest.search.issuesAndPullRequests({ q: reviewer, }),
//To allow the ui to mark this as a review request, the api call is wrapped to add a special attribute (called custom_actions) to the response
this.wrapIssuesAndPullRequestsCall(octokit, { q: reviewer, }, "review_request"),
];
else if (target == "unassigned")
promises = [
Expand Down Expand Up @@ -64,6 +65,13 @@ const gitHubApi = {
additionalOwners: function (provider, additionalOwners) {
return additionalOwners.length == 0 ? "" : " owner:" + additionalOwners.join(" owner:");
},
wrapIssuesAndPullRequestsCall: async function (octokit, query, action) {
return octokit.rest.search.issuesAndPullRequests(query)
.then(async function (response) {
gitHubAdapter.addActionToPullRequestItems(response.data.items, action);
return response;
})
},

updateNotificationsAsync: function (target, provider) {
if (provider.token == "") //skip if no token provider to avoid api call errors
Expand Down
13 changes: 11 additions & 2 deletions dashgit-web/app/GitLabAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ const gitLabAdapter = {
for (let assignee of item.assignees)
assignees += assignee.username + " ";
let iidstr = (common.isIssue ? "#" : "!") + item.iid;
let actions = item.custom_actions == undefined ? {} : item.custom_actions;
model.addItem({
repo_name: common.repoName, type: (common.isIssue ? "issue" : "pr"), iid: item.iid,
title: item.title,
title: item.title, actions: actions,
author: item.author.username, assignees: assignees, created_at: item.created_at, updated_at: item.updated_at,
iidstr: iidstr, url: item.web_url, repo_url: common.repoUrl,
labels: []
Expand Down Expand Up @@ -60,6 +61,14 @@ const gitLabAdapter = {
}
return common;
},
addActionToToDoResponse: function (response, action) {
for (let item of response) {
if (item.target.custom_actions == undefined) //create if does not exist
item.target["custom_actions"] = {};
item.target.custom_actions[action] = true;
}
return response;
},
getLabelsForItem: function (repoName, item, allLabels, model) {
for (let label of item.labels) {
let color = ""; //default if not found
Expand Down Expand Up @@ -112,7 +121,7 @@ const gitLabAdapter = {
const modelItem = { //anyade un id que no esta en gitlab para poder usar como criterio de seleccion en siguiente query
repo_name: repoName, type: "branch", iid: "",
branch_name: branch, status: "notavailable",
title: "",
title: "", actions: {},
author: "", assignees: "", created_at: "", updated_at: "",
iidstr: "", url: "", branch_url: "", repo_url: repoUrl,
labels: [], gid: proj.id
Expand Down
12 changes: 10 additions & 2 deletions dashgit-web/app/GitLabApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ const gitLabApi = {
if (target == "assigned")
promises = [
api.MergeRequests.all(assigned),
api.MergeRequests.all(reviewer),
api.Issues.all(assigned)
api.Issues.all(assigned),
//Review requests come from the notification generated when assigning the reviewer (this notification will disappear after the reviewer finish).
//To allow the ui to mark this as a review request, the api call is wrapped to add a special attribute (called custom_actions) to the response
this.wrapToDoListsCall(api, { state: "pending", action: "review_requested", type: "MergeRequest" }, "review_request"),
];
else if (target == "unassigned")
promises = [
Expand Down Expand Up @@ -76,6 +78,12 @@ const gitLabApi = {
model.header.message = "<em>On GitLab, this view displays issues/merge requests that you are author, assignee or mentioned, but no comenter.</em>";
return model;
},
wrapToDoListsCall: async function (api, query, action) {
return api.TodoLists.all(query)
.then(async function (response) {
return gitLabAdapter.addActionToToDoResponse(response, action);
})
},

updateNotificationsAsync: async function (target, provider) {
this.log(provider.uid, "ASYNC Get Notifications from the REST api");
Expand Down
6 changes: 5 additions & 1 deletion dashgit-web/app/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ class Model {
addItem(value) {
const uid = this.getModelUid(value.repo_name, value.type, value.iid, value.branch_name);
value.uid = uid; //also stores the uid in the item
value.labels = []
// default values for iterables
if (value.labels == undefined)
value.labels = [];
if (value.actions == undefined)
value.actions = {};
this.items.push(value);
this.#index[uid] = value;
return uid;
Expand Down
2 changes: 2 additions & 0 deletions dashgit-web/app/WiServices.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ const wiServices = {
removeDuplicates: function (items) {
for (let i = items.length - 1; i >= 1; i--) {
if (items[i].uid == items[i - 1].uid) {
// before removing item i, aggregate actions of i into i-1
items[i-1].actions = {...items[i].actions, ...items[i-1].actions};
items.splice(i, 1);
}
}
Expand Down
10 changes: 10 additions & 0 deletions dashgit-web/app/WiView.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ const wiView = {
for (let mod of models) {
this.updateBadges(target, mod.header.uid, true);
$(`#${this.getPanelId(target, mod.header.uid)} .wi-status-icon`).tooltip({ delay: 200 });
$(`#${this.getPanelId(target, mod.header.uid)} .wi-action-badge`).tooltip({ delay: 200 });
}
},

Expand Down Expand Up @@ -133,6 +134,7 @@ const wiView = {
${this.notification2html(header.uid, item.uid)}
</td>
<td>
${this.actions2html(item.actions)}
${grouping ? "" : this.repourl2html(item.repo_url, item.repo_name)}
${this.branch2html(item.branch_url, item.branch_name)}
<span class='${item.type == "branch" ? "fw-normal" : "fw-bold"}'>${this.url2html(item.url, item.title)}</span>
Expand All @@ -144,6 +146,14 @@ const wiView = {
</tr>
`;
},
actions2html: function (actions) {
if (actions == undefined)
return "";
let html = "";
if (actions["review_request"])
html += `<span class="badge text-dark bg-warning wi-action-badge" title="Review requested">review</span> `;
return html;
},

groupValue: function (item, grouping, sorting) {
//grouping=true is to group by project name. If false, groups by date groups (today, week, month, older)
Expand Down
12 changes: 12 additions & 0 deletions dashgit-web/test/TestGitHubAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ describe("TestGitHubAdapter - Model transformations from GitHub API results", fu
assert.deepEqual(expected, actual);
});

//Rest API with actions: Same as before, but calling the method to add the actions and then the transformation
it("Transform GitHub REST API results with actions", function () {
let input = JSON.parse(fs.readFileSync("./input/github-rest-result1.json"));
gitHubAdapter.addActionToPullRequestItems(input, "review_request");
gitHubAdapter.addActionToPullRequestItems(input, "other_action");
let provider = { provider: "GitHub", uid: "0-github", user: "usr1", url: 'https://github.com', api: 'https://api.github.com' };
let actual = gitHubAdapter.workitems2model(provider, input);
fs.writeFileSync("./actual/github-rest-model1-actions.json", JSON.stringify(actual, null, 2)); //to allow extenal diff
let expected = JSON.parse(fs.readFileSync("./expected/github-rest-model1-actions.json"));
assert.deepEqual(expected, actual);
});

// GraphQL API, basic (use a first repo: testrepo)
// - pr open, branch (does not have associatedPullRequests)
// - status success, failure, pending, not available (does not have History)
Expand Down
14 changes: 14 additions & 0 deletions dashgit-web/test/TestGitLabAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ describe("TestGitLabAdapter - Model transformations from GitLab API results", fu
assert.deepEqual(expected, actual);
});

//Rest API with actions: Same as before, but calling the method to add the actions and then the transformation
it("Transform GitHub REST API results with actions", function () {
let labels = { "org2/proj2-BLOCKING": { "color": "#FF0000" } }
let input = JSON.parse(fs.readFileSync("./input/gitlab-rest-result2.json"));
gitLabAdapter.addActionToToDoResponse(input, "review_request");
gitLabAdapter.addActionToToDoResponse(input, "other_action");
let provider = { provider: "GitLab", uid: "0-gitlab", user: "usr1", url: 'https://mygitlab.com' };

let actual = gitLabAdapter.workitems2model(provider, input, labels);
fs.writeFileSync("./actual/gitlab-rest-model2-actions.json", JSON.stringify(actual, null, 2)); //to allow extenal diff
let expected = JSON.parse(fs.readFileSync("./expected/gitlab-rest-model2-actions.json"));
assert.deepEqual(expected, actual);
});

it("Transform Gitlab GraphQL API labels", function () {
let input = JSON.parse(fs.readFileSync("./input/gitlab-rest-labels.json"));
let actual = gitLabAdapter.labels2model(input);
Expand Down
20 changes: 20 additions & 0 deletions dashgit-web/test/TestWiServices.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,26 @@ describe("TestView - Main processing in the view module", function () {
assert.deepEqual(['pr001', 'pr002', 'pr005', 'pr006', 'pr007', 'pr008', 'pr009'], items.map(a => a.title));
});

it("Filter duplicates with actions should aggregate all action values", function () {
// The issue here is that if two equal items are adjacent, but one has actions and other has not,
// the item that is kept could depend on the order. Actions must be aggregated (merged) in all cases
// - the only record with actions is the last, reverse
// - two records with actions (should merge)
let mod = new Model().setHeader("GitHub", "0-github", "", "");
mod.addItem({ repo_name: "repo1", type: "pr", iid: "001", title: "pr001", author: "me" });
mod.addItem({ repo_name: "repo1", type: "pr", iid: "001", title: "pr001", author: "me", actions: { request_review1: true } });
mod.addItem({ repo_name: "repo1", type: "pr", iid: "002", title: "pr002", author: "me", actions: { request_review2: true } });
mod.addItem({ repo_name: "repo1", type: "pr", iid: "002", title: "pr002", author: "me" });
mod.addItem({ repo_name: "repo1", type: "pr", iid: "003", title: "pr003", author: "me" });
mod.addItem({ repo_name: "repo1", type: "pr", iid: "003", title: "pr003", author: "me", actions: { request_review3: true } });
mod.addItem({ repo_name: "repo1", type: "pr", iid: "003", title: "pr003", author: "me", actions: { other_action: true } });
let modStr = JSON.stringify(mod);

let items = wiServices.filterBy("assigned", new Date(), 0, "", JSON.parse(modStr).items);
assert.deepEqual(['pr001', 'pr002', 'pr003'], items.map(a => a.title));
assert.deepEqual([{ request_review1: true }, { request_review2: true }, { request_review3: true, other_action: true }], items.map(a => a.actions));
});

it("Filter dependabot authored only at unassigned target", function () {
//author: dependabot/dependa[bot]/other, pr/issue(no filter), target=unassigned/other(no filter)
let mod = new Model().setHeader("GitHub", "0-github", "", "");
Expand Down
12 changes: 12 additions & 0 deletions dashgit-web/test/expected/github-graphql-model1.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"branch_name": "branch-pr63",
"status": "success",
"title": "test pr assignee",
"actions": {},
"author": "",
"assignees": "",
"created_at": "2024-01-09T19:56:21Z",
Expand All @@ -37,6 +38,7 @@
"branch_name": "branch-pr61",
"status": "failure",
"title": "test pr reviewer, other project",
"actions": {},
"author": "",
"assignees": "",
"created_at": "2024-01-08T12:52:35Z",
Expand All @@ -55,6 +57,7 @@
"branch_name": "branch-pr60",
"status": "pending",
"title": "in progress",
"actions": {},
"author": "",
"assignees": "",
"created_at": "2024-01-08T12:50:35Z",
Expand All @@ -73,6 +76,7 @@
"branch_name": "branch-pr59",
"status": "notavailable",
"title": "no status",
"actions": {},
"author": "",
"assignees": "",
"created_at": "2024-01-08T12:49:35Z",
Expand All @@ -91,6 +95,7 @@
"branch_name": "develop",
"status": "success",
"title": "branch success",
"actions": {},
"author": "",
"assignees": "",
"created_at": "2024-01-08T12:48:35Z",
Expand All @@ -109,6 +114,7 @@
"branch_name": "main",
"status": "notavailable",
"title": "branch no status",
"actions": {},
"author": "",
"assignees": "",
"created_at": "2024-01-08T12:47:35Z",
Expand All @@ -127,6 +133,7 @@
"branch_name": "branch-pr79",
"status": "success",
"title": "pr status closed commit",
"actions": {},
"author": "",
"assignees": "",
"created_at": "2024-01-09T19:50:21Z",
Expand All @@ -145,6 +152,7 @@
"branch_name": "branch-pr78",
"status": "success",
"title": "pr status other commit",
"actions": {},
"author": "",
"assignees": "",
"created_at": "2024-01-09T19:50:21Z",
Expand All @@ -163,6 +171,7 @@
"branch_name": "branch-pr77",
"status": "failure",
"title": "pr check error",
"actions": {},
"author": "",
"assignees": "",
"created_at": "2024-01-09T19:56:21Z",
Expand All @@ -181,6 +190,7 @@
"branch_name": "branch-expected",
"status": "pending",
"title": "branch check expected commit",
"actions": {},
"author": "",
"assignees": "",
"created_at": "2024-01-09T19:50:21Z",
Expand All @@ -199,6 +209,7 @@
"branch_name": "branch-other",
"status": "pending",
"title": "branch check other commit",
"actions": {},
"author": "",
"assignees": "",
"created_at": "2024-01-09T19:50:21Z",
Expand All @@ -217,6 +228,7 @@
"branch_name": "branch-null",
"status": "notavailable",
"title": "branch check null commit",
"actions": {},
"author": "",
"assignees": "",
"created_at": "2024-01-09T19:50:21Z",
Expand Down
Loading

0 comments on commit 75689b6

Please sign in to comment.