@bigbinary/neeto-rules-frontend 2.7.19 → 2.7.21

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 (88) 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/en.json +2 -1
  8. package/app/javascript/src/translations/es-MX.json +2 -1
  9. package/app/javascript/src/translations/es.json +2 -1
  10. package/app/javascript/src/translations/et.json +2 -1
  11. package/app/javascript/src/translations/fi.json +2 -1
  12. package/app/javascript/src/translations/fil.json +2 -1
  13. package/app/javascript/src/translations/fr.json +2 -1
  14. package/app/javascript/src/translations/he.json +2 -1
  15. package/app/javascript/src/translations/hi.json +2 -1
  16. package/app/javascript/src/translations/hr.json +2 -1
  17. package/app/javascript/src/translations/hu.json +2 -1
  18. package/app/javascript/src/translations/id.json +2 -1
  19. package/app/javascript/src/translations/it.json +2 -1
  20. package/app/javascript/src/translations/ja.json +2 -1
  21. package/app/javascript/src/translations/ko.json +2 -1
  22. package/app/javascript/src/translations/nl.json +2 -1
  23. package/app/javascript/src/translations/pl.json +2 -1
  24. package/app/javascript/src/translations/pt-BR.json +2 -1
  25. package/app/javascript/src/translations/pt.json +2 -1
  26. package/app/javascript/src/translations/ro.json +2 -1
  27. package/app/javascript/src/translations/ru.json +2 -1
  28. package/app/javascript/src/translations/sk.json +2 -1
  29. package/app/javascript/src/translations/sl.json +2 -1
  30. package/app/javascript/src/translations/sv.json +2 -1
  31. package/app/javascript/src/translations/th.json +2 -1
  32. package/app/javascript/src/translations/tr.json +2 -1
  33. package/app/javascript/src/translations/uk.json +2 -1
  34. package/app/javascript/src/translations/vi.json +2 -1
  35. package/app/javascript/src/translations/zh-CN.json +2 -1
  36. package/app/javascript/src/translations/zh-TW.json +2 -1
  37. package/dist/.ready +1 -1
  38. package/dist/NeetoRulesBuilder.js +79 -17
  39. package/dist/NeetoRulesBuilder.js.map +1 -1
  40. package/dist/NeetoRulesForm.js +2 -2
  41. package/dist/cjs/NeetoRulesBuilder.js +78 -16
  42. package/dist/cjs/NeetoRulesBuilder.js.map +1 -1
  43. package/dist/cjs/NeetoRulesForm.js +2 -2
  44. package/dist/cjs/index.js +2 -2
  45. package/dist/cjs/v2/NeetoRules.js +1 -1
  46. package/dist/cjs/v2/NeetoRulesBuilder.js +370 -154
  47. package/dist/cjs/v2/NeetoRulesBuilder.js.map +1 -1
  48. package/dist/cjs/v2/NeetoRulesForm.js +10 -8
  49. package/dist/cjs/v2/NeetoRulesForm.js.map +1 -1
  50. package/dist/cjs/v2/RulePreview.js +1 -1
  51. package/dist/cjs/v2/hooks.js +2 -2
  52. package/dist/cjs/v2/index.js +4 -4
  53. package/dist/{index-DwGEK-_1.js → index-49edM85x.js} +2 -2
  54. package/dist/{index-DwGEK-_1.js.map → index-49edM85x.js.map} +1 -1
  55. package/dist/{index-ogJeZ752.js → index-BZYwFjcS.js} +2 -2
  56. package/dist/{index-ogJeZ752.js.map → index-BZYwFjcS.js.map} +1 -1
  57. package/dist/{index-k-eGkX-R.js → index-CcbW7H2S.js} +67 -21
  58. package/dist/index-CcbW7H2S.js.map +1 -0
  59. package/dist/{index-Vt6GY_o0.js → index-Fukq1VSN.js} +69 -18
  60. package/dist/index-Fukq1VSN.js.map +1 -0
  61. package/dist/index.js +2 -2
  62. package/dist/keyboardShortcuts-DtnjcivY.js +96 -0
  63. package/dist/{keyboardShortcuts-DNOhEY8h.js.map → keyboardShortcuts-DtnjcivY.js.map} +1 -1
  64. package/dist/keyboardShortcuts-_OrtgF0A.js +92 -0
  65. package/dist/{keyboardShortcuts-SAk712q8.js.map → keyboardShortcuts-_OrtgF0A.js.map} +1 -1
  66. package/dist/{useCustomDataStore-CU3KpyD4.js → useCustomDataStore-CEbhXugO.js} +2 -2
  67. package/dist/{useCustomDataStore-CU3KpyD4.js.map → useCustomDataStore-CEbhXugO.js.map} +1 -1
  68. package/dist/{useCustomDataStore-D9k8F5g-.js → useCustomDataStore-DPmWkEhs.js} +2 -2
  69. package/dist/{useCustomDataStore-D9k8F5g-.js.map → useCustomDataStore-DPmWkEhs.js.map} +1 -1
  70. package/dist/{useUtilityStore-BBb39TOj.js → useUtilityStore-BVCulMEC.js} +9 -2
  71. package/dist/useUtilityStore-BVCulMEC.js.map +1 -0
  72. package/dist/{useUtilityStore-DkxAexDw.js → useUtilityStore-gtPhFvpI.js} +9 -2
  73. package/dist/useUtilityStore-gtPhFvpI.js.map +1 -0
  74. package/dist/v2/NeetoRules.js +1 -1
  75. package/dist/v2/NeetoRulesBuilder.js +352 -155
  76. package/dist/v2/NeetoRulesBuilder.js.map +1 -1
  77. package/dist/v2/NeetoRulesForm.js +10 -8
  78. package/dist/v2/NeetoRulesForm.js.map +1 -1
  79. package/dist/v2/RulePreview.js +1 -1
  80. package/dist/v2/hooks.js +2 -2
  81. package/dist/v2/index.js +4 -4
  82. package/package.json +7 -7
  83. package/dist/index-Vt6GY_o0.js.map +0 -1
  84. package/dist/index-k-eGkX-R.js.map +0 -1
  85. package/dist/keyboardShortcuts-DNOhEY8h.js +0 -88
  86. package/dist/keyboardShortcuts-SAk712q8.js +0 -92
  87. package/dist/useUtilityStore-BBb39TOj.js.map +0 -1
  88. 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-SAk712q8.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-Vt6GY_o0.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,8 +24,9 @@ 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 reactUtils = require('@bigbinary/neeto-commons-frontend/v2/react-utils');
27
+ var yup = require('yup');
28
28
  var _asyncToGenerator = require('@babel/runtime/helpers/asyncToGenerator');
29
+ var useHotkeys = require('@bigbinary/neeto-hotkeys');
29
30
  var Search = require('@bigbinary/neeto-icons/Search');
30
31
  var utils = require('@bigbinary/neeto-commons-frontend/v2/utils');
31
32
  var utils$1 = require('../../utils-B3roKiff.js');
@@ -37,12 +38,11 @@ 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
+ require('@bigbinary/neeto-commons-frontend/v2/react-utils');
42
43
  require('@monaco-editor/react');
43
44
  require('@bigbinary/neeto-molecules/v2/DynamicVariables');
44
45
  require('@bigbinary/neeto-editor/v2/FormikEditor');
45
- require('@bigbinary/neeto-hotkeys');
46
46
  require('react-select/creatable');
47
47
  require('@babel/runtime/helpers/toArray');
48
48
  require('@bigbinary/neeto-molecules/v2/PhoneNumber');
@@ -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() {
@@ -214,6 +253,21 @@ var TOKEN_STATE = {
214
253
  };
215
254
  var STATE_CLASS = _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty({}, TOKEN_STATE.PLACEHOLDER, "mb-placeholder"), TOKEN_STATE.PLACEHOLDER_NEXT, "mb-placeholder mb-placeholder-next"), TOKEN_STATE.DISABLED, "mb-placeholder mb-placeholder-disabled"), TOKEN_STATE.FILLED, "mb-tok"), TOKEN_STATE.MUTED, "mb-tok mb-tok-muted");
216
255
 
256
+ // The flash is a run-once CSS animation, so a repeat submit while it is still
257
+ // applied would not replay it on its own.
258
+ var useReplayFlash = function useReplayFlash(flashSeq) {
259
+ var ref = react.useRef(null);
260
+ react.useEffect(function () {
261
+ var _ref$current, _ref$current$getAnima;
262
+ if (!flashSeq) return;
263
+ (_ref$current = ref.current) === null || _ref$current === void 0 || (_ref$current$getAnima = _ref$current.getAnimations) === null || _ref$current$getAnima === void 0 || _ref$current$getAnima.call(_ref$current).forEach(function (animation) {
264
+ animation.cancel();
265
+ animation.play();
266
+ });
267
+ }, [flashSeq]);
268
+ return ref;
269
+ };
270
+
217
271
  var _excluded = ["children", "state", "active", "invalid", "onClick", "className", "dataTestid"];
218
272
  function ownKeys$c(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; }
219
273
  function _objectSpread$c(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$c(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$c(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -230,8 +284,10 @@ var Token = function Token(_ref) {
230
284
  dataTestid = _ref.dataTestid,
231
285
  rest = _objectWithoutProperties(_ref, _excluded);
232
286
  var isInteractive = typeof onClick === "function" && state !== TOKEN_STATE.DISABLED;
287
+ var tokenRef = useReplayFlash(invalid);
233
288
  return /*#__PURE__*/jsxRuntime.jsx("span", _objectSpread$c(_objectSpread$c({
234
289
  "data-testid": dataTestid,
290
+ ref: tokenRef,
235
291
  role: isInteractive ? "button" : undefined,
236
292
  tabIndex: isInteractive ? 0 : undefined,
237
293
  className: classNames(
@@ -537,6 +593,25 @@ var partsToMinutes = function partsToMinutes(_ref19) {
537
593
  (Number(value) || 0) * (UNIT_MINUTES[unit] || 1)
538
594
  );
539
595
  };
596
+ var leadTimeExceedsMax = function leadTimeExceedsMax(minutes) {
597
+ return minutesToParts(minutes).value > MAX_LEAD_TIME_VALUE;
598
+ };
599
+ var leadTimeValidationSchema = function leadTimeValidationSchema(schema) {
600
+ var _schema$triggers2;
601
+ 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;
602
+ if (!fieldKey) return yup__namespace.object();
603
+ return yup__namespace.object().shape(_defineProperty({}, fieldKey, yup__namespace.object().shape({
604
+ // yup 0.32 can only concat schemas of the same type, and the host's
605
+ // generic field schema for the lead time key is a string schema.
606
+ value: yup__namespace.string().test("max-lead-time", function () {
607
+ return i18next.t("neetoRules.validations.maxLeadTime", {
608
+ max: MAX_LEAD_TIME_VALUE
609
+ });
610
+ }, function (minutes) {
611
+ return !leadTimeExceedsMax(minutes);
612
+ })
613
+ })));
614
+ };
540
615
  var leadTimeLabel = function leadTimeLabel(minutes) {
541
616
  var _minutesToParts = minutesToParts(minutes),
542
617
  value = _minutesToParts.value,
@@ -559,6 +634,9 @@ var normalizeSchema = function normalizeSchema() {
559
634
  var joinTypeFor = function joinTypeFor(mode) {
560
635
  return mode === CONDITION_MODE.OR ? JOIN_TYPE.or : JOIN_TYPE.and;
561
636
  };
637
+ var recipientStorageField = function recipientStorageField(field) {
638
+ return field === RECIPIENT_STORAGE_FIELDS.emails ? RECIPIENT_STORAGE_FIELDS.emails : RECIPIENT_STORAGE_FIELDS.value;
639
+ };
562
640
  var modeFromJoinType = function modeFromJoinType(joinType) {
563
641
  return joinType === JOIN_TYPE.or ? CONDITION_MODE.OR : CONDITION_MODE.AND;
564
642
  };
@@ -574,15 +652,15 @@ var asArray = function asArray(maybeArray) {
574
652
  return Array.isArray(maybeArray) ? maybeArray : [];
575
653
  };
576
654
  var fieldKeysFromSchema = function fieldKeysFromSchema() {
577
- var _schema$triggers2, _schema$actor2, _schema$conditions3, _schema$actions3, _schema$delay, _schema$triggers3, _schema$scope2;
655
+ var _schema$triggers3, _schema$actor2, _schema$conditions3, _schema$actions3, _schema$delay, _schema$triggers4, _schema$scope2;
578
656
  var schema = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
579
657
  return {
580
- triggers: ((_schema$triggers2 = schema.triggers) === null || _schema$triggers2 === void 0 ? void 0 : _schema$triggers2.fieldKey) || "events",
658
+ triggers: ((_schema$triggers3 = schema.triggers) === null || _schema$triggers3 === void 0 ? void 0 : _schema$triggers3.fieldKey) || "events",
581
659
  performer: ((_schema$actor2 = schema.actor) === null || _schema$actor2 === void 0 ? void 0 : _schema$actor2.fieldKey) || "performer",
582
660
  conditions: ((_schema$conditions3 = schema.conditions) === null || _schema$conditions3 === void 0 ? void 0 : _schema$conditions3.fieldKey) || "conditions",
583
661
  actions: ((_schema$actions3 = schema.actions) === null || _schema$actions3 === void 0 ? void 0 : _schema$actions3.fieldKey) || "actions",
584
662
  delay: ((_schema$delay = schema.delay) === null || _schema$delay === void 0 ? void 0 : _schema$delay.fieldKey) || "execution_delay",
585
- 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,
663
+ 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,
586
664
  scope: ((_schema$scope2 = schema.scope) === null || _schema$scope2 === void 0 ? void 0 : _schema$scope2.fieldKey) || "meetingIds",
587
665
  status: "status",
588
666
  name: "name"
@@ -735,6 +813,35 @@ var removeArrayItem = function removeArrayItem(_ref30) {
735
813
  }
736
814
  return result;
737
815
  };
816
+ var clearArrayItems = function clearArrayItems(_ref31) {
817
+ var values = _ref31.values,
818
+ fieldKey = _ref31.fieldKey;
819
+ var list = asArray(valueAt({
820
+ values: values,
821
+ key: fieldKey
822
+ }));
823
+ var removed = list.filter(function (item) {
824
+ return item === null || item === void 0 ? void 0 : item.id;
825
+ }).map(function (item) {
826
+ return _objectSpread$b(_objectSpread$b({}, item), {}, {
827
+ _destroy: true
828
+ });
829
+ });
830
+ var result = [{
831
+ path: "".concat(fieldKey, ".value"),
832
+ value: []
833
+ }];
834
+ if (removed.length) {
835
+ var _values$fieldKey2;
836
+ // eslint-disable-next-line security/detect-object-injection
837
+ var deleted = asArray(values === null || values === void 0 || (_values$fieldKey2 = values[fieldKey]) === null || _values$fieldKey2 === void 0 ? void 0 : _values$fieldKey2.deleted);
838
+ result.push({
839
+ path: "".concat(fieldKey, ".deleted"),
840
+ value: [].concat(_toConsumableArray(deleted), _toConsumableArray(removed))
841
+ });
842
+ }
843
+ return result;
844
+ };
738
845
 
739
846
  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; }
740
847
  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; }
@@ -994,15 +1101,17 @@ var DelayRow = function DelayRow(_ref) {
994
1101
  });
995
1102
  };
996
1103
 
997
- var MetaBlock = reactUtils.withT(function (_ref) {
998
- var t = _ref.t,
999
- rule = _ref.rule,
1104
+ var MetaBlock = function MetaBlock(_ref) {
1105
+ var rule = _ref.rule,
1000
1106
  _ref$showName = _ref.showName,
1001
1107
  showName = _ref$showName === void 0 ? true : _ref$showName,
1002
1108
  _ref$isInvalid = _ref.isInvalid,
1003
1109
  isInvalid = _ref$isInvalid === void 0 ? false : _ref$isInvalid,
1004
1110
  handleEditName = _ref.onEditName,
1005
1111
  handleToggleActive = _ref.onToggleActive;
1112
+ var _useTranslation = reactI18next.useTranslation(),
1113
+ t = _useTranslation.t;
1114
+ var nameRef = useReplayFlash(isInvalid);
1006
1115
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
1007
1116
  className: "mb-meta",
1008
1117
  children: [showName && /*#__PURE__*/jsxRuntime.jsxs("div", {
@@ -1011,6 +1120,8 @@ var MetaBlock = reactUtils.withT(function (_ref) {
1011
1120
  className: "mb-meta-label",
1012
1121
  children: t("neetoRules.builder.automationName")
1013
1122
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
1123
+ ref: nameRef,
1124
+ "data-testid": "rule-name-edit",
1014
1125
  role: handleEditName ? "button" : undefined,
1015
1126
  tabIndex: handleEditName ? 0 : undefined,
1016
1127
  className: classNames("mb-meta-input-wrap", {
@@ -1019,6 +1130,7 @@ var MetaBlock = reactUtils.withT(function (_ref) {
1019
1130
  onClick: handleEditName,
1020
1131
  children: [/*#__PURE__*/jsxRuntime.jsx("span", {
1021
1132
  className: "mb-meta-name-display",
1133
+ "data-testid": "rule-name",
1022
1134
  children: rule.name
1023
1135
  }), /*#__PURE__*/jsxRuntime.jsx("span", {
1024
1136
  "aria-hidden": true,
@@ -1040,8 +1152,10 @@ var MetaBlock = reactUtils.withT(function (_ref) {
1040
1152
  })]
1041
1153
  }), /*#__PURE__*/jsxRuntime.jsxs("label", {
1042
1154
  className: "mb-meta-active",
1155
+ "data-testid": "rule-active-label",
1043
1156
  children: [/*#__PURE__*/jsxRuntime.jsx("input", {
1044
1157
  checked: rule.active,
1158
+ "data-testid": "rule-active-checkbox",
1045
1159
  readOnly: !handleToggleActive,
1046
1160
  type: "checkbox",
1047
1161
  onChange: handleToggleActive || undefined
@@ -1060,7 +1174,7 @@ var MetaBlock = reactUtils.withT(function (_ref) {
1060
1174
  }), t("neetoRules.builder.activateThisAutomation")]
1061
1175
  })]
1062
1176
  });
1063
- });
1177
+ };
1064
1178
 
1065
1179
  function ownKeys$8(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; }
1066
1180
  function _objectSpread$8(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$8(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$8(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -1299,6 +1413,8 @@ var ActionRow = function ActionRow(_ref) {
1299
1413
  });
1300
1414
  var configLabel = mediumLabel || sentencify(option === null || option === void 0 ? void 0 : option.placeholder);
1301
1415
  var isConfigured = neetoCist.isNotEmpty(action === null || action === void 0 ? void 0 : action.metadata);
1416
+ // A host that shows no value label still needs the token to read as filled.
1417
+ var configState = configValue || isConfigured ? TOKEN_STATE.FILLED : TOKEN_STATE.MUTED;
1302
1418
  var _useClearingHover = useClearingHover(),
1303
1419
  clearing = _useClearingHover.clearing,
1304
1420
  clearingHoverProps = _useClearingHover.clearingHoverProps;
@@ -1337,7 +1453,7 @@ var ActionRow = function ActionRow(_ref) {
1337
1453
  children: verbLabel
1338
1454
  }), hasParamTail ? /*#__PURE__*/jsxRuntime.jsx(Token, {
1339
1455
  dataTestid: "action-config-value-".concat(index),
1340
- state: configValue ? TOKEN_STATE.FILLED : TOKEN_STATE.MUTED,
1456
+ state: configState,
1341
1457
  active: isActive({
1342
1458
  type: BUILDER_ANCHORS.ACTION_CONFIG,
1343
1459
  index: index
@@ -1385,7 +1501,7 @@ var ActionRow = function ActionRow(_ref) {
1385
1501
  index: index
1386
1502
  }),
1387
1503
  dataTestid: "action-config-value-".concat(index),
1388
- state: configValue ? TOKEN_STATE.FILLED : TOKEN_STATE.MUTED,
1504
+ state: configState,
1389
1505
  invalid: isInvalid({
1390
1506
  type: BUILDER_ANCHORS.ACTION_CONFIG,
1391
1507
  index: index
@@ -1608,6 +1724,10 @@ var WhenBlock = function WhenBlock(_ref) {
1608
1724
  type: BUILDER_ANCHORS.TRIGGER_LEAD_TIME,
1609
1725
  index: index
1610
1726
  }),
1727
+ invalid: isInvalid({
1728
+ type: BUILDER_ANCHORS.TRIGGER_LEAD_TIME,
1729
+ index: index
1730
+ }),
1611
1731
  onClick: handleToken && function () {
1612
1732
  return handleToken({
1613
1733
  type: BUILDER_ANCHORS.TRIGGER_LEAD_TIME,
@@ -1818,6 +1938,24 @@ var useRuleModel = function useRuleModel(schema) {
1818
1938
  fieldKey: fieldKeysFromSchema(schema).actions,
1819
1939
  index: index
1820
1940
  }));
1941
+ },
1942
+ clearTriggers: function clearTriggers() {
1943
+ return applyAll(clearArrayItems({
1944
+ values: values,
1945
+ fieldKey: fieldKeysFromSchema(schema).triggers
1946
+ }));
1947
+ },
1948
+ clearConditions: function clearConditions() {
1949
+ return applyAll(clearArrayItems({
1950
+ values: values,
1951
+ fieldKey: fieldKeysFromSchema(schema).conditions
1952
+ }));
1953
+ },
1954
+ clearActions: function clearActions() {
1955
+ return applyAll(clearArrayItems({
1956
+ values: values,
1957
+ fieldKey: fieldKeysFromSchema(schema).actions
1958
+ }));
1821
1959
  }
1822
1960
  };
1823
1961
  };
@@ -1964,9 +2102,9 @@ var nextTriggers = function nextTriggers(_ref10) {
1964
2102
  name: value
1965
2103
  }]);
1966
2104
  }
1967
- return [{
2105
+ return [_objectSpread$4(_objectSpread$4({}, rule.triggers[0]), {}, {
1968
2106
  name: value
1969
- }];
2107
+ })];
1970
2108
  };
1971
2109
  var nextConditionAt = function nextConditionAt(_ref11) {
1972
2110
  var _field$allowMatching;
@@ -2213,7 +2351,7 @@ var descriptorFor = function descriptorFor(_ref15) {
2213
2351
  case BUILDER_ANCHORS.ACTION_ADD:
2214
2352
  case BUILDER_ANCHORS.ACTION_CHANNEL:
2215
2353
  {
2216
- var _schema$actions11, _schema$actions12, _channelOf;
2354
+ var _schema$actions11, _channelOf;
2217
2355
  var isSwap = anchor === BUILDER_ANCHORS.ACTION_CHANNEL;
2218
2356
  var channelMetaFor = function channelMetaFor(value) {
2219
2357
  var _schema$actions10;
@@ -2222,13 +2360,10 @@ var descriptorFor = function descriptorFor(_ref15) {
2222
2360
  ((_schema$actions10 = schema.actions) === null || _schema$actions10 === void 0 || (_schema$actions10 = _schema$actions10.channelMeta) === null || _schema$actions10 === void 0 ? void 0 : _schema$actions10[value]) || {}
2223
2361
  );
2224
2362
  };
2225
- var rank = function rank(value) {
2226
- var idx = SWAP_CHANNEL_ORDER.indexOf(value);
2227
- return idx === -1 ? SWAP_CHANNEL_ORDER.length : idx;
2228
- };
2229
- var sourceOptions = isSwap ? _toConsumableArray(((_schema$actions11 = schema.actions) === null || _schema$actions11 === void 0 ? void 0 : _schema$actions11.options) || []).sort(function (optionA, optionB) {
2230
- return rank(optionValue(optionA)) - rank(optionValue(optionB));
2231
- }) : ((_schema$actions12 = schema.actions) === null || _schema$actions12 === void 0 ? void 0 : _schema$actions12.options) || [];
2363
+
2364
+ // Both panes list the host's actions in the order it declared them;
2365
+ // re-ranking only the swap pane made the two disagree.
2366
+ var sourceOptions = ((_schema$actions11 = schema.actions) === null || _schema$actions11 === void 0 ? void 0 : _schema$actions11.options) || [];
2232
2367
  return {
2233
2368
  title: isSwap ? i18next.t("neetoRules.builder.panes.actionSwapTitle") : i18next.t("neetoRules.builder.panes.actionAddTitle"),
2234
2369
  subtitle: isSwap ? i18next.t("neetoRules.builder.panes.actionSwapSubtitle") : i18next.t("neetoRules.builder.panes.actionAddSubtitle"),
@@ -2258,7 +2393,7 @@ var descriptorFor = function descriptorFor(_ref15) {
2258
2393
  }
2259
2394
  case BUILDER_ANCHORS.ACTION_RECIPIENT:
2260
2395
  {
2261
- var _schema$actions13;
2396
+ var _schema$actions12;
2262
2397
  var action = actionAt({
2263
2398
  rule: rule,
2264
2399
  index: index
@@ -2268,7 +2403,7 @@ var descriptorFor = function descriptorFor(_ref15) {
2268
2403
  action: action
2269
2404
  });
2270
2405
  // eslint-disable-next-line security/detect-object-injection
2271
- 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]) || {};
2406
+ 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]) || {};
2272
2407
  var option = findActionOption({
2273
2408
  schema: schema,
2274
2409
  name: channel
@@ -2384,9 +2519,9 @@ var commitFor = function commitFor(_ref16) {
2384
2519
  }]));
2385
2520
  return "stay";
2386
2521
  }
2387
- setTriggers([{
2522
+ setTriggers([_objectSpread$4(_objectSpread$4({}, rule.triggers[0]), {}, {
2388
2523
  name: value
2389
- }]);
2524
+ })]);
2390
2525
  var leadTime = (_schema$triggers5 = schema.triggers) === null || _schema$triggers5 === void 0 ? void 0 : _schema$triggers5.leadTime;
2391
2526
  if (leadTime !== null && leadTime !== void 0 && leadTime.fieldKey && (leadTime.appliesTo || []).includes(value) && !rule.leadTime) {
2392
2527
  var _leadTime$default;
@@ -2653,7 +2788,7 @@ var applyPreview = function applyPreview(_ref19) {
2653
2788
  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; }
2654
2789
  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; }
2655
2790
  var Canvas = function Canvas(_ref) {
2656
- var _schema$scope, _schema$scope2, _schema$conditions, _schema$triggers, _schema$delay, _schema$meta$showName, _schema$meta;
2791
+ var _schema$scope, _schema$conditions, _schema$triggers, _schema$delay, _schema$meta$showName, _schema$meta;
2657
2792
  var schema = _ref.schema;
2658
2793
  var _useTranslation = reactI18next.useTranslation(),
2659
2794
  t = _useTranslation.t;
@@ -2666,15 +2801,16 @@ var Canvas = function Canvas(_ref) {
2666
2801
  var _useRuleModel = useRuleModel(schema),
2667
2802
  rule = _useRuleModel.rule,
2668
2803
  fieldKeys = _useRuleModel.fieldKeys,
2669
- setTriggers = _useRuleModel.setTriggers,
2670
2804
  setPerformer = _useRuleModel.setPerformer,
2671
2805
  setConditions = _useRuleModel.setConditions,
2672
- setActions = _useRuleModel.setActions,
2673
2806
  setDelay = _useRuleModel.setDelay,
2674
2807
  removeCondition = _useRuleModel.removeCondition,
2675
2808
  removeAction = _useRuleModel.removeAction,
2676
2809
  setActive = _useRuleModel.setActive,
2677
- setScope = _useRuleModel.setScope;
2810
+ setScope = _useRuleModel.setScope,
2811
+ clearTriggers = _useRuleModel.clearTriggers,
2812
+ clearConditions = _useRuleModel.clearConditions,
2813
+ clearActions = _useRuleModel.clearActions;
2678
2814
  var _useUtilityStore = useUtilityStore.useUtilityStore(shallow.useShallow(function (store) {
2679
2815
  return {
2680
2816
  builderPreview: store["builderPreview"],
@@ -2699,10 +2835,10 @@ var Canvas = function Canvas(_ref) {
2699
2835
  var flatErrors = react.useMemo(function () {
2700
2836
  return keyboardShortcuts.flatten(errors || {});
2701
2837
  }, [errors]);
2702
- var _useState = react.useState(false),
2838
+ var _useState = react.useState(0),
2703
2839
  _useState2 = _slicedToArray(_useState, 2),
2704
- flashing = _useState2[0],
2705
- setFlashing = _useState2[1];
2840
+ flashSeq = _useState2[0],
2841
+ setFlashSeq = _useState2[1];
2706
2842
  var lastSubmitCount = react.useRef(submitCount);
2707
2843
  react.useEffect(function () {
2708
2844
  if (submitCount <= lastSubmitCount.current) return undefined;
@@ -2716,10 +2852,10 @@ var Canvas = function Canvas(_ref) {
2716
2852
  }))) {
2717
2853
  return undefined;
2718
2854
  }
2719
- setFlashing(true);
2855
+ setFlashSeq(submitCount);
2720
2856
  var timer = setTimeout(function () {
2721
- return setFlashing(false);
2722
- }, 2200);
2857
+ return setFlashSeq(0);
2858
+ }, FLASH_DURATION_MS);
2723
2859
  return function () {
2724
2860
  return clearTimeout(timer);
2725
2861
  };
@@ -2735,11 +2871,10 @@ var Canvas = function Canvas(_ref) {
2735
2871
  });
2736
2872
  });
2737
2873
  };
2738
- var isInvalid = function isInvalid(_ref4) {
2739
- 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;
2874
+ var matchesInvalid = function matchesInvalid(_ref4) {
2875
+ 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;
2740
2876
  var type = _ref4.type,
2741
2877
  index = _ref4.index;
2742
- if (!flashing) return false;
2743
2878
  var conditionMeta = "".concat(fieldKeys.conditions, ".value.").concat(index, ".metadata");
2744
2879
  var actionMeta = "".concat(fieldKeys.actions, ".value.").concat(index, ".metadata");
2745
2880
  // eslint-disable-next-line security/detect-object-injection
@@ -2757,7 +2892,13 @@ var Canvas = function Canvas(_ref) {
2757
2892
  action: actionItem
2758
2893
  }));
2759
2894
  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));
2760
- var recipientFields = [].concat(_toConsumableArray(hasRecipientEditor || hasRecipientField ? ["emails"] : []), _toConsumableArray((flatOption === null || flatOption === void 0 ? void 0 : flatOption.type) === "smsToNumbers" ? ["phoneNumbers"] : []));
2895
+ var recipientConfig = [].concat(_toConsumableArray((((_schema$actions6 = schema.actions) === null || _schema$actions6 === void 0 ? void 0 : _schema$actions6.options) || []).flatMap(function (option) {
2896
+ return option.recipients || [];
2897
+ })), _toConsumableArray(((_schema$actions7 = schema.actions) === null || _schema$actions7 === void 0 ? void 0 : _schema$actions7.recipients) || [])).find(function (item) {
2898
+ var _item$value;
2899
+ return ((_item$value = item.value) !== null && _item$value !== void 0 ? _item$value : item.id) === actionItem.recipient;
2900
+ });
2901
+ 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] : []));
2761
2902
  switch (type) {
2762
2903
  case BUILDER_ANCHORS.TRIGGER_ACTOR:
2763
2904
  {
@@ -2767,6 +2908,10 @@ var Canvas = function Canvas(_ref) {
2767
2908
  prefix: "".concat(actorKey, ".value")
2768
2909
  });
2769
2910
  }
2911
+ case BUILDER_ANCHORS.TRIGGER_LEAD_TIME:
2912
+ return hasErrorAt({
2913
+ prefix: "".concat(fieldKeys.leadTime, ".value")
2914
+ });
2770
2915
  case BUILDER_ANCHORS.COND_FIELD:
2771
2916
  return hasErrorAt({
2772
2917
  prefix: "".concat(fieldKeys.conditions, ".value.").concat(index, ".field")
@@ -2787,7 +2932,9 @@ var Canvas = function Canvas(_ref) {
2787
2932
  exclude: recipientFields
2788
2933
  });
2789
2934
  case BUILDER_ANCHORS.ACTION_RECIPIENT:
2790
- return recipientFields.some(function (field) {
2935
+ return hasErrorAt({
2936
+ prefix: "".concat(fieldKeys.actions, ".value.").concat(index, ".name")
2937
+ }) || recipientFields.some(function (field) {
2791
2938
  return hasErrorAt({
2792
2939
  prefix: "".concat(actionMeta, ".").concat(field)
2793
2940
  });
@@ -2818,6 +2965,12 @@ var Canvas = function Canvas(_ref) {
2818
2965
  return false;
2819
2966
  }
2820
2967
  };
2968
+
2969
+ // Returns the submit generation, not a boolean, so consumers can replay the
2970
+ // flash animation when the same token is still invalid on a repeat submit.
2971
+ var isInvalid = function isInvalid(args) {
2972
+ return flashSeq && matchesInvalid(args) ? flashSeq : 0;
2973
+ };
2821
2974
  var closePaneIfTargeting = function closePaneIfTargeting(_ref5) {
2822
2975
  var anchors = _ref5.anchors,
2823
2976
  index = _ref5.index;
@@ -2859,8 +3012,6 @@ var Canvas = function Canvas(_ref) {
2859
3012
  return (action === null || action === void 0 ? void 0 : action.channel) || (action === null || action === void 0 ? void 0 : action.name);
2860
3013
  });
2861
3014
  var isScopeEnabled = (schema === null || schema === void 0 || (_schema$scope = schema.scope) === null || _schema$scope === void 0 ? void 0 : _schema$scope.enabled) && isTriggerSet && hasAction;
2862
- var isScopeComplete = !(schema !== null && schema !== void 0 && (_schema$scope2 = schema.scope) !== null && _schema$scope2 !== void 0 && _schema$scope2.enabled) || neetoCist.isNotEmpty(rule.scope || []);
2863
- var isComplete = isRuleComplete(rule) && isScopeComplete;
2864
3015
  var handleRemoveScope = function handleRemoveScope(index) {
2865
3016
  closePaneIfTargeting({
2866
3017
  anchors: [BUILDER_ANCHORS.SCOPE_PHONE_FIELD],
@@ -2894,12 +3045,12 @@ var Canvas = function Canvas(_ref) {
2894
3045
  };
2895
3046
  var handleClearTrigger = function handleClearTrigger() {
2896
3047
  var _schema$actor2;
2897
- setTriggers([]);
3048
+ clearTriggers();
2898
3049
  // Hosts without an actor pane can never re-set it, and null fails its validation.
2899
3050
  if ((_schema$actor2 = schema.actor) !== null && _schema$actor2 !== void 0 && _schema$actor2.enabled) setPerformer(null);
2900
- setConditions([]);
3051
+ clearConditions();
2901
3052
  setDelay(null);
2902
- setActions([]);
3053
+ clearActions();
2903
3054
  setScope([]);
2904
3055
  closePane();
2905
3056
  };
@@ -2921,7 +3072,7 @@ var Canvas = function Canvas(_ref) {
2921
3072
  );
2922
3073
  };
2923
3074
  return /*#__PURE__*/jsxRuntime.jsx("div", {
2924
- className: "neeto-rules-builder",
3075
+ className: "neeto-rules-builder nrb-atoms",
2925
3076
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
2926
3077
  className: "mb-canvas neeto-rules-main-card",
2927
3078
  children: [/*#__PURE__*/jsxRuntime.jsx(WhenBlock, {
@@ -2963,6 +3114,7 @@ var Canvas = function Canvas(_ref) {
2963
3114
  }) : /*#__PURE__*/jsxRuntime.jsx("div", {
2964
3115
  className: "mb-add-row",
2965
3116
  children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Button, {
3117
+ "data-testid": "rule-delay-add",
2966
3118
  icon: Plus,
2967
3119
  iconPosition: "left",
2968
3120
  label: t("neetoRules.common.addDelay"),
@@ -2994,24 +3146,22 @@ var Canvas = function Canvas(_ref) {
2994
3146
  onRemoveScope: handleRemoveScope,
2995
3147
  onToken: openPane
2996
3148
  })]
2997
- }), isComplete && /*#__PURE__*/jsxRuntime.jsxs(react.Fragment, {
2998
- children: [/*#__PURE__*/jsxRuntime.jsx(Connector, {
2999
- active: true
3000
- }), /*#__PURE__*/jsxRuntime.jsx(MetaBlock, {
3001
- rule: rule,
3002
- isInvalid: isInvalid({
3149
+ }), /*#__PURE__*/jsxRuntime.jsx(Connector, {
3150
+ active: true
3151
+ }), /*#__PURE__*/jsxRuntime.jsx(MetaBlock, {
3152
+ rule: rule,
3153
+ isInvalid: isInvalid({
3154
+ type: BUILDER_ANCHORS.META_NAME
3155
+ }),
3156
+ 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,
3157
+ onEditName: function onEditName() {
3158
+ return openPane({
3003
3159
  type: BUILDER_ANCHORS.META_NAME
3004
- }),
3005
- 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,
3006
- onEditName: function onEditName() {
3007
- return openPane({
3008
- type: BUILDER_ANCHORS.META_NAME
3009
- });
3010
- },
3011
- onToggleActive: function onToggleActive(event) {
3012
- return setActive(event.target.checked);
3013
- }
3014
- })]
3160
+ });
3161
+ },
3162
+ onToggleActive: function onToggleActive(event) {
3163
+ return setActive(event.target.checked);
3164
+ }
3015
3165
  })]
3016
3166
  })
3017
3167
  });
@@ -3022,6 +3172,7 @@ var ACTION_CONFIG_TYPES = {
3022
3172
  multiSelect: "multiSelect",
3023
3173
  dropdown: "dropdown",
3024
3174
  note: "note",
3175
+ list: "list",
3025
3176
  textarea: "textarea",
3026
3177
  number: "number",
3027
3178
  text: "text",
@@ -3083,6 +3234,7 @@ var ActionConfigFields = function ActionConfigFields(_ref) {
3083
3234
  };
3084
3235
  var noMatches = /*#__PURE__*/jsxRuntime.jsx("div", {
3085
3236
  className: "mb-pane-empty",
3237
+ "data-testid": "pane-no-matches",
3086
3238
  children: t("neetoRules.builder.noMatches")
3087
3239
  });
3088
3240
  if (type === ACTION_CONFIG_TYPES.emailChannel) {
@@ -3091,7 +3243,7 @@ var ActionConfigFields = function ActionConfigFields(_ref) {
3091
3243
  var bodyPath = "".concat(name, ".body");
3092
3244
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
3093
3245
  className: "flex flex-col gap-4",
3094
- children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Input, {
3246
+ children: [!(option !== null && option !== void 0 && option.hideSubject) && /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Input, {
3095
3247
  required: true,
3096
3248
  error: fieldError(subjectPath),
3097
3249
  label: t("neetoRules.builder.config.subject"),
@@ -3124,7 +3276,7 @@ var ActionConfigFields = function ActionConfigFields(_ref) {
3124
3276
  setFieldValue(valuePath, current.includes(value) ? current.filter(neetoCist.isNot(value)) : [].concat(_toConsumableArray(current), [value]));
3125
3277
  };
3126
3278
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
3127
- className: "flex flex-col gap-y-1",
3279
+ className: "mb-pane-list flex flex-col",
3128
3280
  children: [filtered.map(function (item) {
3129
3281
  return /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Checkbox, {
3130
3282
  checked: current.includes(item.value),
@@ -3166,6 +3318,14 @@ var ActionConfigFields = function ActionConfigFields(_ref) {
3166
3318
  })
3167
3319
  });
3168
3320
  }
3321
+ if (type === ACTION_CONFIG_TYPES.list) {
3322
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
3323
+ className: "flex flex-col gap-2",
3324
+ children: [/*#__PURE__*/jsxRuntime.jsx(index.ListField, {
3325
+ name: valuePath
3326
+ }), hintBlock]
3327
+ });
3328
+ }
3169
3329
  if (type === ACTION_CONFIG_TYPES.note) {
3170
3330
  var _action$metadata2;
3171
3331
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
@@ -3411,7 +3571,7 @@ var ConfigPane = function ConfigPane(_ref) {
3411
3571
  while (1) switch (_context.n) {
3412
3572
  case 0:
3413
3573
  _context.n = 1;
3414
- return validate(["emails"]);
3574
+ return validate([RECIPIENT_STORAGE_FIELDS.emails]);
3415
3575
  case 1:
3416
3576
  if (_context.v) {
3417
3577
  _context.n = 2;
@@ -3439,11 +3599,15 @@ var ConfigPane = function ConfigPane(_ref) {
3439
3599
  return _ref2.apply(this, arguments);
3440
3600
  };
3441
3601
  }();
3602
+ useHotkeys(keyboardShortcuts.SHORTCUTS["continue"].sequence, handleContinue, {
3603
+ mode: "global"
3604
+ });
3442
3605
  return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
3443
3606
  children: [/*#__PURE__*/jsxRuntime.jsx(index.Panel.Header, {
3444
3607
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
3445
3608
  className: "flex w-full flex-col gap-y-2",
3446
3609
  children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
3610
+ "data-testid": "pane-title",
3447
3611
  variant: "h5",
3448
3612
  children: title
3449
3613
  }), configSubtitle && /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
@@ -3453,6 +3617,7 @@ var ConfigPane = function ConfigPane(_ref) {
3453
3617
  }), showSearch && /*#__PURE__*/jsxRuntime.jsx("div", {
3454
3618
  className: "mb-pane-search",
3455
3619
  children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Input, {
3620
+ dataTestid: "pane-search",
3456
3621
  placeholder: t("neetoRules.builder.searchPlaceholder"),
3457
3622
  prefix: /*#__PURE__*/jsxRuntime.jsx(Search, {}),
3458
3623
  size: "large",
@@ -3472,20 +3637,14 @@ var ConfigPane = function ConfigPane(_ref) {
3472
3637
  message: disabledReason,
3473
3638
  selectedField: flatOption
3474
3639
  })
3475
- }), isSms ? /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
3476
- children: [/*#__PURE__*/jsxRuntime.jsx(index.SmsFields, {
3477
- action: action,
3478
- index: index$1,
3479
- name: name,
3480
- shouldAutoFocus: true,
3481
- selectedField: flatOption,
3482
- showPhoneNumberInput: false
3483
- }), /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
3484
- className: "mt-2",
3485
- color: "muted",
3486
- variant: "body3",
3487
- children: t("neetoRules.builder.config.smsSegmentHint")
3488
- })]
3640
+ }), isSms ? /*#__PURE__*/jsxRuntime.jsx(index.SmsFields, {
3641
+ action: action,
3642
+ index: index$1,
3643
+ name: name,
3644
+ shouldAutoFocus: true,
3645
+ hint: t("neetoRules.builder.config.smsSegmentHint"),
3646
+ selectedField: flatOption,
3647
+ showPhoneNumberInput: false
3489
3648
  }) : (_hostRenderConfig = hostRenderConfig === null || hostRenderConfig === void 0 ? void 0 : hostRenderConfig({
3490
3649
  name: name,
3491
3650
  action: action,
@@ -3498,8 +3657,9 @@ var ConfigPane = function ConfigPane(_ref) {
3498
3657
  option: flatOption
3499
3658
  })]
3500
3659
  })
3501
- }), shouldAdvanceToRecipient && /*#__PURE__*/jsxRuntime.jsx(index.Panel.Footer, {
3660
+ }), /*#__PURE__*/jsxRuntime.jsx(index.Panel.Footer, {
3502
3661
  children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Button, {
3662
+ "data-testid": "continue-button",
3503
3663
  label: t("neetoRules.buttons.continue"),
3504
3664
  size: "lg",
3505
3665
  onClick: handleContinue
@@ -3516,7 +3676,9 @@ var DelayPane = function DelayPane(_ref) {
3516
3676
  var _useRuleModel = useRuleModel(schema),
3517
3677
  fieldKeys = _useRuleModel.fieldKeys;
3518
3678
  var _useFormikContext = formik.useFormikContext(),
3519
- setFieldValue = _useFormikContext.setFieldValue;
3679
+ setFieldValue = _useFormikContext.setFieldValue,
3680
+ setFieldTouched = _useFormikContext.setFieldTouched,
3681
+ getFieldMeta = _useFormikContext.getFieldMeta;
3520
3682
  var bodyRef = react.useRef(null);
3521
3683
  var name = fieldKeys.delay;
3522
3684
  var _useField = formik.useField("".concat(name, ".value")),
@@ -3525,12 +3687,18 @@ var DelayPane = function DelayPane(_ref) {
3525
3687
  var units = normalizeOptions((_schema$delay = schema.delay) === null || _schema$delay === void 0 ? void 0 : _schema$delay.units);
3526
3688
  var unitOptions = neetoCist.isNotEmpty(units) ? units : DEFAULT_DELAY_UNITS;
3527
3689
  usePaneValidation("".concat(name, ".value"));
3690
+ react.useEffect(function () {
3691
+ if ((value === null || value === void 0 ? void 0 : value.value) === undefined) return;
3692
+ if (getFieldMeta("".concat(name, ".value.value")).touched) return;
3693
+ setFieldTouched("".concat(name, ".value.value"), true, false);
3694
+ // eslint-disable-next-line react-hooks/exhaustive-deps
3695
+ }, [value === null || value === void 0 ? void 0 : value.value]);
3528
3696
  react.useEffect(function () {
3529
3697
  if (ramda.isEmpty(value || {})) {
3530
3698
  var _unitOptions$0$value, _unitOptions$;
3531
3699
  setFieldValue("".concat(name, ".value"), {
3532
- value: 10,
3533
- 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"
3700
+ value: DEFAULT_DELAY_VALUE,
3701
+ 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
3534
3702
  });
3535
3703
  }
3536
3704
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -3548,6 +3716,7 @@ var DelayPane = function DelayPane(_ref) {
3548
3716
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
3549
3717
  className: "flex flex-col gap-y-1",
3550
3718
  children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
3719
+ "data-testid": "pane-title",
3551
3720
  variant: "h5",
3552
3721
  children: t("neetoRules.common.addDelay")
3553
3722
  }), /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
@@ -3568,13 +3737,15 @@ var DelayPane = function DelayPane(_ref) {
3568
3737
  className: "flex items-start gap-x-2",
3569
3738
  children: [/*#__PURE__*/jsxRuntime.jsx(formik$1.Input, {
3570
3739
  className: "w-44",
3571
- max: 999,
3572
- min: 1,
3740
+ dataTestid: "delay-value",
3741
+ max: index.MAX_DELAY_VALUE,
3742
+ min: index.MIN_DELAY_VALUE,
3573
3743
  name: "".concat(name, ".value.value"),
3574
3744
  placeholder: t("neetoRules.placeholders.enterDelay"),
3575
3745
  size: "large",
3576
3746
  type: "number"
3577
3747
  }), /*#__PURE__*/jsxRuntime.jsx(formik$1.Select, {
3748
+ dataTestid: "delay-unit",
3578
3749
  defaultValue: value === null || value === void 0 ? void 0 : value.unit,
3579
3750
  name: "".concat(name, ".value.unit"),
3580
3751
  options: unitOptions,
@@ -3608,11 +3779,13 @@ var asText = function asText(value) {
3608
3779
  var NumberStepper = function NumberStepper(_ref) {
3609
3780
  var value = _ref.value,
3610
3781
  onChange = _ref.onChange,
3782
+ dataTestid = _ref.dataTestid,
3611
3783
  label = _ref.label,
3612
3784
  _ref$min = _ref.min,
3613
- min = _ref$min === void 0 ? 1 : _ref$min,
3785
+ min = _ref$min === void 0 ? STEPPER_MIN_VALUE : _ref$min,
3614
3786
  max = _ref.max,
3615
- required = _ref.required;
3787
+ required = _ref.required,
3788
+ error = _ref.error;
3616
3789
  var _useTranslation = reactI18next.useTranslation(),
3617
3790
  t = _useTranslation.t;
3618
3791
  var _useState = react.useState(null),
@@ -3637,15 +3810,41 @@ var NumberStepper = function NumberStepper(_ref) {
3637
3810
  max: max
3638
3811
  }));
3639
3812
  };
3640
- return /*#__PURE__*/jsxRuntime.jsxs("div", {
3813
+ return /*#__PURE__*/jsxRuntime.jsx("div", {
3641
3814
  className: "mb-stepper",
3642
- children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Input, {
3815
+ children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Input, {
3816
+ dataTestid: dataTestid,
3817
+ error: error,
3643
3818
  label: label,
3644
3819
  min: min,
3645
3820
  required: required,
3646
3821
  autoFocus: true,
3647
3822
  type: "number",
3648
3823
  value: display,
3824
+ suffix: /*#__PURE__*/jsxRuntime.jsxs("div", {
3825
+ className: "mb-stepper-controls",
3826
+ children: [/*#__PURE__*/jsxRuntime.jsx("button", {
3827
+ "aria-label": t("neetoRules.builder.aria.increase"),
3828
+ className: "mb-stepper-btn",
3829
+ "data-testid": "stepper-increase",
3830
+ tabIndex: SKIP_TAB_INDEX,
3831
+ type: "button",
3832
+ onClick: function onClick() {
3833
+ return step(STEPPER_DELTA.INCREMENT);
3834
+ },
3835
+ children: /*#__PURE__*/jsxRuntime.jsx(Up, {})
3836
+ }), /*#__PURE__*/jsxRuntime.jsx("button", {
3837
+ "aria-label": t("neetoRules.builder.aria.decrease"),
3838
+ className: "mb-stepper-btn",
3839
+ "data-testid": "stepper-decrease",
3840
+ tabIndex: SKIP_TAB_INDEX,
3841
+ type: "button",
3842
+ onClick: function onClick() {
3843
+ return step(STEPPER_DELTA.DECREMENT);
3844
+ },
3845
+ children: /*#__PURE__*/jsxRuntime.jsx(Down, {})
3846
+ })]
3847
+ }),
3649
3848
  onBlur: function onBlur() {
3650
3849
  return setDraft(null);
3651
3850
  },
@@ -3655,28 +3854,7 @@ var NumberStepper = function NumberStepper(_ref) {
3655
3854
  onFocus: function onFocus(event) {
3656
3855
  return event.target.select();
3657
3856
  }
3658
- }), /*#__PURE__*/jsxRuntime.jsxs("div", {
3659
- className: "mb-stepper-controls",
3660
- children: [/*#__PURE__*/jsxRuntime.jsx("button", {
3661
- "aria-label": t("neetoRules.builder.aria.increase"),
3662
- className: "mb-stepper-btn",
3663
- tabIndex: -1,
3664
- type: "button",
3665
- onClick: function onClick() {
3666
- return step(1);
3667
- },
3668
- children: /*#__PURE__*/jsxRuntime.jsx(Up, {})
3669
- }), /*#__PURE__*/jsxRuntime.jsx("button", {
3670
- "aria-label": t("neetoRules.builder.aria.decrease"),
3671
- className: "mb-stepper-btn",
3672
- tabIndex: -1,
3673
- type: "button",
3674
- onClick: function onClick() {
3675
- return step(-1);
3676
- },
3677
- children: /*#__PURE__*/jsxRuntime.jsx(Down, {})
3678
- })]
3679
- })]
3857
+ })
3680
3858
  });
3681
3859
  };
3682
3860
 
@@ -3685,7 +3863,9 @@ var LeadTimePane = function LeadTimePane(_ref) {
3685
3863
  var _useTranslation = reactI18next.useTranslation(),
3686
3864
  t = _useTranslation.t;
3687
3865
  var _useFormikContext = formik.useFormikContext(),
3688
- setFieldValue = _useFormikContext.setFieldValue;
3866
+ setFieldValue = _useFormikContext.setFieldValue,
3867
+ setFieldTouched = _useFormikContext.setFieldTouched,
3868
+ getFieldMeta = _useFormikContext.getFieldMeta;
3689
3869
  var _useRuleModel = useRuleModel(schema),
3690
3870
  rule = _useRuleModel.rule,
3691
3871
  fieldKeys = _useRuleModel.fieldKeys;
@@ -3693,6 +3873,11 @@ var LeadTimePane = function LeadTimePane(_ref) {
3693
3873
  amount = _minutesToParts.value,
3694
3874
  unit = _minutesToParts.unit;
3695
3875
  var path = "".concat(fieldKeys.leadTime, ".value");
3876
+ var _useField = formik.useField(path),
3877
+ _useField2 = _slicedToArray(_useField, 2),
3878
+ _useField2$ = _useField2[1],
3879
+ error = _useField2$.error,
3880
+ touched = _useField2$.touched;
3696
3881
  var update = function update(_ref2) {
3697
3882
  var value = _ref2.value,
3698
3883
  nextUnit = _ref2.unit;
@@ -3701,11 +3886,19 @@ var LeadTimePane = function LeadTimePane(_ref) {
3701
3886
  unit: nextUnit
3702
3887
  }));
3703
3888
  };
3889
+ usePaneValidation(path);
3890
+ react.useEffect(function () {
3891
+ if (rule.leadTime === undefined) return;
3892
+ if (getFieldMeta(path).touched) return;
3893
+ setFieldTouched(path, true, false);
3894
+ // eslint-disable-next-line react-hooks/exhaustive-deps
3895
+ }, [rule.leadTime]);
3704
3896
  return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
3705
3897
  children: [/*#__PURE__*/jsxRuntime.jsx(index.Panel.Header, {
3706
3898
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
3707
3899
  className: "flex flex-col gap-y-1",
3708
3900
  children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
3901
+ "data-testid": "pane-title",
3709
3902
  variant: "h5",
3710
3903
  children: t("neetoRules.builder.leadTimeTitle")
3711
3904
  }), /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
@@ -3716,32 +3909,41 @@ var LeadTimePane = function LeadTimePane(_ref) {
3716
3909
  })
3717
3910
  }), /*#__PURE__*/jsxRuntime.jsx(index.Panel.Body, {
3718
3911
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
3719
- className: "flex items-end gap-x-3",
3720
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
3721
- className: "flex-1",
3722
- children: /*#__PURE__*/jsxRuntime.jsx(NumberStepper, {
3723
- label: t("neetoRules.builder.before"),
3724
- value: amount,
3725
- onChange: function onChange(value) {
3726
- return update({
3727
- value: value === "" ? 0 : value,
3728
- unit: unit
3729
- });
3730
- }
3731
- })
3732
- }), /*#__PURE__*/jsxRuntime.jsx("div", {
3733
- className: "w-32 shrink-0",
3734
- children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Select, {
3735
- isSearchable: false,
3736
- options: LEAD_TIME_UNITS,
3737
- value: unit,
3738
- onChange: function onChange(nextUnit) {
3739
- return update({
3740
- value: amount,
3741
- unit: nextUnit
3742
- });
3743
- }
3744
- })
3912
+ className: "flex flex-col gap-y-1.5",
3913
+ children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
3914
+ variant: "body2",
3915
+ weight: "medium",
3916
+ children: t("neetoRules.builder.before")
3917
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
3918
+ className: "flex items-start gap-x-3",
3919
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
3920
+ className: "flex-1",
3921
+ children: /*#__PURE__*/jsxRuntime.jsx(NumberStepper, {
3922
+ dataTestid: "lead-time",
3923
+ error: touched ? error : "",
3924
+ value: amount,
3925
+ onChange: function onChange(value) {
3926
+ return update({
3927
+ value: value === "" ? 0 : value,
3928
+ unit: unit
3929
+ });
3930
+ }
3931
+ })
3932
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
3933
+ className: "w-32 shrink-0",
3934
+ children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Select, {
3935
+ dataTestid: "lead-time-unit",
3936
+ isSearchable: false,
3937
+ options: LEAD_TIME_UNITS,
3938
+ value: unit,
3939
+ onChange: function onChange(nextUnit) {
3940
+ return update({
3941
+ value: amount,
3942
+ unit: nextUnit
3943
+ });
3944
+ }
3945
+ })
3946
+ })]
3745
3947
  })]
3746
3948
  })
3747
3949
  })]
@@ -3759,6 +3961,7 @@ var NamePane = function NamePane(_ref) {
3759
3961
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
3760
3962
  className: "flex flex-col gap-y-1",
3761
3963
  children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
3964
+ "data-testid": "pane-title",
3762
3965
  variant: "h5",
3763
3966
  children: t("neetoRules.builder.automationName")
3764
3967
  }), /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
@@ -3900,6 +4103,11 @@ var OptionsPane = function OptionsPane(_ref) {
3900
4103
  data: target.data
3901
4104
  });else closePane();
3902
4105
  };
4106
+ var canContinue = cascade && selectedValues.some(Boolean);
4107
+ useHotkeys(keyboardShortcuts.SHORTCUTS["continue"].sequence, handleContinue, {
4108
+ enabled: canContinue,
4109
+ mode: "global"
4110
+ });
3903
4111
  var optionLabel = function optionLabel(option) {
3904
4112
  var Icon = option.icon;
3905
4113
  if (!Icon && !option.disabledReason) return option.label;
@@ -3931,12 +4139,13 @@ var OptionsPane = function OptionsPane(_ref) {
3931
4139
  if (ramda.isEmpty(filtered)) {
3932
4140
  return /*#__PURE__*/jsxRuntime.jsx("div", {
3933
4141
  className: "mb-pane-empty",
4142
+ "data-testid": "pane-no-matches",
3934
4143
  children: t("neetoRules.builder.noMatches")
3935
4144
  });
3936
4145
  }
3937
4146
  if (multi) {
3938
4147
  return /*#__PURE__*/jsxRuntime.jsx("div", {
3939
- className: "flex flex-col",
4148
+ className: "mb-pane-list flex flex-col",
3940
4149
  children: groups.map(function (_ref2) {
3941
4150
  var _ref3 = _slicedToArray(_ref2, 2),
3942
4151
  category = _ref3[0],
@@ -3988,6 +4197,7 @@ var OptionsPane = function OptionsPane(_ref) {
3988
4197
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
3989
4198
  className: "flex w-full flex-col gap-y-2",
3990
4199
  children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
4200
+ "data-testid": "pane-title",
3991
4201
  variant: "h5",
3992
4202
  children: title
3993
4203
  }), /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
@@ -3998,6 +4208,7 @@ var OptionsPane = function OptionsPane(_ref) {
3998
4208
  className: "mb-pane-search",
3999
4209
  ref: searchRef,
4000
4210
  children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Input, {
4211
+ dataTestid: "pane-search",
4001
4212
  placeholder: t("neetoRules.builder.searchPlaceholder"),
4002
4213
  prefix: /*#__PURE__*/jsxRuntime.jsx(Search, {}),
4003
4214
  size: "large",
@@ -4012,7 +4223,8 @@ var OptionsPane = function OptionsPane(_ref) {
4012
4223
  children: [renderBody(), belowContent]
4013
4224
  }), cascade && /*#__PURE__*/jsxRuntime.jsx(index.Panel.Footer, {
4014
4225
  children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Button, {
4015
- disabled: !selectedValues.some(Boolean),
4226
+ "data-testid": "continue-button",
4227
+ disabled: !canContinue,
4016
4228
  label: t("neetoRules.buttons.continue"),
4017
4229
  size: "lg",
4018
4230
  onClick: handleContinue
@@ -4037,8 +4249,8 @@ var RecipientField = function RecipientField(_ref) {
4037
4249
  var fieldError = function fieldError(path) {
4038
4250
  return formik.getIn(touched, path) && formik.getIn(errors, path);
4039
4251
  };
4040
- if (field === "emails") {
4041
- var _path = "".concat(name, ".emails");
4252
+ if (field === RECIPIENT_STORAGE_FIELDS.emails) {
4253
+ var _path = "".concat(name, ".").concat(RECIPIENT_STORAGE_FIELDS.emails);
4042
4254
  var _current = formik.getIn(values, _path) || [];
4043
4255
  return /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.MultiEmailInput, {
4044
4256
  required: true,
@@ -4060,7 +4272,7 @@ var RecipientField = function RecipientField(_ref) {
4060
4272
  }
4061
4273
  });
4062
4274
  }
4063
- var path = "".concat(name, ".value");
4275
+ var path = "".concat(name, ".").concat(RECIPIENT_STORAGE_FIELDS.value);
4064
4276
  var current = formik.getIn(values, path);
4065
4277
  var options = normalizeOptions(dropdownOptions);
4066
4278
  return /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Select, {
@@ -4104,7 +4316,7 @@ var RecipientPane = function RecipientPane(_ref) {
4104
4316
  });
4105
4317
  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));
4106
4318
  var isSmsToNumbers = (flatOption === null || flatOption === void 0 ? void 0 : flatOption.type) === SMS_TO_NUMBERS;
4107
- var recipientFieldPath = isSmsToNumbers ? "".concat(name, ".phoneNumbers") : "".concat(name, ".emails");
4319
+ var recipientFieldPath = isSmsToNumbers ? "".concat(name, ".").concat(RECIPIENT_STORAGE_FIELDS.phoneNumbers) : "".concat(name, ".").concat(RECIPIENT_STORAGE_FIELDS.emails);
4108
4320
  usePaneValidation(recipientFieldPath);
4109
4321
  react.useEffect(function () {
4110
4322
  var _bodyRef$current;
@@ -4135,7 +4347,7 @@ var RecipientPane = function RecipientPane(_ref) {
4135
4347
  action: action
4136
4348
  })) !== null && _schema$actions$rende !== void 0 ? _schema$actions$rende : builtInRecipientField;
4137
4349
  var phoneField = isSmsToNumbers ? /*#__PURE__*/jsxRuntime.jsx(index.PhoneNumberField, {
4138
- name: "".concat(name, ".phoneNumbers"),
4350
+ name: "".concat(name, ".").concat(RECIPIENT_STORAGE_FIELDS.phoneNumbers),
4139
4351
  phoneNumbers: (_action$metadata = action.metadata) === null || _action$metadata === void 0 ? void 0 : _action$metadata.phoneNumbers
4140
4352
  }) : null;
4141
4353
  var belowField = phoneField || recipientField;
@@ -4171,6 +4383,7 @@ var RecipientPane = function RecipientPane(_ref) {
4171
4383
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
4172
4384
  className: "flex w-full flex-col gap-y-2",
4173
4385
  children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
4386
+ "data-testid": "pane-title",
4174
4387
  variant: "h5",
4175
4388
  children: meta.recipientTitle || t("neetoRules.builder.panes.recipientTitle")
4176
4389
  }), /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
@@ -4217,6 +4430,7 @@ var ConditionValueFields = function ConditionValueFields(_ref) {
4217
4430
  };
4218
4431
  var noMatches = /*#__PURE__*/jsxRuntime.jsx("div", {
4219
4432
  className: "mb-pane-empty",
4433
+ "data-testid": "pane-no-matches",
4220
4434
  children: t("neetoRules.builder.noMatches")
4221
4435
  });
4222
4436
  if (type === CONDITION_VALUE_TYPES.multiSelect && neetoCist.isNotEmpty(enumOptions)) {
@@ -4228,7 +4442,7 @@ var ConditionValueFields = function ConditionValueFields(_ref) {
4228
4442
  setFieldValue(valuesPath, current.includes(value) ? current.filter(neetoCist.isNot(value)) : [].concat(_toConsumableArray(current), [value]));
4229
4443
  };
4230
4444
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
4231
- className: "flex flex-col gap-y-1",
4445
+ className: "mb-pane-list flex flex-col",
4232
4446
  children: [filtered.map(function (option) {
4233
4447
  return /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Checkbox, {
4234
4448
  checked: current.includes(option.value),
@@ -4372,6 +4586,7 @@ var ValuePane = function ValuePane(_ref) {
4372
4586
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
4373
4587
  className: "flex w-full flex-col gap-y-2",
4374
4588
  children: [/*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Typography, {
4589
+ "data-testid": "pane-title",
4375
4590
  variant: "h5",
4376
4591
  children: t("neetoRules.builder.pickValue", {
4377
4592
  field: (field === null || field === void 0 ? void 0 : field.label) || t("neetoRules.builder.valueWord")
@@ -4386,6 +4601,7 @@ var ValuePane = function ValuePane(_ref) {
4386
4601
  className: "mb-pane-search",
4387
4602
  ref: searchRef,
4388
4603
  children: /*#__PURE__*/jsxRuntime.jsx(neetoAtoms.Input, {
4604
+ dataTestid: "pane-search",
4389
4605
  placeholder: t("neetoRules.builder.searchPlaceholder"),
4390
4606
  prefix: /*#__PURE__*/jsxRuntime.jsx(Search, {}),
4391
4607
  size: "large",
@@ -4532,7 +4748,7 @@ var Form = function Form(_ref) {
4532
4748
  data: data,
4533
4749
  customData: customData,
4534
4750
  isNameGenerationDisabled: isNameRequired
4535
- }),
4751
+ }).concat(leadTimeValidationSchema(schema)),
4536
4752
  onSubmit: submitForm,
4537
4753
  children: function children() {
4538
4754
  return /*#__PURE__*/jsxRuntime.jsxs("div", {