Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps/dbagent/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
DATABASE_URL='postgres://dbagent:changeme@localhost:5432/dbagent'
OPENAI_API_KEY=
DEEPSEEK_API_KEY=
ANTHROPIC_API_KEY=
ANTHROPIC_API_KEY=
PUBLIC_URL='http://localhost:4001'
2 changes: 2 additions & 0 deletions apps/dbagent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@vercel/functions": "^2.0.0",
"ai": "^4.1.45",
"bytes": "^3.1.2",
"canvas-confetti": "^1.9.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cron-parser": "^5.0.4",
Expand All @@ -52,6 +53,7 @@
"@internal/eslint-config": "workspace:*",
"@internal/tsconfig": "workspace:*",
"@types/bytes": "^3.1.5",
"@types/canvas-confetti": "^1.9.0",
"@types/pg": "^8.11.11",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
Expand Down
16 changes: 16 additions & 0 deletions apps/dbagent/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* eslint-disable no-process-env */
import { createServer } from 'http';
import next from 'next';

const port = process.env.PORT || 4001;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();

void app.prepare().then(() => {
createServer((req, res) => {
void handle(req, res);
}).listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
5 changes: 4 additions & 1 deletion apps/dbagent/src/app/(main)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
'use server';
import { BelowHeaderBar, HeaderBar } from '~/app/components/ui/header-bar';
import { getCompletedTaskPercentage } from '~/components/onboarding/actions';
import { SideNav } from '../components/ui/side-nav';

export default async function Layout({ children }: { children: React.ReactNode }) {
const onboardingComplete = await getCompletedTaskPercentage();
return (
<>
<div className="flex h-full overflow-hidden">
Expand All @@ -10,7 +13,7 @@ export default async function Layout({ children }: { children: React.ReactNode }

<BelowHeaderBar>
<div className="mt-14 flex h-full">
<SideNav />
<SideNav onboardingComplete={onboardingComplete} />
<main className="ml-64 flex-1 p-8">{children}</main>
</div>
</BelowHeaderBar>
Expand Down
15 changes: 8 additions & 7 deletions apps/dbagent/src/app/(main)/monitoring/schedule/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ import { actionListConnections } from '~/components/connections/actions';
import { actionListPlaybooks } from '~/components/monitoring/actions';
import { ScheduleForm } from '~/components/monitoring/schedule-form';

export default async function Page({ params }: { params: { id: string; connection?: string } }) {
interface PageParams {
id: string;
connection?: string;
}

export default async function Page({ params }: { params: Promise<PageParams> }) {
const playbooks = await actionListPlaybooks();
const connections = await actionListConnections();
const { id, connection } = await params;
return (
<div className="container">
<ScheduleForm
scheduleId={params.id}
playbooks={playbooks}
connections={connections}
connection={params.connection}
/>
<ScheduleForm scheduleId={id} playbooks={playbooks} connections={connections} connection={connection} />
</div>
);
}
5 changes: 3 additions & 2 deletions apps/dbagent/src/app/(main)/start/connect/edit/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { ConnectionForm } from '~/components/connections/connection-form';

export default async function EditConnection({ params }: { params: { id: number } }) {
export default async function EditConnection({ params }: { params: Promise<{ id: number }> }) {
const { id } = await params;
return (
<div className="container mx-auto p-4">
<h1 className="mb-4 text-2xl font-bold">Edit Connection</h1>
<ConnectionForm id={params.id} />
<ConnectionForm id={id} />
</div>
);
}
12 changes: 12 additions & 0 deletions apps/dbagent/src/app/(main)/start/notifications/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use server';

import { SlackIntegration } from '~/components/slack-integration/slack-integration';

export default async function Page() {
return (
<div className="container mx-auto max-w-6xl p-4">
<h1 className="mb-4 text-2xl font-bold">Collect info about your database</h1>
<SlackIntegration />
</div>
);
}
2 changes: 1 addition & 1 deletion apps/dbagent/src/app/api/chat/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { getTargetDbConnection } from '~/lib/targetdb/db';
export const runtime = 'nodejs';
export const maxDuration = 30;

export function errorHandler(error: unknown) {
function errorHandler(error: unknown) {
if (error == null) {
return 'unknown error';
}
Expand Down
30 changes: 24 additions & 6 deletions apps/dbagent/src/app/components/ui/side-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,46 @@
import { cn, Input } from '@internal/components';
import {
ActivityIcon,
AlarmClock,
BotMessageSquare,
CloudIcon,
DatabaseIcon,
GitBranch,
PlugIcon,
Server,
ZapIcon
} from 'lucide-react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { useEffect, useState } from 'react';

interface SideNavProps {
className?: string;
onboardingComplete: number;
}

export function SideNav({ className }: SideNavProps) {
export function SideNav({ className, onboardingComplete }: SideNavProps) {
const pathname = usePathname();
const [onboardingCompleteState, setOnboardingComplete] = useState(onboardingComplete);

const isActive = (path: string) => {
return pathname === path ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-accent';
};

useEffect(() => {
const handleOnboardingStatus = (e: CustomEvent) => {
// Update your onboarding complete state here
setOnboardingComplete(e.detail.completed);
};

window.addEventListener('onboardingStatusChanged', handleOnboardingStatus as EventListener);

return () => {
window.removeEventListener('onboardingStatusChanged', handleOnboardingStatus as EventListener);
};
}, []);

console.log('onboardingComplete', onboardingCompleteState);

return (
<div className={cn('bg-background fixed h-lvh w-64 border-r', className)}>
<div className="space-y-4 p-4">
Expand All @@ -35,7 +53,7 @@ export function SideNav({ className }: SideNavProps) {
className={cn('flex items-center gap-2 rounded-md px-3 py-2 text-sm', isActive(`/start`))}
>
<ZapIcon className="h-4 w-4" />
Starter guide
Starter guide {onboardingCompleteState ? `(${onboardingCompleteState}%)` : ''}
</Link>
</nav>
<nav className="space-y-2">
Expand Down Expand Up @@ -68,11 +86,11 @@ export function SideNav({ className }: SideNavProps) {

<nav className="space-y-2">
<Link
href="/start/environments"
href="/start/notifications"
className={cn('flex items-center gap-2 rounded-md px-3 py-2 text-xs', isActive(`/start/environments`))}
>
<GitBranch className="h-4 w-4 pl-2" />
Setup environments
<AlarmClock className="h-4 w-4 pl-2" />
Setup notifications
</Link>
</nav>

Expand Down
10 changes: 9 additions & 1 deletion apps/dbagent/src/components/chats/chats-ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
import { useChat } from 'ai/react';
import { Bot, Clock, Lightbulb, Send, User, Wrench } from 'lucide-react';
import { useSearchParams } from 'next/navigation';
import { useEffect, useRef, useState } from 'react';
import { Suspense, useEffect, useRef, useState } from 'react';
import ReactMarkdown from 'react-markdown';
import { DbConnection } from '~/lib/db/connections';
import { ChatSidebar } from './chat-sidebar';
Expand All @@ -24,6 +24,14 @@ import { mockChats } from './mock-data';
import { ModelSelector } from './model-selector';

export function ChatsUI({ connections }: { connections: DbConnection[] }) {
return (
<Suspense fallback={<div>Loading...</div>}>
<ChatsUIContent connections={connections} />
</Suspense>
);
}

function ChatsUIContent({ connections }: { connections: DbConnection[] }) {
const searchParams = useSearchParams();
const [selectedChatId, setSelectedChatId] = useState<string | null>(null);
const [chats, setChats] = useState(mockChats);
Expand Down
2 changes: 1 addition & 1 deletion apps/dbagent/src/components/monitoring/schedules-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ export function MonitoringScheduleTable({ connections }: { connections: DbConnec
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[150px]">Playbook</TableHead>
<TableHead className="w-[150px]">Database</TableHead>
<TableHead className="w-[150px]">Playbook</TableHead>
<TableHead className="w-[150px]">Schedule</TableHead>
<TableHead className="w-[150px]">Status</TableHead>
<TableHead className="w-[150px]">Last Run</TableHead>
Expand Down
11 changes: 11 additions & 0 deletions apps/dbagent/src/components/onboarding/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { getClusters } from '~/lib/db/clusters';
import { getDefaultConnection } from '~/lib/db/connections';
import { getDbInfo } from '~/lib/db/dbinfo';
import { getIntegration } from '~/lib/db/integrations';

// Server action to get completed tasks
export async function getCompletedTasks(): Promise<string[]> {
Expand All @@ -24,5 +25,15 @@ export async function getCompletedTasks(): Promise<string[]> {
completedTasks.push('cloud');
}

const slack = await getIntegration('slack');
if (slack) {
completedTasks.push('notifications');
}

return completedTasks;
}

export async function getCompletedTaskPercentage(): Promise<number> {
const completedTasks = await getCompletedTasks();
return Math.round((completedTasks.length / 4) * 100);
}
Loading
Loading