mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
Add more fixes
This commit is contained in:
parent
a8f21fd671
commit
005aac7df1
|
@ -261,12 +261,12 @@ const mapCookies = (cookies: CurlJson['cookies']): { cookie: string } | {} => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const flattenObject = (obj: { [x: string]: any }, prefix = '') =>
|
export const flattenObject = (obj: { [x: string]: any }, prefix = '') =>
|
||||||
Object.keys(obj).reduce((acc, k) => {
|
Object.keys(obj).reduce<Record<string, unknown>>((acc, k) => {
|
||||||
const pre = prefix.length ? prefix + '.' : '';
|
const pre = prefix.length ? prefix + '.' : '';
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
// @Problem: `typeof null` is `object`, which creates a bug here
|
||||||
if (typeof obj[k] === 'object') Object.assign(acc, flattenObject(obj[k], pre + k));
|
if (typeof obj[k] === 'object')
|
||||||
//@ts-ignore
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
Object.assign(acc, flattenObject(obj[k], pre + k));
|
||||||
else acc[pre + k] = obj[k];
|
else acc[pre + k] = obj[k];
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
@ -465,12 +465,14 @@ export class CurlService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Object.keys(httpNodeParameters.options?.redirect.redirect).length) {
|
if (!Object.keys(httpNodeParameters.options?.redirect.redirect).length) {
|
||||||
// @ts-ignore
|
// @Cleanup: Type `options.redirect` as optional and fix type errors
|
||||||
|
// @ts-expect-error Options is typed as non-optional
|
||||||
delete httpNodeParameters.options.redirect;
|
delete httpNodeParameters.options.redirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Object.keys(httpNodeParameters.options.response.response).length) {
|
if (!Object.keys(httpNodeParameters.options.response.response).length) {
|
||||||
// @ts-ignore
|
// @Cleanup: Type `options.response` as optional and fix type errors
|
||||||
|
// @ts-expect-error Options is typed as non-optional
|
||||||
delete httpNodeParameters.options.response;
|
delete httpNodeParameters.options.response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,8 @@ describe('bodyParser', () => {
|
||||||
const response = await request(server)
|
const response = await request(server)
|
||||||
.post('/')
|
.post('/')
|
||||||
.set('content-encoding', 'gzip')
|
.set('content-encoding', 'gzip')
|
||||||
// @ts-ignore
|
// Mock for testing
|
||||||
.serialize((d) => gzipSync(JSON.stringify(d)))
|
.serialize((d) => gzipSync(JSON.stringify(d)) as unknown as string)
|
||||||
.send({ hello: 'world' })
|
.send({ hello: 'world' })
|
||||||
.expect(200);
|
.expect(200);
|
||||||
expect(response.text).toEqual('{"hello":"world"}');
|
expect(response.text).toEqual('{"hello":"world"}');
|
||||||
|
@ -32,8 +32,8 @@ describe('bodyParser', () => {
|
||||||
const response = await request(server)
|
const response = await request(server)
|
||||||
.post('/')
|
.post('/')
|
||||||
.set('content-encoding', 'deflate')
|
.set('content-encoding', 'deflate')
|
||||||
// @ts-ignore
|
// Mock for testing
|
||||||
.serialize((d) => deflateSync(JSON.stringify(d)))
|
.serialize((d) => deflateSync(JSON.stringify(d)) as unknown as string)
|
||||||
.send({ hello: 'world' })
|
.send({ hello: 'world' })
|
||||||
.expect(200);
|
.expect(200);
|
||||||
expect(response.text).toEqual('{"hello":"world"}');
|
expect(response.text).toEqual('{"hello":"world"}');
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { ICredentialDataDecryptedObject } from 'n8n-workflow';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
|
|
||||||
import { CredentialsEntity } from '@/databases/entities/credentials-entity';
|
import { CredentialsEntity } from '@/databases/entities/credentials-entity';
|
||||||
|
@ -17,8 +18,8 @@ export async function encryptCredentialData(
|
||||||
const { createCredentialsFromCredentialsEntity } = await import('@/credentials-helper');
|
const { createCredentialsFromCredentialsEntity } = await import('@/credentials-helper');
|
||||||
const coreCredential = createCredentialsFromCredentialsEntity(credential, true);
|
const coreCredential = createCredentialsFromCredentialsEntity(credential, true);
|
||||||
|
|
||||||
// @ts-ignore
|
// data column is actually an object despite the type
|
||||||
coreCredential.setData(credential.data);
|
coreCredential.setData(credential.data as unknown as ICredentialDataDecryptedObject);
|
||||||
|
|
||||||
return Object.assign(credential, coreCredential.getDataToSave());
|
return Object.assign(credential, coreCredential.getDataToSave());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1504,17 +1504,11 @@ export class WorkflowExecute {
|
||||||
lineResult.json.$error !== undefined &&
|
lineResult.json.$error !== undefined &&
|
||||||
lineResult.json.$json !== undefined
|
lineResult.json.$json !== undefined
|
||||||
) {
|
) {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
lineResult.error = lineResult.json.$error as NodeApiError | NodeOperationError;
|
lineResult.error = lineResult.json.$error as NodeApiError | NodeOperationError;
|
||||||
lineResult.json = {
|
lineResult.json = {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
error: (lineResult.json.$error as NodeApiError | NodeOperationError).message,
|
error: (lineResult.json.$error as NodeApiError | NodeOperationError).message,
|
||||||
};
|
};
|
||||||
} else if (lineResult.error !== undefined) {
|
} else if (lineResult.error !== undefined) {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore
|
|
||||||
lineResult.json = { error: lineResult.error.message };
|
lineResult.json = { error: lineResult.error.message };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import { ref, onMounted } from 'vue';
|
||||||
import { useUsersStore } from '@/stores/users.store';
|
import { useUsersStore } from '@/stores/users.store';
|
||||||
import { mfaEventBus } from '@/event-bus';
|
import { mfaEventBus } from '@/event-bus';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
//@ts-ignore
|
|
||||||
import QrcodeVue from 'qrcode.vue';
|
import QrcodeVue from 'qrcode.vue';
|
||||||
import { useClipboard } from '@/composables/useClipboard';
|
import { useClipboard } from '@/composables/useClipboard';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
|
|
|
@ -403,7 +403,8 @@ const valueChanged = (parameterData: IUpdateInformation) => {
|
||||||
|
|
||||||
if (parameterData.value && typeof parameterData.value === 'object') {
|
if (parameterData.value && typeof parameterData.value === 'object') {
|
||||||
for (const parameterName of Object.keys(parameterData.value)) {
|
for (const parameterName of Object.keys(parameterData.value)) {
|
||||||
//@ts-ignore
|
// @Cleanup: Instead use `Object.entries()` to get both key and value
|
||||||
|
// @ts-expect-error this breaks the connection of keys and values
|
||||||
newValue = parameterData.value[parameterName];
|
newValue = parameterData.value[parameterName];
|
||||||
|
|
||||||
// Remove the 'parameters.' from the beginning to just have the
|
// Remove the 'parameters.' from the beginning to just have the
|
||||||
|
@ -415,7 +416,8 @@ const valueChanged = (parameterData: IUpdateInformation) => {
|
||||||
const parameterPathArray = parameterPath.match(/(.*)\[(\d+)\]$/);
|
const parameterPathArray = parameterPath.match(/(.*)\[(\d+)\]$/);
|
||||||
|
|
||||||
// Apply the new value
|
// Apply the new value
|
||||||
//@ts-ignore
|
// @Problem: `parameterData[parameterName]` makes little sense to me, please investigate if this should be `parameterData.value[parameterName]`? But that doesn't really make sense either.
|
||||||
|
// @ts-expect-error This seems like a bug?
|
||||||
if (parameterData[parameterName] === undefined && parameterPathArray !== null) {
|
if (parameterData[parameterName] === undefined && parameterPathArray !== null) {
|
||||||
// Delete array item
|
// Delete array item
|
||||||
const path = parameterPathArray[1];
|
const path = parameterPathArray[1];
|
||||||
|
|
|
@ -70,9 +70,8 @@ const vModel = reactive(
|
||||||
return filter[key];
|
return filter[key];
|
||||||
},
|
},
|
||||||
set(value) {
|
set(value) {
|
||||||
// TODO: find out what exactly is typechecker complaining about
|
// @Cleanup: Type the `computed<>()` call correctly or swap reduce for an easier to type solution
|
||||||
|
// @ts-expect-error We lose type info on value because we set this up in a reduce loop
|
||||||
// @ts-ignore
|
|
||||||
filter[key] = value;
|
filter[key] = value;
|
||||||
emit('filterChanged', filter);
|
emit('filterChanged', filter);
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,13 +11,14 @@ import type { PermissionsRecord } from '@/permissions';
|
||||||
|
|
||||||
type Command = 'retrySaved' | 'retryOriginal' | 'delete';
|
type Command = 'retrySaved' | 'retryOriginal' | 'delete';
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<
|
||||||
stop: [data: ExecutionSummary];
|
{
|
||||||
select: [data: ExecutionSummary];
|
stop: [data: ExecutionSummary];
|
||||||
retrySaved: [data: ExecutionSummary];
|
select: [data: ExecutionSummary];
|
||||||
retryOriginal: [data: ExecutionSummary];
|
} & {
|
||||||
delete: [data: ExecutionSummary];
|
[c in Command]: [data: ExecutionSummary];
|
||||||
}>();
|
}
|
||||||
|
>();
|
||||||
|
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
@ -160,8 +161,9 @@ function onSelect() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleActionItemClick(commandData: Command) {
|
async function handleActionItemClick(commandData: Command) {
|
||||||
//@ts-ignore todo: fix this type
|
// The `emit` function is not typed very well and does not take type unions of the single event types
|
||||||
emit(commandData, props.execution);
|
// Se we need to hide the type
|
||||||
|
emit(commandData as never, props.execution);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -4,7 +4,10 @@ import { render } from '@testing-library/vue';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { useHistoryHelper } from './useHistoryHelper';
|
import { useHistoryHelper } from './useHistoryHelper';
|
||||||
import { defineComponent, type PropType } from 'vue';
|
import { defineComponent, type PropType } from 'vue';
|
||||||
import type { RouteLocationNormalizedLoaded } from 'vue-router';
|
import type {
|
||||||
|
RouteLocationNormalizedLoaded,
|
||||||
|
RouteLocationNormalizedLoadedGeneric,
|
||||||
|
} from 'vue-router';
|
||||||
import { mock } from 'vitest-mock-extended';
|
import { mock } from 'vitest-mock-extended';
|
||||||
|
|
||||||
const undoMock = vi.fn();
|
const undoMock = vi.fn();
|
||||||
|
@ -56,7 +59,6 @@ describe('useHistoryHelper', () => {
|
||||||
redoMock.mockClear();
|
redoMock.mockClear();
|
||||||
});
|
});
|
||||||
it('should call undo when Ctrl+Z is pressed', async () => {
|
it('should call undo when Ctrl+Z is pressed', async () => {
|
||||||
// @ts-ignore
|
|
||||||
render(TestComponent, {
|
render(TestComponent, {
|
||||||
props: {
|
props: {
|
||||||
route: mock<RouteLocationNormalizedLoaded>({
|
route: mock<RouteLocationNormalizedLoaded>({
|
||||||
|
@ -74,7 +76,6 @@ describe('useHistoryHelper', () => {
|
||||||
expect(undoMock).toHaveBeenCalledTimes(2);
|
expect(undoMock).toHaveBeenCalledTimes(2);
|
||||||
});
|
});
|
||||||
it('should call redo when Ctrl+Shift+Z is pressed', async () => {
|
it('should call redo when Ctrl+Shift+Z is pressed', async () => {
|
||||||
// @ts-ignore
|
|
||||||
render(TestComponent, {
|
render(TestComponent, {
|
||||||
props: {
|
props: {
|
||||||
route: mock<RouteLocationNormalizedLoaded>({
|
route: mock<RouteLocationNormalizedLoaded>({
|
||||||
|
@ -92,8 +93,7 @@ describe('useHistoryHelper', () => {
|
||||||
expect(redoMock).toHaveBeenCalledTimes(2);
|
expect(redoMock).toHaveBeenCalledTimes(2);
|
||||||
});
|
});
|
||||||
it('should not call undo when Ctrl+Z if not on NodeView', async () => {
|
it('should not call undo when Ctrl+Z if not on NodeView', async () => {
|
||||||
// @ts-ignore
|
render(TestComponent, { props: { route: {} as RouteLocationNormalizedLoadedGeneric } });
|
||||||
render(TestComponent, { props: { route: {} } });
|
|
||||||
|
|
||||||
await userEvent.keyboard('{Control>}z');
|
await userEvent.keyboard('{Control>}z');
|
||||||
await userEvent.keyboard('{Control>}z');
|
await userEvent.keyboard('{Control>}z');
|
||||||
|
|
|
@ -518,7 +518,6 @@ export function useWorkflowHelpers(options: { router: ReturnType<typeof useRoute
|
||||||
|
|
||||||
const nodes: INode[] = [];
|
const nodes: INode[] = [];
|
||||||
for (let nodeIndex = 0; nodeIndex < workflowNodes.length; nodeIndex++) {
|
for (let nodeIndex = 0; nodeIndex < workflowNodes.length; nodeIndex++) {
|
||||||
// @ts-ignore
|
|
||||||
nodeData = getNodeDataToSave(workflowNodes[nodeIndex]);
|
nodeData = getNodeDataToSave(workflowNodes[nodeIndex]);
|
||||||
|
|
||||||
nodes.push(nodeData);
|
nodes.push(nodeData);
|
||||||
|
@ -555,16 +554,17 @@ export function useWorkflowHelpers(options: { router: ReturnType<typeof useRoute
|
||||||
'notes',
|
'notes',
|
||||||
'parameters',
|
'parameters',
|
||||||
'status',
|
'status',
|
||||||
];
|
] as const;
|
||||||
|
|
||||||
// @ts-ignore
|
// @Cleanup: Unify the following lines in a type-safe way, probably with Object.assign() and a filter
|
||||||
const nodeData: INodeUi = {
|
// Cast to INodeUi as we're about to provide all required keys
|
||||||
|
const nodeData = {
|
||||||
parameters: {},
|
parameters: {},
|
||||||
};
|
} as INodeUi;
|
||||||
|
|
||||||
for (const key in node) {
|
for (const key in node) {
|
||||||
if (key.charAt(0) !== '_' && skipKeys.indexOf(key) === -1) {
|
if (key.charAt(0) !== '_' && skipKeys.indexOf(key as never) === -1) {
|
||||||
// @ts-ignore
|
// @ts-expect-error We can't narrow the type to the same key, should Object.assign instead
|
||||||
nodeData[key] = node[key];
|
nodeData[key] = node[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,7 +142,8 @@ export const usePushConnectionStore = defineStore(STORES.PUSH, () => {
|
||||||
async function pushMessageReceived(event: Event) {
|
async function pushMessageReceived(event: Event) {
|
||||||
let receivedData: PushMessage;
|
let receivedData: PushMessage;
|
||||||
try {
|
try {
|
||||||
// @ts-ignore
|
// @Cleanup: Check for data explicitly and log telemetry on missing field if appropriate
|
||||||
|
// @ts-expect-error We're okay to error on missing data attribute here
|
||||||
receivedData = JSON.parse(event.data);
|
receivedData = JSON.parse(event.data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -366,7 +366,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
||||||
undefined,
|
undefined,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
} as unknown as INodeTypes;
|
};
|
||||||
|
|
||||||
return nodeTypes;
|
return nodeTypes;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue