Skip to content

enhan: implement default value handling for number fields and add utility functions - #5246

Open
micanipho wants to merge 3 commits into
shesha-io:releases/0.43from
micanipho:nhlakanipho/b/5212
Open

enhan: implement default value handling for number fields and add utility functions#5246
micanipho wants to merge 3 commits into
shesha-io:releases/0.43from
micanipho:nhlakanipho/b/5212

Conversation

@micanipho

@micanipho micanipho commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

This pull request refactors how default values are handled for number fields in the form designer, ensuring that configured defaults are properly written into the form data and submitted, rather than only appearing as uncontrolled UI state. The changes introduce a new utility for evaluating and applying default values, and update the component structure to use this logic consistently.

Default value handling improvements:

  • Introduced a new resolveDefaultValue utility in utils.ts to safely evaluate and coerce the configured default value (including expressions) for number fields, ensuring the correct type is submitted with the form.
  • Added a NumberFieldEditor component in numberField.tsx that ensures the default value is written into the form data when appropriate, rather than relying on uncontrolled input state. This uses a ref to avoid re-applying the default after user input.
  • Updated the main number field component to use resolveDefaultValue and NumberFieldEditor, and to only apply the default value when the form is in edit mode and data loading is complete.

Code cleanup and documentation:

  • Removed the use of Ant Design's defaultValue prop from NumberFieldControl to prevent discrepancies between UI state and submitted data, with explanatory comments.
  • Added documentation and clarified the evaluation logic for default values, including handling of high-precision fields and empty values.

Summary by CodeRabbit

  • New Features
    • Form fields now apply configured default values consistently during initialization and data loading.
    • Default values can be evaluated from expressions and legacy templates.
    • Numeric and boolean defaults are converted safely, rejecting invalid or lossy values.
    • Nested fields correctly support defaults within parent property paths.
    • Existing values are preserved and are not overwritten by defaults.
    • Number fields support high-precision string values alongside numbers.
  • Bug Fixes
    • Improved handling of default values for number fields, including null and empty values.

Issue: #5212

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

The form store now resolves configured defaults, converts values using metadata, and applies them during model initialization and data loading. Number fields use NumberFieldValue and rely on form state instead of uncontrolled input defaults.

Number field defaults

Layer / File(s) Summary
Default value resolution
shesha-reactjs/src/providers/form/store/defaultValues.ts
Defines default-value contracts, evaluates configured values, converts metadata-based numeric and boolean values, resolves property routes, and applies missing nested model properties.
Form-backed default application
shesha-reactjs/src/providers/form/store/shaFormInstance.tsx
ShaFormInstance evaluates defaults with application context and applies them during markup reset, form initialization, and data loading.
Number field form integration
shesha-reactjs/src/designer-components/numberField/*, shesha-reactjs/src/providers/form/store/shaFormInstance.tsx
Number field values use NumberFieldValue. Local default evaluation and uncontrolled defaultValue usage were removed. Form hooks now provide toolbox components and application context.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant useShaForm
  participant ShaFormInstance
  participant getFormDefaultValues
  participant FormModel
  useShaForm->>ShaFormInstance: Provide toolbox components and application context
  ShaFormInstance->>getFormDefaultValues: Resolve configured component defaults
  getFormDefaultValues-->>ShaFormInstance: Return evaluated default values
  ShaFormInstance->>FormModel: Apply defaults to missing model properties
  FormModel-->>ShaFormInstance: Return initialized form data
Loading

Possibly related PRs

Suggested reviewers: ivanilyichev

Poem

A rabbit sees defaults take flight,
Through form state, clean and right.
Numbers keep their careful shape,
Empty fields find their proper place.
No stray defaults hop unseen—
The model stays precise and clean.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: default-value handling for number fields and added utility functions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 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 `@shesha-reactjs/src/designer-components/numberField/numberField.tsx`:
- Around line 23-29: Define a shared number-field value type covering number,
string, null, and undefined, then use it for INumberFieldEditorProps.value and
the onChange callback parameter instead of any. Update the related control.tsx
value typing to use the same type so stringMode supports high-precision string
values consistently.

In `@shesha-reactjs/src/designer-components/numberField/utils.ts`:
- Around line 33-39: Update the default-value parsing logic around
resolveDefaultValue to reject partially numeric strings such as “12abc” and
non-finite values such as Infinity. Validate the entire evaluated string as a
numeric literal rather than relying on parseFloat prefixes; for
non-high-precision fields, return undefined unless the parsed number is finite,
while preserving raw valid strings for high-precision stringMode.
- Around line 20-22: Update resolveDefaultValue and the related value input to
use unknown instead of any, then add appropriate validation or narrowing before
evaluation and coercion so existing behavior remains safe. Also tighten any
IDefaultValueEvaluationContext properties that currently use any where their
form-mode/data shapes are known.
- Around line 10-24: The number field should no longer resolve or apply
DefaultValue directly. Remove the resolveDefaultValue utility and its usage in
numberField.tsx, including the initialValue/onChange path, and rely on data
produced by the field’s onAfterDataLoad scripts; update both affected files
accordingly.
- Around line 3-7: Remove globalState from IDefaultValueEvaluationContext in
shesha-reactjs/src/designer-components/numberField/utils.ts and update
resolveDefaultValue callers accordingly. In
shesha-reactjs/src/designer-components/numberField/numberField.tsx, remove the
useGlobalState dependency and stop passing globalState into resolveDefaultValue;
use the typed DataContext values instead while preserving the existing
default-value evaluation behavior.
🪄 Autofix

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: ASSERTIVE

Plan: Pro Plus

Run ID: 84fe47d2-9437-45c5-8fab-a2a7bab9d552

📥 Commits

Reviewing files that changed from the base of the PR and between 471f083 and 8a3bc09.

📒 Files selected for processing (3)
  • shesha-reactjs/src/designer-components/numberField/control.tsx
  • shesha-reactjs/src/designer-components/numberField/numberField.tsx
  • shesha-reactjs/src/designer-components/numberField/utils.ts

Comment thread shesha-reactjs/src/designer-components/numberField/numberField.tsx Outdated
Comment thread shesha-reactjs/src/designer-components/numberField/utils.ts Outdated
Comment thread shesha-reactjs/src/designer-components/numberField/utils.ts Outdated
Comment thread shesha-reactjs/src/designer-components/numberField/utils.ts Outdated
Comment thread shesha-reactjs/src/designer-components/numberField/utils.ts Outdated
@micanipho
micanipho requested review from IvanIlyichev and James-Baloyi and removed request for James-Baloyi August 5, 2026 09:40

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 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 `@shesha-reactjs/src/providers/form/store/defaultValues.ts`:
- Around line 39-40: Update isValueSpecified and the applyDefaultValues update
path around lines 188–193 so explicit model values, including null and empty
strings, are preserved. Use a predicate for model presence that treats only
undefined as missing when deciding whether to apply defaults, while retaining
any distinct validation needed for configured default values.
- Around line 93-103: Update the numeric conversion logic in the data-type
handling branch around NUMERIC_LITERAL_REGEX so accepted finite literals such as
.5, 1.0, and 1e3 convert to numbers regardless of lexical formatting. Return the
original value only for non-finite results or unsafe integer results, while
preserving valid safe integers and finite non-integer values.
- Around line 10-20: Replace any-based default-value typing with unknown across
IFormDefaultValue.value, DefaultValueEvaluator, isValueSpecified,
convertToDataType, resolveDefaultValue, and applyDefaultValues. Add explicit
type guards at conversion and model-write boundaries so only validated values
are passed onward, while preserving existing default-value resolution behavior.

In `@shesha-reactjs/src/providers/form/store/shaFormInstance.tsx`:
- Around line 344-354: Remove the default-value resolution and application from
`#initModel`, including getFormDefaultValues, this.defaultValues, and
applyDefaultValues usage there. Configure form defaults through the existing
onAfterDataLoad script flow instead, ensuring scripts execute in dependency
order and write directly to data or context without SetFieldValue.
- Line 30: Update the ApplicationContextGetter type alias to return
IApplicationContext instead of any, ensuring consumers such as
`#evaluateDefaultValue` remain type-checked.
🪄 Autofix

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: ASSERTIVE

Plan: Pro Plus

Run ID: 0473e285-9c8e-4d68-99d5-9eab202e0288

📥 Commits

Reviewing files that changed from the base of the PR and between 56280ff and fb64f25.

📒 Files selected for processing (4)
  • shesha-reactjs/src/designer-components/numberField/control.tsx
  • shesha-reactjs/src/designer-components/numberField/numberField.tsx
  • shesha-reactjs/src/providers/form/store/defaultValues.ts
  • shesha-reactjs/src/providers/form/store/shaFormInstance.tsx

Comment on lines +10 to +20
export interface IFormDefaultValue {
/** Full name (path) of the property the value is bound to, e.g. `qty` or `address.city` */
propertyName: string;
value: any;
}

/**
* Resolves the actual value of the `defaultValue` setting of a component. The setting may be specified as an
* expression (JS setting or a legacy mustache template) and has to be evaluated in the context of the form.
*/
export type DefaultValueEvaluator = (component: IConfigurableFormComponent) => any;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and inspect the target file and nearby use sites without running repository code.
target="shesha-reactjs/src/providers/form/store/defaultValues.ts"

printf 'Target file exists: '
if [ -f "$target" ]; then echo yes; else echo no; fi

printf '\nFile outline:\n'
ast-grep outline "$target" || true

printf '\nRelevant sections:\n'
cat -n "$target" | sed -n '1,240p'

printf '\nSearch for API names in TypeScript files:\n'
rg -n "IFormDefaultValue|DefaultValueEvaluator|applyDefaultValues|\\.applyDefaultValues|applyDefaultValues\\(" -g '*.ts' -g '*.tsx' .

Repository: shesha-io/shesha-framework

Length of output: 11756


Replace the untyped default-value contract.

IFormDefaultValue.value, DefaultValueEvaluator, isValueSpecified, convertToDataType, resolveDefaultValue, and applyDefaultValues propagate any through default-value resolution and model writes. Use unknown for unknown payload values and add explicit type guards before conversion or writes.

🤖 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 `@shesha-reactjs/src/providers/form/store/defaultValues.ts` around lines 10 -
20, Replace any-based default-value typing with unknown across
IFormDefaultValue.value, DefaultValueEvaluator, isValueSpecified,
convertToDataType, resolveDefaultValue, and applyDefaultValues. Add explicit
type guards at conversion and model-write boundaries so only validated values
are passed onward, while preserving existing default-value resolution behavior.

Source: Coding guidelines

Comment on lines +39 to +40
/** Returns true when the value should be treated as specified, i.e. it should not be replaced by a default value. */
const isValueSpecified = (value: any): boolean => value !== undefined && value !== null && value !== '';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not replace explicit null model values.

Line 40 treats null and '' as unspecified. Line 189 then applies the configured default over an explicit cleared value. This contradicts the documented rule that existing model values win.

Use separate predicates for configured defaults and model values. Treat only an absent property (undefined) as missing when applyDefaultValues updates the model.

Proposed fix
-const isValueSpecified = (value: any): boolean => value !== undefined && value !== null && value !== '';
+const hasConfiguredDefault = (value: unknown): boolean => value !== undefined && value !== null && value !== '';
+const hasModelValue = (value: unknown): boolean => value !== undefined;
...
-    if (isValueSpecified(getValueByPropertyName(result, propertyName)))
+    if (hasModelValue(getValueByPropertyName(result, propertyName)))
       return;

Also applies to: 188-193

🤖 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 `@shesha-reactjs/src/providers/form/store/defaultValues.ts` around lines 39 -
40, Update isValueSpecified and the applyDefaultValues update path around lines
188–193 so explicit model values, including null and empty strings, are
preserved. Use a predicate for model presence that treats only undefined as
missing when deciding whether to apply defaults, while retaining any distinct
validation needed for configured default values.

Comment on lines +93 to +103
if (dataType === DataTypes.number) {
if (!NUMERIC_LITERAL_REGEX.test(trimmed))
return value;

const parsed = Number(trimmed);

// keep the literal when the conversion is not lossless, high precision values may legitimately exceed
// `Number.MAX_SAFE_INTEGER`
const isLossless = Number.isFinite(parsed) && (Number.isSafeInteger(parsed) || String(parsed) === trimmed);

return isLossless ? parsed : value;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Convert accepted exact numeric literals.

The regex accepts .5, 1.0, and 1e3, but Line 101 compares the parsed number with the original lexical form. These values remain strings despite being valid numeric defaults. A number-model property can then receive a string.

Check numeric safety without requiring the canonical String(parsed) form to equal the source literal. Preserve only non-finite values and unsafe integer values.

🤖 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 `@shesha-reactjs/src/providers/form/store/defaultValues.ts` around lines 93 -
103, Update the numeric conversion logic in the data-type handling branch around
NUMERIC_LITERAL_REGEX so accepted finite literals such as .5, 1.0, and 1e3
convert to numbers regardless of lexical formatting. Return the original value
only for non-finite results or unsafe integer results, while preserving valid
safe integers and finite non-integer values.

import { useFormDesignerComponents } from "../hooks";

type ForceUpdateTrigger = () => void;
type ApplicationContextGetter = () => any;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate file =="
fd -a 'shaFormInstance\.tsx$' . || true

echo "== file outline/size =="
wc -l shesha-reactjs/src/providers/form/store/shaFormInstance.tsx
ast-grep outline shesha-reactjs/src/providers/form/store/shaFormInstance.tsx --match ApplicationContextGetter --view expanded || true

echo "== relevant lines =="
sed -n '1,70p' shesha-reactjs/src/providers/form/store/shaFormInstance.tsx | cat -n
sed -n '320,370p' shesha-reactjs/src/providers/form/store/shaFormInstance.tsx | cat -n

echo "== imports/usages of IApplicationContext and constants =="
rg -n "IApplicationContext|ApplicationContextGetter|allConstants|`#evaluateDefaultValue`" shesha-reactjs/src/providers/form/store/shaFormInstance.tsx

Repository: shesha-io/shesha-framework

Length of output: 8653


Remove any from ApplicationContextGetter.

This getter returns the form’s application context object. Use () => IApplicationContext instead of () => any so #evaluateDefaultValue remains type-checked.

🤖 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 `@shesha-reactjs/src/providers/form/store/shaFormInstance.tsx` at line 30,
Update the ApplicationContextGetter type alias to return IApplicationContext
instead of any, ensuring consumers such as `#evaluateDefaultValue` remain
type-checked.

Source: Coding guidelines

Comment on lines +344 to +354
#initModel = <T,>(values: T): T => {
this.defaultValues = getFormDefaultValues({
flatStructure: this.flatStructure,
toolboxComponents: this.toolboxComponents,
evaluator: this.#evaluateDefaultValue,
metadata: this.modelMetadata,
});

this.log('LOG: default values', this.defaultValues);

return applyDefaultValues(values, this.defaultValues);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Move configured defaults to onAfterDataLoad.

#initModel resolves and writes component.defaultValue during model initialization. This bypasses the required dependency-ordered onAfterDataLoad scripts. A default expression that depends on another default can evaluate before its dependency is initialized.

Remove the DefaultValue-based initialization flow. Set form defaults from onAfterDataLoad scripts, where scripts can write directly to data and context.

As per coding guidelines, “Form default values must be set through onAfterDataLoad scripts rather than the DefaultValue property; scripts execute in dependency order and may write directly to data and context without SetFieldValue.”

🤖 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 `@shesha-reactjs/src/providers/form/store/shaFormInstance.tsx` around lines 344
- 354, Remove the default-value resolution and application from `#initModel`,
including getFormDefaultValues, this.defaultValues, and applyDefaultValues usage
there. Configure form defaults through the existing onAfterDataLoad script flow
instead, ensuring scripts execute in dependency order and write directly to data
or context without SetFieldValue.

Source: Coding guidelines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant