Commits

Alex Willmer committed 9dbf74c

Merge <link end>.creator differentiation

Comments (0)

Files changed (5)

         Must return a list of `(field, message)` tuples, one for each problem
         detected. `field` can be `None` to indicate an overall problem with the
         ticket. Therefore, a return value of `[]` means everything is OK."""
-        
+
+
 class ITicketLinkController(Interface):
     
     def get_ends():
         """Return an iterable of field names populated in a new ticket created
         as a linked ticket."""
 
+
 class IMilestoneChangeListener(Interface):
     """Extension point interface for components that require notification
     when milestones are created, modified, or deleted."""
                 continue
             field['custom'] = True
             fields.append(field)
-            
+
         # fields for links
         for controller in self.link_controllers:
             for end1, end2 in controller.get_ends():
                     self._add_link_field(end2, controller, fields)
 
         return fields
-    
+
     reserved_field_names = ['report', 'order', 'desc', 'group', 'groupdesc',
                             'col', 'row', 'format', 'max', 'page', 'verbose',
                             'comment', 'or']
-							
+
     def _add_link_field(self, end, controller, fields):
         label = controller.render_end(end)
         copy_fields = controller.get_copy_fields(end)
         if end in [f['name'] for f in fields]:
-            self.log.warning('Duplicate field name "%s" (ignoring)', end)
+            self.log.warning('Duplicate field name "%s" (ignoring)',
+                             end)
             return
-        field = {'name': end, 'type': 'link', 'label': label, 
+        field = {'name': end, 'type': 'link', 'label': label,
+                 'creator': controller.is_creator(end),
                  'link': True, 'format': 'wiki', 'copy_fields': copy_fields}
         fields.append(field)   
 
     
     def __init__(self):
         self._links, self._labels, \
-        self._validators, self._blockers, \
+        self._validators, self._creators, self._blockers, \
         self._copy_fields = self._get_links_config()
 
     def get_ends(self):
     def is_blocker(self, end):
         return self._blockers[end]
     
+    def is_creator(self, end):
+        return self._creators[end]
+    
     def get_copy_fields(self, end):
         if end in self._copy_fields:
             return self._copy_fields[end]
         links = []
         labels = {}
         validators = {}
+        creators = {}
         blockers = {}
         copy_fields = {}
         
             blockers[end1] = config.getbool(end1 + '.blocks', default=False)
             if end2:
                 blockers[end2] = config.getbool(end2 + '.blocks', default=False)
+
+            creators[end1] = config.getbool(end1 + '.creator', default=True)
+            if end2:
+                creators[end2] = config.getbool(end2 + '.creator', default=True)
             
             # <end>.copy_fields may be absent or intentionally set empty.
             # config.getlist() will return [] in either case, so check that
                     if cf_key in config:
                         copy_fields[end] = config.getlist(cf_key)
             
-        return links, labels, validators, blockers, copy_fields
+        return links, labels, validators, creators, blockers, copy_fields
     
     def find_blockers(self, ticket, field, blockers):
         ticket_system = TicketSystem(self.env)

trac/ticket/templates/ticket_box.html

     <br py:if="not ticket.description" style="clear: both" />
   </div>
   <div class="linked">
-    <h3>Linked Issues (${len(linked_tickets)})</h3>
-    <table class="listing tickets">
+    <h3>Linked Tickets (<span id="linked-ticket-count">${len(linked_tickets)}</span>)</h3>
+    <table id="linked-tickets" class="listing tickets">
       <thead>
         <tr style="white-space: nowrap;">
           <th>Link</th>
           <th>Last modified</th>
         </tr>
       </thead>
-      <tbody>
-        <tr py:for="link, tkt_id, ticket in linked_tickets">
-          <td class="ticket_link">${link}</td>
-          <td class="ticket">${tkt_id}</td>
-          <td class="component">${ticket.component}</td>
-          <td class="version">${ticket.status}</td>
-          <td class="summary">${shorten_line(ticket.summary)}</td>
-          <td class="date">${dateinfo(ticket.changetime)}</td>
-        </tr>
-        <tr py:for="link, tkt_id in linked_rejects">
-          <td class="ticket_link">${link}</td>
-          <td class="ticket">${tkt_id}</td>
-          <td class="reject" colspan="4">Ticket details unavailable</td>
-        </tr>
+      <tbody py:if="linked_tickets or linked_rejects">
+        <xi:include href="ticket_entries.html"
+                    py:with="tickets = linked_tickets;
+                             rejects = linked_rejects" />
       </tbody>
     </table>
   </div>
-  <div py:if="'TICKET_CREATE' in perm(ticket.resource)">
-    <form id="newlinked" method="get" action="${context.href.newticket()}">
-      <input type="hidden" id="linked-val" name="linked_val" value="${ticket.id}" />
-      <label for="linked-end">New</label>
-      <select id="linked-end" name="linked_end">
-        <option py:for="link_label, link_end in newlinked_options"
+  <div py:if="'TICKET_CREATE' in perm(ticket.resource)" class="linked">
+    <form id="newlinked" method="get" action="${context.href.newticket()}"><div>
+      <input type="hidden" id="newlinked-linked-val" class="linked-val" name="linked_val" value="${ticket.id}" />
+      <label for="newlinked-linked-end">New</label>
+      <select id="newlinked-linked-end" class="linked-end" name="linked_end">
+        <option py:for="link_label, link_end in newticket_link_options"
                 value="${link_end}">${link_label} ticket</option>
       </select>
       <input type="submit" name="create" value="Create" title="Create new linked ticket" />
-    </form> 
+    </div></form>
   </div>
 </div>

trac/ticket/templates/ticket_entries.html

+<!--! Template for generating rows corresponding to tickets -->
+<html xmlns="http://www.w3.org/1999/xhtml"
+      xmlns:py="http://genshi.edgewall.org/"
+      xmlns:xi="http://www.w3.org/2001/XInclude" py:strip="">
+
+  <tr py:for="link, tkt_id, ticket in tickets">
+    <td class="ticket_link">${link.label}</td>
+    <td class="ticket">${tkt_id}</td>
+    <td class="component">${ticket.component}</td>
+    <td class="version">${ticket.status}</td>
+    <td class="summary">${shorten_line(ticket.summary)}</td>
+    <td class="date">${dateinfo(ticket.changetime)}</td>
+  </tr>
+  <tr py:for="link, tkt_id in rejects">
+    <td class="ticket_link">${link.label}</td>
+    <td class="ticket">${tkt_id}</td>
+    <td class="reject" colspan="4">Ticket details unavailable</td>
+  </tr>
+</html>

trac/ticket/web_ui.py

 
         data['fields'] = fields
 
+        self._prepare_ticket_links(req, ticket, data)
+
         add_stylesheet(req, 'common/css/ticket.css')
         add_script(req, 'common/js/folding.js')
         Chrome(self.env).add_wiki_toolbars(req)
 
         self._insert_ticket_data(req, ticket, data,
                                  get_reporter_id(req, 'author'), field_changes)
+        self._prepare_ticket_links(req, ticket, data)
 
         mime = Mimeview(self.env)
         format = req.args.get('format')
         return 'ticket.html', data, None
 
     def _prepare_data(self, req, ticket, absurls=False):
-        ticket_sys = TicketSystem(self.env)
-        context = Context.from_request(req, ticket.resource, absurls=absurls)
-        link_fields = [field for field in ticket.fields 
-                             if field['type'] == 'link']
-        # Create a pairwise list of (label, end_on_the_other_ticket)
-        # A ticket created using a given label will then be linked to this
-        # ticket by the chosen end
-        new_linked = [(field['label'], ticket_sys.other_end(field['name']))
-                      for field in link_fields]
-        
-        linked_tickets = []
-        linked_rejects = []
-        for field in link_fields:
-            for tkt_id in ticket_sys.parse_links(ticket[field['name']]):
-                tkt_fmt = format_to_oneliner(self.env, context, 
-                                             '#%s' % tkt_id)
-                try:
-                    tkt = Ticket(self.env, tkt_id)
-                    linked_tickets.append((field['label'], tkt_fmt, tkt))
-                except ResourceNotFound:
-                    linked_rejects.append((field['label'], tkt_fmt))
-                
         return {'ticket': ticket,
-                'linked_tickets': linked_tickets,
-                'linked_rejects': linked_rejects,
-                'newlinked_options': new_linked,
-                'context': context,
+                'context': Context.from_request(req, ticket.resource,
+                                                absurls=absurls),
                 'preserve_newlines': self.must_preserve_newlines}
 
     def _toggle_cc(self, req, cc):
             'change_preview': change_preview,
         })
 
+    def _prepare_ticket_links(self, req, ticket, data):
+        """Add linked ticket sequences to template `data`.
+        """
+        ticket_sys = TicketSystem(self.env)
+        link_fields = [field for field in ticket.fields
+                             if field['type'] == 'link']
+        # Create a pairwise list of (label, end_on_the_other_ticket)
+        # A ticket created using a given label will then be linked to this
+        # ticket by the chosen end
+        newticket_link_options = [(field['label'], ticket_sys.other_end(field['name']))
+                                  for field in link_fields if field['creator']]
+
+        # For editting this ticket keep the pairing of labels/ends as is
+        link_options = [(field['label'], field['name'])
+                        for field in link_fields]
+
+        linked_tickets = []
+        linked_rejects = []
+        for field in link_fields:
+            for tkt_id in ticket_sys.parse_links(ticket[field['name']]):
+                tkt_fmt = format_to_oneliner(self.env, data['context'],
+                                             '#%s' % tkt_id)
+                try:
+                    tkt = Ticket(self.env, tkt_id)
+                    linked_tickets.append((field, tkt_fmt, tkt))
+                except ResourceNotFound:
+                    linked_rejects.append((field, tkt_fmt))
+
+        data.update({
+            'linked_tickets': linked_tickets,
+            'linked_rejects': linked_rejects,
+            'newticket_link_options': newticket_link_options,
+            'link_options': link_options,
+        })
+
     def rendered_changelog_entries(self, req, ticket, when=None):
         """Iterate on changelog entries, consolidating related changes
         in a `dict` object.