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 /> )}