added parent delete popup + endpoint
This commit is contained in:
parent
8b0b56cb7b
commit
35d5a81e6f
@ -30,6 +30,7 @@ urlpatterns = [
|
|||||||
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/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>/", 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("projects/<int:id>/set_parent", views.set_parent, name="set_parent"),
|
||||||
|
@ -108,4 +108,8 @@ button, select {
|
|||||||
|
|
||||||
a {
|
a {
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding-left: 2em;
|
||||||
}
|
}
|
@ -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
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.8em;
|
gap: 0.8em;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list li {
|
.list li {
|
||||||
@ -34,4 +35,61 @@
|
|||||||
|
|
||||||
.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);
|
||||||
}
|
}
|
@ -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", () => {
|
window.addEventListener("load", () => {
|
||||||
document.querySelector("button.new").addEventListener("click", () => {
|
document.querySelector("button.new").addEventListener("click", () => {
|
||||||
window.location.href = "new/"
|
window.location.href = "new/"
|
||||||
@ -8,5 +36,20 @@ window.addEventListener("load", () => {
|
|||||||
row.querySelector("button.edit").addEventListener("click", () => {
|
row.querySelector("button.edit").addEventListener("click", () => {
|
||||||
window.location.href = `${id}/`
|
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)
|
||||||
})
|
})
|
||||||
})
|
})
|
11
dispatcher/static/parents.js
Normal file
11
dispatcher/static/parents.js
Normal 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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -5,7 +5,7 @@ window.addEventListener("load", () => {
|
|||||||
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
|
||||||
})
|
})
|
||||||
|
@ -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
|
from dispatcher.models import Project, Parent, Clocking, Task
|
||||||
from dispatcher.serializers import ClockingSerializer
|
from dispatcher.serializers import ClockingSerializer
|
||||||
|
|
||||||
|
|
||||||
@ -32,6 +32,11 @@ 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
|
||||||
@ -43,6 +48,17 @@ def parent_view(request, id):
|
|||||||
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 new_parent_view(request):
|
def new_parent_view(request):
|
||||||
context = {
|
context = {
|
||||||
"class": "parent"
|
"class": "parent"
|
||||||
|
@ -6,13 +6,14 @@
|
|||||||
{% block extra-head %}{% endblock %}
|
{% block extra-head %}{% endblock %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
{% csrf_token %}
|
||||||
<div class="list-wrapper">
|
<div class="list-wrapper">
|
||||||
<div class="list-header">
|
<div class="list-header">
|
||||||
<button class="new">New {{ class_name }}</button>
|
<button class="new">New {{ class_name }}</button>
|
||||||
</div>
|
</div>
|
||||||
<ul class="list">
|
<ul class="list">
|
||||||
{% for element in elements %}
|
{% 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 %}
|
{% block element %}{% endblock %}
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
{% block actions %}{% endblock %}
|
{% block actions %}{% endblock %}
|
||||||
@ -23,4 +24,14 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</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 %}
|
@ -3,8 +3,10 @@
|
|||||||
{% block title %}Parents{% endblock %}
|
{% block title %}Parents{% 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>
|
||||||
{% 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 %}
|
{% if element.project_num %}
|
||||||
@ -13,4 +15,13 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block actions %}
|
{% block actions %}
|
||||||
<button class="edit">Edit</button>
|
<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 %}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user