• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2023 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import m from 'mithril';
16
17import {copyToClipboard} from '../../base/clipboard';
18import {Icons} from '../../base/semantic_icons';
19import {time, Time} from '../../base/time';
20import {Actions} from '../../common/actions';
21import {
22  setTimestampFormat,
23  TimestampFormat,
24  timestampFormat,
25} from '../../core/timestamp_format';
26import {raf} from '../../core/raf_scheduler';
27import {Anchor} from '../../widgets/anchor';
28import {MenuDivider, MenuItem, PopupMenu2} from '../../widgets/menu';
29import {globals} from '../globals';
30
31// import {MenuItem, PopupMenu2} from './menu';
32
33interface TimestampAttrs {
34  // The timestamp to print, this should be the absolute, raw timestamp as
35  // found in trace processor.
36  ts: time;
37  // Custom text value to show instead of the default HH:MM:SS.mmm uuu nnn
38  // formatting.
39  display?: m.Children;
40  extraMenuItems?: m.Child[];
41}
42
43export class Timestamp implements m.ClassComponent<TimestampAttrs> {
44  view({attrs}: m.Vnode<TimestampAttrs>) {
45    const {ts} = attrs;
46    return m(
47      PopupMenu2,
48      {
49        trigger: m(
50          Anchor,
51          {
52            onmouseover: () => {
53              globals.dispatch(Actions.setHoverCursorTimestamp({ts}));
54            },
55            onmouseout: () => {
56              globals.dispatch(
57                Actions.setHoverCursorTimestamp({ts: Time.INVALID}),
58              );
59            },
60          },
61          attrs.display ?? renderTimestamp(ts),
62        ),
63      },
64      m(MenuItem, {
65        icon: Icons.Copy,
66        label: `Copy raw value`,
67        onclick: () => {
68          copyToClipboard(ts.toString());
69        },
70      }),
71      m(
72        MenuItem,
73        {
74          label: 'Time format',
75        },
76        menuItemForFormat(TimestampFormat.Timecode, 'Timecode'),
77        menuItemForFormat(TimestampFormat.UTC, 'Realtime (UTC)'),
78        menuItemForFormat(TimestampFormat.TraceTz, 'Realtime (Trace TZ)'),
79        menuItemForFormat(TimestampFormat.Seconds, 'Seconds'),
80        menuItemForFormat(TimestampFormat.Raw, 'Raw'),
81        menuItemForFormat(
82          TimestampFormat.RawLocale,
83          'Raw (with locale-specific formatting)',
84        ),
85      ),
86      attrs.extraMenuItems ? [m(MenuDivider), attrs.extraMenuItems] : null,
87    );
88  }
89}
90
91export function menuItemForFormat(
92  value: TimestampFormat,
93  label: string,
94): m.Children {
95  return m(MenuItem, {
96    label,
97    active: value === timestampFormat(),
98    onclick: () => {
99      setTimestampFormat(value);
100      raf.scheduleFullRedraw();
101    },
102  });
103}
104
105function renderTimestamp(time: time): m.Children {
106  const fmt = timestampFormat();
107  const domainTime = globals.toDomainTime(time);
108  switch (fmt) {
109    case TimestampFormat.UTC:
110    case TimestampFormat.TraceTz:
111    case TimestampFormat.Timecode:
112      return renderTimecode(domainTime);
113    case TimestampFormat.Raw:
114      return domainTime.toString();
115    case TimestampFormat.RawLocale:
116      return domainTime.toLocaleString();
117    case TimestampFormat.Seconds:
118      return Time.formatSeconds(domainTime);
119    default:
120      const x: never = fmt;
121      throw new Error(`Invalid timestamp ${x}`);
122  }
123}
124
125export function renderTimecode(time: time): m.Children {
126  const {dhhmmss, millis, micros, nanos} = Time.toTimecode(time);
127  return m(
128    'span.pf-timecode',
129    m('span.pf-timecode-hms', dhhmmss),
130    '.',
131    m('span.pf-timecode-millis', millis),
132    m('span.pf-timecode-micros', micros),
133    m('span.pf-timecode-nanos', nanos),
134  );
135}
136