-
گره بعدی را انتخاب کنید
+
+
+ {{
+ addAt.allow === 'condition'
+ ? 'شرط جدید با «و» به شرطهای این شاخه اضافه میشود'
+ : 'گره بعدی را انتخاب کنید'
+ }}
+
-
انصراف
@@ -282,95 +393,26 @@ function nodeClass(step: AutomationStep) {
display: flex;
flex-direction: row;
align-items: center;
- gap: 0;
min-width: max-content;
min-height: 16rem;
}
-.node-wrap {
- position: relative;
- display: flex;
- align-items: center;
-}
-
-.node {
- width: 13.6rem;
- display: flex;
- align-items: center;
- gap: 0.7rem;
- text-align: start;
- padding: 0.72rem 0.8rem;
- border-radius: var(--radius);
- border: 1px solid #d5ddd8;
- background: #fff;
- box-shadow: 0 10px 24px rgba(23, 33, 28, 0.06);
- cursor: pointer;
- color: inherit;
- font: inherit;
-}
-
.node.trigger {
width: 14.2rem;
min-height: 4.35rem;
+ display: flex;
+ align-items: center;
+ gap: 0.7rem;
+ text-align: start;
border-radius: 999px;
- padding-inline: 1rem;
+ padding: 0.72rem 1rem;
+ border: 1px solid #fdba74;
background: #fff7ed;
- border-color: #fdba74;
-}
-
-.node.action:not(.condition) {
- border-radius: var(--radius);
- border-inline-start-width: 5px;
-}
-
-.node.create_activity {
- border-inline-start-color: #14b8a6;
-}
-
-.node.create_notification {
- border-inline-start-color: #2563eb;
-}
-
-.node.add_loyalty_points {
- border-inline-start-color: #7c3aed;
-}
-
-.node.condition {
- width: 15.1rem;
- min-height: 4.6rem;
- padding-inline: 1.15rem;
- border: 0;
- border-radius: 0;
- background: #fffbeb;
- box-shadow: none;
- clip-path: polygon(12% 0%, 88% 0%, 100% 50%, 88% 100%, 12% 100%, 0% 50%);
- filter: drop-shadow(0 8px 14px rgba(180, 83, 9, 0.14));
-}
-
-.branch-tag {
- position: absolute;
- top: -1.35rem;
- inset-inline-start: 50%;
- transform: translateX(50%);
- font-size: 0.68rem;
- font-weight: 700;
- color: #b45309;
- background: #fff7ed;
- border: 1px solid #fed7aa;
- border-radius: 999px;
- padding: 0.05rem 0.5rem;
- white-space: nowrap;
-}
-
-.node.condition.branch-start {
- background: #fef3c7;
-}
-
-.node.on {
- border-color: #14b8a6;
- box-shadow:
- 0 0 0 3px rgba(20, 184, 166, 0.18),
- 0 12px 24px rgba(15, 23, 42, 0.08);
+ box-shadow: 0 10px 24px rgba(23, 33, 28, 0.06);
+ cursor: pointer;
+ color: inherit;
+ font: inherit;
+ flex-shrink: 0;
}
.node.trigger.on {
@@ -380,46 +422,17 @@ function nodeClass(step: AutomationStep) {
0 12px 24px rgba(15, 23, 42, 0.08);
}
-.node.condition.on {
- box-shadow: none;
- filter:
- drop-shadow(0 0 0 3px rgba(217, 119, 6, 0.35))
- drop-shadow(0 8px 14px rgba(180, 83, 9, 0.14));
-}
-
.icon {
width: 2.35rem;
height: 2.35rem;
- border-radius: var(--radius);
+ border-radius: 999px;
display: grid;
place-items: center;
flex-shrink: 0;
- color: #0f766e;
- background: #ecfdf8;
-}
-
-.node.trigger .icon {
- border-radius: 999px;
color: #c2410c;
background: #ffedd5;
}
-.node.create_notification .icon {
- color: #1d4ed8;
- background: #eff6ff;
-}
-
-.node.add_loyalty_points .icon {
- color: #7c3aed;
- background: #f5f3ff;
-}
-
-.node.condition .icon {
- border-radius: var(--radius);
- color: #b45309;
- background: #ffedd5;
-}
-
.copy {
display: grid;
gap: 0.08rem;
@@ -438,39 +451,6 @@ strong {
color: #0f172a;
}
-em {
- font-style: normal;
- font-size: 0.72rem;
- color: #64748b;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.trash {
- position: absolute;
- top: -0.45rem;
- inset-inline-end: -0.45rem;
- width: 1.55rem;
- height: 1.55rem;
- border-radius: 999px;
- border: 1px solid #fecaca;
- background: #fff;
- color: #b91c1c;
- display: grid;
- place-items: center;
- cursor: pointer;
- opacity: 0;
- pointer-events: none;
-}
-
-.node-wrap:hover .trash,
-.node-wrap:focus-within .trash,
-.node.on ~ .trash {
- opacity: 1;
- pointer-events: auto;
-}
-
.wire {
position: relative;
width: 3.4rem;
@@ -490,6 +470,14 @@ em {
border-inline-end: 0;
}
+.wire.stub {
+ width: 1.6rem;
+}
+
+.wire.stub::after {
+ display: none;
+}
+
.plus {
position: absolute;
top: 50%;
@@ -522,17 +510,101 @@ em {
.wire.end {
width: 3.8rem;
- background: repeating-linear-gradient(
- 90deg,
- #cbd5e1 0 6px,
- transparent 6px 10px
- );
+ background: repeating-linear-gradient(90deg, #cbd5e1 0 6px, transparent 6px 10px);
}
.wire.end::after {
display: none;
}
+/* انشعاب: یک خط عمودی که از وسط اولین شاخه تا وسط آخرین شاخه کشیده میشود */
+.flow:has(.branches) {
+ padding-bottom: 2.6rem;
+}
+
+.branches {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+}
+
+.branch {
+ position: relative;
+ display: flex;
+ align-items: center;
+ padding-block: 1.3rem;
+}
+
+.branch::before {
+ content: '';
+ position: absolute;
+ inset-inline-start: 0;
+ width: 2px;
+ top: 0;
+ bottom: 0;
+ background: #cbd5e1;
+}
+
+.branch:first-of-type::before {
+ top: 50%;
+}
+
+.branch:last-of-type::before {
+ bottom: 50%;
+}
+
+.branch-tag {
+ position: absolute;
+ top: 0.05rem;
+ inset-inline-start: 0.9rem;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.25rem;
+ font-size: 0.68rem;
+ font-weight: 700;
+ color: #b45309;
+ background: #fff7ed;
+ border: 1px solid #fed7aa;
+ border-radius: 999px;
+ padding: 0.05rem 0.5rem;
+ white-space: nowrap;
+}
+
+.branch-tag button {
+ display: grid;
+ place-items: center;
+ border: 0;
+ background: none;
+ padding: 0;
+ color: #b91c1c;
+ cursor: pointer;
+}
+
+.add-branch {
+ position: absolute;
+ top: 100%;
+ inset-inline-start: 0.9rem;
+ display: inline-flex;
+ white-space: nowrap;
+ align-items: center;
+ gap: 0.35rem;
+ border: 1px dashed #f59e0b;
+ background: #fffbeb;
+ color: #b45309;
+ border-radius: 999px;
+ padding: 0.35rem 0.8rem;
+ font: inherit;
+ font-size: 0.78rem;
+ font-weight: 700;
+ cursor: pointer;
+}
+
+.add-branch:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
.picker {
margin-top: 1rem;
background: #fff;
@@ -603,16 +675,8 @@ em {
}
@media (max-width: 700px) {
- .node {
- width: 12.4rem;
- }
-
.node.trigger {
width: 13rem;
}
-
- .node.condition {
- width: 14rem;
- }
}
diff --git a/apps/web/src/components/automations/AutomationInspector.vue b/apps/web/src/components/automations/AutomationInspector.vue
index dda884f..938a8f0 100644
--- a/apps/web/src/components/automations/AutomationInspector.vue
+++ b/apps/web/src/components/automations/AutomationInspector.vue
@@ -37,6 +37,7 @@ const props = defineProps<{
forms: LeadFormDto[];
teams: TeamDto[];
activityTypeDefs: ActivityTypeDefDto[];
+ advanced: boolean;
}>();
const trigger = defineModel
('trigger', { required: true });
@@ -53,7 +54,12 @@ const isCondition = computed(
() => !!selectedStep.value && isAutomationCondition(selectedStep.value),
);
-const conditionFields = computed(() => conditionFieldsForTrigger(trigger.value));
+const conditionFields = computed(() =>
+ conditionFieldsForTrigger(trigger.value).filter(
+ (f) =>
+ props.advanced || f !== 'form_field' || selectedStep.value?.conditionField === f,
+ ),
+);
const conditionOps = computed((): AutomationConditionOp[] =>
conditionOpsForField(selectedStep.value?.conditionField),
@@ -77,7 +83,14 @@ const needsConditionValue = computed(() => {
return op !== 'is_set' && op !== 'is_empty';
});
-const assignModes = Object.keys(AUTOMATION_ASSIGN_MODE_LABELS) as AutomationAssignMode[];
+const assignModes = computed(() =>
+ (Object.keys(AUTOMATION_ASSIGN_MODE_LABELS) as AutomationAssignMode[]).filter(
+ (m) =>
+ props.advanced ||
+ (m !== 'team_round_robin' && m !== 'users_round_robin') ||
+ selectedStep.value?.assignMode === m,
+ ),
+);
const dueUnits = [
{ value: 'now', label: 'همان لحظه (امروز)' },
@@ -197,7 +210,7 @@ watch(
برای شرط روی پاسخهای فرم، یک فرم مشخص را انتخاب کنید.
-