"""The T4 lists bundle (goal 41 task 4): the tasks/goals/projects/stacks list pages on the Spry conversion — faceted status chips with counts on /tasks (default view = open work) and /goals, the create-form expanders replaced by native modals (openAppDialog helper in app.js), the goals Tasks column as readable badges, and the projects list's folded repo cell. Markup-level: http_get_page fetches the compiled page; the counts are cross-checked against the slot data the chips count over.""" from harness import * # noqa: F401,F403 — the shared wire helpers def run(ctx): auth, fake, fake_id, fake_token = ctx.auth, ctx.fake, ctx.fake_id, ctx.fake_token OPEN = ("queued", "assigned", "working", "blocked", "suspended") def status_counts(): """Per-status task counts from the /tasks slot (the chip numbers count exactly these rows).""" rows = slot_public(auth, "/tasks", "tasks")["tasks"] counts = {} for row in rows: counts[row["status"]] = counts.get(row["status"], 0) + 1 counts["all"] = len(rows) counts["open"] = sum(n for s, n in counts.items() if s in OPEN) return counts def seed_tasks(): conn = db() for i, status in enumerate(("queued", "working", "blocked", "done", "done", "failed", "draft")): conn.execute( "insert into tasks (project_id, title, status, priority," " created_at) values (1, ?, ?, 5, strftime('%s','now'))", ("T4 chip probe %d" % i, status)) conn.commit() conn.close() print("== /tasks: faceted status chips with counts ==") seed_tasks() counts = status_counts() check(counts["open"] == 3 and counts["all"] >= 7, "the fixture shapes the counts (open %d / all %d)" % (counts["open"], counts["all"])) tasks_page = http_get_page(auth, "/tasks") check("taskChipClass" in tasks_page and "taskStatusCount" in tasks_page and "TASK_OPEN_STATUSES" in tasks_page, "the tasks page ships the chip engine (class/count/open-set)") check(tasks_page.index("goal-strip") < tasks_page.index(" tasks_page.index(""), "the dialog markup sits after the table, opened by the button") check('onclick="window.openAppDialog(\'task-create-dialog\')"' in tasks_page, "the + New task button opens the dialog through the shared helper") # The form inside the dialog is the SAME form: same action, same # fields (the B6b branch fields, the mode select, auto-enqueue). dialog_html = tasks_page[tasks_page.index('id="task-create-dialog"'):] check('stm-action="tasks.create"' in dialog_html and 'name="task_branch"' in dialog_html and 'name="branch_from"' in dialog_html and 'id="task-mode"' in dialog_html and 'id="task-enqueue-after"' in dialog_html and "No project (standalone)" in dialog_html, "the dialog carries the unchanged create form (action + fields)") check('class="dialog-titlebar"' in dialog_html and 'class="dialog-footer"' in dialog_html, "the dialog uses Spry's dialog classes (titlebar/footer)") # Semantics still work end to end: create through the action the # dialog form posts (new tasks land in draft). before = counts["draft"] act(auth, slot_public(auth, "/tasks", "tasks")["create"], { "project_id": "1", "title": "T4 dialog create task", "priority": "5"}) after = status_counts() check(after["draft"] == before + 1, "the dialog form's action still creates (draft %d -> %d)" % (before, after["draft"])) print("== app.js: the shared dialog helper ==") status, app_js = http("GET", "/_statum/resource/app.js") check(status == 200 and "window.openAppDialog" in app_js and "window.closeAppDialog" in app_js, "the shared dialog helper ships in app.js") check("onNotifyHandler" in app_js and "dialog.close()" in app_js, "the helper closes the dialog on the action's notify") print("== /goals: chips + readable task badges + create dialog ==") goals_page = http_get_page(auth, "/goals") check("goalStatusCount" in goals_page and "goalChipClass" in goals_page and "setGoalStatusFilter" in goals_page, "the goals list ships the same chip engine") check("goalRowVisible" in goals_page, "the goals rows filter client-side like the queue") # The four-count muted string is gone; badges carry the shape. check("draft / " not in goals_page and "running_tasks + " in goals_page, "the Tasks column renders the total badge from the counts") check('badge-warning" stm-if="goal.running_tasks > 0"' in goals_page, "running tasks surface as a warning badge") check('id="goal-create-dialog"' in goals_page and 'stm-action="goals.create"' in goals_page, "the goal create form lives in a dialog") goal_dialog = goals_page[goals_page.index('id="goal-create-dialog"'):] check('id="goal-brief"' in goal_dialog and "textarea" in goal_dialog and "required" in goal_dialog, "the required brief textarea is inside the dialog (visible on open)") print("== /projects: the folded repo cell + create dialog ==") projects_page = http_get_page(auth, "/projects") check('id="project-create-dialog"' in projects_page and 'stm-action="projects.create"' in projects_page and 'onclick="window.openAppDialog(\'project-create-dialog\')"' in projects_page, "the project create form lives in a dialog behind the button") check("Repo" in projects_page and "Git URL" not in projects_page, "the Git URL column folded into one Repo cell") check("repo-url" in projects_page and "truncate" in projects_page, "the repo cell truncates the clone URL (branch under it)") print("== /stacks: the create dialog ==") stacks_page = http_get_page(auth, "/stacks") check('id="stack-create-dialog"' in stacks_page and 'stm-action="stacks.create"' in stacks_page and 'onclick="window.openAppDialog(\'stack-create-dialog\')"' in stacks_page, "the stack create form lives in a dialog behind the button") check("
" not in stacks_page and "
" not in projects_page, "no create expander remains on stacks or projects")