feat: added toggle Button to Frontend
This commit is contained in:
@@ -7,7 +7,7 @@ export type FormDataEntry = {
|
||||
value: string | Blob;
|
||||
};
|
||||
|
||||
export type HoppEnvPair = { key: string; value: string };
|
||||
export type HoppEnvPair = { key: string; value: string; secret: boolean };
|
||||
|
||||
export type HoppEnvs = {
|
||||
global: HoppEnvPair[];
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
"turn_off": "Ausschalten",
|
||||
"turn_on": "Einschalten",
|
||||
"undo": "Rückgängig machen",
|
||||
"yes": "Ja"
|
||||
"yes": "Ja",
|
||||
"secret": "Als Secret speichern"
|
||||
},
|
||||
"add": {
|
||||
"new": "Neue hinzufügen",
|
||||
@@ -880,4 +881,4 @@
|
||||
"team": "Team Workspace",
|
||||
"title": "Workspaces"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,8 @@
|
||||
"turn_off": "Turn off",
|
||||
"turn_on": "Turn on",
|
||||
"undo": "Undo",
|
||||
"yes": "Yes"
|
||||
"yes": "Yes",
|
||||
"secret": "Save as secret"
|
||||
},
|
||||
"add": {
|
||||
"new": "Add new",
|
||||
|
||||
@@ -143,7 +143,6 @@ declare module 'vue' {
|
||||
IconLucideAlertTriangle: typeof import('~icons/lucide/alert-triangle')['default']
|
||||
IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['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']
|
||||
IconLucideChevronRight: typeof import('~icons/lucide/chevron-right')['default']
|
||||
IconLucideGlobe: typeof import('~icons/lucide/globe')['default']
|
||||
|
||||
@@ -71,6 +71,16 @@
|
||||
@click="removeEnvironmentVariable(index)"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<HoppButtonSecondary
|
||||
id="variable"
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="t('action.secret')"
|
||||
:icon="IconLock"
|
||||
:color="env.secret ? 'red' : ''"
|
||||
@click="toggleEnvironmentSecret(index)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<HoppSmartPlaceholder
|
||||
v-if="vars.length === 0"
|
||||
@@ -110,6 +120,7 @@ import IconTrash2 from "~icons/lucide/trash-2"
|
||||
import IconDone from "~icons/lucide/check"
|
||||
import IconPlus from "~icons/lucide/plus"
|
||||
import IconTrash from "~icons/lucide/trash"
|
||||
import IconLock from "~icons/lucide/lock"
|
||||
import { clone } from "lodash-es"
|
||||
import { computed, ref, watch } from "vue"
|
||||
import * as E from "fp-ts/Either"
|
||||
@@ -140,6 +151,7 @@ type EnvironmentVariable = {
|
||||
env: {
|
||||
key: string
|
||||
value: string
|
||||
secret: boolean
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +184,7 @@ const idTicker = ref(0)
|
||||
|
||||
const editingName = ref<string | null>(null)
|
||||
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>(
|
||||
@@ -262,6 +274,7 @@ const addEnvironmentVariable = () => {
|
||||
env: {
|
||||
key: "",
|
||||
value: "",
|
||||
secret: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -270,6 +283,10 @@ const removeEnvironmentVariable = (index: number) => {
|
||||
vars.value.splice(index, 1)
|
||||
}
|
||||
|
||||
const toggleEnvironmentSecret = (index: number) => {
|
||||
vars.value[index].env.secret = !vars.value[index].env.secret
|
||||
}
|
||||
|
||||
const saveEnvironment = () => {
|
||||
if (!editingName.value) {
|
||||
toast.error(`${t("environment.invalid_name")}`)
|
||||
|
||||
@@ -74,6 +74,16 @@
|
||||
@click="removeEnvironmentVariable(index)"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<HoppButtonSecondary
|
||||
id="variable"
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="t('action.secret')"
|
||||
:icon="IconLock"
|
||||
:color="env.secret ? 'red' : ''"
|
||||
@click="toggleEnvironmentSecret(index)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<HoppSmartPlaceholder
|
||||
v-if="vars.length === 0"
|
||||
@@ -139,6 +149,7 @@ import IconTrash from "~icons/lucide/trash"
|
||||
import IconTrash2 from "~icons/lucide/trash-2"
|
||||
import IconDone from "~icons/lucide/check"
|
||||
import IconPlus from "~icons/lucide/plus"
|
||||
import IconLock from "~icons/lucide/lock"
|
||||
import { platform } from "~/platform"
|
||||
|
||||
type EnvironmentVariable = {
|
||||
@@ -146,6 +157,7 @@ type EnvironmentVariable = {
|
||||
env: {
|
||||
key: string
|
||||
value: string
|
||||
secret: boolean
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +194,7 @@ const idTicker = ref(0)
|
||||
|
||||
const editingName = ref<string | null>(null)
|
||||
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>(
|
||||
@@ -220,7 +232,7 @@ watch(
|
||||
editingName.value = null
|
||||
vars.value = pipe(
|
||||
props.envVars() ?? [],
|
||||
A.map((e: { key: string; value: string }) => ({
|
||||
A.map((e: { key: string; value: string; secret: boolean }) => ({
|
||||
id: idTicker.value++,
|
||||
env: clone(e),
|
||||
}))
|
||||
@@ -229,7 +241,7 @@ watch(
|
||||
editingName.value = props.editingEnvironment.environment.name ?? null
|
||||
vars.value = pipe(
|
||||
props.editingEnvironment.environment.variables ?? [],
|
||||
A.map((e: { key: string; value: string }) => ({
|
||||
A.map((e: { key: string; value: string; secret: boolean }) => ({
|
||||
id: idTicker.value++,
|
||||
env: clone(e),
|
||||
}))
|
||||
@@ -251,6 +263,7 @@ const addEnvironmentVariable = () => {
|
||||
env: {
|
||||
key: "",
|
||||
value: "",
|
||||
secret: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -259,6 +272,10 @@ const removeEnvironmentVariable = (index: number) => {
|
||||
vars.value.splice(index, 1)
|
||||
}
|
||||
|
||||
const toggleEnvironmentSecret = (index: number) => {
|
||||
vars.value[index].env.secret = !vars.value[index].env.secret
|
||||
}
|
||||
|
||||
const isLoading = ref(false)
|
||||
|
||||
const saveEnvironment = async () => {
|
||||
|
||||
@@ -279,6 +279,7 @@ const globalEnvVars = useReadonlyStream(globalEnv$, []) as Ref<
|
||||
Array<{
|
||||
key: string
|
||||
value: string
|
||||
secret: boolean
|
||||
}>
|
||||
>
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ type Props = {
|
||||
env: {
|
||||
key: string
|
||||
value: string
|
||||
secret: boolean
|
||||
previousValue?: string
|
||||
}
|
||||
status: Status
|
||||
|
||||
@@ -72,7 +72,9 @@ const props = withDefaults(
|
||||
modelValue?: string
|
||||
placeholder?: string
|
||||
styles?: string
|
||||
envs?: { key: string; value: string; source: string }[] | null
|
||||
envs?:
|
||||
| { key: string; value: string; secret: boolean; source: string }[]
|
||||
| null
|
||||
focus?: boolean
|
||||
selectTextOnMount?: boolean
|
||||
environmentHighlights?: boolean
|
||||
@@ -320,6 +322,7 @@ const envVars = computed(() =>
|
||||
? props.envs.map((x) => ({
|
||||
key: x.key,
|
||||
value: x.value,
|
||||
secret: x.secret,
|
||||
sourceEnv: x.source,
|
||||
}))
|
||||
: aggregateEnvs.value
|
||||
|
||||
@@ -66,7 +66,10 @@ const cursorTooltipField = (aggregateEnvs: AggregateEnvironment[]) =>
|
||||
|
||||
const envName = tooltipEnv?.sourceEnv ?? "Choose an Environment"
|
||||
|
||||
const envValue = tooltipEnv?.value ?? "Not found"
|
||||
let envValue = tooltipEnv?.value ?? "Not found"
|
||||
if (tooltipEnv?.secret) {
|
||||
envValue = "*".repeat(envValue.length)
|
||||
}
|
||||
|
||||
const result = parseTemplateStringE(envValue, aggregateEnvs)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"!name": "pw-pre",
|
||||
"pw": {
|
||||
"env": {
|
||||
"set": "fn(key: string, value: string)",
|
||||
"set": "fn(key: string, value: string, secret: boolean)",
|
||||
"get": "fn(key: string) -> string",
|
||||
"getResolve": "fn(key: string) -> string",
|
||||
"resolve": "fn(value: string) -> string"
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"body": "?"
|
||||
},
|
||||
"env": {
|
||||
"set": "fn(key: string, value: string)",
|
||||
"set": "fn(key: string, value: string, secret:boolean)",
|
||||
"get": "fn(key: string) -> string",
|
||||
"getResolve": "fn(key: string) -> string",
|
||||
"resolve": "fn(value: string) -> string"
|
||||
|
||||
@@ -186,14 +186,19 @@ const dispatchers = defineDispatchers({
|
||||
},
|
||||
addEnvironmentVariable(
|
||||
{ environments }: EnvironmentStore,
|
||||
{ envIndex, key, value }: { envIndex: number; key: string; value: string }
|
||||
{
|
||||
envIndex,
|
||||
key,
|
||||
value,
|
||||
secret,
|
||||
}: { envIndex: number; key: string; value: string; secret: boolean }
|
||||
) {
|
||||
return {
|
||||
environments: environments.map((env, index) =>
|
||||
index === envIndex
|
||||
? {
|
||||
...env,
|
||||
variables: [...env.variables, { key, value }],
|
||||
variables: [...env.variables, { key, value, secret }],
|
||||
}
|
||||
: env
|
||||
),
|
||||
@@ -221,7 +226,10 @@ const dispatchers = defineDispatchers({
|
||||
{
|
||||
envIndex,
|
||||
vars,
|
||||
}: { envIndex: number; vars: { key: string; value: string }[] }
|
||||
}: {
|
||||
envIndex: number
|
||||
vars: { key: string; value: string; secret: boolean }[]
|
||||
}
|
||||
) {
|
||||
return {
|
||||
environments: environments.map((env, index) =>
|
||||
@@ -241,11 +249,13 @@ const dispatchers = defineDispatchers({
|
||||
variableIndex,
|
||||
updatedKey,
|
||||
updatedValue,
|
||||
updatedSecret,
|
||||
}: {
|
||||
envIndex: number
|
||||
variableIndex: number
|
||||
updatedKey: string
|
||||
updatedValue: string
|
||||
updatedSecret: boolean
|
||||
}
|
||||
) {
|
||||
return {
|
||||
@@ -255,7 +265,11 @@ const dispatchers = defineDispatchers({
|
||||
...env,
|
||||
variables: env.variables.map((v, vIndex) =>
|
||||
vIndex === variableIndex
|
||||
? { key: updatedKey, value: updatedValue }
|
||||
? {
|
||||
key: updatedKey,
|
||||
value: updatedValue,
|
||||
secret: updatedSecret,
|
||||
}
|
||||
: v
|
||||
),
|
||||
}
|
||||
@@ -359,6 +373,7 @@ export const currentEnvironment$: Observable<Environment | undefined> =
|
||||
export type AggregateEnvironment = {
|
||||
key: string
|
||||
value: string
|
||||
secret: boolean
|
||||
sourceEnv: string
|
||||
}
|
||||
|
||||
@@ -373,11 +388,11 @@ export const aggregateEnvs$: Observable<AggregateEnvironment[]> = combineLatest(
|
||||
map(([selectedEnv, globalVars]) => {
|
||||
const results: AggregateEnvironment[] = []
|
||||
|
||||
selectedEnv?.variables.forEach(({ key, value }) =>
|
||||
results.push({ key, value, sourceEnv: selectedEnv.name })
|
||||
selectedEnv?.variables.forEach(({ key, value, secret }) =>
|
||||
results.push({ key, value, secret, sourceEnv: selectedEnv.name })
|
||||
)
|
||||
globalVars.forEach(({ key, value }) =>
|
||||
results.push({ key, value, sourceEnv: "Global" })
|
||||
globalVars.forEach(({ key, value, secret }) =>
|
||||
results.push({ key, value, secret, sourceEnv: "Global" })
|
||||
)
|
||||
|
||||
return results
|
||||
@@ -593,7 +608,7 @@ export function updateEnvironment(envIndex: number, updatedEnv: Environment) {
|
||||
|
||||
export function setEnvironmentVariables(
|
||||
envIndex: number,
|
||||
vars: { key: string; value: string }[]
|
||||
vars: { key: string; value: string; secret: boolean }[]
|
||||
) {
|
||||
environmentsStore.dispatch({
|
||||
dispatcher: "setEnvironmentVariables",
|
||||
@@ -606,7 +621,7 @@ export function setEnvironmentVariables(
|
||||
|
||||
export function addEnvironmentVariable(
|
||||
envIndex: number,
|
||||
{ key, value }: { key: string; value: string }
|
||||
{ key, value, secret }: { key: string; value: string; secret: boolean }
|
||||
) {
|
||||
environmentsStore.dispatch({
|
||||
dispatcher: "addEnvironmentVariable",
|
||||
@@ -614,6 +629,7 @@ export function addEnvironmentVariable(
|
||||
envIndex,
|
||||
key,
|
||||
value,
|
||||
secret,
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -634,7 +650,7 @@ export function removeEnvironmentVariable(
|
||||
export function updateEnvironmentVariable(
|
||||
envIndex: number,
|
||||
variableIndex: number,
|
||||
{ key, value }: { key: string; value: string }
|
||||
{ key, value, secret }: { key: string; value: string; secret: boolean }
|
||||
) {
|
||||
environmentsStore.dispatch({
|
||||
dispatcher: "updateEnvironmentVariable",
|
||||
@@ -643,6 +659,7 @@ export function updateEnvironmentVariable(
|
||||
variableIndex,
|
||||
updatedKey: key,
|
||||
updatedValue: value,
|
||||
updatedSecret: secret,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ export type Environment = {
|
||||
variables: {
|
||||
key: string
|
||||
value: string
|
||||
secret: boolean
|
||||
}[]
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ export function getEnv(envName: string, envs: TestResult["envs"]) {
|
||||
export function setEnv(
|
||||
envName: string,
|
||||
envValue: string,
|
||||
envSecret: boolean,
|
||||
envs: TestResult["envs"]
|
||||
): TestResult["envs"] {
|
||||
const indexInSelected = envs.selected.findIndex((x) => x.key === envName)
|
||||
@@ -80,6 +81,7 @@ export function setEnv(
|
||||
envs.selected.push({
|
||||
key: envName,
|
||||
value: envValue,
|
||||
secret: envSecret,
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user