Merge lp:~pauljnixon/loggerhead/more_columns into lp:loggerhead
- more_columns
- Merge into trunk-rich
Status: | Merged |
---|---|
Approved by: | Steve Kowalik |
Approved revision: | 478 |
Merged at revision: | 494 |
Proposed branch: | lp:~pauljnixon/loggerhead/more_columns |
Merge into: | lp:loggerhead |
Diff against target: |
386 lines (+97/-50) 9 files modified
loggerhead/apps/branch.py (+15/-0) loggerhead/controllers/directory_ui.py (+6/-6) loggerhead/controllers/inventory_ui.py (+22/-9) loggerhead/history.py (+1/-0) loggerhead/static/css/global.css (+2/-2) loggerhead/static/css/view.css (+1/-2) loggerhead/templates/directory.pt (+12/-13) loggerhead/templates/inventory.pt (+25/-12) loggerhead/util.py (+13/-6) |
To merge this branch: | bzr merge lp:~pauljnixon/loggerhead/more_columns |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Colin Watson (community) | Needs Information | ||
Paul Nixon (community) | Abstain | ||
Steve Kowalik (community) | code | Approve | |
Review via email: mp+118188@code.launchpad.net |
This proposal supersedes a proposal from 2012-07-24.
Commit message
Description of the change
Added "committer" and "comment" columns to Files and Inventory views.
Before: http://
After: http://
Steve Kowalik (stevenk) wrote : Posted in a previous version of this proposal | # |
Paul Nixon (pauljnixon) wrote : Posted in a previous version of this proposal | # |
Before: http://
After: http://
Paul Nixon (pauljnixon) wrote : Posted in a previous version of this proposal | # |
Does this need anything else?
Steve Kowalik (stevenk) wrote : | # |
90 + # determine the last time something in the folder was changed
You missed one. :-)
Thanks for addressing my comments and posting screenshots -- this looks excellent, and I look forward to it landing.
Paul Nixon (pauljnixon) wrote : | # |
Abstaining from a review of my own code, which is already approved anyway. I invited myself to review accidentally.
Colin Watson (cjwatson) wrote : | # |
Sorry this has taken so long to land; I'm going through some old loggerhead merge proposals now. I was about to merge this since it's approved, but I thought the change to the _approximatedate function seemed odd, and possibly unintentional. Was there a reason you removed support for dates in the future from this? I think they can occur if the committer's clock is wrong, and in any case it shouldn't hurt to retain support for them.
Paul Nixon (pauljnixon) wrote : | # |
Hello Colin:
Good point, I think I hadn't considered the possibility of incorrect
clocks. I'd like to keep the addition of months and years, though.
Thank you,
---Paul
Review: Needs Information
Sorry this has taken so long to land; I'm going through some old loggerhead
merge proposals now. I was about to merge this since it's approved, but I
thought the change to the _approximatedate function seemed odd, and
possibly unintentional. Was there a reason you removed support for dates
in the future from this? I think they can occur if the committer's clock
is wrong, and in any case it shouldn't hurt to retain support for them.
--
https:/
You are the owner of lp:~pauljnixon/loggerhead/more_columns.
Colin Watson (cjwatson) wrote : | # |
Sure, adding months and years makes sense in this context, I think. Can you push an adjustment, then, and I can get this merged for you?
- 479. By Paul Nixon
-
Re-added support for future dates in _approximatedate.
Paul Nixon (pauljnixon) wrote : | # |
Hello Colin:
I've added support for future dates and pushed to
lp:~pauljnixon/loggerhead/more_columns . I'm sorry this took so long:
I no longer have access to the test environment that I originally
developed this on, so I had a bit of setup to do before I could start
working on this again.
Should I create a new merge request for the modifications, or resubmit
the old one somehow?
Thank you,
---Paul
On Tue, Mar 17, 2015 at 11:42 AM, Colin Watson <email address hidden> wrote:
> Sure, adding months and years makes sense in this context, I think. Can you push an adjustment, then, and I can get this merged for you?
> --
> https:/
> You are the owner of lp:~pauljnixon/loggerhead/more_columns.
Preview Diff
1 | === modified file 'loggerhead/apps/branch.py' |
2 | --- loggerhead/apps/branch.py 2012-02-08 01:50:02 +0000 |
3 | +++ loggerhead/apps/branch.py 2015-05-31 16:20:47 +0000 |
4 | @@ -93,6 +93,20 @@ |
5 | return History( |
6 | self.branch, self.graph_cache, |
7 | revinfo_disk_cache=revinfo_disk_cache, cache_key=self.friendly_name) |
8 | + |
9 | + # Before the addition of this method, clicking to sort by date from |
10 | + # within a branch caused a jump up to the top of that branch. |
11 | + def sort_url(self, *args, **kw): |
12 | + if isinstance(args[0], list): |
13 | + args = args[0] |
14 | + qs = [] |
15 | + for k, v in kw.iteritems(): |
16 | + if v is not None: |
17 | + qs.append('%s=%s' % (k, urllib.quote(v))) |
18 | + qs = '&'.join(qs) |
19 | + path_info = self._path_info.strip('/').split('?')[0] |
20 | + path_info += '?' + qs |
21 | + return self._url_base + '/' + path_info |
22 | |
23 | def url(self, *args, **kw): |
24 | if isinstance(args[0], list): |
25 | @@ -155,6 +169,7 @@ |
26 | if self.branch.get_config().get_user_option('http_serve') == 'False': |
27 | raise httpexceptions.HTTPNotFound() |
28 | self._url_base = environ['SCRIPT_NAME'] |
29 | + self._path_info = environ['PATH_INFO'] |
30 | self._static_url_base = environ.get('loggerhead.static.url') |
31 | if self._static_url_base is None: |
32 | self._static_url_base = self._url_base |
33 | |
34 | === modified file 'loggerhead/controllers/directory_ui.py' |
35 | --- loggerhead/controllers/directory_ui.py 2012-02-08 01:50:02 +0000 |
36 | +++ loggerhead/controllers/directory_ui.py 2015-05-31 16:20:47 +0000 |
37 | @@ -19,6 +19,7 @@ |
38 | import datetime |
39 | import logging |
40 | import stat |
41 | +import urllib |
42 | |
43 | from bzrlib import branch, errors |
44 | |
45 | @@ -29,18 +30,17 @@ |
46 | class DirEntry(object): |
47 | |
48 | def __init__(self, dirname, parity, branch): |
49 | - self.dirname = dirname |
50 | + self.dirname = urllib.unquote(dirname) |
51 | self.parity = parity |
52 | self.branch = branch |
53 | if branch is not None: |
54 | # If a branch is empty, bzr raises an exception when trying this |
55 | try: |
56 | - self.last_change = datetime.datetime.utcfromtimestamp( |
57 | - branch.repository.get_revision( |
58 | - branch.last_revision()).timestamp) |
59 | + self.last_revision = branch.repository.get_revision(branch.last_revision()) |
60 | + self.last_change_time = datetime.datetime.utcfromtimestamp(self.last_revision.timestamp) |
61 | except: |
62 | - self.last_change = None |
63 | - |
64 | + self.last_revision = None |
65 | + self.last_change_time = None |
66 | |
67 | class DirectoryUI(TemplatedBranchView): |
68 | """ |
69 | |
70 | === modified file 'loggerhead/controllers/inventory_ui.py' |
71 | --- loggerhead/controllers/inventory_ui.py 2013-03-27 05:29:14 +0000 |
72 | +++ loggerhead/controllers/inventory_ui.py 2015-05-31 16:20:47 +0000 |
73 | @@ -70,15 +70,27 @@ |
74 | change_dict[change.revid] = change |
75 | |
76 | for filename, entry in dir_ie.children.iteritems(): |
77 | + revid = entry.revision |
78 | + file_timestamp = change_dict[revid].timestamp |
79 | pathname = filename |
80 | - if entry.kind == 'directory': |
81 | - pathname += '/' |
82 | + contents_changed_rev = None |
83 | if path == '': |
84 | absolutepath = pathname |
85 | else: |
86 | absolutepath = path + '/' + pathname |
87 | - revid = entry.revision |
88 | - |
89 | + if entry.kind == 'directory': |
90 | + # determine the last time something in the folder was changed |
91 | + pathname += '/' |
92 | + sub_dir_id = inv.path2id(absolutepath) |
93 | + sub_dir_ie = inv[sub_dir_id] |
94 | + sub_revid_set = set() |
95 | + for sub_filename, sub_entry in sub_dir_ie.children.iteritems(): |
96 | + sub_revid_set.add(sub_entry.revision) |
97 | + for change in self._history.get_changes(list(sub_revid_set)): |
98 | + change_dict[change.revid] = change |
99 | + if(change.timestamp > file_timestamp): |
100 | + revid = change.revid |
101 | + file_timestamp = change.timestamp |
102 | # TODO: For the JSON rendering, this inlines the "change" aka |
103 | # revision information attached to each file. Consider either |
104 | # pulling this out as a separate changes dict, or possibly just |
105 | @@ -88,7 +100,7 @@ |
106 | filename=filename, executable=entry.executable, |
107 | kind=entry.kind, absolutepath=absolutepath, |
108 | file_id=entry.file_id, size=entry.text_size, revid=revid, |
109 | - change=change_dict[revid]) |
110 | + change=change_dict[revid], contents_changed=contents_changed_rev) |
111 | file_list.append(file) |
112 | |
113 | if sort_type == 'filename': |
114 | @@ -96,10 +108,11 @@ |
115 | elif sort_type == 'size': |
116 | file_list.sort(key=lambda x: x.size) |
117 | elif sort_type == 'date': |
118 | - file_list.sort(key=lambda x: x.change.date) |
119 | - |
120 | - # Always sort directories first. |
121 | - file_list.sort(key=lambda x: x.kind != 'directory') |
122 | + file_list.sort(key=lambda x: x.change.date, reverse=True) |
123 | + |
124 | + if sort_type != 'date': |
125 | + # Don't always sort directories first. |
126 | + file_list.sort(key=lambda x: x.kind != 'directory') |
127 | |
128 | return file_list |
129 | |
130 | |
131 | === modified file 'loggerhead/history.py' |
132 | --- loggerhead/history.py 2012-02-08 01:50:02 +0000 |
133 | +++ loggerhead/history.py 2015-05-31 16:20:47 +0000 |
134 | @@ -722,6 +722,7 @@ |
135 | 'revid': revision.revision_id, |
136 | 'date': datetime.datetime.fromtimestamp(revision.timestamp), |
137 | 'utc_date': datetime.datetime.utcfromtimestamp(revision.timestamp), |
138 | + 'timestamp': revision.timestamp, |
139 | 'committer': revision.committer, |
140 | 'authors': revision.get_apparent_authors(), |
141 | 'branch_nick': revision.properties.get('branch-nick', None), |
142 | |
143 | === modified file 'loggerhead/static/css/global.css' |
144 | --- loggerhead/static/css/global.css 2015-03-17 11:38:32 +0000 |
145 | +++ loggerhead/static/css/global.css 2015-05-31 16:20:47 +0000 |
146 | @@ -230,11 +230,11 @@ |
147 | } |
148 | th.datecell, |
149 | td.date { |
150 | - width: 180px; |
151 | + width: 100px; |
152 | } |
153 | th.timedate, |
154 | td.timedate2 { |
155 | - width: 80px; |
156 | + width: 60px; |
157 | } |
158 | th.downloadcell, |
159 | td.downr { |
160 | |
161 | === modified file 'loggerhead/static/css/view.css' |
162 | --- loggerhead/static/css/view.css 2012-03-19 04:37:07 +0000 |
163 | +++ loggerhead/static/css/view.css 2015-05-31 16:20:47 +0000 |
164 | @@ -5,8 +5,7 @@ |
165 | } |
166 | .viewRev { |
167 | border-right: none; |
168 | - white-space: nowrap; |
169 | - width: 1px; |
170 | + width: 20%; |
171 | padding: .3em .6em; |
172 | } |
173 | .viewComm, |
174 | |
175 | === modified file 'loggerhead/templates/directory.pt' |
176 | --- loggerhead/templates/directory.pt 2011-02-17 19:51:25 +0000 |
177 | +++ loggerhead/templates/directory.pt 2015-05-31 16:20:47 +0000 |
178 | @@ -17,16 +17,16 @@ |
179 | <div > |
180 | <table id="logentries"> |
181 | <tr class="logheader"> |
182 | - <th class="summarycell" colspan="2">Filename</th> |
183 | - <th class="datecell">Latest Rev</th> |
184 | + <th class="datecell">Filename</th> |
185 | + <th class="timedate">Latest Rev</th> |
186 | <th class="datecell">Last Changed</th> |
187 | + <th class="datecell">Committer</th> |
188 | + <th class="summarycell">Comment</th> |
189 | </tr> |
190 | |
191 | <tr class="blueRow0" tal:condition="python:name != '/'"> |
192 | - <td class="icocell"> |
193 | + <td class="summcell" colspan="5"> |
194 | <a href="../"><img tal:attributes="src python:static_url('/static/images/ico_folder_up.gif')" /></a> |
195 | - </td> |
196 | - <td class="summcell" colspan="3"> |
197 | <a href="../">..</a> |
198 | </td> |
199 | </tr> |
200 | @@ -34,32 +34,31 @@ |
201 | |
202 | <tal:branch-row tal:condition="dir/branch"> |
203 | <tr tal:attributes="class string:blueRow${dir/parity}"> |
204 | - <td class="icocell"> |
205 | + <td class="date"> |
206 | <a tal:attributes="href string:${dir/dirname}/files"> |
207 | <img tal:attributes="src python:static_url('/static/images/ico_branch.gif')" alt="Branch" /> |
208 | </a> |
209 | - </td> |
210 | - <td class="autcell"> |
211 | <a tal:attributes="href string:${dir/dirname}/files" tal:content="dir/dirname" /></td> |
212 | <td class="date"> |
213 | <a tal:attributes="href string:${dir/dirname}/revision/${dir/branch/revno}; |
214 | title string:Show revision ${dir/branch/revno}" |
215 | tal:content="dir/branch/revno"></a> |
216 | </td> |
217 | - <td class="date" tal:content="python:util.date_time(dir.last_change)"></td> |
218 | + <td class="date" tal:content="python:util._approximatedate(dir.last_change_time)"></td> |
219 | + <td class="date" tal:content="python:util.hide_email(dir.last_revision.committer) if dir.last_revision is not None else 'Nobody'"></td> |
220 | + <td class="autcell" tal:content="python:dir.last_revision.message[:50] if dir.last_revision is not None else ''"></td> |
221 | </tr> |
222 | + |
223 | </tal:branch-row> |
224 | <tal:non-branch-row tal:condition="not:dir/branch"> |
225 | <tr tal:attributes="class string:blueRow${dir/parity}"> |
226 | - <td class="icocell"> |
227 | + <td class="date"> |
228 | <a tal:attributes="href string:${dir/dirname}/"> |
229 | <img tal:attributes="src python:static_url('/static/images/ico_folder.gif')" alt="Folder" /> |
230 | </a> |
231 | - </td> |
232 | - <td class="autcell"> |
233 | <a tal:attributes="href string:${dir/dirname}/" tal:content="dir/dirname" /></td> |
234 | <td class="date"></td> |
235 | - <td class="date" tal:content="dir/last_change"></td> |
236 | + <td class="date" colspan="4" tal:content="dir/last_change"></td> |
237 | </tr> |
238 | </tal:non-branch-row> |
239 | </tal:block> |
240 | |
241 | === modified file 'loggerhead/templates/inventory.pt' |
242 | --- loggerhead/templates/inventory.pt 2012-02-02 07:42:24 +0000 |
243 | +++ loggerhead/templates/inventory.pt 2015-05-31 16:20:47 +0000 |
244 | @@ -30,7 +30,7 @@ |
245 | <tal:no-link condition="not: branch/branch_link"> |
246 | <span metal:use-macro="breadcrumbs/directory"></span> |
247 | </tal:no-link> |
248 | - <span>: <span metal:use-macro="breadcrumbs/branch" /> (revision <tal:revno content="change/revno"></tal:revno>)</span> |
249 | + <span>: <span metal:use-macro="breadcrumbs/branch" /> (Revision <tal:revno content="change/revno"></tal:revno>)</span> |
250 | </div> |
251 | </tal:block> |
252 | |
253 | @@ -54,10 +54,12 @@ |
254 | |
255 | <table id="logentries"> |
256 | <tr class="logheader"> |
257 | - <th class="summarycell"><a tal:attributes="href python:url(['/files', revid], sort='filename')">Filename</a></th> |
258 | - <th class="datecell">Latest Rev</th> |
259 | - <th class="datecell"><a tal:attributes="href python:url(['/files', revid], sort='date')">Last Changed</a></th> |
260 | - <th class="timedate"><a tal:attributes="href python:url(['/files', revid], sort='size')">Size</a></th> |
261 | + <th class="datecell"><a tal:attributes="href python:branch.sort_url(['/files', revid], sort='filename')">Filename</a></th> |
262 | + <th class="timedate">Latest Rev</th> |
263 | + <th class="datecell"><a tal:attributes="href python:branch.sort_url(['/files', revid], sort='date')">Last Changed</a></th> |
264 | + <th class="datecell">Committer</th> |
265 | + <th class="summarycell">Comment</th> |
266 | + <th class="timedate"><a tal:attributes="href python:branch.sort_url(['/files', revid], sort='size')">Size</a></th> |
267 | <th class="expandcell"></th> |
268 | <th class="expandcell"></th> |
269 | </tr> |
270 | @@ -68,11 +70,15 @@ |
271 | <img tal:attributes="src python:branch.static_url('/static/images/ico_folder_up.gif')" />..</a> |
272 | </td> |
273 | </tr> |
274 | + <tr class="blueRow0" tal:condition="python:updir is None and name != '/'"> |
275 | + <td class="summcell" colspan="6"> |
276 | + <a tal:attributes="href python:'/'.join(branch.friendly_name.split('/')[:-1])"><img tal:attributes="src python:static_url('/static/images/ico_folder_up.gif')" />..</a></td> |
277 | + </tr> |
278 | |
279 | <!-- Show this if it's a directory --> |
280 | <tal:block repeat="file filelist"> |
281 | <tr tal:attributes="class string:blueRow${repeat/file/even}" tal:condition="python:file.kind=='directory'"> |
282 | - <td class="autcell"><a tal:attributes="href python:url(['/files', revno_url, file.absolutepath])"> |
283 | + <td class="date"><a tal:attributes="href python:url(['/files', revno_url, file.absolutepath])"> |
284 | <img tal:attributes="src python:branch.static_url('/static/images/ico_folder.gif'); |
285 | title string:Go to ${file/filename}" /> |
286 | </a> |
287 | @@ -84,8 +90,10 @@ |
288 | title string:Show revision ${file/change/revno}" |
289 | tal:content="file/change/revno"></a> |
290 | </td> |
291 | - <td class="date" tal:content="python:util.date_time(file.change.utc_date)"></td> |
292 | - <td class="timedate2"></td> |
293 | + <td class="date" tal:content="python:util._approximatedate(file.change.utc_date)"></td> |
294 | + <td class="date" tal:content="python:util.hide_email(file.change.committer)"></td> |
295 | + <td class="autcell" tal:content="python:file.change.comment[:50]"></td> |
296 | + <td class="timedate2"></td><!-- not showing sizes of folders --> |
297 | <td class="expcell"><a tal:attributes="href python:url(['/changes'], start_revid=start_revid, filter_file_id=file.file_id); |
298 | title string:Show revision ${file/change/revno}"> |
299 | <img tal:attributes="src python:branch.static_url('/static/images/ico_planilla.gif')" alt="Diff" /> |
300 | @@ -96,7 +104,7 @@ |
301 | |
302 | <!-- Show this if it's a symlink --> |
303 | <tr tal:attributes="class string:blueRow${repeat/file/even}" tal:condition="python:file.kind=='symlink'"> |
304 | - <td class="autcell"><a tal:attributes="href python:url(['/view', change.revno, file.absolutepath])"> |
305 | + <td class="date"><a tal:attributes="href python:url(['/view', change.revno, file.absolutepath])"> |
306 | <img tal:attributes="src python:branch.static_url('/static/images/ico_file_flecha.gif')" alt="Symlink" /> |
307 | </a> |
308 | |
309 | @@ -107,7 +115,9 @@ |
310 | title string:Show revision ${file/change/revno}" |
311 | tal:content="file/change/revno"></a> |
312 | </td> |
313 | - <td class="date" tal:content="python:util.date_time(file.change.utc_date)"></td> |
314 | + <td class="date" tal:content="python:util._approximatedate(file.change.utc_date)"></td> |
315 | + <td class="date" tal:content="python:util.hide_email(file.change.committer)"></td> |
316 | + <td class="autcell" tal:content="python:file.change.comment[:50]"></td> |
317 | <td class="timedate2">.</td> |
318 | <td class="expcell"><a tal:attributes="href python:url(['/changes'], start_revid=start_revid, filter_file_id=file.file_id); |
319 | title string:Show revision ${file/change/revno}"> |
320 | @@ -120,7 +130,7 @@ |
321 | |
322 | <!-- Show this if it's a regular file --> |
323 | <tr tal:attributes="class string:blueRow${repeat/file/even}" tal:condition="python:file.kind=='file'"> |
324 | - <td class="autcell"><a tal:attributes="href python:url(['/view', revno_url, file.absolutepath])"> |
325 | + <td class="date"><a tal:attributes="href python:url(['/view', revno_url, file.absolutepath])"> |
326 | <img tal:attributes="src python:branch.static_url('/static/images/ico_file.gif'); |
327 | title string:View ${file/filename}" |
328 | tal:condition="python:file.executable is False" /> |
329 | @@ -136,7 +146,10 @@ |
330 | title string:Show revision ${file/change/revno}" |
331 | tal:content="file/change/revno"></a> |
332 | </td> |
333 | - <td class="date" tal:content="python:util.date_time(file.change.utc_date)"></td> |
334 | + <td class="date" tal:content="python:util._approximatedate(file.change.utc_date)"></td> |
335 | + <td class="date" tal:content="python:util.hide_email(file.change.committer)"></td> |
336 | + <td class="autcell" tal:content="python:file.change.comment[:50]"></td> |
337 | + |
338 | <td class="timedate2" tal:content="python:util.human_size(file.size)"></td> |
339 | <td class="expcell"><a tal:attributes="href python:url(['/view', revno_url, file.absolutepath]); |
340 | title string:View ${file/filename}"> |
341 | |
342 | === modified file 'loggerhead/util.py' |
343 | --- loggerhead/util.py 2012-04-28 00:57:06 +0000 |
344 | +++ loggerhead/util.py 2015-05-31 16:20:47 +0000 |
345 | @@ -73,12 +73,13 @@ |
346 | |
347 | |
348 | def _approximatedate(date): |
349 | - delta = datetime.datetime.now() - date |
350 | - if abs(delta) > datetime.timedelta(1, 0, 0): |
351 | - # far in the past or future, display the date |
352 | - return date_day(date) |
353 | + if date is None: |
354 | + return 'Never' |
355 | + delta = datetime.datetime.utcnow() - date |
356 | future = delta < datetime.timedelta(0, 0, 0) |
357 | delta = abs(delta) |
358 | + years = delta.days / 365 |
359 | + months = delta.days / 30 # This is approximate. |
360 | days = delta.days |
361 | hours = delta.seconds / 3600 |
362 | minutes = (delta.seconds - (3600*hours)) / 60 |
363 | @@ -86,7 +87,13 @@ |
364 | result = '' |
365 | if future: |
366 | result += 'in ' |
367 | - if days != 0: |
368 | + if years != 0: |
369 | + amount = years |
370 | + unit = 'year' |
371 | + elif months != 0: |
372 | + amount = months |
373 | + unit = 'month' |
374 | + elif days != 0: |
375 | amount = days |
376 | unit = 'day' |
377 | elif hours != 0: |
378 | @@ -103,7 +110,7 @@ |
379 | result += '%s %s' % (amount, unit) |
380 | if not future: |
381 | result += ' ago' |
382 | - return result |
383 | + return result |
384 | |
385 | |
386 | def _wrap_with_date_time_title(date, formatted_date): |
Broadly, this looks good, but I have a few concerns. Firstly, comments should be formatted with a space after the hash, and secondly must be complete sentences. You have added some unneeded whitespace on line 29-30 of the diff. And lastly, since this branch does make some UI changes, I'd like to see at least one screenshot of the before and after view.