-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Duplicate campaign logic warning #3103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded@TWilson023 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 17 minutes and 38 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
WalkthroughThis PR introduces duplicate campaign detection functionality. It adds API filtering by trigger condition, a new warning component that detects and displays campaigns with duplicate logic, extends the CampaignTypeIcon component for customization, introduces a new Clone2 SVG icon, and updates the query schema to support trigger condition filtering. Changes
Sequence DiagramsequenceDiagram
actor User
participant Editor as Campaign Editor
participant Warning as Duplicate Warning
participant API as Campaigns API
participant DB as Database
User->>Editor: Open campaign for editing
activate Editor
Editor->>Warning: Render (with triggerCondition)
activate Warning
Warning->>API: GET /api/campaigns?triggerCondition={condition}
activate API
API->>DB: Query campaigns by triggerCondition
DB-->>API: Return matching campaigns
API-->>Warning: Campaign list
deactivate API
Warning->>Warning: Filter duplicates<br/>(exclude current, draft, canceled)
alt Duplicates found
Warning->>Warning: Render accordion with duplicates
Warning-->>User: Show warning with duplicate links
else No duplicates
Warning->>Warning: Hide/disable accordion
end
deactivate Warning
deactivate Editor
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Areas requiring extra attention:
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (1)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/duplicate-logic-warning.tsx (1)
74-78: Consider showing loading state only on initial load.The loading spinner appears every time the trigger condition changes due to
keepPreviousData: true. This might create a flickering effect during form editing. Consider showing the spinner only when there's no previous data.- {isLoading ? ( + {isLoading && !campaigns ? ( <LoadingSpinner className="size-3 shrink-0" /> ) : ( <Clone2 className="text-content-emphasis size-3 shrink-0" /> )}This way, the Clone2 icon remains visible during background refreshes, providing a smoother UX.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
apps/web/app/(ee)/api/campaigns/route.ts(2 hunks)apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/campaign-editor.tsx(2 hunks)apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/duplicate-logic-warning.tsx(1 hunks)apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/campaign-type-icon.tsx(1 hunks)apps/web/lib/zod/schemas/campaigns.ts(1 hunks)packages/ui/src/icons/nucleo/clone2.tsx(1 hunks)packages/ui/src/icons/nucleo/index.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: TWilson023
Repo: dubinc/dub PR: 2872
File: apps/web/app/(ee)/partners.dub.co/(dashboard)/profile/profile-details-form.tsx:180-189
Timestamp: 2025-09-24T15:50:16.414Z
Learning: TWilson023 prefers to keep security vulnerability fixes separate from refactoring PRs when the vulnerable code is existing and was only moved/relocated rather than newly introduced.
📚 Learning: 2025-07-30T15:25:13.936Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2673
File: apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx:56-66
Timestamp: 2025-07-30T15:25:13.936Z
Learning: In apps/web/ui/partners/rewards/add-edit-reward-sheet.tsx, the form schema uses partial condition objects to allow users to add empty/unconfigured condition fields without type errors, while submission validation uses strict schemas to ensure data integrity. This two-stage validation pattern improves UX by allowing progressive completion of complex forms.
Applied to files:
apps/web/lib/zod/schemas/campaigns.ts
📚 Learning: 2025-08-25T17:33:45.072Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2736
File: apps/web/app/(ee)/api/stripe/integration/webhook/invoice-paid.ts:12-12
Timestamp: 2025-08-25T17:33:45.072Z
Learning: The WorkflowTrigger enum in packages/prisma/schema/workflow.prisma contains three values: leadRecorded, saleRecorded, and commissionEarned. All three are properly used throughout the codebase.
Applied to files:
apps/web/lib/zod/schemas/campaigns.ts
📚 Learning: 2025-10-15T01:05:43.266Z
Learnt from: steven-tey
Repo: dubinc/dub PR: 2958
File: apps/web/app/app.dub.co/(dashboard)/[slug]/settings/members/page-client.tsx:432-457
Timestamp: 2025-10-15T01:05:43.266Z
Learning: In apps/web/app/app.dub.co/(dashboard)/[slug]/settings/members/page-client.tsx, defer refactoring the custom MenuItem component (lines 432-457) to use the shared dub/ui MenuItem component to a future PR, as requested by steven-tey.
Applied to files:
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/duplicate-logic-warning.tsxapps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/campaign-type-icon.tsxapps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/campaign-editor.tsx
📚 Learning: 2025-09-24T16:10:37.349Z
Learnt from: TWilson023
Repo: dubinc/dub PR: 2872
File: apps/web/ui/partners/partner-about.tsx:11-11
Timestamp: 2025-09-24T16:10:37.349Z
Learning: In the Dub codebase, the team prefers to import Icon as a runtime value from "dub/ui" and uses Icon as both a type and variable name in component props, even when this creates shadowing. This is their established pattern and should not be suggested for refactoring.
Applied to files:
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/campaign-type-icon.tsx
📚 Learning: 2025-05-29T04:45:18.504Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2448
File: packages/email/src/templates/partner-program-summary.tsx:0-0
Timestamp: 2025-05-29T04:45:18.504Z
Learning: In the PartnerProgramSummary email template (packages/email/src/templates/partner-program-summary.tsx), the stat titles are hardcoded constants ("Clicks", "Leads", "Sales", "Earnings") that will always match the ICONS object keys after toLowerCase() conversion, so icon lookup failures are not possible.
Applied to files:
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/campaign-type-icon.tsx
🧬 Code graph analysis (4)
apps/web/lib/zod/schemas/campaigns.ts (1)
apps/web/lib/zod/schemas/workflows.ts (1)
workflowConditionSchema(66-70)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/duplicate-logic-warning.tsx (4)
apps/web/lib/swr/use-workspace.ts (1)
useWorkspace(6-46)apps/web/lib/zod/schemas/workflows.ts (1)
workflowConditionSchema(66-70)apps/web/lib/types.ts (1)
CampaignList(629-629)apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/campaign-type-icon.tsx (1)
CampaignTypeIcon(4-27)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/campaign-type-icon.tsx (2)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/campaign-type-badges.tsx (1)
CAMPAIGN_TYPE_BADGES(3-16)packages/ui/src/icons/index.tsx (1)
Icon(80-80)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/campaign-editor.tsx (1)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/duplicate-logic-warning.tsx (1)
DuplicateLogicWarning(14-122)
🔇 Additional comments (2)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/campaign-type-icon.tsx (1)
4-27: LGTM! Clean prop enhancement with proper shadowing avoidance.The refactor correctly introduces the
iconClassNameprop while avoiding variable shadowing by renaming the internal variable totypeIconClassName. This enables customization of the icon's styling independently from the container's styling.apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/duplicate-logic-warning.tsx (1)
27-39: The review comment regarding JSON serialization in query parameters is incorrect.The codebase already implements the proper pattern: the
getCampaignsQuerySchemauses.pipe()with.preprocess()to convert the JSON string from query parameters back into a parsed object, then validates it againstworkflowConditionSchema.Since the schema contains only three small fields (attribute enum, operator enum, and value number), URL length limitations are not a realistic concern here. The serialized size will be minimal (under 200 characters).
The current implementation is correct and handles JSON in query strings properly without needing changes.
Likely an incorrect or invalid review comment.
...eb/app/app.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/campaign-editor.tsx
Show resolved
Hide resolved
...pp.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/duplicate-logic-warning.tsx
Show resolved
Hide resolved
...pp.dub.co/(dashboard)/[slug]/(ee)/program/campaigns/[campaignId]/duplicate-logic-warning.tsx
Outdated
Show resolved
Hide resolved
| triggerCondition: z | ||
| .string() | ||
| .pipe( | ||
| z.preprocess( | ||
| (input: string) => JSON.parse(input), | ||
| workflowConditionSchema, | ||
| ), | ||
| ) | ||
| .optional(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Harden triggerCondition parsing against malformed input.
JSON.parse inside the preprocess will throw a SyntaxError for any malformed triggerCondition query string. Because this happens during getCampaignsQuerySchema.parse, the exception bypasses Zod’s validation path and bubbles out as a 500 response instead of a 400. Please guard the parse and surface a validation error, e.g.:
- triggerCondition: z
- .string()
- .pipe(
- z.preprocess(
- (input: string) => JSON.parse(input),
- workflowConditionSchema,
- ),
- )
- .optional(),
+ triggerCondition: z
+ .string()
+ .transform((raw) => {
+ try {
+ return JSON.parse(raw);
+ } catch {
+ throw new z.ZodError([
+ {
+ code: z.ZodIssueCode.custom,
+ message: "triggerCondition must be valid JSON",
+ path: ["triggerCondition"],
+ },
+ ]);
+ }
+ })
+ .pipe(workflowConditionSchema)
+ .optional(),Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/web/lib/zod/schemas/campaigns.ts around lines 109 to 117, the preprocess
currently calls JSON.parse directly which will throw on malformed input and
escape Zod's validation flow; wrap the JSON.parse call in a try/catch inside the
preprocess, return the parsed value on success and (on failure) return the
original input (or undefined) so that workflowConditionSchema receives a
non-parsed value and Zod produces a validation error (400) instead of letting
the SyntaxError bubble up; ensure no raw exceptions are thrown from the
preprocess.
… duplicate-campaign-logic
Summary by CodeRabbit
Release Notes
New Features
Enhancements