<feed xmlns='http://www.w3.org/2005/Atom'>
<title>doot.git/internal/handlers/widget_test.go, branch master</title>
<subtitle>doot — personal productivity web app
</subtitle>
<id>https://git.terst.org/doot.git/atom?h=master</id>
<link rel='self' href='https://git.terst.org/doot.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/'/>
<updated>2026-07-12T11:12:55+00:00</updated>
<entry>
<title>feat(widget): add recurrence lookup endpoint (GET /api/widget/recurrence)</title>
<updated>2026-07-12T11:12:55+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-12T11:12:55+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=6fdd09bfe030ce91ee188f18c198fd6a57c7b42f'/>
<id>urn:sha1:6fdd09bfe030ce91ee188f18c198fd6a57c7b42f</id>
<content type='text'>
</content>
</entry>
<entry>
<title>feat(widget): capture and forward RecurringEventID for calendar events</title>
<updated>2026-07-12T11:06:32+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-12T11:06:32+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=f31b4722243b8b69564c94e47e07678153c31815'/>
<id>urn:sha1:f31b4722243b8b69564c94e47e07678153c31815</id>
<content type='text'>
</content>
</entry>
<entry>
<title>feat(widget): add POST /api/widget/add for quick-add</title>
<updated>2026-07-12T10:34:34+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-12T10:34:34+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=dfb06e896b92003d219979cbb1476ed16b7734a3'/>
<id>urn:sha1:dfb06e896b92003d219979cbb1476ed16b7734a3</id>
<content type='text'>
</content>
</entry>
<entry>
<title>feat(widget): add DueDate field for doot tasks to the widget API</title>
<updated>2026-07-12T10:21:36+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-12T10:21:36+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=437ee6b10462909fb2db677a64be264d811a2e1c'/>
<id>urn:sha1:437ee6b10462909fb2db677a64be264d811a2e1c</id>
<content type='text'>
</content>
</entry>
<entry>
<title>feat(widget): forward IsOverdue from TimelineItem to WidgetItem API</title>
<updated>2026-07-12T09:48:34+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-12T09:48:34+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=3ada2fc17fd1bc8f4203eaa6fde2ea23d49b87a4'/>
<id>urn:sha1:3ada2fc17fd1bc8f4203eaa6fde2ea23d49b87a4</id>
<content type='text'>
</content>
</entry>
<entry>
<title>fix(widget): pin all-day calendar events to the top instead of losing them</title>
<updated>2026-07-12T06:21:40+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-12T06:21:40+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=84252756c687044d73a0ea5cebf8088c7c9ed3e8'/>
<id>urn:sha1:84252756c687044d73a0ea5cebf8088c7c9ed3e8</id>
<content type='text'>
WidgetItem.isAllDay was carried by the client's data model but nothing
ever read it. All-day events had no Start at all, so they fell into the
same floating-task queue as ordinary untimed tasks; if enough tasks were
ahead of one in the queue, SlotPacker could assign it an hour slot past
the visible grid range entirely -- not merely unpinned, actually
invisible.

Server: TimelineItemToWidgetItem now populates Start for all-day
CALENDAR EVENTS specifically (their real event date), while leaving
undated doot/gtask tasks -- also flagged IsAllDay as a "no specific
time" fallback, a different concept -- on the existing nil-Start
floating behavior.

Client: all-day events are filtered out of the hourly grid/floating-task
pipeline entirely, bucketed by day using the new Start date, and
rendered in a new pinned AllDayRow section right after the TODAY/TOMORROW
headers.
</content>
</entry>
<entry>
<title>fix(widget): surface unmatched task IDs instead of silently no-opping</title>
<updated>2026-07-12T05:36:32+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-12T05:36:32+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=9a87f9db5af943ea253b814d4196020341e3c2ba'/>
<id>urn:sha1:9a87f9db5af943ea253b814d4196020341e3c2ba</id>
<content type='text'>
CompleteNativeTask/UncompleteNativeTask/RescheduleNativeTask ran a plain
UPDATE ... WHERE id = ? and returned whatever error Exec gave back --
which is nil even when 0 rows match, since that's not a SQL error. A
stale or wrong id from the widget looked identical to a real completion:
HTTP 200, nothing changed in the database. Real incident: 1 of 3 widget
completeTask taps silently no-opped this way.

Now checks RowsAffected() and returns ErrNativeTaskNotFound (mirrors the
existing pattern in sqlite.go's ApproveAgentSession/DenyAgentSession).
HandleWidgetComplete and HandleWidgetReschedule surface this as 404
instead of a fake 200, so the widget can tell 'nothing changed' apart
from 'it worked.'
</content>
</entry>
<entry>
<title>feat: remove Todoist integration entirely</title>
<updated>2026-07-06T00:00:59+00:00</updated>
<author>
<name>Doot Agent</name>
<email>agent@doot.local</email>
</author>
<published>2026-07-06T00:00:59+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=945c34590677e161a711ccaff0e1077197b1b178'/>
<id>urn:sha1:945c34590677e161a711ccaff0e1077197b1b178</id>
<content type='text'>
Native tasks (native_tasks table) fully replace Todoist. All Todoist
API code, store functions, handlers, routes, templates, and tests have
been removed. Migration 021 drops the now-unused tasks cache table.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix: native tasks missing from Tasks tab and blank title on completion</title>
<updated>2026-07-05T08:22:17+00:00</updated>
<author>
<name>Doot Agent</name>
<email>agent@doot.local</email>
</author>
<published>2026-07-05T08:22:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=8ca820b05e9e699a7b563a2e37ff2a0629a5505a'/>
<id>urn:sha1:8ca820b05e9e699a7b563a2e37ff2a0629a5505a</id>
<content type='text'>
Bug 1: BuildUnifiedAtomList never called GetNativeTasks(), so doot-sourced
tasks were absent from the web Tasks tab. Added GetNativeTasks() fetch and
NativeTaskToAtom conversion (new model helper, SourceDoot constant).

Bug 2: handleAtomToggle called getAtomDetails after CompleteNativeTask, but
GetNativeTasks filters WHERE completed=0, so the task was already gone and
the title came back blank. Moved getAtomDetails call to before the completion
switch so all sources (including doot) capture title/dueDate first.

Also fixed widget_test.go compile error: TestHandleWidgetComplete_NonTodoist
called HandleWidgetComplete as a package-level function but it is a method on
*Handler. Rewrote the file as package handlers (internal) and construct
&amp;Handler{} directly.

Regression tests added for both bugs in atoms_test.go and handlers_test.go.

Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix: widget handler timezone, auth guard, and type switch clarity</title>
<updated>2026-06-29T00:45:06+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-06-29T00:45:06+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/doot.git/commit/?id=bdb526f8b5dd798f004645a90de87d4bf528ebcb'/>
<id>urn:sha1:bdb526f8b5dd798f004645a90de87d4bf528ebcb</id>
<content type='text'>
Co-Authored-By: Claude Sonnet 4.6 &lt;noreply@anthropic.com&gt;
</content>
</entry>
</feed>
