Skip to content

[1227E] - #8858

Open
jvega190 wants to merge 1 commit into
craftersoftware:developfrom
jvega190:bugfix/1227E
Open

[1227E]#8858
jvega190 wants to merge 1 commit into
craftersoftware:developfrom
jvega190:bugfix/1227E

Conversation

@jvega190

@jvega190 jvega190 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

https://github.com/craftersoftware/craftercms-e/issues/1227

Summary by CodeRabbit

  • Bug Fixes
    • Improved path navigation reliability when users move between folders quickly.
    • Prevented outdated loading results from replacing content for the currently selected path.
    • Improved handling of failed folder and parent-item requests after navigation changes.
    • Ensured refresh and bulk-loading operations apply results only to the path that initiated them.
    • Preserved accurate breadcrumbs and navigation state during rapid changes and asynchronous loading.

@jvega190 jvega190 changed the title [1227] [1227E] Aug 3, 2026
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The path navigator now carries request paths through asynchronous actions and validates them in reducers. Stale successes, failures, and parent-item responses are ignored. Refresh and parent-item 404 recovery only resets to the root when the requested path remains active.

Changes

Path-aware navigation

Layer / File(s) Summary
Propagate request paths through navigation flows
studio-ui/ui/app/src/state/actions/pathNavigator.ts, studio-ui/ui/app/src/state/epics/pathNavigator.ts
Completion and failure actions now include requested or captured paths across refresh, fetch, pagination, keyword, and parent-item flows. Bulk failures now identify requests with { id, path }.
Filter stale results in the reducer
studio-ui/ui/app/src/state/reducers/pathNavigator.ts
The reducer updates the active path when a request starts and ignores results when the navigator is missing or its current path differs from the request path.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PathRequest
  participant pathNavigatorEpics
  participant pathNavigatorReducer
  PathRequest->>pathNavigatorEpics: request navigation or refresh
  pathNavigatorEpics->>pathNavigatorReducer: start fetch with requested path
  pathNavigatorEpics->>pathNavigatorReducer: complete or fail with path
  pathNavigatorReducer->>pathNavigatorReducer: compare requested path with current path
Loading

Possibly related PRs

Suggested reviewers: jmendeza

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title references the ticket but does not describe the primary change, which adds path-aware stale-result handling to path navigation. Replace "[1227E]" with a concise title that describes the main change, such as "Prevent stale path navigator fetch results".
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description check ✅ Passed The description provides the required ticket reference for this template.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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

Caution

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

⚠️ Outside diff range comments (1)
studio-ui/ui/app/src/state/reducers/pathNavigator.ts (1)

152-172: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

pathNavigatorConditionallySetPath is the one flow left out of the new stale-result protection. Every other completion/failure action in this PR now discards results when the navigator has moved on; pathNavigatorConditionallySetPath's round-trip does not, even though it is the action used to recover from a 404 during navigation.

  • studio-ui/ui/app/src/state/reducers/pathNavigator.ts#L152-L172: add path to pathNavigatorConditionallySetPathFailed's payload, move currentPath immediately in the pathNavigatorConditionallySetPath case (mirroring pathNavigatorFetchPath), and guard pathNavigatorConditionallySetPathComplete/Failed with isStaleResult, as shown in the per-file proposed fix.
  • studio-ui/ui/app/src/state/epics/pathNavigator.ts#L138-L148: once the reducer guard exists, forward the request path through pathNavigatorConditionallySetPath's completion/failure so this fallback benefits from it.
  • studio-ui/ui/app/src/state/epics/pathNavigator.ts#L384-L387: same change for the second pathNavigatorConditionallySetPath dispatch site.
🤖 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 `@studio-ui/ui/app/src/state/reducers/pathNavigator.ts` around lines 152 - 172,
Update studio-ui/ui/app/src/state/reducers/pathNavigator.ts lines 152-172:
include path in pathNavigatorConditionallySetPathFailed, set currentPath
immediately in pathNavigatorConditionallySetPath, and guard
pathNavigatorConditionallySetPathComplete and
pathNavigatorConditionallySetPathFailed with isStaleResult. Update
studio-ui/ui/app/src/state/epics/pathNavigator.ts lines 138-148 and 384-387 to
forward the request path through both pathNavigatorConditionallySetPath
completion and failure dispatches.
🤖 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 `@studio-ui/ui/app/src/state/reducers/pathNavigator.ts`:
- Around line 152-172: Update
studio-ui/ui/app/src/state/reducers/pathNavigator.ts lines 152-172: include path
in pathNavigatorConditionallySetPathFailed, set currentPath immediately in
pathNavigatorConditionallySetPath, and guard
pathNavigatorConditionallySetPathComplete and
pathNavigatorConditionallySetPathFailed with isStaleResult. Update
studio-ui/ui/app/src/state/epics/pathNavigator.ts lines 138-148 and 384-387 to
forward the request path through both pathNavigatorConditionallySetPath
completion and failure dispatches.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 13a7e10b-be56-4cd7-9307-5647eb3e9b3f

📥 Commits

Reviewing files that changed from the base of the PR and between 57c06c7 and 22eeacd.

📒 Files selected for processing (3)
  • studio-ui/ui/app/src/state/actions/pathNavigator.ts
  • studio-ui/ui/app/src/state/epics/pathNavigator.ts
  • studio-ui/ui/app/src/state/reducers/pathNavigator.ts

@jvega190

jvega190 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai about the outside diff range comment, pathNavigatorFetchPath can move currentPath immediately because navigation is committed. ConditionallySetPath is different: it probes a candidate and only adopts it on success when parent.childrenCount > 0.
If you set currentPath on the request (as for FetchPath), a success with childrenCount === 0 never rolls it back. You’d leave the navigator on a path it was never supposed to take — the opposite of “conditionally.”

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@jvega190 You are correct. conditionallySetPath must not update currentPath when it starts the request. It commits the candidate path only when the response succeeds and parent.childrenCount > 0.

I withdraw the outside-diff-range comment.

🐇


✏️ Learnings added
Learnt from: jvega190
URL: https://github.com/craftersoftware/craftercms/pull/8858

Timestamp: 2026-08-03T17:53:56.355Z
Learning: In `studio-ui/ui/app/src/state/reducers/pathNavigator.ts`, `pathNavigatorFetchPath` represents committed navigation and can update `currentPath` when the request starts. `conditionallySetPath` probes a candidate path and must update `currentPath` only after a successful response where `parent.childrenCount > 0`; updating it on request would retain a candidate path when the response has no children.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

@jvega190

Copy link
Copy Markdown
Contributor Author

@coderabbitai how does this work look to be merged? Any issues you can point out?

@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== PR metadata and patch ==='
gh pr view 8858 --repo craftersoftware/craftercms --json number,title,state,isDraft,baseRefName,headRefName,mergeable,reviewDecision,statusCheckRollup
gh pr diff 8858 --repo craftersoftware/craftercms --patch

echo '=== Source outlines ==='
for f in \
  studio-ui/ui/app/src/state/actions/pathNavigator.ts \
  studio-ui/ui/app/src/state/epics/pathNavigator.ts \
  studio-ui/ui/app/src/state/reducers/pathNavigator.ts
do
  echo "--- $f ---"
  ast-grep outline "$f" --items all || true
done

echo '=== All changed-action references with context ==='
rg -n -C 4 \
  'pathNavigator(FetchPathComplete|BulkFetchPathComplete|FetchParentItemsComplete|FetchPathFailed|BulkFetchPathFailed)\s*\(' \
  studio-ui/ui/app/src

Length of output: 29392


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Epic: complete request-flow context ==='
nl -ba studio-ui/ui/app/src/state/epics/pathNavigator.ts | sed -n '90,420p'

echo '=== Reducer: complete action-handling context ==='
nl -ba studio-ui/ui/app/src/state/reducers/pathNavigator.ts | sed -n '1,270p'

echo '=== Action declarations ==='
nl -ba studio-ui/ui/app/src/state/actions/pathNavigator.ts | sed -n '1,150p'

echo '=== Path navigator tests and relevant test cases ==='
fd -t f -i 'pathNavigator' studio-ui/ui/app | sort
rg -n -C 5 \
  '(PATH_NAV_|pathNavigator(FetchPath|Refresh|BulkRefresh|FetchParentItems|ConditionallySetPath)|stale|currentPath)' \
  studio-ui/ui/app \
  -g '*test*' -g '*spec*' || true

echo '=== All action creators and raw action-type producers in the repository ==='
rg -n -C 3 \
  '(pathNavigatorFetchPathComplete|pathNavigatorBulkFetchPathComplete|pathNavigatorFetchParentItemsComplete|pathNavigatorFetchPathFailed|pathNavigatorBulkFetchPathFailed)\b|PATH_NAV_(FETCH_PATH_COMPLETE|BULK_FETCH_PATH_COMPLETE|FETCH_PARENT_ITEMS_COMPLETE|FETCH_PATH_FAILED|BULK_FETCH_PATH_FAILED)' \
  .

Length of output: 1497


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Epic: request-flow context ==='
sed -n '90,420p' studio-ui/ui/app/src/state/epics/pathNavigator.ts

echo '=== Reducer: action-handling context ==='
sed -n '1,270p' studio-ui/ui/app/src/state/reducers/pathNavigator.ts

echo '=== Action declarations ==='
sed -n '1,150p' studio-ui/ui/app/src/state/actions/pathNavigator.ts

echo '=== Path navigator test files ==='
find studio-ui/ui/app -type f \( -iname '*pathNavigator*test*' -o -iname '*pathNavigator*spec*' \) -print | sort

echo '=== Relevant test cases ==='
rg -n -C 5 \
  '(PATH_NAV_|pathNavigator(FetchPath|Refresh|BulkRefresh|FetchParentItems|ConditionallySetPath)|stale|currentPath)' \
  studio-ui/ui/app \
  -g '*test*' -g '*spec*' || true

echo '=== All altered-action producers ==='
rg -n -C 3 \
  '(pathNavigatorFetchPathComplete|pathNavigatorBulkFetchPathComplete|pathNavigatorFetchParentItemsComplete|pathNavigatorFetchPathFailed|pathNavigatorBulkFetchPathFailed)\b|PATH_NAV_(FETCH_PATH_COMPLETE|BULK_FETCH_PATH_COMPLETE|FETCH_PARENT_ITEMS_COMPLETE|FETCH_PATH_FAILED|BULK_FETCH_PATH_FAILED)' \
  .

Length of output: 46822


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Completion side-effect epic ==='
sed -n '407,500p' studio-ui/ui/app/src/state/epics/pathNavigator.ts

echo '=== Content reducer completion handlers ==='
sed -n '130,215p' studio-ui/ui/app/src/state/reducers/content.ts

echo '=== Definitions used by the content reducer ==='
rg -n -C 5 \
  'function (updateItemByPath|updateItemsByPaths)|const (updateItemByPath|updateItemsByPaths)|updateItemByPath\s*=|updateItemsByPaths\s*=' \
  studio-ui/ui/app/src/state/reducers/content.ts

echo '=== Test directories and configuration ==='
find . -type d \( -name '__tests__' -o -name 'test' -o -name 'tests' \) -print | sort | head -100
find . -maxdepth 4 -type f \( -name 'package.json' -o -name 'jest.config.*' -o -name 'vitest.config.*' \) -print | sort | head -100

echo '=== Existing navigator test references across the repository ==='
rg -n -C 3 \
  '(pathNavigator|PATH_NAV_)' \
  . \
  -g '*test.*' -g '*spec.*' || true

Length of output: 10001


@jvega190 This work looks ready to merge after the draft status is removed and the required review is complete.

I found no merge-blocking issue.

The implementation now captures the request path for refresh, bulk refresh, fetch, pagination, keyword, and parent-item flows. The reducer rejects a completion or failure when that path differs from currentPath. This prevents an older request from overwriting later navigation.

The bulk refresh change is important. It preserves each navigator path before the asynchronous request starts.

Travis CI passed. The PR is mergeable. GitHub still reports REVIEW_REQUIRED, and the PR is a draft.

One non-blocking recommendation: add reducer or epic tests for these cases:

  • Navigate from path A to path B before the request for A completes.
  • Return success and failure responses for A.
  • Run a bulk refresh where one navigator moves before the response completes.
  • Confirm that a 404 refresh does not move a navigator that has already changed paths.

You are interacting with an AI system.

@jvega190

jvega190 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai can you check if everything looks good? Please give it a final review before I hand over for human review

@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="craftersoftware/craftercms"
pr="8858"

echo '=== Pull request status ==='
gh pr view "$pr" --repo "$repo" \
  --json number,title,state,isDraft,mergeable,reviewDecision,statusCheckRollup,headRefOid,baseRefOid

echo '=== Current pull request diff ==='
gh pr diff "$pr" --repo "$repo" --patch

echo '=== Changed file outlines ==='
for file in \
  studio-ui/ui/app/src/state/actions/pathNavigator.ts \
  studio-ui/ui/app/src/state/epics/pathNavigator.ts \
  studio-ui/ui/app/src/state/reducers/pathNavigator.ts
do
  echo "--- ${file} ---"
  ast-grep outline "$file" --items all || true
done

echo '=== Action declarations ==='
sed -n '1,180p' studio-ui/ui/app/src/state/actions/pathNavigator.ts

echo '=== Epic request and completion flows ==='
sed -n '1,540p' studio-ui/ui/app/src/state/epics/pathNavigator.ts

echo '=== Reducer handlers ==='
sed -n '1,340p' studio-ui/ui/app/src/state/reducers/pathNavigator.ts

echo '=== All changed action creator call sites ==='
rg -n -C 4 --type ts \
  '\bpathNavigator(FetchPathComplete|BulkFetchPathComplete|FetchParentItemsComplete|FetchPathFailed|BulkFetchPathFailed)\s*\(' \
  studio-ui/ui/app/src

echo '=== Relevant test coverage ==='
fd -t f . studio-ui/ui/app | rg '(pathNavigator|PathNavigator).*\.(test|spec)\.(ts|tsx)$' || true
rg -n -C 4 --type ts \
  '\b(pathNavigator(FetchPath|Refresh|BulkRefresh|FetchParentItems|ConditionallySetPath)|PATH_NAV_)' \
  studio-ui/ui/app -g '*test*' -g '*spec*' || true

Length of output: 64280


@jvega190 Final review complete. I found no merge-blocking issues.

The request path is captured before each asynchronous operation completes. The reducer compares that path with currentPath before it applies a result or failure. This prevents an older request from overwriting newer navigation.

conditionallySetPath keeps its required behavior. It commits the candidate path only after a successful response where parent.childrenCount > 0.

GitHub reports that the PR is mergeable. CodeRabbit and Travis CI checks passed. The PR remains a draft and requires human review.

The repository search found no existing path navigator tests. I recommend follow-up test coverage for stale success and failure responses, but this does not block handoff for human review.

⚠️ Action not completed

Already reviewed the last commit. Use @coderabbitai full review to rerun a review of the entire changeset.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@jvega190
jvega190 marked this pull request as ready for review September 3, 2026 16:35
@jvega190
jvega190 requested a review from rart September 3, 2026 16:35

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

Can we make this backward compatible so that it continues to work as before if the path arg is not sent as before?

@jvega190

jvega190 commented Sep 14, 2026

Copy link
Copy Markdown
Contributor Author

Can we make this backward compatible so that it continues to work as before if the path arg is not sent as before?

@rart the thing is that the issue was happening because of a lack of a path to identify the fetch.
e.g.:

  • userA navigates to a path, fetch is being performed, not done yet
  • Just as the fetch for userA is happening, userB does a content edition and it causes a reload of userA's tree.
  • Since there is no path set, the reload for userA is done against the path before navigating.

By adding the path, the tree reload is performed against the new path being set, even if it wasn't fully fetched/set yet.

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.

2 participants