SSE: SSEDisplay Implemented along with SSE ResponseBodyView Type

This commit is contained in:
Manas Hejmadi
2025-06-29 17:07:28 +05:30
parent 882b393fdd
commit 383b6ad4bc
5 changed files with 102 additions and 14 deletions

View File

@@ -159,6 +159,7 @@ enum ResponseBodyView {
preview("Preview", Icons.visibility_rounded), preview("Preview", Icons.visibility_rounded),
code("Preview", Icons.code_rounded), code("Preview", Icons.code_rounded),
raw("Raw", Icons.text_snippet_rounded), raw("Raw", Icons.text_snippet_rounded),
sse("SSE", Icons.stream),
none("Preview", Icons.warning); none("Preview", Icons.warning);
const ResponseBodyView(this.label, this.icon); const ResponseBodyView(this.label, this.icon);

View File

@@ -395,10 +395,12 @@ class CollectionStateNotifier
); );
} else { } else {
final statusCode = response.statusCode; final statusCode = response.statusCode;
respModel = baseHttpResponseModel.fromResponse(
response: response, respModel = respModel ??
time: duration, baseHttpResponseModel.fromResponse(
); response: response,
time: duration,
);
newRequestModel = newRequestModel.copyWith( newRequestModel = newRequestModel.copyWith(
responseStatus: statusCode, responseStatus: statusCode,

View File

@@ -59,16 +59,13 @@ class ResponseBody extends StatelessWidget {
// print('reM -> ${responseModel.sseOutput}'); // print('reM -> ${responseModel.sseOutput}');
if (responseModel.sseOutput?.isNotEmpty ?? false) { if (responseModel.sseOutput?.isNotEmpty ?? false) {
final modifiedBody = responseModel.sseOutput!.join('\n\n'); // final modifiedBody = responseModel.sseOutput!.join('\n\n');
print(modifiedBody);
return ResponseBodySuccess( return ResponseBodySuccess(
key: Key("${selectedRequestModel!.id}-response"), key: Key("${selectedRequestModel!.id}-response"),
mediaType: mediaType, mediaType: MediaType('text', 'event-stream'),
options: options, options: [ResponseBodyView.sse],
bytes: utf8.encode(modifiedBody), bytes: utf8.encode((responseModel.sseOutput!).toString()),
body: modifiedBody, body: jsonEncode(responseModel.sseOutput!),
formattedBody: modifiedBody,
highlightLanguage: highlightLanguage,
); );
} }

View File

@@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_core/apidash_core.dart';
import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:apidash_design_system/apidash_design_system.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@@ -144,6 +146,17 @@ class _ResponseBodySuccessState extends State<ResponseBodySuccess> {
), ),
), ),
), ),
ResponseBodyView.sse => Expanded(
child: Container(
width: double.maxFinite,
padding: kP8,
decoration: textContainerdecoration,
child: SingleChildScrollView(
child: SSEDisplay(
sseOutput: widget.body,
)),
),
),
} }
], ],
), ),
@@ -152,3 +165,78 @@ class _ResponseBodySuccessState extends State<ResponseBodySuccess> {
); );
} }
} }
//MOVE THIS SOMEWHERE ELSE
class SSEDisplay extends StatelessWidget {
final String sseOutput;
const SSEDisplay({super.key, required this.sseOutput});
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
List<dynamic> sse;
try {
sse = jsonDecode(sseOutput);
} catch (e) {
return Text(
'Invalid SSE output',
style: theme.textTheme.bodyMedium?.copyWith(color: Colors.red),
);
}
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: sse.map<Widget>((chunk) {
Map<String, dynamic>? parsedJson;
try {
parsedJson = jsonDecode(chunk);
} catch (_) {
// Not a JSON object
}
return Card(
margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 8),
elevation: 2,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: parsedJson != null
? Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: parsedJson.entries.map((entry) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${entry.key}: ',
style: theme.textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.bold,
color: kColorGQL),
),
SizedBox(width: 4),
Expanded(
child: Text(
entry.value.toString(),
style: theme.textTheme.bodyMedium
?.copyWith(fontFamily: 'monospace'),
),
),
],
),
);
}).toList(),
)
: Text(
chunk.toString(),
style: theme.textTheme.bodyMedium
?.copyWith(fontFamily: 'monospace'),
),
),
);
}).toList(),
);
}
}

View File

@@ -16,8 +16,8 @@ void main() {
theme: kThemeDataLight, theme: kThemeDataLight,
home: Scaffold( home: Scaffold(
body: SendButton( body: SendButton(
isWorking: false,
isStreaming: false, isStreaming: false,
isWorking: false,
onTap: () => sendPressed = true, onTap: () => sendPressed = true,
onCancel: () => cancelPressed = true, onCancel: () => cancelPressed = true,
), ),
@@ -46,8 +46,8 @@ void main() {
theme: kThemeDataLight, theme: kThemeDataLight,
home: Scaffold( home: Scaffold(
body: SendButton( body: SendButton(
isWorking: true,
isStreaming: false, isStreaming: false,
isWorking: true,
onTap: () => sendPressed = true, onTap: () => sendPressed = true,
onCancel: () => cancelPressed = true, onCancel: () => cancelPressed = true,
), ),