@miso.ai/client-sdk-core 1.13.0-beta.5 → 1.13.0-beta.6

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.
@@ -15,6 +15,7 @@ class AnalyticsPlugin extends _commons.Component {
15
15
  super('analytics');
16
16
  this._members = [];
17
17
  this._engagement = undefined;
18
+ this._activity = undefined;
18
19
  }
19
20
  config(options = {}) {
20
21
  this._options = options;
@@ -27,34 +28,94 @@ class AnalyticsPlugin extends _commons.Component {
27
28
  install(MisoClient, context) {
28
29
  context.addSubtree(this);
29
30
  this._engagement = new _commons.UserEngagementObserver(this._handleEngagement.bind(this));
31
+ this._activity = new _commons.UserActivityObserver(this._handleActivity.bind(this));
30
32
  // TODO: should we provide a way to stop the observer?
31
33
  window.addEventListener('beforeunload', this._handlePageExit.bind(this));
34
+ window.addEventListener('click', this._handleClick.bind(this, MisoClient));
32
35
  MisoClient.on('create', this._injectClient.bind(this));
33
36
  }
34
37
  _injectClient(client) {
35
38
  client.on('workflow', this._injectWorkflow.bind(this));
36
39
  }
37
40
  _injectWorkflow(workflow) {
38
- if (!this._shallInjectWorkflow(workflow)) {
41
+ if (!shallApplyAnalytics(workflow)) {
39
42
  return;
40
43
  }
41
44
  workflow.analytics = new Analytics(this, workflow);
42
45
  }
43
- _shallInjectWorkflow(workflow) {
44
- return workflow._name === 'ask' && !workflow.previous || workflow._name === 'hybrid-search';
45
- }
46
46
  _handleEngagement() {
47
47
  for (const member of this._members) {
48
48
  member._syncEngagementState();
49
49
  }
50
50
  }
51
+ _handleActivity(event) {
52
+ for (const member of this._members) {
53
+ member._sendHeartbeat();
54
+ }
55
+ }
51
56
  _handlePageExit() {
52
57
  for (const member of this._members) {
53
58
  member._sendHeartbeat();
54
59
  }
55
60
  }
61
+ _handleClick(MisoClient, event) {
62
+ // get the first client instance
63
+ const client = MisoClient.instances[0];
64
+ if (!client) {
65
+ return;
66
+ }
67
+ const workflow = getGenericClickWorkflow(this, event);
68
+ if (!workflow || !isDataReady(workflow)) {
69
+ return;
70
+ }
71
+ const href = getGenericClickHref(event);
72
+ if (!href) {
73
+ return;
74
+ }
75
+ workflow.trackers.container.genericClick({
76
+ href
77
+ });
78
+ }
56
79
  }
57
80
  exports.default = AnalyticsPlugin;
81
+ function shallApplyAnalytics(workflow) {
82
+ return workflow._name === 'ask' && !workflow.previous || workflow._name === 'hybrid-search';
83
+ }
84
+ function getGenericClickWorkflow(plugin, event) {
85
+ // find the closet container
86
+ for (let element = event.target; element; element = element.parentElement) {
87
+ const {
88
+ role,
89
+ workflow
90
+ } = element;
91
+ if (role && !workflow) {
92
+ return undefined; // inside component, not a generic click
93
+ }
94
+ // if inside a container, we should use the container's workflow
95
+ if (workflow) {
96
+ return shallApplyAnalytics(workflow) ? workflow : undefined;
97
+ }
98
+ }
99
+
100
+ // fallback to default workflow
101
+ for (const member of plugin._members) {
102
+ const workflow = member._workflow;
103
+ if (shallApplyAnalytics(workflow)) {
104
+ return workflow;
105
+ }
106
+ }
107
+ return undefined;
108
+ }
109
+ function getGenericClickHref(event) {
110
+ const element = event.target.closest('[href]');
111
+ return element ? element.getAttribute('href') : undefined;
112
+ }
113
+ function isDataReady(workflow) {
114
+ const {
115
+ data = {}
116
+ } = workflow.states;
117
+ return data.status === 'ready';
118
+ }
58
119
  function normalizeOptions(_ref = {}) {
59
120
  let options = Object.assign({}, (_objectDestructuringEmpty(_ref), _ref));
60
121
  return Object.assign({}, options);
@@ -169,5 +230,6 @@ class Analytics {
169
230
  } else {
170
231
  this._timer.stop();
171
232
  }
233
+ this._sendHeartbeat();
172
234
  }
173
235
  }
@@ -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.13.0-beta.5';
7
+ var _default = exports.default = '1.13.0-beta.6';
package/package.json CHANGED
@@ -30,7 +30,7 @@
30
30
  "url": "https://github.com/MisoAI/miso-client-js-sdk/issues"
31
31
  },
32
32
  "dependencies": {
33
- "@miso.ai/commons": "1.13.0-beta.5"
33
+ "@miso.ai/commons": "1.13.0-beta.6"
34
34
  },
35
- "version": "1.13.0-beta.5"
35
+ "version": "1.13.0-beta.6"
36
36
  }
@@ -1,4 +1,4 @@
1
- import { Component, UserEngagementObserver, Stopwatch, trimObj, mergeInteractions } from '@miso.ai/commons';
1
+ import { Component, UserEngagementObserver, UserActivityObserver, Stopwatch, trimObj, mergeInteractions } from '@miso.ai/commons';
2
2
 
3
3
  const PLUGIN_ID = 'std:analytics';
4
4
 
@@ -12,6 +12,7 @@ export default class AnalyticsPlugin extends Component {
12
12
  super('analytics');
13
13
  this._members = [];
14
14
  this._engagement = undefined;
15
+ this._activity = undefined;
15
16
  }
16
17
 
17
18
  config(options = {}) {
@@ -26,8 +27,10 @@ export default class AnalyticsPlugin extends Component {
26
27
  install(MisoClient, context) {
27
28
  context.addSubtree(this);
28
29
  this._engagement = new UserEngagementObserver(this._handleEngagement.bind(this));
30
+ this._activity = new UserActivityObserver(this._handleActivity.bind(this));
29
31
  // TODO: should we provide a way to stop the observer?
30
32
  window.addEventListener('beforeunload', this._handlePageExit.bind(this));
33
+ window.addEventListener('click', this._handleClick.bind(this, MisoClient));
31
34
  MisoClient.on('create', this._injectClient.bind(this));
32
35
  }
33
36
 
@@ -36,28 +39,85 @@ export default class AnalyticsPlugin extends Component {
36
39
  }
37
40
 
38
41
  _injectWorkflow(workflow) {
39
- if (!this._shallInjectWorkflow(workflow)) {
42
+ if (!shallApplyAnalytics(workflow)) {
40
43
  return;
41
44
  }
42
45
  workflow.analytics = new Analytics(this, workflow);
43
46
  }
44
47
 
45
- _shallInjectWorkflow(workflow) {
46
- return (workflow._name === 'ask' && !workflow.previous) || workflow._name === 'hybrid-search';
47
- }
48
-
49
48
  _handleEngagement() {
50
49
  for (const member of this._members) {
51
50
  member._syncEngagementState();
52
51
  }
53
52
  }
54
53
 
54
+ _handleActivity(event) {
55
+ for (const member of this._members) {
56
+ member._sendHeartbeat();
57
+ }
58
+ }
59
+
55
60
  _handlePageExit() {
56
61
  for (const member of this._members) {
57
62
  member._sendHeartbeat();
58
63
  }
59
64
  }
60
65
 
66
+ _handleClick(MisoClient, event) {
67
+ // get the first client instance
68
+ const client = MisoClient.instances[0];
69
+ if (!client) {
70
+ return;
71
+ }
72
+ const workflow = getGenericClickWorkflow(this, event);
73
+ if (!workflow || !isDataReady(workflow)) {
74
+ return;
75
+ }
76
+ const href = getGenericClickHref(event);
77
+ if (!href) {
78
+ return;
79
+ }
80
+ workflow.trackers.container.genericClick({ href });
81
+ }
82
+
83
+ }
84
+
85
+ function shallApplyAnalytics(workflow) {
86
+ return (workflow._name === 'ask' && !workflow.previous) || workflow._name === 'hybrid-search';
87
+ }
88
+
89
+ function getGenericClickWorkflow(plugin, event) {
90
+ // find the closet container
91
+ for (let element = event.target; element; element = element.parentElement) {
92
+ const { role, workflow } = element;
93
+ if (role && !workflow) {
94
+ return undefined; // inside component, not a generic click
95
+ }
96
+ // if inside a container, we should use the container's workflow
97
+ if (workflow) {
98
+ return shallApplyAnalytics(workflow) ? workflow : undefined;
99
+ }
100
+ }
101
+
102
+ // fallback to default workflow
103
+ for (const member of plugin._members) {
104
+ const workflow = member._workflow;
105
+ if (shallApplyAnalytics(workflow)) {
106
+ return workflow;
107
+ }
108
+ }
109
+
110
+ return undefined;
111
+ }
112
+
113
+ function getGenericClickHref(event) {
114
+ const element = event.target.closest('[href]');
115
+ return element ? element.getAttribute('href') : undefined;
116
+ }
117
+
118
+ function isDataReady(workflow) {
119
+ const { data = {} } = workflow.states;
120
+ return data.status === 'ready';
61
121
  }
62
122
 
63
123
  function normalizeOptions({ ...options } = {}) {
@@ -194,6 +254,8 @@ class Analytics {
194
254
  } else {
195
255
  this._timer.stop();
196
256
  }
257
+
258
+ this._sendHeartbeat();
197
259
  }
198
260
 
199
261
  }
package/src/version.js CHANGED
@@ -1 +1 @@
1
- export default '1.13.0-beta.5';
1
+ export default '1.13.0-beta.6';