273 detailed user profile creation#305
Conversation
📝 WalkthroughWalkthroughReplaces the shared UI package with a local Ark‑UI–based SolidJS component library under Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant User as User
participant Component as WebComponent
participant AlertDialog as AlertDialog (UI)
participant API as Server/API
participant Toast as ToastService
User->>Component: Click "Delete" / "Finish"
Component->>AlertDialog: set open = true (show confirmation)
AlertDialog->>User: render modal
User->>AlertDialog: confirm action
AlertDialog->>Component: invoke confirm handler
Component->>API: perform delete/save request
API-->>Component: success
Component->>AlertDialog: set open = false (close)
Component->>Toast: showToast.success(...)
Toast-->>User: display toast
sequenceDiagram
autonumber
participant User as User
participant CP as CompleteProfile Component
participant Steps as Steps UI
participant Auth as AuthService
participant Toast as ToastService
User->>CP: open CompleteProfile
CP->>Steps: render step 1
User->>Steps: fill inputs -> Next
Steps->>CP: handleStepChange (validation)
CP->>Steps: render step 2
User->>Steps: finish -> Submit
Steps->>CP: aggregate data
CP->>Auth: auth.updateProfile({title,institution,department,...})
Auth-->>CP: success
CP->>Toast: showToast.success(...)
Toast-->>User: display success
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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 |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| 🔵 In progress View logs |
corates | 0483d36 | Jan 18 2026, 06:07 PM |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
corates | ce43844 | Commit Preview URL | Jan 18 2026, 08:52 PM |
There was a problem hiding this comment.
Actionable comments posted: 13
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsx (1)
81-82: Fix the misleading comment about a delayThe code sets selectsReady immediately; the comment implies a delay that does not exist.
Proposed fix
- // Small delay to ensure Select components are ready before rendering setSelectsReady(true);As per coding guidelines, avoid stale comments that contradict the code.
🤖 Fix all issues with AI agents
In `@packages/web/src/components/auth/RoleSelector.jsx`:
- Around line 11-13: getTitleLabel currently treats any falsy value (including
empty string) as absent and returns null, preventing the "None" label from being
returned; change the emptiness check to only treat null or undefined as absent
(e.g., use titleValue == null or titleValue === null || titleValue ===
undefined) so that an explicit empty string will fall through to the
TITLE_OPTIONS lookup (TITLE_OPTIONS.find(t => t.value === titleValue)?.label ||
titleValue) and return the "None" label when appropriate.
In `@packages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx`:
- Around line 163-164: The onOpenChange handler in the Dialog component (in
ScoringSummary.jsx) calls props.onClose() unconditionally, which will throw if
onClose is not provided; update the handler used on the Dialog (the onOpenChange
prop) to guard before invoking props.onClose — e.g., check if props.onClose
exists or use optional chaining (props.onClose?.()) so closing the dialog is
safe when onClose is undefined.
In `@packages/web/src/components/checklist/ScoreTag.jsx`:
- Around line 83-88: In ScoreTag.jsx update the anchor that opens external
guidance (the <a> rendered with href={infoUrl()} and aria-label using
getChecklistMetadata(props.checklistType).name) to include "noopener" in its rel
attribute (e.g., change rel='noreferrer' to include noopener) so the new-tab
link uses rel="noreferrer noopener" to prevent tabnabbing; keep the existing
target='_blank' and accessibility label unchanged.
In `@packages/web/src/components/dashboard/ProjectsSection.jsx`:
- Around line 183-191: The Show condition uses a redundant null check on
canCreateProject()—that function always returns a boolean—so replace the
compound condition with a check that also respects subscription loading; change
the visibility logic to use subscriptionLoading() together with
canCreateProject() (e.g., only show the ContactPrompt when subscriptionLoading()
is false and canCreateProject() is false) so update the Show condition
referencing canCreateProject() and subscriptionLoading() and keep the
ContactPrompt props unchanged.
In `@packages/web/src/components/mocks/ProjectWizardMock.jsx`:
- Around line 752-783: The input element has two onFocus handlers so the first
(which calls setShowSuggestions(true)) is overwritten by the second that applies
styles; combine them by creating a single onFocus callback that both calls
setShowSuggestions(true) and applies the visual styles (same logic currently in
the second onFocus), keeping the existing onBlur behavior and preserving
emailInput(), setShowSuggestions, and tokens usage; update the input's onFocus
to reference that combined handler (or inline combine) so suggestion visibility
and styling both run.
In
`@packages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsx`:
- Around line 119-123: The DialogCloseTrigger control rendering the FiX icon in
AssignReviewersModal (the DialogCloseTrigger element containing <FiX />) lacks
an accessible name; update the DialogCloseTrigger to include an accessible label
by adding an aria-label (e.g., aria-label="Close") or a title prop on the
trigger element (or on the FiX icon) so screen readers announce its purpose,
ensuring the icon-only control is accessible.
In
`@packages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsx`:
- Around line 94-103: The Aim tooltip trigger uses a non-focusable div inside
TooltipTrigger, preventing keyboard users from opening the tooltip; replace that
div with a focusable element (preferably a <button type="button">) keeping the
same className/styles and contents so it receives keyboard focus and triggers
the Tooltip on focus/keyboard activation (or alternatively add tabIndex="0" and
role="button" plus key handlers), updating the element inside TooltipTrigger in
ROB2Navbar.jsx (the container currently with class 'mr-1 flex shrink-0...') to
be focusable.
In `@packages/web/src/components/project/todo-tab/TodoStudyRow.jsx`:
- Around line 94-96: The PDF count currently renders with a unicode middle dot;
update the UI string in the TodoStudyRow component where Show is used (the block
invoking hasPdfs() and pdfCount()) to use an ASCII separator such as " - " or "
| " instead of "·". Locate the Show wrapper around hasPdfs() and replace the
unicode middle dot in the text node that includes pdfCount() with the chosen
ASCII punctuation so the displayed string becomes e.g. " - {pdfCount()} PDFs".
In `@packages/web/src/components/sidebar/Sidebar.jsx`:
- Around line 154-162: confirmDeleteChecklist currently awaits deleteChecklist
without handling errors which can cause unhandled rejections and skip cleanup;
wrap the await deleteChecklist(checklistId) in a try/catch/finally: in try call
deleteChecklist(checklistId), in catch log/report the error and show a
user-facing message (toast/alert) so failures surface, and in finally always
call setDeleteDialogOpen(false) and setPendingDeleteId(null) to ensure cleanup;
reference confirmDeleteChecklist, deleteChecklist, setDeleteDialogOpen, and
setPendingDeleteId when making the change.
In `@packages/web/src/components/ui/alert-dialog.tsx`:
- Around line 246-263: The AlertDialogCloseTrigger is an icon-only button
missing an accessible label; update AlertDialogCloseTriggerProps to accept an
optional ariaLabel?: string (or label?: string) and pass
aria-label={props.ariaLabel ?? 'Close'} into DialogPrimitive.CloseTrigger (the
component returned by AlertDialogCloseTrigger) so the FiX icon button is
announced by screen readers; ensure the prop type and the
DialogPrimitive.CloseTrigger usage are updated accordingly (keep existing class,
disabled handling, and default label 'Close').
In `@packages/web/src/components/ui/button.tsx`:
- Around line 56-63: The Button component currently doesn't set an explicit
type, causing it to default to "submit" inside forms; update the JSX in the
Button component (function named Button) to include a default type="button"
attribute on the <button> element — place type="button" before spreading
{...others} so that callers can still override it via props if desired (or
alternatively add a type prop with default "button" in the splitProps handling
and pass that into the <button>).
In `@packages/web/src/components/ui/checkbox.tsx`:
- Around line 100-108: The Label component uses tailwind peer-disabled classes
that require a sibling with class "peer" but CheckboxHiddenInput does not set
that, so the styles never apply; fix by either adding the "peer" class to the
CheckboxHiddenInput element (where CheckboxHiddenInput is defined/used) or
change the classes on CheckboxPrimitive.Label to use Ark/HTML data attribute
selectors like data-[disabled]:cursor-not-allowed and data-[disabled]:opacity-70
so the disabled styling works without a peer sibling; update
CheckboxPrimitive.Label (and related class composition in cn(...)) and/or add
the "peer" class to CheckboxHiddenInput accordingly.
In `@packages/web/src/global.css`:
- Around line 4-9: The top comment describing Tailwind content sources is stale
(mentions `@corates/ui`) and contradicts the actual `@source` entries; update the
comment above the `@source` './components/ui/**/*.{js,jsx,ts,tsx}' and `@source`
'./lib/ui/**/*.{js,jsx,ts,tsx}' lines to accurately describe that local UI
component directories are being included as Tailwind content sources (remove or
replace the `@corates/ui` reference and any misleading wording), keeping the
intent clear and concise so the comment matches the `@source` declarations.
♻️ Duplicate comments (4)
packages/web/src/components/project/reconcile-tab/ReconcileStudyRow.jsx (2)
93-96: Duplicate: header click needs keyboard accessibilitySame keyboard accessibility concern as in
packages/web/src/components/project/todo-tab/TodoStudyRow.jsx.
118-120: Duplicate: unicode separator in PDF count textSame unicode separator concern as in
packages/web/src/components/project/todo-tab/TodoStudyRow.jsx. As per coding guidelines, avoid unicode symbols in UI strings.packages/web/src/components/project/completed-tab/CompletedStudyRow.jsx (2)
79-82: Duplicate: header click needs keyboard accessibilitySame keyboard accessibility concern as in
packages/web/src/components/project/todo-tab/TodoStudyRow.jsx.
104-106: Duplicate: unicode separator in PDF count textSame unicode separator concern as in
packages/web/src/components/project/todo-tab/TodoStudyRow.jsx. As per coding guidelines, avoid unicode symbols in UI strings.
🧹 Nitpick comments (42)
packages/web/src/components/mocks/ProjectViewComplete.jsx (4)
640-748: Use<For>component instead of.map()for list rendering.The
FiguresTabcomponent uses.map()on lines 650, 675, and 698, which breaks SolidJS reactivity best practices. As per coding guidelines, use Solid's<For>component for rendering lists.Suggested fix for lines 645-659
{/* Summary Stats */} <div class='grid grid-cols-4 gap-4'> - {[ + <For each={[ { label: 'Total Studies', value: '24', change: '+3 this week' }, { label: 'High Confidence', value: '8', pct: '33%' }, { label: 'Moderate', value: '10', pct: '42%' }, { label: 'Low/Critically Low', value: '6', pct: '25%' }, - ].map(stat => ( + ]}> + {stat => ( <div class='rounded-xl border border-slate-200 bg-white p-5'> <p class='text-sm text-slate-500'>{stat.label}</p> <div class='mt-1 flex items-end justify-between'> <span class='text-2xl font-bold text-slate-900'>{stat.value}</span> <span class='text-xs text-slate-400'>{stat.change || stat.pct}</span> </div> </div> - ))} + )} + </For> </div>Apply similar changes to the chart bars (line 675) and domain grid (line 698).
1-6: Update the header comment to reflect the rename from "Charts" to "Figures".Line 5 still references "Charts" in the design direction comment, but the tab has been renamed to "Figures".
Suggested fix
/** * ProjectView Mock - Complete Workflow * * Design Direction: Light-mode dashboard with clear workflow stages. - * Shows the full journey: Team -> Studies -> Assignment -> Review -> Reconcile -> Complete -> Charts + * Shows the full journey: Team -> Studies -> Assignment -> Review -> Reconcile -> Complete -> Figures */
316-318: Remove unusedshowUploadsignal.The
showUploadsignal is created but never used inStudiesTab. This is dead code.Suggested fix
function StudiesTab() { - const [showUpload, setShowUpload] = createSignal(false); - const unassignedStudies = createMemo(() => mockStudies.filter(s => s.assignedTo.length === 0));
782-785: Clarify intent: empty avatars section with production comment.The avatars section is now empty with only comments. If this is intentional for mock purposes, consider adding a
TODO(agent):comment to track the production implementation, or remove the empty<div>entirely if it serves no purpose.Option: Add TODO or remove empty container
- {/* Online team members - powered by Yjs awareness, only shows users currently viewing this project */} - <div class='flex -space-x-2'> - {/* In production, this would filter by awareness state from useProject() */} - </div> + {/* TODO(agent): Render online team members using Yjs awareness from useProject() */}packages/web/src/components/ui/cn.ts (1)
1-15: Consider widening cn input types to match clsx.The current signature rejects arrays and objects supported by clsx, which can force casts at call sites. Consider using clsx's ClassValue type for parity.
Proposed fix
-import { clsx } from 'clsx'; +import { clsx, type ClassValue } from 'clsx'; import { twMerge } from 'tailwind-merge'; @@ -export function cn(...inputs: Array<string | undefined | null | false>): string { +export function cn(...inputs: ClassValue[]): string { return twMerge(clsx(inputs)); }Please confirm your clsx version exports ClassValue, or adjust the import accordingly.
packages/web/src/styles/ark-ui.css (1)
41-61: Extend reduced-motion handling to collapsible animationsCurrently reduced-motion only disables select animations. Collapsible open and close animations should also be disabled to respect user preferences.
Proposed fix
`@media` (prefers-reduced-motion: reduce) { + [data-scope='collapsible'][data-part='content'] { + animation: none; + } [data-scope='select'][data-part='content'] { animation: none; } }Also applies to: 126-130
packages/web/src/components/ui/avatar.tsx (1)
23-81: Avoid splitProps to comply with the no-prop-destructuring ruleThe repo guidelines state not to destructure props in SolidJS components. You can avoid splitProps by spreading props first and overriding class afterward.
Proposed fix
-import { splitProps } from 'solid-js'; @@ -const Avatar: Component<AvatarProps> = props => { - const [local, others] = splitProps(props, ['class', 'children']); - return ( - <AvatarPrimitive.Root - class={cn('relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full', local.class)} - {...others} - > - {local.children} - </AvatarPrimitive.Root> - ); -}; +const Avatar: Component<AvatarProps> = props => ( + <AvatarPrimitive.Root + {...props} + class={cn('relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full', props.class)} + > + {props.children} + </AvatarPrimitive.Root> +); @@ -const AvatarImage: Component<AvatarImageProps> = props => { - const [local, others] = splitProps(props, ['class']); - return ( - <AvatarPrimitive.Image - class={cn('aspect-square h-full w-full object-cover', local.class)} - {...others} - /> - ); -}; +const AvatarImage: Component<AvatarImageProps> = props => ( + <AvatarPrimitive.Image + {...props} + class={cn('aspect-square h-full w-full object-cover', props.class)} + /> +); @@ -const AvatarFallback: Component<AvatarFallbackProps> = props => { - const [local, others] = splitProps(props, ['class', 'children']); - return ( - <AvatarPrimitive.Fallback - class={cn( - 'flex h-full w-full items-center justify-center rounded-full bg-gray-100 text-sm font-medium text-gray-600', - local.class, - )} - {...others} - > - {local.children} - </AvatarPrimitive.Fallback> - ); -}; +const AvatarFallback: Component<AvatarFallbackProps> = props => ( + <AvatarPrimitive.Fallback + {...props} + class={cn( + 'flex h-full w-full items-center justify-center rounded-full bg-gray-100 text-sm font-medium text-gray-600', + props.class, + )} + > + {props.children} + </AvatarPrimitive.Fallback> +);As per coding guidelines, avoid prop destructuring in SolidJS components.
packages/web/src/components/mocks/ProjectViewV2.jsx (4)
357-376: Use For instead of Array.map for list renderingArray.map in JSX bypasses Solid's list rendering conventions and can hurt fine-grained updates. Replace these lists with For.
Proposed fix
- {[ - { label: 'Total Studies', value: stats().total, color: tokens.slate600 }, - { label: 'Completed', value: stats().completed, color: tokens.success }, - { label: 'In Review', value: stats().inReview, color: tokens.blue600 }, - { - label: 'Needs Action', - value: stats().needsReconcile + stats().unassigned, - color: tokens.warning, - }, - ].map(stat => ( - <div class='text-center'> - <p class='text-2xl font-bold' style={{ color: stat.color }}> - {stat.value} - </p> - <p class='text-sm' style={{ color: tokens.slate500 }}> - {stat.label} - </p> - </div> - ))} + <For + each={[ + { label: 'Total Studies', value: stats().total, color: tokens.slate600 }, + { label: 'Completed', value: stats().completed, color: tokens.success }, + { label: 'In Review', value: stats().inReview, color: tokens.blue600 }, + { + label: 'Needs Action', + value: stats().needsReconcile + stats().unassigned, + color: tokens.warning, + }, + ]} + > + {stat => ( + <div class='text-center'> + <p class='text-2xl font-bold' style={{ color: stat.color }}> + {stat.value} + </p> + <p class='text-sm' style={{ color: tokens.slate500 }}> + {stat.label} + </p> + </div> + )} + </For>As per coding guidelines, use For for list rendering in SolidJS components.
Also applies to: 446-485
611-627: Replace Array.map and ternary rendering with For and ShowUse For for the Add Studies button list, and Show for the conditional avatar rendering inside the assigned list.
Proposed fix
- {[ - { icon: FiUpload, label: 'Upload PDFs', desc: 'Drag & drop' }, - { icon: FiLink, label: 'DOI/PMID', desc: 'Lookup metadata' }, - { icon: FiFile, label: 'Reference File', desc: 'RIS, BibTeX' }, - { icon: FiExternalLink, label: 'Google Drive', desc: 'Connect' }, - ].map(source => ( - <button - class='flex flex-col items-center gap-2 rounded-lg border-2 border-dashed p-4 transition-all' - style={{ 'border-color': tokens.slate200, color: tokens.slate500 }} - > - <source.icon class='h-5 w-5' /> - <span class='text-sm font-medium'>{source.label}</span> - <span class='text-xs' style={{ color: tokens.slate400 }}> - {source.desc} - </span> - </button> - ))} + <For + each={[ + { icon: FiUpload, label: 'Upload PDFs', desc: 'Drag & drop' }, + { icon: FiLink, label: 'DOI/PMID', desc: 'Lookup metadata' }, + { icon: FiFile, label: 'Reference File', desc: 'RIS, BibTeX' }, + { icon: FiExternalLink, label: 'Google Drive', desc: 'Connect' }, + ]} + > + {source => ( + <button + class='flex flex-col items-center gap-2 rounded-lg border-2 border-dashed p-4 transition-all' + style={{ 'border-color': tokens.slate200, color: tokens.slate500 }} + > + <source.icon class='h-5 w-5' /> + <span class='text-sm font-medium'>{source.label}</span> + <span class='text-xs' style={{ color: tokens.slate400 }}> + {source.desc} + </span> + </button> + )} + </For> @@ - {memberId => { - const member = mockMembers.find(m => m.id === memberId); - return member ? - <Avatar name={member.name} size='26px' fontSize='9px' /> - : null; - }} + {memberId => { + const member = mockMembers.find(m => m.id === memberId); + return ( + <Show when={member}> + <Avatar name={member.name} size='26px' fontSize='9px' /> + </Show> + ); + }}As per coding guidelines, use For and Show for list and conditional rendering in SolidJS components.
Also applies to: 756-761
985-1004: Use For instead of Array.map in ChartsTab listsArray.map in JSX bypasses Solid's list rendering conventions. Use For for each of these lists.
Proposed fix
- {[ - { label: 'Total Studies', value: '24', sub: '+3 this week' }, - { label: 'High Confidence', value: '8', sub: '33%' }, - { label: 'Moderate', value: '10', sub: '42%' }, - { label: 'Low/Critically Low', value: '6', sub: '25%' }, - ].map(stat => ( - <Card> - <p class='text-sm' style={{ color: tokens.slate500 }}> - {stat.label} - </p> - <div class='mt-1 flex items-end justify-between'> - <span class='text-2xl font-bold' style={{ color: tokens.slate900 }}> - {stat.value} - </span> - <span class='text-xs' style={{ color: tokens.slate400 }}> - {stat.sub} - </span> - </div> - </Card> - ))} + <For + each={[ + { label: 'Total Studies', value: '24', sub: '+3 this week' }, + { label: 'High Confidence', value: '8', sub: '33%' }, + { label: 'Moderate', value: '10', sub: '42%' }, + { label: 'Low/Critically Low', value: '6', sub: '25%' }, + ]} + > + {stat => ( + <Card> + <p class='text-sm' style={{ color: tokens.slate500 }}> + {stat.label} + </p> + <div class='mt-1 flex items-end justify-between'> + <span class='text-2xl font-bold' style={{ color: tokens.slate900 }}> + {stat.value} + </span> + <span class='text-xs' style={{ color: tokens.slate400 }}> + {stat.sub} + </span> + </div> + </Card> + )} + </For>As per coding guidelines, use For for list rendering in SolidJS components.
Also applies to: 1017-1042, 1053-1070, 1083-1122
1267-1270: Avoid runtime font@importinside the componentInline
@importin a component can lead to repeated injections and CSP problems. Prefer loading the font once in global styles or the app shell.packages/web/src/components/mocks/ProjectWizardMock.jsx (2)
1237-1256: PreferForcomponent overArray.map()for list rendering.Per coding guidelines, SolidJS components should use the
Forcomponent for rendering lists instead ofArray.map().Suggested refactor
<div class='grid grid-cols-4 gap-2'> - {[ - { name: 'RIS', desc: 'Research Info Systems' }, - { name: 'BibTeX', desc: 'LaTeX bibliography' }, - { name: 'EndNote', desc: 'XML export' }, - { name: 'CSV', desc: 'Spreadsheet' }, - ].map(format => ( - <div - class='rounded-lg border p-3 text-center' - style={{ 'border-color': tokens.slate200, background: 'white' }} - > - <p class='text-sm font-medium' style={{ color: tokens.slate700 }}> - {format.name} - </p> - <p class='mt-0.5 text-xs' style={{ color: tokens.slate400 }}> - {format.desc} - </p> - </div> - ))} + <For each={[ + { name: 'RIS', desc: 'Research Info Systems' }, + { name: 'BibTeX', desc: 'LaTeX bibliography' }, + { name: 'EndNote', desc: 'XML export' }, + { name: 'CSV', desc: 'Spreadsheet' }, + ]}> + {format => ( + <div + class='rounded-lg border p-3 text-center' + style={{ 'border-color': tokens.slate200, background: 'white' }} + > + <p class='text-sm font-medium' style={{ color: tokens.slate700 }}> + {format.name} + </p> + <p class='mt-0.5 text-xs' style={{ color: tokens.slate400 }}> + {format.desc} + </p> + </div> + )} + </For> </div>
1325-1348: Another instance ofArray.map()that should useFor.Same issue as above - prefer
Forcomponent for list rendering in SolidJS.packages/web/src/components/ui/spinner.tsx (1)
101-106: ButtonSpinner is simpler than the external library version.Note that
packages/ui/src/components/Spinner.tsxhas a more feature-richButtonSpinnerwithloadingandchildrenprops for conditional rendering. This implementation is a simple preset spinner. Consider whether the conditional loading pattern would be useful here.The current approach works for inline composition like:
<Button disabled={loading()}> <Show when={loading()}><ButtonSpinner /></Show> {loading() ? 'Saving...' : 'Save'} </Button>The external library approach wraps content:
<ButtonSpinner loading={loading()}>Save</ButtonSpinner>Both patterns are valid - the simpler approach here is fine for a local UI library.
packages/web/src/components/ui/checkbox.tsx (1)
40-41: Consider removing theCheckboxalias to avoid confusion.Both
Checkbox(line 40) andCheckboxRoot(line 51) export the same underlying component with different APIs.CheckboxRootwraps the primitive with customonCheckedChangehandling, whileCheckboxis the raw primitive. This could lead to confusion about which to use.If the raw primitive is needed for advanced use cases, consider renaming it to
CheckboxPrimitivefor clarity, or remove it ifCheckboxRootcovers all use cases.packages/web/src/components/ui/tooltip.tsx (1)
102-106: Consider usingShowcomponent for conditional rendering.Per coding guidelines, SolidJS components should use the
Showcomponent for conditional rendering instead of&&or ternary operators.Suggested fix
{...others} > - {showArrow() && ( + <Show when={showArrow()}> <TooltipPrimitive.Arrow> <TooltipPrimitive.ArrowTip class='bg-gray-900' /> </TooltipPrimitive.Arrow> - )} + </Show> {local.children} </TooltipPrimitive.Content>packages/web/src/components/project/reconcile-tab/rob2-reconcile/NavbarDomainPill.jsx (1)
89-93: Prefer Show over ternary for the icon swap inside the conditional block.
This is a render-time condition, so using Show keeps conditional rendering consistent.Proposed refactor
- <Show when={props.sectionKey !== 'overall'}> - {props.isExpanded ? - <FiChevronDown class='h-3 w-3 opacity-60' /> - : <FiChevronRight class='h-3 w-3 opacity-60' />} - </Show> + <Show when={props.sectionKey !== 'overall'}> + <Show + when={props.isExpanded} + fallback={<FiChevronRight class='h-3 w-3 opacity-60' />} + > + <FiChevronDown class='h-3 w-3 opacity-60' /> + </Show> + </Show>As per coding guidelines, use Show for conditional rendering.
packages/web/src/components/project/reconcile-tab/amstar2-reconcile/ChecklistReconciliation.jsx (1)
418-420: Use Show for the saving label to match SolidJS conditional rendering guidance.Proposed refactor
- <AlertDialogAction variant='warning' disabled={saving()} onClick={confirmSave}> - {saving() ? 'Saving...' : 'Finish'} - </AlertDialogAction> + <AlertDialogAction variant='warning' disabled={saving()} onClick={confirmSave}> + <Show when={!saving()} fallback='Saving...'> + Finish + </Show> + </AlertDialogAction>As per coding guidelines, use Show for conditional rendering.
packages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Reconciliation.jsx (1)
443-446: Use Show for the saving label to follow SolidJS conditional rendering guidance.Proposed refactor
- <AlertDialogAction variant='warning' disabled={saving()} onClick={confirmSave}> - {saving() ? 'Saving...' : 'Finish'} - </AlertDialogAction> + <AlertDialogAction variant='warning' disabled={saving()} onClick={confirmSave}> + <Show when={!saving()} fallback='Saving...'> + Finish + </Show> + </AlertDialogAction>As per coding guidelines, use Show for conditional rendering.
packages/web/src/components/ui/popover.tsx (1)
57-81: Avoid prop destructuring via splitProps in Solid components.
Project rules require direct props access to preserve reactivity; consider using props.field and composing class names without splitting.As per coding guidelines, avoid destructuring SolidJS props.
Also applies to: 88-103, 109-123, 129-137, 143-151, 158-171, 177-180, 186-194
packages/web/src/components/ui/tabs.tsx (1)
47-129: Avoid prop destructuring via splitProps in Solid components.
Please align with the repo rule to access props directly and compose class names without splitting.As per coding guidelines, avoid destructuring SolidJS props.
packages/web/src/components/checklist/ROBINSIChecklist/ScoringSummary.jsx (1)
194-248: Consider using DialogHeader, DialogBody, and DialogCloseTrigger for consistency.The
ResourcesDialoguses manual div wrappers with border styling instead of the newDialogHeader,DialogBody, andDialogCloseTriggercomponents. While functional, this creates inconsistency with other dialogs in this PR that use the full composition pattern (e.g.,GoogleDrivePickerModal,EditPdfMetadataModal,PdfListItem).Suggested refactor for consistency
-import { - Dialog, - DialogBackdrop, - DialogPositioner, - DialogContent, - DialogTitle, - DialogDescription, -} from '@/components/ui/dialog'; +import { + Dialog, + DialogBackdrop, + DialogPositioner, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogBody, + DialogCloseTrigger, +} from '@/components/ui/dialog'; +import { FiX } from 'solid-icons/fi';Then update the dialog structure:
<DialogContent class='max-h-[85vh] max-w-md overflow-auto'> - <div class='border-b border-gray-200 px-6 py-4'> + <DialogHeader> <DialogTitle>ROBINS-I V2 Resources</DialogTitle> - <DialogDescription class='mt-1'> - Official guidance and documentation for the ROBINS-I assessment tool. - </DialogDescription> - </div> + <DialogCloseTrigger> + <FiX class='h-5 w-5' /> + </DialogCloseTrigger> + </DialogHeader> + <DialogBody> + <DialogDescription> + Official guidance and documentation for the ROBINS-I assessment tool. + </DialogDescription> - <div class='space-y-4 px-6 py-4'> + <div class='mt-4 space-y-4'> {/* ... resource links ... */} - </div> - - <div class='border-t border-gray-200 px-6 py-3'> - <button ...>Close</button> - </div> + </div> + </DialogBody> </DialogContent>packages/web/src/components/project/all-studies-tab/EditPdfMetadataModal.jsx (1)
193-213: Consider using DialogFooter for action buttons.The action buttons are placed inside
DialogBodywith a manualborder-tseparator. TheDialogFootercomponent provides a consistent footer style withbg-gray-50and standardized spacing. This would improve consistency across dialogs.Optional: Use DialogFooter for actions
Add
DialogFooterto imports:import { Dialog, DialogBackdrop, DialogPositioner, DialogContent, DialogHeader, DialogTitle, DialogBody, DialogCloseTrigger, + DialogFooter, } from '@/components/ui/dialog';Then move action buttons:
- {/* Actions */} - <div class='flex justify-end gap-3 border-t border-gray-200 pt-4'> - <button ...>Cancel</button> - <button ...>Save Changes</button> - </div> </div> </DialogBody> + <DialogFooter> + <button ...>Cancel</button> + <button ...>Save Changes</button> + </DialogFooter> </DialogContent>packages/web/src/components/settings/pages/MergeAccountsDialog.jsx (1)
239-334: Use Show instead of ternary expressions in JSXSeveral new conditional fragments use ternary operators (dialog title, help text, placeholder, loader icon). Please refactor these to
<Show>to keep conditional rendering consistent across SolidJS components. As per coding guidelines, use Show for conditional rendering.packages/web/src/components/settings/pages/SessionManagement.jsx (1)
9-18: Prefer local toast module over@corates/uiThe PR introduces the local toast system; switching here avoids mixing toast APIs and keeps the UI migration consistent.
Proposed change
-import { showToast } from '@corates/ui'; +import { showToast } from '@/components/ui/toast';packages/web/src/components/project/reconcile-tab/robins-i-reconcile/NavbarDomainPill.jsx (1)
90-94: Replace ternary icon toggle with ShowUse Show instead of a ternary for conditional rendering.
Proposed change
- <Show when={props.sectionKey !== 'overall'}> - {props.isExpanded ? - <FiChevronDown class='h-3 w-3 opacity-60' /> - : <FiChevronRight class='h-3 w-3 opacity-60' />} - </Show> + <Show when={props.sectionKey !== 'overall'}> + <Show + when={props.isExpanded} + fallback={<FiChevronRight class='h-3 w-3 opacity-60' />} + > + <FiChevronDown class='h-3 w-3 opacity-60' /> + </Show> + </Show>As per coding guidelines, use Show for conditional rendering.
packages/web/src/components/ui/toast.tsx (1)
52-109: Avoid splitProps to comply with no-props-destructuring rulesplitProps is a form of props destructuring. Prefer direct props access and apply the same pattern across the toast wrapper components. If you do this, splitProps can be removed from the imports.
Proposed change
-const ToastRoot: Component<ToastRootProps> = props => { - const [local, others] = splitProps(props, ['class', 'children']); - return ( - <ToastPrimitive.Root - class={cn( - 'toast-item pointer-events-auto w-full max-w-sm rounded-lg border border-gray-200 bg-white p-4 shadow-lg', - local.class, - )} - {...others} - > - {local.children} - </ToastPrimitive.Root> - ); -}; +const ToastRoot: Component<ToastRootProps> = props => { + return ( + <ToastPrimitive.Root + {...props} + class={cn( + 'toast-item pointer-events-auto w-full max-w-sm rounded-lg border border-gray-200 bg-white p-4 shadow-lg', + props.class, + )} + > + {props.children} + </ToastPrimitive.Root> + ); +};As per coding guidelines, avoid prop destructuring in Solid components.
packages/web/src/components/project/ProjectsPanel.jsx (1)
264-270: Use Show for delete button labelReplace the ternary with Show for conditional rendering.
Proposed change
- {deleteLoading() ? 'Deleting...' : 'Delete Project'} + <Show when={deleteLoading()} fallback="Delete Project"> + Deleting... + </Show>As per coding guidelines, use Show for conditional rendering.
packages/web/src/components/ui/steps.tsx (1)
78-84: Avoid splitProps in Steps wrappersProps destructuring is disallowed; use props directly and merge class names. Apply the same pattern across the Steps wrappers.
Proposed change
-const StepsList: Component<StepsListProps> = props => { - const [local, others] = splitProps(props, ['class', 'children']); - return ( - <StepsPrimitive.List class={cn('flex items-center gap-2', local.class)} {...others}> - {local.children} - </StepsPrimitive.List> - ); -}; +const StepsList: Component<StepsListProps> = props => { + return ( + <StepsPrimitive.List {...props} class={cn('flex items-center gap-2', props.class)}> + {props.children} + </StepsPrimitive.List> + ); +};As per coding guidelines, avoid prop destructuring in Solid components.
packages/web/src/components/ui/select.tsx (1)
64-74: Avoid splitProps in Select wrappersUse props directly and override handlers after spreading. Apply the same pattern across the Select wrappers.
Proposed change
-const Select = <T,>(props: SelectProps<T>) => { - const [local, others] = splitProps(props, ['children', 'onValueChange', 'onOpenChange']); - return ( - <SelectPrimitive.Root - onValueChange={details => local.onValueChange?.(details.value)} - onOpenChange={details => local.onOpenChange?.(details.open)} - {...others} - > - {local.children} - </SelectPrimitive.Root> - ); -}; +const Select = <T,>(props: SelectProps<T>) => { + return ( + <SelectPrimitive.Root + {...props} + onValueChange={details => props.onValueChange?.(details.value)} + onOpenChange={details => props.onOpenChange?.(details.open)} + > + {props.children} + </SelectPrimitive.Root> + ); +};As per coding guidelines, avoid prop destructuring in Solid components.
packages/web/src/components/dashboard/LocalAppraisalsSection.jsx (1)
96-116: Consider adding loading state during deletion.The
confirmDeletefunction is async but doesn't indicate loading state to the user. Users may click "Delete" multiple times if the operation takes time.Optional: Add loading state to prevent double-clicks
+ const [isDeleting, setIsDeleting] = createSignal(false); const confirmDelete = async () => { const checklistId = pendingDeleteId(); - if (checklistId) { + if (checklistId && !isDeleting()) { + setIsDeleting(true); await deleteChecklist(checklistId); + setIsDeleting(false); } setDeleteDialogOpen(false); setPendingDeleteId(null); };Then in the AlertDialogAction:
- <AlertDialogAction variant='danger' onClick={confirmDelete}> + <AlertDialogAction variant='danger' onClick={confirmDelete} disabled={isDeleting()}> - Delete + {isDeleting() ? 'Deleting...' : 'Delete'} </AlertDialogAction>packages/web/src/components/checklist/LocalAppraisalsPanel.jsx (1)
38-59: Code duplication with LocalAppraisalsSection.jsx.This delete confirmation pattern (signals, handleDelete, confirmDelete, AlertDialog) is nearly identical to
LocalAppraisalsSection.jsx. Consider extracting a reusable hook or component to reduce duplication.Extract shared delete confirmation logic
Create a primitive hook in
packages/web/src/primitives/:// useDeleteConfirmation.js import { createSignal } from 'solid-js'; export function useDeleteConfirmation(onDelete) { const [dialogOpen, setDialogOpen] = createSignal(false); const [pendingId, setPendingId] = createSignal(null); const [isDeleting, setIsDeleting] = createSignal(false); const requestDelete = (id) => { setPendingId(id); setDialogOpen(true); }; const confirmDelete = async () => { const id = pendingId(); if (id && !isDeleting()) { setIsDeleting(true); await onDelete(id); setIsDeleting(false); } setDialogOpen(false); setPendingId(null); }; const cancelDelete = () => { setDialogOpen(false); setPendingId(null); }; return { dialogOpen, setDialogOpen, isDeleting, requestDelete, confirmDelete, cancelDelete, }; }Then use it in both components:
const { dialogOpen, setDialogOpen, requestDelete, confirmDelete } = useDeleteConfirmation(deleteChecklist);Based on learnings, reusable logic should be extracted to primitives in
packages/web/src/primitives/.packages/web/src/components/settings/SettingsSidebar.jsx (1)
106-114: Minor: Consider using a signal for pathname tracking.The
lastPathnamevariable is mutated within an effect closure. While this works, using a signal would be more idiomatic in SolidJS and clearer about the reactive intent.Optional: Use signal for clearer reactivity
- // Close mobile sidebar when route changes - let lastPathname = location.pathname; - createEffect(() => { - const currentPathname = location.pathname; - if (props.mobileOpen && currentPathname !== lastPathname) { - props.onCloseMobile?.(); - } - lastPathname = currentPathname; - }); + // Close mobile sidebar when route changes + const [lastPathname, setLastPathname] = createSignal(location.pathname); + createEffect(() => { + const currentPathname = location.pathname; + if (props.mobileOpen && currentPathname !== lastPathname()) { + props.onCloseMobile?.(); + } + setLastPathname(currentPathname); + });packages/web/src/components/project/overview-tab/OverviewTab.jsx (2)
423-450: Use Show for conditional trigger textThe helper text in the triggers uses ternary rendering. Prefer Show with fallback and apply the same pattern to both sections. As per coding guidelines, use Show for conditional rendering in SolidJS.
Proposed change
- {chartsExpanded() ? 'Click to collapse' : 'Click to expand charts'} + <Show when={chartsExpanded()} fallback='Click to expand charts'> + Click to collapse + </Show>
468-490: Prefer Show for conditional dialog text and clear pending state on closeThe dialog title, description, and action label use ternary expressions. Use Show with fallbacks, and clear pendingRemoveMember when the dialog closes to avoid stale values. As per coding guidelines, use Show for conditional rendering in SolidJS.
Proposed change
- <AlertDialog open={removeDialogOpen()} onOpenChange={setRemoveDialogOpen}> + <AlertDialog + open={removeDialogOpen()} + onOpenChange={open => { + setRemoveDialogOpen(open); + if (!open) setPendingRemoveMember(null); + }} + > ... - {pendingRemoveMember()?.isSelf ? 'Leave Project' : 'Remove Member'} + <Show when={pendingRemoveMember()?.isSelf} fallback='Remove Member'> + Leave Project + </Show>packages/web/src/components/admin/OrgDetail.jsx (1)
459-501: Replace ternary dialog title and message with ShowThe confirm dialog uses ternary expressions for both title and message. Prefer Show with fallback and apply the same pattern to the message paragraph. As per coding guidelines, use Show for conditional rendering in SolidJS.
Proposed change
- {confirmDialog()?.type === 'cancel-subscription' ? - 'Cancel Subscription' - : 'Revoke Grant'} + <Show when={confirmDialog()?.type === 'cancel-subscription'} fallback='Revoke Grant'> + Cancel Subscription + </Show>packages/web/src/components/admin/ProjectDetail.jsx (1)
520-573: Replace ternary dialog title with ShowThe confirm dialog title uses nested ternary expressions. Prefer Show with fallback for conditional rendering. As per coding guidelines, use Show for conditional rendering in SolidJS.
Proposed change
- {confirmDialog()?.type === 'delete-project' ? - 'Delete Project' - : confirmDialog()?.type === 'remove-member' ? - 'Remove Member' - : 'Confirm'} + <Show + when={confirmDialog()?.type === 'delete-project'} + fallback={ + <Show when={confirmDialog()?.type === 'remove-member'} fallback='Confirm'> + Remove Member + </Show> + } + > + Delete Project + </Show>packages/web/src/components/admin/StorageManagement.jsx (1)
419-449: Prefer Show for pluralizationThe plural suffix uses ternary rendering. Use Show to conditionally render the suffix. As per coding guidelines, use Show for conditional rendering in SolidJS.
Proposed change
- Are you sure you want to delete {deleteDialog()?.length || 0} document - {deleteDialog()?.length === 1 ? '' : 's'}? This action cannot be undone. + Are you sure you want to delete {deleteDialog()?.length || 0} document + <Show when={(deleteDialog()?.length || 0) !== 1}>s</Show>? This action cannot be undone.packages/web/src/components/admin/UserDetail.jsx (1)
691-734: Replace ternary dialog title with ShowThe confirm dialog title uses a ternary expression. Prefer Show with fallback for conditional rendering. As per coding guidelines, use Show for conditional rendering in SolidJS.
Proposed change
- {confirmDialog()?.type === 'delete' ? 'Delete User' : 'Revoke All Sessions'} + <Show when={confirmDialog()?.type === 'delete'} fallback='Revoke All Sessions'> + Delete User + </Show>packages/web/src/components/admin/SubscriptionDialog.jsx (1)
6-16: Use Show for title and submit label statesThe title and submit label rely on nested ternary rendering. Replace with Show blocks and add a Show import to align with Solid conditional rendering guidance. As per coding guidelines, use Show for conditional rendering in SolidJS.
Proposed change
+import { Show } from 'solid-js'; import { Dialog, DialogBackdrop, DialogPositioner, DialogContent, DialogHeader, DialogTitle, DialogBody, DialogCloseTrigger, } from '@/components/ui/dialog'; import { FiX } from 'solid-icons/fi'; ... - <DialogTitle>{isEdit() ? 'Edit Subscription' : 'Create Subscription'}</DialogTitle> + <DialogTitle> + <Show when={isEdit()} fallback='Create Subscription'> + Edit Subscription + </Show> + </DialogTitle> ... - {loading() ? - isEdit() ? - 'Updating...' - : 'Creating...' - : isEdit() ? - 'Update' - : 'Create'} + <Show + when={loading()} + fallback={ + <Show when={isEdit()} fallback='Create'> + Update + </Show> + } + > + <Show when={isEdit()} fallback='Creating...'> + Updating... + </Show> + </Show>Also applies to: 75-219
packages/web/src/components/profile/ProfilePage.jsx (1)
201-204: Unnecessary optional chaining on signal returns.Signals always return a value (string in this case), so the
?.oneditInstitution()andeditDepartment()is redundant. This is a minor style observation and doesn't affect functionality.Suggested simplification
await auth.updateProfile({ title: editTitle() || null, - institution: editInstitution()?.trim() || null, - department: editDepartment()?.trim() || null, + institution: editInstitution().trim() || null, + department: editDepartment().trim() || null, });packages/workers/src/db/schema.ts (1)
19-29: Prefer intent-focused comments over descriptive field notes.
These inline comments mostly restate field meaning; consider removing or rephrasing to document intent, constraints, or validation expectations.Proposed change
- // Academic/professional information - title: text('title'), // 'Dr.', 'Prof.', or custom - institution: text('institution'), // University or organization name - department: text('department'), // Department or faculty name - country: text('country'), // ISO 3166-1 alpha-2 code (e.g., 'US', 'GB') - bio: text('bio'), // Short biography - // User preferences and activity - timezone: text('timezone'), // IANA timezone (e.g., 'America/New_York') - locale: text('locale'), // BCP 47 language tag (e.g., 'en-US') - preferences: text('preferences'), // JSON: { theme, emailNotifications, etc. } + title: text('title'), + institution: text('institution'), + department: text('department'), + country: text('country'), + bio: text('bio'), + timezone: text('timezone'), + locale: text('locale'), + preferences: text('preferences'),As per coding guidelines, keep comments focused on intent and constraints.
| <input | ||
| type='email' | ||
| value={emailInput()} | ||
| onInput={e => { | ||
| setEmailInput(e.target.value); | ||
| setShowSuggestions(true); | ||
| }} | ||
| onFocus={() => setShowSuggestions(true)} | ||
| onKeyDown={e => { | ||
| if (e.key === 'Enter' && emailInput()) { | ||
| e.preventDefault(); | ||
| addMember(emailInput()); | ||
| } | ||
| }} | ||
| placeholder='Email address or name' | ||
| class='w-full rounded-lg border py-2.5 pr-3 pl-10 text-sm transition-all duration-200 outline-none' | ||
| style={{ | ||
| 'border-color': tokens.slate200, | ||
| background: 'white', | ||
| color: tokens.slate900, | ||
| }} | ||
| onFocus={e => { | ||
| e.target.style.borderColor = tokens.blue500; | ||
| e.target.style.boxShadow = `0 0 0 3px ${tokens.blue100}`; | ||
| }} | ||
| onBlur={e => { | ||
| e.target.style.borderColor = tokens.slate200; | ||
| e.target.style.boxShadow = 'none'; | ||
| // Delay hiding suggestions to allow click | ||
| setTimeout(() => setShowSuggestions(false), 150); | ||
| }} | ||
| /> |
There was a problem hiding this comment.
Duplicate onFocus property on input element.
Static analysis correctly identifies that onFocus is assigned twice on this input element (lines 759 and 773). The second handler will override the first, so the autocomplete suggestion visibility logic on line 759 will be lost.
Proposed fix: Combine the onFocus handlers
<input
type='email'
value={emailInput()}
onInput={e => {
setEmailInput(e.target.value);
setShowSuggestions(true);
}}
- onFocus={() => setShowSuggestions(true)}
onKeyDown={e => {
if (e.key === 'Enter' && emailInput()) {
e.preventDefault();
addMember(emailInput());
}
}}
placeholder='Email address or name'
class='w-full rounded-lg border py-2.5 pr-3 pl-10 text-sm transition-all duration-200 outline-none'
style={{
'border-color': tokens.slate200,
background: 'white',
color: tokens.slate900,
}}
onFocus={e => {
+ setShowSuggestions(true);
e.target.style.borderColor = tokens.blue500;
e.target.style.boxShadow = `0 0 0 3px ${tokens.blue100}`;
}}🧰 Tools
🪛 Biome (2.1.2)
[error] 759-759: This JSX property is assigned multiple times.
This attribute is assigned again here.
(lint/suspicious/noDuplicateJsxProps)
🤖 Prompt for AI Agents
In `@packages/web/src/components/mocks/ProjectWizardMock.jsx` around lines 752 -
783, The input element has two onFocus handlers so the first (which calls
setShowSuggestions(true)) is overwritten by the second that applies styles;
combine them by creating a single onFocus callback that both calls
setShowSuggestions(true) and applies the visual styles (same logic currently in
the second onFocus), keeping the existing onBlur behavior and preserving
emailInput(), setShowSuggestions, and tokens usage; update the input's onFocus
to reference that combined handler (or inline combine) so suggestion visibility
and styling both run.
| <Show when={hasPdfs()}> | ||
| <span class='text-gray-400'> · {pdfCount()} PDFs</span> | ||
| </Show> |
There was a problem hiding this comment.
Avoid unicode symbols in the PDF count text
The separator between the citation and PDF count uses a unicode middle dot. Please replace it with ASCII punctuation (for example, " - " or " | ") to comply with the no-unicode rule. As per coding guidelines, avoid unicode symbols in UI strings.
🤖 Prompt for AI Agents
In `@packages/web/src/components/project/todo-tab/TodoStudyRow.jsx` around lines
94 - 96, The PDF count currently renders with a unicode middle dot; update the
UI string in the TodoStudyRow component where Show is used (the block invoking
hasPdfs() and pdfCount()) to use an ASCII separator such as " - " or " | "
instead of "·". Locate the Show wrapper around hasPdfs() and replace the unicode
middle dot in the text node that includes pdfCount() with the chosen ASCII
punctuation so the displayed string becomes e.g. " - {pdfCount()} PDFs".
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@packages/web/src/components/ui/checkbox.tsx`:
- Around line 100-108: The Tailwind data attribute syntax used on
CheckboxPrimitive.Label is incorrect—replace the invalid `data-disabled:` usages
with the proper arbitrary attribute form `data-[disabled]:` so the disabled
styles apply; update the class construction in the CheckboxPrimitive.Label
render (where cn is called with 'text-sm leading-none font-medium
text-gray-900', 'data-disabled:cursor-not-allowed data-disabled:opacity-70',
local.class, and {...others}) to use 'data-[disabled]:cursor-not-allowed' and
'data-[disabled]:opacity-70' instead.
- Around line 71-81: The disabled styles on CheckboxPrimitive.Control use the
native CSS pseudo-class ("disabled:cursor-not-allowed disabled:opacity-50")
which won't apply because Control renders a wrapper element; change those to Ark
UI's data-attribute pattern to mirror the existing state styling (e.g. replace
"disabled:cursor-not-allowed disabled:opacity-50" with
"data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50" in the class
list for CheckboxPrimitive.Control so the wrapper responds to the component's
disabled state).
♻️ Duplicate comments (3)
packages/web/src/components/auth/RoleSelector.jsx (1)
11-14: Previous issue resolved.The null check now correctly uses
titleValue == null, allowing an explicit empty string to fall through to the lookup and return the "None" label as intended.packages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsx (1)
114-124: LGTM - Dialog structure and accessibility.The composed dialog structure (
Dialog→DialogBackdrop→DialogPositioner→DialogContent→DialogHeader/DialogBody) follows the Ark UI composition pattern correctly. Thearia-label='Close'on theDialogCloseTrigger(line 121) addresses the accessibility concern from the previous review.packages/web/src/components/ui/button.tsx (1)
56-66: LGTM! Previous concern addressed.The
type='button'default (line 61) prevents accidental form submissions while still allowing callers to override via props. ThesplitPropspattern correctly maintains SolidJS reactivity without destructuring props.
🧹 Nitpick comments (1)
packages/web/src/components/dashboard/ProjectsSection.jsx (1)
79-167: Consider clearing pendingDeleteId when the dialog closes.This avoids stale state if the dialog is dismissed via backdrop or escape.
Proposed fix
- <AlertDialog open={deleteDialogOpen()} onOpenChange={setDeleteDialogOpen}> + <AlertDialog + open={deleteDialogOpen()} + onOpenChange={open => { + setDeleteDialogOpen(open); + if (!open) setPendingDeleteId(null); + }} + >Also applies to: 248-274
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
packages/web/src/components/auth/RoleSelector.jsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/mocks/ProjectViewV2.jsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/ui/alert-dialog.tsxpackages/web/src/components/ui/button.tsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/global.css
🧰 Additional context used
📓 Path-based instructions (17)
packages/web/src/**/*.{js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/form-state.mdc)
packages/web/src/**/*.{js,jsx}: Save form state to IndexedDB before initiating OAuth redirects (Google Drive, ORCID) using saveFormState() with form type ('createProject' or 'addStudies') and serializable state only
Only save serializable data to IndexedDB—exclude File objects, ArrayBuffers, functions, and other non-serializable objects from form state persistence
Restore form state after OAuth redirects by checking URL restore params with getRestoreParamsFromUrl(), retrieving saved state with getFormState(), restoring to form, clearing saved state with clearFormState(), and clearing URL params with clearRestoreParamsFromUrl()
For temporary File object storage during OAuth flows (e.g., pending PDFs), use projectStore.setPendingProjectData() instead of IndexedDB, as File objects cannot be serialized
Add restore parameters to the URL after OAuth redirects in the format '?restore=&projectId=' to signal form state restoration on mount
Clear URL restore parameters after form state restoration by calling clearRestoreParamsFromUrl() to prevent stale restoration attempts on subsequent navigation
Form state persistence library functions (saveFormState, getFormState, clearFormState, getRestoreParamsFromUrl, clearRestoreParamsFromUrl) are implemented in packages/web/src/lib/formStatePersistence.js and should be imported from@/lib/formStatePersistence.js
Files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/auth/RoleSelector.jsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx
packages/web/src/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)
packages/web/src/**/*.{js,jsx,ts,tsx}: Always useuploadPdffrom@api/pdf-api.jsfor uploading PDF files. Pass object with projectId, studyId, tag ('primary' or 'supplementary'), and fileName
Validate PDF files on frontend by checking file.type includes 'pdf' and file.size is within MAX_PDF_SIZE limit (full validation is done on backend)
UsecachePdfandgetCachedPdffrom@primitives/pdfCache.jsfor caching PDF data in IndexedDB
Implement PDF caching strategy: check cache first, download from server if not cached, then cache the downloaded PDF
Store only PDF metadata in Yjs (id, name, size, tag, uploadedAt, uploadedBy), never store PDF binary data in Yjs as it is too large
UseimportFromGoogleDrivefrom@api/google-drive.jsfor importing PDFs from Google Drive. Pass fileId, projectId, studyId, and tag
Save form state usingsaveFormStatefrom@/lib/formStatePersistence.jsbefore triggering OAuth redirects for Google Drive
UseaddPdfToStudyoperation fromuseProjecthook to add PDFs to a study, passing id, name, size, tag, uploadedAt, and uploadedBy
UseremovePdfFromStudyoperation fromuseProjecthook to remove PDFs from a study
UsepdfPreviewStorefrom@/stores/pdfPreviewStore.jsfor managing PDF preview state (openPreview, closePreview, getPreview methods)
UsedownloadPdffrom@api/pdf-api.jsto download PDFs from server, then cache the result usingcachePdf
Always cache PDFs after download and check cache before downloading to avoid redundant downloads
Use PDF operations fromuseProjecthook instead of bypassing through direct API calls
Files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/ui/button.tsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/auth/RoleSelector.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsxpackages/web/src/components/ui/alert-dialog.tsx
packages/web/src/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)
Use
PdfViewercomponent from@/components/checklist-ui/pdf/PdfViewer.jsxfor displaying PDFs, passing pdfData as ArrayBuffer, fileName, readOnly, and onPageChange
Files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/ui/button.tsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/auth/RoleSelector.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsxpackages/web/src/components/ui/alert-dialog.tsx
{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)
{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}: NEVER destructure props in SolidJS components - access props directly or wrap in functions to maintain reactivity
Use external stores in packages/web/src/stores/ for shared/cross-feature state instead of prop-drilling
Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities
Create reusable logic in primitives (hooks) in packages/web/src/primitives/ and import them into components
Use Solid's Show component for conditional rendering instead of ternary operators
Use Solid's For component for rendering lists instead of Array.map()
Use the children helper when manipulating props.children in SolidJS componentsUse Show and For components for conditional and list rendering in SolidJS
Files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/ui/button.tsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/auth/RoleSelector.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsxpackages/web/src/components/ui/alert-dialog.tsx
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}: Use createSignal for simple reactive values in SolidJS components
Use createStore for complex objects and arrays that need granular reactivity in SolidJS
Use createMemo for computed/derived values that depend on reactive state in SolidJS
Always clean up SolidJS effects that create subscriptions or timers using onCleanup
Import stores directly in components and use store read/write action pattern - read from store, write via actions store
Prefer derived state with createMemo or signals over effects whenever possible
Use local createSignal or createStore for local component state; use external stores for shared/cross-feature state
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}: NEVER destructure props in SolidJS components - it breaks reactivity. Access props directly (e.g., props.name) or wrap in a function (e.g., () => props.name)
Store imports should access store data directly from external stores (packages/web/src/stores/) rather than receiving store data via props
Use createSignal for simple, reactive values in SolidJS
Use createStore for complex objects and nested state in SolidJS, with nested updates using setState pattern (e.g., setState('items', items => [...items, newItem]))
Use createMemo for derived/computed values in SolidJS to maintain reactivity
Use local createSignal or createStore for local component state
Components should receive at most 1-5 props for local configuration only
Move business logic to stores, utilities, or SolidJS primitives rather than keeping it in component code
Files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/ui/button.tsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/auth/RoleSelector.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsxpackages/web/src/components/ui/alert-dialog.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/yjs-sync.mdc)
**/*.{js,jsx,ts,tsx}: Use theuseProjecthook for managing Yjs connections with reference counting instead of creating Y.Doc instances directly
Never create Y.Doc instances directly; always use the connection registry managed by useProject
Access Y.Doc connection state via projectStore.getConnectionState(projectId) instead of checking connection state directly
Read Yjs-synced data from projectStore (using getStudies, getChecklist, etc.) rather than accessing Y.Doc maps/arrays directly
Use operation functions from useProject or projectActionsStore for writing data instead of directly modifying Y.Doc
Don't store Y.Doc references in component state; always retrieve the connection through useProject
Handle connection cleanup via onCleanup() in Solid.js components or equivalent cleanup patterns, calling disconnect() when the component unmounts
Files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/ui/button.tsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/auth/RoleSelector.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsxpackages/web/src/components/ui/alert-dialog.tsx
packages/web/src/**
📄 CodeRabbit inference engine (.cursor/rules/organizations.mdc)
packages/web/src/**: Use human-readable slug in frontend URLs: /orgs/:orgSlug/...
Use orgId (UUID) for API calls, not orgSlug, when making fetch requests to backend endpoints
Files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/ui/button.tsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/auth/RoleSelector.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsxpackages/web/src/global.csspackages/web/src/components/ui/alert-dialog.tsx
packages/web/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
packages/web/**/*.{js,ts,jsx,tsx}: UseapiFetchfor all frontend API calls instead of raw fetch to automatically handle JSON parsing, errors, and toast notifications
UsehandleFetchErrorfor wrapping legacy raw fetch calls in frontend code (legacy pattern, prefer apiFetch)
Use error utility functions likeisErrorCodefrom error-utils to check specific error types instead of direct string comparisons
Files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/ui/button.tsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/auth/RoleSelector.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsxpackages/web/src/components/ui/alert-dialog.tsx
packages/web/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
Use
createFormErrorSignalsfor form error handling in frontend forms to manage field-level and global error states
Files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/ui/button.tsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/auth/RoleSelector.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsxpackages/web/src/components/ui/alert-dialog.tsx
packages/{web,workers}/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
Never throw string literals; always throw Error objects or return domain errors from API routes
Files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/ui/button.tsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/auth/RoleSelector.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsxpackages/web/src/components/ui/alert-dialog.tsx
{packages/web/src/stores/**/*.{js,jsx,ts,tsx},packages/web/src/**/*.{js,jsx,ts,tsx}}
📄 CodeRabbit inference engine (.github/instructions/solidjs.instructions.md)
Shared or cross-feature state should use external stores located in packages/web/src/stores/
Files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/ui/button.tsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/auth/RoleSelector.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsxpackages/web/src/components/ui/alert-dialog.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
**/*.{js,ts,jsx,tsx}: Prefer modern ES6+ syntax and features
Comments should explain why something is being done, not what the code is doing
Reserve comments for explaining intent, context, workarounds, assumptions, edge cases, or limitations
Use TODO(agent): prefix for incomplete work or flagged items with brief description and relevant doc references
Files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/ui/button.tsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/auth/RoleSelector.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsxpackages/web/src/components/ui/alert-dialog.tsx
**/*
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Never use emojis or unicode symbols anywhere in code, comments, documentation, plan files, commit messages, or examples
Files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/ui/button.tsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/auth/RoleSelector.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsxpackages/web/src/global.csspackages/web/src/components/ui/alert-dialog.tsx
packages/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/**/*.{ts,tsx,js,jsx}: Prefer modern ES6+ syntax and features
Prefer config files over hardcoding values
Keep files small, focused, and modular - extract large files into sub-modules or separate utilities
Each file should handle one coherent responsibility
Comments should explain WHY something is being done or provide context, not repeat what the code is saying
Do NOT narrate what code is doing, don't duplicate function/variable names in comments, and don't leave stale comments that contradict the code
Use the Agent TODO convention// TODO(agent): Brief descriptionfor incomplete work, flagging items for future attention, known limitations, and documentation section referencesUse TODO(agent) convention with brief description and relevant doc section references for incomplete work or flagged issues
Files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/ui/button.tsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/auth/RoleSelector.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsxpackages/web/src/components/ui/alert-dialog.tsx
packages/web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
packages/web/src/**/*.{ts,tsx}: For UI icons, usesolid-iconslibrary or SVGs only (never emojis)
Use import aliases from jsconfig.json as defined for the project
Use Ark UI component library (@ark-ui/solid) for UI components
Usesolid-iconslibrary for icons (e.g.,solid-icons/bi,solid-icons/fi)
Do not prop-drill application state in SolidJS components; import stores directly where needed
Do not destructure props in SolidJS; accessprops.fielddirectly or wrap in a function:() => props.field
Components should receive at most 1-5 props (local config only, not shared state)
UsecreateMemofor derived values in SolidJS
Frontend uses orgSlug in URLs (/orgs/:orgSlug/...) for readability
Never destructure SolidJS props as it breaks reactivity
Never prop-drill shared state; import stores directlyUse import aliases from jsconfig.json as defined in the project configuration
packages/web/src/**/*.{ts,tsx}: Import stores directly and never prop-drill application state in SolidJS components
Never destructure SolidJS props - useprops.fieldor() => props.fieldto preserve reactivity
Files:
packages/web/src/components/ui/button.tsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/ui/alert-dialog.tsx
packages/web/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
Group related components in subdirectories with barrel exports
Files:
packages/web/src/components/ui/button.tsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/ui/alert-dialog.tsx
packages/{web,landing}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/{web,landing}/src/**/*.{ts,tsx}: For UI icons, usesolid-iconslibrary (e.g.,solid-icons/bi,solid-icons/fi) or SVGs only, never emojis
Ensure browser compatibility, with particular attention to Safari
Group related components in subdirectories with barrel exports
Use Ark UI components from@ark-ui/solidfor UI components
Usesolid-iconsicon library for all icon needs
Do NOT prop-drill application state in SolidJS - import stores directly where needed
Do NOT destructure SolidJS props - accessprops.fielddirectly or wrap in function:() => props.field
SolidJS components should receive at most 1-5 props (local config only, not shared state)
UsecreateStorefor complex state objects in SolidJS
UsecreateMemofor derived values in SolidJS
Move business logic to stores, utilities, or primitives - not components
Never destructure SolidJS props as it breaks reactivity
Never prop-drill shared state - import stores directly
Files:
packages/web/src/components/ui/button.tsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/ui/alert-dialog.tsx
🧠 Learnings (55)
📓 Common learnings
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Use Ark UI component library (`ark-ui/solid`) for UI components
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use Ark UI components from `ark-ui/solid` for UI components
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-17T16:10:07.519Z
Learning: Use required libraries for specific functionality: Zod for validation, Drizzle for database, Better-Auth for authentication, Ark UI for components
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Create reusable logic in primitives (hooks) in packages/web/src/primitives/ and import them into components
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js,packages/web/src/primitives/useProject/checklists.js : Use checklist operations from useProject hook (createChecklist, updateChecklistAnswer, getChecklistData) instead of manually updating checklist structure
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js,packages/web/src/primitives/useProject/checklists.js : Use checklist operations from useProject hook (createChecklist, updateChecklistAnswer, getChecklistData) instead of manually updating checklist structure
Applied to files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js : Use getChecklistStatus utility from `@/lib/checklist-domain.js` to determine current checklist status before performing operations
Applied to files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js : Checklist status transitions follow sequence: in_progress → completed (when all questions answered) → reconciled (after reconciliation complete)
Applied to files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to packages/web/src/components/checklist-ui/compare/** : Use Y.Text objects for collaborative editing of question notes in reconciliation
Applied to files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/AMSTAR2/checklist-compare.js} : Use compareChecklists utility from checklist-compare.js for comparing reviewer checklists
Applied to files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/lib/checklist-domain.js,packages/web/src/AMSTAR2/checklist-compare.js} : Store final answers in the reconciled checklist itself, not in reconciliation progress metadata
Applied to files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/primitives/useProject/checklists.js : Store question notes as Y.Text objects obtained from useProject hook via getQuestionNote operation to enable collaborative editing
Applied to files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/ui/checkbox.tsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/ROBINS-I/** : Use scoreChecklist utility from `@/ROBINS-I/checklist.js` to determine risk of bias rating: 'Low' | 'Moderate' | 'Serious' | 'Critical'
Applied to files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/ROBINS-I/** : Use shouldStopAssessment utility from `@/ROBINS-I/checklist.js` to check if Section B indicates critical risk of bias requiring assessment termination
Applied to files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/lib/checklist-domain.js,packages/web/src/AMSTAR2/checklist-compare.js} : Reconciliation structure should contain checklist1Id, checklist2Id, and reconciledChecklistId
Applied to files:
packages/web/src/components/sidebar/Sidebar.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use local createSignal or createStore for local component state; use external stores for shared/cross-feature state
Applied to files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/dashboard/ProjectsSection.jsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use `solid-icons` icon library for all icon needs
Applied to files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use `createStore` for complex state objects in SolidJS
Applied to files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/dashboard/ProjectsSection.jsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : For UI icons, use `solid-icons` library (e.g., `solid-icons/bi`, `solid-icons/fi`) or SVGs only, never emojis
Applied to files:
packages/web/src/components/sidebar/Sidebar.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use Solid's Show component for conditional rendering instead of ternary operators
Applied to files:
packages/web/src/components/sidebar/Sidebar.jsxpackages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/ui/alert-dialog.tsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/** : Use scoreChecklist utility from `@/AMSTAR2/checklist.js` to determine quality assessment rating: 'High' | 'Moderate' | 'Low' | 'Critically Low'
Applied to files:
packages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/** : Use NoteEditor component from `@/components/checklist-ui/common/NoteEditor.jsx` for question note editing with max 2000 character limit
Applied to files:
packages/web/src/components/checklist/ScoreTag.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/lib/checklist-domain.js : Register and retrieve checklists using checklist-registry: getChecklistType and getChecklistComponent functions
Applied to files:
packages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx
📚 Learning: 2026-01-17T00:25:12.507Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.507Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use Show and For components for conditional and list rendering in SolidJS
Applied to files:
packages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use `createMemo` for derived values in SolidJS
Applied to files:
packages/web/src/components/checklist/ScoreTag.jsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use Ark UI components from `ark-ui/solid` for UI components
Applied to files:
packages/web/src/components/ui/button.tsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/global.csspackages/web/src/components/ui/alert-dialog.tsx
📚 Learning: 2026-01-17T00:25:35.702Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Use Ark UI component library (`ark-ui/solid`) for UI components
Applied to files:
packages/web/src/components/ui/button.tsxpackages/web/src/components/ui/checkbox.tsxpackages/web/src/global.csspackages/web/src/components/ui/alert-dialog.tsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities
Applied to files:
packages/web/src/components/ui/button.tsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Do NOT destructure SolidJS props - access `props.field` directly or wrap in function: `() => props.field`
Applied to files:
packages/web/src/components/ui/button.tsx
📚 Learning: 2026-01-17T00:25:35.702Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Do not prop-drill application state in SolidJS components; import stores directly where needed
Applied to files:
packages/web/src/components/ui/button.tsx
📚 Learning: 2026-01-17T00:25:35.702Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Do not destructure props in SolidJS; access `props.field` directly or wrap in a function: `() => props.field`
Applied to files:
packages/web/src/components/ui/button.tsx
📚 Learning: 2026-01-17T00:25:35.702Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Use `solid-icons` library for icons (e.g., `solid-icons/bi`, `solid-icons/fi`)
Applied to files:
packages/web/src/components/ui/button.tsxpackages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsx
📚 Learning: 2026-01-17T16:10:07.519Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-17T16:10:07.519Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Never destructure SolidJS props - use `props.field` or `() => props.field` to preserve reactivity
Applied to files:
packages/web/src/components/ui/button.tsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : SolidJS components should receive at most 1-5 props (local config only, not shared state)
Applied to files:
packages/web/src/components/ui/button.tsxpackages/web/src/components/ui/alert-dialog.tsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Never destructure SolidJS props as it breaks reactivity
Applied to files:
packages/web/src/components/ui/button.tsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createSignal for simple reactive values in SolidJS components
Applied to files:
packages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsxpackages/web/src/components/ui/alert-dialog.tsx
📚 Learning: 2026-01-17T00:25:12.507Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.507Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createSignal for simple, reactive values in SolidJS
Applied to files:
packages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsxpackages/web/src/components/dashboard/ProjectsSection.jsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx
📚 Learning: 2025-12-27T03:01:54.727Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/form-state.mdc:0-0
Timestamp: 2025-12-27T03:01:54.727Z
Learning: Applies to packages/web/src/components/project-ui/**/*.{js,jsx} : Form state should include serializable metadata when handling files (name, size, type) and use the store's pendingPdfs pattern for actual File objects that persist across redirects
Applied to files:
packages/web/src/components/dashboard/ProjectsSection.jsx
📚 Learning: 2025-12-27T03:01:54.727Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/form-state.mdc:0-0
Timestamp: 2025-12-27T03:01:54.727Z
Learning: Applies to packages/web/src/**/*.{js,jsx} : Save form state to IndexedDB before initiating OAuth redirects (Google Drive, ORCID) using saveFormState() with form type ('createProject' or 'addStudies') and serializable state only
Applied to files:
packages/web/src/components/dashboard/ProjectsSection.jsx
📚 Learning: 2026-01-06T23:56:57.354Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/error-handling.mdc:0-0
Timestamp: 2026-01-06T23:56:57.354Z
Learning: Applies to packages/web/**/*.{jsx,tsx} : Use `createFormErrorSignals` for form error handling in frontend forms to manage field-level and global error states
Applied to files:
packages/web/src/components/dashboard/ProjectsSection.jsx
📚 Learning: 2026-01-17T00:25:12.507Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.507Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use local createSignal or createStore for local component state
Applied to files:
packages/web/src/components/dashboard/ProjectsSection.jsx
📚 Learning: 2026-01-17T00:25:12.507Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.507Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createStore for complex objects and nested state in SolidJS, with nested updates using setState pattern (e.g., setState('items', items => [...items, newItem]))
Applied to files:
packages/web/src/components/dashboard/ProjectsSection.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createStore for complex objects and arrays that need granular reactivity in SolidJS
Applied to files:
packages/web/src/components/dashboard/ProjectsSection.jsx
📚 Learning: 2025-12-27T03:02:50.087Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/yjs-sync.mdc:0-0
Timestamp: 2025-12-27T03:02:50.087Z
Learning: Applies to packages/web/src/primitives/useProject/**, packages/web/src/stores/projectStore.js : When access is denied (user removed or project deleted), the connection automatically triggers cleanup: IndexedDB data cleared, connection closed, store cleared, and user redirected
Applied to files:
packages/web/src/components/dashboard/ProjectsSection.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createMemo for computed/derived values that depend on reactive state in SolidJS
Applied to files:
packages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsxpackages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx
📚 Learning: 2026-01-17T00:25:12.507Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.507Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createMemo for derived/computed values in SolidJS to maintain reactivity
Applied to files:
packages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use Solid's For component for rendering lists instead of Array.map()
Applied to files:
packages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsx
📚 Learning: 2026-01-17T00:25:35.702Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Use `createMemo` for derived values in SolidJS
Applied to files:
packages/web/src/components/project/reconcile-tab/rob2-reconcile/ROB2Navbar.jsx
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{jsx,tsx} : Use `PdfViewer` component from `@/components/checklist-ui/pdf/PdfViewer.jsx` for displaying PDFs, passing pdfData as ArrayBuffer, fileName, readOnly, and onPageChange
Applied to files:
packages/web/src/components/ui/checkbox.tsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/** : AMSTAR2 answers must use matrix format: array of column arrays with boolean values representing checkbox selections per column
Applied to files:
packages/web/src/components/ui/checkbox.tsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js : Maintain separate answer format implementations for each checklist type (AMSTAR2, ROBINS-I, Generic) to prevent data corruption
Applied to files:
packages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/**/*.{ts,tsx,js,jsx} : Do NOT narrate what code is doing, don't duplicate function/variable names in comments, and don't leave stale comments that contradict the code
Applied to files:
packages/web/src/global.css
📚 Learning: 2026-01-17T00:25:35.702Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to **/*.{js,ts,jsx,tsx} : Reserve comments for explaining intent, context, workarounds, assumptions, edge cases, or limitations
Applied to files:
packages/web/src/global.css
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/**/*.{ts,tsx,js,jsx} : Comments should explain WHY something is being done or provide context, not repeat what the code is saying
Applied to files:
packages/web/src/global.css
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/**/*.{ts,tsx,js,jsx} : Use the Agent TODO convention `// TODO(agent): Brief description` for incomplete work, flagging items for future attention, known limitations, and documentation section references
Applied to files:
packages/web/src/global.css
📚 Learning: 2026-01-17T16:10:07.519Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-17T16:10:07.519Z
Learning: Applies to packages/**/*.{ts,tsx,js,jsx} : Use TODO(agent) convention with brief description and relevant doc section references for incomplete work or flagged issues
Applied to files:
packages/web/src/global.css
📚 Learning: 2026-01-17T00:25:35.702Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to **/*.{js,ts,jsx,tsx} : Comments should explain why something is being done, not what the code is doing
Applied to files:
packages/web/src/global.css
📚 Learning: 2026-01-17T00:25:35.702Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to **/*.{js,ts,jsx,tsx} : Use TODO(agent): prefix for incomplete work or flagged items with brief description and relevant doc references
Applied to files:
packages/web/src/global.css
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Ensure browser compatibility, with particular attention to Safari
Applied to files:
packages/web/src/global.css
🧬 Code graph analysis (5)
packages/web/src/components/ui/button.tsx (1)
packages/web/src/components/ui/cn.ts (1)
cn(13-15)
packages/web/src/components/dashboard/ProjectsSection.jsx (4)
packages/web/src/components/dashboard/LocalAppraisalsSection.jsx (2)
deleteDialogOpen(97-97)pendingDeleteId(98-98)packages/web/src/components/dashboard/Dashboard.jsx (1)
canCreateProject(45-51)packages/web/src/components/project/ContactPrompt.jsx (1)
ContactPrompt(8-52)packages/web/src/components/ui/alert-dialog.tsx (11)
AlertDialog(270-270)AlertDialogBackdrop(271-271)AlertDialogPositioner(272-272)AlertDialogContent(273-273)AlertDialogHeader(274-274)AlertDialogIcon(275-275)AlertDialogTitle(276-276)AlertDialogDescription(277-277)AlertDialogFooter(278-278)AlertDialogCancel(279-279)AlertDialogAction(280-280)
packages/web/src/components/ui/checkbox.tsx (2)
packages/ui/src/components/index.ts (1)
CheckboxPrimitive(7-7)packages/web/src/components/ui/cn.ts (1)
cn(13-15)
packages/web/src/components/checklist/ROB2Checklist/ScoringSummary.jsx (3)
packages/web/src/components/ui/dialog.tsx (6)
Dialog(198-198)DialogBackdrop(200-200)DialogPositioner(201-201)DialogContent(202-202)DialogTitle(203-203)DialogDescription(204-204)packages/web/src/components/admin/GrantDialog.jsx (1)
open(35-35)packages/web/src/components/admin/SubscriptionDialog.jsx (1)
open(48-48)
packages/web/src/components/ui/alert-dialog.tsx (3)
packages/ui/src/components/index.ts (1)
DialogPrimitive(11-11)packages/web/src/components/ui/cn.ts (1)
cn(13-15)packages/web/src/components/ui/z-index.ts (1)
Z_INDEX(15-47)
⏰ 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: Workers Builds: corates
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| <CheckboxPrimitive.Control | ||
| class={cn( | ||
| 'flex h-4 w-4 shrink-0 items-center justify-center rounded border border-gray-300', | ||
| 'ring-offset-white transition-colors', | ||
| 'focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 focus-visible:outline-none', | ||
| 'disabled:cursor-not-allowed disabled:opacity-50', | ||
| 'data-[state=checked]:border-blue-600 data-[state=checked]:bg-blue-600 data-[state=checked]:text-white', | ||
| 'data-[state=indeterminate]:border-blue-600 data-[state=indeterminate]:bg-blue-600 data-[state=indeterminate]:text-white', | ||
| local.class, | ||
| )} | ||
| {...others} |
There was a problem hiding this comment.
disabled: pseudo-class won't work on Ark UI's Control wrapper.
The :disabled CSS pseudo-class only applies to native form elements. Since CheckboxPrimitive.Control renders a wrapper element (not an input), the disabled: utility classes won't take effect. Use Ark UI's data attribute pattern for consistency with the state styling on lines 77-78.
Suggested fix
class={cn(
'flex h-4 w-4 shrink-0 items-center justify-center rounded border border-gray-300',
'ring-offset-white transition-colors',
'focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 focus-visible:outline-none',
- 'disabled:cursor-not-allowed disabled:opacity-50',
+ 'data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50',
'data-[state=checked]:border-blue-600 data-[state=checked]:bg-blue-600 data-[state=checked]:text-white',
'data-[state=indeterminate]:border-blue-600 data-[state=indeterminate]:bg-blue-600 data-[state=indeterminate]:text-white',
local.class,
)}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <CheckboxPrimitive.Control | |
| class={cn( | |
| 'flex h-4 w-4 shrink-0 items-center justify-center rounded border border-gray-300', | |
| 'ring-offset-white transition-colors', | |
| 'focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 focus-visible:outline-none', | |
| 'disabled:cursor-not-allowed disabled:opacity-50', | |
| 'data-[state=checked]:border-blue-600 data-[state=checked]:bg-blue-600 data-[state=checked]:text-white', | |
| 'data-[state=indeterminate]:border-blue-600 data-[state=indeterminate]:bg-blue-600 data-[state=indeterminate]:text-white', | |
| local.class, | |
| )} | |
| {...others} | |
| <CheckboxPrimitive.Control | |
| class={cn( | |
| 'flex h-4 w-4 shrink-0 items-center justify-center rounded border border-gray-300', | |
| 'ring-offset-white transition-colors', | |
| 'focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 focus-visible:outline-none', | |
| 'data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50', | |
| 'data-[state=checked]:border-blue-600 data-[state=checked]:bg-blue-600 data-[state=checked]:text-white', | |
| 'data-[state=indeterminate]:border-blue-600 data-[state=indeterminate]:bg-blue-600 data-[state=indeterminate]:text-white', | |
| local.class, | |
| )} | |
| {...others} |
🤖 Prompt for AI Agents
In `@packages/web/src/components/ui/checkbox.tsx` around lines 71 - 81, The
disabled styles on CheckboxPrimitive.Control use the native CSS pseudo-class
("disabled:cursor-not-allowed disabled:opacity-50") which won't apply because
Control renders a wrapper element; change those to Ark UI's data-attribute
pattern to mirror the existing state styling (e.g. replace
"disabled:cursor-not-allowed disabled:opacity-50" with
"data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50" in the class
list for CheckboxPrimitive.Control so the wrapper responds to the component's
disabled state).
| <CheckboxPrimitive.Label | ||
| class={cn( | ||
| 'text-sm leading-none font-medium text-gray-900', | ||
| 'data-disabled:cursor-not-allowed data-disabled:opacity-70', | ||
| local.class, | ||
| )} | ||
| {...others} | ||
| /> | ||
| ); |
There was a problem hiding this comment.
Incorrect Tailwind data attribute syntax - disabled styling won't apply.
data-disabled: is invalid Tailwind syntax. The correct arbitrary data attribute syntax requires brackets: data-[disabled]:. The disabled styling is currently non-functional.
Suggested fix
<CheckboxPrimitive.Label
class={cn(
'text-sm leading-none font-medium text-gray-900',
- 'data-disabled:cursor-not-allowed data-disabled:opacity-70',
+ 'data-[disabled]:cursor-not-allowed data-[disabled]:opacity-70',
local.class,
)}
{...others}
/>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <CheckboxPrimitive.Label | |
| class={cn( | |
| 'text-sm leading-none font-medium text-gray-900', | |
| 'data-disabled:cursor-not-allowed data-disabled:opacity-70', | |
| local.class, | |
| )} | |
| {...others} | |
| /> | |
| ); | |
| <CheckboxPrimitive.Label | |
| class={cn( | |
| 'text-sm leading-none font-medium text-gray-900', | |
| 'data-[disabled]:cursor-not-allowed data-[disabled]:opacity-70', | |
| local.class, | |
| )} | |
| {...others} | |
| /> | |
| ); |
🤖 Prompt for AI Agents
In `@packages/web/src/components/ui/checkbox.tsx` around lines 100 - 108, The
Tailwind data attribute syntax used on CheckboxPrimitive.Label is
incorrect—replace the invalid `data-disabled:` usages with the proper arbitrary
attribute form `data-[disabled]:` so the disabled styles apply; update the class
construction in the CheckboxPrimitive.Label render (where cn is called with
'text-sm leading-none font-medium text-gray-900',
'data-disabled:cursor-not-allowed data-disabled:opacity-70', local.class, and
{...others}) to use 'data-[disabled]:cursor-not-allowed' and
'data-[disabled]:opacity-70' instead.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/web/src/components/ui/avatar.tsx`:
- Around line 87-92: The getInitials function can throw when name is
whitespace-only or contains empty segments; update getInitials to trim and split
then filter out empty parts (e.g., parts = name.trim().split('
').filter(Boolean)), return '' if parts.length === 0, and use safe access
(optional chaining or default '') when reading parts[0][0] and
parts[parts.length-1][0] so single-part and multi-part names both handle empty
strings without throwing; reference function name getInitials and the parts
variable when making the change.
🧹 Nitpick comments (2)
packages/web/src/components/admin/UserTable.jsx (1)
109-114: Consider removing redundanttitleattribute.The
titleattribute on the<img>element (line 112) is redundant since the tooltip already provides hover text viaTooltipContent. Having both can cause visual overlap on hover.Proposed fix
<img src={providerInfo?.icon} alt={providerInfo?.name || provider} - title={providerInfo?.name || provider} class='h-4 w-4' />packages/web/src/components/project/overview-tab/OverviewTab.jsx (1)
174-197: Consider resettingpendingRemoveMemberafter successful removal.The dialog closes on success, but
pendingRemoveMemberretains stale data. While not functionally problematic, resetting it maintains cleaner state hygiene.Suggested change
setRemoveDialogOpen(false); + setPendingRemoveMember(null); } catch (err) {
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
packages/web/src/components/Navbar.jsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/admin/UserDetail.jsxpackages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/AddMemberModal.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/ui/avatar.tsx
🧰 Additional context used
📓 Path-based instructions (17)
packages/web/src/**/*.{js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/form-state.mdc)
packages/web/src/**/*.{js,jsx}: Save form state to IndexedDB before initiating OAuth redirects (Google Drive, ORCID) using saveFormState() with form type ('createProject' or 'addStudies') and serializable state only
Only save serializable data to IndexedDB—exclude File objects, ArrayBuffers, functions, and other non-serializable objects from form state persistence
Restore form state after OAuth redirects by checking URL restore params with getRestoreParamsFromUrl(), retrieving saved state with getFormState(), restoring to form, clearing saved state with clearFormState(), and clearing URL params with clearRestoreParamsFromUrl()
For temporary File object storage during OAuth flows (e.g., pending PDFs), use projectStore.setPendingProjectData() instead of IndexedDB, as File objects cannot be serialized
Add restore parameters to the URL after OAuth redirects in the format '?restore=&projectId=' to signal form state restoration on mount
Clear URL restore parameters after form state restoration by calling clearRestoreParamsFromUrl() to prevent stale restoration attempts on subsequent navigation
Form state persistence library functions (saveFormState, getFormState, clearFormState, getRestoreParamsFromUrl, clearRestoreParamsFromUrl) are implemented in packages/web/src/lib/formStatePersistence.js and should be imported from@/lib/formStatePersistence.js
Files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/project/overview-tab/AddMemberModal.jsxpackages/web/src/components/Navbar.jsxpackages/web/src/components/admin/UserDetail.jsx
packages/web/src/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)
packages/web/src/**/*.{js,jsx,ts,tsx}: Always useuploadPdffrom@api/pdf-api.jsfor uploading PDF files. Pass object with projectId, studyId, tag ('primary' or 'supplementary'), and fileName
Validate PDF files on frontend by checking file.type includes 'pdf' and file.size is within MAX_PDF_SIZE limit (full validation is done on backend)
UsecachePdfandgetCachedPdffrom@primitives/pdfCache.jsfor caching PDF data in IndexedDB
Implement PDF caching strategy: check cache first, download from server if not cached, then cache the downloaded PDF
Store only PDF metadata in Yjs (id, name, size, tag, uploadedAt, uploadedBy), never store PDF binary data in Yjs as it is too large
UseimportFromGoogleDrivefrom@api/google-drive.jsfor importing PDFs from Google Drive. Pass fileId, projectId, studyId, and tag
Save form state usingsaveFormStatefrom@/lib/formStatePersistence.jsbefore triggering OAuth redirects for Google Drive
UseaddPdfToStudyoperation fromuseProjecthook to add PDFs to a study, passing id, name, size, tag, uploadedAt, and uploadedBy
UseremovePdfFromStudyoperation fromuseProjecthook to remove PDFs from a study
UsepdfPreviewStorefrom@/stores/pdfPreviewStore.jsfor managing PDF preview state (openPreview, closePreview, getPreview methods)
UsedownloadPdffrom@api/pdf-api.jsto download PDFs from server, then cache the result usingcachePdf
Always cache PDFs after download and check cache before downloading to avoid redundant downloads
Use PDF operations fromuseProjecthook instead of bypassing through direct API calls
Files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/ui/avatar.tsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/project/overview-tab/AddMemberModal.jsxpackages/web/src/components/Navbar.jsxpackages/web/src/components/admin/UserDetail.jsx
packages/web/src/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)
Use
PdfViewercomponent from@/components/checklist-ui/pdf/PdfViewer.jsxfor displaying PDFs, passing pdfData as ArrayBuffer, fileName, readOnly, and onPageChange
Files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/ui/avatar.tsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/project/overview-tab/AddMemberModal.jsxpackages/web/src/components/Navbar.jsxpackages/web/src/components/admin/UserDetail.jsx
{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)
{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}: NEVER destructure props in SolidJS components - access props directly or wrap in functions to maintain reactivity
Use external stores in packages/web/src/stores/ for shared/cross-feature state instead of prop-drilling
Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities
Create reusable logic in primitives (hooks) in packages/web/src/primitives/ and import them into components
Use Solid's Show component for conditional rendering instead of ternary operators
Use Solid's For component for rendering lists instead of Array.map()
Use the children helper when manipulating props.children in SolidJS componentsUse Show and For components for conditional and list rendering in SolidJS
Files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/ui/avatar.tsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/project/overview-tab/AddMemberModal.jsxpackages/web/src/components/Navbar.jsxpackages/web/src/components/admin/UserDetail.jsx
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}: Use createSignal for simple reactive values in SolidJS components
Use createStore for complex objects and arrays that need granular reactivity in SolidJS
Use createMemo for computed/derived values that depend on reactive state in SolidJS
Always clean up SolidJS effects that create subscriptions or timers using onCleanup
Import stores directly in components and use store read/write action pattern - read from store, write via actions store
Prefer derived state with createMemo or signals over effects whenever possible
Use local createSignal or createStore for local component state; use external stores for shared/cross-feature state
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}: NEVER destructure props in SolidJS components - it breaks reactivity. Access props directly (e.g., props.name) or wrap in a function (e.g., () => props.name)
Store imports should access store data directly from external stores (packages/web/src/stores/) rather than receiving store data via props
Use createSignal for simple, reactive values in SolidJS
Use createStore for complex objects and nested state in SolidJS, with nested updates using setState pattern (e.g., setState('items', items => [...items, newItem]))
Use createMemo for derived/computed values in SolidJS to maintain reactivity
Use local createSignal or createStore for local component state
Components should receive at most 1-5 props for local configuration only
Move business logic to stores, utilities, or SolidJS primitives rather than keeping it in component code
Files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/ui/avatar.tsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/project/overview-tab/AddMemberModal.jsxpackages/web/src/components/Navbar.jsxpackages/web/src/components/admin/UserDetail.jsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/yjs-sync.mdc)
**/*.{js,jsx,ts,tsx}: Use theuseProjecthook for managing Yjs connections with reference counting instead of creating Y.Doc instances directly
Never create Y.Doc instances directly; always use the connection registry managed by useProject
Access Y.Doc connection state via projectStore.getConnectionState(projectId) instead of checking connection state directly
Read Yjs-synced data from projectStore (using getStudies, getChecklist, etc.) rather than accessing Y.Doc maps/arrays directly
Use operation functions from useProject or projectActionsStore for writing data instead of directly modifying Y.Doc
Don't store Y.Doc references in component state; always retrieve the connection through useProject
Handle connection cleanup via onCleanup() in Solid.js components or equivalent cleanup patterns, calling disconnect() when the component unmounts
Files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/ui/avatar.tsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/project/overview-tab/AddMemberModal.jsxpackages/web/src/components/Navbar.jsxpackages/web/src/components/admin/UserDetail.jsx
packages/web/src/**
📄 CodeRabbit inference engine (.cursor/rules/organizations.mdc)
packages/web/src/**: Use human-readable slug in frontend URLs: /orgs/:orgSlug/...
Use orgId (UUID) for API calls, not orgSlug, when making fetch requests to backend endpoints
Files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/ui/avatar.tsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/project/overview-tab/AddMemberModal.jsxpackages/web/src/components/Navbar.jsxpackages/web/src/components/admin/UserDetail.jsx
packages/web/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
packages/web/**/*.{js,ts,jsx,tsx}: UseapiFetchfor all frontend API calls instead of raw fetch to automatically handle JSON parsing, errors, and toast notifications
UsehandleFetchErrorfor wrapping legacy raw fetch calls in frontend code (legacy pattern, prefer apiFetch)
Use error utility functions likeisErrorCodefrom error-utils to check specific error types instead of direct string comparisons
Files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/ui/avatar.tsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/project/overview-tab/AddMemberModal.jsxpackages/web/src/components/Navbar.jsxpackages/web/src/components/admin/UserDetail.jsx
packages/web/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
Use
createFormErrorSignalsfor form error handling in frontend forms to manage field-level and global error states
Files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/ui/avatar.tsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/project/overview-tab/AddMemberModal.jsxpackages/web/src/components/Navbar.jsxpackages/web/src/components/admin/UserDetail.jsx
packages/{web,workers}/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
Never throw string literals; always throw Error objects or return domain errors from API routes
Files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/ui/avatar.tsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/project/overview-tab/AddMemberModal.jsxpackages/web/src/components/Navbar.jsxpackages/web/src/components/admin/UserDetail.jsx
{packages/web/src/stores/**/*.{js,jsx,ts,tsx},packages/web/src/**/*.{js,jsx,ts,tsx}}
📄 CodeRabbit inference engine (.github/instructions/solidjs.instructions.md)
Shared or cross-feature state should use external stores located in packages/web/src/stores/
Files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/ui/avatar.tsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/project/overview-tab/AddMemberModal.jsxpackages/web/src/components/Navbar.jsxpackages/web/src/components/admin/UserDetail.jsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
**/*.{js,ts,jsx,tsx}: Prefer modern ES6+ syntax and features
Comments should explain why something is being done, not what the code is doing
Reserve comments for explaining intent, context, workarounds, assumptions, edge cases, or limitations
Use TODO(agent): prefix for incomplete work or flagged items with brief description and relevant doc references
Files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/ui/avatar.tsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/project/overview-tab/AddMemberModal.jsxpackages/web/src/components/Navbar.jsxpackages/web/src/components/admin/UserDetail.jsx
**/*
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Never use emojis or unicode symbols anywhere in code, comments, documentation, plan files, commit messages, or examples
Files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/ui/avatar.tsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/project/overview-tab/AddMemberModal.jsxpackages/web/src/components/Navbar.jsxpackages/web/src/components/admin/UserDetail.jsx
packages/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/**/*.{ts,tsx,js,jsx}: Prefer modern ES6+ syntax and features
Prefer config files over hardcoding values
Keep files small, focused, and modular - extract large files into sub-modules or separate utilities
Each file should handle one coherent responsibility
Comments should explain WHY something is being done or provide context, not repeat what the code is saying
Do NOT narrate what code is doing, don't duplicate function/variable names in comments, and don't leave stale comments that contradict the code
Use the Agent TODO convention// TODO(agent): Brief descriptionfor incomplete work, flagging items for future attention, known limitations, and documentation section referencesUse TODO(agent) convention with brief description and relevant doc section references for incomplete work or flagged issues
Files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/ui/avatar.tsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/project/overview-tab/AddMemberModal.jsxpackages/web/src/components/Navbar.jsxpackages/web/src/components/admin/UserDetail.jsx
packages/web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
packages/web/src/**/*.{ts,tsx}: For UI icons, usesolid-iconslibrary or SVGs only (never emojis)
Use import aliases from jsconfig.json as defined for the project
Use Ark UI component library (@ark-ui/solid) for UI components
Usesolid-iconslibrary for icons (e.g.,solid-icons/bi,solid-icons/fi)
Do not prop-drill application state in SolidJS components; import stores directly where needed
Do not destructure props in SolidJS; accessprops.fielddirectly or wrap in a function:() => props.field
Components should receive at most 1-5 props (local config only, not shared state)
UsecreateMemofor derived values in SolidJS
Frontend uses orgSlug in URLs (/orgs/:orgSlug/...) for readability
Never destructure SolidJS props as it breaks reactivity
Never prop-drill shared state; import stores directlyUse import aliases from jsconfig.json as defined in the project configuration
packages/web/src/**/*.{ts,tsx}: Import stores directly and never prop-drill application state in SolidJS components
Never destructure SolidJS props - useprops.fieldor() => props.fieldto preserve reactivity
Files:
packages/web/src/components/ui/avatar.tsx
packages/web/src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
Group related components in subdirectories with barrel exports
Files:
packages/web/src/components/ui/avatar.tsx
packages/{web,landing}/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/{web,landing}/src/**/*.{ts,tsx}: For UI icons, usesolid-iconslibrary (e.g.,solid-icons/bi,solid-icons/fi) or SVGs only, never emojis
Ensure browser compatibility, with particular attention to Safari
Group related components in subdirectories with barrel exports
Use Ark UI components from@ark-ui/solidfor UI components
Usesolid-iconsicon library for all icon needs
Do NOT prop-drill application state in SolidJS - import stores directly where needed
Do NOT destructure SolidJS props - accessprops.fielddirectly or wrap in function:() => props.field
SolidJS components should receive at most 1-5 props (local config only, not shared state)
UsecreateStorefor complex state objects in SolidJS
UsecreateMemofor derived values in SolidJS
Move business logic to stores, utilities, or primitives - not components
Never destructure SolidJS props as it breaks reactivity
Never prop-drill shared state - import stores directly
Files:
packages/web/src/components/ui/avatar.tsx
🧠 Learnings (29)
📓 Common learnings
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Use Ark UI component library (`ark-ui/solid`) for UI components
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use Ark UI components from `ark-ui/solid` for UI components
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-17T16:10:07.519Z
Learning: Use required libraries for specific functionality: Zod for validation, Drizzle for database, Better-Auth for authentication, Ark UI for components
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Group related components in subdirectories with barrel exports
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to packages/web/src/components/**/*.{ts,tsx} : Group related components in subdirectories with barrel exports
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Create reusable logic in primitives (hooks) in packages/web/src/primitives/ and import them into components
📚 Learning: 2026-01-17T00:25:12.507Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.507Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use Show and For components for conditional and list rendering in SolidJS
Applied to files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use Solid's Show component for conditional rendering instead of ternary operators
Applied to files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use Ark UI components from `ark-ui/solid` for UI components
Applied to files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/ui/avatar.tsx
📚 Learning: 2026-01-17T00:25:35.702Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Use Ark UI component library (`ark-ui/solid`) for UI components
Applied to files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/ui/avatar.tsx
📚 Learning: 2026-01-17T00:25:35.702Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Use `solid-icons` library for icons (e.g., `solid-icons/bi`, `solid-icons/fi`)
Applied to files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/admin/UserDetail.jsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : For UI icons, use `solid-icons` library (e.g., `solid-icons/bi`, `solid-icons/fi`) or SVGs only, never emojis
Applied to files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/admin/UserDetail.jsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use `solid-icons` icon library for all icon needs
Applied to files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/admin/ProjectDetail.jsxpackages/web/src/components/admin/UserDetail.jsx
📚 Learning: 2026-01-17T00:25:35.702Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : For UI icons, use `solid-icons` library or SVGs only (never emojis)
Applied to files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/ui/avatar.tsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use Solid's For component for rendering lists instead of Array.map()
Applied to files:
packages/web/src/components/admin/UserTable.jsxpackages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities
Applied to files:
packages/web/src/components/admin/UserTable.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js,packages/web/src/primitives/useProject/checklists.js : Use checklist operations from useProject hook (createChecklist, updateChecklistAnswer, getChecklistData) instead of manually updating checklist structure
Applied to files:
packages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/admin/ProjectDetail.jsx
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to packages/web/src/components/checklist-ui/compare/** : Use Y.Text objects for collaborative editing of question notes in reconciliation
Applied to files:
packages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2026-01-17T00:25:12.507Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.507Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createSignal for simple, reactive values in SolidJS
Applied to files:
packages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createSignal for simple reactive values in SolidJS components
Applied to files:
packages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use `createMemo` for derived values in SolidJS
Applied to files:
packages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createMemo for computed/derived values that depend on reactive state in SolidJS
Applied to files:
packages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/AMSTAR2/**,packages/web/src/ROBINS-I/**,packages/web/src/lib/checklist-domain.js : Use getChecklistStatus utility from `@/lib/checklist-domain.js` to determine current checklist status before performing operations
Applied to files:
packages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2025-12-27T03:02:50.087Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/yjs-sync.mdc:0-0
Timestamp: 2025-12-27T03:02:50.087Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use operation functions from useProject or projectActionsStore for writing data instead of directly modifying Y.Doc
Applied to files:
packages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2025-12-27T03:01:06.933Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/checklist-operations.mdc:0-0
Timestamp: 2025-12-27T03:01:06.933Z
Learning: Applies to packages/web/src/components/checklist-ui/**,packages/web/src/primitives/useProject/checklists.js : Store question notes as Y.Text objects obtained from useProject hook via getQuestionNote operation to enable collaborative editing
Applied to files:
packages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use local createSignal or createStore for local component state; use external stores for shared/cross-feature state
Applied to files:
packages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Import stores directly in components and use store read/write action pattern - read from store, write via actions store
Applied to files:
packages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to {packages/web/src/components/checklist-ui/compare/**,packages/web/src/AMSTAR2/checklist-compare.js} : Use compareChecklists utility from checklist-compare.js for comparing reviewer checklists
Applied to files:
packages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2025-12-27T03:01:54.727Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/form-state.mdc:0-0
Timestamp: 2025-12-27T03:01:54.727Z
Learning: Applies to packages/web/src/components/project-ui/**/*.{js,jsx} : Form state should include serializable metadata when handling files (name, size, type) and use the store's pendingPdfs pattern for actual File objects that persist across redirects
Applied to files:
packages/web/src/components/project/overview-tab/OverviewTab.jsxpackages/web/src/components/admin/ProjectDetail.jsx
📚 Learning: 2026-01-01T23:32:23.488Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/workers.mdc:0-0
Timestamp: 2026-01-01T23:32:23.488Z
Learning: Applies to packages/workers/src/routes/orgs/**/*.{js,ts,jsx,tsx} : Use `requireOrgMembership` and `requireProjectAccess` middleware instead of manual membership checks for org-scoped routes
Applied to files:
packages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2025-12-27T03:01:35.601Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/durable-objects.mdc:0-0
Timestamp: 2025-12-27T03:01:35.601Z
Learning: Applies to packages/workers/src/durable-objects/**/ProjectDoc.{js,ts} : Check user membership in project before allowing WebSocket connection in ProjectDoc
Applied to files:
packages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2025-12-27T03:02:05.951Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/pdf-handling.mdc:0-0
Timestamp: 2025-12-27T03:02:05.951Z
Learning: Applies to packages/web/src/**/*.{js,jsx,ts,tsx} : Use `removePdfFromStudy` operation from `useProject` hook to remove PDFs from a study
Applied to files:
packages/web/src/components/project/overview-tab/OverviewTab.jsx
📚 Learning: 2025-12-27T03:01:35.601Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/durable-objects.mdc:0-0
Timestamp: 2025-12-27T03:01:35.601Z
Learning: Applies to packages/workers/src/durable-objects/**/ProjectDoc.{js,ts} : Structure ProjectDoc Y.Doc with meta (Map), members (Map), and reviews (Map) containing checklists (Map), pdfs (Array), and reconciliation (Map)
Applied to files:
packages/web/src/components/admin/ProjectDetail.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Create reusable logic in primitives (hooks) in packages/web/src/primitives/ and import them into components
Applied to files:
packages/web/src/components/Navbar.jsx
🧬 Code graph analysis (6)
packages/web/src/components/admin/UserTable.jsx (3)
packages/web/src/components/ui/avatar.tsx (1)
UserAvatar(124-124)packages/web/src/components/ui/tooltip.tsx (4)
Tooltip(136-136)TooltipTrigger(137-137)TooltipPositioner(138-138)TooltipContent(139-139)packages/web/src/components/mocks/SettingsMockCombined.jsx (1)
providerInfo(160-163)
packages/web/src/components/project/overview-tab/OverviewTab.jsx (4)
packages/web/src/components/ui/avatar.tsx (4)
Avatar(124-124)AvatarImage(124-124)AvatarFallback(124-124)getInitials(124-124)packages/web/src/components/ui/collapsible.tsx (4)
Collapsible(113-113)CollapsibleTrigger(113-113)CollapsibleIndicator(113-113)CollapsibleContent(113-113)packages/web/src/primitives/useProject/index.js (2)
studies(152-152)members(154-154)packages/web/src/components/ui/alert-dialog.tsx (11)
AlertDialog(270-270)AlertDialogBackdrop(271-271)AlertDialogPositioner(272-272)AlertDialogContent(273-273)AlertDialogHeader(274-274)AlertDialogIcon(275-275)AlertDialogTitle(276-276)AlertDialogDescription(277-277)AlertDialogFooter(278-278)AlertDialogCancel(279-279)AlertDialogAction(280-280)
packages/web/src/components/ui/avatar.tsx (1)
packages/ui/src/components/Avatar.tsx (1)
AvatarProps(8-21)
packages/web/src/components/admin/ProjectDetail.jsx (2)
packages/web/src/components/ui/avatar.tsx (1)
UserAvatar(124-124)packages/web/src/components/ui/dialog.tsx (8)
Dialog(198-198)DialogBackdrop(200-200)DialogPositioner(201-201)DialogContent(202-202)DialogHeader(206-206)DialogTitle(203-203)DialogCloseTrigger(205-205)DialogBody(207-207)
packages/web/src/components/Navbar.jsx (2)
packages/web/src/components/ui/avatar.tsx (4)
Avatar(124-124)AvatarImage(124-124)AvatarFallback(124-124)getInitials(124-124)packages/web/src/api/better-auth-store.js (1)
user(217-240)
packages/web/src/components/admin/UserDetail.jsx (2)
packages/web/src/components/ui/avatar.tsx (1)
UserAvatar(124-124)packages/web/src/components/ui/dialog.tsx (8)
Dialog(198-198)DialogBackdrop(200-200)DialogPositioner(201-201)DialogContent(202-202)DialogHeader(206-206)DialogTitle(203-203)DialogCloseTrigger(205-205)DialogBody(207-207)
⏰ 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: Workers Builds: corates
🔇 Additional comments (20)
packages/web/src/components/project/overview-tab/AddMemberModal.jsx (2)
5-6: LGTM! Clean migration to modular Avatar composition.The updated imports correctly source the Avatar primitives from the local UI module and maintain the
@corates/uiimport forSelectandshowToast. This aligns with the project's component architecture. Based on learnings, the use of Ark UI components from@ark-ui/solid(underlying the avatar module) is consistent with coding guidelines.
224-232: Avatar composition is well-structured.The composition pattern using
Avatar > AvatarImage > AvatarFallbackprovides proper fallback handling when user images fail to load. ThegetInitialshelper correctly generates initials from the display name chain.packages/web/src/components/ui/avatar.tsx (2)
1-31: Well-structured Ark UI integration with comprehensive documentation.The module correctly imports from
@ark-ui/solid/avatarand uses proper TypeScript type imports. The JSDoc examples provide clear usage patterns for consumers. Based on learnings, this follows the project's guidelines for using Ark UI components.
115-122: UserAvatar correctly accesses props without destructuring.The convenience component properly accesses
props.class,props.src,props.alt, andprops.namedirectly, maintaining SolidJS reactivity. As per coding guidelines, this follows the pattern of not destructuring props in SolidJS components.packages/web/src/components/Navbar.jsx (2)
7-7: Import migration aligns with the new avatar module.The import correctly sources all needed Avatar primitives and the
getInitialshelper from the local UI module, replacing the previous@corates/uiimport.
138-143: Avatar composition handles loading and offline states gracefully.The fallback chain
user()?.name || storedNameensures initials display correctly during auth loading states, preventing avatar flashing. The composition pattern withAvatarImageandAvatarFallbackis consistent with the new UI module design.packages/web/src/components/admin/UserTable.jsx (2)
9-15: Imports correctly updated for new UI primitives.The migration to
UserAvatarand the composed Tooltip structure (Tooltip,TooltipTrigger,TooltipPositioner,TooltipContent) follows the Ark UI patterns established in the project. Based on learnings, this aligns with the requirement to use Ark UI components.
55-59: UserAvatar simplifies avatar rendering.Using
UserAvatarhere is appropriate since it's a straightforward user avatar with no custom fallback styling needed. This reduces boilerplate compared to the full composition pattern.packages/web/src/components/admin/ProjectDetail.jsx (2)
32-43: Imports correctly updated for modular Dialog and Avatar components.The migration includes all necessary Dialog primitives and the
UserAvatarcomponent, following the consistent pattern established across admin components.
522-580: Dialog composition provides consistent modal experience.The confirm dialog correctly implements the modular structure with
DialogBackdrop,DialogPositioner,DialogContent,DialogHeader,DialogTitle,DialogCloseTrigger, andDialogBody. The conditional title rendering based on dialog type and the action handling in the confirm button are well-structured.packages/web/src/components/admin/UserDetail.jsx (4)
40-51: Comprehensive imports for the modular UI migration.All necessary Dialog primitives and
UserAvatarare correctly imported. The import grouping is logical with UI components separated from store and utility imports.
270-274: UserAvatar with custom sizing works well for the header.The
class='h-16 w-16 text-xl'prop correctly sizes the avatar for the user detail header. The fallback chain forsrcandnamehandles cases whereavatarUrlordisplayNamemight be missing.
646-690: Ban Dialog follows the modular composition pattern.The dialog structure is consistent with other admin dialogs. The textarea for ban reason and the conditional loading state in the button provide good UX. The
onOpenChange={setBanDialog}correctly handles closing via backdrop click or escape key.
693-741: Confirm Dialog handles multiple action types cleanly.The dialog correctly uses conditional rendering with
Showto display appropriate content for 'delete' vs 'revoke-all' actions. The confirm button handler properly dispatches to the correct action based on dialog type.packages/web/src/components/project/overview-tab/OverviewTab.jsx (6)
15-35: LGTM!The updated imports follow project conventions: Ark UI components for UI primitives and
solid-iconsfor icons. The migration from inline/legacy patterns to the modularAvatar,Collapsible, andAlertDialogcomponents is well-structured.
60-62: LGTM!Good use of
createSignalfor local dialog state. The pattern of storing pending action data before showing the confirmation dialog is clean and maintainable.
345-359: LGTM!The Avatar implementation correctly uses the new component API with proper fallback handling. The image source logic appropriately handles relative paths, absolute URLs, and the default avatar API endpoint.
427-442: Verify the CollapsibleTrigger layout is intentional.The
CollapsibleTriggercontains anh2and adivas direct children without a flex container, causing them to stack vertically. If a side-by-side layout (title left, indicator right) was intended, add flex styling to the trigger.If the current stacked layout is intentional (title above, helper text with indicator below), this can be ignored.
Optional fix for side-by-side layout
- <CollapsibleTrigger class='cursor-pointer px-6 py-4 transition-colors select-none hover:bg-gray-50'> + <CollapsibleTrigger class='flex cursor-pointer items-center justify-between px-6 py-4 transition-colors select-none hover:bg-gray-50'> <h2 class='text-lg font-semibold text-gray-900'>Figures</h2>
446-461: Consistent implementation.The Tables collapsible follows the same pattern as Figures. The same layout consideration noted above applies here.
471-498: LGTM!The AlertDialog implementation is well-structured with proper component composition. The dynamic title and description based on self-removal vs. member removal provides good UX clarity. The danger variant is appropriately applied for the destructive action.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
…om/InfinityBowman/corates into 273-detailed-user-profile-creation
…nt. migrate spinner usage
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/web/src/primitives/useProject/studies.js (1)
153-170: Use apiFetch for project update requests.Raw fetch bypasses the shared error handling/toast flow and duplicates parsing. Please switch both rename and description updates to apiFetch (or handleFetchError if you must keep fetch). As per coding guidelines, use apiFetch for frontend API calls.
Proposed fix
- const response = await fetch(`${API_BASE}/api/orgs/${orgId}/projects/${projectId}`, { - method: 'PUT', - credentials: 'include', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ name: trimmed }), - }); - - if (!response.ok) { - let message = 'Failed to rename project'; - try { - const errorBody = await response.json(); - message = errorBody?.error || message; - } catch (err) { - // JSON parsing failed - use default message - console.debug('Could not parse error response:', err.message); - } - throw new Error(message); - } + await apiFetch(`${API_BASE}/api/orgs/${orgId}/projects/${projectId}`, { + method: 'PUT', + credentials: 'include', + body: { name: trimmed }, + });- const response = await fetch(`${API_BASE}/api/orgs/${orgId}/projects/${projectId}`, { - method: 'PUT', - credentials: 'include', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ description: trimmed || null }), - }); - - if (!response.ok) { - let message = 'Failed to update description'; - try { - const errorBody = await response.json(); - message = errorBody?.error || message; - } catch (err) { - // JSON parsing failed - use default message - console.debug('Could not parse error response:', err.message); - } - throw new Error(message); - } + await apiFetch(`${API_BASE}/api/orgs/${orgId}/projects/${projectId}`, { + method: 'PUT', + credentials: 'include', + body: { description: trimmed || null }, + });Also applies to: 204-221
🤖 Fix all issues with AI agents
In `@packages/web/src/components/project/CreateProjectForm.jsx`:
- Line 205: The placeholder text in CreateProjectForm.jsx currently reads
"SimpleSelect an organization" (a typo/search-replace artifact); update the
placeholder prop on the relevant input/select component (the element with
placeholder='SimpleSelect an organization') to the correct user-facing string,
e.g., "Select an organization", so the UI displays the proper prompt.
In `@packages/web/src/components/project/overview-tab/AddMemberModal.jsx`:
- Line 277: In AddMemberModal.jsx fix the typos: change the comment
"SimpleSelected User Display" to a clear label like "Selected User Display" and
update the user-facing placeholder that currently reads "SimpleSelect" to a
proper user prompt such as "Search users..." or "Select a user"; locate the JSX
block that renders the selected-user display and the input/Select control
(within the AddMemberModal component) and update the comment and the placeholder
prop accordingly so they are user-friendly and free of search-replace artifacts.
In `@packages/web/src/components/ui/select.tsx`:
- Around line 301-356: The collection() and disabledSet() functions inside
SimpleSelect recreate new instances each render causing mismatched references;
replace them with memos using createMemo (e.g., const disabledSet =
createMemo(() => new Set(local.disabledValues || [])) and const collection =
createMemo(() => createListCollection({...})) ) and update all usages to call
disabledSet() and collection() (or access .() per framework conventions) so the
Select prop and the <For> loop receive the same stable instances until inputs
change; ensure item mapping still uses disabledSet() inside the memo and
selectValue() remains unchanged.
♻️ Duplicate comments (2)
packages/web/src/components/ui/checkbox.tsx (2)
71-78: Use Tailwind data attribute variant syntax for disabled styles.
data-disabled:will not apply; usedata-[disabled]:instead.Suggested fix
- 'data-disabled:cursor-not-allowed data-disabled:opacity-50', + 'data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50',Tailwind CSS arbitrary variants data attribute syntax data-[disabled]:
100-104: Fix Tailwind data attribute variant for label disabled styles.
data-disabled:is invalid; usedata-[disabled]:so the styles apply.Suggested fix
- 'data-disabled:cursor-not-allowed data-disabled:opacity-70', + 'data-[disabled]:cursor-not-allowed data-[disabled]:opacity-70',Tailwind CSS arbitrary variants data attribute syntax data-[disabled]:
🧹 Nitpick comments (7)
packages/web/src/components/checklist/LocalAppraisalsPanel.jsx (1)
52-59: Consider adding error handling for failed deletions.If
deleteChecklistthrows or fails, the dialog still closes and state resets, which could leave users unaware that deletion failed. That said, this matches the pattern inLocalAppraisalsSection.jsx, so it may be intentional to handle errors at the store level.Optional: Add error handling
const confirmDelete = async () => { const checklistId = pendingDeleteId(); if (checklistId) { - await deleteChecklist(checklistId); + try { + await deleteChecklist(checklistId); + } catch (error) { + // Error should be handled by store/apiFetch toast + console.error('Failed to delete checklist:', error); + } } setDeleteDialogOpen(false); setPendingDeleteId(null); };packages/web/src/components/project/all-studies-tab/AssignReviewersModal.jsx (1)
35-35: Inconsistent signal/setter namingThe signal is named
selectsReadybut its setter issetSimpleSelectsReady. This inconsistency could cause confusion during maintenance. Consider aligning the names.Suggested fix
- const [selectsReady, setSimpleSelectsReady] = createSignal(false); + const [selectsReady, setSelectsReady] = createSignal(false);Then update references at lines 82, 87, and 139 from
setSimpleSelectsReadytosetSelectsReady.packages/web/src/components/project/ProjectView.jsx (1)
238-264: Consider memoizingtabDefinitionsif tab counts change frequently.
tabDefinitionsis recreated on every render. Since it containsgetCountfunctions that access reactive state, this is functionally correct. However, if performance becomes a concern, consider wrapping it increateMemoto avoid recreating the array structure.packages/web/src/primitives/useProject/studies.js (1)
185-187: Verify project list cache invalidation coverage.If any views read project lists via queryKeys.projects.byOrg(orgId) or queryKeys.projects.list(userId), invalidating only queryKeys.projects.all can leave stale lists after rename/description updates. Please verify which key(s) are used and invalidate accordingly.
Also applies to: 236-237
packages/web/src/components/ui/password-input.tsx (1)
48-55: Avoid splitProps to comply with the no-prop-destructuring rule.Current components split props and then use local/others. The guidelines prefer accessing props directly. Consider spreading props and overriding class/children instead, and apply the same pattern to the other subcomponents in this file. As per coding guidelines.
Proposed fix (apply similarly to other subcomponents)
-const PasswordInput: Component<PasswordInputProps> = props => { - const [local, others] = splitProps(props, ['class', 'children']); - return ( - <PasswordInputPrimitive.Root class={cn('w-full', local.class)} {...others}> - {local.children} - </PasswordInputPrimitive.Root> - ); -}; +const PasswordInput: Component<PasswordInputProps> = props => ( + <PasswordInputPrimitive.Root {...props} class={cn('w-full', props.class)}> + {props.children} + </PasswordInputPrimitive.Root> +);packages/web/src/components/project/CreateProjectForm.jsx (1)
32-32: Inconsistent setter naming pattern.The setter
setSimpleSelectedOrgIdincludes "Simple" in the name, which appears to be a search-replace artifact. Compare toDevImportProject.jsxat line 23 which uses the standard patternsetSelectedOrgId. Consider using consistent naming.Suggested fix
- const [selectedOrgId, setSimpleSelectedOrgId] = createSignal(null); + const [selectedOrgId, setSelectedOrgId] = createSignal(null);And update usages at lines 41 and 204 accordingly.
Also applies to: 41-41
packages/web/src/components/project/overview-tab/AddMemberModal.jsx (1)
25-26: Inconsistent naming pattern from search-replace.The signal setters and handler include "Simple" prefix (
setSimpleSelectedUser,setSimpleSelectedRole,handleSimpleSelectUser) which appears to be a search-replace artifact. Standard naming would besetSelectedUser,setSelectedRole,handleSelectUser.Suggested fix
- const [selectedUser, setSimpleSelectedUser] = createSignal(null); - const [selectedRole, setSimpleSelectedRole] = createSignal('member'); + const [selectedUser, setSelectedUser] = createSignal(null); + const [selectedRole, setSelectedRole] = createSignal('member');- const handleSimpleSelectUser = user => { - setSimpleSelectedUser(user); + const handleSelectUser = user => { + setSelectedUser(user);Update all usages at lines 146-147, 222, 303, 322 accordingly.
Also applies to: 84-88
| </Show> | ||
|
|
||
| {/* Selected User Display */} | ||
| {/* SimpleSelected User Display */} |
There was a problem hiding this comment.
Typos in comment and user-facing placeholder text.
The comment at line 277 says "SimpleSelected" and the placeholder at line 323 contains "SimpleSelect" - both appear to be search-replace artifacts.
Suggested fix
- {/* SimpleSelected User Display */}
+ {/* Selected User Display */}- placeholder='SimpleSelect a role'
+ placeholder='Select a role'Also applies to: 323-323
🤖 Prompt for AI Agents
In `@packages/web/src/components/project/overview-tab/AddMemberModal.jsx` at line
277, In AddMemberModal.jsx fix the typos: change the comment "SimpleSelected
User Display" to a clear label like "Selected User Display" and update the
user-facing placeholder that currently reads "SimpleSelect" to a proper user
prompt such as "Search users..." or "Select a user"; locate the JSX block that
renders the selected-user display and the input/Select control (within the
AddMemberModal component) and update the comment and the placeholder prop
accordingly so they are user-friendly and free of search-replace artifacts.
| const SimpleSelect: Component<SimpleSelectProps> = props => { | ||
| const [local, others] = splitProps(props, [ | ||
| 'items', | ||
| 'value', | ||
| 'onChange', | ||
| 'label', | ||
| 'placeholder', | ||
| 'disabledValues', | ||
| 'inDialog', | ||
| 'class', | ||
| ]); | ||
|
|
||
| const disabledSet = () => new Set(local.disabledValues || []); | ||
|
|
||
| const collection = () => | ||
| createListCollection({ | ||
| items: (local.items || []).map(item => ({ | ||
| ...item, | ||
| disabled: item.disabled || disabledSet().has(item.value), | ||
| })), | ||
| itemToString: item => item.label, | ||
| itemToValue: item => item.value, | ||
| }); | ||
|
|
||
| const selectValue = () => (local.value != null ? [local.value] : []); | ||
|
|
||
| return ( | ||
| <Select | ||
| collection={collection()} | ||
| value={selectValue()} | ||
| onValueChange={values => local.onChange?.(values[0] || '')} | ||
| class={local.class} | ||
| {...others} | ||
| > | ||
| <Show when={local.label}> | ||
| <SelectLabel>{local.label}</SelectLabel> | ||
| </Show> | ||
| <SelectControl> | ||
| <SelectTrigger> | ||
| <SelectValueText placeholder={local.placeholder || 'Select option'} /> | ||
| <SelectIndicator /> | ||
| </SelectTrigger> | ||
| </SelectControl> | ||
| <SelectPositioner inDialog={local.inDialog}> | ||
| <SelectContent> | ||
| <For each={collection().items}> | ||
| {item => ( | ||
| <SelectItem item={item}> | ||
| <SelectItemText>{item.label}</SelectItemText> | ||
| <SelectItemIndicator /> | ||
| </SelectItem> | ||
| )} | ||
| </For> | ||
| </SelectContent> | ||
| </SelectPositioner> | ||
| <SelectHiddenSelect /> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, check if this file exists and view the actual code around the lines mentioned
head -360 packages/web/src/components/ui/select.tsx | tail -80Repository: InfinityBowman/corates
Length of output: 188
🏁 Script executed:
# Search for how Select component is used elsewhere to understand the pattern
rg "Select\s*collection=" packages/web/src --type tsx -A 2 -B 2Repository: InfinityBowman/corates
Length of output: 188
🏁 Script executed:
# Check if there are other memoized collections in the codebase
rg "createMemo.*createListCollection" packages/web/src --type tsxRepository: InfinityBowman/corates
Length of output: 188
🏁 Script executed:
# Look for Ark UI documentation or types to understand Select behavior
rg "@ark-ui.*Select" packages/web/src --type tsx | head -20Repository: InfinityBowman/corates
Length of output: 188
🏁 Script executed:
# Check package.json for Ark UI version
cat package.json | grep -A 2 -B 2 "@ark-ui"Repository: InfinityBowman/corates
Length of output: 188
Memoize the collection and disabled set to maintain stable references.
The collection() and disabledSet() functions create new instances each time they are called. Since collection() is invoked both in the Select component prop and in the For loop within the same render, the Select component and the item loop receive different collection objects, which can break Ark UI's selection state and item identity tracking. Wrap both in createMemo so the same instance is reused until dependencies change.
Proposed fix
-import { For, Show, splitProps } from 'solid-js';
+import { For, Show, splitProps, createMemo } from 'solid-js';
@@
- const disabledSet = () => new Set(local.disabledValues || []);
+ const disabledSet = createMemo(() => new Set(local.disabledValues || []));
- const collection = () =>
- createListCollection({
- items: (local.items || []).map(item => ({
- ...item,
- disabled: item.disabled || disabledSet().has(item.value),
- })),
- itemToString: item => item.label,
- itemToValue: item => item.value,
- });
+ const collection = createMemo(() =>
+ createListCollection({
+ items: (local.items || []).map(item => ({
+ ...item,
+ disabled: item.disabled || disabledSet().has(item.value),
+ })),
+ itemToString: item => item.label,
+ itemToValue: item => item.value,
+ }),
+ );🤖 Prompt for AI Agents
In `@packages/web/src/components/ui/select.tsx` around lines 301 - 356, The
collection() and disabledSet() functions inside SimpleSelect recreate new
instances each render causing mismatched references; replace them with memos
using createMemo (e.g., const disabledSet = createMemo(() => new
Set(local.disabledValues || [])) and const collection = createMemo(() =>
createListCollection({...})) ) and update all usages to call disabledSet() and
collection() (or access .() per framework conventions) so the Select prop and
the <For> loop receive the same stable instances until inputs change; ensure
item mapping still uses disabledSet() inside the memo and selectValue() remains
unchanged.
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/web/src/components/checklist/ChecklistYjsWrapper.jsx (1)
340-358: Guard confirmMarkComplete against stale state.
If the dialog stays open while the checklist or study becomes unavailable or locked,getNextStatusForCompletioncan throw or you could overwrite a finalized status. Re-check before updating.Proposed fix
- const confirmMarkComplete = () => { - const study = currentStudy(); + const confirmMarkComplete = () => { + const checklist = currentChecklist(); + const study = currentStudy(); + if (!checklist || !study || !isEditable(checklist.status)) { + setCompleteDialogOpen(false); + return; + } // Determine the appropriate status based on reviewer count const nextStatus = getNextStatusForCompletion(study); updateChecklist(params.studyId, params.checklistId, { status: nextStatus });packages/web/src/components/project/ProjectView.jsx (1)
186-206: Pass tag parameter to importFromGoogleDrive and use useProject.addPdfToStudy operation.The
importFromGoogleDrivecall is missing the requiredtagparameter. Per coding guidelines, pass the tag (primary or supplementary) as the fourth argument. Additionally, switch fromprojectActionsStore.pdf.addToStudy()to theaddPdfToStudyoperation from theuseProjecthook, which expects the tag field in the metadata object to maintain consistency with other PDF add operations and centralize PDF writes.
🤖 Fix all issues with AI agents
In `@packages/web/src/components/admin/StorageManagement.jsx`:
- Around line 423-427: The close button (DialogCloseTrigger with the FiX icon)
is missing an accessible name — add an accessible label by giving
DialogCloseTrigger an aria-label (e.g., aria-label="Close") or by including
visually hidden text inside the trigger (e.g., a <span
className="sr-only">Close</span>) so screen readers can announce the control;
update the element where DialogCloseTrigger and FiX are used to include one of
these accessible naming approaches.
In `@packages/web/src/components/admin/UserDetail.jsx`:
- Around line 650-654: The DialogCloseTrigger icon-only buttons (components
named DialogCloseTrigger with FiX icon) lack accessible labels; update both
instances (the one near DialogTitle "Ban User" and the other at lines ~701-703)
to include an accessible label by adding an aria-label like "Close dialog" or by
including visually hidden text inside the trigger; ensure the aria-label/value
is descriptive and matches the dialog context (e.g., "Close Ban User dialog") so
screen readers announce the button correctly.
In `@packages/web/src/components/auth/CompleteProfile.jsx`:
- Around line 537-546: The StepsCompletedContent block is unreachable because
handleSubmit immediately navigates to the dashboard before the Steps component
can render the completed state; either remove StepsCompletedContent or change
handleSubmit to set currentStep to the final index (e.g., call setCurrentStep(3)
or set currentStep to count) and then perform a delayed navigation (e.g.,
setTimeout) so the completed UI is visible briefly; locate the handleSubmit
function and the currentStep setter (e.g., setCurrentStep or setStep) and update
it accordingly or delete the StepsCompletedContent JSX to eliminate dead code.
In
`@packages/web/src/components/project/all-studies-tab/EditPdfMetadataModal.jsx`:
- Around line 127-191: The labels in EditPdfMetadataModal.jsx are not linked to
their inputs (Article Title, First Author, Publication Year, Journal, DOI): add
unique id attributes to each input/textarea (e.g., id="title", "firstAuthor",
"publicationYear", "journal", "doi") and set the corresponding label htmlFor to
the same id; keep existing value/onInput handlers (title()/setTitle,
firstAuthor()/setFirstAuthor, publicationYear()/setPublicationYear,
journal()/setJournal, doi()/setDoi) unchanged so accessibility is restored
without altering behavior.
In `@packages/web/src/components/settings/pages/LinkedAccountsSection.jsx`:
- Around line 376-380: The close icon (DialogCloseTrigger containing FiX) lacks
an accessible name; update the DialogCloseTrigger (and/or the element rendering
FiX) to include an accessible label such as aria-label or title (for example
aria-label={`Close ${unlinkProviderName()}`} or a generic "Close") so screen
readers can announce its purpose; ensure the attribute is placed on the
interactive element rendered by DialogCloseTrigger (not only on the icon) and
keep the label concise and localized if applicable.
♻️ Duplicate comments (1)
packages/web/src/components/project/overview-tab/AddMemberModal.jsx (1)
277-277: Fix the typo in the comment and placeholder text.These are the same typos previously flagged; please update both to user-friendly text.
Also applies to: 323-323
🧹 Nitpick comments (10)
packages/web/src/components/ui/qr-code.tsx (1)
68-84: Consider removing unnecessary empty strings incn()calls.The
cn('', local.class)pattern works but the empty string is redundant -cnhandlesundefinedgracefully. This is purely cosmetic.Optional cleanup
const QRCodeFrame: Component<QRCodeFrameProps> = props => { const [local, others] = splitProps(props, ['class', 'children']); return ( - <QrCodePrimitive.Frame class={cn('', local.class)} {...others}> + <QrCodePrimitive.Frame class={local.class} {...others}> {local.children} </QrCodePrimitive.Frame> ); }; // ... const QRCodePattern: Component<QRCodePatternProps> = props => { const [local, others] = splitProps(props, ['class']); - return <QrCodePrimitive.Pattern class={cn('', local.class)} {...others} />; + return <QrCodePrimitive.Pattern class={local.class} {...others} />; };packages/web/src/components/project/add-studies/AddStudiesForm.jsx (1)
223-239: Compute tab count once per render.
getCount()is invoked twice per tab render. Store the value in a local const to avoid duplicate reactive reads and keep the JSX simpler.Proposed change
{tab => { const getCount = () => { if (tab.value === 'pdfs') return studies.pdfCount(); if (tab.value === 'references') return studies.refCount(); if (tab.value === 'lookup') return studies.lookupCount(); if (tab.value === 'drive') return studies.driveCount(); return 0; }; + const count = getCount(); return ( <TabsTrigger value={tab.value} class='gap-2 border-b-2 border-transparent text-gray-600 hover:text-gray-900 data-[selected]:border-blue-600 data-[selected]:text-gray-900' > {tab.label} - <Show when={getCount() > 0}> + <Show when={count > 0}> <span class='inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-blue-100 px-1.5 text-xs font-medium text-blue-700'> - {getCount()} + {count} </span> </Show> </TabsTrigger> ); }}packages/web/src/components/ui/pin-input.tsx (1)
109-116: Consider exporting prop types for consumer use.The type definitions (
PinInputProps,PinInputLabelProps,PinInputControlProps,PinInputFieldProps) are declared but not exported. Consumers building wrappers or typed integrations would benefit from having these types available.Suggested export with types
export { PinInput, PinInputLabel, PinInputControl, PinInputField, PinInputHiddenInput, PinInputContext, }; + +export type { + PinInputProps, + PinInputLabelProps, + PinInputControlProps, + PinInputFieldProps, +};packages/web/src/components/auth/CompleteProfile.jsx (1)
238-242: Consider removing the arbitrary delay or documenting its purpose.The 200ms delay before navigation appears to be a workaround, possibly to allow state updates to propagate. If this is necessary due to a timing issue with
updateProfile, consider adding a brief comment explaining why, or investigate if it can be removed.Suggestion: Add explanatory comment if delay is intentional
- await new Promise(resolve => setTimeout(resolve, 200)); + // Brief delay to allow profile state to propagate before navigation + await new Promise(resolve => setTimeout(resolve, 200));packages/web/src/components/settings/pages/TwoFactorSetup.jsx (1)
331-340: Ensure autocomplete reaches the input element.If PasswordInput does not forward autoComplete to the underlying input, the browser will ignore it. Consider placing autoComplete on PasswordInputField or confirm the wrapper forwards the prop.
Proposed change
- <PasswordInput autoComplete='current-password'> + <PasswordInput> <PasswordInputLabel>Password</PasswordInputLabel> <PasswordInputControl> <PasswordInputField + autoComplete='current-password' value={password()} onInput={e => setPassword(e.target.value)} /> <PasswordInputVisibilityTrigger /> </PasswordInputControl> </PasswordInput>packages/web/src/components/settings/pages/MergeAccountsDialog.jsx (2)
170-188: Use shared error handler for consistency.This path bypasses the shared error handling used elsewhere in the component, which can yield inconsistent messaging and missing error parsing. Consider reusing the same utility.
Proposed fix
- } catch (err) { - setError(err.message); - setStep(STEPS.CONFIRM); - } finally { + } catch (err) { + const { handleError } = await import('@/lib/error-utils.js'); + await handleError(err, { + setError, + showToast: false, + }); + setStep(STEPS.CONFIRM); + } finally { setLoading(false); }
299-317: Prefer Show for conditional copy blocks.The conditional instruction text is currently using a ternary in JSX. Align with the SolidJS guidance to use Show for conditional rendering in UI copy blocks. As per coding guidelines.
Proposed fix
- <p class='text-sm text-gray-600'> - {isOrcidConflict() ? - `Enter the email address or ORCID ID (e.g., 0000-0001-2345-6789) of the other CoRATES account. We'll send a verification code to prove you own it.` - : `Enter the email address of the other CoRATES account. We'll send a verification code to prove you own it.` - } - </p> + <p class='text-sm text-gray-600'> + <Show + when={isOrcidConflict()} + fallback={ + `Enter the email address of the other CoRATES account. We'll send a verification code to prove you own it.` + } + > + {`Enter the email address or ORCID ID (e.g., 0000-0001-2345-6789) of the other CoRATES account. We'll send a verification code to prove you own it.`} + </Show> + </p>packages/web/src/components/ui/toast.tsx (2)
141-159: Consider usingShowcomponent for conditional icon rendering.Per coding guidelines, SolidJS recommends using the
Showcomponent for conditional rendering instead of&&patterns. While this works,Showis more idiomatic and avoids potential reactivity edge cases.Additionally, the
loadingtoast type has no icon rendered. Consider adding a spinner icon for visual consistency.Suggested refactor using Show component
{toast => ( <ToastRoot> <div class='flex gap-3'> - {toast().type === 'success' && ( - <FiCheckCircle class='h-5 w-5 shrink-0 text-green-500' /> - )} - {toast().type === 'error' && <FiAlertCircle class='h-5 w-5 shrink-0 text-red-500' />} - {toast().type === 'warning' && ( - <FiAlertTriangle class='h-5 w-5 shrink-0 text-amber-500' /> - )} - {toast().type === 'info' && <FiInfo class='h-5 w-5 shrink-0 text-blue-500' />} + <Show when={toast().type === 'success'}> + <FiCheckCircle class='h-5 w-5 shrink-0 text-green-500' /> + </Show> + <Show when={toast().type === 'error'}> + <FiAlertCircle class='h-5 w-5 shrink-0 text-red-500' /> + </Show> + <Show when={toast().type === 'warning'}> + <FiAlertTriangle class='h-5 w-5 shrink-0 text-amber-500' /> + </Show> + <Show when={toast().type === 'info'}> + <FiInfo class='h-5 w-5 shrink-0 text-blue-500' /> + </Show> + <Show when={toast().type === 'loading'}> + <FiLoader class='h-5 w-5 shrink-0 animate-spin text-gray-500' /> + </Show> <div class='flex-1'>Note: You'll need to import
FiLoaderfromsolid-icons/fiandShowfromsolid-js.
165-196: Minor API inconsistency:ToastOptionsinterface not used by main methods.The
ToastOptionsinterface is defined but only used byupdate(). The other methods (success,error, etc.) use positional parameters. This is fine for simplicity, but consider unifying if the API expands.packages/web/src/components/admin/UserDetail.jsx (1)
698-700: Prefer Show over a ternary for the dialog title.Use Show for conditional rendering to match project guidelines. As per coding guidelines, use Show instead of ternary operators.
Proposed refactor
- <DialogTitle> - {confirmDialog()?.type === 'delete' ? 'Delete User' : 'Revoke All Sessions'} - </DialogTitle> + <DialogTitle> + <Show when={confirmDialog()?.type === 'delete'} fallback='Revoke All Sessions'> + Delete User + </Show> + </DialogTitle>
| <DialogHeader> | ||
| <DialogTitle>Ban User</DialogTitle> | ||
| <DialogCloseTrigger> | ||
| <FiX class='h-5 w-5' /> | ||
| </DialogCloseTrigger> |
There was a problem hiding this comment.
Add an accessible label for the icon-only close triggers.
Without a label, screen readers will announce an unlabeled button. Consider adding an aria-label (or visually hidden text) to both DialogCloseTrigger instances.
Proposed fix
- <DialogCloseTrigger>
+ <DialogCloseTrigger aria-label='Close dialog'>
<FiX class='h-5 w-5' />
</DialogCloseTrigger>Also applies to: 701-703
🤖 Prompt for AI Agents
In `@packages/web/src/components/admin/UserDetail.jsx` around lines 650 - 654, The
DialogCloseTrigger icon-only buttons (components named DialogCloseTrigger with
FiX icon) lack accessible labels; update both instances (the one near
DialogTitle "Ban User" and the other at lines ~701-703) to include an accessible
label by adding an aria-label like "Close dialog" or by including visually
hidden text inside the trigger; ensure the aria-label/value is descriptive and
matches the dialog context (e.g., "Close Ban User dialog") so screen readers
announce the button correctly.
| {/* Completed Content (shows after all steps) */} | ||
| <StepsCompletedContent> | ||
| <div class='flex flex-col items-center justify-center py-8'> | ||
| <div class='mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-green-100'> | ||
| <FiCheck class='h-8 w-8 text-green-600' /> | ||
| </div> | ||
| <h2 class='mb-2 text-xl font-bold text-gray-900'>All Done!</h2> | ||
| <p class='text-sm text-gray-500'>Redirecting to your dashboard...</p> | ||
| </div> | ||
| </StepsCompletedContent> |
There was a problem hiding this comment.
StepsCompletedContent appears unreachable.
This completion UI will never be displayed because handleSubmit navigates to the dashboard (line 242 or 230) before currentStep could reach 3. The Steps component shows StepsCompletedContent when step >= count, but navigation occurs immediately after successful submission.
Either:
- Remove this dead code if the immediate redirect is intentional
- Show the completed state briefly before navigating by setting
currentStep(3)and using a delayed navigation
Option 1: Remove unreachable code
- {/* Completed Content (shows after all steps) */}
- <StepsCompletedContent>
- <div class='flex flex-col items-center justify-center py-8'>
- <div class='mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-green-100'>
- <FiCheck class='h-8 w-8 text-green-600' />
- </div>
- <h2 class='mb-2 text-xl font-bold text-gray-900'>All Done!</h2>
- <p class='text-sm text-gray-500'>Redirecting to your dashboard...</p>
- </div>
- </StepsCompletedContent>Option 2: Show completion state before redirect (in handleSubmit)
+ // Show completion state before navigating
+ setCurrentStep(3);
await new Promise(resolve => setTimeout(resolve, 200));
+ await new Promise(resolve => setTimeout(resolve, 1000)); // Show "All Done!" briefly
navigate('/dashboard', { replace: true });📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {/* Completed Content (shows after all steps) */} | |
| <StepsCompletedContent> | |
| <div class='flex flex-col items-center justify-center py-8'> | |
| <div class='mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-green-100'> | |
| <FiCheck class='h-8 w-8 text-green-600' /> | |
| </div> | |
| <h2 class='mb-2 text-xl font-bold text-gray-900'>All Done!</h2> | |
| <p class='text-sm text-gray-500'>Redirecting to your dashboard...</p> | |
| </div> | |
| </StepsCompletedContent> | |
| {/* Content for each step */} |
🤖 Prompt for AI Agents
In `@packages/web/src/components/auth/CompleteProfile.jsx` around lines 537 - 546,
The StepsCompletedContent block is unreachable because handleSubmit immediately
navigates to the dashboard before the Steps component can render the completed
state; either remove StepsCompletedContent or change handleSubmit to set
currentStep to the final index (e.g., call setCurrentStep(3) or set currentStep
to count) and then perform a delayed navigation (e.g., setTimeout) so the
completed UI is visible briefly; locate the handleSubmit function and the
currentStep setter (e.g., setCurrentStep or setStep) and update it accordingly
or delete the StepsCompletedContent JSX to eliminate dead code.
| {/* Article Title */} | ||
| <div> | ||
| <label class='mb-1 block text-sm font-medium text-gray-700'>Article Title</label> | ||
| <textarea | ||
| value={title()} | ||
| onInput={e => setTitle(e.target.value)} | ||
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | ||
| placeholder='Full article title' | ||
| rows={2} | ||
| /> | ||
| </div> | ||
|
|
||
| {/* Author and Year */} | ||
| <div class='grid grid-cols-2 gap-4'> | ||
| <div> | ||
| <label class='mb-1 block text-sm font-medium text-gray-700'>First Author</label> | ||
| <input | ||
| type='text' | ||
| value={firstAuthor()} | ||
| onInput={e => setFirstAuthor(e.target.value)} | ||
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | ||
| placeholder='e.g., Smith' | ||
| /> | ||
| </div> | ||
| <div> | ||
| <label class='mb-1 block text-sm font-medium text-gray-700'>Publication Year</label> | ||
| <input | ||
| type='number' | ||
| value={publicationYear()} | ||
| onInput={e => setPublicationYear(e.target.value)} | ||
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | ||
| placeholder='e.g., 2024' | ||
| min='1900' | ||
| max='2100' | ||
| step='1' | ||
| inputMode='numeric' | ||
| /> | ||
| </div> | ||
| </div> | ||
| {/* Author and Year */} | ||
| <div class='grid grid-cols-2 gap-4'> | ||
| <div> | ||
| <label class='mb-1 block text-sm font-medium text-gray-700'>First Author</label> | ||
| <input | ||
| type='text' | ||
| value={firstAuthor()} | ||
| onInput={e => setFirstAuthor(e.target.value)} | ||
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | ||
| placeholder='e.g., Smith' | ||
| /> | ||
| </div> | ||
| <div> | ||
| <label class='mb-1 block text-sm font-medium text-gray-700'> | ||
| Publication Year | ||
| </label> | ||
| <input | ||
| type='number' | ||
| value={publicationYear()} | ||
| onInput={e => setPublicationYear(e.target.value)} | ||
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | ||
| placeholder='e.g., 2024' | ||
| min='1900' | ||
| max='2100' | ||
| step='1' | ||
| inputMode='numeric' | ||
| /> | ||
| </div> | ||
| </div> | ||
|
|
||
| {/* Journal */} | ||
| <div> | ||
| <label class='mb-1 block text-sm font-medium text-gray-700'>Journal</label> | ||
| <input | ||
| type='text' | ||
| value={journal()} | ||
| onInput={e => setJournal(e.target.value)} | ||
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | ||
| placeholder='e.g., Journal of Clinical Research' | ||
| /> | ||
| </div> | ||
| {/* Journal */} | ||
| <div> | ||
| <label class='mb-1 block text-sm font-medium text-gray-700'>Journal</label> | ||
| <input | ||
| type='text' | ||
| value={journal()} | ||
| onInput={e => setJournal(e.target.value)} | ||
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | ||
| placeholder='e.g., Journal of Clinical Research' | ||
| /> | ||
| </div> | ||
|
|
||
| {/* DOI */} | ||
| <div> | ||
| <label class='mb-1 block text-sm font-medium text-gray-700'>DOI</label> | ||
| <input | ||
| type='text' | ||
| value={doi()} | ||
| onInput={e => setDoi(e.target.value)} | ||
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | ||
| placeholder='e.g., 10.1000/xyz123' | ||
| /> | ||
| </div> | ||
| {/* DOI */} | ||
| <div> | ||
| <label class='mb-1 block text-sm font-medium text-gray-700'>DOI</label> | ||
| <input | ||
| type='text' | ||
| value={doi()} | ||
| onInput={e => setDoi(e.target.value)} | ||
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | ||
| placeholder='e.g., 10.1000/xyz123' | ||
| /> | ||
| </div> |
There was a problem hiding this comment.
Form labels are not semantically associated with inputs.
The <label> elements lack htmlFor attributes and inputs lack id attributes, so screen readers won't announce the labels when users focus on inputs. This affects accessibility for users relying on assistive technology.
Suggested fix for one field (apply same pattern to all)
{/* Article Title */}
<div>
- <label class='mb-1 block text-sm font-medium text-gray-700'>Article Title</label>
+ <label htmlFor='pdf-title' class='mb-1 block text-sm font-medium text-gray-700'>Article Title</label>
<textarea
+ id='pdf-title'
value={title()}
onInput={e => setTitle(e.target.value)}Apply the same pattern to firstAuthor, publicationYear, journal, and doi inputs.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {/* Article Title */} | |
| <div> | |
| <label class='mb-1 block text-sm font-medium text-gray-700'>Article Title</label> | |
| <textarea | |
| value={title()} | |
| onInput={e => setTitle(e.target.value)} | |
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | |
| placeholder='Full article title' | |
| rows={2} | |
| /> | |
| </div> | |
| {/* Author and Year */} | |
| <div class='grid grid-cols-2 gap-4'> | |
| <div> | |
| <label class='mb-1 block text-sm font-medium text-gray-700'>First Author</label> | |
| <input | |
| type='text' | |
| value={firstAuthor()} | |
| onInput={e => setFirstAuthor(e.target.value)} | |
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | |
| placeholder='e.g., Smith' | |
| /> | |
| </div> | |
| <div> | |
| <label class='mb-1 block text-sm font-medium text-gray-700'>Publication Year</label> | |
| <input | |
| type='number' | |
| value={publicationYear()} | |
| onInput={e => setPublicationYear(e.target.value)} | |
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | |
| placeholder='e.g., 2024' | |
| min='1900' | |
| max='2100' | |
| step='1' | |
| inputMode='numeric' | |
| /> | |
| </div> | |
| </div> | |
| {/* Author and Year */} | |
| <div class='grid grid-cols-2 gap-4'> | |
| <div> | |
| <label class='mb-1 block text-sm font-medium text-gray-700'>First Author</label> | |
| <input | |
| type='text' | |
| value={firstAuthor()} | |
| onInput={e => setFirstAuthor(e.target.value)} | |
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | |
| placeholder='e.g., Smith' | |
| /> | |
| </div> | |
| <div> | |
| <label class='mb-1 block text-sm font-medium text-gray-700'> | |
| Publication Year | |
| </label> | |
| <input | |
| type='number' | |
| value={publicationYear()} | |
| onInput={e => setPublicationYear(e.target.value)} | |
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | |
| placeholder='e.g., 2024' | |
| min='1900' | |
| max='2100' | |
| step='1' | |
| inputMode='numeric' | |
| /> | |
| </div> | |
| </div> | |
| {/* Journal */} | |
| <div> | |
| <label class='mb-1 block text-sm font-medium text-gray-700'>Journal</label> | |
| <input | |
| type='text' | |
| value={journal()} | |
| onInput={e => setJournal(e.target.value)} | |
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | |
| placeholder='e.g., Journal of Clinical Research' | |
| /> | |
| </div> | |
| {/* Journal */} | |
| <div> | |
| <label class='mb-1 block text-sm font-medium text-gray-700'>Journal</label> | |
| <input | |
| type='text' | |
| value={journal()} | |
| onInput={e => setJournal(e.target.value)} | |
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | |
| placeholder='e.g., Journal of Clinical Research' | |
| /> | |
| </div> | |
| {/* DOI */} | |
| <div> | |
| <label class='mb-1 block text-sm font-medium text-gray-700'>DOI</label> | |
| <input | |
| type='text' | |
| value={doi()} | |
| onInput={e => setDoi(e.target.value)} | |
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | |
| placeholder='e.g., 10.1000/xyz123' | |
| /> | |
| </div> | |
| {/* DOI */} | |
| <div> | |
| <label class='mb-1 block text-sm font-medium text-gray-700'>DOI</label> | |
| <input | |
| type='text' | |
| value={doi()} | |
| onInput={e => setDoi(e.target.value)} | |
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | |
| placeholder='e.g., 10.1000/xyz123' | |
| /> | |
| </div> | |
| {/* Article Title */} | |
| <div> | |
| <label htmlFor='pdf-title' class='mb-1 block text-sm font-medium text-gray-700'>Article Title</label> | |
| <textarea | |
| id='pdf-title' | |
| value={title()} | |
| onInput={e => setTitle(e.target.value)} | |
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | |
| placeholder='Full article title' | |
| rows={2} | |
| /> | |
| </div> | |
| {/* Author and Year */} | |
| <div class='grid grid-cols-2 gap-4'> | |
| <div> | |
| <label htmlFor='pdf-first-author' class='mb-1 block text-sm font-medium text-gray-700'>First Author</label> | |
| <input | |
| id='pdf-first-author' | |
| type='text' | |
| value={firstAuthor()} | |
| onInput={e => setFirstAuthor(e.target.value)} | |
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | |
| placeholder='e.g., Smith' | |
| /> | |
| </div> | |
| <div> | |
| <label htmlFor='pdf-publication-year' class='mb-1 block text-sm font-medium text-gray-700'> | |
| Publication Year | |
| </label> | |
| <input | |
| id='pdf-publication-year' | |
| type='number' | |
| value={publicationYear()} | |
| onInput={e => setPublicationYear(e.target.value)} | |
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | |
| placeholder='e.g., 2024' | |
| min='1900' | |
| max='2100' | |
| step='1' | |
| inputMode='numeric' | |
| /> | |
| </div> | |
| </div> | |
| {/* Journal */} | |
| <div> | |
| <label htmlFor='pdf-journal' class='mb-1 block text-sm font-medium text-gray-700'>Journal</label> | |
| <input | |
| id='pdf-journal' | |
| type='text' | |
| value={journal()} | |
| onInput={e => setJournal(e.target.value)} | |
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | |
| placeholder='e.g., Journal of Clinical Research' | |
| /> | |
| </div> | |
| {/* DOI */} | |
| <div> | |
| <label htmlFor='pdf-doi' class='mb-1 block text-sm font-medium text-gray-700'>DOI</label> | |
| <input | |
| id='pdf-doi' | |
| type='text' | |
| value={doi()} | |
| onInput={e => setDoi(e.target.value)} | |
| class='w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-blue-500' | |
| placeholder='e.g., 10.1000/xyz123' | |
| /> | |
| </div> |
🤖 Prompt for AI Agents
In `@packages/web/src/components/project/all-studies-tab/EditPdfMetadataModal.jsx`
around lines 127 - 191, The labels in EditPdfMetadataModal.jsx are not linked to
their inputs (Article Title, First Author, Publication Year, Journal, DOI): add
unique id attributes to each input/textarea (e.g., id="title", "firstAuthor",
"publicationYear", "journal", "doi") and set the corresponding label htmlFor to
the same id; keep existing value/onInput handlers (title()/setTitle,
firstAuthor()/setFirstAuthor, publicationYear()/setPublicationYear,
journal()/setJournal, doi()/setDoi) unchanged so accessibility is restored
without altering behavior.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/web/src/components/admin/StorageManagement.jsx`:
- Around line 419-453: The dialog currently allows closing via backdrop or close
trigger while deletion is in progress; update the Dialog open/onOpenChange and
the close trigger behavior so the modal cannot be dismissed when loading() is
true: in the Dialog component, change the onOpenChange handler to ignore close
requests if loading() is true and only clear setDeleteDialog(null) when not
loading, and also disable or no-op the DialogCloseTrigger/click handler when
loading() is true (and similarly prevent backdrop clicks) so that handleDelete
can complete without the UI appearing to cancel the operation.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (2)
packages/web/src/components/admin/StorageManagement.jsxpackages/web/src/components/settings/pages/LinkedAccountsSection.jsx
🧰 Additional context used
📓 Path-based instructions (14)
packages/web/src/**/*.{js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/form-state.mdc)
packages/web/src/**/*.{js,jsx}: Save form state to IndexedDB before initiating OAuth redirects (Google Drive, ORCID) using saveFormState() with form type ('createProject' or 'addStudies') and serializable state only
Only save serializable data to IndexedDB—exclude File objects, ArrayBuffers, functions, and other non-serializable objects from form state persistence
Restore form state after OAuth redirects by checking URL restore params with getRestoreParamsFromUrl(), retrieving saved state with getFormState(), restoring to form, clearing saved state with clearFormState(), and clearing URL params with clearRestoreParamsFromUrl()
For temporary File object storage during OAuth flows (e.g., pending PDFs), use projectStore.setPendingProjectData() instead of IndexedDB, as File objects cannot be serialized
Add restore parameters to the URL after OAuth redirects in the format '?restore=&projectId=' to signal form state restoration on mount
Clear URL restore parameters after form state restoration by calling clearRestoreParamsFromUrl() to prevent stale restoration attempts on subsequent navigation
Form state persistence library functions (saveFormState, getFormState, clearFormState, getRestoreParamsFromUrl, clearRestoreParamsFromUrl) are implemented in packages/web/src/lib/formStatePersistence.js and should be imported from@/lib/formStatePersistence.js
Files:
packages/web/src/components/admin/StorageManagement.jsxpackages/web/src/components/settings/pages/LinkedAccountsSection.jsx
packages/web/src/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)
packages/web/src/**/*.{js,jsx,ts,tsx}: Always useuploadPdffrom@api/pdf-api.jsfor uploading PDF files. Pass object with projectId, studyId, tag ('primary' or 'supplementary'), and fileName
Validate PDF files on frontend by checking file.type includes 'pdf' and file.size is within MAX_PDF_SIZE limit (full validation is done on backend)
UsecachePdfandgetCachedPdffrom@primitives/pdfCache.jsfor caching PDF data in IndexedDB
Implement PDF caching strategy: check cache first, download from server if not cached, then cache the downloaded PDF
Store only PDF metadata in Yjs (id, name, size, tag, uploadedAt, uploadedBy), never store PDF binary data in Yjs as it is too large
UseimportFromGoogleDrivefrom@api/google-drive.jsfor importing PDFs from Google Drive. Pass fileId, projectId, studyId, and tag
Save form state usingsaveFormStatefrom@/lib/formStatePersistence.jsbefore triggering OAuth redirects for Google Drive
UseaddPdfToStudyoperation fromuseProjecthook to add PDFs to a study, passing id, name, size, tag, uploadedAt, and uploadedBy
UseremovePdfFromStudyoperation fromuseProjecthook to remove PDFs from a study
UsepdfPreviewStorefrom@/stores/pdfPreviewStore.jsfor managing PDF preview state (openPreview, closePreview, getPreview methods)
UsedownloadPdffrom@api/pdf-api.jsto download PDFs from server, then cache the result usingcachePdf
Always cache PDFs after download and check cache before downloading to avoid redundant downloads
Use PDF operations fromuseProjecthook instead of bypassing through direct API calls
Files:
packages/web/src/components/admin/StorageManagement.jsxpackages/web/src/components/settings/pages/LinkedAccountsSection.jsx
packages/web/src/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/pdf-handling.mdc)
Use
PdfViewercomponent from@/components/checklist-ui/pdf/PdfViewer.jsxfor displaying PDFs, passing pdfData as ArrayBuffer, fileName, readOnly, and onPageChange
Files:
packages/web/src/components/admin/StorageManagement.jsxpackages/web/src/components/settings/pages/LinkedAccountsSection.jsx
{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)
{packages/web/**,packages/landing/**}/**/*.{jsx,tsx}: NEVER destructure props in SolidJS components - access props directly or wrap in functions to maintain reactivity
Use external stores in packages/web/src/stores/ for shared/cross-feature state instead of prop-drilling
Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities
Create reusable logic in primitives (hooks) in packages/web/src/primitives/ and import them into components
Use Solid's Show component for conditional rendering instead of ternary operators
Use Solid's For component for rendering lists instead of Array.map()
Use the children helper when manipulating props.children in SolidJS componentsUse Show and For components for conditional and list rendering in SolidJS
Files:
packages/web/src/components/admin/StorageManagement.jsxpackages/web/src/components/settings/pages/LinkedAccountsSection.jsx
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/solidjs.mdc)
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}: Use createSignal for simple reactive values in SolidJS components
Use createStore for complex objects and arrays that need granular reactivity in SolidJS
Use createMemo for computed/derived values that depend on reactive state in SolidJS
Always clean up SolidJS effects that create subscriptions or timers using onCleanup
Import stores directly in components and use store read/write action pattern - read from store, write via actions store
Prefer derived state with createMemo or signals over effects whenever possible
Use local createSignal or createStore for local component state; use external stores for shared/cross-feature state
{packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx}: NEVER destructure props in SolidJS components - it breaks reactivity. Access props directly (e.g., props.name) or wrap in a function (e.g., () => props.name)
Store imports should access store data directly from external stores (packages/web/src/stores/) rather than receiving store data via props
Use createSignal for simple, reactive values in SolidJS
Use createStore for complex objects and nested state in SolidJS, with nested updates using setState pattern (e.g., setState('items', items => [...items, newItem]))
Use createMemo for derived/computed values in SolidJS to maintain reactivity
Use local createSignal or createStore for local component state
Components should receive at most 1-5 props for local configuration only
Move business logic to stores, utilities, or SolidJS primitives rather than keeping it in component code
Files:
packages/web/src/components/admin/StorageManagement.jsxpackages/web/src/components/settings/pages/LinkedAccountsSection.jsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/yjs-sync.mdc)
**/*.{js,jsx,ts,tsx}: Use theuseProjecthook for managing Yjs connections with reference counting instead of creating Y.Doc instances directly
Never create Y.Doc instances directly; always use the connection registry managed by useProject
Access Y.Doc connection state via projectStore.getConnectionState(projectId) instead of checking connection state directly
Read Yjs-synced data from projectStore (using getStudies, getChecklist, etc.) rather than accessing Y.Doc maps/arrays directly
Use operation functions from useProject or projectActionsStore for writing data instead of directly modifying Y.Doc
Don't store Y.Doc references in component state; always retrieve the connection through useProject
Handle connection cleanup via onCleanup() in Solid.js components or equivalent cleanup patterns, calling disconnect() when the component unmounts
Files:
packages/web/src/components/admin/StorageManagement.jsxpackages/web/src/components/settings/pages/LinkedAccountsSection.jsx
packages/web/src/**
📄 CodeRabbit inference engine (.cursor/rules/organizations.mdc)
packages/web/src/**: Use human-readable slug in frontend URLs: /orgs/:orgSlug/...
Use orgId (UUID) for API calls, not orgSlug, when making fetch requests to backend endpoints
Files:
packages/web/src/components/admin/StorageManagement.jsxpackages/web/src/components/settings/pages/LinkedAccountsSection.jsx
packages/web/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
packages/web/**/*.{js,ts,jsx,tsx}: UseapiFetchfor all frontend API calls instead of raw fetch to automatically handle JSON parsing, errors, and toast notifications
UsehandleFetchErrorfor wrapping legacy raw fetch calls in frontend code (legacy pattern, prefer apiFetch)
Use error utility functions likeisErrorCodefrom error-utils to check specific error types instead of direct string comparisons
Files:
packages/web/src/components/admin/StorageManagement.jsxpackages/web/src/components/settings/pages/LinkedAccountsSection.jsx
packages/web/**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
Use
createFormErrorSignalsfor form error handling in frontend forms to manage field-level and global error states
Files:
packages/web/src/components/admin/StorageManagement.jsxpackages/web/src/components/settings/pages/LinkedAccountsSection.jsx
packages/{web,workers}/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
Never throw string literals; always throw Error objects or return domain errors from API routes
Files:
packages/web/src/components/admin/StorageManagement.jsxpackages/web/src/components/settings/pages/LinkedAccountsSection.jsx
{packages/web/src/stores/**/*.{js,jsx,ts,tsx},packages/web/src/**/*.{js,jsx,ts,tsx}}
📄 CodeRabbit inference engine (.github/instructions/solidjs.instructions.md)
Shared or cross-feature state should use external stores located in packages/web/src/stores/
Files:
packages/web/src/components/admin/StorageManagement.jsxpackages/web/src/components/settings/pages/LinkedAccountsSection.jsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/corates.mdc)
**/*.{js,ts,jsx,tsx}: Prefer modern ES6+ syntax and features
Comments should explain why something is being done, not what the code is doing
Reserve comments for explaining intent, context, workarounds, assumptions, edge cases, or limitations
Use TODO(agent): prefix for incomplete work or flagged items with brief description and relevant doc references
Files:
packages/web/src/components/admin/StorageManagement.jsxpackages/web/src/components/settings/pages/LinkedAccountsSection.jsx
**/*
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Never use emojis or unicode symbols anywhere in code, comments, documentation, plan files, commit messages, or examples
Files:
packages/web/src/components/admin/StorageManagement.jsxpackages/web/src/components/settings/pages/LinkedAccountsSection.jsx
packages/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
packages/**/*.{ts,tsx,js,jsx}: Prefer modern ES6+ syntax and features
Prefer config files over hardcoding values
Keep files small, focused, and modular - extract large files into sub-modules or separate utilities
Each file should handle one coherent responsibility
Comments should explain WHY something is being done or provide context, not repeat what the code is saying
Do NOT narrate what code is doing, don't duplicate function/variable names in comments, and don't leave stale comments that contradict the code
Use the Agent TODO convention// TODO(agent): Brief descriptionfor incomplete work, flagging items for future attention, known limitations, and documentation section referencesUse TODO(agent) convention with brief description and relevant doc section references for incomplete work or flagged issues
Files:
packages/web/src/components/admin/StorageManagement.jsxpackages/web/src/components/settings/pages/LinkedAccountsSection.jsx
🧠 Learnings (17)
📓 Common learnings
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use Ark UI components from `ark-ui/solid` for UI components
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Use Ark UI component library (`ark-ui/solid`) for UI components
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.507Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Move business logic to stores, utilities, or SolidJS primitives rather than keeping it in component code
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use `solid-icons` icon library for all icon needs
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Create reusable logic in primitives (hooks) in packages/web/src/primitives/ and import them into components
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Use `solid-icons` library for icons (e.g., `solid-icons/bi`, `solid-icons/fi`)
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-17T16:10:07.519Z
Learning: Use required libraries for specific functionality: Zod for validation, Drizzle for database, Better-Auth for authentication, Ark UI for components
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use external stores in packages/web/src/stores/ for shared/cross-feature state instead of prop-drilling
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Do not prop-drill application state in SolidJS components; import stores directly where needed
📚 Learning: 2025-12-27T03:01:54.727Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/form-state.mdc:0-0
Timestamp: 2025-12-27T03:01:54.727Z
Learning: Applies to packages/web/src/components/project-ui/**/*.{js,jsx} : Form state should include serializable metadata when handling files (name, size, type) and use the store's pendingPdfs pattern for actual File objects that persist across redirects
Applied to files:
packages/web/src/components/admin/StorageManagement.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Keep SolidJS components lean and focused on rendering - move business logic to stores, primitives, or utilities
Applied to files:
packages/web/src/components/admin/StorageManagement.jsxpackages/web/src/components/settings/pages/LinkedAccountsSection.jsx
📚 Learning: 2025-12-27T03:02:14.854Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/reconciliation.mdc:0-0
Timestamp: 2025-12-27T03:02:14.854Z
Learning: Applies to packages/web/src/components/checklist-ui/compare/** : Use Y.Text objects for collaborative editing of question notes in reconciliation
Applied to files:
packages/web/src/components/admin/StorageManagement.jsx
📚 Learning: 2026-01-17T00:25:35.702Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/corates.mdc:0-0
Timestamp: 2026-01-17T00:25:35.702Z
Learning: Applies to packages/web/src/**/*.{ts,tsx} : Use `solid-icons` library for icons (e.g., `solid-icons/bi`, `solid-icons/fi`)
Applied to files:
packages/web/src/components/admin/StorageManagement.jsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use `solid-icons` icon library for all icon needs
Applied to files:
packages/web/src/components/admin/StorageManagement.jsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : For UI icons, use `solid-icons` library (e.g., `solid-icons/bi`, `solid-icons/fi`) or SVGs only, never emojis
Applied to files:
packages/web/src/components/admin/StorageManagement.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Create reusable logic in primitives (hooks) in packages/web/src/primitives/ and import them into components
Applied to files:
packages/web/src/components/settings/pages/LinkedAccountsSection.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use external stores in packages/web/src/stores/ for shared/cross-feature state instead of prop-drilling
Applied to files:
packages/web/src/components/settings/pages/LinkedAccountsSection.jsx
📚 Learning: 2026-01-17T00:25:12.507Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.507Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use Show and For components for conditional and list rendering in SolidJS
Applied to files:
packages/web/src/components/settings/pages/LinkedAccountsSection.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createSignal for simple reactive values in SolidJS components
Applied to files:
packages/web/src/components/settings/pages/LinkedAccountsSection.jsx
📚 Learning: 2026-01-17T00:25:12.507Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.507Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createSignal for simple, reactive values in SolidJS
Applied to files:
packages/web/src/components/settings/pages/LinkedAccountsSection.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{jsx,tsx} : Use Solid's Show component for conditional rendering instead of ternary operators
Applied to files:
packages/web/src/components/settings/pages/LinkedAccountsSection.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use createMemo for computed/derived values that depend on reactive state in SolidJS
Applied to files:
packages/web/src/components/settings/pages/LinkedAccountsSection.jsx
📚 Learning: 2025-12-27T03:02:26.947Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .cursor/rules/solidjs.mdc:0-0
Timestamp: 2025-12-27T03:02:26.947Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use local createSignal or createStore for local component state; use external stores for shared/cross-feature state
Applied to files:
packages/web/src/components/settings/pages/LinkedAccountsSection.jsx
📚 Learning: 2026-01-17T00:25:12.507Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/instructions/solidjs.instructions.md:0-0
Timestamp: 2026-01-17T00:25:12.507Z
Learning: Applies to {packages/web/**,packages/landing/**}/**/*.{js,jsx,ts,tsx} : Use local createSignal or createStore for local component state
Applied to files:
packages/web/src/components/settings/pages/LinkedAccountsSection.jsx
📚 Learning: 2026-01-17T16:09:36.904Z
Learnt from: CR
Repo: InfinityBowman/corates PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-01-17T16:09:36.904Z
Learning: Applies to packages/{web,landing}/src/**/*.{ts,tsx} : Use `createMemo` for derived values in SolidJS
Applied to files:
packages/web/src/components/settings/pages/LinkedAccountsSection.jsx
🧬 Code graph analysis (1)
packages/web/src/components/admin/StorageManagement.jsx (1)
packages/web/src/components/ui/dialog.tsx (8)
Dialog(198-198)DialogBackdrop(200-200)DialogPositioner(201-201)DialogContent(202-202)DialogHeader(206-206)DialogTitle(203-203)DialogCloseTrigger(205-205)DialogBody(207-207)
⏰ 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: Workers Builds: corates
🔇 Additional comments (3)
packages/web/src/components/settings/pages/LinkedAccountsSection.jsx (2)
14-28: LGTM - Dialog imports migrated to local Ark UI components.The FiX icon import from
solid-icons/fiand the composed dialog imports from@/components/ui/dialogalign with project conventions. Based on learnings, this follows the pattern of using Ark UI components for the UI library.
373-419: LGTM - Dialog refactored to composed structure with proper accessibility.The dialog migration to the composed Ark UI pattern (DialogBackdrop, DialogPositioner, DialogContent, DialogHeader, DialogTitle, DialogBody, DialogCloseTrigger) is well-structured and consistent with the patterns used elsewhere in the codebase. The accessibility concern from the previous review has been addressed with
aria-label='Close'on the DialogCloseTrigger.packages/web/src/components/admin/StorageManagement.jsx (1)
16-30: Imports align with the new dialog composition.The updated icon and dialog imports look consistent with the new UI primitives.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| <Dialog open={!!deleteDialog()} onOpenChange={open => !open && setDeleteDialog(null)}> | ||
| <DialogBackdrop /> | ||
| <DialogPositioner> | ||
| <DialogContent class='max-w-md'> | ||
| <DialogHeader> | ||
| <DialogTitle>Delete Documents</DialogTitle> | ||
| <DialogCloseTrigger aria-label='Close'> | ||
| <FiX class='h-5 w-5' /> | ||
| </DialogCloseTrigger> | ||
| </DialogHeader> | ||
| <DialogBody> | ||
| <div class='space-y-4'> | ||
| <p class='text-sm text-gray-600'> | ||
| Are you sure you want to delete {deleteDialog()?.length || 0} document | ||
| {deleteDialog()?.length === 1 ? '' : 's'}? This action cannot be undone. | ||
| </p> | ||
| <div class='flex justify-end space-x-3'> | ||
| <button | ||
| onClick={() => setDeleteDialog(null)} | ||
| disabled={loading()} | ||
| class='rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-200 disabled:opacity-50' | ||
| > | ||
| Cancel | ||
| </button> | ||
| <button | ||
| onClick={handleDelete} | ||
| disabled={loading()} | ||
| class='rounded-lg bg-red-600 px-4 py-2 text-sm font-medium text-white hover:bg-red-700 focus:ring-2 focus:ring-blue-500 focus:outline-none disabled:opacity-50' | ||
| > | ||
| {loading() ? 'Deleting...' : 'Delete'} | ||
| </button> | ||
| </div> | ||
| </div> | ||
| </DialogBody> | ||
| </DialogContent> |
There was a problem hiding this comment.
Prevent dialog dismissal while deletion is in progress.
Closing via the close trigger or backdrop while loading() is true can make users think the delete was canceled even though it continues. Consider blocking close while loading.
Proposed change
- <Dialog open={!!deleteDialog()} onOpenChange={open => !open && setDeleteDialog(null)}>
+ <Dialog
+ open={!!deleteDialog()}
+ onOpenChange={open => {
+ if (loading()) return;
+ if (!open) setDeleteDialog(null);
+ }}
+ >🤖 Prompt for AI Agents
In `@packages/web/src/components/admin/StorageManagement.jsx` around lines 419 -
453, The dialog currently allows closing via backdrop or close trigger while
deletion is in progress; update the Dialog open/onOpenChange and the close
trigger behavior so the modal cannot be dismissed when loading() is true: in the
Dialog component, change the onOpenChange handler to ignore close requests if
loading() is true and only clear setDeleteDialog(null) when not loading, and
also disable or no-op the DialogCloseTrigger/click handler when loading() is
true (and similarly prevent backdrop clicks) so that handleDelete can complete
without the UI appearing to cancel the operation.
Summary by CodeRabbit
New Features
UX
Database
Chores
✏️ Tip: You can customize this high-level summary in your review settings.