You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
Replaced regex-based .replace(/pattern/g, ...) calls with .replaceAll() for HTML entity decoding, slug generation, and text normalization across multiple files.
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.
Added Readonly<...> wrapper or readonly field modifiers to component prop interfaces across 20+ files, enforcing immutability at the TypeScript level without altering runtime behavior.
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.
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
fix:facebook getFileUploadConfigs trpc #6548 – Modifies Facebook integration utilities (utils.ts, error handling, logging) with overlapping changes to token/account error paths and upload-config fetching.
Fix sales bugs #6878 – Modifies SelectCompany.tsx and SelectCustomer.tsx selection/filter logic, sharing code-level changes to membership checks and data filtering.
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.
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.
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.
All changes in this PR are code quality improvements that address SonarQube issues:
.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.
Readonly<Props>: Good TypeScript practice that prevents accidental mutation of props within components.
Unused import cleanup: Reduces bundle size and improves maintainability.
Error handling improvements: Properly checking if caught errors are Error instances before accessing .message prevents runtime crashes when non-Error values are thrown.
Logic inversions: Changing if (!condition) to if (condition) with swapped blocks improves readability by checking the positive case first.
Accessibility improvements: Adding <track> elements to <audio> and <video> components improves accessibility for users who need captions.
Array methods: Using .includes() instead of .find() for existence checks is more semantically correct and potentially more performant.
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.
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.
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.
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.
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.
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.
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.
🟠 HIGHsecurity: 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:
constre=newRegExp(`^${parentAccount.code}.*`);if(!re.test(doc.code)){thrownewError('Code is not validate of parent account');}
Improved code:
constescapeRegExp=(string: string): string=>{returnstring.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');};constre=newRegExp(`^${escapeRegExp(parentAccount.code)}.*`);if(!re.test(doc.code)){thrownewError('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.
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.
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.
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:
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.
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."
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.
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.
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.
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.
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.
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).
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.
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.
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:
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.
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.
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.
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.
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.
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:
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.
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').
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).
‼️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(newDate())
.format('"yyyy-MM-dd HH:mm')
.toString()
.concat('^',accountingObj.code),
code: dayjs(newDate())
.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).
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.
‼️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.
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.
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).
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.
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.
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>.
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).
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
[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.
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
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.
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary by CodeRabbit
Bug Fixes
Refactor
readonlymodifiers to component props and interface propertiesStyle