mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-05-28 19:05:31 +02:00
commit
11a3a2f357
61 changed files with 5344 additions and 11135 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
"use server";
|
"use server";
|
||||||
import { getSession } from "@auth0/nextjs-auth0";
|
import { auth0 } from "../lib/auth0";
|
||||||
import { USE_AUTH } from "../lib/feature_flags";
|
import { USE_AUTH } from "../lib/feature_flags";
|
||||||
import { WithStringId, User } from "../lib/types/types";
|
import { WithStringId, User } from "../lib/types/types";
|
||||||
import { getUserFromSessionId, GUEST_DB_USER } from "../lib/auth";
|
import { getUserFromSessionId, GUEST_DB_USER } from "../lib/auth";
|
||||||
|
|
@ -12,7 +12,7 @@ export async function authCheck(): Promise<WithStringId<z.infer<typeof User>>> {
|
||||||
return GUEST_DB_USER;
|
return GUEST_DB_USER;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user } = await getSession() || {};
|
const { user } = await auth0.getSession() || {};
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new Error('User not authenticated');
|
throw new Error('User not authenticated');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -777,7 +777,7 @@ export async function generateServerAuthUrl(
|
||||||
await projectAuthCheck(projectId);
|
await projectAuthCheck(projectId);
|
||||||
|
|
||||||
// Get the origin from request headers
|
// Get the origin from request headers
|
||||||
const headersList = headers();
|
const headersList = await headers();
|
||||||
const host = headersList.get('host') || '';
|
const host = headersList.get('host') || '';
|
||||||
const protocol = headersList.get('x-forwarded-proto') || 'http';
|
const protocol = headersList.get('x-forwarded-proto') || 'http';
|
||||||
const origin = `${protocol}://${host}`;
|
const origin = `${protocol}://${host}`;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
// pages/api/auth/[auth0].js
|
|
||||||
import { handleAuth, handleLogin } from '@auth0/nextjs-auth0';
|
|
||||||
|
|
||||||
export const GET = handleAuth({
|
|
||||||
login: handleLogin({
|
|
||||||
authorizationParams: {
|
|
||||||
prompt: 'login'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
@ -3,7 +3,8 @@ import { USE_BILLING } from "@/app/lib/feature_flags";
|
||||||
import { redisClient } from "@/app/lib/redis";
|
import { redisClient } from "@/app/lib/redis";
|
||||||
import { CopilotAPIRequest } from "@/app/lib/types/copilot_types";
|
import { CopilotAPIRequest } from "@/app/lib/types/copilot_types";
|
||||||
|
|
||||||
export async function GET(request: Request, { params }: { params: { streamId: string } }) {
|
export async function GET(request: Request, props: { params: Promise<{ streamId: string }> }) {
|
||||||
|
const params = await props.params;
|
||||||
// get the payload from redis
|
// get the payload from redis
|
||||||
const payload = await redisClient.get(`copilot-stream-${params.streamId}`);
|
const payload = await redisClient.get(`copilot-stream-${params.streamId}`);
|
||||||
if (!payload) {
|
if (!payload) {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ import { redisClient } from "@/app/lib/redis";
|
||||||
import { AgenticAPIChatMessage, AgenticAPIChatRequest, convertFromAgenticAPIChatMessages } from "@/app/lib/types/agents_api_types";
|
import { AgenticAPIChatMessage, AgenticAPIChatRequest, convertFromAgenticAPIChatMessages } from "@/app/lib/types/agents_api_types";
|
||||||
import { createParser, type EventSourceMessage } from 'eventsource-parser';
|
import { createParser, type EventSourceMessage } from 'eventsource-parser';
|
||||||
|
|
||||||
export async function GET(request: Request, { params }: { params: { streamId: string } }) {
|
export async function GET(request: Request, props: { params: Promise<{ streamId: string }> }) {
|
||||||
|
const params = await props.params;
|
||||||
// get the payload from redis
|
// get the payload from redis
|
||||||
const payload = await redisClient.get(`chat-stream-${params.streamId}`);
|
const payload = await redisClient.get(`chat-stream-${params.streamId}`);
|
||||||
if (!payload) {
|
if (!payload) {
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,8 @@ import { ObjectId } from 'mongodb';
|
||||||
const UPLOADS_DIR = process.env.RAG_UPLOADS_DIR || '/uploads';
|
const UPLOADS_DIR = process.env.RAG_UPLOADS_DIR || '/uploads';
|
||||||
|
|
||||||
// PUT endpoint to handle file uploads
|
// PUT endpoint to handle file uploads
|
||||||
export async function PUT(
|
export async function PUT(request: NextRequest, props: { params: Promise<{ fileId: string }> }) {
|
||||||
request: NextRequest,
|
const params = await props.params;
|
||||||
{ params }: { params: { fileId: string } }
|
|
||||||
) {
|
|
||||||
const fileId = params.fileId;
|
const fileId = params.fileId;
|
||||||
if (!fileId) {
|
if (!fileId) {
|
||||||
return NextResponse.json({ error: 'Missing file ID' }, { status: 400 });
|
return NextResponse.json({ error: 'Missing file ID' }, { status: 400 });
|
||||||
|
|
@ -34,10 +32,8 @@ export async function PUT(
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET endpoint to handle file downloads
|
// GET endpoint to handle file downloads
|
||||||
export async function GET(
|
export async function GET(request: NextRequest, props: { params: Promise<{ fileId: string }> }) {
|
||||||
request: NextRequest,
|
const params = await props.params;
|
||||||
{ params }: { params: { fileId: string } }
|
|
||||||
) {
|
|
||||||
const fileId = params.fileId;
|
const fileId = params.fileId;
|
||||||
if (!fileId) {
|
if (!fileId) {
|
||||||
return NextResponse.json({ error: 'Missing file ID' }, { status: 400 });
|
return NextResponse.json({ error: 'Missing file ID' }, { status: 400 });
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,8 @@ import { chatsCollection } from "../../../../../../lib/mongodb";
|
||||||
import { ObjectId } from "mongodb";
|
import { ObjectId } from "mongodb";
|
||||||
import { authCheck } from "../../../utils";
|
import { authCheck } from "../../../utils";
|
||||||
|
|
||||||
export async function POST(
|
export async function POST(request: NextRequest, props: { params: Promise<{ chatId: string }> }): Promise<Response> {
|
||||||
request: NextRequest,
|
const params = await props.params;
|
||||||
{ params }: { params: { chatId: string } }
|
|
||||||
): Promise<Response> {
|
|
||||||
return await authCheck(request, async (session) => {
|
return await authCheck(request, async (session) => {
|
||||||
const { chatId } = params;
|
const { chatId } = params;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,8 @@ import { Filter, ObjectId } from "mongodb";
|
||||||
import { authCheck } from "../../../utils";
|
import { authCheck } from "../../../utils";
|
||||||
|
|
||||||
// list messages
|
// list messages
|
||||||
export async function GET(
|
export async function GET(req: NextRequest, props: { params: Promise<{ chatId: string }> }): Promise<Response> {
|
||||||
req: NextRequest,
|
const params = await props.params;
|
||||||
{ params }: { params: { chatId: string } }
|
|
||||||
): Promise<Response> {
|
|
||||||
return await authCheck(req, async (session) => {
|
return await authCheck(req, async (session) => {
|
||||||
const { chatId } = params;
|
const { chatId } = params;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,21 @@
|
||||||
'use client';
|
'use client';
|
||||||
import { TypewriterEffect } from "./lib/components/typewriter";
|
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import logo from "@/public/logo.png";
|
import logo from "@/public/logo.png";
|
||||||
import { useUser } from "@auth0/nextjs-auth0/client";
|
import { useUser } from "@auth0/nextjs-auth0";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { Spinner } from "@heroui/react";
|
import { Spinner } from "@heroui/react";
|
||||||
import { LogInIcon } from "lucide-react";
|
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { user, error, isLoading } = useUser();
|
const { user, isLoading } = useUser();
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
router.push("/projects");
|
router.push("/projects");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add auto-redirect for non-authenticated users
|
// Add auto-redirect for non-authenticated users
|
||||||
if (!isLoading && !user && !error) {
|
if (!isLoading && !user) {
|
||||||
router.push("/api/auth/login");
|
router.push("/auth/login");
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -30,8 +28,7 @@ export function App() {
|
||||||
alt="RowBoat Logo"
|
alt="RowBoat Logo"
|
||||||
height={40}
|
height={40}
|
||||||
/>
|
/>
|
||||||
{(isLoading || (!user && !error)) && <Spinner size="sm" />}
|
{(isLoading || !user) && <Spinner size="sm" />}
|
||||||
{error && <div className="text-red-500">{error.message}</div>}
|
|
||||||
{user && <div className="flex items-center gap-2">
|
{user && <div className="flex items-center gap-2">
|
||||||
<Spinner size="sm" />
|
<Spinner size="sm" />
|
||||||
<div className="text-sm text-gray-400">Welcome, {user.name}</div>
|
<div className="text-sm text-gray-400">Welcome, {user.name}</div>
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,14 @@ import { redirect } from "next/navigation";
|
||||||
|
|
||||||
export const dynamic = 'force-dynamic';
|
export const dynamic = 'force-dynamic';
|
||||||
|
|
||||||
export default async function Page({
|
export default async function Page(
|
||||||
searchParams,
|
props: {
|
||||||
}: {
|
searchParams: Promise<{
|
||||||
searchParams: {
|
|
||||||
redirect: string;
|
redirect: string;
|
||||||
|
}>
|
||||||
}
|
}
|
||||||
}) {
|
) {
|
||||||
|
const searchParams = await props.searchParams;
|
||||||
const customer = await requireBillingCustomer();
|
const customer = await requireBillingCustomer();
|
||||||
await syncWithStripe(customer._id);
|
await syncWithStripe(customer._id);
|
||||||
const redirectUrl = searchParams.redirect as string;
|
const redirectUrl = searchParams.redirect as string;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap');
|
||||||
|
@import 'tailwindcss';
|
||||||
@import './styles/quill-mentions.css';
|
@import './styles/quill-mentions.css';
|
||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
@plugin './hero.ts';
|
||||||
@tailwind utilities;
|
|
||||||
|
@source '../node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}';
|
||||||
|
@custom-variant dark (&:is(.dark *));
|
||||||
|
|
||||||
|
@reference 'tailwindcss';
|
||||||
|
|
||||||
@layer utilities {
|
@layer utilities {
|
||||||
.text-balance {
|
.text-balance {
|
||||||
|
|
@ -106,74 +112,16 @@ html, body {
|
||||||
input, textarea, select {
|
input, textarea, select {
|
||||||
@apply rounded-lg border-[#E5E7EB] dark:border-[#2E2E30]
|
@apply rounded-lg border-[#E5E7EB] dark:border-[#2E2E30]
|
||||||
bg-[#F3F4F6] dark:bg-[#2A2A2D]
|
bg-[#F3F4F6] dark:bg-[#2A2A2D]
|
||||||
focus:ring-2 focus:ring-indigo-500 focus:ring-opacity-50
|
focus:ring-2 focus:ring-indigo-500/50
|
||||||
transition-all duration-200;
|
transition-all duration-200;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@layer base {
|
|
||||||
* {
|
|
||||||
@apply border-border;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
@apply bg-background text-foreground;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-shadow {
|
|
||||||
@apply shadow-sm dark:shadow-none dark:border-border;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hover-effect {
|
|
||||||
@apply hover:bg-accent/10 dark:hover:bg-accent/20 transition-colors;
|
|
||||||
}
|
|
||||||
|
|
||||||
.border-subtle {
|
|
||||||
@apply border-border dark:border-border/50;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Apply rounded corners to common interactive elements by default */
|
|
||||||
button,
|
|
||||||
input,
|
|
||||||
textarea,
|
|
||||||
select,
|
|
||||||
[role="button"],
|
|
||||||
.card,
|
|
||||||
.input,
|
|
||||||
.select,
|
|
||||||
.textarea,
|
|
||||||
.button {
|
|
||||||
@apply !rounded-lg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
-webkit-transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, opacity 0.2s ease-in-out !important;
|
|
||||||
transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, opacity 0.2s ease-in-out !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
@apply transition-colors duration-200;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add Inter font */
|
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap');
|
|
||||||
|
|
||||||
/* Set base font */
|
|
||||||
html {
|
html {
|
||||||
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes slideUpAndFade {
|
body {
|
||||||
from {
|
background: var(--background);
|
||||||
opacity: 0;
|
color: var(--foreground);
|
||||||
transform: translateY(10px);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-slideUpAndFade {
|
|
||||||
animation: slideUpAndFade 0.2s ease-out forwards;
|
|
||||||
}
|
}
|
||||||
3
apps/rowboat/app/hero.ts
Normal file
3
apps/rowboat/app/hero.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
// hero.ts
|
||||||
|
import { heroui } from "@heroui/react";
|
||||||
|
export default heroui();
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
import { ThemeProvider } from "./providers/theme-provider";
|
import { ThemeProvider } from "./providers/theme-provider";
|
||||||
import { UserProvider } from '@auth0/nextjs-auth0/client';
|
|
||||||
import { Inter } from "next/font/google";
|
import { Inter } from "next/font/google";
|
||||||
import { Providers } from "./providers";
|
import { Providers } from "./providers";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
import { HelpModalProvider } from "./providers/help-modal-provider";
|
import { HelpModalProvider } from "./providers/help-modal-provider";
|
||||||
|
import { Auth0Provider } from "@auth0/nextjs-auth0";
|
||||||
|
|
||||||
const inter = Inter({ subsets: ["latin"] });
|
const inter = Inter({ subsets: ["latin"] });
|
||||||
|
|
||||||
|
|
@ -21,7 +21,7 @@ export default function RootLayout({
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
return <html lang="en" className="h-dvh">
|
return <html lang="en" className="h-dvh">
|
||||||
<UserProvider>
|
<Auth0Provider>
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
<body className={`${inter.className} h-full text-base [scrollbar-width:thin] bg-background`}>
|
<body className={`${inter.className} h-full text-base [scrollbar-width:thin] bg-background`}>
|
||||||
<Providers className='h-full flex flex-col'>
|
<Providers className='h-full flex flex-col'>
|
||||||
|
|
@ -31,6 +31,6 @@ export default function RootLayout({
|
||||||
</Providers>
|
</Providers>
|
||||||
</body>
|
</body>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</UserProvider>
|
</Auth0Provider>
|
||||||
</html>;
|
</html>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { Claims } from "@auth0/nextjs-auth0";
|
|
||||||
import { ObjectId } from "mongodb";
|
import { ObjectId } from "mongodb";
|
||||||
import { usersCollection, projectsCollection, projectMembersCollection } from "./mongodb";
|
import { usersCollection, projectsCollection, projectMembersCollection } from "./mongodb";
|
||||||
import { getSession } from "@auth0/nextjs-auth0";
|
import { auth0 } from "./auth0";
|
||||||
import { User, WithStringId } from "./types/types";
|
import { User, WithStringId } from "./types/types";
|
||||||
import { USE_AUTH } from "./feature_flags";
|
import { USE_AUTH } from "./feature_flags";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
export const GUEST_SESSION: Claims = {
|
export const GUEST_SESSION = {
|
||||||
email: "guest@rowboatlabs.com",
|
email: "guest@rowboatlabs.com",
|
||||||
email_verified: true,
|
email_verified: true,
|
||||||
sub: "guest_user",
|
sub: "guest_user",
|
||||||
|
|
@ -39,9 +38,9 @@ export async function requireAuth(): Promise<WithStringId<z.infer<typeof User>>>
|
||||||
return GUEST_DB_USER;
|
return GUEST_DB_USER;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user } = await getSession() || {};
|
const { user } = await auth0.getSession() || {};
|
||||||
if (!user) {
|
if (!user) {
|
||||||
redirect('/api/auth/login');
|
redirect('/auth/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch db user
|
// fetch db user
|
||||||
|
|
|
||||||
21
apps/rowboat/app/lib/auth0.ts
Normal file
21
apps/rowboat/app/lib/auth0.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
// lib/auth0.js
|
||||||
|
|
||||||
|
import { Auth0Client } from "@auth0/nextjs-auth0/server";
|
||||||
|
|
||||||
|
// Initialize the Auth0 client
|
||||||
|
export const auth0 = new Auth0Client({
|
||||||
|
// Options are loaded from environment variables by default
|
||||||
|
// Ensure necessary environment variables are properly set
|
||||||
|
domain: process.env.AUTH0_ISSUER_BASE_URL,
|
||||||
|
clientId: process.env.AUTH0_CLIENT_ID,
|
||||||
|
clientSecret: process.env.AUTH0_CLIENT_SECRET,
|
||||||
|
appBaseUrl: process.env.AUTH0_BASE_URL,
|
||||||
|
secret: process.env.AUTH0_SECRET,
|
||||||
|
|
||||||
|
authorizationParameters: {
|
||||||
|
// In v4, the AUTH0_SCOPE and AUTH0_AUDIENCE environment variables for API authorized applications are no longer automatically picked up by the SDK.
|
||||||
|
// Instead, we need to provide the values explicitly.
|
||||||
|
scope: process.env.AUTH0_SCOPE,
|
||||||
|
audience: process.env.AUTH0_AUDIENCE,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -3,7 +3,6 @@ import { z } from 'zod';
|
||||||
import { Customer, AuthorizeRequest, AuthorizeResponse, LogUsageRequest, UsageResponse, CustomerPortalSessionResponse, PricesResponse, UpdateSubscriptionPlanRequest, UpdateSubscriptionPlanResponse, ModelsResponse } from './types/billing_types';
|
import { Customer, AuthorizeRequest, AuthorizeResponse, LogUsageRequest, UsageResponse, CustomerPortalSessionResponse, PricesResponse, UpdateSubscriptionPlanRequest, UpdateSubscriptionPlanResponse, ModelsResponse } from './types/billing_types';
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import { projectsCollection, usersCollection } from './mongodb';
|
import { projectsCollection, usersCollection } from './mongodb';
|
||||||
import { getSession } from '@auth0/nextjs-auth0';
|
|
||||||
import { redirect } from 'next/navigation';
|
import { redirect } from 'next/navigation';
|
||||||
import { getUserFromSessionId, requireAuth } from './auth';
|
import { getUserFromSessionId, requireAuth } from './auth';
|
||||||
import { USE_BILLING } from './feature_flags';
|
import { USE_BILLING } from './feature_flags';
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ export default function MarkdownContent({
|
||||||
content: string;
|
content: string;
|
||||||
atValues?: Match[];
|
atValues?: Match[];
|
||||||
}) {
|
}) {
|
||||||
return <Markdown
|
return <div className="overflow-auto break-words">
|
||||||
className="overflow-auto break-words"
|
<Markdown
|
||||||
remarkPlugins={[remarkGfm]}
|
remarkPlugins={[remarkGfm]}
|
||||||
components={{
|
components={{
|
||||||
h1({ children }) {
|
h1({ children }) {
|
||||||
|
|
@ -107,5 +107,6 @@ export default function MarkdownContent({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{content}
|
{content}
|
||||||
</Markdown>;
|
</Markdown>
|
||||||
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
@import "../../globals.css";
|
||||||
|
|
||||||
/* Target both edit mode and view mode mentions */
|
/* Target both edit mode and view mode mentions */
|
||||||
.mention,
|
.mention,
|
||||||
.ql-editor p span[class*="bg-[#e"], /* Matches both #e8f2fe and #e0f2fe */
|
.ql-editor p span[class*="bg-[#e"], /* Matches both #e8f2fe and #e0f2fe */
|
||||||
|
|
@ -15,12 +17,12 @@ span[class*="bg-[#e"] { /* For view mode */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle Next.js dark mode class if needed */
|
/* Handle Next.js dark mode class if needed */
|
||||||
:global(.dark) .mention,
|
/* :global(.dark) .mention,
|
||||||
:global(.dark) .ql-editor p span[class*="bg-[#e"],
|
:global(.dark) .ql-editor p span[class*="bg-[#e"],
|
||||||
:global(.dark) span[class*="bg-[#e"] {
|
:global(.dark) span[class*="bg-[#e"] {
|
||||||
background-color: rgb(31 41 55) !important;
|
background-color: rgb(31 41 55) !important;
|
||||||
color: rgb(243 244 246) !important;
|
color: rgb(243 244 246) !important;
|
||||||
}
|
} */
|
||||||
|
|
||||||
/* Override the inline styles */
|
/* Override the inline styles */
|
||||||
.ql-editor p span[class*="bg-[#e0f2fe]"],
|
.ql-editor p span[class*="bg-[#e0f2fe]"],
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ export function ListItem({
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
rightElement?: React.ReactNode;
|
rightElement?: React.ReactNode;
|
||||||
selectedRef?: React.RefObject<HTMLButtonElement>;
|
selectedRef?: React.RefObject<HTMLButtonElement | null>;
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
'use client';
|
'use client';
|
||||||
import { useUser } from '@auth0/nextjs-auth0/client';
|
import { useUser } from '@auth0/nextjs-auth0';
|
||||||
import { Avatar, Dropdown, DropdownItem, DropdownSection, DropdownTrigger, DropdownMenu } from "@heroui/react";
|
import { Avatar, Dropdown, DropdownItem, DropdownSection, DropdownTrigger, DropdownMenu } from "@heroui/react";
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
'use client';
|
||||||
import { Spinner } from "@heroui/react";
|
import { Spinner } from "@heroui/react";
|
||||||
|
|
||||||
export default function Loading() {
|
export default function Loading() {
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ export function Section({
|
||||||
title: string;
|
title: string;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
return <div className="w-full flex flex-col gap-4 border border-border p-4 rounded-md">
|
return <div className="w-full flex flex-col gap-4 border border p-4 rounded-md">
|
||||||
<h2 className="font-semibold pb-2 border-b border-border">{title}</h2>
|
<h2 className="font-semibold pb-2 border-b border">{title}</h2>
|
||||||
{children}
|
{children}
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
@ -198,9 +198,9 @@ export function ApiKeysSection({
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
{loading && <Spinner size="sm" />}
|
{loading && <Spinner size="sm" />}
|
||||||
{!loading && <div className="border border-border rounded-lg text-sm">
|
{!loading && <div className="border border rounded-lg text-sm">
|
||||||
<div className="flex items-center border-b border-border p-4">
|
<div className="flex items-center border-b border p-4">
|
||||||
<div className="flex-[3] font-normal">API Key</div>
|
<div className="flex-3 font-normal">API Key</div>
|
||||||
<div className="flex-1 font-normal">Created</div>
|
<div className="flex-1 font-normal">Created</div>
|
||||||
<div className="flex-1 font-normal">Last Used</div>
|
<div className="flex-1 font-normal">Last Used</div>
|
||||||
<div className="w-10"></div>
|
<div className="w-10"></div>
|
||||||
|
|
@ -216,8 +216,8 @@ export function ApiKeysSection({
|
||||||
</div>}
|
</div>}
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
{keys.map((key) => (
|
{keys.map((key) => (
|
||||||
<div key={key._id} className="flex items-start border-b border-border last:border-b-0 p-4">
|
<div key={key._id} className="flex items-start border-b border last:border-b-0 p-4">
|
||||||
<div className="flex-[3] p-2">
|
<div className="flex-3 p-2">
|
||||||
<ApiKeyDisplay apiKey={key.key} />
|
<ApiKeyDisplay apiKey={key.key} />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 p-2">
|
<div className="flex-1 p-2">
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,14 @@ export const metadata: Metadata = {
|
||||||
title: "Project config",
|
title: "Project config",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function Page({
|
export default async function Page(
|
||||||
params,
|
props: {
|
||||||
}: {
|
params: Promise<{
|
||||||
params: {
|
|
||||||
projectId: string;
|
projectId: string;
|
||||||
};
|
}>;
|
||||||
}) {
|
}
|
||||||
|
) {
|
||||||
|
const params = await props.params;
|
||||||
await requireActiveBillingSubscription();
|
await requireActiveBillingSubscription();
|
||||||
return <App
|
return <App
|
||||||
projectId={params.projectId}
|
projectId={params.projectId}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ export default async function Layout({
|
||||||
params,
|
params,
|
||||||
children
|
children
|
||||||
}: {
|
}: {
|
||||||
params: { projectId: string }
|
params: Promise<{ projectId: string }>
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
}) {
|
}) {
|
||||||
return children;
|
return children;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { requireActiveBillingSubscription } from '@/app/lib/billing';
|
import { requireActiveBillingSubscription } from '@/app/lib/billing';
|
||||||
|
|
||||||
export default async function Page({
|
export default async function Page(
|
||||||
params
|
props: {
|
||||||
}: {
|
params: Promise<{ projectId: string }>
|
||||||
params: { projectId: string }
|
}
|
||||||
}) {
|
) {
|
||||||
|
const params = await props.params;
|
||||||
await requireActiveBillingSubscription();
|
await requireActiveBillingSubscription();
|
||||||
redirect(`/projects/${params.projectId}/workflow`);
|
redirect(`/projects/${params.projectId}/workflow`);
|
||||||
}
|
}
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
import { SourcePage } from "./source-page";
|
import { SourcePage } from "./source-page";
|
||||||
import { requireActiveBillingSubscription } from '@/app/lib/billing';
|
import { requireActiveBillingSubscription } from '@/app/lib/billing';
|
||||||
|
|
||||||
export default async function Page({
|
export default async function Page(
|
||||||
params,
|
props: {
|
||||||
}: {
|
params: Promise<{
|
||||||
params: {
|
|
||||||
projectId: string,
|
projectId: string,
|
||||||
sourceId: string
|
sourceId: string
|
||||||
|
}>
|
||||||
}
|
}
|
||||||
}) {
|
) {
|
||||||
|
const params = await props.params;
|
||||||
await requireActiveBillingSubscription();
|
await requireActiveBillingSubscription();
|
||||||
return <SourcePage projectId={params.projectId} sourceId={params.sourceId} />;
|
return <SourcePage projectId={params.projectId} sourceId={params.sourceId} />;
|
||||||
}
|
}
|
||||||
|
|
@ -37,7 +37,7 @@ export function SectionRow({ children, className }: { children: ReactNode; class
|
||||||
|
|
||||||
export function SectionLabel({ children, className }: { children: ReactNode; className?: string }) {
|
export function SectionLabel({ children, className }: { children: ReactNode; className?: string }) {
|
||||||
return (
|
return (
|
||||||
<div className={`w-24 flex-shrink-0 text-sm text-gray-500 dark:text-gray-400 ${className || ''}`}>
|
<div className={`w-24 shrink-0 text-sm text-gray-500 dark:text-gray-400 ${className || ''}`}>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export function SourceStatus({
|
||||||
|
|
||||||
{status === 'pending' && (
|
{status === 'pending' && (
|
||||||
<>
|
<>
|
||||||
<div className="flex-shrink-0">
|
<div className="shrink-0">
|
||||||
<Spinner size="sm" className="text-blue-500 dark:text-blue-400" />
|
<Spinner size="sm" className="text-blue-500 dark:text-blue-400" />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ export function ToggleSource({
|
||||||
onClick={handleToggle}
|
onClick={handleToggle}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
className={`
|
className={`
|
||||||
relative inline-flex h-5 w-9 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent
|
relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent
|
||||||
transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-500/20
|
transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-500/20
|
||||||
${isActive ? 'bg-indigo-500' : 'bg-gray-200 dark:bg-gray-700'}
|
${isActive ? 'bg-indigo-500' : 'bg-gray-200 dark:bg-gray-700'}
|
||||||
disabled:opacity-50 disabled:cursor-not-allowed
|
disabled:opacity-50 disabled:cursor-not-allowed
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,12 @@ export const metadata: Metadata = {
|
||||||
title: "Add data source"
|
title: "Add data source"
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function Page({
|
export default async function Page(
|
||||||
params
|
props: {
|
||||||
}: {
|
params: Promise<{ projectId: string }>
|
||||||
params: { projectId: string }
|
}
|
||||||
}) {
|
) {
|
||||||
|
const params = await props.params;
|
||||||
await requireActiveBillingSubscription();
|
await requireActiveBillingSubscription();
|
||||||
if (!USE_RAG) {
|
if (!USE_RAG) {
|
||||||
redirect(`/projects/${params.projectId}`);
|
redirect(`/projects/${params.projectId}`);
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,12 @@ export const metadata: Metadata = {
|
||||||
title: "Data sources",
|
title: "Data sources",
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function Page({
|
export default async function Page(
|
||||||
params,
|
props: {
|
||||||
}: {
|
params: Promise<{ projectId: string }>
|
||||||
params: { projectId: string }
|
}
|
||||||
}) {
|
) {
|
||||||
|
const params = await props.params;
|
||||||
await requireActiveBillingSubscription();
|
await requireActiveBillingSubscription();
|
||||||
return <SourcesList
|
return <SourcesList
|
||||||
projectId={params.projectId}
|
projectId={params.projectId}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ interface ProfileFormProps {
|
||||||
mockTools?: boolean;
|
mockTools?: boolean;
|
||||||
mockPrompt?: string;
|
mockPrompt?: string;
|
||||||
};
|
};
|
||||||
formRef: React.RefObject<HTMLFormElement>;
|
formRef: React.RefObject<HTMLFormElement | null>;
|
||||||
handleSubmit: (formData: FormData) => Promise<void>;
|
handleSubmit: (formData: FormData) => Promise<void>;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
submitButtonText: string;
|
submitButtonText: string;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { FormStatusButton } from "@/app/lib/components/form-status-button";
|
||||||
import { Button, Input, Textarea } from "@heroui/react";
|
import { Button, Input, Textarea } from "@heroui/react";
|
||||||
|
|
||||||
interface ScenarioFormProps {
|
interface ScenarioFormProps {
|
||||||
formRef: React.RefObject<HTMLFormElement>;
|
formRef: React.RefObject<HTMLFormElement | null>;
|
||||||
handleSubmit: (formData: FormData) => Promise<void>;
|
handleSubmit: (formData: FormData) => Promise<void>;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
submitButtonText: string;
|
submitButtonText: string;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import { ProfileSelector } from "@/app/projects/[projectId]/test/[[...slug]]/com
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
interface SimulationFormProps {
|
interface SimulationFormProps {
|
||||||
formRef: React.RefObject<HTMLFormElement>;
|
formRef: React.RefObject<HTMLFormElement | null>;
|
||||||
handleSubmit: (formData: FormData) => Promise<void>;
|
handleSubmit: (formData: FormData) => Promise<void>;
|
||||||
scenario: WithStringId<z.infer<typeof TestScenario>> | null;
|
scenario: WithStringId<z.infer<typeof TestScenario>> | null;
|
||||||
setScenario: (scenario: WithStringId<z.infer<typeof TestScenario>> | null) => void;
|
setScenario: (scenario: WithStringId<z.infer<typeof TestScenario>> | null) => void;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ import { RunsApp } from "./runs_app";
|
||||||
import { TestingMenu } from "./testing_menu";
|
import { TestingMenu } from "./testing_menu";
|
||||||
import { requireActiveBillingSubscription } from '@/app/lib/billing';
|
import { requireActiveBillingSubscription } from '@/app/lib/billing';
|
||||||
|
|
||||||
export default async function TestPage({ params }: { params: { projectId: string; slug?: string[] } }) {
|
export default async function TestPage(props: { params: Promise<{ projectId: string; slug?: string[] }> }) {
|
||||||
|
const params = await props.params;
|
||||||
await requireActiveBillingSubscription();
|
await requireActiveBillingSubscription();
|
||||||
const { projectId, slug = [] } = params;
|
const { projectId, slug = [] } = params;
|
||||||
let app: "scenarios" | "simulations" | "profiles" | "runs" = "runs";
|
let app: "scenarios" | "simulations" | "profiles" | "runs" = "runs";
|
||||||
|
|
|
||||||
|
|
@ -295,7 +295,7 @@ export function CustomServers() {
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="bg-blue-50 dark:bg-blue-900/20 border border-blue-100 dark:border-blue-800 rounded-lg p-4">
|
<div className="bg-blue-50 dark:bg-blue-900/20 border border-blue-100 dark:border-blue-800 rounded-lg p-4">
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<div className="flex-shrink-0">
|
<div className="shrink-0">
|
||||||
<Info className="h-5 w-5 text-blue-600 dark:text-blue-400" />
|
<Info className="h-5 w-5 text-blue-600 dark:text-blue-400" />
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-blue-700 dark:text-blue-300">
|
<p className="text-sm text-blue-700 dark:text-blue-300">
|
||||||
|
|
|
||||||
|
|
@ -578,7 +578,7 @@ export function HostedServers({ onSwitchTab }: HostedServersProps) {
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div className="bg-blue-50 dark:bg-blue-900/20 border border-blue-100 dark:border-blue-800 rounded-lg p-4">
|
<div className="bg-blue-50 dark:bg-blue-900/20 border border-blue-100 dark:border-blue-800 rounded-lg p-4">
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<div className="flex-shrink-0">
|
<div className="shrink-0">
|
||||||
<Info className="h-5 w-5 text-blue-600 dark:text-blue-400" />
|
<Info className="h-5 w-5 text-blue-600 dark:text-blue-400" />
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-blue-700 dark:text-blue-300">
|
<p className="text-sm text-blue-700 dark:text-blue-300">
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ export function TestToolModal({ isOpen, onClose, tool, server }: TestToolModalPr
|
||||||
value={item || ''}
|
value={item || ''}
|
||||||
onChange={(e) => handleArrayItemChange(index, e.target.value)}
|
onChange={(e) => handleArrayItemChange(index, e.target.value)}
|
||||||
placeholder="Enter value"
|
placeholder="Enter value"
|
||||||
className="focus:ring-0 focus:ring-offset-0 !ring-0 !ring-offset-0 focus:outline-none"
|
className="focus:ring-0 focus:ring-offset-0 ring-0! ring-offset-0! focus:outline-none"
|
||||||
/>
|
/>
|
||||||
) : itemSchema.type === 'number' || itemSchema.type === 'integer' ? (
|
) : itemSchema.type === 'number' || itemSchema.type === 'integer' ? (
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -209,7 +209,7 @@ export function TestToolModal({ isOpen, onClose, tool, server }: TestToolModalPr
|
||||||
handleArrayItemChange(index, isNaN(val) ? '' : val);
|
handleArrayItemChange(index, isNaN(val) ? '' : val);
|
||||||
}}
|
}}
|
||||||
placeholder="Enter value"
|
placeholder="Enter value"
|
||||||
className="focus:ring-0 focus:ring-offset-0 !ring-0 !ring-offset-0 focus:outline-none"
|
className="focus:ring-0 focus:ring-offset-0 ring-0! ring-offset-0! focus:outline-none"
|
||||||
/>
|
/>
|
||||||
) : itemSchema.type === 'boolean' ? (
|
) : itemSchema.type === 'boolean' ? (
|
||||||
<div className="scale-75 origin-left">
|
<div className="scale-75 origin-left">
|
||||||
|
|
@ -284,7 +284,7 @@ export function TestToolModal({ isOpen, onClose, tool, server }: TestToolModalPr
|
||||||
className="w-full px-3 py-2 text-sm border border-gray-200 dark:border-gray-700 rounded-md
|
className="w-full px-3 py-2 text-sm border border-gray-200 dark:border-gray-700 rounded-md
|
||||||
bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100
|
bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100
|
||||||
focus:outline-none hover:border-gray-300 dark:hover:border-gray-600
|
focus:outline-none hover:border-gray-300 dark:hover:border-gray-600
|
||||||
focus:ring-0 focus:ring-offset-0 !ring-0 !ring-offset-0"
|
focus:ring-0 focus:ring-offset-0 ring-0! ring-offset-0!"
|
||||||
>
|
>
|
||||||
<option value="" disabled>Select {paramName}</option>
|
<option value="" disabled>Select {paramName}</option>
|
||||||
{schema.enum.map((opt: string) => (
|
{schema.enum.map((opt: string) => (
|
||||||
|
|
@ -299,7 +299,7 @@ export function TestToolModal({ isOpen, onClose, tool, server }: TestToolModalPr
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(e) => handleParameterChange(paramName, e.target.value)}
|
onChange={(e) => handleParameterChange(paramName, e.target.value)}
|
||||||
className="focus:ring-0 focus:ring-offset-0 !ring-0 !ring-offset-0 focus:outline-none"
|
className="focus:ring-0 focus:ring-offset-0 ring-0! ring-offset-0! focus:outline-none"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -309,7 +309,7 @@ export function TestToolModal({ isOpen, onClose, tool, server }: TestToolModalPr
|
||||||
type="date"
|
type="date"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(e) => handleParameterChange(paramName, e.target.value)}
|
onChange={(e) => handleParameterChange(paramName, e.target.value)}
|
||||||
className="focus:ring-0 focus:ring-offset-0 !ring-0 !ring-offset-0 focus:outline-none"
|
className="focus:ring-0 focus:ring-offset-0 ring-0! ring-offset-0! focus:outline-none"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -319,7 +319,7 @@ export function TestToolModal({ isOpen, onClose, tool, server }: TestToolModalPr
|
||||||
type="time"
|
type="time"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(e) => handleParameterChange(paramName, e.target.value)}
|
onChange={(e) => handleParameterChange(paramName, e.target.value)}
|
||||||
className="focus:ring-0 focus:ring-offset-0 !ring-0 !ring-offset-0 focus:outline-none"
|
className="focus:ring-0 focus:ring-offset-0 ring-0! ring-offset-0! focus:outline-none"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -329,7 +329,7 @@ export function TestToolModal({ isOpen, onClose, tool, server }: TestToolModalPr
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(e) => handleParameterChange(paramName, e.target.value)}
|
onChange={(e) => handleParameterChange(paramName, e.target.value)}
|
||||||
placeholder={`Enter ${paramName}`}
|
placeholder={`Enter ${paramName}`}
|
||||||
className="focus:ring-0 focus:ring-offset-0 !ring-0 !ring-offset-0 focus:outline-none"
|
className="focus:ring-0 focus:ring-offset-0 ring-0! ring-offset-0! focus:outline-none"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -349,7 +349,7 @@ export function TestToolModal({ isOpen, onClose, tool, server }: TestToolModalPr
|
||||||
handleParameterChange(paramName, isNaN(val) ? '' : val);
|
handleParameterChange(paramName, isNaN(val) ? '' : val);
|
||||||
}}
|
}}
|
||||||
placeholder={`Enter ${paramName}`}
|
placeholder={`Enter ${paramName}`}
|
||||||
className="focus:ring-0 focus:ring-offset-0 !ring-0 !ring-offset-0 focus:outline-none"
|
className="focus:ring-0 focus:ring-offset-0 ring-0! ring-offset-0! focus:outline-none"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -377,7 +377,7 @@ export function TestToolModal({ isOpen, onClose, tool, server }: TestToolModalPr
|
||||||
value={value}
|
value={value}
|
||||||
onChange={(e) => handleParameterChange(paramName, e.target.value)}
|
onChange={(e) => handleParameterChange(paramName, e.target.value)}
|
||||||
placeholder={`Enter ${paramName}`}
|
placeholder={`Enter ${paramName}`}
|
||||||
className="focus:ring-0 focus:ring-offset-0 !ring-0 !ring-offset-0 focus:outline-none"
|
className="focus:ring-0 focus:ring-offset-0 ring-0! ring-offset-0! focus:outline-none"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ export function ToolsConfig() {
|
||||||
<Tab key="hosted" title={
|
<Tab key="hosted" title={
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span>Tools Library</span>
|
<span>Tools Library</span>
|
||||||
<span className="leading-none px-1.5 py-[2px] text-[9px] font-medium bg-gradient-to-r from-pink-500 to-violet-500 text-white rounded-full">
|
<span className="leading-none px-1.5 py-[2px] text-[9px] font-medium bg-linear-to-r from-pink-500 to-violet-500 text-white rounded-full">
|
||||||
BETA
|
BETA
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ function Section({ title, children, description }: {
|
||||||
|
|
||||||
export function WebhookConfig() {
|
export function WebhookConfig() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const projectId = typeof params.projectId === 'string' ? params.projectId : params.projectId[0];
|
const projectId = params.projectId ? (typeof params.projectId === 'string' ? params.projectId : params.projectId[0]) : '';
|
||||||
|
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [webhookUrl, setWebhookUrl] = useState<string | null>(null);
|
const [webhookUrl, setWebhookUrl] = useState<string | null>(null);
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ const ListItemWithMenu = ({
|
||||||
isSelected?: boolean;
|
isSelected?: boolean;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
selectedRef?: React.RefObject<HTMLButtonElement>;
|
selectedRef?: React.RefObject<HTMLButtonElement | null>;
|
||||||
menuContent: React.ReactNode;
|
menuContent: React.ReactNode;
|
||||||
statusLabel?: React.ReactNode;
|
statusLabel?: React.ReactNode;
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
|
|
@ -111,7 +111,7 @@ const ListItemWithMenu = ({
|
||||||
}}
|
}}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<div className={clsx("flex-shrink-0 flex items-center justify-center w-4 h-4", iconClassName)}>
|
<div className={clsx("shrink-0 flex items-center justify-center w-4 h-4", iconClassName)}>
|
||||||
{mcpServerName ? (
|
{mcpServerName ? (
|
||||||
<ServerLogo
|
<ServerLogo
|
||||||
serverName={mcpServerName}
|
serverName={mcpServerName}
|
||||||
|
|
@ -147,7 +147,7 @@ interface ServerCardProps {
|
||||||
} | null;
|
} | null;
|
||||||
onSelectTool: (name: string) => void;
|
onSelectTool: (name: string) => void;
|
||||||
onDeleteTool: (name: string) => void;
|
onDeleteTool: (name: string) => void;
|
||||||
selectedRef: React.RefObject<HTMLButtonElement>;
|
selectedRef: React.RefObject<HTMLButtonElement | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ServerCard = ({
|
const ServerCard = ({
|
||||||
|
|
@ -343,7 +343,7 @@ export function EntityList({
|
||||||
tourTarget="entity-agents"
|
tourTarget="entity-agents"
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"h-full overflow-hidden",
|
"h-full overflow-hidden",
|
||||||
!expandedPanels.agents && "!h-[53px]"
|
!expandedPanels.agents && "h-[53px]!"
|
||||||
)}
|
)}
|
||||||
title={
|
title={
|
||||||
<button
|
<button
|
||||||
|
|
@ -429,7 +429,7 @@ export function EntityList({
|
||||||
tourTarget="entity-tools"
|
tourTarget="entity-tools"
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"h-full overflow-hidden",
|
"h-full overflow-hidden",
|
||||||
!expandedPanels.tools && "!h-[53px]"
|
!expandedPanels.tools && "h-[53px]!"
|
||||||
)}
|
)}
|
||||||
title={
|
title={
|
||||||
<button
|
<button
|
||||||
|
|
@ -549,7 +549,7 @@ export function EntityList({
|
||||||
tourTarget="entity-prompts"
|
tourTarget="entity-prompts"
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"h-full overflow-hidden",
|
"h-full overflow-hidden",
|
||||||
!expandedPanels.prompts && "!h-[53px]"
|
!expandedPanels.prompts && "h-[53px]!"
|
||||||
)}
|
)}
|
||||||
title={
|
title={
|
||||||
<button
|
<button
|
||||||
|
|
@ -696,7 +696,7 @@ const SortableAgentItem = ({ agent, isSelected, onClick, selectedRef, statusLabe
|
||||||
agent: z.infer<typeof WorkflowAgent>;
|
agent: z.infer<typeof WorkflowAgent>;
|
||||||
isSelected?: boolean;
|
isSelected?: boolean;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
selectedRef?: React.RefObject<HTMLButtonElement>;
|
selectedRef?: React.RefObject<HTMLButtonElement | null>;
|
||||||
statusLabel?: React.ReactNode;
|
statusLabel?: React.ReactNode;
|
||||||
onToggle: (name: string) => void;
|
onToggle: (name: string) => void;
|
||||||
onSetMainAgent: (name: string) => void;
|
onSetMainAgent: (name: string) => void;
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,12 @@ export const metadata: Metadata = {
|
||||||
title: "Workflow"
|
title: "Workflow"
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function Page({
|
export default async function Page(
|
||||||
params,
|
props: {
|
||||||
}: {
|
params: Promise<{ projectId: string }>;
|
||||||
params: { projectId: string };
|
}
|
||||||
}) {
|
) {
|
||||||
|
const params = await props.params;
|
||||||
await requireActiveBillingSubscription();
|
await requireActiveBillingSubscription();
|
||||||
console.log('->>> workflow page being rendered');
|
console.log('->>> workflow page being rendered');
|
||||||
const project = await projectsCollection.findOne({
|
const project = await projectsCollection.findOne({
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ function PreviewModal({
|
||||||
</div>}
|
</div>}
|
||||||
{view === 'markdown' && <div className="flex gap-1">
|
{view === 'markdown' && <div className="flex gap-1">
|
||||||
{oldValue !== undefined && <div className="w-1/2 flex flex-col border-r-2 border-gray-200 overflow-auto">
|
{oldValue !== undefined && <div className="w-1/2 flex flex-col border-r-2 border-gray-200 overflow-auto">
|
||||||
<div className="text-gray-800 font-semibold italic text-sm px-2 py-1 border-b-1 border-gray-200">Old</div>
|
<div className="text-gray-800 font-semibold italic text-sm px-2 py-1 border-b border-gray-200">Old</div>
|
||||||
<div className="p-2 overflow-auto">
|
<div className="p-2 overflow-auto">
|
||||||
<MarkdownContent
|
<MarkdownContent
|
||||||
content={oldValue}
|
content={oldValue}
|
||||||
|
|
@ -158,7 +158,7 @@ function PreviewModal({
|
||||||
<div className={clsx("flex flex-col", {
|
<div className={clsx("flex flex-col", {
|
||||||
'w-1/2': oldValue !== undefined
|
'w-1/2': oldValue !== undefined
|
||||||
})}>
|
})}>
|
||||||
{oldValue !== undefined && <div className="text-gray-800 font-semibold italic text-sm px-2 py-1 border-b-1 border-gray-200">New</div>}
|
{oldValue !== undefined && <div className="text-gray-800 font-semibold italic text-sm px-2 py-1 border-b border-gray-200">New</div>}
|
||||||
<div className="p-2 overflow-auto">
|
<div className="p-2 overflow-auto">
|
||||||
<MarkdownContent
|
<MarkdownContent
|
||||||
content={newValue}
|
content={newValue}
|
||||||
|
|
|
||||||
|
|
@ -580,7 +580,7 @@ export function WorkflowEditor({
|
||||||
eligibleModels: z.infer<typeof ModelsResponse> | "*";
|
eligibleModels: z.infer<typeof ModelsResponse> | "*";
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
const [state, dispatch] = useReducer<Reducer<State, Action>>(reducer, {
|
const [state, dispatch] = useReducer(reducer, {
|
||||||
patches: [],
|
patches: [],
|
||||||
inversePatches: [],
|
inversePatches: [],
|
||||||
currentIndex: 0,
|
currentIndex: 0,
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,20 @@
|
||||||
import Link from "next/link";
|
|
||||||
import { LucideIcon } from "lucide-react";
|
import { LucideIcon } from "lucide-react";
|
||||||
|
|
||||||
interface MenuItemProps {
|
interface MenuItemProps {
|
||||||
href?: string;
|
|
||||||
icon: LucideIcon;
|
icon: LucideIcon;
|
||||||
selected?: boolean;
|
selected?: boolean;
|
||||||
collapsed?: boolean;
|
collapsed?: boolean;
|
||||||
onClick?: () => void;
|
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MenuItem({
|
export default function MenuItem({
|
||||||
href,
|
|
||||||
icon: Icon,
|
icon: Icon,
|
||||||
selected = false,
|
selected = false,
|
||||||
collapsed = false,
|
collapsed = false,
|
||||||
onClick,
|
|
||||||
children
|
children
|
||||||
}: MenuItemProps) {
|
}: MenuItemProps) {
|
||||||
const ButtonContent = (
|
return (
|
||||||
<button
|
<div
|
||||||
onClick={onClick}
|
|
||||||
className={`
|
className={`
|
||||||
w-full px-3 py-2 rounded-md flex items-center gap-3
|
w-full px-3 py-2 rounded-md flex items-center gap-3
|
||||||
text-sm font-medium transition-all duration-200
|
text-sm font-medium transition-all duration-200
|
||||||
|
|
@ -32,12 +26,6 @@ export default function MenuItem({
|
||||||
>
|
>
|
||||||
<Icon size={16} />
|
<Icon size={16} />
|
||||||
{!collapsed && children}
|
{!collapsed && children}
|
||||||
</button>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (href) {
|
|
||||||
return <Link href={href}>{ButtonContent}</Link>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ButtonContent;
|
|
||||||
}
|
}
|
||||||
|
|
@ -98,7 +98,7 @@ export default function Sidebar({ projectId, useRag, useAuth, collapsed = false,
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<aside className={`${collapsed ? 'w-16' : 'w-60'} bg-transparent flex flex-col h-full transition-all duration-300`}>
|
<aside className={`${collapsed ? 'w-16' : 'w-60'} bg-transparent flex flex-col h-full transition-all duration-300`}>
|
||||||
<div className="flex flex-col flex-grow">
|
<div className="flex flex-col grow">
|
||||||
{!isProjectsRoute && (
|
{!isProjectsRoute && (
|
||||||
<>
|
<>
|
||||||
{/* Project Selector */}
|
{/* Project Selector */}
|
||||||
|
|
@ -141,9 +141,6 @@ export default function Sidebar({ projectId, useRag, useAuth, collapsed = false,
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
href={isDisabled ? '#' : fullPath}
|
href={isDisabled ? '#' : fullPath}
|
||||||
className={isDisabled ? 'pointer-events-none' : ''}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className={`
|
className={`
|
||||||
relative w-full rounded-md flex items-center
|
relative w-full rounded-md flex items-center
|
||||||
text-[15px] font-medium transition-all duration-200
|
text-[15px] font-medium transition-all duration-200
|
||||||
|
|
@ -154,8 +151,8 @@ export default function Sidebar({ projectId, useRag, useAuth, collapsed = false,
|
||||||
? 'text-zinc-300 dark:text-zinc-600 cursor-not-allowed'
|
? 'text-zinc-300 dark:text-zinc-600 cursor-not-allowed'
|
||||||
: 'text-zinc-600 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800/50 hover:text-zinc-900 dark:hover:text-zinc-300'
|
: 'text-zinc-600 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800/50 hover:text-zinc-900 dark:hover:text-zinc-300'
|
||||||
}
|
}
|
||||||
|
${isDisabled ? 'pointer-events-none' : ''}
|
||||||
`}
|
`}
|
||||||
disabled={isDisabled}
|
|
||||||
data-tour-target={item.href === 'config' ? 'settings' : item.href === 'sources' ? 'entity-data-sources' : undefined}
|
data-tour-target={item.href === 'config' ? 'settings' : item.href === 'sources' ? 'entity-data-sources' : undefined}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
|
|
@ -174,13 +171,12 @@ export default function Sidebar({ projectId, useRag, useAuth, collapsed = false,
|
||||||
<>
|
<>
|
||||||
<span>{item.label}</span>
|
<span>{item.label}</span>
|
||||||
{item.beta && (
|
{item.beta && (
|
||||||
<span className="ml-1.5 leading-none px-1.5 py-[2px] text-[9px] font-medium bg-gradient-to-r from-pink-500 to-violet-500 text-white rounded-full">
|
<span className="ml-1.5 leading-none px-1.5 py-[2px] text-[9px] font-medium bg-linear-to-r from-pink-500 to-violet-500 text-white rounded-full">
|
||||||
BETA
|
BETA
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</button>
|
|
||||||
</Link>
|
</Link>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ export function Nav({
|
||||||
setCollapsed(!collapsed);
|
setCollapsed(!collapsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className={clsx("shrink-0 flex flex-col gap-2 border-r border-border relative p-2", {
|
return <div className={clsx("shrink-0 flex flex-col gap-2 border-r border relative p-2", {
|
||||||
"w-40": !collapsed,
|
"w-40": !collapsed,
|
||||||
"w-10": collapsed
|
"w-10": collapsed
|
||||||
})}>
|
})}>
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ export function SearchInput({
|
||||||
tokens.colors.dark.text.primary,
|
tokens.colors.dark.text.primary,
|
||||||
"placeholder:text-gray-400 dark:placeholder:text-gray-500",
|
"placeholder:text-gray-400 dark:placeholder:text-gray-500",
|
||||||
"border border-gray-200 dark:border-gray-700",
|
"border border-gray-200 dark:border-gray-700",
|
||||||
"focus:ring-2 focus:ring-indigo-500 focus:ring-opacity-50",
|
"focus:ring-2 focus:ring-indigo-500/50",
|
||||||
"focus:border-transparent"
|
"focus:border-transparent"
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
@ -66,7 +66,7 @@ export function SearchInput({
|
||||||
? "bg-indigo-600 text-white"
|
? "bg-indigo-600 text-white"
|
||||||
: "bg-gray-50 dark:bg-gray-800 text-gray-600 dark:text-gray-400",
|
: "bg-gray-50 dark:bg-gray-800 text-gray-600 dark:text-gray-400",
|
||||||
"hover:bg-gray-100 dark:hover:bg-gray-700",
|
"hover:bg-gray-100 dark:hover:bg-gray-700",
|
||||||
"focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-opacity-50"
|
"focus:outline-none focus:ring-2 focus:ring-indigo-500/50"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{filter.charAt(0).toUpperCase() + filter.slice(1)}
|
{filter.charAt(0).toUpperCase() + filter.slice(1)}
|
||||||
|
|
|
||||||
|
|
@ -99,8 +99,8 @@ export function ComposeBoxCopilot({
|
||||||
autoResize={true}
|
autoResize={true}
|
||||||
maxHeight={120}
|
maxHeight={120}
|
||||||
className={`
|
className={`
|
||||||
!min-h-0
|
min-h-0!
|
||||||
!border-0 !shadow-none !ring-0
|
border-0! shadow-none! ring-0!
|
||||||
bg-transparent
|
bg-transparent
|
||||||
resize-none
|
resize-none
|
||||||
overflow-y-auto
|
overflow-y-auto
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,8 @@ export function ComposeBoxPlayground({
|
||||||
autoResize={true}
|
autoResize={true}
|
||||||
maxHeight={120}
|
maxHeight={120}
|
||||||
className={`
|
className={`
|
||||||
!min-h-0
|
min-h-0!
|
||||||
!border-0 !shadow-none !ring-0
|
border-0! shadow-none! ring-0!
|
||||||
bg-transparent
|
bg-transparent
|
||||||
resize-none
|
resize-none
|
||||||
overflow-y-auto
|
overflow-y-auto
|
||||||
|
|
|
||||||
|
|
@ -93,8 +93,8 @@ export function ComposeBox({
|
||||||
autoResize={true}
|
autoResize={true}
|
||||||
maxHeight={120}
|
maxHeight={120}
|
||||||
className={`
|
className={`
|
||||||
!min-h-0
|
min-h-0!
|
||||||
!border-0 !shadow-none !ring-0
|
border-0! shadow-none! ring-0!
|
||||||
bg-transparent
|
bg-transparent
|
||||||
resize-none
|
resize-none
|
||||||
overflow-y-auto
|
overflow-y-auto
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ export function HelpModal({ isOpen, onClose, onStartTour }: HelpModalProps) {
|
||||||
if (!isOpen) return null;
|
if (!isOpen) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm z-[100] flex items-center justify-center">
|
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm z-100 flex items-center justify-center">
|
||||||
<div className="bg-white dark:bg-zinc-800 rounded-lg shadow-lg p-6 w-[480px] max-w-[90vw] animate-in fade-in duration-200">
|
<div className="bg-white dark:bg-zinc-800 rounded-lg shadow-lg p-6 w-[480px] max-w-[90vw] animate-in fade-in duration-200">
|
||||||
<h2 className="text-xl font-semibold text-gray-900 dark:text-gray-100 mb-6">
|
<h2 className="text-xl font-semibold text-gray-900 dark:text-gray-100 mb-6">
|
||||||
Need Help?
|
Need Help?
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ export function Panel({
|
||||||
"flex flex-col overflow-hidden rounded-xl border relative",
|
"flex flex-col overflow-hidden rounded-xl border relative",
|
||||||
variant === 'copilot' ? "border-blue-200 dark:border-blue-800" : "border-zinc-200 dark:border-zinc-800",
|
variant === 'copilot' ? "border-blue-200 dark:border-blue-800" : "border-zinc-200 dark:border-zinc-800",
|
||||||
"bg-white dark:bg-zinc-900",
|
"bg-white dark:bg-zinc-900",
|
||||||
maxHeight ? "max-h-[var(--panel-height)]" : "h-full",
|
maxHeight ? "max-h-(--panel-height)" : "h-full",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ function TourBackdrop({ targetElement }: { targetElement: Element | null }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* Top */}
|
{/* Top */}
|
||||||
<div className="fixed z-[100] backdrop-blur-sm bg-black/30" style={{
|
<div className="fixed z-100 backdrop-blur-sm bg-black/30" style={{
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
|
|
@ -97,7 +97,7 @@ function TourBackdrop({ targetElement }: { targetElement: Element | null }) {
|
||||||
}} />
|
}} />
|
||||||
|
|
||||||
{/* Left */}
|
{/* Left */}
|
||||||
<div className="fixed z-[100] backdrop-blur-sm bg-black/30" style={{
|
<div className="fixed z-100 backdrop-blur-sm bg-black/30" style={{
|
||||||
top: Math.max(0, rect.top - padding),
|
top: Math.max(0, rect.top - padding),
|
||||||
left: 0,
|
left: 0,
|
||||||
width: Math.max(0, rect.left - padding),
|
width: Math.max(0, rect.left - padding),
|
||||||
|
|
@ -105,7 +105,7 @@ function TourBackdrop({ targetElement }: { targetElement: Element | null }) {
|
||||||
}} />
|
}} />
|
||||||
|
|
||||||
{/* Right */}
|
{/* Right */}
|
||||||
<div className="fixed z-[100] backdrop-blur-sm bg-black/30" style={{
|
<div className="fixed z-100 backdrop-blur-sm bg-black/30" style={{
|
||||||
top: Math.max(0, rect.top - padding),
|
top: Math.max(0, rect.top - padding),
|
||||||
left: rect.right + padding,
|
left: rect.right + padding,
|
||||||
right: 0,
|
right: 0,
|
||||||
|
|
@ -113,7 +113,7 @@ function TourBackdrop({ targetElement }: { targetElement: Element | null }) {
|
||||||
}} />
|
}} />
|
||||||
|
|
||||||
{/* Bottom */}
|
{/* Bottom */}
|
||||||
<div className="fixed z-[100] backdrop-blur-sm bg-black/30" style={{
|
<div className="fixed z-100 backdrop-blur-sm bg-black/30" style={{
|
||||||
top: rect.bottom + padding,
|
top: rect.bottom + padding,
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
|
|
@ -122,7 +122,7 @@ function TourBackdrop({ targetElement }: { targetElement: Element | null }) {
|
||||||
|
|
||||||
{/* Highlight border around target */}
|
{/* Highlight border around target */}
|
||||||
<div
|
<div
|
||||||
className="fixed z-[100] border-2 border-white/50 rounded-lg pointer-events-none"
|
className="fixed z-100 border-2 border-white/50 rounded-lg pointer-events-none"
|
||||||
style={{
|
style={{
|
||||||
top: rect.top - padding,
|
top: rect.top - padding,
|
||||||
left: rect.left - padding,
|
left: rect.left - padding,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { useEffect, RefObject } from 'react';
|
import { useEffect, RefObject } from 'react';
|
||||||
|
|
||||||
export function useClickAway(
|
export function useClickAway(
|
||||||
ref: RefObject<HTMLElement>,
|
ref: RefObject<HTMLElement | null>,
|
||||||
handler: (event: MouseEvent | TouchEvent) => void
|
handler: (event: MouseEvent | TouchEvent) => void
|
||||||
) {
|
) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,20 @@
|
||||||
import { NextFetchEvent, NextRequest, NextResponse } from "next/server";
|
import { NextFetchEvent, NextRequest, NextResponse } from "next/server";
|
||||||
import { withMiddlewareAuthRequired } from "@auth0/nextjs-auth0/edge";
|
import { auth0 } from "./app/lib/auth0";
|
||||||
|
|
||||||
const corsOptions = {
|
const corsOptions = {
|
||||||
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
||||||
'Access-Control-Allow-Headers': 'Content-Type, x-client-id, Authorization',
|
'Access-Control-Allow-Headers': 'Content-Type, x-client-id, Authorization',
|
||||||
}
|
}
|
||||||
|
|
||||||
const auth0MiddlewareHandler = withMiddlewareAuthRequired();
|
|
||||||
|
|
||||||
export async function middleware(request: NextRequest, event: NextFetchEvent) {
|
export async function middleware(request: NextRequest, event: NextFetchEvent) {
|
||||||
|
const authRes = await auth0.middleware(request);
|
||||||
|
|
||||||
|
// Check if the request path starts with /api/auth/
|
||||||
|
if (request.nextUrl.pathname.startsWith('/auth')) {
|
||||||
|
return authRes;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the request path starts with /api/
|
// Check if the request path starts with /api/
|
||||||
if (request.nextUrl.pathname.startsWith('/api/')) {
|
if (request.nextUrl.pathname.startsWith('/api/')) {
|
||||||
// Handle preflighted requests
|
// Handle preflighted requests
|
||||||
|
|
@ -37,10 +43,9 @@ export async function middleware(request: NextRequest, event: NextFetchEvent) {
|
||||||
request.nextUrl.pathname.startsWith('/billing') ||
|
request.nextUrl.pathname.startsWith('/billing') ||
|
||||||
request.nextUrl.pathname.startsWith('/onboarding')) {
|
request.nextUrl.pathname.startsWith('/onboarding')) {
|
||||||
// Skip auth check if USE_AUTH is not enabled
|
// Skip auth check if USE_AUTH is not enabled
|
||||||
if (process.env.USE_AUTH !== 'true') {
|
if (process.env.USE_AUTH === 'true') {
|
||||||
return NextResponse.next();
|
return authRes;
|
||||||
}
|
}
|
||||||
return auth0MiddlewareHandler(request, event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextResponse.next();
|
return NextResponse.next();
|
||||||
|
|
@ -48,10 +53,12 @@ export async function middleware(request: NextRequest, event: NextFetchEvent) {
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
matcher: [
|
matcher: [
|
||||||
'/projects/:path*',
|
/*
|
||||||
'/billing/:path*',
|
* Match all request paths except for the ones starting with:
|
||||||
// '/onboarding/:path*',
|
* - _next/static (static files)
|
||||||
'/api/v1/:path*',
|
* - _next/image (image optimization files)
|
||||||
'/api/widget/v1/:path*',
|
* - favicon.ico, sitemap.xml, robots.txt (metadata files)
|
||||||
|
*/
|
||||||
|
"/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)",
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
15611
apps/rowboat/package-lock.json
generated
15611
apps/rowboat/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -4,7 +4,7 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev --turbopack",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/openai": "^1.3.21",
|
"@ai-sdk/openai": "^1.3.21",
|
||||||
"@auth0/nextjs-auth0": "^3.5.0",
|
"@auth0/nextjs-auth0": "^4.7.0",
|
||||||
"@aws-sdk/client-s3": "^3.743.0",
|
"@aws-sdk/client-s3": "^3.743.0",
|
||||||
"@aws-sdk/s3-request-presigner": "^3.743.0",
|
"@aws-sdk/s3-request-presigner": "^3.743.0",
|
||||||
"@dnd-kit/core": "^6.3.1",
|
"@dnd-kit/core": "^6.3.1",
|
||||||
|
|
@ -25,14 +25,14 @@
|
||||||
"@floating-ui/react": "^0.27.7",
|
"@floating-ui/react": "^0.27.7",
|
||||||
"@google/generative-ai": "^0.21.0",
|
"@google/generative-ai": "^0.21.0",
|
||||||
"@heroicons/react": "^2.2.0",
|
"@heroicons/react": "^2.2.0",
|
||||||
"@heroui/react": "2.7.4",
|
"@heroui/react": "^2.8.0-beta.10",
|
||||||
"@heroui/system": "2.4.11",
|
"@heroui/system": "^2.4.18-beta.2",
|
||||||
"@heroui/theme": "2.4.11",
|
"@heroui/theme": "^2.4.18-beta.2",
|
||||||
"@langchain/core": "^0.3.7",
|
"@langchain/core": "^0.3.7",
|
||||||
"@langchain/textsplitters": "^0.1.0",
|
"@langchain/textsplitters": "^0.1.0",
|
||||||
"@mendable/firecrawl-js": "^1.0.3",
|
"@mendable/firecrawl-js": "^1.0.3",
|
||||||
"@modelcontextprotocol/sdk": "^1.12.1",
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
||||||
"@primer/react": "^36.27.0",
|
"@primer/react": "^37.27.0",
|
||||||
"@qdrant/js-client-rest": "^1.13.0",
|
"@qdrant/js-client-rest": "^1.13.0",
|
||||||
"ai": "^4.3.13",
|
"ai": "^4.3.13",
|
||||||
"cheerio": "^1.0.0",
|
"cheerio": "^1.0.0",
|
||||||
|
|
@ -41,24 +41,24 @@
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"eventsource-parser": "^3.0.2",
|
"eventsource-parser": "^3.0.2",
|
||||||
"framer-motion": "^11.5.4",
|
"framer-motion": "^12.19.1",
|
||||||
"fuse.js": "^7.1.0",
|
"fuse.js": "^7.1.0",
|
||||||
"immer": "^10.1.1",
|
"immer": "^10.1.1",
|
||||||
"jose": "^5.9.6",
|
"jose": "^5.9.6",
|
||||||
"lucide-react": "^0.465.0",
|
"lucide-react": "^0.465.0",
|
||||||
"mongodb": "^6.8.0",
|
"mongodb": "^6.8.0",
|
||||||
"next": "^14.2.25",
|
"next": "15.3.4",
|
||||||
"openai": "^4.67.2",
|
"openai": "^4.67.2",
|
||||||
"quill": "^2.0.3",
|
"quill": "^2.0.3",
|
||||||
"quill-mention": "^6.0.2",
|
"quill-mention": "^6.0.2",
|
||||||
"react": "^18.3.1",
|
"react": "19.1.0",
|
||||||
"react-diff-viewer-continued": "^3.4.0",
|
"react-diff-viewer-continued": "^4.0.6",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "19.1.0",
|
||||||
"react-dropzone": "^14.3.5",
|
"react-dropzone": "^14.3.5",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^10.1.0",
|
||||||
"react-resizable-panels": "^2.1.7",
|
"react-resizable-panels": "^2.1.7",
|
||||||
"redis": "^4.7.0",
|
"redis": "^4.7.0",
|
||||||
"remark-gfm": "^4.0.0",
|
"remark-gfm": "^4.0.1",
|
||||||
"rowboat-shared": "github:rowboatlabs/shared",
|
"rowboat-shared": "github:rowboatlabs/shared",
|
||||||
"sharp": "^0.33.4",
|
"sharp": "^0.33.4",
|
||||||
"styled-components": "^5.3.11",
|
"styled-components": "^5.3.11",
|
||||||
|
|
@ -67,20 +67,24 @@
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"tiktoken": "^1.0.17",
|
"tiktoken": "^1.0.17",
|
||||||
"twilio": "^5.4.5",
|
"twilio": "^5.4.5",
|
||||||
"typewriter-effect": "^2.21.0",
|
|
||||||
"zod": "^3.23.8",
|
"zod": "^3.23.8",
|
||||||
"zod-to-json-schema": "^3.23.5"
|
"zod-to-json-schema": "^3.23.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@tailwindcss/postcss": "^4.1.10",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18",
|
"@types/react": "19.1.8",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "19.1.6",
|
||||||
"@types/redis": "^4.0.11",
|
"@types/redis": "^4.0.11",
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "14.2.5",
|
"eslint-config-next": "15.3.4",
|
||||||
"postcss": "^8",
|
"postcss": "^8.5.6",
|
||||||
"tailwindcss": "^3.4.1",
|
"tailwindcss": "^4.1.10",
|
||||||
"tsx": "^4.19.1",
|
"tsx": "^4.19.1",
|
||||||
"typescript": "^5"
|
"typescript": "^5"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"@types/react": "19.1.8",
|
||||||
|
"@types/react-dom": "19.1.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
/** @type {import('postcss-load-config').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
const config = {
|
export default {
|
||||||
plugins: {
|
plugins: {
|
||||||
tailwindcss: {},
|
'@tailwindcss/postcss': {},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
export default config;
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
import { heroui } from "@heroui/theme";
|
|
||||||
import type { Config } from "tailwindcss";
|
|
||||||
|
|
||||||
const config: Config = {
|
|
||||||
darkMode: ["class"],
|
|
||||||
content: [
|
|
||||||
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
|
|
||||||
"./components/**/*.{js,ts,jsx,tsx,mdx}",
|
|
||||||
"./app/**/*.{js,ts,jsx,tsx,mdx}",
|
|
||||||
"./node_modules/@heroui/theme/dist/components/[object Object].js",
|
|
||||||
"./node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}",
|
|
||||||
],
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
keyframes: {
|
|
||||||
shine: {
|
|
||||||
'100%': { transform: 'translateX(200%)' }
|
|
||||||
},
|
|
||||||
'pulse-subtle': {
|
|
||||||
'0%, 100%': { opacity: '1' },
|
|
||||||
'50%': { opacity: '0.85' }
|
|
||||||
},
|
|
||||||
gradient: {
|
|
||||||
'0%': { backgroundPosition: '0% 50%' },
|
|
||||||
'50%': { backgroundPosition: '100% 50%' },
|
|
||||||
'100%': { backgroundPosition: '0% 50%' }
|
|
||||||
},
|
|
||||||
'sparkle-fade': {
|
|
||||||
'0%': { opacity: '0.2', transform: 'scale(0.9)' },
|
|
||||||
'50%': { opacity: '0.5', transform: 'scale(1.1)' },
|
|
||||||
'100%': { opacity: '0.2', transform: 'scale(0.9)' }
|
|
||||||
},
|
|
||||||
typing: {
|
|
||||||
'0%, 5%': { width: '0%' },
|
|
||||||
'45%, 55%': { width: '100%' },
|
|
||||||
'95%, 100%': { width: '0%' }
|
|
||||||
},
|
|
||||||
blink: {
|
|
||||||
'50%': { borderColor: 'transparent' }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
animation: {
|
|
||||||
shine: 'shine 2s infinite',
|
|
||||||
'pulse-subtle': 'pulse-subtle 2s infinite',
|
|
||||||
'gradient': 'gradient var(--gradient-animation-duration, 15s) ease infinite',
|
|
||||||
'sparkle': 'sparkle-fade 4s cubic-bezier(0.4, 0, 0.6, 1) infinite',
|
|
||||||
'typing': 'typing 8s cubic-bezier(0.4, 0, 0.2, 1) infinite',
|
|
||||||
'cursor': 'blink .75s step-end infinite'
|
|
||||||
},
|
|
||||||
backgroundImage: {
|
|
||||||
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
|
|
||||||
'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))'
|
|
||||||
},
|
|
||||||
borderRadius: {
|
|
||||||
lg: 'var(--radius)',
|
|
||||||
md: 'calc(var(--radius) - 2px)',
|
|
||||||
sm: 'calc(var(--radius) - 4px)'
|
|
||||||
},
|
|
||||||
colors: {
|
|
||||||
background: 'hsl(var(--background))',
|
|
||||||
foreground: 'hsl(var(--foreground))',
|
|
||||||
card: {
|
|
||||||
DEFAULT: 'hsl(var(--card))',
|
|
||||||
foreground: 'hsl(var(--card-foreground))'
|
|
||||||
},
|
|
||||||
popover: {
|
|
||||||
DEFAULT: 'hsl(var(--popover))',
|
|
||||||
foreground: 'hsl(var(--popover-foreground))'
|
|
||||||
},
|
|
||||||
primary: {
|
|
||||||
DEFAULT: 'hsl(var(--primary))',
|
|
||||||
foreground: 'hsl(var(--primary-foreground))'
|
|
||||||
},
|
|
||||||
secondary: {
|
|
||||||
DEFAULT: 'hsl(var(--secondary))',
|
|
||||||
foreground: 'hsl(var(--secondary-foreground))'
|
|
||||||
},
|
|
||||||
muted: {
|
|
||||||
DEFAULT: 'hsl(var(--muted))',
|
|
||||||
foreground: 'hsl(var(--muted-foreground))'
|
|
||||||
},
|
|
||||||
accent: {
|
|
||||||
DEFAULT: 'hsl(var(--accent))',
|
|
||||||
foreground: 'hsl(var(--accent-foreground))'
|
|
||||||
},
|
|
||||||
destructive: {
|
|
||||||
DEFAULT: 'hsl(var(--destructive))',
|
|
||||||
foreground: 'hsl(var(--destructive-foreground))'
|
|
||||||
},
|
|
||||||
border: 'hsl(var(--border))',
|
|
||||||
input: 'hsl(var(--input))',
|
|
||||||
ring: 'hsl(var(--ring))',
|
|
||||||
chart: {
|
|
||||||
'1': 'hsl(var(--chart-1))',
|
|
||||||
'2': 'hsl(var(--chart-2))',
|
|
||||||
'3': 'hsl(var(--chart-3))',
|
|
||||||
'4': 'hsl(var(--chart-4))',
|
|
||||||
'5': 'hsl(var(--chart-5))'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
heroui(),
|
|
||||||
require("tailwindcss-animate")
|
|
||||||
],
|
|
||||||
};
|
|
||||||
export default config;
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
|
@ -18,9 +22,19 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./*"]
|
"@/*": [
|
||||||
}
|
"./*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
"target": "ES2017"
|
||||||
"exclude": ["node_modules"]
|
},
|
||||||
|
"include": [
|
||||||
|
"next-env.d.ts",
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
".next/types/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue