Skip to content

Conversation

@nischitpra
Copy link
Contributor

@nischitpra nischitpra commented Aug 8, 2025

PR-Codex overview

This PR focuses on updating the handling of sigHash in the webhook components to support both single and multiple signature inputs, enhancing user experience and data management.

Detailed summary

  • Changed sigHash from a string to an array in multiple components.
  • Updated form handling to accommodate multiple signatures.
  • Modified UI elements to display pluralization for multiple signatures.
  • Adjusted utility functions to process arrays of signature hashes.
  • Enhanced SignatureSelector to support multi-select functionality.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features

    • Added support for selecting multiple signature hashes in webhook filters and selectors.
    • Enhanced signature selectors to allow both single-select and multi-select modes, with improved handling of custom signatures.
  • Improvements

    • Updated UI labels, placeholders, and descriptions to reflect multi-selection capabilities and pluralization.
    • Review and summary steps now display multiple selected signatures with appropriate formatting.
    • Webhook payloads and validation schemas now support arrays of signature hashes for improved flexibility.

@nischitpra nischitpra requested review from a team as code owners August 8, 2025 12:48
@changeset-bot
Copy link

changeset-bot bot commented Aug 8, 2025

⚠️ No Changeset found

Latest commit: f92201d

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

@vercel
Copy link

vercel bot commented Aug 8, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
thirdweb-www ✅ Ready (Inspect) Visit Preview 💬 Add feedback Aug 8, 2025 8:26pm
4 Skipped Deployments
Name Status Preview Comments Updated (UTC)
docs-v2 ⬜️ Skipped (Inspect) Aug 8, 2025 8:26pm
nebula ⬜️ Skipped (Inspect) Aug 8, 2025 8:26pm
thirdweb_playground ⬜️ Skipped (Inspect) Aug 8, 2025 8:26pm
wallet-ui ⬜️ Skipped (Inspect) Aug 8, 2025 8:26pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 8, 2025

Walkthrough

The changes introduce multi-signature selection support throughout the webhook creation and filtering workflow. Components, form schemas, and utility functions were updated to handle sigHash as either a string or an array of strings. UI components, such as SignatureSelector and related forms, now support multi-select mode, and all relevant logic was adjusted to process multiple signature hashes.

Changes

Cohort / File(s) Change Summary
SignatureSelector Multi-Select Support
apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
Enhanced the SignatureSelector component to support single- and multi-select modes via a new multiSelect prop. Updated value and onChange types to accept string or array of strings. Adjusted internal logic, selection handlers, and UI to handle custom and multiple signatures.
MultiSelect Custom Trigger
apps/dashboard/src/@/components/blocks/multi-select.tsx
Added customTrigger prop to MultiSelect and ensured it is not passed to the internal Button element. Updated prop destructuring and rendering logic to support this new prop.
Form Default Value Update
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
Changed the default value of the sigHash form field from an empty string to an empty array, aligning with multi-signature support.
Filter Details Multi-Signature Support
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx
Updated form logic and UI to handle sigHash as a string or array. Enabled multi-select in signature selectors, updated placeholders, pluralized labels, and adjusted custom signature detection and ABI clearing logic.
Review Step Multi-Signature Display
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx
Enhanced the display logic for the "Signature Hash" field to support and pluralize multiple signature hashes, handling both string and array values.
Topic Selector Modal Multi-Signature Support
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
Refactored to support multiple signature hashes. Normalized sigHash to arrays, updated transformation logic, pluralized UI labels, enabled multi-select in selectors, and updated input handling for both event and transaction topics.
Webhook Payload Multi-Signature Support
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookPayloadUtils.ts
Modified payload construction functions to handle sigHash as an array, iterating and transforming each signature hash as needed for event and transaction webhooks.
Schema Update for sigHash
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts
Changed the schema validation for sigHash to accept a string or an array of strings, supporting multi-signature selection in the form.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CreateWebhookModal
    participant FilterDetailsStep
    participant SignatureSelector
    participant webhookPayloadUtils

    User->>CreateWebhookModal: Open modal
    CreateWebhookModal->>FilterDetailsStep: Render filter step
    FilterDetailsStep->>SignatureSelector: Render with multiSelect=true
    User->>SignatureSelector: Select one or more signatures
    SignatureSelector-->>FilterDetailsStep: onChange (string or string[])
    FilterDetailsStep-->>CreateWebhookModal: Update form state (sigHash: string[])
    User->>CreateWebhookModal: Submit form
    CreateWebhookModal->>webhookPayloadUtils: build payload with sigHash (array)
    webhookPayloadUtils-->>CreateWebhookModal: Payload with multiple signatures
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch np/webhook_multi_topic

🪧 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.
    • Explain this complex logic.
    • 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 explain this code block.
  • 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 explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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 generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests 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.

@graphite-app
Copy link
Contributor

graphite-app bot commented Aug 8, 2025

How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

@github-actions github-actions bot added the Dashboard Involves changes to the Dashboard. label Aug 8, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Aug 8, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 64.03 KB (0%) 1.3 s (0%) 237 ms (+83.58% 🔺) 1.6 s
thirdweb (cjs) 357.38 KB (0%) 7.2 s (0%) 491 ms (-1.01% 🔽) 7.7 s
thirdweb (minimal + tree-shaking) 5.72 KB (0%) 115 ms (0%) 124 ms (+471.23% 🔺) 239 ms
thirdweb/chains (tree-shaking) 526 B (0%) 11 ms (0%) 90 ms (+1455.25% 🔺) 101 ms
thirdweb/react (minimal + tree-shaking) 19.16 KB (0%) 384 ms (0%) 196 ms (+235.18% 🔺) 579 ms

@codecov
Copy link

codecov bot commented Aug 8, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 56.33%. Comparing base (45ba811) to head (f92201d).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #7818   +/-   ##
=======================================
  Coverage   56.33%   56.33%           
=======================================
  Files         905      905           
  Lines       58821    58821           
  Branches     4146     4146           
=======================================
  Hits        33137    33137           
  Misses      25578    25578           
  Partials      106      106           
Flag Coverage Δ
packages 56.33% <ø> (ø)
🚀 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.

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

🔭 Outside diff range comments (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx (1)

453-457: Reset sigHash to [] instead of "" to align with multi-select semantics

Using "" can cause subtle truthy checks and type churn (string vs string[]). Default to an empty array.

-                                form.setValue("sigHash", "");
+                                form.setValue("sigHash", [] as string[]);
                                 form.setValue("sigHashAbi", "");
-                                form.setValue("sigHash", "");
+                                form.setValue("sigHash", [] as string[]);
                                 form.setValue("sigHashAbi", "");

Also applies to: 494-498

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx (2)

90-96: Default sigHash to [] to reflect multi-select

Keep form defaults consistent with multi-select to avoid type/UX inconsistencies.

-      sigHash: "",
+      sigHash: [] as string[],

Apply in both eventFilterForm and transactionFilterForm defaults.

Also applies to: 110-116


578-592: Normalize Input value for sigHash when it may be an array

If sigHash becomes an array, passing it directly to Input can cause React warnings. Join to a string, mirroring the transaction branch.

-                                                    <Input
+                                                    <Input
                                                       disabled={
                                                         (topic.id ===
                                                           "contracts.event.confirmed" &&
                                                           eventAbi.isFetching) ||
                                                         (topic.id ===
                                                           "contracts.transaction.confirmed" &&
                                                           txAbi.isFetching)
                                                       }
                                                       onChange={field.onChange}
                                                       placeholder="Provide above details first..."
-                                                      value={field.value}
+                                                      value={
+                                                        Array.isArray(field.value)
+                                                          ? field.value.join(", ")
+                                                          : field.value || ""
+                                                      }
                                                     />
🧹 Nitpick comments (11)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx (1)

197-198: Avoid multiple watch("sigHash") subscriptions; watch once and reuse

Repeated calls can subscribe multiple times and produce inconsistent snapshots during render. Read once and reuse for label + value.

Apply:

-            <span className="text-muted-foreground text-sm">
-              Signature Hash{Array.isArray(form.watch("sigHash")) && form.watch("sigHash")?.length > 1 ? "es" : ""}:
-            </span>
+            {(() => {
+              const sigHash = form.watch("sigHash");
+              const isPlural = Array.isArray(sigHash) && sigHash.length > 1;
+              return (
+                <span className="text-muted-foreground text-sm">
+                  Signature Hash{isPlural ? "es" : ""}:
+                </span>
+              );
+            })()}
           </span>
           <span className="font-medium text-sm">
             {(() => {
-              const sigHash = form.watch("sigHash");
+              const sigHash = form.watch("sigHash");
               if (!sigHash) return "None";
-              
               if (Array.isArray(sigHash)) {
                 if (sigHash.length === 0) return "None";
                 if (sigHash.length === 1) {
                   return truncateMiddle(sigHash[0], 10, 6);
                 }
                 return `${sigHash.length} signature${sigHash.length > 1 ? 's' : ''} selected`;
               } else {
                 return truncateMiddle(sigHash, 10, 6);
               }
             })()}

Also applies to: 200-213

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookPayloadUtils.ts (3)

36-47: Event signatures: logic is correct for multi-select

Array normalization + keccak256 fallback is sound. Payload omits signatures when none selected, which is ideal.

  • Consider trimming user input: const s = sigHash.trim(); if (!s) continue;
  • Avoid constructing TextEncoder in loop:
-    for (const sigHash of sigHashes) {
+    const encoder = new TextEncoder();
+    for (const sigHash of sigHashes) {
       if (sigHash) {
         eventSignatures.push({
           abi: data.sigHashAbi || data.abi,
           params: {},
-          sig_hash: sigHash.startsWith("0x")
-            ? sigHash
-            : keccak256(new TextEncoder().encode(sigHash)),
+          sig_hash: sigHash.startsWith("0x")
+            ? sigHash
+            : keccak256(encoder.encode(sigHash)),
         });
       }
     }

67-77: Transaction signatures: correct selector handling for multiple entries

Normalization + toFunctionSelector is correct. Same minor improvements suggested for the event path apply here too.

  • Trim input and skip empties.
  • Avoid repeated work:
-    for (const sigHash of sigHashes) {
+    for (const raw of sigHashes) {
+      const sigHash = raw.trim();
       if (sigHash) {
         txSignatures.push({
           abi: data.sigHashAbi || data.abi,
           params: {},
           sig_hash: sigHash.startsWith("0x")
             ? sigHash
             : toFunctionSelector(sigHash),
         });
       }
     }

36-47: Add explicit types for signatures arrays to satisfy TS guidelines

Local arrays are inferred as any[]. Define a shared type and annotate both arrays.

Outside these hunks, add:

type SignatureEntry = {
  sig_hash: string;
  abi?: string;
  params: Record<string, unknown>;
};

Then update declarations:

// in buildEventWebhookPayload
-const eventSignatures = [];
+const eventSignatures: SignatureEntry[] = [];

// in buildTransactionWebhookPayload
-const txSignatures = [];
+const txSignatures: SignatureEntry[] = [];

Also applies to: 67-77

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx (3)

138-145: Pluralize help text to match multi-address placeholder

Helper text says “Enter a contract address” but the placeholder and parser support multiple. Align the copy to reduce confusion.

-                  <p className="text-muted-foreground">
-                    Enter a contract address
-                  </p>
+                  <p className="text-muted-foreground">
+                    Enter contract addresses (comma-separated)
+                  </p>

343-364: Avoid duplicated onChange logic across event/transaction selectors

Both handlers normalize val, compute known, and clear abi if any custom sig. Consider extracting a small helper to DRY this.

Example extract outside the component:

function handleSignatureChange(
  val: string | string[],
  known: string[],
  onChange: (v: string[] | string) => void,
  clearAbi: () => void,
) {
  onChange(val);
  const values = Array.isArray(val) ? val : [val];
  if (values.some((v) => v && !known.includes(v))) {
    clearAbi();
  }
}

Then reuse in both places.


45-60: Add explicit return type on component per guidelines

Declare the return type to JSX.Element.

-export function FilterDetailsStep({
+export function FilterDetailsStep({
   form,
   eventSignatures,
   functionSignatures,
   fetchedAbis = {},
   abiErrors = {},
   fetchedTxAbis = {},
   txAbiErrors = {},
   isFetchingEventAbi,
   isFetchingTxAbi,
   goToNextStep,
   goToPreviousStep,
   isLoading,
   supportedChainIds,
   client,
-}: FilterDetailsStepProps) {
+}: FilterDetailsStepProps): JSX.Element {
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx (2)

446-449: Indicate multiple contract addresses in placeholder

The parser supports comma/space-separated addresses. Reflect that in the placeholder.

-                                                    <Input
-                                                      placeholder="0x..."
-                                                      {...field}
-                                                    />
+                                                    <Input
+                                                      placeholder="0x1234...,0xabcd..."
+                                                      {...field}
+                                                    />

61-66: Add explicit return type on component per guidelines

Declare the return type for the modal component to JSX.Element.

-export function TopicSelectorModal(props: TopicSelectorModalProps) {
+export function TopicSelectorModal(props: TopicSelectorModalProps): JSX.Element {
apps/dashboard/src/@/components/blocks/SignatureSelector.tsx (2)

23-34: Add explicit return type on component per guidelines

Declare JSX.Element on the component.

-export function SignatureSelector({
+export function SignatureSelector({
   options,
   value,
   onChange,
   setAbi,
   placeholder = "Select or enter a signature",
   disabled,
   secondaryTextFormatter,
   className,
   multiSelect = false,
-}: SignatureSelectorProps) {
+}: SignatureSelectorProps): JSX.Element {

106-119: Prevent duplicate custom values when pressing Enter

Currently, typing the same custom signature twice can append duplicates (since the check is only against options). Guard against values already selected.

   const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
     if (event.key === "Enter" && searchValue.trim()) {
       if (!options.some((opt) => opt.value === searchValue.trim())) {
         if (multiSelect) {
           // Add to existing values for multi-select
-          const currentArray = Array.isArray(value) ? value : (value ? [value] : []);
+          const currentArray = Array.isArray(value) ? value : (value ? [value] : []);
           const filteredArray = currentArray.filter((val): val is string => val !== undefined && val !== null);
-          const newValues = [...filteredArray, searchValue.trim()];
+          const trimmed = searchValue.trim();
+          if (filteredArray.includes(trimmed)) {
+            setSearchValue("");
+            inputRef.current?.blur();
+            return;
+          }
+          const newValues = [...filteredArray, trimmed];
           onChange(newValues);
         } else {
           // Replace value for single-select
           onChange(searchValue.trim());
         }
         if (setAbi) setAbi("");
         setSearchValue("");
         // Optionally blur input
         inputRef.current?.blur();
       }
     }
   };
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f7ce6be and ce6615d.

📒 Files selected for processing (8)
  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx (5 hunks)
  • apps/dashboard/src/@/components/blocks/multi-select.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx (7 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx (14 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookPayloadUtils.ts (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts
  • apps/dashboard/src/@/components/blocks/multi-select.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookPayloadUtils.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts
  • apps/dashboard/src/@/components/blocks/multi-select.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookPayloadUtils.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts
  • apps/dashboard/src/@/components/blocks/multi-select.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookPayloadUtils.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
🧠 Learnings (27)
📚 Learning: 2025-06-10T00:55:19.140Z
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/form.ts:12-14
Timestamp: 2025-06-10T00:55:19.140Z
Learning: The NFT collection form (`nftCollectionInfoFormSchema`) in `apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/form.ts` is intentionally designed to only allow File uploads for the `image` field, not hosted URLs. The schema correctly uses `z.instanceof(File).optional()` to restrict image inputs to uploaded files only.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
📚 Learning: 2025-06-26T19:46:04.024Z
Learnt from: gregfromstl
PR: thirdweb-dev/js#7450
File: packages/thirdweb/src/bridge/Webhook.ts:57-81
Timestamp: 2025-06-26T19:46:04.024Z
Learning: In the onramp webhook schema (`packages/thirdweb/src/bridge/Webhook.ts`), the `currencyAmount` field is intentionally typed as `z.number()` while other amount fields use `z.string()` because `currencyAmount` represents fiat currency amounts in decimals (like $10.50), whereas other amount fields represent token amounts in wei (very large integers that benefit from bigint representation). The different naming convention (`currencyAmount` vs `amount`) reflects this intentional distinction.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookPayloadUtils.ts
📚 Learning: 2025-07-10T10:18:33.238Z
Learnt from: arcoraven
PR: thirdweb-dev/js#7505
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/analytics/components/WebhookAnalyticsCharts.tsx:186-204
Timestamp: 2025-07-10T10:18:33.238Z
Learning: The ThirdwebBarChart component in apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/analytics/components/WebhookAnalyticsCharts.tsx does not accept standard accessibility props like `aria-label` and `role` in its TypeScript interface, causing compilation errors when added.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts
  • apps/dashboard/src/@/components/blocks/multi-select.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Return typed results (e.g., `Project[]`, `User[]`) – avoid `any`

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
📚 Learning: 2025-05-21T05:17:31.283Z
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/api/**/*.{ts,tsx} : Return typed results (`Project[]`, `User[]`, …) – avoid `any`.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts
📚 Learning: 2025-06-10T00:50:20.795Z
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookPayloadUtils.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-06-10T15:59:29.585Z
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/_common/SocialUrls.tsx:24-25
Timestamp: 2025-06-10T15:59:29.585Z
Learning: In the SocialUrlsFieldset component in React Hook Form with TypeScript generics, when using useFieldArray with a generic form type T that extends WithSocialUrls, the type assertion `as unknown as UseFormReturn<WithSocialUrls>` is the preferred approach rather than trying to use `as keyof T`, because useFieldArray needs specific type information about the array field structure.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

  • apps/dashboard/src/@/components/blocks/multi-select.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps

Applied to files:

  • apps/dashboard/src/@/components/blocks/multi-select.tsx
  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.

Applied to files:

  • apps/dashboard/src/@/components/blocks/multi-select.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{tsx} : Expose `className` prop on root element of components for overrides

Applied to files:

  • apps/dashboard/src/@/components/blocks/multi-select.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/@/components/blocks/multi-select.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Components that listen to user events, animations or live updates.

Applied to files:

  • apps/dashboard/src/@/components/blocks/multi-select.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx
📚 Learning: 2025-06-23T13:33:05.770Z
Learnt from: AmineAfia
PR: thirdweb-dev/js#7415
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/abiUtils.ts:31-42
Timestamp: 2025-06-23T13:33:05.770Z
Learning: In the thirdweb webhooks ABI utilities, validation of ABI inputs is performed upstream using the `isAbiInput` function before calling `getCanonicalType`. The `getCanonicalType` function only receives pre-validated inputs, so additional runtime validation within the function would be redundant.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Surface breaking changes prominently in PR descriptions

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Comment only ambiguous logic; avoid restating TypeScript in prose

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx
📚 Learning: 2025-06-10T00:49:12.707Z
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/upload-nfts/single-upload/attributes.tsx:24-25
Timestamp: 2025-06-10T00:49:12.707Z
Learning: In React Hook Form with TypeScript generics, when using useFieldArray with a generic form type T that extends a specific interface, it's often necessary to use type assertions like `as unknown as UseFormReturn<WithAttributes>` rather than trying to use `as keyof T`. The type assertion approach works better because useFieldArray needs specific type information about the array field structure, and the generic constraint ensures the field exists safely.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/wallets/** : EIP-1193, EIP-5792, EIP-7702 standard support in wallet modules

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookPayloadUtils.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Event name: human-readable `<subject> <verb>` phrase (e.g. "contract deployed").

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to src/@/analytics/report.ts : Analytics event name: human-readable `<subject> <verb>` (e.g., "contract deployed"); function: `report<Subject><Verb>` (PascalCase)

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
📚 Learning: 2025-06-13T13:50:08.622Z
Learnt from: MananTank
PR: thirdweb-dev/js#7332
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/nft/overview/nft-drop-claim.tsx:170-178
Timestamp: 2025-06-13T13:50:08.622Z
Learning: In event-tracking (`useTrack`) calls across the dashboard, the team intentionally keeps `contractType` generic as `"NFTCollection"` even for ERC-721 drops; contract differentiation is handled via the `ercType` field instead.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Accept a typed `props` object and export a named function (`export function MyComponent()`).

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Write idiomatic TypeScript with explicit function declarations and return types

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Choose composition over inheritance; leverage utility types (`Partial`, `Pick`, etc.)

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to src/exports/react.native.ts : React Native specific exports are in `src/exports/react.native.ts`

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.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). (6)
  • GitHub Check: Lint Packages
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Unit Tests
  • GitHub Check: Size
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (6)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts (1)

76-76: No remaining single-string assumptions for sigHash
Verified that all downstream handlers normalize sigHash to an array in:

  • webhookPayloadUtils.ts (lines 36, 67)
  • ReviewStep.tsx (lines 197–202)
  • CreateWebhookModal.tsx (line 68)
  • FilterDetailsStep.tsx (line 79)
  • topic-selector-modal.tsx (multiple occurrences)

All usages guard against a lone string and wrap it in an array, so the schema change is fully supported.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx (1)

68-68: Default sigHash as [] aligns with multi-select

Defaulting to an empty array matches the updated schema and the new UI flows. No issues.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx (2)

79-85: Custom signature detection correctly handles single/multi values

The normalization to sigHashes and .some checks against known signatures looks correct and resilient.


319-338: Event signature selector multi-select usage looks good

Passing multiSelect, normalizing value to an array, and clearing abi on custom signatures are all correct. Good job keeping sigHashAbi separate.

apps/dashboard/src/@/components/blocks/SignatureSelector.tsx (2)

13-21: API surface for multi-select looks solid

Prop types (value and onChange) and multiSelect flag correctly enable single/multi modes while keeping backward compatibility.

Also applies to: 32-33


164-170: Clear, contextual guidance for custom entries

The warning copy adapts to single/multi and is helpful. Nice touch.

@vercel vercel bot temporarily deployed to Preview – wallet-ui August 8, 2025 17:42 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 August 8, 2025 17:42 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula August 8, 2025 17:42 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground August 8, 2025 17:42 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula August 8, 2025 17:46 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 August 8, 2025 17:46 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui August 8, 2025 17:46 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground August 8, 2025 17:46 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground August 8, 2025 17:52 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui August 8, 2025 17:52 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 August 8, 2025 17:52 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula August 8, 2025 17:52 Inactive
@nischitpra nischitpra enabled auto-merge (squash) August 8, 2025 17:54
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 (2)
apps/dashboard/src/@/components/blocks/SignatureSelector.tsx (2)

47-64: Reduce branching by normalising value once

The current currentValues memo has four nested branches and repeats the same null/undefined filtering.
Normalising value to an array up-front makes the intent clearer and avoids edge-cases.

-const currentValues = useMemo((): string[] => {
-  if (multiSelect) {
-    if (Array.isArray(value)) {
-      return value.filter((val): val is string => val !== undefined && val !== null);
-    } else {
-      return value ? [value] : [];
-    }
-  } else {
-    if (Array.isArray(value)) {
-      return value.length > 0 && value[0] ? [value[0]] : [];
-    } else {
-      return value ? [value] : [];
-    }
-  }
-}, [value, multiSelect]);
+const currentValues = useMemo(() => {
+  const arr = Array.isArray(value) ? value : [value];
+  return arr.filter(Boolean) as string[];
+}, [value]);

This also prevents accidental duplication when multiSelect is false but an array is passed.


115-140: Call preventDefault() on Enter to stop unintended form submits

Pressing Enter inside the search input can bubble up and trigger a surrounding <form> submit. Add event.preventDefault() (and optionally event.stopPropagation()) before mutating state:

-if (event.key === "Enter" && searchValue.trim()) {
+if (event.key === "Enter" && searchValue.trim()) {
+  event.preventDefault();

Minor, but it avoids accidental navigation and improves accessibility.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ce6615d and e03da96.

📒 Files selected for processing (5)
  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx (5 hunks)
  • apps/dashboard/src/@/components/blocks/multi-select.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx (7 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookPayloadUtils.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookPayloadUtils.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx
  • apps/dashboard/src/@/components/blocks/multi-select.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Surface breaking changes prominently in PR descriptions
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-06-10T00:50:20.795Z
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Choose composition over inheritance; leverage utility types (`Partial`, `Pick`, etc.)

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to src/exports/react.native.ts : React Native specific exports are in `src/exports/react.native.ts`

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.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). (8)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
  • GitHub Check: Build Packages
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Lint Packages
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Analyze (javascript)

Copy link
Member

@jnsdls jnsdls left a comment

Choose a reason for hiding this comment

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

look at 🐰 and try to incorporate, otherwise LGTM

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

🔭 Outside diff range comments (1)
apps/dashboard/src/@/components/blocks/SignatureSelector.tsx (1)

1-4: Missing 'use client' directive

This component uses React hooks, so it must start with 'use client'; to be treated as a client component in Next.js.
Add it as the very first line.

+'use client';
 import { useCallback, useMemo, useRef, useState } from "react";
♻️ Duplicate comments (2)
apps/dashboard/src/@/components/blocks/SignatureSelector.tsx (2)

11-21: Use a discriminated union for props
Current value/onChange unions aren’t tied to multiSelect, letting invalid combos through. The earlier review already provided a union example; please apply it for compile-time safety.


88-106: De-duplicate selections in multi-select mode

onChange(selected) forwards the array verbatim, so the same signature can be added multiple times (e.g., via manual input). Deduplicate before propagating:

-  onChange(selected);
+  onChange([...new Set(selected)]);
🧹 Nitpick comments (1)
apps/dashboard/src/@/components/blocks/SignatureSelector.tsx (1)

94-101: Avoid redundant setAbi calls

setAbi fires every selection change even when the ABI hasn’t changed. Cache the previous ABI or compare before updating to prevent unnecessary re-renders.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e03da96 and 3bc5353.

📒 Files selected for processing (3)
  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx (5 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx (14 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
🧠 Learnings (18)
📓 Common learnings
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Surface breaking changes prominently in PR descriptions
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Choose composition over inheritance; leverage utility types (`Partial`, `Pick`, etc.)

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-06-10T00:50:20.795Z
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to src/exports/react.native.ts : React Native specific exports are in `src/exports/react.native.ts`

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Avoid `any` and `unknown` unless unavoidable; narrow generics when possible

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Return typed results (e.g., `Project[]`, `User[]`) – avoid `any`

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Write idiomatic TypeScript with explicit function declarations and return types

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Prefer type aliases over interface except for nominal shapes

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Comment only ambiguous logic; avoid restating TypeScript in prose

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Limit each file to one stateless, single-responsibility function for clarity

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-06-10T15:59:29.585Z
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/_common/SocialUrls.tsx:24-25
Timestamp: 2025-06-10T15:59:29.585Z
Learning: In the SocialUrlsFieldset component in React Hook Form with TypeScript generics, when using useFieldArray with a generic form type T that extends WithSocialUrls, the type assertion `as unknown as UseFormReturn<WithSocialUrls>` is the preferred approach rather than trying to use `as keyof T`, because useFieldArray needs specific type information about the array field structure.

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to src/@/analytics/report.ts : Review `src/@/analytics/report.ts` before adding analytics events to check for duplicates

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Components that listen to user events, animations or live updates.

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-06-24T21:38:03.155Z
Learnt from: MananTank
PR: thirdweb-dev/js#7434
File: apps/dashboard/src/app/(app)/team/~/~/contract/[chain]/[contractAddress]/components/project-selector.tsx:62-76
Timestamp: 2025-06-24T21:38:03.155Z
Learning: In the project-selector.tsx component for contract imports, the addToProject.mutate() call is intentionally not awaited (fire-and-forget pattern) to allow immediate navigation to the contract page while the import happens in the background. This is a deliberate design choice to prioritize user experience.

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.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). (1)
  • GitHub Check: Size

Comment on lines +123 to +133
const currentArray = Array.isArray(value)
? value
: value
? [value]
: [];
const filteredArray = currentArray.filter(
(val): val is string => val !== undefined && val !== null,
);
const newValues = [...filteredArray, searchValue.trim()];
onChange(newValues);
} else {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Also de-duplicate when adding custom values

The manual-input path appends searchValue without checking for duplicates, leading to repeated entries. Apply the same new Set(...) pattern here.

🤖 Prompt for AI Agents
In apps/dashboard/src/@/components/blocks/SignatureSelector.tsx around lines 123
to 133, the code appends searchValue to the array without removing duplicates,
causing repeated entries. To fix this, wrap the combined array of filteredArray
and searchValue.trim() with a new Set to eliminate duplicates before converting
it back to an array. Then pass this deduplicated array to onChange.

Copy link
Contributor Author

nischitpra commented Aug 8, 2025

Merge activity

<!-- start pr-codex -->

## PR-Codex overview
This PR focuses on modifying the handling of `sigHash` to support both single and multiple signature inputs across various components, improving user experience and functionality.

### Detailed summary
- Changed `sigHash` from a string to an array in multiple components.
- Updated validation and handling of `sigHash` in forms and utilities.
- Enhanced UI to reflect multiple signature selections.
- Adjusted props and methods to support multi-select functionality in `SignatureSelector` and related components.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Added support for selecting multiple signature hashes in webhook filters and selectors.
  * Enhanced signature selectors to allow both single-select and multi-select modes, with improved handling of custom signatures.

* **Improvements**
  * Updated UI labels, placeholders, and descriptions to reflect multi-selection capabilities and pluralization.
  * Review and summary steps now display multiple selected signatures with appropriate formatting.
  * Webhook payloads and validation schemas now support arrays of signature hashes for improved flexibility.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@graphite-app graphite-app bot force-pushed the np/webhook_multi_topic branch from 80a9fac to f92201d Compare August 8, 2025 20:18
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground August 8, 2025 20:18 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui August 8, 2025 20:18 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula August 8, 2025 20:18 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 August 8, 2025 20:18 Inactive
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 (2)
apps/dashboard/src/@/components/blocks/SignatureSelector.tsx (2)

11-15: Type-safety gap still unresolved

The props still rely on string | string[] instead of a discriminated union keyed on multiSelect, so misuse is not caught at compile-time. See earlier review for the suggested union definition.

Also applies to: 20-20


90-101: Duplicate entries can still slip through

selected and the array built after manual entry are forwarded as-is, so the same signature can be added multiple times. Deduplicate before calling onChange, e.g.:

- onChange(selected);
+ onChange([...new Set(selected)]);

and

- const newValues = [...filteredArray, searchValue.trim()];
+ const newValues = [...new Set([...filteredArray, searchValue.trim()])];

Also applies to: 121-133

🧹 Nitpick comments (1)
apps/dashboard/src/@/components/blocks/SignatureSelector.tsx (1)

80-85: Possible duplicate option objects

allOptions concatenates formattedOptions with customOptions even when a custom value already exists in the customOptions array from a previous render, producing duplicate entries in the dropdown. Guard with a Set on value before mapping, or dedupe after concatenation.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3bc5353 and f92201d.

📒 Files selected for processing (8)
  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx (5 hunks)
  • apps/dashboard/src/@/components/blocks/multi-select.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx (7 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx (14 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookPayloadUtils.ts (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookTypes.ts
  • apps/dashboard/src/@/components/blocks/multi-select.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/utils/webhookPayloadUtils.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/topic-selector-modal.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/CreateWebhookModal.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/ReviewStep.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/components/FilterDetailsStep.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

Files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
🧠 Learnings (19)
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-06-10T00:50:20.795Z
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Choose composition over inheritance; leverage utility types (`Partial`, `Pick`, etc.)

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Avoid `any` and `unknown` unless unavoidable; narrow generics when possible

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Return typed results (e.g., `Project[]`, `User[]`) – avoid `any`

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Write idiomatic TypeScript with explicit function declarations and return types

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Prefer type aliases over interface except for nominal shapes

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Comment only ambiguous logic; avoid restating TypeScript in prose

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to **/*.{ts,tsx} : Limit each file to one stateless, single-responsibility function for clarity

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-06-10T15:59:29.585Z
Learnt from: MananTank
PR: thirdweb-dev/js#7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/_common/SocialUrls.tsx:24-25
Timestamp: 2025-06-10T15:59:29.585Z
Learning: In the SocialUrlsFieldset component in React Hook Form with TypeScript generics, when using useFieldArray with a generic form type T that extends WithSocialUrls, the type assertion `as unknown as UseFormReturn<WithSocialUrls>` is the preferred approach rather than trying to use `as keyof T`, because useFieldArray needs specific type information about the array field structure.

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Reuse core UI primitives; avoid re-implementing buttons, cards, modals.

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to src/@/analytics/report.ts : Review `src/@/analytics/report.ts` before adding analytics events to check for duplicates

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Components that listen to user events, animations or live updates.

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-06-24T21:38:03.155Z
Learnt from: MananTank
PR: thirdweb-dev/js#7434
File: apps/dashboard/src/app/(app)/team/~/~/contract/[chain]/[contractAddress]/components/project-selector.tsx:62-76
Timestamp: 2025-06-24T21:38:03.155Z
Learning: In the project-selector.tsx component for contract imports, the addToProject.mutate() call is intentionally not awaited (fire-and-forget pattern) to allow immediate navigation to the contract page while the import happens in the background. This is a deliberate design choice to prioritize user experience.

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Keep `queryKey` stable and descriptive for cache hits.

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use descriptive, stable `queryKeys` for React Query cache hits

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*.{tsx,jsx} : Keep components pure; fetch data outside (server component or hook) and pass it down via props.

Applied to files:

  • apps/dashboard/src/@/components/blocks/SignatureSelector.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). (8)
  • GitHub Check: Size
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Unit Tests
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Build Packages
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)

@graphite-app graphite-app bot merged commit f92201d into main Aug 8, 2025
24 checks passed
@graphite-app graphite-app bot deleted the np/webhook_multi_topic branch August 8, 2025 20:26
@graphite-app graphite-app bot removed the merge-queue Adds the pull request to Graphite's merge queue. label Aug 8, 2025
@vercel vercel bot temporarily deployed to Production – thirdweb_playground August 8, 2025 20:26 Inactive
@vercel vercel bot temporarily deployed to Production – wallet-ui August 8, 2025 20:26 Inactive
@vercel vercel bot temporarily deployed to Production – docs-v2 August 8, 2025 20:26 Inactive
@vercel vercel bot temporarily deployed to Production – nebula August 8, 2025 20:26 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Dashboard Involves changes to the Dashboard.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants