diff --git a/lib/dashbot/features/chat/view/widgets/openapi_operation_picker_dialog.dart b/lib/dashbot/features/chat/view/widgets/openapi_operation_picker_dialog.dart index c0607015..158157ba 100644 --- a/lib/dashbot/features/chat/view/widgets/openapi_operation_picker_dialog.dart +++ b/lib/dashbot/features/chat/view/widgets/openapi_operation_picker_dialog.dart @@ -42,113 +42,120 @@ Future?> showOpenApiOperationPickerDialog({ bool selectAll = ops.isNotEmpty; String searchQuery = ''; - return showDialog>( - context: context, - useRootNavigator: true, - builder: (ctx) { - return StatefulBuilder(builder: (ctx, setState) { - // Filter operations based on search query - final filteredOps = []; - for (int i = 0; i < ops.length; i++) { - final o = ops[i]; - final label = '${o.method} ${o.path}'.toLowerCase(); - if (searchQuery.isEmpty || - label.contains(searchQuery.toLowerCase())) { - filteredOps.add(i); + final scrollController = ScrollController(); + try { + return await showDialog>( + context: context, + useRootNavigator: true, + builder: (ctx) { + return StatefulBuilder(builder: (ctx, setState) { + // Filter operations based on search query + final filteredOps = []; + for (int i = 0; i < ops.length; i++) { + final o = ops[i]; + final label = '${o.method} ${o.path}'.toLowerCase(); + if (searchQuery.isEmpty || + label.contains(searchQuery.toLowerCase())) { + filteredOps.add(i); + } } - } - return AlertDialog( - title: Text('Import from $title'), - content: SizedBox( - width: 520, - height: 420, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - // TODO: Create a common Search field widget - Padding( - padding: const EdgeInsets.only(bottom: 16.0), - child: TextField( - onChanged: (value) { + return AlertDialog( + title: Text('Import from $title'), + content: SizedBox( + width: 520, + height: 420, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + // TODO: Create a common Search field widget + Padding( + padding: const EdgeInsets.only(bottom: 16.0), + child: TextField( + onChanged: (value) { + setState(() { + searchQuery = value; + }); + }, + decoration: const InputDecoration( + labelText: 'Search routes', + hintText: 'Type to filter routes...', + prefixIcon: Icon(Icons.search), + border: OutlineInputBorder(), + ), + ), + ), + // Select all checkbox + CheckboxListTile( + value: selectAll, + onChanged: (v) { setState(() { - searchQuery = value; + selectAll = v ?? false; + selected + ..clear() + ..addAll(selectAll + ? List.generate(ops.length, (i) => i) + : const {}); }); }, - decoration: const InputDecoration( - labelText: 'Search routes', - hintText: 'Type to filter routes...', - prefixIcon: Icon(Icons.search), - border: OutlineInputBorder(), + title: const Text('Select all'), + controlAffinity: ListTileControlAffinity.leading, + ), + // Routes list + Expanded( + child: Scrollbar( + controller: scrollController, + thumbVisibility: true, + child: ListView.builder( + controller: scrollController, + itemCount: filteredOps.length, + itemBuilder: (c, index) { + final i = filteredOps[index]; + final o = ops[i]; + final label = '${o.method} ${o.path}'; + final checked = selected.contains(i); + return CheckboxListTile( + value: checked, + onChanged: (v) { + setState(() { + if (v == true) { + selected.add(i); + } else { + selected.remove(i); + } + selectAll = selected.length == ops.length; + }); + }, + title: Text(label), + controlAffinity: ListTileControlAffinity.leading, + ); + }, + ), ), ), - ), - // Select all checkbox - CheckboxListTile( - value: selectAll, - onChanged: (v) { - setState(() { - selectAll = v ?? false; - selected - ..clear() - ..addAll(selectAll - ? List.generate(ops.length, (i) => i) - : const {}); - }); - }, - title: const Text('Select all'), - controlAffinity: ListTileControlAffinity.leading, - ), - // Routes list - Expanded( - child: Scrollbar( - thumbVisibility: true, - child: ListView.builder( - itemCount: filteredOps.length, - itemBuilder: (c, index) { - final i = filteredOps[index]; - final o = ops[i]; - final label = '${o.method} ${o.path}'; - final checked = selected.contains(i); - return CheckboxListTile( - value: checked, - onChanged: (v) { - setState(() { - if (v == true) { - selected.add(i); - } else { - selected.remove(i); - } - selectAll = selected.length == ops.length; - }); - }, - title: Text(label), - controlAffinity: ListTileControlAffinity.leading, - ); + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(ctx).pop(null), + child: const Text('Cancel'), + ), + FilledButton( + onPressed: selected.isEmpty + ? null + : () { + final result = selected.map((i) => ops[i]).toList(); + Navigator.of(ctx).pop(result); }, - ), - ), - ), - ], - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.of(ctx).pop(null), - child: const Text('Cancel'), - ), - FilledButton( - onPressed: selected.isEmpty - ? null - : () { - final result = selected.map((i) => ops[i]).toList(); - Navigator.of(ctx).pop(result); - }, - child: const Text('Import'), - ), - ], - ); - }); - }, - ); + child: const Text('Import'), + ), + ], + ); + }); + }, + ); + } finally { + scrollController.dispose(); + } }