Skip to content

Commit

Permalink
feat: add error and loading state
Browse files Browse the repository at this point in the history
  • Loading branch information
cesconix committed Jul 6, 2024
1 parent 577f4b4 commit 8c4d024
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 44 deletions.
4 changes: 2 additions & 2 deletions packages/pinorama-studio/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ function App() {
<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">🌀 Pinorama</div>
<div className="font-medium px-2">Filters</div>
{hasFilters ? (
<Button
variant="outline"
className="text-muted-foreground"
onClick={handleResetFilters}
>
Reset Filters
Reset
</Button>
) : null}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
type ErrorStateProps = {
error: Error
}

export function ErrorState(props: ErrorStateProps) {
return (
<div className="flex items-center border rounded-md h-10 p-3 my-2 text-sm">
<div className="flex items-center text-red-500 mr-2">
<span className="font-medium">Error:</span>
</div>
<div className="text-foreground">{props.error.message}!</div>
</div>
)
}
10 changes: 10 additions & 0 deletions packages/pinorama-studio/src/components/loading/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { LoaderIcon } from "lucide-react"

export function Loading() {
return (
<div className="flex items-center text-muted-foreground text-sm">
<LoaderIcon className="w-4 h-4 mr-2 animate-spin" />
Loading...
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { useMemo, useRef } from "react"

import { getCoreRowModel, useReactTable } from "@tanstack/react-table"
import { useVirtualizer } from "@tanstack/react-virtual"
import { LoaderIcon } from "lucide-react"
import { ErrorState } from "../error-state/error-state"
import { Loading } from "../loading/loading"
import type { SearchFilters } from "../pinorama-facets/types"
import { TableBody } from "./components/tbody"
import { TableHead } from "./components/thead"
Expand All @@ -16,7 +17,7 @@ type PinoramaDocsTableProps = {

export function PinoramaDocsTable(props: PinoramaDocsTableProps) {
const columns = useColumns()
const { data, status } = useDocs(props.searchText, props.filters)
const { data, status, error } = useDocs(props.searchText, props.filters)

const docs = useMemo(() => data ?? [], [data])

Expand All @@ -39,22 +40,28 @@ export function PinoramaDocsTable(props: PinoramaDocsTableProps) {
overscan: 100
})

const isLoading = status === "pending"
const hasError = status === "error"
const hasNoData = data?.length === 0 || false

return (
<div
ref={tableContainerRef}
className="h-full overflow-auto relative w-full"
>
<table className="text-sm w-full">
<TableHead table={table} />
{status === "pending" ? (
{isLoading || hasNoData || hasError ? (
<tbody>
<tr>
<td
colSpan={columns.length}
className="h-10 px-3 text-muted-foreground flex items-center"
>
<LoaderIcon className="w-4 h-4 mr-2 animate-spin" />
Loading...
<td className="h-10 px-3 text-muted-foreground">
{isLoading ? (
<Loading />
) : hasError ? (
<ErrorState error={error} />
) : hasNoData ? (
"No logs found"
) : null}
</td>
</tr>
</tbody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,27 @@ export function FacetBody(props: FacetBodyProps) {
return (
<div className="my-2">
<div className="border border-muted rounded-md overflow-auto max-h-[241px] my-2">
{props.values?.map(({ value, count }) => {
return (
<FacetItem
key={value as string}
name={props.name}
type={props.type}
value={value}
count={count}
filters={props.filters}
onFiltersChange={props.onFiltersChange}
/>
)
})}
{props.values.length === 0 ? (
<div className="h-10 flex items-center justify-center text-sm text-muted-foreground">
No results found
</div>
) : (
<>
{props.values?.map(({ value, count }) => {
return (
<FacetItem
key={value as string}
name={props.name}
type={props.type}
value={value}
count={count}
filters={props.filters}
onFiltersChange={props.onFiltersChange}
/>
)
})}
</>
)}
</div>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Button } from "@/components/ui/button"
import { ChevronDown, ChevronRight, CircleX, LoaderIcon } from "lucide-react"
import type React from "react"

type FacetHeaderProps = {
name: string
loading: boolean
count: number
open: boolean
onClick: () => void
onCountClick: () => void
onCountClick: (e: React.MouseEvent) => void
}

export function FacetHeader(props: FacetHeaderProps) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ErrorState } from "@/components/error-state/error-state"
import { useCallback, useMemo, useState } from "react"
import { useFacet } from "../hooks/use-facet"
import { facetFilterOperationsFactory } from "../lib/operations"
Expand All @@ -21,21 +22,26 @@ type FacetProps = {
export function Facet(props: FacetProps) {
const [open, setOpen] = useState(true)

const { data: facet, fetchStatus } = useFacet(
props.name,
props.searchText,
props.filters
)
const {
data: facet,
fetchStatus,
status,
error
} = useFacet(props.name, props.searchText, props.filters)

const operations: any = facetFilterOperationsFactory(props.type)
const criteria = props.filters[props.name] || operations.create()
const selelectedOptionCount = operations.length(criteria)

const handleReset = useCallback(() => {
const filters = { ...props.filters }
delete filters[props.name]
props.onFiltersChange(filters)
}, [props.onFiltersChange, props.name, props.filters])
const handleReset = useCallback(
(event: React.MouseEvent) => {
event.stopPropagation()
const filters = { ...props.filters }
delete filters[props.name]
props.onFiltersChange(filters)
},
[props.onFiltersChange, props.name, props.filters]
)

const selected: FacetValue[] = useMemo(() => {
return operations
Expand Down Expand Up @@ -80,13 +86,17 @@ export function Facet(props: FacetProps) {
onCountClick={handleReset}
/>
{open ? (
<FacetBody
name={props.name}
type={props.type}
values={values}
filters={props.filters}
onFiltersChange={props.onFiltersChange}
/>
status === "error" ? (
<ErrorState error={error} />
) : (
<FacetBody
name={props.name}
type={props.type}
values={values}
filters={props.filters}
onFiltersChange={props.onFiltersChange}
/>
)
) : null}
</div>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { usePinoramaIntrospection } from "@/hooks"
import { Facet } from "./components/facet"

import { ErrorState } from "../error-state/error-state"
import { Loading } from "../loading/loading"
import type { SearchFilters } from "./types"

const ALLOWED_TYPES = ["string", "enum", "boolean"]
Expand All @@ -15,11 +17,11 @@ export function PinoramaFacets(props: PinoramaFacetsProps) {
const { data: introspection, status, error } = usePinoramaIntrospection()

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

if (status === "error") {
return <div>Error: {error.message}</div>
return <ErrorState error={error} />
}

return Object.keys(introspection.dbSchema)
Expand Down

0 comments on commit 8c4d024

Please sign in to comment.