feat: initial and current value for environment variables (#5055)
This commit is contained in:
parent
e7aba8a914
commit
01d96fa577
60 changed files with 1684 additions and 431 deletions
|
|
@ -95,6 +95,7 @@ describe("hopp test [options] <file_path_or_id>", { timeout: 100000 }, () => {
|
|||
const testFixtures = [
|
||||
{ fileName: "env-v0.json", version: 0 },
|
||||
{ fileName: "env-v1.json", version: 1 },
|
||||
{ fileName: "env-v2.json", version: 2 },
|
||||
];
|
||||
|
||||
testFixtures.forEach(({ fileName, version }) => {
|
||||
|
|
|
|||
|
|
@ -1,34 +1,42 @@
|
|||
{
|
||||
"v": 1,
|
||||
"v": 2,
|
||||
"id": "cm0dsn3v70004p4qk3l9b7sjm",
|
||||
"name": "AWS Signature - environments",
|
||||
"variables": [
|
||||
{
|
||||
"key": "awsRegion",
|
||||
"value": "us-east-1",
|
||||
"currentValue": "us-east-1",
|
||||
"initialValue": "us-east-1",
|
||||
"secret": false
|
||||
},
|
||||
{
|
||||
"key": "serviceName",
|
||||
"value": "s3",
|
||||
"currentValue": "s3",
|
||||
"initialValue": "s3",
|
||||
"secret": false
|
||||
},
|
||||
{
|
||||
"key": "accessKey",
|
||||
"value": "test-access-key",
|
||||
"currentValue": "test-access-key",
|
||||
"initialValue": "test-access-key",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "secretKey",
|
||||
"currentValue": "",
|
||||
"initialValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "url",
|
||||
"value": "https://echo.hoppscotch.io",
|
||||
"currentValue": "https://echo.hoppscotch.io",
|
||||
"initialValue": "https://echo.hoppscotch.io",
|
||||
"secret": false
|
||||
},
|
||||
{
|
||||
"key": "serviceToken",
|
||||
"currentValue": "",
|
||||
"initialValue": "",
|
||||
"secret": true
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,21 +1,24 @@
|
|||
{
|
||||
"v": 1,
|
||||
"v": 2,
|
||||
"id": "cm0dsn3v70004p4qk3l9b7sjm",
|
||||
"name": "Digest Auth - environments",
|
||||
"variables": [
|
||||
{
|
||||
"key": "username",
|
||||
"value": "admin",
|
||||
"currentValue": "",
|
||||
"initialValue": "admin",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"value": "admin",
|
||||
"currentValue": "",
|
||||
"initialValue": "admin",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "url",
|
||||
"value": "https://test.insightres.org/digest/"
|
||||
"currentValue": "",
|
||||
"initialValue": "https://test.insightres.org/digest/"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"name": "env-v0",
|
||||
"variables": [
|
||||
{
|
||||
"key": "baseURL",
|
||||
"value": "https://echo.hoppscotch.io",
|
||||
"secret": false
|
||||
}
|
||||
]
|
||||
}
|
||||
"name": "env-v1",
|
||||
"variables": [
|
||||
{
|
||||
"key": "baseURL",
|
||||
"value": "https://echo.hoppscotch.io",
|
||||
"secret": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"id": "env-v2",
|
||||
"v": 2,
|
||||
"name": "env-v2",
|
||||
"variables": [
|
||||
{
|
||||
"key": "baseURL",
|
||||
"initialValue": "https://echo.hoppscotch.io",
|
||||
"currentValue": "https://echo.hoppscotch.io",
|
||||
"secret": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,33 +1,42 @@
|
|||
{
|
||||
"v": 1,
|
||||
"v": 2,
|
||||
"id": "cm00r7kpb0006mbd2nq1560w6",
|
||||
"name": "Request variables alongside environment variables",
|
||||
"variables": [
|
||||
{
|
||||
"key": "url",
|
||||
"value": "https://echo.hoppscotch.io",
|
||||
"initialValue": "https://echo.hoppscotch.io",
|
||||
"currentValue": "https://echo.hoppscotch.io",
|
||||
"secret": false
|
||||
},
|
||||
{
|
||||
"key": "secretBasicAuthPasswordEnvVar",
|
||||
"initialValue": "",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "secretBasicAuthUsernameEnvVar",
|
||||
"value": "username",
|
||||
"initialValue": "username",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "username",
|
||||
"initialValue": "",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "password",
|
||||
"initialValue": "",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "testHeaderValue",
|
||||
"value": "test-header-value",
|
||||
"initialValue": "test-header-value",
|
||||
"currentValue": "",
|
||||
"secret": false
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,26 +1,36 @@
|
|||
{
|
||||
"v": 1,
|
||||
"v": 2,
|
||||
"id": "2",
|
||||
"name": "secret-envs-persistence-scripting-envs",
|
||||
"variables": [
|
||||
{
|
||||
"key": "preReqVarOne",
|
||||
"initialValue": "",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "preReqVarTwo",
|
||||
"initialValue": "",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "postReqVarOne",
|
||||
"initialValue": "",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "preReqVarTwo",
|
||||
"initialValue": "",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "customHeaderValueFromSecretVar",
|
||||
"initialValue": "",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,44 +1,60 @@
|
|||
{
|
||||
"id": "2",
|
||||
"v": 1,
|
||||
"v": 2,
|
||||
"name": "secret-envs",
|
||||
"variables": [
|
||||
{
|
||||
"key": "secretBearerToken",
|
||||
"initialValue": "",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "secretBasicAuthUsername",
|
||||
"initialValue": "",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "secretBasicAuthPassword",
|
||||
"initialValue": "",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "secretQueryParamValue",
|
||||
"initialValue": "",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "secretBodyValue",
|
||||
"initialValue": "",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "secretHeaderValue",
|
||||
"initialValue": "",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "nonExistentValueInSystemEnv",
|
||||
"initialValue": "",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "echoHoppBaseURL",
|
||||
"value": "https://echo.hoppscotch.io",
|
||||
"initialValue": "https://echo.hoppscotch.io",
|
||||
"currentValue": "",
|
||||
"secret": false
|
||||
},
|
||||
{
|
||||
"key": "httpbinBaseURL",
|
||||
"value": "https://httpbin.org",
|
||||
"initialValue": "https://httpbin.org",
|
||||
"currentValue": "",
|
||||
"secret": false
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,50 +1,60 @@
|
|||
{
|
||||
"v": 1,
|
||||
"v": 2,
|
||||
"id": "2",
|
||||
"name": "secret-values-envs",
|
||||
"variables": [
|
||||
{
|
||||
"key": "secretBearerToken",
|
||||
"value": "test-token",
|
||||
"initialValue": "test-token",
|
||||
"currentValue": "test-token",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "secretBasicAuthUsername",
|
||||
"value": "test-user",
|
||||
"initialValue": "test-user",
|
||||
"currentValue": "test-user",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "secretBasicAuthPassword",
|
||||
"value": "test-pass",
|
||||
"initialValue": "test-pass",
|
||||
"currentValue": "test-pass",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "secretQueryParamValue",
|
||||
"value": "secret-query-param-value",
|
||||
"initialValue": "secret-query-param-value",
|
||||
"currentValue": "secret-query-param-value",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "secretBodyValue",
|
||||
"value": "secret-body-value",
|
||||
"initialValue": "secret-body-value",
|
||||
"currentValue": "secret-body-value",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "secretHeaderValue",
|
||||
"value": "secret-header-value",
|
||||
"initialValue": "secret-header-value",
|
||||
"currentValue": "secret-header-value",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "nonExistentValueInSystemEnv",
|
||||
"initialValue": "",
|
||||
"currentValue": "",
|
||||
"secret": true
|
||||
},
|
||||
{
|
||||
"key": "echoHoppBaseURL",
|
||||
"value": "https://echo.hoppscotch.io",
|
||||
"initialValue": "https://echo.hoppscotch.io",
|
||||
"currentValue": "https://echo.hoppscotch.io",
|
||||
"secret": false
|
||||
},
|
||||
{
|
||||
"key": "httpbinBaseURL",
|
||||
"value": "https://httpbin.org",
|
||||
"initialValue": "https://httpbin.org",
|
||||
"currentValue": "https://httpbin.org",
|
||||
"secret": false
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -44,7 +44,12 @@ describe("getters", () => {
|
|||
|
||||
describe("getEffectiveFinalMetaData", () => {
|
||||
const environmentVariables = [
|
||||
{ key: "PARAM", value: "parsed_param", secret: false },
|
||||
{
|
||||
key: "PARAM",
|
||||
initialValue: "parsed_param",
|
||||
currentValue: "parsed_param",
|
||||
secret: false,
|
||||
},
|
||||
];
|
||||
|
||||
test("Empty list of meta-data", () => {
|
||||
|
|
@ -421,27 +426,32 @@ describe("getters", () => {
|
|||
const environmentVariables = [
|
||||
{
|
||||
key: "SHARED_KEY_I",
|
||||
value: "environment-variable-shared-value-I",
|
||||
initialValue: "environment-variable-shared-value-I",
|
||||
currentValue: "environment-variable-shared-value-I",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "SHARED_KEY_II",
|
||||
value: "environment-variable-shared-value-II",
|
||||
initialValue: "environment-variable-shared-value-II",
|
||||
currentValue: "environment-variable-shared-value-II",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "ENV_VAR_III",
|
||||
value: "environment-variable-value-III",
|
||||
initialValue: "environment-variable-value-III",
|
||||
currentValue: "environment-variable-value-III",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "ENV_VAR_IV",
|
||||
value: "environment-variable-value-IV",
|
||||
initialValue: "environment-variable-value-IV",
|
||||
currentValue: "environment-variable-value-IV",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "ENV_VAR_V",
|
||||
value: "environment-variable-value-V",
|
||||
initialValue: "environment-variable-value-V",
|
||||
currentValue: "environment-variable-value-V",
|
||||
secret: false,
|
||||
},
|
||||
];
|
||||
|
|
@ -450,32 +460,38 @@ describe("getters", () => {
|
|||
const expected = [
|
||||
{
|
||||
key: "SHARED_KEY_I",
|
||||
value: "request-variable-shared-value-I",
|
||||
currentValue: "request-variable-shared-value-I",
|
||||
initialValue: "request-variable-shared-value-I",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "REQUEST_VAR_III",
|
||||
value: "request-variable-value-III",
|
||||
currentValue: "request-variable-value-III",
|
||||
initialValue: "request-variable-value-III",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "SHARED_KEY_II",
|
||||
value: "environment-variable-shared-value-II",
|
||||
currentValue: "environment-variable-shared-value-II",
|
||||
initialValue: "environment-variable-shared-value-II",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "ENV_VAR_III",
|
||||
value: "environment-variable-value-III",
|
||||
currentValue: "environment-variable-value-III",
|
||||
initialValue: "environment-variable-value-III",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "ENV_VAR_IV",
|
||||
value: "environment-variable-value-IV",
|
||||
currentValue: "environment-variable-value-IV",
|
||||
initialValue: "environment-variable-value-IV",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "ENV_VAR_V",
|
||||
value: "environment-variable-value-V",
|
||||
currentValue: "environment-variable-value-V",
|
||||
initialValue: "environment-variable-value-V",
|
||||
secret: false,
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -75,7 +75,8 @@ export const test = (pathOrId: string, options: TestCmdOptions) => async () => {
|
|||
(key) =>
|
||||
<IterationDataItem>{
|
||||
key: key,
|
||||
value: iterationDataItem[key],
|
||||
initialValue: iterationDataItem[key],
|
||||
currentValue: iterationDataItem[key],
|
||||
secret: false,
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -60,11 +60,16 @@ export async function parseEnvsData(options: TestCmdEnvironmentOptions) {
|
|||
|
||||
if (HoppEnvKeyPairResult.success) {
|
||||
for (const [key, value] of Object.entries(HoppEnvKeyPairResult.data)) {
|
||||
envPairs.push({ key, value, secret: false });
|
||||
envPairs.push({
|
||||
key,
|
||||
initialValue: value,
|
||||
currentValue: value,
|
||||
secret: false,
|
||||
});
|
||||
}
|
||||
} else if (HoppEnvExportObjectResult.type === "ok") {
|
||||
// Original environment variables from the supplied export file
|
||||
const originalEnvVariables = (contents as NonSecretEnvironment).variables;
|
||||
const originalEnvVariables = (contents as Environment).variables;
|
||||
|
||||
// Above environment variables conforming to the latest schema
|
||||
// `value` fields if specified will be omitted for secret environment variables
|
||||
|
|
@ -73,10 +78,10 @@ export async function parseEnvsData(options: TestCmdEnvironmentOptions) {
|
|||
// The values supplied for secret environment variables have to be considered in the CLI
|
||||
// For each secret environment variable, include the value in case supplied
|
||||
const resolvedEnvVariables = migratedEnvVariables.map((variable, idx) => {
|
||||
if (variable.secret && originalEnvVariables[idx].value) {
|
||||
if (variable.secret && originalEnvVariables[idx].initialValue) {
|
||||
return {
|
||||
...variable,
|
||||
value: originalEnvVariables[idx].value,
|
||||
initialValue: originalEnvVariables[idx].initialValue,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -275,9 +275,15 @@ export const getResolvedVariables = (
|
|||
requestVariables: HoppRESTRequestVariables,
|
||||
environmentVariables: EnvironmentVariable[]
|
||||
): EnvironmentVariable[] => {
|
||||
// Transforming request variables to the shape of environment variables
|
||||
const activeRequestVariables = requestVariables
|
||||
.filter(({ active, value }) => active && value)
|
||||
.map(({ key, value }) => ({ key, value, secret: false }));
|
||||
.map(({ key, value }) => ({
|
||||
key,
|
||||
initialValue: value,
|
||||
currentValue: value,
|
||||
secret: false,
|
||||
}));
|
||||
|
||||
const requestVariableKeys = activeRequestVariables.map(({ key }) => key);
|
||||
|
||||
|
|
@ -286,5 +292,17 @@ export const getResolvedVariables = (
|
|||
({ key }) => !requestVariableKeys.includes(key)
|
||||
);
|
||||
|
||||
return [...activeRequestVariables, ...filteredEnvironmentVariables];
|
||||
// Setting currentValue to initialValue for environment variables
|
||||
// because the exported file might not have the currentValue field
|
||||
const processedEnvironmentVariables = filteredEnvironmentVariables.map(
|
||||
({ key, initialValue, currentValue, secret }) => ({
|
||||
key,
|
||||
initialValue,
|
||||
currentValue:
|
||||
currentValue && currentValue !== "" ? currentValue : initialValue,
|
||||
secret,
|
||||
})
|
||||
);
|
||||
|
||||
return [...activeRequestVariables, ...processedEnvironmentVariables];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -42,8 +42,10 @@ const processVariables = (variable: Environment["variables"][number]) => {
|
|||
if (variable.secret) {
|
||||
return {
|
||||
...variable,
|
||||
value:
|
||||
"value" in variable ? variable.value : process.env[variable.key] || "",
|
||||
currentValue:
|
||||
"currentValue" in variable && variable.currentValue !== ""
|
||||
? variable.currentValue
|
||||
: process.env[variable.key] || "",
|
||||
};
|
||||
}
|
||||
return variable;
|
||||
|
|
|
|||
|
|
@ -340,11 +340,13 @@
|
|||
}
|
||||
},
|
||||
"count": {
|
||||
"currentValue": "Current value {count}",
|
||||
"description": "Description {count}",
|
||||
"header": "Header {count}",
|
||||
"initialValue": "Initial value {count}",
|
||||
"key": "Key {count}",
|
||||
"message": "Message {count}",
|
||||
"parameter": "Parameter {count}",
|
||||
"key": "Key {count}",
|
||||
"description": "Description {count}",
|
||||
"protocol": "Protocol {count}",
|
||||
"value": "Value {count}",
|
||||
"variable": "Variable {count}"
|
||||
|
|
|
|||
|
|
@ -70,7 +70,6 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Environment } from "@hoppscotch/data"
|
||||
import { useService } from "dioc/vue"
|
||||
import * as TE from "fp-ts/TaskEither"
|
||||
import { pipe } from "fp-ts/function"
|
||||
|
|
@ -80,17 +79,20 @@ import { useToast } from "~/composables/toast"
|
|||
import { GQLError } from "~/helpers/backend/GQLClient"
|
||||
import { updateTeamEnvironment } from "~/helpers/backend/mutations/TeamEnvironment"
|
||||
import { getEnvActionErrorMessage } from "~/helpers/error-messages"
|
||||
import { TeamEnvironment } from "~/helpers/teams/TeamEnvironment"
|
||||
import {
|
||||
addEnvironmentVariable,
|
||||
addGlobalEnvVariable,
|
||||
setGlobalEnvVariables,
|
||||
updateEnvironment,
|
||||
} from "~/newstore/environments"
|
||||
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||
import { RESTTabService } from "~/services/tab/rest"
|
||||
import { Scope } from "./Selector.vue"
|
||||
import { GlobalEnvironment } from "@hoppscotch/data"
|
||||
|
||||
const t = useI18n()
|
||||
const toast = useToast()
|
||||
|
||||
const tabs = useService(RESTTabService)
|
||||
const currentEnvironmentValueService = useService(CurrentValueService)
|
||||
|
||||
const props = defineProps<{
|
||||
show: boolean
|
||||
|
|
@ -113,6 +115,7 @@ watch(
|
|||
if (!newVal) {
|
||||
scope.value = {
|
||||
type: "global",
|
||||
variables: [],
|
||||
}
|
||||
replaceWithVariable.value = false
|
||||
editingName.value = ""
|
||||
|
|
@ -123,22 +126,9 @@ watch(
|
|||
}
|
||||
)
|
||||
|
||||
type Scope =
|
||||
| {
|
||||
type: "global"
|
||||
}
|
||||
| {
|
||||
type: "my-environment"
|
||||
environment: Environment
|
||||
index: number
|
||||
}
|
||||
| {
|
||||
type: "team-environment"
|
||||
environment: TeamEnvironment
|
||||
}
|
||||
|
||||
const scope = ref<Scope>({
|
||||
type: "global",
|
||||
variables: [],
|
||||
})
|
||||
|
||||
const replaceWithVariable = ref(false)
|
||||
|
|
@ -152,27 +142,67 @@ const addEnvironment = async () => {
|
|||
return
|
||||
}
|
||||
if (scope.value.type === "global") {
|
||||
addGlobalEnvVariable({
|
||||
const newVariables = [
|
||||
...scope.value.variables,
|
||||
{
|
||||
key: editingName.value,
|
||||
initialValue: editingValue.value,
|
||||
currentValue: "",
|
||||
secret: false,
|
||||
},
|
||||
]
|
||||
|
||||
const newEnv: GlobalEnvironment = {
|
||||
v: 2,
|
||||
variables: newVariables,
|
||||
}
|
||||
|
||||
setGlobalEnvVariables(newEnv)
|
||||
currentEnvironmentValueService.addEnvironmentVariable("Global", {
|
||||
key: editingName.value,
|
||||
value: editingValue.value,
|
||||
secret: false,
|
||||
currentValue: editingValue.value,
|
||||
isSecret: false,
|
||||
varIndex: scope.value.variables.length,
|
||||
})
|
||||
toast.success(`${t("environment.updated")}`)
|
||||
} else if (scope.value.type === "my-environment") {
|
||||
addEnvironmentVariable(scope.value.index, {
|
||||
key: editingName.value,
|
||||
value: editingValue.value,
|
||||
secret: false,
|
||||
})
|
||||
const newVariables = [
|
||||
...scope.value.environment.variables,
|
||||
{
|
||||
key: editingName.value,
|
||||
initialValue: editingValue.value,
|
||||
currentValue: "",
|
||||
secret: false,
|
||||
},
|
||||
]
|
||||
|
||||
const newEnv = {
|
||||
...scope.value.environment,
|
||||
variables: newVariables,
|
||||
}
|
||||
|
||||
updateEnvironment(scope.value.index, newEnv)
|
||||
currentEnvironmentValueService.addEnvironmentVariable(
|
||||
scope.value.environment.id,
|
||||
{
|
||||
key: editingName.value,
|
||||
currentValue: editingValue.value,
|
||||
isSecret: false,
|
||||
varIndex: scope.value.environment.variables.length,
|
||||
}
|
||||
)
|
||||
toast.success(`${t("environment.updated")}`)
|
||||
} else {
|
||||
const newVariables = [
|
||||
...scope.value.environment.environment.variables,
|
||||
{
|
||||
key: editingName.value,
|
||||
value: editingValue.value,
|
||||
initialValue: editingValue.value,
|
||||
currentValue: "",
|
||||
secret: false,
|
||||
},
|
||||
]
|
||||
|
||||
await pipe(
|
||||
updateTeamEnvironment(
|
||||
JSON.stringify(newVariables),
|
||||
|
|
@ -185,6 +215,18 @@ const addEnvironment = async () => {
|
|||
toast.error(t(getEnvActionErrorMessage(err)))
|
||||
},
|
||||
() => {
|
||||
if (scope.value.type === "team-environment") {
|
||||
currentEnvironmentValueService.addEnvironmentVariable(
|
||||
scope.value.environment.id,
|
||||
{
|
||||
key: editingName.value,
|
||||
currentValue: editingValue.value,
|
||||
isSecret: false,
|
||||
varIndex:
|
||||
scope.value.environment.environment.variables.length - 1,
|
||||
}
|
||||
)
|
||||
}
|
||||
hideModal()
|
||||
toast.success(`${t("environment.updated")}`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ const insomniaEnvironmentsImport: ImporterOrExporter = {
|
|||
disabled: false,
|
||||
},
|
||||
component: FileSource({
|
||||
acceptedFileTypes: "application/json",
|
||||
acceptedFileTypes: ".json, .yaml, .yml",
|
||||
caption: "import.insomnia_environment_description",
|
||||
onImportFromFile: async (environments) => {
|
||||
isInsomniaImporterInProgress.value = true
|
||||
|
|
@ -362,8 +362,8 @@ const handleImportToStore = async (
|
|||
) => {
|
||||
// Add global envs to the store
|
||||
globalEnvs.forEach(({ variables }) => {
|
||||
variables.forEach(({ key, value, secret }) => {
|
||||
addGlobalEnvVariable({ key, value, secret })
|
||||
variables.forEach(({ key, initialValue, currentValue, secret }) => {
|
||||
addGlobalEnvVariable({ key, initialValue, currentValue, secret })
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@
|
|||
() => {
|
||||
$emit('update:modelValue', {
|
||||
type: 'global',
|
||||
variables: globalVals.variables,
|
||||
})
|
||||
hide()
|
||||
}
|
||||
|
|
@ -245,7 +246,7 @@
|
|||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-for="(variable, index) in globalEnvs.variables"
|
||||
v-for="(variable, index) in globalEnvs"
|
||||
:key="index"
|
||||
class="flex flex-1 space-x-4"
|
||||
>
|
||||
|
|
@ -255,14 +256,11 @@
|
|||
<span class="min-w-[9rem] w-full truncate text-secondaryLight">
|
||||
<template v-if="variable.secret"> ******** </template>
|
||||
<template v-else>
|
||||
{{ variable.value }}
|
||||
{{ variable.currentValue }}
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="globalEnvs.variables.length === 0"
|
||||
class="text-secondaryLight"
|
||||
>
|
||||
<div v-if="globalEnvs.length === 0" class="text-secondaryLight">
|
||||
{{ t("environment.empty_variables") }}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -316,7 +314,7 @@
|
|||
<span class="min-w-[9rem] w-full truncate text-secondaryLight">
|
||||
<template v-if="variable.secret"> ******** </template>
|
||||
<template v-else>
|
||||
{{ variable.value }}
|
||||
{{ variable.currentValue }}
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -359,6 +357,7 @@ import {
|
|||
setSelectedEnvironmentIndex,
|
||||
} from "~/newstore/environments"
|
||||
import { useLocalState } from "~/newstore/localstate"
|
||||
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||
import { WorkspaceService } from "~/services/workspace.service"
|
||||
import IconCheck from "~icons/lucide/check"
|
||||
import IconEdit from "~icons/lucide/edit"
|
||||
|
|
@ -366,9 +365,10 @@ import IconEye from "~icons/lucide/eye"
|
|||
import IconGlobe from "~icons/lucide/globe"
|
||||
import IconLayers from "~icons/lucide/layers"
|
||||
|
||||
type Scope =
|
||||
export type Scope =
|
||||
| {
|
||||
type: "global"
|
||||
variables: GlobalEnvironment["variables"]
|
||||
}
|
||||
| {
|
||||
type: "my-environment"
|
||||
|
|
@ -403,6 +403,8 @@ const myEnvironments = useReadonlyStream(environments$, [])
|
|||
const workspaceService = useService(WorkspaceService)
|
||||
const workspace = workspaceService.currentWorkspace
|
||||
|
||||
const currentEnvironmentValueService = useService(CurrentValueService)
|
||||
|
||||
// TeamList-Adapter
|
||||
const teamListAdapter = workspaceService.acquireTeamListAdapter(null)
|
||||
const myTeams = useReadonlyStream(teamListAdapter.teamList$, null)
|
||||
|
|
@ -577,6 +579,7 @@ const selectedEnv = computed(() => {
|
|||
index: props.modelValue.index,
|
||||
name: props.modelValue.environment?.name,
|
||||
variables: props.modelValue.environment?.variables,
|
||||
id: props.modelValue.environment.id,
|
||||
}
|
||||
} else if (props.modelValue?.type === "team-environment") {
|
||||
return {
|
||||
|
|
@ -584,11 +587,13 @@ const selectedEnv = computed(() => {
|
|||
name: props.modelValue.environment.environment.name,
|
||||
teamEnvID: props.modelValue.environment.id,
|
||||
variables: props.modelValue.environment.environment.variables,
|
||||
id: props.modelValue.environment.id,
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: "global",
|
||||
name: "Global",
|
||||
variables: globalVals.value.variables,
|
||||
}
|
||||
}
|
||||
if (selectedEnvironmentIndex.value.type === "MY_ENV") {
|
||||
|
|
@ -599,6 +604,7 @@ const selectedEnv = computed(() => {
|
|||
index: selectedEnvironmentIndex.value.index,
|
||||
name: environment.name,
|
||||
variables: environment.variables,
|
||||
id: environment.id,
|
||||
}
|
||||
} else if (selectedEnvironmentIndex.value.type === "TEAM_ENV") {
|
||||
const teamEnv = teamEnvironmentList.value.find(
|
||||
|
|
@ -613,6 +619,7 @@ const selectedEnv = computed(() => {
|
|||
name: teamEnv.environment.name,
|
||||
teamEnvID: selectedEnvironmentIndex.value.teamEnvID,
|
||||
variables: teamEnv.environment.variables,
|
||||
id: teamEnv.id,
|
||||
}
|
||||
}
|
||||
return { type: "NO_ENV_SELECTED" }
|
||||
|
|
@ -653,6 +660,7 @@ onMounted(() => {
|
|||
} else {
|
||||
emit("update:modelValue", {
|
||||
type: "global",
|
||||
variables: globalVals.value.variables,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -662,11 +670,29 @@ onMounted(() => {
|
|||
const envSelectorActions = ref<TippyComponent | null>(null)
|
||||
const envQuickPeekActions = ref<TippyComponent | null>(null)
|
||||
|
||||
const globalEnvs = useReadonlyStream(globalEnv$, {} as GlobalEnvironment)
|
||||
const globalVals = useReadonlyStream(globalEnv$, {} as GlobalEnvironment)
|
||||
|
||||
const globalEnvs = computed(() => {
|
||||
return globalVals.value.variables.map((variable, index) => ({
|
||||
...variable,
|
||||
currentValue:
|
||||
currentEnvironmentValueService.getEnvironmentVariableValue(
|
||||
"Global",
|
||||
index
|
||||
) ?? "",
|
||||
}))
|
||||
})
|
||||
|
||||
const environmentVariables = computed(() => {
|
||||
if (selectedEnv.value.variables) {
|
||||
return selectedEnv.value.variables
|
||||
if (selectedEnv.value.variables && selectedEnv.value.id) {
|
||||
return selectedEnv.value.variables.map((variable, index) => ({
|
||||
...variable,
|
||||
currentValue:
|
||||
currentEnvironmentValueService.getEnvironmentVariableValue(
|
||||
selectedEnv.value.id ?? "",
|
||||
index
|
||||
) ?? "",
|
||||
}))
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ const environmentType = ref<EnvironmentsChooseType>({
|
|||
const globalEnv = useReadonlyStream(globalEnv$, {} as GlobalEnvironment)
|
||||
|
||||
const globalEnvironment = computed<Environment>(() => ({
|
||||
v: 1 as const,
|
||||
v: 2 as const,
|
||||
id: "Global",
|
||||
name: "Global",
|
||||
variables: globalEnv.value.variables,
|
||||
|
|
@ -177,6 +177,7 @@ watch(
|
|||
// if navigating away from a team workspace
|
||||
if (
|
||||
selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
|
||||
newTeamID &&
|
||||
selectedEnvironmentIndex.value.teamID !== newTeamID
|
||||
) {
|
||||
setSelectedEnvironmentIndex({
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
v-if="show"
|
||||
dialog
|
||||
:title="t(`environment.${action}`)"
|
||||
styles="sm:max-w-3xl"
|
||||
@close="hideModal"
|
||||
>
|
||||
<template #body>
|
||||
|
|
@ -74,7 +75,7 @@
|
|||
<template v-else>
|
||||
<div
|
||||
v-for="({ id, env }, index) in tab.variables"
|
||||
:key="`variable-${id}-${index}`"
|
||||
:key="`${tab.id}-${id}-${index}`"
|
||||
class="flex divide-x divide-dividerLight"
|
||||
>
|
||||
<input
|
||||
|
|
@ -84,13 +85,23 @@
|
|||
:placeholder="`${t('count.variable', {
|
||||
count: index + 1,
|
||||
})}`"
|
||||
:name="'param' + index"
|
||||
:name="'variable' + index"
|
||||
/>
|
||||
<SmartEnvInput
|
||||
v-model="env.value"
|
||||
:placeholder="`${t('count.value', { count: index + 1 })}`"
|
||||
v-model="env.initialValue"
|
||||
:placeholder="`${t('count.initialValue', { count: index + 1 })}`"
|
||||
:envs="liveEnvs"
|
||||
:name="'value' + index"
|
||||
:name="'initialValue' + index"
|
||||
:secret="tab.isSecret"
|
||||
:select-text-on-mount="
|
||||
env.key ? env.key === editingVariableName : false
|
||||
"
|
||||
/>
|
||||
<SmartEnvInput
|
||||
v-model="env.currentValue"
|
||||
:placeholder="`${t('count.currentValue', { count: index + 1 })}`"
|
||||
:envs="liveEnvs"
|
||||
:name="'currentValue' + index"
|
||||
:secret="tab.isSecret"
|
||||
:select-text-on-mount="
|
||||
env.key ? env.key === editingVariableName : false
|
||||
|
|
@ -162,6 +173,7 @@ import {
|
|||
updateEnvironment,
|
||||
} from "~/newstore/environments"
|
||||
import { platform } from "~/platform"
|
||||
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||
import { SecretEnvironmentService } from "~/services/secret-environment.service"
|
||||
import IconDone from "~icons/lucide/check"
|
||||
import IconHelpCircle from "~icons/lucide/help-circle"
|
||||
|
|
@ -171,11 +183,7 @@ import IconTrash2 from "~icons/lucide/trash-2"
|
|||
|
||||
type EnvironmentVariable = {
|
||||
id: number
|
||||
env: {
|
||||
value: string
|
||||
key: string
|
||||
secret: boolean
|
||||
}
|
||||
env: Environment["variables"][number]
|
||||
}
|
||||
|
||||
const t = useI18n()
|
||||
|
|
@ -237,10 +245,14 @@ const tabsData: ComputedRef<
|
|||
const editingName = ref<string | null>(null)
|
||||
const editingID = ref<string>("")
|
||||
const vars = ref<EnvironmentVariable[]>([
|
||||
{ id: idTicker.value++, env: { key: "", value: "", secret: false } },
|
||||
{
|
||||
id: idTicker.value++,
|
||||
env: { key: "", currentValue: "", initialValue: "", secret: false },
|
||||
},
|
||||
])
|
||||
|
||||
const secretEnvironmentService = useService(SecretEnvironmentService)
|
||||
const currentEnvironmentValueService = useService(CurrentValueService)
|
||||
|
||||
const secretVars = computed(() =>
|
||||
pipe(
|
||||
|
|
@ -302,8 +314,9 @@ const evnExpandError = computed(() => {
|
|||
|
||||
return pipe(
|
||||
variables,
|
||||
A.filter(({ secret }) => !secret),
|
||||
A.exists(({ value }) => E.isLeft(parseTemplateStringE(value, variables)))
|
||||
A.exists(({ currentValue }) =>
|
||||
E.isLeft(parseTemplateStringE(currentValue, variables))
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
|
|
@ -314,12 +327,12 @@ const liveEnvs = computed(() => {
|
|||
|
||||
if (props.editingEnvironmentIndex === "Global") {
|
||||
return [
|
||||
...vars.value.map((x) => ({ ...x.env, source: editingName.value! })),
|
||||
...vars.value.map((x) => ({ ...x.env, sourceEnv: editingName.value! })),
|
||||
]
|
||||
}
|
||||
return [
|
||||
...vars.value.map((x) => ({ ...x.env, source: editingName.value! })),
|
||||
...globalEnv.value.variables.map((x) => ({ ...x, source: "Global" })),
|
||||
...vars.value.map((x) => ({ ...x.env, sourceEnv: editingName.value! })),
|
||||
...globalEnv.value.variables.map((x) => ({ ...x, sourceEnv: "Global" })),
|
||||
]
|
||||
})
|
||||
|
||||
|
|
@ -333,6 +346,16 @@ const workingEnvID = computed(() => {
|
|||
return uniqueID()
|
||||
})
|
||||
|
||||
const getCurrentValue = (id: string | "Global", varIndex: number) => {
|
||||
const env = workingEnv.value?.variables[varIndex]
|
||||
if (env && env.secret) {
|
||||
return secretEnvironmentService.getSecretEnvironmentVariable(id, varIndex)
|
||||
?.value
|
||||
}
|
||||
return currentEnvironmentValueService.getEnvironmentVariable(id, varIndex)
|
||||
?.currentValue
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.show,
|
||||
(show) => {
|
||||
|
|
@ -351,17 +374,14 @@ watch(
|
|||
id: idTicker.value++,
|
||||
env: {
|
||||
key: e.key,
|
||||
value: e.secret
|
||||
? (secretEnvironmentService.getSecretEnvironmentVariable(
|
||||
props.editingEnvironmentIndex === "Global"
|
||||
? "Global"
|
||||
: workingEnvID.value,
|
||||
index
|
||||
)?.value ??
|
||||
// @ts-expect-error `value` field can exist for secret environment variables as inferred while importing
|
||||
e.value ??
|
||||
"")
|
||||
: e.value,
|
||||
currentValue:
|
||||
getCurrentValue(
|
||||
props.editingEnvironmentIndex === "Global"
|
||||
? "Global"
|
||||
: workingEnvID.value,
|
||||
index
|
||||
) ?? "",
|
||||
initialValue: e.initialValue,
|
||||
secret: e.secret,
|
||||
},
|
||||
}))
|
||||
|
|
@ -384,7 +404,8 @@ const addEnvironmentVariable = () => {
|
|||
id: idTicker.value++,
|
||||
env: {
|
||||
key: "",
|
||||
value: "",
|
||||
currentValue: "",
|
||||
initialValue: "",
|
||||
secret: selectedEnvOption.value === "secret",
|
||||
},
|
||||
})
|
||||
|
|
@ -421,26 +442,75 @@ const saveEnvironment = () => {
|
|||
const secretVariables = pipe(
|
||||
filteredVariables,
|
||||
A.filterMapWithIndex((i, e) =>
|
||||
e.secret ? O.some({ key: e.key, value: e.value, varIndex: i }) : O.none
|
||||
e.secret
|
||||
? O.some({
|
||||
key: e.key,
|
||||
value: e.currentValue,
|
||||
varIndex: i,
|
||||
})
|
||||
: O.none
|
||||
)
|
||||
)
|
||||
|
||||
if (editingID.value) {
|
||||
secretEnvironmentService.addSecretEnvironment(
|
||||
editingID.value,
|
||||
secretVariables
|
||||
const nonSecretVariables = pipe(
|
||||
filteredVariables,
|
||||
A.filterMapWithIndex((i, e) =>
|
||||
!e.secret
|
||||
? O.some({
|
||||
key: e.key,
|
||||
currentValue: e.currentValue,
|
||||
varIndex: i,
|
||||
isSecret: e.secret,
|
||||
})
|
||||
: O.none
|
||||
)
|
||||
} else if (props.editingEnvironmentIndex === "Global") {
|
||||
secretEnvironmentService.addSecretEnvironment("Global", secretVariables)
|
||||
)
|
||||
|
||||
if (secretVariables.length > 0) {
|
||||
if (editingID.value) {
|
||||
secretEnvironmentService.addSecretEnvironment(
|
||||
editingID.value,
|
||||
secretVariables
|
||||
)
|
||||
} else if (props.editingEnvironmentIndex === "Global") {
|
||||
secretEnvironmentService.addSecretEnvironment("Global", secretVariables)
|
||||
}
|
||||
}
|
||||
if (nonSecretVariables.length > 0) {
|
||||
if (editingID.value) {
|
||||
currentEnvironmentValueService.addEnvironment(
|
||||
editingID.value,
|
||||
nonSecretVariables
|
||||
)
|
||||
} else if (props.editingEnvironmentIndex === "Global") {
|
||||
currentEnvironmentValueService.addEnvironment(
|
||||
"Global",
|
||||
nonSecretVariables
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const variables = pipe(
|
||||
filteredVariables,
|
||||
A.map((e) => (e.secret ? { key: e.key, secret: e.secret } : e))
|
||||
A.map((e) =>
|
||||
e.secret
|
||||
? {
|
||||
key: e.key,
|
||||
secret: e.secret,
|
||||
initialValue: e.initialValue,
|
||||
currentValue: "",
|
||||
}
|
||||
: {
|
||||
key: e.key,
|
||||
secret: e.secret,
|
||||
initialValue: e.initialValue,
|
||||
currentValue: "",
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
const environmentUpdated: Environment = {
|
||||
v: 1,
|
||||
v: 2,
|
||||
id: uniqueID(),
|
||||
name: editingName.value,
|
||||
variables,
|
||||
|
|
|
|||
|
|
@ -155,6 +155,7 @@ import IconCopy from "~icons/lucide/copy"
|
|||
import IconEdit from "~icons/lucide/edit"
|
||||
import IconMoreVertical from "~icons/lucide/more-vertical"
|
||||
import IconTrash2 from "~icons/lucide/trash-2"
|
||||
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||
|
||||
const t = useI18n()
|
||||
const toast = useToast()
|
||||
|
|
@ -183,6 +184,7 @@ const emit = defineEmits<{
|
|||
const confirmRemove = ref(false)
|
||||
|
||||
const secretEnvironmentService = useService(SecretEnvironmentService)
|
||||
const currentEnvironmentValueService = useService(CurrentValueService)
|
||||
|
||||
watch(
|
||||
() => props.duplicateGlobalEnvironmentLoading,
|
||||
|
|
@ -216,6 +218,7 @@ const removeEnvironment = () => {
|
|||
if (!isGlobalEnvironment.value) {
|
||||
deleteEnvironment(props.environmentIndex as number, props.environment.id)
|
||||
secretEnvironmentService.deleteSecretEnvironment(props.environment.id)
|
||||
currentEnvironmentValueService.deleteEnvironment(props.environment.id)
|
||||
}
|
||||
toast.success(`${t("state.deleted")}`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
v-if="show"
|
||||
dialog
|
||||
:title="t(`environment.${action}`)"
|
||||
styles="sm:max-w-3xl"
|
||||
@close="hideModal"
|
||||
>
|
||||
<template #body>
|
||||
|
|
@ -91,15 +92,24 @@
|
|||
:disabled="isViewer"
|
||||
/>
|
||||
<SmartEnvInput
|
||||
v-model="env.value"
|
||||
v-model="env.initialValue"
|
||||
:placeholder="`${t('count.initialValue', { count: index + 1 })}`"
|
||||
:envs="liveEnvs"
|
||||
:name="'initialValue' + index"
|
||||
:secret="tab.isSecret"
|
||||
:select-text-on-mount="
|
||||
env.key ? env.key === editingVariableName : false
|
||||
"
|
||||
:placeholder="`${t('count.value', { count: index + 1 })}`"
|
||||
/>
|
||||
<SmartEnvInput
|
||||
v-model="env.currentValue"
|
||||
:placeholder="`${t('count.currentValue', { count: index + 1 })}`"
|
||||
:envs="liveEnvs"
|
||||
:name="'value' + index"
|
||||
:name="'currentValue' + index"
|
||||
:secret="tab.isSecret"
|
||||
:readonly="isViewer && !tab.isSecret"
|
||||
:select-text-on-mount="
|
||||
env.key ? env.key === editingVariableName : false
|
||||
"
|
||||
/>
|
||||
<div v-if="!isViewer" class="flex">
|
||||
<HoppButtonSecondary
|
||||
|
|
@ -166,14 +176,11 @@ import { platform } from "~/platform"
|
|||
import { useService } from "dioc/vue"
|
||||
import { SecretEnvironmentService } from "~/services/secret-environment.service"
|
||||
import { getEnvActionErrorMessage } from "~/helpers/error-messages"
|
||||
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||
|
||||
type EnvironmentVariable = {
|
||||
id: number
|
||||
env: {
|
||||
key: string
|
||||
value: string
|
||||
secret: boolean
|
||||
}
|
||||
env: Environment["variables"][number]
|
||||
}
|
||||
|
||||
const t = useI18n()
|
||||
|
|
@ -239,10 +246,14 @@ const tabsData: ComputedRef<
|
|||
const editingName = ref<string | null>(null)
|
||||
const editingID = ref<string | null>(null)
|
||||
const vars = ref<EnvironmentVariable[]>([
|
||||
{ id: idTicker.value++, env: { key: "", value: "", secret: false } },
|
||||
{
|
||||
id: idTicker.value++,
|
||||
env: { key: "", currentValue: "", initialValue: "", secret: false },
|
||||
},
|
||||
])
|
||||
|
||||
const secretEnvironmentService = useService(SecretEnvironmentService)
|
||||
const currentEnvironmentValueService = useService(CurrentValueService)
|
||||
|
||||
const secretVars = computed(() =>
|
||||
pipe(
|
||||
|
|
@ -275,7 +286,9 @@ const evnExpandError = computed(() => {
|
|||
|
||||
return pipe(
|
||||
variables,
|
||||
A.exists(({ value }) => E.isLeft(parseTemplateStringE(value, variables)))
|
||||
A.exists(({ currentValue }) =>
|
||||
E.isLeft(parseTemplateStringE(currentValue, variables))
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
|
|
@ -283,9 +296,28 @@ const liveEnvs = computed(() => {
|
|||
if (evnExpandError.value) {
|
||||
return []
|
||||
}
|
||||
return [...vars.value.map((x) => ({ ...x.env, source: editingName.value! }))]
|
||||
return [
|
||||
...vars.value.map((x) => ({ ...x.env, sourceEnv: editingName.value! })),
|
||||
]
|
||||
})
|
||||
|
||||
const getCurrentValue = (
|
||||
editingID: string,
|
||||
varIndex: number,
|
||||
isSecret: boolean
|
||||
) => {
|
||||
if (isSecret) {
|
||||
return secretEnvironmentService.getSecretEnvironmentVariable(
|
||||
editingID,
|
||||
varIndex
|
||||
)?.value
|
||||
}
|
||||
return currentEnvironmentValueService.getEnvironmentVariable(
|
||||
editingID,
|
||||
varIndex
|
||||
)?.currentValue
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.show,
|
||||
(show) => {
|
||||
|
|
@ -310,15 +342,13 @@ watch(
|
|||
id: idTicker.value++,
|
||||
env: {
|
||||
key: e.key,
|
||||
value: e.secret
|
||||
? (secretEnvironmentService.getSecretEnvironmentVariable(
|
||||
editingID.value ?? "",
|
||||
index
|
||||
)?.value ??
|
||||
// @ts-expect-error `value` field can exist for secret environment variables as inferred while importing
|
||||
e.value ??
|
||||
"")
|
||||
: e.value,
|
||||
currentValue:
|
||||
getCurrentValue(
|
||||
props.editingEnvironment?.id ?? "",
|
||||
index,
|
||||
e.secret
|
||||
) ?? "",
|
||||
initialValue: e.initialValue,
|
||||
secret: e.secret,
|
||||
},
|
||||
}))
|
||||
|
|
@ -339,7 +369,8 @@ const addEnvironmentVariable = () => {
|
|||
id: idTicker.value++,
|
||||
env: {
|
||||
key: "",
|
||||
value: "",
|
||||
currentValue: "",
|
||||
initialValue: "",
|
||||
secret: selectedEnvOption.value === "secret",
|
||||
},
|
||||
})
|
||||
|
|
@ -377,17 +408,38 @@ const saveEnvironment = async () => {
|
|||
const secretVariables = pipe(
|
||||
filteredVariables,
|
||||
A.filterMapWithIndex((i, e) =>
|
||||
e.secret ? O.some({ key: e.key, value: e.value, varIndex: i }) : O.none
|
||||
e.secret
|
||||
? O.some({ key: e.key, value: e.currentValue, varIndex: i })
|
||||
: O.none
|
||||
)
|
||||
)
|
||||
|
||||
const nonSecretVariables = pipe(
|
||||
filteredVariables,
|
||||
A.filterMapWithIndex((i, e) =>
|
||||
!e.secret
|
||||
? O.some({
|
||||
key: e.key,
|
||||
currentValue: e.currentValue,
|
||||
varIndex: i,
|
||||
isSecret: e.secret,
|
||||
})
|
||||
: O.none
|
||||
)
|
||||
)
|
||||
|
||||
const variables = pipe(
|
||||
filteredVariables,
|
||||
A.map((e) => (e.secret ? { key: e.key, secret: e.secret } : e))
|
||||
A.map((e) => ({
|
||||
key: e.key,
|
||||
secret: e.secret,
|
||||
initialValue: e.initialValue,
|
||||
currentValue: "",
|
||||
}))
|
||||
)
|
||||
|
||||
const environmentUpdated: Environment = {
|
||||
v: 1,
|
||||
v: 2,
|
||||
id: editingID.value ?? "",
|
||||
name: editingName.value,
|
||||
variables,
|
||||
|
|
@ -419,6 +471,10 @@ const saveEnvironment = async () => {
|
|||
envID,
|
||||
secretVariables
|
||||
)
|
||||
currentEnvironmentValueService.addEnvironment(
|
||||
envID,
|
||||
nonSecretVariables
|
||||
)
|
||||
}
|
||||
hideModal()
|
||||
toast.success(`${t("environment.created")}`)
|
||||
|
|
@ -463,7 +519,14 @@ const saveEnvironment = async () => {
|
|||
() => {
|
||||
hideModal()
|
||||
toast.success(`${t("environment.updated")}`)
|
||||
|
||||
isLoading.value = false
|
||||
if (editingID.value) {
|
||||
currentEnvironmentValueService.addEnvironment(
|
||||
editingID.value,
|
||||
nonSecretVariables
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
)()
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ import IconEdit from "~icons/lucide/edit"
|
|||
import IconMoreVertical from "~icons/lucide/more-vertical"
|
||||
import IconSettings2 from "~icons/lucide/settings-2"
|
||||
import IconTrash2 from "~icons/lucide/trash-2"
|
||||
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||
|
||||
const t = useI18n()
|
||||
const toast = useToast()
|
||||
|
|
@ -183,6 +184,7 @@ const emit = defineEmits<{
|
|||
}>()
|
||||
|
||||
const secretEnvironmentService = useService(SecretEnvironmentService)
|
||||
const currentEnvironmentValueService = useService(CurrentValueService)
|
||||
|
||||
const confirmRemove = ref(false)
|
||||
|
||||
|
|
@ -214,6 +216,7 @@ const removeEnvironment = () => {
|
|||
() => {
|
||||
toast.success(`${t("team_environment.deleted")}`)
|
||||
secretEnvironmentService.deleteSecretEnvironment(props.environment.id)
|
||||
currentEnvironmentValueService.deleteEnvironment(props.environment.id)
|
||||
}
|
||||
)
|
||||
)()
|
||||
|
|
|
|||
|
|
@ -269,7 +269,6 @@ import linter from "~/helpers/editor/linting/rawKeyValue"
|
|||
import { throwError } from "~/helpers/functional/error"
|
||||
import { objRemoveKey } from "~/helpers/functional/object"
|
||||
import { commonHeaders } from "~/helpers/headers"
|
||||
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
|
||||
import {
|
||||
ComputedHeader,
|
||||
getComputedAuthHeaders,
|
||||
|
|
@ -279,6 +278,7 @@ import {
|
|||
AggregateEnvironment,
|
||||
aggregateEnvs$,
|
||||
getAggregateEnvs,
|
||||
getCurrentEnvironment,
|
||||
} from "~/newstore/environments"
|
||||
import { toggleNestedSetting } from "~/newstore/settings"
|
||||
import { InspectionService, InspectorResult } from "~/services/inspection"
|
||||
|
|
@ -294,6 +294,8 @@ import IconPlus from "~icons/lucide/plus"
|
|||
import IconTrash2 from "~icons/lucide/trash-2"
|
||||
import IconWrapText from "~icons/lucide/wrap-text"
|
||||
import { RESTOptionTabs } from "./RequestOptions.vue"
|
||||
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
|
||||
|
||||
const t = useI18n()
|
||||
const toast = useToast()
|
||||
|
|
@ -311,6 +313,8 @@ const WRAP_LINES = useNestedSetting("WRAP_LINES", "httpHeaders")
|
|||
|
||||
const deletionToast = ref<{ goAway: (delay: number) => void } | null>(null)
|
||||
|
||||
const currentEnvironmentValueService = useService(CurrentValueService)
|
||||
|
||||
// v-model integration with props and emit
|
||||
const props = defineProps<{
|
||||
modelValue:
|
||||
|
|
@ -554,9 +558,25 @@ const computedHeaders: Ref<
|
|||
}[]
|
||||
> = ref([])
|
||||
|
||||
const currentSelectedEnvironment = getCurrentEnvironment()
|
||||
|
||||
watch([props.modelValue, aggregateEnvs], async () => {
|
||||
const resolvedEnvs = aggregateEnvs.value.map((env) => {
|
||||
return {
|
||||
...env,
|
||||
currentValue:
|
||||
env.currentValue !== ""
|
||||
? env.currentValue
|
||||
: (currentEnvironmentValueService.getEnvironmentByKey(
|
||||
env?.sourceEnv !== "Global"
|
||||
? currentSelectedEnvironment.id
|
||||
: "Global",
|
||||
env?.key ?? ""
|
||||
)?.currentValue ?? ""),
|
||||
}
|
||||
})
|
||||
computedHeaders.value = (
|
||||
await getComputedHeaders(props.modelValue, aggregateEnvs.value, false)
|
||||
await getComputedHeaders(props.modelValue, resolvedEnvs, true)
|
||||
).map((header, index) => ({
|
||||
id: `header-${index}`,
|
||||
...header,
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@
|
|||
>
|
||||
<input
|
||||
v-if="isSecret"
|
||||
id="secret"
|
||||
:id="`secret-${uniqueID()}`"
|
||||
v-model="secretText"
|
||||
name="secret"
|
||||
:placeholder="t('environment.secret_value')"
|
||||
:placeholder="placeholder"
|
||||
class="flex flex-1 bg-transparent pl-4"
|
||||
:class="styles"
|
||||
type="password"
|
||||
|
|
@ -97,6 +97,7 @@ import { CompletionContext, autocompletion } from "@codemirror/autocomplete"
|
|||
import { useService } from "dioc/vue"
|
||||
import { RESTTabService } from "~/services/tab/rest"
|
||||
import { syntaxTree } from "@codemirror/language"
|
||||
import { uniqueID } from "~/helpers/utils/uniqueID"
|
||||
|
||||
const t = useI18n()
|
||||
|
||||
|
|
@ -374,11 +375,13 @@ const envVars = computed(() => {
|
|||
if (props.envs) {
|
||||
return props.envs.map((x) => {
|
||||
const { key, secret } = x
|
||||
const value = secret ? "********" : x.value
|
||||
const currentValue = secret ? "********" : x.currentValue
|
||||
const initialValue = secret ? "********" : x.initialValue
|
||||
const sourceEnv = "sourceEnv" in x ? x.sourceEnv : null
|
||||
return {
|
||||
key,
|
||||
value,
|
||||
currentValue,
|
||||
initialValue,
|
||||
sourceEnv,
|
||||
secret,
|
||||
}
|
||||
|
|
@ -393,12 +396,14 @@ const envVars = computed(() => {
|
|||
? tabs.currentActiveTab.value.document.request.requestVariables
|
||||
: []
|
||||
|
||||
// Transform request variables to match the env format
|
||||
return [
|
||||
...requestVariables.map(({ active, key, value }) =>
|
||||
active
|
||||
? {
|
||||
key,
|
||||
value,
|
||||
currentValue: value,
|
||||
initialValue: value,
|
||||
sourceEnv: "RequestVariable",
|
||||
secret: false,
|
||||
}
|
||||
|
|
@ -412,7 +417,7 @@ function envAutoCompletion(context: CompletionContext) {
|
|||
const options = (envVars.value ?? [])
|
||||
.map((env) => ({
|
||||
label: env?.key ? `<<${env.key}>>` : "",
|
||||
info: env?.value ?? "",
|
||||
info: env?.currentValue ?? "",
|
||||
apply: env?.key ? `<<${env.key}>>` : "",
|
||||
}))
|
||||
.filter(Boolean)
|
||||
|
|
@ -539,6 +544,7 @@ const getExtensions = (readonly: boolean): Extension => {
|
|||
override: [envAutoCompletion],
|
||||
})
|
||||
: [],
|
||||
|
||||
ViewPlugin.fromClass(
|
||||
class {
|
||||
update(update: ViewUpdate) {
|
||||
|
|
|
|||
|
|
@ -44,8 +44,13 @@ import {
|
|||
getTemporaryVariables,
|
||||
setTemporaryVariables,
|
||||
} from "./runner/temp_envs"
|
||||
import {
|
||||
CurrentValueService,
|
||||
Variable,
|
||||
} from "~/services/current-environment-value.service"
|
||||
|
||||
const secretEnvironmentService = getService(SecretEnvironmentService)
|
||||
const currentEnvironmentValueService = getService(CurrentValueService)
|
||||
|
||||
export const getTestableBody = (
|
||||
res: HoppRESTResponse & { type: "success" | "fail" }
|
||||
|
|
@ -99,11 +104,12 @@ export const executedResponses$ = new Subject<
|
|||
* @param type Whether the environment variables are global or selected
|
||||
* @returns the updated environment variables
|
||||
*/
|
||||
const updateEnvironmentsWithSecret = (
|
||||
const updateEnvironments = (
|
||||
envs: Environment["variables"] &
|
||||
{
|
||||
secret: true
|
||||
value: string | undefined
|
||||
currentValue: string
|
||||
initialValue: string
|
||||
key: string
|
||||
}[],
|
||||
type: "global" | "selected"
|
||||
|
|
@ -112,6 +118,7 @@ const updateEnvironmentsWithSecret = (
|
|||
type === "selected" ? getCurrentEnvironment().id : "Global"
|
||||
|
||||
const updatedSecretEnvironments: SecretVariable[] = []
|
||||
const nonSecretVariables: Variable[] = []
|
||||
|
||||
const updatedEnv = pipe(
|
||||
envs,
|
||||
|
|
@ -119,16 +126,35 @@ const updateEnvironmentsWithSecret = (
|
|||
if (e.secret) {
|
||||
updatedSecretEnvironments.push({
|
||||
key: e.key,
|
||||
value: e.value ?? "",
|
||||
value: e.currentValue ?? "",
|
||||
varIndex: index,
|
||||
})
|
||||
|
||||
// delete the value from the environment
|
||||
// so that it doesn't get saved in the environment
|
||||
delete e.value
|
||||
return e
|
||||
|
||||
return {
|
||||
key: e.key,
|
||||
secret: e.secret,
|
||||
initialValue: e.initialValue ?? "",
|
||||
currentValue: "",
|
||||
}
|
||||
}
|
||||
|
||||
nonSecretVariables.push({
|
||||
key: e.key,
|
||||
isSecret: e.secret,
|
||||
varIndex: index,
|
||||
currentValue: e.currentValue ?? "",
|
||||
})
|
||||
// set the current value as empty string
|
||||
// so that it doesn't get saved in the environment
|
||||
return {
|
||||
key: e.key,
|
||||
secret: e.secret,
|
||||
initialValue: e.initialValue ?? "",
|
||||
currentValue: "",
|
||||
}
|
||||
return e
|
||||
})
|
||||
)
|
||||
if (currentEnvID) {
|
||||
|
|
@ -136,10 +162,39 @@ const updateEnvironmentsWithSecret = (
|
|||
currentEnvID,
|
||||
updatedSecretEnvironments
|
||||
)
|
||||
|
||||
currentEnvironmentValueService.addEnvironment(
|
||||
currentEnvID,
|
||||
nonSecretVariables
|
||||
)
|
||||
}
|
||||
return updatedEnv
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the environment variable value from the current environment
|
||||
* @param envID The environment ID
|
||||
* @param index The index of the environment variable
|
||||
* @param isSecret Whether the environment variable is a secret
|
||||
* @returns The environment variable value
|
||||
*/
|
||||
const getEnvironmentVariableValue = (
|
||||
envID: string,
|
||||
index: number,
|
||||
isSecret: boolean
|
||||
): string | undefined => {
|
||||
if (isSecret) {
|
||||
return secretEnvironmentService.getSecretEnvironmentVariableValue(
|
||||
envID,
|
||||
index
|
||||
)
|
||||
}
|
||||
return currentEnvironmentValueService.getEnvironmentVariableValue(
|
||||
envID,
|
||||
index
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the environment list to a list with unique keys with value
|
||||
* @param envs The environment list to be transformed
|
||||
|
|
@ -149,7 +204,6 @@ const filterNonEmptyEnvironmentVariables = (
|
|||
envs: Environment["variables"]
|
||||
): Environment["variables"] => {
|
||||
const envsMap = new Map<string, Environment["variables"][number]>()
|
||||
|
||||
envs.forEach((env) => {
|
||||
if (env.secret) {
|
||||
envsMap.set(env.key, env)
|
||||
|
|
@ -158,9 +212,9 @@ const filterNonEmptyEnvironmentVariables = (
|
|||
|
||||
if (
|
||||
existingEnv &&
|
||||
"value" in existingEnv &&
|
||||
existingEnv.value === "" &&
|
||||
env.value !== ""
|
||||
"currentValue" in existingEnv &&
|
||||
existingEnv.currentValue === "" &&
|
||||
env.currentValue !== ""
|
||||
) {
|
||||
envsMap.set(env.key, env)
|
||||
}
|
||||
|
|
@ -231,7 +285,8 @@ export function runRESTRequest$(
|
|||
if (v.active) {
|
||||
return {
|
||||
key: v.key,
|
||||
value: v.value,
|
||||
initialValue: v.value,
|
||||
currentValue: v.value,
|
||||
secret: false,
|
||||
}
|
||||
}
|
||||
|
|
@ -256,7 +311,7 @@ export function runRESTRequest$(
|
|||
|
||||
const effectiveRequest = await getEffectiveRESTRequest(finalRequest, {
|
||||
id: "env-id",
|
||||
v: 1,
|
||||
v: 2,
|
||||
name: "Env",
|
||||
variables: finalEnvsWithNonEmptyValues,
|
||||
})
|
||||
|
|
@ -269,10 +324,7 @@ export function runRESTRequest$(
|
|||
.pipe(filter((res) => res.type === "success" || res.type === "fail"))
|
||||
.subscribe(async (res) => {
|
||||
if (res.type === "success" || res.type === "fail") {
|
||||
executedResponses$.next(
|
||||
// @ts-expect-error Typescript can't figure out this inference for some reason
|
||||
res
|
||||
)
|
||||
executedResponses$.next(res)
|
||||
|
||||
const runResult = await runTestScript(
|
||||
res.req.testScript,
|
||||
|
|
@ -287,10 +339,10 @@ export function runRESTRequest$(
|
|||
if (E.isRight(runResult)) {
|
||||
// set the response in the tab so that multiple tabs can run request simultaneously
|
||||
tab.value.document.response = res
|
||||
const updatedRunResult = updateEnvsAfterTestScript(runResult)
|
||||
tab.value.document.testResults =
|
||||
// @ts-expect-error Typescript can't figure out this inference for some reason
|
||||
translateToSandboxTestResults(updatedRunResult)
|
||||
tab.value.document.testResults = translateToSandboxTestResults(
|
||||
runResult.right
|
||||
)
|
||||
updateEnvsAfterTestScript(runResult)
|
||||
} else {
|
||||
tab.value.document.testResults = {
|
||||
description: "",
|
||||
|
|
@ -323,13 +375,13 @@ export function runRESTRequest$(
|
|||
}
|
||||
|
||||
function updateEnvsAfterTestScript(runResult: E.Right<SandboxTestResult>) {
|
||||
const updatedGlobalEnvVariables = updateEnvironmentsWithSecret(
|
||||
const updatedGlobalEnvVariables = updateEnvironments(
|
||||
// @ts-expect-error Typescript can't figure out this inference for some reason
|
||||
cloneDeep(runResult.right.envs.global),
|
||||
"global"
|
||||
)
|
||||
|
||||
const updatedSelectedEnvVariables = updateEnvironmentsWithSecret(
|
||||
const updatedSelectedEnvVariables = updateEnvironments(
|
||||
// @ts-expect-error Typescript can't figure out this inference for some reason
|
||||
cloneDeep(runResult.right.envs.selected),
|
||||
"selected"
|
||||
|
|
@ -343,14 +395,14 @@ function updateEnvsAfterTestScript(runResult: E.Right<SandboxTestResult>) {
|
|||
},
|
||||
}
|
||||
|
||||
const globalEnvVariables = updateEnvironmentsWithSecret(
|
||||
const globalEnvVariables = updateEnvironments(
|
||||
// @ts-expect-error Typescript can't figure out this inference for some reason
|
||||
runResult.right.envs.global,
|
||||
"global"
|
||||
)
|
||||
|
||||
setGlobalEnvVariables({
|
||||
v: 1,
|
||||
v: 2,
|
||||
variables: globalEnvVariables,
|
||||
})
|
||||
if (environmentsStore.value.selectedEnvironmentIndex.type === "MY_ENV") {
|
||||
|
|
@ -360,7 +412,7 @@ function updateEnvsAfterTestScript(runResult: E.Right<SandboxTestResult>) {
|
|||
})
|
||||
updateEnvironment(environmentsStore.value.selectedEnvironmentIndex.index, {
|
||||
name: env.name,
|
||||
v: 1,
|
||||
v: 2,
|
||||
id: "id" in env ? env.id : "",
|
||||
variables: updatedRunResult.envs.selected,
|
||||
})
|
||||
|
|
@ -411,7 +463,7 @@ export function runTestRunnerRequest(
|
|||
|
||||
const effectiveRequest = await getEffectiveRESTRequest(request, {
|
||||
id: "env-id",
|
||||
v: 1,
|
||||
v: 2,
|
||||
name: "Env",
|
||||
variables: combineEnvVariables({
|
||||
environments: {
|
||||
|
|
@ -429,10 +481,7 @@ export function runTestRunnerRequest(
|
|||
.toPromise()
|
||||
.then(async (res) => {
|
||||
if (res?.type === "success" || res?.type === "fail") {
|
||||
executedResponses$.next(
|
||||
// @ts-expect-error Typescript can't figure out this inference for some reason
|
||||
res
|
||||
)
|
||||
executedResponses$.next(res)
|
||||
|
||||
const runResult = await runTestScript(
|
||||
res.req.testScript,
|
||||
|
|
@ -528,12 +577,12 @@ const getUpdatedEnvVariables = (
|
|||
),
|
||||
O.chain(
|
||||
O.fromPredicate(
|
||||
({ env, index }) => env.value !== current[index].value
|
||||
({ env, index }) => env.currentValue !== current[index].currentValue
|
||||
)
|
||||
),
|
||||
O.map(({ env, index }) => ({
|
||||
...env,
|
||||
previousValue: current[index].value,
|
||||
previousValue: current[index].currentValue,
|
||||
}))
|
||||
)
|
||||
)
|
||||
|
|
@ -550,8 +599,21 @@ function translateToSandboxTestResults(
|
|||
}
|
||||
}
|
||||
|
||||
const globals = cloneDeep(getGlobalVariables())
|
||||
const env = getCurrentEnvironment()
|
||||
const globals = cloneDeep(getGlobalVariables()).map((g, index) => ({
|
||||
...g,
|
||||
currentValue: getEnvironmentVariableValue("Global", index, g.secret) ?? "",
|
||||
}))
|
||||
|
||||
const envVars = getCurrentEnvironment().variables.map((e, index) => ({
|
||||
...e,
|
||||
currentValue:
|
||||
getEnvironmentVariableValue(
|
||||
getCurrentEnvironment().id,
|
||||
index,
|
||||
e.secret
|
||||
) ?? "",
|
||||
}))
|
||||
|
||||
return {
|
||||
description: "",
|
||||
expectResults: testDesc.tests.expectResults,
|
||||
|
|
@ -564,15 +626,9 @@ function translateToSandboxTestResults(
|
|||
updations: getUpdatedEnvVariables(globals, testDesc.envs.global),
|
||||
},
|
||||
selected: {
|
||||
additions: getAddedEnvVariables(env.variables, testDesc.envs.selected),
|
||||
deletions: getRemovedEnvVariables(
|
||||
env.variables,
|
||||
testDesc.envs.selected
|
||||
),
|
||||
updations: getUpdatedEnvVariables(
|
||||
env.variables,
|
||||
testDesc.envs.selected
|
||||
),
|
||||
additions: getAddedEnvVariables(envVars, testDesc.envs.selected),
|
||||
deletions: getRemovedEnvVariables(envVars, testDesc.envs.selected),
|
||||
updations: getUpdatedEnvVariables(envVars, testDesc.envs.selected),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import IconEdit from "~icons/lucide/edit?raw"
|
|||
import IconUser from "~icons/lucide/user?raw"
|
||||
import IconUsers from "~icons/lucide/users?raw"
|
||||
import { isComment } from "./helpers"
|
||||
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||
|
||||
const HOPP_ENVIRONMENT_REGEX = /(<<[a-zA-Z0-9-_]+>>)/g
|
||||
|
||||
|
|
@ -38,6 +39,8 @@ const HOPP_GLOBAL_ENVIRONMENT_HIGHLIGHT = "global-variable-highlight"
|
|||
const HOPP_ENV_HIGHLIGHT_NOT_FOUND = "environment-not-found-highlight"
|
||||
|
||||
const secretEnvironmentService = getService(SecretEnvironmentService)
|
||||
const currentEnvironmentValueService = getService(CurrentValueService)
|
||||
|
||||
const restTabs = getService(RESTTabService)
|
||||
|
||||
/**
|
||||
|
|
@ -54,7 +57,7 @@ const filterNonEmptyEnvironmentVariables = (
|
|||
if (envsMap.has(env.key)) {
|
||||
const existingEnv = envsMap.get(env.key)
|
||||
|
||||
if (existingEnv?.value === "" && env.value !== "") {
|
||||
if (existingEnv?.currentValue === "" && env.currentValue !== "") {
|
||||
envsMap.set(env.key, env)
|
||||
}
|
||||
} else {
|
||||
|
|
@ -110,11 +113,20 @@ const cursorTooltipField = (aggregateEnvs: AggregateEnvironment[]) =>
|
|||
(env) => env.key === parsedEnvKey
|
||||
)
|
||||
|
||||
const currentSelectedEnvironment = getCurrentEnvironment()
|
||||
|
||||
const envName = tooltipEnv?.sourceEnv ?? "Choose an Environment"
|
||||
|
||||
let envValue = "Not Found"
|
||||
|
||||
const currentSelectedEnvironment = getCurrentEnvironment()
|
||||
const envTooltipValue =
|
||||
tooltipEnv?.sourceEnv !== "RequestVariable"
|
||||
? (currentEnvironmentValueService.getEnvironmentByKey(
|
||||
tooltipEnv?.sourceEnv !== "Global"
|
||||
? currentSelectedEnvironment.id
|
||||
: "Global",
|
||||
tooltipEnv?.key ?? ""
|
||||
)?.currentValue ?? "")
|
||||
: tooltipEnv?.currentValue
|
||||
|
||||
const hasSecretEnv = secretEnvironmentService.hasSecretValue(
|
||||
tooltipEnv?.sourceEnv !== "Global"
|
||||
|
|
@ -123,14 +135,15 @@ const cursorTooltipField = (aggregateEnvs: AggregateEnvironment[]) =>
|
|||
tooltipEnv?.key ?? ""
|
||||
)
|
||||
|
||||
if (!tooltipEnv?.secret && tooltipEnv?.value) envValue = tooltipEnv.value
|
||||
else if (tooltipEnv?.secret && hasSecretEnv) {
|
||||
if (!tooltipEnv?.secret && envTooltipValue) {
|
||||
envValue = envTooltipValue
|
||||
} else if (tooltipEnv?.secret && hasSecretEnv) {
|
||||
envValue = "******"
|
||||
} else if (tooltipEnv?.secret && !hasSecretEnv) {
|
||||
envValue = "Empty"
|
||||
} else if (!tooltipEnv?.sourceEnv) {
|
||||
envValue = "Not Found"
|
||||
} else if (!tooltipEnv?.value) {
|
||||
} else if (!envTooltipValue) {
|
||||
envValue = "Empty"
|
||||
}
|
||||
|
||||
|
|
@ -295,7 +308,8 @@ export class HoppEnvironmentPlugin {
|
|||
this.envs = [
|
||||
...requestVariables.map(({ key, value }) => ({
|
||||
key,
|
||||
value,
|
||||
currentValue: value,
|
||||
initialValue: value,
|
||||
sourceEnv: "RequestVariable",
|
||||
secret: false,
|
||||
})),
|
||||
|
|
@ -318,7 +332,8 @@ export class HoppEnvironmentPlugin {
|
|||
this.envs = [
|
||||
...requestVariables.map(({ key, value }) => ({
|
||||
key,
|
||||
value,
|
||||
currentValue: value,
|
||||
initialValue: value,
|
||||
sourceEnv: "RequestVariable",
|
||||
secret: false,
|
||||
})),
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ const getEnvironmentJSON = (
|
|||
? environmentIndex
|
||||
: environmentObj.id
|
||||
|
||||
// Eliminate `value` field from secret environment variables prior to export
|
||||
// Eliminate `currentValue` field from environment variables prior to export
|
||||
const transformedEnvironment = transformEnvironmentVariables(newEnvironment)
|
||||
|
||||
return environmentId !== null
|
||||
|
|
@ -39,17 +39,16 @@ export const transformEnvironmentVariables = ({
|
|||
v,
|
||||
name,
|
||||
variables: variables.map((variable) => {
|
||||
const { key, secret } = variable
|
||||
const { key, secret, initialValue } = variable
|
||||
|
||||
// Eliminate `value` field for secret environment variables
|
||||
if (secret) {
|
||||
return {
|
||||
key,
|
||||
secret,
|
||||
}
|
||||
// Eliminate `currentValue` field for secret environment variables and currentValue
|
||||
|
||||
return {
|
||||
key,
|
||||
secret,
|
||||
initialValue,
|
||||
currentValue: "",
|
||||
}
|
||||
|
||||
return variable
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ export const hoppEnvImporter = (contents: string[]) => {
|
|||
...contentEntry,
|
||||
variables: contentEntry.variables?.map((valueEntry) => ({
|
||||
...valueEntry,
|
||||
...("value" in valueEntry
|
||||
? { value: String(valueEntry.value) }
|
||||
...("initialValue" in valueEntry
|
||||
? { value: String(valueEntry.initialValue) }
|
||||
: {}),
|
||||
})),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,14 +64,18 @@ export const insomniaEnvImporter = (contents: string[]) => {
|
|||
|
||||
insomniaEnvs.forEach((insomniaEnv) => {
|
||||
const parsedInsomniaEnv = insomniaEnvSchema.safeParse(insomniaEnv)
|
||||
|
||||
if (parsedInsomniaEnv.success) {
|
||||
const environment: NonSecretEnvironment = {
|
||||
id: uniqueID(),
|
||||
v: 1,
|
||||
v: 2,
|
||||
name: parsedInsomniaEnv.data.name,
|
||||
variables: Object.entries(parsedInsomniaEnv.data.data).map(
|
||||
([key, value]) => ({ key, value, secret: false })
|
||||
([key, value]) => ({
|
||||
key,
|
||||
initialValue: value,
|
||||
currentValue: value,
|
||||
secret: false,
|
||||
})
|
||||
),
|
||||
}
|
||||
|
||||
|
|
@ -83,7 +87,8 @@ export const insomniaEnvImporter = (contents: string[]) => {
|
|||
...env,
|
||||
variables: env.variables.map((variable) => ({
|
||||
...variable,
|
||||
value: replaceInsomniaTemplating(variable.value),
|
||||
initialValue: replaceInsomniaTemplating(variable.initialValue),
|
||||
currentValue: replaceInsomniaTemplating(variable.currentValue),
|
||||
})),
|
||||
}))
|
||||
|
||||
|
|
|
|||
|
|
@ -52,11 +52,12 @@ export const postmanEnvImporter = (contents: string[]) => {
|
|||
const environments: Environment[] = validationResult.data.map(
|
||||
({ name, values }) => ({
|
||||
id: uniqueID(),
|
||||
v: 1,
|
||||
v: 2,
|
||||
name,
|
||||
variables: values.map(({ key, value, type }) => ({
|
||||
key,
|
||||
value,
|
||||
initialValue: value,
|
||||
currentValue: value,
|
||||
secret: type === "secret",
|
||||
})),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -10,10 +10,18 @@ import {
|
|||
import { TestResult } from "@hoppscotch/js-sandbox"
|
||||
import { getService } from "~/modules/dioc"
|
||||
import { SecretEnvironmentService } from "~/services/secret-environment.service"
|
||||
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||
|
||||
const secretEnvironmentService = getService(SecretEnvironmentService)
|
||||
const currentEnvironmentValueService = getService(CurrentValueService)
|
||||
|
||||
const unsecretEnvironments = (
|
||||
/**
|
||||
* Populate the currentValue of the environment variables and set the secret values
|
||||
* @param selected
|
||||
* @param global
|
||||
* @returns
|
||||
*/
|
||||
const unWrapEnvironments = (
|
||||
selected: Environment,
|
||||
global: Environment["variables"]
|
||||
) => {
|
||||
|
|
@ -22,18 +30,18 @@ const unsecretEnvironments = (
|
|||
"Global",
|
||||
index
|
||||
)
|
||||
const currentVar = currentEnvironmentValueService.getEnvironmentVariable(
|
||||
"Global",
|
||||
index
|
||||
)
|
||||
|
||||
if (secretVar) {
|
||||
return {
|
||||
...globalVar,
|
||||
value: secretVar.value,
|
||||
}
|
||||
} else if (!("value" in globalVar) || !globalVar.value) {
|
||||
return {
|
||||
...globalVar,
|
||||
value: "",
|
||||
currentValue: secretVar.value,
|
||||
}
|
||||
}
|
||||
return globalVar
|
||||
return { ...globalVar, currentValue: currentVar?.currentValue ?? "" }
|
||||
})
|
||||
|
||||
const resolvedSelectedWithSecrets = selected.variables.map(
|
||||
|
|
@ -42,18 +50,17 @@ const unsecretEnvironments = (
|
|||
selected.id,
|
||||
index
|
||||
)
|
||||
const currentVar = currentEnvironmentValueService.getEnvironmentVariable(
|
||||
selected.id,
|
||||
index
|
||||
)
|
||||
if (secretVar) {
|
||||
return {
|
||||
...selectedVar,
|
||||
value: secretVar.value,
|
||||
}
|
||||
} else if (!("value" in selectedVar) || !selectedVar.value) {
|
||||
return {
|
||||
...selectedVar,
|
||||
value: "",
|
||||
currentValue: secretVar.value,
|
||||
}
|
||||
}
|
||||
return selectedVar
|
||||
return { ...selectedVar, currentValue: currentVar?.currentValue ?? "" }
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -64,7 +71,7 @@ const unsecretEnvironments = (
|
|||
}
|
||||
|
||||
export const getCombinedEnvVariables = (temp?: Environment["variables"]) => {
|
||||
const reformedVars = unsecretEnvironments(
|
||||
const reformedVars = unWrapEnvironments(
|
||||
getCurrentEnvironment(),
|
||||
getGlobalVariables()
|
||||
)
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ export default class TeamEnvironmentAdapter {
|
|||
id: x.id,
|
||||
teamID: x.teamID,
|
||||
environment: {
|
||||
v: 1,
|
||||
v: 2,
|
||||
id: x.id,
|
||||
name: x.name,
|
||||
variables: JSON.parse(x.variables),
|
||||
|
|
@ -198,7 +198,7 @@ export default class TeamEnvironmentAdapter {
|
|||
id: x.id,
|
||||
teamID: x.teamID,
|
||||
environment: {
|
||||
v: 1,
|
||||
v: 2,
|
||||
id: x.id,
|
||||
name: x.name,
|
||||
variables: JSON.parse(x.variables),
|
||||
|
|
@ -253,7 +253,7 @@ export default class TeamEnvironmentAdapter {
|
|||
id: x.id,
|
||||
teamID: x.teamID,
|
||||
environment: {
|
||||
v: 1,
|
||||
v: 2,
|
||||
id: x.id,
|
||||
name: x.name,
|
||||
variables: JSON.parse(x.variables),
|
||||
|
|
|
|||
|
|
@ -25,14 +25,14 @@ export type SelectedEnvironmentIndex =
|
|||
}
|
||||
|
||||
const defaultGlobalEnvironmentState: GlobalEnvironment = {
|
||||
v: 1,
|
||||
v: 2,
|
||||
variables: [],
|
||||
}
|
||||
|
||||
const defaultEnvironmentsState = {
|
||||
environments: [
|
||||
{
|
||||
v: 1,
|
||||
v: 2,
|
||||
id: uniqueID(),
|
||||
name: "My Environment Variables",
|
||||
variables: [],
|
||||
|
|
@ -105,12 +105,12 @@ const dispatchers = defineDispatchers({
|
|||
envID
|
||||
? {
|
||||
id: envID,
|
||||
v: 1,
|
||||
v: 2,
|
||||
name,
|
||||
variables,
|
||||
}
|
||||
: {
|
||||
v: 1,
|
||||
v: 2,
|
||||
id: uniqueID(),
|
||||
name,
|
||||
variables,
|
||||
|
|
@ -205,16 +205,26 @@ const dispatchers = defineDispatchers({
|
|||
{
|
||||
envIndex,
|
||||
key,
|
||||
value,
|
||||
initialValue,
|
||||
currentValue,
|
||||
secret,
|
||||
}: { envIndex: number; key: string; value: string; secret: boolean }
|
||||
}: {
|
||||
envIndex: number
|
||||
key: string
|
||||
initialValue: string
|
||||
currentValue: string
|
||||
secret: boolean
|
||||
}
|
||||
) {
|
||||
return {
|
||||
environments: environments.map((env, index) =>
|
||||
index === envIndex
|
||||
? {
|
||||
...env,
|
||||
variables: [...env.variables, { key, value, secret }],
|
||||
variables: [
|
||||
...env.variables,
|
||||
{ key, initialValue, currentValue, secret },
|
||||
],
|
||||
}
|
||||
: env
|
||||
),
|
||||
|
|
@ -244,7 +254,12 @@ const dispatchers = defineDispatchers({
|
|||
vars,
|
||||
}: {
|
||||
envIndex: number
|
||||
vars: { key: string; value: string; secret: boolean }[]
|
||||
vars: {
|
||||
key: string
|
||||
initialValue: string
|
||||
currentValue: string
|
||||
secret: boolean
|
||||
}[]
|
||||
}
|
||||
) {
|
||||
return {
|
||||
|
|
@ -264,12 +279,14 @@ const dispatchers = defineDispatchers({
|
|||
envIndex,
|
||||
variableIndex,
|
||||
updatedKey,
|
||||
updatedValue,
|
||||
updatedInitialValue,
|
||||
updatedCurrentValue,
|
||||
}: {
|
||||
envIndex: number
|
||||
variableIndex: number
|
||||
updatedKey: string
|
||||
updatedValue: string
|
||||
updatedInitialValue: string
|
||||
updatedCurrentValue: string
|
||||
}
|
||||
) {
|
||||
return {
|
||||
|
|
@ -279,7 +296,12 @@ const dispatchers = defineDispatchers({
|
|||
...env,
|
||||
variables: env.variables.map((v, vIndex) =>
|
||||
vIndex === variableIndex
|
||||
? { key: updatedKey, value: updatedValue, secret: v.secret }
|
||||
? {
|
||||
key: updatedKey,
|
||||
initialValue: updatedInitialValue,
|
||||
currentValue: updatedCurrentValue,
|
||||
secret: v.secret,
|
||||
}
|
||||
: v
|
||||
),
|
||||
}
|
||||
|
|
@ -380,7 +402,7 @@ export const currentEnvironment$: Observable<Environment | undefined> =
|
|||
if (selectedEnvironmentIndex.type === "NO_ENV_SELECTED") {
|
||||
const env: Environment = {
|
||||
name: "No environment",
|
||||
v: 1,
|
||||
v: 2,
|
||||
id: "",
|
||||
variables: [],
|
||||
}
|
||||
|
|
@ -395,7 +417,8 @@ export const currentEnvironment$: Observable<Environment | undefined> =
|
|||
|
||||
export type AggregateEnvironment = {
|
||||
key: string
|
||||
value: string
|
||||
initialValue: string
|
||||
currentValue: string
|
||||
secret: boolean
|
||||
sourceEnv: string
|
||||
}
|
||||
|
|
@ -415,7 +438,8 @@ export const aggregateEnvs$: Observable<AggregateEnvironment[]> = combineLatest(
|
|||
HOPP_SUPPORTED_PREDEFINED_VARIABLES.forEach(({ key, getValue }) => {
|
||||
effectiveAggregateEnvs.push({
|
||||
key,
|
||||
value: getValue(),
|
||||
currentValue: getValue(),
|
||||
initialValue: getValue(),
|
||||
secret: false,
|
||||
sourceEnv: selectedEnv?.name ?? "Global",
|
||||
})
|
||||
|
|
@ -425,12 +449,16 @@ export const aggregateEnvs$: Observable<AggregateEnvironment[]> = combineLatest(
|
|||
|
||||
selectedEnv?.variables.forEach((variable) => {
|
||||
const { key, secret } = variable
|
||||
const value = "value" in variable ? variable.value : ""
|
||||
const currentValue =
|
||||
"currentValue" in variable ? variable.currentValue : ""
|
||||
const initialValue =
|
||||
"initialValue" in variable ? variable.initialValue : ""
|
||||
|
||||
if (!aggregateEnvKeys.includes(key)) {
|
||||
effectiveAggregateEnvs.push({
|
||||
key,
|
||||
value,
|
||||
currentValue,
|
||||
initialValue,
|
||||
secret,
|
||||
sourceEnv: selectedEnv.name,
|
||||
})
|
||||
|
|
@ -439,10 +467,19 @@ export const aggregateEnvs$: Observable<AggregateEnvironment[]> = combineLatest(
|
|||
|
||||
globalEnv.variables.forEach((variable) => {
|
||||
const { key, secret } = variable
|
||||
const value = "value" in variable ? variable.value : ""
|
||||
const currentValue =
|
||||
"currentValue" in variable ? variable.currentValue : ""
|
||||
const initialValue =
|
||||
"initialValue" in variable ? variable.initialValue : ""
|
||||
|
||||
if (!aggregateEnvKeys.includes(key)) {
|
||||
effectiveAggregateEnvs.push({ key, value, secret, sourceEnv: "Global" })
|
||||
effectiveAggregateEnvs.push({
|
||||
key,
|
||||
currentValue,
|
||||
initialValue,
|
||||
secret,
|
||||
sourceEnv: "Global",
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -455,26 +492,28 @@ export function getAggregateEnvs() {
|
|||
const currentEnv = getCurrentEnvironment()
|
||||
return [
|
||||
...currentEnv.variables.map((x) => {
|
||||
let value
|
||||
let currentValue
|
||||
if (!x.secret) {
|
||||
value = x.value
|
||||
currentValue = x.currentValue
|
||||
}
|
||||
|
||||
return <AggregateEnvironment>{
|
||||
key: x.key,
|
||||
value,
|
||||
initialValue: x.initialValue,
|
||||
currentValue,
|
||||
secret: x.secret,
|
||||
sourceEnv: currentEnv.name,
|
||||
}
|
||||
}),
|
||||
...getGlobalVariables().map((x) => {
|
||||
let value
|
||||
let currentValue
|
||||
if (!x.secret) {
|
||||
value = x.value
|
||||
currentValue = x.currentValue
|
||||
}
|
||||
return <AggregateEnvironment>{
|
||||
key: x.key,
|
||||
value,
|
||||
initialValue: x.initialValue,
|
||||
currentValue,
|
||||
secret: x.secret,
|
||||
sourceEnv: "Global",
|
||||
}
|
||||
|
|
@ -486,36 +525,40 @@ export function getAggregateEnvsWithSecrets() {
|
|||
const currentEnv = getCurrentEnvironment()
|
||||
return [
|
||||
...currentEnv.variables.map((x, index) => {
|
||||
let value
|
||||
let currentValue
|
||||
if (x.secret) {
|
||||
value = secretEnvironmentService.getSecretEnvironmentVariableValue(
|
||||
currentEnv.id,
|
||||
index
|
||||
)
|
||||
currentValue =
|
||||
secretEnvironmentService.getSecretEnvironmentVariableValue(
|
||||
currentEnv.id,
|
||||
index
|
||||
)
|
||||
} else {
|
||||
value = x.value
|
||||
currentValue = x.currentValue
|
||||
}
|
||||
|
||||
return <AggregateEnvironment>{
|
||||
key: x.key,
|
||||
value,
|
||||
currentValue,
|
||||
initialValue: x.initialValue,
|
||||
secret: x.secret,
|
||||
sourceEnv: currentEnv.name,
|
||||
}
|
||||
}),
|
||||
...getGlobalVariables().map((x, index) => {
|
||||
let value
|
||||
let currentValue
|
||||
if (x.secret) {
|
||||
value = secretEnvironmentService.getSecretEnvironmentVariableValue(
|
||||
"Global",
|
||||
index
|
||||
)
|
||||
currentValue =
|
||||
secretEnvironmentService.getSecretEnvironmentVariableValue(
|
||||
"Global",
|
||||
index
|
||||
)
|
||||
} else {
|
||||
value = x.value
|
||||
currentValue = x.currentValue
|
||||
}
|
||||
return <AggregateEnvironment>{
|
||||
key: x.key,
|
||||
value,
|
||||
currentValue,
|
||||
initialValue: x.initialValue,
|
||||
secret: x.secret,
|
||||
sourceEnv: "Global",
|
||||
}
|
||||
|
|
@ -528,36 +571,40 @@ export const aggregateEnvsWithSecrets$: Observable<AggregateEnvironment[]> =
|
|||
map(([selectedEnv, globalEnv]) => {
|
||||
const results: AggregateEnvironment[] = []
|
||||
selectedEnv?.variables.map((x, index) => {
|
||||
let value
|
||||
let currentValue
|
||||
if (x.secret) {
|
||||
value = secretEnvironmentService.getSecretEnvironmentVariableValue(
|
||||
selectedEnv.id,
|
||||
index
|
||||
)
|
||||
currentValue =
|
||||
secretEnvironmentService.getSecretEnvironmentVariableValue(
|
||||
selectedEnv.id,
|
||||
index
|
||||
)
|
||||
} else {
|
||||
value = x.value
|
||||
currentValue = x.currentValue
|
||||
}
|
||||
results.push({
|
||||
key: x.key,
|
||||
value: value ?? "",
|
||||
currentValue: currentValue ?? "",
|
||||
initialValue: x.initialValue,
|
||||
secret: x.secret,
|
||||
sourceEnv: selectedEnv.name,
|
||||
})
|
||||
})
|
||||
|
||||
globalEnv.variables.map((x, index) => {
|
||||
let value
|
||||
let currentValue
|
||||
if (x.secret) {
|
||||
value = secretEnvironmentService.getSecretEnvironmentVariableValue(
|
||||
"Global",
|
||||
index
|
||||
)
|
||||
currentValue =
|
||||
secretEnvironmentService.getSecretEnvironmentVariableValue(
|
||||
"Global",
|
||||
index
|
||||
)
|
||||
} else {
|
||||
value = x.value
|
||||
currentValue = x.currentValue
|
||||
}
|
||||
results.push({
|
||||
key: x.key,
|
||||
value: value ?? "",
|
||||
currentValue: currentValue ?? "",
|
||||
initialValue: x.initialValue,
|
||||
secret: x.secret,
|
||||
sourceEnv: "Global",
|
||||
})
|
||||
|
|
@ -573,7 +620,7 @@ export function getCurrentEnvironment(): Environment {
|
|||
environmentsStore.value.selectedEnvironmentIndex.type === "NO_ENV_SELECTED"
|
||||
) {
|
||||
return {
|
||||
v: 1,
|
||||
v: 2,
|
||||
id: "",
|
||||
name: "No environment",
|
||||
variables: [],
|
||||
|
|
@ -620,7 +667,7 @@ export function getLegacyGlobalEnvironment(): Environment | null {
|
|||
export function getGlobalVariables(): GlobalEnvironmentVariable[] {
|
||||
return environmentsStore.value.globals.variables.map(
|
||||
(env: GlobalEnvironmentVariable) => {
|
||||
if (env.key && "value" in env && !("secret" in env)) {
|
||||
if (env.key && "currentValue" in env && !("secret" in env)) {
|
||||
return {
|
||||
...(env as GlobalEnvironmentVariable),
|
||||
secret: false,
|
||||
|
|
@ -765,7 +812,12 @@ export function updateEnvironment(envIndex: number, updatedEnv: Environment) {
|
|||
|
||||
export function setEnvironmentVariables(
|
||||
envIndex: number,
|
||||
vars: { key: string; value: string; secret: boolean }[]
|
||||
vars: {
|
||||
key: string
|
||||
currentValue: string
|
||||
initialValue: string
|
||||
secret: boolean
|
||||
}[]
|
||||
) {
|
||||
environmentsStore.dispatch({
|
||||
dispatcher: "setEnvironmentVariables",
|
||||
|
|
@ -778,14 +830,25 @@ export function setEnvironmentVariables(
|
|||
|
||||
export function addEnvironmentVariable(
|
||||
envIndex: number,
|
||||
{ key, value, secret }: { key: string; value: string; secret: boolean }
|
||||
{
|
||||
key,
|
||||
currentValue,
|
||||
initialValue,
|
||||
secret,
|
||||
}: {
|
||||
key: string
|
||||
currentValue: string
|
||||
initialValue: string
|
||||
secret: boolean
|
||||
}
|
||||
) {
|
||||
environmentsStore.dispatch({
|
||||
dispatcher: "addEnvironmentVariable",
|
||||
payload: {
|
||||
envIndex,
|
||||
key,
|
||||
value,
|
||||
currentValue,
|
||||
initialValue,
|
||||
secret,
|
||||
},
|
||||
})
|
||||
|
|
@ -807,7 +870,11 @@ export function removeEnvironmentVariable(
|
|||
export function updateEnvironmentVariable(
|
||||
envIndex: number,
|
||||
variableIndex: number,
|
||||
{ key, value }: { key: string; value: string }
|
||||
{
|
||||
key,
|
||||
currentValue,
|
||||
initialValue,
|
||||
}: { key: string; currentValue: string; initialValue: string }
|
||||
) {
|
||||
environmentsStore.dispatch({
|
||||
dispatcher: "updateEnvironmentVariable",
|
||||
|
|
@ -815,7 +882,8 @@ export function updateEnvironmentVariable(
|
|||
envIndex,
|
||||
variableIndex,
|
||||
updatedKey: key,
|
||||
updatedValue: value,
|
||||
updatedCurrentValue: currentValue,
|
||||
updatedInitialValue: initialValue,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,178 @@
|
|||
import { describe, it, expect, beforeEach } from "vitest"
|
||||
import { TestContainer } from "dioc/testing"
|
||||
import {
|
||||
CurrentValueService,
|
||||
Variable,
|
||||
} from "../current-environment-value.service"
|
||||
|
||||
describe("CurrentValueService", () => {
|
||||
let container: TestContainer
|
||||
let service: CurrentValueService
|
||||
|
||||
beforeEach(() => {
|
||||
container = new TestContainer()
|
||||
service = container.bind(CurrentValueService)
|
||||
})
|
||||
|
||||
describe("addEnvironment", () => {
|
||||
it("should add a new environment with the provided ID and variables", () => {
|
||||
const id = "env1"
|
||||
const vars: Variable[] = [
|
||||
{ key: "key1", currentValue: "value1", varIndex: 1, isSecret: false },
|
||||
]
|
||||
service.addEnvironment(id, vars)
|
||||
expect(service.environments.get(id)).toEqual(vars)
|
||||
})
|
||||
})
|
||||
|
||||
describe("getEnvironment", () => {
|
||||
it("should return the variables of the specified environment", () => {
|
||||
const id = "env1"
|
||||
const vars: Variable[] = [
|
||||
{ key: "key1", currentValue: "value1", varIndex: 1, isSecret: false },
|
||||
]
|
||||
service.environments.set(id, vars)
|
||||
expect(service.getEnvironment(id)).toEqual(vars)
|
||||
})
|
||||
|
||||
it("should return undefined for non-existent environment", () => {
|
||||
expect(service.getEnvironment("nonexistent")).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("getEnvironmentVariable", () => {
|
||||
it("should return the variable at the given index", () => {
|
||||
const id = "env1"
|
||||
const vars: Variable[] = [
|
||||
{ key: "key1", currentValue: "value1", varIndex: 1, isSecret: false },
|
||||
]
|
||||
service.environments.set(id, vars)
|
||||
expect(service.getEnvironmentVariable(id, 1)).toEqual(vars[0])
|
||||
})
|
||||
|
||||
it("should return undefined for non-existent variable", () => {
|
||||
const id = "env1"
|
||||
const vars: Variable[] = [
|
||||
{ key: "key1", currentValue: "value1", varIndex: 1, isSecret: false },
|
||||
]
|
||||
service.environments.set(id, vars)
|
||||
expect(service.getEnvironmentVariable(id, 2)).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("getEnvironmentVariableValue", () => {
|
||||
it("should return the value of the variable", () => {
|
||||
const id = "env1"
|
||||
const vars: Variable[] = [
|
||||
{ key: "key1", currentValue: "value1", varIndex: 1, isSecret: false },
|
||||
]
|
||||
service.environments.set(id, vars)
|
||||
expect(service.getEnvironmentVariableValue(id, 1)).toBe("value1")
|
||||
})
|
||||
|
||||
it("should return undefined if variable doesn't exist", () => {
|
||||
expect(service.getEnvironmentVariableValue("env1", 999)).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("loadEnvironmentsFromPersistedState", () => {
|
||||
it("should load environments correctly", () => {
|
||||
const state = {
|
||||
env1: [{ key: "k", currentValue: "v", varIndex: 0, isSecret: false }],
|
||||
}
|
||||
service.loadEnvironmentsFromPersistedState(state)
|
||||
expect(service.environments.get("env1")).toEqual(state.env1)
|
||||
})
|
||||
})
|
||||
|
||||
describe("deleteEnvironment", () => {
|
||||
it("should delete the specified environment", () => {
|
||||
const id = "env1"
|
||||
service.environments.set(id, [])
|
||||
service.deleteEnvironment(id)
|
||||
expect(service.environments.has(id)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("removeEnvironmentVariable", () => {
|
||||
it("should remove the specified variable", () => {
|
||||
const id = "env1"
|
||||
const vars = [
|
||||
{ key: "key1", currentValue: "value1", varIndex: 1, isSecret: false },
|
||||
{ key: "key2", currentValue: "value2", varIndex: 2, isSecret: false },
|
||||
]
|
||||
service.environments.set(id, vars)
|
||||
service.removeEnvironmentVariable(id, 1)
|
||||
expect(service.environments.get(id)).toEqual([vars[1]])
|
||||
})
|
||||
|
||||
it("should not fail if variable does not exist", () => {
|
||||
const id = "env1"
|
||||
const vars = [
|
||||
{ key: "key1", currentValue: "value1", varIndex: 1, isSecret: false },
|
||||
]
|
||||
service.environments.set(id, vars)
|
||||
service.removeEnvironmentVariable(id, 999)
|
||||
expect(service.environments.get(id)).toEqual(vars)
|
||||
})
|
||||
})
|
||||
|
||||
describe("updateEnvironmentID", () => {
|
||||
it("should update the environment ID", () => {
|
||||
const oldID = "old"
|
||||
const newID = "new"
|
||||
const vars = [
|
||||
{ key: "k", currentValue: "v", varIndex: 0, isSecret: false },
|
||||
]
|
||||
service.environments.set(oldID, vars)
|
||||
service.updateEnvironmentID(oldID, newID)
|
||||
expect(service.environments.has(oldID)).toBe(false)
|
||||
expect(service.environments.get(newID)).toEqual(vars)
|
||||
})
|
||||
})
|
||||
|
||||
describe("hasValue", () => {
|
||||
it("should return true if a variable with the key and non-empty value exists", () => {
|
||||
const id = "env1"
|
||||
const vars = [
|
||||
{ key: "k", currentValue: "v", varIndex: 0, isSecret: true },
|
||||
]
|
||||
service.environments.set(id, vars)
|
||||
expect(service.hasValue(id, "k")).toBe(true)
|
||||
})
|
||||
|
||||
it("should return false if no variable with key exists or value is empty", () => {
|
||||
service.environments.set("env1", [
|
||||
{ key: "k", currentValue: "", varIndex: 0, isSecret: true },
|
||||
])
|
||||
expect(service.hasValue("env1", "k")).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("getEnvironmentByKey", () => {
|
||||
it("should return variable by key", () => {
|
||||
const id = "env1"
|
||||
const vars = [
|
||||
{ key: "k", currentValue: "v", varIndex: 1, isSecret: false },
|
||||
]
|
||||
service.environments.set(id, vars)
|
||||
expect(service.getEnvironmentByKey(id, "k")).toEqual(vars[0])
|
||||
})
|
||||
|
||||
it("should return undefined if key not found", () => {
|
||||
service.environments.set("env1", [])
|
||||
expect(service.getEnvironmentByKey("env1", "k")).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("persistableEnvironments", () => {
|
||||
it("should return the environments in persistable format", () => {
|
||||
const id = "env1"
|
||||
const vars = [
|
||||
{ key: "k", currentValue: "v", varIndex: 0, isSecret: false },
|
||||
]
|
||||
service.environments.set(id, vars)
|
||||
expect(service.persistableEnvironments.value).toEqual({ [id]: vars })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
import { Service } from "dioc"
|
||||
import { cloneDeep } from "lodash-es"
|
||||
import { reactive, computed } from "vue"
|
||||
|
||||
/**
|
||||
* Defines a environment variable.
|
||||
*/
|
||||
export type Variable = {
|
||||
key: string
|
||||
currentValue: string
|
||||
varIndex: number
|
||||
isSecret: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* This service is used to store and manage current value of environment variables.
|
||||
* The current value are not synced with the server.
|
||||
* hence they are not persisted in the database. They are stored
|
||||
* in the local storage of the browser.
|
||||
*/
|
||||
export class CurrentValueService extends Service {
|
||||
public static readonly ID = "CURRENT_VALUE_SERVICE"
|
||||
|
||||
/**
|
||||
* Map of current value of environments.
|
||||
* The key is the ID of the environment.
|
||||
* The value is the list of environment variables.
|
||||
*/
|
||||
public environments = reactive(new Map<string, Variable[]>())
|
||||
|
||||
/**
|
||||
* Add a new environment.
|
||||
* @param id ID of the environment
|
||||
* @param vars List of environment variables
|
||||
*/
|
||||
public addEnvironment(id: string, vars: Variable[]) {
|
||||
this.environments.set(id, vars)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a environment.
|
||||
* @param id ID of the environment
|
||||
*/
|
||||
public getEnvironment(id: string) {
|
||||
return this.environments.get(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new environment variable to the environment.
|
||||
* If the environment does not exist, it will be created.
|
||||
* @param id ID of the environment
|
||||
* @param variable Environment variable to add
|
||||
*/
|
||||
public addEnvironmentVariable(id: string, variable: Variable) {
|
||||
const vars = this.getEnvironment(id)
|
||||
if (vars) {
|
||||
const newVars = cloneDeep(vars)
|
||||
newVars.push(variable)
|
||||
this.environments.set(id, newVars)
|
||||
} else {
|
||||
this.environments.set(id, [variable])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a environment variable.
|
||||
* @param id ID of the environment
|
||||
* @param varIndex Index of the variable in the environment
|
||||
*/
|
||||
public getEnvironmentVariable(id: string, varIndex: number) {
|
||||
const vars = this.getEnvironment(id)
|
||||
return vars?.find((v) => v.varIndex === varIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to get the value of a environment variable.
|
||||
* @param id ID of the environment
|
||||
* @param varIndex Index of the variable in the environment
|
||||
*/
|
||||
public getEnvironmentVariableValue(id: string, varIndex: number) {
|
||||
const variable = this.getEnvironmentVariable(id, varIndex)
|
||||
return variable?.currentValue
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param environments Used to load environments from persisted state.
|
||||
*/
|
||||
public loadEnvironmentsFromPersistedState(
|
||||
environments: Record<string, Variable[]>
|
||||
) {
|
||||
if (environments) {
|
||||
this.environments.clear()
|
||||
|
||||
Object.entries(environments).forEach(([id, vars]) => {
|
||||
this.addEnvironment(id, vars)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a environment.
|
||||
* @param id ID of the environment
|
||||
*/
|
||||
public deleteEnvironment(id: string) {
|
||||
this.environments.delete(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a environment variable.
|
||||
* @param id ID of the environment
|
||||
* @param varIndex Index of the variable in the environment
|
||||
*/
|
||||
public removeEnvironmentVariable(id: string, varIndex: number) {
|
||||
const vars = this.getEnvironment(id)
|
||||
const newVars = vars?.filter((v) => v.varIndex !== varIndex)
|
||||
this.environments.set(id, newVars || [])
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to update the ID of a environment.
|
||||
* Used while syncing with the server.
|
||||
* @param oldID old ID of the environment
|
||||
* @param newID new ID of the environment
|
||||
*/
|
||||
public updateEnvironmentID(oldID: string, newID: string) {
|
||||
const vars = this.getEnvironment(oldID)
|
||||
this.environments.set(newID, vars || [])
|
||||
this.environments.delete(oldID)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param id ID of the environment
|
||||
* @param key Key of the variable to check the value exists
|
||||
* @returns true if the key has a secret value
|
||||
*/
|
||||
public hasValue(id: string, key: string) {
|
||||
return (
|
||||
this.environments.has(id) &&
|
||||
this.environments
|
||||
.get(id)!
|
||||
.some((v) => v.key === key && v.currentValue !== "")
|
||||
)
|
||||
}
|
||||
|
||||
public getEnvironmentByKey(id: string, key: string) {
|
||||
const vars = this.getEnvironment(id)
|
||||
return vars?.find((v) => v.key === key)
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to update the value of a environment variable.
|
||||
*/
|
||||
public persistableEnvironments = computed(() => {
|
||||
const environments: Record<string, Variable[]> = {}
|
||||
this.environments.forEach((vars, id) => {
|
||||
environments[id] = vars
|
||||
})
|
||||
return environments
|
||||
})
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import { EnvironmentInspectorService } from "../environment.inspector"
|
|||
import { InspectionService } from "../../index"
|
||||
import { getDefaultRESTRequest } from "~/helpers/rest/default"
|
||||
import { ref } from "vue"
|
||||
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||
|
||||
vi.mock("~/modules/i18n", () => ({
|
||||
__esModule: true,
|
||||
|
|
@ -16,8 +17,18 @@ vi.mock("~/newstore/environments", async () => {
|
|||
return {
|
||||
__esModule: true,
|
||||
aggregateEnvsWithSecrets$: new BehaviorSubject([
|
||||
{ key: "EXISTING_ENV_VAR", value: "test_value", secret: false },
|
||||
{ key: "EXISTING_ENV_VAR_2", value: "", secret: false },
|
||||
{
|
||||
key: "EXISTING_ENV_VAR",
|
||||
currentValue: "test_value",
|
||||
initialValue: "test_value",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "EXISTING_ENV_VAR_2",
|
||||
currentValue: "",
|
||||
initialValue: "",
|
||||
secret: false,
|
||||
},
|
||||
]),
|
||||
getCurrentEnvironment: () => ({
|
||||
id: "1",
|
||||
|
|
@ -25,7 +36,8 @@ vi.mock("~/newstore/environments", async () => {
|
|||
v: 1,
|
||||
variables: {
|
||||
key: "EXISTING_ENV_VAR",
|
||||
value: "test_value",
|
||||
currentValue: "test_value",
|
||||
initialValue: "test_value",
|
||||
secret: false,
|
||||
},
|
||||
}),
|
||||
|
|
@ -75,6 +87,12 @@ describe("EnvironmentInspectorService", () => {
|
|||
|
||||
it("should not return an inspector result when the URL contains defined environment variables", () => {
|
||||
const container = new TestContainer()
|
||||
container.bindMock(CurrentValueService, {
|
||||
hasValue: vi.fn((key) => {
|
||||
if (key === "EXISTING_ENV_VAR_2") return false
|
||||
return true
|
||||
}),
|
||||
})
|
||||
const envInspector = container.bind(EnvironmentInspectorService)
|
||||
|
||||
const req = ref({
|
||||
|
|
@ -95,7 +113,12 @@ describe("EnvironmentInspectorService", () => {
|
|||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
headers: [
|
||||
{ key: "<<UNDEFINED_ENV_VAR>>", value: "some-value", active: true },
|
||||
{
|
||||
key: "<<UNDEFINED_ENV_VAR>>",
|
||||
value: "some-value",
|
||||
active: true,
|
||||
description: "",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
|
|
@ -115,13 +138,24 @@ describe("EnvironmentInspectorService", () => {
|
|||
|
||||
it("should not return an inspector result when the headers contain defined environment variables", () => {
|
||||
const container = new TestContainer()
|
||||
container.bindMock(CurrentValueService, {
|
||||
hasValue: vi.fn((key) => {
|
||||
if (key === "EXISTING_ENV_VAR_2") return false
|
||||
return true
|
||||
}),
|
||||
})
|
||||
const envInspector = container.bind(EnvironmentInspectorService)
|
||||
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
headers: [
|
||||
{ key: "<<EXISTING_ENV_VAR>>", value: "some-value", active: true },
|
||||
{
|
||||
key: "<<EXISTING_ENV_VAR>>",
|
||||
value: "some-value",
|
||||
active: true,
|
||||
description: "",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
|
|
@ -138,7 +172,12 @@ describe("EnvironmentInspectorService", () => {
|
|||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
params: [
|
||||
{ key: "<<UNDEFINED_ENV_VAR>>", value: "some-value", active: true },
|
||||
{
|
||||
key: "<<UNDEFINED_ENV_VAR>>",
|
||||
value: "some-value",
|
||||
active: true,
|
||||
description: "",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
|
|
@ -158,6 +197,12 @@ describe("EnvironmentInspectorService", () => {
|
|||
|
||||
it("should not return an inspector result when the params contain defined environment variables", () => {
|
||||
const container = new TestContainer()
|
||||
container.bindMock(CurrentValueService, {
|
||||
hasValue: vi.fn((key) => {
|
||||
if (key === "EXISTING_ENV_VAR") return false
|
||||
return true
|
||||
}),
|
||||
})
|
||||
const envInspector = container.bind(EnvironmentInspectorService)
|
||||
|
||||
const req = ref({
|
||||
|
|
@ -165,7 +210,12 @@ describe("EnvironmentInspectorService", () => {
|
|||
endpoint: "http://example.com/api/data",
|
||||
headers: [],
|
||||
params: [
|
||||
{ key: "<<EXISTING_ENV_VAR>>", value: "some-value", active: true },
|
||||
{
|
||||
key: "<<EXISTING_ENV_VAR>>",
|
||||
value: "some-value",
|
||||
active: true,
|
||||
description: "",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
|
|
@ -176,6 +226,12 @@ describe("EnvironmentInspectorService", () => {
|
|||
|
||||
it("should return an inspector result when the URL contains empty value in a environment variable", () => {
|
||||
const container = new TestContainer()
|
||||
container.bindMock(CurrentValueService, {
|
||||
hasValue: vi.fn((key) => {
|
||||
if (key === "EXISTING_ENV_VAR_2") return true
|
||||
return false
|
||||
}),
|
||||
})
|
||||
const envInspector = container.bind(EnvironmentInspectorService)
|
||||
|
||||
const req = ref({
|
||||
|
|
@ -190,6 +246,12 @@ describe("EnvironmentInspectorService", () => {
|
|||
|
||||
it("should not return an inspector result when the URL contains non empty value in a environment variable", () => {
|
||||
const container = new TestContainer()
|
||||
container.bindMock(CurrentValueService, {
|
||||
hasValue: vi.fn((key) => {
|
||||
if (key === "EXISTING_ENV_VAR") return false
|
||||
return true
|
||||
}),
|
||||
})
|
||||
const envInspector = container.bind(EnvironmentInspectorService)
|
||||
|
||||
const req = ref({
|
||||
|
|
@ -210,7 +272,12 @@ describe("EnvironmentInspectorService", () => {
|
|||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
headers: [
|
||||
{ key: "<<EXISTING_ENV_VAR_2>>", value: "some-value", active: true },
|
||||
{
|
||||
key: "<<EXISTING_ENV_VAR_2>>",
|
||||
value: "some-value",
|
||||
active: true,
|
||||
description: "",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
|
|
@ -221,13 +288,24 @@ describe("EnvironmentInspectorService", () => {
|
|||
|
||||
it("should not return an inspector result when the headers contain non empty value in a environment variable", () => {
|
||||
const container = new TestContainer()
|
||||
container.bindMock(CurrentValueService, {
|
||||
hasValue: vi.fn((key) => {
|
||||
if (key === "EXISTING_ENV_VAR") return false
|
||||
return true
|
||||
}),
|
||||
})
|
||||
const envInspector = container.bind(EnvironmentInspectorService)
|
||||
|
||||
const req = ref({
|
||||
...getDefaultRESTRequest(),
|
||||
endpoint: "http://example.com/api/data",
|
||||
headers: [
|
||||
{ key: "<<EXISTING_ENV_VAR>>", value: "some-value", active: true },
|
||||
{
|
||||
key: "<<EXISTING_ENV_VAR>>",
|
||||
value: "some-value",
|
||||
active: true,
|
||||
description: "",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
|
|
@ -245,7 +323,12 @@ describe("EnvironmentInspectorService", () => {
|
|||
endpoint: "http://example.com/api/data",
|
||||
headers: [],
|
||||
params: [
|
||||
{ key: "<<EXISTING_ENV_VAR_2>>", value: "some-value", active: true },
|
||||
{
|
||||
key: "<<EXISTING_ENV_VAR_2>>",
|
||||
value: "some-value",
|
||||
active: true,
|
||||
description: "",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
|
|
@ -256,6 +339,12 @@ describe("EnvironmentInspectorService", () => {
|
|||
|
||||
it("should not return an inspector result when the params contain non empty value in a environment variable", () => {
|
||||
const container = new TestContainer()
|
||||
container.bindMock(CurrentValueService, {
|
||||
hasValue: vi.fn((key) => {
|
||||
if (key === "EXISTING_ENV_VAR") return false
|
||||
return true
|
||||
}),
|
||||
})
|
||||
const envInspector = container.bind(EnvironmentInspectorService)
|
||||
|
||||
const req = ref({
|
||||
|
|
@ -263,7 +352,12 @@ describe("EnvironmentInspectorService", () => {
|
|||
endpoint: "http://example.com/api/data",
|
||||
headers: [],
|
||||
params: [
|
||||
{ key: "<<EXISTING_ENV_VAR>>", value: "some-value", active: true },
|
||||
{
|
||||
key: "<<EXISTING_ENV_VAR>>",
|
||||
value: "some-value",
|
||||
active: true,
|
||||
description: "",
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import { computed } from "vue"
|
|||
import { useStreamStatic } from "~/composables/stream"
|
||||
import { SecretEnvironmentService } from "~/services/secret-environment.service"
|
||||
import { RESTTabService } from "~/services/tab/rest"
|
||||
import { CurrentValueService } from "~/services/current-environment-value.service"
|
||||
|
||||
const HOPP_ENVIRONMENT_REGEX = /(<<[a-zA-Z0-9-_]+>>)/g
|
||||
|
||||
|
|
@ -46,6 +47,7 @@ export class EnvironmentInspectorService extends Service implements Inspector {
|
|||
|
||||
private readonly inspection = this.bind(InspectionService)
|
||||
private readonly secretEnvs = this.bind(SecretEnvironmentService)
|
||||
private readonly currentEnvs = this.bind(CurrentValueService)
|
||||
private readonly restTabs = this.bind(RESTTabService)
|
||||
|
||||
private aggregateEnvsWithSecrets = useStreamStatic(
|
||||
|
|
@ -157,7 +159,7 @@ export class EnvironmentInspectorService extends Service implements Inspector {
|
|||
if (envsMap.has(env.key)) {
|
||||
const existingEnv = envsMap.get(env.key)
|
||||
|
||||
if (existingEnv?.value === "" && env.value !== "") {
|
||||
if (existingEnv?.currentValue === "" && env.currentValue !== "") {
|
||||
envsMap.set(env.key, env)
|
||||
}
|
||||
} else {
|
||||
|
|
@ -200,8 +202,11 @@ export class EnvironmentInspectorService extends Service implements Inspector {
|
|||
|
||||
const environmentVariables =
|
||||
this.filterNonEmptyEnvironmentVariables([
|
||||
// Transform the request variables to environment variables
|
||||
...(currentTabRequest?.requestVariables ?? []).map((env) => ({
|
||||
...env,
|
||||
key: env.key,
|
||||
currentValue: env.value,
|
||||
initialValue: env.value,
|
||||
secret: false,
|
||||
sourceEnv: "RequestVariable",
|
||||
})),
|
||||
|
|
@ -216,8 +221,15 @@ export class EnvironmentInspectorService extends Service implements Inspector {
|
|||
env.key
|
||||
)
|
||||
|
||||
const hasCurrentValue = this.currentEnvs.hasValue(
|
||||
env.sourceEnv !== "Global"
|
||||
? currentSelectedEnvironment.id
|
||||
: "Global",
|
||||
env.key
|
||||
)
|
||||
|
||||
if (env.key === formattedExEnv) {
|
||||
if (env.secret ? !hasSecretEnv : env.value === "") {
|
||||
if (env.secret ? !hasSecretEnv : !hasCurrentValue) {
|
||||
const itemLocation: InspectorLocation = {
|
||||
type: locations.type,
|
||||
position:
|
||||
|
|
|
|||
|
|
@ -81,22 +81,30 @@ export const GQL_COLLECTIONS_MOCK: HoppCollection[] = [
|
|||
|
||||
export const ENVIRONMENTS_MOCK: Environment[] = [
|
||||
{
|
||||
v: 1,
|
||||
v: 2,
|
||||
id: "ENV_1",
|
||||
name: "globals",
|
||||
variables: [
|
||||
{
|
||||
key: "test-global-key",
|
||||
value: "test-global-value",
|
||||
initialValue: "test-global-value",
|
||||
currentValue: "test-global-value",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
v: 1,
|
||||
v: 2,
|
||||
id: "ENV_2",
|
||||
name: "Test",
|
||||
variables: [{ key: "test-key", value: "test-value", secret: false }],
|
||||
variables: [
|
||||
{
|
||||
key: "test-key",
|
||||
initialValue: "test-value",
|
||||
currentValue: "test-value",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -127,8 +135,15 @@ export const MQTT_REQUEST_MOCK = {
|
|||
}
|
||||
|
||||
export const GLOBAL_ENV_MOCK: GlobalEnvironment = {
|
||||
v: 1,
|
||||
variables: [{ key: "test-key", value: "test-value", secret: false }],
|
||||
v: 2,
|
||||
variables: [
|
||||
{
|
||||
key: "test-key",
|
||||
currentValue: "test-value",
|
||||
initialValue: "test-value",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export const VUEX_DATA_MOCK: VUEX_DATA = {
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ import { SIORequest$, setSIORequest } from "../../newstore/SocketIOSession"
|
|||
import { WSRequest$, setWSRequest } from "../../newstore/WebSocketSession"
|
||||
|
||||
import {
|
||||
CURRENT_ENVIRONMENT_VALUE_SCHEMA,
|
||||
ENVIRONMENTS_SCHEMA,
|
||||
GLOBAL_ENVIRONMENT_SCHEMA,
|
||||
GQL_COLLECTION_SCHEMA,
|
||||
|
|
@ -92,6 +93,10 @@ import {
|
|||
import { PersistableTabState } from "../tab"
|
||||
import { HoppTabDocument } from "~/helpers/rest/document"
|
||||
import { HoppGQLDocument } from "~/helpers/graphql/document"
|
||||
import {
|
||||
CurrentValueService,
|
||||
Variable,
|
||||
} from "../current-environment-value.service"
|
||||
|
||||
export const STORE_NAMESPACE = "persistence.v1"
|
||||
|
||||
|
|
@ -113,6 +118,7 @@ export const STORE_KEYS = {
|
|||
REST_TABS: "restTabs",
|
||||
GQL_TABS: "gqlTabs",
|
||||
SECRET_ENVIRONMENTS: "secretEnvironments",
|
||||
CURRENT_ENVIRONMENT_VALUE: "currentEnvironmentValue",
|
||||
SCHEMA_VERSION: "schema_version",
|
||||
} as const
|
||||
|
||||
|
|
@ -175,6 +181,8 @@ export class PersistenceService extends Service {
|
|||
private readonly secretEnvironmentService = this.bind(
|
||||
SecretEnvironmentService
|
||||
)
|
||||
private readonly currentEnvironmentValueService =
|
||||
this.bind(CurrentValueService)
|
||||
|
||||
private showErrorToast(key: string) {
|
||||
const toast = useToast()
|
||||
|
|
@ -600,6 +608,55 @@ export class PersistenceService extends Service {
|
|||
)
|
||||
}
|
||||
|
||||
private async setupCurrentEnvironmentValuePersistence() {
|
||||
const loadResult = await Store.get<any>(
|
||||
STORE_NAMESPACE,
|
||||
STORE_KEYS.CURRENT_ENVIRONMENT_VALUE
|
||||
)
|
||||
|
||||
try {
|
||||
if (E.isRight(loadResult) && loadResult.right) {
|
||||
const result = CURRENT_ENVIRONMENT_VALUE_SCHEMA.safeParse(
|
||||
loadResult.right
|
||||
)
|
||||
|
||||
if (result.success) {
|
||||
this.currentEnvironmentValueService.loadEnvironmentsFromPersistedState(
|
||||
result.data
|
||||
)
|
||||
} else {
|
||||
this.showErrorToast(STORE_KEYS.CURRENT_ENVIRONMENT_VALUE)
|
||||
await Store.set(
|
||||
STORE_NAMESPACE,
|
||||
`${STORE_KEYS.CURRENT_ENVIRONMENT_VALUE}-backup`,
|
||||
loadResult.right
|
||||
)
|
||||
console.error(
|
||||
`Failed parsing persisted CURRENT_ENVIRONMENT_VALUE:`,
|
||||
JSON.stringify(loadResult.right)
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`Failed parsing persisted CURRENT_ENVIRONMENT_VALUE:`,
|
||||
loadResult
|
||||
)
|
||||
}
|
||||
|
||||
watchDebounced(
|
||||
this.currentEnvironmentValueService.persistableEnvironments,
|
||||
async (newData: Record<string, Variable[]>) => {
|
||||
await Store.set(
|
||||
STORE_NAMESPACE,
|
||||
STORE_KEYS.CURRENT_ENVIRONMENT_VALUE,
|
||||
newData
|
||||
)
|
||||
},
|
||||
{ debounce: 500 }
|
||||
)
|
||||
}
|
||||
|
||||
private async setupSelectedEnvPersistence() {
|
||||
const loadResult = await Store.get<any>(
|
||||
STORE_NAMESPACE,
|
||||
|
|
@ -914,6 +971,7 @@ export class PersistenceService extends Service {
|
|||
this.setupGQLTabsPersistence(),
|
||||
|
||||
this.setupSecretEnvironmentsPersistence(),
|
||||
this.setupCurrentEnvironmentValuePersistence(),
|
||||
])
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -228,12 +228,9 @@ export const MQTT_REQUEST_SCHEMA = z.nullable(
|
|||
const EnvironmentVariablesSchema = z.union([
|
||||
z.object({
|
||||
key: z.string(),
|
||||
value: z.string(),
|
||||
secret: z.literal(false).catch(false),
|
||||
}),
|
||||
z.object({
|
||||
key: z.string(),
|
||||
secret: z.literal(true),
|
||||
initialValue: z.string(),
|
||||
currentValue: z.string(),
|
||||
secret: z.boolean(),
|
||||
}),
|
||||
z.object({
|
||||
key: z.string(),
|
||||
|
|
@ -376,6 +373,24 @@ export const SECRET_ENVIRONMENT_VARIABLE_SCHEMA = z.union([
|
|||
),
|
||||
])
|
||||
|
||||
export const CURRENT_ENVIRONMENT_VALUE_SCHEMA = z.union([
|
||||
z.object({}).strict(),
|
||||
|
||||
z.record(
|
||||
z.string(),
|
||||
z.array(
|
||||
z
|
||||
.object({
|
||||
key: z.string(),
|
||||
currentValue: z.string(),
|
||||
varIndex: z.number(),
|
||||
isSecret: z.boolean(),
|
||||
})
|
||||
.strict()
|
||||
)
|
||||
),
|
||||
])
|
||||
|
||||
const HoppTestResultSchema = z
|
||||
.object({
|
||||
tests: z.array(HoppTestDataSchema),
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ export class SecretEnvironmentService extends Service {
|
|||
* Used to get the value of a secret environment variable.
|
||||
* @param id ID of the environment
|
||||
* @param varIndex Index of the variable in the environment
|
||||
= */
|
||||
*/
|
||||
public getSecretEnvironmentVariableValue(id: string, varIndex: number) {
|
||||
const secretVar = this.getSecretEnvironmentVariable(id, varIndex)
|
||||
return secretVar?.value
|
||||
|
|
@ -101,7 +101,7 @@ export class SecretEnvironmentService extends Service {
|
|||
}
|
||||
|
||||
/**
|
||||
* Used to update thye ID of a secret environment.
|
||||
* Used to update the ID of a secret environment.
|
||||
* Used while syncing with the server.
|
||||
* @param oldID old ID of the environment
|
||||
* @param newID new ID of the environment
|
||||
|
|
|
|||
|
|
@ -82,6 +82,10 @@ export class EnvironmentsSpotlightSearcherService extends StaticSpotlightSearche
|
|||
public readonly searcherID = "environments"
|
||||
public searcherSectionTitle = this.t("spotlight.environments.title")
|
||||
|
||||
private readonly workspaceService = this.bind(WorkspaceService)
|
||||
|
||||
private workspace = this.workspaceService.currentWorkspace
|
||||
|
||||
private readonly spotlight = this.bind(SpotlightService)
|
||||
|
||||
private selectedEnvIndex = useStreamStatic(
|
||||
|
|
@ -239,10 +243,17 @@ export class EnvironmentsSpotlightSearcherService extends StaticSpotlightSearche
|
|||
})
|
||||
break
|
||||
case "edit_selected_env":
|
||||
if (this.selectedEnv.value)
|
||||
invokeAction(`modals.my.environment.edit`, {
|
||||
envName: this.selectedEnv.value.name,
|
||||
})
|
||||
if (this.selectedEnv.value) {
|
||||
if (this.workspace.value.type === "personal") {
|
||||
invokeAction(`modals.my.environment.edit`, {
|
||||
envName: this.selectedEnv.value.name,
|
||||
})
|
||||
} else {
|
||||
invokeAction(`modals.team.environment.edit`, {
|
||||
envName: this.selectedEnv.value.name,
|
||||
})
|
||||
}
|
||||
}
|
||||
break
|
||||
case "delete_selected_env":
|
||||
invokeAction(`modals.environment.delete-selected`)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { z } from "zod"
|
|||
|
||||
import V0_VERSION from "./v/0"
|
||||
import V1_VERSION, { uniqueID } from "./v/1"
|
||||
import V2_VERSION from "./v/2"
|
||||
import { HOPP_SUPPORTED_PREDEFINED_VARIABLES } from "../predefinedVariables"
|
||||
|
||||
const versionedObject = z.object({
|
||||
|
|
@ -13,10 +14,11 @@ const versionedObject = z.object({
|
|||
})
|
||||
|
||||
export const Environment = createVersionedEntity({
|
||||
latestVersion: 1,
|
||||
latestVersion: 2,
|
||||
versionMap: {
|
||||
0: V0_VERSION,
|
||||
1: V1_VERSION,
|
||||
2: V2_VERSION,
|
||||
},
|
||||
getVersion(data) {
|
||||
const versionCheck = versionedObject.safeParse(data)
|
||||
|
|
@ -48,7 +50,7 @@ const ENV_MAX_EXPAND_LIMIT = 10
|
|||
*/
|
||||
const ENV_EXPAND_LOOP = "ENV_EXPAND_LOOP" as const
|
||||
|
||||
export const EnvironmentSchemaVersion = 1
|
||||
export const EnvironmentSchemaVersion = 2
|
||||
|
||||
export function parseBodyEnvVariablesE(
|
||||
body: string,
|
||||
|
|
@ -72,8 +74,8 @@ export function parseBodyEnvVariablesE(
|
|||
|
||||
const foundEnv = env.find((envVar) => envVar.key === variableName)
|
||||
|
||||
if (foundEnv && "value" in foundEnv) {
|
||||
return foundEnv.value
|
||||
if (foundEnv && "currentValue" in foundEnv) {
|
||||
return foundEnv.currentValue
|
||||
}
|
||||
return key
|
||||
})
|
||||
|
|
@ -102,7 +104,11 @@ export function parseTemplateStringE(
|
|||
str: string,
|
||||
variables:
|
||||
| Environment["variables"]
|
||||
| { secret: true; value: string; key: string }[],
|
||||
| {
|
||||
secret: true
|
||||
currentValue: string
|
||||
key: string
|
||||
}[],
|
||||
maskValue = false,
|
||||
showKeyIfSecret = false
|
||||
) {
|
||||
|
|
@ -131,7 +137,7 @@ export function parseTemplateStringE(
|
|||
|
||||
const variable = variables.find((x) => x && x.key === p1)
|
||||
|
||||
if (variable && "value" in variable) {
|
||||
if (variable && "currentValue" in variable) {
|
||||
// Show the key if it is a secret and explicitly specified
|
||||
if (variable.secret && showKeyIfSecret) {
|
||||
isSecret = true
|
||||
|
|
@ -140,11 +146,17 @@ export function parseTemplateStringE(
|
|||
// Mask the value if it is a secret and explicitly specified
|
||||
if (variable.secret && maskValue) {
|
||||
return "*".repeat(
|
||||
(variable as { secret: true; value: string; key: string }).value
|
||||
.length
|
||||
(
|
||||
variable as {
|
||||
secret: true
|
||||
initialValue: string
|
||||
currentValue: string
|
||||
key: string
|
||||
}
|
||||
).currentValue.length
|
||||
)
|
||||
}
|
||||
return variable.value
|
||||
return variable.currentValue
|
||||
}
|
||||
|
||||
return ""
|
||||
|
|
@ -173,7 +185,11 @@ export const parseTemplateString = (
|
|||
str: string,
|
||||
variables:
|
||||
| Environment["variables"]
|
||||
| { secret: true; value: string; key: string }[],
|
||||
| {
|
||||
secret: true
|
||||
currentValue: string
|
||||
key: string
|
||||
}[],
|
||||
maskValue = false,
|
||||
showKeyIfSecret = false
|
||||
) =>
|
||||
|
|
@ -187,7 +203,8 @@ export const translateToNewEnvironmentVariables = (
|
|||
): Environment["variables"][number] => {
|
||||
return {
|
||||
key: x.key,
|
||||
value: x.value,
|
||||
initialValue: x.initialValue ?? x.value ?? "",
|
||||
currentValue: x.currentValue ?? x.value ?? "",
|
||||
secret: false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
40
packages/hoppscotch-data/src/environment/v/2.ts
Normal file
40
packages/hoppscotch-data/src/environment/v/2.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import { boolean, z } from "zod"
|
||||
import { defineVersion } from "verzod"
|
||||
import { V1_SCHEMA } from "./1"
|
||||
|
||||
// add initialValue and currentValue to the schema and delete value and add it to initialValue and currentValue
|
||||
export const V2_SCHEMA = V1_SCHEMA.extend({
|
||||
v: z.literal(2),
|
||||
variables: z.array(
|
||||
z.object({
|
||||
key: z.string(),
|
||||
initialValue: z.string(),
|
||||
currentValue: z.string(),
|
||||
secret: z.boolean(),
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
export default defineVersion({
|
||||
initial: false,
|
||||
schema: V2_SCHEMA,
|
||||
up(old: z.infer<typeof V1_SCHEMA>) {
|
||||
const result: z.infer<typeof V2_SCHEMA> = {
|
||||
...old,
|
||||
v: 2,
|
||||
variables: old.variables.map((variable) => {
|
||||
// if the variable is secret, set initialValue and currentValue to empty string
|
||||
// else set initialValue and currentValue to value
|
||||
// and delete value
|
||||
return {
|
||||
...variable,
|
||||
initialValue: variable.secret ? "" : variable.value,
|
||||
currentValue: variable.secret ? "" : variable.value,
|
||||
value: undefined,
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
||||
return result
|
||||
},
|
||||
})
|
||||
|
|
@ -4,16 +4,18 @@ import { z } from "zod"
|
|||
|
||||
import V0_VERSION from "./v/0"
|
||||
import V1_VERSION from "./v/1"
|
||||
import V2_VERSION from "./v/2"
|
||||
|
||||
const versionedObject = z.object({
|
||||
v: z.number(),
|
||||
})
|
||||
|
||||
export const GlobalEnvironment = createVersionedEntity({
|
||||
latestVersion: 1,
|
||||
latestVersion: 2,
|
||||
versionMap: {
|
||||
0: V0_VERSION,
|
||||
1: V1_VERSION,
|
||||
2: V2_VERSION,
|
||||
},
|
||||
getVersion(data) {
|
||||
const versionCheck = versionedObject.safeParse(data)
|
||||
|
|
|
|||
39
packages/hoppscotch-data/src/global-environment/v/2.ts
Normal file
39
packages/hoppscotch-data/src/global-environment/v/2.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import { z } from "zod"
|
||||
import { defineVersion } from "verzod"
|
||||
import { V1_SCHEMA } from "./1"
|
||||
|
||||
export const V2_SCHEMA = V1_SCHEMA.extend({
|
||||
v: z.literal(2),
|
||||
variables: z.array(
|
||||
z.object({
|
||||
key: z.string(),
|
||||
initialValue: z.string(),
|
||||
currentValue: z.string(),
|
||||
secret: z.boolean(),
|
||||
})
|
||||
),
|
||||
})
|
||||
|
||||
export default defineVersion({
|
||||
initial: false,
|
||||
schema: V2_SCHEMA,
|
||||
up(old: z.infer<typeof V1_SCHEMA>) {
|
||||
const result: z.infer<typeof V2_SCHEMA> = {
|
||||
...old,
|
||||
v: 2,
|
||||
variables: old.variables.map((variable) => {
|
||||
// if the variable is secret, set initialValue and currentValue to empty string
|
||||
// else set initialValue and currentValue to value
|
||||
// and delete value
|
||||
return {
|
||||
...variable,
|
||||
initialValue: variable.secret ? "" : variable.value,
|
||||
currentValue: variable.secret ? "" : variable.value,
|
||||
value: undefined,
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
||||
return result
|
||||
},
|
||||
})
|
||||
|
|
@ -11,13 +11,27 @@ describe("Base64 helper functions", () => {
|
|||
atob: {
|
||||
script: `pw.env.set("atob", atob("SGVsbG8gV29ybGQ="))`,
|
||||
environment: {
|
||||
selected: [{ key: "atob", value: "Hello World", secret: false }],
|
||||
selected: [
|
||||
{
|
||||
key: "atob",
|
||||
currentValue: "Hello World",
|
||||
initialValue: "Hello World",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
btoa: {
|
||||
script: `pw.env.set("btoa", btoa("Hello World"))`,
|
||||
environment: {
|
||||
selected: [{ key: "btoa", value: "SGVsbG8gV29ybGQ=", secret: false }],
|
||||
selected: [
|
||||
{
|
||||
key: "btoa",
|
||||
currentValue: "SGVsbG8gV29ybGQ=",
|
||||
initialValue: "SGVsbG8gV29ybGQ=",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ describe("pw.env.get", () => {
|
|||
selected: [
|
||||
{
|
||||
key: "a",
|
||||
value: "b",
|
||||
currentValue: "b",
|
||||
initialValue: "b",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -60,7 +61,8 @@ describe("pw.env.get", () => {
|
|||
global: [
|
||||
{
|
||||
key: "a",
|
||||
value: "b",
|
||||
currentValue: "b",
|
||||
initialValue: "b",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -114,14 +116,16 @@ describe("pw.env.get", () => {
|
|||
global: [
|
||||
{
|
||||
key: "a",
|
||||
value: "global val",
|
||||
currentValue: "global val",
|
||||
initialValue: "global val",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
selected: [
|
||||
{
|
||||
key: "a",
|
||||
value: "selected val",
|
||||
currentValue: "selected val",
|
||||
initialValue: "selected val",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -151,7 +155,8 @@ describe("pw.env.get", () => {
|
|||
selected: [
|
||||
{
|
||||
key: "a",
|
||||
value: "<<hello>>",
|
||||
currentValue: "<<hello>>",
|
||||
initialValue: "<<hello>>",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ describe("pw.env.getResolve", () => {
|
|||
selected: [
|
||||
{
|
||||
key: "a",
|
||||
value: "b",
|
||||
currentValue: "b",
|
||||
initialValue: "b",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -60,7 +61,8 @@ describe("pw.env.getResolve", () => {
|
|||
global: [
|
||||
{
|
||||
key: "a",
|
||||
value: "b",
|
||||
currentValue: "b",
|
||||
initialValue: "b",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -114,14 +116,16 @@ describe("pw.env.getResolve", () => {
|
|||
global: [
|
||||
{
|
||||
key: "a",
|
||||
value: "global val",
|
||||
currentValue: "global val",
|
||||
initialValue: "global val",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
selected: [
|
||||
{
|
||||
key: "a",
|
||||
value: "selected val",
|
||||
currentValue: "selected val",
|
||||
initialValue: "selected val",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -151,12 +155,14 @@ describe("pw.env.getResolve", () => {
|
|||
selected: [
|
||||
{
|
||||
key: "a",
|
||||
value: "<<hello>>",
|
||||
currentValue: "<<hello>>",
|
||||
initialValue: "<<hello>>",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "hello",
|
||||
value: "there",
|
||||
currentValue: "there",
|
||||
initialValue: "there",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -186,12 +192,14 @@ describe("pw.env.getResolve", () => {
|
|||
selected: [
|
||||
{
|
||||
key: "a",
|
||||
value: "<<hello>>",
|
||||
currentValue: "<<hello>>",
|
||||
initialValue: "<<hello>>",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "hello",
|
||||
value: "<<a>>",
|
||||
currentValue: "<<a>>",
|
||||
initialValue: "<<a>>",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ describe("pw.env.resolve", () => {
|
|||
global: [
|
||||
{
|
||||
key: "hello",
|
||||
value: "there",
|
||||
initialValue: "there",
|
||||
currentValue: "there",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -75,7 +76,8 @@ describe("pw.env.resolve", () => {
|
|||
selected: [
|
||||
{
|
||||
key: "hello",
|
||||
value: "there",
|
||||
initialValue: "there",
|
||||
currentValue: "there",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -104,14 +106,16 @@ describe("pw.env.resolve", () => {
|
|||
global: [
|
||||
{
|
||||
key: "hello",
|
||||
value: "yo",
|
||||
initialValue: "yo",
|
||||
currentValue: "yo",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
selected: [
|
||||
{
|
||||
key: "hello",
|
||||
value: "there",
|
||||
initialValue: "there",
|
||||
currentValue: "there",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -141,12 +145,14 @@ describe("pw.env.resolve", () => {
|
|||
selected: [
|
||||
{
|
||||
key: "hello",
|
||||
value: "<<there>>",
|
||||
currentValue: "<<there>>",
|
||||
initialValue: "<<there>>",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "there",
|
||||
value: "<<hello>>",
|
||||
currentValue: "<<hello>>",
|
||||
initialValue: "<<hello>>",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ describe("pw.env.set", () => {
|
|||
selected: [
|
||||
{
|
||||
key: "a",
|
||||
value: "b",
|
||||
currentValue: "b",
|
||||
initialValue: "b",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -47,7 +48,8 @@ describe("pw.env.set", () => {
|
|||
selected: [
|
||||
{
|
||||
key: "a",
|
||||
value: "c",
|
||||
currentValue: "c",
|
||||
initialValue: "b",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -65,7 +67,8 @@ describe("pw.env.set", () => {
|
|||
global: [
|
||||
{
|
||||
key: "a",
|
||||
value: "b",
|
||||
currentValue: "b",
|
||||
initialValue: "b",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -77,7 +80,8 @@ describe("pw.env.set", () => {
|
|||
global: [
|
||||
{
|
||||
key: "a",
|
||||
value: "c",
|
||||
currentValue: "c",
|
||||
initialValue: "b",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -95,14 +99,16 @@ describe("pw.env.set", () => {
|
|||
global: [
|
||||
{
|
||||
key: "a",
|
||||
value: "b",
|
||||
currentValue: "b",
|
||||
initialValue: "b",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
selected: [
|
||||
{
|
||||
key: "a",
|
||||
value: "d",
|
||||
currentValue: "d",
|
||||
initialValue: "d",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -113,14 +119,16 @@ describe("pw.env.set", () => {
|
|||
global: [
|
||||
{
|
||||
key: "a",
|
||||
value: "b",
|
||||
currentValue: "b",
|
||||
initialValue: "b",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
selected: [
|
||||
{
|
||||
key: "a",
|
||||
value: "c",
|
||||
currentValue: "c",
|
||||
initialValue: "d",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -145,7 +153,8 @@ describe("pw.env.set", () => {
|
|||
selected: [
|
||||
{
|
||||
key: "a",
|
||||
value: "c",
|
||||
currentValue: "c",
|
||||
initialValue: "c",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ describe("pw.env.unset", () => {
|
|||
selected: [
|
||||
{
|
||||
key: "baseUrl",
|
||||
value: "https://echo.hoppscotch.io",
|
||||
currentValue: "https://echo.hoppscotch.io",
|
||||
initialValue: "https://echo.hoppscotch.io",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -59,7 +60,8 @@ describe("pw.env.unset", () => {
|
|||
global: [
|
||||
{
|
||||
key: "baseUrl",
|
||||
value: "https://echo.hoppscotch.io",
|
||||
currentValue: "https://echo.hoppscotch.io",
|
||||
initialValue: "https://echo.hoppscotch.io",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -83,14 +85,16 @@ describe("pw.env.unset", () => {
|
|||
global: [
|
||||
{
|
||||
key: "baseUrl",
|
||||
value: "https://httpbin.org",
|
||||
currentValue: "https://httpbin.org",
|
||||
initialValue: "https://httpbin.org",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
selected: [
|
||||
{
|
||||
key: "baseUrl",
|
||||
value: "https://echo.hoppscotch.io",
|
||||
currentValue: "https://echo.hoppscotch.io",
|
||||
initialValue: "https://echo.hoppscotch.io",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -101,7 +105,8 @@ describe("pw.env.unset", () => {
|
|||
global: [
|
||||
{
|
||||
key: "baseUrl",
|
||||
value: "https://httpbin.org",
|
||||
currentValue: "https://httpbin.org",
|
||||
initialValue: "https://httpbin.org",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -120,19 +125,22 @@ describe("pw.env.unset", () => {
|
|||
global: [
|
||||
{
|
||||
key: "baseUrl",
|
||||
value: "https://echo.hoppscotch.io",
|
||||
currentValue: "https://echo.hoppscotch.io",
|
||||
initialValue: "https://echo.hoppscotch.io",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
selected: [
|
||||
{
|
||||
key: "baseUrl",
|
||||
value: "https://httpbin.org",
|
||||
currentValue: "https://httpbin.org",
|
||||
initialValue: "https://httpbin.org",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "baseUrl",
|
||||
value: "https://echo.hoppscotch.io",
|
||||
currentValue: "https://echo.hoppscotch.io",
|
||||
initialValue: "https://echo.hoppscotch.io",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -143,14 +151,16 @@ describe("pw.env.unset", () => {
|
|||
global: [
|
||||
{
|
||||
key: "baseUrl",
|
||||
value: "https://echo.hoppscotch.io",
|
||||
currentValue: "https://echo.hoppscotch.io",
|
||||
initialValue: "https://echo.hoppscotch.io",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
selected: [
|
||||
{
|
||||
key: "baseUrl",
|
||||
value: "https://echo.hoppscotch.io",
|
||||
currentValue: "https://echo.hoppscotch.io",
|
||||
initialValue: "https://echo.hoppscotch.io",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -168,12 +178,14 @@ describe("pw.env.unset", () => {
|
|||
global: [
|
||||
{
|
||||
key: "baseUrl",
|
||||
value: "https://httpbin.org/",
|
||||
currentValue: "https://httpbin.org",
|
||||
initialValue: "https://httpbin.org",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "baseUrl",
|
||||
value: "https://echo.hoppscotch.io",
|
||||
currentValue: "https://echo.hoppscotch.io",
|
||||
initialValue: "https://echo.hoppscotch.io",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -185,7 +197,8 @@ describe("pw.env.unset", () => {
|
|||
global: [
|
||||
{
|
||||
key: "baseUrl",
|
||||
value: "https://echo.hoppscotch.io",
|
||||
currentValue: "https://echo.hoppscotch.io",
|
||||
initialValue: "https://echo.hoppscotch.io",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
@ -239,7 +252,8 @@ describe("pw.env.unset", () => {
|
|||
selected: [
|
||||
{
|
||||
key: "baseUrl",
|
||||
value: "https://echo.hoppscotch.io",
|
||||
currentValue: "https://echo.hoppscotch.io",
|
||||
initialValue: "https://echo.hoppscotch.io",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -12,16 +12,36 @@ describe("runPreRequestScript", () => {
|
|||
{
|
||||
global: [],
|
||||
selected: [
|
||||
{ key: "bob", value: "oldbob", secret: false },
|
||||
{ key: "foo", value: "bar", secret: false },
|
||||
{
|
||||
key: "bob",
|
||||
currentValue: "oldbob",
|
||||
initialValue: "oldbob",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "foo",
|
||||
currentValue: "bar",
|
||||
initialValue: "bar",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
}
|
||||
)()
|
||||
).resolves.toEqualRight({
|
||||
global: [],
|
||||
selected: [
|
||||
{ key: "bob", value: "newbob", secret: false },
|
||||
{ key: "foo", value: "bar", secret: false },
|
||||
{
|
||||
key: "bob",
|
||||
currentValue: "newbob",
|
||||
initialValue: "oldbob",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "foo",
|
||||
currentValue: "bar",
|
||||
initialValue: "bar",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
|
@ -35,8 +55,18 @@ describe("runPreRequestScript", () => {
|
|||
{
|
||||
global: [],
|
||||
selected: [
|
||||
{ key: "bob", value: "oldbob", secret: false },
|
||||
{ key: "foo", value: "bar", secret: false },
|
||||
{
|
||||
key: "bob",
|
||||
currentValue: "oldbob",
|
||||
initialValue: "oldbob",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "foo",
|
||||
currentValue: "bar",
|
||||
initialValue: "bar",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
}
|
||||
)()
|
||||
|
|
@ -52,8 +82,18 @@ describe("runPreRequestScript", () => {
|
|||
{
|
||||
global: [],
|
||||
selected: [
|
||||
{ key: "bob", value: "oldbob", secret: false },
|
||||
{ key: "foo", value: "bar", secret: false },
|
||||
{
|
||||
key: "bob",
|
||||
currentValue: "oldbob",
|
||||
initialValue: "oldbob",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "foo",
|
||||
currentValue: "bar",
|
||||
initialValue: "bar",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
}
|
||||
)()
|
||||
|
|
@ -69,8 +109,18 @@ describe("runPreRequestScript", () => {
|
|||
{
|
||||
global: [],
|
||||
selected: [
|
||||
{ key: "bob", value: "oldbob", secret: false },
|
||||
{ key: "foo", value: "bar", secret: false },
|
||||
{
|
||||
key: "bob",
|
||||
currentValue: "oldbob",
|
||||
initialValue: "oldbob",
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
key: "foo",
|
||||
currentValue: "bar",
|
||||
initialValue: "bar",
|
||||
secret: false,
|
||||
},
|
||||
],
|
||||
}
|
||||
)()
|
||||
|
|
@ -87,7 +137,9 @@ describe("runPreRequestScript", () => {
|
|||
)()
|
||||
).resolves.toEqualRight({
|
||||
global: [],
|
||||
selected: [{ key: "foo", value: "bar", secret: false }],
|
||||
selected: [
|
||||
{ key: "foo", currentValue: "bar", initialValue: "bar", secret: false },
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -39,16 +39,18 @@ const setEnv = (
|
|||
|
||||
if (indexInSelected >= 0) {
|
||||
const selectedEnv = selected[indexInSelected]
|
||||
if ("value" in selectedEnv) {
|
||||
selectedEnv.value = envValue
|
||||
if ("currentValue" in selectedEnv) {
|
||||
selectedEnv.currentValue = envValue
|
||||
}
|
||||
} else if (indexInGlobal >= 0) {
|
||||
if ("value" in global[indexInGlobal])
|
||||
(global[indexInGlobal] as { value: string }).value = envValue
|
||||
if ("currentValue" in global[indexInGlobal])
|
||||
(global[indexInGlobal] as { currentValue: string }).currentValue =
|
||||
envValue
|
||||
} else {
|
||||
selected.push({
|
||||
key: envName,
|
||||
value: envValue,
|
||||
currentValue: envValue,
|
||||
initialValue: envValue,
|
||||
secret: false,
|
||||
})
|
||||
}
|
||||
|
|
@ -93,7 +95,7 @@ const getSharedMethods = (envs: TestResult["envs"]) => {
|
|||
getEnv(key, updatedEnvs),
|
||||
O.fold(
|
||||
() => undefined,
|
||||
(env) => String(env.value)
|
||||
(env) => String(env.currentValue)
|
||||
)
|
||||
)
|
||||
|
||||
|
|
@ -111,11 +113,11 @@ const getSharedMethods = (envs: TestResult["envs"]) => {
|
|||
|
||||
E.map((e) =>
|
||||
pipe(
|
||||
parseTemplateStringE(e.value, [
|
||||
parseTemplateStringE(e.currentValue, [
|
||||
...updatedEnvs.selected,
|
||||
...updatedEnvs.global,
|
||||
]), // If the recursive resolution failed, return the unresolved value
|
||||
E.getOrElse(() => e.value)
|
||||
E.getOrElse(() => e.currentValue)
|
||||
)
|
||||
),
|
||||
E.map((x) => String(x)),
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ export type TestDescriptor = {
|
|||
// Representation of a transformed state for environment variables in the sandbox
|
||||
type TransformedEnvironmentVariable = {
|
||||
key: string
|
||||
value: string
|
||||
currentValue: string
|
||||
initialValue: string
|
||||
secret: boolean
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ async function loadUserEnvironments() {
|
|||
runDispatchWithOutSyncing(() => {
|
||||
replaceEnvironments(
|
||||
environments.map(({ id, variables, name }) => ({
|
||||
v: 1,
|
||||
v: 2,
|
||||
id,
|
||||
name,
|
||||
variables: JSON.parse(variables),
|
||||
|
|
@ -176,7 +176,7 @@ function setupUserEnvironmentUpdatedSubscription() {
|
|||
if ((localIndex || localIndex == 0) && name) {
|
||||
runDispatchWithOutSyncing(() => {
|
||||
updateEnvironment(localIndex, {
|
||||
v: 1,
|
||||
v: 2,
|
||||
id,
|
||||
name,
|
||||
variables: JSON.parse(variables),
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
|||
name: "",
|
||||
variables: entries,
|
||||
id: "",
|
||||
v: 1,
|
||||
v: 2,
|
||||
})()
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ async function loadUserEnvironments() {
|
|||
runDispatchWithOutSyncing(() => {
|
||||
replaceEnvironments(
|
||||
environments.map(({ id, variables, name }) => ({
|
||||
v: 1,
|
||||
v: 2,
|
||||
id,
|
||||
name,
|
||||
variables: JSON.parse(variables),
|
||||
|
|
@ -176,7 +176,7 @@ function setupUserEnvironmentUpdatedSubscription() {
|
|||
if ((localIndex || localIndex == 0) && name) {
|
||||
runDispatchWithOutSyncing(() => {
|
||||
updateEnvironment(localIndex, {
|
||||
v: 1,
|
||||
v: 2,
|
||||
id,
|
||||
name,
|
||||
variables: JSON.parse(variables),
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
|||
name: "",
|
||||
variables: entries,
|
||||
id: "",
|
||||
v: 1,
|
||||
v: 2,
|
||||
})()
|
||||
}
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue