chromium/content/browser/resources/traces_internals/trace_report_list.ts

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import './trace_report.js';
import 'chrome://resources/cr_elements/cr_toast/cr_toast.js';
import 'chrome://resources/cr_elements/cr_button/cr_button.js';
import 'chrome://resources/cr_elements/cr_icon/cr_icon.js';
import 'chrome://resources/cr_elements/icons_lit.html.js';

import type {CrToastElement} from 'chrome://resources/cr_elements/cr_toast/cr_toast.js';
import {assert} from 'chrome://resources/js/assert.js';
import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';

import type {ClientTraceReport} from './trace_report.mojom-webui.js';
import {TraceReportBrowserProxy} from './trace_report_browser_proxy.js';
import {getCss} from './trace_report_list.css.js';
import {getHtml} from './trace_report_list.html.js';
// clang-format on

export enum NotificationType {
  UPDATE = 'Update',
  ERROR = 'Error',
  ANNOUNCEMENT = 'Announcement'
}

export class Notification {
  readonly type: NotificationType;
  readonly label: string;

  constructor(type: NotificationType, label: string) {
    this.type = type;
    this.label = label;
  }
}

export interface TraceReportListElement {
  $: {
    toast: CrToastElement,
  };
}

export class TraceReportListElement extends CrLitElement {
  static get is() {
    return 'trace-report-list';
  }

  static override get styles() {
    return getCss();
  }

  override render() {
    return getHtml.bind(this)();
  }

  static override get properties() {
    return {
      traces_: {type: Array},
      isLoading_: {type: Boolean},
      notification: {type: Notification},
    };
  }

  private traceReportProxy_: TraceReportBrowserProxy =
      TraceReportBrowserProxy.getInstance();
  protected traces_: ClientTraceReport[] = [];
  protected isLoading_: boolean = false;
  protected notification_?: Readonly<Notification>;

  override connectedCallback(): void {
    super.connectedCallback();
    this.initializeList(true);
  }

  protected async initializeList(hasLoading: boolean = false): Promise<void> {
    this.isLoading_ = hasLoading;
    const {reports} = await this.traceReportProxy_.handler.getAllTraceReports();
    if (reports) {
      this.traces_ = reports;
    } else {
      this.traces_ = [];
      this.notification_ = new Notification(
          NotificationType.ERROR,
          'Error: Could not retrieve any trace reports.');
      this.$.toast.show();
    }
    this.isLoading_ = false;
  }

  protected hasTraces_(): boolean {
    return this.traces_.length > 0;
  }

  protected showToastHandler_(e: CustomEvent<Notification>): void {
    assert(e.detail);
    this.notification_ = e.detail;
    this.$.toast.show();
  }

  protected getNotificationIcon_(): string {
    switch (this.getNotificationType_()) {
      case NotificationType.ANNOUNCEMENT:
        return 'cr:info-outline';
      case NotificationType.ERROR:
        return 'cr:error-outline';
      case NotificationType.UPDATE:
        return 'cr:sync';
      default:
        return 'cr:warning';
    }
  }

  protected getNotificationStyling_(): string {
    switch (this.getNotificationType_()) {
      case NotificationType.ANNOUNCEMENT:
        return 'announcement';
      case NotificationType.ERROR:
        return 'error';
      case NotificationType.UPDATE:
        return 'update';
      default:
        return '';
    }
  }

  protected getNotificationLabel_(): string {
    return this.notification_?.label || '';
  }

  protected getNotificationType_(): string {
    return this.notification_?.type || '';
  }

  protected async onDeleteAllTracesClick_(): Promise<void> {
    const {success} = await this.traceReportProxy_.handler.deleteAllTraces();
    if (!success) {
      this.dispatchToast_('Failed to delete to delete all traces.');
    }
    this.initializeList();
  }

  private dispatchToast_(message: string): void {
    this.dispatchEvent(new CustomEvent('show-toast', {
      bubbles: true,
      composed: true,
      detail: new Notification(NotificationType.ERROR, message),
    }));
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'trace-report-list': TraceReportListElement;
  }
}

customElements.define(TraceReportListElement.is, TraceReportListElement);