@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.
- package/dist/cjs/actor/data.js +6 -7
- package/dist/cjs/actor/feedback.js +6 -39
- package/dist/cjs/actor/fields.js +14 -6
- package/dist/cjs/actor/hub.js +1 -2
- package/dist/cjs/actor/index.js +0 -7
- package/dist/cjs/actor/interactions.js +4 -15
- package/dist/cjs/actor/sessions.js +2 -33
- package/dist/cjs/actor/tracker.js +25 -26
- package/dist/cjs/actor/utils.js +0 -49
- package/dist/cjs/actor/view.js +40 -40
- package/dist/cjs/actor/views.js +32 -8
- package/dist/cjs/asset/svgs.js +18 -8
- package/dist/cjs/constants.js +18 -19
- package/dist/cjs/defaults/hybrid-search/answer-box.js +19 -3
- package/dist/cjs/defaults/hybrid-search/phrases.js +5 -5
- package/dist/cjs/defaults/hybrid-search/templates.js +37 -9
- package/dist/cjs/element/role/index.js +12 -5
- package/dist/cjs/element/role/{miso-hits.js → miso-more.js} +4 -4
- package/dist/cjs/element/role/miso-total.js +20 -0
- package/dist/cjs/layout/affiliation/affiliation.js +0 -3
- package/dist/cjs/layout/banner/banner.js +0 -4
- package/dist/cjs/layout/button/more-button.js +73 -0
- package/dist/cjs/layout/container/container.js +0 -3
- package/dist/cjs/layout/error/error.js +0 -4
- package/dist/cjs/layout/index.js +7 -0
- package/dist/cjs/layout/input/facets.js +5 -5
- package/dist/cjs/layout/input/option-list.js +0 -4
- package/dist/cjs/layout/input/search-box.js +35 -17
- package/dist/cjs/layout/list/cards.js +0 -3
- package/dist/cjs/layout/list/carousel.js +0 -3
- package/dist/cjs/layout/list/collection.js +22 -7
- package/dist/cjs/layout/list/list.js +0 -3
- package/dist/cjs/layout/radio/feedback.js +0 -3
- package/dist/cjs/layout/radio/radio.js +0 -4
- package/dist/cjs/layout/raf.js +4 -2
- package/dist/cjs/layout/text/text.js +0 -4
- package/dist/cjs/layout/text/typewriter/index.js +0 -3
- package/dist/cjs/layout/triggerable.js +79 -0
- package/dist/cjs/util/states.js +0 -15
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/workflow/answer-based.js +109 -111
- package/dist/cjs/workflow/ask.js +35 -27
- package/dist/cjs/workflow/asks.js +1 -1
- package/dist/cjs/workflow/autocompletable.js +33 -0
- package/dist/cjs/workflow/autocomplete.js +122 -0
- package/dist/cjs/workflow/base.js +169 -102
- package/dist/cjs/workflow/explore.js +26 -19
- package/dist/cjs/workflow/hybrid-search-answer.js +99 -0
- package/dist/cjs/workflow/hybrid-search-results.js +66 -0
- package/dist/cjs/workflow/hybrid-search-views.js +122 -0
- package/dist/cjs/workflow/hybrid-search.js +98 -103
- package/dist/cjs/workflow/options.js +32 -17
- package/dist/cjs/workflow/processors.js +191 -17
- package/dist/cjs/workflow/recommendation.js +36 -49
- package/dist/cjs/workflow/search-based.js +228 -0
- package/dist/cjs/workflow/search.js +21 -68
- package/package.json +2 -2
- package/src/actor/data.js +2 -4
- package/src/actor/feedback.js +6 -23
- package/src/actor/fields.js +14 -6
- package/src/actor/hub.js +1 -2
- package/src/actor/index.js +0 -1
- package/src/actor/interactions.js +4 -10
- package/src/actor/sessions.js +3 -30
- package/src/actor/tracker.js +25 -19
- package/src/actor/utils.js +0 -47
- package/src/actor/view.js +27 -15
- package/src/actor/views.js +36 -8
- package/src/asset/svgs.js +19 -7
- package/src/constants.js +25 -16
- package/src/defaults/hybrid-search/answer-box.js +17 -5
- package/src/defaults/hybrid-search/phrases.js +4 -4
- package/src/defaults/hybrid-search/templates.js +25 -9
- package/src/element/role/index.js +2 -1
- package/src/element/role/{miso-hits.js → miso-more.js} +3 -3
- package/src/element/role/miso-total.js +16 -0
- package/src/layout/affiliation/affiliation.js +1 -5
- package/src/layout/banner/banner.js +0 -5
- package/src/layout/button/more-button.js +69 -0
- package/src/layout/container/container.js +1 -5
- package/src/layout/error/error.js +0 -5
- package/src/layout/index.js +2 -1
- package/src/layout/input/facets.js +5 -6
- package/src/layout/input/option-list.js +0 -5
- package/src/layout/input/search-box.js +29 -19
- package/src/layout/list/cards.js +0 -4
- package/src/layout/list/carousel.js +0 -4
- package/src/layout/list/collection.js +21 -9
- package/src/layout/list/list.js +0 -4
- package/src/layout/radio/feedback.js +0 -4
- package/src/layout/radio/radio.js +0 -5
- package/src/layout/raf.js +2 -2
- package/src/layout/text/text.js +0 -5
- package/src/layout/text/typewriter/index.js +1 -5
- package/src/layout/trackable.js +1 -1
- package/src/layout/triggerable.js +76 -0
- package/src/util/states.js +0 -14
- package/src/version.js +1 -1
- package/src/workflow/answer-based.js +101 -77
- package/src/workflow/ask.js +33 -25
- package/src/workflow/asks.js +1 -1
- package/src/workflow/autocompletable.js +29 -0
- package/src/workflow/autocomplete.js +113 -0
- package/src/workflow/base.js +147 -93
- package/src/workflow/explore.js +23 -8
- package/src/workflow/hybrid-search-answer.js +92 -0
- package/src/workflow/hybrid-search-results.js +62 -0
- package/src/workflow/hybrid-search-views.js +124 -0
- package/src/workflow/hybrid-search.js +102 -73
- package/src/workflow/options.js +26 -11
- package/src/workflow/processors.js +169 -14
- package/src/workflow/recommendation.js +32 -33
- package/src/workflow/search-based.js +222 -0
- package/src/workflow/search.js +21 -65
- package/dist/cjs/actor/autocomplete.js +0 -160
- package/dist/cjs/workflow/utils.js +0 -42
- package/src/actor/autocomplete.js +0 -133
- package/src/workflow/utils.js +0 -29
package/src/workflow/base.js
CHANGED
|
@@ -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 {
|
|
7
|
-
import {
|
|
8
|
-
|
|
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
|
|
16
|
-
[ROLE.ERROR]: {
|
|
17
|
-
mapping: data => data.error,
|
|
18
|
-
},
|
|
19
|
-
});
|
|
32
|
+
const DEFAULT_TRACKERS = Object.freeze({});
|
|
20
33
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
33
|
-
|
|
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.
|
|
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.
|
|
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,
|
|
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
|
-
|
|
85
|
-
this.
|
|
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
|
-
|
|
116
|
-
this.
|
|
122
|
+
restart() {
|
|
123
|
+
this._emitInterruptEventIfNecessary();
|
|
124
|
+
this._sessions.restart();
|
|
117
125
|
return this;
|
|
118
126
|
}
|
|
119
127
|
|
|
120
|
-
|
|
121
|
-
this.
|
|
122
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
-
//
|
|
131
|
-
updateData(data
|
|
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.
|
|
191
|
+
this._updateData(data);
|
|
156
192
|
|
|
157
|
-
|
|
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
|
-
|
|
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
|
-
|
|
206
|
+
data = writeDataStatus(data);
|
|
207
|
+
data = writeMisoIdToMeta(data);
|
|
208
|
+
return data;
|
|
174
209
|
}
|
|
175
210
|
|
|
176
|
-
|
|
177
|
-
|
|
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
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
+
});
|
package/src/workflow/explore.js
CHANGED
|
@@ -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:
|
|
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(),
|
|
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 (
|
|
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.
|
|
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(
|
|
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
|
+
}
|