Skip to content

fix: sonar resolve fe frontline pipeline components config components#7238

Open
JustTuruu wants to merge 18 commits intomainfrom
sonar_resolve_fe_frontline_pipeline_components_config_components
Open

fix: sonar resolve fe frontline pipeline components config components#7238
JustTuruu wants to merge 18 commits intomainfrom
sonar_resolve_fe_frontline_pipeline_components_config_components

Conversation

@JustTuruu
Copy link
Collaborator

@JustTuruu JustTuruu commented Mar 20, 2026

Summary by CodeRabbit

  • Bug Fixes

    • Improved error handling to provide meaningful error messages when retrieving access tokens
    • Fixed logging message formatting for better debugging clarity
  • Refactor

    • Enhanced type safety by adding readonly modifiers to component props and interface properties
    • Replaced regex-based string replacement methods with modern alternatives for improved readability
    • Simplified conditional logic using nullish coalescing and direct membership checks
    • Improved loop control flow in data classification operations
  • Style

    • Consolidated and reorganized import statements for better code organization
    • Adjusted code formatting and indentation throughout multiple components

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Sorry @JustTuruu, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai
Copy link

coderabbitai bot commented Mar 20, 2026

📝 Walkthrough

Walkthrough

This pull request applies systematic refactoring across 45+ files in the backend (accounting, frontline APIs) and frontend (client portal, products, contacts, CMS modules). Changes include replacing regex-based string replacement with .replaceAll(), adding readonly type modifiers to component props, consolidating redundant imports, and minor logic adjustments (conditional inversions, membership checks). No new features or API signatures are introduced.

Changes

Cohort / File(s) Summary
String Normalization (replaceAll)
backend/core-api/src/modules/documents/blocksToHtml.ts, backend/core-api/src/modules/documents/utils.ts, backend/plugins/frontline_api/src/modules/integrations/facebook/handleFacebookMessage.ts, backend/plugins/frontline_api/src/modules/integrations/facebook/utils.ts, frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/*, frontend/plugins/content_ui/src/modules/cms/posts/formHelpers.ts
Replaced regex-based .replace(/pattern/g, ...) calls with .replaceAll() for HTML entity decoding, slug generation, and text normalization across multiple files.
Accounting Models Logic & Formatting
backend/plugins/accounting_api/src/modules/accounting/db/models/Accounts.ts, backend/plugins/accounting_api/src/modules/accounting/db/models/AdjustInventories.ts, backend/plugins/accounting_api/src/modules/accounting/db/models/Transactions.ts, backend/plugins/accounting_api/src/modules/accounting/db/models/VatRows.ts, backend/plugins/accounting_api/src/modules/accounting/db/models/CtaxRows.ts
Inverted conditional logic for ID classification (usedIds/unUsedIds), refactored parentId assignment flow in Transactions, added readonly to method signatures, and reformatted Mongoose queries and object literals across multiple lines.
Frontend Props Immutability (Readonly)
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetail*.tsx, frontend/libs/ui-modules/src/modules/contacts/components/*.tsx, frontend/plugins/content_ui/src/modules/cms/categories/CategoryDrawer.tsx, frontend/plugins/content_ui/src/modules/cms/posts/PostDrawer.tsx, frontend/plugins/content_ui/src/modules/cms/posts/*.tsx, frontend/plugins/content_ui/src/modules/cms/shared/*.tsx
Added Readonly<...> wrapper or readonly field modifiers to component prop interfaces across 20+ files, enforcing immutability at the TypeScript level without altering runtime behavior.
Import Consolidation
frontend/core-ui/src/modules/client-portal/components/ClientPortalMoreColumn.tsx, frontend/plugins/content_ui/src/modules/cms/categories/Categories.tsx, frontend/plugins/content_ui/src/modules/cms/posts/InlineTagsEditor.tsx, frontend/plugins/content_ui/src/modules/cms/posts/PostActions.tsx, frontend/plugins/content_ui/src/modules/cms/shared/Cms.tsx, frontend/plugins/content_ui/src/modules/cms/shared/IconPicker.tsx, frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/*.tsx, frontend/plugins/operation_ui/src/modules/team/components/team-details/*.tsx
Combined multiple import statements from the same module into single destructured imports, removing redundant erxes-ui and other module imports.
Component Logic & Selection Refactoring
frontend/core-ui/src/modules/products/components/ProductAddSheet.tsx, frontend/core-ui/src/modules/products/components/ProductsFilter.tsx, frontend/libs/ui-modules/src/modules/contacts/components/SelectCompany.tsx, frontend/libs/ui-modules/src/modules/contacts/components/SelectCustomer.tsx
Inverted onOpenChange callback logic in ProductAddSheet, changed empty-state conditional from !productCategories?.length to productCategories?.length === 0, and replaced .find() membership checks with .includes() for selection filtering.
Backend Utility & API Improvements
backend/plugins/frontline_api/src/modules/integrations/facebook/fieldUtils.ts, backend/plugins/frontline_api/src/modules/integrations/facebook/utils.ts
Removed redundant array-spread syntax in field generation, improved error message derivation for invalid tokens, and strengthened logging for upload-config fetch failures.
CMS Heading & Editor Updates
frontend/plugins/content_ui/src/modules/cms/posts/formHelpers.ts, frontend/plugins/content_ui/src/modules/cms/posts/AudioUploader.tsx, frontend/plugins/content_ui/src/modules/cms/posts/VideoUploader.tsx, frontend/plugins/content_ui/src/modules/cms/posts/TranslationEditor.tsx
Replaced heading-level extraction via character indexing with regex capture groups, added <track> captions element to audio/video players, and tightened type safety for Translation interfaces with readonly modifiers.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~28 minutes

Possibly related PRs

Poem

🐰 String methods cleaned, now .replaceAll shines,
Readonly props guard each design line,
Imports consolidated, logic refined,
A thousand small tweaks, all carefully aligned.
This refactor hops forward with grace!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'fix: sonar resolve fe frontline pipeline components config components' is overly broad and vague. It uses generic 'sonar resolve' language without specifying the actual changes made across the codebase. Provide a more specific and descriptive title that highlights the primary change, such as 'refactor: add readonly modifiers and consolidate imports across components' or 'fix: enforce immutability in component props types'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sonar_resolve_fe_frontline_pipeline_components_config_components
📝 Coding Plan
  • Generate coding plan for human review comments

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.

This commit fixes the style issues introduced in 880ea88 according to the output
from Prettier.

Details: #7238
@deepsource-io
Copy link

deepsource-io bot commented Mar 20, 2026

DeepSource Code Review

We reviewed changes in 6ede5e6...5aec591 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
JavaScript Mar 20, 2026 11:55a.m. Review ↗
Docker Mar 20, 2026 11:55a.m. Review ↗

@sonarqubecloud
Copy link

❌ The last analysis has failed.

See analysis details on SonarQube Cloud

@github-actions
Copy link

🌗 Pull Request Overview

This PR addresses SonarQube code quality issues across frontend and backend files. Changes include replacing .replace() with .replaceAll() for clarity, adding Readonly<> type annotations to React props, cleaning up unused imports, and improving error handling.

Reviewed Changes
Kimi performed full review on 36 changed files and found 0 issues.

Show a summary per file
File Description
backend/core-api/src/modules/documents/blocksToHtml.ts Replaced .replace() with .replaceAll() for HTML escaping; consolidated multiple cssProps.push() calls into single call with multiple arguments
backend/core-api/src/modules/documents/utils.ts Changed Array() to new Array() for explicit array construction
backend/plugins/accounting_api/src/modules/accounting/db/models/Accounts.ts Reformatted code; replaced .replace() with .replaceAll(); inverted if-else logic for clarity in ID filtering
backend/plugins/accounting_api/src/modules/accounting/db/models/AdjustInventories.ts Reformatted with proper line breaks and trailing commas; replaced conditional with nullish coalescing assignment (??=)
backend/plugins/accounting_api/src/modules/accounting/db/models/CtaxRows.ts Reformatted code; inverted if-else logic for clarity in ID filtering
backend/plugins/accounting_api/src/modules/accounting/db/models/Transactions.ts Inverted if-else logic for clarity (swapped blocks to check positive condition first)
backend/plugins/accounting_api/src/modules/accounting/db/models/VatRows.ts Reformatted code; inverted if-else logic for clarity in ID filtering
backend/plugins/frontline_api/src/modules/integrations/facebook/fieldUtils.ts Simplified array concatenation by removing unnecessary spread of literal array
backend/plugins/frontline_api/src/modules/integrations/facebook/handleFacebookMessage.ts Replaced .replace() with .replaceAll() for string replacements
backend/plugins/frontline_api/src/modules/integrations/facebook/utils.ts Improved error handling with type checks; fixed type definition spacing; added missing error logging; simplified boolean expressions with !! operator
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailFacebook.tsx Added Readonly<Props> to component props type
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailFirebase.tsx Added Readonly<Props> to component props type
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailGoogle.tsx Added Readonly<Props> to component props type
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailManual.tsx Added Readonly<> to component props type
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailSMSProviders.tsx Added Readonly<Props> to component props type
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailSocialPay.tsx Added Readonly<Props> to component props type
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailToken.tsx Added Readonly<> to component props type
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailToki.tsx Added Readonly<Props> to component props type
frontend/core-ui/src/modules/client-portal/components/ClientPortalMoreColumn.tsx Consolidated imports from same module
frontend/core-ui/src/modules/products/components/ProductAddSheet.tsx Inverted if-else logic for clarity
frontend/core-ui/src/modules/products/components/ProductsFilter.tsx Added Readonly<> to interfaces; changed falsy check to explicit === 0 check
frontend/libs/ui-modules/src/modules/contacts/components/CompanyPhones.tsx Added readonly modifier to interface properties
frontend/libs/ui-modules/src/modules/contacts/components/CustomerEmails.tsx Added readonly modifier to interface properties
frontend/libs/ui-modules/src/modules/contacts/components/CustomerPhones.tsx Added readonly modifier to interface properties
frontend/libs/ui-modules/src/modules/contacts/components/SelectCompany.tsx Simplified array filtering with .includes() instead of .find()
frontend/libs/ui-modules/src/modules/contacts/components/SelectCustomer.tsx Simplified array filtering with .includes() instead of .find()
frontend/plugins/content_ui/src/modules/cms/categories/Categories.tsx Consolidated imports from same module
frontend/plugins/content_ui/src/modules/cms/categories/CategoryDrawer.tsx Added readonly modifier to interface properties
frontend/plugins/content_ui/src/modules/cms/categories/CmsCategoryDrawer.tsx Added readonly modifier to interface properties; replaced .replace() with .replaceAll()
frontend/plugins/content_ui/src/modules/cms/posts/AudioUploader.tsx Added <track> element for accessibility in audio element
frontend/plugins/content_ui/src/modules/cms/posts/DateCell.tsx Added readonly modifier to type property
frontend/plugins/content_ui/src/modules/cms/posts/InlineTagsEditor.tsx Consolidated imports; added readonly to type properties
frontend/plugins/content_ui/src/modules/cms/posts/PostActions.tsx Consolidated imports; added readonly to type properties
frontend/plugins/content_ui/src/modules/cms/posts/PostDrawer.tsx Added readonly modifier to interface properties
frontend/plugins/content_ui/src/modules/cms/posts/TranslationEditor.tsx Added readonly modifier to interface properties; removed unnecessary as any type assertion
frontend/plugins/content_ui/src/modules/cms/posts/VideoUploader.tsx Added <track> element for accessibility in video element
frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/useInlineCategory.ts Replaced .replace() with .replaceAll()
frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/useInlineTag.ts Replaced .replace() with .replaceAll()
frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/usePostData.tsx Consolidated imports from same module
frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/usePostForm.tsx Replaced .replace() with .replaceAll()
frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/usePostSubmission.tsx Replaced .replace() with .replaceAll()
frontend/plugins/content_ui/src/modules/cms/posts/formHelpers.ts Refactored heading tag parsing to use regex capture group instead of charAt(1)
frontend/plugins/content_ui/src/modules/cms/shared/Cms.tsx Consolidated imports from same module
frontend/plugins/content_ui/src/modules/cms/shared/CmsLayout.tsx Added Readonly<> to component props type
frontend/plugins/content_ui/src/modules/cms/shared/EmptyState.tsx Added Readonly<> to component props type
frontend/plugins/content_ui/src/modules/cms/shared/IconPicker.tsx Consolidated imports; added Readonly<> to component props type
frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/ConfigList.tsx Removed unused import IconEdit
frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/ConfigsForm.tsx Removed unused import Popover
frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/CreateConfig.tsx Removed unused import useConfirm
frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/PipelineConfigBreadcrumb.tsx Consolidated imports from same module
frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/TicketBasicFields.tsx Removed unused imports; added readonly modifier to interface properties
frontend/plugins/operation_ui/src/modules/team/components/team-details/DeleteTeamForm.tsx Removed unused import useGetTeam
frontend/plugins/operation_ui/src/modules/team/components/team-details/EstimateSection.tsx Consolidated imports from same module
frontend/plugins/operation_ui/src/modules/team/components/team-details/UpdateTeamForm.tsx Consolidated imports from same module

📋 Review Findings

No issues found! The code looks good.

All changes in this PR are code quality improvements that address SonarQube issues:

  1. .replace().replaceAll(): Makes the intent clearer (replace all occurrences vs first only) and is more readable when using string patterns instead of regex with /g flag.

  2. Readonly<Props>: Good TypeScript practice that prevents accidental mutation of props within components.

  3. Unused import cleanup: Reduces bundle size and improves maintainability.

  4. Error handling improvements: Properly checking if caught errors are Error instances before accessing .message prevents runtime crashes when non-Error values are thrown.

  5. Logic inversions: Changing if (!condition) to if (condition) with swapped blocks improves readability by checking the positive case first.

  6. Accessibility improvements: Adding <track> elements to <audio> and <video> components improves accessibility for users who need captions.

  7. Array methods: Using .includes() instead of .find() for existence checks is more semantically correct and potentially more performant.


Powered by Kimi | Model: kimi-k2.5


const extractText = (html: string): string => {
return html.replace(/<[^>]*>/g, '').trim();
return html.replaceAll(/<[^>]*>/g, '').trim();

Check failure

Code scanning / CodeQL

Incomplete multi-character sanitization High

This string may still contain
<script
, which may cause an HTML element injection vulnerability.
export const loadAdjustInventoriesClass = (models: IModels, subdomain: string) => {
export const loadAdjustInventoriesClass = (
models: IModels,
subdomain: string,
Copy link

Choose a reason for hiding this comment

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

'subdomain' is defined but never used


Unused variables are generally considered a code smell and should be avoided.

}): Promise<IAdjustInvDetail | void>
updateAdjustInvDetail(
args: IAdjustInvDetail,
): Promise<IAdjustInvDetail | void>;
Copy link

Choose a reason for hiding this comment

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

void is not valid as a constituent in a union type


Disallows usage of void type outside of return types or generic type arguments. If void is used as return type, it shouldn’t be a part of intersection/union type with most other types.

multiplier?: number;
hasResp?: boolean;
},
): Promise<IAdjustInvDetail | void>;
Copy link

Choose a reason for hiding this comment

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

void is not valid as a constituent in a union type


Disallows usage of void type outside of return types or generic type arguments. If void is used as return type, it shouldn’t be a part of intersection/union type with most other types.

export const loadAdjustInvDetailsClass = (models: IModels, subdomain: string) => {
export const loadAdjustInvDetailsClass = (
models: IModels,
subdomain: string,
Copy link

Choose a reason for hiding this comment

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

'subdomain' is defined but never used


Unused variables are generally considered a code smell and should be avoided.

public static async updateAdjustInvDetail(args: IAdjustInvDetail & { hasResp: boolean }) {
const { adjustId, productId, accountId, branchId, departmentId, hasResp } = args;
const oldDetail = await models.AdjustInvDetails.findOne({ adjustId, productId, accountId, branchId, departmentId }).lean();
public static async updateAdjustInvDetail(
Copy link

Choose a reason for hiding this comment

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

Expected to return a value at the end of static async method 'updateAdjustInvDetail'


Any code paths that do not have explicit returns will return undefined. It is recommended to replace any implicit dead-ends that return undefined with a return null statement.

// Define a simple in-memory cache (outside the function scope)

type UploadConfig = { AWS_BUCKET?: string;[k: string]: any } | null;
type UploadConfig = { AWS_BUCKET?: string; [k: string]: any } | null;
Copy link

Choose a reason for hiding this comment

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

Unexpected any. Specify a different type


The any type can sometimes leak into your codebase. TypeScript compiler skips the type checking of the any typed variables, so it creates a potential safety hole, and source of bugs in your codebase. We recommend using unknown or never type variable.

id: page.id,
name: page.name,
isUsed: integration ? true : false,
isUsed: !!integration,
Copy link

Choose a reason for hiding this comment

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

use `Boolean(integration)` instead


Prefer using explicit casts by calling Number, Boolean, or String over using operators like +, !! or "" +. This is considered best practice as it improves readability.

});

page.isUsed = integration ? true : false;
page.isUsed = !!integration;
Copy link

Choose a reason for hiding this comment

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

use `Boolean(integration)` instead


Prefer using explicit casts by calling Number, Boolean, or String over using operators like +, !! or "" +. This is considered best practice as it improves readability.

@github-actions
Copy link

🌗 Pull Request Overview

This PR addresses SonarQube/code quality issues across backend and frontend modules. Changes include replacing replace with replaceAll for clarity, adding Readonly modifiers to React props for type safety, consolidating imports, inverting conditional logic for better readability, and improving error handling.

Reviewed Changes
Kimi performed full review on 54 changed files and found 1 issue.

Show a summary per file
File Description
backend/core-api/src/modules/documents/blocksToHtml.ts Migrated .replace() with regex to .replaceAll() for HTML escaping; optimized array pushes
backend/core-api/src/modules/documents/utils.ts Changed Array() to new Array() for explicit constructor usage
backend/plugins/accounting_api/src/modules/accounting/db/models/Accounts.ts Code formatting; replaced .replace() with .replaceAll(); improved error message formatting
backend/plugins/accounting_api/src/modules/accounting/db/models/AdjustInventories.ts Code formatting; used nullish coalescing assignment (??=); improved readability
backend/plugins/accounting_api/src/modules/accounting/db/models/CtaxRows.ts Inverted conditional logic for better readability
backend/plugins/accounting_api/src/modules/accounting/db/models/Transactions.ts Inverted if-else logic (positive condition first)
backend/plugins/accounting_api/src/modules/accounting/db/models/VatRows.ts Inverted conditional logic for better readability
backend/plugins/frontline_api/src/modules/integrations/facebook/fieldUtils.ts Simplified array spread operation
backend/plugins/frontline_api/src/modules/integrations/facebook/handleFacebookMessage.ts Migrated .replace() to .replaceAll()
backend/plugins/frontline_api/src/modules/integrations/facebook/utils.ts Improved error handling with type guards; used !! for boolean conversion; fixed template literals
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailFacebook.tsx Added Readonly<Props> to component props
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailFirebase.tsx Added Readonly<Props> to component props
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailGoogle.tsx Added Readonly<Props> to component props
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailManual.tsx Added Readonly<Props> to component props
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailSMSProviders.tsx Added Readonly<Props> to component props
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailSocialPay.tsx Added Readonly<Props> to component props
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailToken.tsx Added Readonly<Props> to component props
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailToki.tsx Added Readonly<Props> to component props
frontend/core-ui/src/modules/client-portal/components/ClientPortalMoreColumn.tsx Consolidated imports from same module
frontend/core-ui/src/modules/products/components/ProductAddSheet.tsx Inverted conditional for better readability
frontend/core-ui/src/modules/products/components/ProductsFilter.tsx Added Readonly to interfaces; changed length check to explicit === 0
frontend/libs/ui-modules/src/modules/contacts/components/CompanyPhones.tsx Added readonly to interface properties
frontend/libs/ui-modules/src/modules/contacts/components/CustomerEmails.tsx Added readonly to interface properties
frontend/libs/ui-modules/src/modules/contacts/components/CustomerPhones.tsx Added readonly to interface properties
frontend/libs/ui-modules/src/modules/contacts/components/SelectCompany.tsx Fixed indentation; replaced .find() with .includes()
frontend/libs/ui-modules/src/modules/contacts/components/SelectCustomer.tsx Fixed indentation; replaced .find() with .includes()
frontend/plugins/content_ui/src/modules/cms/categories/Categories.tsx Consolidated imports from same module
frontend/plugins/content_ui/src/modules/cms/categories/CategoryDrawer.tsx Added readonly to interface properties
frontend/plugins/content_ui/src/modules/cms/categories/CmsCategoryDrawer.tsx Added readonly to interface properties; migrated to .replaceAll()
frontend/plugins/content_ui/src/modules/cms/posts/AudioUploader.tsx Added empty <track> element for accessibility
frontend/plugins/content_ui/src/modules/cms/posts/DateCell.tsx Added readonly to type property
frontend/plugins/content_ui/src/modules/cms/posts/InlineTagsEditor.tsx Consolidated imports; added readonly to type properties
frontend/plugins/content_ui/src/modules/cms/posts/PostActions.tsx Consolidated imports; added readonly to type properties
frontend/plugins/content_ui/src/modules/cms/posts/PostDrawer.tsx Added readonly to interface properties
frontend/plugins/content_ui/src/modules/cms/posts/TranslationEditor.tsx Added readonly to interface properties; removed unnecessary type assertion
frontend/plugins/content_ui/src/modules/cms/posts/VideoUploader.tsx Added empty <track> element for accessibility
frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/useInlineCategory.ts Migrated to .replaceAll()
frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/useInlineTag.ts Migrated to .replaceAll()
frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/usePostData.tsx Consolidated imports from same module
frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/usePostForm.tsx Migrated to .replaceAll()
frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/usePostSubmission.tsx Migrated to .replaceAll()
frontend/plugins/content_ui/src/modules/cms/posts/formHelpers.ts Improved regex handling with RegExp.exec()
frontend/plugins/content_ui/src/modules/cms/shared/Cms.tsx Consolidated imports from same module
frontend/plugins/content_ui/src/modules/cms/shared/CmsLayout.tsx Added Readonly<Props> to component props
frontend/plugins/content_ui/src/modules/cms/shared/EmptyState.tsx Added Readonly<Props> to component props
frontend/plugins/content_ui/src/modules/cms/shared/IconPicker.tsx Consolidated imports; added Readonly<Props> to component props
frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/ConfigList.tsx Removed unused IconEdit import
frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/ConfigsForm.tsx Removed unused Popover import
frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/CreateConfig.tsx Removed unused useConfirm import
frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/PipelineConfigBreadcrumb.tsx Consolidated imports from same module
frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/TicketBasicFields.tsx Removed unused imports; added readonly to interface
frontend/plugins/operation_ui/src/modules/team/components/team-details/DeleteTeamForm.tsx Removed unused useGetTeam import
frontend/plugins/operation_ui/src/modules/team/components/team-details/EstimateSection.tsx Consolidated imports from same module
frontend/plugins/operation_ui/src/modules/team/components/team-details/UpdateTeamForm.tsx Consolidated imports from same module

📋 Review Findings

📄 backend/plugins/accounting_api/src/modules/accounting/db/models/Accounts.ts

🟠 HIGH security: Potential Regular Expression Denial of Service (ReDoS)

Line 69

The parentAccount.code is interpolated directly into a RegExp without escaping special characters. If parentAccount.code contains regex metacharacters (., *, +, ?, etc.), it could cause unexpected behavior or ReDoS vulnerabilities.

💡 Suggested fix:

Current code:

const re = new RegExp(`^${parentAccount.code}.*`);
if (!re.test(doc.code)) {
  throw new Error('Code is not validate of parent account');
}

Improved code:

const escapeRegExp = (string: string): string => {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
};
const re = new RegExp(`^${escapeRegExp(parentAccount.code)}.*`);
if (!re.test(doc.code)) {
  throw new Error('Code is not validate of parent account');
}

✅ Summary

54 files reviewed, 1 issue found.

The PR consists of legitimate code quality improvements addressing SonarQube findings:

  • Good practices observed: Using Readonly<Props> for React components, replacing .replace() with .replaceAll() for clarity, consolidating imports, using ??= operator, improving error handling with type guards, and replacing .find() with .includes() for better performance.

  • Issue identified: One pre-existing security concern in Accounts.ts where user input is interpolated into a regular expression without sanitization. While this is not introduced by the PR, it should be addressed.

The code changes are safe to merge. The recommended security fix for regex injection should be considered for a follow-up PR.


Powered by Kimi | Model: kimi-k2.5

Copy link

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

Caution

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

⚠️ Outside diff range comments (1)
frontend/plugins/content_ui/src/modules/cms/posts/PostActions.tsx (1)

36-40: ⚠️ Potential issue | 🟡 Minor

Avoid console.error per coding guidelines.

Line 39 uses console.error which conflicts with the guideline to avoid console logs. Consider using a proper error handling mechanism or a toast notification for user-facing errors.

🔧 Proposed fix
             onSelect={() =>
               confirm({ message: 'Delete this post?' })
                 .then(onDelete)
-                .catch(console.error)
+                .catch(() => {
+                  // User cancelled confirmation - no action needed
+                })
             }

As per coding guidelines: "Avoid console logs".

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

In `@frontend/plugins/content_ui/src/modules/cms/posts/PostActions.tsx` around
lines 36 - 40, The onSelect handler in PostActions.tsx currently swallows errors
by calling console.error in the confirm().catch; replace that console.error
usage with the app's error reporting or user-notification mechanism (e.g., call
a provided reportError/logError function or trigger a toast via showToastError)
so failures from confirm()/onDelete are surfaced properly; update the promise
chain in the onSelect callback to .catch(err => reportError(err)) or .catch(err
=> showToastError('Failed to delete post', err)) and ensure any referenced
helper (reportError/showToastError) is imported or passed in where PostActions
(or its onDelete) is defined.
🧹 Nitpick comments (16)
frontend/plugins/content_ui/src/modules/cms/posts/DateCell.tsx (1)

4-6: Use an interface for component props instead of a type alias.

The readonly prop update is good, but this props shape should be declared as an interface to match the repo TS/TSX standard.

♻️ Proposed refactor
-type DateCellProps = {
+interface DateCellProps {
   readonly date: string;
-};
+}

As per coding guidelines, "**/*.{ts,tsx}: ... prefer interfaces over types".

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

In `@frontend/plugins/content_ui/src/modules/cms/posts/DateCell.tsx` around lines
4 - 6, The prop shape for the DateCell component is declared with a type alias;
update it to an interface to match repository TS/TSX standards by replacing the
`type DateCellProps = { readonly date: string; };` declaration with an
equivalent `interface DateCellProps { readonly date: string; }` and ensure any
usages of DateCellProps (e.g., in the DateCell component signature) remain
unchanged other than the new interface form.
frontend/core-ui/src/modules/products/components/ProductsFilter.tsx (1)

49-53: Minor inconsistency in readonly patterns.

The readonly modifier on props prevents reassignment but doesn't prevent mutation of object properties. Note that SelectCategoriesBadgeProps (line 19) uses Readonly<IProductCategory> which provides deeper immutability, while here you're using readonly category: IProductCategory.

For consistency, consider using Readonly<IProductCategory> here as well if deep immutability is desired:

 interface SelectCategoryProps {
-  readonly category: IProductCategory;
-  readonly selectedCategory?: IProductCategory;
+  readonly category: Readonly<IProductCategory>;
+  readonly selectedCategory?: Readonly<IProductCategory>;
   readonly onSelect: (categoryId: string) => void;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/core-ui/src/modules/products/components/ProductsFilter.tsx` around
lines 49 - 53, SelectCategoryProps uses shallow readonly on props while
SelectCategoriesBadgeProps uses Readonly<IProductCategory>; update
SelectCategoryProps so category and selectedCategory use
Readonly<IProductCategory> (keep onSelect signature unchanged) to match deep
immutability pattern and maintain consistency with SelectCategoriesBadgeProps
and related components.
frontend/plugins/content_ui/src/modules/cms/shared/EmptyState.tsx (1)

12-20: Good addition of Readonly wrapper for props immutability.

The Readonly type wrapper correctly enforces immutability on the component props, which is a best practice for React components.

Consider extracting the props to a separate interface for better maintainability and alignment with the coding guidelines. As per coding guidelines, "Use functional components with TypeScript interfaces."

♻️ Optional refactor: Extract props to interface
+interface EmptyStateProps {
+  icon?: React.ElementType;
+  title: string;
+  description?: string;
+  actionLabel?: string;
+  onAction?: () => void;
+  className?: string;
+  children?: React.ReactNode;
+}
+
 export function EmptyState({
   icon: Icon,
   title,
   description,
   actionLabel,
   onAction,
   className,
   children,
-}: Readonly<{
-  icon?: React.ElementType;
-  title: string;
-  description?: string;
-  actionLabel?: string;
-  onAction?: () => void;
-  className?: string;
-  children?: React.ReactNode;
-}>) {
+}: Readonly<EmptyStateProps>) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/plugins/content_ui/src/modules/cms/shared/EmptyState.tsx` around
lines 12 - 20, Extract the inline Readonly prop type into a named interface
(e.g. interface EmptyStateProps) containing icon?: React.ElementType, title:
string, description?: string, actionLabel?: string, onAction?: () => void,
className?: string, children?: React.ReactNode, then update the EmptyState
component signature to accept Readonly<EmptyStateProps> (or use
React.FC<Readonly<EmptyStateProps>>) so the component uses the new
EmptyStateProps type instead of the inline type; ensure all references to the
props remain unchanged.
frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/TicketBasicFields.tsx (1)

164-164: Replace any with Control<TPipelineConfig> for the control prop.

The SortableFieldCardProps interface uses control: any on line 164, losing type inference for Form.Field bindings and path validation. Since TPipelineConfig is already imported and used consistently throughout the component, typing control as Control<TPipelineConfig> enables proper type checking.

♻️ Proposed typing fix
-import { Path, UseFormReturn, useWatch } from 'react-hook-form';
+import { Control, Path, UseFormReturn, useWatch } from 'react-hook-form';
@@
 interface SortableFieldCardProps {
   readonly ticketField: { key: string; label: string; path: string };
-  readonly control: any;
+  readonly control: Control<TPipelineConfig>;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/TicketBasicFields.tsx`
at line 164, The SortableFieldCardProps interface currently types the control
prop as any; change it to Control<TPipelineConfig> so Form.Field bindings and
path validation get proper types—update the control property in the
SortableFieldCardProps interface (referencing SortableFieldCardProps and the
control field) to use the Control generic with the existing TPipelineConfig
import and ensure any usages of control (e.g., in TicketBasicFields component)
still compile with the stricter type.
frontend/plugins/content_ui/src/modules/cms/categories/Categories.tsx (3)

59-59: Use handleAddCategory for consistent state management.

Lines 59 and 85 call setDrawerOpen(true) directly, bypassing the handleAddCategory logic that resets selectedCategory to undefined. This inconsistency could cause bugs where a previously selected category persists when trying to add a new one.

♻️ Proposed fix for consistent handler usage

At line 59:

-      <Button onClick={() => setDrawerOpen(true)}>
+      <Button onClick={handleAddCategory}>

At line 85:

                onAction={() => setDrawerOpen(true)}
+                onAction={handleAddCategory}

Also applies to: 85-85

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

In `@frontend/plugins/content_ui/src/modules/cms/categories/Categories.tsx` at
line 59, The Button onClick handlers call setDrawerOpen(true) directly which
bypasses handleAddCategory's logic that clears selectedCategory; update both
Button onClick usages (the one at the top-level Button and the one at line 85)
to call handleAddCategory() instead of setDrawerOpen(true) so selectedCategory
is reset to undefined before opening the drawer and state remains consistent.

27-27: Remove unused useEffect.

This effect has an empty body and serves no purpose. It should be removed unless there's a specific reason to keep it (e.g., a planned implementation).

🧹 Proposed cleanup
-  useEffect(() => {}, [location]);
-
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/plugins/content_ui/src/modules/cms/categories/Categories.tsx` at
line 27, Remove the no-op effect in the Categories component: delete the empty
useEffect(() => {}, [location]) call in Categories.tsx (the useEffect import can
also be removed if unused elsewhere) so there is no unused hook referencing
location.

115-134: Remove commented-out code.

This large block of commented code should be removed. Version control preserves the history if this implementation needs to be referenced later.

🧹 Proposed cleanup
    </PageContainer>
-    // <div>
-    //   <CategoriesSidebar />
-    //   <CategoriesRecordTable
-    //     key={refetchTrigger}
-    //     clientPortalId={websiteId || ''}
-    //     onEdit={handleEditCategory}
-    //     onRemove={handleRemoveCategory}
-    //     onBulkDelete={handleBulkDelete}
-    //   />
-    //   <CmsCategoryDrawer
-    //     category={selectedCategory}
-    //     isOpen={drawerOpen}
-    //     onClose={() => {
-    //       setDrawerOpen(false);
-    //       setSelectedCategory(undefined);
-    //     }}
-    //     clientPortalId={websiteId || ''}
-    //     onRefetch={refetch}
-    //   />
-    // </div>
  );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/plugins/content_ui/src/modules/cms/categories/Categories.tsx` around
lines 115 - 134, Remove the large commented-out JSX block that contains
CategoriesSidebar, CategoriesRecordTable (with props key={refetchTrigger},
clientPortalId={websiteId || ''}, onEdit={handleEditCategory},
onRemove={handleRemoveCategory}, onBulkDelete={handleBulkDelete}) and
CmsCategoryDrawer (with props category={selectedCategory}, isOpen={drawerOpen},
clientPortalId={websiteId || ''}, onRefetch={refetch}); simply delete that
commented section so the file contains only active code (history is preserved in
VCS).
frontend/plugins/content_ui/src/modules/cms/shared/Cms.tsx (2)

14-17: Consider using absolute imports as per coding guidelines.

The local imports use relative paths (../ and ./), which goes against the project's coding guideline to always use absolute paths when importing.

As per coding guidelines: "Always use absolute paths when importing"

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

In `@frontend/plugins/content_ui/src/modules/cms/shared/Cms.tsx` around lines 14 -
17, The imports in Cms.tsx use relative paths; update them to use the project's
absolute import aliases instead (replace ../components/websites/WebsiteDrawer,
./CmsLayout, ./EmptyState, and ../graphql/queries with their configured absolute
module paths) so that WebsiteDrawer, CmsLayout, EmptyState, and CONTENT_CMS_LIST
are imported via the project's absolute import root/alias; ensure paths match
the tsconfig/webpack alias and run a quick build to verify no unresolved import
errors.

47-47: Consider using explicit types instead of any.

The editingWebsite state and handler parameters use any, which bypasses TypeScript's type safety. Consider using Website | null to leverage the existing Website interface.

🔧 Suggested type improvements

For line 47:

-  const [editingWebsite, setEditingWebsite] = useState<any>(null);
+  const [editingWebsite, setEditingWebsite] = useState<Website | null>(null);

For line 63:

-  const handleEditWebsite = (website: any) => {
+  const handleEditWebsite = (website: Website) => {

For line 68:

-  const handleWebsiteClick = (website: any) => {
+  const handleWebsiteClick = (website: Website) => {

Also applies to: 63-63, 68-68

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

In `@frontend/plugins/content_ui/src/modules/cms/shared/Cms.tsx` at line 47,
Replace the use of the any type for the editingWebsite state and its related
handler parameters with the concrete Website type (or Website | null for state)
to restore type safety: change the state declaration editingWebsite /
setEditingWebsite to use Website | null instead of any, and update any functions
referenced in this file that accept or return editingWebsite (e.g., the handlers
where editingWebsite is passed/received on lines around the open/edit/save
handlers) to accept Website (or Website | null where appropriate) rather than
any; ensure imports/types reference the existing Website interface and adjust
null checks accordingly.
backend/plugins/frontline_api/src/modules/integrations/facebook/utils.ts (1)

328-332: Try-catch is unnecessary - getPageAccessTokenFromMap cannot throw.

Looking at getPageAccessTokenFromMap (lines 304-309), it simply returns (pageTokens || {})[pageId] which cannot throw. The catch block is unreachable dead code. While the fix to use e.message instead of an empty error is an improvement in principle, consider removing the unnecessary try-catch:

♻️ Optional: Remove unnecessary try-catch
 export const getPostLink = async (
   pageId: string,
   pageTokens: { [key: string]: string },
   postId: string,
 ) => {
-  let pageAccessToken;
-
-  try {
-    pageAccessToken = getPageAccessTokenFromMap(pageId, pageTokens);
-  } catch (e) {
-    debugError(`Error occurred while getting page access token: ${e.message}`);
-    throw new Error(e.message);
-  }
+  const pageAccessToken = getPageAccessTokenFromMap(pageId, pageTokens);

   try {
     const response: any = await graphRequest.get(

Note: The same pattern exists in getFacebookUser, sendReply, getFacebookUserProfilePic, and other functions - consider cleaning them up as well.

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

In `@backend/plugins/frontline_api/src/modules/integrations/facebook/utils.ts`
around lines 328 - 332, The try-catch around calling getPageAccessTokenFromMap
is dead code because getPageAccessTokenFromMap simply returns (pageTokens ||
{})[pageId] and cannot throw; remove the try-catch block and directly assign
pageAccessToken = getPageAccessTokenFromMap(pageId, pageTokens), dropping the
debugError/throw path, and apply the same cleanup to similar patterns in
getFacebookUser, sendReply, getFacebookUserProfilePic (and other functions)
where a non-throwing helper is wrapped in an unnecessary try-catch.
backend/plugins/accounting_api/src/modules/accounting/db/models/AdjustInventories.ts (1)

5-17: Use configured path aliases instead of relative imports

Line 12 and Line 17 use relative imports in a .ts file, which breaks the repo alias convention and makes refactors harder.

♻️ Suggested change
 import {
   ADJ_INV_STATUSES,
   IAdjustInvDetail,
   IAdjustInvDetailDocument,
   IAdjustInvDetailParamsId,
   IAdjustInventory,
   IAdjustInventoryDocument,
-} from '../../@types/adjustInventory';
+} from '~/modules/accounting/@types/adjustInventory';
 import { JOURNALS, TR_SIDES } from '../../@types/constants';
 import {
   adjustInvDetailsSchema,
   adjustInventoriesSchema,
-} from '../definitions/adjustInventory';
+} from '~/modules/accounting/db/definitions/adjustInventory';

As per coding guidelines: **/*.ts: "Use path aliases for imports: ~/* for service root, @/* for modules directory, and erxes-api-shared/* for shared library in backend services".

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

In
`@backend/plugins/accounting_api/src/modules/accounting/db/models/AdjustInventories.ts`
around lines 5 - 17, The imports for adjustInvDetailsSchema and
adjustInventoriesSchema use relative paths (lines that import from
'../definitions/adjustInventory') which violates the repo alias convention;
update those import statements to use the configured path alias for modules
(e.g. use `@/modules/`... or the project’s configured alias such as `@/`* or ~/* as
appropriate) so that the symbols adjustInvDetailsSchema and
adjustInventoriesSchema are imported via the alias rather than a relative
'../definitions/adjustInventory' path; keep the existing exported symbol names
and only change the module path.
frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/usePostForm.tsx (1)

80-84: Consider extracting the slug utility to a shared module.

The generateSlug implementation is duplicated across usePostForm.tsx, useInlineCategory.ts, useInlineTag.ts, and usePostSubmission.tsx. Consolidating into a single shared utility would reduce maintenance burden and ensure consistent behavior.

The replaceAll usage itself is correct—both regex patterns include the required global flag.

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

In
`@frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/usePostForm.tsx`
around lines 80 - 84, Extract the duplicated generateSlug function into a single
shared utility (e.g., export a slugify/generateSlug function from a new module)
and replace the local implementations in usePostForm.tsx, useInlineCategory.ts,
useInlineTag.ts, and usePostSubmission.tsx with imports from that shared module;
ensure the exported function preserves the existing behavior and TypeScript
signature (text: string) => string, update all import sites to use the new
utility name (generateSlug or slugify) and remove the local definitions so all
modules use the centralized implementation.
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailManual.tsx (1)

12-12: Prefer a named props interface instead of inline object typing.

Please extract the inline prop shape into an interface (e.g., interface Props { clientPortal: IClientPortal }) and use Readonly<Props> for consistency with project conventions.

As per coding guidelines, "prefer interfaces over types" and "Use functional components with TypeScript interfaces."

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

In
`@frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailManual.tsx`
at line 12, The component ClientPortalDetailManual currently uses an inline prop
type Readonly<{ clientPortal: IClientPortal }>; extract that inline shape into a
named interface (e.g., interface Props { clientPortal: IClientPortal }) and
update the component signature to use Readonly<Props> (or Readonly<Props> with
the same destructuring pattern) so the component uses a named TypeScript
interface instead of the inline object type.
frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailToken.tsx (1)

7-7: Use a named props interface for consistency.

Readonly is a good addition, but this should ideally be Readonly<Props> with a dedicated Props interface instead of inline object typing.

As per coding guidelines, "prefer interfaces over types" and "Use functional components with TypeScript interfaces."

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

In
`@frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailToken.tsx`
at line 7, Replace the inline parameter typing in the ClientPortalDetailToken
component with a named interface: create an interface Props { clientPortal?:
IClientPortal } (prefer interface over type), then update the component
signature to accept Readonly<Props> (or annotate the component as
React.FC<Props>) instead of Readonly<{ clientPortal?: IClientPortal }>; adjust
any imports/exports if needed so ClientPortalDetailToken, Props, and
IClientPortal remain correctly referenced.
backend/plugins/accounting_api/src/modules/accounting/db/models/Accounts.ts (2)

72-74: Use startsWith for the parent-account prefix check.

This is only a literal prefix test. Building a RegExp from parentAccount.code makes regex metacharacters in stored codes affect the match, while startsWith keeps the comparison exact and simpler.

🧹 Simpler prefix check
-        const re = new RegExp(`^${parentAccount.code}.*`);
-        if (!re.test(doc.code)) {
+        if (!doc.code.startsWith(parentAccount.code)) {
           throw new Error('Code is not validate of parent account');
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/plugins/accounting_api/src/modules/accounting/db/models/Accounts.ts`
around lines 72 - 74, The code currently builds a RegExp from parentAccount.code
and tests doc.code with re, which can misinterpret regex metacharacters; replace
that logic by using a literal prefix check: remove the RegExp creation (variable
re) and instead check if doc.code.startsWith(parentAccount.code), throwing the
same Error('Code is not validate of parent account') when the startsWith check
fails so the behavior remains consistent but exact.

57-60: Code uses ES2021 API (replaceAll) against ES2017 target baseline.

While tsconfig.base.json declares "lib": ["es2021"] (allowing compile-time use of ES2021 APIs), the target: "es2017" in backend/plugins/accounting_api/tsconfig.json creates a mismatch. To align with the coding guideline (**/*.ts: target ES2017), either confirm the runtime supports ES2021, or use the ES2017-safe regex alternative:

♻️ ES2017-safe alternative
-      doc.code = doc.code
-        .replaceAll('*', '')
-        .replaceAll('_', '')
-        .replaceAll(' ', '');
+      doc.code = doc.code.replace(/[*_ ]/g, '');

Also applies to: 106-109

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

In `@backend/plugins/accounting_api/src/modules/accounting/db/models/Accounts.ts`
around lines 57 - 60, The code in Accounts.ts uses the ES2021 String.replaceAll
API on doc.code which conflicts with the repo target of ES2017; replace the
chained replaceAll calls on doc.code with an ES2017-safe regex replace (e.g. use
String.prototype.replace with a global regex that matches '*', '_' and space
such as /[*_ ]/g and replace with ''), and apply the same change to the other
occurrence referenced around lines 106-109 so all replaceAll uses are converted
to replace(/[*_ ]/g, '').
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/plugins/accounting_api/src/modules/accounting/db/models/Accounts.ts`:
- Around line 212-215: The timestamp format used when building the account code
in Accounts.ts is using invalid Day.js tokens ("yyyy-MM-dd HH:mm") which will be
rendered literally; update the format string in the code assignment that builds
`code: dayjs(new Date()).format(...).toString().concat('^', accountingObj.code)`
to use Day.js tokens `YYYY-MM-DD HH:mm` so the prefix is the actual timestamp
(e.g., change the format argument passed to `dayjs(...).format` in the account
`code` construction).

In
`@backend/plugins/accounting_api/src/modules/accounting/db/models/AdjustInventories.ts`:
- Around line 360-367: The aggregation pipeline in AdjustInventories.ts uses
wrong field paths and an incorrect _id shape: change all occurrences of
'$detail.*' to '$details.*' in the $group (use _id: { side: '$details.side' },
remainder: { $sum: '$details.count' }, cost: { $sum: '$details.amount' }) and
update the reduce/compare logic that inspects aggregation results to use
ag._id.side (not ag._id) when matching sides; ensure any other reductions or
lookups that referenced detail.amount/detail.count use
details.amount/details.count consistently.
- Around line 278-283: The unitCost calculation can divide by zero because
remainder may be 0; update the computation around the remainder/cost logic
(variables remainder, cost, unitCost, and function fixNum in AdjustInventories)
to guard against zero by detecting if remainder === 0 (or falsy) and handling it
explicitly—e.g., set unitCost to 0 or preserve previous unitCost/default instead
of performing cost / remainder—and then apply fixNum to the final guarded value;
make the same change for the second occurrence later in the file (lines around
the other unitCost calculation).
- Around line 189-211: The two static methods cleanAdjustInvDetails and
cacheAdjustInvDetails contain identical bodies; consolidate them by extracting
the shared delete logic (models.AdjustInvDetails.deleteMany with remainder:
{$eq:0}, cost: {$eq:0}) into a single implementation and have the other method
delegate to it (e.g., implement cleanAdjustInvDetails as the actual delete and
make cacheAdjustInvDetails call cleanAdjustInvDetails or create a private helper
like deleteZeroRemainderAndCost used by both) so there is no duplicate code.

In `@frontend/plugins/content_ui/src/modules/cms/posts/AudioUploader.tsx`:
- Around line 52-54: The <track> element in AudioUploader is rendered with an
empty src which breaks the HTML spec; either remove the non-functional <track>
line from the JSX in AudioUploader or add a new optional prop (e.g.,
captionsUrl) and conditionally render the <track> only when captionsUrl is a
non-empty valid string; if you add captionsUrl, update the AudioUploader
props/type and ensure the render checks captionsUrl before adding <track>, and
remember that displaying captions for audio requires extra TextTrack API
handling for visible captions (so keep the <track> only as a valid source
attribute, not as a visual display).

In
`@frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/usePostSubmission.tsx`:
- Around line 139-141: The extractText function's regex is unsafe for malformed
HTML and edge cases; update extractText (used by computeTitle) to parse HTML via
the browser DOM instead of regex: create a DOMParser or a temporary
HTMLDivElement, set its innerHTML to the input string, then return the element's
textContent trimmed; wrap parsing in a try/catch and fall back to a conservative
regex strip only on failure to avoid throwing on malicious/malformed input—this
ensures extracted titles are plain text and resilient to broken tags.

In `@frontend/plugins/content_ui/src/modules/cms/posts/VideoUploader.tsx`:
- Around line 38-40: In VideoUploader.tsx inside the VideoUploader component,
remove the hard-coded <track src=""> element and instead render a <track> only
when a valid captions URL is present (e.g., a captionsUrl prop/state) and
non-empty; when rendering the track include src, kind="captions", label (e.g.,
"English captions") and srcLang (e.g., "en") so the element is valid and
accessible. Locate the video JSX using the value prop and conditionally render
the track based on the captions URL truthiness (or validate it ends with .vtt)
to avoid empty fetches and broken accessibility.

---

Outside diff comments:
In `@frontend/plugins/content_ui/src/modules/cms/posts/PostActions.tsx`:
- Around line 36-40: The onSelect handler in PostActions.tsx currently swallows
errors by calling console.error in the confirm().catch; replace that
console.error usage with the app's error reporting or user-notification
mechanism (e.g., call a provided reportError/logError function or trigger a
toast via showToastError) so failures from confirm()/onDelete are surfaced
properly; update the promise chain in the onSelect callback to .catch(err =>
reportError(err)) or .catch(err => showToastError('Failed to delete post', err))
and ensure any referenced helper (reportError/showToastError) is imported or
passed in where PostActions (or its onDelete) is defined.

---

Nitpick comments:
In `@backend/plugins/accounting_api/src/modules/accounting/db/models/Accounts.ts`:
- Around line 72-74: The code currently builds a RegExp from parentAccount.code
and tests doc.code with re, which can misinterpret regex metacharacters; replace
that logic by using a literal prefix check: remove the RegExp creation (variable
re) and instead check if doc.code.startsWith(parentAccount.code), throwing the
same Error('Code is not validate of parent account') when the startsWith check
fails so the behavior remains consistent but exact.
- Around line 57-60: The code in Accounts.ts uses the ES2021 String.replaceAll
API on doc.code which conflicts with the repo target of ES2017; replace the
chained replaceAll calls on doc.code with an ES2017-safe regex replace (e.g. use
String.prototype.replace with a global regex that matches '*', '_' and space
such as /[*_ ]/g and replace with ''), and apply the same change to the other
occurrence referenced around lines 106-109 so all replaceAll uses are converted
to replace(/[*_ ]/g, '').

In
`@backend/plugins/accounting_api/src/modules/accounting/db/models/AdjustInventories.ts`:
- Around line 5-17: The imports for adjustInvDetailsSchema and
adjustInventoriesSchema use relative paths (lines that import from
'../definitions/adjustInventory') which violates the repo alias convention;
update those import statements to use the configured path alias for modules
(e.g. use `@/modules/`... or the project’s configured alias such as `@/`* or ~/* as
appropriate) so that the symbols adjustInvDetailsSchema and
adjustInventoriesSchema are imported via the alias rather than a relative
'../definitions/adjustInventory' path; keep the existing exported symbol names
and only change the module path.

In `@backend/plugins/frontline_api/src/modules/integrations/facebook/utils.ts`:
- Around line 328-332: The try-catch around calling getPageAccessTokenFromMap is
dead code because getPageAccessTokenFromMap simply returns (pageTokens ||
{})[pageId] and cannot throw; remove the try-catch block and directly assign
pageAccessToken = getPageAccessTokenFromMap(pageId, pageTokens), dropping the
debugError/throw path, and apply the same cleanup to similar patterns in
getFacebookUser, sendReply, getFacebookUserProfilePic (and other functions)
where a non-throwing helper is wrapped in an unnecessary try-catch.

In
`@frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailManual.tsx`:
- Line 12: The component ClientPortalDetailManual currently uses an inline prop
type Readonly<{ clientPortal: IClientPortal }>; extract that inline shape into a
named interface (e.g., interface Props { clientPortal: IClientPortal }) and
update the component signature to use Readonly<Props> (or Readonly<Props> with
the same destructuring pattern) so the component uses a named TypeScript
interface instead of the inline object type.

In
`@frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailToken.tsx`:
- Line 7: Replace the inline parameter typing in the ClientPortalDetailToken
component with a named interface: create an interface Props { clientPortal?:
IClientPortal } (prefer interface over type), then update the component
signature to accept Readonly<Props> (or annotate the component as
React.FC<Props>) instead of Readonly<{ clientPortal?: IClientPortal }>; adjust
any imports/exports if needed so ClientPortalDetailToken, Props, and
IClientPortal remain correctly referenced.

In `@frontend/core-ui/src/modules/products/components/ProductsFilter.tsx`:
- Around line 49-53: SelectCategoryProps uses shallow readonly on props while
SelectCategoriesBadgeProps uses Readonly<IProductCategory>; update
SelectCategoryProps so category and selectedCategory use
Readonly<IProductCategory> (keep onSelect signature unchanged) to match deep
immutability pattern and maintain consistency with SelectCategoriesBadgeProps
and related components.

In `@frontend/plugins/content_ui/src/modules/cms/categories/Categories.tsx`:
- Line 59: The Button onClick handlers call setDrawerOpen(true) directly which
bypasses handleAddCategory's logic that clears selectedCategory; update both
Button onClick usages (the one at the top-level Button and the one at line 85)
to call handleAddCategory() instead of setDrawerOpen(true) so selectedCategory
is reset to undefined before opening the drawer and state remains consistent.
- Line 27: Remove the no-op effect in the Categories component: delete the empty
useEffect(() => {}, [location]) call in Categories.tsx (the useEffect import can
also be removed if unused elsewhere) so there is no unused hook referencing
location.
- Around line 115-134: Remove the large commented-out JSX block that contains
CategoriesSidebar, CategoriesRecordTable (with props key={refetchTrigger},
clientPortalId={websiteId || ''}, onEdit={handleEditCategory},
onRemove={handleRemoveCategory}, onBulkDelete={handleBulkDelete}) and
CmsCategoryDrawer (with props category={selectedCategory}, isOpen={drawerOpen},
clientPortalId={websiteId || ''}, onRefetch={refetch}); simply delete that
commented section so the file contains only active code (history is preserved in
VCS).

In
`@frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/usePostForm.tsx`:
- Around line 80-84: Extract the duplicated generateSlug function into a single
shared utility (e.g., export a slugify/generateSlug function from a new module)
and replace the local implementations in usePostForm.tsx, useInlineCategory.ts,
useInlineTag.ts, and usePostSubmission.tsx with imports from that shared module;
ensure the exported function preserves the existing behavior and TypeScript
signature (text: string) => string, update all import sites to use the new
utility name (generateSlug or slugify) and remove the local definitions so all
modules use the centralized implementation.

In `@frontend/plugins/content_ui/src/modules/cms/posts/DateCell.tsx`:
- Around line 4-6: The prop shape for the DateCell component is declared with a
type alias; update it to an interface to match repository TS/TSX standards by
replacing the `type DateCellProps = { readonly date: string; };` declaration
with an equivalent `interface DateCellProps { readonly date: string; }` and
ensure any usages of DateCellProps (e.g., in the DateCell component signature)
remain unchanged other than the new interface form.

In `@frontend/plugins/content_ui/src/modules/cms/shared/Cms.tsx`:
- Around line 14-17: The imports in Cms.tsx use relative paths; update them to
use the project's absolute import aliases instead (replace
../components/websites/WebsiteDrawer, ./CmsLayout, ./EmptyState, and
../graphql/queries with their configured absolute module paths) so that
WebsiteDrawer, CmsLayout, EmptyState, and CONTENT_CMS_LIST are imported via the
project's absolute import root/alias; ensure paths match the tsconfig/webpack
alias and run a quick build to verify no unresolved import errors.
- Line 47: Replace the use of the any type for the editingWebsite state and its
related handler parameters with the concrete Website type (or Website | null for
state) to restore type safety: change the state declaration editingWebsite /
setEditingWebsite to use Website | null instead of any, and update any functions
referenced in this file that accept or return editingWebsite (e.g., the handlers
where editingWebsite is passed/received on lines around the open/edit/save
handlers) to accept Website (or Website | null where appropriate) rather than
any; ensure imports/types reference the existing Website interface and adjust
null checks accordingly.

In `@frontend/plugins/content_ui/src/modules/cms/shared/EmptyState.tsx`:
- Around line 12-20: Extract the inline Readonly prop type into a named
interface (e.g. interface EmptyStateProps) containing icon?: React.ElementType,
title: string, description?: string, actionLabel?: string, onAction?: () =>
void, className?: string, children?: React.ReactNode, then update the EmptyState
component signature to accept Readonly<EmptyStateProps> (or use
React.FC<Readonly<EmptyStateProps>>) so the component uses the new
EmptyStateProps type instead of the inline type; ensure all references to the
props remain unchanged.

In
`@frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/TicketBasicFields.tsx`:
- Line 164: The SortableFieldCardProps interface currently types the control
prop as any; change it to Control<TPipelineConfig> so Form.Field bindings and
path validation get proper types—update the control property in the
SortableFieldCardProps interface (referencing SortableFieldCardProps and the
control field) to use the Control generic with the existing TPipelineConfig
import and ensure any usages of control (e.g., in TicketBasicFields component)
still compile with the stricter type.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ba42fce6-94e2-4b7a-8619-705881581edc

📥 Commits

Reviewing files that changed from the base of the PR and between 6ede5e6 and 5aec591.

📒 Files selected for processing (54)
  • backend/core-api/src/modules/documents/blocksToHtml.ts
  • backend/core-api/src/modules/documents/utils.ts
  • backend/plugins/accounting_api/src/modules/accounting/db/models/Accounts.ts
  • backend/plugins/accounting_api/src/modules/accounting/db/models/AdjustInventories.ts
  • backend/plugins/accounting_api/src/modules/accounting/db/models/CtaxRows.ts
  • backend/plugins/accounting_api/src/modules/accounting/db/models/Transactions.ts
  • backend/plugins/accounting_api/src/modules/accounting/db/models/VatRows.ts
  • backend/plugins/frontline_api/src/modules/integrations/facebook/fieldUtils.ts
  • backend/plugins/frontline_api/src/modules/integrations/facebook/handleFacebookMessage.ts
  • backend/plugins/frontline_api/src/modules/integrations/facebook/utils.ts
  • frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailFacebook.tsx
  • frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailFirebase.tsx
  • frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailGoogle.tsx
  • frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailManual.tsx
  • frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailSMSProviders.tsx
  • frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailSocialPay.tsx
  • frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailToken.tsx
  • frontend/core-ui/src/modules/client-portal/components/ClientPortalDetailToki.tsx
  • frontend/core-ui/src/modules/client-portal/components/ClientPortalMoreColumn.tsx
  • frontend/core-ui/src/modules/products/components/ProductAddSheet.tsx
  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
  • frontend/libs/ui-modules/src/modules/contacts/components/CompanyPhones.tsx
  • frontend/libs/ui-modules/src/modules/contacts/components/CustomerEmails.tsx
  • frontend/libs/ui-modules/src/modules/contacts/components/CustomerPhones.tsx
  • frontend/libs/ui-modules/src/modules/contacts/components/SelectCompany.tsx
  • frontend/libs/ui-modules/src/modules/contacts/components/SelectCustomer.tsx
  • frontend/plugins/content_ui/src/modules/cms/categories/Categories.tsx
  • frontend/plugins/content_ui/src/modules/cms/categories/CategoryDrawer.tsx
  • frontend/plugins/content_ui/src/modules/cms/categories/CmsCategoryDrawer.tsx
  • frontend/plugins/content_ui/src/modules/cms/posts/AudioUploader.tsx
  • frontend/plugins/content_ui/src/modules/cms/posts/DateCell.tsx
  • frontend/plugins/content_ui/src/modules/cms/posts/InlineTagsEditor.tsx
  • frontend/plugins/content_ui/src/modules/cms/posts/PostActions.tsx
  • frontend/plugins/content_ui/src/modules/cms/posts/PostDrawer.tsx
  • frontend/plugins/content_ui/src/modules/cms/posts/TranslationEditor.tsx
  • frontend/plugins/content_ui/src/modules/cms/posts/VideoUploader.tsx
  • frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/useInlineCategory.ts
  • frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/useInlineTag.ts
  • frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/usePostData.tsx
  • frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/usePostForm.tsx
  • frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/usePostSubmission.tsx
  • frontend/plugins/content_ui/src/modules/cms/posts/formHelpers.ts
  • frontend/plugins/content_ui/src/modules/cms/shared/Cms.tsx
  • frontend/plugins/content_ui/src/modules/cms/shared/CmsLayout.tsx
  • frontend/plugins/content_ui/src/modules/cms/shared/EmptyState.tsx
  • frontend/plugins/content_ui/src/modules/cms/shared/IconPicker.tsx
  • frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/ConfigList.tsx
  • frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/ConfigsForm.tsx
  • frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/CreateConfig.tsx
  • frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/PipelineConfigBreadcrumb.tsx
  • frontend/plugins/frontline_ui/src/modules/pipelines/components/configs/components/TicketBasicFields.tsx
  • frontend/plugins/operation_ui/src/modules/team/components/team-details/DeleteTeamForm.tsx
  • frontend/plugins/operation_ui/src/modules/team/components/team-details/EstimateSection.tsx
  • frontend/plugins/operation_ui/src/modules/team/components/team-details/UpdateTeamForm.tsx
💤 Files with no reviewable changes (1)
  • frontend/plugins/operation_ui/src/modules/team/components/team-details/DeleteTeamForm.tsx

Comment on lines +212 to +215
code: dayjs(new Date())
.format('"yyyy-MM-dd HH:mm')
.toString()
.concat('^', accountingObj.code),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

In Day.js, what are the correct format()tokens for a 4-digit year and day of month? Wouldformat('"yyyy-MM-dd HH:mm')produce the intended value, or should it beformat('YYYY-MM-DD HH:mm')?

💡 Result:

In Day.js, the correct format tokens are YYYY for a 4-digit year and DD for the day of the month (2 digits, padded with zero). Neither provided option is fully correct for producing "yyyy-MM-dd HH:mm": - format('"yyyy-MM-dd HH:mm"') treats the string as a literal due to the quotes, outputting the exact string "yyyy-MM-dd HH:mm" without formatting the date. - format('YYYY-MM-DD HH:mm') uses uppercase DD (correct for day), but MM is month (not day) and the dashes are uppercase, though case for separators doesn't matter. The correct string to produce a formatted "2026-03-20 14:30" (example) is format('YYYY-MM-DD HH:mm'). This uses: - YYYY: 4-digit year (e.g., 2026) - MM: 2-digit month (03) - DD: 2-digit day of month (20) - HH: 24-hour (14) - mm: 2-digit minutes (30) Note: Day.js follows Moment.js tokens where YYYY is year (not week-year like in some other libs), DD is day of month, and lowercase yyyy is invalid for year (outputs literal 'yyyy').

Citations:


Use valid Day.js format tokens in the timestamp.

The code uses format('"yyyy-MM-dd HH:mm'), where lowercase yyyy and dd are not valid Day.js tokens. These tokens will output their literal string values instead of the date components, causing the account code to be prefixed with "yyyy-MM-dd HH:mm instead of the intended timestamp. Replace with format('YYYY-MM-DD HH:mm') to use the correct Day.js tokens (YYYY for year, MM for month, DD for day of month).

🛠️ Suggested fix
-            code: dayjs(new Date())
-              .format('"yyyy-MM-dd HH:mm')
+            code: dayjs(new Date())
+              .format('YYYY-MM-DD HH:mm')
               .toString()
               .concat('^', accountingObj.code),
📝 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
code: dayjs(new Date())
.format('"yyyy-MM-dd HH:mm')
.toString()
.concat('^', accountingObj.code),
code: dayjs(new Date())
.format('YYYY-MM-DD HH:mm')
.toString()
.concat('^', accountingObj.code),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/plugins/accounting_api/src/modules/accounting/db/models/Accounts.ts`
around lines 212 - 215, The timestamp format used when building the account code
in Accounts.ts is using invalid Day.js tokens ("yyyy-MM-dd HH:mm") which will be
rendered literally; update the format string in the code assignment that builds
`code: dayjs(new Date()).format(...).toString().concat('^', accountingObj.code)`
to use Day.js tokens `YYYY-MM-DD HH:mm` so the prefix is the actual timestamp
(e.g., change the format argument passed to `dayjs(...).format` in the account
`code` construction).

Comment on lines +189 to 211
public static async cleanAdjustInvDetails({
adjustId,
}: {
adjustId: string;
}) {
await models.AdjustInvDetails.deleteMany({
adjustId,
remainder: { $eq: 0 },
cost: { $eq: 0 },
});
}

public static async cacheAdjustInvDetails({ adjustId }: { adjustId: string }) {
await models.AdjustInvDetails.deleteMany({ adjustId, remainder: { $eq: 0 }, cost: { $eq: 0 } });
public static async cacheAdjustInvDetails({
adjustId,
}: {
adjustId: string;
}) {
await models.AdjustInvDetails.deleteMany({
adjustId,
remainder: { $eq: 0 },
cost: { $eq: 0 },
});
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Duplicate method body should be consolidated

Line 201-210 (cacheAdjustInvDetails) is identical to Line 189-198 (cleanAdjustInvDetails). This is the Sonar warning source and should be deduplicated.

♻️ Suggested change
     public static async cacheAdjustInvDetails({
       adjustId,
     }: {
       adjustId: string;
     }) {
-      await models.AdjustInvDetails.deleteMany({
-        adjustId,
-        remainder: { $eq: 0 },
-        cost: { $eq: 0 },
-      });
+      await this.cleanAdjustInvDetails({ adjustId });
     }
📝 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
public static async cleanAdjustInvDetails({
adjustId,
}: {
adjustId: string;
}) {
await models.AdjustInvDetails.deleteMany({
adjustId,
remainder: { $eq: 0 },
cost: { $eq: 0 },
});
}
public static async cacheAdjustInvDetails({ adjustId }: { adjustId: string }) {
await models.AdjustInvDetails.deleteMany({ adjustId, remainder: { $eq: 0 }, cost: { $eq: 0 } });
public static async cacheAdjustInvDetails({
adjustId,
}: {
adjustId: string;
}) {
await models.AdjustInvDetails.deleteMany({
adjustId,
remainder: { $eq: 0 },
cost: { $eq: 0 },
});
}
public static async cleanAdjustInvDetails({
adjustId,
}: {
adjustId: string;
}) {
await models.AdjustInvDetails.deleteMany({
adjustId,
remainder: { $eq: 0 },
cost: { $eq: 0 },
});
}
public static async cacheAdjustInvDetails({
adjustId,
}: {
adjustId: string;
}) {
await this.cleanAdjustInvDetails({ adjustId });
}
🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis

[warning] 201-201: Update this function so that its implementation is not identical to the one on line 189.

See more on https://sonarcloud.io/project/issues?id=erxes_erxes&issues=AZ0LGrhS2KxiX-UOwvF3&open=AZ0LGrhS2KxiX-UOwvF3&pullRequest=7238

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

In
`@backend/plugins/accounting_api/src/modules/accounting/db/models/AdjustInventories.ts`
around lines 189 - 211, The two static methods cleanAdjustInvDetails and
cacheAdjustInvDetails contain identical bodies; consolidate them by extracting
the shared delete logic (models.AdjustInvDetails.deleteMany with remainder:
{$eq:0}, cost: {$eq:0}) into a single implementation and have the other method
delegate to it (e.g., implement cleanAdjustInvDetails as the actual delete and
make cacheAdjustInvDetails call cleanAdjustInvDetails or create a private helper
like deleteZeroRemainderAndCost used by both) so there is no duplicate code.

Comment on lines +278 to 283
const remainder = fixNum(
(adjustDetail.remainder ?? 0) + multiplier * count,
);
const cost = fixNum((adjustDetail.cost ?? 0) + multiplier * amount);
const unitCost = fixNum(cost / (remainder ?? 1));

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Guard unitCost computation against zero remainder

At Line 282 and Line 303, cost / (remainder ?? 1) still divides by zero when remainder is 0, which can produce Infinity and persist invalid values.

🐛 Suggested fix
-      const unitCost = fixNum(cost / (remainder ?? 1));
+      const unitCost = remainder === 0 ? 0 : fixNum(cost / remainder);
...
-          unitCost: fixNum(cost / (remainder ?? 1)),
+          unitCost,

Also applies to: 301-304

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

In
`@backend/plugins/accounting_api/src/modules/accounting/db/models/AdjustInventories.ts`
around lines 278 - 283, The unitCost calculation can divide by zero because
remainder may be 0; update the computation around the remainder/cost logic
(variables remainder, cost, unitCost, and function fixNum in AdjustInventories)
to guard against zero by detecting if remainder === 0 (or falsy) and handling it
explicitly—e.g., set unitCost to 0 or preserve previous unitCost/default instead
of performing cost / remainder—and then apply fixNum to the final guarded value;
make the same change for the second occurrence later in the file (lines around
the other unitCost calculation).

Comment on lines 360 to +367
{ $match: { 'details.productId': productId } },
{ $group: { _id: { side: '$detail.side' }, remainder: { $sum: '$details.count' }, cost: { $sum: '$detail.amount' } } }
])

const remainder = fixNum(trAggs.reduce((sum, ag) => sum + (ag._id === TR_SIDES.DEBIT ? ag.remainder : -1 * ag.remainder), 0));
const cost = fixNum(trAggs.reduce((sum, ag) => sum + (ag._id === TR_SIDES.DEBIT ? ag.cost : -1 * ag.cost), 0));
{
$group: {
_id: { side: '$detail.side' },
remainder: { $sum: '$details.count' },
cost: { $sum: '$detail.amount' },
},
},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Aggregation uses incorrect field paths and side key shape

Line 363 and Line 365 reference $detail.* instead of $details.* after unwind, and the reduce at Line 374/381 compares against ag._id while _id is currently an object ({ side: ... }). This can miscompute remainder/cost.

🐛 Suggested fix
-        { $match: { 'details.productId': productId } },
+        {
+          $match: {
+            'details.productId': productId,
+            'details.accountId': accountId,
+          },
+        },
         {
           $group: {
-            _id: { side: '$detail.side' },
+            _id: '$details.side',
             remainder: { $sum: '$details.count' },
-            cost: { $sum: '$detail.amount' },
+            cost: { $sum: '$details.amount' },
           },
         },
       ]);

       const remainder = fixNum(
         trAggs.reduce(
           (sum, ag) =>
-            sum +
-            (ag._id === TR_SIDES.DEBIT ? ag.remainder : -1 * ag.remainder),
+            sum + (ag._id === TR_SIDES.DEBIT ? ag.remainder : -ag.remainder),
           0,
         ),
       );
       const cost = fixNum(
         trAggs.reduce(
           (sum, ag) =>
-            sum + (ag._id === TR_SIDES.DEBIT ? ag.cost : -1 * ag.cost),
+            sum + (ag._id === TR_SIDES.DEBIT ? ag.cost : -ag.cost),
           0,
         ),
       );

Also applies to: 371-382

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

In
`@backend/plugins/accounting_api/src/modules/accounting/db/models/AdjustInventories.ts`
around lines 360 - 367, The aggregation pipeline in AdjustInventories.ts uses
wrong field paths and an incorrect _id shape: change all occurrences of
'$detail.*' to '$details.*' in the $group (use _id: { side: '$details.side' },
remainder: { $sum: '$details.count' }, cost: { $sum: '$details.amount' }) and
update the reduce/compare logic that inspects aggregation results to use
ag._id.side (not ag._id) when matching sides; ensure any other reductions or
lookups that referenced detail.amount/detail.count use
details.amount/details.count consistently.

Comment on lines +52 to +54
<audio src={value} controls className="w-full">
<track kind="captions" src="" label="English captions" />
</audio>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In HTML media elements, what happens when <track src=""> is used, and what is the correct way to provide captions for <audio>?

💡 Result:

When a <track src=""> element is used in HTML media elements (<audio> or <video>), the empty src attribute violates the HTML specification requirements. The src attribute must be present and contain a valid non-empty URL. An empty src results in the track URL being set to the empty string, preventing the text track resource from loading. The track's readyState will likely be ERROR (3), as no valid resource can be fetched, and the track provides no functionality—neither cues are loaded nor displayed. The correct way to provide captions for <audio> is to use a <track> element with kind="captions" (or "subtitles"), a valid non-empty src pointing to a WebVTT (.vtt) file, srclang for the language, and optionally label and default. Example: <audio controls> <source src="audio.mp3" type="audio/mpeg"> <track kind="captions" src="captions.vtt" srclang="en" label="English" default> </audio> Native browser support for displaying captions on <audio> is limited or absent because <audio> lacks a visual rendering area (unlike <video>). Browsers load the track and make cues available via the TextTrack API (accessible through audio.textTracks), but do not automatically show them. To display captions, use JavaScript to listen for 'cuechange' events and render the active cue text in a custom element, e.g.: audio.textTracks[0].addEventListener('cuechange', function { document.getElementById('captions-display').textContent = this.activeCues[0]?.text || ''; }); Style the display div as needed. This approach works for both <audio> and <video>.

Citations:


🏁 Script executed:

cat -n frontend/plugins/content_ui/src/modules/cms/posts/AudioUploader.tsx

Repository: erxes/erxes

Length of output: 2915


Remove broken captions track or add support for captions URL prop

The <track> element at line 53 has an empty src="" which violates HTML spec and fails to load. However, the larger issue is that the component only receives an audio file URL—there's no captions data available. Either remove the non-functional track element entirely, or add a captionsUrl prop to the component and conditionally render the track only when a valid captions file is available.

Additionally, note that native <audio> elements don't display captions visually like <video> does. Captions would require manual JavaScript handling via the TextTrack API to render cue text to a custom display element.

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

In `@frontend/plugins/content_ui/src/modules/cms/posts/AudioUploader.tsx` around
lines 52 - 54, The <track> element in AudioUploader is rendered with an empty
src which breaks the HTML spec; either remove the non-functional <track> line
from the JSX in AudioUploader or add a new optional prop (e.g., captionsUrl) and
conditionally render the <track> only when captionsUrl is a non-empty valid
string; if you add captionsUrl, update the AudioUploader props/type and ensure
the render checks captionsUrl before adding <track>, and remember that
displaying captions for audio requires extra TextTrack API handling for visible
captions (so keep the <track> only as a valid source attribute, not as a visual
display).

Comment on lines 139 to 141
const extractText = (html: string): string => {
return html.replace(/<[^>]*>/g, '').trim();
return html.replaceAll(/<[^>]*>/g, '').trim();
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Incomplete HTML sanitization may allow tag injection.

The regex /<[^>]*>/g fails on edge cases like <script without a closing bracket or tags with > inside attribute values (e.g., <a href="x>y">). CodeQL flagged this as a potential HTML injection vector.

Since extractText feeds into computeTitle for fallback titles, malformed HTML in content could survive and cause issues if the title is rendered unsafely downstream.

🛡️ Safer alternative using DOMParser (browser) or a text-content approach
 const extractText = (html: string): string => {
-  return html.replaceAll(/<[^>]*>/g, '').trim();
+  if (typeof DOMParser !== 'undefined') {
+    const doc = new DOMParser().parseFromString(html, 'text/html');
+    return (doc.body.textContent || '').trim();
+  }
+  // Fallback: strip tags more conservatively
+  return html
+    .replaceAll(/<script[\s\S]*?<\/script>/gi, '')
+    .replaceAll(/<[^>]*>/g, '')
+    .trim();
 };
🧰 Tools
🪛 GitHub Check: CodeQL

[failure] 140-140: Incomplete multi-character sanitization
This string may still contain <script, which may cause an HTML element injection vulnerability.

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

In
`@frontend/plugins/content_ui/src/modules/cms/posts/components/add-post-form/hooks/usePostSubmission.tsx`
around lines 139 - 141, The extractText function's regex is unsafe for malformed
HTML and edge cases; update extractText (used by computeTitle) to parse HTML via
the browser DOM instead of regex: create a DOMParser or a temporary
HTMLDivElement, set its innerHTML to the input string, then return the element's
textContent trimmed; wrap parsing in a try/catch and fall back to a conservative
regex strip only on failure to avoid throwing on malicious/malformed input—this
ensures extracted titles are plain text and resilient to broken tags.

Comment on lines +38 to +40
<video src={value} controls className="w-full h-64 object-contain">
<track kind="captions" src="" label="English captions" />
</video>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

For HTML5 <video>/<audio><track>, is empty src valid, and what are required/expected attributes for captions/subtitles (e.g., srcLang, label, valid .vtt URL)?

💡 Result:

No, an empty src attribute is not valid for the HTML5 element in

Citations:


Remove the empty <track> element or provide a valid captions URL

The src="" attribute on line 39 is invalid—the src must reference a real .vtt file. An empty src causes unnecessary failed fetch attempts and creates a broken accessibility feature. Render the <track> element only when a valid captions file is available, and include srcLang to specify the language.

Suggested fix
-            <video src={value} controls className="w-full h-64 object-contain">
-              <track kind="captions" src="" label="English captions" />
-            </video>
+            <video src={value} controls className="w-full h-64 object-contain">
+              {captionsUrl && (
+                <track
+                  kind="captions"
+                  src={captionsUrl}
+                  srcLang="en"
+                  label="English captions"
+                />
+              )}
+            </video>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/plugins/content_ui/src/modules/cms/posts/VideoUploader.tsx` around
lines 38 - 40, In VideoUploader.tsx inside the VideoUploader component, remove
the hard-coded <track src=""> element and instead render a <track> only when a
valid captions URL is present (e.g., a captionsUrl prop/state) and non-empty;
when rendering the track include src, kind="captions", label (e.g., "English
captions") and srcLang (e.g., "en") so the element is valid and accessible.
Locate the video JSX using the value prop and conditionally render the track
based on the captions URL truthiness (or validate it ends with .vtt) to avoid
empty fetches and broken accessibility.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant