@miso.ai/client-sdk-ui 1.11.0-beta.0 → 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.
Files changed (118) hide show
  1. package/dist/cjs/actor/data.js +6 -7
  2. package/dist/cjs/actor/feedback.js +6 -39
  3. package/dist/cjs/actor/fields.js +14 -6
  4. package/dist/cjs/actor/hub.js +1 -2
  5. package/dist/cjs/actor/index.js +0 -7
  6. package/dist/cjs/actor/interactions.js +4 -15
  7. package/dist/cjs/actor/sessions.js +2 -33
  8. package/dist/cjs/actor/tracker.js +25 -26
  9. package/dist/cjs/actor/utils.js +0 -49
  10. package/dist/cjs/actor/view.js +40 -40
  11. package/dist/cjs/actor/views.js +32 -8
  12. package/dist/cjs/asset/svgs.js +18 -8
  13. package/dist/cjs/constants.js +18 -19
  14. package/dist/cjs/defaults/hybrid-search/answer-box.js +19 -3
  15. package/dist/cjs/defaults/hybrid-search/phrases.js +5 -5
  16. package/dist/cjs/defaults/hybrid-search/templates.js +37 -9
  17. package/dist/cjs/element/role/index.js +12 -5
  18. package/dist/cjs/element/role/{miso-hits.js → miso-more.js} +4 -4
  19. package/dist/cjs/element/role/miso-total.js +20 -0
  20. package/dist/cjs/layout/affiliation/affiliation.js +0 -3
  21. package/dist/cjs/layout/banner/banner.js +0 -4
  22. package/dist/cjs/layout/button/more-button.js +73 -0
  23. package/dist/cjs/layout/container/container.js +0 -3
  24. package/dist/cjs/layout/error/error.js +0 -4
  25. package/dist/cjs/layout/index.js +7 -0
  26. package/dist/cjs/layout/input/facets.js +5 -5
  27. package/dist/cjs/layout/input/option-list.js +0 -4
  28. package/dist/cjs/layout/input/search-box.js +33 -12
  29. package/dist/cjs/layout/list/cards.js +0 -3
  30. package/dist/cjs/layout/list/carousel.js +0 -3
  31. package/dist/cjs/layout/list/collection.js +25 -7
  32. package/dist/cjs/layout/list/list.js +0 -3
  33. package/dist/cjs/layout/radio/feedback.js +0 -3
  34. package/dist/cjs/layout/radio/radio.js +0 -4
  35. package/dist/cjs/layout/raf.js +4 -2
  36. package/dist/cjs/layout/text/text.js +0 -4
  37. package/dist/cjs/layout/text/typewriter/index.js +3 -3
  38. package/dist/cjs/layout/triggerable.js +79 -0
  39. package/dist/cjs/util/states.js +0 -15
  40. package/dist/cjs/version.js +1 -1
  41. package/dist/cjs/workflow/answer-based.js +109 -111
  42. package/dist/cjs/workflow/ask.js +35 -27
  43. package/dist/cjs/workflow/asks.js +1 -1
  44. package/dist/cjs/workflow/autocompletable.js +33 -0
  45. package/dist/cjs/workflow/autocomplete.js +122 -0
  46. package/dist/cjs/workflow/base.js +169 -102
  47. package/dist/cjs/workflow/explore.js +26 -19
  48. package/dist/cjs/workflow/hybrid-search-answer.js +99 -0
  49. package/dist/cjs/workflow/hybrid-search-results.js +70 -0
  50. package/dist/cjs/workflow/hybrid-search-views.js +122 -0
  51. package/dist/cjs/workflow/hybrid-search.js +98 -103
  52. package/dist/cjs/workflow/options.js +32 -17
  53. package/dist/cjs/workflow/processors.js +185 -17
  54. package/dist/cjs/workflow/recommendation.js +36 -49
  55. package/dist/cjs/workflow/search-based.js +186 -0
  56. package/dist/cjs/workflow/search.js +21 -68
  57. package/package.json +2 -2
  58. package/src/actor/data.js +2 -4
  59. package/src/actor/feedback.js +6 -23
  60. package/src/actor/fields.js +14 -6
  61. package/src/actor/hub.js +1 -2
  62. package/src/actor/index.js +0 -1
  63. package/src/actor/interactions.js +4 -10
  64. package/src/actor/sessions.js +3 -30
  65. package/src/actor/tracker.js +25 -19
  66. package/src/actor/utils.js +0 -47
  67. package/src/actor/view.js +27 -15
  68. package/src/actor/views.js +36 -8
  69. package/src/asset/svgs.js +19 -7
  70. package/src/constants.js +25 -16
  71. package/src/defaults/hybrid-search/answer-box.js +17 -5
  72. package/src/defaults/hybrid-search/phrases.js +4 -4
  73. package/src/defaults/hybrid-search/templates.js +25 -9
  74. package/src/element/role/index.js +2 -1
  75. package/src/element/role/{miso-hits.js → miso-more.js} +3 -3
  76. package/src/element/role/miso-total.js +16 -0
  77. package/src/layout/affiliation/affiliation.js +1 -5
  78. package/src/layout/banner/banner.js +0 -5
  79. package/src/layout/button/more-button.js +69 -0
  80. package/src/layout/container/container.js +1 -5
  81. package/src/layout/error/error.js +0 -5
  82. package/src/layout/index.js +2 -1
  83. package/src/layout/input/facets.js +5 -6
  84. package/src/layout/input/option-list.js +0 -5
  85. package/src/layout/input/search-box.js +27 -14
  86. package/src/layout/list/cards.js +0 -4
  87. package/src/layout/list/carousel.js +0 -4
  88. package/src/layout/list/collection.js +22 -9
  89. package/src/layout/list/list.js +0 -4
  90. package/src/layout/radio/feedback.js +0 -4
  91. package/src/layout/radio/radio.js +0 -5
  92. package/src/layout/raf.js +2 -2
  93. package/src/layout/text/text.js +0 -5
  94. package/src/layout/text/typewriter/index.js +4 -5
  95. package/src/layout/trackable.js +1 -1
  96. package/src/layout/triggerable.js +76 -0
  97. package/src/util/states.js +0 -14
  98. package/src/version.js +1 -1
  99. package/src/workflow/answer-based.js +101 -77
  100. package/src/workflow/ask.js +33 -25
  101. package/src/workflow/asks.js +1 -1
  102. package/src/workflow/autocompletable.js +29 -0
  103. package/src/workflow/autocomplete.js +113 -0
  104. package/src/workflow/base.js +147 -93
  105. package/src/workflow/explore.js +23 -8
  106. package/src/workflow/hybrid-search-answer.js +92 -0
  107. package/src/workflow/hybrid-search-results.js +63 -0
  108. package/src/workflow/hybrid-search-views.js +124 -0
  109. package/src/workflow/hybrid-search.js +102 -73
  110. package/src/workflow/options.js +26 -11
  111. package/src/workflow/processors.js +165 -14
  112. package/src/workflow/recommendation.js +32 -33
  113. package/src/workflow/search-based.js +183 -0
  114. package/src/workflow/search.js +21 -65
  115. package/dist/cjs/actor/autocomplete.js +0 -160
  116. package/dist/cjs/workflow/utils.js +0 -42
  117. package/src/actor/autocomplete.js +0 -133
  118. package/src/workflow/utils.js +0 -29
@@ -40,9 +40,6 @@ function chevron(layout) {
40
40
  return `<svg class="${className}__control-button" shape-rendering="geometricPrecision" stroke="currentColor" stroke-width="24" fill="#fff" viewBox="-30 -30 358 572"><path d="M285.77 441c16.24 16.17 16.32 42.46.15 58.7-16.16 16.24-42.45 16.32-58.69.16l-215-214.47c-16.24-16.16-16.32-42.45-.15-58.69L227.23 12.08c16.24-16.17 42.53-16.09 58.69.15 16.17 16.24 16.09 42.54-.15 58.7l-185.5 185.04L285.77 441z"/></svg>`;
41
41
  }
42
42
  class CarouselLayout extends _collection.default {
43
- static get category() {
44
- return super.category;
45
- }
46
43
  static get type() {
47
44
  return TYPE;
48
45
  }
@@ -7,6 +7,7 @@ exports.default = void 0;
7
7
  var _constants = require("../../constants.js");
8
8
  var _template = _interopRequireDefault(require("../template.js"));
9
9
  var _trackable = require("../trackable.js");
10
+ var _triggerable = require("../triggerable.js");
10
11
  var _templates = require("../templates.js");
11
12
  const _excluded = ["templates", "itemType"];
12
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -21,7 +22,7 @@ function root(layout, state) {
21
22
  status
22
23
  } = state;
23
24
  const roleAttr = role ? `data-role="${role}"` : '';
24
- return `<div class="${className} ${status}" ${roleAttr}>${status === _constants.STATUS.READY ? templates[status](layout, state) : ''}</div>`;
25
+ return `<div class="${className} ${status}" ${roleAttr}>${status === _constants.STATUS.READY ? templates[status](layout, state) : ''}${templates.trigger(layout, state)}${templates.loadingBar(layout, state)}</div>`;
25
26
  }
26
27
  function ready(layout, state) {
27
28
  const {
@@ -31,6 +32,7 @@ function ready(layout, state) {
31
32
 
32
33
  // TODO: handle categories, attributes, etc. by introducing sublayout
33
34
  if (values && values.length > 0 || state.ongoing) {
35
+ // TODO: ad-hoc ongoing?
34
36
  return templates.list(layout, state, values);
35
37
  } else {
36
38
  return templates.empty(layout, state);
@@ -70,6 +72,18 @@ function item(layout, state, value, index) {
70
72
  });
71
73
  return `<li class="${className}__item">${body}</li>`;
72
74
  }
75
+ function trigger(layout, state) {
76
+ const {
77
+ className
78
+ } = layout;
79
+ return `<div class="${className}__trigger" data-role="trigger"></div>`;
80
+ }
81
+ function loadingBar(layout, state) {
82
+ const {
83
+ className
84
+ } = layout;
85
+ return `<div class="${className}__loading-bar"></div>`;
86
+ }
73
87
 
74
88
  // TODO: let templates.js control what to be included here
75
89
 
@@ -95,12 +109,11 @@ const DEFAULT_TEMPLATES = Object.freeze({
95
109
  ctaBlock: _templates.ctaBlock,
96
110
  cta: _templates.cta,
97
111
  imageBlock: _templates.imageBlock,
98
- indexBlock: _templates.indexBlock
112
+ indexBlock: _templates.indexBlock,
113
+ trigger,
114
+ loadingBar
99
115
  });
100
116
  class CollectionLayout extends _template.default {
101
- static get category() {
102
- return _constants.LAYOUT_CATEGORY.LIST;
103
- }
104
117
  static get defaultTemplates() {
105
118
  return DEFAULT_TEMPLATES;
106
119
  }
@@ -115,6 +128,7 @@ class CollectionLayout extends _template.default {
115
128
  itemType
116
129
  }, options));
117
130
  this._initTrackable();
131
+ this._initTriggerable();
118
132
  }
119
133
  initialize(view) {
120
134
  this._unsubscribes.push(view.proxyElement.on('click', this._onClick.bind(this)));
@@ -133,7 +147,7 @@ class CollectionLayout extends _template.default {
133
147
  }
134
148
  _shallRenderIncrementally(state, rendered) {
135
149
  // TODO: compare item ids as well
136
- return this.options.incremental && rendered && rendered.value && rendered.value.length > 0 && state.status === _constants.STATUS.READY && rendered.status === _constants.STATUS.READY && state.session && rendered.session && state.session.id === rendered.session.id;
150
+ return this.options.incremental && rendered && rendered.value && rendered.value.length > 0 && state.value && state.value.length >= rendered.value.length && state.session && rendered.session && state.session.id === rendered.session.id;
137
151
  }
138
152
  _html(state, rendered, incremental) {
139
153
  if (incremental) {
@@ -170,9 +184,11 @@ class CollectionLayout extends _template.default {
170
184
  }
171
185
  _afterRender(element, state) {
172
186
  this._syncBindings(element, state);
187
+ this._syncTrigger(element, state);
173
188
  }
174
189
  _unrender() {
175
190
  this._clearBindings();
191
+ this._untrackTrigger();
176
192
  }
177
193
  _getItems(state) {
178
194
  return state.value;
@@ -212,9 +228,11 @@ class CollectionLayout extends _template.default {
212
228
  }
213
229
  destroy() {
214
230
  this._destroyTrackable();
231
+ this._destroyTriggerable();
215
232
  this._view = undefined;
216
233
  super.destroy();
217
234
  }
218
235
  }
219
236
  exports.default = CollectionLayout;
220
- (0, _trackable.makeTrackable)(CollectionLayout.prototype);
237
+ (0, _trackable.makeTrackable)(CollectionLayout.prototype);
238
+ (0, _triggerable.makeTriggerable)(CollectionLayout.prototype);
@@ -11,9 +11,6 @@ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t =
11
11
  const TYPE = 'list';
12
12
  const DEFAULT_CLASSNAME = 'miso-list';
13
13
  class ListLayout extends _collection.default {
14
- static get category() {
15
- return super.category;
16
- }
17
14
  static get type() {
18
15
  return TYPE;
19
16
  }
@@ -61,9 +61,6 @@ const DEFAULT_TEMPLATES = Object.freeze({
61
61
  text
62
62
  });
63
63
  class FeedbackLayout extends _radio.default {
64
- static get category() {
65
- return super.category;
66
- }
67
64
  static get type() {
68
65
  return TYPE;
69
66
  }
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _commons = require("@miso.ai/commons");
8
- var _constants = require("../../constants.js");
9
8
  var _template = _interopRequireDefault(require("../template.js"));
10
9
  var _templates = require("../templates.js");
11
10
  const _excluded = ["className", "templates", "field", "defaultValue"];
@@ -40,9 +39,6 @@ const DEFAULT_TEMPLATES = Object.freeze(Object.assign({}, (0, _templates.require
40
39
  option
41
40
  }));
42
41
  class RadioLayout extends _template.default {
43
- static get category() {
44
- return _constants.LAYOUT_CATEGORY.RADIO;
45
- }
46
42
  static get defaultTemplates() {
47
43
  return DEFAULT_TEMPLATES;
48
44
  }
@@ -5,19 +5,21 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _commons = require("@miso.ai/commons");
8
- const _excluded = ["role", "workflow"];
8
+ const _excluded = ["role", "workflow", "workflowOptions"];
9
9
  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; }
10
10
  class RafLayout {
11
11
  constructor() {
12
12
  let _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
13
13
  let {
14
14
  role,
15
- workflow
15
+ workflow,
16
+ workflowOptions
16
17
  } = _ref,
17
18
  options = _objectWithoutPropertiesLoose(_ref, _excluded);
18
19
  (0, _commons.defineValues)(this, {
19
20
  role,
20
21
  workflow,
22
+ workflowOptions,
21
23
  options
22
24
  });
23
25
  this._unsubscribes = [];
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _commons = require("@miso.ai/commons");
8
- var _constants = require("../../constants.js");
9
8
  var _template = _interopRequireDefault(require("../template.js"));
10
9
  const _excluded = ["className", "templates", "tag"];
11
10
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -60,9 +59,6 @@ const DEFAULT_TEMPLATES = Object.freeze({
60
59
  root
61
60
  });
62
61
  class TextLayout extends _template.default {
63
- static get category() {
64
- return _constants.LAYOUT_CATEGORY.TEXT;
65
- }
66
62
  static get type() {
67
63
  return TYPE;
68
64
  }
@@ -15,9 +15,6 @@ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t =
15
15
  const TYPE = 'typewriter';
16
16
  const DEFAULT_CLASSNAME = 'miso-typewriter';
17
17
  class TypewriterLayout extends _progressive.default {
18
- static get category() {
19
- return _constants.LAYOUT_CATEGORY.TEXT;
20
- }
21
18
  static get type() {
22
19
  return TYPE;
23
20
  }
@@ -77,6 +74,9 @@ class TypewriterLayout extends _progressive.default {
77
74
  }
78
75
  async _setupForMarkdown() {
79
76
  const context = await this._view._views._extensions.require('markdown');
77
+ if (!this._view) {
78
+ return; // destroyed
79
+ }
80
80
  const cursorClass = (0, _utils.cursorClassName)(this.className);
81
81
  const {
82
82
  onDebug,
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.TriggerableMixin = void 0;
7
+ exports.makeTriggerable = makeTriggerable;
8
+ var _commons = require("@miso.ai/commons");
9
+ var _constants = require("../constants.js");
10
+ var _index = require("../actor/index.js");
11
+ function makeTriggerable(prototype) {
12
+ (0, _commons.mixin)(prototype, TriggerableMixin.prototype);
13
+ }
14
+ class TriggerableMixin {
15
+ _initTriggerable() {
16
+ this._trigger = undefined;
17
+ }
18
+ _syncTrigger(element, state) {
19
+ if (!this.options.infiniteScroll) {
20
+ return;
21
+ }
22
+ const workflowPaginationOptions = this.workflowOptions.pagination;
23
+ if (!workflowPaginationOptions.active || workflowPaginationOptions.mode !== 'infiniteScroll') {
24
+ return;
25
+ }
26
+ // only track trigger when ready
27
+ if (state.status === _constants.STATUS.READY) {
28
+ this._trackTrigger(element);
29
+ } else {
30
+ this._untrackTrigger();
31
+ }
32
+ }
33
+ async _trackTrigger(element) {
34
+ if (this._trigger) {
35
+ return;
36
+ }
37
+ const triggerElement = element.querySelector('[data-role="trigger"]');
38
+ if (!triggerElement) {
39
+ return;
40
+ }
41
+ const ac = new AbortController();
42
+ this._trigger = Object.freeze({
43
+ element: triggerElement,
44
+ ac
45
+ });
46
+ let result = false;
47
+ try {
48
+ await (0, _commons.viewable)(triggerElement, {
49
+ area: 1,
50
+ duration: 0,
51
+ signal: ac.signal
52
+ });
53
+ result = true;
54
+ } catch (e) {
55
+ if (e.name !== 'AbortError') {
56
+ throw e;
57
+ }
58
+ } finally {
59
+ this._trigger = undefined;
60
+ }
61
+ if (result) {
62
+ this._onTrigger();
63
+ }
64
+ }
65
+ _onTrigger() {
66
+ this._view.hub.trigger(_index.fields.more());
67
+ }
68
+ _untrackTrigger() {
69
+ if (!this._trigger) {
70
+ return;
71
+ }
72
+ this._trigger.ac && this._trigger.ac.abort();
73
+ this._trigger = undefined;
74
+ }
75
+ _destroyTriggerable() {
76
+ this._untrackTrigger();
77
+ }
78
+ }
79
+ exports.TriggerableMixin = TriggerableMixin;
@@ -15,21 +15,6 @@ const {
15
15
  UNTRACKED,
16
16
  TRIGGERED
17
17
  } = _constants.TRACKING_STATUS;
18
-
19
- /*
20
- const STATES = {
21
- NEW: Object.freeze({
22
- [IMPRESSION]: UNTRACKED,
23
- [VIEWABLE]: UNTRACKED,
24
- }),
25
- UNTRACKED: Object.freeze({
26
- [IMPRESSION]: UNTRACKED,
27
- [VIEWABLE]: UNTRACKED,
28
- [CLICK]: UNTRACKED,
29
- }),
30
- };
31
- */
32
-
33
18
  const UNTRACKED_STATES = Object.freeze({
34
19
  [IMPRESSION]: UNTRACKED,
35
20
  [VIEWABLE]: UNTRACKED,
@@ -4,4 +4,4 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _default = exports.default = '1.11.0-beta.0';
7
+ var _default = exports.default = '1.11.0-beta.10';
@@ -6,24 +6,22 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = void 0;
7
7
  var _commons = require("@miso.ai/commons");
8
8
  var _base = _interopRequireDefault(require("./base.js"));
9
- var _options = require("./options.js");
10
9
  var _index = require("../actor/index.js");
11
10
  var _constants = require("../constants.js");
12
11
  var _index2 = require("../layout/index.js");
13
12
  var _index3 = require("../affiliation/index.js");
13
+ var _options = require("./options.js");
14
14
  var _processors = require("./processors.js");
15
15
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
- // import * as sources from '../source.js';
17
-
18
- const DEFAULT_API_OPTIONS = Object.freeze({
16
+ const DEFAULT_API_OPTIONS = Object.freeze(Object.assign({}, _base.default.DEFAULT_API_OPTIONS, {
19
17
  group: _commons.API.GROUP.ASK,
20
- payload: {
18
+ payload: Object.assign({}, _base.default.DEFAULT_API_OPTIONS.payload, {
21
19
  source_fl: ['cover_image', 'url', 'created_at', 'updated_at', 'published_at'],
22
20
  cite_link: 1,
23
21
  cite_start: '[',
24
22
  cite_end: ']'
25
- }
26
- });
23
+ })
24
+ }));
27
25
  const DEFAULT_AUTOCOMPLETE_OPTIONS = Object.freeze({
28
26
  actor: false,
29
27
  api: {
@@ -31,7 +29,7 @@ const DEFAULT_AUTOCOMPLETE_OPTIONS = Object.freeze({
31
29
  name: _commons.API.NAME.AUTOCOMPLETE
32
30
  }
33
31
  });
34
- const DEFAULT_LAYOUTS = Object.freeze({
32
+ const DEFAULT_LAYOUTS = Object.freeze(Object.assign({}, _base.default.DEFAULT_LAYOUTS, {
35
33
  [_constants.ROLE.QUERY]: [_index2.SearchBoxLayout.type, {
36
34
  placeholder: 'Ask a question'
37
35
  }],
@@ -54,16 +52,21 @@ const DEFAULT_LAYOUTS = Object.freeze({
54
52
  rel: 'noopener nofollow'
55
53
  }
56
54
  }]
57
- });
58
- const DEFAULT_TRACKERS = Object.freeze({
55
+ }));
56
+ const DEFAULT_TRACKERS = Object.freeze(Object.assign({}, _base.default.DEFAULT_TRACKERS, {
59
57
  [_constants.ROLE.SOURCES]: {},
60
- [_constants.ROLE.AFFILIATION]: {}
61
- });
62
- const DEFAULT_OPTIONS = Object.freeze({
58
+ [_constants.ROLE.AFFILIATION]: {},
59
+ [_constants.ROLE.PRODUCTS]: {}
60
+ }));
61
+ const DEFAULT_OPTIONS = Object.freeze(Object.assign({}, _base.default.DEFAULT_OPTIONS, {
63
62
  api: DEFAULT_API_OPTIONS,
64
63
  autocomplete: DEFAULT_AUTOCOMPLETE_OPTIONS,
65
64
  layouts: DEFAULT_LAYOUTS,
66
65
  trackers: DEFAULT_TRACKERS
66
+ }));
67
+ const ROLES_OPTIONS = (0, _options.mergeRolesOptions)(_base.default.ROLES_OPTIONS, {
68
+ main: _constants.ROLE.ANSWER,
69
+ members: Object.keys(DEFAULT_LAYOUTS)
67
70
  });
68
71
  class AnswerBasedWorkflow extends _base.default {
69
72
  // constructor //
@@ -75,16 +78,19 @@ class AnswerBasedWorkflow extends _base.default {
75
78
  _initActors(args) {
76
79
  super._initActors(args);
77
80
  this._feedback = new _index.FeedbackActor(this._hub);
78
- /*
79
- this._autocomplete = new AutocompleteActor(this._hub, {
80
- source: sources.api(this._client),
81
- options: this._options,
82
- });
83
- */
84
81
  }
85
82
  _initSubscriptions(args) {
86
83
  super._initSubscriptions(args);
87
- this._unsubscribes = [...this._unsubscribes, this._hub.on(_index.fields.query(), args => this._query(args)), 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))];
84
+ this._unsubscribes = [...this._unsubscribes, this._hub.on(_index.fields.query(), args => this._query(args)), this._views.get(_constants.ROLE.ANSWER).on('citation-click', event => this._onCitationClick(event))];
85
+ }
86
+
87
+ // configuration //
88
+ useLink(fn) {
89
+ if (typeof fn !== 'function' && fn !== false) {
90
+ throw new Error('useLink(fn) expects fn to be a function or false');
91
+ }
92
+ this._linkFn = fn;
93
+ return this;
88
94
  }
89
95
 
90
96
  // lifecycle //
@@ -93,26 +99,29 @@ class AnswerBasedWorkflow extends _base.default {
93
99
  if (this._questionId) {
94
100
  this._questionId = undefined;
95
101
  }
96
- // interrupt event
97
- // TODO: move to workflow base
98
- const {
99
- session,
100
- status,
101
- ongoing
102
- } = this._hub.states[_index.fields.view(_constants.ROLE.ANSWER)] || {};
103
- if (session && status !== _constants.STATUS.INITIAL && (status !== _constants.STATUS.READY || ongoing)) {
104
- // it's interrupted by a new question
105
- const state = Object.freeze({
106
- session,
107
- status,
108
- ongoing
109
- });
110
- this._emit('interrupt', state);
111
- this._emit('finally', state);
112
- }
113
102
  // restart
114
103
  super.restart();
115
104
  }
105
+ _emitInterruptEventIfNecessary() {
106
+ const state = this._hub.states[_index.fields.view(this._roles.main)] || {};
107
+ if (state.session && state.status !== _constants.STATUS.INITIAL && (state.status !== _constants.STATUS.READY || state.ongoing)) {
108
+ // it's interrupted by a new question
109
+ this._emitLifecycleEvent('interrupt', state);
110
+ this._emitLifecycleEvent('finally', state);
111
+ }
112
+ }
113
+ _onMainViewUpdate(state) {
114
+ const {
115
+ status
116
+ } = state;
117
+ const done = status === _constants.STATUS.READY && !state.ongoing;
118
+ const erroneous = status === _constants.STATUS.ERRONEOUS;
119
+ const eventName = done ? 'done' : erroneous ? 'error' : status;
120
+ this._emitLifecycleEvent(eventName, state);
121
+ if (done || erroneous) {
122
+ this._emitLifecycleEvent('finally', state);
123
+ }
124
+ }
116
125
 
117
126
  // properties //
118
127
  get questionId() {
@@ -156,55 +165,58 @@ class AnswerBasedWorkflow extends _base.default {
156
165
  }
157
166
  _query() {
158
167
  let args = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
168
+ if (this._linkFn) {
169
+ this._submit(args);
170
+ return;
171
+ }
159
172
  // start a new session
160
173
  this.restart();
161
174
 
162
- // keep track of question source on this session
163
- const {
164
- session
165
- } = this;
166
- session.meta.question_source = args.questionSource || _constants.ORGANIC_QUESTION_SOURCE; // might be null, not undefined
175
+ // keep track of question source on this session, for suggested questions interactions
176
+ this._writeQuestionSourceToSession(args);
167
177
 
168
178
  // build payload and trigger request
169
179
  const payload = this._buildPayload(args);
170
- const event = (0, _options.mergeApiOptions)(this._options.resolved.api, {
171
- payload,
172
- session
180
+ this._request({
181
+ payload
173
182
  });
174
- this._request(event);
175
183
  }
176
- _request(event) {
177
- this._hub.update(_index.fields.request(), event);
184
+ _submit(args) {
185
+ if (!this._linkFn) {
186
+ return;
187
+ }
188
+ // TODO: we want a submit event, but only with linkFn
189
+ const url = this._linkFn(args.q);
190
+ window.open(url, '_blank');
191
+ }
192
+ _writeQuestionSourceToSession(args) {
193
+ this.session.meta.question_source = args.qs || _constants.ORGANIC_QUESTION_SOURCE; // might be null, not undefined
178
194
  }
179
195
  _buildPayload() {
180
196
  throw new Error(`Not implemented`);
181
197
  }
182
198
 
183
- // autocomplete //
184
- /*
185
- updateCompletions(event) {
186
- // TODO: verify
187
- this._hub.update(fields.data(DATA_ASPECT.AUTOCOMPLETE), {
188
- ...event,
189
- source: 'manual',
190
- });
191
- return this;
192
- }
193
- */
194
-
195
199
  // data //
196
- _defaultProcessData(data) {
197
- data = super._defaultProcessData(data);
198
-
199
- // capture question ID and register at context
200
- this._writeQuestionIdFromData(data);
200
+ _updateData(data) {
201
+ // if it's the head response, write question id and return
202
+ if (data.value && !data.value.answer_stage) {
203
+ this._handleHeadResponse(data);
204
+ return;
205
+ }
206
+ super._updateData(data);
201
207
 
202
208
  // update URL if autoQuery.updateUrl is not false
203
209
  this._updateUrlIfNecessary(data);
204
-
205
- // affiliation
210
+ }
211
+ _handleHeadResponse(data) {
212
+ // capture question ID and register at context
213
+ this._writeQuestionIdFromData(data);
214
+ }
215
+ _defaultProcessData(data) {
216
+ data = super._defaultProcessData(data);
206
217
  data = (0, _index3.processData)(data);
207
- return (0, _processors.writeAnswerStageToMeta)(data);
218
+ data = (0, _processors.writeAnswerStageToMeta)(data);
219
+ return data;
208
220
  }
209
221
  _writeQuestionIdFromData(_ref) {
210
222
  let {
@@ -241,53 +253,40 @@ class AnswerBasedWorkflow extends _base.default {
241
253
  }
242
254
 
243
255
  // interactions //
244
- _preprocessInteraction(payload) {
245
- payload = super._preprocessInteraction(payload) || {};
256
+ _defaultProcessInteraction(payload, args) {
257
+ payload = super._defaultProcessInteraction(payload, args);
258
+ payload = this._writeAskPropertiesToInteraction(payload, args);
259
+ return payload;
260
+ }
261
+ _writeAskPropertiesToInteraction() {
262
+ let payload = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
263
+ let args = arguments.length > 1 ? arguments[1] : undefined;
264
+ const question_source = this._getQuestionSourceFromViewState(args);
265
+ const question_id = this.questionId;
266
+ return (0, _processors.mergeInteraction)(payload, {
267
+ context: {
268
+ custom_context: {
269
+ question_source,
270
+ question_id
271
+ }
272
+ }
273
+ });
274
+ }
275
+ _getQuestionSourceFromViewState(args) {
246
276
  const {
247
- context = {}
248
- } = payload;
277
+ request
278
+ } = this._hub.states[_index.fields.view(args.role)] || {};
249
279
  const {
250
- custom_context = {}
251
- } = context;
252
- let {
253
- questionId
254
- } = this;
255
- return Object.assign({}, payload, {
256
- context: Object.assign({}, context, {
257
- custom_context: (0, _commons.trimObj)(Object.assign({
258
- question_id: questionId
259
- }, custom_context))
260
- })
261
- });
280
+ payload
281
+ } = request || {};
282
+ return payload && payload._meta && payload._meta.question_source || undefined;
262
283
  }
263
284
 
264
285
  // handlers //
265
- _onAnswerViewUpdate(_ref3) {
266
- let {
267
- session,
268
- status,
269
- ongoing
270
- } = _ref3;
271
- if (status === _constants.STATUS.INITIAL) {
272
- return;
273
- }
274
- const done = status === _constants.STATUS.READY && !ongoing;
275
- const erroneous = status === _constants.STATUS.ERRONEOUS;
276
- const eventName = done ? 'done' : erroneous ? 'error' : status;
277
- const state = Object.freeze({
278
- session,
279
- status,
280
- ongoing
281
- });
282
- this._emit(eventName, state);
283
- if (done || erroneous) {
284
- this._emit('finally', state);
285
- }
286
- }
287
- _onCitationClick(_ref4) {
286
+ _onCitationClick(_ref3) {
288
287
  let {
289
288
  index
290
- } = _ref4;
289
+ } = _ref3;
291
290
  const {
292
291
  value
293
292
  } = this.states[_index.fields.data()] || {};
@@ -323,13 +322,12 @@ class AnswerBasedWorkflow extends _base.default {
323
322
  super._destroy(options);
324
323
  }
325
324
  }
326
-
327
- // makeConfigurable(AnswerBasedWorkflow.prototype, ['autocomplete']);
328
325
  exports.default = AnswerBasedWorkflow;
329
326
  Object.assign(AnswerBasedWorkflow, {
330
327
  DEFAULT_API_OPTIONS,
331
328
  DEFAULT_AUTOCOMPLETE_OPTIONS,
332
329
  DEFAULT_LAYOUTS,
333
330
  DEFAULT_TRACKERS,
334
- DEFAULT_OPTIONS
331
+ DEFAULT_OPTIONS,
332
+ ROLES_OPTIONS
335
333
  });