mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 01:56:46 +00:00
fix(AWS Bedrock Chat Model Node): Do not show issues for arbitrary model names (#17079)
This commit is contained in:
@@ -60,6 +60,7 @@ export class LmChatAwsBedrock implements INodeType {
|
||||
displayName: 'Model',
|
||||
name: 'model',
|
||||
type: 'options',
|
||||
allowArbitraryValues: true, // Hide issues when model name is specified in the expression and does not match any of the options
|
||||
description:
|
||||
'The model which will generate the completion. <a href="https://docs.aws.amazon.com/bedrock/latest/userguide/foundation-models.html">Learn more</a>.',
|
||||
typeOptions: {
|
||||
|
||||
@@ -417,17 +417,19 @@ const getIssues = computed<string[]>(() => {
|
||||
['options', 'multiOptions'].includes(props.parameter.type) &&
|
||||
!remoteParameterOptionsLoading.value &&
|
||||
remoteParameterOptionsLoadingIssues.value === null &&
|
||||
parameterOptions.value
|
||||
parameterOptions.value &&
|
||||
(!isModelValueExpression.value || props.expressionEvaluated !== null)
|
||||
) {
|
||||
// Check if the value resolves to a valid option
|
||||
// Currently it only displays an error in the node itself in
|
||||
// Check if the value resolves to a valid option.
|
||||
// For expressions do not validate if there is no evaluated value.
|
||||
// Currently, it only displays an error in the node itself in
|
||||
// case the value is not valid. The workflow can still be executed
|
||||
// and the error is not displayed on the node in the workflow
|
||||
const validOptions = parameterOptions.value.map((options) => options.value);
|
||||
|
||||
let checkValues: string[] = [];
|
||||
|
||||
if (!shouldSkipParamValidation(displayValue.value)) {
|
||||
if (!shouldSkipParamValidation(props.parameter, displayValue.value)) {
|
||||
if (Array.isArray(displayValue.value)) {
|
||||
checkValues = checkValues.concat(displayValue.value);
|
||||
} else {
|
||||
|
||||
@@ -14,11 +14,11 @@ import { mockedStore } from '@/__tests__/utils';
|
||||
import type { INodeUi } from '@/Interface';
|
||||
|
||||
describe('useNodeSettingsParameters', () => {
|
||||
describe('setValue', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createTestingPinia());
|
||||
});
|
||||
beforeEach(() => {
|
||||
setActivePinia(createTestingPinia());
|
||||
});
|
||||
|
||||
describe('setValue', () => {
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import type {
|
||||
IDataObject,
|
||||
INodeTypeDescription,
|
||||
INodePropertyOptions,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
import {
|
||||
updateDynamicConnections,
|
||||
@@ -13,8 +14,9 @@ import {
|
||||
nameIsParameter,
|
||||
formatAsExpression,
|
||||
parseFromExpression,
|
||||
shouldSkipParamValidation,
|
||||
} from './nodeSettingsUtils';
|
||||
import { SWITCH_NODE_TYPE } from '@/constants';
|
||||
import { CUSTOM_API_CALL_KEY, SWITCH_NODE_TYPE } from '@/constants';
|
||||
import type { INodeUi, IUpdateInformation } from '@/Interface';
|
||||
|
||||
describe('updateDynamicConnections', () => {
|
||||
@@ -396,3 +398,158 @@ describe('parseFromExpression', () => {
|
||||
expect(parseFromExpression({}, undefined, 'json', null, [])).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('shouldSkipParamValidation', () => {
|
||||
describe('CUSTOM_API_CALL_KEY detection', () => {
|
||||
it('should skip validation when value is CUSTOM_API_CALL_KEY', () => {
|
||||
const parameter: INodeProperties = {
|
||||
name: 'testParam',
|
||||
displayName: 'Test Parameter',
|
||||
type: 'string',
|
||||
default: '',
|
||||
};
|
||||
|
||||
const result = shouldSkipParamValidation(parameter, CUSTOM_API_CALL_KEY);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should skip validation when value is a string containing CUSTOM_API_CALL_KEY', () => {
|
||||
const parameter: INodeProperties = {
|
||||
name: 'testParam',
|
||||
displayName: 'Test Parameter',
|
||||
type: 'string',
|
||||
default: '',
|
||||
};
|
||||
|
||||
const valueWithKey = `some prefix ${CUSTOM_API_CALL_KEY} some suffix`;
|
||||
const result = shouldSkipParamValidation(parameter, valueWithKey);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should not skip validation when value is a string not containing CUSTOM_API_CALL_KEY', () => {
|
||||
const parameter: INodeProperties = {
|
||||
name: 'testParam',
|
||||
displayName: 'Test Parameter',
|
||||
type: 'string',
|
||||
default: '',
|
||||
};
|
||||
|
||||
const result = shouldSkipParamValidation(parameter, 'regular string value');
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('options parameter type with allowArbitraryValues', () => {
|
||||
it('should skip validation for options parameter with allowArbitraryValues=true', () => {
|
||||
const parameter: INodeProperties = {
|
||||
name: 'optionsParam',
|
||||
displayName: 'Options Parameter',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ name: 'Option 1', value: 'option1' },
|
||||
{ name: 'Option 2', value: 'option2' },
|
||||
],
|
||||
allowArbitraryValues: true,
|
||||
default: '',
|
||||
};
|
||||
|
||||
const result = shouldSkipParamValidation(parameter, 'arbitrary_value');
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should not skip validation for options parameter with allowArbitraryValues=false', () => {
|
||||
const parameter: INodeProperties = {
|
||||
name: 'optionsParam',
|
||||
displayName: 'Options Parameter',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ name: 'Option 1', value: 'option1' },
|
||||
{ name: 'Option 2', value: 'option2' },
|
||||
],
|
||||
allowArbitraryValues: false,
|
||||
default: '',
|
||||
};
|
||||
|
||||
const result = shouldSkipParamValidation(parameter, 'arbitrary_value');
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should not skip validation for options parameter with allowArbitraryValues=undefined', () => {
|
||||
const parameter: INodeProperties = {
|
||||
name: 'optionsParam',
|
||||
displayName: 'Options Parameter',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ name: 'Option 1', value: 'option1' },
|
||||
{ name: 'Option 2', value: 'option2' },
|
||||
],
|
||||
default: '',
|
||||
};
|
||||
|
||||
const result = shouldSkipParamValidation(parameter, 'arbitrary_value');
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('multiOptions parameter type with allowArbitraryValues', () => {
|
||||
it('should skip validation for multiOptions parameter with allowArbitraryValues=true', () => {
|
||||
const parameter: INodeProperties = {
|
||||
name: 'multiOptionsParam',
|
||||
displayName: 'Multi Options Parameter',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{ name: 'Option 1', value: 'option1' },
|
||||
{ name: 'Option 2', value: 'option2' },
|
||||
],
|
||||
allowArbitraryValues: true,
|
||||
default: [],
|
||||
};
|
||||
|
||||
const result = shouldSkipParamValidation(parameter, ['arbitrary_value']);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should not skip validation for multiOptions parameter with allowArbitraryValues=false', () => {
|
||||
const parameter: INodeProperties = {
|
||||
name: 'multiOptionsParam',
|
||||
displayName: 'Multi Options Parameter',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{ name: 'Option 1', value: 'option1' },
|
||||
{ name: 'Option 2', value: 'option2' },
|
||||
],
|
||||
allowArbitraryValues: false,
|
||||
default: [],
|
||||
};
|
||||
|
||||
const result = shouldSkipParamValidation(parameter, ['arbitrary_value']);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('non-options parameter types', () => {
|
||||
const nonOptionsParameterTypes = [
|
||||
'string',
|
||||
'number',
|
||||
'boolean',
|
||||
'json',
|
||||
'dateTime',
|
||||
'color',
|
||||
] as Array<INodeProperties['type']>;
|
||||
|
||||
nonOptionsParameterTypes.forEach((type) => {
|
||||
it(`should not skip validation for ${type} parameter type regardless of allowArbitraryValues`, () => {
|
||||
const parameter: INodeProperties = {
|
||||
name: 'testParam',
|
||||
displayName: 'Test Parameter',
|
||||
type,
|
||||
allowArbitraryValues: true,
|
||||
default: '',
|
||||
};
|
||||
|
||||
const result = shouldSkipParamValidation(parameter, 'test_value');
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -359,6 +359,13 @@ export function parseFromExpression(
|
||||
return null;
|
||||
}
|
||||
|
||||
export function shouldSkipParamValidation(value: string | number | boolean | null) {
|
||||
return typeof value === 'string' && value.includes(CUSTOM_API_CALL_KEY);
|
||||
export function shouldSkipParamValidation(
|
||||
parameter: INodeProperties,
|
||||
value: NodeParameterValueType,
|
||||
) {
|
||||
return (
|
||||
(typeof value === 'string' && value.includes(CUSTOM_API_CALL_KEY)) ||
|
||||
(['options', 'multiOptions'].includes(parameter.type) &&
|
||||
Boolean(parameter.allowArbitraryValues))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1466,6 +1466,8 @@ export interface INodeProperties {
|
||||
// allows to skip validation during execution or set custom validation/casting logic inside node
|
||||
// inline error messages would still be shown in UI
|
||||
ignoreValidationDuringExecution?: boolean;
|
||||
// for type: options | multiOptions – skip validation of the value (e.g. when value is not in the list and specified via expression)
|
||||
allowArbitraryValues?: boolean;
|
||||
}
|
||||
|
||||
export interface INodePropertyModeTypeOptions {
|
||||
|
||||
Reference in New Issue
Block a user