@miso.ai/client-sdk-ui 1.11.0-beta.8 → 1.11.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.
- package/dist/cjs/actor/feedback.js +6 -39
- package/dist/cjs/actor/fields.js +14 -6
- package/dist/cjs/actor/index.js +0 -7
- package/dist/cjs/actor/interactions.js +4 -15
- package/dist/cjs/actor/sessions.js +2 -32
- package/dist/cjs/actor/tracker.js +25 -26
- package/dist/cjs/actor/utils.js +0 -49
- package/dist/cjs/actor/view.js +40 -40
- package/dist/cjs/actor/views.js +29 -8
- package/dist/cjs/constants.js +18 -19
- package/dist/cjs/defaults/hybrid-search/phrases.js +3 -3
- package/dist/cjs/defaults/hybrid-search/templates.js +28 -9
- package/dist/cjs/element/role/index.js +12 -5
- package/dist/cjs/element/role/{miso-hits.js → miso-more.js} +4 -4
- package/dist/cjs/element/role/miso-total.js +20 -0
- package/dist/cjs/layout/affiliation/affiliation.js +0 -3
- package/dist/cjs/layout/banner/banner.js +0 -4
- package/dist/cjs/layout/button/more-button.js +73 -0
- package/dist/cjs/layout/container/container.js +0 -3
- package/dist/cjs/layout/error/error.js +0 -4
- package/dist/cjs/layout/index.js +7 -0
- package/dist/cjs/layout/input/facets.js +0 -4
- package/dist/cjs/layout/input/option-list.js +0 -4
- package/dist/cjs/layout/input/search-box.js +13 -12
- package/dist/cjs/layout/list/cards.js +0 -3
- package/dist/cjs/layout/list/carousel.js +0 -3
- package/dist/cjs/layout/list/collection.js +22 -7
- package/dist/cjs/layout/list/list.js +0 -3
- package/dist/cjs/layout/radio/feedback.js +0 -3
- package/dist/cjs/layout/radio/radio.js +0 -4
- package/dist/cjs/layout/raf.js +4 -2
- package/dist/cjs/layout/text/text.js +0 -4
- package/dist/cjs/layout/text/typewriter/index.js +0 -3
- package/dist/cjs/layout/triggerable.js +79 -0
- package/dist/cjs/util/states.js +0 -15
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/workflow/answer-based.js +70 -105
- package/dist/cjs/workflow/ask.js +29 -27
- package/dist/cjs/workflow/asks.js +1 -1
- package/dist/cjs/workflow/autocompletable.js +33 -0
- package/dist/cjs/workflow/autocomplete.js +122 -0
- package/dist/cjs/workflow/base.js +156 -98
- package/dist/cjs/workflow/explore.js +48 -46
- package/dist/cjs/workflow/hybrid-search-answer.js +17 -7
- package/dist/cjs/workflow/hybrid-search-results.js +17 -87
- package/dist/cjs/workflow/hybrid-search-views.js +122 -0
- package/dist/cjs/workflow/hybrid-search.js +47 -168
- package/dist/cjs/workflow/options.js +32 -17
- package/dist/cjs/workflow/processors.js +166 -2
- package/dist/cjs/workflow/recommendation.js +36 -49
- package/dist/cjs/workflow/search-based.js +228 -0
- package/dist/cjs/workflow/search.js +21 -68
- package/dist/cjs/workflow/use-link.js +44 -0
- package/package.json +2 -2
- package/src/actor/feedback.js +6 -23
- package/src/actor/fields.js +14 -6
- package/src/actor/index.js +0 -1
- package/src/actor/interactions.js +4 -10
- package/src/actor/sessions.js +3 -31
- package/src/actor/tracker.js +25 -19
- package/src/actor/utils.js +0 -47
- package/src/actor/view.js +27 -15
- package/src/actor/views.js +32 -8
- package/src/constants.js +25 -16
- package/src/defaults/hybrid-search/phrases.js +2 -2
- package/src/defaults/hybrid-search/templates.js +20 -9
- package/src/element/role/index.js +2 -1
- package/src/element/role/{miso-hits.js → miso-more.js} +3 -3
- package/src/element/role/miso-total.js +16 -0
- package/src/layout/affiliation/affiliation.js +1 -5
- package/src/layout/banner/banner.js +0 -5
- package/src/layout/button/more-button.js +69 -0
- package/src/layout/container/container.js +1 -5
- package/src/layout/error/error.js +0 -5
- package/src/layout/index.js +2 -1
- package/src/layout/input/facets.js +0 -5
- package/src/layout/input/option-list.js +0 -5
- package/src/layout/input/search-box.js +11 -14
- package/src/layout/list/cards.js +0 -4
- package/src/layout/list/carousel.js +0 -4
- package/src/layout/list/collection.js +21 -9
- package/src/layout/list/list.js +0 -4
- package/src/layout/radio/feedback.js +0 -4
- package/src/layout/radio/radio.js +0 -5
- package/src/layout/raf.js +2 -2
- package/src/layout/text/text.js +0 -5
- package/src/layout/text/typewriter/index.js +1 -5
- package/src/layout/triggerable.js +76 -0
- package/src/util/states.js +0 -14
- package/src/version.js +1 -1
- package/src/workflow/answer-based.js +61 -72
- package/src/workflow/ask.js +30 -24
- package/src/workflow/asks.js +1 -1
- package/src/workflow/autocompletable.js +29 -0
- package/src/workflow/autocomplete.js +113 -0
- package/src/workflow/base.js +133 -87
- package/src/workflow/explore.js +38 -30
- package/src/workflow/hybrid-search-answer.js +17 -6
- package/src/workflow/hybrid-search-results.js +17 -77
- package/src/workflow/hybrid-search-views.js +124 -0
- package/src/workflow/hybrid-search.js +47 -157
- package/src/workflow/options.js +26 -11
- package/src/workflow/processors.js +151 -3
- package/src/workflow/recommendation.js +32 -33
- package/src/workflow/search-based.js +222 -0
- package/src/workflow/search.js +21 -65
- package/src/workflow/use-link.js +40 -0
- package/dist/cjs/actor/autocomplete.js +0 -160
- package/dist/cjs/workflow/utils.js +0 -42
- package/src/actor/autocomplete.js +0 -133
- package/src/workflow/utils.js +0 -29
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { ROLE } from '../constants.js';
|
|
2
|
+
|
|
3
|
+
function getSubworkflowByRole(role) {
|
|
4
|
+
// TODO: ROLE.ERROR
|
|
5
|
+
switch (role) {
|
|
6
|
+
case ROLE.PRODUCTS:
|
|
7
|
+
case ROLE.TOTAL:
|
|
8
|
+
case ROLE.FACETS:
|
|
9
|
+
case ROLE.KEYWORDS:
|
|
10
|
+
case ROLE.MORE:
|
|
11
|
+
return 'results';
|
|
12
|
+
default:
|
|
13
|
+
return 'answer';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default class HybridSearchViewsActor {
|
|
18
|
+
|
|
19
|
+
constructor(workflow) {
|
|
20
|
+
this._workflow = workflow;
|
|
21
|
+
this._containers = new Set();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get(role) {
|
|
25
|
+
return this._getSubviews(role).get(role);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
addContainer(element) {
|
|
29
|
+
if (this._containers.has(element)) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
this._containers.add(element);
|
|
33
|
+
|
|
34
|
+
const { components } = element;
|
|
35
|
+
for (const component of components) {
|
|
36
|
+
this.addComponent(component);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
removeContainer(element) {
|
|
41
|
+
for (const subworkflow of this._workflow._subworkflows) {
|
|
42
|
+
subworkflow._views.removeContainer(element);
|
|
43
|
+
}
|
|
44
|
+
this._containers.delete(element);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
addComponent(element) {
|
|
48
|
+
this._getViewByElement(element).element = element;
|
|
49
|
+
this._addContainerToSubviews(element._container, element);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
removeComponent(element) {
|
|
53
|
+
this._getViewByElement(element).element = undefined;
|
|
54
|
+
this._removeContainerFromSubviewsIfNecessary(element._container);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
updateComponentRole(element, oldRole, newRole) {
|
|
58
|
+
// TODO
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
refreshElement(element) {
|
|
62
|
+
const view = element.isContainer ? this._containers.get(element) : this._getViewByElement(element);
|
|
63
|
+
view && view.refresh({ force: true });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// helpers //
|
|
67
|
+
_getSubworkflow(role) {
|
|
68
|
+
return this._workflow._getSubworkflow(getSubworkflowByRole(role));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
_getAllSubviews() {
|
|
72
|
+
return this._workflow._subworkflows.flatMap(subworkflow => subworkflow._views);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
_getSubviews(role) {
|
|
76
|
+
return this._getSubworkflow(role)._views;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
_getViewByElement(element) {
|
|
80
|
+
let { role } = element;
|
|
81
|
+
if (!role) {
|
|
82
|
+
throw new Error('Component must have a role');
|
|
83
|
+
}
|
|
84
|
+
return this.get(role);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
_addContainerToSubviews(container, child) {
|
|
88
|
+
if (!container) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const { role } = child;
|
|
92
|
+
const subviews = this._getSubviews(role);
|
|
93
|
+
if (subviews._containers.has(container)) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// check if the container is in other subviews
|
|
97
|
+
for (const otherSubviews of this._getAllSubviews()) {
|
|
98
|
+
if (otherSubviews === subviews) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (otherSubviews._containers.has(container)) {
|
|
102
|
+
// find the conflicting element
|
|
103
|
+
for (const component of container.components) {
|
|
104
|
+
if (otherSubviews.containsElement(component)) {
|
|
105
|
+
throw new Error(`<${container.tagName}> cannot contain both <${component.tagName}> and <${child.tagName}>, for they don't share the same data lifecycle.`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
throw new Error(`Failed to add container <${container.tagName}> with child component <${child.tagName}>.`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// add the container to the subviews
|
|
112
|
+
subviews.addContainer(container);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
_removeContainerFromSubviewsIfNecessary(container) {
|
|
116
|
+
if (!container || container.components.length > 0) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
for (const subviews of this._getAllSubviews()) {
|
|
120
|
+
subviews.removeContainer(container);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
}
|
|
@@ -1,70 +1,70 @@
|
|
|
1
1
|
import { API } from '@miso.ai/commons';
|
|
2
2
|
import { InteractionsActor } from '../actor/index.js';
|
|
3
3
|
import Workflow from './base.js';
|
|
4
|
+
import SearchBasedWorkflow from './search-based.js';
|
|
4
5
|
import AnswerBasedWorkflow from './answer-based.js';
|
|
5
6
|
import { ROLE } from '../constants.js';
|
|
6
|
-
import { SearchBoxLayout,
|
|
7
|
+
import { SearchBoxLayout, TextLayout } from '../layout/index.js';
|
|
7
8
|
import HybridSearchAnswer from './hybrid-search-answer.js';
|
|
8
9
|
import HybridSearchResults from './hybrid-search-results.js';
|
|
10
|
+
import HybridSearchViewsActor from './hybrid-search-views.js';
|
|
9
11
|
|
|
10
12
|
const DEFAULT_API_OPTIONS = Object.freeze({
|
|
11
|
-
|
|
13
|
+
group: API.GROUP.ASK,
|
|
12
14
|
name: API.NAME.SEARCH,
|
|
13
15
|
payload: {
|
|
14
16
|
...AnswerBasedWorkflow.DEFAULT_API_OPTIONS.payload,
|
|
17
|
+
...SearchBasedWorkflow.DEFAULT_API_OPTIONS.payload,
|
|
15
18
|
source_fl: ['cover_image', 'url', 'created_at', 'updated_at', 'published_at', 'title'],
|
|
16
|
-
fl: ['cover_image', 'url', 'created_at', 'updated_at', 'published_at', 'title'],
|
|
17
19
|
},
|
|
18
20
|
});
|
|
19
21
|
|
|
20
22
|
const DEFAULT_LAYOUTS = Object.freeze({
|
|
21
23
|
...AnswerBasedWorkflow.DEFAULT_LAYOUTS,
|
|
24
|
+
...SearchBasedWorkflow.DEFAULT_LAYOUTS,
|
|
22
25
|
[ROLE.QUERY]: [SearchBoxLayout.type, { placeholder: '' }],
|
|
23
26
|
[ROLE.QUESTION]: [TextLayout.type, { raw: true }],
|
|
24
|
-
[ROLE.PRODUCTS]: [ListLayout.type, { itemType: 'article' }],
|
|
25
|
-
[ROLE.KEYWORDS]: [TextLayout.type, { raw: true }],
|
|
26
|
-
[ROLE.HITS]: [TextLayout.type, { raw: true, format: 'number' }],
|
|
27
|
-
[ROLE.FACETS]: [FacetsLayout.type],
|
|
28
27
|
});
|
|
29
28
|
|
|
30
29
|
const DEFAULT_TRACKERS = Object.freeze({
|
|
31
30
|
...AnswerBasedWorkflow.DEFAULT_TRACKERS,
|
|
31
|
+
...SearchBasedWorkflow.DEFAULT_TRACKERS,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const DEFAULT_PAGINATION = Object.freeze({
|
|
35
|
+
...SearchBasedWorkflow.DEFAULT_PAGINATION,
|
|
36
|
+
active: true,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const DEFAULT_AUTOCOMPLETE_OPTIONS = Object.freeze({
|
|
40
|
+
api: {
|
|
41
|
+
group: API.GROUP.ASK,
|
|
42
|
+
name: API.NAME.SEARCH_AUTOCOMPLETE,
|
|
43
|
+
payload: {
|
|
44
|
+
completion_fields: ['suggested_queries'],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
32
47
|
});
|
|
33
48
|
|
|
34
49
|
const DEFAULT_OPTIONS = Object.freeze({
|
|
35
50
|
...AnswerBasedWorkflow.DEFAULT_OPTIONS,
|
|
51
|
+
...SearchBasedWorkflow.DEFAULT_OPTIONS,
|
|
36
52
|
api: DEFAULT_API_OPTIONS,
|
|
37
53
|
layouts: DEFAULT_LAYOUTS,
|
|
38
54
|
trackers: DEFAULT_TRACKERS,
|
|
55
|
+
autocomplete: DEFAULT_AUTOCOMPLETE_OPTIONS,
|
|
56
|
+
pagination: DEFAULT_PAGINATION,
|
|
39
57
|
});
|
|
40
58
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
},
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
const SUBWORKFLOW = Object.freeze({
|
|
51
|
-
ANSWER: 'answer',
|
|
52
|
-
RESULTS: 'results',
|
|
59
|
+
const ROLES_OPTIONS = Object.freeze({
|
|
60
|
+
main: ROLE.PRODUCTS,
|
|
61
|
+
members: Object.keys(DEFAULT_LAYOUTS),
|
|
62
|
+
mappings: Object.freeze({
|
|
63
|
+
...AnswerBasedWorkflow.ROLES_OPTIONS.mappings,
|
|
64
|
+
...SearchBasedWorkflow.ROLES_OPTIONS.mappings,
|
|
65
|
+
}),
|
|
53
66
|
});
|
|
54
67
|
|
|
55
|
-
function getSubworkflowByRole(role) {
|
|
56
|
-
// TODO: ROLE.ERROR
|
|
57
|
-
switch (role) {
|
|
58
|
-
case ROLE.PRODUCTS:
|
|
59
|
-
case ROLE.HITS:
|
|
60
|
-
case ROLE.FACETS:
|
|
61
|
-
case ROLE.KEYWORDS:
|
|
62
|
-
return SUBWORKFLOW.RESULTS;
|
|
63
|
-
default:
|
|
64
|
-
return SUBWORKFLOW.ANSWER;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
68
|
export default class HybridSearch extends Workflow {
|
|
69
69
|
|
|
70
70
|
constructor(plugin, client) {
|
|
@@ -72,8 +72,7 @@ export default class HybridSearch extends Workflow {
|
|
|
72
72
|
name: 'hybrid-search',
|
|
73
73
|
plugin,
|
|
74
74
|
client,
|
|
75
|
-
roles:
|
|
76
|
-
rolesConfig: ROLES_CONFIG,
|
|
75
|
+
roles: ROLES_OPTIONS,
|
|
77
76
|
defaults: DEFAULT_OPTIONS,
|
|
78
77
|
});
|
|
79
78
|
}
|
|
@@ -88,9 +87,9 @@ export default class HybridSearch extends Workflow {
|
|
|
88
87
|
|
|
89
88
|
_getSubworkflow(name) {
|
|
90
89
|
switch (name) {
|
|
91
|
-
case
|
|
90
|
+
case 'answer':
|
|
92
91
|
return this._answer;
|
|
93
|
-
case
|
|
92
|
+
case 'results':
|
|
94
93
|
return this._results;
|
|
95
94
|
default:
|
|
96
95
|
throw new Error(`Invalid subworkflow: ${name}`);
|
|
@@ -106,18 +105,14 @@ export default class HybridSearch extends Workflow {
|
|
|
106
105
|
this._interactions = new InteractionsActor(hub, { client, options });
|
|
107
106
|
}
|
|
108
107
|
|
|
109
|
-
|
|
110
|
-
this._results.
|
|
111
|
-
this._answer.
|
|
108
|
+
_initSession() {
|
|
109
|
+
this._results._sessions.restart();
|
|
110
|
+
this._answer._sessions.restart();
|
|
112
111
|
}
|
|
113
112
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
this.
|
|
117
|
-
const { session } = this;
|
|
118
|
-
if (!answer) {
|
|
119
|
-
session._answer = previousSession._answer || previousSession;
|
|
120
|
-
}
|
|
113
|
+
// configuration //
|
|
114
|
+
useLink(fn, options) {
|
|
115
|
+
this._answer.useLink(fn, options);
|
|
121
116
|
return this;
|
|
122
117
|
}
|
|
123
118
|
|
|
@@ -130,6 +125,10 @@ export default class HybridSearch extends Workflow {
|
|
|
130
125
|
return this._results._views.filters;
|
|
131
126
|
}
|
|
132
127
|
|
|
128
|
+
get autocomplete() {
|
|
129
|
+
return this._answer.autocomplete;
|
|
130
|
+
}
|
|
131
|
+
|
|
133
132
|
// query //
|
|
134
133
|
autoQuery(options) {
|
|
135
134
|
this._answer.autoQuery(options);
|
|
@@ -140,8 +139,8 @@ export default class HybridSearch extends Workflow {
|
|
|
140
139
|
}
|
|
141
140
|
|
|
142
141
|
// interactions //
|
|
143
|
-
|
|
144
|
-
return this._answer.
|
|
142
|
+
_defaultProcessInteraction(payload, args) {
|
|
143
|
+
return this._answer._defaultProcessInteraction(payload, args);
|
|
145
144
|
}
|
|
146
145
|
|
|
147
146
|
// destroy //
|
|
@@ -153,112 +152,3 @@ export default class HybridSearch extends Workflow {
|
|
|
153
152
|
}
|
|
154
153
|
|
|
155
154
|
}
|
|
156
|
-
|
|
157
|
-
class HybridSearchViewsActor {
|
|
158
|
-
|
|
159
|
-
constructor(workflow) {
|
|
160
|
-
this._workflow = workflow;
|
|
161
|
-
this._containers = new Set();
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
get(role) {
|
|
165
|
-
return this._getSubviews(role).get(role);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
addContainer(element) {
|
|
169
|
-
if (this._containers.has(element)) {
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
this._containers.add(element);
|
|
173
|
-
|
|
174
|
-
const { components } = element;
|
|
175
|
-
for (const component of components) {
|
|
176
|
-
this.addComponent(component);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
removeContainer(element) {
|
|
181
|
-
for (const subworkflow of this._workflow._subworkflows) {
|
|
182
|
-
subworkflow._views.removeContainer(element);
|
|
183
|
-
}
|
|
184
|
-
this._containers.delete(element);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
addComponent(element) {
|
|
188
|
-
this._getViewByElement(element).element = element;
|
|
189
|
-
this._addContainerToSubviews(element._container, element);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
removeComponent(element) {
|
|
193
|
-
this._getViewByElement(element).element = undefined;
|
|
194
|
-
this._removeContainerFromSubviewsIfNecessary(element._container);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
updateComponentRole(element, oldRole, newRole) {
|
|
198
|
-
// TODO
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
refreshElement(element) {
|
|
202
|
-
const view = element.isContainer ? this._containers.get(element) : this._getViewByElement(element);
|
|
203
|
-
view && view.refresh({ force: true });
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// helpers //
|
|
207
|
-
_getSubworkflow(role) {
|
|
208
|
-
return this._workflow._getSubworkflow(getSubworkflowByRole(role));
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
_getAllSubviews() {
|
|
212
|
-
return this._workflow._subworkflows.flatMap(subworkflow => subworkflow._views);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
_getSubviews(role) {
|
|
216
|
-
return this._getSubworkflow(role)._views;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
_getViewByElement(element) {
|
|
220
|
-
let { role } = element;
|
|
221
|
-
if (!role) {
|
|
222
|
-
throw new Error('Component must have a role');
|
|
223
|
-
}
|
|
224
|
-
return this.get(role);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
_addContainerToSubviews(container, child) {
|
|
228
|
-
if (!container) {
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
const { role } = child;
|
|
232
|
-
const subviews = this._getSubviews(role);
|
|
233
|
-
if (subviews._containers.has(container)) {
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
// check if the container is in other subviews
|
|
237
|
-
for (const otherSubviews of this._getAllSubviews()) {
|
|
238
|
-
if (otherSubviews === subviews) {
|
|
239
|
-
continue;
|
|
240
|
-
}
|
|
241
|
-
if (otherSubviews._containers.has(container)) {
|
|
242
|
-
// find the conflicting element
|
|
243
|
-
for (const component of container.components) {
|
|
244
|
-
if (otherSubviews.containsElement(component)) {
|
|
245
|
-
throw new Error(`<${container.tagName}> cannot contain both <${component.tagName}> and <${child.tagName}>, for they don't share the same data lifecycle.`);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
throw new Error(`Failed to add container <${container.tagName}> with child component <${child.tagName}>.`);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
// add the container to the subviews
|
|
252
|
-
subviews.addContainer(container);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
_removeContainerFromSubviewsIfNecessary(container) {
|
|
256
|
-
if (!container || container.components.length > 0) {
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
for (const subviews of this._getAllSubviews()) {
|
|
260
|
-
subviews.removeContainer(container);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
}
|
package/src/workflow/options.js
CHANGED
|
@@ -110,15 +110,14 @@ export function normalizeInteractionsOptions(options) {
|
|
|
110
110
|
return { ...options, preprocess };
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
export function
|
|
113
|
+
export function normalizePaginationOptions(options) {
|
|
114
114
|
if (options === undefined) {
|
|
115
|
-
throw new Error(`Expect
|
|
115
|
+
throw new Error(`Expect pagination options to be an object or a boolean value: ${options}`);
|
|
116
116
|
}
|
|
117
117
|
if (typeof options === 'boolean') {
|
|
118
|
-
options = {
|
|
118
|
+
options = { active: options };
|
|
119
119
|
}
|
|
120
|
-
|
|
121
|
-
return { ...options, processData };
|
|
120
|
+
return options;
|
|
122
121
|
}
|
|
123
122
|
|
|
124
123
|
// merge //
|
|
@@ -206,17 +205,33 @@ export function mergeInteractionsOptions(...optionsList) {
|
|
|
206
205
|
}));
|
|
207
206
|
}
|
|
208
207
|
|
|
209
|
-
export function
|
|
208
|
+
export function mergePaginationOptions(...optionsList) {
|
|
210
209
|
if (optionsList[optionsList.length - 1] === false) {
|
|
211
210
|
return false;
|
|
212
211
|
}
|
|
212
|
+
return mergeOptions(optionsList, (merged, options) => Object.assign(merged, options));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export function mergeAutocompleteOptions(...optionsList) {
|
|
213
216
|
return mergeOptions(optionsList, (merged, options) => Object.assign(merged, {
|
|
214
217
|
...options,
|
|
215
218
|
api: mergeApiOptions(merged.api, options.api),
|
|
216
|
-
processData: mergeDataProcessorOptions(merged.processData, options.processData),
|
|
217
219
|
}));
|
|
218
220
|
}
|
|
219
221
|
|
|
222
|
+
export function mergeRolesOptions(base, overrides) {
|
|
223
|
+
return Object.freeze({
|
|
224
|
+
...base,
|
|
225
|
+
...overrides,
|
|
226
|
+
members: mergeRolesMembers(base.members, overrides.members),
|
|
227
|
+
mappings: Object.freeze({ ...base.mappings, ...overrides.mappings }),
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function mergeRolesMembers(base = [], overrides = []) {
|
|
232
|
+
return [...new Set([...base, ...overrides])];
|
|
233
|
+
}
|
|
234
|
+
|
|
220
235
|
|
|
221
236
|
|
|
222
237
|
// manifest //
|
|
@@ -247,9 +262,9 @@ const FEATURES = [
|
|
|
247
262
|
merge: mergeInteractionsOptions,
|
|
248
263
|
},
|
|
249
264
|
{
|
|
250
|
-
key: '
|
|
251
|
-
normalize:
|
|
252
|
-
merge:
|
|
265
|
+
key: 'pagination',
|
|
266
|
+
normalize: normalizePaginationOptions,
|
|
267
|
+
merge: mergePaginationOptions,
|
|
253
268
|
},
|
|
254
269
|
];
|
|
255
270
|
|
|
@@ -272,7 +287,7 @@ export class WorkflowOptions {
|
|
|
272
287
|
|
|
273
288
|
constructor(context = {}, defaults = {}) {
|
|
274
289
|
this._events = new EventEmitter({ target: this });
|
|
275
|
-
this._defaults = defaults;
|
|
290
|
+
this._defaults = defaults; // TODO: we should call normalize() on defaults
|
|
276
291
|
this._context = context || {};
|
|
277
292
|
this._locals = {};
|
|
278
293
|
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { trimObj } from '@miso.ai/commons';
|
|
2
|
-
import { STATUS } from '../constants.js';
|
|
2
|
+
import { STATUS, ROLE, EVENT_TYPE, isPerformanceEventType, isProductRole } from '../constants.js';
|
|
3
|
+
|
|
4
|
+
// data //
|
|
5
|
+
export function getRevision(data) {
|
|
6
|
+
return data && data.value && data.value.revision;
|
|
7
|
+
}
|
|
3
8
|
|
|
4
9
|
export function writeDataStatus(data) {
|
|
5
10
|
const status = getStatus(data);
|
|
6
|
-
const ongoing = status === STATUS.READY ?
|
|
11
|
+
const ongoing = status === STATUS.READY ? data.ongoing : undefined;
|
|
7
12
|
return trimObj({ status, ongoing, ...data }); // let orinigal data override status and ongoing
|
|
8
13
|
}
|
|
9
14
|
|
|
@@ -74,7 +79,14 @@ export function writeAnswerStageToMeta(data) {
|
|
|
74
79
|
};
|
|
75
80
|
}
|
|
76
81
|
|
|
77
|
-
export function
|
|
82
|
+
export function writeFiltersToPayload(payload = {}, filters) {
|
|
83
|
+
return trimObj({
|
|
84
|
+
...payload,
|
|
85
|
+
...composeFiltersPayload(filters),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function composeFiltersPayload(filters) {
|
|
78
90
|
if (!filters) {
|
|
79
91
|
return undefined;
|
|
80
92
|
}
|
|
@@ -100,3 +112,139 @@ function composeFacetFilters(facets) {
|
|
|
100
112
|
}
|
|
101
113
|
return Object.keys(filters).length ? filters : undefined;
|
|
102
114
|
}
|
|
115
|
+
|
|
116
|
+
export function retainFacetCountsInData(data, currentFacetCounts) {
|
|
117
|
+
if (!currentFacetCounts) {
|
|
118
|
+
return data;
|
|
119
|
+
}
|
|
120
|
+
const { status, value } = data;
|
|
121
|
+
switch (status) {
|
|
122
|
+
case STATUS.INITIAL:
|
|
123
|
+
case STATUS.LOADING:
|
|
124
|
+
break;
|
|
125
|
+
default:
|
|
126
|
+
return data;
|
|
127
|
+
}
|
|
128
|
+
if (value && value.facet_counts) {
|
|
129
|
+
return data;
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
...data,
|
|
133
|
+
value: {
|
|
134
|
+
...value,
|
|
135
|
+
facet_counts: currentFacetCounts,
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function concatItemsFromMoreResponse(oldData, newData, { role = ROLE.PRODUCTS } = {}) {
|
|
141
|
+
if (!newData.value) {
|
|
142
|
+
return oldData;
|
|
143
|
+
}
|
|
144
|
+
const { [role]: oldProducts = [], facet_counts, total } = oldData.value;
|
|
145
|
+
const { [role]: newProducts = [] } = newData.value;
|
|
146
|
+
// keep old exhaustion flag, just in case
|
|
147
|
+
// TODO
|
|
148
|
+
|
|
149
|
+
// use old values of facet_counts and total, for they are affected by product_id exclusion
|
|
150
|
+
return {
|
|
151
|
+
...newData,
|
|
152
|
+
facet_counts,
|
|
153
|
+
total,
|
|
154
|
+
value: {
|
|
155
|
+
...newData.value,
|
|
156
|
+
[role]: [...oldProducts, ...newProducts],
|
|
157
|
+
},
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function writeExhaustionToData(data, { role = ROLE.PRODUCTS } = {}) {
|
|
162
|
+
const { status, request, value } = data;
|
|
163
|
+
// keep track of the exhaustion state
|
|
164
|
+
if (status !== STATUS.READY || !request || !value) {
|
|
165
|
+
return data;
|
|
166
|
+
}
|
|
167
|
+
const { [role]: items } = value;
|
|
168
|
+
if (!items) {
|
|
169
|
+
return data;
|
|
170
|
+
}
|
|
171
|
+
const { rows } = request.payload;
|
|
172
|
+
const { length } = items;
|
|
173
|
+
const exhausted = length < rows;
|
|
174
|
+
if (!exhausted) {
|
|
175
|
+
return data;
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
...data,
|
|
179
|
+
meta: {
|
|
180
|
+
...data.meta,
|
|
181
|
+
exhausted: true,
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// interactions //
|
|
187
|
+
export function buildBaseInteraction(args) {
|
|
188
|
+
const { role, type, items } = args;
|
|
189
|
+
const payload = {
|
|
190
|
+
type: type === 'viewable' ? 'viewable_impression' : type,
|
|
191
|
+
context: {
|
|
192
|
+
custom_context: trimObj({
|
|
193
|
+
property: role,
|
|
194
|
+
}),
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
if (isPerformanceEventType(type)) {
|
|
199
|
+
if (isProductRole(role)) {
|
|
200
|
+
payload.product_ids = (items || []).map(v => typeof v === 'string' ? v : v.product_id).filter(v => v);
|
|
201
|
+
} else {
|
|
202
|
+
payload.product_ids = [];
|
|
203
|
+
payload.context.custom_context.items = (items || []).map(v => v.text || v.id || v);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
switch (type) {
|
|
208
|
+
case EVENT_TYPE.SUBMIT:
|
|
209
|
+
payload.context.custom_context.value = args.value;
|
|
210
|
+
break;
|
|
211
|
+
case EVENT_TYPE.FEEDBACK:
|
|
212
|
+
payload.context.custom_context.value = payload.value = args.value;
|
|
213
|
+
payload.context.custom_context.result_type = payload.result_type = args.result_type;
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return trimObj(payload);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function writeAffiliationInfoToInteraction(payload, args) {
|
|
221
|
+
if (args.role !== ROLE.AFFILIATION) {
|
|
222
|
+
return payload;
|
|
223
|
+
}
|
|
224
|
+
const { items } = args;
|
|
225
|
+
const channel = (items[0] && items[0].channel) || undefined;
|
|
226
|
+
const positions = items.map(v => v.position);
|
|
227
|
+
return mergeInteraction(payload, {
|
|
228
|
+
context: {
|
|
229
|
+
custom_context: {
|
|
230
|
+
channel,
|
|
231
|
+
positions,
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export function mergeInteraction(base = {}, patch = {}) {
|
|
238
|
+
return trimObj({
|
|
239
|
+
...base,
|
|
240
|
+
...patch,
|
|
241
|
+
context:trimObj({
|
|
242
|
+
...base.context,
|
|
243
|
+
...patch.context,
|
|
244
|
+
custom_context: trimObj({
|
|
245
|
+
...(base.context && base.context.custom_context),
|
|
246
|
+
...(patch.context && patch.context.custom_context),
|
|
247
|
+
}),
|
|
248
|
+
}),
|
|
249
|
+
});
|
|
250
|
+
}
|