• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2023 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import {assert} from 'chrome://resources/js/assert.js';
6
7/**
8 * Key-Value pair for the summary and metrics table.
9 */
10interface KeyValue {
11  key: string;
12  value: number|string|boolean;
13}
14
15/**
16 * Sequence information for an event.
17 */
18interface SequenceMetadata {
19  id: string;
20  systemUptimeMs: string;
21  resetCounter: string;
22}
23
24/**
25 * An event and its data. This includes metadata about the event and sequence
26 * information if applicable.
27 */
28export interface StructuredMetricEvent {
29  project: string;
30  event: string;
31  type: string;
32  sequenceMetadata?: SequenceMetadata;
33  metrics: KeyValue[];
34}
35
36/**
37 * Summary about Structured Metrics service.
38 */
39export interface StructuredMetricsSummary {
40  enabled: boolean;
41  flags: KeyValue[];
42  crosDeviceId: string;
43}
44
45/**
46 * Updates the Summary table with new information.
47 *
48 * @param summaryBody Body of the summary table.
49 * @param summary Summary object to populate the table.
50 * @param template Key-Value pair HTML template.
51 */
52export function updateStructuredMetricsSummary(
53    summaryBody: HTMLElement, summary: StructuredMetricsSummary,
54    template: HTMLTemplateElement): void {
55  // Clear the table first.
56  summaryBody.replaceChildren();
57
58  const enabled =
59      buildKeyValueRow('Enabled', summary.enabled.toString(), template);
60  summaryBody.append(enabled);
61
62  const crosDeviceId =
63      buildKeyValueRow('CrOS Device Id', summary.crosDeviceId || '-', template);
64  summaryBody.append(crosDeviceId);
65}
66
67/**
68 * Updates the events table with the events recorded by the client.
69 *
70 * @param eventBody Body of the event table.
71 * @param events List of events to populate the table.
72 * @param template HTML template for the event table row.
73 * @param kvTemplate Key-Value pair HTML template.
74 */
75export function updateStructuredMetricsEvents(
76    eventBody: HTMLElement, events: StructuredMetricEvent[],
77    eventTemplate: HTMLTemplateElement, detailsTemplate: HTMLTemplateElement,
78    kvTemplate: HTMLTemplateElement): void {
79  eventBody.replaceChildren();
80
81  for (const event of events) {
82    const row = eventTemplate.content.cloneNode(true) as HTMLElement;
83    const [project, evn, type, uptime] = row.querySelectorAll('td');
84
85    assert(project);
86    project.textContent = event.project;
87
88    assert(evn);
89    evn.textContent = event.event;
90
91    assert(type);
92    type.textContent = event.type;
93
94    assert(uptime);
95    uptime.textContent = event.sequenceMetadata?.systemUptimeMs ?? '-';
96
97    const detailsRow = detailsTemplate.content.cloneNode(true) as HTMLElement;
98    const metricsRow = detailsRow.querySelector('#metrics-row') as HTMLElement;
99    assert(metricsRow);
100
101    const [details, metrics] = detailsRow.querySelectorAll('tbody');
102    assert(details);
103    assert(metrics);
104
105    updateEventDetailsTable(details, event, kvTemplate);
106    updateEventMetricsTable(metrics, event, kvTemplate);
107
108    const eventRow = row.querySelector('#event-row') as HTMLElement;
109    eventRow.addEventListener('click', () => {
110      if (metricsRow.style.display === 'none') {
111        metricsRow.style.display = 'table-row';
112      } else {
113        metricsRow.style.display = 'none';
114      }
115    }, false);
116
117    eventBody.append(row);
118    eventBody.append(detailsRow);
119  }
120}
121
122function updateEventDetailsTable(
123    detailTable: HTMLElement, event: StructuredMetricEvent,
124    template: HTMLTemplateElement): void {
125  detailTable.replaceChildren();
126
127  const resetCounter = event.sequenceMetadata?.resetCounter ?? '-';
128  const systemUptime = event.sequenceMetadata?.systemUptimeMs ?? '-';
129  const eventId = event.sequenceMetadata?.id ?? '-';
130
131  const resetCounterRow = buildKeyValueRow('Reset Id', resetCounter, template);
132  const systemUptimeRow =
133      buildKeyValueRow('System Uptime', systemUptime, template);
134  const eventIdRow = buildKeyValueRow('Event Id', eventId, template);
135
136  detailTable.append(resetCounterRow);
137  detailTable.append(systemUptimeRow);
138  detailTable.append(eventIdRow);
139}
140
141function updateEventMetricsTable(
142    metricsTable: HTMLElement, event: StructuredMetricEvent,
143    template: HTMLTemplateElement): void {
144  metricsTable.replaceChildren();
145  for (const metric of event.metrics) {
146    const metricRow =
147        buildKeyValueRow(metric.key, metric.value.toString(), template);
148    metricsTable.append(metricRow);
149  }
150}
151
152function buildKeyValueRow(
153    key: string, value: string, template: HTMLTemplateElement): HTMLElement {
154  const kvRow = template.content.cloneNode(true) as HTMLElement;
155
156  const [k, v] = kvRow.querySelectorAll('td');
157  assert(k);
158  k.textContent = key;
159  assert(v);
160  v.textContent = value;
161
162  return kvRow;
163}
164