From 80f828b558dbe8f6866a40535bcb19d575679557 Mon Sep 17 00:00:00 2001 From: Affan Shaikhsurab <51104750+AffanShaikhsurab@users.noreply.github.com> Date: Tue, 4 Mar 2025 13:29:33 +0530 Subject: [PATCH 1/5] Added env variable support for form request body MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✨ Added env variable support for form request body to enhance flexibility and reduce manual updates. --- .../details_card/request_pane/request_form_data.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart index 6b0a48c2..a2c99138 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart @@ -1,4 +1,5 @@ import 'dart:math'; +import 'package:apidash/screens/common_widgets/envfield_cell.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; @@ -82,7 +83,7 @@ class _FormDataBodyState extends ConsumerState { key: ValueKey("$selectedId-$index-form-row-$seed"), cells: [ DataCell( - CellField( + EnvCellField( keyId: "$selectedId-$index-form-k-$seed", initialValue: formRows[index].name, hintText: kHintAddFieldName, @@ -138,7 +139,7 @@ class _FormDataBodyState extends ConsumerState { }, initialValue: formRows[index].value, ) - : CellField( + : EnvCellField( keyId: "$selectedId-$index-form-v-$seed", initialValue: formRows[index].value, hintText: kHintAddValue, From f133845c4f63d9f4d89b880d715d4b331463e467 Mon Sep 17 00:00:00 2001 From: Affan Shaikhsurab <51104750+AffanShaikhsurab@users.noreply.github.com> Date: Tue, 4 Mar 2025 09:55:25 +0000 Subject: [PATCH 2/5] UPDATED ENV SUBSTITUTION --- .../details_card/request_pane/request_form_data.dart | 2 +- lib/utils/envvar_utils.dart | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart index a2c99138..f2749745 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart @@ -83,7 +83,7 @@ class _FormDataBodyState extends ConsumerState { key: ValueKey("$selectedId-$index-form-row-$seed"), cells: [ DataCell( - EnvCellField( + CellField( keyId: "$selectedId-$index-form-k-$seed", initialValue: formRows[index].name, hintText: kHintAddFieldName, diff --git a/lib/utils/envvar_utils.dart b/lib/utils/envvar_utils.dart index 230cf535..4bf9af1c 100644 --- a/lib/utils/envvar_utils.dart +++ b/lib/utils/envvar_utils.dart @@ -85,6 +85,13 @@ HttpRequestModel substituteHttpRequestModel( value: substituteVariables(param.value, envMap, activeEnvironmentId), ); }).toList(), + formData: httpRequestModel.formData?.map((formData) { + return formData.copyWith( + name: + substituteVariables(formData.name, envMap, activeEnvironmentId) ?? "", + value: substituteVariables(formData.value, envMap, activeEnvironmentId) ?? "", + ); + }).toList(), body: substituteVariables( httpRequestModel.body, envMap, From 104273e24b6cac9213ec6e63f652ba28b8f5dd02 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Tue, 11 Mar 2025 03:33:43 +0530 Subject: [PATCH 3/5] Update substituteVariables --- lib/utils/envvar_utils.dart | 68 ++++++++++++++----------------- test/utils/envvar_utils_test.dart | 52 ++++++++--------------- 2 files changed, 48 insertions(+), 72 deletions(-) diff --git a/lib/utils/envvar_utils.dart b/lib/utils/envvar_utils.dart index 4bf9af1c..c94f6eeb 100644 --- a/lib/utils/envvar_utils.dart +++ b/lib/utils/envvar_utils.dart @@ -37,66 +37,60 @@ List getEnvironmentSecrets( } String? substituteVariables( - String? input, - Map> envMap, - String? activeEnvironmentId) { + String? input, + Map envVarMap, +) { if (input == null) return null; - - final Map combinedMap = {}; - final activeEnv = envMap[activeEnvironmentId] ?? []; - final globalEnv = envMap[kGlobalEnvironmentId] ?? []; - - for (var variable in globalEnv) { - combinedMap[variable.key] = variable.value; - } - for (var variable in activeEnv) { - combinedMap[variable.key] = variable.value; + if (envVarMap.keys.isEmpty) { + return input; } + final regex = RegExp("{{(${envVarMap.keys.join('|')})}}"); - String result = input.replaceAllMapped(kEnvVarRegEx, (match) { + String result = input.replaceAllMapped(regex, (match) { final key = match.group(1)?.trim() ?? ''; - return combinedMap[key] ?? ''; + return envVarMap[key] ?? '{{$key}}'; }); return result; } HttpRequestModel substituteHttpRequestModel( - HttpRequestModel httpRequestModel, - Map> envMap, - String? activeEnvironmentId) { + HttpRequestModel httpRequestModel, + Map> envMap, + String? activeEnvironmentId, +) { + final Map combinedEnvVarMap = {}; + final activeEnv = envMap[activeEnvironmentId] ?? []; + final globalEnv = envMap[kGlobalEnvironmentId] ?? []; + + for (var variable in globalEnv) { + combinedEnvVarMap[variable.key] = variable.value; + } + for (var variable in activeEnv) { + combinedEnvVarMap[variable.key] = variable.value; + } + var newRequestModel = httpRequestModel.copyWith( - url: substituteVariables( - httpRequestModel.url, - envMap, - activeEnvironmentId, - )!, + url: substituteVariables(httpRequestModel.url, combinedEnvVarMap)!, headers: httpRequestModel.headers?.map((header) { return header.copyWith( - name: - substituteVariables(header.name, envMap, activeEnvironmentId) ?? "", - value: substituteVariables(header.value, envMap, activeEnvironmentId), + name: substituteVariables(header.name, combinedEnvVarMap) ?? "", + value: substituteVariables(header.value, combinedEnvVarMap), ); }).toList(), params: httpRequestModel.params?.map((param) { return param.copyWith( - name: - substituteVariables(param.name, envMap, activeEnvironmentId) ?? "", - value: substituteVariables(param.value, envMap, activeEnvironmentId), + name: substituteVariables(param.name, combinedEnvVarMap) ?? "", + value: substituteVariables(param.value, combinedEnvVarMap), ); }).toList(), formData: httpRequestModel.formData?.map((formData) { return formData.copyWith( - name: - substituteVariables(formData.name, envMap, activeEnvironmentId) ?? "", - value: substituteVariables(formData.value, envMap, activeEnvironmentId) ?? "", + name: substituteVariables(formData.name, combinedEnvVarMap) ?? "", + value: substituteVariables(formData.value, combinedEnvVarMap) ?? "", ); }).toList(), - body: substituteVariables( - httpRequestModel.body, - envMap, - activeEnvironmentId, - ), + body: substituteVariables(httpRequestModel.body, combinedEnvVarMap), ); return newRequestModel; } diff --git a/test/utils/envvar_utils_test.dart b/test/utils/envvar_utils_test.dart index 6e2dfa55..48fc7735 100644 --- a/test/utils/envvar_utils_test.dart +++ b/test/utils/envvar_utils_test.dart @@ -48,10 +48,13 @@ const globalVars = [ EnvironmentVariableModel(key: "num", value: "5670000"), EnvironmentVariableModel(key: "token", value: "token"), ]; +final globalVarsMap = {for (var item in globalVars) item.key: item.value}; const activeEnvVars = [ EnvironmentVariableModel(key: "url", value: "api.apidash.dev"), EnvironmentVariableModel(key: "num", value: "8940000"), ]; +final activeEnvVarsMap = {for (var item in activeEnvVars) item.key: item.value}; +final combinedEnvVarsMap = mergeMaps(globalVarsMap, activeEnvVarsMap); void main() { group("Testing getEnvironmentTitle function", () { @@ -125,66 +128,45 @@ void main() { group("Testing substituteVariables function", () { test("Testing substituteVariables with null", () { String? input; - Map> envMap = {}; - String? activeEnvironmentId; - expect(substituteVariables(input, envMap, activeEnvironmentId), null); + Map envMap = {}; + expect(substituteVariables(input, envMap), null); }); test("Testing substituteVariables with empty input", () { String input = ""; - Map> envMap = {}; - String? activeEnvironmentId; - expect(substituteVariables(input, envMap, activeEnvironmentId), ""); + Map envMap = {}; + expect(substituteVariables(input, envMap), ""); }); test("Testing substituteVariables with empty envMap", () { String input = "{{url}}/humanize/social?num={{num}}"; - Map> envMap = {}; - String? activeEnvironmentId; - String expected = "/humanize/social?num="; - expect(substituteVariables(input, envMap, activeEnvironmentId), expected); + Map envMap = {}; + String expected = "{{url}}/humanize/social?num={{num}}"; + expect(substituteVariables(input, envMap), expected); }); test("Testing substituteVariables with empty activeEnvironmentId", () { String input = "{{url}}/humanize/social?num={{num}}"; - Map> envMap = { - kGlobalEnvironmentId: globalVars, - }; String expected = "api.foss42.com/humanize/social?num=5670000"; - expect(substituteVariables(input, envMap, null), expected); + expect(substituteVariables(input, globalVarsMap), expected); }); test("Testing substituteVariables with non-empty activeEnvironmentId", () { String input = "{{url}}/humanize/social?num={{num}}"; - Map> envMap = { - kGlobalEnvironmentId: globalVars, - "activeEnvId": activeEnvVars, - }; - String? activeEnvId = "activeEnvId"; String expected = "api.apidash.dev/humanize/social?num=8940000"; - expect(substituteVariables(input, envMap, activeEnvId), expected); + expect(substituteVariables(input, combinedEnvVarsMap), expected); }); test("Testing substituteVariables with incorrect paranthesis", () { String input = "{{url}}}/humanize/social?num={{num}}"; - Map> envMap = { - kGlobalEnvironmentId: globalVars, - "activeEnvId": activeEnvVars, - }; - String? activeEnvId = "activeEnvId"; String expected = "api.apidash.dev}/humanize/social?num=8940000"; - expect(substituteVariables(input, envMap, activeEnvId), expected); + expect(substituteVariables(input, combinedEnvVarsMap), expected); }); test("Testing substituteVariables function with unavailable variables", () { String input = "{{url1}}/humanize/social?num={{num}}"; - Map> envMap = { - kGlobalEnvironmentId: globalVars, - "activeEnvId": activeEnvVars, - }; - String? activeEnvironmentId = "activeEnvId"; - String expected = "/humanize/social?num=8940000"; - expect(substituteVariables(input, envMap, activeEnvironmentId), expected); + String expected = "{{url1}}/humanize/social?num=8940000"; + expect(substituteVariables(input, combinedEnvVarsMap), expected); }); }); @@ -251,9 +233,9 @@ void main() { }; String? activeEnvironmentId = "activeEnvId"; const expected = HttpRequestModel( - url: "/humanize/social", + url: "{{url1}}/humanize/social", headers: [ - NameValueModel(name: "Authorization", value: "Bearer "), + NameValueModel(name: "Authorization", value: "Bearer {{token1}}"), ], params: [ NameValueModel(name: "num", value: "8940000"), From becf17f6a2836b0b1665cb497c0176ce39bd0040 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Tue, 11 Mar 2025 03:34:30 +0530 Subject: [PATCH 4/5] Abstract InputDecoration for TextField --- lib/screens/common_widgets/envfield_cell.dart | 17 +-------- .../widgets/decoration_input_textfield.dart | 38 +++++++++++++++++++ .../lib/widgets/textfield_outlined.dart | 29 +++++--------- .../lib/widgets/widgets.dart | 1 + 4 files changed, 51 insertions(+), 34 deletions(-) create mode 100644 packages/apidash_design_system/lib/widgets/decoration_input_textfield.dart diff --git a/lib/screens/common_widgets/envfield_cell.dart b/lib/screens/common_widgets/envfield_cell.dart index 7aceae1b..b99f4a7e 100644 --- a/lib/screens/common_widgets/envfield_cell.dart +++ b/lib/screens/common_widgets/envfield_cell.dart @@ -27,22 +27,9 @@ class EnvCellField extends StatelessWidget { style: kCodeStyle.copyWith( color: clrScheme.onSurface, ), - decoration: InputDecoration( - hintStyle: kCodeStyle.copyWith( - color: clrScheme.outlineVariant, - ), + decoration: getTextFieldInputDecoration( + clrScheme, hintText: hintText, - contentPadding: const EdgeInsets.only(bottom: 12), - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: clrScheme.outlineVariant, - ), - ), - enabledBorder: UnderlineInputBorder( - borderSide: BorderSide( - color: clrScheme.surfaceContainerHighest, - ), - ), ), onChanged: onChanged, ); diff --git a/packages/apidash_design_system/lib/widgets/decoration_input_textfield.dart b/packages/apidash_design_system/lib/widgets/decoration_input_textfield.dart new file mode 100644 index 00000000..0fe86fcf --- /dev/null +++ b/packages/apidash_design_system/lib/widgets/decoration_input_textfield.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; +import '../tokens/tokens.dart'; + +InputDecoration getTextFieldInputDecoration( + ColorScheme clrScheme, { + Color? fillColor, + String? hintText, + TextStyle? hintTextStyle, + double? hintTextFontSize, + Color? hintTextColor, + EdgeInsetsGeometry? contentPadding, + Color? focussedBorderColor, + Color? enabledBorderColor, + bool? isDense, +}) { + return InputDecoration( + filled: true, + fillColor: fillColor ?? clrScheme.surfaceContainerLowest, + hintStyle: hintTextStyle ?? + kCodeStyle.copyWith( + fontSize: hintTextFontSize, + color: hintTextColor ?? clrScheme.outlineVariant, + ), + hintText: hintText, + contentPadding: contentPadding ?? kP10, + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: focussedBorderColor ?? clrScheme.outline, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: enabledBorderColor ?? clrScheme.surfaceContainerHighest, + ), + ), + isDense: isDense, + ); +} diff --git a/packages/apidash_design_system/lib/widgets/textfield_outlined.dart b/packages/apidash_design_system/lib/widgets/textfield_outlined.dart index a347633d..b9b2588d 100644 --- a/packages/apidash_design_system/lib/widgets/textfield_outlined.dart +++ b/packages/apidash_design_system/lib/widgets/textfield_outlined.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import '../tokens/tokens.dart'; +import 'decoration_input_textfield.dart'; class ADOutlinedTextField extends StatelessWidget { const ADOutlinedTextField({ @@ -65,26 +66,16 @@ class ADOutlinedTextField extends StatelessWidget { fontSize: textFontSize, color: textColor ?? clrScheme.onSurface, ), - decoration: InputDecoration( - filled: true, - fillColor: fillColor ?? clrScheme.surfaceContainerLowest, - hintStyle: hintTextStyle ?? - kCodeStyle.copyWith( - fontSize: hintTextFontSize, - color: hintTextColor ?? clrScheme.outlineVariant, - ), + decoration: getTextFieldInputDecoration( + clrScheme, + fillColor: fillColor, hintText: hintText, - contentPadding: contentPadding ?? kP10, - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: focussedBorderColor ?? clrScheme.outline, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: enabledBorderColor ?? clrScheme.surfaceContainerHighest, - ), - ), + hintTextStyle: hintTextStyle, + hintTextFontSize: hintTextFontSize, + hintTextColor: hintTextColor, + contentPadding: contentPadding, + focussedBorderColor: focussedBorderColor, + enabledBorderColor: enabledBorderColor, isDense: isDense, ), onChanged: onChanged, diff --git a/packages/apidash_design_system/lib/widgets/widgets.dart b/packages/apidash_design_system/lib/widgets/widgets.dart index 955babce..1ebd0836 100644 --- a/packages/apidash_design_system/lib/widgets/widgets.dart +++ b/packages/apidash_design_system/lib/widgets/widgets.dart @@ -2,6 +2,7 @@ export 'button_filled.dart'; export 'button_icon.dart'; export 'button_text.dart'; export 'checkbox.dart'; +export 'decoration_input_textfield.dart'; export 'dropdown.dart'; export 'popup_menu.dart'; export 'snackbar.dart'; From 3382782f379b5462e0559dd435e932fe257e4326 Mon Sep 17 00:00:00 2001 From: Ashita Prasad Date: Tue, 11 Mar 2025 03:34:44 +0530 Subject: [PATCH 5/5] Update request_form_data.dart --- .../details_card/request_pane/request_form_data.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart index f2749745..56d3d138 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_form_data.dart @@ -1,11 +1,11 @@ import 'dart:math'; -import 'package:apidash/screens/common_widgets/envfield_cell.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:data_table_2/data_table_2.dart'; import 'package:apidash/providers/providers.dart'; +import 'package:apidash/screens/common_widgets/common_widgets.dart'; import 'package:apidash/widgets/widgets.dart'; import 'package:apidash/utils/utils.dart'; import 'package:apidash/consts.dart'; @@ -83,7 +83,7 @@ class _FormDataBodyState extends ConsumerState { key: ValueKey("$selectedId-$index-form-row-$seed"), cells: [ DataCell( - CellField( + EnvCellField( keyId: "$selectedId-$index-form-k-$seed", initialValue: formRows[index].name, hintText: kHintAddFieldName,