Skip to content

Commit c4beff2

Browse files
committed
streamline openai key addition/edit flow
1 parent 0d33cda commit c4beff2

6 files changed

Lines changed: 62 additions & 39 deletions

File tree

packages/flowtest-electron/src/ipc/collection.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -206,19 +206,20 @@ const registerRendererEventHandlers = (mainWindow, watcher) => {
206206
}
207207
});
208208

209+
ipcMain.handle('renderer:create-dotenv', async (event, collectionPath, content) => {
210+
try {
211+
createFile('.env', collectionPath, content || '');
212+
} catch (error) {
213+
return Promise.reject(error);
214+
}
215+
});
216+
209217
ipcMain.handle('renderer:addOrUpdate-dotEnvironment', async (event, collectionPath, variables) => {
210218
try {
211219
const pathname = path.join(collectionPath, '.env');
212220
// variables should be of format `k1=v1\nk2=v2`;
213221

214-
// Append to the .env file or create it if it doesn't exist
215-
fs.appendFile(pathname, variables, (err) => {
216-
if (err) {
217-
console.error('Error writing to .env file:', err);
218-
return Promise.reject(error);
219-
}
220-
console.log('.env file has been updated');
221-
});
222+
updateFile(pathname, variables);
222223
} catch (error) {
223224
return Promise.reject(error);
224225
}

src/components/molecules/flow/flowtestai.js

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { GENAI_MODELS } from 'constants/Common';
2+
import { addOrUpdateDotEnvironmentFile } from 'service/collection';
23
import useCollectionStore from 'stores/CollectionStore';
34

45
const translateGeneratedNodesToOpenApiNodes = (generatedNodes, openApiNodes) => {
@@ -34,27 +35,32 @@ const translateGeneratedNodesToOpenApiNodes = (generatedNodes, openApiNodes) =>
3435
return outputNodes;
3536
};
3637

37-
export const generateFlowData = async (instruction, modelName, collectionId) => {
38+
export const generateFlowData = async (instruction, modelName, modelKey, collectionId) => {
3839
try {
3940
const { ipcRenderer } = window;
4041

4142
const collection = useCollectionStore.getState().collections.find((c) => c.id === collectionId);
4243
if (collection) {
4344
if (modelName === GENAI_MODELS.openai) {
44-
const apiKey = collection.dotEnvVariables['OPENAI_APIKEY'];
45-
if (apiKey) {
46-
const generatedNodes = await ipcRenderer.invoke('renderer:generate-nodes-ai', instruction, collectionId, {
47-
name: GENAI_MODELS.openai,
48-
apiKey,
45+
if (!collection.dotEnvVariables) {
46+
await ipcRenderer.invoke('renderer:create-dotenv', collection.pathname, `OPENAI_APIKEY=${modelKey}`);
47+
} else if (
48+
!Object.prototype.hasOwnProperty.call(collection.dotEnvVariables, 'OPENAI_APIKEY') ||
49+
modelKey != collection.dotEnvVariables['OPENAI_APIKEY']
50+
) {
51+
await addOrUpdateDotEnvironmentFile(collectionId, {
52+
...collection.dotEnvVariables,
53+
OPENAI_APIKEY: modelKey,
4954
});
50-
const flowData = {
51-
nodes: translateGeneratedNodesToOpenApiNodes(generatedNodes, collection.nodes),
52-
};
53-
return flowData;
54-
} else {
55-
// prompt the user to add openai api key
56-
return Promise.reject(new Error(`OpenAI api key not added`));
5755
}
56+
const generatedNodes = await ipcRenderer.invoke('renderer:generate-nodes-ai', instruction, collectionId, {
57+
name: GENAI_MODELS.openai,
58+
apiKey: modelKey,
59+
});
60+
const flowData = {
61+
nodes: translateGeneratedNodesToOpenApiNodes(generatedNodes, collection.nodes),
62+
};
63+
return flowData;
5864
} else {
5965
return Promise.reject(new Error(`model: ${modelName} not supported`));
6066
}

src/components/molecules/flow/index.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,6 @@ const Flow = ({ tab, collectionId }) => {
227227
setViewport(data);
228228
}}
229229
isValidConnection={isValidConnection}
230-
fitView
231230
>
232231
<Background variant='dots' gap={12} size={1} />
233232
<Controls

src/components/molecules/headers/SideBarSubHeader.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const SideBarSubHeader = () => {
2626
btnType={BUTTON_TYPES.tertiary}
2727
classes={'rounded-none'}
2828
isDisabled={false}
29-
onClickHandle={() => setOpenCollectionModal(true)}
29+
onClickHandle={() => setImportCollectionModal(true)}
3030
fullWidth={true}
3131
>
3232
<PlusIcon className='w-4 h-4' />

src/components/molecules/modals/GenerateFlowTestModal.js

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const GenerateFlowTestModal = ({ closeFn = () => null, open = false, collectionI
2121

2222
const [selectedModel, setSelectedModel] = useState(null);
2323
const [textareaValue, setTextareaValue] = useState('');
24+
const [modelkey, setModelKey] = useState('');
2425

2526
const collection = useCollectionStore.getState().collections.find((c) => c.id === collectionId);
2627

@@ -55,7 +56,21 @@ const GenerateFlowTestModal = ({ closeFn = () => null, open = false, collectionI
5556
Use our AI to generate the flow
5657
</Dialog.Title>
5758
<div className='mt-6'>
58-
<Listbox value={selectedModel} onChange={setSelectedModel}>
59+
<Listbox
60+
value={selectedModel}
61+
onChange={(m) => {
62+
if (GENAI_MODELS.openai) {
63+
if (
64+
collection &&
65+
collection.dotEnvVariables &&
66+
Object.prototype.hasOwnProperty.call(collection.dotEnvVariables, 'OPENAI_APIKEY')
67+
) {
68+
setModelKey(collection.dotEnvVariables['OPENAI_APIKEY']);
69+
}
70+
}
71+
setSelectedModel(m);
72+
}}
73+
>
5974
<div className='relative flex w-full h-full'>
6075
<Listbox.Button className='flex items-center justify-between w-full gap-4 px-2 py-4 border rounded cursor-default border-neutral-300'>
6176
<div className='pl-2 text-left min-w-32'>{selectedModel ? selectedModel : 'Select model'}</div>
@@ -109,16 +124,10 @@ const GenerateFlowTestModal = ({ closeFn = () => null, open = false, collectionI
109124
type='text'
110125
className='nodrag nowheel block w-full p-2.5'
111126
name='keyName'
112-
placeholder='Enter your Open AI key'
113-
value={
114-
collection &&
115-
collection.dotEnvVariables &&
116-
Object.prototype.hasOwnProperty.call(collection.dotEnvVariables, 'OPENAI_APIKEY')
117-
? collection.dotEnvVariables['OPENAI_APIKEY']
118-
: 'Enter your OPENAI key: https://flowtestai.gitbook.io/flowtestai/generative-ai'
119-
}
120-
readOnly='readonly'
121-
//onChange={(e) => setOpenAIKey(e.target.value)}
127+
placeholder='Enter your OPENAI api key'
128+
value={modelkey.trim() != '' ? modelkey : 'Enter your OPENAI api key'}
129+
//readOnly='readonly'
130+
onChange={(e) => setModelKey(e.target.value)}
122131
/>
123132
</div>
124133
) : (
@@ -129,6 +138,7 @@ const GenerateFlowTestModal = ({ closeFn = () => null, open = false, collectionI
129138
id='gen-ai-text'
130139
className='block w-full p-4 text-sm text-gray-900 border border-gray-300 rounded min-h-80 bg-gray-50 outline-blue-300 focus:border-blue-100 focus:ring-blue-100'
131140
placeholder='Describe your flow step by step'
141+
value={textareaValue}
132142
onChange={(event) => setTextareaValue(event.target.value)}
133143
/>
134144
</div>
@@ -152,9 +162,14 @@ const GenerateFlowTestModal = ({ closeFn = () => null, open = false, collectionI
152162
toast.info('Please describe your flow');
153163
} else if (selectedModel === null) {
154164
toast.info('Please select a model');
165+
} else if (modelkey.trim() === '') {
166+
toast.info(`Please enter ${selectedModel} api key`);
155167
} else {
156168
setShowLoader(true);
157-
promiseWithTimeout(generateFlowData(textareaValue, selectedModel, collectionId), 30000)
169+
promiseWithTimeout(
170+
generateFlowData(textareaValue, selectedModel, modelkey, collectionId),
171+
30000,
172+
)
158173
.then((flowData) => {
159174
setShowLoader(false);
160175
if (isEqual(flowData.nodes, [])) {

src/service/collection.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,15 +216,17 @@ export const deleteEnvironmentFile = (name, collectionId) => {
216216

217217
export const addOrUpdateDotEnvironmentFile = (collectionId, variables) => {
218218
const { ipcRenderer } = window;
219+
console.log(variables);
219220

220221
const collection = useCollectionStore.getState().collections.find((c) => c.id === collectionId);
221222

222223
if (collection) {
224+
const env = Object.entries(variables)
225+
.map(([key, value]) => `${key}: "${value}"`)
226+
.join('\n');
227+
223228
return new Promise((resolve, reject) => {
224-
ipcRenderer
225-
.invoke('renderer:addOrUpdate-dotEnvironment', collection.pathname, variables)
226-
.then(resolve)
227-
.catch(reject);
229+
ipcRenderer.invoke('renderer:addOrUpdate-dotEnvironment', collection.pathname, env).then(resolve).catch(reject);
228230
});
229231
} else {
230232
return Promise.reject(new Error('Collection not found'));

0 commit comments

Comments
 (0)