mirror of
https://github.com/foss42/apidash.git
synced 2025-07-03 14:36:22 +08:00
Merge branch 'main' into elapsed-time-by-request
This commit is contained in:
CONTRIBUTING.mdpubspec.yaml
lib
codegen
consts.dartmodels
providers
screens/home_page
collection_pane.dart
editor_pane/details_card
widgets
test
@ -154,4 +154,16 @@ ClientException with SocketException: Connection failed (OS Error: Operation not
|
|||||||
|
|
||||||
You can read more [here](https://docs.flutter.dev/platform-integration/macos/building#setting-up-entitlements)
|
You can read more [here](https://docs.flutter.dev/platform-integration/macos/building#setting-up-entitlements)
|
||||||
|
|
||||||
|
### Android (Work in Progress)
|
||||||
|
|
||||||
|
Add the `multiDexEnabled true` line to the `defaultConfig` section at `android/app/build.gradle file`
|
||||||
|
|
||||||
|
```
|
||||||
|
android {
|
||||||
|
...
|
||||||
|
defaultConfig {
|
||||||
|
...
|
||||||
|
multiDexEnabled true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@ -9,6 +9,7 @@ import 'php/guzzle.dart';
|
|||||||
import 'python/http_client.dart';
|
import 'python/http_client.dart';
|
||||||
import 'python/requests.dart';
|
import 'python/requests.dart';
|
||||||
import 'rust/actix.dart';
|
import 'rust/actix.dart';
|
||||||
|
import 'rust/curl_rust.dart';
|
||||||
import 'rust/reqwest.dart';
|
import 'rust/reqwest.dart';
|
||||||
import 'rust/ureq.dart';
|
import 'rust/ureq.dart';
|
||||||
import 'js/axios.dart';
|
import 'js/axios.dart';
|
||||||
@ -73,6 +74,8 @@ class Codegen {
|
|||||||
return PythonRequestsCodeGen().getCode(rM, boundary: boundary);
|
return PythonRequestsCodeGen().getCode(rM, boundary: boundary);
|
||||||
case CodegenLanguage.rustActix:
|
case CodegenLanguage.rustActix:
|
||||||
return RustActixCodeGen().getCode(rM, boundary: boundary);
|
return RustActixCodeGen().getCode(rM, boundary: boundary);
|
||||||
|
case CodegenLanguage.rustCurl:
|
||||||
|
return RustCurlCodeGen().getCode(rM);
|
||||||
case CodegenLanguage.rustReqwest:
|
case CodegenLanguage.rustReqwest:
|
||||||
return RustReqwestCodeGen().getCode(rM);
|
return RustReqwestCodeGen().getCode(rM);
|
||||||
case CodegenLanguage.rustUreq:
|
case CodegenLanguage.rustUreq:
|
||||||
|
147
lib/codegen/rust/curl_rust.dart
Normal file
147
lib/codegen/rust/curl_rust.dart
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
import 'package:jinja/jinja.dart' as jj;
|
||||||
|
import 'package:apidash/utils/utils.dart'
|
||||||
|
show getValidRequestUri, requestModelToHARJsonRequest;
|
||||||
|
import 'package:apidash/models/models.dart' show RequestModel;
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
|
class RustCurlCodeGen {
|
||||||
|
final String kTemplateStart = """use curl::easy::Easy;
|
||||||
|
{% if hasJsonBody %}use serde_json::json;
|
||||||
|
{% endif %}{% if hasHeaders %}use curl::easy::List;
|
||||||
|
{% endif %}
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
String kTemplateUrl = """
|
||||||
|
easy.url("{{url}}").unwrap();
|
||||||
|
""";
|
||||||
|
|
||||||
|
String kTemplateMethod = """
|
||||||
|
{% if method == 'get' or method == 'post' or method == 'put' %}
|
||||||
|
easy.{{ method }}(true).unwrap();
|
||||||
|
{% elif method == 'delete' %}
|
||||||
|
easy.custom_request("DELETE").unwrap();
|
||||||
|
{% elif method == 'patch' %}
|
||||||
|
easy.custom_request("PATCH").unwrap();
|
||||||
|
{% elif method == 'head' %}
|
||||||
|
easy.nobody(true).unwrap();
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
String kTemplateRawBody = """
|
||||||
|
easy.post_fields_copy(r#"{{body}}"#.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
String kTemplateJsonBody = """
|
||||||
|
easy.post_fields_copy(json!({{body}}).to_string().as_bytes()).unwrap();
|
||||||
|
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
String kTemplateFormData = """
|
||||||
|
let mut form = curl::easy::Form::new();
|
||||||
|
{% for field in fields %}
|
||||||
|
form.part("{{field.name}}")
|
||||||
|
{% if field.type == "file" %}.file("{{field.value}}"){% else %}.contents(b"{{field.value}}"){% endif %}
|
||||||
|
.add().unwrap();
|
||||||
|
{% endfor %}
|
||||||
|
easy.httppost(form).unwrap();
|
||||||
|
""";
|
||||||
|
|
||||||
|
String kTemplateHeader = """
|
||||||
|
{% if headers %}let mut list = List::new();{% for header, value in headers %}
|
||||||
|
list.append("{{header}}: {{value}}").unwrap();{% endfor %}
|
||||||
|
easy.http_headers(list).unwrap();
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
final String kTemplateEnd = """
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
|
||||||
|
String? getCode(RequestModel requestModel) {
|
||||||
|
try {
|
||||||
|
String result = "";
|
||||||
|
var requestBody = requestModel.requestBody;
|
||||||
|
|
||||||
|
String url = requestModel.url;
|
||||||
|
|
||||||
|
result += jj.Template(kTemplateStart).render({
|
||||||
|
"hasJsonBody": requestModel.hasJsonData,
|
||||||
|
"hasHeaders": (requestModel.enabledRequestHeaders != null &&
|
||||||
|
requestModel.enabledRequestHeaders!.isNotEmpty) ||
|
||||||
|
(requestModel.hasJsonData || requestModel.hasTextData)
|
||||||
|
});
|
||||||
|
|
||||||
|
var rec = getValidRequestUri(
|
||||||
|
url,
|
||||||
|
requestModel.enabledRequestParams,
|
||||||
|
);
|
||||||
|
|
||||||
|
Uri? uri = rec.$1;
|
||||||
|
var harJson =
|
||||||
|
requestModelToHARJsonRequest(requestModel, useEnabled: true);
|
||||||
|
|
||||||
|
var templateUrl = jj.Template(kTemplateUrl);
|
||||||
|
result += templateUrl.render({"url": harJson["url"]});
|
||||||
|
|
||||||
|
var methodTemplate = jj.Template(kTemplateMethod);
|
||||||
|
result += methodTemplate.render({"method": requestModel.method.name});
|
||||||
|
|
||||||
|
if (uri != null) {
|
||||||
|
if (requestModel.hasTextData) {
|
||||||
|
var templateBody = jj.Template(kTemplateRawBody);
|
||||||
|
result += templateBody.render({"body": requestBody});
|
||||||
|
} else if (requestModel.hasJsonData) {
|
||||||
|
var templateBody = jj.Template(kTemplateJsonBody);
|
||||||
|
result += templateBody.render({"body": requestBody});
|
||||||
|
} else if (requestModel.hasFormData) {
|
||||||
|
var templateFormData = jj.Template(kTemplateFormData);
|
||||||
|
result += templateFormData.render({
|
||||||
|
"fields": requestModel.formDataMapList,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var headersList = requestModel.enabledRequestHeaders;
|
||||||
|
if (headersList != null || requestModel.hasBody) {
|
||||||
|
var headers = requestModel.enabledHeadersMap;
|
||||||
|
if (requestModel.hasJsonData || requestModel.hasTextData) {
|
||||||
|
headers.putIfAbsent(kHeaderContentType,
|
||||||
|
() => requestModel.requestBodyContentType.header);
|
||||||
|
}
|
||||||
|
if (headers.isNotEmpty) {
|
||||||
|
var templateHeader = jj.Template(kTemplateHeader);
|
||||||
|
result += templateHeader.render({
|
||||||
|
"headers": headers,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result += kTemplateEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -56,6 +56,7 @@ const kForegroundOpacity = 0.05;
|
|||||||
const kOverlayBackgroundOpacity = 0.5;
|
const kOverlayBackgroundOpacity = 0.5;
|
||||||
|
|
||||||
const kTextStyleButton = TextStyle(fontWeight: FontWeight.bold);
|
const kTextStyleButton = TextStyle(fontWeight: FontWeight.bold);
|
||||||
|
const kTextStyleTab = TextStyle(fontSize: 14);
|
||||||
const kTextStyleButtonSmall = TextStyle(fontSize: 12);
|
const kTextStyleButtonSmall = TextStyle(fontSize: 12);
|
||||||
const kFormDataButtonLabelTextStyle = TextStyle(
|
const kFormDataButtonLabelTextStyle = TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
@ -71,9 +72,13 @@ const kP5 = EdgeInsets.all(5);
|
|||||||
const kP8 = EdgeInsets.all(8);
|
const kP8 = EdgeInsets.all(8);
|
||||||
const kPs8 = EdgeInsets.only(left: 8);
|
const kPs8 = EdgeInsets.only(left: 8);
|
||||||
const kPs2 = EdgeInsets.only(left: 2);
|
const kPs2 = EdgeInsets.only(left: 2);
|
||||||
|
const kPe8 = EdgeInsets.only(right: 8.0);
|
||||||
const kPh20v5 = EdgeInsets.symmetric(horizontal: 20, vertical: 5);
|
const kPh20v5 = EdgeInsets.symmetric(horizontal: 20, vertical: 5);
|
||||||
const kPh20v10 = EdgeInsets.symmetric(horizontal: 20, vertical: 10);
|
const kPh20v10 = EdgeInsets.symmetric(horizontal: 20, vertical: 10);
|
||||||
const kP10 = EdgeInsets.all(10);
|
const kP10 = EdgeInsets.all(10);
|
||||||
|
const kPv8 = EdgeInsets.symmetric(vertical: 8);
|
||||||
|
const kPv2 = EdgeInsets.symmetric(vertical: 2);
|
||||||
|
const kPh2 = EdgeInsets.symmetric(horizontal: 2);
|
||||||
const kPt24o8 = EdgeInsets.only(top: 24, left: 8.0, right: 8.0, bottom: 8.0);
|
const kPt24o8 = EdgeInsets.only(top: 24, left: 8.0, right: 8.0, bottom: 8.0);
|
||||||
const kPt5o10 =
|
const kPt5o10 =
|
||||||
EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 10.0);
|
EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 10.0);
|
||||||
@ -102,8 +107,9 @@ const kP8CollectionPane = EdgeInsets.only(
|
|||||||
const kPb10 = EdgeInsets.only(
|
const kPb10 = EdgeInsets.only(
|
||||||
bottom: 10,
|
bottom: 10,
|
||||||
);
|
);
|
||||||
const kPr8CollectionPane = EdgeInsets.only(right: 8.0);
|
const kPb15 = EdgeInsets.only(
|
||||||
const kpsV5 = EdgeInsets.symmetric(vertical: 2);
|
bottom: 15,
|
||||||
|
);
|
||||||
const kHSpacer4 = SizedBox(width: 4);
|
const kHSpacer4 = SizedBox(width: 4);
|
||||||
const kHSpacer5 = SizedBox(width: 5);
|
const kHSpacer5 = SizedBox(width: 5);
|
||||||
const kHSpacer10 = SizedBox(width: 10);
|
const kHSpacer10 = SizedBox(width: 10);
|
||||||
@ -112,9 +118,10 @@ const kVSpacer5 = SizedBox(height: 5);
|
|||||||
const kVSpacer8 = SizedBox(height: 8);
|
const kVSpacer8 = SizedBox(height: 8);
|
||||||
const kVSpacer10 = SizedBox(height: 10);
|
const kVSpacer10 = SizedBox(height: 10);
|
||||||
const kVSpacer20 = SizedBox(height: 20);
|
const kVSpacer20 = SizedBox(height: 20);
|
||||||
|
const kVSpacer40 = SizedBox(height: 40);
|
||||||
|
|
||||||
const kTabAnimationDuration = Duration(milliseconds: 200);
|
const kTabAnimationDuration = Duration(milliseconds: 200);
|
||||||
const kTabHeight = 45.0;
|
const kTabHeight = 32.0;
|
||||||
const kHeaderHeight = 32.0;
|
const kHeaderHeight = 32.0;
|
||||||
const kSegmentHeight = 24.0;
|
const kSegmentHeight = 24.0;
|
||||||
const kTextButtonMinWidth = 44.0;
|
const kTextButtonMinWidth = 44.0;
|
||||||
@ -284,6 +291,7 @@ enum CodegenLanguage {
|
|||||||
pythonHttpClient("Python (http.client)", "python", "py"),
|
pythonHttpClient("Python (http.client)", "python", "py"),
|
||||||
rustActix("Rust (Actix Client)", "rust", "rs"),
|
rustActix("Rust (Actix Client)", "rust", "rs"),
|
||||||
rustReqwest("Rust (reqwest)", "rust", "rs"),
|
rustReqwest("Rust (reqwest)", "rust", "rs"),
|
||||||
|
rustCurl("Rust (curl-rust)", "rust", "rs"),
|
||||||
rustUreq("Rust (ureq)", "rust", "rs"),
|
rustUreq("Rust (ureq)", "rust", "rs"),
|
||||||
javaOkHttp("Java (okhttp3)", "java", 'java'),
|
javaOkHttp("Java (okhttp3)", "java", 'java'),
|
||||||
javaAsyncHttpClient("Java (asynchttpclient)", "java", "java"),
|
javaAsyncHttpClient("Java (asynchttpclient)", "java", "java"),
|
||||||
@ -532,3 +540,36 @@ const kLabelSave = "Save";
|
|||||||
const kLabelDownload = "Download";
|
const kLabelDownload = "Download";
|
||||||
const kLabelSaving = "Saving";
|
const kLabelSaving = "Saving";
|
||||||
const kLabelSaved = "Saved";
|
const kLabelSaved = "Saved";
|
||||||
|
// Request Pane
|
||||||
|
const kLabelRequest = "Request";
|
||||||
|
const kLabelHideCode = "Hide Code";
|
||||||
|
const kLabelViewCode = "View Code";
|
||||||
|
const kLabelURLParams = "URL Params";
|
||||||
|
const kLabelHeaders = "Headers";
|
||||||
|
const kLabelBody = "Body";
|
||||||
|
const kNameCheckbox = "Checkbox";
|
||||||
|
const kNameURLParam = "URL Parameter";
|
||||||
|
const kNameHeader = "Header Name";
|
||||||
|
const kNameValue = "Value";
|
||||||
|
const kNameField = "Field";
|
||||||
|
const kHintAddURLParam = "Add URL Parameter";
|
||||||
|
const kHintAddValue = "Add Value";
|
||||||
|
const kHintAddName = "Add Name";
|
||||||
|
const kHintAddFieldName = "Add Field Name";
|
||||||
|
const kLabelAddParam = "Add Param";
|
||||||
|
const kLabelAddHeader = "Add Header";
|
||||||
|
const kLabelSelectFile = "Select File";
|
||||||
|
const kLabelAddFormField = "Add Form Field";
|
||||||
|
// Response Pane
|
||||||
|
const kLabelNotSent = "Not Sent";
|
||||||
|
const kLabelResponse = "Response";
|
||||||
|
const kLabelResponseBody = "Response Body";
|
||||||
|
const kTooltipClearResponse = "Clear Response";
|
||||||
|
const kHeaderRow = ["Header Name", "Header Value"];
|
||||||
|
const kLabelRequestHeaders = "Request Headers";
|
||||||
|
const kLabelResponseHeaders = "Response Headers";
|
||||||
|
const kLabelItems = "items";
|
||||||
|
const kMsgError = "Error: Response data does not exist.";
|
||||||
|
const kMsgNullBody = "Response body is missing (null).";
|
||||||
|
const kMsgNoContent = "No content";
|
||||||
|
const kMsgUnknowContentType = "Unknown Response Content-Type";
|
||||||
|
@ -97,6 +97,7 @@ class RequestModel {
|
|||||||
RequestModel duplicate({
|
RequestModel duplicate({
|
||||||
required String id,
|
required String id,
|
||||||
String? name,
|
String? name,
|
||||||
|
int? requestTabIndex,
|
||||||
}) {
|
}) {
|
||||||
return RequestModel(
|
return RequestModel(
|
||||||
id: id,
|
id: id,
|
||||||
@ -104,6 +105,7 @@ class RequestModel {
|
|||||||
url: url,
|
url: url,
|
||||||
name: name ?? "${this.name} (copy)",
|
name: name ?? "${this.name} (copy)",
|
||||||
description: description,
|
description: description,
|
||||||
|
requestTabIndex: requestTabIndex ?? 0,
|
||||||
requestHeaders: requestHeaders != null ? [...requestHeaders!] : null,
|
requestHeaders: requestHeaders != null ? [...requestHeaders!] : null,
|
||||||
requestParams: requestParams != null ? [...requestParams!] : null,
|
requestParams: requestParams != null ? [...requestParams!] : null,
|
||||||
isHeaderEnabledList:
|
isHeaderEnabledList:
|
||||||
|
@ -102,6 +102,7 @@ class CollectionStateNotifier
|
|||||||
final newModel = currentModel.duplicate(
|
final newModel = currentModel.duplicate(
|
||||||
id: id,
|
id: id,
|
||||||
name: currentModel.name,
|
name: currentModel.name,
|
||||||
|
requestTabIndex: currentModel.requestTabIndex,
|
||||||
);
|
);
|
||||||
var map = {...state!};
|
var map = {...state!};
|
||||||
map[id] = newModel;
|
map[id] = newModel;
|
||||||
|
@ -23,3 +23,5 @@ final nameTextFieldFocusNodeProvider =
|
|||||||
});
|
});
|
||||||
return focusNode;
|
return focusNode;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final searchQueryProvider = StateProvider<String>((ref) => '');
|
||||||
|
@ -26,7 +26,7 @@ class CollectionPane extends ConsumerWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: kPr8CollectionPane,
|
padding: kPe8,
|
||||||
child: Wrap(
|
child: Wrap(
|
||||||
alignment: WrapAlignment.spaceBetween,
|
alignment: WrapAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
@ -69,7 +69,39 @@ class CollectionPane extends ConsumerWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
kVSpacer8,
|
kVSpacer10,
|
||||||
|
Container(
|
||||||
|
height: 30,
|
||||||
|
margin: const EdgeInsets.only(right: 8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: kBorderRadius8,
|
||||||
|
border: Border.all(
|
||||||
|
color: Theme.of(context).colorScheme.surfaceVariant,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
kHSpacer5,
|
||||||
|
Icon(
|
||||||
|
Icons.filter_alt,
|
||||||
|
size: 18,
|
||||||
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
kHSpacer5,
|
||||||
|
Expanded(
|
||||||
|
child: RawTextField(
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
hintText: "Filter by name or URL",
|
||||||
|
onChanged: (value) {
|
||||||
|
ref.read(searchQueryProvider.notifier).state =
|
||||||
|
value.toLowerCase();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
kVSpacer10,
|
||||||
const Expanded(
|
const Expanded(
|
||||||
child: RequestList(),
|
child: RequestList(),
|
||||||
),
|
),
|
||||||
@ -109,13 +141,15 @@ class _RequestListState extends ConsumerState<RequestList> {
|
|||||||
final requestItems = ref.watch(collectionStateNotifierProvider)!;
|
final requestItems = ref.watch(collectionStateNotifierProvider)!;
|
||||||
final alwaysShowCollectionPaneScrollbar = ref.watch(settingsProvider
|
final alwaysShowCollectionPaneScrollbar = ref.watch(settingsProvider
|
||||||
.select((value) => value.alwaysShowCollectionPaneScrollbar));
|
.select((value) => value.alwaysShowCollectionPaneScrollbar));
|
||||||
|
final filterQuery = ref.watch(searchQueryProvider).trim();
|
||||||
|
|
||||||
return Scrollbar(
|
return Scrollbar(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
thumbVisibility: alwaysShowCollectionPaneScrollbar ? true : null,
|
thumbVisibility: alwaysShowCollectionPaneScrollbar ? true : null,
|
||||||
radius: const Radius.circular(12),
|
radius: const Radius.circular(12),
|
||||||
child: ReorderableListView.builder(
|
child: filterQuery.isEmpty
|
||||||
padding: kPr8CollectionPane,
|
? ReorderableListView.builder(
|
||||||
|
padding: kPe8,
|
||||||
scrollController: controller,
|
scrollController: controller,
|
||||||
buildDefaultDragHandles: false,
|
buildDefaultDragHandles: false,
|
||||||
itemCount: requestSequence.length,
|
itemCount: requestSequence.length,
|
||||||
@ -143,6 +177,24 @@ class _RequestListState extends ConsumerState<RequestList> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
)
|
||||||
|
: ListView(
|
||||||
|
padding: kPe8,
|
||||||
|
controller: controller,
|
||||||
|
children: requestSequence.map((id) {
|
||||||
|
var item = requestItems[id]!;
|
||||||
|
if (item.url.toLowerCase().contains(filterQuery) ||
|
||||||
|
item.name.toLowerCase().contains(filterQuery)) {
|
||||||
|
return Padding(
|
||||||
|
padding: kP1,
|
||||||
|
child: RequestItem(
|
||||||
|
id: id,
|
||||||
|
requestModel: item,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return const SizedBox();
|
||||||
|
}).toList(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -17,48 +17,72 @@ class FormDataWidget extends ConsumerStatefulWidget {
|
|||||||
class _FormDataBodyState extends ConsumerState<FormDataWidget> {
|
class _FormDataBodyState extends ConsumerState<FormDataWidget> {
|
||||||
late int seed;
|
late int seed;
|
||||||
final random = Random.secure();
|
final random = Random.secure();
|
||||||
late List<FormDataModel> rows;
|
late List<FormDataModel> formRows;
|
||||||
|
bool isAddingRow = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
seed = random.nextInt(kRandMax);
|
seed = random.nextInt(kRandMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onFieldChange(String selectedId) {
|
||||||
|
ref.read(collectionStateNotifierProvider.notifier).update(
|
||||||
|
selectedId,
|
||||||
|
requestFormDataList: formRows.sublist(0, formRows.length - 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final selectedId = ref.watch(selectedIdStateProvider);
|
final selectedId = ref.watch(selectedIdStateProvider);
|
||||||
var formRows = ref.read(selectedRequestModelProvider)?.requestFormDataList;
|
ref.watch(selectedRequestModelProvider
|
||||||
rows =
|
.select((value) => value?.requestFormDataList?.length));
|
||||||
formRows == null || formRows.isEmpty ? [kFormDataEmptyModel] : formRows;
|
var rF = ref.read(selectedRequestModelProvider)?.requestFormDataList;
|
||||||
|
bool isFormDataEmpty = rF == null || rF.isEmpty;
|
||||||
|
List<FormDataModel> rows = (isFormDataEmpty)
|
||||||
|
? [
|
||||||
|
kFormDataEmptyModel,
|
||||||
|
]
|
||||||
|
: rF;
|
||||||
|
formRows = isFormDataEmpty ? rows : rows + [kFormDataEmptyModel];
|
||||||
|
isAddingRow = false;
|
||||||
|
|
||||||
DaviModel<FormDataModel> daviModelRows = DaviModel<FormDataModel>(
|
DaviModel<FormDataModel> daviModelRows = DaviModel<FormDataModel>(
|
||||||
rows: rows,
|
rows: formRows,
|
||||||
columns: [
|
columns: [
|
||||||
DaviColumn(
|
DaviColumn(
|
||||||
cellPadding: kpsV5,
|
cellPadding: kPv2,
|
||||||
name: 'Key',
|
name: kNameField,
|
||||||
grow: 4,
|
grow: 4,
|
||||||
cellBuilder: (_, row) {
|
cellBuilder: (_, row) {
|
||||||
int idx = row.index;
|
int idx = row.index;
|
||||||
|
bool isLast = idx + 1 == formRows.length;
|
||||||
return Theme(
|
return Theme(
|
||||||
data: Theme.of(context),
|
data: Theme.of(context),
|
||||||
child: FormDataField(
|
child: FormDataField(
|
||||||
keyId: "$selectedId-$idx-form-v-$seed",
|
keyId: "$selectedId-$idx-form-v-$seed",
|
||||||
initialValue: rows[idx].name,
|
initialValue: formRows[idx].name,
|
||||||
hintText: " Add Key",
|
hintText: kHintAddFieldName,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
rows[idx] = rows[idx].copyWith(
|
formRows[idx] = formRows[idx].copyWith(name: value);
|
||||||
name: value,
|
if (isLast && !isAddingRow) {
|
||||||
);
|
isAddingRow = true;
|
||||||
|
formRows.add(kFormDataEmptyModel);
|
||||||
|
}
|
||||||
_onFieldChange(selectedId!);
|
_onFieldChange(selectedId!);
|
||||||
},
|
},
|
||||||
colorScheme: Theme.of(context).colorScheme,
|
colorScheme: Theme.of(context).colorScheme,
|
||||||
formDataType: rows[idx].type,
|
formDataType: formRows[idx].type,
|
||||||
onFormDataTypeChanged: (value) {
|
onFormDataTypeChanged: (value) {
|
||||||
rows[idx] = rows[idx].copyWith(
|
bool hasChanged = formRows[idx].type != value;
|
||||||
|
formRows[idx] = formRows[idx].copyWith(
|
||||||
type: value ?? FormDataType.text,
|
type: value ?? FormDataType.text,
|
||||||
);
|
);
|
||||||
rows[idx] = rows[idx].copyWith(value: "");
|
formRows[idx] = formRows[idx].copyWith(value: "");
|
||||||
|
if (isLast && hasChanged) {
|
||||||
|
formRows.add(kFormDataEmptyModel);
|
||||||
|
}
|
||||||
setState(() {});
|
setState(() {});
|
||||||
_onFieldChange(selectedId!);
|
_onFieldChange(selectedId!);
|
||||||
},
|
},
|
||||||
@ -69,7 +93,7 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
|
|||||||
),
|
),
|
||||||
DaviColumn(
|
DaviColumn(
|
||||||
width: 40,
|
width: 40,
|
||||||
cellPadding: kpsV5,
|
cellPadding: kPv2,
|
||||||
cellAlignment: Alignment.center,
|
cellAlignment: Alignment.center,
|
||||||
cellBuilder: (_, row) {
|
cellBuilder: (_, row) {
|
||||||
return Text(
|
return Text(
|
||||||
@ -79,12 +103,13 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
DaviColumn(
|
DaviColumn(
|
||||||
name: 'Value',
|
name: kNameValue,
|
||||||
grow: 4,
|
grow: 4,
|
||||||
cellPadding: kpsV5,
|
cellPadding: kPv2,
|
||||||
cellBuilder: (_, row) {
|
cellBuilder: (_, row) {
|
||||||
int idx = row.index;
|
int idx = row.index;
|
||||||
return rows[idx].type == FormDataType.file
|
bool isLast = idx + 1 == formRows.length;
|
||||||
|
return formRows[idx].type == FormDataType.file
|
||||||
? Align(
|
? Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -109,7 +134,7 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
|
|||||||
if (pickedResult != null &&
|
if (pickedResult != null &&
|
||||||
pickedResult.files.isNotEmpty &&
|
pickedResult.files.isNotEmpty &&
|
||||||
pickedResult.files.first.path != null) {
|
pickedResult.files.first.path != null) {
|
||||||
rows[idx] = rows[idx].copyWith(
|
formRows[idx] = formRows[idx].copyWith(
|
||||||
value: pickedResult.files.first.path!,
|
value: pickedResult.files.first.path!,
|
||||||
);
|
);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
@ -117,10 +142,10 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
label: Text(
|
label: Text(
|
||||||
(rows[idx].type == FormDataType.file &&
|
(formRows[idx].type == FormDataType.file &&
|
||||||
rows[idx].value.isNotEmpty)
|
formRows[idx].value.isNotEmpty)
|
||||||
? rows[idx].value.toString()
|
? formRows[idx].value.toString()
|
||||||
: "Select File",
|
: kLabelSelectFile,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: kFormDataButtonLabelTextStyle,
|
style: kFormDataButtonLabelTextStyle,
|
||||||
@ -133,10 +158,14 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
|
|||||||
)
|
)
|
||||||
: CellField(
|
: CellField(
|
||||||
keyId: "$selectedId-$idx-form-v-$seed",
|
keyId: "$selectedId-$idx-form-v-$seed",
|
||||||
initialValue: rows[idx].value,
|
initialValue: formRows[idx].value,
|
||||||
hintText: " Add Value",
|
hintText: kHintAddValue,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
rows[idx] = rows[idx].copyWith(value: value);
|
formRows[idx] = formRows[idx].copyWith(value: value);
|
||||||
|
if (isLast && !isAddingRow) {
|
||||||
|
isAddingRow = true;
|
||||||
|
formRows.add(kFormDataEmptyModel);
|
||||||
|
}
|
||||||
_onFieldChange(selectedId!);
|
_onFieldChange(selectedId!);
|
||||||
},
|
},
|
||||||
colorScheme: Theme.of(context).colorScheme,
|
colorScheme: Theme.of(context).colorScheme,
|
||||||
@ -148,22 +177,24 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
|
|||||||
pinStatus: PinStatus.none,
|
pinStatus: PinStatus.none,
|
||||||
width: 30,
|
width: 30,
|
||||||
cellBuilder: (_, row) {
|
cellBuilder: (_, row) {
|
||||||
|
bool isLast = row.index + 1 == formRows.length;
|
||||||
return InkWell(
|
return InkWell(
|
||||||
|
onTap: isLast
|
||||||
|
? null
|
||||||
|
: () {
|
||||||
|
seed = random.nextInt(kRandMax);
|
||||||
|
if (formRows.length == 2) {
|
||||||
|
setState(() {
|
||||||
|
formRows = [kFormDataEmptyModel];
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
formRows.removeAt(row.index);
|
||||||
|
}
|
||||||
|
_onFieldChange(selectedId!);
|
||||||
|
},
|
||||||
child: Theme.of(context).brightness == Brightness.dark
|
child: Theme.of(context).brightness == Brightness.dark
|
||||||
? kIconRemoveDark
|
? kIconRemoveDark
|
||||||
: kIconRemoveLight,
|
: kIconRemoveLight,
|
||||||
onTap: () {
|
|
||||||
seed = random.nextInt(kRandMax);
|
|
||||||
if (rows.length == 1) {
|
|
||||||
setState(() {
|
|
||||||
rows = [kFormDataEmptyModel];
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
rows.removeAt(row.index);
|
|
||||||
}
|
|
||||||
_onFieldChange(selectedId!);
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -185,23 +216,22 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
|
|||||||
child: Davi<FormDataModel>(daviModelRows),
|
child: Davi<FormDataModel>(daviModelRows),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
kVSpacer20,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 30),
|
padding: const EdgeInsets.only(bottom: 5),
|
||||||
child: ElevatedButton.icon(
|
child: ElevatedButton.icon(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
formRows.add(kFormDataEmptyModel);
|
||||||
rows.add(kFormDataEmptyModel);
|
|
||||||
});
|
|
||||||
_onFieldChange(selectedId!);
|
_onFieldChange(selectedId!);
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
label: const Text(
|
label: const Text(
|
||||||
"Add Form Data",
|
kLabelAddFormField,
|
||||||
style: kTextStyleButton,
|
style: kTextStyleButton,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -210,11 +240,4 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onFieldChange(String selectedId) {
|
|
||||||
ref.read(collectionStateNotifierProvider.notifier).update(
|
|
||||||
selectedId,
|
|
||||||
requestFormDataList: rows,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,11 @@ class EditRequestHeaders extends ConsumerStatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
||||||
final random = Random.secure();
|
|
||||||
late List<NameValueModel> rows;
|
|
||||||
late List<bool> isRowEnabledList;
|
|
||||||
late int seed;
|
late int seed;
|
||||||
|
final random = Random.secure();
|
||||||
|
late List<NameValueModel> headerRows;
|
||||||
|
late List<bool> isRowEnabledList;
|
||||||
|
bool isAddingRow = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -29,8 +30,9 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
|||||||
void _onFieldChange(String selectedId) {
|
void _onFieldChange(String selectedId) {
|
||||||
ref.read(collectionStateNotifierProvider.notifier).update(
|
ref.read(collectionStateNotifierProvider.notifier).update(
|
||||||
selectedId,
|
selectedId,
|
||||||
requestHeaders: rows,
|
requestHeaders: headerRows.sublist(0, headerRows.length - 1),
|
||||||
isHeaderEnabledList: isRowEnabledList,
|
isHeaderEnabledList:
|
||||||
|
isRowEnabledList.sublist(0, headerRows.length - 1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,27 +42,34 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
|||||||
ref.watch(selectedRequestModelProvider
|
ref.watch(selectedRequestModelProvider
|
||||||
.select((value) => value?.requestHeaders?.length));
|
.select((value) => value?.requestHeaders?.length));
|
||||||
var rH = ref.read(selectedRequestModelProvider)?.requestHeaders;
|
var rH = ref.read(selectedRequestModelProvider)?.requestHeaders;
|
||||||
rows = (rH == null || rH.isEmpty)
|
bool isHeadersEmpty = rH == null || rH.isEmpty;
|
||||||
|
List<NameValueModel> rows = (isHeadersEmpty)
|
||||||
? [
|
? [
|
||||||
kNameValueEmptyModel,
|
kNameValueEmptyModel,
|
||||||
]
|
]
|
||||||
: rH;
|
: rH;
|
||||||
|
headerRows = isHeadersEmpty ? rows : rows + [kNameValueEmptyModel];
|
||||||
isRowEnabledList =
|
isRowEnabledList =
|
||||||
ref.read(selectedRequestModelProvider)?.isHeaderEnabledList ??
|
ref.read(selectedRequestModelProvider)?.isHeaderEnabledList ??
|
||||||
List.filled(rows.length, true, growable: true);
|
List.filled(rH?.length ?? 0, true, growable: true);
|
||||||
|
isRowEnabledList.add(false);
|
||||||
|
isAddingRow = false;
|
||||||
|
|
||||||
DaviModel<NameValueModel> model = DaviModel<NameValueModel>(
|
DaviModel<NameValueModel> model = DaviModel<NameValueModel>(
|
||||||
rows: rows,
|
rows: headerRows,
|
||||||
columns: [
|
columns: [
|
||||||
DaviColumn(
|
DaviColumn(
|
||||||
name: 'Checkbox',
|
name: kNameCheckbox,
|
||||||
width: 30,
|
width: 30,
|
||||||
cellBuilder: (_, row) {
|
cellBuilder: (_, row) {
|
||||||
int idx = row.index;
|
int idx = row.index;
|
||||||
|
bool isLast = idx + 1 == headerRows.length;
|
||||||
return CheckBox(
|
return CheckBox(
|
||||||
keyId: "$selectedId-$idx-headers-c-$seed",
|
keyId: "$selectedId-$idx-headers-c-$seed",
|
||||||
value: isRowEnabledList[idx],
|
value: isRowEnabledList[idx],
|
||||||
onChanged: (value) {
|
onChanged: isLast
|
||||||
|
? null
|
||||||
|
: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
isRowEnabledList[idx] = value!;
|
isRowEnabledList[idx] = value!;
|
||||||
});
|
});
|
||||||
@ -71,17 +80,24 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
DaviColumn(
|
DaviColumn(
|
||||||
name: 'Header Name',
|
name: kNameHeader,
|
||||||
width: 70,
|
width: 70,
|
||||||
grow: 1,
|
grow: 1,
|
||||||
cellBuilder: (_, row) {
|
cellBuilder: (_, row) {
|
||||||
int idx = row.index;
|
int idx = row.index;
|
||||||
|
bool isLast = idx + 1 == headerRows.length;
|
||||||
return HeaderField(
|
return HeaderField(
|
||||||
keyId: "$selectedId-$idx-headers-k-$seed",
|
keyId: "$selectedId-$idx-headers-k-$seed",
|
||||||
initialValue: rows[idx].name,
|
initialValue: headerRows[idx].name,
|
||||||
hintText: "Add Header Name",
|
hintText: kHintAddName,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
rows[idx] = rows[idx].copyWith(name: value);
|
headerRows[idx] = headerRows[idx].copyWith(name: value);
|
||||||
|
if (isLast && !isAddingRow) {
|
||||||
|
isAddingRow = true;
|
||||||
|
isRowEnabledList[idx] = true;
|
||||||
|
headerRows.add(kNameValueEmptyModel);
|
||||||
|
isRowEnabledList.add(false);
|
||||||
|
}
|
||||||
_onFieldChange(selectedId!);
|
_onFieldChange(selectedId!);
|
||||||
},
|
},
|
||||||
colorScheme: Theme.of(context).colorScheme,
|
colorScheme: Theme.of(context).colorScheme,
|
||||||
@ -99,16 +115,23 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
DaviColumn(
|
DaviColumn(
|
||||||
name: 'Header Value',
|
name: kNameValue,
|
||||||
grow: 1,
|
grow: 1,
|
||||||
cellBuilder: (_, row) {
|
cellBuilder: (_, row) {
|
||||||
int idx = row.index;
|
int idx = row.index;
|
||||||
|
bool isLast = idx + 1 == headerRows.length;
|
||||||
return CellField(
|
return CellField(
|
||||||
keyId: "$selectedId-$idx-headers-v-$seed",
|
keyId: "$selectedId-$idx-headers-v-$seed",
|
||||||
initialValue: rows[idx].value,
|
initialValue: headerRows[idx].value,
|
||||||
hintText: " Add Header Value",
|
hintText: kHintAddValue,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
rows[idx] = rows[idx].copyWith(value: value);
|
headerRows[idx] = headerRows[idx].copyWith(value: value);
|
||||||
|
if (isLast && !isAddingRow) {
|
||||||
|
isAddingRow = true;
|
||||||
|
isRowEnabledList[idx] = true;
|
||||||
|
headerRows.add(kNameValueEmptyModel);
|
||||||
|
isRowEnabledList.add(false);
|
||||||
|
}
|
||||||
_onFieldChange(selectedId!);
|
_onFieldChange(selectedId!);
|
||||||
},
|
},
|
||||||
colorScheme: Theme.of(context).colorScheme,
|
colorScheme: Theme.of(context).colorScheme,
|
||||||
@ -120,25 +143,28 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
|||||||
pinStatus: PinStatus.none,
|
pinStatus: PinStatus.none,
|
||||||
width: 30,
|
width: 30,
|
||||||
cellBuilder: (_, row) {
|
cellBuilder: (_, row) {
|
||||||
|
bool isLast = row.index + 1 == headerRows.length;
|
||||||
return InkWell(
|
return InkWell(
|
||||||
child: Theme.of(context).brightness == Brightness.dark
|
onTap: isLast
|
||||||
? kIconRemoveDark
|
? null
|
||||||
: kIconRemoveLight,
|
: () {
|
||||||
onTap: () {
|
|
||||||
seed = random.nextInt(kRandMax);
|
seed = random.nextInt(kRandMax);
|
||||||
if (rows.length == 1) {
|
if (headerRows.length == 2) {
|
||||||
setState(() {
|
setState(() {
|
||||||
rows = [
|
headerRows = [
|
||||||
kNameValueEmptyModel,
|
kNameValueEmptyModel,
|
||||||
];
|
];
|
||||||
isRowEnabledList = [true];
|
isRowEnabledList = [false];
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
rows.removeAt(row.index);
|
headerRows.removeAt(row.index);
|
||||||
isRowEnabledList.removeAt(row.index);
|
isRowEnabledList.removeAt(row.index);
|
||||||
}
|
}
|
||||||
_onFieldChange(selectedId!);
|
_onFieldChange(selectedId!);
|
||||||
},
|
},
|
||||||
|
child: Theme.of(context).brightness == Brightness.dark
|
||||||
|
? kIconRemoveDark
|
||||||
|
: kIconRemoveLight,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -160,22 +186,23 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
|||||||
child: Davi<NameValueModel>(model),
|
child: Davi<NameValueModel>(model),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
kVSpacer40,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 30),
|
padding: kPb15,
|
||||||
child: ElevatedButton.icon(
|
child: ElevatedButton.icon(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
rows.add(kNameValueEmptyModel);
|
headerRows.add(kNameValueEmptyModel);
|
||||||
isRowEnabledList.add(true);
|
isRowEnabledList.add(false);
|
||||||
_onFieldChange(selectedId!);
|
_onFieldChange(selectedId!);
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
label: const Text(
|
label: const Text(
|
||||||
"Add Header",
|
kLabelAddHeader,
|
||||||
style: kTextStyleButton,
|
style: kTextStyleButton,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -16,10 +16,11 @@ class EditRequestURLParams extends ConsumerStatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
||||||
final random = Random.secure();
|
|
||||||
late List<NameValueModel> rows;
|
|
||||||
late List<bool> isRowEnabledList;
|
|
||||||
late int seed;
|
late int seed;
|
||||||
|
final random = Random.secure();
|
||||||
|
late List<NameValueModel> paramRows;
|
||||||
|
late List<bool> isRowEnabledList;
|
||||||
|
bool isAddingRow = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -30,8 +31,8 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
|||||||
void _onFieldChange(String selectedId) {
|
void _onFieldChange(String selectedId) {
|
||||||
ref.read(collectionStateNotifierProvider.notifier).update(
|
ref.read(collectionStateNotifierProvider.notifier).update(
|
||||||
selectedId,
|
selectedId,
|
||||||
requestParams: rows,
|
requestParams: paramRows.sublist(0, paramRows.length - 1),
|
||||||
isParamEnabledList: isRowEnabledList,
|
isParamEnabledList: isRowEnabledList.sublist(0, paramRows.length - 1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,27 +42,34 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
|||||||
ref.watch(selectedRequestModelProvider
|
ref.watch(selectedRequestModelProvider
|
||||||
.select((value) => value?.requestParams?.length));
|
.select((value) => value?.requestParams?.length));
|
||||||
var rP = ref.read(selectedRequestModelProvider)?.requestParams;
|
var rP = ref.read(selectedRequestModelProvider)?.requestParams;
|
||||||
rows = (rP == null || rP.isEmpty)
|
bool isParamsEmpty = rP == null || rP.isEmpty;
|
||||||
|
List<NameValueModel> rows = (isParamsEmpty)
|
||||||
? [
|
? [
|
||||||
kNameValueEmptyModel,
|
kNameValueEmptyModel,
|
||||||
]
|
]
|
||||||
: rP;
|
: rP;
|
||||||
|
paramRows = isParamsEmpty ? rows : rows + [kNameValueEmptyModel];
|
||||||
isRowEnabledList =
|
isRowEnabledList =
|
||||||
ref.read(selectedRequestModelProvider)?.isParamEnabledList ??
|
ref.read(selectedRequestModelProvider)?.isParamEnabledList ??
|
||||||
List.filled(rows.length, true, growable: true);
|
List.filled(rP?.length ?? 0, true, growable: true);
|
||||||
|
isRowEnabledList.add(false);
|
||||||
|
isAddingRow = false;
|
||||||
|
|
||||||
DaviModel<NameValueModel> model = DaviModel<NameValueModel>(
|
DaviModel<NameValueModel> model = DaviModel<NameValueModel>(
|
||||||
rows: rows,
|
rows: paramRows,
|
||||||
columns: [
|
columns: [
|
||||||
DaviColumn(
|
DaviColumn(
|
||||||
name: 'Checkbox',
|
name: kNameCheckbox,
|
||||||
width: 30,
|
width: 30,
|
||||||
cellBuilder: (_, row) {
|
cellBuilder: (_, row) {
|
||||||
int idx = row.index;
|
int idx = row.index;
|
||||||
|
bool isLast = idx + 1 == paramRows.length;
|
||||||
return CheckBox(
|
return CheckBox(
|
||||||
keyId: "$selectedId-$idx-params-c-$seed",
|
keyId: "$selectedId-$idx-params-c-$seed",
|
||||||
value: isRowEnabledList[idx],
|
value: isRowEnabledList[idx],
|
||||||
onChanged: (value) {
|
onChanged: isLast
|
||||||
|
? null
|
||||||
|
: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
isRowEnabledList[idx] = value!;
|
isRowEnabledList[idx] = value!;
|
||||||
});
|
});
|
||||||
@ -72,17 +80,24 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
DaviColumn(
|
DaviColumn(
|
||||||
name: 'URL Parameter',
|
name: kNameURLParam,
|
||||||
width: 70,
|
width: 70,
|
||||||
grow: 1,
|
grow: 1,
|
||||||
cellBuilder: (_, row) {
|
cellBuilder: (_, row) {
|
||||||
int idx = row.index;
|
int idx = row.index;
|
||||||
|
bool isLast = idx + 1 == paramRows.length;
|
||||||
return CellField(
|
return CellField(
|
||||||
keyId: "$selectedId-$idx-params-k-$seed",
|
keyId: "$selectedId-$idx-params-k-$seed",
|
||||||
initialValue: rows[idx].name,
|
initialValue: paramRows[idx].name,
|
||||||
hintText: "Add URL Parameter",
|
hintText: kHintAddURLParam,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
rows[idx] = rows[idx].copyWith(name: value);
|
paramRows[idx] = paramRows[idx].copyWith(name: value);
|
||||||
|
if (isLast && !isAddingRow) {
|
||||||
|
isAddingRow = true;
|
||||||
|
isRowEnabledList[idx] = true;
|
||||||
|
paramRows.add(kNameValueEmptyModel);
|
||||||
|
isRowEnabledList.add(false);
|
||||||
|
}
|
||||||
_onFieldChange(selectedId!);
|
_onFieldChange(selectedId!);
|
||||||
},
|
},
|
||||||
colorScheme: Theme.of(context).colorScheme,
|
colorScheme: Theme.of(context).colorScheme,
|
||||||
@ -100,16 +115,23 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
DaviColumn(
|
DaviColumn(
|
||||||
name: 'Value',
|
name: kNameValue,
|
||||||
grow: 1,
|
grow: 1,
|
||||||
cellBuilder: (_, row) {
|
cellBuilder: (_, row) {
|
||||||
int idx = row.index;
|
int idx = row.index;
|
||||||
|
bool isLast = idx + 1 == paramRows.length;
|
||||||
return CellField(
|
return CellField(
|
||||||
keyId: "$selectedId-$idx-params-v-$seed",
|
keyId: "$selectedId-$idx-params-v-$seed",
|
||||||
initialValue: rows[idx].value,
|
initialValue: paramRows[idx].value,
|
||||||
hintText: "Add Value",
|
hintText: kHintAddValue,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
rows[idx] = rows[idx].copyWith(value: value);
|
paramRows[idx] = paramRows[idx].copyWith(value: value);
|
||||||
|
if (isLast && !isAddingRow) {
|
||||||
|
isAddingRow = true;
|
||||||
|
isRowEnabledList[idx] = true;
|
||||||
|
paramRows.add(kNameValueEmptyModel);
|
||||||
|
isRowEnabledList.add(false);
|
||||||
|
}
|
||||||
_onFieldChange(selectedId!);
|
_onFieldChange(selectedId!);
|
||||||
},
|
},
|
||||||
colorScheme: Theme.of(context).colorScheme,
|
colorScheme: Theme.of(context).colorScheme,
|
||||||
@ -121,25 +143,28 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
|||||||
pinStatus: PinStatus.none,
|
pinStatus: PinStatus.none,
|
||||||
width: 30,
|
width: 30,
|
||||||
cellBuilder: (_, row) {
|
cellBuilder: (_, row) {
|
||||||
|
bool isLast = row.index + 1 == paramRows.length;
|
||||||
return InkWell(
|
return InkWell(
|
||||||
child: Theme.of(context).brightness == Brightness.dark
|
onTap: isLast
|
||||||
? kIconRemoveDark
|
? null
|
||||||
: kIconRemoveLight,
|
: () {
|
||||||
onTap: () {
|
|
||||||
seed = random.nextInt(kRandMax);
|
seed = random.nextInt(kRandMax);
|
||||||
if (rows.length == 1) {
|
if (paramRows.length == 2) {
|
||||||
setState(() {
|
setState(() {
|
||||||
rows = [
|
paramRows = [
|
||||||
kNameValueEmptyModel,
|
kNameValueEmptyModel,
|
||||||
];
|
];
|
||||||
isRowEnabledList = [true];
|
isRowEnabledList = [false];
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
rows.removeAt(row.index);
|
paramRows.removeAt(row.index);
|
||||||
isRowEnabledList.removeAt(row.index);
|
isRowEnabledList.removeAt(row.index);
|
||||||
}
|
}
|
||||||
_onFieldChange(selectedId!);
|
_onFieldChange(selectedId!);
|
||||||
},
|
},
|
||||||
|
child: Theme.of(context).brightness == Brightness.dark
|
||||||
|
? kIconRemoveDark
|
||||||
|
: kIconRemoveLight,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -161,22 +186,23 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
|||||||
child: Davi<NameValueModel>(model),
|
child: Davi<NameValueModel>(model),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
kVSpacer40,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 30),
|
padding: kPb15,
|
||||||
child: ElevatedButton.icon(
|
child: ElevatedButton.icon(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
rows.add(kNameValueEmptyModel);
|
paramRows.add(kNameValueEmptyModel);
|
||||||
isRowEnabledList.add(true);
|
isRowEnabledList.add(false);
|
||||||
_onFieldChange(selectedId!);
|
_onFieldChange(selectedId!);
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
label: const Text(
|
label: const Text(
|
||||||
"Add Param",
|
kLabelAddParam,
|
||||||
style: kTextStyleButton,
|
style: kTextStyleButton,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -39,7 +39,6 @@ class ResponseDetails extends ConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
var sm = ScaffoldMessenger.of(context);
|
|
||||||
final responseStatus = ref.watch(
|
final responseStatus = ref.watch(
|
||||||
selectedRequestModelProvider.select((value) => value?.responseStatus));
|
selectedRequestModelProvider.select((value) => value?.responseStatus));
|
||||||
final message = ref
|
final message = ref
|
||||||
@ -57,8 +56,6 @@ class ResponseDetails extends ConsumerWidget {
|
|||||||
ref
|
ref
|
||||||
.read(collectionStateNotifierProvider.notifier)
|
.read(collectionStateNotifierProvider.notifier)
|
||||||
.clearResponse(selectedRequest?.id);
|
.clearResponse(selectedRequest?.id);
|
||||||
sm.hideCurrentSnackBar();
|
|
||||||
sm.showSnackBar(getSnackBar('Response cleared'));
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Expanded(
|
const Expanded(
|
||||||
|
@ -246,15 +246,12 @@ class ClearResponseButton extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Tooltip(
|
return IconButton(
|
||||||
message: 'Clear response',
|
tooltip: kTooltipClearResponse,
|
||||||
child: TextButton(
|
|
||||||
style: TextButton.styleFrom(minimumSize: const Size(40, 40)),
|
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
child: const Icon(
|
icon: const Icon(
|
||||||
Icons.delete,
|
Icons.delete,
|
||||||
size: 20,
|
size: 16,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||||||
class CheckBox extends StatelessWidget {
|
class CheckBox extends StatelessWidget {
|
||||||
final String keyId;
|
final String keyId;
|
||||||
final bool value;
|
final bool value;
|
||||||
final ValueChanged<bool?> onChanged;
|
final ValueChanged<bool?>? onChanged;
|
||||||
final ColorScheme? colorScheme;
|
final ColorScheme? colorScheme;
|
||||||
const CheckBox({
|
const CheckBox({
|
||||||
super.key,
|
super.key,
|
||||||
|
@ -157,6 +157,7 @@ class DropdownButtonCodegenLanguage extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final surfaceColor = Theme.of(context).colorScheme.surface;
|
final surfaceColor = Theme.of(context).colorScheme.surface;
|
||||||
return DropdownButton<CodegenLanguage>(
|
return DropdownButton<CodegenLanguage>(
|
||||||
|
isExpanded: true,
|
||||||
focusColor: surfaceColor,
|
focusColor: surfaceColor,
|
||||||
value: codegenLanguage,
|
value: codegenLanguage,
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
@ -181,6 +182,8 @@ class DropdownButtonCodegenLanguage extends StatelessWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
value.label,
|
value.label,
|
||||||
style: kTextStyleButton,
|
style: kTextStyleButton,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
maxLines: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -48,16 +48,12 @@ class _RequestPaneState extends State<RequestPane>
|
|||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: kPh20v10,
|
padding: kP8,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: kHeaderHeight,
|
height: kHeaderHeight,
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
|
||||||
"Request",
|
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
FilledButton.tonalIcon(
|
FilledButton.tonalIcon(
|
||||||
onPressed: widget.onPressedCodeButton,
|
onPressed: widget.onPressedCodeButton,
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
@ -68,7 +64,8 @@ class _RequestPaneState extends State<RequestPane>
|
|||||||
label: SizedBox(
|
label: SizedBox(
|
||||||
width: 75,
|
width: 75,
|
||||||
child: Text(
|
child: Text(
|
||||||
widget.codePaneVisible ? "Hide Code" : "View Code"),
|
widget.codePaneVisible ? kLabelHideCode : kLabelViewCode,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -79,18 +76,19 @@ class _RequestPaneState extends State<RequestPane>
|
|||||||
key: Key(widget.selectedId!),
|
key: Key(widget.selectedId!),
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
overlayColor: kColorTransparentState,
|
overlayColor: kColorTransparentState,
|
||||||
|
labelPadding: kPh2,
|
||||||
onTap: widget.onTapTabBar,
|
onTap: widget.onTapTabBar,
|
||||||
tabs: [
|
tabs: [
|
||||||
TabLabel(
|
TabLabel(
|
||||||
text: 'URL Params',
|
text: kLabelURLParams,
|
||||||
showIndicator: widget.showIndicators[0],
|
showIndicator: widget.showIndicators[0],
|
||||||
),
|
),
|
||||||
TabLabel(
|
TabLabel(
|
||||||
text: 'Headers',
|
text: kLabelHeaders,
|
||||||
showIndicator: widget.showIndicators[1],
|
showIndicator: widget.showIndicators[1],
|
||||||
),
|
),
|
||||||
TabLabel(
|
TabLabel(
|
||||||
text: 'Body',
|
text: kLabelBody,
|
||||||
showIndicator: widget.showIndicators[2],
|
showIndicator: widget.showIndicators[2],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -25,11 +25,9 @@ class NotSentWidget extends StatelessWidget {
|
|||||||
color: color,
|
color: color,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Not Sent',
|
kLabelNotSent,
|
||||||
style: Theme.of(context)
|
style:
|
||||||
.textTheme
|
Theme.of(context).textTheme.titleMedium?.copyWith(color: color),
|
||||||
.titleMedium
|
|
||||||
?.copyWith(color: color),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -123,42 +121,19 @@ class ResponsePaneHeader extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: kPh20v10,
|
padding: kPv8,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: kHeaderHeight,
|
height: kHeaderHeight,
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text.rich(
|
kHSpacer10,
|
||||||
TextSpan(
|
|
||||||
children: [
|
|
||||||
const TextSpan(
|
|
||||||
text: "Response (",
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
text: "$responseStatus",
|
|
||||||
style: TextStyle(
|
|
||||||
color: getResponseStatusCodeColor(
|
|
||||||
responseStatus,
|
|
||||||
brightness: Theme.of(context).brightness,
|
|
||||||
),
|
|
||||||
fontFamily: kCodeStyle.fontFamily,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const TextSpan(
|
|
||||||
text: ")",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
kHSpacer20,
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
message ?? "",
|
"$responseStatus: ${message ?? '-'}",
|
||||||
softWrap: false,
|
softWrap: false,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: Theme.of(context).textTheme.titleMedium!.copyWith(
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
fontFamily: kCodeStyle.fontFamily,
|
fontFamily: kCodeStyle.fontFamily,
|
||||||
color: getResponseStatusCodeColor(
|
color: getResponseStatusCodeColor(
|
||||||
responseStatus,
|
responseStatus,
|
||||||
@ -167,10 +142,10 @@ class ResponsePaneHeader extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
kHSpacer20,
|
kHSpacer10,
|
||||||
Text(
|
Text(
|
||||||
humanizeDuration(time),
|
humanizeDuration(time),
|
||||||
style: Theme.of(context).textTheme.titleMedium!.copyWith(
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
fontFamily: kCodeStyle.fontFamily,
|
fontFamily: kCodeStyle.fontFamily,
|
||||||
color: Theme.of(context).colorScheme.secondary,
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
),
|
),
|
||||||
@ -220,31 +195,15 @@ class _ResponseTabViewState extends State<ResponseTabView>
|
|||||||
TabBar(
|
TabBar(
|
||||||
key: Key(widget.selectedId!),
|
key: Key(widget.selectedId!),
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
|
labelPadding: kPh2,
|
||||||
overlayColor: kColorTransparentState,
|
overlayColor: kColorTransparentState,
|
||||||
onTap: (index) {},
|
onTap: (index) {},
|
||||||
tabs: const [
|
tabs: const [
|
||||||
SizedBox(
|
TabLabel(
|
||||||
height: kTabHeight,
|
text: kLabelResponseBody,
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
'Body',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
overflow: TextOverflow.fade,
|
|
||||||
softWrap: false,
|
|
||||||
style: kTextStyleButton,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: kTabHeight,
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
'Headers',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
overflow: TextOverflow.fade,
|
|
||||||
style: kTextStyleButton,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
TabLabel(
|
||||||
|
text: kLabelHeaders,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -284,8 +243,8 @@ class ResponseHeadersHeader extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
"$name (${map.length} items)",
|
"$name (${map.length} $kLabelItems)",
|
||||||
style: Theme.of(context).textTheme.labelLarge!.copyWith(
|
style: Theme.of(context).textTheme.labelMedium?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -300,8 +259,6 @@ class ResponseHeadersHeader extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const kHeaderRow = ["Header Name", "Header Value"];
|
|
||||||
|
|
||||||
class ResponseHeaders extends StatelessWidget {
|
class ResponseHeaders extends StatelessWidget {
|
||||||
const ResponseHeaders({
|
const ResponseHeaders({
|
||||||
super.key,
|
super.key,
|
||||||
@ -320,7 +277,7 @@ class ResponseHeaders extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
ResponseHeadersHeader(
|
ResponseHeadersHeader(
|
||||||
map: responseHeaders,
|
map: responseHeaders,
|
||||||
name: "Response Headers",
|
name: kLabelResponseHeaders,
|
||||||
),
|
),
|
||||||
if (responseHeaders.isNotEmpty) kVSpacer5,
|
if (responseHeaders.isNotEmpty) kVSpacer5,
|
||||||
if (responseHeaders.isNotEmpty)
|
if (responseHeaders.isNotEmpty)
|
||||||
@ -332,7 +289,7 @@ class ResponseHeaders extends StatelessWidget {
|
|||||||
kVSpacer10,
|
kVSpacer10,
|
||||||
ResponseHeadersHeader(
|
ResponseHeadersHeader(
|
||||||
map: requestHeaders,
|
map: requestHeaders,
|
||||||
name: "Request Headers",
|
name: kLabelRequestHeaders,
|
||||||
),
|
),
|
||||||
if (requestHeaders.isNotEmpty) kVSpacer5,
|
if (requestHeaders.isNotEmpty) kVSpacer5,
|
||||||
if (requestHeaders.isNotEmpty)
|
if (requestHeaders.isNotEmpty)
|
||||||
@ -359,20 +316,18 @@ class ResponseBody extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final responseModel = selectedRequestModel?.responseModel;
|
final responseModel = selectedRequestModel?.responseModel;
|
||||||
if (responseModel == null) {
|
if (responseModel == null) {
|
||||||
return const ErrorMessage(
|
return const ErrorMessage(message: '$kMsgError $kUnexpectedRaiseIssue');
|
||||||
message:
|
|
||||||
'Error: Response data does not exist. $kUnexpectedRaiseIssue');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var body = responseModel.body;
|
var body = responseModel.body;
|
||||||
var formattedBody = responseModel.formattedBody;
|
var formattedBody = responseModel.formattedBody;
|
||||||
if (body == null) {
|
if (body == null) {
|
||||||
return const ErrorMessage(
|
return const ErrorMessage(
|
||||||
message: 'Response body is missing (null). $kUnexpectedRaiseIssue');
|
message: '$kMsgNullBody $kUnexpectedRaiseIssue');
|
||||||
}
|
}
|
||||||
if (body.isEmpty) {
|
if (body.isEmpty) {
|
||||||
return const ErrorMessage(
|
return const ErrorMessage(
|
||||||
message: 'No content',
|
message: kMsgNoContent,
|
||||||
showIcon: false,
|
showIcon: false,
|
||||||
showIssueButton: false,
|
showIssueButton: false,
|
||||||
);
|
);
|
||||||
@ -382,7 +337,7 @@ class ResponseBody extends StatelessWidget {
|
|||||||
if (mediaType == null) {
|
if (mediaType == null) {
|
||||||
return ErrorMessage(
|
return ErrorMessage(
|
||||||
message:
|
message:
|
||||||
'Unknown Response Content-Type - ${responseModel.contentType}. $kUnexpectedRaiseIssue');
|
'$kMsgUnknowContentType - ${responseModel.contentType}. $kUnexpectedRaiseIssue');
|
||||||
}
|
}
|
||||||
|
|
||||||
var responseBodyView = getResponseBodyViewOptions(mediaType);
|
var responseBodyView = getResponseBodyViewOptions(mediaType);
|
||||||
|
@ -2,7 +2,11 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:apidash/consts.dart';
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
class TabLabel extends StatelessWidget {
|
class TabLabel extends StatelessWidget {
|
||||||
const TabLabel({super.key, required this.text, this.showIndicator = false});
|
const TabLabel({
|
||||||
|
super.key,
|
||||||
|
required this.text,
|
||||||
|
this.showIndicator = false,
|
||||||
|
});
|
||||||
final String text;
|
final String text;
|
||||||
final bool showIndicator;
|
final bool showIndicator;
|
||||||
|
|
||||||
@ -18,14 +22,14 @@ class TabLabel extends StatelessWidget {
|
|||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
overflow: TextOverflow.fade,
|
overflow: TextOverflow.fade,
|
||||||
softWrap: false,
|
softWrap: false,
|
||||||
style: kTextStyleButton,
|
style: kTextStyleTab,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (showIndicator)
|
if (showIndicator)
|
||||||
const Align(
|
const Align(
|
||||||
alignment: Alignment.topCenter,
|
alignment: Alignment.topCenter,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(top: 6),
|
padding: EdgeInsets.only(top: 1),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.circle,
|
Icons.circle,
|
||||||
size: 6,
|
size: 6,
|
||||||
|
@ -94,14 +94,39 @@ class JsonSearchField extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return TextField(
|
return RawTextField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
style: kCodeStyle,
|
style: kCodeStyle,
|
||||||
decoration: const InputDecoration(
|
hintText: 'Search..',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RawTextField extends StatelessWidget {
|
||||||
|
const RawTextField({
|
||||||
|
super.key,
|
||||||
|
this.onChanged,
|
||||||
|
this.controller,
|
||||||
|
this.hintText,
|
||||||
|
this.style,
|
||||||
|
});
|
||||||
|
|
||||||
|
final void Function(String)? onChanged;
|
||||||
|
final TextEditingController? controller;
|
||||||
|
final String? hintText;
|
||||||
|
final TextStyle? style;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return TextField(
|
||||||
|
controller: controller,
|
||||||
|
onChanged: onChanged,
|
||||||
|
style: style,
|
||||||
|
decoration: InputDecoration(
|
||||||
isDense: true,
|
isDense: true,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
hintText: 'Search..',
|
hintText: hintText,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
992
test/codegen/rust_curl_codegen_test.dart
Normal file
992
test/codegen/rust_curl_codegen_test.dart
Normal file
@ -0,0 +1,992 @@
|
|||||||
|
import 'package:apidash/codegen/codegen.dart';
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
import '../request_models.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
final codeGen = Codegen();
|
||||||
|
|
||||||
|
group('GET Request', () {
|
||||||
|
test('GET1', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev").unwrap();
|
||||||
|
easy.get(true).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelGet1, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('GET2', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev/country/data?code=US").unwrap();
|
||||||
|
easy.get(true).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelGet2, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('GET3', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev/country/data?code=IND").unwrap();
|
||||||
|
easy.get(true).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelGet3, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('GET4', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev/humanize/social?num=8700000&digits=3&system=SS&add_space=true&trailing_zeros=true").unwrap();
|
||||||
|
easy.get(true).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelGet4, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('GET5', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
use curl::easy::List;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.github.com/repos/foss42/apidash").unwrap();
|
||||||
|
easy.get(true).unwrap();
|
||||||
|
|
||||||
|
let mut list = List::new();
|
||||||
|
list.append("User-Agent: Test Agent").unwrap();
|
||||||
|
easy.http_headers(list).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelGet5, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('GET6', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
use curl::easy::List;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.github.com/repos/foss42/apidash?raw=true").unwrap();
|
||||||
|
easy.get(true).unwrap();
|
||||||
|
|
||||||
|
let mut list = List::new();
|
||||||
|
list.append("User-Agent: Test Agent").unwrap();
|
||||||
|
easy.http_headers(list).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelGet6, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('GET7', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev").unwrap();
|
||||||
|
easy.get(true).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelGet7, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('GET8', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
use curl::easy::List;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.github.com/repos/foss42/apidash?raw=true").unwrap();
|
||||||
|
easy.get(true).unwrap();
|
||||||
|
|
||||||
|
let mut list = List::new();
|
||||||
|
list.append("User-Agent: Test Agent").unwrap();
|
||||||
|
easy.http_headers(list).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelGet8, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('GET9', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev/humanize/social?num=8700000&add_space=true").unwrap();
|
||||||
|
easy.get(true).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelGet9, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('GET10', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
use curl::easy::List;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev/humanize/social").unwrap();
|
||||||
|
easy.get(true).unwrap();
|
||||||
|
|
||||||
|
let mut list = List::new();
|
||||||
|
list.append("User-Agent: Test Agent").unwrap();
|
||||||
|
easy.http_headers(list).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelGet10, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('GET11', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
use curl::easy::List;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev/humanize/social?num=8700000&digits=3").unwrap();
|
||||||
|
easy.get(true).unwrap();
|
||||||
|
|
||||||
|
let mut list = List::new();
|
||||||
|
list.append("User-Agent: Test Agent").unwrap();
|
||||||
|
easy.http_headers(list).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelGet11, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('GET12', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev/humanize/social").unwrap();
|
||||||
|
easy.get(true).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelGet12, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('HEAD Request', () {
|
||||||
|
test('HEAD1', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev").unwrap();
|
||||||
|
easy.nobody(true).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelHead1, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('HEAD2', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev").unwrap();
|
||||||
|
easy.nobody(true).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelHead2, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('POST Request', () {
|
||||||
|
test('POST1', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
use curl::easy::List;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev/case/lower").unwrap();
|
||||||
|
easy.post(true).unwrap();
|
||||||
|
|
||||||
|
easy.post_fields_copy(r#"{
|
||||||
|
"text": "I LOVE Flutter"
|
||||||
|
}"#.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
let mut list = List::new();
|
||||||
|
list.append("Content-Type: text/plain").unwrap();
|
||||||
|
easy.http_headers(list).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelPost1, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('POST2', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
use serde_json::json;
|
||||||
|
use curl::easy::List;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev/case/lower").unwrap();
|
||||||
|
easy.post(true).unwrap();
|
||||||
|
|
||||||
|
easy.post_fields_copy(json!({
|
||||||
|
"text": "I LOVE Flutter",
|
||||||
|
"flag": null,
|
||||||
|
"male": true,
|
||||||
|
"female": false,
|
||||||
|
"no": 1.2,
|
||||||
|
"arr": ["null", "true", "false", null]
|
||||||
|
}).to_string().as_bytes()).unwrap();
|
||||||
|
|
||||||
|
let mut list = List::new();
|
||||||
|
list.append("Content-Type: application/json").unwrap();
|
||||||
|
easy.http_headers(list).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelPost2, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('POST3', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
use serde_json::json;
|
||||||
|
use curl::easy::List;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev/case/lower").unwrap();
|
||||||
|
easy.post(true).unwrap();
|
||||||
|
|
||||||
|
easy.post_fields_copy(json!({
|
||||||
|
"text": "I LOVE Flutter"
|
||||||
|
}).to_string().as_bytes()).unwrap();
|
||||||
|
|
||||||
|
let mut list = List::new();
|
||||||
|
list.append("User-Agent: Test Agent").unwrap();
|
||||||
|
list.append("Content-Type: application/json").unwrap();
|
||||||
|
easy.http_headers(list).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelPost3, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('POST4', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev/io/form").unwrap();
|
||||||
|
easy.post(true).unwrap();
|
||||||
|
|
||||||
|
let mut form = curl::easy::Form::new();
|
||||||
|
|
||||||
|
form.part("text")
|
||||||
|
.contents(b"API")
|
||||||
|
.add().unwrap();
|
||||||
|
|
||||||
|
form.part("sep")
|
||||||
|
.contents(b"|")
|
||||||
|
.add().unwrap();
|
||||||
|
|
||||||
|
form.part("times")
|
||||||
|
.contents(b"3")
|
||||||
|
.add().unwrap();
|
||||||
|
|
||||||
|
easy.httppost(form).unwrap();
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelPost4, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('POST5', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
use curl::easy::List;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev/io/form").unwrap();
|
||||||
|
easy.post(true).unwrap();
|
||||||
|
|
||||||
|
let mut form = curl::easy::Form::new();
|
||||||
|
|
||||||
|
form.part("text")
|
||||||
|
.contents(b"API")
|
||||||
|
.add().unwrap();
|
||||||
|
|
||||||
|
form.part("sep")
|
||||||
|
.contents(b"|")
|
||||||
|
.add().unwrap();
|
||||||
|
|
||||||
|
form.part("times")
|
||||||
|
.contents(b"3")
|
||||||
|
.add().unwrap();
|
||||||
|
|
||||||
|
easy.httppost(form).unwrap();
|
||||||
|
let mut list = List::new();
|
||||||
|
list.append("User-Agent: Test Agent").unwrap();
|
||||||
|
easy.http_headers(list).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelPost5, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('POST6', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev/io/img").unwrap();
|
||||||
|
easy.post(true).unwrap();
|
||||||
|
|
||||||
|
let mut form = curl::easy::Form::new();
|
||||||
|
|
||||||
|
form.part("token")
|
||||||
|
.contents(b"xyz")
|
||||||
|
.add().unwrap();
|
||||||
|
|
||||||
|
form.part("imfile")
|
||||||
|
.file("/Documents/up/1.png")
|
||||||
|
.add().unwrap();
|
||||||
|
|
||||||
|
easy.httppost(form).unwrap();
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelPost6, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('POST7', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev/io/img").unwrap();
|
||||||
|
easy.post(true).unwrap();
|
||||||
|
|
||||||
|
let mut form = curl::easy::Form::new();
|
||||||
|
|
||||||
|
form.part("token")
|
||||||
|
.contents(b"xyz")
|
||||||
|
.add().unwrap();
|
||||||
|
|
||||||
|
form.part("imfile")
|
||||||
|
.file("/Documents/up/1.png")
|
||||||
|
.add().unwrap();
|
||||||
|
|
||||||
|
easy.httppost(form).unwrap();
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelPost7, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('POST8', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev/io/form?size=2&len=3").unwrap();
|
||||||
|
easy.post(true).unwrap();
|
||||||
|
|
||||||
|
let mut form = curl::easy::Form::new();
|
||||||
|
|
||||||
|
form.part("text")
|
||||||
|
.contents(b"API")
|
||||||
|
.add().unwrap();
|
||||||
|
|
||||||
|
form.part("sep")
|
||||||
|
.contents(b"|")
|
||||||
|
.add().unwrap();
|
||||||
|
|
||||||
|
form.part("times")
|
||||||
|
.contents(b"3")
|
||||||
|
.add().unwrap();
|
||||||
|
|
||||||
|
easy.httppost(form).unwrap();
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelPost8, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('POST9', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
use curl::easy::List;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://api.apidash.dev/io/img?size=2&len=3").unwrap();
|
||||||
|
easy.post(true).unwrap();
|
||||||
|
|
||||||
|
let mut form = curl::easy::Form::new();
|
||||||
|
|
||||||
|
form.part("token")
|
||||||
|
.contents(b"xyz")
|
||||||
|
.add().unwrap();
|
||||||
|
|
||||||
|
form.part("imfile")
|
||||||
|
.file("/Documents/up/1.png")
|
||||||
|
.add().unwrap();
|
||||||
|
|
||||||
|
easy.httppost(form).unwrap();
|
||||||
|
let mut list = List::new();
|
||||||
|
list.append("User-Agent: Test Agent").unwrap();
|
||||||
|
list.append("Keep-Alive: true").unwrap();
|
||||||
|
easy.http_headers(list).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelPost9, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('PUT Request', () {
|
||||||
|
test('PUT1', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
use serde_json::json;
|
||||||
|
use curl::easy::List;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://reqres.in/api/users/2").unwrap();
|
||||||
|
easy.put(true).unwrap();
|
||||||
|
|
||||||
|
easy.post_fields_copy(json!({
|
||||||
|
"name": "morpheus",
|
||||||
|
"job": "zion resident"
|
||||||
|
}).to_string().as_bytes()).unwrap();
|
||||||
|
|
||||||
|
let mut list = List::new();
|
||||||
|
list.append("Content-Type: application/json").unwrap();
|
||||||
|
easy.http_headers(list).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelPut1, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('PATCH Request', () {
|
||||||
|
test('PATCH1', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
use serde_json::json;
|
||||||
|
use curl::easy::List;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://reqres.in/api/users/2").unwrap();
|
||||||
|
easy.custom_request("PATCH").unwrap();
|
||||||
|
|
||||||
|
easy.post_fields_copy(json!({
|
||||||
|
"name": "marfeus",
|
||||||
|
"job": "accountant"
|
||||||
|
}).to_string().as_bytes()).unwrap();
|
||||||
|
|
||||||
|
let mut list = List::new();
|
||||||
|
list.append("Content-Type: application/json").unwrap();
|
||||||
|
easy.http_headers(list).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelPatch1, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('DELETE Request', () {
|
||||||
|
test('DELETE1', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://reqres.in/api/users/2").unwrap();
|
||||||
|
easy.custom_request("DELETE").unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelDelete1, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
test('DELETE2', () {
|
||||||
|
const expectedCode = r"""
|
||||||
|
use curl::easy::Easy;
|
||||||
|
use serde_json::json;
|
||||||
|
use curl::easy::List;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut easy = Easy::new();
|
||||||
|
let mut data = Vec::new();
|
||||||
|
easy.url("https://reqres.in/api/users/2").unwrap();
|
||||||
|
easy.custom_request("DELETE").unwrap();
|
||||||
|
|
||||||
|
easy.post_fields_copy(json!({
|
||||||
|
"name": "marfeus",
|
||||||
|
"job": "accountant"
|
||||||
|
}).to_string().as_bytes()).unwrap();
|
||||||
|
|
||||||
|
let mut list = List::new();
|
||||||
|
list.append("Content-Type: application/json").unwrap();
|
||||||
|
easy.http_headers(list).unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut transfer = easy.transfer();
|
||||||
|
transfer.write_function(|new_data| {
|
||||||
|
data.extend_from_slice(new_data);
|
||||||
|
Ok(new_data.len())
|
||||||
|
}).unwrap();
|
||||||
|
transfer.perform().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = String::from_utf8_lossy(&data);
|
||||||
|
|
||||||
|
println!("Response body: {}", response_body);
|
||||||
|
println!("Response code: {}", easy.response_code().unwrap());
|
||||||
|
}""";
|
||||||
|
expect(
|
||||||
|
codeGen.getCode(
|
||||||
|
CodegenLanguage.rustCurl, requestModelDelete2, "https"),
|
||||||
|
expectedCode);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
339
test/providers/ui_providers_test.dart
Normal file
339
test/providers/ui_providers_test.dart
Normal file
@ -0,0 +1,339 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:apidash/providers/providers.dart';
|
||||||
|
import 'package:apidash/screens/dashboard.dart';
|
||||||
|
import 'package:apidash/screens/home_page/collection_pane.dart';
|
||||||
|
import 'package:apidash/screens/home_page/home_page.dart';
|
||||||
|
import 'package:apidash/screens/intro_page.dart';
|
||||||
|
import 'package:apidash/screens/settings_page.dart';
|
||||||
|
import 'package:apidash/services/hive_services.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
setUp(() async {
|
||||||
|
const MethodChannel channel =
|
||||||
|
MethodChannel('plugins.flutter.io/path_provider');
|
||||||
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
||||||
|
.setMockMethodCallHandler(channel, (MethodCall methodCall) async {
|
||||||
|
if (methodCall.method == 'getApplicationDocumentsDirectory') {
|
||||||
|
// Create a mock app doc directory for testing
|
||||||
|
Directory tempDir =
|
||||||
|
await Directory.systemTemp.createTemp('mock_app_doc_dir');
|
||||||
|
return tempDir.path; // Return the path to the mock directory
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
await openBoxes();
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Testing navRailIndexStateProvider', () {
|
||||||
|
testWidgets('Dashboard should display correct initial page',
|
||||||
|
(tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const ProviderScope(
|
||||||
|
child: MaterialApp(
|
||||||
|
home: Dashboard(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify that the HomePage is displayed initially
|
||||||
|
expect(find.byType(HomePage), findsOneWidget);
|
||||||
|
expect(find.byType(IntroPage), findsNothing);
|
||||||
|
expect(find.byType(SettingsPage), findsNothing);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
"Dashboard should display IntroPage when navRailIndexStateProvider is 1",
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
ProviderScope(
|
||||||
|
overrides: [
|
||||||
|
navRailIndexStateProvider.overrideWith((ref) => 1),
|
||||||
|
],
|
||||||
|
child: const MaterialApp(
|
||||||
|
home: Dashboard(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify that the IntroPage is displayed
|
||||||
|
expect(find.byType(IntroPage), findsOneWidget);
|
||||||
|
expect(find.byType(HomePage), findsNothing);
|
||||||
|
expect(find.byType(SettingsPage), findsNothing);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
"Dashboard should display SettingsPage when navRailIndexStateProvider is 2",
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
ProviderScope(
|
||||||
|
overrides: [
|
||||||
|
navRailIndexStateProvider.overrideWith((ref) => 2),
|
||||||
|
],
|
||||||
|
child: const MaterialApp(
|
||||||
|
home: Dashboard(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify that the SettingsPage is displayed
|
||||||
|
expect(find.byType(SettingsPage), findsOneWidget);
|
||||||
|
expect(find.byType(IntroPage), findsNothing);
|
||||||
|
expect(find.byType(HomePage), findsNothing);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'navRailIndexStateProvider should update when icon button is pressed',
|
||||||
|
(tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const ProviderScope(
|
||||||
|
child: MaterialApp(
|
||||||
|
home: Dashboard(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Tap on the Intro icon
|
||||||
|
await tester.tap(find.byIcon(Icons.help_outline));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
// Verify that the navRailIndexStateProvider is updated
|
||||||
|
final dashboard = tester.element(find.byType(Dashboard));
|
||||||
|
final container = ProviderScope.containerOf(dashboard);
|
||||||
|
expect(container.read(navRailIndexStateProvider), 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'navRailIndexStateProvider should persist across widget rebuilds',
|
||||||
|
(tester) async {
|
||||||
|
// Pump the initial widget tree
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const ProviderScope(
|
||||||
|
child: MaterialApp(
|
||||||
|
home: Dashboard(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Tap on the Settings icon to change the index to 2
|
||||||
|
await tester.tap(find.byIcon(Icons.settings_outlined));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
// Rebuild the widget tree with the same ProviderScope
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const ProviderScope(
|
||||||
|
child: MaterialApp(
|
||||||
|
home: Dashboard(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify that the navRailIndexStateProvider still has the updated value
|
||||||
|
final dashboard = tester.element(find.byType(Dashboard));
|
||||||
|
final container = ProviderScope.containerOf(dashboard);
|
||||||
|
expect(container.read(navRailIndexStateProvider), 2);
|
||||||
|
|
||||||
|
// Verify that the SettingsPage is still displayed after the rebuild
|
||||||
|
expect(find.byType(SettingsPage), findsOneWidget);
|
||||||
|
expect(find.byType(IntroPage), findsNothing);
|
||||||
|
expect(find.byType(HomePage), findsNothing);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'UI should update correctly when navRailIndexStateProvider changes',
|
||||||
|
(tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const ProviderScope(
|
||||||
|
child: MaterialApp(
|
||||||
|
home: Dashboard(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Grab the Dashboard widget and its ProviderContainer
|
||||||
|
final dashboard = tester.element(find.byType(Dashboard));
|
||||||
|
final container = ProviderScope.containerOf(dashboard);
|
||||||
|
|
||||||
|
// Go to IntroPage
|
||||||
|
container.read(navRailIndexStateProvider.notifier).state = 1;
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
// Verify that the IntroPage is displayed
|
||||||
|
expect(find.byType(IntroPage), findsOneWidget);
|
||||||
|
// Verify that the selected icon is the filled version (selectedIcon)
|
||||||
|
expect(find.byIcon(Icons.help), findsOneWidget);
|
||||||
|
|
||||||
|
// Go to SettingsPage
|
||||||
|
container.read(navRailIndexStateProvider.notifier).state = 2;
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
// Verify that the SettingsPage is displayed
|
||||||
|
expect(find.byType(SettingsPage), findsOneWidget);
|
||||||
|
// Verify that the selected icon is the filled version (selectedIcon)
|
||||||
|
expect(find.byIcon(Icons.settings), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'navRailIndexStateProvider should be disposed when Dashboard is removed',
|
||||||
|
(tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const ProviderScope(
|
||||||
|
child: MaterialApp(
|
||||||
|
home: Dashboard(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Grab the Dashboard widget and its ProviderContainer
|
||||||
|
final dashboard = tester.element(find.byType(Dashboard));
|
||||||
|
final container = ProviderScope.containerOf(dashboard);
|
||||||
|
|
||||||
|
// Pumping a different widget to remove the Dashboard from the widget tree
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const MaterialApp(
|
||||||
|
home: Scaffold(body: Text('Different Widget')),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify that the ProviderContainer has been disposed
|
||||||
|
// by trying to read from disposed container
|
||||||
|
bool isDisposed = false;
|
||||||
|
try {
|
||||||
|
container.read(navRailIndexStateProvider);
|
||||||
|
} catch (e) {
|
||||||
|
isDisposed = true;
|
||||||
|
}
|
||||||
|
expect(isDisposed, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group("Testing selectedIdEditStateProvider", () {
|
||||||
|
testWidgets('It should have an initial value of null', (tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const ProviderScope(
|
||||||
|
child: MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: CollectionPane(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify that the initial value is null
|
||||||
|
final collectionPane = tester.element(find.byType(CollectionPane));
|
||||||
|
final container = ProviderScope.containerOf(collectionPane);
|
||||||
|
expect(container.read(selectedIdEditStateProvider), null);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'selectedIdEditStateProvider should not be null after rename button has been tapped',
|
||||||
|
(tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const ProviderScope(
|
||||||
|
child: MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: CollectionPane(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Tap on the three dots to open the request card menu
|
||||||
|
await tester.tap(find.byType(RequestList));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.tap(find.byType(RequestItem));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.tap(find.byIcon(Icons.more_vert).first);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Tap on the "Rename" option in the menu
|
||||||
|
await tester.tap(find.text('Rename'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Verify that the selectedIdEditStateProvider is not null
|
||||||
|
final collectionPane = tester.element(find.byType(CollectionPane));
|
||||||
|
final container = ProviderScope.containerOf(collectionPane);
|
||||||
|
expect(container.read(selectedIdEditStateProvider), isNotNull);
|
||||||
|
expect((container.read(selectedIdEditStateProvider)).runtimeType, String);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'It should be set back to null when user taps outside name editor',
|
||||||
|
(tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const ProviderScope(
|
||||||
|
child: MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: CollectionPane(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Grab the CollectionPane widget and its ProviderContainer
|
||||||
|
final collectionPane = tester.element(find.byType(CollectionPane));
|
||||||
|
final container = ProviderScope.containerOf(collectionPane);
|
||||||
|
|
||||||
|
// Tap on the three dots to open the request card menu
|
||||||
|
await tester.tap(find.byType(RequestList));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.tap(find.byType(RequestItem));
|
||||||
|
await tester.pump();
|
||||||
|
await tester.tap(find.byIcon(Icons.more_vert).first);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Tap on the "Rename" option in the menu
|
||||||
|
await tester.tap(find.text('Rename'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Verify that the selectedIdEditStateProvider is not null
|
||||||
|
expect(container.read(selectedIdEditStateProvider), isNotNull);
|
||||||
|
expect((container.read(selectedIdEditStateProvider)).runtimeType, String);
|
||||||
|
|
||||||
|
// Tap on the screen to simulate tapping outside the name editor
|
||||||
|
await tester.tap(find.byType(CollectionPane));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Verify that the selectedIdEditStateProvider is null
|
||||||
|
expect(container.read(selectedIdEditStateProvider), null);
|
||||||
|
});
|
||||||
|
testWidgets("It should be properly disposed", (tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const ProviderScope(
|
||||||
|
child: MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: CollectionPane(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Grab the Dashboard widget and its ProviderContainer
|
||||||
|
final collectionPane = tester.element(find.byType(CollectionPane));
|
||||||
|
final container = ProviderScope.containerOf(collectionPane);
|
||||||
|
|
||||||
|
// Pumping a different widget to remove the CollectionPane from the widget tree
|
||||||
|
await tester.pumpWidget(
|
||||||
|
const MaterialApp(
|
||||||
|
home: Scaffold(body: Text('Foo')),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify that the ProviderContainer has been disposed
|
||||||
|
// by trying to read from disposed container
|
||||||
|
bool isDisposed = false;
|
||||||
|
try {
|
||||||
|
container.read(selectedIdEditStateProvider);
|
||||||
|
} catch (e) {
|
||||||
|
isDisposed = true;
|
||||||
|
}
|
||||||
|
expect(isDisposed, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -21,7 +21,6 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(find.byType(Center), findsAtLeastNWidgets(1));
|
expect(find.byType(Center), findsAtLeastNWidgets(1));
|
||||||
expect(find.text('Request'), findsOneWidget);
|
|
||||||
expect(find.text('Hide Code'), findsOneWidget);
|
expect(find.text('Hide Code'), findsOneWidget);
|
||||||
expect(find.text('View Code'), findsNothing);
|
expect(find.text('View Code'), findsNothing);
|
||||||
expect(find.text('URL Params'), findsOneWidget);
|
expect(find.text('URL Params'), findsOneWidget);
|
||||||
@ -52,7 +51,6 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(find.byType(Center), findsAtLeastNWidgets(1));
|
expect(find.byType(Center), findsAtLeastNWidgets(1));
|
||||||
expect(find.text('Request'), findsOneWidget);
|
|
||||||
expect(find.text('Hide Code'), findsOneWidget);
|
expect(find.text('Hide Code'), findsOneWidget);
|
||||||
expect(find.text('View Code'), findsNothing);
|
expect(find.text('View Code'), findsNothing);
|
||||||
expect(find.text('URL Params'), findsOneWidget);
|
expect(find.text('URL Params'), findsOneWidget);
|
||||||
@ -83,7 +81,6 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(find.byType(Center), findsAtLeastNWidgets(1));
|
expect(find.byType(Center), findsAtLeastNWidgets(1));
|
||||||
expect(find.text('Request'), findsOneWidget);
|
|
||||||
expect(find.text('Hide Code'), findsNothing);
|
expect(find.text('Hide Code'), findsNothing);
|
||||||
expect(find.text('View Code'), findsOneWidget);
|
expect(find.text('View Code'), findsOneWidget);
|
||||||
expect(find.text('URL Params'), findsOneWidget);
|
expect(find.text('URL Params'), findsOneWidget);
|
||||||
@ -117,7 +114,6 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(find.byType(Center), findsAtLeastNWidgets(1));
|
expect(find.byType(Center), findsAtLeastNWidgets(1));
|
||||||
expect(find.text('Request'), findsOneWidget);
|
|
||||||
expect(find.text('URL Params'), findsOneWidget);
|
expect(find.text('URL Params'), findsOneWidget);
|
||||||
expect(find.text('Headers'), findsOneWidget);
|
expect(find.text('Headers'), findsOneWidget);
|
||||||
expect(find.text('Body'), findsOneWidget);
|
expect(find.text('Body'), findsOneWidget);
|
||||||
|
@ -75,11 +75,8 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(find.byType(RichText), findsAtLeastNWidgets(1));
|
|
||||||
expect(
|
|
||||||
find.textContaining("Response (", findRichText: true), findsOneWidget);
|
|
||||||
expect(find.text('Hi'), findsOneWidget);
|
|
||||||
expect(find.textContaining("200", findRichText: true), findsOneWidget);
|
expect(find.textContaining("200", findRichText: true), findsOneWidget);
|
||||||
|
expect(find.textContaining("Hi", findRichText: true), findsOneWidget);
|
||||||
expect(find.text(humanizeDuration(const Duration(microseconds: 23))),
|
expect(find.text(humanizeDuration(const Duration(microseconds: 23))),
|
||||||
findsOneWidget);
|
findsOneWidget);
|
||||||
});
|
});
|
||||||
@ -96,7 +93,7 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(find.text('Body'), findsOneWidget);
|
expect(find.text('Response Body'), findsOneWidget);
|
||||||
expect(find.text('Headers'), findsOneWidget);
|
expect(find.text('Headers'), findsOneWidget);
|
||||||
|
|
||||||
await tester.tap(find.text('Headers'));
|
await tester.tap(find.text('Headers'));
|
||||||
@ -104,7 +101,7 @@ void main() {
|
|||||||
|
|
||||||
expect(find.text('first'), findsNothing);
|
expect(find.text('first'), findsNothing);
|
||||||
expect(find.text('second'), findsOneWidget);
|
expect(find.text('second'), findsOneWidget);
|
||||||
await tester.tap(find.text('Body'));
|
await tester.tap(find.text('Response Body'));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(find.text('first'), findsOneWidget);
|
expect(find.text('first'), findsOneWidget);
|
||||||
|
Reference in New Issue
Block a user