diff --git a/web/src/app/(app)/reviews/page.tsx b/web/src/app/(app)/reviews/page.tsx index f926ece..aac6b99 100644 --- a/web/src/app/(app)/reviews/page.tsx +++ b/web/src/app/(app)/reviews/page.tsx @@ -4,6 +4,8 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import { AppShell } from "@/components/AppShell"; import { Badge, + EmptyState, + LoadingSpinner, Panel, } from "@/components/ui/Primitives"; import { @@ -33,6 +35,7 @@ export default function ReviewsPage() { const [selectedApprovalId, setSelectedApprovalId] = useState(null); const [selectedBatchIds, setSelectedBatchIds] = useState>(new Set()); const [reviewNote, setReviewNote] = useState(""); + const [isLoading, setIsLoading] = useState(true); const [isSubmitting, setIsSubmitting] = useState(false); const [error, setError] = useState(null); @@ -50,6 +53,8 @@ export default function ReviewsPage() { setTimeline(nextTimeline); } catch (err) { setError(err instanceof Error ? err.message : "Unable to load review queue"); + } finally { + setIsLoading(false); } })(); }, []); @@ -281,15 +286,27 @@ export default function ReviewsPage() { onClear={clearBatch} onBatchDecision={(decision) => void handleBatchDecision(decision)} /> - {error ?
{error}
: null} - - batchMode ? toggleBatchItem(id) : setSelectedApprovalId(id)} - /> + {isLoading ? ( + + ) : error && approvalQueue.length === 0 ? ( + window.location.reload()} + /> + ) : ( + <> + {error ? : null} + batchMode ? toggleBatchItem(id) : setSelectedApprovalId(id)} + /> + + )} diff --git a/web/src/components/reviews/ReviewWorkflow.tsx b/web/src/components/reviews/ReviewWorkflow.tsx index 4b43e07..acd7a6b 100644 --- a/web/src/components/reviews/ReviewWorkflow.tsx +++ b/web/src/components/reviews/ReviewWorkflow.tsx @@ -4,6 +4,7 @@ import { ProposalReviewCard } from "@/components/ProposalReviewCard"; import { Badge, Button, + EmptyState, ListItemButton, Panel, PanelBody, @@ -126,6 +127,15 @@ export function ReviewQueueList({ selectedApprovalId: string | null; onSelectItem: (id: string) => void; }) { + if (items.length === 0) { + return ( + + ); + } + return (
{items.map((item) => ( @@ -212,5 +222,19 @@ export function ProposalDiffCard({ } export function ReviewTimeline({ items }: { items: AgentTimelineItem[] }) { + if (items.length === 0) { + return ( + + + Agent activity timeline + + + + ); + } + return ; } diff --git a/web/src/components/ui/Primitives.tsx b/web/src/components/ui/Primitives.tsx index f07ed79..e85c465 100644 --- a/web/src/components/ui/Primitives.tsx +++ b/web/src/components/ui/Primitives.tsx @@ -23,10 +23,12 @@ import { DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuTrigger, + EmptyState as BytelystEmptyState, IconButton as BytelystIconButton, Input as BytelystInput, Label as BytelystLabel, ListItemButton as BytelystListItemButton, + LoadingSpinner as BytelystLoadingSpinner, Panel as BytelystPanel, PanelBody as BytelystPanelBody, PanelDescription as BytelystPanelDescription, @@ -57,10 +59,12 @@ import { type DataListItemProps, type DataListProps, type DiffCardProps, + type EmptyStateProps, type IconButtonProps, type InputProps, type LabelProps, type ListItemButtonProps, + type LoadingSpinnerProps, type PanelBodyProps, type PanelDescriptionProps, type PanelHeaderProps, @@ -297,3 +301,11 @@ export function DataListItem({ className, ...props }: DataListItemProps) { export const OperationalList = DataList; export const OperationalListItem = DataListItem; + +export function EmptyState({ className, ...props }: EmptyStateProps) { + return ; +} + +export function LoadingSpinner({ className, ...props }: LoadingSpinnerProps) { + return ; +}