@miso.ai/client-sdk-ui 1.11.0-beta.1 → 1.11.0-beta.11

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 +35 -17
  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 +22 -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 +0 -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 +66 -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 +191 -17
  54. package/dist/cjs/workflow/recommendation.js +36 -49
  55. package/dist/cjs/workflow/search-based.js +228 -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 +29 -19
  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 +21 -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 +1 -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 +62 -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 +169 -14
  112. package/src/workflow/recommendation.js +32 -33
  113. package/src/workflow/search-based.js +222 -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
@@ -3,42 +3,52 @@ import { Hub, SessionMaker, DataActor, ViewsActor, InteractionsActor, fields } f
3
3
  import * as sources from '../source.js';
4
4
  import { STATUS, ROLE } from '../constants.js';
5
5
  import { ContainerLayout, ErrorLayout } from '../layout/index.js';
6
- import { injectLogger } from './utils.js';
7
- import { WorkflowOptions, mergeLayoutsOptions, mergeInteractionsOptions, makeConfigurable } from './options.js';
8
- import { writeDataStatus, writeMisoIdToMeta, addDataInstructions } from './processors.js';
6
+ import { WorkflowOptions, mergeApiOptions, makeConfigurable } from './options.js';
7
+ import { getRevision, writeDataStatus, writeMisoIdToMeta, buildBaseInteraction, writeAffiliationInfoToInteraction, mergeInteraction } from './processors.js';
8
+
9
+ // TODO: just bury this into hub
10
+ function injectLogger(hub, callback) {
11
+ const { update, trigger } = hub;
12
+ hub.update = (name, state, options) => {
13
+ if (!options || !options.silent) {
14
+ callback('update', name, state, options);
15
+ }
16
+ return update.call(hub, name, state, options);
17
+ }
18
+ hub.trigger = (...args) => {
19
+ callback('trigger', ...args);
20
+ return trigger.apply(hub, args);
21
+ }
22
+ return hub;
23
+ }
24
+
25
+ const DEFAULT_API_OPTIONS = Object.freeze({});
9
26
 
10
27
  const DEFAULT_LAYOUTS = Object.freeze({
11
28
  [ROLE.CONTAINER]: ContainerLayout.type,
12
29
  [ROLE.ERROR]: ErrorLayout.type,
13
30
  });
14
31
 
15
- const ROLES_CONFIG = Object.freeze({
16
- [ROLE.ERROR]: {
17
- mapping: data => data.error,
18
- },
19
- });
32
+ const DEFAULT_TRACKERS = Object.freeze({});
20
33
 
21
- function mergeDefaults(workflow, { layouts, interactions, ...defaults } = {}) {
22
- const DEFAULT_INTERACTIONS = {
23
- preprocess: [payload => workflow._preprocessInteraction(payload)],
24
- };
25
- return {
26
- ...defaults,
27
- layouts: mergeLayoutsOptions(DEFAULT_LAYOUTS, layouts),
28
- interactions: mergeInteractionsOptions(DEFAULT_INTERACTIONS, interactions),
29
- };
30
- }
34
+ const DEFAULT_OPTIONS = Object.freeze({
35
+ api: DEFAULT_API_OPTIONS,
36
+ layouts: DEFAULT_LAYOUTS,
37
+ trackers: DEFAULT_TRACKERS,
38
+ });
31
39
 
32
- function getRevision(data) {
33
- return data && data.value && data.value.revision;
34
- }
40
+ const ROLES_OPTIONS = Object.freeze({
41
+ mappings: {
42
+ [ROLE.ERROR]: data => data.error,
43
+ },
44
+ });
35
45
 
36
46
  export default class Workflow extends Component {
37
47
 
38
48
  constructor(args) {
39
49
  super(args.name || 'workflow', args.plugin);
40
50
 
41
- let { context, plugin, client } = args;
51
+ let { context, plugin, client, options } = args;
42
52
  this._context = context;
43
53
  this._plugin = plugin = plugin || context._plugin;
44
54
  this._client = client = client || context._client;
@@ -46,43 +56,45 @@ export default class Workflow extends Component {
46
56
 
47
57
  this._name = args.name;
48
58
  this._roles = args.roles;
49
- this._rolesConfig = { ...ROLES_CONFIG, ...args.rolesConfig };
50
59
 
51
60
  this._extensions = plugin._getExtensions(client);
52
- this._options = new WorkflowOptions(context && context._options, mergeDefaults(this, args.defaults));
61
+ this._defaults = args.defaults;
62
+ this._options = options || new WorkflowOptions(context && context._options, args.defaults);
53
63
  this._hub = injectLogger(new Hub(), (...args) => this._log(...args));
54
64
 
55
65
  this._initProperties(args);
56
66
  this._initActors(args);
57
67
  this._initSubscriptions(args);
58
- this._initReset(args);
68
+ this._initSession(args);
59
69
  }
60
70
 
61
71
  _initProperties() {}
62
72
 
63
- _initActors() {
73
+ _initActors({ name, roles }) {
64
74
  const hub = this._hub;
65
75
  const client = this._client;
66
- const roles = this._roles;
67
- const rolesConfig = this._rolesConfig;
68
76
  const options = this._options;
69
77
  const extensions = this._extensions;
70
78
  const layouts = this._plugin.layouts;
71
79
 
72
80
  this._sessions = new SessionMaker(hub);
73
81
  this._data = new DataActor(hub, { source: sources.api(client), options });
74
- this._views = new ViewsActor(hub, { extensions, layouts, roles, rolesConfig, options, workflow: this._name });
82
+ this._views = new ViewsActor(hub, { extensions, layouts, roles, options, workflow: name });
75
83
  this._interactions = new InteractionsActor(hub, { client, options });
76
84
  }
77
85
 
78
- _initSubscriptions() {
86
+ _initSubscriptions({ roles }) {
79
87
  this._unsubscribes = [
80
88
  this._hub.on(fields.response(), data => this.updateData(data)),
89
+ this._hub.on(fields.tracker(), args => this._onTracker(args)),
81
90
  ];
91
+ if (roles.main) {
92
+ this._unsubscribes.push(this._hub.on(fields.view(roles.main), state => this._onMainViewUpdate(state)));
93
+ }
82
94
  }
83
95
 
84
- _initReset() {
85
- this.reset();
96
+ _initSession() {
97
+ this.restart();
86
98
  }
87
99
 
88
100
  get uuid() {
@@ -90,12 +102,7 @@ export default class Workflow extends Component {
90
102
  }
91
103
 
92
104
  get session() {
93
- return this._hub.states.session;
94
- }
95
-
96
- get active() {
97
- const { session } = this;
98
- return !!session && session.active;
105
+ return this._hub.states[fields.session()];
99
106
  }
100
107
 
101
108
  get states() {
@@ -112,23 +119,52 @@ export default class Workflow extends Component {
112
119
  }
113
120
 
114
121
  // lifecycle //
115
- reset() {
116
- this._sessions.new();
122
+ restart() {
123
+ this._emitInterruptEventIfNecessary();
124
+ this._sessions.restart();
117
125
  return this;
118
126
  }
119
127
 
120
- start() {
121
- this._sessions.start();
122
- return this;
128
+ _emitInterruptEventIfNecessary() {
129
+ const { main } = this._roles;
130
+ if (!main) {
131
+ return;
132
+ }
133
+ const state = this._hub.states[fields.view(main)] || {};
134
+ if (state.session && state.status === STATUS.LOADING) {
135
+ // it's interrupted by a new question
136
+ this._emitLifecycleEvent('interrupt', state);
137
+ this._emitLifecycleEvent('finally', state);
138
+ }
123
139
  }
124
140
 
125
- restart() {
126
- this._sessions.restart();
127
- return this;
141
+ _onMainViewUpdate(state) {
142
+ const { status } = state;
143
+ const done = status === STATUS.READY;
144
+ const erroneous = status === STATUS.ERRONEOUS;
145
+ const eventName = erroneous ? 'error' : status;
146
+ this._emitLifecycleEvent(eventName, state);
147
+ if (done) {
148
+ this._emitLifecycleEvent('done', state);
149
+ }
150
+ if (done || erroneous) {
151
+ this._emitLifecycleEvent('finally', state);
152
+ }
153
+ }
154
+
155
+ _emitLifecycleEvent(name, event) {
156
+ this._emit(name, event);
157
+ }
158
+
159
+ // request //
160
+ _request(options = {}) {
161
+ const { session } = this;
162
+ const event = mergeApiOptions(this._options.resolved.api, { ...options, session });
163
+ this._hub.update(fields.request(), event);
128
164
  }
129
165
 
130
- // states //
131
- updateData(data, { instructions } = {}) {
166
+ // data //
167
+ updateData(data) {
132
168
  if (!data) {
133
169
  throw new Error(`Data is required.`);
134
170
  }
@@ -152,43 +188,33 @@ export default class Workflow extends Component {
152
188
  }
153
189
  }
154
190
 
155
- this._sessions.start(); // in case session not started yet
191
+ this._updateData(data);
156
192
 
157
- data = writeDataStatus(data);
193
+ return this;
194
+ }
195
+
196
+ _updateData(data) {
158
197
  data = this._defaultProcessData(data);
159
198
  for (const process of this._options.resolved.dataProcessor) {
160
199
  data = process(data);
161
200
  }
162
201
 
163
- // write data instructions from function args
164
- data = addDataInstructions(data, instructions);
165
- data = this._mergeDataIfNecessary(data);
166
-
167
- this._hub.update(fields.data(), data);
168
-
169
- return this;
202
+ this._updateDataInHub(data);
170
203
  }
171
204
 
172
205
  _defaultProcessData(data) {
173
- return writeMisoIdToMeta(data);
206
+ data = writeDataStatus(data);
207
+ data = writeMisoIdToMeta(data);
208
+ return data;
174
209
  }
175
210
 
176
- _mergeDataIfNecessary(data) {
177
- if (!data._inst || !data._inst.merge) {
178
- return data;
179
- }
180
- return {
181
- ...this._hub.states[fields.data()],
182
- ...data,
183
- };
211
+ _updateDataInHub(data) {
212
+ this._hub.update(fields.data(), data);
184
213
  }
185
214
 
186
- _handleResponseObject() {}
187
-
188
215
  // TODO: notifyViewUpdateAll()
189
216
 
190
217
  notifyViewUpdate(role, state) {
191
- this._assertActive();
192
218
  state = {
193
219
  status: STATUS.READY,
194
220
  session: this.session,
@@ -203,28 +229,54 @@ export default class Workflow extends Component {
203
229
  return this._views.trackers;
204
230
  }
205
231
 
206
- _preprocessInteraction({
207
- context: {
208
- custom_context,
209
- ...context
210
- } = {},
211
- ...payload
212
- } = {}) {
213
- const {
214
- group: api_group,
215
- name: api_name,
216
- } = this._options.resolved.api;
217
- return {
218
- ...payload,
232
+ _onTracker(args) {
233
+ const payload = this._buildInteraction(args);
234
+ this._sendInteraction(payload);
235
+ }
236
+
237
+ _buildInteraction(args) {
238
+ let payload = buildBaseInteraction(args);
239
+ payload = this._defaultProcessInteraction(payload, args);
240
+ const { preprocess = [] } = this._options.resolved.interactions;
241
+ for (const p of preprocess) {
242
+ payload = p(payload, args);
243
+ }
244
+ return payload;
245
+ }
246
+
247
+ _defaultProcessInteraction(payload, args) {
248
+ payload = this._writeApiInfoToInteraction(payload, args);
249
+ payload = this._writeMisoIdToInteraction(payload, args);
250
+ payload = writeAffiliationInfoToInteraction(payload, args);
251
+ return payload;
252
+ }
253
+
254
+ _writeApiInfoToInteraction(payload) {
255
+ const { group, name } = this._options.resolved.api;
256
+ return mergeInteraction(payload, {
219
257
  context: {
220
- ...context,
221
258
  custom_context: {
222
- api_group,
223
- api_name,
224
- ...custom_context,
259
+ api_group: group,
260
+ api_name: name,
225
261
  },
226
262
  },
227
- };
263
+ });
264
+ }
265
+
266
+ _writeMisoIdToInteraction(payload, args) {
267
+ // TODO: ad-hoc, try to pass info from tracker
268
+ const state = this._hub.states[fields.view(args.role)] || {};
269
+ const miso_id = (state.meta && state.meta.miso_id) || undefined;
270
+ return miso_id ? mergeInteraction(payload, { miso_id }) : payload;
271
+ }
272
+
273
+ _sendInteraction(payload) {
274
+ const { handle } = this._options.resolved.interactions;
275
+ if (typeof handle === 'function') {
276
+ handle(payload);
277
+ } else {
278
+ this._hub.trigger(fields.interaction(), payload);
279
+ }
228
280
  }
229
281
 
230
282
  // destroy //
@@ -255,12 +307,14 @@ export default class Workflow extends Component {
255
307
  }
256
308
  }
257
309
 
258
- _assertActive() {
259
- if (!this.active) {
260
- throw new Error(`Unit is not active yet. Call unit.start() to activate it.`)
261
- }
262
- }
263
-
264
310
  }
265
311
 
266
312
  makeConfigurable(Workflow.prototype);
313
+
314
+ Object.assign(Workflow, {
315
+ DEFAULT_API_OPTIONS,
316
+ DEFAULT_LAYOUTS,
317
+ DEFAULT_TRACKERS,
318
+ DEFAULT_OPTIONS,
319
+ ROLES_OPTIONS,
320
+ });
@@ -1,21 +1,24 @@
1
1
  import { API } from '@miso.ai/commons';
2
2
  import Workflow from './base.js';
3
- import { mergeApiOptions } from './options.js';
4
3
  import { fields } from '../actor/index.js';
5
4
  import { ROLE, EVENT_TYPE } from '../constants.js';
6
5
  import { ListLayout, SearchBoxLayout } from '../layout/index.js';
6
+ import { mergeRolesOptions } from './options.js';
7
7
 
8
8
  const DEFAULT_API_OPTIONS = Object.freeze({
9
+ ...Workflow.DEFAULT_API_OPTIONS,
9
10
  group: API.GROUP.ASK,
10
11
  name: API.NAME.RELATED_QUESTIONS,
11
12
  });
12
13
 
13
14
  const DEFAULT_LAYOUTS = Object.freeze({
15
+ ...Workflow.DEFAULT_LAYOUTS,
14
16
  [ROLE.RELATED_QUESTIONS]: [ListLayout.type, { itemType: 'question', link: { rel: 'noopener nofollow' } }],
15
17
  [ROLE.QUERY]: [SearchBoxLayout.type, { placeholder: 'Ask a question' }],
16
18
  });
17
19
 
18
20
  const DEFAULT_TRACKERS = Object.freeze({
21
+ ...Workflow.DEFAULT_TRACKERS,
19
22
  [ROLE.RELATED_QUESTIONS]: {},
20
23
  [ROLE.CONTAINER]: {},
21
24
  [ROLE.QUERY]: {
@@ -24,11 +27,17 @@ const DEFAULT_TRACKERS = Object.freeze({
24
27
  });
25
28
 
26
29
  const DEFAULT_OPTIONS = Object.freeze({
30
+ ...Workflow.DEFAULT_OPTIONS,
27
31
  api: DEFAULT_API_OPTIONS,
28
32
  layouts: DEFAULT_LAYOUTS,
29
33
  trackers: DEFAULT_TRACKERS,
30
34
  });
31
35
 
36
+ const ROLES_OPTIONS = mergeRolesOptions(Workflow.ROLES_OPTIONS, {
37
+ main: ROLE.RELATED_QUESTIONS,
38
+ members: Object.keys(DEFAULT_LAYOUTS),
39
+ });
40
+
32
41
  export default class Explore extends Workflow {
33
42
 
34
43
  constructor(plugin, client) {
@@ -36,7 +45,7 @@ export default class Explore extends Workflow {
36
45
  name: 'explore',
37
46
  plugin,
38
47
  client,
39
- roles: Object.keys(DEFAULT_LAYOUTS),
48
+ roles: ROLES_OPTIONS,
40
49
  defaults: DEFAULT_OPTIONS,
41
50
  });
42
51
  }
@@ -52,7 +61,7 @@ export default class Explore extends Workflow {
52
61
  this._unsubscribes = [
53
62
  ...this._unsubscribes,
54
63
  this._views.get(ROLE.RELATED_QUESTIONS).on('click', event => this._handleRelatedQuestionClick(event)),
55
- this._hub.on(fields.query(), payload => this.query(payload)),
64
+ this._hub.on(fields.query(), args => this._submit(args)),
56
65
  ];
57
66
  }
58
67
 
@@ -82,17 +91,16 @@ export default class Explore extends Workflow {
82
91
 
83
92
  // lifecycle //
84
93
  start({ relatedQuestions = true } = {}) {
85
- if (relatedQuestions && this._linkFn === undefined) {
94
+ if (this._linkFn === undefined) {
86
95
  throw new Error('Define link mapping function before calling start()');
87
96
  }
88
- this._sessions.start();
89
97
  // in explore workflow, start() triggers query
90
98
  // TODO: we should still make the query lifecycle
91
- const { session } = this;
92
99
  if (relatedQuestions) {
93
- this._hub.update(fields.request(), mergeApiOptions(this._options.resolved.api, { session }));
100
+ this._request();
94
101
  } else {
95
102
  // TODO: ad-hoc
103
+ const { session } = this;
96
104
  this.updateData({ session, request: {}, value: { related_questions: [] } });
97
105
  }
98
106
  return this;
@@ -124,7 +132,14 @@ export default class Explore extends Workflow {
124
132
  this._events.emit('select', Object.freeze({ ...event, question }));
125
133
  }
126
134
 
127
- query({ q } = {}) {
135
+ query(args) {
136
+ if (!args.q) {
137
+ throw new Error(`q is required in query() call`);
138
+ }
139
+ this._hub.update(fields.query(), args);
140
+ }
141
+
142
+ _submit({ q } = {}) {
128
143
  if (!this._linkFn) {
129
144
  return;
130
145
  }
@@ -0,0 +1,92 @@
1
+ import AnswerBasedWorkflow from './answer-based.js';
2
+ import { ROLE, STATUS, ORGANIC_QUESTION_SOURCE } from '../constants.js';
3
+ import { mergeRolesOptions } from './options.js';
4
+ import { writeKeywordsToData } from './processors.js';
5
+ import { makeAutocompletable } from './autocompletable.js';
6
+
7
+ const ROLES_OPTIONS = mergeRolesOptions(AnswerBasedWorkflow.ROLES_OPTIONS, {
8
+ mappings: {
9
+ [ROLE.QUESTION]: ROLE.KEYWORDS,
10
+ },
11
+ });
12
+
13
+ export default class HybridSearchAnswer extends AnswerBasedWorkflow {
14
+
15
+ constructor(superworkflow) {
16
+ super({
17
+ name: 'hybrid-search/answer',
18
+ plugin: superworkflow._plugin,
19
+ client: superworkflow._client,
20
+ options: superworkflow._options,
21
+ defaults: superworkflow._defaults,
22
+ roles: ROLES_OPTIONS,
23
+ superworkflow,
24
+ });
25
+ }
26
+
27
+ _initProperties(args) {
28
+ super._initProperties(args);
29
+ this._initAutocomplete(args);
30
+ this._superworkflow = args.superworkflow;
31
+ }
32
+
33
+ _initSession() {} // no reset here, will manually reset later
34
+
35
+ restart() {
36
+ super.restart();
37
+ // cascade restart to the sibling
38
+ const results = this._superworkflow._results;
39
+ results._views.filters.reset();
40
+ results.restart();
41
+ this._resultsSession = results.session; // keep track of the session
42
+ }
43
+
44
+ // query //
45
+ _buildPayload({ q, qs, ...payload } = {}) {
46
+ return {
47
+ ...payload,
48
+ q, // q, not question
49
+ _meta: {
50
+ ...payload._meta,
51
+ question_source: qs || ORGANIC_QUESTION_SOURCE, // might be null, not undefined
52
+ },
53
+ };
54
+ }
55
+
56
+ // data //
57
+ _defaultProcessData(data) {
58
+ data = super._defaultProcessData(data);
59
+ data = writeKeywordsToData(data);
60
+ return data;
61
+ }
62
+
63
+ _updateDataInHub(data) {
64
+ switch (data.status) {
65
+ case STATUS.INITIAL:
66
+ case STATUS.LOADING:
67
+ // share the initial/loading status with its sibling
68
+ this._dispatchDataToSibling(data);
69
+ break;
70
+ }
71
+ super._updateDataInHub(data);
72
+ }
73
+
74
+ _handleHeadResponse(data) {
75
+ super._handleHeadResponse(data);
76
+ // share the search results with its sibling
77
+ this._dispatchDataToSibling(data);
78
+ }
79
+
80
+ _dispatchDataToSibling(data) {
81
+ this._resultsSession && this._superworkflow._results.updateData({ ...data, session: this._resultsSession });
82
+ }
83
+
84
+ // destroy //
85
+ _destroy(options) {
86
+ this._destroyAutocomplete();
87
+ super._destroy(options);
88
+ }
89
+
90
+ }
91
+
92
+ makeAutocompletable(HybridSearchAnswer.prototype);
@@ -0,0 +1,62 @@
1
+ import { trimObj } from '@miso.ai/commons';
2
+ import SearchBasedWorkflow from './search-based.js';
3
+ import { fields } from '../actor/index.js';
4
+ import { ROLE } from '../constants.js';
5
+ import { mergeRolesOptions } from './options.js';
6
+
7
+ const ROLES_OPTIONS = mergeRolesOptions(SearchBasedWorkflow.ROLES_OPTIONS, {
8
+ members: [ROLE.PRODUCTS, ROLE.KEYWORDS, ROLE.TOTAL, ROLE.FACETS, ROLE.MORE],
9
+ });
10
+
11
+ export default class HybridSearchResults extends SearchBasedWorkflow {
12
+
13
+ constructor(superworkflow) {
14
+ super({
15
+ name: 'hybrid-search/results',
16
+ plugin: superworkflow._plugin,
17
+ client: superworkflow._client,
18
+ options: superworkflow._options,
19
+ defaults: superworkflow._defaults,
20
+ roles: ROLES_OPTIONS,
21
+ superworkflow,
22
+ });
23
+ }
24
+
25
+ _initProperties(args) {
26
+ super._initProperties(args);
27
+ this._superworkflow = args.superworkflow;
28
+ }
29
+
30
+ _initSession() {} // no reset here, will manually reset later
31
+
32
+ // lifecycle //
33
+ _emitLifecycleEvent(name, event) {
34
+ super._emitLifecycleEvent(name, event);
35
+ this._superworkflow._emitLifecycleEvent(name, event);
36
+ }
37
+
38
+ // query //
39
+ _getQuery() {
40
+ // get stored query from sibling
41
+ return this._superworkflow._answer._hub.states[fields.query()];
42
+ }
43
+
44
+ _buildPayload({ filters, ...payload } = {}) {
45
+ // borrow the work from the sibling
46
+ payload = this._superworkflow._answer._buildPayload(payload);
47
+ payload = SearchBasedWorkflow.prototype._buildPayload.call(this, payload);
48
+ payload = this._writeQuestionIdToPayload(payload);
49
+ return { ...payload, answer: false };
50
+ }
51
+
52
+ _writeQuestionIdToPayload(payload) {
53
+ return {
54
+ ...payload,
55
+ _meta: trimObj({
56
+ ...payload._meta,
57
+ question_id: this._superworkflow._answer.questionId,
58
+ }),
59
+ };
60
+ }
61
+
62
+ }