mirror of
https://github.com/ArchiveBox/ArchiveBox.git
synced 2025-05-09 12:21:57 -04:00
Feature implementation
This commit is contained in:
parent
275ad22db7
commit
254d2502fd
6 changed files with 331 additions and 1 deletions
|
@ -96,6 +96,13 @@ class SnapshotAdmin(SearchResultsAdminMixin, admin.ModelAdmin):
|
|||
actions_template = 'admin/actions_as_select.html'
|
||||
form = SnapshotAdminForm
|
||||
|
||||
def get_urls(self):
|
||||
urls = super().get_urls()
|
||||
custom_urls = [
|
||||
path('grid/', self.admin_site.admin_view(self.grid_view),name='grid')
|
||||
]
|
||||
return custom_urls + urls
|
||||
|
||||
def get_queryset(self, request):
|
||||
return super().get_queryset(request).prefetch_related('tags')
|
||||
|
||||
|
@ -153,6 +160,31 @@ class SnapshotAdmin(SearchResultsAdminMixin, admin.ModelAdmin):
|
|||
obj.url.split('://www.', 1)[-1].split('://', 1)[-1][:64],
|
||||
)
|
||||
|
||||
def grid_view(self, request):
|
||||
|
||||
# cl = self.get_changelist_instance(request)
|
||||
|
||||
# Save before monkey patching to restore for changelist list view
|
||||
saved_change_list_template = self.change_list_template
|
||||
saved_list_per_page = self.list_per_page
|
||||
saved_list_max_show_all = self.list_max_show_all
|
||||
|
||||
# Monkey patch here plus core_tags.py
|
||||
self.change_list_template = 'admin/grid_change_list.html'
|
||||
self.list_per_page = 20
|
||||
self.list_max_show_all = self.list_per_page
|
||||
|
||||
# Call monkey patched view
|
||||
rendered_response = self.changelist_view(request)
|
||||
|
||||
# Restore values
|
||||
self.change_list_template = saved_change_list_template
|
||||
self.list_per_page = saved_list_per_page
|
||||
self.list_max_show_all = saved_list_max_show_all
|
||||
|
||||
return rendered_response
|
||||
|
||||
|
||||
id_str.short_description = 'ID'
|
||||
title_str.short_description = 'Title'
|
||||
url_str.short_description = 'Original URL'
|
||||
|
@ -218,7 +250,6 @@ class ArchiveBoxAdmin(admin.AdminSite):
|
|||
|
||||
return render(template_name='add_links.html', request=request, context=context)
|
||||
|
||||
|
||||
admin.site = ArchiveBoxAdmin()
|
||||
admin.site.register(get_user_model())
|
||||
admin.site.register(Snapshot, SnapshotAdmin)
|
||||
|
|
0
archivebox/core/templatetags/__init__.py
Normal file
0
archivebox/core/templatetags/__init__.py
Normal file
47
archivebox/core/templatetags/core_tags.py
Normal file
47
archivebox/core/templatetags/core_tags.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
from django import template
|
||||
from django.urls import reverse
|
||||
from django.contrib.admin.templatetags.base import InclusionAdminNode
|
||||
from django.templatetags.static import static
|
||||
|
||||
|
||||
from typing import Union
|
||||
|
||||
from core.models import ArchiveResult
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.simple_tag
|
||||
def snapshot_image(snapshot):
|
||||
result = ArchiveResult.objects.filter(snapshot=snapshot, extractor='screenshot', status='succeeded').first()
|
||||
if result:
|
||||
return reverse('LinkAssets', args=[f'{str(snapshot.timestamp)}/{result.output}'])
|
||||
|
||||
return static('archive.png')
|
||||
|
||||
@register.filter
|
||||
def file_size(num_bytes: Union[int, float]) -> str:
|
||||
for count in ['Bytes','KB','MB','GB']:
|
||||
if num_bytes > -1024.0 and num_bytes < 1024.0:
|
||||
return '%3.1f %s' % (num_bytes, count)
|
||||
num_bytes /= 1024.0
|
||||
return '%3.1f %s' % (num_bytes, 'TB')
|
||||
|
||||
def result_list(cl):
|
||||
"""
|
||||
Monkey patched result
|
||||
"""
|
||||
num_sorted_fields = 0
|
||||
return {
|
||||
'cl': cl,
|
||||
'num_sorted_fields': num_sorted_fields,
|
||||
'results': cl.result_list,
|
||||
}
|
||||
|
||||
@register.tag(name='snapshots_grid')
|
||||
def result_list_tag(parser, token):
|
||||
return InclusionAdminNode(
|
||||
parser, token,
|
||||
func=result_list,
|
||||
template_name='snapshots_grid.html',
|
||||
takes_context=False,
|
||||
)
|
|
@ -107,6 +107,9 @@
|
|||
<a href="{% url 'admin:password_change' %}">{% trans 'Change password' %}</a> /
|
||||
{% endif %}
|
||||
<a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a>
|
||||
|
|
||||
<a href="{% url 'admin:core_snapshot_changelist' %}">☰</a>
|
||||
<a href="{% url 'admin:grid' %}"><span style="letter-spacing: -.4em">⣿⣿</span> </a>
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
91
archivebox/themes/admin/grid_change_list.html
Normal file
91
archivebox/themes/admin/grid_change_list.html
Normal file
|
@ -0,0 +1,91 @@
|
|||
{% extends "admin/base_site.html" %}
|
||||
{% load i18n admin_urls static admin_list %}
|
||||
{% load core_tags %}
|
||||
|
||||
{% block extrastyle %}
|
||||
{{ block.super }}
|
||||
<link rel="stylesheet" type="text/css" href="{% static "admin/css/changelists.css" %}">
|
||||
{% if cl.formset %}
|
||||
<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}">
|
||||
{% endif %}
|
||||
{% if cl.formset or action_form %}
|
||||
<script src="{% url 'admin:jsi18n' %}"></script>
|
||||
{% endif %}
|
||||
{{ media.css }}
|
||||
{% if not actions_on_top and not actions_on_bottom %}
|
||||
<style>
|
||||
#changelist table thead th:first-child {width: inherit}
|
||||
</style>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extrahead %}
|
||||
{{ block.super }}
|
||||
{{ media.js }}
|
||||
{% endblock %}
|
||||
|
||||
{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} change-list{% endblock %}
|
||||
|
||||
{% if not is_popup %}
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="{% url 'admin:index' %}">{% translate 'Home' %}</a>
|
||||
› <a href="{% url 'admin:app_list' app_label=cl.opts.app_label %}">{{ cl.opts.app_config.verbose_name }}</a>
|
||||
› {{ cl.opts.verbose_name_plural|capfirst }}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
|
||||
{% block coltype %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="content-main">
|
||||
{% block object-tools %}
|
||||
<ul class="object-tools">
|
||||
{% block object-tools-items %}
|
||||
{% change_list_object_tools %}
|
||||
{% endblock %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
{% if cl.formset and cl.formset.errors %}
|
||||
<p class="errornote">
|
||||
{% if cl.formset.total_error_count == 1 %}{% translate "Please correct the error below." %}{% else %}{% translate "Please correct the errors below." %}{% endif %}
|
||||
</p>
|
||||
{{ cl.formset.non_form_errors }}
|
||||
{% endif %}
|
||||
<div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
|
||||
<div class="changelist-form-container">
|
||||
{% block search %}{% search_form cl %}{% endblock %}
|
||||
{% block date_hierarchy %}{% if cl.date_hierarchy %}{% date_hierarchy cl %}{% endif %}{% endblock %}
|
||||
|
||||
<form id="changelist-form" method="post"{% if cl.formset and cl.formset.is_multipart %} enctype="multipart/form-data"{% endif %} novalidate>{% csrf_token %}
|
||||
{% if cl.formset %}
|
||||
<div>{{ cl.formset.management_form }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% block result_list %}
|
||||
{% comment %} {% if action_form and actions_on_top and cl.show_admin_actions %}{% admin_actions %}{% endif %} {% endcomment %}
|
||||
{% comment %}
|
||||
Table grid
|
||||
{% result_list cl %}
|
||||
{% endcomment %}
|
||||
{% snapshots_grid cl %}
|
||||
{% comment %} {% if action_form and actions_on_bottom and cl.show_admin_actions %}{% admin_actions %}{% endif %} {% endcomment %}
|
||||
{% endblock %}
|
||||
{% block pagination %}{% pagination cl %}{% endblock %}
|
||||
</form>
|
||||
</div>
|
||||
{% block filters %}
|
||||
{% if cl.has_filters %}
|
||||
<div id="changelist-filter">
|
||||
<h2>{% translate 'Filter' %}</h2>
|
||||
{% if cl.has_active_filters %}<h3 id="changelist-filter-clear">
|
||||
<a href="{{ cl.clear_all_filters_qs }}">✖ {% translate "Clear all filters" %}</a>
|
||||
</h3>{% endif %}
|
||||
{% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
158
archivebox/themes/admin/snapshots_grid.html
Normal file
158
archivebox/themes/admin/snapshots_grid.html
Normal file
|
@ -0,0 +1,158 @@
|
|||
{% load i18n admin_urls static admin_list %}
|
||||
{% load core_tags %}
|
||||
|
||||
{% block extrastyle %}
|
||||
<style>
|
||||
* {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: orange;
|
||||
}
|
||||
h2 {
|
||||
color: #000;
|
||||
margin: 2rem 0 .5rem;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 400;
|
||||
{% comment %} text-transform: uppercase; {% endcomment %}
|
||||
}
|
||||
|
||||
card.img {
|
||||
display: block;
|
||||
border: 0;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/*************************** Cards *******************************/
|
||||
|
||||
.cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); /* see notes below */
|
||||
grid-auto-rows: minmax(200px, auto);
|
||||
grid-gap: 1rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
/*height: 200px;*/
|
||||
/*background: red;*/
|
||||
border: 2px solid #e7e7e7;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.15);
|
||||
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.15);
|
||||
display: flex;
|
||||
/* -webkit-box-orient: vertical; */
|
||||
/* -webkit-box-direction: normal; */
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
color: #5d5e5e;
|
||||
} /* li item */
|
||||
|
||||
.thumbnail img {
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
font-size: .75rem;
|
||||
padding: .5rem;
|
||||
display: flex;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
|
||||
}
|
||||
|
||||
.card-content h4{
|
||||
vertical-align:bottom;
|
||||
margin: 1.2em 0 0em 0;
|
||||
}
|
||||
|
||||
.category {
|
||||
font-size: .75rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.category {
|
||||
position: absolute;
|
||||
top: 5%;
|
||||
right: 0;
|
||||
color: #fff;
|
||||
background: #e74c3c;
|
||||
padding: 10px 15px;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.category__01 {
|
||||
background-color: #50c6db;
|
||||
|
||||
}
|
||||
|
||||
.tags{
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
footer {
|
||||
border-top: 2px solid #e7e7e7;
|
||||
{% comment %} margin: .5rem 0 0; {% endcomment %}
|
||||
{% comment %} min-height: 30px; {% endcomment %}
|
||||
font-size: .5rem;
|
||||
}
|
||||
.post-meta {
|
||||
padding: .3rem;
|
||||
}
|
||||
|
||||
.comments {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section class="cards">
|
||||
{% for obj in results %}
|
||||
<article class="card">
|
||||
<picture class="thumbnail">
|
||||
<a href="/{{obj.archive_path}}/index.html">
|
||||
<img class="category__01" src="{% snapshot_image obj%}" alt="" />
|
||||
</a>
|
||||
</picture>
|
||||
<div class="card-content">
|
||||
{% if obj.tags_str %}
|
||||
<p class="category category__01 tags">{{obj.tags_str}}</p>
|
||||
{% endif %}
|
||||
{% if obj.title %}
|
||||
<a href="{% url 'admin:core_snapshot_change' obj.id %}">
|
||||
<h4>{{obj.title|truncatechars:55 }}</h4>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% comment %} <p> TEXT If needed.</p> {% endcomment %}
|
||||
</div><!-- .card-content -->
|
||||
<footer>
|
||||
<div class="post-meta">
|
||||
<span class="timestamp">🕑 {{obj.added}}</span>
|
||||
<span class="comments">📖{{obj.num_outputs}}</span>
|
||||
<span>🗄️{{ obj.archive_size | file_size }}</span>
|
||||
</div>
|
||||
</footer>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
Loading…
Add table
Add a link
Reference in a new issue