Skip to content

fix: remove unsafe any in AddCustomSound and EditSound#38940

Open
Agarwalchetan wants to merge 6 commits intoRocketChat:developfrom
Agarwalchetan:fix/custom-sound-any-types
Open

fix: remove unsafe any in AddCustomSound and EditSound#38940
Agarwalchetan wants to merge 6 commits intoRocketChat:developfrom
Agarwalchetan:fix/custom-sound-any-types

Conversation

@Agarwalchetan
Copy link
Copy Markdown
Contributor

@Agarwalchetan Agarwalchetan commented Feb 23, 2026

Related Issue / Discussion:

Fixes FIXME comments in:

  • AddCustomSound.tsx
  • EditSound.tsx

Changes:

  • Modified apps/meteor/client/views/admin/customSounds/lib.ts

    • Relaxed createSoundData first parameter from ICustomSoundFile to { name: string }
    • No runtime behavior change — function only uses .name
  • Modified AddCustomSound.tsx

    • Replaced soundFile: any with soundFile: File
    • Updated state type to useState<File>()
    • Removed FIXME comment
    • Added guard to prevent undefined file submission
  • Modified EditSound.tsx

    • Replaced sound: any with SoundFile union (File | ExistingSound)
    • Added proper instanceof File narrowing before:
      • validate
      • FileReader
      • .type access
    • Removed FIXME comment
    • Ensured safe extension handling

Further Details:

Summary

This PR removes unsafe any usage in the custom sounds admin components and replaces it with properly narrowed TypeScript types.

Key improvements:

  • Introduces a safe File | ExistingSound union in EditSound
  • Uses instanceof File guards before all File-specific APIs
  • Keeps ICustomSoundFile private to lib.ts
  • Relaxes createSoundData parameter to match actual usage ({ name: string })
  • No runtime logic changes
  • Pure type-safety improvement

Behaviour Before

  • any allowed unsafe .type access
  • TypeScript could not guarantee correctness
  • FIXME comments left in code

Behaviour After

  • All any removed
  • Proper narrowing before File-specific logic
  • Type-safe validation flow
  • No runtime behavior changes

Verification

  • tsc --noEmit passes for modified files
  • ESLint clean (no new errors introduced)
  • Prettier formatted
  • No test changes required (type-level fix only)

Summary by CodeRabbit

  • New Features

    • Save button in Admin Custom Sounds is disabled until both a sound file and name are provided.
  • Bug Fixes

    • Prevents saving when sound or name is missing with an added runtime guard.
    • More reliable edit flow: edits now correctly distinguish new file uploads from existing sounds, improving validation and upload behaviors.
  • Tests

    • Added isolation mocks for translation and toast utilities in markup tests.

COMM-144

Relax createSoundData soundFile param to { name: string } since only .name is used.
AddCustomSound: soundFile: any -> File, update state type, add undefined guard.
EditSound: add SoundFile union, narrow with instanceof File before validate/FileReader.

Fixes FIXME comments in both components.
@Agarwalchetan Agarwalchetan requested a review from a team as a code owner February 23, 2026 17:31
@dionisio-bot
Copy link
Copy Markdown
Contributor

dionisio-bot bot commented Feb 23, 2026

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is targeting the wrong base branch. It should target 8.4.0, but it targets 8.3.0

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Feb 23, 2026

⚠️ No Changeset found

Latest commit: 03277d0

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 23, 2026

Walkthrough

Switches custom-sounds admin UI to use File-typed sound state, differentiates uploaded Files from existing sounds in save/validation flows, narrows createSoundData parameter type, adds Save-button and runtime guards to prevent saving without name and file, and adds test mocks for i18n/toast.

Changes

Cohort / File(s) Summary
Add: Save guard & File type
apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx
Changed sound state to File, saveAction parameter to File, added Save button disabled when sound or name missing, and added runtime guard (!sound) in handleSave.
Edit: Existing vs Uploaded sound handling
apps/meteor/client/views/admin/customSounds/EditSound.tsx
Added ExistingSound and SoundFile types; saveAction now accepts SoundFile; logic distinguishes File instances from existing sounds for validation, extension handling, and upload UI/flow (uses instanceof File).
Lib: Narrowed createSoundData parameter
apps/meteor/client/views/admin/customSounds/lib.ts
Updated createSoundData signature: soundFile type narrowed from ICustomSoundFile to { name: string }, preserving use of soundFile.name.
Tests: added mocks
packages/gazzodown/src/Markup.spec.tsx
Added Jest mocks for react-i18next and @rocket.chat/ui-contexts to stub translation (t) and toast dispatch in tests.
Manifest
package.json
Touched (metadata/config recorded in diff).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I nudged the files with gentle paws,

Files and names now know their laws.
Save waits patient, neither lost nor wild,
Old sounds stay safe, new ones join the pile.
A little hop — the admin's reconciled.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly summarizes the main change: removing unsafe any type annotations in AddCustomSound and EditSound components, which is the primary focus of the changeset.
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.


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.

@Agarwalchetan Agarwalchetan changed the title Fix any type in AddCustomSound and EditSound (customSounds admin) fix: remove unsafe any in AddCustomSound and EditSound Feb 23, 2026
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-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.

1 issue found across 3 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx">

<violation number="1" location="apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx:75">
P2: Early return on missing sound file bypasses validation/toast errors, making Save a silent no-op when no file is selected (regression of required-field feedback).</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/meteor/client/views/admin/customSounds/EditSound.tsx (1)

21-27: ExistingSound duplicates EditSoundProps['data'] — consider unifying.

ExistingSound is structurally identical to the inline data type in EditSoundProps. Additionally, the existing useState type annotation (lines 38–45) now manually duplicates the SoundFile union instead of referencing it.

♻️ Suggested consolidation
-type ExistingSound = {
-	_id: string;
-	name: string;
-	extension?: string;
-};
-
-type SoundFile = File | ExistingSound;

 type EditSoundProps = {
 	close?: () => void;
 	onChange: () => void;
-	data: {
-		_id: string;
-		name: string;
-		extension?: string;
-	};
+	data: ExistingSound;
 };
+
+type ExistingSound = {
+	_id: string;
+	name: string;
+	extension?: string;
+};
+
+type SoundFile = File | ExistingSound;

And update the useState to use the alias:

-	const [sound, setSound] = useState<
-		| {
-				_id: string;
-				name: string;
-				extension?: string;
-		  }
-		| File
-	>(() => data);
+	const [sound, setSound] = useState<SoundFile>(() => data);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/meteor/client/views/admin/customSounds/EditSound.tsx` around lines 21 -
27, ExistingSound duplicates the inline type used as EditSoundProps['data'] and
SoundFile union was re-declared instead of being reused; replace the inline data
type in EditSoundProps with a reference to the ExistingSound alias (or remove
ExistingSound and export/reuse EditSoundProps['data'] as a single shared type)
and update the useState type annotation to reference the SoundFile alias rather
than re-declaring the union, ensuring components like EditSound and any state
variables consistently use ExistingSound, SoundFile and EditSoundProps['data']
as the single source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx`:
- Around line 75-77: The current early return in AddCustomSound's saveAction
causes a silent no-op when sound is undefined; instead disable the Save action
at the source: remove the silent-return behavior in saveAction/handleSave and
change the Save button's disabled prop (the component rendering Save in
AddCustomSound) to be true when sound is falsy or validation errors exist (e.g.,
disabled={!sound || hasValidationErrors}). If you prefer the alternate fix,
replace the return inside saveAction with dispatching the existing error toast
(used by handleSave's catch) so users get feedback when no file is selected;
reference saveAction, validate, handleSave and the Save button component to
implement the change.

---

Nitpick comments:
In `@apps/meteor/client/views/admin/customSounds/EditSound.tsx`:
- Around line 21-27: ExistingSound duplicates the inline type used as
EditSoundProps['data'] and SoundFile union was re-declared instead of being
reused; replace the inline data type in EditSoundProps with a reference to the
ExistingSound alias (or remove ExistingSound and export/reuse
EditSoundProps['data'] as a single shared type) and update the useState type
annotation to reference the SoundFile alias rather than re-declaring the union,
ensuring components like EditSound and any state variables consistently use
ExistingSound, SoundFile and EditSoundProps['data'] as the single source of
truth.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fbb5136 and d140540.

📒 Files selected for processing (3)
  • apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx
  • apps/meteor/client/views/admin/customSounds/EditSound.tsx
  • apps/meteor/client/views/admin/customSounds/lib.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: cubic · AI code reviewer
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/client/views/admin/customSounds/EditSound.tsx
  • apps/meteor/client/views/admin/customSounds/lib.ts
  • apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx
🧠 Learnings (2)
📚 Learning: 2026-01-17T01:51:47.764Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38219
File: packages/core-typings/src/cloud/Announcement.ts:5-6
Timestamp: 2026-01-17T01:51:47.764Z
Learning: In packages/core-typings/src/cloud/Announcement.ts, the AnnouncementSchema.createdBy field intentionally overrides IBannerSchema.createdBy (object with _id and optional username) with a string enum ['cloud', 'system'] to match existing runtime behavior. This is documented as technical debt with a FIXME comment at apps/meteor/app/cloud/server/functions/syncWorkspace/handleCommsSync.ts:53 and should not be flagged as an error until the runtime behavior is corrected.

Applied to files:

  • apps/meteor/client/views/admin/customSounds/lib.ts
📚 Learning: 2026-02-10T16:32:42.586Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 38528
File: apps/meteor/client/startup/roles.ts:14-14
Timestamp: 2026-02-10T16:32:42.586Z
Learning: In Rocket.Chat's Meteor client code, DDP streams use EJSON and Date fields arrive as Date objects; do not manually construct new Date() in stream handlers (for example, in sdk.stream()). Only REST API responses return plain JSON where dates are strings, so implement explicit conversion there if needed. Apply this guidance to all TypeScript files under apps/meteor/client to ensure consistent date handling in DDP streams and REST responses.

Applied to files:

  • apps/meteor/client/views/admin/customSounds/lib.ts
🧬 Code graph analysis (1)
apps/meteor/client/views/admin/customSounds/EditSound.tsx (1)
apps/meteor/client/views/admin/customSounds/lib.ts (2)
  • createSoundData (32-61)
  • validate (10-30)
🔇 Additional comments (4)
apps/meteor/client/views/admin/customSounds/lib.ts (1)

33-33: LGTM — correct parameter narrowing.

Relaxing soundFile from ICustomSoundFile to { name: string } is accurate: only soundFile.name is accessed inside the function body. ICustomSoundFile still serves validate, so no dead code is introduced.

apps/meteor/client/views/admin/customSounds/EditSound.tsx (1)

63-70: LGTM — instanceof File narrowing is correct.

soundFile is correctly resolved to sound (a File) or undefined before being forwarded to validate, and the upload branch is gated on instanceof File. The extension field threaded through previousData (line 68) is accepted by createSoundData's type but is never read by the function (it always derives extension from soundFile.name), so the computed value is silently discarded. This is a pre-existing quirk of lib.ts's previousData shape and not introduced by this PR, but worth noting if lib.ts is refactored later.

apps/meteor/client/views/admin/customSounds/AddCustomSound.tsx (2)

22-22: LGTM — useState<File>() is clean.


34-34: LGTM — soundFile: File correctly replaces any.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/gazzodown/src/Markup.spec.tsx (1)

11-17: Use jest.requireActual to avoid silently clobbering other module exports.

Both mocks replace the entire module with a single-property object. Any other named export from react-i18next (e.g. Trans) or @rocket.chat/ui-contexts (e.g. useEndpoint, constants, types re-exported as values) will resolve to undefined inside the test environment. The idiomatic fix is to spread the actual module and override only the targeted export: { ...jest.requireActual('module'), targetHook: mockImpl }.

♻️ Proposed fix
-jest.mock('react-i18next', () => ({
-	useTranslation: () => ({ t: (key: string) => key }),
-}));
-
-jest.mock('@rocket.chat/ui-contexts', () => ({
-	useToastMessageDispatch: () => (): void => undefined,
-}));
+jest.mock('react-i18next', () => ({
+	...jest.requireActual('react-i18next'),
+	useTranslation: () => ({ t: (key: string) => key }),
+}));
+
+jest.mock('@rocket.chat/ui-contexts', () => ({
+	...jest.requireActual('@rocket.chat/ui-contexts'),
+	useToastMessageDispatch: () => (): void => undefined,
+}));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/gazzodown/src/Markup.spec.tsx` around lines 11 - 17, The current
tests fully replace the react-i18next and `@rocket.chat/ui-contexts` modules which
can clobber other exports; update the mocks to spread the real module and
override only the specific hooks by using jest.requireActual('react-i18next')
and jest.requireActual('@rocket.chat/ui-contexts') and return { ...actual,
useTranslation: () => ({ t: (key: string) => key }) } and { ...actual,
useToastMessageDispatch: () => (): void => undefined } respectively so other
named exports (e.g. Trans, useEndpoint) remain available.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/gazzodown/src/Markup.spec.tsx`:
- Around line 11-17: The current tests fully replace the react-i18next and
`@rocket.chat/ui-contexts` modules which can clobber other exports; update the
mocks to spread the real module and override only the specific hooks by using
jest.requireActual('react-i18next') and
jest.requireActual('@rocket.chat/ui-contexts') and return { ...actual,
useTranslation: () => ({ t: (key: string) => key }) } and { ...actual,
useToastMessageDispatch: () => (): void => undefined } respectively so other
named exports (e.g. Trans, useEndpoint) remain available.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1bb2875 and 03277d0.

📒 Files selected for processing (1)
  • packages/gazzodown/src/Markup.spec.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • packages/gazzodown/src/Markup.spec.tsx
🧠 Learnings (7)
📚 Learning: 2025-12-10T21:00:54.909Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37091
File: ee/packages/abac/jest.config.ts:4-7
Timestamp: 2025-12-10T21:00:54.909Z
Learning: Rocket.Chat monorepo: Jest testMatch pattern '<rootDir>/src/**/*.spec.(ts|js|mjs)' is valid in this repo and used across multiple packages (e.g., packages/tools, ee/packages/omnichannel-services). Do not flag it as invalid in future reviews.

Applied to files:

  • packages/gazzodown/src/Markup.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Utilize Playwright fixtures (`test`, `page`, `expect`) for consistency in test files

Applied to files:

  • packages/gazzodown/src/Markup.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `expect` matchers for assertions (`toEqual`, `toContain`, `toBeTruthy`, `toHaveLength`, etc.) instead of `assert` statements in Playwright tests

Applied to files:

  • packages/gazzodown/src/Markup.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Maintain test isolation between test cases in Playwright tests

Applied to files:

  • packages/gazzodown/src/Markup.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Prefer web-first assertions (`toBeVisible`, `toHaveText`, etc.) in Playwright tests

Applied to files:

  • packages/gazzodown/src/Markup.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure tests run reliably in parallel without shared state conflicts

Applied to files:

  • packages/gazzodown/src/Markup.spec.tsx
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to **/*.spec.ts : Use descriptive test names that clearly communicate expected behavior in Playwright tests

Applied to files:

  • packages/gazzodown/src/Markup.spec.tsx
🔇 Additional comments (1)
packages/gazzodown/src/Markup.spec.tsx (1)

15-17: The mock is correctly placed and necessary.

@rocket.chat/ui-contexts is an explicit dependency of the gazzodown package, and CodeBlock.tsx (a child component rendered by Markup) imports and uses useToastMessageDispatch on line 32. The mock in Markup.spec.tsx is required to test the Markup component and its child components.

Likely an incorrect or invalid review comment.

@KevLehman KevLehman added the valid A valid contribution where maintainers will review based on priority label Feb 23, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Feb 23, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 70.63%. Comparing base (fbb5136) to head (03277d0).
⚠️ Report is 143 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #38940      +/-   ##
===========================================
+ Coverage    70.56%   70.63%   +0.07%     
===========================================
  Files         3189     3189              
  Lines       112701   112717      +16     
  Branches     20428    20383      -45     
===========================================
+ Hits         79526    79618      +92     
+ Misses       31114    31053      -61     
+ Partials      2061     2046      -15     
Flag Coverage Δ
e2e 60.37% <ø> (-0.01%) ⬇️
e2e-api 47.87% <ø> (+0.08%) ⬆️
unit 71.19% <ø> (-0.35%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Agarwalchetan
Copy link
Copy Markdown
Contributor Author

Hi, just a gentle follow-up on this PR
Please let me know if any changes or clarifications are needed.
Happy to update accordingly.

@ggazzo ggazzo added this to the 8.3.0 milestone Feb 27, 2026
@scuciatto scuciatto modified the milestones: 8.3.0, 8.4.0 Mar 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community valid A valid contribution where maintainers will review based on priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants