Title a collapsed Variables or Properties node by what it does

Collapsed, the node reads "Set 2 variables", "Get width" or "No properties";
expanded it is always "Variables" / "Properties". The Properties node shows
its object type (and behavior) as a line under the title instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5 committed 2026-09-11 19:53:43 +02:00
1 parent 58f19a3451
commit 0376ae175d
11 files changed
+182 -69

No files matched your search

+39 -10
View File
@@ -4,6 +4,7 @@
*/
import { describe, expect, it } from 'vitest';
import { CommandError } from '../../src/core/commands/Command';
import { CollapseNodesCommand } from '../../src/core/commands/graphCommands';
import { AddPortCommand, RenamePortCommand } from '../../src/core/commands/portCommands';
import { RenameVariableCommand } from '../../src/core/commands/variableCommands';
import {
@@ -141,18 +142,46 @@ describe('what a port carries, by the type of the node', () => {
expect(propertyPort({ key: 'ready', kind: 'boolean' }, {}).default).toBe(false);
});
it('names the node after its type, or after the behavior it points at', () => {
it('shows its type as a setting row, and the behavior only under that type', () => {
const fixture = makeProject();
const game = makeBehavior(fixture, 'Game');
const edit = graphEditor(fixture, makeBehavior(fixture, 'Player'));
const title = (params: PropertyBag) =>
resolveDef(edit.properties([], params), game.graph, behaviorLookup(fixture.project))!.label;
expect(title({})).toBe('Properties');
expect(title(SPRITE)).toBe('Sprite properties');
expect(title({ [OBJECT_TYPE_PARAM]: 'behavior', [OBJECT_BEHAVIOR_PARAM]: game.id })).toBe(
'Game properties',
const edit = graphEditor(fixture, makeBehavior(fixture, 'B'));
const hidden = (params: PropertyBag) => {
const node = edit.properties([], params);
return resolveDef(node, { nodes: [node], edges: [] }, NO_BEHAVIORS)!.hiddenParams?.(node.params);
};
expect(hidden(SPRITE)).toEqual([OBJECT_BEHAVIOR_PARAM]);
expect(hidden({})).toEqual([OBJECT_BEHAVIOR_PARAM]);
expect(hidden({ [OBJECT_TYPE_PARAM]: 'behavior' })).toEqual([]);
});
it('is titled Properties while open and says what it does once collapsed', () => {
const fixture = makeProject();
const behavior = makeBehavior(fixture, 'B');
const edit = graphEditor(fixture, behavior);
const width = { key: 'width', kind: 'number' } as const;
const nodes = [
edit.properties([set('width'), set('height')], SPRITE),
edit.properties([width, { key: 'height', kind: 'number' }], SPRITE),
edit.properties([set('width')], SPRITE),
edit.properties([width], SPRITE),
edit.properties([], SPRITE),
];
const titles = () => nodes.map((node) => resolveDef(node, behavior.graph, NO_BEHAVIORS)!.label);
expect(new Set(titles())).toEqual(new Set(['Properties']));
fixture.stack.execute(
new CollapseNodesCommand(
behavior.id,
nodes.map((node) => node.id),
true,
),
);
expect(title({ [OBJECT_TYPE_PARAM]: 'behavior' })).toBe('Behavior properties');
expect(titles()).toEqual([
'Set 2 properties',
'Get 2 properties',
'Set width',
'Get width',
'No properties',
]);
});
});
+30 -14
View File
@@ -1,4 +1,5 @@
import { describe, expect, it } from 'vitest';
import { CollapseNodesCommand } from '../../src/core/commands/graphCommands';
import { RemovePortCommand, SetPortWriteCommand } from '../../src/core/commands/portCommands';
import { AddVariableCommand, RenameVariableCommand } from '../../src/core/commands/variableCommands';
import { type GraphNode, GraphInterpreter, inlineValue, resolveDef } from '../../src/core/graph';
@@ -238,22 +239,37 @@ describe('Variables node titles', () => {
const titleOf = (behavior: BehaviorAsset, node: GraphNode) =>
resolveDef(node, behavior.graph, () => null)!.label;
it('name a single variable, and stay plain for none or several', () => {
const { behavior, edit } = setup();
const one = edit.variables(['count'], { write: true });
const none = edit.variables([]);
const two = edit.variables(['count', 'copy']);
expect([one, none, two].map((node) => titleOf(behavior, node))).toEqual([
'count',
'Variables',
'Variables',
]);
});
it('follow a renamed variable', () => {
it('follow a renamed variable once collapsed', () => {
const { fixture, behavior, edit } = setup();
const node = edit.variables(['count']);
fixture.stack.execute(new CollapseNodesCommand(behavior.id, [node.id], true));
fixture.stack.execute(new RenameVariableCommand(behavior.id, 'count', 'score'));
expect(titleOf(behavior, node)).toBe('score');
expect(titleOf(behavior, node)).toBe('Get score');
});
it('say what the node does once it is collapsed, and only then', () => {
const { fixture, behavior, edit } = setup(['a', 'b', 'c']);
const nodes = [
edit.variables(['a', 'b', 'c'], { write: ['a', 'b'] }),
edit.variables(['a', 'b', 'c'], { write: ['a'] }),
edit.variables(['a', 'b'], { write: ['a'] }),
edit.variables(['a'], { write: true }),
edit.variables(['a']),
edit.variables([]),
];
const open = nodes.map((node) => titleOf(behavior, node));
const ids = nodes.map((node) => node.id);
fixture.stack.execute(new CollapseNodesCommand(behavior.id, ids, true));
expect(nodes.map((node) => titleOf(behavior, node))).toEqual([
'Set 2 variables',
'Get 2 variables',
'Set a',
'Set a',
'Get a',
'No variables',
]);
fixture.stack.undo();
expect(nodes.map((node) => titleOf(behavior, node))).toEqual(open);
expect(new Set(open)).toEqual(new Set(['Variables']));
});
});