@bigbinary/neeto-rules-frontend 2.7.20 → 2.7.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/app/javascript/src/translations/ar.json +2 -1
  2. package/app/javascript/src/translations/bg.json +2 -1
  3. package/app/javascript/src/translations/ca.json +2 -1
  4. package/app/javascript/src/translations/cs.json +2 -1
  5. package/app/javascript/src/translations/da.json +2 -1
  6. package/app/javascript/src/translations/de.json +2 -1
  7. package/app/javascript/src/translations/es-MX.json +2 -1
  8. package/app/javascript/src/translations/es.json +2 -1
  9. package/app/javascript/src/translations/et.json +2 -1
  10. package/app/javascript/src/translations/fi.json +2 -1
  11. package/app/javascript/src/translations/fil.json +2 -1
  12. package/app/javascript/src/translations/fr.json +2 -1
  13. package/app/javascript/src/translations/he.json +2 -1
  14. package/app/javascript/src/translations/hi.json +2 -1
  15. package/app/javascript/src/translations/hr.json +2 -1
  16. package/app/javascript/src/translations/hu.json +2 -1
  17. package/app/javascript/src/translations/id.json +2 -1
  18. package/app/javascript/src/translations/it.json +2 -1
  19. package/app/javascript/src/translations/ja.json +2 -1
  20. package/app/javascript/src/translations/ko.json +2 -1
  21. package/app/javascript/src/translations/nl.json +2 -1
  22. package/app/javascript/src/translations/pl.json +2 -1
  23. package/app/javascript/src/translations/pt-BR.json +2 -1
  24. package/app/javascript/src/translations/pt.json +2 -1
  25. package/app/javascript/src/translations/ro.json +2 -1
  26. package/app/javascript/src/translations/ru.json +2 -1
  27. package/app/javascript/src/translations/sk.json +2 -1
  28. package/app/javascript/src/translations/sl.json +2 -1
  29. package/app/javascript/src/translations/sv.json +2 -1
  30. package/app/javascript/src/translations/th.json +2 -1
  31. package/app/javascript/src/translations/tr.json +2 -1
  32. package/app/javascript/src/translations/uk.json +2 -1
  33. package/app/javascript/src/translations/vi.json +2 -1
  34. package/app/javascript/src/translations/zh-CN.json +2 -1
  35. package/app/javascript/src/translations/zh-TW.json +2 -1
  36. package/dist/.ready +1 -1
  37. package/dist/NeetoRulesBuilder.js +30 -2
  38. package/dist/NeetoRulesBuilder.js.map +1 -1
  39. package/dist/NeetoRulesForm.js +2 -2
  40. package/dist/cjs/NeetoRulesBuilder.js +30 -2
  41. package/dist/cjs/NeetoRulesBuilder.js.map +1 -1
  42. package/dist/cjs/NeetoRulesForm.js +2 -2
  43. package/dist/cjs/index.js +2 -2
  44. package/dist/cjs/v2/NeetoRules.js +1 -1
  45. package/dist/cjs/v2/NeetoRulesBuilder.js +407 -207
  46. package/dist/cjs/v2/NeetoRulesBuilder.js.map +1 -1
  47. package/dist/cjs/v2/NeetoRulesForm.js +10 -8
  48. package/dist/cjs/v2/NeetoRulesForm.js.map +1 -1
  49. package/dist/cjs/v2/RulePreview.js +1 -1
  50. package/dist/cjs/v2/hooks.js +2 -2
  51. package/dist/cjs/v2/index.js +4 -4
  52. package/dist/{index-DMCgC01M.js → index-49edM85x.js} +2 -2
  53. package/dist/{index-DMCgC01M.js.map → index-49edM85x.js.map} +1 -1
  54. package/dist/{index-D_dEe2Gg.js → index-BZYwFjcS.js} +2 -2
  55. package/dist/{index-D_dEe2Gg.js.map → index-BZYwFjcS.js.map} +1 -1
  56. package/dist/{index-BXLCiV70.js → index-CcbW7H2S.js} +67 -21
  57. package/dist/index-CcbW7H2S.js.map +1 -0
  58. package/dist/{index-hvuc6OIP.js → index-Fukq1VSN.js} +69 -18
  59. package/dist/index-Fukq1VSN.js.map +1 -0
  60. package/dist/index.js +2 -2
  61. package/dist/keyboardShortcuts-DtnjcivY.js +96 -0
  62. package/dist/{keyboardShortcuts-lX0oq49M.js.map → keyboardShortcuts-DtnjcivY.js.map} +1 -1
  63. package/dist/keyboardShortcuts-_OrtgF0A.js +92 -0
  64. package/dist/{keyboardShortcuts-DXP5YgeG.js.map → keyboardShortcuts-_OrtgF0A.js.map} +1 -1
  65. package/dist/{useCustomDataStore-CU3KpyD4.js → useCustomDataStore-CEbhXugO.js} +2 -2
  66. package/dist/{useCustomDataStore-CU3KpyD4.js.map → useCustomDataStore-CEbhXugO.js.map} +1 -1
  67. package/dist/{useCustomDataStore-D9k8F5g-.js → useCustomDataStore-DPmWkEhs.js} +2 -2
  68. package/dist/{useCustomDataStore-D9k8F5g-.js.map → useCustomDataStore-DPmWkEhs.js.map} +1 -1
  69. package/dist/{useUtilityStore-BBb39TOj.js → useUtilityStore-BVCulMEC.js} +9 -2
  70. package/dist/useUtilityStore-BVCulMEC.js.map +1 -0
  71. package/dist/{useUtilityStore-DkxAexDw.js → useUtilityStore-gtPhFvpI.js} +9 -2
  72. package/dist/useUtilityStore-gtPhFvpI.js.map +1 -0
  73. package/dist/v2/NeetoRules.js +1 -1
  74. package/dist/v2/NeetoRulesBuilder.js +388 -207
  75. package/dist/v2/NeetoRulesBuilder.js.map +1 -1
  76. package/dist/v2/NeetoRulesForm.js +10 -8
  77. package/dist/v2/NeetoRulesForm.js.map +1 -1
  78. package/dist/v2/RulePreview.js +1 -1
  79. package/dist/v2/hooks.js +2 -2
  80. package/dist/v2/index.js +4 -4
  81. package/package.json +7 -7
  82. package/dist/index-BXLCiV70.js.map +0 -1
  83. package/dist/index-hvuc6OIP.js.map +0 -1
  84. package/dist/keyboardShortcuts-DXP5YgeG.js +0 -92
  85. package/dist/keyboardShortcuts-lX0oq49M.js +0 -96
  86. package/dist/useUtilityStore-BBb39TOj.js.map +0 -1
  87. package/dist/useUtilityStore-DkxAexDw.js.map +0 -1
@@ -2,7 +2,7 @@
2
2
 
3
3
  var _defineProperty = require('@babel/runtime/helpers/defineProperty');
4
4
  var _objectDestructuringEmpty = require('@babel/runtime/helpers/objectDestructuringEmpty');
5
- var keyboardShortcuts = require('../../keyboardShortcuts-lX0oq49M.js');
5
+ var keyboardShortcuts = require('../../keyboardShortcuts-DtnjcivY.js');
6
6
  var shallow = require('zustand/shallow');
7
7
  var react = require('react');
8
8
  var neetoAtoms = require('@bigbinary/neeto-atoms');
@@ -13,9 +13,9 @@ var neetoCist = require('@bigbinary/neeto-cist');
13
13
  var Container = require('@bigbinary/neeto-molecules/v2/Container');
14
14
  var Header = require('@bigbinary/neeto-molecules/v2/Header');
15
15
  var reactI18next = require('react-i18next');
16
- var index = require('../../index-hvuc6OIP.js');
17
- var useCustomDataStore = require('../../useCustomDataStore-D9k8F5g-.js');
18
- var useUtilityStore = require('../../useUtilityStore-DkxAexDw.js');
16
+ var index = require('../../index-Fukq1VSN.js');
17
+ var useCustomDataStore = require('../../useCustomDataStore-DPmWkEhs.js');
18
+ var useUtilityStore = require('../../useUtilityStore-gtPhFvpI.js');
19
19
  var _toConsumableArray = require('@babel/runtime/helpers/toConsumableArray');
20
20
  var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
21
21
  var Plus = require('@bigbinary/neeto-icons/Plus');
@@ -24,6 +24,7 @@ var Delete = require('@bigbinary/neeto-icons/Delete');
24
24
  var _objectWithoutProperties = require('@babel/runtime/helpers/objectWithoutProperties');
25
25
  var jsxRuntime = require('react/jsx-runtime');
26
26
  var i18next = require('i18next');
27
+ var yup = require('yup');
27
28
  var _asyncToGenerator = require('@babel/runtime/helpers/asyncToGenerator');
28
29
  var useHotkeys = require('@bigbinary/neeto-hotkeys');
29
30
  var Search = require('@bigbinary/neeto-icons/Search');
@@ -37,7 +38,6 @@ require('@tanstack/react-query');
37
38
  require('@bigbinary/neeto-commons-frontend/react-utils');
38
39
  require('axios');
39
40
  require('../../index-DFwPrb81.js');
40
- require('yup');
41
41
  require('lucide-react');
42
42
  require('@bigbinary/neeto-commons-frontend/v2/react-utils');
43
43
  require('@monaco-editor/react');
@@ -54,6 +54,25 @@ require('zustand');
54
54
  require('@bigbinary/neeto-commons-frontend/initializers');
55
55
  require('@bigbinary/neeto-commons-frontend/utils');
56
56
 
57
+ function _interopNamespaceDefault(e) {
58
+ var n = Object.create(null);
59
+ if (e) {
60
+ Object.keys(e).forEach(function (k) {
61
+ if (k !== 'default') {
62
+ var d = Object.getOwnPropertyDescriptor(e, k);
63
+ Object.defineProperty(n, k, d.get ? d : {
64
+ enumerable: true,
65
+ get: function () { return e[k]; }
66
+ });
67
+ }
68
+ });
69
+ }
70
+ n.default = e;
71
+ return Object.freeze(n);
72
+ }
73
+
74
+ var yup__namespace = /*#__PURE__*/_interopNamespaceDefault(yup);
75
+
57
76
  var _TOKEN_TO_PANEL_TYPE;
58
77
  var PARAM_KIND = {
59
78
  ENUM_SINGLE: "enum-single",
@@ -81,6 +100,22 @@ var TIME_UNITS = [{
81
100
  /* eslint-enable @bigbinary/neeto/neetocommons-tips */
82
101
 
83
102
  var LEAD_TIME_UNITS = TIME_UNITS;
103
+
104
+ // Mirrors the classic form's three-digit input cap; 999 days equals the
105
+ // backend's maximum lead time.
106
+ var MAX_LEAD_TIME_VALUE = 999;
107
+ var STEPPER_DELTA = {
108
+ INCREMENT: 1,
109
+ DECREMENT: -1
110
+ };
111
+ var STEPPER_MIN_VALUE = 1;
112
+ var DEFAULT_DELAY_VALUE = 10;
113
+
114
+ // Matches the token flash animation duration in sentence-builder.css.
115
+ var FLASH_DURATION_MS = 2200;
116
+
117
+ // Keeps an element out of the keyboard tab order (HTML tabindex sentinel).
118
+ var SKIP_TAB_INDEX = -1;
84
119
  var CONDITION_VERBS = {
85
120
  IS: "is",
86
121
  IS_NOT: "is_not",
@@ -178,7 +213,11 @@ var CONFIG_FOCUSABLE_SELECTOR = 'input:not([type="radio"]):not([type="checkbox"]
178
213
  var SMS_TYPES = ["sms", "smsToNumbers"];
179
214
  var RECIPIENT_FOCUSABLE_SELECTOR = 'input, textarea, [contenteditable="true"]';
180
215
  var SMS_TO_NUMBERS = "smsToNumbers";
181
- var SWAP_CHANNEL_ORDER = ["email", "sms", "slack", "webhook", "calendar_invite"];
216
+ var RECIPIENT_STORAGE_FIELDS = {
217
+ emails: "emails",
218
+ value: "value",
219
+ phoneNumbers: "phoneNumbers"
220
+ };
182
221
  var DEFAULT_DELAY_UNITS = TIME_UNITS;
183
222
 
184
223
  var useClearingHover = function useClearingHover() {
@@ -445,6 +484,18 @@ var actionParts = function actionParts(_ref11) {
445
484
  recipientSubtitle: channelMeta.recipientSubtitle || (option === null || option === void 0 ? void 0 : option.recipientSubtitle)
446
485
  };
447
486
  };
487
+
488
+ // Which condition fields a host offers can depend on the rule — a trigger may
489
+ // only support a subset. Lookups deliberately keep using the full list so a
490
+ // field already on the rule still resolves after the offer narrows.
491
+ var offeredConditionFields = function offeredConditionFields(_ref12) {
492
+ var _ref13, _schema$conditions$fi, _schema$conditions3, _schema$conditions3$f, _schema$conditions4;
493
+ var schema = _ref12.schema,
494
+ rule = _ref12.rule;
495
+ return (_ref13 = (_schema$conditions$fi = schema === null || schema === void 0 || (_schema$conditions3 = schema.conditions) === null || _schema$conditions3 === void 0 || (_schema$conditions3$f = _schema$conditions3.fieldsFor) === null || _schema$conditions3$f === void 0 ? void 0 : _schema$conditions3$f.call(_schema$conditions3, {
496
+ rule: rule
497
+ })) !== null && _schema$conditions$fi !== void 0 ? _schema$conditions$fi : schema === null || schema === void 0 || (_schema$conditions4 = schema.conditions) === null || _schema$conditions4 === void 0 ? void 0 : _schema$conditions4.fields) !== null && _ref13 !== void 0 ? _ref13 : [];
498
+ };
448
499
  var hasTrigger = function hasTrigger(rule) {
449
500
  return !ramda.isEmpty((rule === null || rule === void 0 ? void 0 : rule.triggers) || []);
450
501
  };
@@ -456,28 +507,28 @@ var hasAction = function hasAction(rule) {
456
507
  var isRuleComplete = function isRuleComplete(rule) {
457
508
  return hasTrigger(rule) && hasAction(rule);
458
509
  };
459
- var scopeOptionFor = function scopeOptionFor(_ref12) {
510
+ var scopeOptionFor = function scopeOptionFor(_ref14) {
460
511
  var _item$value, _schema$scope;
461
- var schema = _ref12.schema,
462
- item = _ref12.item;
512
+ var schema = _ref14.schema,
513
+ item = _ref14.item;
463
514
  var value = (_item$value = item === null || item === void 0 ? void 0 : item.value) !== null && _item$value !== void 0 ? _item$value : item;
464
515
  return ((schema === null || schema === void 0 || (_schema$scope = schema.scope) === null || _schema$scope === void 0 ? void 0 : _schema$scope.options) || []).find(function (candidate) {
465
516
  var _candidate$value2;
466
517
  return ((_candidate$value2 = candidate.value) !== null && _candidate$value2 !== void 0 ? _candidate$value2 : candidate.id) === value;
467
518
  });
468
519
  };
469
- var scopePhoneFields = function scopePhoneFields(_ref13) {
470
- var _ref14, _item$phoneFields, _scopeOptionFor;
471
- var schema = _ref13.schema,
472
- item = _ref13.item;
473
- return (_ref14 = (_item$phoneFields = item === null || item === void 0 ? void 0 : item.phoneFields) !== null && _item$phoneFields !== void 0 ? _item$phoneFields : (_scopeOptionFor = scopeOptionFor({
520
+ var scopePhoneFields = function scopePhoneFields(_ref15) {
521
+ var _ref16, _item$phoneFields, _scopeOptionFor;
522
+ var schema = _ref15.schema,
523
+ item = _ref15.item;
524
+ return (_ref16 = (_item$phoneFields = item === null || item === void 0 ? void 0 : item.phoneFields) !== null && _item$phoneFields !== void 0 ? _item$phoneFields : (_scopeOptionFor = scopeOptionFor({
474
525
  schema: schema,
475
526
  item: item
476
- })) === null || _scopeOptionFor === void 0 ? void 0 : _scopeOptionFor.phoneFields) !== null && _ref14 !== void 0 ? _ref14 : null;
527
+ })) === null || _scopeOptionFor === void 0 ? void 0 : _scopeOptionFor.phoneFields) !== null && _ref16 !== void 0 ? _ref16 : null;
477
528
  };
478
- var effectiveScopePhoneField = function effectiveScopePhoneField(_ref15) {
479
- var schema = _ref15.schema,
480
- item = _ref15.item;
529
+ var effectiveScopePhoneField = function effectiveScopePhoneField(_ref17) {
530
+ var schema = _ref17.schema,
531
+ item = _ref17.item;
481
532
  if (item !== null && item !== void 0 && item.phoneField) return item.phoneField;
482
533
  var phoneFields = scopePhoneFields({
483
534
  schema: schema,
@@ -485,14 +536,14 @@ var effectiveScopePhoneField = function effectiveScopePhoneField(_ref15) {
485
536
  });
486
537
  return (phoneFields === null || phoneFields === void 0 ? void 0 : phoneFields.length) === 1 ? phoneFields[0].value : undefined;
487
538
  };
488
- var invalidScopeIndexes = function invalidScopeIndexes(_ref16) {
539
+ var invalidScopeIndexes = function invalidScopeIndexes(_ref18) {
489
540
  var _scope$requiresPhone;
490
- var rule = _ref16.rule,
491
- schema = _ref16.schema;
541
+ var rule = _ref18.rule,
542
+ schema = _ref18.schema;
492
543
  var scope = schema === null || schema === void 0 ? void 0 : schema.scope;
493
544
  if (!(scope !== null && scope !== void 0 && scope.enabled) || !((_scope$requiresPhone = scope.requiresPhone) !== null && _scope$requiresPhone !== void 0 && _scope$requiresPhone.call(scope, (rule === null || rule === void 0 ? void 0 : rule.actions) || []))) return [];
494
545
  return ((rule === null || rule === void 0 ? void 0 : rule.scope) || []).reduce(function (indexes, item, index) {
495
- var _ref17, _item$hasPhoneField;
546
+ var _ref19, _item$hasPhoneField;
496
547
  var option = scopeOptionFor({
497
548
  schema: schema,
498
549
  item: item
@@ -501,15 +552,15 @@ var invalidScopeIndexes = function invalidScopeIndexes(_ref16) {
501
552
  schema: schema,
502
553
  item: item
503
554
  });
504
- var hasPhoneField = (_ref17 = (_item$hasPhoneField = item === null || item === void 0 ? void 0 : item.hasPhoneField) !== null && _item$hasPhoneField !== void 0 ? _item$hasPhoneField : option === null || option === void 0 ? void 0 : option.hasPhoneField) !== null && _ref17 !== void 0 ? _ref17 : phoneFields ? phoneFields.length > 0 : undefined;
555
+ var hasPhoneField = (_ref19 = (_item$hasPhoneField = item === null || item === void 0 ? void 0 : item.hasPhoneField) !== null && _item$hasPhoneField !== void 0 ? _item$hasPhoneField : option === null || option === void 0 ? void 0 : option.hasPhoneField) !== null && _ref19 !== void 0 ? _ref19 : phoneFields ? phoneFields.length > 0 : undefined;
505
556
  if (hasPhoneField === false) indexes.push(index);
506
557
  return indexes;
507
558
  }, []);
508
559
  };
509
- var invalidScopePhoneFieldIndexes = function invalidScopePhoneFieldIndexes(_ref18) {
560
+ var invalidScopePhoneFieldIndexes = function invalidScopePhoneFieldIndexes(_ref20) {
510
561
  var _scope$requiresPhone2;
511
- var rule = _ref18.rule,
512
- schema = _ref18.schema;
562
+ var rule = _ref20.rule,
563
+ schema = _ref20.schema;
513
564
  var scope = schema === null || schema === void 0 ? void 0 : schema.scope;
514
565
  if (!(scope !== null && scope !== void 0 && scope.enabled) || !((_scope$requiresPhone2 = scope.requiresPhone) !== null && _scope$requiresPhone2 !== void 0 && _scope$requiresPhone2.call(scope, (rule === null || rule === void 0 ? void 0 : rule.actions) || []))) return [];
515
566
  return ((rule === null || rule === void 0 ? void 0 : rule.scope) || []).reduce(function (indexes, item, index) {
@@ -546,14 +597,33 @@ var minutesToParts = function minutesToParts(minutes) {
546
597
  unit: "minutes"
547
598
  };
548
599
  };
549
- var partsToMinutes = function partsToMinutes(_ref19) {
550
- var value = _ref19.value,
551
- unit = _ref19.unit;
600
+ var partsToMinutes = function partsToMinutes(_ref21) {
601
+ var value = _ref21.value,
602
+ unit = _ref21.unit;
552
603
  return (
553
604
  // eslint-disable-next-line security/detect-object-injection
554
605
  (Number(value) || 0) * (UNIT_MINUTES[unit] || 1)
555
606
  );
556
607
  };
608
+ var leadTimeExceedsMax = function leadTimeExceedsMax(minutes) {
609
+ return minutesToParts(minutes).value > MAX_LEAD_TIME_VALUE;
610
+ };
611
+ var leadTimeValidationSchema = function leadTimeValidationSchema(schema) {
612
+ var _schema$triggers2;
613
+ var fieldKey = schema === null || schema === void 0 || (_schema$triggers2 = schema.triggers) === null || _schema$triggers2 === void 0 || (_schema$triggers2 = _schema$triggers2.leadTime) === null || _schema$triggers2 === void 0 ? void 0 : _schema$triggers2.fieldKey;
614
+ if (!fieldKey) return yup__namespace.object();
615
+ return yup__namespace.object().shape(_defineProperty({}, fieldKey, yup__namespace.object().shape({
616
+ // yup 0.32 can only concat schemas of the same type, and the host's
617
+ // generic field schema for the lead time key is a string schema.
618
+ value: yup__namespace.string().test("max-lead-time", function () {
619
+ return i18next.t("neetoRules.validations.maxLeadTime", {
620
+ max: MAX_LEAD_TIME_VALUE
621
+ });
622
+ }, function (minutes) {
623
+ return !leadTimeExceedsMax(minutes);
624
+ })
625
+ })));
626
+ };
557
627
  var leadTimeLabel = function leadTimeLabel(minutes) {
558
628
  var _minutesToParts = minutesToParts(minutes),
559
629
  value = _minutesToParts.value,
@@ -576,30 +646,33 @@ var normalizeSchema = function normalizeSchema() {
576
646
  var joinTypeFor = function joinTypeFor(mode) {
577
647
  return mode === CONDITION_MODE.OR ? JOIN_TYPE.or : JOIN_TYPE.and;
578
648
  };
649
+ var recipientStorageField = function recipientStorageField(field) {
650
+ return field === RECIPIENT_STORAGE_FIELDS.emails ? RECIPIENT_STORAGE_FIELDS.emails : RECIPIENT_STORAGE_FIELDS.value;
651
+ };
579
652
  var modeFromJoinType = function modeFromJoinType(joinType) {
580
653
  return joinType === JOIN_TYPE.or ? CONDITION_MODE.OR : CONDITION_MODE.AND;
581
654
  };
582
655
 
583
656
  // eslint-disable-next-line security/detect-object-injection
584
- var valueAt = function valueAt(_ref20) {
657
+ var valueAt = function valueAt(_ref22) {
585
658
  var _values$key;
586
- var values = _ref20.values,
587
- key = _ref20.key;
659
+ var values = _ref22.values,
660
+ key = _ref22.key;
588
661
  return values === null || values === void 0 || (_values$key = values[key]) === null || _values$key === void 0 ? void 0 : _values$key.value;
589
662
  };
590
663
  var asArray = function asArray(maybeArray) {
591
664
  return Array.isArray(maybeArray) ? maybeArray : [];
592
665
  };
593
666
  var fieldKeysFromSchema = function fieldKeysFromSchema() {
594
- var _schema$triggers2, _schema$actor2, _schema$conditions3, _schema$actions3, _schema$delay, _schema$triggers3, _schema$scope2;
667
+ var _schema$triggers3, _schema$actor2, _schema$conditions5, _schema$actions3, _schema$delay, _schema$triggers4, _schema$scope2;
595
668
  var schema = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
596
669
  return {
597
- triggers: ((_schema$triggers2 = schema.triggers) === null || _schema$triggers2 === void 0 ? void 0 : _schema$triggers2.fieldKey) || "events",
670
+ triggers: ((_schema$triggers3 = schema.triggers) === null || _schema$triggers3 === void 0 ? void 0 : _schema$triggers3.fieldKey) || "events",
598
671
  performer: ((_schema$actor2 = schema.actor) === null || _schema$actor2 === void 0 ? void 0 : _schema$actor2.fieldKey) || "performer",
599
- conditions: ((_schema$conditions3 = schema.conditions) === null || _schema$conditions3 === void 0 ? void 0 : _schema$conditions3.fieldKey) || "conditions",
672
+ conditions: ((_schema$conditions5 = schema.conditions) === null || _schema$conditions5 === void 0 ? void 0 : _schema$conditions5.fieldKey) || "conditions",
600
673
  actions: ((_schema$actions3 = schema.actions) === null || _schema$actions3 === void 0 ? void 0 : _schema$actions3.fieldKey) || "actions",
601
674
  delay: ((_schema$delay = schema.delay) === null || _schema$delay === void 0 ? void 0 : _schema$delay.fieldKey) || "execution_delay",
602
- leadTime: (_schema$triggers3 = schema.triggers) === null || _schema$triggers3 === void 0 || (_schema$triggers3 = _schema$triggers3.leadTime) === null || _schema$triggers3 === void 0 ? void 0 : _schema$triggers3.fieldKey,
675
+ leadTime: (_schema$triggers4 = schema.triggers) === null || _schema$triggers4 === void 0 || (_schema$triggers4 = _schema$triggers4.leadTime) === null || _schema$triggers4 === void 0 ? void 0 : _schema$triggers4.fieldKey,
603
676
  scope: ((_schema$scope2 = schema.scope) === null || _schema$scope2 === void 0 ? void 0 : _schema$scope2.fieldKey) || "meetingIds",
604
677
  status: "status",
605
678
  name: "name"
@@ -607,11 +680,11 @@ var fieldKeysFromSchema = function fieldKeysFromSchema() {
607
680
  };
608
681
  var valuesToRuleModel = function valuesToRuleModel() {
609
682
  var _valueAt, _conditions$;
610
- var _ref21 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
611
- _ref21$values = _ref21.values,
612
- values = _ref21$values === void 0 ? {} : _ref21$values,
613
- _ref21$schema = _ref21.schema,
614
- schema = _ref21$schema === void 0 ? {} : _ref21$schema;
683
+ var _ref23 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
684
+ _ref23$values = _ref23.values,
685
+ values = _ref23$values === void 0 ? {} : _ref23$values,
686
+ _ref23$schema = _ref23.schema,
687
+ schema = _ref23$schema === void 0 ? {} : _ref23$schema;
615
688
  var keys = fieldKeysFromSchema(schema);
616
689
  var conditions = asArray(valueAt({
617
690
  values: values,
@@ -655,42 +728,42 @@ var valuesToRuleModel = function valuesToRuleModel() {
655
728
  }))
656
729
  };
657
730
  };
658
- var setTriggers = function setTriggers(_ref22) {
659
- var schema = _ref22.schema,
660
- triggers = _ref22.triggers;
731
+ var setTriggers = function setTriggers(_ref24) {
732
+ var schema = _ref24.schema,
733
+ triggers = _ref24.triggers;
661
734
  return {
662
735
  path: "".concat(fieldKeysFromSchema(schema).triggers, ".value"),
663
736
  value: triggers
664
737
  };
665
738
  };
666
- var setPerformer = function setPerformer(_ref23) {
667
- var schema = _ref23.schema,
668
- performer = _ref23.performer;
739
+ var setPerformer = function setPerformer(_ref25) {
740
+ var schema = _ref25.schema,
741
+ performer = _ref25.performer;
669
742
  return {
670
743
  path: "".concat(fieldKeysFromSchema(schema).performer, ".value"),
671
744
  value: performer
672
745
  };
673
746
  };
674
- var setActions = function setActions(_ref24) {
675
- var schema = _ref24.schema,
676
- actions = _ref24.actions;
747
+ var setActions = function setActions(_ref26) {
748
+ var schema = _ref26.schema,
749
+ actions = _ref26.actions;
677
750
  return {
678
751
  path: "".concat(fieldKeysFromSchema(schema).actions, ".value"),
679
752
  value: actions
680
753
  };
681
754
  };
682
- var setConditions = function setConditions(_ref25) {
683
- var schema = _ref25.schema,
684
- conditions = _ref25.conditions;
755
+ var setConditions = function setConditions(_ref27) {
756
+ var schema = _ref27.schema,
757
+ conditions = _ref27.conditions;
685
758
  return {
686
759
  path: "".concat(fieldKeysFromSchema(schema).conditions, ".value"),
687
760
  value: conditions
688
761
  };
689
762
  };
690
- var setConditionMode = function setConditionMode(_ref26) {
691
- var schema = _ref26.schema,
692
- conditions = _ref26.conditions,
693
- joinType = _ref26.joinType;
763
+ var setConditionMode = function setConditionMode(_ref28) {
764
+ var schema = _ref28.schema,
765
+ conditions = _ref28.conditions,
766
+ joinType = _ref28.joinType;
694
767
  return setConditions({
695
768
  schema: schema,
696
769
  conditions: conditions.map(function (condition) {
@@ -698,34 +771,34 @@ var setConditionMode = function setConditionMode(_ref26) {
698
771
  })
699
772
  });
700
773
  };
701
- var setDelay = function setDelay(_ref27) {
702
- var schema = _ref27.schema,
703
- delay = _ref27.delay;
774
+ var setDelay = function setDelay(_ref29) {
775
+ var schema = _ref29.schema,
776
+ delay = _ref29.delay;
704
777
  return {
705
778
  path: "".concat(fieldKeysFromSchema(schema).delay, ".value"),
706
779
  value: delay !== null && delay !== void 0 ? delay : {}
707
780
  };
708
781
  };
709
- var setActive = function setActive(_ref28) {
710
- var schema = _ref28.schema,
711
- active = _ref28.active;
782
+ var setActive = function setActive(_ref30) {
783
+ var schema = _ref30.schema,
784
+ active = _ref30.active;
712
785
  return {
713
786
  path: "".concat(fieldKeysFromSchema(schema).status, ".value"),
714
787
  value: active ? STATUS_KEYS.ENABLED : STATUS_KEYS.DISABLED
715
788
  };
716
789
  };
717
- var setScope = function setScope(_ref29) {
718
- var schema = _ref29.schema,
719
- scope = _ref29.scope;
790
+ var setScope = function setScope(_ref31) {
791
+ var schema = _ref31.schema,
792
+ scope = _ref31.scope;
720
793
  return {
721
794
  path: "".concat(fieldKeysFromSchema(schema).scope, ".value"),
722
795
  value: scope
723
796
  };
724
797
  };
725
- var removeArrayItem = function removeArrayItem(_ref30) {
726
- var values = _ref30.values,
727
- fieldKey = _ref30.fieldKey,
728
- index = _ref30.index;
798
+ var removeArrayItem = function removeArrayItem(_ref32) {
799
+ var values = _ref32.values,
800
+ fieldKey = _ref32.fieldKey,
801
+ index = _ref32.index;
729
802
  var list = asArray(valueAt({
730
803
  values: values,
731
804
  key: fieldKey
@@ -752,6 +825,35 @@ var removeArrayItem = function removeArrayItem(_ref30) {
752
825
  }
753
826
  return result;
754
827
  };
828
+ var clearArrayItems = function clearArrayItems(_ref33) {
829
+ var values = _ref33.values,
830
+ fieldKey = _ref33.fieldKey;
831
+ var list = asArray(valueAt({
832
+ values: values,
833
+ key: fieldKey
834
+ }));
835
+ var removed = list.filter(function (item) {
836
+ return item === null || item === void 0 ? void 0 : item.id;
837
+ }).map(function (item) {
838
+ return _objectSpread$b(_objectSpread$b({}, item), {}, {
839
+ _destroy: true
840
+ });
841
+ });
842
+ var result = [{
843
+ path: "".concat(fieldKey, ".value"),
844
+ value: []
845
+ }];
846
+ if (removed.length) {
847
+ var _values$fieldKey2;
848
+ // eslint-disable-next-line security/detect-object-injection
849
+ var deleted = asArray(values === null || values === void 0 || (_values$fieldKey2 = values[fieldKey]) === null || _values$fieldKey2 === void 0 ? void 0 : _values$fieldKey2.deleted);
850
+ result.push({
851
+ path: "".concat(fieldKey, ".deleted"),
852
+ value: [].concat(_toConsumableArray(deleted), _toConsumableArray(removed))
853
+ });
854
+ }
855
+ return result;
856
+ };
755
857
 
756
858
  function ownKeys$a(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
757
859
  function _objectSpread$a(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$a(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$a(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -1031,6 +1133,7 @@ var MetaBlock = function MetaBlock(_ref) {
1031
1133
  children: t("neetoRules.builder.automationName")
1032
1134
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
1033
1135
  ref: nameRef,
1136
+ "data-testid": "rule-name-edit",
1034
1137
  role: handleEditName ? "button" : undefined,
1035
1138
  tabIndex: handleEditName ? 0 : undefined,
1036
1139
  className: classNames("mb-meta-input-wrap", {
@@ -1039,6 +1142,7 @@ var MetaBlock = function MetaBlock(_ref) {
1039
1142
  onClick: handleEditName,
1040
1143
  children: [/*#__PURE__*/jsxRuntime.jsx("span", {
1041
1144
  className: "mb-meta-name-display",
1145
+ "data-testid": "rule-name",
1042
1146
  children: rule.name
1043
1147
  }), /*#__PURE__*/jsxRuntime.jsx("span", {
1044
1148
  "aria-hidden": true,
@@ -1060,8 +1164,10 @@ var MetaBlock = function MetaBlock(_ref) {
1060
1164
  })]
1061
1165
  }), /*#__PURE__*/jsxRuntime.jsxs("label", {
1062
1166
  className: "mb-meta-active",
1167
+ "data-testid": "rule-active-label",
1063
1168
  children: [/*#__PURE__*/jsxRuntime.jsx("input", {
1064
1169
  checked: rule.active,
1170
+ "data-testid": "rule-active-checkbox",
1065
1171
  readOnly: !handleToggleActive,
1066
1172
  type: "checkbox",
1067
1173
  onChange: handleToggleActive || undefined
@@ -1319,6 +1425,8 @@ var ActionRow = function ActionRow(_ref) {
1319
1425
  });
1320
1426
  var configLabel = mediumLabel || sentencify(option === null || option === void 0 ? void 0 : option.placeholder);
1321
1427
  var isConfigured = neetoCist.isNotEmpty(action === null || action === void 0 ? void 0 : action.metadata);
1428
+ // A host that shows no value label still needs the token to read as filled.
1429
+ var configState = configValue || isConfigured ? TOKEN_STATE.FILLED : TOKEN_STATE.MUTED;
1322
1430
  var _useClearingHover = useClearingHover(),
1323
1431
  clearing = _useClearingHover.clearing,
1324
1432
  clearingHoverProps = _useClearingHover.clearingHoverProps;
@@ -1357,7 +1465,7 @@ var ActionRow = function ActionRow(_ref) {
1357
1465
  children: verbLabel
1358
1466
  }), hasParamTail ? /*#__PURE__*/jsxRuntime.jsx(Token, {
1359
1467
  dataTestid: "action-config-value-".concat(index),
1360
- state: configValue ? TOKEN_STATE.FILLED : TOKEN_STATE.MUTED,
1468
+ state: configState,
1361
1469
  active: isActive({
1362
1470
  type: BUILDER_ANCHORS.ACTION_CONFIG,
1363
1471
  index: index
@@ -1405,7 +1513,7 @@ var ActionRow = function ActionRow(_ref) {
1405
1513
  index: index
1406
1514
  }),
1407
1515
  dataTestid: "action-config-value-".concat(index),
1408
- state: configValue ? TOKEN_STATE.FILLED : TOKEN_STATE.MUTED,
1516
+ state: configState,
1409
1517
  invalid: isInvalid({
1410
1518
  type: BUILDER_ANCHORS.ACTION_CONFIG,
1411
1519
  index: index
@@ -1628,6 +1736,10 @@ var WhenBlock = function WhenBlock(_ref) {
1628
1736
  type: BUILDER_ANCHORS.TRIGGER_LEAD_TIME,
1629
1737
  index: index
1630
1738
  }),
1739
+ invalid: isInvalid({
1740
+ type: BUILDER_ANCHORS.TRIGGER_LEAD_TIME,
1741
+ index: index
1742
+ }),
1631
1743
  onClick: handleToken && function () {
1632
1744
  return handleToken({
1633
1745
  type: BUILDER_ANCHORS.TRIGGER_LEAD_TIME,
@@ -1838,6 +1950,24 @@ var useRuleModel = function useRuleModel(schema) {
1838
1950
  fieldKey: fieldKeysFromSchema(schema).actions,
1839
1951
  index: index
1840
1952
  }));
1953
+ },
1954
+ clearTriggers: function clearTriggers() {
1955
+ return applyAll(clearArrayItems({
1956
+ values: values,
1957
+ fieldKey: fieldKeysFromSchema(schema).triggers
1958
+ }));
1959
+ },
1960
+ clearConditions: function clearConditions() {
1961
+ return applyAll(clearArrayItems({
1962
+ values: values,
1963
+ fieldKey: fieldKeysFromSchema(schema).conditions
1964
+ }));
1965
+ },
1966
+ clearActions: function clearActions() {
1967
+ return applyAll(clearArrayItems({
1968
+ values: values,
1969
+ fieldKey: fieldKeysFromSchema(schema).actions
1970
+ }));
1841
1971
  }
1842
1972
  };
1843
1973
  };
@@ -1984,9 +2114,9 @@ var nextTriggers = function nextTriggers(_ref10) {
1984
2114
  name: value
1985
2115
  }]);
1986
2116
  }
1987
- return [{
2117
+ return [_objectSpread$4(_objectSpread$4({}, rule.triggers[0]), {}, {
1988
2118
  name: value
1989
- }];
2119
+ })];
1990
2120
  };
1991
2121
  var nextConditionAt = function nextConditionAt(_ref11) {
1992
2122
  var _field$allowMatching;
@@ -2119,7 +2249,7 @@ var nextActionRecipientAt = function nextActionRecipientAt(_ref14) {
2119
2249
  });
2120
2250
  };
2121
2251
  var descriptorFor = function descriptorFor(_ref15) {
2122
- var _schema$actor2, _schema$conditions2;
2252
+ var _schema$actor2;
2123
2253
  var anchor = _ref15.anchor,
2124
2254
  schema = _ref15.schema,
2125
2255
  rule = _ref15.rule,
@@ -2165,7 +2295,10 @@ var descriptorFor = function descriptorFor(_ref15) {
2165
2295
  title: i18next.t("neetoRules.builder.panes.addCondition"),
2166
2296
  subtitle: i18next.t("neetoRules.builder.panes.condFieldSubtitle"),
2167
2297
  cascade: true,
2168
- options: (((_schema$conditions2 = schema.conditions) === null || _schema$conditions2 === void 0 ? void 0 : _schema$conditions2.fields) || []).map(function (field) {
2298
+ options: offeredConditionFields({
2299
+ schema: schema,
2300
+ rule: rule
2301
+ }).map(function (field) {
2169
2302
  return {
2170
2303
  label: field.paneLabel || field.label,
2171
2304
  value: optionValue(field),
@@ -2179,7 +2312,7 @@ var descriptorFor = function descriptorFor(_ref15) {
2179
2312
  };
2180
2313
  case BUILDER_ANCHORS.COND_OP_TOGGLE:
2181
2314
  {
2182
- var _schema$conditions3;
2315
+ var _schema$conditions2;
2183
2316
  var field = findField({
2184
2317
  schema: schema,
2185
2318
  value: conditionAt({
@@ -2187,7 +2320,7 @@ var descriptorFor = function descriptorFor(_ref15) {
2187
2320
  index: index
2188
2321
  }).field
2189
2322
  });
2190
- var labels = ((_schema$conditions3 = schema.conditions) === null || _schema$conditions3 === void 0 ? void 0 : _schema$conditions3.operatorLabels) || {};
2323
+ var labels = ((_schema$conditions2 = schema.conditions) === null || _schema$conditions2 === void 0 ? void 0 : _schema$conditions2.operatorLabels) || {};
2191
2324
  var verbs = (field === null || field === void 0 ? void 0 : field.allowMatching) || [];
2192
2325
  var fieldLabel = (field === null || field === void 0 ? void 0 : field.paneLabel) || (field === null || field === void 0 ? void 0 : field.label) || "";
2193
2326
  var isContains = neetoCist.isNotEmpty(verbs) && verbs.every(isContainsVerb);
@@ -2233,7 +2366,7 @@ var descriptorFor = function descriptorFor(_ref15) {
2233
2366
  case BUILDER_ANCHORS.ACTION_ADD:
2234
2367
  case BUILDER_ANCHORS.ACTION_CHANNEL:
2235
2368
  {
2236
- var _schema$actions11, _schema$actions12, _channelOf;
2369
+ var _schema$actions11, _channelOf;
2237
2370
  var isSwap = anchor === BUILDER_ANCHORS.ACTION_CHANNEL;
2238
2371
  var channelMetaFor = function channelMetaFor(value) {
2239
2372
  var _schema$actions10;
@@ -2242,13 +2375,10 @@ var descriptorFor = function descriptorFor(_ref15) {
2242
2375
  ((_schema$actions10 = schema.actions) === null || _schema$actions10 === void 0 || (_schema$actions10 = _schema$actions10.channelMeta) === null || _schema$actions10 === void 0 ? void 0 : _schema$actions10[value]) || {}
2243
2376
  );
2244
2377
  };
2245
- var rank = function rank(value) {
2246
- var idx = SWAP_CHANNEL_ORDER.indexOf(value);
2247
- return idx === -1 ? SWAP_CHANNEL_ORDER.length : idx;
2248
- };
2249
- var sourceOptions = isSwap ? _toConsumableArray(((_schema$actions11 = schema.actions) === null || _schema$actions11 === void 0 ? void 0 : _schema$actions11.options) || []).sort(function (optionA, optionB) {
2250
- return rank(optionValue(optionA)) - rank(optionValue(optionB));
2251
- }) : ((_schema$actions12 = schema.actions) === null || _schema$actions12 === void 0 ? void 0 : _schema$actions12.options) || [];
2378
+
2379
+ // Both panes list the host's actions in the order it declared them;
2380
+ // re-ranking only the swap pane made the two disagree.
2381
+ var sourceOptions = ((_schema$actions11 = schema.actions) === null || _schema$actions11 === void 0 ? void 0 : _schema$actions11.options) || [];
2252
2382
  return {
2253
2383
  title: isSwap ? i18next.t("neetoRules.builder.panes.actionSwapTitle") : i18next.t("neetoRules.builder.panes.actionAddTitle"),
2254
2384
  subtitle: isSwap ? i18next.t("neetoRules.builder.panes.actionSwapSubtitle") : i18next.t("neetoRules.builder.panes.actionAddSubtitle"),
@@ -2278,7 +2408,7 @@ var descriptorFor = function descriptorFor(_ref15) {
2278
2408
  }
2279
2409
  case BUILDER_ANCHORS.ACTION_RECIPIENT:
2280
2410
  {
2281
- var _schema$actions13;
2411
+ var _schema$actions12;
2282
2412
  var action = actionAt({
2283
2413
  rule: rule,
2284
2414
  index: index
@@ -2288,7 +2418,7 @@ var descriptorFor = function descriptorFor(_ref15) {
2288
2418
  action: action
2289
2419
  });
2290
2420
  // eslint-disable-next-line security/detect-object-injection
2291
- var meta = ((_schema$actions13 = schema.actions) === null || _schema$actions13 === void 0 || (_schema$actions13 = _schema$actions13.channelMeta) === null || _schema$actions13 === void 0 ? void 0 : _schema$actions13[channel]) || {};
2421
+ var meta = ((_schema$actions12 = schema.actions) === null || _schema$actions12 === void 0 || (_schema$actions12 = _schema$actions12.channelMeta) === null || _schema$actions12 === void 0 ? void 0 : _schema$actions12[channel]) || {};
2292
2422
  var option = findActionOption({
2293
2423
  schema: schema,
2294
2424
  name: channel
@@ -2404,9 +2534,9 @@ var commitFor = function commitFor(_ref16) {
2404
2534
  }]));
2405
2535
  return "stay";
2406
2536
  }
2407
- setTriggers([{
2537
+ setTriggers([_objectSpread$4(_objectSpread$4({}, rule.triggers[0]), {}, {
2408
2538
  name: value
2409
- }]);
2539
+ })]);
2410
2540
  var leadTime = (_schema$triggers5 = schema.triggers) === null || _schema$triggers5 === void 0 ? void 0 : _schema$triggers5.leadTime;
2411
2541
  if (leadTime !== null && leadTime !== void 0 && leadTime.fieldKey && (leadTime.appliesTo || []).includes(value) && !rule.leadTime) {
2412
2542
  var _leadTime$default;
@@ -2673,7 +2803,7 @@ var applyPreview = function applyPreview(_ref19) {
2673
2803
  function ownKeys$3(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
2674
2804
  function _objectSpread$3(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$3(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$3(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
2675
2805
  var Canvas = function Canvas(_ref) {
2676
- var _schema$scope, _schema$scope2, _schema$conditions, _schema$triggers, _schema$delay, _schema$meta$showName, _schema$meta;
2806
+ var _schema$scope, _schema$triggers, _schema$delay, _schema$meta$showName, _schema$meta;
2677
2807
  var schema = _ref.schema;
2678
2808
  var _useTranslation = reactI18next.useTranslation(),
2679
2809
  t = _useTranslation.t;
@@ -2686,15 +2816,16 @@ var Canvas = function Canvas(_ref) {
2686
2816
  var _useRuleModel = useRuleModel(schema),
2687
2817
  rule = _useRuleModel.rule,
2688
2818
  fieldKeys = _useRuleModel.fieldKeys,
2689
- setTriggers = _useRuleModel.setTriggers,
2690
2819
  setPerformer = _useRuleModel.setPerformer,
2691
2820
  setConditions = _useRuleModel.setConditions,
2692
- setActions = _useRuleModel.setActions,
2693
2821
  setDelay = _useRuleModel.setDelay,
2694
2822
  removeCondition = _useRuleModel.removeCondition,
2695
2823
  removeAction = _useRuleModel.removeAction,
2696
2824
  setActive = _useRuleModel.setActive,
2697
- setScope = _useRuleModel.setScope;
2825
+ setScope = _useRuleModel.setScope,
2826
+ clearTriggers = _useRuleModel.clearTriggers,
2827
+ clearConditions = _useRuleModel.clearConditions,
2828
+ clearActions = _useRuleModel.clearActions;
2698
2829
  var _useUtilityStore = useUtilityStore.useUtilityStore(shallow.useShallow(function (store) {
2699
2830
  return {
2700
2831
  builderPreview: store["builderPreview"],
@@ -2739,7 +2870,7 @@ var Canvas = function Canvas(_ref) {
2739
2870
  setFlashSeq(submitCount);
2740
2871
  var timer = setTimeout(function () {
2741
2872
  return setFlashSeq(0);
2742
- }, 2200);
2873
+ }, FLASH_DURATION_MS);
2743
2874
  return function () {
2744
2875
  return clearTimeout(timer);
2745
2876
  };
@@ -2756,7 +2887,7 @@ var Canvas = function Canvas(_ref) {
2756
2887
  });
2757
2888
  };
2758
2889
  var matchesInvalid = function matchesInvalid(_ref4) {
2759
- var _schema$actions, _schema$actions$actio, _schema$actions2, _schema$actions2$rend, _schema$actions3, _schema$actions3$rend, _schema$actions4, _schema$actions4$opti, _schema$actions5, _schema$actions5$opti;
2890
+ var _schema$actions, _schema$actions$actio, _schema$actions2, _schema$actions2$rend, _schema$actions3, _schema$actions3$rend, _schema$actions4, _schema$actions4$opti, _schema$actions5, _schema$actions5$opti, _schema$actions6, _schema$actions7;
2760
2891
  var type = _ref4.type,
2761
2892
  index = _ref4.index;
2762
2893
  var conditionMeta = "".concat(fieldKeys.conditions, ".value.").concat(index, ".metadata");
@@ -2776,7 +2907,13 @@ var Canvas = function Canvas(_ref) {
2776
2907
  action: actionItem
2777
2908
  }));
2778
2909
  var flatOption = ((_schema$actions4 = schema.actions) === null || _schema$actions4 === void 0 || (_schema$actions4$opti = _schema$actions4.optionForName) === null || _schema$actions4$opti === void 0 ? void 0 : _schema$actions4$opti.call(_schema$actions4, actionItem.name)) || ((_schema$actions5 = schema.actions) === null || _schema$actions5 === void 0 || (_schema$actions5$opti = _schema$actions5.optionForChannel) === null || _schema$actions5$opti === void 0 ? void 0 : _schema$actions5$opti.call(_schema$actions5, channel));
2779
- var recipientFields = [].concat(_toConsumableArray(hasRecipientEditor || hasRecipientField ? ["emails"] : []), _toConsumableArray((flatOption === null || flatOption === void 0 ? void 0 : flatOption.type) === "smsToNumbers" ? ["phoneNumbers"] : []));
2910
+ var recipientConfig = [].concat(_toConsumableArray((((_schema$actions6 = schema.actions) === null || _schema$actions6 === void 0 ? void 0 : _schema$actions6.options) || []).flatMap(function (option) {
2911
+ return option.recipients || [];
2912
+ })), _toConsumableArray(((_schema$actions7 = schema.actions) === null || _schema$actions7 === void 0 ? void 0 : _schema$actions7.recipients) || [])).find(function (item) {
2913
+ var _item$value;
2914
+ return ((_item$value = item.value) !== null && _item$value !== void 0 ? _item$value : item.id) === actionItem.recipient;
2915
+ });
2916
+ var recipientFields = [].concat(_toConsumableArray(hasRecipientEditor || hasRecipientField ? [RECIPIENT_STORAGE_FIELDS.emails] : []), _toConsumableArray(recipientConfig !== null && recipientConfig !== void 0 && recipientConfig.field ? [recipientStorageField(recipientConfig.field)] : []), _toConsumableArray((flatOption === null || flatOption === void 0 ? void 0 : flatOption.type) === SMS_TO_NUMBERS ? [RECIPIENT_STORAGE_FIELDS.phoneNumbers] : []));
2780
2917
  switch (type) {
2781
2918
  case BUILDER_ANCHORS.TRIGGER_ACTOR:
2782
2919
  {
@@ -2786,6 +2923,10 @@ var Canvas = function Canvas(_ref) {
2786
2923
  prefix: "".concat(actorKey, ".value")
2787
2924
  });
2788
2925
  }
2926
+ case BUILDER_ANCHORS.TRIGGER_LEAD_TIME:
2927
+ return hasErrorAt({
2928
+ prefix: "".concat(fieldKeys.leadTime, ".value")
2929
+ });
2789
2930
  case BUILDER_ANCHORS.COND_FIELD:
2790
2931
  return hasErrorAt({
2791
2932
  prefix: "".concat(fieldKeys.conditions, ".value.").concat(index, ".field")
@@ -2806,7 +2947,9 @@ var Canvas = function Canvas(_ref) {
2806
2947
  exclude: recipientFields
2807
2948
  });
2808
2949
  case BUILDER_ANCHORS.ACTION_RECIPIENT:
2809
- return recipientFields.some(function (field) {
2950
+ return hasErrorAt({
2951
+ prefix: "".concat(fieldKeys.actions, ".value.").concat(index, ".name")
2952
+ }) || recipientFields.some(function (field) {
2810
2953
  return hasErrorAt({
2811
2954
  prefix: "".concat(actionMeta, ".").concat(field)
2812
2955
  });
@@ -2884,8 +3027,6 @@ var Canvas = function Canvas(_ref) {
2884
3027
  return (action === null || action === void 0 ? void 0 : action.channel) || (action === null || action === void 0 ? void 0 : action.name);
2885
3028
  });
2886
3029
  var isScopeEnabled = (schema === null || schema === void 0 || (_schema$scope = schema.scope) === null || _schema$scope === void 0 ? void 0 : _schema$scope.enabled) && isTriggerSet && hasAction;
2887
- var isScopeComplete = !(schema !== null && schema !== void 0 && (_schema$scope2 = schema.scope) !== null && _schema$scope2 !== void 0 && _schema$scope2.enabled) || neetoCist.isNotEmpty(rule.scope || []);
2888
- var isComplete = isRuleComplete(rule) && isScopeComplete;
2889
3030
  var handleRemoveScope = function handleRemoveScope(index) {
2890
3031
  closePaneIfTargeting({
2891
3032
  anchors: [BUILDER_ANCHORS.SCOPE_PHONE_FIELD],
@@ -2895,7 +3036,10 @@ var Canvas = function Canvas(_ref) {
2895
3036
  return i !== index;
2896
3037
  }));
2897
3038
  };
2898
- var conditionFields = (schema === null || schema === void 0 || (_schema$conditions = schema.conditions) === null || _schema$conditions === void 0 ? void 0 : _schema$conditions.fields) || [];
3039
+ var conditionFields = offeredConditionFields({
3040
+ schema: schema,
3041
+ rule: rule
3042
+ });
2899
3043
  var canAddCondition = neetoCist.isNotEmpty(conditionFields);
2900
3044
  var leadTimeAppliesTo = (schema === null || schema === void 0 || (_schema$triggers = schema.triggers) === null || _schema$triggers === void 0 || (_schema$triggers = _schema$triggers.leadTime) === null || _schema$triggers === void 0 ? void 0 : _schema$triggers.appliesTo) || [];
2901
3045
  var hasLeadTimeTrigger = rule.triggers.some(function (trigger) {
@@ -2919,12 +3063,12 @@ var Canvas = function Canvas(_ref) {
2919
3063
  };
2920
3064
  var handleClearTrigger = function handleClearTrigger() {
2921
3065
  var _schema$actor2;
2922
- setTriggers([]);
3066
+ clearTriggers();
2923
3067
  // Hosts without an actor pane can never re-set it, and null fails its validation.
2924
3068
  if ((_schema$actor2 = schema.actor) !== null && _schema$actor2 !== void 0 && _schema$actor2.enabled) setPerformer(null);
2925
- setConditions([]);
3069
+ clearConditions();
2926
3070
  setDelay(null);
2927
- setActions([]);
3071
+ clearActions();
2928
3072
  setScope([]);
2929
3073
  closePane();
2930
3074
  };
@@ -2946,7 +3090,7 @@ var Canvas = function Canvas(_ref) {
2946
3090
  );
2947
3091
  };
2948
3092
  return /*#__PURE__*/jsxRuntime.jsx("div", {
2949
- className: "neeto-rules-builder",
3093
+ className: "neeto-rules-builder nrb-atoms",
2950
3094
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
2951
3095
  className: "mb-canvas neeto-rules-main-card",
2952
3096
  children: [/*#__PURE__*/jsxRuntime.jsx(WhenBlock, {
@@ -2988,6 +3132,7 @@ var Canvas = function Canvas(_ref) {
2988
3132
  }) : /*#__PURE__*/jsxRuntime.jsx("div", {
2989
3133
  className: "mb-add-row",
2990
3134
  children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Button, {
3135
+ "data-testid": "rule-delay-add",
2991
3136
  icon: Plus,
2992
3137
  iconPosition: "left",
2993
3138
  label: t("neetoRules.common.addDelay"),
@@ -3019,24 +3164,22 @@ var Canvas = function Canvas(_ref) {
3019
3164
  onRemoveScope: handleRemoveScope,
3020
3165
  onToken: openPane
3021
3166
  })]
3022
- }), isComplete && /*#__PURE__*/jsxRuntime.jsxs(react.Fragment, {
3023
- children: [/*#__PURE__*/jsxRuntime.jsx(Connector, {
3024
- active: true
3025
- }), /*#__PURE__*/jsxRuntime.jsx(MetaBlock, {
3026
- rule: rule,
3027
- isInvalid: isInvalid({
3167
+ }), /*#__PURE__*/jsxRuntime.jsx(Connector, {
3168
+ active: true
3169
+ }), /*#__PURE__*/jsxRuntime.jsx(MetaBlock, {
3170
+ rule: rule,
3171
+ isInvalid: isInvalid({
3172
+ type: BUILDER_ANCHORS.META_NAME
3173
+ }),
3174
+ showName: (_schema$meta$showName = schema === null || schema === void 0 || (_schema$meta = schema.meta) === null || _schema$meta === void 0 ? void 0 : _schema$meta.showName) !== null && _schema$meta$showName !== void 0 ? _schema$meta$showName : true,
3175
+ onEditName: function onEditName() {
3176
+ return openPane({
3028
3177
  type: BUILDER_ANCHORS.META_NAME
3029
- }),
3030
- showName: (_schema$meta$showName = schema === null || schema === void 0 || (_schema$meta = schema.meta) === null || _schema$meta === void 0 ? void 0 : _schema$meta.showName) !== null && _schema$meta$showName !== void 0 ? _schema$meta$showName : true,
3031
- onEditName: function onEditName() {
3032
- return openPane({
3033
- type: BUILDER_ANCHORS.META_NAME
3034
- });
3035
- },
3036
- onToggleActive: function onToggleActive(event) {
3037
- return setActive(event.target.checked);
3038
- }
3039
- })]
3178
+ });
3179
+ },
3180
+ onToggleActive: function onToggleActive(event) {
3181
+ return setActive(event.target.checked);
3182
+ }
3040
3183
  })]
3041
3184
  })
3042
3185
  });
@@ -3047,6 +3190,7 @@ var ACTION_CONFIG_TYPES = {
3047
3190
  multiSelect: "multiSelect",
3048
3191
  dropdown: "dropdown",
3049
3192
  note: "note",
3193
+ list: "list",
3050
3194
  textarea: "textarea",
3051
3195
  number: "number",
3052
3196
  text: "text",
@@ -3108,6 +3252,7 @@ var ActionConfigFields = function ActionConfigFields(_ref) {
3108
3252
  };
3109
3253
  var noMatches = /*#__PURE__*/jsxRuntime.jsx("div", {
3110
3254
  className: "mb-pane-empty",
3255
+ "data-testid": "pane-no-matches",
3111
3256
  children: t("neetoRules.builder.noMatches")
3112
3257
  });
3113
3258
  if (type === ACTION_CONFIG_TYPES.emailChannel) {
@@ -3116,7 +3261,7 @@ var ActionConfigFields = function ActionConfigFields(_ref) {
3116
3261
  var bodyPath = "".concat(name, ".body");
3117
3262
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
3118
3263
  className: "flex flex-col gap-4",
3119
- children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Input, {
3264
+ children: [!(option !== null && option !== void 0 && option.hideSubject) && /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Input, {
3120
3265
  required: true,
3121
3266
  error: fieldError(subjectPath),
3122
3267
  label: t("neetoRules.builder.config.subject"),
@@ -3149,7 +3294,7 @@ var ActionConfigFields = function ActionConfigFields(_ref) {
3149
3294
  setFieldValue(valuePath, current.includes(value) ? current.filter(neetoCist.isNot(value)) : [].concat(_toConsumableArray(current), [value]));
3150
3295
  };
3151
3296
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
3152
- className: "flex flex-col gap-y-1",
3297
+ className: "mb-pane-list flex flex-col",
3153
3298
  children: [filtered.map(function (item) {
3154
3299
  return /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Checkbox, {
3155
3300
  checked: current.includes(item.value),
@@ -3191,6 +3336,14 @@ var ActionConfigFields = function ActionConfigFields(_ref) {
3191
3336
  })
3192
3337
  });
3193
3338
  }
3339
+ if (type === ACTION_CONFIG_TYPES.list) {
3340
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
3341
+ className: "flex flex-col gap-2",
3342
+ children: [/*#__PURE__*/jsxRuntime.jsx(index.ListField, {
3343
+ name: valuePath
3344
+ }), hintBlock]
3345
+ });
3346
+ }
3194
3347
  if (type === ACTION_CONFIG_TYPES.note) {
3195
3348
  var _action$metadata2;
3196
3349
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
@@ -3436,7 +3589,7 @@ var ConfigPane = function ConfigPane(_ref) {
3436
3589
  while (1) switch (_context.n) {
3437
3590
  case 0:
3438
3591
  _context.n = 1;
3439
- return validate(["emails"]);
3592
+ return validate([RECIPIENT_STORAGE_FIELDS.emails]);
3440
3593
  case 1:
3441
3594
  if (_context.v) {
3442
3595
  _context.n = 2;
@@ -3465,7 +3618,6 @@ var ConfigPane = function ConfigPane(_ref) {
3465
3618
  };
3466
3619
  }();
3467
3620
  useHotkeys(keyboardShortcuts.SHORTCUTS["continue"].sequence, handleContinue, {
3468
- enabled: shouldAdvanceToRecipient,
3469
3621
  mode: "global"
3470
3622
  });
3471
3623
  return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
@@ -3473,6 +3625,7 @@ var ConfigPane = function ConfigPane(_ref) {
3473
3625
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
3474
3626
  className: "flex w-full flex-col gap-y-2",
3475
3627
  children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
3628
+ "data-testid": "pane-title",
3476
3629
  variant: "h5",
3477
3630
  children: title
3478
3631
  }), configSubtitle && /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
@@ -3482,6 +3635,7 @@ var ConfigPane = function ConfigPane(_ref) {
3482
3635
  }), showSearch && /*#__PURE__*/jsxRuntime.jsx("div", {
3483
3636
  className: "mb-pane-search",
3484
3637
  children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Input, {
3638
+ dataTestid: "pane-search",
3485
3639
  placeholder: t("neetoRules.builder.searchPlaceholder"),
3486
3640
  prefix: /*#__PURE__*/jsxRuntime.jsx(Search, {}),
3487
3641
  size: "large",
@@ -3501,20 +3655,14 @@ var ConfigPane = function ConfigPane(_ref) {
3501
3655
  message: disabledReason,
3502
3656
  selectedField: flatOption
3503
3657
  })
3504
- }), isSms ? /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
3505
- children: [/*#__PURE__*/jsxRuntime.jsx(index.SmsFields, {
3506
- action: action,
3507
- index: index$1,
3508
- name: name,
3509
- shouldAutoFocus: true,
3510
- selectedField: flatOption,
3511
- showPhoneNumberInput: false
3512
- }), /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
3513
- className: "mt-2",
3514
- color: "muted",
3515
- variant: "body3",
3516
- children: t("neetoRules.builder.config.smsSegmentHint")
3517
- })]
3658
+ }), isSms ? /*#__PURE__*/jsxRuntime.jsx(index.SmsFields, {
3659
+ action: action,
3660
+ index: index$1,
3661
+ name: name,
3662
+ shouldAutoFocus: true,
3663
+ hint: t("neetoRules.builder.config.smsSegmentHint"),
3664
+ selectedField: flatOption,
3665
+ showPhoneNumberInput: false
3518
3666
  }) : (_hostRenderConfig = hostRenderConfig === null || hostRenderConfig === void 0 ? void 0 : hostRenderConfig({
3519
3667
  name: name,
3520
3668
  action: action,
@@ -3527,8 +3675,9 @@ var ConfigPane = function ConfigPane(_ref) {
3527
3675
  option: flatOption
3528
3676
  })]
3529
3677
  })
3530
- }), shouldAdvanceToRecipient && /*#__PURE__*/jsxRuntime.jsx(index.Panel.Footer, {
3678
+ }), /*#__PURE__*/jsxRuntime.jsx(index.Panel.Footer, {
3531
3679
  children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Button, {
3680
+ "data-testid": "continue-button",
3532
3681
  label: t("neetoRules.buttons.continue"),
3533
3682
  size: "lg",
3534
3683
  onClick: handleContinue
@@ -3545,7 +3694,9 @@ var DelayPane = function DelayPane(_ref) {
3545
3694
  var _useRuleModel = useRuleModel(schema),
3546
3695
  fieldKeys = _useRuleModel.fieldKeys;
3547
3696
  var _useFormikContext = formik.useFormikContext(),
3548
- setFieldValue = _useFormikContext.setFieldValue;
3697
+ setFieldValue = _useFormikContext.setFieldValue,
3698
+ setFieldTouched = _useFormikContext.setFieldTouched,
3699
+ getFieldMeta = _useFormikContext.getFieldMeta;
3549
3700
  var bodyRef = react.useRef(null);
3550
3701
  var name = fieldKeys.delay;
3551
3702
  var _useField = formik.useField("".concat(name, ".value")),
@@ -3554,12 +3705,18 @@ var DelayPane = function DelayPane(_ref) {
3554
3705
  var units = normalizeOptions((_schema$delay = schema.delay) === null || _schema$delay === void 0 ? void 0 : _schema$delay.units);
3555
3706
  var unitOptions = neetoCist.isNotEmpty(units) ? units : DEFAULT_DELAY_UNITS;
3556
3707
  usePaneValidation("".concat(name, ".value"));
3708
+ react.useEffect(function () {
3709
+ if ((value === null || value === void 0 ? void 0 : value.value) === undefined) return;
3710
+ if (getFieldMeta("".concat(name, ".value.value")).touched) return;
3711
+ setFieldTouched("".concat(name, ".value.value"), true, false);
3712
+ // eslint-disable-next-line react-hooks/exhaustive-deps
3713
+ }, [value === null || value === void 0 ? void 0 : value.value]);
3557
3714
  react.useEffect(function () {
3558
3715
  if (ramda.isEmpty(value || {})) {
3559
3716
  var _unitOptions$0$value, _unitOptions$;
3560
3717
  setFieldValue("".concat(name, ".value"), {
3561
- value: 10,
3562
- unit: (_unitOptions$0$value = (_unitOptions$ = unitOptions[0]) === null || _unitOptions$ === void 0 ? void 0 : _unitOptions$.value) !== null && _unitOptions$0$value !== void 0 ? _unitOptions$0$value : "minutes"
3718
+ value: DEFAULT_DELAY_VALUE,
3719
+ unit: (_unitOptions$0$value = (_unitOptions$ = unitOptions[0]) === null || _unitOptions$ === void 0 ? void 0 : _unitOptions$.value) !== null && _unitOptions$0$value !== void 0 ? _unitOptions$0$value : DEFAULT_DELAY_UNITS[0].value
3563
3720
  });
3564
3721
  }
3565
3722
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -3577,6 +3734,7 @@ var DelayPane = function DelayPane(_ref) {
3577
3734
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
3578
3735
  className: "flex flex-col gap-y-1",
3579
3736
  children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
3737
+ "data-testid": "pane-title",
3580
3738
  variant: "h5",
3581
3739
  children: t("neetoRules.common.addDelay")
3582
3740
  }), /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
@@ -3597,13 +3755,15 @@ var DelayPane = function DelayPane(_ref) {
3597
3755
  className: "flex items-start gap-x-2",
3598
3756
  children: [/*#__PURE__*/jsxRuntime.jsx(formik$1.Input, {
3599
3757
  className: "w-44",
3600
- max: 999,
3601
- min: 1,
3758
+ dataTestid: "delay-value",
3759
+ max: index.MAX_DELAY_VALUE,
3760
+ min: index.MIN_DELAY_VALUE,
3602
3761
  name: "".concat(name, ".value.value"),
3603
3762
  placeholder: t("neetoRules.placeholders.enterDelay"),
3604
3763
  size: "large",
3605
3764
  type: "number"
3606
3765
  }), /*#__PURE__*/jsxRuntime.jsx(formik$1.Select, {
3766
+ dataTestid: "delay-unit",
3607
3767
  defaultValue: value === null || value === void 0 ? void 0 : value.unit,
3608
3768
  name: "".concat(name, ".value.unit"),
3609
3769
  options: unitOptions,
@@ -3637,11 +3797,13 @@ var asText = function asText(value) {
3637
3797
  var NumberStepper = function NumberStepper(_ref) {
3638
3798
  var value = _ref.value,
3639
3799
  onChange = _ref.onChange,
3800
+ dataTestid = _ref.dataTestid,
3640
3801
  label = _ref.label,
3641
3802
  _ref$min = _ref.min,
3642
- min = _ref$min === void 0 ? 1 : _ref$min,
3803
+ min = _ref$min === void 0 ? STEPPER_MIN_VALUE : _ref$min,
3643
3804
  max = _ref.max,
3644
- required = _ref.required;
3805
+ required = _ref.required,
3806
+ error = _ref.error;
3645
3807
  var _useTranslation = reactI18next.useTranslation(),
3646
3808
  t = _useTranslation.t;
3647
3809
  var _useState = react.useState(null),
@@ -3666,15 +3828,41 @@ var NumberStepper = function NumberStepper(_ref) {
3666
3828
  max: max
3667
3829
  }));
3668
3830
  };
3669
- return /*#__PURE__*/jsxRuntime.jsxs("div", {
3831
+ return /*#__PURE__*/jsxRuntime.jsx("div", {
3670
3832
  className: "mb-stepper",
3671
- children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Input, {
3833
+ children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Input, {
3834
+ dataTestid: dataTestid,
3835
+ error: error,
3672
3836
  label: label,
3673
3837
  min: min,
3674
3838
  required: required,
3675
3839
  autoFocus: true,
3676
3840
  type: "number",
3677
3841
  value: display,
3842
+ suffix: /*#__PURE__*/jsxRuntime.jsxs("div", {
3843
+ className: "mb-stepper-controls",
3844
+ children: [/*#__PURE__*/jsxRuntime.jsx("button", {
3845
+ "aria-label": t("neetoRules.builder.aria.increase"),
3846
+ className: "mb-stepper-btn",
3847
+ "data-testid": "stepper-increase",
3848
+ tabIndex: SKIP_TAB_INDEX,
3849
+ type: "button",
3850
+ onClick: function onClick() {
3851
+ return step(STEPPER_DELTA.INCREMENT);
3852
+ },
3853
+ children: /*#__PURE__*/jsxRuntime.jsx(Up, {})
3854
+ }), /*#__PURE__*/jsxRuntime.jsx("button", {
3855
+ "aria-label": t("neetoRules.builder.aria.decrease"),
3856
+ className: "mb-stepper-btn",
3857
+ "data-testid": "stepper-decrease",
3858
+ tabIndex: SKIP_TAB_INDEX,
3859
+ type: "button",
3860
+ onClick: function onClick() {
3861
+ return step(STEPPER_DELTA.DECREMENT);
3862
+ },
3863
+ children: /*#__PURE__*/jsxRuntime.jsx(Down, {})
3864
+ })]
3865
+ }),
3678
3866
  onBlur: function onBlur() {
3679
3867
  return setDraft(null);
3680
3868
  },
@@ -3684,28 +3872,7 @@ var NumberStepper = function NumberStepper(_ref) {
3684
3872
  onFocus: function onFocus(event) {
3685
3873
  return event.target.select();
3686
3874
  }
3687
- }), /*#__PURE__*/jsxRuntime.jsxs("div", {
3688
- className: "mb-stepper-controls",
3689
- children: [/*#__PURE__*/jsxRuntime.jsx("button", {
3690
- "aria-label": t("neetoRules.builder.aria.increase"),
3691
- className: "mb-stepper-btn",
3692
- tabIndex: -1,
3693
- type: "button",
3694
- onClick: function onClick() {
3695
- return step(1);
3696
- },
3697
- children: /*#__PURE__*/jsxRuntime.jsx(Up, {})
3698
- }), /*#__PURE__*/jsxRuntime.jsx("button", {
3699
- "aria-label": t("neetoRules.builder.aria.decrease"),
3700
- className: "mb-stepper-btn",
3701
- tabIndex: -1,
3702
- type: "button",
3703
- onClick: function onClick() {
3704
- return step(-1);
3705
- },
3706
- children: /*#__PURE__*/jsxRuntime.jsx(Down, {})
3707
- })]
3708
- })]
3875
+ })
3709
3876
  });
3710
3877
  };
3711
3878
 
@@ -3714,7 +3881,9 @@ var LeadTimePane = function LeadTimePane(_ref) {
3714
3881
  var _useTranslation = reactI18next.useTranslation(),
3715
3882
  t = _useTranslation.t;
3716
3883
  var _useFormikContext = formik.useFormikContext(),
3717
- setFieldValue = _useFormikContext.setFieldValue;
3884
+ setFieldValue = _useFormikContext.setFieldValue,
3885
+ setFieldTouched = _useFormikContext.setFieldTouched,
3886
+ getFieldMeta = _useFormikContext.getFieldMeta;
3718
3887
  var _useRuleModel = useRuleModel(schema),
3719
3888
  rule = _useRuleModel.rule,
3720
3889
  fieldKeys = _useRuleModel.fieldKeys;
@@ -3722,6 +3891,11 @@ var LeadTimePane = function LeadTimePane(_ref) {
3722
3891
  amount = _minutesToParts.value,
3723
3892
  unit = _minutesToParts.unit;
3724
3893
  var path = "".concat(fieldKeys.leadTime, ".value");
3894
+ var _useField = formik.useField(path),
3895
+ _useField2 = _slicedToArray(_useField, 2),
3896
+ _useField2$ = _useField2[1],
3897
+ error = _useField2$.error,
3898
+ touched = _useField2$.touched;
3725
3899
  var update = function update(_ref2) {
3726
3900
  var value = _ref2.value,
3727
3901
  nextUnit = _ref2.unit;
@@ -3730,11 +3904,19 @@ var LeadTimePane = function LeadTimePane(_ref) {
3730
3904
  unit: nextUnit
3731
3905
  }));
3732
3906
  };
3907
+ usePaneValidation(path);
3908
+ react.useEffect(function () {
3909
+ if (rule.leadTime === undefined) return;
3910
+ if (getFieldMeta(path).touched) return;
3911
+ setFieldTouched(path, true, false);
3912
+ // eslint-disable-next-line react-hooks/exhaustive-deps
3913
+ }, [rule.leadTime]);
3733
3914
  return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
3734
3915
  children: [/*#__PURE__*/jsxRuntime.jsx(index.Panel.Header, {
3735
3916
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
3736
3917
  className: "flex flex-col gap-y-1",
3737
3918
  children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
3919
+ "data-testid": "pane-title",
3738
3920
  variant: "h5",
3739
3921
  children: t("neetoRules.builder.leadTimeTitle")
3740
3922
  }), /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
@@ -3745,32 +3927,41 @@ var LeadTimePane = function LeadTimePane(_ref) {
3745
3927
  })
3746
3928
  }), /*#__PURE__*/jsxRuntime.jsx(index.Panel.Body, {
3747
3929
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
3748
- className: "flex items-end gap-x-3",
3749
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
3750
- className: "flex-1",
3751
- children: /*#__PURE__*/jsxRuntime.jsx(NumberStepper, {
3752
- label: t("neetoRules.builder.before"),
3753
- value: amount,
3754
- onChange: function onChange(value) {
3755
- return update({
3756
- value: value === "" ? 0 : value,
3757
- unit: unit
3758
- });
3759
- }
3760
- })
3761
- }), /*#__PURE__*/jsxRuntime.jsx("div", {
3762
- className: "w-32 shrink-0",
3763
- children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Select, {
3764
- isSearchable: false,
3765
- options: LEAD_TIME_UNITS,
3766
- value: unit,
3767
- onChange: function onChange(nextUnit) {
3768
- return update({
3769
- value: amount,
3770
- unit: nextUnit
3771
- });
3772
- }
3773
- })
3930
+ className: "flex flex-col gap-y-1.5",
3931
+ children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
3932
+ variant: "body2",
3933
+ weight: "medium",
3934
+ children: t("neetoRules.builder.before")
3935
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
3936
+ className: "flex items-start gap-x-3",
3937
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
3938
+ className: "flex-1",
3939
+ children: /*#__PURE__*/jsxRuntime.jsx(NumberStepper, {
3940
+ dataTestid: "lead-time",
3941
+ error: touched ? error : "",
3942
+ value: amount,
3943
+ onChange: function onChange(value) {
3944
+ return update({
3945
+ value: value === "" ? 0 : value,
3946
+ unit: unit
3947
+ });
3948
+ }
3949
+ })
3950
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
3951
+ className: "w-32 shrink-0",
3952
+ children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Select, {
3953
+ dataTestid: "lead-time-unit",
3954
+ isSearchable: false,
3955
+ options: LEAD_TIME_UNITS,
3956
+ value: unit,
3957
+ onChange: function onChange(nextUnit) {
3958
+ return update({
3959
+ value: amount,
3960
+ unit: nextUnit
3961
+ });
3962
+ }
3963
+ })
3964
+ })]
3774
3965
  })]
3775
3966
  })
3776
3967
  })]
@@ -3788,6 +3979,7 @@ var NamePane = function NamePane(_ref) {
3788
3979
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
3789
3980
  className: "flex flex-col gap-y-1",
3790
3981
  children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
3982
+ "data-testid": "pane-title",
3791
3983
  variant: "h5",
3792
3984
  children: t("neetoRules.builder.automationName")
3793
3985
  }), /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
@@ -3965,12 +4157,13 @@ var OptionsPane = function OptionsPane(_ref) {
3965
4157
  if (ramda.isEmpty(filtered)) {
3966
4158
  return /*#__PURE__*/jsxRuntime.jsx("div", {
3967
4159
  className: "mb-pane-empty",
4160
+ "data-testid": "pane-no-matches",
3968
4161
  children: t("neetoRules.builder.noMatches")
3969
4162
  });
3970
4163
  }
3971
4164
  if (multi) {
3972
4165
  return /*#__PURE__*/jsxRuntime.jsx("div", {
3973
- className: "flex flex-col",
4166
+ className: "mb-pane-list flex flex-col",
3974
4167
  children: groups.map(function (_ref2) {
3975
4168
  var _ref3 = _slicedToArray(_ref2, 2),
3976
4169
  category = _ref3[0],
@@ -4022,6 +4215,7 @@ var OptionsPane = function OptionsPane(_ref) {
4022
4215
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
4023
4216
  className: "flex w-full flex-col gap-y-2",
4024
4217
  children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
4218
+ "data-testid": "pane-title",
4025
4219
  variant: "h5",
4026
4220
  children: title
4027
4221
  }), /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
@@ -4032,6 +4226,7 @@ var OptionsPane = function OptionsPane(_ref) {
4032
4226
  className: "mb-pane-search",
4033
4227
  ref: searchRef,
4034
4228
  children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Input, {
4229
+ dataTestid: "pane-search",
4035
4230
  placeholder: t("neetoRules.builder.searchPlaceholder"),
4036
4231
  prefix: /*#__PURE__*/jsxRuntime.jsx(Search, {}),
4037
4232
  size: "large",
@@ -4046,6 +4241,7 @@ var OptionsPane = function OptionsPane(_ref) {
4046
4241
  children: [renderBody(), belowContent]
4047
4242
  }), cascade && /*#__PURE__*/jsxRuntime.jsx(index.Panel.Footer, {
4048
4243
  children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Button, {
4244
+ "data-testid": "continue-button",
4049
4245
  disabled: !canContinue,
4050
4246
  label: t("neetoRules.buttons.continue"),
4051
4247
  size: "lg",
@@ -4071,8 +4267,8 @@ var RecipientField = function RecipientField(_ref) {
4071
4267
  var fieldError = function fieldError(path) {
4072
4268
  return formik.getIn(touched, path) && formik.getIn(errors, path);
4073
4269
  };
4074
- if (field === "emails") {
4075
- var _path = "".concat(name, ".emails");
4270
+ if (field === RECIPIENT_STORAGE_FIELDS.emails) {
4271
+ var _path = "".concat(name, ".").concat(RECIPIENT_STORAGE_FIELDS.emails);
4076
4272
  var _current = formik.getIn(values, _path) || [];
4077
4273
  return /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.MultiEmailInput, {
4078
4274
  required: true,
@@ -4094,7 +4290,7 @@ var RecipientField = function RecipientField(_ref) {
4094
4290
  }
4095
4291
  });
4096
4292
  }
4097
- var path = "".concat(name, ".value");
4293
+ var path = "".concat(name, ".").concat(RECIPIENT_STORAGE_FIELDS.value);
4098
4294
  var current = formik.getIn(values, path);
4099
4295
  var options = normalizeOptions(dropdownOptions);
4100
4296
  return /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Select, {
@@ -4138,7 +4334,7 @@ var RecipientPane = function RecipientPane(_ref) {
4138
4334
  });
4139
4335
  var flatOption = ((_schema$actions4 = schema.actions) === null || _schema$actions4 === void 0 || (_schema$actions4$opti = _schema$actions4.optionForName) === null || _schema$actions4$opti === void 0 ? void 0 : _schema$actions4$opti.call(_schema$actions4, action.name)) || ((_schema$actions5 = schema.actions) === null || _schema$actions5 === void 0 || (_schema$actions5$opti = _schema$actions5.optionForChannel) === null || _schema$actions5$opti === void 0 ? void 0 : _schema$actions5$opti.call(_schema$actions5, channel));
4140
4336
  var isSmsToNumbers = (flatOption === null || flatOption === void 0 ? void 0 : flatOption.type) === SMS_TO_NUMBERS;
4141
- var recipientFieldPath = isSmsToNumbers ? "".concat(name, ".phoneNumbers") : "".concat(name, ".emails");
4337
+ var recipientFieldPath = isSmsToNumbers ? "".concat(name, ".").concat(RECIPIENT_STORAGE_FIELDS.phoneNumbers) : "".concat(name, ".").concat(RECIPIENT_STORAGE_FIELDS.emails);
4142
4338
  usePaneValidation(recipientFieldPath);
4143
4339
  react.useEffect(function () {
4144
4340
  var _bodyRef$current;
@@ -4169,7 +4365,7 @@ var RecipientPane = function RecipientPane(_ref) {
4169
4365
  action: action
4170
4366
  })) !== null && _schema$actions$rende !== void 0 ? _schema$actions$rende : builtInRecipientField;
4171
4367
  var phoneField = isSmsToNumbers ? /*#__PURE__*/jsxRuntime.jsx(index.PhoneNumberField, {
4172
- name: "".concat(name, ".phoneNumbers"),
4368
+ name: "".concat(name, ".").concat(RECIPIENT_STORAGE_FIELDS.phoneNumbers),
4173
4369
  phoneNumbers: (_action$metadata = action.metadata) === null || _action$metadata === void 0 ? void 0 : _action$metadata.phoneNumbers
4174
4370
  }) : null;
4175
4371
  var belowField = phoneField || recipientField;
@@ -4205,6 +4401,7 @@ var RecipientPane = function RecipientPane(_ref) {
4205
4401
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
4206
4402
  className: "flex w-full flex-col gap-y-2",
4207
4403
  children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
4404
+ "data-testid": "pane-title",
4208
4405
  variant: "h5",
4209
4406
  children: meta.recipientTitle || t("neetoRules.builder.panes.recipientTitle")
4210
4407
  }), /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
@@ -4251,6 +4448,7 @@ var ConditionValueFields = function ConditionValueFields(_ref) {
4251
4448
  };
4252
4449
  var noMatches = /*#__PURE__*/jsxRuntime.jsx("div", {
4253
4450
  className: "mb-pane-empty",
4451
+ "data-testid": "pane-no-matches",
4254
4452
  children: t("neetoRules.builder.noMatches")
4255
4453
  });
4256
4454
  if (type === CONDITION_VALUE_TYPES.multiSelect && neetoCist.isNotEmpty(enumOptions)) {
@@ -4262,7 +4460,7 @@ var ConditionValueFields = function ConditionValueFields(_ref) {
4262
4460
  setFieldValue(valuesPath, current.includes(value) ? current.filter(neetoCist.isNot(value)) : [].concat(_toConsumableArray(current), [value]));
4263
4461
  };
4264
4462
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
4265
- className: "flex flex-col gap-y-1",
4463
+ className: "mb-pane-list flex flex-col",
4266
4464
  children: [filtered.map(function (option) {
4267
4465
  return /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Checkbox, {
4268
4466
  checked: current.includes(option.value),
@@ -4406,6 +4604,7 @@ var ValuePane = function ValuePane(_ref) {
4406
4604
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
4407
4605
  className: "flex w-full flex-col gap-y-2",
4408
4606
  children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
4607
+ "data-testid": "pane-title",
4409
4608
  variant: "h5",
4410
4609
  children: t("neetoRules.builder.pickValue", {
4411
4610
  field: (field === null || field === void 0 ? void 0 : field.label) || t("neetoRules.builder.valueWord")
@@ -4420,6 +4619,7 @@ var ValuePane = function ValuePane(_ref) {
4420
4619
  className: "mb-pane-search",
4421
4620
  ref: searchRef,
4422
4621
  children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Input, {
4622
+ dataTestid: "pane-search",
4423
4623
  placeholder: t("neetoRules.builder.searchPlaceholder"),
4424
4624
  prefix: /*#__PURE__*/jsxRuntime.jsx(Search, {}),
4425
4625
  size: "large",
@@ -4566,7 +4766,7 @@ var Form = function Form(_ref) {
4566
4766
  data: data,
4567
4767
  customData: customData,
4568
4768
  isNameGenerationDisabled: isNameRequired
4569
- }),
4769
+ }).concat(leadTimeValidationSchema(schema)),
4570
4770
  onSubmit: submitForm,
4571
4771
  children: function children() {
4572
4772
  return /*#__PURE__*/jsxRuntime.jsxs("div", {