mirror of
https://github.com/foss42/apidash.git
synced 2025-07-01 21:47:11 +08:00
Merge pull request #101 from vidya-hub/form_data_imp
Form-Data and multi-part request feature added
This commit is contained in:
@ -1,8 +1,8 @@
|
|||||||
import 'package:apidash/consts.dart';
|
import 'dart:convert';
|
||||||
import 'package:apidash/models/request_model.dart' show RequestModel;
|
|
||||||
import 'package:code_builder/code_builder.dart';
|
import 'package:code_builder/code_builder.dart';
|
||||||
import 'package:dart_style/dart_style.dart';
|
import 'package:dart_style/dart_style.dart';
|
||||||
|
import 'package:apidash/models/request_model.dart' show RequestModel;
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
import 'shared.dart';
|
import 'shared.dart';
|
||||||
|
|
||||||
class DartDioCodeGen {
|
class DartDioCodeGen {
|
||||||
@ -22,6 +22,7 @@ class DartDioCodeGen {
|
|||||||
headers: requestModel.enabledHeadersMap,
|
headers: requestModel.enabledHeadersMap,
|
||||||
body: requestModel.requestBody,
|
body: requestModel.requestBody,
|
||||||
contentType: requestModel.requestBodyContentType,
|
contentType: requestModel.requestBodyContentType,
|
||||||
|
formData: requestModel.formDataMapList,
|
||||||
);
|
);
|
||||||
return next;
|
return next;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -36,6 +37,7 @@ class DartDioCodeGen {
|
|||||||
required Map<String, String> headers,
|
required Map<String, String> headers,
|
||||||
required String? body,
|
required String? body,
|
||||||
required ContentType contentType,
|
required ContentType contentType,
|
||||||
|
required List<Map<String, dynamic>> formData,
|
||||||
}) {
|
}) {
|
||||||
final sbf = StringBuffer();
|
final sbf = StringBuffer();
|
||||||
final emitter = DartEmitter();
|
final emitter = DartEmitter();
|
||||||
@ -54,9 +56,22 @@ class DartDioCodeGen {
|
|||||||
literalMap(headers.map((key, value) => MapEntry(key, value))),
|
literalMap(headers.map((key, value) => MapEntry(key, value))),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
final multiPartList = Code('''
|
||||||
|
final List<Map<String,String>> formDataList = ${json.encode(formData)};
|
||||||
|
for (var formField in formDataList) {
|
||||||
|
if (formField['type'] == 'file') {
|
||||||
|
formData.files.add(MapEntry(
|
||||||
|
formField['name'],
|
||||||
|
await MultipartFile.fromFile(formField['value'], filename: formField['value']),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
formData.fields.add(MapEntry(formField['name'], formField['value']));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
Expression? dataExp;
|
Expression? dataExp;
|
||||||
if (kMethodsWithBody.contains(method) && (body?.isNotEmpty ?? false)) {
|
if ((kMethodsWithBody.contains(method) && (body?.isNotEmpty ?? false) ||
|
||||||
|
contentType == ContentType.formdata)) {
|
||||||
final strContent = CodeExpression(Code('r\'\'\'$body\'\'\''));
|
final strContent = CodeExpression(Code('r\'\'\'$body\'\'\''));
|
||||||
switch (contentType) {
|
switch (contentType) {
|
||||||
// dio dosen't need pass `content-type` header when body is json or plain text
|
// dio dosen't need pass `content-type` header when body is json or plain text
|
||||||
@ -68,6 +83,8 @@ class DartDioCodeGen {
|
|||||||
case ContentType.text:
|
case ContentType.text:
|
||||||
dataExp = declareFinal('data').assign(strContent);
|
dataExp = declareFinal('data').assign(strContent);
|
||||||
// when add new type of [ContentType], need update [dataExp].
|
// when add new type of [ContentType], need update [dataExp].
|
||||||
|
case ContentType.formdata:
|
||||||
|
dataExp = declareFinal('data').assign(refer('FormData()'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final responseExp = declareFinal('response').assign(InvokeExpression.newOf(
|
final responseExp = declareFinal('response').assign(InvokeExpression.newOf(
|
||||||
@ -93,6 +110,8 @@ class DartDioCodeGen {
|
|||||||
if (queryParamExp != null) queryParamExp,
|
if (queryParamExp != null) queryParamExp,
|
||||||
if (headerExp != null) headerExp,
|
if (headerExp != null) headerExp,
|
||||||
if (dataExp != null) dataExp,
|
if (dataExp != null) dataExp,
|
||||||
|
if ((contentType == ContentType.formdata && formData.isNotEmpty))
|
||||||
|
multiPartList,
|
||||||
responseExp,
|
responseExp,
|
||||||
refer('print').call([refer('response').property('statusCode')]),
|
refer('print').call([refer('response').property('statusCode')]),
|
||||||
refer('print').call([refer('response').property('data')]),
|
refer('print').call([refer('response').property('data')]),
|
||||||
@ -122,6 +141,8 @@ class DartDioCodeGen {
|
|||||||
|
|
||||||
sbf.writeln(mainFunction.accept(emitter));
|
sbf.writeln(mainFunction.accept(emitter));
|
||||||
|
|
||||||
return DartFormatter(pageWidth: 160).format(sbf.toString());
|
return DartFormatter(
|
||||||
|
pageWidth: contentType == ContentType.formdata ? 70 : 160)
|
||||||
|
.format(sbf.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:apidash/consts.dart';
|
|
||||||
import 'package:apidash/models/models.dart' show RequestModel;
|
|
||||||
import 'package:code_builder/code_builder.dart';
|
import 'package:code_builder/code_builder.dart';
|
||||||
import 'package:dart_style/dart_style.dart';
|
import 'package:dart_style/dart_style.dart';
|
||||||
|
import 'package:apidash/models/models.dart' show RequestModel;
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
import 'shared.dart';
|
import 'shared.dart';
|
||||||
|
|
||||||
class DartHttpCodeGen {
|
class DartHttpCodeGen {
|
||||||
@ -22,9 +21,10 @@ class DartHttpCodeGen {
|
|||||||
method: requestModel.method,
|
method: requestModel.method,
|
||||||
queryParams: requestModel.enabledParamsMap,
|
queryParams: requestModel.enabledParamsMap,
|
||||||
headers: {...requestModel.enabledHeadersMap},
|
headers: {...requestModel.enabledHeadersMap},
|
||||||
body: requestModel.requestBody,
|
|
||||||
contentType: requestModel.requestBodyContentType,
|
contentType: requestModel.requestBodyContentType,
|
||||||
hasContentTypeHeader: requestModel.hasContentTypeHeader,
|
hasContentTypeHeader: requestModel.hasContentTypeHeader,
|
||||||
|
body: requestModel.requestBody,
|
||||||
|
formData: requestModel.formDataMapList,
|
||||||
);
|
);
|
||||||
return next;
|
return next;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -37,9 +37,10 @@ class DartHttpCodeGen {
|
|||||||
required HTTPVerb method,
|
required HTTPVerb method,
|
||||||
required Map<String, String> queryParams,
|
required Map<String, String> queryParams,
|
||||||
required Map<String, String> headers,
|
required Map<String, String> headers,
|
||||||
required String? body,
|
|
||||||
required ContentType contentType,
|
required ContentType contentType,
|
||||||
|
required String? body,
|
||||||
required bool hasContentTypeHeader,
|
required bool hasContentTypeHeader,
|
||||||
|
required List<Map<String, dynamic>> formData,
|
||||||
}) {
|
}) {
|
||||||
final uri = Uri.parse(url);
|
final uri = Uri.parse(url);
|
||||||
|
|
||||||
@ -55,7 +56,6 @@ class DartHttpCodeGen {
|
|||||||
if (kMethodsWithBody.contains(method) && (body?.isNotEmpty ?? false)) {
|
if (kMethodsWithBody.contains(method) && (body?.isNotEmpty ?? false)) {
|
||||||
final strContent = CodeExpression(Code('r\'\'\'$body\'\'\''));
|
final strContent = CodeExpression(Code('r\'\'\'$body\'\'\''));
|
||||||
dataExp = declareVar('body', type: refer('String')).assign(strContent);
|
dataExp = declareVar('body', type: refer('String')).assign(strContent);
|
||||||
|
|
||||||
if (!hasContentTypeHeader) {
|
if (!hasContentTypeHeader) {
|
||||||
headers.putIfAbsent(HttpHeaders.contentTypeHeader,
|
headers.putIfAbsent(HttpHeaders.contentTypeHeader,
|
||||||
() => kContentTypeMap[contentType] ?? '');
|
() => kContentTypeMap[contentType] ?? '');
|
||||||
@ -102,7 +102,9 @@ class DartHttpCodeGen {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
final responseExp = declareFinal('response').assign(InvokeExpression.newOf(
|
final responseExp = declareFinal('response').assign(InvokeExpression.newOf(
|
||||||
refer('http.${method.name}'),
|
refer(
|
||||||
|
'http.${method.name}',
|
||||||
|
),
|
||||||
[refer('uri')],
|
[refer('uri')],
|
||||||
{
|
{
|
||||||
if (headerExp != null) 'headers': refer('headers'),
|
if (headerExp != null) 'headers': refer('headers'),
|
||||||
@ -110,7 +112,36 @@ class DartHttpCodeGen {
|
|||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
).awaited);
|
).awaited);
|
||||||
|
final multiPartRequest =
|
||||||
|
declareFinal('request').assign(InvokeExpression.newOf(
|
||||||
|
refer(
|
||||||
|
'http.MultipartRequest',
|
||||||
|
),
|
||||||
|
[refer(jsonEncode(method.name.toUpperCase())), refer('uri')],
|
||||||
|
));
|
||||||
|
final multiPartFiles = declareFinal('formDataList').assign(refer(
|
||||||
|
jsonEncode(formData),
|
||||||
|
));
|
||||||
|
|
||||||
|
final addHeaders = refer('request.headers.addAll').call([refer('headers')]);
|
||||||
|
const multiPartList = Code('''
|
||||||
|
for (Map<String, String> formData in formDataList){
|
||||||
|
if (formData['type'] == 'text') {
|
||||||
|
request.fields.addAll({formData['name']: formData['value']});
|
||||||
|
} else {
|
||||||
|
request.files.add(
|
||||||
|
await http.MultipartFile.fromPath(
|
||||||
|
formData['name'],
|
||||||
|
formData['value'],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''');
|
||||||
|
var multiPartRequestSend =
|
||||||
|
declareFinal('response').assign(refer('request.send()').awaited);
|
||||||
|
var multiPartResponseBody = declareFinal('responseBody')
|
||||||
|
.assign(refer('response.stream.bytesToString()').awaited);
|
||||||
final mainFunction = Method((m) {
|
final mainFunction = Method((m) {
|
||||||
final statusRef = refer('statusCode');
|
final statusRef = refer('statusCode');
|
||||||
m
|
m
|
||||||
@ -135,25 +166,49 @@ class DartHttpCodeGen {
|
|||||||
b.statements.add(headerExp.statement);
|
b.statements.add(headerExp.statement);
|
||||||
}
|
}
|
||||||
b.statements.add(const Code('\n'));
|
b.statements.add(const Code('\n'));
|
||||||
|
if (contentType == ContentType.formdata) {
|
||||||
|
if (formData.isNotEmpty) {
|
||||||
|
b.statements.add(multiPartFiles.statement);
|
||||||
|
}
|
||||||
|
b.statements.add(multiPartRequest.statement);
|
||||||
|
if (formData.isNotEmpty) {
|
||||||
|
b.statements.add(multiPartList);
|
||||||
|
}
|
||||||
|
if (headerExp != null) {
|
||||||
|
b.statements.add(addHeaders.statement);
|
||||||
|
}
|
||||||
|
b.statements.add(multiPartRequestSend.statement);
|
||||||
|
b.statements.add(multiPartResponseBody.statement);
|
||||||
|
b.statements.add(declareVar('statusCode', type: refer('int'))
|
||||||
|
.assign(refer('response').property('statusCode'))
|
||||||
|
.statement);
|
||||||
|
b.statements.add(const Code('\n'));
|
||||||
|
} else {
|
||||||
b.statements.add(responseExp.statement);
|
b.statements.add(responseExp.statement);
|
||||||
b.statements.add(const Code('\n'));
|
b.statements.add(const Code('\n'));
|
||||||
b.statements.add(declareVar('statusCode', type: refer('int'))
|
b.statements.add(declareVar('statusCode', type: refer('int'))
|
||||||
.assign(refer('response').property('statusCode'))
|
.assign(refer('response').property('statusCode'))
|
||||||
.statement);
|
.statement);
|
||||||
|
}
|
||||||
|
|
||||||
b.statements.add(declareIfElse(
|
b.statements.add(declareIfElse(
|
||||||
condition: statusRef
|
condition: statusRef
|
||||||
.greaterOrEqualTo(literalNum(200))
|
.greaterOrEqualTo(literalNum(200))
|
||||||
.and(statusRef.lessThan(literalNum(300))),
|
.and(statusRef.lessThan(literalNum(300))),
|
||||||
body: [
|
body: [
|
||||||
refer('print').call([literalString(r'Status Code: $statusCode')]),
|
refer('print').call([literalString(r'Status Code: $statusCode')]),
|
||||||
refer('print')
|
refer('print').call([
|
||||||
.call([literalString(r'Response Body: ${response.body}')]),
|
literalString(
|
||||||
|
'Response Body: ${contentType == ContentType.formdata ? ':\$responseBody' : '\${response.body}'}')
|
||||||
|
]),
|
||||||
],
|
],
|
||||||
elseBody: [
|
elseBody: [
|
||||||
refer('print')
|
refer('print')
|
||||||
.call([literalString(r'Error Status Code: $statusCode')]),
|
.call([literalString(r'Error Status Code: $statusCode')]),
|
||||||
refer('print').call(
|
refer('print').call([
|
||||||
[literalString(r'Error Response Body: ${response.body}')]),
|
literalString(
|
||||||
|
'Error Response Body: ${contentType == ContentType.formdata ? ':\$responseBody' : '\${response.body}'}')
|
||||||
|
]),
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
@ -161,6 +216,8 @@ class DartHttpCodeGen {
|
|||||||
|
|
||||||
sbf.writeln(mainFunction.accept(emitter));
|
sbf.writeln(mainFunction.accept(emitter));
|
||||||
|
|
||||||
return DartFormatter(pageWidth: 160).format(sbf.toString());
|
return DartFormatter(
|
||||||
|
pageWidth: contentType == ContentType.formdata ? 70 : 160)
|
||||||
|
.format(sbf.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
import 'package:apidash/consts.dart';
|
import 'dart:convert';
|
||||||
import 'package:jinja/jinja.dart' as jj;
|
import 'package:jinja/jinja.dart' as jj;
|
||||||
import 'package:apidash/utils/utils.dart'
|
import 'package:apidash/utils/utils.dart'
|
||||||
show requestModelToHARJsonRequest, padMultilineString, stripUrlParams;
|
show padMultilineString, requestModelToHARJsonRequest, stripUrlParams;
|
||||||
import 'package:apidash/models/models.dart' show RequestModel;
|
import 'package:apidash/models/models.dart' show RequestModel;
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
class AxiosCodeGen {
|
class AxiosCodeGen {
|
||||||
AxiosCodeGen({this.isNodeJs = false});
|
AxiosCodeGen({this.isNodeJs = false});
|
||||||
|
|
||||||
final bool isNodeJs;
|
final bool isNodeJs;
|
||||||
|
|
||||||
String kStringImportNode = """import axios from 'axios';
|
String kStringImportNode = """{% if isNodeJs %}import axios from 'axios';
|
||||||
|
|
||||||
|
{% endif %}{% if isFormDataRequest and isNodeJs %}const fs = require('fs');{% endif %}
|
||||||
""";
|
""";
|
||||||
|
|
||||||
String kTemplateStart = """let config = {
|
String kTemplateStart = """let config = {
|
||||||
@ -46,13 +48,49 @@ axios(config)
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
});
|
});
|
||||||
""";
|
""";
|
||||||
|
String kMultiPartBodyTemplate = r'''
|
||||||
|
|
||||||
|
|
||||||
|
async function buildFormData(fields) {
|
||||||
|
var formdata = new FormData();
|
||||||
|
for (const field of fields) {
|
||||||
|
const name = field.name || '';
|
||||||
|
const value = field.value || '';
|
||||||
|
const type = field.type || 'text';
|
||||||
|
|
||||||
|
if (type === 'text') {
|
||||||
|
formdata.append(name, value);
|
||||||
|
} else if (type === 'file') {
|
||||||
|
formdata.append(name,{% if isNodeJs %} fs.createReadStream(value){% else %} fileInput.files[0],value{% endif %});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return formdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
''';
|
||||||
|
var kGetFormDataTemplate = '''buildFormData({{fields_list}});
|
||||||
|
''';
|
||||||
String? getCode(
|
String? getCode(
|
||||||
RequestModel requestModel,
|
RequestModel requestModel,
|
||||||
String defaultUriScheme,
|
String defaultUriScheme,
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
String result = isNodeJs ? kStringImportNode : "";
|
jj.Template kNodejsImportTemplate = jj.Template(kStringImportNode);
|
||||||
|
String importsData = kNodejsImportTemplate.render({
|
||||||
|
"isFormDataRequest": requestModel.isFormDataRequest,
|
||||||
|
"isNodeJs": isNodeJs,
|
||||||
|
});
|
||||||
|
|
||||||
|
String result = importsData;
|
||||||
|
if (requestModel.isFormDataRequest &&
|
||||||
|
requestModel.formDataMapList.isNotEmpty) {
|
||||||
|
var templateMultiPartBody = jj.Template(kMultiPartBodyTemplate);
|
||||||
|
var renderedMultiPartBody = templateMultiPartBody.render({
|
||||||
|
"isNodeJs": isNodeJs,
|
||||||
|
});
|
||||||
|
result += renderedMultiPartBody;
|
||||||
|
}
|
||||||
|
|
||||||
String url = requestModel.url;
|
String url = requestModel.url;
|
||||||
if (!url.contains("://") && url.isNotEmpty) {
|
if (!url.contains("://") && url.isNotEmpty) {
|
||||||
@ -80,18 +118,31 @@ axios(config)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var headers = harJson["headers"];
|
var headers = harJson["headers"];
|
||||||
if (headers.isNotEmpty) {
|
if (headers.isNotEmpty || requestModel.isFormDataRequest) {
|
||||||
var templateHeader = jj.Template(kTemplateHeader);
|
var templateHeader = jj.Template(kTemplateHeader);
|
||||||
var m = {};
|
var m = {};
|
||||||
for (var i in headers) {
|
for (var i in headers) {
|
||||||
m[i["name"]] = i["value"];
|
m[i["name"]] = i["value"];
|
||||||
}
|
}
|
||||||
|
if (requestModel.isFormDataRequest) {
|
||||||
|
m['Content-Type'] = 'multipart/form-data';
|
||||||
|
}
|
||||||
result += templateHeader
|
result += templateHeader
|
||||||
.render({"headers": padMultilineString(kEncoder.convert(m), 2)});
|
.render({"headers": padMultilineString(kEncoder.convert(m), 2)});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (harJson["postData"]?["text"] != null) {
|
|
||||||
var templateBody = jj.Template(kTemplateBody);
|
var templateBody = jj.Template(kTemplateBody);
|
||||||
|
|
||||||
|
if (requestModel.isFormDataRequest &&
|
||||||
|
requestModel.formDataMapList.isNotEmpty) {
|
||||||
|
var getFieldDataTemplate = jj.Template(kGetFormDataTemplate);
|
||||||
|
|
||||||
|
result += templateBody.render({
|
||||||
|
"body": getFieldDataTemplate.render({
|
||||||
|
"fields_list": json.encode(requestModel.formDataMapList),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (harJson["postData"]?["text"] != null) {
|
||||||
result += templateBody
|
result += templateBody
|
||||||
.render({"body": kEncoder.convert(harJson["postData"]["text"])});
|
.render({"body": kEncoder.convert(harJson["postData"]["text"])});
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
import 'package:apidash/consts.dart';
|
import 'dart:convert';
|
||||||
import 'package:jinja/jinja.dart' as jj;
|
import 'package:jinja/jinja.dart' as jj;
|
||||||
import 'package:apidash/utils/utils.dart'
|
import 'package:apidash/utils/utils.dart'
|
||||||
show requestModelToHARJsonRequest, padMultilineString;
|
show padMultilineString, requestModelToHARJsonRequest;
|
||||||
import 'package:apidash/models/models.dart' show RequestModel;
|
import 'package:apidash/models/models.dart' show RequestModel;
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
class FetchCodeGen {
|
class FetchCodeGen {
|
||||||
FetchCodeGen({this.isNodeJs = false});
|
FetchCodeGen({this.isNodeJs = false});
|
||||||
|
|
||||||
final bool isNodeJs;
|
final bool isNodeJs;
|
||||||
|
|
||||||
String kStringImportNode = """import fetch from 'node-fetch';
|
String kStringImportNode = """
|
||||||
|
import fetch from 'node-fetch';
|
||||||
|
{% if isFormDataRequest %}const fs = require('fs');{% endif %}
|
||||||
|
|
||||||
""";
|
""";
|
||||||
|
|
||||||
@ -28,6 +31,26 @@ let options = {
|
|||||||
{{body}}
|
{{body}}
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
String kMultiPartBodyTemplate = r'''
|
||||||
|
async function buildDataList(fields) {
|
||||||
|
var formdata = new FormData();
|
||||||
|
for (const field of fields) {
|
||||||
|
const name = field.name || '';
|
||||||
|
const value = field.value || '';
|
||||||
|
const type = field.type || 'text';
|
||||||
|
|
||||||
|
if (type === 'text') {
|
||||||
|
formdata.append(name, value);
|
||||||
|
} else if (type === 'file') {
|
||||||
|
formdata.append(name,{% if isNodeJs %} fs.createReadStream(value){% else %} fileInput.files[0],value{% endif %});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return formdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = buildDataList({{fields_list}});
|
||||||
|
|
||||||
|
''';
|
||||||
String kStringRequest = """
|
String kStringRequest = """
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -53,8 +76,19 @@ fetch(url, options)
|
|||||||
String defaultUriScheme,
|
String defaultUriScheme,
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
String result = isNodeJs ? kStringImportNode : "";
|
jj.Template kNodejsImportTemplate = jj.Template(kStringImportNode);
|
||||||
|
String importsData = kNodejsImportTemplate.render({
|
||||||
|
"isFormDataRequest": requestModel.isFormDataRequest,
|
||||||
|
});
|
||||||
|
|
||||||
|
String result = isNodeJs ? importsData : "";
|
||||||
|
if (requestModel.isFormDataRequest) {
|
||||||
|
var templateMultiPartBody = jj.Template(kMultiPartBodyTemplate);
|
||||||
|
result += templateMultiPartBody.render({
|
||||||
|
"isNodeJs": isNodeJs,
|
||||||
|
"fields_list": json.encode(requestModel.formDataMapList),
|
||||||
|
});
|
||||||
|
}
|
||||||
String url = requestModel.url;
|
String url = requestModel.url;
|
||||||
if (!url.contains("://") && url.isNotEmpty) {
|
if (!url.contains("://") && url.isNotEmpty) {
|
||||||
url = "$defaultUriScheme://$url";
|
url = "$defaultUriScheme://$url";
|
||||||
@ -70,21 +104,33 @@ fetch(url, options)
|
|||||||
});
|
});
|
||||||
|
|
||||||
var headers = harJson["headers"];
|
var headers = harJson["headers"];
|
||||||
|
|
||||||
if (headers.isNotEmpty) {
|
if (headers.isNotEmpty) {
|
||||||
var templateHeader = jj.Template(kTemplateHeader);
|
var templateHeader = jj.Template(kTemplateHeader);
|
||||||
var m = {};
|
var m = {};
|
||||||
|
if (requestModel.isFormDataRequest) {
|
||||||
|
m["Content-Type"] = "multipart/form-data";
|
||||||
|
}
|
||||||
for (var i in headers) {
|
for (var i in headers) {
|
||||||
m[i["name"]] = i["value"];
|
m[i["name"]] = i["value"];
|
||||||
}
|
}
|
||||||
result += templateHeader
|
result += templateHeader.render({
|
||||||
.render({"headers": padMultilineString(kEncoder.convert(m), 2)});
|
"headers": padMultilineString(kEncoder.convert(m), 2),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (harJson["postData"]?["text"] != null) {
|
if (harJson["postData"]?["text"] != null) {
|
||||||
var templateBody = jj.Template(kTemplateBody);
|
var templateBody = jj.Template(kTemplateBody);
|
||||||
result += templateBody
|
result += templateBody.render({
|
||||||
.render({"body": kEncoder.convert(harJson["postData"]["text"])});
|
"body": kEncoder.convert(harJson["postData"]["text"]),
|
||||||
|
});
|
||||||
|
} else if (requestModel.isFormDataRequest) {
|
||||||
|
var templateBody = jj.Template(kTemplateBody);
|
||||||
|
result += templateBody.render({
|
||||||
|
"body": 'payload',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
result += kStringRequest;
|
result += kStringRequest;
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:apidash/consts.dart';
|
|
||||||
import 'package:jinja/jinja.dart' as jj;
|
import 'package:jinja/jinja.dart' as jj;
|
||||||
import 'package:apidash/utils/utils.dart'
|
import 'package:apidash/utils/utils.dart'
|
||||||
show getValidRequestUri, stripUriParams;
|
show getValidRequestUri, stripUriParams;
|
||||||
import '../../models/request_model.dart';
|
import '../../models/request_model.dart';
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
class KotlinOkHttpCodeGen {
|
class KotlinOkHttpCodeGen {
|
||||||
final String kTemplateStart = """import okhttp3.OkHttpClient
|
final String kTemplateStart = """import okhttp3.OkHttpClient
|
||||||
@ -61,6 +61,13 @@ import okhttp3.MediaType.Companion.toMediaType""";
|
|||||||
}
|
}
|
||||||
|
|
||||||
""";
|
""";
|
||||||
|
// Converting list of form data objects to kolin multi part data
|
||||||
|
String kFormDataBody = '''
|
||||||
|
val body = MultipartBody.Builder().setType(MultipartBody.FORM){% for item in formDataList %}{% if item.type == 'file' %}
|
||||||
|
.addFormDataPart("{{item.name}}",null,File("{{item.value}}").asRequestBody("application/octet-stream".toMediaType()))
|
||||||
|
{% else %}.addFormDataPart("{{item.name}}","{{item.value}}")
|
||||||
|
{% endif %}{% endfor %}.build()
|
||||||
|
''';
|
||||||
|
|
||||||
String? getCode(
|
String? getCode(
|
||||||
RequestModel requestModel,
|
RequestModel requestModel,
|
||||||
@ -68,7 +75,6 @@ import okhttp3.MediaType.Companion.toMediaType""";
|
|||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
String result = "";
|
String result = "";
|
||||||
bool hasHeaders = false;
|
|
||||||
bool hasQuery = false;
|
bool hasQuery = false;
|
||||||
bool hasBody = false;
|
bool hasBody = false;
|
||||||
|
|
||||||
@ -102,7 +108,13 @@ import okhttp3.MediaType.Companion.toMediaType""";
|
|||||||
|
|
||||||
var method = requestModel.method;
|
var method = requestModel.method;
|
||||||
var requestBody = requestModel.requestBody;
|
var requestBody = requestModel.requestBody;
|
||||||
if (kMethodsWithBody.contains(method) && requestBody != null) {
|
if (requestModel.isFormDataRequest) {
|
||||||
|
var formDataTemplate = jj.Template(kFormDataBody);
|
||||||
|
|
||||||
|
result += formDataTemplate.render({
|
||||||
|
"formDataList": requestModel.formDataMapList,
|
||||||
|
});
|
||||||
|
} else if (kMethodsWithBody.contains(method) && requestBody != null) {
|
||||||
var contentLength = utf8.encode(requestBody).length;
|
var contentLength = utf8.encode(requestBody).length;
|
||||||
if (contentLength > 0) {
|
if (contentLength > 0) {
|
||||||
hasBody = true;
|
hasBody = true;
|
||||||
@ -127,7 +139,6 @@ import okhttp3.MediaType.Companion.toMediaType""";
|
|||||||
if (headersList != null) {
|
if (headersList != null) {
|
||||||
var headers = requestModel.enabledHeadersMap;
|
var headers = requestModel.enabledHeadersMap;
|
||||||
if (headers.isNotEmpty) {
|
if (headers.isNotEmpty) {
|
||||||
hasHeaders = true;
|
|
||||||
result += getHeaders(headers);
|
result += getHeaders(headers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,7 +146,7 @@ import okhttp3.MediaType.Companion.toMediaType""";
|
|||||||
var templateRequestEnd = jj.Template(kTemplateRequestEnd);
|
var templateRequestEnd = jj.Template(kTemplateRequestEnd);
|
||||||
result += templateRequestEnd.render({
|
result += templateRequestEnd.render({
|
||||||
"method": method.name.toLowerCase(),
|
"method": method.name.toLowerCase(),
|
||||||
"hasBody": hasBody ? "body" : "",
|
"hasBody": (hasBody || requestModel.isFormDataRequest) ? "body" : "",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -10,6 +10,9 @@ class cURLCodeGen {
|
|||||||
String kTemplateHeader = """ \\
|
String kTemplateHeader = """ \\
|
||||||
--header '{{name}}: {{value}}'
|
--header '{{name}}: {{value}}'
|
||||||
""";
|
""";
|
||||||
|
String kTemplateFormData = """ \\
|
||||||
|
--form '{{name}}: {{value}}'
|
||||||
|
""";
|
||||||
|
|
||||||
String kTemplateBody = """ \\
|
String kTemplateBody = """ \\
|
||||||
--data '{{body}}'
|
--data '{{body}}'
|
||||||
@ -48,6 +51,23 @@ class cURLCodeGen {
|
|||||||
.render({"name": item["name"], "value": item["value"]});
|
.render({"name": item["name"], "value": item["value"]});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (harJson['formData'] != null) {
|
||||||
|
var formDataList = harJson['formData'] as List<Map<String, dynamic>>;
|
||||||
|
for (var formData in formDataList) {
|
||||||
|
var templateFormData = jj.Template(kTemplateFormData);
|
||||||
|
if (formData['type'] != null &&
|
||||||
|
formData['name'] != null &&
|
||||||
|
formData['value'] != null &&
|
||||||
|
formData['name']!.isNotEmpty &&
|
||||||
|
formData['value']!.isNotEmpty) {
|
||||||
|
result += templateFormData.render({
|
||||||
|
"name": formData["name"],
|
||||||
|
"value":
|
||||||
|
"${formData['type'] == 'file' ? '@' : ''}${formData["value"]}",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (harJson["postData"]?["text"] != null) {
|
if (harJson["postData"]?["text"] != null) {
|
||||||
var templateBody = jj.Template(kTemplateBody);
|
var templateBody = jj.Template(kTemplateBody);
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:jinja/jinja.dart' as jj;
|
import 'package:jinja/jinja.dart' as jj;
|
||||||
import 'package:apidash/consts.dart';
|
|
||||||
import 'package:apidash/utils/utils.dart'
|
import 'package:apidash/utils/utils.dart'
|
||||||
show getValidRequestUri, padMultilineString;
|
show getNewUuid, getValidRequestUri, padMultilineString;
|
||||||
import 'package:apidash/models/models.dart' show RequestModel;
|
import 'package:apidash/models/models.dart' show RequestModel;
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
class PythonHttpClientCodeGen {
|
class PythonHttpClientCodeGen {
|
||||||
final String kTemplateStart = """import http.client
|
final String kTemplateStart = """import http.client
|
||||||
|
{% if isFormDataRequest %}import mimetypes
|
||||||
|
from codecs import encode
|
||||||
|
{% endif %}
|
||||||
""";
|
""";
|
||||||
|
|
||||||
String kTemplateParams = """
|
String kTemplateParams = """
|
||||||
@ -30,6 +33,8 @@ body = r'''{{body}}'''
|
|||||||
headers = {{headers}}
|
headers = {{headers}}
|
||||||
|
|
||||||
""";
|
""";
|
||||||
|
String kTemplateFormHeaderContentType = '''
|
||||||
|
multipart/form-data; boundary={{boundary}}''';
|
||||||
|
|
||||||
int kHeadersPadding = 10;
|
int kHeadersPadding = 10;
|
||||||
|
|
||||||
@ -55,10 +60,38 @@ data = res.read()
|
|||||||
print(data.decode("utf-8"))
|
print(data.decode("utf-8"))
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
final String kStringFormDataBody = r'''
|
||||||
|
|
||||||
|
def build_data_list(fields):
|
||||||
|
dataList = []
|
||||||
|
for field in fields:
|
||||||
|
name = field.get('name', '')
|
||||||
|
value = field.get('value', '')
|
||||||
|
type_ = field.get('type', 'text')
|
||||||
|
dataList.append(encode('--{{boundary}}'))
|
||||||
|
if type_ == 'text':
|
||||||
|
dataList.append(encode(f'Content-Disposition: form-data; name="{name}"'))
|
||||||
|
dataList.append(encode('Content-Type: text/plain'))
|
||||||
|
dataList.append(encode(''))
|
||||||
|
dataList.append(encode(value))
|
||||||
|
elif type_ == 'file':
|
||||||
|
dataList.append(encode(f'Content-Disposition: form-data; name="{name}"; filename="{value}"'))
|
||||||
|
dataList.append(encode(f'Content-Type: {mimetypes.guess_type(value)[0] or "application/octet-stream"}'))
|
||||||
|
dataList.append(encode(''))
|
||||||
|
dataList.append(open(value, 'rb').read())
|
||||||
|
dataList.append(encode(f'--{{boundary}}--'))
|
||||||
|
dataList.append(encode(''))
|
||||||
|
return dataList
|
||||||
|
|
||||||
|
dataList = build_data_list({{fields_list}})
|
||||||
|
body = b'\r\n'.join(dataList)
|
||||||
|
''';
|
||||||
String? getCode(
|
String? getCode(
|
||||||
RequestModel requestModel,
|
RequestModel requestModel,
|
||||||
String defaultUriScheme,
|
String defaultUriScheme,
|
||||||
) {
|
) {
|
||||||
|
String uuid = getNewUuid();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String result = "";
|
String result = "";
|
||||||
bool hasHeaders = false;
|
bool hasHeaders = false;
|
||||||
@ -70,11 +103,17 @@ print(data.decode("utf-8"))
|
|||||||
url = "$defaultUriScheme://$url";
|
url = "$defaultUriScheme://$url";
|
||||||
}
|
}
|
||||||
|
|
||||||
result += kTemplateStart;
|
var templateStartUrl = jj.Template(kTemplateStart);
|
||||||
|
result += templateStartUrl.render(
|
||||||
|
{
|
||||||
|
"isFormDataRequest": requestModel.isFormDataRequest,
|
||||||
|
},
|
||||||
|
);
|
||||||
var rec = getValidRequestUri(
|
var rec = getValidRequestUri(
|
||||||
url,
|
url,
|
||||||
requestModel.enabledRequestParams,
|
requestModel.enabledRequestParams,
|
||||||
);
|
);
|
||||||
|
|
||||||
Uri? uri = rec.$1;
|
Uri? uri = rec.$1;
|
||||||
|
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
@ -103,6 +142,14 @@ print(data.decode("utf-8"))
|
|||||||
var headersList = requestModel.enabledRequestHeaders;
|
var headersList = requestModel.enabledRequestHeaders;
|
||||||
if (headersList != null || hasBody) {
|
if (headersList != null || hasBody) {
|
||||||
var headers = requestModel.enabledHeadersMap;
|
var headers = requestModel.enabledHeadersMap;
|
||||||
|
if (requestModel.isFormDataRequest) {
|
||||||
|
var formHeaderTemplate =
|
||||||
|
jj.Template(kTemplateFormHeaderContentType);
|
||||||
|
headers[HttpHeaders.contentTypeHeader] = formHeaderTemplate.render({
|
||||||
|
"boundary": uuid,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (headers.isNotEmpty || hasBody) {
|
if (headers.isNotEmpty || hasBody) {
|
||||||
hasHeaders = true;
|
hasHeaders = true;
|
||||||
if (hasBody && !requestModel.hasContentTypeHeader) {
|
if (hasBody && !requestModel.hasContentTypeHeader) {
|
||||||
@ -115,7 +162,15 @@ print(data.decode("utf-8"))
|
|||||||
result += templateHeaders.render({"headers": headersString});
|
result += templateHeaders.render({"headers": headersString});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (requestModel.isFormDataRequest) {
|
||||||
|
var formDataBodyData = jj.Template(kStringFormDataBody);
|
||||||
|
result += formDataBodyData.render(
|
||||||
|
{
|
||||||
|
"fields_list": json.encode(requestModel.formDataMapList),
|
||||||
|
"boundary": uuid,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
var templateConnection = jj.Template(kTemplateConnection);
|
var templateConnection = jj.Template(kTemplateConnection);
|
||||||
result += templateConnection.render({
|
result += templateConnection.render({
|
||||||
"isHttps": uri.scheme == "https" ? "S" : "",
|
"isHttps": uri.scheme == "https" ? "S" : "",
|
||||||
@ -129,11 +184,11 @@ print(data.decode("utf-8"))
|
|||||||
"queryParamsStr": hasQuery ? " + queryParamsStr" : "",
|
"queryParamsStr": hasQuery ? " + queryParamsStr" : "",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (hasBody) {
|
if (hasBody || requestModel.isFormDataRequest) {
|
||||||
result += kStringRequestBody;
|
result += kStringRequestBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasHeaders) {
|
if (hasHeaders || requestModel.isFormDataRequest) {
|
||||||
result += kStringRequestHeaders;
|
result += kStringRequestHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,12 +3,14 @@ import 'dart:convert';
|
|||||||
import 'package:jinja/jinja.dart' as jj;
|
import 'package:jinja/jinja.dart' as jj;
|
||||||
import 'package:apidash/consts.dart';
|
import 'package:apidash/consts.dart';
|
||||||
import 'package:apidash/utils/utils.dart'
|
import 'package:apidash/utils/utils.dart'
|
||||||
show getValidRequestUri, padMultilineString, stripUriParams;
|
show getNewUuid, getValidRequestUri, padMultilineString, stripUriParams;
|
||||||
import 'package:apidash/models/models.dart' show RequestModel;
|
import 'package:apidash/models/models.dart' show RequestModel;
|
||||||
|
|
||||||
class PythonRequestsCodeGen {
|
class PythonRequestsCodeGen {
|
||||||
final String kTemplateStart = """import requests
|
final String kTemplateStart = """import requests
|
||||||
|
{% if isFormDataRequest %}import mimetypes
|
||||||
|
from codecs import encode
|
||||||
|
{% endif %}
|
||||||
url = '{{url}}'
|
url = '{{url}}'
|
||||||
|
|
||||||
""";
|
""";
|
||||||
@ -37,6 +39,8 @@ payload = {{body}}
|
|||||||
headers = {{headers}}
|
headers = {{headers}}
|
||||||
|
|
||||||
""";
|
""";
|
||||||
|
String kTemplateFormHeaderContentType = '''
|
||||||
|
multipart/form-data; boundary={{boundary}}''';
|
||||||
|
|
||||||
int kHeadersPadding = 10;
|
int kHeadersPadding = 10;
|
||||||
|
|
||||||
@ -45,6 +49,34 @@ headers = {{headers}}
|
|||||||
response = requests.{{method}}(url
|
response = requests.{{method}}(url
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
final String kStringFormDataBody = r'''
|
||||||
|
|
||||||
|
def build_data_list(fields):
|
||||||
|
dataList = []
|
||||||
|
for field in fields:
|
||||||
|
name = field.get('name', '')
|
||||||
|
value = field.get('value', '')
|
||||||
|
type_ = field.get('type', 'text')
|
||||||
|
|
||||||
|
dataList.append(encode('--{{boundary}}'))
|
||||||
|
if type_ == 'text':
|
||||||
|
dataList.append(encode(f'Content-Disposition: form-data; name="{name}"'))
|
||||||
|
dataList.append(encode('Content-Type: text/plain'))
|
||||||
|
dataList.append(encode(''))
|
||||||
|
dataList.append(encode(value))
|
||||||
|
elif type_ == 'file':
|
||||||
|
dataList.append(encode(f'Content-Disposition: form-data; name="{name}"; filename="{value}"'))
|
||||||
|
dataList.append(encode(f'Content-Type: {mimetypes.guess_type(value)[0] or "application/octet-stream"}'))
|
||||||
|
dataList.append(encode(''))
|
||||||
|
dataList.append(open(value, 'rb').read())
|
||||||
|
dataList.append(encode('--{{boundary}}--'))
|
||||||
|
dataList.append(encode(''))
|
||||||
|
return dataList
|
||||||
|
|
||||||
|
dataList = build_data_list({{fields_list}})
|
||||||
|
payload = b'\r\n'.join(dataList)
|
||||||
|
''';
|
||||||
|
|
||||||
String kStringRequestParams = """, params=params""";
|
String kStringRequestParams = """, params=params""";
|
||||||
|
|
||||||
String kStringRequestBody = """, data=payload""";
|
String kStringRequestBody = """, data=payload""";
|
||||||
@ -69,6 +101,7 @@ print('Response Body:', response.text)
|
|||||||
bool hasHeaders = false;
|
bool hasHeaders = false;
|
||||||
bool hasBody = false;
|
bool hasBody = false;
|
||||||
bool hasJsonBody = false;
|
bool hasJsonBody = false;
|
||||||
|
String uuid = getNewUuid();
|
||||||
|
|
||||||
String url = requestModel.url;
|
String url = requestModel.url;
|
||||||
if (!url.contains("://") && url.isNotEmpty) {
|
if (!url.contains("://") && url.isNotEmpty) {
|
||||||
@ -82,7 +115,10 @@ print('Response Body:', response.text)
|
|||||||
Uri? uri = rec.$1;
|
Uri? uri = rec.$1;
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
var templateStartUrl = jj.Template(kTemplateStart);
|
var templateStartUrl = jj.Template(kTemplateStart);
|
||||||
result += templateStartUrl.render({"url": stripUriParams(uri)});
|
result += templateStartUrl.render({
|
||||||
|
"url": stripUriParams(uri),
|
||||||
|
'isFormDataRequest': requestModel.isFormDataRequest
|
||||||
|
});
|
||||||
|
|
||||||
if (uri.hasQuery) {
|
if (uri.hasQuery) {
|
||||||
var params = uri.queryParameters;
|
var params = uri.queryParameters;
|
||||||
@ -115,6 +151,13 @@ print('Response Body:', response.text)
|
|||||||
var headersList = requestModel.enabledRequestHeaders;
|
var headersList = requestModel.enabledRequestHeaders;
|
||||||
if (headersList != null || hasBody) {
|
if (headersList != null || hasBody) {
|
||||||
var headers = requestModel.enabledHeadersMap;
|
var headers = requestModel.enabledHeadersMap;
|
||||||
|
if (requestModel.isFormDataRequest) {
|
||||||
|
var formHeaderTemplate =
|
||||||
|
jj.Template(kTemplateFormHeaderContentType);
|
||||||
|
headers[HttpHeaders.contentTypeHeader] = formHeaderTemplate.render({
|
||||||
|
"boundary": uuid,
|
||||||
|
});
|
||||||
|
}
|
||||||
if (headers.isNotEmpty || hasBody) {
|
if (headers.isNotEmpty || hasBody) {
|
||||||
hasHeaders = true;
|
hasHeaders = true;
|
||||||
if (hasBody) {
|
if (hasBody) {
|
||||||
@ -127,7 +170,15 @@ print('Response Body:', response.text)
|
|||||||
result += templateHeaders.render({"headers": headersString});
|
result += templateHeaders.render({"headers": headersString});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (requestModel.isFormDataRequest) {
|
||||||
|
var formDataBodyData = jj.Template(kStringFormDataBody);
|
||||||
|
result += formDataBodyData.render(
|
||||||
|
{
|
||||||
|
"fields_list": json.encode(requestModel.formDataMapList),
|
||||||
|
"boundary": uuid,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
var templateRequest = jj.Template(kTemplateRequest);
|
var templateRequest = jj.Template(kTemplateRequest);
|
||||||
result += templateRequest.render({
|
result += templateRequest.render({
|
||||||
"method": method.name.toLowerCase(),
|
"method": method.name.toLowerCase(),
|
||||||
@ -137,15 +188,15 @@ print('Response Body:', response.text)
|
|||||||
result += kStringRequestParams;
|
result += kStringRequestParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasBody) {
|
if (hasBody || requestModel.isFormDataRequest) {
|
||||||
result += kStringRequestBody;
|
result += kStringRequestBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasJsonBody) {
|
if (hasJsonBody || requestModel.isFormDataRequest) {
|
||||||
result += kStringRequestJson;
|
result += kStringRequestJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasHeaders) {
|
if (hasHeaders || requestModel.isFormDataRequest) {
|
||||||
result += kStringRequestHeaders;
|
result += kStringRequestHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +48,10 @@ const kHintOpacity = 0.6;
|
|||||||
const kForegroundOpacity = 0.05;
|
const kForegroundOpacity = 0.05;
|
||||||
|
|
||||||
const kTextStyleButton = TextStyle(fontWeight: FontWeight.bold);
|
const kTextStyleButton = TextStyle(fontWeight: FontWeight.bold);
|
||||||
|
const kFormDataButtonLabelTextStyle = TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
);
|
||||||
|
|
||||||
const kBorderRadius8 = BorderRadius.all(Radius.circular(8));
|
const kBorderRadius8 = BorderRadius.all(Radius.circular(8));
|
||||||
final kBorderRadius10 = BorderRadius.circular(10);
|
final kBorderRadius10 = BorderRadius.circular(10);
|
||||||
@ -57,6 +61,7 @@ const kP1 = EdgeInsets.all(1);
|
|||||||
const kP5 = EdgeInsets.all(5);
|
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 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);
|
||||||
@ -85,7 +90,7 @@ const kP8CollectionPane = EdgeInsets.only(
|
|||||||
// bottom: 8.0,
|
// bottom: 8.0,
|
||||||
);
|
);
|
||||||
const kPr8CollectionPane = EdgeInsets.only(right: 8.0);
|
const kPr8CollectionPane = EdgeInsets.only(right: 8.0);
|
||||||
|
const kpsV5 = EdgeInsets.symmetric(vertical: 2);
|
||||||
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);
|
||||||
@ -237,7 +242,9 @@ enum RequestItemMenuOption { edit, delete, duplicate }
|
|||||||
|
|
||||||
enum HTTPVerb { get, head, post, put, patch, delete }
|
enum HTTPVerb { get, head, post, put, patch, delete }
|
||||||
|
|
||||||
enum ContentType { json, text }
|
enum ContentType { json, text, formdata }
|
||||||
|
|
||||||
|
enum FormDataType { text, file }
|
||||||
|
|
||||||
const kSupportedUriSchemes = ["https", "http"];
|
const kSupportedUriSchemes = ["https", "http"];
|
||||||
const kDefaultUriScheme = "https";
|
const kDefaultUriScheme = "https";
|
||||||
@ -308,6 +315,7 @@ const kSubTypeDefaultViewOptions = 'all';
|
|||||||
const kContentTypeMap = {
|
const kContentTypeMap = {
|
||||||
ContentType.json: "$kTypeApplication/$kSubTypeJson",
|
ContentType.json: "$kTypeApplication/$kSubTypeJson",
|
||||||
ContentType.text: "$kTypeText/$kSubTypePlain",
|
ContentType.text: "$kTypeText/$kSubTypePlain",
|
||||||
|
ContentType.formdata: "multipart/form-data",
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ResponseBodyView { preview, code, raw, none }
|
enum ResponseBodyView { preview, code, raw, none }
|
||||||
|
23
lib/models/form_data_model.dart
Normal file
23
lib/models/form_data_model.dart
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'form_data_model.freezed.dart';
|
||||||
|
part 'form_data_model.g.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class FormDataModel with _$FormDataModel {
|
||||||
|
const factory FormDataModel({
|
||||||
|
required String name,
|
||||||
|
required String value,
|
||||||
|
required FormDataType type,
|
||||||
|
}) = _FormDataModel;
|
||||||
|
|
||||||
|
factory FormDataModel.fromJson(Map<String, Object?> json) =>
|
||||||
|
_$FormDataModelFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
const kFormDataEmptyModel = FormDataModel(
|
||||||
|
name: "",
|
||||||
|
value: "",
|
||||||
|
type: FormDataType.text,
|
||||||
|
);
|
187
lib/models/form_data_model.freezed.dart
Normal file
187
lib/models/form_data_model.freezed.dart
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
// coverage:ignore-file
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||||
|
|
||||||
|
part of 'form_data_model.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
final _privateConstructorUsedError = UnsupportedError(
|
||||||
|
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||||
|
|
||||||
|
FormDataModel _$FormDataModelFromJson(Map<String, dynamic> json) {
|
||||||
|
return _FormDataModel.fromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$FormDataModel {
|
||||||
|
String get name => throw _privateConstructorUsedError;
|
||||||
|
String get value => throw _privateConstructorUsedError;
|
||||||
|
FormDataType get type => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
$FormDataModelCopyWith<FormDataModel> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $FormDataModelCopyWith<$Res> {
|
||||||
|
factory $FormDataModelCopyWith(
|
||||||
|
FormDataModel value, $Res Function(FormDataModel) then) =
|
||||||
|
_$FormDataModelCopyWithImpl<$Res, FormDataModel>;
|
||||||
|
@useResult
|
||||||
|
$Res call({String name, String value, FormDataType type});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$FormDataModelCopyWithImpl<$Res, $Val extends FormDataModel>
|
||||||
|
implements $FormDataModelCopyWith<$Res> {
|
||||||
|
_$FormDataModelCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? name = null,
|
||||||
|
Object? value = null,
|
||||||
|
Object? type = null,
|
||||||
|
}) {
|
||||||
|
return _then(_value.copyWith(
|
||||||
|
name: null == name
|
||||||
|
? _value.name
|
||||||
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
value: null == value
|
||||||
|
? _value.value
|
||||||
|
: value // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
type: null == type
|
||||||
|
? _value.type
|
||||||
|
: type // ignore: cast_nullable_to_non_nullable
|
||||||
|
as FormDataType,
|
||||||
|
) as $Val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$FormDataModelImplCopyWith<$Res>
|
||||||
|
implements $FormDataModelCopyWith<$Res> {
|
||||||
|
factory _$$FormDataModelImplCopyWith(
|
||||||
|
_$FormDataModelImpl value, $Res Function(_$FormDataModelImpl) then) =
|
||||||
|
__$$FormDataModelImplCopyWithImpl<$Res>;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call({String name, String value, FormDataType type});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$FormDataModelImplCopyWithImpl<$Res>
|
||||||
|
extends _$FormDataModelCopyWithImpl<$Res, _$FormDataModelImpl>
|
||||||
|
implements _$$FormDataModelImplCopyWith<$Res> {
|
||||||
|
__$$FormDataModelImplCopyWithImpl(
|
||||||
|
_$FormDataModelImpl _value, $Res Function(_$FormDataModelImpl) _then)
|
||||||
|
: super(_value, _then);
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? name = null,
|
||||||
|
Object? value = null,
|
||||||
|
Object? type = null,
|
||||||
|
}) {
|
||||||
|
return _then(_$FormDataModelImpl(
|
||||||
|
name: null == name
|
||||||
|
? _value.name
|
||||||
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
value: null == value
|
||||||
|
? _value.value
|
||||||
|
: value // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
type: null == type
|
||||||
|
? _value.type
|
||||||
|
: type // ignore: cast_nullable_to_non_nullable
|
||||||
|
as FormDataType,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _$FormDataModelImpl implements _FormDataModel {
|
||||||
|
const _$FormDataModelImpl(
|
||||||
|
{required this.name, required this.value, required this.type});
|
||||||
|
|
||||||
|
factory _$FormDataModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$$FormDataModelImplFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String name;
|
||||||
|
@override
|
||||||
|
final String value;
|
||||||
|
@override
|
||||||
|
final FormDataType type;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'FormDataModel(name: $name, value: $value, type: $type)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(dynamic other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$FormDataModelImpl &&
|
||||||
|
(identical(other.name, name) || other.name == name) &&
|
||||||
|
(identical(other.value, value) || other.value == value) &&
|
||||||
|
(identical(other.type, type) || other.type == type));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType, name, value, type);
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$FormDataModelImplCopyWith<_$FormDataModelImpl> get copyWith =>
|
||||||
|
__$$FormDataModelImplCopyWithImpl<_$FormDataModelImpl>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$$FormDataModelImplToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _FormDataModel implements FormDataModel {
|
||||||
|
const factory _FormDataModel(
|
||||||
|
{required final String name,
|
||||||
|
required final String value,
|
||||||
|
required final FormDataType type}) = _$FormDataModelImpl;
|
||||||
|
|
||||||
|
factory _FormDataModel.fromJson(Map<String, dynamic> json) =
|
||||||
|
_$FormDataModelImpl.fromJson;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get name;
|
||||||
|
@override
|
||||||
|
String get value;
|
||||||
|
@override
|
||||||
|
FormDataType get type;
|
||||||
|
@override
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
_$$FormDataModelImplCopyWith<_$FormDataModelImpl> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
26
lib/models/form_data_model.g.dart
Normal file
26
lib/models/form_data_model.g.dart
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'form_data_model.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_$FormDataModelImpl _$$FormDataModelImplFromJson(Map<String, dynamic> json) =>
|
||||||
|
_$FormDataModelImpl(
|
||||||
|
name: json['name'] as String,
|
||||||
|
value: json['value'] as String,
|
||||||
|
type: $enumDecode(_$FormDataTypeEnumMap, json['type']),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$FormDataModelImplToJson(_$FormDataModelImpl instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'name': instance.name,
|
||||||
|
'value': instance.value,
|
||||||
|
'type': _$FormDataTypeEnumMap[instance.type]!,
|
||||||
|
};
|
||||||
|
|
||||||
|
const _$FormDataTypeEnumMap = {
|
||||||
|
FormDataType.text: 'text',
|
||||||
|
FormDataType.file: 'file',
|
||||||
|
};
|
@ -2,3 +2,4 @@ export 'name_value_model.dart';
|
|||||||
export 'request_model.dart';
|
export 'request_model.dart';
|
||||||
export 'response_model.dart';
|
export 'response_model.dart';
|
||||||
export 'settings_model.dart';
|
export 'settings_model.dart';
|
||||||
|
export 'form_data_model.dart';
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:apidash/consts.dart';
|
import '../utils/utils.dart'
|
||||||
import 'package:apidash/utils/utils.dart'
|
show
|
||||||
show mapToRows, rowsToMap, getEnabledRows;
|
mapListToFormDataModelRows,
|
||||||
import 'name_value_model.dart';
|
rowsToFormDataMapList,
|
||||||
import 'response_model.dart';
|
mapToRows,
|
||||||
|
rowsToMap,
|
||||||
|
getEnabledRows;
|
||||||
|
import '../consts.dart';
|
||||||
|
import 'models.dart';
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
class RequestModel {
|
class RequestModel {
|
||||||
@ -21,6 +25,7 @@ class RequestModel {
|
|||||||
this.isParamEnabledList,
|
this.isParamEnabledList,
|
||||||
this.requestBodyContentType = ContentType.json,
|
this.requestBodyContentType = ContentType.json,
|
||||||
this.requestBody,
|
this.requestBody,
|
||||||
|
this.requestFormDataList,
|
||||||
this.responseStatus,
|
this.responseStatus,
|
||||||
this.message,
|
this.message,
|
||||||
this.responseModel,
|
this.responseModel,
|
||||||
@ -38,6 +43,7 @@ class RequestModel {
|
|||||||
final List<bool>? isParamEnabledList;
|
final List<bool>? isParamEnabledList;
|
||||||
final ContentType requestBodyContentType;
|
final ContentType requestBodyContentType;
|
||||||
final String? requestBody;
|
final String? requestBody;
|
||||||
|
final List<FormDataModel>? requestFormDataList;
|
||||||
final int? responseStatus;
|
final int? responseStatus;
|
||||||
final String? message;
|
final String? message;
|
||||||
final ResponseModel? responseModel;
|
final ResponseModel? responseModel;
|
||||||
@ -54,6 +60,10 @@ class RequestModel {
|
|||||||
Map<String, String> get headersMap => rowsToMap(requestHeaders) ?? {};
|
Map<String, String> get headersMap => rowsToMap(requestHeaders) ?? {};
|
||||||
Map<String, String> get paramsMap => rowsToMap(requestParams) ?? {};
|
Map<String, String> get paramsMap => rowsToMap(requestParams) ?? {};
|
||||||
|
|
||||||
|
List<Map<String, dynamic>> get formDataMapList =>
|
||||||
|
rowsToFormDataMapList(requestFormDataList) ?? [];
|
||||||
|
bool get isFormDataRequest => requestBodyContentType == ContentType.formdata;
|
||||||
|
|
||||||
bool get hasContentTypeHeader => enabledHeadersMap.keys
|
bool get hasContentTypeHeader => enabledHeadersMap.keys
|
||||||
.any((k) => k.toLowerCase() == HttpHeaders.contentTypeHeader);
|
.any((k) => k.toLowerCase() == HttpHeaders.contentTypeHeader);
|
||||||
|
|
||||||
@ -74,6 +84,8 @@ class RequestModel {
|
|||||||
isParamEnabledList != null ? [...isParamEnabledList!] : null,
|
isParamEnabledList != null ? [...isParamEnabledList!] : null,
|
||||||
requestBodyContentType: requestBodyContentType,
|
requestBodyContentType: requestBodyContentType,
|
||||||
requestBody: requestBody,
|
requestBody: requestBody,
|
||||||
|
requestFormDataList:
|
||||||
|
requestFormDataList != null ? [...requestFormDataList!] : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,6 +102,7 @@ class RequestModel {
|
|||||||
List<bool>? isParamEnabledList,
|
List<bool>? isParamEnabledList,
|
||||||
ContentType? requestBodyContentType,
|
ContentType? requestBodyContentType,
|
||||||
String? requestBody,
|
String? requestBody,
|
||||||
|
List<FormDataModel>? requestFormDataList,
|
||||||
int? responseStatus,
|
int? responseStatus,
|
||||||
String? message,
|
String? message,
|
||||||
ResponseModel? responseModel,
|
ResponseModel? responseModel,
|
||||||
@ -112,6 +125,7 @@ class RequestModel {
|
|||||||
requestBodyContentType:
|
requestBodyContentType:
|
||||||
requestBodyContentType ?? this.requestBodyContentType,
|
requestBodyContentType ?? this.requestBodyContentType,
|
||||||
requestBody: requestBody ?? this.requestBody,
|
requestBody: requestBody ?? this.requestBody,
|
||||||
|
requestFormDataList: requestFormDataList ?? this.requestFormDataList,
|
||||||
responseStatus: responseStatus ?? this.responseStatus,
|
responseStatus: responseStatus ?? this.responseStatus,
|
||||||
message: message ?? this.message,
|
message: message ?? this.message,
|
||||||
responseModel: responseModel ?? this.responseModel,
|
responseModel: responseModel ?? this.responseModel,
|
||||||
@ -143,9 +157,11 @@ class RequestModel {
|
|||||||
requestBodyContentType = kDefaultContentType;
|
requestBodyContentType = kDefaultContentType;
|
||||||
}
|
}
|
||||||
final requestBody = data["requestBody"] as String?;
|
final requestBody = data["requestBody"] as String?;
|
||||||
|
final requestFormDataList = data["requestFormDataList"];
|
||||||
final responseStatus = data["responseStatus"] as int?;
|
final responseStatus = data["responseStatus"] as int?;
|
||||||
final message = data["message"] as String?;
|
final message = data["message"] as String?;
|
||||||
final responseModelJson = data["responseModel"];
|
final responseModelJson = data["responseModel"];
|
||||||
|
|
||||||
if (responseModelJson != null) {
|
if (responseModelJson != null) {
|
||||||
responseModel =
|
responseModel =
|
||||||
ResponseModel.fromJson(Map<String, dynamic>.from(responseModelJson));
|
ResponseModel.fromJson(Map<String, dynamic>.from(responseModelJson));
|
||||||
@ -170,6 +186,9 @@ class RequestModel {
|
|||||||
isParamEnabledList: isParamEnabledList,
|
isParamEnabledList: isParamEnabledList,
|
||||||
requestBodyContentType: requestBodyContentType,
|
requestBodyContentType: requestBodyContentType,
|
||||||
requestBody: requestBody,
|
requestBody: requestBody,
|
||||||
|
requestFormDataList: requestFormDataList != null
|
||||||
|
? mapListToFormDataModelRows(List<Map>.from(requestFormDataList))
|
||||||
|
: null,
|
||||||
responseStatus: responseStatus,
|
responseStatus: responseStatus,
|
||||||
message: message,
|
message: message,
|
||||||
responseModel: responseModel,
|
responseModel: responseModel,
|
||||||
@ -189,6 +208,7 @@ class RequestModel {
|
|||||||
"isParamEnabledList": isParamEnabledList,
|
"isParamEnabledList": isParamEnabledList,
|
||||||
"requestBodyContentType": requestBodyContentType.name,
|
"requestBodyContentType": requestBodyContentType.name,
|
||||||
"requestBody": requestBody,
|
"requestBody": requestBody,
|
||||||
|
"requestFormDataList": rowsToFormDataMapList(requestFormDataList),
|
||||||
"responseStatus": includeResponse ? responseStatus : null,
|
"responseStatus": includeResponse ? responseStatus : null,
|
||||||
"message": includeResponse ? message : null,
|
"message": includeResponse ? message : null,
|
||||||
"responseModel": includeResponse ? responseModel?.toJson() : null,
|
"responseModel": includeResponse ? responseModel?.toJson() : null,
|
||||||
@ -210,6 +230,7 @@ class RequestModel {
|
|||||||
"Enabled Params: ${isParamEnabledList.toString()}",
|
"Enabled Params: ${isParamEnabledList.toString()}",
|
||||||
"Request Body Content Type: ${requestBodyContentType.toString()}",
|
"Request Body Content Type: ${requestBodyContentType.toString()}",
|
||||||
"Request Body: ${requestBody.toString()}",
|
"Request Body: ${requestBody.toString()}",
|
||||||
|
"Request FormData: ${requestFormDataList.toString()}",
|
||||||
"Response Status: $responseStatus",
|
"Response Status: $responseStatus",
|
||||||
"Response Message: $message",
|
"Response Message: $message",
|
||||||
"Response: ${responseModel.toString()}"
|
"Response: ${responseModel.toString()}"
|
||||||
@ -232,6 +253,7 @@ class RequestModel {
|
|||||||
listEquals(other.isParamEnabledList, isParamEnabledList) &&
|
listEquals(other.isParamEnabledList, isParamEnabledList) &&
|
||||||
other.requestBodyContentType == requestBodyContentType &&
|
other.requestBodyContentType == requestBodyContentType &&
|
||||||
other.requestBody == requestBody &&
|
other.requestBody == requestBody &&
|
||||||
|
other.requestFormDataList == requestFormDataList &&
|
||||||
other.responseStatus == responseStatus &&
|
other.responseStatus == responseStatus &&
|
||||||
other.message == message &&
|
other.message == message &&
|
||||||
other.responseModel == responseModel;
|
other.responseModel == responseModel;
|
||||||
@ -253,6 +275,7 @@ class RequestModel {
|
|||||||
isParamEnabledList,
|
isParamEnabledList,
|
||||||
requestBodyContentType,
|
requestBodyContentType,
|
||||||
requestBody,
|
requestBody,
|
||||||
|
requestFormDataList,
|
||||||
responseStatus,
|
responseStatus,
|
||||||
message,
|
message,
|
||||||
responseModel,
|
responseModel,
|
||||||
|
@ -5,6 +5,7 @@ import '../models/models.dart';
|
|||||||
import '../services/services.dart' show hiveHandler, HiveHandler, request;
|
import '../services/services.dart' show hiveHandler, HiveHandler, request;
|
||||||
import '../utils/utils.dart' show uuid, collectionToHAR;
|
import '../utils/utils.dart' show uuid, collectionToHAR;
|
||||||
import '../consts.dart';
|
import '../consts.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
final activeIdStateProvider = StateProvider<String?>((ref) => null);
|
final activeIdStateProvider = StateProvider<String?>((ref) => null);
|
||||||
|
|
||||||
@ -127,6 +128,7 @@ class CollectionStateNotifier
|
|||||||
List<bool>? isParamEnabledList,
|
List<bool>? isParamEnabledList,
|
||||||
ContentType? requestBodyContentType,
|
ContentType? requestBodyContentType,
|
||||||
String? requestBody,
|
String? requestBody,
|
||||||
|
List<FormDataModel>? requestFormDataList,
|
||||||
int? responseStatus,
|
int? responseStatus,
|
||||||
String? message,
|
String? message,
|
||||||
ResponseModel? responseModel,
|
ResponseModel? responseModel,
|
||||||
@ -143,9 +145,11 @@ class CollectionStateNotifier
|
|||||||
isParamEnabledList: isParamEnabledList,
|
isParamEnabledList: isParamEnabledList,
|
||||||
requestBodyContentType: requestBodyContentType,
|
requestBodyContentType: requestBodyContentType,
|
||||||
requestBody: requestBody,
|
requestBody: requestBody,
|
||||||
|
requestFormDataList: requestFormDataList,
|
||||||
responseStatus: responseStatus,
|
responseStatus: responseStatus,
|
||||||
message: message,
|
message: message,
|
||||||
responseModel: responseModel);
|
responseModel: responseModel);
|
||||||
|
//print(newModel);
|
||||||
var map = {...state!};
|
var map = {...state!};
|
||||||
map[id] = newModel;
|
map[id] = newModel;
|
||||||
state = map;
|
state = map;
|
||||||
@ -156,10 +160,13 @@ class CollectionStateNotifier
|
|||||||
ref.read(codePaneVisibleStateProvider.notifier).state = false;
|
ref.read(codePaneVisibleStateProvider.notifier).state = false;
|
||||||
final defaultUriScheme =
|
final defaultUriScheme =
|
||||||
ref.read(settingsProvider.select((value) => value.defaultUriScheme));
|
ref.read(settingsProvider.select((value) => value.defaultUriScheme));
|
||||||
|
|
||||||
RequestModel requestModel = state![id]!;
|
RequestModel requestModel = state![id]!;
|
||||||
var responseRec =
|
(http.Response?, Duration?, String?)? responseRec = await request(
|
||||||
await request(requestModel, defaultUriScheme: defaultUriScheme);
|
requestModel,
|
||||||
|
defaultUriScheme: defaultUriScheme,
|
||||||
|
isMultiPartRequest:
|
||||||
|
requestModel.requestBodyContentType == ContentType.formdata,
|
||||||
|
);
|
||||||
late final RequestModel newRequestModel;
|
late final RequestModel newRequestModel;
|
||||||
if (responseRec.$1 == null) {
|
if (responseRec.$1 == null) {
|
||||||
newRequestModel = requestModel.copyWith(
|
newRequestModel = requestModel.copyWith(
|
||||||
|
@ -18,6 +18,10 @@ class _EditRequestBodyState extends ConsumerState<EditRequestBody> {
|
|||||||
final requestModel = ref
|
final requestModel = ref
|
||||||
.read(collectionStateNotifierProvider.notifier)
|
.read(collectionStateNotifierProvider.notifier)
|
||||||
.getRequestModel(activeId!);
|
.getRequestModel(activeId!);
|
||||||
|
ContentType? requestBodyStateWatcher = (ref
|
||||||
|
.watch(collectionStateNotifierProvider)![activeId]
|
||||||
|
?.requestBodyContentType) ??
|
||||||
|
ContentType.values.first;
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.background,
|
||||||
@ -38,7 +42,9 @@ class _EditRequestBodyState extends ConsumerState<EditRequestBody> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TextFieldEditor(
|
child: requestBodyStateWatcher == ContentType.formdata
|
||||||
|
? const FormDataWidget()
|
||||||
|
: TextFieldEditor(
|
||||||
key: Key("$activeId-body"),
|
key: Key("$activeId-body"),
|
||||||
fieldKey: "$activeId-body-editor",
|
fieldKey: "$activeId-body-editor",
|
||||||
initialValue: requestModel?.requestBody,
|
initialValue: requestModel?.requestBody,
|
||||||
|
@ -9,6 +9,7 @@ import 'package:apidash/consts.dart';
|
|||||||
Future<(http.Response?, Duration?, String?)> request(
|
Future<(http.Response?, Duration?, String?)> request(
|
||||||
RequestModel requestModel, {
|
RequestModel requestModel, {
|
||||||
String defaultUriScheme = kDefaultUriScheme,
|
String defaultUriScheme = kDefaultUriScheme,
|
||||||
|
bool isMultiPartRequest = false,
|
||||||
}) async {
|
}) async {
|
||||||
(Uri?, String?) uriRec = getValidRequestUri(
|
(Uri?, String?) uriRec = getValidRequestUri(
|
||||||
requestModel.url,
|
requestModel.url,
|
||||||
@ -35,6 +36,31 @@ Future<(http.Response?, Duration?, String?)> request(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Stopwatch stopwatch = Stopwatch()..start();
|
Stopwatch stopwatch = Stopwatch()..start();
|
||||||
|
if (isMultiPartRequest) {
|
||||||
|
var multiPartRequest = http.MultipartRequest(
|
||||||
|
requestModel.method.name.toUpperCase(),
|
||||||
|
requestUrl,
|
||||||
|
);
|
||||||
|
multiPartRequest.headers.addAll(headers);
|
||||||
|
for (FormDataModel formData
|
||||||
|
in (requestModel.requestFormDataList ?? [])) {
|
||||||
|
if (formData.type == FormDataType.text) {
|
||||||
|
multiPartRequest.fields.addAll({formData.name: formData.value});
|
||||||
|
} else {
|
||||||
|
multiPartRequest.files.add(
|
||||||
|
await http.MultipartFile.fromPath(
|
||||||
|
formData.name,
|
||||||
|
formData.value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
http.StreamedResponse multiPartResponse = await multiPartRequest.send();
|
||||||
|
stopwatch.stop();
|
||||||
|
http.Response convertedMultiPartResponse =
|
||||||
|
await convertStreamedResponse(multiPartResponse);
|
||||||
|
return (convertedMultiPartResponse, stopwatch.elapsed, null);
|
||||||
|
}
|
||||||
switch (requestModel.method) {
|
switch (requestModel.method) {
|
||||||
case HTTPVerb.get:
|
case HTTPVerb.get:
|
||||||
response = await http.get(requestUrl, headers: headers);
|
response = await http.get(requestUrl, headers: headers);
|
||||||
|
@ -2,6 +2,7 @@ import 'dart:typed_data';
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import '../models/models.dart';
|
import '../models/models.dart';
|
||||||
import '../consts.dart';
|
import '../consts.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
String humanizeDuration(Duration? duration) {
|
String humanizeDuration(Duration? duration) {
|
||||||
if (duration == null) {
|
if (duration == null) {
|
||||||
@ -89,6 +90,43 @@ List<NameValueModel>? mapToRows(Map<String, String>? kvMap) {
|
|||||||
return finalRows;
|
return finalRows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Map<String, dynamic>>? rowsToFormDataMapList(
|
||||||
|
List<FormDataModel>? kvRows,
|
||||||
|
) {
|
||||||
|
if (kvRows == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<Map<String, dynamic>> finalMap = kvRows
|
||||||
|
.map((FormDataModel formData) => {
|
||||||
|
"name": formData.name,
|
||||||
|
"value": formData.value,
|
||||||
|
"type": formData.type.name,
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
|
return finalMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<FormDataModel>? mapListToFormDataModelRows(List<Map>? kvMap) {
|
||||||
|
if (kvMap == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<FormDataModel> finalRows = kvMap.map(
|
||||||
|
(formData) {
|
||||||
|
return FormDataModel(
|
||||||
|
name: formData["name"],
|
||||||
|
value: formData["value"],
|
||||||
|
type: getFormDataType(formData["type"]),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).toList();
|
||||||
|
return finalRows;
|
||||||
|
}
|
||||||
|
|
||||||
|
FormDataType getFormDataType(String? type) {
|
||||||
|
return FormDataType.values.firstWhere((element) => element.name == type,
|
||||||
|
orElse: () => FormDataType.text);
|
||||||
|
}
|
||||||
|
|
||||||
Uint8List? stringToBytes(String? text) {
|
Uint8List? stringToBytes(String? text) {
|
||||||
if (text == null) {
|
if (text == null) {
|
||||||
return null;
|
return null;
|
||||||
@ -110,6 +148,23 @@ Uint8List jsonMapToBytes(Map<String, dynamic>? map) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<http.Response> convertStreamedResponse(
|
||||||
|
http.StreamedResponse streamedResponse,
|
||||||
|
) async {
|
||||||
|
Uint8List bodyBytes = await streamedResponse.stream.toBytes();
|
||||||
|
|
||||||
|
http.Response response = http.Response.bytes(
|
||||||
|
bodyBytes,
|
||||||
|
streamedResponse.statusCode,
|
||||||
|
headers: streamedResponse.headers,
|
||||||
|
persistentConnection: streamedResponse.persistentConnection,
|
||||||
|
reasonPhrase: streamedResponse.reasonPhrase,
|
||||||
|
request: streamedResponse.request,
|
||||||
|
);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
List<NameValueModel>? getEnabledRows(
|
List<NameValueModel>? getEnabledRows(
|
||||||
List<NameValueModel>? rows, List<bool>? isRowEnabledList) {
|
List<NameValueModel>? rows, List<bool>? isRowEnabledList) {
|
||||||
if (rows == null || isRowEnabledList == null) {
|
if (rows == null || isRowEnabledList == null) {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:apidash/consts.dart';
|
import 'package:apidash/consts.dart';
|
||||||
|
import 'package:apidash/models/form_data_model.dart';
|
||||||
|
import 'package:apidash/utils/convert_utils.dart';
|
||||||
import 'package:apidash/utils/utils.dart' show getValidRequestUri;
|
import 'package:apidash/utils/utils.dart' show getValidRequestUri;
|
||||||
import 'package:apidash/models/models.dart' show RequestModel;
|
import 'package:apidash/models/models.dart' show RequestModel;
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
@ -153,7 +155,9 @@ Map<String, dynamic> requestModelToHARJsonRequest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (requestModel.isFormDataRequest) {
|
||||||
|
json["formData"] = requestModel.formDataMapList;
|
||||||
|
}
|
||||||
if (exportMode) {
|
if (exportMode) {
|
||||||
json["comment"] = "";
|
json["comment"] = "";
|
||||||
json["cookies"] = [];
|
json["cookies"] = [];
|
||||||
|
@ -93,6 +93,56 @@ class DropdownButtonContentType extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DropdownButtonFormData extends StatefulWidget {
|
||||||
|
const DropdownButtonFormData({
|
||||||
|
super.key,
|
||||||
|
this.formDataType,
|
||||||
|
this.onChanged,
|
||||||
|
});
|
||||||
|
|
||||||
|
final FormDataType? formDataType;
|
||||||
|
final void Function(FormDataType?)? onChanged;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DropdownButtonFormData> createState() => _DropdownButtonFormData();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DropdownButtonFormData extends State<DropdownButtonFormData> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final surfaceColor = Theme.of(context).colorScheme.surface;
|
||||||
|
return DropdownButton<FormDataType>(
|
||||||
|
dropdownColor: surfaceColor,
|
||||||
|
focusColor: surfaceColor,
|
||||||
|
value: widget.formDataType,
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.unfold_more_rounded,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
elevation: 4,
|
||||||
|
style: kCodeStyle.copyWith(
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
underline: const IgnorePointer(),
|
||||||
|
onChanged: widget.onChanged,
|
||||||
|
borderRadius: kBorderRadius12,
|
||||||
|
items: FormDataType.values
|
||||||
|
.map<DropdownMenuItem<FormDataType>>((FormDataType value) {
|
||||||
|
return DropdownMenuItem<FormDataType>(
|
||||||
|
value: value,
|
||||||
|
child: Padding(
|
||||||
|
padding: kPs8,
|
||||||
|
child: Text(
|
||||||
|
value.name,
|
||||||
|
style: kTextStyleButton,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class DropdownButtonCodegenLanguage extends StatelessWidget {
|
class DropdownButtonCodegenLanguage extends StatelessWidget {
|
||||||
const DropdownButtonCodegenLanguage({
|
const DropdownButtonCodegenLanguage({
|
||||||
super.key,
|
super.key,
|
||||||
|
81
lib/widgets/form_data_field.dart
Normal file
81
lib/widgets/form_data_field.dart
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
import 'package:apidash/widgets/widgets.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class FormDataField extends StatefulWidget {
|
||||||
|
const FormDataField({
|
||||||
|
super.key,
|
||||||
|
required this.keyId,
|
||||||
|
this.initialValue,
|
||||||
|
this.hintText,
|
||||||
|
this.onChanged,
|
||||||
|
this.colorScheme,
|
||||||
|
this.formDataType,
|
||||||
|
this.onFormDataTypeChanged,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String keyId;
|
||||||
|
final String? initialValue;
|
||||||
|
final String? hintText;
|
||||||
|
final void Function(String)? onChanged;
|
||||||
|
final ColorScheme? colorScheme;
|
||||||
|
final FormDataType? formDataType;
|
||||||
|
final void Function(FormDataType?)? onFormDataTypeChanged;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<FormDataField> createState() => _FormDataFieldState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FormDataFieldState extends State<FormDataField> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var colorScheme = widget.colorScheme ?? Theme.of(context).colorScheme;
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: TextFormField(
|
||||||
|
initialValue: widget.initialValue,
|
||||||
|
key: Key(widget.keyId),
|
||||||
|
style: kCodeStyle.copyWith(
|
||||||
|
color: colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintStyle: kCodeStyle.copyWith(
|
||||||
|
color: colorScheme.outline.withOpacity(
|
||||||
|
kHintOpacity,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
hintText: widget.hintText,
|
||||||
|
focusedBorder: UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: colorScheme.primary.withOpacity(
|
||||||
|
kHintOpacity,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
enabledBorder: UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: colorScheme.surfaceVariant,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
suffixIcon: DropdownButtonFormData(
|
||||||
|
formDataType: widget.formDataType,
|
||||||
|
onChanged: (p0) {
|
||||||
|
if (widget.onFormDataTypeChanged != null) {
|
||||||
|
widget.onFormDataTypeChanged!(p0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
onChanged: widget.onChanged,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
223
lib/widgets/form_data_widget.dart
Normal file
223
lib/widgets/form_data_widget.dart
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
import 'package:apidash/models/form_data_model.dart';
|
||||||
|
import 'package:apidash/models/models.dart';
|
||||||
|
import 'package:apidash/providers/collection_providers.dart';
|
||||||
|
import 'package:apidash/widgets/form_data_field.dart';
|
||||||
|
import 'package:apidash/widgets/textfields.dart';
|
||||||
|
import 'package:davi/davi.dart';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
class FormDataWidget extends ConsumerStatefulWidget {
|
||||||
|
const FormDataWidget({super.key});
|
||||||
|
@override
|
||||||
|
ConsumerState<FormDataWidget> createState() => _FormDataBodyState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FormDataBodyState extends ConsumerState<FormDataWidget> {
|
||||||
|
late int seed;
|
||||||
|
final random = Random.secure();
|
||||||
|
late List<FormDataModel> rows;
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
seed = random.nextInt(kRandMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final activeId = ref.watch(activeIdStateProvider);
|
||||||
|
var formRows = ref.read(activeRequestModelProvider)?.requestFormDataList;
|
||||||
|
rows =
|
||||||
|
formRows == null || formRows.isEmpty ? [kFormDataEmptyModel] : formRows;
|
||||||
|
|
||||||
|
DaviModel<FormDataModel> daviModelRows = DaviModel<FormDataModel>(
|
||||||
|
rows: rows,
|
||||||
|
columns: [
|
||||||
|
DaviColumn(
|
||||||
|
cellPadding: kpsV5,
|
||||||
|
name: 'Key',
|
||||||
|
grow: 4,
|
||||||
|
cellBuilder: (_, row) {
|
||||||
|
int idx = row.index;
|
||||||
|
return Theme(
|
||||||
|
data: Theme.of(context),
|
||||||
|
child: FormDataField(
|
||||||
|
keyId: "$activeId-$idx-form-v-$seed",
|
||||||
|
initialValue: rows[idx].name,
|
||||||
|
hintText: " Add Key",
|
||||||
|
onChanged: (value) {
|
||||||
|
rows[idx] = rows[idx].copyWith(
|
||||||
|
name: value,
|
||||||
|
);
|
||||||
|
_onFieldChange(activeId!);
|
||||||
|
},
|
||||||
|
colorScheme: Theme.of(context).colorScheme,
|
||||||
|
formDataType: rows[idx].type,
|
||||||
|
onFormDataTypeChanged: (value) {
|
||||||
|
rows[idx] = rows[idx].copyWith(
|
||||||
|
type: value ?? FormDataType.text,
|
||||||
|
);
|
||||||
|
rows[idx] = rows[idx].copyWith(value: "");
|
||||||
|
setState(() {});
|
||||||
|
_onFieldChange(activeId!);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
sortable: false,
|
||||||
|
),
|
||||||
|
DaviColumn(
|
||||||
|
width: 40,
|
||||||
|
cellPadding: kpsV5,
|
||||||
|
cellAlignment: Alignment.center,
|
||||||
|
cellBuilder: (_, row) {
|
||||||
|
return Text(
|
||||||
|
"=",
|
||||||
|
style: kCodeStyle,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
DaviColumn(
|
||||||
|
name: 'Value',
|
||||||
|
grow: 4,
|
||||||
|
cellPadding: kpsV5,
|
||||||
|
cellBuilder: (_, row) {
|
||||||
|
int idx = row.index;
|
||||||
|
return rows[idx].type == FormDataType.file
|
||||||
|
? Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Theme(
|
||||||
|
data: Theme.of(context),
|
||||||
|
child: ElevatedButton.icon(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.snippet_folder_rounded,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
style: ButtonStyle(
|
||||||
|
shape: MaterialStatePropertyAll(
|
||||||
|
RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(6),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
FilePickerResult? pickedResult =
|
||||||
|
await FilePicker.platform.pickFiles();
|
||||||
|
if (pickedResult != null &&
|
||||||
|
pickedResult.files.isNotEmpty &&
|
||||||
|
pickedResult.files.first.path != null) {
|
||||||
|
rows[idx] = rows[idx].copyWith(
|
||||||
|
value: pickedResult.files.first.path!,
|
||||||
|
);
|
||||||
|
setState(() {});
|
||||||
|
_onFieldChange(activeId!);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
label: Text(
|
||||||
|
(rows[idx].type == FormDataType.file &&
|
||||||
|
rows[idx].value.isNotEmpty)
|
||||||
|
? rows[idx].value.toString()
|
||||||
|
: "Select File",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: kFormDataButtonLabelTextStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: CellField(
|
||||||
|
keyId: "$activeId-$idx-form-v-$seed",
|
||||||
|
initialValue: rows[idx].value,
|
||||||
|
hintText: " Add Value",
|
||||||
|
onChanged: (value) {
|
||||||
|
rows[idx] = rows[idx].copyWith(value: value);
|
||||||
|
_onFieldChange(activeId!);
|
||||||
|
},
|
||||||
|
colorScheme: Theme.of(context).colorScheme,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
sortable: false,
|
||||||
|
),
|
||||||
|
DaviColumn(
|
||||||
|
pinStatus: PinStatus.none,
|
||||||
|
width: 30,
|
||||||
|
cellBuilder: (_, row) {
|
||||||
|
return InkWell(
|
||||||
|
child: Theme.of(context).brightness == Brightness.dark
|
||||||
|
? kIconRemoveDark
|
||||||
|
: kIconRemoveLight,
|
||||||
|
onTap: () {
|
||||||
|
seed = random.nextInt(kRandMax);
|
||||||
|
if (rows.length == 1) {
|
||||||
|
setState(() {
|
||||||
|
rows = [kFormDataEmptyModel];
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
rows.removeAt(row.index);
|
||||||
|
}
|
||||||
|
_onFieldChange(activeId!);
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.background,
|
||||||
|
borderRadius: kBorderRadius12,
|
||||||
|
),
|
||||||
|
margin: kP10,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: DaviTheme(
|
||||||
|
data: kTableThemeData,
|
||||||
|
child: Davi<FormDataModel>(daviModelRows),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 30),
|
||||||
|
child: ElevatedButton.icon(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
rows.add(kFormDataEmptyModel);
|
||||||
|
});
|
||||||
|
_onFieldChange(activeId!);
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.add),
|
||||||
|
label: const Text(
|
||||||
|
"Add Form Data",
|
||||||
|
style: kTextStyleButton,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onFieldChange(String activeId) {
|
||||||
|
ref.read(collectionStateNotifierProvider.notifier).update(
|
||||||
|
activeId,
|
||||||
|
requestFormDataList: rows,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -22,3 +22,4 @@ export 'textfields.dart';
|
|||||||
export 'texts.dart';
|
export 'texts.dart';
|
||||||
export 'uint8_audio_player.dart';
|
export 'uint8_audio_player.dart';
|
||||||
export 'window_caption.dart';
|
export 'window_caption.dart';
|
||||||
|
export 'form_data_widget.dart';
|
||||||
|
@ -48,6 +48,7 @@ dependencies:
|
|||||||
url: https://github.com/foss42/json_data_explorer.git
|
url: https://github.com/foss42/json_data_explorer.git
|
||||||
version: ^0.1.1
|
version: ^0.1.1
|
||||||
scrollable_positioned_list: ^0.2.3
|
scrollable_positioned_list: ^0.2.3
|
||||||
|
file_picker: ^6.1.1
|
||||||
flutter_svg: ^2.0.9
|
flutter_svg: ^2.0.9
|
||||||
vector_graphics_compiler: ^1.1.9+1
|
vector_graphics_compiler: ^1.1.9+1
|
||||||
code_builder: ^4.9.0
|
code_builder: ^4.9.0
|
||||||
|
@ -113,6 +113,7 @@ void main() {
|
|||||||
"requestBody": '''{
|
"requestBody": '''{
|
||||||
"text":"WORLD"
|
"text":"WORLD"
|
||||||
}''',
|
}''',
|
||||||
|
'requestFormDataList': null,
|
||||||
'responseStatus': null,
|
'responseStatus': null,
|
||||||
'message': null,
|
'message': null,
|
||||||
'responseModel': null
|
'responseModel': null
|
||||||
@ -147,6 +148,7 @@ void main() {
|
|||||||
"Enabled Params: null",
|
"Enabled Params: null",
|
||||||
"Request Body Content Type: ContentType.json",
|
"Request Body Content Type: ContentType.json",
|
||||||
'Request Body: {\n"text":"WORLD"\n}',
|
'Request Body: {\n"text":"WORLD"\n}',
|
||||||
|
'Request FormData: null',
|
||||||
"Response Status: null",
|
"Response Status: null",
|
||||||
"Response Message: null",
|
"Response Message: null",
|
||||||
"Response: null"
|
"Response: null"
|
||||||
|
Reference in New Issue
Block a user