From 1173ac870f396716b0516c6d7487f0e8a3009a59 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Thu, 9 Jan 2025 18:52:43 +0530 Subject: [PATCH 01/53] Create instructions_to_run_generated_codes.md --- doc/user_guide/instructions_to_run_generated_codes.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/user_guide/instructions_to_run_generated_codes.md diff --git a/doc/user_guide/instructions_to_run_generated_codes.md b/doc/user_guide/instructions_to_run_generated_codes.md new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/doc/user_guide/instructions_to_run_generated_codes.md @@ -0,0 +1 @@ + From 72c5383195906e736899e67c3f557b53c78484f4 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Thu, 9 Jan 2025 18:54:20 +0530 Subject: [PATCH 02/53] Rename instructions_to_run_generated_codes.md to instructions_to_run_generated_code.md --- ...n_generated_codes.md => instructions_to_run_generated_code.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename doc/user_guide/{instructions_to_run_generated_codes.md => instructions_to_run_generated_code.md} (100%) diff --git a/doc/user_guide/instructions_to_run_generated_codes.md b/doc/user_guide/instructions_to_run_generated_code.md similarity index 100% rename from doc/user_guide/instructions_to_run_generated_codes.md rename to doc/user_guide/instructions_to_run_generated_code.md From 207a17a648a451a8a1e9dc561f0d1b111cde387b Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Thu, 9 Jan 2025 18:55:34 +0530 Subject: [PATCH 03/53] Update instructions_to_run_generated_code.md --- doc/user_guide/instructions_to_run_generated_code.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user_guide/instructions_to_run_generated_code.md b/doc/user_guide/instructions_to_run_generated_code.md index 8b137891..ef9088e7 100644 --- a/doc/user_guide/instructions_to_run_generated_code.md +++ b/doc/user_guide/instructions_to_run_generated_code.md @@ -1 +1 @@ - +# How to Run Generated Code for a Programming Language From 338f511221aeba2f2129eab2cfe1cb5b64d8c03c Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Thu, 9 Jan 2025 18:56:15 +0530 Subject: [PATCH 04/53] Update README.md --- doc/user_guide/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/user_guide/README.md b/doc/user_guide/README.md index a22842ae..88d659b4 100644 --- a/doc/user_guide/README.md +++ b/doc/user_guide/README.md @@ -3,6 +3,6 @@ - [History of Requests](https://github.com/foss42/apidash/blob/main/doc/user_guide/his_user_guide.md) - [Environment Variables Manager](https://github.com/foss42/apidash/blob/main/doc/user_guide/env_user_guide.md) - [How to Disable SSL for Requests](https://github.com/foss42/apidash/blob/main/doc/user_guide/disable_ssl.md) -- Import Request for cURL (Doc TODO) -- How to use Code Generator (Doc TODO) +- Import Request for cURL (Contributions Welcome!) +- [How to Run Generated Code for a Programming Language](https://github.com/foss42/apidash/blob/main/doc/user_guide/instructions_to_run_generated_code.md) (Contributions Welcome!) - [API Dash on Mobile](https://github.com/foss42/apidash/blob/main/doc/user_guide/req_user_guide.md) From 5bff5b1c72218c891020c0d442984e8404aad912 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Thu, 9 Jan 2025 19:05:53 +0530 Subject: [PATCH 05/53] Update instructions_to_run_generated_code.md --- .../instructions_to_run_generated_code.md | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/doc/user_guide/instructions_to_run_generated_code.md b/doc/user_guide/instructions_to_run_generated_code.md index ef9088e7..1bf5a043 100644 --- a/doc/user_guide/instructions_to_run_generated_code.md +++ b/doc/user_guide/instructions_to_run_generated_code.md @@ -1 +1,148 @@ # How to Run Generated Code for a Programming Language + +Choose your programming language/library from the list provided below to learn more how you can execute them: +- cURL +- C (libcurl) +- C# (HttpClient) +- C# (RestSharp) +- Dart (http) +- Dart (dio) +- Go (net/http) +- JavaScript (axios) +- JavaScript (fetch) +- node.js (JavaScript, axios) +- node.js (JavaScript, fetch) +- Java (asynchttpclient) +- Java (HttpClient) +- Java (okhttp3) +- Java (Unirest) +- Julia (HTTP) +- Kotlin (okhttp3) +- PHP (curl) +- PHP (guzzle) +- PHP (HTTPlug) +- Python (requests) +- Python (http.client) +- Ruby (faraday) +- Ruby (net/http) +- Rust (hyper) +- Rust (reqwest) +- Rust (ureq) +- Rust (Actix Client) +- Swift + +## cURL + +TODO + +## C (libcurl) + +TODO + +## C# (HttpClient) + +TODO + +## C# (RestSharp) + +TODO + +## Dart (http) + +TODO + +## Dart (dio) + +TODO + +## Go (net/http) + +TODO + +## JavaScript (axios) + +TODO + +## JavaScript (fetch) + +TODO + +## node.js (JavaScript, axios) + +TODO + +## node.js (JavaScript, fetch) + +TODO + +## Java (asynchttpclient) + +TODO + +## Java (HttpClient) + +TODO + +## Java (okhttp3) + +TODO + +## Java (Unirest) + +TODO + +## Julia (HTTP) + +TODO + +## Kotlin (okhttp3) + +TODO + +## PHP (curl) + +TODO + +## PHP (guzzle) + +TODO + +## PHP (HTTPlug) + +TODO + +## Python (requests) + +TODO + +## Python (http.client) + +TODO + +## Ruby (faraday) + +TODO + +## Ruby (net/http) + +TODO + +## Rust (hyper) + +TODO + +## Rust (reqwest) + +TODO + +## Rust (ureq) + +TODO + +## Rust (Actix Client) + +TODO + +## Swift + +TODO From 96e3810506547a257cb2250529dd305df7743253 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Thu, 9 Jan 2025 19:14:23 +0530 Subject: [PATCH 06/53] Update instructions_to_run_generated_code.md --- .../instructions_to_run_generated_code.md | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/doc/user_guide/instructions_to_run_generated_code.md b/doc/user_guide/instructions_to_run_generated_code.md index 1bf5a043..ce5c9589 100644 --- a/doc/user_guide/instructions_to_run_generated_code.md +++ b/doc/user_guide/instructions_to_run_generated_code.md @@ -1,35 +1,37 @@ # How to Run Generated Code for a Programming Language Choose your programming language/library from the list provided below to learn more how you can execute them: -- cURL -- C (libcurl) -- C# (HttpClient) -- C# (RestSharp) -- Dart (http) -- Dart (dio) -- Go (net/http) -- JavaScript (axios) -- JavaScript (fetch) -- node.js (JavaScript, axios) -- node.js (JavaScript, fetch) -- Java (asynchttpclient) -- Java (HttpClient) -- Java (okhttp3) -- Java (Unirest) -- Julia (HTTP) -- Kotlin (okhttp3) -- PHP (curl) -- PHP (guzzle) -- PHP (HTTPlug) -- Python (requests) -- Python (http.client) -- Ruby (faraday) -- Ruby (net/http) -- Rust (hyper) -- Rust (reqwest) -- Rust (ureq) -- Rust (Actix Client) -- Swift +- [cURL](#curl) +- [C (libcurl)](#c-libcurl) +- [C# (HttpClient)](#c-httpclient) +- [C# (RestSharp)](#c-restsharp) +- [Dart (http)](#dart-http) +- [Dart (dio)](#dart-dio) +- [Go (net/http)](#go-nethttp) +- [JavaScript (axios)](#javascript-axios) +- [JavaScript (fetch)](#javascript-fetch) +- [node.js (JavaScript, axios)](#nodejs-javascript-axios) +- [node.js (JavaScript, fetch)](#nodejs-javascript-fetch) +- [Java (asynchttpclient)](#java-asynchttpclient) +- [Java (HttpClient)](#java-httpclient) +- [Java (okhttp3)](#java-okhttp3) +- [Java (Unirest)](#java-unirest) +- [Julia (HTTP)](#julia-http) +- [Kotlin (okhttp3)](#kotlin-okhttp3) +- [PHP (curl)](#php-curl) +- [PHP (guzzle)](#php-guzzle) +- [PHP (HTTPlug)](#php-httplug) +- [Python (requests)](#python-requests) +- [Python (http.client)](#python-httpclient) +- [Ruby (faraday)](#ruby-faraday) +- [Ruby (net/http)](#ruby-nethttp) +- [Rust (hyper)](#rust-hyper) +- [Rust (reqwest)](#rust-reqwest) +- [Rust (ureq)](#rust-ureq) +- [Rust (Actix Client)](#rust-actix-client) +- [Swift](#swift) + +**Please raise a GitHub issue in case any instruction is not clear or if it is not working.** ## cURL From 1aad26f22dd662ccfa3c88092fe6f1600a5fd85e Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Thu, 9 Jan 2025 19:48:12 +0530 Subject: [PATCH 07/53] Update README.md --- doc/user_guide/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user_guide/README.md b/doc/user_guide/README.md index 88d659b4..7d0795af 100644 --- a/doc/user_guide/README.md +++ b/doc/user_guide/README.md @@ -1,4 +1,4 @@ -## API Dash User Guide +# API Dash User Guide - [History of Requests](https://github.com/foss42/apidash/blob/main/doc/user_guide/his_user_guide.md) - [Environment Variables Manager](https://github.com/foss42/apidash/blob/main/doc/user_guide/env_user_guide.md) From a84af15f0daa789c164a13ff3e21b391095ffb80 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 11 Jan 2025 12:36:01 +0530 Subject: [PATCH 08/53] Add graphql enum --- packages/apidash_core/lib/consts.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/apidash_core/lib/consts.dart b/packages/apidash_core/lib/consts.dart index c17ec451..1ef6b0dd 100644 --- a/packages/apidash_core/lib/consts.dart +++ b/packages/apidash_core/lib/consts.dart @@ -1,7 +1,8 @@ import 'dart:convert'; enum APIType { - rest("HTTP"); + rest("HTTP"), + graphql("GraphQL"); const APIType(this.label); final String label; From ba532462e4808eb717ea16448d7fea7b4f6d73e6 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 11 Jan 2025 13:46:47 +0530 Subject: [PATCH 09/53] Update request_model.g.dart --- lib/models/request_model.g.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/models/request_model.g.dart b/lib/models/request_model.g.dart index be2132fe..68b56395 100644 --- a/lib/models/request_model.g.dart +++ b/lib/models/request_model.g.dart @@ -43,4 +43,5 @@ Map _$$RequestModelImplToJson(_$RequestModelImpl instance) => const _$APITypeEnumMap = { APIType.rest: 'rest', + APIType.graphql: 'graphql', }; From 9339d9a8de94c73cd206276315abd98c2e047468 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 11 Jan 2025 13:46:51 +0530 Subject: [PATCH 10/53] Update consts.dart --- lib/consts.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/consts.dart b/lib/consts.dart index 89fe61fb..6b569de5 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -438,6 +438,7 @@ const kLabelViewCode = "View Code"; const kLabelURLParams = "URL Params"; const kLabelHeaders = "Headers"; const kLabelBody = "Body"; +const kLabelQuery = "Query"; const kNameCheckbox = "Checkbox"; const kNameURLParam = "URL Parameter"; const kNameHeader = "Header Name"; From d5d02a23cebbb4d0f7564d60589efa4fe064084a Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 11 Jan 2025 14:13:01 +0530 Subject: [PATCH 11/53] Fix seed --- packages/seed/CHANGELOG.md | 4 ++++ packages/seed/pubspec.yaml | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/seed/CHANGELOG.md b/packages/seed/CHANGELOG.md index f64fbe64..1415857f 100644 --- a/packages/seed/CHANGELOG.md +++ b/packages/seed/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.3 + +- Fix: Add `json_serializable` under dev_dependencies. + ## 0.0.2 - Fix pubspec dependency for freezed_annotation. diff --git a/packages/seed/pubspec.yaml b/packages/seed/pubspec.yaml index 6f52781a..03d4ec9b 100644 --- a/packages/seed/pubspec.yaml +++ b/packages/seed/pubspec.yaml @@ -1,6 +1,6 @@ name: seed description: Seed is a foundational package designed to provide reusable building blocks for API Dash projects. -version: 0.0.2 +version: 0.0.3 homepage: https://github.com/foss42/apidash/tree/main/packages/seed repository: https://github.com/foss42/apidash/tree/main/packages/seed issue_tracker: https://github.com/foss42/apidash/issues @@ -15,5 +15,6 @@ dependencies: dev_dependencies: build_runner: ^2.4.12 freezed: ^2.5.7 + json_serializable: ^6.7.1 lints: ^4.0.0 test: ^1.24.0 From e9b495b166f2f72e491e19dde050c225f8296f52 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 11 Jan 2025 14:15:22 +0530 Subject: [PATCH 12/53] Update curl_parser --- packages/curl_parser/CHANGELOG.md | 4 ++++ packages/curl_parser/pubspec.yaml | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/curl_parser/CHANGELOG.md b/packages/curl_parser/CHANGELOG.md index 67747c87..a1e45ef0 100644 --- a/packages/curl_parser/CHANGELOG.md +++ b/packages/curl_parser/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.1.2 + +- Bump dependencies. + ## 0.1.1 - Add formdata support and new test cases. diff --git a/packages/curl_parser/pubspec.yaml b/packages/curl_parser/pubspec.yaml index 1f3c969f..82e795ca 100644 --- a/packages/curl_parser/pubspec.yaml +++ b/packages/curl_parser/pubspec.yaml @@ -1,6 +1,6 @@ name: curl_parser description: Parse cURL command to Dart object and convert Dart object to cURL command. -version: 0.1.1 +version: 0.1.2 homepage: https://github.com/foss42/apidash/tree/main/packages/curl_parser repository: https://github.com/foss42/apidash/tree/main/packages/curl_parser issue_tracker: https://github.com/foss42/apidash/issues @@ -19,7 +19,7 @@ environment: dependencies: args: ^2.5.0 equatable: ^2.0.5 - seed: ^0.0.1 + seed: ^0.0.3 shlex: ^2.0.2 dev_dependencies: From d2858cfdaf710dfb586f2094e4e004753121c527 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 11 Jan 2025 14:22:17 +0530 Subject: [PATCH 13/53] Delete pubspec_overrides.yaml --- packages/curl_parser/pubspec_overrides.yaml | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 packages/curl_parser/pubspec_overrides.yaml diff --git a/packages/curl_parser/pubspec_overrides.yaml b/packages/curl_parser/pubspec_overrides.yaml deleted file mode 100644 index 8fa1ad79..00000000 --- a/packages/curl_parser/pubspec_overrides.yaml +++ /dev/null @@ -1,4 +0,0 @@ -# melos_managed_dependency_overrides: seed -dependency_overrides: - seed: - path: ../seed From bc4054343e9d592940f999a6c7d124f39298a4f7 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 11 Jan 2025 14:23:00 +0530 Subject: [PATCH 14/53] Update ignore files --- packages/curl_parser/.gitignore | 1 + packages/curl_parser/.pubignore | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/curl_parser/.gitignore b/packages/curl_parser/.gitignore index 04a9b6ff..9e94da4c 100644 --- a/packages/curl_parser/.gitignore +++ b/packages/curl_parser/.gitignore @@ -30,3 +30,4 @@ build/ .vscode/ coverage/ +pubspec_overrides.yaml diff --git a/packages/curl_parser/.pubignore b/packages/curl_parser/.pubignore index 6cea8211..b36f11f5 100644 --- a/packages/curl_parser/.pubignore +++ b/packages/curl_parser/.pubignore @@ -4,3 +4,4 @@ melos_curl_parser.iml build/ coverage/ test/ +pubspec_overrides.yaml From 4c524dba9c16dc99bc5bbff5648195f8ff147dbc Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 11 Jan 2025 14:26:58 +0530 Subject: [PATCH 15/53] Update HttpRequestModel --- .../lib/models/http_request_model.dart | 3 ++- .../models/http_request_model.freezed.dart | 23 ++++++++++++++++++- .../lib/models/http_request_model.g.dart | 2 ++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/apidash_core/lib/models/http_request_model.dart b/packages/apidash_core/lib/models/http_request_model.dart index 90efe4be..cc2d7411 100644 --- a/packages/apidash_core/lib/models/http_request_model.dart +++ b/packages/apidash_core/lib/models/http_request_model.dart @@ -7,7 +7,6 @@ import '../utils/utils.dart' import '../consts.dart'; part 'http_request_model.freezed.dart'; - part 'http_request_model.g.dart'; @freezed @@ -27,6 +26,7 @@ class HttpRequestModel with _$HttpRequestModel { List? isParamEnabledList, @Default(ContentType.json) ContentType bodyContentType, String? body, + String? query, List? formData, }) = _HttpRequestModel; @@ -61,6 +61,7 @@ class HttpRequestModel with _$HttpRequestModel { kMethodsWithBody.contains(method) && hasFormDataContentType && formDataMapList.isNotEmpty; + bool get hasQuery => query?.isNotEmpty ?? false; List get formDataList => formData ?? []; List> get formDataMapList => rowsToFormDataMapList(formDataList) ?? []; diff --git a/packages/apidash_core/lib/models/http_request_model.freezed.dart b/packages/apidash_core/lib/models/http_request_model.freezed.dart index 23c9dbbb..38cd0132 100644 --- a/packages/apidash_core/lib/models/http_request_model.freezed.dart +++ b/packages/apidash_core/lib/models/http_request_model.freezed.dart @@ -28,6 +28,7 @@ mixin _$HttpRequestModel { List? get isParamEnabledList => throw _privateConstructorUsedError; ContentType get bodyContentType => throw _privateConstructorUsedError; String? get body => throw _privateConstructorUsedError; + String? get query => throw _privateConstructorUsedError; List? get formData => throw _privateConstructorUsedError; /// Serializes this HttpRequestModel to a JSON map. @@ -55,6 +56,7 @@ abstract class $HttpRequestModelCopyWith<$Res> { List? isParamEnabledList, ContentType bodyContentType, String? body, + String? query, List? formData}); } @@ -81,6 +83,7 @@ class _$HttpRequestModelCopyWithImpl<$Res, $Val extends HttpRequestModel> Object? isParamEnabledList = freezed, Object? bodyContentType = null, Object? body = freezed, + Object? query = freezed, Object? formData = freezed, }) { return _then(_value.copyWith( @@ -116,6 +119,10 @@ class _$HttpRequestModelCopyWithImpl<$Res, $Val extends HttpRequestModel> ? _value.body : body // ignore: cast_nullable_to_non_nullable as String?, + query: freezed == query + ? _value.query + : query // ignore: cast_nullable_to_non_nullable + as String?, formData: freezed == formData ? _value.formData : formData // ignore: cast_nullable_to_non_nullable @@ -141,6 +148,7 @@ abstract class _$$HttpRequestModelImplCopyWith<$Res> List? isParamEnabledList, ContentType bodyContentType, String? body, + String? query, List? formData}); } @@ -165,6 +173,7 @@ class __$$HttpRequestModelImplCopyWithImpl<$Res> Object? isParamEnabledList = freezed, Object? bodyContentType = null, Object? body = freezed, + Object? query = freezed, Object? formData = freezed, }) { return _then(_$HttpRequestModelImpl( @@ -200,6 +209,10 @@ class __$$HttpRequestModelImplCopyWithImpl<$Res> ? _value.body : body // ignore: cast_nullable_to_non_nullable as String?, + query: freezed == query + ? _value.query + : query // ignore: cast_nullable_to_non_nullable + as String?, formData: freezed == formData ? _value._formData : formData // ignore: cast_nullable_to_non_nullable @@ -221,6 +234,7 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { final List? isParamEnabledList, this.bodyContentType = ContentType.json, this.body, + this.query, final List? formData}) : _headers = headers, _params = params, @@ -285,6 +299,8 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { final ContentType bodyContentType; @override final String? body; + @override + final String? query; final List? _formData; @override List? get formData { @@ -297,7 +313,7 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { @override String toString() { - return 'HttpRequestModel(method: $method, url: $url, headers: $headers, params: $params, isHeaderEnabledList: $isHeaderEnabledList, isParamEnabledList: $isParamEnabledList, bodyContentType: $bodyContentType, body: $body, formData: $formData)'; + return 'HttpRequestModel(method: $method, url: $url, headers: $headers, params: $params, isHeaderEnabledList: $isHeaderEnabledList, isParamEnabledList: $isParamEnabledList, bodyContentType: $bodyContentType, body: $body, query: $query, formData: $formData)'; } @override @@ -316,6 +332,7 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { (identical(other.bodyContentType, bodyContentType) || other.bodyContentType == bodyContentType) && (identical(other.body, body) || other.body == body) && + (identical(other.query, query) || other.query == query) && const DeepCollectionEquality().equals(other._formData, _formData)); } @@ -331,6 +348,7 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { const DeepCollectionEquality().hash(_isParamEnabledList), bodyContentType, body, + query, const DeepCollectionEquality().hash(_formData)); /// Create a copy of HttpRequestModel @@ -360,6 +378,7 @@ abstract class _HttpRequestModel extends HttpRequestModel { final List? isParamEnabledList, final ContentType bodyContentType, final String? body, + final String? query, final List? formData}) = _$HttpRequestModelImpl; const _HttpRequestModel._() : super._(); @@ -383,6 +402,8 @@ abstract class _HttpRequestModel extends HttpRequestModel { @override String? get body; @override + String? get query; + @override List? get formData; /// Create a copy of HttpRequestModel diff --git a/packages/apidash_core/lib/models/http_request_model.g.dart b/packages/apidash_core/lib/models/http_request_model.g.dart index da13d3ae..29005786 100644 --- a/packages/apidash_core/lib/models/http_request_model.g.dart +++ b/packages/apidash_core/lib/models/http_request_model.g.dart @@ -29,6 +29,7 @@ _$HttpRequestModelImpl _$$HttpRequestModelImplFromJson(Map json) => $enumDecodeNullable(_$ContentTypeEnumMap, json['bodyContentType']) ?? ContentType.json, body: json['body'] as String?, + query: json['query'] as String?, formData: (json['formData'] as List?) ?.map((e) => FormDataModel.fromJson(Map.from(e as Map))) @@ -46,6 +47,7 @@ Map _$$HttpRequestModelImplToJson( 'isParamEnabledList': instance.isParamEnabledList, 'bodyContentType': _$ContentTypeEnumMap[instance.bodyContentType]!, 'body': instance.body, + 'query': instance.query, 'formData': instance.formData?.map((e) => e.toJson()).toList(), }; From 008e8cdcaf9a2e1ea9b30f09401544975d8804f7 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 11 Jan 2025 14:27:05 +0530 Subject: [PATCH 16/53] Update http_response_model.dart --- packages/apidash_core/lib/models/http_response_model.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/apidash_core/lib/models/http_response_model.dart b/packages/apidash_core/lib/models/http_response_model.dart index 9a3ff7a2..914aaa57 100644 --- a/packages/apidash_core/lib/models/http_response_model.dart +++ b/packages/apidash_core/lib/models/http_response_model.dart @@ -10,7 +10,6 @@ import '../utils/utils.dart'; import '../consts.dart'; part 'http_response_model.freezed.dart'; - part 'http_response_model.g.dart'; class Uint8ListConverter implements JsonConverter?> { From 14ec41de65d800e2cc5613ac13fee424d27cfebc Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 11 Jan 2025 14:27:26 +0530 Subject: [PATCH 17/53] Update pubspec.yaml --- packages/apidash_core/pubspec.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/apidash_core/pubspec.yaml b/packages/apidash_core/pubspec.yaml index f6f72beb..f9c31cfd 100644 --- a/packages/apidash_core/pubspec.yaml +++ b/packages/apidash_core/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: http_parser: ^4.0.2 postman: path: ../postman - seed: ^0.0.2 + seed: ^0.0.3 xml: ^6.3.0 dev_dependencies: @@ -28,4 +28,5 @@ dev_dependencies: build_runner: ^2.4.12 flutter_lints: ^4.0.0 freezed: ^2.5.7 + json_serializable: ^6.7.1 test: ^1.25.2 From 86e782e25768340340f8d933d3d1f705da6544e8 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 11 Jan 2025 14:27:35 +0530 Subject: [PATCH 18/53] Update pubspec_overrides.yaml --- packages/apidash_core/pubspec_overrides.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/apidash_core/pubspec_overrides.yaml b/packages/apidash_core/pubspec_overrides.yaml index e1c03143..7c2883d9 100644 --- a/packages/apidash_core/pubspec_overrides.yaml +++ b/packages/apidash_core/pubspec_overrides.yaml @@ -1,6 +1,8 @@ -# melos_managed_dependency_overrides: seed,curl_parser +# melos_managed_dependency_overrides: curl_parser,postman,seed dependency_overrides: curl_parser: path: ../curl_parser + postman: + path: ../postman seed: path: ../seed From 0c682ac14e5d911d26fcdc29c701747b27e7244d Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sat, 11 Jan 2025 14:27:49 +0530 Subject: [PATCH 19/53] Update response_model_test.dart --- test/models/response_model_test.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/models/response_model_test.dart b/test/models/response_model_test.dart index 10e9f2e1..a568e383 100644 --- a/test/models/response_model_test.dart +++ b/test/models/response_model_test.dart @@ -16,6 +16,7 @@ void main() { test('Testing fromResponse', () async { (HttpResponse?, Duration?, String?)? responseRec = await request( requestModelGet1.id, + requestModelGet1.apiType, requestModelGet1.httpRequestModel!, defaultUriScheme: kDefaultUriScheme, noSSL: false, @@ -33,6 +34,7 @@ void main() { test('Testing fromResponse for contentType not Json', () async { (HttpResponse?, Duration?, String?)? responseRec = await request( requestModelGet13.id, + requestModelGet1.apiType, requestModelGet13.httpRequestModel!, defaultUriScheme: kDefaultUriScheme, noSSL: false, @@ -48,6 +50,7 @@ void main() { test('Testing fromResponse for Bad SSL with certificate check', () async { (HttpResponse?, Duration?, String?)? responseRec = await request( requestModelGetBadSSL.id, + requestModelGet1.apiType, requestModelGetBadSSL.httpRequestModel!, defaultUriScheme: kDefaultUriScheme, noSSL: false, @@ -59,6 +62,7 @@ void main() { test('Testing fromResponse for Bad SSL with no certificate check', () async { (HttpResponse?, Duration?, String?)? responseRec = await request( requestModelGetBadSSL.id, + requestModelGet1.apiType, requestModelGetBadSSL.httpRequestModel!, defaultUriScheme: kDefaultUriScheme, noSSL: true, From e33e79e2b43b2d13a564ae6e28de11efd5ef24b3 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 15:42:45 +0530 Subject: [PATCH 20/53] untitled constant --- integration_test/env_helper.dart | 2 +- integration_test/req_helper.dart | 2 +- lib/consts.dart | 1 + test/utils/envvar_utils_test.dart | 7 +++---- test/utils/http_utils_test.dart | 9 ++++----- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/integration_test/env_helper.dart b/integration_test/env_helper.dart index c26775a7..6f116674 100644 --- a/integration_test/env_helper.dart +++ b/integration_test/env_helper.dart @@ -26,7 +26,7 @@ class ApidashTestEnvHelper { Future renameNewEnvironment(String newEnvName) async { Finder envItems = find.byType(EnvironmentItem); Finder newEnvItem = envItems.at(1); - expect(find.descendant(of: newEnvItem, matching: find.text("untitled")), + expect(find.descendant(of: newEnvItem, matching: find.text(kUntitled)), findsOneWidget); Finder itemCardMenu = find.descendant(of: newEnvItem, matching: find.byType(ItemCardMenu)); diff --git a/integration_test/req_helper.dart b/integration_test/req_helper.dart index 8697c1bc..4a18745a 100644 --- a/integration_test/req_helper.dart +++ b/integration_test/req_helper.dart @@ -29,7 +29,7 @@ class ApidashTestRequestHelper { Future renameNewRequest(String newReqName) async { Finder reqItems = find.byType(RequestItem); Finder newReqItem = reqItems.at(0); - expect(find.descendant(of: newReqItem, matching: find.text("untitled")), + expect(find.descendant(of: newReqItem, matching: find.text(kUntitled)), findsOneWidget); Finder itemCardMenu = find.descendant(of: newReqItem, matching: find.byType(ItemCardMenu)); diff --git a/lib/consts.dart b/lib/consts.dart index 6b569de5..59680326 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -431,6 +431,7 @@ const kLabelSelect = "Select"; const kLabelContinue = "Continue"; const kLabelCancel = "Cancel"; const kLabelOk = "Ok"; +const kUntitled = "untitled"; // Request Pane const kLabelRequest = "Request"; const kLabelHideCode = "Hide Code"; diff --git a/test/utils/envvar_utils_test.dart b/test/utils/envvar_utils_test.dart index 5c166566..a6c9ee03 100644 --- a/test/utils/envvar_utils_test.dart +++ b/test/utils/envvar_utils_test.dart @@ -56,20 +56,19 @@ const activeEnvVars = [ void main() { group("Testing getEnvironmentTitle function", () { - String titleUntitled = "untitled"; test("Testing getEnvironmentTitle with null", () { String? envName1; - expect(getEnvironmentTitle(envName1), titleUntitled); + expect(getEnvironmentTitle(envName1), kUntitled); }); test("Testing getEnvironmentTitle with empty string", () { String envName2 = ""; - expect(getEnvironmentTitle(envName2), titleUntitled); + expect(getEnvironmentTitle(envName2), kUntitled); }); test("Testing getEnvironmentTitle with trimmable string", () { String envName3 = " "; - expect(getEnvironmentTitle(envName3), titleUntitled); + expect(getEnvironmentTitle(envName3), kUntitled); }); test("Testing getEnvironmentTitle with non-empty string", () { diff --git a/test/utils/http_utils_test.dart b/test/utils/http_utils_test.dart index 0f777ab1..7ffc7551 100644 --- a/test/utils/http_utils_test.dart +++ b/test/utils/http_utils_test.dart @@ -5,15 +5,14 @@ import 'package:apidash/consts.dart'; void main() { group("Testing getRequestTitleFromUrl function", () { - String titleUntitled = "untitled"; test('Testing getRequestTitleFromUrl using url1', () { String url1 = ""; - expect(getRequestTitleFromUrl(url1), titleUntitled); + expect(getRequestTitleFromUrl(url1), kUntitled); }); test('Testing getRequestTitleFromUrl using url2', () { String url2 = " "; - expect(getRequestTitleFromUrl(url2), titleUntitled); + expect(getRequestTitleFromUrl(url2), kUntitled); }); test('Testing getRequestTitleFromUrl using url3', () { @@ -30,11 +29,11 @@ void main() { test('Testing getRequestTitleFromUrl using url5', () { String url5 = "http://"; - expect(getRequestTitleFromUrl(url5), titleUntitled); + expect(getRequestTitleFromUrl(url5), kUntitled); }); test('Testing getRequestTitleFromUrl for null value', () { - expect(getRequestTitleFromUrl(null), titleUntitled); + expect(getRequestTitleFromUrl(null), kUntitled); }); }); From d8ec76aceca724e1b9a007e51ee19902effef95a Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 15:43:27 +0530 Subject: [PATCH 21/53] request_widgets_test => request_pane_test --- ...request_widgets.dart => request_pane.dart} | 28 ++++++++----------- lib/widgets/widgets.dart | 4 +-- ...dgets_test.dart => request_pane_test.dart} | 8 ++++-- 3 files changed, 20 insertions(+), 20 deletions(-) rename lib/widgets/{request_widgets.dart => request_pane.dart} (86%) rename test/widgets/{request_widgets_test.dart => request_pane_test.dart} (94%) diff --git a/lib/widgets/request_widgets.dart b/lib/widgets/request_pane.dart similarity index 86% rename from lib/widgets/request_widgets.dart rename to lib/widgets/request_pane.dart index 638c1f7a..95871d53 100644 --- a/lib/widgets/request_widgets.dart +++ b/lib/widgets/request_pane.dart @@ -12,6 +12,7 @@ class RequestPane extends StatefulHookWidget { this.tabIndex, this.onPressedCodeButton, this.onTapTabBar, + required this.tabLabels, required this.children, this.showIndicators = const [false, false, false], this.showViewCodeButton, @@ -22,6 +23,7 @@ class RequestPane extends StatefulHookWidget { final int? tabIndex; final void Function()? onPressedCodeButton; final void Function(int)? onTapTabBar; + final List tabLabels; final List children; final List showIndicators; final bool? showViewCodeButton; @@ -35,7 +37,7 @@ class _RequestPaneState extends State @override Widget build(BuildContext context) { final TabController controller = useTabController( - initialLength: 3, + initialLength: widget.children.length, vsync: this, ); if (widget.tabIndex != null) { @@ -75,27 +77,21 @@ class _RequestPaneState extends State ), ), ) - : const SizedBox.shrink(), + : kVSpacer10, TabBar( key: Key(widget.selectedId!), controller: controller, overlayColor: kColorTransparentState, labelPadding: kPh2, onTap: widget.onTapTabBar, - tabs: [ - TabLabel( - text: kLabelURLParams, - showIndicator: widget.showIndicators[0], - ), - TabLabel( - text: kLabelHeaders, - showIndicator: widget.showIndicators[1], - ), - TabLabel( - text: kLabelBody, - showIndicator: widget.showIndicators[2], - ), - ], + tabs: widget.tabLabels.indexed + .map( + (e) => TabLabel( + text: e.$2, + showIndicator: widget.showIndicators[e.$1], + ), + ) + .toList(), ), kVSpacer5, Expanded( diff --git a/lib/widgets/widgets.dart b/lib/widgets/widgets.dart index 1e452d7a..59b61f54 100644 --- a/lib/widgets/widgets.dart +++ b/lib/widgets/widgets.dart @@ -24,7 +24,6 @@ export 'dropdown_content_type.dart'; export 'dropdown_formdata.dart'; export 'dropdown_http_method.dart'; export 'dropdown_import_format.dart'; -export 'dropdown_api_type.dart'; export 'editor_json.dart'; export 'editor.dart'; export 'error_message.dart'; @@ -40,12 +39,13 @@ export 'markdown.dart'; export 'menu_item_card.dart'; export 'menu_sidebar_top.dart'; export 'overlay_widget.dart'; +export 'popup_menu_api_type.dart'; export 'popup_menu_codegen.dart'; export 'popup_menu_env.dart'; export 'popup_menu_history.dart'; export 'popup_menu_uri.dart'; export 'previewer.dart'; -export 'request_widgets.dart'; +export 'request_pane.dart'; export 'response_widgets.dart'; export 'splitview_drawer.dart'; export 'splitview_dashboard.dart'; diff --git a/test/widgets/request_widgets_test.dart b/test/widgets/request_pane_test.dart similarity index 94% rename from test/widgets/request_widgets_test.dart rename to test/widgets/request_pane_test.dart index 26322c24..8522c020 100644 --- a/test/widgets/request_widgets_test.dart +++ b/test/widgets/request_pane_test.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:apidash/widgets/request_widgets.dart'; +import 'package:apidash/widgets/request_pane.dart'; import '../extensions/widget_tester_extensions.dart'; import '../test_consts.dart'; @@ -15,8 +15,9 @@ void main() { body: RequestPane( selectedId: '1', codePaneVisible: true, - children: const [Text('abc'), Text('xyz'), Text('mno')], + tabLabels: const ['URL Params', 'Headers', 'Body'], onPressedCodeButton: () {}, + children: const [Text('abc'), Text('xyz'), Text('mno')], ), ), ), @@ -47,6 +48,7 @@ void main() { codePaneVisible: true, onPressedCodeButton: () {}, tabIndex: 1, + tabLabels: const ['URL Params', 'Headers', 'Body'], children: const [Text('abc'), Text('xyz'), Text('mno')], ), ), @@ -78,6 +80,7 @@ void main() { codePaneVisible: false, onPressedCodeButton: () {}, tabIndex: 2, + tabLabels: const ['URL Params', 'Headers', 'Body'], children: const [Text('abc'), Text('xyz'), Text('mno')], ), ), @@ -111,6 +114,7 @@ void main() { onTapTabBar: (value) { computedTabIndex = value; }, + tabLabels: const ['URL Params', 'Headers', 'Body'], children: const [Text('abc'), Text('xyz'), Text('mno')], ), ), From 45c2c73057beeb5668c56ad83bd8693ff2f264d7 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 15:43:33 +0530 Subject: [PATCH 22/53] Update pubspec.lock --- pubspec.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index ed80a941..0f9f35a4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -306,7 +306,7 @@ packages: path: "packages/curl_parser" relative: true source: path - version: "0.1.1" + version: "0.1.2" dart_style: dependency: "direct main" description: @@ -1364,10 +1364,10 @@ packages: dependency: transitive description: name: seed - sha256: "5c5ac5d73bf94e4b207d8c283903fc2b62ca8015e519b99949a8389605ee0eef" + sha256: "0d74a46abd169c96a73d9dec4739e6623021915661beadf265e885bb1eafd214" url: "https://pub.dev" source: hosted - version: "0.0.2" + version: "0.0.3" shared_preferences: dependency: "direct main" description: From 2a0bc9233f6d8e6128d4be88348f9433a1c0dd7c Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 15:43:38 +0530 Subject: [PATCH 23/53] Update melos.yaml --- melos.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/melos.yaml b/melos.yaml index 76344628..0759b566 100644 --- a/melos.yaml +++ b/melos.yaml @@ -8,6 +8,14 @@ scripts: run: melos exec -- "flutter analyze" description: Analyze all packages + clean: + run: melos exec -- "flutter clean" + description: Clean all packages + + build-gen: + run: melos exec -- "dart run build_runner build --delete-conflicting-outputs" + description: Run build generator for all packages + test: run: melos exec --dir-exists=test -- "flutter test --coverage" description: Run tests for all packages From f89123e26c85254e412be7750f120882f7dcc7f0 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 15:43:52 +0530 Subject: [PATCH 24/53] Add border color --- packages/apidash_design_system/lib/widgets/popup_menu.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/apidash_design_system/lib/widgets/popup_menu.dart b/packages/apidash_design_system/lib/widgets/popup_menu.dart index 06adea10..266028ee 100644 --- a/packages/apidash_design_system/lib/widgets/popup_menu.dart +++ b/packages/apidash_design_system/lib/widgets/popup_menu.dart @@ -10,6 +10,7 @@ class ADPopupMenu extends StatelessWidget { this.tooltip, this.width, this.isOutlined = false, + this.borderColor, }); final String? value; @@ -18,6 +19,7 @@ class ADPopupMenu extends StatelessWidget { final String? tooltip; final double? width; final bool isOutlined; + final Color? borderColor; @override Widget build(BuildContext context) { @@ -62,7 +64,8 @@ class ADPopupMenu extends StatelessWidget { return Container( decoration: BoxDecoration( border: Border.all( - color: Theme.of(context).colorScheme.onSurface, + color: borderColor ?? + Theme.of(context).colorScheme.surfaceContainerHighest, ), borderRadius: kBorderRadius8, ), From bdd7900f3cd6f385d3e73034e7adf4c157d96193 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 15:43:55 +0530 Subject: [PATCH 25/53] Update measurements.dart --- packages/apidash_design_system/lib/tokens/measurements.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/apidash_design_system/lib/tokens/measurements.dart b/packages/apidash_design_system/lib/tokens/measurements.dart index 4be0ec8a..638e5413 100644 --- a/packages/apidash_design_system/lib/tokens/measurements.dart +++ b/packages/apidash_design_system/lib/tokens/measurements.dart @@ -90,6 +90,7 @@ const kHSpacer10 = SizedBox(width: 10); const kHSpacer12 = SizedBox(width: 12); const kHSpacer20 = SizedBox(width: 20); const kHSpacer40 = SizedBox(width: 40); +const kVSpacer3 = SizedBox(height: 3); const kVSpacer5 = SizedBox(height: 5); const kVSpacer8 = SizedBox(height: 8); const kVSpacer10 = SizedBox(height: 10); From 7753e93e71a93bd2d9ecc7dbe94c7bc990a6be91 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 15:44:45 +0530 Subject: [PATCH 26/53] Add graphql support in apicore_core --- .../lib/services/http_service.dart | 135 ++++++++++-------- .../apidash_core/lib/utils/graphql_utils.dart | 11 ++ .../lib/utils/http_request_utils.dart | 13 ++ packages/apidash_core/lib/utils/utils.dart | 1 + 4 files changed, 104 insertions(+), 56 deletions(-) create mode 100644 packages/apidash_core/lib/utils/graphql_utils.dart diff --git a/packages/apidash_core/lib/services/http_service.dart b/packages/apidash_core/lib/services/http_service.dart index 2fb6aa7a..0bbc0501 100644 --- a/packages/apidash_core/lib/services/http_service.dart +++ b/packages/apidash_core/lib/services/http_service.dart @@ -12,6 +12,7 @@ typedef HttpResponse = http.Response; Future<(HttpResponse?, Duration?, String?)> request( String requestId, + APIType apiType, HttpRequestModel requestModel, { SupportedUriSchemes defaultUriScheme = kDefaultUriScheme, bool noSSL = false, @@ -28,74 +29,96 @@ Future<(HttpResponse?, Duration?, String?)> request( if (uriRec.$1 != null) { Uri requestUrl = uriRec.$1!; Map headers = requestModel.enabledHeadersMap; - HttpResponse response; + HttpResponse? response; String? body; try { Stopwatch stopwatch = Stopwatch()..start(); - var isMultiPartRequest = - requestModel.bodyContentType == ContentType.formdata; + if (apiType == APIType.rest) { + var isMultiPartRequest = + requestModel.bodyContentType == ContentType.formdata; - if (kMethodsWithBody.contains(requestModel.method)) { - var requestBody = requestModel.body; - if (requestBody != null && !isMultiPartRequest) { + if (kMethodsWithBody.contains(requestModel.method)) { + var requestBody = requestModel.body; + if (requestBody != null && !isMultiPartRequest) { + var contentLength = utf8.encode(requestBody).length; + if (contentLength > 0) { + body = requestBody; + headers[HttpHeaders.contentLengthHeader] = + contentLength.toString(); + if (!requestModel.hasContentTypeHeader) { + headers[HttpHeaders.contentTypeHeader] = + requestModel.bodyContentType.header; + } + } + } + if (isMultiPartRequest) { + var multiPartRequest = http.MultipartRequest( + requestModel.method.name.toUpperCase(), + requestUrl, + ); + multiPartRequest.headers.addAll(headers); + for (var formData in requestModel.formDataList) { + if (formData.type == FormDataType.text) { + multiPartRequest.fields.addAll({formData.name: formData.value}); + } else { + multiPartRequest.files.add( + await http.MultipartFile.fromPath( + formData.name, + formData.value, + ), + ); + } + } + http.StreamedResponse multiPartResponse = + await multiPartRequest.send(); + stopwatch.stop(); + http.Response convertedMultiPartResponse = + await convertStreamedResponse(multiPartResponse); + return (convertedMultiPartResponse, stopwatch.elapsed, null); + } + } + switch (requestModel.method) { + case HTTPVerb.get: + response = await client.get(requestUrl, headers: headers); + break; + case HTTPVerb.head: + response = await client.head(requestUrl, headers: headers); + break; + case HTTPVerb.post: + response = + await client.post(requestUrl, headers: headers, body: body); + break; + case HTTPVerb.put: + response = + await client.put(requestUrl, headers: headers, body: body); + break; + case HTTPVerb.patch: + response = + await client.patch(requestUrl, headers: headers, body: body); + break; + case HTTPVerb.delete: + response = + await client.delete(requestUrl, headers: headers, body: body); + break; + } + } + if (apiType == APIType.graphql) { + var requestBody = getGraphQLBody(requestModel); + if (requestBody != null) { var contentLength = utf8.encode(requestBody).length; if (contentLength > 0) { body = requestBody; headers[HttpHeaders.contentLengthHeader] = contentLength.toString(); if (!requestModel.hasContentTypeHeader) { - headers[HttpHeaders.contentTypeHeader] = - requestModel.bodyContentType.header; + headers[HttpHeaders.contentTypeHeader] = ContentType.json.header; } } } - if (isMultiPartRequest) { - var multiPartRequest = http.MultipartRequest( - requestModel.method.name.toUpperCase(), - requestUrl, - ); - multiPartRequest.headers.addAll(headers); - for (var formData in requestModel.formDataList) { - if (formData.type == FormDataType.text) { - multiPartRequest.fields.addAll({formData.name: formData.value}); - } else { - multiPartRequest.files.add( - await http.MultipartFile.fromPath( - formData.name, - formData.value, - ), - ); - } - } - http.StreamedResponse multiPartResponse = - await multiPartRequest.send(); - stopwatch.stop(); - http.Response convertedMultiPartResponse = - await convertStreamedResponse(multiPartResponse); - return (convertedMultiPartResponse, stopwatch.elapsed, null); - } - } - switch (requestModel.method) { - case HTTPVerb.get: - response = await client.get(requestUrl, headers: headers); - break; - case HTTPVerb.head: - response = await client.head(requestUrl, headers: headers); - break; - case HTTPVerb.post: - response = - await client.post(requestUrl, headers: headers, body: body); - break; - case HTTPVerb.put: - response = await client.put(requestUrl, headers: headers, body: body); - break; - case HTTPVerb.patch: - response = - await client.patch(requestUrl, headers: headers, body: body); - break; - case HTTPVerb.delete: - response = - await client.delete(requestUrl, headers: headers, body: body); - break; + response = await client.post( + requestUrl, + headers: headers, + body: body, + ); } stopwatch.stop(); return (response, stopwatch.elapsed, null); diff --git a/packages/apidash_core/lib/utils/graphql_utils.dart b/packages/apidash_core/lib/utils/graphql_utils.dart new file mode 100644 index 00000000..afa874bf --- /dev/null +++ b/packages/apidash_core/lib/utils/graphql_utils.dart @@ -0,0 +1,11 @@ +import '../consts.dart'; +import '../models/models.dart'; + +String? getGraphQLBody(HttpRequestModel httpRequestModel) { + if (httpRequestModel.hasQuery) { + return kJsonEncoder.convert({ + "query": httpRequestModel.query, + }); + } + return null; +} diff --git a/packages/apidash_core/lib/utils/http_request_utils.dart b/packages/apidash_core/lib/utils/http_request_utils.dart index 2e1daea5..7a912ac1 100644 --- a/packages/apidash_core/lib/utils/http_request_utils.dart +++ b/packages/apidash_core/lib/utils/http_request_utils.dart @@ -1,5 +1,8 @@ +import 'package:apidash_core/consts.dart'; import 'package:collection/collection.dart'; import 'package:seed/seed.dart'; +import '../models/models.dart'; +import 'graphql_utils.dart'; Map? rowsToMap( List? kvRows, { @@ -88,3 +91,13 @@ List? getEnabledRows( rows.where((element) => isRowEnabledList[rows.indexOf(element)]).toList(); return finalRows == [] ? null : finalRows; } + +String? getRequestBody(APIType type, HttpRequestModel httpRequestModel) { + return switch (type) { + APIType.rest => + (httpRequestModel.hasJsonData || httpRequestModel.hasTextData) + ? httpRequestModel.body + : null, + APIType.graphql => getGraphQLBody(httpRequestModel), + }; +} diff --git a/packages/apidash_core/lib/utils/utils.dart b/packages/apidash_core/lib/utils/utils.dart index 201d4d64..f39e563d 100644 --- a/packages/apidash_core/lib/utils/utils.dart +++ b/packages/apidash_core/lib/utils/utils.dart @@ -1,4 +1,5 @@ export 'content_type_utils.dart'; +export 'graphql_utils.dart'; export 'http_request_utils.dart'; export 'http_response_utils.dart'; export 'string_utils.dart'; From 641e04a84078256ed0dd6dc2368ff8627ab47762 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 15:44:50 +0530 Subject: [PATCH 27/53] Update string_extensions.dart --- .../lib/extensions/string_extensions.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/apidash_core/lib/extensions/string_extensions.dart b/packages/apidash_core/lib/extensions/string_extensions.dart index 86813788..6835a923 100644 --- a/packages/apidash_core/lib/extensions/string_extensions.dart +++ b/packages/apidash_core/lib/extensions/string_extensions.dart @@ -19,3 +19,15 @@ extension StringExtension on String { return "${substring(0, limit)}..."; } } + +extension StringOrNullExtension on String? { + bool isNullOrEmpty() { + if (this == null) { + return true; + } + if (this!.isEmpty) { + return true; + } + return false; + } +} From 37bc6dc4fa227a8c9537844b7c802a680a32cfaf Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 15:45:05 +0530 Subject: [PATCH 28/53] Create popup_menu_api_type.dart --- lib/widgets/popup_menu_api_type.dart | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 lib/widgets/popup_menu_api_type.dart diff --git a/lib/widgets/popup_menu_api_type.dart b/lib/widgets/popup_menu_api_type.dart new file mode 100644 index 00000000..22996e17 --- /dev/null +++ b/lib/widgets/popup_menu_api_type.dart @@ -0,0 +1,26 @@ +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:flutter/material.dart'; + +class APITypePopupMenu extends StatelessWidget { + const APITypePopupMenu({ + super.key, + required this.apiType, + this.onChanged, + }); + + final APIType? apiType; + final void Function(APIType?)? onChanged; + + @override + Widget build(BuildContext context) { + return ADPopupMenu( + tooltip: "Select API Type", + width: 100, + value: apiType?.label, + values: APIType.values.map((e) => (e, e.label)), + onChanged: onChanged, + isOutlined: true, + ); + } +} From 418f3991f678047329d01aa48402f092bcfce167 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 15:45:17 +0530 Subject: [PATCH 29/53] Update editor.dart --- lib/widgets/editor.dart | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/widgets/editor.dart b/lib/widgets/editor.dart index 18b391b9..4ad4c8d4 100644 --- a/lib/widgets/editor.dart +++ b/lib/widgets/editor.dart @@ -10,12 +10,14 @@ class TextFieldEditor extends StatefulWidget { this.onChanged, this.initialValue, this.readOnly = false, + this.hintText, }); final String fieldKey; final Function(String)? onChanged; final String? initialValue; final bool readOnly; + final String? hintText; @override State createState() => _TextFieldEditorState(); } @@ -25,7 +27,7 @@ class _TextFieldEditorState extends State { late final FocusNode editorFocusNode; void insertTab() { - String sp = " "; + String sp = " "; int offset = math.min( controller.selection.baseOffset, controller.selection.extentOffset); String text = controller.text.substring(0, offset) + @@ -72,14 +74,16 @@ class _TextFieldEditorState extends State { expands: true, maxLines: null, readOnly: widget.readOnly, - style: kCodeStyle, + style: kCodeStyle.copyWith( + fontSize: Theme.of(context).textTheme.bodyMedium?.fontSize, + ), textAlignVertical: TextAlignVertical.top, onChanged: widget.onChanged, onTapOutside: (PointerDownEvent event) { editorFocusNode.unfocus(); }, decoration: InputDecoration( - hintText: "Enter content (body)", + hintText: widget.hintText ?? "Enter content", hintStyle: TextStyle( color: Theme.of(context).colorScheme.outline.withOpacity( kHintOpacity, From 114b2114379ca3fcc48145c574babb0d0a3bb88f Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 15:45:36 +0530 Subject: [PATCH 30/53] cleanup --- lib/utils/envvar_utils.dart | 2 +- lib/utils/http_utils.dart | 4 ++-- lib/widgets/dropdown_api_type.dart | 24 ------------------------ 3 files changed, 3 insertions(+), 27 deletions(-) delete mode 100644 lib/widgets/dropdown_api_type.dart diff --git a/lib/utils/envvar_utils.dart b/lib/utils/envvar_utils.dart index af0195ff..620b8f4a 100644 --- a/lib/utils/envvar_utils.dart +++ b/lib/utils/envvar_utils.dart @@ -4,7 +4,7 @@ import 'package:apidash/models/models.dart'; String getEnvironmentTitle(String? name) { if (name == null || name.trim() == "") { - return "untitled"; + return kUntitled; } return name; } diff --git a/lib/utils/http_utils.dart b/lib/utils/http_utils.dart index 9fcfc677..379a3bf9 100644 --- a/lib/utils/http_utils.dart +++ b/lib/utils/http_utils.dart @@ -3,12 +3,12 @@ import '../consts.dart'; String getRequestTitleFromUrl(String? url) { if (url == null || url.trim() == "") { - return "untitled"; + return kUntitled; } if (url.contains("://")) { String rem = url.split("://")[1]; if (rem.trim() == "") { - return "untitled"; + return kUntitled; } return rem; } diff --git a/lib/widgets/dropdown_api_type.dart b/lib/widgets/dropdown_api_type.dart deleted file mode 100644 index aa9f6922..00000000 --- a/lib/widgets/dropdown_api_type.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:apidash_core/apidash_core.dart'; -import 'package:apidash_design_system/apidash_design_system.dart'; -import 'package:flutter/material.dart'; - -class DropdownButtonAPIType extends StatelessWidget { - const DropdownButtonAPIType({ - super.key, - this.apiType, - this.onChanged, - }); - - final APIType? apiType; - final void Function(APIType?)? onChanged; - - @override - Widget build(BuildContext context) { - return ADDropdownButton( - value: apiType, - values: APIType.values.map((e) => (e, e.label)), - onChanged: onChanged, - isDense: true, - ); - } -} From 89834957a2c8f2a41a06a781aee3be3316165ceb Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 15:47:19 +0530 Subject: [PATCH 31/53] Add graphQL UI --- .../request_pane/request_pane.dart | 55 ++++------------- .../request_pane/request_pane_graphql.dart | 51 ++++++++++++++++ .../request_pane/request_pane_rest.dart | 60 +++++++++++++++++++ .../home_page/editor_pane/url_card.dart | 46 +++++++++----- .../mobile/requests_page/request_tabs.dart | 21 +++++-- .../mobile/requests_page/requests_page.dart | 8 +-- 6 files changed, 174 insertions(+), 67 deletions(-) create mode 100644 lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart create mode 100644 lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane.dart index ed385bb6..9c852c71 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane.dart @@ -1,54 +1,23 @@ +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/providers/providers.dart'; -import 'package:apidash/widgets/widgets.dart'; -import 'request_headers.dart'; -import 'request_params.dart'; -import 'request_body.dart'; +import 'request_pane_graphql.dart'; +import 'request_pane_rest.dart'; class EditRequestPane extends ConsumerWidget { const EditRequestPane({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { - final selectedId = ref.watch(selectedIdStateProvider); - final codePaneVisible = ref.watch(codePaneVisibleStateProvider); - final tabIndex = ref.watch( - selectedRequestModelProvider.select((value) => value?.requestTabIndex)); - - final headerLength = ref.watch(selectedRequestModelProvider - .select((value) => value?.httpRequestModel?.headersMap.length)) ?? - 0; - final paramLength = ref.watch(selectedRequestModelProvider - .select((value) => value?.httpRequestModel?.paramsMap.length)) ?? - 0; - final hasBody = ref.watch(selectedRequestModelProvider - .select((value) => value?.httpRequestModel?.hasBody)) ?? - false; - - return RequestPane( - selectedId: selectedId, - codePaneVisible: codePaneVisible, - tabIndex: tabIndex, - onPressedCodeButton: () { - ref.read(codePaneVisibleStateProvider.notifier).state = - !codePaneVisible; - }, - onTapTabBar: (index) { - ref - .read(collectionStateNotifierProvider.notifier) - .update(selectedId!, requestTabIndex: index); - }, - showIndicators: [ - paramLength > 0, - headerLength > 0, - hasBody, - ], - children: const [ - EditRequestURLParams(), - EditRequestHeaders(), - EditRequestBody(), - ], - ); + ref.watch(selectedIdStateProvider); + final apiType = ref + .watch(selectedRequestModelProvider.select((value) => value?.apiType)); + return switch (apiType) { + APIType.rest => const EditRestRequestPane(), + APIType.graphql => const EditGraphQLRequestPane(), + _ => kSizedBoxEmpty, + }; } } diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart new file mode 100644 index 00000000..767a7b45 --- /dev/null +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart @@ -0,0 +1,51 @@ +import 'package:apidash/consts.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:apidash/providers/providers.dart'; +import 'package:apidash/widgets/widgets.dart'; +import 'request_headers.dart'; +import 'request_body.dart'; + +class EditGraphQLRequestPane extends ConsumerWidget { + const EditGraphQLRequestPane({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final selectedId = ref.watch(selectedIdStateProvider); + var tabIndex = ref.watch( + selectedRequestModelProvider.select((value) => value?.requestTabIndex)); + + final headerLength = ref.watch(selectedRequestModelProvider + .select((value) => value?.httpRequestModel?.headersMap.length)) ?? + 0; + final hasQuery = ref.watch(selectedRequestModelProvider + .select((value) => value?.httpRequestModel?.hasQuery)) ?? + false; + if (tabIndex >= 2) { + tabIndex = 0; + } + return RequestPane( + selectedId: selectedId, + codePaneVisible: false, + showViewCodeButton: false, + tabIndex: tabIndex, + onTapTabBar: (index) { + ref + .read(collectionStateNotifierProvider.notifier) + .update(requestTabIndex: index); + }, + showIndicators: [ + headerLength > 0, + hasQuery, + ], + tabLabels: const [ + kLabelHeaders, + kLabelQuery, + ], + children: const [ + EditRequestHeaders(), + EditRequestBody(), + ], + ); + } +} diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart new file mode 100644 index 00000000..e323f83b --- /dev/null +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart @@ -0,0 +1,60 @@ +import 'package:apidash/consts.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:apidash/providers/providers.dart'; +import 'package:apidash/widgets/widgets.dart'; +import 'request_headers.dart'; +import 'request_params.dart'; +import 'request_body.dart'; + +class EditRestRequestPane extends ConsumerWidget { + const EditRestRequestPane({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final selectedId = ref.watch(selectedIdStateProvider); + final codePaneVisible = ref.watch(codePaneVisibleStateProvider); + final tabIndex = ref.watch( + selectedRequestModelProvider.select((value) => value?.requestTabIndex)); + + final headerLength = ref.watch(selectedRequestModelProvider + .select((value) => value?.httpRequestModel?.headersMap.length)) ?? + 0; + final paramLength = ref.watch(selectedRequestModelProvider + .select((value) => value?.httpRequestModel?.paramsMap.length)) ?? + 0; + final hasBody = ref.watch(selectedRequestModelProvider + .select((value) => value?.httpRequestModel?.hasBody)) ?? + false; + + return RequestPane( + selectedId: selectedId, + codePaneVisible: codePaneVisible, + tabIndex: tabIndex, + onPressedCodeButton: () { + ref.read(codePaneVisibleStateProvider.notifier).state = + !codePaneVisible; + }, + onTapTabBar: (index) { + ref + .read(collectionStateNotifierProvider.notifier) + .update(requestTabIndex: index); + }, + showIndicators: [ + paramLength > 0, + headerLength > 0, + hasBody, + ], + tabLabels: const [ + kLabelURLParams, + kLabelHeaders, + kLabelBody, + ], + children: const [ + EditRequestURLParams(), + EditRequestHeaders(), + EditRequestBody(), + ], + ); + } +} diff --git a/lib/screens/home_page/editor_pane/url_card.dart b/lib/screens/home_page/editor_pane/url_card.dart index 2caac33b..829bc5c9 100644 --- a/lib/screens/home_page/editor_pane/url_card.dart +++ b/lib/screens/home_page/editor_pane/url_card.dart @@ -6,11 +6,14 @@ import 'package:apidash/providers/providers.dart'; import 'package:apidash/widgets/widgets.dart'; import '../../common_widgets/common_widgets.dart'; -class EditorPaneRequestURLCard extends StatelessWidget { +class EditorPaneRequestURLCard extends ConsumerWidget { const EditorPaneRequestURLCard({super.key}); @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { + ref.watch(selectedIdStateProvider); + final apiType = ref + .watch(selectedRequestModelProvider.select((value) => value?.apiType)); return Card( color: kColorTransparent, surfaceTintColor: kColorTransparent, @@ -27,24 +30,38 @@ class EditorPaneRequestURLCard extends StatelessWidget { horizontal: !context.isMediumWindow ? 20 : 6, ), child: context.isMediumWindow - ? const Row( + ? Row( children: [ - DropdownButtonHTTPMethod(), - kHSpacer5, - Expanded( + switch (apiType) { + APIType.rest => const DropdownButtonHTTPMethod(), + APIType.graphql => kSizedBoxEmpty, + null => kSizedBoxEmpty, + }, + switch (apiType) { + APIType.rest => kHSpacer5, + _ => kHSpacer8, + }, + const Expanded( child: URLTextField(), ), ], ) - : const Row( + : Row( children: [ - DropdownButtonHTTPMethod(), - kHSpacer20, - Expanded( + switch (apiType) { + APIType.rest => const DropdownButtonHTTPMethod(), + APIType.graphql => kSizedBoxEmpty, + null => kSizedBoxEmpty, + }, + switch (apiType) { + APIType.rest => kHSpacer20, + _ => kHSpacer8, + }, + const Expanded( child: URLTextField(), ), kHSpacer20, - SizedBox( + const SizedBox( height: 36, child: SendRequestButton(), ) @@ -67,10 +84,9 @@ class DropdownButtonHTTPMethod extends ConsumerWidget { return DropdownButtonHttpMethod( method: method, onChanged: (HTTPVerb? value) { - final selectedId = ref.read(selectedRequestModelProvider)!.id; ref .read(collectionStateNotifierProvider.notifier) - .update(selectedId, method: value); + .update(method: value); }, ); } @@ -92,9 +108,7 @@ class URLTextField extends ConsumerWidget { ?.httpRequestModel ?.url, onChanged: (value) { - ref - .read(collectionStateNotifierProvider.notifier) - .update(selectedId, url: value); + ref.read(collectionStateNotifierProvider.notifier).update(url: value); }, onFieldSubmitted: (value) { ref.read(collectionStateNotifierProvider.notifier).sendRequest(); diff --git a/lib/screens/mobile/requests_page/request_tabs.dart b/lib/screens/mobile/requests_page/request_tabs.dart index 1cfe1ef0..54404a86 100644 --- a/lib/screens/mobile/requests_page/request_tabs.dart +++ b/lib/screens/mobile/requests_page/request_tabs.dart @@ -1,21 +1,34 @@ -import 'package:apidash/screens/common_widgets/common_widgets.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; import 'package:apidash/widgets/widgets.dart'; -import 'package:apidash/consts.dart'; +import '../../../consts.dart'; +import '../../common_widgets/common_widgets.dart'; import '../../home_page/editor_pane/details_card/response_pane.dart'; import '../../home_page/editor_pane/editor_request.dart'; import '../../home_page/editor_pane/url_card.dart'; class RequestTabs extends StatelessWidget { - const RequestTabs({super.key, required this.controller}); + const RequestTabs({ + super.key, + required this.controller, + }); final TabController controller; @override Widget build(BuildContext context) { return Column( children: [ - kVSpacer5, + const Padding( + padding: kPh8, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + APITypeDropdown(), + EnvironmentDropdown(), + ], + ), + ), + kVSpacer3, const Padding( padding: kPh4, child: EditorPaneRequestURLCard(), diff --git a/lib/screens/mobile/requests_page/requests_page.dart b/lib/screens/mobile/requests_page/requests_page.dart index 77fc6ce7..ce66bc73 100644 --- a/lib/screens/mobile/requests_page/requests_page.dart +++ b/lib/screens/mobile/requests_page/requests_page.dart @@ -40,19 +40,19 @@ class _RequestResponsePageState extends ConsumerState showRenameDialog(context, "Rename Request", name, (val) { ref .read(collectionStateNotifierProvider.notifier) - .update(id!, name: val); + .update(name: val); }); } if (item == ItemMenuOption.delete) { - ref.read(collectionStateNotifierProvider.notifier).remove(id!); + ref.read(collectionStateNotifierProvider.notifier).remove(); } if (item == ItemMenuOption.duplicate) { - ref.read(collectionStateNotifierProvider.notifier).duplicate(id!); + ref.read(collectionStateNotifierProvider.notifier).duplicate(); } }, ), leftDrawerContent: const CollectionPane(), - actions: const [Padding(padding: kPh8, child: EnvironmentDropdown())], + actions: const [kVSpacer16], mainContent: id == null ? const RequestEditorDefault() : RequestTabs( From 76341d7e0cb3df59b08a6a081d3cd5af9cdbff86 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 15:48:00 +0530 Subject: [PATCH 32/53] code optimization --- lib/providers/collection_providers.dart | 47 ++++++++++++------- .../history_widgets/his_request_pane.dart | 5 ++ lib/screens/home_page/collection_pane.dart | 6 +-- .../request_pane/request_form_data.dart | 15 +++--- .../request_pane/request_headers.dart | 13 +++-- .../request_pane/request_params.dart | 13 +++-- .../details_card/response_pane.dart | 5 +- .../editor_pane/request_editor_top_bar.dart | 26 ++++------ 8 files changed, 68 insertions(+), 62 deletions(-) diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index c3f50291..d79b529e 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -1,4 +1,5 @@ import 'package:apidash_core/apidash_core.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/consts.dart'; import 'providers.dart'; @@ -112,10 +113,11 @@ class CollectionStateNotifier unsave(); } - void remove(String id) { + void remove({String? id}) { + final rId = id ?? ref.read(selectedIdStateProvider); var itemIds = ref.read(requestSequenceProvider); - int idx = itemIds.indexOf(id); - itemIds.remove(id); + int idx = itemIds.indexOf(rId!); + itemIds.remove(rId); ref.read(requestSequenceProvider.notifier).state = [...itemIds]; String? newId; @@ -130,14 +132,15 @@ class CollectionStateNotifier ref.read(selectedIdStateProvider.notifier).state = newId; var map = {...state!}; - map.remove(id); + map.remove(rId); state = map; unsave(); } - void clearResponse(String? id) { - if (id == null || state?[id] == null) return; - var currentModel = state![id]!; + void clearResponse({String? id}) { + final rId = id ?? ref.read(selectedIdStateProvider); + if (rId == null || state?[rId] == null) return; + var currentModel = state![rId]!; final newModel = currentModel.copyWith( responseStatus: null, message: null, @@ -146,17 +149,18 @@ class CollectionStateNotifier sendingTime: null, ); var map = {...state!}; - map[id] = newModel; + map[rId] = newModel; state = map; unsave(); } - void duplicate(String id) { + void duplicate({String? id}) { + final rId = id ?? ref.read(selectedIdStateProvider); final newId = getNewUuid(); var itemIds = ref.read(requestSequenceProvider); - int idx = itemIds.indexOf(id); - var currentModel = state![id]!; + int idx = itemIds.indexOf(rId!); + var currentModel = state![rId]!; final newModel = currentModel.copyWith( id: newId, name: "${currentModel.name} (copy)", @@ -204,9 +208,10 @@ class CollectionStateNotifier unsave(); } - void update( - String id, { + void update({ + String? id, HTTPVerb? method, + APIType? apiType, String? url, String? name, String? description, @@ -217,14 +222,21 @@ class CollectionStateNotifier List? isParamEnabledList, ContentType? bodyContentType, String? body, + String? query, List? formData, int? responseStatus, String? message, HttpResponseModel? httpResponseModel, }) { - var currentModel = state![id]!; + final rId = id ?? ref.read(selectedIdStateProvider); + if (rId == null) { + debugPrint("Unable to update as Request Id is null"); + return; + } + 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, @@ -240,6 +252,7 @@ class CollectionStateNotifier bodyContentType: bodyContentType ?? currentHttpRequestModel.bodyContentType, body: body ?? currentHttpRequestModel.body, + query: query ?? currentHttpRequestModel.query, formData: formData ?? currentHttpRequestModel.formData, ), responseStatus: responseStatus ?? currentModel.responseStatus, @@ -248,7 +261,7 @@ class CollectionStateNotifier ); var map = {...state!}; - map[id] = newModel; + map[rId] = newModel; state = map; unsave(); } @@ -267,8 +280,9 @@ class CollectionStateNotifier return; } + APIType apiType = requestModel!.apiType; HttpRequestModel substitutedHttpRequestModel = - getSubstitutedHttpRequestModel(requestModel!.httpRequestModel!); + getSubstitutedHttpRequestModel(requestModel.httpRequestModel!); // set current model's isWorking to true and update state var map = {...state!}; @@ -281,6 +295,7 @@ class CollectionStateNotifier bool noSSL = ref.read(settingsProvider).isSSLDisabled; (HttpResponse?, Duration?, String?)? responseRec = await request( requestId, + apiType, substitutedHttpRequestModel, defaultUriScheme: defaultUriScheme, noSSL: noSSL, diff --git a/lib/screens/history/history_widgets/his_request_pane.dart b/lib/screens/history/history_widgets/his_request_pane.dart index f24fd668..7f2cbab2 100644 --- a/lib/screens/history/history_widgets/his_request_pane.dart +++ b/lib/screens/history/history_widgets/his_request_pane.dart @@ -46,6 +46,11 @@ class HistoryRequestPane extends ConsumerWidget { headerLength > 0, hasBody, ], + tabLabels: const [ + kLabelURLParams, + kLabelHeaders, + kLabelBody, + ], children: [ RequestDataTable( rows: paramsMap, diff --git a/lib/screens/home_page/collection_pane.dart b/lib/screens/home_page/collection_pane.dart index bfac27a8..6793c59a 100644 --- a/lib/screens/home_page/collection_pane.dart +++ b/lib/screens/home_page/collection_pane.dart @@ -208,7 +208,7 @@ class RequestItem extends ConsumerWidget { value = value.trim(); ref .read(collectionStateNotifierProvider.notifier) - .update(editRequestId!, name: value); + .update(id: editRequestId!, name: value); }, onTapOutsideNameEditor: () { ref.read(selectedIdEditStateProvider.notifier).state = null; @@ -231,10 +231,10 @@ class RequestItem extends ConsumerWidget { ); } if (item == ItemMenuOption.delete) { - ref.read(collectionStateNotifierProvider.notifier).remove(id); + ref.read(collectionStateNotifierProvider.notifier).remove(id: id); } if (item == ItemMenuOption.duplicate) { - ref.read(collectionStateNotifierProvider.notifier).duplicate(id); + ref.read(collectionStateNotifierProvider.notifier).duplicate(id: id); } }, ); diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart index a25faebd..6b0a48c2 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart @@ -27,9 +27,8 @@ class _FormDataBodyState extends ConsumerState { seed = random.nextInt(kRandMax); } - void _onFieldChange(String selectedId) { + void _onFieldChange() { ref.read(collectionStateNotifierProvider.notifier).update( - selectedId, formData: formRows.sublist(0, formRows.length - 1), ); } @@ -93,7 +92,7 @@ class _FormDataBodyState extends ConsumerState { isAddingRow = true; formRows.add(kFormDataEmptyModel); } - _onFieldChange(selectedId!); + _onFieldChange(); }, colorScheme: Theme.of(context).colorScheme, ), @@ -119,7 +118,7 @@ class _FormDataBodyState extends ConsumerState { formRows.add(kFormDataEmptyModel); } setState(() {}); - _onFieldChange(selectedId!); + _onFieldChange(); }, ), ), @@ -134,7 +133,7 @@ class _FormDataBodyState extends ConsumerState { value: pickedResult.path, ); setState(() {}); - _onFieldChange(selectedId!); + _onFieldChange(); } }, initialValue: formRows[index].value, @@ -150,7 +149,7 @@ class _FormDataBodyState extends ConsumerState { isAddingRow = true; formRows.add(kFormDataEmptyModel); } - _onFieldChange(selectedId!); + _onFieldChange(); }, colorScheme: Theme.of(context).colorScheme, ), @@ -170,7 +169,7 @@ class _FormDataBodyState extends ConsumerState { } else { formRows.removeAt(index); } - _onFieldChange(selectedId!); + _onFieldChange(); }, child: Theme.of(context).brightness == Brightness.dark ? kIconRemoveDark @@ -216,7 +215,7 @@ class _FormDataBodyState extends ConsumerState { child: ElevatedButton.icon( onPressed: () { formRows.add(kFormDataEmptyModel); - _onFieldChange(selectedId!); + _onFieldChange(); }, icon: const Icon(Icons.add), label: const Text( diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_headers.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_headers.dart index 3efd41bb..ecb3f6da 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_headers.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_headers.dart @@ -29,9 +29,8 @@ class EditRequestHeadersState extends ConsumerState { seed = random.nextInt(kRandMax); } - void _onFieldChange(String selectedId) { + void _onFieldChange() { ref.read(collectionStateNotifierProvider.notifier).update( - selectedId, headers: headerRows.sublist(0, headerRows.length - 1), isHeaderEnabledList: isRowEnabledList.sublist(0, headerRows.length - 1), @@ -99,7 +98,7 @@ class EditRequestHeadersState extends ConsumerState { setState(() { isRowEnabledList[index] = value!; }); - _onFieldChange(selectedId!); + _onFieldChange(); }, colorScheme: Theme.of(context).colorScheme, ), @@ -117,7 +116,7 @@ class EditRequestHeadersState extends ConsumerState { headerRows.add(kNameValueEmptyModel); isRowEnabledList.add(false); } - _onFieldChange(selectedId!); + _onFieldChange(); }, colorScheme: Theme.of(context).colorScheme, ), @@ -143,7 +142,7 @@ class EditRequestHeadersState extends ConsumerState { headerRows.add(kNameValueEmptyModel); isRowEnabledList.add(false); } - _onFieldChange(selectedId!); + _onFieldChange(); }, colorScheme: Theme.of(context).colorScheme, ), @@ -165,7 +164,7 @@ class EditRequestHeadersState extends ConsumerState { headerRows.removeAt(index); isRowEnabledList.removeAt(index); } - _onFieldChange(selectedId!); + _onFieldChange(); }, child: Theme.of(context).brightness == Brightness.dark ? kIconRemoveDark @@ -212,7 +211,7 @@ class EditRequestHeadersState extends ConsumerState { onPressed: () { headerRows.add(kNameValueEmptyModel); isRowEnabledList.add(false); - _onFieldChange(selectedId!); + _onFieldChange(); }, icon: const Icon(Icons.add), label: const Text( diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_params.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_params.dart index ccd1814a..a583b183 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_params.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_params.dart @@ -29,9 +29,8 @@ class EditRequestURLParamsState extends ConsumerState { seed = random.nextInt(kRandMax); } - void _onFieldChange(String selectedId) { + void _onFieldChange() { ref.read(collectionStateNotifierProvider.notifier).update( - selectedId, params: paramRows.sublist(0, paramRows.length - 1), isParamEnabledList: isRowEnabledList.sublist(0, paramRows.length - 1), ); @@ -98,7 +97,7 @@ class EditRequestURLParamsState extends ConsumerState { setState(() { isRowEnabledList[index] = value!; }); - _onFieldChange(selectedId!); + _onFieldChange(); }, colorScheme: Theme.of(context).colorScheme, ), @@ -116,7 +115,7 @@ class EditRequestURLParamsState extends ConsumerState { paramRows.add(kNameValueEmptyModel); isRowEnabledList.add(false); } - _onFieldChange(selectedId!); + _onFieldChange(); }, colorScheme: Theme.of(context).colorScheme, ), @@ -142,7 +141,7 @@ class EditRequestURLParamsState extends ConsumerState { paramRows.add(kNameValueEmptyModel); isRowEnabledList.add(false); } - _onFieldChange(selectedId!); + _onFieldChange(); }, colorScheme: Theme.of(context).colorScheme, ), @@ -164,7 +163,7 @@ class EditRequestURLParamsState extends ConsumerState { paramRows.removeAt(index); isRowEnabledList.removeAt(index); } - _onFieldChange(selectedId!); + _onFieldChange(); }, child: Theme.of(context).brightness == Brightness.dark ? kIconRemoveDark @@ -212,7 +211,7 @@ class EditRequestURLParamsState extends ConsumerState { onPressed: () { paramRows.add(kNameValueEmptyModel); isRowEnabledList.add(false); - _onFieldChange(selectedId!); + _onFieldChange(); }, icon: const Icon(Icons.add), label: const Text( diff --git a/lib/screens/home_page/editor_pane/details_card/response_pane.dart b/lib/screens/home_page/editor_pane/details_card/response_pane.dart index 322da874..50d5531a 100644 --- a/lib/screens/home_page/editor_pane/details_card/response_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/response_pane.dart @@ -61,10 +61,7 @@ class ResponseDetails extends ConsumerWidget { message: message, time: responseModel?.time, onClearResponse: () { - final selectedRequest = ref.read(selectedRequestModelProvider); - ref - .read(collectionStateNotifierProvider.notifier) - .clearResponse(selectedRequest?.id); + ref.read(collectionStateNotifierProvider.notifier).clearResponse(); }, ), const Expanded( diff --git a/lib/screens/home_page/editor_pane/request_editor_top_bar.dart b/lib/screens/home_page/editor_pane/request_editor_top_bar.dart index 9be8990c..022b50ff 100644 --- a/lib/screens/home_page/editor_pane/request_editor_top_bar.dart +++ b/lib/screens/home_page/editor_pane/request_editor_top_bar.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/providers/providers.dart'; import 'package:apidash/widgets/widgets.dart'; +import '../../../consts.dart'; import '../../common_widgets/common_widgets.dart'; class RequestEditorTopBar extends ConsumerWidget { @@ -11,26 +12,18 @@ class RequestEditorTopBar extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final id = ref.watch(selectedIdStateProvider); + ref.watch(selectedIdStateProvider); final name = ref.watch(selectedRequestModelProvider.select((value) => value?.name)); return Padding( - padding: const EdgeInsets.only( - left: 12.0, - top: 4.0, - right: 4.0, - bottom: 4.0, - ), + padding: kP4, child: Row( children: [ - DropdownButtonAPIType( - apiType: APIType.rest, - onChanged: (apiType) {}, - ), + const APITypeDropdown(), kHSpacer10, Expanded( child: Text( - name ?? "", + name.isNullOrEmpty() ? kUntitled : name!, style: Theme.of(context).textTheme.bodyMedium, overflow: TextOverflow.ellipsis, maxLines: 1, @@ -42,14 +35,13 @@ class RequestEditorTopBar extends ConsumerWidget { showRenameDialog(context, "Rename Request", name, (val) { ref .read(collectionStateNotifierProvider.notifier) - .update(id!, name: val); + .update(name: val); }); }, - onDuplicatePressed: () => ref - .read(collectionStateNotifierProvider.notifier) - .duplicate(id!), + onDuplicatePressed: () => + ref.read(collectionStateNotifierProvider.notifier).duplicate(), onDeletePressed: () => - ref.read(collectionStateNotifierProvider.notifier).remove(id!), + ref.read(collectionStateNotifierProvider.notifier).remove(), ), kHSpacer10, const EnvironmentDropdown(), From ca31d113881fb65da608b580fcabbc7406814746 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 15:48:21 +0530 Subject: [PATCH 33/53] Add API selector --- .../common_widgets/api_type_dropdown.dart | 23 +++++++++++++++++++ .../common_widgets/common_widgets.dart | 1 + 2 files changed, 24 insertions(+) create mode 100644 lib/screens/common_widgets/api_type_dropdown.dart diff --git a/lib/screens/common_widgets/api_type_dropdown.dart b/lib/screens/common_widgets/api_type_dropdown.dart new file mode 100644 index 00000000..c35645d6 --- /dev/null +++ b/lib/screens/common_widgets/api_type_dropdown.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:apidash/providers/providers.dart'; +import 'package:apidash/widgets/widgets.dart'; + +class APITypeDropdown extends ConsumerWidget { + const APITypeDropdown({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + ref.watch(selectedIdStateProvider); + final apiType = ref + .watch(selectedRequestModelProvider.select((value) => value?.apiType)); + return APITypePopupMenu( + apiType: apiType, + onChanged: (type) { + ref + .read(collectionStateNotifierProvider.notifier) + .update(apiType: type); + }, + ); + } +} diff --git a/lib/screens/common_widgets/common_widgets.dart b/lib/screens/common_widgets/common_widgets.dart index ee150dd8..d6932407 100644 --- a/lib/screens/common_widgets/common_widgets.dart +++ b/lib/screens/common_widgets/common_widgets.dart @@ -1,3 +1,4 @@ +export 'api_type_dropdown.dart'; export 'button_navbar.dart'; export 'code_pane.dart'; export 'editor_title.dart'; From 2ebeded784d575d9e3926acb9b432cbc4b90c845 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 15:48:35 +0530 Subject: [PATCH 34/53] Update widget to write Query --- .../request_pane/request_body.dart | 115 +++++++++++------- 1 file changed, 70 insertions(+), 45 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart index 31c52de4..3ac839b6 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart @@ -18,6 +18,8 @@ class EditRequestBody extends ConsumerWidget { .getRequestModel(selectedId!); final contentType = ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.bodyContentType)); + final apiType = ref + .watch(selectedRequestModelProvider.select((value) => value?.apiType)); // TODO: #178 GET->POST Currently switches to POST everytime user edits body even if the user intentionally chooses GET // final sm = ScaffoldMessenger.of(context); @@ -36,57 +38,80 @@ class EditRequestBody extends ConsumerWidget { return Column( children: [ - const SizedBox( - height: kHeaderHeight, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "Select Content Type:", - ), - DropdownButtonBodyContentType(), - ], - ), - ), - Expanded( - child: switch (contentType) { - ContentType.formdata => const Padding( - padding: kPh4, - child: FormDataWidget( - // TODO: See changeToPostMethod above - // changeMethodToPost: changeToPostMethod, - )), - // TODO: Fix JsonTextFieldEditor & plug it here - ContentType.json => Padding( + (apiType == APIType.rest) + ? const SizedBox( + height: kHeaderHeight, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "Select Content Type:", + ), + DropdownButtonBodyContentType(), + ], + ), + ) + : kSizedBoxEmpty, + switch (apiType) { + APIType.rest => Expanded( + child: switch (contentType) { + ContentType.formdata => const Padding( + padding: kPh4, + child: FormDataWidget( + // TODO: See changeToPostMethod above + // changeMethodToPost: changeToPostMethod, + )), + // TODO: Fix JsonTextFieldEditor & plug it here + ContentType.json => Padding( + padding: kPt5o10, + child: TextFieldEditor( + key: Key("$selectedId-json-body"), + fieldKey: "$selectedId-json-body-editor", + initialValue: requestModel?.httpRequestModel?.body, + onChanged: (String value) { + // changeToPostMethod(); + ref + .read(collectionStateNotifierProvider.notifier) + .update(body: value); + }, + hintText: "Enter JSON", + ), + ), + _ => Padding( + padding: kPt5o10, + child: TextFieldEditor( + key: Key("$selectedId-body"), + fieldKey: "$selectedId-body-editor", + initialValue: requestModel?.httpRequestModel?.body, + onChanged: (String value) { + // changeToPostMethod(); + ref + .read(collectionStateNotifierProvider.notifier) + .update(body: value); + }, + hintText: "Enter text", + ), + ), + }, + ), + APIType.graphql => Expanded( + child: Padding( padding: kPt5o10, child: TextFieldEditor( - key: Key("$selectedId-json-body"), - fieldKey: "$selectedId-json-body-editor", - initialValue: requestModel?.httpRequestModel?.body, + key: Key("$selectedId-query"), + fieldKey: "$selectedId-query-editor", + initialValue: requestModel?.httpRequestModel?.query, onChanged: (String value) { - // changeToPostMethod(); ref .read(collectionStateNotifierProvider.notifier) - .update(selectedId, body: value); + .update(query: value); }, + hintText: "Enter Query", ), ), - _ => Padding( - padding: kPt5o10, - child: TextFieldEditor( - key: Key("$selectedId-body"), - fieldKey: "$selectedId-body-editor", - initialValue: requestModel?.httpRequestModel?.body, - onChanged: (String value) { - // changeToPostMethod(); - ref - .read(collectionStateNotifierProvider.notifier) - .update(selectedId, body: value); - }, - ), - ), - }, - ) + ), + _ => kSizedBoxEmpty, + } ], ); } @@ -99,7 +124,7 @@ class DropdownButtonBodyContentType extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final selectedId = ref.watch(selectedIdStateProvider); + ref.watch(selectedIdStateProvider); final requestBodyContentType = ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.bodyContentType)); return DropdownButtonContentType( @@ -107,7 +132,7 @@ class DropdownButtonBodyContentType extends ConsumerWidget { onChanged: (ContentType? value) { ref .read(collectionStateNotifierProvider.notifier) - .update(selectedId!, bodyContentType: value); + .update(bodyContentType: value); }, ); } From 18f4687d30cbc379781bda950dffe81f76894c2b Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 16:37:57 +0530 Subject: [PATCH 35/53] Update HistoryMetaModel --- lib/models/history_meta_model.dart | 1 + lib/models/history_meta_model.freezed.dart | 26 +++++++++++++++++++--- lib/models/history_meta_model.g.dart | 7 ++++++ lib/providers/collection_providers.dart | 1 + lib/screens/history/history_pane.dart | 1 + lib/screens/home_page/collection_pane.dart | 1 + 6 files changed, 34 insertions(+), 3 deletions(-) diff --git a/lib/models/history_meta_model.dart b/lib/models/history_meta_model.dart index 0e2bdb43..c0226086 100644 --- a/lib/models/history_meta_model.dart +++ b/lib/models/history_meta_model.dart @@ -9,6 +9,7 @@ class HistoryMetaModel with _$HistoryMetaModel { const factory HistoryMetaModel({ required String historyId, required String requestId, + required APIType apiType, @Default("") String name, required String url, required HTTPVerb method, diff --git a/lib/models/history_meta_model.freezed.dart b/lib/models/history_meta_model.freezed.dart index 38931547..97a068b2 100644 --- a/lib/models/history_meta_model.freezed.dart +++ b/lib/models/history_meta_model.freezed.dart @@ -22,6 +22,7 @@ HistoryMetaModel _$HistoryMetaModelFromJson(Map json) { mixin _$HistoryMetaModel { String get historyId => throw _privateConstructorUsedError; String get requestId => throw _privateConstructorUsedError; + APIType get apiType => throw _privateConstructorUsedError; String get name => throw _privateConstructorUsedError; String get url => throw _privateConstructorUsedError; HTTPVerb get method => throw _privateConstructorUsedError; @@ -47,6 +48,7 @@ abstract class $HistoryMetaModelCopyWith<$Res> { $Res call( {String historyId, String requestId, + APIType apiType, String name, String url, HTTPVerb method, @@ -71,6 +73,7 @@ class _$HistoryMetaModelCopyWithImpl<$Res, $Val extends HistoryMetaModel> $Res call({ Object? historyId = null, Object? requestId = null, + Object? apiType = null, Object? name = null, Object? url = null, Object? method = null, @@ -86,6 +89,10 @@ class _$HistoryMetaModelCopyWithImpl<$Res, $Val extends HistoryMetaModel> ? _value.requestId : requestId // ignore: cast_nullable_to_non_nullable as String, + apiType: null == apiType + ? _value.apiType + : apiType // ignore: cast_nullable_to_non_nullable + as APIType, name: null == name ? _value.name : name // ignore: cast_nullable_to_non_nullable @@ -121,6 +128,7 @@ abstract class _$$HistoryMetaModelImplCopyWith<$Res> $Res call( {String historyId, String requestId, + APIType apiType, String name, String url, HTTPVerb method, @@ -143,6 +151,7 @@ class __$$HistoryMetaModelImplCopyWithImpl<$Res> $Res call({ Object? historyId = null, Object? requestId = null, + Object? apiType = null, Object? name = null, Object? url = null, Object? method = null, @@ -158,6 +167,10 @@ class __$$HistoryMetaModelImplCopyWithImpl<$Res> ? _value.requestId : requestId // ignore: cast_nullable_to_non_nullable as String, + apiType: null == apiType + ? _value.apiType + : apiType // ignore: cast_nullable_to_non_nullable + as APIType, name: null == name ? _value.name : name // ignore: cast_nullable_to_non_nullable @@ -188,6 +201,7 @@ class _$HistoryMetaModelImpl implements _HistoryMetaModel { const _$HistoryMetaModelImpl( {required this.historyId, required this.requestId, + required this.apiType, this.name = "", required this.url, required this.method, @@ -202,6 +216,8 @@ class _$HistoryMetaModelImpl implements _HistoryMetaModel { @override final String requestId; @override + final APIType apiType; + @override @JsonKey() final String name; @override @@ -215,7 +231,7 @@ class _$HistoryMetaModelImpl implements _HistoryMetaModel { @override String toString() { - return 'HistoryMetaModel(historyId: $historyId, requestId: $requestId, name: $name, url: $url, method: $method, responseStatus: $responseStatus, timeStamp: $timeStamp)'; + return 'HistoryMetaModel(historyId: $historyId, requestId: $requestId, apiType: $apiType, name: $name, url: $url, method: $method, responseStatus: $responseStatus, timeStamp: $timeStamp)'; } @override @@ -227,6 +243,7 @@ class _$HistoryMetaModelImpl implements _HistoryMetaModel { other.historyId == historyId) && (identical(other.requestId, requestId) || other.requestId == requestId) && + (identical(other.apiType, apiType) || other.apiType == apiType) && (identical(other.name, name) || other.name == name) && (identical(other.url, url) || other.url == url) && (identical(other.method, method) || other.method == method) && @@ -238,8 +255,8 @@ class _$HistoryMetaModelImpl implements _HistoryMetaModel { @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => Object.hash(runtimeType, historyId, requestId, name, url, - method, responseStatus, timeStamp); + int get hashCode => Object.hash(runtimeType, historyId, requestId, apiType, + name, url, method, responseStatus, timeStamp); /// Create a copy of HistoryMetaModel /// with the given fields replaced by the non-null parameter values. @@ -262,6 +279,7 @@ abstract class _HistoryMetaModel implements HistoryMetaModel { const factory _HistoryMetaModel( {required final String historyId, required final String requestId, + required final APIType apiType, final String name, required final String url, required final HTTPVerb method, @@ -276,6 +294,8 @@ abstract class _HistoryMetaModel implements HistoryMetaModel { @override String get requestId; @override + APIType get apiType; + @override String get name; @override String get url; diff --git a/lib/models/history_meta_model.g.dart b/lib/models/history_meta_model.g.dart index 3d8af833..a2b2b7b1 100644 --- a/lib/models/history_meta_model.g.dart +++ b/lib/models/history_meta_model.g.dart @@ -11,6 +11,7 @@ _$HistoryMetaModelImpl _$$HistoryMetaModelImplFromJson( _$HistoryMetaModelImpl( historyId: json['historyId'] as String, requestId: json['requestId'] as String, + apiType: $enumDecode(_$APITypeEnumMap, json['apiType']), name: json['name'] as String? ?? "", url: json['url'] as String, method: $enumDecode(_$HTTPVerbEnumMap, json['method']), @@ -23,6 +24,7 @@ Map _$$HistoryMetaModelImplToJson( { 'historyId': instance.historyId, 'requestId': instance.requestId, + 'apiType': _$APITypeEnumMap[instance.apiType]!, 'name': instance.name, 'url': instance.url, 'method': _$HTTPVerbEnumMap[instance.method]!, @@ -30,6 +32,11 @@ Map _$$HistoryMetaModelImplToJson( 'timeStamp': instance.timeStamp.toIso8601String(), }; +const _$APITypeEnumMap = { + APIType.rest: 'rest', + APIType.graphql: 'graphql', +}; + const _$HTTPVerbEnumMap = { HTTPVerb.get: 'get', HTTPVerb.head: 'head', diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index d79b529e..2fb83077 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -326,6 +326,7 @@ class CollectionStateNotifier metaData: HistoryMetaModel( historyId: newHistoryId, requestId: requestId, + apiType: requestModel.apiType, name: requestModel.name, url: substitutedHttpRequestModel.url, method: substitutedHttpRequestModel.method, diff --git a/lib/screens/history/history_pane.dart b/lib/screens/history/history_pane.dart index 95cbb559..77e4b36e 100644 --- a/lib/screens/history/history_pane.dart +++ b/lib/screens/history/history_pane.dart @@ -142,6 +142,7 @@ class _HistoryExpansionTileState extends ConsumerState padding: kPv2 + kPh4, child: SidebarHistoryCard( id: item.first.historyId, + apiType: item.first.apiType, models: item, method: item.first.method, isSelected: selectedGroupId == getHistoryRequestKey(item.first), diff --git a/lib/screens/home_page/collection_pane.dart b/lib/screens/home_page/collection_pane.dart index 6793c59a..4573b7ea 100644 --- a/lib/screens/home_page/collection_pane.dart +++ b/lib/screens/home_page/collection_pane.dart @@ -186,6 +186,7 @@ class RequestItem extends ConsumerWidget { return SidebarRequestCard( id: id, + apiType: requestModel.apiType, method: requestModel.httpRequestModel!.method, name: requestModel.name, url: requestModel.httpRequestModel?.url, From 2c2db4ff219b514db68b14b5d64099ea847123e5 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 16:38:27 +0530 Subject: [PATCH 36/53] Hint constants --- lib/consts.dart | 4 ++++ .../editor_pane/details_card/request_pane/request_body.dart | 6 +++--- lib/widgets/editor.dart | 3 ++- lib/widgets/editor_json.dart | 3 ++- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/consts.dart b/lib/consts.dart index 59680326..d03980f9 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -454,6 +454,10 @@ const kLabelAddHeader = "Add Header"; const kLabelAddVariable = "Add Variable"; const kLabelSelectFile = "Select File"; const kLabelAddFormField = "Add Form Field"; +const kHintContent = "Enter content"; +const kHintText = "Enter text"; +const kHintJson = "Enter JSON"; +const kHintQuery = "Enter Query"; // Response Pane const kLabelNotSent = "Not Sent"; const kLabelResponse = "Response"; diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart index 3ac839b6..26686e67 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart @@ -74,7 +74,7 @@ class EditRequestBody extends ConsumerWidget { .read(collectionStateNotifierProvider.notifier) .update(body: value); }, - hintText: "Enter JSON", + hintText: kHintJson, ), ), _ => Padding( @@ -89,7 +89,7 @@ class EditRequestBody extends ConsumerWidget { .read(collectionStateNotifierProvider.notifier) .update(body: value); }, - hintText: "Enter text", + hintText: kHintText, ), ), }, @@ -106,7 +106,7 @@ class EditRequestBody extends ConsumerWidget { .read(collectionStateNotifierProvider.notifier) .update(query: value); }, - hintText: "Enter Query", + hintText: kHintQuery, ), ), ), diff --git a/lib/widgets/editor.dart b/lib/widgets/editor.dart index 4ad4c8d4..516406b4 100644 --- a/lib/widgets/editor.dart +++ b/lib/widgets/editor.dart @@ -1,4 +1,5 @@ import 'dart:math' as math; +import 'package:apidash/consts.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -83,7 +84,7 @@ class _TextFieldEditorState extends State { editorFocusNode.unfocus(); }, decoration: InputDecoration( - hintText: widget.hintText ?? "Enter content", + hintText: widget.hintText ?? kHintContent, hintStyle: TextStyle( color: Theme.of(context).colorScheme.outline.withOpacity( kHintOpacity, diff --git a/lib/widgets/editor_json.dart b/lib/widgets/editor_json.dart index 1c1af0d1..3c0c2abf 100644 --- a/lib/widgets/editor_json.dart +++ b/lib/widgets/editor_json.dart @@ -1,4 +1,5 @@ import 'dart:math' as math; +import 'package:apidash/consts.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -93,7 +94,7 @@ class _JsonTextFieldEditorState extends State { widget.onChanged?.call(value); }, decoration: InputDecoration( - hintText: "Enter content (body)", + hintText: kHintJson, hintStyle: TextStyle( color: Theme.of(context).colorScheme.outline.withOpacity( kHintOpacity, From 105ef7cf1de0b735b3eb90dbe3994fa64238e0c0 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 16:39:22 +0530 Subject: [PATCH 37/53] MethodBox => SidebarRequestCardTextBox --- lib/widgets/card_sidebar_history.dart | 9 +++++++-- lib/widgets/card_sidebar_request.dart | 9 +++++++-- lib/widgets/texts.dart | 22 +++++++++++++++------- test/widgets/texts_test.dart | 12 ++++++++++-- 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/lib/widgets/card_sidebar_history.dart b/lib/widgets/card_sidebar_history.dart index 49378125..8ecd1f1e 100644 --- a/lib/widgets/card_sidebar_history.dart +++ b/lib/widgets/card_sidebar_history.dart @@ -3,12 +3,13 @@ import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; import 'package:apidash/models/models.dart'; import 'package:apidash/utils/utils.dart'; -import 'texts.dart' show MethodBox; +import 'texts.dart'; class SidebarHistoryCard extends StatelessWidget { const SidebarHistoryCard({ super.key, required this.id, + required this.apiType, required this.models, required this.method, this.isSelected = false, @@ -17,6 +18,7 @@ class SidebarHistoryCard extends StatelessWidget { }); final String id; + final APIType apiType; final List models; final HTTPVerb method; final bool isSelected; @@ -63,7 +65,10 @@ class SidebarHistoryCard extends StatelessWidget { height: 20, child: Row( children: [ - MethodBox(method: method), + SidebarRequestCardTextBox( + apiType: apiType, + method: method, + ), kHSpacer4, Expanded( child: Text( diff --git a/lib/widgets/card_sidebar_request.dart b/lib/widgets/card_sidebar_request.dart index 23455fbd..e7826274 100644 --- a/lib/widgets/card_sidebar_request.dart +++ b/lib/widgets/card_sidebar_request.dart @@ -4,12 +4,13 @@ import 'package:flutter/material.dart'; import 'package:apidash/consts.dart'; import 'package:apidash/utils/utils.dart'; import 'menu_item_card.dart'; -import 'texts.dart' show MethodBox; +import 'texts.dart'; class SidebarRequestCard extends StatelessWidget { const SidebarRequestCard({ super.key, required this.id, + required this.apiType, required this.method, this.name, this.url, @@ -26,6 +27,7 @@ class SidebarRequestCard extends StatelessWidget { }); final String id; + final APIType apiType; final String? name; final String? url; final HTTPVerb method; @@ -88,7 +90,10 @@ class SidebarRequestCard extends StatelessWidget { height: 20, child: Row( children: [ - MethodBox(method: method), + SidebarRequestCardTextBox( + apiType: apiType, + method: method, + ), kHSpacer4, Expanded( child: inEditMode diff --git a/lib/widgets/texts.dart b/lib/widgets/texts.dart index dad5e0ce..cd43714e 100644 --- a/lib/widgets/texts.dart +++ b/lib/widgets/texts.dart @@ -3,11 +3,13 @@ import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; import 'package:apidash/utils/utils.dart'; -class MethodBox extends StatelessWidget { - const MethodBox({ +class SidebarRequestCardTextBox extends StatelessWidget { + const SidebarRequestCardTextBox({ super.key, + required this.apiType, required this.method, }); + final APIType apiType; final HTTPVerb method; @override @@ -15,15 +17,21 @@ class MethodBox extends StatelessWidget { return SizedBox( width: 24, child: Text( - method.abbr, + switch (apiType) { + APIType.rest => method.abbr, + APIType.graphql => apiType.abbr, + }, textAlign: TextAlign.center, style: TextStyle( fontSize: 8, fontWeight: FontWeight.bold, - color: getHTTPMethodColor( - method, - brightness: Theme.of(context).brightness, - ), + color: switch (apiType) { + APIType.rest => getHTTPMethodColor( + method, + brightness: Theme.of(context).brightness, + ), + APIType.graphql => kColorGQL, + }, ), ), ); diff --git a/test/widgets/texts_test.dart b/test/widgets/texts_test.dart index 303a6d0f..79107fe1 100644 --- a/test/widgets/texts_test.dart +++ b/test/widgets/texts_test.dart @@ -8,12 +8,16 @@ import 'package:apidash/widgets/texts.dart'; void main() { testWidgets('Testing when method is GET', (tester) async { var methodGet = HTTPVerb.get; + var apiType = APIType.rest; await tester.pumpWidget( MaterialApp( title: 'Texts', theme: ThemeData(brightness: Brightness.light), home: Scaffold( - body: MethodBox(method: methodGet), + body: SidebarRequestCardTextBox( + apiType: apiType, + method: methodGet, + ), ), ), ); @@ -28,12 +32,16 @@ void main() { testWidgets('Testing when method is DELETE', (tester) async { var methodDel = HTTPVerb.delete; + var apiType = APIType.rest; await tester.pumpWidget( MaterialApp( title: 'Texts', theme: ThemeData(brightness: Brightness.dark), home: Scaffold( - body: MethodBox(method: methodDel), + body: SidebarRequestCardTextBox( + apiType: apiType, + method: methodDel, + ), ), ), ); From f76d520f577507c0c4fd1b6b52ccb3771f238fef Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 16:39:33 +0530 Subject: [PATCH 38/53] Update tests --- test/models/history_models.dart | 4 ++++ test/models/http_request_models.dart | 2 ++ test/widgets/card_history_request_test.dart | 1 + test/widgets/card_sidebar_history_test.dart | 3 +++ test/widgets/card_sidebar_request_test.dart | 2 ++ test/widgets/editor_test.dart | 9 +++++---- 6 files changed, 17 insertions(+), 4 deletions(-) diff --git a/test/models/history_models.dart b/test/models/history_models.dart index 5deeb655..e33c2f99 100644 --- a/test/models/history_models.dart +++ b/test/models/history_models.dart @@ -9,6 +9,7 @@ import 'http_response_models.dart'; final historyMetaModel1 = HistoryMetaModel( historyId: 'historyId1', requestId: 'requestId1', + apiType: APIType.rest, url: 'https://api.apidash.dev/humanize/social', method: HTTPVerb.get, timeStamp: DateTime(2024, 1, 1), @@ -26,6 +27,7 @@ final historyRequestModel1 = HistoryRequestModel( final historyMetaModel2 = HistoryMetaModel( historyId: 'historyId2', requestId: 'requestId2', + apiType: APIType.rest, url: 'https://api.apidash.dev/case/lower', method: HTTPVerb.post, timeStamp: DateTime(2024, 1, 1), @@ -43,6 +45,7 @@ final historyRequestModel2 = HistoryRequestModel( final Map historyMetaModelJson1 = { "historyId": "historyId1", "requestId": "requestId1", + "apiType": "rest", "name": "", "url": "https://api.apidash.dev/humanize/social", "method": "get", @@ -60,6 +63,7 @@ final Map historyRequestModelJson1 = { final Map historyMetaModelJson2 = { "historyId": "historyId2", "requestId": "requestId2", + "apiType": "rest", "name": "", "url": "https://api.apidash.dev/case/lower", "method": "post", diff --git a/test/models/http_request_models.dart b/test/models/http_request_models.dart index f50dd2df..e3448c30 100644 --- a/test/models/http_request_models.dart +++ b/test/models/http_request_models.dart @@ -388,6 +388,7 @@ const httpRequestModelGet4Json = { "isParamEnabledList": null, "bodyContentType": "json", "body": null, + "query": null, "formData": null }; @@ -408,6 +409,7 @@ const httpRequestModelPost10Json = { "body": '''{ "text": "I LOVE Flutter" }''', + "query": null, 'formData': [ {'name': 'token', 'value': 'xyz', 'type': 'text'}, {'name': 'imfile', 'value': '/Documents/up/1.png', 'type': 'file'} diff --git a/test/widgets/card_history_request_test.dart b/test/widgets/card_history_request_test.dart index 7c811a88..ba3a074b 100644 --- a/test/widgets/card_history_request_test.dart +++ b/test/widgets/card_history_request_test.dart @@ -13,6 +13,7 @@ void main() { final mockModel = HistoryMetaModel( historyId: 'historyId', requestId: 'requestId', + apiType: APIType.rest, url: 'https://api.apidash.dev', method: HTTPVerb.get, timeStamp: DateTime.now(), diff --git a/test/widgets/card_sidebar_history_test.dart b/test/widgets/card_sidebar_history_test.dart index a4d3c0a1..e3022dd3 100644 --- a/test/widgets/card_sidebar_history_test.dart +++ b/test/widgets/card_sidebar_history_test.dart @@ -11,6 +11,7 @@ void main() { HistoryMetaModel( historyId: 'historyId', requestId: 'requestId', + apiType: APIType.rest, url: 'https://api.apidash.dev', method: HTTPVerb.get, timeStamp: DateTime.now(), @@ -30,6 +31,7 @@ void main() { SidebarHistoryCard( id: '1', models: sampleModels, + apiType: APIType.rest, method: HTTPVerb.get, onTap: () { changedValue = 'Tapped'; @@ -68,6 +70,7 @@ void main() { children: [ SidebarHistoryCard( id: '1', + apiType: APIType.rest, models: sampleModels, method: HTTPVerb.get, onTap: () { diff --git a/test/widgets/card_sidebar_request_test.dart b/test/widgets/card_sidebar_request_test.dart index 2d1f2be9..d31b9061 100644 --- a/test/widgets/card_sidebar_request_test.dart +++ b/test/widgets/card_sidebar_request_test.dart @@ -16,6 +16,7 @@ void main() { children: [ SidebarRequestCard( id: '23', + apiType: APIType.rest, selectedId: '2', url: 'https://api.apidash.dev', method: HTTPVerb.get, @@ -61,6 +62,7 @@ void main() { children: [ SidebarRequestCard( id: '2', + apiType: APIType.rest, selectedId: '2', editRequestId: '2', url: 'https://api.apidash.dev', diff --git a/test/widgets/editor_test.dart b/test/widgets/editor_test.dart index 238b432c..12b4991b 100644 --- a/test/widgets/editor_test.dart +++ b/test/widgets/editor_test.dart @@ -1,3 +1,4 @@ +import 'package:apidash/consts.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -28,7 +29,7 @@ void main() { expect(find.byType(TextFormField), findsOneWidget); expect(find.byKey(const Key("2")), findsOneWidget); - expect(find.text('Enter content (body)'), findsOneWidget); + expect(find.text(kHintContent), findsOneWidget); var txtForm = find.byKey(const Key("2")); await tester.enterText(txtForm, 'entering 123 for testing content body'); await tester.pump(); @@ -40,7 +41,7 @@ void main() { await tester.pump(); await tester.pumpAndSettle(); - expect(changedValue, 'entering 123 for testing content body '); + expect(changedValue, 'entering 123 for testing content body '); }); testWidgets('Testing Editor Dark theme', (tester) async { dynamic changedValue; @@ -66,7 +67,7 @@ void main() { expect(find.text('initial'), findsOneWidget); expect(find.byType(TextFormField), findsOneWidget); expect(find.byKey(const Key("2")), findsOneWidget); - expect(find.text('Enter content (body)'), findsOneWidget); + expect(find.text(kHintContent), findsOneWidget); var txtForm = find.byKey(const Key("2")); await tester.enterText(txtForm, 'entering 123 for testing content body'); await tester.pump(); @@ -78,6 +79,6 @@ void main() { await tester.pump(); await tester.pumpAndSettle(); - expect(changedValue, 'entering 123 for testing content body '); + expect(changedValue, 'entering 123 for testing content body '); }); } From 67146ba65f0953b45999247abb1845cb1b7b0642 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 16:39:38 +0530 Subject: [PATCH 39/53] Update colors.dart --- packages/apidash_design_system/lib/tokens/colors.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/apidash_design_system/lib/tokens/colors.dart b/packages/apidash_design_system/lib/tokens/colors.dart index 287b70b6..7d873fcd 100644 --- a/packages/apidash_design_system/lib/tokens/colors.dart +++ b/packages/apidash_design_system/lib/tokens/colors.dart @@ -24,6 +24,8 @@ final kColorHttpMethodPut = Colors.amber.shade900; final kColorHttpMethodPatch = kColorHttpMethodPut; final kColorHttpMethodDelete = Colors.red.shade800; +final kColorGQL = Colors.pink.shade600; + const kHintOpacity = 0.6; const kForegroundOpacity = 0.05; const kOverlayBackgroundOpacity = 0.5; From 06ad52b9334e35d6c906130ea0eb27a3c45c8b08 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 16:39:40 +0530 Subject: [PATCH 40/53] Update consts.dart --- packages/apidash_core/lib/consts.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/apidash_core/lib/consts.dart b/packages/apidash_core/lib/consts.dart index 1ef6b0dd..c3ac388c 100644 --- a/packages/apidash_core/lib/consts.dart +++ b/packages/apidash_core/lib/consts.dart @@ -1,11 +1,12 @@ import 'dart:convert'; enum APIType { - rest("HTTP"), - graphql("GraphQL"); + rest("HTTP", "HTTP"), + graphql("GraphQL", "GQL"); - const APIType(this.label); + const APIType(this.label, this.abbr); final String label; + final String abbr; } enum HTTPVerb { From bd5c7597c900bc37031a6e263f294322c2b0a120 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 17:30:17 +0530 Subject: [PATCH 41/53] Add clear history --- .../history_widgets/his_sidebar_header.dart | 21 ++++++++++++------- lib/services/hive_services.dart | 5 +++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/screens/history/history_widgets/his_sidebar_header.dart b/lib/screens/history/history_widgets/his_sidebar_header.dart index 9f929e40..ad6fb1da 100644 --- a/lib/screens/history/history_widgets/his_sidebar_header.dart +++ b/lib/screens/history/history_widgets/his_sidebar_header.dart @@ -1,3 +1,4 @@ +import 'package:apidash/services/services.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -21,11 +22,19 @@ class HistorySidebarHeader extends ConsumerWidget { style: Theme.of(context).textTheme.titleMedium, ), const Spacer(), - IconButton( + ADIconButton( + icon: Icons.delete_forever, + iconSize: kButtonIconSizeLarge, + tooltip: "Clear History", + color: Theme.of(context).brightness == Brightness.dark + ? kColorDarkDanger + : kColorLightDanger, + onPressed: () => hiveHandler.clearAllHistory(), + ), + ADIconButton( + icon: Icons.manage_history_rounded, + iconSize: kButtonIconSizeLarge, tooltip: "Manage History", - style: IconButton.styleFrom( - foregroundColor: Theme.of(context).colorScheme.primary, - ), onPressed: () { showHistoryRetentionDialog( context, @@ -36,10 +45,6 @@ class HistorySidebarHeader extends ConsumerWidget { ); }); }, - icon: const Icon( - Icons.manage_history_rounded, - size: 20, - ), ), context.width <= kMinWindowSize.width ? IconButton( diff --git a/lib/services/hive_services.dart b/lib/services/hive_services.dart index 09ac8489..5ca47607 100644 --- a/lib/services/hive_services.dart +++ b/lib/services/hive_services.dart @@ -140,6 +140,11 @@ class HiveHandler { Future deleteHistoryRequest(String id) => historyLazyBox.delete(id); + Future clearAllHistory() async { + await historyMetaBox.clear(); + await historyLazyBox.clear(); + } + Future clear() async { await dataBox.clear(); await environmentBox.clear(); From 0eb81efed4a6645e6f92e5fa31a23bd42dddeed0 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 18:32:03 +0530 Subject: [PATCH 42/53] Update Codepane for GraphQL --- lib/screens/common_widgets/code_pane.dart | 8 ++++++++ .../details_card/request_pane/request_pane_graphql.dart | 9 ++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/screens/common_widgets/code_pane.dart b/lib/screens/common_widgets/code_pane.dart index 1da84542..654b9440 100644 --- a/lib/screens/common_widgets/code_pane.dart +++ b/lib/screens/common_widgets/code_pane.dart @@ -1,3 +1,4 @@ +import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/providers/providers.dart'; @@ -39,6 +40,13 @@ class CodePane extends ConsumerWidget { final code = codegen.getCode( codegenLanguage, substitutedRequestModel!, defaultUriScheme); + + // TODO: Add GraphQL Codegen + if (substitutedRequestModel.apiType == APIType.graphql) { + return const ErrorMessage( + message: "Code generation for GraphQL is currently not available.", + ); + } if (code == null) { return const ErrorMessage( message: "An error was encountered while generating code. $kRaiseIssue", diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart index 767a7b45..beae2b6c 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart @@ -14,7 +14,7 @@ class EditGraphQLRequestPane extends ConsumerWidget { final selectedId = ref.watch(selectedIdStateProvider); var tabIndex = ref.watch( selectedRequestModelProvider.select((value) => value?.requestTabIndex)); - + final codePaneVisible = ref.watch(codePaneVisibleStateProvider); final headerLength = ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.headersMap.length)) ?? 0; @@ -26,9 +26,12 @@ class EditGraphQLRequestPane extends ConsumerWidget { } return RequestPane( selectedId: selectedId, - codePaneVisible: false, - showViewCodeButton: false, + codePaneVisible: codePaneVisible, tabIndex: tabIndex, + onPressedCodeButton: () { + ref.read(codePaneVisibleStateProvider.notifier).state = + !codePaneVisible; + }, onTapTabBar: (index) { ref .read(collectionStateNotifierProvider.notifier) From da1bdb5cb89df6b1cde0c80882582c99879e5df9 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 18:32:13 +0530 Subject: [PATCH 43/53] Update History Sidebar --- lib/screens/history/history_page.dart | 2 +- lib/screens/history/{history_pane.dart => history_sidebar.dart} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename lib/screens/history/{history_pane.dart => history_sidebar.dart} (100%) diff --git a/lib/screens/history/history_page.dart b/lib/screens/history/history_page.dart index 37ca2c5e..5db100e6 100644 --- a/lib/screens/history/history_page.dart +++ b/lib/screens/history/history_page.dart @@ -5,7 +5,7 @@ import 'package:apidash/widgets/widgets.dart'; import 'package:apidash/providers/providers.dart'; import 'package:apidash/utils/utils.dart'; import 'package:apidash/consts.dart'; -import 'history_pane.dart'; +import 'history_sidebar.dart'; import 'history_viewer.dart'; class HistoryPage extends ConsumerWidget { diff --git a/lib/screens/history/history_pane.dart b/lib/screens/history/history_sidebar.dart similarity index 100% rename from lib/screens/history/history_pane.dart rename to lib/screens/history/history_sidebar.dart From b314c1b0181fb387ff2f1d634f4902f7cdfc913f Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 18:37:33 +0530 Subject: [PATCH 44/53] Update history_utils.dart --- lib/utils/history_utils.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/utils/history_utils.dart b/lib/utils/history_utils.dart index e6db9d38..d1c3dbbc 100644 --- a/lib/utils/history_utils.dart +++ b/lib/utils/history_utils.dart @@ -9,6 +9,7 @@ DateTime stripTime(DateTime dateTime) { RequestModel getRequestModelFromHistoryModel(HistoryRequestModel model) { return RequestModel( id: model.historyId, + apiType: model.metaData.apiType, name: model.metaData.name, responseStatus: model.httpResponseModel.statusCode, message: kResponseCodeReasons[model.httpResponseModel.statusCode], From a12fb51d945e9e37e5b128b87e1daa4964d50130 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 19:01:14 +0530 Subject: [PATCH 45/53] Fix GraphQL in History --- .../history_widgets/his_request_pane.dart | 200 +++++++++++------- .../history/history_widgets/his_url_card.dart | 24 ++- 2 files changed, 138 insertions(+), 86 deletions(-) diff --git a/lib/screens/history/history_widgets/his_request_pane.dart b/lib/screens/history/history_widgets/his_request_pane.dart index 7f2cbab2..dc618e77 100644 --- a/lib/screens/history/history_widgets/his_request_pane.dart +++ b/lib/screens/history/history_widgets/his_request_pane.dart @@ -18,7 +18,8 @@ class HistoryRequestPane extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final selectedId = ref.watch(selectedHistoryIdStateProvider); 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)) ?? {}; @@ -33,36 +34,69 @@ class HistoryRequestPane extends ConsumerWidget { .select((value) => value?.httpRequestModel.hasBody)) ?? false; - return RequestPane( - selectedId: selectedId, - codePaneVisible: codePaneVisible, - onPressedCodeButton: () { - ref.read(historyCodePaneVisibleStateProvider.notifier).state = - !codePaneVisible; - }, - showViewCodeButton: !isCompact, - showIndicators: [ - paramLength > 0, - headerLength > 0, - hasBody, - ], - tabLabels: const [ - kLabelURLParams, - kLabelHeaders, - kLabelBody, - ], - children: [ - RequestDataTable( - rows: paramsMap, - keyName: kNameURLParam, + final hasQuery = ref.watch(selectedHistoryRequestModelProvider + .select((value) => value?.httpRequestModel.hasQuery)) ?? + false; + + return switch (apiType) { + APIType.rest => RequestPane( + key: const Key("history-request-pane-rest"), + selectedId: selectedId, + codePaneVisible: codePaneVisible, + onPressedCodeButton: () { + ref.read(historyCodePaneVisibleStateProvider.notifier).state = + !codePaneVisible; + }, + showViewCodeButton: !isCompact, + showIndicators: [ + paramLength > 0, + headerLength > 0, + hasBody, + ], + tabLabels: const [ + kLabelURLParams, + kLabelHeaders, + kLabelBody, + ], + children: [ + RequestDataTable( + rows: paramsMap, + keyName: kNameURLParam, + ), + RequestDataTable( + rows: headersMap, + keyName: kNameHeader, + ), + const HisRequestBody(), + ], ), - RequestDataTable( - rows: headersMap, - keyName: kNameHeader, + APIType.graphql => RequestPane( + key: const Key("history-request-pane-graphql"), + selectedId: selectedId, + codePaneVisible: codePaneVisible, + onPressedCodeButton: () { + ref.read(historyCodePaneVisibleStateProvider.notifier).state = + !codePaneVisible; + }, + showViewCodeButton: !isCompact, + showIndicators: [ + headerLength > 0, + hasQuery, + ], + tabLabels: const [ + kLabelHeaders, + kLabelQuery, + ], + children: [ + RequestDataTable( + rows: headersMap, + keyName: kNameHeader, + ), + const HisRequestBody(), + ], ), - const HisRequestBody(), - ], - ); + _ => kSizedBoxEmpty, + }; } } @@ -72,58 +106,72 @@ class HisRequestBody extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final selectedHistoryModel = ref.watch(selectedHistoryRequestModelProvider); + final apiType = selectedHistoryModel?.metaData.apiType; final requestModel = selectedHistoryModel?.httpRequestModel; final contentType = requestModel?.bodyContentType; - return Column( - children: [ - kVSpacer5, - RichText( - text: TextSpan( - style: Theme.of(context).textTheme.labelLarge, - children: [ - const TextSpan( - text: "Content Type: ", + return switch (apiType) { + APIType.rest => Column( + children: [ + kVSpacer5, + RichText( + text: TextSpan( + style: Theme.of(context).textTheme.labelLarge, + children: [ + const TextSpan( + text: "Content Type: ", + ), + TextSpan( + text: contentType?.name ?? "text", + style: Theme.of(context).textTheme.titleSmall?.copyWith( + color: Theme.of(context).colorScheme.primary, + fontWeight: FontWeight.bold, + )), + ], ), - TextSpan( - text: contentType?.name ?? "text", - style: Theme.of(context).textTheme.titleSmall?.copyWith( - color: Theme.of(context).colorScheme.primary, - fontWeight: FontWeight.bold, - )), - ], + ), + kVSpacer5, + Expanded( + child: switch (contentType) { + ContentType.formdata => Padding( + padding: kPh4, + child: RequestFormDataTable( + rows: requestModel?.formData ?? [])), + // TODO: Fix JsonTextFieldEditor & plug it here + ContentType.json => Padding( + padding: kPt5o10, + child: TextFieldEditor( + key: Key("${selectedHistoryModel?.historyId}-json-body"), + fieldKey: + "${selectedHistoryModel?.historyId}-json-body-viewer", + initialValue: requestModel?.body, + readOnly: true, + ), + ), + _ => Padding( + padding: kPt5o10, + child: TextFieldEditor( + key: Key("${selectedHistoryModel?.historyId}-body"), + fieldKey: + "${selectedHistoryModel?.historyId}-body-viewer", + initialValue: requestModel?.body, + readOnly: true, + ), + ), + }, + ) + ], + ), + APIType.graphql => Padding( + padding: kPt5o10, + child: TextFieldEditor( + key: Key("${selectedHistoryModel?.historyId}-query"), + fieldKey: "${selectedHistoryModel?.historyId}-query-viewer", + initialValue: requestModel?.query, + readOnly: true, ), ), - kVSpacer5, - Expanded( - child: switch (contentType) { - ContentType.formdata => Padding( - padding: kPh4, - child: - RequestFormDataTable(rows: requestModel?.formData ?? [])), - // TODO: Fix JsonTextFieldEditor & plug it here - ContentType.json => Padding( - padding: kPt5o10, - child: TextFieldEditor( - key: Key("${selectedHistoryModel?.historyId}-json-body"), - fieldKey: - "${selectedHistoryModel?.historyId}-json-body-viewer", - initialValue: requestModel?.body, - readOnly: true, - ), - ), - _ => Padding( - padding: kPt5o10, - child: TextFieldEditor( - key: Key("${selectedHistoryModel?.historyId}-body"), - fieldKey: "${selectedHistoryModel?.historyId}-body-viewer", - initialValue: requestModel?.body, - readOnly: true, - ), - ), - }, - ) - ], - ); + _ => kSizedBoxEmpty, + }; } } diff --git a/lib/screens/history/history_widgets/his_url_card.dart b/lib/screens/history/history_widgets/his_url_card.dart index 7ce5833c..61e568f4 100644 --- a/lib/screens/history/history_widgets/his_url_card.dart +++ b/lib/screens/history/history_widgets/his_url_card.dart @@ -1,3 +1,4 @@ +import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; import 'package:apidash/widgets/widgets.dart'; @@ -16,6 +17,7 @@ class HistoryURLCard extends StatelessWidget { @override Widget build(BuildContext context) { + final apiType = historyRequestModel?.metaData.apiType; final method = historyRequestModel?.metaData.method; final url = historyRequestModel?.metaData.url; final fontSize = Theme.of(context).textTheme.titleMedium?.fontSize; @@ -41,18 +43,20 @@ class HistoryURLCard extends StatelessWidget { child: Row( children: [ isCompact ? const SizedBox.shrink() : kHSpacer10, - Text( - method!.name.toUpperCase(), - style: kCodeStyle.copyWith( - fontSize: fontSize, - fontWeight: FontWeight.bold, - color: getHTTPMethodColor( - method, - brightness: Theme.of(context).brightness, + if (apiType == APIType.rest) ...[ + Text( + method!.name.toUpperCase(), + style: kCodeStyle.copyWith( + fontSize: fontSize, + fontWeight: FontWeight.bold, + color: getHTTPMethodColor( + method, + brightness: Theme.of(context).brightness, + ), ), ), - ), - isCompact ? kHSpacer10 : kHSpacer20, + isCompact ? kHSpacer10 : kHSpacer20, + ], Expanded( child: ReadOnlyTextField( initialValue: url, From f8953f9967a817c841d94b0e1859bf60a705d8e0 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 19:22:21 +0530 Subject: [PATCH 46/53] Update README.md --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index bcb6d23e..b7427842 100644 --- a/README.md +++ b/README.md @@ -76,11 +76,22 @@ API Dash can be downloaded from the links below: ## List of Features +| API Type | Supported | +| --- | --- | +| HTTP | ✅ | +| GraphQL | ✅ | +| SSE | https://github.com/foss42/apidash/issues/116 | +| WebSocket | https://github.com/foss42/apidash/issues/15 | +| MQTT | https://github.com/foss42/apidash/issues/115 | +| gRPC | https://github.com/foss42/apidash/issues/14 | + + **↗️ Create & Customize API Requests** - Create different types of HTTP requests (`GET`, `HEAD`, `POST`, `PATCH`, `PUT` and `DELETE`). - Easily manipulate and play around with request inputs like `headers`, `query parameters` and `body`. - Full support to send text content with 🥳 Unicode/Emoji and preview any API response containing Unicode/Emoji. +- Create GraphQL requests with `headers` and `query`. **💼 Organize Requests in Collections & Folders** From 92efdc1494d4f8eb0da13dd7f48d130b13d40cad Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 19:24:32 +0530 Subject: [PATCH 47/53] Update ROADMAP.md --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 04dfeb08..35fda3eb 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -9,7 +9,7 @@ - [ ] WebSocket support (https://github.com/foss42/apidash/issues/15) - [ ] SSE support (https://github.com/foss42/apidash/issues/116) - [ ] MQTT support (https://github.com/foss42/apidash/issues/115) -- [ ] GraphQL support (https://github.com/foss42/apidash/issues/117) +- [x] GraphQL support (https://github.com/foss42/apidash/issues/117) - [ ] gRPC support (https://github.com/foss42/apidash/issues/14) - [ ] Figuring out how to build for various Linux packaging formats (https://github.com/foss42/apidash/discussions/240) [Docs] - [ ] Save items in Response headers/body in an Environment variable to be used by other requests (https://github.com/foss42/apidash/issues/465) From e1208ae9c6bc71af2a41d06bbbd6799bf7a16779 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 19:27:51 +0530 Subject: [PATCH 48/53] Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index b7427842..eb82a738 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,15 @@ API Dash can be downloaded from the links below: | MQTT | https://github.com/foss42/apidash/issues/115 | | gRPC | https://github.com/foss42/apidash/issues/14 | +| Import Collection From | Supported | +| --- | --- | +| Postman | ✅ | +| cURL | ✅ | +| Insomnia | https://github.com/foss42/apidash/issues/125 | +| OpenAPI | https://github.com/foss42/apidash/issues/121 | +| hurl | https://github.com/foss42/apidash/issues/123 | +| HAR | https://github.com/foss42/apidash/issues/122 | + **↗️ Create & Customize API Requests** From 084b68d62f42bd70bf83db021c74bc600528e8ce Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 20:38:17 +0530 Subject: [PATCH 49/53] bump version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index ce0bc937..e2d00bad 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: apidash description: API Dash is a beautiful open-source cross-platform API Client built using Flutter which can help you easily create & customize your API requests, visually inspect responses and generate Dart code on the go. publish_to: "none" -version: 0.4.0+4 +version: 0.5.0+5 environment: sdk: ">=3.0.0 <4.0.0" From d9584b0bdc377e509d09d07a653f72cbc3d21f46 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 21:10:46 +0530 Subject: [PATCH 50/53] Update CHANGELOG.md --- CHANGELOG.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a975ee6..ef684ccd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,21 @@ # API Dash ⚡️ Changelog -## v0.4.0 [WIP] +## v0.5.0 [WIP] + +In this release, we have added the following features: + +1. Create workspace (directory) to persist your entire data locally in the provided file-system location +2. Environment varibles +3. GraphQL support +4. Import requests from cURL & Postman Collection (v2.1) +5. History of your requests & response +6. Support for Request cancellation +7. Disable SSL verification +8. Codegen for Swift, hyper, etc. + +A big shout-out to all the contributors 🎉 + +## v0.4.0 [iOS Release] In this release, we have added the following features: @@ -15,7 +30,7 @@ In this release, we have added the following features: 9. Dart http codegen has been rewritten using dart code builder 10. Ability to override request contenttype 11. More header suggestions - +12. Mobile platform support ## v0.3.0 [29-11-2023] From fc60925eaed5ac5dcd35f1e4a03cbfdf47647386 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 21:11:31 +0530 Subject: [PATCH 51/53] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb82a738..e5070a32 100644 --- a/README.md +++ b/README.md @@ -242,7 +242,7 @@ Here is the complete list of MIME types that are syntax highlighted in API Dash: | `text/javascript` | `.js` | | | `text/markdown` | `.md` | | -## What's new in v0.3.0? +## What's new in v0.5.0? Visit [CHANGELOG.md](CHANGELOG.md) From 08337cbfedcb86c4b5e303de6775cb5b5b66a279 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 21:12:57 +0530 Subject: [PATCH 52/53] Update ROADMAP.md --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 35fda3eb..87a6d49e 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -12,7 +12,7 @@ - [x] GraphQL support (https://github.com/foss42/apidash/issues/117) - [ ] gRPC support (https://github.com/foss42/apidash/issues/14) - [ ] Figuring out how to build for various Linux packaging formats (https://github.com/foss42/apidash/discussions/240) [Docs] -- [ ] Save items in Response headers/body in an Environment variable to be used by other requests (https://github.com/foss42/apidash/issues/465) +- [ ] Save items in Response headers/body in an Environment variable to be used by other requests. Something like a post-processing script. (https://github.com/foss42/apidash/issues/465) - [ ] Importers - [ ] OpenAPI (https://github.com/foss42/apidash/issues/121) - [ ] Insomnia (https://github.com/foss42/apidash/issues/125) From 81fc65c11ce748c95beb78019b7dbd7d1c4e845e Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Sun, 12 Jan 2025 21:13:12 +0530 Subject: [PATCH 53/53] Update ROADMAP.md --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index 87a6d49e..f18b4757 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -5,7 +5,7 @@ - [x] Remaining Code Generators (https://github.com/foss42/apidash/discussions/80) - [x] Environment Variables (https://github.com/foss42/apidash/issues/25) - [x] Integration Testing (https://github.com/foss42/apidash/issues/119) -- [ ] Paste not working on iOS and desktop (Right Click -> Paste) (https://github.com/foss42/apidash/issues/490) +- [x] Paste not working on iOS and desktop (Right Click -> Paste) (https://github.com/foss42/apidash/issues/490) - [ ] WebSocket support (https://github.com/foss42/apidash/issues/15) - [ ] SSE support (https://github.com/foss42/apidash/issues/116) - [ ] MQTT support (https://github.com/foss42/apidash/issues/115)