From 9d54d971d2e9027823f0821671775fdcf0e2fa0a Mon Sep 17 00:00:00 2001 From: arkml Date: Wed, 30 Jul 2025 09:01:08 +0530 Subject: [PATCH] Deployment settings (#189) * moved settings to a modal inside the build view under deployment * project name is a editable field in the build view * project name is propogated correctly * remove project name from settings modal * split settings into phone and api * added chat widget option to the deploy settings * bring back top level settings tab with few options * removed cancel option from twilio settings --- .../app/projects/[projectId]/config/app.tsx | 84 ++++---- .../[projectId]/config/components/project.tsx | 84 ++++---- .../[projectId]/config/components/voice.tsx | 20 +- .../app/projects/[projectId]/config/page.tsx | 9 +- .../app/projects/[projectId]/workflow/app.tsx | 11 ++ .../projects/[projectId]/workflow/page.tsx | 1 + .../[projectId]/workflow/workflow_editor.tsx | 185 ++++++++++++++++-- apps/rowboat/app/projects/layout/menu.tsx | 9 +- 8 files changed, 274 insertions(+), 129 deletions(-) diff --git a/apps/rowboat/app/projects/[projectId]/config/app.tsx b/apps/rowboat/app/projects/[projectId]/config/app.tsx index 5c8ecff1..e7b0d26b 100644 --- a/apps/rowboat/app/projects/[projectId]/config/app.tsx +++ b/apps/rowboat/app/projects/[projectId]/config/app.tsx @@ -1,7 +1,8 @@ 'use client'; import { Metadata } from "next"; -import { Spinner, Textarea, Button, Dropdown, DropdownMenu, DropdownItem, DropdownTrigger, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Input, useDisclosure, Divider, Tab, Tabs } from "@heroui/react"; +import { Spinner, Dropdown, DropdownMenu, DropdownItem, DropdownTrigger, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Input, useDisclosure, Divider, Textarea } from "@heroui/react"; +import { Button } from "@/components/ui/button"; import { ReactNode, useEffect, useState } from "react"; import { getProjectConfig, updateProjectName, updateWebhookUrl, createApiKey, deleteApiKey, listApiKeys, deleteProject, rotateSecret } from "../../../actions/project_actions"; import { CopyButton } from "../../../../components/common/copy-button"; @@ -14,8 +15,7 @@ import { RelativeTime } from "@primer/react"; import { Label } from "../../../lib/components/label"; import { FormSection } from "../../../lib/components/form-section"; import { Panel } from "@/components/common/panel-common"; -import { ProjectSection } from './components/project'; -import { VoiceSection } from "./components/voice"; +import { ProjectSection, SimpleProjectSection } from './components/project'; export const metadata: Metadata = { title: "Project config", @@ -187,11 +187,11 @@ export function ApiKeysSection({ API keys are used to authenticate requests to the Rowboat API.

@@ -321,10 +321,10 @@ export function SecretSection({ /> @@ -477,9 +477,8 @@ export function DeleteProjectSection({ @@ -508,13 +507,13 @@ export function DeleteProjectSection({ - @@ -566,39 +565,34 @@ export function ConfigApp({ useChatWidget: boolean; chatWidgetHost: string; }) { - const [selected, setSelected] = useState("general"); - return (
- setSelected(key.toString())} - fullWidth - > - - - - - + + + +
+ ); +} - - - - - - +export function SimpleConfigApp({ + projectId, + onProjectConfigUpdated, +}: { + projectId: string; + onProjectConfigUpdated?: () => void; +}) { + return ( +
+ + +
); } diff --git a/apps/rowboat/app/projects/[projectId]/config/components/project.tsx b/apps/rowboat/app/projects/[projectId]/config/components/project.tsx index a1b84780..4c2c9661 100644 --- a/apps/rowboat/app/projects/[projectId]/config/components/project.tsx +++ b/apps/rowboat/app/projects/[projectId]/config/components/project.tsx @@ -3,8 +3,7 @@ import { ReactNode, useEffect, useState, useCallback } from "react"; import { Spinner, Dropdown, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Input, useDisclosure } from "@heroui/react"; import { Button } from "@/components/ui/button"; -import { Textarea } from "@/components/ui/textarea"; -import { getProjectConfig, updateProjectName, createApiKey, deleteApiKey, listApiKeys, deleteProject, rotateSecret } from "../../../../actions/project_actions"; +import { getProjectConfig, createApiKey, deleteApiKey, listApiKeys, deleteProject, rotateSecret, updateProjectName } from "../../../../actions/project_actions"; import { CopyButton } from "../../../../../components/common/copy-button"; import { EyeIcon, EyeOffIcon, PlusIcon, Trash2Icon } from "lucide-react"; import { WithStringId } from "../../../../lib/types/types"; @@ -14,6 +13,7 @@ import { RelativeTime } from "@primer/react"; import { Label } from "../../../../lib/components/label"; import { sectionHeaderStyles, sectionDescriptionStyles } from './shared-styles'; import { clsx } from "clsx"; +import { InputField } from "../../../../lib/components/input-field"; export function Section({ title, @@ -61,10 +61,15 @@ export function RightContent({ return
{children}
; } -function ProjectNameSection({ projectId }: { projectId: string }) { +function ProjectNameSection({ + projectId, + onProjectConfigUpdated +}: { + projectId: string; + onProjectConfigUpdated?: () => void; +}) { const [loading, setLoading] = useState(false); const [projectName, setProjectName] = useState(null); - const [error, setError] = useState(null); useEffect(() => { setLoading(true); @@ -74,44 +79,32 @@ function ProjectNameSection({ projectId }: { projectId: string }) { }); }, [projectId]); - const handleChange = (e: React.ChangeEvent) => { - const value = e.target.value; - setProjectName(value); - - if (!value.trim()) { - setError("Project name cannot be empty"); - return; + async function updateName(name: string) { + setLoading(true); + await updateProjectName(projectId, name); + setProjectName(name); + setLoading(false); + if (onProjectConfigUpdated) { + onProjectConfigUpdated(); } - - setError(null); - updateProjectName(projectId, value); - }; + } return
- {loading ? ( - - ) : ( -
-
-