fix: inputfield to readonly + asterisk if secret
This commit is contained in:
18
packages/hoppscotch-common/src/components.d.ts
vendored
18
packages/hoppscotch-common/src/components.d.ts
vendored
@@ -133,24 +133,6 @@ declare module 'vue' {
|
|||||||
HttpTestResultReport: typeof import('./components/http/TestResultReport.vue')['default']
|
HttpTestResultReport: typeof import('./components/http/TestResultReport.vue')['default']
|
||||||
HttpTests: typeof import('./components/http/Tests.vue')['default']
|
HttpTests: typeof import('./components/http/Tests.vue')['default']
|
||||||
HttpURLEncodedParams: typeof import('./components/http/URLEncodedParams.vue')['default']
|
HttpURLEncodedParams: typeof import('./components/http/URLEncodedParams.vue')['default']
|
||||||
IconLucideActivity: typeof import('~icons/lucide/activity')['default']
|
|
||||||
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']
|
|
||||||
IconLucideCheckCircle: typeof import('~icons/lucide/check-circle')['default']
|
|
||||||
IconLucideChevronRight: typeof import('~icons/lucide/chevron-right')['default']
|
|
||||||
IconLucideGlobe: typeof import('~icons/lucide/globe')['default']
|
|
||||||
IconLucideHelpCircle: typeof import('~icons/lucide/help-circle')['default']
|
|
||||||
IconLucideInbox: typeof import('~icons/lucide/inbox')['default']
|
|
||||||
IconLucideInfo: typeof import('~icons/lucide/info')['default']
|
|
||||||
IconLucideLayers: typeof import('~icons/lucide/layers')['default']
|
|
||||||
IconLucideListEnd: typeof import('~icons/lucide/list-end')['default']
|
|
||||||
IconLucideMinus: typeof import('~icons/lucide/minus')['default']
|
|
||||||
IconLucideRss: typeof import('~icons/lucide/rss')['default']
|
|
||||||
IconLucideSearch: typeof import('~icons/lucide/search')['default']
|
|
||||||
IconLucideUsers: typeof import('~icons/lucide/users')['default']
|
|
||||||
IconLucideVerified: typeof import('~icons/lucide/verified')['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']
|
||||||
LensesRenderersAudioLensRenderer: typeof import('./components/lenses/renderers/AudioLensRenderer.vue')['default']
|
LensesRenderersAudioLensRenderer: typeof import('./components/lenses/renderers/AudioLensRenderer.vue')['default']
|
||||||
|
|||||||
@@ -60,6 +60,7 @@
|
|||||||
: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">
|
<div class="flex">
|
||||||
<HoppButtonSecondary
|
<HoppButtonSecondary
|
||||||
@@ -215,6 +216,8 @@ const workingEnv = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const oldEnvironments = ref<Environment | null>(workingEnv.value)
|
||||||
|
|
||||||
const envList = useReadonlyStream(environments$, []) || props.envVars()
|
const envList = useReadonlyStream(environments$, []) || props.envVars()
|
||||||
|
|
||||||
const evnExpandError = computed(() => {
|
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(
|
watch(
|
||||||
() => props.show,
|
() => props.show,
|
||||||
(show) => {
|
(show) => {
|
||||||
@@ -292,7 +310,14 @@ const saveEnvironment = () => {
|
|||||||
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?.variables[i].value
|
||||||
|
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,6 +63,7 @@
|
|||||||
:envs="liveEnvs"
|
:envs="liveEnvs"
|
||||||
:name="'value' + index"
|
:name="'value' + index"
|
||||||
:readonly="isViewer"
|
:readonly="isViewer"
|
||||||
|
:secret="env.secret"
|
||||||
/>
|
/>
|
||||||
<div v-if="!isViewer" class="flex">
|
<div v-if="!isViewer" class="flex">
|
||||||
<HoppButtonSecondary
|
<HoppButtonSecondary
|
||||||
@@ -197,6 +198,7 @@ const vars = ref<EnvironmentVariable[]>([
|
|||||||
{ id: idTicker.value++, env: { key: "", value: "", secret: false } },
|
{ id: idTicker.value++, env: { key: "", value: "", secret: false } },
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const oldEnvironments = ref(props.envVars())
|
||||||
const clearIcon = refAutoReset<typeof IconTrash2 | typeof IconDone>(
|
const clearIcon = refAutoReset<typeof IconTrash2 | typeof IconDone>(
|
||||||
IconTrash2,
|
IconTrash2,
|
||||||
1000
|
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(
|
watch(
|
||||||
() => props.show,
|
() => props.show,
|
||||||
(show) => {
|
(show) => {
|
||||||
@@ -286,6 +303,15 @@ const saveEnvironment = async () => {
|
|||||||
return
|
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(
|
const filterdVariables = pipe(
|
||||||
vars.value,
|
vars.value,
|
||||||
A.filterMap(
|
A.filterMap(
|
||||||
|
|||||||
@@ -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"
|
||||||
@@ -81,6 +86,8 @@ const props = withDefaults(
|
|||||||
readonly?: boolean
|
readonly?: boolean
|
||||||
autoCompleteSource?: string[]
|
autoCompleteSource?: string[]
|
||||||
inspectionResults?: InspectorResult[] | undefined
|
inspectionResults?: InspectorResult[] | undefined
|
||||||
|
defaultValue?: string
|
||||||
|
secret?: boolean
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
modelValue: "",
|
modelValue: "",
|
||||||
@@ -93,6 +100,8 @@ const props = withDefaults(
|
|||||||
autoCompleteSource: undefined,
|
autoCompleteSource: undefined,
|
||||||
inspectionResult: undefined,
|
inspectionResult: undefined,
|
||||||
inspectionResults: undefined,
|
inspectionResults: undefined,
|
||||||
|
defaultValue: "",
|
||||||
|
secret: false,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -106,6 +115,8 @@ const emit = defineEmits<{
|
|||||||
(e: "click", ev: any): void
|
(e: "click", ev: any): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const ASTERISK = "******"
|
||||||
|
|
||||||
const cachedValue = ref(props.modelValue)
|
const cachedValue = ref(props.modelValue)
|
||||||
|
|
||||||
const view = ref<EditorView>()
|
const view = ref<EditorView>()
|
||||||
@@ -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
|
* Used to scroll the active suggestion into view
|
||||||
*/
|
*/
|
||||||
@@ -286,7 +314,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)
|
||||||
@@ -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) => {
|
const initView = (el: any) => {
|
||||||
// Debounce to prevent double click from selecting the word
|
// Debounce to prevent double click from selecting the word
|
||||||
@@ -367,17 +402,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", 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 = [
|
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)",
|
||||||
@@ -409,7 +458,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)
|
||||||
@@ -448,14 +497,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 = () => {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ const cursorTooltipField = (aggregateEnvs: AggregateEnvironment[]) =>
|
|||||||
|
|
||||||
let envValue = tooltipEnv?.value ?? "Not found"
|
let envValue = tooltipEnv?.value ?? "Not found"
|
||||||
if (tooltipEnv?.secret) {
|
if (tooltipEnv?.secret) {
|
||||||
envValue = "*".repeat(envValue.length)
|
envValue = "******"
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = parseTemplateStringE(envValue, aggregateEnvs)
|
const result = parseTemplateStringE(envValue, aggregateEnvs)
|
||||||
|
|||||||
Reference in New Issue
Block a user