diff --git a/bookmarks/migrations/0028_userprofile_display_archive_bookmark_action_and_more.py b/bookmarks/migrations/0028_userprofile_display_archive_bookmark_action_and_more.py new file mode 100644 index 0000000..6af3d30 --- /dev/null +++ b/bookmarks/migrations/0028_userprofile_display_archive_bookmark_action_and_more.py @@ -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), + ), + ] diff --git a/bookmarks/migrations/0029_bookmark_list_actions_toast.py b/bookmarks/migrations/0029_bookmark_list_actions_toast.py new file mode 100644 index 0000000..05891b4 --- /dev/null +++ b/bookmarks/migrations/0029_bookmark_list_actions_toast.py @@ -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), + ] diff --git a/bookmarks/models.py b/bookmarks/models.py index 126353e..c321dad 100644 --- a/bookmarks/models.py +++ b/bookmarks/models.py @@ -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) @@ -366,6 +370,10 @@ class UserProfileForm(forms.ModelForm): "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", ] diff --git a/bookmarks/templates/bookmarks/bookmark_list.html b/bookmarks/templates/bookmarks/bookmark_list.html index 3c2c3c8..bc1808c 100644 --- a/bookmarks/templates/bookmarks/bookmark_list.html +++ b/bookmarks/templates/bookmarks/bookmark_list.html @@ -79,25 +79,33 @@ {% endif %} | {% endif %} - {# View link is always visible #} - View + {# View link is visible for both owned and shared bookmarks #} + {% if bookmark_list.show_view_action %} + View + {% endif %} {% if bookmark_item.is_editable %} {# Bookmark owner actions #} - Edit - {% if bookmark_item.is_archived %} - - {% else %} - + {% else %} + + {% endif %} + {% endif %} + {% if bookmark_list.show_remove_action %} + {% endif %} - {% else %} {# Shared bookmark actions #} Shared by diff --git a/bookmarks/templates/bookmarks/layout.html b/bookmarks/templates/bookmarks/layout.html index fca6a9a..b75959d 100644 --- a/bookmarks/templates/bookmarks/layout.html +++ b/bookmarks/templates/bookmarks/layout.html @@ -105,9 +105,9 @@
{% csrf_token %} {% for toast in toast_messages %} -
+
{{ toast.message }} - +
{% endfor %} diff --git a/bookmarks/templates/settings/general.html b/bookmarks/templates/settings/general.html index a8ff541..c71696b 100644 --- a/bookmarks/templates/settings/general.html +++ b/bookmarks/templates/settings/general.html @@ -39,7 +39,8 @@
- + {{ form.bookmark_description_max_lines|add_class:"form-input width-25 width-sm-100" }}
Limits the number of lines that are displayed for the bookmark description. @@ -64,6 +65,28 @@ Alternatively the keyboard shortcut e can be used to temporarily show all notes.
+
+ + + + + +
+ Which actions to display for each bookmark. +
+
{{ form.bookmark_link_target|add_class:"form-select width-25 width-sm-100" }} diff --git a/bookmarks/tests/test_bookmarks_list_template.py b/bookmarks/tests/test_bookmarks_list_template.py index e7e8311..e76bc7c 100644 --- a/bookmarks/tests/test_bookmarks_list_template.py +++ b/bookmarks/tests/test_bookmarks_list_template.py @@ -61,6 +61,20 @@ class BookmarkListTemplateTest(TestCase, BookmarkFactoryMixin, HtmlTestMixin): 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]) @@ -69,7 +83,37 @@ class BookmarkListTemplateTest(TestCase, BookmarkFactoryMixin, HtmlTestMixin): View """, html, - count=1, + count=count, + ) + + def assertEditLinkCount(self, html: str, bookmark: Bookmark, count=1): + edit_url = reverse("bookmarks:edit", args=[bookmark.id]) + self.assertInHTML( + f""" + Edit + """, + html, + count=count, + ) + + def assertArchiveLinkCount(self, html: str, bookmark: Bookmark, count=1): + self.assertInHTML( + f""" + + """, + html, + count=count, + ) + + def assertDeleteLinkCount(self, html: str, bookmark: Bookmark, count=1): + self.assertInHTML( + f""" + + """, + html, + count=count, ) def assertBookmarkActions(self, html: str, bookmark: Bookmark): @@ -79,33 +123,9 @@ class BookmarkListTemplateTest(TestCase, BookmarkFactoryMixin, HtmlTestMixin): self.assertBookmarkActionsCount(html, bookmark, count=0) def assertBookmarkActionsCount(self, html: str, bookmark: Bookmark, count=1): - # Edit link - edit_url = reverse("bookmarks:edit", args=[bookmark.id]) - self.assertInHTML( - f""" - Edit - """, - html, - count=count, - ) - # Archive link - self.assertInHTML( - f""" - - """, - html, - count=count, - ) - # Delete link - self.assertInHTML( - f""" - - """, - html, - count=count, - ) + 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) @@ -535,6 +555,54 @@ class BookmarkListTemplateTest(TestCase, BookmarkFactoryMixin, HtmlTestMixin): 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" diff --git a/bookmarks/tests/test_settings_general_view.py b/bookmarks/tests/test_settings_general_view.py index 61058e9..7f8e7c8 100644 --- a/bookmarks/tests/test_settings_general_view.py +++ b/bookmarks/tests/test_settings_general_view.py @@ -33,6 +33,10 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin): "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": "", } @@ -67,6 +71,10 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin): "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; }", } @@ -104,6 +112,22 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin): ) 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"] ) diff --git a/bookmarks/tests/test_toasts_view.py b/bookmarks/tests/test_toasts_view.py index 451288b..23bb426 100644 --- a/bookmarks/tests/test_toasts_view.py +++ b/bookmarks/tests/test_toasts_view.py @@ -40,7 +40,7 @@ class ToastsViewTestCase(TestCase, BookmarkFactoryMixin): # Should render toasts container self.assertContains(response, '
') # Should render two toasts - self.assertContains(response, '
', count=2) + self.assertContains(response, '
', count=2) def test_should_not_render_acknowledged_toasts(self): self.create_toast(acknowledged=True) @@ -81,9 +81,9 @@ class ToastsViewTestCase(TestCase, BookmarkFactoryMixin): def test_toast_content(self): toast = self.create_toast() expected_toast = f""" -
+
{toast.message} - +
""" diff --git a/bookmarks/views/partials/contexts.py b/bookmarks/views/partials/contexts.py index 8a6a79c..2320268 100644 --- a/bookmarks/views/partials/contexts.py +++ b/bookmarks/views/partials/contexts.py @@ -99,6 +99,10 @@ class BookmarkListContext: self.description_display = user_profile.bookmark_description_display self.description_max_lines = user_profile.bookmark_description_max_lines self.show_url = user_profile.display_url + self.show_view_action = user_profile.display_view_bookmark_action + self.show_edit_action = user_profile.display_edit_bookmark_action + self.show_archive_action = user_profile.display_archive_bookmark_action + self.show_remove_action = user_profile.display_remove_bookmark_action self.show_favicons = user_profile.enable_favicons self.show_notes = user_profile.permanent_notes