@botonic/plugin-flow-builder 0.25.0-alpha.9 → 0.25.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 (173) hide show
  1. package/lib/cjs/action/index.js +5 -3
  2. package/lib/cjs/action/index.js.map +1 -1
  3. package/lib/cjs/action/knowledge-bases.js +4 -2
  4. package/lib/cjs/action/knowledge-bases.js.map +1 -1
  5. package/lib/cjs/api.d.ts +6 -2
  6. package/lib/cjs/api.js +35 -7
  7. package/lib/cjs/api.js.map +1 -1
  8. package/lib/cjs/constants.d.ts +3 -1
  9. package/lib/cjs/constants.js +4 -2
  10. package/lib/cjs/constants.js.map +1 -1
  11. package/lib/cjs/content-fields/flow-handoff.js +1 -1
  12. package/lib/cjs/content-fields/flow-handoff.js.map +1 -1
  13. package/lib/cjs/content-fields/flow-text.d.ts +4 -2
  14. package/lib/cjs/content-fields/flow-text.js +17 -10
  15. package/lib/cjs/content-fields/flow-text.js.map +1 -1
  16. package/lib/cjs/content-fields/hubtype-fields/common.d.ts +1 -0
  17. package/lib/cjs/content-fields/hubtype-fields/index.d.ts +1 -0
  18. package/lib/cjs/content-fields/hubtype-fields/index.js +1 -0
  19. package/lib/cjs/content-fields/hubtype-fields/index.js.map +1 -1
  20. package/lib/cjs/content-fields/hubtype-fields/node-types.d.ts +1 -0
  21. package/lib/cjs/content-fields/hubtype-fields/node-types.js +1 -0
  22. package/lib/cjs/content-fields/hubtype-fields/node-types.js.map +1 -1
  23. package/lib/cjs/content-fields/hubtype-fields/nodes.d.ts +2 -1
  24. package/lib/cjs/content-fields/hubtype-fields/smart-intent.d.ts +11 -0
  25. package/lib/cjs/content-fields/hubtype-fields/smart-intent.js +3 -0
  26. package/lib/cjs/content-fields/hubtype-fields/smart-intent.js.map +1 -0
  27. package/lib/cjs/content-fields/whatsapp-button-list/flow-whatsapp-button-list-row.d.ts +2 -1
  28. package/lib/cjs/content-fields/whatsapp-button-list/flow-whatsapp-button-list-row.js +2 -3
  29. package/lib/cjs/content-fields/whatsapp-button-list/flow-whatsapp-button-list-row.js.map +1 -1
  30. package/lib/cjs/content-fields/whatsapp-button-list/flow-whatsapp-button-list-section.d.ts +2 -1
  31. package/lib/cjs/content-fields/whatsapp-button-list/flow-whatsapp-button-list-section.js +2 -2
  32. package/lib/cjs/content-fields/whatsapp-button-list/flow-whatsapp-button-list-section.js.map +1 -1
  33. package/lib/cjs/content-fields/whatsapp-button-list/flow-whatsapp-button-list.d.ts +2 -1
  34. package/lib/cjs/content-fields/whatsapp-button-list/flow-whatsapp-button-list.js +2 -2
  35. package/lib/cjs/content-fields/whatsapp-button-list/flow-whatsapp-button-list.js.map +1 -1
  36. package/lib/cjs/functions/conditional-bot-variable.d.ts +8 -0
  37. package/lib/cjs/functions/conditional-bot-variable.js +11 -0
  38. package/lib/cjs/functions/conditional-bot-variable.js.map +1 -0
  39. package/lib/cjs/functions/conditional-country.d.ts +7 -0
  40. package/lib/cjs/functions/conditional-country.js +9 -0
  41. package/lib/cjs/functions/conditional-country.js.map +1 -0
  42. package/lib/cjs/functions/conditional-provider.js +1 -3
  43. package/lib/cjs/functions/conditional-provider.js.map +1 -1
  44. package/lib/cjs/functions/index.d.ts +4 -0
  45. package/lib/cjs/functions/index.js +4 -0
  46. package/lib/cjs/functions/index.js.map +1 -1
  47. package/lib/cjs/index.d.ts +3 -2
  48. package/lib/cjs/index.js +8 -4
  49. package/lib/cjs/index.js.map +1 -1
  50. package/lib/cjs/{action/tracking.js → tracking.js} +1 -1
  51. package/lib/cjs/tracking.js.map +1 -0
  52. package/lib/cjs/types.d.ts +1 -1
  53. package/lib/cjs/user-input/index.d.ts +4 -0
  54. package/lib/cjs/{action/user-input.js → user-input/index.js} +8 -4
  55. package/lib/cjs/user-input/index.js.map +1 -0
  56. package/lib/cjs/{action → user-input}/intent.js +1 -1
  57. package/lib/cjs/user-input/intent.js.map +1 -0
  58. package/lib/cjs/{action → user-input}/keyword.js +1 -1
  59. package/lib/cjs/user-input/keyword.js.map +1 -0
  60. package/lib/cjs/user-input/smart-intent.d.ts +4 -0
  61. package/lib/cjs/user-input/smart-intent.js +40 -0
  62. package/lib/cjs/user-input/smart-intent.js.map +1 -0
  63. package/lib/cjs/utils.d.ts +2 -0
  64. package/lib/cjs/utils.js +18 -1
  65. package/lib/cjs/utils.js.map +1 -1
  66. package/lib/esm/action/index.js +5 -3
  67. package/lib/esm/action/index.js.map +1 -1
  68. package/lib/esm/action/knowledge-bases.js +4 -2
  69. package/lib/esm/action/knowledge-bases.js.map +1 -1
  70. package/lib/esm/api.d.ts +6 -2
  71. package/lib/esm/api.js +36 -8
  72. package/lib/esm/api.js.map +1 -1
  73. package/lib/esm/constants.d.ts +3 -1
  74. package/lib/esm/constants.js +3 -1
  75. package/lib/esm/constants.js.map +1 -1
  76. package/lib/esm/content-fields/flow-handoff.js +1 -1
  77. package/lib/esm/content-fields/flow-handoff.js.map +1 -1
  78. package/lib/esm/content-fields/flow-text.d.ts +4 -2
  79. package/lib/esm/content-fields/flow-text.js +18 -11
  80. package/lib/esm/content-fields/flow-text.js.map +1 -1
  81. package/lib/esm/content-fields/hubtype-fields/common.d.ts +1 -0
  82. package/lib/esm/content-fields/hubtype-fields/index.d.ts +1 -0
  83. package/lib/esm/content-fields/hubtype-fields/index.js +1 -0
  84. package/lib/esm/content-fields/hubtype-fields/index.js.map +1 -1
  85. package/lib/esm/content-fields/hubtype-fields/node-types.d.ts +1 -0
  86. package/lib/esm/content-fields/hubtype-fields/node-types.js +1 -0
  87. package/lib/esm/content-fields/hubtype-fields/node-types.js.map +1 -1
  88. package/lib/esm/content-fields/hubtype-fields/nodes.d.ts +2 -1
  89. package/lib/esm/content-fields/hubtype-fields/smart-intent.d.ts +11 -0
  90. package/lib/esm/content-fields/hubtype-fields/smart-intent.js +2 -0
  91. package/lib/esm/content-fields/hubtype-fields/smart-intent.js.map +1 -0
  92. package/lib/esm/content-fields/whatsapp-button-list/flow-whatsapp-button-list-row.d.ts +2 -1
  93. package/lib/esm/content-fields/whatsapp-button-list/flow-whatsapp-button-list-row.js +2 -3
  94. package/lib/esm/content-fields/whatsapp-button-list/flow-whatsapp-button-list-row.js.map +1 -1
  95. package/lib/esm/content-fields/whatsapp-button-list/flow-whatsapp-button-list-section.d.ts +2 -1
  96. package/lib/esm/content-fields/whatsapp-button-list/flow-whatsapp-button-list-section.js +2 -2
  97. package/lib/esm/content-fields/whatsapp-button-list/flow-whatsapp-button-list-section.js.map +1 -1
  98. package/lib/esm/content-fields/whatsapp-button-list/flow-whatsapp-button-list.d.ts +2 -1
  99. package/lib/esm/content-fields/whatsapp-button-list/flow-whatsapp-button-list.js +2 -2
  100. package/lib/esm/content-fields/whatsapp-button-list/flow-whatsapp-button-list.js.map +1 -1
  101. package/lib/esm/functions/conditional-bot-variable.d.ts +8 -0
  102. package/lib/esm/functions/conditional-bot-variable.js +7 -0
  103. package/lib/esm/functions/conditional-bot-variable.js.map +1 -0
  104. package/lib/esm/functions/conditional-country.d.ts +7 -0
  105. package/lib/esm/functions/conditional-country.js +5 -0
  106. package/lib/esm/functions/conditional-country.js.map +1 -0
  107. package/lib/esm/functions/conditional-provider.js +1 -3
  108. package/lib/esm/functions/conditional-provider.js.map +1 -1
  109. package/lib/esm/functions/index.d.ts +4 -0
  110. package/lib/esm/functions/index.js +4 -0
  111. package/lib/esm/functions/index.js.map +1 -1
  112. package/lib/esm/index.d.ts +3 -2
  113. package/lib/esm/index.js +8 -4
  114. package/lib/esm/index.js.map +1 -1
  115. package/lib/esm/{action/tracking.js → tracking.js} +1 -1
  116. package/lib/esm/tracking.js.map +1 -0
  117. package/lib/esm/types.d.ts +1 -1
  118. package/lib/esm/user-input/index.d.ts +4 -0
  119. package/lib/esm/{action/user-input.js → user-input/index.js} +8 -4
  120. package/lib/esm/user-input/index.js.map +1 -0
  121. package/lib/esm/{action → user-input}/intent.js +1 -1
  122. package/lib/esm/user-input/intent.js.map +1 -0
  123. package/lib/esm/{action → user-input}/keyword.js +1 -1
  124. package/lib/esm/user-input/keyword.js.map +1 -0
  125. package/lib/esm/user-input/smart-intent.d.ts +4 -0
  126. package/lib/esm/user-input/smart-intent.js +36 -0
  127. package/lib/esm/user-input/smart-intent.js.map +1 -0
  128. package/lib/esm/utils.d.ts +2 -0
  129. package/lib/esm/utils.js +16 -0
  130. package/lib/esm/utils.js.map +1 -1
  131. package/package.json +4 -4
  132. package/src/action/index.tsx +5 -3
  133. package/src/action/knowledge-bases.ts +4 -3
  134. package/src/api.ts +51 -8
  135. package/src/constants.ts +3 -1
  136. package/src/content-fields/flow-handoff.tsx +1 -1
  137. package/src/content-fields/flow-text.tsx +23 -17
  138. package/src/content-fields/hubtype-fields/common.ts +1 -0
  139. package/src/content-fields/hubtype-fields/index.ts +1 -0
  140. package/src/content-fields/hubtype-fields/node-types.ts +1 -0
  141. package/src/content-fields/hubtype-fields/nodes.ts +2 -0
  142. package/src/content-fields/hubtype-fields/smart-intent.ts +12 -0
  143. package/src/content-fields/whatsapp-button-list/flow-whatsapp-button-list-row.tsx +4 -2
  144. package/src/content-fields/whatsapp-button-list/flow-whatsapp-button-list-section.tsx +4 -2
  145. package/src/content-fields/whatsapp-button-list/flow-whatsapp-button-list.tsx +4 -2
  146. package/src/functions/conditional-bot-variable.ts +18 -0
  147. package/src/functions/conditional-country.ts +14 -0
  148. package/src/functions/conditional-provider.ts +1 -2
  149. package/src/functions/index.ts +4 -0
  150. package/src/index.ts +15 -6
  151. package/src/{action/tracking.ts → tracking.ts} +1 -1
  152. package/src/types.ts +1 -1
  153. package/src/{action/user-input.ts → user-input/index.ts} +13 -5
  154. package/src/{action → user-input}/intent.ts +1 -1
  155. package/src/{action → user-input}/keyword.ts +1 -1
  156. package/src/user-input/smart-intent.ts +42 -0
  157. package/src/utils.ts +26 -0
  158. package/lib/cjs/action/intent.js.map +0 -1
  159. package/lib/cjs/action/keyword.js.map +0 -1
  160. package/lib/cjs/action/tracking.js.map +0 -1
  161. package/lib/cjs/action/user-input.d.ts +0 -4
  162. package/lib/cjs/action/user-input.js.map +0 -1
  163. package/lib/esm/action/intent.js.map +0 -1
  164. package/lib/esm/action/keyword.js.map +0 -1
  165. package/lib/esm/action/tracking.js.map +0 -1
  166. package/lib/esm/action/user-input.d.ts +0 -4
  167. package/lib/esm/action/user-input.js.map +0 -1
  168. /package/lib/cjs/{action/tracking.d.ts → tracking.d.ts} +0 -0
  169. /package/lib/cjs/{action → user-input}/intent.d.ts +0 -0
  170. /package/lib/cjs/{action → user-input}/keyword.d.ts +0 -0
  171. /package/lib/esm/{action/tracking.d.ts → tracking.d.ts} +0 -0
  172. /package/lib/esm/{action → user-input}/intent.d.ts +0 -0
  173. /package/lib/esm/{action → user-input}/keyword.d.ts +0 -0
@@ -0,0 +1,36 @@
1
+ import { __awaiter } from "tslib";
2
+ import axios from 'axios';
3
+ export function getSmartIntentNodeByInput(cmsApi, request) {
4
+ return __awaiter(this, void 0, void 0, function* () {
5
+ const smartIntentNodes = cmsApi.getSmartIntentNodes();
6
+ const intentsInferenceParams = smartIntentNodes.map(smartIntentNode => {
7
+ return {
8
+ name: smartIntentNode.content.title,
9
+ definition: smartIntentNode.content.description,
10
+ };
11
+ });
12
+ intentsInferenceParams.push({
13
+ name: 'Other',
14
+ definition: 'The text does not belong to any other intent.',
15
+ });
16
+ try {
17
+ const response = yield axios({
18
+ method: 'POST',
19
+ url: `${process.env.HUBTYPE_API_URL}/external/v1/ai/smart_intents/inference/`,
20
+ headers: {
21
+ Authorization: `Bearer ${request.session._access_token}`,
22
+ 'Content-Type': 'application/json',
23
+ },
24
+ data: { text: request.input.data, intents: intentsInferenceParams },
25
+ timeout: 10000,
26
+ });
27
+ console.log({ response });
28
+ return smartIntentNodes.find(smartIntentNode => smartIntentNode.content.title === response.data.intent_name);
29
+ }
30
+ catch (e) {
31
+ console.error(e);
32
+ return undefined;
33
+ }
34
+ });
35
+ }
36
+ //# sourceMappingURL=smart-intent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smart-intent.js","sourceRoot":"","sources":["../../../src/user-input/smart-intent.ts"],"names":[],"mappings":";AACA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,MAAM,UAAgB,yBAAyB,CAC7C,MAAsB,EACtB,OAAsB;;QAEtB,MAAM,gBAAgB,GAAG,MAAM,CAAC,mBAAmB,EAAE,CAAA;QACrD,MAAM,sBAAsB,GAAG,gBAAgB,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE;YACpE,OAAO;gBACL,IAAI,EAAE,eAAe,CAAC,OAAO,CAAC,KAAK;gBACnC,UAAU,EAAE,eAAe,CAAC,OAAO,CAAC,WAAW;aAChD,CAAA;QACH,CAAC,CAAC,CAAA;QACF,sBAAsB,CAAC,IAAI,CAAC;YAC1B,IAAI,EAAE,OAAO;YACb,UAAU,EAAE,+CAA+C;SAC5D,CAAC,CAAA;QACF,IAAI;YACF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC;gBAC3B,MAAM,EAAE,MAAM;gBACd,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,0CAA0C;gBAC7E,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,OAAO,CAAC,OAAO,CAAC,aAAa,EAAE;oBACxD,cAAc,EAAE,kBAAkB;iBACnC;gBACD,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,sBAAsB,EAAE;gBACnE,OAAO,EAAE,KAAK;aACf,CAAC,CAAA;YACF,OAAO,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAA;YACzB,OAAO,gBAAgB,CAAC,IAAI,CAC1B,eAAe,CAAC,EAAE,CAChB,eAAe,CAAC,OAAO,CAAC,KAAK,KAAK,QAAQ,CAAC,IAAI,CAAC,WAAW,CAC9D,CAAA;SACF;QAAC,OAAO,CAAC,EAAE;YACV,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YAChB,OAAO,SAAS,CAAA;SACjB;IACH,CAAC;CAAA"}
@@ -1,3 +1,5 @@
1
1
  import { Session } from '@botonic/core';
2
+ import { ActionRequest } from '@botonic/react';
2
3
  import { BotonicPluginFlowBuilderOptions } from './types';
3
4
  export declare function resolveGetAccessToken(options: BotonicPluginFlowBuilderOptions): (session: Session) => string;
5
+ export declare function getValueFromKeyPath(request: ActionRequest, keyPath: string): any;
package/lib/esm/utils.js CHANGED
@@ -15,4 +15,20 @@ export function resolveGetAccessToken(options) {
15
15
  throw new Error('No method defined for getting access token');
16
16
  }
17
17
  }
18
+ export function getValueFromKeyPath(request, keyPath) {
19
+ if (keyPath.startsWith('input') || keyPath.startsWith('session')) {
20
+ return keyPath
21
+ .split('.')
22
+ .reduce((object, key) => resolveObjectKey(object, key), request);
23
+ }
24
+ return keyPath
25
+ .split('.')
26
+ .reduce((object, key) => resolveObjectKey(object, key), request.session.user.extra_data);
27
+ }
28
+ function resolveObjectKey(object, key) {
29
+ if (object && object[key] !== undefined) {
30
+ return object[key];
31
+ }
32
+ return undefined;
33
+ }
18
34
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmC,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAE7E,SAAS,yBAAyB,CAAC,OAAgB;IACjD,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;QAC1B,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;KACpD;IACD,OAAO,OAAO,CAAC,aAAa,CAAA;AAC9B,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,OAAwC;IAExC,QAAQ,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE;QAC5B,KAAK,kBAAkB,CAAC,UAAU;YAChC,OAAO,yBAAyB,CAAA;QAClC,KAAK,kBAAkB,CAAC,WAAW;YACjC,OAAO,OAAO,CAAC,cAAc,CAAA;QAC/B;YACE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;KAChE;AACH,CAAC"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAmC,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAE7E,SAAS,yBAAyB,CAAC,OAAgB;IACjD,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE;QAC1B,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;KACpD;IACD,OAAO,OAAO,CAAC,aAAa,CAAA;AAC9B,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,OAAwC;IAExC,QAAQ,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE;QAC5B,KAAK,kBAAkB,CAAC,UAAU;YAChC,OAAO,yBAAyB,CAAA;QAClC,KAAK,kBAAkB,CAAC,WAAW;YACjC,OAAO,OAAO,CAAC,cAAc,CAAA;QAC/B;YACE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;KAChE;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,OAAsB,EACtB,OAAe;IAEf,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE;QAChE,OAAO,OAAO;aACX,KAAK,CAAC,GAAG,CAAC;aACV,MAAM,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,CAAA;KACnE;IAED,OAAO,OAAO;SACX,KAAK,CAAC,GAAG,CAAC;SACV,MAAM,CACL,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,CAAC,EAC9C,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAChC,CAAA;AACL,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAW,EAAE,GAAW;IAChD,IAAI,MAAM,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE;QACvC,OAAO,MAAM,CAAC,GAAG,CAAC,CAAA;KACnB;IACD,OAAO,SAAS,CAAA;AAClB,CAAC"}
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "@botonic/plugin-flow-builder",
3
- "version": "0.25.0-alpha.9",
3
+ "version": "0.25.0",
4
4
  "main": "./lib/cjs/index.js",
5
5
  "module": "./lib/esm/index.js",
6
6
  "description": "Use Flow Builder to show your contents",
7
7
  "scripts": {
8
8
  "build": "rm -rf lib && ../../node_modules/.bin/tsc -p tsconfig.json && ../../node_modules/.bin/tsc -p tsconfig.esm.json",
9
9
  "build:watch": "npm run build -- --watch",
10
- "test": "echo \"Error: no test specified\" && exit 1",
10
+ "test": "echo Skipping tests...",
11
11
  "cloc": "../../scripts/qa/cloc-package.sh .",
12
12
  "prepublishOnly": "rm -rf lib && npm i && npm run build",
13
13
  "lint": "npm run lint_core -- --fix",
14
14
  "lint_core": "../../node_modules/.bin/eslint_d --cache --quiet 'src/**/*.ts*'"
15
15
  },
16
16
  "dependencies": {
17
- "@botonic/react": "0.25.0-alpha.6",
18
- "axios": "^1.6.7",
17
+ "@botonic/react": "^0.25.0",
18
+ "axios": "^1.6.8",
19
19
  "uuid": "^9.0.1"
20
20
  },
21
21
  "repository": {
@@ -6,7 +6,7 @@ import { FlowContent, FlowHandoff } from '../content-fields'
6
6
  import { HtNodeWithContent } from '../content-fields/hubtype-fields'
7
7
  import { getFlowBuilderPlugin } from '../helpers'
8
8
  import { createNodeFromKnowledgeBase } from './knowledge-bases'
9
- import { EventName, trackEvent } from './tracking'
9
+ import { EventName, trackEvent } from '../tracking'
10
10
 
11
11
  export type FlowBuilderActionProps = {
12
12
  contents: FlowContent[]
@@ -38,16 +38,18 @@ export class FlowBuilderAction extends React.Component<FlowBuilderActionProps> {
38
38
 
39
39
  render(): JSX.Element | JSX.Element[] {
40
40
  const { contents } = this.props
41
- return contents.map(content => content.toBotonic(content.id))
41
+ const request = this.context
42
+ return contents.map(content => content.toBotonic(content.id, request))
42
43
  }
43
44
  }
44
45
 
45
46
  export class FlowBuilderMultichannelAction extends FlowBuilderAction {
46
47
  render(): JSX.Element | JSX.Element[] {
47
48
  const { contents } = this.props
49
+ const request = this.context
48
50
  return (
49
51
  <Multichannel text={{ buttonsAsText: false }}>
50
- {contents.map(content => content.toBotonic(content.id))}
52
+ {contents.map(content => content.toBotonic(content.id, request))}
51
53
  </Multichannel>
52
54
  )
53
55
  }
@@ -9,7 +9,7 @@ import {
9
9
  HtTextNode,
10
10
  } from '../content-fields/hubtype-fields'
11
11
  import { getFlowBuilderPlugin } from '../helpers'
12
- import { EventName, trackEvent } from './tracking'
12
+ import { EventName, trackEvent } from '../tracking'
13
13
 
14
14
  export async function createNodeFromKnowledgeBase(
15
15
  cmsApi: FlowBuilderApi,
@@ -17,6 +17,7 @@ export async function createNodeFromKnowledgeBase(
17
17
  ): Promise<HtNodeWithContent | undefined> {
18
18
  const flowBuilderPlugin = getFlowBuilderPlugin(request.plugins)
19
19
  const locale = flowBuilderPlugin.getLocale(request.session)
20
+ const resolvedLocale = cmsApi.getResolvedLocale(locale)
20
21
  const knowledgeBaseConfig = cmsApi.getKnowledgeBaseConfig()
21
22
 
22
23
  if (
@@ -26,7 +27,6 @@ export async function createNodeFromKnowledgeBase(
26
27
  try {
27
28
  const knowledgeBaseResponse =
28
29
  await flowBuilderPlugin.getKnowledgeBaseResponse(request)
29
-
30
30
  if (knowledgeBaseResponse.hasKnowledge) {
31
31
  await trackEvent(request, EventName.botAiKnowledgeBase, {
32
32
  answer: knowledgeBaseResponse.answer,
@@ -41,12 +41,13 @@ export async function createNodeFromKnowledgeBase(
41
41
  text: [
42
42
  {
43
43
  message: knowledgeBaseResponse.answer,
44
- locale,
44
+ locale: resolvedLocale,
45
45
  },
46
46
  ],
47
47
  buttons_style: undefined,
48
48
  buttons: [],
49
49
  },
50
+ flow_id: 'randomUUID', // TODO: Add flow_id consequentially with HtBaseNode changes
50
51
  id: uuid(),
51
52
  code: 'knowledge-response',
52
53
  meta: {
package/src/api.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import { Input, PluginPreRequest } from '@botonic/core'
2
2
  import axios from 'axios'
3
3
 
4
- import { SEPARATOR } from './constants'
4
+ import { REG_EXP_PATTERN, SEPARATOR } from './constants'
5
5
  import {
6
6
  HtBotActionNode,
7
7
  HtFallbackNode,
8
8
  HtFlowBuilderData,
9
+ HtGoToFlow,
9
10
  HtIntentNode,
10
11
  HtKeywordNode,
11
12
  HtNodeComponent,
@@ -15,6 +16,7 @@ import {
15
16
  HtNodeWithoutContentType,
16
17
  HtPayloadNode,
17
18
  } from './content-fields/hubtype-fields'
19
+ import { HtSmartIntentNode } from './content-fields/hubtype-fields/smart-intent'
18
20
  import { FlowBuilderApiOptions } from './types'
19
21
 
20
22
  export class FlowBuilderApi {
@@ -56,11 +58,11 @@ export class FlowBuilderApi {
56
58
  return node as T
57
59
  }
58
60
 
59
- getNodeByCode(code: string): HtNodeComponent {
61
+ getNodeByContentID(contentID: string): HtNodeComponent {
60
62
  const content = this.flow.nodes.find(node =>
61
- 'code' in node ? node.code === code : false
63
+ 'code' in node ? node.code === contentID : false
62
64
  )
63
- if (!content) throw Error(`Node with code: '${code}' not found`)
65
+ if (!content) throw Error(`Node with contentID: '${contentID}' not found`)
64
66
  return content
65
67
  }
66
68
 
@@ -124,6 +126,12 @@ export class FlowBuilderApi {
124
126
  return undefined
125
127
  }
126
128
 
129
+ getSmartIntentNodes(): HtSmartIntentNode[] {
130
+ return this.flow.nodes.filter(
131
+ node => node.type === HtNodeWithContentType.SMART_INTENT
132
+ ) as HtSmartIntentNode[]
133
+ }
134
+
127
135
  private nodeContainsIntent(
128
136
  node: HtIntentNode,
129
137
  intent: string,
@@ -169,13 +177,30 @@ export class FlowBuilderApi {
169
177
  locale: string
170
178
  ): boolean {
171
179
  const result = node.content.keywords.find(
172
- i => i.locale === locale && this.containsAnyKeywords(input, i.values)
180
+ keywords =>
181
+ keywords.locale === locale &&
182
+ this.inputMatchesAnyKeyword(input, keywords.values)
173
183
  )
174
184
  return Boolean(result)
175
185
  }
176
186
 
177
- private containsAnyKeywords(input: string, keywords: string[]): boolean {
178
- return keywords.some(keyword => input.includes(keyword))
187
+ private inputMatchesAnyKeyword(input: string, keywords: string[]): boolean {
188
+ return keywords.some(keyword => {
189
+ const regExpMatchArray = keyword.match(REG_EXP_PATTERN)
190
+ if (regExpMatchArray) {
191
+ return this.resolveKeywordAsRegExp(regExpMatchArray, input)
192
+ }
193
+ return input.includes(keyword)
194
+ })
195
+ }
196
+
197
+ private resolveKeywordAsRegExp(
198
+ regExpMatchArray: RegExpMatchArray,
199
+ input: string
200
+ ) {
201
+ const [, pattern, flags] = regExpMatchArray
202
+ const keywordAsRegExp = new RegExp(pattern, flags)
203
+ return input.match(keywordAsRegExp)
179
204
  }
180
205
 
181
206
  getPayload(target?: HtNodeLink): string | undefined {
@@ -197,13 +222,31 @@ export class FlowBuilderApi {
197
222
  const customParams = JSON.parse(
198
223
  botActionNode.content.payload_params || '{}'
199
224
  )
225
+
226
+ const followUpContentID = this.getFollowUpContentID(
227
+ botActionNode.follow_up?.id
228
+ )
229
+
200
230
  const payloadJson = JSON.stringify({
201
231
  ...customParams,
202
- followUpId: botActionNode.follow_up?.id,
232
+ followUpContentID,
203
233
  })
204
234
  return `${payloadNode.content.payload}${SEPARATOR}${payloadJson}`
205
235
  }
206
236
 
237
+ private getFollowUpContentID(id?: string): string | undefined {
238
+ const followUpNode = id
239
+ ? this.getNodeById<HtNodeWithContent | HtGoToFlow>(id)
240
+ : undefined
241
+
242
+ if (followUpNode?.type === HtNodeWithoutContentType.GO_TO_FLOW) {
243
+ return this.getNodeById<HtNodeWithContent>(followUpNode?.content.flow_id)
244
+ .code
245
+ } else {
246
+ return followUpNode?.code
247
+ }
248
+ }
249
+
207
250
  getResolvedLocale(locale: string): string {
208
251
  if (this.flow.locales.find(flowLocale => flowLocale === locale)) {
209
252
  return locale
package/src/constants.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  export const SEPARATOR = '|'
2
2
  export const SOURCE_INFO_SEPARATOR = `${SEPARATOR}source_`
3
- export const VARIABLE_REGEX = /{([^}]+)}/g
3
+ export const VARIABLE_PATTERN = /{([^}]+)}/g
4
+ export const ACCESS_TOKEN_VARIABLE_KEY = '_access_token'
5
+ export const REG_EXP_PATTERN = /^\/(.*)\/([gimyus]*)$/
@@ -2,7 +2,7 @@ import { HandOffBuilder } from '@botonic/core'
2
2
  import { ActionRequest, WebchatSettings } from '@botonic/react'
3
3
  import React from 'react'
4
4
 
5
- import { EventName, trackEvent } from '../action/tracking'
5
+ import { EventName, trackEvent } from '../tracking'
6
6
  import { FlowBuilderApi } from '../api'
7
7
  import { getQueueAvailability } from '../functions/conditional-queue-status'
8
8
  import { ContentFieldsBase } from './content-fields-base'
@@ -1,8 +1,9 @@
1
- import { Text } from '@botonic/react'
1
+ import { ActionRequest, Text } from '@botonic/react'
2
2
  import React from 'react'
3
3
 
4
4
  import { FlowBuilderApi } from '../api'
5
- import { VARIABLE_REGEX } from '../constants'
5
+ import { ACCESS_TOKEN_VARIABLE_KEY, VARIABLE_PATTERN } from '../constants'
6
+ import { getValueFromKeyPath } from '../utils'
6
7
  import { ContentFieldsBase } from './content-fields-base'
7
8
  import { FlowButton } from './flow-button'
8
9
  import { HtButtonStyle, HtTextNode } from './hubtype-fields'
@@ -21,38 +22,43 @@ export class FlowText extends ContentFieldsBase {
21
22
  const newText = new FlowText(cmsText.id)
22
23
  newText.code = cmsText.code
23
24
  newText.buttonStyle = cmsText.content.buttons_style || HtButtonStyle.BUTTON
24
- newText.text = this.replaceVariables(
25
- this.getTextByLocale(locale, cmsText.content.text),
26
- cmsApi.request.session.user.extra_data
27
- )
25
+ newText.text = this.getTextByLocale(locale, cmsText.content.text)
28
26
  newText.buttons = cmsText.content.buttons.map(button =>
29
27
  FlowButton.fromHubtypeCMS(button, locale, cmsApi)
30
28
  )
31
29
  return newText
32
30
  }
33
31
 
34
- static replaceVariables(
35
- text: string,
36
- extraData?: Record<string, any>
37
- ): string {
38
- const matches = text.match(VARIABLE_REGEX)
32
+ static replaceVariables(text: string, request: ActionRequest): string {
33
+ const matches = text.match(VARIABLE_PATTERN)
39
34
 
40
35
  let replacedText = text
41
- if (matches && extraData) {
36
+ if (matches && request) {
42
37
  matches.forEach(match => {
43
- const variable = match.slice(1, -1)
44
- const value = extraData[variable] ?? match
45
- replacedText = replacedText.replace(match, value)
38
+ const keyPath = match.slice(1, -1)
39
+ const botVariable = keyPath.endsWith(ACCESS_TOKEN_VARIABLE_KEY)
40
+ ? match
41
+ : getValueFromKeyPath(request, keyPath)
42
+ replacedText = replacedText.replace(
43
+ match,
44
+ this.isValidType(botVariable) ? botVariable : match
45
+ )
46
46
  })
47
47
  }
48
48
 
49
49
  return replacedText
50
50
  }
51
51
 
52
- toBotonic(id: string): JSX.Element {
52
+ private static isValidType(botVariable: any): boolean {
53
+ const validTypes = ['boolean', 'string', 'number']
54
+ return validTypes.includes(typeof botVariable)
55
+ }
56
+
57
+ toBotonic(id: string, request: ActionRequest): JSX.Element {
58
+ const replacedText = FlowText.replaceVariables(this.text, request)
53
59
  return (
54
60
  <Text key={id}>
55
- {this.text}
61
+ {replacedText}
56
62
  {this.buttons.map((button, buttonIndex) =>
57
63
  button.renderButton(buttonIndex, this.buttonStyle)
58
64
  )}
@@ -31,6 +31,7 @@ export interface HtBaseNode {
31
31
  }
32
32
  follow_up?: HtNodeLink
33
33
  target?: HtNodeLink
34
+ flow_id: string // TODO: Review if this field is necessary in all HtBaseNode
34
35
  }
35
36
 
36
37
  export interface HtTextLocale {
@@ -12,6 +12,7 @@ export * from './keyword'
12
12
  export * from './node-types'
13
13
  export * from './nodes'
14
14
  export * from './payload'
15
+ export * from './smart-intent'
15
16
  export * from './text'
16
17
  export * from './url'
17
18
  export * from './video'
@@ -5,6 +5,7 @@ export enum HtNodeWithContentType {
5
5
  TEXT = 'text',
6
6
  KEYWORD = 'keyword',
7
7
  INTENT = 'intent',
8
+ SMART_INTENT = 'smart-intent',
8
9
  FUNCTION = 'function',
9
10
  FALLBACK = 'fallback',
10
11
  VIDEO = 'video',
@@ -8,6 +8,7 @@ import { HtImageNode } from './image'
8
8
  import { HtIntentNode } from './intent'
9
9
  import { HtKeywordNode } from './keyword'
10
10
  import { HtPayloadNode } from './payload'
11
+ import { HtSmartIntentNode } from './smart-intent'
11
12
  import { HtTextNode } from './text'
12
13
  import { HtUrlNode } from './url'
13
14
  import { HtVideoNode } from './video'
@@ -24,6 +25,7 @@ export type HtNodeWithContent =
24
25
  | HtFunctionNode
25
26
  | HtFallbackNode
26
27
  | HtWhatsappButtonListNode
28
+ | HtSmartIntentNode
27
29
 
28
30
  export type HtNodeWithoutContent =
29
31
  | HtUrlNode
@@ -0,0 +1,12 @@
1
+ import { HtBaseNode } from './common'
2
+ import { HtNodeWithContentType } from './node-types'
3
+
4
+ interface SmartIntent {
5
+ title: string
6
+ description: string
7
+ }
8
+
9
+ export interface HtSmartIntentNode extends HtBaseNode {
10
+ type: HtNodeWithContentType.SMART_INTENT
11
+ content: SmartIntent
12
+ }
@@ -1,5 +1,6 @@
1
1
  import { WhatsappButtonListRowProps } from '@botonic/react'
2
2
 
3
+ import { FlowBuilderApi } from '../../api'
3
4
  import { SOURCE_INFO_SEPARATOR } from '../../constants'
4
5
  import { ContentFieldsBase } from '../content-fields-base'
5
6
  import { HtWhatsappButtonListRow } from '../hubtype-fields'
@@ -11,12 +12,13 @@ export class FlowWhatsappButtonListRow extends ContentFieldsBase {
11
12
 
12
13
  static fromHubtypeCMS(
13
14
  component: HtWhatsappButtonListRow,
14
- locale: string
15
+ locale: string,
16
+ cmsApi: FlowBuilderApi
15
17
  ): FlowWhatsappButtonListRow {
16
18
  const newRow = new FlowWhatsappButtonListRow(component.id)
17
19
  newRow.title = this.getTextByLocale(locale, component.text)
18
20
  newRow.description = this.getTextByLocale(locale, component.description)
19
- newRow.targetId = component.target?.id
21
+ newRow.targetId = cmsApi.getPayload(component.target)
20
22
  return newRow
21
23
  }
22
24
 
@@ -3,6 +3,7 @@ import {
3
3
  WhatsappButtonListSectionProps,
4
4
  } from '@botonic/react'
5
5
 
6
+ import { FlowBuilderApi } from '../../api'
6
7
  import { HtWhatsappButtonListSection } from '../hubtype-fields'
7
8
  import { ContentFieldsBase } from './../content-fields-base'
8
9
  import { FlowWhatsappButtonListRow } from './flow-whatsapp-button-list-row'
@@ -13,12 +14,13 @@ export class FlowWhatsappButtonListSection extends ContentFieldsBase {
13
14
 
14
15
  static fromHubtypeCMS(
15
16
  component: HtWhatsappButtonListSection,
16
- locale: string
17
+ locale: string,
18
+ cmsApi: FlowBuilderApi
17
19
  ): FlowWhatsappButtonListSection {
18
20
  const newButton = new FlowWhatsappButtonListSection(component.id)
19
21
  newButton.title = this.getTextByLocale(locale, component.title)
20
22
  newButton.rows = component.rows.map(row =>
21
- FlowWhatsappButtonListRow.fromHubtypeCMS(row, locale)
23
+ FlowWhatsappButtonListRow.fromHubtypeCMS(row, locale, cmsApi)
22
24
  )
23
25
  return newButton
24
26
  }
@@ -1,6 +1,7 @@
1
1
  import { WhatsappButtonList } from '@botonic/react'
2
2
  import React from 'react'
3
3
 
4
+ import { FlowBuilderApi } from '../../api'
4
5
  import { HtWhatsappButtonListNode } from '../hubtype-fields'
5
6
  import { ContentFieldsBase } from './../content-fields-base'
6
7
  import { FlowWhatsappButtonListSection } from './flow-whatsapp-button-list-section'
@@ -13,7 +14,8 @@ export class FlowWhatsappButtonList extends ContentFieldsBase {
13
14
 
14
15
  static fromHubtypeCMS(
15
16
  component: HtWhatsappButtonListNode,
16
- locale: string
17
+ locale: string,
18
+ cmsApi: FlowBuilderApi
17
19
  ): FlowWhatsappButtonList {
18
20
  const newWhatsappButtonList = new FlowWhatsappButtonList(component.id)
19
21
  newWhatsappButtonList.code = component.code
@@ -26,7 +28,7 @@ export class FlowWhatsappButtonList extends ContentFieldsBase {
26
28
  component.content.button_text
27
29
  )
28
30
  newWhatsappButtonList.sections = component.content.sections.map(section =>
29
- FlowWhatsappButtonListSection.fromHubtypeCMS(section, locale)
31
+ FlowWhatsappButtonListSection.fromHubtypeCMS(section, locale, cmsApi)
30
32
  )
31
33
  return newWhatsappButtonList
32
34
  }
@@ -0,0 +1,18 @@
1
+ import { ActionRequest } from '@botonic/react'
2
+
3
+ import { getValueFromKeyPath } from '../utils'
4
+
5
+ interface ConditionalCountryArgs {
6
+ request: ActionRequest
7
+ results: string[]
8
+ keyPath: string
9
+ }
10
+
11
+ export function conditionalBotVariable({
12
+ request,
13
+ results,
14
+ keyPath,
15
+ }: ConditionalCountryArgs): string {
16
+ const botVariable = getValueFromKeyPath(request, keyPath)
17
+ return results.find(result => result === botVariable) ?? 'default'
18
+ }
@@ -0,0 +1,14 @@
1
+ import { ActionRequest } from '@botonic/react'
2
+
3
+ interface ConditionalCountryArgs {
4
+ request: ActionRequest
5
+ results: string[]
6
+ }
7
+
8
+ export function conditionalCountry({
9
+ request,
10
+ results,
11
+ }: ConditionalCountryArgs): string {
12
+ const country = request.session.user.extra_data.country
13
+ return results.find(result => result === country) || 'default'
14
+ }
@@ -10,6 +10,5 @@ export function conditionalProvider({
10
10
  results,
11
11
  }: ConditionalProviderArgs): string {
12
12
  const provider = request.session.user.provider
13
- if (results.includes(provider)) return provider
14
- return 'default'
13
+ return results.find(result => result === provider) || 'default'
15
14
  }
@@ -1,3 +1,5 @@
1
+ import { conditionalBotVariable } from './conditional-bot-variable'
2
+ import { conditionalCountry } from './conditional-country'
1
3
  import { conditionalProvider } from './conditional-provider'
2
4
  import { conditionalQueueStatus } from './conditional-queue-status'
3
5
 
@@ -5,4 +7,6 @@ export const DEFAULT_FUNCTIONS = {
5
7
  // TODO: Rename api action name
6
8
  'check-queue-status': conditionalQueueStatus,
7
9
  'get-channel-type': conditionalProvider,
10
+ 'check-country': conditionalCountry,
11
+ 'check-bot-variable': conditionalBotVariable,
8
12
  }
package/src/index.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Plugin, PluginPreRequest, Session } from '@botonic/core'
2
2
  import { ActionRequest } from '@botonic/react'
3
3
 
4
- import { getNodeByUserInput } from './action/user-input'
5
4
  import { FlowBuilderApi } from './api'
6
5
  import { SEPARATOR, SOURCE_INFO_SEPARATOR } from './constants'
7
6
  import {
@@ -28,6 +27,7 @@ import {
28
27
  KnowledgeBaseResponse,
29
28
  PayloadParamsBase,
30
29
  } from './types'
30
+ import { getNodeByUserInput } from './user-input'
31
31
  import { resolveGetAccessToken } from './utils'
32
32
 
33
33
  export default class BotonicPluginFlowBuilder implements Plugin {
@@ -90,16 +90,21 @@ export default class BotonicPluginFlowBuilder implements Plugin {
90
90
  }
91
91
  }
92
92
 
93
- async getContentsByCode(
94
- code: string,
93
+ async getContentsByContentID(
94
+ contentID: string,
95
95
  locale: string,
96
96
  prevContents?: FlowContent[]
97
97
  ): Promise<FlowContent[]> {
98
- const node = this.cmsApi.getNodeByCode(code) as HtNodeWithContent
98
+ const node = this.cmsApi.getNodeByContentID(contentID) as HtNodeWithContent
99
99
  return await this.getContentsByNode(node, locale, prevContents)
100
100
  }
101
101
 
102
- async getContentsById(
102
+ getUUIDByContentID(contentID: string): string {
103
+ const node = this.cmsApi.getNodeByContentID(contentID)
104
+ return node.id
105
+ }
106
+
107
+ private async getContentsById(
103
108
  id: string,
104
109
  locale: string,
105
110
  prevContents?: FlowContent[]
@@ -153,7 +158,11 @@ export default class BotonicPluginFlowBuilder implements Plugin {
153
158
  case HtNodeWithContentType.VIDEO:
154
159
  return FlowVideo.fromHubtypeCMS(hubtypeContent, locale)
155
160
  case HtNodeWithContentType.WHATSAPP_BUTTON_LIST:
156
- return FlowWhatsappButtonList.fromHubtypeCMS(hubtypeContent, locale)
161
+ return FlowWhatsappButtonList.fromHubtypeCMS(
162
+ hubtypeContent,
163
+ locale,
164
+ this.cmsApi
165
+ )
157
166
  case HtNodeWithContentType.HANDOFF:
158
167
  return FlowHandoff.fromHubtypeCMS(hubtypeContent, locale, this.cmsApi)
159
168
  default:
@@ -1,6 +1,6 @@
1
1
  import { ActionRequest } from '@botonic/react'
2
2
 
3
- import { getFlowBuilderPlugin } from '../helpers'
3
+ import { getFlowBuilderPlugin } from './helpers'
4
4
 
5
5
  export async function trackEvent(
6
6
  request: ActionRequest,
package/src/types.ts CHANGED
@@ -41,5 +41,5 @@ export interface KnowledgeBaseResponse {
41
41
  }
42
42
 
43
43
  export interface PayloadParamsBase {
44
- followUpId?: string
44
+ followUpContentID?: string
45
45
  }