Skip to content

Commit

Permalink
fix(editor): Render dates correctly in parameter hint (#9089)
Browse files Browse the repository at this point in the history
  • Loading branch information
elsmr committed Apr 11, 2024
1 parent d7abc30 commit 064e8f4
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 46 deletions.
Expand Up @@ -4,14 +4,13 @@ import InputTriple from '@/components/InputTriple/InputTriple.vue';
import ParameterInputFull from '@/components/ParameterInputFull.vue';
import ParameterInputHint from '@/components/ParameterInputHint.vue';
import ParameterIssues from '@/components/ParameterIssues.vue';
import { resolveParameter } from '@/composables/useWorkflowHelpers';
import { isExpression } from '@/utils/expressions';
import { isObject } from '@jsplumb/util';
import type { AssignmentValue, INodeProperties } from 'n8n-workflow';
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
import { isExpression, stringifyExpressionResult } from '@/utils/expressions';
import type { AssignmentValue, INodeProperties, Result } from 'n8n-workflow';
import { computed, ref } from 'vue';
import TypeSelect from './TypeSelect.vue';
import { useNDVStore } from '@/stores/ndv.store';
import { useI18n } from '@/composables/useI18n';
import { useRouter } from 'vue-router';
interface Props {
path: string;
Expand All @@ -32,7 +31,8 @@ const emit = defineEmits<{
}>();
const ndvStore = useNDVStore();
const i18n = useI18n();
const router = useRouter();
const { resolveExpression } = useWorkflowHelpers({ router });
const assignmentTypeToNodeProperty = (
type: string,
Expand Down Expand Up @@ -81,29 +81,21 @@ const hint = computed(() => {
return '';
}
let result: Result<unknown, Error>;
try {
const resolvedValue = resolveParameter(value, {
const resolvedValue = resolveExpression(value, undefined, {
targetItem: ndvStore.hoveringItem ?? undefined,
inputNodeName: ndvStore.ndvInputNodeName,
inputRunIndex: ndvStore.ndvInputRunIndex,
inputBranchIndex: ndvStore.ndvInputBranchIndex,
}) as unknown;
if (isObject(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;
result = { ok: true, result: resolvedValue };
} catch (error) {
return '';
result = { ok: false, error };
}
return stringifyExpressionResult(result);
});
const highlightHint = computed(() =>
Expand Down
30 changes: 5 additions & 25 deletions packages/editor-ui/src/components/ParameterInputWrapper.vue
Expand Up @@ -71,7 +71,7 @@ import type { EventBus } from 'n8n-design-system/utils';
import { createEventBus } from 'n8n-design-system/utils';
import { useRouter } from 'vue-router';
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
import { getExpressionErrorMessage, getResolvableState } from '@/utils/expressions';
import { stringifyExpressionResult } from '@/utils/expressions';
export default defineComponent({
name: 'ParameterInputWrapper',
Expand Down Expand Up @@ -197,12 +197,13 @@ export default defineComponent({
isInputParentOfActiveNode(): boolean {
return this.ndvStore.isInputParentOfActiveNode;
},
evaluatedExpression(): Result<unknown, unknown> {
evaluatedExpression(): Result<unknown, Error> {
const value = isResourceLocatorValue(this.modelValue)
? this.modelValue.value
: this.modelValue;
if (!this.activeNode || !this.isValueExpression || typeof value !== 'string') {
return { ok: false, error: '' };
return { ok: false, error: new Error() };
}
try {
Expand All @@ -227,28 +228,7 @@ export default defineComponent({
return evaluated.ok ? evaluated.result : null;
},
evaluatedExpressionString(): string | null {
const evaluated = 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);
return stringifyExpressionResult(this.evaluatedExpression);
},
expressionOutput(): string | null {
if (this.isValueExpression && this.evaluatedExpressionString) {
Expand Down
34 changes: 34 additions & 0 deletions packages/editor-ui/src/utils/__tests__/expressions.test.ts
@@ -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');
});
});
22 changes: 21 additions & 1 deletion packages/editor-ui/src/utils/expressions.ts
@@ -1,5 +1,5 @@
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 { useWorkflowsStore } from '@/stores/workflows.store';

Expand Down Expand Up @@ -110,3 +110,23 @@ export const getExpressionErrorMessage = (error: Error): string => {

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);
};

0 comments on commit 064e8f4

Please sign in to comment.