-
Notifications
You must be signed in to change notification settings - Fork 3.1k
[WEB-5782]chore: migrated modals to @plane/ui #8420
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
|
Linked to Plane Work Item(s) This comment was auto-generated by Plane |
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughThis PR migrates ~25 modal components from Headless UI Dialog/Transition implementations to a unified ModalCore-based modal system, replacing nested Transition/Dialog wrappers with ModalCore (position and width enums) while preserving internal content, logic, validation, and public component signatures. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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.
This is the final PR Bugbot will review for you during this billing cycle
Your free Bugbot reviews will reset on January 20
Details
Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
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: 11
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
apps/web/core/components/core/filters/date-filter-modal.tsx (1)
43-43: Critical bug:date2watches wrong form field.Line 43 incorrectly watches
"date1"instead of"date2", causingdate2to always equaldate1. This breaks the range validation on Line 45—isInvalidwill always befalse, allowing users to select invalid date ranges where the start date is after the end date.🔎 Proposed fix
const date1 = getDate(watch("date1")); - const date2 = getDate(watch("date1")); + const date2 = getDate(watch("date2"));apps/web/core/components/workspace-notifications/sidebar/notification-card/options/snooze/modal.tsx (2)
74-86: Time filtering logic doesn't handle 12 AM correctly.When filtering times for today, the AM period with hour 12 (12:00 AM, 12:30 AM) should be treated as hour 0, but the current logic doesn't convert it. This could cause 12 AM times to be incorrectly filtered.
🔎 Proposed fix
return timeStamps.filter((optionTime) => { let optionHours = parseInt(optionTime.value.split(":")[0]); const optionMinutes = parseInt(optionTime.value.split(":")[1]); const period = watch("period"); - if (period === "PM" && optionHours !== 12) optionHours += 12; + if (period === "PM" && optionHours !== 12) optionHours += 12; + if (period === "AM" && optionHours === 12) optionHours = 0; if (optionHours < hours) return false; if (optionHours === hours && optionMinutes < minutes) return false;
93-98: Hour conversion for 12-hour to 24-hour format has edge case bugs.The conversion logic incorrectly handles 12 PM (should stay 12, not become 0) and 12 AM (should become 0, but isn't handled). The current check
parseInt(time[0]) + 12 === 24converts 12 PM to "00" which is midnight, not noon.🔎 Proposed fix for proper 12-hour to 24-hour conversion
const time = formData.time.split(":"); - const hours = parseInt( - `${period === "AM" ? time[0] : parseInt(time[0]) + 12 === 24 ? "00" : parseInt(time[0]) + 12}` - ); + let hours = parseInt(time[0]); + if (period === "AM" && hours === 12) { + hours = 0; // 12 AM is midnight (0:00) + } else if (period === "PM" && hours !== 12) { + hours += 12; // PM hours except 12 PM need +12 + } + // 12 PM stays as 12 const minutes = parseInt(time[1]);apps/web/core/components/issues/parent-issues-list-modal.tsx (1)
66-85: MissingsearchEpicin useEffect dependency array.The effect uses
searchEpicat lines 75 and 78 to conditionally set theparentandepicparameters, but it's not included in the dependency array. IfsearchEpicchanges while the modal is open, the search won't re-trigger with the updated value.🔎 Proposed fix
- }, [debouncedSearchTerm, isOpen, issueId, projectId, workspaceSlug]); + }, [debouncedSearchTerm, isOpen, issueId, projectId, workspaceSlug, searchEpic]);apps/web/core/components/core/modals/existing-issues-list-modal.tsx (1)
127-129: Incomplete dependency array in useEffect.The
handleSearchfunction referencessearchParamsandworkItemSearchServiceCallbackfrom props, but these aren't included in the dependency array. Changes to these props won't trigger a new search.🔎 Proposed fix
Consider using
useCallbackforhandleSearchand including it in deps, or add the missing dependencies:useEffect(() => { handleSearch(); - }, [debouncedSearchTerm, isOpen, isWorkspaceLevel, projectId, workspaceSlug]); + }, [debouncedSearchTerm, isOpen, isWorkspaceLevel, projectId, workspaceSlug, searchParams, workItemSearchServiceCallback]);Note: If
searchParamsis an object that changes reference on each render, you may need to stabilize it at the call site or use a deep comparison.
🧹 Nitpick comments (14)
apps/web/core/components/inbox/modals/snooze-issue-modal.tsx (2)
18-18: State not synced with prop changes.If
valueprop changes while the component remains mounted,datestate won't update sinceuseStateonly uses the initial value. Consider adding auseEffectto sync state when the modal opens:useEffect(() => { if (isOpen) { setDate(value || new Date()); } }, [isOpen, value]);This ensures the calendar reflects the latest
valueeach time the modal opens.
28-29: Redundantnew Date()wrapping.Since
dateis already aDateobject (initialized on line 18), wrapping it withnew Date(date)is unnecessary.🔎 Proposed simplification
- selected={date ? new Date(date) : undefined} - defaultMonth={date ? new Date(date) : undefined} + selected={date} + defaultMonth={date}apps/web/core/components/integration/delete-import-modal.tsx (1)
14-19: Remove unuseduserprop.The
userparameter is declared in the Props interface but never used in the component. Consider removing it to keep the interface clean.🔎 Proposed fix
type Props = { isOpen: boolean; handleClose: () => void; data: IImporterService | null; - user: IUser | null; };apps/web/core/components/core/filters/date-filter-modal.tsx (1)
49-49: Consider addingonSubmithandler to form element for better keyboard accessibility.Currently the form submission is triggered only via the Apply button's
onClick. Adding anonSubmithandler to the<form>element would allow users to submit by pressing Enter, improving keyboard navigation.🔎 Suggested enhancement
- <form className="space-y-4 px-5 py-8 sm:p-6"> + <form className="space-y-4 px-5 py-8 sm:p-6" onSubmit={handleSubmit(handleFormSubmit)}>Then update the Apply button to use
type="submit"instead oftype="button":<Button variant="primary" size="lg" - type="button" + type="submit" - onClick={handleSubmit(handleFormSubmit)} disabled={isInvalid} > Apply </Button>apps/web/core/components/cycles/archived-cycles/modal.tsx (1)
54-54: Redundantreturnstatement.The
return;inside the.then()callback has no effect—.finally()executes regardless, and the return value of.then()is unused. This is harmless but unnecessary.🔎 Suggested cleanup
onClose(); router.push(`/${workspaceSlug}/projects/${projectId}/cycles`); - return; })apps/web/core/components/modules/archived-modules/modal.tsx (1)
46-46: Redundantreturnstatement (same as cycles modal).Same observation as in
archived-cycles/modal.tsx—thereturn;has no effect inside the.then()callback.🔎 Suggested cleanup
onClose(); router.push(`/${workspaceSlug}/projects/${projectId}/modules`); - return; })apps/web/core/components/project/join-project-modal.tsx (1)
28-43: Consider removing redundant return statement.Line 35 contains an explicit
return;afterhandleClose()in the promise chain. Since there's no code following it in the then() block, this return is unnecessary.🔎 Optional cleanup
await joinProject(workspaceSlug, project.id) .then(() => { router.push(`/${workspaceSlug}/projects/${project.id}/issues`); handleClose(); - return; })apps/web/core/components/issues/archive-issue-modal.tsx (1)
40-62: Consider removing redundant return statement.Line 52 has an unnecessary explicit
return;afteronClose()in the success handler. This doesn't change behavior but can be removed for cleaner code.🔎 Optional cleanup
await onSubmit() .then(() => { setToast({ type: TOAST_TYPE.SUCCESS, title: t("issue.archive.success.label"), message: t("issue.archive.success.message"), }); onClose(); - return; })apps/web/core/components/project/settings/archive-project/archive-restore-modal.tsx (1)
36-80: Consider removing redundant return statements.Lines 47 and 70 contain unnecessary explicit
return;statements afterrouter.push()in the success handlers. These don't affect behavior and can be removed.🔎 Optional cleanup
await archiveProject(workspaceSlug, projectId) .then(() => { setToast({ type: TOAST_TYPE.SUCCESS, title: "Archive success", message: `${projectDetails.name} has been archived successfully`, }); onClose(); router.push(`/${workspaceSlug}/projects/`); - return; })await restoreProject(workspaceSlug, projectId) .then(() => { setToast({ type: TOAST_TYPE.SUCCESS, title: "Restore success", message: `You can find ${projectDetails.name} in your projects.`, }); onClose(); router.push(`/${workspaceSlug}/projects/`); - return; })apps/web/core/components/core/modals/bulk-delete-issues-modal.tsx (1)
8-8: Note: Partial Headless UI dependency remains.While the modal wrapper has been migrated to ModalCore, the Combobox component from
@headlessui/reactis still in use. This maintains a partial dependency on Headless UI. Consider whether Combobox should also be migrated to a @plane/ui component in a future refactor for consistency.apps/web/core/components/core/modals/workspace-image-upload-modal.tsx (1)
151-165: Layout inconsistency: content outside padded container.The format helper text (line 152) and button container (lines 153-165) appear to lack the consistent padding applied to the main content div (line 105:
px-5 py-8). This may cause visual misalignment.🔎 Proposed fix to add consistent padding
</div> - <p className="my-4 text-13 text-secondary">File formats supported- .jpeg, .jpg, .png, .webp</p> - <div className="flex items-center justify-between"> + <p className="my-4 px-5 text-13 text-secondary">File formats supported- .jpeg, .jpg, .png, .webp</p> + <div className="flex items-center justify-between px-5 pb-5"> <Button variant="error-fill" size="lg" onClick={handleImageRemove} disabled={!value} loading={isRemoving}>apps/web/core/components/issues/parent-issues-list-modal.tsx (1)
111-120: Hardcoded English text should use i18n.The search results heading uses hardcoded English ("Search results for ... in project:") while
t()is available and used elsewhere in the component (e.g., line 103). This should be translated for consistency.🔎 Proposed fix
{searchTerm !== "" && ( <h5 className="mx-2 text-13 text-secondary"> - Search results for{" "} - <span className="text-primary"> - {'"'} - {searchTerm} - {'"'} - </span>{" "} - in project: + {t("common.search.results_for", { term: searchTerm })} </h5> )}Requires adding the translation key to your i18n config.
apps/web/core/components/core/modals/existing-issues-list-modal.tsx (1)
209-220: TODO comment and hardcoded text should be addressed.There's a TODO comment indicating the search results text needs translation. The hardcoded English text ("Search results for ... in project:") is inconsistent with the i18n usage elsewhere in this file.
Would you like me to open an issue to track this translation task, or would you prefer to address it in this PR?
apps/web/core/components/automation/select-month-modal.tsx (1)
48-115: Consider extracting duplicated field logic.The
close_inandarchive_infields share identical validation rules, error messages, and rendering structure. Extracting this into a helper function would improve maintainability.💡 Example refactor to reduce duplication
const fieldName = type === "auto-close" ? "close_in" : "archive_in"; <Controller control={control} name={fieldName} rules={{ required: "Select a month between 1 and 12.", min: 1, max: 12, }} render={({ field: { value, onChange, ref } }) => ( <div className="relative flex w-full flex-col justify-center gap-1"> <Input id={fieldName} name={fieldName} type="number" value={value?.toString()} onChange={onChange} ref={ref} hasError={Boolean(errors[fieldName])} placeholder="Enter Months" className="w-full border-subtle" min={1} max={12} /> <span className="absolute right-8 top-2.5 text-13 text-secondary">Months</span> </div> )} /> {errors[fieldName] && ( <span className="px-1 text-13 text-red-500">Select a month between 1 and 12.</span> )}
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (25)
apps/web/core/components/account/deactivate-account-modal.tsxapps/web/core/components/automation/select-month-modal.tsxapps/web/core/components/core/filters/date-filter-modal.tsxapps/web/core/components/core/modals/bulk-delete-issues-modal.tsxapps/web/core/components/core/modals/change-email-modal.tsxapps/web/core/components/core/modals/existing-issues-list-modal.tsxapps/web/core/components/core/modals/user-image-upload-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsxapps/web/core/components/cycles/archived-cycles/modal.tsxapps/web/core/components/cycles/transfer-issues-modal.tsxapps/web/core/components/exporter/export-modal.tsxapps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/inbox/modals/snooze-issue-modal.tsxapps/web/core/components/integration/delete-import-modal.tsxapps/web/core/components/issues/archive-issue-modal.tsxapps/web/core/components/issues/confirm-issue-discard.tsxapps/web/core/components/issues/parent-issues-list-modal.tsxapps/web/core/components/modules/archived-modules/modal.tsxapps/web/core/components/project/confirm-project-member-remove.tsxapps/web/core/components/project/delete-project-modal.tsxapps/web/core/components/project/join-project-modal.tsxapps/web/core/components/project/leave-project-modal.tsxapps/web/core/components/project/send-project-invitation-modal.tsxapps/web/core/components/project/settings/archive-project/archive-restore-modal.tsxapps/web/core/components/workspace-notifications/sidebar/notification-card/options/snooze/modal.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,mts,cts}
📄 CodeRabbit inference engine (.github/instructions/typescript.instructions.md)
**/*.{ts,tsx,mts,cts}: Useconsttype parameters for more precise literal inference in TypeScript 5.0+
Use thesatisfiesoperator to validate types without widening them
Leverage inferred type predicates to reduce the need for explicitisreturn types in filter/check functions
UseNoInfer<T>utility to block inference for specific type arguments when they should be determined by other arguments
Utilize narrowing inswitch(true)blocks for control flow analysis (TypeScript 5.3+)
Rely on narrowing from direct boolean comparisons for type guards
Trust preserved narrowing in closures when variables aren't modified after the check (TypeScript 5.4+)
Use constant indices to narrow object/array properties (TypeScript 5.5+)
Use standard ECMAScript decorators (Stage 3) instead of legacyexperimentalDecorators
Useusingdeclarations for explicit resource management with Disposable pattern instead of manual cleanup (TypeScript 5.2+)
Usewith { type: "json" }for import attributes; avoid deprecatedassertsyntax (TypeScript 5.3/5.8+)
Useimport typeexplicitly when importing types to ensure they are erased during compilation, respectingverbatimModuleSyntaxflag
Use.ts,.mts,.ctsextensions inimport typestatements (TypeScript 5.2+)
Useimport type { Type } from "mod" with { "resolution-mode": "import" }for specific module resolution contexts (TypeScript 5.3+)
Use new iterator methods (map, filter, etc.) if targeting modern environments (TypeScript 5.6+)
Utilize newSetmethods likeunion,intersection, etc., when available (TypeScript 5.5+)
UseObject.groupBy/Map.groupBystandard methods for grouping instead of external libraries (TypeScript 5.4+)
UsePromise.withResolvers()for creating promises with exposed resolve/reject functions (TypeScript 5.7+)
Use copying array methods (toSorted,toSpliced,with) for immutable array operations (TypeScript 5.2+)
Avoid accessing instance fields viasuperin classes (TypeScript 5....
Files:
apps/web/core/components/cycles/archived-cycles/modal.tsxapps/web/core/components/project/settings/archive-project/archive-restore-modal.tsxapps/web/core/components/project/confirm-project-member-remove.tsxapps/web/core/components/project/join-project-modal.tsxapps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/core/modals/bulk-delete-issues-modal.tsxapps/web/core/components/cycles/transfer-issues-modal.tsxapps/web/core/components/project/delete-project-modal.tsxapps/web/core/components/project/leave-project-modal.tsxapps/web/core/components/account/deactivate-account-modal.tsxapps/web/core/components/workspace-notifications/sidebar/notification-card/options/snooze/modal.tsxapps/web/core/components/automation/select-month-modal.tsxapps/web/core/components/issues/archive-issue-modal.tsxapps/web/core/components/issues/parent-issues-list-modal.tsxapps/web/core/components/issues/confirm-issue-discard.tsxapps/web/core/components/project/send-project-invitation-modal.tsxapps/web/core/components/core/filters/date-filter-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsxapps/web/core/components/core/modals/change-email-modal.tsxapps/web/core/components/exporter/export-modal.tsxapps/web/core/components/modules/archived-modules/modal.tsxapps/web/core/components/integration/delete-import-modal.tsxapps/web/core/components/core/modals/existing-issues-list-modal.tsxapps/web/core/components/core/modals/user-image-upload-modal.tsxapps/web/core/components/inbox/modals/snooze-issue-modal.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Enable TypeScript strict mode and ensure all files are fully typed
Files:
apps/web/core/components/cycles/archived-cycles/modal.tsxapps/web/core/components/project/settings/archive-project/archive-restore-modal.tsxapps/web/core/components/project/confirm-project-member-remove.tsxapps/web/core/components/project/join-project-modal.tsxapps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/core/modals/bulk-delete-issues-modal.tsxapps/web/core/components/cycles/transfer-issues-modal.tsxapps/web/core/components/project/delete-project-modal.tsxapps/web/core/components/project/leave-project-modal.tsxapps/web/core/components/account/deactivate-account-modal.tsxapps/web/core/components/workspace-notifications/sidebar/notification-card/options/snooze/modal.tsxapps/web/core/components/automation/select-month-modal.tsxapps/web/core/components/issues/archive-issue-modal.tsxapps/web/core/components/issues/parent-issues-list-modal.tsxapps/web/core/components/issues/confirm-issue-discard.tsxapps/web/core/components/project/send-project-invitation-modal.tsxapps/web/core/components/core/filters/date-filter-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsxapps/web/core/components/core/modals/change-email-modal.tsxapps/web/core/components/exporter/export-modal.tsxapps/web/core/components/modules/archived-modules/modal.tsxapps/web/core/components/integration/delete-import-modal.tsxapps/web/core/components/core/modals/existing-issues-list-modal.tsxapps/web/core/components/core/modals/user-image-upload-modal.tsxapps/web/core/components/inbox/modals/snooze-issue-modal.tsx
**/*.{js,jsx,ts,tsx,json,css}
📄 CodeRabbit inference engine (AGENTS.md)
Use Prettier with Tailwind plugin for code formatting, run
pnpm fix:format
Files:
apps/web/core/components/cycles/archived-cycles/modal.tsxapps/web/core/components/project/settings/archive-project/archive-restore-modal.tsxapps/web/core/components/project/confirm-project-member-remove.tsxapps/web/core/components/project/join-project-modal.tsxapps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/core/modals/bulk-delete-issues-modal.tsxapps/web/core/components/cycles/transfer-issues-modal.tsxapps/web/core/components/project/delete-project-modal.tsxapps/web/core/components/project/leave-project-modal.tsxapps/web/core/components/account/deactivate-account-modal.tsxapps/web/core/components/workspace-notifications/sidebar/notification-card/options/snooze/modal.tsxapps/web/core/components/automation/select-month-modal.tsxapps/web/core/components/issues/archive-issue-modal.tsxapps/web/core/components/issues/parent-issues-list-modal.tsxapps/web/core/components/issues/confirm-issue-discard.tsxapps/web/core/components/project/send-project-invitation-modal.tsxapps/web/core/components/core/filters/date-filter-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsxapps/web/core/components/core/modals/change-email-modal.tsxapps/web/core/components/exporter/export-modal.tsxapps/web/core/components/modules/archived-modules/modal.tsxapps/web/core/components/integration/delete-import-modal.tsxapps/web/core/components/core/modals/existing-issues-list-modal.tsxapps/web/core/components/core/modals/user-image-upload-modal.tsxapps/web/core/components/inbox/modals/snooze-issue-modal.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,jsx,ts,tsx}: Use ESLint with shared config across packages, adhering to max warnings limits per package
Use camelCase for variable and function names, PascalCase for components and types
Use try-catch with proper error types and log errors appropriately
Files:
apps/web/core/components/cycles/archived-cycles/modal.tsxapps/web/core/components/project/settings/archive-project/archive-restore-modal.tsxapps/web/core/components/project/confirm-project-member-remove.tsxapps/web/core/components/project/join-project-modal.tsxapps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/core/modals/bulk-delete-issues-modal.tsxapps/web/core/components/cycles/transfer-issues-modal.tsxapps/web/core/components/project/delete-project-modal.tsxapps/web/core/components/project/leave-project-modal.tsxapps/web/core/components/account/deactivate-account-modal.tsxapps/web/core/components/workspace-notifications/sidebar/notification-card/options/snooze/modal.tsxapps/web/core/components/automation/select-month-modal.tsxapps/web/core/components/issues/archive-issue-modal.tsxapps/web/core/components/issues/parent-issues-list-modal.tsxapps/web/core/components/issues/confirm-issue-discard.tsxapps/web/core/components/project/send-project-invitation-modal.tsxapps/web/core/components/core/filters/date-filter-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsxapps/web/core/components/core/modals/change-email-modal.tsxapps/web/core/components/exporter/export-modal.tsxapps/web/core/components/modules/archived-modules/modal.tsxapps/web/core/components/integration/delete-import-modal.tsxapps/web/core/components/core/modals/existing-issues-list-modal.tsxapps/web/core/components/core/modals/user-image-upload-modal.tsxapps/web/core/components/inbox/modals/snooze-issue-modal.tsx
🧠 Learnings (10)
📚 Learning: 2025-10-21T17:22:05.204Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7989
File: apps/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/[pageId]/page.tsx:45-46
Timestamp: 2025-10-21T17:22:05.204Z
Learning: In the makeplane/plane repository, the refactor from useParams() to params prop is specifically scoped to page.tsx and layout.tsx files in apps/web/app (Next.js App Router pattern). Other components (hooks, regular client components, utilities) should continue using the useParams() hook as that is the correct pattern for non-route components.
Applied to files:
apps/web/core/components/cycles/archived-cycles/modal.tsxapps/web/core/components/project/settings/archive-project/archive-restore-modal.tsxapps/web/core/components/project/confirm-project-member-remove.tsxapps/web/core/components/project/join-project-modal.tsxapps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/core/modals/bulk-delete-issues-modal.tsxapps/web/core/components/cycles/transfer-issues-modal.tsxapps/web/core/components/project/delete-project-modal.tsxapps/web/core/components/project/leave-project-modal.tsxapps/web/core/components/account/deactivate-account-modal.tsxapps/web/core/components/workspace-notifications/sidebar/notification-card/options/snooze/modal.tsxapps/web/core/components/automation/select-month-modal.tsxapps/web/core/components/issues/archive-issue-modal.tsxapps/web/core/components/issues/confirm-issue-discard.tsxapps/web/core/components/project/send-project-invitation-modal.tsxapps/web/core/components/core/filters/date-filter-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsxapps/web/core/components/core/modals/change-email-modal.tsxapps/web/core/components/exporter/export-modal.tsxapps/web/core/components/modules/archived-modules/modal.tsxapps/web/core/components/integration/delete-import-modal.tsxapps/web/core/components/core/modals/existing-issues-list-modal.tsxapps/web/core/components/core/modals/user-image-upload-modal.tsx
📚 Learning: 2025-10-09T20:42:31.843Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7922
File: apps/admin/app/(all)/(dashboard)/ai/form.tsx:19-19
Timestamp: 2025-10-09T20:42:31.843Z
Learning: In the makeplane/plane repository, React types are globally available through TypeScript configuration. Type annotations like React.FC, React.ReactNode, etc. can be used without explicitly importing the React namespace. The codebase uses the modern JSX transform, so React imports are not required for JSX or type references.
Applied to files:
apps/web/core/components/cycles/archived-cycles/modal.tsxapps/web/core/components/project/settings/archive-project/archive-restore-modal.tsxapps/web/core/components/project/confirm-project-member-remove.tsxapps/web/core/components/project/join-project-modal.tsxapps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/core/modals/bulk-delete-issues-modal.tsxapps/web/core/components/cycles/transfer-issues-modal.tsxapps/web/core/components/project/delete-project-modal.tsxapps/web/core/components/project/leave-project-modal.tsxapps/web/core/components/account/deactivate-account-modal.tsxapps/web/core/components/workspace-notifications/sidebar/notification-card/options/snooze/modal.tsxapps/web/core/components/automation/select-month-modal.tsxapps/web/core/components/issues/archive-issue-modal.tsxapps/web/core/components/issues/parent-issues-list-modal.tsxapps/web/core/components/issues/confirm-issue-discard.tsxapps/web/core/components/project/send-project-invitation-modal.tsxapps/web/core/components/core/filters/date-filter-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsxapps/web/core/components/core/modals/change-email-modal.tsxapps/web/core/components/exporter/export-modal.tsxapps/web/core/components/modules/archived-modules/modal.tsxapps/web/core/components/integration/delete-import-modal.tsxapps/web/core/components/core/modals/existing-issues-list-modal.tsxapps/web/core/components/core/modals/user-image-upload-modal.tsxapps/web/core/components/inbox/modals/snooze-issue-modal.tsx
📚 Learning: 2025-09-02T08:14:49.260Z
Learnt from: sriramveeraghanta
Repo: makeplane/plane PR: 7697
File: apps/web/app/(all)/[workspaceSlug]/(projects)/header.tsx:12-13
Timestamp: 2025-09-02T08:14:49.260Z
Learning: The star-us-link.tsx file in apps/web/app/(all)/[workspaceSlug]/(projects)/ already has "use client" directive at the top, making it a proper Client Component for hook usage.
Applied to files:
apps/web/core/components/project/settings/archive-project/archive-restore-modal.tsxapps/web/core/components/project/confirm-project-member-remove.tsxapps/web/core/components/project/join-project-modal.tsx
📚 Learning: 2025-12-12T15:20:36.542Z
Learnt from: CR
Repo: makeplane/plane PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T15:20:36.542Z
Learning: Applies to packages/shared-state/**/*.{ts,tsx} : Maintain MobX stores in `packages/shared-state` using reactive patterns
Applied to files:
apps/web/core/components/project/confirm-project-member-remove.tsxapps/web/core/components/cycles/transfer-issues-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsx
📚 Learning: 2025-12-12T15:20:36.542Z
Learnt from: CR
Repo: makeplane/plane PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T15:20:36.542Z
Learning: Applies to packages/plane/ui/**/*.{ts,tsx} : Build components in `plane/ui` package with Storybook for isolated development
Applied to files:
apps/web/core/components/project/join-project-modal.tsxapps/web/core/components/project/leave-project-modal.tsxapps/web/core/components/automation/select-month-modal.tsx
📚 Learning: 2025-10-01T15:30:17.605Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7888
File: packages/propel/src/avatar/avatar.stories.tsx:2-3
Timestamp: 2025-10-01T15:30:17.605Z
Learning: In the makeplane/plane repository, avoid suggesting inline type imports (e.g., `import { Avatar, type TAvatarSize }`) due to bundler compatibility issues. Keep type imports and value imports as separate statements.
Applied to files:
apps/web/core/components/project/join-project-modal.tsxapps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/core/modals/bulk-delete-issues-modal.tsxapps/web/core/components/issues/archive-issue-modal.tsxapps/web/core/components/project/send-project-invitation-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsxapps/web/core/components/core/modals/change-email-modal.tsxapps/web/core/components/core/modals/user-image-upload-modal.tsx
📚 Learning: 2025-10-09T20:43:07.762Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7922
File: apps/admin/core/components/new-user-popup.tsx:4-6
Timestamp: 2025-10-09T20:43:07.762Z
Learning: The `next-themes` library is React-compatible and can be used outside of Next.js applications. It's not Next.js-specific despite its name.
Applied to files:
apps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/core/modals/bulk-delete-issues-modal.tsx
📚 Learning: 2025-10-10T13:25:14.810Z
Learnt from: gakshita
Repo: makeplane/plane PR: 7949
File: apps/web/core/components/issues/issue-modal/form.tsx:183-189
Timestamp: 2025-10-10T13:25:14.810Z
Learning: In `apps/web/core/components/issues/issue-modal/form.tsx`, the form reset effect uses a `dataResetProperties` dependency array prop (default: []) to give parent components explicit control over when the form resets. Do not suggest adding the `data` prop itself to the dependency array, as this would cause unwanted resets on every render when the data object reference changes, disrupting user input. The current pattern is intentional and allows the parent to trigger resets only when specific conditions are met.
Applied to files:
apps/web/core/components/core/modals/bulk-delete-issues-modal.tsxapps/web/core/components/cycles/transfer-issues-modal.tsxapps/web/core/components/issues/parent-issues-list-modal.tsxapps/web/core/components/core/modals/existing-issues-list-modal.tsx
📚 Learning: 2025-10-09T22:12:26.424Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7922
File: apps/admin/app/(all)/(dashboard)/ai/form.tsx:19-19
Timestamp: 2025-10-09T22:12:26.424Z
Learning: When `types/react` is installed in a TypeScript project (which is standard for React + TypeScript codebases), React types (React.FC, React.ReactNode, React.ComponentProps, etc.) are globally available by design. These type annotations can and should be used without explicitly importing the React namespace. This is a TypeScript/DefinitelyTyped feature, not codebase-specific configuration.
Applied to files:
apps/web/core/components/automation/select-month-modal.tsx
📚 Learning: 2025-12-17T10:58:59.591Z
Learnt from: CR
Repo: makeplane/plane PR: 0
File: packages/tailwind-config/AGENTS.md:0-0
Timestamp: 2025-12-17T10:58:59.591Z
Learning: Applies to packages/tailwind-config/**/*.{ts,tsx} : Modals, dropdowns, and overlay components that exist on a different plane (with their own z-index/stacking context) are an exception to the no-nested-surfaces rule and may use a surface even when a surface already exists below them
Applied to files:
apps/web/core/components/exporter/export-modal.tsx
🧬 Code graph analysis (18)
apps/web/core/components/cycles/archived-cycles/modal.tsx (1)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)
apps/web/core/components/project/confirm-project-member-remove.tsx (2)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)apps/web/core/store/project/project.store.ts (1)
currentProjectDetails(216-219)
apps/web/core/components/project/join-project-modal.tsx (3)
apps/web/core/services/user.service.ts (1)
joinProject(247-253)apps/space/core/store/publish/publish.store.ts (1)
workspaceSlug(93-95)packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)
apps/web/core/components/inbox/modals/select-duplicate.tsx (4)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)packages/propel/src/combobox/combobox.tsx (1)
Combobox(230-230)packages/propel/src/input/input.stories.tsx (1)
Search(131-134)packages/ui/src/loader.tsx (1)
Loader(32-32)
apps/web/core/components/cycles/transfer-issues-modal.tsx (4)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)packages/propel/src/icons/transfer-icon.tsx (1)
TransferIcon(5-17)packages/propel/src/icons/actions/close-icon.tsx (1)
CloseIcon(6-15)packages/propel/src/icons/project/cycle-icon.tsx (1)
CycleIcon(6-21)
apps/web/core/components/project/delete-project-modal.tsx (1)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)
apps/web/core/components/project/leave-project-modal.tsx (2)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)packages/ui/src/form-fields/input.tsx (1)
Input(54-54)
apps/web/core/components/account/deactivate-account-modal.tsx (2)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)packages/i18n/src/store/index.ts (1)
t(222-243)
apps/web/core/components/workspace-notifications/sidebar/notification-card/options/snooze/modal.tsx (4)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)packages/propel/src/icons/actions/close-icon.tsx (1)
CloseIcon(6-15)apps/web/core/components/dropdowns/date.tsx (1)
DateDropdown(40-207)packages/ui/src/dropdowns/custom-select.tsx (1)
CustomSelect(184-184)
apps/web/core/components/automation/select-month-modal.tsx (1)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)
apps/web/core/components/issues/archive-issue-modal.tsx (2)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)packages/i18n/src/store/index.ts (1)
t(222-243)
apps/web/core/components/issues/parent-issues-list-modal.tsx (4)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)packages/i18n/src/store/index.ts (1)
t(222-243)apps/web/ce/components/issues/issue-details/issue-identifier.tsx (1)
IssueIdentifier(9-36)packages/utils/src/work-item/base.ts (1)
generateWorkItemLink(309-331)
apps/web/core/components/project/send-project-invitation-modal.tsx (4)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)packages/ui/src/dropdowns/custom-search-select.tsx (1)
CustomSearchSelect(15-226)packages/ui/src/dropdowns/custom-select.tsx (1)
CustomSelect(184-184)packages/propel/src/icons/actions/close-icon.tsx (1)
CloseIcon(6-15)
apps/web/core/components/core/modals/workspace-image-upload-modal.tsx (2)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)packages/propel/src/icons/properties/user-circle-icon.tsx (1)
UserCirclePropertyIcon(6-17)
apps/web/core/components/exporter/export-modal.tsx (2)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)packages/ui/src/dropdowns/custom-search-select.tsx (1)
CustomSearchSelect(15-226)
apps/web/core/components/modules/archived-modules/modal.tsx (1)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)
apps/web/core/components/integration/delete-import-modal.tsx (2)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)packages/ui/src/form-fields/input.tsx (1)
Input(54-54)
apps/web/core/components/inbox/modals/snooze-issue-modal.tsx (3)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)packages/propel/src/calendar/root.tsx (1)
Calendar(9-36)packages/i18n/src/store/index.ts (1)
t(222-243)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Cursor Bugbot
- GitHub Check: Build packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (31)
apps/web/core/components/inbox/modals/snooze-issue-modal.tsx (1)
1-6: LGTM!Imports are correctly updated for the ModalCore migration, bringing in the required position and width enums from
@plane/ui.apps/web/core/components/project/delete-project-modal.tsx (1)
91-162: LGTM! Clean migration to ModalCore.The modal migration correctly wraps the form content with
ModalCore, preserving all form validation, submission logic, and the delayed reset behavior inhandleClose. The explicitpositionandwidthprops are consistent with other modals in this PR.apps/web/core/components/cycles/archived-cycles/modal.tsx (1)
73-88: LGTM! Modal migration preserves all functionality.The
ModalCorewrapper withLGwidth is appropriate for this confirmation dialog. State management, archive action flow, and button behaviors are correctly preserved.apps/web/core/components/exporter/export-modal.tsx (1)
101-108: Good UX pattern: Preventing modal close during dropdown interaction.The
isSelectOpenguard inhandleClosecorrectly prevents the modal from closing when the user is interacting with theCustomSearchSelectdropdown. This is important because clicking inside the dropdown could otherwise trigger the modal's backdrop close behavior.apps/web/core/components/inbox/modals/select-duplicate.tsx (1)
127-155: LGTM! Correct migration while retaining Combobox.The migration appropriately keeps
Comboboxfrom Headless UI for the searchable list functionality (whichModalCoredoesn't replace) while wrapping everything inModalCore. Thestaticprop onCombobox.Optionsensures the options are always visible, and the loading state is handled correctly.apps/web/core/components/modules/archived-modules/modal.tsx (1)
59-74: LGTM! Consistent modal migration.The structure mirrors the
ArchiveCycleModalappropriately. Modal content, state management, and archive flow are correctly preserved.apps/web/core/components/project/leave-project-modal.tsx (1)
110-186: LGTM! Clean modal migration.The migration from Headless UI Dialog/Transition to ModalCore is well-executed. The form logic, validation, and error handling are preserved without any behavioral changes.
apps/web/core/components/project/join-project-modal.tsx (1)
46-63: LGTM! Modal migration successful.The ModalCore integration is clean and preserves all existing functionality.
apps/web/core/components/issues/archive-issue-modal.tsx (1)
65-80: LGTM! Modal structure updated successfully.The ModalCore integration maintains all functionality including translations and toast notifications.
apps/web/core/components/project/settings/archive-project/archive-restore-modal.tsx (1)
83-108: LGTM! Clean modal migration.The ModalCore integration successfully preserves both archive and restore flows.
apps/web/core/components/core/modals/bulk-delete-issues-modal.tsx (1)
153-204: LGTM! Modal migration preserves all functionality.The ModalCore integration maintains the search, loading states, and issue selection logic without any issues.
apps/web/core/components/project/confirm-project-member-remove.tsx (1)
50-86: LGTM! Modal migration executed cleanly.The ModalCore integration preserves both the "leave project" and "remove member" flows, with proper conditional rendering and loading states.
apps/web/core/components/cycles/transfer-issues-modal.tsx (2)
74-74: Verify modal position choice.This modal uses
EModalPosition.TOPwhile most other migrated modals useEModalPosition.CENTER. Confirm this positioning is intentional for the transfer issues workflow.
74-138: LGTM! Transfer functionality preserved.The ModalCore integration maintains all search, filtering, and transfer logic without issues.
apps/web/core/components/issues/confirm-issue-discard.tsx (1)
30-58: LGTM! Modal migration maintains three-action layout.The ModalCore integration successfully preserves the unique three-button layout (Discard, Cancel, Save to Drafts) and loading states.
apps/web/core/components/core/modals/change-email-modal.tsx (2)
1-8: LGTM!The import changes align with the modern JSX transform pattern used in the codebase. The
useStateimport is correctly extracted, and the new ModalCore imports with position/width enums are properly added. Based on learnings, React types are globally available through TypeScript configuration, so removing the React namespace import is appropriate.
129-205: LGTM!The modal migration to ModalCore is well-executed:
- Proper use of
EModalPosition.CENTERandEModalWidth.XXL- Form structure, validation rules, and Controller usage preserved
- Two-step conditional rendering for email/code fields maintained
- Button states and submit logic intact
- Error handling with conditional error message display works correctly
apps/web/core/components/account/deactivate-account-modal.tsx (2)
1-8: LGTM!Imports are correctly updated for the ModalCore migration pattern.
66-90: LGTM on ModalCore structure!The modal content layout with icon, title, description, and action buttons is well-organized within the ModalCore wrapper.
apps/web/core/components/core/modals/workspace-image-upload-modal.tsx (2)
1-11: LGTM!Imports are correctly updated. Using
EModalWidth.XL(instead of XXL) is appropriate for an image upload modal with a focused purpose.
104-141: LGTM on ModalCore and dropzone implementation!The image upload modal correctly implements:
- ModalCore with centered positioning
- Dropzone with proper drag-and-drop handling
- Conditional rendering for image preview vs placeholder
- Edit button overlay on existing images
apps/web/core/components/project/send-project-invitation-modal.tsx (2)
11-11: LGTM!Import statement correctly adds ModalCore with position and width enums alongside existing UI components.
185-319: LGTM on overall modal structure!The invitation modal migration is well-executed:
- ModalCore wrapper with appropriate positioning
- Form structure with dynamic field array preserved
- Member selection with CustomSearchSelect works correctly
- Role selection with permission filtering maintained
- Add/remove member row functionality intact
apps/web/core/components/workspace-notifications/sidebar/notification-card/options/snooze/modal.tsx (3)
7-10: LGTM!Imports correctly updated for ModalCore migration with proper utility imports.
169-192: Verify AM/PM toggle behavior inside CustomSelect dropdown.The AM/PM toggle divs are rendered as children of
CustomSelect. Clicking these divs may trigger the dropdown's click-outside handler and close it unexpectedly before the user can select a time. Verify this interaction works as intended.
110-121: LGTM on modal header structure!The modal header with title and close button is cleanly implemented within the ModalCore wrapper.
apps/web/core/components/core/modals/user-image-upload-modal.tsx (1)
90-153: LGTM on modal migration.The migration from Headless UI Dialog/Transition to
ModalCoreis correctly implemented. Theposition,width, andhandleCloseprops are properly configured, and the internal content structure is preserved.apps/web/core/components/issues/parent-issues-list-modal.tsx (1)
87-193: Modal migration looks good.The migration to
ModalCorewithComboboxis well-structured. The search, loading states, empty state handling, and issue selection flow are preserved correctly.apps/web/core/components/core/modals/existing-issues-list-modal.tsx (1)
133-323: Modal migration and multi-select flow implemented correctly.The migration to
ModalCorewith the Combobox-based multi-select pattern is well-structured. The selected issues chips, workspace-level toggle, loading states, and action buttons are properly wired.apps/web/core/components/automation/select-month-modal.tsx (2)
7-7: LGTM! Clean import migration.The imports have been correctly updated to use ModalCore and related enums from @plane/ui, removing the Headless UI dependencies.
119-127: LGTM! Action buttons correctly preserved.The Cancel and Submit buttons maintain the correct behavior, variants, and loading states from the original implementation.
apps/web/core/components/core/modals/user-image-upload-modal.tsx
Outdated
Show resolved
Hide resolved
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: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/core/components/core/modals/user-image-upload-modal.tsx (1)
72-88: Use consistent error handling with user feedback.The
handleImageRemovefunction logs errors to console (line 84) whilehandleSubmitdisplays toast notifications to users (lines 61-65). Users should be informed when image removal fails.🔎 Proposed fix for consistent error handling
} catch (error) { - console.log("Error in uploading user asset:", error); + setToast({ + type: TOAST_TYPE.ERROR, + title: "Error!", + message: "Failed to remove image. Please try again.", + }); } finally { setIsRemoving(false);
♻️ Duplicate comments (3)
apps/web/core/components/automation/select-month-modal.tsx (2)
43-128: Add padding wrapper inside ModalCore for consistent spacing.The modal content renders directly inside ModalCore without internal padding. Based on the ModalCore implementation (packages/ui/src/modals/modal-core.tsx), it provides the panel container but no padding. Wrap the form or its immediate content in a div with padding classes (e.g.,
className="p-6") to ensure consistent modal spacing.🔎 Suggested padding wrapper
<ModalCore isOpen={isOpen} handleClose={onClose} position={EModalPosition.CENTER} width={EModalWidth.XXL}> + <div className="p-6"> <form onSubmit={handleSubmit(onSubmit)}> <div> <h3 className="text-16 font-medium leading-6 text-primary">Customize time range</h3> ... </form> + </div> </ModalCore>
45-45: Restore ARIA labeling for screen reader accessibility.The h3 title changed from
Dialog.Titleto a plain element, removing the automaticaria-labelledbyassociation. Screen readers can no longer properly identify the modal's purpose. Either wrap the title withDialog.Titleagain, or add anidto the h3 (e.g.,id="select-month-modal-title") and setaria-labelledbyon the containing Dialog/Panel.🔎 Suggested fix for accessibility
Option 1 - Add id and aria-labelledby:
- <h3 className="text-16 font-medium leading-6 text-primary">Customize time range</h3> + <h3 id="select-month-modal-title" className="text-16 font-medium leading-6 text-primary">Customize time range</h3>Then verify ModalCore or its internal Dialog supports
aria-labelledbyprop, or manually add it to the Dialog.Panel.Option 2 - Use Dialog.Title:
+import { Dialog } from "@headlessui/react"; ... - <h3 className="text-16 font-medium leading-6 text-primary">Customize time range</h3> + <Dialog.Title as="h3" className="text-16 font-medium leading-6 text-primary"> + Customize time range + </Dialog.Title>apps/web/core/components/core/modals/user-image-upload-modal.tsx (1)
112-116: Memory leak: Blob URL is never revoked.The blob URL created by
URL.createObjectURL(image)on line 113 persists until page unload. This issue was previously identified and a fix usinguseEffectcleanup was proposed in an earlier review.
🧹 Nitpick comments (4)
apps/web/core/components/inbox/modals/snooze-issue-modal.tsx (1)
28-29: Redundant Date object creation.Since
dateis always a Date object (initialized asvalue || new Date()), wrapping it innew Date(date)is unnecessary. You can passdatedirectly to bothselectedanddefaultMonth.🔎 Proposed simplification
- selected={date ? new Date(date) : undefined} - defaultMonth={date ? new Date(date) : undefined} + selected={date} + defaultMonth={date}apps/web/core/components/core/modals/user-image-upload-modal.tsx (1)
138-138: Consider removing explicit margin to rely on parent spacing.The
my-4class may override the parent container'sspace-y-5spacing system. For consistency, consider removingmy-4and letting the parent's spacing handle vertical rhythm.🔎 Proposed refinement
- <p className="my-4 text-13 text-secondary">File formats supported- .jpeg, .jpg, .png, .webp</p> + <p className="text-13 text-secondary">File formats supported- .jpeg, .jpg, .png, .webp</p>apps/web/core/components/inbox/modals/select-duplicate.tsx (1)
135-140: Consider making the search input a controlled component.The input field updates
queryviaonChangebut doesn't have avalue={query}prop, making it uncontrolled. While this works in practice due to component unmounting, using a controlled input is a recommended React pattern for predictability and testing.🔎 Proposed fix
<input type="text" className="h-12 w-full border-0 bg-transparent pl-11 pr-4 text-primary outline-none focus:ring-0 sm:text-13" placeholder="Search..." + value={query} onChange={(e) => setQuery(e.target.value)} />apps/web/core/components/account/deactivate-account-modal.tsx (1)
50-50: Optional: Redundant return statement.The
return;statement at line 50 is redundant since there's no code after it in the.then()block and the promise chain continues regardless. While explicit, it can be removed for cleaner code.🔎 Proposed cleanup
signOut(); router.push("/"); handleClose(); - return; })
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
apps/web/core/components/account/deactivate-account-modal.tsxapps/web/core/components/automation/select-month-modal.tsxapps/web/core/components/core/modals/user-image-upload-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsxapps/web/core/components/exporter/export-modal.tsxapps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/inbox/modals/snooze-issue-modal.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,mts,cts}
📄 CodeRabbit inference engine (.github/instructions/typescript.instructions.md)
**/*.{ts,tsx,mts,cts}: Useconsttype parameters for more precise literal inference in TypeScript 5.0+
Use thesatisfiesoperator to validate types without widening them
Leverage inferred type predicates to reduce the need for explicitisreturn types in filter/check functions
UseNoInfer<T>utility to block inference for specific type arguments when they should be determined by other arguments
Utilize narrowing inswitch(true)blocks for control flow analysis (TypeScript 5.3+)
Rely on narrowing from direct boolean comparisons for type guards
Trust preserved narrowing in closures when variables aren't modified after the check (TypeScript 5.4+)
Use constant indices to narrow object/array properties (TypeScript 5.5+)
Use standard ECMAScript decorators (Stage 3) instead of legacyexperimentalDecorators
Useusingdeclarations for explicit resource management with Disposable pattern instead of manual cleanup (TypeScript 5.2+)
Usewith { type: "json" }for import attributes; avoid deprecatedassertsyntax (TypeScript 5.3/5.8+)
Useimport typeexplicitly when importing types to ensure they are erased during compilation, respectingverbatimModuleSyntaxflag
Use.ts,.mts,.ctsextensions inimport typestatements (TypeScript 5.2+)
Useimport type { Type } from "mod" with { "resolution-mode": "import" }for specific module resolution contexts (TypeScript 5.3+)
Use new iterator methods (map, filter, etc.) if targeting modern environments (TypeScript 5.6+)
Utilize newSetmethods likeunion,intersection, etc., when available (TypeScript 5.5+)
UseObject.groupBy/Map.groupBystandard methods for grouping instead of external libraries (TypeScript 5.4+)
UsePromise.withResolvers()for creating promises with exposed resolve/reject functions (TypeScript 5.7+)
Use copying array methods (toSorted,toSpliced,with) for immutable array operations (TypeScript 5.2+)
Avoid accessing instance fields viasuperin classes (TypeScript 5....
Files:
apps/web/core/components/exporter/export-modal.tsxapps/web/core/components/inbox/modals/snooze-issue-modal.tsxapps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/core/modals/user-image-upload-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsxapps/web/core/components/automation/select-month-modal.tsxapps/web/core/components/account/deactivate-account-modal.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Enable TypeScript strict mode and ensure all files are fully typed
Files:
apps/web/core/components/exporter/export-modal.tsxapps/web/core/components/inbox/modals/snooze-issue-modal.tsxapps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/core/modals/user-image-upload-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsxapps/web/core/components/automation/select-month-modal.tsxapps/web/core/components/account/deactivate-account-modal.tsx
**/*.{js,jsx,ts,tsx,json,css}
📄 CodeRabbit inference engine (AGENTS.md)
Use Prettier with Tailwind plugin for code formatting, run
pnpm fix:format
Files:
apps/web/core/components/exporter/export-modal.tsxapps/web/core/components/inbox/modals/snooze-issue-modal.tsxapps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/core/modals/user-image-upload-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsxapps/web/core/components/automation/select-month-modal.tsxapps/web/core/components/account/deactivate-account-modal.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,jsx,ts,tsx}: Use ESLint with shared config across packages, adhering to max warnings limits per package
Use camelCase for variable and function names, PascalCase for components and types
Use try-catch with proper error types and log errors appropriately
Files:
apps/web/core/components/exporter/export-modal.tsxapps/web/core/components/inbox/modals/snooze-issue-modal.tsxapps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/core/modals/user-image-upload-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsxapps/web/core/components/automation/select-month-modal.tsxapps/web/core/components/account/deactivate-account-modal.tsx
🧠 Learnings (12)
📚 Learning: 2025-10-21T17:22:05.204Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7989
File: apps/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/[pageId]/page.tsx:45-46
Timestamp: 2025-10-21T17:22:05.204Z
Learning: In the makeplane/plane repository, the refactor from useParams() to params prop is specifically scoped to page.tsx and layout.tsx files in apps/web/app (Next.js App Router pattern). Other components (hooks, regular client components, utilities) should continue using the useParams() hook as that is the correct pattern for non-route components.
Applied to files:
apps/web/core/components/exporter/export-modal.tsxapps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/core/modals/user-image-upload-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsxapps/web/core/components/automation/select-month-modal.tsxapps/web/core/components/account/deactivate-account-modal.tsx
📚 Learning: 2025-10-09T20:42:31.843Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7922
File: apps/admin/app/(all)/(dashboard)/ai/form.tsx:19-19
Timestamp: 2025-10-09T20:42:31.843Z
Learning: In the makeplane/plane repository, React types are globally available through TypeScript configuration. Type annotations like React.FC, React.ReactNode, etc. can be used without explicitly importing the React namespace. The codebase uses the modern JSX transform, so React imports are not required for JSX or type references.
Applied to files:
apps/web/core/components/exporter/export-modal.tsxapps/web/core/components/inbox/modals/snooze-issue-modal.tsxapps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/core/modals/user-image-upload-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsxapps/web/core/components/automation/select-month-modal.tsxapps/web/core/components/account/deactivate-account-modal.tsx
📚 Learning: 2025-12-17T10:58:59.591Z
Learnt from: CR
Repo: makeplane/plane PR: 0
File: packages/tailwind-config/AGENTS.md:0-0
Timestamp: 2025-12-17T10:58:59.591Z
Learning: Applies to packages/tailwind-config/**/*.{ts,tsx} : Modals, dropdowns, and overlay components that exist on a different plane (with their own z-index/stacking context) are an exception to the no-nested-surfaces rule and may use a surface even when a surface already exists below them
Applied to files:
apps/web/core/components/exporter/export-modal.tsx
📚 Learning: 2025-10-09T20:43:07.762Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7922
File: apps/admin/core/components/new-user-popup.tsx:4-6
Timestamp: 2025-10-09T20:43:07.762Z
Learning: The `next-themes` library is React-compatible and can be used outside of Next.js applications. It's not Next.js-specific despite its name.
Applied to files:
apps/web/core/components/inbox/modals/select-duplicate.tsx
📚 Learning: 2025-10-01T15:30:17.605Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7888
File: packages/propel/src/avatar/avatar.stories.tsx:2-3
Timestamp: 2025-10-01T15:30:17.605Z
Learning: In the makeplane/plane repository, avoid suggesting inline type imports (e.g., `import { Avatar, type TAvatarSize }`) due to bundler compatibility issues. Keep type imports and value imports as separate statements.
Applied to files:
apps/web/core/components/inbox/modals/select-duplicate.tsxapps/web/core/components/core/modals/user-image-upload-modal.tsxapps/web/core/components/core/modals/workspace-image-upload-modal.tsx
📚 Learning: 2025-12-17T10:58:59.591Z
Learnt from: CR
Repo: makeplane/plane PR: 0
File: packages/tailwind-config/AGENTS.md:0-0
Timestamp: 2025-12-17T10:58:59.591Z
Learning: Applies to packages/tailwind-config/**/*.{ts,tsx} : Use the rare exception to go one level above for visual separation only in interactive form elements (inputs, buttons, switches) within modals - for example, a modal with `bg-surface-1` can use `bg-layer-2` for form inputs to achieve visual distinction
Applied to files:
apps/web/core/components/core/modals/user-image-upload-modal.tsxapps/web/core/components/automation/select-month-modal.tsx
📚 Learning: 2025-12-17T10:58:59.591Z
Learnt from: CR
Repo: makeplane/plane PR: 0
File: packages/tailwind-config/AGENTS.md:0-0
Timestamp: 2025-12-17T10:58:59.591Z
Learning: Applies to packages/tailwind-config/**/*.{ts,tsx} : Headers and main content sections within a page should be part of the same surface container (using semantic borders for visual separation if needed) rather than using separate surface backgrounds
Applied to files:
apps/web/core/components/core/modals/user-image-upload-modal.tsxapps/web/core/components/automation/select-month-modal.tsx
📚 Learning: 2025-12-12T15:20:36.542Z
Learnt from: CR
Repo: makeplane/plane PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T15:20:36.542Z
Learning: Applies to packages/shared-state/**/*.{ts,tsx} : Maintain MobX stores in `packages/shared-state` using reactive patterns
Applied to files:
apps/web/core/components/core/modals/workspace-image-upload-modal.tsx
📚 Learning: 2025-10-10T13:25:14.810Z
Learnt from: gakshita
Repo: makeplane/plane PR: 7949
File: apps/web/core/components/issues/issue-modal/form.tsx:183-189
Timestamp: 2025-10-10T13:25:14.810Z
Learning: In `apps/web/core/components/issues/issue-modal/form.tsx`, the form reset effect uses a `dataResetProperties` dependency array prop (default: []) to give parent components explicit control over when the form resets. Do not suggest adding the `data` prop itself to the dependency array, as this would cause unwanted resets on every render when the data object reference changes, disrupting user input. The current pattern is intentional and allows the parent to trigger resets only when specific conditions are met.
Applied to files:
apps/web/core/components/automation/select-month-modal.tsx
📚 Learning: 2025-12-17T10:58:59.591Z
Learnt from: CR
Repo: makeplane/plane PR: 0
File: packages/tailwind-config/AGENTS.md:0-0
Timestamp: 2025-12-17T10:58:59.591Z
Learning: Applies to packages/tailwind-config/**/*.{ts,tsx} : Never use `bg-layer-2` or higher for content boxes and cards - always use the matching layer number; the exception for going one level above applies only to interactive form elements
Applied to files:
apps/web/core/components/automation/select-month-modal.tsx
📚 Learning: 2025-12-12T15:20:36.542Z
Learnt from: CR
Repo: makeplane/plane PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-12T15:20:36.542Z
Learning: Applies to packages/plane/ui/**/*.{ts,tsx} : Build components in `plane/ui` package with Storybook for isolated development
Applied to files:
apps/web/core/components/automation/select-month-modal.tsx
📚 Learning: 2025-10-09T22:12:26.424Z
Learnt from: lifeiscontent
Repo: makeplane/plane PR: 7922
File: apps/admin/app/(all)/(dashboard)/ai/form.tsx:19-19
Timestamp: 2025-10-09T22:12:26.424Z
Learning: When `types/react` is installed in a TypeScript project (which is standard for React + TypeScript codebases), React types (React.FC, React.ReactNode, React.ComponentProps, etc.) are globally available by design. These type annotations can and should be used without explicitly importing the React namespace. This is a TypeScript/DefinitelyTyped feature, not codebase-specific configuration.
Applied to files:
apps/web/core/components/automation/select-month-modal.tsx
🧬 Code graph analysis (5)
apps/web/core/components/exporter/export-modal.tsx (2)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)packages/ui/src/dropdowns/custom-search-select.tsx (1)
CustomSearchSelect(15-226)
apps/web/core/components/inbox/modals/snooze-issue-modal.tsx (3)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)packages/propel/src/calendar/root.tsx (1)
Calendar(9-36)packages/i18n/src/store/index.ts (1)
t(222-243)
apps/web/core/components/inbox/modals/select-duplicate.tsx (4)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)packages/propel/src/combobox/combobox.tsx (1)
Combobox(230-230)packages/propel/src/input/input.stories.tsx (1)
Search(131-134)packages/ui/src/loader.tsx (1)
Loader(32-32)
apps/web/core/components/automation/select-month-modal.tsx (1)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)
apps/web/core/components/account/deactivate-account-modal.tsx (2)
packages/ui/src/modals/modal-core.tsx (1)
ModalCore(16-67)packages/i18n/src/store/index.ts (1)
t(222-243)
⏰ 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). (4)
- GitHub Check: check:types
- GitHub Check: check:lint
- GitHub Check: Cursor Bugbot
- GitHub Check: Analyze (javascript)
🔇 Additional comments (9)
apps/web/core/components/inbox/modals/snooze-issue-modal.tsx (1)
43-46: Critical issue from previous review has been fixed.The undefined
close()call has been correctly replaced withhandleClose(), resolving the runtime error that was flagged in previous reviews.apps/web/core/components/automation/select-month-modal.tsx (3)
30-33: LGTM: Close handler correctly resets form.The
onClosefunction properly wrapshandleCloseand includes the form reset, and line 42 correctly passesonCloseto ModalCore. This ensures the form resets to initial values regardless of how the modal is closed (backdrop, escape, or cancel button).Also applies to: 42-42
46-118: LGTM: Form structure and validation preserved correctly.The form logic, Controller implementations, validation rules, and error handling are correctly preserved within the new ModalCore wrapper. Both
close_inandarchive_infields maintain their original validation constraints (min: 1, max: 12) and error messages.
119-126: LGTM: Footer actions properly implemented.The footer buttons are correctly structured with appropriate variants and behaviors. The Cancel button properly calls
onClose(ensuring form reset), and the Submit button correctly handles the loading state during submission.apps/web/core/components/core/modals/user-image-upload-modal.tsx (2)
1-1: LGTM: Import updates correctly support the modal migration.The imports properly bring in
ModalCoreand its configuration enums while maintaining the necessary React hooks. The absence of a React default import is correct given the modern JSX transform.Also applies to: 10-10
91-91: LGTM: ModalCore wrapper correctly replaces Headless UI.The modal structure properly uses
ModalCorewith appropriate positioning and width configuration, successfully completing the migration objective.Also applies to: 153-153
apps/web/core/components/inbox/modals/select-duplicate.tsx (1)
68-68: Query clearing on modal close is now handled correctly.The addition of
setQuery("")inhandleCloseproperly addresses the previous issue where the search query persisted between modal sessions.apps/web/core/components/account/deactivate-account-modal.tsx (1)
34-63: Deactivation flow correctly implemented with ModalCore.The migration preserves the deactivation logic, error handling, and state management correctly. The
handleClosecall in the.then()block properly resets state before navigating away.apps/web/core/components/core/modals/workspace-image-upload-modal.tsx (1)
104-166: Clean migration to ModalCore with preserved functionality.The modal migration correctly preserves all drag-and-drop functionality, image preview/edit UI, and error handling. The conditional rendering logic for the dropzone border states remains appropriate, and all action buttons are properly wired to their handlers.
Description
This update migrates all modals to @plane/ui from headless ui.
Type of Change
Screenshots and Media (if applicable)
Test Scenarios
References
Note
Replaces Headless UI Dialog-based modals with
@plane/uiModalCoreacross the app and makes small behavioral cleanups (early returns, close handlers, minor tweaks).UI Refactor — migrate to
@plane/uiDialog/Transitionwrappers withModalCore(+EModalPosition,EModalWidth) in modals such as:account/deactivate-account-modal.tsx,automation/select-month-modal.tsx,core/filters/date-filter-modal.tsxcore/modals/*(bulk delete, change email, existing issues list, user/workspace image upload)cycles/*(archive, transfer issues)exporter/export-modal.tsx,inbox/modals/*(select duplicate, snooze)integration/delete-import-modal.tsxissues/*(archive issue, confirm discard, parent issues list)modules/archived-modules/modal.tsxproject/*(member remove, delete, join, leave, invite members; project archive/restore)Behavioral tweaks
returnafter success handlers (e.g., account/cycle/module/project actions) and standardizehandleCloseusage.Written by Cursor Bugbot for commit cc7c141. This will update automatically on new commits. Configure here.
Summary by CodeRabbit
Refactor
Bug Fixes
UX
✏️ Tip: You can customize this high-level summary in your review settings.