Compare commits
8 Commits
fix/graphq
...
pr/danithe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9581f1d747 | ||
|
|
882aafdb43 | ||
|
|
f33fa6ac1a | ||
|
|
b9a1cc21f1 | ||
|
|
f530fc2853 | ||
|
|
e0eb8af6f5 | ||
|
|
088f1d6b47 | ||
|
|
7d61e69b3d |
@@ -14,7 +14,8 @@ import { isHoppCLIError } from "../utils/checks";
|
|||||||
export const test = (path: string, options: TestCmdOptions) => async () => {
|
export const test = (path: string, options: TestCmdOptions) => async () => {
|
||||||
try {
|
try {
|
||||||
const delay = options.delay ? parseDelayOption(options.delay) : 0
|
const delay = options.delay ? parseDelayOption(options.delay) : 0
|
||||||
const envs = options.env ? await parseEnvsData(options.env) : <HoppEnvs>{ global: [], selected: [] }
|
const envName = options.envName
|
||||||
|
const envs = options.env ? await parseEnvsData(options.env, envName) : <HoppEnvs>{ global: [], selected: [] }
|
||||||
const collections = await parseCollectionData(path)
|
const collections = await parseCollectionData(path)
|
||||||
|
|
||||||
const report = await collectionsRunner({collections, envs, delay})
|
const report = await collectionsRunner({collections, envs, delay})
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ export const handleError = <T extends HoppErrorCode>(error: HoppError<T>) => {
|
|||||||
case "MALFORMED_COLLECTION":
|
case "MALFORMED_COLLECTION":
|
||||||
ERROR_MSG = `${error.path}\n${parseErrorData(error.data)}`;
|
ERROR_MSG = `${error.path}\n${parseErrorData(error.data)}`;
|
||||||
break;
|
break;
|
||||||
|
case "ENVIRONMENT_NAME_NOT_FOUND":
|
||||||
|
ERROR_MSG = `\n${parseErrorData(error.data)}`;
|
||||||
|
break;
|
||||||
case "NO_FILE_PATH":
|
case "NO_FILE_PATH":
|
||||||
ERROR_MSG = `Please provide a hoppscotch-collection file path.`;
|
ERROR_MSG = `Please provide a hoppscotch-collection file path.`;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ program
|
|||||||
"path to a hoppscotch collection.json file for CI testing"
|
"path to a hoppscotch collection.json file for CI testing"
|
||||||
)
|
)
|
||||||
.option("-e, --env <file_path>", "path to an environment variables json file")
|
.option("-e, --env <file_path>", "path to an environment variables json file")
|
||||||
|
.option("-eN, --envName <environment_name>","Specific Name of the environment")
|
||||||
.option(
|
.option(
|
||||||
"-d, --delay <delay_in_ms>",
|
"-d, --delay <delay_in_ms>",
|
||||||
"delay in milliseconds(ms) between consecutive requests within a collection"
|
"delay in milliseconds(ms) between consecutive requests within a collection"
|
||||||
|
|||||||
@@ -33,4 +33,5 @@ export interface EffectiveHoppRESTRequest extends HoppRESTRequest {
|
|||||||
effectiveFinalHeaders: { key: string; value: string; active: boolean }[];
|
effectiveFinalHeaders: { key: string; value: string; active: boolean }[];
|
||||||
effectiveFinalParams: { key: string; value: string; active: boolean }[];
|
effectiveFinalParams: { key: string; value: string; active: boolean }[];
|
||||||
effectiveFinalBody: FormData | string | null;
|
effectiveFinalBody: FormData | string | null;
|
||||||
|
effectiveFinalMaskedURL: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,23 +5,46 @@ import { readJsonFile } from "../../utils/mutators";
|
|||||||
/**
|
/**
|
||||||
* Parses env json file for given path and validates the parsed env json object.
|
* Parses env json file for given path and validates the parsed env json object.
|
||||||
* @param path Path of env.json file to be parsed.
|
* @param path Path of env.json file to be parsed.
|
||||||
|
* @param envName Name of the environment that should be used. If undefined first environment is used.
|
||||||
* @returns For successful parsing we get HoppEnvs object.
|
* @returns For successful parsing we get HoppEnvs object.
|
||||||
*/
|
*/
|
||||||
export async function parseEnvsData(path: string) {
|
export async function parseEnvsData(path: string, envName: string | undefined) {
|
||||||
const contents = await readJsonFile(path)
|
const contents = await readJsonFile(path)
|
||||||
|
if(!(contents && typeof contents === "object" && Array.isArray(contents))) {
|
||||||
if(!(contents && typeof contents === "object" && !Array.isArray(contents))) {
|
|
||||||
throw error({ code: "MALFORMED_ENV_FILE", path, data: null })
|
throw error({ code: "MALFORMED_ENV_FILE", path, data: null })
|
||||||
}
|
}
|
||||||
|
|
||||||
const envPairs: Array<HoppEnvPair> = []
|
const envPairs: Array<HoppEnvPair> = []
|
||||||
|
|
||||||
for( const [key,value] of Object.entries(contents)) {
|
const contentEntries = Object.entries(contents)
|
||||||
if(typeof value !== "string") {
|
let environmentFound = false;
|
||||||
throw error({ code: "MALFORMED_ENV_FILE", path, data: {value: value} })
|
|
||||||
}
|
|
||||||
|
|
||||||
envPairs.push({key, value})
|
for(const [key, obj] of contentEntries) {
|
||||||
|
if(!(typeof obj === "object" && "name" in obj && "variables" in obj)) {
|
||||||
|
throw error({ code: "MALFORMED_ENV_FILE", path, data: { value: obj } })
|
||||||
|
}
|
||||||
|
if(envName && envName !== obj.name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
environmentFound = true;
|
||||||
|
for(const variable of obj.variables) {
|
||||||
|
if(
|
||||||
|
!(
|
||||||
|
typeof variable === "object" &&
|
||||||
|
"key" in variable &&
|
||||||
|
"value" in variable &&
|
||||||
|
"secret" in variable
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
throw error({ code: "MALFORMED_ENV_FILE", path, data: { value: variable } });
|
||||||
|
}
|
||||||
|
const { key, value, secret } = variable;
|
||||||
|
envPairs.push({ key: key, value: value, secret: secret });
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if(envName && !environmentFound) {
|
||||||
|
throw error({ code: "ENVIRONMENT_NAME_NOT_FOUND", data: envName });
|
||||||
}
|
}
|
||||||
return <HoppEnvs>{ global: [], selected: envPairs }
|
return <HoppEnvs>{ global: [], selected: envPairs }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
export type TestCmdOptions = {
|
export type TestCmdOptions = {
|
||||||
env: string | undefined;
|
env: string | undefined;
|
||||||
delay: string | undefined;
|
delay: string | undefined;
|
||||||
|
envName: string | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type HOPP_ENV_FILE_EXT = "json";
|
export type HOPP_ENV_FILE_EXT = "json";
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type HoppErrors = {
|
|||||||
FILE_NOT_FOUND: HoppErrorPath;
|
FILE_NOT_FOUND: HoppErrorPath;
|
||||||
UNKNOWN_COMMAND: HoppErrorCmd;
|
UNKNOWN_COMMAND: HoppErrorCmd;
|
||||||
MALFORMED_COLLECTION: HoppErrorPath & HoppErrorData;
|
MALFORMED_COLLECTION: HoppErrorPath & HoppErrorData;
|
||||||
|
ENVIRONMENT_NAME_NOT_FOUND: HoppErrorData;
|
||||||
NO_FILE_PATH: {};
|
NO_FILE_PATH: {};
|
||||||
PRE_REQUEST_SCRIPT_ERROR: HoppErrorData;
|
PRE_REQUEST_SCRIPT_ERROR: HoppErrorData;
|
||||||
PARSING_ERROR: HoppErrorData;
|
PARSING_ERROR: HoppErrorData;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export type FormDataEntry = {
|
|||||||
value: string | Blob;
|
value: string | Blob;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type HoppEnvPair = { key: string; value: string };
|
export type HoppEnvPair = { key: string; value: string; secret: boolean };
|
||||||
|
|
||||||
export type HoppEnvs = {
|
export type HoppEnvs = {
|
||||||
global: HoppEnvPair[];
|
global: HoppEnvPair[];
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { bold } from "chalk";
|
import { bold } from "chalk";
|
||||||
import { groupEnd, group, log } from "console";
|
import { groupEnd, group, log } from "console";
|
||||||
import { handleError } from "../handlers/error";
|
import { handleError } from "../handlers/error";
|
||||||
import { RequestConfig } from "../interfaces/request";
|
import { Method } from "axios";
|
||||||
import { RequestRunnerResponse, TestReport } from "../interfaces/response";
|
import { RequestRunnerResponse, TestReport } from "../interfaces/response";
|
||||||
import { HoppCLIError } from "../types/errors";
|
import { HoppCLIError } from "../types/errors";
|
||||||
import {
|
import {
|
||||||
@@ -172,11 +172,12 @@ export const printFailedTestsReport = (
|
|||||||
export const printRequestRunner = {
|
export const printRequestRunner = {
|
||||||
/**
|
/**
|
||||||
* Request-runner starting message.
|
* Request-runner starting message.
|
||||||
* @param requestConfig Provides request's method and url.
|
* @param requestMethod Provides request's method
|
||||||
|
* @param maskedURL Provides the URL with secrets masked with asterisks
|
||||||
*/
|
*/
|
||||||
start: (requestConfig: RequestConfig) => {
|
start: (requestMethod: Method | undefined, maskedURL: string) => {
|
||||||
const METHOD = BG_INFO(` ${requestConfig.method} `);
|
const METHOD = BG_INFO(` ${requestMethod} `);
|
||||||
const ENDPOINT = requestConfig.url;
|
const ENDPOINT = maskedURL;
|
||||||
|
|
||||||
process.stdout.write(`${METHOD} ${ENDPOINT}`);
|
process.stdout.write(`${METHOD} ${ENDPOINT}`);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -151,6 +151,12 @@ export function getEffectiveRESTRequest(
|
|||||||
request.endpoint,
|
request.endpoint,
|
||||||
envVariables
|
envVariables
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const maskedEnvVariables = setAllEnvironmentValuesToAsterisk(envVariables)
|
||||||
|
const _effectiveFinalMaskedURL = parseTemplateStringE(
|
||||||
|
request.endpoint,
|
||||||
|
maskedEnvVariables)
|
||||||
|
|
||||||
if (E.isLeft(_effectiveFinalURL)) {
|
if (E.isLeft(_effectiveFinalURL)) {
|
||||||
return E.left(
|
return E.left(
|
||||||
error({
|
error({
|
||||||
@@ -160,6 +166,7 @@ export function getEffectiveRESTRequest(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
const effectiveFinalURL = _effectiveFinalURL.right;
|
const effectiveFinalURL = _effectiveFinalURL.right;
|
||||||
|
const effectiveFinalMaskedURL = E.isLeft(_effectiveFinalMaskedURL) ? request.endpoint : _effectiveFinalMaskedURL.right;
|
||||||
|
|
||||||
return E.right({
|
return E.right({
|
||||||
...request,
|
...request,
|
||||||
@@ -167,6 +174,7 @@ export function getEffectiveRESTRequest(
|
|||||||
effectiveFinalHeaders,
|
effectiveFinalHeaders,
|
||||||
effectiveFinalParams,
|
effectiveFinalParams,
|
||||||
effectiveFinalBody,
|
effectiveFinalBody,
|
||||||
|
effectiveFinalMaskedURL,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,3 +295,22 @@ export const getPreRequestMetrics = (
|
|||||||
hasPreReqErrors ? { failed: 1, passed: 0 } : { failed: 0, passed: 1 },
|
hasPreReqErrors ? { failed: 1, passed: 0 } : { failed: 0, passed: 1 },
|
||||||
(scripts) => <PreRequestMetrics>{ scripts, duration }
|
(scripts) => <PreRequestMetrics>{ scripts, duration }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mask all environment values with asterisks
|
||||||
|
* @param variables Environment variable array
|
||||||
|
* @returns Environment variable array with masked values
|
||||||
|
*/
|
||||||
|
const setAllEnvironmentValuesToAsterisk = (
|
||||||
|
variables: Environment["variables"]
|
||||||
|
): Environment["variables"] => {
|
||||||
|
const envVariables: Environment["variables"] = [];
|
||||||
|
for (const variable of variables) {
|
||||||
|
let value = variable.value
|
||||||
|
if (variable.secret) {
|
||||||
|
value = "******"
|
||||||
|
}
|
||||||
|
envVariables.push({ key: variable.key, secret: variable.secret, value: value })
|
||||||
|
}
|
||||||
|
return envVariables
|
||||||
|
}
|
||||||
|
|||||||
@@ -220,6 +220,7 @@ export const processRequest =
|
|||||||
effectiveFinalHeaders: [],
|
effectiveFinalHeaders: [],
|
||||||
effectiveFinalParams: [],
|
effectiveFinalParams: [],
|
||||||
effectiveFinalURL: "",
|
effectiveFinalURL: "",
|
||||||
|
effectiveFinalMaskedURL:"",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Executing pre-request-script
|
// Executing pre-request-script
|
||||||
@@ -238,7 +239,7 @@ export const processRequest =
|
|||||||
// Creating request-config for request-runner.
|
// Creating request-config for request-runner.
|
||||||
const requestConfig = createRequest(effectiveRequest);
|
const requestConfig = createRequest(effectiveRequest);
|
||||||
|
|
||||||
printRequestRunner.start(requestConfig);
|
printRequestRunner.start(requestConfig.method, effectiveRequest.effectiveFinalMaskedURL);
|
||||||
|
|
||||||
// Default value for request-runner's response.
|
// Default value for request-runner's response.
|
||||||
let _requestRunnerRes: RequestRunnerResponse = {
|
let _requestRunnerRes: RequestRunnerResponse = {
|
||||||
|
|||||||
@@ -48,7 +48,8 @@
|
|||||||
"turn_off": "Ausschalten",
|
"turn_off": "Ausschalten",
|
||||||
"turn_on": "Einschalten",
|
"turn_on": "Einschalten",
|
||||||
"undo": "Rückgängig machen",
|
"undo": "Rückgängig machen",
|
||||||
"yes": "Ja"
|
"yes": "Ja",
|
||||||
|
"secret": "Als Secret speichern"
|
||||||
},
|
},
|
||||||
"add": {
|
"add": {
|
||||||
"new": "Neue hinzufügen",
|
"new": "Neue hinzufügen",
|
||||||
|
|||||||
@@ -48,7 +48,8 @@
|
|||||||
"turn_off": "Turn off",
|
"turn_off": "Turn off",
|
||||||
"turn_on": "Turn on",
|
"turn_on": "Turn on",
|
||||||
"undo": "Undo",
|
"undo": "Undo",
|
||||||
"yes": "Yes"
|
"yes": "Yes",
|
||||||
|
"secret": "Save as secret"
|
||||||
},
|
},
|
||||||
"add": {
|
"add": {
|
||||||
"new": "Add new",
|
"new": "Add new",
|
||||||
|
|||||||
@@ -96,7 +96,6 @@ declare module 'vue' {
|
|||||||
HoppSmartExpand: typeof import('@hoppscotch/ui')['HoppSmartExpand']
|
HoppSmartExpand: typeof import('@hoppscotch/ui')['HoppSmartExpand']
|
||||||
HoppSmartFileChip: typeof import('@hoppscotch/ui')['HoppSmartFileChip']
|
HoppSmartFileChip: typeof import('@hoppscotch/ui')['HoppSmartFileChip']
|
||||||
HoppSmartInput: typeof import('@hoppscotch/ui')['HoppSmartInput']
|
HoppSmartInput: typeof import('@hoppscotch/ui')['HoppSmartInput']
|
||||||
HoppSmartIntersection: typeof import('@hoppscotch/ui')['HoppSmartIntersection']
|
|
||||||
HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem']
|
HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem']
|
||||||
HoppSmartLink: typeof import('@hoppscotch/ui')['HoppSmartLink']
|
HoppSmartLink: typeof import('@hoppscotch/ui')['HoppSmartLink']
|
||||||
HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal']
|
HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal']
|
||||||
@@ -143,7 +142,6 @@ declare module 'vue' {
|
|||||||
IconLucideAlertTriangle: typeof import('~icons/lucide/alert-triangle')['default']
|
IconLucideAlertTriangle: typeof import('~icons/lucide/alert-triangle')['default']
|
||||||
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default']
|
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default']
|
||||||
IconLucideArrowUpRight: typeof import('~icons/lucide/arrow-up-right')['default']
|
IconLucideArrowUpRight: typeof import('~icons/lucide/arrow-up-right')['default']
|
||||||
IconLucideBrush: typeof import('~icons/lucide/brush')['default']
|
|
||||||
IconLucideCheckCircle: typeof import('~icons/lucide/check-circle')['default']
|
IconLucideCheckCircle: typeof import('~icons/lucide/check-circle')['default']
|
||||||
IconLucideChevronRight: typeof import('~icons/lucide/chevron-right')['default']
|
IconLucideChevronRight: typeof import('~icons/lucide/chevron-right')['default']
|
||||||
IconLucideGlobe: typeof import('~icons/lucide/globe')['default']
|
IconLucideGlobe: typeof import('~icons/lucide/globe')['default']
|
||||||
@@ -153,10 +151,8 @@ declare module 'vue' {
|
|||||||
IconLucideLayers: typeof import('~icons/lucide/layers')['default']
|
IconLucideLayers: typeof import('~icons/lucide/layers')['default']
|
||||||
IconLucideListEnd: typeof import('~icons/lucide/list-end')['default']
|
IconLucideListEnd: typeof import('~icons/lucide/list-end')['default']
|
||||||
IconLucideMinus: typeof import('~icons/lucide/minus')['default']
|
IconLucideMinus: typeof import('~icons/lucide/minus')['default']
|
||||||
IconLucideRss: typeof import('~icons/lucide/rss')['default']
|
|
||||||
IconLucideSearch: typeof import('~icons/lucide/search')['default']
|
IconLucideSearch: typeof import('~icons/lucide/search')['default']
|
||||||
IconLucideUsers: typeof import('~icons/lucide/users')['default']
|
IconLucideUsers: typeof import('~icons/lucide/users')['default']
|
||||||
IconLucideVerified: typeof import('~icons/lucide/verified')['default']
|
|
||||||
InterceptorsExtensionSubtitle: typeof import('./components/interceptors/ExtensionSubtitle.vue')['default']
|
InterceptorsExtensionSubtitle: typeof import('./components/interceptors/ExtensionSubtitle.vue')['default']
|
||||||
LensesHeadersRenderer: typeof import('./components/lenses/HeadersRenderer.vue')['default']
|
LensesHeadersRenderer: typeof import('./components/lenses/HeadersRenderer.vue')['default']
|
||||||
LensesHeadersRendererEntry: typeof import('./components/lenses/HeadersRendererEntry.vue')['default']
|
LensesHeadersRendererEntry: typeof import('./components/lenses/HeadersRendererEntry.vue')['default']
|
||||||
|
|||||||
@@ -60,7 +60,17 @@
|
|||||||
:placeholder="`${t('count.value', { count: index + 1 })}`"
|
:placeholder="`${t('count.value', { count: index + 1 })}`"
|
||||||
:envs="liveEnvs"
|
:envs="liveEnvs"
|
||||||
:name="'value' + index"
|
:name="'value' + index"
|
||||||
|
:secret="env.secret"
|
||||||
/>
|
/>
|
||||||
|
<div class="flex">
|
||||||
|
<HoppButtonSecondary
|
||||||
|
id="variable"
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="t('action.secret')"
|
||||||
|
:icon="env.secret ? IconEyeOff : IconEye"
|
||||||
|
@click="toggleEnvironmentSecret(index)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<HoppButtonSecondary
|
<HoppButtonSecondary
|
||||||
id="variable"
|
id="variable"
|
||||||
@@ -110,6 +120,8 @@ import IconTrash2 from "~icons/lucide/trash-2"
|
|||||||
import IconDone from "~icons/lucide/check"
|
import IconDone from "~icons/lucide/check"
|
||||||
import IconPlus from "~icons/lucide/plus"
|
import IconPlus from "~icons/lucide/plus"
|
||||||
import IconTrash from "~icons/lucide/trash"
|
import IconTrash from "~icons/lucide/trash"
|
||||||
|
import IconEye from "~icons/lucide/eye"
|
||||||
|
import IconEyeOff from "~icons/lucide/eye-off"
|
||||||
import { clone } from "lodash-es"
|
import { clone } from "lodash-es"
|
||||||
import { computed, ref, watch } from "vue"
|
import { computed, ref, watch } from "vue"
|
||||||
import * as E from "fp-ts/Either"
|
import * as E from "fp-ts/Either"
|
||||||
@@ -140,6 +152,7 @@ type EnvironmentVariable = {
|
|||||||
env: {
|
env: {
|
||||||
key: string
|
key: string
|
||||||
value: string
|
value: string
|
||||||
|
secret: boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +185,7 @@ const idTicker = ref(0)
|
|||||||
|
|
||||||
const editingName = ref<string | null>(null)
|
const editingName = ref<string | null>(null)
|
||||||
const vars = ref<EnvironmentVariable[]>([
|
const vars = ref<EnvironmentVariable[]>([
|
||||||
{ id: idTicker.value++, env: { key: "", value: "" } },
|
{ id: idTicker.value++, env: { key: "", value: "", secret: false } },
|
||||||
])
|
])
|
||||||
|
|
||||||
const clearIcon = refAutoReset<typeof IconTrash2 | typeof IconDone>(
|
const clearIcon = refAutoReset<typeof IconTrash2 | typeof IconDone>(
|
||||||
@@ -203,6 +216,8 @@ const workingEnv = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const oldEnvironments = ref<string[]>([])
|
||||||
|
|
||||||
const envList = useReadonlyStream(environments$, []) || props.envVars()
|
const envList = useReadonlyStream(environments$, []) || props.envVars()
|
||||||
|
|
||||||
const evnExpandError = computed(() => {
|
const evnExpandError = computed(() => {
|
||||||
@@ -234,6 +249,28 @@ const liveEnvs = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(liveEnvs, (newLiveEnv, oldLiveEnv) => {
|
||||||
|
const oldEnvLength = oldLiveEnv.length
|
||||||
|
const newEnvLength = newLiveEnv.length
|
||||||
|
if (oldEnvLength === newEnvLength) {
|
||||||
|
const _oldEnvironments = []
|
||||||
|
for (let i = 0; i < newEnvLength; i++) {
|
||||||
|
const newVar = newLiveEnv[i]
|
||||||
|
const oldVar = oldLiveEnv[i]
|
||||||
|
let newValue = ""
|
||||||
|
if (!newVar.secret) {
|
||||||
|
newValue = newVar.value
|
||||||
|
} else if (!oldVar.secret) {
|
||||||
|
newValue = oldVar.value
|
||||||
|
} else {
|
||||||
|
newValue = oldEnvironments.value[i]
|
||||||
|
}
|
||||||
|
_oldEnvironments.push(newValue)
|
||||||
|
}
|
||||||
|
oldEnvironments.value = _oldEnvironments
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.show,
|
() => props.show,
|
||||||
(show) => {
|
(show) => {
|
||||||
@@ -262,6 +299,7 @@ const addEnvironmentVariable = () => {
|
|||||||
env: {
|
env: {
|
||||||
key: "",
|
key: "",
|
||||||
value: "",
|
value: "",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -270,12 +308,23 @@ const removeEnvironmentVariable = (index: number) => {
|
|||||||
vars.value.splice(index, 1)
|
vars.value.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toggleEnvironmentSecret = (index: number) => {
|
||||||
|
vars.value[index].env.secret = !vars.value[index].env.secret
|
||||||
|
}
|
||||||
|
|
||||||
const saveEnvironment = () => {
|
const saveEnvironment = () => {
|
||||||
if (!editingName.value) {
|
if (!editingName.value) {
|
||||||
toast.error(`${t("environment.invalid_name")}`)
|
toast.error(`${t("environment.invalid_name")}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const _vars = vars.value
|
||||||
|
for (let i = 0; i < vars.value.length; i++) {
|
||||||
|
const value = oldEnvironments.value[i]
|
||||||
|
if (value) {
|
||||||
|
_vars[i].env.value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vars.value = _vars
|
||||||
const filterdVariables = pipe(
|
const filterdVariables = pipe(
|
||||||
vars.value,
|
vars.value,
|
||||||
A.filterMap(
|
A.filterMap(
|
||||||
|
|||||||
@@ -63,7 +63,17 @@
|
|||||||
:envs="liveEnvs"
|
:envs="liveEnvs"
|
||||||
:name="'value' + index"
|
:name="'value' + index"
|
||||||
:readonly="isViewer"
|
:readonly="isViewer"
|
||||||
|
:secret="env.secret"
|
||||||
/>
|
/>
|
||||||
|
<div v-if="!isViewer" class="flex">
|
||||||
|
<HoppButtonSecondary
|
||||||
|
id="variable"
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="t('action.secret')"
|
||||||
|
:icon="env.secret ? IconEyeOff : IconEye"
|
||||||
|
@click="toggleEnvironmentSecret(index)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div v-if="!isViewer" class="flex">
|
<div v-if="!isViewer" class="flex">
|
||||||
<HoppButtonSecondary
|
<HoppButtonSecondary
|
||||||
id="variable"
|
id="variable"
|
||||||
@@ -139,6 +149,8 @@ import IconTrash from "~icons/lucide/trash"
|
|||||||
import IconTrash2 from "~icons/lucide/trash-2"
|
import IconTrash2 from "~icons/lucide/trash-2"
|
||||||
import IconDone from "~icons/lucide/check"
|
import IconDone from "~icons/lucide/check"
|
||||||
import IconPlus from "~icons/lucide/plus"
|
import IconPlus from "~icons/lucide/plus"
|
||||||
|
import IconEye from "~icons/lucide/eye"
|
||||||
|
import IconEyeOff from "~icons/lucide/eye-off"
|
||||||
import { platform } from "~/platform"
|
import { platform } from "~/platform"
|
||||||
|
|
||||||
type EnvironmentVariable = {
|
type EnvironmentVariable = {
|
||||||
@@ -146,6 +158,7 @@ type EnvironmentVariable = {
|
|||||||
env: {
|
env: {
|
||||||
key: string
|
key: string
|
||||||
value: string
|
value: string
|
||||||
|
secret: boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,9 +195,10 @@ const idTicker = ref(0)
|
|||||||
|
|
||||||
const editingName = ref<string | null>(null)
|
const editingName = ref<string | null>(null)
|
||||||
const vars = ref<EnvironmentVariable[]>([
|
const vars = ref<EnvironmentVariable[]>([
|
||||||
{ id: idTicker.value++, env: { key: "", value: "" } },
|
{ id: idTicker.value++, env: { key: "", value: "", secret: false } },
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const oldEnvironments = ref<string[]>([])
|
||||||
const clearIcon = refAutoReset<typeof IconTrash2 | typeof IconDone>(
|
const clearIcon = refAutoReset<typeof IconTrash2 | typeof IconDone>(
|
||||||
IconTrash2,
|
IconTrash2,
|
||||||
1000
|
1000
|
||||||
@@ -212,6 +226,28 @@ const liveEnvs = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(liveEnvs, (newLiveEnv, oldLiveEnv) => {
|
||||||
|
const oldEnvLength = oldLiveEnv.length
|
||||||
|
const newEnvLength = newLiveEnv.length
|
||||||
|
if (oldEnvLength === newEnvLength) {
|
||||||
|
const _oldEnvironments = []
|
||||||
|
for (let i = 0; i < newEnvLength; i++) {
|
||||||
|
const newVar = newLiveEnv[i]
|
||||||
|
const oldVar = oldLiveEnv[i]
|
||||||
|
let newValue = ""
|
||||||
|
if (!newVar.secret) {
|
||||||
|
newValue = newVar.value
|
||||||
|
} else if (!oldVar.secret) {
|
||||||
|
newValue = oldVar.value
|
||||||
|
} else {
|
||||||
|
newValue = oldEnvironments.value[i]
|
||||||
|
}
|
||||||
|
_oldEnvironments.push(newValue)
|
||||||
|
}
|
||||||
|
oldEnvironments.value = _oldEnvironments
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.show,
|
() => props.show,
|
||||||
(show) => {
|
(show) => {
|
||||||
@@ -220,7 +256,7 @@ watch(
|
|||||||
editingName.value = null
|
editingName.value = null
|
||||||
vars.value = pipe(
|
vars.value = pipe(
|
||||||
props.envVars() ?? [],
|
props.envVars() ?? [],
|
||||||
A.map((e: { key: string; value: string }) => ({
|
A.map((e: { key: string; value: string; secret: boolean }) => ({
|
||||||
id: idTicker.value++,
|
id: idTicker.value++,
|
||||||
env: clone(e),
|
env: clone(e),
|
||||||
}))
|
}))
|
||||||
@@ -229,7 +265,7 @@ watch(
|
|||||||
editingName.value = props.editingEnvironment.environment.name ?? null
|
editingName.value = props.editingEnvironment.environment.name ?? null
|
||||||
vars.value = pipe(
|
vars.value = pipe(
|
||||||
props.editingEnvironment.environment.variables ?? [],
|
props.editingEnvironment.environment.variables ?? [],
|
||||||
A.map((e: { key: string; value: string }) => ({
|
A.map((e: { key: string; value: string; secret: boolean }) => ({
|
||||||
id: idTicker.value++,
|
id: idTicker.value++,
|
||||||
env: clone(e),
|
env: clone(e),
|
||||||
}))
|
}))
|
||||||
@@ -251,6 +287,7 @@ const addEnvironmentVariable = () => {
|
|||||||
env: {
|
env: {
|
||||||
key: "",
|
key: "",
|
||||||
value: "",
|
value: "",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -259,6 +296,10 @@ const removeEnvironmentVariable = (index: number) => {
|
|||||||
vars.value.splice(index, 1)
|
vars.value.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toggleEnvironmentSecret = (index: number) => {
|
||||||
|
vars.value[index].env.secret = !vars.value[index].env.secret
|
||||||
|
}
|
||||||
|
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
|
|
||||||
const saveEnvironment = async () => {
|
const saveEnvironment = async () => {
|
||||||
@@ -269,6 +310,15 @@ const saveEnvironment = async () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _vars = vars.value
|
||||||
|
for (let i = 0; i < vars.value.length; i++) {
|
||||||
|
const value = oldEnvironments.value[i]
|
||||||
|
if (value) {
|
||||||
|
_vars[i].env.value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vars.value = _vars
|
||||||
|
|
||||||
const filterdVariables = pipe(
|
const filterdVariables = pipe(
|
||||||
vars.value,
|
vars.value,
|
||||||
A.filterMap(
|
A.filterMap(
|
||||||
|
|||||||
@@ -279,6 +279,7 @@ const globalEnvVars = useReadonlyStream(globalEnv$, []) as Ref<
|
|||||||
Array<{
|
Array<{
|
||||||
key: string
|
key: string
|
||||||
value: string
|
value: string
|
||||||
|
secret: boolean
|
||||||
}>
|
}>
|
||||||
>
|
>
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ type Props = {
|
|||||||
env: {
|
env: {
|
||||||
key: string
|
key: string
|
||||||
value: string
|
value: string
|
||||||
|
secret: boolean
|
||||||
previousValue?: string
|
previousValue?: string
|
||||||
}
|
}
|
||||||
status: Status
|
status: Status
|
||||||
|
|||||||
@@ -55,7 +55,12 @@ import {
|
|||||||
keymap,
|
keymap,
|
||||||
tooltips,
|
tooltips,
|
||||||
} from "@codemirror/view"
|
} from "@codemirror/view"
|
||||||
import { EditorSelection, EditorState, Extension } from "@codemirror/state"
|
import {
|
||||||
|
EditorSelection,
|
||||||
|
EditorState,
|
||||||
|
Extension,
|
||||||
|
StateEffect,
|
||||||
|
} from "@codemirror/state"
|
||||||
import { clone } from "lodash-es"
|
import { clone } from "lodash-es"
|
||||||
import { history, historyKeymap } from "@codemirror/commands"
|
import { history, historyKeymap } from "@codemirror/commands"
|
||||||
import { inputTheme } from "~/helpers/editor/themes/baseTheme"
|
import { inputTheme } from "~/helpers/editor/themes/baseTheme"
|
||||||
@@ -72,13 +77,17 @@ const props = withDefaults(
|
|||||||
modelValue?: string
|
modelValue?: string
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
styles?: string
|
styles?: string
|
||||||
envs?: { key: string; value: string; source: string }[] | null
|
envs?:
|
||||||
|
| { key: string; value: string; secret: boolean; source: string }[]
|
||||||
|
| null
|
||||||
focus?: boolean
|
focus?: boolean
|
||||||
selectTextOnMount?: boolean
|
selectTextOnMount?: boolean
|
||||||
environmentHighlights?: boolean
|
environmentHighlights?: boolean
|
||||||
readonly?: boolean
|
readonly?: boolean
|
||||||
autoCompleteSource?: string[]
|
autoCompleteSource?: string[]
|
||||||
inspectionResults?: InspectorResult[] | undefined
|
inspectionResults?: InspectorResult[] | undefined
|
||||||
|
defaultValue?: string
|
||||||
|
secret?: boolean
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
modelValue: "",
|
modelValue: "",
|
||||||
@@ -91,6 +100,8 @@ const props = withDefaults(
|
|||||||
autoCompleteSource: undefined,
|
autoCompleteSource: undefined,
|
||||||
inspectionResult: undefined,
|
inspectionResult: undefined,
|
||||||
inspectionResults: undefined,
|
inspectionResults: undefined,
|
||||||
|
defaultValue: "",
|
||||||
|
secret: false,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -104,6 +115,8 @@ const emit = defineEmits<{
|
|||||||
(e: "click", ev: any): void
|
(e: "click", ev: any): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const asterikedText = computed(() => "*".repeat(props.modelValue.length))
|
||||||
|
|
||||||
const cachedValue = ref(props.modelValue)
|
const cachedValue = ref(props.modelValue)
|
||||||
|
|
||||||
const view = ref<EditorView>()
|
const view = ref<EditorView>()
|
||||||
@@ -263,6 +276,22 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const prevModelValue = ref(props.modelValue)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.secret,
|
||||||
|
(newValue) => {
|
||||||
|
let visibleValue = asterikedText.value
|
||||||
|
if (!newValue) {
|
||||||
|
visibleValue = prevModelValue.value
|
||||||
|
} else {
|
||||||
|
prevModelValue.value = props.modelValue
|
||||||
|
}
|
||||||
|
emit("update:modelValue", visibleValue)
|
||||||
|
updateEditorViewTheme(newValue)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to scroll the active suggestion into view
|
* Used to scroll the active suggestion into view
|
||||||
*/
|
*/
|
||||||
@@ -284,7 +313,6 @@ watch(
|
|||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
(newVal) => {
|
(newVal) => {
|
||||||
const singleLinedText = newVal.replaceAll("\n", "")
|
const singleLinedText = newVal.replaceAll("\n", "")
|
||||||
|
|
||||||
const currDoc = view.value?.state.doc
|
const currDoc = view.value?.state.doc
|
||||||
.toJSON()
|
.toJSON()
|
||||||
.join(view.value.state.lineBreak)
|
.join(view.value.state.lineBreak)
|
||||||
@@ -320,6 +348,7 @@ const envVars = computed(() =>
|
|||||||
? props.envs.map((x) => ({
|
? props.envs.map((x) => ({
|
||||||
key: x.key,
|
key: x.key,
|
||||||
value: x.value,
|
value: x.value,
|
||||||
|
secret: x.secret,
|
||||||
sourceEnv: x.source,
|
sourceEnv: x.source,
|
||||||
}))
|
}))
|
||||||
: aggregateEnvs.value
|
: aggregateEnvs.value
|
||||||
@@ -354,6 +383,14 @@ function handleTextSelection() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const updateEditorViewTheme = (readonly: boolean) => {
|
||||||
|
if (view.value) {
|
||||||
|
const extensions: Extension = getExtensions(readonly)
|
||||||
|
view.value.dispatch({
|
||||||
|
effects: [StateEffect.reconfigure.of(extensions)],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const initView = (el: any) => {
|
const initView = (el: any) => {
|
||||||
// Debounce to prevent double click from selecting the word
|
// Debounce to prevent double click from selecting the word
|
||||||
@@ -364,17 +401,31 @@ const initView = (el: any) => {
|
|||||||
el.addEventListener("mouseup", debounceFn)
|
el.addEventListener("mouseup", debounceFn)
|
||||||
el.addEventListener("keyup", debounceFn)
|
el.addEventListener("keyup", debounceFn)
|
||||||
|
|
||||||
|
if (props.secret) {
|
||||||
|
emit("update:modelValue", asterikedText.value)
|
||||||
|
}
|
||||||
|
const extensions: Extension = getExtensions(props.readonly || props.secret)
|
||||||
|
view.value = new EditorView({
|
||||||
|
parent: el,
|
||||||
|
state: EditorState.create({
|
||||||
|
doc: props.modelValue,
|
||||||
|
extensions,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getExtensions = (readonly: boolean): Extension => {
|
||||||
const extensions: Extension = [
|
const extensions: Extension = [
|
||||||
EditorView.contentAttributes.of({ "aria-label": props.placeholder }),
|
EditorView.contentAttributes.of({ "aria-label": props.placeholder }),
|
||||||
EditorView.contentAttributes.of({ "data-enable-grammarly": "false" }),
|
EditorView.contentAttributes.of({ "data-enable-grammarly": "false" }),
|
||||||
EditorView.updateListener.of((update) => {
|
EditorView.updateListener.of((update) => {
|
||||||
if (props.readonly) {
|
if (readonly) {
|
||||||
update.view.contentDOM.inputMode = "none"
|
update.view.contentDOM.inputMode = "none"
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
EditorState.changeFilter.of(() => !props.readonly),
|
EditorState.changeFilter.of(() => !readonly),
|
||||||
inputTheme,
|
inputTheme,
|
||||||
props.readonly
|
readonly
|
||||||
? EditorView.theme({
|
? EditorView.theme({
|
||||||
".cm-content": {
|
".cm-content": {
|
||||||
caretColor: "var(--secondary-dark-color)",
|
caretColor: "var(--secondary-dark-color)",
|
||||||
@@ -406,7 +457,7 @@ const initView = (el: any) => {
|
|||||||
ViewPlugin.fromClass(
|
ViewPlugin.fromClass(
|
||||||
class {
|
class {
|
||||||
update(update: ViewUpdate) {
|
update(update: ViewUpdate) {
|
||||||
if (props.readonly) return
|
if (readonly) return
|
||||||
|
|
||||||
if (update.docChanged) {
|
if (update.docChanged) {
|
||||||
const prevValue = clone(cachedValue.value)
|
const prevValue = clone(cachedValue.value)
|
||||||
@@ -418,9 +469,14 @@ const initView = (el: any) => {
|
|||||||
// We do not update the cache directly in this case (to trigger value watcher to dispatch)
|
// We do not update the cache directly in this case (to trigger value watcher to dispatch)
|
||||||
// So, we desync cachedValue a bit so we can trigger updates
|
// So, we desync cachedValue a bit so we can trigger updates
|
||||||
const value = clone(cachedValue.value).replaceAll("\n", "")
|
const value = clone(cachedValue.value).replaceAll("\n", "")
|
||||||
|
if (props.secret) {
|
||||||
|
const asterikedValue = "*".repeat(value.length)
|
||||||
|
emit("update:modelValue", asterikedValue)
|
||||||
|
emit("change", asterikedValue)
|
||||||
|
} else {
|
||||||
emit("update:modelValue", value)
|
emit("update:modelValue", value)
|
||||||
emit("change", value)
|
emit("change", value)
|
||||||
|
}
|
||||||
|
|
||||||
const pasted = !!update.transactions.find((txn) =>
|
const pasted = !!update.transactions.find((txn) =>
|
||||||
txn.isUserEvent("input.paste")
|
txn.isUserEvent("input.paste")
|
||||||
@@ -445,14 +501,7 @@ const initView = (el: any) => {
|
|||||||
history(),
|
history(),
|
||||||
keymap.of([...historyKeymap]),
|
keymap.of([...historyKeymap]),
|
||||||
]
|
]
|
||||||
|
return extensions
|
||||||
view.value = new EditorView({
|
|
||||||
parent: el,
|
|
||||||
state: EditorState.create({
|
|
||||||
doc: props.modelValue,
|
|
||||||
extensions,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const triggerTextSelection = () => {
|
const triggerTextSelection = () => {
|
||||||
|
|||||||
@@ -66,7 +66,10 @@ const cursorTooltipField = (aggregateEnvs: AggregateEnvironment[]) =>
|
|||||||
|
|
||||||
const envName = tooltipEnv?.sourceEnv ?? "Choose an Environment"
|
const envName = tooltipEnv?.sourceEnv ?? "Choose an Environment"
|
||||||
|
|
||||||
const envValue = tooltipEnv?.value ?? "Not found"
|
let envValue = tooltipEnv?.value ?? "Not found"
|
||||||
|
if (tooltipEnv?.secret) {
|
||||||
|
envValue = "******"
|
||||||
|
}
|
||||||
|
|
||||||
const result = parseTemplateStringE(envValue, aggregateEnvs)
|
const result = parseTemplateStringE(envValue, aggregateEnvs)
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"!name": "pw-pre",
|
"!name": "pw-pre",
|
||||||
"pw": {
|
"pw": {
|
||||||
"env": {
|
"env": {
|
||||||
"set": "fn(key: string, value: string)",
|
"set": "fn(key: string, value: string, secret: boolean)",
|
||||||
"get": "fn(key: string) -> string",
|
"get": "fn(key: string) -> string",
|
||||||
"getResolve": "fn(key: string) -> string",
|
"getResolve": "fn(key: string) -> string",
|
||||||
"resolve": "fn(value: string) -> string"
|
"resolve": "fn(value: string) -> string"
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
"body": "?"
|
"body": "?"
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"set": "fn(key: string, value: string)",
|
"set": "fn(key: string, value: string, secret:boolean)",
|
||||||
"get": "fn(key: string) -> string",
|
"get": "fn(key: string) -> string",
|
||||||
"getResolve": "fn(key: string) -> string",
|
"getResolve": "fn(key: string) -> string",
|
||||||
"resolve": "fn(value: string) -> string"
|
"resolve": "fn(value: string) -> string"
|
||||||
|
|||||||
@@ -186,14 +186,19 @@ const dispatchers = defineDispatchers({
|
|||||||
},
|
},
|
||||||
addEnvironmentVariable(
|
addEnvironmentVariable(
|
||||||
{ environments }: EnvironmentStore,
|
{ environments }: EnvironmentStore,
|
||||||
{ envIndex, key, value }: { envIndex: number; key: string; value: string }
|
{
|
||||||
|
envIndex,
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
secret,
|
||||||
|
}: { envIndex: number; key: string; value: string; secret: boolean }
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
environments: environments.map((env, index) =>
|
environments: environments.map((env, index) =>
|
||||||
index === envIndex
|
index === envIndex
|
||||||
? {
|
? {
|
||||||
...env,
|
...env,
|
||||||
variables: [...env.variables, { key, value }],
|
variables: [...env.variables, { key, value, secret }],
|
||||||
}
|
}
|
||||||
: env
|
: env
|
||||||
),
|
),
|
||||||
@@ -221,7 +226,10 @@ const dispatchers = defineDispatchers({
|
|||||||
{
|
{
|
||||||
envIndex,
|
envIndex,
|
||||||
vars,
|
vars,
|
||||||
}: { envIndex: number; vars: { key: string; value: string }[] }
|
}: {
|
||||||
|
envIndex: number
|
||||||
|
vars: { key: string; value: string; secret: boolean }[]
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
environments: environments.map((env, index) =>
|
environments: environments.map((env, index) =>
|
||||||
@@ -241,11 +249,13 @@ const dispatchers = defineDispatchers({
|
|||||||
variableIndex,
|
variableIndex,
|
||||||
updatedKey,
|
updatedKey,
|
||||||
updatedValue,
|
updatedValue,
|
||||||
|
updatedSecret,
|
||||||
}: {
|
}: {
|
||||||
envIndex: number
|
envIndex: number
|
||||||
variableIndex: number
|
variableIndex: number
|
||||||
updatedKey: string
|
updatedKey: string
|
||||||
updatedValue: string
|
updatedValue: string
|
||||||
|
updatedSecret: boolean
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
@@ -255,7 +265,11 @@ const dispatchers = defineDispatchers({
|
|||||||
...env,
|
...env,
|
||||||
variables: env.variables.map((v, vIndex) =>
|
variables: env.variables.map((v, vIndex) =>
|
||||||
vIndex === variableIndex
|
vIndex === variableIndex
|
||||||
? { key: updatedKey, value: updatedValue }
|
? {
|
||||||
|
key: updatedKey,
|
||||||
|
value: updatedValue,
|
||||||
|
secret: updatedSecret,
|
||||||
|
}
|
||||||
: v
|
: v
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@@ -359,6 +373,7 @@ export const currentEnvironment$: Observable<Environment | undefined> =
|
|||||||
export type AggregateEnvironment = {
|
export type AggregateEnvironment = {
|
||||||
key: string
|
key: string
|
||||||
value: string
|
value: string
|
||||||
|
secret: boolean
|
||||||
sourceEnv: string
|
sourceEnv: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,11 +388,11 @@ export const aggregateEnvs$: Observable<AggregateEnvironment[]> = combineLatest(
|
|||||||
map(([selectedEnv, globalVars]) => {
|
map(([selectedEnv, globalVars]) => {
|
||||||
const results: AggregateEnvironment[] = []
|
const results: AggregateEnvironment[] = []
|
||||||
|
|
||||||
selectedEnv?.variables.forEach(({ key, value }) =>
|
selectedEnv?.variables.forEach(({ key, value, secret }) =>
|
||||||
results.push({ key, value, sourceEnv: selectedEnv.name })
|
results.push({ key, value, secret, sourceEnv: selectedEnv.name })
|
||||||
)
|
)
|
||||||
globalVars.forEach(({ key, value }) =>
|
globalVars.forEach(({ key, value, secret }) =>
|
||||||
results.push({ key, value, sourceEnv: "Global" })
|
results.push({ key, value, secret, sourceEnv: "Global" })
|
||||||
)
|
)
|
||||||
|
|
||||||
return results
|
return results
|
||||||
@@ -593,7 +608,7 @@ export function updateEnvironment(envIndex: number, updatedEnv: Environment) {
|
|||||||
|
|
||||||
export function setEnvironmentVariables(
|
export function setEnvironmentVariables(
|
||||||
envIndex: number,
|
envIndex: number,
|
||||||
vars: { key: string; value: string }[]
|
vars: { key: string; value: string; secret: boolean }[]
|
||||||
) {
|
) {
|
||||||
environmentsStore.dispatch({
|
environmentsStore.dispatch({
|
||||||
dispatcher: "setEnvironmentVariables",
|
dispatcher: "setEnvironmentVariables",
|
||||||
@@ -606,7 +621,7 @@ export function setEnvironmentVariables(
|
|||||||
|
|
||||||
export function addEnvironmentVariable(
|
export function addEnvironmentVariable(
|
||||||
envIndex: number,
|
envIndex: number,
|
||||||
{ key, value }: { key: string; value: string }
|
{ key, value, secret }: { key: string; value: string; secret: boolean }
|
||||||
) {
|
) {
|
||||||
environmentsStore.dispatch({
|
environmentsStore.dispatch({
|
||||||
dispatcher: "addEnvironmentVariable",
|
dispatcher: "addEnvironmentVariable",
|
||||||
@@ -614,6 +629,7 @@ export function addEnvironmentVariable(
|
|||||||
envIndex,
|
envIndex,
|
||||||
key,
|
key,
|
||||||
value,
|
value,
|
||||||
|
secret,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -634,7 +650,7 @@ export function removeEnvironmentVariable(
|
|||||||
export function updateEnvironmentVariable(
|
export function updateEnvironmentVariable(
|
||||||
envIndex: number,
|
envIndex: number,
|
||||||
variableIndex: number,
|
variableIndex: number,
|
||||||
{ key, value }: { key: string; value: string }
|
{ key, value, secret }: { key: string; value: string; secret: boolean }
|
||||||
) {
|
) {
|
||||||
environmentsStore.dispatch({
|
environmentsStore.dispatch({
|
||||||
dispatcher: "updateEnvironmentVariable",
|
dispatcher: "updateEnvironmentVariable",
|
||||||
@@ -643,6 +659,7 @@ export function updateEnvironmentVariable(
|
|||||||
variableIndex,
|
variableIndex,
|
||||||
updatedKey: key,
|
updatedKey: key,
|
||||||
updatedValue: value,
|
updatedValue: value,
|
||||||
|
updatedSecret: secret,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export type Environment = {
|
|||||||
variables: {
|
variables: {
|
||||||
key: string
|
key: string
|
||||||
value: string
|
value: string
|
||||||
|
secret: boolean
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,16 +11,16 @@ describe("execPreRequestScript", () => {
|
|||||||
{
|
{
|
||||||
global: [],
|
global: [],
|
||||||
selected: [
|
selected: [
|
||||||
{ key: "bob", value: "oldbob" },
|
{ key: "bob", value: "oldbob", secret: false },
|
||||||
{ key: "foo", value: "bar" },
|
{ key: "foo", value: "bar", secret: false },
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
)()
|
)()
|
||||||
).resolves.toEqualRight({
|
).resolves.toEqualRight({
|
||||||
global: [],
|
global: [],
|
||||||
selected: [
|
selected: [
|
||||||
{ key: "bob", value: "newbob" },
|
{ key: "bob", value: "newbob", secret: false },
|
||||||
{ key: "foo", value: "bar" },
|
{ key: "foo", value: "bar", secret: false },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -34,8 +34,8 @@ describe("execPreRequestScript", () => {
|
|||||||
{
|
{
|
||||||
global: [],
|
global: [],
|
||||||
selected: [
|
selected: [
|
||||||
{ key: "bob", value: "oldbob" },
|
{ key: "bob", value: "oldbob", secret: false },
|
||||||
{ key: "foo", value: "bar" },
|
{ key: "foo", value: "bar", secret: false },
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
)()
|
)()
|
||||||
@@ -51,8 +51,8 @@ describe("execPreRequestScript", () => {
|
|||||||
{
|
{
|
||||||
global: [],
|
global: [],
|
||||||
selected: [
|
selected: [
|
||||||
{ key: "bob", value: "oldbob" },
|
{ key: "bob", value: "oldbob", secret: false },
|
||||||
{ key: "foo", value: "bar" },
|
{ key: "foo", value: "bar", secret: false },
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
)()
|
)()
|
||||||
@@ -68,8 +68,8 @@ describe("execPreRequestScript", () => {
|
|||||||
{
|
{
|
||||||
global: [],
|
global: [],
|
||||||
selected: [
|
selected: [
|
||||||
{ key: "bob", value: "oldbob" },
|
{ key: "bob", value: "oldbob", secret: false },
|
||||||
{ key: "foo", value: "bar" },
|
{ key: "foo", value: "bar", secret: false },
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
)()
|
)()
|
||||||
@@ -86,7 +86,7 @@ describe("execPreRequestScript", () => {
|
|||||||
)()
|
)()
|
||||||
).resolves.toEqualRight({
|
).resolves.toEqualRight({
|
||||||
global: [],
|
global: [],
|
||||||
selected: [{ key: "foo", value: "bar" }],
|
selected: [{ key: "foo", value: "bar", secret: false }],
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ describe("pw.env.get", () => {
|
|||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "b",
|
value: "b",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -58,6 +59,7 @@ describe("pw.env.get", () => {
|
|||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "b",
|
value: "b",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
selected: [],
|
selected: [],
|
||||||
@@ -111,12 +113,14 @@ describe("pw.env.get", () => {
|
|||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "global val",
|
value: "global val",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
selected: [
|
selected: [
|
||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "selected val",
|
value: "selected val",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -146,6 +150,7 @@ describe("pw.env.get", () => {
|
|||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "<<hello>>",
|
value: "<<hello>>",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ describe("pw.env.getResolve", () => {
|
|||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "b",
|
value: "b",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -58,6 +59,7 @@ describe("pw.env.getResolve", () => {
|
|||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "b",
|
value: "b",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
selected: [],
|
selected: [],
|
||||||
@@ -111,12 +113,14 @@ describe("pw.env.getResolve", () => {
|
|||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "global val",
|
value: "global val",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
selected: [
|
selected: [
|
||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "selected val",
|
value: "selected val",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -146,10 +150,12 @@ describe("pw.env.getResolve", () => {
|
|||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "<<hello>>",
|
value: "<<hello>>",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "hello",
|
key: "hello",
|
||||||
value: "there",
|
value: "there",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -179,10 +185,12 @@ describe("pw.env.getResolve", () => {
|
|||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "<<hello>>",
|
value: "<<hello>>",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "hello",
|
key: "hello",
|
||||||
value: "<<a>>",
|
value: "<<a>>",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ describe("pw.env.resolve", () => {
|
|||||||
{
|
{
|
||||||
key: "hello",
|
key: "hello",
|
||||||
value: "there",
|
value: "there",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
selected: [],
|
selected: [],
|
||||||
@@ -71,6 +72,7 @@ describe("pw.env.resolve", () => {
|
|||||||
{
|
{
|
||||||
key: "hello",
|
key: "hello",
|
||||||
value: "there",
|
value: "there",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -99,12 +101,14 @@ describe("pw.env.resolve", () => {
|
|||||||
{
|
{
|
||||||
key: "hello",
|
key: "hello",
|
||||||
value: "yo",
|
value: "yo",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
selected: [
|
selected: [
|
||||||
{
|
{
|
||||||
key: "hello",
|
key: "hello",
|
||||||
value: "there",
|
value: "there",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -134,10 +138,12 @@ describe("pw.env.resolve", () => {
|
|||||||
{
|
{
|
||||||
key: "hello",
|
key: "hello",
|
||||||
value: "<<there>>",
|
value: "<<there>>",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "there",
|
key: "there",
|
||||||
value: "<<hello>>",
|
value: "<<hello>>",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ describe("pw.env.set", () => {
|
|||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "b",
|
value: "b",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -43,6 +44,7 @@ describe("pw.env.set", () => {
|
|||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "c",
|
value: "c",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
@@ -60,6 +62,7 @@ describe("pw.env.set", () => {
|
|||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "b",
|
value: "b",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
selected: [],
|
selected: [],
|
||||||
@@ -71,6 +74,7 @@ describe("pw.env.set", () => {
|
|||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "c",
|
value: "c",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
@@ -88,12 +92,14 @@ describe("pw.env.set", () => {
|
|||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "b",
|
value: "b",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
selected: [
|
selected: [
|
||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "d",
|
value: "d",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
@@ -104,12 +110,14 @@ describe("pw.env.set", () => {
|
|||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "b",
|
value: "b",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
selected: [
|
selected: [
|
||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "c",
|
value: "c",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
@@ -134,6 +142,7 @@ describe("pw.env.set", () => {
|
|||||||
{
|
{
|
||||||
key: "a",
|
key: "a",
|
||||||
value: "c",
|
value: "c",
|
||||||
|
secret: false,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -87,9 +87,12 @@ export const execPreRequestScript = (
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const envSetHandle = vm.newFunction("set", (keyHandle, valueHandle) => {
|
const envSetHandle = vm.newFunction(
|
||||||
|
"set",
|
||||||
|
(keyHandle, valueHandle, secretHandle) => {
|
||||||
const key: unknown = vm.dump(keyHandle)
|
const key: unknown = vm.dump(keyHandle)
|
||||||
const value: unknown = vm.dump(valueHandle)
|
const value: unknown = vm.dump(valueHandle)
|
||||||
|
const secret: boolean = vm.dump(secretHandle)
|
||||||
|
|
||||||
if (typeof key !== "string") {
|
if (typeof key !== "string") {
|
||||||
return {
|
return {
|
||||||
@@ -103,12 +106,13 @@ export const execPreRequestScript = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentEnvs = setEnv(key, value, currentEnvs)
|
currentEnvs = setEnv(key, value, secret, currentEnvs)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
value: vm.undefined,
|
value: vm.undefined,
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const envResolveHandle = vm.newFunction("resolve", (valueHandle) => {
|
const envResolveHandle = vm.newFunction("resolve", (valueHandle) => {
|
||||||
const value: unknown = vm.dump(valueHandle)
|
const value: unknown = vm.dump(valueHandle)
|
||||||
|
|||||||
@@ -527,9 +527,12 @@ export const execTestScript = (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const envSetHandle = vm.newFunction("set", (keyHandle, valueHandle) => {
|
const envSetHandle = vm.newFunction(
|
||||||
|
"set",
|
||||||
|
(keyHandle, valueHandle, secretHandle) => {
|
||||||
const key: unknown = vm.dump(keyHandle)
|
const key: unknown = vm.dump(keyHandle)
|
||||||
const value: unknown = vm.dump(valueHandle)
|
const value: unknown = vm.dump(valueHandle)
|
||||||
|
const secret: boolean = vm.dump(secretHandle)
|
||||||
|
|
||||||
if (typeof key !== "string") {
|
if (typeof key !== "string") {
|
||||||
return {
|
return {
|
||||||
@@ -543,12 +546,13 @@ export const execTestScript = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentEnvs = setEnv(key, value, currentEnvs)
|
currentEnvs = setEnv(key, value, secret, currentEnvs)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
value: vm.undefined,
|
value: vm.undefined,
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const envResolveHandle = vm.newFunction("resolve", (valueHandle) => {
|
const envResolveHandle = vm.newFunction("resolve", (valueHandle) => {
|
||||||
const value: unknown = vm.dump(valueHandle)
|
const value: unknown = vm.dump(valueHandle)
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export function getEnv(envName: string, envs: TestResult["envs"]) {
|
|||||||
export function setEnv(
|
export function setEnv(
|
||||||
envName: string,
|
envName: string,
|
||||||
envValue: string,
|
envValue: string,
|
||||||
|
envSecret: boolean,
|
||||||
envs: TestResult["envs"]
|
envs: TestResult["envs"]
|
||||||
): TestResult["envs"] {
|
): TestResult["envs"] {
|
||||||
const indexInSelected = envs.selected.findIndex((x) => x.key === envName)
|
const indexInSelected = envs.selected.findIndex((x) => x.key === envName)
|
||||||
@@ -80,6 +81,7 @@ export function setEnv(
|
|||||||
envs.selected.push({
|
envs.selected.push({
|
||||||
key: envName,
|
key: envName,
|
||||||
value: envValue,
|
value: envValue,
|
||||||
|
secret: envSecret,
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user