github.com/GoogleCloudPlatform/testgrid@v0.0.174/web/src/testgrid-group-summary.ts (about) 1 import { LitElement, html, css } from 'lit'; 2 import { customElement, property, state } from 'lit/decorators.js'; 3 import { ListDashboardSummariesResponse } from './gen/pb/api/v1/data'; 4 import { DashboardSummary } from './gen/pb/api/v1/data'; 5 import { map } from 'lit/directives/map.js'; 6 import { TabStatusIcon } from './testgrid-dashboard-summary'; 7 8 /** 9 * RenderedDashboardSummary defines the dashboard summary representation required for rendering 10 */ 11 interface RenderedDashboardSummary { 12 name: string; 13 overallStatus: string; 14 icon: string; 15 tabDescription: string; 16 } 17 18 @customElement('testgrid-group-summary') 19 export class TestgridGroupSummary extends LitElement { 20 21 @property({ type: String }) 22 groupName = ''; 23 24 @state() 25 dashboardSummaries: RenderedDashboardSummary[] = []; 26 27 render() { 28 return html` 29 <link 30 rel="stylesheet" 31 href="https://fonts.googleapis.com/icon?family=Material+Icons" 32 /> 33 <table> 34 <thead> 35 <tr> 36 <th>Status</th> 37 <th>Dashboard</th> 38 <th>Health</th> 39 </tr> 40 </thead> 41 <tbody> 42 ${map(this.dashboardSummaries, 43 (ds: RenderedDashboardSummary) => html` 44 <tr> 45 <td><i class="material-icons ${ds.overallStatus}">${ds.icon}</i></td> 46 <td>${ds.name}</td> 47 <td>${ds.tabDescription}</td> 48 </tr> 49 `)} 50 </tbody> 51 </table> 52 `; 53 } 54 55 connectedCallback() { 56 super.connectedCallback(); 57 this.fetchDashboardSummaries(); 58 } 59 60 private async fetchDashboardSummaries() { 61 try { 62 const response = await fetch( 63 `http://${process.env.API_HOST}:${process.env.API_PORT}/api/v1/dashboard-groups/${this.groupName}/dashboard-summaries` 64 ); 65 if (!response.ok) { 66 throw new Error(`HTTP error: ${response.status}`); 67 } 68 const data = ListDashboardSummariesResponse.fromJson(await response.json()); 69 var summaries: RenderedDashboardSummary[] = []; 70 data.dashboardSummaries.forEach(summary => summaries.push(this.convertResponse(summary))); 71 this.dashboardSummaries = summaries; 72 } catch (error) { 73 console.error(`Could not get grid rows: ${error}`); 74 } 75 } 76 77 private convertResponse(summary: DashboardSummary){ 78 const sortedStatuses: string[] = [ 79 "PASSING", 80 "ACCEPTABLE", 81 "FLAKY", 82 "FAILING", 83 "STALE", 84 "BROKEN", 85 "PENDING" 86 ] 87 88 var numPassing = 0; 89 var total = 0; 90 for (const key in summary.tabStatusCount){ 91 if (key === "PASSING"){ 92 numPassing = summary.tabStatusCount[key]; 93 } 94 total += summary.tabStatusCount[key]; 95 } 96 97 var prefix = `${numPassing} / ${total} PASSING`; 98 var descriptions: string [] = []; 99 sortedStatuses.forEach(status => { 100 if (summary.tabStatusCount[status] > 0){ 101 descriptions.push(`${summary.tabStatusCount[status]} ${status}`); 102 } 103 }); 104 105 if (descriptions.length >0){ 106 prefix += " ("+ descriptions.join(", ") +")"; 107 } 108 109 const rds: RenderedDashboardSummary = { 110 name: summary.name, 111 overallStatus: summary.overallStatus, 112 icon: TabStatusIcon.get(summary.overallStatus)!, 113 tabDescription: prefix 114 }; 115 116 return rds; 117 } 118 119 static styles = css` 120 121 body{ 122 font-size: 12px; 123 } 124 125 .material-icons{ 126 font-size: 2em; 127 } 128 129 th, td { 130 padding: 0.5em 2em; 131 } 132 133 thead{ 134 background-color: #e0e0e0; 135 } 136 137 table { 138 border-radius: 6px; 139 border: 1px solid #cbcbcb; 140 border-spacing: 0; 141 } 142 143 .PENDING { 144 color: #cc8200; 145 } 146 147 .PASSING { 148 color: #0c3; 149 } 150 151 .FAILING { 152 color: #a00; 153 } 154 155 .FLAKY { 156 color: #609; 157 } 158 159 .ACCEPTABLE { 160 color: #39a2ae; 161 } 162 163 .STALE { 164 color: #808b96; 165 } 166 167 .BROKEN { 168 color: #000; 169 } 170 `; 171 }