diff --git a/src-web/components/EnvironmentEditor.tsx b/src-web/components/EnvironmentEditor.tsx index 2648be49..623f5988 100644 --- a/src-web/components/EnvironmentEditor.tsx +++ b/src-web/components/EnvironmentEditor.tsx @@ -17,7 +17,7 @@ import { DismissibleBanner } from './core/DismissibleBanner'; import type { GenericCompletionConfig } from './core/Editor/genericCompletion'; import { Heading } from './core/Heading'; import type { PairWithId } from './core/PairEditor'; -import { ensurePairId } from './core/PairEditor'; +import { ensurePairId } from './core/PairEditor.util'; import { PairOrBulkEditor } from './core/PairOrBulkEditor'; import { VStack } from './core/Stacks'; import { EnvironmentColorIndicator } from './EnvironmentColorIndicator'; @@ -151,7 +151,7 @@ export function EnvironmentEditor({ namePlaceholder="VAR_NAME" nameValidate={validateName} valueType={valueType} - valueAutocompleteVariables + valueAutocompleteVariables='environment' valueAutocompleteFunctions forceUpdateKey={`${environment.id}::${forceUpdateKey}`} pairs={environment.variables} diff --git a/src-web/components/HeadersEditor.tsx b/src-web/components/HeadersEditor.tsx index e6f99c31..c18dcfdc 100644 --- a/src-web/components/HeadersEditor.tsx +++ b/src-web/components/HeadersEditor.tsx @@ -10,7 +10,8 @@ import { DetailsBanner } from './core/DetailsBanner'; import type { GenericCompletionConfig } from './core/Editor/genericCompletion'; import type { InputProps } from './core/Input'; import type { Pair, PairEditorProps } from './core/PairEditor'; -import { ensurePairId, PairEditorRow } from './core/PairEditor'; +import { PairEditorRow } from './core/PairEditor'; +import { ensurePairId } from './core/PairEditor.util'; import { PairOrBulkEditor } from './core/PairOrBulkEditor'; import { HStack } from './core/Stacks'; diff --git a/src-web/components/core/Editor/Editor.tsx b/src-web/components/core/Editor/Editor.tsx index 40bc9396..9acb4143 100644 --- a/src-web/components/core/Editor/Editor.tsx +++ b/src-web/components/core/Editor/Editor.tsx @@ -66,7 +66,7 @@ export interface EditorProps { autoSelect?: boolean; autocomplete?: GenericCompletionConfig; autocompleteFunctions?: boolean; - autocompleteVariables?: boolean; + autocompleteVariables?: boolean | ((v: WrappedEnvironmentVariable) => boolean); className?: string; defaultValue?: string | null; disableTabIndent?: boolean; @@ -138,8 +138,13 @@ export const Editor = forwardRef(function E const settings = useAtomValue(settingsAtom); const allEnvironmentVariables = useEnvironmentVariables(forcedEnvironmentId ?? null); - const environmentVariables = autocompleteVariables ? allEnvironmentVariables : emptyVariables; const useTemplating = !!(autocompleteFunctions || autocompleteVariables || autocomplete); + const environmentVariables = useMemo(() => { + if (!autocompleteVariables) return emptyVariables; + return typeof autocompleteVariables === 'function' + ? allEnvironmentVariables.filter(autocompleteVariables) + : allEnvironmentVariables; + }, [allEnvironmentVariables, autocompleteVariables]); if (settings && wrapLines === undefined) { wrapLines = settings.editorSoftWrap; diff --git a/src-web/components/core/PairEditor.tsx b/src-web/components/core/PairEditor.tsx index b0526c48..a4a045a2 100644 --- a/src-web/components/core/PairEditor.tsx +++ b/src-web/components/core/PairEditor.tsx @@ -12,11 +12,11 @@ import { } from 'react'; import type { XYCoord } from 'react-dnd'; import { useDrag, useDrop } from 'react-dnd'; +import type { WrappedEnvironmentVariable } from '../../hooks/useEnvironmentVariables'; import { useRandomKey } from '../../hooks/useRandomKey'; import { useToggle } from '../../hooks/useToggle'; import { languageFromContentType } from '../../lib/contentType'; import { showDialog } from '../../lib/dialog'; -import { generateId } from '../../lib/generateId'; import { showPrompt } from '../../lib/prompt'; import { DropMarker } from '../DropMarker'; import { SelectFile } from '../SelectFile'; @@ -24,12 +24,14 @@ import { Button } from './Button'; import { Checkbox } from './Checkbox'; import type { DropdownItem } from './Dropdown'; import { Dropdown } from './Dropdown'; +import type { EditorProps } from './Editor/Editor'; import { Editor } from './Editor/Editor'; import type { GenericCompletionConfig } from './Editor/genericCompletion'; import { Icon } from './Icon'; import { IconButton } from './IconButton'; import type { InputProps } from './Input'; import { Input } from './Input'; +import { ensurePairId } from './PairEditor.util'; import { PlainInput } from './PlainInput'; import type { RadioDropdownItem } from './RadioDropdown'; import { RadioDropdown } from './RadioDropdown'; @@ -55,7 +57,7 @@ export type PairEditorProps = { stateKey: InputProps['stateKey']; valueAutocomplete?: (name: string) => GenericCompletionConfig | undefined; valueAutocompleteFunctions?: boolean; - valueAutocompleteVariables?: boolean; + valueAutocompleteVariables?: boolean | 'environment'; valuePlaceholder?: string; valueType?: InputProps['type'] | ((pair: Pair) => InputProps['type']); valueValidate?: InputProps['validate']; @@ -471,6 +473,15 @@ export function PairEditorRow({ [pair, onEnd], ); + // Filter out the current pair name + const valueAutocompleteVariablesFiltered = useMemo(() => { + if (valueAutocompleteVariables === 'environment') { + return (v: WrappedEnvironmentVariable): boolean => v.variable.name !== pair.name; + } else { + return valueAutocompleteVariables; + } + }, [pair.name, valueAutocompleteVariables]); + connectDrag(ref); connectDrop(ref); @@ -601,7 +612,7 @@ export function PairEditorRow({ placeholder={valuePlaceholder ?? 'value'} autocomplete={valueAutocomplete?.(pair.name)} autocompleteFunctions={valueAutocompleteFunctions} - autocompleteVariables={valueAutocompleteVariables} + autocompleteVariables={valueAutocompleteVariablesFiltered} /> )} @@ -761,12 +772,3 @@ function MultilineEditDialog({ ); } - -// eslint-disable-next-line react-refresh/only-export-components -export function ensurePairId(p: Pair): PairWithId { - if (typeof p.id === 'string') { - return p as PairWithId; - } else { - return { ...p, id: p.id ?? generateId() }; - } -} diff --git a/src-web/components/core/PairEditor.util.tsx b/src-web/components/core/PairEditor.util.tsx new file mode 100644 index 00000000..6bb7100b --- /dev/null +++ b/src-web/components/core/PairEditor.util.tsx @@ -0,0 +1,10 @@ +import { generateId } from '../../lib/generateId'; +import type { Pair, PairWithId } from './PairEditor'; + +export function ensurePairId(p: Pair): PairWithId { + if (typeof p.id === 'string') { + return p as PairWithId; + } else { + return { ...p, id: p.id ?? generateId() }; + } +} diff --git a/src-web/hooks/useEnvironmentVariables.ts b/src-web/hooks/useEnvironmentVariables.ts index 9be8ddc1..f04f7d77 100644 --- a/src-web/hooks/useEnvironmentVariables.ts +++ b/src-web/hooks/useEnvironmentVariables.ts @@ -3,7 +3,7 @@ import { foldersAtom } from '@yaakapp-internal/models'; import { useAtomValue } from 'jotai'; import { useMemo } from 'react'; import { jotaiStore } from '../lib/jotai'; -import { isFolderEnvironment } from '../lib/model_util'; +import { isBaseEnvironment, isFolderEnvironment } from '../lib/model_util'; import { useActiveEnvironment } from './useActiveEnvironment'; import { useActiveRequest } from './useActiveRequest'; import { useEnvironmentsBreakdown } from './useEnvironmentsBreakdown'; @@ -24,11 +24,13 @@ export function useEnvironmentVariables(targetEnvironmentId: string | null) { wrapVariables(folderEnvironments.find((fe) => fe.parentId === f.id) ?? null), ); - // Folder environments also can auto-complete from the active environment + // Add active environment variables to everything except sub environments const activeEnvironmentVariables = - targetEnvironment == null || isFolderEnvironment(targetEnvironment) + targetEnvironment == null || // Editing request + isFolderEnvironment(targetEnvironment) || // Editing folder variables + isBaseEnvironment(targetEnvironment) // Editing global variables ? wrapVariables(activeEnvironment) - : []; + : wrapVariables(targetEnvironment); // Add own variables for sub environments const allVariables = [ ...folderVariables,