Skip to content

Conversation

@aleksandernsilva
Copy link
Contributor

@aleksandernsilva aleksandernsilva commented Sep 17, 2025

Proposed changes (including videos or screenshots)

This PR improves how the Outbound Message modal handles scrolling on smaller screens and with larger templates. The structure was simplified by removing extra wrappers, section heights were adjusted for consistency, and Scrollable was added where needed. A new OutboundMessageForm component was also introduced to manage the submit shortcut and shared styling across all outbound message forms.

Issue(s)

CTZ-340

Steps to test or reproduce

  • Open workspace
  • Create new > Outbound message
  • In smaller resolutions modal content should be scrollable

Further comments

Summary by CodeRabbit

  • Bug Fixes

    • Improved scrolling and height handling in the Outbound Message modal and preview (prevents cutoff on small viewports; preview now capped).
    • Better recipient/sender formatting based on provider type.
  • New Features

    • Submit button shows loading state during submission.
  • Refactor

    • Streamlined wizard and form layouts for more consistent spacing and responsive behavior.
  • Chores

    • Bumped client and app packages to minor versions.

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Sep 17, 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 Sep 17, 2025

🦋 Changeset detected

Latest commit: 54b2026

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

This PR includes changesets to release 39 packages
Name Type
@rocket.chat/ui-client Major
@rocket.chat/meteor Minor
@rocket.chat/gazzodown Major
@rocket.chat/ui-voip Major
@rocket.chat/web-ui-registration Major
@rocket.chat/fuselage-ui-kit Major
@rocket.chat/livechat Patch
@rocket.chat/uikit-playground Patch
@rocket.chat/core-typings Minor
@rocket.chat/rest-typings Minor
@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/http-router Patch
@rocket.chat/model-typings Patch
@rocket.chat/ui-avatar Major
@rocket.chat/ui-contexts 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/license 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/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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 17, 2025

Walkthrough

Updates layout and scrolling for the Outbound Message modal and wizard: replaces many divs with Box, adds a shared OutboundMessageForm and Scrollable wrappers, forwards Box props across several components, and extends OutboundMessagePreview with providerType and Box prop forwarding.

Changes

Cohort / File(s) Summary
Changeset bump
.changeset/witty-impalas-flow.md
Adds a changeset bumping @rocket.chat/ui-client and @rocket.chat/meteor with note about improved Outbound Message modal scrolling.
Wizard infra (ui-client)
packages/ui-client/src/components/Wizard/Wizard.tsx, packages/ui-client/src/components/Wizard/WizardContent.tsx
Wizard now accepts and forwards Box props (WizardProps extends Box props); WizardContent removes an unnecessary wrapper and returns children directly when active.
Modal & wizard layout (meteor)
apps/meteor/.../OutboundMessageModal/OutboundMessageModal.tsx, apps/meteor/.../OutboundMessageWizard/OutboundMessageWizard.tsx
Modal display handling changed (isClosing ? 'none' : undefined) and ModalContent set to height='100%'. Wizard container switched to vertical flex with height='100%'; content Box given minHeight={0} and flexGrow={1}.
Shared form & scrolling wrappers
apps/meteor/.../OutboundMessageWizard/components/OutboundMessageForm.tsx, apps/meteor/.../forms/*/MessageForm.tsx, .../RecipientForm.tsx, .../RepliesForm.tsx
Adds OutboundMessageForm (Box as form) and replaces native wrappers with it; wraps field content in <Scrollable vertical> and adjusts FieldGroup/layout props.
Steps DOM simplification & review update
apps/meteor/.../steps/MessageStep.tsx, .../steps/RecipientStep.tsx, .../steps/RepliesStep.tsx, .../steps/ReviewStep.tsx
Removes redundant outer divs in steps. ReviewStep converted to vertical flex with Scrollable around preview and passes maxHeight={500} to OutboundMessagePreview.
Preview & field components prop forwarding
apps/meteor/.../OutboundMessagePreview/OutboundMessagePreview.tsx, .../forms/MessageForm/components/TemplateField.tsx, .../RepliesForm/components/{AgentField,DepartmentField}.tsx
OutboundMessagePreview now extends Box props, uses is='section', accepts optional providerType and forwards rest props. TemplateField, AgentField, DepartmentField types updated to extend Field props and forward extra props onto <Field />.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

stat: ready to merge

Suggested reviewers

  • lucas-a-pelegrino
  • tassoevan

Poem

I hop through boxes, scrolls, and frames,
I nudge the wizard, call its names.
No button hidden, no field astray —
I tuck the UI right away.
Bugs nibble less; I bound and play. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The PR also introduces unrelated changes such as generic prop forwarding enhancements in TemplateField, AgentField, and DepartmentField, providerType formatting in OutboundMessagePreview, and Box prop integration in core Wizard components, which go beyond the scrolling fix outlined in CTZ-340. Please extract the generic prop-forwarding and API enhancements into separate PRs so that this change set focuses solely on the Outbound Message modal structure and scrolling behavior required by CTZ-340.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title concisely and specifically describes the main change—improving the outbound message modal’s scrolling behavior—without extraneous details.
Linked Issues Check ✅ Passed The PR directly addresses CTZ-340 by restructuring the Outbound Message modal to use full-height containers, adding Scrollable wrappers in each form step, and ensuring that templates with many parameters can be scrolled so the Next and Back buttons become accessible.
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 feat/outbound-scroll-improvements

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Sep 17, 2025

Codecov Report

❌ Patch coverage is 96.57534% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.32%. Comparing base (e748e94) to head (54b2026).
⚠️ Report is 2 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #36974      +/-   ##
===========================================
+ Coverage    65.88%   67.32%   +1.44%     
===========================================
  Files         3314     3339      +25     
  Lines       114127   113204     -923     
  Branches     20832    20531     -301     
===========================================
+ Hits         75187    76211    +1024     
+ Misses       36391    34383    -2008     
- Partials      2549     2610      +61     
Flag Coverage Δ
e2e 56.89% <11.11%> (+1.48%) ⬆️
e2e-api 40.38% <ø> (+4.69%) ⬆️
unit 71.23% <96.57%> (+<0.01%) ⬆️

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 September 18, 2025 13:09
@aleksandernsilva aleksandernsilva requested a review from a team as a code owner September 18, 2025 13:09
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: 2

🧹 Nitpick comments (6)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RepliesForm.tsx (2)

123-196: Make Scrollable a flexible child to avoid layout edge cases.

To prevent double scrollbars or clipped content in some flex parents, let Scrollable grow and set minHeight=0.

-            <Scrollable vertical>
+            <Scrollable vertical flexGrow={1} minHeight={0}>

167-176: Inconsistent error prop type vs department field.

Department passes a message string (errors.departmentId?.message) while Agent passes a boolean (!!errors.agentId). Aligning helps UX/types unless AutoCompleteAgent intentionally differs.

If Agent also accepts a message, consider:

-                                        error={!!errors.agentId}
+                                        error={errors.agentId?.message}
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx (1)

181-209: Let the Scrollable grow to fill vertical space.

Prevents rare clipping in nested flex layouts.

-            <Scrollable vertical>
+            <Scrollable vertical flexGrow={1} minHeight={0}>
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.tsx (1)

102-144: Ensure Scrollable participates in flex sizing.

Same rationale as other forms.

-            <Scrollable vertical>
+            <Scrollable vertical flexGrow={1} minHeight={0}>
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/ReviewStep.tsx (1)

19-23: Avoid hard-coded preview height.

Consider a viewport-relative cap for better small/large screen behavior.

-            <Scrollable vertical>
-                <OutboundMessagePreview {...props} maxHeight={500} />
+            <Scrollable vertical maxHeight='60vh'>
+                <OutboundMessagePreview {...props} />
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessagePreview/OutboundMessagePreview.tsx (1)

73-74: Optional a11y: give the section an accessible name.

Adding aria-label or aria-labelledby helps screen readers.

-    <Box {...props} is='section'>
+    <Box {...props} is='section' aria-label='Outbound message preview'>
📜 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 27cc5b7 and 48e9e11.

⛔ Files ignored due to path filters (5)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/__snapshots__/MessageStep.spec.tsx.snap is excluded by !**/*.snap
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/__snapshots__/RecipientStep.spec.tsx.snap is excluded by !**/*.snap
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/__snapshots__/RepliesStep.spec.tsx.snap is excluded by !**/*.snap
  • packages/ui-client/src/components/Wizard/__snapshots__/Wizard.spec.tsx.snap is excluded by !**/*.snap
  • packages/ui-client/src/components/Wizard/__snapshots__/WizardActions.spec.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (14)
  • .changeset/witty-impalas-flow.md (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessagePreview/OutboundMessagePreview.tsx (5 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/components/OutboundMessageForm.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.tsx (4 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx (3 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RepliesForm.tsx (4 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/MessageStep.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/RecipientStep.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/RepliesStep.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/ReviewStep.tsx (3 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/modals/OutboundMessageModal/OutboundMessageModal.tsx (1 hunks)
  • packages/ui-client/src/components/Wizard/Wizard.tsx (1 hunks)
  • packages/ui-client/src/components/Wizard/WizardContent.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
apps/meteor/client/components/Omnichannel/OutboundMessage/modals/OutboundMessageModal/OutboundMessageModal.tsx (1)
apps/meteor/tests/e2e/page-objects/modal.ts (1)
  • Modal (3-25)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.tsx (2)
apps/meteor/app/utils/lib/i18n.ts (1)
  • t (6-6)
apps/meteor/client/components/Omnichannel/OutboundMessage/constants.ts (1)
  • OUTBOUND_DOCS_LINK (1-1)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/components/OutboundMessageForm.tsx (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/hooks/useFormKeyboardSubmit.tsx (1)
  • useFormKeyboardSubmit (14-24)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RepliesForm.tsx (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/utils/cx.ts (1)
  • cxp (29-34)
packages/ui-client/src/components/Wizard/Wizard.tsx (1)
packages/ui-client/src/components/Wizard/WizardContext.tsx (2)
  • WizardAPI (7-15)
  • WizardContext (17-17)
⏰ 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). (7)
  • GitHub Check: 🔨 Test Storybook / Test Storybook
  • GitHub Check: 🔎 Code Check / Code Lint
  • GitHub Check: 🔨 Test Unit / Unit Tests
  • GitHub Check: 🔎 Code Check / TypeScript
  • GitHub Check: 📦 Meteor Build - coverage
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (13)
.changeset/witty-impalas-flow.md (1)

1-6: Changeset reads well and matches the PR scope.

Scope and messaging look accurate.

packages/ui-client/src/components/Wizard/WizardContent.tsx (1)

13-18: Wrapper removal: double-check styling/ARIA assumptions.

Returning children directly removes a DOM node; verify no selectors or layout rules relied on a wrapper element.

Run quick checks:

  • Inspect step containers to ensure margins/paddings still apply.
  • Verify focus trapping/tab order unchanged.
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/MessageStep.tsx (1)

21-32: Wrapper removal LGTM.

Lean DOM and submit flow with WizardNextButton manual looks correct.

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

22-31: LGTM: direct form return aligns with new layout.

Actions rendering and submit progression remain intact.

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

21-30: LGTM: flatter structure, unchanged behavior.

Back/Next and manual submit wiring look good.

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

150-154: Flex container + minHeight=0 is the right combo for scrollables.

Good fix for overflow on small viewports.

Manual checks:

  • 320x568 and 375x667: confirm inner Scrollable receives focus and wheel/touch scroll works.
  • Long template on Step 2: Next/Back visible after scroll; keyboard Cmd/Ctrl+Enter submits.
packages/ui-client/src/components/Wizard/Wizard.tsx (1)

12-15: Forward ref through Wizard to the root Box.

Repo search found no occurrences or existing ref usage; forwarding the ref is safe for internal code — confirm external consumers won't rely on the current signature.

-import { ComponentProps, memo, type ReactNode } from 'react';
+import { ComponentProps, memo, forwardRef, type ReactNode } from 'react';
@@
-const Wizard = ({ children, api, ...props }: WizardProps) => (
-	<WizardContext.Provider value={api}>
-		<Box {...props}>{children}</Box>
-	</WizardContext.Provider>
-);
-
-export default memo(Wizard);
+const Wizard = forwardRef<HTMLDivElement, WizardProps>(({ children, api, ...props }, ref) => (
+	<WizardContext.Provider value={api}>
+		<Box ref={ref} {...props}>{children}</Box>
+	</WizardContext.Provider>
+));
+
+export default memo(Wizard);
apps/meteor/client/components/Omnichannel/OutboundMessage/modals/OutboundMessageModal/OutboundMessageModal.tsx (2)

49-49: Confirm focus/ARIA behavior when confirmation is open.

Hiding the underlying Modal via display='none' is fine; please also ensure it’s removed from the a11y tree and doesn’t trap focus. If needed, add aria-hidden when isClosing is true.

Apply if required:

- <Modal aria-labelledby={modalId} display={isClosing ? 'none' : undefined}>
+ <Modal aria-labelledby={modalId} display={isClosing ? 'none' : undefined} aria-hidden={isClosing || undefined}>

55-57: Height=100% on content helps Scrollable sizing.

Looks good. Please sanity-check on small viewports that inner Scrollable areas actually scroll and the modal itself doesn’t get a second scrollbar.

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

179-181: Shared Form wrapper adoption looks good.

Consistent handling across steps.

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

18-29: LGTM: Box props forwarding increases composability.

Accepting ComponentProps is a nice touch for layout control.

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

121-126: Approve — OutboundMessageForm renders a native

and forwards noValidate/onSubmit.
Box is='form'; onSubmit is passed explicitly and {...props} is spread (so noValidate will be forwarded).

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

130-134: Update OUTBOUND_DOCS_LINK to the canonical Rocket.Chat WhatsApp template docs.

Set OUTBOUND_DOCS_LINK to https://developer.rocket.chat/docs/whatsapp-business-template-messages, remove the TODO, and confirm the change in apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.tsx (lines 130–134).

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

♻️ Duplicate comments (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/components/OutboundMessageForm.tsx (1)

2-6: Fix onSubmit typing and wire Cmd/Ctrl+Enter to native form submission.

  • onSubmit: () => void is incompatible with standard FormEvent handlers used by RHF and native forms.
  • Add a keyboard shortcut that calls requestSubmit() so validations fire consistently.
  • Prevent overriding is; this component should always render a form.

Apply:

-import { Box } from '@rocket.chat/fuselage';
-import type { ComponentProps } from 'react';
+import { Box } from '@rocket.chat/fuselage';
+import { useCallback, type ComponentProps, type FormEventHandler, type KeyboardEvent } from 'react';
 
-type OutboundMessageFormProps = ComponentProps<typeof Box> & {
-	onSubmit?: () => void;
-};
+type OutboundMessageFormProps = Omit<ComponentProps<typeof Box>, 'is' | 'onSubmit' | 'onKeyDown'> & {
+	onSubmit?: FormEventHandler<HTMLFormElement>;
+	onKeyDown?: (e: KeyboardEvent<HTMLFormElement>) => void;
+};
 
-const OutboundMessageForm = ({ onSubmit, ...props }: OutboundMessageFormProps) => {
-	return <Box is='form' display='flex' flexDirection='column' height='100%' flexGrow={1} flexShrink={0} onSubmit={onSubmit} {...props} />;
-};
+const OutboundMessageForm = ({ onSubmit, onKeyDown, ...props }: OutboundMessageFormProps) => {
+	const handleKeyDown = useCallback(
+		(e: KeyboardEvent<HTMLFormElement>) => {
+			onKeyDown?.(e);
+			if (!e.isDefaultPrevented() && (e.metaKey || e.ctrlKey) && e.key === 'Enter') {
+				e.preventDefault();
+				e.currentTarget.requestSubmit();
+			}
+		},
+		[onKeyDown],
+	);
+
+	return (
+		<Box
+			is='form'
+			display='flex'
+			flexDirection='column'
+			height='100%'
+			flexGrow={1}
+			flexShrink={0}
+			onKeyDown={handleKeyDown}
+			onSubmit={onSubmit}
+			{...props}
+		/>
+	);
+};

Run to confirm there are no remaining custom keyboard-submit handlers in the wizard forms (to avoid double submissions):

#!/bin/bash
rg -nP --type=tsx -C2 '\bonKeyDown\b|\buseFormKeyboardSubmit\b' apps/meteor/client/components/Omnichannel/OutboundMessage

Also applies to: 8-10

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

9-9: Allow nested Scrollable to size correctly inside flex containers.

Add minHeight={0} to avoid flex children preventing overflow-based scrolling in some layouts.

-  return <Box is='form' display='flex' flexDirection='column' height='100%' flexGrow={1} flexShrink={0} onSubmit={onSubmit} {...props} />;
+  return <Box is='form' display='flex' flexDirection='column' height='100%' minHeight={0} flexGrow={1} flexShrink={0} onSubmit={onSubmit} {...props} />;
📜 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 48e9e11 and 155e793.

📒 Files selected for processing (1)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/components/OutboundMessageForm.tsx (1 hunks)
⏰ 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). (7)
  • GitHub Check: 🔨 Test Unit / Unit Tests
  • GitHub Check: 🔨 Test Storybook / Test Storybook
  • GitHub Check: 🔎 Code Check / Code Lint
  • GitHub Check: 🔎 Code Check / TypeScript
  • GitHub Check: 📦 Meteor Build - coverage
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build

@aleksandernsilva aleksandernsilva added this to the 7.11.0 milestone Sep 18, 2025
tassoevan
tassoevan previously approved these changes Sep 19, 2025
@tassoevan tassoevan added the stat: QA assured Means it has been tested and approved by a company insider label Sep 19, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Sep 19, 2025
@kodiakhq kodiakhq bot removed the stat: ready to merge PR tested and approved waiting for merge label Sep 19, 2025
@kodiakhq
Copy link
Contributor

kodiakhq bot commented Sep 19, 2025

This PR currently has a merge conflict. Please resolve this and then re-add the ['stat: ready to merge', 'automerge'] label.

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 (5)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessagePreview/OutboundMessagePreview.tsx (3)

18-29: Avoid accepting children here to prevent shadowing/ignoring passed children

Because you also provide explicit children to <Box>, any user-supplied children in ...props would be ignored. Tighten the prop type to omit children and rename the spread to clarify intent.

-type OutboundMessagePreviewProps = ComponentProps<typeof Box> & {
+type OutboundMessagePreviewProps = Omit<ComponentProps<typeof Box>, 'children'> & {
@@
-	templateParameters,
-	...props
+	templateParameters,
+	...boxProps
 }: OutboundMessagePreviewProps) => {
@@
-		<Box {...props} is='section'>
+		<Box {...boxProps} is='section'>

Also applies to: 54-55


31-38: Phone formatting condition likely too narrow

providerType === 'phone' may miss SMS/WhatsApp-like providers that also use phone numbers. Consider a small allowlist to trigger phone formatting.

- if (providerType === 'phone') {
+ if (providerType === 'phone' || providerType === 'sms' || providerType === 'whatsapp') {
   return formatPhoneNumber(rawValue);
 }

If the enum differs, align with the actual provider types used in IOutboundProviderMetadata.


73-74: Minor a11y: label the section

Add an accessible name to the <section> so screen readers announce it meaningfully in the Review step.

- <Box {...boxProps} is='section'>
+ <Box {...boxProps} is='section' aria-label='Outbound message preview'>
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/RepliesStep.tsx (2)

15-18: Remove unnecessary async

onSubmit is typed as synchronous. Dropping async avoids confusion and micro overhead.

- const handleSubmit = useEffectEvent(async (values: RepliesFormSubmitPayload) => {
+ const handleSubmit = useEffectEvent((values: RepliesFormSubmitPayload) => {
   onSubmit(values);
   next();
 });

25-28: Disable Back while submitting

Prevents navigation during an active submit.

- <WizardBackButton />
+ <WizardBackButton disabled={isSubmitting} />
📜 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 cb1ff55 and fd5e18f.

⛔ Files ignored due to path filters (6)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/__snapshots__/MessageStep.spec.tsx.snap is excluded by !**/*.snap
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/__snapshots__/RecipientStep.spec.tsx.snap is excluded by !**/*.snap
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/__snapshots__/RepliesStep.spec.tsx.snap is excluded by !**/*.snap
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/__snapshots__/ReviewStep.spec.tsx.snap is excluded by !**/*.snap
  • packages/ui-client/src/components/Wizard/__snapshots__/Wizard.spec.tsx.snap is excluded by !**/*.snap
  • packages/ui-client/src/components/Wizard/__snapshots__/WizardActions.spec.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (14)
  • .changeset/witty-impalas-flow.md (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessagePreview/OutboundMessagePreview.tsx (5 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/components/OutboundMessageForm.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.tsx (4 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx (3 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RepliesForm/RepliesForm.tsx (4 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/MessageStep.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/RecipientStep.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/RepliesStep.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/ReviewStep.tsx (3 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/modals/OutboundMessageModal/OutboundMessageModal.tsx (1 hunks)
  • packages/ui-client/src/components/Wizard/Wizard.tsx (1 hunks)
  • packages/ui-client/src/components/Wizard/WizardContent.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/components/OutboundMessageForm.tsx
  • packages/ui-client/src/components/Wizard/WizardContent.tsx
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx
  • .changeset/witty-impalas-flow.md
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/MessageStep.tsx
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.tsx
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/ReviewStep.tsx
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.tsx
  • packages/ui-client/src/components/Wizard/Wizard.tsx
  • apps/meteor/client/components/Omnichannel/OutboundMessage/modals/OutboundMessageModal/OutboundMessageModal.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
🔇 Additional comments (2)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/RecipientStep.tsx (1)

22-31: LGTM — wrapper removal + manual submit flow look right

Quick sanity-check: ensure RecipientForm renders renderActions inside the actual <form> so the type='submit' Next button submits the form. If not, pass form attr pointing to the form id (pattern used in RepliesForm).

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

119-140: Scrollable placement is good; verify container allows it to actually scroll

This looks correct (fields inside Scrollable; actions outside). Ensure the parent Form sets a flex column layout with minHeight: 0 and overflow: hidden (or equivalent) so the inner <Scrollable vertical> can gain height and scroll on small viewports. If not, add flexGrow={1} to a wrapper around Scrollable or set these styles on Form.

Also applies to: 148-148

@aleksandernsilva aleksandernsilva force-pushed the feat/outbound-scroll-improvements branch from fd5e18f to e937bb5 Compare September 19, 2025 16:35
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

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/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RepliesForm/components/DepartmentField.tsx (1)

14-21: Avoid prop-type collision on onChange.

ComponentProps<typeof Field> & { onChange: () => void } risks an incompatible intersection if Field exposes onChange. Make onChange your own prop by omitting it from Field’s props.

Apply:

-type DepartmentFieldProps = ComponentProps<typeof Field> & {
+type DepartmentFieldProps = Omit<ComponentProps<typeof Field>, 'onChange'> & {
   control: Control<RepliesFormData>;
   onlyMyDepartments?: boolean;
   isError: boolean;
   isFetching: boolean;
   onRefetch: () => void;
   onChange: () => void;
 };

Also applies to: 30-31

♻️ Duplicate comments (2)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/components/OutboundMessageForm.tsx (2)

4-6: Fix onSubmit typing (conflicts with Box’s native signature).

ComponentProps<typeof Box> & { onSubmit?: () => void } creates an unsatisfiable intersection for onSubmit and will reject standard FormEvent handlers.

Apply:

-import type { ComponentProps } from 'react';
+import { useCallback, useRef, type ComponentProps } from 'react';

-type OutboundMessageFormProps = ComponentProps<typeof Box> & {
-	onSubmit?: () => void;
-};
+type OutboundMessageFormProps = Omit<ComponentProps<typeof Box>, 'onSubmit' | 'is' | 'ref'> & {
+	onSubmit?: ComponentProps<typeof Box>['onSubmit'];
+};

8-10: Add Cmd/Ctrl+Enter submit and harden invariants (always a form).

The PR description says this component manages the submit shortcut; current code doesn’t. Also prevent consumers from overriding is='form'.

Apply:

-const OutboundMessageForm = ({ onSubmit, ...props }: OutboundMessageFormProps) => (
-	<Box is='form' display='flex' flexDirection='column' height='100%' flexGrow={1} flexShrink={0} onSubmit={onSubmit} {...props} />
-);
+// NOTE: adjust the import path of useFormKeyboardSubmit if different in this repo
+// import { useFormKeyboardSubmit } from '.../useFormKeyboardSubmit';
+const OutboundMessageForm = ({ onSubmit, ...props }: OutboundMessageFormProps) => {
+	const nodeRef = useRef<HTMLFormElement | null>(null);
+	const kbRef = useFormKeyboardSubmit(() => nodeRef.current?.requestSubmit(), []);
+	const combinedRef = useCallback((el: HTMLFormElement | null) => {
+		nodeRef.current = el;
+		kbRef(el);
+	}, [kbRef]);
+
+	return (
+		<Box
+			{...props}
+			is='form'
+			display='flex'
+			flexDirection='column'
+			height='100%'
+			flexGrow={1}
+			flexShrink={0}
+			ref={combinedRef}
+			onSubmit={onSubmit}
+		/>
+	);
+};

Run to locate the hook and confirm the import path:

#!/bin/bash
rg -nC2 '\buseFormKeyboardSubmit\b'
🧹 Nitpick comments (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/RecipientStep.tsx (1)

26-29: Option: Disable Next when the form is invalid.

If RecipientForm exposes validity (e.g., isValid or canSubmit) to renderActions, disable the submit to prevent no-op submissions and improve UX.

Apply if supported by renderActions’ signature:

- renderActions={({ isSubmitting }) => (
+ renderActions={({ isSubmitting, isValid }) => (
    <WizardActions>
-     <WizardNextButton manual type='submit' loading={isSubmitting} />
+     <WizardNextButton manual type='submit' loading={isSubmitting} disabled={!isValid} />
    </WizardActions>
  )}
📜 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 fd5e18f and e937bb5.

⛔ Files ignored due to path filters (6)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/__snapshots__/MessageStep.spec.tsx.snap is excluded by !**/*.snap
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/__snapshots__/RecipientStep.spec.tsx.snap is excluded by !**/*.snap
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/__snapshots__/RepliesStep.spec.tsx.snap is excluded by !**/*.snap
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/__snapshots__/ReviewStep.spec.tsx.snap is excluded by !**/*.snap
  • packages/ui-client/src/components/Wizard/__snapshots__/Wizard.spec.tsx.snap is excluded by !**/*.snap
  • packages/ui-client/src/components/Wizard/__snapshots__/WizardActions.spec.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (15)
  • .changeset/witty-impalas-flow.md (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessagePreview/OutboundMessagePreview.tsx (5 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/components/OutboundMessageForm.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.tsx (4 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/MessageForm/components/TemplateField.tsx (3 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx (3 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RepliesForm/RepliesForm.tsx (4 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RepliesForm/components/AgentField.tsx (3 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RepliesForm/components/DepartmentField.tsx (4 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/MessageStep.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/RecipientStep.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/RepliesStep.tsx (1 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/ReviewStep.tsx (3 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/modals/OutboundMessageModal/OutboundMessageModal.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
  • .changeset/witty-impalas-flow.md
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/MessageStep.tsx
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.tsx
  • apps/meteor/client/components/Omnichannel/OutboundMessage/modals/OutboundMessageModal/OutboundMessageModal.tsx
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/RepliesStep.tsx
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RepliesForm/RepliesForm.tsx
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/OutboundMessageWizard.tsx
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/steps/ReviewStep.tsx
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessagePreview/OutboundMessagePreview.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-18T17:32:33.969Z
Learnt from: aleksandernsilva
PR: RocketChat/Rocket.Chat#36974
File: apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.tsx:124-129
Timestamp: 2025-09-18T17:32:33.969Z
Learning: The ARIA mismatch issue in MessageForm's template field (where FieldError id used templateId instead of messageFormId) was addressed in PR #36972 through refactoring the template field into a separate TemplateField component, which uses consistent templateFieldId for both aria-describedby and FieldError id.

Applied to files:

  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/MessageForm/components/TemplateField.tsx
🧬 Code graph analysis (2)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RepliesForm/components/AgentField.tsx (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RepliesForm/RepliesForm.tsx (1)
  • RepliesFormData (19-22)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/MessageForm/components/TemplateField.tsx (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/MessageForm/MessageForm.tsx (1)
  • MessageFormData (18-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). (2)
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (5)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/MessageForm/components/TemplateField.tsx (1)

15-19: Prop-forwarding is correct and a11y wiring looks good.

Extending ComponentProps<typeof Field> and forwarding via <Field {...props}> is consistent; label/aria IDs are coherent with TemplateSelect.

Please sanity-check that cxp(templateFieldId, { error, hint: true }) renders “-error -hint” when error exists. If it doesn’t, aria-describedby may miss the error node.

Also applies to: 21-21, 50-50

apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RepliesForm/components/DepartmentField.tsx (1)

54-79: Good a11y and retry UX.

aria-labelledby, aria-describedby, and inline retry control are wired cleanly; error/hint IDs follow a consistent convention.

apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RepliesForm/components/AgentField.tsx (1)

13-19: Approve — AutoCompleteDepartmentAgent default export confirmed

Default export AutoCompleteDepartmentAgent found in apps/meteor/client/components/Omnichannel/OutboundMessage/components/AutoCompleteDepartmentAgent.tsx (line 64); import name matches — no changes required.

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

22-31: Good cleanup: render the form directly (fewer wrappers).

Returning RecipientForm at the top level aligns with the new scrollable Form layout and avoids unnecessary nesting.


22-31: No change required — submit button is inside the form.

RecipientForm renders renderActions inside its

(OutboundMessageForm is a Box with is='form'), so the WizardNextButton (type='submit') will be inside the form and will submit as expected.

@aleksandernsilva aleksandernsilva 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 Sep 19, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Sep 19, 2025
@kodiakhq kodiakhq bot merged commit 399ab02 into develop Sep 19, 2025
69 of 71 checks passed
@kodiakhq kodiakhq bot deleted the feat/outbound-scroll-improvements branch September 19, 2025 23:55
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.

3 participants