Skip to content

Commit 5f03f81

Browse files
authored
exp: Modifcation nodes can be added without source (#3638)
Modification nodes (like Aggregation node or Modify Columns) can now be added from the graph, without parent node - in an invalid state
1 parent 38370af commit 5f03f81

File tree

4 files changed

+34
-2
lines changed

4 files changed

+34
-2
lines changed

ui/src/plugins/dev.perfetto.ExplorePage/query_builder/graph/graph.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,12 @@ export class Graph implements m.ClassComponent<GraphAttrs> {
596596
attrs.onAddSourceNode,
597597
);
598598

599+
const modificationMenuItems = buildMenuItems(
600+
'modification',
601+
attrs.devMode,
602+
attrs.onAddSourceNode,
603+
);
604+
599605
const operationMenuItems = buildMenuItems(
600606
'multisource',
601607
attrs.devMode,
@@ -608,6 +614,9 @@ export class Graph implements m.ClassComponent<GraphAttrs> {
608614
m(MenuDivider),
609615
m(MenuTitle, {label: 'Operations'}),
610616
...operationMenuItems,
617+
m(MenuDivider),
618+
m(MenuTitle, {label: 'Modification nodes'}),
619+
...modificationMenuItems,
611620
];
612621

613622
const moreMenuItems = [

ui/src/plugins/dev.perfetto.ExplorePage/query_builder/nodes/aggregation_node.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ export class AggregationNode implements ModificationNode {
8181
readonly state: AggregationNodeState;
8282

8383
get finalCols(): ColumnInfo[] {
84+
// When there's no prevNode, aggregation doesn't make sense
85+
// Return empty array to indicate no output columns
86+
if (this.prevNode === undefined) {
87+
return [];
88+
}
8489
const selected = this.state.groupByColumns.filter((c) => c.checked);
8590
for (const agg of this.state.aggregations) {
8691
selected.push(
@@ -99,7 +104,7 @@ export class AggregationNode implements ModificationNode {
99104
};
100105
this.prevNode = state.prevNode;
101106
this.nextNodes = [];
102-
if (this.state.groupByColumns.length === 0) {
107+
if (this.state.groupByColumns.length === 0 && this.prevNode !== undefined) {
103108
this.state.groupByColumns = newColumnInfoList(
104109
this.prevNode.finalCols ?? [],
105110
false,
@@ -117,6 +122,9 @@ export class AggregationNode implements ModificationNode {
117122
}
118123

119124
updateGroupByColumns() {
125+
if (this.prevNode === undefined) {
126+
return;
127+
}
120128
const newGroupByColumns = newColumnInfoList(
121129
this.prevNode.finalCols ?? [],
122130
false,
@@ -321,6 +329,9 @@ export class AggregationNode implements ModificationNode {
321329
getStructuredQuery(): protos.PerfettoSqlStructuredQuery | undefined {
322330
if (!this.validate()) return;
323331

332+
// Defensive check: prevNode must exist for aggregation to work
333+
if (this.prevNode === undefined) return undefined;
334+
324335
// Prepare groupByColumns
325336
const groupByColumns = this.state.groupByColumns
326337
.filter((c) => c.checked)
@@ -381,6 +392,9 @@ export class AggregationNode implements ModificationNode {
381392
}
382393

383394
resolveColumns() {
395+
if (this.prevNode === undefined) {
396+
return;
397+
}
384398
const sourceCols = this.prevNode.finalCols ?? [];
385399
this.state.groupByColumns.forEach((c) => {
386400
const sourceCol = sourceCols.find((s) => s.name === c.name);

ui/src/plugins/dev.perfetto.ExplorePage/query_builder/nodes/modify_columns_node.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,11 @@ export class ModifyColumnsNode implements ModificationNode {
489489

490490
onPrevNodesUpdated() {
491491
// This node assumes it has only one previous node.
492-
const sourceCols = this.state.prevNode.finalCols;
492+
if (this.prevNode === undefined) {
493+
return;
494+
}
495+
496+
const sourceCols = this.prevNode.finalCols;
493497

494498
const newSelectedColumns = newColumnInfoList(sourceCols);
495499

@@ -525,6 +529,10 @@ export class ModifyColumnsNode implements ModificationNode {
525529

526530
resolveColumns() {
527531
// Recover full column information from prevNode
532+
if (this.prevNode === undefined) {
533+
return;
534+
}
535+
528536
const sourceCols = this.prevNode.finalCols ?? [];
529537
this.state.selectedColumns.forEach((c) => {
530538
const sourceCol = sourceCols.find((s) => s.name === c.name);

ui/src/plugins/dev.perfetto.ExplorePage/query_node.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ export function addConnection(
340340
} else {
341341
// Otherwise connect to prevNode (default single input from above)
342342
modNode.prevNode = fromNode;
343+
modNode.onPrevNodesUpdated?.();
343344
}
344345
} else if ('prevNodes' in toNode && Array.isArray(toNode.prevNodes)) {
345346
// MultiSourceNode - multiple inputs

0 commit comments

Comments
 (0)