From 452020f7208d4f2dcc46c1f022ed3f029548b226 Mon Sep 17 00:00:00 2001 From: Manas Hejmadi Date: Sun, 8 Jun 2025 22:34:26 +0530 Subject: [PATCH] AI Request History & Duplication Feature --- lib/models/history_request_model.dart | 4 +- lib/models/history_request_model.freezed.dart | 79 ++++++-- lib/models/history_request_model.g.dart | 13 +- lib/providers/collection_providers.dart | 8 +- lib/screens/common_widgets/code_pane.dart | 7 + .../history_widgets/ai_history_page.dart | 178 ++++++++++++++++++ .../history_widgets/his_request_pane.dart | 57 +++++- .../history_widgets/his_response_pane.dart | 8 +- lib/utils/history_utils.dart | 1 + .../genai/lib/widgets/ai_config_widgets.dart | 9 + .../history_widgets/his_url_card_test.dart | 4 +- 11 files changed, 331 insertions(+), 37 deletions(-) create mode 100644 lib/screens/history/history_widgets/ai_history_page.dart diff --git a/lib/models/history_request_model.dart b/lib/models/history_request_model.dart index f46382a7..a2b3d84e 100644 --- a/lib/models/history_request_model.dart +++ b/lib/models/history_request_model.dart @@ -1,4 +1,5 @@ import 'package:apidash_core/apidash_core.dart'; +import 'package:genai/genai.dart'; import 'models.dart'; part 'history_request_model.freezed.dart'; @@ -14,7 +15,8 @@ class HistoryRequestModel with _$HistoryRequestModel { const factory HistoryRequestModel({ required String historyId, required HistoryMetaModel metaData, - required HttpRequestModel httpRequestModel, + HttpRequestModel? httpRequestModel, + AIRequestModel? aiRequestModel, required HttpResponseModel httpResponseModel, String? preRequestScript, String? postRequestScript, diff --git a/lib/models/history_request_model.freezed.dart b/lib/models/history_request_model.freezed.dart index 020ea13d..dd553171 100644 --- a/lib/models/history_request_model.freezed.dart +++ b/lib/models/history_request_model.freezed.dart @@ -22,7 +22,8 @@ HistoryRequestModel _$HistoryRequestModelFromJson(Map json) { mixin _$HistoryRequestModel { String get historyId => throw _privateConstructorUsedError; HistoryMetaModel get metaData => throw _privateConstructorUsedError; - HttpRequestModel get httpRequestModel => throw _privateConstructorUsedError; + HttpRequestModel? get httpRequestModel => throw _privateConstructorUsedError; + AIRequestModel? get aiRequestModel => throw _privateConstructorUsedError; HttpResponseModel get httpResponseModel => throw _privateConstructorUsedError; String? get preRequestScript => throw _privateConstructorUsedError; String? get postRequestScript => throw _privateConstructorUsedError; @@ -47,14 +48,16 @@ abstract class $HistoryRequestModelCopyWith<$Res> { $Res call( {String historyId, HistoryMetaModel metaData, - HttpRequestModel httpRequestModel, + HttpRequestModel? httpRequestModel, + AIRequestModel? aiRequestModel, HttpResponseModel httpResponseModel, String? preRequestScript, String? postRequestScript, AuthModel? authModel}); $HistoryMetaModelCopyWith<$Res> get metaData; - $HttpRequestModelCopyWith<$Res> get httpRequestModel; + $HttpRequestModelCopyWith<$Res>? get httpRequestModel; + $AIRequestModelCopyWith<$Res>? get aiRequestModel; $HttpResponseModelCopyWith<$Res> get httpResponseModel; $AuthModelCopyWith<$Res>? get authModel; } @@ -76,7 +79,8 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel> $Res call({ Object? historyId = null, Object? metaData = null, - Object? httpRequestModel = null, + Object? httpRequestModel = freezed, + Object? aiRequestModel = freezed, Object? httpResponseModel = null, Object? preRequestScript = freezed, Object? postRequestScript = freezed, @@ -91,10 +95,14 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel> ? _value.metaData : metaData // ignore: cast_nullable_to_non_nullable as HistoryMetaModel, - httpRequestModel: null == httpRequestModel + httpRequestModel: freezed == httpRequestModel ? _value.httpRequestModel : httpRequestModel // ignore: cast_nullable_to_non_nullable - as HttpRequestModel, + as HttpRequestModel?, + aiRequestModel: freezed == aiRequestModel + ? _value.aiRequestModel + : aiRequestModel // ignore: cast_nullable_to_non_nullable + as AIRequestModel?, httpResponseModel: null == httpResponseModel ? _value.httpResponseModel : httpResponseModel // ignore: cast_nullable_to_non_nullable @@ -128,12 +136,30 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel> /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') - $HttpRequestModelCopyWith<$Res> get httpRequestModel { - return $HttpRequestModelCopyWith<$Res>(_value.httpRequestModel, (value) { + $HttpRequestModelCopyWith<$Res>? get httpRequestModel { + if (_value.httpRequestModel == null) { + return null; + } + + return $HttpRequestModelCopyWith<$Res>(_value.httpRequestModel!, (value) { return _then(_value.copyWith(httpRequestModel: value) as $Val); }); } + /// Create a copy of HistoryRequestModel + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $AIRequestModelCopyWith<$Res>? get aiRequestModel { + if (_value.aiRequestModel == null) { + return null; + } + + return $AIRequestModelCopyWith<$Res>(_value.aiRequestModel!, (value) { + return _then(_value.copyWith(aiRequestModel: value) as $Val); + }); + } + /// Create a copy of HistoryRequestModel /// with the given fields replaced by the non-null parameter values. @override @@ -170,7 +196,8 @@ abstract class _$$HistoryRequestModelImplCopyWith<$Res> $Res call( {String historyId, HistoryMetaModel metaData, - HttpRequestModel httpRequestModel, + HttpRequestModel? httpRequestModel, + AIRequestModel? aiRequestModel, HttpResponseModel httpResponseModel, String? preRequestScript, String? postRequestScript, @@ -179,7 +206,9 @@ abstract class _$$HistoryRequestModelImplCopyWith<$Res> @override $HistoryMetaModelCopyWith<$Res> get metaData; @override - $HttpRequestModelCopyWith<$Res> get httpRequestModel; + $HttpRequestModelCopyWith<$Res>? get httpRequestModel; + @override + $AIRequestModelCopyWith<$Res>? get aiRequestModel; @override $HttpResponseModelCopyWith<$Res> get httpResponseModel; @override @@ -201,7 +230,8 @@ class __$$HistoryRequestModelImplCopyWithImpl<$Res> $Res call({ Object? historyId = null, Object? metaData = null, - Object? httpRequestModel = null, + Object? httpRequestModel = freezed, + Object? aiRequestModel = freezed, Object? httpResponseModel = null, Object? preRequestScript = freezed, Object? postRequestScript = freezed, @@ -216,10 +246,14 @@ class __$$HistoryRequestModelImplCopyWithImpl<$Res> ? _value.metaData : metaData // ignore: cast_nullable_to_non_nullable as HistoryMetaModel, - httpRequestModel: null == httpRequestModel + httpRequestModel: freezed == httpRequestModel ? _value.httpRequestModel : httpRequestModel // ignore: cast_nullable_to_non_nullable - as HttpRequestModel, + as HttpRequestModel?, + aiRequestModel: freezed == aiRequestModel + ? _value.aiRequestModel + : aiRequestModel // ignore: cast_nullable_to_non_nullable + as AIRequestModel?, httpResponseModel: null == httpResponseModel ? _value.httpResponseModel : httpResponseModel // ignore: cast_nullable_to_non_nullable @@ -247,7 +281,8 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel { const _$HistoryRequestModelImpl( {required this.historyId, required this.metaData, - required this.httpRequestModel, + this.httpRequestModel, + this.aiRequestModel, required this.httpResponseModel, this.preRequestScript, this.postRequestScript, @@ -261,7 +296,9 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel { @override final HistoryMetaModel metaData; @override - final HttpRequestModel httpRequestModel; + final HttpRequestModel? httpRequestModel; + @override + final AIRequestModel? aiRequestModel; @override final HttpResponseModel httpResponseModel; @override @@ -273,7 +310,7 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel { @override String toString() { - return 'HistoryRequestModel(historyId: $historyId, metaData: $metaData, httpRequestModel: $httpRequestModel, httpResponseModel: $httpResponseModel, preRequestScript: $preRequestScript, postRequestScript: $postRequestScript, authModel: $authModel)'; + return 'HistoryRequestModel(historyId: $historyId, metaData: $metaData, httpRequestModel: $httpRequestModel, aiRequestModel: $aiRequestModel, httpResponseModel: $httpResponseModel, preRequestScript: $preRequestScript, postRequestScript: $postRequestScript, authModel: $authModel)'; } @override @@ -287,6 +324,8 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel { other.metaData == metaData) && (identical(other.httpRequestModel, httpRequestModel) || other.httpRequestModel == httpRequestModel) && + (identical(other.aiRequestModel, aiRequestModel) || + other.aiRequestModel == aiRequestModel) && (identical(other.httpResponseModel, httpResponseModel) || other.httpResponseModel == httpResponseModel) && (identical(other.preRequestScript, preRequestScript) || @@ -304,6 +343,7 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel { historyId, metaData, httpRequestModel, + aiRequestModel, httpResponseModel, preRequestScript, postRequestScript, @@ -330,7 +370,8 @@ abstract class _HistoryRequestModel implements HistoryRequestModel { const factory _HistoryRequestModel( {required final String historyId, required final HistoryMetaModel metaData, - required final HttpRequestModel httpRequestModel, + final HttpRequestModel? httpRequestModel, + final AIRequestModel? aiRequestModel, required final HttpResponseModel httpResponseModel, final String? preRequestScript, final String? postRequestScript, @@ -344,7 +385,9 @@ abstract class _HistoryRequestModel implements HistoryRequestModel { @override HistoryMetaModel get metaData; @override - HttpRequestModel get httpRequestModel; + HttpRequestModel? get httpRequestModel; + @override + AIRequestModel? get aiRequestModel; @override HttpResponseModel get httpResponseModel; @override diff --git a/lib/models/history_request_model.g.dart b/lib/models/history_request_model.g.dart index 66aee83b..2548ce76 100644 --- a/lib/models/history_request_model.g.dart +++ b/lib/models/history_request_model.g.dart @@ -11,8 +11,14 @@ _$HistoryRequestModelImpl _$$HistoryRequestModelImplFromJson(Map json) => historyId: json['historyId'] as String, metaData: HistoryMetaModel.fromJson( Map.from(json['metaData'] as Map)), - httpRequestModel: HttpRequestModel.fromJson( - Map.from(json['httpRequestModel'] as Map)), + httpRequestModel: json['httpRequestModel'] == null + ? null + : HttpRequestModel.fromJson( + Map.from(json['httpRequestModel'] as Map)), + aiRequestModel: json['aiRequestModel'] == null + ? null + : AIRequestModel.fromJson( + Map.from(json['aiRequestModel'] as Map)), httpResponseModel: HttpResponseModel.fromJson( Map.from(json['httpResponseModel'] as Map)), preRequestScript: json['preRequestScript'] as String?, @@ -28,7 +34,8 @@ Map _$$HistoryRequestModelImplToJson( { 'historyId': instance.historyId, 'metaData': instance.metaData.toJson(), - 'httpRequestModel': instance.httpRequestModel.toJson(), + 'httpRequestModel': instance.httpRequestModel?.toJson(), + 'aiRequestModel': instance.aiRequestModel?.toJson(), 'httpResponseModel': instance.httpResponseModel.toJson(), 'preRequestScript': instance.preRequestScript, 'postRequestScript': instance.postRequestScript, diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 4203f445..127fc9a9 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -187,10 +187,15 @@ class CollectionStateNotifier var itemIds = ref.read(requestSequenceProvider); var currentModel = historyRequestModel; + + final aT = currentModel.aiRequestModel != null ? APIType.ai : APIType.rest; + final newModel = RequestModel( + apiType: aT, id: newId, name: "${currentModel.metaData.name} (history)", - httpRequestModel: currentModel.httpRequestModel, + aiRequestModel: currentModel.aiRequestModel, + httpRequestModel: currentModel.httpRequestModel ?? HttpRequestModel(), responseStatus: currentModel.metaData.responseStatus, message: kResponseCodeReasons[currentModel.metaData.responseStatus], httpResponseModel: currentModel.httpResponseModel, @@ -461,6 +466,7 @@ class CollectionStateNotifier timeStamp: DateTime.now(), ), httpRequestModel: substitutedHttpRequestModel, + aiRequestModel: aiRequestModel, httpResponseModel: httpResponseModel!, preRequestScript: requestModel.preRequestScript, postRequestScript: requestModel.postRequestScript, diff --git a/lib/screens/common_widgets/code_pane.dart b/lib/screens/common_widgets/code_pane.dart index 654b9440..c4031fae 100644 --- a/lib/screens/common_widgets/code_pane.dart +++ b/lib/screens/common_widgets/code_pane.dart @@ -28,6 +28,13 @@ class CodePane extends ConsumerWidget { final selectedRequestModel = isHistoryRequest ? getRequestModelFromHistoryModel(selectedHistoryRequestModel!) : ref.watch(selectedRequestModelProvider); + + if (selectedRequestModel!.apiType == APIType.ai) { + return const ErrorMessage( + message: "Code generation for AI Requests is currently not available.", + ); + } + final defaultUriScheme = ref.watch(settingsProvider.select((value) => value.defaultUriScheme)); diff --git a/lib/screens/history/history_widgets/ai_history_page.dart b/lib/screens/history/history_widgets/ai_history_page.dart new file mode 100644 index 00000000..72bb98bd --- /dev/null +++ b/lib/screens/history/history_widgets/ai_history_page.dart @@ -0,0 +1,178 @@ +import 'package:apidash/providers/collection_providers.dart'; +import 'package:apidash/providers/history_providers.dart'; +import 'package:apidash/widgets/editor.dart'; +import 'package:apidash_design_system/tokens/measurements.dart'; +import 'package:apidash_design_system/widgets/textfield_outlined.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:genai/llm_config.dart'; +import 'package:genai/widgets/ai_config_widgets.dart'; + +class HisAIRequestPromptSection extends ConsumerWidget { + const HisAIRequestPromptSection({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final selectedHistoryModel = + ref.watch(selectedHistoryRequestModelProvider)!; + + final aiReqM = selectedHistoryModel.aiRequestModel!; + final payload = aiReqM.payload; + final systemPrompt = payload.systemPrompt; + final userPrompt = payload.userPrompt; + + return Container( + padding: EdgeInsets.symmetric(vertical: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 25.0), + child: Text( + 'System Prompt', + ), + ), + kVSpacer10, + Expanded( + child: Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: TextFieldEditor( + key: Key( + "${selectedHistoryModel.historyId}-aireq-sysprompt-body"), + fieldKey: + "${selectedHistoryModel.historyId}-aireq-sysprompt-body", + initialValue: systemPrompt, + readOnly: true, + ), + ), + ), + SizedBox(height: 10), + Padding( + padding: const EdgeInsets.only(left: 25.0), + child: Text( + 'User Prompt / Input', + ), + ), + kVSpacer10, + Expanded( + child: Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: TextFieldEditor( + key: Key( + "${selectedHistoryModel.historyId}-aireq-userprompt-body"), + fieldKey: + "${selectedHistoryModel.historyId}-aireq-userprompt-body", + initialValue: userPrompt, + readOnly: true, + ), + ), + ), + ], + ), + ); + } +} + +class HisAIRequestAuthorizationSection extends ConsumerWidget { + const HisAIRequestAuthorizationSection({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final selectedHistoryModel = + ref.watch(selectedHistoryRequestModelProvider)!; + + final aiReqM = selectedHistoryModel.aiRequestModel!; + + final payload = aiReqM.payload; + + final cred = payload.credential; + + return Container( + padding: EdgeInsets.symmetric(vertical: 20), + child: Column( + children: [ + Expanded( + child: Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: TextFieldEditor( + key: Key( + "${selectedHistoryModel.historyId}-aireq-authvalue-body"), + fieldKey: + "${selectedHistoryModel.historyId}-aireq-authvalue-body", + initialValue: cred, + readOnly: true, + ), + ), + ), + ], + ), + ); + } +} + +class HisAIRequestConfigSection extends ConsumerWidget { + const HisAIRequestConfigSection({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final selectedHistoryModel = + ref.watch(selectedHistoryRequestModelProvider)!; + + final aiReqM = selectedHistoryModel.aiRequestModel!; + + final payload = aiReqM.payload; + + return SingleChildScrollView( + padding: EdgeInsets.symmetric(vertical: 20), + child: Column( + key: ValueKey(selectedHistoryModel.historyId), + children: [ + ...payload.configMap.values.map( + (el) => ListTile( + title: Text(el.configName), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + el.configDescription, + ), + SizedBox(height: 5), + if (el.configType == LLMModelConfigurationType.boolean) ...[ + BooleanAIConfig( + readonly: true, + configuration: el, + onConfigUpdated: (x) {}, + ), + ] else if (el.configType == + LLMModelConfigurationType.numeric) ...[ + WritableAIConfig( + configuration: el, + onConfigUpdated: (x) {}, + readonly: true, + numeric: true, + ), + ] else if (el.configType == + LLMModelConfigurationType.text) ...[ + WritableAIConfig( + configuration: el, + onConfigUpdated: (x) {}, + readonly: true, + ), + ] else if (el.configType == + LLMModelConfigurationType.slider) ...[ + SliderAIConfig( + configuration: el, + onSliderUpdated: (x) {}, + readonly: true, + ), + ], + SizedBox(height: 10), + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/history/history_widgets/his_request_pane.dart b/lib/screens/history/history_widgets/his_request_pane.dart index 73f61927..f6093326 100644 --- a/lib/screens/history/history_widgets/his_request_pane.dart +++ b/lib/screens/history/history_widgets/his_request_pane.dart @@ -1,3 +1,4 @@ +import 'package:apidash/screens/history/history_widgets/ai_history_page.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; @@ -22,23 +23,39 @@ class HistoryRequestPane extends ConsumerWidget { final codePaneVisible = ref.watch(historyCodePaneVisibleStateProvider); final apiType = ref.watch(selectedHistoryRequestModelProvider .select((value) => value?.metaData.apiType)); - final headersMap = ref.watch(selectedHistoryRequestModelProvider - .select((value) => value?.httpRequestModel.headersMap)) ?? + + final headersMap = ref.watch(selectedHistoryRequestModelProvider.select( + (value) { + if (apiType == APIType.ai) return {}; + return value?.httpRequestModel!.headersMap; + }, + )) ?? {}; final headerLength = headersMap.length; - final paramsMap = ref.watch(selectedHistoryRequestModelProvider - .select((value) => value?.httpRequestModel.paramsMap)) ?? + final paramsMap = ref.watch(selectedHistoryRequestModelProvider.select( + (value) { + if (apiType == APIType.ai) return {}; + return value?.httpRequestModel!.paramsMap; + }, + )) ?? {}; final paramLength = paramsMap.length; - final hasBody = ref.watch(selectedHistoryRequestModelProvider - .select((value) => value?.httpRequestModel.hasBody)) ?? + final hasBody = ref.watch(selectedHistoryRequestModelProvider.select( + (value) { + if (apiType == APIType.ai) return false; + return value?.httpRequestModel!.hasBody; + }, + )) ?? false; - final hasQuery = ref.watch(selectedHistoryRequestModelProvider - .select((value) => value?.httpRequestModel.hasQuery)) ?? - false; + final hasQuery = + ref.watch(selectedHistoryRequestModelProvider.select((value) { + if (apiType == APIType.ai) return false; + return value?.httpRequestModel!.hasQuery; + })) ?? + false; final scriptsLength = ref.watch(selectedHistoryRequestModelProvider .select((value) => value?.preRequestScript?.length)) ?? @@ -127,7 +144,27 @@ class HistoryRequestPane extends ConsumerWidget { const HistoryScriptsTab(), ], ), - APIType.ai => FlutterLogo(), + APIType.ai => RequestPane( + key: const Key("history-request-pane-ai"), + selectedId: selectedId, + codePaneVisible: codePaneVisible, + onPressedCodeButton: () { + ref.read(historyCodePaneVisibleStateProvider.notifier).state = + !codePaneVisible; + }, + showViewCodeButton: !isCompact, + showIndicators: [ + false, + false, + false, + ], + tabLabels: const ["Prompts", "Authorization", "Configuration"], + children: [ + const HisAIRequestPromptSection(), + const HisAIRequestAuthorizationSection(), + const HisAIRequestConfigSection(), + ], + ), _ => kSizedBoxEmpty, }; } diff --git a/lib/screens/history/history_widgets/his_response_pane.dart b/lib/screens/history/history_widgets/his_response_pane.dart index f90390cb..695c3785 100644 --- a/lib/screens/history/history_widgets/his_response_pane.dart +++ b/lib/screens/history/history_widgets/his_response_pane.dart @@ -13,16 +13,20 @@ class HistoryResponsePane extends ConsumerWidget { final selectedId = ref.watch(selectedHistoryIdStateProvider); final selectedHistoryRequest = ref.watch(selectedHistoryRequestModelProvider); + final historyHttpResponseModel = selectedHistoryRequest?.httpResponseModel; if (selectedId != null) { final requestModel = getRequestModelFromHistoryModel(selectedHistoryRequest!); + + final statusCode = historyHttpResponseModel?.statusCode; + return Column( children: [ ResponsePaneHeader( - responseStatus: historyHttpResponseModel?.statusCode, - message: kResponseCodeReasons[historyHttpResponseModel?.statusCode], + responseStatus: statusCode, + message: kResponseCodeReasons[statusCode], time: historyHttpResponseModel?.time, ), Expanded( diff --git a/lib/utils/history_utils.dart b/lib/utils/history_utils.dart index d1c3dbbc..60ea7ae3 100644 --- a/lib/utils/history_utils.dart +++ b/lib/utils/history_utils.dart @@ -13,6 +13,7 @@ RequestModel getRequestModelFromHistoryModel(HistoryRequestModel model) { name: model.metaData.name, responseStatus: model.httpResponseModel.statusCode, message: kResponseCodeReasons[model.httpResponseModel.statusCode], + aiRequestModel: model.aiRequestModel, httpRequestModel: model.httpRequestModel, httpResponseModel: model.httpResponseModel, ); diff --git a/packages/genai/lib/widgets/ai_config_widgets.dart b/packages/genai/lib/widgets/ai_config_widgets.dart index 2113b447..957c5c1f 100644 --- a/packages/genai/lib/widgets/ai_config_widgets.dart +++ b/packages/genai/lib/widgets/ai_config_widgets.dart @@ -4,10 +4,12 @@ import 'package:genai/llm_config.dart'; class SliderAIConfig extends StatelessWidget { final LLMModelConfiguration configuration; final Function(LLMModelConfiguration) onSliderUpdated; + final bool readonly; const SliderAIConfig({ super.key, required this.configuration, required this.onSliderUpdated, + this.readonly = false, }); @override @@ -23,6 +25,7 @@ class SliderAIConfig extends StatelessWidget { max: (configuration.configValue.value as (double, double, double)) .$3, onChanged: (x) { + if (readonly) return; final z = configuration.configValue.value as (double, double, double); configuration.configValue.value = (z.$1, x, z.$3); @@ -43,11 +46,13 @@ class WritableAIConfig extends StatelessWidget { final bool numeric; final LLMModelConfiguration configuration; final Function(LLMModelConfiguration) onConfigUpdated; + final bool readonly; const WritableAIConfig({ super.key, this.numeric = false, required this.configuration, required this.onConfigUpdated, + this.readonly = false, }); @override @@ -55,6 +60,7 @@ class WritableAIConfig extends StatelessWidget { return TextFormField( initialValue: configuration.configValue.value.toString(), onChanged: (x) { + if (readonly) return; if (numeric) { if (x.isEmpty) x = '0'; if (num.tryParse(x) == null) return; @@ -71,10 +77,12 @@ class WritableAIConfig extends StatelessWidget { class BooleanAIConfig extends StatelessWidget { final LLMModelConfiguration configuration; final Function(LLMModelConfiguration) onConfigUpdated; + final bool readonly; const BooleanAIConfig({ super.key, required this.configuration, required this.onConfigUpdated, + this.readonly = false, }); @override @@ -82,6 +90,7 @@ class BooleanAIConfig extends StatelessWidget { return Switch( value: configuration.configValue.value as bool, onChanged: (x) { + if (readonly) return; configuration.configValue.value = x; onConfigUpdated(configuration); }, diff --git a/test/screens/history/history_widgets/his_url_card_test.dart b/test/screens/history/history_widgets/his_url_card_test.dart index 6723fefb..50308a2d 100644 --- a/test/screens/history/history_widgets/his_url_card_test.dart +++ b/test/screens/history/history_widgets/his_url_card_test.dart @@ -31,7 +31,7 @@ void main() { expect( find.text( - historyRequestModel.httpRequestModel.method.name.toUpperCase()), + historyRequestModel.httpRequestModel!.method.name.toUpperCase()), findsOneWidget); }); @@ -45,7 +45,7 @@ void main() { ); expect( - find.text(historyRequestModel.httpRequestModel.url), findsOneWidget); + find.text(historyRequestModel.httpRequestModel!.url), findsOneWidget); }); }); }