Skip to content

Waves editing fixes - #3196

Merged
feruzm merged 12 commits into
developmentfrom
wavesedit
May 20, 2026
Merged

Waves editing fixes#3196
feruzm merged 12 commits into
developmentfrom
wavesedit

Conversation

@feruzm

@feruzm feruzm commented May 20, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • Bug Fixes

    • Prevented duplicate/rapid post submissions by improving submit guards; submit flags now clear on errors, cancellations, and scheduling failures.
  • Improvements

    • Post deletion eligibility now aligns better with on-chain rules and can be delegated to per-feed handlers; missing handlers show a clear failure alert.
    • Wave posts use deterministic, content-based permlinks to reduce duplicates.
  • New Features

    • Share/copy link behavior normalized to canonical post paths.
  • Tests

    • Added tests for URL normalization and canonical post URL generation.

Review Change Stack

@greptile-apps greptile-apps 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.

feruzm has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@coderabbitai

coderabbitai Bot commented May 20, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds deterministic permlink generation for wave replies, delegates post deletion via optional callback with eligibility update, routes deletes through per-feed registered deleters, hardens editor submission guards, and normalizes post URLs with tests.

Changes

Wave submission idempotency and delegated deletion

Layer / File(s) Summary
Content-based permlink utility
src/utils/editor.ts
New generateContentBasedPermlink(prefix, contentKey) computes SHA-256 of contentKey, truncates, and returns ${prefix}-${hash} or '' when prefix is falsy.
Wave reply permlink generation
src/components/quickPostModal/usePostSubmitter.ts
_submitReply builds a deterministic contentKey (account, parent identifiers, body, first video thumb, serialized pollDraft) and uses generateContentBasedPermlink for PostTypes.WAVE; constructs canonical /@parentAuthor/parentPermlink#@author/permlink URLs.
Editor submission reentry protection
src/screens/editor/container/editorContainer.tsx
Adds synchronous _isSubmitting lifecycle handling: clears flag on early returns, wraps publish/edit flows in try/catch routed to _handleSubmitFailure, awaits scheduling, and ensures Alert cancel handlers clear the guard.
PostOptionsModal props and eligibility
src/components/postOptionsModal/container/postOptionsModal.tsx
Props now accepts optional onDelete; _canDeletePost replaces active_votes emptiness check with net_rshares <= 0 while keeping author/payout/children constraints; share link canonicalization added.
PostOptionsModal delegated delete flow
src/components/postOptionsModal/container/postOptionsModal.tsx
When onDelete is provided, delete confirmation awaits onDelete(content) and on error logs and dispatches a failure toast, returning early to skip the component's internal delete mutation/navigation/success toast.
WavesScreen delete wiring
src/screens/waves/screen/wavesScreen.tsx
Adds per-feed deleter registration (registerDeleter(feedKey, fn)), stores deleters in a parent Map, and supplies an async onDelete to PostOptionsModal that looks up and awaits the active feed's deleteWave; shows alert.fail if no handler is registered.
Post URL normalization & tests
src/utils/post.ts, src/utils/post.test.ts, src/components/comments/container/commentsContainer.tsx, src/providers/queries/postQueries/repostQueries.ts
Adds stripCategoryFromPostPath and getPostUrl tests; normalizes comment copy and repost/cross-post links to canonical /@author/permlink paths and updates tests accordingly.

Sequence Diagram

sequenceDiagram
  participant User as User (Compose/Delete)
  participant Submitter as usePostSubmitter
  participant EditorUtil as generateContentBasedPermlink
  participant PostModal as PostOptionsModal
  participant WavesScreen as WavesScreen
  participant FeedDeleter as Feed.deleteWave

  User->>Submitter: _submitReply (WAVE)
  Submitter->>EditorUtil: generateContentBasedPermlink(contentKey)
  EditorUtil->>EditorUtil: SHA-256 -> hex -> truncate
  EditorUtil-->>Submitter: deterministic permlink
  Submitter-->>User: submit with deterministic permlink

  User->>PostModal: open -> confirm delete
  PostModal->>WavesScreen: onDelete(content)
  WavesScreen->>FeedDeleter: deleteWave(permlink, parent_permlink)
  FeedDeleter-->>WavesScreen: Promise<void> resolution
  WavesScreen-->>PostModal: completion / Alert on missing handler
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Poem

🐰
I hash the words to make them stick,
Replies that post behave so slick.
A delete callback hops in line,
Guards hold the gates against repeat sign.
Waves and permlinks, neat and fine.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'Waves editing fixes' is vague and generic, failing to convey specific information about the changes. While the PR does include editing-related fixes, the title doesn't clarify what aspects were fixed or what the main change is. Provide a more descriptive title that specifies the key changes, such as 'Add optional onDelete callback to PostOptionsModal for waves' or 'Refactor wave deletion flow and normalize post URLs'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch wavesedit

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
src/screens/editor/container/editorContainer.tsx (1)

283-291: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical bug: Reply submissions are completely broken.

Setting _isSubmitting = true at line 1291 before calling _submitReply at line 1294 causes _submitReply to exit early on its first check at line 958. The first submission attempt itself would fail for replies because _submitReply checks this._isSubmitting at the very beginning and returns if it's true.

For edits and new posts, this works correctly because an Alert is shown first and the actual submission happens asynchronously in the alert callback. But for replies, _submitReply is called directly without an alert, so it immediately hits the guard check and exits.

Move this._isSubmitting = true to only the edit/post code paths, not before the if (isReply && !isEdit) branch. The reply path has its own guard in _submitReply that will prevent duplicate submissions.

🤖 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 `@src/screens/editor/container/editorContainer.tsx` around lines 283 - 291, The
bug is that _isSubmitting is set to true before calling _submitReply for
replies, causing the early-return guard in _submitReply to block the first reply
submission; change the logic in the component method that currently sets
this._isSubmitting = true (before the isReply check) so that _isSubmitting is
only set in the edit/new-post code paths (the branches that show the Alert and
then call _submitReply asynchronously) and not in the if (isReply && !isEdit)
branch; leave _submitReply and its internal guard unchanged so replies rely on
their existing duplication protection.
🤖 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/components/postOptionsModal/container/postOptionsModal.tsx`:
- Around line 352-363: The onDelete branch currently only logs errors so users
get no feedback; update the catch block for the onDelete(content) call to also
display a user-visible failure toast (use the same toast/helper used elsewhere
in this component, e.g., showToast/toast.error) with a friendly message like
"Failed to delete post" and optionally include err.message for debugging, keep
the console.warn and then return as before; modify the catch in the onDelete
handler around onDelete and content to call the toast helper.

In `@src/screens/waves/screen/wavesScreen.tsx`:
- Around line 387-397: The onDelete currently uses optional chaining on
activeDeleteWaveRef.current which can silently drop confirmed deletes; change it
to explicitly check activeDeleteWaveRef.current and, if present, invoke it with
the permlink/parent_permlink, otherwise perform a clear fallback (e.g., call the
same deletion logic used by the feed such as wavesQuery.deleteWave(permlink,
parent_permlink) and/or navigate back with navigation.goBack(), and log or
surface an error) so deletes are never no-ops; locate the onDelete handler and
update the logic around activeDeleteWaveRef.current to implement this explicit
branch and fallback.

---

Outside diff comments:
In `@src/screens/editor/container/editorContainer.tsx`:
- Around line 283-291: The bug is that _isSubmitting is set to true before
calling _submitReply for replies, causing the early-return guard in _submitReply
to block the first reply submission; change the logic in the component method
that currently sets this._isSubmitting = true (before the isReply check) so that
_isSubmitting is only set in the edit/new-post code paths (the branches that
show the Alert and then call _submitReply asynchronously) and not in the if
(isReply && !isEdit) branch; leave _submitReply and its internal guard unchanged
so replies rely on their existing duplication protection.
🪄 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: 021d221f-da8f-420a-86f8-7e6b0b9e9885

📥 Commits

Reviewing files that changed from the base of the PR and between f6e97d5 and ae96871.

📒 Files selected for processing (5)
  • src/components/postOptionsModal/container/postOptionsModal.tsx
  • src/components/quickPostModal/usePostSubmitter.ts
  • src/screens/editor/container/editorContainer.tsx
  • src/screens/waves/screen/wavesScreen.tsx
  • src/utils/editor.ts

Comment thread src/components/postOptionsModal/container/postOptionsModal.tsx
Comment thread src/screens/waves/screen/wavesScreen.tsx Outdated
@greptile-apps

greptile-apps Bot commented May 20, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes several waves editing bugs: duplicate submission guards now release _isSubmitting on all early-return paths (HiveAuth prompt dismissal, isPostSending early exit, _setScheduledPost failure), wave permlinks switch to a content-hash form to make retries idempotent, and the waves-feed delete clobbering is fixed by replacing the single activeDeleteWaveRef with a per-feed Map.

  • Submit-guard hardening (editorContainer.tsx, usePostSubmitter.ts): _isSubmitting is released before every async await and re-armed after; outer try/catch wraps the full submit body so any unexpected throw routes through _handleSubmitFailure; _setScheduledPost is now await-ed and its failure path uses _handleSubmitFailure instead of a silent setState.
  • Deterministic wave permlinks (editor.ts, usePostSubmitter.ts): generateContentBasedPermlink derives a SHA-256 hash from author + parent + body, making accidental resubmits produce the same permlink (Hive rejects the duplicate) rather than creating two identical waves.
  • Per-feed delete routing (wavesScreen.tsx, wavesQueries.ts): each WavesFeed registers its deleteWave under a stable feedKey in a parent Map; deleteWave is useCallback-memoised so the registration effect doesn't re-fire on every render; the options-modal delete resolves the correct feed by active key.

Confidence Score: 5/5

Safe to merge — all previously flagged submit-lock wedging, feed-deleter clobbering, and duplicate-wave issues are addressed with clean, well-commented fixes.

All six bugs raised in earlier review rounds are resolved: the HiveAuth dismissal path now releases the submit lock before awaiting; the recursive re-arm is correctly gated on manageSubmittingState; _setScheduledPost is awaited and its failure routes through _handleSubmitFailure; wave permlinks are now content-derived making retries idempotent; and the per-feed delete Map prevents the two simultaneously-mounted feeds from overwriting each other's deleter. No new defects identified.

No files require special attention.

Important Files Changed

Filename Overview
src/screens/editor/container/editorContainer.tsx Submit-guard refactor: _isSubmitting now cleared on every early-return and pre-await path in _submitPost/_submitEdit; outer try/catch added for any errors that escape inner mutation; _setScheduledPost now awaited; Alert cancel callbacks clear the guard.
src/components/quickPostModal/usePostSubmitter.ts setIsSubmitting(false) is now unconditional before the HiveAuth await, preventing permanent lock when the prompt sheet is dismissed without callbacks; re-arm logic correctly branches on manageSubmittingState to avoid tripping the entry guard on the recursive comment path; waves switch to content-based permlink.
src/screens/waves/screen/wavesScreen.tsx Single activeDeleteWaveRef replaced by a Map keyed by feedKey; each WavesFeed registers/unregisters its deleter slot on mount/unmount; delete routes through the currently-active feed's deleter rather than whichever tab rendered last.
src/providers/queries/postQueries/wavesQueries.ts deleteWave wrapped in useCallback with appropriate deps so its identity is stable across renders, preventing the registration effect in WavesFeed from re-firing on every parent render.
src/components/postOptionsModal/container/postOptionsModal.tsx Adds optional onDelete prop for delegated deletion; fixes _canDeletePost to use net_rshares <= 0 (aligning with Hive on-chain rule) instead of active_votes.length; normalises share/copy URLs to canonical form.
src/utils/editor.ts Adds generateContentBasedPermlink using CryptoJS SHA256; deterministic permlink scoped by author/parent/body eliminates duplicate wave creation on retry.
src/utils/post.ts Adds stripCategoryFromPostPath utility to normalise legacy //@author/permlink paths to canonical /@author/permlink form; handles null/undefined/empty inputs and already-canonical paths safely.
src/utils/post.test.ts New test file covering stripCategoryFromPostPath and getPostUrl; tests canonical pass-through, legacy stripping, comment fragments, empty/null inputs, and non-matching paths.
src/providers/queries/postQueries/repostQueries.ts Cross-post link body now uses canonical /@author/permlink form; drops unused category field extraction.
src/components/comments/container/commentsContainer.tsx Copy-link action for comments now strips the legacy category prefix from the URL before writing to clipboard.

Reviews (11): Last reviewed commit: "fix recur" | Re-trigger Greptile

Comment thread src/utils/editor.ts Outdated
Comment thread src/screens/editor/container/editorContainer.tsx

@coderabbitai coderabbitai 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.

♻️ Duplicate comments (1)
src/screens/waves/screen/wavesScreen.tsx (1)

395-401: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make the handler async to properly propagate errors from the mutation.

PostOptionsModal awaits the onDelete callback (line 359) and wraps it in a try/catch to show a toast on failure. Since deleteWave is an async function (wavesQueries.ts:93) that returns a Promise, calling it without await means any rejection will not be caught by the modal's error handler, leaving the delete silently failed after the modal closes.

Proposed fix
-        onDelete={(content) => {
+        onDelete={async (content) => {
           // Route the options-menu delete through the active feed's
           // `wavesQuery.deleteWave`, which both broadcasts the delete and
           // removes the wave from the waves infinite-query cache. The
           // modal's default path uses `navigation.goBack()` and never
           // updates the cache, so the wave would stay visible on the feed
           // even after a successful delete.
           const deleteWave = activeDeleteWaveRef.current;
           if (deleteWave) {
-            deleteWave({
+            await deleteWave({
               _permlink: content.permlink,
               _parent_permlink: content.parent_permlink,
             });
             return;
           }

Also update the onVisibilityChange type (lines 64-71) to reflect that deleteWave returns Promise<void>.

🤖 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 `@src/screens/waves/screen/wavesScreen.tsx` around lines 395 - 401, The delete
handler calls the ref'd function without awaiting it so rejections escape the
caller; update the handler that invokes activeDeleteWaveRef.current (the local
deleteWave invocation) to be async and await deleteWave({...}) so the Promise
rejection is propagated to PostOptionsModal's onDelete try/catch, and adjust the
onVisibilityChange callback type to return Promise<void> (and any related types)
to reflect that deleteWave (from wavesQueries.ts) is async.
🤖 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.

Duplicate comments:
In `@src/screens/waves/screen/wavesScreen.tsx`:
- Around line 395-401: The delete handler calls the ref'd function without
awaiting it so rejections escape the caller; update the handler that invokes
activeDeleteWaveRef.current (the local deleteWave invocation) to be async and
await deleteWave({...}) so the Promise rejection is propagated to
PostOptionsModal's onDelete try/catch, and adjust the onVisibilityChange
callback type to return Promise<void> (and any related types) to reflect that
deleteWave (from wavesQueries.ts) is async.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2342c2b9-cdd4-43ae-946d-78ade8da32eb

📥 Commits

Reviewing files that changed from the base of the PR and between ae96871 and 44fa5d8.

📒 Files selected for processing (4)
  • src/components/postOptionsModal/container/postOptionsModal.tsx
  • src/screens/editor/container/editorContainer.tsx
  • src/screens/waves/screen/wavesScreen.tsx
  • src/utils/editor.ts

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
src/components/postOptionsModal/container/postOptionsModal.tsx (1)

670-675: ⚡ Quick win

Wrap the case 'copy' declaration in a block.

Line 673 declares const _url directly in a switch clause without block scope. While the project's ESLint configuration has no-case-declarations disabled, wrapping the case with braces prevents potential variable hoisting issues and improves code clarity.

Proposed fix
       case 'copy':
+      {
         // Mirror the canonical-form normalization used in `_share` so copied
         // links go to `/@author/permlink` instead of the legacy
         // `/<category>/@author/permlink` (which the web 302s anyway).
         const _url = isWave
           ? `/@${content.author}/${content.permlink}`
           : stripCategoryFromPostPath(content.url);
         await writeToClipboard(getPostUrl(_url));
         alertTimer.current = setTimeout(() => {
           dispatch(
             toastNotification(
               intl.formatMessage({
                 id: 'alert.copied',
               }),
             ),
           );
           alertTimer.current = null;
         }, 300);
         break;
+      }
🤖 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 `@src/components/postOptionsModal/container/postOptionsModal.tsx` around lines
670 - 675, Wrap the case 'copy' branch in postOptionsModal.tsx in a block to
avoid declaring const _url directly inside the switch clause; specifically,
surround the case 'copy' logic with { } and move the declaration of _url (which
uses isWave, content.author, content.permlink, and
stripCategoryFromPostPath(content.url)) inside that block so the constant is
scoped locally to the case and prevents hoisting/clarity issues.
🤖 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.

Nitpick comments:
In `@src/components/postOptionsModal/container/postOptionsModal.tsx`:
- Around line 670-675: Wrap the case 'copy' branch in postOptionsModal.tsx in a
block to avoid declaring const _url directly inside the switch clause;
specifically, surround the case 'copy' logic with { } and move the declaration
of _url (which uses isWave, content.author, content.permlink, and
stripCategoryFromPostPath(content.url)) inside that block so the constant is
scoped locally to the case and prevents hoisting/clarity issues.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 139a4a84-f2d9-45c8-9843-3dfef1b9a8a4

📥 Commits

Reviewing files that changed from the base of the PR and between aefe3fd and 495c388.

📒 Files selected for processing (7)
  • src/components/comments/container/commentsContainer.tsx
  • src/components/postOptionsModal/container/postOptionsModal.tsx
  • src/components/quickPostModal/usePostSubmitter.ts
  • src/providers/queries/postQueries/repostQueries.ts
  • src/screens/editor/container/editorContainer.tsx
  • src/utils/post.test.ts
  • src/utils/post.ts

Comment thread src/components/quickPostModal/usePostSubmitter.ts Outdated
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