Skip to content

Comments

feat: QWC file regeneration - new file path flow#1762

Open
JustARatherRidiculouslyLongUsername wants to merge 1 commit intoqwc-regen-prerequisitesfrom
qwc-regen-new-path-flow
Open

feat: QWC file regeneration - new file path flow#1762
JustARatherRidiculouslyLongUsername wants to merge 1 commit intoqwc-regen-prerequisitesfrom
qwc-regen-new-path-flow

Conversation

@JustARatherRidiculouslyLongUsername
Copy link
Contributor

@JustARatherRidiculouslyLongUsername JustARatherRidiculouslyLongUsername commented Feb 23, 2026

Description

localhost_4200_integrations_qbd_direct_main_configuration_qwc_file (5) localhost_4200_integrations_qbd_direct_main_configuration_qwc_file (6) localhost_4200_integrations_qbd_direct_main_configuration_qwc_file (7) localhost_4200_integrations_qbd_direct_main_configuration_qwc_file_new

Clickup

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

Summary by CodeRabbit

Release Notes

  • New Features

    • Added company name mismatch detection during QuickBooks Desktop setup.
    • Enhanced QWC file regeneration workflow with improved download and connection setup steps.
    • Introduced new help articles for QuickBooks Desktop integration guidance.
    • Added XML file download utility support.
  • Documentation

    • Expanded user-facing messaging for onboarding steps and error scenarios.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 23, 2026

Walkthrough

This PR introduces QuickBooks Direct (QBD_DIRECT) regeneration flow support with new branding KB article links, a new onboarding state (COMPANY_NAME_MISMATCH), QWC workflow states, and a substantial refactor of the regenerate QWC component to implement a signal-based multi-step wizard with async download and connection handling.

Changes

Cohort / File(s) Summary
Branding Configuration
src/app/branding/c1/branding-config.ts, src/app/branding/fyle/branding-config.ts
Added QBD_DIRECT block under postOnboardingArticles.SAGE50 with five new KB article keys (REGENERATE_QWC_FILE_LANDING_HEADER, TEAM_ACCESS_QWC_NOT_RECOMMENDED, REGENERATE_QWC_FILE_EXISTING_PATH_WARNING, REGENERATE_QWC_FILE_NEW_PATH_HEADER, REGENERATE_QWC_FILE_NEW_PATH_WARNING) pointing to QuickBooks Desktop integration article URLs.
Type System & Models
src/app/core/models/branding/kb-article.model.ts, src/app/core/models/enum/enum.model.ts, src/app/core/models/qbd-direct/qbd-direct-configuration/qbd-direct-qwc-file.model.ts, src/app/core/models/qbd-direct/qbd-direct-configuration/qbd-direct-onboarding.model.ts
Extended KbArticle type with QBD_DIRECT object; added COMPANY_NAME_MISMATCH enum state; introduced QwcFlowState enum (PREREQUISITES, DOWNLOAD, DOWNLOAD_IN_PROGRESS, DOWNLOAD_DONE, SETUP_CONNECTION, CONNECTION_IN_PROGRESS, CONNECTION_DONE); simplified QbdOnboardingStepperMap to generic Record type.
CSV Import Generic Infrastructure
src/app/core/models/db/csv-import-attributes.model.ts, src/app/core/services/sage50/sage50-configuration/sage50-import-attributes.service.ts, src/app/shared/components/configuration/configuration-csv-import-field/configuration-csv-import-field.component.ts, src/app/shared/components/configuration/configuration-csv-upload-field/configuration-csv-upload-field.component.ts, src/app/shared/components/dialog/csv-upload-dialog/csv-upload-dialog.component.ts
Replaced union-based attribute types with centralized map-based generic system: added CSVImportAttributeTypeMap, CSVAppName, and CSVImportAttributeTypeForApp types; parameterized CSV service and component classes with generics; updated data shapes to use generic types.
QBD Direct Onboarding Service & Routing
src/app/core/services/qbd-direct/qbd-direct-configuration/qbd-direct-onboarding.service.ts, src/app/integrations/qbd-direct/qbd-direct.component.ts
Mapped COMPANY_NAME_MISMATCH onboarding state to step index 2; added explicit type annotation and routing for new state to '/integrations/qbd_direct/main'.
QBD Direct Configuration Step Header
src/app/shared/components/configuration/configuration-step-header/configuration-step-header.component.ts
Made redirectLink input optional (string → string?).
QBD Direct QWC File Landing
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-qwc-file/qbd-direct-qwc-file-landing/qbd-direct-qwc-file-landing.component.html, src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-qwc-file/qbd-direct-qwc-file-landing/qbd-direct-qwc-file-landing.component.ts
Replaced single redirectLink property with two new properties: headerRedirectLink and teamAccessNotRecommendedRedirectLink; updated template bindings accordingly.
QBD Direct Regenerate QWC File Component
src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-qwc-file/qbd-direct-regenerate-qwc-file/qbd-direct-regenerate-qwc-file.component.html, src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-qwc-file/qbd-direct-regenerate-qwc-file/qbd-direct-regenerate-qwc-file.component.ts
Major refactor: replaced static prerequisites with state-driven multi-block UI including loading splash, header, download/setup subcomponents, and confirmation dialog. Introduced signal-based reactive state (state, isCompanyPathInvalid, password, xmlFileContent, isDialogVisible), computed connectionStatus, and multiple handler methods for download, connection, retry, and terminal state management with async polling and user feedback.
QBD Direct Onboarding Connector
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-connector/qbd-direct-onboarding-connector.component.ts
Changed downloaded QWC file name from fyle_quickbooks.qwc to sem_qbd_integration.qwc.
File Download Utilities
src/app/core/util/downloadFile.ts
Added blob URL cleanup (revokeObjectURL); introduced new downloadXMLFile(content, fileName) export for XML downloads.
Internationalization
src/assets/i18n/en.json
Added qbdDirectRegenerateQwcFile namespace with 10 new translation keys including headerTitleExistingPath, headerTitleNewPath, downloadError, connectionError, incorrectPasswordMessage, incorrectCompanyPathMessage, companyNameMismatchMessage, and connectionSuccessToast.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Component as QBD Regenerate<br/>QWC Component
    participant Service as QBD Direct<br/>Connector Service
    participant Backend as Backend API
    participant Workspace as Workspace Service
    participant Storage as Storage Service
    
    User->>Component: Click Download QWC
    Component->>Service: handleDownloadClick(filePath)
    Service->>Backend: Request QWC file & password
    Backend-->>Service: Return XML content & password
    Service-->>Component: Success (set state, content, password)
    Component->>Storage: Store xmlFileContent & password
    Component->>Component: Advance to DOWNLOAD_DONE state
    
    User->>Component: Manual Download or Next Step
    Component->>Component: handleManualDownload() / handleDownloadNextStepClick()
    Component->>Component: Trigger XML file download
    Component->>Component: Advance to SETUP_CONNECTION state
    
    User->>Component: Connection established
    Component->>Component: handleConnectionDone(event)
    Component->>Workspace: Poll workspace status (interval/switchMap)
    Workspace-->>Component: Connection status updates
    Component->>Component: Check isTerminalStatus()
    
    alt Terminal State Reached
        Component->>Component: handleStatus(state)
        Component->>Component: Show warning/success dialog
        Component->>Component: Update onboarding state
        Component->>Component: Navigate to DONE or error state
    else Poll Continues
        Workspace-->>Component: Continue polling
    end
    
    User->>Component: Confirm or Close Dialog
    Component->>Component: handleConnectionNext() / closeDialog()
    Component->>Component: Navigate to dashboard
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~70 minutes

Poem

🐰 Hop, hop, hooray! The QWC flows so bright,
With signals and states, we've made the refactor right,
From PREREQUISITES to DONE, the wizard takes flight,
New generics unite the CSV apps with delight,
And regenerate files dance in the moonlight! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The PR description provides visual context with four screenshots showing the implemented UI flow, but lacks written explanation of the changes, technical details, and the structured information required by the repository template (Description and ClickUp sections are incomplete). Add a written description explaining the key changes (component refactor to signals/computed pattern, new branding article keys, enum expansion), the business purpose, and testing notes alongside the screenshots.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: implementing QWC file regeneration functionality with a new file path flow, which aligns with the substantial refactoring of the QWC regeneration component and related configuration changes throughout the codebase.
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-new-path-flow

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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.

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: 9

🧹 Nitpick comments (9)
src/app/core/models/qbd-direct/qbd-direct-configuration/qbd-direct-qwc-file.model.ts (1)

12-19: Consider using string values for consistency with QwcRegenerationFlowType.

QwcFlowState uses implicit numeric values while the co-located QwcRegenerationFlowType uses explicit string values. String enums produce more readable log output and eliminate potential issues with numeric comparisons if the enum order ever shifts.

♻️ Proposed refactor
 export enum QwcFlowState {
-  PREREQUISITES,
-  DOWNLOAD,
-  DOWNLOAD_IN_PROGRESS,
-  DOWNLOAD_DONE,
-  SETUP_CONNECTION,
-  CONNECTION_IN_PROGRESS,
-  CONNECTION_DONE
+  PREREQUISITES = 'PREREQUISITES',
+  DOWNLOAD = 'DOWNLOAD',
+  DOWNLOAD_IN_PROGRESS = 'DOWNLOAD_IN_PROGRESS',
+  DOWNLOAD_DONE = 'DOWNLOAD_DONE',
+  SETUP_CONNECTION = 'SETUP_CONNECTION',
+  CONNECTION_IN_PROGRESS = 'CONNECTION_IN_PROGRESS',
+  CONNECTION_DONE = 'CONNECTION_DONE'
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/core/models/qbd-direct/qbd-direct-configuration/qbd-direct-qwc-file.model.ts`
around lines 12 - 19, QwcFlowState currently uses implicit numeric enum members
while the neighboring QwcRegenerationFlowType uses string values; change
QwcFlowState to an explicit string enum by assigning each member its name as a
string (e.g., PREREQUISITES = "PREREQUISITES", DOWNLOAD = "DOWNLOAD", etc.) so
logs and comparisons are readable and stable, and then search for any runtime
code that compares against numeric values of QwcFlowState (in switches, equality
checks, or persisted data) and update those to compare against the new string
values or the enum members (e.g., QwcFlowState.PREREQUISITES) to ensure behavior
remains correct.
src/app/core/util/downloadFile.ts (1)

16-18: LGTM — consistent with existing downloadCSVFile pattern.

The new downloadXMLFile utility is clean. Note that qbd-direct-onboarding-connector.component.ts (triggerManualDownload, lines 111-120) duplicates this logic manually instead of reusing this utility. Consider refactoring that method to use downloadXMLFile for consistency.

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

In `@src/app/core/util/downloadFile.ts` around lines 16 - 18, Duplicate
XML-download logic exists: refactor
qbd-direct-onboarding-connector.component.ts's triggerManualDownload to call the
shared utility downloadXMLFile(content, fileName) instead of reimplementing
blob/mime handling. Import downloadXMLFile, remove the manual Blob/new
URL/revokeObjectURL code in triggerManualDownload, pass the XML string and
desired filename to downloadXMLFile, and ensure any related type/signature
differences are adjusted (e.g., content as string and fileName variable) so
behavior remains identical.
src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-connector/qbd-direct-onboarding-connector.component.ts (2)

155-159: Pre-existing: onConnectionDone polling uses deprecated subscribe signature and silently discards errors.

Line 159 logs errors to console but provides no user-facing feedback, unlike the regenerate component which shows a toast message. This is a pre-existing concern.

🤖 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-onboarding/qbd-direct-onboarding-connector/qbd-direct-onboarding-connector.component.ts`
around lines 155 - 159, The polling subscribe call uses the deprecated
positional signature and only logs errors to console; change it to the
object-style subscribe({ next, error }) so errors are handled properly, route
the error into the same user-facing toast mechanism used in the regenerate
component (e.g., call the component's toast/toaster service method) instead of
console.error, and ensure the error handler stops further processing; locate the
subscribe call that invokes handleStatus and isTerminalStatus (and uses
takeWhile) to make this change.

111-120: Pre-existing: triggerManualDownload creates a redundant blob URL on line 113 that is never revoked.

Line 113 creates url via createObjectURL, and line 115 creates a second objectUrl from the same blob. Only objectUrl is used and revoked; url leaks. Consider refactoring this method to use the new downloadXMLFile utility from src/app/core/util/downloadFile.ts, which would fix the leak and eliminate duplication with the regenerate component's handleManualDownload.

Proposed fix
+import { downloadXMLFile } from 'src/app/core/util/downloadFile';

  triggerManualDownload() {
-    const blob = new Blob([this.xmlFileContent], { type: 'text/xml' });
-    const url = window.URL.createObjectURL(blob);
-    const a = document.createElement('a');
-    const objectUrl = URL.createObjectURL(blob);
-    a.href = objectUrl;
-    a.download = 'sem_qbd_integration.qwc';
-    a.click();
-    URL.revokeObjectURL(objectUrl);
+    downloadXMLFile(this.xmlFileContent, 'sem_qbd_integration.qwc');
  }
🤖 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-onboarding/qbd-direct-onboarding-connector/qbd-direct-onboarding-connector.component.ts`
around lines 111 - 120, triggerManualDownload currently creates a redundant blob
URL (the local variable url) that is never used or revoked; replace the manual
blob/createObjectURL/revoke logic by importing and calling the shared
downloadXMLFile utility (same helper used by the regenerate component's
handleManualDownload), remove the unused url and the manual revoke, and ensure
the function calls downloadXMLFile passing this.xmlFileContent, the filename
'sem_qbd_integration.qwc' and MIME 'text/xml' and add the corresponding import
for downloadXMLFile.
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)

100-100: filePath parameter is typed as any — should be explicitly typed.

Use string (or string | null | undefined if needed) to take advantage of type checking and prevent accidental misuse.

Proposed fix
-  handleDownloadClick(filePath: any): void {
+  handleDownloadClick(filePath: string): void {
🤖 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`
at line 100, The handleDownloadClick parameter filePath is currently typed as
any; change its signature in qbd-direct-regenerate-qwc-file.component.ts from
handleDownloadClick(filePath: any): void to use a stricter type (e.g., filePath:
string or filePath: string | null | undefined depending on whether
null/undefined is possible) and update any internal null-checks or callers
accordingly so TypeScript can enforce correct usage for the handleDownloadClick
method.
src/app/branding/c1/branding-config.ts (1)

197-203: All five QBD_DIRECT post-onboarding article keys resolve to the same URL.

Is this intentional? If different sections of the article should be targeted (like the onboarding articles use #h_ anchors), consider adding distinct fragment identifiers. Otherwise, this is fine as a starting point with differentiation to follow.

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

In `@src/app/branding/c1/branding-config.ts` around lines 197 - 203, The five
QBD_DIRECT keys (REGENERATE_QWC_FILE_LANDING_HEADER,
TEAM_ACCESS_QWC_NOT_RECOMMENDED, REGENERATE_QWC_FILE_EXISTING_PATH_WARNING,
REGENERATE_QWC_FILE_NEW_PATH_HEADER, REGENERATE_QWC_FILE_NEW_PATH_WARNING) all
resolve to the same URL; update each key in branding-config.ts to point to
distinct targets by appending appropriate fragment identifiers (e.g.,
`#h_`<section>) or different article paths on brandingConfig.helpArticleDomain so
each UI section links to the correct anchor/section, or explicitly confirm and
document that a single shared URL is intentional.
src/app/shared/components/configuration/configuration-csv-upload-field/configuration-csv-upload-field.component.ts (1)

21-31: Complete the generic refactor — attributeType should also be parameterized.

The component was made generic over CSVAppName (Line 21), and appResourceKey and uploadData are correctly parameterized. However, attributeType remains hardcoded to Sage50AttributeType (Line 25), breaking the generic contract. Since CSVImportAttributeTypeForApp<A> exists and resolves the correct attribute type per app, use it here:

♻️ Suggested fix
-import { CSVAppName, CSVImportAttributesService } from 'src/app/core/models/db/csv-import-attributes.model';
+import { CSVAppName, CSVImportAttributesService, CSVImportAttributeTypeForApp } from 'src/app/core/models/db/csv-import-attributes.model';
 ...
-  `@Input`({ required: true }) attributeType!: Sage50AttributeType;
+  `@Input`({ required: true }) attributeType!: CSVImportAttributeTypeForApp<A>;

Additionally, TrackingApp.SAGE50 (Line 56) is hardcoded; parameterizing this would require a mapping from CSVAppName to TrackingApp.

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

In
`@src/app/shared/components/configuration/configuration-csv-upload-field/configuration-csv-upload-field.component.ts`
around lines 21 - 31, The component’s generic was incomplete: change the `@Input`
type of attributeType on ConfigurationCsvUploadFieldComponent to use the
app-specific type CSVImportAttributeTypeForApp<A> instead of the hardcoded
Sage50AttributeType (so attributeType becomes CSVImportAttributeTypeForApp<A>),
and update any usages that assume Sage50 types to use the generic type;
additionally remove the hardcoded TrackingApp.SAGE50 usage and replace it with a
mapping/deriver from the generic appResourceKey (e.g., a small function that
maps CSVAppName to TrackingApp) and use that mapping wherever TrackingApp.SAGE50
was referenced so the component fully respects the A generic.
src/app/shared/components/dialog/csv-upload-dialog/csv-upload-dialog.component.ts (2)

33-39: Type correlation between appResourceKey and attributeType is lost.

Unlike ConfigurationCsvImportFieldComponent<A>, this dialog uses CSVAppName directly (not a generic parameter), so attributeType resolves to the union of all apps' attribute types. This means TypeScript won't catch a mismatch where, e.g., a SAGE50 appResourceKey is paired with a non-Sage50 attribute type.

This is understandable given that DynamicDialogConfig data is inherently untyped, but worth noting as a known gap—especially if more apps are added later.

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

In
`@src/app/shared/components/dialog/csv-upload-dialog/csv-upload-dialog.component.ts`
around lines 33 - 39, The data property loses the correlation between
appResourceKey and attributeType because it uses CSVAppName directly; make the
component generic (e.g., add a type parameter A extends CSVAppName on the
component/class) and change the data shape to use that generic: attributeType:
CSVImportAttributeTypeForApp<A>, appResourceKey: A, uploadData:
CSVImportAttributesService<A>['importAttributes']; update any instantiation
sites (DynamicDialogConfig data casts) to supply the concrete A so TypeScript
can enforce matching types (see data, CSVImportAttributeTypeForApp, CSVAppName,
CSVImportAttributesService and ConfigurationCsvImportFieldComponent<A> for
reference).

162-165: Hardcoded Sage50 display-name lookup in an app-agnostic component.

Line 164 uses sage50AttributeDisplayNames[this.data.attributeType], which ties this dialog to Sage50 even though the rest of the refactor is making it app-agnostic via CSVAppName. If another app is added to CSVImportAttributeTypeMap, this lookup will produce undefined.

Consider passing displayName directly in the dialog data, or creating a per-app display-name map keyed by CSVAppName.

Proposed approach: pass displayName via dialog data
  data!: {
    attributeType: CSVImportAttributeTypeForApp<CSVAppName>,
    articleLink: string,
    videoURL: string,
    appResourceKey: CSVAppName,
-   uploadData: CSVImportAttributesService<CSVAppName>['importAttributes']
+   uploadData: CSVImportAttributesService<CSVAppName>['importAttributes'],
+   displayName: string
  };

- displayName: string;
  ...

  ngOnInit(): void {
    this.data = this.config.data;
-   this.displayName = sage50AttributeDisplayNames[this.data.attributeType];
+   this.displayName = this.data.displayName;
  }

The caller (configuration-csv-import-field) already knows the dimension display name and can pass it along.

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

In
`@src/app/shared/components/dialog/csv-upload-dialog/csv-upload-dialog.component.ts`
around lines 162 - 165, ngOnInit currently reads displayName directly from
sage50AttributeDisplayNames
(sage50AttributeDisplayNames[this.data.attributeType]) which hardcodes Sage50
into an app-agnostic dialog; change it to use a caller-provided displayName if
present (this.data.displayName) and otherwise perform a lookup from a per-app
map keyed by this.data.CSVAppName (e.g.,
CSVAttributeDisplayNames[this.data.CSVAppName]?.[this.data.attributeType]);
update callers (like configuration-csv-import-field) to pass displayName when
they know it, or add entries to CSVAttributeDisplayNames for each app and ensure
ngOnInit falls back gracefully (undefined-safe) to avoid returning the
Sage50-only value.
🤖 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/core/models/enum/enum.model.ts`:
- Line 402: The onboarding connector's isTerminalStatus method in
qbd-direct-onboarding-connector.component.ts currently omits the enum value
COMPANY_NAME_MISMATCH, which causes polling to never stop if the backend returns
that state; update isTerminalStatus to include
QbdDirectOnboardingState.COMPANY_NAME_MISMATCH in the array of terminal states
(alongside DESTINATION_SYNC_IN_PROGRESS, INCORRECT_PASSWORD,
INCORRECT_COMPANY_PATH, DESTINATION_SYNC_COMPLETE) so the method treats
COMPANY_NAME_MISMATCH as a terminal status and polling will terminate.

In
`@src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-qwc-file/qbd-direct-regenerate-qwc-file/qbd-direct-regenerate-qwc-file.component.html`:
- Around line 23-25: The QwcFlowState enum relies on implicit numeric ordering
which can break if members are reordered; update the QwcFlowState enum
declaration to assign explicit numeric values (e.g., PREREQUISITES = 0,
DOWNLOAD_IN_PROGRESS = 1, DOWNLOAD_DONE = 2, etc.) so comparisons like state()
=== QwcFlowState.DOWNLOAD_IN_PROGRESS and state() > QwcFlowState.DOWNLOAD_DONE
remain stable; ensure every enum member in QwcFlowState has an explicit integer
value preserving the intended sequence used by state().

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 194-205: The updateWorkspaceOnboardingState call in the
DESTINATION_SYNC_COMPLETE branch only logs errors to console so users get no
feedback and remain in CONNECTION_IN_PROGRESS; change the error handler on
workspaceService.updateWorkspaceOnboardingState (the subscription inside the if
branch handling QbdDirectOnboardingState.DESTINATION_SYNC_COMPLETE) to surface a
user-facing error (e.g., call your notification/toast service or set a UI error
state) and transition this.state to an error/retry flow (instead of leaving it
stuck) so the UI shows the failure and exposes a retry that re-invokes
workspaceService.updateWorkspaceOnboardingState and ultimately calls
this.state.set(QwcFlowState.CONNECTION_DONE) on success.
- Around line 48-55: The computed connectionStatus currently maps every
non-CONNECTION_DONE QwcFlowState to QBDConnectionStatus.INCORRECT_COMPANY_PATH
causing premature error UI; update the logic in connectionStatus (in
qbd-direct-regenerate-qwc-file.component.ts) to return a neutral/in-progress
value for non-terminal states (e.g., return QBDConnectionStatus.PENDING or
QBDConnectionStatus.UNKNOWN) and only map terminal states (e.g.,
QwcFlowState.CONNECTION_DONE -> QBDConnectionStatus.SUCCESS and a failure state
-> QBDConnectionStatus.INCORRECT_COMPANY_PATH) so the template sees an error
status only after a terminal failure.
- Around line 138-141: The handler handleConnectionDone currently sets
this.state.set(QwcFlowState.CONNECTION_IN_PROGRESS) unconditionally and then
only proceeds when event.value is true, leaving the component stuck when the
checkbox is unchecked; change the logic so the state transition is guarded or
the false branch is handled: either move the
this.state.set(QwcFlowState.CONNECTION_IN_PROGRESS) inside the if (event.value)
block, or add an explicit else that resets this.state to the idle/neutral state
(e.g., QwcFlowState.CONNECTION_IDLE or previousState) and aborts any started
work; ensure any user lookup (storageService.get('user')) and subsequent
processing only runs when event.value is true and that the false branch cancels
timers/polling and updates the UI state accordingly.
- Around line 138-158: The polling subscription created in handleConnectionDone
(interval(...).pipe(...).subscribe(...)) is never cleaned up; update the
component to store/teardown the subscription by adding a private destroy$ = new
Subject<void>() and piping takeUntil(this.destroy$) into the observable (before
subscribe) or capture the Subscription and unsubscribe it in ngOnDestroy; ensure
you reference handleConnectionDone, isTerminalStatus, handleStatus,
workspaceService and storageService correctly and call this.destroy$.next();
this.destroy$.complete() (or unsubscribe) in ngOnDestroy to prevent polling
after component destruction.
- Around line 129-136: The subscription to
workspaceService.updateWorkspaceOnboardingState in handleDownloadNextStepClick
currently has no error handler, so if the API fails the UI remains in
QwcFlowState.DOWNLOAD_IN_PROGRESS; update handleDownloadNextStepClick to add an
error callback to the subscribe call that resets or advances the flow (e.g., set
this.state.set(QwcFlowState.ERROR) or revert to a safe state), surface user
feedback (toast/processLogger) and optionally log the error; ensure you
reference the existing symbols: handleDownloadNextStepClick, this.state.set,
workspaceService.updateWorkspaceOnboardingState,
QwcFlowState.DOWNLOAD_IN_PROGRESS and QwcFlowState.SETUP_CONNECTION when making
the change.

In
`@src/app/shared/components/dialog/csv-upload-dialog/csv-upload-dialog.component.ts`:
- Around line 157-159: The code unsafely casts this.data.appResourceKey (a
CSVAppName) to TrackingApp inside downloadErrorLog; instead create a safe
mapping from CSVAppName → TrackingApp (e.g., a const map keyed by
CSVImportAttributeTypeMap keys) and use it to look up the TrackingApp before
calling trackingService.onClickEvent, handling a missing mapping with a safe
default or early return and a warning; alternatively change the dialog input to
accept a TrackingApp directly so downloadErrorLog uses that value; update
references in downloadErrorLog to use the mapped/trusted TrackingApp rather than
using "as" on this.data.appResourceKey.

In `@src/assets/i18n/en.json`:
- Around line 2783-2796: Reorder the child keys inside the
qbdDirectRegenerateQwcFile object so they are alphabetically sorted as required
by the i18n guideline: companyNameMismatchMessage, connectionError,
connectionFailed, connectionSuccessToast, downloadError, gotIt,
headerSubTitleExistingPath, headerSubTitleNewPath, headerTitleExistingPath,
headerTitleNewPath, incorrectCompanyPathMessage, incorrectPasswordMessage;
locate the qbdDirectRegenerateQwcFile block in src/assets/i18n/en.json and
rearrange the existing key/value pairs accordingly without changing any string
values.

---

Nitpick comments:
In `@src/app/branding/c1/branding-config.ts`:
- Around line 197-203: The five QBD_DIRECT keys
(REGENERATE_QWC_FILE_LANDING_HEADER, TEAM_ACCESS_QWC_NOT_RECOMMENDED,
REGENERATE_QWC_FILE_EXISTING_PATH_WARNING, REGENERATE_QWC_FILE_NEW_PATH_HEADER,
REGENERATE_QWC_FILE_NEW_PATH_WARNING) all resolve to the same URL; update each
key in branding-config.ts to point to distinct targets by appending appropriate
fragment identifiers (e.g., `#h_`<section>) or different article paths on
brandingConfig.helpArticleDomain so each UI section links to the correct
anchor/section, or explicitly confirm and document that a single shared URL is
intentional.

In
`@src/app/core/models/qbd-direct/qbd-direct-configuration/qbd-direct-qwc-file.model.ts`:
- Around line 12-19: QwcFlowState currently uses implicit numeric enum members
while the neighboring QwcRegenerationFlowType uses string values; change
QwcFlowState to an explicit string enum by assigning each member its name as a
string (e.g., PREREQUISITES = "PREREQUISITES", DOWNLOAD = "DOWNLOAD", etc.) so
logs and comparisons are readable and stable, and then search for any runtime
code that compares against numeric values of QwcFlowState (in switches, equality
checks, or persisted data) and update those to compare against the new string
values or the enum members (e.g., QwcFlowState.PREREQUISITES) to ensure behavior
remains correct.

In `@src/app/core/util/downloadFile.ts`:
- Around line 16-18: Duplicate XML-download logic exists: refactor
qbd-direct-onboarding-connector.component.ts's triggerManualDownload to call the
shared utility downloadXMLFile(content, fileName) instead of reimplementing
blob/mime handling. Import downloadXMLFile, remove the manual Blob/new
URL/revokeObjectURL code in triggerManualDownload, pass the XML string and
desired filename to downloadXMLFile, and ensure any related type/signature
differences are adjusted (e.g., content as string and fileName variable) so
behavior remains identical.

In
`@src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-connector/qbd-direct-onboarding-connector.component.ts`:
- Around line 155-159: The polling subscribe call uses the deprecated positional
signature and only logs errors to console; change it to the object-style
subscribe({ next, error }) so errors are handled properly, route the error into
the same user-facing toast mechanism used in the regenerate component (e.g.,
call the component's toast/toaster service method) instead of console.error, and
ensure the error handler stops further processing; locate the subscribe call
that invokes handleStatus and isTerminalStatus (and uses takeWhile) to make this
change.
- Around line 111-120: triggerManualDownload currently creates a redundant blob
URL (the local variable url) that is never used or revoked; replace the manual
blob/createObjectURL/revoke logic by importing and calling the shared
downloadXMLFile utility (same helper used by the regenerate component's
handleManualDownload), remove the unused url and the manual revoke, and ensure
the function calls downloadXMLFile passing this.xmlFileContent, the filename
'sem_qbd_integration.qwc' and MIME 'text/xml' and add the corresponding import
for downloadXMLFile.

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`:
- Line 100: The handleDownloadClick parameter filePath is currently typed as
any; change its signature in qbd-direct-regenerate-qwc-file.component.ts from
handleDownloadClick(filePath: any): void to use a stricter type (e.g., filePath:
string or filePath: string | null | undefined depending on whether
null/undefined is possible) and update any internal null-checks or callers
accordingly so TypeScript can enforce correct usage for the handleDownloadClick
method.

In
`@src/app/shared/components/configuration/configuration-csv-upload-field/configuration-csv-upload-field.component.ts`:
- Around line 21-31: The component’s generic was incomplete: change the `@Input`
type of attributeType on ConfigurationCsvUploadFieldComponent to use the
app-specific type CSVImportAttributeTypeForApp<A> instead of the hardcoded
Sage50AttributeType (so attributeType becomes CSVImportAttributeTypeForApp<A>),
and update any usages that assume Sage50 types to use the generic type;
additionally remove the hardcoded TrackingApp.SAGE50 usage and replace it with a
mapping/deriver from the generic appResourceKey (e.g., a small function that
maps CSVAppName to TrackingApp) and use that mapping wherever TrackingApp.SAGE50
was referenced so the component fully respects the A generic.

In
`@src/app/shared/components/dialog/csv-upload-dialog/csv-upload-dialog.component.ts`:
- Around line 33-39: The data property loses the correlation between
appResourceKey and attributeType because it uses CSVAppName directly; make the
component generic (e.g., add a type parameter A extends CSVAppName on the
component/class) and change the data shape to use that generic: attributeType:
CSVImportAttributeTypeForApp<A>, appResourceKey: A, uploadData:
CSVImportAttributesService<A>['importAttributes']; update any instantiation
sites (DynamicDialogConfig data casts) to supply the concrete A so TypeScript
can enforce matching types (see data, CSVImportAttributeTypeForApp, CSVAppName,
CSVImportAttributesService and ConfigurationCsvImportFieldComponent<A> for
reference).
- Around line 162-165: ngOnInit currently reads displayName directly from
sage50AttributeDisplayNames
(sage50AttributeDisplayNames[this.data.attributeType]) which hardcodes Sage50
into an app-agnostic dialog; change it to use a caller-provided displayName if
present (this.data.displayName) and otherwise perform a lookup from a per-app
map keyed by this.data.CSVAppName (e.g.,
CSVAttributeDisplayNames[this.data.CSVAppName]?.[this.data.attributeType]);
update callers (like configuration-csv-import-field) to pass displayName when
they know it, or add entries to CSVAttributeDisplayNames for each app and ensure
ngOnInit falls back gracefully (undefined-safe) to avoid returning the
Sage50-only value.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ec56fc2 and 1f43e21.

📒 Files selected for processing (21)
  • src/app/branding/c1/branding-config.ts
  • src/app/branding/fyle/branding-config.ts
  • src/app/core/models/branding/kb-article.model.ts
  • src/app/core/models/db/csv-import-attributes.model.ts
  • src/app/core/models/enum/enum.model.ts
  • src/app/core/models/qbd-direct/qbd-direct-configuration/qbd-direct-onboarding.model.ts
  • src/app/core/models/qbd-direct/qbd-direct-configuration/qbd-direct-qwc-file.model.ts
  • src/app/core/services/qbd-direct/qbd-direct-configuration/qbd-direct-onboarding.service.ts
  • src/app/core/services/sage50/sage50-configuration/sage50-import-attributes.service.ts
  • src/app/core/util/downloadFile.ts
  • src/app/integrations/qbd-direct/qbd-direct-onboarding/qbd-direct-onboarding-connector/qbd-direct-onboarding-connector.component.ts
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-qwc-file/qbd-direct-qwc-file-landing/qbd-direct-qwc-file-landing.component.html
  • src/app/integrations/qbd-direct/qbd-direct-shared/qbd-direct-qwc-file/qbd-direct-qwc-file-landing/qbd-direct-qwc-file-landing.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.html
  • 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/configuration/configuration-csv-import-field/configuration-csv-import-field.component.ts
  • src/app/shared/components/configuration/configuration-csv-upload-field/configuration-csv-upload-field.component.ts
  • src/app/shared/components/configuration/configuration-step-header/configuration-step-header.component.ts
  • src/app/shared/components/dialog/csv-upload-dialog/csv-upload-dialog.component.ts
  • src/assets/i18n/en.json

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

Labels

size/L Large PR

Development

Successfully merging this pull request may close these issues.

2 participants