ui(alerts): ReviewStep blocks save on empty webhooks+targets
Shows a warning banner and disables the Save button when a rule has neither webhooks nor targets — would have been rejected at the server edge (Task 3.3 validator), now caught earlier in the wizard with clear reason.
This commit is contained in:
@@ -1,6 +1,26 @@
|
|||||||
import { Toggle } from '@cameleer/design-system';
|
import { useMemo } from 'react';
|
||||||
|
import { Alert, Toggle } from '@cameleer/design-system';
|
||||||
import { toRequest, type FormState } from './form-state';
|
import { toRequest, type FormState } from './form-state';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pure helper: returns a human-readable reason why saving should be blocked,
|
||||||
|
* or null when the rule is safe to save (from the wizard's perspective).
|
||||||
|
*
|
||||||
|
* Currently covers: a rule with no webhooks AND no targets would be rejected
|
||||||
|
* at the server edge (Task 3.3 validator) and would never notify anyone, so
|
||||||
|
* the wizard blocks it earlier with a clear reason. The helper is exported
|
||||||
|
* so `RuleEditorWizard` can also drive the Save button's `disabled` state
|
||||||
|
* off the same single source of truth.
|
||||||
|
*/
|
||||||
|
export function computeSaveBlockReason(form: FormState): string | null {
|
||||||
|
const noWebhooks = (form.webhooks ?? []).length === 0;
|
||||||
|
const noTargets = (form.targets ?? []).length === 0;
|
||||||
|
if (noWebhooks && noTargets) {
|
||||||
|
return 'Add at least one webhook or target \u2014 a rule with no recipients never notifies anyone.';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
export function ReviewStep({
|
export function ReviewStep({
|
||||||
form,
|
form,
|
||||||
setForm,
|
setForm,
|
||||||
@@ -9,8 +29,14 @@ export function ReviewStep({
|
|||||||
setForm?: (f: FormState) => void;
|
setForm?: (f: FormState) => void;
|
||||||
}) {
|
}) {
|
||||||
const req = toRequest(form);
|
const req = toRequest(form);
|
||||||
|
const saveBlockReason = useMemo(() => computeSaveBlockReason(form), [form]);
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'grid', gap: 12, maxWidth: 720 }}>
|
<div style={{ display: 'grid', gap: 12, maxWidth: 720 }}>
|
||||||
|
{saveBlockReason && (
|
||||||
|
<Alert variant="error" title="Rule cannot be saved yet">
|
||||||
|
{saveBlockReason}
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
<div>
|
<div>
|
||||||
<strong>Name:</strong> {form.name}
|
<strong>Name:</strong> {form.name}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { ScopeStep } from './ScopeStep';
|
|||||||
import { ConditionStep } from './ConditionStep';
|
import { ConditionStep } from './ConditionStep';
|
||||||
import { TriggerStep } from './TriggerStep';
|
import { TriggerStep } from './TriggerStep';
|
||||||
import { NotifyStep } from './NotifyStep';
|
import { NotifyStep } from './NotifyStep';
|
||||||
import { ReviewStep } from './ReviewStep';
|
import { ReviewStep, computeSaveBlockReason } from './ReviewStep';
|
||||||
import { prefillFromPromotion, type PrefillWarning } from './promotion-prefill';
|
import { prefillFromPromotion, type PrefillWarning } from './promotion-prefill';
|
||||||
import { useCatalog } from '../../../api/queries/catalog';
|
import { useCatalog } from '../../../api/queries/catalog';
|
||||||
import { useOutboundConnections } from '../../../api/queries/admin/outboundConnections';
|
import { useOutboundConnections } from '../../../api/queries/admin/outboundConnections';
|
||||||
@@ -194,7 +194,11 @@ export default function RuleEditorWizard() {
|
|||||||
Next
|
Next
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<Button variant="primary" onClick={onSave} disabled={create.isPending || update.isPending}>
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
onClick={onSave}
|
||||||
|
disabled={create.isPending || update.isPending || computeSaveBlockReason(form) !== null}
|
||||||
|
>
|
||||||
{isEdit ? 'Save changes' : 'Create rule'}
|
{isEdit ? 'Save changes' : 'Create rule'}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user