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 {