1<template>
2  <div>
3
4    <div v-if="source.type === 'vsyncEvent'" class="vsync">
5      <div class="vsync-dot" />
6      <md-tooltip md-direction="left">
7        VSync
8      </md-tooltip>
9    </div>
10
11    <div v-else
12      class="entry"
13      :class="{
14        inactive: source.timestamp > currentTimestamp,
15        selected: isSelected
16      }"
17      @click="onClick(source)"
18    >
19      <div class="time-column">
20        <a @click="e => setTimelineTime(e, source.timestamp)" class="time-link">
21          {{source.time}}
22        </a>
23        <div
24          class="new-badge"
25          :style="{visibility: source.new ? 'visible' : 'hidden'} "
26        >
27          New
28        </div>
29      </div>
30      <div class="type-column">{{transactionTypeOf(source)}}</div>
31      <div class="affected-surfaces-column">
32        <span
33          v-for="(surface, index) in sufacesAffectedBy(source)"
34          v-bind:key="surface.id"
35        >
36          <!-- eslint-disable-next-line max-len -->
37          <span v-if="surface.name" class="surface-name">{{ surface.name }}</span>
38          <span class="surface-id">
39            <!-- eslint-disable-next-line max-len -->
40            <span v-if="surface.name">(</span>{{surface.id}}<span v-if="surface.name">)</span>
41          </span>
42          <!-- eslint-disable-next-line max-len -->
43          <span v-if="index + 1 < sufacesAffectedBy(source).length">,&nbsp;</span>
44        </span>
45      </div>
46      <div class="extra-info-column">
47        <span v-if="source.identifier">
48          <!-- eslint-disable-next-line max-len -->
49          Tx Id: <span class="light">{{ prettifyTransactionId(source.identifier) }}</span><br/>
50        </span>
51        <span v-if="source.origin">
52          PID: <span class="light">{{ source.origin.pid }}</span><br/>
53          UID: <span class="light">{{ source.origin.uid }}</span><br/>
54        </span>
55      </div>
56    </div>
57
58  </div>
59</template>
60
61<script>
62export default {
63  name: 'transaction-entry',
64  props: {
65    index: {
66      type: Number,
67    },
68    source: {
69      type: Object,
70      default() {
71        return {};
72      },
73    },
74    onClick: {
75      type: Function,
76    },
77    selectedTransaction: {
78      type: Object,
79    },
80    transactionsTrace: {
81      type: Object,
82    },
83    prettifyTransactionId: {
84      type: Function,
85    },
86  },
87  computed: {
88    currentTimestamp() {
89      return this.$store.state.currentTimestamp;
90    },
91    isSelected() {
92      return this.source === this.selectedTransaction;
93    },
94    hasOverrideChangeDueToMerge() {
95      const transaction = this.source;
96
97      if (!transaction.identifier) {
98        return;
99      }
100
101      // console.log('transaction', transaction.identifier);
102
103      // const history = this.transactionsTrace.transactionHistory;
104
105      // const allTransactionsMergedInto = history
106      //     .allTransactionsMergedInto(transaction.identifier);
107      // console.log('All merges', allTransactionsMergedInto);
108
109      // console.log('Direct merges',
110      //     history.allDirectMergesInto(transaction.identifier));
111
112
113      return true;
114    },
115  },
116  methods: {
117    setTimelineTime(e, timestamp) {
118      e.preventDefault();
119      e.stopPropagation();
120      this.$store.dispatch('updateTimelineTime', timestamp);
121    },
122    transactionTypeOf(transaction) {
123      if (transaction.type !== 'transaction') {
124        return transaction.type;
125      }
126
127      if (transaction.transactions.length === 0) {
128        return 'Empty Transaction';
129      }
130
131      const types = new Set();
132      transaction.transactions.forEach((t) => types.add(t.type));
133
134      return Array.from(types).join(', ');
135    },
136    sufacesAffectedBy(transaction) {
137      if (transaction.type !== 'transaction') {
138        // TODO (b/162402459): Shorten layer name
139        return [{name: transaction.layerName, id: transaction.obj.id}];
140      }
141
142      const surfaceIds = new Set();
143      const affectedSurfaces = [];
144      for (const transaction of transaction.transactions) {
145        const id = transaction.obj.id;
146        if (!surfaceIds.has(id)) {
147          surfaceIds.add(id);
148          affectedSurfaces.push({name: transaction.layerName, id});
149        }
150      }
151
152      return affectedSurfaces;
153    },
154  },
155};
156</script>
157<style scoped>
158.time-column {
159  display: inline-flex;
160  width: 13em;
161}
162
163.time-column .time-link {
164  width: 9em;
165}
166
167.type-column {
168  width: 12em;
169}
170
171.origin-column {
172  width: 9em;
173}
174
175.affected-surfaces-column {
176  word-wrap: break-word;
177  width: 30em;
178}
179
180.extra-info-column {
181  width: 20em;
182}
183
184.entry {
185  display: inline-flex;
186  cursor: pointer;
187}
188
189.entry > div {
190  padding: 6px 10px;
191  border-bottom: 1px solid #f1f1f1;
192}
193
194.entry.selected {
195  background-color: #365179;
196  color: white;
197}
198
199.entry.selected a {
200  color: white;
201}
202
203.entry:not(.selected):hover {
204  background: #f1f1f1;
205}
206
207a {
208  cursor: pointer;
209}
210
211.inactive {
212  color: gray;
213}
214
215.inactive a {
216  color: gray;
217}
218
219.new-badge {
220  display: inline-block;
221  background: rgb(84, 139, 247);
222  border-radius: 3px;
223  color: white;
224  padding: 0 5px;
225  margin-left: 5px;
226  font-size: 10px;
227}
228
229.affected-surfaces-column .surface-id {
230  color: #999999
231}
232
233.inactive .affected-surfaces-column .surface-id {
234  color: #b4b4b4
235}
236
237.light {
238  color: #999999
239}
240
241.inactive .light {
242  color: #b4b4b4
243}
244
245.vsync {
246  position: relative;
247}
248
249.vsync-dot:before {
250  content: "";
251  position: absolute;
252  left: 0;
253  top: -5px;
254  height: 10px;
255  width: 10px;
256  background-color: rgb(170, 65, 255);
257  border-radius: 50%;
258  display: inline-block;
259}
260
261.vsync-dot:after {
262  content: "";
263  position: absolute;
264  left: 0;
265  top: 0;
266  height: 1px;
267  width: 100%;
268  background-color: rgb(170, 65, 255);
269  display: inline-block;
270}
271</style>
272