Skip to content

Commit

Permalink
refactor: components composition
Browse files Browse the repository at this point in the history
  • Loading branch information
cesconix committed Jul 9, 2024
1 parent cbae749 commit 41a5ee5
Show file tree
Hide file tree
Showing 29 changed files with 483 additions and 349 deletions.
88 changes: 6 additions & 82 deletions packages/pinorama-studio/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,88 +1,12 @@
import { Search } from "lucide-react"
import { useCallback, useEffect, useRef, useState } from "react"
import type { ImperativePanelHandle } from "react-resizable-panels"
import { PinoramaDocsTable } from "./components/pinorama-docs-table"
import { PinoramaFacets } from "./components/pinorama-facets"
import { Button } from "./components/ui/button"
import { Input } from "./components/ui/input"
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup
} from "./components/ui/resizable"
import { LogExplorer } from "./components/log-explorer"
import { TitleBar } from "./components/title-bar/title-bar"

function App() {
const panelRef = useRef<ImperativePanelHandle | null>(null)

const [searchText, setSearchText] = useState("")
const [filters, setFilters] = useState({})
const [rowSelection, setRowSelection] = useState(null)

useEffect(() => {
const panel = panelRef.current
rowSelection ? panel?.expand(20) : panel?.collapse()
}, [rowSelection])

const handleResetFilters = useCallback(() => {
setFilters({})
setSearchText("")
}, [])

const hasFilters = Object.keys(filters).length > 0 || searchText.length > 0

return (
<ResizablePanelGroup direction="horizontal" className="min-h-screen w-full">
<ResizablePanel defaultSize={20}>
<div className="flex flex-col h-screen p-3 overflow-auto">
<div className="flex text-sm whitespace-nowrap justify-between items-center mb-0.5 h-[40px]">
<div className="font-medium px-2">Filters</div>
{hasFilters ? (
<Button
variant="outline"
size={"sm"}
className="text-muted-foreground"
onClick={handleResetFilters}
>
Reset
</Button>
) : null}
</div>
<PinoramaFacets
searchText={searchText}
filters={filters}
onFiltersChange={setFilters}
/>
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={80}>
<div className="flex flex-col h-screen bg-muted/20">
<div className="p-3 pb-1 bg-background space-x-1">
<div className="relative flex items-center">
<Search className="h-4 w-4 absolute left-3 text-muted-foreground" />
<Input
type="text"
placeholder="Search logs..."
className="pl-9"
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
/>
</div>
</div>
<PinoramaDocsTable
searchText={searchText}
filters={filters}
onRowSelectionChange={setRowSelection}
/>
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel ref={panelRef} defaultSize={0} collapsible={true}>
<div className="flex flex-col h-screen p-3 overflow-auto">
<pre className="text-sm">{JSON.stringify(rowSelection, null, 2)}</pre>
</div>
</ResizablePanel>
</ResizablePanelGroup>
<div className="h-screen w-full grid grid-rows-[40px_1fr]">
<TitleBar />
<LogExplorer />
</div>
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { usePinoramaIntrospection } from "@/hooks"

export function ConnectionStatus() {
const { status } = usePinoramaIntrospection()

let statusColor = ""
let statusText = ""

switch (status) {
case "pending":
statusColor = "bg-orange-500"
statusText = "Connecting"
break
case "success":
statusColor = "bg-green-500"
statusText = "Connected"
break
case "error":
statusColor = "bg-red-500"
statusText = "Connection timed out"
break
default:
statusColor = "bg-gray-500"
statusText = "Unknown"
}

return (
<div className="flex items-center space-x-1.5">
<div className={`w-2 h-2 rounded-full ${statusColor}`} />
<span className="">{statusText}</span>
<span className="text-muted-foreground">
http://localhost:6200/pinorama
</span>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { cn } from "@/lib/utils"

type EmptyStateProps = {
message: string
className?: string
}

export function EmptyState(props: EmptyStateProps) {
return (
<div className="flex items-center h-10 p-3 my-2 text-sm text-muted-foreground border rounded-md">
<div
className={cn(
"flex items-center h-10 p-3 m-2 text-sm border rounded-md text-muted-foreground",
props.className
)}
>
{props.message}
</div>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { cn } from "@/lib/utils"

type ErrorStateProps = {
error: Error
className?: string
}

export function ErrorState(props: ErrorStateProps) {
return (
<div className="flex items-center h-10 p-3 my-2 text-sm border rounded-md">
<div
className={cn(
"flex items-center h-10 p-3 m-2 text-sm border rounded-md",
props.className
)}
>
<div className="flex items-center text-red-500 mr-2">
<span className="font-medium">Error:</span>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { LoaderIcon } from "lucide-react"

export function LoadingState() {
return (
<div className="flex items-center h-10 p-3 my-2 text-sm text-muted-foreground">
<div className="flex items-center h-10 p-3 m-2 text-sm text-muted-foreground">
<LoaderIcon className="w-4 h-4 mr-2 animate-spin" />
Loading...
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
type LogDetailsProps = {
data: any
}

export function LogDetails(props: LogDetailsProps) {
return (
<div className="flex flex-col h-full p-3 overflow-auto">
<pre className="text-sm">{JSON.stringify(props.data, null, 2)}</pre>
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ export function Facet(props: FacetProps) {
/>
{open ? (
hasError ? (
<ErrorState error={error} />
<ErrorState error={error} className="my-2 mx-0" />
) : hasNoData ? (
<EmptyState message={"No results found"} />
<EmptyState message={"No results found"} className="my-2 mx-0" />
) : (
<FacetBody
name={props.name}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ export const useFacet = (
const response: any = await client?.search(payload)
return response.facets[name]
},
placeholderData: keepPreviousData
placeholderData: keepPreviousData,
refetchInterval: 3000
})

return query
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { ErrorState } from "@/components/error-state/error-state"
import { usePinoramaIntrospection } from "@/hooks"
import { Facet } from "./components/facet"

import { LoadingState } from "@/components/loading-state/loading-state"
import { useMemo } from "react"
import type { SearchFilters } from "./types"

const ALLOWED_TYPES = ["string", "enum", "boolean"]

type PinoramaFacetsProps = {
searchText: string
filters: SearchFilters
onFiltersChange: (filters: SearchFilters) => void
}

export function LogFilters(props: PinoramaFacetsProps) {
const { data: introspection, status, error } = usePinoramaIntrospection()

const facets = useMemo(() => {
if (!introspection) return []
return Object.keys(introspection?.dbSchema).filter((name) => {
const type = introspection.dbSchema[name]
return ALLOWED_TYPES.includes(type)
})
}, [introspection])

if (status === "pending") {
return <LoadingState />
}

if (status === "error") {
return <ErrorState error={error} />
}

/*
const handleResetFilters = useCallback(() => {
setFilters({})
setSearchText("")
}, [])
const hasFilters = Object.keys(filters).length > 0 || searchText.length > 0
*/

return (
<div className="flex flex-col h-full p-3 overflow-auto">
{/* <div className="flex text-sm whitespace-nowrap justify-between items-center mb-0.5"> */}
{/* <div className="flex font-medium px-2 h-10 items-center"> */}
{/* Filters */}
{/* </div> */}
{/* {hasFilters ? ( */}
{/* <Button */}
{/* variant="outline" */}
{/* className="text-muted-foreground" */}
{/* onClick={handleResetFilters} */}
{/* > */}
{/* Reset */}
{/* </Button> */}
{/* ) : null} */}
{/* </div> */}
{facets.map((name) => {
return (
<Facet
key={name}
name={name}
type={introspection.dbSchema[name]}
searchText={props.searchText}
filters={props.filters}
onFiltersChange={props.onFiltersChange}
/>
)
})}
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { type Table, flexRender } from "@tanstack/react-table"

export function TableHead({ table }: { table: Table<unknown> }) {
return (
<thead className="group sticky top-0 z-10 bg-background select-none flex">
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th
key={header.id}
colSpan={header.colSpan}
className="relative px-3 mb-1 text-left font-normal text-muted-foreground align-middle h-9"
style={{ width: header.getSize() }}
>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
{header.column.getCanResize() && (
<div
onMouseDown={header.getResizeHandler()}
onTouchStart={header.getResizeHandler()}
className={`absolute right-0 top-0 h-[32px] w-[3px] bg-muted opacity-0 group-hover:opacity-100 cursor-col-resize select-none touch-none ${
header.column.getIsResizing()
? "group-hover:bg-accent-foreground bg-accent-foreground"
: ""
}`}
/>
)}
</th>
))}
</tr>
))}
</thead>
)
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import type { SearchFilters } from "@/components/pinorama-facets/types"
import { usePinoramaClient } from "@/contexts"
import { useQuery } from "@tanstack/react-query"

export const useDocs = (searchText?: string, filters?: SearchFilters) => {
import type { SearchFilters } from "../../log-filters/types"

export const useLogs = (searchText?: string, filters?: SearchFilters) => {
const client = usePinoramaClient()

const query = useQuery({
queryKey: ["docs", searchText, filters],
queryKey: ["logs", searchText, filters],
queryFn: async ({ signal }) => {
await new Promise((resolve) => setTimeout(resolve, 500))

Expand All @@ -29,7 +30,8 @@ export const useDocs = (searchText?: string, filters?: SearchFilters) => {
const response: any = await client?.search(payload)

return response.hits.map((hit: { document: unknown }) => hit.document)
}
},
refetchInterval: 3000
})

return query
Expand Down
Loading

0 comments on commit 41a5ee5

Please sign in to comment.