Files
kandev/apps/web/components/task/task-layout.tsx
T
João Salavisa b277e7f1d8 feat: add chat-top-bar plugin slot (#1827)
* feat: add chat-top-bar plugin slot

Adds a new named plugin UI slot, chat-top-bar, rendered in the session
top bar beside the CPU/DB metrics and document/editor/debug controls.
Mirrors the existing chat-input-actions slot pattern: a wrapper
component (TaskTopBarPluginActions) assembles slotProps from the store
and renders <PluginSlot name="chat-top-bar" />, forwarding
{ taskId, taskTitle, workspaceId, activeSessionId, sessionIds }.

Updates PLUGIN-API.md, the public authoring guide, and the
PluginSlotName JSDoc to document the new slot. No backend changes
needed since slot names are an open string type.

* fix: address PR review — mobile chat-top-bar slot, gate by archived state

- Wire the chat-top-bar plugin slot into the mobile session top bar
  (session-mobile-top-bar.tsx), matching desktop's slotProps shape.
- Gate the plugin cluster behind !isArchived in TopBarRight, matching
  every other interactive control in that group (port-forward, PR/MR
  buttons, layout preset, editors menu).
- Extract RemoteExecutorIndicator, ApproveButton, and MobileTopBarDialogs
  to keep the mobile top bar under lint complexity/length limits.

* fix: gate mobile chat-top-bar plugin slot by archived state

Threads isArchived through TaskLayout -> SessionMobileLayout ->
SessionMobileTopBar -> MobileTopBarActions so the mobile top bar
hides plugin content on archived tasks, matching the desktop
TopBarRight behavior fixed in the previous commit.

---------

Co-authored-by: Kandev Agent <agent@kandev.dev>
2026-07-20 18:52:56 +01:00

114 lines
3.1 KiB
TypeScript

"use client";
import { memo } from "react";
import dynamic from "@/lib/routing/client-dynamic";
import { useResponsiveBreakpoint } from "@/hooks/use-responsive-breakpoint";
import { SessionMobileLayout, SessionTabletLayout } from "./mobile";
import type { Repository, RepositoryScript } from "@/lib/types/http";
import type { Terminal } from "@/hooks/domains/session/use-terminals";
import type { Layout } from "react-resizable-panels";
// Re-export for backwards compatibility
export type { SelectedDiff } from "@/hooks/use-session-layout-state";
// Dynamic import for dockview (no SSR)
const DockviewDesktopLayout = dynamic(
() => import("./dockview-desktop-layout").then((mod) => mod.DockviewDesktopLayout),
{ ssr: false },
);
type TaskLayoutProps = {
workspaceId: string | null;
workflowId: string | null;
sessionId?: string | null;
repository?: Repository | null;
initialScripts?: RepositoryScript[];
initialTerminals?: Terminal[];
defaultLayouts?: Record<string, Layout>;
taskTitle?: string;
baseBranch?: string;
worktreeBranch?: string | null;
isRemoteExecutor?: boolean;
remoteExecutorType?: string | null;
remoteExecutorName?: string | null;
remoteState?: string | null;
remoteCreatedAt?: string | null;
remoteCheckedAt?: string | null;
remoteStatusError?: string | null;
initialLayout?: string | null;
isArchived?: boolean;
};
export const TaskLayout = memo(function TaskLayout({
workspaceId,
workflowId,
sessionId = null,
repository = null,
initialScripts = [],
initialTerminals,
defaultLayouts = {},
taskTitle,
baseBranch,
worktreeBranch,
isRemoteExecutor,
remoteExecutorType,
remoteExecutorName,
remoteState,
remoteCreatedAt,
remoteCheckedAt,
remoteStatusError,
initialLayout,
isArchived,
}: TaskLayoutProps) {
const { isMobile, usesDesktopWorkbench, isFullDesktop } = useResponsiveBreakpoint();
// Mobile layout
if (isMobile) {
return (
<SessionMobileLayout
workspaceId={workspaceId}
workflowId={workflowId}
sessionId={sessionId}
baseBranch={baseBranch}
worktreeBranch={worktreeBranch}
taskTitle={taskTitle}
isRemoteExecutor={isRemoteExecutor}
remoteExecutorType={remoteExecutorType}
remoteExecutorName={remoteExecutorName}
remoteState={remoteState}
remoteCreatedAt={remoteCreatedAt}
remoteCheckedAt={remoteCheckedAt}
remoteStatusError={remoteStatusError}
isArchived={isArchived}
/>
);
}
// Tablet fallback for coarse-pointer half-screen devices.
if (!usesDesktopWorkbench) {
return (
<SessionTabletLayout
workspaceId={workspaceId}
workflowId={workflowId}
sessionId={sessionId}
repository={repository}
defaultLayouts={defaultLayouts}
/>
);
}
// Desktop layout - dockview
return (
<DockviewDesktopLayout
workspaceId={workspaceId}
workflowId={workflowId}
sessionId={sessionId}
repository={repository}
initialScripts={initialScripts}
initialTerminals={initialTerminals}
initialLayout={initialLayout}
compact={!isFullDesktop}
/>
);
});