diff --git a/package-lock.json b/package-lock.json index 19217c1f363dd..8ff43df9fc5d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -224,6 +224,8 @@ "pdf-parse": "^1.1.1", "pg": "^8.3.0", "pg-promise": "^10.5.8", + "posthog-js": "^1.26.0", + "posthog-node": "^1.3.0", "prettier": "^2.3.2", "prismjs": "^1.17.1", "prom-client": "^13.1.0", @@ -12684,6 +12686,14 @@ "url": "https://ko-fi.com/killymxi" } }, + "node_modules/@sentry/types": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.7.0.tgz", + "integrity": "sha512-4x8O7uerSGLnYC10krHl9t8h7xXHn5FextqKYbTCXCnx2hC8D+9lz8wcbQAFo0d97wiUYqI8opmEgFVGx7c5hQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/@servie/events": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@servie/events/-/events-1.0.0.tgz", @@ -49000,6 +49010,50 @@ "node": ">=0.10.0" } }, + "node_modules/posthog-js": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.26.0.tgz", + "integrity": "sha512-Fjc5REUJxrVTQ0WzfChn+CW/UrparZGwINPOtO9FoB25U2IrXnvnTUpkYhSPucZPWUwUMRdXBCo9838COn464Q==", + "dependencies": { + "@sentry/types": "^7.2.0", + "fflate": "^0.4.1", + "rrweb-snapshot": "^1.1.14" + } + }, + "node_modules/posthog-js/node_modules/fflate": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", + "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==" + }, + "node_modules/posthog-node": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-1.3.0.tgz", + "integrity": "sha512-2+VhqiY/rKIqKIXyvemBFHbeijHE25sP7eKltnqcFqAssUE6+sX6vusN9A4luzToOqHQkUZexiCKxvuGagh7JA==", + "dependencies": { + "axios": "0.24.0", + "axios-retry": "^3.1.9", + "component-type": "^1.2.1", + "join-component": "^1.1.0", + "md5": "^2.3.0", + "ms": "^2.1.3", + "remove-trailing-slash": "^0.1.1", + "uuid": "^8.3.2" + }, + "bin": { + "posthog": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/posthog-node/node_modules/axios": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", + "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "dependencies": { + "follow-redirects": "^1.14.4" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -51485,6 +51539,11 @@ "fsevents": "~2.3.2" } }, + "node_modules/rrweb-snapshot": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/rrweb-snapshot/-/rrweb-snapshot-1.1.14.tgz", + "integrity": "sha512-eP5pirNjP5+GewQfcOQY4uBiDnpqxNRc65yKPW0eSoU1XamDfc4M8oqpXGMyUyvLyxFDB0q0+DChuxxiU2FXBQ==" + }, "node_modules/rss-parser": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/rss-parser/-/rss-parser-3.12.0.tgz", @@ -71474,6 +71533,11 @@ "selderee": "^0.6.0" } }, + "@sentry/types": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.7.0.tgz", + "integrity": "sha512-4x8O7uerSGLnYC10krHl9t8h7xXHn5FextqKYbTCXCnx2hC8D+9lz8wcbQAFo0d97wiUYqI8opmEgFVGx7c5hQ==" + }, "@servie/events": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@servie/events/-/events-1.0.0.tgz", @@ -100013,6 +100077,48 @@ "xtend": "^4.0.0" } }, + "posthog-js": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.26.0.tgz", + "integrity": "sha512-Fjc5REUJxrVTQ0WzfChn+CW/UrparZGwINPOtO9FoB25U2IrXnvnTUpkYhSPucZPWUwUMRdXBCo9838COn464Q==", + "requires": { + "@sentry/types": "^7.2.0", + "fflate": "^0.4.1", + "rrweb-snapshot": "^1.1.14" + }, + "dependencies": { + "fflate": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", + "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==" + } + } + }, + "posthog-node": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/posthog-node/-/posthog-node-1.3.0.tgz", + "integrity": "sha512-2+VhqiY/rKIqKIXyvemBFHbeijHE25sP7eKltnqcFqAssUE6+sX6vusN9A4luzToOqHQkUZexiCKxvuGagh7JA==", + "requires": { + "axios": "0.24.0", + "axios-retry": "^3.1.9", + "component-type": "^1.2.1", + "join-component": "^1.1.0", + "md5": "^2.3.0", + "ms": "^2.1.3", + "remove-trailing-slash": "^0.1.1", + "uuid": "^8.3.2" + }, + "dependencies": { + "axios": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", + "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "requires": { + "follow-redirects": "^1.14.4" + } + } + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -101974,6 +102080,11 @@ "fsevents": "~2.3.2" } }, + "rrweb-snapshot": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/rrweb-snapshot/-/rrweb-snapshot-1.1.14.tgz", + "integrity": "sha512-eP5pirNjP5+GewQfcOQY4uBiDnpqxNRc65yKPW0eSoU1XamDfc4M8oqpXGMyUyvLyxFDB0q0+DChuxxiU2FXBQ==" + }, "rss-parser": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/rss-parser/-/rss-parser-3.12.0.tgz", diff --git a/packages/cli/config/schema.ts b/packages/cli/config/schema.ts index 50111f874a48a..d77ca4f330903 100644 --- a/packages/cli/config/schema.ts +++ b/packages/cli/config/schema.ts @@ -888,6 +888,20 @@ export const schema = { env: 'N8N_DIAGNOSTICS_ENABLED', }, config: { + posthog: { + apiKey: { + doc: 'API key for PostHog', + format: String, + default: 'phc_QLECpA3yiIJcyafUv0pe6EoxvdfIDZ5A12dGpGXH4jV', + env: 'N8N_DIAGNOSTICS_POSTHOG_API_KEY', + }, + apiHost: { + doc: 'API host for PostHog', + format: String, + default: 'https://app.posthog.com', + env: 'N8N_DIAGNOSTICS_POSTHOG_API_HOST', + }, + }, frontend: { doc: 'Diagnostics config for frontend.', format: String, diff --git a/packages/cli/package.json b/packages/cli/package.json index a4a182c0c5732..6030108a6a96f 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -96,9 +96,9 @@ "typescript": "~4.6.0" }, "dependencies": { - "@oclif/core": "^1.9.3", "@apidevtools/swagger-cli": "4.0.0", "@oclif/command": "^1.5.18", + "@oclif/core": "^1.9.3", "@oclif/errors": "^1.2.2", "@rudderstack/rudder-sdk-node": "1.0.6", "@types/json-diff": "^0.5.1", @@ -156,6 +156,7 @@ "passport-cookie": "^1.0.9", "passport-jwt": "^4.0.0", "pg": "^8.3.0", + "posthog-node": "^1.3.0", "prom-client": "^13.1.0", "psl": "^1.8.0", "request-promise-native": "^1.0.7", diff --git a/packages/cli/src/Interfaces.ts b/packages/cli/src/Interfaces.ts index e59cd8423827e..4f2da15aa60e2 100644 --- a/packages/cli/src/Interfaces.ts +++ b/packages/cli/src/Interfaces.ts @@ -515,6 +515,9 @@ export interface IN8nUISettings { missingPackages?: boolean; executionMode: 'regular' | 'queue'; communityNodesEnabled: boolean; + deployment: { + type: string; + }; } export interface IPersonalizationSurveyAnswers { diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index b4aeac677d6c2..14ef2f6d8b340 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -172,6 +172,7 @@ import { } from './UserManagement/UserManagementHelper'; import { loadPublicApiVersions } from './PublicApi'; import { SharedWorkflow } from './databases/entities/SharedWorkflow'; +import * as telemetryScripts from './telemetry/scripts'; require('body-parser-xml')(bodyParser); @@ -337,6 +338,9 @@ class App { }, executionMode: config.getEnv('executions.mode'), communityNodesEnabled: config.getEnv('nodes.communityPackages.enabled'), + deployment: { + type: config.getEnv('deployment.type'), + }, }; } @@ -2604,6 +2608,27 @@ class App { readIndexFile = readIndexFile.replace(/\/%BASE_PATH%\//g, n8nPath); readIndexFile = readIndexFile.replace(/\/favicon.ico/g, `${n8nPath}favicon.ico`); + if (this.frontendSettings.telemetry.enabled) { + // @TODO_PART_3: + // Confirm if `autocapture` is needed for session recording, if so enable + + // @TODO_ON_COMPLETION: + // Set `disableSessionRecording` to `!['desktop_mac', 'desktop_win', 'cloud'].includes(deploymentType)` + // Set `debug` to `config.getEnv('logs.level') === 'debug'` + + const postHogScript = telemetryScripts.postHog({ + apiKey: config.getEnv('diagnostics.config.posthog.apiKey'), + apiHost: config.getEnv('diagnostics.config.posthog.apiHost'), + autocapture: false, + disableSessionRecording: true, + debug: true, + }); + + const firstLinkedScript = '`; diff --git a/packages/cli/test/unit/Telemetry.test.ts b/packages/cli/test/unit/Telemetry.test.ts index 199aef92cb42f..a9a1f61fde39e 100644 --- a/packages/cli/test/unit/Telemetry.test.ts +++ b/packages/cli/test/unit/Telemetry.test.ts @@ -1,6 +1,6 @@ import { Telemetry } from '../../src/telemetry'; -jest.spyOn(Telemetry.prototype as any, 'createTelemetryClient').mockImplementation(() => { +jest.spyOn(Telemetry.prototype as any, 'initRudderStack').mockImplementation(() => { return { flush: () => {}, identify: () => {}, diff --git a/packages/design-system/src/main.d.ts b/packages/design-system/src/main.d.ts index 9a58de1c940e6..2116dd4bcec80 100644 --- a/packages/design-system/src/main.d.ts +++ b/packages/design-system/src/main.d.ts @@ -14,3 +14,4 @@ declare module 'n8n-design-system' { } export * from './types'; +export { locale } from './locale'; diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json index 06a944b9b9d27..b781766c1edb1 100644 --- a/packages/editor-ui/package.json +++ b/packages/editor-ui/package.json @@ -79,8 +79,8 @@ "lodash.debounce": "^4.0.8", "lodash.get": "^4.4.2", "lodash.set": "^4.3.2", - "n8n-workflow": "~0.109.0", "monaco-editor-webpack-plugin": "^5.0.0", + "n8n-workflow": "~0.109.0", "normalize-wheel": "^1.0.1", "prismjs": "^1.17.1", "quill": "^2.0.0-dev.3", diff --git a/packages/editor-ui/src/components/PersonalizationModal.vue b/packages/editor-ui/src/components/PersonalizationModal.vue index 0959b741d2288..2661101ba05e2 100644 --- a/packages/editor-ui/src/components/PersonalizationModal.vue +++ b/packages/editor-ui/src/components/PersonalizationModal.vue @@ -494,7 +494,12 @@ export default mixins(showMessage, workflowHelpers).extend({ this.$data.isSaving = true; try { - await this.$store.dispatch('users/submitPersonalizationSurvey', {...values, version: SURVEY_VERSION}); + const survey = { ...values, version: SURVEY_VERSION }; + + // @TODO_PART_2: To be done via hook + // window.posthog.people.set(survey); + + await this.$store.dispatch('users/submitPersonalizationSurvey', survey); if (Object.keys(values).length === 0) { this.closeDialog(); diff --git a/packages/editor-ui/src/components/Telemetry.vue b/packages/editor-ui/src/components/Telemetry.vue index ea9fca1d7a321..57ec05450648a 100644 --- a/packages/editor-ui/src/components/Telemetry.vue +++ b/packages/editor-ui/src/components/Telemetry.vue @@ -11,13 +11,14 @@ export default Vue.extend({ name: 'Telemetry', data() { return { - initialised: false, + isTelemetryInitialized: false, }; }, computed: { ...mapGetters('settings', ['telemetry']), ...mapGetters('users', ['currentUserId']), - isTelemeteryEnabledOnRoute(): boolean { + ...mapGetters(['instanceId']), + isTelemetryEnabledOnRoute(): boolean { return this.$route.meta && this.$route.meta.telemetry ? !this.$route.meta.telemetry.disabled: true; }, }, @@ -26,17 +27,22 @@ export default Vue.extend({ }, methods: { init() { - if (this.initialised || !this.isTelemeteryEnabledOnRoute) { - return; - } - const opts = this.telemetry; - if (opts && opts.enabled) { - this.initialised = true; - const instanceId = this.$store.getters.instanceId; - const userId = this.$store.getters['users/currentUserId']; - const logLevel = this.$store.getters['settings/logLevel']; - this.$telemetry.init(opts, { instanceId, logLevel, userId, store: this.$store }); - } + if (this.isTelemetryInitialized || !this.isTelemetryEnabledOnRoute) return; + + const telemetrySettings = this.telemetry; + + if (!telemetrySettings || !telemetrySettings.enabled) return; + + this.$telemetry.init( + telemetrySettings, + { + instanceId: this.instanceId, + userId: this.currentUserId, + store: this.$store, + }, + ); + + this.isTelemetryInitialized = true; }, }, watch: { @@ -44,10 +50,9 @@ export default Vue.extend({ this.init(); }, currentUserId(userId) { - const instanceId = this.$store.getters.instanceId; - this.$telemetry.identify(instanceId, userId); + this.$telemetry.identify(this.instanceId, userId); }, - isTelemeteryEnabledOnRoute(enabled) { + isTelemetryEnabledOnRoute(enabled) { if (enabled) { this.init(); } diff --git a/packages/editor-ui/src/modules/users.ts b/packages/editor-ui/src/modules/users.ts index e2ed105a6023f..bb00db2537367 100644 --- a/packages/editor-ui/src/modules/users.ts +++ b/packages/editor-ui/src/modules/users.ts @@ -96,6 +96,9 @@ const module: Module = { getUserById(state: IUsersState): (userId: string) => IUser | null { return (userId: string): IUser | null => state.users[userId]; }, + globalRoleName(state: IUsersState, getters: any) { // tslint:disable-line:no-any + return getters.currentUser.globalRole.name; + }, canUserDeleteTags(state: IUsersState, getters: any, rootState: IRootState, rootGetters: any) { // tslint:disable-line:no-any const currentUser = getters.currentUser; diff --git a/packages/editor-ui/src/plugins/telemetry/index.ts b/packages/editor-ui/src/plugins/telemetry/index.ts index 5b6b4660eb293..245c583cf785d 100644 --- a/packages/editor-ui/src/plugins/telemetry/index.ts +++ b/packages/editor-ui/src/plugins/telemetry/index.ts @@ -4,15 +4,11 @@ import { ITelemetryTrackProperties, IDataObject, } from 'n8n-workflow'; -import { ILogLevel, INodeCreateElement, IRootState } from "@/Interface"; import { Route } from "vue-router"; -import { Store } from "vuex"; -declare module 'vue/types/vue' { - interface Vue { - $telemetry: Telemetry; - } -} +import type { INodeCreateElement, IRootState } from "@/Interface"; +import type { Store } from "vuex"; +import type { IUserNodesPanelSession } from "./telemetry.types"; export function TelemetryPlugin(vue: typeof _Vue): void { const telemetry = new Telemetry(); @@ -25,25 +21,13 @@ export function TelemetryPlugin(vue: typeof _Vue): void { }); } -interface IUserNodesPanelSessionData { - nodeFilter: string; - resultsNodes: string[]; - filterMode: string; -} - -interface IUserNodesPanelSession { - sessionId: string; - data: IUserNodesPanelSessionData; -} - -class Telemetry { +export class Telemetry { private pageEventQueue: Array<{route: Route}>; private previousPath: string; private store: Store | null; - private get telemetry() { - // @ts-ignore + private get rudderStack() { return window.rudderanalytics; } @@ -62,45 +46,64 @@ class Telemetry { this.store = null; } - init(options: ITelemetrySettings, { instanceId, logLevel, userId, store }: { instanceId: string, logLevel?: ILogLevel, userId?: string, store: Store }) { - if (options.enabled && !this.telemetry) { - if(!options.config) { - return; - } + init( + telemetrySettings: ITelemetrySettings, + { instanceId, userId, store }: { + instanceId: string; + userId?: string; + store: Store; + }, + ) { + if (!telemetrySettings.enabled || !telemetrySettings.config || this.rudderStack) return; - this.store = store; - const logging = logLevel === 'debug' ? { logLevel: 'DEBUG'} : {}; - this.loadTelemetryLibrary(options.config.key, options.config.url, { integrations: { All: false }, loadIntegration: false, ...logging}); - this.identify(instanceId, userId); - this.flushPageEvents(); - this.track('Session started', { session_id: store.getters.sessionId }); - } + const { config: { key, url } } = telemetrySettings; + + this.store = store; + + const logLevel = store.getters['settings/logLevel']; + + const logging = logLevel === 'debug' ? { logLevel: 'DEBUG' } : {}; + + this.initRudderStack( + key, + url, + { + integrations: { All: false }, + loadIntegration: false, + ...logging, + }, + ); + + this.identify(instanceId, userId); + + this.flushPageEvents(); + this.track('Session started', { session_id: store.getters.sessionId }); } identify(instanceId: string, userId?: string) { const traits = { instance_id: instanceId }; if (userId) { - this.telemetry.identify(`${instanceId}#${userId}`, traits); + this.rudderStack.identify(`${instanceId}#${userId}`, traits); } else { - this.telemetry.reset(); - this.telemetry.identify(undefined, traits); + this.rudderStack.reset(); + this.rudderStack.identify(undefined, traits); } } track(event: string, properties?: ITelemetryTrackProperties) { - if (this.telemetry) { - const updatedProperties = { - ...properties, - version_cli: this.store && this.store.getters.versionCli, - }; + if (!this.rudderStack) return; - this.telemetry.track(event, updatedProperties); - } + const updatedProperties = { + ...properties, + version_cli: this.store && this.store.getters.versionCli, + }; + + this.rudderStack.track(event, updatedProperties); } page(route: Route) { - if (this.telemetry) { + if (this.rudderStack) { if (route.path === this.previousPath) { // avoid duplicate requests query is changed for example on search page return; } @@ -113,7 +116,7 @@ class Telemetry { } const category = (route.meta && route.meta.telemetry && route.meta.telemetry.pageCategory) || 'Editor'; - this.telemetry.page(category, pageName, properties); + this.rudderStack.page(category, pageName!, properties); } else { this.pageEventQueue.push({ @@ -131,7 +134,7 @@ class Telemetry { } trackNodesPanel(event: string, properties: IDataObject = {}) { - if (this.telemetry) { + if (this.rudderStack) { properties.nodes_panel_session_id = this.userNodesPanelSession.sessionId; switch (event) { case 'nodeView.createNodeActiveChanged': @@ -203,36 +206,50 @@ class Telemetry { }; } - private loadTelemetryLibrary(key: string, url: string, options: IDataObject) { - // @ts-ignore + private initRudderStack(key: string, url: string, options: IDataObject) { window.rudderanalytics = window.rudderanalytics || []; - this.telemetry.methods = ["load", "page", "track", "identify", "alias", "group", "ready", "reset", "getAnonymousId", "setAnonymousId"]; - this.telemetry.factory = (t: any) => { // tslint:disable-line:no-any - return (...args: any[]) => { // tslint:disable-line:no-any - const r = Array.prototype.slice.call(args); - r.unshift(t); - this.telemetry.push(r); - return this.telemetry; + this.rudderStack.methods = [ + "load", + "page", + "track", + "identify", + "alias", + "group", + "ready", + "reset", + "getAnonymousId", + "setAnonymousId", + ]; + + this.rudderStack.factory = (method: string) => { + return (...args: unknown[]) => { + const argsCopy = [method, ...args]; + this.rudderStack.push(argsCopy); + + return this.rudderStack; }; }; - for (let t = 0; t < this.telemetry.methods.length; t++) { - const r = this.telemetry.methods[t]; - this.telemetry[r] = this.telemetry.factory(r); + for (const method of this.rudderStack.methods) { + this.rudderStack[method] = this.rudderStack.factory(method); } - this.telemetry.loadJS = () => { - const r = document.createElement("script"); - r.type = "text/javascript"; - r.async = !0; - r.src = "https://cdn.rudderlabs.com/v1/rudder-analytics.min.js"; - const a = document.getElementsByTagName("script")[0]; - if(a && a.parentNode) { - a.parentNode.insertBefore(r, a); + this.rudderStack.loadJS = () => { + const script = document.createElement("script"); + + script.type = "text/javascript"; + script.async = !0; + script.src = "https://cdn.rudderlabs.com/v1/rudder-analytics.min.js"; + + const element: Element = document.getElementsByTagName("script")[0]; + + if (element && element.parentNode) { + element.parentNode.insertBefore(script, element); } }; - this.telemetry.loadJS(); - this.telemetry.load(key, url, options); + + this.rudderStack.loadJS(); + this.rudderStack.load(key, url, options); } } diff --git a/packages/editor-ui/src/plugins/telemetry/rudder-sdk.d.ts b/packages/editor-ui/src/plugins/telemetry/rudder-sdk.d.ts deleted file mode 100644 index b456554b11f49..0000000000000 --- a/packages/editor-ui/src/plugins/telemetry/rudder-sdk.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module 'rudder-sdk-js'; diff --git a/packages/editor-ui/src/plugins/telemetry/telemetry.types.ts b/packages/editor-ui/src/plugins/telemetry/telemetry.types.ts new file mode 100644 index 0000000000000..1d8124c7c696e --- /dev/null +++ b/packages/editor-ui/src/plugins/telemetry/telemetry.types.ts @@ -0,0 +1,122 @@ +import type { Telemetry } from '.'; + +declare module 'vue/types/vue' { + interface Vue { + $telemetry: Telemetry; + } +} + +declare global { + interface Window { + rudderanalytics: RudderStack; + posthog: posthog; + } +} + +export interface IUserNodesPanelSession { + sessionId: string; + data: IUserNodesPanelSessionData; +} + +interface IUserNodesPanelSessionData { + nodeFilter: string; + resultsNodes: string[]; + filterMode: string; +} + +/** + * Simplified version of: + * https://github.com/PostHog/posthog-js/blob/master/src/module.d.ts + */ + +/* tslint:disable-next-line */ +interface posthog { + identify( + uniqueId?: string, + userPropertiesToSet?: object, + userPropertiesToSetOnce?: object, + ): void; + + reset(resetDeviceId?: boolean): void; + + capture( + eventName: string, + properties?: object, + options?: object, + ): unknown; + + isFeatureEnabled(key: string, options?: object): boolean; + + register(properties: object, days?: number): void; + + people: { + set( + prop: object | string, + to?: object, + callback?: Function, + ): unknown; + }; +} + +/** + * Simplified version of: + * https://github.com/rudderlabs/rudder-sdk-js/blob/master/dist/rudder-sdk-js/index.d.ts + */ +interface RudderStack extends Array { + [key: string]: unknown; + + methods: string[]; + + factory: (method: string) => (...args: unknown[]) => RudderStack; + + loadJS(): void; + + /** + * Native methods + */ + + load( + writeKey: string, + dataPlaneUrl: string, + options?: object, + ): void; + + ready(): void; + + page( + category?: string, + name?: string, + properties?: object, + options?: object, + ): void; + + track( + event: string, + properties?: object, + options?: object, + ): void; + + identify( + id?: string, + traits?: object, + options?: object, + ): void; + + alias( + to: string, + from?: string, + options?: object, + ): void; + + group( + group: string, + traits?: object, + options?: object, + ): void; + + getAnonymousId(): void; + + setAnonymousId(id?: string): void; + + reset(): void; +}