@miso.ai/client-sdk-ui 1.12.1 → 1.12.2-beta.1

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.
Files changed (40) hide show
  1. package/dist/cjs/affiliation/index.js +15 -15
  2. package/dist/cjs/constants.js +2 -1
  3. package/dist/cjs/defaults/ask/controls.js +28 -23
  4. package/dist/cjs/defaults/ask/templates.js +1 -2
  5. package/dist/cjs/element/context/index.js +13 -0
  6. package/dist/cjs/element/context/miso-context.js +53 -0
  7. package/dist/cjs/element/context/miso-follow-ups.js +64 -0
  8. package/dist/cjs/element/index.js +8 -5
  9. package/dist/cjs/layout/affiliation/affiliation.js +0 -6
  10. package/dist/cjs/layout/list/collection.js +1 -1
  11. package/dist/cjs/plugin.js +6 -4
  12. package/dist/cjs/version.js +1 -1
  13. package/dist/cjs/workflow/ask.js +6 -1
  14. package/dist/cjs/workflow/asks.js +39 -1
  15. package/dist/cjs/workflow/context.js +1 -0
  16. package/dist/cjs/workflow/hybrid-search.js +6 -7
  17. package/dist/cjs/workflow/options/options.js +5 -0
  18. package/dist/cjs/workflow/options/templates.js +30 -0
  19. package/dist/cjs/workflow/processors.js +4 -1
  20. package/package.json +2 -2
  21. package/src/actor/views.js +1 -1
  22. package/src/affiliation/index.js +2 -5
  23. package/src/constants.js +1 -0
  24. package/src/defaults/ask/controls.js +24 -16
  25. package/src/defaults/ask/templates.js +2 -2
  26. package/src/element/context/index.js +1 -0
  27. package/src/element/context/miso-context.js +53 -0
  28. package/src/element/context/miso-follow-ups.js +62 -0
  29. package/src/element/index.js +2 -1
  30. package/src/layout/affiliation/affiliation.js +0 -5
  31. package/src/layout/list/collection.js +1 -1
  32. package/src/plugin.js +4 -2
  33. package/src/version.js +1 -1
  34. package/src/workflow/ask.js +6 -0
  35. package/src/workflow/asks.js +37 -0
  36. package/src/workflow/context.js +1 -0
  37. package/src/workflow/hybrid-search.js +0 -1
  38. package/src/workflow/options/options.js +6 -0
  39. package/src/workflow/options/templates.js +27 -0
  40. package/src/workflow/processors.js +5 -1
@@ -6,9 +6,10 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.processData = processData;
7
7
  exports.processSovrnProduct = processSovrnProduct;
8
8
  var _commons = require("@miso.ai/commons");
9
- const _excluded = ["sovrn_aff"],
10
- _excluded2 = ["products"],
11
- _excluded3 = ["id", "deeplink", "headline", "description", "currency", "retailPrice", "salePrice", "discountRate", "image", "thumbnail", "merchant"];
9
+ const _excluded = ["affiliation_products"],
10
+ _excluded2 = ["sovrn_aff"],
11
+ _excluded3 = ["products"],
12
+ _excluded4 = ["id", "deeplink", "headline", "description", "currency", "retailPrice", "salePrice", "discountRate", "image", "thumbnail", "merchant"];
12
13
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
13
14
  function processData(data) {
14
15
  if (!data || !data.value) {
@@ -22,20 +23,19 @@ function processData(data) {
22
23
  });
23
24
  }
24
25
  function processValue(value) {
25
- /*
26
26
  if (value.affiliation_products) {
27
- const { affiliation_products, ...rest } = value;
28
- value = {
29
- ...rest,
30
- affiliation: processMisoData(affiliation_products),
31
- };
32
- } else
33
- */
34
- if (value.sovrn_aff) {
35
27
  const {
36
- sovrn_aff
28
+ affiliation_products
37
29
  } = value,
38
30
  rest = _objectWithoutPropertiesLoose(value, _excluded);
31
+ value = Object.assign({}, rest, {
32
+ affiliation: processMisoData(affiliation_products)
33
+ });
34
+ } else if (value.sovrn_aff) {
35
+ const {
36
+ sovrn_aff
37
+ } = value,
38
+ rest = _objectWithoutPropertiesLoose(value, _excluded2);
39
39
  value = Object.assign({}, rest, {
40
40
  affiliation: processSovrnData(sovrn_aff)
41
41
  });
@@ -80,7 +80,7 @@ function processSovrnData(_ref) {
80
80
  let {
81
81
  products
82
82
  } = _ref,
83
- data = _objectWithoutPropertiesLoose(_ref, _excluded2);
83
+ data = _objectWithoutPropertiesLoose(_ref, _excluded3);
84
84
  return Object.assign({
85
85
  channel: 'sovrn'
86
86
  }, data, {
@@ -101,7 +101,7 @@ function processSovrnProduct(_ref2) {
101
101
  thumbnail,
102
102
  merchant
103
103
  } = _ref2,
104
- product = _objectWithoutPropertiesLoose(_ref2, _excluded3);
104
+ product = _objectWithoutPropertiesLoose(_ref2, _excluded4);
105
105
  const brand = merchant && merchant.name;
106
106
  const brand_logo = merchant && merchant.logo;
107
107
  return (0, _commons.trimObj)({
@@ -93,5 +93,6 @@ const WORKFLOW_CONFIGURABLE = exports.WORKFLOW_CONFIGURABLE = Object.freeze({
93
93
  TRACKERS: 'trackers',
94
94
  INTERACTIONS: 'interactions',
95
95
  FILTERS: 'filters',
96
- PAGINATION: 'pagination'
96
+ PAGINATION: 'pagination',
97
+ TEMPLATES: 'templates'
97
98
  });
@@ -8,39 +8,44 @@ exports.wireRelatedResources = wireRelatedResources;
8
8
  var _templates = require("./templates.js");
9
9
  const _excluded = ["template"];
10
10
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
11
- function wireFollowUps(client, element, _ref = {}) {
11
+ function wireFollowUps(client, element, options) {
12
+ if (!client) {
13
+ throw new Error('client is required');
14
+ }
15
+ // backward compatible
16
+ setFollowUpTemplate(client, options);
17
+ replaceFollowUpsElement(element);
18
+ }
19
+ function setFollowUpTemplate(client, _ref = {}) {
12
20
  let {
13
21
  template = _templates.followUp
14
22
  } = _ref,
15
23
  options = _objectWithoutPropertiesLoose(_ref, _excluded);
16
- if (!client) {
17
- throw new Error('client is required');
18
- }
19
24
  if (typeof template !== 'function') {
20
25
  throw new Error('template must be a function or undefined');
21
26
  }
22
- if (!element) {
23
- return;
27
+ const hasExtraOptions = Object.keys(options).length > 0;
28
+ if (template === _templates.followUp && !hasExtraOptions) {
29
+ return; // same as default
24
30
  }
25
- const context = client.ui.asks;
26
- const rootWorkflow = client.ui.ask;
27
-
28
- // 1. when an answer is fully populated, insert a new section for the follow-up question
29
- context.on('done', event => {
30
- element.insertAdjacentHTML('beforeend', template(Object.assign({}, options, {
31
- parentQuestionId: event.workflow.questionId
32
- })));
33
- });
34
- // 2. if user starts over, clean up existing follow-up questions
35
- rootWorkflow.on('loading', () => {
36
- // clean up the entire follow-ups section
37
- element.innerHTML = '';
38
- // destroy all follow-up workflows
39
- context.reset({
40
- root: false
41
- });
31
+ client.ui.asks.useTemplates({
32
+ followUp: hasExtraOptions ? args => template(Object.assign({}, options, args)) : template
42
33
  });
43
34
  }
35
+ function replaceFollowUpsElement(element) {
36
+ if (!element || element.tagName.toLowerCase() === 'miso-follow-ups') {
37
+ return;
38
+ }
39
+ // replace element with <miso-follow-ups>, carrying over attributes
40
+ const newElement = document.createElement('miso-follow-ups');
41
+ for (const {
42
+ name,
43
+ value
44
+ } of element.attributes) {
45
+ newElement.setAttribute(name, value);
46
+ }
47
+ element.parentNode.replaceChild(newElement, element);
48
+ }
44
49
  function wireRelatedResources(client, element) {
45
50
  if (!client) {
46
51
  throw new Error('client is required');
@@ -91,10 +91,9 @@ class Sections extends _templates.Sections {
91
91
  }
92
92
  followUps(options) {
93
93
  const {
94
- classPrefix,
95
94
  features = {}
96
95
  } = options;
97
- return features.followUpQuestions === false ? '' : `<div id="${classPrefix}__follow-ups" class="${classPrefix}__follow-ups"></div>`;
96
+ return features.followUpQuestions === false ? '' : `<miso-follow-ups id="miso-ask-combo__follow-ups" class="miso-ask-combo__follow-ups"></miso-follow-ups>`;
98
97
  }
99
98
  relatedResourcesSection(options) {
100
99
  const {
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "MisoFollowUpsElement", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _misoFollowUps.default;
10
+ }
11
+ });
12
+ var _misoFollowUps = _interopRequireDefault(require("./miso-follow-ups.js"));
13
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _misoStub = _interopRequireDefault(require("../util/miso-stub.js"));
8
+ var _utils = require("../utils.js");
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ class MisoContextElement extends _misoStub.default {
11
+ static get observedAttributes() {
12
+ return _misoStub.default.observedAttributes;
13
+ }
14
+ constructor() {
15
+ super();
16
+ this._context = undefined;
17
+ }
18
+
19
+ // properties //
20
+ get context() {
21
+ return this._context;
22
+ }
23
+ set context(context) {
24
+ this._setContext(context);
25
+ }
26
+
27
+ // lifecycle //
28
+ async connectedCallback() {
29
+ super.connectedCallback();
30
+ const client = this._client = await (0, _utils.getClient)(MisoContextElement);
31
+ if (document.body.contains(this)) {
32
+ // in case already disconnected
33
+ this._setContext(this._getContext(client));
34
+ }
35
+ }
36
+ disconnectedCallback() {
37
+ this._setContext(undefined);
38
+ super.disconnectedCallback();
39
+ }
40
+ _getContext(client) {
41
+ throw new Error('Unimplemented');
42
+ }
43
+ _setContext(context) {
44
+ if (this._context === context) {
45
+ return;
46
+ }
47
+ const oldContext = this._context;
48
+ this._context = context;
49
+ this._onContext(context, oldContext);
50
+ }
51
+ _onContext() {}
52
+ }
53
+ exports.default = MisoContextElement;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _misoContext = _interopRequireDefault(require("./miso-context.js"));
8
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
+ const TAG_NAME = 'miso-follow-ups';
10
+ class MisoFollowUpsElement extends _misoContext.default {
11
+ static get tagName() {
12
+ return TAG_NAME;
13
+ }
14
+ static get observedAttributes() {
15
+ return _misoContext.default.observedAttributes;
16
+ }
17
+ constructor() {
18
+ super();
19
+ this._unsubscribes = [];
20
+ }
21
+ _getContext(client) {
22
+ return client.ui.asks;
23
+ }
24
+ _onContext(context, oldContext) {
25
+ if (context === oldContext) {
26
+ return;
27
+ }
28
+ this._unwire();
29
+ this._wire(context);
30
+ }
31
+ _unwire() {
32
+ for (const unsubscribe of this._unsubscribes || []) {
33
+ unsubscribe();
34
+ }
35
+ this._unsubscribes = [];
36
+ }
37
+ _wire(context) {
38
+ if (!context) {
39
+ return;
40
+ }
41
+
42
+ // 1. when an answer is fully populated, insert a new section for the follow-up question
43
+ this._unsubscribes.push(context.on('done', event => {
44
+ const template = event.workflow._options.resolved.templates.followUp;
45
+ if (!template) {
46
+ return;
47
+ }
48
+ this.insertAdjacentHTML('beforeend', template({
49
+ parentQuestionId: event.workflow.questionId
50
+ }));
51
+ }));
52
+
53
+ // 2. if user starts over, clean up existing follow-up questions
54
+ this._unsubscribes.push(context.root.on('loading', () => {
55
+ // clean up the entire follow-ups section
56
+ this.innerHTML = '';
57
+ // destroy all follow-up workflows
58
+ context.reset({
59
+ root: false
60
+ });
61
+ }));
62
+ }
63
+ }
64
+ exports.default = MisoFollowUpsElement;
@@ -6,24 +6,27 @@ Object.defineProperty(exports, "__esModule", {
6
6
  var _exportNames = {
7
7
  containers: true,
8
8
  roles: true,
9
+ contexts: true,
9
10
  combos: true
10
11
  };
11
- exports.roles = exports.containers = exports.combos = void 0;
12
+ exports.roles = exports.contexts = exports.containers = exports.combos = void 0;
12
13
  var containers = _interopRequireWildcard(require("./container/index.js"));
13
14
  exports.containers = containers;
14
15
  var roles = _interopRequireWildcard(require("./role/index.js"));
15
16
  exports.roles = roles;
17
+ var contexts = _interopRequireWildcard(require("./context/index.js"));
18
+ exports.contexts = contexts;
16
19
  var combos = _interopRequireWildcard(require("./combo/index.js"));
17
20
  exports.combos = combos;
18
- var _index4 = require("./util/index.js");
19
- Object.keys(_index4).forEach(function (key) {
21
+ var _index5 = require("./util/index.js");
22
+ Object.keys(_index5).forEach(function (key) {
20
23
  if (key === "default" || key === "__esModule") return;
21
24
  if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
22
- if (key in exports && exports[key] === _index4[key]) return;
25
+ if (key in exports && exports[key] === _index5[key]) return;
23
26
  Object.defineProperty(exports, key, {
24
27
  enumerable: true,
25
28
  get: function () {
26
- return _index4[key];
29
+ return _index5[key];
27
30
  }
28
31
  });
29
32
  });
@@ -255,12 +255,6 @@ class AffiliationLayout extends _collection.default {
255
255
  }
256
256
  this.itemIndex--;
257
257
  }
258
- _getItems(state) {
259
- const {
260
- products
261
- } = state.value || {};
262
- return products;
263
- }
264
258
  _render(element, states, controls) {
265
259
  super._render(element, states, controls);
266
260
  // sync again for incremental item rendering
@@ -197,7 +197,7 @@ class CollectionLayout extends _template.default {
197
197
  this._untrackTrigger();
198
198
  }
199
199
  _getItems(state) {
200
- return state.value;
200
+ return state.value && (state.value.products || state.value);
201
201
  }
202
202
  _getListElement(element) {
203
203
  return element.querySelector('[data-role="list"]');
@@ -15,8 +15,9 @@ var defaults = _interopRequireWildcard(require("./defaults/index.js"));
15
15
  var traits = _interopRequireWildcard(require("./trait/index.js"));
16
16
  var _styles = require("./styles.js");
17
17
  var _misoContainer = _interopRequireDefault(require("./element/container/miso-container.js"));
18
+ var _misoContext = _interopRequireDefault(require("./element/context/miso-context.js"));
18
19
  var _misoCombo = _interopRequireDefault(require("./element/combo/miso-combo.js"));
19
- const _excluded = ["containers", "roles", "combos"];
20
+ const _excluded = ["containers", "roles", "combos", "contexts"];
20
21
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
21
22
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
22
23
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
@@ -65,12 +66,13 @@ class UiPlugin extends _commons.Component {
65
66
  const {
66
67
  containers,
67
68
  roles,
68
- combos
69
+ combos,
70
+ contexts
69
71
  } = elements,
70
72
  others = _objectWithoutPropertiesLoose(elements, _excluded);
71
73
  // containers must go first, so their APIs will be ready before children are defined
72
- const ElementClasses = [...Object.values(combos), ...Object.values(containers), ...Object.values(roles), ...Object.values(others)];
73
- const ElementSuperClasses = [_misoContainer.default, _misoCombo.default];
74
+ const ElementClasses = [...Object.values(combos), ...Object.values(contexts), ...Object.values(containers), ...Object.values(roles), ...Object.values(others)];
75
+ const ElementSuperClasses = [_misoContainer.default, _misoContext.default, _misoCombo.default];
74
76
  for (const ElementClass of [...ElementSuperClasses, ...ElementClasses]) {
75
77
  ElementClass.MisoClient = MisoClient; // TODO: find better way
76
78
  }
@@ -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.12.1';
7
+ var _default = exports.default = '1.12.2-beta.1';
@@ -11,6 +11,7 @@ var _constants = require("../constants.js");
11
11
  var _index2 = require("../layout/index.js");
12
12
  var _processors = require("./processors.js");
13
13
  var _index3 = require("./options/index.js");
14
+ var _templates = require("../defaults/ask/templates.js");
14
15
  const _excluded = ["q", "qs"];
15
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
17
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
@@ -41,10 +42,14 @@ const DEFAULT_TRACKERS = Object.freeze(Object.assign({}, _answerBased.default.DE
41
42
  })
42
43
  })
43
44
  }));
45
+ const DEFAULT_TEMPLATES = Object.freeze({
46
+ followUp: _templates.followUp
47
+ });
44
48
  const DEFAULT_OPTIONS = Object.freeze(Object.assign({}, _answerBased.default.DEFAULT_OPTIONS, {
45
49
  api: DEFAULT_API_OPTIONS,
46
50
  layouts: DEFAULT_LAYOUTS,
47
- trackers: DEFAULT_TRACKERS
51
+ trackers: DEFAULT_TRACKERS,
52
+ templates: DEFAULT_TEMPLATES
48
53
  }));
49
54
  const ROLES_OPTIONS = (0, _index3.mergeRolesOptions)(_answerBased.default.ROLES_OPTIONS, {
50
55
  members: Object.keys(DEFAULT_LAYOUTS),
@@ -4,17 +4,42 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
+ var _constants = require("../constants.js");
7
8
  var _context = _interopRequireDefault(require("./context.js"));
8
9
  var _ask = _interopRequireDefault(require("./ask.js"));
10
+ var _index = require("./options/index.js");
9
11
  const _excluded = ["root", "events"];
10
12
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
13
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
14
+ const DEFAULT_AUTO_NEXT_OPTIONS = {
15
+ event: 'done'
16
+ };
17
+ function autoNextOptionsAsPredicate(options = DEFAULT_AUTO_NEXT_OPTIONS) {
18
+ if (options === true) {
19
+ options = DEFAULT_AUTO_NEXT_OPTIONS;
20
+ }
21
+ if (typeof options === 'string') {
22
+ options = {
23
+ event: options
24
+ };
25
+ }
26
+ switch (typeof options) {
27
+ case 'object':
28
+ // TODO: support more options
29
+ return event => options.event === event._event;
30
+ case 'function':
31
+ return options;
32
+ default:
33
+ return false;
34
+ }
35
+ }
12
36
  class Asks extends _context.default {
13
37
  constructor(plugin, client) {
14
38
  super('asks', plugin, client);
15
39
  this._byQid = new Map();
16
40
  this._byPqid = new Map();
17
41
  this._root = new _ask.default(this); // initialize with default workflow
42
+ this._events.on('*', event => this._createNextIfNecessary(event));
18
43
  }
19
44
  get root() {
20
45
  return this._root;
@@ -67,5 +92,18 @@ class Asks extends _context.default {
67
92
  this._root.restart();
68
93
  }
69
94
  }
95
+ autoNext(options) {
96
+ this._autoNextFn = autoNextOptionsAsPredicate(options);
97
+ }
98
+ _createNextIfNecessary(event) {
99
+ if (!this._autoNextFn || !this._autoNextFn(event)) {
100
+ return;
101
+ }
102
+ const {
103
+ workflow
104
+ } = event;
105
+ workflow && workflow.getOrCreateNext();
106
+ }
70
107
  }
71
- exports.default = Asks;
108
+ exports.default = Asks;
109
+ (0, _index.makeConfigurable)(Asks.prototype, [_constants.WORKFLOW_CONFIGURABLE.TEMPLATES]);
@@ -9,6 +9,7 @@ var _index = require("./options/index.js");
9
9
  class WorkflowContext extends _commons.Component {
10
10
  constructor(name, plugin, client) {
11
11
  super(name, plugin);
12
+ this._name = name;
12
13
  this._plugin = plugin;
13
14
  this._client = client;
14
15
  this._options = new _index.WorkflowContextOptions();
@@ -5,17 +5,16 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _commons = require("@miso.ai/commons");
8
- var _index = require("../actor/index.js");
9
8
  var _base = _interopRequireDefault(require("./base.js"));
10
9
  var _searchBased = _interopRequireDefault(require("./search-based.js"));
11
10
  var _answerBased = _interopRequireDefault(require("./answer-based.js"));
12
11
  var _constants = require("../constants.js");
13
- var _index2 = require("../layout/index.js");
12
+ var _index = require("../layout/index.js");
14
13
  var _templates = require("../layout/templates.js");
15
14
  var _hybridSearchAnswer = _interopRequireDefault(require("./hybrid-search-answer.js"));
16
15
  var _hybridSearchResults = _interopRequireDefault(require("./hybrid-search-results.js"));
17
16
  var _hybridSearchViews = _interopRequireDefault(require("./hybrid-search-views.js"));
18
- var _index3 = require("./options/index.js");
17
+ var _index2 = require("./options/index.js");
19
18
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
20
19
  const DEFAULT_API_OPTIONS = Object.freeze({
21
20
  group: _commons.API.GROUP.ASK,
@@ -25,13 +24,13 @@ const DEFAULT_API_OPTIONS = Object.freeze({
25
24
  })
26
25
  });
27
26
  const DEFAULT_LAYOUTS = Object.freeze(Object.assign({}, _answerBased.default.DEFAULT_LAYOUTS, _searchBased.default.DEFAULT_LAYOUTS, {
28
- [_constants.ROLE.QUERY]: [_index2.SearchBoxLayout.type, {
27
+ [_constants.ROLE.QUERY]: [_index.SearchBoxLayout.type, {
29
28
  placeholder: ''
30
29
  }],
31
- [_constants.ROLE.QUESTION]: [_index2.TextLayout.type, {
30
+ [_constants.ROLE.QUESTION]: [_index.TextLayout.type, {
32
31
  raw: true
33
32
  }],
34
- [_constants.ROLE.SOURCES]: [_index2.HorizontalLayout.type, {
33
+ [_constants.ROLE.SOURCES]: [_index.HorizontalLayout.type, {
35
34
  incremental: true,
36
35
  itemType: 'article',
37
36
  templates: {
@@ -158,4 +157,4 @@ class HybridSearch extends _base.default {
158
157
  }
159
158
  }
160
159
  exports.default = HybridSearch;
161
- (0, _index3.makeConfigurable)(HybridSearch.prototype, [_constants.WORKFLOW_CONFIGURABLE.PAGINATION, _constants.WORKFLOW_CONFIGURABLE.FILTERS]);
160
+ (0, _index2.makeConfigurable)(HybridSearch.prototype, [_constants.WORKFLOW_CONFIGURABLE.PAGINATION, _constants.WORKFLOW_CONFIGURABLE.FILTERS]);
@@ -13,6 +13,7 @@ var _trackers = require("./trackers.js");
13
13
  var _interactions = require("./interactions.js");
14
14
  var _filters = require("./filters.js");
15
15
  var _pagination = require("./pagination.js");
16
+ var _templates = require("./templates.js");
16
17
  const FEATURES = [{
17
18
  key: _constants.WORKFLOW_CONFIGURABLE.API,
18
19
  normalize: _api.normalizeApiOptions,
@@ -41,6 +42,10 @@ const FEATURES = [{
41
42
  key: _constants.WORKFLOW_CONFIGURABLE.PAGINATION,
42
43
  normalize: _pagination.normalizePaginationOptions,
43
44
  merge: _pagination.mergePaginationOptions
45
+ }, {
46
+ key: _constants.WORKFLOW_CONFIGURABLE.TEMPLATES,
47
+ normalize: _templates.normalizeTemplatesOptions,
48
+ merge: _templates.mergeTemplatesOptions
44
49
  }];
45
50
  class WorkflowContextOptions {
46
51
  constructor() {
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.mergeTemplatesOptions = mergeTemplatesOptions;
7
+ exports.normalizeTemplatesOptions = normalizeTemplatesOptions;
8
+ var _utils = require("./utils.js");
9
+ function normalizeTemplatesOptions(options = {}) {
10
+ const normalize = {};
11
+ for (const [key, args] of Object.entries(options)) {
12
+ normalize[key] = normalizeTemplateOptions(args);
13
+ }
14
+ return normalize;
15
+ }
16
+ function normalizeTemplateOptions(args) {
17
+ // TODO: if object, make it function arguments
18
+ return args === undefined ? undefined : typeof args !== 'function' ? () => args : args;
19
+ }
20
+ function mergeTemplatesOptions(...optionsList) {
21
+ return (0, _utils.mergeOptions)(optionsList, (merged, options) => {
22
+ for (const [key, args] of Object.entries(options)) {
23
+ merged[key] = mergeTemplateOptions(merged[key], args);
24
+ }
25
+ return merged;
26
+ });
27
+ }
28
+ function mergeTemplateOptions(base, overrides) {
29
+ return normalizeTemplateOptions(overrides) || base;
30
+ }
@@ -327,7 +327,7 @@ function buildBaseInteraction(args) {
327
327
  }
328
328
  };
329
329
  if ((0, _constants.isPerformanceEventType)(type)) {
330
- if ((0, _constants.isProductRole)(role)) {
330
+ if (areProducts(role, items)) {
331
331
  payload.product_ids = (items || []).map(v => typeof v === 'string' ? v : v.product_id).filter(v => v);
332
332
  } else {
333
333
  payload.product_ids = [];
@@ -345,6 +345,9 @@ function buildBaseInteraction(args) {
345
345
  }
346
346
  return (0, _commons.trimObj)(payload);
347
347
  }
348
+ function areProducts(role, items = []) {
349
+ return (0, _constants.isProductRole)(role) || items.length > 0 && typeof items[0] === 'object' && items[0].product_id;
350
+ }
348
351
  function writeAffiliationInfoToInteraction(payload, args) {
349
352
  if (args.role !== _constants.ROLE.AFFILIATION) {
350
353
  return payload;
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.12.1"
29
+ "@miso.ai/commons": "1.12.2-beta.1"
30
30
  },
31
- "version": "1.12.1"
31
+ "version": "1.12.2-beta.1"
32
32
  }
@@ -1,4 +1,4 @@
1
- import { defineValues, delegateGetters, trimObj } from '@miso.ai/commons';
1
+ import { defineValues, delegateGetters } from '@miso.ai/commons';
2
2
  import { ROLE } from '../constants.js';
3
3
  import * as fields from './fields.js';
4
4
  import ViewActor from './view.js';
@@ -12,21 +12,18 @@ export function processData(data) {
12
12
  }
13
13
 
14
14
  function processValue(value) {
15
- /*
16
15
  if (value.affiliation_products) {
17
16
  const { affiliation_products, ...rest } = value;
18
17
  value = {
19
18
  ...rest,
20
19
  affiliation: processMisoData(affiliation_products),
21
20
  };
22
- } else
23
- */
24
- if (value.sovrn_aff) {
21
+ } else if (value.sovrn_aff) {
25
22
  const { sovrn_aff, ...rest } = value;
26
23
  value = {
27
24
  ...rest,
28
25
  affiliation: processSovrnData(sovrn_aff),
29
- }
26
+ };
30
27
  }
31
28
  return postProcessValue(value);
32
29
  }
package/src/constants.js CHANGED
@@ -130,4 +130,5 @@ export const WORKFLOW_CONFIGURABLE = Object.freeze({
130
130
  INTERACTIONS: 'interactions',
131
131
  FILTERS: 'filters',
132
132
  PAGINATION: 'pagination',
133
+ TEMPLATES: 'templates',
133
134
  });
@@ -1,31 +1,39 @@
1
1
  import { followUp as followUpTemplate } from './templates.js';
2
2
 
3
- export function wireFollowUps(client, element, { template = followUpTemplate, ...options } = {}) {
3
+ export function wireFollowUps(client, element, options) {
4
4
  if (!client) {
5
5
  throw new Error('client is required');
6
6
  }
7
+ // backward compatible
8
+ setFollowUpTemplate(client, options);
9
+ replaceFollowUpsElement(element);
10
+ }
11
+
12
+ function setFollowUpTemplate(client, { template = followUpTemplate, ...options } = {}) {
7
13
  if (typeof template !== 'function') {
8
14
  throw new Error('template must be a function or undefined');
9
15
  }
10
- if (!element) {
11
- return;
16
+ const hasExtraOptions = Object.keys(options).length > 0;
17
+ if (template === followUpTemplate && !hasExtraOptions) {
18
+ return; // same as default
12
19
  }
13
- const context = client.ui.asks;
14
- const rootWorkflow = client.ui.ask;
15
-
16
- // 1. when an answer is fully populated, insert a new section for the follow-up question
17
- context.on('done', (event) => {
18
- element.insertAdjacentHTML('beforeend', template({ ...options, parentQuestionId: event.workflow.questionId }));
19
- });
20
- // 2. if user starts over, clean up existing follow-up questions
21
- rootWorkflow.on('loading', () => {
22
- // clean up the entire follow-ups section
23
- element.innerHTML = '';
24
- // destroy all follow-up workflows
25
- context.reset({ root: false });
20
+ client.ui.asks.useTemplates({
21
+ followUp: hasExtraOptions ? (args) => template({ ...options, ...args }) : template,
26
22
  });
27
23
  }
28
24
 
25
+ function replaceFollowUpsElement(element) {
26
+ if (!element || element.tagName.toLowerCase() === 'miso-follow-ups') {
27
+ return;
28
+ }
29
+ // replace element with <miso-follow-ups>, carrying over attributes
30
+ const newElement = document.createElement('miso-follow-ups');
31
+ for (const { name, value } of element.attributes) {
32
+ newElement.setAttribute(name, value);
33
+ }
34
+ element.parentNode.replaceChild(newElement, element);
35
+ }
36
+
29
37
  export function wireRelatedResources(client, element) {
30
38
  if (!client) {
31
39
  throw new Error('client is required');
@@ -77,8 +77,8 @@ class Sections extends _Sections {
77
77
  }
78
78
 
79
79
  followUps(options) {
80
- const { classPrefix, features = {} } = options;
81
- return features.followUpQuestions === false ? '' : `<div id="${classPrefix}__follow-ups" class="${classPrefix}__follow-ups"></div>`;
80
+ const { features = {} } = options;
81
+ return features.followUpQuestions === false ? '' : `<miso-follow-ups id="miso-ask-combo__follow-ups" class="miso-ask-combo__follow-ups"></miso-follow-ups>`;
82
82
  }
83
83
 
84
84
  relatedResourcesSection(options) {
@@ -0,0 +1 @@
1
+ export { default as MisoFollowUpsElement } from './miso-follow-ups.js';
@@ -0,0 +1,53 @@
1
+ import MisoStubElement from '../util/miso-stub.js';
2
+ import { getClient } from '../utils.js';
3
+
4
+ export default class MisoContextElement extends MisoStubElement {
5
+
6
+ static get observedAttributes() {
7
+ return MisoStubElement.observedAttributes;
8
+ }
9
+
10
+ constructor() {
11
+ super();
12
+ this._context = undefined;
13
+ }
14
+
15
+ // properties //
16
+ get context() {
17
+ return this._context;
18
+ }
19
+
20
+ set context(context) {
21
+ this._setContext(context);
22
+ }
23
+
24
+ // lifecycle //
25
+ async connectedCallback() {
26
+ super.connectedCallback();
27
+ const client = this._client = await getClient(MisoContextElement);
28
+ if (document.body.contains(this)) { // in case already disconnected
29
+ this._setContext(this._getContext(client));
30
+ }
31
+ }
32
+
33
+ disconnectedCallback() {
34
+ this._setContext(undefined);
35
+ super.disconnectedCallback();
36
+ }
37
+
38
+ _getContext(client) {
39
+ throw new Error('Unimplemented');
40
+ }
41
+
42
+ _setContext(context) {
43
+ if (this._context === context) {
44
+ return;
45
+ }
46
+ const oldContext = this._context;
47
+ this._context = context;
48
+ this._onContext(context, oldContext);
49
+ }
50
+
51
+ _onContext() {}
52
+
53
+ }
@@ -0,0 +1,62 @@
1
+ import MisoContextElement from './miso-context.js';
2
+
3
+ const TAG_NAME = 'miso-follow-ups';
4
+
5
+ export default class MisoFollowUpsElement extends MisoContextElement {
6
+
7
+ static get tagName() {
8
+ return TAG_NAME;
9
+ }
10
+
11
+ static get observedAttributes() {
12
+ return MisoContextElement.observedAttributes;
13
+ }
14
+
15
+ constructor() {
16
+ super();
17
+ this._unsubscribes = [];
18
+ }
19
+
20
+ _getContext(client) {
21
+ return client.ui.asks;
22
+ }
23
+
24
+ _onContext(context, oldContext) {
25
+ if (context === oldContext) {
26
+ return;
27
+ }
28
+ this._unwire();
29
+ this._wire(context);
30
+ }
31
+
32
+ _unwire() {
33
+ for (const unsubscribe of this._unsubscribes || []) {
34
+ unsubscribe();
35
+ }
36
+ this._unsubscribes = [];
37
+ }
38
+
39
+ _wire(context) {
40
+ if (!context) {
41
+ return;
42
+ }
43
+
44
+ // 1. when an answer is fully populated, insert a new section for the follow-up question
45
+ this._unsubscribes.push(context.on('done', (event) => {
46
+ const template = event.workflow._options.resolved.templates.followUp;
47
+ if (!template) {
48
+ return;
49
+ }
50
+ this.insertAdjacentHTML('beforeend', template({ parentQuestionId: event.workflow.questionId }));
51
+ }));
52
+
53
+ // 2. if user starts over, clean up existing follow-up questions
54
+ this._unsubscribes.push(context.root.on('loading', () => {
55
+ // clean up the entire follow-ups section
56
+ this.innerHTML = '';
57
+ // destroy all follow-up workflows
58
+ context.reset({ root: false });
59
+ }));
60
+ }
61
+
62
+ }
@@ -1,7 +1,8 @@
1
1
  import * as containers from './container/index.js';
2
2
  import * as roles from './role/index.js';
3
+ import * as contexts from './context/index.js';
3
4
  import * as combos from './combo/index.js';
4
5
 
5
- export { containers, roles, combos };
6
+ export { containers, roles, contexts, combos };
6
7
 
7
8
  export * from './util/index.js';
@@ -221,11 +221,6 @@ export default class AffiliationLayout extends CollectionLayout {
221
221
  this.itemIndex--;
222
222
  }
223
223
 
224
- _getItems(state) {
225
- const { products } = state.value || {};
226
- return products;
227
- }
228
-
229
224
  _render(element, states, controls) {
230
225
  super._render(element, states, controls);
231
226
  // sync again for incremental item rendering
@@ -168,7 +168,7 @@ export default class CollectionLayout extends TemplateBasedLayout {
168
168
  }
169
169
 
170
170
  _getItems(state) {
171
- return state.value;
171
+ return state.value && (state.value.products || state.value);
172
172
  }
173
173
 
174
174
  _getListElement(element) {
package/src/plugin.js CHANGED
@@ -10,6 +10,7 @@ import * as traits from './trait/index.js';
10
10
  import { loadStylesIfNecessary } from './styles.js';
11
11
 
12
12
  import MisoContainerElement from './element/container/miso-container.js';
13
+ import MisoContextElement from './element/context/miso-context.js';
13
14
  import MisoComboElement from './element/combo/miso-combo.js';
14
15
 
15
16
  const PLUGIN_ID = 'std:ui';
@@ -52,15 +53,16 @@ export default class UiPlugin extends Component {
52
53
  }
53
54
 
54
55
  // custom elements
55
- const { containers, roles, combos, ...others } = elements;
56
+ const { containers, roles, combos, contexts, ...others } = elements;
56
57
  // containers must go first, so their APIs will be ready before children are defined
57
58
  const ElementClasses = [
58
59
  ...Object.values(combos),
60
+ ...Object.values(contexts),
59
61
  ...Object.values(containers),
60
62
  ...Object.values(roles),
61
63
  ...Object.values(others),
62
64
  ];
63
- const ElementSuperClasses = [MisoContainerElement, MisoComboElement];
65
+ const ElementSuperClasses = [MisoContainerElement, MisoContextElement, MisoComboElement];
64
66
  for (const ElementClass of [...ElementSuperClasses, ...ElementClasses]) {
65
67
  ElementClass.MisoClient = MisoClient; // TODO: find better way
66
68
  }
package/src/version.js CHANGED
@@ -1 +1 @@
1
- export default '1.12.1';
1
+ export default '1.12.2-beta.1';
@@ -6,6 +6,7 @@ import { OptionListLayout, ListLayout, SearchBoxLayout, TypewriterLayout } from
6
6
  import { mergeInteraction } from './processors.js';
7
7
  import { mergeRolesOptions, DEFAULT_TRACKER_OPTIONS } from './options/index.js';
8
8
  import { mappingSuggestionsData } from './processors.js';
9
+ import { followUp as followUpTemplate } from '../defaults/ask/templates.js';
9
10
 
10
11
  const DEFAULT_API_OPTIONS = Object.freeze({
11
12
  ...AnswerBasedWorkflow.DEFAULT_API_OPTIONS,
@@ -36,11 +37,16 @@ const DEFAULT_TRACKERS = Object.freeze({
36
37
  },
37
38
  });
38
39
 
40
+ const DEFAULT_TEMPLATES = Object.freeze({
41
+ followUp: followUpTemplate,
42
+ });
43
+
39
44
  const DEFAULT_OPTIONS = Object.freeze({
40
45
  ...AnswerBasedWorkflow.DEFAULT_OPTIONS,
41
46
  api: DEFAULT_API_OPTIONS,
42
47
  layouts: DEFAULT_LAYOUTS,
43
48
  trackers: DEFAULT_TRACKERS,
49
+ templates: DEFAULT_TEMPLATES,
44
50
  });
45
51
 
46
52
  const ROLES_OPTIONS = mergeRolesOptions(AnswerBasedWorkflow.ROLES_OPTIONS, {
@@ -1,5 +1,27 @@
1
+ import { WORKFLOW_CONFIGURABLE } from '../constants.js';
1
2
  import WorkflowContext from './context.js';
2
3
  import Ask from './ask.js';
4
+ import { makeConfigurable } from './options/index.js';
5
+
6
+ const DEFAULT_AUTO_NEXT_OPTIONS = { event: 'done' };
7
+
8
+ function autoNextOptionsAsPredicate(options = DEFAULT_AUTO_NEXT_OPTIONS) {
9
+ if (options === true) {
10
+ options = DEFAULT_AUTO_NEXT_OPTIONS;
11
+ }
12
+ if (typeof options === 'string') {
13
+ options = { event: options };
14
+ }
15
+ switch (typeof options) {
16
+ case 'object':
17
+ // TODO: support more options
18
+ return event => options.event === event._event;
19
+ case 'function':
20
+ return options;
21
+ default:
22
+ return false;
23
+ }
24
+ }
3
25
 
4
26
  export default class Asks extends WorkflowContext {
5
27
 
@@ -8,6 +30,7 @@ export default class Asks extends WorkflowContext {
8
30
  this._byQid = new Map();
9
31
  this._byPqid = new Map();
10
32
  this._root = new Ask(this); // initialize with default workflow
33
+ this._events.on('*', event => this._createNextIfNecessary(event));
11
34
  }
12
35
 
13
36
  get root() {
@@ -59,4 +82,18 @@ export default class Asks extends WorkflowContext {
59
82
  }
60
83
  }
61
84
 
85
+ autoNext(options) {
86
+ this._autoNextFn = autoNextOptionsAsPredicate(options);
87
+ }
88
+
89
+ _createNextIfNecessary(event) {
90
+ if (!this._autoNextFn || !this._autoNextFn(event)) {
91
+ return;
92
+ }
93
+ const { workflow } = event;
94
+ workflow && workflow.getOrCreateNext();
95
+ }
96
+
62
97
  }
98
+
99
+ makeConfigurable(Asks.prototype, [WORKFLOW_CONFIGURABLE.TEMPLATES]);
@@ -5,6 +5,7 @@ export default class WorkflowContext extends Component {
5
5
 
6
6
  constructor(name, plugin, client) {
7
7
  super(name, plugin);
8
+ this._name = name;
8
9
  this._plugin = plugin;
9
10
  this._client = client;
10
11
  this._options = new WorkflowContextOptions();
@@ -1,5 +1,4 @@
1
1
  import { API } from '@miso.ai/commons';
2
- import { InteractionsActor } from '../actor/index.js';
3
2
  import Workflow from './base.js';
4
3
  import SearchBasedWorkflow from './search-based.js';
5
4
  import AnswerBasedWorkflow from './answer-based.js';
@@ -7,6 +7,7 @@ import { normalizeTrackersOptions, mergeTrackersOptions } from './trackers.js';
7
7
  import { normalizeInteractionsOptions, mergeInteractionsOptions } from './interactions.js';
8
8
  import { normalizeFiltersOptions, mergeFiltersOptions } from './filters.js';
9
9
  import { normalizePaginationOptions, mergePaginationOptions } from './pagination.js';
10
+ import { normalizeTemplatesOptions, mergeTemplatesOptions } from './templates.js';
10
11
 
11
12
  const FEATURES = [
12
13
  {
@@ -44,6 +45,11 @@ const FEATURES = [
44
45
  normalize: normalizePaginationOptions,
45
46
  merge: mergePaginationOptions,
46
47
  },
48
+ {
49
+ key: WORKFLOW_CONFIGURABLE.TEMPLATES,
50
+ normalize: normalizeTemplatesOptions,
51
+ merge: mergeTemplatesOptions,
52
+ },
47
53
  ];
48
54
 
49
55
 
@@ -0,0 +1,27 @@
1
+ import { mergeOptions } from './utils.js';
2
+
3
+ export function normalizeTemplatesOptions(options = {}) {
4
+ const normalize = {};
5
+ for (const [key, args] of Object.entries(options)) {
6
+ normalize[key] = normalizeTemplateOptions(args);
7
+ }
8
+ return normalize;
9
+ }
10
+
11
+ function normalizeTemplateOptions(args) {
12
+ // TODO: if object, make it function arguments
13
+ return args === undefined ? undefined : typeof args !== 'function' ? () => args : args;
14
+ }
15
+
16
+ export function mergeTemplatesOptions(...optionsList) {
17
+ return mergeOptions(optionsList, (merged, options) => {
18
+ for (const [key, args] of Object.entries(options)) {
19
+ merged[key] = mergeTemplateOptions(merged[key], args);
20
+ }
21
+ return merged;
22
+ });
23
+ }
24
+
25
+ function mergeTemplateOptions(base, overrides) {
26
+ return normalizeTemplateOptions(overrides) || base;
27
+ }
@@ -245,7 +245,7 @@ export function buildBaseInteraction(args) {
245
245
  };
246
246
 
247
247
  if (isPerformanceEventType(type)) {
248
- if (isProductRole(role)) {
248
+ if (areProducts(role, items)) {
249
249
  payload.product_ids = (items || []).map(v => typeof v === 'string' ? v : v.product_id).filter(v => v);
250
250
  } else {
251
251
  payload.product_ids = [];
@@ -266,6 +266,10 @@ export function buildBaseInteraction(args) {
266
266
  return trimObj(payload);
267
267
  }
268
268
 
269
+ function areProducts(role, items = []) {
270
+ return isProductRole(role) || (items.length > 0 && typeof items[0] === 'object' && items[0].product_id);
271
+ }
272
+
269
273
  export function writeAffiliationInfoToInteraction(payload, args) {
270
274
  if (args.role !== ROLE.AFFILIATION) {
271
275
  return payload;