-
← {% trans "Collections" %}
-
{{ collection.title }}
-
- {% if collection.team %}
{{ collection.team.name }}{% else %}
{{ collection.get_visibility_display }}{% endif %}
- {% for tag in collection.tags.all %}
#{{ tag.name }}{% endfor %}
+
+
-
- {% if collection.description %}
{{ collection.description|markdown }}
{% endif %}
+ {% if collection.description %}
{{ collection.description|markdown }}
{% endif %}
+
{% if sections %}
-
+
{% endif %}
- {% if pending_item %}
-
-
{% trans "The note has a different visibility" %}
-
{% trans "To add it, change its visibility or create a separate copy for this collection." %}
-
{{ pending_item.content|truncatechars:180 }}
-
- {% if not pending_can_convert %}
{% trans "The original cannot be changed because it is used elsewhere or you cannot edit it." %}
{% endif %}
-
- {% endif %}
-
-
+
{% for section in sections %}
-
-
-
{{ section.title|default:section.item.content|truncatechars:100 }}
-
#{{ section.item.id }}
-
-
{{ section.item|item_markdown }}
- {% if section.item.comment %}
{{ section.item.comment|markdown }}
{% endif %}
- {% if can_edit %}
-
-
-
-
-
{% endif %}
-
+
+ {% if section.title %}{{ section.title }}
{% endif %}
+ {{ section.item|item_markdown }}
+ {% if section.item.comment %}{{ section.item.comment|markdown }}
{% endif %}
+
{% empty %}
{% trans "This collection has no sections yet." %}
{% endfor %}
-
- {% if can_edit %}
-
-
{% trans "Add existing note" %}
-
-
- {% for item in candidates %}
{{ item.content|truncatechars:180 }}
#{{ item.id }} · {{ item.get_visibility_display }}{% if item.team %} · {{ item.team.name }}{% endif %}
{% empty %}
{% trans "No matching notes." %}
{% endfor %}
-
-
- {% endif %}
-
+
{% endblock %}
diff --git a/core/templates/core/collection_manage.html b/core/templates/core/collection_manage.html
new file mode 100644
index 0000000..fb483ae
--- /dev/null
+++ b/core/templates/core/collection_manage.html
@@ -0,0 +1,67 @@
+{% extends 'core/base.html' %}
+{% load i18n markdown_extras %}
+{% block content %}
+
{% trans "Collections are currently available on desktop only." %}
+
+
+
+
← {% trans "View collection" %}
+
{{ collection.title }}
+
+ {% if collection.team %}{{ collection.team.name }}{% else %}{{ collection.get_visibility_display }}{% endif %}
+ {% for tag in collection.tags.all %}#{{ tag.name }}{% endfor %}
+
+
+ {% if can_edit %}
{% endif %}
+
+
+ {% if collection.description %}
{{ collection.description|markdown }}
{% endif %}
+
+ {% if sections %}
+
+ {% endif %}
+
+ {% if pending_item %}
+
+
{% trans "The note has a different visibility" %}
+
{% trans "To add it, change its visibility or create a separate copy for this collection." %}
+
{{ pending_item.content|truncatechars:180 }}
+
+ {% if not pending_can_convert %}
{% trans "The original cannot be changed because it is used elsewhere or you cannot edit it." %}
{% endif %}
+
+ {% endif %}
+
+
+ {% for section in sections %}
+
+
+
{{ section.title|default:section.item.content|truncatechars:100 }}
+
#{{ section.item.id }}
+
+
{{ section.item|item_markdown }}
+ {% if section.item.comment %}
{{ section.item.comment|markdown }}
{% endif %}
+ {% if can_edit %}
+
+
+
+
+
{% endif %}
+
+ {% empty %}
{% trans "This collection has no sections yet." %}
{% endfor %}
+
+
+ {% if can_edit %}
+
+
{% trans "Add existing note" %}
+
+
+ {% for item in candidates %}
{{ item.content|truncatechars:180 }}
#{{ item.id }} · {{ item.get_visibility_display }}{% if item.team %} · {{ item.team.name }}{% endif %}
{% empty %}
{% trans "No matching notes." %}
{% endfor %}
+
+
+ {% endif %}
+
+{% endblock %}
diff --git a/core/tests.py b/core/tests.py
index 0277523..e8ca668 100644
--- a/core/tests.py
+++ b/core/tests.py
@@ -159,20 +159,22 @@ class CollectionTests(TestCase):
collection = Collection.objects.get()
self.assertRedirects(response, collection.get_absolute_url())
note = Item.objects.create(owner=self.user, kind=Item.Kind.NOTE, content='Introduction')
- response = self.client.post(collection.get_absolute_url(), {'action': 'add', 'item_id': note.id})
- self.assertRedirects(response, collection.get_absolute_url())
+ manage_url = reverse('collection_manage', args=[collection.id])
+ response = self.client.post(manage_url, {'action': 'add', 'item_id': note.id})
+ self.assertRedirects(response, manage_url)
self.assertTrue(CollectionSection.objects.filter(collection=collection, item=note).exists())
def test_public_collection_asks_before_copying_private_note(self):
collection = Collection.objects.create(owner=self.user, title='Public guide', visibility=Item.Visibility.PUBLIC)
note = Item.objects.create(owner=self.user, kind=Item.Kind.NOTE, content='Private section')
- response = self.client.post(collection.get_absolute_url(), {'action': 'add', 'item_id': note.id})
+ manage_url = reverse('collection_manage', args=[collection.id])
+ response = self.client.post(manage_url, {'action': 'add', 'item_id': note.id})
self.assertContains(response, 'name="mode" value="copy"')
- response = self.client.post(collection.get_absolute_url(), {
+ response = self.client.post(manage_url, {
'action': 'confirm_add', 'item_id': note.id, 'mode': 'copy',
})
- self.assertRedirects(response, collection.get_absolute_url())
+ self.assertRedirects(response, manage_url)
copied = collection.sections.get().item
self.assertNotEqual(copied.id, note.id)
self.assertEqual(copied.visibility, Item.Visibility.PUBLIC)
@@ -199,10 +201,24 @@ class CollectionTests(TestCase):
self.assertEqual(collection.team, team)
self.assertEqual(collection.visibility, Item.Visibility.TEAM)
+ def test_collection_opens_as_continuous_reading_view(self):
+ collection = Collection.objects.create(owner=self.user, title='Reading view')
+ first = Item.objects.create(owner=self.user, kind=Item.Kind.NOTE, content='First paragraph')
+ second = Item.objects.create(owner=self.user, kind=Item.Kind.NOTE, content='Second paragraph')
+ CollectionSection.objects.create(collection=collection, item=first, title='First', position=0)
+ CollectionSection.objects.create(collection=collection, item=second, position=1)
+ response = self.client.get(collection.get_absolute_url())
+ self.assertContains(response, 'collection-flow')
+ self.assertContains(response, reverse('collection_manage', args=[collection.id]))
+ self.assertNotContains(response, 'Add existing note')
+ self.assertNotContains(response, 'section_id')
+
def test_public_collection_is_visible_without_login(self):
collection = Collection.objects.create(owner=self.user, title='Public', visibility=Item.Visibility.PUBLIC)
self.client.logout()
- self.assertEqual(self.client.get(collection.get_absolute_url()).status_code, 200)
+ response = self.client.get(collection.get_absolute_url())
+ self.assertEqual(response.status_code, 200)
+ self.assertNotContains(response, reverse('collection_manage', args=[collection.id]))
def test_collection_tag_is_not_removed_as_unused(self):
tag = Tag.objects.create(name='documentation')
diff --git a/core/urls.py b/core/urls.py
index bbd82bc..0294f70 100644
--- a/core/urls.py
+++ b/core/urls.py
@@ -22,6 +22,7 @@ urlpatterns = [
path('collections/', views.collection_list, name='collection_list'),
path('collections/new/', views.collection_create, name='collection_create'),
path('collections/
/', views.collection_detail, name='collection_detail'),
+ path('collections//manage/', views.collection_manage, name='collection_manage'),
path('collections//edit/', views.collection_edit, name='collection_edit'),
path('collections//delete/', views.collection_delete, name='collection_delete'),
path('items//', views.item_detail, name='item_detail'),
diff --git a/core/views.py b/core/views.py
index 8f380de..6f5e274 100644
--- a/core/views.py
+++ b/core/views.py
@@ -692,29 +692,40 @@ def collection_edit(request, pk):
def collection_detail(request, pk):
collection = get_object_or_404(visible_collections(request.user), pk=pk)
+ return render(request, 'core/collection_detail.html', {
+ 'collection': collection,
+ 'sections': collection.sections.select_related('item').prefetch_related('item__tags', 'item__attachments'),
+ 'can_edit': user_can_edit_collection(request.user, collection),
+ })
+
+
+@login_required
+def collection_manage(request, pk):
+ collection = get_object_or_404(visible_collections(request.user), pk=pk)
+ if not user_can_edit_collection(request.user, collection):
+ return JsonResponse({'error': 'forbidden'}, status=403)
+ manage_url = reverse('collection_manage', args=[collection.pk])
if request.method == 'POST':
- if not user_can_edit_collection(request.user, collection):
- return JsonResponse({'error': 'forbidden'}, status=403)
action = request.POST.get('action')
if action in {'add', 'confirm_add'}:
item = get_object_or_404(visible_items(request.user), pk=request.POST.get('item_id'), kind=Item.Kind.NOTE)
if collection_item_is_compatible(collection, item):
add_collection_section(collection, item)
- return redirect(collection)
+ return redirect(manage_url)
if action == 'add':
- return render(request, 'core/collection_detail.html', collection_detail_context(request, collection, item))
+ return render(request, 'core/collection_manage.html', collection_detail_context(request, collection, item))
mode = request.POST.get('mode')
if mode == 'convert':
if not item_can_change_for_collection(request.user, item, collection):
messages.error(request, _('This note is used by an incompatible collection or cannot be edited. Create a copy instead.'))
- return redirect(collection)
+ return redirect(manage_url)
item = adapt_item_for_collection(item, collection)
elif mode == 'copy':
item = copy_item_for_collection(item, collection, request.user)
else:
- return redirect(collection)
+ return redirect(manage_url)
add_collection_section(collection, item)
- return redirect(collection)
+ return redirect(manage_url)
section = get_object_or_404(CollectionSection, pk=request.POST.get('section_id'), collection=collection)
if action == 'remove':
section.delete()
@@ -733,8 +744,8 @@ def collection_detail(request, pk):
CollectionSection.objects.filter(pk=section.pk).update(position=temporary)
CollectionSection.objects.filter(pk=other.pk).update(position=section.position)
CollectionSection.objects.filter(pk=section.pk).update(position=other.position)
- return redirect(collection)
- return render(request, 'core/collection_detail.html', collection_detail_context(request, collection))
+ return redirect(manage_url)
+ return render(request, 'core/collection_manage.html', collection_detail_context(request, collection))
@login_required
diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po
index 62766f9..e0451e1 100644
--- a/locale/de/LC_MESSAGES/django.po
+++ b/locale/de/LC_MESSAGES/django.po
@@ -664,6 +664,14 @@ msgstr "Sammlungen sind derzeit nur auf dem Desktop verfügbar."
msgid "Edit collection"
msgstr "Sammlung bearbeiten"
+#: core/templates/core/collection_manage.html
+msgid "View collection"
+msgstr "Sammlung ansehen"
+
+#: core/templates/core/collection_manage.html
+msgid "Collection settings"
+msgstr "Sammlungseinstellungen"
+
#: core/templates/core/collection_detail.html
msgid "Delete collection? The notes remain available."
msgstr "Sammlung löschen? Die Notizen bleiben erhalten."