From 3bb9fb25310eadf36c04ec9d453eb2ffa1b7c1f3 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Wed, 10 Sep 2025 12:55:42 +0530 Subject: [PATCH] refactor: split terminal models --- lib/consts.dart | 10 +++ lib/models/models.dart | 2 +- lib/models/terminal/js_log_data.dart | 15 +++++ lib/models/terminal/models.dart | 4 ++ lib/models/terminal/network_log_data.dart | 82 +++++++++++++++++++++++ lib/models/terminal/system_log_data.dart | 6 ++ lib/models/terminal/terminal_entry.dart | 55 +++++++++++++++ lib/providers/terminal_providers.dart | 3 +- lib/screens/terminal/terminal_page.dart | 11 +-- 9 files changed, 182 insertions(+), 6 deletions(-) create mode 100644 lib/models/terminal/js_log_data.dart create mode 100644 lib/models/terminal/models.dart create mode 100644 lib/models/terminal/network_log_data.dart create mode 100644 lib/models/terminal/system_log_data.dart create mode 100644 lib/models/terminal/terminal_entry.dart diff --git a/lib/consts.dart b/lib/consts.dart index 1d7aa6e4..cf8e5fe6 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -3,6 +3,7 @@ import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +// Terminal enums moved here from models to avoid circular imports and simplify usage const kDiscordUrl = "https://bit.ly/heyfoss"; const kGitUrl = "https://github.com/foss42/apidash"; @@ -85,6 +86,15 @@ enum HistoryRetentionPeriod { final IconData icon; } +/// Source category of a terminal entry +enum TerminalSource { network, js, system } + +/// Severity level of a terminal entry +enum TerminalLevel { debug, info, warn, error } + +/// Phase of a network log lifecycle +enum NetworkPhase { started, progress, completed, failed } + enum ItemMenuOption { edit("Rename"), delete("Delete"), diff --git a/lib/models/models.dart b/lib/models/models.dart index 6a724dd5..cfc7c58d 100644 --- a/lib/models/models.dart +++ b/lib/models/models.dart @@ -2,4 +2,4 @@ export 'history_meta_model.dart'; export 'history_request_model.dart'; export 'request_model.dart'; export 'settings_model.dart'; -export 'terminal_models.dart'; +export 'terminal/models.dart'; diff --git a/lib/models/terminal/js_log_data.dart b/lib/models/terminal/js_log_data.dart new file mode 100644 index 00000000..7a166f31 --- /dev/null +++ b/lib/models/terminal/js_log_data.dart @@ -0,0 +1,15 @@ +class JsLogData { + JsLogData({ + required this.level, + required this.args, + this.stack, + this.context, + this.contextRequestId, + }); + + final String level; // log | warn | error | fatal + final List args; + final String? stack; + final String? context; // preRequest | postResponse | global + final String? contextRequestId; +} diff --git a/lib/models/terminal/models.dart b/lib/models/terminal/models.dart new file mode 100644 index 00000000..82c1977b --- /dev/null +++ b/lib/models/terminal/models.dart @@ -0,0 +1,4 @@ +export 'network_log_data.dart'; +export 'js_log_data.dart'; +export 'system_log_data.dart'; +export 'terminal_entry.dart'; diff --git a/lib/models/terminal/network_log_data.dart b/lib/models/terminal/network_log_data.dart new file mode 100644 index 00000000..ae6e55b1 --- /dev/null +++ b/lib/models/terminal/network_log_data.dart @@ -0,0 +1,82 @@ +import 'package:apidash/consts.dart'; +import 'package:apidash_core/apidash_core.dart' show APIType, HTTPVerb; + +class NetworkLogData { + NetworkLogData({ + required this.phase, + required this.apiType, + required this.method, + required this.url, + this.requestHeaders, + this.requestBodyPreview, + this.responseStatus, + this.responseHeaders, + this.responseBodyPreview, + this.duration, + this.isStreaming = false, + this.sentAt, + this.completedAt, + this.errorMessage, + List? chunks, + }) : chunks = chunks ?? []; + + final NetworkPhase phase; + final APIType apiType; + final HTTPVerb method; + final String url; + final Map? requestHeaders; + final String? requestBodyPreview; + final int? responseStatus; + final Map? responseHeaders; + final String? responseBodyPreview; + final Duration? duration; + final bool isStreaming; + final DateTime? sentAt; + final DateTime? completedAt; + final String? errorMessage; + final List chunks; + + NetworkLogData copyWith({ + NetworkPhase? phase, + APIType? apiType, + HTTPVerb? method, + String? url, + Map? requestHeaders, + String? requestBodyPreview, + int? responseStatus, + Map? responseHeaders, + String? responseBodyPreview, + Duration? duration, + bool? isStreaming, + DateTime? sentAt, + DateTime? completedAt, + String? errorMessage, + List? chunks, + }) { + return NetworkLogData( + phase: phase ?? this.phase, + apiType: apiType ?? this.apiType, + method: method ?? this.method, + url: url ?? this.url, + requestHeaders: requestHeaders ?? this.requestHeaders, + requestBodyPreview: requestBodyPreview ?? this.requestBodyPreview, + responseStatus: responseStatus ?? this.responseStatus, + responseHeaders: responseHeaders ?? this.responseHeaders, + responseBodyPreview: responseBodyPreview ?? this.responseBodyPreview, + duration: duration ?? this.duration, + isStreaming: isStreaming ?? this.isStreaming, + sentAt: sentAt ?? this.sentAt, + completedAt: completedAt ?? this.completedAt, + errorMessage: errorMessage ?? this.errorMessage, + chunks: chunks ?? this.chunks, + ); + } +} + +class BodyChunk { + BodyChunk({required this.ts, required this.text, required this.sizeBytes}); + + final DateTime ts; + final String text; // preview text (could be partial) + final int sizeBytes; +} diff --git a/lib/models/terminal/system_log_data.dart b/lib/models/terminal/system_log_data.dart new file mode 100644 index 00000000..bb20c17b --- /dev/null +++ b/lib/models/terminal/system_log_data.dart @@ -0,0 +1,6 @@ +class SystemLogData { + SystemLogData({required this.category, required this.message, this.stack}); + final String category; // ui | provider | io | storage | unknown + final String message; + final String? stack; +} diff --git a/lib/models/terminal/terminal_entry.dart b/lib/models/terminal/terminal_entry.dart new file mode 100644 index 00000000..ae1e2fa9 --- /dev/null +++ b/lib/models/terminal/terminal_entry.dart @@ -0,0 +1,55 @@ +import 'package:apidash/consts.dart'; +import 'network_log_data.dart'; +import 'js_log_data.dart'; +import 'system_log_data.dart'; + +class TerminalEntry { + TerminalEntry({ + required this.id, + required this.ts, + required this.source, + required this.level, + this.requestId, + this.correlationId, + this.tags = const [], + this.network, + this.js, + this.system, + }); + + final String id; + final DateTime ts; + final TerminalSource source; + final TerminalLevel level; + final String? requestId; // App request id for correlation + final String? correlationId; // Additional correlation if any + final List tags; + final NetworkLogData? network; + final JsLogData? js; + final SystemLogData? system; + + TerminalEntry copyWith({ + DateTime? ts, + TerminalSource? source, + TerminalLevel? level, + String? requestId, + String? correlationId, + List? tags, + NetworkLogData? network, + JsLogData? js, + SystemLogData? system, + }) { + return TerminalEntry( + id: id, + ts: ts ?? this.ts, + source: source ?? this.source, + level: level ?? this.level, + requestId: requestId ?? this.requestId, + correlationId: correlationId ?? this.correlationId, + tags: tags ?? this.tags, + network: network ?? this.network, + js: js ?? this.js, + system: system ?? this.system, + ); + } +} diff --git a/lib/providers/terminal_providers.dart b/lib/providers/terminal_providers.dart index 3ec406ab..b8453283 100644 --- a/lib/providers/terminal_providers.dart +++ b/lib/providers/terminal_providers.dart @@ -1,7 +1,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:uuid/uuid.dart'; import 'package:apidash_core/apidash_core.dart'; -import '../models/terminal_models.dart'; +import '../models/terminal/models.dart'; +import '../consts.dart'; final terminalStateProvider = StateNotifierProvider((ref) { diff --git a/lib/screens/terminal/terminal_page.dart b/lib/screens/terminal/terminal_page.dart index 14237529..5c7fa52d 100644 --- a/lib/screens/terminal/terminal_page.dart +++ b/lib/screens/terminal/terminal_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import '../../models/terminal_models.dart'; +import '../../models/terminal/models.dart'; +import '../../consts.dart'; import '../../providers/terminal_providers.dart'; class TerminalPage extends ConsumerWidget { @@ -23,9 +24,11 @@ class TerminalPage extends ConsumerWidget { final icon = _iconFor(e); return ListTile( leading: Icon(icon), - title: Text(title, maxLines: 1, overflow: TextOverflow.ellipsis), - subtitle: Text(subtitle ?? '', - maxLines: 2, overflow: TextOverflow.ellipsis), + title: SelectableText(title, maxLines: 1), + subtitle: SelectableText( + subtitle ?? '', + maxLines: 2, + ), dense: true, ); },