6c605849d8
- /api/workspaces and `agenthub workspace(s)` / `--workspace` as aliases of /api/lanes and `agenthub lanes` / `--lane`; old names print one stderr note. REPL `help lanes|workspace|workspaces` resolves through the aliases. - A workspace holds up to ten sessions (slots 0-9); every console tab is a group of 1-4 split panes (PaneGroups, agenthub.workspace.paneLayout); parseGroups keeps the stored active tab when an earlier one is dropped. - Browse button beside path fields: POST /api/lanes/pick-path opens the OS picker on the server's desktop — loopback only and no forwarding header (EREMOTE), a display failure is ENODIALOG not a Cancel, the dialog is killed when the request closes, a folder field falls back to the in-app browser on any failure. - Changes rail counts chip, image viewer (/git/raw), status bar session counts and per-day cost (`date=` on /api/pricing/cost). - /agenthub-open and /agenthub-doctor run from the INSTALLED build (supersededBy), doctor offers fixes behind two confirmations; plugin-open treats a locked bootstrap as non-fatal. - New-terminal shell waits for the first attach (issue #55). - repo-onboarding / debug-live-issue skills removed. - OpenAPI: pick-path, lane/date on /pricing/cost, tool on /run/history, /api/workspaces mount.
58 lines
1.9 KiB
TypeScript
58 lines
1.9 KiB
TypeScript
/**
|
|
* @file WorkspaceRowMenu — the sidebar workspace row's context menu, opened at
|
|
* the pointer (right-click) or under the row's `⋯` button. Every item is an
|
|
* existing call: Rename (the row's inline field), New workspace here (the
|
|
* Add modal prefilled), Copy path, and Reset/Remove through `DestructiveLaneModal` — Reset only on a
|
|
* managed lane. The server's guards are the real ones; the menu only hides
|
|
* what the lane's kind or tool makes meaningless. The shell (position,
|
|
* Escape / outside-click close) is `ContextMenu`.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
import { useTranslation } from "react-i18next";
|
|
import type { Lane } from "../../lib/types";
|
|
import { ContextMenu, MenuItem, MenuSeparator } from "../ContextMenu";
|
|
import { copyText } from "../../lib/clipboard";
|
|
|
|
export type WorkspaceMenuAction = "rename" | "new-here" | "reset" | "remove";
|
|
|
|
export function WorkspaceRowMenu({
|
|
lane,
|
|
x,
|
|
y,
|
|
onClose,
|
|
onAction,
|
|
}: {
|
|
lane: Lane;
|
|
x: number;
|
|
y: number;
|
|
onClose: () => void;
|
|
/** Items the tree itself carries out (rename field, modals). */
|
|
onAction: (action: WorkspaceMenuAction) => void;
|
|
}) {
|
|
const { t } = useTranslation("lanes");
|
|
return (
|
|
<ContextMenu x={x} y={y} onClose={onClose} testId={`workspace-row-menu-${lane.id}`}>
|
|
<MenuItem onSelect={() => onAction("rename")}>{t("menu.rename")}</MenuItem>
|
|
<MenuItem onSelect={() => onAction("new-here")}>{t("menu.newHere")}</MenuItem>
|
|
<MenuItem
|
|
onSelect={() => {
|
|
onClose();
|
|
void copyText(lane.cwd);
|
|
}}
|
|
>
|
|
{t("menu.copyPath")}
|
|
</MenuItem>
|
|
<MenuSeparator />
|
|
{lane.kind === "managed" && (
|
|
<MenuItem danger onSelect={() => onAction("reset")}>
|
|
{t("menu.reset")}
|
|
</MenuItem>
|
|
)}
|
|
<MenuItem danger onSelect={() => onAction("remove")}>
|
|
{t("menu.remove")}
|
|
</MenuItem>
|
|
</ContextMenu>
|
|
);
|
|
}
|