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