diff --git a/apps/web/cypress/tests/notification-editor/variants.spec.ts b/apps/web/cypress/tests/notification-editor/variants.spec.ts
index 408eaecf7d2..821a822a0c3 100644
--- a/apps/web/cypress/tests/notification-editor/variants.spec.ts
+++ b/apps/web/cypress/tests/notification-editor/variants.spec.ts
@@ -841,6 +841,40 @@ describe('Workflow Editor - Variants', function () {
cy.wait('@getWorkflow');
cy.getByTestId('variants-count').should('not.exist');
});
+
+ it('should not allow removing all conditions from a variant', function () {
+ createWorkflow('Test Removing All Conditions');
+
+ dragAndDrop('inApp');
+ editChannel('inApp');
+ fillEditorContent('inApp');
+ goBack();
+
+ showStepActions('inApp');
+ addVariantActionClick('inApp');
+ addConditions();
+
+ cy.getByTestId('notification-template-submit-btn').click();
+ cy.wait('@updateWorkflow');
+
+ cy.reload();
+ cy.wait('@getWorkflow');
+
+ // edit the variant condition
+ cy.getByTestId('editor-sidebar-edit-conditions').click();
+
+ // open conditions row menu
+ cy.getByTestId('conditions-row-btn').click();
+
+ // delete the condition
+ cy.contains('Delete').click();
+
+ // submit ("Apply conditions") should be disabled
+ cy.getByTestId('apply-conditions-btn').should('be.disabled').click({ force: true });
+
+ // tooltip should warn the user
+ cy.get('div[role="tooltip"]').contains('At least one condition is required');
+ });
});
describe('Variants List Errors', function () {
diff --git a/apps/web/src/components/conditions/Conditions.tsx b/apps/web/src/components/conditions/Conditions.tsx
index 7d88fe7fc51..40dc68f3aa7 100644
--- a/apps/web/src/components/conditions/Conditions.tsx
+++ b/apps/web/src/components/conditions/Conditions.tsx
@@ -26,6 +26,19 @@ import { OnlineConditionRow } from './OnlineConditionRow';
import { DefaultGroupOperatorData, DefaultOperatorData } from './constants';
import { PreviousStepsConditionRow } from './PreviousStepsConditionRow';
+export interface IConditionsComponentProps {
+ isOpened: boolean;
+ isReadonly?: boolean;
+ onClose: () => void;
+ updateConditions: (data: IConditions[]) => void;
+ conditions?: IConditions[];
+ name: string;
+ label?: string;
+ filterPartsList: IFilterTypeList[];
+ defaultFilter?: FilterPartTypeEnum;
+ shouldDisallowEmptyConditions?: boolean;
+}
+
export function Conditions({
isOpened,
isReadonly = false,
@@ -36,17 +49,8 @@ export function Conditions({
label = '',
filterPartsList,
defaultFilter,
-}: {
- isOpened: boolean;
- isReadonly?: boolean;
- onClose: () => void;
- updateConditions: (data: IConditions[]) => void;
- conditions?: IConditions[];
- name: string;
- label?: string;
- filterPartsList: IFilterTypeList[];
- defaultFilter?: FilterPartTypeEnum;
-}) {
+ shouldDisallowEmptyConditions,
+}: IConditionsComponentProps) {
const { colorScheme } = useMantineTheme();
const {
@@ -95,9 +99,17 @@ export function Conditions({
remove(index);
}
+ /** Flag for determining if conditions are empty but expected not to be */
+ const hasDisallowedEmptyConditions = Boolean(
+ shouldDisallowEmptyConditions && getValues().conditions?.some(({ children }) => !children?.[0])
+ );
+
+ const isSubmitDisabled =
+ !isDirty || isReadonly || (conditions?.length === 0 && fields?.length === 0) || hasDisallowedEmptyConditions;
+
const onApplyConditions = async () => {
await trigger('conditions');
- if (!errors.conditions) {
+ if (!errors.conditions && !isSubmitDisabled) {
updateConditions(getValues('conditions'));
onClose();
}
@@ -121,13 +133,16 @@ export function Conditions({
-
+
-
diff --git a/apps/web/src/pages/templates/components/EditorSidebarHeaderActions.tsx b/apps/web/src/pages/templates/components/EditorSidebarHeaderActions.tsx
index 0954bf86b9f..ec7bbd971d3 100644
--- a/apps/web/src/pages/templates/components/EditorSidebarHeaderActions.tsx
+++ b/apps/web/src/pages/templates/components/EditorSidebarHeaderActions.tsx
@@ -166,6 +166,7 @@ export const EditorSidebarHeaderActions = () => {
conditions={conditions}
filterPartsList={filterPartsList}
defaultFilter={FilterPartTypeEnum.PAYLOAD}
+ shouldDisallowEmptyConditions={isUnderVariantPath}
/>
)}
diff --git a/apps/web/src/pages/templates/components/VariantItemCard.tsx b/apps/web/src/pages/templates/components/VariantItemCard.tsx
index fe8a7c50725..9542a451f0f 100644
--- a/apps/web/src/pages/templates/components/VariantItemCard.tsx
+++ b/apps/web/src/pages/templates/components/VariantItemCard.tsx
@@ -264,6 +264,7 @@ export const VariantItemCard = ({
conditions={conditions}
filterPartsList={filterPartsList}
defaultFilter={FilterPartTypeEnum.PAYLOAD}
+ shouldDisallowEmptyConditions
/>
)}