Skip to content

Commit

Permalink
Make bookmark list actions configurable (#666)
Browse files Browse the repository at this point in the history
* Make bookmark list actions configurable

* Add upgrade notice
  • Loading branch information
sissbruecker committed Mar 29, 2024
1 parent 92f62d3 commit d9b7996
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Generated by Django 5.0.2 on 2024-03-29 20:05

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("bookmarks", "0027_userprofile_bookmark_description_display_and_more"),
]

operations = [
migrations.AddField(
model_name="userprofile",
name="display_archive_bookmark_action",
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name="userprofile",
name="display_edit_bookmark_action",
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name="userprofile",
name="display_remove_bookmark_action",
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name="userprofile",
name="display_view_bookmark_action",
field=models.BooleanField(default=True),
),
]
34 changes: 34 additions & 0 deletions bookmarks/migrations/0029_bookmark_list_actions_toast.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Generated by Django 5.0.2 on 2024-03-29 21:25

from django.db import migrations
from django.contrib.auth import get_user_model

from bookmarks.models import Toast

User = get_user_model()


def forwards(apps, schema_editor):

for user in User.objects.all():
toast = Toast(
key="bookmark_list_actions_hint",
message="This version adds a new link to each bookmark to view details in a dialog. If you feel there is too much clutter you can now hide individual links in the settings.",
owner=user,
)
toast.save()


def reverse(apps, schema_editor):
Toast.objects.filter(key="bookmark_list_actions_hint").delete()


class Migration(migrations.Migration):

dependencies = [
("bookmarks", "0028_userprofile_display_archive_bookmark_action_and_more"),
]

operations = [
migrations.RunPython(forwards, reverse),
]
8 changes: 8 additions & 0 deletions bookmarks/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,10 @@ class UserProfile(models.Model):
enable_public_sharing = models.BooleanField(default=False, null=False)
enable_favicons = models.BooleanField(default=False, null=False)
display_url = models.BooleanField(default=False, null=False)
display_view_bookmark_action = models.BooleanField(default=True, null=False)
display_edit_bookmark_action = models.BooleanField(default=True, null=False)
display_archive_bookmark_action = models.BooleanField(default=True, null=False)
display_remove_bookmark_action = models.BooleanField(default=True, null=False)
permanent_notes = models.BooleanField(default=False, null=False)
custom_css = models.TextField(blank=True, null=False)
search_preferences = models.JSONField(default=dict, null=False)
Expand All @@ -366,6 +370,10 @@ class Meta:
"enable_public_sharing",
"enable_favicons",
"display_url",
"display_view_bookmark_action",
"display_edit_bookmark_action",
"display_archive_bookmark_action",
"display_remove_bookmark_action",
"permanent_notes",
"custom_css",
]
Expand Down
38 changes: 23 additions & 15 deletions bookmarks/templates/bookmarks/bookmark_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -79,25 +79,33 @@
{% endif %}
<span>|</span>
{% endif %}
{# View link is always visible #}
<a ld-modal
modal-url="{% url 'bookmarks:details_modal' bookmark_item.id %}?return_url={{ bookmark_list.return_url|urlencode }}"
href="{% url 'bookmarks:details' bookmark_item.id %}">View</a>
{# View link is visible for both owned and shared bookmarks #}
{% if bookmark_list.show_view_action %}
<a ld-modal
modal-url="{% url 'bookmarks:details_modal' bookmark_item.id %}?return_url={{ bookmark_list.return_url|urlencode }}"
href="{% url 'bookmarks:details' bookmark_item.id %}">View</a>
{% endif %}
{% if bookmark_item.is_editable %}
{# Bookmark owner actions #}
<a href="{% url 'bookmarks:edit' bookmark_item.id %}?return_url={{ bookmark_list.return_url|urlencode }}">Edit</a>
{% if bookmark_item.is_archived %}
<button type="submit" name="unarchive" value="{{ bookmark_item.id }}"
class="btn btn-link btn-sm">Unarchive
</button>
{% else %}
<button type="submit" name="archive" value="{{ bookmark_item.id }}"
class="btn btn-link btn-sm">Archive
{% if bookmark_list.show_edit_action %}
<a href="{% url 'bookmarks:edit' bookmark_item.id %}?return_url={{ bookmark_list.return_url|urlencode }}">Edit</a>
{% endif %}
{% if bookmark_list.show_archive_action %}
{% if bookmark_item.is_archived %}
<button type="submit" name="unarchive" value="{{ bookmark_item.id }}"
class="btn btn-link btn-sm">Unarchive
</button>
{% else %}
<button type="submit" name="archive" value="{{ bookmark_item.id }}"
class="btn btn-link btn-sm">Archive
</button>
{% endif %}
{% endif %}
{% if bookmark_list.show_remove_action %}
<button ld-confirm-button type="submit" name="remove" value="{{ bookmark_item.id }}"
class="btn btn-link btn-sm">Remove
</button>
{% endif %}
<button ld-confirm-button type="submit" name="remove" value="{{ bookmark_item.id }}"
class="btn btn-link btn-sm">Remove
</button>
{% else %}
{# Shared bookmark actions #}
<span>Shared by
Expand Down
4 changes: 2 additions & 2 deletions bookmarks/templates/bookmarks/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@
<form action="{% url 'bookmarks:toasts.acknowledge' %}?return_url={{ request.path | urlencode }}" method="post">
{% csrf_token %}
{% for toast in toast_messages %}
<div class="toast">
<div class="toast d-flex">
{{ toast.message }}
<button type="submit" name="toast" value="{{ toast.id }}" class="btn btn-clear float-right"></button>
<button type="submit" name="toast" value="{{ toast.id }}" class="btn btn-clear"></button>
</div>
{% endfor %}
</form>
Expand Down
25 changes: 24 additions & 1 deletion bookmarks/templates/settings/general.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ <h2>Profile</h2>
</div>
<div
class="form-group {% if request.user_profile.bookmark_description_display == 'inline' %}d-hide{% endif %}">
<label for="{{ form.bookmark_description_max_lines.id_for_label }}" class="form-label">Bookmark description max lines</label>
<label for="{{ form.bookmark_description_max_lines.id_for_label }}" class="form-label">Bookmark description
max lines</label>
{{ form.bookmark_description_max_lines|add_class:"form-input width-25 width-sm-100" }}
<div class="form-input-hint">
Limits the number of lines that are displayed for the bookmark description.
Expand All @@ -64,6 +65,28 @@ <h2>Profile</h2>
Alternatively the keyboard shortcut <code>e</code> can be used to temporarily show all notes.
</div>
</div>
<div class="form-group">
<label>Bookmark actions</label>
<label for="{{ form.display_view_bookmark_action.id_for_label }}" class="form-checkbox">
{{ form.display_view_bookmark_action }}
<i class="form-icon"></i> View
</label>
<label for="{{ form.display_edit_bookmark_action.id_for_label }}" class="form-checkbox">
{{ form.display_edit_bookmark_action }}
<i class="form-icon"></i> Edit
</label>
<label for="{{ form.display_archive_bookmark_action.id_for_label }}" class="form-checkbox">
{{ form.display_archive_bookmark_action }}
<i class="form-icon"></i> Archive
</label>
<label for="{{ form.display_remove_bookmark_action.id_for_label }}" class="form-checkbox">
{{ form.display_remove_bookmark_action }}
<i class="form-icon"></i> Remove
</label>
<div class="form-input-hint">
Which actions to display for each bookmark.
</div>
</div>
<div class="form-group">
<label for="{{ form.bookmark_link_target.id_for_label }}" class="form-label">Open bookmarks in</label>
{{ form.bookmark_link_target|add_class:"form-select width-25 width-sm-100" }}
Expand Down
90 changes: 79 additions & 11 deletions bookmarks/tests/test_bookmarks_list_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,20 @@ def assertWebArchiveLink(

def assertViewLink(
self, html: str, bookmark: Bookmark, return_url=reverse("bookmarks:index")
):
self.assertViewLinkCount(html, bookmark, return_url=return_url)

def assertNoViewLink(
self, html: str, bookmark: Bookmark, return_url=reverse("bookmarks:index")
):
self.assertViewLinkCount(html, bookmark, count=0, return_url=return_url)

def assertViewLinkCount(
self,
html: str,
bookmark: Bookmark,
count=1,
return_url=reverse("bookmarks:index"),
):
details_url = reverse("bookmarks:details", args=[bookmark.id])
details_modal_url = reverse("bookmarks:details_modal", args=[bookmark.id])
Expand All @@ -69,17 +83,10 @@ def assertViewLink(
<a ld-modal modal-url="{details_modal_url}?return_url={return_url}" href="{details_url}">View</a>
""",
html,
count=1,
count=count,
)

def assertBookmarkActions(self, html: str, bookmark: Bookmark):
self.assertBookmarkActionsCount(html, bookmark, count=1)

def assertNoBookmarkActions(self, html: str, bookmark: Bookmark):
self.assertBookmarkActionsCount(html, bookmark, count=0)

def assertBookmarkActionsCount(self, html: str, bookmark: Bookmark, count=1):
# Edit link
def assertEditLinkCount(self, html: str, bookmark: Bookmark, count=1):
edit_url = reverse("bookmarks:edit", args=[bookmark.id])
self.assertInHTML(
f"""
Expand All @@ -88,7 +95,8 @@ def assertBookmarkActionsCount(self, html: str, bookmark: Bookmark, count=1):
html,
count=count,
)
# Archive link

def assertArchiveLinkCount(self, html: str, bookmark: Bookmark, count=1):
self.assertInHTML(
f"""
<button type="submit" name="archive" value="{bookmark.id}"
Expand All @@ -97,7 +105,8 @@ def assertBookmarkActionsCount(self, html: str, bookmark: Bookmark, count=1):
html,
count=count,
)
# Delete link

def assertDeleteLinkCount(self, html: str, bookmark: Bookmark, count=1):
self.assertInHTML(
f"""
<button ld-confirm-button type="submit" name="remove" value="{bookmark.id}"
Expand All @@ -107,6 +116,17 @@ def assertBookmarkActionsCount(self, html: str, bookmark: Bookmark, count=1):
count=count,
)

def assertBookmarkActions(self, html: str, bookmark: Bookmark):
self.assertBookmarkActionsCount(html, bookmark, count=1)

def assertNoBookmarkActions(self, html: str, bookmark: Bookmark):
self.assertBookmarkActionsCount(html, bookmark, count=0)

def assertBookmarkActionsCount(self, html: str, bookmark: Bookmark, count=1):
self.assertEditLinkCount(html, bookmark, count=count)
self.assertArchiveLinkCount(html, bookmark, count=count)
self.assertDeleteLinkCount(html, bookmark, count=count)

def assertShareInfo(self, html: str, bookmark: Bookmark):
self.assertShareInfoCount(html, bookmark, 1)

Expand Down Expand Up @@ -535,6 +555,54 @@ def test_show_bookmark_actions_for_owned_bookmarks(self):
self.assertBookmarkActions(html, bookmark)
self.assertNoShareInfo(html, bookmark)

def test_hide_view_link(self):
bookmark = self.setup_bookmark()
profile = self.get_or_create_test_user().profile
profile.display_view_bookmark_action = False
profile.save()

html = self.render_template()
self.assertViewLinkCount(html, bookmark, count=0)
self.assertEditLinkCount(html, bookmark, count=1)
self.assertArchiveLinkCount(html, bookmark, count=1)
self.assertDeleteLinkCount(html, bookmark, count=1)

def test_hide_edit_link(self):
bookmark = self.setup_bookmark()
profile = self.get_or_create_test_user().profile
profile.display_edit_bookmark_action = False
profile.save()

html = self.render_template()
self.assertViewLinkCount(html, bookmark, count=1)
self.assertEditLinkCount(html, bookmark, count=0)
self.assertArchiveLinkCount(html, bookmark, count=1)
self.assertDeleteLinkCount(html, bookmark, count=1)

def test_hide_archive_link(self):
bookmark = self.setup_bookmark()
profile = self.get_or_create_test_user().profile
profile.display_archive_bookmark_action = False
profile.save()

html = self.render_template()
self.assertViewLinkCount(html, bookmark, count=1)
self.assertEditLinkCount(html, bookmark, count=1)
self.assertArchiveLinkCount(html, bookmark, count=0)
self.assertDeleteLinkCount(html, bookmark, count=1)

def test_hide_remove_link(self):
bookmark = self.setup_bookmark()
profile = self.get_or_create_test_user().profile
profile.display_remove_bookmark_action = False
profile.save()

html = self.render_template()
self.assertViewLinkCount(html, bookmark, count=1)
self.assertEditLinkCount(html, bookmark, count=1)
self.assertArchiveLinkCount(html, bookmark, count=1)
self.assertDeleteLinkCount(html, bookmark, count=0)

def test_show_share_info_for_non_owned_bookmarks(self):
other_user = User.objects.create_user(
"otheruser", "otheruser@example.com", "password123"
Expand Down
24 changes: 24 additions & 0 deletions bookmarks/tests/test_settings_general_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ def create_profile_form_data(self, overrides=None):
"enable_favicons": False,
"tag_search": UserProfile.TAG_SEARCH_STRICT,
"display_url": False,
"display_view_bookmark_action": True,
"display_edit_bookmark_action": True,
"display_archive_bookmark_action": True,
"display_remove_bookmark_action": True,
"permanent_notes": False,
"custom_css": "",
}
Expand Down Expand Up @@ -67,6 +71,10 @@ def test_update_profile(self):
"enable_favicons": True,
"tag_search": UserProfile.TAG_SEARCH_LAX,
"display_url": True,
"display_view_bookmark_action": False,
"display_edit_bookmark_action": False,
"display_archive_bookmark_action": False,
"display_remove_bookmark_action": False,
"permanent_notes": True,
"custom_css": "body { background-color: #000; }",
}
Expand Down Expand Up @@ -104,6 +112,22 @@ def test_update_profile(self):
)
self.assertEqual(self.user.profile.tag_search, form_data["tag_search"])
self.assertEqual(self.user.profile.display_url, form_data["display_url"])
self.assertEqual(
self.user.profile.display_view_bookmark_action,
form_data["display_view_bookmark_action"],
)
self.assertEqual(
self.user.profile.display_edit_bookmark_action,
form_data["display_edit_bookmark_action"],
)
self.assertEqual(
self.user.profile.display_archive_bookmark_action,
form_data["display_archive_bookmark_action"],
)
self.assertEqual(
self.user.profile.display_remove_bookmark_action,
form_data["display_remove_bookmark_action"],
)
self.assertEqual(
self.user.profile.permanent_notes, form_data["permanent_notes"]
)
Expand Down
6 changes: 3 additions & 3 deletions bookmarks/tests/test_toasts_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def test_should_render_unacknowledged_toasts(self):
# Should render toasts container
self.assertContains(response, '<div class="toasts">')
# Should render two toasts
self.assertContains(response, '<div class="toast">', count=2)
self.assertContains(response, '<div class="toast d-flex">', count=2)

def test_should_not_render_acknowledged_toasts(self):
self.create_toast(acknowledged=True)
Expand Down Expand Up @@ -81,9 +81,9 @@ def test_form_tag(self):
def test_toast_content(self):
toast = self.create_toast()
expected_toast = f"""
<div class="toast">
<div class="toast d-flex">
{toast.message}
<button type="submit" name="toast" value="{toast.id}" class="btn btn-clear float-right"></button>
<button type="submit" name="toast" value="{toast.id}" class="btn btn-clear"></button>
</div>
"""

Expand Down

0 comments on commit d9b7996

Please sign in to comment.