mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(editor): Render dates correctly in parameter hint (#9089)
This commit is contained in:
parent
d7abc30104
commit
064e8f4a1d
|
@ -4,14 +4,13 @@ import InputTriple from '@/components/InputTriple/InputTriple.vue';
|
||||||
import ParameterInputFull from '@/components/ParameterInputFull.vue';
|
import ParameterInputFull from '@/components/ParameterInputFull.vue';
|
||||||
import ParameterInputHint from '@/components/ParameterInputHint.vue';
|
import ParameterInputHint from '@/components/ParameterInputHint.vue';
|
||||||
import ParameterIssues from '@/components/ParameterIssues.vue';
|
import ParameterIssues from '@/components/ParameterIssues.vue';
|
||||||
import { resolveParameter } from '@/composables/useWorkflowHelpers';
|
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
|
||||||
import { isExpression } from '@/utils/expressions';
|
import { isExpression, stringifyExpressionResult } from '@/utils/expressions';
|
||||||
import { isObject } from '@jsplumb/util';
|
import type { AssignmentValue, INodeProperties, Result } from 'n8n-workflow';
|
||||||
import type { AssignmentValue, INodeProperties } from 'n8n-workflow';
|
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import TypeSelect from './TypeSelect.vue';
|
import TypeSelect from './TypeSelect.vue';
|
||||||
import { useNDVStore } from '@/stores/ndv.store';
|
import { useNDVStore } from '@/stores/ndv.store';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
path: string;
|
path: string;
|
||||||
|
@ -32,7 +31,8 @@ const emit = defineEmits<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const ndvStore = useNDVStore();
|
const ndvStore = useNDVStore();
|
||||||
const i18n = useI18n();
|
const router = useRouter();
|
||||||
|
const { resolveExpression } = useWorkflowHelpers({ router });
|
||||||
|
|
||||||
const assignmentTypeToNodeProperty = (
|
const assignmentTypeToNodeProperty = (
|
||||||
type: string,
|
type: string,
|
||||||
|
@ -81,29 +81,21 @@ const hint = computed(() => {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let result: Result<unknown, Error>;
|
||||||
try {
|
try {
|
||||||
const resolvedValue = resolveParameter(value, {
|
const resolvedValue = resolveExpression(value, undefined, {
|
||||||
targetItem: ndvStore.hoveringItem ?? undefined,
|
targetItem: ndvStore.hoveringItem ?? undefined,
|
||||||
inputNodeName: ndvStore.ndvInputNodeName,
|
inputNodeName: ndvStore.ndvInputNodeName,
|
||||||
inputRunIndex: ndvStore.ndvInputRunIndex,
|
inputRunIndex: ndvStore.ndvInputRunIndex,
|
||||||
inputBranchIndex: ndvStore.ndvInputBranchIndex,
|
inputBranchIndex: ndvStore.ndvInputBranchIndex,
|
||||||
}) as unknown;
|
}) as unknown;
|
||||||
|
|
||||||
if (isObject(resolvedValue)) {
|
result = { ok: true, result: resolvedValue };
|
||||||
return JSON.stringify(resolvedValue);
|
|
||||||
}
|
|
||||||
if (typeof resolvedValue === 'boolean' || typeof resolvedValue === 'number') {
|
|
||||||
return resolvedValue.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resolvedValue === '') {
|
|
||||||
return i18n.baseText('parameterInput.emptyString');
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolvedValue as string;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return '';
|
result = { ok: false, error };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return stringifyExpressionResult(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
const highlightHint = computed(() =>
|
const highlightHint = computed(() =>
|
||||||
|
|
|
@ -71,7 +71,7 @@ import type { EventBus } from 'n8n-design-system/utils';
|
||||||
import { createEventBus } from 'n8n-design-system/utils';
|
import { createEventBus } from 'n8n-design-system/utils';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
|
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
|
||||||
import { getExpressionErrorMessage, getResolvableState } from '@/utils/expressions';
|
import { stringifyExpressionResult } from '@/utils/expressions';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ParameterInputWrapper',
|
name: 'ParameterInputWrapper',
|
||||||
|
@ -197,12 +197,13 @@ export default defineComponent({
|
||||||
isInputParentOfActiveNode(): boolean {
|
isInputParentOfActiveNode(): boolean {
|
||||||
return this.ndvStore.isInputParentOfActiveNode;
|
return this.ndvStore.isInputParentOfActiveNode;
|
||||||
},
|
},
|
||||||
evaluatedExpression(): Result<unknown, unknown> {
|
evaluatedExpression(): Result<unknown, Error> {
|
||||||
const value = isResourceLocatorValue(this.modelValue)
|
const value = isResourceLocatorValue(this.modelValue)
|
||||||
? this.modelValue.value
|
? this.modelValue.value
|
||||||
: this.modelValue;
|
: this.modelValue;
|
||||||
|
|
||||||
if (!this.activeNode || !this.isValueExpression || typeof value !== 'string') {
|
if (!this.activeNode || !this.isValueExpression || typeof value !== 'string') {
|
||||||
return { ok: false, error: '' };
|
return { ok: false, error: new Error() };
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -227,28 +228,7 @@ export default defineComponent({
|
||||||
return evaluated.ok ? evaluated.result : null;
|
return evaluated.ok ? evaluated.result : null;
|
||||||
},
|
},
|
||||||
evaluatedExpressionString(): string | null {
|
evaluatedExpressionString(): string | null {
|
||||||
const evaluated = this.evaluatedExpression;
|
return stringifyExpressionResult(this.evaluatedExpression);
|
||||||
|
|
||||||
if (!evaluated.ok) {
|
|
||||||
if (getResolvableState(evaluated.error) !== 'invalid') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `[${this.$locale.baseText('parameterInput.error')}: ${getExpressionErrorMessage(
|
|
||||||
evaluated.error as Error,
|
|
||||||
)}]`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (evaluated.result === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof evaluated.result === 'string' && evaluated.result.length === 0) {
|
|
||||||
return this.$locale.baseText('parameterInput.emptyString');
|
|
||||||
}
|
|
||||||
return typeof evaluated.result === 'string'
|
|
||||||
? evaluated.result
|
|
||||||
: JSON.stringify(evaluated.result);
|
|
||||||
},
|
},
|
||||||
expressionOutput(): string | null {
|
expressionOutput(): string | null {
|
||||||
if (this.isValueExpression && this.evaluatedExpressionString) {
|
if (this.isValueExpression && this.evaluatedExpressionString) {
|
||||||
|
|
34
packages/editor-ui/src/utils/__tests__/expressions.test.ts
Normal file
34
packages/editor-ui/src/utils/__tests__/expressions.test.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import { ExpressionError } from 'n8n-workflow';
|
||||||
|
import { stringifyExpressionResult } from '../expressions';
|
||||||
|
|
||||||
|
describe('stringifyExpressionResult()', () => {
|
||||||
|
it('should return empty string for non-critical errors', () => {
|
||||||
|
expect(
|
||||||
|
stringifyExpressionResult({
|
||||||
|
ok: false,
|
||||||
|
error: new ExpressionError('error message', { type: 'no_execution_data' }),
|
||||||
|
}),
|
||||||
|
).toEqual('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an error message for critical errors', () => {
|
||||||
|
expect(
|
||||||
|
stringifyExpressionResult({
|
||||||
|
ok: false,
|
||||||
|
error: new ExpressionError('error message', { type: 'no_input_connection' }),
|
||||||
|
}),
|
||||||
|
).toEqual('[ERROR: No input connected]');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return empty string when result is null', () => {
|
||||||
|
expect(stringifyExpressionResult({ ok: true, result: null })).toEqual('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return [empty] message when result is empty string', () => {
|
||||||
|
expect(stringifyExpressionResult({ ok: true, result: '' })).toEqual('[empty]');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the result when it is a string', () => {
|
||||||
|
expect(stringifyExpressionResult({ ok: true, result: 'foo' })).toEqual('foo');
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,5 +1,5 @@
|
||||||
import type { ResolvableState } from '@/types/expressions';
|
import type { ResolvableState } from '@/types/expressions';
|
||||||
import { ExpressionError, ExpressionParser } from 'n8n-workflow';
|
import { ExpressionError, ExpressionParser, type Result } from 'n8n-workflow';
|
||||||
import { i18n } from '@/plugins/i18n';
|
import { i18n } from '@/plugins/i18n';
|
||||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
|
|
||||||
|
@ -110,3 +110,23 @@ export const getExpressionErrorMessage = (error: Error): string => {
|
||||||
|
|
||||||
return error.message;
|
return error.message;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const stringifyExpressionResult = (result: Result<unknown, Error>): string => {
|
||||||
|
if (!result.ok) {
|
||||||
|
if (getResolvableState(result.error) !== 'invalid') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return `[${i18n.baseText('parameterInput.error')}: ${getExpressionErrorMessage(result.error)}]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.result === null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof result.result === 'string' && result.result.length === 0) {
|
||||||
|
return i18n.baseText('parameterInput.emptyString');
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeof result.result === 'string' ? result.result : JSON.stringify(result.result);
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in a new issue