@thoughtspot/visual-embed-sdk 1.25.0 → 1.26.0-token-cache.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.
- package/README.md +1 -1
- package/cjs/package.json +1 -1
- package/cjs/src/auth.d.ts +0 -12
- package/cjs/src/auth.d.ts.map +1 -1
- package/cjs/src/auth.js +15 -54
- package/cjs/src/auth.js.map +1 -1
- package/cjs/src/auth.spec.d.ts.map +1 -1
- package/cjs/src/auth.spec.js +44 -5
- package/cjs/src/auth.spec.js.map +1 -1
- package/cjs/src/authToken.d.ts +4 -0
- package/cjs/src/authToken.d.ts.map +1 -0
- package/cjs/src/authToken.js +60 -0
- package/cjs/src/authToken.js.map +1 -0
- package/cjs/src/config.d.ts.map +1 -1
- package/cjs/src/config.js +3 -0
- package/cjs/src/config.js.map +1 -1
- package/cjs/src/config.spec.js +1 -1
- package/cjs/src/config.spec.js.map +1 -1
- package/cjs/src/embed/TsEmbed.d.ts +302 -0
- package/cjs/src/embed/TsEmbed.d.ts.map +1 -0
- package/cjs/src/embed/TsEmbed.js +851 -0
- package/cjs/src/embed/TsEmbed.js.map +1 -0
- package/cjs/src/embed/base.d.ts +0 -1
- package/cjs/src/embed/base.d.ts.map +1 -1
- package/cjs/src/embed/base.js +6 -5
- package/cjs/src/embed/base.js.map +1 -1
- package/cjs/src/embed/base.spec.js +7 -5
- package/cjs/src/embed/base.spec.js.map +1 -1
- package/cjs/src/embed/search.d.ts +0 -4
- package/cjs/src/embed/search.d.ts.map +1 -1
- package/cjs/src/embed/search.js +3 -2
- package/cjs/src/embed/search.js.map +1 -1
- package/cjs/src/embed/ts-embed.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.js +3 -2
- package/cjs/src/embed/ts-embed.js.map +1 -1
- package/cjs/src/embed/ts-embed.spec.js +48 -37
- package/cjs/src/embed/ts-embed.spec.js.map +1 -1
- package/cjs/src/react/index.spec.js +0 -12
- package/cjs/src/react/index.spec.js.map +1 -1
- package/cjs/src/tokenizedFetch.d.ts +2 -0
- package/cjs/src/tokenizedFetch.d.ts.map +1 -0
- package/cjs/src/tokenizedFetch.js +20 -0
- package/cjs/src/tokenizedFetch.js.map +1 -0
- package/cjs/src/types.d.ts +11 -1
- package/cjs/src/types.d.ts.map +1 -1
- package/cjs/src/types.js +7 -1
- package/cjs/src/types.js.map +1 -1
- package/cjs/src/utils/answerService.d.ts +10 -0
- package/cjs/src/utils/answerService.d.ts.map +1 -0
- package/cjs/src/utils/answerService.js +61 -0
- package/cjs/src/utils/answerService.js.map +1 -0
- package/cjs/src/utils/answerService.spec.d.ts +2 -0
- package/cjs/src/utils/answerService.spec.d.ts.map +1 -0
- package/cjs/src/utils/answerService.spec.js +31 -0
- package/cjs/src/utils/answerService.spec.js.map +1 -0
- package/cjs/src/utils/authService.d.ts +12 -1
- package/cjs/src/utils/authService.d.ts.map +1 -1
- package/cjs/src/utils/authService.js +32 -16
- package/cjs/src/utils/authService.js.map +1 -1
- package/cjs/src/utils/authService.spec.js +3 -4
- package/cjs/src/utils/authService.spec.js.map +1 -1
- package/cjs/src/utils/graphql/answerService/answerService.d.ts +1 -0
- package/cjs/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
- package/cjs/src/utils/graphql/answerService/answerService.js +6 -2
- package/cjs/src/utils/graphql/answerService/answerService.js.map +1 -1
- package/cjs/src/utils/graphql/answerService/answerService.spec.js +18 -2
- package/cjs/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
- package/cjs/src/utils/graphql/graphql-request.spec.d.ts +2 -0
- package/cjs/src/utils/graphql/graphql-request.spec.d.ts.map +1 -0
- package/cjs/src/utils/graphql/graphql-request.spec.js +39 -0
- package/cjs/src/utils/graphql/graphql-request.spec.js.map +1 -0
- package/cjs/src/utils/logger.d.ts +28 -0
- package/cjs/src/utils/logger.d.ts.map +1 -0
- package/cjs/src/utils/logger.js +82 -0
- package/cjs/src/utils/logger.js.map +1 -0
- package/cjs/src/utils/processData.d.ts.map +1 -1
- package/cjs/src/utils/processData.js +2 -2
- package/cjs/src/utils/processData.js.map +1 -1
- package/cjs/src/utils/processData.spec.js +2 -2
- package/cjs/src/utils/processData.spec.js.map +1 -1
- package/dist/src/auth.d.ts +0 -12
- package/dist/src/auth.d.ts.map +1 -1
- package/dist/src/auth.spec.d.ts.map +1 -1
- package/dist/src/authToken.d.ts +4 -0
- package/dist/src/authToken.d.ts.map +1 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/embed/base.d.ts +0 -1
- package/dist/src/embed/base.d.ts.map +1 -1
- package/dist/src/embed/search.d.ts +0 -4
- package/dist/src/embed/search.d.ts.map +1 -1
- package/dist/src/embed/ts-embed.d.ts.map +1 -1
- package/dist/src/tokenizedFetch.d.ts +2 -0
- package/dist/src/tokenizedFetch.d.ts.map +1 -0
- package/dist/src/types.d.ts +11 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/answerService.d.ts +10 -0
- package/dist/src/utils/answerService.d.ts.map +1 -0
- package/dist/src/utils/answerService.spec.d.ts +2 -0
- package/dist/src/utils/answerService.spec.d.ts.map +1 -0
- package/dist/src/utils/authService.d.ts +12 -1
- package/dist/src/utils/authService.d.ts.map +1 -1
- package/dist/src/utils/graphql/answerService/answerService.d.ts +1 -0
- package/dist/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
- package/dist/src/utils/graphql/graphql-request.spec.d.ts +2 -0
- package/dist/src/utils/graphql/graphql-request.spec.d.ts.map +1 -0
- package/dist/src/utils/logger.d.ts +28 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/processData.d.ts.map +1 -1
- package/dist/tsembed-react.es.js +2149 -2094
- package/dist/tsembed-react.js +2152 -2097
- package/dist/tsembed.es.js +6483 -6425
- package/dist/tsembed.js +6483 -6425
- package/dist/visual-embed-sdk-react-full.d.ts +12 -18
- package/dist/visual-embed-sdk-react.d.ts +12 -18
- package/dist/visual-embed-sdk.d.ts +12 -18
- package/lib/package.json +1 -1
- package/lib/src/auth.d.ts +0 -12
- package/lib/src/auth.d.ts.map +1 -1
- package/lib/src/auth.js +10 -48
- package/lib/src/auth.js.map +1 -1
- package/lib/src/auth.spec.d.ts.map +1 -1
- package/lib/src/auth.spec.js +44 -5
- package/lib/src/auth.spec.js.map +1 -1
- package/lib/src/authToken.d.ts +4 -0
- package/lib/src/authToken.d.ts.map +1 -0
- package/lib/src/authToken.js +55 -0
- package/lib/src/authToken.js.map +1 -0
- package/lib/src/config.d.ts.map +1 -1
- package/lib/src/config.js +3 -0
- package/lib/src/config.js.map +1 -1
- package/lib/src/config.spec.js +1 -1
- package/lib/src/config.spec.js.map +1 -1
- package/lib/src/embed/TsEmbed.d.ts +302 -0
- package/lib/src/embed/TsEmbed.d.ts.map +1 -0
- package/lib/src/embed/TsEmbed.js +847 -0
- package/lib/src/embed/TsEmbed.js.map +1 -0
- package/lib/src/embed/base.d.ts +0 -1
- package/lib/src/embed/base.d.ts.map +1 -1
- package/lib/src/embed/base.js +3 -2
- package/lib/src/embed/base.js.map +1 -1
- package/lib/src/embed/base.spec.js +7 -5
- package/lib/src/embed/base.spec.js.map +1 -1
- package/lib/src/embed/search.d.ts +0 -4
- package/lib/src/embed/search.d.ts.map +1 -1
- package/lib/src/embed/search.js +3 -2
- package/lib/src/embed/search.js.map +1 -1
- package/lib/src/embed/ts-embed.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.js +2 -1
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/embed/ts-embed.spec.js +48 -37
- package/lib/src/embed/ts-embed.spec.js.map +1 -1
- package/lib/src/react/index.spec.js +0 -12
- package/lib/src/react/index.spec.js.map +1 -1
- package/lib/src/tokenizedFetch.d.ts +2 -0
- package/lib/src/tokenizedFetch.d.ts.map +1 -0
- package/lib/src/tokenizedFetch.js +16 -0
- package/lib/src/tokenizedFetch.js.map +1 -0
- package/lib/src/types.d.ts +11 -1
- package/lib/src/types.d.ts.map +1 -1
- package/lib/src/types.js +7 -1
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils/answerService.d.ts +10 -0
- package/lib/src/utils/answerService.d.ts.map +1 -0
- package/lib/src/utils/answerService.js +57 -0
- package/lib/src/utils/answerService.js.map +1 -0
- package/lib/src/utils/answerService.spec.d.ts +2 -0
- package/lib/src/utils/answerService.spec.d.ts.map +1 -0
- package/lib/src/utils/answerService.spec.js +29 -0
- package/lib/src/utils/answerService.spec.js.map +1 -0
- package/lib/src/utils/authService.d.ts +12 -1
- package/lib/src/utils/authService.d.ts.map +1 -1
- package/lib/src/utils/authService.js +26 -10
- package/lib/src/utils/authService.js.map +1 -1
- package/lib/src/utils/authService.spec.js +1 -2
- package/lib/src/utils/authService.spec.js.map +1 -1
- package/lib/src/utils/graphql/answerService/answerService.d.ts +1 -0
- package/lib/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
- package/lib/src/utils/graphql/answerService/answerService.js +6 -2
- package/lib/src/utils/graphql/answerService/answerService.js.map +1 -1
- package/lib/src/utils/graphql/answerService/answerService.spec.js +17 -2
- package/lib/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
- package/lib/src/utils/graphql/graphql-request.spec.d.ts +2 -0
- package/lib/src/utils/graphql/graphql-request.spec.d.ts.map +1 -0
- package/lib/src/utils/graphql/graphql-request.spec.js +36 -0
- package/lib/src/utils/graphql/graphql-request.spec.js.map +1 -0
- package/lib/src/utils/logger.d.ts +28 -0
- package/lib/src/utils/logger.d.ts.map +1 -0
- package/lib/src/utils/logger.js +75 -0
- package/lib/src/utils/logger.js.map +1 -0
- package/lib/src/utils/processData.d.ts.map +1 -1
- package/lib/src/utils/processData.js +2 -2
- package/lib/src/utils/processData.js.map +1 -1
- package/lib/src/utils/processData.spec.js +2 -2
- package/lib/src/utils/processData.spec.js.map +1 -1
- package/lib/src/visual-embed-sdk.d.ts +12 -18
- package/package.json +1 -1
- package/src/auth.spec.ts +47 -7
- package/src/auth.ts +9 -50
- package/src/authToken.ts +60 -0
- package/src/config.spec.ts +1 -1
- package/src/config.ts +3 -0
- package/src/embed/base.spec.ts +7 -6
- package/src/embed/base.ts +2 -3
- package/src/embed/search.ts +2 -6
- package/src/embed/ts-embed.spec.ts +54 -40
- package/src/embed/ts-embed.ts +2 -1
- package/src/react/index.spec.tsx +0 -29
- package/src/tokenizedFetch.ts +16 -0
- package/src/types.ts +12 -2
- package/src/utils/authService.spec.ts +1 -2
- package/src/utils/authService.ts +29 -10
- package/src/utils/graphql/answerService/answerService.spec.ts +27 -3
- package/src/utils/graphql/answerService/answerService.ts +7 -2
- package/src/utils/processData.spec.ts +2 -2
- package/src/utils/processData.ts +2 -1
package/dist/tsembed-react.es.js
CHANGED
|
@@ -1146,11 +1146,17 @@ var EmbedEvent;
|
|
|
1146
1146
|
*/
|
|
1147
1147
|
EmbedEvent["SageWorksheetUpdated"] = "sageWorksheetUpdated";
|
|
1148
1148
|
/**
|
|
1149
|
-
*
|
|
1149
|
+
* Emitted when a user updates a connection in Data tab
|
|
1150
1150
|
*
|
|
1151
1151
|
* @version SDK : 1.27.0 | Thoughtspot: 9.8.0.cl
|
|
1152
1152
|
*/
|
|
1153
1153
|
EmbedEvent["UpdateConnection"] = "updateConnection";
|
|
1154
|
+
/**
|
|
1155
|
+
* Emitted when a user updates a connection in Data tab
|
|
1156
|
+
*
|
|
1157
|
+
* @version SDK : 1.27.0 | Thoughtspot: 9.8.0.cl
|
|
1158
|
+
*/
|
|
1159
|
+
EmbedEvent["CreateConnection"] = "createConnection";
|
|
1154
1160
|
/**
|
|
1155
1161
|
* Emitted when name, status (private or public) or filter values of a
|
|
1156
1162
|
* PersonalisedView is updated.
|
|
@@ -5106,384 +5112,543 @@ function isEqual(value, other) {
|
|
|
5106
5112
|
|
|
5107
5113
|
var isEqual_1 = isEqual;
|
|
5108
5114
|
|
|
5115
|
+
const EndPoints = {
|
|
5116
|
+
AUTH_VERIFICATION: '/callosum/v1/session/info',
|
|
5117
|
+
SAML_LOGIN_TEMPLATE: (targetUrl) => `/callosum/v1/saml/login?targetURLPath=${targetUrl}`,
|
|
5118
|
+
OIDC_LOGIN_TEMPLATE: (targetUrl) => `/callosum/v1/oidc/login?targetURLPath=${targetUrl}`,
|
|
5119
|
+
TOKEN_LOGIN: '/callosum/v1/session/login/token',
|
|
5120
|
+
BASIC_LOGIN: '/callosum/v1/session/login',
|
|
5121
|
+
LOGOUT: '/callosum/v1/session/logout',
|
|
5122
|
+
EXECUTE_TML: '/api/rest/2.0/metadata/tml/import',
|
|
5123
|
+
EXPORT_TML: '/api/rest/2.0/metadata/tml/export',
|
|
5124
|
+
IS_ACTIVE: '/callosum/v1/session/isactive',
|
|
5125
|
+
};
|
|
5109
5126
|
/**
|
|
5110
5127
|
*
|
|
5111
|
-
* @param
|
|
5112
|
-
* @param
|
|
5113
|
-
* @param root0.variables
|
|
5114
|
-
* @param root0.thoughtSpotHost
|
|
5115
|
-
* @param root0.isCompositeQuery
|
|
5128
|
+
* @param url
|
|
5129
|
+
* @param options
|
|
5116
5130
|
*/
|
|
5117
|
-
|
|
5118
|
-
|
|
5131
|
+
function failureLoggedFetch(url, options = {}) {
|
|
5132
|
+
return fetch(url, options).then(async (r) => {
|
|
5133
|
+
var _a;
|
|
5134
|
+
if (!r.ok && r.type !== 'opaqueredirect' && r.type !== 'opaque') {
|
|
5135
|
+
console.error('Failure', await ((_a = r.text) === null || _a === void 0 ? void 0 : _a.call(r)));
|
|
5136
|
+
}
|
|
5137
|
+
return r;
|
|
5138
|
+
});
|
|
5139
|
+
}
|
|
5140
|
+
/**
|
|
5141
|
+
*
|
|
5142
|
+
* @param authVerificationUrl
|
|
5143
|
+
*/
|
|
5144
|
+
function fetchSessionInfoService(authVerificationUrl) {
|
|
5145
|
+
return failureLoggedFetch(authVerificationUrl, {
|
|
5146
|
+
credentials: 'include',
|
|
5147
|
+
});
|
|
5148
|
+
}
|
|
5149
|
+
/**
|
|
5150
|
+
* Service to validate a auth token against a ThoughtSpot host.
|
|
5151
|
+
*
|
|
5152
|
+
* @param thoughtSpotHost : ThoughtSpot host to verify the token against.
|
|
5153
|
+
* @param authToken : Auth token to verify.
|
|
5154
|
+
*/
|
|
5155
|
+
async function verifyTokenService(thoughtSpotHost, authToken) {
|
|
5156
|
+
const authVerificationUrl = `${thoughtSpotHost}${EndPoints.IS_ACTIVE}`;
|
|
5119
5157
|
try {
|
|
5120
|
-
const
|
|
5121
|
-
method: 'POST',
|
|
5158
|
+
const res = await fetch(authVerificationUrl, {
|
|
5122
5159
|
headers: {
|
|
5123
|
-
|
|
5160
|
+
Authorization: `Bearer ${authToken}`,
|
|
5124
5161
|
'x-requested-by': 'ThoughtSpot',
|
|
5125
|
-
accept: '*/*',
|
|
5126
|
-
'accept-language': 'en-us',
|
|
5127
5162
|
},
|
|
5128
|
-
|
|
5129
|
-
operationName,
|
|
5130
|
-
query,
|
|
5131
|
-
variables,
|
|
5132
|
-
}),
|
|
5133
|
-
credentials: 'include',
|
|
5163
|
+
credentials: 'omit',
|
|
5134
5164
|
});
|
|
5135
|
-
|
|
5136
|
-
const dataValues = Object.values(result.data);
|
|
5137
|
-
return (isCompositeQuery) ? result.data : dataValues[0];
|
|
5165
|
+
return res.ok;
|
|
5138
5166
|
}
|
|
5139
|
-
catch (
|
|
5140
|
-
|
|
5167
|
+
catch (e) {
|
|
5168
|
+
console.error(`Token Verification Service failed : ${e.message}`);
|
|
5141
5169
|
}
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
authorDisplayName
|
|
5152
|
-
isExternal
|
|
5153
|
-
type
|
|
5154
|
-
created
|
|
5155
|
-
modified
|
|
5156
|
-
columns {
|
|
5157
|
-
id
|
|
5158
|
-
name
|
|
5159
|
-
author
|
|
5160
|
-
authorDisplayName
|
|
5161
|
-
description
|
|
5162
|
-
dataType
|
|
5163
|
-
type
|
|
5164
|
-
modified
|
|
5165
|
-
ownerName
|
|
5166
|
-
owner
|
|
5167
|
-
dataRecency
|
|
5168
|
-
sources {
|
|
5169
|
-
tableId
|
|
5170
|
-
tableName
|
|
5171
|
-
columnId
|
|
5172
|
-
columnName
|
|
5173
|
-
__typename
|
|
5174
|
-
}
|
|
5175
|
-
synonyms
|
|
5176
|
-
cohortAnswerId
|
|
5177
|
-
__typename
|
|
5178
|
-
}
|
|
5179
|
-
relationships
|
|
5180
|
-
destinationRelationships
|
|
5181
|
-
dataSourceId
|
|
5182
|
-
__typename
|
|
5183
|
-
}
|
|
5184
|
-
}
|
|
5185
|
-
`;
|
|
5186
|
-
const sourceDetailCache = new Map();
|
|
5170
|
+
return false;
|
|
5171
|
+
}
|
|
5172
|
+
/**
|
|
5173
|
+
*
|
|
5174
|
+
* @param authEndpoint
|
|
5175
|
+
*/
|
|
5176
|
+
async function fetchAuthTokenService(authEndpoint) {
|
|
5177
|
+
return fetch(authEndpoint);
|
|
5178
|
+
}
|
|
5187
5179
|
/**
|
|
5188
5180
|
*
|
|
5189
5181
|
* @param thoughtSpotHost
|
|
5190
|
-
* @param
|
|
5182
|
+
* @param username
|
|
5183
|
+
* @param authToken
|
|
5191
5184
|
*/
|
|
5192
|
-
async function
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5185
|
+
async function fetchAuthService(thoughtSpotHost, username, authToken) {
|
|
5186
|
+
return failureLoggedFetch(`${thoughtSpotHost}${EndPoints.TOKEN_LOGIN}?username=${username}&auth_token=${authToken}`, {
|
|
5187
|
+
credentials: 'include',
|
|
5188
|
+
// We do not want to follow the redirect, as it starts giving a CORS
|
|
5189
|
+
// error
|
|
5190
|
+
redirect: 'manual',
|
|
5191
|
+
});
|
|
5192
|
+
}
|
|
5193
|
+
/**
|
|
5194
|
+
*
|
|
5195
|
+
* @param thoughtSpotHost
|
|
5196
|
+
* @param username
|
|
5197
|
+
* @param authToken
|
|
5198
|
+
*/
|
|
5199
|
+
async function fetchAuthPostService(thoughtSpotHost, username, authToken) {
|
|
5200
|
+
return failureLoggedFetch(`${thoughtSpotHost}${EndPoints.TOKEN_LOGIN}`, {
|
|
5201
|
+
method: 'POST',
|
|
5202
|
+
headers: {
|
|
5203
|
+
'content-type': 'application/x-www-form-urlencoded',
|
|
5204
|
+
'x-requested-by': 'ThoughtSpot',
|
|
5200
5205
|
},
|
|
5201
|
-
|
|
5206
|
+
body: `username=${encodeURIComponent(username)}&auth_token=${encodeURIComponent(authToken)}`,
|
|
5207
|
+
credentials: 'include',
|
|
5208
|
+
// We do not want to follow the redirect, as it starts giving a CORS
|
|
5209
|
+
// error
|
|
5210
|
+
redirect: 'manual',
|
|
5211
|
+
});
|
|
5212
|
+
}
|
|
5213
|
+
/**
|
|
5214
|
+
*
|
|
5215
|
+
* @param thoughtSpotHost
|
|
5216
|
+
* @param username
|
|
5217
|
+
* @param password
|
|
5218
|
+
*/
|
|
5219
|
+
async function fetchBasicAuthService(thoughtSpotHost, username, password) {
|
|
5220
|
+
return failureLoggedFetch(`${thoughtSpotHost}${EndPoints.BASIC_LOGIN}`, {
|
|
5221
|
+
method: 'POST',
|
|
5222
|
+
headers: {
|
|
5223
|
+
'content-type': 'application/x-www-form-urlencoded',
|
|
5224
|
+
'x-requested-by': 'ThoughtSpot',
|
|
5225
|
+
},
|
|
5226
|
+
body: `username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}`,
|
|
5227
|
+
credentials: 'include',
|
|
5202
5228
|
});
|
|
5203
|
-
const souceDetails = details[0];
|
|
5204
|
-
if (souceDetails) {
|
|
5205
|
-
sourceDetailCache.set(sourceId, souceDetails);
|
|
5206
|
-
}
|
|
5207
|
-
return souceDetails;
|
|
5208
5229
|
}
|
|
5209
5230
|
|
|
5210
|
-
const
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5231
|
+
const DUPLICATE_TOKEN_ERR = 'Duplicate token, please issue a new token every time getAuthToken callback is called.'
|
|
5232
|
+
+ 'See https://developers.thoughtspot.com/docs/?pageid=embed-auth#trusted-auth-embed for more details.';
|
|
5233
|
+
const INVALID_TOKEN_ERR = 'Invalid token received form token callback or authToken endpoint.';
|
|
5234
|
+
let cachedAuthToken = null;
|
|
5235
|
+
// This method can be used to get the authToken using the embedConfig
|
|
5236
|
+
const getAuthenticationToken = async (embedConfig) => {
|
|
5237
|
+
if (cachedAuthToken) {
|
|
5238
|
+
try {
|
|
5239
|
+
const isCachedTokenStillValid = await validateAuthToken(embedConfig, cachedAuthToken);
|
|
5240
|
+
if (isCachedTokenStillValid)
|
|
5241
|
+
return cachedAuthToken;
|
|
5242
|
+
}
|
|
5243
|
+
catch {
|
|
5244
|
+
// Continue to get a new token if validation fails
|
|
5245
|
+
}
|
|
5246
|
+
}
|
|
5247
|
+
const { authEndpoint, getAuthToken } = embedConfig;
|
|
5248
|
+
let authToken = null;
|
|
5249
|
+
if (getAuthToken) {
|
|
5250
|
+
authToken = await getAuthToken();
|
|
5251
|
+
}
|
|
5252
|
+
else {
|
|
5253
|
+
const response = await fetchAuthTokenService(authEndpoint);
|
|
5254
|
+
authToken = await response.text();
|
|
5255
|
+
}
|
|
5256
|
+
// this will throw error if the token is not valid
|
|
5257
|
+
await validateAuthToken(embedConfig, authToken);
|
|
5258
|
+
cachedAuthToken = authToken;
|
|
5259
|
+
return authToken;
|
|
5260
|
+
};
|
|
5261
|
+
const validateAuthToken = async (embedConfig, authToken) => {
|
|
5262
|
+
try {
|
|
5263
|
+
const isTokenValid = await verifyTokenService(embedConfig.thoughtSpotHost, authToken);
|
|
5264
|
+
if (isTokenValid)
|
|
5265
|
+
return true;
|
|
5266
|
+
}
|
|
5267
|
+
catch {
|
|
5268
|
+
return false;
|
|
5269
|
+
}
|
|
5270
|
+
if (cachedAuthToken && cachedAuthToken === authToken) {
|
|
5271
|
+
if (!embedConfig.suppressErrorAlerts) {
|
|
5272
|
+
// eslint-disable-next-line no-alert
|
|
5273
|
+
alert(DUPLICATE_TOKEN_ERR);
|
|
5274
|
+
}
|
|
5275
|
+
throw new Error(DUPLICATE_TOKEN_ERR);
|
|
5276
|
+
}
|
|
5277
|
+
else {
|
|
5278
|
+
throw new Error(INVALID_TOKEN_ERR);
|
|
5279
|
+
}
|
|
5280
|
+
};
|
|
5281
|
+
|
|
5282
|
+
var eventemitter3 = createCommonjsModule(function (module) {
|
|
5283
|
+
|
|
5284
|
+
var has = Object.prototype.hasOwnProperty
|
|
5285
|
+
, prefix = '~';
|
|
5286
|
+
|
|
5287
|
+
/**
|
|
5288
|
+
* Constructor to create a storage for our `EE` objects.
|
|
5289
|
+
* An `Events` instance is a plain object whose properties are event names.
|
|
5290
|
+
*
|
|
5291
|
+
* @constructor
|
|
5292
|
+
* @private
|
|
5293
|
+
*/
|
|
5294
|
+
function Events() {}
|
|
5295
|
+
|
|
5296
|
+
//
|
|
5297
|
+
// We try to not inherit from `Object.prototype`. In some engines creating an
|
|
5298
|
+
// instance in this way is faster than calling `Object.create(null)` directly.
|
|
5299
|
+
// If `Object.create(null)` is not supported we prefix the event names with a
|
|
5300
|
+
// character to make sure that the built-in object properties are not
|
|
5301
|
+
// overridden or used as an attack vector.
|
|
5302
|
+
//
|
|
5303
|
+
if (Object.create) {
|
|
5304
|
+
Events.prototype = Object.create(null);
|
|
5305
|
+
|
|
5306
|
+
//
|
|
5307
|
+
// This hack is needed because the `__proto__` property is still inherited in
|
|
5308
|
+
// some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.
|
|
5309
|
+
//
|
|
5310
|
+
if (!new Events().__proto__) prefix = false;
|
|
5218
5311
|
}
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
displayName
|
|
5234
|
-
}
|
|
5235
|
-
}
|
|
5236
|
-
}
|
|
5237
|
-
}
|
|
5238
|
-
}
|
|
5239
|
-
}
|
|
5240
|
-
}
|
|
5241
|
-
}
|
|
5242
|
-
`;
|
|
5243
|
-
const removeColumns = `
|
|
5244
|
-
mutation RemoveColumns($session: BachSessionIdInput!, $logicalColumnIds: [GUID!], $columnIds: [GUID!]) {
|
|
5245
|
-
Answer__removeColumns(
|
|
5246
|
-
session: $session
|
|
5247
|
-
logicalColumnIds: $logicalColumnIds
|
|
5248
|
-
columnIds: $columnIds
|
|
5249
|
-
) {
|
|
5250
|
-
${bachSessionId}
|
|
5251
|
-
}
|
|
5312
|
+
|
|
5313
|
+
/**
|
|
5314
|
+
* Representation of a single event listener.
|
|
5315
|
+
*
|
|
5316
|
+
* @param {Function} fn The listener function.
|
|
5317
|
+
* @param {*} context The context to invoke the listener with.
|
|
5318
|
+
* @param {Boolean} [once=false] Specify if the listener is a one-time listener.
|
|
5319
|
+
* @constructor
|
|
5320
|
+
* @private
|
|
5321
|
+
*/
|
|
5322
|
+
function EE(fn, context, once) {
|
|
5323
|
+
this.fn = fn;
|
|
5324
|
+
this.context = context;
|
|
5325
|
+
this.once = once || false;
|
|
5252
5326
|
}
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5327
|
+
|
|
5328
|
+
/**
|
|
5329
|
+
* Add a listener for a given event.
|
|
5330
|
+
*
|
|
5331
|
+
* @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
|
|
5332
|
+
* @param {(String|Symbol)} event The event name.
|
|
5333
|
+
* @param {Function} fn The listener function.
|
|
5334
|
+
* @param {*} context The context to invoke the listener with.
|
|
5335
|
+
* @param {Boolean} once Specify if the listener is a one-time listener.
|
|
5336
|
+
* @returns {EventEmitter}
|
|
5337
|
+
* @private
|
|
5338
|
+
*/
|
|
5339
|
+
function addListener(emitter, event, fn, context, once) {
|
|
5340
|
+
if (typeof fn !== 'function') {
|
|
5341
|
+
throw new TypeError('The listener must be a function');
|
|
5342
|
+
}
|
|
5343
|
+
|
|
5344
|
+
var listener = new EE(fn, context || emitter, once)
|
|
5345
|
+
, evt = prefix ? prefix + event : event;
|
|
5346
|
+
|
|
5347
|
+
if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
|
|
5348
|
+
else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
|
|
5349
|
+
else emitter._events[evt] = [emitter._events[evt], listener];
|
|
5350
|
+
|
|
5351
|
+
return emitter;
|
|
5352
|
+
}
|
|
5353
|
+
|
|
5354
|
+
/**
|
|
5355
|
+
* Clear event by name.
|
|
5356
|
+
*
|
|
5357
|
+
* @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
|
|
5358
|
+
* @param {(String|Symbol)} evt The Event name.
|
|
5359
|
+
* @private
|
|
5360
|
+
*/
|
|
5361
|
+
function clearEvent(emitter, evt) {
|
|
5362
|
+
if (--emitter._eventsCount === 0) emitter._events = new Events();
|
|
5363
|
+
else delete emitter._events[evt];
|
|
5364
|
+
}
|
|
5365
|
+
|
|
5366
|
+
/**
|
|
5367
|
+
* Minimal `EventEmitter` interface that is molded against the Node.js
|
|
5368
|
+
* `EventEmitter` interface.
|
|
5369
|
+
*
|
|
5370
|
+
* @constructor
|
|
5371
|
+
* @public
|
|
5372
|
+
*/
|
|
5373
|
+
function EventEmitter() {
|
|
5374
|
+
this._events = new Events();
|
|
5375
|
+
this._eventsCount = 0;
|
|
5376
|
+
}
|
|
5377
|
+
|
|
5378
|
+
/**
|
|
5379
|
+
* Return an array listing the events for which the emitter has registered
|
|
5380
|
+
* listeners.
|
|
5381
|
+
*
|
|
5382
|
+
* @returns {Array}
|
|
5383
|
+
* @public
|
|
5384
|
+
*/
|
|
5385
|
+
EventEmitter.prototype.eventNames = function eventNames() {
|
|
5386
|
+
var names = []
|
|
5387
|
+
, events
|
|
5388
|
+
, name;
|
|
5389
|
+
|
|
5390
|
+
if (this._eventsCount === 0) return names;
|
|
5391
|
+
|
|
5392
|
+
for (name in (events = this._events)) {
|
|
5393
|
+
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
|
|
5394
|
+
}
|
|
5395
|
+
|
|
5396
|
+
if (Object.getOwnPropertySymbols) {
|
|
5397
|
+
return names.concat(Object.getOwnPropertySymbols(events));
|
|
5398
|
+
}
|
|
5399
|
+
|
|
5400
|
+
return names;
|
|
5401
|
+
};
|
|
5402
|
+
|
|
5403
|
+
/**
|
|
5404
|
+
* Return the listeners registered for a given event.
|
|
5405
|
+
*
|
|
5406
|
+
* @param {(String|Symbol)} event The event name.
|
|
5407
|
+
* @returns {Array} The registered listeners.
|
|
5408
|
+
* @public
|
|
5409
|
+
*/
|
|
5410
|
+
EventEmitter.prototype.listeners = function listeners(event) {
|
|
5411
|
+
var evt = prefix ? prefix + event : event
|
|
5412
|
+
, handlers = this._events[evt];
|
|
5413
|
+
|
|
5414
|
+
if (!handlers) return [];
|
|
5415
|
+
if (handlers.fn) return [handlers.fn];
|
|
5416
|
+
|
|
5417
|
+
for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
|
|
5418
|
+
ee[i] = handlers[i].fn;
|
|
5419
|
+
}
|
|
5420
|
+
|
|
5421
|
+
return ee;
|
|
5422
|
+
};
|
|
5423
|
+
|
|
5424
|
+
/**
|
|
5425
|
+
* Return the number of listeners listening to a given event.
|
|
5426
|
+
*
|
|
5427
|
+
* @param {(String|Symbol)} event The event name.
|
|
5428
|
+
* @returns {Number} The number of listeners.
|
|
5429
|
+
* @public
|
|
5430
|
+
*/
|
|
5431
|
+
EventEmitter.prototype.listenerCount = function listenerCount(event) {
|
|
5432
|
+
var evt = prefix ? prefix + event : event
|
|
5433
|
+
, listeners = this._events[evt];
|
|
5434
|
+
|
|
5435
|
+
if (!listeners) return 0;
|
|
5436
|
+
if (listeners.fn) return 1;
|
|
5437
|
+
return listeners.length;
|
|
5438
|
+
};
|
|
5439
|
+
|
|
5440
|
+
/**
|
|
5441
|
+
* Calls each of the listeners registered for a given event.
|
|
5442
|
+
*
|
|
5443
|
+
* @param {(String|Symbol)} event The event name.
|
|
5444
|
+
* @returns {Boolean} `true` if the event had listeners, else `false`.
|
|
5445
|
+
* @public
|
|
5446
|
+
*/
|
|
5447
|
+
EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
|
|
5448
|
+
var evt = prefix ? prefix + event : event;
|
|
5449
|
+
|
|
5450
|
+
if (!this._events[evt]) return false;
|
|
5451
|
+
|
|
5452
|
+
var listeners = this._events[evt]
|
|
5453
|
+
, len = arguments.length
|
|
5454
|
+
, args
|
|
5455
|
+
, i;
|
|
5456
|
+
|
|
5457
|
+
if (listeners.fn) {
|
|
5458
|
+
if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);
|
|
5459
|
+
|
|
5460
|
+
switch (len) {
|
|
5461
|
+
case 1: return listeners.fn.call(listeners.context), true;
|
|
5462
|
+
case 2: return listeners.fn.call(listeners.context, a1), true;
|
|
5463
|
+
case 3: return listeners.fn.call(listeners.context, a1, a2), true;
|
|
5464
|
+
case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;
|
|
5465
|
+
case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
|
|
5466
|
+
case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
|
|
5259
5467
|
}
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
getAnswer(session: $session) {
|
|
5264
|
-
${bachSessionId}
|
|
5265
|
-
answer {
|
|
5266
|
-
id
|
|
5267
|
-
visualizations {
|
|
5268
|
-
id
|
|
5269
|
-
... on TableViz {
|
|
5270
|
-
columns {
|
|
5271
|
-
column {
|
|
5272
|
-
id
|
|
5273
|
-
name
|
|
5274
|
-
type
|
|
5275
|
-
aggregationType
|
|
5276
|
-
dataType
|
|
5277
|
-
}
|
|
5278
|
-
}
|
|
5279
|
-
data(deadline: $deadline, pagination: $dataPaginationParams)
|
|
5280
|
-
}
|
|
5281
|
-
}
|
|
5282
|
-
}
|
|
5283
|
-
}
|
|
5468
|
+
|
|
5469
|
+
for (i = 1, args = new Array(len -1); i < len; i++) {
|
|
5470
|
+
args[i - 1] = arguments[i];
|
|
5284
5471
|
}
|
|
5285
|
-
`;
|
|
5286
5472
|
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
*
|
|
5442
|
-
*
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
* @param colVal
|
|
5449
|
-
*/
|
|
5450
|
-
function addPointFromColVal(colVal) {
|
|
5451
|
-
var _a;
|
|
5452
|
-
const dataType = colVal.column.dataType;
|
|
5453
|
-
const id = colVal.column.id;
|
|
5454
|
-
let dataValue;
|
|
5455
|
-
if (dataType === 'DATE') {
|
|
5456
|
-
if (Number.isFinite(colVal.value)) {
|
|
5457
|
-
dataValue = [{
|
|
5458
|
-
epochRange: {
|
|
5459
|
-
startEpoch: colVal.value,
|
|
5460
|
-
},
|
|
5461
|
-
}];
|
|
5462
|
-
// Case for custom calendar.
|
|
5463
|
-
}
|
|
5464
|
-
else if ((_a = colVal.value) === null || _a === void 0 ? void 0 : _a.v) {
|
|
5465
|
-
dataValue = [{
|
|
5466
|
-
epochRange: {
|
|
5467
|
-
startEpoch: colVal.value.v.s,
|
|
5468
|
-
endEpoch: colVal.value.v.e,
|
|
5469
|
-
},
|
|
5470
|
-
}];
|
|
5471
|
-
}
|
|
5472
|
-
}
|
|
5473
|
-
else {
|
|
5474
|
-
dataValue = [{ value: colVal.value }];
|
|
5475
|
-
}
|
|
5476
|
-
underlyingDataPoint.push({
|
|
5477
|
-
columnId: colVal.column.id,
|
|
5478
|
-
dataValue,
|
|
5479
|
-
});
|
|
5480
|
-
}
|
|
5481
|
-
selectedPoints.forEach((p) => {
|
|
5482
|
-
p.selectedAttributes.forEach(addPointFromColVal);
|
|
5483
|
-
});
|
|
5484
|
-
return underlyingDataPoint;
|
|
5473
|
+
listeners.fn.apply(listeners.context, args);
|
|
5474
|
+
} else {
|
|
5475
|
+
var length = listeners.length
|
|
5476
|
+
, j;
|
|
5477
|
+
|
|
5478
|
+
for (i = 0; i < length; i++) {
|
|
5479
|
+
if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);
|
|
5480
|
+
|
|
5481
|
+
switch (len) {
|
|
5482
|
+
case 1: listeners[i].fn.call(listeners[i].context); break;
|
|
5483
|
+
case 2: listeners[i].fn.call(listeners[i].context, a1); break;
|
|
5484
|
+
case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;
|
|
5485
|
+
case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;
|
|
5486
|
+
default:
|
|
5487
|
+
if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {
|
|
5488
|
+
args[j - 1] = arguments[j];
|
|
5489
|
+
}
|
|
5490
|
+
|
|
5491
|
+
listeners[i].fn.apply(listeners[i].context, args);
|
|
5492
|
+
}
|
|
5493
|
+
}
|
|
5494
|
+
}
|
|
5495
|
+
|
|
5496
|
+
return true;
|
|
5497
|
+
};
|
|
5498
|
+
|
|
5499
|
+
/**
|
|
5500
|
+
* Add a listener for a given event.
|
|
5501
|
+
*
|
|
5502
|
+
* @param {(String|Symbol)} event The event name.
|
|
5503
|
+
* @param {Function} fn The listener function.
|
|
5504
|
+
* @param {*} [context=this] The context to invoke the listener with.
|
|
5505
|
+
* @returns {EventEmitter} `this`.
|
|
5506
|
+
* @public
|
|
5507
|
+
*/
|
|
5508
|
+
EventEmitter.prototype.on = function on(event, fn, context) {
|
|
5509
|
+
return addListener(this, event, fn, context, false);
|
|
5510
|
+
};
|
|
5511
|
+
|
|
5512
|
+
/**
|
|
5513
|
+
* Add a one-time listener for a given event.
|
|
5514
|
+
*
|
|
5515
|
+
* @param {(String|Symbol)} event The event name.
|
|
5516
|
+
* @param {Function} fn The listener function.
|
|
5517
|
+
* @param {*} [context=this] The context to invoke the listener with.
|
|
5518
|
+
* @returns {EventEmitter} `this`.
|
|
5519
|
+
* @public
|
|
5520
|
+
*/
|
|
5521
|
+
EventEmitter.prototype.once = function once(event, fn, context) {
|
|
5522
|
+
return addListener(this, event, fn, context, true);
|
|
5523
|
+
};
|
|
5524
|
+
|
|
5525
|
+
/**
|
|
5526
|
+
* Remove the listeners of a given event.
|
|
5527
|
+
*
|
|
5528
|
+
* @param {(String|Symbol)} event The event name.
|
|
5529
|
+
* @param {Function} fn Only remove the listeners that match this function.
|
|
5530
|
+
* @param {*} context Only remove the listeners that have this context.
|
|
5531
|
+
* @param {Boolean} once Only remove one-time listeners.
|
|
5532
|
+
* @returns {EventEmitter} `this`.
|
|
5533
|
+
* @public
|
|
5534
|
+
*/
|
|
5535
|
+
EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
|
|
5536
|
+
var evt = prefix ? prefix + event : event;
|
|
5537
|
+
|
|
5538
|
+
if (!this._events[evt]) return this;
|
|
5539
|
+
if (!fn) {
|
|
5540
|
+
clearEvent(this, evt);
|
|
5541
|
+
return this;
|
|
5542
|
+
}
|
|
5543
|
+
|
|
5544
|
+
var listeners = this._events[evt];
|
|
5545
|
+
|
|
5546
|
+
if (listeners.fn) {
|
|
5547
|
+
if (
|
|
5548
|
+
listeners.fn === fn &&
|
|
5549
|
+
(!once || listeners.once) &&
|
|
5550
|
+
(!context || listeners.context === context)
|
|
5551
|
+
) {
|
|
5552
|
+
clearEvent(this, evt);
|
|
5553
|
+
}
|
|
5554
|
+
} else {
|
|
5555
|
+
for (var i = 0, events = [], length = listeners.length; i < length; i++) {
|
|
5556
|
+
if (
|
|
5557
|
+
listeners[i].fn !== fn ||
|
|
5558
|
+
(once && !listeners[i].once) ||
|
|
5559
|
+
(context && listeners[i].context !== context)
|
|
5560
|
+
) {
|
|
5561
|
+
events.push(listeners[i]);
|
|
5562
|
+
}
|
|
5563
|
+
}
|
|
5564
|
+
|
|
5565
|
+
//
|
|
5566
|
+
// Reset the array, or remove it completely if we have no more listeners.
|
|
5567
|
+
//
|
|
5568
|
+
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
|
|
5569
|
+
else clearEvent(this, evt);
|
|
5570
|
+
}
|
|
5571
|
+
|
|
5572
|
+
return this;
|
|
5573
|
+
};
|
|
5574
|
+
|
|
5575
|
+
/**
|
|
5576
|
+
* Remove all listeners, or those of the specified event.
|
|
5577
|
+
*
|
|
5578
|
+
* @param {(String|Symbol)} [event] The event name.
|
|
5579
|
+
* @returns {EventEmitter} `this`.
|
|
5580
|
+
* @public
|
|
5581
|
+
*/
|
|
5582
|
+
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
|
|
5583
|
+
var evt;
|
|
5584
|
+
|
|
5585
|
+
if (event) {
|
|
5586
|
+
evt = prefix ? prefix + event : event;
|
|
5587
|
+
if (this._events[evt]) clearEvent(this, evt);
|
|
5588
|
+
} else {
|
|
5589
|
+
this._events = new Events();
|
|
5590
|
+
this._eventsCount = 0;
|
|
5591
|
+
}
|
|
5592
|
+
|
|
5593
|
+
return this;
|
|
5594
|
+
};
|
|
5595
|
+
|
|
5596
|
+
//
|
|
5597
|
+
// Alias methods names because people roll like that.
|
|
5598
|
+
//
|
|
5599
|
+
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
|
5600
|
+
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
|
|
5601
|
+
|
|
5602
|
+
//
|
|
5603
|
+
// Expose the prefix.
|
|
5604
|
+
//
|
|
5605
|
+
EventEmitter.prefixed = prefix;
|
|
5606
|
+
|
|
5607
|
+
//
|
|
5608
|
+
// Allow `EventEmitter` to be imported as module namespace.
|
|
5609
|
+
//
|
|
5610
|
+
EventEmitter.EventEmitter = EventEmitter;
|
|
5611
|
+
|
|
5612
|
+
//
|
|
5613
|
+
// Expose the module.
|
|
5614
|
+
//
|
|
5615
|
+
{
|
|
5616
|
+
module.exports = EventEmitter;
|
|
5617
|
+
}
|
|
5618
|
+
});
|
|
5619
|
+
|
|
5620
|
+
/**
|
|
5621
|
+
* This method returns `undefined`.
|
|
5622
|
+
*
|
|
5623
|
+
* @static
|
|
5624
|
+
* @memberOf _
|
|
5625
|
+
* @since 2.3.0
|
|
5626
|
+
* @category Util
|
|
5627
|
+
* @example
|
|
5628
|
+
*
|
|
5629
|
+
* _.times(2, _.noop);
|
|
5630
|
+
* // => [undefined, undefined]
|
|
5631
|
+
*/
|
|
5632
|
+
function noop() {
|
|
5633
|
+
// No operation performed.
|
|
5485
5634
|
}
|
|
5486
5635
|
|
|
5636
|
+
var noop_1 = noop;
|
|
5637
|
+
|
|
5638
|
+
/** Used as references for various `Number` constants. */
|
|
5639
|
+
var INFINITY = 1 / 0;
|
|
5640
|
+
|
|
5641
|
+
/**
|
|
5642
|
+
* Creates a set object of `values`.
|
|
5643
|
+
*
|
|
5644
|
+
* @private
|
|
5645
|
+
* @param {Array} values The values to add to the set.
|
|
5646
|
+
* @returns {Object} Returns the new set.
|
|
5647
|
+
*/
|
|
5648
|
+
var createSet = !(_Set && (1 / _setToArray(new _Set([,-0]))[1]) == INFINITY) ? noop_1 : function(values) {
|
|
5649
|
+
return new _Set(values);
|
|
5650
|
+
};
|
|
5651
|
+
|
|
5487
5652
|
const ERROR_MESSAGE = {
|
|
5488
5653
|
INVALID_THOUGHTSPOT_HOST: 'Error parsing ThoughtSpot host. Please provide a valid URL.',
|
|
5489
5654
|
LIVEBOARD_VIZ_ID_VALIDATION: 'Please provide either liveboardId or pinboardId',
|
|
@@ -5514,6 +5679,9 @@ const urlRegex = new RegExp([
|
|
|
5514
5679
|
* @param config
|
|
5515
5680
|
*/
|
|
5516
5681
|
const getThoughtSpotHost = (config) => {
|
|
5682
|
+
if (!config.thoughtSpotHost) {
|
|
5683
|
+
throw new Error(ERROR_MESSAGE.INVALID_THOUGHTSPOT_HOST);
|
|
5684
|
+
}
|
|
5517
5685
|
const urlParts = config.thoughtSpotHost.match(urlRegex);
|
|
5518
5686
|
if (!urlParts) {
|
|
5519
5687
|
throw new Error(ERROR_MESSAGE.INVALID_THOUGHTSPOT_HOST);
|
|
@@ -10474,1611 +10642,1142 @@ MixpanelLib.prototype.remove_group = addOptOutCheckMixpanelLib(function(group_ke
|
|
|
10474
10642
|
* @param {Object=} groups An object mapping group name keys to one or more values
|
|
10475
10643
|
* @param {Function} [callback] If provided, the callback will be called after tracking the event.
|
|
10476
10644
|
*/
|
|
10477
|
-
MixpanelLib.prototype.track_with_groups = addOptOutCheckMixpanelLib(function(event_name, properties, groups, callback) {
|
|
10478
|
-
var tracking_props = _.extend({}, properties || {});
|
|
10479
|
-
_.each(groups, function(v, k) {
|
|
10480
|
-
if (v !== null && v !== undefined) {
|
|
10481
|
-
tracking_props[k] = v;
|
|
10482
|
-
}
|
|
10483
|
-
});
|
|
10484
|
-
return this.track(event_name, tracking_props, callback);
|
|
10485
|
-
});
|
|
10486
|
-
|
|
10487
|
-
MixpanelLib.prototype._create_map_key = function (group_key, group_id) {
|
|
10488
|
-
return group_key + '_' + JSON.stringify(group_id);
|
|
10489
|
-
};
|
|
10490
|
-
|
|
10491
|
-
MixpanelLib.prototype._remove_group_from_cache = function (group_key, group_id) {
|
|
10492
|
-
delete this._cached_groups[this._create_map_key(group_key, group_id)];
|
|
10493
|
-
};
|
|
10494
|
-
|
|
10495
|
-
/**
|
|
10496
|
-
* Look up reference to a Mixpanel group
|
|
10497
|
-
*
|
|
10498
|
-
* ### Usage:
|
|
10499
|
-
*
|
|
10500
|
-
* mixpanel.get_group(group_key, group_id)
|
|
10501
|
-
*
|
|
10502
|
-
* @param {String} group_key Group key
|
|
10503
|
-
* @param {Object} group_id A valid Mixpanel property type
|
|
10504
|
-
* @returns {Object} A MixpanelGroup identifier
|
|
10505
|
-
*/
|
|
10506
|
-
MixpanelLib.prototype.get_group = function (group_key, group_id) {
|
|
10507
|
-
var map_key = this._create_map_key(group_key, group_id);
|
|
10508
|
-
var group = this._cached_groups[map_key];
|
|
10509
|
-
if (group === undefined || group._group_key !== group_key || group._group_id !== group_id) {
|
|
10510
|
-
group = new MixpanelGroup();
|
|
10511
|
-
group._init(this, group_key, group_id);
|
|
10512
|
-
this._cached_groups[map_key] = group;
|
|
10513
|
-
}
|
|
10514
|
-
return group;
|
|
10515
|
-
};
|
|
10516
|
-
|
|
10517
|
-
/**
|
|
10518
|
-
* Track mp_page_view event. This is now ignored by the server.
|
|
10519
|
-
*
|
|
10520
|
-
* @param {String} [page] The url of the page to record. If you don't include this, it defaults to the current url.
|
|
10521
|
-
* @deprecated
|
|
10522
|
-
*/
|
|
10523
|
-
MixpanelLib.prototype.track_pageview = function(page) {
|
|
10524
|
-
if (_.isUndefined(page)) {
|
|
10525
|
-
page = document$1.location.href;
|
|
10526
|
-
}
|
|
10527
|
-
this.track('mp_page_view', _.info.pageviewInfo(page));
|
|
10528
|
-
};
|
|
10529
|
-
|
|
10530
|
-
/**
|
|
10531
|
-
* Track clicks on a set of document elements. Selector must be a
|
|
10532
|
-
* valid query. Elements must exist on the page at the time track_links is called.
|
|
10533
|
-
*
|
|
10534
|
-
* ### Usage:
|
|
10535
|
-
*
|
|
10536
|
-
* // track click for link id #nav
|
|
10537
|
-
* mixpanel.track_links('#nav', 'Clicked Nav Link');
|
|
10538
|
-
*
|
|
10539
|
-
* ### Notes:
|
|
10540
|
-
*
|
|
10541
|
-
* This function will wait up to 300 ms for the Mixpanel
|
|
10542
|
-
* servers to respond. If they have not responded by that time
|
|
10543
|
-
* it will head to the link without ensuring that your event
|
|
10544
|
-
* has been tracked. To configure this timeout please see the
|
|
10545
|
-
* set_config() documentation below.
|
|
10546
|
-
*
|
|
10547
|
-
* If you pass a function in as the properties argument, the
|
|
10548
|
-
* function will receive the DOMElement that triggered the
|
|
10549
|
-
* event as an argument. You are expected to return an object
|
|
10550
|
-
* from the function; any properties defined on this object
|
|
10551
|
-
* will be sent to mixpanel as event properties.
|
|
10552
|
-
*
|
|
10553
|
-
* @type {Function}
|
|
10554
|
-
* @param {Object|String} query A valid DOM query, element or jQuery-esque list
|
|
10555
|
-
* @param {String} event_name The name of the event to track
|
|
10556
|
-
* @param {Object|Function} [properties] A properties object or function that returns a dictionary of properties when passed a DOMElement
|
|
10557
|
-
*/
|
|
10558
|
-
MixpanelLib.prototype.track_links = function() {
|
|
10559
|
-
return this._track_dom.call(this, LinkTracker, arguments);
|
|
10560
|
-
};
|
|
10561
|
-
|
|
10562
|
-
/**
|
|
10563
|
-
* Track form submissions. Selector must be a valid query.
|
|
10564
|
-
*
|
|
10565
|
-
* ### Usage:
|
|
10566
|
-
*
|
|
10567
|
-
* // track submission for form id 'register'
|
|
10568
|
-
* mixpanel.track_forms('#register', 'Created Account');
|
|
10569
|
-
*
|
|
10570
|
-
* ### Notes:
|
|
10571
|
-
*
|
|
10572
|
-
* This function will wait up to 300 ms for the mixpanel
|
|
10573
|
-
* servers to respond, if they have not responded by that time
|
|
10574
|
-
* it will head to the link without ensuring that your event
|
|
10575
|
-
* has been tracked. To configure this timeout please see the
|
|
10576
|
-
* set_config() documentation below.
|
|
10577
|
-
*
|
|
10578
|
-
* If you pass a function in as the properties argument, the
|
|
10579
|
-
* function will receive the DOMElement that triggered the
|
|
10580
|
-
* event as an argument. You are expected to return an object
|
|
10581
|
-
* from the function; any properties defined on this object
|
|
10582
|
-
* will be sent to mixpanel as event properties.
|
|
10583
|
-
*
|
|
10584
|
-
* @type {Function}
|
|
10585
|
-
* @param {Object|String} query A valid DOM query, element or jQuery-esque list
|
|
10586
|
-
* @param {String} event_name The name of the event to track
|
|
10587
|
-
* @param {Object|Function} [properties] This can be a set of properties, or a function that returns a set of properties after being passed a DOMElement
|
|
10588
|
-
*/
|
|
10589
|
-
MixpanelLib.prototype.track_forms = function() {
|
|
10590
|
-
return this._track_dom.call(this, FormTracker, arguments);
|
|
10591
|
-
};
|
|
10592
|
-
|
|
10593
|
-
/**
|
|
10594
|
-
* Time an event by including the time between this call and a
|
|
10595
|
-
* later 'track' call for the same event in the properties sent
|
|
10596
|
-
* with the event.
|
|
10597
|
-
*
|
|
10598
|
-
* ### Usage:
|
|
10599
|
-
*
|
|
10600
|
-
* // time an event named 'Registered'
|
|
10601
|
-
* mixpanel.time_event('Registered');
|
|
10602
|
-
* mixpanel.track('Registered', {'Gender': 'Male', 'Age': 21});
|
|
10603
|
-
*
|
|
10604
|
-
* When called for a particular event name, the next track call for that event
|
|
10605
|
-
* name will include the elapsed time between the 'time_event' and 'track'
|
|
10606
|
-
* calls. This value is stored as seconds in the '$duration' property.
|
|
10607
|
-
*
|
|
10608
|
-
* @param {String} event_name The name of the event.
|
|
10609
|
-
*/
|
|
10610
|
-
MixpanelLib.prototype.time_event = function(event_name) {
|
|
10611
|
-
if (_.isUndefined(event_name)) {
|
|
10612
|
-
this.report_error('No event name provided to mixpanel.time_event');
|
|
10613
|
-
return;
|
|
10614
|
-
}
|
|
10615
|
-
|
|
10616
|
-
if (this._event_is_disabled(event_name)) {
|
|
10617
|
-
return;
|
|
10618
|
-
}
|
|
10619
|
-
|
|
10620
|
-
this['persistence'].set_event_timer(event_name, new Date().getTime());
|
|
10621
|
-
};
|
|
10622
|
-
|
|
10623
|
-
var REGISTER_DEFAULTS = {
|
|
10624
|
-
'persistent': true
|
|
10625
|
-
};
|
|
10626
|
-
/**
|
|
10627
|
-
* Helper to parse options param for register methods, maintaining
|
|
10628
|
-
* legacy support for plain "days" param instead of options object
|
|
10629
|
-
* @param {Number|Object} [days_or_options] 'days' option (Number), or Options object for register methods
|
|
10630
|
-
* @returns {Object} options object
|
|
10631
|
-
*/
|
|
10632
|
-
var options_for_register = function(days_or_options) {
|
|
10633
|
-
var options;
|
|
10634
|
-
if (_.isObject(days_or_options)) {
|
|
10635
|
-
options = days_or_options;
|
|
10636
|
-
} else if (!_.isUndefined(days_or_options)) {
|
|
10637
|
-
options = {'days': days_or_options};
|
|
10638
|
-
} else {
|
|
10639
|
-
options = {};
|
|
10640
|
-
}
|
|
10641
|
-
return _.extend({}, REGISTER_DEFAULTS, options);
|
|
10642
|
-
};
|
|
10643
|
-
|
|
10644
|
-
/**
|
|
10645
|
-
* Register a set of super properties, which are included with all
|
|
10646
|
-
* events. This will overwrite previous super property values.
|
|
10647
|
-
*
|
|
10648
|
-
* ### Usage:
|
|
10649
|
-
*
|
|
10650
|
-
* // register 'Gender' as a super property
|
|
10651
|
-
* mixpanel.register({'Gender': 'Female'});
|
|
10652
|
-
*
|
|
10653
|
-
* // register several super properties when a user signs up
|
|
10654
|
-
* mixpanel.register({
|
|
10655
|
-
* 'Email': 'jdoe@example.com',
|
|
10656
|
-
* 'Account Type': 'Free'
|
|
10657
|
-
* });
|
|
10658
|
-
*
|
|
10659
|
-
* // register only for the current pageload
|
|
10660
|
-
* mixpanel.register({'Name': 'Pat'}, {persistent: false});
|
|
10661
|
-
*
|
|
10662
|
-
* @param {Object} properties An associative array of properties to store about the user
|
|
10663
|
-
* @param {Number|Object} [days_or_options] Options object or number of days since the user's last visit to store the super properties (only valid for persisted props)
|
|
10664
|
-
* @param {boolean} [days_or_options.days] - number of days since the user's last visit to store the super properties (only valid for persisted props)
|
|
10665
|
-
* @param {boolean} [days_or_options.persistent=true] - whether to put in persistent storage (cookie/localStorage)
|
|
10666
|
-
*/
|
|
10667
|
-
MixpanelLib.prototype.register = function(props, days_or_options) {
|
|
10668
|
-
var options = options_for_register(days_or_options);
|
|
10669
|
-
if (options['persistent']) {
|
|
10670
|
-
this['persistence'].register(props, options['days']);
|
|
10671
|
-
} else {
|
|
10672
|
-
_.extend(this.unpersisted_superprops, props);
|
|
10673
|
-
}
|
|
10674
|
-
};
|
|
10675
|
-
|
|
10676
|
-
/**
|
|
10677
|
-
* Register a set of super properties only once. This will not
|
|
10678
|
-
* overwrite previous super property values, unlike register().
|
|
10679
|
-
*
|
|
10680
|
-
* ### Usage:
|
|
10681
|
-
*
|
|
10682
|
-
* // register a super property for the first time only
|
|
10683
|
-
* mixpanel.register_once({
|
|
10684
|
-
* 'First Login Date': new Date().toISOString()
|
|
10685
|
-
* });
|
|
10686
|
-
*
|
|
10687
|
-
* // register once, only for the current pageload
|
|
10688
|
-
* mixpanel.register_once({
|
|
10689
|
-
* 'First interaction time': new Date().toISOString()
|
|
10690
|
-
* }, 'None', {persistent: false});
|
|
10691
|
-
*
|
|
10692
|
-
* ### Notes:
|
|
10693
|
-
*
|
|
10694
|
-
* If default_value is specified, current super properties
|
|
10695
|
-
* with that value will be overwritten.
|
|
10696
|
-
*
|
|
10697
|
-
* @param {Object} properties An associative array of properties to store about the user
|
|
10698
|
-
* @param {*} [default_value] Value to override if already set in super properties (ex: 'False') Default: 'None'
|
|
10699
|
-
* @param {Number|Object} [days_or_options] Options object or number of days since the user's last visit to store the super properties (only valid for persisted props)
|
|
10700
|
-
* @param {boolean} [days_or_options.days] - number of days since the user's last visit to store the super properties (only valid for persisted props)
|
|
10701
|
-
* @param {boolean} [days_or_options.persistent=true] - whether to put in persistent storage (cookie/localStorage)
|
|
10702
|
-
*/
|
|
10703
|
-
MixpanelLib.prototype.register_once = function(props, default_value, days_or_options) {
|
|
10704
|
-
var options = options_for_register(days_or_options);
|
|
10705
|
-
if (options['persistent']) {
|
|
10706
|
-
this['persistence'].register_once(props, default_value, options['days']);
|
|
10707
|
-
} else {
|
|
10708
|
-
if (typeof(default_value) === 'undefined') {
|
|
10709
|
-
default_value = 'None';
|
|
10710
|
-
}
|
|
10711
|
-
_.each(props, function(val, prop) {
|
|
10712
|
-
if (!this.unpersisted_superprops.hasOwnProperty(prop) || this.unpersisted_superprops[prop] === default_value) {
|
|
10713
|
-
this.unpersisted_superprops[prop] = val;
|
|
10714
|
-
}
|
|
10715
|
-
}, this);
|
|
10716
|
-
}
|
|
10717
|
-
};
|
|
10718
|
-
|
|
10719
|
-
/**
|
|
10720
|
-
* Delete a super property stored with the current user.
|
|
10721
|
-
*
|
|
10722
|
-
* @param {String} property The name of the super property to remove
|
|
10723
|
-
* @param {Object} [options]
|
|
10724
|
-
* @param {boolean} [options.persistent=true] - whether to look in persistent storage (cookie/localStorage)
|
|
10725
|
-
*/
|
|
10726
|
-
MixpanelLib.prototype.unregister = function(property, options) {
|
|
10727
|
-
options = options_for_register(options);
|
|
10728
|
-
if (options['persistent']) {
|
|
10729
|
-
this['persistence'].unregister(property);
|
|
10730
|
-
} else {
|
|
10731
|
-
delete this.unpersisted_superprops[property];
|
|
10732
|
-
}
|
|
10645
|
+
MixpanelLib.prototype.track_with_groups = addOptOutCheckMixpanelLib(function(event_name, properties, groups, callback) {
|
|
10646
|
+
var tracking_props = _.extend({}, properties || {});
|
|
10647
|
+
_.each(groups, function(v, k) {
|
|
10648
|
+
if (v !== null && v !== undefined) {
|
|
10649
|
+
tracking_props[k] = v;
|
|
10650
|
+
}
|
|
10651
|
+
});
|
|
10652
|
+
return this.track(event_name, tracking_props, callback);
|
|
10653
|
+
});
|
|
10654
|
+
|
|
10655
|
+
MixpanelLib.prototype._create_map_key = function (group_key, group_id) {
|
|
10656
|
+
return group_key + '_' + JSON.stringify(group_id);
|
|
10733
10657
|
};
|
|
10734
10658
|
|
|
10735
|
-
MixpanelLib.prototype.
|
|
10736
|
-
|
|
10737
|
-
props[prop] = value;
|
|
10738
|
-
this.register(props);
|
|
10659
|
+
MixpanelLib.prototype._remove_group_from_cache = function (group_key, group_id) {
|
|
10660
|
+
delete this._cached_groups[this._create_map_key(group_key, group_id)];
|
|
10739
10661
|
};
|
|
10740
10662
|
|
|
10741
10663
|
/**
|
|
10742
|
-
*
|
|
10743
|
-
* devices, tie a user to their events, and create a user profile.
|
|
10744
|
-
* If you never call this method, unique visitors are tracked using
|
|
10745
|
-
* a UUID generated the first time they visit the site.
|
|
10746
|
-
*
|
|
10747
|
-
* Call identify when you know the identity of the current user,
|
|
10748
|
-
* typically after login or signup. We recommend against using
|
|
10749
|
-
* identify for anonymous visitors to your site.
|
|
10664
|
+
* Look up reference to a Mixpanel group
|
|
10750
10665
|
*
|
|
10751
|
-
* ###
|
|
10752
|
-
* If your project has
|
|
10753
|
-
* <a href="https://help.mixpanel.com/hc/en-us/articles/360039133851">ID Merge</a>
|
|
10754
|
-
* enabled, the identify method will connect pre- and
|
|
10755
|
-
* post-authentication events when appropriate.
|
|
10666
|
+
* ### Usage:
|
|
10756
10667
|
*
|
|
10757
|
-
*
|
|
10758
|
-
* change the user's local distinct_id to the unique ID you pass.
|
|
10759
|
-
* Events tracked prior to authentication will not be connected
|
|
10760
|
-
* to the same user identity. If ID Merge is disabled, alias can
|
|
10761
|
-
* be used to connect pre- and post-registration events.
|
|
10668
|
+
* mixpanel.get_group(group_key, group_id)
|
|
10762
10669
|
*
|
|
10763
|
-
* @param {String}
|
|
10670
|
+
* @param {String} group_key Group key
|
|
10671
|
+
* @param {Object} group_id A valid Mixpanel property type
|
|
10672
|
+
* @returns {Object} A MixpanelGroup identifier
|
|
10764
10673
|
*/
|
|
10765
|
-
MixpanelLib.prototype.
|
|
10766
|
-
|
|
10767
|
-
|
|
10768
|
-
|
|
10769
|
-
|
|
10770
|
-
|
|
10771
|
-
|
|
10772
|
-
// _set_once_callback:function A callback to be run if and when the People set_once queue is flushed
|
|
10773
|
-
// _union_callback:function A callback to be run if and when the People union queue is flushed
|
|
10774
|
-
// _unset_callback:function A callback to be run if and when the People unset queue is flushed
|
|
10775
|
-
|
|
10776
|
-
var previous_distinct_id = this.get_distinct_id();
|
|
10777
|
-
this.register({'$user_id': new_distinct_id});
|
|
10778
|
-
|
|
10779
|
-
if (!this.get_property('$device_id')) {
|
|
10780
|
-
// The persisted distinct id might not actually be a device id at all
|
|
10781
|
-
// it might be a distinct id of the user from before
|
|
10782
|
-
var device_id = previous_distinct_id;
|
|
10783
|
-
this.register_once({
|
|
10784
|
-
'$had_persisted_distinct_id': true,
|
|
10785
|
-
'$device_id': device_id
|
|
10786
|
-
}, '');
|
|
10787
|
-
}
|
|
10788
|
-
|
|
10789
|
-
// identify only changes the distinct id if it doesn't match either the existing or the alias;
|
|
10790
|
-
// if it's new, blow away the alias as well.
|
|
10791
|
-
if (new_distinct_id !== previous_distinct_id && new_distinct_id !== this.get_property(ALIAS_ID_KEY)) {
|
|
10792
|
-
this.unregister(ALIAS_ID_KEY);
|
|
10793
|
-
this.register({'distinct_id': new_distinct_id});
|
|
10794
|
-
}
|
|
10795
|
-
this._flags.identify_called = true;
|
|
10796
|
-
// Flush any queued up people requests
|
|
10797
|
-
this['people']._flush(_set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback);
|
|
10798
|
-
|
|
10799
|
-
// send an $identify event any time the distinct_id is changing - logic on the server
|
|
10800
|
-
// will determine whether or not to do anything with it.
|
|
10801
|
-
if (new_distinct_id !== previous_distinct_id) {
|
|
10802
|
-
this.track('$identify', {
|
|
10803
|
-
'distinct_id': new_distinct_id,
|
|
10804
|
-
'$anon_distinct_id': previous_distinct_id
|
|
10805
|
-
}, {skip_hooks: true});
|
|
10674
|
+
MixpanelLib.prototype.get_group = function (group_key, group_id) {
|
|
10675
|
+
var map_key = this._create_map_key(group_key, group_id);
|
|
10676
|
+
var group = this._cached_groups[map_key];
|
|
10677
|
+
if (group === undefined || group._group_key !== group_key || group._group_id !== group_id) {
|
|
10678
|
+
group = new MixpanelGroup();
|
|
10679
|
+
group._init(this, group_key, group_id);
|
|
10680
|
+
this._cached_groups[map_key] = group;
|
|
10806
10681
|
}
|
|
10682
|
+
return group;
|
|
10807
10683
|
};
|
|
10808
10684
|
|
|
10809
10685
|
/**
|
|
10810
|
-
*
|
|
10811
|
-
*
|
|
10686
|
+
* Track mp_page_view event. This is now ignored by the server.
|
|
10687
|
+
*
|
|
10688
|
+
* @param {String} [page] The url of the page to record. If you don't include this, it defaults to the current url.
|
|
10689
|
+
* @deprecated
|
|
10812
10690
|
*/
|
|
10813
|
-
MixpanelLib.prototype.
|
|
10814
|
-
|
|
10815
|
-
|
|
10816
|
-
|
|
10817
|
-
this.
|
|
10818
|
-
'distinct_id': uuid,
|
|
10819
|
-
'$device_id': uuid
|
|
10820
|
-
}, '');
|
|
10691
|
+
MixpanelLib.prototype.track_pageview = function(page) {
|
|
10692
|
+
if (_.isUndefined(page)) {
|
|
10693
|
+
page = document$1.location.href;
|
|
10694
|
+
}
|
|
10695
|
+
this.track('mp_page_view', _.info.pageviewInfo(page));
|
|
10821
10696
|
};
|
|
10822
10697
|
|
|
10823
10698
|
/**
|
|
10824
|
-
*
|
|
10825
|
-
*
|
|
10699
|
+
* Track clicks on a set of document elements. Selector must be a
|
|
10700
|
+
* valid query. Elements must exist on the page at the time track_links is called.
|
|
10701
|
+
*
|
|
10702
|
+
* ### Usage:
|
|
10703
|
+
*
|
|
10704
|
+
* // track click for link id #nav
|
|
10705
|
+
* mixpanel.track_links('#nav', 'Clicked Nav Link');
|
|
10826
10706
|
*
|
|
10827
10707
|
* ### Notes:
|
|
10828
10708
|
*
|
|
10829
|
-
*
|
|
10830
|
-
*
|
|
10709
|
+
* This function will wait up to 300 ms for the Mixpanel
|
|
10710
|
+
* servers to respond. If they have not responded by that time
|
|
10711
|
+
* it will head to the link without ensuring that your event
|
|
10712
|
+
* has been tracked. To configure this timeout please see the
|
|
10713
|
+
* set_config() documentation below.
|
|
10831
10714
|
*
|
|
10832
|
-
*
|
|
10833
|
-
*
|
|
10834
|
-
*
|
|
10835
|
-
*
|
|
10836
|
-
*
|
|
10837
|
-
*
|
|
10715
|
+
* If you pass a function in as the properties argument, the
|
|
10716
|
+
* function will receive the DOMElement that triggered the
|
|
10717
|
+
* event as an argument. You are expected to return an object
|
|
10718
|
+
* from the function; any properties defined on this object
|
|
10719
|
+
* will be sent to mixpanel as event properties.
|
|
10720
|
+
*
|
|
10721
|
+
* @type {Function}
|
|
10722
|
+
* @param {Object|String} query A valid DOM query, element or jQuery-esque list
|
|
10723
|
+
* @param {String} event_name The name of the event to track
|
|
10724
|
+
* @param {Object|Function} [properties] A properties object or function that returns a dictionary of properties when passed a DOMElement
|
|
10838
10725
|
*/
|
|
10839
|
-
MixpanelLib.prototype.
|
|
10840
|
-
return this.
|
|
10726
|
+
MixpanelLib.prototype.track_links = function() {
|
|
10727
|
+
return this._track_dom.call(this, LinkTracker, arguments);
|
|
10841
10728
|
};
|
|
10842
10729
|
|
|
10843
10730
|
/**
|
|
10844
|
-
*
|
|
10845
|
-
* remap one id to another. Multiple aliases can point to the
|
|
10846
|
-
* same identifier.
|
|
10731
|
+
* Track form submissions. Selector must be a valid query.
|
|
10847
10732
|
*
|
|
10848
|
-
*
|
|
10733
|
+
* ### Usage:
|
|
10849
10734
|
*
|
|
10850
|
-
*
|
|
10851
|
-
*
|
|
10852
|
-
* mixpanel.alias('newer_id', 'existing_id');
|
|
10735
|
+
* // track submission for form id 'register'
|
|
10736
|
+
* mixpanel.track_forms('#register', 'Created Account');
|
|
10853
10737
|
*
|
|
10854
|
-
*
|
|
10738
|
+
* ### Notes:
|
|
10855
10739
|
*
|
|
10856
|
-
*
|
|
10857
|
-
*
|
|
10858
|
-
*
|
|
10740
|
+
* This function will wait up to 300 ms for the mixpanel
|
|
10741
|
+
* servers to respond, if they have not responded by that time
|
|
10742
|
+
* it will head to the link without ensuring that your event
|
|
10743
|
+
* has been tracked. To configure this timeout please see the
|
|
10744
|
+
* set_config() documentation below.
|
|
10859
10745
|
*
|
|
10860
|
-
*
|
|
10861
|
-
*
|
|
10746
|
+
* If you pass a function in as the properties argument, the
|
|
10747
|
+
* function will receive the DOMElement that triggered the
|
|
10748
|
+
* event as an argument. You are expected to return an object
|
|
10749
|
+
* from the function; any properties defined on this object
|
|
10750
|
+
* will be sent to mixpanel as event properties.
|
|
10862
10751
|
*
|
|
10863
|
-
*
|
|
10864
|
-
*
|
|
10865
|
-
*
|
|
10752
|
+
* @type {Function}
|
|
10753
|
+
* @param {Object|String} query A valid DOM query, element or jQuery-esque list
|
|
10754
|
+
* @param {String} event_name The name of the event to track
|
|
10755
|
+
* @param {Object|Function} [properties] This can be a set of properties, or a function that returns a set of properties after being passed a DOMElement
|
|
10756
|
+
*/
|
|
10757
|
+
MixpanelLib.prototype.track_forms = function() {
|
|
10758
|
+
return this._track_dom.call(this, FormTracker, arguments);
|
|
10759
|
+
};
|
|
10760
|
+
|
|
10761
|
+
/**
|
|
10762
|
+
* Time an event by including the time between this call and a
|
|
10763
|
+
* later 'track' call for the same event in the properties sent
|
|
10764
|
+
* with the event.
|
|
10866
10765
|
*
|
|
10867
|
-
* ###
|
|
10766
|
+
* ### Usage:
|
|
10868
10767
|
*
|
|
10869
|
-
*
|
|
10870
|
-
*
|
|
10871
|
-
*
|
|
10872
|
-
* ID is first created for a user (e.g., when a user first registers
|
|
10873
|
-
* for an account). Do not use alias multiple times for a single
|
|
10874
|
-
* user without ID Merge enabled.
|
|
10768
|
+
* // time an event named 'Registered'
|
|
10769
|
+
* mixpanel.time_event('Registered');
|
|
10770
|
+
* mixpanel.track('Registered', {'Gender': 'Male', 'Age': 21});
|
|
10875
10771
|
*
|
|
10876
|
-
*
|
|
10877
|
-
*
|
|
10772
|
+
* When called for a particular event name, the next track call for that event
|
|
10773
|
+
* name will include the elapsed time between the 'time_event' and 'track'
|
|
10774
|
+
* calls. This value is stored as seconds in the '$duration' property.
|
|
10775
|
+
*
|
|
10776
|
+
* @param {String} event_name The name of the event.
|
|
10878
10777
|
*/
|
|
10879
|
-
MixpanelLib.prototype.
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
10883
|
-
if (alias === this.get_property(PEOPLE_DISTINCT_ID_KEY)) {
|
|
10884
|
-
this.report_error('Attempting to create alias for existing People user - aborting.');
|
|
10885
|
-
return -2;
|
|
10778
|
+
MixpanelLib.prototype.time_event = function(event_name) {
|
|
10779
|
+
if (_.isUndefined(event_name)) {
|
|
10780
|
+
this.report_error('No event name provided to mixpanel.time_event');
|
|
10781
|
+
return;
|
|
10886
10782
|
}
|
|
10887
10783
|
|
|
10888
|
-
|
|
10889
|
-
|
|
10890
|
-
original = this.get_distinct_id();
|
|
10784
|
+
if (this._event_is_disabled(event_name)) {
|
|
10785
|
+
return;
|
|
10891
10786
|
}
|
|
10892
|
-
|
|
10893
|
-
|
|
10894
|
-
|
|
10895
|
-
|
|
10896
|
-
|
|
10897
|
-
|
|
10898
|
-
|
|
10899
|
-
|
|
10900
|
-
|
|
10901
|
-
|
|
10902
|
-
|
|
10787
|
+
|
|
10788
|
+
this['persistence'].set_event_timer(event_name, new Date().getTime());
|
|
10789
|
+
};
|
|
10790
|
+
|
|
10791
|
+
var REGISTER_DEFAULTS = {
|
|
10792
|
+
'persistent': true
|
|
10793
|
+
};
|
|
10794
|
+
/**
|
|
10795
|
+
* Helper to parse options param for register methods, maintaining
|
|
10796
|
+
* legacy support for plain "days" param instead of options object
|
|
10797
|
+
* @param {Number|Object} [days_or_options] 'days' option (Number), or Options object for register methods
|
|
10798
|
+
* @returns {Object} options object
|
|
10799
|
+
*/
|
|
10800
|
+
var options_for_register = function(days_or_options) {
|
|
10801
|
+
var options;
|
|
10802
|
+
if (_.isObject(days_or_options)) {
|
|
10803
|
+
options = days_or_options;
|
|
10804
|
+
} else if (!_.isUndefined(days_or_options)) {
|
|
10805
|
+
options = {'days': days_or_options};
|
|
10903
10806
|
} else {
|
|
10904
|
-
|
|
10905
|
-
this.identify(alias);
|
|
10906
|
-
return -1;
|
|
10807
|
+
options = {};
|
|
10907
10808
|
}
|
|
10809
|
+
return _.extend({}, REGISTER_DEFAULTS, options);
|
|
10908
10810
|
};
|
|
10909
10811
|
|
|
10910
10812
|
/**
|
|
10911
|
-
*
|
|
10912
|
-
*
|
|
10913
|
-
* than an automatically generated name. Name tags do not have to
|
|
10914
|
-
* be unique.
|
|
10813
|
+
* Register a set of super properties, which are included with all
|
|
10814
|
+
* events. This will overwrite previous super property values.
|
|
10915
10815
|
*
|
|
10916
|
-
*
|
|
10816
|
+
* ### Usage:
|
|
10917
10817
|
*
|
|
10918
|
-
*
|
|
10919
|
-
*
|
|
10818
|
+
* // register 'Gender' as a super property
|
|
10819
|
+
* mixpanel.register({'Gender': 'Female'});
|
|
10820
|
+
*
|
|
10821
|
+
* // register several super properties when a user signs up
|
|
10822
|
+
* mixpanel.register({
|
|
10823
|
+
* 'Email': 'jdoe@example.com',
|
|
10824
|
+
* 'Account Type': 'Free'
|
|
10825
|
+
* });
|
|
10826
|
+
*
|
|
10827
|
+
* // register only for the current pageload
|
|
10828
|
+
* mixpanel.register({'Name': 'Pat'}, {persistent: false});
|
|
10829
|
+
*
|
|
10830
|
+
* @param {Object} properties An associative array of properties to store about the user
|
|
10831
|
+
* @param {Number|Object} [days_or_options] Options object or number of days since the user's last visit to store the super properties (only valid for persisted props)
|
|
10832
|
+
* @param {boolean} [days_or_options.days] - number of days since the user's last visit to store the super properties (only valid for persisted props)
|
|
10833
|
+
* @param {boolean} [days_or_options.persistent=true] - whether to put in persistent storage (cookie/localStorage)
|
|
10920
10834
|
*/
|
|
10921
|
-
MixpanelLib.prototype.
|
|
10922
|
-
|
|
10835
|
+
MixpanelLib.prototype.register = function(props, days_or_options) {
|
|
10836
|
+
var options = options_for_register(days_or_options);
|
|
10837
|
+
if (options['persistent']) {
|
|
10838
|
+
this['persistence'].register(props, options['days']);
|
|
10839
|
+
} else {
|
|
10840
|
+
_.extend(this.unpersisted_superprops, props);
|
|
10841
|
+
}
|
|
10923
10842
|
};
|
|
10924
10843
|
|
|
10925
10844
|
/**
|
|
10926
|
-
*
|
|
10927
|
-
*
|
|
10928
|
-
* The default config is:
|
|
10929
|
-
*
|
|
10930
|
-
* {
|
|
10931
|
-
* // HTTP method for tracking requests
|
|
10932
|
-
* api_method: 'POST'
|
|
10933
|
-
*
|
|
10934
|
-
* // transport for sending requests ('XHR' or 'sendBeacon')
|
|
10935
|
-
* // NB: sendBeacon should only be used for scenarios such as
|
|
10936
|
-
* // page unload where a "best-effort" attempt to send is
|
|
10937
|
-
* // acceptable; the sendBeacon API does not support callbacks
|
|
10938
|
-
* // or any way to know the result of the request. Mixpanel
|
|
10939
|
-
* // tracking via sendBeacon will not support any event-
|
|
10940
|
-
* // batching or retry mechanisms.
|
|
10941
|
-
* api_transport: 'XHR'
|
|
10942
|
-
*
|
|
10943
|
-
* // turn on request-batching/queueing/retry
|
|
10944
|
-
* batch_requests: false,
|
|
10945
|
-
*
|
|
10946
|
-
* // maximum number of events/updates to send in a single
|
|
10947
|
-
* // network request
|
|
10948
|
-
* batch_size: 50,
|
|
10949
|
-
*
|
|
10950
|
-
* // milliseconds to wait between sending batch requests
|
|
10951
|
-
* batch_flush_interval_ms: 5000,
|
|
10952
|
-
*
|
|
10953
|
-
* // milliseconds to wait for network responses to batch requests
|
|
10954
|
-
* // before they are considered timed-out and retried
|
|
10955
|
-
* batch_request_timeout_ms: 90000,
|
|
10956
|
-
*
|
|
10957
|
-
* // override value for cookie domain, only useful for ensuring
|
|
10958
|
-
* // correct cross-subdomain cookies on unusual domains like
|
|
10959
|
-
* // subdomain.mainsite.avocat.fr; NB this cannot be used to
|
|
10960
|
-
* // set cookies on a different domain than the current origin
|
|
10961
|
-
* cookie_domain: ''
|
|
10962
|
-
*
|
|
10963
|
-
* // super properties cookie expiration (in days)
|
|
10964
|
-
* cookie_expiration: 365
|
|
10965
|
-
*
|
|
10966
|
-
* // if true, cookie will be set with SameSite=None; Secure
|
|
10967
|
-
* // this is only useful in special situations, like embedded
|
|
10968
|
-
* // 3rd-party iframes that set up a Mixpanel instance
|
|
10969
|
-
* cross_site_cookie: false
|
|
10970
|
-
*
|
|
10971
|
-
* // super properties span subdomains
|
|
10972
|
-
* cross_subdomain_cookie: true
|
|
10973
|
-
*
|
|
10974
|
-
* // debug mode
|
|
10975
|
-
* debug: false
|
|
10976
|
-
*
|
|
10977
|
-
* // if this is true, the mixpanel cookie or localStorage entry
|
|
10978
|
-
* // will be deleted, and no user persistence will take place
|
|
10979
|
-
* disable_persistence: false
|
|
10980
|
-
*
|
|
10981
|
-
* // if this is true, Mixpanel will automatically determine
|
|
10982
|
-
* // City, Region and Country data using the IP address of
|
|
10983
|
-
* //the client
|
|
10984
|
-
* ip: true
|
|
10985
|
-
*
|
|
10986
|
-
* // opt users out of tracking by this Mixpanel instance by default
|
|
10987
|
-
* opt_out_tracking_by_default: false
|
|
10988
|
-
*
|
|
10989
|
-
* // opt users out of browser data storage by this Mixpanel instance by default
|
|
10990
|
-
* opt_out_persistence_by_default: false
|
|
10991
|
-
*
|
|
10992
|
-
* // persistence mechanism used by opt-in/opt-out methods - cookie
|
|
10993
|
-
* // or localStorage - falls back to cookie if localStorage is unavailable
|
|
10994
|
-
* opt_out_tracking_persistence_type: 'localStorage'
|
|
10845
|
+
* Register a set of super properties only once. This will not
|
|
10846
|
+
* overwrite previous super property values, unlike register().
|
|
10995
10847
|
*
|
|
10996
|
-
*
|
|
10997
|
-
* opt_out_tracking_cookie_prefix: null
|
|
10848
|
+
* ### Usage:
|
|
10998
10849
|
*
|
|
10999
|
-
*
|
|
11000
|
-
*
|
|
11001
|
-
*
|
|
11002
|
-
*
|
|
11003
|
-
* persistence: 'cookie'
|
|
10850
|
+
* // register a super property for the first time only
|
|
10851
|
+
* mixpanel.register_once({
|
|
10852
|
+
* 'First Login Date': new Date().toISOString()
|
|
10853
|
+
* });
|
|
11004
10854
|
*
|
|
11005
|
-
*
|
|
11006
|
-
*
|
|
10855
|
+
* // register once, only for the current pageload
|
|
10856
|
+
* mixpanel.register_once({
|
|
10857
|
+
* 'First interaction time': new Date().toISOString()
|
|
10858
|
+
* }, 'None', {persistent: false});
|
|
11007
10859
|
*
|
|
11008
|
-
*
|
|
11009
|
-
* // be sent with track() calls
|
|
11010
|
-
* property_blacklist: []
|
|
10860
|
+
* ### Notes:
|
|
11011
10861
|
*
|
|
11012
|
-
*
|
|
11013
|
-
*
|
|
11014
|
-
* secure_cookie: false
|
|
10862
|
+
* If default_value is specified, current super properties
|
|
10863
|
+
* with that value will be overwritten.
|
|
11015
10864
|
*
|
|
11016
|
-
*
|
|
11017
|
-
*
|
|
11018
|
-
*
|
|
10865
|
+
* @param {Object} properties An associative array of properties to store about the user
|
|
10866
|
+
* @param {*} [default_value] Value to override if already set in super properties (ex: 'False') Default: 'None'
|
|
10867
|
+
* @param {Number|Object} [days_or_options] Options object or number of days since the user's last visit to store the super properties (only valid for persisted props)
|
|
10868
|
+
* @param {boolean} [days_or_options.days] - number of days since the user's last visit to store the super properties (only valid for persisted props)
|
|
10869
|
+
* @param {boolean} [days_or_options.persistent=true] - whether to put in persistent storage (cookie/localStorage)
|
|
10870
|
+
*/
|
|
10871
|
+
MixpanelLib.prototype.register_once = function(props, default_value, days_or_options) {
|
|
10872
|
+
var options = options_for_register(days_or_options);
|
|
10873
|
+
if (options['persistent']) {
|
|
10874
|
+
this['persistence'].register_once(props, default_value, options['days']);
|
|
10875
|
+
} else {
|
|
10876
|
+
if (typeof(default_value) === 'undefined') {
|
|
10877
|
+
default_value = 'None';
|
|
10878
|
+
}
|
|
10879
|
+
_.each(props, function(val, prop) {
|
|
10880
|
+
if (!this.unpersisted_superprops.hasOwnProperty(prop) || this.unpersisted_superprops[prop] === default_value) {
|
|
10881
|
+
this.unpersisted_superprops[prop] = val;
|
|
10882
|
+
}
|
|
10883
|
+
}, this);
|
|
10884
|
+
}
|
|
10885
|
+
};
|
|
10886
|
+
|
|
10887
|
+
/**
|
|
10888
|
+
* Delete a super property stored with the current user.
|
|
11019
10889
|
*
|
|
11020
|
-
*
|
|
11021
|
-
*
|
|
11022
|
-
*
|
|
11023
|
-
|
|
11024
|
-
|
|
11025
|
-
|
|
10890
|
+
* @param {String} property The name of the super property to remove
|
|
10891
|
+
* @param {Object} [options]
|
|
10892
|
+
* @param {boolean} [options.persistent=true] - whether to look in persistent storage (cookie/localStorage)
|
|
10893
|
+
*/
|
|
10894
|
+
MixpanelLib.prototype.unregister = function(property, options) {
|
|
10895
|
+
options = options_for_register(options);
|
|
10896
|
+
if (options['persistent']) {
|
|
10897
|
+
this['persistence'].unregister(property);
|
|
10898
|
+
} else {
|
|
10899
|
+
delete this.unpersisted_superprops[property];
|
|
10900
|
+
}
|
|
10901
|
+
};
|
|
10902
|
+
|
|
10903
|
+
MixpanelLib.prototype._register_single = function(prop, value) {
|
|
10904
|
+
var props = {};
|
|
10905
|
+
props[prop] = value;
|
|
10906
|
+
this.register(props);
|
|
10907
|
+
};
|
|
10908
|
+
|
|
10909
|
+
/**
|
|
10910
|
+
* Identify a user with a unique ID to track user activity across
|
|
10911
|
+
* devices, tie a user to their events, and create a user profile.
|
|
10912
|
+
* If you never call this method, unique visitors are tracked using
|
|
10913
|
+
* a UUID generated the first time they visit the site.
|
|
11026
10914
|
*
|
|
11027
|
-
*
|
|
11028
|
-
*
|
|
11029
|
-
*
|
|
10915
|
+
* Call identify when you know the identity of the current user,
|
|
10916
|
+
* typically after login or signup. We recommend against using
|
|
10917
|
+
* identify for anonymous visitors to your site.
|
|
11030
10918
|
*
|
|
11031
|
-
*
|
|
11032
|
-
*
|
|
11033
|
-
*
|
|
10919
|
+
* ### Notes:
|
|
10920
|
+
* If your project has
|
|
10921
|
+
* <a href="https://help.mixpanel.com/hc/en-us/articles/360039133851">ID Merge</a>
|
|
10922
|
+
* enabled, the identify method will connect pre- and
|
|
10923
|
+
* post-authentication events when appropriate.
|
|
11034
10924
|
*
|
|
10925
|
+
* If your project does not have ID Merge enabled, identify will
|
|
10926
|
+
* change the user's local distinct_id to the unique ID you pass.
|
|
10927
|
+
* Events tracked prior to authentication will not be connected
|
|
10928
|
+
* to the same user identity. If ID Merge is disabled, alias can
|
|
10929
|
+
* be used to connect pre- and post-registration events.
|
|
11035
10930
|
*
|
|
11036
|
-
* @param {
|
|
10931
|
+
* @param {String} [unique_id] A string that uniquely identifies a user. If not provided, the distinct_id currently in the persistent store (cookie or localStorage) will be used.
|
|
11037
10932
|
*/
|
|
11038
|
-
MixpanelLib.prototype.
|
|
11039
|
-
|
|
11040
|
-
|
|
10933
|
+
MixpanelLib.prototype.identify = function(
|
|
10934
|
+
new_distinct_id, _set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback
|
|
10935
|
+
) {
|
|
10936
|
+
// Optional Parameters
|
|
10937
|
+
// _set_callback:function A callback to be run if and when the People set queue is flushed
|
|
10938
|
+
// _add_callback:function A callback to be run if and when the People add queue is flushed
|
|
10939
|
+
// _append_callback:function A callback to be run if and when the People append queue is flushed
|
|
10940
|
+
// _set_once_callback:function A callback to be run if and when the People set_once queue is flushed
|
|
10941
|
+
// _union_callback:function A callback to be run if and when the People union queue is flushed
|
|
10942
|
+
// _unset_callback:function A callback to be run if and when the People unset queue is flushed
|
|
11041
10943
|
|
|
11042
|
-
|
|
11043
|
-
|
|
11044
|
-
_.each(this.request_batchers, function(batcher) {
|
|
11045
|
-
batcher.resetBatchSize();
|
|
11046
|
-
});
|
|
11047
|
-
}
|
|
10944
|
+
var previous_distinct_id = this.get_distinct_id();
|
|
10945
|
+
this.register({'$user_id': new_distinct_id});
|
|
11048
10946
|
|
|
11049
|
-
|
|
11050
|
-
|
|
11051
|
-
|
|
11052
|
-
|
|
11053
|
-
|
|
11054
|
-
|
|
10947
|
+
if (!this.get_property('$device_id')) {
|
|
10948
|
+
// The persisted distinct id might not actually be a device id at all
|
|
10949
|
+
// it might be a distinct id of the user from before
|
|
10950
|
+
var device_id = previous_distinct_id;
|
|
10951
|
+
this.register_once({
|
|
10952
|
+
'$had_persisted_distinct_id': true,
|
|
10953
|
+
'$device_id': device_id
|
|
10954
|
+
}, '');
|
|
10955
|
+
}
|
|
11055
10956
|
|
|
11056
|
-
|
|
11057
|
-
|
|
11058
|
-
|
|
11059
|
-
|
|
10957
|
+
// identify only changes the distinct id if it doesn't match either the existing or the alias;
|
|
10958
|
+
// if it's new, blow away the alias as well.
|
|
10959
|
+
if (new_distinct_id !== previous_distinct_id && new_distinct_id !== this.get_property(ALIAS_ID_KEY)) {
|
|
10960
|
+
this.unregister(ALIAS_ID_KEY);
|
|
10961
|
+
this.register({'distinct_id': new_distinct_id});
|
|
11060
10962
|
}
|
|
11061
|
-
|
|
10963
|
+
this._flags.identify_called = true;
|
|
10964
|
+
// Flush any queued up people requests
|
|
10965
|
+
this['people']._flush(_set_callback, _add_callback, _append_callback, _set_once_callback, _union_callback, _unset_callback, _remove_callback);
|
|
11062
10966
|
|
|
11063
|
-
|
|
11064
|
-
|
|
11065
|
-
|
|
11066
|
-
|
|
11067
|
-
|
|
10967
|
+
// send an $identify event any time the distinct_id is changing - logic on the server
|
|
10968
|
+
// will determine whether or not to do anything with it.
|
|
10969
|
+
if (new_distinct_id !== previous_distinct_id) {
|
|
10970
|
+
this.track('$identify', {
|
|
10971
|
+
'distinct_id': new_distinct_id,
|
|
10972
|
+
'$anon_distinct_id': previous_distinct_id
|
|
10973
|
+
}, {skip_hooks: true});
|
|
10974
|
+
}
|
|
11068
10975
|
};
|
|
11069
10976
|
|
|
11070
10977
|
/**
|
|
11071
|
-
*
|
|
11072
|
-
*
|
|
11073
|
-
* @param {string} hook_name which hook to retrieve
|
|
11074
|
-
* @returns {any|null} return value of user-provided hook, or null if nothing was returned
|
|
10978
|
+
* Clears super properties and generates a new random distinct_id for this instance.
|
|
10979
|
+
* Useful for clearing data when a user logs out.
|
|
11075
10980
|
*/
|
|
11076
|
-
MixpanelLib.prototype.
|
|
11077
|
-
|
|
11078
|
-
|
|
11079
|
-
|
|
11080
|
-
|
|
11081
|
-
|
|
11082
|
-
|
|
10981
|
+
MixpanelLib.prototype.reset = function() {
|
|
10982
|
+
this['persistence'].clear();
|
|
10983
|
+
this._flags.identify_called = false;
|
|
10984
|
+
var uuid = _.UUID();
|
|
10985
|
+
this.register_once({
|
|
10986
|
+
'distinct_id': uuid,
|
|
10987
|
+
'$device_id': uuid
|
|
10988
|
+
}, '');
|
|
11083
10989
|
};
|
|
11084
10990
|
|
|
11085
10991
|
/**
|
|
11086
|
-
* Returns the
|
|
11087
|
-
*
|
|
10992
|
+
* Returns the current distinct id of the user. This is either the id automatically
|
|
10993
|
+
* generated by the library or the id that has been passed by a call to identify().
|
|
11088
10994
|
*
|
|
11089
10995
|
* ### Notes:
|
|
11090
10996
|
*
|
|
11091
|
-
*
|
|
10997
|
+
* get_distinct_id() can only be called after the Mixpanel library has finished loading.
|
|
11092
10998
|
* init() has a loaded function available to handle this automatically. For example:
|
|
11093
10999
|
*
|
|
11094
|
-
* //
|
|
11000
|
+
* // set distinct_id after the mixpanel library has loaded
|
|
11095
11001
|
* mixpanel.init('YOUR PROJECT TOKEN', {
|
|
11096
11002
|
* loaded: function(mixpanel) {
|
|
11097
|
-
*
|
|
11003
|
+
* distinct_id = mixpanel.get_distinct_id();
|
|
11098
11004
|
* }
|
|
11099
11005
|
* });
|
|
11100
|
-
*
|
|
11101
|
-
* @param {String} property_name The name of the super property you want to retrieve
|
|
11102
|
-
*/
|
|
11103
|
-
MixpanelLib.prototype.get_property = function(property_name) {
|
|
11104
|
-
return this['persistence']['props'][property_name];
|
|
11105
|
-
};
|
|
11106
|
-
|
|
11107
|
-
MixpanelLib.prototype.toString = function() {
|
|
11108
|
-
var name = this.get_config('name');
|
|
11109
|
-
if (name !== PRIMARY_INSTANCE_NAME) {
|
|
11110
|
-
name = PRIMARY_INSTANCE_NAME + '.' + name;
|
|
11111
|
-
}
|
|
11112
|
-
return name;
|
|
11113
|
-
};
|
|
11114
|
-
|
|
11115
|
-
MixpanelLib.prototype._event_is_disabled = function(event_name) {
|
|
11116
|
-
return _.isBlockedUA(userAgent) ||
|
|
11117
|
-
this._flags.disable_all_events ||
|
|
11118
|
-
_.include(this.__disabled_events, event_name);
|
|
11119
|
-
};
|
|
11120
|
-
|
|
11121
|
-
// perform some housekeeping around GDPR opt-in/out state
|
|
11122
|
-
MixpanelLib.prototype._gdpr_init = function() {
|
|
11123
|
-
var is_localStorage_requested = this.get_config('opt_out_tracking_persistence_type') === 'localStorage';
|
|
11124
|
-
|
|
11125
|
-
// try to convert opt-in/out cookies to localStorage if possible
|
|
11126
|
-
if (is_localStorage_requested && _.localStorage.is_supported()) {
|
|
11127
|
-
if (!this.has_opted_in_tracking() && this.has_opted_in_tracking({'persistence_type': 'cookie'})) {
|
|
11128
|
-
this.opt_in_tracking({'enable_persistence': false});
|
|
11129
|
-
}
|
|
11130
|
-
if (!this.has_opted_out_tracking() && this.has_opted_out_tracking({'persistence_type': 'cookie'})) {
|
|
11131
|
-
this.opt_out_tracking({'clear_persistence': false});
|
|
11132
|
-
}
|
|
11133
|
-
this.clear_opt_in_out_tracking({
|
|
11134
|
-
'persistence_type': 'cookie',
|
|
11135
|
-
'enable_persistence': false
|
|
11136
|
-
});
|
|
11137
|
-
}
|
|
11138
|
-
|
|
11139
|
-
// check whether the user has already opted out - if so, clear & disable persistence
|
|
11140
|
-
if (this.has_opted_out_tracking()) {
|
|
11141
|
-
this._gdpr_update_persistence({'clear_persistence': true});
|
|
11142
|
-
|
|
11143
|
-
// check whether we should opt out by default
|
|
11144
|
-
// note: we don't clear persistence here by default since opt-out default state is often
|
|
11145
|
-
// used as an initial state while GDPR information is being collected
|
|
11146
|
-
} else if (!this.has_opted_in_tracking() && (
|
|
11147
|
-
this.get_config('opt_out_tracking_by_default') || _.cookie.get('mp_optout')
|
|
11148
|
-
)) {
|
|
11149
|
-
_.cookie.remove('mp_optout');
|
|
11150
|
-
this.opt_out_tracking({
|
|
11151
|
-
'clear_persistence': this.get_config('opt_out_persistence_by_default')
|
|
11152
|
-
});
|
|
11153
|
-
}
|
|
11154
|
-
};
|
|
11155
|
-
|
|
11156
|
-
/**
|
|
11157
|
-
* Enable or disable persistence based on options
|
|
11158
|
-
* only enable/disable if persistence is not already in this state
|
|
11159
|
-
* @param {boolean} [options.clear_persistence] If true, will delete all data stored by the sdk in persistence and disable it
|
|
11160
|
-
* @param {boolean} [options.enable_persistence] If true, will re-enable sdk persistence
|
|
11161
11006
|
*/
|
|
11162
|
-
MixpanelLib.prototype.
|
|
11163
|
-
|
|
11164
|
-
if (options && options['clear_persistence']) {
|
|
11165
|
-
disabled = true;
|
|
11166
|
-
} else if (options && options['enable_persistence']) {
|
|
11167
|
-
disabled = false;
|
|
11168
|
-
} else {
|
|
11169
|
-
return;
|
|
11170
|
-
}
|
|
11171
|
-
|
|
11172
|
-
if (!this.get_config('disable_persistence') && this['persistence'].disabled !== disabled) {
|
|
11173
|
-
this['persistence'].set_disabled(disabled);
|
|
11174
|
-
}
|
|
11175
|
-
|
|
11176
|
-
if (disabled) {
|
|
11177
|
-
_.each(this.request_batchers, function(batcher) {
|
|
11178
|
-
batcher.clear();
|
|
11179
|
-
});
|
|
11180
|
-
}
|
|
11181
|
-
};
|
|
11182
|
-
|
|
11183
|
-
// call a base gdpr function after constructing the appropriate token and options args
|
|
11184
|
-
MixpanelLib.prototype._gdpr_call_func = function(func, options) {
|
|
11185
|
-
options = _.extend({
|
|
11186
|
-
'track': _.bind(this.track, this),
|
|
11187
|
-
'persistence_type': this.get_config('opt_out_tracking_persistence_type'),
|
|
11188
|
-
'cookie_prefix': this.get_config('opt_out_tracking_cookie_prefix'),
|
|
11189
|
-
'cookie_expiration': this.get_config('cookie_expiration'),
|
|
11190
|
-
'cross_site_cookie': this.get_config('cross_site_cookie'),
|
|
11191
|
-
'cross_subdomain_cookie': this.get_config('cross_subdomain_cookie'),
|
|
11192
|
-
'cookie_domain': this.get_config('cookie_domain'),
|
|
11193
|
-
'secure_cookie': this.get_config('secure_cookie'),
|
|
11194
|
-
'ignore_dnt': this.get_config('ignore_dnt')
|
|
11195
|
-
}, options);
|
|
11196
|
-
|
|
11197
|
-
// check if localStorage can be used for recording opt out status, fall back to cookie if not
|
|
11198
|
-
if (!_.localStorage.is_supported()) {
|
|
11199
|
-
options['persistence_type'] = 'cookie';
|
|
11200
|
-
}
|
|
11201
|
-
|
|
11202
|
-
return func(this.get_config('token'), {
|
|
11203
|
-
track: options['track'],
|
|
11204
|
-
trackEventName: options['track_event_name'],
|
|
11205
|
-
trackProperties: options['track_properties'],
|
|
11206
|
-
persistenceType: options['persistence_type'],
|
|
11207
|
-
persistencePrefix: options['cookie_prefix'],
|
|
11208
|
-
cookieDomain: options['cookie_domain'],
|
|
11209
|
-
cookieExpiration: options['cookie_expiration'],
|
|
11210
|
-
crossSiteCookie: options['cross_site_cookie'],
|
|
11211
|
-
crossSubdomainCookie: options['cross_subdomain_cookie'],
|
|
11212
|
-
secureCookie: options['secure_cookie'],
|
|
11213
|
-
ignoreDnt: options['ignore_dnt']
|
|
11214
|
-
});
|
|
11007
|
+
MixpanelLib.prototype.get_distinct_id = function() {
|
|
11008
|
+
return this.get_property('distinct_id');
|
|
11215
11009
|
};
|
|
11216
11010
|
|
|
11217
11011
|
/**
|
|
11218
|
-
*
|
|
11012
|
+
* The alias method creates an alias which Mixpanel will use to
|
|
11013
|
+
* remap one id to another. Multiple aliases can point to the
|
|
11014
|
+
* same identifier.
|
|
11219
11015
|
*
|
|
11220
|
-
*
|
|
11016
|
+
* The following is a valid use of alias:
|
|
11221
11017
|
*
|
|
11222
|
-
*
|
|
11223
|
-
*
|
|
11018
|
+
* mixpanel.alias('new_id', 'existing_id');
|
|
11019
|
+
* // You can add multiple id aliases to the existing ID
|
|
11020
|
+
* mixpanel.alias('newer_id', 'existing_id');
|
|
11224
11021
|
*
|
|
11225
|
-
*
|
|
11226
|
-
* mixpanel.opt_in_tracking({
|
|
11227
|
-
* track_event_name: 'User opted in',
|
|
11228
|
-
* track_event_properties: {
|
|
11229
|
-
* 'Email': 'jdoe@example.com'
|
|
11230
|
-
* },
|
|
11231
|
-
* cookie_expiration: 30,
|
|
11232
|
-
* secure_cookie: true
|
|
11233
|
-
* });
|
|
11022
|
+
* Aliases can also be chained - the following is a valid example:
|
|
11234
11023
|
*
|
|
11235
|
-
*
|
|
11236
|
-
*
|
|
11237
|
-
*
|
|
11238
|
-
* @param {Object} [options.track_properties] Set of properties to be tracked along with the opt-in action
|
|
11239
|
-
* @param {boolean} [options.enable_persistence=true] If true, will re-enable sdk persistence
|
|
11240
|
-
* @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable
|
|
11241
|
-
* @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
|
|
11242
|
-
* @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this Mixpanel instance's config)
|
|
11243
|
-
* @param {string} [options.cookie_domain] Custom cookie domain (overrides value specified in this Mixpanel instance's config)
|
|
11244
|
-
* @param {boolean} [options.cross_site_cookie] Whether the opt-in cookie is set as cross-site-enabled (overrides value specified in this Mixpanel instance's config)
|
|
11245
|
-
* @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this Mixpanel instance's config)
|
|
11246
|
-
* @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this Mixpanel instance's config)
|
|
11247
|
-
*/
|
|
11248
|
-
MixpanelLib.prototype.opt_in_tracking = function(options) {
|
|
11249
|
-
options = _.extend({
|
|
11250
|
-
'enable_persistence': true
|
|
11251
|
-
}, options);
|
|
11252
|
-
|
|
11253
|
-
this._gdpr_call_func(optIn, options);
|
|
11254
|
-
this._gdpr_update_persistence(options);
|
|
11255
|
-
};
|
|
11256
|
-
|
|
11257
|
-
/**
|
|
11258
|
-
* Opt the user out of data tracking and cookies/localstorage for this Mixpanel instance
|
|
11024
|
+
* mixpanel.alias('new_id', 'existing_id');
|
|
11025
|
+
* // chain newer_id - new_id - existing_id
|
|
11026
|
+
* mixpanel.alias('newer_id', 'new_id');
|
|
11259
11027
|
*
|
|
11260
|
-
*
|
|
11028
|
+
* Aliases cannot point to multiple identifiers - the following
|
|
11029
|
+
* example will not work:
|
|
11261
11030
|
*
|
|
11262
|
-
*
|
|
11263
|
-
*
|
|
11031
|
+
* mixpanel.alias('new_id', 'existing_id');
|
|
11032
|
+
* // this is invalid as 'new_id' already points to 'existing_id'
|
|
11033
|
+
* mixpanel.alias('new_id', 'newer_id');
|
|
11264
11034
|
*
|
|
11265
|
-
*
|
|
11266
|
-
* mixpanel.opt_out_tracking({
|
|
11267
|
-
* cookie_expiration: 30,
|
|
11268
|
-
* secure_cookie: true
|
|
11269
|
-
* });
|
|
11035
|
+
* ### Notes:
|
|
11270
11036
|
*
|
|
11271
|
-
*
|
|
11272
|
-
*
|
|
11273
|
-
*
|
|
11274
|
-
*
|
|
11275
|
-
*
|
|
11276
|
-
*
|
|
11277
|
-
*
|
|
11278
|
-
* @param {
|
|
11279
|
-
* @param {
|
|
11280
|
-
* @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this Mixpanel instance's config)
|
|
11037
|
+
* If your project does not have
|
|
11038
|
+
* <a href="https://help.mixpanel.com/hc/en-us/articles/360039133851">ID Merge</a>
|
|
11039
|
+
* enabled, the best practice is to call alias once when a unique
|
|
11040
|
+
* ID is first created for a user (e.g., when a user first registers
|
|
11041
|
+
* for an account). Do not use alias multiple times for a single
|
|
11042
|
+
* user without ID Merge enabled.
|
|
11043
|
+
*
|
|
11044
|
+
* @param {String} alias A unique identifier that you want to use for this user in the future.
|
|
11045
|
+
* @param {String} [original] The current identifier being used for this user.
|
|
11281
11046
|
*/
|
|
11282
|
-
MixpanelLib.prototype.
|
|
11283
|
-
|
|
11284
|
-
|
|
11285
|
-
|
|
11286
|
-
|
|
11287
|
-
|
|
11288
|
-
|
|
11289
|
-
if (options['delete_user'] && this['people'] && this['people']._identify_called()) {
|
|
11290
|
-
this['people'].delete_user();
|
|
11291
|
-
this['people'].clear_charges();
|
|
11047
|
+
MixpanelLib.prototype.alias = function(alias, original) {
|
|
11048
|
+
// If the $people_distinct_id key exists in persistence, there has been a previous
|
|
11049
|
+
// mixpanel.people.identify() call made for this user. It is VERY BAD to make an alias with
|
|
11050
|
+
// this ID, as it will duplicate users.
|
|
11051
|
+
if (alias === this.get_property(PEOPLE_DISTINCT_ID_KEY)) {
|
|
11052
|
+
this.report_error('Attempting to create alias for existing People user - aborting.');
|
|
11053
|
+
return -2;
|
|
11292
11054
|
}
|
|
11293
11055
|
|
|
11294
|
-
this
|
|
11295
|
-
|
|
11056
|
+
var _this = this;
|
|
11057
|
+
if (_.isUndefined(original)) {
|
|
11058
|
+
original = this.get_distinct_id();
|
|
11059
|
+
}
|
|
11060
|
+
if (alias !== original) {
|
|
11061
|
+
this._register_single(ALIAS_ID_KEY, alias);
|
|
11062
|
+
return this.track('$create_alias', {
|
|
11063
|
+
'alias': alias,
|
|
11064
|
+
'distinct_id': original
|
|
11065
|
+
}, {
|
|
11066
|
+
skip_hooks: true
|
|
11067
|
+
}, function() {
|
|
11068
|
+
// Flush the people queue
|
|
11069
|
+
_this.identify(alias);
|
|
11070
|
+
});
|
|
11071
|
+
} else {
|
|
11072
|
+
this.report_error('alias matches current distinct_id - skipping api call.');
|
|
11073
|
+
this.identify(alias);
|
|
11074
|
+
return -1;
|
|
11075
|
+
}
|
|
11296
11076
|
};
|
|
11297
11077
|
|
|
11298
11078
|
/**
|
|
11299
|
-
*
|
|
11300
|
-
*
|
|
11301
|
-
*
|
|
11079
|
+
* Provide a string to recognize the user by. The string passed to
|
|
11080
|
+
* this method will appear in the Mixpanel Streams product rather
|
|
11081
|
+
* than an automatically generated name. Name tags do not have to
|
|
11082
|
+
* be unique.
|
|
11302
11083
|
*
|
|
11303
|
-
*
|
|
11304
|
-
* // use has_opted_in value
|
|
11084
|
+
* This value will only be included in Streams data.
|
|
11305
11085
|
*
|
|
11306
|
-
* @param {
|
|
11307
|
-
* @
|
|
11308
|
-
* @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
|
|
11309
|
-
* @returns {boolean} current opt-in status
|
|
11086
|
+
* @param {String} name_tag A human readable name for the user
|
|
11087
|
+
* @deprecated
|
|
11310
11088
|
*/
|
|
11311
|
-
MixpanelLib.prototype.
|
|
11312
|
-
|
|
11089
|
+
MixpanelLib.prototype.name_tag = function(name_tag) {
|
|
11090
|
+
this._register_single('mp_name_tag', name_tag);
|
|
11313
11091
|
};
|
|
11314
11092
|
|
|
11315
11093
|
/**
|
|
11316
|
-
*
|
|
11094
|
+
* Update the configuration of a mixpanel library instance.
|
|
11317
11095
|
*
|
|
11318
|
-
*
|
|
11096
|
+
* The default config is:
|
|
11319
11097
|
*
|
|
11320
|
-
*
|
|
11321
|
-
*
|
|
11098
|
+
* {
|
|
11099
|
+
* // HTTP method for tracking requests
|
|
11100
|
+
* api_method: 'POST'
|
|
11322
11101
|
*
|
|
11323
|
-
*
|
|
11324
|
-
*
|
|
11325
|
-
*
|
|
11326
|
-
*
|
|
11327
|
-
|
|
11328
|
-
|
|
11329
|
-
|
|
11330
|
-
|
|
11331
|
-
|
|
11332
|
-
/**
|
|
11333
|
-
* Clear the user's opt in/out status of data tracking and cookies/localstorage for this Mixpanel instance
|
|
11102
|
+
* // transport for sending requests ('XHR' or 'sendBeacon')
|
|
11103
|
+
* // NB: sendBeacon should only be used for scenarios such as
|
|
11104
|
+
* // page unload where a "best-effort" attempt to send is
|
|
11105
|
+
* // acceptable; the sendBeacon API does not support callbacks
|
|
11106
|
+
* // or any way to know the result of the request. Mixpanel
|
|
11107
|
+
* // tracking via sendBeacon will not support any event-
|
|
11108
|
+
* // batching or retry mechanisms.
|
|
11109
|
+
* api_transport: 'XHR'
|
|
11334
11110
|
*
|
|
11335
|
-
*
|
|
11111
|
+
* // turn on request-batching/queueing/retry
|
|
11112
|
+
* batch_requests: false,
|
|
11336
11113
|
*
|
|
11337
|
-
*
|
|
11338
|
-
*
|
|
11114
|
+
* // maximum number of events/updates to send in a single
|
|
11115
|
+
* // network request
|
|
11116
|
+
* batch_size: 50,
|
|
11339
11117
|
*
|
|
11340
|
-
*
|
|
11341
|
-
*
|
|
11342
|
-
* mixpanel.clear_opt_in_out_tracking({
|
|
11343
|
-
* cookie_expiration: 30,
|
|
11344
|
-
* secure_cookie: true
|
|
11345
|
-
* });
|
|
11118
|
+
* // milliseconds to wait between sending batch requests
|
|
11119
|
+
* batch_flush_interval_ms: 5000,
|
|
11346
11120
|
*
|
|
11347
|
-
*
|
|
11348
|
-
*
|
|
11349
|
-
*
|
|
11350
|
-
*
|
|
11351
|
-
*
|
|
11352
|
-
*
|
|
11353
|
-
*
|
|
11354
|
-
*
|
|
11355
|
-
*
|
|
11356
|
-
|
|
11357
|
-
|
|
11358
|
-
|
|
11359
|
-
|
|
11360
|
-
|
|
11361
|
-
|
|
11362
|
-
|
|
11363
|
-
|
|
11364
|
-
|
|
11365
|
-
|
|
11366
|
-
|
|
11367
|
-
|
|
11368
|
-
|
|
11369
|
-
|
|
11370
|
-
|
|
11371
|
-
|
|
11372
|
-
|
|
11373
|
-
|
|
11374
|
-
|
|
11375
|
-
|
|
11376
|
-
|
|
11377
|
-
|
|
11378
|
-
|
|
11379
|
-
|
|
11380
|
-
//
|
|
11381
|
-
|
|
11382
|
-
|
|
11383
|
-
|
|
11384
|
-
|
|
11385
|
-
|
|
11386
|
-
|
|
11387
|
-
|
|
11388
|
-
|
|
11389
|
-
|
|
11390
|
-
|
|
11391
|
-
|
|
11392
|
-
|
|
11393
|
-
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
|
|
11397
|
-
|
|
11398
|
-
|
|
11399
|
-
|
|
11400
|
-
|
|
11401
|
-
|
|
11402
|
-
|
|
11403
|
-
|
|
11404
|
-
|
|
11405
|
-
|
|
11406
|
-
|
|
11407
|
-
|
|
11408
|
-
|
|
11409
|
-
|
|
11410
|
-
|
|
11411
|
-
|
|
11412
|
-
|
|
11413
|
-
|
|
11414
|
-
|
|
11415
|
-
|
|
11416
|
-
|
|
11417
|
-
|
|
11418
|
-
|
|
11419
|
-
|
|
11420
|
-
|
|
11421
|
-
|
|
11422
|
-
|
|
11423
|
-
|
|
11424
|
-
|
|
11425
|
-
|
|
11426
|
-
|
|
11427
|
-
|
|
11428
|
-
|
|
11429
|
-
|
|
11430
|
-
}
|
|
11431
|
-
|
|
11432
|
-
|
|
11433
|
-
|
|
11434
|
-
|
|
11435
|
-
mixpanel_master['init'] = function(token, config, name) {
|
|
11436
|
-
if (name) {
|
|
11437
|
-
// initialize a sub library
|
|
11438
|
-
if (!mixpanel_master[name]) {
|
|
11439
|
-
mixpanel_master[name] = instances[name] = create_mplib(token, config, name);
|
|
11440
|
-
mixpanel_master[name]._loaded();
|
|
11441
|
-
}
|
|
11442
|
-
return mixpanel_master[name];
|
|
11443
|
-
} else {
|
|
11444
|
-
var instance = mixpanel_master;
|
|
11445
|
-
|
|
11446
|
-
if (instances[PRIMARY_INSTANCE_NAME]) {
|
|
11447
|
-
// main mixpanel lib already initialized
|
|
11448
|
-
instance = instances[PRIMARY_INSTANCE_NAME];
|
|
11449
|
-
} else if (token) {
|
|
11450
|
-
// intialize the main mixpanel lib
|
|
11451
|
-
instance = create_mplib(token, config, PRIMARY_INSTANCE_NAME);
|
|
11452
|
-
instance._loaded();
|
|
11453
|
-
instances[PRIMARY_INSTANCE_NAME] = instance;
|
|
11454
|
-
}
|
|
11455
|
-
|
|
11456
|
-
mixpanel_master = instance;
|
|
11457
|
-
if (init_type === INIT_SNIPPET) {
|
|
11458
|
-
window$1[PRIMARY_INSTANCE_NAME] = mixpanel_master;
|
|
11459
|
-
}
|
|
11460
|
-
extend_mp();
|
|
11461
|
-
}
|
|
11462
|
-
};
|
|
11463
|
-
};
|
|
11464
|
-
|
|
11465
|
-
var add_dom_loaded_handler = function() {
|
|
11466
|
-
// Cross browser DOM Loaded support
|
|
11467
|
-
function dom_loaded_handler() {
|
|
11468
|
-
// function flag since we only want to execute this once
|
|
11469
|
-
if (dom_loaded_handler.done) { return; }
|
|
11470
|
-
dom_loaded_handler.done = true;
|
|
11471
|
-
|
|
11472
|
-
DOM_LOADED = true;
|
|
11473
|
-
ENQUEUE_REQUESTS = false;
|
|
11474
|
-
|
|
11475
|
-
_.each(instances, function(inst) {
|
|
11476
|
-
inst._dom_loaded();
|
|
11477
|
-
});
|
|
11478
|
-
}
|
|
11121
|
+
* // milliseconds to wait for network responses to batch requests
|
|
11122
|
+
* // before they are considered timed-out and retried
|
|
11123
|
+
* batch_request_timeout_ms: 90000,
|
|
11124
|
+
*
|
|
11125
|
+
* // override value for cookie domain, only useful for ensuring
|
|
11126
|
+
* // correct cross-subdomain cookies on unusual domains like
|
|
11127
|
+
* // subdomain.mainsite.avocat.fr; NB this cannot be used to
|
|
11128
|
+
* // set cookies on a different domain than the current origin
|
|
11129
|
+
* cookie_domain: ''
|
|
11130
|
+
*
|
|
11131
|
+
* // super properties cookie expiration (in days)
|
|
11132
|
+
* cookie_expiration: 365
|
|
11133
|
+
*
|
|
11134
|
+
* // if true, cookie will be set with SameSite=None; Secure
|
|
11135
|
+
* // this is only useful in special situations, like embedded
|
|
11136
|
+
* // 3rd-party iframes that set up a Mixpanel instance
|
|
11137
|
+
* cross_site_cookie: false
|
|
11138
|
+
*
|
|
11139
|
+
* // super properties span subdomains
|
|
11140
|
+
* cross_subdomain_cookie: true
|
|
11141
|
+
*
|
|
11142
|
+
* // debug mode
|
|
11143
|
+
* debug: false
|
|
11144
|
+
*
|
|
11145
|
+
* // if this is true, the mixpanel cookie or localStorage entry
|
|
11146
|
+
* // will be deleted, and no user persistence will take place
|
|
11147
|
+
* disable_persistence: false
|
|
11148
|
+
*
|
|
11149
|
+
* // if this is true, Mixpanel will automatically determine
|
|
11150
|
+
* // City, Region and Country data using the IP address of
|
|
11151
|
+
* //the client
|
|
11152
|
+
* ip: true
|
|
11153
|
+
*
|
|
11154
|
+
* // opt users out of tracking by this Mixpanel instance by default
|
|
11155
|
+
* opt_out_tracking_by_default: false
|
|
11156
|
+
*
|
|
11157
|
+
* // opt users out of browser data storage by this Mixpanel instance by default
|
|
11158
|
+
* opt_out_persistence_by_default: false
|
|
11159
|
+
*
|
|
11160
|
+
* // persistence mechanism used by opt-in/opt-out methods - cookie
|
|
11161
|
+
* // or localStorage - falls back to cookie if localStorage is unavailable
|
|
11162
|
+
* opt_out_tracking_persistence_type: 'localStorage'
|
|
11163
|
+
*
|
|
11164
|
+
* // customize the name of cookie/localStorage set by opt-in/opt-out methods
|
|
11165
|
+
* opt_out_tracking_cookie_prefix: null
|
|
11166
|
+
*
|
|
11167
|
+
* // type of persistent store for super properties (cookie/
|
|
11168
|
+
* // localStorage) if set to 'localStorage', any existing
|
|
11169
|
+
* // mixpanel cookie value with the same persistence_name
|
|
11170
|
+
* // will be transferred to localStorage and deleted
|
|
11171
|
+
* persistence: 'cookie'
|
|
11172
|
+
*
|
|
11173
|
+
* // name for super properties persistent store
|
|
11174
|
+
* persistence_name: ''
|
|
11175
|
+
*
|
|
11176
|
+
* // names of properties/superproperties which should never
|
|
11177
|
+
* // be sent with track() calls
|
|
11178
|
+
* property_blacklist: []
|
|
11179
|
+
*
|
|
11180
|
+
* // if this is true, mixpanel cookies will be marked as
|
|
11181
|
+
* // secure, meaning they will only be transmitted over https
|
|
11182
|
+
* secure_cookie: false
|
|
11183
|
+
*
|
|
11184
|
+
* // the amount of time track_links will
|
|
11185
|
+
* // wait for Mixpanel's servers to respond
|
|
11186
|
+
* track_links_timeout: 300
|
|
11187
|
+
*
|
|
11188
|
+
* // if you set upgrade to be true, the library will check for
|
|
11189
|
+
* // a cookie from our old js library and import super
|
|
11190
|
+
* // properties from it, then the old cookie is deleted
|
|
11191
|
+
* // The upgrade config option only works in the initialization,
|
|
11192
|
+
* // so make sure you set it when you create the library.
|
|
11193
|
+
* upgrade: false
|
|
11194
|
+
*
|
|
11195
|
+
* // extra HTTP request headers to set for each API request, in
|
|
11196
|
+
* // the format {'Header-Name': value}
|
|
11197
|
+
* xhr_headers: {}
|
|
11198
|
+
*
|
|
11199
|
+
* // whether to ignore or respect the web browser's Do Not Track setting
|
|
11200
|
+
* ignore_dnt: false
|
|
11201
|
+
* }
|
|
11202
|
+
*
|
|
11203
|
+
*
|
|
11204
|
+
* @param {Object} config A dictionary of new configuration values to update
|
|
11205
|
+
*/
|
|
11206
|
+
MixpanelLib.prototype.set_config = function(config) {
|
|
11207
|
+
if (_.isObject(config)) {
|
|
11208
|
+
_.extend(this['config'], config);
|
|
11479
11209
|
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
|
|
11484
|
-
|
|
11485
|
-
return;
|
|
11210
|
+
var new_batch_size = config['batch_size'];
|
|
11211
|
+
if (new_batch_size) {
|
|
11212
|
+
_.each(this.request_batchers, function(batcher) {
|
|
11213
|
+
batcher.resetBatchSize();
|
|
11214
|
+
});
|
|
11486
11215
|
}
|
|
11487
11216
|
|
|
11488
|
-
|
|
11489
|
-
|
|
11490
|
-
|
|
11491
|
-
if (document$1.addEventListener) {
|
|
11492
|
-
if (document$1.readyState === 'complete') {
|
|
11493
|
-
// safari 4 can fire the DOMContentLoaded event before loading all
|
|
11494
|
-
// external JS (including this file). you will see some copypasta
|
|
11495
|
-
// on the internet that checks for 'complete' and 'loaded', but
|
|
11496
|
-
// 'loaded' is an IE thing
|
|
11497
|
-
dom_loaded_handler();
|
|
11498
|
-
} else {
|
|
11499
|
-
document$1.addEventListener('DOMContentLoaded', dom_loaded_handler, false);
|
|
11217
|
+
if (!this.get_config('persistence_name')) {
|
|
11218
|
+
this['config']['persistence_name'] = this['config']['cookie_name'];
|
|
11500
11219
|
}
|
|
11501
|
-
|
|
11502
|
-
|
|
11503
|
-
document$1.attachEvent('onreadystatechange', dom_loaded_handler);
|
|
11504
|
-
|
|
11505
|
-
// check to make sure we arn't in a frame
|
|
11506
|
-
var toplevel = false;
|
|
11507
|
-
try {
|
|
11508
|
-
toplevel = window$1.frameElement === null;
|
|
11509
|
-
} catch(e) {
|
|
11510
|
-
// noop
|
|
11220
|
+
if (!this.get_config('disable_persistence')) {
|
|
11221
|
+
this['config']['disable_persistence'] = this['config']['disable_cookie'];
|
|
11511
11222
|
}
|
|
11512
11223
|
|
|
11513
|
-
if (
|
|
11514
|
-
|
|
11224
|
+
if (this['persistence']) {
|
|
11225
|
+
this['persistence'].update_config(this['config']);
|
|
11515
11226
|
}
|
|
11227
|
+
Config.DEBUG = Config.DEBUG || this.get_config('debug');
|
|
11516
11228
|
}
|
|
11517
|
-
|
|
11518
|
-
// fallback handler, always will work
|
|
11519
|
-
_.register_event(window$1, 'load', dom_loaded_handler, true);
|
|
11520
11229
|
};
|
|
11521
11230
|
|
|
11522
|
-
function init_as_module() {
|
|
11523
|
-
init_type = INIT_MODULE;
|
|
11524
|
-
mixpanel_master = new MixpanelLib();
|
|
11525
|
-
|
|
11526
|
-
override_mp_init_func();
|
|
11527
|
-
mixpanel_master['init']();
|
|
11528
|
-
add_dom_loaded_handler();
|
|
11529
|
-
|
|
11530
|
-
return mixpanel_master;
|
|
11531
|
-
}
|
|
11532
|
-
|
|
11533
|
-
var mixpanel = init_as_module();
|
|
11534
|
-
|
|
11535
|
-
var mixpanel_cjs = mixpanel;
|
|
11536
|
-
|
|
11537
|
-
var mixpanel$1 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.assign(/*#__PURE__*/Object.create(null), mixpanel_cjs, {
|
|
11538
|
-
'default': mixpanel_cjs
|
|
11539
|
-
}));
|
|
11540
|
-
|
|
11541
|
-
// Needed to avoid error in CJS builds on some bundlers.
|
|
11542
|
-
const mixpanelLib = mixpanel_cjs || mixpanel$1;
|
|
11543
|
-
let mixpanelInstance;
|
|
11544
|
-
const MIXPANEL_EVENT = {
|
|
11545
|
-
VISUAL_SDK_RENDER_START: 'visual-sdk-render-start',
|
|
11546
|
-
VISUAL_SDK_CALLED_INIT: 'visual-sdk-called-init',
|
|
11547
|
-
VISUAL_SDK_RENDER_COMPLETE: 'visual-sdk-render-complete',
|
|
11548
|
-
VISUAL_SDK_RENDER_FAILED: 'visual-sdk-render-failed',
|
|
11549
|
-
VISUAL_SDK_TRIGGER: 'visual-sdk-trigger',
|
|
11550
|
-
VISUAL_SDK_ON: 'visual-sdk-on',
|
|
11551
|
-
VISUAL_SDK_IFRAME_LOAD_PERFORMANCE: 'visual-sdk-iframe-load-performance',
|
|
11552
|
-
VISUAL_SDK_EMBED_CREATE: 'visual-sdk-embed-create',
|
|
11553
|
-
};
|
|
11554
|
-
let isMixpanelInitialized = false;
|
|
11555
|
-
let eventQueue = [];
|
|
11556
|
-
/**
|
|
11557
|
-
* Pushes the event with its Property key-value map to mixpanel.
|
|
11558
|
-
*
|
|
11559
|
-
* @param eventId
|
|
11560
|
-
* @param eventProps
|
|
11561
|
-
*/
|
|
11562
|
-
function uploadMixpanelEvent(eventId, eventProps = {}) {
|
|
11563
|
-
if (!isMixpanelInitialized) {
|
|
11564
|
-
eventQueue.push({ eventId, eventProps });
|
|
11565
|
-
return;
|
|
11566
|
-
}
|
|
11567
|
-
mixpanelInstance.track(eventId, eventProps);
|
|
11568
|
-
}
|
|
11569
|
-
/**
|
|
11570
|
-
*
|
|
11571
|
-
*/
|
|
11572
|
-
function emptyQueue() {
|
|
11573
|
-
if (!isMixpanelInitialized) {
|
|
11574
|
-
return;
|
|
11575
|
-
}
|
|
11576
|
-
eventQueue.forEach((event) => {
|
|
11577
|
-
uploadMixpanelEvent(event.eventId, event.eventProps);
|
|
11578
|
-
});
|
|
11579
|
-
eventQueue = [];
|
|
11580
|
-
}
|
|
11581
|
-
/**
|
|
11582
|
-
*
|
|
11583
|
-
* @param sessionInfo
|
|
11584
|
-
*/
|
|
11585
|
-
function initMixpanel(sessionInfo) {
|
|
11586
|
-
var _a;
|
|
11587
|
-
if (!sessionInfo || !sessionInfo.mixpanelToken) {
|
|
11588
|
-
return;
|
|
11589
|
-
}
|
|
11590
|
-
// On a public cluster the user is anonymous, so don't set the identify to
|
|
11591
|
-
// userGUID
|
|
11592
|
-
const isPublicCluster = !!sessionInfo.isPublicUser;
|
|
11593
|
-
const token = sessionInfo.mixpanelToken;
|
|
11594
|
-
try {
|
|
11595
|
-
if (token) {
|
|
11596
|
-
mixpanelInstance = mixpanelLib.init(token, undefined, 'tsEmbed');
|
|
11597
|
-
if (!isPublicCluster) {
|
|
11598
|
-
mixpanelInstance.identify(sessionInfo.userGUID);
|
|
11599
|
-
}
|
|
11600
|
-
mixpanelInstance.register_once({
|
|
11601
|
-
clusterId: sessionInfo.clusterId,
|
|
11602
|
-
clusterName: sessionInfo.clusterName,
|
|
11603
|
-
releaseVersion: sessionInfo.releaseVersion,
|
|
11604
|
-
hostAppUrl: ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.host) || '',
|
|
11605
|
-
});
|
|
11606
|
-
isMixpanelInitialized = true;
|
|
11607
|
-
emptyQueue();
|
|
11608
|
-
}
|
|
11609
|
-
}
|
|
11610
|
-
catch (e) {
|
|
11611
|
-
console.error('Error initializing mixpanel', e);
|
|
11612
|
-
}
|
|
11613
|
-
}
|
|
11614
|
-
|
|
11615
|
-
var eventemitter3 = createCommonjsModule(function (module) {
|
|
11616
|
-
|
|
11617
|
-
var has = Object.prototype.hasOwnProperty
|
|
11618
|
-
, prefix = '~';
|
|
11619
|
-
|
|
11620
11231
|
/**
|
|
11621
|
-
*
|
|
11622
|
-
* An `Events` instance is a plain object whose properties are event names.
|
|
11623
|
-
*
|
|
11624
|
-
* @constructor
|
|
11625
|
-
* @private
|
|
11232
|
+
* returns the current config object for the library.
|
|
11626
11233
|
*/
|
|
11627
|
-
function
|
|
11628
|
-
|
|
11629
|
-
|
|
11630
|
-
// We try to not inherit from `Object.prototype`. In some engines creating an
|
|
11631
|
-
// instance in this way is faster than calling `Object.create(null)` directly.
|
|
11632
|
-
// If `Object.create(null)` is not supported we prefix the event names with a
|
|
11633
|
-
// character to make sure that the built-in object properties are not
|
|
11634
|
-
// overridden or used as an attack vector.
|
|
11635
|
-
//
|
|
11636
|
-
if (Object.create) {
|
|
11637
|
-
Events.prototype = Object.create(null);
|
|
11638
|
-
|
|
11639
|
-
//
|
|
11640
|
-
// This hack is needed because the `__proto__` property is still inherited in
|
|
11641
|
-
// some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.
|
|
11642
|
-
//
|
|
11643
|
-
if (!new Events().__proto__) prefix = false;
|
|
11644
|
-
}
|
|
11234
|
+
MixpanelLib.prototype.get_config = function(prop_name) {
|
|
11235
|
+
return this['config'][prop_name];
|
|
11236
|
+
};
|
|
11645
11237
|
|
|
11646
11238
|
/**
|
|
11647
|
-
*
|
|
11648
|
-
*
|
|
11649
|
-
* @param {
|
|
11650
|
-
* @
|
|
11651
|
-
* @param {Boolean} [once=false] Specify if the listener is a one-time listener.
|
|
11652
|
-
* @constructor
|
|
11653
|
-
* @private
|
|
11239
|
+
* Fetch a hook function from config, with safe default, and run it
|
|
11240
|
+
* against the given arguments
|
|
11241
|
+
* @param {string} hook_name which hook to retrieve
|
|
11242
|
+
* @returns {any|null} return value of user-provided hook, or null if nothing was returned
|
|
11654
11243
|
*/
|
|
11655
|
-
function
|
|
11656
|
-
|
|
11657
|
-
|
|
11658
|
-
|
|
11659
|
-
|
|
11244
|
+
MixpanelLib.prototype._run_hook = function(hook_name) {
|
|
11245
|
+
var ret = (this['config']['hooks'][hook_name] || IDENTITY_FUNC).apply(this, slice.call(arguments, 1));
|
|
11246
|
+
if (typeof ret === 'undefined') {
|
|
11247
|
+
this.report_error(hook_name + ' hook did not return a value');
|
|
11248
|
+
ret = null;
|
|
11249
|
+
}
|
|
11250
|
+
return ret;
|
|
11251
|
+
};
|
|
11660
11252
|
|
|
11661
11253
|
/**
|
|
11662
|
-
*
|
|
11254
|
+
* Returns the value of the super property named property_name. If no such
|
|
11255
|
+
* property is set, get_property() will return the undefined value.
|
|
11663
11256
|
*
|
|
11664
|
-
*
|
|
11665
|
-
*
|
|
11666
|
-
*
|
|
11667
|
-
*
|
|
11668
|
-
*
|
|
11669
|
-
*
|
|
11670
|
-
*
|
|
11257
|
+
* ### Notes:
|
|
11258
|
+
*
|
|
11259
|
+
* get_property() can only be called after the Mixpanel library has finished loading.
|
|
11260
|
+
* init() has a loaded function available to handle this automatically. For example:
|
|
11261
|
+
*
|
|
11262
|
+
* // grab value for 'user_id' after the mixpanel library has loaded
|
|
11263
|
+
* mixpanel.init('YOUR PROJECT TOKEN', {
|
|
11264
|
+
* loaded: function(mixpanel) {
|
|
11265
|
+
* user_id = mixpanel.get_property('user_id');
|
|
11266
|
+
* }
|
|
11267
|
+
* });
|
|
11268
|
+
*
|
|
11269
|
+
* @param {String} property_name The name of the super property you want to retrieve
|
|
11671
11270
|
*/
|
|
11672
|
-
function
|
|
11673
|
-
|
|
11674
|
-
|
|
11675
|
-
}
|
|
11271
|
+
MixpanelLib.prototype.get_property = function(property_name) {
|
|
11272
|
+
return this['persistence']['props'][property_name];
|
|
11273
|
+
};
|
|
11676
11274
|
|
|
11677
|
-
|
|
11678
|
-
|
|
11275
|
+
MixpanelLib.prototype.toString = function() {
|
|
11276
|
+
var name = this.get_config('name');
|
|
11277
|
+
if (name !== PRIMARY_INSTANCE_NAME) {
|
|
11278
|
+
name = PRIMARY_INSTANCE_NAME + '.' + name;
|
|
11279
|
+
}
|
|
11280
|
+
return name;
|
|
11281
|
+
};
|
|
11679
11282
|
|
|
11680
|
-
|
|
11681
|
-
|
|
11682
|
-
|
|
11283
|
+
MixpanelLib.prototype._event_is_disabled = function(event_name) {
|
|
11284
|
+
return _.isBlockedUA(userAgent) ||
|
|
11285
|
+
this._flags.disable_all_events ||
|
|
11286
|
+
_.include(this.__disabled_events, event_name);
|
|
11287
|
+
};
|
|
11683
11288
|
|
|
11684
|
-
|
|
11685
|
-
|
|
11289
|
+
// perform some housekeeping around GDPR opt-in/out state
|
|
11290
|
+
MixpanelLib.prototype._gdpr_init = function() {
|
|
11291
|
+
var is_localStorage_requested = this.get_config('opt_out_tracking_persistence_type') === 'localStorage';
|
|
11686
11292
|
|
|
11687
|
-
|
|
11688
|
-
|
|
11689
|
-
|
|
11690
|
-
|
|
11691
|
-
|
|
11692
|
-
|
|
11693
|
-
|
|
11694
|
-
|
|
11695
|
-
|
|
11696
|
-
|
|
11697
|
-
|
|
11293
|
+
// try to convert opt-in/out cookies to localStorage if possible
|
|
11294
|
+
if (is_localStorage_requested && _.localStorage.is_supported()) {
|
|
11295
|
+
if (!this.has_opted_in_tracking() && this.has_opted_in_tracking({'persistence_type': 'cookie'})) {
|
|
11296
|
+
this.opt_in_tracking({'enable_persistence': false});
|
|
11297
|
+
}
|
|
11298
|
+
if (!this.has_opted_out_tracking() && this.has_opted_out_tracking({'persistence_type': 'cookie'})) {
|
|
11299
|
+
this.opt_out_tracking({'clear_persistence': false});
|
|
11300
|
+
}
|
|
11301
|
+
this.clear_opt_in_out_tracking({
|
|
11302
|
+
'persistence_type': 'cookie',
|
|
11303
|
+
'enable_persistence': false
|
|
11304
|
+
});
|
|
11305
|
+
}
|
|
11698
11306
|
|
|
11699
|
-
|
|
11700
|
-
|
|
11701
|
-
|
|
11702
|
-
|
|
11703
|
-
|
|
11704
|
-
|
|
11705
|
-
|
|
11706
|
-
|
|
11707
|
-
|
|
11708
|
-
|
|
11709
|
-
|
|
11307
|
+
// check whether the user has already opted out - if so, clear & disable persistence
|
|
11308
|
+
if (this.has_opted_out_tracking()) {
|
|
11309
|
+
this._gdpr_update_persistence({'clear_persistence': true});
|
|
11310
|
+
|
|
11311
|
+
// check whether we should opt out by default
|
|
11312
|
+
// note: we don't clear persistence here by default since opt-out default state is often
|
|
11313
|
+
// used as an initial state while GDPR information is being collected
|
|
11314
|
+
} else if (!this.has_opted_in_tracking() && (
|
|
11315
|
+
this.get_config('opt_out_tracking_by_default') || _.cookie.get('mp_optout')
|
|
11316
|
+
)) {
|
|
11317
|
+
_.cookie.remove('mp_optout');
|
|
11318
|
+
this.opt_out_tracking({
|
|
11319
|
+
'clear_persistence': this.get_config('opt_out_persistence_by_default')
|
|
11320
|
+
});
|
|
11321
|
+
}
|
|
11322
|
+
};
|
|
11710
11323
|
|
|
11711
11324
|
/**
|
|
11712
|
-
*
|
|
11713
|
-
*
|
|
11714
|
-
*
|
|
11715
|
-
* @
|
|
11716
|
-
* @public
|
|
11325
|
+
* Enable or disable persistence based on options
|
|
11326
|
+
* only enable/disable if persistence is not already in this state
|
|
11327
|
+
* @param {boolean} [options.clear_persistence] If true, will delete all data stored by the sdk in persistence and disable it
|
|
11328
|
+
* @param {boolean} [options.enable_persistence] If true, will re-enable sdk persistence
|
|
11717
11329
|
*/
|
|
11718
|
-
|
|
11719
|
-
|
|
11720
|
-
|
|
11721
|
-
|
|
11330
|
+
MixpanelLib.prototype._gdpr_update_persistence = function(options) {
|
|
11331
|
+
var disabled;
|
|
11332
|
+
if (options && options['clear_persistence']) {
|
|
11333
|
+
disabled = true;
|
|
11334
|
+
} else if (options && options['enable_persistence']) {
|
|
11335
|
+
disabled = false;
|
|
11336
|
+
} else {
|
|
11337
|
+
return;
|
|
11338
|
+
}
|
|
11722
11339
|
|
|
11723
|
-
|
|
11340
|
+
if (!this.get_config('disable_persistence') && this['persistence'].disabled !== disabled) {
|
|
11341
|
+
this['persistence'].set_disabled(disabled);
|
|
11342
|
+
}
|
|
11724
11343
|
|
|
11725
|
-
|
|
11726
|
-
|
|
11727
|
-
|
|
11344
|
+
if (disabled) {
|
|
11345
|
+
_.each(this.request_batchers, function(batcher) {
|
|
11346
|
+
batcher.clear();
|
|
11347
|
+
});
|
|
11348
|
+
}
|
|
11349
|
+
};
|
|
11728
11350
|
|
|
11729
|
-
|
|
11730
|
-
|
|
11731
|
-
|
|
11351
|
+
// call a base gdpr function after constructing the appropriate token and options args
|
|
11352
|
+
MixpanelLib.prototype._gdpr_call_func = function(func, options) {
|
|
11353
|
+
options = _.extend({
|
|
11354
|
+
'track': _.bind(this.track, this),
|
|
11355
|
+
'persistence_type': this.get_config('opt_out_tracking_persistence_type'),
|
|
11356
|
+
'cookie_prefix': this.get_config('opt_out_tracking_cookie_prefix'),
|
|
11357
|
+
'cookie_expiration': this.get_config('cookie_expiration'),
|
|
11358
|
+
'cross_site_cookie': this.get_config('cross_site_cookie'),
|
|
11359
|
+
'cross_subdomain_cookie': this.get_config('cross_subdomain_cookie'),
|
|
11360
|
+
'cookie_domain': this.get_config('cookie_domain'),
|
|
11361
|
+
'secure_cookie': this.get_config('secure_cookie'),
|
|
11362
|
+
'ignore_dnt': this.get_config('ignore_dnt')
|
|
11363
|
+
}, options);
|
|
11732
11364
|
|
|
11733
|
-
|
|
11365
|
+
// check if localStorage can be used for recording opt out status, fall back to cookie if not
|
|
11366
|
+
if (!_.localStorage.is_supported()) {
|
|
11367
|
+
options['persistence_type'] = 'cookie';
|
|
11368
|
+
}
|
|
11369
|
+
|
|
11370
|
+
return func(this.get_config('token'), {
|
|
11371
|
+
track: options['track'],
|
|
11372
|
+
trackEventName: options['track_event_name'],
|
|
11373
|
+
trackProperties: options['track_properties'],
|
|
11374
|
+
persistenceType: options['persistence_type'],
|
|
11375
|
+
persistencePrefix: options['cookie_prefix'],
|
|
11376
|
+
cookieDomain: options['cookie_domain'],
|
|
11377
|
+
cookieExpiration: options['cookie_expiration'],
|
|
11378
|
+
crossSiteCookie: options['cross_site_cookie'],
|
|
11379
|
+
crossSubdomainCookie: options['cross_subdomain_cookie'],
|
|
11380
|
+
secureCookie: options['secure_cookie'],
|
|
11381
|
+
ignoreDnt: options['ignore_dnt']
|
|
11382
|
+
});
|
|
11734
11383
|
};
|
|
11735
11384
|
|
|
11736
11385
|
/**
|
|
11737
|
-
*
|
|
11386
|
+
* Opt the user in to data tracking and cookies/localstorage for this Mixpanel instance
|
|
11738
11387
|
*
|
|
11739
|
-
*
|
|
11740
|
-
*
|
|
11741
|
-
*
|
|
11388
|
+
* ### Usage
|
|
11389
|
+
*
|
|
11390
|
+
* // opt user in
|
|
11391
|
+
* mixpanel.opt_in_tracking();
|
|
11392
|
+
*
|
|
11393
|
+
* // opt user in with specific event name, properties, cookie configuration
|
|
11394
|
+
* mixpanel.opt_in_tracking({
|
|
11395
|
+
* track_event_name: 'User opted in',
|
|
11396
|
+
* track_event_properties: {
|
|
11397
|
+
* 'Email': 'jdoe@example.com'
|
|
11398
|
+
* },
|
|
11399
|
+
* cookie_expiration: 30,
|
|
11400
|
+
* secure_cookie: true
|
|
11401
|
+
* });
|
|
11402
|
+
*
|
|
11403
|
+
* @param {Object} [options] A dictionary of config options to override
|
|
11404
|
+
* @param {function} [options.track] Function used for tracking a Mixpanel event to record the opt-in action (default is this Mixpanel instance's track method)
|
|
11405
|
+
* @param {string} [options.track_event_name=$opt_in] Event name to be used for tracking the opt-in action
|
|
11406
|
+
* @param {Object} [options.track_properties] Set of properties to be tracked along with the opt-in action
|
|
11407
|
+
* @param {boolean} [options.enable_persistence=true] If true, will re-enable sdk persistence
|
|
11408
|
+
* @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable
|
|
11409
|
+
* @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
|
|
11410
|
+
* @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this Mixpanel instance's config)
|
|
11411
|
+
* @param {string} [options.cookie_domain] Custom cookie domain (overrides value specified in this Mixpanel instance's config)
|
|
11412
|
+
* @param {boolean} [options.cross_site_cookie] Whether the opt-in cookie is set as cross-site-enabled (overrides value specified in this Mixpanel instance's config)
|
|
11413
|
+
* @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this Mixpanel instance's config)
|
|
11414
|
+
* @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this Mixpanel instance's config)
|
|
11742
11415
|
*/
|
|
11743
|
-
|
|
11744
|
-
|
|
11745
|
-
|
|
11416
|
+
MixpanelLib.prototype.opt_in_tracking = function(options) {
|
|
11417
|
+
options = _.extend({
|
|
11418
|
+
'enable_persistence': true
|
|
11419
|
+
}, options);
|
|
11746
11420
|
|
|
11747
|
-
|
|
11748
|
-
|
|
11421
|
+
this._gdpr_call_func(optIn, options);
|
|
11422
|
+
this._gdpr_update_persistence(options);
|
|
11423
|
+
};
|
|
11749
11424
|
|
|
11750
|
-
|
|
11751
|
-
|
|
11752
|
-
|
|
11425
|
+
/**
|
|
11426
|
+
* Opt the user out of data tracking and cookies/localstorage for this Mixpanel instance
|
|
11427
|
+
*
|
|
11428
|
+
* ### Usage
|
|
11429
|
+
*
|
|
11430
|
+
* // opt user out
|
|
11431
|
+
* mixpanel.opt_out_tracking();
|
|
11432
|
+
*
|
|
11433
|
+
* // opt user out with different cookie configuration from Mixpanel instance
|
|
11434
|
+
* mixpanel.opt_out_tracking({
|
|
11435
|
+
* cookie_expiration: 30,
|
|
11436
|
+
* secure_cookie: true
|
|
11437
|
+
* });
|
|
11438
|
+
*
|
|
11439
|
+
* @param {Object} [options] A dictionary of config options to override
|
|
11440
|
+
* @param {boolean} [options.delete_user=true] If true, will delete the currently identified user's profile and clear all charges after opting the user out
|
|
11441
|
+
* @param {boolean} [options.clear_persistence=true] If true, will delete all data stored by the sdk in persistence
|
|
11442
|
+
* @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable
|
|
11443
|
+
* @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
|
|
11444
|
+
* @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this Mixpanel instance's config)
|
|
11445
|
+
* @param {string} [options.cookie_domain] Custom cookie domain (overrides value specified in this Mixpanel instance's config)
|
|
11446
|
+
* @param {boolean} [options.cross_site_cookie] Whether the opt-in cookie is set as cross-site-enabled (overrides value specified in this Mixpanel instance's config)
|
|
11447
|
+
* @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this Mixpanel instance's config)
|
|
11448
|
+
* @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this Mixpanel instance's config)
|
|
11449
|
+
*/
|
|
11450
|
+
MixpanelLib.prototype.opt_out_tracking = function(options) {
|
|
11451
|
+
options = _.extend({
|
|
11452
|
+
'clear_persistence': true,
|
|
11453
|
+
'delete_user': true
|
|
11454
|
+
}, options);
|
|
11455
|
+
|
|
11456
|
+
// delete user and clear charges since these methods may be disabled by opt-out
|
|
11457
|
+
if (options['delete_user'] && this['people'] && this['people']._identify_called()) {
|
|
11458
|
+
this['people'].delete_user();
|
|
11459
|
+
this['people'].clear_charges();
|
|
11460
|
+
}
|
|
11753
11461
|
|
|
11754
|
-
|
|
11462
|
+
this._gdpr_call_func(optOut, options);
|
|
11463
|
+
this._gdpr_update_persistence(options);
|
|
11755
11464
|
};
|
|
11756
11465
|
|
|
11757
11466
|
/**
|
|
11758
|
-
*
|
|
11467
|
+
* Check whether the user has opted in to data tracking and cookies/localstorage for this Mixpanel instance
|
|
11759
11468
|
*
|
|
11760
|
-
*
|
|
11761
|
-
*
|
|
11762
|
-
*
|
|
11469
|
+
* ### Usage
|
|
11470
|
+
*
|
|
11471
|
+
* var has_opted_in = mixpanel.has_opted_in_tracking();
|
|
11472
|
+
* // use has_opted_in value
|
|
11473
|
+
*
|
|
11474
|
+
* @param {Object} [options] A dictionary of config options to override
|
|
11475
|
+
* @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable
|
|
11476
|
+
* @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
|
|
11477
|
+
* @returns {boolean} current opt-in status
|
|
11763
11478
|
*/
|
|
11764
|
-
|
|
11765
|
-
|
|
11766
|
-
, listeners = this._events[evt];
|
|
11767
|
-
|
|
11768
|
-
if (!listeners) return 0;
|
|
11769
|
-
if (listeners.fn) return 1;
|
|
11770
|
-
return listeners.length;
|
|
11479
|
+
MixpanelLib.prototype.has_opted_in_tracking = function(options) {
|
|
11480
|
+
return this._gdpr_call_func(hasOptedIn, options);
|
|
11771
11481
|
};
|
|
11772
11482
|
|
|
11773
11483
|
/**
|
|
11774
|
-
*
|
|
11484
|
+
* Check whether the user has opted out of data tracking and cookies/localstorage for this Mixpanel instance
|
|
11775
11485
|
*
|
|
11776
|
-
*
|
|
11777
|
-
*
|
|
11778
|
-
*
|
|
11486
|
+
* ### Usage
|
|
11487
|
+
*
|
|
11488
|
+
* var has_opted_out = mixpanel.has_opted_out_tracking();
|
|
11489
|
+
* // use has_opted_out value
|
|
11490
|
+
*
|
|
11491
|
+
* @param {Object} [options] A dictionary of config options to override
|
|
11492
|
+
* @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable
|
|
11493
|
+
* @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
|
|
11494
|
+
* @returns {boolean} current opt-out status
|
|
11779
11495
|
*/
|
|
11780
|
-
|
|
11781
|
-
|
|
11782
|
-
|
|
11783
|
-
if (!this._events[evt]) return false;
|
|
11496
|
+
MixpanelLib.prototype.has_opted_out_tracking = function(options) {
|
|
11497
|
+
return this._gdpr_call_func(hasOptedOut, options);
|
|
11498
|
+
};
|
|
11784
11499
|
|
|
11785
|
-
|
|
11786
|
-
|
|
11787
|
-
|
|
11788
|
-
|
|
11500
|
+
/**
|
|
11501
|
+
* Clear the user's opt in/out status of data tracking and cookies/localstorage for this Mixpanel instance
|
|
11502
|
+
*
|
|
11503
|
+
* ### Usage
|
|
11504
|
+
*
|
|
11505
|
+
* // clear user's opt-in/out status
|
|
11506
|
+
* mixpanel.clear_opt_in_out_tracking();
|
|
11507
|
+
*
|
|
11508
|
+
* // clear user's opt-in/out status with specific cookie configuration - should match
|
|
11509
|
+
* // configuration used when opt_in_tracking/opt_out_tracking methods were called.
|
|
11510
|
+
* mixpanel.clear_opt_in_out_tracking({
|
|
11511
|
+
* cookie_expiration: 30,
|
|
11512
|
+
* secure_cookie: true
|
|
11513
|
+
* });
|
|
11514
|
+
*
|
|
11515
|
+
* @param {Object} [options] A dictionary of config options to override
|
|
11516
|
+
* @param {boolean} [options.enable_persistence=true] If true, will re-enable sdk persistence
|
|
11517
|
+
* @param {string} [options.persistence_type=localStorage] Persistence mechanism used - cookie or localStorage - falls back to cookie if localStorage is unavailable
|
|
11518
|
+
* @param {string} [options.cookie_prefix=__mp_opt_in_out] Custom prefix to be used in the cookie/localstorage name
|
|
11519
|
+
* @param {Number} [options.cookie_expiration] Number of days until the opt-in cookie expires (overrides value specified in this Mixpanel instance's config)
|
|
11520
|
+
* @param {string} [options.cookie_domain] Custom cookie domain (overrides value specified in this Mixpanel instance's config)
|
|
11521
|
+
* @param {boolean} [options.cross_site_cookie] Whether the opt-in cookie is set as cross-site-enabled (overrides value specified in this Mixpanel instance's config)
|
|
11522
|
+
* @param {boolean} [options.cross_subdomain_cookie] Whether the opt-in cookie is set as cross-subdomain or not (overrides value specified in this Mixpanel instance's config)
|
|
11523
|
+
* @param {boolean} [options.secure_cookie] Whether the opt-in cookie is set as secure or not (overrides value specified in this Mixpanel instance's config)
|
|
11524
|
+
*/
|
|
11525
|
+
MixpanelLib.prototype.clear_opt_in_out_tracking = function(options) {
|
|
11526
|
+
options = _.extend({
|
|
11527
|
+
'enable_persistence': true
|
|
11528
|
+
}, options);
|
|
11789
11529
|
|
|
11790
|
-
|
|
11791
|
-
|
|
11530
|
+
this._gdpr_call_func(clearOptInOut, options);
|
|
11531
|
+
this._gdpr_update_persistence(options);
|
|
11532
|
+
};
|
|
11792
11533
|
|
|
11793
|
-
|
|
11794
|
-
|
|
11795
|
-
|
|
11796
|
-
|
|
11797
|
-
|
|
11798
|
-
|
|
11799
|
-
|
|
11534
|
+
MixpanelLib.prototype.report_error = function(msg, err) {
|
|
11535
|
+
console$1.error.apply(console$1.error, arguments);
|
|
11536
|
+
try {
|
|
11537
|
+
if (!err && !(msg instanceof Error)) {
|
|
11538
|
+
msg = new Error(msg);
|
|
11539
|
+
}
|
|
11540
|
+
this.get_config('error_reporter')(msg, err);
|
|
11541
|
+
} catch(err) {
|
|
11542
|
+
console$1.error(err);
|
|
11800
11543
|
}
|
|
11544
|
+
};
|
|
11801
11545
|
|
|
11802
|
-
|
|
11803
|
-
args[i - 1] = arguments[i];
|
|
11804
|
-
}
|
|
11546
|
+
// EXPORTS (for closure compiler)
|
|
11805
11547
|
|
|
11806
|
-
|
|
11807
|
-
|
|
11808
|
-
|
|
11809
|
-
|
|
11548
|
+
// MixpanelLib Exports
|
|
11549
|
+
MixpanelLib.prototype['init'] = MixpanelLib.prototype.init;
|
|
11550
|
+
MixpanelLib.prototype['reset'] = MixpanelLib.prototype.reset;
|
|
11551
|
+
MixpanelLib.prototype['disable'] = MixpanelLib.prototype.disable;
|
|
11552
|
+
MixpanelLib.prototype['time_event'] = MixpanelLib.prototype.time_event;
|
|
11553
|
+
MixpanelLib.prototype['track'] = MixpanelLib.prototype.track;
|
|
11554
|
+
MixpanelLib.prototype['track_links'] = MixpanelLib.prototype.track_links;
|
|
11555
|
+
MixpanelLib.prototype['track_forms'] = MixpanelLib.prototype.track_forms;
|
|
11556
|
+
MixpanelLib.prototype['track_pageview'] = MixpanelLib.prototype.track_pageview;
|
|
11557
|
+
MixpanelLib.prototype['register'] = MixpanelLib.prototype.register;
|
|
11558
|
+
MixpanelLib.prototype['register_once'] = MixpanelLib.prototype.register_once;
|
|
11559
|
+
MixpanelLib.prototype['unregister'] = MixpanelLib.prototype.unregister;
|
|
11560
|
+
MixpanelLib.prototype['identify'] = MixpanelLib.prototype.identify;
|
|
11561
|
+
MixpanelLib.prototype['alias'] = MixpanelLib.prototype.alias;
|
|
11562
|
+
MixpanelLib.prototype['name_tag'] = MixpanelLib.prototype.name_tag;
|
|
11563
|
+
MixpanelLib.prototype['set_config'] = MixpanelLib.prototype.set_config;
|
|
11564
|
+
MixpanelLib.prototype['get_config'] = MixpanelLib.prototype.get_config;
|
|
11565
|
+
MixpanelLib.prototype['get_property'] = MixpanelLib.prototype.get_property;
|
|
11566
|
+
MixpanelLib.prototype['get_distinct_id'] = MixpanelLib.prototype.get_distinct_id;
|
|
11567
|
+
MixpanelLib.prototype['toString'] = MixpanelLib.prototype.toString;
|
|
11568
|
+
MixpanelLib.prototype['opt_out_tracking'] = MixpanelLib.prototype.opt_out_tracking;
|
|
11569
|
+
MixpanelLib.prototype['opt_in_tracking'] = MixpanelLib.prototype.opt_in_tracking;
|
|
11570
|
+
MixpanelLib.prototype['has_opted_out_tracking'] = MixpanelLib.prototype.has_opted_out_tracking;
|
|
11571
|
+
MixpanelLib.prototype['has_opted_in_tracking'] = MixpanelLib.prototype.has_opted_in_tracking;
|
|
11572
|
+
MixpanelLib.prototype['clear_opt_in_out_tracking'] = MixpanelLib.prototype.clear_opt_in_out_tracking;
|
|
11573
|
+
MixpanelLib.prototype['get_group'] = MixpanelLib.prototype.get_group;
|
|
11574
|
+
MixpanelLib.prototype['set_group'] = MixpanelLib.prototype.set_group;
|
|
11575
|
+
MixpanelLib.prototype['add_group'] = MixpanelLib.prototype.add_group;
|
|
11576
|
+
MixpanelLib.prototype['remove_group'] = MixpanelLib.prototype.remove_group;
|
|
11577
|
+
MixpanelLib.prototype['track_with_groups'] = MixpanelLib.prototype.track_with_groups;
|
|
11578
|
+
MixpanelLib.prototype['start_batch_senders'] = MixpanelLib.prototype.start_batch_senders;
|
|
11579
|
+
MixpanelLib.prototype['stop_batch_senders'] = MixpanelLib.prototype.stop_batch_senders;
|
|
11810
11580
|
|
|
11811
|
-
|
|
11812
|
-
|
|
11581
|
+
// MixpanelPersistence Exports
|
|
11582
|
+
MixpanelPersistence.prototype['properties'] = MixpanelPersistence.prototype.properties;
|
|
11583
|
+
MixpanelPersistence.prototype['update_search_keyword'] = MixpanelPersistence.prototype.update_search_keyword;
|
|
11584
|
+
MixpanelPersistence.prototype['update_referrer_info'] = MixpanelPersistence.prototype.update_referrer_info;
|
|
11585
|
+
MixpanelPersistence.prototype['get_cross_subdomain'] = MixpanelPersistence.prototype.get_cross_subdomain;
|
|
11586
|
+
MixpanelPersistence.prototype['clear'] = MixpanelPersistence.prototype.clear;
|
|
11813
11587
|
|
|
11814
|
-
switch (len) {
|
|
11815
|
-
case 1: listeners[i].fn.call(listeners[i].context); break;
|
|
11816
|
-
case 2: listeners[i].fn.call(listeners[i].context, a1); break;
|
|
11817
|
-
case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;
|
|
11818
|
-
case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;
|
|
11819
|
-
default:
|
|
11820
|
-
if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {
|
|
11821
|
-
args[j - 1] = arguments[j];
|
|
11822
|
-
}
|
|
11823
11588
|
|
|
11824
|
-
|
|
11825
|
-
|
|
11826
|
-
|
|
11827
|
-
|
|
11589
|
+
var instances = {};
|
|
11590
|
+
var extend_mp = function() {
|
|
11591
|
+
// add all the sub mixpanel instances
|
|
11592
|
+
_.each(instances, function(instance, name) {
|
|
11593
|
+
if (name !== PRIMARY_INSTANCE_NAME) { mixpanel_master[name] = instance; }
|
|
11594
|
+
});
|
|
11828
11595
|
|
|
11829
|
-
|
|
11596
|
+
// add private functions as _
|
|
11597
|
+
mixpanel_master['_'] = _;
|
|
11830
11598
|
};
|
|
11831
11599
|
|
|
11832
|
-
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
}
|
|
11600
|
+
var override_mp_init_func = function() {
|
|
11601
|
+
// we override the snippets init function to handle the case where a
|
|
11602
|
+
// user initializes the mixpanel library after the script loads & runs
|
|
11603
|
+
mixpanel_master['init'] = function(token, config, name) {
|
|
11604
|
+
if (name) {
|
|
11605
|
+
// initialize a sub library
|
|
11606
|
+
if (!mixpanel_master[name]) {
|
|
11607
|
+
mixpanel_master[name] = instances[name] = create_mplib(token, config, name);
|
|
11608
|
+
mixpanel_master[name]._loaded();
|
|
11609
|
+
}
|
|
11610
|
+
return mixpanel_master[name];
|
|
11611
|
+
} else {
|
|
11612
|
+
var instance = mixpanel_master;
|
|
11844
11613
|
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
EventEmitter.prototype.once = function once(event, fn, context) {
|
|
11855
|
-
return addListener(this, event, fn, context, true);
|
|
11856
|
-
};
|
|
11614
|
+
if (instances[PRIMARY_INSTANCE_NAME]) {
|
|
11615
|
+
// main mixpanel lib already initialized
|
|
11616
|
+
instance = instances[PRIMARY_INSTANCE_NAME];
|
|
11617
|
+
} else if (token) {
|
|
11618
|
+
// intialize the main mixpanel lib
|
|
11619
|
+
instance = create_mplib(token, config, PRIMARY_INSTANCE_NAME);
|
|
11620
|
+
instance._loaded();
|
|
11621
|
+
instances[PRIMARY_INSTANCE_NAME] = instance;
|
|
11622
|
+
}
|
|
11857
11623
|
|
|
11858
|
-
|
|
11859
|
-
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
|
|
11863
|
-
|
|
11864
|
-
|
|
11865
|
-
|
|
11866
|
-
* @public
|
|
11867
|
-
*/
|
|
11868
|
-
EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
|
|
11869
|
-
var evt = prefix ? prefix + event : event;
|
|
11624
|
+
mixpanel_master = instance;
|
|
11625
|
+
if (init_type === INIT_SNIPPET) {
|
|
11626
|
+
window$1[PRIMARY_INSTANCE_NAME] = mixpanel_master;
|
|
11627
|
+
}
|
|
11628
|
+
extend_mp();
|
|
11629
|
+
}
|
|
11630
|
+
};
|
|
11631
|
+
};
|
|
11870
11632
|
|
|
11871
|
-
|
|
11872
|
-
|
|
11873
|
-
|
|
11874
|
-
|
|
11875
|
-
|
|
11633
|
+
var add_dom_loaded_handler = function() {
|
|
11634
|
+
// Cross browser DOM Loaded support
|
|
11635
|
+
function dom_loaded_handler() {
|
|
11636
|
+
// function flag since we only want to execute this once
|
|
11637
|
+
if (dom_loaded_handler.done) { return; }
|
|
11638
|
+
dom_loaded_handler.done = true;
|
|
11876
11639
|
|
|
11877
|
-
|
|
11640
|
+
DOM_LOADED = true;
|
|
11641
|
+
ENQUEUE_REQUESTS = false;
|
|
11878
11642
|
|
|
11879
|
-
|
|
11880
|
-
|
|
11881
|
-
|
|
11882
|
-
(!once || listeners.once) &&
|
|
11883
|
-
(!context || listeners.context === context)
|
|
11884
|
-
) {
|
|
11885
|
-
clearEvent(this, evt);
|
|
11886
|
-
}
|
|
11887
|
-
} else {
|
|
11888
|
-
for (var i = 0, events = [], length = listeners.length; i < length; i++) {
|
|
11889
|
-
if (
|
|
11890
|
-
listeners[i].fn !== fn ||
|
|
11891
|
-
(once && !listeners[i].once) ||
|
|
11892
|
-
(context && listeners[i].context !== context)
|
|
11893
|
-
) {
|
|
11894
|
-
events.push(listeners[i]);
|
|
11895
|
-
}
|
|
11643
|
+
_.each(instances, function(inst) {
|
|
11644
|
+
inst._dom_loaded();
|
|
11645
|
+
});
|
|
11896
11646
|
}
|
|
11897
11647
|
|
|
11898
|
-
|
|
11899
|
-
|
|
11900
|
-
|
|
11901
|
-
|
|
11902
|
-
|
|
11903
|
-
|
|
11904
|
-
|
|
11905
|
-
return this;
|
|
11906
|
-
};
|
|
11648
|
+
function do_scroll_check() {
|
|
11649
|
+
try {
|
|
11650
|
+
document$1.documentElement.doScroll('left');
|
|
11651
|
+
} catch(e) {
|
|
11652
|
+
setTimeout(do_scroll_check, 1);
|
|
11653
|
+
return;
|
|
11654
|
+
}
|
|
11907
11655
|
|
|
11908
|
-
|
|
11909
|
-
|
|
11910
|
-
*
|
|
11911
|
-
* @param {(String|Symbol)} [event] The event name.
|
|
11912
|
-
* @returns {EventEmitter} `this`.
|
|
11913
|
-
* @public
|
|
11914
|
-
*/
|
|
11915
|
-
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
|
|
11916
|
-
var evt;
|
|
11656
|
+
dom_loaded_handler();
|
|
11657
|
+
}
|
|
11917
11658
|
|
|
11918
|
-
|
|
11919
|
-
|
|
11920
|
-
|
|
11921
|
-
|
|
11922
|
-
|
|
11923
|
-
|
|
11924
|
-
|
|
11659
|
+
if (document$1.addEventListener) {
|
|
11660
|
+
if (document$1.readyState === 'complete') {
|
|
11661
|
+
// safari 4 can fire the DOMContentLoaded event before loading all
|
|
11662
|
+
// external JS (including this file). you will see some copypasta
|
|
11663
|
+
// on the internet that checks for 'complete' and 'loaded', but
|
|
11664
|
+
// 'loaded' is an IE thing
|
|
11665
|
+
dom_loaded_handler();
|
|
11666
|
+
} else {
|
|
11667
|
+
document$1.addEventListener('DOMContentLoaded', dom_loaded_handler, false);
|
|
11668
|
+
}
|
|
11669
|
+
} else if (document$1.attachEvent) {
|
|
11670
|
+
// IE
|
|
11671
|
+
document$1.attachEvent('onreadystatechange', dom_loaded_handler);
|
|
11925
11672
|
|
|
11926
|
-
|
|
11927
|
-
|
|
11673
|
+
// check to make sure we arn't in a frame
|
|
11674
|
+
var toplevel = false;
|
|
11675
|
+
try {
|
|
11676
|
+
toplevel = window$1.frameElement === null;
|
|
11677
|
+
} catch(e) {
|
|
11678
|
+
// noop
|
|
11679
|
+
}
|
|
11928
11680
|
|
|
11929
|
-
|
|
11930
|
-
|
|
11931
|
-
|
|
11932
|
-
|
|
11933
|
-
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
|
|
11681
|
+
if (document$1.documentElement.doScroll && toplevel) {
|
|
11682
|
+
do_scroll_check();
|
|
11683
|
+
}
|
|
11684
|
+
}
|
|
11934
11685
|
|
|
11935
|
-
//
|
|
11936
|
-
|
|
11937
|
-
|
|
11938
|
-
EventEmitter.prefixed = prefix;
|
|
11686
|
+
// fallback handler, always will work
|
|
11687
|
+
_.register_event(window$1, 'load', dom_loaded_handler, true);
|
|
11688
|
+
};
|
|
11939
11689
|
|
|
11940
|
-
|
|
11941
|
-
|
|
11942
|
-
|
|
11943
|
-
EventEmitter.EventEmitter = EventEmitter;
|
|
11690
|
+
function init_as_module() {
|
|
11691
|
+
init_type = INIT_MODULE;
|
|
11692
|
+
mixpanel_master = new MixpanelLib();
|
|
11944
11693
|
|
|
11945
|
-
|
|
11946
|
-
|
|
11947
|
-
|
|
11948
|
-
{
|
|
11949
|
-
module.exports = EventEmitter;
|
|
11950
|
-
}
|
|
11951
|
-
});
|
|
11694
|
+
override_mp_init_func();
|
|
11695
|
+
mixpanel_master['init']();
|
|
11696
|
+
add_dom_loaded_handler();
|
|
11952
11697
|
|
|
11953
|
-
|
|
11954
|
-
* This method returns `undefined`.
|
|
11955
|
-
*
|
|
11956
|
-
* @static
|
|
11957
|
-
* @memberOf _
|
|
11958
|
-
* @since 2.3.0
|
|
11959
|
-
* @category Util
|
|
11960
|
-
* @example
|
|
11961
|
-
*
|
|
11962
|
-
* _.times(2, _.noop);
|
|
11963
|
-
* // => [undefined, undefined]
|
|
11964
|
-
*/
|
|
11965
|
-
function noop() {
|
|
11966
|
-
// No operation performed.
|
|
11698
|
+
return mixpanel_master;
|
|
11967
11699
|
}
|
|
11968
11700
|
|
|
11969
|
-
var
|
|
11701
|
+
var mixpanel = init_as_module();
|
|
11970
11702
|
|
|
11971
|
-
|
|
11972
|
-
var INFINITY = 1 / 0;
|
|
11703
|
+
var mixpanel_cjs = mixpanel;
|
|
11973
11704
|
|
|
11974
|
-
|
|
11975
|
-
|
|
11976
|
-
|
|
11977
|
-
* @private
|
|
11978
|
-
* @param {Array} values The values to add to the set.
|
|
11979
|
-
* @returns {Object} Returns the new set.
|
|
11980
|
-
*/
|
|
11981
|
-
var createSet = !(_Set && (1 / _setToArray(new _Set([,-0]))[1]) == INFINITY) ? noop_1 : function(values) {
|
|
11982
|
-
return new _Set(values);
|
|
11983
|
-
};
|
|
11705
|
+
var mixpanel$1 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.assign(/*#__PURE__*/Object.create(null), mixpanel_cjs, {
|
|
11706
|
+
'default': mixpanel_cjs
|
|
11707
|
+
}));
|
|
11984
11708
|
|
|
11985
|
-
//
|
|
11986
|
-
|
|
11987
|
-
|
|
11988
|
-
|
|
11989
|
-
|
|
11990
|
-
|
|
11991
|
-
|
|
11992
|
-
|
|
11993
|
-
|
|
11994
|
-
|
|
11995
|
-
|
|
11996
|
-
|
|
11997
|
-
|
|
11998
|
-
|
|
11999
|
-
|
|
12000
|
-
/**
|
|
12001
|
-
*
|
|
12002
|
-
* @param authVerificationUrl
|
|
12003
|
-
*/
|
|
12004
|
-
function fetchSessionInfoService(authVerificationUrl) {
|
|
12005
|
-
return failureLoggedFetch(authVerificationUrl, {
|
|
12006
|
-
credentials: 'include',
|
|
12007
|
-
});
|
|
12008
|
-
}
|
|
12009
|
-
/**
|
|
12010
|
-
* Service to validate a auth token against a ThoughtSpot host.
|
|
12011
|
-
*
|
|
12012
|
-
* @param thoughtSpotHost : ThoughtSpot host to verify the token against.
|
|
12013
|
-
* @param authToken : Auth token to verify.
|
|
12014
|
-
*/
|
|
12015
|
-
function verifyTokenService(thoughtSpotHost, authToken) {
|
|
12016
|
-
const authVerificationUrl = `${thoughtSpotHost}${EndPoints.IS_ACTIVE}`;
|
|
12017
|
-
return fetch(authVerificationUrl, {
|
|
12018
|
-
headers: {
|
|
12019
|
-
Authorization: `Bearer ${authToken}`,
|
|
12020
|
-
'x-requested-by': 'ThoughtSpot',
|
|
12021
|
-
},
|
|
12022
|
-
credentials: 'omit',
|
|
12023
|
-
});
|
|
12024
|
-
}
|
|
12025
|
-
/**
|
|
12026
|
-
*
|
|
12027
|
-
* @param authEndpoint
|
|
12028
|
-
*/
|
|
12029
|
-
async function fetchAuthTokenService(authEndpoint) {
|
|
12030
|
-
return fetch(authEndpoint);
|
|
12031
|
-
}
|
|
11709
|
+
// Needed to avoid error in CJS builds on some bundlers.
|
|
11710
|
+
const mixpanelLib = mixpanel_cjs || mixpanel$1;
|
|
11711
|
+
let mixpanelInstance;
|
|
11712
|
+
const MIXPANEL_EVENT = {
|
|
11713
|
+
VISUAL_SDK_RENDER_START: 'visual-sdk-render-start',
|
|
11714
|
+
VISUAL_SDK_CALLED_INIT: 'visual-sdk-called-init',
|
|
11715
|
+
VISUAL_SDK_RENDER_COMPLETE: 'visual-sdk-render-complete',
|
|
11716
|
+
VISUAL_SDK_RENDER_FAILED: 'visual-sdk-render-failed',
|
|
11717
|
+
VISUAL_SDK_TRIGGER: 'visual-sdk-trigger',
|
|
11718
|
+
VISUAL_SDK_ON: 'visual-sdk-on',
|
|
11719
|
+
VISUAL_SDK_IFRAME_LOAD_PERFORMANCE: 'visual-sdk-iframe-load-performance',
|
|
11720
|
+
VISUAL_SDK_EMBED_CREATE: 'visual-sdk-embed-create',
|
|
11721
|
+
};
|
|
11722
|
+
let isMixpanelInitialized = false;
|
|
11723
|
+
let eventQueue = [];
|
|
12032
11724
|
/**
|
|
11725
|
+
* Pushes the event with its Property key-value map to mixpanel.
|
|
12033
11726
|
*
|
|
12034
|
-
* @param
|
|
12035
|
-
* @param
|
|
12036
|
-
* @param authToken
|
|
11727
|
+
* @param eventId
|
|
11728
|
+
* @param eventProps
|
|
12037
11729
|
*/
|
|
12038
|
-
|
|
12039
|
-
|
|
12040
|
-
|
|
12041
|
-
|
|
12042
|
-
|
|
12043
|
-
|
|
12044
|
-
});
|
|
11730
|
+
function uploadMixpanelEvent(eventId, eventProps = {}) {
|
|
11731
|
+
if (!isMixpanelInitialized) {
|
|
11732
|
+
eventQueue.push({ eventId, eventProps });
|
|
11733
|
+
return;
|
|
11734
|
+
}
|
|
11735
|
+
mixpanelInstance.track(eventId, eventProps);
|
|
12045
11736
|
}
|
|
12046
11737
|
/**
|
|
12047
11738
|
*
|
|
12048
|
-
* @param thoughtSpotHost
|
|
12049
|
-
* @param username
|
|
12050
|
-
* @param authToken
|
|
12051
11739
|
*/
|
|
12052
|
-
|
|
12053
|
-
|
|
12054
|
-
|
|
12055
|
-
|
|
12056
|
-
|
|
12057
|
-
|
|
12058
|
-
},
|
|
12059
|
-
body: `username=${encodeURIComponent(username)}&auth_token=${encodeURIComponent(authToken)}`,
|
|
12060
|
-
credentials: 'include',
|
|
12061
|
-
// We do not want to follow the redirect, as it starts giving a CORS
|
|
12062
|
-
// error
|
|
12063
|
-
redirect: 'manual',
|
|
11740
|
+
function emptyQueue() {
|
|
11741
|
+
if (!isMixpanelInitialized) {
|
|
11742
|
+
return;
|
|
11743
|
+
}
|
|
11744
|
+
eventQueue.forEach((event) => {
|
|
11745
|
+
uploadMixpanelEvent(event.eventId, event.eventProps);
|
|
12064
11746
|
});
|
|
11747
|
+
eventQueue = [];
|
|
12065
11748
|
}
|
|
12066
11749
|
/**
|
|
12067
11750
|
*
|
|
12068
|
-
* @param
|
|
12069
|
-
|
|
12070
|
-
|
|
12071
|
-
|
|
12072
|
-
|
|
12073
|
-
|
|
12074
|
-
|
|
12075
|
-
|
|
12076
|
-
|
|
12077
|
-
|
|
12078
|
-
|
|
12079
|
-
|
|
12080
|
-
|
|
12081
|
-
|
|
11751
|
+
* @param sessionInfo
|
|
11752
|
+
*/
|
|
11753
|
+
function initMixpanel(sessionInfo) {
|
|
11754
|
+
var _a;
|
|
11755
|
+
if (!sessionInfo || !sessionInfo.mixpanelToken) {
|
|
11756
|
+
return;
|
|
11757
|
+
}
|
|
11758
|
+
// On a public cluster the user is anonymous, so don't set the identify to
|
|
11759
|
+
// userGUID
|
|
11760
|
+
const isPublicCluster = !!sessionInfo.isPublicUser;
|
|
11761
|
+
const token = sessionInfo.mixpanelToken;
|
|
11762
|
+
try {
|
|
11763
|
+
if (token) {
|
|
11764
|
+
mixpanelInstance = mixpanelLib.init(token, undefined, 'tsEmbed');
|
|
11765
|
+
if (!isPublicCluster) {
|
|
11766
|
+
mixpanelInstance.identify(sessionInfo.userGUID);
|
|
11767
|
+
}
|
|
11768
|
+
mixpanelInstance.register_once({
|
|
11769
|
+
clusterId: sessionInfo.clusterId,
|
|
11770
|
+
clusterName: sessionInfo.clusterName,
|
|
11771
|
+
releaseVersion: sessionInfo.releaseVersion,
|
|
11772
|
+
hostAppUrl: ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.host) || '',
|
|
11773
|
+
});
|
|
11774
|
+
isMixpanelInitialized = true;
|
|
11775
|
+
emptyQueue();
|
|
11776
|
+
}
|
|
11777
|
+
}
|
|
11778
|
+
catch (e) {
|
|
11779
|
+
console.error('Error initializing mixpanel', e);
|
|
11780
|
+
}
|
|
12082
11781
|
}
|
|
12083
11782
|
|
|
12084
11783
|
// eslint-disable-next-line import/no-mutable-exports
|
|
@@ -12094,17 +11793,6 @@ const sessionInfoPromise = new Promise((resolve) => {
|
|
|
12094
11793
|
});
|
|
12095
11794
|
let releaseVersion = '';
|
|
12096
11795
|
const SSO_REDIRECTION_MARKER_GUID = '5e16222e-ef02-43e9-9fbd-24226bf3ce5b';
|
|
12097
|
-
const EndPoints = {
|
|
12098
|
-
AUTH_VERIFICATION: '/callosum/v1/session/info',
|
|
12099
|
-
SAML_LOGIN_TEMPLATE: (targetUrl) => `/callosum/v1/saml/login?targetURLPath=${targetUrl}`,
|
|
12100
|
-
OIDC_LOGIN_TEMPLATE: (targetUrl) => `/callosum/v1/oidc/login?targetURLPath=${targetUrl}`,
|
|
12101
|
-
TOKEN_LOGIN: '/callosum/v1/session/login/token',
|
|
12102
|
-
BASIC_LOGIN: '/callosum/v1/session/login',
|
|
12103
|
-
LOGOUT: '/callosum/v1/session/logout',
|
|
12104
|
-
EXECUTE_TML: '/api/rest/2.0/metadata/tml/import',
|
|
12105
|
-
EXPORT_TML: '/api/rest/2.0/metadata/tml/export',
|
|
12106
|
-
IS_ACTIVE: '/callosum/v1/session/isactive',
|
|
12107
|
-
};
|
|
12108
11796
|
/**
|
|
12109
11797
|
* Enum for auth failure types. This is the parameter passed to the listner
|
|
12110
11798
|
* of {@link AuthStatus.FAILURE}.
|
|
@@ -12171,382 +11859,748 @@ function notifyAuthSDKSuccess() {
|
|
|
12171
11859
|
console.error('SDK not initialized');
|
|
12172
11860
|
return;
|
|
12173
11861
|
}
|
|
12174
|
-
}
|
|
12175
|
-
/**
|
|
12176
|
-
*
|
|
12177
|
-
*/
|
|
12178
|
-
function notifyAuthSuccess() {
|
|
12179
|
-
{
|
|
12180
|
-
console.error('SDK not initialized');
|
|
11862
|
+
}
|
|
11863
|
+
/**
|
|
11864
|
+
*
|
|
11865
|
+
*/
|
|
11866
|
+
function notifyAuthSuccess() {
|
|
11867
|
+
{
|
|
11868
|
+
console.error('SDK not initialized');
|
|
11869
|
+
return;
|
|
11870
|
+
}
|
|
11871
|
+
}
|
|
11872
|
+
/**
|
|
11873
|
+
*
|
|
11874
|
+
* @param failureType
|
|
11875
|
+
*/
|
|
11876
|
+
function notifyAuthFailure(failureType) {
|
|
11877
|
+
{
|
|
11878
|
+
console.error('SDK not initialized');
|
|
11879
|
+
return;
|
|
11880
|
+
}
|
|
11881
|
+
}
|
|
11882
|
+
/**
|
|
11883
|
+
*
|
|
11884
|
+
*/
|
|
11885
|
+
function notifyLogout() {
|
|
11886
|
+
{
|
|
11887
|
+
console.error('SDK not initialized');
|
|
11888
|
+
return;
|
|
11889
|
+
}
|
|
11890
|
+
}
|
|
11891
|
+
const initSession = (sessionDetails) => {
|
|
11892
|
+
if (sessionInfo == null) {
|
|
11893
|
+
sessionInfo = sessionDetails;
|
|
11894
|
+
initMixpanel(sessionInfo);
|
|
11895
|
+
sessionInfoResolver(sessionInfo);
|
|
11896
|
+
}
|
|
11897
|
+
};
|
|
11898
|
+
const getSessionDetails = (sessionInfoResp) => {
|
|
11899
|
+
console.log('helloooo');
|
|
11900
|
+
const devMixpanelToken = sessionInfoResp.configInfo.mixpanelConfig.devSdkKey;
|
|
11901
|
+
const prodMixpanelToken = sessionInfoResp.configInfo.mixpanelConfig.prodSdkKey;
|
|
11902
|
+
const mixpanelToken = sessionInfoResp.configInfo.mixpanelConfig.production
|
|
11903
|
+
? prodMixpanelToken
|
|
11904
|
+
: devMixpanelToken;
|
|
11905
|
+
return {
|
|
11906
|
+
userGUID: sessionInfoResp.userGUID,
|
|
11907
|
+
mixpanelToken,
|
|
11908
|
+
isPublicUser: sessionInfoResp.configInfo.isPublicUser,
|
|
11909
|
+
releaseVersion: sessionInfoResp.releaseVersion,
|
|
11910
|
+
clusterId: sessionInfoResp.configInfo.selfClusterId,
|
|
11911
|
+
clusterName: sessionInfoResp.configInfo.selfClusterName,
|
|
11912
|
+
...sessionInfoResp,
|
|
11913
|
+
};
|
|
11914
|
+
};
|
|
11915
|
+
/**
|
|
11916
|
+
* Check if we are logged into the ThoughtSpot cluster
|
|
11917
|
+
*
|
|
11918
|
+
* @param thoughtSpotHost The ThoughtSpot cluster hostname or IP
|
|
11919
|
+
*/
|
|
11920
|
+
async function isLoggedIn(thoughtSpotHost) {
|
|
11921
|
+
const authVerificationUrl = `${thoughtSpotHost}${EndPoints.AUTH_VERIFICATION}`;
|
|
11922
|
+
let response = null;
|
|
11923
|
+
try {
|
|
11924
|
+
response = await fetchSessionInfoService(authVerificationUrl);
|
|
11925
|
+
const sessionInfoResp = await response.json();
|
|
11926
|
+
const sessionDetails = getSessionDetails(sessionInfoResp);
|
|
11927
|
+
// Store user session details from session info
|
|
11928
|
+
initSession(sessionDetails);
|
|
11929
|
+
releaseVersion = sessionInfoResp.releaseVersion;
|
|
11930
|
+
}
|
|
11931
|
+
catch (e) {
|
|
11932
|
+
return false;
|
|
11933
|
+
}
|
|
11934
|
+
return response.status === 200;
|
|
11935
|
+
}
|
|
11936
|
+
/**
|
|
11937
|
+
* Return releaseVersion if available
|
|
11938
|
+
*/
|
|
11939
|
+
function getReleaseVersion() {
|
|
11940
|
+
return releaseVersion;
|
|
11941
|
+
}
|
|
11942
|
+
/**
|
|
11943
|
+
* Check if we are stuck at the SSO redirect URL
|
|
11944
|
+
*/
|
|
11945
|
+
function isAtSSORedirectUrl() {
|
|
11946
|
+
return window.location.href.indexOf(SSO_REDIRECTION_MARKER_GUID) >= 0;
|
|
11947
|
+
}
|
|
11948
|
+
/**
|
|
11949
|
+
* Remove the SSO redirect URL marker
|
|
11950
|
+
*/
|
|
11951
|
+
function removeSSORedirectUrlMarker() {
|
|
11952
|
+
// Note (sunny): This will leave a # around even if it was not in the URL
|
|
11953
|
+
// to begin with. Trying to remove the hash by changing window.location will
|
|
11954
|
+
// reload the page which we don't want. We'll live with adding an
|
|
11955
|
+
// unnecessary hash to the parent page URL until we find any use case where
|
|
11956
|
+
// that creates an issue.
|
|
11957
|
+
window.location.hash = window.location.hash.replace(SSO_REDIRECTION_MARKER_GUID, '');
|
|
11958
|
+
}
|
|
11959
|
+
/**
|
|
11960
|
+
* Perform token based authentication
|
|
11961
|
+
*
|
|
11962
|
+
* @param embedConfig The embed configuration
|
|
11963
|
+
*/
|
|
11964
|
+
const doTokenAuth = async (embedConfig) => {
|
|
11965
|
+
const { thoughtSpotHost, username, authEndpoint, getAuthToken, } = embedConfig;
|
|
11966
|
+
if (!authEndpoint && !getAuthToken) {
|
|
11967
|
+
throw new Error('Either auth endpoint or getAuthToken function must be provided');
|
|
11968
|
+
}
|
|
11969
|
+
loggedInStatus = await isLoggedIn(thoughtSpotHost);
|
|
11970
|
+
if (!loggedInStatus) {
|
|
11971
|
+
const authToken = await getAuthenticationToken(embedConfig);
|
|
11972
|
+
let resp;
|
|
11973
|
+
try {
|
|
11974
|
+
resp = await fetchAuthPostService(thoughtSpotHost, username, authToken);
|
|
11975
|
+
}
|
|
11976
|
+
catch (e) {
|
|
11977
|
+
resp = await fetchAuthService(thoughtSpotHost, username, authToken);
|
|
11978
|
+
}
|
|
11979
|
+
// token login issues a 302 when successful
|
|
11980
|
+
loggedInStatus = resp.ok || resp.type === 'opaqueredirect';
|
|
11981
|
+
if (loggedInStatus && embedConfig.detectCookieAccessSlow) {
|
|
11982
|
+
// When 3rd party cookie access is blocked, this will fail because
|
|
11983
|
+
// cookies will not be sent with the call.
|
|
11984
|
+
loggedInStatus = await isLoggedIn(thoughtSpotHost);
|
|
11985
|
+
}
|
|
11986
|
+
}
|
|
11987
|
+
return loggedInStatus;
|
|
11988
|
+
};
|
|
11989
|
+
/**
|
|
11990
|
+
* Validate embedConfig parameters required for cookielessTokenAuth
|
|
11991
|
+
*
|
|
11992
|
+
* @param embedConfig The embed configuration
|
|
11993
|
+
*/
|
|
11994
|
+
const doCookielessTokenAuth = async (embedConfig) => {
|
|
11995
|
+
const { authEndpoint, getAuthToken } = embedConfig;
|
|
11996
|
+
if (!authEndpoint && !getAuthToken) {
|
|
11997
|
+
throw new Error('Either auth endpoint or getAuthToken function must be provided');
|
|
11998
|
+
}
|
|
11999
|
+
try {
|
|
12000
|
+
const authToken = await getAuthenticationToken(embedConfig);
|
|
12001
|
+
if (authToken)
|
|
12002
|
+
return true;
|
|
12003
|
+
}
|
|
12004
|
+
catch {
|
|
12005
|
+
// return false if getAuthenticationToken fails
|
|
12006
|
+
}
|
|
12007
|
+
return false;
|
|
12008
|
+
};
|
|
12009
|
+
/**
|
|
12010
|
+
* Perform basic authentication to the ThoughtSpot cluster using the cluster
|
|
12011
|
+
* credentials.
|
|
12012
|
+
*
|
|
12013
|
+
* Warning: This feature is primarily intended for developer testing. It is
|
|
12014
|
+
* strongly advised not to use this authentication method in production.
|
|
12015
|
+
*
|
|
12016
|
+
* @param embedConfig The embed configuration
|
|
12017
|
+
*/
|
|
12018
|
+
const doBasicAuth = async (embedConfig) => {
|
|
12019
|
+
const { thoughtSpotHost, username, password } = embedConfig;
|
|
12020
|
+
const loggedIn = await isLoggedIn(thoughtSpotHost);
|
|
12021
|
+
if (!loggedIn) {
|
|
12022
|
+
const response = await fetchBasicAuthService(thoughtSpotHost, username, password);
|
|
12023
|
+
loggedInStatus = response.ok;
|
|
12024
|
+
if (embedConfig.detectCookieAccessSlow) {
|
|
12025
|
+
loggedInStatus = await isLoggedIn(thoughtSpotHost);
|
|
12026
|
+
}
|
|
12027
|
+
}
|
|
12028
|
+
else {
|
|
12029
|
+
loggedInStatus = true;
|
|
12030
|
+
}
|
|
12031
|
+
return loggedInStatus;
|
|
12032
|
+
};
|
|
12033
|
+
/**
|
|
12034
|
+
*
|
|
12035
|
+
* @param ssoURL
|
|
12036
|
+
* @param triggerContainer
|
|
12037
|
+
* @param triggerText
|
|
12038
|
+
*/
|
|
12039
|
+
async function samlPopupFlow(ssoURL, triggerContainer, triggerText) {
|
|
12040
|
+
const openPopup = () => {
|
|
12041
|
+
if (samlAuthWindow === null || samlAuthWindow.closed) {
|
|
12042
|
+
samlAuthWindow = window.open(ssoURL, '_blank', 'location=no,height=570,width=520,scrollbars=yes,status=yes');
|
|
12043
|
+
}
|
|
12044
|
+
else {
|
|
12045
|
+
samlAuthWindow.focus();
|
|
12046
|
+
}
|
|
12047
|
+
};
|
|
12048
|
+
const containerEl = getDOMNode(triggerContainer);
|
|
12049
|
+
if (containerEl) {
|
|
12050
|
+
containerEl.innerHTML = '<button id="ts-auth-btn" class="ts-auth-btn" style="margin: auto;"></button>';
|
|
12051
|
+
const authElem = document.getElementById('ts-auth-btn');
|
|
12052
|
+
authElem.textContent = triggerText;
|
|
12053
|
+
authElem.addEventListener('click', openPopup, { once: true });
|
|
12054
|
+
}
|
|
12055
|
+
samlCompletionPromise = samlCompletionPromise
|
|
12056
|
+
|| new Promise((resolve, reject) => {
|
|
12057
|
+
window.addEventListener('message', (e) => {
|
|
12058
|
+
if (e.data.type === EmbedEvent.SAMLComplete) {
|
|
12059
|
+
e.source.close();
|
|
12060
|
+
resolve();
|
|
12061
|
+
}
|
|
12062
|
+
});
|
|
12063
|
+
});
|
|
12064
|
+
return samlCompletionPromise;
|
|
12065
|
+
}
|
|
12066
|
+
/**
|
|
12067
|
+
* Perform SAML authentication
|
|
12068
|
+
*
|
|
12069
|
+
* @param embedConfig The embed configuration
|
|
12070
|
+
* @param ssoEndPoint
|
|
12071
|
+
*/
|
|
12072
|
+
const doSSOAuth = async (embedConfig, ssoEndPoint) => {
|
|
12073
|
+
const { thoughtSpotHost } = embedConfig;
|
|
12074
|
+
const loggedIn = await isLoggedIn(thoughtSpotHost);
|
|
12075
|
+
if (loggedIn) {
|
|
12076
|
+
if (isAtSSORedirectUrl()) {
|
|
12077
|
+
removeSSORedirectUrlMarker();
|
|
12078
|
+
}
|
|
12079
|
+
loggedInStatus = true;
|
|
12080
|
+
return;
|
|
12081
|
+
}
|
|
12082
|
+
// we have already tried authentication and it did not succeed, restore
|
|
12083
|
+
// the current URL to the original one and invoke the callback.
|
|
12084
|
+
if (isAtSSORedirectUrl()) {
|
|
12085
|
+
removeSSORedirectUrlMarker();
|
|
12086
|
+
loggedInStatus = false;
|
|
12087
|
+
return;
|
|
12088
|
+
}
|
|
12089
|
+
const ssoURL = `${thoughtSpotHost}${ssoEndPoint}`;
|
|
12090
|
+
if (embedConfig.inPopup) {
|
|
12091
|
+
await samlPopupFlow(ssoURL, embedConfig.authTriggerContainer, embedConfig.authTriggerText);
|
|
12092
|
+
loggedInStatus = await isLoggedIn(thoughtSpotHost);
|
|
12181
12093
|
return;
|
|
12182
12094
|
}
|
|
12183
|
-
|
|
12095
|
+
window.location.href = ssoURL;
|
|
12096
|
+
};
|
|
12097
|
+
const doSamlAuth = async (embedConfig) => {
|
|
12098
|
+
const { thoughtSpotHost } = embedConfig;
|
|
12099
|
+
// redirect for SSO, when the SSO authentication is done, this page will be
|
|
12100
|
+
// loaded again and the same JS will execute again.
|
|
12101
|
+
const ssoRedirectUrl = embedConfig.inPopup
|
|
12102
|
+
? `${thoughtSpotHost}/v2/#/embed/saml-complete`
|
|
12103
|
+
: getRedirectUrl(window.location.href, SSO_REDIRECTION_MARKER_GUID, embedConfig.redirectPath);
|
|
12104
|
+
// bring back the page to the same URL
|
|
12105
|
+
const ssoEndPoint = `${EndPoints.SAML_LOGIN_TEMPLATE(encodeURIComponent(ssoRedirectUrl))}`;
|
|
12106
|
+
await doSSOAuth(embedConfig, ssoEndPoint);
|
|
12107
|
+
return loggedInStatus;
|
|
12108
|
+
};
|
|
12109
|
+
const doOIDCAuth = async (embedConfig) => {
|
|
12110
|
+
const { thoughtSpotHost } = embedConfig;
|
|
12111
|
+
// redirect for SSO, when the SSO authentication is done, this page will be
|
|
12112
|
+
// loaded again and the same JS will execute again.
|
|
12113
|
+
const ssoRedirectUrl = embedConfig.noRedirect || embedConfig.inPopup
|
|
12114
|
+
? `${thoughtSpotHost}/v2/#/embed/saml-complete`
|
|
12115
|
+
: getRedirectUrl(window.location.href, SSO_REDIRECTION_MARKER_GUID, embedConfig.redirectPath);
|
|
12116
|
+
// bring back the page to the same URL
|
|
12117
|
+
const ssoEndPoint = `${EndPoints.OIDC_LOGIN_TEMPLATE(encodeURIComponent(ssoRedirectUrl))}`;
|
|
12118
|
+
await doSSOAuth(embedConfig, ssoEndPoint);
|
|
12119
|
+
return loggedInStatus;
|
|
12120
|
+
};
|
|
12184
12121
|
/**
|
|
12122
|
+
* Perform authentication on the ThoughtSpot cluster
|
|
12185
12123
|
*
|
|
12186
|
-
* @param
|
|
12124
|
+
* @param embedConfig The embed configuration
|
|
12187
12125
|
*/
|
|
12188
|
-
|
|
12189
|
-
{
|
|
12190
|
-
|
|
12191
|
-
|
|
12126
|
+
const authenticate = async (embedConfig) => {
|
|
12127
|
+
const { authType } = embedConfig;
|
|
12128
|
+
switch (authType) {
|
|
12129
|
+
case AuthType.SSO:
|
|
12130
|
+
case AuthType.SAMLRedirect:
|
|
12131
|
+
case AuthType.SAML:
|
|
12132
|
+
return doSamlAuth(embedConfig);
|
|
12133
|
+
case AuthType.OIDC:
|
|
12134
|
+
case AuthType.OIDCRedirect:
|
|
12135
|
+
return doOIDCAuth(embedConfig);
|
|
12136
|
+
case AuthType.AuthServer:
|
|
12137
|
+
case AuthType.TrustedAuthToken:
|
|
12138
|
+
return doTokenAuth(embedConfig);
|
|
12139
|
+
case AuthType.TrustedAuthTokenCookieless:
|
|
12140
|
+
return doCookielessTokenAuth(embedConfig);
|
|
12141
|
+
case AuthType.Basic:
|
|
12142
|
+
return doBasicAuth(embedConfig);
|
|
12143
|
+
default:
|
|
12144
|
+
return Promise.resolve(true);
|
|
12192
12145
|
}
|
|
12193
|
-
}
|
|
12146
|
+
};
|
|
12147
|
+
|
|
12148
|
+
/* eslint-disable camelcase */
|
|
12149
|
+
let config = {};
|
|
12150
|
+
const CONFIG_DEFAULTS = {
|
|
12151
|
+
loginFailedMessage: 'Not logged in',
|
|
12152
|
+
authTriggerText: 'Authorize',
|
|
12153
|
+
authType: AuthType.None,
|
|
12154
|
+
};
|
|
12155
|
+
let authPromise;
|
|
12194
12156
|
/**
|
|
12157
|
+
* Gets the configuration embed was initialized with.
|
|
12195
12158
|
*
|
|
12159
|
+
* @returns {@link EmbedConfig} The configuration embed was initialized with.
|
|
12160
|
+
* @version SDK: 1.19.0 | ThoughtSpot: *
|
|
12161
|
+
* @group Global methods
|
|
12196
12162
|
*/
|
|
12197
|
-
|
|
12198
|
-
|
|
12199
|
-
|
|
12200
|
-
|
|
12201
|
-
|
|
12202
|
-
|
|
12203
|
-
|
|
12204
|
-
|
|
12205
|
-
|
|
12206
|
-
|
|
12207
|
-
|
|
12208
|
-
|
|
12163
|
+
const getEmbedConfig = () => config;
|
|
12164
|
+
const getAuthPromise = () => authPromise;
|
|
12165
|
+
/**
|
|
12166
|
+
* Perform authentication on the ThoughtSpot app as applicable.
|
|
12167
|
+
*/
|
|
12168
|
+
const handleAuth = () => {
|
|
12169
|
+
authPromise = authenticate(config);
|
|
12170
|
+
authPromise.then((isLoggedIn) => {
|
|
12171
|
+
if (!isLoggedIn) {
|
|
12172
|
+
notifyAuthFailure(AuthFailureType.SDK);
|
|
12173
|
+
}
|
|
12174
|
+
else {
|
|
12175
|
+
notifyAuthSDKSuccess();
|
|
12176
|
+
}
|
|
12177
|
+
}, () => {
|
|
12178
|
+
notifyAuthFailure(AuthFailureType.SDK);
|
|
12179
|
+
});
|
|
12180
|
+
return authPromise;
|
|
12209
12181
|
};
|
|
12210
|
-
const
|
|
12211
|
-
|
|
12212
|
-
|
|
12213
|
-
|
|
12214
|
-
|
|
12215
|
-
: devMixpanelToken;
|
|
12216
|
-
return {
|
|
12217
|
-
userGUID: sessionInfoResp.userGUID,
|
|
12218
|
-
mixpanelToken,
|
|
12219
|
-
isPublicUser: sessionInfoResp.configInfo.isPublicUser,
|
|
12220
|
-
releaseVersion: sessionInfoResp.releaseVersion,
|
|
12221
|
-
clusterId: sessionInfoResp.configInfo.selfClusterId,
|
|
12222
|
-
clusterName: sessionInfoResp.configInfo.selfClusterName,
|
|
12223
|
-
...sessionInfoResp,
|
|
12224
|
-
};
|
|
12182
|
+
const hostUrlToFeatureUrl = {
|
|
12183
|
+
[PrefetchFeatures.SearchEmbed]: (url) => `${url}v2/#/embed/answer`,
|
|
12184
|
+
[PrefetchFeatures.LiveboardEmbed]: (url) => url,
|
|
12185
|
+
[PrefetchFeatures.FullApp]: (url) => url,
|
|
12186
|
+
[PrefetchFeatures.VizEmbed]: (url) => url,
|
|
12225
12187
|
};
|
|
12226
12188
|
/**
|
|
12227
|
-
* Check if we are logged into the ThoughtSpot cluster
|
|
12228
12189
|
*
|
|
12229
|
-
* @param thoughtSpotHost The ThoughtSpot cluster hostname or IP
|
|
12230
|
-
*/
|
|
12231
|
-
async function isLoggedIn(thoughtSpotHost) {
|
|
12232
|
-
const authVerificationUrl = `${thoughtSpotHost}${EndPoints.AUTH_VERIFICATION}`;
|
|
12233
|
-
let response = null;
|
|
12234
|
-
try {
|
|
12235
|
-
response = await fetchSessionInfoService(authVerificationUrl);
|
|
12236
|
-
const sessionInfoResp = await response.json();
|
|
12237
|
-
const sessionDetails = getSessionDetails(sessionInfoResp);
|
|
12238
|
-
// Store user session details from session info
|
|
12239
|
-
initSession(sessionDetails);
|
|
12240
|
-
releaseVersion = sessionInfoResp.releaseVersion;
|
|
12241
|
-
}
|
|
12242
|
-
catch (e) {
|
|
12243
|
-
return false;
|
|
12244
|
-
}
|
|
12245
|
-
return response.status === 200;
|
|
12246
|
-
}
|
|
12247
|
-
/**
|
|
12248
|
-
* Return releaseVersion if available
|
|
12249
12190
|
*/
|
|
12250
|
-
function
|
|
12251
|
-
|
|
12191
|
+
function disableAutoLogin() {
|
|
12192
|
+
config.autoLogin = false;
|
|
12252
12193
|
}
|
|
12253
|
-
|
|
12254
|
-
+ 'See https://developers.thoughtspot.com/docs/?pageid=embed-auth#trusted-auth-embed for more details.';
|
|
12255
|
-
let prevAuthToken = null;
|
|
12194
|
+
let renderQueue = Promise.resolve();
|
|
12256
12195
|
/**
|
|
12196
|
+
* Renders functions in a queue, resolves to next function only after the callback next
|
|
12197
|
+
* is called
|
|
12257
12198
|
*
|
|
12258
|
-
* @param
|
|
12199
|
+
* @param fn The function being registered
|
|
12259
12200
|
*/
|
|
12260
|
-
|
|
12261
|
-
|
|
12262
|
-
|
|
12263
|
-
|
|
12264
|
-
|
|
12201
|
+
const renderInQueue = (fn) => {
|
|
12202
|
+
const { queueMultiRenders = false } = config;
|
|
12203
|
+
if (queueMultiRenders) {
|
|
12204
|
+
renderQueue = renderQueue.then(() => new Promise((res) => fn(res)));
|
|
12205
|
+
return renderQueue;
|
|
12265
12206
|
}
|
|
12266
|
-
|
|
12267
|
-
}
|
|
12207
|
+
// Sending an empty function to keep it consistent with the above usage.
|
|
12208
|
+
return fn(() => { }); // eslint-disable-line @typescript-eslint/no-empty-function
|
|
12209
|
+
};
|
|
12210
|
+
|
|
12211
|
+
const tokenizedFetch = async (input, init) => {
|
|
12212
|
+
const req = new Request(input, init);
|
|
12213
|
+
const embedConfig = getEmbedConfig();
|
|
12214
|
+
if (embedConfig.authType !== AuthType.TrustedAuthTokenCookieless) {
|
|
12215
|
+
return fetch(req);
|
|
12216
|
+
}
|
|
12217
|
+
const authToken = await getAuthenticationToken(embedConfig);
|
|
12218
|
+
if (authToken) {
|
|
12219
|
+
req.headers.append('Authorization', `Bearer ${authToken}`);
|
|
12220
|
+
}
|
|
12221
|
+
return fetch(req);
|
|
12222
|
+
};
|
|
12223
|
+
|
|
12268
12224
|
/**
|
|
12269
|
-
*
|
|
12225
|
+
*
|
|
12226
|
+
* @param root0
|
|
12227
|
+
* @param root0.query
|
|
12228
|
+
* @param root0.variables
|
|
12229
|
+
* @param root0.thoughtSpotHost
|
|
12230
|
+
* @param root0.isCompositeQuery
|
|
12270
12231
|
*/
|
|
12271
|
-
function
|
|
12272
|
-
|
|
12273
|
-
|
|
12232
|
+
async function graphqlQuery({ query, variables, thoughtSpotHost, isCompositeQuery = false, }) {
|
|
12233
|
+
const operationName = getOperationNameFromQuery(query);
|
|
12234
|
+
try {
|
|
12235
|
+
const response = await fetch(`${thoughtSpotHost}/prism/?op=${operationName}`, {
|
|
12236
|
+
method: 'POST',
|
|
12237
|
+
headers: {
|
|
12238
|
+
'content-type': 'application/json;charset=UTF-8',
|
|
12239
|
+
'x-requested-by': 'ThoughtSpot',
|
|
12240
|
+
accept: '*/*',
|
|
12241
|
+
'accept-language': 'en-us',
|
|
12242
|
+
},
|
|
12243
|
+
body: JSON.stringify({
|
|
12244
|
+
operationName,
|
|
12245
|
+
query,
|
|
12246
|
+
variables,
|
|
12247
|
+
}),
|
|
12248
|
+
credentials: 'include',
|
|
12249
|
+
});
|
|
12250
|
+
const result = await response.json();
|
|
12251
|
+
const dataValues = Object.values(result.data);
|
|
12252
|
+
return (isCompositeQuery) ? result.data : dataValues[0];
|
|
12253
|
+
}
|
|
12254
|
+
catch (error) {
|
|
12255
|
+
return error;
|
|
12256
|
+
}
|
|
12257
|
+
}
|
|
12258
|
+
|
|
12259
|
+
const getSourceDetailQuery = `
|
|
12260
|
+
query GetSourceDetail($ids: [GUID!]!) {
|
|
12261
|
+
getSourceDetailById(ids: $ids, type: LOGICAL_TABLE) {
|
|
12262
|
+
id
|
|
12263
|
+
name
|
|
12264
|
+
description
|
|
12265
|
+
authorName
|
|
12266
|
+
authorDisplayName
|
|
12267
|
+
isExternal
|
|
12268
|
+
type
|
|
12269
|
+
created
|
|
12270
|
+
modified
|
|
12271
|
+
columns {
|
|
12272
|
+
id
|
|
12273
|
+
name
|
|
12274
|
+
author
|
|
12275
|
+
authorDisplayName
|
|
12276
|
+
description
|
|
12277
|
+
dataType
|
|
12278
|
+
type
|
|
12279
|
+
modified
|
|
12280
|
+
ownerName
|
|
12281
|
+
owner
|
|
12282
|
+
dataRecency
|
|
12283
|
+
sources {
|
|
12284
|
+
tableId
|
|
12285
|
+
tableName
|
|
12286
|
+
columnId
|
|
12287
|
+
columnName
|
|
12288
|
+
__typename
|
|
12289
|
+
}
|
|
12290
|
+
synonyms
|
|
12291
|
+
cohortAnswerId
|
|
12292
|
+
__typename
|
|
12293
|
+
}
|
|
12294
|
+
relationships
|
|
12295
|
+
destinationRelationships
|
|
12296
|
+
dataSourceId
|
|
12297
|
+
__typename
|
|
12298
|
+
}
|
|
12299
|
+
}
|
|
12300
|
+
`;
|
|
12301
|
+
const sourceDetailCache = new Map();
|
|
12274
12302
|
/**
|
|
12275
|
-
*
|
|
12303
|
+
*
|
|
12304
|
+
* @param thoughtSpotHost
|
|
12305
|
+
* @param sourceId
|
|
12276
12306
|
*/
|
|
12277
|
-
function
|
|
12278
|
-
|
|
12279
|
-
|
|
12280
|
-
// reload the page which we don't want. We'll live with adding an
|
|
12281
|
-
// unnecessary hash to the parent page URL until we find any use case where
|
|
12282
|
-
// that creates an issue.
|
|
12283
|
-
window.location.hash = window.location.hash.replace(SSO_REDIRECTION_MARKER_GUID, '');
|
|
12284
|
-
}
|
|
12285
|
-
const getAuthenticationToken = async (embedConfig) => {
|
|
12286
|
-
const { authEndpoint, getAuthToken } = embedConfig;
|
|
12287
|
-
let authToken = null;
|
|
12288
|
-
if (getAuthToken) {
|
|
12289
|
-
authToken = await getAuthToken();
|
|
12290
|
-
alertForDuplicateToken(authToken);
|
|
12307
|
+
async function getSourceDetail(thoughtSpotHost, sourceId) {
|
|
12308
|
+
if (sourceDetailCache.get(sourceId)) {
|
|
12309
|
+
return sourceDetailCache.get(sourceId);
|
|
12291
12310
|
}
|
|
12292
|
-
|
|
12293
|
-
|
|
12294
|
-
|
|
12311
|
+
const details = await graphqlQuery({
|
|
12312
|
+
query: getSourceDetailQuery,
|
|
12313
|
+
variables: {
|
|
12314
|
+
ids: [sourceId],
|
|
12315
|
+
},
|
|
12316
|
+
thoughtSpotHost,
|
|
12317
|
+
});
|
|
12318
|
+
const souceDetails = details[0];
|
|
12319
|
+
if (souceDetails) {
|
|
12320
|
+
sourceDetailCache.set(sourceId, souceDetails);
|
|
12295
12321
|
}
|
|
12296
|
-
return
|
|
12297
|
-
}
|
|
12322
|
+
return souceDetails;
|
|
12323
|
+
}
|
|
12324
|
+
|
|
12325
|
+
const bachSessionId = `
|
|
12326
|
+
id {
|
|
12327
|
+
sessionId
|
|
12328
|
+
genNo
|
|
12329
|
+
acSession {
|
|
12330
|
+
sessionId
|
|
12331
|
+
genNo
|
|
12332
|
+
}
|
|
12333
|
+
}
|
|
12334
|
+
`;
|
|
12335
|
+
const getUnaggregatedAnswerSession = `
|
|
12336
|
+
mutation GetUnAggregatedAnswerSession($session: BachSessionIdInput!, $columns: [UserPointSelectionInput!]!) {
|
|
12337
|
+
Answer__getUnaggregatedAnswer(session: $session, columns: $columns) {
|
|
12338
|
+
${bachSessionId}
|
|
12339
|
+
answer {
|
|
12340
|
+
visualizations {
|
|
12341
|
+
... on TableViz {
|
|
12342
|
+
columns {
|
|
12343
|
+
column {
|
|
12344
|
+
id
|
|
12345
|
+
name
|
|
12346
|
+
referencedColumns {
|
|
12347
|
+
guid
|
|
12348
|
+
displayName
|
|
12349
|
+
}
|
|
12350
|
+
}
|
|
12351
|
+
}
|
|
12352
|
+
}
|
|
12353
|
+
}
|
|
12354
|
+
}
|
|
12355
|
+
}
|
|
12356
|
+
}
|
|
12357
|
+
`;
|
|
12358
|
+
const removeColumns = `
|
|
12359
|
+
mutation RemoveColumns($session: BachSessionIdInput!, $logicalColumnIds: [GUID!], $columnIds: [GUID!]) {
|
|
12360
|
+
Answer__removeColumns(
|
|
12361
|
+
session: $session
|
|
12362
|
+
logicalColumnIds: $logicalColumnIds
|
|
12363
|
+
columnIds: $columnIds
|
|
12364
|
+
) {
|
|
12365
|
+
${bachSessionId}
|
|
12366
|
+
}
|
|
12367
|
+
}
|
|
12368
|
+
`;
|
|
12369
|
+
const addColumns = `
|
|
12370
|
+
mutation AddColumns($session: BachSessionIdInput!, $columns: [AnswerColumnInfo!]!) {
|
|
12371
|
+
Answer__addColumn(session: $session, columns: $columns) {
|
|
12372
|
+
${bachSessionId}
|
|
12373
|
+
}
|
|
12374
|
+
}
|
|
12375
|
+
`;
|
|
12376
|
+
const getAnswerData = `
|
|
12377
|
+
query GetTableWithHeadlineData($session: BachSessionIdInput!, $deadline: Int!, $dataPaginationParams: DataPaginationParamsInput!) {
|
|
12378
|
+
getAnswer(session: $session) {
|
|
12379
|
+
${bachSessionId}
|
|
12380
|
+
answer {
|
|
12381
|
+
id
|
|
12382
|
+
visualizations {
|
|
12383
|
+
id
|
|
12384
|
+
... on TableViz {
|
|
12385
|
+
columns {
|
|
12386
|
+
column {
|
|
12387
|
+
id
|
|
12388
|
+
name
|
|
12389
|
+
type
|
|
12390
|
+
aggregationType
|
|
12391
|
+
dataType
|
|
12392
|
+
}
|
|
12393
|
+
}
|
|
12394
|
+
data(deadline: $deadline, pagination: $dataPaginationParams)
|
|
12395
|
+
}
|
|
12396
|
+
}
|
|
12397
|
+
}
|
|
12398
|
+
}
|
|
12399
|
+
}
|
|
12400
|
+
`;
|
|
12401
|
+
|
|
12402
|
+
// eslint-disable-next-line no-shadow
|
|
12403
|
+
var OperationType;
|
|
12404
|
+
(function (OperationType) {
|
|
12405
|
+
OperationType["GetChartWithData"] = "GetChartWithData";
|
|
12406
|
+
OperationType["GetTableWithHeadlineData"] = "GetTableWithHeadlineData";
|
|
12407
|
+
})(OperationType || (OperationType = {}));
|
|
12298
12408
|
/**
|
|
12299
|
-
*
|
|
12409
|
+
* Class representing the answer service provided with the
|
|
12410
|
+
* custom action payload. This service could be used to run
|
|
12411
|
+
* graphql queries in the context of the answer on which the
|
|
12412
|
+
* custom action was triggered.
|
|
12300
12413
|
*
|
|
12301
|
-
* @
|
|
12414
|
+
* @example
|
|
12415
|
+
* ```js
|
|
12416
|
+
* embed.on(EmbedEvent.CustomAction, e => {
|
|
12417
|
+
* const underlying = await e.answerService.getUnderlyingDataForPoint([
|
|
12418
|
+
* 'col name 1'
|
|
12419
|
+
* ]);
|
|
12420
|
+
* const data = await underlying.fetchData(0, 100);
|
|
12421
|
+
* })
|
|
12422
|
+
* ```
|
|
12423
|
+
* @version
|
|
12424
|
+
* ThoughtSpot: 9.9.0.cl / SDK: 1.25.0
|
|
12425
|
+
* @group Events
|
|
12302
12426
|
*/
|
|
12303
|
-
|
|
12304
|
-
|
|
12305
|
-
|
|
12306
|
-
|
|
12427
|
+
class AnswerService {
|
|
12428
|
+
constructor(session, answer, thoughtSpotHost, selectedPoints) {
|
|
12429
|
+
this.session = session;
|
|
12430
|
+
this.answer = answer;
|
|
12431
|
+
this.thoughtSpotHost = thoughtSpotHost;
|
|
12432
|
+
this.selectedPoints = selectedPoints;
|
|
12433
|
+
this.session = removeTypename(session);
|
|
12307
12434
|
}
|
|
12308
|
-
|
|
12309
|
-
|
|
12310
|
-
|
|
12311
|
-
let resp;
|
|
12312
|
-
try {
|
|
12313
|
-
resp = await fetchAuthPostService(thoughtSpotHost, username, authToken);
|
|
12314
|
-
}
|
|
12315
|
-
catch (e) {
|
|
12316
|
-
resp = await fetchAuthService(thoughtSpotHost, username, authToken);
|
|
12317
|
-
}
|
|
12318
|
-
// token login issues a 302 when successful
|
|
12319
|
-
loggedInStatus = resp.ok || resp.type === 'opaqueredirect';
|
|
12320
|
-
if (loggedInStatus && embedConfig.detectCookieAccessSlow) {
|
|
12321
|
-
// When 3rd party cookie access is blocked, this will fail because
|
|
12322
|
-
// cookies will not be sent with the call.
|
|
12323
|
-
loggedInStatus = await isLoggedIn(thoughtSpotHost);
|
|
12324
|
-
}
|
|
12435
|
+
async getSourceDetail() {
|
|
12436
|
+
const sourceId = this.answer.sources[0].header.guid;
|
|
12437
|
+
return getSourceDetail(this.thoughtSpotHost, sourceId);
|
|
12325
12438
|
}
|
|
12326
|
-
|
|
12327
|
-
|
|
12328
|
-
|
|
12329
|
-
|
|
12330
|
-
*
|
|
12331
|
-
* @param embedConfig The embed configuration
|
|
12332
|
-
*/
|
|
12333
|
-
const doCookielessTokenAuth = async (embedConfig) => {
|
|
12334
|
-
const { authEndpoint, getAuthToken } = embedConfig;
|
|
12335
|
-
if (!authEndpoint && !getAuthToken) {
|
|
12336
|
-
throw new Error('Either auth endpoint or getAuthToken function must be provided');
|
|
12439
|
+
async removeColumns(columnIds) {
|
|
12440
|
+
return this.executeQuery(removeColumns, {
|
|
12441
|
+
logicalColumnIds: columnIds,
|
|
12442
|
+
});
|
|
12337
12443
|
}
|
|
12338
|
-
|
|
12339
|
-
|
|
12340
|
-
|
|
12341
|
-
|
|
12342
|
-
return false;
|
|
12444
|
+
async addColumns(columnIds) {
|
|
12445
|
+
return this.executeQuery(addColumns, {
|
|
12446
|
+
columns: columnIds.map((colId) => ({ logicalColumnId: colId })),
|
|
12447
|
+
});
|
|
12343
12448
|
}
|
|
12344
|
-
|
|
12345
|
-
|
|
12449
|
+
async fetchData(offset = 0, size = 1000) {
|
|
12450
|
+
const { answer } = await this.executeQuery(getAnswerData, {
|
|
12451
|
+
deadline: 0,
|
|
12452
|
+
dataPaginationParams: {
|
|
12453
|
+
isClientPaginated: true,
|
|
12454
|
+
offset,
|
|
12455
|
+
size,
|
|
12456
|
+
},
|
|
12457
|
+
});
|
|
12458
|
+
const { columns, data } = answer.visualizations[0];
|
|
12459
|
+
return {
|
|
12460
|
+
columns,
|
|
12461
|
+
data,
|
|
12462
|
+
};
|
|
12346
12463
|
}
|
|
12347
|
-
|
|
12348
|
-
|
|
12349
|
-
|
|
12350
|
-
|
|
12351
|
-
|
|
12352
|
-
|
|
12353
|
-
|
|
12354
|
-
|
|
12355
|
-
|
|
12356
|
-
|
|
12357
|
-
|
|
12358
|
-
const doBasicAuth = async (embedConfig) => {
|
|
12359
|
-
const { thoughtSpotHost, username, password } = embedConfig;
|
|
12360
|
-
const loggedIn = await isLoggedIn(thoughtSpotHost);
|
|
12361
|
-
if (!loggedIn) {
|
|
12362
|
-
const response = await fetchBasicAuthService(thoughtSpotHost, username, password);
|
|
12363
|
-
loggedInStatus = response.ok;
|
|
12364
|
-
if (embedConfig.detectCookieAccessSlow) {
|
|
12365
|
-
loggedInStatus = await isLoggedIn(thoughtSpotHost);
|
|
12366
|
-
}
|
|
12464
|
+
/**
|
|
12465
|
+
*
|
|
12466
|
+
* @param userLocale
|
|
12467
|
+
* @param includeInfo Include the CSV header in the output
|
|
12468
|
+
* @returns Response
|
|
12469
|
+
*/
|
|
12470
|
+
async fetchCSVBlob(userLocale = 'en-us', includeInfo = false) {
|
|
12471
|
+
const fetchUrl = this.getFetchCSVBlobUrl(userLocale, includeInfo);
|
|
12472
|
+
return tokenizedFetch(fetchUrl, {
|
|
12473
|
+
credentials: 'include',
|
|
12474
|
+
});
|
|
12367
12475
|
}
|
|
12368
|
-
|
|
12369
|
-
|
|
12476
|
+
getFetchCSVBlobUrl(userLocale = 'en-us', includeInfo = false) {
|
|
12477
|
+
return `${this.thoughtSpotHost}/prism/download/answer/csv?sessionId=${this.session.sessionId}&genNo=${this.session.genNo}&userLocale=${userLocale}&exportFileName=data&hideCsvHeader=${!includeInfo}`;
|
|
12370
12478
|
}
|
|
12371
|
-
|
|
12372
|
-
|
|
12373
|
-
|
|
12374
|
-
|
|
12375
|
-
|
|
12376
|
-
|
|
12377
|
-
|
|
12378
|
-
|
|
12379
|
-
|
|
12380
|
-
|
|
12381
|
-
|
|
12382
|
-
|
|
12479
|
+
/**
|
|
12480
|
+
* Get underlying data given a point and the output column names.
|
|
12481
|
+
*
|
|
12482
|
+
* @param outputColumnNames
|
|
12483
|
+
* @param selectedPoints
|
|
12484
|
+
* @example
|
|
12485
|
+
* ```js
|
|
12486
|
+
* embed.on(EmbedEvent.CustomAction, e => {
|
|
12487
|
+
* const underlying = await e.answerService.getUnderlyingDataForPoint([
|
|
12488
|
+
* 'col name 1' // The column should exist in the data source.
|
|
12489
|
+
* ]);
|
|
12490
|
+
* const data = await underlying.fetchData(0, 100);
|
|
12491
|
+
* })
|
|
12492
|
+
* ```
|
|
12493
|
+
* @version
|
|
12494
|
+
* ThoughtSpot: 9.9.0.cl / SDK: 1.25.0
|
|
12495
|
+
*/
|
|
12496
|
+
async getUnderlyingDataForPoint(outputColumnNames, selectedPoints) {
|
|
12497
|
+
if (!selectedPoints && !this.selectedPoints) {
|
|
12498
|
+
throw new Error('Needs to be triggered in context of a point');
|
|
12383
12499
|
}
|
|
12384
|
-
|
|
12385
|
-
|
|
12500
|
+
if (!selectedPoints) {
|
|
12501
|
+
selectedPoints = getSelectedPointsForUnderlyingDataQuery(this.selectedPoints);
|
|
12386
12502
|
}
|
|
12387
|
-
|
|
12388
|
-
|
|
12389
|
-
|
|
12390
|
-
|
|
12391
|
-
|
|
12392
|
-
|
|
12393
|
-
|
|
12394
|
-
|
|
12395
|
-
|
|
12396
|
-
|| new Promise((resolve, reject) => {
|
|
12397
|
-
window.addEventListener('message', (e) => {
|
|
12398
|
-
if (e.data.type === EmbedEvent.SAMLComplete) {
|
|
12399
|
-
e.source.close();
|
|
12400
|
-
resolve();
|
|
12401
|
-
}
|
|
12402
|
-
});
|
|
12503
|
+
const sourceDetail = await this.getSourceDetail();
|
|
12504
|
+
const ouputColumnGuids = getGuidsFromColumnNames(sourceDetail, outputColumnNames);
|
|
12505
|
+
const unAggAnswer = await graphqlQuery({
|
|
12506
|
+
query: getUnaggregatedAnswerSession,
|
|
12507
|
+
variables: {
|
|
12508
|
+
session: this.session,
|
|
12509
|
+
columns: selectedPoints,
|
|
12510
|
+
},
|
|
12511
|
+
thoughtSpotHost: this.thoughtSpotHost,
|
|
12403
12512
|
});
|
|
12404
|
-
|
|
12405
|
-
|
|
12406
|
-
|
|
12407
|
-
|
|
12408
|
-
|
|
12409
|
-
|
|
12410
|
-
* @param ssoEndPoint
|
|
12411
|
-
*/
|
|
12412
|
-
const doSSOAuth = async (embedConfig, ssoEndPoint) => {
|
|
12413
|
-
const { thoughtSpotHost } = embedConfig;
|
|
12414
|
-
const loggedIn = await isLoggedIn(thoughtSpotHost);
|
|
12415
|
-
if (loggedIn) {
|
|
12416
|
-
if (isAtSSORedirectUrl()) {
|
|
12417
|
-
removeSSORedirectUrlMarker();
|
|
12513
|
+
const unaggAnswerSession = new AnswerService(unAggAnswer.id, unAggAnswer.answer, this.thoughtSpotHost);
|
|
12514
|
+
const currentColumns = new Set(unAggAnswer.answer.visualizations[0].columns
|
|
12515
|
+
.map((c) => c.column.referencedColumns[0].guid));
|
|
12516
|
+
const columnsToAdd = [...ouputColumnGuids].filter((col) => !currentColumns.has(col));
|
|
12517
|
+
if (columnsToAdd.length) {
|
|
12518
|
+
await unaggAnswerSession.addColumns(columnsToAdd);
|
|
12418
12519
|
}
|
|
12419
|
-
|
|
12420
|
-
|
|
12520
|
+
const columnsToRemove = [...currentColumns].filter((col) => !ouputColumnGuids.has(col));
|
|
12521
|
+
if (columnsToRemove.length) {
|
|
12522
|
+
await unaggAnswerSession.removeColumns(columnsToRemove);
|
|
12523
|
+
}
|
|
12524
|
+
return unaggAnswerSession;
|
|
12421
12525
|
}
|
|
12422
|
-
|
|
12423
|
-
|
|
12424
|
-
|
|
12425
|
-
|
|
12426
|
-
|
|
12427
|
-
|
|
12526
|
+
async executeQuery(query, variables) {
|
|
12527
|
+
const data = await graphqlQuery({
|
|
12528
|
+
query,
|
|
12529
|
+
variables: {
|
|
12530
|
+
session: this.session,
|
|
12531
|
+
...variables,
|
|
12532
|
+
},
|
|
12533
|
+
thoughtSpotHost: this.thoughtSpotHost,
|
|
12534
|
+
isCompositeQuery: false,
|
|
12535
|
+
});
|
|
12536
|
+
this.session = deepMerge(this.session, (data === null || data === void 0 ? void 0 : data.id) || {});
|
|
12537
|
+
return data;
|
|
12428
12538
|
}
|
|
12429
|
-
|
|
12430
|
-
|
|
12431
|
-
await samlPopupFlow(ssoURL, embedConfig.authTriggerContainer, embedConfig.authTriggerText);
|
|
12432
|
-
loggedInStatus = await isLoggedIn(thoughtSpotHost);
|
|
12433
|
-
return;
|
|
12539
|
+
getSession() {
|
|
12540
|
+
return this.session;
|
|
12434
12541
|
}
|
|
12435
|
-
|
|
12436
|
-
};
|
|
12437
|
-
const doSamlAuth = async (embedConfig) => {
|
|
12438
|
-
const { thoughtSpotHost } = embedConfig;
|
|
12439
|
-
// redirect for SSO, when the SSO authentication is done, this page will be
|
|
12440
|
-
// loaded again and the same JS will execute again.
|
|
12441
|
-
const ssoRedirectUrl = embedConfig.inPopup
|
|
12442
|
-
? `${thoughtSpotHost}/v2/#/embed/saml-complete`
|
|
12443
|
-
: getRedirectUrl(window.location.href, SSO_REDIRECTION_MARKER_GUID, embedConfig.redirectPath);
|
|
12444
|
-
// bring back the page to the same URL
|
|
12445
|
-
const ssoEndPoint = `${EndPoints.SAML_LOGIN_TEMPLATE(encodeURIComponent(ssoRedirectUrl))}`;
|
|
12446
|
-
await doSSOAuth(embedConfig, ssoEndPoint);
|
|
12447
|
-
return loggedInStatus;
|
|
12448
|
-
};
|
|
12449
|
-
const doOIDCAuth = async (embedConfig) => {
|
|
12450
|
-
const { thoughtSpotHost } = embedConfig;
|
|
12451
|
-
// redirect for SSO, when the SSO authentication is done, this page will be
|
|
12452
|
-
// loaded again and the same JS will execute again.
|
|
12453
|
-
const ssoRedirectUrl = embedConfig.noRedirect || embedConfig.inPopup
|
|
12454
|
-
? `${thoughtSpotHost}/v2/#/embed/saml-complete`
|
|
12455
|
-
: getRedirectUrl(window.location.href, SSO_REDIRECTION_MARKER_GUID, embedConfig.redirectPath);
|
|
12456
|
-
// bring back the page to the same URL
|
|
12457
|
-
const ssoEndPoint = `${EndPoints.OIDC_LOGIN_TEMPLATE(encodeURIComponent(ssoRedirectUrl))}`;
|
|
12458
|
-
await doSSOAuth(embedConfig, ssoEndPoint);
|
|
12459
|
-
return loggedInStatus;
|
|
12460
|
-
};
|
|
12542
|
+
}
|
|
12461
12543
|
/**
|
|
12462
|
-
* Perform authentication on the ThoughtSpot cluster
|
|
12463
12544
|
*
|
|
12464
|
-
* @param
|
|
12545
|
+
* @param sourceDetail
|
|
12546
|
+
* @param colNames
|
|
12465
12547
|
*/
|
|
12466
|
-
|
|
12467
|
-
const
|
|
12468
|
-
|
|
12469
|
-
|
|
12470
|
-
|
|
12471
|
-
|
|
12472
|
-
|
|
12473
|
-
|
|
12474
|
-
|
|
12475
|
-
|
|
12476
|
-
case AuthType.AuthServer:
|
|
12477
|
-
case AuthType.TrustedAuthToken:
|
|
12478
|
-
return doTokenAuth(embedConfig);
|
|
12479
|
-
case AuthType.TrustedAuthTokenCookieless:
|
|
12480
|
-
return doCookielessTokenAuth(embedConfig);
|
|
12481
|
-
case AuthType.Basic:
|
|
12482
|
-
return doBasicAuth(embedConfig);
|
|
12483
|
-
default:
|
|
12484
|
-
return Promise.resolve(true);
|
|
12485
|
-
}
|
|
12486
|
-
};
|
|
12487
|
-
|
|
12488
|
-
/* eslint-disable camelcase */
|
|
12489
|
-
let config = {};
|
|
12490
|
-
const CONFIG_DEFAULTS = {
|
|
12491
|
-
loginFailedMessage: 'Not logged in',
|
|
12492
|
-
authTriggerText: 'Authorize',
|
|
12493
|
-
authType: AuthType.None,
|
|
12494
|
-
};
|
|
12495
|
-
let authPromise;
|
|
12548
|
+
function getGuidsFromColumnNames(sourceDetail, colNames) {
|
|
12549
|
+
const cols = sourceDetail.columns.reduce((colSet, col) => {
|
|
12550
|
+
colSet[col.name] = col;
|
|
12551
|
+
return colSet;
|
|
12552
|
+
}, {});
|
|
12553
|
+
return new Set(colNames.map((colName) => {
|
|
12554
|
+
const col = cols[colName];
|
|
12555
|
+
return col.id;
|
|
12556
|
+
}));
|
|
12557
|
+
}
|
|
12496
12558
|
/**
|
|
12497
|
-
* Gets the configuration embed was initialized with.
|
|
12498
12559
|
*
|
|
12499
|
-
* @
|
|
12500
|
-
* @version SDK: 1.19.0 | ThoughtSpot: *
|
|
12501
|
-
* @group Global methods
|
|
12502
|
-
*/
|
|
12503
|
-
const getEmbedConfig = () => config;
|
|
12504
|
-
const getAuthPromise = () => authPromise;
|
|
12505
|
-
/**
|
|
12506
|
-
* Perform authentication on the ThoughtSpot app as applicable.
|
|
12560
|
+
* @param selectedPoints
|
|
12507
12561
|
*/
|
|
12508
|
-
|
|
12509
|
-
|
|
12510
|
-
|
|
12511
|
-
|
|
12512
|
-
|
|
12562
|
+
function getSelectedPointsForUnderlyingDataQuery(selectedPoints) {
|
|
12563
|
+
const underlyingDataPoint = [];
|
|
12564
|
+
/**
|
|
12565
|
+
*
|
|
12566
|
+
* @param colVal
|
|
12567
|
+
*/
|
|
12568
|
+
function addPointFromColVal(colVal) {
|
|
12569
|
+
var _a;
|
|
12570
|
+
const dataType = colVal.column.dataType;
|
|
12571
|
+
const id = colVal.column.id;
|
|
12572
|
+
let dataValue;
|
|
12573
|
+
if (dataType === 'DATE') {
|
|
12574
|
+
if (Number.isFinite(colVal.value)) {
|
|
12575
|
+
dataValue = [{
|
|
12576
|
+
epochRange: {
|
|
12577
|
+
startEpoch: colVal.value,
|
|
12578
|
+
},
|
|
12579
|
+
}];
|
|
12580
|
+
// Case for custom calendar.
|
|
12581
|
+
}
|
|
12582
|
+
else if ((_a = colVal.value) === null || _a === void 0 ? void 0 : _a.v) {
|
|
12583
|
+
dataValue = [{
|
|
12584
|
+
epochRange: {
|
|
12585
|
+
startEpoch: colVal.value.v.s,
|
|
12586
|
+
endEpoch: colVal.value.v.e,
|
|
12587
|
+
},
|
|
12588
|
+
}];
|
|
12589
|
+
}
|
|
12513
12590
|
}
|
|
12514
12591
|
else {
|
|
12515
|
-
|
|
12592
|
+
dataValue = [{ value: colVal.value }];
|
|
12516
12593
|
}
|
|
12517
|
-
|
|
12518
|
-
|
|
12519
|
-
|
|
12520
|
-
|
|
12521
|
-
};
|
|
12522
|
-
const hostUrlToFeatureUrl = {
|
|
12523
|
-
[PrefetchFeatures.SearchEmbed]: (url) => `${url}v2/#/embed/answer`,
|
|
12524
|
-
[PrefetchFeatures.LiveboardEmbed]: (url) => url,
|
|
12525
|
-
[PrefetchFeatures.FullApp]: (url) => url,
|
|
12526
|
-
[PrefetchFeatures.VizEmbed]: (url) => url,
|
|
12527
|
-
};
|
|
12528
|
-
/**
|
|
12529
|
-
*
|
|
12530
|
-
*/
|
|
12531
|
-
function disableAutoLogin() {
|
|
12532
|
-
config.autoLogin = false;
|
|
12533
|
-
}
|
|
12534
|
-
let renderQueue = Promise.resolve();
|
|
12535
|
-
/**
|
|
12536
|
-
* Renders functions in a queue, resolves to next function only after the callback next
|
|
12537
|
-
* is called
|
|
12538
|
-
*
|
|
12539
|
-
* @param fn The function being registered
|
|
12540
|
-
*/
|
|
12541
|
-
const renderInQueue = (fn) => {
|
|
12542
|
-
const { queueMultiRenders = false } = config;
|
|
12543
|
-
if (queueMultiRenders) {
|
|
12544
|
-
renderQueue = renderQueue.then(() => new Promise((res) => fn(res)));
|
|
12545
|
-
return renderQueue;
|
|
12594
|
+
underlyingDataPoint.push({
|
|
12595
|
+
columnId: colVal.column.id,
|
|
12596
|
+
dataValue,
|
|
12597
|
+
});
|
|
12546
12598
|
}
|
|
12547
|
-
|
|
12548
|
-
|
|
12549
|
-
};
|
|
12599
|
+
selectedPoints.forEach((p) => {
|
|
12600
|
+
p.selectedAttributes.forEach(addPointFromColVal);
|
|
12601
|
+
});
|
|
12602
|
+
return underlyingDataPoint;
|
|
12603
|
+
}
|
|
12550
12604
|
|
|
12551
12605
|
/**
|
|
12552
12606
|
*
|
|
@@ -12584,9 +12638,9 @@ function processAuthInit(e) {
|
|
|
12584
12638
|
* @param containerEl
|
|
12585
12639
|
*/
|
|
12586
12640
|
function processNoCookieAccess(e, containerEl) {
|
|
12587
|
-
const { loginFailedMessage, suppressNoCookieAccessAlert, ignoreNoCookieAccess, } = getEmbedConfig();
|
|
12641
|
+
const { loginFailedMessage, suppressNoCookieAccessAlert, ignoreNoCookieAccess, suppressErrorAlerts, } = getEmbedConfig();
|
|
12588
12642
|
if (!ignoreNoCookieAccess) {
|
|
12589
|
-
if (!suppressNoCookieAccessAlert) {
|
|
12643
|
+
if (!suppressNoCookieAccessAlert && !suppressErrorAlerts) {
|
|
12590
12644
|
// eslint-disable-next-line no-alert
|
|
12591
12645
|
alert('Third party cookie access is blocked on this browser, please allow third party cookies for this to work properly. \nYou can use `suppressNoCookieAccessAlert` to suppress this message.');
|
|
12592
12646
|
}
|
|
@@ -12704,7 +12758,7 @@ function processTrigger(iFrame, messageType, thoughtSpotHost, data) {
|
|
|
12704
12758
|
});
|
|
12705
12759
|
}
|
|
12706
12760
|
|
|
12707
|
-
var name="@thoughtspot/visual-embed-sdk";var version="1.
|
|
12761
|
+
var name="@thoughtspot/visual-embed-sdk";var version="1.26.0-token-cache.0";var description="ThoughtSpot Embed SDK";var module="lib/src/index.js";var main="dist/tsembed.js";var types="lib/src/index.d.ts";var files=["dist/**","lib/**","src/**","cjs/**"];var exports={".":{"import":"./lib/src/index.js",require:"./cjs/src/index.js",types:"./lib/src/index.d.ts"},"./react":{"import":"./lib/src/react/all-types-export.js",require:"./cjs/src/react/all-types-export.js",types:"./lib/src/react/all-types-export.d.ts"},"./lib/src/react":{"import":"./lib/src/react/all-types-export.js",require:"./cjs/src/react/all-types-export.js",types:"./lib/src/react/all-types-export.d.ts"}};var typesVersions={"*":{react:["./lib/src/react/all-types-export.d.ts"]}};var scripts={lint:"eslint 'src/**'","lint:fix":"eslint 'src/**/*.*' --fix",tsc:"tsc -p . --incremental false; tsc -p . --incremental false --module commonjs --outDir cjs",start:"gatsby develop","build:gatsby":"npm run clean:gatsby && gatsby build --prefix-paths","build:gatsby:noprefix":"npm run clean:gatsby && gatsby build","serve:gatsby":"gatsby serve","clean:gatsby":"gatsby clean","build-and-publish":"npm run build:gatsby && npm run publish","bundle-dts-file":"dts-bundle --name @thoughtspot/visual-embed-sdk --out visual-embed-sdk.d.ts --main lib/src/index.d.ts","bundle-dts":"dts-bundle --name ../../dist/visual-embed-sdk --main lib/src/index.d.ts --outputAsModuleFolder=true","bundle-dts-react":"dts-bundle --name ../../../dist/visual-embed-sdk-react --main lib/src/react/index.d.ts --outputAsModuleFolder=true","bundle-dts-react-full":"dts-bundle --name ../../../dist/visual-embed-sdk-react-full --main lib/src/react/all-types-export.d.ts --outputAsModuleFolder=true",build:"rollup -c",watch:"rollup -cw","docs-cmd":"node scripts/gatsby-commands.js",docgen:"typedoc --tsconfig tsconfig.json --theme typedoc-theme","test-sdk":"jest -c jest.config.sdk.js --runInBand","test-docs":"jest -c jest.config.docs.js",test:"npm run test-sdk && npm run test-docs",posttest:"cat ./coverage/sdk/lcov.info | coveralls","is-publish-allowed":"node scripts/is-publish-allowed.js",prepublishOnly:"npm run is-publish-allowed && npm run test && npm run tsc && npm run bundle-dts-file && npm run bundle-dts && npm run bundle-dts-react && npm run bundle-dts-react-full && npm run build","check-size":"npm run build && size-limit","publish-dev":"npm publish --tag dev","publish-prod":"npm publish --tag latest"};var peerDependencies={react:"> 16.8.0","react-dom":"> 16.8.0"};var dependencies={algoliasearch:"^4.10.5",classnames:"^2.3.1",dompurify:"^2.3.4","eslint-plugin-comment-length":"^0.9.2","eslint-plugin-jsdoc":"^40.1.0",eventemitter3:"^4.0.7","gatsby-plugin-vercel":"^1.0.3","html-react-parser":"^1.4.12",lodash:"^4.17.21","mixpanel-browser":"^2.45.0","ts-deepmerge":"^6.0.2",tslib:"^2.5.3","use-deep-compare-effect":"^1.8.1"};var devDependencies={"@mdx-js/mdx":"^1.6.22","@mdx-js/react":"^1.6.22","@react-icons/all-files":"^4.1.0","@rollup/plugin-commonjs":"^18.0.0","@rollup/plugin-json":"^4.1.0","@rollup/plugin-node-resolve":"^11.2.1","@rollup/plugin-replace":"^5.0.2","@size-limit/preset-big-lib":"^8.2.6","@testing-library/dom":"^7.31.0","@testing-library/jest-dom":"^5.14.1","@testing-library/react":"^11.2.7","@testing-library/user-event":"^13.1.8","@types/jest":"^22.2.3","@types/mixpanel-browser":"^2.35.6","@types/react-test-renderer":"^17.0.1","@typescript-eslint/eslint-plugin":"^4.6.0","@typescript-eslint/parser":"^4.6.0",asciidoctor:"^2.2.1","babel-jest":"^26.6.3","babel-preset-gatsby":"^1.10.0","command-line-args":"^5.1.1",coveralls:"^3.1.0","current-git-branch":"^1.1.0","dts-bundle":"^0.7.3",eslint:"^7.12.1","eslint-config-airbnb-base":"^14.2.0","eslint-config-prettier":"^6.15.0","eslint-import-resolver-typescript":"^2.3.0","eslint-plugin-import":"^2.22.1","eslint-plugin-prettier":"^3.1.4","eslint-plugin-react-hooks":"^4.2.0","fs-extra":"^10.0.0",gatsby:"3.13.1","gatsby-plugin-algolia":"^0.22.2","gatsby-plugin-catch-links":"^3.1.0","gatsby-plugin-env-variables":"^2.1.0","gatsby-plugin-intl":"^0.3.3","gatsby-plugin-manifest":"^3.2.0","gatsby-plugin-output":"^0.1.3","gatsby-plugin-sass":"6.7.0","gatsby-plugin-sitemap":"^4.10.0","gatsby-source-filesystem":"3.1.0","gatsby-transformer-asciidoc":"2.1.0","gatsby-transformer-rehype":"2.0.0","gh-pages":"^3.1.0","highlight.js":"^10.6.0","html-to-text":"^8.0.0","identity-obj-proxy":"^3.0.0","istanbul-merge":"^1.1.1",jest:"^26.6.3","jest-fetch-mock":"^3.0.3",jsdom:"^17.0.0","node-sass":"^8.0.0",prettier:"2.1.2",react:"^16.14.0","react-dom":"^16.14.0","react-resizable":"^1.11.0","react-resize-detector":"^6.6.0","react-test-renderer":"^17.0.2","react-use-flexsearch":"^0.1.1",rollup:"2.30.0","rollup-plugin-typescript2":"0.27.3","ts-jest":"^26.5.5","ts-loader":"8.0.4",typedoc:"0.21.6","typedoc-plugin-toc-group":"thoughtspot/typedoc-plugin-toc-group",typescript:"^4.9.4","url-search-params-polyfill":"^8.1.0",util:"^0.12.4"};var author="ThoughtSpot";var email="support@thoughtspot.com";var license="ThoughtSpot Development Tools End User License Agreement";var directories={lib:"lib"};var repository={type:"git",url:"git+https://github.com/thoughtspot/visual-embed-sdk.git"};var publishConfig={registry:"https://registry.npmjs.org"};var keywords=["thoughtspot","everywhere","embed","sdk","analytics"];var bugs={url:"https://github.com/thoughtspot/visual-embed-sdk/issues"};var homepage="https://github.com/thoughtspot/visual-embed-sdk#readme";var globals={window:{}};var pkgInfo = {name:name,version:version,description:description,module:module,main:main,types:types,files:files,exports:exports,typesVersions:typesVersions,"size-limit":[{path:"dist/tsembed.js",limit:"43 kB"}],scripts:scripts,peerDependencies:peerDependencies,dependencies:dependencies,devDependencies:devDependencies,author:author,email:email,license:license,directories:directories,repository:repository,publishConfig:publishConfig,keywords:keywords,bugs:bugs,homepage:homepage,globals:globals};
|
|
12708
12762
|
|
|
12709
12763
|
/**
|
|
12710
12764
|
* Copyright (c) 2022
|
|
@@ -13915,7 +13969,7 @@ class SearchEmbed extends TsEmbed {
|
|
|
13915
13969
|
}
|
|
13916
13970
|
getEmbedParams() {
|
|
13917
13971
|
var _a;
|
|
13918
|
-
const { hideResults,
|
|
13972
|
+
const { hideResults, enableSearchAssist, forceTable, searchOptions, runtimeFilters, dataSource, dataSources, excludeRuntimeFiltersfromURL, dataPanelV2 = false, useLastSelectedSources = false, runtimeParameters, } = this.viewConfig;
|
|
13919
13973
|
const queryParams = this.getBaseQueryParams();
|
|
13920
13974
|
queryParams[Param.HideActions] = [
|
|
13921
13975
|
...((_a = queryParams[Param.HideActions]) !== null && _a !== void 0 ? _a : []),
|
|
@@ -13984,7 +14038,8 @@ class SearchEmbed extends TsEmbed {
|
|
|
13984
14038
|
const src = this.getIFrameSrc(answerId);
|
|
13985
14039
|
this.renderIFrame(src);
|
|
13986
14040
|
getAuthPromise().then(() => {
|
|
13987
|
-
if (checkReleaseVersionInBeta(getReleaseVersion(), getEmbedConfig().suppressSearchEmbedBetaWarning
|
|
14041
|
+
if (checkReleaseVersionInBeta(getReleaseVersion(), getEmbedConfig().suppressSearchEmbedBetaWarning
|
|
14042
|
+
|| getEmbedConfig().suppressErrorAlerts)) {
|
|
13988
14043
|
alert(ERROR_MESSAGE.SEARCHEMBED_BETA_WRANING_MESSAGE);
|
|
13989
14044
|
}
|
|
13990
14045
|
});
|