admin lot tags

This commit is contained in:
Cayo Puigdefabregas 2025-02-03 13:37:44 +01:00
parent 1f0a9a60ce
commit 5b5b864f80
5 changed files with 264 additions and 12 deletions

View file

@ -0,0 +1,173 @@
{% extends "base.html" %}
{% load i18n django_bootstrap5 %}
{% block content %}
<div class="row">
<div class="col">
<h3>{{ subtitle }}</h3>
</div>
<div class="col text-end">
<button type="button" class="btn btn-green-admin" data-bs-toggle="modal" data-bs-target="#addLotTagModal">
{% trans "Add" %}
</button>
</div>
</div>
<div class="row mt-4">
<div class="col">
{% if lot_tags %}
<table class="table table-hover table-bordered align-middle">
<thead class="table-light">
<tr>
<th scope="col">{% trans "Tag" %}
</th>
<th scope="col" width="15%" class="text-center">{% trans "Actions" %}
</th>
</tr>
</thead>
<tbody id="sortable_list">
{% for tag in lot_tags %}
<tr>
<td class="font-monospace">
{{ tag.name }}
</td>
<!-- action buttons -->
<td>
<div class="btn-group float-end">
<button
type="button"
class="btn btn-sm btn-outline-info d-flex align-items-center"
data-bs-toggle="modal" data-bs-target="#editLotTagModal{{ tag.id }}">
<i class="bi bi-pencil me-1"></i>
{% trans 'Edit' %}
</button>
<button
type="button" class="btn btn-sm btn-outline-danger d-flex align-items-center"
data-bs-toggle="modal"
data-bs-target="#deleteLotTagModal{{ tag.id }}" >
<i class="bi bi-trash me-1"></i>
{% trans 'Delete' %}
</button>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="alert alert-primary text-center mt-5" role="alert">
{% trans "No Lot Tags found on current organization" %}
</div>
{% endif %}
</div>
</div>
<!-- add lot tag Modal -->
<div class="modal fade" id="addLotTagModal" tabindex="-1" aria-labelledby="addLoTagModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addLotTagModalLabel">{% trans "Add Lot Tag" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form method="post" action="{% url 'admin:add_lot_tag' %}">
{% csrf_token %}
<div class="mb-3">
<label for="lotTagInput" class="form-label">{% trans "Tag" %}</label>
<input type="text" class="form-control" id="lotTagInput" name="name" maxlength="50" required>
<div class="form-text">{% trans "Maximum 50 characters." %}</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Close" %}</button>
<button type="submit" class="btn btn-primary">{% trans "Add Lot tag" %}</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Edit Lot Tag Modals -->
{% for tag in lot_tags %}
<div class="modal fade" id="editLotTagModal{{ tag.id }}" tabindex="-1" aria-labelledby="editLotTagModalLabel{{ tag.id }}" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<form method="post" action="{% url 'admin:edit_lot_tag' tag.id %}">
{% csrf_token %}
<div class="modal-header">
<h5 class="modal-title" id="editLotTagModalLabel{{ tag.id }}">
{% trans "Edit Lot Tag" %}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% trans 'Close' %}"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label for="editLotTagInput{{ tag.id }}" class="form-label">{% trans "Tag" %}</label>
<input type="text" class="form-control" id="editLotTagInput{{ tag.id }}" name="name" maxlength="50" value="{{ tag.name }}" required>
<div class="form-text">{% trans "Maximum 50 characters." %}</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
<button type="submit" class="btn btn-green-admin">{% trans "Save Changes" %}</button>
</div>
</form>
</div>
</div>
</div>
{% endfor %}
<!-- delete lot tag definition Modal -->
{% for tag in lot_tags %}
<div class="modal fade" id="deleteLotTagModal{{ tag.id }}" tabindex="-1" aria-labelledby="deleteLotTagModalLabel{{ tag.id }}" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title fw-bold" id="deleteLotTagModalLabel{{ tag.id }}">
{% trans "Delete Lot Tag" %}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% trans 'Close' %}"></button>
</div>
<div class="modal-body">
{% if tag.lot_set.first %}
<div class="alert alert-warning text-center" role="alert">
{% trans "There are lots with this tag. Change the tag for this lots" %}
</div>
{% endif %}
<div class="d-flex align-items-center border rounded p-3 mt-3">
<div>
<p class="mb-0 fw-bold">{{ tag.name }}</p>
</div>
</div>
</div>
<div class="modal-footer">
<form method="post" action="{% url 'admin:delete_lot_tag' tag.pk %}">
{% csrf_token %}
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
{% trans "Cancel" %}
</button>
{% if tag.lot_set.first %}
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
{% trans "Delete" %}
</button>
{% else %}
<button type="submit" class="btn btn-danger">
{% trans "Delete" %}
</button>
{% endif %}
</form>
</div>
</div>
</div>
</div>
{% endfor %}
{% endblock %}

View file

@ -10,4 +10,8 @@ urlpatterns = [
path("users/edit/<int:pk>", views.EditUserView.as_view(), name="edit_user"), path("users/edit/<int:pk>", views.EditUserView.as_view(), name="edit_user"),
path("users/delete/<int:pk>", views.DeleteUserView.as_view(), name="delete_user"), path("users/delete/<int:pk>", views.DeleteUserView.as_view(), name="delete_user"),
path("institution/<int:pk>", views.InstitutionView.as_view(), name="institution"), path("institution/<int:pk>", views.InstitutionView.as_view(), name="institution"),
path("lot_tag/", views.LotTagPanelView.as_view(), name="tag_panel"),
path("lot_tag/add", views.AddLotTagView.as_view(), name="add_lot_tag"),
path("lot_tag/delete/<int:pk>", views.DeleteLotTagView.as_view(), name='delete_lot_tag'),
path("lot_tag/edit/<int:pk>/", views.UpdateLotTagView.as_view(), name='edit_lot_tag'),
] ]

View file

@ -1,6 +1,7 @@
from smtplib import SMTPException from smtplib import SMTPException
from django.contrib import messages
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404, redirect
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.views.generic.edit import ( from django.views.generic.edit import (
@ -11,6 +12,7 @@ from django.views.generic.edit import (
from dashboard.mixins import DashboardView, Http403 from dashboard.mixins import DashboardView, Http403
from user.models import User, Institution from user.models import User, Institution
from admin.email import NotifyActivateUserByEmail from admin.email import NotifyActivateUserByEmail
from lot.models import LotTag
class AdminView(DashboardView): class AdminView(DashboardView):
@ -18,7 +20,7 @@ class AdminView(DashboardView):
response = super().get(*args, **kwargs) response = super().get(*args, **kwargs)
if not self.request.user.is_admin: if not self.request.user.is_admin:
raise Http403 raise Http403
return response return response
class PanelView(AdminView, TemplateView): class PanelView(AdminView, TemplateView):
@ -104,7 +106,75 @@ class EditUserView(AdminView, UpdateView):
kwargs = super().get_form_kwargs() kwargs = super().get_form_kwargs()
return kwargs return kwargs
class LotTagPanelView(AdminView, TemplateView):
template_name = "lot_tag_panel.html"
title = _("Lot Tag Panel")
breadcrumb = _("admin / Lot Tag Panel")
class AddLotTagView(AdminView, CreateView):
template_name = "lot_tag_panel.html"
title = _("New lot tag Definition")
breadcrumb = "Admin / New lot tag"
success_url = reverse_lazy('admin:tag_panel')
model = LotTag
fields = ('name',)
def form_valid(self, form):
form.instance.owner = self.request.user.institution
form.instance.user = self.request.user
response = super().form_valid(form)
messages.success(self.request, _("Lot Tag successfully added."))
return response
class DeleteLotTagView(AdminView, DeleteView):
model = LotTag
success_url = reverse_lazy('admin:tag_panel')
def post(self, request, *args, **kwargs):
pk = kwargs.get('pk')
self.object = get_object_or_404(
self.model,
owner=self.request.user.institution,
pk=pk
)
if self.object.lot_set.first():
msg = _('This tag have lots. Impossible deleted.')
messages.warning(self.request, msg)
return redirect(reverse_lazy('admin:tag_panel'))
response = super().delete(request, *args, **kwargs)
msg = _('Lot Tag has been deleted.')
messages.success(self.request, msg)
return response
class UpdateLotTagView(AdminView, UpdateView):
model = LotTag
template_name = 'lot_tag_panel.html'
fields = ['name']
success_url = reverse_lazy('admin:tag_panel')
def get_form_kwargs(self):
pk = self.kwargs.get('pk')
self.object = get_object_or_404(
self.model,
owner=self.request.user.institution,
pk=pk
)
return super().get_form_kwargs()
def form_valid(self, form):
response = super().form_valid(form)
msg = _("Lot Tag updated successfully.")
messages.success(self.request, msg)
return response
class InstitutionView(AdminView, UpdateView): class InstitutionView(AdminView, UpdateView):
template_name = "institution.html" template_name = "institution.html"
title = _("Edit institution") title = _("Edit institution")

View file

@ -51,7 +51,7 @@
} }
</style> </style>
<!-- Custom styles for this template --> <!-- Custom styles for this template -->
<link href="{% static "/css/dashboard.css" %}" rel="stylesheet"> <link href="{% static "/css/dashboard.css" %}" rel="stylesheet">
{% endblock %} {% endblock %}
@ -81,11 +81,11 @@
<ul class="nav flex-column"> <ul class="nav flex-column">
{% if user.is_admin %} {% if user.is_admin %}
<li class="nav-item"> <li class="nav-item">
<a class="admin {% if path in 'panel users' %}active {% endif %}nav-link fw-bold" data-bs-toggle="collapse" data-bs-target="#ul_admin" aria-expanded="false" aria-controls="ul_admin" href="javascript:void()"> <a class="admin {% if path in 'panel users tag_panel' %}active {% endif %}nav-link fw-bold" data-bs-toggle="collapse" data-bs-target="#ul_admin" aria-expanded="false" aria-controls="ul_admin" href="javascript:void()">
<i class="bi bi-person-fill-gear icon_sidebar"></i> <i class="bi bi-person-fill-gear icon_sidebar"></i>
{% trans 'Admin' %} {% trans 'Admin' %}
</a> </a>
<ul class="flex-column mb-2 ul_sidebar accordion-collapse {% if path in 'panel users' %}expanded{% else %}collapse{% endif %}" id="ul_admin" data-bs-parent="#sidebarMenu"> <ul class="flex-column mb-2 ul_sidebar accordion-collapse {% if path in 'panel users tag_panel' %}expanded{% else %}collapse{% endif %}" id="ul_admin" data-bs-parent="#sidebarMenu">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link{% if path == 'panel' %} active2{% endif %}" href="{% url 'admin:panel' %}"> <a class="nav-link{% if path == 'panel' %} active2{% endif %}" href="{% url 'admin:panel' %}">
{% trans 'Panel' %} {% trans 'Panel' %}
@ -96,6 +96,11 @@
{% trans 'Users' %} {% trans 'Users' %}
</a> </a>
</li> </li>
<li class="nav-item">
<a class="nav-link{% if path == 'tag_panel' %} active2{% endif %}" href="{% url 'admin:tag_panel' %}">
{% trans 'Lot Tags' %}
</a>
</li>
</ul> </ul>
</li> </li>
{% endif %} {% endif %}
@ -113,14 +118,14 @@
</ul> </ul>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="admin {% if path == 'tag' %}active {% endif %}nav-link fw-bold" data-bs-toggle="collapse" data-bs-target="#ul_lots" aria-expanded="false" aria-controls="ul_lots" href="javascript:void()"> <a class="admin {% if path == 'tags' or path == 'lot' %}active {% endif %}nav-link fw-bold" data-bs-toggle="collapse" data-bs-target="#ul_lots" aria-expanded="false" aria-controls="ul_lots" href="javascript:void()">
<i class="bi bi-database icon_sidebar"></i> <i class="bi bi-database icon_sidebar"></i>
{% trans 'Lots' %} {% trans 'Lots' %}
</a> </a>
<ul class="flex-column mb-2 ul_sidebar accordion-collapse {% if path == 'tag' %}expanded{% else %}collapse{% endif %}" id="ul_lots" data-bs-parent="#sidebarMenu"> <ul class="flex-column mb-2 ul_sidebar accordion-collapse {% if path == 'tags' or path == 'lot' %}expanded{% else %}collapse{% endif %}" id="ul_lots" data-bs-parent="#sidebarMenu">
{% for tag in lot_tags %} {% for tag in lot_tags %}
<li class="nav-items"> <li class="nav-items">
<a class="nav-link{% if path == 'tag' %} active2{% endif %}" href="{% url 'lot:tag' tag.id %}"> <a class="nav-link{% if path == 'tags' %} active2{% endif %}" href="{% url 'lot:tags' tag.id %}">
{{ tag.name }} {{ tag.name }}
</a> </a>
</li> </li>
@ -189,9 +194,9 @@
</span> </span>
</div> </div>
</form> </form>
</div> </div>
<div class="row border-bottom mb-3"> <div class="row border-bottom mb-3">
<div class="col"> <div class="col">
<small style="color:#899bbd"><i>{{ breadcrumb }}</i></small> <small style="color:#899bbd"><i>{{ breadcrumb }}</i></small>

View file

@ -9,7 +9,7 @@ urlpatterns = [
path("edit/<int:pk>/", views.EditLotView.as_view(), name="edit"), path("edit/<int:pk>/", views.EditLotView.as_view(), name="edit"),
path("add/devices/", views.AddToLotView.as_view(), name="add_devices"), path("add/devices/", views.AddToLotView.as_view(), name="add_devices"),
path("del/devices/", views.DelToLotView.as_view(), name="del_devices"), path("del/devices/", views.DelToLotView.as_view(), name="del_devices"),
path("tag/<int:pk>/", views.LotsTagsView.as_view(), name="tag"), path("tag/<int:pk>/", views.LotsTagsView.as_view(), name="tags"),
path("<int:pk>/document/", views.LotDocumentsView.as_view(), name="documents"), path("<int:pk>/document/", views.LotDocumentsView.as_view(), name="documents"),
path("<int:pk>/document/add", views.LotAddDocumentView.as_view(), name="add_document"), path("<int:pk>/document/add", views.LotAddDocumentView.as_view(), name="add_document"),
path("<int:pk>/annotation", views.LotAnnotationsView.as_view(), name="annotations"), path("<int:pk>/annotation", views.LotAnnotationsView.as_view(), name="annotations"),