Welcome back! in the previous chapter, Hooks Config Menu, we built the "brain" of our applicationβthe router that decides which screen to show.
Now, we are going to build the first screen the user actually sees: the Event Selection Mode.
Imagine walking into a massive department store. You are looking for a specific pair of running shoes. You don't immediately start looking at every single item in the store. Instead, you look at the Directory:
You select Men's Clothing, and then you go deeper.
The Event Selection Mode is that directory. We have many hooks (scripts), but they are organized by when they run (the "Event").
The Problem: A user has 50 different hooks configured. They want to check a script that cleans up data after a tool finishes. If we showed a list of all 50 hooks, it would be a mess.
The Solution: We present a high-level list of "Lifecycles" (Events). The user clicks "PostToolExecution", and we only show them the hooks inside that category.
Before we code, let's look at how data flows through this component.
To build this, we need to understand three simple concepts:
(3 hooks)). This saves the user time; they won't click an empty category.
Let's look at SelectEventMode.tsx. We will break the code down into the logic that prepares the data and the logic that renders the list.
The component receives a list of events. We need to transform this raw data into a format that our generic <Select /> component can understand. We need a label (what the user sees), a value (the ID), and a description.
// We map over the metadata to create menu options
const options = Object.entries(hookEventMetadata).map(([name, metadata]) => {
// Get the count of hooks for this specific event
const count = hooksByEvent[name] || 0;
return {
// If hooks exist, show the name AND the count (e.g., "PreToolUse (5)")
label: count > 0 ? `${name} (${count})` : name,
value: name,
description: metadata.summary // e.g., "Runs before a tool..."
};
});
Explanation:
.map() to loop through every available event type.hooksByEvent to see if the user has any scripts for this event.Sometimes, an administrator might disable hooks entirely for security reasons. We should visually warn the user if this is happening.
// Check if policies restrict hooks
const policyWarning = restrictedByPolicy ? (
<Box flexDirection="column">
<Text color="suggestion">Hooks Restricted by Policy</Text>
<Text dimColor>Only managed settings can run.</Text>
</Box>
) : null;
Explanation:
restrictedByPolicy is true, we create a small UI box with a warning message.policyWarning is null and nothing shows up.
Finally, we return the JSX (the UI layout). We use a Dialog to frame the content and the Select component to show the list we created in Step 1.
return (
<Dialog title="Hooks" onCancel={onCancel}>
<Box flexDirection="column" gap={1}>
{/* 1. Show warning if needed */}
{policyWarning}
{/* 2. Show the interactive list */}
<Select
options={options}
onChange={(value) => onSelectEvent(value)} // Pass selection to parent
onCancel={onCancel}
/>
</Box>
</Dialog>
);
Explanation:
<Dialog>: Draws a box around our content with a title.onSelectEvent(value): This is the most crucial line. When the user hits "Enter" on an option, this function tells the parent (Hooks Config Menu) to change the state.In this chapter, we built the Event Selection Mode.
When the user makes a selection here, the parent component captures the event name (e.g., PreToolUse) and switches the view.
What happens next? Now that the user has chosen a category (like "PreToolUse"), we need to ask them how they want to filter those hooks. Do they want to match a specific tool name? Or all tools?
Let's move on to Chapter 3: Matcher Selection Mode.
Generated by Code IQ