Skip to content

[DG-266] adding the callback support to the create component fn - #486

Open
carbonFibreCode wants to merge 3 commits into
mainfrom
arun/dg-266
Open

[DG-266] adding the callback support to the create component fn#486
carbonFibreCode wants to merge 3 commits into
mainfrom
arun/dg-266

Conversation

@carbonFibreCode

Copy link
Copy Markdown
Collaborator

No description provided.

@coderabbitai

coderabbitai Bot commented Dec 22, 2025

Copy link
Copy Markdown

Walkthrough

Adds native Dart callback support via a new DUICallback typedef and early-exit execution path for Function types, exports the callback type, and refactors component construction with callback usage documentation.

Changes

Cohort / File(s) Summary
Native Callback Support
lib/src/framework/actions/execute_callback/processor.dart, lib/digia_ui.dart
Introduced DUICallback typedef for native callbacks (Future<Object?>? Function(Map<String, dynamic> args)). Added conditional execution path in execute method to delegate Function types to new private _executeNativeCallback handler instead of parsing ActionFlow. Callback result emitted via executionContext with error rethrow support. Exported DUICallback type from main library.
Component Construction Refactoring
lib/src/framework/ui_factory.dart
Refactored createComponent to extract component instantiation into local variable prior to DefaultActionExecutor wrapping. Added documentation block describing native callback injection via args map for Action.executeCallback with usage example.

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive No pull request description was provided by the author, so the check cannot confirm the description is related to the changeset. Add a description explaining what callback support was added, why it was added, and how it works with the createComponent function.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title '[DG-266] adding the callback support to the create component fn' directly describes the main change: adding callback support to the createComponent function.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch arun/dg-266

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2eea2a1 and 4f812fc.

📒 Files selected for processing (3)
  • lib/digia_ui.dart
  • lib/src/framework/actions/execute_callback/processor.dart
  • lib/src/framework/ui_factory.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/src/framework/actions/execute_callback/processor.dart
🔇 Additional comments (4)
lib/src/framework/ui_factory.dart (3)

571-589: Excellent documentation for the callback feature.

The documentation clearly explains how to pass native Dart callbacks through the args map and provides a practical example. This will be very helpful for developers using this feature.


613-630: Refactoring looks correct.

The component is now instantiated as a local variable before being wrapped with DefaultActionExecutor. This structural change maintains the same behavior while improving code clarity.


640-640: The callback execution implementation in processor.dart is properly implemented. The early-exit path for Function types exists at line 80, correctly checks if (evaluatedActionName is Function), and routes to _executeNativeCallback. The method properly converts argUpdates to resolvedArgs at line 44 and invokes the callback at line 193 with await callback(resolvedArgs). Error handling and observability context notifications are correctly in place.

lib/digia_ui.dart (1)

10-11: The DUICallback typedef signature matches the documented callback signature. The typedef definition at processor.dart line 18 correctly specifies Future<Object?>? Function(Map<String, dynamic> args), which matches the documented parameter signature (Map<String, dynamic> args) async { ... }. No changes required.


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 and usage tips.

@coderabbitai coderabbitai 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.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/src/framework/component/component.dart (1)

1-1: Address Dart formatting failure.

The pipeline indicates formatting issues. Run dart format . to fix.

Based on pipeline failure logs.

🧹 Nitpick comments (1)
lib/src/framework/widgets/navigation_bar_custom.dart (1)

29-42: Consider using getActionOrCallback for consistency with other widgets.

Unlike button.dart and calendar.dart which use payload.getActionOrCallback(...) to allow developer callbacks to override actions via createComponent args, this widget passes the action directly from props. If callback support should also be available for navigation item selection, consider aligning with the pattern:

final action = payload.getActionOrCallback(
    'onPageSelected', onPageSelectedAction);

If this is intentional (navigation items define their own actions and shouldn't be overridable), this is fine as-is.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4bad44a and 4791011.

📒 Files selected for processing (12)
  • lib/src/framework/component/component.dart
  • lib/src/framework/render_payload.dart
  • lib/src/framework/widgets/animated_button.dart
  • lib/src/framework/widgets/button.dart
  • lib/src/framework/widgets/calendar.dart
  • lib/src/framework/widgets/icon_button.dart
  • lib/src/framework/widgets/navigation_bar.dart
  • lib/src/framework/widgets/navigation_bar_custom.dart
  • lib/src/framework/widgets/page_view.dart
  • lib/src/framework/widgets/refresh_indicator.dart
  • lib/src/framework/widgets/rich_text.dart
  • lib/src/framework/widgets/text_form_field.dart
🧰 Additional context used
🪛 GitHub Actions: Pull Request Checks
lib/src/framework/component/component.dart

[error] 1-1: Dart format check failed. The command 'dart format --output=none --set-exit-if-changed .' reported changes and exited with code 1; run 'dart format' to fix the formatting issues.

🔇 Additional comments (13)
lib/src/framework/component/component.dart (1)

48-57: Two-stage argument resolution enables callback support.

The implementation correctly merges default values from argDefs with developer-provided args. This allows callbacks and other runtime arguments to be passed even when not explicitly defined in argDefs, which aligns with the PR objective.

The spread order ensures developer-provided args override defined args as intended.

lib/src/framework/widgets/refresh_indicator.dart (1)

29-34: LGTM: Action resolution updated to new pattern.

The change from ActionFlow.fromJson to payload.getActionOrCallback simplifies action resolution and aligns with the framework-wide refactor to support callbacks.

lib/src/framework/widgets/page_view.dart (1)

37-38: LGTM: Consistent action resolution pattern.

The onPageChanged handler now uses payload.getActionOrCallback, consistent with the refactor across other widgets.

lib/src/framework/widgets/rich_text.dart (1)

86-93: LGTM: Simplified onClick execution.

Passing p0 directly to executeAction instead of wrapping it in ActionFlow.fromJson simplifies the code and aligns with the new callback support mechanism.

lib/src/framework/widgets/icon_button.dart (1)

64-68: LGTM: Action resolution updated consistently.

The onClick handler now uses payload.getActionOrCallback, consistent with the framework-wide refactor.

lib/src/framework/widgets/animated_button.dart (1)

67-74: LGTM: Consistent onClick resolution.

The animated button now uses payload.getActionOrCallback for action resolution, maintaining consistency with other interactive widgets.

lib/src/framework/widgets/navigation_bar.dart (1)

27-40: LGTM: Simplified action execution in navigation handler.

Passing onPageSelectedAction directly to executeAction instead of wrapping it in ActionFlow.fromJson aligns with the new callback support approach.

lib/src/framework/widgets/text_form_field.dart (1)

80-93: LGTM: Consistent action resolution for form field events.

Both onChanged and onSubmit handlers now use payload.getActionOrCallback, maintaining consistency with the framework-wide refactor to support callbacks.

lib/src/framework/widgets/button.dart (1)

84-88: LGTM!

The button correctly adopts the new getActionOrCallback pattern, enabling developers to pass callbacks via createComponent args while maintaining fallback to props-defined actions.

lib/src/framework/widgets/calendar.dart (1)

76-79: LGTM!

Both onDateSelected and onRangeSelected correctly use the new getActionOrCallback pattern, allowing developers to inject custom callbacks while preserving fallback to dashboard-defined actions.

lib/src/framework/render_payload.dart (3)

72-90: LGTM!

The getActionOrCallback method provides a clean mechanism for prioritizing developer-provided callbacks from scope over props-defined actions. The documentation is clear and helpful.


106-113: Function callbacks are invoked with zero arguments; scopeContext and triggerType are ignored.

When actionOrCallback is a Function, it's invoked as actionOrCallback() without any parameters. This means:

  1. Developer callbacks must be zero-argument functions
  2. The scopeContext and triggerType parameters passed to executeAction are silently ignored for Function callbacks

If developers need access to context data within their callbacks, this design won't support that. Consider either:

  • Documenting this limitation clearly in the method's docstring
  • Passing context to callbacks if supported signatures are defined (e.g., Function(ScopeContext?))

If zero-arg callbacks are the intended design, adding a note to the docstring would help prevent confusion.


115-120: No action needed — ActionFlow.fromJson already handles invalid inputs gracefully.

ActionFlow.fromJson accepts Object? and explicitly checks if (json is! JsonLike) return null; at line 21, returning null for any non-JsonLike input (primitives, unexpected types) without throwing exceptions. The implementation already satisfies the safety concern.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4791011 and bb608c6.

📒 Files selected for processing (1)
  • lib/src/framework/component/component.dart
⏰ 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: run-format-and-analyse
🔇 Additional comments (3)
lib/src/framework/component/component.dart (3)

63-63: LGTM: Consistent argument propagation.

The resolved arguments are correctly passed to the scope context for state initialization.


72-72: LGTM: Proper observability integration.

The resolved arguments are correctly provided to the state observer for inspection.


97-97: LGTM: Consistent context creation.

The resolved arguments are correctly passed to the expression context, ensuring all parameters are available for expression evaluation.

Comment thread lib/src/framework/component/component.dart Outdated

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/src/framework/actions/execute_callback/processor.dart (1)

1-1: Fix Dart formatting issues.

The pipeline indicates formatting failures. Run dart format . to fix formatting issues in this file.

🧹 Nitpick comments (2)
lib/src/framework/actions/execute_callback/processor.dart (1)

189-201: Defensive null check is redundant but acceptable.

The has() check at line 75 already confirms the callback exists before calling _executeNativeCallback. This null check will never trigger in normal execution flow since both checks occur synchronously. Consider simplifying:

🔎 Optional simplification
   final callback = callbackRegistry.get(callbackName);
-
-    if (callback == null) {
-      executionContext?.notifyComplete(
-        id: id,
-        parentActionId: parentActionId,
-        descriptor: actionDescriptor,
-        error: 'Native callback "$callbackName" not found in registry',
-        stackTrace: StackTrace.current,
-        observabilityContext: observabilityContext,
-      );
-      return null;
-    }
+    // callback is guaranteed non-null since has() was checked before calling this method
lib/src/framework/callback/callback_registry.dart (1)

96-100: Consider throwing a descriptive error instead of assert + force-unwrap.

The assert is stripped in release builds, so if of() is called without a CallbackProvider ancestor, users will see a cryptic null dereference error rather than the helpful message. Since maybeOf is used in the processor, this is low-risk, but for API robustness:

🔎 Optional improvement
  static CallbackRegistry of(BuildContext context) {
    final registry = maybeOf(context);
-   assert(registry != null, 'No CallbackProvider found in widget tree');
-   return registry!;
+   if (registry == null) {
+     throw FlutterError('No CallbackProvider found in widget tree');
+   }
+   return registry;
  }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb608c6 and c759d15.

📒 Files selected for processing (4)
  • lib/digia_ui.dart
  • lib/src/framework/actions/execute_callback/processor.dart
  • lib/src/framework/callback/callback_registry.dart
  • lib/src/framework/ui_factory.dart
🧰 Additional context used
🪛 GitHub Actions: Pull Request Checks
lib/src/framework/actions/execute_callback/processor.dart

[error] 1-1: Dart format check failed. The formatter changed the file(s); run 'dart format --output=none --set-exit-if-changed .' to reformat.

lib/src/framework/callback/callback_registry.dart

[error] 1-1: Dart format check failed. The formatter changed the file(s); run 'dart format --output=none --set-exit-if-changed .' to reformat.

🔇 Additional comments (11)
lib/digia_ui.dart (1)

11-11: LGTM!

The export is correctly placed in alphabetical order and properly exposes the new callback infrastructure (DUICallback, CallbackRegistry, CallbackProvider) to library consumers.

lib/src/framework/actions/execute_callback/processor.dart (2)

70-87: LGTM!

The native callback routing logic is well-structured with proper null safety checks and clean early-return pattern.


203-228: LGTM!

The callback execution follows the established pattern with proper error handling, observability notifications, and consistent rethrow behavior matching the existing ActionFlow execution path.

lib/src/framework/ui_factory.dart (5)

11-11: LGTM!

Import correctly added for the new callback infrastructure.


572-586: LGTM!

Clear documentation with a practical example showing how to pass callbacks and their expected signature.


611-623: LGTM!

The callback name injection pattern is elegant—when an expression like args.onButtonClick is evaluated, it returns the string "onButtonClick", which the processor then matches against the registry.


626-642: LGTM!

Component correctly created with merged args that include callback name mappings.


654-663: LGTM!

The wrapping order is correct—CallbackProvider is placed above DefaultActionExecutor in the widget tree, ensuring the registry is accessible via context.getInheritedWidgetOfExactType from within the component's build context.

lib/src/framework/callback/callback_registry.dart (3)

3-11: LGTM!

The typedef signature is flexible, allowing callbacks to return null synchronously or an async Future<Object?>, which the processor handles correctly with await.


31-68: LGTM!

Clean API with defensive copy in constructor. The registry provides all necessary operations for callback management.


102-109: LGTM!

The updateShouldNotify returning false is appropriate since the processor uses getInheritedWidgetOfExactType (no subscription) and callbacks are accessed during action execution rather than during widget builds. Good documentation of the design decision.

Comment thread lib/src/framework/callback/callback_registry.dart Outdated
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