{% extends "repo_master.html" %}
{% from "_render_repo.html" import pagination_link %}
{% from "_render_issues.html" import render_issue_row %}
{% block title %}Issues - {{
repo.namespace + '/' if repo.namespace }}{{ repo.name }}{% endblock %}
{% set tag = "home"%}
{% block header %}
<link href="{{ url_for('static', filename='vendor/selectize/selectize.bootstrap3.css') }}"
rel="stylesheet" />
<style>
#tags-filter-group .selectize-input .item{
background-color: {{tag.tag_color}};
color:white;
font-weight:bold;
padding-left:6px;
width:100%;
}
{% for tag in tag_list %}
#tags-filter-group .selectize-input .item[data-value='{{tag.tag}}']{
background-color: {{tag.tag_color}};
}
{% endfor %}
</style>
{% endblock %}
{% block repo %}
{% if status|lower in ['open', 'true'] %}
{% set status_filter = 'open' %}
{% set filtered_open_issues_count = issues_cnt %}
{% set filtered_closed_issues_count = oth_issues_cnt %}
{% set filtered_all_issues_count = issues_cnt+oth_issues_cnt %}
{% elif not status %}
{% set status_filter = 'all' %}
{% set filtered_open_issues_count = oth_issues_cnt %}
{% set filtered_closed_issues_count = issues_cnt-oth_issues_cnt %}
{% set filtered_all_issues_count = issues_cnt %}
{% else %}
{% set status_filter = 'closed' %}
{% set filtered_open_issues_count = oth_issues_cnt %}
{% set filtered_closed_issues_count = issues_cnt %}
{% set filtered_all_issues_count = issues_cnt+oth_issues_cnt %}
{% endif %}
<h3 class="font-weight-bold">
<i class="fa fa-exclamation-circle text-muted"></i>
Issues
<div class="btn-group btn-group-sm float-right" role="group">
<a class="btn btn-sm btn-outline-success font-weight-bold"
href="{{ url_for('ui_ns.view_issues',
repo=repo.name,
username=username,
namespace=repo.namespace,
status='Open') }}">
<span class="fa fa-fw fa-exclamation-circle"></span> {{total_open}} Open
</a>
<a class="btn btn-sm btn-outline-danger font-weight-bold"
href="{{ url_for('ui_ns.view_issues',
repo=repo.name,
username=username,
namespace=repo.namespace,
status='Closed') }}">
<span class="fa fa-fw fa-exclamation-circle"></span> {{total_closed}} Closed
</a>
</div>
</h3>
<div class="row mt-4">
<div class="col">
<div class="list-group">
{% if issues_cnt+oth_issues_cnt > 0 %}
{% if not status %}
{% if oth_issues_cnt > 0 %}
{% set percentage = (100.0 * (oth_issues_cnt / issues_cnt)) %}
{% else %}
{% set percentage = 0 %}
{% endif %}
{% set progress_popover_string = oth_issues_cnt|string+" Open Issues | "+ (issues_cnt-oth_issues_cnt)|string + " Closed Issues"%}
{% elif status|lower in ['open', 'true'] %}
{% if issues_cnt > 0 %}
{% set percentage = (100.0 * (issues_cnt / (oth_issues_cnt+issues_cnt))) %}
{% else %}
{% set percentage = 0 %}
{% endif %}
{% set progress_popover_string = issues_cnt|string+" Open Issues | "+ (oth_issues_cnt)|string + " Closed Issues"%}
{% else %}
{% if oth_issues_cnt > 0 %}
{% set percentage = (100.0 * (oth_issues_cnt / (oth_issues_cnt+issues_cnt))) %}
{% else %}
{% set percentage = 0 %}
{% endif %}
{% set progress_popover_string = oth_issues_cnt|string+" Open Issues | "+ issues_cnt|string + " Closed Issues"%}
{% endif %}
<div class="list-group-item p-0">
<div class="progress" style="height:8px" title="{{progress_popover_string}}">
<div class="progress-bar bg-success" role="progressbar"
style="width:{{percentage|round|int}}%"
aria-valuenow="{{percentage|round|int}}" aria-valuemin="0" aria-valuemax="{{percentage|round|int}}">
</div>
<div class="progress-bar bg-danger" role="progressbar"
style="width:{{100-percentage|round|int}}%"
aria-valuenow="{{100-percentage|round|int}}" aria-valuemin="{{percentage|round|int}}" aria-valuemax="100">
</div>
</div>
</div>
{% endif %}
<div class="list-group-item bg-light">
<div class="row">
<div class="col">
<div class="btn-group">
<div class="dropdown">
{% if status_filter == 'open' %}
<a class="btn btn-sm btn-outline-success border-0 font-weight-bold dropdown-toggle" href="#" data-toggle="dropdown" id="issue-status-dropdown">
<span class="fa fa-fw fa-exclamation-circle"></span> {{filtered_open_issues_count}} Open Issues
{% elif status_filter == 'closed'%}
{% if status == 'Closed' %}
<a class="btn btn-sm btn-outline-danger border-0 font-weight-bold dropdown-toggle" href="#" data-toggle="dropdown" id="issue-status-dropdown">
<span class="fa fa-fw fa-exclamation-circle"></span> {{filtered_closed_issues_count}} Closed Issues
{% else %}
<a class="btn btn-sm btn-outline-danger border-0 font-weight-bold dropdown-toggle" href="#" data-toggle="dropdown" id="issue-status-dropdown">
<span class="fa fa-fw fa-exclamation-circle"></span> {{close_status_cnt}} Closed:{{status}} Issues
{% endif %}
{% else %}
<a class="btn btn-sm btn-outline-secondary border-0 font-weight-bold dropdown-toggle" href="#" data-toggle="dropdown" id="issue-status-dropdown">
<span class="fa fa-fw fa-exclamation-circle"></span> {{filtered_all_issues_count}} Open & Closed Issues
{% endif %}
</a>
<div class="dropdown-menu">
<a class="dropdown-item {% if status_filter == 'open' %}active{%endif%}"
href="{{ url_for('ui_ns.view_issues',
repo=repo.name,
username=username,
namespace=repo.namespace,
search_pattern=search_pattern,
tags=tags, author=author,
milestone=milestones,
assignee=assignee) }}">
{{filtered_open_issues_count}} Open issues
</a>
<a class="dropdown-item {% if status_filter == 'closed' %}active{%endif%}"
href="{{ url_for('ui_ns.view_issues',
repo=repo.name,
username=username,
namespace=repo.namespace,
search_pattern=search_pattern,
tags=tags, author=author, status='Closed',
milestone=milestones,
assignee=assignee) }}">
{{filtered_closed_issues_count}} Closed Issues
</a>
<a class="dropdown-item {% if status_filter == 'all' %}active{%endif%}"
href="{{ url_for('ui_ns.view_issues',
repo=repo.name,
username=username,
namespace=repo.namespace,
search_pattern=search_pattern,
tags=tags, author=author, status='all',
milestone=milestones,
assignee=assignee) }}">
{{filtered_all_issues_count}} Open & Closed Issues
</a>
</div>
</div>
<div class="btn-group">
<button class="btn btn-sm btn-outline-secondary border-0 dropdown-toggle" data-flip="false" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="font-weight-bold">Filter{%if
tags or
milestones or
priority or
author or
search_pattern or
assignee %}:{% endif %}
</span>
{% if tags %}
<i class="fa fa-tag pl-2 pr-1" title="tagged"></i>
{% for tag in tags %}
<span>{{ tag }}</span>
{% if not loop.last %}
&
{% endif %}
{% endfor%}
{% endif %}
{% if milestones %}
<i class="fa fa-map-signs pl-2 pr-1" title="milestone"></i>
<span>{{ milestones[0] }}</span>
{% elif no_milestones %}
<i class="fa fa-map-signs pl-2 pr-1" title="milestone"></i>
<span>No Milestone</span>
{% endif %}
{% if priority %}
<i class="fa fa-bolt pl-2 pr-1" title="priority"></i>
<span>{{ repo.priorities[priority|string] }}</span>
{% endif %}
{% if author %}
<i class="fa fa-user pl-2 pr-1" title="reported by"></i>
{{ author }}
{% endif %}
{% if assignee %}
<i class="fa fa-user-plus pl-2 pr-1" title="assigned to"></i>
{{ assignee }}
{% endif %}
{% if search_pattern %}
<i class="fa fa-search pl-2 pr-1" title="tagged"></i>
<span>{{ search_pattern }}</span>
{% endif %}
</button>
<div class="dropdown-menu p-4" style="min-width:400px" aria-labelledby="dropdownMenuButton" id="filters-dropdown">
<div>
<form id="filters_form" action="{{ url_for('ui_ns.view_issues',
username=username,
namespace=repo.namespace,
repo=repo.name ) }}" method="GET">
<input type="hidden" name="status" value="{{ status or 'all' }}" />
<div class="form-group row mb-1" id="tags-filter-group">
<label for="tags" class="col-auto align-self-center pl-1 pr-0"><i class="text-muted fa fa-fw fa-tag"></i></label>
<div class="col pl-1">
<select name="tags" multiple id="tags-selectize" placeholder="Tags">
{% for tag in tag_list %}
<option value="{{ tag.tag }}" {% if tag.tag in tags %}selected="selected"{% endif %}>{{tag.tag}}</option>
{% endfor %}
</select>
</div>
<div class="col-auto pl-0 pr-1 pt-1">
<i class="fa fa-times fa-fw text-muted" id="tags-selectize-reset"></i>
</div>
</div>
<div class="form-group row mb-2">
<label for="search_pattern" class="col-auto align-self-center pl-1 pr-0"><i class="text-muted fa fa-fw fa-search"></i></label>
<div class="col pl-1">
<input type="text" class="form-control"
name="search_pattern" placeholder="Search"
value="{{ search_pattern or '' }}" />
</div>
<div class="col-auto pl-0 pr-1 pt-1">
<i class="fa fa-times fa-fw text-muted" id="search_pattern-selectize-reset"></i>
</div>
</div>
<div class="form-group row mb-1" id="milestone-filter-group">
<label for="milestone" class="col-auto align-self-center pl-1 pr-0"><i class="text-muted fa fa-fw fa-map-signs"></i></label>
<div class="col pl-1">
<select name="milestone" id="milestone-selectize" placeholder="Milestone">
<option value=""></option>
<option value="none" {% if no_milestones %}selected="selected"{% endif %}>Milestone unset</option>
{% for stone in repo.milestones %}
{% if loop.first %}
<optgroup label="Active">
{% endif %}
{% if repo.milestones[stone]['active']%}
<option value="{{ stone }}" {% if milestones[0] == stone %}selected="selected"{% endif %}>{{stone}}</option>
{% endif %}
{% if loop.last %}
</optgroup>
{% endif %}
{% endfor %}
{% for stone in repo.milestones %}
{% if loop.first %}
<optgroup label="Inactive">
{% endif %}
{% if not repo.milestones[stone]['active']%}
<option value="{{ stone }}" {% if milestones[0] == stone %}selected="selected"{% endif %}>{{stone}}</option>
{% endif %}
{% if loop.last %}
</optgroup>
{% endif %}
{% endfor %}
</select>
</div>
<div class="col-auto pl-0 pr-1 pt-1">
<i class="fa fa-times fa-fw text-muted" id="milestone-selectize-reset"></i>
</div>
</div>
<div class="form-group row mb-1" id="priority-filter-group">
<label for="priority" class="col-auto align-self-center pl-1 pr-0"><i class="text-muted fa fa-fw fa-bolt"></i></label>
<div class="col pl-1">
<select name="priority" id="priority-selectize" placeholder="Priority">
{% for p in repo.priorities | sort %}
<option value="{{ p }}" {% if p | int == priority | int %}selected="selected"{% endif %}>{{repo.priorities[p | string]}}</option>
{% endfor %}
</select>
</div>
<div class="col-auto pl-0 pr-1 pt-1">
<i class="fa fa-times fa-fw text-muted" id="priority-selectize-reset"></i>
</div>
</div>
<div class="form-group row mb-1" id="assignee-filter-group">
<label for="assignee" class="col-auto align-self-center pl-1 pr-0"><i class="text-muted fa fa-fw fa-user-plus"></i></label>
<div class="col pl-1">
<select name="assignee" id="assignee-selectize" placeholder="Assignee">
{% if assignee %}
<option value="{{assignee}}" selected="selected">{{assignee}}</option>
{% endif %}
</select>
</div>
<div class="col-auto pl-0 pr-1 pt-1">
<i class="fa fa-times fa-fw text-muted" id="assignee-selectize-reset"></i>
</div>
</div>
<div class="form-group row mb-1" id="author-filter-group">
<label for="author" class="col-auto align-self-center pl-1 pr-0"><i class="text-muted fa fa-fw fa-user"></i></label>
<div class="col pl-1">
<select name="author" id="author-selectize" placeholder="Submitted by">
{% if author %}
<option value="{{author}}" selected="selected">{{author}}</option>
{% endif %}
</select>
</div>
<div class="col-auto pl-0 pr-1 pt-1">
<i class="fa fa-times fa-fw text-muted" id="author-selectize-reset"></i>
</div>
</div>
<input type="submit" class="btn btn-block btn-primary" value="Apply Filters" />
<a href="{{ url_for('ui_ns.view_issues',
repo=repo.name,
username=username,
namespace=repo.namespace,
status=status) }}" class="btn btn-link btn-block">Reset Filters</a>
</form>
</div>
</div>
</div>
</div>
<div class="btn-group float-right">
{% if g.repo.reports or g.repo_admin %}
<div class="btn-group">
<a class="btn btn-outline-primary btn-sm dropdown-toggle"
type="button" id="dropdownMenu1" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false" href="#">
<i class="fa fa-fw fa-sticky-note"></i> Reports
</a>
<div class="dropdown-menu dropdown-menu-right p-0" aria-labelledby="dropdownMenu1">
<div class="list-group list-group-flush">
{% if g.repo.reports %}
{% for report in repo.reports %}
<a class="list-group-item list-group-item-action" href="{{ url_for(
'ui_ns.view_report', namespace=repo.namespace,
username=username, repo=repo.name, report=report) }}">
{{ report }}
</a>
{% endfor %}
{% else %}
<div class="list-group-item text-center font-weight-bold text-muted">
No Reports
</div>
{% endif %}
{% if g.repo_admin %}
<div class="list-group-item bg-light">
<a type="button" class="btn btn-primary btn-block"
data-toggle="modal" data-target="#report_modal" href="#">
Save New Report
</a>
</div>
{% endif %}
</div>
</div>
</div>
{% endif %}
<div class="btn-group">
{% set filters_list = [
{"key": "date_created", "display_string": "Open Date", "sort_icon_prefix": "fa-sort-numeric-", "icon":"fa-calendar"},
{"key": "last_updated", "display_string": "Last Modified Date", "sort_icon_prefix": "fa-sort-numeric-", "icon":"fa-calendar"},
{"key": "closed_at", "display_string": "Closed Date", "sort_icon_prefix": "fa-sort-numeric-", "icon":"fa-calendar"},
{"key": "title", "display_string": "Issue Title", "sort_icon_prefix": "fa-sort-alpha-", "icon":"fa-exclamation-circle"},
{"key": "priority", "display_string": "Priority", "sort_icon_prefix": "fa-sort-numeric-", "icon":"fa-bolt"},
{"key": "user", "display_string": "Reporter", "sort_icon_prefix": "fa-sort-alpha-", "icon":"fa-user"},
{"key": "assignee", "display_string": "Assignee", "sort_icon_prefix": "fa-sort-alpha-", "icon":"fa-user-plus"},
] %}
<button class="btn btn-sm btn-outline-primary dropdown-toggle" type="button" id="dropdownMenuButton" data-flip="false" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-fw fa-sort"></i> Sort
</button>
<div class="dropdown-menu dropdown-menu-right" style="min-width:300px" aria-labelledby="dropdownMenuButton">
<div class="list-group list-group-flush">
{% for filter in filters_list %}
<div class="list-group-item pl-1">
<div class="btn btn-outline-dark border-0 font-weight-bold disabled">
<span class="fa fa-fw {{filter['icon']}}"></span> {{filter["display_string"]}}
</div>
<div class="btn-group float-right">
<a class="btn {%if filter['key'] == order_key and order == 'asc' %}btn-primary{%else%}btn-outline-primary{%endif%}"
href="{{ url_for('ui_ns.view_issues',
repo=repo.name, username=username, namespace=repo.namespace,
tags=tags, author=author, assignee=assignee, priority=priority, milestone=milestones,
status=status or 'all', order_key=filter['key'],
order='asc' )}}"><i class="fa fa-fw {{filter['sort_icon_prefix']}}asc"></i></a>
<a class="btn {%if filter['key'] == order_key and order == 'desc' %}btn-primary{%else%}btn-outline-primary{%endif%}"
href="{{ url_for('ui_ns.view_issues',
repo=repo.name, username=username, namespace=repo.namespace,
tags=tags, author=author, assignee=assignee, priority=priority, milestone=milestones,
status=status or 'all', order_key=filter['key'],
order='desc' )}}"><i class="fa fa-fw {{filter['sort_icon_prefix']}}desc"></i></a>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
{% if g.repo_admin %}
<div class="modal fade" id="report_modal" tabindex="-1"
role="dialog" aria-labelledby="New report" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
<span class="sr-only">Close</span>
</button>
<h4 class="modal-title" id="myModalLabel">New Report</h4>
</div>
<div class="modal-body">
<form action="{{ url_for(
'ui_ns.save_reports', namespace=repo.namespace,
username=username, repo=repo.name) }}" method="post" class="icon">
<fieldset class="form-group">
<label for="report_name">Report name</label>
<input class="form-control" name="report_name" required/>
<small class="text-muted">name of the report</small>
</fieldset>
{{ add_report_form.csrf_token }}
<button class="btn btn-primary" type="submit" title="Save this report">
Save
</button>
</form>
</div>
</div>
</div>
</div>
{% endif %}
</div>
</div>
</div>
{% if issues %}
{% for issue in issues %}
{{render_issue_row(issue, repo, username)}}
{% endfor %}
{% else %}
<div class="list-group-item">
<div class="row">
<div class="col text-center p-5">
<h4 class="text-muted">
{% if status_filter == 'open'%}
<span class="font-weight-bold">no open issues found</span>
{% if oth_issues_cnt %}
<div>
<small>
<a href="{{ url_for('ui_ns.view_issues',
repo=repo.name,
username=username,
namespace=repo.namespace,
search_pattern=search_pattern,
tags=tags, author=author,
milestone=milestones, status='Closed',
assignee=assignee) }}">
{{oth_issues_cnt}} closed issues
</a>
match this filter
</small>
</div>
{% else %}
<div><small>no closed issues match this filter either</small></div>
{% endif %}
{% elif status_filter == 'closed'%}
<span class="font-weight-bold">no closed issues found</span>
{% if oth_issues_cnt %}
<div>
<small>
<a href="{{ url_for('ui_ns.view_issues',
repo=repo.name,
username=username,
namespace=repo.namespace,
search_pattern=search_pattern,
tags=tags, author=author,
milestone=milestones,
assignee=assignee) }}">
{{oth_issues_cnt}} open issues
</a>
match this filter
</small>
</div>
{% else %}
<div><small>no open issues match this filter either</small></div>
{% endif %}
{% else %}
no open or closed issues found
{% endif %}
</h4>
</div>
</div>
</div>
{% endif %}
</div>
</div>
</div>
{% if total_page > 1 %}
{{ pagination_link('page', g.page, total_page) }}
{% endif %}
{% endblock %}
{% block jscripts %}
{{ super() }}
<script type="text/javascript"
src="{{ url_for('static', filename='vendor/selectize/selectize.min.js') }}"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#search_pattern-selectize-reset").on('click', function(e){
$('input[name="search_pattern"]').val('');
});
var $tags_selectize = $('#tags-selectize').selectize({
plugins: ['remove_button'],
closeAfterSelect: true,
onInitialize: function(){
$("#tags-filter-group .selectize-control").on('click', function(event){
event.stopPropagation();
})
$("#filters-dropdown").on('click', function(event){
event.stopPropagation();
})
}
});
var tags_selectize_control = $tags_selectize[0].selectize;
$("#tags-selectize-reset").on('click', function(e){
tags_selectize_control.clear();
});
var $milestone_selectize = $('#milestone-selectize').selectize({
onInitialize: function(){
$("#milestone-filter-group .selectize-control").on('click', function(event){
event.stopPropagation();
})
$("#filters-dropdown").on('click', function(event){
event.stopPropagation();
})
}
});
var milestone_selectize_control = $milestone_selectize[0].selectize;
$("#milestone-selectize-reset").on('click', function(e){
milestone_selectize_control.clear();
});
var $priority_selectize = $('#priority-selectize').selectize({
onInitialize: function(){
$("#priority-filter-group .selectize-control").on('click', function(event){
event.stopPropagation();
})
$("#filters-dropdown").on('click', function(event){
event.stopPropagation();
})
}
});
var priority_selectize_control = $priority_selectize[0].selectize;
$("#priority-selectize-reset").on('click', function(e){
priority_selectize_control.clear();
});
var $assignee_selectize = $('#assignee-selectize').selectize({
valueField: 'user',
labelField: 'user',
searchField: 'user',
maxItems: 1,
create: false,
load: function(query, callback) {
if (!query.length) return callback();
$.getJSON(
"{{ url_for('api_ns.api_users') }}", {
pattern: query.term
},
function( data ) {
callback( data.users.map(function(x) { return { user: x }; }) );
}
);
}
});
var assignee_selectize_control = $assignee_selectize[0].selectize;
$("#assignee-selectize-reset").on('click', function(e){
assignee_selectize_control.clear();
});
var $author_selectize = $('#author-selectize').selectize({
valueField: 'user',
labelField: 'user',
searchField: 'user',
maxItems: 1,
create: false,
load: function(query, callback) {
if (!query.length) return callback();
$.getJSON(
"{{ url_for('api_ns.api_users') }}", {
pattern: query.term
},
function( data ) {
callback( data.users.map(function(x) { return { user: x }; }) );
}
);
}
});
var author_selectize_control = $author_selectize[0].selectize;
$("#author-selectize-reset").on('click', function(e){
author_selectize_control.clear();
});
$( "#filters_form" ).submit(function( event ) {
if ($('input[name="search_pattern"]').val() == ''){
$('input[name="search_pattern"]').prop("disabled", true);
}
if ($('select[name="milestone"]').val() == ''){
$('select[name="milestone"]').prop("disabled", true);
}
if ($('select[name="priority"]').val() == ''){
$('select[name="priority"]').prop("disabled", true);
}
if ($('select[name="assignee"]').val() == ''){
$('select[name="assignee"]').prop("disabled", true);
}
if ($('select[name="author"]').val() == ''){
$('select[name="author"]').prop("disabled", true);
}
});
});
</script>
{% endblock %}