Skip to content

Conversation

@Alexandero89
Copy link
Contributor

Introduced the ability to filter executions by specific nodes in both backend and frontend components.

Summary

This PR is a first draft and also serves as a Request for Comments (RFC).

  • I frequently need to see all executions where a specific node was executed.
  • Currently, there is no way to filter executions by executed nodes.
  • This PR adds a button to the right-click context menu in the editor, enabling quick access to this functionality.
  • It introduces an update to the /executions route router, so that it can accept a URL parameter.
  • The URL parameter allows specifying the nodeId to be filtered for in the backend/database.

Feedback and suggestions are highly appreciated!

Showcasevideo

bildschirmaufzeichnung-vom-2025-06-05-02-47-12_wKow5MCV.mp4

Review / Merge checklist

  • PR title and summary are descriptive. (conventions)
  • Docs updated or follow-up ticket created.
  • Tests included.
  • PR Labeled with release/backport (if the PR is an urgent fix that needs to be backported)

Alex O added 2 commits June 5, 2025 02:24
Introduced the ability to filter executions by specific nodes in both backend and frontend components.
@CLAassistant
Copy link

CLAassistant commented Jun 5, 2025

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ Alexandero89
❌ Alex O


Alex O seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cubic found 10 issues across 12 files. Review them in cubic.dev

React with 👍 or 👎 to teach cubic. Tag @cubic-dev-ai to give specific feedback.

"contextMenu.addSticky": "Add sticky note",
"contextMenu.editSticky": "Edit sticky note",
"contextMenu.changeColor": "Change color",
"contextMenu.FilterExecutionsBy": "Filter Executions by",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Translation key naming inconsistency. The key uses camelCase 'FilterExecutionsBy' but is referenced in code as 'filter_executions_by'.

Suggested change
"contextMenu.FilterExecutionsBy": "Filter Executions by",
"contextMenu.filter_executions_by": "Filter Executions by",

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will change this and some other variables to be consistent with the rest of the naming

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

: [],
);
const FilterExecutionsBy = computed(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rule violated: Ensure every PR has unit tests for Vue files

  Missing unit tests for WorkflowExecutionsView.vue component

const idConditions: string[] = [];
query.nodesExecuted.forEach((node, idx) => {
idConditions.push(
`json_type(json_extract(execution_data.data, '$[4].' || :nodeName${idx})) IS NOT NULL`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SQL function json_extract may not be compatible with all database types

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this query executed in the sqlite and the postgres setup aswell?
Or only the sqlite?

Cause:
"json_extract is natively supported in modern SQLite versions (3.9.0 and above, released since 2015) if it is compiled with the JSON1 extension—most pre-built binaries include this by default."

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The query is executed in postgres set up as well. Can you change the way the execution data is extracted?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated the query to also support postgresdb

const idConditions: string[] = [];
query.nodesExecuted.forEach((node, idx) => {
idConditions.push(
`json_type(json_extract(execution_data.data, '$[4].' || :nodeName${idx})) IS NOT NULL`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded array index '$[4]' in JSON path is brittle and lacks documentation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I analyzed the json in the database and it seems the 4th element is a list where all executed nodes of an execution are listed. so we should always find the node we are searching for in the 4th element.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hardcoded index is brittle, indeed. @Alexandero89 have you found any other way to do this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually it seems this is some kind of standard. The executed nodes are always saved at position 4.
I think someone of your team at n8n should know if this is a standard and if its always saved at this position or if we can do this in some better way.

startedBefore?: string;
annotationTags?: string[];
vote?: ExecutionFilterVote;
nodesExecuted: string[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type inconsistency between ExecutionFilterType and ExecutionsQueryFilter interfaces. In ExecutionFilterType, nodesExecuted is optional, but in ExecutionsQueryFilter, it's required. This could cause runtime errors when transforming between these types in executionFilterToQueryFilter function.

Suggested change
nodesExecuted: string[];
+ nodesExecuted?: string[];

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

import Edge from './elements/edges/CanvasEdge.vue';
import Node from './elements/nodes/CanvasNode.vue';
import { useViewportAutoAdjust } from '@/components/canvas/composables/useViewportAutoAdjust';
import { useRouter, useRoute } from 'vue-router';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rule violated: Ensure every PR has unit tests for Vue files

  Missing unit tests for the new filter executions functionality

async function onFilterExecutionBy(input: { ids: string[] }) {
const workflowId = route.params.name as string;
if (!workflowId || !input || !input.ids || input.ids.length === 0) return;
const customFilter = nodeDataById.value[input.ids[0]]?.name;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing validation for nodeDataById.value[input.ids[0]] existence before accessing name property

Suggested change
const customFilter = nodeDataById.value[input.ids[0]]?.name;
+ const customFilter = nodeDataById.value[input.ids[0]]?.name || undefined;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

const qb = this.createQueryBuilder('execution')
.select(fields)
.innerJoin('execution.workflow', 'workflow')
// Add join to execution_data in the query builder
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment indicates this join might not be needed for all queries, but it's added unconditionally

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will have to think about how to solve this better. not every execution needs this join.
feedback is very welcomed here

Copy link
Contributor Author

@Alexandero89 Alexandero89 Jun 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

implemented a better solution in the new commit. have a look

payload?: CanvasNodeEventBusEvents[keyof CanvasNodeEventBusEvents];
};
tidyUp: { source: CanvasLayoutSource };
filter_executions_by: { ids: string[] };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The event only uses the first node ID from the array in the implementation, but the type suggests multiple IDs are supported.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this proof of concept i implemented the filtering for only one node.
The idea is later to be able to filter by multiple nodes that are marked.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's start with one node 👍

case 'extract_sub_workflow':
return emit('extract-workflow', nodeIds);
case 'filter_executions_by':
onFilterExecutionBy({ ids: nodeIds });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant function call before emitting the same event

@n8n-assistant n8n-assistant bot added community Authored by a community member core Enhancement outside /nodes-base and /editor-ui in linear Issue or PR has been created in Linear for internal review labels Jun 5, 2025
@Joffcom
Copy link
Member

Joffcom commented Jun 5, 2025

Hey @Alexandero89,

Thanks for the PR, We have created "GHC-2353" as the internal reference to get this reviewed.

One of us will be in touch if there are any changes needed, in most cases this is normally within a couple of weeks but it depends on the current workload of the team.

@bundlemon
Copy link

bundlemon bot commented Jun 19, 2025

BundleMon

Unchanged files (2)
Status Path Size Limits
WASM Dependencies
tree-sitter-bash.wasm
181.26KB -
WASM Dependencies
tree-sitter.wasm
74.47KB -

No change in files bundle size

Groups updated (2)
Status Path Size Limits
**/*.js
5.16MB (+27.53KB +0.52%) -
**/*.css
182.67KB (+3.62KB +2.02%) -

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

.innerJoin('execution.workflow', 'workflow');

// Add join to execution_data only if nodesExecuted is not null or not an empty array
if (nodesExecuted && Array.isArray(nodesExecuted) ? nodesExecuted.length > 0 : true) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this always be true?
If nodesExecuted is undefined?, then true is returned,
If it's an array, nodesExecuted.length > 0 is returned which is also true

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. Changed the check to be more precise

Copy link
Contributor

@nikhilkuria nikhilkuria left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice idea @Alexandero89 👏
Let's polish it and make it better

@nikhilkuria
Copy link
Contributor

Also, can you fix the broken tests?

changing label
better check for nodesExecuted not to be empty
better db query to also support postgresdb
@Alexandero89 Alexandero89 changed the title Filter Executions by executed node fix(editor): Filter Executions by executed node Jul 7, 2025
@Alexandero89 Alexandero89 changed the title fix(editor): Filter Executions by executed node feat(editor): Filter Executions by executed node Jul 7, 2025
void the promise instead of ignoring it
if (query.nodesExecuted && query.nodesExecuted.length > 0) {
const idConditions: string[] = [];
query.nodesExecuted.forEach((node, idx) => {
const fragment = isPostgres
Copy link
Contributor

@nikhilkuria nikhilkuria Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you get the changes to work in a postgresdb?
I had to change it as follows for the filtering to work

const fragment = isPostgres
? `jsonb_exists(execution_data.data::jsonb->4, :nodeName${idx})`
: `json_type(json_extract(execution_data.data, '$[4].' || :nodeName${idx})) IS NOT NULL`;

Is this related to different postgres versions?

@nikhilkuria
Copy link
Contributor

I think it's shaping real nice. The check for postgres is the way to go. Nice work!

@nikhilkuria
Copy link
Contributor

@nikhilkuria
Copy link
Contributor

Hi @Alexandero89 did you manage to take a look at my last comments

@nikhilkuria
Copy link
Contributor

@Alexandero89 we are closing this PR. When you find time to work on, please reopen and we can continue our conversation

@nikhilkuria nikhilkuria closed this Oct 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community Authored by a community member core Enhancement outside /nodes-base and /editor-ui in linear Issue or PR has been created in Linear for internal review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants