Files
espresso_frame/server/app/widgets/tasks.py
T
Thomas Faour b5c52004c8
Build and push server image / test (push) Successful in 24s
Build and push server image / build-and-push (push) Successful in 2m1s
Build and push server image / deploy (push) Successful in 56s
Split the tasks feature out of the calendar widget into its own widget type
Task lists used to be a week-view-only sub-feature bolted onto calendar
widgets (CalendarWidgetConfig.tasks_*), so a task list could only exist
tied to a calendar's view and only inside its footprint. Tasks are now
a standalone widget type (TaskWidgetConfig, app/widgets/tasks.py) that
can be placed and sized independently, same as photos/calendar/
whiteboard -- no separate "enabled" flag either, since being on the
grid at all is the on/off switch, matching every other widget type.

Migration 17 creates task_widget_configs, extracts any existing
calendar widget's configured task source into a new sibling tasks
widget (auto-placed in open grid space, source dropped+logged if truly
none is left), then drops calendar_widget_configs' now-dead tasks_*
columns in the same migration -- this project's usual same-migration-
drop convention. Also handles the rarer case of a database jumping
straight from before the widget system existed to after this split in
one boot, via the legacy Frame.calendar_tasks_* columns.

Verified live in the browser at desktop and mobile widths: adding a
Tasks widget, its own dialog (task-list source picker + preview), and
confirming the calendar widget's dialog no longer mentions tasks at
all. Full test suite (180 tests, including new coverage for the widget
render/actions, the migration's data-extraction path, and the
permission-boundary shape for tasks-source) passes.
2026-07-25 02:11:45 +00:00

37 lines
1.5 KiB
Python

"""Tasks widget: a simple outstanding-task checklist in its own region --
split out of the calendar widget's old week-view-only task list (see
models.TaskWidgetConfig) so a task list can be placed and sized on its
own, independent of any calendar's view/footprint.
No "enabled" concept and no button actions: the widget's mere presence
on the grid is the on/off switch (same as every other widget type), and
its cache refreshes on the same throttled schedule as weather -- nothing
here to advance/back/force."""
from __future__ import annotations
from PIL import Image
from sqlalchemy.orm import Session
from ..calendar_render import _build_tasks
from ..models import Frame, TaskWidgetConfig, Widget
from ..routers.common import get_or_refresh_tasks_for_widget
from ._shared import placeholder_image
ACTION_LABELS: dict[str, str] = {}
def render(db: Session, frame: Frame, widget: Widget, target_w: int, target_h: int,
is_normal_wake: bool = True) -> Image.Image:
"""is_normal_wake is unused here -- see app/widgets/photos.py's
identical note; every widget type's render() shares one call
signature regardless of which ones actually care."""
cfg = db.get(TaskWidgetConfig, widget.id)
if not cfg.calendar_key or not cfg.user_id:
return placeholder_image(target_w, target_h, ["Tasks widget", "not configured yet"])
tasks = get_or_refresh_tasks_for_widget(db, frame, widget)
return _build_tasks(tasks, target_w, target_h)
ACTIONS: dict = {}