Allow bulk editing unread and shared state of bookmarks (#517)

* Move bulk actions into select

* Update tests

* Implement bulk read / unread actions

* Implement bulk share/unshare actions

* Show correct archiving actions

* Allow selecting bookmarks across pages

* Dynamically update select across checkbox

* Filter available bulk actions

* Refactor tag autocomplete toggling
This commit is contained in:
Sascha Ißbrücker
2023-08-25 13:54:23 +02:00
committed by GitHub
parent 2ceac9a87d
commit e2e5930985
25 changed files with 1019 additions and 124 deletions

View File

@@ -0,0 +1,232 @@
from django.urls import reverse
from playwright.sync_api import sync_playwright, expect
from bookmarks.e2e.helpers import LinkdingE2ETestCase
from bookmarks.models import Bookmark
class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
def setup_test_data(self):
self.setup_numbered_bookmarks(50)
self.setup_numbered_bookmarks(50, archived=True)
self.setup_numbered_bookmarks(50, prefix='foo')
self.setup_numbered_bookmarks(50, archived=True, prefix='foo')
self.assertEqual(50, Bookmark.objects.filter(is_archived=False, title__startswith='Bookmark').count())
self.assertEqual(50, Bookmark.objects.filter(is_archived=True, title__startswith='Archived Bookmark').count())
self.assertEqual(50, Bookmark.objects.filter(is_archived=False, title__startswith='foo').count())
self.assertEqual(50, Bookmark.objects.filter(is_archived=True, title__startswith='foo').count())
def test_active_bookmarks_bulk_select_across(self):
self.setup_test_data()
with sync_playwright() as p:
self.open(reverse('bookmarks:index'), p)
self.locate_bulk_edit_toggle().click()
self.locate_bulk_edit_select_all().click()
self.locate_bulk_edit_select_across().click()
self.select_bulk_action('Delete')
self.locate_bulk_edit_bar().get_by_text('Execute').click()
self.locate_bulk_edit_bar().get_by_text('Confirm').click()
self.assertEqual(0, Bookmark.objects.filter(is_archived=False, title__startswith='Bookmark').count())
self.assertEqual(50, Bookmark.objects.filter(is_archived=True, title__startswith='Archived Bookmark').count())
self.assertEqual(0, Bookmark.objects.filter(is_archived=False, title__startswith='foo').count())
self.assertEqual(50, Bookmark.objects.filter(is_archived=True, title__startswith='foo').count())
def test_archived_bookmarks_bulk_select_across(self):
self.setup_test_data()
with sync_playwright() as p:
self.open(reverse('bookmarks:archived'), p)
self.locate_bulk_edit_toggle().click()
self.locate_bulk_edit_select_all().click()
self.locate_bulk_edit_select_across().click()
self.select_bulk_action('Delete')
self.locate_bulk_edit_bar().get_by_text('Execute').click()
self.locate_bulk_edit_bar().get_by_text('Confirm').click()
self.assertEqual(50, Bookmark.objects.filter(is_archived=False, title__startswith='Bookmark').count())
self.assertEqual(0, Bookmark.objects.filter(is_archived=True, title__startswith='Archived Bookmark').count())
self.assertEqual(50, Bookmark.objects.filter(is_archived=False, title__startswith='foo').count())
self.assertEqual(0, Bookmark.objects.filter(is_archived=True, title__startswith='foo').count())
def test_active_bookmarks_bulk_select_across_respects_query(self):
self.setup_test_data()
with sync_playwright() as p:
self.open(reverse('bookmarks:index') + '?q=foo', p)
self.locate_bulk_edit_toggle().click()
self.locate_bulk_edit_select_all().click()
self.locate_bulk_edit_select_across().click()
self.select_bulk_action('Delete')
self.locate_bulk_edit_bar().get_by_text('Execute').click()
self.locate_bulk_edit_bar().get_by_text('Confirm').click()
self.assertEqual(50, Bookmark.objects.filter(is_archived=False, title__startswith='Bookmark').count())
self.assertEqual(50, Bookmark.objects.filter(is_archived=True, title__startswith='Archived Bookmark').count())
self.assertEqual(0, Bookmark.objects.filter(is_archived=False, title__startswith='foo').count())
self.assertEqual(50, Bookmark.objects.filter(is_archived=True, title__startswith='foo').count())
def test_archived_bookmarks_bulk_select_across_respects_query(self):
self.setup_test_data()
with sync_playwright() as p:
self.open(reverse('bookmarks:archived') + '?q=foo', p)
self.locate_bulk_edit_toggle().click()
self.locate_bulk_edit_select_all().click()
self.locate_bulk_edit_select_across().click()
self.select_bulk_action('Delete')
self.locate_bulk_edit_bar().get_by_text('Execute').click()
self.locate_bulk_edit_bar().get_by_text('Confirm').click()
self.assertEqual(50, Bookmark.objects.filter(is_archived=False, title__startswith='Bookmark').count())
self.assertEqual(50, Bookmark.objects.filter(is_archived=True, title__startswith='Archived Bookmark').count())
self.assertEqual(50, Bookmark.objects.filter(is_archived=False, title__startswith='foo').count())
self.assertEqual(0, Bookmark.objects.filter(is_archived=True, title__startswith='foo').count())
def test_select_all_toggles_all_checkboxes(self):
self.setup_numbered_bookmarks(5)
with sync_playwright() as p:
url = reverse('bookmarks:index')
page = self.open(url, p)
self.locate_bulk_edit_toggle().click()
checkboxes = page.locator('label[ld-bulk-edit-checkbox] input')
self.assertEqual(6, checkboxes.count())
for i in range(checkboxes.count()):
expect(checkboxes.nth(i)).not_to_be_checked()
self.locate_bulk_edit_select_all().click()
for i in range(checkboxes.count()):
expect(checkboxes.nth(i)).to_be_checked()
self.locate_bulk_edit_select_all().click()
for i in range(checkboxes.count()):
expect(checkboxes.nth(i)).not_to_be_checked()
def test_select_all_shows_select_across(self):
self.setup_numbered_bookmarks(5)
with sync_playwright() as p:
url = reverse('bookmarks:index')
self.open(url, p)
self.locate_bulk_edit_toggle().click()
expect(self.locate_bulk_edit_select_across()).not_to_be_visible()
self.locate_bulk_edit_select_all().click()
expect(self.locate_bulk_edit_select_across()).to_be_visible()
self.locate_bulk_edit_select_all().click()
expect(self.locate_bulk_edit_select_across()).not_to_be_visible()
def test_select_across_is_unchecked_when_toggling_all(self):
self.setup_numbered_bookmarks(5)
with sync_playwright() as p:
url = reverse('bookmarks:index')
self.open(url, p)
self.locate_bulk_edit_toggle().click()
# Show select across, check it
self.locate_bulk_edit_select_all().click()
self.locate_bulk_edit_select_across().click()
expect(self.locate_bulk_edit_select_across()).to_be_checked()
# Hide select across by toggling select all
self.locate_bulk_edit_select_all().click()
expect(self.locate_bulk_edit_select_across()).not_to_be_visible()
# Show select across again, verify it is unchecked
self.locate_bulk_edit_select_all().click()
expect(self.locate_bulk_edit_select_across()).not_to_be_checked()
def test_select_across_is_unchecked_when_toggling_bookmark(self):
self.setup_numbered_bookmarks(5)
with sync_playwright() as p:
url = reverse('bookmarks:index')
self.open(url, p)
self.locate_bulk_edit_toggle().click()
# Show select across, check it
self.locate_bulk_edit_select_all().click()
self.locate_bulk_edit_select_across().click()
expect(self.locate_bulk_edit_select_across()).to_be_checked()
# Hide select across by toggling a single bookmark
self.locate_bookmark('Bookmark 1').locator('label[ld-bulk-edit-checkbox]').click()
expect(self.locate_bulk_edit_select_across()).not_to_be_visible()
# Show select across again, verify it is unchecked
self.locate_bookmark('Bookmark 1').locator('label[ld-bulk-edit-checkbox]').click()
expect(self.locate_bulk_edit_select_across()).not_to_be_checked()
def test_execute_resets_all_checkboxes(self):
self.setup_numbered_bookmarks(100)
with sync_playwright() as p:
url = reverse('bookmarks:index')
page = self.open(url, p)
# Select all bookmarks, enable select across
self.locate_bulk_edit_toggle().click()
self.locate_bulk_edit_select_all().click()
self.locate_bulk_edit_select_across().click()
# Get reference for bookmark list
bookmark_list = page.locator('ul[ld-bookmark-list]')
# Execute bulk action
self.select_bulk_action('Mark as unread')
self.locate_bulk_edit_bar().get_by_text('Execute').click()
self.locate_bulk_edit_bar().get_by_text('Confirm').click()
# Wait until bookmark list is updated (old reference becomes invisible)
expect(bookmark_list).not_to_be_visible()
# Verify bulk edit checkboxes are reset
checkboxes = page.locator('label[ld-bulk-edit-checkbox] input')
self.assertEqual(31, checkboxes.count())
for i in range(checkboxes.count()):
expect(checkboxes.nth(i)).not_to_be_checked()
# Toggle select all and verify select across is reset
self.locate_bulk_edit_select_all().click()
expect(self.locate_bulk_edit_select_across()).not_to_be_checked()
def test_update_select_across_bookmark_count(self):
self.setup_numbered_bookmarks(100)
with sync_playwright() as p:
url = reverse('bookmarks:index')
self.open(url, p)
self.locate_bulk_edit_toggle().click()
self.locate_bulk_edit_select_all().click()
expect(self.locate_bulk_edit_bar().get_by_text('All pages (100 bookmarks)')).to_be_visible()
self.select_bulk_action('Delete')
self.locate_bulk_edit_bar().get_by_text('Execute').click()
self.locate_bulk_edit_bar().get_by_text('Confirm').click()
self.locate_bulk_edit_select_all().click()
expect(self.locate_bulk_edit_bar().get_by_text('All pages (70 bookmarks)')).to_be_visible()