Extract the toolbar component, improve filtering/counting logic

This commit is contained in:
Yuri Sizov
2023-03-23 14:29:55 +01:00
parent 9c95bf4d7b
commit eee4aaf526
4 changed files with 286 additions and 126 deletions

13
.editorconfig Normal file
View File

@@ -0,0 +1,13 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
[*.{css}]
indent_style = space
indent_size = 2

View File

@@ -1,5 +1,6 @@
import { LitElement, html, css, customElement, property } from 'lit-element';
import ChangesToolbar from "./ChangesToolbar"
import PullRequestItem from "./PullRequestItem";
@customElement('gr-changes-list')
@@ -9,14 +10,10 @@ export default class ChangesList extends LitElement {
/** Colors and variables **/
:host {
--changes-background-color: #e5edf8;
--changes-toolbar-color: #9bbaed;
--changes-toolbar-accent-color: #5a6f90;
}
@media (prefers-color-scheme: dark) {
:host {
--changes-background-color: #191d23;
--changes-toolbar-color: #222c3d;
--changes-toolbar-accent-color: #566783;
}
}
@@ -25,6 +22,20 @@ export default class ChangesList extends LitElement {
flex-grow: 1;
}
:host .version-changes {
background-color: var(--changes-background-color);
border-radius: 0 4px 4px 0;
padding: 8px 12px;
max-width: 760px;
}
@media only screen and (max-width: 900px) {
:host .version-changes {
padding: 8px;
max-width: 95%;
margin: 0px auto;
}
}
:host .version-changes-empty {
color: var(--g-font-color);
display: inline-block;
@@ -35,50 +46,6 @@ export default class ChangesList extends LitElement {
padding: 14px 12px;
word-break: break-word;
}
:host .version-changes {
background-color: var(--changes-background-color);
border-radius: 0 4px 4px 0;
padding: 8px 12px;
max-width: 760px;
}
:host .version-changes-toolbar {
background: var(--changes-toolbar-color);
border-radius: 4px;
display: flex;
flex-direction: row;
gap: 16px;
padding: 10px 14px;
margin-bottom: 6px;
}
:host .changes-count {
font-size: 15px;
}
:host .changes-count strong {
font-size: 18px;
}
:host .changes-count-label {
color: var(--dimmed-font-color);
}
@media only screen and (max-width: 900px) {
:host .version-changes {
padding: 8px;
max-width: 95%;
margin: 0px auto;
}
:host .changes-count {
font-size: 17px;
text-align: center;
width: 100%;
}
:host .changes-count strong {
font-size: 20px;
}
}
`;
}
@@ -92,6 +59,160 @@ export default class ChangesList extends LitElement {
@property({ type: String }) selectedRelease = "";
@property({ type: Boolean, reflect: true }) loading = false;
constructor() {
super();
this._active_log = [];
this._filtered_commits = [];
this._filtered_pulls = [];
this._filtered_authors = [];
}
_updateActiveLog() {
this._active_log = [];
if (this._selectedVersion === "") {
return;
}
// Default to the main log of the version.
this._active_log = this.version.commit_log;
// But if we're in a specific release, find its log.
if (this.selectedRelease !== "") {
for (let release of this.version.releases) {
if (release.name === this.selectedRelease) {
this._active_log = release.commit_log;
break;
}
}
}
}
_updateLists() {
this._filtered_commits = [];
this._filtered_pulls = [];
this._filtered_authors = [];
this._active_log.forEach((commitHash) => {
if (typeof this.commits[commitHash] === "undefined") {
return; // This is not good.
}
const commit = this.commits[commitHash];
let originalCommit = commit;
if (commit.is_cherrypick && typeof this.commits[commit.cherrypick_hash] !== "undefined") {
originalCommit = this.commits[commit.cherrypick_hash];
}
this._appendCommit(commit, originalCommit);
if (originalCommit.pull !== "" && typeof this.pulls[originalCommit.pull] !== "undefined") {
const pull = this.pulls[originalCommit.pull];
this._appendPull(pull);
}
});
}
_appendCommit(commit, originalCommit) {
const filteredCommit = {
"commit": commit,
"original_commit": null,
"authors": [],
};
if (commit !== originalCommit) {
filteredCommit.original_commit = originalCommit;
}
const authorIds = this._findCommitAuthors([ commit, originalCommit ]);
filteredCommit.authors = this._getAuthors(authorIds);
this._filtered_commits.push(filteredCommit);
this._appendAuthors(filteredCommit.authors);
}
_appendPull(pull) {
const existing = this._filtered_pulls.find((item) => {
return item.pull === pull;
});
if (typeof existing !== "undefined") {
return;
}
const filteredPull = {
"pull": pull,
"authors": [],
};
let authorIds = this._findCommitAuthors(pull.commits);
if (authorIds.indexOf(pull.authored_by) < 0) {
authorIds.push(pull.authored_by);
}
filteredPull.authors = this._getAuthors(authorIds);
this._filtered_pulls.push(filteredPull);
this._appendAuthors(filteredPull.authors);
}
_appendAuthors(authors) {
authors.forEach((item) => {
this._appendAuthor(item);
});
}
_appendAuthor(author) {
const existing = this._filtered_authors.find((item) => {
return item.author === author;
});
if (typeof existing === "undefined") {
const filteredAuthor = {
"author": author,
"commits": [],
"pulls": [],
}
this._filtered_authors.push(filteredAuthor);
}
}
_findCommitAuthors(commits) {
let authorIds = [];
commits.forEach((commitHash) => {
if (typeof this.commits[commitHash] === "undefined") {
return;
}
const commit = this.commits[commitHash];
commit.authored_by.forEach((authoredBy) => {
if (authorIds.indexOf(authoredBy) < 0) {
authorIds.push(authoredBy);
}
})
});
return authorIds;
}
_getAuthors(authorIds) {
let authors = [];
authorIds.forEach((authoredBy) => {
if (typeof this.authors[authoredBy] !== "undefined") {
authors.push(this.authors[authoredBy]);
}
});
return authors;
}
update(changedProperties) {
this._updateActiveLog();
this._updateLists();
super.update(changedProperties);
}
render(){
if (this.selectedVersion === "") {
return html``;
@@ -102,94 +223,33 @@ export default class ChangesList extends LitElement {
`
}
let filtered_commits = [];
let filtered_pulls = [];
let commit_log = this.version.commit_log;
if (this.selectedRelease !== "") {
for (let release of this.version.releases) {
if (release.name === this.selectedRelease) {
commit_log = release.commit_log;
break;
}
}
}
commit_log.forEach((commitHash) => {
if (typeof this.commits[commitHash] === "undefined") {
return; // This is not good.
}
let commit = this.commits[commitHash];
filtered_commits.push(commit);
if (commit.is_cherrypick && typeof this.commits[commit.cherrypick_hash] !== "undefined") {
commit = this.commits[commit.cherrypick_hash];
}
if (commit.pull !== "" && typeof this.pulls[commit.pull] !== "undefined") {
const pull = this.pulls[commit.pull];
if (filtered_pulls.indexOf(pull) < 0) {
filtered_pulls.push(this.pulls[commit.pull]);
}
}
});
return html`
<div class="version-changes">
<div class="version-changes-toolbar">
<div class="changes-count">
<strong>${filtered_commits.length}</strong>
<span class="changes-count-label"> ${(filtered_commits.length === 1 ? "commit": "commits")}</span>
</div>
<div class="changes-count">
<strong>${filtered_pulls.length}</strong>
<span class="changes-count-label"> ${(filtered_pulls.length === 1 ? "PR": "PRs")}</span>
</div>
</div>
<gr-changes-toolbar
.pull_count="${this._filtered_pulls.length}"
.commit_count="${this._filtered_commits.length}"
.author_count="${this._filtered_authors.length}"
></gr-changes-toolbar>
${(filtered_pulls.length === 0 ? html`
${(this._filtered_pulls.length === 0 ? html`
<span class="version-changes-empty">This version contains no new changes.</span>
` : null)}
${filtered_pulls.map((item) => {
let authorIds = [];
item.commits.forEach((commitHash) => {
if (typeof this.commits[commitHash] === "undefined") {
return;
}
const commit = this.commits[commitHash];
commit.authored_by.forEach((authoredBy) => {
if (authorIds.indexOf(authoredBy) < 0) {
authorIds.push(authoredBy);
}
})
});
if (authorIds.indexOf(item.authored_by) < 0) {
authorIds.push(item.authored_by);
}
let authors = [];
authorIds.forEach((authoredBy) => {
if (typeof this.authors[authoredBy] !== "undefined") {
authors.push(this.authors[authoredBy]);
}
});
${this._filtered_pulls.map((item) => {
const pull = item.pull;
return html`
<gr-pull-request
.id="${item.public_id}"
.title="${item.title}"
.authors="${authors}"
.url="${item.url}"
.created_at="${item.created_at}"
.updated_at="${item.updated_at}"
.labels="${item.labels}"
.id="${pull.public_id}"
.title="${pull.title}"
.authors="${item.authors}"
.url="${pull.url}"
.created_at="${pull.created_at}"
.updated_at="${pull.updated_at}"
.labels="${pull.labels}"
/>
`;
})}
})}
</div>
`;
}

View File

@@ -0,0 +1,87 @@
import { LitElement, html, css, customElement, property } from 'lit-element';
@customElement('gr-changes-toolbar')
export default class ChangesToolbar extends LitElement {
static get styles() {
return css`
/** Colors and variables **/
:host {
--changes-toolbar-color: #9bbaed;
--changes-toolbar-accent-color: #5a6f90;
}
@media (prefers-color-scheme: dark) {
:host {
--changes-toolbar-color: #222c3d;
--changes-toolbar-accent-color: #566783;
}
}
/** Component styling **/
:host {
}
:host .version-changes-toolbar {
background: var(--changes-toolbar-color);
border-radius: 4px;
display: flex;
flex-direction: row;
gap: 20px;
padding: 10px 14px;
margin-bottom: 6px;
}
:host .changes-count {
display: flex;
flex-direction: row;
gap: 6px;
font-size: 15px;
}
:host .changes-count strong {
font-size: 18px;
}
:host .changes-count-label {
color: var(--dimmed-font-color);
}
@media only screen and (max-width: 900px) {
:host .changes-count {
font-size: 17px;
text-align: center;
width: 100%;
}
:host .changes-count strong {
font-size: 20px;
}
}
`;
}
@property({ type: Number }) pull_count = 0;
@property({ type: Number }) commit_count = 0;
@property({ type: Number }) author_count = 0;
render() {
return html`
<div class="version-changes-toolbar">
<div class="changes-count">
<strong>${this.commit_count}</strong>
<span class="changes-count-label">
${(this.commit_count === 1 ? "commit" : "commits")}
</span>
</div>
<div class="changes-count">
<strong>${this.pull_count}</strong>
<span class="changes-count-label">
${(this.pull_count === 1 ? "pull-request" : "pull-requests")}
</span>
</div>
<div class="changes-count">
<strong>${this.author_count}</strong>
<span class="changes-count-label">
${(this.author_count === 1 ? "contributor" : "contributors")}
</span>
</div>
</div>
`;
}
}

View File

@@ -163,7 +163,7 @@ export default class EntryComponent extends LitElement {
window.scrollTo(0, 0);
}
render(){
render() {
// Dereferencing to ensure it triggers an update.
const [...versions] = this._versions;
const [...loadingVersions] = this._loadingVersions;