mirror of
https://github.com/n8n-io/n8n
synced 2026-04-21 15:47:20 +00:00
fix(editor): Restore WASM file paths for cURL import in HTTP Request node (#28610)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Matsuuu <huhta.matias@gmail.com>
This commit is contained in:
parent
3b248eedc2
commit
51bc71e897
5 changed files with 82 additions and 21 deletions
|
|
@ -1198,7 +1198,7 @@
|
|||
"experiments.resourceCenter.seeMore": "See more",
|
||||
"experiments.resourceCenter.sidebar": "Resources",
|
||||
"experiments.resourceCenter.sidebar.inspiration": "Inspiration",
|
||||
"experiments.resourceCenter.templateCard.useNow": "▶︎ Run workflow",
|
||||
"experiments.resourceCenter.templateCard.useNow": "▶ Run workflow",
|
||||
"experiments.resourceCenter.templatePreviews.title": "Popular Templates",
|
||||
"experiments.resourceCenter.title": "Resources",
|
||||
"experiments.resourceCenter.viewAllTemplates": "View all templates",
|
||||
|
|
@ -3461,7 +3461,7 @@
|
|||
"templates.collection": "Collection",
|
||||
"templates.collections": "Collections",
|
||||
"templates.collectionsNotFound": "Collection could not be found",
|
||||
"templates.connectionWarning": "⚠️ There was a problem fetching workflow templates. Check your internet connection.",
|
||||
"templates.connectionWarning": "! There was a problem fetching workflow templates. Check your internet connection.",
|
||||
"templates.heading": "Workflow templates",
|
||||
"templates.shareWorkflow": "Share template",
|
||||
"templates.noSearchResults": "Nothing found. Try adjusting your search to see more.",
|
||||
|
|
@ -3994,6 +3994,8 @@
|
|||
"ImportCurlModal.notice.content": "This will overwrite any changes you have already made to the current node",
|
||||
"importCurlModal.button.label": "Import",
|
||||
"importCurlParameter.label": "Import cURL",
|
||||
"importCurlParameter.showError.failedToLoad.title": "Failed to load dependencies",
|
||||
"importCurlParameter.showError.failedToLoad.message": "There was an error loading required dependencies.",
|
||||
"importCurlParameter.showError.invalidCurlCommand.title": "Couldn’t import cURL command",
|
||||
"importCurlParameter.showError.invalidCurlCommand.message": "This command is in an unsupported format",
|
||||
"importCurlParameter.showError.invalidProtocol1.title": "Use the {node} node",
|
||||
|
|
|
|||
|
|
@ -15,16 +15,23 @@ vi.mock('@/app/composables/useTelemetry', () => ({
|
|||
}),
|
||||
}));
|
||||
|
||||
const mockShowToast = vi.fn();
|
||||
vi.mock('@/app/composables/useToast', () => ({
|
||||
useToast: () => ({ showToast: mockShowToast }),
|
||||
}));
|
||||
|
||||
const mockImportCurlCommand = vi.fn();
|
||||
let mockImportOptions: {
|
||||
onImportSuccess: () => void;
|
||||
onImportFailure: (data: { invalidProtocol: boolean; protocol?: string }) => void;
|
||||
onAfterImport: () => void;
|
||||
};
|
||||
|
||||
vi.mock('@/app/composables/useImportCurlCommand', () => ({
|
||||
useImportCurlCommand: (options: {
|
||||
onImportSuccess: () => void;
|
||||
onAfterImport: () => void;
|
||||
}) => ({
|
||||
importCurlCommand: () => {
|
||||
options.onImportSuccess();
|
||||
options.onAfterImport();
|
||||
},
|
||||
}),
|
||||
useImportCurlCommand: (options: typeof mockImportOptions) => {
|
||||
mockImportOptions = options;
|
||||
return { importCurlCommand: mockImportCurlCommand };
|
||||
},
|
||||
}));
|
||||
|
||||
const renderModal = createComponentRenderer(ImportCurlModal, {
|
||||
|
|
@ -43,6 +50,10 @@ const testNode = {
|
|||
describe('ImportCurlModal', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mockImportCurlCommand.mockImplementation(() => {
|
||||
mockImportOptions.onImportSuccess();
|
||||
mockImportOptions.onAfterImport();
|
||||
});
|
||||
});
|
||||
|
||||
it('should show empty input when no curl command exists for active node', async () => {
|
||||
|
|
@ -149,4 +160,35 @@ describe('ImportCurlModal', () => {
|
|||
'node-1': 'curl -X GET https://api.example.com/other',
|
||||
});
|
||||
});
|
||||
|
||||
it('should show error toast and track failure telemetry when import throws (e.g. WASM load failure)', async () => {
|
||||
mockImportCurlCommand.mockImplementation(() => {
|
||||
throw new Error('WASM failed to load');
|
||||
});
|
||||
|
||||
const uiStore = mockedStore(useUIStore);
|
||||
uiStore.modalsById = {
|
||||
[IMPORT_CURL_MODAL_KEY]: {
|
||||
open: true,
|
||||
data: { curlCommands: {} },
|
||||
},
|
||||
};
|
||||
uiStore.modalStack = [IMPORT_CURL_MODAL_KEY];
|
||||
const ndvStore = mockedStore(useNDVStore);
|
||||
ndvStore.activeNode = testNode;
|
||||
|
||||
const { getByTestId } = renderModal();
|
||||
await nextTick();
|
||||
|
||||
const input = getByTestId('import-curl-modal-input');
|
||||
await userEvent.type(input, 'curl -X GET https://api.example.com/data');
|
||||
const button = getByTestId('import-curl-modal-button');
|
||||
await userEvent.click(button);
|
||||
|
||||
expect(mockShowToast).toHaveBeenCalledWith(expect.objectContaining({ type: 'error' }));
|
||||
expect(mockTelemetryTrack).toHaveBeenCalledWith(
|
||||
'User imported curl command',
|
||||
expect.objectContaining({ success: false }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@ import { onMounted, ref } from 'vue';
|
|||
import { useUIStore } from '@/app/stores/ui.store';
|
||||
import { createEventBus } from '@n8n/utils/event-bus';
|
||||
import { useTelemetry } from '@/app/composables/useTelemetry';
|
||||
import { useToast } from '@/app/composables/useToast';
|
||||
import { useI18n } from '@n8n/i18n';
|
||||
import { useNDVStore } from '@/features/ndv/shared/ndv.store';
|
||||
|
||||
import { N8nButton, N8nInput, N8nInputLabel, N8nNotice } from '@n8n/design-system';
|
||||
const telemetry = useTelemetry();
|
||||
const toast = useToast();
|
||||
const i18n = useI18n();
|
||||
|
||||
const uiStore = useUIStore();
|
||||
|
|
@ -80,13 +82,24 @@ function sendTelemetry(
|
|||
}
|
||||
|
||||
async function onImport() {
|
||||
const { useImportCurlCommand } = await import('@/app/composables/useImportCurlCommand');
|
||||
const { importCurlCommand } = useImportCurlCommand({
|
||||
onImportSuccess,
|
||||
onImportFailure,
|
||||
onAfterImport,
|
||||
});
|
||||
importCurlCommand(curlCommand);
|
||||
try {
|
||||
const { useImportCurlCommand } = await import('@/app/composables/useImportCurlCommand');
|
||||
const { importCurlCommand } = useImportCurlCommand({
|
||||
onImportSuccess,
|
||||
onImportFailure,
|
||||
onAfterImport,
|
||||
});
|
||||
importCurlCommand(curlCommand);
|
||||
} catch {
|
||||
// Handles WASM loading failures (e.g. wrong MIME type for tree-sitter.wasm)
|
||||
toast.showToast({
|
||||
title: i18n.baseText('importCurlParameter.showError.failedToLoad.title'),
|
||||
message: i18n.baseText('importCurlParameter.showError.failedToLoad.message'),
|
||||
type: 'error',
|
||||
duration: 0,
|
||||
});
|
||||
onImportFailure({ invalidProtocol: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -460,7 +460,9 @@ const setHttpNodeParameters = (parameters: CurlToJSONResponse) => {
|
|||
name: 'parameters',
|
||||
value: parameters as unknown as INodeParameters,
|
||||
});
|
||||
} catch {}
|
||||
} catch (error) {
|
||||
console.error('Failed to apply cURL parameters to node:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const onSwitchSelectedNode = (node: string) => {
|
||||
|
|
|
|||
|
|
@ -110,11 +110,13 @@ const plugins: UserConfig['plugins'] = [
|
|||
targets: [
|
||||
{
|
||||
src: 'node_modules/web-tree-sitter/tree-sitter.wasm',
|
||||
dest: 'dist',
|
||||
dest: '.',
|
||||
rename: { stripBase: true },
|
||||
},
|
||||
{
|
||||
src: 'node_modules/curlconverter/dist/tree-sitter-bash.wasm',
|
||||
dest: 'dist',
|
||||
dest: '.',
|
||||
rename: { stripBase: true },
|
||||
},
|
||||
// wa-sqlite WASM files for OPFS database support (no cross-origin isolation needed)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue