Persist quick composer default type
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
{% if item_kind_choices %}
|
||||
<label class="ms-auto mb-0 d-flex align-items-center gap-2 small text-muted">
|
||||
<span class="d-none d-sm-inline">{% trans 'Type' %}</span>
|
||||
<select class="form-select form-select-sm w-auto" name="default_item_kind" title="{% trans 'Default type for new entry' %}">
|
||||
<select class="form-select form-select-sm w-auto" name="default_item_kind" title="{% trans 'Default type for new entry' %}" hx-post="{% url 'set_default_item_kind' %}" hx-trigger="change" hx-swap="none">
|
||||
{% for value, label in item_kind_choices %}<option value="{{ value }}"{% if value == selected_item_kind %} selected{% endif %}>{{ label }}</option>{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
</div>
|
||||
</aside>
|
||||
<section class="col-lg-9">
|
||||
<form class="desktop-quick-create position-relative mb-4" method="post" enctype="multipart/form-data" hx-post="{{ request.get_full_path }}" hx-target="#items" hx-swap="afterbegin" x-data="quickComposer([{% for tag in composer_tags %}'{{ tag.name|escapejs }}'{% if not forloop.last %},{% endif %}{% endfor %}])" x-on:htmx:after-request="if($event.detail.successful){text='';open=false;$el.reset()}">
|
||||
<form class="desktop-quick-create position-relative mb-4" method="post" enctype="multipart/form-data" hx-post="{{ request.get_full_path }}" hx-target="#items" hx-swap="afterbegin" x-data="quickComposer([{% for tag in composer_tags %}'{{ tag.name|escapejs }}'{% if not forloop.last %},{% endif %}{% endfor %}])" x-on:htmx:after-request="if($event.detail.successful){let kind=$el.querySelector('[name=default_item_kind]')?.value;text='';open=false;$el.reset();if(kind)$el.querySelector('[name=default_item_kind]').value=kind}">
|
||||
{% csrf_token %}
|
||||
<fieldset :disabled="editingItem" :class="{'opacity-50': editingItem}">
|
||||
<div class="small text-muted mb-2" x-show="editingItem" x-cloak>{% trans "Inline editor is open; quick entry is disabled." %}</div>
|
||||
|
||||
+12
-1
@@ -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, '<option value="link" selected>', html=False)
|
||||
|
||||
def test_explicit_command_overrides_default(self):
|
||||
kind, _, content, _ = parse_quick_content('/note Explicit note', Item.Kind.TODO)
|
||||
|
||||
@@ -13,6 +13,7 @@ urlpatterns = [
|
||||
path('kanban/<int:pk>/', views.kanban_detail, name='kanban_detail'),
|
||||
path('kanban/<int:pk>/move/<int:item_pk>/', 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/<int:pk>/delete/', views.delete_api_key, name='delete_api_key'),
|
||||
path('settings/invites/<int:pk>/delete/', views.delete_user_invite, name='delete_user_invite'),
|
||||
|
||||
+16
-4
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user