added parent delete popup + endpoint

This commit is contained in:
Louis Heredero 2025-02-02 22:43:52 +01:00
parent 8b0b56cb7b
commit 35d5a81e6f
Signed by: HEL
GPG Key ID: 8D83DE470F8544E7
10 changed files with 160 additions and 5 deletions

View File

@ -30,6 +30,7 @@ urlpatterns = [
path("table/<date:start_date>/<date:end_date>/", views.get_table_data, name="table_data"),
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("projects/<int:id>/", views.project_view, name="project"),
path("projects/<int:id>/set_parent", views.set_parent, name="set_parent"),

View File

@ -108,4 +108,8 @@ button, select {
a {
color: var(--accent);
}
ul {
padding-left: 2em;
}

View File

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

View File

@ -21,6 +21,7 @@
display: flex;
gap: 0.8em;
flex-direction: column;
padding: 0;
}
.list li {
@ -34,4 +35,61 @@
.list li .actions {
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,3 +1,31 @@
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/"
@ -8,5 +36,20 @@ window.addEventListener("load", () => {
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

@ -0,0 +1,11 @@
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(".project-count").innerText = res.projects
popup.querySelector(".task-count").innerText = res.tasks
}
})
}

View File

@ -5,7 +5,7 @@ window.addEventListener("load", () => {
selector.addEventListener("change", () => {
let fd = new FormData()
fd.set("parent_id", selector.value)
req(`${id}/set_parent`, {
req(`${id}/set_parent/`, {
method: "POST",
body: fd
})

View File

@ -10,7 +10,7 @@ from django.views.decorators.http import require_POST
from dispatcher.core import import_tasks
from dispatcher.forms import ProjectForm, ImportForm, ParentForm
from dispatcher.models import Project, Parent, Clocking
from dispatcher.models import Project, Parent, Clocking, Task
from dispatcher.serializers import ClockingSerializer
@ -32,6 +32,11 @@ def projects_view(request):
def parent_view(request, id):
parent = get_object_or_404(Parent, id=id)
if request.method == "DELETE":
parent.delete()
return JsonResponse({"status": "success"})
context = {
"class": "parent",
"id": id
@ -43,6 +48,17 @@ def parent_view(request, id):
context["form"] = ParentForm(instance=parent)
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 new_parent_view(request):
context = {
"class": "parent"

View File

@ -6,13 +6,14 @@
{% block extra-head %}{% endblock %}
{% endblock %}
{% block main %}
{% csrf_token %}
<div class="list-wrapper">
<div class="list-header">
<button class="new">New {{ class_name }}</button>
</div>
<ul class="list">
{% for element in elements %}
<li data-id="{{ element.id }}" class="{% block extra-class %}{% endblock %}">
<li data-id="{{ element.id }}" data-name="{% block element-name %}{% endblock %}" class="{% block extra-class %}{% endblock %}">
{% block element %}{% endblock %}
<div class="actions">
{% block actions %}{% endblock %}
@ -23,4 +24,14 @@
{% 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 %}

View File

@ -3,8 +3,10 @@
{% block title %}Parents{% endblock %}
{% block extra-head %}
<link rel="stylesheet" href="{% static "parents.css" %}">
<script src="{% static "parents.js" %}"></script>
{% endblock %}
{% block extra-class %}{% if element.is_productive %}productive{% endif %}{% endblock %}
{% block element-name %}{{ element.name }}{% endblock %}
{% block element %}
<div class="name">{{ element.name }}</div>
{% if element.project_num %}
@ -13,4 +15,13 @@
{% endblock %}
{% block actions %}
<button class="edit">Edit</button>
{% endblock %}
<button class="delete">Delete</button>
{% 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 %}