Skip to content

Commit 1e60563

Browse files
committed
Fixed button and updated other component to use proper flow state
1 parent d347a59 commit 1e60563

File tree

12 files changed

+151
-102
lines changed

12 files changed

+151
-102
lines changed

packages/digit_flow_builder/lib/action_handler/executors/clear_state_executor.dart

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
33
import '../../blocs/flow_crud_bloc.dart';
44
import '../../blocs/search_state_manager.dart';
55
import '../../utils/interpolation.dart';
6+
import '../../widget_registry.dart';
67
import '../action_config.dart';
78
import 'action_executor.dart';
89

@@ -27,10 +28,16 @@ class ClearStateExecutor extends ActionExecutor {
2728
Map<String, dynamic> contextData,
2829
) async {
2930
// Use getEffectiveScreenKey to handle popup context
30-
final screenKey = getEffectiveScreenKey(context, contextData);
31+
final crudCtx = CrudItemContext.of(context);
32+
final screenKey =
33+
crudCtx?.screenKey ?? getEffectiveScreenKey(context, contextData);
3134

3235
// Get composite key for FlowCrudStateRegistry operations
33-
final compositeKey = getEffectiveCompositeKey(context, contextData);
36+
// IMPORTANT: Try CrudItemContext.compositeKey first - it's correctly passed
37+
// from popups via ActionPopupWidget. Only fall back to getEffectiveCompositeKey
38+
// when not in a popup context.
39+
final compositeKey =
40+
crudCtx?.compositeKey ?? getEffectiveCompositeKey(context, contextData);
3441

3542
if (compositeKey == null) {
3643
debugPrint('⚠️ CLEAR_STATE: No compositeKey found, skipping');

packages/digit_flow_builder/lib/action_handler/executors/refresh_search_executor.dart

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,21 @@ class RefreshSearchExecutor extends ActionExecutor {
4242
final direction = data['direction'] as String? ?? 'down';
4343
final paginationConfig = data['pagination'] as Map<String, dynamic>?;
4444

45-
// Get screen key
45+
// Get composite key (includes instanceId for proper isolation)
46+
// IMPORTANT: Try CrudItemContext.compositeKey first - it's correctly passed
47+
// from popups via ActionPopupWidget. Only fall back to getEffectiveCompositeKey
48+
// when not in a popup context.
4649
final crudCtx = CrudItemContext.of(context);
47-
final screenKey =
48-
crudCtx?.screenKey ?? getEffectiveScreenKey(context, contextData);
50+
final compositeKey =
51+
crudCtx?.compositeKey ?? getEffectiveCompositeKey(context, contextData);
4952

50-
if (screenKey == null) {
51-
debugPrint('REFRESH_SEARCH: No screen key found, cannot refresh');
53+
if (compositeKey == null) {
54+
debugPrint('REFRESH_SEARCH: No composite key found, cannot refresh');
5255
return contextData;
5356
}
5457

5558
// Check if there are any accumulated filters for this screen
56-
final hasFilters = SearchStateManager().hasFiltersForScreen(screenKey);
59+
final hasFilters = SearchStateManager().hasFiltersForScreen(compositeKey);
5760

5861
if (!hasFilters) {
5962
debugPrint('REFRESH_SEARCH: No accumulated filters for screen, skipping');
@@ -64,7 +67,7 @@ class RefreshSearchExecutor extends ActionExecutor {
6467
return _executeWithBidirectionalPagination(
6568
context,
6669
contextData,
67-
screenKey,
70+
compositeKey,
6871
direction,
6972
paginationConfig,
7073
);
@@ -73,15 +76,15 @@ class RefreshSearchExecutor extends ActionExecutor {
7376
Future<Map<String, dynamic>> _executeWithBidirectionalPagination(
7477
BuildContext context,
7578
Map<String, dynamic> contextData,
76-
String screenKey,
79+
String compositeKey,
7780
String direction,
7881
Map<String, dynamic>? paginationConfig,
7982
) async {
8083
final stateManager = SearchStateManager();
8184
const paginationKey = '_pagination';
8285

8386
// Get config for default pagination settings
84-
final config = FlowRegistry.getByName(screenKey.split('::').last);
87+
final config = FlowRegistry.getByName(compositeKey.split('::').last);
8588
final defaultPaginationConfig =
8689
config?['wrapperConfig']?['searchConfig']?['pagination'];
8790
final defaultLimit = defaultPaginationConfig?['limit'] as int? ?? 10;
@@ -97,32 +100,32 @@ class RefreshSearchExecutor extends ActionExecutor {
97100
: defaultMaxItems);
98101

99102
// Get or initialize pagination window
100-
debugPrint('REFRESH_SEARCH: Looking for pagination window with screenKey=$screenKey');
101-
var window = stateManager.getPaginationWindow(screenKey, paginationKey);
103+
debugPrint('REFRESH_SEARCH: Looking for pagination window with compositeKey=$compositeKey');
104+
var window = stateManager.getPaginationWindow(compositeKey, paginationKey);
102105
debugPrint('REFRESH_SEARCH: Found window=$window');
103106

104107
if (window == null) {
105108
// Initialize window if not exists (shouldn't happen normally)
106109
debugPrint('REFRESH_SEARCH: Window not found, initializing new one');
107110
stateManager.initPaginationWindow(
108-
screenKey,
111+
compositeKey,
109112
paginationKey,
110113
limit: limit,
111114
maxItems: maxItems,
112115
);
113-
window = stateManager.getPaginationWindow(screenKey, paginationKey);
116+
window = stateManager.getPaginationWindow(compositeKey, paginationKey);
114117
}
115118

116119
// Determine offset based on direction
117120
int? offset;
118121
if (direction == 'down') {
119-
offset = stateManager.prepareLoadDown(screenKey, paginationKey);
122+
offset = stateManager.prepareLoadDown(compositeKey, paginationKey);
120123
if (offset == null) {
121124
debugPrint('REFRESH_SEARCH: Cannot load down - no more data');
122125
return contextData;
123126
}
124127
} else if (direction == 'up') {
125-
offset = stateManager.prepareLoadUp(screenKey, paginationKey);
128+
offset = stateManager.prepareLoadUp(compositeKey, paginationKey);
126129
if (offset == null) {
127130
debugPrint('REFRESH_SEARCH: Cannot load up - at beginning');
128131
return contextData;
@@ -136,7 +139,7 @@ class RefreshSearchExecutor extends ActionExecutor {
136139
'REFRESH_SEARCH: Loading $direction from offset=$offset, limit=$limit');
137140

138141
// Get ALL accumulated filters for the screen (across all searchNames)
139-
final accumulatedFilters = stateManager.getAllFilters(screenKey);
142+
final accumulatedFilters = stateManager.getAllFilters(compositeKey);
140143

141144
// Convert to SearchFilter objects
142145
final filters = <SearchFilter>[];
@@ -178,7 +181,7 @@ class RefreshSearchExecutor extends ActionExecutor {
178181
);
179182

180183
// Set mode in registry - FlowCrudBloc.onTransition will handle it
181-
final registryKey = screenKey.split('::').last;
184+
final registryKey = compositeKey.split('::').last;
182185
FlowCrudStateRegistry().setScrollDirection(registryKey, direction);
183186
FlowCrudStateRegistry().setPaginationInfo(
184187
registryKey,

packages/digit_flow_builder/lib/action_handler/executors/search_executor.dart

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,11 @@ class SearchExecutor extends ActionExecutor {
3434
crudCtx?.screenKey ?? getEffectiveScreenKey(context, contextData);
3535

3636
// Get composite key for FlowCrudStateRegistry operations
37+
// IMPORTANT: Try CrudItemContext.compositeKey first - it's correctly passed
38+
// from popups via ActionPopupWidget. Only fall back to getEffectiveCompositeKey
39+
// when not in a popup context (i.e., CrudItemContext is null or has no compositeKey)
3740
final compositeKey =
38-
getEffectiveCompositeKey(context, contextData);
41+
crudCtx?.compositeKey ?? getEffectiveCompositeKey(context, contextData);
3942

4043
// Register search callback (SearchStateManager handles deduplication)
4144
// This allows ClearStateExecutor to trigger search with accumulated filters
@@ -508,14 +511,14 @@ class SearchExecutor extends ActionExecutor {
508511
/// This is called via the registered callback when triggered by ClearStateExecutor
509512
static void _executeSearchWithAccumulatedFilters(
510513
CrudBloc crudBloc,
511-
String screenKey,
514+
String compositeKey,
512515
String searchName,
513516
Map<String, dynamic>? config,
514517
) {
515518
final accumulatedFilters =
516-
SearchStateManager().getFilters(screenKey, searchName);
519+
SearchStateManager().getFilters(compositeKey, searchName);
517520
final accumulatedOrderBy =
518-
SearchStateManager().getOrderBy(screenKey, searchName);
521+
SearchStateManager().getOrderBy(compositeKey, searchName);
519522

520523
if (accumulatedFilters.isEmpty) {
521524
debugPrint(

packages/digit_flow_builder/lib/utils/interpolation.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,9 @@ String? getEffectiveCompositeKey(
113113
BuildContext context,
114114
Map<String, dynamic> contextData,
115115
) {
116-
final screenKey = getEffectiveScreenKey(context, contextData);
116+
final data = contextData;
117+
118+
final screenKey = data['parentScreenKey'] ?? getEffectiveScreenKey(context, data);
117119
if (screenKey == null) return null;
118120

119121
final instanceId = getInstanceIdFromArgs(context);

packages/digit_flow_builder/lib/widgets/implementations/button_widget.dart

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,24 @@ class ButtonWidget implements FlowWidget {
8484
if (json['onAction'] != null) {
8585
final actionsList = List<Map<String, dynamic>>.from(json['onAction']);
8686

87+
// Read current data from registry at click time
88+
// flowState data is captured at widget build time and may be stale
89+
final compositeKey = flowState.compositeKey ?? flowState.screenKey;
90+
final registryState = compositeKey != null
91+
? FlowCrudStateRegistry().get(compositeKey)
92+
: null;
93+
final currentWidgetData = registryState?.widgetData ?? flowState.widgetData;
94+
final currentFormData = registryState?.formData ?? flowState.formData;
95+
96+
// Build evalContext with latest widgetData and formData
97+
final currentEvalContext = <String, dynamic>{
98+
...flowState.evalContext,
99+
...currentFormData,
100+
...currentWidgetData,
101+
'widgetData': currentWidgetData,
102+
'formData': currentFormData,
103+
};
104+
87105
// Helper function to resolve navigation data for an action
88106
Map<String, dynamic> resolveNavDataForAction(Map<String, dynamic> actionJson) {
89107
var action = ActionConfig.fromJson(actionJson);
@@ -93,18 +111,18 @@ class ButtonWidget implements FlowWidget {
93111
final resolvedData = navData.map((entry) {
94112
final rawValue = entry['value'];
95113

96-
// Try to resolve from stateData first, then widgetData, then formData
97-
dynamic resolvedValue = resolveValue(rawValue, flowState.evalContext)
114+
// Try to resolve from evalContext first, then widgetData, then formData
115+
dynamic resolvedValue = resolveValue(rawValue, currentEvalContext)
98116
?? rawValue;
99117

100-
if (resolvedValue == rawValue && flowState.widgetData.isNotEmpty) {
101-
// If not resolved from stateData, try widgetData
102-
resolvedValue = resolveValue(rawValue, flowState.widgetData);
118+
if (resolvedValue == rawValue && currentWidgetData.isNotEmpty) {
119+
// If not resolved from evalContext, try widgetData
120+
resolvedValue = resolveValue(rawValue, currentWidgetData);
103121
}
104122

105-
if (resolvedValue == rawValue && flowState.formData.isNotEmpty) {
123+
if (resolvedValue == rawValue && currentFormData.isNotEmpty) {
106124
// If not resolved from widgetData, try formData
107-
resolvedValue = resolveValue(rawValue, flowState.formData);
125+
resolvedValue = resolveValue(rawValue, currentFormData);
108126
}
109127

110128
return {
@@ -134,12 +152,12 @@ class ButtonWidget implements FlowWidget {
134152
final condition = Map<String, dynamic>.from(actionJson['condition']);
135153
final expression = condition['expression'] as String?;
136154
if (expression != null && expression.contains('{{')) {
137-
// Resolve the expression template using flowState.evalContext
138-
String resolvedExpression = resolveTemplate(expression, flowState.evalContext) ?? expression;
155+
// Resolve the expression template using current registry data
156+
String resolvedExpression = resolveTemplate(expression, currentEvalContext) ?? expression;
139157
if (resolvedExpression == expression && crudStateData != null) {
140158
resolvedExpression = resolveValueRaw(
141159
expression,
142-
flowState.evalContext,
160+
currentEvalContext,
143161
);
144162
}
145163
condition['expression'] = resolvedExpression;
@@ -162,19 +180,19 @@ class ButtonWidget implements FlowWidget {
162180
return resolvedActionJson;
163181
}).toList();
164182

165-
// Build initial context data from current state using flowState.evalContext
183+
// Build initial context data using current registry data
166184
// Also include navigation params from registry for condition evaluation
167185
final screenKey = flowState.screenKey;
168186
final navigationParams = screenKey != null
169-
? FlowCrudStateRegistry().getNavigationParams(flowState.compositeKey ?? screenKey) ??
187+
? FlowCrudStateRegistry().getNavigationParams(compositeKey ?? screenKey) ??
170188
FlowCrudStateRegistry()
171189
.getNavigationParams(screenKey.split('::').last) ??
172190
{}
173191
: <String, dynamic>{};
174192

175193
final initialContextData = <String, dynamic>{
176194
'wrappers': const [],
177-
...flowState.evalContext,
195+
...currentEvalContext,
178196
'navigation': navigationParams,
179197
};
180198

0 commit comments

Comments
 (0)