Skip to content

Conversation

@aleksandernsilva
Copy link
Contributor

@aleksandernsilva aleksandernsilva commented Sep 30, 2025

Proposed changes (including videos or screenshots)

This PR adjusts the validations for accessing the outbound message feature, allowing community workspaces to access the upsell flow.

Issue(s)

CTZ-348

Steps to test or reproduce

  • Access a Community Edition workspace
  • Create new
  • Outbound message option should be visible
  • Clicking should display upsell modal

Further comments

Summary by CodeRabbit

  • New Features

    • Wizard now shows an explicit error when Omnichannel is disabled and refines upsell/modal gating for outbound messaging.
    • Outbound message UI flows respect Omnichannel enablement, required modules, and user permission before proceeding.
  • Accessibility

    • Loading state announced to assistive tech (role=status, aria-busy).
  • Refactor

    • Outbound access checks unified across menus, buttons, and provider lists via a single access hook.
  • Tests

    • Expanded tests for loading, unauthorized, omnichannel-disabled scenarios and new access-hook coverage.

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Sep 30, 2025

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

  • This PR is missing the 'stat: QA assured' label

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Sep 30, 2025

⚠️ No Changeset found

Latest commit: 41e9ad5

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
Contributor

coderabbitai bot commented Sep 30, 2025

Walkthrough

Replaces scattered outbound-message permission/license checks with a new useOutboundMessageAccess hook; wires omnichannel-enabled guards and upsell gating into the OutboundMessageWizard; updates providers gating and modal exports; and adjusts tests to provide OmnichannelContext and ARIA loading attributes.

Changes

Cohort / File(s) Summary
Access hook & tests
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.ts, apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.spec.ts, apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/index.ts
Add useOutboundMessageAccess (boolean hook) with tests; re-export it from hooks index.
UI adoption (entry points)
apps/meteor/client/NavBarV2/NavBarPagesGroup/hooks/useCreateNewItems.tsx, apps/meteor/client/sidebar/header/actions/hooks/useCreateRoomItems.tsx, apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoOutboundMessageButton.tsx
Replace direct usePermission/license checks with useOutboundMessageAccess() to gate outbound-message UI actions.
Wizard flow & gating
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.tsx, .../OutboundMessageWizard/components/OutboundMessageWizardSkeleton.tsx
Add useOmnichannelEnabled guard (early error state), switch to useLayoutEffect for upsell gating, and add role="status" aria-busy="true" to skeleton.
Providers gating
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundProvidersList.ts
Expand providers gating to require omnichannel enabled, outbound-messaging module, and outbound-send permission (plus existing enabled flag).
Modals export
apps/meteor/client/components/Omnichannel/OutboundMessage/modals/index.ts
Re-export OutboundMessageModal alongside existing upsell modal.
Tests & context wiring
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.spec.tsx, apps/meteor/client/components/Omnichannel/OutboundMessage/forms/RecipientForm/RecipientForm.spec.tsx
Update tests to provide OmnichannelContext, toggle omnichannelEnabled, cover loading/error/unauthorized/upsell scenarios, and use screen queries.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as UI Entrypoints\n(Create New / Sidebar / Contact Info)
  participant Access as useOutboundMessageAccess
  participant Flags as Hooks\n(useOmnichannelEnabled / useHasLicenseModule / usePermission)

  User->>UI: open action menu
  UI->>Access: canSendOutboundMessage?
  Access->>Flags: isOmnichannelEnabled()
  alt Omnichannel disabled
    Access-->>UI: false
    UI-->>User: hide action
  else
    Access->>Flags: has livechat-enterprise? / has outbound-messaging?
    alt Any module missing
      Access-->>UI: true (upsell path)
      UI-->>User: show action (may open upsell)
    else All modules present
      Access->>Flags: has 'outbound.send-messages'?
      Access-->>UI: true / false
      UI-->>User: show / hide action
    end
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant Wizard as OutboundMessageWizard
  participant Env as useOmnichannelEnabled
  participant Lic as useHasLicenseModule
  participant Prov as Providers API
  participant Upsell as Upsell Modal

  User->>Wizard: open wizard
  Wizard->>Env: isOmnichannelEnabled?
  alt Not enabled
    Wizard-->>User: render error state
  else Enabled
    Wizard->>Lic: check livechat-enterprise & outbound-messaging
    Wizard->>Prov: fetch providers
    alt Modules & providers present
      Wizard-->>User: render wizard UI
    else Missing module/provider
      Wizard->>Upsell: open upsell modal
      Upsell-->>User: show upsell
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

stat: ready to merge, stat: QA assured

Suggested reviewers

  • tassoevan
  • dougfabris

Poem

I’m a rabbit in the code, nose twitching bright,
New hooks hop in to check permissions right.
Wizards peek the burrow — enabled? licensed? clear —
If not, an upsell carrot will soon appear.
Tests and ARIA sing — the outbound path hops near. 🥕🐇

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly identifies the primary change as addressing a regression in outbound message permissions visibility in Community Edition and directly relates to the linked issue and code modifications implemented in this pull request. It is concise, specific, and informs a reviewer of the key problem and context without extraneous detail.
Linked Issues Check ✅ Passed The updates introduce a new access hook for outbound messaging, replace direct permission checks in menu and button components with this hook, and adjust the wizard and tests to ensure the upsell modal appears in Community Edition as required, thereby restoring visibility under “Create New,” maintaining outbound-send permissions, and triggering the upsell flow on click as specified in CTZ-348.
Out of Scope Changes Check ✅ Passed All code changes focus exclusively on outbound messaging permission gating, menu item visibility, upsell modal behavior, and related test adjustments to satisfy the regression fix for Community Edition, with no unrelated features or modules modified.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch regression/outbound-comms-permissions

📜 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 bec9718 and 41e9ad5.

📒 Files selected for processing (12)
  • apps/meteor/client/NavBarV2/NavBarPagesGroup/hooks/useCreateNewItems.tsx (2 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.spec.tsx (4 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.tsx (4 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/components/OutboundMessageWizardSkeleton.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.spec.tsx (2 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/index.ts (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.spec.ts (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.ts (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundProvidersList.ts (2 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/modals/index.ts (1 hunks)
  • apps/meteor/client/sidebar/header/actions/hooks/useCreateRoomItems.tsx (2 hunks)
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoOutboundMessageButton.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.spec.tsx
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.spec.tsx
  • apps/meteor/client/sidebar/header/actions/hooks/useCreateRoomItems.tsx
  • apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.ts
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/components/OutboundMessageWizardSkeleton.tsx
  • apps/meteor/client/NavBarV2/NavBarPagesGroup/hooks/useCreateNewItems.tsx
🧰 Additional context used
🧬 Code graph analysis (3)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundProvidersList.ts (2)
packages/ui-contexts/src/index.ts (1)
  • usePermission (55-55)
apps/meteor/client/lib/queryKeys.ts (1)
  • omnichannelQueryKeys (30-84)
apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoOutboundMessageButton.tsx (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.ts (1)
  • useOutboundMessageAccess (6-21)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.spec.ts (2)
packages/ui-contexts/src/index.ts (1)
  • usePermission (55-55)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.ts (1)
  • useOutboundMessageAccess (6-21)
⏰ 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 (10)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.spec.ts (4)

1-23: LGTM: Clean test setup with proper mocking.

The test file correctly mocks all three dependencies (usePermission, useOmnichannelEnabled, useHasLicenseModule) and follows standard testing-library patterns. The mock setup is clean and reusable across test cases.


29-36: LGTM: Correctly tests the omnichannel-disabled guard.

This test verifies that when isOmnichannelEnabled is false, the hook returns false regardless of other conditions (module/permission state). This matches the early-return guard in the implementation.


38-63: LGTM: Comprehensive upsell scenario coverage.

These three test cases thoroughly cover the upsell logic:

  1. Missing livechat-enterprise module
  2. Missing outbound-messaging module
  3. Both modules missing

All correctly expect true to enable the upsell flow. The mock implementation pattern using a predicate function is appropriate for testing selective module availability.


65-81: LGTM: Permission gating tests are correct.

The final two test cases verify the permission check logic when all modules are present:

  • Line 65-72: All conditions met + permission → true
  • Line 74-81: All conditions met but no permission → false

This correctly validates the permission-based access control.

apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/index.ts (1)

1-1: LGTM: Standard barrel export pattern.

Clean re-export enabling consumers to import useOutboundMessageAccess from the hooks index.

apps/meteor/client/components/Omnichannel/OutboundMessage/modals/index.ts (1)

2-2: LGTM: Adds OutboundMessageModal to public exports.

Complements the existing upsell modal export, enabling consumers to import both modals from the index.

apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoOutboundMessageButton.tsx (1)

4-4: LGTM: Clean refactoring consolidates access logic.

The component now delegates all permission/license/omnichannel checks to the centralized useOutboundMessageAccess hook, replacing scattered individual checks. This improves maintainability and ensures consistent gating logic across the application.

Also applies to: 17-21

apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.tsx (3)

79-87: Verify useLayoutEffect necessity for upsell gating.

The change from useEffect to useLayoutEffect (line 79) makes the upsell modal logic run synchronously before the browser paints. While this prevents visual flicker, it can block rendering.

Questions to consider:

  • Is the synchronous blocking justified here? The upsell modal appears to be a one-time check that could tolerate a brief render before showing.
  • Are there performance implications if isLoadingModule or isLoadingProviders take time to resolve?

If the goal is to prevent users from seeing the wizard UI before the upsell modal, consider whether the existing loading skeleton (line 162) already provides adequate UX, making useLayoutEffect unnecessary.

Alternatively, if synchronous gating is required, document why in a comment:

+// Use layout effect to gate upsell synchronously before paint, preventing wizard UI flash
 useLayoutEffect(() => {

84-86: LGTM: Upsell triggers correctly for missing modules or providers.

The condition !hasOmnichannelModule || !hasOutboundModule || !hasProviders correctly opens the upsell modal when:

  • Omnichannel enterprise module is missing
  • Outbound messaging module is missing
  • No providers are configured

This aligns with the PR objective to show the upsell flow in Community Edition.

Note: This logic depends on the provider list query being enabled (see critical issue in useOutboundProvidersList.ts). Once that's fixed to use useOmnichannelEnabled(), this upsell detection will work correctly in Community Edition.


151-153: LGTM: Adds defensive omnichannel-enabled guard.

The early guard prevents access when Omnichannel is completely disabled, providing a clear error message before evaluating permissions. This is good defensive programming and improves the user experience with an explicit error state.


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.

@aleksandernsilva aleksandernsilva added this to the 7.11.0 milestone Sep 30, 2025
@codecov
Copy link

codecov bot commented Sep 30, 2025

Codecov Report

❌ Patch coverage is 97.87234% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 67.43%. Comparing base (1d0fc48) to head (41e9ad5).
⚠️ Report is 1 commits behind head on release-7.11.0.

Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##           release-7.11.0   #37107      +/-   ##
==================================================
+ Coverage           67.39%   67.43%   +0.03%     
==================================================
  Files                3328     3329       +1     
  Lines              113353   113387      +34     
  Branches            20568    20576       +8     
==================================================
+ Hits                76399    76462      +63     
+ Misses              34348    34327      -21     
+ Partials             2606     2598       -8     
Flag Coverage Δ
e2e 57.28% <44.00%> (+0.02%) ⬆️
unit 71.20% <100.00%> (+0.03%) ⬆️

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.

@aleksandernsilva aleksandernsilva marked this pull request as ready for review October 1, 2025 12:50
@aleksandernsilva aleksandernsilva requested a review from a team as a code owner October 1, 2025 12:50
Copilot AI review requested due to automatic review settings October 1, 2025 12:50
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR moves outbound messaging permissions from the enterprise-only Livechat module to the common authorization system, making these permissions available in Community Edition workspaces to enable the feature upsell flow.

  • Removes four outbound messaging permissions from the enterprise-specific omnichannelEEPermissions array
  • Adds the same four permissions to the general permissions array in the authorization module

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
apps/meteor/ee/app/livechat-enterprise/server/permissions.ts Removes outbound messaging permissions from enterprise-only permissions
apps/meteor/app/authorization/server/constant/permissions.ts Adds outbound messaging permissions to common authorization system

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@aleksandernsilva aleksandernsilva marked this pull request as draft October 1, 2025 14:41
@aleksandernsilva aleksandernsilva force-pushed the regression/outbound-comms-permissions branch from ba32d56 to 5621ef8 Compare October 1, 2025 17:51
@aleksandernsilva aleksandernsilva marked this pull request as ready for review October 1, 2025 17:57
@aleksandernsilva aleksandernsilva requested a review from a team as a code owner October 1, 2025 17:57
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: 3

🧹 Nitpick comments (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.tsx (1)

79-87: Verify useLayoutEffect is necessary.

Switching to useLayoutEffect prevents the wizard from flashing before the upsell modal opens, but it also blocks the browser paint. Consider whether useEffect would be acceptable here—most modal libraries handle rendering imperatively and the brief flash is typically unnoticeable.

The dependency array correctly includes hasOmnichannelModule, which is used in the condition on line 84.

If the flash isn't a UX concern, consider reverting to useEffect to avoid blocking paint:

-	useLayoutEffect(() => {
+	useEffect(() => {
 		if (isLoadingModule || isLoadingProviders) {
 			return;
 		}
 
 		if (!hasOmnichannelModule || !hasOutboundModule || !hasProviders) {
 			upsellModal.open();
 		}
 	}, [hasOmnichannelModule, hasOutboundModule, hasProviders, isLoadingModule, isLoadingProviders, upsellModal]);
📜 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 ba32d56 and 5621ef8.

📒 Files selected for processing (12)
  • apps/meteor/client/NavBarV2/NavBarPagesGroup/hooks/useCreateNewItems.tsx (2 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.spec.tsx (4 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.tsx (4 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/components/OutboundMessageWizardSkeleton.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.spec.tsx (2 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/index.ts (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.spec.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundProvidersList.ts (2 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/modals/index.ts (1 hunks)
  • apps/meteor/client/sidebar/header/actions/hooks/useCreateRoomItems.tsx (2 hunks)
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoOutboundMessageButton.tsx (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/modals/index.ts
🧰 Additional context used
🧬 Code graph analysis (7)
apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoOutboundMessageButton.tsx (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.tsx (1)
  • useOutboundMessageAccess (6-21)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundProvidersList.ts (2)
packages/ui-contexts/src/index.ts (1)
  • usePermission (55-55)
apps/meteor/client/lib/queryKeys.ts (1)
  • omnichannelQueryKeys (30-84)
apps/meteor/client/NavBarV2/NavBarPagesGroup/hooks/useCreateNewItems.tsx (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.tsx (1)
  • useOutboundMessageAccess (6-21)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.spec.tsx (2)
packages/ui-contexts/src/index.ts (1)
  • usePermission (55-55)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.tsx (1)
  • useOutboundMessageAccess (6-21)
apps/meteor/client/sidebar/header/actions/hooks/useCreateRoomItems.tsx (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.tsx (1)
  • useOutboundMessageAccess (6-21)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.tsx (1)
packages/ui-contexts/src/index.ts (1)
  • usePermission (55-55)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.spec.tsx (3)
packages/mock-providers/src/index.ts (1)
  • mockAppRoot (3-3)
packages/ui-client/src/components/Wizard/WizardContext.tsx (1)
  • WizardContext (17-17)
apps/meteor/tests/mocks/data.ts (1)
  • createFakeLicenseInfo (213-260)
⏰ 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: 🔎 Code Check / Code Lint
  • GitHub Check: 📦 Meteor Build - coverage
🔇 Additional comments (16)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.spec.tsx (1)

10-11: LGTM! Clean type-only import.

The imports are properly structured with the type keyword for OmnichannelContextValue, ensuring it's only used at the type level.

apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/components/OutboundMessageWizardSkeleton.tsx (1)

5-5: LGTM: Good accessibility improvement.

Adding role='status' and aria-busy='true' properly signals the loading state to assistive technologies.

apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/index.ts (1)

1-1: LGTM: Clean barrel export pattern.

Re-exporting the new hook provides a cleaner public API for consumers.

apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoOutboundMessageButton.tsx (1)

4-4: LGTM: Centralized access logic simplifies maintenance.

Replacing dual checks (license + permission) with the unified useOutboundMessageAccess hook aligns with the PR objective to enable Community Edition upsell flows while maintaining proper authorization in licensed environments.

Also applies to: 17-21

apps/meteor/client/sidebar/header/actions/hooks/useCreateRoomItems.tsx (1)

2-2: LGTM: Consistent migration to centralized access hook.

Replacing the direct permission check with useOutboundMessageAccess maintains consistency across all outbound message entry points and enables Community Edition users to see the menu item and trigger the upsell flow.

Also applies to: 5-6, 25-25, 78-78

apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.tsx (2)

7-7: LGTM: Appropriate omnichannel enablement check.

Adding useOmnichannelEnabled ensures the wizard validates omnichannel status before rendering, preventing access when the feature is disabled at the workspace level.

Also applies to: 14-14, 41-41


151-153: LGTM: Defense-in-depth check for omnichannel enablement.

Adding an early return when omnichannel is disabled prevents direct access to the wizard even if users bypass the UI entry points. The ordering (omnichannel enabled → permission → modules/providers) is correct.

apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.tsx (1)

1-21: LGTM! Clean implementation of the access control logic.

The hook correctly implements the upsell flow by returning true when either required module is missing, allowing Community Edition users to see the option and trigger the upsell modal. The strict === true comparisons at lines 8-9 ensure that undefined/loading states are treated as missing modules, which is appropriate for the upsell scenario.

apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.spec.tsx (1)

1-82: Excellent test coverage!

The test suite comprehensively covers all logical branches of the useOutboundMessageAccess hook:

  • Omnichannel disabled case
  • Individual module missing scenarios (both livechat-enterprise and outbound-messaging)
  • Both modules missing
  • Permission granted/denied when all modules present

The mock implementations correctly simulate the different module availability states.

apps/meteor/client/NavBarV2/NavBarPagesGroup/hooks/useCreateNewItems.tsx (3)

2-2: Clean refactor replacing direct permission check.

The removal of usePermission is appropriate since the new useOutboundMessageAccess hook encapsulates the permission check along with the omnichannel and module validation logic.


6-7: LGTM! Appropriate import of the new access hook.


25-25: Access control correctly delegated to the new hook.

This change enables the upsell flow for Community Edition users by using the centralized access logic that returns true when modules are missing.

apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundProvidersList.ts (1)

29-29: Query gating aligns with upsell flow design.

The query is appropriately disabled when modules are missing, preventing unnecessary API calls while still allowing the UI to show (via useOutboundMessageAccess returning true for upsell). However, verify the omnichannel check consistency flagged above.

apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.spec.tsx (3)

63-73: Consider aligning Livechat_enabled setting with omnichannelEnabled parameter.

The appRoot function always sets Livechat_enabled to true (line 66) regardless of the omnichannelEnabled parameter value passed to the context (line 70). This could cause confusion if useOmnichannelEnabled checks the setting while the context uses a different value.

Verify whether this inconsistency is intentional for testing purposes, or if the setting should mirror the parameter:

 const appRoot = (omnichannelEnabled = true) =>
 	mockAppRoot()
 		.withJohnDoe()
-		.withSetting('Livechat_enabled', true)
+		.withSetting('Livechat_enabled', omnichannelEnabled)
 		.withEndpoint('GET', '/v1/omnichannel/outbound/providers', () => getProvidersMock())

80-100: Excellent test coverage for error states.

The new test group thoroughly validates loading, authorization, and omnichannel-disabled scenarios. The use of screen.findByRole and screen.findByText follows testing-library best practices.


122-140: Tests correctly validate module presence for upsell flow.

The updated tests appropriately include both livechat-enterprise and outbound-messaging modules to verify the upsell modal behavior when modules are present versus absent.

tassoevan
tassoevan previously approved these changes Oct 1, 2025
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: 0

🧹 Nitpick comments (2)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.spec.ts (1)

29-81: Comprehensive test coverage for the access logic.

The test suite effectively covers all key scenarios:

  • Omnichannel disabled (guard condition)
  • Missing modules triggering upsell flow (lines 38-63) - this is critical for the Community Edition fix
  • Permission-based access when modules are present

The mock implementations correctly test the OR condition in the hook (either module missing → upsell).

Optional: Consider adding a test case for when useHasLicenseModule returns undefined:

it('should return true if license module status is undefined (upsell)', () => {
  useOmnichannelEnabledMock.mockReturnValue(true);
  useHasLicenseModuleMock.mockReturnValue(undefined);
  usePermissionMock.mockReturnValue(true);

  const { result } = renderHook(() => useOutboundMessageAccess());
  expect(result.current).toBe(true);
});

This would verify the explicit === true checks handle undefined correctly.

apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.ts (1)

6-21: Logic correctly implements the Community Edition upsell flow.

The hook properly handles three scenarios:

  1. Omnichannel disabled (lines 12-14): Returns false - option hidden entirely.
  2. Missing modules (lines 16-18): Returns true - enables the upsell flow for Community Edition. This is the key fix for the regression.
  3. Modules present (line 20): Returns permission status - standard access control for Enterprise users.

The explicit === true checks on lines 8-9 correctly treat undefined/null as falsy, ensuring missing modules trigger the upsell path.

Minor naming consideration: The hook name useOutboundMessageAccess returns true for both "has actual access" and "should show upsell". Consider adding a JSDoc comment to clarify:

/**
 * Determines if the outbound message option should be visible.
 * Returns true when:
 * - User has actual access (licensed + permission), OR
 * - Modules are missing (triggers upsell flow for Community Edition)
 * Returns false when omnichannel is disabled or user lacks permission in Enterprise.
 */
export const useOutboundMessageAccess = (): boolean => {

This clarifies that true doesn't always mean "full access" but rather "show the option (with upsell if needed)".

📜 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 5621ef8 and d6864e8.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (2)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.spec.ts (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.spec.ts (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.ts (1)
  • useOutboundMessageAccess (6-21)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.ts (1)
packages/ui-contexts/src/index.ts (1)
  • usePermission (55-55)
⏰ 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 (3)
apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.spec.ts (2)

8-22: Mock setup is correct for isolated testing.

The mock setup appropriately covers the three dependencies (usePermission, useOmnichannelEnabled, useHasLicenseModule) needed for the hook. The use of jest.mocked for type-safe mock access is a good practice.


25-27: LGTM!

Proper cleanup between tests using jest.clearAllMocks().

apps/meteor/client/components/Omnichannel/OutboundMessage/hooks/useOutboundMessageAccess.ts (1)

1-4: LGTM!

All necessary dependencies are imported with correct paths.

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

🧹 Nitpick comments (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.spec.tsx (1)

63-73: Consider aligning Livechat_enabled setting with the omnichannelEnabled parameter.

The appRoot helper always sets Livechat_enabled to true regardless of the omnichannelEnabled parameter value. This could create confusion when testing omnichannel-disabled scenarios, where the setting and context don't align.

Consider applying this diff:

 const appRoot = (omnichannelEnabled = true) =>
 	mockAppRoot()
 		.withJohnDoe()
-		.withSetting('Livechat_enabled', true)
+		.withSetting('Livechat_enabled', omnichannelEnabled)
 		.withEndpoint('GET', '/v1/omnichannel/outbound/providers', () => getProvidersMock())
 		.withEndpoint('GET', '/v1/licenses.info', () => getLicenseMock())
 		.wrap((children) => (
 			<OmnichannelContext.Provider value={{ enabled: omnichannelEnabled } as OmnichannelContextValue}>
 				<WizardContext.Provider value={mockWizardApi}>{children}</WizardContext.Provider>
 			</OmnichannelContext.Provider>
 		));
📜 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 d6864e8 and d6d2ddf.

📒 Files selected for processing (1)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.spec.tsx (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.spec.tsx (3)
packages/mock-providers/src/index.ts (1)
  • mockAppRoot (3-3)
packages/ui-client/src/components/Wizard/WizardContext.tsx (1)
  • WizardContext (17-17)
apps/meteor/tests/mocks/data.ts (1)
  • createFakeLicenseInfo (213-260)
⏰ 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
🔇 Additional comments (4)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.spec.tsx (4)

3-3: LGTM! Appropriate test imports added.

The screen import and OmnichannelContext imports are correctly added and used throughout the updated tests.

Also applies to: 8-9


80-100: LGTM! Comprehensive error and loading state coverage.

The new test suite properly covers:

  • Loading state with aria-busy verification
  • Unauthorized access when permission is missing
  • Omnichannel disabled scenario

Note: The typo "unauthrized" from the previous review has been corrected to "unauthorized" on line 89.


122-124: LGTM! License mocks correctly updated with required modules.

The activeModules arrays now properly include both 'livechat-enterprise' and 'outbound-messaging', which aligns with the PR's goal of ensuring outbound messaging permissions are available in Community Edition and matches the expected module dependencies.

Also applies to: 138-140


107-107: No explicit permission needed for module/provider upsell tests. The useOutboundMessageAccess hook returns true whenever either license module is missing—before checking permissions—so omitting .withPermission('outbound.send-messages') in these tests is correct.

@aleksandernsilva aleksandernsilva force-pushed the regression/outbound-comms-permissions branch from bec9718 to 41e9ad5 Compare October 2, 2025 13:04
Copy link
Contributor

@lucas-a-pelegrino lucas-a-pelegrino left a comment

Choose a reason for hiding this comment

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

LGTM

@tassoevan tassoevan merged commit 318f272 into release-7.11.0 Oct 2, 2025
50 checks passed
@tassoevan tassoevan deleted the regression/outbound-comms-permissions branch October 2, 2025 14:57
ricardogarim pushed a commit that referenced this pull request Oct 7, 2025
…dition (#37107)

Co-authored-by: Tasso <tasso.evangelista@rocket.chat>
ricardogarim pushed a commit that referenced this pull request Oct 8, 2025
…dition (#37107)

Co-authored-by: Tasso <tasso.evangelista@rocket.chat>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants