Filter out current variable from autocomplete and show sub environment variables in base environment autocomplete

This commit is contained in:
Gregory Schier
2025-09-29 06:57:04 -07:00
parent b9613591f8
commit 6abbdc8726
6 changed files with 41 additions and 21 deletions

View File

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

View File

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

View File

@@ -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<EditorView | undefined, EditorProps>(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;

View File

@@ -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<EditorProps['autocompleteVariables']>(() => {
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}
/>
)}
</div>
@@ -761,12 +772,3 @@ function MultilineEditDialog({
</div>
);
}
// 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() };
}
}

View File

@@ -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() };
}
}

View File

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