feat(logs): added logs structure; connecting to DB now

This commit is contained in:
Emir Karabeg
2025-03-05 14:47:42 -08:00
parent 07780800d8
commit 43d22d2f06
10 changed files with 287 additions and 2 deletions

View File

@@ -3,7 +3,7 @@
import { useMemo, useState } from 'react'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import { Plus, Settings } from 'lucide-react'
import { Plus, ScrollText, Settings } from 'lucide-react'
import { AgentIcon } from '@/components/icons'
import { Button } from '@/components/ui/button'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
@@ -42,7 +42,7 @@ export function Sidebar() {
<aside className="fixed inset-y-0 left-0 z-10 hidden w-14 flex-col border-r bg-background sm:flex">
<nav className="flex flex-col items-center gap-4 px-2 py-5">
<Link
href="/"
href="/w/1"
className="group flex h-8 w-8 items-center justify-center rounded-lg bg-[#7F2FFF]"
>
<AgentIcon className="text-white transition-all group-hover:scale-110 -translate-y-[0.5px] w-5 h-5" />
@@ -79,6 +79,22 @@ export function Sidebar() {
</nav>
<nav className="flex flex-col items-center gap-4 px-2 py-[18px]">
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
asChild
className="flex !h-9 !w-9 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:text-foreground md:h-8 md:w-8"
>
<Link href="/w/logs">
<ScrollText className="!h-5 !w-5" />
<span className="sr-only">Logs</span>
</Link>
</Button>
</TooltipTrigger>
<TooltipContent side="right">Logs</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button

View File

@@ -0,0 +1,71 @@
'use client'
import { useState } from 'react'
import { RefreshCw, Search } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
/**
* Control bar for logs page - includes search functionality and refresh/live controls
*/
export function ControlBar() {
const [isLive, setIsLive] = useState(false)
const [searchQuery, setSearchQuery] = useState('')
const handleRefresh = () => {
// Implement refresh functionality
console.log('Refreshing logs')
}
const toggleLive = () => {
setIsLive(!isLive)
}
return (
<div className="flex h-16 w-full items-center justify-between bg-background px-6 border-b transition-all duration-300">
{/* Left Section - Search */}
<div className="relative w-[400px]">
<div className="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
<Search className="h-4 w-4 text-muted-foreground" />
</div>
<Input
type="search"
placeholder="Search logs..."
className="pl-10 h-9"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
{/* Middle Section - Reserved for future use */}
<div className="flex-1" />
{/* Right Section - Actions */}
<div className="flex items-center gap-3">
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={handleRefresh}
className="hover:text-foreground"
>
<RefreshCw className="h-5 w-5" />
<span className="sr-only">Refresh</span>
</Button>
</TooltipTrigger>
<TooltipContent>Refresh</TooltipContent>
</Tooltip>
<Button
variant={isLive ? 'default' : 'outline'}
className={isLive ? 'bg-[#7F2FFF] hover:bg-[#7F2FFF]/90 text-white' : ''}
onClick={toggleLive}
>
Live
</Button>
</div>
</div>
)
}

View File

@@ -0,0 +1,41 @@
import { useState } from 'react'
import { ChevronDown } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
export default function FilterSection({
title,
defaultOpen = false,
content,
}: {
title: string
defaultOpen?: boolean
content?: React.ReactNode
}) {
const [isOpen, setIsOpen] = useState(defaultOpen)
return (
<Collapsible open={isOpen} onOpenChange={setIsOpen} className="mb-3">
<CollapsibleTrigger asChild>
<Button
variant="ghost"
className="flex w-full justify-between px-2 text-sm font-medium hover:bg-accent rounded-md"
>
<span>{title}</span>
<ChevronDown
className={`h-4 w-4 text-muted-foreground transition-transform mr-[5px] ${
isOpen ? 'rotate-180' : ''
}`}
/>
</Button>
</CollapsibleTrigger>
<CollapsibleContent className="pt-2">
{content || (
<div className="text-sm text-muted-foreground">
Filter options for {title} will go here
</div>
)}
</CollapsibleContent>
</Collapsible>
)
}

View File

@@ -0,0 +1,36 @@
import { useState } from 'react'
import { ChevronDown } from 'lucide-react'
import { Button } from '@/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
export default function Timeline() {
const [selectedTimeRange, setSelectedTimeRange] = useState('Past 30 minutes')
const timeRanges = ['Past 30 minutes', 'Past hour', 'Past 24 hours', 'All time']
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="sm" className="w-full justify-between text-sm font-normal">
{selectedTimeRange}
<ChevronDown className="h-4 w-4 ml-2 text-muted-foreground" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="overflow-y-auto">
{timeRanges.map((range) => (
<DropdownMenuItem
key={range}
onClick={() => setSelectedTimeRange(range)}
className="flex items-start p-2 cursor-pointer text-sm"
>
{range}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
)
}

View File

@@ -0,0 +1,33 @@
'use client'
import { useState } from 'react'
import { ChevronDown } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import FilterSection from './components/filter-section/filter-section'
import Timeline from './components/timeline'
/**
* Filters component for logs page - includes timeline and other filter options
*/
export function Filters() {
return (
<div className="p-4 w-64 border-r h-full overflow-auto">
<h2 className="text-sm font-medium mb-4 pl-2">Filters</h2>
{/* Timeline Filter */}
<FilterSection title="Timeline" defaultOpen={true} content={<Timeline />} />
{/* Additional filter sections */}
<FilterSection title="Contains Level" />
<FilterSection title="Environment" />
<FilterSection title="Route" />
</div>
)
}

19
app/w/logs/logs.tsx Normal file
View File

@@ -0,0 +1,19 @@
'use client'
import { ControlBar } from './components/control-bar/control-bar'
import { Filters } from './components/filters/filters'
export default function Logs() {
return (
<div className="flex flex-col h-full">
<ControlBar />
<div className="flex flex-1 overflow-hidden">
<Filters />
<div className="flex-1 overflow-auto p-4">
{/* Logs content will go here */}
<div className="text-muted-foreground text-center mt-10">137 total logs found...</div>
</div>
</div>
</div>
)
}

3
app/w/logs/page.tsx Normal file
View File

@@ -0,0 +1,3 @@
import Logs from './logs'
export default Logs

View File

@@ -0,0 +1,11 @@
'use client'
import * as CollapsiblePrimitive from '@radix-ui/react-collapsible'
const Collapsible = CollapsiblePrimitive.Root
const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger
const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent
export { Collapsible, CollapsibleTrigger, CollapsibleContent }

54
package-lock.json generated
View File

@@ -15,6 +15,7 @@
"@cerebras/cerebras_cloud_sdk": "^1.23.0",
"@radix-ui/react-alert-dialog": "^1.1.5",
"@radix-ui/react-checkbox": "^1.1.3",
"@radix-ui/react-collapsible": "^1.1.3",
"@radix-ui/react-dialog": "^1.1.5",
"@radix-ui/react-dropdown-menu": "^2.1.4",
"@radix-ui/react-label": "^2.1.1",
@@ -1866,6 +1867,59 @@
}
}
},
"node_modules/@radix-ui/react-collapsible": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.3.tgz",
"integrity": "sha512-jFSerheto1X03MUC0g6R7LedNW9EEGWdg9W1+MlpkMLwGkgkbUXLPBH/KIuWKXUoeYRVY11llqbTBDzuLg7qrw==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.1",
"@radix-ui/react-compose-refs": "1.1.1",
"@radix-ui/react-context": "1.1.1",
"@radix-ui/react-id": "1.1.0",
"@radix-ui/react-presence": "1.1.2",
"@radix-ui/react-primitive": "2.0.2",
"@radix-ui/react-use-controllable-state": "1.1.0",
"@radix-ui/react-use-layout-effect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-primitive": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
"integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-slot": "1.1.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-collection": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.1.tgz",

View File

@@ -28,6 +28,7 @@
"@cerebras/cerebras_cloud_sdk": "^1.23.0",
"@radix-ui/react-alert-dialog": "^1.1.5",
"@radix-ui/react-checkbox": "^1.1.3",
"@radix-ui/react-collapsible": "^1.1.3",
"@radix-ui/react-dialog": "^1.1.5",
"@radix-ui/react-dropdown-menu": "^2.1.4",
"@radix-ui/react-label": "^2.1.1",