refactor: improve simple modals (@fehmer)#8000
Conversation
|
Continuous integration check(s) failed. Please review the failing check's logs and make the necessary changes. |
|
Continuous integration check(s) failed. Please review the failing check's logs and make the necessary changes. |
There was a problem hiding this comment.
Pull request overview
Refactors the Solid showSimpleModal API to be schema-driven: callers pass a Zod object schema plus a matching inputs map, and execFn receives the parsed object. Loader/notification handling moves from states/simple-modal.ts into the SimpleModal component, and the legacy class-based modal is decoupled by copying its input types into elements/simple-modal.ts. Several call sites migrate from array-based inputs with manual validation to schema/preprocess.
Changes:
- New typed
SimpleModalConfig<S>keyed by Zod schema withInputsFromSchema<S>; execution/loader/notification moved intoSimpleModal.tsx; min/max derived from schemas viagetMinAndMax/getDateMinAndMaxand a newconvertFn. - Migrated
AddTagModal,QuoteSearchModal, leaderboardNavigation,FontFamily,ImportExport,Tags,Themeto schema+preprocess form, replacing manualparseInt/normalizeNameandvalidation.isValidblocks. - Legacy
elements/simple-modal.tsnow owns its own input/config types; consumers (simple-modals.ts,ape-key-table.ts) re-importedTextInput/TextArea/PasswordInputfrom there. AddedtypedEntriesutil.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/ts/utils/misc.ts | Adds typed Object.entries helper used by the new modal. |
| frontend/src/ts/states/simple-modal.ts | Rewrites types to be schema-generic; removes loader/notification execution. |
| frontend/src/ts/elements/simple-modal.ts | Duplicates legacy input/config types locally to decouple from Solid path. |
| frontend/src/ts/modals/simple-modals.ts | Updates legacy imports to new location. |
| frontend/src/ts/elements/account-settings/ape-key-table.ts | Updates TextArea import path. |
| frontend/src/ts/components/modals/SimpleModal.tsx | Reworks form to object-shaped inputs; adds convertFn, schema-based min/max, in-component execFn handling. |
| frontend/src/ts/components/modals/AddTagModal.tsx | Migrates to schema + preprocess: normalizeName. |
| frontend/src/ts/components/modals/QuoteSearchModal.tsx | Replaces parseInt/NaN checks with Zod number schema. |
| frontend/src/ts/components/pages/leaderboard/Navigation.tsx | Uses local z.number().int().safe().min(1) instead of PageNumberSchema. |
| frontend/src/ts/components/pages/settings/custom-setting/FontFamily.tsx | Uses schema + normalizeName preprocess. |
| frontend/src/ts/components/pages/settings/custom-setting/ImportExport.tsx | Switches inputs to schema/object form. |
| frontend/src/ts/components/pages/settings/custom-setting/Tags.tsx | Schema-driven rename; drops manual loader-bar calls. |
| frontend/src/ts/components/pages/settings/custom-setting/Presets.tsx | Drops manual loader-bar calls. |
| frontend/src/ts/components/pages/settings/custom-setting/Theme.tsx | Schema-driven share/update modals; uses replaceUnderscoresWithSpaces/normalizeName. |
| frontend/src/ts/components/ui/form/InputField.tsx | Forwards min/max to underlying input. |
Comments suppressed due to low confidence (1)
frontend/src/ts/components/modals/SimpleModal.tsx:210
- After the user types into a date/datetime-local input,
handleChange(e.currentTarget.value)writes a string into the form state. On the next render,formatDate(props.field().state.value as Date)will pass that string todate-fns/format, which expects aDate/number and will throw "Invalid time value" (or render NaN). Previously the state was stored as a pre-formatted string so this worked, but with the newinitVal ?? nulldefaulting to a Date object the state alternates between Date and string. Consider either storing the formatted string ingetDefaultValuesfor date inputs (as before) or detecting the value type insideformatDateand skipping formatting when it's already a string.
<input
type={props.input.type}
class={cn("w-full", props.input.class)}
value={formatDate(props.field().state.value as Date)}
disabled={props.input.disabled}
{...getDateMinAndMax(props.schema, formatDate)}
onInput={(e) => {
props.field().handleChange(e.currentTarget.value);
props.input.oninput?.(e);
}}
onBlur={() => props.field().handleBlur()}
/>
| return Object.fromEntries( | ||
| Object.entries(inputs).map(([key, input]) => [key, input.initVal ?? null]), | ||
| ); |
| const required = | ||
| !input.hidden && !input.optional && input.type !== "checkbox"; | ||
|
|
||
| const schema = input.validation?.schema; | ||
| !input.hidden && !schema.isOptional() && input.type !== "checkbox"; |
No description provided.