@miso.ai/client-sdk-ui 1.11.0-beta.1 → 1.11.0-beta.10
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/data.js +6 -7
- package/dist/cjs/actor/feedback.js +6 -39
- package/dist/cjs/actor/fields.js +14 -6
- package/dist/cjs/actor/hub.js +1 -2
- package/dist/cjs/actor/index.js +0 -7
- package/dist/cjs/actor/interactions.js +4 -15
- package/dist/cjs/actor/sessions.js +2 -33
- 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 +32 -8
- package/dist/cjs/asset/svgs.js +18 -8
- package/dist/cjs/constants.js +18 -19
- package/dist/cjs/defaults/hybrid-search/answer-box.js +19 -3
- package/dist/cjs/defaults/hybrid-search/phrases.js +5 -5
- package/dist/cjs/defaults/hybrid-search/templates.js +37 -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 +5 -5
- package/dist/cjs/layout/input/option-list.js +0 -4
- package/dist/cjs/layout/input/search-box.js +33 -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 +25 -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 +109 -111
- package/dist/cjs/workflow/ask.js +35 -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 +169 -102
- package/dist/cjs/workflow/explore.js +26 -19
- package/dist/cjs/workflow/hybrid-search-answer.js +99 -0
- package/dist/cjs/workflow/hybrid-search-results.js +70 -0
- package/dist/cjs/workflow/hybrid-search-views.js +122 -0
- package/dist/cjs/workflow/hybrid-search.js +98 -103
- package/dist/cjs/workflow/options.js +32 -17
- package/dist/cjs/workflow/processors.js +185 -17
- package/dist/cjs/workflow/recommendation.js +36 -49
- package/dist/cjs/workflow/search-based.js +186 -0
- package/dist/cjs/workflow/search.js +21 -68
- package/package.json +2 -2
- package/src/actor/data.js +2 -4
- package/src/actor/feedback.js +6 -23
- package/src/actor/fields.js +14 -6
- package/src/actor/hub.js +1 -2
- package/src/actor/index.js +0 -1
- package/src/actor/interactions.js +4 -10
- package/src/actor/sessions.js +3 -30
- 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 +36 -8
- package/src/asset/svgs.js +19 -7
- package/src/constants.js +25 -16
- package/src/defaults/hybrid-search/answer-box.js +17 -5
- package/src/defaults/hybrid-search/phrases.js +4 -4
- package/src/defaults/hybrid-search/templates.js +25 -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 +5 -6
- package/src/layout/input/option-list.js +0 -5
- package/src/layout/input/search-box.js +27 -14
- package/src/layout/list/cards.js +0 -4
- package/src/layout/list/carousel.js +0 -4
- package/src/layout/list/collection.js +22 -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/trackable.js +1 -1
- 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 +101 -77
- package/src/workflow/ask.js +33 -25
- 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 +147 -93
- package/src/workflow/explore.js +23 -8
- package/src/workflow/hybrid-search-answer.js +92 -0
- package/src/workflow/hybrid-search-results.js +63 -0
- package/src/workflow/hybrid-search-views.js +124 -0
- package/src/workflow/hybrid-search.js +102 -73
- package/src/workflow/options.js +26 -11
- package/src/workflow/processors.js +165 -14
- package/src/workflow/recommendation.js +32 -33
- package/src/workflow/search-based.js +183 -0
- package/src/workflow/search.js +21 -65
- 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
|
@@ -1,10 +1,15 @@
|
|
|
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 ?
|
|
7
|
-
return trimObj({
|
|
11
|
+
const ongoing = status === STATUS.READY ? data.ongoing : undefined;
|
|
12
|
+
return trimObj({ status, ongoing, ...data }); // let orinigal data override status and ongoing
|
|
8
13
|
}
|
|
9
14
|
|
|
10
15
|
function getStatus(data) {
|
|
@@ -35,7 +40,8 @@ export function writeMisoIdToMeta(data) {
|
|
|
35
40
|
|
|
36
41
|
export function writeKeywordsToData(data) {
|
|
37
42
|
const { request, value } = data;
|
|
38
|
-
|
|
43
|
+
// we still want the value in loading status
|
|
44
|
+
if (!request) {
|
|
39
45
|
return data;
|
|
40
46
|
}
|
|
41
47
|
const { payload } = request || {};
|
|
@@ -73,23 +79,168 @@ export function writeAnswerStageToMeta(data) {
|
|
|
73
79
|
};
|
|
74
80
|
}
|
|
75
81
|
|
|
76
|
-
export function
|
|
77
|
-
|
|
82
|
+
export function writeFiltersToPayload(payload = {}, filters) {
|
|
83
|
+
return trimObj({
|
|
84
|
+
...payload,
|
|
85
|
+
...composeFiltersPayload(filters),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function composeFiltersPayload(filters) {
|
|
90
|
+
if (!filters) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
const { facets } = filters;
|
|
94
|
+
return trimObj({
|
|
95
|
+
facet_filters: composeFacetFilters(facets),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function composeFacetFilters(facets) {
|
|
100
|
+
if (!facets) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
const filters = {};
|
|
104
|
+
for (const field in facets) {
|
|
105
|
+
const values = facets[field];
|
|
106
|
+
if (!values || !values.length) {
|
|
107
|
+
continue; // just in case
|
|
108
|
+
}
|
|
109
|
+
filters[field] = {
|
|
110
|
+
terms: values,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return Object.keys(filters).length ? filters : undefined;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function retainFacetCounts(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) {
|
|
78
129
|
return data;
|
|
79
130
|
}
|
|
80
131
|
return {
|
|
81
|
-
_inst: {
|
|
82
|
-
...data._inst,
|
|
83
|
-
...instructions,
|
|
84
|
-
},
|
|
85
132
|
...data,
|
|
133
|
+
value: {
|
|
134
|
+
...value,
|
|
135
|
+
facet_counts: currentFacetCounts,
|
|
136
|
+
},
|
|
86
137
|
};
|
|
87
138
|
}
|
|
88
139
|
|
|
89
|
-
export function
|
|
90
|
-
if (
|
|
140
|
+
export function concatResults(oldData, newData, { role = ROLE.PRODUCTS } = {}) {
|
|
141
|
+
if (!newData.value) {
|
|
142
|
+
return oldData;
|
|
143
|
+
}
|
|
144
|
+
const { [role]: oldProducts = [] } = oldData.value;
|
|
145
|
+
const { [role]: newProducts = [] } = newData.value;
|
|
146
|
+
// keep exhaustion flag
|
|
147
|
+
// TODO
|
|
148
|
+
return {
|
|
149
|
+
...newData,
|
|
150
|
+
value: {
|
|
151
|
+
...newData.value,
|
|
152
|
+
[role]: [...oldProducts, ...newProducts],
|
|
153
|
+
},
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function markExhaustion(data, { role = ROLE.PRODUCTS } = {}) {
|
|
158
|
+
const { status, request, value } = data;
|
|
159
|
+
// keep track of the exhaustion state
|
|
160
|
+
if (status !== STATUS.READY || !request || !value) {
|
|
91
161
|
return data;
|
|
92
162
|
}
|
|
93
|
-
const {
|
|
94
|
-
|
|
163
|
+
const { [role]: products } = value;
|
|
164
|
+
if (!products) {
|
|
165
|
+
return data;
|
|
166
|
+
}
|
|
167
|
+
const { rows } = request.payload;
|
|
168
|
+
const { length } = products;
|
|
169
|
+
const exhausted = length < rows;
|
|
170
|
+
if (!exhausted) {
|
|
171
|
+
return data;
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
...data,
|
|
175
|
+
meta: {
|
|
176
|
+
...data.meta,
|
|
177
|
+
exhausted: true,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// interactions //
|
|
183
|
+
export function buildBaseInteraction(args) {
|
|
184
|
+
const { role, type, items } = args;
|
|
185
|
+
const payload = {
|
|
186
|
+
type: type === 'viewable' ? 'viewable_impression' : type,
|
|
187
|
+
context: {
|
|
188
|
+
custom_context: trimObj({
|
|
189
|
+
property: role,
|
|
190
|
+
}),
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
if (isPerformanceEventType(type)) {
|
|
195
|
+
if (isProductRole(role)) {
|
|
196
|
+
payload.product_ids = (items || []).map(v => typeof v === 'string' ? v : v.product_id).filter(v => v);
|
|
197
|
+
} else {
|
|
198
|
+
payload.product_ids = [];
|
|
199
|
+
payload.context.custom_context.items = (items || []).map(v => v.text || v.id || v);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
switch (type) {
|
|
204
|
+
case EVENT_TYPE.SUBMIT:
|
|
205
|
+
payload.context.custom_context.value = args.value;
|
|
206
|
+
break;
|
|
207
|
+
case EVENT_TYPE.FEEDBACK:
|
|
208
|
+
payload.context.custom_context.value = payload.value = args.value;
|
|
209
|
+
payload.context.custom_context.result_type = payload.result_type = args.result_type;
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return trimObj(payload);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export function writeAffiliationInfoToInteraction(payload, args) {
|
|
217
|
+
if (args.role !== ROLE.AFFILIATION) {
|
|
218
|
+
return payload;
|
|
219
|
+
}
|
|
220
|
+
const { items } = args;
|
|
221
|
+
const channel = (items[0] && items[0].channel) || undefined;
|
|
222
|
+
const positions = items.map(v => v.position);
|
|
223
|
+
return mergeInteraction(payload, {
|
|
224
|
+
context: {
|
|
225
|
+
custom_context: {
|
|
226
|
+
channel,
|
|
227
|
+
positions,
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function mergeInteraction(base = {}, patch = {}) {
|
|
234
|
+
return trimObj({
|
|
235
|
+
...base,
|
|
236
|
+
...patch,
|
|
237
|
+
context:trimObj({
|
|
238
|
+
...base.context,
|
|
239
|
+
...patch.context,
|
|
240
|
+
custom_context: trimObj({
|
|
241
|
+
...(base.context && base.context.custom_context),
|
|
242
|
+
...(patch.context && patch.context.custom_context),
|
|
243
|
+
}),
|
|
244
|
+
}),
|
|
245
|
+
});
|
|
95
246
|
}
|
|
@@ -1,39 +1,49 @@
|
|
|
1
|
-
import { defineValues,
|
|
1
|
+
import { defineValues, API } from '@miso.ai/commons';
|
|
2
2
|
import Workflow from './base.js';
|
|
3
|
-
import { mergeApiOptions } from './options.js';
|
|
4
|
-
import { fields } from '../actor/index.js';
|
|
5
3
|
import { ListLayout } from '../layout/index.js';
|
|
6
4
|
import { ROLE } from '../constants.js';
|
|
5
|
+
import { mergeRolesOptions } from './options.js';
|
|
6
|
+
import { mergeInteraction } from './processors.js';
|
|
7
7
|
|
|
8
8
|
const DEFAULT_API_OPTIONS = Object.freeze({
|
|
9
|
+
...Workflow.DEFAULT_API_OPTIONS,
|
|
9
10
|
group: API.GROUP.RECOMMENDATION,
|
|
10
11
|
name: API.NAME.USER_TO_PRODUCTS,
|
|
11
12
|
payload: {
|
|
13
|
+
...Workflow.DEFAULT_API_OPTIONS.payload,
|
|
12
14
|
fl: ['*'],
|
|
13
15
|
},
|
|
14
16
|
});
|
|
15
17
|
|
|
16
18
|
const DEFAULT_LAYOUTS = Object.freeze({
|
|
19
|
+
...Workflow.DEFAULT_LAYOUTS,
|
|
17
20
|
[ROLE.PRODUCTS]: ListLayout.type,
|
|
18
21
|
});
|
|
19
22
|
|
|
20
23
|
const DEFAULT_TRACKERS = Object.freeze({
|
|
24
|
+
...Workflow.DEFAULT_TRACKERS,
|
|
21
25
|
[ROLE.PRODUCTS]: {},
|
|
22
26
|
});
|
|
23
27
|
|
|
24
28
|
const DEFAULT_OPTIONS = Object.freeze({
|
|
29
|
+
...Workflow.DEFAULT_OPTIONS,
|
|
25
30
|
api: DEFAULT_API_OPTIONS,
|
|
26
31
|
layouts: DEFAULT_LAYOUTS,
|
|
27
32
|
trackers: DEFAULT_TRACKERS,
|
|
28
33
|
});
|
|
29
34
|
|
|
35
|
+
const ROLES_OPTIONS = mergeRolesOptions(Workflow.ROLES_OPTIONS, {
|
|
36
|
+
main: ROLE.PRODUCTS,
|
|
37
|
+
members: Object.keys(DEFAULT_LAYOUTS),
|
|
38
|
+
});
|
|
39
|
+
|
|
30
40
|
export default class Recommendation extends Workflow {
|
|
31
41
|
|
|
32
42
|
constructor(context, id) {
|
|
33
43
|
super({
|
|
34
44
|
name: 'recommendation',
|
|
35
45
|
context,
|
|
36
|
-
roles:
|
|
46
|
+
roles: ROLES_OPTIONS,
|
|
37
47
|
defaults: DEFAULT_OPTIONS,
|
|
38
48
|
id,
|
|
39
49
|
});
|
|
@@ -45,28 +55,15 @@ export default class Recommendation extends Workflow {
|
|
|
45
55
|
defineValues(this, { id });
|
|
46
56
|
}
|
|
47
57
|
|
|
48
|
-
|
|
58
|
+
_initSession(args) {
|
|
49
59
|
this._context._members.set(args.id, this);
|
|
50
|
-
super.
|
|
60
|
+
super._initSession(args);
|
|
51
61
|
}
|
|
52
62
|
|
|
53
63
|
// lifecycle //
|
|
54
64
|
start() {
|
|
55
|
-
this._sessions.start();
|
|
56
65
|
// in recommendation workflow, start() triggers query
|
|
57
|
-
|
|
58
|
-
const { session } = this;
|
|
59
|
-
this._hub.update(fields.request(), mergeApiOptions(this._options.resolved.api, { session }));
|
|
60
|
-
return this;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// TODO: deprecate this
|
|
64
|
-
startTracker() {
|
|
65
|
-
this.useApi(false);
|
|
66
|
-
this.useLayouts(false);
|
|
67
|
-
this._sessions.start();
|
|
68
|
-
this.notifyViewUpdate(ROLE.CONTAINER);
|
|
69
|
-
this.notifyViewUpdate(ROLE.PRODUCTS);
|
|
66
|
+
this._request();
|
|
70
67
|
return this;
|
|
71
68
|
}
|
|
72
69
|
|
|
@@ -76,21 +73,23 @@ export default class Recommendation extends Workflow {
|
|
|
76
73
|
}
|
|
77
74
|
|
|
78
75
|
// interactions //
|
|
79
|
-
|
|
80
|
-
payload = super.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
76
|
+
_defaultProcessInteraction(payload, args) {
|
|
77
|
+
payload = super._defaultProcessInteraction(payload, args);
|
|
78
|
+
payload = this._writeUnitIdToInteraction(payload, args);
|
|
79
|
+
return payload;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
_writeUnitIdToInteraction(payload) {
|
|
83
|
+
const unit_id = this.id;
|
|
84
|
+
const unit_instance_uuid = this.uuid;
|
|
85
|
+
return mergeInteraction(payload, {
|
|
85
86
|
context: {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
...custom_context,
|
|
91
|
-
}),
|
|
87
|
+
custom_context: {
|
|
88
|
+
unit_id,
|
|
89
|
+
unit_instance_uuid,
|
|
90
|
+
},
|
|
92
91
|
},
|
|
93
|
-
};
|
|
92
|
+
});
|
|
94
93
|
}
|
|
95
94
|
|
|
96
95
|
// destroy //
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { API } from '@miso.ai/commons';
|
|
2
|
+
import Workflow from './base.js';
|
|
3
|
+
import { fields } from '../actor/index.js';
|
|
4
|
+
import { ROLE } from '../constants.js';
|
|
5
|
+
import { SearchBoxLayout, ListLayout, TextLayout, FacetsLayout, MoreButtonLayout } from '../layout/index.js';
|
|
6
|
+
import { writeKeywordsToData, writeFiltersToPayload, retainFacetCounts, markExhaustion, concatResults } from './processors.js';
|
|
7
|
+
import { mergeRolesOptions, makeConfigurable } from './options.js';
|
|
8
|
+
|
|
9
|
+
const DEFAULT_ROWS = 10;
|
|
10
|
+
const DEFAULT_PAGE_LIMIT = 10;
|
|
11
|
+
|
|
12
|
+
const DEFAULT_API_OPTIONS = Object.freeze({
|
|
13
|
+
...Workflow.DEFAULT_API_OPTIONS,
|
|
14
|
+
group: API.GROUP.SEARCH,
|
|
15
|
+
payload: {
|
|
16
|
+
...Workflow.DEFAULT_API_OPTIONS.payload,
|
|
17
|
+
fl: ['cover_image', 'url', 'created_at', 'updated_at', 'published_at', 'title'],
|
|
18
|
+
rows: DEFAULT_ROWS,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const DEFAULT_LAYOUTS = Object.freeze({
|
|
23
|
+
...Workflow.DEFAULT_LAYOUTS,
|
|
24
|
+
[ROLE.QUERY]: [SearchBoxLayout.type],
|
|
25
|
+
[ROLE.PRODUCTS]: [ListLayout.type, { incremental: true, infiniteScroll: true }],
|
|
26
|
+
[ROLE.KEYWORDS]: [TextLayout.type, { raw: true }],
|
|
27
|
+
[ROLE.TOTAL]: [TextLayout.type, { raw: true, format: 'number' }],
|
|
28
|
+
[ROLE.FACETS]: [FacetsLayout.type],
|
|
29
|
+
[ROLE.MORE]: [MoreButtonLayout.type],
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const DEFAULT_TRACKERS = Object.freeze({
|
|
33
|
+
...Workflow.DEFAULT_TRACKERS,
|
|
34
|
+
[ROLE.PRODUCTS]: {},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const DEFAULT_PAGINATION = Object.freeze({
|
|
38
|
+
active: false,
|
|
39
|
+
mode: 'infiniteScroll',
|
|
40
|
+
pageLimit: 10,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const DEFAULT_OPTIONS = Object.freeze({
|
|
44
|
+
...Workflow.DEFAULT_OPTIONS,
|
|
45
|
+
api: DEFAULT_API_OPTIONS,
|
|
46
|
+
layouts: DEFAULT_LAYOUTS,
|
|
47
|
+
trackers: DEFAULT_TRACKERS,
|
|
48
|
+
pagination: DEFAULT_PAGINATION,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const ROLES_OPTIONS = mergeRolesOptions(Workflow.ROLES_OPTIONS, {
|
|
52
|
+
main: ROLE.PRODUCTS,
|
|
53
|
+
members: Object.keys(DEFAULT_LAYOUTS),
|
|
54
|
+
mappings: {
|
|
55
|
+
[ROLE.FACETS]: 'facet_counts',
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export default class SearchBasedWorkflow extends Workflow {
|
|
60
|
+
|
|
61
|
+
_initSubscriptions(args) {
|
|
62
|
+
super._initSubscriptions(args);
|
|
63
|
+
this._unsubscribes = [
|
|
64
|
+
...this._unsubscribes,
|
|
65
|
+
this._hub.on(fields.query(), args => this._query(args)),
|
|
66
|
+
this._hub.on(fields.filters(), filters => this._refine(filters)),
|
|
67
|
+
this._hub.on(fields.more(), () => this._more()),
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
restart() {
|
|
72
|
+
super.restart();
|
|
73
|
+
this._page = 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// properties //
|
|
77
|
+
get exhausted() {
|
|
78
|
+
const data = this._hub.states[fields.data()];
|
|
79
|
+
return !!(data && data.meta && data.meta.exhausted);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// query //
|
|
83
|
+
query(args) {
|
|
84
|
+
if (!args.q) {
|
|
85
|
+
throw new Error(`q is required in query() call`);
|
|
86
|
+
}
|
|
87
|
+
this._hub.update(fields.query(), args);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
_query(args) {
|
|
91
|
+
// keep track of the query args for refine and more calls
|
|
92
|
+
this._queryArgs = args;
|
|
93
|
+
|
|
94
|
+
// start a new session
|
|
95
|
+
this.restart();
|
|
96
|
+
|
|
97
|
+
// payload
|
|
98
|
+
const payload = this._buildPayload(args);
|
|
99
|
+
|
|
100
|
+
this._request({ payload });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
_refine(filters) {
|
|
104
|
+
// remember current facet_counts
|
|
105
|
+
const { facet_counts } = this._hub.states[fields.data()].value || {};
|
|
106
|
+
this._currentFacetCounts = facet_counts;
|
|
107
|
+
|
|
108
|
+
// start a new session
|
|
109
|
+
this.restart();
|
|
110
|
+
|
|
111
|
+
// payload
|
|
112
|
+
const query = this._getQuery();
|
|
113
|
+
const payload = this._buildPayload({ ...query, filters });
|
|
114
|
+
|
|
115
|
+
this._request({ payload });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
_more() {
|
|
119
|
+
if (this.exhausted || this._page >= DEFAULT_PAGE_LIMIT - 1) {
|
|
120
|
+
return; // ignore
|
|
121
|
+
}
|
|
122
|
+
// don't create a new session!
|
|
123
|
+
|
|
124
|
+
// payload
|
|
125
|
+
const query = this._getQuery();
|
|
126
|
+
const filters = this._hub.states[fields.filters()]; // get stored filters
|
|
127
|
+
const start = (this._page + 1) * this._getPageSize();
|
|
128
|
+
const payload = this._buildPayload({ ...query, filters, start });
|
|
129
|
+
|
|
130
|
+
this._request({ payload });
|
|
131
|
+
|
|
132
|
+
this._page++;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
_getQuery() {
|
|
136
|
+
return this._queryArgs;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
_getPageSize() {
|
|
140
|
+
return this._options.resolved.api.payload.rows;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
_buildPayload({ filters, ...payload } = {}) {
|
|
144
|
+
payload = writeFiltersToPayload(payload, filters);
|
|
145
|
+
return payload;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// data //
|
|
149
|
+
_defaultProcessData(data) {
|
|
150
|
+
data = super._defaultProcessData(data);
|
|
151
|
+
data = writeKeywordsToData(data);
|
|
152
|
+
data = retainFacetCounts(data, this._currentFacetCounts);
|
|
153
|
+
data = markExhaustion(data);
|
|
154
|
+
return data;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
_updateDataInHub(data) {
|
|
158
|
+
data = this._appendResultsFromMoreRequest(data);
|
|
159
|
+
super._updateDataInHub(data);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
_appendResultsFromMoreRequest(data) {
|
|
163
|
+
const { request } = data;
|
|
164
|
+
if (!request || !request.payload.start) {
|
|
165
|
+
return data; // the initial state, or not from "more" request
|
|
166
|
+
}
|
|
167
|
+
// concat records if it's from "more" request
|
|
168
|
+
const currentData = this._hub.states[fields.data()];
|
|
169
|
+
return concatResults(currentData, data);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
makeConfigurable(SearchBasedWorkflow.prototype, ['pagination']);
|
|
175
|
+
|
|
176
|
+
Object.assign(SearchBasedWorkflow, {
|
|
177
|
+
DEFAULT_API_OPTIONS,
|
|
178
|
+
DEFAULT_LAYOUTS,
|
|
179
|
+
DEFAULT_TRACKERS,
|
|
180
|
+
DEFAULT_PAGINATION,
|
|
181
|
+
DEFAULT_OPTIONS,
|
|
182
|
+
ROLES_OPTIONS,
|
|
183
|
+
});
|
package/src/workflow/search.js
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { API } from '@miso.ai/commons';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import { fields, AutocompleteActor } from '../actor/index.js';
|
|
6
|
-
import { ROLE, DATA_ASPECT } from '../constants.js';
|
|
7
|
-
import { ListLayout, SearchBoxLayout } from '../layout/index.js';
|
|
8
|
-
import { makeConfigurable } from './options.js';
|
|
2
|
+
import { ROLE } from '../constants.js';
|
|
3
|
+
import SearchBasedWorkflow from './search-based.js';
|
|
4
|
+
import { makeAutocompletable } from './autocompletable.js';
|
|
9
5
|
|
|
10
6
|
const DEFAULT_API_OPTIONS = Object.freeze({
|
|
11
7
|
group: API.GROUP.SEARCH,
|
|
@@ -16,7 +12,6 @@ const DEFAULT_API_OPTIONS = Object.freeze({
|
|
|
16
12
|
});
|
|
17
13
|
|
|
18
14
|
const DEFAULT_AUTOCOMPLETE_OPTIONS = Object.freeze({
|
|
19
|
-
actor: false,
|
|
20
15
|
api: {
|
|
21
16
|
group: API.GROUP.SEARCH,
|
|
22
17
|
name: API.NAME.AUTOCOMPLETE,
|
|
@@ -25,54 +20,43 @@ const DEFAULT_AUTOCOMPLETE_OPTIONS = Object.freeze({
|
|
|
25
20
|
fl: ['title', 'url', 'cover_image'],
|
|
26
21
|
},
|
|
27
22
|
},
|
|
28
|
-
throttle: 300,
|
|
29
23
|
});
|
|
30
24
|
|
|
31
25
|
const DEFAULT_LAYOUTS = Object.freeze({
|
|
32
|
-
|
|
33
|
-
[ROLE.PRODUCTS]: ListLayout.type,
|
|
26
|
+
...SearchBasedWorkflow.DEFAULT_LAYOUTS,
|
|
34
27
|
});
|
|
35
28
|
|
|
36
29
|
const DEFAULT_TRACKERS = Object.freeze({
|
|
37
|
-
|
|
30
|
+
...SearchBasedWorkflow.DEFAULT_TRACKERS,
|
|
38
31
|
});
|
|
39
32
|
|
|
40
33
|
const DEFAULT_OPTIONS = Object.freeze({
|
|
34
|
+
...SearchBasedWorkflow.DEFAULT_OPTIONS,
|
|
41
35
|
api: DEFAULT_API_OPTIONS,
|
|
42
36
|
autocomplete: DEFAULT_AUTOCOMPLETE_OPTIONS,
|
|
43
37
|
layouts: DEFAULT_LAYOUTS,
|
|
44
38
|
trackers: DEFAULT_TRACKERS,
|
|
45
39
|
});
|
|
46
40
|
|
|
47
|
-
|
|
41
|
+
const ROLES_OPTIONS = SearchBasedWorkflow.ROLES_OPTIONS;
|
|
42
|
+
|
|
43
|
+
export default class Search extends SearchBasedWorkflow {
|
|
48
44
|
|
|
49
45
|
constructor(plugin, client) {
|
|
50
46
|
super({
|
|
51
47
|
name: 'search',
|
|
52
48
|
plugin,
|
|
53
49
|
client,
|
|
54
|
-
roles:
|
|
50
|
+
roles: ROLES_OPTIONS,
|
|
55
51
|
defaults: DEFAULT_OPTIONS,
|
|
56
52
|
});
|
|
57
53
|
}
|
|
58
54
|
|
|
59
|
-
|
|
60
|
-
super.
|
|
61
|
-
this.
|
|
62
|
-
source: sources.api(this._client),
|
|
63
|
-
options: this._options,
|
|
64
|
-
});
|
|
55
|
+
_initProperties(args) {
|
|
56
|
+
super._initProperties(args);
|
|
57
|
+
this._initAutocomplete(args);
|
|
65
58
|
}
|
|
66
59
|
|
|
67
|
-
_initSubscriptions(args) {
|
|
68
|
-
super._initSubscriptions(args);
|
|
69
|
-
this._unsubscribes = [
|
|
70
|
-
...this._unsubscribes,
|
|
71
|
-
this._hub.on(fields.query(), args => this._query(args)),
|
|
72
|
-
];
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// lifecycle //
|
|
76
60
|
autoQuery({ setValue = true, focus = true } = {}) {
|
|
77
61
|
const q = new URLSearchParams(window.location.search).get('q');
|
|
78
62
|
const { layout } = this._views.get(ROLE.QUERY);
|
|
@@ -89,46 +73,18 @@ export default class Search extends Workflow {
|
|
|
89
73
|
}
|
|
90
74
|
}
|
|
91
75
|
|
|
92
|
-
query(args) {
|
|
93
|
-
if (!args.q) {
|
|
94
|
-
throw new Error(`q is required in query() call`);
|
|
95
|
-
}
|
|
96
|
-
this._hub.update(fields.query(), args);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
_query(args) {
|
|
100
|
-
// start a new session
|
|
101
|
-
this.restart();
|
|
102
|
-
const { session } = this;
|
|
103
|
-
|
|
104
|
-
// build payload and trigger request
|
|
105
|
-
const payload = this._buildPayload(args);
|
|
106
|
-
const event = mergeApiOptions(this._options.resolved.api, { payload, session });
|
|
107
|
-
this._request(event);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
_buildPayload(args) {
|
|
111
|
-
return args;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
_request(event) {
|
|
115
|
-
this._hub.update(fields.request(), event);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
updateCompletions(event) {
|
|
119
|
-
// TODO: verify
|
|
120
|
-
this._hub.update(fields.data(DATA_ASPECT.AUTOCOMPLETE), {
|
|
121
|
-
...event,
|
|
122
|
-
source: 'manual',
|
|
123
|
-
});
|
|
124
|
-
return this;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
76
|
notifyViewUpdate(role = ROLE.PRODUCTS, ...args) {
|
|
128
77
|
super.notifyViewUpdate(role, ...args);
|
|
129
78
|
return this;
|
|
130
79
|
}
|
|
131
80
|
|
|
81
|
+
// destroy //
|
|
82
|
+
_destroy(options) {
|
|
83
|
+
this._feedback._destroy();
|
|
84
|
+
this._destroyAutocomplete();
|
|
85
|
+
super._destroy(options);
|
|
86
|
+
}
|
|
87
|
+
|
|
132
88
|
}
|
|
133
89
|
|
|
134
|
-
|
|
90
|
+
makeAutocompletable(Search.prototype);
|