@atlassian/atlassian-connect-js 5.3.190
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/.depcheckrc.json +16 -0
- package/.editorconfig +9 -0
- package/.envrc +5 -0
- package/.eslintignore +12 -0
- package/.eslintrc +31 -0
- package/.husky/pre-commit +11 -0
- package/.lintstagedrc.js +6 -0
- package/.netrc +1 -0
- package/.npmrc-public +4 -0
- package/.nvmrc +1 -0
- package/LICENSE +3 -0
- package/README.md +281 -0
- package/bitbucket-pipelines.yml +33 -0
- package/build/bin/bin-helper.js +29 -0
- package/build/bin/npm-postinstall.js +9 -0
- package/build/configs/append-sourcemapping.js +13 -0
- package/build/configs/availabletasks.js +15 -0
- package/build/configs/clean.js +12 -0
- package/build/configs/concat.js +44 -0
- package/build/configs/copy.js +32 -0
- package/build/configs/index.js +19 -0
- package/build/configs/jshint.js +9 -0
- package/build/configs/karma.js +11 -0
- package/build/configs/replace.js +10 -0
- package/build/configs/requirejs.js +187 -0
- package/build/configs/saucelabs-launchers.js +30 -0
- package/build/configs/shell.js +24 -0
- package/build/configs/uglify.js +15 -0
- package/build/configs/watch.js +45 -0
- package/build/end.frag +13 -0
- package/build/start.frag +18 -0
- package/bundlesize.config.json +14 -0
- package/dist/connect-host.css +225 -0
- package/dist/connect-host.js +13908 -0
- package/dist/connect-host.min.css +1 -0
- package/dist/iframe-fedramp.js +13663 -0
- package/dist/iframe.js +13663 -0
- package/dist/legacy-text-colors.css +245 -0
- package/dist/surfaces.css +11 -0
- package/dist/themes/atlaskit-tokens_dark-future.css +6 -0
- package/dist/themes/atlaskit-tokens_dark.css +394 -0
- package/dist/themes/atlaskit-tokens_legacy-dark.css +394 -0
- package/dist/themes/atlaskit-tokens_legacy-light.css +394 -0
- package/dist/themes/atlaskit-tokens_light-future.css +6 -0
- package/dist/themes/atlaskit-tokens_light.css +394 -0
- package/dist/themes/atlaskit-tokens_shape.css +14 -0
- package/dist/themes/atlaskit-tokens_spacing.css +26 -0
- package/dist/themes/atlaskit-tokens_typography-adg3.css +25 -0
- package/dist/themes/atlaskit-tokens_typography-modernized.css +25 -0
- package/dist/themes/atlaskit-tokens_typography-refreshed.css +25 -0
- package/gulpfile.js +204 -0
- package/memleak-check/app.html +10 -0
- package/memleak-check/index.html +31 -0
- package/memleak-check/index.js +33 -0
- package/package.json +102 -0
- package/renovate.json +11 -0
- package/security-assistant.yml +2 -0
- package/spec/.eslintrc +10 -0
- package/spec/config/karma.base.conf.js +200 -0
- package/spec/config/karma.conf.js +20 -0
- package/spec/fixtures/base_dialog_component_tests.js +180 -0
- package/spec/mocks/mock_feature_flag.js +23 -0
- package/spec/tests/amd_spec.js +122 -0
- package/spec/tests/analytics_dispatcher_spec.js +429 -0
- package/spec/tests/analytics_performance_spec.js +41 -0
- package/spec/tests/button_spec.js +143 -0
- package/spec/tests/dialog_extension_spec.js +59 -0
- package/spec/tests/dialog_module_provider_spec.js +499 -0
- package/spec/tests/dialog_module_spec.js +395 -0
- package/spec/tests/dialog_spec.js +296 -0
- package/spec/tests/dialog_webitem_spec.js +183 -0
- package/spec/tests/dropdown_module_spec.js +77 -0
- package/spec/tests/env_module_spec.js +153 -0
- package/spec/tests/events_spec.js +77 -0
- package/spec/tests/extension_configuration_options_store_spec.js +25 -0
- package/spec/tests/flag_module_provider_spec.js +79 -0
- package/spec/tests/flag_module_spec.js +118 -0
- package/spec/tests/flag_spec.js +243 -0
- package/spec/tests/host-api_spec.js +220 -0
- package/spec/tests/iframe-create_spec.js +43 -0
- package/spec/tests/iframe_container_spec.js +19 -0
- package/spec/tests/iframe_spec.js +265 -0
- package/spec/tests/inline_dialog_spec.js +41 -0
- package/spec/tests/inline_dialog_webitem_spec.js +331 -0
- package/spec/tests/loading_indicator_spec.js +48 -0
- package/spec/tests/messages_module_spec.js +108 -0
- package/spec/tests/meta_spec.js +71 -0
- package/spec/tests/module_args_spec.js +52 -0
- package/spec/tests/observe_spec.js +73 -0
- package/spec/tests/public_events.spec.js +102 -0
- package/spec/tests/scroll_position_spec.js +109 -0
- package/spec/tests/theming_spec.js +594 -0
- package/spec/tests/util_spec.js +55 -0
- package/spec/tests/utils/base64_spec.js +20 -0
- package/spec/tests/utils/button_spec.js +11 -0
- package/spec/tests/utils/cookie_spec.js +19 -0
- package/spec/tests/utils/deprecate_spec.js +22 -0
- package/spec/tests/utils/dialog_spec.js +297 -0
- package/spec/tests/utils/host_util_spec.js +45 -0
- package/spec/tests/utils/iframe_spec.js +41 -0
- package/spec/tests/utils/jwt_spec.js +135 -0
- package/spec/tests/utils/url_spec.js +37 -0
- package/spec/tests/utils/waitUntilReadyNextTick.js +5 -0
- package/spec/tests/utils/webitem.js +219 -0
- package/spec/tests/webitem_spec.js +131 -0
- package/src/css/host/dialog.css +144 -0
- package/src/css/host/flags.css +5 -0
- package/src/css/host/host.css +64 -0
- package/src/css/host/messages.css +12 -0
- package/src/css/plugin/legacy-text-colors.less +55 -0
- package/src/css/plugin/surfaces.css +11 -0
- package/src/host/ACJSFrameworkAdaptor.js +44 -0
- package/src/host/actions/analytics_action.js +35 -0
- package/src/host/actions/button_actions.js +21 -0
- package/src/host/actions/dialog_actions.js +27 -0
- package/src/host/actions/dialog_extension_actions.js +25 -0
- package/src/host/actions/dom_event_actions.js +32 -0
- package/src/host/actions/dropdown_actions.js +12 -0
- package/src/host/actions/env_actions.js +57 -0
- package/src/host/actions/event_actions.js +33 -0
- package/src/host/actions/flag_actions.js +22 -0
- package/src/host/actions/iframe_actions.js +27 -0
- package/src/host/actions/inline_dialog_actions.js +26 -0
- package/src/host/actions/inline_dialog_webitem_actions.js +10 -0
- package/src/host/actions/jwt_actions.js +51 -0
- package/src/host/actions/loading_indicator_actions.js +10 -0
- package/src/host/actions/module_actions.js +14 -0
- package/src/host/actions/webitem_actions.js +29 -0
- package/src/host/components/button.js +112 -0
- package/src/host/components/dialog.js +447 -0
- package/src/host/components/dialog_extension.js +106 -0
- package/src/host/components/dialog_webitem.js +69 -0
- package/src/host/components/flag.js +102 -0
- package/src/host/components/iframe.js +130 -0
- package/src/host/components/iframe_container.js +38 -0
- package/src/host/components/inline_dialog.js +108 -0
- package/src/host/components/inline_dialog_webitem.js +157 -0
- package/src/host/components/loading_indicator.js +110 -0
- package/src/host/components/webitem.js +227 -0
- package/src/host/deprecate.js +20 -0
- package/src/host/dispatchers/analytics_dispatcher.js +512 -0
- package/src/host/dispatchers/event_dispatcher.js +46 -0
- package/src/host/dollar.js +8 -0
- package/src/host/host-api.js +325 -0
- package/src/host/iframe-create.js +7 -0
- package/src/host/index.js +108 -0
- package/src/host/module-providers.js +13 -0
- package/src/host/modules/_featureFlag.js +42 -0
- package/src/host/modules/_performance.js +54 -0
- package/src/host/modules/analytics.js +17 -0
- package/src/host/modules/dialog.js +496 -0
- package/src/host/modules/dropdown.js +255 -0
- package/src/host/modules/env.js +156 -0
- package/src/host/modules/events.js +28 -0
- package/src/host/modules/flag.js +170 -0
- package/src/host/modules/host.js +19 -0
- package/src/host/modules/inline-dialog.js +33 -0
- package/src/host/modules/messages.js +309 -0
- package/src/host/modules/page.js +29 -0
- package/src/host/modules/scroll-position.js +102 -0
- package/src/host/modules/theming.js +114 -0
- package/src/host/stores/extension_configuration_options_store.js +24 -0
- package/src/host/util.js +98 -0
- package/src/host/utils/access-narrowing-context.js +18 -0
- package/src/host/utils/base64.js +22 -0
- package/src/host/utils/button.js +10 -0
- package/src/host/utils/cookie.js +14 -0
- package/src/host/utils/dialog.js +239 -0
- package/src/host/utils/feature-flag.js +27 -0
- package/src/host/utils/iframe.js +23 -0
- package/src/host/utils/jwt.js +60 -0
- package/src/host/utils/observe.js +34 -0
- package/src/host/utils/removal-observer.js +30 -0
- package/src/host/utils/simplexdm.js +58 -0
- package/src/host/utils/url.js +23 -0
- package/src/host/utils/webitem.js +214 -0
- package/src/plugin/amd.js +115 -0
- package/src/plugin/analytics.js +84 -0
- package/src/plugin/deprecate.js +16 -0
- package/src/plugin/dialog.js +197 -0
- package/src/plugin/dollar.js +77 -0
- package/src/plugin/events-instance.js +2 -0
- package/src/plugin/events.js +246 -0
- package/src/plugin/extension_configuration_options_store.js +27 -0
- package/src/plugin/featureFlag.js +8 -0
- package/src/plugin/index.js +118 -0
- package/src/plugin/meta.js +14 -0
- package/src/plugin/public-events.js +73 -0
- package/src/plugin/theming.js +211 -0
- package/src/plugin/util.js +104 -0
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
import EventDispatcher from './event_dispatcher';
|
|
2
|
+
import $ from '../dollar';
|
|
3
|
+
import observe from '../utils/observe';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Timings beyond 20 seconds (connect's load timeout) will be clipped to an X.
|
|
7
|
+
* @const
|
|
8
|
+
* @type {int}
|
|
9
|
+
*/
|
|
10
|
+
const LOADING_TIME_THRESHOLD = 20000;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Trim extra zeros from the load time.
|
|
14
|
+
* @const
|
|
15
|
+
* @type {int}
|
|
16
|
+
*/
|
|
17
|
+
const LOADING_TIME_TRIMP_PRECISION = 100;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {number} value
|
|
21
|
+
* @returns {number}
|
|
22
|
+
*/
|
|
23
|
+
function bucketLoadingTime(value) {
|
|
24
|
+
const bucket = value > LOADING_TIME_THRESHOLD ? LOADING_TIME_THRESHOLD : value;
|
|
25
|
+
return (Math.ceil(bucket / LOADING_TIME_TRIMP_PRECISION) * LOADING_TIME_TRIMP_PRECISION)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Only send 0.1% of content resolver events
|
|
29
|
+
const CONTENT_RESOLVER_SAMPLE_RATE = 0.1;
|
|
30
|
+
|
|
31
|
+
// Only send 0.1% of invoke method events
|
|
32
|
+
const INVOKE_METHOD_SAMPLE_RATE = 0.1;
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
const ALLOWLISTED_METHODS = [
|
|
36
|
+
'saveMacro',
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class AnalyticsDispatcher {
|
|
41
|
+
|
|
42
|
+
constructor() {
|
|
43
|
+
this._addons = {};
|
|
44
|
+
this._sampleLoadEvent = new Map();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Determines whether a sampled event should be sent based on given rate.
|
|
49
|
+
* @param {int} rate Rate as an integer percentage.
|
|
50
|
+
* @returns {boolean}
|
|
51
|
+
*/
|
|
52
|
+
_shouldSampleEvent(rate) {
|
|
53
|
+
return Math.random() * 100 <= rate
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* We want to keep sampling consistent across the various events that are sent for a single iframe load.
|
|
58
|
+
* @param extension
|
|
59
|
+
* @returns {boolean}
|
|
60
|
+
*/
|
|
61
|
+
_shouldSampleLoadEvent(extension) {
|
|
62
|
+
// Only send 1% of iframe load events
|
|
63
|
+
const IFRAME_LOAD_SAMPLE_RATE = 1;
|
|
64
|
+
if (this._sampleLoadEvent.has(extension.id)) {
|
|
65
|
+
return this._sampleLoadEvent.get(extension.id);
|
|
66
|
+
}
|
|
67
|
+
const shouldSample = this._shouldSampleEvent(IFRAME_LOAD_SAMPLE_RATE);
|
|
68
|
+
this._sampleLoadEvent.set(extension.id, shouldSample);
|
|
69
|
+
return shouldSample;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Track an event via GasV3.
|
|
74
|
+
*
|
|
75
|
+
* Warning! Confluence does not use ac/analytics, we have to manually forward it
|
|
76
|
+
* The legacy way of doing this was using individual hooks for each event. Many existing events have dedicated hooks.
|
|
77
|
+
* If you are creating a new event, you can use sendExternal=true to avoid the need for a dedicated hook.
|
|
78
|
+
*
|
|
79
|
+
* https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/browse/confluence/packages/confluence-connect-support/src/ConnectAnalyticsPublishSupport.js
|
|
80
|
+
* @param eventType {string}
|
|
81
|
+
* @param event {object}
|
|
82
|
+
* @param sendExternal {boolean}
|
|
83
|
+
* @private
|
|
84
|
+
*/
|
|
85
|
+
_trackGasV3(eventType, event, sendExternal) {
|
|
86
|
+
if (event.attributes) {
|
|
87
|
+
event.attributes.apVersion = (window._AP && window._AP.version) ? window._AP.version : undefined;
|
|
88
|
+
}
|
|
89
|
+
if (sendExternal) {
|
|
90
|
+
this._forwardGasV3AnalyticsEvent(eventType, event);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const analyticsCrossProduct = window.require('ac/analytics');
|
|
95
|
+
analyticsCrossProduct.emitGasV3(eventType, event);
|
|
96
|
+
} catch (e) {
|
|
97
|
+
if (!window.Confluence && !window.__karma__) {
|
|
98
|
+
// this is not serious. It usually means the product is doing analytics using another mechanism
|
|
99
|
+
// Confluence no longer uses ac/analytics so we should stop reporting it as an error
|
|
100
|
+
console.info('Connect GasV3 catch', e);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
_trackAndForwardGasV3(eventType, event) {
|
|
106
|
+
this._trackGasV3(eventType, event, true);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
_forwardGasV3AnalyticsEvent(eventType, event) {
|
|
110
|
+
EventDispatcher.dispatch('analytics-forward-event', eventType, event)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
_time() {
|
|
114
|
+
return window.performance && window.performance.now ? window.performance.now() : new Date().getTime();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
trackLoadingStarted(extension) {
|
|
118
|
+
if (this._addons && extension && extension.id) {
|
|
119
|
+
extension.startLoading = this._time();
|
|
120
|
+
this._addons[extension.id] = extension;
|
|
121
|
+
} else {
|
|
122
|
+
console.error('ACJS: cannot track loading analytics', this._addons, extension);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
trackGasV3UseOfDeprecatedMethod(methodUsed, extension) {
|
|
127
|
+
this._trackAndForwardGasV3('operational', {
|
|
128
|
+
action: 'deprecatedMethod',
|
|
129
|
+
actionSubject: 'connectAddon',
|
|
130
|
+
actionSubjectId: extension.addon_key,
|
|
131
|
+
attributes: {
|
|
132
|
+
moduleKey: extension.key,
|
|
133
|
+
methodUsed: methodUsed
|
|
134
|
+
},
|
|
135
|
+
source: extension.addon_key
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
trackGasV3MultipleDialogOpening(dialogType, extension) {
|
|
140
|
+
this._trackAndForwardGasV3('operational', {
|
|
141
|
+
action: 'multipleDialogOpened',
|
|
142
|
+
actionSubject: 'connectAddon',
|
|
143
|
+
actionSubjectId: extension.addon_key,
|
|
144
|
+
attributes: {
|
|
145
|
+
moduleKey: extension.key,
|
|
146
|
+
dialogType: dialogType
|
|
147
|
+
},
|
|
148
|
+
source: extension.addon_key
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
trackIframePerformance(metrics, extension) {
|
|
153
|
+
if (!this._shouldSampleLoadEvent(extension)) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
this._trackGasV3('operational', {
|
|
157
|
+
source: extension.addon_key,
|
|
158
|
+
action: 'iframeRendered',
|
|
159
|
+
actionSubject: 'connectAddon',
|
|
160
|
+
actionSubjectId: extension.addon_key,
|
|
161
|
+
attributes: {
|
|
162
|
+
key: extension['key'],
|
|
163
|
+
pearApp: this._getPearApp(extension),
|
|
164
|
+
moduleType: this._getModuleType(extension),
|
|
165
|
+
iframeIsCacheable: this._isCacheable(extension),
|
|
166
|
+
moduleLocation: this._getModuleLocation(extension),
|
|
167
|
+
domainLookupTime: metrics.domainLookupTime,
|
|
168
|
+
connectionTime: metrics.connectionTime,
|
|
169
|
+
decodedBodySize: metrics.decodedBodySize,
|
|
170
|
+
domContentLoadedTime: metrics.domContentLoadedTime,
|
|
171
|
+
fetchTime: metrics.fetchTime
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
trackGasV3WebVitals(metrics, extension) {
|
|
177
|
+
if (!this._shouldSampleLoadEvent(extension)) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
this._trackAndForwardGasV3('operational', {
|
|
181
|
+
source: extension.addon_key,
|
|
182
|
+
action: 'webVitals',
|
|
183
|
+
actionSubject: 'connectAddon',
|
|
184
|
+
actionSubjectId: extension.addon_key,
|
|
185
|
+
attributes: Object.assign({}, metrics, {
|
|
186
|
+
key: extension['key'],
|
|
187
|
+
pearApp: this._getPearApp(extension),
|
|
188
|
+
moduleType: this._getModuleType(extension),
|
|
189
|
+
iframeIsCacheable: this._isCacheable(extension),
|
|
190
|
+
moduleLocation: this._getModuleLocation(extension),
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
dispatch(name, data) {
|
|
196
|
+
this._trackGasV3External(name, data);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
trackExternal(name, data) {
|
|
200
|
+
this._trackGasV3External(name, data);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
_trackGasV3External(name, data) {
|
|
204
|
+
this._trackAndForwardGasV3('operational', {
|
|
205
|
+
action: 'externalEvent',
|
|
206
|
+
actionSubject: 'connectAddon',
|
|
207
|
+
actionSubjectId: name,
|
|
208
|
+
attributes: {
|
|
209
|
+
eventName: name,
|
|
210
|
+
...(typeof data === 'object' ? data : { values: data })
|
|
211
|
+
},
|
|
212
|
+
source: 'connectAddon'
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* method called when an iframe's loading metrics gets corrupted
|
|
218
|
+
* to destroy the analytics as they cannot be reliable
|
|
219
|
+
* this should be called when:
|
|
220
|
+
* 1. the product calls iframe creation multiple times for the same connect addon
|
|
221
|
+
* 2. the iframe is moved / repainted causing a window.reload event
|
|
222
|
+
* 3. user right clicks iframe and reloads it
|
|
223
|
+
*/
|
|
224
|
+
_resetAnalyticsDueToUnreliable(extensionId) {
|
|
225
|
+
if(!extensionId) {
|
|
226
|
+
throw new Error('Cannot reset analytics due to no extension id');
|
|
227
|
+
}
|
|
228
|
+
if(this._addons[extensionId]) {
|
|
229
|
+
clearTimeout(this._addons[extensionId]);
|
|
230
|
+
delete this._addons[extensionId];
|
|
231
|
+
} else {
|
|
232
|
+
console.info('Cannot clear analytics, cache does not contain extension id');
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
_isCacheable(extension) {
|
|
237
|
+
const href = extension.url;
|
|
238
|
+
return href !== undefined && href.indexOf('xdm_e=') === -1;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
_getModuleType(extension) {
|
|
242
|
+
return extension.options ? extension.options.moduleType : undefined;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
_getModuleLocation(extension) {
|
|
246
|
+
return extension.options ? extension.options.moduleLocation : undefined;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
_getPearApp(extension) {
|
|
250
|
+
return extension.options && extension.options.pearApp === 'true';
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
trackGasV3Visible (extension) {
|
|
254
|
+
if (!this._shouldSampleLoadEvent(extension)) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
this._trackGasV3('operational', {
|
|
258
|
+
action: 'iframeViewed',
|
|
259
|
+
actionSubject: 'connectAddon',
|
|
260
|
+
actionSubjectId: extension['addon_key'],
|
|
261
|
+
attributes: {
|
|
262
|
+
moduleType: this._getModuleType(extension),
|
|
263
|
+
iframeIsCacheable: this._isCacheable(extension),
|
|
264
|
+
moduleKey: extension.key,
|
|
265
|
+
moduleLocation: this._getModuleLocation(extension),
|
|
266
|
+
pearApp: this._getPearApp(extension)
|
|
267
|
+
},
|
|
268
|
+
source: extension.addon_key
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
trackGasV3InvokeMethod(extension, module, method, methodArgs) {
|
|
273
|
+
if (!this._shouldSampleEvent(INVOKE_METHOD_SAMPLE_RATE) && !ALLOWLISTED_METHODS.includes(method)) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const args = Array.isArray(methodArgs) ? [...methodArgs] : [];
|
|
278
|
+
const isContextFn = (arg) => typeof arg === 'function' && Boolean(arg._context);
|
|
279
|
+
|
|
280
|
+
// Remove undefined values, or the callback context function only at the very end of the array
|
|
281
|
+
while (args.length > 0 && (args[args.length - 1] === undefined || isContextFn(args[args.length - 1]))) {
|
|
282
|
+
args.pop();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const argTypes = args.map(arg => {
|
|
286
|
+
if (Array.isArray(arg)) {
|
|
287
|
+
return 'array'
|
|
288
|
+
} else if (arg === null) {
|
|
289
|
+
return 'null'
|
|
290
|
+
}
|
|
291
|
+
return typeof arg;
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
this._trackAndForwardGasV3('operational', {
|
|
295
|
+
action: 'invokeMethod',
|
|
296
|
+
actionSubject: 'connectAddon',
|
|
297
|
+
actionSubjectId: extension['addon_key'],
|
|
298
|
+
attributes: {
|
|
299
|
+
argCount: args.length,
|
|
300
|
+
argTypes,
|
|
301
|
+
module: module,
|
|
302
|
+
method: method,
|
|
303
|
+
moduleType: this._getModuleType(extension),
|
|
304
|
+
moduleKey: extension.key,
|
|
305
|
+
moduleLocation: this._getModuleLocation(extension),
|
|
306
|
+
pearApp: this._getPearApp(extension)
|
|
307
|
+
},
|
|
308
|
+
source: extension.addon_key
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
trackGasV3ContentResolver(isSuccess, extra) {
|
|
313
|
+
if (!this._shouldSampleEvent(CONTENT_RESOLVER_SAMPLE_RATE)) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
const extension = extra.extension;
|
|
317
|
+
const attrs = extra.attrs;
|
|
318
|
+
const action = isSuccess ? 'contentResolverSucceeded' : 'contentResolverFailed';
|
|
319
|
+
this._trackGasV3('operational', {
|
|
320
|
+
action: action,
|
|
321
|
+
actionSubject: 'connectAddon',
|
|
322
|
+
actionSubjectId: extension['addon_key'],
|
|
323
|
+
attributes: Object.assign({}, attrs, {
|
|
324
|
+
moduleType: this._getModuleType(extension),
|
|
325
|
+
moduleKey: extension.key,
|
|
326
|
+
moduleLocation: this._getModuleLocation(extension),
|
|
327
|
+
pearApp: this._getPearApp(extension)
|
|
328
|
+
}),
|
|
329
|
+
source: extension.addon_key
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
trackGasV3LoadingEnded (extension) {
|
|
334
|
+
if (!this._shouldSampleLoadEvent(extension)) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
var iframeLoadMillis = this._time() - this._addons[extension.id].startLoading;
|
|
338
|
+
this._trackGasV3('operational', {
|
|
339
|
+
action: 'iframeLoaded',
|
|
340
|
+
actionSubject: 'connectAddon',
|
|
341
|
+
actionSubjectId: extension['addon_key'],
|
|
342
|
+
attributes: {
|
|
343
|
+
moduleType: this._getModuleType(extension),
|
|
344
|
+
iframeIsCacheable: this._isCacheable(extension),
|
|
345
|
+
iframeLoadMillis: iframeLoadMillis,
|
|
346
|
+
iframeLoadBucket: bucketLoadingTime(iframeLoadMillis),
|
|
347
|
+
moduleKey: extension.key,
|
|
348
|
+
moduleLocation: this._getModuleLocation(extension),
|
|
349
|
+
pearApp: this._getPearApp(extension)
|
|
350
|
+
},
|
|
351
|
+
source: extension.addon_key
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
trackGasV3LoadingTimeout (extension) {
|
|
356
|
+
if (!this._shouldSampleLoadEvent(extension)) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
this._trackGasV3('operational', {
|
|
360
|
+
action: 'iframeTimeout',
|
|
361
|
+
actionSubject: 'connectAddon',
|
|
362
|
+
actionSubjectId: extension['addon_key'],
|
|
363
|
+
attributes: {
|
|
364
|
+
moduleType: this._getModuleType(extension),
|
|
365
|
+
iframeIsCacheable: this._isCacheable(extension),
|
|
366
|
+
moduleKey: extension.key,
|
|
367
|
+
moduleLocation: this._getModuleLocation(extension),
|
|
368
|
+
pearApp: this._getPearApp(extension),
|
|
369
|
+
connectedStatus: typeof window.navigator.onLine === 'boolean' ? window.navigator.onLine.toString() : 'not-supported'
|
|
370
|
+
},
|
|
371
|
+
source: extension.addon_key
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* @param {WebItemInvokedEventData} data
|
|
377
|
+
*/
|
|
378
|
+
trackGasV3InlineDialogOpened(data) {
|
|
379
|
+
const extension = data.extension;
|
|
380
|
+
this._trackAndForwardGasV3('operational', {
|
|
381
|
+
action: 'inlineDialogOpened',
|
|
382
|
+
actionSubject: 'connectAddon',
|
|
383
|
+
actionSubjectId: extension['addon_key'],
|
|
384
|
+
attributes: {
|
|
385
|
+
moduleKey: extension.key,
|
|
386
|
+
moduleLocation: this._getModuleLocation(extension),
|
|
387
|
+
eventType: data.eventType,
|
|
388
|
+
onHoverEnabled: data.onHover
|
|
389
|
+
},
|
|
390
|
+
source: extension.addon_key
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Track a dialog opened via the legacy event-handler (non-imperative) API
|
|
396
|
+
*/
|
|
397
|
+
trackGasV3LegacyDialogOpened(data) {
|
|
398
|
+
const extension = data.extension;
|
|
399
|
+
this._trackAndForwardGasV3('operational', {
|
|
400
|
+
action: 'legacyDialogOpened',
|
|
401
|
+
actionSubject: 'connectAddon',
|
|
402
|
+
actionSubjectId: extension['addon_key'],
|
|
403
|
+
attributes: {
|
|
404
|
+
moduleKey: extension.key,
|
|
405
|
+
moduleLocation: this._getModuleLocation(extension),
|
|
406
|
+
parentIds: data.parentIds
|
|
407
|
+
},
|
|
408
|
+
source: extension.addon_key
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Tracks when the Statsig client is not initialised before the Statsig feature flag is fetched
|
|
414
|
+
* Jira - https://data-portal.internal.atlassian.com/analytics/registry/67270
|
|
415
|
+
* Confluence - https://data-portal.internal.atlassian.com/analytics/registry/67271
|
|
416
|
+
*/
|
|
417
|
+
trackGasV3FeatureFlagDefaultFalse(featureFlag) {
|
|
418
|
+
this._trackAndForwardGasV3('operational', {
|
|
419
|
+
action: 'returned',
|
|
420
|
+
actionSubject: 'defaultFalseFeatureFlag',
|
|
421
|
+
actionSubjectId: featureFlag,
|
|
422
|
+
source: 'host',
|
|
423
|
+
attributes: {
|
|
424
|
+
featureFlag
|
|
425
|
+
},
|
|
426
|
+
source: 'Host'
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Tracks when a Connect iframe is clicked
|
|
432
|
+
*/
|
|
433
|
+
trackGasV3IframeClicked(data) {
|
|
434
|
+
this._trackAndForwardGasV3('ui', {
|
|
435
|
+
action: 'iframeClicked',
|
|
436
|
+
actionSubject: 'connectAddon',
|
|
437
|
+
source: 'host',
|
|
438
|
+
attributes: {
|
|
439
|
+
appId: data.addonKey,
|
|
440
|
+
moduleType: data.moduleType,
|
|
441
|
+
moduleLocation: data.moduleLocation,
|
|
442
|
+
baseUrl: data.baseUrl,
|
|
443
|
+
}
|
|
444
|
+
})
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
var analytics = new AnalyticsDispatcher();
|
|
449
|
+
if ($.fn) {
|
|
450
|
+
EventDispatcher.register('iframe-create', function (data) {
|
|
451
|
+
analytics.trackLoadingStarted(data.extension);
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
EventDispatcher.register('method-invoked', function (data) {
|
|
456
|
+
analytics.trackGasV3InvokeMethod(data.extension, data.module, data.fn, data.args);
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
EventDispatcher.register('iframe-bridge-start', function (data) {
|
|
460
|
+
analytics.trackLoadingStarted(data.extension);
|
|
461
|
+
});
|
|
462
|
+
EventDispatcher.register('iframe-bridge-established', function (data) {
|
|
463
|
+
analytics.trackGasV3LoadingEnded(data.extension);
|
|
464
|
+
observe(document.getElementById(data.extension.id), () => {
|
|
465
|
+
EventDispatcher.dispatch('iframe-visible', data.extension);
|
|
466
|
+
analytics.trackGasV3Visible(data.extension);
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
EventDispatcher.register('iframe-bridge-timeout', function (data) {
|
|
471
|
+
analytics.trackGasV3LoadingTimeout(data.extension);
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
EventDispatcher.register('analytics-deprecated-method-used', function (data) {
|
|
475
|
+
analytics.trackGasV3UseOfDeprecatedMethod(data.methodUsed, data.extension);
|
|
476
|
+
});
|
|
477
|
+
EventDispatcher.register('analytics-iframe-performance', function (data) {
|
|
478
|
+
analytics.trackIframePerformance(data.metrics, data.extension);
|
|
479
|
+
});
|
|
480
|
+
EventDispatcher.register('analytics-web-vitals', function (data) {
|
|
481
|
+
analytics.trackGasV3WebVitals(data.metrics, data.extension);
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
EventDispatcher.register('iframe-destroyed', function (data) {
|
|
485
|
+
analytics._resetAnalyticsDueToUnreliable(data.extension.extension_id);
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
EventDispatcher.register('analytics-external-event-track', function (data) {
|
|
489
|
+
analytics.trackExternal(data.eventName, data.values);
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
EventDispatcher.register('analytics-content-resolver-track', function (data) {
|
|
493
|
+
const success = data.success;
|
|
494
|
+
const extra = data.extra;
|
|
495
|
+
analytics.trackGasV3ContentResolver(success, extra);
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
EventDispatcher.register('analytics-inline-dialog-opened', function (data) {
|
|
499
|
+
analytics.trackGasV3InlineDialogOpened(data);
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
EventDispatcher.register('analytics-legacy-dialog-opened', function (data) {
|
|
503
|
+
analytics.trackGasV3LegacyDialogOpened(data);
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
EventDispatcher.register('analytics-track-iframe-clicked', function (data) {
|
|
507
|
+
analytics.trackGasV3IframeClicked(data);
|
|
508
|
+
})
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
export default analytics;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pub/sub for extension state (created, destroyed, initialized)
|
|
3
|
+
* taken from hipchat webcore
|
|
4
|
+
**/
|
|
5
|
+
|
|
6
|
+
import EventEmitter from 'events';
|
|
7
|
+
|
|
8
|
+
class EventDispatcher extends EventEmitter {
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
super();
|
|
12
|
+
this.setMaxListeners(20);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
dispatch(action, ...args) {
|
|
16
|
+
this.emit.apply(this, ['before:' + action].concat(args));
|
|
17
|
+
this.emit.apply(this, arguments);
|
|
18
|
+
this.emit.apply(this, ['after:' + action].concat(args));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
registerOnce(action, callback) {
|
|
22
|
+
if (typeof action === 'string') {
|
|
23
|
+
this.once(action, callback);
|
|
24
|
+
} else {
|
|
25
|
+
throw 'ACJS: event name must be string';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
register(action, callback) {
|
|
30
|
+
if (typeof action === 'string') {
|
|
31
|
+
this.on(action, callback);
|
|
32
|
+
} else {
|
|
33
|
+
throw 'ACJS: event name must be string';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
unregister(action, callback) {
|
|
38
|
+
if (typeof action === 'string') {
|
|
39
|
+
this.removeListener(action, callback);
|
|
40
|
+
} else {
|
|
41
|
+
throw 'ACJS: event name must be string';
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default new EventDispatcher();
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The iframe-side code exposes a jquery-like implementation via _dollar.
|
|
3
|
+
* This runs on the product side to provide AJS.$ under a _dollar module to provide a consistent interface
|
|
4
|
+
* to code that runs on host and iframe.
|
|
5
|
+
*/
|
|
6
|
+
export default (window.AJS && window.AJS.$) || function() {
|
|
7
|
+
console.error('[ACJS] jQuery was not loaded before Connect. If in product frontend, make sure to load via a wrapper, eg withConnectHost()')
|
|
8
|
+
};
|