From 9cad69fd0c71c1662674384cb79ef60c33bb7701 Mon Sep 17 00:00:00 2001 From: ValueOn AG Date: Fri, 13 Mar 2026 08:29:30 +0100 Subject: [PATCH] fix feature instance passing --- src/api/workflowApi.ts | 75 +++++++++---------- src/hooks/playground/useDashboardInputForm.ts | 2 +- src/hooks/playground/useWorkflowLifecycle.ts | 13 ++-- src/hooks/playground/useWorkflows.ts | 20 +++-- src/hooks/useWorkflows.ts | 6 +- src/pages/workflows/WorkflowsPage.tsx | 2 +- 6 files changed, 66 insertions(+), 52 deletions(-) diff --git a/src/api/workflowApi.ts b/src/api/workflowApi.ts index 3d7b0db..7254640 100644 --- a/src/api/workflowApi.ts +++ b/src/api/workflowApi.ts @@ -68,17 +68,23 @@ export type ApiRequestFunction = (options: ApiRequestOptions) => Promise { - const url = apiBaseUrl ? `${apiBaseUrl}/workflows` : '/api/workflows/'; + const base = _requireApiBaseUrl(apiBaseUrl, 'fetchWorkflows'); + const url = `${base}/workflows`; console.log('📤 fetchWorkflows: Making API request to', url); try { @@ -135,30 +141,28 @@ export async function fetchWorkflows( } /** - * Fetch a single workflow by ID - * When apiBaseUrl provided: GET {apiBaseUrl}/workflows/{workflowId} - * Otherwise: GET /api/workflows/{workflowId} + * Fetch a single workflow by ID: GET {apiBaseUrl}/workflows/{workflowId} */ export async function fetchWorkflow( request: ApiRequestFunction, workflowId: string, apiBaseUrl?: string ): Promise { - const url = apiBaseUrl ? `${apiBaseUrl}/workflows/${workflowId}` : `/api/workflows/${workflowId}`; + const base = _requireApiBaseUrl(apiBaseUrl, 'fetchWorkflow'); + const url = `${base}/workflows/${workflowId}`; return await request({ url, method: 'get' }); } /** - * Fetch workflow status (lightweight status check) - * When apiBaseUrl provided: GET {apiBaseUrl}/workflows/{workflowId}/status - * Otherwise: GET /api/workflows/{workflowId}/status + * Fetch workflow status (lightweight status check): GET {apiBaseUrl}/workflows/{workflowId}/status */ export async function fetchWorkflowStatus( request: ApiRequestFunction, workflowId: string, apiBaseUrl?: string ): Promise { - const url = apiBaseUrl ? `${apiBaseUrl}/workflows/${workflowId}/status` : `/api/workflows/${workflowId}/status`; + const base = _requireApiBaseUrl(apiBaseUrl, 'fetchWorkflowStatus'); + const url = `${base}/workflows/${workflowId}/status`; const data = await request({ url, method: 'get' }); if (data && typeof data === 'object') { @@ -172,9 +176,7 @@ export async function fetchWorkflowStatus( } /** - * Fetch workflow messages - * When apiBaseUrl provided: GET {apiBaseUrl}/workflows/{workflowId}/messages - * Otherwise: GET /api/workflows/{workflowId}/messages + * Fetch workflow messages: GET {apiBaseUrl}/workflows/{workflowId}/messages */ export async function fetchWorkflowMessages( request: ApiRequestFunction, @@ -183,7 +185,8 @@ export async function fetchWorkflowMessages( apiBaseUrl?: string ): Promise { const params = messageId ? { messageId } : undefined; - const url = apiBaseUrl ? `${apiBaseUrl}/workflows/${workflowId}/messages` : `/api/workflows/${workflowId}/messages`; + const base = _requireApiBaseUrl(apiBaseUrl, 'fetchWorkflowMessages'); + const url = `${base}/workflows/${workflowId}/messages`; const data = await request({ url, method: 'get', params }); if (Array.isArray(data)) { @@ -203,9 +206,7 @@ export async function fetchWorkflowMessages( } /** - * Fetch workflow logs - * When apiBaseUrl provided: GET {apiBaseUrl}/workflows/{workflowId}/logs - * Otherwise: GET /api/workflows/{workflowId}/logs + * Fetch workflow logs: GET {apiBaseUrl}/workflows/{workflowId}/logs */ export async function fetchWorkflowLogs( request: ApiRequestFunction, @@ -214,7 +215,8 @@ export async function fetchWorkflowLogs( apiBaseUrl?: string ): Promise { const params = logId ? { logId } : undefined; - const url = apiBaseUrl ? `${apiBaseUrl}/workflows/${workflowId}/logs` : `/api/workflows/${workflowId}/logs`; + const base = _requireApiBaseUrl(apiBaseUrl, 'fetchWorkflowLogs'); + const url = `${base}/workflows/${workflowId}/logs`; const data = await request({ url, method: 'get', params }); if (Array.isArray(data)) { @@ -389,9 +391,7 @@ export async function stopWorkflowApi( } /** - * Update workflow properties - * When apiBaseUrl provided: PUT {apiBaseUrl}/workflows/{workflowId} - * Otherwise: PUT /api/workflows/{workflowId} + * Update workflow properties: PUT {apiBaseUrl}/workflows/{workflowId} */ export async function updateWorkflowApi( request: ApiRequestFunction, @@ -399,34 +399,33 @@ export async function updateWorkflowApi( updateData: Partial<{ name: string; description?: string; tags?: string[] }>, apiBaseUrl?: string ): Promise { - const url = apiBaseUrl ? `${apiBaseUrl}/workflows/${workflowId}` : `/api/workflows/${workflowId}`; + const base = _requireApiBaseUrl(apiBaseUrl, 'updateWorkflowApi'); + const url = `${base}/workflows/${workflowId}`; return await request({ url, method: 'put', data: updateData }); } /** - * Delete a workflow and all associated data - * When apiBaseUrl provided: DELETE {apiBaseUrl}/workflows/{workflowId} - * Otherwise: DELETE /api/workflows/{workflowId} + * Delete a workflow and all associated data: DELETE {apiBaseUrl}/workflows/{workflowId} */ export async function deleteWorkflowApi( request: ApiRequestFunction, workflowId: string, apiBaseUrl?: string ): Promise { - const url = apiBaseUrl ? `${apiBaseUrl}/workflows/${workflowId}` : `/api/workflows/${workflowId}`; + const base = _requireApiBaseUrl(apiBaseUrl, 'deleteWorkflowApi'); + const url = `${base}/workflows/${workflowId}`; await request({ url, method: 'delete' }); } /** - * Delete multiple workflows - * When apiBaseUrl provided, uses feature-scoped delete endpoint + * Delete multiple workflows: DELETE {apiBaseUrl}/workflows/{workflowId} (per workflow) */ export async function deleteWorkflowsApi( request: ApiRequestFunction, workflowIds: string[], apiBaseUrl?: string ): Promise { - const base = apiBaseUrl ? `${apiBaseUrl}/workflows` : '/api/workflows'; + const base = `${_requireApiBaseUrl(apiBaseUrl, 'deleteWorkflowsApi')}/workflows`; const deletePromises = workflowIds.map(workflowId => request({ url: `${base}/${workflowId}`, @@ -441,9 +440,7 @@ export async function deleteWorkflowsApi( } /** - * Delete a message from a workflow - * When apiBaseUrl provided: DELETE {apiBaseUrl}/workflows/{workflowId}/messages/{messageId} - * Otherwise: DELETE /api/workflows/{workflowId}/messages/{messageId} + * Delete a message from a workflow: DELETE {apiBaseUrl}/workflows/{workflowId}/messages/{messageId} */ export async function deleteMessageApi( request: ApiRequestFunction, @@ -451,14 +448,13 @@ export async function deleteMessageApi( messageId: string, apiBaseUrl?: string ): Promise { - const url = apiBaseUrl ? `${apiBaseUrl}/workflows/${workflowId}/messages/${messageId}` : `/api/workflows/${workflowId}/messages/${messageId}`; + const base = _requireApiBaseUrl(apiBaseUrl, 'deleteMessageApi'); + const url = `${base}/workflows/${workflowId}/messages/${messageId}`; await request({ url, method: 'delete' }); } /** - * Delete a file reference from a message - * When apiBaseUrl provided: DELETE {apiBaseUrl}/workflows/{workflowId}/messages/{messageId}/files/{fileId} - * Otherwise: DELETE /api/workflows/{workflowId}/messages/{messageId}/files/{fileId} + * Delete a file reference from a message: DELETE {apiBaseUrl}/workflows/{workflowId}/messages/{messageId}/files/{fileId} */ export async function deleteFileFromMessageApi( request: ApiRequestFunction, @@ -467,7 +463,8 @@ export async function deleteFileFromMessageApi( fileId: string, apiBaseUrl?: string ): Promise { - const url = apiBaseUrl ? `${apiBaseUrl}/workflows/${workflowId}/messages/${messageId}/files/${fileId}` : `/api/workflows/${workflowId}/messages/${messageId}/files/${fileId}`; + const base = _requireApiBaseUrl(apiBaseUrl, 'deleteFileFromMessageApi'); + const url = `${base}/workflows/${workflowId}/messages/${messageId}/files/${fileId}`; await request({ url, method: 'delete' }); } diff --git a/src/hooks/playground/useDashboardInputForm.ts b/src/hooks/playground/useDashboardInputForm.ts index d9f0538..cd5fec0 100644 --- a/src/hooks/playground/useDashboardInputForm.ts +++ b/src/hooks/playground/useDashboardInputForm.ts @@ -152,7 +152,7 @@ export function useDashboardInputForm(instanceId: string) { }; }, []); - const { workflows, loading: workflowsLoading, refetch: refetchWorkflows } = useWorkflows(); + const { workflows, loading: workflowsLoading, refetch: refetchWorkflows } = useWorkflows(instanceId); // Track processed log IDs to avoid reprocessing const processedLogIdsRef = useRef>(new Set()); diff --git a/src/hooks/playground/useWorkflowLifecycle.ts b/src/hooks/playground/useWorkflowLifecycle.ts index 3fb301e..9b1be84 100644 --- a/src/hooks/playground/useWorkflowLifecycle.ts +++ b/src/hooks/playground/useWorkflowLifecycle.ts @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback, useRef } from 'react'; +import { useState, useEffect, useCallback, useRef, useMemo } from 'react'; import { useApiRequest } from '../useApi'; import { type Workflow, @@ -11,6 +11,7 @@ import { import { useWorkflowOperations } from './useWorkflowOperations'; import { sortMessages, sortLogs } from './playgroundUtils'; import { useWorkflowPolling } from './useWorkflowPolling'; +import { getWorkflowApiBaseUrl } from '../useWorkflows'; interface UnifiedChatDataItem { type: 'message' | 'log' | 'stat'; @@ -65,6 +66,8 @@ interface UnifiedChatDataItem { */ export function useWorkflowLifecycle(instanceId: string) { + const apiBaseUrl = useMemo(() => getWorkflowApiBaseUrl(instanceId, 'chatplayground'), [instanceId]); + // === STATE === const [workflowId, setWorkflowId] = useState(null); const [workflowStatus, setWorkflowStatus] = useState('idle'); @@ -333,7 +336,7 @@ export function useWorkflowLifecycle(instanceId: string) { const afterTimestamp = lastRenderedTimestampRef.current || undefined; // Fetch workflow status - const workflowData = await fetchWorkflowApi(request, id).catch(() => null); + const workflowData = await fetchWorkflowApi(request, id, apiBaseUrl).catch(() => null); if (workflowData) { const status = workflowData.status || 'idle'; @@ -366,7 +369,7 @@ export function useWorkflowLifecycle(instanceId: string) { } catch (error) { console.error('❌ Polling error:', error); } - }, [request, instanceId, updateWorkflowStatus, processUnifiedChatData]); + }, [request, instanceId, apiBaseUrl, updateWorkflowStatus, processUnifiedChatData]); // === POLLING CONTROL EFFECT === useEffect(() => { @@ -517,7 +520,7 @@ export function useWorkflowLifecycle(instanceId: string) { setHasRenderedLastMessage(false); // Fetch workflow data - const workflowData = await fetchWorkflowApi(request, workflowIdToSelect).catch(() => null); + const workflowData = await fetchWorkflowApi(request, workflowIdToSelect, apiBaseUrl).catch(() => null); if (!workflowData) { setMessages([]); @@ -578,7 +581,7 @@ export function useWorkflowLifecycle(instanceId: string) { } catch (error) { console.error('❌ Error selecting workflow:', error); } - }, [request, instanceId, updateWorkflowStatus, processUnifiedChatData]); + }, [request, instanceId, apiBaseUrl, updateWorkflowStatus, processUnifiedChatData]); // === EXPOSE STATUS SETTER FOR OPTIMISTIC UPDATES === const setWorkflowStatusOptimistic = useCallback((status: string) => { diff --git a/src/hooks/playground/useWorkflows.ts b/src/hooks/playground/useWorkflows.ts index c7cfe6f..ebf367b 100644 --- a/src/hooks/playground/useWorkflows.ts +++ b/src/hooks/playground/useWorkflows.ts @@ -1,9 +1,10 @@ -import { useState, useEffect, useCallback } from 'react'; +import { useState, useEffect, useCallback, useMemo } from 'react'; import { useApiRequest } from '../useApi'; import { useWorkflowSelection } from '../../contexts/WorkflowSelectionContext'; import { fetchWorkflows as fetchWorkflowsApi, type Workflow } from '../../api/workflowApi'; +import { getWorkflowApiBaseUrl } from '../useWorkflows'; -export function useWorkflows() { +export function useWorkflows(instanceId?: string, featureCode: string = 'chatplayground') { const [workflows, setWorkflows] = useState([]); const [isRefetching, setIsRefetching] = useState(false); const [loading, setLoading] = useState(false); @@ -11,13 +12,22 @@ export function useWorkflows() { const { request } = useApiRequest(); const { selectedWorkflowId, clearWorkflow } = useWorkflowSelection(); + const apiBaseUrl = useMemo( + () => getWorkflowApiBaseUrl(instanceId, featureCode), + [instanceId, featureCode] + ); + const fetchWorkflows = useCallback(async () => { + if (!apiBaseUrl) { + console.warn('⚠️ useWorkflows: No apiBaseUrl available (missing instanceId), skipping fetch'); + return; + } try { setLoading(true); setError(null); - console.log('🔄 useWorkflows: Fetching workflows from API...'); - const workflowList = await fetchWorkflowsApi(request); + console.log('🔄 useWorkflows: Fetching workflows from API...', { apiBaseUrl }); + const workflowList = await fetchWorkflowsApi(request, undefined, apiBaseUrl); console.log('✅ useWorkflows: Fetched workflows:', workflowList); if (Array.isArray(workflowList)) { @@ -34,7 +44,7 @@ export function useWorkflows() { } finally { setLoading(false); } - }, [request]); + }, [request, apiBaseUrl]); useEffect(() => { fetchWorkflows(); diff --git a/src/hooks/useWorkflows.ts b/src/hooks/useWorkflows.ts index adcb033..cdc25dc 100644 --- a/src/hooks/useWorkflows.ts +++ b/src/hooks/useWorkflows.ts @@ -122,7 +122,11 @@ export function useUserWorkflows(options?: { instanceId?: string; featureCode?: } let data: any; - const url = apiBaseUrl ? `${apiBaseUrl}/workflows` : '/api/workflows/'; + if (!apiBaseUrl) { + console.error('useUserWorkflows: apiBaseUrl is required (missing instanceId/featureCode)'); + return; + } + const url = `${apiBaseUrl}/workflows`; if (Object.keys(requestParams).length > 0) { data = await request({ url, method: 'get', params: requestParams }); } else { diff --git a/src/pages/workflows/WorkflowsPage.tsx b/src/pages/workflows/WorkflowsPage.tsx index d32fb08..e38d710 100644 --- a/src/pages/workflows/WorkflowsPage.tsx +++ b/src/pages/workflows/WorkflowsPage.tsx @@ -27,7 +27,7 @@ export const WorkflowsPage: React.FC = () => { const { instanceId, featureCode } = useCurrentInstance(); const workflowOptions = instanceId && featureCode ? { instanceId, featureCode } : undefined; const apiBaseUrl = getWorkflowApiBaseUrl(instanceId, featureCode); - const apiEndpoint = apiBaseUrl ? `${apiBaseUrl}/workflows` : '/api/workflows/'; + const apiEndpoint = apiBaseUrl ? `${apiBaseUrl}/workflows` : ''; // Data hook - pass instance context when in feature route const {