Implement expanding and collapsing of run and result sections
https://imgur.com/a/igkanld
Change-Id: I3fa03f76ced994f98d7af11755f1bcd01d156b1d
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-results.ts b/polygerrit-ui/app/elements/checks/gr-checks-results.ts
index e448374..002c8c3 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-results.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-results.ts
@@ -295,6 +295,8 @@
@property()
runs: CheckRun[] = [];
+ private isSectionExpanded = new Map<Category | 'SUCCESS', boolean>();
+
static get styles() {
return [
sharedStyles,
@@ -312,23 +314,36 @@
margin-top: var(--spacing-l);
margin-left: var(--spacing-l);
text-transform: capitalize;
+ cursor: default;
}
- .categoryHeader iron-icon {
+ .categoryHeader .expandIcon {
+ width: var(--line-height-h3);
+ height: var(--line-height-h3);
+ margin-right: var(--spacing-s);
+ }
+ .categoryHeader .statusIcon {
position: relative;
- top: 1px;
+ top: 2px;
}
- .categoryHeader iron-icon.error {
+ .categoryHeader .statusIcon.error {
color: var(--error-foreground);
}
- .categoryHeader iron-icon.warning {
+ .categoryHeader .statusIcon.warning {
color: var(--warning-foreground);
}
- .categoryHeader iron-icon.info {
+ .categoryHeader .statusIcon.info {
color: var(--info-foreground);
}
- .categoryHeader iron-icon.success {
+ .categoryHeader .statusIcon.success {
color: var(--success-foreground);
}
+ .collapsed table {
+ display: none;
+ }
+ .collapsed {
+ border-bottom: 1px solid var(--border-color);
+ padding-bottom: var(--spacing-m);
+ }
.noCompleted {
margin-top: var(--spacing-l);
}
@@ -354,7 +369,7 @@
${this.renderFilter()} ${this.renderNoCompleted()}
${this.renderSection(Category.ERROR)}
${this.renderSection(Category.WARNING)}
- ${this.renderSection(Category.INFO)} ${this.renderSuccess()}
+ ${this.renderSection(Category.INFO)} ${this.renderSection('SUCCESS')}
`;
}
@@ -384,36 +399,62 @@
return html`<div class="noCompleted">${text}</div>`;
}
- renderSection(category: Category) {
+ renderSection(category: Category | 'SUCCESS') {
const catString = category.toString().toLowerCase();
- const runs = this.runs.filter(r =>
- (r.results ?? []).some(res => res.category === category)
- );
+ let runs = this.runs;
+ if (category === 'SUCCESS') {
+ runs = runs
+ .filter(hasCompletedWithoutResults)
+ .filter(r => this.filterRegExp.test(r.checkName));
+ } else {
+ runs = runs.filter(r =>
+ (r.results ?? []).some(res => res.category === category)
+ );
+ }
if (runs.length === 0) return;
+ const expanded = this.isSectionExpanded.get(category) ?? true;
+ const expandedClass = expanded ? 'expanded' : 'collapsed';
+ const icon = expanded ? 'gr-icons:expand-more' : 'gr-icons:expand-less';
return html`
- <h3 class="categoryHeader heading-3">
- <iron-icon
- icon="gr-icons:${iconForCategory(category)}"
- class="${catString}"
- ></iron-icon>
- ${catString}
- </h3>
- <table class="resultsTable">
- <thead>
- <tr class="headerRow">
- <th class="iconCol"></th>
- <th class="nameCol">Run</th>
- <th class="summaryCol">Summary</th>
- <th class="expanderCol"></th>
- </tr>
- </thead>
- <tbody>
- ${runs.map(run => this.renderRun(category, run))}
- </tbody>
- </table>
+ <div class="${expandedClass}">
+ <h3
+ class="categoryHeader heading-3"
+ @click="${() => this.toggleExpanded(category)}"
+ >
+ <iron-icon class="expandIcon" icon="${icon}"></iron-icon>
+ <iron-icon
+ icon="gr-icons:${iconForCategory(category)}"
+ class="statusIcon ${catString}"
+ ></iron-icon>
+ ${catString}
+ </h3>
+ <table class="resultsTable">
+ <thead>
+ <tr class="headerRow">
+ <th class="iconCol"></th>
+ <th class="nameCol">Run</th>
+ <th class="summaryCol">Summary</th>
+ <th class="expanderCol"></th>
+ </tr>
+ </thead>
+ <tbody>
+ ${runs.map(run =>
+ category === 'SUCCESS'
+ ? this.renderSuccessfulRun(run)
+ : this.renderRun(category, run)
+ )}
+ </tbody>
+ </table>
+ </div>
`;
}
+ toggleExpanded(category: Category | 'SUCCESS') {
+ const expanded = this.isSectionExpanded.get(category) ?? true;
+ this.isSectionExpanded.set(category, !expanded);
+ this.requestUpdate();
+ }
+
renderRun(category: Category, run: CheckRun) {
return html`${run.results
?.filter(result => result.category === category)
@@ -428,31 +469,6 @@
)}`;
}
- renderSuccess() {
- const runs = this.runs
- .filter(hasCompletedWithoutResults)
- .filter(r => this.filterRegExp.test(r.checkName));
- if (runs.length === 0) return;
- return html`
- <h3 class="categoryHeader heading-3">
- <iron-icon
- icon="gr-icons:check-circle-outline"
- class="success"
- ></iron-icon>
- Success
- </h3>
- <table class="resultsTable">
- <tr class="headerRow">
- <th class="iconCol"></th>
- <th class="nameCol">Run</th>
- <th class="summaryCol">Summary</th>
- <th class="expanderCol"></th>
- </tr>
- ${runs.map(run => this.renderSuccessfulRun(run))}
- </table>
- `;
- }
-
renderSuccessfulRun(run: CheckRun) {
const adaptedRun: RunResult = {
category: Category.INFO, // will not be used, but is required
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
index 71ad041..df0a735 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
@@ -238,6 +238,8 @@
private selectedRuns = new Set<string>();
+ private isSectionExpanded = new Map<RunStatus, boolean>();
+
constructor() {
super();
this.subscribe('runs', allRuns$);
@@ -251,9 +253,24 @@
display: block;
padding: var(--spacing-xl);
}
- .statusHeader {
+ .expandIcon {
+ width: var(--line-height-h3);
+ height: var(--line-height-h3);
+ }
+ .sectionHeader {
padding-top: var(--spacing-l);
text-transform: capitalize;
+ cursor: default;
+ }
+ .sectionHeader h3 {
+ display: inline-block;
+ }
+ .collapsed .sectionRuns {
+ display: none;
+ }
+ .collapsed {
+ border-bottom: 1px solid var(--border-color);
+ padding-bottom: var(--spacing-m);
}
input#filterInput {
margin-top: var(--spacing-s);
@@ -344,14 +361,31 @@
.filter(r => this.filterRegExp.test(r.checkName))
.sort(compareByWorstCategory);
if (runs.length === 0) return;
+ const expanded = this.isSectionExpanded.get(status) ?? true;
+ const expandedClass = expanded ? 'expanded' : 'collapsed';
+ const icon = expanded ? 'gr-icons:expand-more' : 'gr-icons:expand-less';
return html`
- <div class="${status.toLowerCase()}">
- <h3 class="statusHeader heading-3">${status.toLowerCase()}</h3>
- ${runs.map(run => this.renderRun(run))}
+ <div class="${status.toLowerCase()} ${expandedClass}">
+ <div
+ class="sectionHeader"
+ @click="${() => this.toggleExpanded(status)}"
+ >
+ <iron-icon class="expandIcon" icon="${icon}"></iron-icon>
+ <h3 class="heading-3">${status.toLowerCase()}</h3>
+ </div>
+ <div class="sectionRuns">
+ ${runs.map(run => this.renderRun(run))}
+ </div>
</div>
`;
}
+ toggleExpanded(status: RunStatus) {
+ const expanded = this.isSectionExpanded.get(status) ?? true;
+ this.isSectionExpanded.set(status, !expanded);
+ this.requestUpdate();
+ }
+
renderRun(run: CheckRun) {
const selected = this.selectedRuns.has(run.checkName);
const deselected = !selected && this.selectedRuns.size > 0;
diff --git a/polygerrit-ui/app/services/checks/checks-util.ts b/polygerrit-ui/app/services/checks/checks-util.ts
index 176464f..1613359 100644
--- a/polygerrit-ui/app/services/checks/checks-util.ts
+++ b/polygerrit-ui/app/services/checks/checks-util.ts
@@ -24,7 +24,7 @@
return undefined;
}
-export function iconForCategory(category: Category) {
+export function iconForCategory(category: Category | 'SUCCESS') {
switch (category) {
case Category.ERROR:
return 'error';
@@ -32,6 +32,8 @@
return 'info-outline';
case Category.WARNING:
return 'warning';
+ case 'SUCCESS':
+ return 'check-circle-outline';
default:
assertNever(category, `Unsupported category: ${category}`);
}
diff --git a/polygerrit-ui/app/styles/themes/app-theme.ts b/polygerrit-ui/app/styles/themes/app-theme.ts
index c3b0681..9d505b9 100644
--- a/polygerrit-ui/app/styles/themes/app-theme.ts
+++ b/polygerrit-ui/app/styles/themes/app-theme.ts
@@ -171,7 +171,7 @@
--line-height-mono: 1.286rem; /* 18px */
--line-height-small: 1.143rem; /* 16px */
--line-height-normal: 1.429rem; /* 20px */
- --line-height-h3: 1.714rem; /* 24px */
+ --line-height-h3: 1.715rem; /* 24px */
--line-height-h2: 2rem; /* 28px */
--line-height-h1: 2.286rem; /* 32px */
--font-weight-normal: 400; /* 400 is the same as 'normal' */