Edgewall Software

Changes between Initial Version and Version 1 of TracDev/PluginDevelopment/ExtensionPoints/trac.ticket.roadmap.ITicketGroupStatsProvider

Jul 30, 2014, 5:20:15 PM (8 years ago)
Peter Suter


  • TracDev/PluginDevelopment/ExtensionPoints/trac.ticket.roadmap.ITicketGroupStatsProvider

    v1 v1  
     1== Extension Point : ''ITicketGroupStatsProvider'' ==
     3||'''Interface'''||''ITicketGroupStatsProvider''||'''Since'''||[wiki:TracDev/ApiChanges/0.11#ITicketGroupStatsProvider 0.11]||
     4||'''Module'''||''trac.ticket.roadmap''||'''Source'''||[source:trunk/trac/ticket/roadmap.py#/ITicketGroupStatsProvider roadmap.py]||
     6The ''ITicketGroupStatsProvider'' allows components to provide alternate ways to compute Milestone statistics.
     8== Purpose ==
     10The [TracRoadmap roadmap] provides a view on the [TracTickets ticket] milestones with  aggregated group statistics displayed as a milestone progress bar. The default grouping simply shows the ratio between active and resolved tickets. It is possible to [TracRoadmapCustomGroups customise] the ticket grouping and have multiple ticket statuses shown on the progress bar. Plugins can further customize the roadmap system to modify the milestone completion progress bars by changing the way ticket statistics are collected.
     12The main purpose for this interface is to allow plugins to incorporate more information into the milestone completion calculations (e.g. tracked hours).
     14Note that for simply having more ticket groups displayed, a change of [TracIni#milestone-groups-section configuration] is enough and no new plugin is needed.
     16== Usage ==
     18Implementing the interface follows the standard guidelines found in [wiki:TracDev/ComponentArchitecture] and of course [wiki:TracDev/PluginDevelopment].
     20The component has to be configured as the [TracIni#milestone-section "[milestone]"] `stats_provider` (to use it when viewing individual milestones) and / or the [TracIni#roadmap-section "[roadmap]"] `stats_provider` (to use it when viewing the roadmap). Trac then automatically calls the `get_ticket_group_stats` method to retrieve a `TicketGroupStats` object for a given group of tickets.
     22Typically this consists of these steps:
     23* Create a new instance by calling `stat = TicketGroupStats(title, unit)` where:
     24  * `title` is the title of the statistic (e.g. `'ticket status'` as in ''Ticket status by milestone'').
     25  * `unit` is the name of the unit for the statistic (e.g. `'tickets'` as in ''Total number of tickets'', or `'hours'` as in ''Total number of hours'').
     26* Calculate some statistics e.g. by quering the database.
     27* Add intervalls to make up the progress bar by calling `stat.add_interval(title, count, qry_args, css_class, overall_completion=None)` where:
     28  * `title` is the name of this interval displayed in front of the unit name (e.g. `'closed'`) as in ''Close tickets'').
     29  * `count` is the number of units in this interval.
     30  * `qry_args` is a dict of extra parameters used in a TracQuery to link to tickets in this interval.
     31  * `css_class` is the css class that will be used to display this interval.
     32  * `overall_completion` can optionally be set to `True` to make this interval count towards overall completion of this group of tickets.
     33* Call `stat.refresh_calcs()` to calculate the interval percentages so they add up to 100%, and then `return stat`.
     35== Examples ==
     37Projects might for some reason want to group tickets and see progress by ''ticket owner'', and count only those tickets as completed where the owner is done with ''all'' tickets:
     39from trac.core import Component, implements
     40from trac.ticket.roadmap import ITicketGroupStatsProvider, TicketGroupStats
     42class TicketOwnerGroupStats(Component):
     43    implements(ITicketGroupStatsProvider)
     45    def get_ticket_group_stats(self, ticket_ids):
     46        total_cnt = len(ticket_ids)
     47        stat = TicketGroupStats('ticket owner', 'tickets')
     48        if total_cnt:
     49            for owner, count, closed in self.env.db_query("""
     50                    SELECT
     51                        owner,
     52                        count(owner),
     53                        SUM(CASE WHEN status = 'closed' THEN 1 ELSE 0 END) as closed
     54                    FROM ticket
     55                    WHERE id IN (%s) GROUP BY owner
     56                    """ % ",".join(str(x) for x in sorted(ticket_ids))):
     57                label = owner
     58                query_args = {'owner': [owner]}
     59                css_class = owner
     60                stat.add_interval(label, count, query_args, css_class, count == closed)
     61        stat.refresh_calcs()
     62        return stat
     65== Available Implementations ==
     67* `trac.ticket.roadmap.DefaultTicketGroupStatsProvider`:
     69* th:RoadmapHoursPlugin: Shows intervals ''Worked hours'' and ''Remaining hours''.
     70* th:SumStatsPlugin: Sums up a configurable custom ticket field.
     71* th:CustomRoadmapPlugin: Automatically customizes CSS.
     73== Additional Information and References ==
     75 * [apiref:trac.ticket.roadmap.ITicketGroupStatsProvider-class epydoc]
     76 * [apidoc:api/trac_ticket_roadmap#trac.ticket.roadmap.ITicketGroupStatsProvider API Reference]
     77 * Related tickets:
     78   * #6232 refactor `DefaultTicketGroupStatsProvider` so subclasses could easily reuse some parts of its logic.
     79   * #1534 weighted tickets for progress bar.
     80 * Archived discussions:
     81   * [Trac-ML:5084 Discussions] [Trac-ML:5099 during] [Trac-ML:5212 development]
     83=== API History
     84 * [wiki:TracDev/ApiChanges/0.11#ITicketGroupStatsProvider 0.11] introduced the interface (#2314)
     85 * 0.12 [changeset:10661 removed] the [changeset:6011 deprecated] `countsToProg` argument to `TicketGroupStats.add_interval()`.