feat: added toggle Button to Frontend

This commit is contained in:
Daniel Maurer
2023-07-21 14:56:19 +02:00
committed by nivedin
parent 7beed30815
commit 7d61e69b3d
15 changed files with 87 additions and 24 deletions

View File

@@ -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[];

View File

@@ -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",
@@ -880,4 +881,4 @@
"team": "Team Workspace", "team": "Team Workspace",
"title": "Workspaces" "title": "Workspaces"
} }
} }

View File

@@ -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",

View File

@@ -143,7 +143,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']

View File

@@ -71,6 +71,16 @@
@click="removeEnvironmentVariable(index)" @click="removeEnvironmentVariable(index)"
/> />
</div> </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> </div>
<HoppSmartPlaceholder <HoppSmartPlaceholder
v-if="vars.length === 0" v-if="vars.length === 0"
@@ -110,6 +120,7 @@ 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 IconLock from "~icons/lucide/lock"
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 +151,7 @@ type EnvironmentVariable = {
env: { env: {
key: string key: string
value: string value: string
secret: boolean
} }
} }
@@ -172,7 +184,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>(
@@ -262,6 +274,7 @@ const addEnvironmentVariable = () => {
env: { env: {
key: "", key: "",
value: "", value: "",
secret: false,
}, },
}) })
} }
@@ -270,6 +283,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 saveEnvironment = () => { const saveEnvironment = () => {
if (!editingName.value) { if (!editingName.value) {
toast.error(`${t("environment.invalid_name")}`) toast.error(`${t("environment.invalid_name")}`)

View File

@@ -74,6 +74,16 @@
@click="removeEnvironmentVariable(index)" @click="removeEnvironmentVariable(index)"
/> />
</div> </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> </div>
<HoppSmartPlaceholder <HoppSmartPlaceholder
v-if="vars.length === 0" v-if="vars.length === 0"
@@ -139,6 +149,7 @@ 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 IconLock from "~icons/lucide/lock"
import { platform } from "~/platform" import { platform } from "~/platform"
type EnvironmentVariable = { type EnvironmentVariable = {
@@ -146,6 +157,7 @@ type EnvironmentVariable = {
env: { env: {
key: string key: string
value: string value: string
secret: boolean
} }
} }
@@ -182,7 +194,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>(
@@ -220,7 +232,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 +241,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 +263,7 @@ const addEnvironmentVariable = () => {
env: { env: {
key: "", key: "",
value: "", value: "",
secret: false,
}, },
}) })
} }
@@ -259,6 +272,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 () => {

View File

@@ -279,6 +279,7 @@ const globalEnvVars = useReadonlyStream(globalEnv$, []) as Ref<
Array<{ Array<{
key: string key: string
value: string value: string
secret: boolean
}> }>
> >

View File

@@ -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

View File

@@ -72,7 +72,9 @@ 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
@@ -320,6 +322,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

View File

@@ -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 = "*".repeat(envValue.length)
}
const result = parseTemplateStringE(envValue, aggregateEnvs) const result = parseTemplateStringE(envValue, aggregateEnvs)

View File

@@ -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"

View File

@@ -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"

View File

@@ -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,
}, },
}) })
} }

View File

@@ -7,6 +7,7 @@ export type Environment = {
variables: { variables: {
key: string key: string
value: string value: string
secret: boolean
}[] }[]
} }

View File

@@ -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 {