e94cf6de83
Co-authored-by: Kandev Agent <agent@kandev.dev>
88 lines
3.2 KiB
TypeScript
88 lines
3.2 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* DockviewLayout — generalised dockview shell shared by both task
|
|
* detail routes. Takes (executionId, sessionId, kind). When
|
|
* `executionId` is null the agent is dormant: render a read-only
|
|
* banner + chat-history pane, with terminal & prompt input disabled.
|
|
*
|
|
* The "active" path delegates to the existing OfficeDockviewLayout for
|
|
* office tasks (no sidebar / no multi-session) and the kanban
|
|
* DockviewDesktopLayout for kanban tasks (sidebar + persistence).
|
|
*
|
|
* Phase 7 NOTE: dormant mode does NOT spin up a read-only agentctl —
|
|
* the file tree + chat history are sourced from the worktree on disk
|
|
* and the runtime-tier `agent_messages` table respectively. v1 has no
|
|
* "open a shell anyway" affordance (decision pinned in plan.md F7.4).
|
|
*/
|
|
|
|
import dynamic from "@/lib/routing/client-dynamic";
|
|
import { IconClock } from "@tabler/icons-react";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
const OfficeDockviewLayout = dynamic(
|
|
() =>
|
|
import("@/app/office/tasks/[id]/office-dockview-layout").then((m) => ({
|
|
default: m.OfficeDockviewLayout,
|
|
})),
|
|
{ ssr: false },
|
|
);
|
|
|
|
export type DockviewLayoutKind = "kanban" | "office";
|
|
|
|
export type DockviewLayoutProps = {
|
|
/** Null when the agent is between turns ("dormant"). */
|
|
executionId: string | null;
|
|
sessionId: string | null;
|
|
taskId: string;
|
|
/** Picks dormant-state messaging only. Active path is unaffected. */
|
|
kind?: DockviewLayoutKind;
|
|
};
|
|
|
|
/**
|
|
* Pure helper — exported for tests. Returns true when the layout
|
|
* should render the dormant placeholder instead of the live dockview.
|
|
*/
|
|
export function isDormant(executionId: string | null | undefined): boolean {
|
|
return executionId === null || executionId === undefined;
|
|
}
|
|
|
|
function DormantPanel({ kind }: { kind: DockviewLayoutKind }) {
|
|
const { t } = useTranslation();
|
|
const verb = kind === "office" ? "Routine" : "Agent";
|
|
return (
|
|
<div className="flex flex-1 flex-col items-center justify-center bg-background min-h-0 p-8">
|
|
<div
|
|
role="status"
|
|
className="flex max-w-md flex-col items-center gap-3 rounded-lg border border-dashed border-border bg-muted/30 p-8 text-center"
|
|
>
|
|
<IconClock className="h-8 w-8 text-muted-foreground" aria-hidden="true" />
|
|
<h2 className="text-base font-semibold">{t("task:verbIsDormant", { verb })}</h2>
|
|
<p className="text-sm text-muted-foreground">{t("task:theAgentHasFinishedItsLast")}</p>
|
|
<p className="text-xs text-muted-foreground">
|
|
{t("task:terminalPromptInputAreDisabledUntil")}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function DockviewLayout({
|
|
executionId,
|
|
sessionId,
|
|
taskId,
|
|
kind = "office",
|
|
}: DockviewLayoutProps) {
|
|
if (isDormant(executionId)) {
|
|
return <DormantPanel kind={kind} />;
|
|
}
|
|
|
|
// Active path: delegate to the existing per-kind dockview layout.
|
|
// Kanban's DockviewDesktopLayout has a richer interface (workspace,
|
|
// workflow, repository, scripts...) that needs SSR-fetched data; the
|
|
// kanban shell renders it directly via TaskPageContent. The shared
|
|
// entry point below covers the office case which only needs
|
|
// (taskId, sessionId).
|
|
return <OfficeDockviewLayout taskId={taskId} sessionId={sessionId} />;
|
|
}
|