mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-05-16 18:25:17 +02:00
load /workflow from backend
This commit is contained in:
parent
9b7894dcd4
commit
9219590d64
2 changed files with 52 additions and 41 deletions
|
|
@ -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}
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue