feat: add disable all hook toggle (#726)
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
// Interactive TUI for managing hooks configuration
|
||||
|
||||
import { Box, Text, useInput } from "ink";
|
||||
import { memo, useCallback, useEffect, useState } from "react";
|
||||
import { memo, useCallback, useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
type HookEvent,
|
||||
type HookMatcher,
|
||||
@@ -18,11 +18,14 @@ import {
|
||||
countTotalHooks,
|
||||
type HookMatcherWithSource,
|
||||
type HookWithSource,
|
||||
isUserHooksDisabled,
|
||||
loadMatchersWithSource,
|
||||
loadSimpleMatchersWithSource,
|
||||
removeHook,
|
||||
type SaveLocation,
|
||||
setHooksDisabled,
|
||||
} from "../../hooks/writer";
|
||||
import { settingsManager } from "../../settings-manager";
|
||||
import { useTerminalWidth } from "../hooks/useTerminalWidth";
|
||||
import { colors } from "./colors";
|
||||
import { PasteAwareTextInput } from "./PasteAwareTextInput";
|
||||
@@ -145,6 +148,9 @@ export const HooksManager = memo(function HooksManager({
|
||||
// Dynamic tool names from agent
|
||||
const [toolNames, setToolNames] = useState<string[]>(FALLBACK_TOOL_NAMES);
|
||||
|
||||
// Track whether all hooks are disabled
|
||||
const [hooksDisabled, setHooksDisabledState] = useState(isUserHooksDisabled);
|
||||
|
||||
// Fetch agent tools on mount
|
||||
useEffect(() => {
|
||||
if (!agentId) return;
|
||||
@@ -188,9 +194,30 @@ export const HooksManager = memo(function HooksManager({
|
||||
// Refresh counts - called when hooks change
|
||||
const refreshCounts = useCallback(() => {
|
||||
setTotalHooks(countTotalHooks());
|
||||
setHooksDisabledState(isUserHooksDisabled());
|
||||
}, []);
|
||||
|
||||
// Load total hooks count on mount and when returning to events screen
|
||||
// Track if initial settings load has been done
|
||||
const initialLoadDone = useRef(false);
|
||||
|
||||
// Ensure settings are loaded before counting hooks (runs once on mount)
|
||||
useEffect(() => {
|
||||
if (initialLoadDone.current) return;
|
||||
initialLoadDone.current = true;
|
||||
|
||||
const loadSettings = async () => {
|
||||
try {
|
||||
await settingsManager.loadProjectSettings();
|
||||
await settingsManager.loadLocalProjectSettings();
|
||||
} catch {
|
||||
// Settings may already be loaded or not available
|
||||
}
|
||||
refreshCounts();
|
||||
};
|
||||
loadSettings();
|
||||
}, [refreshCounts]);
|
||||
|
||||
// Refresh counts when returning to events screen
|
||||
useEffect(() => {
|
||||
if (screen === "events") {
|
||||
refreshCounts();
|
||||
@@ -267,6 +294,13 @@ export const HooksManager = memo(function HooksManager({
|
||||
setSelectedIndex(0);
|
||||
}, [deleteHookIndex, selectedEvent, hooks, loadHooks, refreshCounts]);
|
||||
|
||||
// Handle toggling the "disable all hooks" setting
|
||||
const handleToggleDisableAll = useCallback(() => {
|
||||
const newValue = !hooksDisabled;
|
||||
setHooksDisabled(newValue);
|
||||
setHooksDisabledState(newValue);
|
||||
}, [hooksDisabled]);
|
||||
|
||||
useInput((input, key) => {
|
||||
// CTRL-C: immediately cancel
|
||||
if (key.ctrl && input === "c") {
|
||||
@@ -276,17 +310,26 @@ export const HooksManager = memo(function HooksManager({
|
||||
|
||||
// Handle each screen
|
||||
if (screen === "events") {
|
||||
// Total items: 1 (disable toggle) + HOOK_EVENTS.length
|
||||
const totalItems = 1 + HOOK_EVENTS.length;
|
||||
|
||||
if (key.upArrow) {
|
||||
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
||||
} else if (key.downArrow) {
|
||||
setSelectedIndex((prev) => Math.min(HOOK_EVENTS.length - 1, prev + 1));
|
||||
setSelectedIndex((prev) => Math.min(totalItems - 1, prev + 1));
|
||||
} else if (key.return) {
|
||||
const selected = HOOK_EVENTS[selectedIndex];
|
||||
if (selected) {
|
||||
setSelectedEvent(selected.event);
|
||||
loadHooks(selected.event);
|
||||
setScreen("hooks-list");
|
||||
setSelectedIndex(0);
|
||||
if (selectedIndex === 0) {
|
||||
// Toggle "disable all hooks"
|
||||
handleToggleDisableAll();
|
||||
} else {
|
||||
// Select a hook event (index is shifted by 1)
|
||||
const selected = HOOK_EVENTS[selectedIndex - 1];
|
||||
if (selected) {
|
||||
setSelectedEvent(selected.event);
|
||||
loadHooks(selected.event);
|
||||
setScreen("hooks-list");
|
||||
setSelectedIndex(0);
|
||||
}
|
||||
}
|
||||
} else if (key.escape) {
|
||||
onClose();
|
||||
@@ -372,20 +415,45 @@ export const HooksManager = memo(function HooksManager({
|
||||
|
||||
// Render Events List
|
||||
if (screen === "events") {
|
||||
const disableToggleSelected = selectedIndex === 0;
|
||||
const disableToggleLabel = hooksDisabled
|
||||
? "Enable all hooks"
|
||||
: "Disable all hooks";
|
||||
const titleBase = " Hooks";
|
||||
const titleSuffix = hooksDisabled ? " (disabled)" : "";
|
||||
const hooksCountText = `${totalHooks} hooks `;
|
||||
const titlePadding =
|
||||
boxWidth -
|
||||
titleBase.length -
|
||||
titleSuffix.length -
|
||||
hooksCountText.length -
|
||||
2;
|
||||
|
||||
return (
|
||||
<Box flexDirection="column" paddingX={1}>
|
||||
<Text>{boxTop(boxWidth)}</Text>
|
||||
<Text>
|
||||
{boxLine(
|
||||
` Hooks${" ".repeat(boxWidth - 20)}${totalHooks} hooks `,
|
||||
boxWidth,
|
||||
)}
|
||||
{BOX_VERTICAL}
|
||||
{titleBase}
|
||||
<Text color="red">{titleSuffix}</Text>
|
||||
{" ".repeat(Math.max(0, titlePadding))}
|
||||
{hooksCountText}
|
||||
{BOX_VERTICAL}
|
||||
</Text>
|
||||
<Text>{boxBottom(boxWidth)}</Text>
|
||||
<Text> </Text>
|
||||
|
||||
{/* Disable all hooks toggle - first item */}
|
||||
<Text>
|
||||
<Text color={disableToggleSelected ? colors.input.prompt : undefined}>
|
||||
{disableToggleSelected ? "❯" : " "} 1.
|
||||
</Text>
|
||||
<Text dimColor> {disableToggleLabel}</Text>
|
||||
</Text>
|
||||
|
||||
{/* Hook events */}
|
||||
{HOOK_EVENTS.map((item, index) => {
|
||||
const isSelected = index === selectedIndex;
|
||||
const isSelected = index + 1 === selectedIndex;
|
||||
const hookCount = countHooksForEvent(item.event);
|
||||
const prefix = isSelected ? "❯" : " ";
|
||||
const countStr = hookCount > 0 ? ` (${hookCount})` : "";
|
||||
@@ -393,7 +461,7 @@ export const HooksManager = memo(function HooksManager({
|
||||
return (
|
||||
<Text key={item.event}>
|
||||
<Text color={isSelected ? colors.input.prompt : undefined}>
|
||||
{prefix} {index + 1}. {item.event}
|
||||
{prefix} {index + 2}. {item.event}
|
||||
</Text>
|
||||
<Text dimColor> - {item.description}</Text>
|
||||
<Text color="yellow">{countStr}</Text>
|
||||
|
||||
Reference in New Issue
Block a user