build: raise frontend TypeScript to 6.0 - #1707
Draft
shivoomiess wants to merge 27 commits into
Draft
Conversation
- Migrate ChangeExperimentSafetyStatus Grid to MUI v6 size API - Wrap material-table action icons as function components for MUI v9 icon type compatibility - Move Typography fontWeight to sx (MUI v9) - Remove unused isSchedulerEnabled in OverviewPage - Apply prettier formatting from Grid codemod
The CI build failed with "Cannot find module @rollup/rollup-linux-x64-gnu". The lockfile had been regenerated on an arm64 Mac in a way that recorded only the darwin-arm64 optional dependency of every package that ships prebuilt binaries, so `npm ci` on ubuntu had no Linux binary to install. Restores the 92 missing entries across four families - @rollup/rollup-* (4.59.0), @esbuild/* (0.21.5), @unrs/resolver-binding-* (1.11.1, two trees) and @napi-rs/canvas-* (0.1.97) - taking version, resolved and integrity from develop's lockfile, which pins the identical versions and is installed by CI on every build. Restoring the entries rather than regenerating the lockfile is deliberate: a full regeneration drifted 230 unrelated packages (pdfjs-dist, graphql, luxon, eslint, x-date-pickers among them), which does not belong in a MUI upgrade. The diff is additions only - no existing entry changed or removed, and the relative order of existing keys is preserved. Verified with `npm ci` + `npm run build` in a linux/amd64 Node 22 container, matching the failing CI job.
…user-office-core into chore/mui-upgrade-pt1
MenuItem calls useMenuListContext() on every render, and in v9 that throws
"MUI: MenuListContext is missing. MenuItems must be placed within Menu or
MenuList." when no provider is present (MenuList/MenuListContext.js). The throw
sits outside the NODE_ENV guard, so it fires in production too.
Autocomplete renders its listbox as a plain styled('ul') with no such provider,
so both call sites threw:
- ProposalPeopleSelectorModal returned a MenuItem from renderOption, so every
option that rendered crashed the modal.
- NoOptionsText returned one for an exact email match.
Both now use ListItemButton. renderOption also passes component="li" so the
option stays a valid child of the listbox <ul>; the spread `props` already
carries the role, id and event handlers Autocomplete needs.
Reached via PrincipalInvestigator and UserManagementTable, so this covers
co-proposers, data access users, visit registration and the proposal basis
questionary component.
The WIP commit replaced the entire UserRole.USER dashboard with a copy of
Material UI's Accordion demo. components/proposalBooking/BasicCard.tsx does not
exist on develop, still exports a component named ControlledAccordions, and
renders the docs' placeholder copy verbatim ("I am an accordion", "You are
currently not an owner", "Filtering has been entirely disabled for whole web
server").
Users therefore saw four sample accordions instead of:
- ProposalTableUser, their proposal list
- UserUpcomingExperimentsTable, gated on the SCHEDULER feature flag
Restores OverviewPage.tsx to develop's version and deletes BasicCard.tsx.
Nothing else referenced it. develop has not touched OverviewPage.tsx since the
branch point, so this is a clean revert rather than a merge.
Neither restored component needed migrating: both are free of v5-only APIs and
neither was modified anywhere on this branch.
This was scratch work rather than part of the v9 migration, which is why it is
separated out. Note that the merge commit's "Remove unused isSchedulerEnabled in
OverviewPage" was a consequence of this change, not an unrelated tidy-up.
inputProps={{ maxLength: '20' }}
-> slotProps={{ htmlInput: { maxLength: '20' } }}
docs:
old https://v5.mui.com/material-ui/api/text-field/#text-field-prop-inputProps
new https://mui.com/material-ui/api/text-field/#text-field-prop-slotProps
migration guide https://mui.com/material-ui/migration/migrating-from-deprecated-apis/
Material UI v9 removed `inputProps` from TextField. TextField.js:111-112
destructures only `slots` and `slotProps`; everything else falls into `...other`,
which TextField.js:165-171 forwards to the root slot, TextFieldRoot =
styled(FormControl) (TextField.js:42-45). So the object landed on the wrapper
<div> and never reached the <input>.
Nothing caught this. The type dropped the prop, but Formik's Field renders
`createElement(component, { field, form, ...props })`
(formik.cjs.development.js:1383) and forwards extra props verbatim without
checking them against the target component, so `tsc --noEmit` stayed green.
components/common/FormikUITextField.tsx:34 then spreads them on unchanged.
82 sites across 37 files: 79 written as <Field component={TextField}>, and 3 as
<Field component={TextFieldNoSubmit}>, where TextFieldNoSubmit is
withPreventSubmit(TextField) in all three files and forwards to the same place.
What this restores:
- maxLength on 4 fields, where limits had stopped being enforced:
CallGeneralInfo.tsx (20 and 100), CallNotificationAndCycleInfo.tsx (100),
TemplateTopicEditor.tsx (32)
- min on 4 sample-count fields in the sample declaration question editors
- data-cy on 70 inputs the e2e suite selects on
- onChange/onBlur handlers on 3 questionary basis components
Applied with a jscodeshift transform rather than by hand or with
`@mui/codemod deprecations/text-field-props`: that codemod matches JSX elements
named TextField, and this codebase has none carrying the prop - the element is
always Field.
Existing slotProps entries take precedence, so any hand-migrated call site is
left untouched.
InputProps={{ endAdornment: <IconButton …/> }}
-> slotProps={{ input: { endAdornment: <IconButton …/> } }}
docs:
old https://v5.mui.com/material-ui/api/text-field/#text-field-prop-InputProps
new https://mui.com/material-ui/api/text-field/#text-field-prop-slotProps
migration guide https://mui.com/material-ui/migration/migrating-from-deprecated-apis/
Same mechanism as the previous commit: v9's TextField does not destructure
InputProps, so it fell through to the root FormControl.
Note this maps to `input`, not `htmlInput`. On TextField the `input` slot is the
InputBase and `htmlInput` is the element itself (TextField.d.ts:65 and :75,
TextField.js:184 and :195). Adornments are React nodes rendered by the InputBase,
so they belong on `input`.
16 sites across 9 files, carrying: 8 data-cy, 3 endAdornment, 1 startAdornment,
5 nested inputProps objects, and one minRows/maxRows pair.
The one clearly user-visible loss was in CallGeneralInfo.tsx: the help button
opening the reference-number-format dialog sits inside InputProps.endAdornment,
so the whole IconButton was unrendered and the dialog unreachable from that
screen. The rest are test hooks and adornments in CreateUnit,
TemplateMetadataEditor, CreateUpdateApiAccessToken, ProposalAdmin, the file
upload question editors and QuestionDynamicMultipleChoiceForm.
Deliberately excluded: the 22 InputProps call sites on <FormikUIAutocomplete>.
That is not MUI's prop - the component declares InputProps in its own props
interface (FormikUIAutocomplete.tsx:105), destructures it (:119) and already
forwards it into slotProps.input correctly (:154-158). Renaming those would have
broken working code, since the wrapper does not accept slotProps. This is also
why the eight RefreshListIcon adornments in CallGeneralInfo.tsx are untouched:
they are on FormikUIAutocomplete and were never broken.
InputLabelProps={{ shrink: true }}
-> slotProps={{ inputLabel: { shrink: true } }}
docs:
old https://v5.mui.com/material-ui/api/text-field/#text-field-prop-InputLabelProps
new https://mui.com/material-ui/api/text-field/#text-field-prop-slotProps
migration guide https://mui.com/material-ui/migration/migrating-from-deprecated-apis/
`InputLabelProps` does not appear anywhere in v9's TextField.js, so it fell
through to the root FormControl like the other two. Every site passed
`shrink: true`, which forces the label to stay floated; without it the label
drops back over the field's value.
Three sites migrated mechanically: ExperimentSafetyReviewPage.tsx:77 and
QuestionaryComponentProposalBasis.tsx:109,142.
Two more needed a different shape. QuestionaryComponentVisitBasis.tsx:56,83 pass
the prop to components/common/FormikUIDatePicker, which spreads unknown props
straight through to the MUI X picker, where a bare InputLabelProps is not a prop
at all. Both already had the wrapper's `textField` prop, so the label props nest
inside it:
textField={{ fullWidth: true, required: true }}
InputLabelProps={{ shrink: true }}
-> textField={{
fullWidth: true,
required: true,
slotProps: { inputLabel: { shrink: true } },
}}
That resolves to slotProps.textField.slotProps.inputLabel on the picker, since
the wrapper spreads `textField` into the picker's textField slot
(FormikUIDatePicker.tsx:41-52).
pickers reference https://mui.com/x/migration/migration-pickers-v7/
inputProps={{ 'data-cy': 'includeTime' }}
-> slotProps={{ input: { 'data-cy': 'includeTime' } }}
docs:
old https://v5.mui.com/material-ui/api/checkbox/#checkbox-prop-inputProps
new https://mui.com/material-ui/api/checkbox/#checkbox-prop-slotProps
migration guide https://mui.com/material-ui/migration/migrating-from-deprecated-apis/
Note the slot differs from TextField. Checkbox has no InputBase, so its `input`
slot is the html element itself (Checkbox.d.ts:19-21, "the component that renders
the input slot, default SwitchBase's input"). On TextField the same payload would
belong on `htmlInput`, because there `input` is the InputBase. Sending these to
`input` on a TextField, or `htmlInput` on a Checkbox, reintroduces the same bug
in a new spelling.
internal/SwitchBase.js, which Checkbox wraps, contains zero occurrences of
inputProps - it destructures only slots and slotProps - so the attribute fell
through to the root and never reached the element.
11 sites across 7 files, all reached through components/common/
FormikUICheckboxWithLabel. That wrapper needs no change: its props extend
Omit<MuiCheckboxProps, ...>, so slotProps is already in its surface, and it
spreads through to MuiCheckbox at line 44.
Both spellings appeared - `inputProps` at 7 sites and `InputProps` at 4 - and
both mean the html input here, so both map to `input`. No element carried both,
so nothing was merged.
Restores 10 data-cy attributes the e2e suite selects on, and one aria-label at
FapGeneralInfo.tsx:135.
ListboxProps={{ 'data-cy': props['data-cy'] + '-options' }}
-> slotProps={{ listbox: { 'data-cy': props['data-cy'] + '-options' } }}
docs:
old https://v5.mui.com/material-ui/api/autocomplete/#autocomplete-prop-ListboxProps
new https://mui.com/material-ui/api/autocomplete/#autocomplete-prop-slotProps
migration guide https://mui.com/material-ui/migration/migrating-from-deprecated-apis/
One site, FormikUIAutocomplete.tsx:171, but it is the hook every Autocomplete
dropdown assertion in the e2e suite selects on, since the wrapper derives it from
each call site's own data-cy.
v9 removed the prop. The two remaining `ListboxProps` matches in v9's
Autocomplete.js (:491, :591) are `getListboxProps`, an internal hook from
useAutocomplete, not the prop - it is neither destructured from props nor present
in Autocomplete.d.ts as one. The listbox itself is a plain styled('ul')
(Autocomplete.js:334).
The recast printer also reflowed the unrelated AutocompleteProps interface
declaration above; that has been reverted by hand so the diff is the one prop.
inputProps={{ placeholder: dateFormat }}
-> removed, no replacement
docs:
old https://v5.mui.com/x/api/date-pickers/date-picker/
new https://mui.com/x/migration/migration-pickers-v7/
field structure https://mui.com/x/react-date-pickers/custom-field/
Unlike the other categories this is a deletion, not a migration, for two
independent reasons.
The props were never arriving. DatePicker.js contains zero occurrences of
`inputProps`, so the picker does not destructure it. The app passed it through
components/common/FormikUIDatePicker, which spreads unknown props straight on to
the picker, where it was discarded.
And there is nothing left for them to do. Since the accessible field structure
became the default, the visible field is a PickersSectionList of styled elements
rather than an <input> (PickersInputBase.js:401), with a separate aria-hidden
input for form semantics at :435. `placeholder` is an HTML attribute that only
has an effect on an <input>. The picker already renders the format itself from
the `format` prop these call sites pass, and PickersInputBase.js:102-136 governs
when those empty-state sections are visible: hidden when a label sits unshrunk in
the field, shown otherwise. So deleting the prop changes nothing at runtime.
16 sites across 6 files: CallGeneralInfo, CallNotificationAndCycleInfo,
CallReviewsInfo, QuestionDateForm, QuestionaryComponentDatePicker and
QuestionaryComponentVisitBasis.
Includes the sites written as <Field component={component}> where
`component = includeTime ? DateTimePicker : DatePicker` (QuestionDateForm.tsx:79),
which is why hosts are resolved from the AST rather than by matching the tag name.
The transform only removes the attribute when `placeholder` is its only key, so
any picker carrying something else alongside it is left alone. All 16 qualified;
the diff is deletions only.
Related upstream, for cases where the empty-state sections stay hidden when users
expect them: mui/mui-x#18996
@mui/x-date-pickers ^9.9.0 -> ^9.10.1 This is the only MUI-related package with an upgrade available. @mui/material, @mui/icons-material and @mui/system are all already at 9.2.0, which is latest, and @emotion/react 11.14.0 / @emotion/styled 11.14.1 are likewise current. Lockfile drift is limited to @mui/x-date-pickers and its @mui/x-internals dependency; no other package changed. npm pkg set also moved the two @emotion entries into alphabetical order, where they had been inserted out of sequence. Also brings the range up to what @material-table/core@8 requires (^9.10.0), should that upgrade happen later. This does NOT resolve the outstanding peer dependency conflict: @mui/system@9.2.0 deduped invalid: "^5.8.0" from node_modules/@material-table/core/node_modules/@mui/x-date-pickers No version of the v9 packages can satisfy it. @material-table/core@6.4.4 depends on @mui/x-date-pickers@^6.19.0, whose peer range is @mui/system ^5.8.0, so npm installs a second MUI v5 tree underneath it. The only two ways out are pinning @mui/material and @mui/system through npm `overrides`, or upgrading @material-table/core to v8 - which requires React 19 and so is a much larger piece of work. Everything else npm reports is UNMET OPTIONAL DEPENDENCY for picker date adapters this app does not use (dayjs, moment, date-fns-jalali and similar). Those are expected and not a problem. Verified with tsc --noEmit and a production build.
notistack v3 renders its own wrapper instead of a MuiSnackbar and names the content element notistack-MuiContent-<variant>, so both the ancestor and the target of these rules had stopped matching and toasts fell back to notistack's own colours. Also corrects variantInformation, which is spelled info by notistack and looks to have never matched.
The accessible picker field is the only DOM structure from @mui/x-date-pickers v8 onward, so the input these helpers targeted is now aria-hidden and cannot be typed into. setDatePickerValue types into the section spans instead, and clearDatePickerValue joins it for the cases that clear a field to trigger validation. Also updates three selectors that MUI renamed or restructured: v9 renders step connectors inside each Step rather than as siblings, so the studio selector in samples.cy.ts had shifted onto the wrong step; the autocomplete tag attribute is now data-item-index; and the notistack success class is notistack-MuiContent-success.
Material UI v9 renamed the Tabs slot to MuiTabs-list, so the parent in these selectors no longer exists. The horizontal-tab-N ids come from SimpleTabs rather than from MUI, so dropping the class is enough and leaves nothing coupled to MUI internals. These tests are feature flag gated and skipped in CI, which is why the upgrade did not surface this.
The min, max and default date fields on the Date question config were still typed into directly, addressed by data-cy rather than by name, which is why the first sweep missed them. calls.cy.ts asserted on the TYPE_ERR_INVALID_DATE typeError after clearing a date. The accessible picker field cannot hold a malformed date and reports an incomplete field as having no value, so an emptied field now fails the required rule instead. The test still covers what it is named for, that validation blocks the next step.
Removes `fullWidth` and `inputProps={{ 'data-cy': 'dependencies' }}` from the
<Field> at QuestionDependencyList.tsx:145.
Not a Material UI v9 issue. FormikUICustomDependencySelector destructures a
closed list of five props - field, template, form, dependency, currentQuestionId
(FormikUICustomDependencySelector.tsx:25-32) - with no rest element. Formik
forwards everything except validate/name/render/children/as/component/className
verbatim (formik.cjs.development.js:1314-1320, :1383-1389), so both props arrived
at the component and were discarded at the destructure, one frame in. They never
reached Material UI at all.
They have never worked. `git log -S` puts the line in f5e2d5f (Sept 2023), a
folder-renaming refactor, long predating the v9 work.
Nothing depends on the missing hook. No spec selects [data-cy="dependencies"].
The component renders its own hooks instead - dependencyField, dependencyOperator
and dependencyValue - and those are the ones the suite uses, in 2 and 3 spec
files respectively.
Kept separate from the slotProps migration commits deliberately: this looks like
the same breakage, but migrating it to slotProps would have changed nothing,
since the prop is dropped before Material UI sees it.
One call site only. tsc --noEmit clean.
inputProps={{ type: 'number', min, max, step, inputMode }}
-> slotProps={{ htmlInput: { … } }} on the TextField branch only
docs:
old https://v5.mui.com/material-ui/api/text-field/#text-field-prop-inputProps
new https://mui.com/material-ui/api/text-field/#text-field-prop-slotProps
select (unchanged) https://mui.com/material-ui/api/select/#select-prop-inputProps
The grade field switches component on whether the grade is picked from a list:
a classification, or a whole-number grade, renders a Select; anything else
renders a TextField. The same condition drove a matching `inputProps` ternary.
Only the TextField branch was broken. Material UI v9 removed inputProps from
TextField in 9.0.0-alpha.4, so the object fell through to the root FormControl
and the numeric field lost:
type="number" rendered as a plain text box, no stepper
inputMode="decimal" mobile keyboards showed the alphabetic layout
min="1" / max="10" the grade bound was unenforced
step decimal precision from config.decimalPoints unconstrained
id="grade-proposal" labelId="grade-proposal-label" no longer resolved to it
Select was not converted to slots and still takes inputProps - confirmed against
Select.js:65,113,138 (zero occurrences of slotProps in the .js or the .d.ts), the
shipped CHANGELOG, where the only [select] removals are CSS classes and props
passed via MenuProps, and mui.com, which documents inputProps with no deprecation
notice and lists no slots section. So the two branches need different prop names,
not just different slot keys, which is why a rename could not fix this and the
jscodeshift pass skipped it: the host was a ternary it could not resolve.
Hoists the duplicated condition into `isGradePickedFromList`. It was written out
twice, once for `component` and once for `inputProps`, which is what let the two
drift apart in the first place.
Not verified in a browser. tsc --noEmit clean.
Pure refactor, no behaviour change.
The grade field makes one decision - is the grade picked from a list, or typed -
and that decision was spelled out three separate ways in the same element:
component={gradeType === 'Classification' || decimalPoints === 0 ? … }
inputProps={gradeType === 'Classification' || decimalPoints === 0 ? … }
options={gradeType === 'Classification' ? … : decimalPoints === 0 ? … : undefined}
The first two were collapsed into `isGradePickedFromList` in the previous commit.
This does the third: `gradeOptions` is now derived alongside it, so all three read
from the same predicate. That divergence is what let the component and its input
attributes drift out of step and produce the bug the previous commit fixed.
Equivalence, since the branches are reordered: options were non-undefined exactly
when Classification, or decimalPoints === 0 - which is the definition of
isGradePickedFromList. So `!isGradePickedFromList -> undefined` first, then
Classification, then the whole-number list, covers the same three cases.
Also lifts the 1-to-10 list to a module constant. It never depended on props or
state but was rebuilt on every render, via `[...Array(10)].map((e, i) => …)` with
an unused first parameter. Now Array.from({ length: 10 }, (_, i) => …) at module
scope.
The `label` ternary is left alone; it keys off gradeType only, not the compound
condition, and flattening the layout is a separate change.
tsc --noEmit clean.
Behaviour-neutral. Renders the Select and the TextField as separate elements under `isGradePickedFromList` instead of one <Field> that switched component and carried both sets of props at once. Before, roughly half the props on that element were inert whichever branch ran. `MenuProps`, `labelId` and `options` mean nothing to TextField; the numeric input attributes mean nothing to Select. Nothing kept the component and its props in step, which is exactly how they drifted apart and produced the bug fixed in e14e36b. After the split each element carries only props its own component accepts, so that class of drift is structurally impossible rather than merely absent. Shared values are hoisted rather than duplicated: `gradeLabel` and `handleGradeChange`. `gradeInputProps` is gone - the conditional prop object only existed to paper over the single element, and each branch now states its own directly. One prop is deliberately not carried across. `formControl={{ fullWidth: true, required: true, margin: 'normal' }}` is FormikUISelect's own prop, declared at FormikUISelect.tsx:19, destructured at :69 and applied to its FormControl at :98. FormikUITextField has no such prop and neither does MUI's TextField - zero occurrences in TextField.d.ts - so on the numeric branch it was already being dropped onto the root and discarded. Copying it into the new TextField element would carry dead code into new code, so it stays on the Select branch only. That means the numeric grade field has no fullWidth, no required and no margin="normal" - as was already the case. Restoring them is a visible change and is left as a separate decision rather than folded into a refactor. tsc --noEmit clean. Not verified in a browser.
setDatePickerValue ended its chain on the section span it had just typed into,
so the three `should('have.value', ...)` assertions chained onto it in
calls.cy.ts were reading an element that carries no value at all. The value the
form submits lives on the aria-hidden input, so yield that instead.
templateDeleteAndArchive was the one visit-registration site the v9 picker pass
missed: it still cleared and typed straight into the picker input, which the
accessible field DOM structure makes impossible because that input sits beneath
the section list. Drive it through the helper, the same way visits.cy.ts does.
shivoomiess
force-pushed
the
build/frontend-typescript-6
branch
from
August 6, 2026 09:20
5cc3138 to
05ac0f3
Compare
The previous commit made setDatePickerValue yield the picker input so a chained
should('have.value', ...) would read a real value. That broke visits.cy.ts:
"Visitor should be able to register for a visit" went from green to failing on
every branch in the stack, in the default config, deterministically through
retries. The mechanism is not understood, so the helper goes back to exactly the
code that was green rather than being adjusted further.
The three assertions in calls.cy.ts that needed a value now query the input
themselves. That is where the value being checked is actually read, and it keeps
the helper doing one thing.
The three date questions in experimentSafetyReview.cy.ts still typed straight into the picker input. Under x-date-pickers v9 that input is aria-hidden and sits beneath the section list, so Cypress reports it as covered and the type fails. These were the sites the earlier v9 picker pass missed. Four of the seven failures on the ae shard came from this. The other three were Cypress failing to write the failure screenshots, because this spec's nested describe names exceed the filesystem name limit; that is pre-existing and left alone here.
shivoomiess
force-pushed
the
build/frontend-typescript-6
branch
from
August 6, 2026 11:41
05ac0f3 to
fa9170d
Compare
The frontend declared `typescript: ^4.7.4` in `dependencies` while the backend and e2e workspaces were already on 5.x, and 4.9.5 was what actually resolved. React 19 forces the issue: `@types/react@19` declares `typeScriptVersion: 5.6`. Targets 6.0.3 rather than 7.0.2. TypeScript 7 ships without a programmatic API - `exports["."]` resolves to `lib/version.cjs`, and there is no `tsserver` binary - so typescript-eslint cannot run on it, and npm refuses the install outright against its `>=4.8.4 <6.1.0` peer range. That API is expected in 7.1. 6.0 is the bridge release: it reports every option 7 removes, so the remaining work is visible rather than discovered later. Moved to `devDependencies`, where the rest of the build tooling already sits. Raises the typescript-eslint packages to ^8.66.0 in the same change. 8.56.0 declares `typescript: ">=4.8.4 <6.0.0"`, which TypeScript 6 violates; 8.66.0 widened it to `<6.1.0`. The three declarations are moved together so they cannot drift - `@typescript-eslint/parser` and `eslint-plugin` had already floated to 8.66.0 while the unified `typescript-eslint` package stayed pinned at 8.56.0. Two tsconfig entries, both explained in place: - `ignoreDeprecations: "6.0"` keeps this bump separate from the TypeScript 7 config migration (`target`, `moduleResolution`, `baseUrl`). That migration needs no import changes - Vite resolves the absolute imports through its own aliases - but it does surface 11 errors in 9 files, 6 of which disappear once React 19 upgrades html-react-parser. - `types: ["node", "vite/client"]` - TypeScript 6 no longer includes `@types/*` automatically, which dropped the `process` and `NodeJS` globals. Fixes the three latent type errors the bump surfaced. None are new bugs; all were mistyped in ways 4.9 did not check: - MultistepWizard: `WizardStep.validationSchema` was `Yup.AnyObjectSchema`, i.e. `ObjectSchema<any, any, any, any>`. From TypeScript 5 a concrete `ObjectSchema` is not assignable to it, because `concat` is invariant in the schema's shape, so every real schema was rejected. The step never reads the prop - the wizard forwards it to Formik - so the polymorphic `Yup.ISchema` is the accurate type. - QuestionaryDetails: `TableRowData.label`/`value` were `JSX.Element | string | null`, but both are produced by `React.FunctionComponent` renderers, which return `ReactNode`, and the only reader renders them straight into a `TableCell`. Widened to `ReactNode`. - ProposalContainer: `(<CopyToClipboard .../>) || 'DRAFT'` - a JSX element is always truthy, so the fallback was unreachable. Removed the dead operand, which leaves behaviour unchanged. Note the removed `|| 'DRAFT'` reveals intent that never took effect: when a proposal has no id the inner ternary already renders an empty string, so the UI shows an empty clickable CopyToClipboard rather than "DRAFT". Left as-is because correcting it is a product decision, not part of a TypeScript upgrade.
shivoomiess
force-pushed
the
build/frontend-typescript-6
branch
from
August 10, 2026 12:21
fa9170d to
8b809ef
Compare
shivoomiess
marked this pull request as ready for review
August 20, 2026 12:05
shivoomiess
requested review from
Scott-James-Hurley
and removed request for
a team
August 20, 2026 12:05
yoganandaness
approved these changes
Aug 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This PR upgrades the TypeScript version in the frontend from 4.7.4 to 6.0.3.
Motivation and Context
This upgrade was necessary to leverage the latest TypeScript features, improve code quality, ensure better type safety, and stay up to date with the latest best practices in the development community. It also resolves compatibility issues with some other packages.
Changes
How Has This Been Tested?
Fixes Jira Issue
https://jira.ess.eu//browse/
Depends On
Tests included/Docs Updated?