@miso.ai/client-sdk-ui 1.10.3 → 1.10.4-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/actor/autocomplete.js +4 -1
- package/dist/cjs/actor/data.js +15 -6
- package/dist/cjs/actor/fields.js +10 -10
- package/dist/cjs/actor/filters.js +114 -0
- package/dist/cjs/actor/hub.js +2 -1
- package/dist/cjs/actor/sessions.js +3 -5
- package/dist/cjs/actor/view.js +19 -6
- package/dist/cjs/actor/views.js +32 -19
- package/dist/cjs/constants.js +9 -2
- package/dist/cjs/defaults/ask/constants.js +3 -2
- package/dist/cjs/defaults/ask/templates.js +112 -219
- package/dist/cjs/defaults/common/templates.js +234 -0
- package/dist/cjs/defaults/hybrid-search/answer-box.js +115 -0
- package/dist/cjs/defaults/hybrid-search/constants.js +8 -0
- package/dist/cjs/defaults/hybrid-search/controls.js +17 -0
- package/dist/cjs/defaults/hybrid-search/index.js +31 -0
- package/dist/cjs/defaults/hybrid-search/phrases.js +27 -0
- package/dist/cjs/defaults/hybrid-search/templates.js +127 -0
- package/dist/cjs/defaults/index.js +4 -2
- package/dist/cjs/element/container/index.js +7 -0
- package/dist/cjs/element/container/miso-hybrid-search.js +21 -0
- package/dist/cjs/element/role/index.js +21 -0
- package/dist/cjs/element/role/miso-facets.js +20 -0
- package/dist/cjs/element/role/miso-hits.js +20 -0
- package/dist/cjs/element/role/miso-keywords.js +20 -0
- package/dist/cjs/layout/index.js +7 -0
- package/dist/cjs/layout/input/facets.js +294 -0
- package/dist/cjs/layout/input/option-list.js +4 -4
- package/dist/cjs/layout/input/search-box.js +6 -8
- package/dist/cjs/layout/list/collection.js +1 -2
- package/dist/cjs/layout/raf.js +1 -0
- package/dist/cjs/layout/template.js +3 -1
- package/dist/cjs/layout/templates.js +15 -0
- package/dist/cjs/layout/text/text.js +38 -5
- package/dist/cjs/layout/trackable.js +2 -16
- package/dist/cjs/plugin.js +4 -1
- package/dist/cjs/{source/index.js → source.js} +7 -4
- package/dist/cjs/util/bindings.js +3 -0
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/workflow/answer-based.js +335 -0
- package/dist/cjs/workflow/ask.js +98 -271
- package/dist/cjs/workflow/base.js +69 -35
- package/dist/cjs/workflow/explore.js +10 -0
- package/dist/cjs/workflow/hybrid-search.js +140 -0
- package/dist/cjs/workflow/index.js +7 -0
- package/dist/cjs/workflow/processors.js +113 -0
- package/dist/cjs/workflow/recommendation.js +12 -3
- package/dist/cjs/workflow/search.js +34 -12
- package/package.json +2 -2
- package/src/actor/autocomplete.js +4 -2
- package/src/actor/data.js +8 -2
- package/src/actor/fields.js +10 -10
- package/src/actor/filters.js +103 -0
- package/src/actor/hub.js +2 -1
- package/src/actor/sessions.js +3 -4
- package/src/actor/view.js +19 -2
- package/src/actor/views.js +30 -16
- package/src/constants.js +10 -0
- package/src/defaults/ask/constants.js +1 -0
- package/src/defaults/ask/templates.js +70 -179
- package/src/defaults/common/templates.js +173 -0
- package/src/defaults/hybrid-search/answer-box.js +118 -0
- package/src/defaults/hybrid-search/constants.js +2 -0
- package/src/defaults/hybrid-search/controls.js +11 -0
- package/src/defaults/hybrid-search/index.js +9 -0
- package/src/defaults/hybrid-search/phrases.js +22 -0
- package/src/defaults/hybrid-search/templates.js +83 -0
- package/src/defaults/index.js +2 -0
- package/src/element/container/index.js +1 -0
- package/src/element/container/miso-hybrid-search.js +19 -0
- package/src/element/role/index.js +3 -0
- package/src/element/role/miso-facets.js +16 -0
- package/src/element/role/miso-hits.js +16 -0
- package/src/element/role/miso-keywords.js +16 -0
- package/src/layout/index.js +1 -0
- package/src/layout/input/facets.js +242 -0
- package/src/layout/input/option-list.js +3 -4
- package/src/layout/input/search-box.js +6 -7
- package/src/layout/list/collection.js +1 -2
- package/src/layout/raf.js +1 -0
- package/src/layout/template.js +2 -1
- package/src/layout/templates.js +15 -0
- package/src/layout/text/text.js +28 -3
- package/src/layout/trackable.js +2 -15
- package/src/plugin.js +6 -2
- package/src/{source/index.js → source.js} +7 -4
- package/src/util/bindings.js +4 -0
- package/src/version.js +1 -1
- package/src/workflow/answer-based.js +280 -0
- package/src/workflow/ask.js +82 -204
- package/src/workflow/base.js +64 -27
- package/src/workflow/explore.js +10 -1
- package/src/workflow/hybrid-search.js +125 -0
- package/src/workflow/index.js +1 -0
- package/src/workflow/processors.js +95 -0
- package/src/workflow/recommendation.js +9 -2
- package/src/workflow/search.js +35 -7
- package/dist/cjs/source/api.js +0 -23
- package/src/source/api.js +0 -12
package/src/workflow/ask.js
CHANGED
|
@@ -1,48 +1,27 @@
|
|
|
1
1
|
import { defineValues, trimObj, API } from '@miso.ai/commons';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import { ROLE, STATUS, ORGANIC_QUESTION_SOURCE } from '../constants.js';
|
|
7
|
-
import { SearchBoxLayout, OptionListLayout, ListLayout, TextLayout, TypewriterLayout, FeedbackLayout, AffiliationLayout } from '../layout/index.js';
|
|
8
|
-
import { makeConfigurable } from './options.js';
|
|
9
|
-
import { processData as processAffiliationData } from '../affiliation/index.js';
|
|
2
|
+
import AnswerBasedWorkflow from './answer-based.js';
|
|
3
|
+
import { fields } from '../actor/index.js';
|
|
4
|
+
import { ROLE, ORGANIC_QUESTION_SOURCE } from '../constants.js';
|
|
5
|
+
import { OptionListLayout, ListLayout, TextLayout } from '../layout/index.js';
|
|
10
6
|
|
|
11
7
|
const DEFAULT_API_OPTIONS = Object.freeze({
|
|
12
|
-
|
|
8
|
+
...AnswerBasedWorkflow.DEFAULT_API_OPTIONS,
|
|
13
9
|
name: API.NAME.QUESTIONS,
|
|
14
10
|
payload: {
|
|
15
|
-
|
|
11
|
+
...AnswerBasedWorkflow.DEFAULT_API_OPTIONS.payload,
|
|
16
12
|
related_resource_fl: ['cover_image', 'url', 'created_at', 'updated_at', 'published_at'],
|
|
17
|
-
cite_link: 1,
|
|
18
|
-
cite_start: '[',
|
|
19
|
-
cite_end: ']',
|
|
20
|
-
},
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
const DEFAULT_AUTOCOMPLETE_OPTIONS = Object.freeze({
|
|
24
|
-
actor: false,
|
|
25
|
-
api: {
|
|
26
|
-
group: API.GROUP.ASK,
|
|
27
|
-
name: API.NAME.AUTOCOMPLETE,
|
|
28
13
|
},
|
|
29
14
|
});
|
|
30
15
|
|
|
31
16
|
const DEFAULT_LAYOUTS = Object.freeze({
|
|
32
|
-
|
|
33
|
-
[ROLE.QUESTION]: [TextLayout.type, { tag: 'h2' }],
|
|
34
|
-
[ROLE.ANSWER]: TypewriterLayout.type,
|
|
35
|
-
[ROLE.FEEDBACK]: FeedbackLayout.type,
|
|
36
|
-
[ROLE.SOURCES]: [ListLayout.type, { incremental: true, itemType: 'article', templates: { ordered: true } }],
|
|
17
|
+
...AnswerBasedWorkflow.DEFAULT_LAYOUTS,
|
|
37
18
|
[ROLE.RELATED_RESOURCES]: [ListLayout.type, { incremental: true, itemType: 'article' }],
|
|
38
19
|
[ROLE.QUERY_SUGGESTIONS]: OptionListLayout.type,
|
|
39
|
-
[ROLE.AFFILIATION]: [AffiliationLayout.type, { incremental: true, itemType: 'affiliation', link: { rel: 'noopener nofollow' } }],
|
|
40
20
|
});
|
|
41
21
|
|
|
42
22
|
const DEFAULT_TRACKERS = Object.freeze({
|
|
43
|
-
|
|
23
|
+
...AnswerBasedWorkflow.DEFAULT_TRACKERS,
|
|
44
24
|
[ROLE.RELATED_RESOURCES]: {},
|
|
45
|
-
[ROLE.AFFILIATION]: {},
|
|
46
25
|
[ROLE.QUERY_SUGGESTIONS]: {
|
|
47
26
|
click: {
|
|
48
27
|
validate: event => event.button === 0, // left click only
|
|
@@ -51,13 +30,13 @@ const DEFAULT_TRACKERS = Object.freeze({
|
|
|
51
30
|
});
|
|
52
31
|
|
|
53
32
|
const DEFAULT_OPTIONS = Object.freeze({
|
|
33
|
+
...AnswerBasedWorkflow.DEFAULT_OPTIONS,
|
|
54
34
|
api: DEFAULT_API_OPTIONS,
|
|
55
|
-
autocomplete: DEFAULT_AUTOCOMPLETE_OPTIONS,
|
|
56
35
|
layouts: DEFAULT_LAYOUTS,
|
|
57
36
|
trackers: DEFAULT_TRACKERS,
|
|
58
37
|
});
|
|
59
38
|
|
|
60
|
-
export default class Ask extends
|
|
39
|
+
export default class Ask extends AnswerBasedWorkflow {
|
|
61
40
|
|
|
62
41
|
constructor(context, parentQuestionId) {
|
|
63
42
|
super({
|
|
@@ -65,38 +44,47 @@ export default class Ask extends Workflow {
|
|
|
65
44
|
context,
|
|
66
45
|
roles: Object.keys(DEFAULT_LAYOUTS),
|
|
67
46
|
defaults: DEFAULT_OPTIONS,
|
|
47
|
+
parentQuestionId,
|
|
68
48
|
});
|
|
69
|
-
|
|
70
|
-
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
_initProperties(args) {
|
|
52
|
+
super._initProperties(args);
|
|
53
|
+
const { parentQuestionId } = args;
|
|
71
54
|
defineValues(this, { parentQuestionId });
|
|
55
|
+
}
|
|
72
56
|
|
|
73
|
-
|
|
57
|
+
_initSubscriptions(args) {
|
|
74
58
|
this._setSuggestedQuestions();
|
|
59
|
+
super._initSubscriptions(args);
|
|
60
|
+
}
|
|
75
61
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
this.
|
|
84
|
-
|
|
85
|
-
this._hub.on(fields.query(), payload => this.query(payload)),
|
|
86
|
-
this._hub.on(fields.view(ROLE.ANSWER), data => this._onAnswerViewUpdate(data)),
|
|
87
|
-
this._views.get(ROLE.ANSWER).on('citation-click', event => this._onCitationClick(event)),
|
|
88
|
-
];
|
|
89
|
-
|
|
90
|
-
parentQuestionId && context._byPqid.set(parentQuestionId, this);
|
|
91
|
-
context._events.emit('create', this);
|
|
62
|
+
_setSuggestedQuestions() {
|
|
63
|
+
const { previous } = this;
|
|
64
|
+
if (!previous) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const values = previous.states[fields.data()].value;
|
|
68
|
+
const value = values.suggested_followup_questions || values.followup_questions || [];
|
|
69
|
+
this._hub.update(fields.suggestions(), { value: value.map(text => ({ text })) });
|
|
70
|
+
}
|
|
92
71
|
|
|
93
|
-
|
|
72
|
+
_initReset(args) {
|
|
73
|
+
// register at context
|
|
74
|
+
args.parentQuestionId && this._context._byPqid.set(args.parentQuestionId, this);
|
|
75
|
+
this._context._events.emit('create', this);
|
|
76
|
+
super._initReset(args);
|
|
94
77
|
}
|
|
95
78
|
|
|
96
|
-
|
|
97
|
-
|
|
79
|
+
// lifecycle //
|
|
80
|
+
restart() {
|
|
81
|
+
if (this._questionId) {
|
|
82
|
+
this._context._byQid.delete(this._questionId);
|
|
83
|
+
}
|
|
84
|
+
super.restart();
|
|
98
85
|
}
|
|
99
86
|
|
|
87
|
+
// properties //
|
|
100
88
|
get rootQuestionId() {
|
|
101
89
|
return this._context.root.questionId;
|
|
102
90
|
}
|
|
@@ -116,174 +104,65 @@ export default class Ask extends Workflow {
|
|
|
116
104
|
return questionId ? this._context.getByParentQuestionId(questionId, { autoCreate: true }) : undefined;
|
|
117
105
|
}
|
|
118
106
|
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
const {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
if (!q && focus) {
|
|
131
|
-
layout.focus();
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
if (q) {
|
|
135
|
-
this.query({ q, qs });
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
query({ q: question, qs: questionSource, ...payload } = {}) {
|
|
140
|
-
payload = { ...payload, question };
|
|
141
|
-
questionSource = questionSource || ORGANIC_QUESTION_SOURCE;
|
|
142
|
-
|
|
143
|
-
if (this.parentQuestionId) {
|
|
144
|
-
payload.parent_question_id = this.parentQuestionId;
|
|
145
|
-
}
|
|
146
|
-
(payload._meta || (payload._meta = {})).question_source = questionSource;
|
|
147
|
-
|
|
148
|
-
// clear question id from previous session
|
|
149
|
-
if (this._questionId) {
|
|
150
|
-
this._context._byQid.delete(this._questionId);
|
|
151
|
-
this._questionId = undefined;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
this.restart();
|
|
155
|
-
|
|
156
|
-
const { session } = this;
|
|
157
|
-
session.meta.question_source = questionSource;
|
|
158
|
-
this._hub.update(fields.request(), mergeApiOptions(this._options.resolved.api, { payload, session }));
|
|
159
|
-
|
|
160
|
-
return this;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
restart() {
|
|
164
|
-
// TODO: move to workflow base
|
|
165
|
-
const { session, status, ongoing } = this._hub.states[fields.view(ROLE.ANSWER)] || {};
|
|
166
|
-
if (session && status !== STATUS.INITIAL && (status !== STATUS.READY || ongoing)) {
|
|
167
|
-
// it's interrupted by a new question
|
|
168
|
-
const state = Object.freeze({ session, status, ongoing });
|
|
169
|
-
this._emit('interrupt', state);
|
|
170
|
-
this._emit('finally', state);
|
|
171
|
-
}
|
|
172
|
-
super.restart();
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/*
|
|
176
|
-
updateCompletions(event) {
|
|
177
|
-
// TODO: verify
|
|
178
|
-
this._hub.update(fields.completions(), {
|
|
179
|
-
...event,
|
|
180
|
-
source: 'manual',
|
|
107
|
+
// query //
|
|
108
|
+
_buildPayload({ q, qs, ...payload } = {}) {
|
|
109
|
+
const { parentQuestionId } = this;
|
|
110
|
+
return trimObj({
|
|
111
|
+
...payload,
|
|
112
|
+
question: q, // question, not q
|
|
113
|
+
parent_question_id: parentQuestionId,
|
|
114
|
+
_meta: {
|
|
115
|
+
...payload._meta,
|
|
116
|
+
question_source: qs || ORGANIC_QUESTION_SOURCE, // might be null, not undefined
|
|
117
|
+
},
|
|
181
118
|
});
|
|
182
|
-
return this;
|
|
183
119
|
}
|
|
184
|
-
*/
|
|
185
120
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if (!value) {
|
|
190
|
-
return data;
|
|
191
|
-
}
|
|
192
|
-
const { question_id: questionId, question } = value;
|
|
193
|
-
const organic = request && request.payload && request.payload._meta && request.payload._meta.question_source === ORGANIC_QUESTION_SOURCE;
|
|
121
|
+
// interactions //
|
|
122
|
+
_preprocessInteraction(payload) {
|
|
123
|
+
payload = super._preprocessInteraction(payload) || {};
|
|
194
124
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
this._context._byQid.set(questionId, this);
|
|
199
|
-
}
|
|
125
|
+
const { context = {} } = payload;
|
|
126
|
+
const { ...custom_context } = context.custom_context || {};
|
|
127
|
+
let { rootQuestionId, parentQuestionId, questionId } = this;
|
|
200
128
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (question !== currentQuestion && (!organic || this._autoQuery.updateUrl === true)) {
|
|
207
|
-
url.searchParams.set('q', question);
|
|
208
|
-
window.history.replaceState({}, '', url);
|
|
209
|
-
}
|
|
129
|
+
if (custom_context.property === ROLE.QUERY_SUGGESTIONS) {
|
|
130
|
+
questionId = parentQuestionId;
|
|
131
|
+
parentQuestionId = this.previous && this.previous.parentQuestionId;
|
|
132
|
+
custom_context.property = 'suggested_followup_questions';
|
|
133
|
+
custom_context.question_source = this.previous && this.previous.session.meta.question_source;
|
|
210
134
|
}
|
|
135
|
+
custom_context.question_id = questionId;
|
|
136
|
+
custom_context.root_question_id = rootQuestionId;
|
|
137
|
+
custom_context.parent_question_id = parentQuestionId;
|
|
211
138
|
|
|
212
|
-
// affiliation
|
|
213
|
-
data = processAffiliationData(data);
|
|
214
|
-
|
|
215
|
-
// 1. put answer_stage to meta
|
|
216
|
-
// 2. mark ongoing flag
|
|
217
139
|
return {
|
|
218
|
-
...
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
answer_stage: value.answer_stage,
|
|
140
|
+
...payload,
|
|
141
|
+
context: {
|
|
142
|
+
...context,
|
|
143
|
+
custom_context: trimObj(custom_context),
|
|
223
144
|
},
|
|
224
145
|
};
|
|
225
146
|
}
|
|
226
147
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const eventName = done ? 'done' : erroneous ? 'error' : status;
|
|
234
|
-
const state = Object.freeze({ session, status, ongoing });
|
|
235
|
-
this._emit(eventName, state);
|
|
236
|
-
if (done || erroneous) {
|
|
237
|
-
this._emit('finally', state);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
_setSuggestedQuestions() {
|
|
242
|
-
const { previous } = this;
|
|
243
|
-
if (!previous) {
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
const values = previous.states[fields.data()].value;
|
|
247
|
-
const value = values.suggested_followup_questions || values.followup_questions || [];
|
|
248
|
-
this._hub.update(fields.suggestions(), { value: value.map(text => ({ text })) });
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
_onCitationClick({ index }) {
|
|
252
|
-
const { value } = this.states[fields.data()] || {};
|
|
253
|
-
const { sources } = value || {};
|
|
254
|
-
// index is 1-based
|
|
255
|
-
const source = sources && sources[index - 1];
|
|
256
|
-
if (!source || !source.product_id) {
|
|
257
|
-
return;
|
|
148
|
+
// helpers //
|
|
149
|
+
_writeQuestionId(questionId) {
|
|
150
|
+
// capture question ID and register at context
|
|
151
|
+
if (!this._questionId && questionId) {
|
|
152
|
+
this._questionId = questionId;
|
|
153
|
+
this._context._byQid.set(questionId, this);
|
|
258
154
|
}
|
|
259
|
-
// TODO: should we track impression as well?
|
|
260
|
-
this._trackers.sources.click([source.product_id], { manual: false });
|
|
261
155
|
}
|
|
262
156
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
// when we track suggested questions, we are actually tracking the suggested_followup_questions of the previous workflow
|
|
269
|
-
if (custom_context.property === ROLE.QUERY_SUGGESTIONS) {
|
|
270
|
-
questionId = parentQuestionId;
|
|
271
|
-
parentQuestionId = this.previous && this.previous.parentQuestionId;
|
|
272
|
-
custom_context.property = 'suggested_followup_questions';
|
|
273
|
-
custom_context.question_source = this.previous && this.previous.session.meta.question_source;
|
|
157
|
+
_clearQuestionId() {
|
|
158
|
+
// clear question id from previous session
|
|
159
|
+
if (this._questionId) {
|
|
160
|
+
this._context._byQid.delete(this._questionId);
|
|
161
|
+
this._questionId = undefined;
|
|
274
162
|
}
|
|
275
|
-
payload.context = {
|
|
276
|
-
...context,
|
|
277
|
-
custom_context: trimObj({
|
|
278
|
-
root_question_id: rootQuestionId,
|
|
279
|
-
parent_question_id: parentQuestionId,
|
|
280
|
-
question_id: questionId,
|
|
281
|
-
...custom_context,
|
|
282
|
-
}),
|
|
283
|
-
};
|
|
284
|
-
return payload;
|
|
285
163
|
}
|
|
286
164
|
|
|
165
|
+
// destroy //
|
|
287
166
|
_destroy(options) {
|
|
288
167
|
const { parentQuestionId, questionId } = this;
|
|
289
168
|
if (parentQuestionId) {
|
|
@@ -292,7 +171,6 @@ export default class Ask extends Workflow {
|
|
|
292
171
|
if (questionId) {
|
|
293
172
|
this._context._byQid.delete(questionId);
|
|
294
173
|
}
|
|
295
|
-
this._feedback._destroy();
|
|
296
174
|
super._destroy(options);
|
|
297
175
|
}
|
|
298
176
|
|
package/src/workflow/base.js
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import { Component, isNullLike } from '@miso.ai/commons';
|
|
2
2
|
import { Hub, SessionMaker, DataActor, ViewsActor, InteractionsActor, fields } from '../actor/index.js';
|
|
3
|
-
import * as sources from '../source
|
|
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
6
|
import { injectLogger } from './utils.js';
|
|
7
7
|
import { WorkflowOptions, mergeLayoutsOptions, mergeInteractionsOptions, makeConfigurable } from './options.js';
|
|
8
|
+
import { writeDataStatus, writeMisoIdToMeta, addDataInstructions } from './processors.js';
|
|
8
9
|
|
|
9
10
|
const DEFAULT_LAYOUTS = Object.freeze({
|
|
10
11
|
[ROLE.CONTAINER]: ContainerLayout.type,
|
|
11
12
|
[ROLE.ERROR]: ErrorLayout.type,
|
|
12
13
|
});
|
|
13
14
|
|
|
15
|
+
const ROLES_CONFIG = Object.freeze({
|
|
16
|
+
[ROLE.ERROR]: {
|
|
17
|
+
mapping: data => data.error,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
14
21
|
function mergeDefaults(workflow, { layouts, interactions, ...defaults } = {}) {
|
|
15
22
|
const DEFAULT_INTERACTIONS = {
|
|
16
23
|
preprocess: [payload => workflow._preprocessInteraction(payload)],
|
|
@@ -28,36 +35,56 @@ function getRevision(data) {
|
|
|
28
35
|
|
|
29
36
|
export default class Workflow extends Component {
|
|
30
37
|
|
|
31
|
-
constructor({
|
|
32
|
-
name,
|
|
33
|
-
|
|
34
|
-
plugin,
|
|
35
|
-
client,
|
|
36
|
-
roles,
|
|
37
|
-
defaults,
|
|
38
|
-
}) {
|
|
39
|
-
super(name || 'workflow', plugin);
|
|
38
|
+
constructor(args) {
|
|
39
|
+
super(args.name || 'workflow', args.plugin);
|
|
40
|
+
|
|
41
|
+
let { context, plugin, client } = args;
|
|
40
42
|
this._context = context;
|
|
41
43
|
this._plugin = plugin = plugin || context._plugin;
|
|
42
44
|
this._client = client = client || context._client;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
args = Object.freeze({ ...args, plugin, client });
|
|
46
|
+
|
|
47
|
+
this._name = args.name;
|
|
48
|
+
this._roles = args.roles;
|
|
49
|
+
this._rolesConfig = { ...ROLES_CONFIG, ...args.rolesConfig };
|
|
50
|
+
|
|
51
|
+
this._extensions = plugin._getExtensions(client);
|
|
52
|
+
this._options = new WorkflowOptions(context && context._options, mergeDefaults(this, args.defaults));
|
|
53
|
+
this._hub = injectLogger(new Hub(), (...args) => this._log(...args));
|
|
45
54
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
55
|
+
this._initProperties(args);
|
|
56
|
+
this._initActors(args);
|
|
57
|
+
this._initSubscriptions(args);
|
|
58
|
+
this._initReset(args);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
_initProperties() {}
|
|
62
|
+
|
|
63
|
+
_initActors() {
|
|
64
|
+
const hub = this._hub;
|
|
65
|
+
const client = this._client;
|
|
66
|
+
const roles = this._roles;
|
|
67
|
+
const rolesConfig = this._rolesConfig;
|
|
68
|
+
const options = this._options;
|
|
69
|
+
const extensions = this._extensions;
|
|
70
|
+
const layouts = this._plugin.layouts;
|
|
50
71
|
|
|
51
72
|
this._sessions = new SessionMaker(hub);
|
|
52
73
|
this._data = new DataActor(hub, { source: sources.api(client), options });
|
|
53
|
-
this._views = new ViewsActor(hub, { extensions, layouts, roles, options, workflow:
|
|
74
|
+
this._views = new ViewsActor(hub, { extensions, layouts, roles, rolesConfig, options, workflow: this._name });
|
|
54
75
|
this._interactions = new InteractionsActor(hub, { client, options });
|
|
76
|
+
}
|
|
55
77
|
|
|
78
|
+
_initSubscriptions() {
|
|
56
79
|
this._unsubscribes = [
|
|
57
80
|
this._hub.on(fields.response(), data => this.updateData(data)),
|
|
58
81
|
];
|
|
59
82
|
}
|
|
60
83
|
|
|
84
|
+
_initReset() {
|
|
85
|
+
this.reset();
|
|
86
|
+
}
|
|
87
|
+
|
|
61
88
|
get uuid() {
|
|
62
89
|
return this.session && this.session.uuid;
|
|
63
90
|
}
|
|
@@ -75,6 +102,11 @@ export default class Workflow extends Component {
|
|
|
75
102
|
return this._hub.states;
|
|
76
103
|
}
|
|
77
104
|
|
|
105
|
+
get status() {
|
|
106
|
+
const data = this._hub.states[fields.data()];
|
|
107
|
+
return data && data.status;
|
|
108
|
+
}
|
|
109
|
+
|
|
78
110
|
get views() {
|
|
79
111
|
return this._views.interface;
|
|
80
112
|
}
|
|
@@ -91,13 +123,12 @@ export default class Workflow extends Component {
|
|
|
91
123
|
}
|
|
92
124
|
|
|
93
125
|
restart() {
|
|
94
|
-
this.
|
|
95
|
-
this.start();
|
|
126
|
+
this._sessions.restart();
|
|
96
127
|
return this;
|
|
97
128
|
}
|
|
98
129
|
|
|
99
130
|
// states //
|
|
100
|
-
updateData(data) {
|
|
131
|
+
updateData(data, { instructions } = {}) {
|
|
101
132
|
if (!data) {
|
|
102
133
|
throw new Error(`Data is required.`);
|
|
103
134
|
}
|
|
@@ -123,31 +154,37 @@ export default class Workflow extends Component {
|
|
|
123
154
|
|
|
124
155
|
this._sessions.start(); // in case session not started yet
|
|
125
156
|
|
|
157
|
+
data = writeDataStatus(data);
|
|
126
158
|
data = this._defaultProcessData(data);
|
|
127
159
|
for (const process of this._options.resolved.dataProcessor) {
|
|
128
160
|
data = process(data);
|
|
129
161
|
}
|
|
130
162
|
|
|
163
|
+
// write data instructions from function args
|
|
164
|
+
data = addDataInstructions(data, instructions);
|
|
165
|
+
data = this._mergeDataIfNecessary(data);
|
|
166
|
+
|
|
131
167
|
this._hub.update(fields.data(), data);
|
|
132
168
|
|
|
133
169
|
return this;
|
|
134
170
|
}
|
|
135
171
|
|
|
136
172
|
_defaultProcessData(data) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
173
|
+
return writeMisoIdToMeta(data);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
_mergeDataIfNecessary(data) {
|
|
177
|
+
if (!data._inst || !data._inst.merge) {
|
|
140
178
|
return data;
|
|
141
179
|
}
|
|
142
180
|
return {
|
|
181
|
+
...this._hub.states[fields.data()],
|
|
143
182
|
...data,
|
|
144
|
-
meta: {
|
|
145
|
-
...data.meta,
|
|
146
|
-
miso_id: value.miso_id,
|
|
147
|
-
},
|
|
148
183
|
};
|
|
149
184
|
}
|
|
150
185
|
|
|
186
|
+
_handleResponseObject() {}
|
|
187
|
+
|
|
151
188
|
// TODO: notifyViewUpdateAll()
|
|
152
189
|
|
|
153
190
|
notifyViewUpdate(role, state) {
|
package/src/workflow/explore.js
CHANGED
|
@@ -39,9 +39,16 @@ export default class Explore extends Workflow {
|
|
|
39
39
|
roles: Object.keys(DEFAULT_LAYOUTS),
|
|
40
40
|
defaults: DEFAULT_OPTIONS,
|
|
41
41
|
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
_initProperties(args) {
|
|
45
|
+
super._initProperties(args);
|
|
42
46
|
this._productId = undefined;
|
|
43
47
|
this._linkFn = undefined;
|
|
48
|
+
}
|
|
44
49
|
|
|
50
|
+
_initSubscriptions(args) {
|
|
51
|
+
super._initSubscriptions(args);
|
|
45
52
|
this._unsubscribes = [
|
|
46
53
|
...this._unsubscribes,
|
|
47
54
|
this._views.get(ROLE.RELATED_QUESTIONS).on('click', event => this._handleRelatedQuestionClick(event)),
|
|
@@ -49,6 +56,7 @@ export default class Explore extends Workflow {
|
|
|
49
56
|
];
|
|
50
57
|
}
|
|
51
58
|
|
|
59
|
+
// configuration //
|
|
52
60
|
set productId(value) {
|
|
53
61
|
console.warning('DEPRECATED: use useApi() instead');
|
|
54
62
|
this.useApi({
|
|
@@ -84,7 +92,8 @@ export default class Explore extends Workflow {
|
|
|
84
92
|
if (relatedQuestions) {
|
|
85
93
|
this._hub.update(fields.request(), mergeApiOptions(this._options.resolved.api, { session }));
|
|
86
94
|
} else {
|
|
87
|
-
|
|
95
|
+
// TODO: ad-hoc
|
|
96
|
+
this.updateData({ session, request: {}, value: { related_questions: [] } });
|
|
88
97
|
}
|
|
89
98
|
return this;
|
|
90
99
|
}
|