A behavior node that cannot run looked exactly like a healthy one: no start node, no behavior picked, a deleted behavior or a self-call were all silently skipped. The call still had to be forgiving at runtime -- a dangling reference must not abort a game -- so the fix is diagnosis, not an exception: describeProblem() names the one reason, the node draws it in red under its title, and the inspector repeats it where you pick the behavior. A missing end node is deliberately not a problem: a call is always synchronous, and the end node only decides which values come back. Two ways in: a behavior dragged from the asset panel lands in the graph under the pointer, and double-clicking a call node opens the graph it runs. Both reuse machinery that already existed -- the asset panel already starts the drag, and list views already report double clicks. The e2e module needed its assets at the head of the asset list: after 18 modules the list is long enough that a newly appended row scrolls out of view, and the press then lands on the panel behind it, starting no drag at all. That looked exactly like a rejected drop and cost two full runs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
30 lines
970 B
TypeScript
30 lines
970 B
TypeScript
import { Label, type TextField, type VStack } from '../../ui';
|
|
import type { EditorState } from '../state';
|
|
import type { FieldContext, FieldRow } from './fieldFactory';
|
|
|
|
/** What the inspector sections build into: the panel body and the registry of rows. */
|
|
export interface InspectorHost extends FieldContext {
|
|
readonly state: EditorState;
|
|
readonly body: VStack;
|
|
/** Rows by key; live refreshes and highlight updates find them here. */
|
|
readonly fields: Map<string, FieldRow>;
|
|
/** The name field at the top, when the selection has a name. */
|
|
nameField: TextField | null;
|
|
}
|
|
|
|
export function addTitle(host: InspectorHost, text: string): void {
|
|
host.body.add(new Label(text, { style: 'title' }));
|
|
}
|
|
|
|
export function addNote(
|
|
host: InspectorHost,
|
|
text: string,
|
|
style: 'muted' | 'small' | 'warning' = 'muted',
|
|
): void {
|
|
host.body.add(new Label(text, { style }));
|
|
}
|
|
|
|
export function addGap(host: InspectorHost): void {
|
|
host.body.add(new Label(''));
|
|
}
|