feat(automations): multi-option form-field conditions (all / any / none / exact)
This commit is contained in:
@@ -3166,6 +3166,7 @@ export type AutomationConditionOp =
|
||||
| "is_set"
|
||||
| "is_empty"
|
||||
| "contains"
|
||||
| "contains_any"
|
||||
| "not_contains";
|
||||
|
||||
/** stop: شرط ناموفق کل زنجیره را متوقف میکند — branches: هر شرط فقط عملهای بعدی خودش را تا شرط بعدی کنترل میکند */
|
||||
@@ -3214,6 +3215,7 @@ export const AUTOMATION_CONDITION_OP_LABELS: Record<
|
||||
is_set: "دارد",
|
||||
is_empty: "ندارد",
|
||||
contains: "شامل",
|
||||
contains_any: "شامل یکی از",
|
||||
not_contains: "شامل نیست",
|
||||
};
|
||||
|
||||
@@ -3269,7 +3271,7 @@ export function conditionOpsForField(
|
||||
if (field === "deal_amount") return ["gte", "lte", "eq", "neq"];
|
||||
if (field === "ticket_priority") return ["eq", "neq"];
|
||||
if (field === "form_field") {
|
||||
return ["contains", "not_contains", "eq", "neq", "is_set", "is_empty"];
|
||||
return ["contains", "contains_any", "not_contains", "eq", "neq", "is_set", "is_empty"];
|
||||
}
|
||||
return ["is_set", "is_empty"];
|
||||
}
|
||||
@@ -3289,6 +3291,8 @@ export interface AutomationStep {
|
||||
conditionField?: AutomationConditionField;
|
||||
conditionOp?: AutomationConditionOp;
|
||||
conditionValue?: string | number;
|
||||
/** چند گزینهٔ فیلد فرم (چندانتخابی)؛ اگر پر باشد بهجای conditionValue استفاده میشود */
|
||||
conditionValues?: string[];
|
||||
/** کلید فیلد فرم برای شرط form_field */
|
||||
conditionKey?: string | null;
|
||||
assignMode?: AutomationAssignMode;
|
||||
@@ -3365,6 +3369,9 @@ export function normalizeAutomationSteps(
|
||||
conditionField: s.conditionField,
|
||||
conditionOp: s.conditionOp,
|
||||
conditionValue: s.conditionValue,
|
||||
conditionValues: Array.isArray(s.conditionValues)
|
||||
? s.conditionValues.map((v) => String(v).trim()).filter(Boolean)
|
||||
: undefined,
|
||||
conditionKey: s.conditionKey,
|
||||
assignMode: s.assignMode,
|
||||
assigneeTeamId: s.assigneeTeamId,
|
||||
@@ -3518,27 +3525,49 @@ export function splitFormAnswer(raw: unknown): string[] {
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
/** گزینههای مورد انتظار شرط فرم: چندتایی اگر پر باشد، وگرنه مقدار تکی */
|
||||
export function formConditionValues(
|
||||
step: Pick<AutomationStep, "conditionValue" | "conditionValues">,
|
||||
): string[] {
|
||||
const many = (step.conditionValues ?? []).map((v) => String(v).trim()).filter(Boolean);
|
||||
if (many.length) return [...new Set(many)];
|
||||
const one = String(step.conditionValue ?? "").trim();
|
||||
return one ? [one] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* contains: همهٔ گزینهها انتخاب شده باشند — contains_any: حداقل یکی —
|
||||
* not_contains: هیچکدام — eq: دقیقاً همین گزینهها (نه بیشتر، نه کمتر)
|
||||
*/
|
||||
export function matchFormFieldCondition(
|
||||
op: AutomationConditionOp | undefined,
|
||||
raw: unknown,
|
||||
expected: unknown,
|
||||
expected: string | number | string[] | null | undefined,
|
||||
): boolean {
|
||||
const parts = splitFormAnswer(raw);
|
||||
const value = String(expected ?? "").trim();
|
||||
const whole = raw == null ? "" : String(raw).trim();
|
||||
const values = (Array.isArray(expected) ? expected : [expected])
|
||||
.map((v) => String(v ?? "").trim())
|
||||
.filter(Boolean);
|
||||
const exact = () =>
|
||||
values.length === 1
|
||||
? whole === values[0] || (parts.length === 1 && parts[0] === values[0])
|
||||
: new Set(parts).size === values.length && values.every((v) => parts.includes(v));
|
||||
switch (op ?? "contains") {
|
||||
case "is_set":
|
||||
return parts.length > 0;
|
||||
case "is_empty":
|
||||
return parts.length === 0;
|
||||
case "contains":
|
||||
return Boolean(value) && parts.includes(value);
|
||||
return values.length > 0 && values.every((v) => parts.includes(v));
|
||||
case "contains_any":
|
||||
return values.some((v) => parts.includes(v));
|
||||
case "not_contains":
|
||||
return !value || !parts.includes(value);
|
||||
return !values.some((v) => parts.includes(v));
|
||||
case "eq":
|
||||
return whole === value || (parts.length === 1 && parts[0] === value);
|
||||
return values.length > 0 && exact();
|
||||
case "neq":
|
||||
return !(whole === value || (parts.length === 1 && parts[0] === value));
|
||||
return !(values.length > 0 && exact());
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user