@miso.ai/client-sdk-ui 1.11.0-beta.10 → 1.11.0-beta.12
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/layout/input/search-box.js +2 -5
- package/dist/cjs/layout/list/collection.js +4 -7
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/workflow/answer-based.js +3 -18
- package/dist/cjs/workflow/explore.js +25 -30
- package/dist/cjs/workflow/hybrid-search-results.js +2 -6
- package/dist/cjs/workflow/hybrid-search.js +2 -2
- package/dist/cjs/workflow/processors.js +17 -11
- package/dist/cjs/workflow/search-based.js +53 -11
- package/dist/cjs/workflow/use-link.js +44 -0
- package/package.json +2 -2
- package/src/layout/input/search-box.js +2 -5
- package/src/layout/list/collection.js +4 -5
- package/src/version.js +1 -1
- package/src/workflow/answer-based.js +4 -19
- package/src/workflow/explore.js +18 -25
- package/src/workflow/hybrid-search-results.js +1 -2
- package/src/workflow/hybrid-search.js +2 -2
- package/src/workflow/processors.js +12 -8
- package/src/workflow/search-based.js +51 -12
- package/src/workflow/use-link.js +40 -0
|
@@ -107,10 +107,7 @@ function completionList(layout, type, items) {
|
|
|
107
107
|
className,
|
|
108
108
|
templates
|
|
109
109
|
} = layout;
|
|
110
|
-
return
|
|
111
|
-
<ul class="${className}__${type}-list" data-role="${type}-list">
|
|
112
|
-
${items.map(item => templates.completionItem(layout, type, item)).join('')}
|
|
113
|
-
</ul>`.trim();
|
|
110
|
+
return `<ul class="${className}__${type}-list" data-role="${type}-list">${items.map(item => templates.completionItem(layout, type, item)).join('')}</ul>`;
|
|
114
111
|
}
|
|
115
112
|
function completionItem(layout, type, item) {
|
|
116
113
|
const {
|
|
@@ -334,7 +331,7 @@ class SearchBoxLayout extends _template.default {
|
|
|
334
331
|
target,
|
|
335
332
|
isComposing
|
|
336
333
|
} = _ref8;
|
|
337
|
-
if (!isComposing && key === 'Enter' && target.matches('input')) {
|
|
334
|
+
if (!isComposing && key === 'Enter' && target.matches('[data-role="input"]')) {
|
|
338
335
|
this._submit(target.value);
|
|
339
336
|
target.blur();
|
|
340
337
|
}
|
|
@@ -22,7 +22,7 @@ function root(layout, state) {
|
|
|
22
22
|
status
|
|
23
23
|
} = state;
|
|
24
24
|
const roleAttr = role ? `data-role="${role}"` : '';
|
|
25
|
-
return `<div class="${className} ${status}" ${roleAttr}>${status === _constants.STATUS.READY ? templates[status](layout, state) : ''}${templates.trigger(layout, state)}${templates.
|
|
25
|
+
return `<div class="${className} ${status}" ${roleAttr}>${status === _constants.STATUS.READY ? templates[status](layout, state) : ''}${templates.trigger(layout, state)}${templates.loading(layout, state)}</div>`;
|
|
26
26
|
}
|
|
27
27
|
function ready(layout, state) {
|
|
28
28
|
const {
|
|
@@ -78,11 +78,8 @@ function trigger(layout, state) {
|
|
|
78
78
|
} = layout;
|
|
79
79
|
return `<div class="${className}__trigger" data-role="trigger"></div>`;
|
|
80
80
|
}
|
|
81
|
-
function
|
|
82
|
-
|
|
83
|
-
className
|
|
84
|
-
} = layout;
|
|
85
|
-
return `<div class="${className}__loading-bar"></div>`;
|
|
81
|
+
function loading() {
|
|
82
|
+
return `<div class="miso-loading" aria-label="Loading" data-role="loading"></div>`;
|
|
86
83
|
}
|
|
87
84
|
|
|
88
85
|
// TODO: let templates.js control what to be included here
|
|
@@ -111,7 +108,7 @@ const DEFAULT_TEMPLATES = Object.freeze({
|
|
|
111
108
|
imageBlock: _templates.imageBlock,
|
|
112
109
|
indexBlock: _templates.indexBlock,
|
|
113
110
|
trigger,
|
|
114
|
-
|
|
111
|
+
loading
|
|
115
112
|
});
|
|
116
113
|
class CollectionLayout extends _template.default {
|
|
117
114
|
static get defaultTemplates() {
|
package/dist/cjs/version.js
CHANGED
|
@@ -12,6 +12,7 @@ var _index2 = require("../layout/index.js");
|
|
|
12
12
|
var _index3 = require("../affiliation/index.js");
|
|
13
13
|
var _options = require("./options.js");
|
|
14
14
|
var _processors = require("./processors.js");
|
|
15
|
+
var _useLink = require("./use-link.js");
|
|
15
16
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
17
|
const DEFAULT_API_OPTIONS = Object.freeze(Object.assign({}, _base.default.DEFAULT_API_OPTIONS, {
|
|
17
18
|
group: _commons.API.GROUP.ASK,
|
|
@@ -84,15 +85,6 @@ class AnswerBasedWorkflow extends _base.default {
|
|
|
84
85
|
this._unsubscribes = [...this._unsubscribes, this._hub.on(_index.fields.query(), args => this._query(args)), this._views.get(_constants.ROLE.ANSWER).on('citation-click', event => this._onCitationClick(event))];
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
// configuration //
|
|
88
|
-
useLink(fn) {
|
|
89
|
-
if (typeof fn !== 'function' && fn !== false) {
|
|
90
|
-
throw new Error('useLink(fn) expects fn to be a function or false');
|
|
91
|
-
}
|
|
92
|
-
this._linkFn = fn;
|
|
93
|
-
return this;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
88
|
// lifecycle //
|
|
97
89
|
restart() {
|
|
98
90
|
// clear question id from previous session
|
|
@@ -166,7 +158,7 @@ class AnswerBasedWorkflow extends _base.default {
|
|
|
166
158
|
_query() {
|
|
167
159
|
let args = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
168
160
|
if (this._linkFn) {
|
|
169
|
-
this.
|
|
161
|
+
this._submitToPage(args);
|
|
170
162
|
return;
|
|
171
163
|
}
|
|
172
164
|
// start a new session
|
|
@@ -181,14 +173,6 @@ class AnswerBasedWorkflow extends _base.default {
|
|
|
181
173
|
payload
|
|
182
174
|
});
|
|
183
175
|
}
|
|
184
|
-
_submit(args) {
|
|
185
|
-
if (!this._linkFn) {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
// TODO: we want a submit event, but only with linkFn
|
|
189
|
-
const url = this._linkFn(args.q);
|
|
190
|
-
window.open(url, '_blank');
|
|
191
|
-
}
|
|
192
176
|
_writeQuestionSourceToSession(args) {
|
|
193
177
|
this.session.meta.question_source = args.qs || _constants.ORGANIC_QUESTION_SOURCE; // might be null, not undefined
|
|
194
178
|
}
|
|
@@ -323,6 +307,7 @@ class AnswerBasedWorkflow extends _base.default {
|
|
|
323
307
|
}
|
|
324
308
|
}
|
|
325
309
|
exports.default = AnswerBasedWorkflow;
|
|
310
|
+
(0, _useLink.enableUseLink)(AnswerBasedWorkflow.prototype);
|
|
326
311
|
Object.assign(AnswerBasedWorkflow, {
|
|
327
312
|
DEFAULT_API_OPTIONS,
|
|
328
313
|
DEFAULT_AUTOCOMPLETE_OPTIONS,
|
|
@@ -10,6 +10,7 @@ var _index = require("../actor/index.js");
|
|
|
10
10
|
var _constants = require("../constants.js");
|
|
11
11
|
var _index2 = require("../layout/index.js");
|
|
12
12
|
var _options = require("./options.js");
|
|
13
|
+
var _useLink = require("./use-link.js");
|
|
13
14
|
const _excluded = ["value"];
|
|
14
15
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
16
|
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; }
|
|
@@ -61,7 +62,7 @@ class Explore extends _base.default {
|
|
|
61
62
|
}
|
|
62
63
|
_initSubscriptions(args) {
|
|
63
64
|
super._initSubscriptions(args);
|
|
64
|
-
this._unsubscribes = [...this._unsubscribes, this._views.get(_constants.ROLE.RELATED_QUESTIONS).on('click', event => this._handleRelatedQuestionClick(event)), this._hub.on(_index.fields.query(), args => this.
|
|
65
|
+
this._unsubscribes = [...this._unsubscribes, this._views.get(_constants.ROLE.RELATED_QUESTIONS).on('click', event => this._handleRelatedQuestionClick(event)), this._hub.on(_index.fields.query(), args => this._query(args))];
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
// configuration //
|
|
@@ -80,13 +81,6 @@ class Explore extends _base.default {
|
|
|
80
81
|
}
|
|
81
82
|
return super.useApi(options);
|
|
82
83
|
}
|
|
83
|
-
useLink(fn) {
|
|
84
|
-
if (typeof fn !== 'function' && fn !== false) {
|
|
85
|
-
throw new Error('useLink(fn) expects fn to be a function or false');
|
|
86
|
-
}
|
|
87
|
-
this._linkFn = fn;
|
|
88
|
-
return this;
|
|
89
|
-
}
|
|
90
84
|
|
|
91
85
|
// lifecycle //
|
|
92
86
|
start() {
|
|
@@ -94,7 +88,7 @@ class Explore extends _base.default {
|
|
|
94
88
|
relatedQuestions = true
|
|
95
89
|
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
96
90
|
if (this._linkFn === undefined) {
|
|
97
|
-
throw new Error('
|
|
91
|
+
throw new Error('Must define link mapping function with useLink(fn) before calling start()');
|
|
98
92
|
}
|
|
99
93
|
// in explore workflow, start() triggers query
|
|
100
94
|
// TODO: we should still make the query lifecycle
|
|
@@ -125,16 +119,24 @@ class Explore extends _base.default {
|
|
|
125
119
|
}
|
|
126
120
|
_defaultProcessData(data) {
|
|
127
121
|
data = super._defaultProcessData(data);
|
|
128
|
-
|
|
122
|
+
data = this._addUrlToRelatedQuestions(data);
|
|
123
|
+
return data;
|
|
124
|
+
}
|
|
125
|
+
_addUrlToRelatedQuestions(data) {
|
|
126
|
+
const {
|
|
129
127
|
value
|
|
130
128
|
} = data;
|
|
131
|
-
if (!value) {
|
|
129
|
+
if (!value || !value.related_questions) {
|
|
132
130
|
return data;
|
|
133
131
|
}
|
|
134
|
-
|
|
135
|
-
const related_questions = value.related_questions.map(
|
|
132
|
+
const linkFn = this._linkFn && this._linkFn[0];
|
|
133
|
+
const related_questions = value.related_questions.map(linkFn ? text => ({
|
|
136
134
|
text,
|
|
137
|
-
url: this.
|
|
135
|
+
url: this._getSubmitUrl({
|
|
136
|
+
q: text
|
|
137
|
+
}, {
|
|
138
|
+
generated: true
|
|
139
|
+
})
|
|
138
140
|
}) : text => ({
|
|
139
141
|
text
|
|
140
142
|
}));
|
|
@@ -159,26 +161,19 @@ class Explore extends _base.default {
|
|
|
159
161
|
}
|
|
160
162
|
this._hub.update(_index.fields.query(), args);
|
|
161
163
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
q
|
|
165
|
-
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
166
|
-
if (!this._linkFn) {
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
const url = this._getAnswersUrl(q);
|
|
170
|
-
window.open(url, '_blank');
|
|
164
|
+
_query(args) {
|
|
165
|
+
this._submitToPage(args);
|
|
171
166
|
}
|
|
172
|
-
|
|
173
|
-
let
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const url = this._linkFn(text);
|
|
167
|
+
_getSubmitUrl(args) {
|
|
168
|
+
let {
|
|
169
|
+
generated = false
|
|
170
|
+
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
171
|
+
let url = _useLink.UseLinkMixin.prototype._getSubmitUrl.call(this, args);
|
|
178
172
|
if (!generated || !this._productId) {
|
|
179
173
|
return url;
|
|
180
174
|
}
|
|
181
175
|
return `${url}&qs=${encodeURIComponent(this._productId)}`;
|
|
182
176
|
}
|
|
183
177
|
}
|
|
184
|
-
exports.default = Explore;
|
|
178
|
+
exports.default = Explore;
|
|
179
|
+
(0, _useLink.enableUseLink)(Explore.prototype);
|
|
@@ -9,7 +9,6 @@ var _searchBased = _interopRequireDefault(require("./search-based.js"));
|
|
|
9
9
|
var _index = require("../actor/index.js");
|
|
10
10
|
var _constants = require("../constants.js");
|
|
11
11
|
var _options = require("./options.js");
|
|
12
|
-
var _processors = require("./processors.js");
|
|
13
12
|
const _excluded = ["filters"];
|
|
14
13
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
14
|
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; }
|
|
@@ -47,13 +46,10 @@ class HybridSearchResults extends _searchBased.default {
|
|
|
47
46
|
}
|
|
48
47
|
_buildPayload() {
|
|
49
48
|
let _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
50
|
-
let
|
|
51
|
-
filters
|
|
52
|
-
} = _ref,
|
|
53
|
-
payload = _objectWithoutPropertiesLoose(_ref, _excluded);
|
|
49
|
+
let payload = _objectWithoutPropertiesLoose(_ref, _excluded);
|
|
54
50
|
// borrow the work from the sibling
|
|
55
51
|
payload = this._superworkflow._answer._buildPayload(payload);
|
|
56
|
-
payload = (
|
|
52
|
+
payload = _searchBased.default.prototype._buildPayload.call(this, payload);
|
|
57
53
|
payload = this._writeQuestionIdToPayload(payload);
|
|
58
54
|
return Object.assign({}, payload, {
|
|
59
55
|
answer: false
|
|
@@ -4,14 +4,14 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.buildBaseInteraction = buildBaseInteraction;
|
|
7
|
-
exports.
|
|
7
|
+
exports.concatItemsFromMoreResponse = concatItemsFromMoreResponse;
|
|
8
8
|
exports.getRevision = getRevision;
|
|
9
|
-
exports.markExhaustion = markExhaustion;
|
|
10
9
|
exports.mergeInteraction = mergeInteraction;
|
|
11
|
-
exports.
|
|
10
|
+
exports.retainFacetCountsInData = retainFacetCountsInData;
|
|
12
11
|
exports.writeAffiliationInfoToInteraction = writeAffiliationInfoToInteraction;
|
|
13
12
|
exports.writeAnswerStageToMeta = writeAnswerStageToMeta;
|
|
14
13
|
exports.writeDataStatus = writeDataStatus;
|
|
14
|
+
exports.writeExhaustionToData = writeExhaustionToData;
|
|
15
15
|
exports.writeFiltersToPayload = writeFiltersToPayload;
|
|
16
16
|
exports.writeKeywordsToData = writeKeywordsToData;
|
|
17
17
|
exports.writeMisoIdToMeta = writeMisoIdToMeta;
|
|
@@ -137,7 +137,7 @@ function composeFacetFilters(facets) {
|
|
|
137
137
|
}
|
|
138
138
|
return Object.keys(filters).length ? filters : undefined;
|
|
139
139
|
}
|
|
140
|
-
function
|
|
140
|
+
function retainFacetCountsInData(data, currentFacetCounts) {
|
|
141
141
|
if (!currentFacetCounts) {
|
|
142
142
|
return data;
|
|
143
143
|
}
|
|
@@ -161,7 +161,7 @@ function retainFacetCounts(data, currentFacetCounts) {
|
|
|
161
161
|
})
|
|
162
162
|
});
|
|
163
163
|
}
|
|
164
|
-
function
|
|
164
|
+
function concatItemsFromMoreResponse(oldData, newData) {
|
|
165
165
|
let {
|
|
166
166
|
role = _constants.ROLE.PRODUCTS
|
|
167
167
|
} = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
@@ -169,20 +169,26 @@ function concatResults(oldData, newData) {
|
|
|
169
169
|
return oldData;
|
|
170
170
|
}
|
|
171
171
|
const {
|
|
172
|
-
[role]: oldProducts = []
|
|
172
|
+
[role]: oldProducts = [],
|
|
173
|
+
facet_counts,
|
|
174
|
+
total
|
|
173
175
|
} = oldData.value;
|
|
174
176
|
const {
|
|
175
177
|
[role]: newProducts = []
|
|
176
178
|
} = newData.value;
|
|
177
|
-
// keep exhaustion flag
|
|
179
|
+
// keep old exhaustion flag, just in case
|
|
178
180
|
// TODO
|
|
181
|
+
|
|
182
|
+
// use old values of facet_counts and total, for they are affected by product_id exclusion
|
|
179
183
|
return Object.assign({}, newData, {
|
|
184
|
+
facet_counts,
|
|
185
|
+
total,
|
|
180
186
|
value: Object.assign({}, newData.value, {
|
|
181
187
|
[role]: [...oldProducts, ...newProducts]
|
|
182
188
|
})
|
|
183
189
|
});
|
|
184
190
|
}
|
|
185
|
-
function
|
|
191
|
+
function writeExhaustionToData(data) {
|
|
186
192
|
let {
|
|
187
193
|
role = _constants.ROLE.PRODUCTS
|
|
188
194
|
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
@@ -196,9 +202,9 @@ function markExhaustion(data) {
|
|
|
196
202
|
return data;
|
|
197
203
|
}
|
|
198
204
|
const {
|
|
199
|
-
[role]:
|
|
205
|
+
[role]: items
|
|
200
206
|
} = value;
|
|
201
|
-
if (!
|
|
207
|
+
if (!items) {
|
|
202
208
|
return data;
|
|
203
209
|
}
|
|
204
210
|
const {
|
|
@@ -206,7 +212,7 @@ function markExhaustion(data) {
|
|
|
206
212
|
} = request.payload;
|
|
207
213
|
const {
|
|
208
214
|
length
|
|
209
|
-
} =
|
|
215
|
+
} = items;
|
|
210
216
|
const exhausted = length < rows;
|
|
211
217
|
if (!exhausted) {
|
|
212
218
|
return data;
|
|
@@ -75,6 +75,9 @@ class SearchBasedWorkflow extends _base.default {
|
|
|
75
75
|
const data = this._hub.states[_index.fields.data()];
|
|
76
76
|
return !!(data && data.meta && data.meta.exhausted);
|
|
77
77
|
}
|
|
78
|
+
get page() {
|
|
79
|
+
return this._page;
|
|
80
|
+
}
|
|
78
81
|
|
|
79
82
|
// query //
|
|
80
83
|
query(args) {
|
|
@@ -116,25 +119,31 @@ class SearchBasedWorkflow extends _base.default {
|
|
|
116
119
|
});
|
|
117
120
|
}
|
|
118
121
|
_more() {
|
|
122
|
+
// if still loading, complain
|
|
123
|
+
if (this.status !== _constants.STATUS.READY) {
|
|
124
|
+
throw new Error(`Can not call more() while loading.`);
|
|
125
|
+
}
|
|
126
|
+
// no more pages, ignore
|
|
119
127
|
if (this.exhausted || this._page >= DEFAULT_PAGE_LIMIT - 1) {
|
|
120
|
-
return;
|
|
128
|
+
return;
|
|
121
129
|
}
|
|
122
130
|
// don't create a new session!
|
|
123
131
|
|
|
132
|
+
this._page++;
|
|
133
|
+
|
|
124
134
|
// payload
|
|
125
135
|
const query = this._getQuery();
|
|
126
136
|
const filters = this._hub.states[_index.fields.filters()]; // get stored filters
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
filters,
|
|
130
|
-
start
|
|
137
|
+
let payload = this._buildPayload(Object.assign({}, query, {
|
|
138
|
+
filters
|
|
131
139
|
}));
|
|
140
|
+
payload = this._processPayloadForMoreRequest(payload);
|
|
132
141
|
this._request({
|
|
133
142
|
payload
|
|
134
143
|
});
|
|
135
|
-
this._page++;
|
|
136
144
|
}
|
|
137
145
|
_getQuery() {
|
|
146
|
+
// TODO: just get from the hub
|
|
138
147
|
return this._queryArgs;
|
|
139
148
|
}
|
|
140
149
|
_getPageSize() {
|
|
@@ -147,15 +156,40 @@ class SearchBasedWorkflow extends _base.default {
|
|
|
147
156
|
} = _ref,
|
|
148
157
|
payload = _objectWithoutPropertiesLoose(_ref, _excluded);
|
|
149
158
|
payload = (0, _processors.writeFiltersToPayload)(payload, filters);
|
|
159
|
+
payload = this._writePageInfoToPayload(payload);
|
|
150
160
|
return payload;
|
|
151
161
|
}
|
|
162
|
+
_writePageInfoToPayload(payload) {
|
|
163
|
+
return Object.assign({}, payload, {
|
|
164
|
+
_meta: Object.assign({}, payload._meta, {
|
|
165
|
+
page: this._page
|
|
166
|
+
})
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
_processPayloadForMoreRequest() {
|
|
170
|
+
let payload = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
171
|
+
const data = this._hub.states[_index.fields.data()];
|
|
172
|
+
const {
|
|
173
|
+
[this._roles.main]: items = []
|
|
174
|
+
} = data && data.value || {};
|
|
175
|
+
const productIds = items.map(item => item.product_id).filter(v => v);
|
|
176
|
+
const exclude = [...(payload.exclude || []), ...productIds];
|
|
177
|
+
if (exclude.length === 0) {
|
|
178
|
+
return payload;
|
|
179
|
+
}
|
|
180
|
+
return Object.assign({}, payload, {
|
|
181
|
+
exclude
|
|
182
|
+
});
|
|
183
|
+
}
|
|
152
184
|
|
|
153
185
|
// data //
|
|
154
186
|
_defaultProcessData(data) {
|
|
155
187
|
data = super._defaultProcessData(data);
|
|
156
188
|
data = (0, _processors.writeKeywordsToData)(data);
|
|
157
|
-
data = (0, _processors.
|
|
158
|
-
data = (0, _processors.
|
|
189
|
+
data = (0, _processors.retainFacetCountsInData)(data, this._currentFacetCounts);
|
|
190
|
+
data = (0, _processors.writeExhaustionToData)(data, {
|
|
191
|
+
role: this._roles.main
|
|
192
|
+
});
|
|
159
193
|
return data;
|
|
160
194
|
}
|
|
161
195
|
_updateDataInHub(data) {
|
|
@@ -166,12 +200,20 @@ class SearchBasedWorkflow extends _base.default {
|
|
|
166
200
|
const {
|
|
167
201
|
request
|
|
168
202
|
} = data;
|
|
169
|
-
if (!request
|
|
170
|
-
return data; // the initial state
|
|
203
|
+
if (!request) {
|
|
204
|
+
return data; // the initial state
|
|
205
|
+
}
|
|
206
|
+
const {
|
|
207
|
+
_meta
|
|
208
|
+
} = request.payload;
|
|
209
|
+
if (!_meta || !_meta.page) {
|
|
210
|
+
return data; // not from "more" request
|
|
171
211
|
}
|
|
172
212
|
// concat records if it's from "more" request
|
|
173
213
|
const currentData = this._hub.states[_index.fields.data()];
|
|
174
|
-
return (0, _processors.
|
|
214
|
+
return (0, _processors.concatItemsFromMoreResponse)(currentData, data, {
|
|
215
|
+
role: this._roles.main
|
|
216
|
+
});
|
|
175
217
|
}
|
|
176
218
|
}
|
|
177
219
|
exports.default = SearchBasedWorkflow;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.UseLinkMixin = void 0;
|
|
7
|
+
exports.enableUseLink = enableUseLink;
|
|
8
|
+
var _commons = require("@miso.ai/commons");
|
|
9
|
+
function enableUseLink(prototype) {
|
|
10
|
+
(0, _commons.mixin)(prototype, UseLinkMixin.prototype);
|
|
11
|
+
}
|
|
12
|
+
class UseLinkMixin {
|
|
13
|
+
useLink(fn) {
|
|
14
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
15
|
+
if (typeof fn !== 'function' && fn !== false) {
|
|
16
|
+
throw new Error('useLink(fn) expects fn to be a function or false');
|
|
17
|
+
}
|
|
18
|
+
this._linkFn = fn ? [fn, options] : false;
|
|
19
|
+
return this;
|
|
20
|
+
}
|
|
21
|
+
_submitToPage() {
|
|
22
|
+
let args = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
23
|
+
if (!this._linkFn) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
// TODO: we want a submit event
|
|
27
|
+
const url = this._getSubmitUrl(args);
|
|
28
|
+
const [_, options = {}] = this._linkFn;
|
|
29
|
+
if (options.open === false) {
|
|
30
|
+
window.location.href = url;
|
|
31
|
+
} else {
|
|
32
|
+
const target = options.target || '_blank';
|
|
33
|
+
const windowFeatures = options.windowFeatures || '';
|
|
34
|
+
window.open(url, target, windowFeatures);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
_getSubmitUrl(args) {
|
|
38
|
+
if (!this._linkFn) {
|
|
39
|
+
throw new Error('useLink(fn) must be called before _getSubmitUrl()');
|
|
40
|
+
}
|
|
41
|
+
return this._linkFn[0](args.q);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.UseLinkMixin = UseLinkMixin;
|
package/package.json
CHANGED
|
@@ -78,10 +78,7 @@ function product(layout, { product }) {
|
|
|
78
78
|
|
|
79
79
|
function completionList(layout, type, items) {
|
|
80
80
|
const { className, templates } = layout;
|
|
81
|
-
return
|
|
82
|
-
<ul class="${className}__${type}-list" data-role="${type}-list">
|
|
83
|
-
${items.map(item => templates.completionItem(layout, type, item)).join('')}
|
|
84
|
-
</ul>`.trim();
|
|
81
|
+
return `<ul class="${className}__${type}-list" data-role="${type}-list">${items.map(item => templates.completionItem(layout, type, item)).join('')}</ul>`;
|
|
85
82
|
}
|
|
86
83
|
|
|
87
84
|
function completionItem(layout, type, item) {
|
|
@@ -289,7 +286,7 @@ export default class SearchBoxLayout extends TemplateBasedLayout {
|
|
|
289
286
|
}
|
|
290
287
|
|
|
291
288
|
_handleKeyDown({ key, target, isComposing }) {
|
|
292
|
-
if (!isComposing && key === 'Enter' && target.matches('input')) {
|
|
289
|
+
if (!isComposing && key === 'Enter' && target.matches('[data-role="input"]')) {
|
|
293
290
|
this._submit(target.value);
|
|
294
291
|
target.blur();
|
|
295
292
|
}
|
|
@@ -8,7 +8,7 @@ function root(layout, state) {
|
|
|
8
8
|
const { className, role, templates } = layout;
|
|
9
9
|
const { status } = state;
|
|
10
10
|
const roleAttr = role ? `data-role="${role}"` : '';
|
|
11
|
-
return `<div class="${className} ${status}" ${roleAttr}>${status === STATUS.READY ? templates[status](layout, state) : ''}${templates.trigger(layout, state)}${templates.
|
|
11
|
+
return `<div class="${className} ${status}" ${roleAttr}>${status === STATUS.READY ? templates[status](layout, state) : ''}${templates.trigger(layout, state)}${templates.loading(layout, state)}</div>`;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function ready(layout, state) {
|
|
@@ -48,9 +48,8 @@ function trigger(layout, state) {
|
|
|
48
48
|
return `<div class="${className}__trigger" data-role="trigger"></div>`;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
return `<div class="${className}__loading-bar"></div>`;
|
|
51
|
+
function loading() {
|
|
52
|
+
return `<div class="miso-loading" aria-label="Loading" data-role="loading"></div>`;
|
|
54
53
|
}
|
|
55
54
|
|
|
56
55
|
// TODO: let templates.js control what to be included here
|
|
@@ -79,7 +78,7 @@ const DEFAULT_TEMPLATES = Object.freeze({
|
|
|
79
78
|
imageBlock,
|
|
80
79
|
indexBlock,
|
|
81
80
|
trigger,
|
|
82
|
-
|
|
81
|
+
loading,
|
|
83
82
|
});
|
|
84
83
|
|
|
85
84
|
export default class CollectionLayout extends TemplateBasedLayout {
|
package/src/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default '1.11.0-beta.
|
|
1
|
+
export default '1.11.0-beta.12';
|
|
@@ -6,6 +6,7 @@ import { SearchBoxLayout, TextLayout, ListLayout, TypewriterLayout, FeedbackLayo
|
|
|
6
6
|
import { processData as processAffiliationData } from '../affiliation/index.js';
|
|
7
7
|
import { mergeRolesOptions } from './options.js';
|
|
8
8
|
import { writeAnswerStageToMeta, mergeInteraction } from './processors.js';
|
|
9
|
+
import { enableUseLink } from './use-link.js';
|
|
9
10
|
|
|
10
11
|
const DEFAULT_API_OPTIONS = Object.freeze({
|
|
11
12
|
...Workflow.DEFAULT_API_OPTIONS,
|
|
@@ -80,15 +81,6 @@ export default class AnswerBasedWorkflow extends Workflow {
|
|
|
80
81
|
];
|
|
81
82
|
}
|
|
82
83
|
|
|
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
|
-
|
|
92
84
|
// lifecycle //
|
|
93
85
|
restart() {
|
|
94
86
|
// clear question id from previous session
|
|
@@ -154,7 +146,7 @@ export default class AnswerBasedWorkflow extends Workflow {
|
|
|
154
146
|
|
|
155
147
|
_query(args = {}) {
|
|
156
148
|
if (this._linkFn) {
|
|
157
|
-
this.
|
|
149
|
+
this._submitToPage(args);
|
|
158
150
|
return;
|
|
159
151
|
}
|
|
160
152
|
// start a new session
|
|
@@ -168,15 +160,6 @@ export default class AnswerBasedWorkflow extends Workflow {
|
|
|
168
160
|
this._request({ payload });
|
|
169
161
|
}
|
|
170
162
|
|
|
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');
|
|
178
|
-
}
|
|
179
|
-
|
|
180
163
|
_writeQuestionSourceToSession(args) {
|
|
181
164
|
this.session.meta.question_source = args.qs || ORGANIC_QUESTION_SOURCE; // might be null, not undefined
|
|
182
165
|
}
|
|
@@ -294,6 +277,8 @@ export default class AnswerBasedWorkflow extends Workflow {
|
|
|
294
277
|
|
|
295
278
|
}
|
|
296
279
|
|
|
280
|
+
enableUseLink(AnswerBasedWorkflow.prototype);
|
|
281
|
+
|
|
297
282
|
Object.assign(AnswerBasedWorkflow, {
|
|
298
283
|
DEFAULT_API_OPTIONS,
|
|
299
284
|
DEFAULT_AUTOCOMPLETE_OPTIONS,
|
package/src/workflow/explore.js
CHANGED
|
@@ -4,6 +4,7 @@ import { fields } from '../actor/index.js';
|
|
|
4
4
|
import { ROLE, EVENT_TYPE } from '../constants.js';
|
|
5
5
|
import { ListLayout, SearchBoxLayout } from '../layout/index.js';
|
|
6
6
|
import { mergeRolesOptions } from './options.js';
|
|
7
|
+
import { enableUseLink, UseLinkMixin } from './use-link.js';
|
|
7
8
|
|
|
8
9
|
const DEFAULT_API_OPTIONS = Object.freeze({
|
|
9
10
|
...Workflow.DEFAULT_API_OPTIONS,
|
|
@@ -61,7 +62,7 @@ export default class Explore extends Workflow {
|
|
|
61
62
|
this._unsubscribes = [
|
|
62
63
|
...this._unsubscribes,
|
|
63
64
|
this._views.get(ROLE.RELATED_QUESTIONS).on('click', event => this._handleRelatedQuestionClick(event)),
|
|
64
|
-
this._hub.on(fields.query(), args => this.
|
|
65
|
+
this._hub.on(fields.query(), args => this._query(args)),
|
|
65
66
|
];
|
|
66
67
|
}
|
|
67
68
|
|
|
@@ -81,18 +82,10 @@ export default class Explore extends Workflow {
|
|
|
81
82
|
return super.useApi(options);
|
|
82
83
|
}
|
|
83
84
|
|
|
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
|
-
|
|
92
85
|
// lifecycle //
|
|
93
86
|
start({ relatedQuestions = true } = {}) {
|
|
94
87
|
if (this._linkFn === undefined) {
|
|
95
|
-
throw new Error('
|
|
88
|
+
throw new Error('Must define link mapping function with useLink(fn) before calling start()');
|
|
96
89
|
}
|
|
97
90
|
// in explore workflow, start() triggers query
|
|
98
91
|
// TODO: we should still make the query lifecycle
|
|
@@ -113,12 +106,17 @@ export default class Explore extends Workflow {
|
|
|
113
106
|
|
|
114
107
|
_defaultProcessData(data) {
|
|
115
108
|
data = super._defaultProcessData(data);
|
|
116
|
-
|
|
117
|
-
|
|
109
|
+
data = this._addUrlToRelatedQuestions(data);
|
|
110
|
+
return data;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
_addUrlToRelatedQuestions(data) {
|
|
114
|
+
const { value } = data;
|
|
115
|
+
if (!value || !value.related_questions) {
|
|
118
116
|
return data;
|
|
119
117
|
}
|
|
120
|
-
|
|
121
|
-
const related_questions = value.related_questions.map(
|
|
118
|
+
const linkFn = this._linkFn && this._linkFn[0];
|
|
119
|
+
const related_questions = value.related_questions.map(linkFn ? (text => ({ text, url: this._getSubmitUrl({ q: text }, { generated: true }) })) : (text => ({ text })));
|
|
122
120
|
return {
|
|
123
121
|
...data,
|
|
124
122
|
value: {
|
|
@@ -139,19 +137,12 @@ export default class Explore extends Workflow {
|
|
|
139
137
|
this._hub.update(fields.query(), args);
|
|
140
138
|
}
|
|
141
139
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
const url = this._getAnswersUrl(q);
|
|
147
|
-
window.open(url, '_blank');
|
|
140
|
+
_query(args) {
|
|
141
|
+
this._submitToPage(args);
|
|
148
142
|
}
|
|
149
143
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
const url = this._linkFn(text);
|
|
144
|
+
_getSubmitUrl(args, { generated = false } = {}) {
|
|
145
|
+
let url = UseLinkMixin.prototype._getSubmitUrl.call(this, args);
|
|
155
146
|
if (!generated || !this._productId) {
|
|
156
147
|
return url;
|
|
157
148
|
}
|
|
@@ -159,3 +150,5 @@ export default class Explore extends Workflow {
|
|
|
159
150
|
}
|
|
160
151
|
|
|
161
152
|
}
|
|
153
|
+
|
|
154
|
+
enableUseLink(Explore.prototype);
|
|
@@ -3,7 +3,6 @@ import SearchBasedWorkflow from './search-based.js';
|
|
|
3
3
|
import { fields } from '../actor/index.js';
|
|
4
4
|
import { ROLE } from '../constants.js';
|
|
5
5
|
import { mergeRolesOptions } from './options.js';
|
|
6
|
-
import { writeFiltersToPayload } from './processors.js';
|
|
7
6
|
|
|
8
7
|
const ROLES_OPTIONS = mergeRolesOptions(SearchBasedWorkflow.ROLES_OPTIONS, {
|
|
9
8
|
members: [ROLE.PRODUCTS, ROLE.KEYWORDS, ROLE.TOTAL, ROLE.FACETS, ROLE.MORE],
|
|
@@ -45,7 +44,7 @@ export default class HybridSearchResults extends SearchBasedWorkflow {
|
|
|
45
44
|
_buildPayload({ filters, ...payload } = {}) {
|
|
46
45
|
// borrow the work from the sibling
|
|
47
46
|
payload = this._superworkflow._answer._buildPayload(payload);
|
|
48
|
-
payload =
|
|
47
|
+
payload = SearchBasedWorkflow.prototype._buildPayload.call(this, payload);
|
|
49
48
|
payload = this._writeQuestionIdToPayload(payload);
|
|
50
49
|
return { ...payload, answer: false };
|
|
51
50
|
}
|
|
@@ -113,7 +113,7 @@ function composeFacetFilters(facets) {
|
|
|
113
113
|
return Object.keys(filters).length ? filters : undefined;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
export function
|
|
116
|
+
export function retainFacetCountsInData(data, currentFacetCounts) {
|
|
117
117
|
if (!currentFacetCounts) {
|
|
118
118
|
return data;
|
|
119
119
|
}
|
|
@@ -137,16 +137,20 @@ export function retainFacetCounts(data, currentFacetCounts) {
|
|
|
137
137
|
};
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
export function
|
|
140
|
+
export function concatItemsFromMoreResponse(oldData, newData, { role = ROLE.PRODUCTS } = {}) {
|
|
141
141
|
if (!newData.value) {
|
|
142
142
|
return oldData;
|
|
143
143
|
}
|
|
144
|
-
const { [role]: oldProducts = [] } = oldData.value;
|
|
144
|
+
const { [role]: oldProducts = [], facet_counts, total } = oldData.value;
|
|
145
145
|
const { [role]: newProducts = [] } = newData.value;
|
|
146
|
-
// keep exhaustion flag
|
|
146
|
+
// keep old exhaustion flag, just in case
|
|
147
147
|
// TODO
|
|
148
|
+
|
|
149
|
+
// use old values of facet_counts and total, for they are affected by product_id exclusion
|
|
148
150
|
return {
|
|
149
151
|
...newData,
|
|
152
|
+
facet_counts,
|
|
153
|
+
total,
|
|
150
154
|
value: {
|
|
151
155
|
...newData.value,
|
|
152
156
|
[role]: [...oldProducts, ...newProducts],
|
|
@@ -154,18 +158,18 @@ export function concatResults(oldData, newData, { role = ROLE.PRODUCTS } = {}) {
|
|
|
154
158
|
}
|
|
155
159
|
}
|
|
156
160
|
|
|
157
|
-
export function
|
|
161
|
+
export function writeExhaustionToData(data, { role = ROLE.PRODUCTS } = {}) {
|
|
158
162
|
const { status, request, value } = data;
|
|
159
163
|
// keep track of the exhaustion state
|
|
160
164
|
if (status !== STATUS.READY || !request || !value) {
|
|
161
165
|
return data;
|
|
162
166
|
}
|
|
163
|
-
const { [role]:
|
|
164
|
-
if (!
|
|
167
|
+
const { [role]: items } = value;
|
|
168
|
+
if (!items) {
|
|
165
169
|
return data;
|
|
166
170
|
}
|
|
167
171
|
const { rows } = request.payload;
|
|
168
|
-
const { length } =
|
|
172
|
+
const { length } = items;
|
|
169
173
|
const exhausted = length < rows;
|
|
170
174
|
if (!exhausted) {
|
|
171
175
|
return data;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { API } from '@miso.ai/commons';
|
|
2
2
|
import Workflow from './base.js';
|
|
3
3
|
import { fields } from '../actor/index.js';
|
|
4
|
-
import { ROLE } from '../constants.js';
|
|
4
|
+
import { STATUS, ROLE } from '../constants.js';
|
|
5
5
|
import { SearchBoxLayout, ListLayout, TextLayout, FacetsLayout, MoreButtonLayout } from '../layout/index.js';
|
|
6
|
-
import { writeKeywordsToData, writeFiltersToPayload,
|
|
6
|
+
import { writeKeywordsToData, writeFiltersToPayload, retainFacetCountsInData, writeExhaustionToData, concatItemsFromMoreResponse } from './processors.js';
|
|
7
7
|
import { mergeRolesOptions, makeConfigurable } from './options.js';
|
|
8
8
|
|
|
9
9
|
const DEFAULT_ROWS = 10;
|
|
@@ -79,6 +79,10 @@ export default class SearchBasedWorkflow extends Workflow {
|
|
|
79
79
|
return !!(data && data.meta && data.meta.exhausted);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
get page() {
|
|
83
|
+
return this._page;
|
|
84
|
+
}
|
|
85
|
+
|
|
82
86
|
// query //
|
|
83
87
|
query(args) {
|
|
84
88
|
if (!args.q) {
|
|
@@ -116,23 +120,29 @@ export default class SearchBasedWorkflow extends Workflow {
|
|
|
116
120
|
}
|
|
117
121
|
|
|
118
122
|
_more() {
|
|
123
|
+
// if still loading, complain
|
|
124
|
+
if (this.status !== STATUS.READY) {
|
|
125
|
+
throw new Error(`Can not call more() while loading.`);
|
|
126
|
+
}
|
|
127
|
+
// no more pages, ignore
|
|
119
128
|
if (this.exhausted || this._page >= DEFAULT_PAGE_LIMIT - 1) {
|
|
120
|
-
return;
|
|
129
|
+
return;
|
|
121
130
|
}
|
|
122
131
|
// don't create a new session!
|
|
123
132
|
|
|
133
|
+
this._page++;
|
|
134
|
+
|
|
124
135
|
// payload
|
|
125
136
|
const query = this._getQuery();
|
|
126
137
|
const filters = this._hub.states[fields.filters()]; // get stored filters
|
|
127
|
-
|
|
128
|
-
|
|
138
|
+
let payload = this._buildPayload({ ...query, filters });
|
|
139
|
+
payload = this._processPayloadForMoreRequest(payload);
|
|
129
140
|
|
|
130
141
|
this._request({ payload });
|
|
131
|
-
|
|
132
|
-
this._page++;
|
|
133
142
|
}
|
|
134
143
|
|
|
135
144
|
_getQuery() {
|
|
145
|
+
// TODO: just get from the hub
|
|
136
146
|
return this._queryArgs;
|
|
137
147
|
}
|
|
138
148
|
|
|
@@ -142,15 +152,40 @@ export default class SearchBasedWorkflow extends Workflow {
|
|
|
142
152
|
|
|
143
153
|
_buildPayload({ filters, ...payload } = {}) {
|
|
144
154
|
payload = writeFiltersToPayload(payload, filters);
|
|
155
|
+
payload = this._writePageInfoToPayload(payload);
|
|
145
156
|
return payload;
|
|
146
157
|
}
|
|
147
158
|
|
|
159
|
+
_writePageInfoToPayload(payload) {
|
|
160
|
+
return {
|
|
161
|
+
...payload,
|
|
162
|
+
_meta: {
|
|
163
|
+
...payload._meta,
|
|
164
|
+
page: this._page,
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
_processPayloadForMoreRequest(payload = {}) {
|
|
170
|
+
const data = this._hub.states[fields.data()];
|
|
171
|
+
const { [this._roles.main]: items = [] } = (data && data.value) || {};
|
|
172
|
+
const productIds = items.map(item => item.product_id).filter(v => v);
|
|
173
|
+
const exclude = [...(payload.exclude || []), ...productIds];
|
|
174
|
+
if (exclude.length === 0) {
|
|
175
|
+
return payload;
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
...payload,
|
|
179
|
+
exclude,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
148
183
|
// data //
|
|
149
184
|
_defaultProcessData(data) {
|
|
150
185
|
data = super._defaultProcessData(data);
|
|
151
186
|
data = writeKeywordsToData(data);
|
|
152
|
-
data =
|
|
153
|
-
data =
|
|
187
|
+
data = retainFacetCountsInData(data, this._currentFacetCounts);
|
|
188
|
+
data = writeExhaustionToData(data, { role: this._roles.main });
|
|
154
189
|
return data;
|
|
155
190
|
}
|
|
156
191
|
|
|
@@ -161,12 +196,16 @@ export default class SearchBasedWorkflow extends Workflow {
|
|
|
161
196
|
|
|
162
197
|
_appendResultsFromMoreRequest(data) {
|
|
163
198
|
const { request } = data;
|
|
164
|
-
if (!request
|
|
165
|
-
return data; // the initial state
|
|
199
|
+
if (!request) {
|
|
200
|
+
return data; // the initial state
|
|
201
|
+
}
|
|
202
|
+
const { _meta } = request.payload;
|
|
203
|
+
if (!_meta || !_meta.page) {
|
|
204
|
+
return data; // not from "more" request
|
|
166
205
|
}
|
|
167
206
|
// concat records if it's from "more" request
|
|
168
207
|
const currentData = this._hub.states[fields.data()];
|
|
169
|
-
return
|
|
208
|
+
return concatItemsFromMoreResponse(currentData, data, { role: this._roles.main });
|
|
170
209
|
}
|
|
171
210
|
|
|
172
211
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { mixin } from '@miso.ai/commons';
|
|
2
|
+
|
|
3
|
+
export function enableUseLink(prototype) {
|
|
4
|
+
mixin(prototype, UseLinkMixin.prototype);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export class UseLinkMixin {
|
|
8
|
+
|
|
9
|
+
useLink(fn, options = {}) {
|
|
10
|
+
if (typeof fn !== 'function' && fn !== false) {
|
|
11
|
+
throw new Error('useLink(fn) expects fn to be a function or false');
|
|
12
|
+
}
|
|
13
|
+
this._linkFn = fn ? [fn, options] : false;
|
|
14
|
+
return this;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
_submitToPage(args = {}) {
|
|
18
|
+
if (!this._linkFn) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
// TODO: we want a submit event
|
|
22
|
+
const url = this._getSubmitUrl(args);
|
|
23
|
+
const [_, options = {}] = this._linkFn;
|
|
24
|
+
if (options.open === false) {
|
|
25
|
+
window.location.href = url;
|
|
26
|
+
} else {
|
|
27
|
+
const target = options.target || '_blank';
|
|
28
|
+
const windowFeatures = options.windowFeatures || '';
|
|
29
|
+
window.open(url, target, windowFeatures);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
_getSubmitUrl(args) {
|
|
34
|
+
if (!this._linkFn) {
|
|
35
|
+
throw new Error('useLink(fn) must be called before _getSubmitUrl()');
|
|
36
|
+
}
|
|
37
|
+
return this._linkFn[0](args.q);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
}
|