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 { LitElement, html, css, customElement, property } from 'lit-element';
import ChangesToolbar from "./ChangesToolbar"
import PullRequestItem from "./PullRequestItem"; import PullRequestItem from "./PullRequestItem";
@customElement('gr-changes-list') @customElement('gr-changes-list')
@@ -9,14 +10,10 @@ export default class ChangesList extends LitElement {
/** Colors and variables **/ /** Colors and variables **/
:host { :host {
--changes-background-color: #e5edf8; --changes-background-color: #e5edf8;
--changes-toolbar-color: #9bbaed;
--changes-toolbar-accent-color: #5a6f90;
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:host { :host {
--changes-background-color: #191d23; --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; 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 { :host .version-changes-empty {
color: var(--g-font-color); color: var(--g-font-color);
display: inline-block; display: inline-block;
@@ -35,50 +46,6 @@ export default class ChangesList extends LitElement {
padding: 14px 12px; padding: 14px 12px;
word-break: break-word; 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: String }) selectedRelease = "";
@property({ type: Boolean, reflect: true }) loading = false; @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(){ render(){
if (this.selectedVersion === "") { if (this.selectedVersion === "") {
return html``; 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` return html`
<div class="version-changes"> <div class="version-changes">
<div class="version-changes-toolbar"> <gr-changes-toolbar
<div class="changes-count"> .pull_count="${this._filtered_pulls.length}"
<strong>${filtered_commits.length}</strong> .commit_count="${this._filtered_commits.length}"
<span class="changes-count-label"> ${(filtered_commits.length === 1 ? "commit": "commits")}</span> .author_count="${this._filtered_authors.length}"
</div> ></gr-changes-toolbar>
<div class="changes-count">
<strong>${filtered_pulls.length}</strong>
<span class="changes-count-label"> ${(filtered_pulls.length === 1 ? "PR": "PRs")}</span>
</div>
</div>
${(filtered_pulls.length === 0 ? html` ${(this._filtered_pulls.length === 0 ? html`
<span class="version-changes-empty">This version contains no new changes.</span> <span class="version-changes-empty">This version contains no new changes.</span>
` : null)} ` : null)}
${filtered_pulls.map((item) => { ${this._filtered_pulls.map((item) => {
let authorIds = []; const pull = item.pull;
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]);
}
});
return html` return html`
<gr-pull-request <gr-pull-request
.id="${item.public_id}" .id="${pull.public_id}"
.title="${item.title}" .title="${pull.title}"
.authors="${authors}" .authors="${item.authors}"
.url="${item.url}" .url="${pull.url}"
.created_at="${item.created_at}" .created_at="${pull.created_at}"
.updated_at="${item.updated_at}" .updated_at="${pull.updated_at}"
.labels="${item.labels}" .labels="${pull.labels}"
/> />
`; `;
})} })}
</div> </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); window.scrollTo(0, 0);
} }
render(){ render() {
// Dereferencing to ensure it triggers an update. // Dereferencing to ensure it triggers an update.
const [...versions] = this._versions; const [...versions] = this._versions;
const [...loadingVersions] = this._loadingVersions; const [...loadingVersions] = this._loadingVersions;