Skip to content

Conversation

@gabriellsh
Copy link
Member

@gabriellsh gabriellsh commented Oct 15, 2025

Proposed changes (including videos or screenshots)

image

Extension assignment should now be available in the user edit form.

Issue(s)

VGA-4

Steps to test or reproduce

Further comments

Summary by CodeRabbit

  • New Features

    • Voice call extension field added to user edit form and shown in user info panels; Storybook variant added.
  • Refactor

    • Removed separate assign/remove extension modals and related button/actions; extension is now managed via the user edit flow.
  • Tests

    • Added end-to-end tests for extension create/update scenarios; removed legacy modal unit tests.
  • Chores

    • Server-side permission/validation checks added for editing extensions; old extension API route marked deprecated.

@gabriellsh gabriellsh requested a review from a team as a code owner October 15, 2025 21:49
@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Oct 15, 2025

Looks like this PR is ready to merge! 🎉
If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Oct 15, 2025

🦋 Changeset detected

Latest commit: cee38de

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 41 packages
Name Type
@rocket.chat/meteor Minor
@rocket.chat/core-typings Minor
@rocket.chat/rest-typings Minor
@rocket.chat/uikit-playground Patch
@rocket.chat/api-client Patch
@rocket.chat/apps Patch
@rocket.chat/core-services Patch
@rocket.chat/cron Patch
@rocket.chat/ddp-client Patch
@rocket.chat/freeswitch Patch
@rocket.chat/fuselage-ui-kit Major
@rocket.chat/gazzodown Major
@rocket.chat/http-router Patch
@rocket.chat/livechat Patch
@rocket.chat/model-typings Patch
@rocket.chat/ui-avatar Major
@rocket.chat/ui-client Major
@rocket.chat/ui-contexts Major
@rocket.chat/web-ui-registration Major
@rocket.chat/account-service Patch
@rocket.chat/authorization-service Patch
@rocket.chat/ddp-streamer Patch
@rocket.chat/omnichannel-transcript Patch
@rocket.chat/presence-service Patch
@rocket.chat/queue-worker Patch
@rocket.chat/stream-hub-service Patch
@rocket.chat/federation-matrix Patch
@rocket.chat/license Patch
@rocket.chat/media-calls Patch
@rocket.chat/omnichannel-services Patch
@rocket.chat/pdf-worker Patch
@rocket.chat/presence Patch
rocketchat-services Patch
@rocket.chat/models Patch
@rocket.chat/network-broker Patch
@rocket.chat/omni-core-ee Patch
@rocket.chat/mock-providers Patch
@rocket.chat/ui-video-conf Major
@rocket.chat/ui-voip Major
@rocket.chat/instance-status Patch
@rocket.chat/omni-core Patch

Not sure what this means? Click here to learn what changesets are.

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

@gabriellsh gabriellsh marked this pull request as draft October 15, 2025 21:49
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 15, 2025

Walkthrough

Replaces modal-based VoIP extension assignment with an inline Voice_call_extension input across admin/user forms; propagates freeSwitchExtension through client displays, server save/validation, REST typings, and end-to-end tests; removes related modal components, hooks, and their unit tests; adds server-side permission/uniqueness checks and API guard.

Changes

Cohort / File(s) Change Summary
Changeset
\.changeset/shy-bats-worry.md
Adds changeset entry documenting minor bump and UI change from modal to form input.
UserInfo component & stories
apps/meteor/client/components/UserInfo/UserInfo.tsx, apps/meteor/client/components/UserInfo/UserInfo.stories.tsx
Adds freeSwitchExtension prop and conditional Voice_call_extension field; adds WithVoiceCallExtension story variant.
User data propagation
apps/meteor/client/views/admin/users/AdminUserInfoWithData.tsx, apps/meteor/client/views/room/contextualBar/UserInfo/UserInfoWithData.tsx
Extracts and forwards freeSwitchExtension from API user data into UI user objects.
Admin user form
apps/meteor/client/views/admin/users/AdminUserForm.tsx
Adds freeSwitchExtension to props/initial values, renders conditional extension input when permitted, wires control and save payload.
Removed modal UI & actions
apps/meteor/client/views/admin/users/voip/AssignExtensionButton.tsx, apps/meteor/client/views/admin/users/voip/AssignExtensionModal.tsx, apps/meteor/client/views/admin/users/voip/RemoveExtensionModal.tsx, apps/meteor/client/views/admin/users/voip/hooks/useVoipExtensionAction.tsx
Deletes Assign/Remove modal components, AssignExtensionButton, and the useVoipExtensionAction hook.
Removed modal tests
apps/meteor/client/views/admin/users/voip/AssignExtensionModal.spec.tsx, apps/meteor/client/views/admin/users/voip/RemoveExtensionModal.spec.tsx
Removes test suites covering the removed modal components.
Admin UI reference updates
apps/meteor/client/views/admin/users/UsersPageHeaderContent.tsx, apps/meteor/client/views/admin/users/UsersTable/..., apps/meteor/client/views/admin/users/UsersTable/UsersTableRow.tsx, apps/meteor/client/views/admin/users/UsersPageHeaderContent.spec.tsx, apps/meteor/client/views/admin/users/UsersTable/UsersTable.spec.tsx
Removes AssignExtensionButton usage/import, removes voip action wiring, adjusts hook import path, and prunes related unit tests.
Server-side save & validation
apps/meteor/app/lib/server/functions/saveUser/saveUser.ts, apps/meteor/app/lib/server/functions/saveUser/saveNewUser.ts, apps/meteor/app/lib/server/functions/saveUser/validateUserEditing.ts
Adds freeSwitchExtension handling in save flows; introduces canEditExtension to validate permission, feature flag, and uniqueness; integrates checks into create/update flows and throws/returns appropriate errors.
API route guard
apps/meteor/app/api/server/v1/users.ts
Adds guard using canEditExtension in users.create to block unauthorized extension edits.
REST typings
packages/rest-typings/src/v1/users/UserCreateParamsPOST.ts, packages/rest-typings/src/v1/users/UsersUpdateParamsPOST.ts
Adds optional freeSwitchExtension?: string to create/update parameter types and schemas.
End-to-end & test helpers
apps/meteor/tests/end-to-end/api/users.ts, apps/meteor/tests/data/users.helper.ts
Adds EE-gated E2E tests for create/update/conflict/permission scenarios; extends test helper to support freeSwitchExtension.
Enterprise route metadata
apps/meteor/ee/app/api-enterprise/server/voip-freeswitch.ts
Marks voip-freeswitch.extension.assign route deprecated (v8.0.0) with alternative /v1/users.update.

Sequence Diagram(s)

sequenceDiagram
    participant Admin
    participant UI as AdminUserForm (client)
    participant API as REST API (/v1/users.update)
    participant Server as saveUser & validateUserEditing

    rect rgba(46,125,50,0.06)
    Note over Admin,UI: Inline extension edit flow
    Admin->>UI: Open edit form (canManageVoipExtension)
    UI-->>Admin: Show Voice_call_extension input
    Admin->>UI: Enter/modify extension
    Admin->>UI: Click Save
    UI->>API: POST /v1/users.update (payload includes freeSwitchExtension)
    API->>Server: validateUserEditing -> canEditExtension
    alt allowed
        Server->>API: validation OK
        API->>Server: saveUser (persist freeSwitchExtension)
        Server-->>API: Success
        API-->>UI: 200 OK
        UI-->>Admin: Success
    else denied / conflict
        Server-->>API: MeteorError (action not allowed / extension in use)
        API-->>UI: Error
        UI-->>Admin: Error
    end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

stat: ready to merge, stat: QA assured

Suggested reviewers

  • dougfabris
  • MartinSchoeler

Poem

🐰 I swapped the modal for a neat input line,
No popups now, the user edit's fine.
Extensions hop straight into place,
Permissions checked with careful grace.
Hooray — less clicking, more tidy space! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Linked Issues Check ❓ Inconclusive The PR successfully addresses the primary objectives from VGA-4 by replacing the modal-based workflow with a form-based one that allows admins to assign extension numbers directly in the user edit form [AdminUserForm.tsx, UserInfo.tsx]. The implementation includes validation that prevents duplicate extensions by checking if an extension is already assigned to another user and throwing an error to prevent the assignment [validateUserEditing.ts]. The PR also implements permission checks and VoIP enablement verification. However, the provided summaries do not explicitly confirm implementation of RegEx validation against a defined pattern, which is mentioned as a requirement in VGA-4, making it unclear whether this validation criterion is fully satisfied. Verify that the RegEx validation requirement from VGA-4 ("validate assigned extension numbers against the defined regular expression") has been implemented. Review the validation logic in validateUserEditing.ts, saveUser.ts, and related validation files to confirm that extension format validation against a specific RegEx pattern is present and functioning as intended.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "Replace old voice extension assingment flow" clearly describes the primary objective of the changeset. The PR systematically removes the old modal-based assignment workflow (AssignExtensionModal, RemoveExtensionModal, AssignExtensionButton, useVoipExtensionAction) while adding a new form-based approach integrated into the user edit form across both admin and room contexts. The title accurately reflects these core changes, though it contains a typo ("assingment" instead of "assignment").
Out of Scope Changes Check ✅ Passed All changes in this PR are directly related to the core objective of replacing the old voice extension assignment flow. The PR cohesively removes the entire old modal-based workflow (modals, buttons, hooks, and related tests) while introducing the new form-based approach with proper validation, type definitions, and comprehensive test coverage. Supporting changes include deprecation metadata for the old API endpoint, type updates, test helpers, and end-to-end tests, all aligned with the stated objective [voip-freeswitch.ts, UserCreateParamsPOST.ts, UsersUpdateParamsPOST.ts, users.ts e2e tests].
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/voiceExtension

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0b7a7f7 and 2976753.

📒 Files selected for processing (1)
  • apps/meteor/client/views/admin/users/UsersPageHeaderContent.spec.tsx (0 hunks)
💤 Files with no reviewable changes (1)
  • apps/meteor/client/views/admin/users/UsersPageHeaderContent.spec.tsx
⏰ 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: CodeQL-Build
  • GitHub Check: CodeQL-Build

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.

@gabriellsh gabriellsh marked this pull request as ready for review October 16, 2025 19:27
@codecov
Copy link

codecov bot commented Oct 16, 2025

Codecov Report

❌ Patch coverage is 90.00000% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.61%. Comparing base (7a7aad5) to head (cee38de).
⚠️ Report is 1 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #37245      +/-   ##
===========================================
- Coverage    67.69%   67.61%   -0.09%     
===========================================
  Files         3342     3338       -4     
  Lines       114030   113711     -319     
  Branches     20678    20656      -22     
===========================================
- Hits         77197    76889     -308     
+ Misses       34158    34140      -18     
- Partials      2675     2682       +7     
Flag Coverage Δ
e2e 57.40% <50.00%> (+0.06%) ⬆️
unit 71.59% <100.00%> (-0.10%) ⬇️

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.

@scuciatto scuciatto modified the milestones: 7.11.0, 7.12.0 Oct 17, 2025
@gabriellsh gabriellsh requested review from a team as code owners October 17, 2025 18:16
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

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

⚠️ Outside diff range comments (1)
apps/meteor/client/views/admin/users/AdminUserForm.tsx (1)

175-183: Do not send freeSwitchExtension when empty or when user lacks permission

Currently the payload always includes freeSwitchExtension (possibly ''), which may clear the value or violate the server regex. Strip it when the field is not visible (no permission/setting) or when it’s empty/whitespace.

  const handleSaveUser = useEffectEvent(async (userFormPayload: UserFormProps) => {
-    const { avatar, passwordConfirmation, ...userFormData } = userFormPayload;
+    const { avatar, passwordConfirmation, ...userFormData } = userFormPayload;
+
+    // sanitize optional voice extension
+    if (!canManageVoipExtension || !userFormData.freeSwitchExtension?.trim()) {
+      // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
+      delete (userFormData as Partial<UserFormProps>).freeSwitchExtension;
+    }
🧹 Nitpick comments (9)
apps/meteor/app/lib/server/functions/saveUser/validateUserEditing.ts (1)

1-1: Optional refactor: Consider breaking down validation complexity.

The eslint-disable complexity directive suggests this function may benefit from decomposition. While the current implementation is acceptable, consider extracting validation groups into helper functions if complexity increases further.

apps/meteor/tests/end-to-end/api/users.ts (6)

581-589: Consolidate test hooks to avoid linter errors and reduce redundancy

Biome flags duplicate setup/teardown hooks. You can drop this after() entirely; beforeEach already enforces the desired baseline per test. Alternatively, convert both to beforeEach/afterEach if you want symmetry.

Suggested minimal change: remove the after() here.

-			after(async () => {
-				await updateSetting('VoIP_TeamCollab_Enabled', true);
-				await updatePermission('manage-voip-extensions', ['admin']);
-			});

592-614: Make identifiers unique to avoid test pollution across runs

Hardcoding email/username can collide on retries or parallelization. Generate unique values per run.

-						email: 'success_extension_user@rocket.chat',
-						name: 'success_extension_user',
-						username: 'success_extension_user',
+						email: `success_extension_user_${Date.now()}@rocket.chat`,
+						name: `success_extension_user_${Date.now()}`,
+						username: `success_extension_user_${Date.now()}`,

616-619: Minor: prefer idiomatic null-check

user! is unnecessary; just check truthiness.

-				if (user!) {
+				if (user) {
 					await deleteUser(user);
 				}

621-646: Add a regex-negative test to cover invalid extensions

The issue requires validating extensions against a RegEx. Please add a failing case (e.g., non‑digits or wrong length) to assert 400 with the expected errorType.

I can draft an additional it(...) that posts freeSwitchExtension: '12ab' and expects errorType like 'invalid-params' or 'error-extension-invalid' (confirm the exact error key).


2417-2434: Avoid duplicate hooks and tighten isolation

This describe has before, beforeEach, and after. The linter complains about duplicate hooks across the suite. Also, using beforeEach to set settings/permissions is enough; consider removing the after() here, and if you need a fresh user per test, switch to beforeEach to create/delete it per test for isolation.

-			let user: TestUser<IUser>;
-
-			before(async () => {
-				user = await createUser();
-			});
-
-			after(async () => {
-				await Promise.all([
-					deleteUser(user),
-					updateSetting('VoIP_TeamCollab_Enabled', true),
-					updatePermission('manage-voip-extensions', ['admin']),
-				]);
-			});
+			let user: TestUser<IUser>;
+			beforeEach(async () => {
+				user = await createUser();
+			});
+			afterEach(async () => {
+				await deleteUser(user);
+			});

Then keep the existing beforeEach that sets permissions/settings.


2484-2500: Assert the exact error payload for permission and setting checks

Add explicit expectations for errorType to strengthen assertions and maintain consistency with the create‑flow tests.

-					.expect(400)
+					.expect(400)
 					.expect((res) => {
-						expect(res.body).to.have.property('success', false);
+						expect(res.body).to.have.property('success', false);
+						expect(res.body).to.have.property('errorType', 'error-action-not-allowed');
 					});

Similarly for the permission case above, assert errorType 'error-action-not-allowed'.

apps/meteor/client/views/admin/users/AdminUserForm.tsx (2)

58-61: Remove duplicated type field; rely on REST typings

freeSwitchExtension is already in UserCreateParamsPOST. Duplicating it in the intersection risks drift.

-export type UserFormProps = Omit<
-	UserCreateParamsPOST & { avatar: AvatarObject; passwordConfirmation: string; freeSwitchExtension?: string },
-	'fields'
->;
+export type UserFormProps = Omit<UserCreateParamsPOST & { avatar: AvatarObject; passwordConfirmation: string }, 'fields'>;

345-356: Client-side input hints for better UX (numeric only, optional pattern)

Add inputMode='numeric' and optionally a basic pattern to guide users. Keep server as source of truth.

-									render={({ field }) => <TextInput {...field} id={voiceExtensionId} flexGrow={1} />}
+									render={({ field }) => (
+										<TextInput
+											{...field}
+											id={voiceExtensionId}
+											flexGrow={1}
+											inputMode='numeric'
+											autoComplete='off'
+										/>
+									)}

If there is a configurable regex in settings, consider rendering a FieldHint with that pattern.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 37b7766 and f93b8c3.

📒 Files selected for processing (10)
  • apps/meteor/app/api/server/v1/users.ts (2 hunks)
  • apps/meteor/app/lib/server/functions/saveUser/saveNewUser.ts (1 hunks)
  • apps/meteor/app/lib/server/functions/saveUser/saveUser.ts (2 hunks)
  • apps/meteor/app/lib/server/functions/saveUser/validateUserEditing.ts (3 hunks)
  • apps/meteor/client/views/admin/users/AdminUserForm.tsx (6 hunks)
  • apps/meteor/client/views/admin/users/UsersTable/UsersTable.spec.tsx (1 hunks)
  • apps/meteor/tests/data/users.helper.ts (1 hunks)
  • apps/meteor/tests/end-to-end/api/users.ts (2 hunks)
  • packages/rest-typings/src/v1/users/UserCreateParamsPOST.ts (2 hunks)
  • packages/rest-typings/src/v1/users/UsersUpdateParamsPOST.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
apps/meteor/tests/end-to-end/api/users.ts (3)
apps/meteor/tests/data/users.helper.ts (3)
  • TestUser (8-8)
  • deleteUser (55-62)
  • createUser (10-37)
packages/core-typings/src/IUser.ts (1)
  • IUser (186-255)
apps/meteor/tests/data/api-data.ts (2)
  • request (10-10)
  • credentials (39-42)
apps/meteor/client/views/admin/users/AdminUserForm.tsx (3)
packages/rest-typings/src/v1/users/UserCreateParamsPOST.ts (1)
  • UserCreateParamsPOST (8-28)
packages/core-typings/src/IUser.ts (1)
  • AvatarObject (317-317)
apps/meteor/client/views/admin/users/useVoipExtensionPermission.tsx (1)
  • useVoipExtensionPermission (3-8)
apps/meteor/app/api/server/v1/users.ts (1)
apps/meteor/app/lib/server/functions/saveUser/validateUserEditing.ts (1)
  • canEditExtension (15-29)
🪛 Biome (2.1.2)
apps/meteor/tests/end-to-end/api/users.ts

[error] 586-589: Disallow duplicate setup and teardown hooks.

Disallow after duplicacy inside the describe function.

(lint/suspicious/noDuplicateTestHooks)


[error] 2420-2422: Disallow duplicate setup and teardown hooks.

Disallow before duplicacy inside the describe function.

(lint/suspicious/noDuplicateTestHooks)


[error] 2424-2430: Disallow duplicate setup and teardown hooks.

Disallow after duplicacy inside the describe function.

(lint/suspicious/noDuplicateTestHooks)

⏰ 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: CodeQL-Build
🔇 Additional comments (9)
apps/meteor/client/views/admin/users/UsersTable/UsersTable.spec.tsx (1)

1-21: LGTM! Test simplification aligns with UI refactoring.

The removal of VoIP-specific tests and retention of story-based accessibility tests is appropriate given the broader refactoring that moves extension assignment to the user edit form.

apps/meteor/tests/data/users.helper.ts (1)

21-21: LGTM! Test helper properly extended.

The addition of the optional freeSwitchExtension parameter is clean and will be properly included in the request payload via the spread operator.

apps/meteor/app/lib/server/functions/saveUser/saveNewUser.ts (1)

50-52: LGTM! Extension assignment logic is sound.

The check properly ensures that freeSwitchExtension is only set when it's a non-empty string, maintaining data consistency.

apps/meteor/app/api/server/v1/users.ts (2)

59-59: Import added for extension validation.

The canEditExtension function is properly imported for use in the user creation flow.


329-331: The race condition risk is already mitigated by an existing database unique index.

The verification confirms that a unique index on freeSwitchExtension already exists in the Users model schema (packages/models/src/models/Users.ts:96), configured as { key: { freeSwitchExtension: 1 }, sparse: true, unique: true }. This provides atomic enforcement at the database level, which is the preferred mitigation option mentioned in the review comment. Even if a concurrent request creates a gap between the canEditExtension check and the save operation, the database constraint will prevent duplicate extensions from being persisted.

No code changes are required.

apps/meteor/app/lib/server/functions/saveUser/saveUser.ts (2)

57-57: LGTM! Type definition properly extended.

The addition of freeSwitchExtension to SaveUserData is clean and consistent with other optional fields.


167-173: LGTM! Extension update logic handles all cases correctly.

The logic properly:

  • Only processes changes when the value differs from the current extension
  • Unsets the field when an empty/whitespace value is provided
  • Sets the new value for valid extensions
  • Relies on validateUserEditing (line 105) for permission and uniqueness checks within the transaction
apps/meteor/app/lib/server/functions/saveUser/validateUserEditing.ts (2)

15-29: LGTM! Extension validation logic is well-structured.

The canEditExtension function properly validates:

  • VoIP feature enablement
  • User permissions
  • Extension uniqueness

The uniqueness check at line 24 will throw an error if the extension is already assigned, preventing duplicate assignments.

However, runtime uniqueness checks are vulnerable to race conditions without database-level enforcement. Run the verification script from the comment on users.ts:329-331 to confirm a unique index exists on freeSwitchExtension.


118-126: LGTM! Proper validation for extension editing.

The validation correctly:

  • Uses isEditingField to detect actual changes (line 119), preventing unnecessary validation when a user retains their current extension
  • Calls canEditExtension with the new extension value for permission and uniqueness checks

@gabriellsh gabriellsh added the stat: QA assured Means it has been tested and approved by a company insider label Oct 20, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Oct 20, 2025
@dionisio-bot dionisio-bot bot removed the stat: ready to merge PR tested and approved waiting for merge label Oct 20, 2025
@gabriellsh gabriellsh added stat: QA assured Means it has been tested and approved by a company insider and removed stat: QA assured Means it has been tested and approved by a company insider labels Oct 20, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Oct 20, 2025
@kodiakhq kodiakhq bot merged commit 0870d72 into develop Oct 21, 2025
84 of 86 checks passed
@kodiakhq kodiakhq bot deleted the chore/voiceExtension branch October 21, 2025 02:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stat: QA assured Means it has been tested and approved by a company insider stat: ready to merge PR tested and approved waiting for merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants