@miso.ai/client-sdk-ui 1.11.0-beta.1 → 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.
- 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 +33 -12
- 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 +25 -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 +70 -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 +185 -17
- package/dist/cjs/workflow/recommendation.js +36 -49
- package/dist/cjs/workflow/search-based.js +186 -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 +27 -14
- package/src/layout/list/cards.js +0 -4
- package/src/layout/list/carousel.js +0 -4
- package/src/layout/list/collection.js +22 -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 +63 -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 +165 -14
- package/src/workflow/recommendation.js +32 -33
- package/src/workflow/search-based.js +183 -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
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { STATUS
|
|
1
|
+
import { STATUS } from '../../constants.js';
|
|
2
2
|
import TemplateBasedLayout from '../template.js';
|
|
3
3
|
import { makeTrackable } from '../trackable.js';
|
|
4
|
+
import { makeTriggerable } from '../triggerable.js';
|
|
4
5
|
import { product, article, question, productInfoBlock, articleInfoBlock, titleBlock, brandBlock, descriptionBlock, dateBlock, priceBlock, discountRateText, ctaBlock, cta, imageBlock, indexBlock } from '../templates.js';
|
|
5
6
|
|
|
6
7
|
function root(layout, state) {
|
|
7
8
|
const { className, role, templates } = layout;
|
|
8
9
|
const { status } = state;
|
|
9
10
|
const roleAttr = role ? `data-role="${role}"` : '';
|
|
10
|
-
return `<div class="${className} ${status}" ${roleAttr}>${status === STATUS.READY ? templates[status](layout, state) : ''}</div>`;
|
|
11
|
+
return `<div class="${className} ${status}" ${roleAttr}>${status === STATUS.READY ? templates[status](layout, state) : ''}${templates.trigger(layout, state)}${templates.loadingBar(layout, state)}</div>`;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
function ready(layout, state) {
|
|
@@ -15,7 +16,7 @@ function ready(layout, state) {
|
|
|
15
16
|
const values = layout._getItems(state);
|
|
16
17
|
|
|
17
18
|
// TODO: handle categories, attributes, etc. by introducing sublayout
|
|
18
|
-
if ((values && values.length > 0) || state.ongoing) {
|
|
19
|
+
if ((values && values.length > 0) || state.ongoing) { // TODO: ad-hoc ongoing?
|
|
19
20
|
return templates.list(layout, state, values);
|
|
20
21
|
} else {
|
|
21
22
|
return templates.empty(layout, state);
|
|
@@ -42,6 +43,16 @@ function item(layout, state, value, index) {
|
|
|
42
43
|
return `<li class="${className}__item">${body}</li>`;
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
function trigger(layout, state) {
|
|
47
|
+
const { className } = layout;
|
|
48
|
+
return `<div class="${className}__trigger" data-role="trigger"></div>`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function loadingBar(layout, state) {
|
|
52
|
+
const { className } = layout;
|
|
53
|
+
return `<div class="${className}__loading-bar"></div>`;
|
|
54
|
+
}
|
|
55
|
+
|
|
45
56
|
// TODO: let templates.js control what to be included here
|
|
46
57
|
|
|
47
58
|
const DEFAULT_TEMPLATES = Object.freeze({
|
|
@@ -67,14 +78,12 @@ const DEFAULT_TEMPLATES = Object.freeze({
|
|
|
67
78
|
cta,
|
|
68
79
|
imageBlock,
|
|
69
80
|
indexBlock,
|
|
81
|
+
trigger,
|
|
82
|
+
loadingBar,
|
|
70
83
|
});
|
|
71
84
|
|
|
72
85
|
export default class CollectionLayout extends TemplateBasedLayout {
|
|
73
86
|
|
|
74
|
-
static get category() {
|
|
75
|
-
return LAYOUT_CATEGORY.LIST;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
87
|
static get defaultTemplates() {
|
|
79
88
|
return DEFAULT_TEMPLATES;
|
|
80
89
|
}
|
|
@@ -86,6 +95,7 @@ export default class CollectionLayout extends TemplateBasedLayout {
|
|
|
86
95
|
...options,
|
|
87
96
|
});
|
|
88
97
|
this._initTrackable();
|
|
98
|
+
this._initTriggerable();
|
|
89
99
|
}
|
|
90
100
|
|
|
91
101
|
initialize(view) {
|
|
@@ -106,8 +116,7 @@ export default class CollectionLayout extends TemplateBasedLayout {
|
|
|
106
116
|
// TODO: compare item ids as well
|
|
107
117
|
return this.options.incremental &&
|
|
108
118
|
rendered && rendered.value && rendered.value.length > 0 &&
|
|
109
|
-
|
|
110
|
-
rendered.status === STATUS.READY &&
|
|
119
|
+
state.value && state.value.length >= rendered.value.length &&
|
|
111
120
|
state.session && rendered.session &&
|
|
112
121
|
state.session.id === rendered.session.id;
|
|
113
122
|
}
|
|
@@ -138,10 +147,12 @@ export default class CollectionLayout extends TemplateBasedLayout {
|
|
|
138
147
|
|
|
139
148
|
_afterRender(element, state) {
|
|
140
149
|
this._syncBindings(element, state);
|
|
150
|
+
this._syncTrigger(element, state);
|
|
141
151
|
}
|
|
142
152
|
|
|
143
153
|
_unrender() {
|
|
144
154
|
this._clearBindings();
|
|
155
|
+
this._untrackTrigger();
|
|
145
156
|
}
|
|
146
157
|
|
|
147
158
|
_getItems(state) {
|
|
@@ -177,6 +188,7 @@ export default class CollectionLayout extends TemplateBasedLayout {
|
|
|
177
188
|
|
|
178
189
|
destroy() {
|
|
179
190
|
this._destroyTrackable();
|
|
191
|
+
this._destroyTriggerable();
|
|
180
192
|
this._view = undefined;
|
|
181
193
|
super.destroy();
|
|
182
194
|
}
|
|
@@ -184,3 +196,4 @@ export default class CollectionLayout extends TemplateBasedLayout {
|
|
|
184
196
|
}
|
|
185
197
|
|
|
186
198
|
makeTrackable(CollectionLayout.prototype);
|
|
199
|
+
makeTriggerable(CollectionLayout.prototype);
|
package/src/layout/list/list.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { findInAncestors, requestAnimationFrame as raf } from '@miso.ai/commons';
|
|
2
|
-
import { LAYOUT_CATEGORY } from '../../constants.js';
|
|
3
2
|
import TemplateBasedLayout from '../template.js';
|
|
4
3
|
import { requiresImplementation } from '../templates.js';
|
|
5
4
|
|
|
@@ -30,10 +29,6 @@ const DEFAULT_TEMPLATES = Object.freeze({
|
|
|
30
29
|
|
|
31
30
|
export default class RadioLayout extends TemplateBasedLayout {
|
|
32
31
|
|
|
33
|
-
static get category() {
|
|
34
|
-
return LAYOUT_CATEGORY.RADIO;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
32
|
static get defaultTemplates() {
|
|
38
33
|
return DEFAULT_TEMPLATES;
|
|
39
34
|
}
|
package/src/layout/raf.js
CHANGED
|
@@ -2,8 +2,8 @@ import { defineValues, requestAnimationFrame as raf, capture } from '@miso.ai/co
|
|
|
2
2
|
|
|
3
3
|
export default class RafLayout {
|
|
4
4
|
|
|
5
|
-
constructor({ role, workflow, ...options } = {}) {
|
|
6
|
-
defineValues(this, { role, workflow, options });
|
|
5
|
+
constructor({ role, workflow, workflowOptions, ...options } = {}) {
|
|
6
|
+
defineValues(this, { role, workflow, workflowOptions, options });
|
|
7
7
|
this._unsubscribes = [];
|
|
8
8
|
this._rendered = new WeakMap();
|
|
9
9
|
this._element = undefined;
|
package/src/layout/text/text.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { escapeHtml } from '@miso.ai/commons';
|
|
2
|
-
import { LAYOUT_CATEGORY } from '../../constants.js';
|
|
3
2
|
import TemplateBasedLayout from '../template.js';
|
|
4
3
|
|
|
5
4
|
const TYPE = 'text';
|
|
@@ -42,10 +41,6 @@ const DEFAULT_TEMPLATES = Object.freeze({
|
|
|
42
41
|
|
|
43
42
|
export default class TextLayout extends TemplateBasedLayout {
|
|
44
43
|
|
|
45
|
-
static get category() {
|
|
46
|
-
return LAYOUT_CATEGORY.TEXT;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
44
|
static get type() {
|
|
50
45
|
return TYPE;
|
|
51
46
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { trimObj, defineValues, Resolution, pacer } from '@miso.ai/commons';
|
|
2
|
-
import {
|
|
2
|
+
import { STATUS } from '../../../constants.js';
|
|
3
3
|
import ProgressiveLayout from '../../progressive.js';
|
|
4
4
|
import PlaintextRenderer from './plaintext.js';
|
|
5
5
|
import { containerElement, cursorClassName, fromSameSession, normalizeOnDebug } from './utils.js';
|
|
@@ -9,10 +9,6 @@ const DEFAULT_CLASSNAME = 'miso-typewriter';
|
|
|
9
9
|
|
|
10
10
|
export default class TypewriterLayout extends ProgressiveLayout {
|
|
11
11
|
|
|
12
|
-
static get category() {
|
|
13
|
-
return LAYOUT_CATEGORY.TEXT;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
12
|
static get type() {
|
|
17
13
|
return TYPE;
|
|
18
14
|
}
|
package/src/layout/trackable.js
CHANGED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { mixin, viewable as whenViewable } from '@miso.ai/commons';
|
|
2
|
+
import { STATUS } from '../constants.js';
|
|
3
|
+
import { fields } from '../actor/index.js';
|
|
4
|
+
|
|
5
|
+
export function makeTriggerable(prototype) {
|
|
6
|
+
mixin(prototype, TriggerableMixin.prototype);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class TriggerableMixin {
|
|
10
|
+
|
|
11
|
+
_initTriggerable() {
|
|
12
|
+
this._trigger = undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
_syncTrigger(element, state) {
|
|
16
|
+
if (!this.options.infiniteScroll) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const workflowPaginationOptions = this.workflowOptions.pagination;
|
|
20
|
+
if (!workflowPaginationOptions.active || workflowPaginationOptions.mode !== 'infiniteScroll') {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
// only track trigger when ready
|
|
24
|
+
if (state.status === STATUS.READY) {
|
|
25
|
+
this._trackTrigger(element);
|
|
26
|
+
} else {
|
|
27
|
+
this._untrackTrigger();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async _trackTrigger(element) {
|
|
32
|
+
if (this._trigger) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const triggerElement = element.querySelector('[data-role="trigger"]');
|
|
36
|
+
if (!triggerElement) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const ac = new AbortController();
|
|
40
|
+
this._trigger = Object.freeze({
|
|
41
|
+
element: triggerElement,
|
|
42
|
+
ac,
|
|
43
|
+
});
|
|
44
|
+
let result = false;
|
|
45
|
+
try {
|
|
46
|
+
await whenViewable(triggerElement, { area: 1, duration: 0, signal: ac.signal });
|
|
47
|
+
result = true;
|
|
48
|
+
} catch (e) {
|
|
49
|
+
if (e.name !== 'AbortError') {
|
|
50
|
+
throw e;
|
|
51
|
+
}
|
|
52
|
+
} finally {
|
|
53
|
+
this._trigger = undefined;
|
|
54
|
+
}
|
|
55
|
+
if (result) {
|
|
56
|
+
this._onTrigger();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
_onTrigger() {
|
|
61
|
+
this._view.hub.trigger(fields.more());
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
_untrackTrigger() {
|
|
65
|
+
if (!this._trigger) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
this._trigger.ac && this._trigger.ac.abort();
|
|
69
|
+
this._trigger = undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
_destroyTriggerable() {
|
|
73
|
+
this._untrackTrigger();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
}
|
package/src/util/states.js
CHANGED
|
@@ -4,20 +4,6 @@ import { EVENT_TYPE, TRACKING_STATUS, validateEventType, validateTrackingStatus
|
|
|
4
4
|
const { IMPRESSION, VIEWABLE, CLICK } = EVENT_TYPE;
|
|
5
5
|
const { UNTRACKED, TRIGGERED } = TRACKING_STATUS;
|
|
6
6
|
|
|
7
|
-
/*
|
|
8
|
-
const STATES = {
|
|
9
|
-
NEW: Object.freeze({
|
|
10
|
-
[IMPRESSION]: UNTRACKED,
|
|
11
|
-
[VIEWABLE]: UNTRACKED,
|
|
12
|
-
}),
|
|
13
|
-
UNTRACKED: Object.freeze({
|
|
14
|
-
[IMPRESSION]: UNTRACKED,
|
|
15
|
-
[VIEWABLE]: UNTRACKED,
|
|
16
|
-
[CLICK]: UNTRACKED,
|
|
17
|
-
}),
|
|
18
|
-
};
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
7
|
const UNTRACKED_STATES = Object.freeze({
|
|
22
8
|
[IMPRESSION]: UNTRACKED,
|
|
23
9
|
[VIEWABLE]: UNTRACKED,
|
package/src/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default '1.11.0-beta.
|
|
1
|
+
export default '1.11.0-beta.10';
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { API } from '@miso.ai/commons';
|
|
2
2
|
import Workflow from './base.js';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import { fields, FeedbackActor, AutocompleteActor } from '../actor/index.js';
|
|
6
|
-
import { ROLE, STATUS, ORGANIC_QUESTION_SOURCE, DATA_ASPECT } from '../constants.js';
|
|
3
|
+
import { fields, FeedbackActor } from '../actor/index.js';
|
|
4
|
+
import { ROLE, STATUS, ORGANIC_QUESTION_SOURCE } from '../constants.js';
|
|
7
5
|
import { SearchBoxLayout, TextLayout, ListLayout, TypewriterLayout, FeedbackLayout, AffiliationLayout } from '../layout/index.js';
|
|
8
6
|
import { processData as processAffiliationData } from '../affiliation/index.js';
|
|
9
|
-
import {
|
|
7
|
+
import { mergeRolesOptions } from './options.js';
|
|
8
|
+
import { writeAnswerStageToMeta, mergeInteraction } from './processors.js';
|
|
10
9
|
|
|
11
10
|
const DEFAULT_API_OPTIONS = Object.freeze({
|
|
11
|
+
...Workflow.DEFAULT_API_OPTIONS,
|
|
12
12
|
group: API.GROUP.ASK,
|
|
13
13
|
payload: {
|
|
14
|
+
...Workflow.DEFAULT_API_OPTIONS.payload,
|
|
14
15
|
source_fl: ['cover_image', 'url', 'created_at', 'updated_at', 'published_at'],
|
|
15
16
|
cite_link: 1,
|
|
16
17
|
cite_start: '[',
|
|
@@ -27,6 +28,7 @@ const DEFAULT_AUTOCOMPLETE_OPTIONS = Object.freeze({
|
|
|
27
28
|
});
|
|
28
29
|
|
|
29
30
|
const DEFAULT_LAYOUTS = Object.freeze({
|
|
31
|
+
...Workflow.DEFAULT_LAYOUTS,
|
|
30
32
|
[ROLE.QUERY]: [SearchBoxLayout.type, { placeholder: 'Ask a question' }],
|
|
31
33
|
[ROLE.QUESTION]: [TextLayout.type, { tag: 'h2' }],
|
|
32
34
|
[ROLE.ANSWER]: TypewriterLayout.type,
|
|
@@ -36,17 +38,25 @@ const DEFAULT_LAYOUTS = Object.freeze({
|
|
|
36
38
|
});
|
|
37
39
|
|
|
38
40
|
const DEFAULT_TRACKERS = Object.freeze({
|
|
41
|
+
...Workflow.DEFAULT_TRACKERS,
|
|
39
42
|
[ROLE.SOURCES]: {},
|
|
40
43
|
[ROLE.AFFILIATION]: {},
|
|
44
|
+
[ROLE.PRODUCTS]: {},
|
|
41
45
|
});
|
|
42
46
|
|
|
43
47
|
const DEFAULT_OPTIONS = Object.freeze({
|
|
48
|
+
...Workflow.DEFAULT_OPTIONS,
|
|
44
49
|
api: DEFAULT_API_OPTIONS,
|
|
45
50
|
autocomplete: DEFAULT_AUTOCOMPLETE_OPTIONS,
|
|
46
51
|
layouts: DEFAULT_LAYOUTS,
|
|
47
52
|
trackers: DEFAULT_TRACKERS,
|
|
48
53
|
});
|
|
49
54
|
|
|
55
|
+
const ROLES_OPTIONS = mergeRolesOptions(Workflow.ROLES_OPTIONS, {
|
|
56
|
+
main: ROLE.ANSWER,
|
|
57
|
+
members: Object.keys(DEFAULT_LAYOUTS),
|
|
58
|
+
});
|
|
59
|
+
|
|
50
60
|
export default class AnswerBasedWorkflow extends Workflow {
|
|
51
61
|
|
|
52
62
|
// constructor //
|
|
@@ -59,12 +69,6 @@ export default class AnswerBasedWorkflow extends Workflow {
|
|
|
59
69
|
_initActors(args) {
|
|
60
70
|
super._initActors(args);
|
|
61
71
|
this._feedback = new FeedbackActor(this._hub);
|
|
62
|
-
/*
|
|
63
|
-
this._autocomplete = new AutocompleteActor(this._hub, {
|
|
64
|
-
source: sources.api(this._client),
|
|
65
|
-
options: this._options,
|
|
66
|
-
});
|
|
67
|
-
*/
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
_initSubscriptions(args) {
|
|
@@ -72,30 +76,49 @@ export default class AnswerBasedWorkflow extends Workflow {
|
|
|
72
76
|
this._unsubscribes = [
|
|
73
77
|
...this._unsubscribes,
|
|
74
78
|
this._hub.on(fields.query(), args => this._query(args)),
|
|
75
|
-
this._hub.on(fields.view(ROLE.ANSWER), data => this._onAnswerViewUpdate(data)),
|
|
76
79
|
this._views.get(ROLE.ANSWER).on('citation-click', event => this._onCitationClick(event)),
|
|
77
80
|
];
|
|
78
81
|
}
|
|
79
82
|
|
|
83
|
+
// configuration //
|
|
84
|
+
useLink(fn) {
|
|
85
|
+
if (typeof fn !== 'function' && fn !== false) {
|
|
86
|
+
throw new Error('useLink(fn) expects fn to be a function or false');
|
|
87
|
+
}
|
|
88
|
+
this._linkFn = fn;
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
|
|
80
92
|
// lifecycle //
|
|
81
93
|
restart() {
|
|
82
94
|
// clear question id from previous session
|
|
83
95
|
if (this._questionId) {
|
|
84
96
|
this._questionId = undefined;
|
|
85
97
|
}
|
|
86
|
-
// interrupt event
|
|
87
|
-
// TODO: move to workflow base
|
|
88
|
-
const { session, status, ongoing } = this._hub.states[fields.view(ROLE.ANSWER)] || {};
|
|
89
|
-
if (session && status !== STATUS.INITIAL && (status !== STATUS.READY || ongoing)) {
|
|
90
|
-
// it's interrupted by a new question
|
|
91
|
-
const state = Object.freeze({ session, status, ongoing });
|
|
92
|
-
this._emit('interrupt', state);
|
|
93
|
-
this._emit('finally', state);
|
|
94
|
-
}
|
|
95
98
|
// restart
|
|
96
99
|
super.restart();
|
|
97
100
|
}
|
|
98
101
|
|
|
102
|
+
_emitInterruptEventIfNecessary() {
|
|
103
|
+
const state = this._hub.states[fields.view(this._roles.main)] || {};
|
|
104
|
+
if (state.session && state.status !== STATUS.INITIAL && (state.status !== STATUS.READY || state.ongoing)) {
|
|
105
|
+
// it's interrupted by a new question
|
|
106
|
+
this._emitLifecycleEvent('interrupt', state);
|
|
107
|
+
this._emitLifecycleEvent('finally', state);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
_onMainViewUpdate(state) {
|
|
112
|
+
const { status } = state;
|
|
113
|
+
const done = status === STATUS.READY && !state.ongoing;
|
|
114
|
+
const erroneous = status === STATUS.ERRONEOUS;
|
|
115
|
+
const eventName = done ? 'done' : erroneous ? 'error' : status;
|
|
116
|
+
this._emitLifecycleEvent(eventName, state);
|
|
117
|
+
if (done || erroneous) {
|
|
118
|
+
this._emitLifecycleEvent('finally', state);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
99
122
|
// properties //
|
|
100
123
|
get questionId() {
|
|
101
124
|
return this._questionId;
|
|
@@ -130,53 +153,61 @@ export default class AnswerBasedWorkflow extends Workflow {
|
|
|
130
153
|
}
|
|
131
154
|
|
|
132
155
|
_query(args = {}) {
|
|
156
|
+
if (this._linkFn) {
|
|
157
|
+
this._submit(args);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
133
160
|
// start a new session
|
|
134
161
|
this.restart();
|
|
135
162
|
|
|
136
|
-
// keep track of question source on this session
|
|
137
|
-
|
|
138
|
-
session.meta.question_source = args.questionSource || ORGANIC_QUESTION_SOURCE; // might be null, not undefined
|
|
163
|
+
// keep track of question source on this session, for suggested questions interactions
|
|
164
|
+
this._writeQuestionSourceToSession(args);
|
|
139
165
|
|
|
140
166
|
// build payload and trigger request
|
|
141
167
|
const payload = this._buildPayload(args);
|
|
142
|
-
|
|
143
|
-
this._request(event);
|
|
168
|
+
this._request({ payload });
|
|
144
169
|
}
|
|
145
170
|
|
|
146
|
-
|
|
147
|
-
this.
|
|
171
|
+
_submit(args) {
|
|
172
|
+
if (!this._linkFn) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
// TODO: we want a submit event, but only with linkFn
|
|
176
|
+
const url = this._linkFn(args.q);
|
|
177
|
+
window.open(url, '_blank');
|
|
148
178
|
}
|
|
149
179
|
|
|
150
|
-
|
|
151
|
-
|
|
180
|
+
_writeQuestionSourceToSession(args) {
|
|
181
|
+
this.session.meta.question_source = args.qs || ORGANIC_QUESTION_SOURCE; // might be null, not undefined
|
|
152
182
|
}
|
|
153
183
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
updateCompletions(event) {
|
|
157
|
-
// TODO: verify
|
|
158
|
-
this._hub.update(fields.data(DATA_ASPECT.AUTOCOMPLETE), {
|
|
159
|
-
...event,
|
|
160
|
-
source: 'manual',
|
|
161
|
-
});
|
|
162
|
-
return this;
|
|
184
|
+
_buildPayload() {
|
|
185
|
+
throw new Error(`Not implemented`);
|
|
163
186
|
}
|
|
164
|
-
*/
|
|
165
187
|
|
|
166
188
|
// data //
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
189
|
+
_updateData(data) {
|
|
190
|
+
// if it's the head response, write question id and return
|
|
191
|
+
if (data.value && !data.value.answer_stage) {
|
|
192
|
+
this._handleHeadResponse(data);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
super._updateData(data);
|
|
172
196
|
|
|
173
197
|
// update URL if autoQuery.updateUrl is not false
|
|
174
198
|
this._updateUrlIfNecessary(data);
|
|
199
|
+
}
|
|
175
200
|
|
|
176
|
-
|
|
177
|
-
|
|
201
|
+
_handleHeadResponse(data) {
|
|
202
|
+
// capture question ID and register at context
|
|
203
|
+
this._writeQuestionIdFromData(data);
|
|
204
|
+
}
|
|
178
205
|
|
|
179
|
-
|
|
206
|
+
_defaultProcessData(data) {
|
|
207
|
+
data = super._defaultProcessData(data);
|
|
208
|
+
data = processAffiliationData(data);
|
|
209
|
+
data = writeAnswerStageToMeta(data);
|
|
210
|
+
return data;
|
|
180
211
|
}
|
|
181
212
|
|
|
182
213
|
_writeQuestionIdFromData({ value }) {
|
|
@@ -204,38 +235,32 @@ export default class AnswerBasedWorkflow extends Workflow {
|
|
|
204
235
|
}
|
|
205
236
|
|
|
206
237
|
// interactions //
|
|
207
|
-
|
|
208
|
-
payload = super.
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
238
|
+
_defaultProcessInteraction(payload, args) {
|
|
239
|
+
payload = super._defaultProcessInteraction(payload, args);
|
|
240
|
+
payload = this._writeAskPropertiesToInteraction(payload, args);
|
|
241
|
+
return payload;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
_writeAskPropertiesToInteraction(payload = {}, args) {
|
|
245
|
+
const question_source = this._getQuestionSourceFromViewState(args);
|
|
246
|
+
const question_id = this.questionId;
|
|
247
|
+
return mergeInteraction(payload, {
|
|
214
248
|
context: {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
question_id
|
|
218
|
-
|
|
219
|
-
}),
|
|
249
|
+
custom_context: {
|
|
250
|
+
question_source,
|
|
251
|
+
question_id,
|
|
252
|
+
},
|
|
220
253
|
},
|
|
221
|
-
};
|
|
254
|
+
});
|
|
222
255
|
}
|
|
223
256
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
const done = status === STATUS.READY && !ongoing;
|
|
230
|
-
const erroneous = status === STATUS.ERRONEOUS;
|
|
231
|
-
const eventName = done ? 'done' : erroneous ? 'error' : status;
|
|
232
|
-
const state = Object.freeze({ session, status, ongoing });
|
|
233
|
-
this._emit(eventName, state);
|
|
234
|
-
if (done || erroneous) {
|
|
235
|
-
this._emit('finally', state);
|
|
236
|
-
}
|
|
257
|
+
_getQuestionSourceFromViewState(args) {
|
|
258
|
+
const { request } = this._hub.states[fields.view(args.role)] || {};
|
|
259
|
+
const { payload } = request || {};
|
|
260
|
+
return (payload && payload._meta && payload._meta.question_source) || undefined;
|
|
237
261
|
}
|
|
238
262
|
|
|
263
|
+
// handlers //
|
|
239
264
|
_onCitationClick({ index }) {
|
|
240
265
|
const { value } = this.states[fields.data()] || {};
|
|
241
266
|
const { sources } = value || {};
|
|
@@ -269,12 +294,11 @@ export default class AnswerBasedWorkflow extends Workflow {
|
|
|
269
294
|
|
|
270
295
|
}
|
|
271
296
|
|
|
272
|
-
// makeConfigurable(AnswerBasedWorkflow.prototype, ['autocomplete']);
|
|
273
|
-
|
|
274
297
|
Object.assign(AnswerBasedWorkflow, {
|
|
275
298
|
DEFAULT_API_OPTIONS,
|
|
276
299
|
DEFAULT_AUTOCOMPLETE_OPTIONS,
|
|
277
300
|
DEFAULT_LAYOUTS,
|
|
278
301
|
DEFAULT_TRACKERS,
|
|
279
302
|
DEFAULT_OPTIONS,
|
|
303
|
+
ROLES_OPTIONS,
|
|
280
304
|
});
|