Skip to content

fix(tinyplace): replace native window.confirm with in-app modal on feed delete#4214

Merged
senamakel merged 4 commits into
tinyhumansai:mainfrom
M3gA-Mind:fix/tinyplace-feed-delete-modal-4197
Jun 29, 2026
Merged

fix(tinyplace): replace native window.confirm with in-app modal on feed delete#4214
senamakel merged 4 commits into
tinyhumansai:mainfrom
M3gA-Mind:fix/tinyplace-feed-delete-modal-4197

Conversation

@M3gA-Mind

@M3gA-Mind M3gA-Mind commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Feed delete used native window.confirm(), which renders the OS dialog titled "tauri.localhost says — Delete this post?" — exposing the internal hostname and breaking from the app's design system.

Adds a reusable ConfirmDialog (built on the shared ModalShell) and uses it for both the post delete (FeedSection.handleDeletePost) and the comment delete (CommentRow). The delete RPC runs only after the user confirms, with a busy state disabling the buttons while in flight. Includes a Vitest suite for ConfirmDialog.

Closes #4197

Summary by CodeRabbit

  • New Features

    • Added an in-app confirmation dialog for destructive actions, with customizable confirm/cancel labels and a busy state.
    • Post and comment deletion now use the modal confirmation flow instead of browser prompts.
  • Bug Fixes

    • Deletion actions only proceed after an explicit confirmation.
    • Confirm/cancel controls are disabled during busy states, preventing premature closure or duplicate actions.
  • Tests

    • Added a dedicated test suite for the confirmation dialog behavior and busy handling.
    • Updated feed deletion tests to confirm via the modal before triggering delete requests.

…ation

Feed delete used native window.confirm(), which renders the OS dialog titled
"tauri.localhost says — Delete this post?", exposing the internal hostname and
breaking from the app's design system.

Add a reusable ConfirmDialog (built on the shared ModalShell) and use it for
both the post delete (FeedSection.handleDeletePost) and the comment delete
(CommentRow). The destructive RPC now runs only after the user confirms, with a
busy state that disables the buttons while the delete is in flight. Adds a
Vitest suite for ConfirmDialog.
@M3gA-Mind M3gA-Mind requested a review from a team June 26, 2026 16:04
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds an in-app ConfirmDialog for feed deletions. Comment and post deletes now open the modal, wait for confirmation, call their delete RPCs, and clear or refresh state after completion. Tests were updated to confirm through the modal.

Changes

Feed delete confirmation

Layer / File(s) Summary
Dialog component and tests
app/src/agentworld/components/ConfirmDialog.tsx, app/src/agentworld/components/ConfirmDialog.test.tsx
ConfirmDialog renders a ModalShell-based modal with configurable confirm/cancel labels, destructive tone, and busy-state gating, and the tests cover render and callback behavior.
Comment deletion flow
app/src/agentworld/pages/FeedSection.tsx, app/src/agentworld/pages/FeedSection.test.tsx
CommentRow now opens ConfirmDialog before deleting a comment, calls apiClient.feeds.deleteComment(...) on confirm, and clears dialog and busy state after completion; the related tests click the modal confirm button before asserting the delete RPC.
Post deletion flow
app/src/agentworld/pages/FeedSection.tsx, app/src/agentworld/pages/FeedSection.test.tsx
FeedSection now stores a pending post for deletion, opens ConfirmDialog, calls apiClient.feeds.deletePost(...) on confirm, refetches homeFeed, and clears modal state in finally; the post deletion test now confirms through the modal before asserting the RPC.

Sequence Diagram(s)

Comment deletion flow

sequenceDiagram
  participant User
  participant CommentRow
  participant ConfirmDialog
  participant apiClient.feeds
  participant FeedSection

  User->>CommentRow: click Delete
  CommentRow->>ConfirmDialog: open confirmation modal
  User->>ConfirmDialog: click confirm-dialog-confirm
  ConfirmDialog-->>CommentRow: onConfirm()
  CommentRow->>apiClient.feeds: deleteComment(...)
  apiClient.feeds-->>CommentRow: success
  CommentRow->>FeedSection: onCommentDeleted()
  CommentRow->>CommentRow: clear confirmingDelete and deleting
Loading

Post deletion flow

sequenceDiagram
  participant User
  participant FeedSection
  participant ConfirmDialog
  participant apiClient.feeds
  participant homeFeed

  User->>FeedSection: click Delete
  FeedSection->>ConfirmDialog: open confirmation modal
  User->>ConfirmDialog: click confirm-dialog-confirm
  ConfirmDialog-->>FeedSection: onConfirm()
  FeedSection->>apiClient.feeds: deletePost(...)
  apiClient.feeds-->>FeedSection: success
  FeedSection->>homeFeed: refetch()
  FeedSection->>FeedSection: clear postPendingDelete and deletingPost
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I hopped past window.confirm with a grin,
to a cozy modal where the buttons begin.
🐇 Click, confirm, and off we go,
the feed now twinkles with a gentler glow.
Thump-thump—no more browser dialog fright!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% 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 title clearly summarizes the main change: replacing native delete confirmation with an in-app modal in Tiny Place.
Linked Issues check ✅ Passed The PR matches #4197 by replacing window.confirm with a design-system modal and waiting for user confirmation before delete RPCs.
Out of Scope Changes check ✅ Passed The changes stay focused on feed delete confirmation UI, related state handling, and tests, with no obvious unrelated additions.

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2c8f797039

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +581 to +583
title="Delete comment"
message="Delete this comment? This can't be undone."
confirmLabel="Delete"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Localize new confirmation copy

AGENTS.md requires all UI text to go through useT() with locale entries, but this new delete dialog copy is hard-coded in English here (and the post dialog below repeats the same pattern). In any non-English locale, users will still see English text for the destructive confirmation modal, so these labels/messages should be moved into the i18n catalog and passed through translations.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/agentworld/pages/FeedSection.tsx (1)

742-758: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep post deletion pending until the refresh actually succeeds.

This handler has two contract gaps: it ignores the { ok: boolean } result from deletePost(), and it detaches the homeFeed() refresh with void. A backend ok: false or a refresh rejection both fall through to finally, closing the modal and leaving stale feed state behind.

Suggested fix
   const confirmDeletePost = () => {
     const post = postPendingDelete;
     if (!post) return;
     setDeletingPost(true);
     void apiClient.feeds
       .deletePost(post.postId)
-      .then(() => {
-        void apiClient.graphql.homeFeed({ limit: 50, includeSelf: true }).then(result => {
+      .then(({ ok }) => {
+        if (!ok) throw new Error('Post deletion was not accepted by the backend');
+        return apiClient.graphql.homeFeed({ limit: 50, includeSelf: true }).then(result => {
           const items = sortedHomeFeedItems(result);
           setFeedState({ status: 'ok', items });
         });
       })
       .catch(err => console.error('[FeedSection] delete post failed:', err))
       .finally(() => {
         setDeletingPost(false);
         setPostPendingDelete(null);
       });
   };
🤖 Prompt for 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.

In `@app/src/agentworld/pages/FeedSection.tsx` around lines 742 - 758, The
confirmDeletePost handler in FeedSection should keep the delete flow pending
until both deletePost() and the homeFeed refresh succeed. Check the { ok:
boolean } result returned by apiClient.feeds.deletePost(post.postId) and treat
ok: false as a failure instead of proceeding to refresh. Also remove the
detached void from the apiClient.graphql.homeFeed(...) refresh so its rejection
is awaited and can prevent the cleanup in finally. Only clear deletingPost and
postPendingDelete after the refresh succeeds; on any failure, log the error and
leave the modal/state intact for retry.
🤖 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 `@app/src/agentworld/pages/FeedSection.tsx`:
- Around line 538-547: The delete flow in confirmDeleteComment currently treats
any resolved deleteComment() call as success, but apiClient.feeds.deleteComment
returns an object with an ok flag that must be checked. Update the promise
handling in confirmDeleteComment to inspect the deleteComment result and call
onCommentDeleted() only when ok is true; if ok is false, skip the success path
and keep the failure handling consistent with the existing error logging and
state reset logic in FeedSection.

---

Outside diff comments:
In `@app/src/agentworld/pages/FeedSection.tsx`:
- Around line 742-758: The confirmDeletePost handler in FeedSection should keep
the delete flow pending until both deletePost() and the homeFeed refresh
succeed. Check the { ok: boolean } result returned by
apiClient.feeds.deletePost(post.postId) and treat ok: false as a failure instead
of proceeding to refresh. Also remove the detached void from the
apiClient.graphql.homeFeed(...) refresh so its rejection is awaited and can
prevent the cleanup in finally. Only clear deletingPost and postPendingDelete
after the refresh succeeds; on any failure, log the error and leave the
modal/state intact for retry.
🪄 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: CHILL

Plan: Pro

Run ID: 033acff0-3667-43f6-95ea-ec22d35befdf

📥 Commits

Reviewing files that changed from the base of the PR and between 56af7ec and 2c8f797.

📒 Files selected for processing (3)
  • app/src/agentworld/components/ConfirmDialog.test.tsx
  • app/src/agentworld/components/ConfirmDialog.tsx
  • app/src/agentworld/pages/FeedSection.tsx

Comment thread app/src/agentworld/pages/FeedSection.tsx
…nding until refresh

- Update the two delete tests to confirm via the in-app modal (they relied on
  window.confirm, which the modal replaced) — the broken CI tests.
- Address CodeRabbit: check the {ok} result from deletePost/deleteComment and
  chain (not detach) the feed/detail refresh so a backend rejection or refresh
  failure is caught instead of silently closing the modal on stale state.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/agentworld/pages/FeedSection.test.tsx (1)

687-691: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Wait for the refetch, not just the delete RPC.

These assertions only wait for feeds.deletePost / feeds.deleteComment to be invoked. The follow-up homeFeed / graphql.post refetch happens later in the promise chain, so the immediate toHaveBeenCalledTimes(2) can race and flake. Fold the refetch assertion into waitFor (or assert on refreshed UI) so the test waits for the whole delete flow.

Suggested change
-    await waitFor(() => {
-      expect(vi.mocked(apiClient.feeds.deletePost)).toHaveBeenCalledWith(ownPost.postId);
-    });
-    // Feed refetched after delete
-    expect(vi.mocked(apiClient.graphql.homeFeed)).toHaveBeenCalledTimes(2);
+    await waitFor(() => {
+      expect(vi.mocked(apiClient.feeds.deletePost)).toHaveBeenCalledWith(ownPost.postId);
+      expect(vi.mocked(apiClient.graphql.homeFeed)).toHaveBeenCalledTimes(2);
+    });
-    await waitFor(() => {
-      expect(vi.mocked(apiClient.feeds.deleteComment)).toHaveBeenCalledWith(
-        samplePost.author.handle,
-        samplePost.postId,
-        myComment.commentId
-      );
-    });
-    // Detail refetched after delete
-    expect(vi.mocked(apiClient.graphql.post)).toHaveBeenCalledTimes(2);
+    await waitFor(() => {
+      expect(vi.mocked(apiClient.feeds.deleteComment)).toHaveBeenCalledWith(
+        samplePost.author.handle,
+        samplePost.postId,
+        myComment.commentId
+      );
+      expect(vi.mocked(apiClient.graphql.post)).toHaveBeenCalledTimes(2);
+    });

Based on the delete promise chains in app/src/agentworld/pages/FeedSection.tsx, each refetch is triggered after the delete RPC resolves.

Also applies to: 731-739

🤖 Prompt for 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.

In `@app/src/agentworld/pages/FeedSection.test.tsx` around lines 687 - 691, The
delete-flow tests in FeedSection are only waiting for deletePost/deleteComment
to be called, but the homeFeed/graphql.post refetch happens later in the promise
chain. Update the affected tests in FeedSection.test.tsx to wait for the full
delete sequence by moving the refetch assertion into waitFor, or assert on the
refreshed UI state after the delete RPC resolves. Use the existing
delete-related assertions around apiClient.feeds.deletePost,
apiClient.feeds.deleteComment, apiClient.graphql.homeFeed, and
apiClient.graphql.post to locate and adjust both cases.
🤖 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.

Outside diff comments:
In `@app/src/agentworld/pages/FeedSection.test.tsx`:
- Around line 687-691: The delete-flow tests in FeedSection are only waiting for
deletePost/deleteComment to be called, but the homeFeed/graphql.post refetch
happens later in the promise chain. Update the affected tests in
FeedSection.test.tsx to wait for the full delete sequence by moving the refetch
assertion into waitFor, or assert on the refreshed UI state after the delete RPC
resolves. Use the existing delete-related assertions around
apiClient.feeds.deletePost, apiClient.feeds.deleteComment,
apiClient.graphql.homeFeed, and apiClient.graphql.post to locate and adjust both
cases.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b9e941de-4d3b-4dca-a7f8-6a604f47f4e7

📥 Commits

Reviewing files that changed from the base of the PR and between 2c8f797 and aa45866.

📒 Files selected for processing (2)
  • app/src/agentworld/pages/FeedSection.test.tsx
  • app/src/agentworld/pages/FeedSection.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/agentworld/pages/FeedSection.tsx

@senamakel senamakel merged commit f9fb8fc into tinyhumansai:main Jun 29, 2026
19 checks passed
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.

bug: Feed delete confirmation uses native browser dialog ("tauri.localhost says") instead of in-app modal

2 participants