示例#1
0
    def expand_macro(self, formatter, name, content):
        req = formatter.req
        # Analyze the arguments list, that should be in content
        args = content.split(',')
        if len(args) == 0:
            raise TracError("No argument provided for %s." %
                            self.__class__.__name__)

        # The first must be the type of the chart
        chart_type = self._get_chart_type(args[0])
        # The second the Sprint
        sprint_name = self._get_sprint(args[1])
        width, height = self._get_dimensions(args[2:])
        filter_by = None
        if len(args) >= 4:
            filter_by = args[3]

        chart_params = dict(sprint_name=sprint_name,
                            width=width,
                            height=height,
                            filter_by=filter_by)
        debug(self.env, "Params: %s" % chart_params)
        chart = ChartGenerator(self.env).get_chartwidget(
            chart_type, **chart_params)
        chart.prepare_rendering(req)
        return html.DIV(chart.display())
示例#2
0
 def ticket_changed(self, ticket, comment, author, old_values):
     ticket = AgiloTicket.as_agilo_ticket(ticket)
     generator = ChartGenerator(self.env)
     # AT: this will only work if the task has been explicitly planned for
     # the sprint, otherwise it won't update. The sprint change is good for
     # task containers.
     # if ticket[Key.SPRINT]:
     if ticket[Key.SPRINT] or ticket.is_writeable_field(Key.REMAINING_TIME):
         sprint = self._get_sprint_name(ticket)
         generator.invalidate_cache(sprint_name=sprint)
     if old_values.get(Key.SPRINT) and old_values[Key.SPRINT] != ticket[Key.SPRINT]:
         generator.invalidate_cache(sprint_name=old_values[Key.SPRINT])
示例#3
0
    def _add_charts_to_template_data(self, req, current_sprint_name, data):
        if current_sprint_name is None:
            # If we don't have at least one running sprint, we can not display
            # any chart.
            data['burndown'] = FakeWidget(self.env, '')
            data['points'] = FakeWidget(self.env, '')
            data['pie'] = FakeWidget(self.env, '')
            data['ticket_stats'] = FakeWidget(self.env, '')
            return
        cached_data = dict()
        if current_sprint_name not in [None, '']:
            backlog = self._get_sprint_backlog(sprint_name=current_sprint_name)
            cached_data = dict(tickets=backlog)

        # Hour Burndown Chart
        chart_generator = ChartGenerator(self.env)
        get_widget = chart_generator.get_chartwidget
        widget = get_widget(ChartType.BURNDOWN,
                            width=680,
                            height=350,
                            sprint_name=current_sprint_name,
                            cached_data=cached_data)
        widget.prepare_rendering(req)
        data['burndown'] = widget

        # Story Point Burndown Chart
        chart_generator = ChartGenerator(self.env)
        get_widget = chart_generator.get_chartwidget
        widget = get_widget(ChartType.POINT_BURNDOWN,
                            width=680,
                            height=350,
                            sprint_name=current_sprint_name,
                            cached_data=cached_data)
        widget.prepare_rendering(req)
        data['points'] = widget

        widget = get_widget(ChartType.SPRINT_RESOURCES_STATS,
                            width=300,
                            height=300,
                            sprint_name=current_sprint_name,
                            cached_data=cached_data)
        widget.prepare_rendering(req)
        data['pie'] = widget

        widget = get_widget(ChartType.SPRINT_TICKET_STATS,
                            width=300,
                            height=300,
                            sprint_name=current_sprint_name)
        widget.prepare_rendering(req)
        data['ticket_stats'] = widget
示例#4
0
 def testTeamMetricsChartContainsAllMetricsDataForMultipleSeries(self):
     self.env.compmgr.enabled[MetricsChartGenerator] = True
     today = now()
     self._add_metrics(self.sprint, **{Key.VELOCITY: 10})
     start_sprint2 = today - timedelta(days=30)
     sprint2 = self.teh.create_sprint(name='Sprint 2', start=start_sprint2, 
                                      duration=20, team=self.sprint.team)
     self._add_metrics(sprint2, **{Key.ESTIMATED_VELOCITY: 7})
     start_sprint3 = today - 2 * timedelta(days=30)
     sprint3 = self.teh.create_sprint(name='Sprint 3', start=start_sprint3,
                                      duration=20, team=self.sprint.team)
     self._add_metrics(sprint3, **{Key.VELOCITY: 5})
     self._add_metrics(sprint3, **{Key.ESTIMATED_VELOCITY: 9})
     
     widget = ChartGenerator(self.env).get_chartwidget(ChartType.TEAM_METRICS, 
                   team_name=self.sprint.team.name, metric_names=[Key.ESTIMATED_VELOCITY, Key.VELOCITY])
     self.assert_equals(['Sprint 3', 'Sprint 2', self.sprint.name], widget.data['sprint_names'])
     metrics = widget.data['metrics']
     self.assert_equals(2, len(metrics))
     
     velocity_label, velocity_data = metrics[0]
     self.assert_equals(get_label(Key.ESTIMATED_VELOCITY), velocity_label)
     self.assert_equals([(0, 9), (1, 7)], velocity_data)
     
     velocity_label, velocity_data = metrics[1]
     self.assert_equals(get_label(Key.VELOCITY), velocity_label)
     self.assert_equals([(0, 5), (2, 10)], velocity_data)
示例#5
0
文件: admin.py 项目: nagyist/agilo
    def detail_save_view(self, req, cat, page, name):
        team_member = req.args.get('team_member') or req.args.get('new_team_member')
        if team_member:
            # save from team member view
            return self.member_save(req, cat, page, name)

        if name=='unassigned':
            team = None
        else:
            team = self.tm.get(name=name)
            if not team:
                return req.redirect(req.href.admin(cat, page))

        if req.args.get('delete'):
            for member_name in req.args.getlist('delete'):
                member = self.tmm.get(name=member_name)
                if team:
                    member.team = None
                    self.tmm.save(member)
                else:
                    self.tmm.delete(member)
            
            # removing members will reduce the capacity, hence the ideal 
            # burndown must be recalculated
            ChartGenerator(self.env).invalidate_cache()
            return req.redirect(req.href.admin(cat, page, name))


        team.description = req.args.get('description')
        self.tm.save(team)
        return req.redirect(req.href.admin(cat, page))
示例#6
0
文件: admin.py 项目: nagyist/agilo
 def member_save(self, req, cat, page, name):
     if req.args.get('createUser_cancel'):
         self.redirect_to_team_view_page(req, cat, page, name)
     team = self.tm.get(name=name)
     
     member_name = req.args.get('team_member') or req.args.get('new_team_member')
     team_member = self._get_or_create_team_member_without_saving(req, member_name, team)
     
     if self.show_confirmation_user_creation(req, team_member.name):
         data = {'view': 'create_user_confirm', 
                 'user_name': team_member.name, 'team_name': team.name,
                 'member_description' : team_member.description}
         return 'agilo_admin_team.html', data
     
     query_params = {}
     if self.perform_user_creation(req):
         self.create_user_and_grant_permissions(req, team_member)
         query_params = dict(team_member=team_member.name)
     else:
         try:
             team_member.capacity = [float(req.args.get('ts_%d' % i) or '0') for i in range(7)]
         except ValueError:
             # TODO: Enhance error handling
             add_warning(req, 'Could not parse time value')
             self.redirect_to_team_view_page(req, cat, page, name)
     
     self.tmm.save(team_member)
     # capacity may have changed - hence the ideal burndown is different
     ChartGenerator(self.env).invalidate_cache()
     self.redirect_to_team_view_page(req, cat, page, name, **query_params)
示例#7
0
文件: web_ui.py 项目: nagyist/agilo
    def _get_and_prepare_burndown_chart_if_neccessary(self, req, backlog):
        if not backlog.is_sprint_backlog():
            return {}

        sprint = backlog.sprint()
        get_widget = ChartGenerator(self.env).get_chartwidget
        widget = get_widget(ChartType.BURNDOWN, sprint_name=sprint.name)
        widget.prepare_rendering(req)
        return dict(chart=widget)
示例#8
0
    def testSprintTicketStatsChartUsesAliases(self):
        self.env.compmgr.enabled[SprintTicketStatsChartGenerator] = True
        self.teh.create_ticket(Type.USER_STORY, {Key.SPRINT: self.sprint.name})

        get_widget = ChartGenerator(self.env).get_chartwidget
        widget = get_widget(ChartType.SPRINT_TICKET_STATS,
                            sprint_name=self.sprint.name)

        chart_labels = set([item[1] for item in widget.data['labels']])
        self.assert_equals(set(['User Story', 'Task']), chart_labels)
示例#9
0
文件: web_ui.py 项目: nagyist/agilo
 def _get_charts(self, req, team, available_metrics):
     chart_widgets = []
     
     grouped_metrics = self._get_metric_groups(available_metrics)
     get_widget = ChartGenerator(self.env).get_chartwidget
     for metric_names in grouped_metrics:
         widget = get_widget(ChartType.TEAM_METRICS, team_name=team.name, 
                             metric_names=metric_names)
         widget.prepare_rendering(req)
         chart_widgets.append(widget)
     return chart_widgets
示例#10
0
 def get_widget(self,
                sprint_name,
                use_cache=False,
                filter_by=None,
                tz=localtz):
     get_widget = ChartGenerator(self.env).get_chartwidget
     widget = get_widget(ChartType.BURNDOWN,
                         sprint_name=sprint_name,
                         use_cache=use_cache,
                         filter_by=filter_by)
     widget.prepare_rendering(self.teh.mock_request(tz=tz))
     return widget
示例#11
0
 def expand_macro(self, formatter, name, content):
     req = formatter.req
     # Analyze the arguments list, that should be in content
     args = content.split(',')
     if len(args) == 0:
         raise TracError("No argument provided for %s." % self.__class__.__name__)
     
     # The first must be the type of the chart
     chart_type = self._get_chart_type(args[0])
     # The second the Sprint
     sprint_name = self._get_sprint(args[1])
     width, height = self._get_dimensions(args[2:])
     filter_by = None
     if len(args) >= 4:
         filter_by = args[3]
     
     chart_params = dict(sprint_name=sprint_name, width=width, height=height, 
                         filter_by=filter_by)
     debug(self.env, "Params: %s" % chart_params)
     chart = ChartGenerator(self.env).get_chartwidget(chart_type, **chart_params)
     chart.prepare_rendering(req)
     return html.DIV(chart.display())
示例#12
0
 def ticket_changed(self, ticket, comment, author, old_values):
     ticket = AgiloTicket.as_agilo_ticket(ticket)
     generator = ChartGenerator(self.env)
     # AT: this will only work if the task has been explicitly planned for
     # the sprint, otherwise it won't update. The sprint change is good for
     # task containers.
     #if ticket[Key.SPRINT]:
     if ticket[Key.SPRINT] or ticket.is_writeable_field(Key.REMAINING_TIME):
         sprint = self._get_sprint_name(ticket)
         generator.invalidate_cache(sprint_name=sprint)
     if old_values.get(
             Key.SPRINT) and old_values[Key.SPRINT] != ticket[Key.SPRINT]:
         generator.invalidate_cache(sprint_name=old_values[Key.SPRINT])
示例#13
0
    def testSprintTicketStatsChartShowsCorrectTotal(self):
        self.env.compmgr.enabled[SprintTicketStatsChartGenerator] = True
        self.teh.create_ticket(Type.USER_STORY, {Key.SPRINT: self.sprint.name})

        get_widget = ChartGenerator(self.env).get_chartwidget
        widget = get_widget(ChartType.SPRINT_TICKET_STATS,
                            sprint_name=self.sprint.name)

        self.assert_equals(2, len(widget.data['closed']))

        task_alias = AgiloConfig(self.env).ALIASES.get(Type.TASK)
        self.assert_equals((1, task_alias), widget.data['labels'][1])
        task_data = zip(widget.data['closed'], widget.data['planned'],
                        widget.data['total'])[1]
        closed, planned, total = [value for (t, value) in task_data]
        # previously we assumed that closed+planned == total which is wrong, so
        # detect this situation here...
        self.assert_not_equals(closed + planned, total)
        self.assert_equals(closed + planned + 2, total)
示例#14
0
 def ticket_deleted(self, ticket):
     ticket = AgiloTicket.as_agilo_ticket(ticket)
     if ticket[Key.SPRINT] or ticket.is_writeable_field(Key.REMAINING_TIME):
         sprint = self._get_sprint_name(ticket)
         generator = ChartGenerator(self.env)
         generator.invalidate_cache(sprint_name=sprint)
示例#15
0
 def ticket_deleted(self, ticket):
     ticket = AgiloTicket.as_agilo_ticket(ticket)
     if ticket[Key.SPRINT] or ticket.is_writeable_field(Key.REMAINING_TIME):
         sprint = self._get_sprint_name(ticket)
         generator = ChartGenerator(self.env)
         generator.invalidate_cache(sprint_name=sprint)