(workingEnv.value)
+
const envList = useReadonlyStream(environments$, []) || props.envVars()
const evnExpandError = computed(() => {
@@ -246,6 +249,21 @@ const liveEnvs = computed(() => {
}
})
+watch(liveEnvs, (newLiveEnv, oldLiveEnv) => {
+ for (let i = 0; i < newLiveEnv.length; i++) {
+ const newVar = newLiveEnv[i]
+ const oldVar = oldLiveEnv[i]
+
+ if (!newVar.secret && newVar.value !== oldVar.value) {
+ const _oldEnvironments = oldEnvironments.value
+ if (_oldEnvironments) {
+ _oldEnvironments.variables[i].value = newVar.value
+ }
+ oldEnvironments.value = _oldEnvironments
+ }
+ }
+})
+
watch(
() => props.show,
(show) => {
@@ -292,7 +310,14 @@ const saveEnvironment = () => {
toast.error(`${t("environment.invalid_name")}`)
return
}
-
+ const _vars = vars.value
+ for (let i = 0; i < vars.value.length; i++) {
+ const value = oldEnvironments.value?.variables[i].value
+ if (value) {
+ _vars[i].env.value = value
+ }
+ }
+ vars.value = _vars
const filterdVariables = pipe(
vars.value,
A.filterMap(
diff --git a/packages/hoppscotch-common/src/components/environments/teams/Details.vue b/packages/hoppscotch-common/src/components/environments/teams/Details.vue
index 40b5cebc1..072477903 100644
--- a/packages/hoppscotch-common/src/components/environments/teams/Details.vue
+++ b/packages/hoppscotch-common/src/components/environments/teams/Details.vue
@@ -63,6 +63,7 @@
:envs="liveEnvs"
:name="'value' + index"
:readonly="isViewer"
+ :secret="env.secret"
/>
([
{ id: idTicker.value++, env: { key: "", value: "", secret: false } },
])
+const oldEnvironments = ref(props.envVars())
const clearIcon = refAutoReset(
IconTrash2,
1000
@@ -224,6 +226,21 @@ const liveEnvs = computed(() => {
}
})
+watch(liveEnvs, (newLiveEnv, oldLiveEnv) => {
+ for (let i = 0; i < newLiveEnv.length; i++) {
+ const newVar = newLiveEnv[i]
+ const oldVar = oldLiveEnv[i]
+
+ if (!newVar.secret && newVar.value !== oldVar.value) {
+ const _oldEnvironments = oldEnvironments.value
+ if (_oldEnvironments) {
+ _oldEnvironments[i].value = newVar.value
+ }
+ oldEnvironments.value = _oldEnvironments
+ }
+ }
+})
+
watch(
() => props.show,
(show) => {
@@ -286,6 +303,15 @@ const saveEnvironment = async () => {
return
}
+ const _vars = vars.value
+ for (let i = 0; i < vars.value.length; i++) {
+ const value = oldEnvironments.value[i].value
+ if (value) {
+ _vars[i].env.value = value
+ }
+ }
+ vars.value = _vars
+
const filterdVariables = pipe(
vars.value,
A.filterMap(
diff --git a/packages/hoppscotch-common/src/components/smart/EnvInput.vue b/packages/hoppscotch-common/src/components/smart/EnvInput.vue
index f9bcfa942..e35bbe050 100644
--- a/packages/hoppscotch-common/src/components/smart/EnvInput.vue
+++ b/packages/hoppscotch-common/src/components/smart/EnvInput.vue
@@ -55,7 +55,12 @@ import {
keymap,
tooltips,
} from "@codemirror/view"
-import { EditorSelection, EditorState, Extension } from "@codemirror/state"
+import {
+ EditorSelection,
+ EditorState,
+ Extension,
+ StateEffect,
+} from "@codemirror/state"
import { clone } from "lodash-es"
import { history, historyKeymap } from "@codemirror/commands"
import { inputTheme } from "~/helpers/editor/themes/baseTheme"
@@ -81,6 +86,8 @@ const props = withDefaults(
readonly?: boolean
autoCompleteSource?: string[]
inspectionResults?: InspectorResult[] | undefined
+ defaultValue?: string
+ secret?: boolean
}>(),
{
modelValue: "",
@@ -93,6 +100,8 @@ const props = withDefaults(
autoCompleteSource: undefined,
inspectionResult: undefined,
inspectionResults: undefined,
+ defaultValue: "",
+ secret: false,
}
)
@@ -106,6 +115,8 @@ const emit = defineEmits<{
(e: "click", ev: any): void
}>()
+const ASTERISK = "******"
+
const cachedValue = ref(props.modelValue)
const view = ref()
@@ -265,6 +276,23 @@ watch(
}
)
+const prevModelValue = ref(props.modelValue)
+watch(
+ () => props.secret,
+ (newValue, oldValue) => {
+ if (newValue !== oldValue) {
+ let visibleValue = ASTERISK
+ if (!newValue) {
+ visibleValue = prevModelValue.value
+ } else {
+ prevModelValue.value = props.modelValue
+ }
+ emit("update:modelValue", visibleValue)
+ updateEditorViewTheme(newValue)
+ }
+ }
+)
+
/**
* Used to scroll the active suggestion into view
*/
@@ -286,7 +314,6 @@ watch(
() => props.modelValue,
(newVal) => {
const singleLinedText = newVal.replaceAll("\n", "")
-
const currDoc = view.value?.state.doc
.toJSON()
.join(view.value.state.lineBreak)
@@ -357,6 +384,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) => {
// Debounce to prevent double click from selecting the word
@@ -367,17 +402,31 @@ const initView = (el: any) => {
el.addEventListener("mouseup", debounceFn)
el.addEventListener("keyup", debounceFn)
+ if (props.secret) {
+ emit("update:modelValue", ASTERISK)
+ }
+ 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 = [
EditorView.contentAttributes.of({ "aria-label": props.placeholder }),
EditorView.contentAttributes.of({ "data-enable-grammarly": "false" }),
EditorView.updateListener.of((update) => {
- if (props.readonly) {
+ if (readonly) {
update.view.contentDOM.inputMode = "none"
}
}),
- EditorState.changeFilter.of(() => !props.readonly),
+ EditorState.changeFilter.of(() => !readonly),
inputTheme,
- props.readonly
+ readonly
? EditorView.theme({
".cm-content": {
caretColor: "var(--secondary-dark-color)",
@@ -409,7 +458,7 @@ const initView = (el: any) => {
ViewPlugin.fromClass(
class {
update(update: ViewUpdate) {
- if (props.readonly) return
+ if (readonly) return
if (update.docChanged) {
const prevValue = clone(cachedValue.value)
@@ -448,14 +497,7 @@ const initView = (el: any) => {
history(),
keymap.of([...historyKeymap]),
]
-
- view.value = new EditorView({
- parent: el,
- state: EditorState.create({
- doc: props.modelValue,
- extensions,
- }),
- })
+ return extensions
}
const triggerTextSelection = () => {
diff --git a/packages/hoppscotch-common/src/helpers/editor/extensions/HoppEnvironment.ts b/packages/hoppscotch-common/src/helpers/editor/extensions/HoppEnvironment.ts
index f9d0e1cad..fa0d22861 100644
--- a/packages/hoppscotch-common/src/helpers/editor/extensions/HoppEnvironment.ts
+++ b/packages/hoppscotch-common/src/helpers/editor/extensions/HoppEnvironment.ts
@@ -68,7 +68,7 @@ const cursorTooltipField = (aggregateEnvs: AggregateEnvironment[]) =>
let envValue = tooltipEnv?.value ?? "Not found"
if (tooltipEnv?.secret) {
- envValue = "*".repeat(envValue.length)
+ envValue = "******"
}
const result = parseTemplateStringE(envValue, aggregateEnvs)