github.com/GoogleCloudPlatform/testgrid@v0.0.174/web/src/testgrid-dashboard-summary.ts (about)

     1  import { LitElement, html } from 'lit';
     2  // eslint-disable-next-line @typescript-eslint/no-unused-vars
     3  import { customElement, property, state } from 'lit/decorators.js';
     4  import { map } from 'lit/directives/map.js';
     5  import { Timestamp } from './gen/google/protobuf/timestamp.js';
     6  import { FailuresSummary, ListTabSummariesResponse, TabSummary } from './gen/pb/api/v1/data.js';
     7  import './tab-summary.js';
     8  
     9  export interface TabSummaryInfo {
    10    icon: string;
    11    name: string;
    12    overallStatus: string;
    13    detailedStatusMsg: string;
    14    lastUpdateTimestamp: string;
    15    lastRunTimestamp: string;
    16    latestGreenBuild: string;
    17    dashboardName: string;
    18    failuresSummary?: FailuresSummaryInfo;
    19    healthinessSummary?: HealthinessSummaryInfo;
    20  }
    21  
    22  export interface FailuresSummaryInfo {
    23    topFailingTests: FailingTestInfo[];
    24    failureStats: FailureStats;
    25  }
    26  
    27  export interface FailingTestInfo {
    28    displayName: string;
    29    failCount: number;
    30    passTimestamp: string;
    31    failTimestamp: string;
    32  }
    33  
    34  export interface FailureStats {
    35    numFailingTests: number;
    36  }
    37  
    38  export interface HealthinessSummaryInfo {
    39    topFlakyTests: FlakyTestInfo[];
    40    healthinessStats: HealthinessStats;
    41  }
    42  
    43  export interface FlakyTestInfo {
    44    displayName: string;
    45    flakiness: number;
    46  }
    47  
    48  export interface HealthinessStats {
    49    startTimestamp: string;
    50    endTimestamp: string;
    51    numFlakyTests: number;
    52    averageFlakiness: number;
    53    previousFlakiness: number;
    54  }
    55  
    56  // TODO: define in a shared file (dashboard group also uses this)
    57  export const TabStatusIcon = new Map<string, string>([
    58    ['PASSING', 'done'],
    59    ['FAILING', 'warning'],
    60    ['FLAKY', 'remove_circle_outline'],
    61    ['STALE', 'error_outline'],
    62    ['BROKEN', 'broken_image'],
    63    ['PENDING', 'schedule'],
    64    ['ACCEPTABLE', 'add_circle_outline'],
    65  ]);
    66  
    67  // TODO: generate the correct time representation
    68  function convertResponse(ts: TabSummary) {
    69    const tsi: TabSummaryInfo = {
    70      icon: TabStatusIcon.get(ts.overallStatus)!,
    71      name: ts.tabName,
    72      overallStatus: ts.overallStatus,
    73      detailedStatusMsg: ts.detailedStatusMessage,
    74      lastUpdateTimestamp: Timestamp.toDate(
    75        ts.lastUpdateTimestamp!
    76      ).toISOString(),
    77      lastRunTimestamp: Timestamp.toDate(ts.lastRunTimestamp!).toISOString(),
    78      latestGreenBuild: ts.latestPassingBuild,
    79      dashboardName: ts.dashboardName,
    80    };
    81    if (ts.failuresSummary !== undefined) {
    82      tsi.failuresSummary = {} as FailuresSummaryInfo
    83      const failureStats: FailureStats = {
    84        numFailingTests: ts.failuresSummary!.failureStats!.numFailingTests,
    85      }
    86      tsi.failuresSummary!.failureStats = failureStats
    87  
    88      tsi.failuresSummary!.topFailingTests = [];
    89      ts.failuresSummary?.topFailingTests.forEach( (test, i) => {
    90      const failingTest: FailingTestInfo = {
    91        displayName: test.displayName,
    92        failCount: test.failCount,
    93        passTimestamp: Timestamp.toDate(test.passTimestamp!).toISOString(),
    94        failTimestamp: Timestamp.toDate(test.failTimestamp!).toISOString(),
    95      }
    96      tsi.failuresSummary!.topFailingTests.push(failingTest)
    97      });
    98    }
    99  
   100    if (ts.healthinessSummary !== undefined) {
   101      tsi.healthinessSummary = {} as HealthinessSummaryInfo
   102      const healthinessStats: HealthinessStats = {
   103        startTimestamp: Timestamp.toDate(ts.healthinessSummary!.healthinessStats!.start!).toISOString(),
   104        endTimestamp: Timestamp.toDate(ts.healthinessSummary!.healthinessStats!.end!).toISOString(),
   105        numFlakyTests: ts.healthinessSummary!.healthinessStats!.numFlakyTests,
   106        averageFlakiness: ts.healthinessSummary!.healthinessStats!.averageFlakiness,
   107        previousFlakiness: ts.healthinessSummary!.healthinessStats!.previousFlakiness,
   108      }
   109      tsi.healthinessSummary!.healthinessStats = healthinessStats
   110  
   111      tsi.healthinessSummary!.topFlakyTests = [];
   112      ts.healthinessSummary?.topFlakyTests.forEach( test => {
   113        const flakyTest: FlakyTestInfo = {
   114          displayName: test.displayName,
   115          flakiness: test.flakiness,
   116        }
   117        tsi.healthinessSummary!.topFlakyTests.push(flakyTest)
   118      })
   119    }
   120    return tsi;
   121  }
   122  
   123  /**
   124   * Class definition for the `testgrid-dashboard-summary` element.
   125   * Renders the dashboard summary (summary of dashboard tabs).
   126   */
   127  @customElement('testgrid-dashboard-summary')
   128  // eslint-disable-next-line @typescript-eslint/no-unused-vars
   129  export class TestgridDashboardSummary extends LitElement {
   130  
   131    @property()
   132    dashboardName: string = '';
   133  
   134    @state()
   135    tabSummariesInfo: Array<TabSummaryInfo> = [];
   136  
   137    connectedCallback(){
   138      super.connectedCallback();
   139      this.fetchTabSummaries();
   140    }
   141  
   142    /**
   143     * Lit-element lifecycle method.
   144     * Invoked on each update to perform rendering tasks.
   145     */
   146    render() {
   147      return html`
   148        ${map(
   149        this.tabSummariesInfo,
   150        (ts: TabSummaryInfo) => html`<tab-summary .info=${ts}></tab-summary>`
   151      )}
   152    `;
   153    }
   154  
   155    // fetch the tab summaries and tab names to populate the tab bar
   156    private async fetchTabSummaries() {
   157      try {
   158        const response = await fetch(
   159          `http://${process.env.API_HOST}:${process.env.API_PORT}/api/v1/dashboards/${this.dashboardName}/tab-summaries`
   160        );
   161        if (!response.ok) {
   162          throw new Error(`HTTP error: ${response.status}`);
   163        }
   164        const data = ListTabSummariesResponse.fromJson(await response.json());
   165        var tabSummaries: Array<TabSummaryInfo> = [];
   166        data.tabSummaries.forEach(ts => {
   167          const si = convertResponse(ts);
   168          tabSummaries.push(si);
   169        });
   170        this.tabSummariesInfo = tabSummaries;
   171      } catch (error) {
   172        console.error(`Could not get dashboard summaries: ${error}`);
   173      }
   174    }
   175  }