Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
"use client";

import { useEffect, useRef, useState } from "react";
import { Loader2 } from "lucide-react";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Skeleton } from "@/components/ui/skeleton";

type TrajectoryPageProps = {
trajectoryUrl: string;
fallbackUrl: string;
stderrText: string | null;
verifierText: string | null;
topOffsetClassName?: string;
};

export function TrajectoryPage({
trajectoryUrl,
fallbackUrl,
stderrText,
verifierText,
topOffsetClassName = "top-28",
}: TrajectoryPageProps) {
const [iframeLoading, setIframeLoading] = useState(false);
const [activeTab, setActiveTab] = useState("trajectory");
Expand Down Expand Up @@ -54,46 +52,40 @@ export function TrajectoryPage({
};

return (
<div className="fixed inset-0 w-full h-full">
<div className={`absolute inset-x-0 ${topOffsetClassName} bottom-4 sm:bottom-6`}>
<div className="mx-auto h-full w-full max-w-[1400px] px-4 sm:px-7 lg:px-10">
<div className="h-full w-full pb-4 pt-4 sm:pb-6 sm:pt-5">
<div className="mx-auto h-full w-full max-w-[1400px] px-4 sm:px-7 lg:px-10">
<Tabs
value={activeTab}
onValueChange={setActiveTab}
className="h-full gap-0 overflow-hidden rounded-xl border border-border/60 bg-background/70 backdrop-blur-sm shadow-sm"
className="flex h-full min-h-0 flex-col gap-0 overflow-hidden rounded-xl border border-border bg-background/70 backdrop-blur-sm shadow-sm"
>
<div className="border-b border-border/50 bg-background/50 px-3 py-3 sm:px-4">
<TabsList className="grid h-11 w-[300px] max-w-full grid-cols-3 items-stretch gap-1 border border-border/40 bg-background/60 p-1">
<div className="border-b border-border bg-background/40 px-3 py-3 sm:px-4">
<TabsList className="grid h-11 w-[300px] max-w-full grid-cols-3 items-stretch gap-1 rounded-xl bg-muted/55 p-1">
<TabsTrigger
value="trajectory"
className="h-full w-full cursor-pointer border border-transparent py-0 leading-none text-muted-foreground transition-colors hover:bg-primary/10 hover:text-foreground data-[state=active]:border-primary/35 data-[state=active]:bg-primary/18 data-[state=active]:text-foreground data-[state=active]:shadow-none"
className="h-full w-full cursor-pointer rounded-lg border-0 py-0 leading-none text-muted-foreground transition-colors hover:bg-primary/10 hover:text-foreground data-[state=active]:bg-primary/18 data-[state=active]:text-foreground data-[state=active]:shadow-none"
>
Trajectory
</TabsTrigger>
<TabsTrigger
value="log"
className="h-full w-full cursor-pointer border border-transparent py-0 leading-none text-muted-foreground transition-colors hover:bg-primary/10 hover:text-foreground data-[state=active]:border-primary/35 data-[state=active]:bg-primary/18 data-[state=active]:text-foreground data-[state=active]:shadow-none"
className="h-full w-full cursor-pointer rounded-lg border-0 py-0 leading-none text-muted-foreground transition-colors hover:bg-primary/10 hover:text-foreground data-[state=active]:bg-primary/18 data-[state=active]:text-foreground data-[state=active]:shadow-none"
>
Log
</TabsTrigger>
<TabsTrigger
value="test"
className="h-full w-full cursor-pointer border border-transparent py-0 leading-none text-muted-foreground transition-colors hover:bg-primary/10 hover:text-foreground data-[state=active]:border-primary/35 data-[state=active]:bg-primary/18 data-[state=active]:text-foreground data-[state=active]:shadow-none"
className="h-full w-full cursor-pointer rounded-lg border-0 py-0 leading-none text-muted-foreground transition-colors hover:bg-primary/10 hover:text-foreground data-[state=active]:bg-primary/18 data-[state=active]:text-foreground data-[state=active]:shadow-none"
>
Test
</TabsTrigger>
</TabsList>
</div>

<TabsContent value="trajectory" className="relative min-h-0 overflow-hidden" forceMount>
<TabsContent value="trajectory" className="relative min-h-0 flex-1 overflow-hidden px-2" forceMount>
{iframeLoading && (
<div className="absolute inset-0 z-10 flex flex-col items-center justify-center space-y-6 bg-background/80 backdrop-blur-sm">
<div className="relative flex items-center justify-center">
<Loader2 className="relative z-10 h-12 w-12 animate-spin text-primary" />
</div>
<div className="space-y-2 text-center">
<h2 className="text-lg font-semibold tracking-tight text-foreground">Loading</h2>
</div>
<div className="absolute inset-0 z-10 overflow-auto bg-background/80 backdrop-blur-sm">
<TrajectorySkeleton />
</div>
)}
<iframe
Expand All @@ -106,24 +98,49 @@ export function TrajectoryPage({
/>
</TabsContent>

<TabsContent value="log" className="min-h-0 overflow-hidden" forceMount>
<TabsContent value="log" className="min-h-0 flex-1 overflow-hidden" forceMount>
<ScrollArea className="h-full w-full">
<div className="px-3 pb-4 pt-2 sm:px-4 sm:pb-5 sm:pt-3">
{renderLogContent(stderrText, "No stderr content available for this trial.")}
</div>
</ScrollArea>
</TabsContent>

<TabsContent value="test" className="min-h-0 overflow-hidden" forceMount>
<TabsContent value="test" className="min-h-0 flex-1 overflow-hidden" forceMount>
<ScrollArea className="h-full w-full">
<div className="px-3 pb-4 pt-2 sm:px-4 sm:pb-5 sm:pt-3">
{renderLogContent(verifierText, "No verifier test output available for this trial.")}
</div>
</ScrollArea>
</TabsContent>
</Tabs>
</div>
</div>
);
}

function TrajectorySkeleton() {
return (
<div className="animate-pulse space-y-2 p-4">
<div className="flex items-center space-x-3">
<Skeleton className="size-6 rounded-full" />
<Skeleton className="h-4 w-16" />
</div>
<div className="space-y-2 pt-1">
<Skeleton className="h-4 w-[80%]" />
<Skeleton className="h-4 w-[50%]" />
</div>
<div className="mt-8 flex items-center space-x-3">
<div className="flex items-center space-x-3">
<Skeleton className="size-6 rounded-full" />
<Skeleton className="h-4 w-16" />
</div>
</div>
<div className="space-y-2 pt-1">
<Skeleton className="h-4 w-[80%]" />
<Skeleton className="h-4 w-[80%]" />
<Skeleton className="h-4 w-[50%]" />
</div>
</div>
);
}
56 changes: 34 additions & 22 deletions site/app/tasks/[name]/[jobId]/trajectory/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import type { CSSProperties } from "react";
import tasksData from "@/zealt/tasks.json";
import { TrajectoryPage } from "./components/trajectory-page";
import zealtConfig from "@/zealt/config.json";
import { redirect } from "next/navigation";
import { AlertTriangle, Check, HelpCircle, X as XIcon } from "lucide-react";
import { AlertTriangle, Check, ExternalLink, HelpCircle, X as XIcon } from "lucide-react";


type RouteParams = {
Expand Down Expand Up @@ -135,6 +134,10 @@ function buildFallbackUrl(jobName: string, trialName: string) {
return `${zealtConfig.github_repo}/blob/main/jobs/${jobName}/${trialName}/result.json`
}

function buildTaskDirUrl(taskName: string) {
return `${zealtConfig.github_repo}/tree/main/tasks/${encodeURIComponent(taskName)}`;
}

function splitTrialName(trialName: string): { taskName: string; jobId: string } | null {
const separatorIndex = trialName.lastIndexOf("__");
if (separatorIndex <= 0 || separatorIndex >= trialName.length - 2) {
Expand All @@ -148,7 +151,7 @@ function splitTrialName(trialName: string): { taskName: string; jobId: string }
}

function getServerBaseUrl() {
return process.env.CLIPS_BASE_URL || 'https://cc.getpochi.com';
return process.env.CLIPS_BASE_URL || 'https://fletch.getpochi.com';
}

function getGithubOwnerRepo(): string {
Expand Down Expand Up @@ -267,32 +270,40 @@ export default async function TrajectoryRoutePage({
const trialStatus = getTrialStatus(trialEntry);
const statusMeta = getStatusMeta(trialStatus);
const StatusIcon = statusMeta.Icon;
const contentTopOffsetClassName = "top-36 sm:top-32 lg:top-28";
const taskDirUrl = buildTaskDirUrl(resolvedParams.name);

const trajectoryUrl = clipId && trialEntry
? buildClipUrl(trialEntry.job_name, trialEntry.trial_name, resolvedParams.name)
: null;

// FIXME
if (!trajectoryUrl) {
// Redirect
if (!trajectoryUrl || !trialEntry) {
redirect(fallbackUrl ?? '/tasks');
}

const stderrText = trialEntry?.stderr_text ?? null;
const verifierText = trialEntry?.verifier_text ?? null;
const pageThemeVars = {
"--background": "oklch(0.268 0.004 106.643)",
"--border": "oklch(0.362 0.01 106.893)",
} as CSSProperties;

return (
<div style={pageThemeVars} className="w-full h-screen bg-background text-foreground font-sans selection:bg-primary/20 overflow-hidden">
<div className="flex h-screen w-full flex-col overflow-hidden bg-background text-foreground font-sans selection:bg-primary/20">
<div className="fixed inset-0 -z-10 h-full w-full bg-background bg-[radial-gradient(#2a2a2a_1px,transparent_1px)] [background-size:16px_16px] [mask-image:radial-gradient(ellipse_50%_50%_at_50%_50%,#000_70%,transparent_100%)] opacity-20 dark:opacity-40"></div>
<div className="fixed inset-x-0 top-0 z-40 border-b border-border/50 bg-background/85 backdrop-blur-sm">
<div className="z-40 shrink-0 bg-background/85 backdrop-blur-sm">
<div className="mx-auto w-full max-w-[1400px] px-4 py-4 sm:px-7 lg:px-10">
<div className="flex flex-col gap-1">
<h1 className="truncate whitespace-nowrap font-bold text-2xl">
{headerTitle}
</h1>
<div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between sm:gap-3">
<h1 className="min-w-0 truncate whitespace-nowrap font-bold text-2xl sm:flex-1 sm:pr-4">
{headerTitle}
</h1>
<a
href={taskDirUrl}
target="_blank"
rel="noopener noreferrer"
className="group inline-flex w-fit shrink-0 items-center gap-1.5 whitespace-nowrap rounded-md border border-border/70 bg-background/40 px-2.5 py-1 text-xs text-muted-foreground transition-colors hover:bg-secondary/45 hover:text-foreground sm:text-sm"
>
<ExternalLink className="h-4 w-4" />
<span>Task</span>
</a>
</div>
<div className="mt-2 text-xs sm:text-sm">
<div className="flex flex-col gap-1 sm:flex-row sm:gap-4">
<span className={`inline-flex shrink-0 items-center gap-0 font-medium`}>
Expand All @@ -306,13 +317,14 @@ export default async function TrajectoryRoutePage({
</div>
</div>
</div>
<TrajectoryPage
trajectoryUrl={trajectoryUrl}
fallbackUrl={fallbackUrl ?? ''}
stderrText={stderrText}
verifierText={verifierText}
topOffsetClassName={contentTopOffsetClassName}
/>
<div className="min-h-0 flex-1">
<TrajectoryPage
trajectoryUrl={trajectoryUrl}
fallbackUrl={fallbackUrl ?? ''}
stderrText={stderrText}
verifierText={verifierText}
/>
</div>
</div>
);
}
4 changes: 2 additions & 2 deletions site/app/tasks/components/tasks-page-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ export function TasksPageClient({ tasksData }: TasksPageClientProps) {
};

const selectedTaskInstructionUrl = selectedTask
? `${zealtConfig.github_repo}/tree/main/tasks/${selectedTask}/instruction.md`
? `${zealtConfig.github_repo}/tree/main/tasks/${selectedTask}`
: "";

const selectedTaskInstruction = selectedTask
Expand Down Expand Up @@ -378,7 +378,7 @@ export function TasksPageClient({ tasksData }: TasksPageClientProps) {
<Button variant="outline" asChild className="h-8 w-full text-xs sm:h-9 sm:w-auto sm:text-sm">
<a href={selectedTaskInstructionUrl} target="_blank" rel="noopener noreferrer">
<ExternalLink className="h-4 w-4" />
Open instruction.md
Open
</a>
</Button>
</div>
Expand Down
Loading