Skip to content

feat: lock navigation while regenerating QWC file#1767

Open
JustARatherRidiculouslyLongUsername wants to merge 2 commits intoqwc-regen-handle-redirectionfrom
qwc-regen-lockdown
Open

feat: lock navigation while regenerating QWC file#1767
JustARatherRidiculouslyLongUsername wants to merge 2 commits intoqwc-regen-handle-redirectionfrom
qwc-regen-lockdown

Conversation

@JustARatherRidiculouslyLongUsername
Copy link
Contributor

@JustARatherRidiculouslyLongUsername JustARatherRidiculouslyLongUsername commented Feb 26, 2026

Description

localhost_4200_integrations_ (1)

Clickup

https://app.clickup.com/t/86d1xy7uw

Summary by CodeRabbit

  • New Features
    • QWC file regeneration can be enabled/disabled per branding environment.
    • Navigation is now locked during critical QWC regeneration steps to prevent accidental leaving.
  • Bug Fixes / UX
    • Menu and sub-menu tabs become non-interactive while navigation is locked, preserving in-progress workflows.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8504be2 and adeca9d.

📒 Files selected for processing (1)
  • src/app/integrations/qbd-direct/qbd-direct-main/qbd-direct-configuration/qbd-direct-configuration.component.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/integrations/qbd-direct/qbd-direct-main/qbd-direct-configuration/qbd-direct-configuration.component.ts

Walkthrough

Adds an allowQwcRegeneration flag to branding configs and FeatureConfiguration, introduces a root-scoped NavigationLockService, and integrates navigation locking and gating for QWC regeneration across QBD Direct components and menu templates.

Changes

Cohort / File(s) Summary
Configuration Models
src/app/branding/c1/branding-config.ts, src/app/branding/fyle/branding-config.ts, src/app/core/models/branding/feature-configuration.model.ts
Added allowQwcRegeneration: boolean to qbdDirect configuration; set to false for c1 and true for fyle; model type updated to include the field.
Navigation Lock Service
src/app/core/services/common/navigation-lock.service.ts
New injectable service (providedIn: 'root') exposing isLocked signal and lock() / unlock() methods.
QBD Direct Integration
src/app/integrations/qbd-direct/qbd-direct.component.ts, src/app/integrations/qbd-direct/qbd-direct-configuration/qbd-direct-configuration.component.ts
Gates QWC regeneration behind allowQwcRegeneration; injects NavigationLockService, locks navigation when entering regeneration flow; onboarding-state routing map extended.
Regenerate QWC Component
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-qwc-file/qbd-direct-regenerate-qwc-file/qbd-direct-regenerate-qwc-file.component.ts
Injected NavigationLockService and added lock/unlock calls around flow transitions (prerequisites, download, back/navigation, connection status) to prevent navigation during critical steps.
Menu Components & Templates
src/app/shared/components/menu/main-menu/main-menu.component.ts, src/app/shared/components/menu/main-menu/main-menu.component.html, src/app/shared/components/menu/sub-menu/sub-menu.component.ts, src/app/shared/components/menu/sub-menu/sub-menu.component.html
Injected NavigationLockService into menu components and added [disabled]="navigationLockService.isLocked()" bindings on tabs; simplified main-menu showMoreDropdown initialization.

Sequence Diagram

sequenceDiagram
  participant User
  participant Menu as Main Menu
  participant QBD as QBD Direct Component
  participant Regen as Regenerate QWC Component
  participant Nav as Navigation Lock Service

  User->>Menu: open menu / click QBD
  Menu->>QBD: check allowQwcRegeneration
  QBD->>Nav: lock()
  QBD->>Regen: navigate to regeneration flow
  Regen->>Regen: perform prerequisites / download / setup
  Regen->>Nav: lock() / unlock() around critical transitions
  Regen->>Nav: unlock() when CONNECTION_DONE or terminal state
  Nav->>Menu: isLocked signal updates
  Menu->>User: tabs enabled/disabled based on isLocked
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hop the flow and hold the gate,
A quiet lock to guard the state,
QWC dreams bloom without a fret,
Until the dance is finished—then I let,
The world roam free, the file set. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is largely incomplete. While it includes a screenshot and ClickUp link as required, the Description section lacks substantive details explaining the changes, objectives, or implementation approach. Add detailed explanation of what the PR does (e.g., the navigation locking mechanism, why it's needed, affected flows) and any relevant implementation details beyond just the screenshot.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: implementing navigation locking during QWC file regeneration, which aligns with the core changes across multiple components.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch qwc-regen-lockdown

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.

@github-actions github-actions bot added the size/M Medium PR label Feb 26, 2026
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: 3

Caution

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

⚠️ Outside diff range comments (2)
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-qwc-file/qbd-direct-regenerate-qwc-file/qbd-direct-regenerate-qwc-file.component.ts (1)

282-290: ⚠️ Potential issue | 🟠 Major

Unlock navigation on the DESTINATION_SYNC_COMPLETE error path too.

At Line 286, catchError returns without calling unlockNavigation(). If this update fails, the user can remain permanently locked from menu navigation.

🔧 Proposed fix
-import { catchError, interval, map, Observable, of, switchMap, takeWhile, tap } from 'rxjs';
+import { catchError, finalize, interval, map, Observable, of, switchMap, takeWhile, tap } from 'rxjs';
@@
     } else if (state === QbdDirectOnboardingState.DESTINATION_SYNC_COMPLETE) {
       return this.workspaceService.updateWorkspaceOnboardingState({
         onboarding_state: QbdDirectOnboardingState.COMPLETE
       }).pipe(
         tap(() => {
           this.state.set(QwcFlowState.CONNECTION_DONE);
-          this.unlockNavigation();
         }),
         catchError((error) => {
           console.error('Error updating workspace onboarding state:', error);
           this.toastService.displayToastMessage(ToastSeverity.ERROR, this.translocoService.translate('qbdDirectRegenerateQwcFile.somethingWentWrong'));
           return of(null);
         }),
+        finalize(() => this.unlockNavigation()),
         map(() => null)
       );
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-qwc-file/qbd-direct-regenerate-qwc-file/qbd-direct-regenerate-qwc-file.component.ts`
around lines 282 - 290, The catchError inside the observable leaves navigation
locked when updating the workspace onboarding state fails; modify the catchError
handler in qbd-direct-regenerate-qwc-file.component (the block handling
state.set(QwcFlowState.CONNECTION_DONE)) to call this.unlockNavigation() before
returning of(null) and after showing the toast (ensure unlockNavigation() is
invoked regardless of success or error), so the unlockNavigation() function is
executed on the DESTINATION_SYNC_COMPLETE/error path as well.
src/app/integrations/qbd-direct/qbd-direct.component.ts (1)

68-85: ⚠️ Potential issue | 🟠 Major

Navigation lock can leak across flows without an explicit reset path.

This method locks navigation on the regeneration branch (Line 75), but there is no corresponding unlock in the non-regeneration branches of navigate(). A stale locked state can keep menus disabled outside the regen flow.

Suggested fix
 private navigate(): void {
+  // Reset lock when entering root routing decision tree.
+  this.navigationLockService.unlock();
+
   const pathName = this.windowReference.location.pathname;
   const connectionStates = [
@@
     if (brandingFeatureConfig.qbdDirect.allowQwcRegeneration && connectionStates.includes(this.workspace.onboarding_state)) {
@@
           this.router.navigateByUrl(`/integrations/qbd_direct/main/configuration/qwc_file/${flowRoute}`);
           this.navigationLockService.lock();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/integrations/qbd-direct/qbd-direct.component.ts` around lines 68 -
85, The navigationLockService.lock() call in the regeneration branch can leak
because other branches (the onboarding navigation and early returns) never call
unlock; update navigate() so every execution path that previously returned or
navigated without unlocking now calls navigationLockService.unlock() where
appropriate (e.g., in the error callback of
qbdDirectAdvancedSettingsService.getQbdAdvancedSettings().subscribe and before
any return when the lock might have been set), or refactor the async subscribe
call to use a finally-like handler (or RxJS finalize) to ensure
navigationLockService.unlock() runs after navigation logic; reference
qbdDirectAdvancedSettingsService.getQbdAdvancedSettings().subscribe,
navigationLockService.lock(), navigationLockService.unlock(), and the navigate()
method to locate and implement the change.
🧹 Nitpick comments (1)
src/app/integrations/qbd-direct/qbd-direct-main/qbd-direct-configuration/qbd-direct-configuration.component.ts (1)

33-36: Use guideline-compliant i18n key naming for the new QWC tab label.

Line 35 adds qbd_direct.configuration.QWCFile.stepName, which doesn't match the component i18n schema in the current guidelines. Please align this new key with the component-scoped camelCase format.

🔧 Proposed key update (example)
-        {label: this.translocoService.translate('qbd_direct.configuration.QWCFile.stepName'), routerLink: '/integrations/qbd_direct/main/configuration/qwc_file', value: 'qwc_file'}
+        {label: this.translocoService.translate('qbdDirectConfiguration.qwcFileStepName'), routerLink: '/integrations/qbd_direct/main/configuration/qwc_file', value: 'qwc_file'}

As per coding guidelines: **/*.component.{ts,html} top-level i18n object must be component/feature folder name in camelCase, and keys should be meaningful/semantic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/integrations/qbd-direct/qbd-direct-main/qbd-direct-configuration/qbd-direct-configuration.component.ts`
around lines 33 - 36, The i18n key used in the translocoService.translate call
when pushing the QWC tab is not following the component-scoped camelCase schema;
update the key passed to translocoService.translate inside the modules.push call
in qbd-direct-configuration.component (the line using
this.translocoService.translate('qbd_direct.configuration.QWCFile.stepName')) to
a component/feature folder camelCase root (e.g., qwcFile.stepName or
qbdDirectQwcFile.stepName) and add the corresponding entry to the component’s
i18n object so the label follows the required component-scoped camelCase naming
convention.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-qwc-file/qbd-direct-regenerate-qwc-file/qbd-direct-regenerate-qwc-file.component.ts`:
- Around line 120-127: The component sets a global navigation lock in
lockNavigation() but never releases it; add an Angular lifecycle teardown to
call unlockNavigation() when the component is destroyed (implement ngOnDestroy()
in the qbd-direct-regenerate-qwc-file.component class and invoke
this.unlockNavigation()), ensuring the global lock (navigationLockService) is
always unlocked on component destruction; also consider clearing the
qbdDirectQwcLastVisitedFlowService value if appropriate inside the same
ngOnDestroy to avoid stale state.

In `@src/app/integrations/qbd-direct/qbd-direct.component.ts`:
- Line 103: The navigation call using
onboardingStateComponentMap[this.workspace.onboarding_state] can produce
undefined and break routing; update the code around router.navigateByUrl in
qbd-direct.component (the line calling this.router.navigateByUrl(...)) to
resolve a safe fallback: compute a target =
onboardingStateComponentMap[this.workspace.onboarding_state] || '<defaultRoute>'
(choose the appropriate default route string used by your app) and call
this.router.navigateByUrl(target) instead, ensuring you reference
onboardingStateComponentMap and this.workspace.onboarding_state when
implementing the guard so unexpected backend values route to the default.

In `@src/app/shared/components/menu/main-menu/main-menu.component.ts`:
- Line 80: The dropdown visibility was changed to rely solely on
brandingFeatureConfig.showMoreDropdownInMainMenu, removing the iframe-origin
guard; restore that guard so the “More” menu remains hidden in embedded/iframe
contexts by combining the two checks (e.g. set showMoreDropdown =
brandingFeatureConfig.showMoreDropdownInMainMenu && !isEmbeddedIframe() or &&
window.self === window.top), or call your existing iframe-detection helper if
present; update the assignment of showMoreDropdown in main-menu.component.ts
accordingly so both the branding flag and iframe context are respected.

---

Outside diff comments:
In
`@src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-qwc-file/qbd-direct-regenerate-qwc-file/qbd-direct-regenerate-qwc-file.component.ts`:
- Around line 282-290: The catchError inside the observable leaves navigation
locked when updating the workspace onboarding state fails; modify the catchError
handler in qbd-direct-regenerate-qwc-file.component (the block handling
state.set(QwcFlowState.CONNECTION_DONE)) to call this.unlockNavigation() before
returning of(null) and after showing the toast (ensure unlockNavigation() is
invoked regardless of success or error), so the unlockNavigation() function is
executed on the DESTINATION_SYNC_COMPLETE/error path as well.

In `@src/app/integrations/qbd-direct/qbd-direct.component.ts`:
- Around line 68-85: The navigationLockService.lock() call in the regeneration
branch can leak because other branches (the onboarding navigation and early
returns) never call unlock; update navigate() so every execution path that
previously returned or navigated without unlocking now calls
navigationLockService.unlock() where appropriate (e.g., in the error callback of
qbdDirectAdvancedSettingsService.getQbdAdvancedSettings().subscribe and before
any return when the lock might have been set), or refactor the async subscribe
call to use a finally-like handler (or RxJS finalize) to ensure
navigationLockService.unlock() runs after navigation logic; reference
qbdDirectAdvancedSettingsService.getQbdAdvancedSettings().subscribe,
navigationLockService.lock(), navigationLockService.unlock(), and the navigate()
method to locate and implement the change.

---

Nitpick comments:
In
`@src/app/integrations/qbd-direct/qbd-direct-main/qbd-direct-configuration/qbd-direct-configuration.component.ts`:
- Around line 33-36: The i18n key used in the translocoService.translate call
when pushing the QWC tab is not following the component-scoped camelCase schema;
update the key passed to translocoService.translate inside the modules.push call
in qbd-direct-configuration.component (the line using
this.translocoService.translate('qbd_direct.configuration.QWCFile.stepName')) to
a component/feature folder camelCase root (e.g., qwcFile.stepName or
qbdDirectQwcFile.stepName) and add the corresponding entry to the component’s
i18n object so the label follows the required component-scoped camelCase naming
convention.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ab9f385 and 8504be2.

📒 Files selected for processing (11)
  • src/app/branding/c1/branding-config.ts
  • src/app/branding/fyle/branding-config.ts
  • src/app/core/models/branding/feature-configuration.model.ts
  • src/app/core/services/common/navigation-lock.service.ts
  • src/app/integrations/qbd-direct/qbd-direct-main/qbd-direct-configuration/qbd-direct-configuration.component.ts
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-qwc-file/qbd-direct-regenerate-qwc-file/qbd-direct-regenerate-qwc-file.component.ts
  • src/app/integrations/qbd-direct/qbd-direct.component.ts
  • src/app/shared/components/menu/main-menu/main-menu.component.html
  • src/app/shared/components/menu/main-menu/main-menu.component.ts
  • src/app/shared/components/menu/sub-menu/sub-menu.component.html
  • src/app/shared/components/menu/sub-menu/sub-menu.component.ts

Comment on lines +120 to +127
private lockNavigation(): void {
this.qbdDirectQwcLastVisitedFlowService.set(this.flowType);
this.navigationLockService.lock();
}

private unlockNavigation(): void {
this.navigationLockService.unlock();
}
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 | 🟠 Major

Release the global navigation lock when this component is destroyed.

Line 120 introduces a global lock path, but there is no teardown unlock. If users leave via browser back/direct URL, isLocked can remain true and keep menus disabled app-wide.

🔧 Proposed fix
-import { Component, computed, OnInit, signal } from '@angular/core';
+import { Component, computed, OnDestroy, OnInit, signal } from '@angular/core';
@@
-export class QbdDirectRegenerateQwcFileComponent implements OnInit {
+export class QbdDirectRegenerateQwcFileComponent implements OnInit, OnDestroy {
@@
   ngOnInit(): void {
@@
   }
+
+  ngOnDestroy(): void {
+    this.unlockNavigation();
+  }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-qwc-file/qbd-direct-regenerate-qwc-file/qbd-direct-regenerate-qwc-file.component.ts`
around lines 120 - 127, The component sets a global navigation lock in
lockNavigation() but never releases it; add an Angular lifecycle teardown to
call unlockNavigation() when the component is destroyed (implement ngOnDestroy()
in the qbd-direct-regenerate-qwc-file.component class and invoke
this.unlockNavigation()), ensuring the global lock (navigationLockService) is
always unlocked on component destruction; also consider clearing the
qbdDirectQwcLastVisitedFlowService value if appropriate inside the same
ngOnDestroy to avoid stale state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M Medium PR

Development

Successfully merging this pull request may close these issues.

1 participant