@nyaruka/temba-components 0.129.11 → 0.130.0

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 (120) hide show
  1. package/CHANGELOG.md +7 -4
  2. package/demo/components/flow/example.html +5 -1
  3. package/demo/data/flows/sample-flow.json +144 -80
  4. package/dist/temba-components.js +290 -346
  5. package/dist/temba-components.js.map +1 -1
  6. package/out-tsc/src/flow/CanvasNode.js +3 -35
  7. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  8. package/out-tsc/src/flow/NodeEditor.js +44 -11
  9. package/out-tsc/src/flow/NodeEditor.js.map +1 -1
  10. package/out-tsc/src/flow/actions/add_contact_groups.js +1 -1
  11. package/out-tsc/src/flow/actions/add_contact_groups.js.map +1 -1
  12. package/out-tsc/src/flow/actions/add_contact_urn.js +1 -1
  13. package/out-tsc/src/flow/actions/add_contact_urn.js.map +1 -1
  14. package/out-tsc/src/flow/actions/add_input_labels.js +1 -1
  15. package/out-tsc/src/flow/actions/add_input_labels.js.map +1 -1
  16. package/out-tsc/src/flow/actions/remove_contact_groups.js +1 -1
  17. package/out-tsc/src/flow/actions/remove_contact_groups.js.map +1 -1
  18. package/out-tsc/src/flow/actions/send_email.js +9 -0
  19. package/out-tsc/src/flow/actions/send_email.js.map +1 -1
  20. package/out-tsc/src/flow/actions/send_msg.js +7 -8
  21. package/out-tsc/src/flow/actions/send_msg.js.map +1 -1
  22. package/out-tsc/src/flow/actions/set_contact_channel.js +25 -4
  23. package/out-tsc/src/flow/actions/set_contact_channel.js.map +1 -1
  24. package/out-tsc/src/flow/actions/set_contact_field.js +51 -1
  25. package/out-tsc/src/flow/actions/set_contact_field.js.map +1 -1
  26. package/out-tsc/src/flow/actions/set_contact_language.js +70 -2
  27. package/out-tsc/src/flow/actions/set_contact_language.js.map +1 -1
  28. package/out-tsc/src/flow/actions/set_contact_name.js +27 -2
  29. package/out-tsc/src/flow/actions/set_contact_name.js.map +1 -1
  30. package/out-tsc/src/flow/actions/set_contact_status.js +32 -2
  31. package/out-tsc/src/flow/actions/set_contact_status.js.map +1 -1
  32. package/out-tsc/src/flow/actions/set_run_result.js +13 -11
  33. package/out-tsc/src/flow/actions/set_run_result.js.map +1 -1
  34. package/out-tsc/src/flow/actions/split_by_expression_example.js +4 -4
  35. package/out-tsc/src/flow/actions/split_by_expression_example.js.map +1 -1
  36. package/out-tsc/src/flow/forms/index.js +2 -0
  37. package/out-tsc/src/flow/forms/index.js.map +1 -0
  38. package/out-tsc/src/flow/nodes/split_by_random.js +117 -0
  39. package/out-tsc/src/flow/nodes/split_by_random.js.map +1 -1
  40. package/out-tsc/src/flow/nodes/split_by_ticket.js +0 -1
  41. package/out-tsc/src/flow/nodes/split_by_ticket.js.map +1 -1
  42. package/out-tsc/src/flow/nodes/split_by_webhook.js +1 -3
  43. package/out-tsc/src/flow/nodes/split_by_webhook.js.map +1 -1
  44. package/out-tsc/src/flow/types.js.map +1 -1
  45. package/out-tsc/src/form/ArrayEditor.js +9 -25
  46. package/out-tsc/src/form/ArrayEditor.js.map +1 -1
  47. package/out-tsc/src/form/FieldRenderer.js +6 -64
  48. package/out-tsc/src/form/FieldRenderer.js.map +1 -1
  49. package/out-tsc/src/form/select/Select.js +29 -58
  50. package/out-tsc/src/form/select/Select.js.map +1 -1
  51. package/out-tsc/src/utils.js +3 -0
  52. package/out-tsc/src/utils.js.map +1 -1
  53. package/out-tsc/test/nodes/split_by_random.test.js +0 -6
  54. package/out-tsc/test/nodes/split_by_random.test.js.map +1 -1
  55. package/out-tsc/test/temba-field-renderer.test.js +6 -3
  56. package/out-tsc/test/temba-field-renderer.test.js.map +1 -1
  57. package/out-tsc/test/utils.test.js +18 -0
  58. package/out-tsc/test/utils.test.js.map +1 -1
  59. package/package.json +1 -1
  60. package/screenshots/truth/actions/add_contact_groups/editor/descriptive-group-names.png +0 -0
  61. package/screenshots/truth/actions/add_contact_groups/editor/long-group-names.png +0 -0
  62. package/screenshots/truth/actions/add_contact_groups/editor/many-groups.png +0 -0
  63. package/screenshots/truth/actions/add_contact_groups/editor/multiple-groups.png +0 -0
  64. package/screenshots/truth/actions/add_contact_groups/editor/single-group.png +0 -0
  65. package/screenshots/truth/actions/add_contact_groups/render/descriptive-group-names.png +0 -0
  66. package/screenshots/truth/actions/add_contact_groups/render/long-group-names.png +0 -0
  67. package/screenshots/truth/actions/add_contact_groups/render/many-groups.png +0 -0
  68. package/screenshots/truth/actions/add_contact_groups/render/multiple-groups.png +0 -0
  69. package/screenshots/truth/actions/add_contact_groups/render/single-group.png +0 -0
  70. package/screenshots/truth/actions/remove_contact_groups/editor/cleanup-groups.png +0 -0
  71. package/screenshots/truth/actions/remove_contact_groups/editor/long-descriptive-group-names.png +0 -0
  72. package/screenshots/truth/actions/remove_contact_groups/editor/many-groups.png +0 -0
  73. package/screenshots/truth/actions/remove_contact_groups/editor/multiple-groups.png +0 -0
  74. package/screenshots/truth/actions/remove_contact_groups/editor/remove-from-all-groups.png +0 -0
  75. package/screenshots/truth/actions/remove_contact_groups/editor/single-group.png +0 -0
  76. package/screenshots/truth/actions/remove_contact_groups/render/cleanup-groups.png +0 -0
  77. package/screenshots/truth/actions/remove_contact_groups/render/long-descriptive-group-names.png +0 -0
  78. package/screenshots/truth/actions/remove_contact_groups/render/many-groups.png +0 -0
  79. package/screenshots/truth/actions/remove_contact_groups/render/multiple-groups.png +0 -0
  80. package/screenshots/truth/actions/remove_contact_groups/render/remove-from-all-groups.png +0 -0
  81. package/screenshots/truth/actions/remove_contact_groups/render/single-group.png +0 -0
  82. package/screenshots/truth/editor/set_contact_language.png +0 -0
  83. package/screenshots/truth/editor/set_contact_name.png +0 -0
  84. package/screenshots/truth/editor/set_run_result.png +0 -0
  85. package/screenshots/truth/nodes/split_by_random/editor/ab-test-multiple-variants.png +0 -0
  86. package/screenshots/truth/nodes/split_by_random/editor/sampling-split.png +0 -0
  87. package/screenshots/truth/nodes/split_by_random/editor/three-way-split.png +0 -0
  88. package/screenshots/truth/nodes/split_by_random/editor/two-bucket-split.png +0 -0
  89. package/src/flow/CanvasNode.ts +2 -39
  90. package/src/flow/NodeEditor.ts +54 -13
  91. package/src/flow/actions/add_contact_groups.ts +1 -1
  92. package/src/flow/actions/add_contact_urn.ts +1 -1
  93. package/src/flow/actions/add_input_labels.ts +1 -1
  94. package/src/flow/actions/remove_contact_groups.ts +1 -1
  95. package/src/flow/actions/send_email.ts +11 -1
  96. package/src/flow/actions/send_msg.ts +20 -11
  97. package/src/flow/actions/set_contact_channel.ts +28 -5
  98. package/src/flow/actions/set_contact_field.ts +56 -2
  99. package/src/flow/actions/set_contact_language.ts +74 -3
  100. package/src/flow/actions/set_contact_name.ts +31 -3
  101. package/src/flow/actions/set_contact_status.ts +36 -3
  102. package/src/flow/actions/set_run_result.ts +13 -15
  103. package/src/flow/actions/split_by_expression_example.ts +4 -4
  104. package/src/flow/forms/index.ts +1 -0
  105. package/src/flow/nodes/split_by_random.ts +148 -0
  106. package/src/flow/nodes/split_by_ticket.ts +0 -1
  107. package/src/flow/nodes/split_by_webhook.ts +1 -3
  108. package/src/flow/types.ts +2 -1
  109. package/src/form/ArrayEditor.ts +6 -20
  110. package/src/form/FieldRenderer.ts +6 -65
  111. package/src/form/select/Select.ts +34 -66
  112. package/src/store/flow-definition.d.ts +6 -1
  113. package/src/utils.ts +4 -0
  114. package/static/api/fields.json +93 -1208
  115. package/static/api/workspace.json +23 -0
  116. package/test/nodes/split_by_random.test.ts +0 -7
  117. package/test/temba-field-renderer.test.ts +26 -13
  118. package/test/utils.test.ts +20 -0
  119. package/web-dev-server.config.mjs +2 -0
  120. package/web-test-runner.config.mjs +37 -0
@@ -592,6 +592,10 @@ export class Select<T extends SelectOption> extends FieldElement {
592
592
  this.prepareOptionsDefault = this.prepareOptionsDefault.bind(this);
593
593
  this.isMatchDefault = this.isMatchDefault.bind(this);
594
594
  this.handleOrderChanged = this.handleOrderChanged.bind(this);
595
+
596
+ this.createArbitraryOption = (
597
+ this.createArbitraryOption || this.createArbitraryOptionDefault
598
+ ).bind(this);
595
599
  }
596
600
 
597
601
  public prepareOptionsDefault(options: T[]): T[] {
@@ -701,17 +705,6 @@ export class Select<T extends SelectOption> extends FieldElement {
701
705
  );
702
706
  }
703
707
 
704
- public async createOptionPost(payload: any) {
705
- return postJSON(this.endpoint, payload).then((response) => {
706
- if (response.status >= 200 && response.status < 300) {
707
- return {
708
- json: response.json,
709
- payload
710
- };
711
- }
712
- });
713
- }
714
-
715
708
  public updated(changes: Map<string, any>) {
716
709
  super.updated(changes);
717
710
 
@@ -727,60 +720,8 @@ export class Select<T extends SelectOption> extends FieldElement {
727
720
 
728
721
  if (changes.has('values')) {
729
722
  this.updateInputs();
730
-
731
723
  if (this.hasChanges(changes.get('values'))) {
732
- const materialized = [];
733
-
734
- // see if we need to materialize anything
735
- if (this.allowCreate) {
736
- // arbitrary values need to be posted
737
- const arbitraryValues = this.values.filter((value) => {
738
- return (value as any).arbitrary;
739
- });
740
-
741
- for (const value of arbitraryValues) {
742
- if ((value as any).arbitrary) {
743
- materialized.push(this.createOptionPost(value));
744
- }
745
- }
746
-
747
- // update our created values
748
- Promise.all(materialized).then((responses) => {
749
- for (const response of responses) {
750
- if (response) {
751
- // find the value that matches our payload
752
- const original = arbitraryValues.find((value) => {
753
- return value === response.payload;
754
- }) as any;
755
-
756
- if (original) {
757
- // remove our arbitrary flag
758
- delete original.arbitrary;
759
-
760
- // add in the new values from our respones.json
761
- if (response.json) {
762
- for (const key in response.json) {
763
- original[key] = response.json[key];
764
- }
765
- }
766
- }
767
- }
768
- }
769
-
770
- // remove any arbitrary values
771
- for (let i = this.values.length - 1; i >= 0; i--) {
772
- if ((this.values[i] as any).arbitrary) {
773
- this.values.splice(i, 1);
774
- }
775
- }
776
-
777
- // reset our cache
778
- this.cacheKey = new Date().getTime().toString();
779
- this.fireEvent('change');
780
- });
781
- } else {
782
- this.fireEvent('change');
783
- }
724
+ this.fireEvent('change');
784
725
  }
785
726
  }
786
727
 
@@ -955,19 +896,31 @@ export class Select<T extends SelectOption> extends FieldElement {
955
896
  }
956
897
 
957
898
  const selected = event.detail.selected;
899
+
958
900
  // check if we should post it
959
- if (selected.post && this.endpoint) {
901
+ if (selected.arbitrary && this.allowCreate && this.endpoint) {
902
+ this.resolving = true;
960
903
  postJSON(this.endpoint, selected).then((response) => {
961
904
  if (response.status >= 200 && response.status < 300) {
962
905
  this.setSelectedOption(response.json);
963
906
  this.lruCache = lru(20, 60000);
907
+ this.errors = [];
964
908
  } else {
965
- // TODO: find a way to share inline errors
909
+ this.setSelectedOption(selected);
910
+ setTimeout(() => {
911
+ this.errors = [
912
+ 'There was an error creating "' +
913
+ this.getNameInternal(selected) +
914
+ '"'
915
+ ];
916
+ }, 0);
966
917
  this.blur();
967
918
  }
919
+ this.resolving = false;
968
920
  });
969
921
  } else {
970
922
  this.setSelectedOption(selected);
923
+ this.errors = [];
971
924
  }
972
925
  }
973
926
 
@@ -1009,6 +962,21 @@ export class Select<T extends SelectOption> extends FieldElement {
1009
962
  public handleRemoveSelection(selectionToRemove: any): void {
1010
963
  this.removeValue(selectionToRemove);
1011
964
  this.visibleOptions = [];
965
+ this.errors = [];
966
+
967
+ // if we allow create, double check our values
968
+ if (this.allowCreate) {
969
+ const arbitrary = this.values.find((v) => v.arbitrary);
970
+ if (arbitrary) {
971
+ setTimeout(() => {
972
+ this.errors = [
973
+ 'There was an error creating "' +
974
+ this.getNameInternal(arbitrary) +
975
+ '"'
976
+ ];
977
+ }, 0);
978
+ }
979
+ }
1012
980
  }
1013
981
 
1014
982
  private createArbitraryOptionDefault(input: string, _options: any[]): any {
@@ -68,6 +68,11 @@ export interface NamedObject {
68
68
  name: string;
69
69
  }
70
70
 
71
+ export interface FieldReference {
72
+ key: string;
73
+ name: string;
74
+ }
75
+
71
76
  export interface Group extends NamedObject {
72
77
  status?: string;
73
78
  system?: boolean;
@@ -111,7 +116,7 @@ export interface RemoveFromGroup extends Action {
111
116
  }
112
117
 
113
118
  export interface SetContactField extends Action {
114
- field: NamedObject;
119
+ field: FieldReference;
115
120
  value: string;
116
121
  }
117
122
 
package/src/utils.ts CHANGED
@@ -1124,3 +1124,7 @@ export const createMultiCategoryRouter = (
1124
1124
  exits: exits
1125
1125
  };
1126
1126
  };
1127
+
1128
+ export const titleCase = (str: string) => {
1129
+ return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
1130
+ };