@botonic/plugin-flow-builder 0.21.0-alpha.9 → 0.21.2
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.
- package/lib/cjs/action.js +23 -32
- package/lib/cjs/action.js.map +1 -1
- package/lib/cjs/content-fields/content-fields-base.d.ts +3 -2
- package/lib/cjs/content-fields/content-fields-base.js +6 -1
- package/lib/cjs/content-fields/content-fields-base.js.map +1 -1
- package/lib/cjs/content-fields/flow-button.d.ts +1 -1
- package/lib/cjs/content-fields/flow-button.js +7 -5
- package/lib/cjs/content-fields/flow-button.js.map +1 -1
- package/lib/cjs/content-fields/flow-carousel.d.ts +1 -1
- package/lib/cjs/content-fields/flow-carousel.js +4 -5
- package/lib/cjs/content-fields/flow-carousel.js.map +1 -1
- package/lib/cjs/content-fields/flow-image.d.ts +1 -1
- package/lib/cjs/content-fields/flow-image.js +2 -2
- package/lib/cjs/content-fields/flow-image.js.map +1 -1
- package/lib/cjs/content-fields/flow-text.d.ts +1 -1
- package/lib/cjs/content-fields/flow-text.js +3 -3
- package/lib/cjs/content-fields/flow-text.js.map +1 -1
- package/lib/cjs/content-fields/flow-video.d.ts +8 -0
- package/lib/cjs/content-fields/flow-video.js +26 -0
- package/lib/cjs/content-fields/flow-video.js.map +1 -0
- package/lib/cjs/content-fields/index.d.ts +1 -0
- package/lib/cjs/content-fields/index.js +3 -1
- package/lib/cjs/content-fields/index.js.map +1 -1
- package/lib/cjs/content-fields/types.d.ts +2 -1
- package/lib/cjs/flow-builder-models.d.ts +26 -4
- package/lib/cjs/flow-builder-models.js +2 -0
- package/lib/cjs/flow-builder-models.js.map +1 -1
- package/lib/cjs/handoff.d.ts +2 -1
- package/lib/cjs/handoff.js +21 -14
- package/lib/cjs/handoff.js.map +1 -1
- package/lib/cjs/helpers.d.ts +6 -0
- package/lib/cjs/helpers.js +27 -0
- package/lib/cjs/helpers.js.map +1 -0
- package/lib/cjs/index.d.ts +10 -11
- package/lib/cjs/index.js +45 -42
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/types.d.ts +13 -0
- package/lib/cjs/types.js +9 -0
- package/lib/cjs/types.js.map +1 -0
- package/lib/cjs/utils.d.ts +3 -0
- package/lib/cjs/utils.js +19 -1
- package/lib/cjs/utils.js.map +1 -1
- package/lib/esm/action.js +24 -33
- package/lib/esm/action.js.map +1 -1
- package/lib/esm/content-fields/content-fields-base.d.ts +3 -2
- package/lib/esm/content-fields/content-fields-base.js +6 -1
- package/lib/esm/content-fields/content-fields-base.js.map +1 -1
- package/lib/esm/content-fields/flow-button.d.ts +1 -1
- package/lib/esm/content-fields/flow-button.js +7 -5
- package/lib/esm/content-fields/flow-button.js.map +1 -1
- package/lib/esm/content-fields/flow-carousel.d.ts +1 -1
- package/lib/esm/content-fields/flow-carousel.js +4 -5
- package/lib/esm/content-fields/flow-carousel.js.map +1 -1
- package/lib/esm/content-fields/flow-image.d.ts +1 -1
- package/lib/esm/content-fields/flow-image.js +2 -2
- package/lib/esm/content-fields/flow-image.js.map +1 -1
- package/lib/esm/content-fields/flow-text.d.ts +1 -1
- package/lib/esm/content-fields/flow-text.js +3 -3
- package/lib/esm/content-fields/flow-text.js.map +1 -1
- package/lib/esm/content-fields/flow-video.d.ts +8 -0
- package/lib/esm/content-fields/flow-video.js +21 -0
- package/lib/esm/content-fields/flow-video.js.map +1 -0
- package/lib/esm/content-fields/index.d.ts +1 -0
- package/lib/esm/content-fields/index.js +1 -0
- package/lib/esm/content-fields/index.js.map +1 -1
- package/lib/esm/content-fields/types.d.ts +2 -1
- package/lib/esm/flow-builder-models.d.ts +26 -4
- package/lib/esm/flow-builder-models.js +2 -0
- package/lib/esm/flow-builder-models.js.map +1 -1
- package/lib/esm/handoff.d.ts +2 -1
- package/lib/esm/handoff.js +21 -14
- package/lib/esm/handoff.js.map +1 -1
- package/lib/esm/helpers.d.ts +6 -0
- package/lib/esm/helpers.js +22 -0
- package/lib/esm/helpers.js.map +1 -0
- package/lib/esm/index.d.ts +10 -11
- package/lib/esm/index.js +46 -43
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/types.d.ts +13 -0
- package/lib/esm/types.js +6 -0
- package/lib/esm/types.js.map +1 -0
- package/lib/esm/utils.d.ts +3 -0
- package/lib/esm/utils.js +17 -0
- package/lib/esm/utils.js.map +1 -1
- package/package.json +3 -3
- package/src/action.tsx +29 -35
- package/src/content-fields/content-fields-base.ts +12 -3
- package/src/content-fields/flow-button.tsx +6 -4
- package/src/content-fields/flow-carousel.tsx +4 -5
- package/src/content-fields/flow-image.tsx +2 -2
- package/src/content-fields/flow-text.tsx +4 -4
- package/src/content-fields/flow-video.tsx +22 -0
- package/src/content-fields/index.ts +1 -0
- package/src/content-fields/types.ts +2 -1
- package/src/flow-builder-models.ts +30 -2
- package/src/handoff.ts +25 -16
- package/src/helpers.ts +39 -0
- package/src/index.ts +61 -61
- package/src/types.ts +16 -0
- package/src/utils.ts +24 -0
|
@@ -18,11 +18,11 @@ export class FlowCarousel extends ContentFieldsBase {
|
|
|
18
18
|
return newCarousel
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
toBotonic(
|
|
21
|
+
toBotonic(id: string): JSX.Element {
|
|
22
22
|
return (
|
|
23
|
-
<Carousel key={
|
|
24
|
-
{this.elements.map(
|
|
25
|
-
<Element key={
|
|
23
|
+
<Carousel key={id}>
|
|
24
|
+
{this.elements.map(element => (
|
|
25
|
+
<Element key={`${id}-${element.id}`}>
|
|
26
26
|
<Pic src={element.image} />
|
|
27
27
|
<Title style=''>{element.title}</Title>
|
|
28
28
|
<Subtitle style=''>{element.subtitle}</Subtitle>
|
|
@@ -33,7 +33,6 @@ export class FlowCarousel extends ContentFieldsBase {
|
|
|
33
33
|
>
|
|
34
34
|
{element.buttons?.text}
|
|
35
35
|
</Button>
|
|
36
|
-
,
|
|
37
36
|
</Element>
|
|
38
37
|
))}
|
|
39
38
|
</Carousel>
|
|
@@ -15,7 +15,7 @@ export class FlowImage extends ContentFieldsBase {
|
|
|
15
15
|
return newImage
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
toBotonic(
|
|
19
|
-
return <Image src={this.src}
|
|
18
|
+
toBotonic(id: string): JSX.Element {
|
|
19
|
+
return <Image key={id} src={this.src} />
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -22,12 +22,12 @@ export class FlowText extends ContentFieldsBase {
|
|
|
22
22
|
return newText
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
toBotonic(
|
|
25
|
+
toBotonic(id: string): JSX.Element {
|
|
26
26
|
return (
|
|
27
|
-
<Text key={
|
|
27
|
+
<Text key={id}>
|
|
28
28
|
{this.text}
|
|
29
|
-
{this.buttons.map(
|
|
30
|
-
button.renderButton(
|
|
29
|
+
{this.buttons.map(button =>
|
|
30
|
+
button.renderButton(button.id, this.buttonStyle)
|
|
31
31
|
)}
|
|
32
32
|
</Text>
|
|
33
33
|
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Video } from '@botonic/react'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import { VideoNode } from '../flow-builder-models'
|
|
5
|
+
import { ContentFieldsBase } from './content-fields-base'
|
|
6
|
+
|
|
7
|
+
export class FlowVideo extends ContentFieldsBase {
|
|
8
|
+
public src = ''
|
|
9
|
+
public code = ''
|
|
10
|
+
|
|
11
|
+
static fromHubtypeCMS(component: VideoNode, locale: string): FlowVideo {
|
|
12
|
+
const newVideo = new FlowVideo(component.id)
|
|
13
|
+
newVideo.code = component.code
|
|
14
|
+
newVideo.src = this.getVideoByLocale(locale, component.content.video)
|
|
15
|
+
return newVideo
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
toBotonic(id: string): JSX.Element {
|
|
19
|
+
// @ts-ignore
|
|
20
|
+
return <Video key={id} src={this.src} />
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FlowCarousel } from './flow-carousel'
|
|
2
2
|
import { FlowImage } from './flow-image'
|
|
3
3
|
import { FlowText } from './flow-text'
|
|
4
|
+
import { FlowVideo } from './flow-video'
|
|
4
5
|
|
|
5
|
-
export type FlowContent = FlowText | FlowImage | FlowCarousel
|
|
6
|
+
export type FlowContent = FlowText | FlowImage | FlowCarousel | FlowVideo
|
|
@@ -18,6 +18,8 @@ export enum NodeType {
|
|
|
18
18
|
URL = 'url',
|
|
19
19
|
PAYLOAD = 'payload',
|
|
20
20
|
FUNCTION = 'function',
|
|
21
|
+
FALLBACK = 'fallback',
|
|
22
|
+
VIDEO = 'video',
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
export interface BaseNode {
|
|
@@ -67,8 +69,8 @@ export interface Button {
|
|
|
67
69
|
text: TextLocale[]
|
|
68
70
|
target?: NodeLink
|
|
69
71
|
hidden: string
|
|
70
|
-
url?: UrlLocale
|
|
71
|
-
payload?: PayloadLocale
|
|
72
|
+
url?: UrlLocale[]
|
|
73
|
+
payload?: PayloadLocale[]
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
export interface TextNodeContent {
|
|
@@ -207,6 +209,30 @@ export interface FunctionNode extends Node {
|
|
|
207
209
|
content: FunctionNodeContent
|
|
208
210
|
}
|
|
209
211
|
|
|
212
|
+
export interface FallbackNodeContent {
|
|
213
|
+
first_message: NodeLink
|
|
214
|
+
second_message: NodeLink
|
|
215
|
+
}
|
|
216
|
+
export interface FallbackNode extends Node {
|
|
217
|
+
type: NodeType.FALLBACK
|
|
218
|
+
content: FallbackNodeContent
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export interface VideoLocale {
|
|
222
|
+
url: string
|
|
223
|
+
is_embedded?: boolean
|
|
224
|
+
locale: string
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export interface VideoNodeContent {
|
|
228
|
+
video: VideoLocale[]
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export interface VideoNode extends Node {
|
|
232
|
+
type: NodeType.VIDEO
|
|
233
|
+
content: VideoNodeContent
|
|
234
|
+
}
|
|
235
|
+
|
|
210
236
|
export type NodeComponent =
|
|
211
237
|
| TextNode
|
|
212
238
|
| ImageNode
|
|
@@ -218,3 +244,5 @@ export type NodeComponent =
|
|
|
218
244
|
| StartNode
|
|
219
245
|
| PayloadNode
|
|
220
246
|
| FunctionNode
|
|
247
|
+
| FallbackNode
|
|
248
|
+
| VideoNode
|
package/src/handoff.ts
CHANGED
|
@@ -1,28 +1,37 @@
|
|
|
1
1
|
import { HandOffBuilder } from '@botonic/core'
|
|
2
2
|
import { ActionRequest } from '@botonic/react'
|
|
3
3
|
|
|
4
|
+
import { HandoffNode } from './flow-builder-models'
|
|
5
|
+
import { getFlowBuilderPlugin } from './helpers'
|
|
6
|
+
|
|
4
7
|
export async function doHandoff(
|
|
5
8
|
request: ActionRequest,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
agentEmail?: string
|
|
9
|
+
locale: string,
|
|
10
|
+
handoffNode: HandoffNode
|
|
9
11
|
): Promise<void> {
|
|
12
|
+
const flowBuilderPlugin = getFlowBuilderPlugin(request.plugins)
|
|
13
|
+
const handoffTargetNode = await flowBuilderPlugin.getHandoffContent(
|
|
14
|
+
handoffNode.target?.id
|
|
15
|
+
)
|
|
10
16
|
// @ts-ignore
|
|
11
|
-
const
|
|
12
|
-
const
|
|
17
|
+
const handOffBuilder = new HandOffBuilder(request.session) // handOffBuilder.withQueue(handoffNode.content.queue)
|
|
18
|
+
const handoffQueues = handoffNode.content.queue
|
|
19
|
+
const queueFound = handoffQueues.find(q => q.locale === locale)
|
|
20
|
+
if (queueFound) handOffBuilder.withQueue(queueFound.id)
|
|
21
|
+
// TODO: Retrieve params from FlowBuilder
|
|
22
|
+
// const handoffParams = {
|
|
23
|
+
// agentEmail: 'test@gmail.com',
|
|
24
|
+
// note: 'This is a note that will be attached to the case as a reminder',
|
|
25
|
+
// }
|
|
13
26
|
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
27
|
+
// if (handoffParams.note) {
|
|
28
|
+
// handOffBuilder.withNote(handoffParams.note)
|
|
29
|
+
// }
|
|
17
30
|
|
|
18
|
-
if (
|
|
19
|
-
|
|
20
|
-
}
|
|
31
|
+
// if (handoffParams.agentEmail) {
|
|
32
|
+
// handOffBuilder.withAgentEmail(handoffParams.agentEmail)
|
|
33
|
+
// }
|
|
21
34
|
|
|
22
|
-
|
|
23
|
-
handOffBuilder.withAgentEmail(agentEmail)
|
|
24
|
-
}
|
|
25
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
26
|
-
handOffBuilder.withOnFinishPayload(handoffContent.target?.id!)
|
|
35
|
+
handOffBuilder.withOnFinishPayload(handoffTargetNode.id)
|
|
27
36
|
await handOffBuilder.handOff()
|
|
28
37
|
}
|
package/src/helpers.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Plugin } from '@botonic/core'
|
|
2
|
+
import BotonicPluginFlowBuilder from './index'
|
|
3
|
+
import { NodeComponent } from './flow-builder-models'
|
|
4
|
+
|
|
5
|
+
const FLOW_BUILDER_PLUGIN_NAME = 'BotonicPluginFlowBuilder'
|
|
6
|
+
|
|
7
|
+
export function getFlowBuilderPlugin(plugins: {
|
|
8
|
+
[id: string]: Plugin
|
|
9
|
+
}): BotonicPluginFlowBuilder {
|
|
10
|
+
const flowBuilderPlugin = Object.values(plugins).find(
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
plugin => plugin.name === FLOW_BUILDER_PLUGIN_NAME
|
|
13
|
+
) as BotonicPluginFlowBuilder
|
|
14
|
+
if (!flowBuilderPlugin)
|
|
15
|
+
throw new Error(
|
|
16
|
+
`You must include '@botonic/plugin-flow-builder' in your plugins file.`
|
|
17
|
+
)
|
|
18
|
+
return flowBuilderPlugin
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function updateButtonUrls(
|
|
22
|
+
hubtypeContent: any,
|
|
23
|
+
contentKey: string,
|
|
24
|
+
getContentFn: any
|
|
25
|
+
): Promise<void> {
|
|
26
|
+
if (hubtypeContent.content[contentKey]) {
|
|
27
|
+
for (const i in hubtypeContent.content[contentKey]) {
|
|
28
|
+
const button = hubtypeContent.content[contentKey][i].button
|
|
29
|
+
if (button.url) {
|
|
30
|
+
for (const j in button.url) {
|
|
31
|
+
button.url[j] = {
|
|
32
|
+
...button.url[j],
|
|
33
|
+
...(await getContentFn(button.url[j].id)),
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -12,8 +12,10 @@ import {
|
|
|
12
12
|
FlowContent,
|
|
13
13
|
FlowImage,
|
|
14
14
|
FlowText,
|
|
15
|
+
FlowVideo,
|
|
15
16
|
} from './content-fields'
|
|
16
17
|
import {
|
|
18
|
+
FallbackNode,
|
|
17
19
|
FlowBuilderData,
|
|
18
20
|
FunctionNode,
|
|
19
21
|
HandoffNode,
|
|
@@ -24,42 +26,37 @@ import {
|
|
|
24
26
|
StartNode,
|
|
25
27
|
} from './flow-builder-models'
|
|
26
28
|
import { DEFAULT_FUNCTIONS } from './functions'
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
flow?: FlowBuilderData
|
|
31
|
-
customFunctions?: Record<any, any>
|
|
32
|
-
getLocale: (session: Session) => string
|
|
33
|
-
getAccessToken: () => string
|
|
34
|
-
}
|
|
29
|
+
import { BotonicPluginFlowBuilderOptions } from './types'
|
|
30
|
+
import { resolveGetAccessToken } from './utils'
|
|
31
|
+
import { updateButtonUrls } from './helpers'
|
|
35
32
|
|
|
36
33
|
export default class BotonicPluginFlowBuilder implements Plugin {
|
|
37
34
|
private flowUrl: string
|
|
38
35
|
private flow: Promise<FlowBuilderData> | FlowBuilderData
|
|
39
36
|
private functions: Record<any, any>
|
|
40
37
|
private currentRequest: PluginPreRequest
|
|
41
|
-
private getAccessToken: () => string
|
|
38
|
+
private getAccessToken: (session: Session) => string
|
|
42
39
|
public getLocale: (session: Session) => string
|
|
43
40
|
|
|
44
41
|
constructor(readonly options: BotonicPluginFlowBuilderOptions) {
|
|
45
42
|
this.getLocale = options.getLocale
|
|
46
|
-
this.getAccessToken = options
|
|
43
|
+
this.getAccessToken = resolveGetAccessToken(options)
|
|
47
44
|
this.flowUrl = options.flowUrl
|
|
48
|
-
this.flow = options.flow
|
|
45
|
+
if (options.flow) this.flow = options.flow
|
|
49
46
|
const customFunctions = options.customFunctions || {}
|
|
50
47
|
this.functions = { ...DEFAULT_FUNCTIONS, ...customFunctions }
|
|
51
48
|
}
|
|
52
49
|
|
|
53
|
-
async readFlowContent(): Promise<FlowBuilderData> {
|
|
54
|
-
const
|
|
55
|
-
headers: { Authorization: `Bearer ${this.getAccessToken()}` },
|
|
50
|
+
async readFlowContent(session: Session): Promise<FlowBuilderData> {
|
|
51
|
+
const { data } = await axios.get(this.flowUrl, {
|
|
52
|
+
headers: { Authorization: `Bearer ${this.getAccessToken(session)}` },
|
|
56
53
|
})
|
|
57
|
-
return
|
|
54
|
+
return data
|
|
58
55
|
}
|
|
59
56
|
|
|
60
57
|
async pre(request: PluginPreRequest): Promise<void> {
|
|
61
58
|
this.currentRequest = request
|
|
62
|
-
this.flow = this.readFlowContent()
|
|
59
|
+
this.flow = await this.readFlowContent(this.currentRequest.session)
|
|
63
60
|
}
|
|
64
61
|
|
|
65
62
|
async post(_request: PluginPostRequest): Promise<void> {}
|
|
@@ -71,10 +68,12 @@ export default class BotonicPluginFlowBuilder implements Plugin {
|
|
|
71
68
|
return content
|
|
72
69
|
}
|
|
73
70
|
|
|
74
|
-
async getHandoffContent(
|
|
71
|
+
async getHandoffContent(
|
|
72
|
+
handoffTargetId: string | undefined
|
|
73
|
+
): Promise<HandoffNode> {
|
|
75
74
|
const flow = await this.flow
|
|
76
75
|
const content = flow.nodes.find(
|
|
77
|
-
node => node.
|
|
76
|
+
node => node.id === handoffTargetId
|
|
78
77
|
) as HandoffNode
|
|
79
78
|
if (!content) throw Error(`Handoff node not found`)
|
|
80
79
|
return content
|
|
@@ -91,6 +90,8 @@ export default class BotonicPluginFlowBuilder implements Plugin {
|
|
|
91
90
|
return FlowImage.fromHubtypeCMS(hubtypeContent, locale)
|
|
92
91
|
case NodeType.CAROUSEL:
|
|
93
92
|
return FlowCarousel.fromHubtypeCMS(hubtypeContent, locale)
|
|
93
|
+
case NodeType.VIDEO:
|
|
94
|
+
return FlowVideo.fromHubtypeCMS(hubtypeContent, locale)
|
|
94
95
|
default:
|
|
95
96
|
return undefined
|
|
96
97
|
}
|
|
@@ -98,46 +99,35 @@ export default class BotonicPluginFlowBuilder implements Plugin {
|
|
|
98
99
|
|
|
99
100
|
async getStartId(): Promise<string> {
|
|
100
101
|
const flow = await this.flow
|
|
101
|
-
const startNode = flow.nodes.find(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return
|
|
102
|
+
const startNode = flow.nodes.find(
|
|
103
|
+
node => node.type === NodeType.START_UP
|
|
104
|
+
) as StartNode | undefined
|
|
105
|
+
if (!startNode) throw new Error('start-up id must be defined')
|
|
106
|
+
return startNode.target.id
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
async getFallbackId(alternate: boolean): Promise<string> {
|
|
110
|
+
const flow = await this.flow
|
|
111
|
+
const fallbackNode = flow.nodes.find(
|
|
112
|
+
node => node.type === NodeType.FALLBACK
|
|
113
|
+
) as FallbackNode | undefined
|
|
114
|
+
if (!fallbackNode) throw new Error('fallback node must be defined')
|
|
115
|
+
const fallbackFirstMessage = fallbackNode.content.first_message
|
|
116
|
+
const fallbackSecondMessage = fallbackNode.content.second_message
|
|
117
|
+
if (!fallbackSecondMessage) return fallbackFirstMessage.id
|
|
118
|
+
return alternate ? fallbackFirstMessage.id : fallbackSecondMessage.id
|
|
119
|
+
}
|
|
108
120
|
async getContents(
|
|
109
121
|
id: string,
|
|
110
122
|
locale: string,
|
|
111
123
|
prevContents?: FlowContent[]
|
|
112
|
-
): Promise<FlowContent[]> {
|
|
124
|
+
): Promise<{ contents: FlowContent[]; handoffNode: HandoffNode }> {
|
|
113
125
|
const contents = prevContents || []
|
|
114
126
|
const hubtypeContent: any = await this.getContent(id)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
for (const j in button.url) {
|
|
120
|
-
button.url[j] = {
|
|
121
|
-
...button.url[j],
|
|
122
|
-
...(await this.getContent(button.url[j].id)),
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
if (hubtypeContent.content.buttons) {
|
|
129
|
-
for (const i in hubtypeContent.content.buttons) {
|
|
130
|
-
const button = hubtypeContent.content.buttons[i]
|
|
131
|
-
if (button.url) {
|
|
132
|
-
for (const j in button.url) {
|
|
133
|
-
button.url[j] = {
|
|
134
|
-
...button.url[j],
|
|
135
|
-
...(await this.getContent(button.url[j].id)),
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
127
|
+
const isHandoff = hubtypeContent.type === NodeType.HANDOFF
|
|
128
|
+
// TODO: Create function to populate these buttons
|
|
129
|
+
await updateButtonUrls(hubtypeContent, 'elements', this.getContent)
|
|
130
|
+
await updateButtonUrls(hubtypeContent, 'buttons', this.getContent)
|
|
141
131
|
const content = await this.getFlowContent(hubtypeContent, locale)
|
|
142
132
|
if (hubtypeContent.type === NodeType.FUNCTION) {
|
|
143
133
|
const targetId = await this.callFunction(hubtypeContent, locale)
|
|
@@ -151,10 +141,10 @@ export default class BotonicPluginFlowBuilder implements Plugin {
|
|
|
151
141
|
}
|
|
152
142
|
// execute function
|
|
153
143
|
// return this.getContents(function result_mapping target, locale, contents)
|
|
154
|
-
return contents
|
|
144
|
+
return { contents, handoffNode: isHandoff && hubtypeContent }
|
|
155
145
|
}
|
|
156
146
|
|
|
157
|
-
async
|
|
147
|
+
async getPayloadByIntent(
|
|
158
148
|
input: Input,
|
|
159
149
|
locale: string
|
|
160
150
|
): Promise<string | undefined> {
|
|
@@ -163,14 +153,17 @@ export default class BotonicPluginFlowBuilder implements Plugin {
|
|
|
163
153
|
const intents = flow.nodes.filter(
|
|
164
154
|
node => node.type === NodeType.INTENT
|
|
165
155
|
) as IntentNode[]
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
156
|
+
const inputIntent = input.intent
|
|
157
|
+
const inputConfidence = input.confidence
|
|
158
|
+
if (inputIntent) {
|
|
159
|
+
const matchedIntentNode = intents.find(
|
|
160
|
+
node =>
|
|
161
|
+
inputIntent &&
|
|
162
|
+
this.hasIntent(node, inputIntent, locale) &&
|
|
163
|
+
inputConfidence &&
|
|
164
|
+
this.hasMetConfidenceThreshold(node, inputConfidence)
|
|
170
165
|
)
|
|
171
|
-
|
|
172
|
-
return matchedIntents[0].target?.id
|
|
173
|
-
}
|
|
166
|
+
return matchedIntentNode?.target?.id
|
|
174
167
|
}
|
|
175
168
|
} catch (error) {
|
|
176
169
|
console.error('Error getting payload by input: ', error)
|
|
@@ -180,10 +173,17 @@ export default class BotonicPluginFlowBuilder implements Plugin {
|
|
|
180
173
|
}
|
|
181
174
|
|
|
182
175
|
hasIntent(node: IntentNode, intent: string, locale: string): boolean {
|
|
183
|
-
|
|
176
|
+
return node.content.intents.some(
|
|
184
177
|
i => i.locale === locale && i.values.includes(intent)
|
|
185
178
|
)
|
|
186
|
-
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
hasMetConfidenceThreshold(
|
|
182
|
+
node: IntentNode,
|
|
183
|
+
predictedConfidence: number
|
|
184
|
+
): boolean {
|
|
185
|
+
const nodeConfidence = node.content.confidence / 100
|
|
186
|
+
return predictedConfidence >= nodeConfidence
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
async getPayloadByKeyword(
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Session } from '@botonic/core'
|
|
2
|
+
|
|
3
|
+
import { FlowBuilderData } from './flow-builder-models'
|
|
4
|
+
|
|
5
|
+
export interface BotonicPluginFlowBuilderOptions {
|
|
6
|
+
flowUrl: string
|
|
7
|
+
flow?: FlowBuilderData
|
|
8
|
+
customFunctions?: Record<any, any>
|
|
9
|
+
getLocale: (session: Session) => string
|
|
10
|
+
getAccessToken: () => string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export enum ProcessEnvNodeEnvs {
|
|
14
|
+
PRODUCTION = 'production',
|
|
15
|
+
DEVELOPMENT = 'development',
|
|
16
|
+
}
|
package/src/utils.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { Session } from '@botonic/core'
|
|
2
|
+
|
|
3
|
+
import { BotonicPluginFlowBuilderOptions, ProcessEnvNodeEnvs } from './types'
|
|
4
|
+
|
|
1
5
|
export function getWebpackEnvVar(
|
|
2
6
|
webpackEnvVar: string | false,
|
|
3
7
|
name: string,
|
|
@@ -9,3 +13,23 @@ export function getWebpackEnvVar(
|
|
|
9
13
|
defaultValue
|
|
10
14
|
)
|
|
11
15
|
}
|
|
16
|
+
|
|
17
|
+
function getAccessTokenFromSession(session: Session): string {
|
|
18
|
+
if (!session._access_token) {
|
|
19
|
+
throw new Error('No access token found in session')
|
|
20
|
+
}
|
|
21
|
+
return session._access_token
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function resolveGetAccessToken(
|
|
25
|
+
options: BotonicPluginFlowBuilderOptions
|
|
26
|
+
): (session: Session) => string {
|
|
27
|
+
switch (process.env.NODE_ENV) {
|
|
28
|
+
case ProcessEnvNodeEnvs.PRODUCTION:
|
|
29
|
+
return getAccessTokenFromSession
|
|
30
|
+
case ProcessEnvNodeEnvs.DEVELOPMENT:
|
|
31
|
+
return options.getAccessToken
|
|
32
|
+
default:
|
|
33
|
+
throw new Error('No method defined for getting access token')
|
|
34
|
+
}
|
|
35
|
+
}
|