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']
|
||||
HttpTests: typeof import('./components/http/Tests.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']
|
||||
LensesHeadersRendererEntry: typeof import('./components/lenses/HeadersRendererEntry.vue')['default']
|
||||
LensesRenderersAudioLensRenderer: typeof import('./components/lenses/renderers/AudioLensRenderer.vue')['default']
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
:placeholder="`${t('count.value', { count: index + 1 })}`"
|
||||
:envs="liveEnvs"
|
||||
:name="'value' + index"
|
||||
:secret="env.secret"
|
||||
/>
|
||||
<div class="flex">
|
||||
<HoppButtonSecondary
|
||||
@@ -215,6 +216,8 @@ const workingEnv = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
const oldEnvironments = ref<Environment | null>(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(
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
:envs="liveEnvs"
|
||||
:name="'value' + index"
|
||||
:readonly="isViewer"
|
||||
:secret="env.secret"
|
||||
/>
|
||||
<div v-if="!isViewer" class="flex">
|
||||
<HoppButtonSecondary
|
||||
@@ -197,6 +198,7 @@ const vars = ref<EnvironmentVariable[]>([
|
||||
{ id: idTicker.value++, env: { key: "", value: "", secret: false } },
|
||||
])
|
||||
|
||||
const oldEnvironments = ref(props.envVars())
|
||||
const clearIcon = refAutoReset<typeof IconTrash2 | typeof IconDone>(
|
||||
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(
|
||||
|
||||
@@ -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<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
|
||||
*/
|
||||
@@ -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 = () => {
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user