diff --git a/core/templates/core/_format_toolbar.html b/core/templates/core/_format_toolbar.html index 8d487a3..486e36e 100644 --- a/core/templates/core/_format_toolbar.html +++ b/core/templates/core/_format_toolbar.html @@ -16,7 +16,7 @@ {% if item_kind_choices %} {% trans 'Type' %} - + {% for value, label in item_kind_choices %}{{ label }}{% endfor %} diff --git a/core/templates/core/index.html b/core/templates/core/index.html index 4f3e2cb..5b5a275 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -109,7 +109,7 @@ - + {% csrf_token %} {% trans "Inline editor is open; quick entry is disabled." %} diff --git a/core/tests.py b/core/tests.py index da94510..3b2a526 100644 --- a/core/tests.py +++ b/core/tests.py @@ -51,10 +51,21 @@ class DefaultItemKindTests(TestCase): self.assertRedirects(response, reverse('index')) self.assertEqual(Item.objects.get().kind, Item.Kind.TODO) - def test_quick_create_can_override_default_from_composer(self): + def test_quick_create_can_override_and_persist_default_from_composer(self): response = self.client.post(reverse('index'), {'content': 'Composer note', 'default_item_kind': Item.Kind.NOTE}) self.assertRedirects(response, reverse('index')) self.assertEqual(Item.objects.get().kind, Item.Kind.NOTE) + self.preferences.refresh_from_db() + self.assertEqual(self.preferences.default_item_kind, Item.Kind.NOTE) + + def test_default_item_kind_select_persists_immediately(self): + response = self.client.post(reverse('set_default_item_kind'), {'default_item_kind': Item.Kind.LINK}) + self.assertEqual(response.status_code, 204) + self.preferences.refresh_from_db() + self.assertEqual(self.preferences.default_item_kind, Item.Kind.LINK) + + response = self.client.get(reverse('index')) + self.assertContains(response, '', html=False) def test_explicit_command_overrides_default(self): kind, _, content, _ = parse_quick_content('/note Explicit note', Item.Kind.TODO) diff --git a/core/urls.py b/core/urls.py index 0294f70..d16317f 100644 --- a/core/urls.py +++ b/core/urls.py @@ -13,6 +13,7 @@ urlpatterns = [ path('kanban//', views.kanban_detail, name='kanban_detail'), path('kanban//move//', views.kanban_move, name='kanban_move'), path('language/', views.set_user_language, name='set_user_language'), + path('default-item-kind/', views.set_default_item_kind, name='set_default_item_kind'), path('settings/', views.settings_view, name='settings'), path('settings/api-keys//delete/', views.delete_api_key, name='delete_api_key'), path('settings/invites//delete/', views.delete_user_invite, name='delete_user_invite'), diff --git a/core/views.py b/core/views.py index cb85d89..571b034 100644 --- a/core/views.py +++ b/core/views.py @@ -327,7 +327,7 @@ def index(request): if form.is_valid(): raw = form.cleaned_data['content'] raw, due_at, _ = parse_due_command(raw) - kind, visibility, content, url = parse_quick_content(raw, requested_default_item_kind(request.POST, prefs)) + kind, visibility, content, url = parse_quick_content(raw, requested_default_item_kind(request.POST, prefs, save=True)) active_tag = request.GET.get('tag') if active_tag and not TAG_RE.search(without_markdown_code(content)): content = f'{content} #{active_tag.strip().lower()}' @@ -425,7 +425,7 @@ def new_item(request): if requested_kind in {'todo', 'link', 'journal'} and not TYPE_COMMAND_RE.match(raw.strip()): raw = f'/{requested_kind} {raw}' raw, due_at, _ = parse_due_command(raw) - kind, visibility, content, url = parse_quick_content(raw, requested_default_item_kind(request.POST, prefs)) + kind, visibility, content, url = parse_quick_content(raw, requested_default_item_kind(request.POST, prefs, save=True)) item = Item.objects.create(owner=request.user, kind=kind, visibility=visibility, content=content, url=url, due_at=due_at) attach_files_and_replace_tokens(item, request.FILES.getlist('files')) item.sync_metadata() @@ -1169,9 +1169,21 @@ def tag_list(request): return render(request, 'core/_tags.html', {'tags': index_filter_tags(request, request.user, prefs, active_tags), 'active_tag': active_tags[0] if active_tags else None, 'active_tags': active_tags, 'active_tag_mode': active_tag_mode}) -def requested_default_item_kind(post, prefs): +def requested_default_item_kind(post, prefs, save=False): kind = post.get('default_item_kind') or prefs.default_item_kind - return kind if kind in Item.Kind.values else prefs.default_item_kind + kind = kind if kind in Item.Kind.values else prefs.default_item_kind + if save and kind != prefs.default_item_kind: + prefs.default_item_kind = kind + prefs.save(update_fields=['default_item_kind']) + return kind + + +@login_required +@require_POST +def set_default_item_kind(request): + prefs, created = UserPreference.objects.get_or_create(user=request.user) + requested_default_item_kind(request.POST, prefs, save=True) + return HttpResponse(status=204) @login_required