mirror of
https://github.com/sissbruecker/linkding.git
synced 2026-02-27 22:43:15 +08:00
Use single bookmark page template
This commit is contained in:
2
Makefile
2
Makefile
@@ -16,7 +16,7 @@ test:
|
||||
|
||||
format:
|
||||
uv run black bookmarks
|
||||
uv run djlint bookmarks/templates --reformat --quiet
|
||||
uv run djlint bookmarks/templates --reformat --quiet --warn
|
||||
npx prettier bookmarks/frontend --write
|
||||
npx prettier bookmarks/styles --write
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
{% extends "shared/layout.html" %}
|
||||
{% load static %}
|
||||
{% load shared %}
|
||||
{% load bookmarks %}
|
||||
{% block content %}
|
||||
<ld-bookmark-page class="bookmarks-page grid columns-md-1 {% if bookmark_list.collapse_side_panel %}collapse-side-panel{% endif %}">
|
||||
{# Bookmark list #}
|
||||
<main class="main col-2" aria-labelledby="main-heading">
|
||||
<div class="section-header mb-0">
|
||||
<h1 id="main-heading">Archived bookmarks</h1>
|
||||
<div class="header-controls">
|
||||
{% bookmark_search bookmark_list.search mode='archived' %}
|
||||
{% include 'bookmarks/bulk_edit/toggle.html' %}
|
||||
<ld-filter-drawer-trigger>
|
||||
<button class="btn ml-2">Filters</button>
|
||||
</ld-filter-drawer-trigger>
|
||||
</div>
|
||||
</div>
|
||||
<form class="bookmark-actions"
|
||||
action="{{ bookmark_list.action_url|safe }}"
|
||||
method="post"
|
||||
autocomplete="off">
|
||||
{% csrf_token %}
|
||||
{% include 'bookmarks/bulk_edit/bar.html' with disable_actions='bulk_archive' %}
|
||||
<div id="bookmark-list-container">{% include 'bookmarks/bookmark_list.html' %}</div>
|
||||
</form>
|
||||
</main>
|
||||
{# Filters #}
|
||||
<div class="side-panel col-1 hide-md">
|
||||
{% include 'bookmarks/bundle_section.html' %}
|
||||
{% include 'bookmarks/tag_section.html' %}
|
||||
</div>
|
||||
</ld-bookmark-page>
|
||||
{% endblock %}
|
||||
{% block overlays %}
|
||||
{% include 'bookmarks/details/modal.html' %}
|
||||
{% endblock %}
|
||||
59
bookmarks/templates/bookmarks/bookmark_page.html
Normal file
59
bookmarks/templates/bookmarks/bookmark_page.html
Normal file
@@ -0,0 +1,59 @@
|
||||
{% extends "shared/layout.html" %}
|
||||
{% load static shared bookmarks %}
|
||||
{% block content %}
|
||||
<ld-bookmark-page class="bookmarks-page grid columns-md-1 {% if bookmark_list.collapse_side_panel %}collapse-side-panel{% endif %}">
|
||||
{# Bookmark list #}
|
||||
<main class="main col-2" aria-labelledby="main-heading">
|
||||
<div class="section-header {% if bookmark_list.bulk_edit_enabled %}mb-0{% endif %}">
|
||||
<h1 id="main-heading">{{ bookmark_list.list_title }}</h1>
|
||||
<div class="header-controls">
|
||||
{% bookmark_search bookmark_list.search mode=bookmark_list.search_mode %}
|
||||
{% if bookmark_list.bulk_edit_enabled %}
|
||||
<button class="btn hide-sm ml-2 bulk-edit-active-toggle" title="Bulk edit">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="20px"
|
||||
height="20px"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1" />
|
||||
<path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415z" />
|
||||
<path d="M16 5l3 3" />
|
||||
</svg>
|
||||
</button>
|
||||
{% endif %}
|
||||
<ld-filter-drawer-trigger>
|
||||
<button class="btn ml-2">Filters</button>
|
||||
</ld-filter-drawer-trigger>
|
||||
</div>
|
||||
</div>
|
||||
<form class="bookmark-actions"
|
||||
action="{{ bookmark_list.action_url|safe }}"
|
||||
method="post"
|
||||
autocomplete="off">
|
||||
{% csrf_token %}
|
||||
{% if bookmark_list.bulk_edit_enabled %}
|
||||
{% include 'bookmarks/bulk_edit_bar.html' %}
|
||||
{% endif %}
|
||||
<div id="bookmark-list-container">{% include 'bookmarks/bookmark_list.html' %}</div>
|
||||
</form>
|
||||
</main>
|
||||
{# Filters #}
|
||||
<div class="side-panel col-1 hide-md">
|
||||
{% if bundles %}
|
||||
{% include 'bookmarks/bundle_section.html' %}
|
||||
{% endif %}
|
||||
{% if user_list %}
|
||||
{% include 'bookmarks/user_section.html' %}
|
||||
{% endif %}
|
||||
{% include 'bookmarks/tag_section.html' %}
|
||||
</div>
|
||||
</ld-bookmark-page>
|
||||
{% endblock %}
|
||||
{% block overlays %}
|
||||
{% include 'bookmarks/details/modal.html' %}
|
||||
{% endblock %}
|
||||
@@ -1,16 +0,0 @@
|
||||
<button class="btn hide-sm ml-2 bulk-edit-active-toggle" title="Bulk edit">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="20px"
|
||||
height="20px"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1" />
|
||||
<path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415z" />
|
||||
<path d="M16 5l3 3" />
|
||||
</svg>
|
||||
</button>
|
||||
@@ -7,8 +7,12 @@
|
||||
<i class="form-icon"></i>
|
||||
</label>
|
||||
<select name="bulk_action" class="form-select select-sm">
|
||||
{% if not 'bulk_archive' in disable_actions %}<option value="bulk_archive">Archive</option>{% endif %}
|
||||
{% if not 'bulk_unarchive' in disable_actions %}<option value="bulk_unarchive">Unarchive</option>{% endif %}
|
||||
{% if not 'bulk_archive' in bookmark_list.bulk_edit_disabled_actions %}
|
||||
<option value="bulk_archive">Archive</option>
|
||||
{% endif %}
|
||||
{% if not 'bulk_unarchive' in bookmark_list.bulk_edit_disabled_actions %}
|
||||
<option value="bulk_unarchive">Unarchive</option>
|
||||
{% endif %}
|
||||
<option value="bulk_delete">Delete</option>
|
||||
<option value="bulk_tag">Add tags</option>
|
||||
<option value="bulk_untag">Remove tags</option>
|
||||
@@ -1,38 +0,0 @@
|
||||
{% extends "shared/layout.html" %}
|
||||
{% load static %}
|
||||
{% load shared %}
|
||||
{% load bookmarks %}
|
||||
{% block title %}Bookmarks - Linkding{% endblock %}
|
||||
{% block content %}
|
||||
<ld-bookmark-page class="bookmarks-page grid columns-md-1 {% if bookmark_list.collapse_side_panel %}collapse-side-panel{% endif %}">
|
||||
{# Bookmark list #}
|
||||
<main class="main col-2" aria-labelledby="main-heading">
|
||||
<div class="section-header mb-0">
|
||||
<h1 id="main-heading">Bookmarks</h1>
|
||||
<div class="header-controls">
|
||||
{% bookmark_search bookmark_list.search %}
|
||||
{% include 'bookmarks/bulk_edit/toggle.html' %}
|
||||
<ld-filter-drawer-trigger>
|
||||
<button class="btn ml-2">Filters</button>
|
||||
</ld-filter-drawer-trigger>
|
||||
</div>
|
||||
</div>
|
||||
<form class="bookmark-actions"
|
||||
action="{{ bookmark_list.action_url|safe }}"
|
||||
method="post"
|
||||
autocomplete="off">
|
||||
{% csrf_token %}
|
||||
{% include 'bookmarks/bulk_edit/bar.html' with disable_actions='bulk_unarchive' %}
|
||||
<div id="bookmark-list-container">{% include 'bookmarks/bookmark_list.html' %}</div>
|
||||
</form>
|
||||
</main>
|
||||
{# Filters #}
|
||||
<div class="side-panel col-1 hide-md">
|
||||
{% include 'bookmarks/bundle_section.html' %}
|
||||
{% include 'bookmarks/tag_section.html' %}
|
||||
</div>
|
||||
</ld-bookmark-page>
|
||||
{% endblock %}
|
||||
{% block overlays %}
|
||||
{% include 'bookmarks/details/modal.html' %}
|
||||
{% endblock %}
|
||||
@@ -1,44 +0,0 @@
|
||||
{% extends "shared/layout.html" %}
|
||||
{% load static %}
|
||||
{% load shared %}
|
||||
{% load bookmarks %}
|
||||
{% block content %}
|
||||
<ld-bookmark-page no-bulk-edit
|
||||
class="bookmarks-page grid columns-md-1 {% if bookmark_list.collapse_side_panel %}collapse-side-panel{% endif %}">
|
||||
{# Bookmark list #}
|
||||
<main class="main col-2" aria-labelledby="main-heading">
|
||||
<div class="section-header">
|
||||
<h1 id="main-heading">Shared bookmarks</h1>
|
||||
<div class="header-controls">
|
||||
{% bookmark_search bookmark_list.search mode='shared' %}
|
||||
<ld-filter-drawer-trigger>
|
||||
<button class="btn ml-2">Filters</button>
|
||||
</ld-filter-drawer-trigger>
|
||||
</div>
|
||||
</div>
|
||||
<form class="bookmark-actions"
|
||||
action="{{ bookmark_list.action_url|safe }}"
|
||||
method="post"
|
||||
autocomplete="off">
|
||||
{% csrf_token %}
|
||||
<div id="bookmark-list-container">{% include 'bookmarks/bookmark_list.html' %}</div>
|
||||
</form>
|
||||
</main>
|
||||
{# Filters #}
|
||||
<div class="side-panel col-1 hide-md">
|
||||
<section aria-labelledby="user-heading">
|
||||
<div class="section-header">
|
||||
<h2 id="user-heading">User</h2>
|
||||
</div>
|
||||
<div>
|
||||
{% user_select bookmark_list.search users %}
|
||||
<br>
|
||||
</div>
|
||||
</section>
|
||||
{% include 'bookmarks/tag_section.html' %}
|
||||
</div>
|
||||
</ld-bookmark-page>
|
||||
{% endblock %}
|
||||
{% block overlays %}
|
||||
{% include 'bookmarks/details/modal.html' %}
|
||||
{% endblock %}
|
||||
22
bookmarks/templates/bookmarks/user_section.html
Normal file
22
bookmarks/templates/bookmarks/user_section.html
Normal file
@@ -0,0 +1,22 @@
|
||||
{% load widget_tweaks %}
|
||||
<section aria-labelledby="user-heading">
|
||||
<div class="section-header">
|
||||
<h2 id="user-heading">User</h2>
|
||||
</div>
|
||||
<div>
|
||||
<ld-form data-form-reset>
|
||||
<form id="user-select" action="" method="get">
|
||||
{% for hidden_field in user_list.form.hidden_fields %}{{ hidden_field }}{% endfor %}
|
||||
<div class="form-group">
|
||||
<div class="d-flex">
|
||||
{% render_field user_list.form.user class+="form-select" data-submit-on-change="" %}
|
||||
<noscript>
|
||||
<button type="submit" class="btn btn-link ml-2">Apply</button>
|
||||
</noscript>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</ld-form>
|
||||
<br>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1,14 +0,0 @@
|
||||
{% load widget_tweaks %}
|
||||
<ld-form data-form-reset>
|
||||
<form id="user-select" action="" method="get">
|
||||
{% for hidden_field in form.hidden_fields %}{{ hidden_field }}{% endfor %}
|
||||
<div class="form-group">
|
||||
<div class="d-flex">
|
||||
{% render_field form.user class+="form-select" data-submit-on-change="" %}
|
||||
<noscript>
|
||||
<button type="submit" class="btn btn-link ml-2">Apply</button>
|
||||
</noscript>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</ld-form>
|
||||
@@ -1,11 +1,8 @@
|
||||
from typing import List
|
||||
|
||||
from django import template
|
||||
|
||||
from bookmarks.models import (
|
||||
BookmarkSearch,
|
||||
BookmarkSearchForm,
|
||||
User,
|
||||
)
|
||||
|
||||
register = template.Library()
|
||||
@@ -30,16 +27,3 @@ def bookmark_search(context, search: BookmarkSearch, mode: str = ""):
|
||||
"preferences_form": preferences_form,
|
||||
"mode": mode,
|
||||
}
|
||||
|
||||
|
||||
@register.inclusion_tag(
|
||||
"bookmarks/user_select.html", name="user_select", takes_context=True
|
||||
)
|
||||
def user_select(context, search: BookmarkSearch, users: List[User]):
|
||||
sorted_users = sorted(users, key=lambda x: str.lower(x.username))
|
||||
form = BookmarkSearchForm(search, editable_fields=["user"], users=sorted_users)
|
||||
return {
|
||||
"search": search,
|
||||
"users": sorted_users,
|
||||
"form": form,
|
||||
}
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
from django.db.models import QuerySet
|
||||
from django.template import Template, RequestContext
|
||||
from django.test import TestCase, RequestFactory
|
||||
|
||||
from bookmarks.models import BookmarkSearch, User
|
||||
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||
from bookmarks.views import contexts
|
||||
|
||||
|
||||
class UserSelectTagTest(TestCase, BookmarkFactoryMixin):
|
||||
def render_template(self, url: str, users: QuerySet[User] = User.objects.all()):
|
||||
def render_template(self, url: str):
|
||||
rf = RequestFactory()
|
||||
request = rf.get(url)
|
||||
request.user = self.get_or_create_test_user()
|
||||
request.user_profile = self.get_or_create_test_user().profile
|
||||
search = BookmarkSearch.from_request(request, request.GET)
|
||||
user_list = contexts.UserListContext(request, search)
|
||||
context = RequestContext(
|
||||
request,
|
||||
{
|
||||
"request": request,
|
||||
"search": search,
|
||||
"users": users,
|
||||
"user_list": user_list,
|
||||
},
|
||||
)
|
||||
template_to_render = Template(
|
||||
"{% load bookmarks %}" "{% user_select search users %}"
|
||||
)
|
||||
template_to_render = Template("{% include 'bookmarks/user_section.html' %}")
|
||||
return template_to_render.render(context)
|
||||
|
||||
def assertUserOption(self, html: str, user: User, selected: bool = False):
|
||||
@@ -49,6 +47,9 @@ class UserSelectTagTest(TestCase, BookmarkFactoryMixin):
|
||||
self.assertNotIn(needle, html)
|
||||
|
||||
def test_empty_option(self):
|
||||
user1 = self.setup_user(name="user1", enable_sharing=True)
|
||||
self.setup_bookmark(user=user1, shared=True)
|
||||
|
||||
rendered_template = self.render_template("/test")
|
||||
|
||||
self.assertInHTML(
|
||||
@@ -59,22 +60,30 @@ class UserSelectTagTest(TestCase, BookmarkFactoryMixin):
|
||||
)
|
||||
|
||||
def test_render_user_options(self):
|
||||
user1 = User.objects.create_user("user1", "user1@example.com", "password123")
|
||||
user2 = User.objects.create_user("user2", "user2@example.com", "password123")
|
||||
user3 = User.objects.create_user("user3", "user3@example.com", "password123")
|
||||
user1 = self.setup_user(name="user1", enable_sharing=True)
|
||||
user2 = self.setup_user(name="user2", enable_sharing=True)
|
||||
user3 = self.setup_user(name="user3", enable_sharing=True)
|
||||
|
||||
rendered_template = self.render_template("/test", User.objects.all())
|
||||
self.setup_bookmark(user=user1, shared=True)
|
||||
self.setup_bookmark(user=user2, shared=True)
|
||||
self.setup_bookmark(user=user3, shared=True)
|
||||
|
||||
rendered_template = self.render_template("/test")
|
||||
|
||||
self.assertUserOption(rendered_template, user1)
|
||||
self.assertUserOption(rendered_template, user2)
|
||||
self.assertUserOption(rendered_template, user3)
|
||||
|
||||
def test_preselect_user_option(self):
|
||||
user1 = User.objects.create_user("user1", "user1@example.com", "password123")
|
||||
User.objects.create_user("user2", "user2@example.com", "password123")
|
||||
User.objects.create_user("user3", "user3@example.com", "password123")
|
||||
user1 = self.setup_user(name="user1", enable_sharing=True)
|
||||
user2 = self.setup_user(name="user2", enable_sharing=True)
|
||||
user3 = self.setup_user(name="user3", enable_sharing=True)
|
||||
|
||||
rendered_template = self.render_template("/test?user=user1", User.objects.all())
|
||||
self.setup_bookmark(user=user1, shared=True)
|
||||
self.setup_bookmark(user=user2, shared=True)
|
||||
self.setup_bookmark(user=user3, shared=True)
|
||||
|
||||
rendered_template = self.render_template("/test?user=user1")
|
||||
|
||||
self.assertUserOption(rendered_template, user1, True)
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ def index(request: HttpRequest):
|
||||
|
||||
return render_bookmarks_view(
|
||||
request,
|
||||
"bookmarks/index.html",
|
||||
{
|
||||
"page_title": "Bookmarks - Linkding",
|
||||
"bookmark_list": bookmark_list,
|
||||
@@ -95,7 +94,6 @@ def archived(request: HttpRequest):
|
||||
|
||||
return render_bookmarks_view(
|
||||
request,
|
||||
"bookmarks/archive.html",
|
||||
{
|
||||
"page_title": "Archived bookmarks - Linkding",
|
||||
"bookmark_list": bookmark_list,
|
||||
@@ -130,19 +128,15 @@ def shared(request: HttpRequest):
|
||||
bookmark_details = contexts.get_details_context(
|
||||
request, contexts.SharedBookmarkDetailsContext
|
||||
)
|
||||
public_only = not request.user.is_authenticated
|
||||
users = queries.query_shared_bookmark_users(
|
||||
request.user_profile, bookmark_list.search, public_only
|
||||
)
|
||||
user_list = contexts.UserListContext(request, search)
|
||||
return render_bookmarks_view(
|
||||
request,
|
||||
"bookmarks/shared.html",
|
||||
{
|
||||
"page_title": "Shared bookmarks - Linkding",
|
||||
"bookmark_list": bookmark_list,
|
||||
"tag_cloud": tag_cloud,
|
||||
"details": bookmark_details,
|
||||
"users": users,
|
||||
"user_list": user_list,
|
||||
"rss_feed_url": reverse("linkding:feeds.public_shared"),
|
||||
},
|
||||
)
|
||||
@@ -160,7 +154,7 @@ def shared_update(request: HttpRequest):
|
||||
return render_bookmarks_update(request, bookmark_list, tag_cloud, details)
|
||||
|
||||
|
||||
def render_bookmarks_view(request: HttpRequest, template_name, context):
|
||||
def render_bookmarks_view(request: HttpRequest, context):
|
||||
if context["details"]:
|
||||
context["page_title"] = "Bookmark details - Linkding"
|
||||
|
||||
@@ -169,7 +163,7 @@ def render_bookmarks_view(request: HttpRequest, template_name, context):
|
||||
|
||||
return render(
|
||||
request,
|
||||
template_name,
|
||||
"bookmarks/bookmark_page.html",
|
||||
context,
|
||||
)
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ from bookmarks.models import (
|
||||
BookmarkAsset,
|
||||
BookmarkBundle,
|
||||
BookmarkSearch,
|
||||
BookmarkSearchForm,
|
||||
User,
|
||||
UserProfile,
|
||||
Tag,
|
||||
@@ -266,14 +267,26 @@ class BookmarkListContext:
|
||||
|
||||
|
||||
class ActiveBookmarkListContext(BookmarkListContext):
|
||||
list_title = "Bookmarks"
|
||||
search_mode = ""
|
||||
bulk_edit_enabled = True
|
||||
bulk_edit_disabled_actions = "bulk_unarchive"
|
||||
request_context = ActiveBookmarksContext
|
||||
|
||||
|
||||
class ArchivedBookmarkListContext(BookmarkListContext):
|
||||
list_title = "Archived bookmarks"
|
||||
search_mode = "archived"
|
||||
bulk_edit_enabled = True
|
||||
bulk_edit_disabled_actions = "bulk_archive"
|
||||
request_context = ArchivedBookmarksContext
|
||||
|
||||
|
||||
class SharedBookmarkListContext(BookmarkListContext):
|
||||
list_title = "Shared bookmarks"
|
||||
search_mode = "shared"
|
||||
bulk_edit_enabled = False
|
||||
bulk_edit_disabled_actions = ""
|
||||
request_context = SharedBookmarksContext
|
||||
|
||||
|
||||
@@ -649,3 +662,13 @@ class BundlesContext:
|
||||
(bundle for bundle in self.bundles if bundle.id == selected_bundle_id),
|
||||
None,
|
||||
)
|
||||
|
||||
|
||||
class UserListContext:
|
||||
def __init__(self, request: HttpRequest, search: BookmarkSearch) -> None:
|
||||
public_only = not request.user.is_authenticated
|
||||
users = queries.query_shared_bookmark_users(
|
||||
request.user_profile, search, public_only
|
||||
)
|
||||
users = sorted(users, key=lambda x: str.lower(x.username))
|
||||
self.form = BookmarkSearchForm(search, editable_fields=["user"], users=users)
|
||||
|
||||
Reference in New Issue
Block a user