feat(workspace): split menus start AI tools; drop the Tools menu
A pane's split right/down menus offered only New terminal. They now list the same AI tools as the tab bar's + menu (newTabTools/newTabBody, shared from ConsoleTabs), started bare in the first free slot on that side of the pane. The tab bar's Tools menu is gone: its readme run hit 409 ERUNLIVE whenever slot 0 was live (always, in the session view) and depended on a personal skill; MCP sync and the dev-sync check served the dormant ship-feature-lane pipeline. The sidebar row menu's readme item goes too. The routes stay, reached by `agenthub lanes mcp sync` and `agenthub lanes sync-base`. Also: the home's Memory header and file tabs no longer shrink (a long file squeezed the tab row and clipped it).
This commit is contained in:
@@ -17,16 +17,7 @@
|
||||
|
||||
import { useCallback, useEffect, useRef, useState, type ReactNode } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
Check,
|
||||
ChevronDown,
|
||||
Columns2,
|
||||
GripVertical,
|
||||
Plus,
|
||||
Rows2,
|
||||
SquareTerminal,
|
||||
X,
|
||||
} from "lucide-react";
|
||||
import { Check, ChevronDown, Columns2, GripVertical, Rows2, SquareTerminal, X } from "lucide-react";
|
||||
import type { RunHandle } from "../../lib/api";
|
||||
import { ContextMenu, MenuItem, MenuSeparator, useContextMenu } from "../ContextMenu";
|
||||
import {
|
||||
@@ -174,7 +165,7 @@ const ITEM =
|
||||
"flex w-full items-center gap-2.5 rounded-md px-2.5 py-1.5 text-left text-sm text-fg-secondary hover:bg-surface-4 hover:text-fg-primary";
|
||||
|
||||
/** A pane's split-right / split-down menus: move a hidden run beside
|
||||
* `slot`, or start a new terminal there. In a pane header when the view is
|
||||
* `slot`, or start a new terminal or AI tool there. In a pane header when the view is
|
||||
* split, beside Tools in the tab bar while one pane is shown. */
|
||||
export function SplitMenus({
|
||||
slot,
|
||||
@@ -183,6 +174,8 @@ export function SplitMenus({
|
||||
label,
|
||||
onChange,
|
||||
canStart,
|
||||
tools,
|
||||
toolLabel,
|
||||
onNewSplit,
|
||||
}: {
|
||||
slot: number;
|
||||
@@ -192,7 +185,11 @@ export function SplitMenus({
|
||||
label: (r: RunHandle) => string;
|
||||
onChange: LayoutUpdate;
|
||||
canStart: boolean;
|
||||
onNewSplit: (target: number, edge: Edge) => void;
|
||||
/** AI tool ids a new split can start, beside the terminal. */
|
||||
tools: string[];
|
||||
toolLabel: (id: string) => string;
|
||||
/** `tool`: an AI tool id; none — a terminal. */
|
||||
onNewSplit: (target: number, edge: Edge, tool?: string) => void;
|
||||
}) {
|
||||
const { t } = useTranslation("lanes");
|
||||
const full = shown.length >= MAX_PANES;
|
||||
@@ -246,9 +243,27 @@ export function SplitMenus({
|
||||
onNewSplit(slot, edge);
|
||||
}}
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
<SquareTerminal className="h-4 w-4" />
|
||||
{t("panes.newTerminal")}
|
||||
</button>
|
||||
{tools.map((id) => (
|
||||
<button
|
||||
key={id}
|
||||
type="button"
|
||||
role="menuitem"
|
||||
data-testid={`pane-split-new-${edge}-${slot}-${id}`}
|
||||
disabled={!canStart}
|
||||
title={canStart ? undefined : t("tabs.full")}
|
||||
className={`${ITEM} disabled:opacity-40 disabled:hover:bg-transparent`}
|
||||
onClick={() => {
|
||||
close();
|
||||
onNewSplit(slot, edge, id);
|
||||
}}
|
||||
>
|
||||
<AiToolIcon tool={{ id, label: toolLabel(id) }} className="h-4 w-4 !p-0" />
|
||||
{toolLabel(id)}
|
||||
</button>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</PaneMenu>
|
||||
@@ -265,6 +280,8 @@ export function PaneGrid({
|
||||
renderPane,
|
||||
onChange,
|
||||
canStart,
|
||||
tools,
|
||||
toolLabel,
|
||||
onNewSplit,
|
||||
}: {
|
||||
layout: PaneLayout;
|
||||
@@ -277,8 +294,11 @@ export function PaneGrid({
|
||||
onChange: LayoutUpdate;
|
||||
/** A slot is free for a new terminal. */
|
||||
canStart: boolean;
|
||||
/** Start a new terminal into a split of `target`. */
|
||||
onNewSplit: (target: number, edge: Edge) => void;
|
||||
/** AI tool ids a new split can start, beside the terminal. */
|
||||
tools: string[];
|
||||
toolLabel: (id: string) => string;
|
||||
/** Start a new terminal (or AI tool) into a split of `target`. */
|
||||
onNewSplit: (target: number, edge: Edge, tool?: string) => void;
|
||||
}) {
|
||||
const { t } = useTranslation("lanes");
|
||||
const gridRef = useRef<HTMLDivElement>(null);
|
||||
@@ -450,6 +470,8 @@ export function PaneGrid({
|
||||
label={label}
|
||||
onChange={onChange}
|
||||
canStart={canStart}
|
||||
tools={tools}
|
||||
toolLabel={toolLabel}
|
||||
onNewSplit={onNewSplit}
|
||||
/>
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user