@miso.ai/client-sdk-ui 1.10.0-beta.0 → 1.10.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.
Files changed (90) hide show
  1. package/dist/cjs/actor/autocomplete.js +157 -0
  2. package/dist/cjs/actor/data.js +4 -12
  3. package/dist/cjs/actor/fields.js +8 -0
  4. package/dist/cjs/actor/index.js +7 -0
  5. package/dist/cjs/actor/tracker.js +46 -70
  6. package/dist/cjs/actor/trackers.js +5 -1
  7. package/dist/cjs/actor/utils.js +16 -2
  8. package/dist/cjs/actor/view.js +14 -3
  9. package/dist/cjs/actor/views.js +9 -1
  10. package/dist/cjs/affiliation/index.js +126 -0
  11. package/dist/cjs/combo/ask/options.js +1 -1
  12. package/dist/cjs/combo/base.js +1 -1
  13. package/dist/cjs/constants.js +6 -3
  14. package/dist/cjs/defaults/ask/controls.js +1 -1
  15. package/dist/cjs/defaults/ask/phrases.js +1 -1
  16. package/dist/cjs/defaults/ask/templates.js +35 -4
  17. package/dist/cjs/element/role/index.js +7 -0
  18. package/dist/cjs/element/role/miso-affiliation.js +20 -0
  19. package/dist/cjs/layout/affiliation/affiliation.js +330 -0
  20. package/dist/cjs/layout/banner/banner.js +1 -1
  21. package/dist/cjs/layout/container/container.js +1 -1
  22. package/dist/cjs/layout/error/error.js +1 -1
  23. package/dist/cjs/layout/index.js +7 -0
  24. package/dist/cjs/layout/input/option-list.js +35 -50
  25. package/dist/cjs/layout/input/search-box.js +227 -129
  26. package/dist/cjs/layout/list/cards.js +1 -1
  27. package/dist/cjs/layout/list/carousel.js +5 -3
  28. package/dist/cjs/layout/list/collection.js +44 -49
  29. package/dist/cjs/layout/list/list.js +1 -1
  30. package/dist/cjs/layout/radio/feedback.js +1 -1
  31. package/dist/cjs/layout/radio/radio.js +1 -1
  32. package/dist/cjs/layout/raf.js +1 -1
  33. package/dist/cjs/layout/template.js +1 -1
  34. package/dist/cjs/layout/templates.js +172 -66
  35. package/dist/cjs/layout/text/text.js +1 -1
  36. package/dist/cjs/layout/text/typewriter/index.js +3 -3
  37. package/dist/cjs/layout/trackable.js +124 -0
  38. package/dist/cjs/plugin.js +1 -1
  39. package/dist/cjs/source/index.js +20 -8
  40. package/dist/cjs/util/bindings.js +58 -110
  41. package/dist/cjs/util/states.js +31 -24
  42. package/dist/cjs/util/trackers.js +75 -0
  43. package/dist/cjs/util/viewables.js +55 -0
  44. package/dist/cjs/version.js +1 -1
  45. package/dist/cjs/workflow/ask.js +60 -19
  46. package/dist/cjs/workflow/asks.js +1 -1
  47. package/dist/cjs/workflow/base.js +6 -7
  48. package/dist/cjs/workflow/explore.js +5 -2
  49. package/dist/cjs/workflow/options.js +60 -14
  50. package/dist/cjs/workflow/recommendation.js +2 -0
  51. package/dist/cjs/workflow/search.js +35 -7
  52. package/package.json +2 -2
  53. package/src/actor/autocomplete.js +131 -0
  54. package/src/actor/data.js +3 -10
  55. package/src/actor/fields.js +8 -0
  56. package/src/actor/index.js +1 -0
  57. package/src/actor/tracker.js +39 -62
  58. package/src/actor/trackers.js +3 -1
  59. package/src/actor/utils.js +14 -2
  60. package/src/actor/view.js +12 -1
  61. package/src/actor/views.js +11 -0
  62. package/src/affiliation/index.js +108 -0
  63. package/src/constants.js +10 -1
  64. package/src/defaults/ask/phrases.js +1 -1
  65. package/src/defaults/ask/templates.js +34 -2
  66. package/src/element/role/index.js +1 -0
  67. package/src/element/role/miso-affiliation.js +16 -0
  68. package/src/layout/affiliation/affiliation.js +295 -0
  69. package/src/layout/index.js +1 -0
  70. package/src/layout/input/option-list.js +35 -43
  71. package/src/layout/input/search-box.js +192 -95
  72. package/src/layout/list/carousel.js +4 -2
  73. package/src/layout/list/collection.js +42 -43
  74. package/src/layout/templates.js +127 -46
  75. package/src/layout/text/typewriter/index.js +2 -2
  76. package/src/layout/trackable.js +106 -0
  77. package/src/source/index.js +14 -1
  78. package/src/util/bindings.js +47 -103
  79. package/src/util/states.js +26 -20
  80. package/src/util/trackers.js +69 -0
  81. package/src/util/viewables.js +47 -0
  82. package/src/version.js +1 -1
  83. package/src/workflow/ask.js +37 -3
  84. package/src/workflow/base.js +2 -3
  85. package/src/workflow/explore.js +1 -1
  86. package/src/workflow/options.js +54 -13
  87. package/src/workflow/recommendation.js +1 -0
  88. package/src/workflow/search.js +33 -1
  89. package/dist/cjs/util/tracker.js +0 -348
  90. package/src/util/tracker.js +0 -318
@@ -7,12 +7,16 @@ 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 _index = require("../actor/index.js");
10
+ var sources = _interopRequireWildcard(require("../source/index.js"));
11
+ var _index2 = require("../actor/index.js");
11
12
  var _constants = require("../constants.js");
12
- var _index2 = require("../layout/index.js");
13
+ var _index3 = require("../layout/index.js");
14
+ var _index4 = require("../affiliation/index.js");
13
15
  const _excluded = ["q", "qs"];
16
+ 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); }
17
+ 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
18
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
- 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; }
19
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; }
16
20
  const DEFAULT_API_OPTIONS = Object.freeze({
17
21
  group: _commons.API.GROUP.ASK,
18
22
  name: _commons.API.NAME.QUESTIONS,
@@ -24,34 +28,47 @@ const DEFAULT_API_OPTIONS = Object.freeze({
24
28
  cite_end: ']'
25
29
  }
26
30
  });
31
+ const DEFAULT_AUTOCOMPLETE_OPTIONS = Object.freeze({
32
+ actor: false,
33
+ api: {
34
+ group: _commons.API.GROUP.ASK,
35
+ name: _commons.API.NAME.AUTOCOMPLETE
36
+ }
37
+ });
27
38
  const DEFAULT_LAYOUTS = Object.freeze({
28
- [_constants.ROLE.QUERY]: [_index2.SearchBoxLayout.type, {
39
+ [_constants.ROLE.QUERY]: [_index3.SearchBoxLayout.type, {
29
40
  placeholder: 'Ask a question'
30
41
  }],
31
- [_constants.ROLE.QUESTION]: [_index2.TextLayout.type, {
42
+ [_constants.ROLE.QUESTION]: [_index3.TextLayout.type, {
32
43
  tag: 'h2'
33
44
  }],
34
- [_constants.ROLE.ANSWER]: _index2.TypewriterLayout.type,
35
- [_constants.ROLE.FEEDBACK]: _index2.FeedbackLayout.type,
36
- [_constants.ROLE.SOURCES]: [_index2.ListLayout.type, {
45
+ [_constants.ROLE.ANSWER]: _index3.TypewriterLayout.type,
46
+ [_constants.ROLE.FEEDBACK]: _index3.FeedbackLayout.type,
47
+ [_constants.ROLE.SOURCES]: [_index3.ListLayout.type, {
37
48
  incremental: true,
38
49
  itemType: 'article',
39
50
  templates: {
40
51
  ordered: true
41
52
  }
42
53
  }],
43
- [_constants.ROLE.RELATED_RESOURCES]: [_index2.ListLayout.type, {
54
+ [_constants.ROLE.RELATED_RESOURCES]: [_index3.ListLayout.type, {
44
55
  incremental: true,
45
56
  itemType: 'article'
46
57
  }],
47
- [_constants.ROLE.QUERY_SUGGESTIONS]: _index2.OptionListLayout.type
58
+ [_constants.ROLE.QUERY_SUGGESTIONS]: _index3.OptionListLayout.type,
59
+ [_constants.ROLE.AFFILIATION]: [_index3.AffiliationLayout.type, {
60
+ incremental: true,
61
+ itemType: 'affiliation',
62
+ link: {
63
+ rel: 'noopener nofollow'
64
+ }
65
+ }]
48
66
  });
49
67
  const DEFAULT_TRACKERS = Object.freeze({
50
68
  [_constants.ROLE.SOURCES]: {},
51
69
  [_constants.ROLE.RELATED_RESOURCES]: {},
70
+ [_constants.ROLE.AFFILIATION]: {},
52
71
  [_constants.ROLE.QUERY_SUGGESTIONS]: {
53
- active: true,
54
- // we are tracking events at initial stage, when session is not active yet
55
72
  click: {
56
73
  validate: event => event.button === 0 // left click only
57
74
  }
@@ -59,6 +76,7 @@ const DEFAULT_TRACKERS = Object.freeze({
59
76
  });
60
77
  const DEFAULT_OPTIONS = Object.freeze({
61
78
  api: DEFAULT_API_OPTIONS,
79
+ autocomplete: DEFAULT_AUTOCOMPLETE_OPTIONS,
62
80
  layouts: DEFAULT_LAYOUTS,
63
81
  trackers: DEFAULT_TRACKERS
64
82
  });
@@ -75,9 +93,17 @@ class Ask extends _base.default {
75
93
  (0, _commons.defineValues)(this, {
76
94
  parentQuestionId
77
95
  });
78
- this._feedback = new _index.FeedbackActor(this._hub);
96
+ this._feedback = new _index2.FeedbackActor(this._hub);
79
97
  this._setSuggestedQuestions();
80
- this._unsubscribes = [...this._unsubscribes, this._hub.on(_index.fields.query(), payload => this.query(payload)), this._hub.on(_index.fields.view(_constants.ROLE.ANSWER), data => this._onAnswerViewUpdate(data)), this._views.get(_constants.ROLE.ANSWER).on('citation-click', event => this._onCitationClick(event))];
98
+
99
+ /*
100
+ this._autocomplete = new AutocompleteActor(this._hub, {
101
+ source: sources.api(this._client),
102
+ options: this._options,
103
+ });
104
+ */
105
+
106
+ 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
107
  parentQuestionId && context._byPqid.set(parentQuestionId, this);
82
108
  context._events.emit('create', this);
83
109
  this.reset(); // create a session so query suggestions can be tracked
@@ -163,7 +189,7 @@ class Ask extends _base.default {
163
189
  session
164
190
  } = this;
165
191
  session.meta.question_source = questionSource;
166
- this._hub.update(_index.fields.request(), (0, _options.mergeApiOptions)(this._options.resolved.api, {
192
+ this._hub.update(_index2.fields.request(), (0, _options.mergeApiOptions)(this._options.resolved.api, {
167
193
  payload,
168
194
  session
169
195
  }));
@@ -175,7 +201,7 @@ class Ask extends _base.default {
175
201
  session,
176
202
  status,
177
203
  ongoing
178
- } = this._hub.states[_index.fields.view(_constants.ROLE.ANSWER)] || {};
204
+ } = this._hub.states[_index2.fields.view(_constants.ROLE.ANSWER)] || {};
179
205
  if (session && status !== _constants.STATUS.INITIAL && (status !== _constants.STATUS.READY || ongoing)) {
180
206
  // it's interrupted by a new question
181
207
  const state = Object.freeze({
@@ -188,6 +214,18 @@ class Ask extends _base.default {
188
214
  }
189
215
  super.restart();
190
216
  }
217
+
218
+ /*
219
+ updateCompletions(event) {
220
+ // TODO: verify
221
+ this._hub.update(fields.completions(), {
222
+ ...event,
223
+ source: 'manual',
224
+ });
225
+ return this;
226
+ }
227
+ */
228
+
191
229
  _defaultProcessData(data) {
192
230
  data = super._defaultProcessData(data);
193
231
  const {
@@ -220,6 +258,9 @@ class Ask extends _base.default {
220
258
  }
221
259
  }
222
260
 
261
+ // affiliation
262
+ data = (0, _index4.processData)(data);
263
+
223
264
  // 1. put answer_stage to meta
224
265
  // 2. mark ongoing flag
225
266
  return Object.assign({}, data, {
@@ -258,9 +299,9 @@ class Ask extends _base.default {
258
299
  if (!previous) {
259
300
  return;
260
301
  }
261
- const values = previous.states[_index.fields.data()].value;
302
+ const values = previous.states[_index2.fields.data()].value;
262
303
  const value = values.suggested_followup_questions || values.followup_questions || [];
263
- this._hub.update(_index.fields.suggestions(), {
304
+ this._hub.update(_index2.fields.suggestions(), {
264
305
  value: value.map(text => ({
265
306
  text
266
307
  }))
@@ -272,7 +313,7 @@ class Ask extends _base.default {
272
313
  } = _ref3;
273
314
  const {
274
315
  value
275
- } = this.states[_index.fields.data()] || {};
316
+ } = this.states[_index2.fields.data()] || {};
276
317
  const {
277
318
  sources
278
319
  } = value || {};
@@ -8,7 +8,7 @@ var _context = _interopRequireDefault(require("./context.js"));
8
8
  var _ask = _interopRequireDefault(require("./ask.js"));
9
9
  const _excluded = ["root", "events"];
10
10
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
- 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; }
11
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; }
12
12
  class Asks extends _context.default {
13
13
  constructor(plugin, client) {
14
14
  super('asks', plugin, client);
@@ -16,7 +16,7 @@ const _excluded = ["layouts", "interactions"],
16
16
  _excluded3 = ["context"];
17
17
  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); }
18
18
  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; }
19
- 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; }
19
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; }
20
20
  const DEFAULT_LAYOUTS = Object.freeze({
21
21
  [_constants.ROLE.CONTAINER]: _index3.ContainerLayout.type,
22
22
  [_constants.ROLE.ERROR]: _index3.ErrorLayout.type
@@ -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, {
@@ -73,14 +72,14 @@ class Workflow extends _commons.Component {
73
72
  options,
74
73
  workflow: name
75
74
  });
76
- this._interactions = new _index.InteractionsActor(hub, {
77
- client,
78
- options
79
- });
80
75
  this._trackers = new _index.Trackers(hub, {
81
76
  views,
82
77
  options
83
78
  });
79
+ this._interactions = new _index.InteractionsActor(hub, {
80
+ client,
81
+ options
82
+ });
84
83
  this._unsubscribes = [this._hub.on(_index.fields.response(), data => this.updateData(data))];
85
84
  }
86
85
  get uuid() {
@@ -12,14 +12,17 @@ var _constants = require("../constants.js");
12
12
  var _index2 = require("../layout/index.js");
13
13
  const _excluded = ["value"];
14
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
- 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; }
15
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; }
16
16
  const DEFAULT_API_OPTIONS = Object.freeze({
17
17
  group: _commons.API.GROUP.ASK,
18
18
  name: _commons.API.NAME.RELATED_QUESTIONS
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,23 +6,26 @@ 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;
17
19
  exports.normalizeTrackers = normalizeTrackers;
18
20
  var _commons = require("@miso.ai/commons");
19
21
  var _constants = require("../constants.js");
20
- 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; }
22
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; }
21
23
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
22
24
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
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
@@ -32,10 +35,15 @@ function normalizeApiOptions() {
32
35
  payload = name;
33
36
  name = undefined;
34
37
  }
38
+ let group = undefined;
39
+ if (name && name.indexOf('/') !== -1) {
40
+ [group, name] = name.split('/');
41
+ }
35
42
  if (name && typeof name !== 'string' || payload !== undefined && typeof payload !== 'object') {
36
43
  throw new Error(`Invalid arguments for useApi(): ${name}, ${payload}`);
37
44
  }
38
45
  return (0, _commons.trimObj)({
46
+ group,
39
47
  name,
40
48
  payload
41
49
  });
@@ -131,6 +139,20 @@ function normalizeInteractionsOptions(options) {
131
139
  preprocess
132
140
  });
133
141
  }
142
+ function normalizeAutocompleteOptions(options) {
143
+ if (options === undefined) {
144
+ throw new Error(`Expect autocomplete options to be an object or a boolean value: ${options}`);
145
+ }
146
+ if (typeof options === 'boolean') {
147
+ options = {
148
+ actor: options
149
+ };
150
+ }
151
+ const processData = normalizeDataProcessorOptions(options.processData);
152
+ return Object.assign({}, options, {
153
+ processData
154
+ });
155
+ }
134
156
 
135
157
  // merge //
136
158
  function mergeApiOptions() {
@@ -217,6 +239,18 @@ function mergeInteractionsOptions() {
217
239
  preprocess: concatArrays(merged.preprocess, options.preprocess)
218
240
  })));
219
241
  }
242
+ function mergeAutocompleteOptions() {
243
+ for (var _len6 = arguments.length, optionsList = new Array(_len6), _key7 = 0; _key7 < _len6; _key7++) {
244
+ optionsList[_key7] = arguments[_key7];
245
+ }
246
+ if (optionsList[optionsList.length - 1] === false) {
247
+ return false;
248
+ }
249
+ return mergeOptions(optionsList, (merged, options) => Object.assign(merged, Object.assign({}, options, {
250
+ api: mergeApiOptions(merged.api, options.api),
251
+ processData: mergeDataProcessorOptions(merged.processData, options.processData)
252
+ })));
253
+ }
220
254
 
221
255
  // manifest //
222
256
  const FEATURES = [{
@@ -239,6 +273,10 @@ const FEATURES = [{
239
273
  key: 'interactions',
240
274
  normalize: normalizeInteractionsOptions,
241
275
  merge: mergeInteractionsOptions
276
+ }, {
277
+ key: 'autocomplete',
278
+ normalize: normalizeAutocompleteOptions,
279
+ merge: mergeAutocompleteOptions
242
280
  }];
243
281
  class WorkflowContextOptions {
244
282
  constructor() {
@@ -339,21 +377,29 @@ for (const {
339
377
  }
340
378
  });
341
379
  }
380
+ const DEFAULT_FEATURES = ['api', 'layouts', 'dataProcessor', 'trackers', 'interactions'];
342
381
  function makeConfigurable(prototype) {
343
- Object.assign(prototype, {
344
- useApi() {
345
- for (var _len6 = arguments.length, args = new Array(_len6), _key7 = 0; _key7 < _len6; _key7++) {
346
- args[_key7] = arguments[_key7];
382
+ let features = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_FEATURES;
383
+ for (const feature of features) {
384
+ injectConfigurableFeature(prototype, feature);
385
+ }
386
+ }
387
+ function injectConfigurableFeature(prototype, feature) {
388
+ if (feature === 'api') {
389
+ Object.assign(prototype, {
390
+ useApi() {
391
+ for (var _len7 = arguments.length, args = new Array(_len7), _key8 = 0; _key8 < _len7; _key8++) {
392
+ args[_key8] = arguments[_key8];
393
+ }
394
+ this._options.api.merge(args);
395
+ return this;
396
+ },
397
+ clearApi() {
398
+ this._options.api.set();
399
+ return this;
347
400
  }
348
- this._options.api.merge(args);
349
- return this;
350
- },
351
- clearApi() {
352
- this._options.api.set();
353
- return this;
354
- }
355
- });
356
- for (const feature of ['layouts', 'dataProcessor', 'trackers', 'interactions']) {
401
+ });
402
+ } else {
357
403
  const upperCased = upperCase(feature);
358
404
  Object.assign(prototype, {
359
405
  [`use${upperCased}`](value) {
@@ -57,6 +57,8 @@ class Recommendation extends _base.default {
57
57
  }));
58
58
  return this;
59
59
  }
60
+
61
+ // TODO: deprecate this
60
62
  startTracker() {
61
63
  this.useApi(false);
62
64
  this.useLayouts(false);
@@ -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 _index = require("../actor/index.js");
10
+ var sources = _interopRequireWildcard(require("../source/index.js"));
11
+ var _index2 = require("../actor/index.js");
11
12
  var _constants = require("../constants.js");
12
- var _index2 = require("../layout/index.js");
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]: _index2.SearchBoxLayout.type,
23
- [_constants.ROLE.PRODUCTS]: _index2.ListLayout.type
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._unsubscribes.push(this._hub.on(_index.fields.query(), payload => this.query(payload)));
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(_index.fields.request(), (0, _options.mergeApiOptions)(this._options.resolved.api, {
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
@@ -26,7 +26,7 @@
26
26
  "url": "https://github.com/MisoAI/miso-client-js-sdk/issues"
27
27
  },
28
28
  "dependencies": {
29
- "@miso.ai/commons": "1.10.0-beta.0"
29
+ "@miso.ai/commons": "1.10.0-beta.10"
30
30
  },
31
- "version": "1.10.0-beta.0"
31
+ "version": "1.10.0-beta.10"
32
32
  }
@@ -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._isCurrentSession(session)) {
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._isCurrentSession(response.session) && this._emitResponse(response);
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) {
@@ -37,3 +37,11 @@ export function interaction() {
37
37
  export function feedback() {
38
38
  return 'feedback';
39
39
  }
40
+
41
+ export function input() {
42
+ return 'input';
43
+ }
44
+
45
+ export function completions() {
46
+ return 'completions';
47
+ }
@@ -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';