mirror of
https://github.com/foss42/apidash.git
synced 2025-12-01 18:28:25 +08:00
Add AI request model support and improve type handling
Refactored collection state management to handle API type changes and AI request models. Updated widgets and tests to support nullable HTTP methods and AI request models, and improved response body rendering for AI responses.
This commit is contained in:
@@ -241,34 +241,54 @@ class CollectionStateNotifier
|
||||
}
|
||||
var currentModel = state![rId]!;
|
||||
var currentHttpRequestModel = currentModel.httpRequestModel;
|
||||
final newModel = currentModel.copyWith(
|
||||
apiType: apiType ?? currentModel.apiType,
|
||||
name: name ?? currentModel.name,
|
||||
description: description ?? currentModel.description,
|
||||
requestTabIndex: requestTabIndex ?? currentModel.requestTabIndex,
|
||||
httpRequestModel: currentHttpRequestModel?.copyWith(
|
||||
method: method ?? currentHttpRequestModel.method,
|
||||
url: url ?? currentHttpRequestModel.url,
|
||||
headers: headers ?? currentHttpRequestModel.headers,
|
||||
params: params ?? currentHttpRequestModel.params,
|
||||
authModel: authModel ?? currentHttpRequestModel.authModel,
|
||||
isHeaderEnabledList:
|
||||
isHeaderEnabledList ?? currentHttpRequestModel.isHeaderEnabledList,
|
||||
isParamEnabledList:
|
||||
isParamEnabledList ?? currentHttpRequestModel.isParamEnabledList,
|
||||
bodyContentType:
|
||||
bodyContentType ?? currentHttpRequestModel.bodyContentType,
|
||||
body: body ?? currentHttpRequestModel.body,
|
||||
query: query ?? currentHttpRequestModel.query,
|
||||
formData: formData ?? currentHttpRequestModel.formData,
|
||||
),
|
||||
responseStatus: responseStatus ?? currentModel.responseStatus,
|
||||
message: message ?? currentModel.message,
|
||||
httpResponseModel: httpResponseModel ?? currentModel.httpResponseModel,
|
||||
preRequestScript: preRequestScript ?? currentModel.preRequestScript,
|
||||
postRequestScript: postRequestScript ?? currentModel.postRequestScript,
|
||||
aiRequestModel: aiRequestModel ?? currentModel.aiRequestModel,
|
||||
);
|
||||
|
||||
RequestModel newModel;
|
||||
|
||||
if (apiType != null && currentModel.apiType != apiType) {
|
||||
newModel = switch (apiType) {
|
||||
APIType.rest || APIType.graphql => currentModel.copyWith(
|
||||
apiType: apiType,
|
||||
name: name ?? currentModel.name,
|
||||
description: description ?? currentModel.description,
|
||||
httpRequestModel: const HttpRequestModel(),
|
||||
aiRequestModel: null),
|
||||
APIType.ai => currentModel.copyWith(
|
||||
apiType: apiType,
|
||||
name: name ?? currentModel.name,
|
||||
description: description ?? currentModel.description,
|
||||
httpRequestModel: null,
|
||||
aiRequestModel: const AIRequestModel()),
|
||||
};
|
||||
} else {
|
||||
newModel = currentModel.copyWith(
|
||||
apiType: apiType ?? currentModel.apiType,
|
||||
name: name ?? currentModel.name,
|
||||
description: description ?? currentModel.description,
|
||||
requestTabIndex: requestTabIndex ?? currentModel.requestTabIndex,
|
||||
httpRequestModel: currentHttpRequestModel?.copyWith(
|
||||
method: method ?? currentHttpRequestModel.method,
|
||||
url: url ?? currentHttpRequestModel.url,
|
||||
headers: headers ?? currentHttpRequestModel.headers,
|
||||
params: params ?? currentHttpRequestModel.params,
|
||||
authModel: authModel ?? currentHttpRequestModel.authModel,
|
||||
isHeaderEnabledList: isHeaderEnabledList ??
|
||||
currentHttpRequestModel.isHeaderEnabledList,
|
||||
isParamEnabledList:
|
||||
isParamEnabledList ?? currentHttpRequestModel.isParamEnabledList,
|
||||
bodyContentType:
|
||||
bodyContentType ?? currentHttpRequestModel.bodyContentType,
|
||||
body: body ?? currentHttpRequestModel.body,
|
||||
query: query ?? currentHttpRequestModel.query,
|
||||
formData: formData ?? currentHttpRequestModel.formData,
|
||||
),
|
||||
responseStatus: responseStatus ?? currentModel.responseStatus,
|
||||
message: message ?? currentModel.message,
|
||||
httpResponseModel: httpResponseModel ?? currentModel.httpResponseModel,
|
||||
preRequestScript: preRequestScript ?? currentModel.preRequestScript,
|
||||
postRequestScript: postRequestScript ?? currentModel.postRequestScript,
|
||||
aiRequestModel: aiRequestModel ?? currentModel.aiRequestModel,
|
||||
);
|
||||
}
|
||||
|
||||
var map = {...state!};
|
||||
map[rId] = newModel;
|
||||
@@ -285,7 +305,8 @@ class CollectionStateNotifier
|
||||
}
|
||||
|
||||
RequestModel? requestModel = state![requestId];
|
||||
if (requestModel?.httpRequestModel == null) {
|
||||
if (requestModel?.httpRequestModel == null &&
|
||||
requestModel?.aiRequestModel == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ class AIModelSelector extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
AIRequestModel? aiRequestModel;
|
||||
if (readOnlyModel != null) {
|
||||
if (readOnlyModel == null) {
|
||||
ref.watch(selectedIdStateProvider);
|
||||
aiRequestModel = ref.watch(selectedRequestModelProvider
|
||||
.select((value) => value?.aiRequestModel));
|
||||
|
||||
@@ -193,7 +193,7 @@ class RequestItem extends ConsumerWidget {
|
||||
return SidebarRequestCard(
|
||||
id: id,
|
||||
apiType: requestModel.apiType,
|
||||
method: requestModel.httpRequestModel!.method,
|
||||
method: requestModel.httpRequestModel?.method,
|
||||
name: requestModel.name,
|
||||
url: requestModel.httpRequestModel?.url,
|
||||
selectedId: selectedId,
|
||||
|
||||
@@ -102,6 +102,10 @@ class URLTextField extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final selectedId = ref.watch(selectedIdStateProvider);
|
||||
ref.watch(selectedRequestModelProvider
|
||||
.select((value) => value?.aiRequestModel?.url));
|
||||
ref.watch(selectedRequestModelProvider
|
||||
.select((value) => value?.httpRequestModel?.url));
|
||||
final requestModel = ref
|
||||
.read(collectionStateNotifierProvider.notifier)
|
||||
.getRequestModel(selectedId!)!;
|
||||
|
||||
@@ -11,7 +11,7 @@ class SidebarRequestCard extends StatelessWidget {
|
||||
super.key,
|
||||
required this.id,
|
||||
required this.apiType,
|
||||
required this.method,
|
||||
this.method,
|
||||
this.name,
|
||||
this.url,
|
||||
this.selectedId,
|
||||
@@ -30,7 +30,7 @@ class SidebarRequestCard extends StatelessWidget {
|
||||
final APIType apiType;
|
||||
final String? name;
|
||||
final String? url;
|
||||
final HTTPVerb method;
|
||||
final HTTPVerb? method;
|
||||
final String? selectedId;
|
||||
final String? editRequestId;
|
||||
final void Function()? onTap;
|
||||
|
||||
@@ -49,8 +49,7 @@ class ResponseBody extends StatelessWidget {
|
||||
// '$kMsgUnknowContentType - ${responseModel.contentType}. $kUnexpectedRaiseIssue');
|
||||
// }
|
||||
|
||||
var responseBodyView = (selectedRequestModel?.apiType == APIType.ai &&
|
||||
(responseModel.sseOutput?.isNotEmpty ?? false))
|
||||
var responseBodyView = selectedRequestModel?.apiType == APIType.ai
|
||||
? (kAnswerRawBodyViewOptions, kSubTypePlain)
|
||||
: getResponseBodyViewOptions(mediaType);
|
||||
var options = responseBodyView.$1;
|
||||
@@ -70,6 +69,7 @@ class ResponseBody extends StatelessWidget {
|
||||
formattedBody: formattedBody,
|
||||
highlightLanguage: highlightLanguage,
|
||||
sseOutput: responseModel.sseOutput,
|
||||
isAIResponse: selectedRequestModel?.apiType == APIType.ai,
|
||||
aiRequestModel: selectedRequestModel?.aiRequestModel,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ class ResponseBodySuccess extends StatefulWidget {
|
||||
this.formattedBody,
|
||||
this.highlightLanguage,
|
||||
this.sseOutput,
|
||||
this.isAIResponse = false,
|
||||
this.aiRequestModel,
|
||||
});
|
||||
final MediaType mediaType;
|
||||
@@ -26,6 +27,7 @@ class ResponseBodySuccess extends StatefulWidget {
|
||||
final String? formattedBody;
|
||||
final List<String>? sseOutput;
|
||||
final String? highlightLanguage;
|
||||
final bool isAIResponse;
|
||||
final AIRequestModel? aiRequestModel;
|
||||
|
||||
@override
|
||||
@@ -137,7 +139,7 @@ class _ResponseBodySuccessState extends State<ResponseBodySuccess> {
|
||||
),
|
||||
),
|
||||
),
|
||||
ResponseBodyView.raw || ResponseBodyView.answer => Expanded(
|
||||
ResponseBodyView.answer => Expanded(
|
||||
child: Container(
|
||||
width: double.maxFinite,
|
||||
padding: kP8,
|
||||
@@ -150,6 +152,21 @@ class _ResponseBodySuccessState extends State<ResponseBodySuccess> {
|
||||
),
|
||||
),
|
||||
),
|
||||
ResponseBodyView.raw => Expanded(
|
||||
child: Container(
|
||||
width: double.maxFinite,
|
||||
padding: kP8,
|
||||
decoration: textContainerdecoration,
|
||||
child: SingleChildScrollView(
|
||||
child: SelectableText(
|
||||
widget.isAIResponse
|
||||
? widget.body
|
||||
: (widget.formattedBody ?? widget.body),
|
||||
style: kCodeStyle,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
ResponseBodyView.sse => Expanded(
|
||||
child: Container(
|
||||
width: double.maxFinite,
|
||||
|
||||
@@ -7,10 +7,10 @@ class SidebarRequestCardTextBox extends StatelessWidget {
|
||||
const SidebarRequestCardTextBox({
|
||||
super.key,
|
||||
required this.apiType,
|
||||
required this.method,
|
||||
this.method,
|
||||
});
|
||||
final APIType apiType;
|
||||
final HTTPVerb method;
|
||||
final HTTPVerb? method;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -18,7 +18,7 @@ class SidebarRequestCardTextBox extends StatelessWidget {
|
||||
width: 24,
|
||||
child: Text(
|
||||
switch (apiType) {
|
||||
APIType.rest => method.abbr,
|
||||
APIType.rest => method!.abbr,
|
||||
APIType.graphql => apiType.abbr,
|
||||
APIType.ai => apiType.abbr,
|
||||
},
|
||||
|
||||
@@ -1117,6 +1117,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
nanoid:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: nanoid
|
||||
sha256: be3f8752d9046c825df2f3914195151eb876f3ad64b9d833dd0b799b77b8759e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
nanoid2:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -57,6 +57,7 @@ final Map<String, dynamic> historyRequestModelJson1 = {
|
||||
"historyId": "historyId1",
|
||||
"metaData": historyMetaModelJson1,
|
||||
"httpRequestModel": httpRequestModelGet4Json,
|
||||
'aiRequestModel': null,
|
||||
"httpResponseModel": responseModelJson,
|
||||
'preRequestScript': null,
|
||||
'postRequestScript': null,
|
||||
|
||||
@@ -218,7 +218,8 @@ Map<String, dynamic> requestModelJson = {
|
||||
'message': null,
|
||||
'httpResponseModel': responseModelJson,
|
||||
'preRequestScript': null,
|
||||
'postRequestScript': null
|
||||
'postRequestScript': null,
|
||||
'aiRequestModel': null
|
||||
};
|
||||
|
||||
/// Basic GET request model for apidash.dev
|
||||
|
||||
Reference in New Issue
Block a user