and some fixes
This commit is contained in:
@@ -21,6 +21,7 @@ from .models import (
|
|||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
|
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
from django.template.defaultfilters import filesizeformat
|
||||||
|
|
||||||
from easy_thumbnails.files import get_thumbnailer
|
from easy_thumbnails.files import get_thumbnailer
|
||||||
|
|
||||||
@@ -159,6 +160,11 @@ class CaseTable(SelectionTable):
|
|||||||
return mark_safe(", ".join(links))
|
return mark_safe(", ".join(links))
|
||||||
return "No collections"
|
return "No collections"
|
||||||
|
|
||||||
|
def render_case_size(self, value):
|
||||||
|
if value is None:
|
||||||
|
return "-"
|
||||||
|
return filesizeformat(value)
|
||||||
|
|
||||||
associated_cases = tables.Column(
|
associated_cases = tables.Column(
|
||||||
verbose_name="Associated Cases", accessor="pk", orderable=False
|
verbose_name="Associated Cases", accessor="pk", orderable=False
|
||||||
)
|
)
|
||||||
@@ -167,6 +173,10 @@ class CaseTable(SelectionTable):
|
|||||||
verbose_name="Collections", accessor="pk", orderable=False
|
verbose_name="Collections", accessor="pk", orderable=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
case_size = tables.Column(
|
||||||
|
verbose_name="Case size", accessor="total_images_series_size"
|
||||||
|
)
|
||||||
|
|
||||||
edit = tables.LinkColumn(
|
edit = tables.LinkColumn(
|
||||||
"atlas:case_update", text="Edit", args=[A("pk")], orderable=False
|
"atlas:case_update", text="Edit", args=[A("pk")], orderable=False
|
||||||
)
|
)
|
||||||
@@ -188,6 +198,7 @@ class CaseTable(SelectionTable):
|
|||||||
"title",
|
"title",
|
||||||
"description",
|
"description",
|
||||||
"created_date",
|
"created_date",
|
||||||
|
"case_size",
|
||||||
"series",
|
"series",
|
||||||
"author",
|
"author",
|
||||||
"associated_cases",
|
"associated_cases",
|
||||||
|
|||||||
@@ -54,6 +54,9 @@
|
|||||||
</li>
|
</li>
|
||||||
{% if request.user.is_staff %}
|
{% if request.user.is_staff %}
|
||||||
<li><hr class="dropdown-divider"></li>
|
<li><hr class="dropdown-divider"></li>
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item" href="{% url 'atlas:case_admin_overview' %}"><i class="bi bi-speedometer2 me-1" aria-hidden="true"></i>Case Admin Overview</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item" href="{% url 'atlas:cases_by_size' %}"><i class="bi bi-hDD-stack me-1" aria-hidden="true"></i>Large cases</a>
|
<a class="dropdown-item" href="{% url 'atlas:cases_by_size' %}"><i class="bi bi-hDD-stack me-1" aria-hidden="true"></i>Large cases</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,112 +1,116 @@
|
|||||||
{% extends 'atlas/base.html' %}
|
{% extends 'atlas/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container-fluid py-3">
|
<div class="container-fluid py-3">
|
||||||
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
||||||
<h3 class="mb-0">Case Admin Overview</h3>
|
<h3 class="mb-0">Case Admin Overview</h3>
|
||||||
<a class="btn btn-sm btn-outline-secondary" href="{% url 'atlas:case_view' %}">Back to case list</a>
|
<a class="btn btn-sm btn-outline-secondary" href="{% url 'atlas:case_view' %}">Back to case list</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row g-3 mb-3">
|
<div class="row g-3 mb-3">
|
||||||
<div class="col-sm-6 col-xl-3">
|
<div class="col-sm-6 col-xl-3">
|
||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="text-muted small">Total cases</div>
|
<div class="text-muted small">Total cases</div>
|
||||||
<div class="fs-4 fw-semibold">{{ totals.total_cases }}</div>
|
<div class="fs-4 fw-semibold">{{ totals.total_cases }}</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6 col-xl-3">
|
|
||||||
<div class="card h-100">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="text-muted small">Authors with cases</div>
|
|
||||||
<div class="fs-4 fw-semibold">{{ totals.total_authors }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6 col-xl-3">
|
|
||||||
<div class="card h-100">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="text-muted small">Open-access cases</div>
|
|
||||||
<div class="fs-4 fw-semibold">{{ totals.open_access_cases }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6 col-xl-3">
|
|
||||||
<div class="card h-100">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="text-muted small">Archived cases</div>
|
|
||||||
<div class="fs-4 fw-semibold">{{ totals.archived_cases }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-sm-6 col-xl-3">
|
||||||
<div class="row g-3">
|
<div class="card h-100">
|
||||||
<div class="col-lg-5">
|
<div class="card-body">
|
||||||
<div class="card h-100">
|
<div class="text-muted small">Authors with cases</div>
|
||||||
<div class="card-header">Cases per user</div>
|
<div class="fs-4 fw-semibold">{{ totals.total_authors }}</div>
|
||||||
<div class="card-body p-0">
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-sm table-striped mb-0 align-middle">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>User</th>
|
|
||||||
<th class="text-end">Case count</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for row in author_rows %}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
{% if row.get_full_name %}{{ row.get_full_name }}{% else %}{{ row.username }}{% endif %}
|
|
||||||
<div class="text-muted small">{{ row.username }}</div>
|
|
||||||
</td>
|
|
||||||
<td class="text-end fw-semibold">{{ row.case_count }}</td>
|
|
||||||
</tr>
|
|
||||||
{% empty %}
|
|
||||||
<tr>
|
|
||||||
<td colspan="2" class="text-muted">No case authors found.</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="col-lg-7 d-flex flex-column gap-3">
|
<div class="col-sm-6 col-xl-3">
|
||||||
<div class="card">
|
<div class="card h-100">
|
||||||
<div class="card-header d-flex justify-content-between align-items-center">
|
<div class="card-body">
|
||||||
<span>Recently added cases</span>
|
<div class="text-muted small">Open-access cases</div>
|
||||||
<button class="btn btn-sm btn-outline-info"
|
<div class="fs-4 fw-semibold">{{ totals.open_access_cases }}</div>
|
||||||
hx-get="{% url 'atlas:case_admin_recent_cases_partial' %}"
|
|
||||||
hx-target="#admin-recent-cases"
|
|
||||||
hx-swap="innerHTML">
|
|
||||||
Load
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div id="admin-recent-cases" class="card-body text-muted small">
|
|
||||||
Click Load to fetch recently added cases.
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="card">
|
</div>
|
||||||
<div class="card-header d-flex justify-content-between align-items-center">
|
<div class="col-sm-6 col-xl-3">
|
||||||
<span>Largest cases</span>
|
<div class="card h-100">
|
||||||
<button class="btn btn-sm btn-outline-warning"
|
<div class="card-body">
|
||||||
hx-get="{% url 'atlas:case_admin_largest_cases_partial' %}"
|
<div class="text-muted small">Archived cases</div>
|
||||||
hx-target="#admin-largest-cases"
|
<div class="fs-4 fw-semibold">{{ totals.archived_cases }}</div>
|
||||||
hx-swap="innerHTML">
|
|
||||||
Load
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div id="admin-largest-cases" class="card-body text-muted small">
|
|
||||||
Click Load to fetch the largest cases by image footprint.
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-lg-5">
|
||||||
|
<div class="card h-100">
|
||||||
|
<div class="card-header">Cases per user</div>
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-sm table-striped mb-0 align-middle">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>User</th>
|
||||||
|
<th class="text-end">Case count</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for row in author_rows %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="{% url 'atlas:case_view' %}?author={{ row.pk }}">
|
||||||
|
{% if row.get_full_name %}{{ row.get_full_name }}{% else %}{{ row.username }}{% endif %}
|
||||||
|
</a>
|
||||||
|
<div class="text-muted small">{{ row.username }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="text-end fw-semibold">
|
||||||
|
<a href="{% url 'atlas:case_view' %}?author={{ row.pk }}">{{ row.case_count }}</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" class="text-muted">No case authors found.</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-lg-7 d-flex flex-column gap-3">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<span>Recently added cases</span>
|
||||||
|
<button class="btn btn-sm btn-outline-info"
|
||||||
|
hx-get="{% url 'atlas:case_admin_recent_cases_partial' %}"
|
||||||
|
hx-target="#admin-recent-cases"
|
||||||
|
hx-swap="innerHTML">
|
||||||
|
Load
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div id="admin-recent-cases" class="card-body text-muted small">
|
||||||
|
Click Load to fetch recently added cases.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<span>Largest cases</span>
|
||||||
|
<button class="btn btn-sm btn-outline-warning"
|
||||||
|
hx-get="{% url 'atlas:case_admin_largest_cases_partial' %}"
|
||||||
|
hx-target="#admin-largest-cases"
|
||||||
|
hx-swap="innerHTML">
|
||||||
|
Load
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div id="admin-largest-cases" class="card-body text-muted small">
|
||||||
|
Click Load to fetch the largest cases by image footprint.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -57,7 +57,14 @@
|
|||||||
{% if can_merge %}
|
{% if can_merge %}
|
||||||
<dt class="col-sm-4">Edit relationships</dt>
|
<dt class="col-sm-4">Edit relationships</dt>
|
||||||
<dd class="col-sm-8">
|
<dd class="col-sm-8">
|
||||||
{% include 'atlas/partials/_condition_relationships.html' %}
|
<p>
|
||||||
|
<a class="btn btn-sm btn-outline-primary" data-bs-toggle="collapse" href="#relationshipCollapse" role="button" aria-expanded="false" aria-controls="relationshipCollapse">Show relationship editor</a>
|
||||||
|
</p>
|
||||||
|
<div class="collapse" id="relationshipCollapse">
|
||||||
|
<div class="card card-body">
|
||||||
|
{% include 'atlas/partials/_condition_relationships.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</dd>
|
</dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<td class="small">{{ case.created_date|date:"Y-m-d H:i" }}</td>
|
<td class="small">{{ case.created_date|date:"Y-m-d H:i" }}</td>
|
||||||
<td class="small">
|
<td class="small">
|
||||||
{% for author in case.author.all %}
|
{% for author in case.author.all %}
|
||||||
<span class="badge text-bg-secondary me-1">{{ author.username }}</span>
|
<a class="badge text-bg-secondary me-1 text-decoration-none" href="{% url 'atlas:case_view' %}?author={{ author.pk }}">{{ author.username }}</a>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<span class="text-muted">None</span>
|
<span class="text-muted">None</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -844,6 +844,11 @@
|
|||||||
/* small helpers */
|
/* small helpers */
|
||||||
.text-muted { color: var(--muted) !important; }
|
.text-muted { color: var(--muted) !important; }
|
||||||
|
|
||||||
|
#caseSeriesModal .modal-body {
|
||||||
|
max-height: min(72vh, 760px);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
#series-list li {
|
#series-list li {
|
||||||
}
|
}
|
||||||
#series-list .selected {
|
#series-list .selected {
|
||||||
|
|||||||
Reference in New Issue
Block a user