Skip to content

fix: card reset view layout#8732

Open
VincentHan12 wants to merge 1 commit intomainfrom
vincenthan/nes-138-unconnected-card-redirection
Open

fix: card reset view layout#8732
VincentHan12 wants to merge 1 commit intomainfrom
vincenthan/nes-138-unconnected-card-redirection

Conversation

@VincentHan12
Copy link
Contributor

@VincentHan12 VincentHan12 commented Feb 13, 2026

Summary by CodeRabbit

  • Refactor
    • Enhanced step arrangement logic in the journey flow editor to improve position calculations by considering edge connectivity when organizing steps.

@linear
Copy link

linear bot commented Feb 13, 2026

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 13, 2026

Walkthrough

These changes introduce edge-aware positioning logic to the journey flow step arrangement system. The arrangeSteps function now accepts an optional edges parameter and uses edge traversal to compute step positions vertically, replacing previous horizontal layout. Test fixtures and component integration are updated accordingly to reflect the new vertical arrangement strategy.

Changes

Cohort / File(s) Summary
Step arrangement refactoring
apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/libs/arrangeSteps/arrangeSteps.ts, arrangeSteps.spec.ts
Core positioning algorithm redesigned to support edge-aware traversal. Signature updated to accept optional edges parameter. New helper functions added: buildSourceToTargetsMap, buildBlocksByEdgeTraversal, buildBlocksByStructureTraversal, finalizeBlocks. Test data migrated from horizontal (x: 600, 1200, 1800...) to vertical layout (x: 0, y: 172, 352...). New test case added for isolated directed cycles.
Component and test updates
apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/JourneyFlow.tsx, JourneyFlow.spec.tsx
JourneyFlow component now maintains edgesRef and passes current edges to arrangeSteps for edge-aware positioning. Test fixtures updated from horizontal step offsets to vertical stacking arrangement across multiple test scenarios.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • edmonday
🚥 Pre-merge checks | ✅ 3 | ❌ 3
❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'fix: card reset view layout' is vague and generic, not clearly describing the actual changes made to the codebase. Use a more specific title like 'fix: arrange unconnected steps below main branch on reset view' that describes the actual implementation change being made.
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.
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (180 files):

⚔️ apis/api-analytics/infrastructure/locals.tf (content)
⚔️ apis/api-gateway/infrastructure/locals.tf (content)
⚔️ apis/api-gateway/schema.graphql (content)
⚔️ apis/api-journeys-modern/infrastructure/locals.tf (content)
⚔️ apis/api-journeys-modern/schema.graphql (content)
⚔️ apis/api-journeys-modern/src/emails/templates/JourneyAccessRequest/JourneyAccessRequest.tsx (content)
⚔️ apis/api-journeys-modern/src/emails/templates/JourneyShared/JourneyShared.tsx (content)
⚔️ apis/api-journeys-modern/src/emails/templates/JourneyShared/JourneySharedNoAccount/JourneySharedNoAccount.tsx (content)
⚔️ apis/api-journeys-modern/src/emails/templates/TeamInvite/TeamInvite.tsx (content)
⚔️ apis/api-journeys-modern/src/emails/templates/TeamInvite/TeamInviteNoAccount/TeamInviteNoAccount.tsx (content)
⚔️ apis/api-journeys-modern/src/emails/templates/TeamInviteAccepted/TeamInviteAccepted.tsx (content)
⚔️ apis/api-journeys-modern/src/emails/templates/TeamRemoved/TeamRemoved.tsx (content)
⚔️ apis/api-journeys-modern/src/schema/user/index.ts (content)
⚔️ apis/api-journeys-modern/src/schema/user/user.ts (content)
⚔️ apis/api-journeys/db/seed.ts (content)
⚔️ apis/api-journeys/db/seeds/playwrightUserAccess.ts (content)
⚔️ apis/api-journeys/infrastructure/locals.tf (content)
⚔️ apis/api-journeys/schema.graphql (content)
⚔️ apis/api-journeys/src/__generated__/graphql.ts (content)
⚔️ apis/api-journeys/src/app/__generated__/graphql.ts (content)
⚔️ apis/api-journeys/src/app/modules/journey/journey.resolver.spec.ts (content)
⚔️ apis/api-journeys/src/app/modules/journey/journey.resolver.ts (content)
⚔️ apis/api-journeys/src/app/modules/userTeam/userTeam.graphql (content)
⚔️ apis/api-languages/infrastructure/locals.tf (content)
⚔️ apis/api-languages/schema.graphql (content)
⚔️ apis/api-languages/src/schema/user/user.ts (content)
⚔️ apis/api-media/Dockerfile (content)
⚔️ apis/api-media/infrastructure/locals.tf (content)
⚔️ apis/api-media/schema.graphql (content)
⚔️ apis/api-media/src/schema/arclightApiKey/arclightApiKey.spec.ts (content)
⚔️ apis/api-media/src/schema/bibleCitation/bibleCitation.spec.ts (content)
⚔️ apis/api-media/src/schema/cloudflare/image/image.spec.ts (content)
⚔️ apis/api-media/src/schema/cloudflare/r2/asset.spec.ts (content)
⚔️ apis/api-media/src/schema/cloudflare/r2/asset.ts (content)
⚔️ apis/api-media/src/schema/keyword/keyword.spec.ts (content)
⚔️ apis/api-media/src/schema/shortLink/shortLink.spec.ts (content)
⚔️ apis/api-media/src/schema/shortLink/shortLinkDomain/shortLinkDomain.spec.ts (content)
⚔️ apis/api-media/src/schema/taxonomy/taxonomy.spec.ts (content)
⚔️ apis/api-media/src/schema/user/index.ts (content)
⚔️ apis/api-media/src/schema/user/user.spec.ts (content)
⚔️ apis/api-media/src/schema/user/user.ts (content)
⚔️ apis/api-media/src/schema/video/video.spec.ts (content)
⚔️ apis/api-media/src/schema/video/videoAlgolia/videoAlgolia.spec.ts (content)
⚔️ apis/api-media/src/schema/video/videoDescription/videoDescription.spec.ts (content)
⚔️ apis/api-media/src/schema/video/videoImageAlt/videoImageAtl.spec.ts (content)
⚔️ apis/api-media/src/schema/video/videoOrigin/videoOrigin.spec.ts (content)
⚔️ apis/api-media/src/schema/video/videoPublishChildren.mutation.spec.ts (content)
⚔️ apis/api-media/src/schema/video/videoPublishChildrenAndLanguages.mutation.spec.ts (content)
⚔️ apis/api-media/src/schema/video/videoSnippet/videoSnippet.spec.ts (content)
⚔️ apis/api-media/src/schema/video/videoStudyQuestion/videoStudyQuestion.spec.ts (content)
⚔️ apis/api-media/src/schema/video/videoSubtitle/videoSubtitle.spec.ts (content)
⚔️ apis/api-media/src/schema/video/videoTitle/videoTitle.spec.ts (content)
⚔️ apis/api-media/src/schema/videoEdition/videoEdition.spec.ts (content)
⚔️ apis/api-media/src/schema/videoVariant/videoVariant.spec.ts (content)
⚔️ apis/api-media/src/schema/videoVariant/videoVariant.ts (content)
⚔️ apis/api-media/src/schema/videoVariant/videoVariantDownload/videoVariantDownload.spec.ts (content)
⚔️ apis/api-media/src/workers/crowdin/importers/studyQuestions/studyQuestions.spec.ts (content)
⚔️ apis/api-media/src/workers/crowdin/importers/videoTitles/videoTitles.spec.ts (content)
⚔️ apis/api-media/src/workers/processVideoUploads/service/service.ts (content)
⚔️ apis/api-media/src/workers/seed/service/taxonomy/taxonomy.spec.ts (content)
⚔️ apis/api-users/infrastructure/locals.tf (content)
⚔️ apis/api-users/schema.graphql (content)
⚔️ apis/api-users/src/emails/stories/EmailVerify.stories.tsx (content)
⚔️ apis/api-users/src/schema/user/findOrFetchUser.spec.ts (content)
⚔️ apis/api-users/src/schema/user/findOrFetchUser.ts (content)
⚔️ apis/api-users/src/schema/user/inputs/createVerificationRequestInput.ts (content)
⚔️ apis/api-users/src/schema/user/inputs/meInput.ts (content)
⚔️ apis/api-users/src/schema/user/objects/index.ts (content)
⚔️ apis/api-users/src/schema/user/objects/user.ts (content)
⚔️ apis/api-users/src/schema/user/user.spec.ts (content)
⚔️ apis/api-users/src/schema/user/user.ts (content)
⚔️ apis/api-users/src/schema/user/verifyUser.spec.ts (content)
⚔️ apis/api-users/src/schema/user/verifyUser.ts (content)
⚔️ apis/api-users/src/workers/email/service/service.ts (content)
⚔️ apps/cms/infrastructure/locals.tf (content)
⚔️ apps/journeys-admin-e2e/src/e2e/discover/active-archived-trash.spec.ts (content)
⚔️ apps/journeys-admin-e2e/src/e2e/discover/card-level-actions.spec.ts (content)
⚔️ apps/journeys-admin-e2e/src/e2e/discover/custom-journey.spec.ts (content)
⚔️ apps/journeys-admin-e2e/src/e2e/discover/journey-level-actions.spec.ts (content)
⚔️ apps/journeys-admin-e2e/src/e2e/discover/teams.spec.ts (content)
⚔️ apps/journeys-admin-e2e/src/pages/card-level-actions.ts (content)
⚔️ apps/journeys-admin-e2e/src/pages/journey-level-actions-page.ts (content)
⚔️ apps/journeys-admin-e2e/src/pages/journey-page.ts (content)
⚔️ apps/journeys-admin-e2e/src/pages/teams-page.ts (content)
⚔️ apps/journeys-admin/__generated__/globalTypes.ts (content)
⚔️ apps/journeys-admin/pages/index.tsx (content)
⚔️ apps/journeys-admin/pages/templates/[journeyId]/customize.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/RadioOptionEdit/RadioOptionEdit.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/Content/Canvas/InlineEditWrapper/RadioQuestionEdit/RadioQuestionEdit.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/JourneyFlow.spec.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/JourneyFlow.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/libs/arrangeSteps/arrangeSteps.spec.ts (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/libs/arrangeSteps/arrangeSteps.ts (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/nodes/StepBlockNode/StepBlockNodeMenu/StepBlockNodeMenu.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/AddBlock/NewMultiselectButton/NewMultiselectButton.spec.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/AddBlock/NewMultiselectButton/NewMultiselectButton.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/JourneyAppearance/Host/HostSelection/HostSelection.spec.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/Settings/CanvasDetails/JourneyAppearance/Host/HostSelection/HostSelection.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/VideoBlockEditorSettings.spec.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoBlockEditor/Settings/VideoBlockEditorSettings.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoDetails/VideoDetails.spec.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoDetails/VideoDetails.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromMux/AddByFile/AddByFile.spec.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Slider/Settings/Drawer/VideoLibrary/VideoFromMux/AddByFile/AddByFile.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/ShareItem.spec.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Toolbar/Items/ShareItem/ShareItem.tsx (content)
⚔️ apps/journeys-admin/src/components/Editor/Toolbar/JourneyDetails/JourneyDetails.tsx (content)
⚔️ apps/journeys-admin/src/components/HelpScoutBeacon/BeaconInit/BeaconInit.tsx (content)
⚔️ apps/journeys-admin/src/components/HelpScoutBeacon/BeaconInit/constants.ts (content)
⚔️ apps/journeys-admin/src/components/HelpScoutBeacon/HelpScoutBeacon.spec.tsx (content)
⚔️ apps/journeys-admin/src/components/HelpScoutBeacon/HelpScoutBeacon.tsx (content)
⚔️ apps/journeys-admin/src/components/JourneyList/AddJourneyFab/AddJourneyFab.spec.tsx (content)
⚔️ apps/journeys-admin/src/components/JourneyList/AddJourneyFab/AddJourneyFab.tsx (content)
⚔️ apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCard.spec.tsx (content)
⚔️ apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCard.tsx (content)
⚔️ apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCardMenu/DefaultMenu/DefaultMenu.tsx (content)
⚔️ apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCardMenu/JourneyCardMenu.spec.tsx (content)
⚔️ apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCardMenu/JourneyCardMenu.tsx (content)
⚔️ apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCardMenu/TrashMenu/TrashMenu.spec.tsx (content)
⚔️ apps/journeys-admin/src/components/JourneyList/JourneyCard/JourneyCardMenu/TrashMenu/TrashMenu.tsx (content)
⚔️ apps/journeys-admin/src/components/JourneyList/JourneyList.spec.tsx (content)
⚔️ apps/journeys-admin/src/components/JourneyList/JourneyList.tsx (content)
⚔️ apps/journeys-admin/src/components/JourneyVisitorsList/FilterDrawer/GoogleSheetsSyncDialog/GoogleSheetsSyncDialog.spec.tsx (content)
⚔️ apps/journeys-admin/src/components/JourneyVisitorsList/FilterDrawer/GoogleSheetsSyncDialog/GoogleSheetsSyncDialog.tsx (content)
⚔️ apps/journeys-admin/src/components/PageWrapper/AppHeader/AppHeader.tsx (content)
⚔️ apps/journeys-admin/src/components/PageWrapper/PageWrapper.spec.tsx (content)
⚔️ apps/journeys-admin/src/components/PageWrapper/PageWrapper.tsx (content)
⚔️ apps/journeys-admin/src/components/Team/CopyToTeamMenuItem/CopyToTeamMenuItem.spec.tsx (content)
⚔️ apps/journeys-admin/src/components/Team/CopyToTeamMenuItem/CopyToTeamMenuItem.tsx (content)
⚔️ apps/journeys-admin/src/components/TemplateBreakdownAnalyticsDialog/InfoIcon/InfoIcon.tsx (content)
⚔️ apps/journeys-admin/src/components/TemplateCustomization/MultiStepForm/Screens/LanguageScreen/LanguageScreen.tsx (content)
⚔️ apps/video-importer/src/utils/videoEditionValidator.ts (content)
⚔️ apps/videos-admin/src/app/_UploadVideoVariantProvider/UploadVideoVariantProvider.tsx (content)
⚔️ apps/watch/middleware.spec.ts (content)
⚔️ apps/watch/middleware.ts (content)
⚔️ apps/watch/src/components/ContentHeader/ContentHeader.tsx (content)
⚔️ infrastructure/modules/aws/ecs-task/main.tf (content)
⚔️ infrastructure/modules/aws/ecs-task/variables.tf (content)
⚔️ libs/journeys/ui/src/components/RadioQuestion/RadioQuestion.tsx (content)
⚔️ libs/journeys/ui/src/components/TemplateGallery/HeaderAndLanguageFilter/HeaderAndLanguageFilter.spec.tsx (content)
⚔️ libs/journeys/ui/src/components/TemplateGallery/HeaderAndLanguageFilter/HeaderAndLanguageFilter.tsx (content)
⚔️ libs/journeys/ui/src/components/TemplateGallery/HeaderAndLanguageFilter/LanguagesFilterPopper/LanguagesFilterPopper.tsx (content)
⚔️ libs/journeys/ui/src/components/TemplateGallery/TemplateGallery.spec.tsx (content)
⚔️ libs/journeys/ui/src/components/TemplateView/UseThisTemplateButton/UseThisTemplateButton.tsx (content)
⚔️ libs/locales/am-ET/apps-journeys-admin.json (content)
⚔️ libs/locales/ar-SA/apps-journeys-admin.json (content)
⚔️ libs/locales/bn-BD/apps-journeys-admin.json (content)
⚔️ libs/locales/de-DE/apps-journeys-admin.json (content)
⚔️ libs/locales/en/apps-journeys-admin.json (content)
⚔️ libs/locales/es-ES/apps-journeys-admin.json (content)
⚔️ libs/locales/fr-FR/apps-journeys-admin.json (content)
⚔️ libs/locales/hi-IN/apps-journeys-admin.json (content)
⚔️ libs/locales/id-ID/apps-journeys-admin.json (content)
⚔️ libs/locales/ja-JP/apps-journeys-admin.json (content)
⚔️ libs/locales/ko-KR/apps-journeys-admin.json (content)
⚔️ libs/locales/ms-MY/apps-journeys-admin.json (content)
⚔️ libs/locales/my-MM/apps-journeys-admin.json (content)
⚔️ libs/locales/ne-NP/apps-journeys-admin.json (content)
⚔️ libs/locales/pt-BR/apps-journeys-admin.json (content)
⚔️ libs/locales/ru-RU/apps-journeys-admin.json (content)
⚔️ libs/locales/th-TH/apps-journeys-admin.json (content)
⚔️ libs/locales/tl-PH/apps-journeys-admin.json (content)
⚔️ libs/locales/tr-TR/apps-journeys-admin.json (content)
⚔️ libs/locales/ur-PK/apps-journeys-admin.json (content)
⚔️ libs/locales/vi-VN/apps-journeys-admin.json (content)
⚔️ libs/locales/zh-Hans-CN/apps-journeys-admin.json (content)
⚔️ libs/locales/zh-Hant-TW/apps-journeys-admin.json (content)
⚔️ libs/prisma/media/db/schema.prisma (content)
⚔️ libs/prisma/media/src/__generated__/pothos-types.ts (content)
⚔️ libs/shared/gql/src/__generated__/graphql-env.d.ts (content)
⚔️ libs/yoga/src/email/components/EmailLogo/EmailLogo.tsx (content)
⚔️ libs/yoga/src/email/components/Footer/Footer.tsx (content)
⚔️ libs/yoga/src/email/components/Header/Header.tsx (content)
⚔️ libs/yoga/src/email/components/index.ts (content)
⚔️ libs/yoga/src/email/email.spec.ts (content)
⚔️ libs/yoga/src/email/email.ts (content)
⚔️ validate-branch-name.config.js (content)
⚔️ workers/jf-proxy/src/index.spec.ts (content)
⚔️ workers/jf-proxy/src/index.ts (content)
⚔️ workers/jf-proxy/wrangler.toml (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The changes implement edge-aware step arrangement to position unconnected cards below the main branch, directly addressing NES-138's requirement.
Out of Scope Changes check ✅ Passed All changes focus on implementing the arrangeSteps algorithm with edge awareness to handle unconnected step placement, staying within scope of NES-138.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch vincenthan/nes-138-unconnected-card-redirection
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch vincenthan/nes-138-unconnected-card-redirection
  • Create stacked PR with resolved conflicts
  • Post resolved changes as copyable diffs in a comment

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.

@nx-cloud
Copy link

nx-cloud bot commented Feb 13, 2026

View your CI Pipeline Execution ↗ for commit f415f86

Command Status Duration Result
nx run journeys-admin-e2e:e2e ✅ Succeeded 33s View ↗
nx run-many --target=vercel-alias --projects=jo... ✅ Succeeded 2s View ↗
nx run-many --target=upload-sourcemaps --projec... ✅ Succeeded 12s View ↗
nx run-many --target=deploy --projects=journeys... ✅ Succeeded 2m 45s View ↗

☁️ Nx Cloud last updated this comment at 2026-02-13 02:42:16 UTC

@github-actions github-actions bot temporarily deployed to Preview - journeys-admin February 13, 2026 02:34 Inactive
Copy link
Contributor

@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

🤖 Fix all issues with AI agents
In
`@apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/JourneyFlow.tsx`:
- Around line 203-209: The initial arrangement uses the fallback because
edgesRef.current is empty when arrangeSteps(steps, edgesRef.current) runs;
ensure edges are computed/populated before triggering the edge-aware layout by
moving or adding the edge population step ahead of the call that invokes
allBlockPositionUpdate(true)/arrangeSteps — specifically, populate edgesRef (or
call setEdges / the edge-computation helper) before calling
allBlockPositionUpdate in the useEffect, or defer running arrangeSteps until you
have a computed edges value and pass that into arrangeSteps(steps, edges) so the
edge-aware path runs even on first load.

In
`@apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/libs/arrangeSteps/arrangeSteps.ts`:
- Around line 105-116: The forEach arrow currently uses an expression body that
implicitly returns the Set from placedIds.add(s.id), which triggers the lint
warning; in processLevel change the callback to a block body (e.g., .forEach((s)
=> { placedIds.add(s.id); })) to suppress the implicit-return, and make the
identical change for the other forEach occurrence referenced around line 150 so
both callbacks use block bodies instead of expression bodies; locate these by
the function name processLevel and by occurrences of placedIds.add(...) in the
file.
🧹 Nitpick comments (2)
apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/libs/arrangeSteps/arrangeSteps.ts (1)

210-234: prevActionBlock is unused — likely a leftover from prior logic.

The reduce callback receives prevActionBlock on line 210 but never uses it inside the body. The return value on line 233 is computed but only feeds back as prevActionBlock for the next iteration, where it's again unused.

apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/libs/arrangeSteps/arrangeSteps.spec.ts (1)

182-191: Cycle test assertions are weak — consider asserting actual position values.

The test only checks that positions are defined, not what the actual x/y values are. This doesn't verify the layout is correct for cycles. Asserting specific coordinates (or at least structural properties like "all steps in cycle A share the same x") would catch regressions more effectively.

Comment on lines +203 to +209

const stepBlockInputs = Object.entries(
arrangeSteps(steps, edgesRef.current)
).map(([id, position]) => ({
id,
...position
}))
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

On first load with invalid positions, edgesRef.current will be [] — falling back to structure traversal.

When the useEffect at line 260 detects invalid step positions and calls allBlockPositionUpdate(true), it returns early before setEdges populates the edge state. So this initial arrangement uses the structure-based fallback. On subsequent "reset view" clicks (the actual fix target), edges are populated and the edge-aware path runs correctly.

This is likely fine for the initial load scenario, but worth being aware of — if the initial layout also needs edge-aware positioning, you'd need to compute edges before calling allBlockPositionUpdate.

🤖 Prompt for AI Agents
In `@apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/JourneyFlow.tsx`
around lines 203 - 209, The initial arrangement uses the fallback because
edgesRef.current is empty when arrangeSteps(steps, edgesRef.current) runs;
ensure edges are computed/populated before triggering the edge-aware layout by
moving or adding the edge population step ahead of the call that invokes
allBlockPositionUpdate(true)/arrangeSteps — specifically, populate edgesRef (or
call setEdges / the edge-computation helper) before calling
allBlockPositionUpdate in the useEffect, or defer running arrangeSteps until you
have a computed edges value and pass that into arrangeSteps(steps, edges) so the
edge-aware path runs even on first load.

Comment on lines +105 to +116
function processLevel(levelSteps: TreeStepBlock[]): void {
blocks.push(levelSteps)
levelSteps.forEach((s) => placedIds.add(s.id))
const nextIds = levelSteps.flatMap((s) => sourceToTargets.get(s.id) ?? [])
const uniqueNextIds = [...new Set(nextIds)].filter(
(id) => !placedIds.has(id)
)
const nextSteps = uniqueNextIds
.map((id) => steps.find((s) => s.id === id))
.filter((s): s is TreeStepBlock => s != null)
if (nextSteps.length > 0) processLevel(nextSteps)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Static analysis: forEach callback implicitly returns a value (lines 107, 150).

Set.add() returns the Set itself, so the arrow in .forEach((s) => placedIds.add(s.id)) implicitly returns a value. Biome flags this as suspicious. Use a block body to suppress the lint error.

🔧 Proposed fix
-      levelSteps.forEach((s) => placedIds.add(s.id))
+      levelSteps.forEach((s) => { placedIds.add(s.id) })

Apply the same fix at line 150:

-      levelSteps.forEach((s) => loopPlacedIds.add(s.id))
+      levelSteps.forEach((s) => { loopPlacedIds.add(s.id) })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function processLevel(levelSteps: TreeStepBlock[]): void {
blocks.push(levelSteps)
levelSteps.forEach((s) => placedIds.add(s.id))
const nextIds = levelSteps.flatMap((s) => sourceToTargets.get(s.id) ?? [])
const uniqueNextIds = [...new Set(nextIds)].filter(
(id) => !placedIds.has(id)
)
const nextSteps = uniqueNextIds
.map((id) => steps.find((s) => s.id === id))
.filter((s): s is TreeStepBlock => s != null)
if (nextSteps.length > 0) processLevel(nextSteps)
}
function processLevel(levelSteps: TreeStepBlock[]): void {
blocks.push(levelSteps)
levelSteps.forEach((s) => { placedIds.add(s.id) })
const nextIds = levelSteps.flatMap((s) => sourceToTargets.get(s.id) ?? [])
const uniqueNextIds = [...new Set(nextIds)].filter(
(id) => !placedIds.has(id)
)
const nextSteps = uniqueNextIds
.map((id) => steps.find((s) => s.id === id))
.filter((s): s is TreeStepBlock => s != null)
if (nextSteps.length > 0) processLevel(nextSteps)
}
🧰 Tools
🪛 Biome (2.3.14)

[error] 107-107: This callback passed to forEach() iterable method should not return a value.

Either remove this return or remove the returned value.

(lint/suspicious/useIterableCallbackReturn)

🤖 Prompt for AI Agents
In
`@apps/journeys-admin/src/components/Editor/Slider/JourneyFlow/libs/arrangeSteps/arrangeSteps.ts`
around lines 105 - 116, The forEach arrow currently uses an expression body that
implicitly returns the Set from placedIds.add(s.id), which triggers the lint
warning; in processLevel change the callback to a block body (e.g., .forEach((s)
=> { placedIds.add(s.id); })) to suppress the implicit-return, and make the
identical change for the other forEach occurrence referenced around line 150 so
both callbacks use block bodies instead of expression bodies; locate these by
the function name processLevel and by occurrences of placedIds.add(...) in the
file.

@github-actions
Copy link
Contributor

The latest updates on your projects.

Name Status Preview Updated (UTC)
journeys-admin ✅ Ready journeys-admin preview Fri Feb 13 15:39:00 NZDT 2026

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