feature: modularized express routes for reusability, testability, composability and performance (#2030)

* transition GET /api/v1/apikey

* transition POST /api/v1/apikey

* transition PUT /api/v1/apikey/:id

* transition DELETE /api/v1/apikey/:id

* Enable e2e tests for api/v1/apikey routes

* remove unused addChatflowsCount

* Enable e2e tests for api/v1/variables routes

* Enable Cypress in GitHub Action

* Update main.yml

* Update main.yml

* Transition GET /api/v1/variables

* Enable cypress on github workflow

* Transition POST /api/v1/variables

* Transition PUT /api/v1/variables

* Transition DELETE /api/v1/variables

* Transition GET /api/v1/variables

* Transition GET /api/v1/chatflows

* Transition GET /api/v1/chatflows/:id

* Transition POST /api/v1/chatflows

* Transition DELETE /api/v1/chatflows/:id

* Transition PUT /api/v1/chatflows/:id

* Transition GET /api/v1/chatflows/apikey/:apiKey

* Transition GET /api/v1/credentials

* Transition POST /api/v1/credentials

* Transition GET /api/v1/credentials/:id

* Transition PUT /api/v1/credentials/:id

* Transition DELETE /api/v1/credentials/:id

* Transition GET /api/v1/tools

* Transition GET /api/v1/tools/:id

* Transition POST /api/v1/tools

* Transition PUT & DELETE /api/v1/tools/:id

* Transition /api/v1/assistants routes

* Transition /api/v1/nodes routes

* Transition GET /api/v1/chatflows-streaming/:id & GET /api/v1/chatflows-uploads/:id

* wip-all-routes

* Transition GET /api/v1/public-chatflows/:id & /api/v1/public-chatbotConfig/:id

* Remove ts-ignore annotations

* Transition GET /api/v1/chatmessage/:id

* Transition POST /api/v1/chatmessage/:id

* delete /api/v1/chatmessage/:id

* transition /api/v1/feedback/:id routes

* transition /api/v1/stats/:id

* Transition GET /api/v1/openai-assistants/:id

* Transition GET /api/v1/openai-assistants

* Transition POST /api/v1/openai-assistants-file

* transition GET /api/v1/get-upload-path

* transition GET /api/v1/get-upload-file

* transition GET /api/v1/flow-config/:id

* transition POST /api/v1/node-config

* transition GET /api/v1/version

* transition GET /api/v1/fetch-links

* transition POST /api/v1/vector/upsert/:id

* transition POST /api/v1/vector/internal-upsert/:id

* transition POST /api/v1/load-prompt

* Update index.ts

* transition POST /api/v1/prompts-list

* transition predictions

* Update index.ts

* transition GET /api/v1/marketplaces/templates

* Router update modularity cleanup

* extend request interface - express namespace

* Update index.ts

* add errorMiddleware

* Add custom application error handler

* Fix pnpm lock file

* prediction return and vector upsert

* Move the getUploadsConfig into its own file

* Remove lint warnings

* fix undefined variable value

* Fix node-load-method api call

* standardize the error message display

* Apply review comment bugfixes

* Update index.ts

* standardize error message display  in snack notifications

* Error message standard in the UI

* Rename flowXpressApp to appServer

* Upload middleware fix and axios update

* fix async await

---------

Co-authored-by: Henry <hzj94@hotmail.com>
This commit is contained in:
Octavian FlowiseAI
2024-04-02 17:44:04 +02:00
committed by GitHub
parent ea255db15d
commit 957694a912
136 changed files with 5347 additions and 2380 deletions
@@ -77,9 +77,8 @@ const APIKeyDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
onConfirm()
}
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to add new API key: ${errorData}`,
message: `Failed to add new API key: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -114,9 +113,8 @@ const APIKeyDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
onConfirm()
}
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to save API key: ${errorData}`,
message: `Failed to save API key: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -211,7 +209,11 @@ const APIKeyDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
</Box>
</DialogContent>
<DialogActions>
<StyledButton variant='contained' onClick={() => (dialogProps.type === 'ADD' ? addNewKey() : saveKey())}>
<StyledButton
variant='contained'
onClick={() => (dialogProps.type === 'ADD' ? addNewKey() : saveKey())}
id={dialogProps.customBtnId}
>
{dialogProps.confirmButtonName}
</StyledButton>
</DialogActions>
+7 -4
View File
@@ -234,7 +234,8 @@ const APIKey = () => {
title: 'Add New API Key',
type: 'ADD',
cancelButtonName: 'Cancel',
confirmButtonName: 'Add'
confirmButtonName: 'Add',
customBtnId: 'btn_confirmAddingApiKey'
}
setDialogProps(dialogProp)
setShowDialog(true)
@@ -246,6 +247,7 @@ const APIKey = () => {
type: 'EDIT',
cancelButtonName: 'Cancel',
confirmButtonName: 'Save',
customBtnId: 'btn_confirmEditingApiKey',
key
}
setDialogProps(dialogProp)
@@ -260,7 +262,8 @@ const APIKey = () => {
? `Delete key [${key.keyName}] ? `
: `Delete key [${key.keyName}] ?\n There are ${key.chatFlows.length} chatflows using this key.`,
confirmButtonName: 'Delete',
cancelButtonName: 'Cancel'
cancelButtonName: 'Cancel',
customBtnId: 'btn_initiateDeleteApiKey'
}
const isConfirmed = await confirm(confirmPayload)
@@ -283,9 +286,8 @@ const APIKey = () => {
onConfirm()
}
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to delete API key: ${errorData}`,
message: `Failed to delete API key: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -363,6 +365,7 @@ const APIKey = () => {
sx={{ color: 'white', mr: 1, height: 37 }}
onClick={addNew}
startIcon={<IconPlus />}
id='btn_createApiKey'
>
Create Key
</StyledButton>
@@ -235,9 +235,8 @@ const AssistantDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
}
setLoading(false)
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to add new Assistant: ${errorData}`,
message: `Failed to add new Assistant: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -289,9 +288,8 @@ const AssistantDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
}
setLoading(false)
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to save Assistant: ${errorData}`,
message: `Failed to save Assistant: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -329,9 +327,8 @@ const AssistantDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
}
setLoading(false)
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to sync Assistant: ${errorData}`,
message: `Failed to sync Assistant: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -376,9 +373,8 @@ const AssistantDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
onConfirm()
}
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to delete Assistant: ${errorData}`,
message: `Failed to delete Assistant: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
+4 -11
View File
@@ -172,9 +172,8 @@ const Canvas = () => {
localStorage.removeItem(`${chatflow.id}_INTERNAL`)
navigate('/')
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: errorData,
message: error.response.data.message,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -359,9 +358,7 @@ const Canvas = () => {
setEdges(initialFlow.edges || [])
dispatch({ type: SET_CHATFLOW, chatflow })
} else if (getSpecificChatflowApi.error) {
const error = getSpecificChatflowApi.error
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
errorFailed(`Failed to retrieve chatflow: ${errorData}`)
errorFailed(`Failed to retrieve chatflow: ${error.response.data.message}`)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -375,9 +372,7 @@ const Canvas = () => {
saveChatflowSuccess()
window.history.replaceState(null, null, `/canvas/${chatflow.id}`)
} else if (createNewChatflowApi.error) {
const error = createNewChatflowApi.error
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
errorFailed(`Failed to save chatflow: ${errorData}`)
errorFailed(`Failed to save chatflow: ${error.response.data.message}`)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -389,9 +384,7 @@ const Canvas = () => {
dispatch({ type: SET_CHATFLOW, chatflow: updateChatflowApi.data })
saveChatflowSuccess()
} else if (updateChatflowApi.error) {
const error = updateChatflowApi.error
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
errorFailed(`Failed to save chatflow: ${errorData}`)
errorFailed(`Failed to save chatflow: ${error.response.data.message}`)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -161,10 +161,8 @@ const ShareChatbot = ({ isSessionMemory }) => {
dispatch({ type: SET_CHATFLOW, chatflow: saveResp.data })
}
} catch (error) {
console.error(error)
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to save Chatbot Configuration: ${errorData}`,
message: `Failed to save Chatbot Configuration: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -198,10 +196,8 @@ const ShareChatbot = ({ isSessionMemory }) => {
dispatch({ type: SET_CHATFLOW, chatflow: saveResp.data })
}
} catch (error) {
console.error(error)
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to save Chatbot Configuration: ${errorData}`,
message: `Failed to save Chatbot Configuration: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -456,8 +456,7 @@ export const ChatMessage = ({ open, chatflowid, isDialog, previews, setPreviews
}, 100)
}
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
handleError(errorData)
handleError(error.response.data.message)
return
}
}
@@ -105,9 +105,8 @@ export const ChatPopUp = ({ chatflowid }) => {
}
})
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: errorData,
message: error.response.data.message,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -118,9 +118,8 @@ const AddEditCredentialDialog = ({ show, dialogProps, onCancel, onConfirm }) =>
onConfirm(createResp.data.id)
}
} catch (error) {
const errorData = typeof err === 'string' ? err : err.response.data || `${err.response.status}: ${err.response.statusText}`
enqueueSnackbar({
message: `Failed to add new Credential: ${errorData}`,
message: `Failed to add new Credential: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -168,9 +167,8 @@ const AddEditCredentialDialog = ({ show, dialogProps, onCancel, onConfirm }) =>
onConfirm(saveResp.data.id)
}
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to save Credential: ${errorData}`,
message: `Failed to save Credential: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
+1 -2
View File
@@ -139,9 +139,8 @@ const Credentials = () => {
onConfirm()
}
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to delete Credential: ${errorData}`,
message: `Failed to delete Credential: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
+4 -9
View File
@@ -225,9 +225,8 @@ const ToolDialog = ({ show, dialogProps, onUseTemplate, onCancel, onConfirm }) =
linkElement.click()
}
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to export Tool: ${errorData}`,
message: `Failed to export Tool: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -270,9 +269,8 @@ const ToolDialog = ({ show, dialogProps, onUseTemplate, onCancel, onConfirm }) =
onConfirm(createResp.data.id)
}
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to add new Tool: ${errorData}`,
message: `Failed to add new Tool: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -313,10 +311,8 @@ const ToolDialog = ({ show, dialogProps, onUseTemplate, onCancel, onConfirm }) =
onConfirm(saveResp.data.id)
}
} catch (error) {
console.error(error)
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to save Tool: ${errorData}`,
message: `Failed to save Tool: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -360,9 +356,8 @@ const ToolDialog = ({ show, dialogProps, onUseTemplate, onCancel, onConfirm }) =
onConfirm()
}
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: `Failed to delete Tool: ${errorData}`,
message: `Failed to delete Tool: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -111,9 +111,8 @@ const AddEditVariableDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
onConfirm(createResp.data.id)
}
} catch (err) {
const errorData = typeof err === 'string' ? err : err.response?.data || `${err.response?.status}: ${err.response?.statusText}`
enqueueSnackbar({
message: `Failed to add new Variable: ${errorData}`,
message: `Failed to add new Variable: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -154,9 +153,8 @@ const AddEditVariableDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
onConfirm(saveResp.data.id)
}
} catch (error) {
const errorData = error.response?.data || `${error.response?.status}: ${error.response?.statusText}`
enqueueSnackbar({
message: `Failed to save Variable: ${errorData}`,
message: `Failed to save Variable: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -222,6 +220,7 @@ const AddEditVariableDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
key='variableName'
onChange={(e) => setVariableName(e.target.value)}
value={variableName ?? ''}
id='txtInput_variableName'
/>
</Box>
<Box sx={{ p: 2 }}>
@@ -237,6 +236,7 @@ const AddEditVariableDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
options={variableTypes}
onSelect={(newValue) => setVariableType(newValue)}
value={variableType ?? 'choose an option'}
id='dropdown_variableType'
/>
</Box>
{variableType === 'static' && (
@@ -255,6 +255,7 @@ const AddEditVariableDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
key='variableValue'
onChange={(e) => setVariableValue(e.target.value)}
value={variableValue ?? ''}
id='txtInput_variableValue'
/>
</Box>
)}
@@ -264,6 +265,7 @@ const AddEditVariableDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
disabled={!variableName || !variableType || (variableType === 'static' && !variableValue)}
variant='contained'
onClick={() => (dialogType === 'ADD' ? addNewVariable() : saveVariable())}
id='btn_confirmAddingNewVariable'
>
{dialogProps.confirmButtonName}
</StyledButton>
+3 -2
View File
@@ -81,6 +81,7 @@ const Variables = () => {
type: 'ADD',
cancelButtonName: 'Cancel',
confirmButtonName: 'Add',
customBtnId: 'btn_confirmAddingVariable',
data: {}
}
setVariableDialogProps(dialogProp)
@@ -126,9 +127,8 @@ const Variables = () => {
onConfirm()
}
} catch (error) {
const errorData = error.response?.data || `${error.response?.status}: ${error.response?.statusText}`
enqueueSnackbar({
message: `Failed to delete Variable: ${errorData}`,
message: `Failed to delete Variable: ${error.response.data.message}`,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -207,6 +207,7 @@ const Variables = () => {
sx={{ color: 'white', mr: 1, height: 37 }}
onClick={addNew}
startIcon={<IconPlus />}
id='btn_createVariable'
>
Add Variable
</StyledButton>
@@ -291,9 +291,8 @@ query(formData).then((response) => {
})
setLoading(false)
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: errorData,
message: error.response.data.message,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',
@@ -59,9 +59,8 @@ export const VectorStorePopUp = ({ chatflowid }) => {
}
})
} catch (error) {
const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
enqueueSnackbar({
message: errorData,
message: error.response.data.message,
options: {
key: new Date().getTime() + Math.random(),
variant: 'error',