Quick add task from the header (owner): modal, g t shortcut, auto_handle + Daisy webhook
Some checks failed
Deploy production / deploy (push) Has been cancelled

- + button next to Dashboard (desktop and mobile sheet), lazy-loaded native <dialog>
- POST /trackers/tasks/quick inserts source 'quick-add', notes, due date, priority
- tasks.tasks.auto_handle (default false) with a Daisy badge in the tracker
- DAISY_TASK_WEBHOOK_URL/KEY/HEADER: fire-and-forget POST {task_id, title}, 3 s timeout
This commit is contained in:
2026-10-24 16:13:44 +00:00
parent 3903317a59
commit 0aa14cebf3
9 changed files with 20152 additions and 2 deletions

View File

@@ -276,6 +276,7 @@
<p class="flex flex-wrap items-center gap-x-2 gap-y-1">
<button type="button" class="title" onclick={() => openTask(t)}>{t.title}</button>
{#if t.flagged}<Flag size={13} class="text-red-500" aria-label="Flagged" />{/if}
{#if t.autoHandle}<span class="chip daisy" title="Daisy handles this">Daisy</span>{/if}
{#if t.priority >= 2}<span class="chip prio-{t.priority}">{PRIORITY[t.priority]}</span>{/if}
{#if t.dueDate}<span class="chip due-{isOpen(t) ? due : 'later'}">{dueLabel(t)}</span>{/if}
{#if t.reminderAt && isOpen(t)}<span class="chip" title="Reminder"
@@ -839,6 +840,11 @@
color: var(--site-muted);
white-space: nowrap;
}
.daisy {
background: rgb(139 92 246 / 0.15);
border-color: rgb(139 92 246 / 0.5);
color: rgb(139 92 246);
}
.due-overdue {
background: rgb(239 68 68 / 0.15);
border-color: rgb(239 68 68 / 0.5);

View File

@@ -0,0 +1,45 @@
import * as z from 'zod';
import { error, json } from '@sveltejs/kit';
import { db } from '#lib/server/db/index.js';
import { todoActivity, todoTasks } from '#lib/server/db/schema/index.js';
import { requireOwner } from '#lib/server/owner.js';
import { parseQuickTitle } from '#lib/server/tasks.js';
import { notifyDaisy } from '#lib/server/daisy-hook.js';
import type { RequestHandler } from './$types';
// Header "quick add task" modal (any page, owner only; hooks.server.ts also refuses
// non-owner writes under /trackers/tasks). "!"/"!!!" in the title work as on the tracker.
const input = z.object({
title: z.string().trim().min(1, 'Give the task a title').max(500),
notes: z.string().trim().max(10_000).optional().default(''),
due: z
.string()
.regex(/^(\d{4}-\d{2}-\d{2})?$/, 'Invalid deadline')
.optional()
.default(''),
priority: z.coerce.number().int().min(0).max(3).optional().default(0),
autoHandle: z.boolean().optional().default(false)
});
export const POST: RequestHandler = async (event) => {
requireOwner(event);
const parsed = input.safeParse(await event.request.json().catch(() => null));
if (!parsed.success) error(400, parsed.error.issues[0]?.message ?? 'Invalid task');
const quick = parseQuickTitle(parsed.data.title);
if (!quick.title) error(400, 'Give the task a title');
const [row] = await db
.insert(todoTasks)
.values({
title: quick.title,
notes: parsed.data.notes || null,
dueDate: parsed.data.due || null,
priority: parsed.data.priority || quick.priority,
flagged: quick.flagged,
autoHandle: parsed.data.autoHandle,
source: 'quick-add'
})
.returning({ id: todoTasks.id, title: todoTasks.title });
await db.insert(todoActivity).values({ taskId: row.id, kind: 'created', toStatus: 'todo' });
const hook = parsed.data.autoHandle ? notifyDaisy(row) : 'off';
return json({ id: row.id, title: row.title, hook });
};