Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions devel/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from django.core.cache import cache
from django.core.cache.utils import make_template_fragment_key
from django.db import transaction
from django.db.models import Count, Max
from django.db.models import Count, F, Max
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.utils.encoding import force_str
Expand Down Expand Up @@ -65,10 +65,13 @@ def index(request):
group.sort(key=lambda p: (p.pkgname != p.pkgbase, p.pkgname))

todopkgs = TodolistPackage.objects.select_related(
'todolist', 'pkg', 'arch', 'repo').exclude(
status=TodolistPackage.COMPLETE).filter(removed__isnull=True)
'todolist', 'pkg', 'arch', 'repo').filter(
removed__isnull=True, progress__lte=F('todolist__progress'))
todopkgs = todopkgs.filter(pkgbase__in=inner_q).order_by('todolist__name',
'pkgname')
# only stages asking for per-package completion need action
todopkgs = [tp for tp in todopkgs
if tp.todolist.current_stage and tp.todolist.current_stage.per_package]

todolists = get_annotated_todolists(incomplete_only=True)

Expand Down
30 changes: 30 additions & 0 deletions sitestatic/archweb.css
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,19 @@ form.general-form textarea {
width: 45%;
}

form.general-form div.form-field {
margin: .33em 0 1em;
}

form.general-form div.checkbox-list {
display: inline-block;
vertical-align: top;
}

form.general-form div.checkbox-list label {
width: auto;
}

/* archdev navbar */
#archdev-navbar {
margin: 1.5em 0;
Expand Down Expand Up @@ -1094,6 +1107,23 @@ ul.admin-actions {
border-top: 1px dotted #bbb;
}

.todo-stages {
margin-bottom: 1em;
}

.todo-stages form {
display: inline;
}

.todo-warning {
margin: 1em 0;
padding: 4px 6px;

color: #8a6d3b;
background: #fcf8e3;
border: 1px solid #faebcc;
}

.todo-list h4 {
margin-top: 0;
margin-bottom: 0.4em;
Expand Down
1 change: 1 addition & 0 deletions sitestatic/archweb.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ function todolist_flag() {
data.css_class.toLowerCase());
/* let tablesorter know the cell value has changed */
$('.results').trigger('updateCell', [$(link).closest('td')[0], false, null]);
$('#todo-advance').prop('disabled', $('a.status-link.incomplete').length > 0);
});
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion templates/devel/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ <h3>Package Todo Lists</h3>
<td>{{ todo.created|date:"Y-m-d" }}</td>
<td>{{ todo.creator.get_full_name }}</td>
<td>{{ todo.pkg_count }}</td>
<td>{{ todo.incomplete_count }}</td>
<td>{% if todo.current_stage.per_package %}{{ todo.incomplete_count }}{% endif %}</td>
<td>{{ todo.kind_str }}</td>
</tr>
{% empty %}
Expand Down
4 changes: 2 additions & 2 deletions templates/general_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ <h2>{{title}}</h2>
<fieldset>
{% for field in form %}
{{field.errors}}
<p><label for="{{field.auto_id}}">{{field.label}}:</label>
<div class="form-field"><label for="{{field.auto_id}}">{{field.label}}:</label>
{% if field.help_text %}<br/><span class="form-help">{{field.help_text}}</span>{% endif %}
{{field}}
{% if field.field.required %}<span class="form-req-field">*</span>{% endif %}
</p>
</div>
{% endfor %}
</fieldset>
<p><label></label> <input type="submit" value="{{submit_text}}" /></p>
Expand Down
2 changes: 1 addition & 1 deletion templates/todolists/complete_email_notification.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% autoescape off %}The todo list "{{ todolist.name }}" is complete.
{% autoescape off %}All packages on the todo list "{{ todolist.name }}" have completed the stage "{{ stage.name }}". Use "{{ stage.caption }}" on the todo list page to proceed.

Todo list information:
Name: {{ todolist.name }}
Expand Down
7 changes: 5 additions & 2 deletions templates/todolists/email_notification.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
{% autoescape off %}The todo list "{{ todolist.name }}" has had the following packages added to it for which you are a maintainer:
{% autoescape off %}{% if stage %}The todo list "{{ todolist.name }}" has reached the stage "{{ stage.name }}". The following packages for which you are a maintainer need to be handled:{% else %}The todo list "{{ todolist.name }}" has had the following packages added to it for which you are a maintainer:{% endif %}

{% for tpkg in todo_packages %}
* {{ tpkg.repo.name|lower }}/{{ tpkg.pkgname }} ({{ tpkg.arch.name }}) - {{ tpkg.pkg.get_full_url }}{% endfor %}

{% if stage %}
Stage information:
{{ stage.description|wordwrap:78 }}
{% endif %}
Todo list information:
Name: {{ todolist.name }}
URL: {{ todolist.get_full_url }}
Expand Down
19 changes: 19 additions & 0 deletions templates/todolists/form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{% extends "general_form.html" %}

{% block script_block %}
{% if default_stages %}
{{ default_stages|json_script:"default-stages" }}
<script type="text/javascript" nonce={{ csp_nonce }}>
(function() {
var defaults = JSON.parse(document.getElementById('default-stages').textContent);
var kind = document.getElementById('id_kind');
kind.addEventListener('change', function() {
var stages = defaults[kind.value];
document.querySelectorAll('#id_stages input[type="checkbox"]').forEach(function(box) {
box.checked = stages.indexOf(box.value) !== -1;
});
});
})();
</script>
{% endif %}
{% endblock %}
6 changes: 3 additions & 3 deletions templates/todolists/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ <h2>Package Todo Lists</h2>
<td>{{ list.created|date:"Y-m-d" }}</td>
<td>{{ list.creator.get_full_name }}</td>
<td>{{ list.pkg_count }}</td>
<td>{{ list.incomplete_count }}</td>
<td>{% if list.current_stage.per_package %}{{ list.incomplete_count }}{% endif %}</td>
<td>{{ list.kind_str }}</td>
<td>{% if list.incomplete_count == 0 %}<span class="complete">Complete</span>
{% else %}<span class="incomplete">Incomplete</span>{% endif %}</td>
<td>{% if list.finished %}<span class="complete">Complete</span>
{% else %}<span class="incomplete">{{ list.current_stage.name }}</span>{% endif %}</td>
</tr>
{% endfor %}
</tbody>
Expand Down
59 changes: 53 additions & 6 deletions templates/todolists/view.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,47 @@ <h2>{{ list.kind_str | title }} Todo List {{ list.name }}</h2>
{{list.stripped_description|default:'(no description)'|urlize|linebreaks}}
</div>

<div class="todo-stages">
{% with stage=list.current_stage %}
{% if stage %}
<p><strong>Current stage: {{ stage.name }}</strong> &ndash; {{ stage.description }}</p>
{% else %}
<p><strong>This todo list is complete.</strong></p>
{% endif %}
{% with missing=list.missing_package_names %}
{% if missing %}
<div class="todo-warning">
<strong>Warning:</strong> The following package name{{ missing|pluralize }}
{{ missing|length|pluralize:"was,were" }} not found in any stable repository and
{{ missing|length|pluralize:"is,are" }} not part of this list:
{{ missing|join:", " }}
</div>
{% endif %}
{% endwith %}
{% for other, pkgbases in list.overlapping_rebuilds %}
<div class="todo-warning">
<strong>Warning:</strong> The active rebuild
<a href="{{ other.get_absolute_url }}" title="View todo list: {{ other.name }}">{{ other.name }}</a>
({{ other.current_stage.name }}) shares the following package base{{ pkgbases|pluralize }}
with this todo list: {{ pkgbases|join:", " }}
</div>
{% endfor %}
{% if perms.todolists.change_todolist %}
{% if list.progress > 0 %}
<form method="post" action="/todo/{{ list.slug }}/back/">{% csrf_token %}
<input type="submit" value="Back to previous stage"/>
</form>
{% endif %}
{% if stage %}
<form method="post" action="/todo/{{ list.slug }}/advance/">{% csrf_token %}
<input type="submit" id="todo-advance" value="{{ stage.caption }}"
{% if not list.can_advance %}disabled="disabled"{% endif %}/>
</form>
{% endif %}
{% endif %}
{% endwith %}
</div>

<div class="todo-pkgbases">
<p><a href="pkgbases/">List of pkgbase values</a></p>
</div>
Expand All @@ -52,8 +93,10 @@ <h3>Filter Todo List Packages</h3>
<div><label for="id_mine_only" title="Show only packages maintained by me">Only Mine</label>
<input type="checkbox" name="mine_only" id="id_mine_only" value="mine_only"/></div>
{% endif %}
{% if per_package %}
<div><label for="id_incomplete" title="Packages not yet completed">Only Incomplete</label>
<input type="checkbox" name="incomplete" id="id_incomplete" value="incomplete"/></div>
{% endif %}
<div ><label>&nbsp;</label><input title="Reset search criteria" type="button" id="criteria_reset" value="Reset"/></div>
<div class="clear"></div>
<div id="filter-info">
Expand All @@ -73,7 +116,7 @@ <h3>Filter Todo List Packages</h3>
<th>Current Version</th>
<th>Staging Version</th>
<th>Maintainers</th>
<th>Status</th>
{% if per_package %}<th>Status</th>{% endif %}
<th>Last Touched By</th>
</tr>
</thead>
Expand All @@ -94,18 +137,22 @@ <h3>Filter Todo List Packages</h3>
<td>{% if staging %}{% pkg_details_link staging staging.full_version %}{% endif %}</td>
{% endwith %}
<td>{{ pkg.maintainers|join:', ' }}</td>
{% if per_package %}
<td>
{% if perms.todolists.change_todolistpackage %}
<a href="/todo/{{ list.slug }}/flag/{{ pkg.id }}/"
class="status-link {{ pkg.status_css_class }}" title="Toggle completion status">{{ pkg.get_status_display }}</a>
class="status-link {{ pkg.status_css_class }}" title="Toggle completion status">{{ pkg.status_str }}</a>
{% else %}
<span class="{{ pkg.status_css_class }}">{{ pkg.get_status_display }}</span>
<span class="{{ pkg.status_css_class }}">{{ pkg.status_str }}</span>
{% endif %}
</td>
{% endif %}
<td>
{% if pkg.user %}
{% if user.is_authenticated %}
{{ pkg.user }} <span title="{{ pkg.last_modified|timezone:user.userprofile.time_zone|date:"Y-m-d H:i T" }}">({{ pkg.last_modified|naturaltime }})</span>
{% with time_zone=user.userprofile.time_zone|default:"UTC" %}
{{ pkg.user }} <span title="{{ pkg.last_modified|timezone:time_zone|date:"Y-m-d H:i T" }}">({{ pkg.last_modified|naturaltime }})</span>
{% endwith %}
{% else %}
{{ pkg.user }} <span title="{{ pkg.last_modified|date:"Y-m-d H:i T" }}">({{ pkg.last_modified|naturaltime }})</span>
{% endif %}
Expand All @@ -125,8 +172,8 @@ <h3>Filter Todo List Packages</h3>
$(document).ready(function() {
$(".results").tablesorter({
widgets: ['zebra'],
sortList: [[2,0], [0,0]],
headers: { 6: { sorter: 'todostatus' } }
sortList: [[2,0], [0,0]]{% if per_package %},
headers: { 6: { sorter: 'todostatus' } }{% endif %}
});
});
$(document).ready(function() {
Expand Down
48 changes: 48 additions & 0 deletions todolists/migrations/0003_stages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Generated by Django 6.0.9 on 2026-11-11 21:19

from django.db import migrations, models

COMPLETE = 1


def migrate_status(apps, schema_editor):
'''Existing todo lists get a single "In progress" stage which packages have
completed if they were marked as complete.'''
Todolist = apps.get_model('todolists', 'Todolist')
TodolistPackage = apps.get_model('todolists', 'TodolistPackage')

TodolistPackage.objects.filter(status=COMPLETE).update(progress=1)
Todolist.objects.update(stages=['in_progress'], progress=1)
incomplete = TodolistPackage.objects.filter(
removed__isnull=True, progress=0).values('todolist_id')
Todolist.objects.filter(id__in=incomplete).update(progress=0)


class Migration(migrations.Migration):

dependencies = [
("todolists", "0002_todolist_kind"),
]

operations = [
migrations.AddField(
model_name="todolist",
name="progress",
field=models.PositiveSmallIntegerField(default=0, editable=False),
),
migrations.AddField(
model_name="todolist",
name="stages",
field=models.JSONField(default=list, editable=False),
),
migrations.AddField(
model_name="todolistpackage",
name="progress",
field=models.PositiveSmallIntegerField(default=0),
),
migrations.RunPython(migrate_status, migrations.RunPython.noop),
migrations.RemoveField(
model_name="todolistpackage",
name="status",
),
]
Loading
Loading