From 35d5a81e6f24c121295ab094373692fd3bf397b0 Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Sun, 2 Feb 2025 22:43:52 +0100 Subject: [PATCH] added parent delete popup + endpoint --- TimeDispatcher/urls.py | 1 + dispatcher/static/base.css | 4 +++ dispatcher/static/base.js | 2 +- dispatcher/static/list.css | 58 +++++++++++++++++++++++++++++++++++ dispatcher/static/list.js | 43 ++++++++++++++++++++++++++ dispatcher/static/parents.js | 11 +++++++ dispatcher/static/projects.js | 2 +- dispatcher/views.py | 18 ++++++++++- templates/list.html | 13 +++++++- templates/parents.html | 13 +++++++- 10 files changed, 160 insertions(+), 5 deletions(-) create mode 100644 dispatcher/static/parents.js diff --git a/TimeDispatcher/urls.py b/TimeDispatcher/urls.py index 859bfad..7b4ce68 100644 --- a/TimeDispatcher/urls.py +++ b/TimeDispatcher/urls.py @@ -30,6 +30,7 @@ urlpatterns = [ path("table///", 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//on_delete/", views.parent_on_delete_view, name="parent_on_delete"), path("parents//", views.parent_view, name="parent"), path("projects//", views.project_view, name="project"), path("projects//set_parent", views.set_parent, name="set_parent"), diff --git a/dispatcher/static/base.css b/dispatcher/static/base.css index 9ff71dd..a164621 100644 --- a/dispatcher/static/base.css +++ b/dispatcher/static/base.css @@ -108,4 +108,8 @@ button, select { a { color: var(--accent); +} + +ul { + padding-left: 2em; } \ No newline at end of file diff --git a/dispatcher/static/base.js b/dispatcher/static/base.js index 57a40e0..817435e 100644 --- a/dispatcher/static/base.js +++ b/dispatcher/static/base.js @@ -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 diff --git a/dispatcher/static/list.css b/dispatcher/static/list.css index c2ab8fc..f469b4d 100644 --- a/dispatcher/static/list.css +++ b/dispatcher/static/list.css @@ -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); } \ No newline at end of file diff --git a/dispatcher/static/list.js b/dispatcher/static/list.js index b138911..95b640d 100644 --- a/dispatcher/static/list.js +++ b/dispatcher/static/list.js @@ -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) }) }) \ No newline at end of file diff --git a/dispatcher/static/parents.js b/dispatcher/static/parents.js new file mode 100644 index 0000000..41b1b0d --- /dev/null +++ b/dispatcher/static/parents.js @@ -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 + } + }) +} \ No newline at end of file diff --git a/dispatcher/static/projects.js b/dispatcher/static/projects.js index 2f8f37f..43168f0 100644 --- a/dispatcher/static/projects.js +++ b/dispatcher/static/projects.js @@ -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 }) diff --git a/dispatcher/views.py b/dispatcher/views.py index e72d536..ee00b9b 100644 --- a/dispatcher/views.py +++ b/dispatcher/views.py @@ -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" diff --git a/templates/list.html b/templates/list.html index 8db4edf..d55ea52 100644 --- a/templates/list.html +++ b/templates/list.html @@ -6,13 +6,14 @@ {% block extra-head %}{% endblock %} {% endblock %} {% block main %} + {% csrf_token %}
    {% for element in elements %} -
  • +
  • {% block element %}{% endblock %}
    {% block actions %}{% endblock %} @@ -23,4 +24,14 @@ {% endfor %}
+ {% endblock %} \ No newline at end of file diff --git a/templates/parents.html b/templates/parents.html index 07fc3bc..7cf6eef 100644 --- a/templates/parents.html +++ b/templates/parents.html @@ -3,8 +3,10 @@ {% block title %}Parents{% endblock %} {% block extra-head %} + {% endblock %} {% block extra-class %}{% if element.is_productive %}productive{% endif %}{% endblock %} +{% block element-name %}{{ element.name }}{% endblock %} {% block element %}
{{ element.name }}
{% if element.project_num %} @@ -13,4 +15,13 @@ {% endblock %} {% block actions %} -{% endblock %} \ No newline at end of file + +{% endblock %} +{% block delete-desc %} + Are sure you want to delete ? + This action is IRREVERSIBLE ! By deleting this element, you will also delete: +
    +
  • project(s)
  • +
  • task imputation(s)
  • +
+{% endblock %}