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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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.loadingBar(layout, state)}</div>`;
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 loadingBar(layout, state) {
82
- const {
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
- loadingBar
111
+ loading
115
112
  });
116
113
  class CollectionLayout extends _template.default {
117
114
  static get defaultTemplates() {
@@ -4,4 +4,4 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _default = exports.default = '1.11.0-beta.10';
7
+ var _default = exports.default = '1.11.0-beta.11';
@@ -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 = (0, _processors.writeFiltersToPayload)(payload, filters);
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.concatResults = concatResults;
7
+ exports.concatItemsFromMoreResponse = concatItemsFromMoreResponse;
8
8
  exports.getRevision = getRevision;
9
- exports.markExhaustion = markExhaustion;
10
9
  exports.mergeInteraction = mergeInteraction;
11
- exports.retainFacetCounts = retainFacetCounts;
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 retainFacetCounts(data, currentFacetCounts) {
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 concatResults(oldData, newData) {
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 markExhaustion(data) {
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]: products
205
+ [role]: items
200
206
  } = value;
201
- if (!products) {
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
- } = products;
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; // ignore
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
- const start = (this._page + 1) * this._getPageSize();
128
- const payload = this._buildPayload(Object.assign({}, query, {
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.retainFacetCounts)(data, this._currentFacetCounts);
158
- data = (0, _processors.markExhaustion)(data);
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 || !request.payload.start) {
170
- return data; // the initial state, or not from "more" request
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.concatResults)(currentData, data);
214
+ return (0, _processors.concatItemsFromMoreResponse)(currentData, data, {
215
+ role: this._roles.main
216
+ });
175
217
  }
176
218
  }
177
219
  exports.default = SearchBasedWorkflow;
package/package.json CHANGED
@@ -26,7 +26,7 @@
26
26
  "url": "https://github.com/MisoAI/miso-client-js-sdk/issues"
27
27
  },
28
28
  "dependencies": {
29
- "@miso.ai/commons": "1.11.0-beta.10"
29
+ "@miso.ai/commons": "1.11.0-beta.11"
30
30
  },
31
- "version": "1.11.0-beta.10"
31
+ "version": "1.11.0-beta.11"
32
32
  }
@@ -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.loadingBar(layout, state)}</div>`;
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 loadingBar(layout, state) {
52
- const { className } = layout;
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
- loadingBar,
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.10';
1
+ export default '1.11.0-beta.11';
@@ -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 = writeFiltersToPayload(payload, filters);
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 retainFacetCounts(data, currentFacetCounts) {
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 concatResults(oldData, newData, { role = ROLE.PRODUCTS } = {}) {
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 markExhaustion(data, { role = ROLE.PRODUCTS } = {}) {
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]: products } = value;
164
- if (!products) {
167
+ const { [role]: items } = value;
168
+ if (!items) {
165
169
  return data;
166
170
  }
167
171
  const { rows } = request.payload;
168
- const { length } = products;
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, retainFacetCounts, markExhaustion, concatResults } from './processors.js';
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; // ignore
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
- const start = (this._page + 1) * this._getPageSize();
128
- const payload = this._buildPayload({ ...query, filters, start });
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 = retainFacetCounts(data, this._currentFacetCounts);
153
- data = markExhaustion(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 || !request.payload.start) {
165
- return data; // the initial state, or not from "more" request
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 concatResults(currentData, data);
208
+ return concatItemsFromMoreResponse(currentData, data, { role: this._roles.main });
170
209
  }
171
210
 
172
211
  }