Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(58)

Side by Side Diff: appengine/monorail/tracker/tablecell.py

Issue 1868553004: Open Source Monorail (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Rebase Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « appengine/monorail/tracker/spam_helpers.py ('k') | appengine/monorail/tracker/test/__init__.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2016 The Chromium Authors. All rights reserved.
2 # Use of this source code is govered by a BSD-style
3 # license that can be found in the LICENSE file or at
4 # https://developers.google.com/open-source/licenses/bsd
5
6 """Classes that generate value cells in the issue list table."""
7
8 import logging
9 import time
10 from third_party import ezt
11
12 from framework import table_view_helpers
13 from framework import timestr
14 from tracker import tracker_bizobj
15
16 # pylint: disable=unused-argument
17
18
19 class TableCellID(table_view_helpers.TableCell):
20 """TableCell subclass specifically for showing issue IDs."""
21
22 def __init__(
23 self, issue, col, users_by_id, non_col_labels, label_values,
24 _related_issues, _config):
25 table_view_helpers.TableCell.__init__(
26 self, table_view_helpers.CELL_TYPE_ID, [str(issue.local_id)])
27
28
29 class TableCellStatus(table_view_helpers.TableCell):
30 """TableCell subclass specifically for showing issue status values."""
31
32 def __init__(
33 self, issue, col, users_by_id, non_col_labels, label_values,
34 _related_issues, _config):
35 values = []
36 derived_values = []
37 if issue.status:
38 values = [issue.status]
39 if issue.derived_status:
40 derived_values = [issue.derived_status]
41
42 table_view_helpers.TableCell.__init__(
43 self, table_view_helpers.CELL_TYPE_ATTR, values,
44 derived_values=derived_values)
45
46
47 class TableCellOwner(table_view_helpers.TableCell):
48 """TableCell subclass specifically for showing issue owner name."""
49
50 # Make instances of this class render with whitespace:nowrap.
51 NOWRAP = ezt.boolean(True)
52
53 def __init__(
54 self, issue, col, users_by_id, non_col_labels, label_values,
55 _related_issues, _config):
56 values = []
57 derived_values = []
58 if issue.owner_id:
59 values = [users_by_id[issue.owner_id].display_name]
60 if issue.derived_owner_id:
61 derived_values = [users_by_id[issue.derived_owner_id].display_name]
62
63 table_view_helpers.TableCell.__init__(
64 self, table_view_helpers.CELL_TYPE_ATTR, values,
65 derived_values=derived_values)
66
67
68 class TableCellReporter(table_view_helpers.TableCell):
69 """TableCell subclass specifically for showing issue reporter name."""
70
71 # Make instances of this class render with whitespace:nowrap.
72 NOWRAP = ezt.boolean(True)
73
74 def __init__(
75 self, issue, col, users_by_id, non_col_labels, label_values,
76 _related_issues, _config):
77 try:
78 values = [users_by_id[issue.reporter_id].display_name]
79 except KeyError:
80 logging.info('issue reporter %r not found', issue.reporter_id)
81 values = ['deleted?']
82
83 table_view_helpers.TableCell.__init__(
84 self, table_view_helpers.CELL_TYPE_ATTR, values)
85
86
87 class TableCellCc(table_view_helpers.TableCell):
88 """TableCell subclass specifically for showing issue Cc user names."""
89
90 def __init__(
91 self, issue, _col, users_by_id, _non_col_labels,
92 _label_values, _related_issues, _config):
93 values = [users_by_id[cc_id].display_name
94 for cc_id in issue.cc_ids]
95
96 derived_values = [users_by_id[cc_id].display_name
97 for cc_id in issue.derived_cc_ids]
98
99 table_view_helpers.TableCell.__init__(
100 self, table_view_helpers.CELL_TYPE_ATTR, values,
101 derived_values=derived_values)
102
103
104 class TableCellAttachments(table_view_helpers.TableCell):
105 """TableCell subclass specifically for showing issue attachment count."""
106
107 def __init__(
108 self, issue, col, users_by_id, non_col_labels, label_values,
109 _related_issues, _config):
110 table_view_helpers.TableCell.__init__(
111 self, table_view_helpers.CELL_TYPE_ATTR, [issue.attachment_count],
112 align='right')
113
114
115 class TableCellOpened(table_view_helpers.TableCell):
116 """TableCell subclass specifically for showing issue opened date."""
117
118 # Make instances of this class render with whitespace:nowrap.
119 NOWRAP = ezt.boolean(True)
120
121 def __init__(
122 self, issue, col, users_by_id, non_col_labels, label_values,
123 _related_issues, _config):
124 date_str = timestr.FormatRelativeDate(
125 issue.opened_timestamp, recent_only=True)
126 if not date_str:
127 date_str = timestr.FormatAbsoluteDate(issue.opened_timestamp)
128
129 table_view_helpers.TableCell.__init__(
130 self, table_view_helpers.CELL_TYPE_UNFILTERABLE, [date_str])
131
132
133 class TableCellClosed(table_view_helpers.TableCell):
134 """TableCell subclass specifically for showing issue closed date."""
135
136 # Make instances of this class render with whitespace:nowrap.
137 NOWRAP = ezt.boolean(True)
138
139 def __init__(
140 self, issue, col, users_by_id, non_col_labels, label_values,
141 _related_issues, _config):
142 values = []
143 if issue.closed_timestamp:
144 date_str = timestr.FormatRelativeDate(
145 issue.closed_timestamp, recent_only=True)
146 if not date_str:
147 date_str = timestr.FormatAbsoluteDate(issue.closed_timestamp)
148 values = [date_str]
149
150 table_view_helpers.TableCell.__init__(
151 self, table_view_helpers.CELL_TYPE_UNFILTERABLE, values)
152
153
154 class TableCellModified(table_view_helpers.TableCell):
155 """TableCell subclass specifically for showing issue modified date."""
156
157 # Make instances of this class render with whitespace:nowrap.
158 NOWRAP = ezt.boolean(True)
159
160 def __init__(
161 self, issue, col, users_by_id, non_col_labels, label_values,
162 _related_issues, _config):
163 values = []
164 if issue.modified_timestamp:
165 date_str = timestr.FormatRelativeDate(
166 issue.modified_timestamp, recent_only=True)
167 if not date_str:
168 date_str = timestr.FormatAbsoluteDate(issue.modified_timestamp)
169 values = [date_str]
170
171 table_view_helpers.TableCell.__init__(
172 self, table_view_helpers.CELL_TYPE_UNFILTERABLE, values)
173
174
175 class TableCellBlockedOn(table_view_helpers.TableCell):
176 """TableCell subclass for listing issues the current issue is blocked on."""
177
178 def __init__(
179 self, issue, col, users_by_id, non_col_labels, label_values,
180 related_issues, _config):
181 ref_issues = [related_issues[iid] for iid in issue.blocked_on_iids
182 if iid in related_issues]
183 default_pn = issue.project_name
184 # TODO(jrobbins): in cross-project searches, leave default_pn = None.
185 values = [
186 tracker_bizobj.FormatIssueRef(
187 (ref_issue.project_name, ref_issue.local_id),
188 default_project_name=default_pn)
189 for ref_issue in ref_issues]
190 table_view_helpers.TableCell.__init__(
191 self, table_view_helpers.CELL_TYPE_ATTR, values)
192
193
194 class TableCellBlocking(table_view_helpers.TableCell):
195 """TableCell subclass for listing issues the current issue is blocking."""
196
197 def __init__(
198 self, issue, col, users_by_id, non_col_labels, label_values,
199 related_issues, _config):
200 ref_issues = [related_issues[iid] for iid in issue.blocking_iids
201 if iid in related_issues]
202 default_pn = issue.project_name
203 # TODO(jrobbins): in cross-project searches, leave default_pn = None.
204 values = [
205 tracker_bizobj.FormatIssueRef(
206 (ref_issue.project_name, ref_issue.local_id),
207 default_project_name=default_pn)
208 for ref_issue in ref_issues]
209 table_view_helpers.TableCell.__init__(
210 self, table_view_helpers.CELL_TYPE_ATTR, values)
211
212
213 class TableCellBlocked(table_view_helpers.TableCell):
214 """TableCell subclass for showing whether an issue is blocked."""
215
216 def __init__(
217 self, issue, col, users_by_id, non_col_labels, label_values,
218 _related_issues, _config):
219 if issue.blocked_on_iids:
220 value = 'Yes'
221 else:
222 value = 'No'
223
224 table_view_helpers.TableCell.__init__(
225 self, table_view_helpers.CELL_TYPE_ATTR, [value])
226
227
228 class TableCellMergedInto(table_view_helpers.TableCell):
229 """TableCell subclass for showing whether an issue is blocked."""
230
231 def __init__(
232 self, issue, col, users_by_id, non_col_labels, label_values,
233 related_issues, _config):
234 if issue.merged_into:
235 ref_issue = related_issues[issue.merged_into]
236 ref = ref_issue.project_name, ref_issue.local_id
237 default_pn = issue.project_name
238 # TODO(jrobbins): in cross-project searches, leave default_pn = None.
239 values = [
240 tracker_bizobj.FormatIssueRef(ref, default_project_name=default_pn)]
241 else: # Note: None means not merged into any issue.
242 values = []
243
244 table_view_helpers.TableCell.__init__(
245 self, table_view_helpers.CELL_TYPE_ATTR, values)
246
247
248 class TableCellComponent(table_view_helpers.TableCell):
249 """TableCell subclass for showing components."""
250
251 def __init__(
252 self, issue, _col, _users_by_id, _non_col_labels,
253 _label_values, _related_issues, config):
254 explicit_paths = []
255 for component_id in issue.component_ids:
256 cd = tracker_bizobj.FindComponentDefByID(component_id, config)
257 if cd:
258 explicit_paths.append(cd.path)
259
260 derived_paths = []
261 for component_id in issue.derived_component_ids:
262 cd = tracker_bizobj.FindComponentDefByID(component_id, config)
263 if cd:
264 derived_paths.append(cd.path)
265
266 table_view_helpers.TableCell.__init__(
267 self, table_view_helpers.CELL_TYPE_ATTR, explicit_paths,
268 derived_values=derived_paths)
269
270
271 # This maps column names to factories/constructors that make table cells.
272 # Subclasses can override this mapping, so any additions to this mapping
273 # should also be added to subclasses.
274 CELL_FACTORIES = {
275 'id': TableCellID,
276 'project': table_view_helpers.TableCellProject,
277 'component': TableCellComponent,
278 'summary': table_view_helpers.TableCellSummary,
279 'status': TableCellStatus,
280 'owner': TableCellOwner,
281 'reporter': TableCellReporter,
282 'cc': TableCellCc,
283 'stars': table_view_helpers.TableCellStars,
284 'attachments': TableCellAttachments,
285 'opened': TableCellOpened,
286 'closed': TableCellClosed,
287 'modified': TableCellModified,
288 'blockedon': TableCellBlockedOn,
289 'blocking': TableCellBlocking,
290 'blocked': TableCellBlocked,
291 'mergedinto': TableCellMergedInto,
292 }
293
294
295 # Time format that spreadsheets seem to understand.
296 # E.g.: "May 19 2008 13:30:23". Tested with MS Excel 2003,
297 # OpenOffice.org, NeoOffice, and Google Spreadsheets.
298 CSV_DATE_TIME_FMT = '%b %d, %Y %H:%M:%S'
299
300
301 def TimeStringForCSV(timestamp):
302 """Return a timestamp in a format that spreadsheets understand."""
303 return time.strftime(CSV_DATE_TIME_FMT, time.gmtime(timestamp))
304
305
306 class TableCellSummaryCSV(table_view_helpers.TableCell):
307 """TableCell subclass for showing issue summaries escaped for CSV."""
308
309 def __init__(
310 self, issue, col, users_by_id, non_col_labels, label_values,
311 _related, _config):
312 escaped_summary = issue.summary.replace('"', '""')
313 table_view_helpers.TableCell.__init__(
314 self, table_view_helpers.CELL_TYPE_SUMMARY, [escaped_summary],
315 non_column_labels=non_col_labels)
316
317
318 class TableCellAllLabels(table_view_helpers.TableCell):
319 """TableCell subclass specifically for showing all labels on an issue."""
320
321 def __init__(
322 self, issue, col, users_by_id, non_col_labels, label_values,
323 _related, _config):
324 values = []
325 derived_values = []
326 if issue.labels:
327 values = issue.labels[:]
328 if issue.derived_labels:
329 derived_values = issue.derived_labels[:]
330
331 table_view_helpers.TableCell.__init__(
332 self, table_view_helpers.CELL_TYPE_ATTR, values,
333 derived_values=derived_values)
334
335
336 class TableCellOpenedCSV(table_view_helpers.TableCell):
337 """TableCell subclass specifically for showing issue opened date."""
338
339 def __init__(
340 self, issue, col, users_by_id, non_col_labels, label_values,
341 _related, _config):
342 date_str = TimeStringForCSV(issue.opened_timestamp)
343
344 table_view_helpers.TableCell.__init__(
345 self, table_view_helpers.CELL_TYPE_UNFILTERABLE, [date_str])
346
347
348 class TableCellOpenedTimestamp(table_view_helpers.TableCell):
349 """TableCell subclass specifically for showing issue opened timestamp."""
350
351 def __init__(
352 self, issue, col, users_by_id, non_col_labels, label_values,
353 _related, _config):
354 table_view_helpers.TableCell.__init__(
355 self, table_view_helpers.CELL_TYPE_UNFILTERABLE,
356 [issue.opened_timestamp])
357
358
359 class TableCellModifiedCSV(table_view_helpers.TableCell):
360 """TableCell subclass specifically for showing issue modified date."""
361
362 def __init__(
363 self, issue, col, users_by_id, non_col_labels, label_values,
364 _related, _config):
365 values = []
366 if issue.modified_timestamp:
367 values = [TimeStringForCSV(issue.modified_timestamp)]
368
369 table_view_helpers.TableCell.__init__(
370 self, table_view_helpers.CELL_TYPE_UNFILTERABLE, values)
371
372
373 class TableCellModifiedTimestamp(table_view_helpers.TableCell):
374 """TableCell subclass specifically for showing issue modified timestamp."""
375
376 def __init__(
377 self, issue, col, users_by_id, non_col_labels, label_values,
378 _related, _config):
379 table_view_helpers.TableCell.__init__(
380 self, table_view_helpers.CELL_TYPE_UNFILTERABLE,
381 [issue.modified_timestamp])
382
383
384 class TableCellClosedCSV(table_view_helpers.TableCell):
385 """TableCell subclass specifically for showing issue closed date."""
386
387 def __init__(
388 self, issue, col, users_by_id, non_col_labels, label_values,
389 _related, _config):
390 values = []
391 if issue.closed_timestamp:
392 values = [TimeStringForCSV(issue.closed_timestamp)]
393
394 table_view_helpers.TableCell.__init__(
395 self, table_view_helpers.CELL_TYPE_UNFILTERABLE, values)
396
397
398 class TableCellClosedTimestamp(table_view_helpers.TableCell):
399 """TableCell subclass specifically for showing issue closed timestamp."""
400
401 def __init__(
402 self, issue, col, users_by_id, non_col_labels, label_values,
403 _related, _config):
404 table_view_helpers.TableCell.__init__(
405 self, table_view_helpers.CELL_TYPE_UNFILTERABLE,
406 [issue.closed_timestamp])
407
408
409 # Maps column names to factories/constructors that make table cells.
410 # Uses the defaults in issuelist.py but changes the factory for the
411 # summary cell to properly escape the data for CSV files.
412 CSV_CELL_FACTORIES = CELL_FACTORIES.copy()
413 CSV_CELL_FACTORIES.update({
414 'summary': TableCellSummaryCSV,
415 'alllabels': TableCellAllLabels,
416 'opened': TableCellOpenedCSV,
417 'openedtimestamp': TableCellOpenedTimestamp,
418 'closed': TableCellClosedCSV,
419 'closedtimestamp': TableCellClosedTimestamp,
420 'modified': TableCellModifiedCSV,
421 'modifiedtimestamp': TableCellModifiedTimestamp,
422 })
OLDNEW
« no previous file with comments | « appengine/monorail/tracker/spam_helpers.py ('k') | appengine/monorail/tracker/test/__init__.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698