=== htdocs/css/timeline.css
==================================================================
|
|
|
|
| 27 | 27 | dt .time { color: #777 } |
| 28 | 28 | dd { font-size: 80%; margin: 0 0 .5em 5em; padding: 0 } |
| 29 | 29 | |
| | 30 | |
| 30 | 31 | /* Apply icon background-image twice to avoid hover-flicker in IE/Win */ |
| 31 | 32 | dt.changeset, dt.changeset a { background-image: url(../changeset.png) !important } |
| 32 | 33 | dt.newticket, dt.newticket a { background-image: url(../newticket.png) !important } |
| 33 | 34 | dt.closedticket, dt.closedticket a { background-image: url(../closedticket.png) !important } |
| 34 | 35 | dt.wiki, dt.wiki a { background-image: url(../wiki.png) !important } |
| 35 | 36 | dt.milestone, dt.milestone a { background-image: url(../milestone.png) !important } |
| | 37 | dt.ticketcomment a { font-size: 80%; color: #555 } |
| | 38 | dd.ticketcomment { font-size: 70%; color: #555; margin: 0 0 .5em 5em; padding: 0 } |
| 36 | 39 | |
| | 40 | |
| 37 | 41 | .diff-unmod { color: #000 } |
| 38 | 42 | .diff-rem { color: #e00 } |
| 39 | 43 | .diff-add { color: #2e2 } |
=== templates/timeline.cs
==================================================================
|
|
|
|
| 18 | 18 | <?cs if:trac.acl.TICKET_VIEW ?><div class="field"> |
| 19 | 19 | <input type="checkbox" id="ticket" name="ticket" <?cs |
| 20 | 20 | if:timeline.ticket ?>checked="checked"<?cs /if ?> /> |
| 21 | | <label for="ticket">Ticket changes</label> |
| | 21 | <label for="ticket">Ticket status changes</label> |
| | 22 | <input type="checkbox" id="ticket_comments" name="ticket_comments" <?cs |
| | 23 | if:timeline.ticket_comments ?>checked="checked"<?cs /if ?> /> |
| | 24 | <label for="ticket_comments">Ticket contributions</label> |
| 22 | 25 | </div><?cs /if ?> |
| 23 | 26 | <?cs if:trac.acl.CHANGESET_VIEW ?><div class="field"> |
| 24 | 27 | <input type="checkbox" id="changeset" name="changeset" <?cs |
| … |
… |
|
| 55 | 58 | <a href="<?cs var:url ?>"><span class="time"><?cs |
| 56 | 59 | var:item.time ?> :</span> <?cs var:msg ?></a> |
| 57 | 60 | </dt> |
| 58 | | <?cs if:descr ?><dd><?cs var:descr ?></dd><?cs /if ?> |
| | 61 | <?cs if:descr ?><dd class="<?cs var:type ?>"><?cs var:descr ?></dd><?cs /if ?> |
| 59 | 62 | <?cs /def ?> |
| 60 | 63 | |
| 61 | 64 | <?cs each:item = timeline.items ?> |
| … |
… |
|
| 84 | 87 | <?cs elif:item.type == #6 ?><!-- milestone --> |
| 85 | 88 | <?cs call:tlitem(item.href, 'milestone', |
| 86 | 89 | '<em>Milestone '+$item.message+'</em> reached', '') ?> |
| | 90 | <?cs elif:item.type == #7 ?><!-- Ticket comment --> |
| | 91 | <?cs call:tlitem(item.href, 'ticketcomment', |
| | 92 | 'Ticket <em>#'+$item.idata+'</em> contribution by '+$item.author, $item.message) ?> |
| 87 | 93 | <?cs /if ?> |
| 88 | 94 | <?cs /each ?> |
| 89 | 95 | <?cs if:len(timeline.items) ?></dl><?cs /if ?> |
=== trac/Timeline.py
==================================================================
|
|
|
|
| 34 | 34 | template_name = 'timeline.cs' |
| 35 | 35 | template_rss_name = 'timeline_rss.cs' |
| 36 | 36 | |
| 37 | | def get_info (self, start, stop, maxrows, tickets, |
| | 37 | def get_info (self, start, stop, maxrows, tickets, ticket_comments, |
| 38 | 38 | changeset, wiki, milestone): |
| 39 | 39 | cursor = self.db.cursor () |
| 40 | 40 | |
| 41 | 41 | tickets = tickets and self.perm.has_permission(perm.TICKET_VIEW) |
| | 42 | ticket_comments = ticket_comments and self.perm.has_permission(perm.TICKET_VIEW) |
| 42 | 43 | changeset = changeset and self.perm.has_permission(perm.CHANGESET_VIEW) |
| 43 | 44 | wiki = wiki and self.perm.has_permission(perm.WIKI_VIEW) |
| 44 | 45 | milestone = milestone and self.perm.has_permission(perm.MILESTONE_VIEW) |
| … |
… |
|
| 52 | 53 | REOPENED_TICKET = 4 |
| 53 | 54 | WIKI = 5 |
| 54 | 55 | MILESTONE = 6 |
| | 56 | TICKET_COMMENT = 7 |
| 55 | 57 | |
| 56 | 58 | q = [] |
| 57 | 59 | if changeset: |
| … |
… |
|
| 90 | 92 | "name AS message, '' AS author " |
| 91 | 93 | "FROM milestone WHERE time>=%s AND time<=%s" % |
| 92 | 94 | (start, stop)) |
| | 95 | if ticket_comments: |
| | 96 | q.append("SELECT time, ticket AS idata, '' AS tdata, 7 AS type, " |
| | 97 | "newvalue AS message, author AS author " |
| | 98 | "FROM ticket_change WHERE field = 'comment' " |
| | 99 | "AND time>=%s AND time<=%s" % (start, stop)) |
| 93 | 100 | |
| 94 | 101 | q_str = string.join(q, ' UNION ALL ') |
| 95 | 102 | q_str += ' ORDER BY time DESC' |
| … |
… |
|
| 100 | 107 | |
| 101 | 108 | # Make the data more HDF-friendly |
| 102 | 109 | info = [] |
| | 110 | tickets = {} |
| 103 | 111 | while 1: |
| 104 | 112 | row = cursor.fetchone() |
| 105 | 113 | if not row: |
| … |
… |
|
| 163 | 171 | elif item['type'] == MILESTONE: |
| 164 | 172 | item['href'] = self.env.href.milestone(item['message']) |
| 165 | 173 | item['message'] = util.escape(item['message']) |
| 166 | | else: # TICKET |
| | 174 | else: # all the TICKET types |
| 167 | 175 | item['href'] = self.env.href.ticket(item['idata']) |
| | 176 | if item['type'] == TICKET_COMMENT: |
| | 177 | # The following would be ok if there would be a cost effective way |
| | 178 | # to get that change number... |
| | 179 | # item['href'] += '#change_%d' % item['change'] |
| | 180 | pass |
| | 181 | else: |
| | 182 | tickets[(item['idata'], item['time'])] = 1 |
| 168 | 183 | msg = item['message'] |
| 169 | 184 | item['shortmsg'] = util.escape(util.shorten_line(msg)) |
| 170 | 185 | item['message'] = wiki_to_oneliner( |
| … |
… |
|
| 182 | 197 | item['message.rss'] = util.escape(item['message'] or '') |
| 183 | 198 | |
| 184 | 199 | info.append(item) |
| 185 | | return info |
| | 200 | # Ok, the following line is maybe not Python 2.1 friendly, I don't know... |
| | 201 | # return [ i for i in info if i['type'] != 7 or not tickets.has_key((i['idata'], i['time'])) ] |
| | 202 | info2 = [] |
| | 203 | for item in info: |
| | 204 | if item['type'] != 7 or not tickets.has_key((item['idata'], item['time'])): |
| | 205 | info2.append(item) |
| | 206 | return info2 |
| 186 | 207 | |
| 187 | 208 | def render (self): |
| 188 | 209 | self.perm.assert_permission(perm.TIMELINE_VIEW) |
| … |
… |
|
| 214 | 235 | |
| 215 | 236 | wiki = self.args.has_key('wiki') |
| 216 | 237 | ticket = self.args.has_key('ticket') |
| | 238 | ticket_comments = self.args.has_key('ticket_comments') |
| 217 | 239 | changeset = self.args.has_key('changeset') |
| 218 | 240 | milestone = self.args.has_key('milestone') |
| 219 | 241 | if not (wiki or ticket or changeset or milestone): |
| … |
… |
|
| 223 | 245 | self.req.hdf.setValue('timeline.wiki', 'checked') |
| 224 | 246 | if ticket: |
| 225 | 247 | self.req.hdf.setValue('timeline.ticket', 'checked') |
| | 248 | if ticket_comments: |
| | 249 | self.req.hdf.setValue('timeline.ticket_comments', 'checked') |
| 226 | 250 | if changeset: |
| 227 | 251 | self.req.hdf.setValue('timeline.changeset', 'checked') |
| 228 | 252 | if milestone: |
| 229 | 253 | self.req.hdf.setValue('timeline.milestone', 'checked') |
| 230 | 254 | |
| 231 | | info = self.get_info (start, stop, maxrows, ticket, |
| | 255 | info = self.get_info (start, stop, maxrows, ticket, ticket_comments, |
| 232 | 256 | changeset, wiki, milestone) |
| 233 | 257 | util.add_dictlist_to_hdf(info, self.req.hdf, 'timeline.items') |
| 234 | 258 | self.req.hdf.setValue('title', 'Timeline') |