Skip to content
Open
26 changes: 26 additions & 0 deletions lib/screens/envvar/editor_pane/variables_pane.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ class EditEnvironmentVariablesState
DataColumn2(
label: Text("Variable value"),
),
DataColumn2(
label: Text('OS'),
fixedWidth: 50,
tooltip: 'Use OS environment variable',
),
DataColumn2(
label: Text(''),
fixedWidth: 32,
Expand Down Expand Up @@ -148,6 +153,27 @@ class EditEnvironmentVariablesState
colorScheme: Theme.of(context).colorScheme,
),
),
DataCell(
Tooltip(
message: 'Fetch value from OS environment',
child: ADCheckBox(
keyId: "$selectedId-$index-variables-os-$seed",
value: variableRows[index].fromOS,
onChanged: isLast
? null
: (value) {
if (value != null) {
setState(() {
variableRows[index] =
variableRows[index].copyWith(fromOS: value);
});
}
_onFieldChange(selectedId!);
},
colorScheme: Theme.of(context).colorScheme,
),
),
),
DataCell(
InkWell(
onTap: isLast
Expand Down
38 changes: 38 additions & 0 deletions lib/services/os_env_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import 'dart:io';

/// Service to handle OS environment variable operations
class OSEnvironmentService {
/// Get the value of an environment variable from the OS
/// Returns null if variable is not found
String? getOSEnvironmentVariable(String key) {
try {

final envVars = Platform.environment;

final matchingKey = envVars.keys
.firstWhere((k) => k.toUpperCase() == key.toUpperCase(), orElse: () => '');

if (matchingKey.isNotEmpty) {
final value = envVars[matchingKey];
return value;
}

return null;
} catch (e) {
return null;
}
}

/// Check if an environment variable exists in the OS
bool hasOSEnvironmentVariable(String key) {
try {
final exists = Platform.environment.keys
.any((k) => k.toUpperCase() == key.toUpperCase());
return exists;
} catch (e) {
return false;
}
}
}

final osEnvironmentService = OSEnvironmentService();
1 change: 1 addition & 0 deletions lib/services/services.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export 'hive_services.dart';
export 'history_service.dart';
export 'window_services.dart';
export 'shared_preferences_services.dart';
export 'os_env_service.dart';
43 changes: 32 additions & 11 deletions lib/utils/envvar_utils.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'package:apidash_core/apidash_core.dart';
import 'package:apidash/consts.dart';

import '../services/services.dart';

String getEnvironmentTitle(String? name) {
if (name == null || name.trim() == "") {
return kUntitled;
Expand Down Expand Up @@ -39,6 +41,7 @@ List<EnvironmentVariableModel> getEnvironmentSecrets(
String? substituteVariables(
String? input,
Map<String, String> envVarMap,
String? activeEnvironmentId,
) {
if (input == null) return null;
if (envVarMap.keys.isEmpty) {
Expand All @@ -54,6 +57,14 @@ String? substituteVariables(
return result;
}

String getEnvironmentVariableValue(EnvironmentVariableModel variable, String? activeEnvironmentId, Map<String, String> combinedEnvVarMap) {
if (variable.fromOS) {
final osValue = osEnvironmentService.getOSEnvironmentVariable(variable.key);
return osValue ?? variable.value;
}
return combinedEnvVarMap[variable.key] ?? variable.value;
}

HttpRequestModel substituteHttpRequestModel(
HttpRequestModel httpRequestModel,
Map<String?, List<EnvironmentVariableModel>> envMap,
Expand All @@ -64,33 +75,43 @@ HttpRequestModel substituteHttpRequestModel(
final globalEnv = envMap[kGlobalEnvironmentId] ?? [];

for (var variable in globalEnv) {
combinedEnvVarMap[variable.key] = variable.value;
combinedEnvVarMap[variable.key] = getEnvironmentVariableValue(variable, activeEnvironmentId, combinedEnvVarMap);
}
for (var variable in activeEnv) {
combinedEnvVarMap[variable.key] = variable.value;
combinedEnvVarMap[variable.key] = getEnvironmentVariableValue(variable, activeEnvironmentId, combinedEnvVarMap);
}

var newRequestModel = httpRequestModel.copyWith(
url: substituteVariables(httpRequestModel.url, combinedEnvVarMap)!,
url: substituteVariables(
httpRequestModel.url,
combinedEnvVarMap,
activeEnvironmentId,
)!,
headers: httpRequestModel.headers?.map((header) {
return header.copyWith(
name: substituteVariables(header.name, combinedEnvVarMap) ?? "",
value: substituteVariables(header.value, combinedEnvVarMap),
name:
substituteVariables(header.name, combinedEnvVarMap, activeEnvironmentId) ?? "",
value: substituteVariables(header.value, combinedEnvVarMap, activeEnvironmentId),
);
}).toList(),
params: httpRequestModel.params?.map((param) {
return param.copyWith(
name: substituteVariables(param.name, combinedEnvVarMap) ?? "",
value: substituteVariables(param.value, combinedEnvVarMap),
name:
substituteVariables(param.name, combinedEnvVarMap, activeEnvironmentId) ?? "",
value: substituteVariables(param.value, combinedEnvVarMap, activeEnvironmentId),
);
}).toList(),
formData: httpRequestModel.formData?.map((formData) {
return formData.copyWith(
name: substituteVariables(formData.name, combinedEnvVarMap) ?? "",
value: substituteVariables(formData.value, combinedEnvVarMap) ?? "",
name: substituteVariables(formData.name, combinedEnvVarMap, activeEnvironmentId) ?? "",
value: substituteVariables(formData.value, combinedEnvVarMap, activeEnvironmentId) ?? "",
);
}).toList(),
body: substituteVariables(httpRequestModel.body, combinedEnvVarMap),
body: substituteVariables(
httpRequestModel.body,
combinedEnvVarMap,
activeEnvironmentId,
),
);
return newRequestModel;
}
Expand Down Expand Up @@ -156,4 +177,4 @@ EnvironmentVariableSuggestion getVariableStatus(
environmentId: "unknown",
variable: EnvironmentVariableModel(
key: key, type: EnvironmentVariableType.variable, value: "unknown"));
}
}
5 changes: 3 additions & 2 deletions packages/apidash_core/lib/models/environment_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,17 @@ class EnvironmentVariableModel with _$EnvironmentVariableModel {
required String value,
@Default(EnvironmentVariableType.variable) EnvironmentVariableType type,
@Default(false) bool enabled,
@Default(false) bool fromOS,
}) = _EnvironmentVariableModel;

factory EnvironmentVariableModel.fromJson(Map<String, Object?> json) =>
_$EnvironmentVariableModelFromJson(json);
}

const kEnvironmentVariableEmptyModel =
EnvironmentVariableModel(key: "", value: "");
EnvironmentVariableModel(key: "", value: "", fromOS: false);
const kEnvironmentSecretEmptyModel = EnvironmentVariableModel(
key: "", value: "", type: EnvironmentVariableType.secret);
key: "", value: "", type: EnvironmentVariableType.secret, fromOS: false);

class EnvironmentVariableSuggestion {
final String environmentId;
Expand Down
42 changes: 35 additions & 7 deletions packages/apidash_core/lib/models/environment_model.freezed.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions packages/apidash_core/lib/models/environment_model.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions test/models/environment_models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,14 @@ const environmentModel1Json = {
'value': 'value1',
'type': 'variable',
'enabled': true,
'fromOS': false,
},
{
'key': 'key2',
'value': 'value2',
'type': 'variable',
'enabled': false,
'fromOS': false,
},
],
};
Expand All @@ -116,12 +118,14 @@ const environmentModel2Json = {
'value': 'value1',
'type': 'secret',
'enabled': true,
'fromOS': false,
},
{
'key': 'key2',
'value': 'value2',
'type': 'secret',
'enabled': false,
'fromOS': false,
},
],
};
Expand All @@ -131,11 +135,13 @@ const environmentVariableModel1Json = {
'value': 'value1',
'type': 'variable',
'enabled': true,
'fromOS': false,
};

const environmentVariableModel2Json = {
'key': 'key1',
'value': 'value1',
'type': 'secret',
'enabled': true,
'fromOS': false,
};
Loading