@miso.ai/client-sdk-ui 1.10.0-beta.0 → 1.10.0-beta.1
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/autocomplete.js +157 -0
- package/dist/cjs/actor/data.js +3 -11
- package/dist/cjs/actor/fields.js +8 -0
- package/dist/cjs/actor/index.js +7 -0
- package/dist/cjs/actor/utils.js +10 -0
- package/dist/cjs/defaults/ask/templates.js +21 -0
- package/dist/cjs/layout/input/search-box.js +213 -127
- package/dist/cjs/layout/list/collection.js +6 -1
- package/dist/cjs/layout/templates.js +50 -35
- package/dist/cjs/source/index.js +20 -8
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/workflow/ask.js +48 -16
- package/dist/cjs/workflow/base.js +1 -2
- package/dist/cjs/workflow/explore.js +4 -1
- package/dist/cjs/workflow/options.js +54 -13
- package/dist/cjs/workflow/search.js +35 -7
- package/package.json +2 -2
- package/src/actor/autocomplete.js +131 -0
- package/src/actor/data.js +3 -10
- package/src/actor/fields.js +8 -0
- package/src/actor/index.js +1 -0
- package/src/actor/utils.js +8 -0
- package/src/defaults/ask/templates.js +21 -0
- package/src/layout/input/search-box.js +186 -94
- package/src/layout/list/collection.js +6 -1
- package/src/layout/templates.js +31 -25
- package/src/source/index.js +14 -1
- package/src/version.js +1 -1
- package/src/workflow/ask.js +31 -1
- package/src/workflow/base.js +1 -2
- package/src/workflow/explore.js +1 -1
- package/src/workflow/options.js +49 -12
- package/src/workflow/search.js +33 -1
package/dist/cjs/version.js
CHANGED
package/dist/cjs/workflow/ask.js
CHANGED
|
@@ -7,10 +7,13 @@ exports.default = void 0;
|
|
|
7
7
|
var _commons = require("@miso.ai/commons");
|
|
8
8
|
var _base = _interopRequireDefault(require("./base.js"));
|
|
9
9
|
var _options = require("./options.js");
|
|
10
|
-
var
|
|
10
|
+
var sources = _interopRequireWildcard(require("../source/index.js"));
|
|
11
|
+
var _index2 = require("../actor/index.js");
|
|
11
12
|
var _constants = require("../constants.js");
|
|
12
|
-
var
|
|
13
|
+
var _index3 = require("../layout/index.js");
|
|
13
14
|
const _excluded = ["q", "qs"];
|
|
15
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
16
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
14
17
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
18
|
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.indexOf(n) >= 0) continue; t[n] = r[n]; } return t; }
|
|
16
19
|
const DEFAULT_API_OPTIONS = Object.freeze({
|
|
@@ -24,27 +27,34 @@ const DEFAULT_API_OPTIONS = Object.freeze({
|
|
|
24
27
|
cite_end: ']'
|
|
25
28
|
}
|
|
26
29
|
});
|
|
30
|
+
const DEFAULT_AUTOCOMPLETE_OPTIONS = Object.freeze({
|
|
31
|
+
actor: false,
|
|
32
|
+
api: {
|
|
33
|
+
group: _commons.API.GROUP.ASK,
|
|
34
|
+
name: _commons.API.NAME.AUTOCOMPLETE
|
|
35
|
+
}
|
|
36
|
+
});
|
|
27
37
|
const DEFAULT_LAYOUTS = Object.freeze({
|
|
28
|
-
[_constants.ROLE.QUERY]: [
|
|
38
|
+
[_constants.ROLE.QUERY]: [_index3.SearchBoxLayout.type, {
|
|
29
39
|
placeholder: 'Ask a question'
|
|
30
40
|
}],
|
|
31
|
-
[_constants.ROLE.QUESTION]: [
|
|
41
|
+
[_constants.ROLE.QUESTION]: [_index3.TextLayout.type, {
|
|
32
42
|
tag: 'h2'
|
|
33
43
|
}],
|
|
34
|
-
[_constants.ROLE.ANSWER]:
|
|
35
|
-
[_constants.ROLE.FEEDBACK]:
|
|
36
|
-
[_constants.ROLE.SOURCES]: [
|
|
44
|
+
[_constants.ROLE.ANSWER]: _index3.TypewriterLayout.type,
|
|
45
|
+
[_constants.ROLE.FEEDBACK]: _index3.FeedbackLayout.type,
|
|
46
|
+
[_constants.ROLE.SOURCES]: [_index3.ListLayout.type, {
|
|
37
47
|
incremental: true,
|
|
38
48
|
itemType: 'article',
|
|
39
49
|
templates: {
|
|
40
50
|
ordered: true
|
|
41
51
|
}
|
|
42
52
|
}],
|
|
43
|
-
[_constants.ROLE.RELATED_RESOURCES]: [
|
|
53
|
+
[_constants.ROLE.RELATED_RESOURCES]: [_index3.ListLayout.type, {
|
|
44
54
|
incremental: true,
|
|
45
55
|
itemType: 'article'
|
|
46
56
|
}],
|
|
47
|
-
[_constants.ROLE.QUERY_SUGGESTIONS]:
|
|
57
|
+
[_constants.ROLE.QUERY_SUGGESTIONS]: _index3.OptionListLayout.type
|
|
48
58
|
});
|
|
49
59
|
const DEFAULT_TRACKERS = Object.freeze({
|
|
50
60
|
[_constants.ROLE.SOURCES]: {},
|
|
@@ -59,6 +69,7 @@ const DEFAULT_TRACKERS = Object.freeze({
|
|
|
59
69
|
});
|
|
60
70
|
const DEFAULT_OPTIONS = Object.freeze({
|
|
61
71
|
api: DEFAULT_API_OPTIONS,
|
|
72
|
+
autocomplete: DEFAULT_AUTOCOMPLETE_OPTIONS,
|
|
62
73
|
layouts: DEFAULT_LAYOUTS,
|
|
63
74
|
trackers: DEFAULT_TRACKERS
|
|
64
75
|
});
|
|
@@ -75,9 +86,17 @@ class Ask extends _base.default {
|
|
|
75
86
|
(0, _commons.defineValues)(this, {
|
|
76
87
|
parentQuestionId
|
|
77
88
|
});
|
|
78
|
-
this._feedback = new
|
|
89
|
+
this._feedback = new _index2.FeedbackActor(this._hub);
|
|
79
90
|
this._setSuggestedQuestions();
|
|
80
|
-
|
|
91
|
+
|
|
92
|
+
/*
|
|
93
|
+
this._autocomplete = new AutocompleteActor(this._hub, {
|
|
94
|
+
source: sources.api(this._client),
|
|
95
|
+
options: this._options,
|
|
96
|
+
});
|
|
97
|
+
*/
|
|
98
|
+
|
|
99
|
+
this._unsubscribes = [...this._unsubscribes, this._hub.on(_index2.fields.query(), payload => this.query(payload)), this._hub.on(_index2.fields.view(_constants.ROLE.ANSWER), data => this._onAnswerViewUpdate(data)), this._views.get(_constants.ROLE.ANSWER).on('citation-click', event => this._onCitationClick(event))];
|
|
81
100
|
parentQuestionId && context._byPqid.set(parentQuestionId, this);
|
|
82
101
|
context._events.emit('create', this);
|
|
83
102
|
this.reset(); // create a session so query suggestions can be tracked
|
|
@@ -163,7 +182,7 @@ class Ask extends _base.default {
|
|
|
163
182
|
session
|
|
164
183
|
} = this;
|
|
165
184
|
session.meta.question_source = questionSource;
|
|
166
|
-
this._hub.update(
|
|
185
|
+
this._hub.update(_index2.fields.request(), (0, _options.mergeApiOptions)(this._options.resolved.api, {
|
|
167
186
|
payload,
|
|
168
187
|
session
|
|
169
188
|
}));
|
|
@@ -175,7 +194,7 @@ class Ask extends _base.default {
|
|
|
175
194
|
session,
|
|
176
195
|
status,
|
|
177
196
|
ongoing
|
|
178
|
-
} = this._hub.states[
|
|
197
|
+
} = this._hub.states[_index2.fields.view(_constants.ROLE.ANSWER)] || {};
|
|
179
198
|
if (session && status !== _constants.STATUS.INITIAL && (status !== _constants.STATUS.READY || ongoing)) {
|
|
180
199
|
// it's interrupted by a new question
|
|
181
200
|
const state = Object.freeze({
|
|
@@ -188,6 +207,18 @@ class Ask extends _base.default {
|
|
|
188
207
|
}
|
|
189
208
|
super.restart();
|
|
190
209
|
}
|
|
210
|
+
|
|
211
|
+
/*
|
|
212
|
+
updateCompletions(event) {
|
|
213
|
+
// TODO: verify
|
|
214
|
+
this._hub.update(fields.completions(), {
|
|
215
|
+
...event,
|
|
216
|
+
source: 'manual',
|
|
217
|
+
});
|
|
218
|
+
return this;
|
|
219
|
+
}
|
|
220
|
+
*/
|
|
221
|
+
|
|
191
222
|
_defaultProcessData(data) {
|
|
192
223
|
data = super._defaultProcessData(data);
|
|
193
224
|
const {
|
|
@@ -258,9 +289,9 @@ class Ask extends _base.default {
|
|
|
258
289
|
if (!previous) {
|
|
259
290
|
return;
|
|
260
291
|
}
|
|
261
|
-
const values = previous.states[
|
|
292
|
+
const values = previous.states[_index2.fields.data()].value;
|
|
262
293
|
const value = values.suggested_followup_questions || values.followup_questions || [];
|
|
263
|
-
this._hub.update(
|
|
294
|
+
this._hub.update(_index2.fields.suggestions(), {
|
|
264
295
|
value: value.map(text => ({
|
|
265
296
|
text
|
|
266
297
|
}))
|
|
@@ -272,7 +303,7 @@ class Ask extends _base.default {
|
|
|
272
303
|
} = _ref3;
|
|
273
304
|
const {
|
|
274
305
|
value
|
|
275
|
-
} = this.states[
|
|
306
|
+
} = this.states[_index2.fields.data()] || {};
|
|
276
307
|
const {
|
|
277
308
|
sources
|
|
278
309
|
} = value || {};
|
|
@@ -327,6 +358,7 @@ class Ask extends _base.default {
|
|
|
327
358
|
this._context._byQid.delete(questionId);
|
|
328
359
|
}
|
|
329
360
|
this._feedback._destroy();
|
|
361
|
+
this._autocomplete._destroy();
|
|
330
362
|
super._destroy(options);
|
|
331
363
|
}
|
|
332
364
|
}
|
|
@@ -59,11 +59,10 @@ class Workflow extends _commons.Component {
|
|
|
59
59
|
const hub = this._hub = (0, _utils.injectLogger)(new _index.Hub(), function () {
|
|
60
60
|
return _this._log(...arguments);
|
|
61
61
|
});
|
|
62
|
-
const source = this._source = sources.api(client);
|
|
63
62
|
const layouts = plugin.layouts;
|
|
64
63
|
this._sessions = new _index.SessionMaker(hub);
|
|
65
64
|
this._data = new _index.DataActor(hub, {
|
|
66
|
-
source,
|
|
65
|
+
source: sources.api(client),
|
|
67
66
|
options
|
|
68
67
|
});
|
|
69
68
|
const views = this._views = new _index.ViewsActor(hub, {
|
|
@@ -19,7 +19,10 @@ const DEFAULT_API_OPTIONS = Object.freeze({
|
|
|
19
19
|
});
|
|
20
20
|
const DEFAULT_LAYOUTS = Object.freeze({
|
|
21
21
|
[_constants.ROLE.RELATED_QUESTIONS]: [_index2.ListLayout.type, {
|
|
22
|
-
itemType: 'question'
|
|
22
|
+
itemType: 'question',
|
|
23
|
+
link: {
|
|
24
|
+
rel: 'noopener nofollow'
|
|
25
|
+
}
|
|
23
26
|
}],
|
|
24
27
|
[_constants.ROLE.QUERY]: [_index2.SearchBoxLayout.type, {
|
|
25
28
|
placeholder: 'Ask a question'
|
|
@@ -6,11 +6,13 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.WorkflowOptions = exports.WorkflowContextOptions = void 0;
|
|
7
7
|
exports.makeConfigurable = makeConfigurable;
|
|
8
8
|
exports.mergeApiOptions = mergeApiOptions;
|
|
9
|
+
exports.mergeAutocompleteOptions = mergeAutocompleteOptions;
|
|
9
10
|
exports.mergeDataProcessorOptions = mergeDataProcessorOptions;
|
|
10
11
|
exports.mergeInteractionsOptions = mergeInteractionsOptions;
|
|
11
12
|
exports.mergeLayoutsOptions = mergeLayoutsOptions;
|
|
12
13
|
exports.mergeTrackersOptions = mergeTrackersOptions;
|
|
13
14
|
exports.normalizeApiOptions = normalizeApiOptions;
|
|
15
|
+
exports.normalizeAutocompleteOptions = normalizeAutocompleteOptions;
|
|
14
16
|
exports.normalizeDataProcessorOptions = normalizeDataProcessorOptions;
|
|
15
17
|
exports.normalizeInteractionsOptions = normalizeInteractionsOptions;
|
|
16
18
|
exports.normalizeLayoutsOptions = normalizeLayoutsOptions;
|
|
@@ -23,6 +25,7 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
|
|
|
23
25
|
// normalize //
|
|
24
26
|
function normalizeApiOptions() {
|
|
25
27
|
let [name, payload] = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
28
|
+
// TODO: take object form as well
|
|
26
29
|
if (name === false) {
|
|
27
30
|
return {
|
|
28
31
|
actor: false
|
|
@@ -131,6 +134,20 @@ function normalizeInteractionsOptions(options) {
|
|
|
131
134
|
preprocess
|
|
132
135
|
});
|
|
133
136
|
}
|
|
137
|
+
function normalizeAutocompleteOptions(options) {
|
|
138
|
+
if (options === undefined) {
|
|
139
|
+
throw new Error(`Expect autocomplete options to be an object or a boolean value: ${options}`);
|
|
140
|
+
}
|
|
141
|
+
if (typeof options === 'boolean') {
|
|
142
|
+
options = {
|
|
143
|
+
actor: options
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
const processData = normalizeDataProcessorOptions(options.processData);
|
|
147
|
+
return Object.assign({}, options, {
|
|
148
|
+
processData
|
|
149
|
+
});
|
|
150
|
+
}
|
|
134
151
|
|
|
135
152
|
// merge //
|
|
136
153
|
function mergeApiOptions() {
|
|
@@ -217,6 +234,18 @@ function mergeInteractionsOptions() {
|
|
|
217
234
|
preprocess: concatArrays(merged.preprocess, options.preprocess)
|
|
218
235
|
})));
|
|
219
236
|
}
|
|
237
|
+
function mergeAutocompleteOptions() {
|
|
238
|
+
for (var _len6 = arguments.length, optionsList = new Array(_len6), _key7 = 0; _key7 < _len6; _key7++) {
|
|
239
|
+
optionsList[_key7] = arguments[_key7];
|
|
240
|
+
}
|
|
241
|
+
if (optionsList[optionsList.length - 1] === false) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
return mergeOptions(optionsList, (merged, options) => Object.assign(merged, Object.assign({}, options, {
|
|
245
|
+
api: mergeApiOptions(merged.api, options.api),
|
|
246
|
+
processData: mergeDataProcessorOptions(merged.processData, options.processData)
|
|
247
|
+
})));
|
|
248
|
+
}
|
|
220
249
|
|
|
221
250
|
// manifest //
|
|
222
251
|
const FEATURES = [{
|
|
@@ -239,6 +268,10 @@ const FEATURES = [{
|
|
|
239
268
|
key: 'interactions',
|
|
240
269
|
normalize: normalizeInteractionsOptions,
|
|
241
270
|
merge: mergeInteractionsOptions
|
|
271
|
+
}, {
|
|
272
|
+
key: 'autocomplete',
|
|
273
|
+
normalize: normalizeAutocompleteOptions,
|
|
274
|
+
merge: mergeAutocompleteOptions
|
|
242
275
|
}];
|
|
243
276
|
class WorkflowContextOptions {
|
|
244
277
|
constructor() {
|
|
@@ -339,21 +372,29 @@ for (const {
|
|
|
339
372
|
}
|
|
340
373
|
});
|
|
341
374
|
}
|
|
375
|
+
const DEFAULT_FEATURES = ['api', 'layouts', 'dataProcessor', 'trackers', 'interactions'];
|
|
342
376
|
function makeConfigurable(prototype) {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
377
|
+
let features = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_FEATURES;
|
|
378
|
+
for (const feature of features) {
|
|
379
|
+
injectConfigurableFeature(prototype, feature);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
function injectConfigurableFeature(prototype, feature) {
|
|
383
|
+
if (feature === 'api') {
|
|
384
|
+
Object.assign(prototype, {
|
|
385
|
+
useApi() {
|
|
386
|
+
for (var _len7 = arguments.length, args = new Array(_len7), _key8 = 0; _key8 < _len7; _key8++) {
|
|
387
|
+
args[_key8] = arguments[_key8];
|
|
388
|
+
}
|
|
389
|
+
this._options.api.merge(args);
|
|
390
|
+
return this;
|
|
391
|
+
},
|
|
392
|
+
clearApi() {
|
|
393
|
+
this._options.api.set();
|
|
394
|
+
return this;
|
|
347
395
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
},
|
|
351
|
-
clearApi() {
|
|
352
|
-
this._options.api.set();
|
|
353
|
-
return this;
|
|
354
|
-
}
|
|
355
|
-
});
|
|
356
|
-
for (const feature of ['layouts', 'dataProcessor', 'trackers', 'interactions']) {
|
|
396
|
+
});
|
|
397
|
+
} else {
|
|
357
398
|
const upperCased = upperCase(feature);
|
|
358
399
|
Object.assign(prototype, {
|
|
359
400
|
[`use${upperCased}`](value) {
|
|
@@ -7,9 +7,12 @@ exports.default = void 0;
|
|
|
7
7
|
var _commons = require("@miso.ai/commons");
|
|
8
8
|
var _base = _interopRequireDefault(require("./base.js"));
|
|
9
9
|
var _options = require("./options.js");
|
|
10
|
-
var
|
|
10
|
+
var sources = _interopRequireWildcard(require("../source/index.js"));
|
|
11
|
+
var _index2 = require("../actor/index.js");
|
|
11
12
|
var _constants = require("../constants.js");
|
|
12
|
-
var
|
|
13
|
+
var _index3 = require("../layout/index.js");
|
|
14
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
15
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
13
16
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
17
|
const DEFAULT_API_OPTIONS = Object.freeze({
|
|
15
18
|
group: _commons.API.GROUP.SEARCH,
|
|
@@ -18,15 +21,28 @@ const DEFAULT_API_OPTIONS = Object.freeze({
|
|
|
18
21
|
fl: ['*']
|
|
19
22
|
}
|
|
20
23
|
});
|
|
24
|
+
const DEFAULT_AUTOCOMPLETE_OPTIONS = Object.freeze({
|
|
25
|
+
actor: false,
|
|
26
|
+
api: {
|
|
27
|
+
group: _commons.API.GROUP.SEARCH,
|
|
28
|
+
name: _commons.API.NAME.AUTOCOMPLETE,
|
|
29
|
+
payload: {
|
|
30
|
+
completion_fields: ['suggested_queries', 'title'],
|
|
31
|
+
fl: ['title', 'url', 'cover_image']
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
throttle: 300
|
|
35
|
+
});
|
|
21
36
|
const DEFAULT_LAYOUTS = Object.freeze({
|
|
22
|
-
[_constants.ROLE.QUERY]:
|
|
23
|
-
[_constants.ROLE.PRODUCTS]:
|
|
37
|
+
[_constants.ROLE.QUERY]: _index3.SearchBoxLayout.type,
|
|
38
|
+
[_constants.ROLE.PRODUCTS]: _index3.ListLayout.type
|
|
24
39
|
});
|
|
25
40
|
const DEFAULT_TRACKERS = Object.freeze({
|
|
26
41
|
[_constants.ROLE.PRODUCTS]: {}
|
|
27
42
|
});
|
|
28
43
|
const DEFAULT_OPTIONS = Object.freeze({
|
|
29
44
|
api: DEFAULT_API_OPTIONS,
|
|
45
|
+
autocomplete: DEFAULT_AUTOCOMPLETE_OPTIONS,
|
|
30
46
|
layouts: DEFAULT_LAYOUTS,
|
|
31
47
|
trackers: DEFAULT_TRACKERS
|
|
32
48
|
});
|
|
@@ -39,7 +55,11 @@ class Search extends _base.default {
|
|
|
39
55
|
roles: Object.keys(DEFAULT_LAYOUTS),
|
|
40
56
|
defaults: DEFAULT_OPTIONS
|
|
41
57
|
});
|
|
42
|
-
this.
|
|
58
|
+
this._autocomplete = new _index2.AutocompleteActor(this._hub, {
|
|
59
|
+
source: sources.api(this._client),
|
|
60
|
+
options: this._options
|
|
61
|
+
});
|
|
62
|
+
this._unsubscribes.push(this._hub.on(_index2.fields.query(), payload => this.query(payload)));
|
|
43
63
|
}
|
|
44
64
|
|
|
45
65
|
// lifecycle //
|
|
@@ -71,12 +91,19 @@ class Search extends _base.default {
|
|
|
71
91
|
const {
|
|
72
92
|
session
|
|
73
93
|
} = this;
|
|
74
|
-
this._hub.update(
|
|
94
|
+
this._hub.update(_index2.fields.request(), (0, _options.mergeApiOptions)(this._options.resolved.api, {
|
|
75
95
|
payload,
|
|
76
96
|
session
|
|
77
97
|
}));
|
|
78
98
|
return this;
|
|
79
99
|
}
|
|
100
|
+
updateCompletions(event) {
|
|
101
|
+
// TODO: verify
|
|
102
|
+
this._hub.update(_index2.fields.completions(), Object.assign({}, event, {
|
|
103
|
+
source: 'manual'
|
|
104
|
+
}));
|
|
105
|
+
return this;
|
|
106
|
+
}
|
|
80
107
|
notifyViewUpdate() {
|
|
81
108
|
let role = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _constants.ROLE.PRODUCTS;
|
|
82
109
|
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
@@ -86,4 +113,5 @@ class Search extends _base.default {
|
|
|
86
113
|
return this;
|
|
87
114
|
}
|
|
88
115
|
}
|
|
89
|
-
exports.default = Search;
|
|
116
|
+
exports.default = Search;
|
|
117
|
+
(0, _options.makeConfigurable)(Search.prototype, ['autocomplete']);
|
package/package.json
CHANGED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { STATUS } from '../constants.js';
|
|
2
|
+
import * as fields from './fields.js';
|
|
3
|
+
|
|
4
|
+
export default class AutocompleteActor {
|
|
5
|
+
|
|
6
|
+
constructor(hub, { source, options }) {
|
|
7
|
+
this._hub = hub;
|
|
8
|
+
this._source = source;
|
|
9
|
+
this._options = options;
|
|
10
|
+
this._index = -1;
|
|
11
|
+
|
|
12
|
+
this._unsubscribes = [
|
|
13
|
+
hub.on(fields.input(), () => this._sync()),
|
|
14
|
+
options.on('autocomplete', () => this._syncOptions()),
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
// sync right away
|
|
18
|
+
this._sync(true);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get active() {
|
|
22
|
+
return this._options.resolved.autocomplete.actor !== false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get source() {
|
|
26
|
+
return this._source;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_syncOptions() {
|
|
30
|
+
// TODO: explore scenarios where options.actor true -> false
|
|
31
|
+
this._sync(true);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async _sync(force = false) {
|
|
35
|
+
// protocol: inactive -> no reaction
|
|
36
|
+
if (!this.active) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const { input } = this._hub.states;
|
|
41
|
+
const value = input && input.value && input.value.trim() || undefined;
|
|
42
|
+
|
|
43
|
+
if (sameInput(this._input, input) && !force) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
this._input = input;
|
|
47
|
+
const index = ++this._index;
|
|
48
|
+
|
|
49
|
+
// new input, abort previous data fetch if any
|
|
50
|
+
this._clearTimeout();
|
|
51
|
+
this._abortPendingRequest({
|
|
52
|
+
type: 'new-input',
|
|
53
|
+
message: 'A new input renders previous autocomplete request obsolete.',
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// emit loading/initial state
|
|
57
|
+
this._emitCompletions({ index, input, status: value ? STATUS.LOADING : STATUS.INITIAL });
|
|
58
|
+
|
|
59
|
+
if (!value) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const response = await this._fetchCompletions(input);
|
|
65
|
+
if (this._index !== index) {
|
|
66
|
+
return; // new results loading, discard this one
|
|
67
|
+
}
|
|
68
|
+
this._emitCompletions({ index, input, status: STATUS.READY, value: response.completions });
|
|
69
|
+
} catch (error) {
|
|
70
|
+
this._error(error);
|
|
71
|
+
if (this._index !== index) {
|
|
72
|
+
return; // ignore
|
|
73
|
+
}
|
|
74
|
+
this._emitCompletions({ index, input, status: STATUS.ERRONEOUS, error });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async _getCompletions(input) {
|
|
79
|
+
// TODO: cache
|
|
80
|
+
return await this._fetchCompletions(input);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async _fetchCompletions({ value }) {
|
|
84
|
+
// TODO: other options?
|
|
85
|
+
const { api } = this._options.resolved.autocomplete;
|
|
86
|
+
const { group, name } = api;
|
|
87
|
+
const { signal } = this._ac || {};
|
|
88
|
+
const options = { ...api.options, signal };
|
|
89
|
+
const payload = { ...api.payload, q: value };
|
|
90
|
+
return await this._source({ group, name, payload, options });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
_clearTimeout() {
|
|
94
|
+
if (this._timeoutId) {
|
|
95
|
+
clearTimeout(this._timeoutId);
|
|
96
|
+
this._timeoutId = undefined;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
_abortPendingRequest(info) {
|
|
101
|
+
this._ac && this._ac.abort(info);
|
|
102
|
+
this._ac = new AbortController();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
_emitCompletions(event) {
|
|
106
|
+
event.source = 'actor';
|
|
107
|
+
this._hub.update(fields.completions(), event);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
_error(error) {
|
|
111
|
+
// TODO
|
|
112
|
+
console.error(error);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
_destroy() {
|
|
116
|
+
// abort ongoing data fetch if any
|
|
117
|
+
this._ac && this._ac.abort({
|
|
118
|
+
type: 'autocomplete-actor-destroy',
|
|
119
|
+
message: 'Autocomplete actor is destroyed.',
|
|
120
|
+
});
|
|
121
|
+
for (const unsubscribe of this._unsubscribes) {
|
|
122
|
+
unsubscribe();
|
|
123
|
+
}
|
|
124
|
+
this._unsubscribes = [];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function sameInput(a, b) {
|
|
130
|
+
return (!a && !b) || (a && b && a.value === b.value);
|
|
131
|
+
}
|
package/src/actor/data.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as fields from './fields.js';
|
|
2
|
+
import { isCurrentSession } from './utils.js';
|
|
2
3
|
|
|
3
4
|
export default class DataActor {
|
|
4
5
|
|
|
@@ -61,7 +62,7 @@ export default class DataActor {
|
|
|
61
62
|
let value;
|
|
62
63
|
for await (value of response) {
|
|
63
64
|
// A new session invalidates ongoing data fetch for the old session, terminating the loop
|
|
64
|
-
if (!this.
|
|
65
|
+
if (!isCurrentSession(this._hub, session)) {
|
|
65
66
|
break;
|
|
66
67
|
}
|
|
67
68
|
this._emitResponse({ session, request, value });
|
|
@@ -77,15 +78,7 @@ export default class DataActor {
|
|
|
77
78
|
|
|
78
79
|
_emitResponseWithSessionCheck(response) {
|
|
79
80
|
// A new session invalidates ongoing data fetch
|
|
80
|
-
this.
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
_isCurrentSession(session) {
|
|
84
|
-
if (!session) {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
const { session: currentSession } = this._hub.states;
|
|
88
|
-
return currentSession && currentSession.index === session.index;
|
|
81
|
+
isCurrentSession(this._hub, response.session) && this._emitResponse(response);
|
|
89
82
|
}
|
|
90
83
|
|
|
91
84
|
_emitResponse(response) {
|
package/src/actor/fields.js
CHANGED
package/src/actor/index.js
CHANGED
|
@@ -7,4 +7,5 @@ export { default as DataActor } from './data.js';
|
|
|
7
7
|
export { default as ViewsActor } from './views.js';
|
|
8
8
|
export { default as Trackers } from './trackers.js';
|
|
9
9
|
export { default as FeedbackActor } from './feedback.js';
|
|
10
|
+
export { default as AutocompleteActor } from './autocomplete.js';
|
|
10
11
|
export { default as InteractionsActor } from './interactions.js';
|
package/src/actor/utils.js
CHANGED
|
@@ -40,3 +40,11 @@ export function toInteraction({ property, misoId, request }, { event, values, ma
|
|
|
40
40
|
});
|
|
41
41
|
return payload;
|
|
42
42
|
}
|
|
43
|
+
|
|
44
|
+
export function isCurrentSession(hub, session) {
|
|
45
|
+
if (!session) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const { session: currentSession } = hub.states;
|
|
49
|
+
return currentSession && currentSession.index === session.index;
|
|
50
|
+
}
|
|
@@ -26,6 +26,27 @@ export function followUp(options = {}) {
|
|
|
26
26
|
]);
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
export const sections = Object.freeze({
|
|
30
|
+
followUps,
|
|
31
|
+
relatedResources,
|
|
32
|
+
querySuggestions,
|
|
33
|
+
answerGroup,
|
|
34
|
+
answer,
|
|
35
|
+
sources,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export const helpers = Object.freeze({
|
|
39
|
+
normalizeOptions,
|
|
40
|
+
normalizePhraseOptions,
|
|
41
|
+
normalizePhraseOptionKey,
|
|
42
|
+
phrase,
|
|
43
|
+
phraseText,
|
|
44
|
+
section,
|
|
45
|
+
container,
|
|
46
|
+
element,
|
|
47
|
+
attrs,
|
|
48
|
+
});
|
|
49
|
+
|
|
29
50
|
|
|
30
51
|
|
|
31
52
|
// options //
|