1{% extends "base.html" %}
2{% import "macros.html" as macros %}
3
4{% block title %}{{ project_name }} — td{% endblock %}
5
6{% block content %}
7<nav aria-label="Breadcrumb">
8 <ol class="unstyled hstack">
9 <li><a href="/" class="unstyled">Projects</a></li>
10 <li aria-hidden="true">/</li>
11 <li aria-current="page"><strong>{{ project_name }}</strong></li>
12 </ol>
13</nav>
14
15<h1>{{ project_name }}</h1>
16
17{% if stats_in_progress > 0 %}
18<div class="row">
19 <article class="card col-4 border-warning">
20 <p class="text-light">In progress</p>
21 <p><strong>{{ stats_in_progress }}</strong></p>
22 </article>
23 <article class="card col-4{% if stats_open > 0 %} border-success{% endif %}">
24 <p class="text-light">Open</p>
25 <p><strong>{{ stats_open }}</strong></p>
26 </article>
27 <article class="card col-4">
28 <p class="text-light">Closed</p>
29 <p><strong>{{ stats_closed }}</strong></p>
30 </article>
31</div>
32{% else %}
33<div class="row">
34 <article class="card col-4{% if stats_open > 0 %} border-success{% endif %}">
35 <p class="text-light">Open</p>
36 <p><strong>{{ stats_open }}</strong></p>
37 </article>
38 <article class="card col-4">
39 <p class="text-light">In progress</p>
40 <p><strong>{{ stats_in_progress }}</strong></p>
41 </article>
42 <article class="card col-4">
43 <p class="text-light">Closed</p>
44 <p><strong>{{ stats_closed }}</strong></p>
45 </article>
46</div>
47{% endif %}
48
49{% if !next_up.is_empty() %}
50<details open class="mt-4">
51 <summary>Next up</summary>
52 <form method="get" action="/projects/{{ project_name }}" class="mt-2 mb-2">
53 {% let preserve = self.section_only_qs() %}
54 {% if !preserve.is_empty() %}
55 {% for pair in preserve.split('&') %}
56 {% let kv = pair.splitn(2, '=').collect::<Vec<_>>() %}
57 {% if kv.len() == 2 %}
58 <input type="hidden" name="{{ kv[0] }}" value="{{ kv[1] }}">
59 {% endif %}
60 {% endfor %}
61 {% endif %}
62 <label>
63 <input type="checkbox" role="switch" name="next_mode" value="effort"{% if next_mode == "effort" %} checked{% endif %} onchange="this.form.submit()">
64 Effort mode
65 </label>
66 <noscript><button type="submit" class="outline small">Apply</button></noscript>
67 </form>
68 <div class="table">
69 <table>
70 <caption class="sr-only">Top scored tasks recommended to work on next</caption>
71 <thead>
72 <tr>
73 <th scope="col">#</th>
74 <th scope="col">ID</th>
75 <th scope="col">Score</th>
76 <th scope="col">Title</th>
77 <th scope="col">Labels</th>
78 <th scope="col">Change status</th>
79 </tr>
80 </thead>
81 <tbody>
82 {% for (i, s) in next_up.iter().enumerate() %}
83 <tr>
84 <td>{{ i + 1 }}</td>
85 <td><a href="/projects/{{ project_name }}/tasks/{{ s.id }}"><code>{{ s.short_id }}</code></a></td>
86 <td title="{{ s.equation }} {{ s.unblocks_display }}">{{ s.score }}</td>
87 <td>{{ s.title }}</td>
88 <td>{% for l in s.labels %}{% if !loop.first %}, {% endif %}{{ l }}{% endfor %}</td>
89 <td>
90 <ot-dropdown>
91 <button popovertarget="next-status-{{ s.short_id }}" class="outline small" aria-label="Change status of {{ s.short_id }}, currently {{ s.status_display }}">
92 {{ s.status_display }}
93 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>
94 </button>
95 <menu popover id="next-status-{{ s.short_id }}">
96 <button role="menuitemradio" aria-checked="{{ s.status == "open" }}" {% if s.status == "open" %}disabled{% else %}form="next-set-open-{{ s.short_id }}"{% endif %}>Open</button>
97 <button role="menuitemradio" aria-checked="{{ s.status == "in_progress" }}" {% if s.status == "in_progress" %}disabled{% else %}form="next-set-in-progress-{{ s.short_id }}"{% endif %}>In progress</button>
98 <button role="menuitemradio" aria-checked="{{ s.status == "closed" }}" {% if s.status == "closed" %}disabled{% else %}form="next-set-closed-{{ s.short_id }}"{% endif %}>Closed</button>
99 </menu>
100 </ot-dropdown>
101 {% if s.status != "open" %}
102 <form id="next-set-open-{{ s.short_id }}" method="post" action="/projects/{{ project_name }}/tasks/{{ s.id }}" hidden>
103 <input type="hidden" name="status" value="open">
104 <input type="hidden" name="redirect" value="{{ self.mutation_redirect() }}">
105 </form>
106 {% endif %}
107 {% if s.status != "in_progress" %}
108 <form id="next-set-in-progress-{{ s.short_id }}" method="post" action="/projects/{{ project_name }}/tasks/{{ s.id }}" hidden>
109 <input type="hidden" name="status" value="in_progress">
110 <input type="hidden" name="redirect" value="{{ self.mutation_redirect() }}">
111 </form>
112 {% endif %}
113 {% if s.status != "closed" %}
114 <form id="next-set-closed-{{ s.short_id }}" method="post" action="/projects/{{ project_name }}/tasks/{{ s.id }}" hidden>
115 <input type="hidden" name="status" value="closed">
116 <input type="hidden" name="redirect" value="{{ self.mutation_redirect() }}">
117 </form>
118 {% endif %}
119 </td>
120 </tr>
121 {% endfor %}
122 </tbody>
123 </table>
124 </div>
125</details>
126{% endif %}
127
128{# Render sections: in-progress before open when it has tasks, otherwise open first #}
129{% let redirect_url = self.mutation_redirect() %}
130
131{% if in_progress.total_count > 0 %}
132{# In progress first when there are tasks #}
133<details{% if in_progress.total_count > 0 || in_progress.has_user_params %} open{% endif %} class="mt-4">
134 <summary>{{ in_progress.label }} ({% if in_progress.filtered_count != in_progress.total_count %}{{ in_progress.filtered_count }} of {% endif %}{{ in_progress.total_count }})</summary>
135 {% call macros::task_section(project_name, in_progress, all_labels, redirect_url) %}{% endcall %}
136</details>
137
138<details{% if open.total_count > 0 || open.has_user_params %} open{% endif %} class="mt-4">
139 <summary>{{ open.label }} ({% if open.filtered_count != open.total_count %}{{ open.filtered_count }} of {% endif %}{{ open.total_count }})</summary>
140 {% call macros::task_section(project_name, open, all_labels, redirect_url) %}{% endcall %}
141</details>
142{% else %}
143{# Open first when nothing is in progress #}
144<details{% if open.total_count > 0 || open.has_user_params %} open{% endif %} class="mt-4">
145 <summary>{{ open.label }} ({% if open.filtered_count != open.total_count %}{{ open.filtered_count }} of {% endif %}{{ open.total_count }})</summary>
146 {% call macros::task_section(project_name, open, all_labels, redirect_url) %}{% endcall %}
147</details>
148
149<details{% if in_progress.has_user_params %} open{% endif %} class="mt-4">
150 <summary>{{ in_progress.label }} ({{ in_progress.total_count }})</summary>
151 {% call macros::task_section(project_name, in_progress, all_labels, redirect_url) %}{% endcall %}
152</details>
153{% endif %}
154
155<details{% if closed.has_user_params %} open{% endif %} class="mt-4">
156 <summary>{{ closed.label }} ({% if closed.filtered_count != closed.total_count %}{{ closed.filtered_count }} of {% endif %}{{ closed.total_count }})</summary>
157 {% call macros::task_section(project_name, closed, all_labels, redirect_url) %}{% endcall %}
158</details>
159{% endblock %}