Skip to content

feat: bulk-add todos via multi-line paste, retire Import buttons (#110)#117

Merged
ryota-murakami merged 4 commits into
mainfrom
feat/110-bulk-paste-todo-input
Jun 24, 2026
Merged

feat: bulk-add todos via multi-line paste, retire Import buttons (#110)#117
ryota-murakami merged 4 commits into
mainfrom
feat/110-bulk-paste-todo-input

Conversation

@ryota-murakami

@ryota-murakami ryota-murakami commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

Bulk-add todos by pasting a multi-line list, and retire the now-redundant manual Import buttons (Issue #110).

Pasting a multi-line list into a todo/task input now opens the existing paste-import confirm dialog (one task per line) instead of mangling the whole list into a single task. A single-line paste/type still adds inline. The two stand-alone "Import a list" / toolbar "Import" entry points are removed — paste is the import affordance now.

Closes #110.

What changed

  • src/lib/interceptBulkPaste.ts (new) — single source of the "intercept a multi-line paste only when it replaces the entire field (empty or fully-selected)" rule. Falls through to native paste for single-line, mid-edit caret, or when no bulk handler is wired.
  • src/lib/isMultiLinePaste.ts (new) — isMultiLinePaste(text) = parsePasteToTasks(text).length >= MULTI_LINE_PASTE_MIN_LINES.
  • src/app/(main)/home/_components/AddTodoForm.tsx — Home todo input onPaste → shared helper; placeholder now "Type a todo, or paste a list...".
  • src/components/floating-navigator/FloatingNavigator.tsx — Floating task input onPaste → shared helper.
  • TodoImportEntry.tsx deleted; empty-state and toolbar Import buttons removed (AC#5/Fix Electron auth sync and remove E2E bypass #6).
  • Tests: interceptBulkPaste.test.ts (5 DAMP unit cases — first unit coverage of the Home paste path), Floating Navigator bulk-paste component tests, and the authed web E2E paste-import.spec.ts.

The shared helper was extracted in response to the pre-landing two-axis review, which flagged the byte-for-byte duplicated onPaste handler across the two inputs as a DRY violation.

Acceptance criteria

AC Requirement Verification
1 Multi-line paste into Home todo input → import dialog, one task/line web E2E paste-import.spec.ts (authed, real browser) + 5 unit cases
2 Same for Floating Navigator task input 3 component tests + shared-helper unit (live deferred — see note)
3 Single-line paste/type still adds inline (no dialog) E2E single-line case + unit fall-through + mid-edit guard
4 Undo affordance after confirm E2E Undo cases (60s Undo removes imported todos)
5 Empty-state "Import a list" button removed E2E asserts the button is gone
6 Toolbar "Import" button removed TodoImportEntry.tsx deleted; no dangling refs (typecheck + lint clean)

Verification

  • pnpm validate GREEN — 671 unit pass, typecheck 0, build 0, lint 0.
  • Web E2E paste-import.spec.ts 9/9 GREEN (CI Node 24.13.0).
  • QA: browser liveness clean (0 console errors), auth gate intact; health 100/100, 0 bugs.

AC#2 live note: the /floating-navigator route renders a desktop-only fallback in a plain browser (gated on the Electron-preload window.floatingNavigatorAPI global), so AC#2 is proven by component + unit tests with live confirmation deferred to post-merge prod — the same precedent accepted for #93 / #104.

Out of scope

AI auto-labeling (#53 Slice2, paid — on hold) and the Completed "Import past wins" flow (CompletedImportEntry preserved).

Summary by CodeRabbit

  • New Features

    • Bulk multi-line paste now opens a review dialog with the pasted list prefilled (including from the floating task navigator), instead of using the retired inline import button.
    • After importing, an undo banner appears to quickly revert the last bulk import.
    • Empty-pending state now suggests “Paste a list to add several at once.”; the todo input placeholder updates to “Type a todo, or paste a list...”.
  • Bug Fixes

    • Single-line pastes still behave normally (no bulk dialog).
    • Blank/whitespace-only and prefix-only lines are ignored in the import preview, and valid multi-line paste enables adding pending todos.

Multi-line paste into the main todo input or the Floating Navigator task input now opens the existing import confirm dialog (one task per line), seeded with the pasted list. Single-line paste/typing is unchanged. The empty-state "Import a list" and toolbar "Import" buttons are removed; a quiet on-voice empty-state hint replaces the button.

- isMultiLinePaste reuses parsePasteToTasks so detection equals the dialog's own preview (CRLF / trailing-newline / prefix-only / blank handled identically; no dead-end dialog).

- useTodoPasteImport shares the seeded-dialog + invalidate/broadcast wiring between TodoList and FloatingNavigatorContainer: the importing window invalidates its own todo/category/heatmap queries then broadcasts (it never receives its own echo).

- Paste interception fires only when the input is empty/fully-selected, so mid-text edits fall through to native paste.

- FloatingNavigator gains a decoupled bulkImportBanner slot so the 60s undo banner sits above the list, not clipped in the compact window.

- Delete TodoImportEntry; preserve the Completed "Import past wins" flow.

E2E: paste-import spec now drives a real synthetic paste ClipboardEvent (the Import button is gone) and adds AC#3/AC#6 guards. All Todo-zone specs pass locally; the 2 Completed-zone failures are a pre-existing UTC-vs-local day-detail date artifact (JST early morning), green on CI's UTC runners.
The floating route renders a desktop-only fallback in a plain browser (gated on window.floatingNavigatorAPI), so the web E2E provably can't reach the floating task input. These component tests give the genuinely-new handleTaskPaste handler deterministic CI coverage: multi-line into the empty/fully-selected input opens the bulk import dialog, a single line falls through to native paste, and a multi-line paste mid-edit is never hijacked.
$gstack-review (Standards axis) flagged the multi-line paste-interception
logic as a hard DRY violation: it was copy-pasted byte-for-byte in
AddTodoForm.handleTextPaste and FloatingNavigator.handleTaskPaste. The
controller half was already a shared hook (useTodoPasteImport); this folds
the interception half into one source too.

- Add src/lib/interceptBulkPaste.ts — the single source of the "intercept a
  multi-line paste only when it replaces the entire field" rule (AC#1/#2/#3),
  reusing isMultiLinePaste so detection still matches the dialog preview.
- Both onPaste handlers now call it; drop the duplicated component handlers.
- Add src/lib/interceptBulkPaste.test.ts (5 DAMP cases) — the home AddTodoForm
  path had no unit coverage before, only the web E2E.

Behavior unchanged: 671 unit + paste-import web E2E 9/9 green (TZ=UTC).
@vercel

vercel Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
corelive Ready Ready Preview, Comment Jun 24, 2026 6:30pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b2c8d20-d8e9-44b0-b68f-e0d5e2847a85

📥 Commits

Reviewing files that changed from the base of the PR and between 477d7b2 and 9120955.

📒 Files selected for processing (7)
  • e2e/web/category.spec.ts
  • e2e/web/qa-fixes.spec.ts
  • e2e/web/sidebar-navigation.spec.ts
  • e2e/web/skill-tree.spec.ts
  • e2e/web/sound-palette.spec.ts
  • e2e/web/theme.spec.ts
  • e2e/web/todo-app.spec.ts
✅ Files skipped from review due to trivial changes (2)
  • e2e/web/sound-palette.spec.ts
  • e2e/web/skill-tree.spec.ts

📝 Walkthrough

Walkthrough

Implements multi-line paste-import for the home todo input and Floating Navigator, replacing toolbar import entry points. Adds paste detection utilities, a shared paste-import controller, dialog seeding support, undo banner wiring, and updated E2E/unit coverage.

Changes

Bulk Paste-Import Flow (Issue #110)

Layer / File(s) Summary
Paste detection core logic and tests
src/lib/constants/import.ts, src/lib/isMultiLinePaste.ts, src/lib/isMultiLinePaste.test.ts, src/lib/interceptBulkPaste.ts, src/lib/interceptBulkPaste.test.ts
Adds MULTI_LINE_PASTE_MIN_LINES, isMultiLinePaste, and interceptBulkPaste, with tests for multi-line, single-line, mid-edit, full-selection, and missing-handler paste cases.
Paste import controller and dialog seeding
src/hooks/useTodoPasteImport.ts, src/components/import/PasteImport.tsx
Adds useTodoPasteImport, the TodoPasteImportController interface, and initialText support for seeding the import dialog textarea.
Home todo input wiring and import UI
src/app/(main)/home/_components/AddTodoForm.tsx, src/app/(main)/home/_components/TodoList.tsx, src/app/(main)/home/_components/TodoImportEntry.tsx
AddTodoForm gains bulk-paste handling, and TodoList wires the paste controller into the dialog, undo banner, and empty-state hint while removing TodoImportEntry.
FloatingNavigator bulk paste wiring
src/components/floating-navigator/FloatingNavigator.tsx, src/components/floating-navigator/FloatingNavigatorContainer.tsx, src/components/floating-navigator/FloatingNavigator.test.tsx
FloatingNavigator and its container gain bulk-paste props, paste interception, banner rendering, dialog orchestration, and updated unit tests.
E2E paste-import spec updates
e2e/web/paste-import.spec.ts
Switches the spec to synthetic paste entry, updates todo-zone scenarios to seed dialog content through paste, adds the single-line no-dialog test, and adjusts wrong-zone recovery flow.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Input as AddTodoForm / FloatingNavigator input
  participant PasteHelper as interceptBulkPaste
  participant Controller as useTodoPasteImport
  participant Dialog as PasteImport
  participant Cache as React Query cache
  participant Windows as Other browser windows

  User->>Input: paste text
  Input->>PasteHelper: onPaste
  PasteHelper->>PasteHelper: detect multi-line + full selection
  PasteHelper->>Controller: openWithPaste(text)
  Controller->>Dialog: open with initialText
  User->>Dialog: confirm import
  Dialog->>Controller: handleImported(result)
  Controller->>Cache: invalidate todo queries
  Controller->>Windows: broadcast sync events
  Controller->>Input: show undo banner
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐇 I hopped with paste and newline cheer,
Two lines in, the dialog’s here.
One line skims right on by,
No extra button in the sky.
Undo hops close, then off we go —
A tidy list with rabbit flow ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: multi-line paste bulk-add for todos and removal of the Import buttons.
Linked Issues check ✅ Passed The changes align with #110 by enabling multi-line paste imports in both inputs, preserving single-line behavior, undo, and removing the Import entry points.
Out of Scope Changes check ✅ Passed The additional hook, helpers, tests, and E2E selector updates are all directly supporting the paste-import flow and button removal.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/110-bulk-paste-todo-input

Comment @coderabbitai help to get the list of available commands.

@codecov-commenter

codecov-commenter commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 67.04%. Comparing base (2d0a438) to head (9120955).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #117      +/-   ##
==========================================
+ Coverage   66.89%   67.04%   +0.14%     
==========================================
  Files         137      139       +2     
  Lines        4335     4348      +13     
  Branches     1184     1188       +4     
==========================================
+ Hits         2900     2915      +15     
+ Misses       1218     1216       -2     
  Partials      217      217              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

#110 renamed the home todo input placeholder 'Enter a new todo...' -> 'Type a todo, or paste a list...' to advertise the paste-a-list affordance now that the explicit Import buttons are gone. Seven web E2E specs located the input by the OLD placeholder text, so they timed out trying to fill it once the rename landed -- failing the category, qa-fixes, sidebar-navigation, skill-tree, sound-palette, theme, and todo-app shards, while paste-import (already on the new string) passed. Updated all 21 getByPlaceholder('Enter a new todo...') call sites to the new text. Test-only; no production change.
@ryota-murakami ryota-murakami merged commit 246a10b into main Jun 24, 2026
25 checks passed
@ryota-murakami ryota-murakami deleted the feat/110-bulk-paste-todo-input branch June 24, 2026 18:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bulk-add tasks by pasting multiple lines into the todo input (remove the separate Import buttons)

2 participants