Skip to content

Commit 6018948

Browse files
committed
allow auth nodes to also use autocompletion and autosuggest variables
1 parent b310437 commit 6018948

4 files changed

Lines changed: 75 additions & 26 deletions

File tree

src/components/atoms/common/TextEditor.js

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,30 @@ import { defaultKeymap } from '@codemirror/commands';
99
import { syntaxHighlighting, defaultHighlightStyle, HighlightStyle, StreamLanguage } from '@codemirror/language';
1010
import { autocompletion, CompletionContext } from '@codemirror/autocomplete';
1111
import { tags, styleTags } from '@lezer/highlight';
12+
import { isEqual } from 'lodash';
1213

13-
// Define the autocomplete function
14-
const myCompletions = (context) => {
15-
let word = context.matchBefore(/{{\w*$/);
16-
if (!word) return null;
17-
18-
return {
19-
from: word.from,
20-
options: [
21-
{ label: '{{example1}}', type: 'keyword' },
22-
{ label: '{{example2}}', type: 'variable' },
23-
{ label: '{{example3}}', type: 'text' },
24-
],
14+
// Function to dynamically generate autocomplete options
15+
const createAutocompleteSource = (options) => {
16+
return (context) => {
17+
let word = context.matchBefore(/\{\{\w*$/);
18+
if (!word) return null;
19+
20+
return {
21+
from: word.from,
22+
options: options.map((option) => ({ label: `{{${option}}}`, type: 'keyword' })),
23+
};
2524
};
2625
};
2726

28-
// Configure the autocomplete extension
29-
const myAutocomplete = autocompletion({
30-
override: [myCompletions],
31-
activateOnTyping: true,
32-
});
27+
// Create a Compartment for autocomplete
28+
const autocompleteCompartment = new Compartment();
29+
30+
// Function to update autocomplete options
31+
const updateAutocompleteOptions = (view, newOptions) => {
32+
view.dispatch({
33+
effects: autocompleteCompartment.reconfigure(autocompletion({ override: [createAutocompleteSource(newOptions)] })),
34+
});
35+
};
3336

3437
// Custom styles to hide scrollbar
3538
const hideScrollbar = EditorView.theme({
@@ -94,11 +97,16 @@ const highlightStyle = EditorView.baseTheme({
9497
},
9598
});
9699

97-
export const TextEditor = ({ id, placeHolder, onChangeHandler, name, value, disableState }) => {
100+
export const TextEditor = ({ placeHolder, onChangeHandler, value, disableState, completionOptions, styles }) => {
98101
const editor1 = useRef();
99102
const [view, setView] = useState(null);
103+
const [dynamicOptions, setDynamicOptions] = useState([]);
100104

101105
if (view) {
106+
if (!isEqual(dynamicOptions, completionOptions)) {
107+
updateAutocompleteOptions(view, completionOptions);
108+
setDynamicOptions(completionOptions);
109+
}
102110
if (value != view.state.doc.toString()) {
103111
view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: value } });
104112
}
@@ -116,7 +124,7 @@ export const TextEditor = ({ id, placeHolder, onChangeHandler, name, value, disa
116124
extensions: [
117125
//EditorView.lineWrapping,
118126
placeholder(placeHolder),
119-
myAutocomplete,
127+
//myAutocomplete,
120128
//basicSetup,
121129
keymap.of([defaultKeymap, indentWithTab]),
122130
onUpdate,
@@ -126,6 +134,7 @@ export const TextEditor = ({ id, placeHolder, onChangeHandler, name, value, disa
126134
rebindEnterKey,
127135
highlightPlugin,
128136
highlightStyle,
137+
autocompleteCompartment.of(autocompletion({ override: [createAutocompleteSource(dynamicOptions)] })),
129138
],
130139
});
131140

@@ -139,8 +148,8 @@ export const TextEditor = ({ id, placeHolder, onChangeHandler, name, value, disa
139148
}, []);
140149

141150
const mainStyles =
142-
'nodrag nowheel block w-3/4 rounded border border-slate-700 bg-background-light p-2.5 text-sm outline-none';
151+
'nodrag nowheel block rounded border border-slate-700 bg-background-light p-2.5 text-sm outline-none';
143152
const intentStyles = disableState ? 'cursor-not-allowed text-slate-400' : 'text-slate-900';
144153

145-
return <div ref={editor1} className={`${mainStyles} ${intentStyles}`}></div>;
154+
return <div ref={editor1} className={`${mainStyles} ${intentStyles} ${styles}`}></div>;
146155
};

src/components/molecules/flow/AddNodes.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ const AddNodes = ({ collectionId }) => {
5050

5151
// Get all requests of this collections
5252
const collection = useCollectionStore.getState().collections.find((c) => c.id === collectionId);
53-
console.log(collection);
5453
const nodesByTags = orderNodesByTags(collection.nodes, searchFilter);
5554

5655
return (

src/components/molecules/flow/nodes/AuthNode.js

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ import useCanvasStore from 'stores/CanvasStore';
55
import { Listbox, Transition } from '@headlessui/react';
66
import { CheckIcon, ChevronUpDownIcon } from '@heroicons/react/20/solid';
77
import TextInput from 'components/atoms/common/TextInput';
8+
import { TextEditor } from 'components/atoms/common/TextEditor';
9+
import useCollectionStore from 'stores/CollectionStore';
10+
import { useTabStore } from 'stores/TabStore';
11+
import { cloneDeep } from 'lodash';
812

913
const AuthNode = ({ id, data }) => {
1014
const setAuthNodeType = useCanvasStore((state) => state.setAuthNodeType);
@@ -15,6 +19,20 @@ const AuthNode = ({ id, data }) => {
1519
setBasicAuthValues(id, option, value);
1620
};
1721

22+
const getActiveVariables = () => {
23+
const collectionId = useCanvasStore.getState().collectionId;
24+
if (collectionId) {
25+
const activeEnv = useCollectionStore
26+
.getState()
27+
.collections.find((c) => c.id === collectionId)
28+
?.environments.find((e) => e.name === useTabStore.getState().selectedEnv);
29+
if (activeEnv) {
30+
return Object.keys(cloneDeep(activeEnv.variables));
31+
}
32+
}
33+
return [];
34+
};
35+
1836
return (
1937
<>
2038
<FlowNode
@@ -89,17 +107,21 @@ const AuthNode = ({ id, data }) => {
89107
</Listbox>
90108
{data.type === 'basic-auth' && (
91109
<div className='flex flex-col gap-2 py-4'>
92-
<TextInput
110+
<TextEditor
93111
placeHolder={`Username`}
94-
onChangeHandler={(e) => handleChange(e.target.value, 'username')}
112+
onChangeHandler={(value) => handleChange(value, 'username')}
95113
name={'username'}
96114
value={data.username ? data.username : ''}
115+
completionOptions={getActiveVariables()}
116+
styles={'w-full'}
97117
/>
98-
<TextInput
118+
<TextEditor
99119
placeHolder={`Password`}
100-
onChangeHandler={(e) => handleChange(e.target.value, 'password')}
120+
onChangeHandler={(value) => handleChange(value, 'password')}
101121
name={'username'}
102122
value={data.password ? data.password : ''}
123+
completionOptions={getActiveVariables()}
124+
styles={'w-full'}
103125
/>
104126
</div>
105127
)}

src/components/molecules/flow/nodes/RequestNode.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import { Listbox, Transition } from '@headlessui/react';
1313
import { CheckIcon, ChevronUpDownIcon } from '@heroicons/react/20/solid';
1414
import requestNodes from '../constants/requestNodes';
1515
import { TextEditor } from 'components/atoms/common/TextEditor';
16+
import useCollectionStore from 'stores/CollectionStore';
17+
import { useTabStore } from 'stores/TabStore';
18+
import { cloneDeep } from 'lodash';
1619

1720
const RequestNode = ({ id, data }) => {
1821
const setRequestNodeUrl = useCanvasStore((state) => state.setRequestNodeUrl);
@@ -107,6 +110,20 @@ const RequestNode = ({ id, data }) => {
107110
);
108111
};
109112

113+
const getActiveVariables = () => {
114+
const collectionId = useCanvasStore.getState().collectionId;
115+
if (collectionId) {
116+
const activeEnv = useCollectionStore
117+
.getState()
118+
.collections.find((c) => c.id === collectionId)
119+
?.environments.find((e) => e.name === useTabStore.getState().selectedEnv);
120+
if (activeEnv) {
121+
return Object.keys(cloneDeep(activeEnv.variables));
122+
}
123+
}
124+
return [];
125+
};
126+
110127
return (
111128
<FlowNode
112129
title={data.requestType + ' Request'}
@@ -171,6 +188,8 @@ const RequestNode = ({ id, data }) => {
171188
onChangeHandler={handleUrlInputChange}
172189
name={'url'}
173190
value={data.url ? data.url : ''}
191+
completionOptions={getActiveVariables()}
192+
styles={'w-3/4'}
174193
/>
175194
</div>
176195
<NodeHorizontalDivider />

0 commit comments

Comments
 (0)