1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109

content / browser / resources / indexed_db / transaction_table.ts [blame]

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

import {CustomElement} from 'chrome://resources/js/custom_element.js';
import {mojoString16ToString} from 'chrome://resources/js/mojo_type_util.js';
import type {String16} from 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-webui.js';

import {IdbTransactionMode, IdbTransactionState} from './indexed_db_internals_types.mojom-webui.js';
import type {IdbTransactionMetadata} from './indexed_db_internals_types.mojom-webui.js';
import {getTemplate} from './transaction_table.html.js';

// Joins a list of Mojom strings to a comma separated JS string.
function scope(mojoScope: String16[]): string {
  return `[${mojoScope.map(s => mojoString16ToString(s)).join(', ')}]`;
}

// Converts IdbTransactionState enum into a readable string.
function transactionState(mojoState: IdbTransactionState): string {
  switch (mojoState) {
    case IdbTransactionState.kBlocked:
      return 'Blocked';
    case IdbTransactionState.kRunning:
      return 'Running';
    case IdbTransactionState.kStarted:
      return 'Started';
    case IdbTransactionState.kCommitting:
      return 'Comitting';
    case IdbTransactionState.kFinished:
      return 'Finished';
    default:
      return 'Unknown';
  }
}

// Converts IdbTransactionMode enum into a readable string.
function transactionMode(mojoMode: IdbTransactionMode): string {
  switch (mojoMode) {
    case IdbTransactionMode.kReadOnly:
      return 'ReadOnly';
    case IdbTransactionMode.kReadWrite:
      return 'ReadWrite';
    case IdbTransactionMode.kVersionChange:
      return 'VersionChange';
    default:
      return 'Unknown';
  }
}

export class IndexedDbTransactionTable extends CustomElement {
  static override get template() {
    return getTemplate();
  }

  // Similar to CustomElement.$, but asserts that the element exists.
  $a<T extends HTMLElement = HTMLElement>(query: string): T {
    return this.getRequiredElement<T>(query);
  }

  // Setter for `data` property. Updates the component contents with the
  // provided metadata.
  set transactions(transactions: IdbTransactionMetadata[]) {
    const transactionTableBodyElement = this.$a('.transaction-list tbody');
    const transactionRowTemplateElement =
        this.$a<HTMLTemplateElement>(`#transaction-row`);

    transactionTableBodyElement.textContent = '';
    for (const transaction of transactions) {
      const row = (transactionRowTemplateElement.content.cloneNode(true) as
                   DocumentFragment)
                      .firstElementChild!;
      row.classList.add(transactionState(transaction.state).toLowerCase());
      row.querySelector('td.tid')!.textContent = transaction.tid.toString();
      row.querySelector('td.mode')!.textContent =
          transactionMode(transaction.mode);
      row.querySelector('td.scope')!.textContent = scope(transaction.scope);
      row.querySelector('td.requests-complete')!.textContent =
          transaction.tasksCompleted.toString();
      row.querySelector('td.requests-pending')!.textContent =
          (transaction.tasksScheduled - transaction.tasksCompleted).toString();
      row.querySelector('td.age')!.textContent =
          Math.round(transaction.age).toString();
      if (transaction.state === IdbTransactionState.kStarted ||
          transaction.state === IdbTransactionState.kRunning ||
          transaction.state === IdbTransactionState.kCommitting) {
        row.querySelector('td.runtime')!.textContent =
            Math.round(transaction.runtime).toString();
      }
      row.querySelector('td.state .text')!.textContent =
          transactionState(transaction.state);
      for (const state of transaction.stateHistory) {
        const li = document.createElement('li');
        li.textContent =
            `${transactionState(state.state)}: ${Math.round(state.duration)}ms`;
        row.querySelector('td.state ul')!.appendChild(li);
      }

      transactionTableBodyElement.appendChild(row);
    }
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'indexeddb-transaction-table': IndexedDbTransactionTable;
  }
}

customElements.define('indexeddb-transaction-table', IndexedDbTransactionTable);