diff --git a/pagure/templates/roadmap.html b/pagure/templates/roadmap.html new file mode 100644 index 0000000..cdde25d --- /dev/null +++ b/pagure/templates/roadmap.html @@ -0,0 +1,169 @@ +{% extends "repo_master.html" %} + +{% block title %}Roadmap - {{ repo.name }}{% endblock %} +{% set tag = "home"%} + + +{% block repo %} + + +

+ {{ issues|count }} Milestones + + + + + + + + +

+ {% if oth_issues %} +
+ {% if (issues | length + oth_issues) %} + + {{ (100.0 * (1 - issues | length / (issues | length + oth_issues)))|round|int }}% + + {% endif %} +
+ {% endif %} + +
+ + {% if not status %} + Open + All + {% else %} + Open + All + {% endif %} + + + + {% for tag in tag_list %} + {% if tag.tag in tags %} + {% if status and status != 'Open' %} + + {% else %} + + {% endif %} + {% else %} + + {% endif %} + + {{ tag.tag }} + {% endfor %} + +
+ +{% for milestone in issues | sort %} +
+
+
+ Milestone: {{ milestone }} + {% if repo.milestones[milestone] %} + + Due: {{ repo.milestones[milestone] }} + + {% endif %} +
+
+ +
+ + + + + {% for issue in issues[milestone] |sort(attribute='priority') %} + + + + + + + {% else %} + + + + {% endfor %} + +
+ #{{ issue.id }} + {% if status and status != 'Open' %} + {{issue.status}} + {% endif %} + {% if issue.private %} + + {% endif %} + + {{ issue.title | noJS("img") | safe }} + +    + {% if issue.comments|count > 0 %} + + + {{issue.comments|count}} + + {% endif %} + {% for tag in issue.tags%} + {{tag.tag}} + {% endfor%} + + {{ + issue.date_created | humanize}} + + {% if issue.priority %} + {{repo.priorities[issue.priority | string] }} + {% endif %} + + {% if issue.status != 'Open' %} + {{ issue.status }} + {% else %} + {% if issue.assignee %} + {{ issue.assignee.default_email | avatar(16) | safe }} + {{ issue.assignee.user }} + {% else %} + unassigned + {% endif %} + {% endif %} +
No issues found
+
+
+{% endfor %} +{% endblock %} +{% block jscripts %} +{{ super() }} + + + +{% endblock %} diff --git a/pagure/ui/issues.py b/pagure/ui/issues.py index 5642016..ae06a30 100644 --- a/pagure/ui/issues.py +++ b/pagure/ui/issues.py @@ -10,6 +10,7 @@ import flask import os +from collections import defaultdict import pygit2 from sqlalchemy.exc import SQLAlchemyError @@ -446,6 +447,88 @@ def view_issues(repo, username=None): ) +@APP.route('//roadmap/') +@APP.route('//roadmap') +@APP.route('/fork///roadmap/') +@APP.route('/fork///roadmap') +def view_roadmap(repo, username=None): + """ List all issues associated to a repo as roadmap + """ + status = flask.request.args.get('status', 'Open') + if status.lower() == 'all': + status = None + milestone = flask.request.args.getlist('milestone', None) + + repo = pagure.lib.get_project(SESSION, repo, user=username) + + if repo is None: + flask.abort(404, 'Project not found') + + if not repo.settings.get('issue_tracker', True): + flask.abort(404, 'No issue tracker found for this project') + + # Hide private tickets + private = False + # If user is authenticated, show him/her his/her private tickets + if authenticated(): + private = flask.g.fas_user.username + # If user is repo admin, show all tickets included the private ones + if is_repo_admin(repo): + private = None + + milestones = milestone or list(repo.milestones.keys()) + tags = ['roadmap'] + milestones + + issues = pagure.lib.search_issues( + SESSION, + repo, + tags=tags, + private=private, + ) + + # Change from a list of issues to a dict of milestone/issues + milestone_issues = defaultdict(list) + for cnt in range(len(issues)): + saved = False + for milestone in sorted(milestones): + if milestone in issues[cnt].tags_text: + milestone_issues[milestone].append(issues[cnt]) + saved = True + break + if saved: + continue + milestone_issues['unplaned'].append(issues[cnt]) + + if status: + for key in milestone_issues.keys(): + active = False + for issue in milestone_issues[key]: + if issue.status == 'Open': + active = True + break + if not active: + del(milestone_issues[key]) + + tag_list = pagure.lib.get_tags_of_project(SESSION, repo) + + reponame = pagure.get_repo_path(repo) + repo_obj = pygit2.Repository(reponame) + + return flask.render_template( + 'roadmap.html', + select='issues', + repo=repo, + username=username, + tag_list=tag_list, + status=status, + issues=milestone_issues, + tags=tags, + repo_admin=is_repo_admin(repo), + repo_obj=repo_obj, + ) + + + @APP.route('//new_issue/', methods=('GET', 'POST')) @APP.route('//new_issue', methods=('GET', 'POST')) @APP.route('/fork///new_issue/', methods=('GET', 'POST'))