Improve tasks and align page elements

This commit is contained in:
2026-03-02 13:33:04 +00:00
parent e1de6d016d
commit 56c620473f
8 changed files with 387 additions and 47 deletions

View File

@@ -26,6 +26,17 @@ from core.models import (
)
from core.tasks.providers.mock import get_provider
SAFE_TASK_FLAGS_DEFAULTS = {
"derive_enabled": True,
"match_mode": "strict",
"require_prefix": True,
"allowed_prefixes": ["task:", "todo:"],
"completion_enabled": True,
"ai_title_enabled": True,
"announce_task_id": False,
"min_chars": 3,
}
def _to_bool(raw, default=False) -> bool:
if raw is None:
@@ -50,32 +61,73 @@ def _parse_prefixes(value: str) -> list[str]:
return rows or ["task:", "todo:"]
def _looks_like_old_risky_defaults(raw: dict) -> bool:
row = dict(raw or {})
mode = str(row.get("match_mode") or "").strip().lower()
require_prefix = _to_bool(row.get("require_prefix"), False)
prefixes = _parse_prefixes(",".join(list(row.get("allowed_prefixes") or [])))
min_chars = int(row.get("min_chars") or 8)
return (
mode in {"", "balanced"}
and (not require_prefix)
and prefixes == ["task:", "todo:", "action:"]
and min_chars >= 8
)
def _normalized_safe_flags(raw: dict | None) -> dict:
row = dict(raw or {})
defaults = dict(SAFE_TASK_FLAGS_DEFAULTS)
if _looks_like_old_risky_defaults(row):
return defaults
merged = dict(defaults)
merged.update(
{
"derive_enabled": _to_bool(row.get("derive_enabled"), defaults["derive_enabled"]),
"match_mode": str(row.get("match_mode") or defaults["match_mode"]).strip().lower() or defaults["match_mode"],
"require_prefix": _to_bool(row.get("require_prefix"), defaults["require_prefix"]),
"allowed_prefixes": _parse_prefixes(",".join(list(row.get("allowed_prefixes") or defaults["allowed_prefixes"]))),
"completion_enabled": _to_bool(row.get("completion_enabled"), defaults["completion_enabled"]),
"ai_title_enabled": _to_bool(row.get("ai_title_enabled"), defaults["ai_title_enabled"]),
"announce_task_id": _to_bool(row.get("announce_task_id"), defaults["announce_task_id"]),
"min_chars": max(1, int(row.get("min_chars") or defaults["min_chars"])),
}
)
return merged
def _apply_safe_defaults_for_user(user) -> None:
projects = list(TaskProject.objects.filter(user=user).only("id", "settings"))
for row in projects:
normalized = _normalized_safe_flags(row.settings)
if dict(row.settings or {}) != normalized:
row.settings = normalized
row.save(update_fields=["settings", "updated_at"])
sources = list(ChatTaskSource.objects.filter(user=user).only("id", "settings"))
for row in sources:
normalized = _normalized_safe_flags(row.settings)
if dict(row.settings or {}) != normalized:
row.settings = normalized
row.save(update_fields=["settings", "updated_at"])
def _flags_from_post(request, prefix: str = "") -> dict:
key = lambda name: f"{prefix}{name}" if prefix else name
defaults = dict(SAFE_TASK_FLAGS_DEFAULTS)
return {
"derive_enabled": _to_bool(request.POST.get(key("derive_enabled")), True),
"match_mode": str(request.POST.get(key("match_mode")) or "strict").strip().lower() or "strict",
"require_prefix": _to_bool(request.POST.get(key("require_prefix")), True),
"allowed_prefixes": _parse_prefixes(str(request.POST.get(key("allowed_prefixes")) or "")),
"completion_enabled": _to_bool(request.POST.get(key("completion_enabled")), True),
"ai_title_enabled": _to_bool(request.POST.get(key("ai_title_enabled")), True),
"announce_task_id": _to_bool(request.POST.get(key("announce_task_id")), True),
"min_chars": max(1, int(str(request.POST.get(key("min_chars")) or "3").strip() or "3")),
"derive_enabled": _to_bool(request.POST.get(key("derive_enabled")), defaults["derive_enabled"]),
"match_mode": str(request.POST.get(key("match_mode")) or defaults["match_mode"]).strip().lower() or defaults["match_mode"],
"require_prefix": _to_bool(request.POST.get(key("require_prefix")), defaults["require_prefix"]),
"allowed_prefixes": _parse_prefixes(str(request.POST.get(key("allowed_prefixes")) or ",".join(defaults["allowed_prefixes"]))),
"completion_enabled": _to_bool(request.POST.get(key("completion_enabled")), defaults["completion_enabled"]),
"ai_title_enabled": _to_bool(request.POST.get(key("ai_title_enabled")), defaults["ai_title_enabled"]),
"announce_task_id": _to_bool(request.POST.get(key("announce_task_id")), defaults["announce_task_id"]),
"min_chars": max(1, int(str(request.POST.get(key("min_chars")) or str(defaults["min_chars"])).strip() or str(defaults["min_chars"]))),
}
def _flags_with_defaults(raw: dict | None) -> dict:
row = dict(raw or {})
return {
"derive_enabled": _to_bool(row.get("derive_enabled"), True),
"match_mode": str(row.get("match_mode") or "strict").strip().lower() or "strict",
"require_prefix": _to_bool(row.get("require_prefix"), True),
"allowed_prefixes": _parse_prefixes(",".join(list(row.get("allowed_prefixes") or []))),
"completion_enabled": _to_bool(row.get("completion_enabled"), True),
"ai_title_enabled": _to_bool(row.get("ai_title_enabled"), True),
"announce_task_id": _to_bool(row.get("announce_task_id"), True),
"min_chars": max(1, int(row.get("min_chars") or 3)),
}
return _normalized_safe_flags(raw)
def _settings_redirect(request):
@@ -277,6 +329,7 @@ class TaskSettings(LoginRequiredMixin, View):
template_name = "pages/tasks-settings.html"
def _context(self, request):
_apply_safe_defaults_for_user(request.user)
prefill_service = str(request.GET.get("service") or "").strip().lower()
prefill_identifier = str(request.GET.get("identifier") or "").strip()
projects = list(TaskProject.objects.filter(user=request.user).order_by("name"))