Skip to content

feat(pig-detail): inline edit + delete in popover#44

Merged
archae0pteryx merged 4 commits intomainfrom
feat-pig-detail-edit-delete
May 5, 2026
Merged

feat(pig-detail): inline edit + delete in popover#44
archae0pteryx merged 4 commits intomainfrom
feat-pig-detail-edit-delete

Conversation

@archae0pteryx
Copy link
Copy Markdown
Contributor

@archae0pteryx archae0pteryx commented May 5, 2026

Summary

  • Click pig → popover. Title + task text are now always-editable inputs (commit on blur/Enter, revert on Escape, empty title reverts + shows inline error).
  • Task rows gain a checkbox that toggles markdown - [ ] ↔ - [x].
  • New trash button on the popover header gated by settings.widget.confirm_delete: shows inline Delete "…"? [Delete] [Cancel] overlay when true, deletes immediately when false.
  • End-to-end rename_focus / update_task / toggle_task across storage → commands → Tauri bridge → HTTP PATCH /focuses/:id and PATCH /focuses/:id/tasks/:idx → frontend FocusWriter.
  • Domain Task gains a done: bool field, parsed from checkbox state. Slug/dir name remains stable on rename — id never changes.

Layer counts

Layer Tests added
storage::focus_store 7 (rename happy + missing, update happy + range, toggle on/off + range)
commands::focus 5 (rename happy + blank, update blank + replace, toggle round-trip)
http-api 4 (PATCH focus title happy + blank, PATCH task text + done)
PigDetail.test.tsx 10 (title editing × 3, task editing × 4, delete focus × 3)

task check green: rust tests 51 + 68 + 24 + 20, vitest 71 passed.

Test plan

  • Restart task dev (port 1420 currently held — kill old node before relaunch so new Tauri commands register).
  • Click pig → popover opens with title input populated.
  • Edit title → blur → markdown frontmatter title: updates; pig sprite name updates.
  • Clear title → blur → reverts to old, inline "Title cannot be empty" error shown.
  • Edit task text → Enter → markdown bullet rewrites preserving [ ]/[x] state.
  • Toggle checkbox → markdown bullet flips [ ] ↔ [x]; UI shows strikethrough on done.
  • In Settings, set confirm_delete = true. Click trash → inline Delete "…"? overlay; Cancel hides; Delete removes focus dir + closes popover.
  • Set confirm_delete = false. Click trash → immediate delete + close.
  • Stable id check: rename a focus, then restart app — focus reappears with new title at same dir slug.

Summary by CodeRabbit

  • New Features

    • Rename focus titles (validated), update task text, and toggle task completion; UI, backend and API routes wired end-to-end; task objects include completion state.
  • Style

    • Updated pig-detail overlay, header/input, delete-confirm and task visuals (done-state styling).
  • Tests

    • Expanded unit and integration tests covering renames, task edits, toggles and API patch behavior.
  • Chores

    • Added hook for configurable delete-confirm behavior.

Adds end-to-end rename_focus / update_task / toggle_task across storage,
commands, Tauri bridge, HTTP PATCH routes, and frontend FocusWriter.

PigDetail popover now renders title and task text as always-editable
inputs (commit on blur/Enter, revert on Escape), task checkboxes that
flip [ ]/[x] in markdown, and a trash button gated by the
widget.confirm_delete setting (inline confirm overlay vs immediate).

Domain Task gains a `done: bool` field, parsed from the markdown
checkbox state.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 5, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 86c02da3-b104-422b-96a9-16e558e99f29

📥 Commits

Reviewing files that changed from the base of the PR and between 6ba4d8c and 270d6cb.

📒 Files selected for processing (2)
  • src-tauri/src/display/overlay.rs
  • src/hooks/useConfirmDelete.ts

📝 Walkthrough

Walkthrough

Adds task completion tracking and three mutation operations: rename focus, update task text, and toggle task done. Changes span domain model and parsing, storage trait and Markdown implementation, command validation and delegation, HTTP/Tauri APIs, frontend wiring/components/styles, and tests/fixtures.

Changes

Focus & Task Mutation

Layer / File(s) Summary
Data Model
crates/domain/src/focus.rs, src/types/focus.ts
Task gains done: bool (Rust #[serde(default)]) and readonly done: boolean (TS).
Parsing
crates/domain/src/parse.rs
parse_tasks recognizes - [x] vs - [ ] and constructs Task { done }.
Storage Trait
crates/storage/src/focus_store.rs
FocusStore trait adds rename_focus, update_task, toggle_task.
Markdown Implementation
crates/storage/src/focus_store.rs
MarkdownFocusStore implements rename_focus (rewrite YAML title) and task mutations via shared rewrite_task_line that rewrites the Nth checkbox bullet and atomically writes focus.md.
Commands Layer
crates/commands/src/focus.rs, crates/commands/src/caps.rs
Commands exposes rename_focus, update_task, toggle_task with input validation (trim/empty title, TaskText::new); test StubStore updated to include the new trait methods (stubbed).
HTTP API
crates/http-api/src/router/focuses.rs, crates/http-api/src/router/tests.rs
Adds PATCH /focuses/:idrename_focus and PATCH /focuses/:id/tasks/:idxpatch_task (optional text/done), plus integration tests for rename, blank-title 400, task text update, and toggle round-trip.
Tauri Bridge & Invoke
src-tauri/src/ui_bridge/mod.rs, src-tauri/src/app/mod.rs
New Tauri commands rename_focus, update_task, toggle_task and registered invoke handlers delegating to Commands.
Frontend API
src/api/focusWriter.ts, src/api/tauriFocusReader.ts
FocusWriter adds renameFocus, updateTask, toggleTask; tauriFocusReader maps optional done from Rust to boolean (defaults to false).
UI Wiring & Components
src/components/App.tsx, src/components/PigDetail.tsx, src/styles.css
App wires confirmDelete and new handlers; PigDetail gains inline editable title (trim/validation), delete confirmation, TaskEditor with checkbox and editable text, and new styles.
Tests & Fixtures
various tests and fixtures across crates and frontend
Fixtures updated to include done: false; unit/integration/component tests added/extended to cover rename, update, toggle, and delete-confirm flows.

Sequence Diagram

sequenceDiagram
    actor User
    participant React as "React UI"
    participant Tauri as "Tauri Bridge"
    participant Commands as "Commands"
    participant Storage as "FocusStore"
    participant FS as "Filesystem"

    User->>React: Toggle task checkbox
    React->>Tauri: invoke('toggle_task', { focusId, index, done })
    Tauri->>Commands: commands.toggle_task(focusId, index, done)
    Commands->>Storage: store.toggle_task(focusId, index, done)
    Storage->>FS: read focus.md
    Storage->>Storage: find Nth checkbox, rewrite line
    Storage->>FS: write updated focus.md atomically
    FS-->>Storage: write complete
    Storage-->>Commands: Ok(())
    Commands-->>Tauri: Ok(())
    Tauri-->>React: Ok(())
    React-->>User: UI updated (done state)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐇 I nibble lines and mark them done,

Checkboxes ticked beneath the sun.
Titles trimmed and files rewritten neat,
Tasks toggle, round trips complete.
Hooray — small hops, a workflow sweet.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.49% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly describes the main feature: inline editing and deletion functionality in the PigDetail popover component, which is the core focus of this changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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-pig-detail-edit-delete

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/commands/src/focus.rs`:
- Around line 239-253: The test toggle_task_round_trip currently only ensures no
panic; update it to assert the final task done state by loading the focus after
the toggles and checking the task's done field is false. In the
toggle_task_round_trip test, after the two commands.toggle_task calls (and using
the created.id from commands.create_focus/CreateFocusInput and the appended task
at index 0), call the appropriate read/get method on commands (e.g.,
commands.get_focus or commands.read_focus) to retrieve the focus, access its
tasks[0].done, and assert it equals false to validate the round-trip.

In `@crates/http-api/src/router/tests.rs`:
- Around line 168-186: Extend the patch_task_toggles_done test to also verify
reverse toggling: after the existing PATCH that sets {"done": true} and
asserting "- [x] one", send a second PATCH via the same helper patch_json to
"/focuses/f1/tasks/0" with {"done": false}, assert StatusCode::NO_CONTENT again,
read the file at h.focuses_root.join("f1/focus.md") and assert the content
contains "- [ ] one"; update the test function patch_task_toggles_done and reuse
make_app, write_focus, focus_md, and patch_json helpers so both directions
(true→false and false→true) are covered.

In `@src/components/App.tsx`:
- Around line 26-30: The App component currently performs I/O by calling
getSettings inside its useEffect and setting local state via setConfirmDelete;
move this logic out of src/components by creating a non-component adapter or
hook (e.g., useSettingsService or settingsService.getConfirmDelete) outside the
components folder, have that module call getSettings and expose confirmDelete
(and a subscription or promise) and then inject the boolean into the App
component as a prop (confirmDelete) or via a lightweight view-only hook imported
from outside src/components; update App to remove
useEffect/getSettings/setConfirmDelete and rely only on the injected
confirmDelete value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1fbe4235-4d6c-4d44-a2cd-df2c211718b5

📥 Commits

Reviewing files that changed from the base of the PR and between 4787efe and 93eb525.

📒 Files selected for processing (22)
  • crates/commands/src/caps.rs
  • crates/commands/src/focus.rs
  • crates/domain/src/caps.rs
  • crates/domain/src/focus.rs
  • crates/domain/src/parse.rs
  • crates/http-api/src/router/focuses.rs
  • crates/http-api/src/router/tests.rs
  • crates/storage/src/focus_store.rs
  • src-tauri/src/app/mod.rs
  • src-tauri/src/ui_bridge/mod.rs
  • src/api/fixtureFocusReader.test.ts
  • src/api/focusWriter.ts
  • src/api/tauriFocusReader.ts
  • src/components/App.test.tsx
  • src/components/App.tsx
  • src/components/FocusCard.test.tsx
  • src/components/FocusList.test.tsx
  • src/components/PigDetail.test.tsx
  • src/components/PigDetail.tsx
  • src/lib/capState.test.ts
  • src/styles.css
  • src/types/focus.ts

Comment thread crates/commands/src/focus.rs
Comment thread crates/http-api/src/router/tests.rs
Comment thread src/components/App.tsx Outdated
macOS demotes NSWindow level across key/resign-key transitions when
the window is not an NSPanel. Popover inputs make the overlay key on
click; without re-application the overlay drops below other windows.
- Assert final done state in toggle_task round-trip test
- Add reverse-toggle (true→false) coverage in PATCH task test
- Extract getSettings IPC out of App.tsx into useConfirmDelete hook
  to keep components view-only per project conventions
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src-tauri/src/display/overlay.rs`:
- Around line 70-78: The on_window_event handler in overlay::ensure_shown is
being re-registered on every call, causing duplicate handlers; change
ensure_shown (or overlay initialization) to register the window event listener
exactly once — e.g. add a boolean/once flag (or store the handler id) on the
overlay/display manager state and check it before calling
window.on_window_event, or move the registration into the overlay/module init
path so DisplayManager::apply and overlay::ensure_shown no longer re-register;
keep the handler body calling crate::app::window_always_on_top::apply(&win_evt,
true) unchanged.

In `@src/hooks/useConfirmDelete.ts`:
- Around line 4-11: The fetched settings currently fall back to true and ignore
the hook's initial parameter; in useConfirmDelete replace the hardcoded fallback
true with the initial argument so the setConfirmDelete call uses
s?.widget?.confirm_delete ?? initial; keep the initial default parameter and
retain the existing error handling and useEffect shape.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 99475939-4353-417d-8cbc-443078a2d0a4

📥 Commits

Reviewing files that changed from the base of the PR and between 93eb525 and 6ba4d8c.

📒 Files selected for processing (5)
  • crates/commands/src/focus.rs
  • crates/http-api/src/router/tests.rs
  • src-tauri/src/display/overlay.rs
  • src/components/App.tsx
  • src/hooks/useConfirmDelete.ts

Comment thread src-tauri/src/display/overlay.rs Outdated
Comment thread src/hooks/useConfirmDelete.ts Outdated
- Move overlay window-event registration into the new-window branch so
  repeated ensure_shown calls on display config changes don't accumulate
  duplicate Focused listeners
- useConfirmDelete: fall back to initial param (not hardcoded true) when
  fetched settings are missing, and include initial in effect deps
@archae0pteryx archae0pteryx merged commit 91ef664 into main May 5, 2026
1 of 2 checks passed
@archae0pteryx archae0pteryx deleted the feat-pig-detail-edit-delete branch May 5, 2026 17:10
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.

1 participant