load /workflow from backend

This commit is contained in:
Ramnique Singh 2025-08-18 13:51:28 +05:30
parent 9b7894dcd4
commit 9219590d64
2 changed files with 52 additions and 41 deletions

View file

@ -1,5 +1,4 @@
"use client"; "use client";
import { MCPServer, WithStringId } from "../../../lib/types/types";
import { DataSource } from "@/src/entities/models/data-source"; import { DataSource } from "@/src/entities/models/data-source";
import { Project } from "@/src/entities/models/project"; import { Project } from "@/src/entities/models/project";
import { z } from "zod"; import { z } from "zod";
@ -9,12 +8,13 @@ import { Spinner } from "@heroui/react";
import { listDataSources } from "../../../actions/data-source.actions"; import { listDataSources } from "../../../actions/data-source.actions";
import { revertToLiveWorkflow } from "@/app/actions/project.actions"; import { revertToLiveWorkflow } from "@/app/actions/project.actions";
import { fetchProject } from "@/app/actions/project.actions"; import { fetchProject } from "@/app/actions/project.actions";
import { Workflow, WorkflowTool } from "@/app/lib/types/workflow_types"; import { Workflow } from "@/app/lib/types/workflow_types";
import { getEligibleModels } from "@/app/actions/billing.actions";
import { ModelsResponse } from "@/app/lib/types/billing_types"; import { ModelsResponse } from "@/app/lib/types/billing_types";
export function App({ export function App({
projectId, initialProjectData,
initialDataSources,
eligibleModels,
useRag, useRag,
useRagUploads, useRagUploads,
useRagS3Uploads, useRagS3Uploads,
@ -22,7 +22,9 @@ export function App({
defaultModel, defaultModel,
chatWidgetHost, chatWidgetHost,
}: { }: {
projectId: string; initialProjectData: z.infer<typeof Project>;
initialDataSources: z.infer<typeof DataSource>[];
eligibleModels: z.infer<typeof ModelsResponse> | "*";
useRag: boolean; useRag: boolean;
useRagUploads: boolean; useRagUploads: boolean;
useRagS3Uploads: boolean; useRagS3Uploads: boolean;
@ -31,11 +33,9 @@ export function App({
chatWidgetHost: string; chatWidgetHost: string;
}) { }) {
const [mode, setMode] = useState<'draft' | 'live'>('draft'); const [mode, setMode] = useState<'draft' | 'live'>('draft');
const [project, setProject] = useState<z.infer<typeof Project> | null>(null); const [project, setProject] = useState<z.infer<typeof Project>>(initialProjectData);
const [dataSources, setDataSources] = useState<z.infer<typeof DataSource>[] | null>(null); const [dataSources, setDataSources] = useState<z.infer<typeof DataSource>[]>(initialDataSources);
const [projectConfig, setProjectConfig] = useState<z.infer<typeof Project> | null>(null);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [eligibleModels, setEligibleModels] = useState<z.infer<typeof ModelsResponse> | "*">("*");
console.log('workflow app.tsx render'); console.log('workflow app.tsx render');
@ -45,44 +45,39 @@ export function App({
workflow = project?.liveWorkflow; workflow = project?.liveWorkflow;
} }
const loadData = useCallback(async () => { const reloadData = useCallback(async () => {
setLoading(true); setLoading(true);
const [ const [
project, projectData,
dataSources, sourcesData,
eligibleModels,
] = await Promise.all([ ] = await Promise.all([
fetchProject(projectId), fetchProject(initialProjectData.id),
listDataSources(projectId), listDataSources(initialProjectData.id),
getEligibleModels(),
]); ]);
setProject(project); setProject(projectData);
setDataSources(dataSources); setDataSources(sourcesData);
setEligibleModels(eligibleModels);
setLoading(false); setLoading(false);
}, [projectId]); }, [initialProjectData.id]);
const handleProjectToolsUpdate = useCallback(async () => { const handleProjectToolsUpdate = useCallback(async () => {
// Lightweight refresh for tool-only updates // Lightweight refresh for tool-only updates
const projectConfig = await fetchProject(projectId); const projectConfig = await fetchProject(initialProjectData.id);
setProject(projectConfig); setProject(projectConfig);
setProjectConfig(projectConfig); }, [initialProjectData.id]);
}, [projectId]);
const handleDataSourcesUpdate = useCallback(async () => { const handleDataSourcesUpdate = useCallback(async () => {
// Refresh data sources // Refresh data sources
const updatedDataSources = await listDataSources(projectId); const updatedDataSources = await listDataSources(initialProjectData.id);
setDataSources(updatedDataSources); setDataSources(updatedDataSources);
}, [projectId]); }, [initialProjectData.id]);
const handleProjectConfigUpdate = useCallback(async () => { const handleProjectConfigUpdate = useCallback(async () => {
// Refresh project config when project name or other settings change // Refresh project config when project name or other settings change
const updatedProjectConfig = await fetchProject(projectId); const updatedProjectConfig = await fetchProject(initialProjectData.id);
setProject(updatedProjectConfig); setProject(updatedProjectConfig);
setProjectConfig(updatedProjectConfig); }, [initialProjectData.id]);
}, [projectId]);
// Auto-update data sources when there are pending ones // Auto-update data sources when there are pending ones
useEffect(() => { useEffect(() => {
@ -92,7 +87,7 @@ export function App({
if (!hasPendingSources) return; if (!hasPendingSources) return;
const interval = setInterval(async () => { const interval = setInterval(async () => {
const updatedDataSources = await listDataSources(projectId); const updatedDataSources = await listDataSources(initialProjectData.id);
setDataSources(updatedDataSources); setDataSources(updatedDataSources);
// Stop polling if no more pending sources // Stop polling if no more pending sources
@ -103,11 +98,7 @@ export function App({
}, 7000); // Poll every 7 seconds (reduced from 3) }, 7000); // Poll every 7 seconds (reduced from 3)
return () => clearInterval(interval); return () => clearInterval(interval);
}, [dataSources, projectId]); }, [dataSources, initialProjectData.id]);
// Add this useEffect for initial load
useEffect(() => {
loadData();
}, [mode, loadData, projectId]);
function handleSetMode(mode: 'draft' | 'live') { function handleSetMode(mode: 'draft' | 'live') {
setMode(mode); setMode(mode);
@ -115,8 +106,8 @@ export function App({
async function handleRevertToLive() { async function handleRevertToLive() {
setLoading(true); setLoading(true);
await revertToLiveWorkflow(projectId); await revertToLiveWorkflow(initialProjectData.id);
loadData(); reloadData();
} }
// if workflow is null, show the selector // if workflow is null, show the selector
@ -128,11 +119,11 @@ export function App({
</div>} </div>}
{!loading && !workflow && <div>No workflow found!</div>} {!loading && !workflow && <div>No workflow found!</div>}
{!loading && project && workflow && (dataSources !== null) && <WorkflowEditor {!loading && project && workflow && (dataSources !== null) && <WorkflowEditor
projectId={projectId} projectId={initialProjectData.id}
isLive={mode == 'live'} isLive={mode == 'live'}
workflow={workflow} workflow={workflow}
dataSources={dataSources} dataSources={dataSources}
projectConfig={projectConfig || project} projectConfig={project}
useRag={useRag} useRag={useRag}
useRagUploads={useRagUploads} useRagUploads={useRagUploads}
useRagS3Uploads={useRagS3Uploads} useRagS3Uploads={useRagS3Uploads}

View file

@ -1,12 +1,17 @@
import { Metadata } from "next"; import { Metadata } from "next";
import { App } from "./app"; import { App } from "./app";
import { USE_RAG, USE_RAG_UPLOADS, USE_RAG_S3_UPLOADS, USE_RAG_SCRAPING } from "@/app/lib/feature_flags"; import { USE_RAG, USE_RAG_UPLOADS, USE_RAG_S3_UPLOADS, USE_RAG_SCRAPING, USE_BILLING } from "@/app/lib/feature_flags";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
import { requireActiveBillingSubscription } from '@/app/lib/billing'; import { requireActiveBillingSubscription } from '@/app/lib/billing';
import { container } from "@/di/container"; import { container } from "@/di/container";
import { IProjectsRepository } from "@/src/application/repositories/projects.repository.interface"; import { IProjectsRepository } from "@/src/application/repositories/projects.repository.interface";
import { IDataSourcesRepository } from "@/src/application/repositories/data-sources.repository.interface";
import { getEligibleModels } from "@/app/lib/billing";
import { ModelsResponse } from "@/app/lib/types/billing_types";
import { z } from "zod";
const projectsRepository = container.resolve<IProjectsRepository>('projectsRepository'); const projectsRepository = container.resolve<IProjectsRepository>('projectsRepository');
const dataSourceRepository = container.resolve<IDataSourcesRepository>('dataSourcesRepository');
const DEFAULT_MODEL = process.env.PROVIDER_DEFAULT_MODEL || "gpt-4.1"; const DEFAULT_MODEL = process.env.PROVIDER_DEFAULT_MODEL || "gpt-4.1";
@ -20,18 +25,33 @@ export default async function Page(
} }
) { ) {
const params = await props.params; const params = await props.params;
await requireActiveBillingSubscription(); const customer = await requireActiveBillingSubscription();
console.log('->>> workflow page being rendered'); console.log('->>> workflow page being rendered');
const project = await projectsRepository.fetch(params.projectId); const project = await projectsRepository.fetch(params.projectId);
if (!project) { if (!project) {
notFound(); notFound();
} }
const sources = [];
let cursor = undefined;
do {
const result = await dataSourceRepository.list(project.id, undefined, cursor);
sources.push(...result.items);
cursor = result.nextCursor;
} while (cursor);
let eligibleModels: z.infer<typeof ModelsResponse> | "*" = '*';
if (USE_BILLING) {
eligibleModels = await getEligibleModels(customer._id);
}
console.log('/workflow page.tsx serve'); console.log('/workflow page.tsx serve');
return ( return (
<App <App
projectId={params.projectId} initialProjectData={project}
initialDataSources={sources}
eligibleModels={eligibleModels}
useRag={USE_RAG} useRag={USE_RAG}
useRagUploads={USE_RAG_UPLOADS} useRagUploads={USE_RAG_UPLOADS}
useRagS3Uploads={USE_RAG_S3_UPLOADS} useRagS3Uploads={USE_RAG_S3_UPLOADS}