@miso.ai/client-sdk-ui 1.10.3 → 1.11.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/dist/cjs/actor/autocomplete.js +4 -1
  2. package/dist/cjs/actor/data.js +15 -6
  3. package/dist/cjs/actor/fields.js +10 -10
  4. package/dist/cjs/actor/filters.js +114 -0
  5. package/dist/cjs/actor/hub.js +2 -1
  6. package/dist/cjs/actor/sessions.js +3 -5
  7. package/dist/cjs/actor/view.js +19 -6
  8. package/dist/cjs/actor/views.js +32 -19
  9. package/dist/cjs/constants.js +9 -2
  10. package/dist/cjs/defaults/ask/constants.js +3 -2
  11. package/dist/cjs/defaults/ask/templates.js +112 -219
  12. package/dist/cjs/defaults/common/templates.js +234 -0
  13. package/dist/cjs/defaults/hybrid-search/answer-box.js +115 -0
  14. package/dist/cjs/defaults/hybrid-search/constants.js +8 -0
  15. package/dist/cjs/defaults/hybrid-search/controls.js +17 -0
  16. package/dist/cjs/defaults/hybrid-search/index.js +31 -0
  17. package/dist/cjs/defaults/hybrid-search/phrases.js +27 -0
  18. package/dist/cjs/defaults/hybrid-search/templates.js +127 -0
  19. package/dist/cjs/defaults/index.js +4 -2
  20. package/dist/cjs/element/container/index.js +7 -0
  21. package/dist/cjs/element/container/miso-hybrid-search.js +21 -0
  22. package/dist/cjs/element/role/index.js +21 -0
  23. package/dist/cjs/element/role/miso-facets.js +20 -0
  24. package/dist/cjs/element/role/miso-hits.js +20 -0
  25. package/dist/cjs/element/role/miso-keywords.js +20 -0
  26. package/dist/cjs/layout/index.js +7 -0
  27. package/dist/cjs/layout/input/facets.js +294 -0
  28. package/dist/cjs/layout/input/option-list.js +4 -4
  29. package/dist/cjs/layout/input/search-box.js +6 -8
  30. package/dist/cjs/layout/list/collection.js +1 -2
  31. package/dist/cjs/layout/radio/radio.js +1 -1
  32. package/dist/cjs/layout/raf.js +1 -0
  33. package/dist/cjs/layout/template.js +3 -1
  34. package/dist/cjs/layout/templates.js +15 -0
  35. package/dist/cjs/layout/text/text.js +38 -5
  36. package/dist/cjs/layout/trackable.js +2 -16
  37. package/dist/cjs/plugin.js +4 -1
  38. package/dist/cjs/{source/index.js → source.js} +7 -4
  39. package/dist/cjs/util/bindings.js +3 -0
  40. package/dist/cjs/version.js +1 -1
  41. package/dist/cjs/workflow/answer-based.js +335 -0
  42. package/dist/cjs/workflow/ask.js +98 -271
  43. package/dist/cjs/workflow/base.js +69 -35
  44. package/dist/cjs/workflow/explore.js +10 -0
  45. package/dist/cjs/workflow/hybrid-search.js +140 -0
  46. package/dist/cjs/workflow/index.js +7 -0
  47. package/dist/cjs/workflow/processors.js +113 -0
  48. package/dist/cjs/workflow/recommendation.js +12 -3
  49. package/dist/cjs/workflow/search.js +34 -12
  50. package/package.json +2 -2
  51. package/src/actor/autocomplete.js +4 -2
  52. package/src/actor/data.js +8 -2
  53. package/src/actor/fields.js +10 -10
  54. package/src/actor/filters.js +103 -0
  55. package/src/actor/hub.js +2 -1
  56. package/src/actor/sessions.js +3 -4
  57. package/src/actor/view.js +19 -2
  58. package/src/actor/views.js +30 -16
  59. package/src/constants.js +10 -0
  60. package/src/defaults/ask/constants.js +1 -0
  61. package/src/defaults/ask/templates.js +70 -179
  62. package/src/defaults/common/templates.js +173 -0
  63. package/src/defaults/hybrid-search/answer-box.js +118 -0
  64. package/src/defaults/hybrid-search/constants.js +2 -0
  65. package/src/defaults/hybrid-search/controls.js +11 -0
  66. package/src/defaults/hybrid-search/index.js +9 -0
  67. package/src/defaults/hybrid-search/phrases.js +22 -0
  68. package/src/defaults/hybrid-search/templates.js +83 -0
  69. package/src/defaults/index.js +2 -0
  70. package/src/element/container/index.js +1 -0
  71. package/src/element/container/miso-hybrid-search.js +19 -0
  72. package/src/element/role/index.js +3 -0
  73. package/src/element/role/miso-facets.js +16 -0
  74. package/src/element/role/miso-hits.js +16 -0
  75. package/src/element/role/miso-keywords.js +16 -0
  76. package/src/layout/index.js +1 -0
  77. package/src/layout/input/facets.js +242 -0
  78. package/src/layout/input/option-list.js +3 -4
  79. package/src/layout/input/search-box.js +6 -7
  80. package/src/layout/list/collection.js +1 -2
  81. package/src/layout/radio/radio.js +1 -1
  82. package/src/layout/raf.js +1 -0
  83. package/src/layout/template.js +2 -1
  84. package/src/layout/templates.js +15 -0
  85. package/src/layout/text/text.js +28 -3
  86. package/src/layout/trackable.js +2 -15
  87. package/src/plugin.js +6 -2
  88. package/src/{source/index.js → source.js} +7 -4
  89. package/src/util/bindings.js +4 -0
  90. package/src/version.js +1 -1
  91. package/src/workflow/answer-based.js +280 -0
  92. package/src/workflow/ask.js +82 -204
  93. package/src/workflow/base.js +64 -27
  94. package/src/workflow/explore.js +10 -1
  95. package/src/workflow/hybrid-search.js +125 -0
  96. package/src/workflow/index.js +1 -0
  97. package/src/workflow/processors.js +95 -0
  98. package/src/workflow/recommendation.js +9 -2
  99. package/src/workflow/search.js +35 -7
  100. package/dist/cjs/source/api.js +0 -23
  101. package/src/source/api.js +0 -12
@@ -0,0 +1,125 @@
1
+ import { trimObj, API } from '@miso.ai/commons';
2
+ import AnswerBasedWorkflow from './answer-based.js';
3
+ import { mergeApiOptions } from './options.js';
4
+ import { fields } from '../actor/index.js';
5
+ import { ROLE, ORGANIC_QUESTION_SOURCE } from '../constants.js';
6
+ import { ListLayout, TextLayout, FacetsLayout } from '../layout/index.js';
7
+ import { writeKeywordsToData, addDataInstructions } from './processors.js';
8
+
9
+ const DEFAULT_API_OPTIONS = Object.freeze({
10
+ ...AnswerBasedWorkflow.DEFAULT_API_OPTIONS,
11
+ name: API.NAME.SEARCH,
12
+ payload: {
13
+ ...AnswerBasedWorkflow.DEFAULT_API_OPTIONS.payload,
14
+ },
15
+ });
16
+
17
+ const DEFAULT_LAYOUTS = Object.freeze({
18
+ ...AnswerBasedWorkflow.DEFAULT_LAYOUTS,
19
+ [ROLE.PRODUCTS]: [ListLayout.type, { itemType: 'article' }],
20
+ [ROLE.KEYWORDS]: [TextLayout.type, { raw: true }],
21
+ [ROLE.HITS]: [TextLayout.type, { raw: true, format: 'number' }],
22
+ [ROLE.FACETS]: [FacetsLayout.type],
23
+ });
24
+
25
+ const DEFAULT_TRACKERS = Object.freeze({
26
+ ...AnswerBasedWorkflow.DEFAULT_TRACKERS,
27
+ });
28
+
29
+ const DEFAULT_OPTIONS = Object.freeze({
30
+ ...AnswerBasedWorkflow.DEFAULT_OPTIONS,
31
+ api: DEFAULT_API_OPTIONS,
32
+ layouts: DEFAULT_LAYOUTS,
33
+ trackers: DEFAULT_TRACKERS,
34
+ });
35
+
36
+ const ROLES_CONFIG = Object.freeze({
37
+ [ROLE.QUESTION]: {
38
+ mapping: ROLE.KEYWORDS,
39
+ },
40
+ [ROLE.FACETS]: {
41
+ mapping: 'facet_counts',
42
+ },
43
+ });
44
+
45
+ export default class HybridSearch extends AnswerBasedWorkflow {
46
+
47
+ constructor(plugin, client) {
48
+ super({
49
+ name: 'hybrid-search',
50
+ plugin,
51
+ client,
52
+ roles: Object.keys(DEFAULT_LAYOUTS),
53
+ rolesConfig: ROLES_CONFIG,
54
+ defaults: DEFAULT_OPTIONS,
55
+ });
56
+ }
57
+
58
+ _initSubscriptions(args) {
59
+ super._initSubscriptions(args);
60
+ this._unsubscribes = [
61
+ ...this._unsubscribes,
62
+ this._hub.on(fields.filters(), filters => this._refine(filters)),
63
+ ];
64
+ }
65
+
66
+ // query //
67
+ _buildPayload({ q, qs, filters, ...payload } = {}) {
68
+ const fq = this._buildFq(filters); // TODO: combine with fq in payload?
69
+ return trimObj({
70
+ ...payload,
71
+ q, // q, not question
72
+ fq,
73
+ _meta: {
74
+ ...payload._meta,
75
+ question_source: qs || ORGANIC_QUESTION_SOURCE, // might be null, not undefined
76
+ },
77
+ });
78
+ }
79
+
80
+ _buildFq(filters) {
81
+ if (!filters) {
82
+ return undefined;
83
+ }
84
+ const clauses = [];
85
+ const { facets } = filters;
86
+ for (const field in facets) {
87
+ const values = facets[field];
88
+ if (!values || !values.length) {
89
+ continue; // just in case
90
+ }
91
+ clauses.push(`${field}:(${values.map(v => `"${v}"`).join(' OR ')})`);
92
+ }
93
+ return clauses.map(c => `(${c})`).join(' AND ');
94
+ }
95
+
96
+ _refine(filters) {
97
+ const query = this._hub.states[fields.query()];
98
+ const payload = this._buildPayload({ ...query, filters, answer: false });
99
+ const { session } = this;
100
+
101
+ const event = mergeApiOptions(this._options.resolved.api, { payload, session, _skipLoading: true });
102
+ this._request(event);
103
+
104
+ // emulate loading status exclusively for products
105
+ // TODO
106
+ }
107
+
108
+ // data //
109
+ _defaultProcessData(data) {
110
+ data = super._defaultProcessData(data);
111
+ data = writeKeywordsToData(data);
112
+ data = instructPartialUpdates(data);
113
+ return data;
114
+ }
115
+
116
+ }
117
+
118
+ function instructPartialUpdates(data) {
119
+ if (!data.value) {
120
+ return data;
121
+ }
122
+ return addDataInstructions(data, data.value.products ?
123
+ { includes: [ ROLE.PRODUCTS, ROLE.HITS, ROLE.FACETS, ROLE.KEYWORDS, ROLE.QUESTION ], merge: true } :
124
+ { excludes: [ ROLE.PRODUCTS, ROLE.HITS, ROLE.FACETS ], merge: true });
125
+ }
@@ -1,4 +1,5 @@
1
1
  export { default as Asks } from './asks.js';
2
+ export { default as HybridSearch } from './hybrid-search.js';
2
3
  export { default as Explore } from './explore.js';
3
4
  export { default as Search } from './search.js';
4
5
  export { default as Recommendations } from './recommendations.js';
@@ -0,0 +1,95 @@
1
+ import { trimObj } from '@miso.ai/commons';
2
+ import { STATUS } from '../constants.js';
3
+
4
+ export function writeDataStatus(data) {
5
+ const status = getStatus(data);
6
+ const ongoing = status === STATUS.READY ? !!data.ongoing : undefined;
7
+ return trimObj({ ...data, status, ongoing });
8
+ }
9
+
10
+ function getStatus(data) {
11
+ if (!data) {
12
+ return STATUS.INITIAL;
13
+ }
14
+ const { request, error, value } = data;
15
+ return error ? STATUS.ERRONEOUS : value ? STATUS.READY : request ? STATUS.LOADING : STATUS.INITIAL;
16
+ }
17
+
18
+ export function writeMisoIdToMeta(data) {
19
+ const { value } = data;
20
+ if (!value) {
21
+ return data;
22
+ }
23
+ const { miso_id } = value;
24
+ if (!miso_id) {
25
+ return data;
26
+ }
27
+ return {
28
+ ...data,
29
+ meta: {
30
+ ...data.meta,
31
+ miso_id,
32
+ },
33
+ };
34
+ }
35
+
36
+ export function writeKeywordsToData(data) {
37
+ const { request, value } = data;
38
+ if (!request || !value) {
39
+ return data;
40
+ }
41
+ const { payload } = request || {};
42
+ const { q: keywords } = payload || {};
43
+ if (!keywords) {
44
+ return data;
45
+ }
46
+ return {
47
+ ...data,
48
+ value: {
49
+ ...value,
50
+ keywords,
51
+ },
52
+ };
53
+ }
54
+
55
+ export function writeAnswerStageToMeta(data) {
56
+ const { value } = data;
57
+ if (!value) {
58
+ return data;
59
+ }
60
+ const { answer_stage } = value;
61
+ if (!answer_stage) {
62
+ return data;
63
+ }
64
+ // 1. put answer_stage to meta
65
+ // 2. mark ongoing flag
66
+ return {
67
+ ...data,
68
+ ongoing: !value.finished,
69
+ meta: {
70
+ ...data.meta,
71
+ answer_stage,
72
+ },
73
+ };
74
+ }
75
+
76
+ export function addDataInstructions(data, instructions) {
77
+ if (!instructions) {
78
+ return data;
79
+ }
80
+ return {
81
+ _inst: {
82
+ ...data._inst,
83
+ ...instructions,
84
+ },
85
+ ...data,
86
+ };
87
+ }
88
+
89
+ export function removeDataInstructions(data) {
90
+ if (typeof data !== 'object') {
91
+ return data;
92
+ }
93
+ const { _inst, ...rest } = data;
94
+ return rest;
95
+ }
@@ -35,12 +35,19 @@ export default class Recommendation extends Workflow {
35
35
  context,
36
36
  roles: Object.keys(DEFAULT_LAYOUTS),
37
37
  defaults: DEFAULT_OPTIONS,
38
+ id,
38
39
  });
40
+ }
39
41
 
42
+ _initProperties(args) {
43
+ super._initProperties(args);
44
+ const { id } = args;
40
45
  defineValues(this, { id });
41
- this._context = context;
46
+ }
42
47
 
43
- context._members.set(id, this);
48
+ _initReset(args) {
49
+ this._context._members.set(args.id, this);
50
+ super._initReset(args);
44
51
  }
45
52
 
46
53
  // lifecycle //
@@ -1,9 +1,9 @@
1
1
  import { API } from '@miso.ai/commons';
2
2
  import Workflow from './base.js';
3
3
  import { mergeApiOptions } from './options.js';
4
- import * as sources from '../source/index.js';
4
+ import * as sources from '../source.js';
5
5
  import { fields, AutocompleteActor } from '../actor/index.js';
6
- import { ROLE } from '../constants.js';
6
+ import { ROLE, DATA_ASPECT } from '../constants.js';
7
7
  import { ListLayout, SearchBoxLayout } from '../layout/index.js';
8
8
  import { makeConfigurable } from './options.js';
9
9
 
@@ -54,13 +54,22 @@ export default class Search extends Workflow {
54
54
  roles: Object.keys(DEFAULT_LAYOUTS),
55
55
  defaults: DEFAULT_OPTIONS,
56
56
  });
57
+ }
57
58
 
59
+ _initActors(args) {
60
+ super._initActors(args);
58
61
  this._autocomplete = new AutocompleteActor(this._hub, {
59
62
  source: sources.api(this._client),
60
63
  options: this._options,
61
64
  });
65
+ }
62
66
 
63
- this._unsubscribes.push(this._hub.on(fields.query(), payload => this.query(payload)));
67
+ _initSubscriptions(args) {
68
+ super._initSubscriptions(args);
69
+ this._unsubscribes = [
70
+ ...this._unsubscribes,
71
+ this._hub.on(fields.query(), args => this._query(args)),
72
+ ];
64
73
  }
65
74
 
66
75
  // lifecycle //
@@ -80,16 +89,35 @@ export default class Search extends Workflow {
80
89
  }
81
90
  }
82
91
 
83
- query(payload) {
92
+ query(args) {
93
+ if (!args.q) {
94
+ throw new Error(`q is required in query() call`);
95
+ }
96
+ this._hub.update(fields.query(), args);
97
+ }
98
+
99
+ _query(args) {
100
+ // start a new session
84
101
  this.restart();
85
102
  const { session } = this;
86
- this._hub.update(fields.request(), mergeApiOptions(this._options.resolved.api, { payload, session }));
87
- return this;
103
+
104
+ // build payload and trigger request
105
+ const payload = this._buildPayload(args);
106
+ const event = mergeApiOptions(this._options.resolved.api, { payload, session });
107
+ this._request(event);
108
+ }
109
+
110
+ _buildPayload(args) {
111
+ return args;
112
+ }
113
+
114
+ _request(event) {
115
+ this._hub.update(fields.request(), event);
88
116
  }
89
117
 
90
118
  updateCompletions(event) {
91
119
  // TODO: verify
92
- this._hub.update(fields.completions(), {
120
+ this._hub.update(fields.data(DATA_ASPECT.AUTOCOMPLETE), {
93
121
  ...event,
94
122
  source: 'manual',
95
123
  });
@@ -1,23 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = _default;
7
- var _commons = require("@miso.ai/commons");
8
- function _default(client) {
9
- // TODO: send uuid & unit id
10
- return async _ref => {
11
- let {
12
- group,
13
- name,
14
- payload,
15
- options
16
- } = _ref;
17
- if (group === _commons.API.GROUP.ASK && name === _commons.API.NAME.QUESTIONS) {
18
- return client.api.ask.questions(payload, options);
19
- }
20
- // because name is in snake case
21
- return client.api[group]._run(name, payload, options);
22
- };
23
- }
package/src/source/api.js DELETED
@@ -1,12 +0,0 @@
1
- import { API } from '@miso.ai/commons';
2
-
3
- export default function(client) {
4
- // TODO: send uuid & unit id
5
- return async ({ group, name, payload, options }) => {
6
- if (group === API.GROUP.ASK && name === API.NAME.QUESTIONS) {
7
- return client.api.ask.questions(payload, options);
8
- }
9
- // because name is in snake case
10
- return client.api[group]._run(name, payload, options);
11
- };
12
- }