mirror of https://github.com/langgenius/dify.git
use new env variables update api
This commit is contained in:
parent
3867fece4a
commit
ab438b42da
|
|
@ -17,8 +17,8 @@ from core.variables.segment_group import SegmentGroup
|
|||
from core.variables.segments import ArrayFileSegment, FileSegment, Segment
|
||||
from core.variables.types import SegmentType
|
||||
from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID, SYSTEM_VARIABLE_NODE_ID
|
||||
from factories import variable_factory
|
||||
from factories.file_factory import build_from_mapping, build_from_mappings
|
||||
from factories.variable_factory import build_segment_with_type
|
||||
from libs.login import current_user, login_required
|
||||
from models import App, AppMode, db
|
||||
from models.workflow import WorkflowDraftVariable
|
||||
|
|
@ -295,7 +295,7 @@ class VariableApi(Resource):
|
|||
if len(raw_value) > 0 and not isinstance(raw_value[0], dict):
|
||||
raise InvalidArgumentError(description=f"expected dict for files[0], got {type(raw_value)}")
|
||||
raw_value = build_from_mappings(mappings=raw_value, tenant_id=app_model.tenant_id)
|
||||
new_value = build_segment_with_type(variable.value_type, raw_value)
|
||||
new_value = variable_factory.build_segment_with_type(variable.value_type, raw_value)
|
||||
draft_var_srv.update_variable(variable, name=new_name, value=new_value)
|
||||
db.session.commit()
|
||||
return variable
|
||||
|
|
@ -411,6 +411,34 @@ class EnvironmentVariableCollectionApi(Resource):
|
|||
)
|
||||
|
||||
return {"items": env_vars_list}
|
||||
|
||||
@setup_required
|
||||
@login_required
|
||||
@account_initialization_required
|
||||
@get_app_model(mode=[AppMode.ADVANCED_CHAT, AppMode.WORKFLOW])
|
||||
def post(self, app_model: App):
|
||||
# The role of the current user in the ta table must be admin, owner, or editor
|
||||
if not current_user.is_editor:
|
||||
raise Forbidden()
|
||||
|
||||
parser = reqparse.RequestParser()
|
||||
parser.add_argument("environment_variables", type=list, required=True, location="json")
|
||||
args = parser.parse_args()
|
||||
|
||||
workflow_service = WorkflowService()
|
||||
|
||||
environment_variables_list = args.get("environment_variables") or []
|
||||
environment_variables = [
|
||||
variable_factory.build_environment_variable_from_mapping(obj) for obj in environment_variables_list
|
||||
]
|
||||
|
||||
workflow_service.update_draft_workflow_environment_variables(
|
||||
app_model=app_model,
|
||||
account=current_user,
|
||||
environment_variables=environment_variables,
|
||||
)
|
||||
|
||||
return { "result": "success" }
|
||||
|
||||
|
||||
api.add_resource(
|
||||
|
|
|
|||
|
|
@ -244,6 +244,28 @@ class WorkflowService:
|
|||
|
||||
# return draft workflow
|
||||
return workflow
|
||||
|
||||
def update_draft_workflow_environment_variables(
|
||||
self, *,
|
||||
app_model: App,
|
||||
environment_variables: Sequence[Variable],
|
||||
account: Account,
|
||||
):
|
||||
"""
|
||||
Update draft workflow environment variables
|
||||
"""
|
||||
# fetch draft workflow by app_model
|
||||
workflow = self.get_draft_workflow(app_model=app_model)
|
||||
|
||||
if not workflow:
|
||||
raise ValueError("No draft workflow found.")
|
||||
|
||||
workflow.environment_variables = environment_variables
|
||||
workflow.updated_by = account.id
|
||||
workflow.updated_at = datetime.now(UTC).replace(tzinfo=None)
|
||||
|
||||
# commit db session changes
|
||||
db.session.commit()
|
||||
|
||||
def publish_workflow(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ import type {
|
|||
import { findUsedVarNodes, updateNodeVars } from '@/app/components/workflow/nodes/_base/components/variable/utils'
|
||||
import RemoveEffectVarConfirm from '@/app/components/workflow/nodes/_base/components/remove-effect-var-confirm'
|
||||
import cn from '@/utils/classnames'
|
||||
import { useNodesSyncDraft } from '@/app/components/workflow/hooks/use-nodes-sync-draft'
|
||||
import { webSocketClient } from '@/app/components/workflow/collaboration/core/websocket-manager'
|
||||
import { useStore as useWorkflowStore } from '@/app/components/workflow/store'
|
||||
import { updateEnvironmentVariables } from '@/service/workflow'
|
||||
|
||||
const EnvPanel = () => {
|
||||
const { t } = useTranslation()
|
||||
|
|
@ -29,7 +29,6 @@ const EnvPanel = () => {
|
|||
const envSecrets = useStore(s => s.envSecrets)
|
||||
const updateEnvList = useStore(s => s.setEnvironmentVariables)
|
||||
const setEnvSecrets = useStore(s => s.setEnvSecrets)
|
||||
const { doSyncWorkflowDraft } = useNodesSyncDraft()
|
||||
const appId = useWorkflowStore(s => s.appId)
|
||||
|
||||
const [showVariableModal, setShowVariableModal] = useState(false)
|
||||
|
|
@ -70,18 +69,31 @@ const EnvPanel = () => {
|
|||
|
||||
const handleDelete = useCallback(async (env: EnvironmentVariable) => {
|
||||
removeUsedVarInNodes(env)
|
||||
updateEnvList(envList.filter(e => e.id !== env.id))
|
||||
const newEnvList = envList.filter(e => e.id !== env.id)
|
||||
updateEnvList(newEnvList)
|
||||
setCacheForDelete(undefined)
|
||||
setShowRemoveConfirm(false)
|
||||
await doSyncWorkflowDraft()
|
||||
|
||||
// Emit update event to other connected clients
|
||||
const socket = webSocketClient.getSocket(appId)
|
||||
if (socket?.connected) {
|
||||
socket.emit('collaboration_event', {
|
||||
type: 'varsAndFeaturesUpdate',
|
||||
timestamp: Date.now(),
|
||||
// Use new dedicated environment variables API instead of workflow draft sync
|
||||
try {
|
||||
await updateEnvironmentVariables({
|
||||
appId,
|
||||
environmentVariables: newEnvList,
|
||||
})
|
||||
|
||||
// Emit update event to other connected clients
|
||||
const socket = webSocketClient.getSocket(appId)
|
||||
if (socket?.connected) {
|
||||
socket.emit('collaboration_event', {
|
||||
type: 'varsAndFeaturesUpdate',
|
||||
timestamp: Date.now(),
|
||||
})
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Failed to update environment variables:', error)
|
||||
// Revert local state on error
|
||||
updateEnvList(envList)
|
||||
}
|
||||
|
||||
if (env.value_type === 'secret') {
|
||||
|
|
@ -89,7 +101,7 @@ const EnvPanel = () => {
|
|||
delete newMap[env.id]
|
||||
setEnvSecrets(newMap)
|
||||
}
|
||||
}, [doSyncWorkflowDraft, envList, envSecrets, removeUsedVarInNodes, setEnvSecrets, updateEnvList, appId])
|
||||
}, [envList, envSecrets, removeUsedVarInNodes, setEnvSecrets, updateEnvList, appId])
|
||||
|
||||
const deleteCheck = useCallback((env: EnvironmentVariable) => {
|
||||
const effectedNodes = getEffectedNodes(env)
|
||||
|
|
@ -105,26 +117,46 @@ const EnvPanel = () => {
|
|||
const handleSave = useCallback(async (env: EnvironmentVariable) => {
|
||||
// add env
|
||||
let newEnv = env
|
||||
let newList: EnvironmentVariable[]
|
||||
|
||||
if (!currentVar) {
|
||||
// Adding new environment variable
|
||||
if (env.value_type === 'secret') {
|
||||
setEnvSecrets({
|
||||
...envSecrets,
|
||||
[env.id]: formatSecret(env.value),
|
||||
})
|
||||
}
|
||||
const newList = [env, ...envList]
|
||||
newList = [env, ...envList]
|
||||
updateEnvList(newList)
|
||||
await doSyncWorkflowDraft()
|
||||
const socket = webSocketClient.getSocket(appId)
|
||||
if (socket) {
|
||||
socket.emit('collaboration_event', {
|
||||
type: 'varsAndFeaturesUpdate',
|
||||
|
||||
// Use new dedicated environment variables API
|
||||
try {
|
||||
await updateEnvironmentVariables({
|
||||
appId,
|
||||
environmentVariables: newList,
|
||||
})
|
||||
|
||||
const socket = webSocketClient.getSocket(appId)
|
||||
if (socket) {
|
||||
socket.emit('collaboration_event', {
|
||||
type: 'varsAndFeaturesUpdate',
|
||||
})
|
||||
}
|
||||
|
||||
// Hide secret values in UI
|
||||
updateEnvList(newList.map(e => (e.id === env.id && env.value_type === 'secret') ? { ...e, value: '[__HIDDEN__]' } : e))
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Failed to update environment variables:', error)
|
||||
// Revert local state on error
|
||||
updateEnvList(envList)
|
||||
}
|
||||
updateEnvList(newList.map(e => (e.id === env.id && env.value_type === 'secret') ? { ...e, value: '[__HIDDEN__]' } : e))
|
||||
return
|
||||
}
|
||||
else if (currentVar.value_type === 'secret') {
|
||||
|
||||
// Updating existing environment variable
|
||||
if (currentVar.value_type === 'secret') {
|
||||
if (env.value_type === 'secret') {
|
||||
if (envSecrets[currentVar.id] !== env.value) {
|
||||
newEnv = env
|
||||
|
|
@ -147,8 +179,10 @@ const EnvPanel = () => {
|
|||
})
|
||||
}
|
||||
}
|
||||
const newList = envList.map(e => e.id === currentVar.id ? newEnv : e)
|
||||
|
||||
newList = envList.map(e => e.id === currentVar.id ? newEnv : e)
|
||||
updateEnvList(newList)
|
||||
|
||||
// side effects of rename env
|
||||
if (currentVar.name !== env.name) {
|
||||
const { getNodes, setNodes } = store.getState()
|
||||
|
|
@ -161,15 +195,30 @@ const EnvPanel = () => {
|
|||
})
|
||||
setNodes(newNodes)
|
||||
}
|
||||
await doSyncWorkflowDraft()
|
||||
const socket = webSocketClient.getSocket(appId)
|
||||
if (socket) {
|
||||
socket.emit('collaboration_event', {
|
||||
type: 'varsAndFeaturesUpdate',
|
||||
|
||||
// Use new dedicated environment variables API
|
||||
try {
|
||||
await updateEnvironmentVariables({
|
||||
appId,
|
||||
environmentVariables: newList,
|
||||
})
|
||||
|
||||
const socket = webSocketClient.getSocket(appId)
|
||||
if (socket) {
|
||||
socket.emit('collaboration_event', {
|
||||
type: 'varsAndFeaturesUpdate',
|
||||
})
|
||||
}
|
||||
|
||||
// Hide secret values in UI
|
||||
updateEnvList(newList.map(e => (e.id === env.id && env.value_type === 'secret') ? { ...e, value: '[__HIDDEN__]' } : e))
|
||||
}
|
||||
updateEnvList(newList.map(e => (e.id === env.id && env.value_type === 'secret') ? { ...e, value: '[__HIDDEN__]' } : e))
|
||||
}, [currentVar, doSyncWorkflowDraft, envList, envSecrets, getEffectedNodes, setEnvSecrets, store, updateEnvList, appId])
|
||||
catch (error) {
|
||||
console.error('Failed to update environment variables:', error)
|
||||
// Revert local state on error
|
||||
updateEnvList(envList)
|
||||
}
|
||||
}, [currentVar, envList, envSecrets, getEffectedNodes, setEnvSecrets, store, updateEnvList, appId])
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import type {
|
|||
} from '@/types/workflow'
|
||||
import type { BlockEnum } from '@/app/components/workflow/types'
|
||||
import type { VarInInspect } from '@/types/workflow'
|
||||
import type { EnvironmentVariable } from '@/app/components/workflow/types'
|
||||
|
||||
export const fetchWorkflowDraft = (url: string) => {
|
||||
return get(url, {}, { silent: true }) as Promise<FetchWorkflowDraftResponse>
|
||||
|
|
@ -99,3 +100,18 @@ export const fetchNodeInspectVars = async (appId: string, nodeId: string): Promi
|
|||
const { items } = (await get(`apps/${appId}/workflows/draft/nodes/${nodeId}/variables`)) as { items: VarInInspect[] }
|
||||
return items
|
||||
}
|
||||
|
||||
// Environment Variables API
|
||||
export const fetchEnvironmentVariables = async (appId: string): Promise<EnvironmentVariable[]> => {
|
||||
const { items } = (await get(`apps/${appId}/workflows/draft/environment-variables`)) as { items: EnvironmentVariable[] }
|
||||
return items
|
||||
}
|
||||
|
||||
export const updateEnvironmentVariables = ({ appId, environmentVariables }: {
|
||||
appId: string
|
||||
environmentVariables: EnvironmentVariable[]
|
||||
}) => {
|
||||
return post<CommonResponse>(`apps/${appId}/workflows/draft/environment-variables`, {
|
||||
body: { environment_variables: environmentVariables },
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue