mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 17:29:45 +00:00
fix(automations): persist default match_type for Keyword Match triggers
Creating a keyword_match automation with Match type left on the default "Contains" failed activation with `match type must be "exact" or "contains"` (path trigger.match_type). The dropdown showed "Contains" via a display-only fallback, but the value was never written to the config, so the saved payload omitted match_type entirely. Both engines already treat a missing match_type as "contains" (automations/engine.ts, flows/engine.ts), so the activation validator was stricter than runtime. Two coordinated fixes: - validate.ts: accept a missing match_type (defaults to "contains"); only an explicit, unrecognised value is rejected. Aligns the validator with the engines and any non-UI client. - automation-builder.tsx: seed match_type: "contains" on mount of KeywordMatchConfig so the displayed default is actually persisted, keeping the saved record explicit and self-describing. Adds a regression test that a keyword_match config with no match_type passes activation validation. Fixes #271 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
9d13a1d308
commit
ca3aa29c3a
@ -723,6 +723,18 @@ function KeywordMatchConfig({
|
|||||||
// when the trigger type changes, so the seed stays in sync.
|
// when the trigger type changes, so the seed stays in sync.
|
||||||
const [draft, setDraft] = useState(keywords.join(", "))
|
const [draft, setDraft] = useState(keywords.join(", "))
|
||||||
|
|
||||||
|
// Persist the default the <select> displays. The dropdown falls back to
|
||||||
|
// "contains" for display, but leaving it untouched would otherwise omit
|
||||||
|
// match_type from the saved config — and activation validation then
|
||||||
|
// rejected it (trigger.match_type). Seed once on mount; the component
|
||||||
|
// remounts when the trigger type changes, matching the keywords draft.
|
||||||
|
useEffect(() => {
|
||||||
|
if (config?.match_type == null) {
|
||||||
|
onChange({ ...config, match_type: "contains" })
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [])
|
||||||
|
|
||||||
function commit() {
|
function commit() {
|
||||||
const parsed = draft
|
const parsed = draft
|
||||||
.split(",")
|
.split(",")
|
||||||
|
|||||||
@ -212,6 +212,12 @@ describe("validateTriggerForActivation", () => {
|
|||||||
expect(issues.map((i) => i.path)).toContain("trigger.match_type");
|
expect(issues.map((i) => i.path)).toContain("trigger.match_type");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("accepts keyword_match with a missing match_type (defaults to contains)", () => {
|
||||||
|
expect(
|
||||||
|
validateTriggerForActivation("keyword_match", { keywords: ["hi"] }),
|
||||||
|
).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
it("requires schedule on time_based triggers", () => {
|
it("requires schedule on time_based triggers", () => {
|
||||||
expect(validateTriggerForActivation("time_based", {})).toEqual([
|
expect(validateTriggerForActivation("time_based", {})).toEqual([
|
||||||
{ path: "trigger.schedule", message: "schedule is required" },
|
{ path: "trigger.schedule", message: "schedule is required" },
|
||||||
|
|||||||
@ -154,7 +154,13 @@ export function validateTriggerForActivation(
|
|||||||
} else if (k.some((v) => typeof v !== 'string' || v.trim() === '')) {
|
} else if (k.some((v) => typeof v !== 'string' || v.trim() === '')) {
|
||||||
issues.push({ path: 'trigger.keywords', message: 'keywords cannot be empty strings' })
|
issues.push({ path: 'trigger.keywords', message: 'keywords cannot be empty strings' })
|
||||||
}
|
}
|
||||||
if (cfg.match_type !== 'exact' && cfg.match_type !== 'contains') {
|
// A missing match_type defaults to "contains" at runtime (see
|
||||||
|
// automations/engine.ts and flows/engine.ts, which both read
|
||||||
|
// `match_type ?? "contains"`), so only an explicit, unrecognised
|
||||||
|
// value is invalid here. This keeps activation validation in step
|
||||||
|
// with the engine and with the builder's "Contains" default — an
|
||||||
|
// automation that shows the default in the UI must not be rejected.
|
||||||
|
if (cfg.match_type != null && cfg.match_type !== 'exact' && cfg.match_type !== 'contains') {
|
||||||
issues.push({
|
issues.push({
|
||||||
path: 'trigger.match_type',
|
path: 'trigger.match_type',
|
||||||
message: 'match type must be "exact" or "contains"',
|
message: 'match type must be "exact" or "contains"',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user