mirror of
https://github.com/sissbruecker/linkding
synced 2024-11-21 19:03:02 +00:00
Add option for disabling tag grouping (#735)
* Configurable tag grouping * update tag group name --------- Co-authored-by: Sascha Ißbrücker <sascha.issbruecker@gmail.com>
This commit is contained in:
parent
a92a35cfb8
commit
e03f536925
6 changed files with 106 additions and 2 deletions
22
bookmarks/migrations/0035_userprofile_tag_grouping.py
Normal file
22
bookmarks/migrations/0035_userprofile_tag_grouping.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Generated by Django 5.0.3 on 2024-05-14 08:28
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("bookmarks", "0034_bookmark_preview_image_file_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="userprofile",
|
||||
name="tag_grouping",
|
||||
field=models.CharField(
|
||||
choices=[("alphabetical", "Alphabetical"), ("disabled", "Disabled")],
|
||||
default="alphabetical",
|
||||
max_length=12,
|
||||
),
|
||||
),
|
||||
]
|
|
@ -352,6 +352,12 @@ class UserProfile(models.Model):
|
|||
(TAG_SEARCH_STRICT, "Strict"),
|
||||
(TAG_SEARCH_LAX, "Lax"),
|
||||
]
|
||||
TAG_GROUPING_ALPHABETICAL = "alphabetical"
|
||||
TAG_GROUPING_DISABLED = "disabled"
|
||||
TAG_GROUPING_CHOICES = [
|
||||
(TAG_GROUPING_ALPHABETICAL, "Alphabetical"),
|
||||
(TAG_GROUPING_DISABLED, "Disabled"),
|
||||
]
|
||||
user = models.OneToOneField(
|
||||
get_user_model(), related_name="profile", on_delete=models.CASCADE
|
||||
)
|
||||
|
@ -392,6 +398,12 @@ class UserProfile(models.Model):
|
|||
blank=False,
|
||||
default=TAG_SEARCH_STRICT,
|
||||
)
|
||||
tag_grouping = models.CharField(
|
||||
max_length=12,
|
||||
choices=TAG_GROUPING_CHOICES,
|
||||
blank=False,
|
||||
default=TAG_GROUPING_ALPHABETICAL,
|
||||
)
|
||||
enable_sharing = models.BooleanField(default=False, null=False)
|
||||
enable_public_sharing = models.BooleanField(default=False, null=False)
|
||||
enable_favicons = models.BooleanField(default=False, null=False)
|
||||
|
@ -419,6 +431,7 @@ class UserProfileForm(forms.ModelForm):
|
|||
"bookmark_link_target",
|
||||
"web_archive_integration",
|
||||
"tag_search",
|
||||
"tag_grouping",
|
||||
"enable_sharing",
|
||||
"enable_public_sharing",
|
||||
"enable_favicons",
|
||||
|
|
|
@ -110,6 +110,14 @@
|
|||
result will also include bookmarks where a search term matches otherwise.
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.tag_grouping.id_for_label }}" class="form-label">Tag grouping</label>
|
||||
{{ form.tag_grouping|add_class:"form-select width-25 width-sm-100" }}
|
||||
<div class="form-input-hint">
|
||||
In alphabetical mode, tags will be grouped by the first letter.
|
||||
If disabled, tags will not be grouped.
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.enable_favicons.id_for_label }}" class="form-checkbox">
|
||||
{{ form.enable_favicons }}
|
||||
|
|
|
@ -34,6 +34,7 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
|
|||
"enable_preview_images": False,
|
||||
"enable_automatic_html_snapshots": True,
|
||||
"tag_search": UserProfile.TAG_SEARCH_STRICT,
|
||||
"tag_grouping": UserProfile.TAG_GROUPING_ALPHABETICAL,
|
||||
"display_url": False,
|
||||
"display_view_bookmark_action": True,
|
||||
"display_edit_bookmark_action": True,
|
||||
|
@ -92,6 +93,7 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
|
|||
"enable_preview_images": True,
|
||||
"enable_automatic_html_snapshots": False,
|
||||
"tag_search": UserProfile.TAG_SEARCH_LAX,
|
||||
"tag_grouping": UserProfile.TAG_GROUPING_DISABLED,
|
||||
"display_url": True,
|
||||
"display_view_bookmark_action": False,
|
||||
"display_edit_bookmark_action": False,
|
||||
|
@ -141,6 +143,7 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
|
|||
form_data["enable_automatic_html_snapshots"],
|
||||
)
|
||||
self.assertEqual(self.user.profile.tag_search, form_data["tag_search"])
|
||||
self.assertEqual(self.user.profile.tag_grouping, form_data["tag_grouping"])
|
||||
self.assertEqual(self.user.profile.display_url, form_data["display_url"])
|
||||
self.assertEqual(
|
||||
self.user.profile.display_view_bookmark_action,
|
||||
|
|
|
@ -140,6 +140,43 @@ class TagCloudTemplateTest(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
|
|||
],
|
||||
)
|
||||
|
||||
def test_group_when_grouping_disabled(self):
|
||||
profile = self.get_or_create_test_user().profile
|
||||
profile.tag_grouping = UserProfile.TAG_GROUPING_DISABLED
|
||||
profile.save()
|
||||
|
||||
tags = [
|
||||
self.setup_tag(name="Cockatoo"),
|
||||
self.setup_tag(name="Badger"),
|
||||
self.setup_tag(name="Buffalo"),
|
||||
self.setup_tag(name="Chihuahua"),
|
||||
self.setup_tag(name="Alpaca"),
|
||||
self.setup_tag(name="Coyote"),
|
||||
self.setup_tag(name="Aardvark"),
|
||||
self.setup_tag(name="Bumblebee"),
|
||||
self.setup_tag(name="Armadillo"),
|
||||
]
|
||||
self.setup_bookmark(tags=tags)
|
||||
|
||||
rendered_template = self.render_template()
|
||||
|
||||
self.assertTagGroups(
|
||||
rendered_template,
|
||||
[
|
||||
[
|
||||
"Aardvark",
|
||||
"Alpaca",
|
||||
"Armadillo",
|
||||
"Badger",
|
||||
"Buffalo",
|
||||
"Bumblebee",
|
||||
"Chihuahua",
|
||||
"Cockatoo",
|
||||
"Coyote",
|
||||
],
|
||||
],
|
||||
)
|
||||
|
||||
def test_no_duplicate_tag_names(self):
|
||||
tags = [
|
||||
self.setup_tag(name="shared", user=self.setup_user(enable_sharing=True)),
|
||||
|
|
|
@ -264,7 +264,16 @@ class TagGroup:
|
|||
return f"<{self.char} TagGroup>"
|
||||
|
||||
@staticmethod
|
||||
def create_tag_groups(tags: Set[Tag]):
|
||||
def create_tag_groups(mode: str, tags: Set[Tag]):
|
||||
if mode == UserProfile.TAG_GROUPING_ALPHABETICAL:
|
||||
return TagGroup._create_tag_groups_alphabetical(tags)
|
||||
elif mode == UserProfile.TAG_GROUPING_DISABLED:
|
||||
return TagGroup._create_tag_groups_disabled(tags)
|
||||
else:
|
||||
raise ValueError(f"{mode} is not a valid tag grouping mode")
|
||||
|
||||
@staticmethod
|
||||
def _create_tag_groups_alphabetical(tags: Set[Tag]):
|
||||
# Ensure groups, as well as tags within groups, are ordered alphabetically
|
||||
sorted_tags = sorted(tags, key=lambda x: str.lower(x.name))
|
||||
group = None
|
||||
|
@ -289,6 +298,18 @@ class TagGroup:
|
|||
groups.append(cjk_group)
|
||||
return groups
|
||||
|
||||
@staticmethod
|
||||
def _create_tag_groups_disabled(tags: Set[Tag]):
|
||||
if len(tags) == 0:
|
||||
return []
|
||||
|
||||
sorted_tags = sorted(tags, key=lambda x: str.lower(x.name))
|
||||
group = TagGroup("Ungrouped")
|
||||
for tag in sorted_tags:
|
||||
group.tags.append(tag)
|
||||
|
||||
return [group]
|
||||
|
||||
|
||||
class TagCloudContext:
|
||||
request_context = RequestContext
|
||||
|
@ -311,7 +332,7 @@ class TagCloudContext:
|
|||
)
|
||||
has_selected_tags = len(unique_selected_tags) > 0
|
||||
unselected_tags = set(unique_tags).symmetric_difference(unique_selected_tags)
|
||||
groups = TagGroup.create_tag_groups(unselected_tags)
|
||||
groups = TagGroup.create_tag_groups(user_profile.tag_grouping, unselected_tags)
|
||||
|
||||
self.tags = unique_tags
|
||||
self.groups = groups
|
||||
|
|
Loading…
Reference in a new issue