mirror of
https://github.com/foss42/apidash.git
synced 2025-12-01 18:28:25 +08:00
Refactor SSE response handling and display
Updated response body widgets to handle SSE output as a list of strings instead of a single string. Adjusted view options for SSE-related media types and refactored SSEDisplay to be a stateless widget that accepts a list of SSE events. This improves clarity and consistency in handling and displaying SSE responses.
This commit is contained in:
@@ -183,6 +183,10 @@ const kPreviewCodeRawBodyViewOptions = [
|
|||||||
ResponseBodyView.code,
|
ResponseBodyView.code,
|
||||||
ResponseBodyView.raw
|
ResponseBodyView.raw
|
||||||
];
|
];
|
||||||
|
const kPreviewSSERawBodyViewOptions = [
|
||||||
|
ResponseBodyView.sse,
|
||||||
|
ResponseBodyView.raw
|
||||||
|
];
|
||||||
|
|
||||||
const Map<String, Map<String, List<ResponseBodyView>>>
|
const Map<String, Map<String, List<ResponseBodyView>>>
|
||||||
kResponseBodyViewOptions = {
|
kResponseBodyViewOptions = {
|
||||||
@@ -196,6 +200,15 @@ const Map<String, Map<String, List<ResponseBodyView>>>
|
|||||||
kSubTypeYaml: kCodeRawBodyViewOptions,
|
kSubTypeYaml: kCodeRawBodyViewOptions,
|
||||||
kSubTypeXYaml: kCodeRawBodyViewOptions,
|
kSubTypeXYaml: kCodeRawBodyViewOptions,
|
||||||
kSubTypeYml: kCodeRawBodyViewOptions,
|
kSubTypeYml: kCodeRawBodyViewOptions,
|
||||||
|
kSubTypeXNdjson: kPreviewSSERawBodyViewOptions,
|
||||||
|
kSubTypeNdjson: kPreviewSSERawBodyViewOptions,
|
||||||
|
kSubTypeJsonSeq: kPreviewSSERawBodyViewOptions,
|
||||||
|
kSubTypeXLdjson: kPreviewSSERawBodyViewOptions,
|
||||||
|
kSubTypeLdjson: kPreviewSSERawBodyViewOptions,
|
||||||
|
kSubTypeXJsonStream: kPreviewSSERawBodyViewOptions,
|
||||||
|
kSubTypeJsonStream: kPreviewSSERawBodyViewOptions,
|
||||||
|
kSubTypeJsonstream: kPreviewSSERawBodyViewOptions,
|
||||||
|
kSubTypeStreamJson: kPreviewSSERawBodyViewOptions,
|
||||||
},
|
},
|
||||||
kTypeImage: {
|
kTypeImage: {
|
||||||
kSubTypeDefaultViewOptions: kPreviewBodyViewOptions,
|
kSubTypeDefaultViewOptions: kPreviewBodyViewOptions,
|
||||||
@@ -217,6 +230,7 @@ const Map<String, Map<String, List<ResponseBodyView>>>
|
|||||||
kSubTypeTextXml: kCodeRawBodyViewOptions,
|
kSubTypeTextXml: kCodeRawBodyViewOptions,
|
||||||
kSubTypeTextYaml: kCodeRawBodyViewOptions,
|
kSubTypeTextYaml: kCodeRawBodyViewOptions,
|
||||||
kSubTypeTextYml: kCodeRawBodyViewOptions,
|
kSubTypeTextYml: kCodeRawBodyViewOptions,
|
||||||
|
kSubTypeEventStream: kPreviewSSERawBodyViewOptions,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:apidash_core/apidash_core.dart';
|
import 'package:apidash_core/apidash_core.dart';
|
||||||
import 'package:apidash/models/models.dart';
|
import 'package:apidash/models/models.dart';
|
||||||
@@ -24,6 +22,7 @@ class ResponseBody extends StatelessWidget {
|
|||||||
message: '$kNullResponseModelError $kUnexpectedRaiseIssue');
|
message: '$kNullResponseModelError $kUnexpectedRaiseIssue');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final isSSE = responseModel.sseOutput?.isNotEmpty ?? false;
|
||||||
var body = responseModel.body;
|
var body = responseModel.body;
|
||||||
var formattedBody = responseModel.formattedBody;
|
var formattedBody = responseModel.formattedBody;
|
||||||
if (body == null) {
|
if (body == null) {
|
||||||
@@ -37,6 +36,9 @@ class ResponseBody extends StatelessWidget {
|
|||||||
showIssueButton: false,
|
showIssueButton: false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (isSSE) {
|
||||||
|
body = responseModel.sseOutput!.join();
|
||||||
|
}
|
||||||
|
|
||||||
final mediaType =
|
final mediaType =
|
||||||
responseModel.mediaType ?? MediaType(kTypeText, kSubTypePlain);
|
responseModel.mediaType ?? MediaType(kTypeText, kSubTypePlain);
|
||||||
@@ -56,20 +58,6 @@ class ResponseBody extends StatelessWidget {
|
|||||||
options.remove(ResponseBodyView.code);
|
options.remove(ResponseBodyView.code);
|
||||||
}
|
}
|
||||||
|
|
||||||
// print('reM -> ${responseModel.sseOutput}');
|
|
||||||
|
|
||||||
if (responseModel.sseOutput?.isNotEmpty ?? false) {
|
|
||||||
// final modifiedBody = responseModel.sseOutput!.join('\n\n');
|
|
||||||
return ResponseBodySuccess(
|
|
||||||
key: Key("${selectedRequestModel!.id}-response"),
|
|
||||||
mediaType: MediaType('text', 'event-stream'),
|
|
||||||
options: [ResponseBodyView.sse, ResponseBodyView.raw],
|
|
||||||
bytes: utf8.encode((responseModel.sseOutput!).toString()),
|
|
||||||
body: jsonEncode(responseModel.sseOutput!),
|
|
||||||
formattedBody: responseModel.sseOutput!.join('\n'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResponseBodySuccess(
|
return ResponseBodySuccess(
|
||||||
key: Key("${selectedRequestModel!.id}-response"),
|
key: Key("${selectedRequestModel!.id}-response"),
|
||||||
mediaType: mediaType,
|
mediaType: mediaType,
|
||||||
@@ -77,6 +65,7 @@ class ResponseBody extends StatelessWidget {
|
|||||||
bytes: responseModel.bodyBytes!,
|
bytes: responseModel.bodyBytes!,
|
||||||
body: body,
|
body: body,
|
||||||
formattedBody: formattedBody,
|
formattedBody: formattedBody,
|
||||||
|
sseOutput: responseModel.sseOutput,
|
||||||
highlightLanguage: highlightLanguage,
|
highlightLanguage: highlightLanguage,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,13 +15,16 @@ class ResponseBodySuccess extends StatefulWidget {
|
|||||||
required this.options,
|
required this.options,
|
||||||
required this.bytes,
|
required this.bytes,
|
||||||
this.formattedBody,
|
this.formattedBody,
|
||||||
|
this.sseOutput,
|
||||||
this.highlightLanguage});
|
this.highlightLanguage});
|
||||||
final MediaType mediaType;
|
final MediaType mediaType;
|
||||||
final List<ResponseBodyView> options;
|
final List<ResponseBodyView> options;
|
||||||
final String body;
|
final String body;
|
||||||
final Uint8List bytes;
|
final Uint8List bytes;
|
||||||
final String? formattedBody;
|
final String? formattedBody;
|
||||||
|
final List<String>? sseOutput;
|
||||||
final String? highlightLanguage;
|
final String? highlightLanguage;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ResponseBodySuccess> createState() => _ResponseBodySuccessState();
|
State<ResponseBodySuccess> createState() => _ResponseBodySuccessState();
|
||||||
}
|
}
|
||||||
@@ -150,7 +153,7 @@ class _ResponseBodySuccessState extends State<ResponseBodySuccess> {
|
|||||||
padding: kP8,
|
padding: kP8,
|
||||||
decoration: textContainerdecoration,
|
decoration: textContainerdecoration,
|
||||||
child: SSEDisplay(
|
child: SSEDisplay(
|
||||||
sseOutput: widget.body,
|
sseOutput: widget.sseOutput,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -2,26 +2,21 @@ import 'dart:convert';
|
|||||||
import 'package:apidash_design_system/apidash_design_system.dart';
|
import 'package:apidash_design_system/apidash_design_system.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class SSEDisplay extends StatefulWidget {
|
class SSEDisplay extends StatelessWidget {
|
||||||
final String sseOutput;
|
final List<String>? sseOutput;
|
||||||
const SSEDisplay({super.key, required this.sseOutput});
|
const SSEDisplay({
|
||||||
|
super.key,
|
||||||
|
this.sseOutput,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
|
||||||
State<SSEDisplay> createState() => _SSEDisplayState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SSEDisplayState extends State<SSEDisplay> {
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final fontSizeMedium = theme.textTheme.bodyMedium?.fontSize;
|
final fontSizeMedium = theme.textTheme.bodyMedium?.fontSize;
|
||||||
final isDark = theme.brightness == Brightness.dark;
|
final isDark = theme.brightness == Brightness.dark;
|
||||||
List<dynamic> sse;
|
if (sseOutput == null || sseOutput!.isEmpty) {
|
||||||
try {
|
|
||||||
sse = jsonDecode(widget.sseOutput);
|
|
||||||
} catch (e) {
|
|
||||||
return Text(
|
return Text(
|
||||||
'Invalid SSE output',
|
'No content',
|
||||||
style: kCodeStyle.copyWith(
|
style: kCodeStyle.copyWith(
|
||||||
fontSize: fontSizeMedium,
|
fontSize: fontSizeMedium,
|
||||||
color: isDark ? kColorDarkDanger : kColorLightDanger,
|
color: isDark ? kColorDarkDanger : kColorLightDanger,
|
||||||
@@ -31,7 +26,7 @@ class _SSEDisplayState extends State<SSEDisplay> {
|
|||||||
|
|
||||||
return ListView(
|
return ListView(
|
||||||
padding: kP1,
|
padding: kP1,
|
||||||
children: sse.reversed.where((e) => e != '').map<Widget>((chunk) {
|
children: sseOutput!.reversed.where((e) => e != '').map<Widget>((chunk) {
|
||||||
Map<String, dynamic>? parsedJson;
|
Map<String, dynamic>? parsedJson;
|
||||||
try {
|
try {
|
||||||
parsedJson = jsonDecode(chunk);
|
parsedJson = jsonDecode(chunk);
|
||||||
|
|||||||
Reference in New Issue
Block a user