feat(automations): parallel branch canvas, simple/advanced level per org, rules list UX

This commit is contained in:
2026-10-11 14:48:12 +03:30
parent b3b92abae9
commit 17638786a8
18 changed files with 957 additions and 354 deletions
+47 -2
View File
@@ -114,6 +114,7 @@ export type OrgModuleKey =
| "activities"
| "tickets"
| "workflow_automations"
| "workflow_automations_advanced"
| "message_automations"
| "lead_forms"
| "project_boards"
@@ -153,6 +154,7 @@ export const ORG_MODULE_KEYS: OrgModuleKey[] = [
"activities",
"tickets",
"workflow_automations",
"workflow_automations_advanced",
"message_automations",
"lead_forms",
"leads",
@@ -193,6 +195,7 @@ export const ORG_MODULE_LABELS: Record<OrgModuleKey, string> = {
activities: "فعالیت‌ها",
tickets: "تیکت‌ها",
workflow_automations: "اتوماسیون گردش کار",
workflow_automations_advanced: "اتوماسیون گردش کار حرفه‌ای (چندشاخه)",
message_automations: "اتوماسیون پیامک",
lead_forms: "فرم‌ساز سرنخ",
leads: "مدیریت لیدها",
@@ -283,8 +286,11 @@ export function isOrgModuleKey(value: string): value is OrgModuleKey {
return (ORG_MODULE_KEYS as readonly string[]).includes(value);
}
/** ماژول‌هایی که باید صراحتاً توسط سوپرادمین فعال شوند */
export const OPT_IN_ORG_MODULES: OrgModuleKey[] = ["workflow_automations_advanced"];
export function defaultEnabledModules(): OrgModuleKey[] {
return [...ORG_MODULE_KEYS];
return ORG_MODULE_KEYS.filter((k) => !OPT_IN_ORG_MODULES.includes(k));
}
export interface SubscriptionSummaryDto {
@@ -3105,7 +3111,7 @@ export const AUTOMATION_ACTION_LABELS: Record<AutomationAction, string> = {
add_loyalty_points: "افزودن امتیاز باشگاه",
};
export const MAX_AUTOMATION_STEPS = 12;
export const MAX_AUTOMATION_STEPS = 20;
export const AUTOMATION_ACTIONS = [
"create_activity",
@@ -3464,6 +3470,45 @@ export function planAutomationActions(
return out;
}
export interface AutomationBranchRange {
/** اندیس اولین شرط شاخه */
start: number;
/** اندیس بعد از آخرین گام شاخه */
end: number;
}
/** گام‌های بدون شرط ابتدای زنجیره و بازهٔ هر شاخه (در حالت branches) */
export function splitAutomationBranches(steps: AutomationStep[]): {
prefixEnd: number;
branches: AutomationBranchRange[];
} {
const branches: AutomationBranchRange[] = [];
let prefixEnd = steps.length;
steps.forEach((step, i) => {
if (!isAutomationCondition(step)) return;
const prev = steps[i - 1];
if (prev && isAutomationCondition(prev)) return;
if (!branches.length) prefixEnd = i;
else branches[branches.length - 1].end = i;
branches.push({ start: i, end: steps.length });
});
return { prefixEnd, branches };
}
/** قانون از امکانات اتوماسیون حرفه‌ای (شاخه، شرط فرم، تخصیص نوبتی) استفاده می‌کند */
export function automationUsesAdvanced(
steps: AutomationStep[],
chainMode: AutomationChainMode | undefined,
): boolean {
if (chainMode === "branches") return true;
return steps.some(
(s) =>
(isAutomationCondition(s) && s.conditionField === "form_field") ||
s.assignMode === "team_round_robin" ||
s.assignMode === "users_round_robin",
);
}
/** مقدار پاسخ فرم را به گزینه‌ها می‌شکند (چندانتخابی با کاما ذخیره می‌شود) */
export function splitFormAnswer(raw: unknown): string[] {
if (raw == null) return [];