281 lines
12 KiB
Django/Jinja
281 lines
12 KiB
Django/Jinja
{% extends "base.html.jinja" %}
|
|
{% block title %}Papers{% endblock title %}
|
|
{% block content %}
|
|
|
|
{# --- Sort direction logic for each column --- #}
|
|
{% set title_sort = 'asc' if sort_by != 'title' or sort_dir == 'desc' else 'desc' %}
|
|
{% set journal_sort = 'asc' if sort_by != 'journal' or sort_dir == 'desc' else 'desc' %}
|
|
{% set doi_sort = 'asc' if sort_by != 'doi' or sort_dir == 'desc' else 'desc' %}
|
|
{% set issn_sort = 'asc' if sort_by != 'issn' or sort_dir == 'desc' else 'desc' %}
|
|
{% set status_sort = 'asc' if sort_by != 'status' or sort_dir == 'desc' else 'desc' %}
|
|
{% set created_sort = 'asc' if sort_by != 'created_at' or sort_dir == 'desc' else 'desc' %}
|
|
{% set updated_sort = 'asc' if sort_by != 'updated_at' or sort_dir == 'desc' else 'desc' %}
|
|
|
|
<form method="get" class="mb-4 row g-3">
|
|
<div class="col-md-2">
|
|
<label>Status</label>
|
|
<select name="status" class="form-select">
|
|
<option value="">All</option>
|
|
{% if request.args.get('status') == 'Pending' %}
|
|
<option value="Pending" selected>Pending</option>
|
|
{% else %}
|
|
<option value="Pending">Pending</option>
|
|
{% endif %}
|
|
|
|
{% if request.args.get('status') == 'Done' %}
|
|
<option value="Done" selected>Done</option>
|
|
{% else %}
|
|
<option value="Done">Done</option>
|
|
{% endif %}
|
|
|
|
{% if request.args.get('status') == 'Failed' %}
|
|
<option value="Failed" selected>Failed</option>
|
|
{% else %}
|
|
<option value="Failed">Failed</option>
|
|
{% endif %}
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label>Created from</label>
|
|
<input type="date" name="created_from" class="form-control" value="{{ request.args.get('created_from', '') }}">
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label>Created to</label>
|
|
<input type="date" name="created_to" class="form-control" value="{{ request.args.get('created_to', '') }}">
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label>Updated from</label>
|
|
<input type="date" name="updated_from" class="form-control" value="{{ request.args.get('updated_from', '') }}">
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label>Updated to</label>
|
|
<input type="date" name="updated_to" class="form-control" value="{{ request.args.get('updated_to', '') }}">
|
|
</div>
|
|
<div class="col-md-2 d-flex align-items-end">
|
|
<button type="submit" class="btn btn-primary w-100">Filter</button>
|
|
</div>
|
|
</form>
|
|
|
|
<div class="modal fade" id="paperDetailModal" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
|
<div class="modal-content" id="paper-detail-content">
|
|
<!-- AJAX-loaded content will go here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex align-items-center mb-4">
|
|
<!-- Statistics Section -->
|
|
<div class="me-auto">
|
|
<div class="list-group list-group-horizontal">
|
|
<div class="list-group-item d-flex justify-content-between align-items-center">
|
|
<strong>Total Papers</strong>
|
|
<span class="badge bg-primary rounded-pill">{{ total_papers }}</span>
|
|
</div>
|
|
{% for status, count in status_counts.items() %}
|
|
<div class="list-group-item d-flex justify-content-between align-items-center">
|
|
<strong>{{ status }}:</strong>
|
|
<span class="badge bg-primary rounded-pill">{{ count }}</span>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Pagination Section -->
|
|
<nav aria-label="Page navigation" class="mx-auto">
|
|
<ul class="pagination justify-content-center mb-0">
|
|
{% if pagination.has_prev %}
|
|
<li class="page-item">
|
|
{% set params = request.args.to_dict() %}
|
|
{% set _ = params.pop('page', None) %}
|
|
<a class="page-link" href="{{ url_for('papers.list_papers', page=pagination.prev_num, **params) }}"
|
|
aria-label="Previous">
|
|
<span aria-hidden="true">«</span>
|
|
</a>
|
|
</li>
|
|
{% else %}
|
|
<li class="page-item disabled">
|
|
<span class="page-link" aria-hidden="true">«</span>
|
|
</li>
|
|
{% endif %}
|
|
|
|
{% for page_num in pagination.iter_pages(left_edge=2, right_edge=2, left_current=2, right_current=2) %}
|
|
{% if page_num %}
|
|
<li class="page-item {% if page_num == pagination.page %}active{% endif %}">
|
|
{% set params = request.args.to_dict() %}
|
|
{% set _ = params.pop('page', None) %}
|
|
<a class="page-link" href="{{ url_for('papers.list_papers', page=page_num, **params) }}">{{ page_num
|
|
}}</a>
|
|
</li>
|
|
{% else %}
|
|
<li class="page-item disabled"><span class="page-link">…</span></li>
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
{% if pagination.has_next %}
|
|
<li class="page-item">
|
|
{% set params = request.args.to_dict() %}
|
|
{% set _ = params.pop('page', None) %}
|
|
<a class="page-link" href="{{ url_for('papers.list_papers', page=pagination.next_num, **params) }}"
|
|
aria-label="Next">
|
|
<span aria-hidden="true">»</span>
|
|
</a>
|
|
</li>
|
|
{% else %}
|
|
<li class="page-item disabled">
|
|
<span class="page-link" aria-hidden="true">»</span>
|
|
</li>
|
|
{% endif %}
|
|
</ul>
|
|
</nav>
|
|
|
|
<!-- Buttons Section -->
|
|
<div class="ms-auto">
|
|
<a href="{{ url_for('papers.export_papers') }}" class="btn btn-outline-secondary">Export CSV</a>
|
|
</div>
|
|
</div>
|
|
<table class="table table-striped table-bordered table-smaller">
|
|
<thead>
|
|
<tr>
|
|
<th>
|
|
{% set params = request.args.to_dict() %}
|
|
{% set params = params.update({'sort_by': 'title', 'sort_dir': title_sort}) or params %}
|
|
<a href="{{ url_for('papers.list_papers', **params) }}">Title</a>
|
|
</th>
|
|
<th>
|
|
{% set params = request.args.to_dict() %}
|
|
{% set params = params.update({'sort_by': 'journal', 'sort_dir': journal_sort}) or params %}
|
|
<a href="{{ url_for('papers.list_papers', **params) }}">Journal</a>
|
|
</th>
|
|
<th>
|
|
{% set params = request.args.to_dict() %}
|
|
{% set params = params.update({'sort_by': 'doi', 'sort_dir': doi_sort}) or params %}
|
|
<a href="{{ url_for('papers.list_papers', **params) }}">DOI</a>
|
|
</th>
|
|
<th>
|
|
{% set params = request.args.to_dict() %}
|
|
{% set params = params.update({'sort_by': 'issn', 'sort_dir': issn_sort}) or params %}
|
|
<a href="{{ url_for('papers.list_papers', **params) }}">ISSN</a>
|
|
</th>
|
|
<th>
|
|
{% set params = request.args.to_dict() %}
|
|
{% set params = params.update({'sort_by': 'status', 'sort_dir': status_sort}) or params %}
|
|
<a href="{{ url_for('papers.list_papers', **params) }}">Status</a>
|
|
</th>
|
|
<th>
|
|
{% set params = request.args.to_dict() %}
|
|
{% set params = params.update({'sort_by': 'created_at', 'sort_dir': created_sort}) or params %}
|
|
<a href="{{ url_for('papers.list_papers', **params) }}">Created</a>
|
|
</th>
|
|
<th>
|
|
{% set params = request.args.to_dict() %}
|
|
{% set params = params.update({'sort_by': 'updated_at', 'sort_dir': updated_sort}) or params %}
|
|
<a href="{{ url_for('papers.list_papers', **params) }}">Updated</a>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for paper in papers %}
|
|
<tr>
|
|
<td>
|
|
<a href="#" class="icon-link icon-link-hover paper-link"
|
|
data-url="{{ url_for('papers.paper_detail', paper_id=paper.id) }}">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="bi" viewBox="0 0 16 16" aria-hidden="true">
|
|
<path
|
|
d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z" />
|
|
<path
|
|
d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z" />
|
|
</svg>
|
|
{{ paper.title }}
|
|
</a>
|
|
</td>
|
|
<td>{{ paper.journal }}</td>
|
|
<td>
|
|
<a href="https://doi.org/{{ paper.doi }}" target="_blank" class="icon-link icon-link-hover">
|
|
{{ paper.doi }}
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="bi" viewBox="0 0 16 16" aria-hidden="true">
|
|
<path
|
|
d="M1 8a.5.5 0 0 1 .5-.5h11.793l-3.147-3.146a.5.5 0 0 1 .708-.708l4 4a.5.5 0 0 1 0 .708l-4 4a.5.5 0 0 1-.708-.708L13.293 8.5H1.5A.5.5 0 0 1 1 8z" />
|
|
</svg>
|
|
</a>
|
|
</td>
|
|
<td>{{ paper.issn }}</td>
|
|
<td>{{ paper.status }}</td>
|
|
<td>{{ paper.created_at.strftime('%Y-%m-%d %H:%M:%S') }}</td>
|
|
<td>{{ paper.updated_at.strftime('%Y-%m-%d %H:%M:%S') }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
|
|
<nav aria-label="Page navigation">
|
|
<ul class="pagination justify-content-center">
|
|
{% if pagination.has_prev %}
|
|
<li class="page-item">
|
|
{% set params = request.args.to_dict() %}
|
|
{% set _ = params.pop('page', None) %}
|
|
<a class="page-link" href="{{ url_for('papers.list_papers', page=pagination.prev_num, **params) }}"
|
|
aria-label="Previous">
|
|
<span aria-hidden="true">«</span>
|
|
</a>
|
|
</li>
|
|
{% else %}
|
|
<li class="page-item disabled">
|
|
<span class="page-link" aria-hidden="true">«</span>
|
|
</li>
|
|
{% endif %}
|
|
|
|
{% for page_num in pagination.iter_pages(left_edge=2, right_edge=2, left_current=2, right_current=2) %}
|
|
{% if page_num %}
|
|
<li class="page-item {% if page_num == pagination.page %}active{% endif %}">
|
|
{% set params = request.args.to_dict() %}
|
|
{% set _ = params.pop('page', None) %}
|
|
<a class="page-link" href="{{ url_for('papers.list_papers', page=page_num, **params) }}">{{ page_num }}</a>
|
|
</li>
|
|
{% else %}
|
|
<li class="page-item disabled"><span class="page-link">…</span></li>
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
{% if pagination.has_next %}
|
|
<li class="page-item">
|
|
{% set params = request.args.to_dict() %}
|
|
{% set _ = params.pop('page', None) %}
|
|
<a class="page-link" href="{{ url_for('papers.list_papers', page=pagination.next_num, **params) }}"
|
|
aria-label="Next">
|
|
<span aria-hidden="true">»</span>
|
|
</a>
|
|
</li>
|
|
{% else %}
|
|
<li class="page-item disabled">
|
|
<span class="page-link" aria-hidden="true">»</span>
|
|
</li>
|
|
{% endif %}
|
|
</ul>
|
|
</nav>
|
|
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
const modal = new bootstrap.Modal(document.getElementById('paperDetailModal'));
|
|
const content = document.getElementById('paper-detail-content');
|
|
|
|
document.querySelectorAll('.paper-link').forEach(link => {
|
|
link.addEventListener('click', function (e) {
|
|
e.preventDefault();
|
|
const url = this.getAttribute('data-url');
|
|
|
|
fetch(url)
|
|
.then(response => response.text())
|
|
.then(html => {
|
|
content.innerHTML = html;
|
|
modal.show();
|
|
})
|
|
.catch(err => {
|
|
content.innerHTML = '<div class="modal-body text-danger">Error loading details.</div>';
|
|
modal.show();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock content %} |