feat: migration to latest ui components library with file viewer#2281
feat: migration to latest ui components library with file viewer#2281kemuru wants to merge 8 commits into
Conversation
❌ Deploy Preview for kleros-v2-testnet-devtools failed. Why did it fail? →
|
❌ Deploy Preview for kleros-v2-testnet failed. Why did it fail? →
|
❌ Deploy Preview for kleros-v2-neo failed. Why did it fail? →
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughUpgrade UI library to v3, add global library CSS, migrate Field→TextField and event-based onChange→value, remap Button props (disabled→isDisabled, onClick→onPress), reshape Dropdown/Cascader items, migrate timeline/tabs typings, and apply assorted styling and small API fixes. ChangesKleros UI v3 migration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
|
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)
web/src/pages/Resolver/Parameters/Jurors.tsx (1)
81-82:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAvoid rendering
"undefined"in the jurors input.Line 88 stringifies
noOfVotesunconditionally. WhendisputeData.numberOfJurorsisundefined, the field shows"undefined"instead of empty input.💡 Proposed fix
- const noOfVotes = Number.isNaN(disputeData.numberOfJurors) ? "" : disputeData.numberOfJurors; + const noOfVotes = + isUndefined(disputeData.numberOfJurors) || Number.isNaN(disputeData.numberOfJurors) + ? "" + : String(disputeData.numberOfJurors); ... - value={String(noOfVotes)} + value={noOfVotes}Also applies to: 88-88
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/pages/Resolver/Parameters/Jurors.tsx` around lines 81 - 82, The jurors input shows "undefined" because noOfVotes is set using Number.isNaN(disputeData.numberOfJurors) which returns false for undefined; change the assignment so non-numeric or null/undefined values map to an empty string. For example, update the noOfVotes calculation (the noOfVotes variable that reads disputeData.numberOfJurors) to: if typeof disputeData.numberOfJurors === 'number' && !Number.isNaN(disputeData.numberOfJurors) use the numeric value, otherwise use ""; also ensure when rendering you convert only numeric noOfVotes to a string (e.g., noOfVotes === "" ? "" : String(noOfVotes)) so the input never displays "undefined".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/src/components/LabeledInput.tsx`:
- Around line 28-33: The label is using id={label} and the input id is derived
from label text which is unstable; update the LabeledInput component to generate
a stable unique id (use React.useId()) and use that id for the input
(StyledField) and htmlFor on the label (StyledLabel); if props includes an
explicit id respect and use props.id fallback, otherwise generate idFromHook and
use that, and only render StyledLabel with htmlFor when a label exists.
In `@web/src/components/Radio.tsx`:
- Around line 23-33: The radio input's explicit cursor rule overrides the
label's disabled state; update the Radio component styles to set the input's
cursor to not-allowed when disabled (target the input[type="radio"]:disabled
selector inside the Radio component or inside the &:has(input:disabled) block)
so both the label and the actual input show the not-allowed cursor when
disabled, preserving the existing accent-color/size rules and only changing the
cursor for disabled inputs.
In `@web/src/pages/Resolver/Parameters/VotingOptions/OptionsFields.tsx`:
- Around line 56-59: handleOptionWrite is mutating disputeData.answers in place
which can break memoization; instead create a new answers array and a new answer
object for the specific key and call setDisputeData with a new disputeData
object. Concretely, in handleOptionWrite copy disputeData.answers (e.g., const
newAnswers = [...disputeData.answers]), replace newAnswers[key] with a
shallow-copied updated object, then call setDisputeData({ ...disputeData,
answers: newAnswers }) to avoid mutating answers by reference.
---
Outside diff comments:
In `@web/src/pages/Resolver/Parameters/Jurors.tsx`:
- Around line 81-82: The jurors input shows "undefined" because noOfVotes is set
using Number.isNaN(disputeData.numberOfJurors) which returns false for
undefined; change the assignment so non-numeric or null/undefined values map to
an empty string. For example, update the noOfVotes calculation (the noOfVotes
variable that reads disputeData.numberOfJurors) to: if typeof
disputeData.numberOfJurors === 'number' &&
!Number.isNaN(disputeData.numberOfJurors) use the numeric value, otherwise use
""; also ensure when rendering you convert only numeric noOfVotes to a string
(e.g., noOfVotes === "" ? "" : String(noOfVotes)) so the input never displays
"undefined".
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d591b8fd-b856-4877-9e8a-6a1a2c432cbe
📒 Files selected for processing (71)
web/package.jsonweb/src/app.tsxweb/src/components/CasesDisplay/Filters.tsxweb/src/components/CasesDisplay/Search.tsxweb/src/components/ClaimPnkButton.tsxweb/src/components/ConnectWallet/index.tsxweb/src/components/DisputeFeatures/Features/GatedErc1155.tsxweb/src/components/DisputeFeatures/Features/GatedErc20.tsxweb/src/components/DisputeFeatures/Features/index.tsxweb/src/components/EnsureAuth.tsxweb/src/components/FileViewer/Viewers/MarkdownViewer.tsxweb/src/components/FileViewer/index.tsxweb/src/components/LabeledInput.tsxweb/src/components/LightButton.tsxweb/src/components/Loader.tsxweb/src/components/NumberInputField.tsxweb/src/components/Radio.tsxweb/src/components/Verdict/DisputeTimeline.tsxweb/src/hooks/queries/useCourtTree.tsweb/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/FormContact.tsxweb/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/index.tsxweb/src/layout/Header/navbar/Menu/Settings/index.tsxweb/src/pages/AttachmentDisplay/index.tsxweb/src/pages/Cases/CaseDetails/Appeal/Classic/Fund.tsxweb/src/pages/Cases/CaseDetails/Appeal/OptionCard.tsxweb/src/pages/Cases/CaseDetails/Appeal/Shutter/Fund.tsxweb/src/pages/Cases/CaseDetails/Evidence/EvidenceSearch.tsxweb/src/pages/Cases/CaseDetails/Evidence/SubmitEvidenceModal.tsxweb/src/pages/Cases/CaseDetails/MaintenanceButtons/DistributeRewards.tsxweb/src/pages/Cases/CaseDetails/MaintenanceButtons/DrawButton.tsxweb/src/pages/Cases/CaseDetails/MaintenanceButtons/ExecuteRuling.tsxweb/src/pages/Cases/CaseDetails/MaintenanceButtons/PassPeriodButton.tsxweb/src/pages/Cases/CaseDetails/MaintenanceButtons/SetJurorsButton.tsxweb/src/pages/Cases/CaseDetails/MaintenanceButtons/WithdrawAppealFees.tsxweb/src/pages/Cases/CaseDetails/Tabs.tsxweb/src/pages/Cases/CaseDetails/Voting/Classic/Reveal.tsxweb/src/pages/Cases/CaseDetails/Voting/OptionsContainer.tsxweb/src/pages/Cases/CaseDetails/Voting/Shutter/Reveal.tsxweb/src/pages/Cases/CaseDetails/Voting/VotingHistory.tsxweb/src/pages/Courts/CourtDetails/Description.tsxweb/src/pages/Courts/CourtDetails/JurorsStakedByCourt/Search.tsxweb/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsxweb/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawPopup/index.tsxweb/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawPopup/stakeSteps.tsxweb/src/pages/Courts/CourtDetails/StakingHistoryByCourt/Search.tsxweb/src/pages/Courts/CourtDetails/TopSearch.tsxweb/src/pages/Courts/StakeMaintenanceButton/ExecuteDelayedStakeButton.tsxweb/src/pages/Courts/StakeMaintenanceButton/PassPhaseButton.tsxweb/src/pages/Home/CourtOverview/Chart.tsxweb/src/pages/Home/CourtOverview/ExtraStats.tsxweb/src/pages/Jurors/Search.tsxweb/src/pages/Jurors/StatsAndFilters.tsxweb/src/pages/Profile/JurorCard/BottomContent/Coherence.tsxweb/src/pages/Profile/Votes/StatsAndFilters/Filters.tsxweb/src/pages/Profile/index.tsxweb/src/pages/Resolver/Briefing/Title.tsxweb/src/pages/Resolver/Landing/CreationCard.tsxweb/src/pages/Resolver/Landing/index.tsxweb/src/pages/Resolver/NavigationButtons/NextButton.tsxweb/src/pages/Resolver/NavigationButtons/SubmitBatchDisputesButton.tsxweb/src/pages/Resolver/NavigationButtons/SubmitDisputeButton.tsxweb/src/pages/Resolver/Parameters/Category.tsxweb/src/pages/Resolver/Parameters/Court/index.tsxweb/src/pages/Resolver/Parameters/Jurors.tsxweb/src/pages/Resolver/Parameters/NotablePersons/PersonFields.tsxweb/src/pages/Resolver/Parameters/VotingOptions/OptionsFields.tsxweb/src/pages/Resolver/Parameters/VotingOptions/index.tsxweb/src/pages/Resolver/Preview/BatchCreationCard.tsxweb/src/styles/styled.d.tsweb/src/styles/themes.tsweb/src/utils/uiComponentsTypes.ts
💤 Files with no reviewable changes (3)
- web/src/components/FileViewer/Viewers/MarkdownViewer.tsx
- web/src/components/FileViewer/index.tsx
- web/src/styles/themes.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/src/pages/AttachmentDisplay/index.tsx`:
- Line 16: The lazy-loaded FileViewer (const FileViewer = lazy(...)) can throw
on chunk load failures and currently only has Suspense for loading; wrap the
Suspense subtree (where FileViewer is rendered) with an ErrorBoundary component
to catch import/rejection errors and render a fallback UI. Add or reuse an
ErrorBoundary component (or create one) and place it as the parent of the
Suspense that renders FileViewer so any lazy import failures are caught and
handled instead of crashing the tree.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 01996863-7c8e-4d49-95b6-d9ce75a6910d
📒 Files selected for processing (1)
web/src/pages/AttachmentDisplay/index.tsx
| label: string; | ||
| } | ||
|
|
||
| const Radio: React.FC<RadioProps> = ({ label, small, className, ...props }) => ( |
There was a problem hiding this comment.
Use the Radio component exported by the library
There was a problem hiding this comment.
v3 still exports Radio, but it now points to the RadioGroup component — there's no single-radio component behind that name anymore. So import { Radio } gives you a group control (single-select, options: { label }[]), and although RadioOption extends AriaRadioProps so the type looks like it accepts children, the component overwrites children with its own circle+label renderer, so only the label string ever shows — there's no slot for custom per-item content. That's the blocker here, because all three places this is used need exactly that: the dispute-feature picker (Court step) wraps each option in a help tooltip and renders a token-address TextField under the gated ERC-20/1155 options, the appeal OptionCard puts the indicator inside a card with a funding progress bar (its input is even display:none, so the card is the click target), and CreationCard is a rich icon/title/description card with a case-ID field. So this local component keeps the single-radio contract those cases need, rather than the group component.
| content: null, | ||
| }))} | ||
| callback={(i: number) => setCurrentTab(i)} | ||
| callback={(_key, value) => setCurrentTab(value)} |
There was a problem hiding this comment.
If not needed externally, we can let Tab handle the currentTab itself
There was a problem hiding this comment.
if not needed externally condition doesn't hold here: currentTab feeds PendingVotesBox, VotesAccordion, the drawnJurors memo and isHiddenVotes, and the useEffect that auto-jumps to the latest round needs to set the selected tab, which only controlled selectedKey allows (defaultSelectedKey can't). So letting Tab own it would break the auto-latest-round behavior.
did the equivalent simplification on CaseDetails/Tabs instead, where the value isn't needed externally.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/src/components/LabeledInput.tsx`:
- Around line 28-33: LabeledInput currently overwrites any caller-provided
inputProps by setting inputProps={{ id: inputId, dir: "auto" }} on StyledField;
instead, merge the caller's inputProps with the injected id/dir so existing
properties are preserved. Locate the LabeledInput component (inputId) and change
the StyledField prop to combine props.inputProps (or props.inputProps ?? {})
with { id: inputId, dir: "auto" } before passing it to StyledField, ensuring
other props from callers remain intact.
In `@web/src/styles/base-elements.css`:
- Around line 58-64: The global CSS rule for the selector "a" in
base-elements.css removes the underline and relies solely on color, which breaks
accessibility; restore a non-color affordance by removing the blanket
text-decoration:none from the global "a" rule (or restrict that removal to a
specific utility class like ".no-underline"), and ensure links retain an
underline or another clear non-color indicator (and visible focus/hover styles)
so that the "a" rule, focus states, and any new ".no-underline" utility behave
accessibly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ad550fb5-7d85-4bb1-a495-3e7b787fd7fd
📒 Files selected for processing (69)
web/src/app.tsxweb/src/components/CaseStarButton.tsxweb/src/components/CasesDisplay/Filters.tsxweb/src/components/ClaimPnkButton.tsxweb/src/components/ConnectWallet/index.tsxweb/src/components/DisputeFeatures/GroupsUI.tsxweb/src/components/EnsureAuth.tsxweb/src/components/ErrorFallback.tsxweb/src/components/ExternalLinkWarning.tsxweb/src/components/Field.tsxweb/src/components/LabeledInput.tsxweb/src/components/LightButton.tsxweb/src/components/Popup/Description/SwapSuccess.tsxweb/src/components/Popup/index.tsxweb/src/components/Tag.tsxweb/src/components/Verdict/DisputeTimeline.tsxweb/src/index.htmlweb/src/layout/Header/DesktopHeader.tsxweb/src/layout/Header/MobileHeader.tsxweb/src/layout/Header/navbar/Menu/Settings/General/index.tsxweb/src/layout/Header/navbar/Menu/Settings/Notifications/FormContactDetails/EmailVerificationInfo.tsxweb/src/layout/Header/navbar/Menu/Settings/index.tsxweb/src/layout/Header/navbar/Menu/index.tsxweb/src/layout/Header/navbar/index.tsxweb/src/pages/AttachmentDisplay/Header.tsxweb/src/pages/AttachmentDisplay/index.tsxweb/src/pages/Cases/CaseDetails/Appeal/Classic/Fund.tsxweb/src/pages/Cases/CaseDetails/Appeal/OptionCard.tsxweb/src/pages/Cases/CaseDetails/Appeal/Shutter/Fund.tsxweb/src/pages/Cases/CaseDetails/Evidence/EvidenceSearch.tsxweb/src/pages/Cases/CaseDetails/Evidence/SubmitEvidenceModal.tsxweb/src/pages/Cases/CaseDetails/Evidence/index.tsxweb/src/pages/Cases/CaseDetails/MaintenanceButtons/DistributeRewards.tsxweb/src/pages/Cases/CaseDetails/MaintenanceButtons/DrawButton.tsxweb/src/pages/Cases/CaseDetails/MaintenanceButtons/ExecuteRuling.tsxweb/src/pages/Cases/CaseDetails/MaintenanceButtons/PassPeriodButton.tsxweb/src/pages/Cases/CaseDetails/MaintenanceButtons/SetJurorsButton.tsxweb/src/pages/Cases/CaseDetails/MaintenanceButtons/WithdrawAppealFees.tsxweb/src/pages/Cases/CaseDetails/Tabs.tsxweb/src/pages/Cases/CaseDetails/Timeline.tsxweb/src/pages/Cases/CaseDetails/Voting/Classic/Reveal.tsxweb/src/pages/Cases/CaseDetails/Voting/OptionsContainer.tsxweb/src/pages/Cases/CaseDetails/Voting/Shutter/Reveal.tsxweb/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsxweb/src/pages/Cases/CaseDetails/Voting/VotesDetails/index.tsxweb/src/pages/Cases/CaseDetails/Voting/VotingHistory.tsxweb/src/pages/Courts/CourtDetails/Description.tsxweb/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsxweb/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawPopup/index.tsxweb/src/pages/Courts/CourtDetails/Stats/index.tsxweb/src/pages/Courts/StakeMaintenanceButton/ExecuteDelayedStakeButton.tsxweb/src/pages/Courts/StakeMaintenanceButton/PassPhaseButton.tsxweb/src/pages/Home/CourtOverview/Chart.tsxweb/src/pages/Home/CourtOverview/ExtraStats.tsxweb/src/pages/Home/CourtOverview/Header.tsxweb/src/pages/Jurors/StatsAndFilters.tsxweb/src/pages/Profile/Votes/StatsAndFilters/Filters.tsxweb/src/pages/Profile/index.tsxweb/src/pages/Resolver/Landing/index.tsxweb/src/pages/Resolver/NavigationButtons/NextButton.tsxweb/src/pages/Resolver/NavigationButtons/PreviousButton.tsxweb/src/pages/Resolver/NavigationButtons/SubmitBatchDisputesButton.tsxweb/src/pages/Resolver/NavigationButtons/SubmitDisputeButton.tsxweb/src/pages/Resolver/Parameters/VotingOptions/OptionsFields.tsxweb/src/pages/Resolver/Timeline.tsxweb/src/styles/base-elements.cssweb/src/styles/global-style.tsweb/src/styles/themes.tsweb/src/utils/uiComponentsTypes.ts
💤 Files with no reviewable changes (1)
- web/src/utils/uiComponentsTypes.ts
✅ Files skipped from review due to trivial changes (6)
- web/src/app.tsx
- web/src/layout/Header/navbar/Menu/Settings/General/index.tsx
- web/src/pages/Home/CourtOverview/Header.tsx
- web/src/pages/Cases/CaseDetails/Voting/VotesDetails/AccordionTitle.tsx
- web/src/pages/Cases/CaseDetails/Timeline.tsx
- web/src/pages/Resolver/Timeline.tsx
|


needs also:
Summary by CodeRabbit
New Features
Bug Fixes
Improvements
Chores
PR-Codex overview
This PR primarily focuses on updating various components to replace
onClickevent handlers withonPressfor better consistency across the codebase. Additionally, it involves styling adjustments, component imports, and the transition to usingTextFieldinstead ofField.Detailed summary
onClickwithonPressin multiple components.Fieldcomponent toTextFieldin several instances.