Compare commits

..

No commits in common. "092812b9b758a8b59c60adbc166a4ce31dac06b1" and "6ff3f05272d4419b5d9f8e8b99eed198e547e722" have entirely different histories.

19 changed files with 82 additions and 443 deletions

View File

@ -25,16 +25,13 @@ register_converter(DateConverter, "date")
urlpatterns = [ urlpatterns = [
path("", views.dashboard_view, name="dashboard"), path("", views.dashboard_view, name="dashboard"),
path("import/", views.import_view, name="import"), path("import/", views.import_view, name="import"),
path("projects/", views.ProjectsView.as_view(), name="projects"), path("projects/", views.projects_view, name="projects"),
path("parents/", views.ParentsView.as_view(), name="parents"), path("parents/", views.ParentsView.as_view(), name="parents"),
path("table/<date:start_date>/<date:end_date>/", views.get_table_data, name="table_data"), path("table/<date:start_date>/<date:end_date>/", views.get_table_data, name="table_data"),
path("table/", views.table_view, name="table"), path("table/", views.table_view, name="table"),
path("parents/new/", views.new_parent_view, name="new_parent"),
path("parents/<int:id>/on_delete/", views.parent_on_delete_view, name="parent_on_delete"),
path("parents/<int:id>/", views.parent_view, name="parent"), path("parents/<int:id>/", views.parent_view, name="parent"),
path("projects/<int:id>/on_delete/", views.project_on_delete_view, name="project_on_delete"),
path("projects/<int:id>/set_parent/", views.set_parent, name="set_parent"),
path("projects/<int:id>/", views.project_view, name="project"), path("projects/<int:id>/", views.project_view, name="project"),
path("projects/<int:id>/set_parent", views.set_parent, name="set_parent"),
path("stats/by-month/<int:year>/<int:month>/", views.get_stats_by_month, name="stats_by_month"), path("stats/by-month/<int:year>/<int:month>/", views.get_stats_by_month, name="stats_by_month"),
path("stats/between/<date:start_date>/<date:end_date>/", views.get_stats_between, name="stats_between"), path("stats/between/<date:start_date>/<date:end_date>/", views.get_stats_between, name="stats_between"),
path("clockings/<date:date>/", views.set_clocking, name="set_clocking") path("clockings/<date:date>/", views.set_clocking, name="set_clocking")

View File

@ -7,8 +7,6 @@
--light2: #e5e5e5; --light2: #e5e5e5;
--light3: #cccccc; --light3: #cccccc;
--light4: #c5c5c5; --light4: #c5c5c5;
--accent: #69c935;
--accent2: #61ba31;
} }
* { * {
@ -45,16 +43,6 @@ nav a {
transition: background-color 0.2s; transition: background-color 0.2s;
} }
nav a.logo {
padding-top: 0;
padding-bottom: 0;
}
nav a.logo img {
object-fit: contain;
height: 2em;
width: 2em;
}
nav a.active { nav a.active {
box-shadow: 0 -2px var(--light1) inset; box-shadow: 0 -2px var(--light1) inset;
} }
@ -82,7 +70,6 @@ main {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 2em; padding: 2em;
overflow-y: auto;
} }
button, input, select { button, input, select {
@ -108,9 +95,5 @@ button, select {
} }
a { a {
color: var(--accent); color: #69c935
}
ul {
padding-left: 2em;
} }

View File

@ -72,7 +72,7 @@ function formatPercentage(ratio) {
return percentage + "%" return percentage + "%"
} }
function req(url, options = {}) { function req(url, options) {
let headers = options.headers || {} let headers = options.headers || {}
let csrftoken = document.querySelector("input[name='csrfmiddlewaretoken']").value let csrftoken = document.querySelector("input[name='csrfmiddlewaretoken']").value
headers["X-CSRFToken"] = csrftoken headers["X-CSRFToken"] = csrftoken

View File

@ -42,7 +42,7 @@ form input[type="checkbox"] {
form input[type="checkbox"]:checked::after { form input[type="checkbox"]:checked::after {
content: ""; content: "";
background-color: var(--accent); background-color: #69c935;
width: 80%; width: 80%;
height: 80%; height: 80%;
border-radius: 10%; border-radius: 10%;

View File

@ -1,29 +1,10 @@
.list-wrapper { .list {
display: flex;
width: 100%; width: 100%;
max-width: 40em; max-width: 40em;
align-self: center; align-self: center;
display: flex;
flex-direction: column;
gap: 1em;
overflow-y: auto;
}
.list-header {
display: flex;
justify-content: flex-end;
gap: 1em;
}
.list-header button {
padding: 0.4em 1.2em;
}
.list {
display: flex;
gap: 0.8em; gap: 0.8em;
flex-direction: column; flex-direction: column;
padding: 0;
overflow-y: auto;
} }
.list li { .list li {
@ -37,61 +18,4 @@
.list li .actions { .list li .actions {
margin-left: auto; margin-left: auto;
}
.popup {
background-color: #00000040;
position: fixed;
inset: 0;
display: grid;
place-items: center;
}
.popup:not(.show) {
display: none;
}
.popup .popup-container {
display: flex;
flex-direction: column;
gap: 1em;
padding: 2em;
background-color: var(--dark1);
border-radius: 1em;
width: 100%;
max-width: 40em;
box-shadow: 0 0.2em 0.8em var(--dark3);
}
.popup .popup-container .elmt-name {
text-decoration: underline;
}
.popup .popup-container .actions {
display: flex;
justify-content: space-evenly;
gap: 1em;
}
.popup .popup-container .actions button {
padding: 0.4em 1.2em;
}
.popup .popup-container .actions .cancel {
background-color: var(--light2);
}
.popup .popup-container .actions .cancel:hover {
background-color: var(--light3);
}
.popup .popup-container .actions .delete {
--col: #f95f4b;
color: var(--col);
border-color: var(--col);
background-color: var(--dark1);
}
.popup .popup-container .actions .delete:hover {
background-color: var(--dark2);
} }

View File

@ -1,55 +0,0 @@
function showDeletePopup(id, name) {
let popup = document.getElementById("delete-popup")
popup.dataset.id = id
popup.querySelectorAll(".elmt-name").forEach(elmt => {
elmt.innerText = name
})
popup.classList.add("show")
}
function deleteElement(id) {
let url = window.location.href
if (!url.endsWith("/")) {
url += "/"
}
url += `${id}/`
req(url, {
method: "DELETE"
}).then(res => {
return res.json()
}).then(res => {
if (res.status === "success") {
window.location.reload()
}
})
}
let onBeforeDelete = null
window.addEventListener("load", () => {
document.querySelector("button.new").addEventListener("click", () => {
window.location.href = "new/"
})
document.querySelectorAll(".list li").forEach(row => {
let id = row.dataset.id
row.querySelector("button.edit")?.addEventListener("click", () => {
window.location.href = `${id}/`
})
row.querySelector("button.delete")?.addEventListener("click", async () => {
if (onBeforeDelete) {
await onBeforeDelete(row)
}
showDeletePopup(id, row.dataset.name)
})
})
let deletePopup = document.getElementById("delete-popup")
deletePopup.querySelector(".actions .cancel").addEventListener("click", () => {
deletePopup.classList.remove("show")
})
deletePopup.querySelector(".actions .delete").addEventListener("click", () => {
deleteElement(deletePopup.dataset.id)
})
})

View File

@ -1,99 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="64"
height="64"
viewBox="0 0 64 64"
version="1.1"
id="svg1"
sodipodi:docname="logo.svg"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="true"
inkscape:zoom="11.559708"
inkscape:cx="31.012894"
inkscape:cy="41.047749"
inkscape:window-width="1920"
inkscape:window-height="1016"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<inkscape:grid
id="grid1"
units="px"
originx="0"
originy="0"
spacingx="1"
spacingy="1"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="8"
enabled="true"
visible="true" />
</sodipodi:namedview>
<defs
id="defs1">
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect3"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,1,1,0,2,0,1 @ F,0,1,1,0,2,0,1 @ F,0,1,1,0,2,0,1 @ F,0,1,1,0,2,0,1 @ F,0,1,1,0,2,0,1 @ F,0,0,1,0,2,0,1 @ F,0,1,1,0,2,0,1 @ F,0,1,1,0,2,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g4">
<path
style="fill:#69c935;fill-opacity:1;stroke-width:6;stroke-linecap:square;stroke:none"
d="m 8,10 v 4 a 2,2 45 0 0 2,2 h 7 a 2,2 45 0 1 2,2 v 36 a 2,2 45 0 0 2,2 h 4 a 2,2 135 0 0 2,-2 V 18 a 2,2 135 0 1 2,-2 h 7 a 2,2 135 0 0 2,-2 V 10 A 2,2 45 0 0 36,8 H 10 a 2,2 135 0 0 -2,2 z"
id="path1"
sodipodi:nodetypes="ccccccccc"
inkscape:path-effect="#path-effect3"
inkscape:original-d="m 8,8 v 8 h 11 v 40 h 8 V 16 H 38 V 8 Z" />
<g
id="g3"
style="stroke:#61ba31;stroke-opacity:1;fill:none">
<path
id="path2"
style="fill:none;stroke:#61ba31;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 44.834929,13.274537 C 51.52452,17.296808 56,24.625752 56,33 56,45.702549 45.702549,56 33,56"
sodipodi:nodetypes="csc" />
<path
style="fill:none;stroke:#61ba31;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 44,47 33,33 38,26"
id="path3" />
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -1,3 +1,3 @@
.productive { .productive {
box-shadow: 0.2em 0 0 var(--accent) inset; box-shadow: 0.2em 0 0 #69c935 inset;
} }

View File

@ -1,11 +1,8 @@
onBeforeDelete = async row => { window.addEventListener("load", () => {
await req(`${row.dataset.id}/on_delete/`).then(res => { document.querySelectorAll(".list li").forEach(row => {
return res.json() let id = row.dataset.id
}).then(res => { row.querySelector("button.edit").addEventListener("click", () => {
if (res.status === "success") { window.location.href = `${id}/`
let popup = document.getElementById("delete-popup") })
popup.querySelector(".project-count").innerText = res.projects
popup.querySelector(".task-count").innerText = res.tasks
}
}) })
} })

View File

@ -1,8 +1,4 @@
.productive {
box-shadow: 0.2em 0 0 var(--accent) inset;
}
/*
.projects { .projects {
width: 100%; width: 100%;
max-width: 40em; max-width: 40em;
@ -25,5 +21,4 @@
.projects tbody tr:nth-child(even) { .projects tbody tr:nth-child(even) {
background-color: var(--dark2); background-color: var(--dark2);
} }
*/

View File

@ -1,25 +1,18 @@
onBeforeDelete = async row => {
await req(`${row.dataset.id}/on_delete/`).then(res => {
return res.json()
}).then(res => {
if (res.status === "success") {
let popup = document.getElementById("delete-popup")
popup.querySelector(".task-count").innerText = res.tasks
}
})
}
window.addEventListener("load", () => { window.addEventListener("load", () => {
document.querySelectorAll(".list li").forEach(row => { document.querySelectorAll(".projects tbody tr").forEach(row => {
let id = row.dataset.id let id = row.dataset.id
let selector = row.querySelector(".parent-sel") let selector = row.querySelector(".parent-sel")
selector.addEventListener("change", () => { selector.addEventListener("change", () => {
let fd = new FormData() let fd = new FormData()
fd.set("parent_id", selector.value) fd.set("parent_id", selector.value)
req(`${id}/set_parent/`, { req(`${id}/set_parent`, {
method: "POST", method: "POST",
body: fd body: fd
}) })
}) })
row.querySelector("button.edit").addEventListener("click", () => {
window.location.href = `${id}/`
})
}) })
}) })

View File

@ -10,7 +10,7 @@ from django.views.decorators.http import require_POST
from dispatcher.core import import_tasks from dispatcher.core import import_tasks
from dispatcher.forms import ProjectForm, ImportForm, ParentForm from dispatcher.forms import ProjectForm, ImportForm, ParentForm
from dispatcher.models import Project, Parent, Clocking, Task from dispatcher.models import Project, Parent, Clocking
from dispatcher.serializers import ClockingSerializer from dispatcher.serializers import ClockingSerializer
@ -23,7 +23,6 @@ def dashboard_view(request):
def projects_view(request): def projects_view(request):
context = { context = {
"class_name": "parent",
"projects": Project.objects.all(), "projects": Project.objects.all(),
"parents": Parent.objects.all() "parents": Parent.objects.all()
} }
@ -32,11 +31,6 @@ def projects_view(request):
def parent_view(request, id): def parent_view(request, id):
parent = get_object_or_404(Parent, id=id) parent = get_object_or_404(Parent, id=id)
if request.method == "DELETE":
parent.delete()
return JsonResponse({"status": "success"})
context = { context = {
"class": "parent", "class": "parent",
"id": id "id": id
@ -44,48 +38,11 @@ def parent_view(request, id):
form = ParentForm(request.POST or None, request.FILES or None, instance=parent) form = ParentForm(request.POST or None, request.FILES or None, instance=parent)
if form.is_valid(): if form.is_valid():
form.save() form.save()
return redirect("parents")
context["form"] = ParentForm(instance=parent) context["form"] = ParentForm(instance=parent)
return render(request, "edit.html", context) return render(request, "edit.html", context)
def parent_on_delete_view(request, id):
parent = get_object_or_404(Parent, id=id)
projects = parent.project_set.count()
tasks = Task.objects.filter(project__parent=parent).count()
return JsonResponse({
"status": "success",
"projects": projects,
"tasks": tasks
})
def project_on_delete_view(request, id):
project = get_object_or_404(Project, id=id)
tasks = project.task_set.count()
return JsonResponse({
"status": "success",
"tasks": tasks
})
def new_parent_view(request):
context = {
"class": "parent"
}
form = ParentForm(request.POST or None, request.FILES or None)
if form.is_valid():
form.save()
return redirect("parents")
context["form"] = form
return render(request, "add.html", context)
def project_view(request, id): def project_view(request, id):
project = get_object_or_404(Project, id=id) project = get_object_or_404(Project, id=id)
if request.method == "DELETE":
project.delete()
return JsonResponse({"status": "success"})
context = { context = {
"class": "project", "class": "project",
"id": id "id": id
@ -102,7 +59,7 @@ def table_view(request):
@require_POST @require_POST
def set_parent(request, id): def set_parent(request, id):
project = get_object_or_404(Project, id=id) project = get_object_or_404(Project, id=id)
parent_id = request.POST.get("parent_id") or None parent_id = request.POST.get("parent_id")
try: try:
parent = Parent.objects.get(id=parent_id) parent = Parent.objects.get(id=parent_id)
except Parent.DoesNotExist: except Parent.DoesNotExist:
@ -195,16 +152,6 @@ class ParentsView(generic.ListView):
template_name = "parents.html" template_name = "parents.html"
context_object_name = "elements" context_object_name = "elements"
class ProjectsView(generic.ListView):
model = Project
template_name = "projects.html"
context_object_name = "elements"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["parents"] = Parent.objects.all()
return context
def get_table_data(request, start_date: datetime.date, end_date: datetime.date): def get_table_data(request, start_date: datetime.date, end_date: datetime.date):
end_date = end_date + timedelta(days=1) end_date = end_date + timedelta(days=1)

View File

@ -1,16 +0,0 @@
{% extends "base.html" %}
{% load static %}
{% block title %}New {{ class }}{% endblock %}
{% block head %}
<link rel="stylesheet" href="{% static "form.css" %}">
{% endblock %}
{% block main %}
<div class="container">
<h2>New {{ class }}</h2>
<form action="" method="POST">
{% csrf_token %}
{{ form }}
<button type="submit">Create</button>
</form>
</div>
{% endblock %}

View File

@ -4,7 +4,6 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>{% block title %}Title{% endblock %}</title> <title>{% block title %}Title{% endblock %}</title>
<link rel="shortcut icon" href="{% static "logo.svg" %}" type="image/x-svg">
<link rel="stylesheet" href="{% static "base.css" %}"> <link rel="stylesheet" href="{% static "base.css" %}">
<script src="{% static "base.js" %}"></script> <script src="{% static "base.js" %}"></script>
{% block head %}{% endblock %} {% block head %}{% endblock %}
@ -12,7 +11,6 @@
<body> <body>
<header> <header>
<nav> <nav>
<a class="logo" href="{% url "dashboard" %}"><img src="{% static "logo.svg" %}" alt="Time Dispatcher logo"></a>
{% for nav_link in nav_links %} {% for nav_link in nav_links %}
<a href="{% url nav_link.view %}" {% if request.resolver_match.view_name == nav_link.view %}class="active"{% endif %}>{{ nav_link.label }}</a> <a href="{% url nav_link.view %}" {% if request.resolver_match.view_name == nav_link.view %}class="active"{% endif %}>{{ nav_link.label }}</a>
{% endfor %} {% endfor %}

View File

@ -2,7 +2,7 @@
{% load static %} {% load static %}
{% block title %}Editing {{ class }} {{ id }}{% endblock %} {% block title %}Editing {{ class }} {{ id }}{% endblock %}
{% block head %} {% block head %}
<link rel="stylesheet" href="{% static "form.css" %}"> <link rel="stylesheet" href="{% static "edit.css" %}">
{% endblock %} {% endblock %}
{% block main %} {% block main %}
<div class="container"> <div class="container">

View File

@ -1,19 +1,12 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load static %}
{% block title %}Import tasks{% endblock %} {% block title %}Import tasks{% endblock %}
{% block head %}
<link rel="stylesheet" href="{% static "form.css" %}">
{% endblock %}
{% block main %} {% block main %}
<div class="container"> <form action="" method="POST" enctype="multipart/form-data">
<h1>Import tasks</h1> {% csrf_token %}
<form action="" method="POST" enctype="multipart/form-data"> <div>
{% csrf_token %} <label for="file">File</label>
<div> <input type="file" name="file" id="file">
<label for="file">File</label> </div>
<input type="file" name="file" id="file"> <button type="submit">Import</button>
</div> </form>
<button type="submit">Import</button>
</form>
</div>
{% endblock %} {% endblock %}

View File

@ -2,36 +2,19 @@
{% load static %} {% load static %}
{% block head %} {% block head %}
<link rel="stylesheet" href="{% static "list.css" %}"> <link rel="stylesheet" href="{% static "list.css" %}">
<script src="{% static "list.js" %}"></script>
{% block extra-head %}{% endblock %} {% block extra-head %}{% endblock %}
{% endblock %} {% endblock %}
{% block main %} {% block main %}
{% csrf_token %} <ul class="list">
<div class="list-wrapper"> {% for element in elements %}
<div class="list-header"> <li data-id="{{ element.id }}" class="{% block extra-class %}{% endblock %}">
<button class="new">New {{ class_name }}</button> {% block element %}{% endblock %}
</div> <div class="actions">
<ul class="list"> {% block actions %}{% endblock %}
{% for element in elements %} </div>
<li data-id="{{ element.id }}" data-name="{% block element-name %}{% endblock %}" class="{% block extra-class %}{% endblock %}"> </li>
{% block element %}{% endblock %} {% empty %}
<div class="actions"> <li class="empty">No {% block element_name %}{% endblock %} defined yet</li>
{% block actions %}{% endblock %} {% endfor %}
</div> </ul>
</li>
{% empty %}
<li class="empty">No {{ class_name }} defined yet</li>
{% endfor %}
</ul>
</div>
<div class="popup" id="delete-popup">
<div class="popup-container">
<h2 class="title">Delete <span class="elmt-name"></span> ?</h2>
<p class="desc">{% block delete-desc %}{% endblock %}</p>
<div class="actions">
<button class="cancel">Cancel</button>
<button class="delete">Delete</button>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -1,27 +1,16 @@
{% extends "list.html" %} {% extends "list.html" %}
{% load static %} {% load static %}
{% block title %}Parents{% endblock %} {% block title %}Parents{% endblock %}
{% block element_name %}parent{% endblock %}
{% block extra-head %} {% block extra-head %}
<link rel="stylesheet" href="{% static "parents.css" %}"> <link rel="stylesheet" href="{% static "parents.css" %}">
<script src="{% static "parents.js" %}"></script> <script src="{% static "parents.js" %}"></script>
{% endblock %} {% endblock %}
{% block extra-class %}{% if element.is_productive %}productive{% endif %}{% endblock %} {% block extra-class %}{% if element.is_productive %}productive{% endif %}{% endblock %}
{% block element-name %}{{ element.name }}{% endblock %}
{% block element %} {% block element %}
<div class="name">{{ element.name }}</div> <div class="name">{{ element.name }}</div>
{% if element.project_num %} <div class="project_num">({{ element.project_num }})</div>
<div class="project_num">({{ element.project_num }})</div>
{% endif %}
{% endblock %} {% endblock %}
{% block actions %} {% block actions %}
<button class="edit">Edit</button> <button class="edit">Edit</button>
<button class="delete">Delete</button> {% endblock %}
{% endblock %}
{% block delete-desc %}
Are sure you want to delete <span class="elmt-name"></span> ?
This action is <u>IRREVERSIBLE</u> ! By deleting this element, you will also delete:
<ul>
<li><span class="project-count"></span> project(s)</li>
<li><span class="task-count"></span> task imputation(s)</li>
</ul>
{% endblock %}

View File

@ -1,29 +1,39 @@
{% extends "list.html" %} {% extends "base.html" %}
{% load static %} {% load static %}
{% block title %}Projects{% endblock %} {% block title %}Projects{% endblock %}
{% block extra-head %} {% block head %}
<link rel="stylesheet" href="{% static "projects.css" %}"> <link rel="stylesheet" href="{% static "projects.css" %}">
<script src="{% static "projects.js" %}"></script> <script src="{% static "projects.js" %}"></script>
{% endblock %} {% endblock %}
{% block extra-class %}{% if element.parent.is_productive %}productive{% endif %}{% endblock %} {% block footer %}{% endblock %}
{% block element-name %}{{ element.name }}{% endblock %} {% block main %}
{% block element %} {% csrf_token %}
<div class="name">{{ element.name }}</div> <table class="projects">
{% endblock %} <thead>
{% block actions %} <tr>
<select class="parent-sel"> <th>Project</th>
<option value=""></option> <th>Parent</th>
{% for parent in parents %} <th>Actions</th>
<option value="{{ parent.id }}" {% if element.parent.id == parent.id %}selected{% endif %}>{{ parent.name }}</option> </tr>
{% endfor %} </thead>
</select> <tbody>
<button class="edit">Edit</button> {% for project in projects %}
<button class="delete">Delete</button> <tr data-id="{{ project.id }}">
{% endblock %} <td>{{ project.name }}</td>
{% block delete-desc %} <td>
Are sure you want to delete <span class="elmt-name"></span> ? <select class="parent-sel">
This action is <u>IRREVERSIBLE</u> ! By deleting this element, you will also delete: <option value=""></option>
<ul> {% for parent in parents %}
<li><span class="task-count"></span> task imputation(s)</li> <option value="{{ parent.id }}" {% if project.parent.id == parent.id %}selected{% endif %}>{{ parent.name }}</option>
</ul> {% endfor %}
{% endblock %} </select>
</td>
<td>
<button class="edit">Edit</button>
<button class="delete">Delete</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}