Skip to content

feat: webhook inbox#5

Merged
CayoPOliveira merged 29 commits intofazer-ai/mainfrom
feat/webhook-inbox
Feb 28, 2025
Merged

feat: webhook inbox#5
CayoPOliveira merged 29 commits intofazer-ai/mainfrom
feat/webhook-inbox

Conversation

@CayoPOliveira
Copy link

@CayoPOliveira CayoPOliveira commented Feb 25, 2025

This change is Reviewable

Summary by CodeRabbit

  • New Features

    • Enhanced webhook settings with a new inbox selection dropdown and improved user interface labels.
    • Added an “editing” mode for webhook forms to better distinguish between creation and update actions.
    • Introduced a new component for displaying inbox names associated with webhooks.
  • Refactor

    • Streamlined the configuration process by differentiating parameter handling for creating versus updating webhooks.
  • Bug Fixes

    • Improved webhook delivery logic to ensure proper processing based on inbox matching.
  • Tests

    • Expanded test coverage to ensure reliable behavior in webhook updates and inbox matching logic.
  • Style

    • Added new button styles for enhanced visual distinction.

Copy link
Author

@CayoPOliveira CayoPOliveira left a comment

Choose a reason for hiding this comment

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

Reviewed 9 of 9 files at r1, 1 of 1 files at r2, all commit messages.
Reviewable status: all files reviewed, 5 unresolved discussions (waiting on @CayoPOliveira)


app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue line 83 at r1 (raw file):

      return this.$t('INTEGRATION_SETTINGS.WEBHOOK.FORM.NAME.PLACEHOLDER');
    },
    webhookInboxInputPlaceholder() {

NIT I will remove this


app/javascript/dashboard/i18n/locale/en/integrations.json line 198 at r1 (raw file):

        "LOADING": "Fetching dashboard apps...",
        "TABLE_HEADER": {
          "NAME": "Name",

Linter
I need to rollback?


app/javascript/dashboard/i18n/locale/en/integrations.json line 431 at r1 (raw file):

        "SUCCESS_MESSAGE": "The document has been successfully deleted",
        "ERROR_MESSAGE": "There was an error deleting the document, please try again."
      },

Linter


app/javascript/dashboard/i18n/locale/en/integrations.json line 481 at r1 (raw file):

          "PLACEHOLDER": "Enter the answer here",
          "ERROR": "Please provide a valid answer."
        },

Linter


app/javascript/dashboard/i18n/locale/en/integrations.json line 536 at r1 (raw file):

    }
  }
}

Linter

@CayoPOliveira CayoPOliveira changed the title Feat: webhook inbox feat: webhook inbox Feb 25, 2025
Copy link
Member

@gabrieljablonski gabrieljablonski left a comment

Choose a reason for hiding this comment

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

-(review needed) +(questions/changes requested)

Reviewed 5 of 9 files at r1, all commit messages.
Reviewable status: all files reviewed, 15 unresolved discussions (waiting on @CayoPOliveira)


app/javascript/dashboard/i18n/locale/en/integrations.json line 198 at r1 (raw file):

Previously, CayoPOliveira (Cayo P. R. Oliveira) wrote…

Linter
I need to rollback?

Please fix your VSCode config so this doesn't happen anymore.


spec/controllers/api/v1/accounts/webhook_controller_spec.rb line 131 at r2 (raw file):

        expect(response).to have_http_status(:unprocessable_entity)
        expect(response.parsed_body['message']).to eql 'Inbox cannot be updated'
      end

Change to "ignores trying to update inbox_id"


app/listeners/webhook_listener.rb line 92 at r2 (raw file):

    account.webhooks.account_type.each do |webhook|
      next unless webhook.subscriptions.include?(payload[:event])
      next if payload[:inbox].present? && (webhook.inbox_id.present? && webhook.inbox_id != payload[:inbox][:id])

NIT

Suggestion:

      next if payload[:inbox].present? && webhook.inbox_id.present? && webhook.inbox_id != payload[:inbox][:id]

app/controllers/api/v1/accounts/webhooks_controller.rb line 18 at r2 (raw file):

      render json: { message: 'Inbox cannot be updated' }, status: :unprocessable_entity
      return
    end

This can be removed. See suggestion below.


app/controllers/api/v1/accounts/webhooks_controller.rb line 32 at r2 (raw file):

  def webhook_params
    params.require(:webhook).permit(:inbox_id, :name, :url, subscriptions: [])
  end

This is a better way to allow/disallow updating specific fields.

Let's take the opportunity to also disallow changing the URL.

Suggestion:

  def create_webhook_params
    params.require(:webhook).permit(:inbox_id, :name, :url, subscriptions: [])
  end

  def update_webhook_params
    params.require(:webhook).permit(:name, subscriptions: [])
  end

app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue line 65 at r2 (raw file):

      url: this.value.url || '',
      name: this.value.name || '',
      inbox_id: this.value.inbox_id || '',

NIT

Suggestion:

      inboxId: this.value.inbox_id || '',

app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue line 89 at r2 (raw file):

        url: this.url,
        name: this.name,
        inbox_id: this.inbox_id,

Try updating this as well. If it doesn't work, can be kept as snake case.

Suggestion:

        inboxId: this.inbox_id,

app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue line 113 at r2 (raw file):

          :placeholder="webhookURLInputPlaceholder"
          @input="v$.url.$touch"
        />

Disable as well when editing.


app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookRow.vue line 62 at r2 (raw file):

  olive.olive9,
  cyan.cyan9,
];

Remove colors.


app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookRow.vue line 89 at r2 (raw file):

      <div
        v-if="webhook.inbox"
        class="flex gap-2 font-medium break-words text-slate-500 dark:text-slate-400"

Add mt-1


app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookRow.vue line 97 at r2 (raw file):

            color: COLORS[webhook.inbox.id % COLORS.length],
          }"
        />

Is it possible to use an icon instead? Like is done on the sidebar.

image.png

Copy link
Author

@CayoPOliveira CayoPOliveira left a comment

Choose a reason for hiding this comment

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

-(questions/changes requested) +(review needed)

Reviewed 8 of 8 files at r3, 1 of 1 files at r4, all commit messages.
Reviewable status: all files reviewed, 8 unresolved discussions (waiting on @gabrieljablonski)


app/controllers/api/v1/accounts/webhooks_controller.rb line 18 at r2 (raw file):

Previously, gabrieljablonski (Gabriel Jablonski) wrote…

This can be removed. See suggestion below.

Done.


app/controllers/api/v1/accounts/webhooks_controller.rb line 32 at r2 (raw file):

Previously, gabrieljablonski (Gabriel Jablonski) wrote…

This is a better way to allow/disallow updating specific fields.

Let's take the opportunity to also disallow changing the URL.

Done.


app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue line 89 at r2 (raw file):

Previously, gabrieljablonski (Gabriel Jablonski) wrote…

Try updating this as well. If it doesn't work, can be kept as snake case.

It doesn't work here


app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue line 113 at r2 (raw file):

Previously, gabrieljablonski (Gabriel Jablonski) wrote…

Disable as well when editing.

Done.


app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookRow.vue line 62 at r2 (raw file):

Previously, gabrieljablonski (Gabriel Jablonski) wrote…

Remove colors.

Done.


app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookRow.vue line 89 at r2 (raw file):

Previously, gabrieljablonski (Gabriel Jablonski) wrote…

Add mt-1

Done.


app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookRow.vue line 97 at r2 (raw file):

Previously, gabrieljablonski (Gabriel Jablonski) wrote…

Is it possible to use an icon instead? Like is done on the sidebar.

image.png

I used the InboxName from conversations page


spec/controllers/api/v1/accounts/webhook_controller_spec.rb line 131 at r2 (raw file):

Previously, gabrieljablonski (Gabriel Jablonski) wrote…

Change to "ignores trying to update inbox_id"

Changed to "ignores trying to update inbox_id and url"

Copy link
Member

@gabrieljablonski gabrieljablonski left a comment

Choose a reason for hiding this comment

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

-(review needed) +(questions/changes requested)

Reviewed 1 of 9 files at r1, 7 of 8 files at r3, 1 of 1 files at r4, all commit messages.
Reviewable status: all files reviewed, 10 unresolved discussions (waiting on @CayoPOliveira)


spec/controllers/api/v1/accounts/webhook_controller_spec.rb line 131 at r2 (raw file):

Previously, CayoPOliveira (Cayo P. R. Oliveira) wrote…

Changed to "ignores trying to update inbox_id and url"

Looks good, but use .to eql ... with the original values, instead of .not_to eql ....


a discussion (no related file):
Dropdown UX can be improved. See example for selecting agent on conversation.

2025-02-26_11-29-15.mp4

  1. We need a "All inboxes" explicit option (FE-only, still send null to BE).
  2. Close the dropdown after selecting an option

PS.: On the video above, you can see an option can be de-selected by clicking it when it is already selected. I don't think we need that.


spec/listeners/webhook_listener_spec.rb line 97 at r4 (raw file):

        listener.message_created(message_created_event)
      end
    end

Try applying this patch instead of placing these under #message_created, since they're supposed to test "generic" behavior.

webhook-specs.patch

Note the changes I made to the spec descriptions, and the (very slight) newline changes to make the Arrange-Act-Assert pattern clearer (unfortunately, original specs in this file don't seem to follow that pattern).


app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookRow.vue line 40 at r4 (raw file):

    <td class="py-4 ltr:pr-4 rtl:pl-4">
      <div v-if="webhook.inbox">
        <InboxName :inbox="webhook.inbox" class="flex break-words !mx-0" />

Do we need all of these classes?

Suggestion:

        <InboxName :inbox="webhook.inbox" class="!mx-0" />

app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookRow.vue line 41 at r4 (raw file):

      <div v-if="webhook.inbox">
        <InboxName :inbox="webhook.inbox" class="flex break-words !mx-0" />
      </div>

This div seems pointless

Suggestion:

      <InboxName v-if="webhook.inbox" :inbox="webhook.inbox" class="flex break-words !mx-0" />

app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue line 68 at r4 (raw file):

      subscriptions: this.value.subscriptions || [],
      supportedWebhookEvents: SUPPORTED_WEBHOOK_EVENTS,
      selectedInbox: this.value.inbox || {},

Can we use null instead? From what I can tell, nothing should change, but makes more sense instead of {}.

Suggestion:

      selectedInbox: this.value.inbox || null,

app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue line 128 at r4 (raw file):

        />
      </label>
      <div class="flex flex-col w-full">

Is w-full not enough?

Suggestion:

      <div class="w-full">

app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue line 148 at r4 (raw file):

              "
              :disabled="isEditing"
              button-variant="secondary"

secondary variant actually does nothing, other than overriding the hollow variant.

Try applying this patch for the dark variant instead:

chatwoot-button-dark-variant

image.png

Still not ideal (couldn't manage to update the border to match the other inputs), but looks better this way.


Ideally we should also match the "disabled" styling better, but not worth wasting more time on this right now. Creating the dark variant should be good enough.

image copy 1.png


app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue line 154 at r4 (raw file):

        </label>
      </div>
      <label :class="{ error: v$.url.$error }" class="mb-2">

WDYT of changing the order of inputs to URL -> Inbox -> Name?

Feels a bit weird to have the fields be disabled -> enabled -> disabled when editing.

image.png


app/listeners/webhook_listener.rb line 6 at r4 (raw file):

    changed_attributes = extract_changed_attributes(event)
    inbox = conversation.inbox

Do we really need this newline? Breaks the styling from other methods below.

@coderabbitai
Copy link

coderabbitai bot commented Feb 27, 2025

Walkthrough

This pull request refines webhook parameter handling in the API controller by differentiating between create and update actions. It introduces new UI elements and component properties for inbox selection in the dashboard. Additionally, the webhook listener's logic is enhanced to ensure that the webhook job is executed only when the payload’s inbox matches. Frontend Vue components are updated with new props and methods to support inbox selection, and corresponding tests have been modified to reflect these changes.

Changes

File(s) Change Summary
app/controllers/.../webhooks_controller.rb Renamed webhook_params to webhook_create_params and added webhook_update_params to enforce distinct parameter rules for create (allows inbox_id, name, url, subscriptions) vs. update (allows only name and subscriptions).
app/javascript/dashboard/.../integrations.json Added a new "INBOX" section with keys for "LABEL", "TITLE", "PLACEHOLDER", "NO_RESULTS", and "INPUT_PLACEHOLDER" for UI inbox selection.
app/javascript/dashboard/.../EditWebHook.vue,
WebhookForm.vue,
WebhookRow.vue
Introduced new props (is-editing/isEditing) for edit state; integrated a MultiselectDropdown in the form to select an inbox and inserted an InboxName component for conditional rendering of the inbox in a webhook row; updated submission to include inbox_id.
app/javascript/shared/components/ui/MultiselectDropdown.vue Added new props buttonVariant (default 'hollow') and disabled (default false) to customize button appearance and state.
app/listeners/webhook_listener.rb,
app/views/api/v1/accounts/webhooks/_webhook.json.jbuilder
In the listener, added a condition to check if payload[:inbox][:id] matches the webhook’s inbox_id before triggering WebhookJob; updated JSON output to include channel_type from webhook.inbox.
spec/controllers/api/v1/accounts/webhook_controller_spec.rb,
spec/listeners/webhook_listener_spec.rb
Updated tests: the webhook update tests now ignore url and inbox_id changes during update, and listener tests now verify that webhook jobs only trigger when the inbox matches.

Sequence Diagram(s)

sequenceDiagram
    participant E as Event Source
    participant WL as WebhookListener
    participant WJ as WebhookJob

    E->>WL: deliver_account_webhooks(payload)
    alt Payload has inbox & matches webhook.inbox_id
      WL->>WJ: perform_later(webhook, payload)
    else
      WL-->>E: Skip processing (inbox mismatch)
    end
Loading
sequenceDiagram
    participant U as User
    participant WF as WebhookForm
    participant MD as MultiselectDropdown

    U->>WF: Open Edit Webhook form (isEditing enabled)
    WF->>MD: Load inbox options
    U->>MD: Select an inbox
    MD->>WF: onClickAssignInbox(inbox)
    WF->>WF: Update selectedInbox & inboxId
    U->>WF: Submit form (inbox_id included)
Loading

Poem

I hopped into code with a skip and a cheer,
Refining my parameters to make things clear.
Inbox choices now dance in a dropdown delight,
With conditional checks keeping things just right.
As a joyful rabbit, I celebrate this day—
New features and fixes, hip-hip-hooray!
🐇🌟


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8f6f423 and 3261e4f.

📒 Files selected for processing (1)
  • app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: test

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue (1)

89-89: Minor naming inconsistency between JavaScript and backend

There's a slight naming difference between the JavaScript property inboxId (camelCase) and the emitted property inbox_id (snake_case).

While this works correctly (as the backend expects snake_case), consider using a helper function to normalize property naming between frontend and backend to maintain consistency:

onSubmit() {
  this.$emit('submit', {
    url: this.url,
    name: this.name,
-   inbox_id: this.inboxId,
+   inbox_id: this.inboxId, // Comment: normalizing camelCase to snake_case for API
    subscriptions: this.subscriptions,
  });
},
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9cdf2ad and 259235f.

📒 Files selected for processing (10)
  • app/controllers/api/v1/accounts/webhooks_controller.rb (2 hunks)
  • app/javascript/dashboard/i18n/locale/en/integrations.json (1 hunks)
  • app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/EditWebHook.vue (1 hunks)
  • app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue (7 hunks)
  • app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookRow.vue (2 hunks)
  • app/javascript/shared/components/ui/MultiselectDropdown.vue (3 hunks)
  • app/listeners/webhook_listener.rb (2 hunks)
  • app/views/api/v1/accounts/webhooks/_webhook.json.jbuilder (1 hunks)
  • spec/controllers/api/v1/accounts/webhook_controller_spec.rb (1 hunks)
  • spec/listeners/webhook_listener_spec.rb (1 hunks)
🔇 Additional comments (25)
app/views/api/v1/accounts/webhooks/_webhook.json.jbuilder (1)

10-10: LGTM: Enhanced JSON response with channel_type information.

Adding the channel_type attribute to the webhook JSON response when an inbox is associated with the webhook provides more complete information to frontend consumers.

app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookRow.vue (2)

6-6: LGTM: New component import for inbox display.

The import of the InboxName component is appropriate for displaying inbox details in the webhook row.


39-41: LGTM: Enhanced UI with conditional inbox display.

The conditional rendering of the InboxName component when a webhook has an associated inbox enhances the UI by displaying relevant inbox information. The component is properly integrated with appropriate class styling.

app/listeners/webhook_listener.rb (2)

6-6: LGTM: Improved code readability.

Adding a blank line improves the readability of the method.


92-92: LGTM: Added proper inbox filtering for webhooks.

This change ensures that webhooks associated with specific inboxes will only be triggered for events related to that particular inbox, preventing unwanted webhook triggers across different inboxes.

app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/EditWebHook.vue (1)

56-56: LGTM: Added editing state indicator to form component.

Adding the is-editing prop to the WebhookForm component appropriately communicates that this form is being used in an editing context, which allows the form to adapt its behavior or appearance accordingly.

spec/listeners/webhook_listener_spec.rb (2)

79-87: Well-structured test for inbox-matching behavior.

This test case correctly verifies that when a webhook's inbox matches the event's inbox, the webhook job is triggered with the expected parameters.


89-97: Good negative test case for inbox filtering.

This test correctly verifies that webhooks are not triggered when their associated inbox doesn't match the event's inbox, which is essential for ensuring proper filtering behavior.

app/javascript/dashboard/i18n/locale/en/integrations.json (1)

36-42: Good addition of localization strings for inbox selection.

The new inbox selection UI strings are clear and provide all the necessary text elements for a complete user experience including placeholder text and empty state messages.

spec/controllers/api/v1/accounts/webhook_controller_spec.rb (1)

115-117: Test correctly updated to focus on name updates only.

The test now properly verifies that webhook names can be updated, which aligns with the controller changes that likely restrict updates to only the name and subscriptions.

app/javascript/shared/components/ui/MultiselectDropdown.vue (3)

38-45: Good addition of flexibility with new props.

Adding the buttonVariant and disabled props enhances the component's reusability by allowing consumers to customize the appearance and state of the dropdown.


69-74: Improved button accessibility and flexibility.

Adding the type="button" attribute and binding the button's variant and disabled state to props improves both accessibility and flexibility of the component.


115-117: Improved button semantics.

Adding type="button" to the close button ensures it's properly recognized as a button by browsers and assistive technologies, which is good for accessibility.

app/controllers/api/v1/accounts/webhooks_controller.rb (4)

10-10: Good method name change for webhook creation

The change to use webhook_create_params instead of webhook_params for the create action aligns well with the separation of concerns between create and update operations.


15-15: Good restriction of update permissions

The update action now correctly uses webhook_update_params, which limits the parameters that can be modified during an update operation, improving security.


25-27: Appropriate parameter permissions for webhook creation

The renamed method properly permits all necessary fields for webhook creation including inbox_id, name, url, and subscriptions.


29-31: Good security practice: limiting update parameters

This new method restricts what can be updated on an existing webhook, preventing changes to the URL and inbox_id after creation. This is a good security practice as it prevents potential abuse or unintended consequences from changing these critical fields.

app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue (8)

6-7: Good component imports for enhanced functionality

The imports of MultiselectDropdown and useMapGetter are appropriate for implementing the inbox selection feature.


23-25: Proper component registration

The MultiselectDropdown component is correctly registered in the components section.


39-42: Well-defined isEditing prop

The isEditing prop is appropriately defined with a default value, which will control field visibility and editability based on whether we're creating or updating a webhook.


46-49: Good use of composables for accessing store data

The setup function correctly uses the useMapGetter composable to retrieve inbox data from the store, making it available to the component.


65-65: Proper initialization of inbox-related data

The inboxId and selectedInbox state variables are correctly initialized from props, ensuring form state consistency.

Also applies to: 68-68


93-96: Well-implemented inbox selection handler

The onClickAssignInbox method correctly handles inbox selection, updating both the display value and the ID needed for submission.


111-111: Correctly disabled URL field when editing

The URL field is appropriately disabled in edit mode, which aligns with the backend restriction that prevents URL modification during updates.


128-153: Well-structured inbox selection UI

The implementation of the inbox selection dropdown is well-structured and correctly:

  1. Uses the MultiselectDropdown component
  2. Passes appropriate props including options from the store
  3. Handles selection events
  4. Disables the dropdown when in edit mode
  5. Includes proper internationalization for all text elements

This aligns perfectly with the backend changes that support inbox_id in webhook creation.

Comment on lines +123 to +131
it 'ignores trying to update inbox_id and url' do
put "/api/v1/accounts/#{account.id}/webhooks/#{webhook.id}",
params: { url: 'https://other.url.com', inbox_id: create(:inbox, account: account).id },
headers: administrator.create_new_auth_token,
as: :json
expect(response).to have_http_status(:success)
expect(response.parsed_body['payload']['webhook']['inbox_id']).not_to eql inbox.id
expect(response.parsed_body['payload']['webhook']['url']).not_to eql 'https://other.url.com'
end
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Assertion appears incorrect for testing immutability.

The test logic seems to be testing the wrong condition for immutability.

If you're testing that the webhook's inbox_id and url remain unchanged when updates are attempted, the assertions should verify that they still match the original values, not that they differ:

-        expect(response.parsed_body['payload']['webhook']['inbox_id']).not_to eql inbox.id
-        expect(response.parsed_body['payload']['webhook']['url']).not_to eql 'https://other.url.com'
+        expect(response.parsed_body['payload']['webhook']['inbox_id']).to eql inbox.id
+        expect(response.parsed_body['payload']['webhook']['url']).to eql 'https://hello.com'

The current assertions suggest you expect different values, which contradicts the test's purpose of verifying that these fields can't be changed.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it 'ignores trying to update inbox_id and url' do
put "/api/v1/accounts/#{account.id}/webhooks/#{webhook.id}",
params: { url: 'https://other.url.com', inbox_id: create(:inbox, account: account).id },
headers: administrator.create_new_auth_token,
as: :json
expect(response).to have_http_status(:success)
expect(response.parsed_body['payload']['webhook']['inbox_id']).not_to eql inbox.id
expect(response.parsed_body['payload']['webhook']['url']).not_to eql 'https://other.url.com'
end
it 'ignores trying to update inbox_id and url' do
put "/api/v1/accounts/#{account.id}/webhooks/#{webhook.id}",
params: { url: 'https://other.url.com', inbox_id: create(:inbox, account: account).id },
headers: administrator.create_new_auth_token,
as: :json
expect(response).to have_http_status(:success)
expect(response.parsed_body['payload']['webhook']['inbox_id']).to eql inbox.id
expect(response.parsed_body['payload']['webhook']['url']).to eql 'https://hello.com'
end

Copy link
Member

@gabrieljablonski gabrieljablonski left a comment

Choose a reason for hiding this comment

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

Reviewable status: all files reviewed, 12 unresolved discussions (waiting on @CayoPOliveira)


spec/controllers/api/v1/accounts/webhook_controller_spec.rb line 128 at r4 (raw file):

            headers: administrator.create_new_auth_token,
            as: :json
        expect(response).to have_http_status(:success)

Avoid inlining create calls.

Suggestion:

      it 'ignores trying to update inbox_id and url' do
        new_inbox = create(:inbox, account: account)

        put "/api/v1/accounts/#{account.id}/webhooks/#{webhook.id}",
            params: { url: 'https://other.url.com', inbox_id: new_inbox.id },
            headers: administrator.create_new_auth_token,
            as: :json
        expect(response).to have_http_status(:success)

Copy link

@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)
app/javascript/dashboard/assets/scss/widgets/_buttons.scss (1)

192-194: New .dark Button Modifier Styling

The addition of the .dark class (lines 192–194) applies bg-n-slate-1 to buttons. Please verify that:

  • The chosen background color (bg-n-slate-1) provides sufficient contrast with the text and aligns with your dark-theme design guidelines.
  • This style is consistent with other dark-themed components in the application.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 259235f and 8f6f423.

📒 Files selected for processing (6)
  • app/javascript/dashboard/assets/scss/widgets/_buttons.scss (1 hunks)
  • app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue (5 hunks)
  • app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookRow.vue (2 hunks)
  • app/listeners/webhook_listener.rb (1 hunks)
  • spec/controllers/api/v1/accounts/webhook_controller_spec.rb (2 hunks)
  • spec/listeners/webhook_listener_spec.rb (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • app/listeners/webhook_listener.rb
  • app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookRow.vue
  • spec/controllers/api/v1/accounts/webhook_controller_spec.rb
  • app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: test
🔇 Additional comments (1)
spec/listeners/webhook_listener_spec.rb (1)

18-40: Tests for webhook inbox filtering look good!

Great job adding thorough test coverage for the inbox filtering feature. You've properly covered both positive (matching inbox) and negative (non-matching inbox) cases to ensure the webhook only triggers for the appropriate inbox.

The tests clearly validate that:

  1. When a webhook is associated with an inbox, it triggers for events from that inbox
  2. When a webhook is associated with an inbox, it doesn't trigger for events from other inboxes

These tests align well with the webhook inbox feature being implemented, ensuring webhooks can be specifically targeted to certain inboxes rather than triggering for all events account-wide.

Copy link
Member

@gabrieljablonski gabrieljablonski left a comment

Choose a reason for hiding this comment

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

Reviewable status: 5 of 11 files reviewed, 12 unresolved discussions (waiting on @CayoPOliveira and @coderabbitai[bot])


app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue line 148 at r4 (raw file):

Previously, gabrieljablonski (Gabriel Jablonski) wrote…

secondary variant actually does nothing, other than overriding the hollow variant.

Try applying this patch for the dark variant instead:

chatwoot-button-dark-variant

image.png

Still not ideal (couldn't manage to update the border to match the other inputs), but looks better this way.


Ideally we should also match the "disabled" styling better, but not worth wasting more time on this right now. Creating the dark variant should be good enough.

image copy 1.png

Self-reminder to improve styling (maybe input-like button variant?)

Copy link
Author

@CayoPOliveira CayoPOliveira left a comment

Choose a reason for hiding this comment

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

Reviewed 5 of 6 files at r5, 2 of 3 files at r6, all commit messages.
Reviewable status: 10 of 11 files reviewed, 5 unresolved discussions (waiting on @coderabbitai[bot] and @gabrieljablonski)


a discussion (no related file):

Previously, gabrieljablonski (Gabriel Jablonski) wrote…

Dropdown UX can be improved. See example for selecting agent on conversation.

2025-02-26_11-29-15.mp4

  1. We need a "All inboxes" explicit option (FE-only, still send null to BE).
  2. Close the dropdown after selecting an option

PS.: On the video above, you can see an option can be de-selected by clicking it when it is already selected. I don't think we need that.

Done.


app/javascript/dashboard/routes/dashboard/settings/integrations/Webhooks/WebhookForm.vue line 148 at r4 (raw file):

Previously, gabrieljablonski (Gabriel Jablonski) wrote…

secondary variant actually does nothing, other than overriding the hollow variant.

Try applying this patch for the dark variant instead:

chatwoot-button-dark-variant

image.png

Still not ideal (couldn't manage to update the border to match the other inputs), but looks better this way.


Ideally we should also match the "disabled" styling better, but not worth wasting more time on this right now. Creating the dark variant should be good enough.

image copy 1.png

This only works in dark mode


spec/listeners/webhook_listener_spec.rb line 97 at r4 (raw file):

Previously, gabrieljablonski (Gabriel Jablonski) wrote…

Try applying this patch instead of placing these under #message_created, since they're supposed to test "generic" behavior.

webhook-specs.patch

Note the changes I made to the spec descriptions, and the (very slight) newline changes to make the Arrange-Act-Assert pattern clearer (unfortunately, original specs in this file don't seem to follow that pattern).

  • I applied the patch
  • Added a describe to the contexts
  • Changed the way the context 'when webhook has an inbox and it does not match the event inbox' performed the expect, for greater accuracy

a discussion (no related file):
-(questions/changes requested)

Copy link
Member

@gabrieljablonski gabrieljablonski left a comment

Choose a reason for hiding this comment

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

Reviewed 4 of 6 files at r5, 2 of 3 files at r6, 1 of 1 files at r7, 1 of 1 files at r9, 1 of 1 files at r10, all commit messages.
Dismissed @coderabbitai[bot] from a discussion.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on @CayoPOliveira)

Copy link
Author

@CayoPOliveira CayoPOliveira left a comment

Choose a reason for hiding this comment

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

Reviewed 1 of 3 files at r6, 1 of 1 files at r7, 1 of 1 files at r9.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on @CayoPOliveira)

@CayoPOliveira CayoPOliveira merged commit 5076b13 into fazer-ai/main Feb 28, 2025
3 checks passed
@CayoPOliveira CayoPOliveira deleted the feat/webhook-inbox branch February 28, 2025 21:27
gabrieljablonski added a commit that referenced this pull request Mar 5, 2025
* chore: exclude inbox_id from webhook update parameters

* feat: display inbox label in webhook settings

* feat: add inbox selection to webhook form

* feat: prevent updating inbox_id in webhook update

* feat: integrate MultiselectDropdown for inbox selection in webhook form

* feat: add inbox matching logic to webhook event delivery

* feat: remove unused inbox input placeholder from webhook form

* fix: MultiselectDropdown component submiting form

* feat: refine webhook parameters for create and update actions

* feat: disable URL input field when editing webhook

* chore: remove unnecessary parentheses

* chore: update webhook controller spec to ignore inbox_id and url updates

* fix: clean up JSON formatting

* fix: standardize inbox_id to inboxId in WebhookForm component

* refactor: replace LabelItem with InboxName component in WebhookRow

* chore: enhance MultiselectDropdown with button variant prop and update styling in WebhookForm

* chore: simplify MultiselectDropdown wrapper in WebhookForm component

* chore: update selectedInbox initialization to null and reorder form fields

* refactor: simplify InboxName

* chore: add dark variant styling for buttons in SCSS

* test: add inbox filtering for webhook event triggers in WebhookListener

* test: refactor webhook controller spec to use a variable for URL and improve update expectations

* feat(webhook): all inboxes option

* chore: remove dark variant styling for buttons in SCSS

* fix: bad interaction multiselectdropdown inside label

* chore: invert if

* chore: rename to assignedInbox and drop inboxId

* refactor(WebhookForm): restore div separating fields from buttons

* test: improve description

---------

Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
gabrieljablonski added a commit that referenced this pull request Mar 28, 2025
* chore: exclude inbox_id from webhook update parameters

* feat: display inbox label in webhook settings

* feat: add inbox selection to webhook form

* feat: prevent updating inbox_id in webhook update

* feat: integrate MultiselectDropdown for inbox selection in webhook form

* feat: add inbox matching logic to webhook event delivery

* feat: remove unused inbox input placeholder from webhook form

* fix: MultiselectDropdown component submiting form

* feat: refine webhook parameters for create and update actions

* feat: disable URL input field when editing webhook

* chore: remove unnecessary parentheses

* chore: update webhook controller spec to ignore inbox_id and url updates

* fix: clean up JSON formatting

* fix: standardize inbox_id to inboxId in WebhookForm component

* refactor: replace LabelItem with InboxName component in WebhookRow

* chore: enhance MultiselectDropdown with button variant prop and update styling in WebhookForm

* chore: simplify MultiselectDropdown wrapper in WebhookForm component

* chore: update selectedInbox initialization to null and reorder form fields

* refactor: simplify InboxName

* chore: add dark variant styling for buttons in SCSS

* test: add inbox filtering for webhook event triggers in WebhookListener

* test: refactor webhook controller spec to use a variable for URL and improve update expectations

* feat(webhook): all inboxes option

* chore: remove dark variant styling for buttons in SCSS

* fix: bad interaction multiselectdropdown inside label

* chore: invert if

* chore: rename to assignedInbox and drop inboxId

* refactor(WebhookForm): restore div separating fields from buttons

* test: improve description

---------

Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
gabrieljablonski added a commit that referenced this pull request Mar 30, 2025
* chore: exclude inbox_id from webhook update parameters

* feat: display inbox label in webhook settings

* feat: add inbox selection to webhook form

* feat: prevent updating inbox_id in webhook update

* feat: integrate MultiselectDropdown for inbox selection in webhook form

* feat: add inbox matching logic to webhook event delivery

* feat: remove unused inbox input placeholder from webhook form

* fix: MultiselectDropdown component submiting form

* feat: refine webhook parameters for create and update actions

* feat: disable URL input field when editing webhook

* chore: remove unnecessary parentheses

* chore: update webhook controller spec to ignore inbox_id and url updates

* fix: clean up JSON formatting

* fix: standardize inbox_id to inboxId in WebhookForm component

* refactor: replace LabelItem with InboxName component in WebhookRow

* chore: enhance MultiselectDropdown with button variant prop and update styling in WebhookForm

* chore: simplify MultiselectDropdown wrapper in WebhookForm component

* chore: update selectedInbox initialization to null and reorder form fields

* refactor: simplify InboxName

* chore: add dark variant styling for buttons in SCSS

* test: add inbox filtering for webhook event triggers in WebhookListener

* test: refactor webhook controller spec to use a variable for URL and improve update expectations

* feat(webhook): all inboxes option

* chore: remove dark variant styling for buttons in SCSS

* fix: bad interaction multiselectdropdown inside label

* chore: invert if

* chore: rename to assignedInbox and drop inboxId

* refactor(WebhookForm): restore div separating fields from buttons

* test: improve description

---------

Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
gabrieljablonski added a commit that referenced this pull request Apr 4, 2025
* chore: exclude inbox_id from webhook update parameters

* feat: display inbox label in webhook settings

* feat: add inbox selection to webhook form

* feat: prevent updating inbox_id in webhook update

* feat: integrate MultiselectDropdown for inbox selection in webhook form

* feat: add inbox matching logic to webhook event delivery

* feat: remove unused inbox input placeholder from webhook form

* fix: MultiselectDropdown component submiting form

* feat: refine webhook parameters for create and update actions

* feat: disable URL input field when editing webhook

* chore: remove unnecessary parentheses

* chore: update webhook controller spec to ignore inbox_id and url updates

* fix: clean up JSON formatting

* fix: standardize inbox_id to inboxId in WebhookForm component

* refactor: replace LabelItem with InboxName component in WebhookRow

* chore: enhance MultiselectDropdown with button variant prop and update styling in WebhookForm

* chore: simplify MultiselectDropdown wrapper in WebhookForm component

* chore: update selectedInbox initialization to null and reorder form fields

* refactor: simplify InboxName

* chore: add dark variant styling for buttons in SCSS

* test: add inbox filtering for webhook event triggers in WebhookListener

* test: refactor webhook controller spec to use a variable for URL and improve update expectations

* feat(webhook): all inboxes option

* chore: remove dark variant styling for buttons in SCSS

* fix: bad interaction multiselectdropdown inside label

* chore: invert if

* chore: rename to assignedInbox and drop inboxId

* refactor(WebhookForm): restore div separating fields from buttons

* test: improve description

---------

Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
@coderabbitai coderabbitai bot mentioned this pull request Jan 3, 2026
12 tasks
gabrieljablonski added a commit that referenced this pull request Jan 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved for merge enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants