github.com/GoogleCloudPlatform/testgrid@v0.0.174/web/src/testgrid-index.ts (about) 1 import { LitElement, html, css } from 'lit'; 2 // eslint-disable-next-line @typescript-eslint/no-unused-vars 3 import { customElement, property } from 'lit/decorators.js'; 4 import { map } from 'lit/directives/map.js'; 5 import { ListDashboardsResponse, ListDashboardGroupsResponse } from './gen/pb/api/v1/data.js'; 6 import { navigate } from './utils/navigation'; 7 import '@material/mwc-button'; 8 import '@material/mwc-list'; 9 10 11 // dashboards template 12 // clicking on any dashboard should navigate to the /dashboards view 13 const dashboardTemplate = (dashboards: Array<string>) => html` 14 <div> 15 <mwc-list activatable style="min-width: 755px"> 16 ${map( 17 dashboards, 18 (dash: string, index: number) => html` 19 <mwc-list-item id=${index} @click=${() => navigate(dash)} class="column card dashboard"> 20 <div class="container"> 21 <p>${dash}</p> 22 </div> 23 </a> 24 </mwc-list-item> 25 ` 26 )} 27 </mwc-list> 28 </div> 29 `; 30 31 /** 32 * Class definition for the `testgrid-index` element. 33 * Renders the list of dashboards and dashboard groups available. 34 */ 35 @customElement('testgrid-index') 36 // eslint-disable-next-line @typescript-eslint/no-unused-vars 37 export class TestgridIndex extends LitElement { 38 39 @property({ type: Array<string> }) 40 dashboards: Array<string> = []; 41 42 @property({ type: Array<string> }) 43 dashboardGroups: Array<string> = []; 44 45 @property({ type: Array<string> }) 46 respectiveDashboards: Array<string> = []; 47 48 // toggles between the dashboards of a particular group or a dashboard without a group 49 @property({ type: Boolean }) 50 show = true; 51 52 /** 53 * Lit-element lifecycle method. 54 * Invoked when a component is added to the document's DOM. 55 */ 56 connectedCallback() { 57 super.connectedCallback(); 58 this.fetchDashboardGroups(); 59 this.fetchDashboards(); 60 } 61 62 /** 63 * Lit-element lifecycle method. 64 * Invoked on each update to perform rendering tasks. 65 */ 66 render() { 67 return html` 68 <div class="flex-container"> 69 <!-- loading dashboard groups --> 70 <mwc-list style="min-width: 760px"> 71 ${map(this.dashboardGroups, (dash: string, index: number) => 72 html` 73 <mwc-list-item 74 id=${index} 75 class="column card dashboard-group" 76 raised 77 @click="${() => this.fetchRespectiveDashboards(dash)}" 78 > 79 <div class="container"> 80 <p>${dash}</p> 81 </div> 82 </mwc-list-item> 83 `)} 84 </mwc-list> 85 86 <!-- loading dashboards --> 87 ${this.show ? dashboardTemplate(this.dashboards) : ''} 88 89 <!-- loading respective dashboards --> 90 ${!this.show ? dashboardTemplate(this.respectiveDashboards) : ''} 91 ${!this.show ? html` 92 <mwc-button class="column" raised @click="${() => this.show = !this.show }">X</mwc-button> 93 ` 94 : ''} 95 </div> 96 `; 97 } 98 99 // fetch the the list of dashboards from the API 100 async fetchDashboards() { 101 try{ 102 fetch(`http://${process.env.API_HOST}:${process.env.API_PORT}/api/v1/dashboards`).then( 103 async response => { 104 const resp = ListDashboardsResponse.fromJson(await response.json()); 105 const dashboards: string[] = []; 106 107 resp.dashboards.forEach(db => { 108 if (db.dashboardGroupName === ""){ 109 dashboards.push(db.name); 110 } 111 }); 112 this.dashboards = dashboards; 113 } 114 ); 115 } catch (error) { 116 console.log(`failed to fetch: ${error}`); 117 } 118 } 119 120 // fetch the list of dashboard groups from API 121 async fetchDashboardGroups() { 122 try{ 123 fetch(`http://${process.env.API_HOST}:${process.env.API_PORT}/api/v1/dashboard-groups`).then( 124 async response => { 125 const resp = ListDashboardGroupsResponse.fromJson(await response.json()); 126 const dashboardGroups: string[] = []; 127 128 resp.dashboardGroups.forEach(db => { 129 dashboardGroups.push(db.name); 130 }); 131 132 this.dashboardGroups = dashboardGroups; 133 } 134 ); 135 } catch(error){ 136 console.log(`failed to fetch: ${error}`); 137 } 138 } 139 140 // fetch the list of respective dashboards for a group from API 141 async fetchRespectiveDashboards(name: string) { 142 this.show = false; 143 try { 144 fetch(`http://${process.env.API_HOST}:${process.env.API_PORT}/api/v1/dashboard-groups/${name}`).then( 145 async response => { 146 const resp = ListDashboardsResponse.fromJson(await response.json()); 147 const respectiveDashboards: string[] = []; 148 149 resp.dashboards.forEach(ts => { 150 respectiveDashboards.push(ts.name); 151 }); 152 153 this.respectiveDashboards = respectiveDashboards; 154 } 155 ); 156 } catch (error) { 157 console.error(`Could not get dashboard summaries: ${error}`); 158 } 159 } 160 161 static styles = css` 162 :host { 163 overflow: auto; 164 min-height: 100vh; 165 display: flex; 166 flex-direction: column; 167 justify-content: flex; 168 font-size: calc(10px + 2vmin); 169 color: #1a2b42; 170 margin: 0 auto; 171 text-align: center; 172 background-color: var(--example-app-background-color); 173 } 174 175 .flex-container { 176 display: grid; 177 gap: 30px; 178 grid-template-columns: auto auto auto; 179 } 180 181 .column { 182 display: inline-grid; 183 padding: 10px; 184 } 185 186 .card { 187 /* Add shadows to create the "card" effect */ 188 width: 350px; 189 height: 80px; 190 margin-bottom: 10px; 191 box-shadow: 0 30px 30px -25px rgba(#7168c9, 0.25); 192 } 193 194 .dashboard { 195 background-color: #9e60eb; 196 color: #fff; 197 } 198 199 .dashboard-group { 200 background-color: #707df1; 201 color: #fff; 202 } 203 204 .dashboard-group:focus, 205 .dashboard-group:hover { 206 background-color: #fff; 207 color: #707df1; 208 border-style: solid; 209 border-color: #707df1; 210 } 211 212 .dashboard:hover, 213 .dashboard:focus { 214 background-color: #fff; 215 color: #9e60eb; 216 border-style: solid; 217 border-color: #9e60eb; 218 } 219 220 /* Add some padding inside the card container */ 221 .container { 222 padding: 2px 16px; 223 } 224 `; 225 }