Skip to content

Commit 0fd427d

Browse files
fix(editor): Fix empty project ID when creating resources using RLC (n8n-io#27544)
1 parent 8b9de31 commit 0fd427d

2 files changed

Lines changed: 47 additions & 5 deletions

File tree

packages/frontend/editor-ui/src/features/ndv/parameters/components/ResourceLocator/ResourceLocator.test.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ import { createComponentRenderer } from '@/__tests__/render';
33
import { useNodeTypesStore } from '@/app/stores/nodeTypes.store';
44
import { useProjectsStore } from '@/features/collaboration/projects/projects.store';
55
import { ExpressionLocalResolveContextSymbol } from '@/app/constants';
6+
import { WorkflowDocumentStoreKey } from '@/app/constants/injectionKeys';
67
import { useWorkflowHelpers } from '@/app/composables/useWorkflowHelpers';
78
import ResourceLocator from './ResourceLocator.vue';
89
import { createTestingPinia } from '@pinia/testing';
910
import userEvent from '@testing-library/user-event';
1011
import { fireEvent, screen, waitFor } from '@testing-library/vue';
11-
import { computed } from 'vue';
12+
import { computed, shallowRef } from 'vue';
1213
import { mockedStore } from '@/__tests__/utils';
1314
import { vi } from 'vitest';
1415
import {
@@ -482,6 +483,43 @@ describe('ResourceLocator', () => {
482483
expect(nodeTypesStore.getNodeParameterActionResult).not.toHaveBeenCalled();
483484
});
484485

486+
it('falls back to workflow homeProject ID when currentProjectId is not available', async () => {
487+
const windowOpenSpy = vi.spyOn(window, 'open');
488+
projectsStore.currentProjectId = undefined as unknown as string;
489+
nodeTypesStore.getResourceLocatorResults.mockResolvedValue({
490+
results: [],
491+
paginationToken: null,
492+
});
493+
494+
const mockWorkflowDocumentStore = shallowRef({
495+
homeProject: { id: 'home-project-456', name: 'Test Project', type: 'team' },
496+
});
497+
498+
const { getByTestId } = renderComponent({
499+
props: {
500+
modelValue: TEST_MODEL_VALUE,
501+
parameter: TEST_PARAMETER_URL_REDIRECT,
502+
path: `parameters.${TEST_PARAMETER_URL_REDIRECT.name}`,
503+
node: TEST_NODE_URL_REDIRECT,
504+
displayTitle: 'Test Resource Locator',
505+
expressionComputedValue: '',
506+
},
507+
global: {
508+
provide: {
509+
[WorkflowDocumentStoreKey as symbol]: mockWorkflowDocumentStore,
510+
},
511+
},
512+
});
513+
514+
await userEvent.click(getByTestId('rlc-input'));
515+
await userEvent.click(getByTestId('rlc-item-add-resource'));
516+
517+
expect(windowOpenSpy).toHaveBeenCalledWith(
518+
'/projects/home-project-456/datatables/new',
519+
'_blank',
520+
);
521+
});
522+
485523
it('clears cached resources after URL redirect so fresh data is fetched on re-open', async () => {
486524
const TEST_ITEMS = [{ name: 'Old Table', value: 'old-table' }];
487525
const TEST_ITEMS_UPDATED = [

packages/frontend/editor-ui/src/features/ndv/parameters/components/ResourceLocator/ResourceLocator.vue

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import {
5757
import { completeExpressionSyntax } from '@/app/utils/expressions';
5858
import { ExpressionLocalResolveContextSymbol } from '@/app/constants';
5959
import { useProjectsStore } from '@/features/collaboration/projects/projects.store';
60+
import { injectWorkflowDocumentStore } from '@/app/stores/workflowDocument.store';
6061
import FromAiOverrideButton from '../ParameterInputOverrides/FromAiOverrideButton.vue';
6162
import FromAiOverrideField from '../ParameterInputOverrides/FromAiOverrideField.vue';
6263
import ParameterOverrideSelectableList from '../ParameterInputOverrides/ParameterOverrideSelectableList.vue';
@@ -161,6 +162,7 @@ const rootStore = useRootStore();
161162
const uiStore = useUIStore();
162163
const workflowsStore = useWorkflowsStore();
163164
const projectsStore = useProjectsStore();
165+
const workflowDocumentStore = injectWorkflowDocumentStore();
164166
const expressionLocalResolveCtx = inject(ExpressionLocalResolveContextSymbol, undefined);
165167
166168
const appName = computed(() => {
@@ -412,10 +414,12 @@ const handleAddResourceClick = async () => {
412414
let resolvedUrl = redirectUrl;
413415
414416
if (resolvedUrl.includes('{{$projectId}}')) {
415-
resolvedUrl = resolvedUrl.replace(
416-
/\{\{\$projectId\}\}/g,
417-
projectsStore.currentProjectId ?? '',
418-
);
417+
const projectId =
418+
projectsStore.currentProjectId ??
419+
workflowDocumentStore?.value?.homeProject?.id ??
420+
projectsStore.personalProject?.id ??
421+
'';
422+
resolvedUrl = resolvedUrl.replace(/\{\{\$projectId\}\}/g, projectId);
419423
}
420424
421425
hideResourceDropdown();

0 commit comments

Comments
 (0)