UI/UX improvements (#218)

This commit is contained in:
Kerem Yilmaz
2024-04-23 13:54:04 -07:00
committed by GitHub
parent 9b540b9416
commit 550ad65c5d
6 changed files with 220 additions and 173 deletions

View File

@@ -23,7 +23,7 @@ const CardHeader = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<div <div
ref={ref} ref={ref}
className={cn("flex flex-col space-y-1.5 p-6", className)} className={cn("flex flex-col space-y-1.5 p-4", className)}
{...props} {...props}
/> />
)); ));
@@ -57,7 +57,7 @@ const CardContent = React.forwardRef<
HTMLDivElement, HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} /> <div ref={ref} className={cn("p-4", className)} {...props} />
)); ));
CardContent.displayName = "CardContent"; CardContent.displayName = "CardContent";
@@ -67,7 +67,7 @@ const CardFooter = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<div <div
ref={ref} ref={ref}
className={cn("flex items-center p-6 pt-0", className)} className={cn("flex items-center p-4 pt-0", className)}
{...props} {...props}
/> />
)); ));

View File

@@ -1,5 +1,4 @@
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { useId } from "react";
import { import {
Select, Select,
SelectContent, SelectContent,
@@ -8,19 +7,31 @@ import {
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { useSettingsStore } from "@/store/SettingsStore"; import { useSettingsStore } from "@/store/SettingsStore";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
function Settings() { function Settings() {
const { environment, organization, setEnvironment, setOrganization } = const { environment, organization, setEnvironment, setOrganization } =
useSettingsStore(); useSettingsStore();
const environmentInputId = useId();
const organizationInputId = useId();
return ( return (
<div className="flex flex-col gap-6"> <div className="flex flex-col gap-8 max-w-5xl mx-auto">
<h1>Settings</h1> <Card>
<CardHeader className="border-b-2">
<CardTitle className="text-lg">Settings</CardTitle>
<CardDescription>
You can select environment and organization here
</CardDescription>
</CardHeader>
<CardContent className="p-8">
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<Label htmlFor={environmentInputId}>Environment</Label> <div className="flex gap-4 items-center">
<div> <Label className="whitespace-nowrap w-36">Environment</Label>
<Select value={environment} onValueChange={setEnvironment}> <Select value={environment} onValueChange={setEnvironment}>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Environment" /> <SelectValue placeholder="Environment" />
@@ -30,8 +41,8 @@ function Settings() {
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
<Label htmlFor={organizationInputId}>Organization</Label> <div className="flex gap-4 items-center">
<div> <Label className="whitespace-nowrap w-36">Organization</Label>
<Select value={organization} onValueChange={setOrganization}> <Select value={organization} onValueChange={setOrganization}>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="Organization" /> <SelectValue placeholder="Organization" />
@@ -42,6 +53,8 @@ function Settings() {
</Select> </Select>
</div> </div>
</div> </div>
</CardContent>
</Card>
</div> </div>
); );
} }

View File

@@ -18,6 +18,7 @@ import { StepArtifactsLayout } from "./StepArtifactsLayout";
import Zoom from "react-medium-image-zoom"; import Zoom from "react-medium-image-zoom";
import { AspectRatio } from "@/components/ui/aspect-ratio"; import { AspectRatio } from "@/components/ui/aspect-ratio";
import { getRecordingURL, getScreenshotURL } from "./artifactUtils"; import { getRecordingURL, getScreenshotURL } from "./artifactUtils";
import { Skeleton } from "@/components/ui/skeleton";
function TaskDetails() { function TaskDetails() {
const { taskId } = useParams(); const { taskId } = useParams();
@@ -39,14 +40,6 @@ function TaskDetails() {
return <div>Error: {taskError?.message}</div>; return <div>Error: {taskError?.message}</div>;
} }
if (isTaskFetching) {
return <div>Loading...</div>; // TODO: skeleton
}
if (!task) {
return <div>Task not found</div>;
}
return ( return (
<div> <div>
<div className="flex flex-col gap-4 relative"> <div className="flex flex-col gap-4 relative">
@@ -58,9 +51,9 @@ function TaskDetails() {
refetch(); refetch();
}} }}
> >
<ReloadIcon /> <ReloadIcon className="w-4 h-4" />
</Button> </Button>
{task.recording_url ? ( {task?.recording_url ? (
<div className="flex"> <div className="flex">
<Label className="w-32">Recording</Label> <Label className="w-32">Recording</Label>
<video src={getRecordingURL(task)} controls /> <video src={getRecordingURL(task)} controls />
@@ -68,9 +61,13 @@ function TaskDetails() {
) : null} ) : null}
<div className="flex items-center"> <div className="flex items-center">
<Label className="w-32">Status</Label> <Label className="w-32">Status</Label>
<StatusBadge status={task.status} /> {isTaskFetching ? (
<Skeleton className="w-32 h-8" />
) : task ? (
<StatusBadge status={task?.status} />
) : null}
</div> </div>
{task.status === Status.Completed ? ( {task?.status === Status.Completed ? (
<div className="flex items-center"> <div className="flex items-center">
<Label className="w-32 shrink-0">Extracted Information</Label> <Label className="w-32 shrink-0">Extracted Information</Label>
<Textarea <Textarea
@@ -80,7 +77,8 @@ function TaskDetails() {
/> />
</div> </div>
) : null} ) : null}
{task.status === Status.Failed || task.status === Status.Terminated ? ( {task?.status === Status.Failed ||
task?.status === Status.Terminated ? (
<div className="flex items-center"> <div className="flex items-center">
<Label className="w-32 shrink-0">Failure Reason</Label> <Label className="w-32 shrink-0">Failure Reason</Label>
<Textarea <Textarea
@@ -97,6 +95,7 @@ function TaskDetails() {
<h1>Task Parameters</h1> <h1>Task Parameters</h1>
</AccordionTrigger> </AccordionTrigger>
<AccordionContent> <AccordionContent>
{task ? (
<div> <div>
<p className="py-2">Task ID: {taskId}</p> <p className="py-2">Task ID: {taskId}</p>
<p className="py-2">URL: {task.request.url}</p> <p className="py-2">URL: {task.request.url}</p>
@@ -128,13 +127,15 @@ function TaskDetails() {
/> />
</div> </div>
</div> </div>
) : null}
</AccordionContent> </AccordionContent>
</AccordionItem> </AccordionItem>
<AccordionItem value="task-artifacts"> <AccordionItem value="task-artifacts">
<AccordionTrigger> <AccordionTrigger>
<h1>Screenshot</h1> <h1>Final Screenshot</h1>
</AccordionTrigger> </AccordionTrigger>
<AccordionContent> <AccordionContent>
{task ? (
<div className="max-w-sm mx-auto"> <div className="max-w-sm mx-auto">
{task.screenshot_url ? ( {task.screenshot_url ? (
<Zoom zoomMargin={16}> <Zoom zoomMargin={16}>
@@ -146,6 +147,7 @@ function TaskDetails() {
<p>No screenshot</p> <p>No screenshot</p>
)} )}
</div> </div>
) : null}
</AccordionContent> </AccordionContent>
</AccordionItem> </AccordionItem>
<AccordionItem value="task-steps"> <AccordionItem value="task-steps">

View File

@@ -25,6 +25,13 @@ import { PAGE_SIZE } from "../constants";
import { StatusBadge } from "@/components/StatusBadge"; import { StatusBadge } from "@/components/StatusBadge";
import { basicTimeFormat } from "@/util/timeFormat"; import { basicTimeFormat } from "@/util/timeFormat";
import { QueuedTasks } from "../running/QueuedTasks"; import { QueuedTasks } from "../running/QueuedTasks";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
function TaskList() { function TaskList() {
const navigate = useNavigate(); const navigate = useNavigate();
@@ -52,19 +59,11 @@ function TaskList() {
placeholderData: keepPreviousData, placeholderData: keepPreviousData,
}); });
if (isPending) {
return <TaskListSkeleton />;
}
if (isError) { if (isError) {
return <div>Error: {error?.message}</div>; return <div>Error: {error?.message}</div>;
} }
if (!tasks) { const resolvedTasks = tasks?.filter(
return null;
}
const resolvedTasks = tasks.filter(
(task) => (task) =>
task.status === "completed" || task.status === "completed" ||
task.status === "failed" || task.status === "failed" ||
@@ -72,14 +71,37 @@ function TaskList() {
); );
return ( return (
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-8 max-w-5xl mx-auto">
<h1 className="text-2xl py-2 border-b-2">Running Tasks</h1> <Card>
<CardHeader className="border-b-2">
<CardTitle className="text-xl">Running Tasks</CardTitle>
<CardDescription>Tasks that are currently running</CardDescription>
</CardHeader>
<CardContent className="p-4">
<div className="grid grid-cols-4 gap-4"> <div className="grid grid-cols-4 gap-4">
<RunningTasks /> <RunningTasks />
</div> </div>
<h1 className="text-2xl py-2 border-b-2">Queued Tasks</h1> </CardContent>
</Card>
<Card>
<CardHeader className="border-b-2">
<CardTitle className="text-xl">Queued Tasks</CardTitle>
<CardDescription>Tasks that are waiting to run</CardDescription>
</CardHeader>
<CardContent className="p-4">
<QueuedTasks /> <QueuedTasks />
<h1 className="text-2xl py-2 border-b-2">Task History</h1> </CardContent>
</Card>
<Card>
<CardHeader className="border-b-2">
<CardTitle className="text-xl">Task History</CardTitle>
<CardDescription>Tasks you have run previously</CardDescription>
</CardHeader>
<CardContent className="p-4">
{isPending ? (
<TaskListSkeleton />
) : (
<>
<Table> <Table>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
@@ -94,7 +116,7 @@ function TaskList() {
<TableCell colSpan={3}>No tasks found</TableCell> <TableCell colSpan={3}>No tasks found</TableCell>
</TableRow> </TableRow>
) : ( ) : (
resolvedTasks.map((task) => { resolvedTasks?.map((task) => {
return ( return (
<TableRow <TableRow
key={task.task_id} key={task.task_id}
@@ -103,7 +125,9 @@ function TaskList() {
navigate(task.task_id); navigate(task.task_id);
}} }}
> >
<TableCell className="w-1/3">{task.request.url}</TableCell> <TableCell className="w-1/3">
{task.request.url}
</TableCell>
<TableCell className="w-1/3"> <TableCell className="w-1/3">
<StatusBadge status={task.status} /> <StatusBadge status={task.status} />
</TableCell> </TableCell>
@@ -147,6 +171,10 @@ function TaskList() {
</PaginationItem> </PaginationItem>
</PaginationContent> </PaginationContent>
</Pagination> </Pagination>
</>
)}
</CardContent>
</Card>
</div> </div>
); );
} }

View File

@@ -8,7 +8,7 @@ import {
TableRow, TableRow,
} from "@/components/ui/table"; } from "@/components/ui/table";
const pageSizeArray = new Array(15).fill(null); // doesn't matter the value const pageSizeArray = new Array(5).fill(null); // doesn't matter the value
function TaskListSkeleton() { function TaskListSkeleton() {
return ( return (
@@ -26,13 +26,13 @@ function TaskListSkeleton() {
return ( return (
<TableRow key={index}> <TableRow key={index}>
<TableCell className="w-1/3"> <TableCell className="w-1/3">
<Skeleton className="w-full h-full" /> <Skeleton className="w-full h-4" />
</TableCell> </TableCell>
<TableCell className="w-1/3"> <TableCell className="w-1/3">
<Skeleton className="w-full h-full" /> <Skeleton className="w-full h-4" />
</TableCell> </TableCell>
<TableCell className="w-1/3"> <TableCell className="w-1/3">
<Skeleton className="w-full h-full" /> <Skeleton className="w-full h-4" />
</TableCell> </TableCell>
</TableRow> </TableRow>
); );

View File

@@ -28,6 +28,10 @@ function QueuedTasks() {
?.filter((task) => task.status === Status.Queued) ?.filter((task) => task.status === Status.Queued)
.slice(0, 10); .slice(0, 10);
if (queuedTasks?.length === 0) {
return <div>No queued tasks</div>;
}
return ( return (
<Table> <Table>
<TableHeader> <TableHeader>