Commits

Anonymous committed 3c90a4b

Timeline: highlight yet unseen events with a green sidebar on the left.

Patch contributed by Mikael Relbe, thanks!

Closes #9282.

Comments (0)

Files changed (3)

trac/htdocs/css/timeline.css

  font-size: 105%;
  margin: 2em 0 .5em;
 }
-dl { line-height: 1.3em; margin-left: 1em }
+dl {
+ line-height: 1.3em;
+ margin-left: 1em;
+}
+dl.unread { 
+ margin-left: 0.38em;
+ border-left: 0.31em solid #c0f0c0;
+ padding-left: 0.31em;
+}
+
 dt { background: 3px 4px no-repeat; padding: 0 }
 dt :link, dt :visited {
  background: 3px 3px no-repeat;
 dt.highlight { background-color: #ffa; } 
 dd { 
  font-size: 80%;
- margin: 0 0 .75em 5.5em;
+ margin: 0 0 .75em 5.8em;
  padding: 0;
  color: #776;
 }

trac/timeline/templates/timeline.html

 
       <py:for each="day, events in groupby(events, key=lambda e: format_date(e.date))">
         <h2>${day}: ${day == today and _("Today") or day == yesterday and _("Yesterday") or None}</h2>
-        <dl>
+        <dl py:for="unread, events in groupby(events, key=lambda e: lastvisit and lastvisit &lt; e.dateuid)"
+            class="${unread and 'unread' or None}">
           <py:for each="event in events"
             py:with="highlight = precision and precisedate and timedelta(0) &lt;= (event.date - precisedate) &lt; precision">
-            <dt class="${classes(event.kind, highlight=highlight)}">
+            <dt class="${classes(event.kind, highlight=highlight, unread=unread)}">
               <a href="${event.render('url', context)}" py:choose="">
                 <py:when test="event.author"><i18n:msg params="time, title, author">
                   <span class="time">${format_time(event.date, str('%H:%M'))}</span> ${event.render('title', context)}

trac/timeline/web_ui.py

 
         format = req.args.get('format')
         maxrows = int(req.args.get('max', format == 'rss' and 50 or 0))
+        lastvisit = int(req.session.get('timeline.lastvisit', '0'))
+
+        # indication of new events is unchanged when form is updated by user
+        revisit = any([a in req.args for a in ['update', 'from', 'daysback',
+                                               'author']])
+        if revisit:
+            lastvisit = int(req.session.get('timeline.nextlastvisit',
+                                            lastvisit))
 
         # Parse the from date and adjust the timestamp to the last second of
         # the day
                                          tzinfo=req.tz),
                 'precisedate': precisedate, 'precision': precision,
                 'events': [], 'filters': [],
-                'abbreviated_messages': self.abbreviated_messages}
+                'abbreviated_messages': self.abbreviated_messages,
+                'lastvisit': lastvisit}
 
         available_filters = []
         for event_provider in self.event_providers:
         else:
             req.session['timeline.daysback'] = daysback
             req.session['timeline.authors'] = authors
+            # store lastvisit
+            if events and not revisit:
+                lastviewed = to_utimestamp(events[0]['date'])
+                req.session['timeline.lastvisit'] = max(lastvisit, lastviewed)
+                req.session['timeline.nextlastvisit'] = lastvisit
             html_context = Context.from_request(req)
             html_context.set_hints(wiki_flavor='oneliner', 
                                    shorten_lines=self.abbreviated_messages)