feat(core): Display conditions in displayOptions (no-changelog) (#7888)

This commit is contained in:
Michael Kret
2024-01-24 18:04:46 +02:00
committed by GitHub
parent d6deceacde
commit ed7d6b7b3a
6 changed files with 2131 additions and 63 deletions

View File

@@ -1160,7 +1160,31 @@ export type FilterTypeOptions = Partial<{
typeValidation: 'strict' | 'loose' | {}; // default = strict, `| {}` is a TypeScript trick to allow custom strings, but still give autocomplete
}>;
export type DisplayCondition =
| { _cnd: { eq: NodeParameterValue } }
| { _cnd: { not: NodeParameterValue } }
| { _cnd: { gte: number | string } }
| { _cnd: { lte: number | string } }
| { _cnd: { gt: number | string } }
| { _cnd: { lt: number | string } }
| { _cnd: { between: { from: number | string; to: number | string } } }
| { _cnd: { startsWith: string } }
| { _cnd: { endsWith: string } }
| { _cnd: { includes: string } }
| { _cnd: { regex: string } };
export interface IDisplayOptions {
hide?: {
[key: string]: Array<NodeParameterValue | DisplayCondition> | undefined;
};
show?: {
'@version'?: Array<number | DisplayCondition>;
[key: string]: Array<NodeParameterValue | DisplayCondition> | undefined;
};
hideOnCloud?: boolean;
}
export interface ICredentialsDisplayOptions {
hide?: {
[key: string]: NodeParameterValue[] | undefined;
};
@@ -1402,7 +1426,7 @@ export interface INodeCredentialTestRequest {
export interface INodeCredentialDescription {
name: string;
required?: boolean;
displayOptions?: IDisplayOptions;
displayOptions?: ICredentialsDisplayOptions;
testedBy?: ICredentialTestRequest | string; // Name of a function inside `loadOptions.credentialTest`
}

View File

@@ -41,6 +41,7 @@ import type {
INodeOutputConfiguration,
INodeInputConfiguration,
GenericValue,
DisplayCondition,
} from './Interfaces';
import {
isFilterValue,
@@ -282,6 +283,90 @@ export function applySpecialNodeParameters(nodeType: INodeType): void {
}
}
const getPropertyValues = (
nodeValues: INodeParameters,
propertyName: string,
node: Pick<INode, 'typeVersion'> | null,
nodeValuesRoot: INodeParameters,
) => {
let value;
if (propertyName.charAt(0) === '/') {
// Get the value from the root of the node
value = get(nodeValuesRoot, propertyName.slice(1));
} else if (propertyName === '@version') {
value = node?.typeVersion || 0;
} else {
// Get the value from current level
value = get(nodeValues, propertyName);
}
if (value && typeof value === 'object' && '__rl' in value && value.__rl) {
value = value.value;
}
if (!Array.isArray(value)) {
return [value as NodeParameterValue];
} else {
return value as NodeParameterValue[];
}
};
const checkConditions = (
conditions: Array<NodeParameterValue | DisplayCondition>,
actualValues: NodeParameterValue[],
) => {
return conditions.some((condition) => {
if (
condition &&
typeof condition === 'object' &&
condition._cnd &&
Object.keys(condition).length === 1
) {
const [key, targetValue] = Object.entries(condition._cnd)[0];
return actualValues.every((propertyValue) => {
if (key === 'eq') {
return isEqual(propertyValue, targetValue);
}
if (key === 'not') {
return !isEqual(propertyValue, targetValue);
}
if (key === 'gte') {
return (propertyValue as number) >= targetValue;
}
if (key === 'lte') {
return (propertyValue as number) <= targetValue;
}
if (key === 'gt') {
return (propertyValue as number) > targetValue;
}
if (key === 'lt') {
return (propertyValue as number) < targetValue;
}
if (key === 'between') {
const { from, to } = targetValue as { from: number; to: number };
return (propertyValue as number) >= from && (propertyValue as number) <= to;
}
if (key === 'includes') {
return (propertyValue as string).includes(targetValue);
}
if (key === 'startsWith') {
return (propertyValue as string).startsWith(targetValue);
}
if (key === 'endsWith') {
return (propertyValue as string).endsWith(targetValue);
}
if (key === 'regex') {
return new RegExp(targetValue as string).test(propertyValue as string);
}
return false;
});
}
return actualValues.includes(condition as NodeParameterValue);
});
};
/**
* Returns if the parameter should be displayed or not
*
@@ -300,76 +385,31 @@ export function displayParameter(
return true;
}
const { show, hide } = parameter.displayOptions;
nodeValuesRoot = nodeValuesRoot || nodeValues;
let value;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const values: any[] = [];
if (parameter.displayOptions.show) {
if (show) {
// All the defined rules have to match to display parameter
for (const propertyName of Object.keys(parameter.displayOptions.show)) {
if (propertyName.charAt(0) === '/') {
// Get the value from the root of the node
value = get(nodeValuesRoot, propertyName.slice(1));
} else if (propertyName === '@version') {
value = node?.typeVersion || 0;
} else {
// Get the value from current level
value = get(nodeValues, propertyName);
}
if (value && typeof value === 'object' && '__rl' in value && value.__rl) {
value = value.value;
}
values.length = 0;
if (!Array.isArray(value)) {
values.push(value);
} else {
values.push.apply(values, value);
}
for (const propertyName of Object.keys(show)) {
const values = getPropertyValues(nodeValues, propertyName, node, nodeValuesRoot);
if (values.some((v) => typeof v === 'string' && v.charAt(0) === '=')) {
return true;
}
if (
values.length === 0 ||
!parameter.displayOptions.show[propertyName]!.some((v) => values.includes(v))
) {
if (values.length === 0 || !checkConditions(show[propertyName]!, values)) {
return false;
}
}
}
if (parameter.displayOptions.hide) {
if (hide) {
// Any of the defined hide rules have to match to hide the parameter
for (const propertyName of Object.keys(parameter.displayOptions.hide)) {
if (propertyName.charAt(0) === '/') {
// Get the value from the root of the node
value = get(nodeValuesRoot, propertyName.slice(1));
} else if (propertyName === '@version') {
value = node?.typeVersion || 0;
} else {
// Get the value from current level
value = get(nodeValues, propertyName);
}
for (const propertyName of Object.keys(hide)) {
const values = getPropertyValues(nodeValues, propertyName, node, nodeValuesRoot);
if (value && typeof value === 'object' && '__rl' in value && value.__rl) {
value = value.value;
}
values.length = 0;
if (!Array.isArray(value)) {
values.push(value);
} else {
values.push.apply(values, value);
}
if (
values.length !== 0 &&
parameter.displayOptions.hide[propertyName]!.some((v) => values.includes(v))
) {
if (values.length !== 0 && checkConditions(hide[propertyName]!, values)) {
return false;
}
}

File diff suppressed because it is too large Load Diff