mirror of
https://github.com/Kong/insomnia
synced 2024-11-07 22:30:15 +00:00
chore: move GA events to segment (#4403)
* drop events * move pageview to segment * replace trackEvent with trackSegmentEvent * remove categories and set ids * remove duplicate events * fxi tests * fix lint * fix inso * use analytics setting and dont log boring stuff * add context to page view
This commit is contained in:
parent
3c66874414
commit
48ac330d95
@ -1,5 +1,4 @@
|
||||
// WARNING: changing this to `export default` will break the mock and be incredibly hard to debug. Ask me how I know.
|
||||
const _analytics = jest.requireActual('../analytics');
|
||||
_analytics.trackEvent = jest.fn();
|
||||
_analytics.trackSegmentEvent = jest.fn();
|
||||
module.exports = _analytics;
|
||||
|
@ -1,203 +0,0 @@
|
||||
import * as electron from 'electron';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
import { globalBeforeEach } from '../../__jest__/before-each';
|
||||
import * as models from '../../models/index';
|
||||
import { _trackEvent, _trackPageView } from '../analytics';
|
||||
import {
|
||||
getAppId,
|
||||
getAppName,
|
||||
getAppPlatform,
|
||||
getAppVersion,
|
||||
getBrowserUserAgent,
|
||||
getGoogleAnalyticsId,
|
||||
getGoogleAnalyticsLocation,
|
||||
} from '../constants';
|
||||
|
||||
describe('init()', () => {
|
||||
beforeEach(async () => {
|
||||
await globalBeforeEach();
|
||||
electron.net.request = jest.fn(() => {
|
||||
const req = new EventEmitter();
|
||||
|
||||
req.end = function() {};
|
||||
|
||||
return req;
|
||||
});
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
it('does not work with tracking disabled', async () => {
|
||||
const settings = await models.settings.patch({
|
||||
enableAnalytics: false,
|
||||
deviceId: 'device',
|
||||
});
|
||||
expect(settings.enableAnalytics).toBe(false);
|
||||
expect(electron.net.request.mock.calls).toEqual([]);
|
||||
await _trackEvent({ interactive: true, category: 'Foo', action: 'Bar' });
|
||||
jest.runAllTimers();
|
||||
expect(electron.net.request.mock.calls).toEqual([]);
|
||||
});
|
||||
|
||||
it('works with tracking enabled', async () => {
|
||||
const settings = await models.settings.patch({
|
||||
enableAnalytics: true,
|
||||
deviceId: 'device',
|
||||
});
|
||||
expect(settings.enableAnalytics).toBe(true);
|
||||
expect(electron.net.request.mock.calls).toEqual([]);
|
||||
await _trackEvent({ interactive: true, category: 'Foo', action: 'Bar' });
|
||||
jest.runAllTimers();
|
||||
expect(electron.net.request.mock.calls).toEqual([
|
||||
[
|
||||
'https://www.google-analytics.com/collect?' +
|
||||
'v=1&' +
|
||||
`tid=${getGoogleAnalyticsId()}&` +
|
||||
'cid=device&' +
|
||||
`ua=${getBrowserUserAgent()}&` +
|
||||
`dl=${encodeURIComponent(getGoogleAnalyticsLocation())}%2F&` +
|
||||
'sr=1920x1080&' +
|
||||
'ul=en-US&' +
|
||||
`dt=${getAppId()}%3A${getAppVersion()}&` +
|
||||
`cd1=${getAppPlatform()}&` +
|
||||
`cd2=${getAppVersion()}&` +
|
||||
'aip=1&' +
|
||||
`an=${encodeURI(getAppName())}&` +
|
||||
`aid=${getAppId()}&` +
|
||||
`av=${getAppVersion()}&` +
|
||||
'vp=1900x1060&' +
|
||||
'de=UTF-8&' +
|
||||
't=event&' +
|
||||
'ec=Foo&' +
|
||||
'ea=Bar',
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
it('tracks non-interactive event', async () => {
|
||||
await models.settings.patch({
|
||||
deviceId: 'device',
|
||||
enableAnalytics: true,
|
||||
});
|
||||
await _trackEvent({ interactive: false, category: 'Foo', action: 'Bar' });
|
||||
jest.runAllTimers();
|
||||
expect(electron.net.request.mock.calls).toEqual([
|
||||
[
|
||||
'https://www.google-analytics.com/collect?' +
|
||||
'v=1&' +
|
||||
`tid=${getGoogleAnalyticsId()}&` +
|
||||
'cid=device&' +
|
||||
`ua=${getBrowserUserAgent()}&` +
|
||||
`dl=${encodeURIComponent(getGoogleAnalyticsLocation())}%2F&` +
|
||||
'sr=1920x1080&' +
|
||||
'ul=en-US&' +
|
||||
`dt=${getAppId()}%3A${getAppVersion()}&` +
|
||||
`cd1=${getAppPlatform()}&` +
|
||||
`cd2=${getAppVersion()}&` +
|
||||
'aip=1&' +
|
||||
`an=${encodeURI(getAppName())}&` +
|
||||
`aid=${getAppId()}&` +
|
||||
`av=${getAppVersion()}&` +
|
||||
'vp=1900x1060&' +
|
||||
'de=UTF-8&' +
|
||||
't=event&' +
|
||||
'ec=Foo&' +
|
||||
'ea=Bar&' +
|
||||
'ni=1',
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
it('tracks page view', async () => {
|
||||
await models.settings.patch({
|
||||
deviceId: 'device',
|
||||
enableAnalytics: true,
|
||||
});
|
||||
await _trackPageView('/my/path');
|
||||
jest.runAllTimers();
|
||||
expect(electron.net.request.mock.calls).toEqual([
|
||||
[
|
||||
'https://www.google-analytics.com/collect?' +
|
||||
'v=1&' +
|
||||
`tid=${getGoogleAnalyticsId()}&` +
|
||||
'cid=device&' +
|
||||
`ua=${getBrowserUserAgent()}&` +
|
||||
`dl=${encodeURIComponent(getGoogleAnalyticsLocation())}%2Fmy%2Fpath&` +
|
||||
'sr=1920x1080&' +
|
||||
'ul=en-US&' +
|
||||
`dt=${getAppId()}%3A${getAppVersion()}&` +
|
||||
`cd1=${getAppPlatform()}&` +
|
||||
`cd2=${getAppVersion()}&` +
|
||||
'aip=1&' +
|
||||
`an=${encodeURI(getAppName())}&` +
|
||||
`aid=${getAppId()}&` +
|
||||
`av=${getAppVersion()}&` +
|
||||
'vp=1900x1060&' +
|
||||
'de=UTF-8&' +
|
||||
't=pageview',
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
it('tracking page view remembers path', async () => {
|
||||
await models.settings.patch({
|
||||
deviceId: 'device',
|
||||
enableAnalytics: true,
|
||||
});
|
||||
await _trackPageView('/my/path');
|
||||
jest.runAllTimers();
|
||||
await _trackEvent({
|
||||
interactive: true,
|
||||
category: 'cat',
|
||||
action: 'act',
|
||||
label: 'lab',
|
||||
value: 'val',
|
||||
});
|
||||
expect(electron.net.request.mock.calls).toEqual([
|
||||
[
|
||||
'https://www.google-analytics.com/collect?' +
|
||||
'v=1&' +
|
||||
`tid=${getGoogleAnalyticsId()}&` +
|
||||
'cid=device&' +
|
||||
`ua=${getBrowserUserAgent()}&` +
|
||||
`dl=${encodeURIComponent(getGoogleAnalyticsLocation())}%2Fmy%2Fpath&` +
|
||||
'sr=1920x1080&' +
|
||||
'ul=en-US&' +
|
||||
`dt=${getAppId()}%3A${getAppVersion()}&` +
|
||||
`cd1=${getAppPlatform()}&` +
|
||||
`cd2=${getAppVersion()}&` +
|
||||
'aip=1&' +
|
||||
`an=${encodeURI(getAppName())}&` +
|
||||
`aid=${getAppId()}&` +
|
||||
`av=${getAppVersion()}&` +
|
||||
'vp=1900x1060&' +
|
||||
'de=UTF-8&' +
|
||||
't=pageview',
|
||||
],
|
||||
[
|
||||
'https://www.google-analytics.com/collect?' +
|
||||
'v=1&' +
|
||||
`tid=${getGoogleAnalyticsId()}&` +
|
||||
'cid=device&' +
|
||||
`ua=${getBrowserUserAgent()}&` +
|
||||
`dl=${encodeURIComponent(getGoogleAnalyticsLocation())}%2Fmy%2Fpath&` +
|
||||
'sr=1920x1080&' +
|
||||
'ul=en-US&' +
|
||||
`dt=${getAppId()}%3A${getAppVersion()}&` +
|
||||
`cd1=${getAppPlatform()}&` +
|
||||
`cd2=${getAppVersion()}&` +
|
||||
'aip=1&' +
|
||||
`an=${encodeURI(getAppName())}&` +
|
||||
`aid=${getAppId()}&` +
|
||||
`av=${getAppVersion()}&` +
|
||||
'vp=1900x1060&' +
|
||||
'de=UTF-8&' +
|
||||
't=event&' +
|
||||
'ec=cat&' +
|
||||
'ea=act&' +
|
||||
'el=lab&' +
|
||||
'ev=val',
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
@ -1,95 +1,58 @@
|
||||
import Analytics from 'analytics-node';
|
||||
import * as electron from 'electron';
|
||||
import { buildQueryStringFromParams, joinUrlAndQueryString } from 'insomnia-url';
|
||||
import * as uuid from 'uuid';
|
||||
|
||||
import { getAccountId } from '../account/session';
|
||||
import { database as db } from '../common/database';
|
||||
import * as models from '../models/index';
|
||||
import type { RequestParameter } from '../models/request';
|
||||
import { isSettings } from '../models/settings';
|
||||
import {
|
||||
getAppId,
|
||||
getAppName,
|
||||
getAppPlatform,
|
||||
getAppVersion,
|
||||
getGoogleAnalyticsId,
|
||||
getGoogleAnalyticsLocation,
|
||||
getSegmentWriteKey,
|
||||
isDevelopment,
|
||||
} from './constants';
|
||||
import { getScreenResolution, getUserLanguage, getViewportSize } from './electron-helpers';
|
||||
|
||||
const DIMENSION_PLATFORM = 1;
|
||||
const DIMENSION_VERSION = 2;
|
||||
const KEY_TRACKING_ID = 'tid';
|
||||
const KEY_VERSION = 'v';
|
||||
const KEY_CLIENT_ID = 'cid';
|
||||
const KEY_HIT_TYPE = 't';
|
||||
const KEY_LOCATION = 'dl';
|
||||
const KEY_TITLE = 'dt';
|
||||
const KEY_NON_INTERACTION = 'ni';
|
||||
const KEY_VIEWPORT_SIZE = 'vp';
|
||||
const KEY_SCREEN_RESOLUTION = 'sr';
|
||||
const KEY_USER_LANGUAGE = 'ul';
|
||||
const KEY_USER_AGENT = 'ua';
|
||||
const KEY_DOCUMENT_ENCODING = 'de';
|
||||
const KEY_EVENT_CATEGORY = 'ec';
|
||||
const KEY_EVENT_ACTION = 'ea';
|
||||
const KEY_EVENT_LABEL = 'el';
|
||||
const KEY_EVENT_VALUE = 'ev';
|
||||
const KEY_ANONYMIZE_IP = 'aip';
|
||||
const KEY_APPLICATION_NAME = 'an';
|
||||
const KEY_APPLICATION_ID = 'aid';
|
||||
const KEY_APPLICATION_VERSION = 'av';
|
||||
const KEY_CUSTOM_DIMENSION_PREFIX = 'cd';
|
||||
let _currentLocationPath = '/';
|
||||
const segmentClient = new Analytics(getSegmentWriteKey(), {
|
||||
// @ts-expect-error -- TSCONVERSION
|
||||
axiosConfig: {
|
||||
// This is needed to ensure that we use the NodeJS adapter in the render process
|
||||
...(global?.require && {
|
||||
adapter: global.require('axios/lib/adapters/http'),
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
export function trackEvent(
|
||||
category: string,
|
||||
action: string,
|
||||
label?: string | null,
|
||||
value?: string | null,
|
||||
) {
|
||||
process.nextTick(async () => {
|
||||
await _trackEvent({
|
||||
interactive: true,
|
||||
category,
|
||||
action,
|
||||
label,
|
||||
value,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function trackPageView(path: string) {
|
||||
process.nextTick(async () => {
|
||||
await _trackPageView(path);
|
||||
});
|
||||
}
|
||||
|
||||
export async function getDeviceId() {
|
||||
const getDeviceId = async () => {
|
||||
const settings = await models.settings.getOrCreate();
|
||||
let { deviceId } = settings;
|
||||
return settings.deviceId || (await models.settings.update(settings, { deviceId: uuid.v4() })).deviceId;
|
||||
};
|
||||
|
||||
if (!deviceId) {
|
||||
// Migrate old GA ID into settings model if needed
|
||||
const oldId = (window && window.localStorage.getItem('gaClientId')) || null;
|
||||
deviceId = oldId || uuid.v4();
|
||||
await models.settings.update(settings, {
|
||||
deviceId,
|
||||
const sendSegment = async (segmentType: 'track' | 'page', options) => {
|
||||
try {
|
||||
const anonymousId = await getDeviceId();
|
||||
const userId = getAccountId();
|
||||
const context = {
|
||||
app: { name: getAppName(), version: getAppVersion() },
|
||||
os: { name: _getOsName(), version: process.getSystemVersion() },
|
||||
};
|
||||
segmentClient?.[segmentType]({ ...options, context, anonymousId, userId }, error => {
|
||||
if (error) console.warn('[analytics] Error sending segment event', error);
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
console.warn('[analytics] Unexpected error while sending segment event', error);
|
||||
}
|
||||
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
let segmentClient: Analytics | null = null;
|
||||
};
|
||||
|
||||
export enum SegmentEvent {
|
||||
appStarted = 'App Started',
|
||||
collectionCreate = 'Collection Created',
|
||||
criticalError = 'Critical Error Encountered',
|
||||
dataExport = 'Data Exported',
|
||||
dataImport = 'Data Imported',
|
||||
documentCreate = 'Document Created',
|
||||
kongConnected = 'Kong Connected',
|
||||
kongSync = 'Kong Synced',
|
||||
requestBodyTypeSelect = 'Request Body Type Selected',
|
||||
requestCreate = 'Request Created',
|
||||
requestExecute = 'Request Executed',
|
||||
projectLocalCreate = 'Local Project Created',
|
||||
@ -110,9 +73,9 @@ type PushPull = 'push' | 'pull';
|
||||
export function vcsSegmentEventProperties(
|
||||
type: 'git',
|
||||
action: PushPull | `force_${PushPull}` |
|
||||
'create_branch' | 'merge_branch' | 'delete_branch' | 'checkout_branch' |
|
||||
'commit' | 'stage_all' | 'stage' | 'unstage_all' | 'unstage' | 'rollback' | 'rollback_all' |
|
||||
'update' | 'setup' | 'clone',
|
||||
'create_branch' | 'merge_branch' | 'delete_branch' | 'checkout_branch' |
|
||||
'commit' | 'stage_all' | 'stage' | 'unstage_all' | 'unstage' | 'rollback' | 'rollback_all' |
|
||||
'update' | 'setup' | 'clone',
|
||||
error?: string
|
||||
) {
|
||||
return {
|
||||
@ -138,7 +101,6 @@ interface QueuedSegmentEvent {
|
||||
let queuedEvents: QueuedSegmentEvent[] = [];
|
||||
|
||||
async function flushQueuedEvents() {
|
||||
console.log(`[segment] Flushing ${queuedEvents.length} queued events`, queuedEvents);
|
||||
const events = [...queuedEvents];
|
||||
|
||||
// Clear queue before we even start sending to prevent races
|
||||
@ -173,52 +135,21 @@ export async function trackSegmentEvent(
|
||||
properties,
|
||||
timestamp: new Date(),
|
||||
};
|
||||
console.log('[segment] Queued event', queuedEvent);
|
||||
queuedEvents.push(queuedEvent);
|
||||
}
|
||||
return;
|
||||
}
|
||||
sendSegment('track', {
|
||||
event,
|
||||
properties,
|
||||
...(timestamp ? { timestamp } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
if (!segmentClient) {
|
||||
segmentClient = new Analytics(getSegmentWriteKey(), {
|
||||
// @ts-expect-error -- TSCONVERSION
|
||||
axiosConfig: {
|
||||
// This is needed to ensure that we use the NodeJS adapter in the render process
|
||||
...(global?.require && {
|
||||
adapter: global.require('axios/lib/adapters/http'),
|
||||
}),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const anonymousId = await getDeviceId();
|
||||
// This may return an empty string or undefined when a user is not logged in
|
||||
const userId = getAccountId();
|
||||
segmentClient.track({
|
||||
anonymousId,
|
||||
userId,
|
||||
event,
|
||||
properties,
|
||||
...(timestamp ? { timestamp } : {}),
|
||||
context: {
|
||||
app: {
|
||||
name: getAppName(),
|
||||
version: getAppVersion(),
|
||||
},
|
||||
os: {
|
||||
name: _getOsName(),
|
||||
version: process.getSystemVersion(),
|
||||
},
|
||||
},
|
||||
}, error => {
|
||||
if (error) {
|
||||
console.warn('[analytics] Error sending segment event', error);
|
||||
}
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
console.warn('[analytics] Unexpected error while sending segment event', error);
|
||||
}
|
||||
export async function trackPageView(name: string) {
|
||||
const settings = await models.settings.getOrCreate();
|
||||
if (!settings.enableAnalytics) return;
|
||||
sendSegment('page', { name });
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~ //
|
||||
@ -226,156 +157,7 @@ export async function trackSegmentEvent(
|
||||
// ~~~~~~~~~~~~~~~~~ //
|
||||
function _getOsName() {
|
||||
const platform = getAppPlatform();
|
||||
|
||||
switch (platform) {
|
||||
case 'darwin':
|
||||
return 'mac';
|
||||
|
||||
case 'win32':
|
||||
return 'windows';
|
||||
|
||||
default:
|
||||
return platform;
|
||||
}
|
||||
}
|
||||
|
||||
// Exported for testing
|
||||
export async function _trackEvent({
|
||||
interactive,
|
||||
category,
|
||||
action,
|
||||
label,
|
||||
value,
|
||||
}: {
|
||||
interactive: boolean;
|
||||
category: string;
|
||||
action: string;
|
||||
label?: string | null;
|
||||
value?: string | null;
|
||||
}) {
|
||||
const prefix = interactive ? '[ga] Event' : '[ga] Non-interactive';
|
||||
console.log(prefix, [category, action, label, value].filter(Boolean).join(', '));
|
||||
const params = [
|
||||
{
|
||||
name: KEY_HIT_TYPE,
|
||||
value: 'event',
|
||||
},
|
||||
{
|
||||
name: KEY_EVENT_CATEGORY,
|
||||
value: category,
|
||||
},
|
||||
{
|
||||
name: KEY_EVENT_ACTION,
|
||||
value: action,
|
||||
},
|
||||
|
||||
...(!interactive ? [{
|
||||
name: KEY_NON_INTERACTION,
|
||||
value: '1',
|
||||
}] : []),
|
||||
|
||||
...(label ? [{
|
||||
name: KEY_EVENT_LABEL,
|
||||
value: label,
|
||||
}] : []),
|
||||
|
||||
...(value ? [{
|
||||
name: KEY_EVENT_VALUE,
|
||||
value: value,
|
||||
}] : []),
|
||||
];
|
||||
|
||||
await _sendToGoogle({ params });
|
||||
}
|
||||
|
||||
export async function _trackPageView(location: string) {
|
||||
_currentLocationPath = location;
|
||||
console.log('[ga] Page', _currentLocationPath);
|
||||
const params = [
|
||||
{
|
||||
name: KEY_HIT_TYPE,
|
||||
value: 'pageview',
|
||||
},
|
||||
];
|
||||
await _sendToGoogle({ params });
|
||||
}
|
||||
|
||||
async function _getDefaultParams(): Promise<RequestParameter[]> {
|
||||
const deviceId = await getDeviceId();
|
||||
// Prepping user agent string prior to sending to GA due to Electron base UA not being GA friendly.
|
||||
const ua = String(window?.navigator?.userAgent)
|
||||
.replace(new RegExp(`${getAppId()}\\/\\d+\\.\\d+\\.\\d+ `), '')
|
||||
.replace(/Electron\/\d+\.\d+\.\d+ /, '');
|
||||
|
||||
const viewport = getViewportSize();
|
||||
|
||||
const params = [
|
||||
{
|
||||
name: KEY_VERSION,
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
name: KEY_TRACKING_ID,
|
||||
value: getGoogleAnalyticsId(),
|
||||
},
|
||||
{
|
||||
name: KEY_CLIENT_ID,
|
||||
value: deviceId,
|
||||
},
|
||||
{
|
||||
name: KEY_USER_AGENT,
|
||||
value: ua,
|
||||
},
|
||||
{
|
||||
name: KEY_LOCATION,
|
||||
value: getGoogleAnalyticsLocation() + _currentLocationPath,
|
||||
},
|
||||
{
|
||||
name: KEY_SCREEN_RESOLUTION,
|
||||
value: getScreenResolution(),
|
||||
},
|
||||
{
|
||||
name: KEY_USER_LANGUAGE,
|
||||
value: getUserLanguage(),
|
||||
},
|
||||
{
|
||||
name: KEY_TITLE,
|
||||
value: `${getAppId()}:${getAppVersion()}`,
|
||||
},
|
||||
{
|
||||
name: KEY_CUSTOM_DIMENSION_PREFIX + DIMENSION_PLATFORM,
|
||||
value: getAppPlatform(),
|
||||
},
|
||||
{
|
||||
name: KEY_CUSTOM_DIMENSION_PREFIX + DIMENSION_VERSION,
|
||||
value: getAppVersion(),
|
||||
},
|
||||
{
|
||||
name: KEY_ANONYMIZE_IP,
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
name: KEY_APPLICATION_NAME,
|
||||
value: getAppName(),
|
||||
},
|
||||
{
|
||||
name: KEY_APPLICATION_ID,
|
||||
value: getAppId(),
|
||||
},
|
||||
{
|
||||
name: KEY_APPLICATION_VERSION,
|
||||
value: getAppVersion(),
|
||||
},
|
||||
...(viewport ? [{
|
||||
name: KEY_VIEWPORT_SIZE,
|
||||
value: viewport,
|
||||
}] : []),
|
||||
...(global.document ? [{
|
||||
name: KEY_DOCUMENT_ENCODING,
|
||||
value: global.document.inputEncoding,
|
||||
}] : []),
|
||||
];
|
||||
return params;
|
||||
return { darwin: 'mac', win32: 'windows' }[platform] || platform;
|
||||
}
|
||||
|
||||
// Monitor database changes to see if analytics gets enabled.
|
||||
@ -383,72 +165,9 @@ async function _getDefaultParams(): Promise<RequestParameter[]> {
|
||||
db.onChange(async changes => {
|
||||
for (const change of changes) {
|
||||
const [event, doc] = change;
|
||||
|
||||
if (isSettings(doc) && event === 'update') {
|
||||
if (doc.enableAnalytics) {
|
||||
await flushQueuedEvents();
|
||||
}
|
||||
const isUpdatingSettings = isSettings(doc) && event === 'update';
|
||||
if (isUpdatingSettings && doc.enableAnalytics) {
|
||||
await flushQueuedEvents();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function _sendToGoogle({ params }: { params: RequestParameter[] }) {
|
||||
const settings = await models.settings.getOrCreate();
|
||||
|
||||
if (!settings.enableAnalytics) {
|
||||
return;
|
||||
}
|
||||
|
||||
const baseParams = await _getDefaultParams();
|
||||
const allParams = [...baseParams, ...params];
|
||||
const qs = buildQueryStringFromParams(allParams);
|
||||
const baseUrl = isDevelopment()
|
||||
? 'https://www.google-analytics.com/debug/collect'
|
||||
: 'https://www.google-analytics.com/collect';
|
||||
const url = joinUrlAndQueryString(baseUrl, qs);
|
||||
const net = (electron.remote || electron).net;
|
||||
const request = net.request(url);
|
||||
request.once('error', err => {
|
||||
console.warn('[ga] Network error', err);
|
||||
});
|
||||
request.once('response', response => {
|
||||
const { statusCode } = response;
|
||||
|
||||
if (statusCode < 200 && statusCode >= 300) {
|
||||
console.warn('[ga] Bad status code ' + statusCode);
|
||||
}
|
||||
|
||||
const chunks: Buffer[] = [];
|
||||
const [contentType] = response.headers['content-type'] || [];
|
||||
|
||||
if (contentType !== 'application/json') {
|
||||
// Production GA API returns a Gif to use for tracking
|
||||
return;
|
||||
}
|
||||
|
||||
response.on('end', () => {
|
||||
const jsonStr = Buffer.concat(chunks).toString('utf8');
|
||||
|
||||
try {
|
||||
const data = JSON.parse(jsonStr);
|
||||
const { hitParsingResult } = data;
|
||||
|
||||
if (hitParsingResult.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const result of hitParsingResult || []) {
|
||||
for (const msg of result.parserMessage || []) {
|
||||
console.warn(`[ga] Error ${msg.description}`);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[ga] Failed to parse response', err);
|
||||
}
|
||||
});
|
||||
response.on('data', chunk => {
|
||||
chunks.push(chunk);
|
||||
});
|
||||
});
|
||||
request.end();
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import { isUnitTest } from '../models/unit-test';
|
||||
import { isUnitTestSuite } from '../models/unit-test-suite';
|
||||
import { isWorkspace, Workspace } from '../models/workspace';
|
||||
import { resetKeys } from '../sync/ignore-keys';
|
||||
import { trackEvent } from './analytics';
|
||||
import { SegmentEvent, trackSegmentEvent } from './analytics';
|
||||
import {
|
||||
EXPORT_TYPE_API_SPEC,
|
||||
EXPORT_TYPE_COOKIE_JAR,
|
||||
@ -113,7 +113,7 @@ export async function exportRequestsHAR(
|
||||
}
|
||||
|
||||
const data = await har.exportHar(harRequests);
|
||||
trackEvent('Data', 'Export', 'HAR');
|
||||
trackSegmentEvent(SegmentEvent.dataExport);
|
||||
return JSON.stringify(data, null, '\t');
|
||||
}
|
||||
|
||||
@ -247,7 +247,7 @@ export async function exportRequestsData(
|
||||
delete d.type;
|
||||
return d;
|
||||
});
|
||||
trackEvent('Data', 'Export', `Insomnia ${format}`);
|
||||
trackSegmentEvent(SegmentEvent.dataExport);
|
||||
|
||||
if (format.toLowerCase() === 'yaml') {
|
||||
return YAML.stringify(data);
|
||||
|
@ -9,7 +9,7 @@ import { isWorkspace, Workspace } from '../models/workspace';
|
||||
import { AlertModal } from '../ui/components/modals/alert-modal';
|
||||
import { showError, showModal } from '../ui/components/modals/index';
|
||||
import { ImportToWorkspacePrompt, SetWorkspaceScopePrompt } from '../ui/redux/modules/helpers';
|
||||
import { trackEvent } from './analytics';
|
||||
import { SegmentEvent, trackSegmentEvent } from './analytics';
|
||||
import {
|
||||
BASE_ENVIRONMENT_ID_KEY,
|
||||
CONTENT_TYPE_GRAPHQL,
|
||||
@ -321,7 +321,7 @@ export async function importRaw(
|
||||
}
|
||||
|
||||
await db.flushChanges();
|
||||
trackEvent('Data', 'Import', resultsType.id);
|
||||
trackSegmentEvent(SegmentEvent.dataImport);
|
||||
const importRequest: ImportResult = {
|
||||
source: resultsType && typeof resultsType.id === 'string' ? resultsType.id : 'unknown',
|
||||
summary: importedDocs,
|
||||
|
@ -9,7 +9,6 @@ import * as models from '../models';
|
||||
import { getModelName } from '../models';
|
||||
import type { Settings } from '../models/settings';
|
||||
import { forceWorkspaceScopeToDesign } from '../sync/git/force-workspace-scope-to-design';
|
||||
import { trackEvent } from './analytics';
|
||||
import { database as db } from './database';
|
||||
|
||||
async function loadDesignerDb(
|
||||
@ -158,7 +157,6 @@ export default async function migrateFromDesigner({
|
||||
const modelTypesToMerge = [];
|
||||
|
||||
if (useDesignerSettings) {
|
||||
trackEvent('Data', 'Migration', 'Settings');
|
||||
// @ts-expect-error -- TSCONVERSION
|
||||
modelTypesToMerge.push(models.settings.type);
|
||||
console.log('[db-merge] keeping settings from Insomnia Designer');
|
||||
@ -167,7 +165,6 @@ export default async function migrateFromDesigner({
|
||||
}
|
||||
|
||||
if (copyWorkspaces) {
|
||||
trackEvent('Data', 'Migration', 'Workspaces');
|
||||
// @ts-expect-error -- TSCONVERSION
|
||||
modelTypesToMerge.push(...workspaceModels);
|
||||
}
|
||||
@ -222,17 +219,14 @@ export default async function migrateFromDesigner({
|
||||
|
||||
if (copyPlugins) {
|
||||
console.log('[db-merge] migrating plugins from designer to core');
|
||||
trackEvent('Data', 'Migration', 'Plugins');
|
||||
await migratePlugins(designerDataDir, coreDataDir);
|
||||
}
|
||||
|
||||
console.log('[db-merge] done!');
|
||||
trackEvent('Data', 'Migration', 'Success');
|
||||
return {};
|
||||
} catch (error) {
|
||||
console.log('[db-merge] an error occurred while migrating');
|
||||
console.error(error);
|
||||
trackEvent('Data', 'Migration', 'Failure');
|
||||
await restoreCoreBackup(backupDir, coreDataDir);
|
||||
return {
|
||||
error,
|
||||
|
@ -1,7 +1,6 @@
|
||||
import * as git from 'isomorphic-git';
|
||||
import path from 'path';
|
||||
|
||||
import { trackEvent } from '../../common/analytics';
|
||||
import { httpClient } from './http-client';
|
||||
import { convertToOsSep, convertToPosixSep } from './path-sep';
|
||||
import { gitCallbacks } from './utils';
|
||||
@ -223,7 +222,6 @@ export class GitVCS {
|
||||
|
||||
async commit(message: string) {
|
||||
console.log(`[git] Commit "${message}"`);
|
||||
trackEvent('Git', 'Commit');
|
||||
return git.commit({ ...this._baseOpts, message });
|
||||
}
|
||||
|
||||
@ -264,7 +262,6 @@ export class GitVCS {
|
||||
|
||||
async push(gitCredentials?: GitCredentials | null, force = false) {
|
||||
console.log(`[git] Push remote=origin force=${force ? 'true' : 'false'}`);
|
||||
trackEvent('Git', 'Push');
|
||||
// eslint-disable-next-line no-unreachable
|
||||
const response: git.PushResult = await git.push({
|
||||
...this._baseOpts,
|
||||
@ -286,7 +283,6 @@ export class GitVCS {
|
||||
|
||||
async pull(gitCredentials?: GitCredentials | null) {
|
||||
console.log('[git] Pull remote=origin', await this.getBranch());
|
||||
trackEvent('Git', 'Pull');
|
||||
return git.pull({
|
||||
...this._baseOpts,
|
||||
...gitCallbacks(gitCredentials),
|
||||
@ -298,7 +294,6 @@ export class GitVCS {
|
||||
async merge(theirBranch: string) {
|
||||
const ours = await this.getBranch();
|
||||
console.log(`[git] Merge ${ours} <-- ${theirBranch}`);
|
||||
trackEvent('Git', 'Merge');
|
||||
return git.merge({
|
||||
...this._baseOpts,
|
||||
ours,
|
||||
@ -336,13 +331,11 @@ export class GitVCS {
|
||||
}
|
||||
|
||||
async branch(branch: string, checkout = false) {
|
||||
trackEvent('Git', 'Create Branch');
|
||||
// @ts-expect-error -- TSCONVERSION remote doesn't exist as an option
|
||||
await git.branch({ ...this._baseOpts, ref: branch, checkout, remote: 'origin' });
|
||||
}
|
||||
|
||||
async deleteBranch(branch: string) {
|
||||
trackEvent('Git', 'Delete Branch');
|
||||
await git.deleteBranch({ ...this._baseOpts, ref: branch });
|
||||
}
|
||||
|
||||
@ -353,7 +346,6 @@ export class GitVCS {
|
||||
const branches = await this.listBranches();
|
||||
|
||||
if (branches.includes(branch)) {
|
||||
trackEvent('Git', 'Checkout Branch');
|
||||
await git.checkout({ ...this._baseOpts, ref: branch, remote: 'origin' });
|
||||
} else {
|
||||
await this.branch(branch, true);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { autoBindMethodsForReact } from 'class-autobind-decorator';
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import { trackEvent } from '../../../common/analytics';
|
||||
import { SegmentEvent, trackSegmentEvent } from '../../../common/analytics';
|
||||
import {
|
||||
AUTOBIND_CFG,
|
||||
CONTENT_TYPE_EDN,
|
||||
@ -72,7 +72,7 @@ export class ContentTypeDropdown extends PureComponent<Props> {
|
||||
}
|
||||
|
||||
this.props.onChange(mimeType);
|
||||
trackEvent('Request', 'Change MimeType', mimeType);
|
||||
trackSegmentEvent(SegmentEvent.requestBodyTypeSelect, { type:mimeType });
|
||||
}
|
||||
|
||||
_renderDropdownItem(mimeType: string | null, forcedName = '') {
|
||||
|
@ -4,7 +4,7 @@ import React, { Fragment, PureComponent, ReactNode } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
|
||||
import { SegmentEvent, trackEvent, trackSegmentEvent, vcsSegmentEventProperties } from '../../../common/analytics';
|
||||
import { SegmentEvent, trackSegmentEvent, vcsSegmentEventProperties } from '../../../common/analytics';
|
||||
import { AUTOBIND_CFG } from '../../../common/constants';
|
||||
import { database as db } from '../../../common/database';
|
||||
import { docsGitSync } from '../../../common/documentation';
|
||||
@ -111,7 +111,7 @@ class GitSyncDropdown extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
async _handleOpen() {
|
||||
trackEvent('Git Dropdown', 'Open');
|
||||
trackSegmentEvent(SegmentEvent.vcsSyncStart, vcsSegmentEventProperties('git', 'setup'));
|
||||
await this._refreshState();
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { trackEvent } from '../../../common/analytics';
|
||||
import { trackPageView } from '../../../common/analytics';
|
||||
import { AlertModal, AlertModalOptions } from './alert-modal';
|
||||
import { ErrorModal, ErrorModalOptions } from './error-modal';
|
||||
import { PromptModal, PromptModalOptions } from './prompt-modal';
|
||||
@ -15,7 +15,7 @@ export function registerModal(instance) {
|
||||
}
|
||||
|
||||
export function showModal(modalCls, ...args) {
|
||||
trackEvent('Modals', 'Show', modalCls.name);
|
||||
trackPageView(modalCls.name);
|
||||
return _getModal(modalCls).show(...args);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { autoBindMethodsForReact } from 'class-autobind-decorator';
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import { trackEvent } from '../../../common/analytics';
|
||||
import { SegmentEvent, trackSegmentEvent } from '../../../common/analytics';
|
||||
import {
|
||||
AUTOBIND_CFG,
|
||||
getContentTypeName,
|
||||
@ -97,7 +97,7 @@ export class RequestCreateModal extends PureComponent<{}, State> {
|
||||
}
|
||||
|
||||
this.hide();
|
||||
trackEvent('Request', 'Create');
|
||||
trackSegmentEvent(SegmentEvent.requestCreate);
|
||||
}
|
||||
|
||||
_handleChangeSelectedContentType(selectedContentType: string | null) {
|
||||
|
@ -3,7 +3,6 @@ import { Tooltip } from 'insomnia-components';
|
||||
import React, { FC, Fragment, useCallback } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { trackEvent } from '../../../common/analytics';
|
||||
import {
|
||||
ACTIVITY_MIGRATION,
|
||||
EditorKeyMap,
|
||||
@ -102,7 +101,6 @@ export const General: FC<Props> = ({ hideModal }) => {
|
||||
const settings = useSelector(selectSettings);
|
||||
|
||||
const handleStartMigration = useCallback(() => {
|
||||
trackEvent('Data', 'Migration', 'Manual');
|
||||
dispatch(setActiveActivity(ACTIVITY_MIGRATION));
|
||||
hideModal();
|
||||
}, [hideModal, dispatch]);
|
||||
|
@ -5,7 +5,6 @@ import styled from 'styled-components';
|
||||
import YAML from 'yaml';
|
||||
import YAMLSourceMap from 'yaml-source-map';
|
||||
|
||||
import { trackEvent } from '../../../common/analytics';
|
||||
import { AUTOBIND_CFG } from '../../../common/constants';
|
||||
import type { ApiSpec } from '../../../models/api-spec';
|
||||
|
||||
@ -41,7 +40,6 @@ export class SpecEditorSidebar extends Component<Props, State> {
|
||||
col: number;
|
||||
};
|
||||
}) {
|
||||
trackEvent('Spec Sidebar', 'Navigate');
|
||||
const { handleSetSelection } = this.props;
|
||||
// NOTE: We're subtracting 1 from everything because YAML CST uses
|
||||
// 1-based indexing and we use 0-based.
|
||||
|
@ -3,7 +3,6 @@ import React, { FunctionComponent, useCallback, useMemo, useState } from 'react'
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useMount } from 'react-use';
|
||||
|
||||
import { trackEvent } from '../../common/analytics';
|
||||
import { ACTIVITY_HOME } from '../../common/constants';
|
||||
import { getDataDirectory, getDesignerDataDir, restartApp } from '../../common/electron-helpers';
|
||||
import type { MigrationOptions } from '../../common/migrate-from-designer';
|
||||
@ -276,7 +275,6 @@ const MigrationBody = () => {
|
||||
|
||||
const reduxDispatch = useDispatch();
|
||||
const cancel = useCallback(() => {
|
||||
trackEvent('Data', 'Migration', 'Skip');
|
||||
reduxDispatch(setActiveActivity(ACTIVITY_HOME));
|
||||
}, [reduxDispatch]);
|
||||
|
||||
|
@ -2,7 +2,6 @@ import { autoBindMethodsForReact } from 'class-autobind-decorator';
|
||||
import * as importers from 'insomnia-importers';
|
||||
import React, { Fragment, PureComponent, Ref } from 'react';
|
||||
|
||||
import { trackPageView } from '../../common/analytics';
|
||||
import type { GlobalActivity } from '../../common/constants';
|
||||
import {
|
||||
ACTIVITY_DEBUG,
|
||||
@ -439,21 +438,6 @@ export class Wrapper extends PureComponent<WrapperProps, State> {
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { activity } = this.props;
|
||||
trackPageView(`/${activity || ''}`);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: WrapperProps) {
|
||||
// We're using activities as page views so here we monitor
|
||||
// for a change in activity and send it as a pageview.
|
||||
const { activity } = this.props;
|
||||
|
||||
if (prevProps.activity !== activity) {
|
||||
trackPageView(`/${activity || ''}`);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
activeCookieJar,
|
||||
|
@ -6,7 +6,7 @@ import { hot } from 'react-hot-loader';
|
||||
import { Provider } from 'react-redux';
|
||||
import * as styledComponents from 'styled-components';
|
||||
|
||||
import { trackEvent } from '../common/analytics';
|
||||
import { SegmentEvent, trackSegmentEvent } from '../common/analytics';
|
||||
import { getAppLongName, isDevelopment } from '../common/constants';
|
||||
import { database as db } from '../common/database';
|
||||
import { initializeLogging } from '../common/log';
|
||||
@ -69,11 +69,11 @@ window['styled-components'] = styledComponents;
|
||||
if (window && !isDevelopment()) {
|
||||
window.addEventListener('error', e => {
|
||||
console.error('Uncaught Error', e.error || e);
|
||||
trackEvent('Error', 'Uncaught Error');
|
||||
trackSegmentEvent(SegmentEvent.criticalError, { detail: e?.message });
|
||||
});
|
||||
window.addEventListener('unhandledrejection', e => {
|
||||
console.error('Unhandled Promise', e.reason);
|
||||
trackEvent('Error', 'Uncaught Promise');
|
||||
trackSegmentEvent(SegmentEvent.criticalError, { detail: e?.reason });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ import { mocked } from 'ts-jest/utils';
|
||||
|
||||
import { globalBeforeEach } from '../../../../__jest__/before-each';
|
||||
import { reduxStateForTest } from '../../../../__jest__/redux-state-for-test';
|
||||
import { SegmentEvent, trackEvent, trackSegmentEvent } from '../../../../common/analytics';
|
||||
import { SegmentEvent, trackSegmentEvent } from '../../../../common/analytics';
|
||||
import { ACTIVITY_SPEC } from '../../../../common/constants';
|
||||
import * as models from '../../../../models';
|
||||
import { gitRepositorySchema } from '../../../../models/__schemas__/model-schemas';
|
||||
@ -84,7 +84,6 @@ describe('git', () => {
|
||||
|
||||
const shouldPromptToCreateWorkspace = async (memClient: PromiseFsClient) => {
|
||||
const { repoSettings } = await dispatchCloneAndSubmitSettings(memClient);
|
||||
expect(trackEvent).toHaveBeenCalledWith('Git', 'Clone');
|
||||
// show alert asking to create a document
|
||||
const alertArgs = getAndClearShowAlertMockArgs();
|
||||
expect(alertArgs.title).toBe('No document found');
|
||||
@ -111,7 +110,6 @@ describe('git', () => {
|
||||
expect(meta?.gitRepositoryId).toBe(repoSettings._id);
|
||||
// Ensure tracking events
|
||||
expect(trackSegmentEvent).toHaveBeenCalledWith(SegmentEvent.documentCreate);
|
||||
expect(trackEvent).toHaveBeenCalledWith('Workspace', 'Create');
|
||||
// Ensure activity is activated
|
||||
expect(store.getActions()).toEqual([
|
||||
{
|
||||
|
@ -3,7 +3,6 @@ import configureMockStore from 'redux-mock-store';
|
||||
import thunk from 'redux-thunk';
|
||||
|
||||
import { globalBeforeEach } from '../../../../__jest__/before-each';
|
||||
import { trackEvent } from '../../../../common/analytics';
|
||||
import {
|
||||
ACTIVITY_DEBUG,
|
||||
ACTIVITY_HOME,
|
||||
@ -68,7 +67,6 @@ describe('global', () => {
|
||||
activity,
|
||||
};
|
||||
expect(setActiveActivity(activity)).toStrictEqual(expectedEvent);
|
||||
expect(trackEvent).toHaveBeenCalledWith('Activity', 'Change', activity);
|
||||
expect(global.localStorage.getItem(`${LOCALSTORAGE_PREFIX}::activity`)).toBe(
|
||||
JSON.stringify(activity),
|
||||
);
|
||||
|
@ -3,7 +3,7 @@ import thunk from 'redux-thunk';
|
||||
|
||||
import { globalBeforeEach } from '../../../../__jest__/before-each';
|
||||
import { reduxStateForTest } from '../../../../__jest__/redux-state-for-test';
|
||||
import { SegmentEvent, trackEvent, trackSegmentEvent } from '../../../../common/analytics';
|
||||
import { SegmentEvent, trackSegmentEvent } from '../../../../common/analytics';
|
||||
import { ACTIVITY_HOME } from '../../../../common/constants';
|
||||
import * as models from '../../../../models';
|
||||
import { DEFAULT_PROJECT_ID } from '../../../../models/project';
|
||||
@ -49,7 +49,6 @@ describe('project', () => {
|
||||
const project = projects[1];
|
||||
expect(project.name).toBe(projectName);
|
||||
expect(trackSegmentEvent).toHaveBeenCalledWith(SegmentEvent.projectLocalCreate);
|
||||
expect(trackEvent).toHaveBeenCalledWith('Project', 'Create');
|
||||
expect(store.getActions()).toEqual([
|
||||
{
|
||||
type: SET_ACTIVE_PROJECT,
|
||||
@ -93,7 +92,6 @@ describe('project', () => {
|
||||
const project = projects[1];
|
||||
expect(project).toStrictEqual(projectTwo);
|
||||
expect(trackSegmentEvent).toHaveBeenCalledWith(SegmentEvent.projectLocalDelete);
|
||||
expect(trackEvent).toHaveBeenCalledWith('Project', 'Delete');
|
||||
expect(store.getActions()).toEqual([
|
||||
{
|
||||
type: SET_ACTIVE_PROJECT,
|
||||
|
@ -3,7 +3,7 @@ import thunk from 'redux-thunk';
|
||||
|
||||
import { globalBeforeEach } from '../../../../__jest__/before-each';
|
||||
import { reduxStateForTest } from '../../../../__jest__/redux-state-for-test';
|
||||
import { SegmentEvent, trackEvent, trackSegmentEvent } from '../../../../common/analytics';
|
||||
import { SegmentEvent, trackSegmentEvent } from '../../../../common/analytics';
|
||||
import { ACTIVITY_DEBUG, ACTIVITY_SPEC, ACTIVITY_UNIT_TEST } from '../../../../common/constants';
|
||||
import { database } from '../../../../common/database';
|
||||
import * as models from '../../../../models';
|
||||
@ -62,7 +62,6 @@ describe('workspace', () => {
|
||||
const workspaceId = await expectedModelsCreated(workspaceName, WorkspaceScopeKeys.design, projectId);
|
||||
|
||||
expect(trackSegmentEvent).toHaveBeenCalledWith(SegmentEvent.documentCreate);
|
||||
expect(trackEvent).toHaveBeenCalledWith('Workspace', 'Create');
|
||||
expect(store.getActions()).toEqual([
|
||||
{
|
||||
type: SET_ACTIVE_PROJECT,
|
||||
@ -96,7 +95,6 @@ describe('workspace', () => {
|
||||
const workspaceId = await expectedModelsCreated(workspaceName, WorkspaceScopeKeys.collection, projectId);
|
||||
|
||||
expect(trackSegmentEvent).toHaveBeenCalledWith(SegmentEvent.collectionCreate);
|
||||
expect(trackEvent).toHaveBeenCalledWith('Workspace', 'Create');
|
||||
expect(store.getActions()).toEqual([
|
||||
{
|
||||
type: SET_ACTIVE_PROJECT,
|
||||
|
@ -3,7 +3,7 @@ import path from 'path';
|
||||
import React, { ReactNode } from 'react';
|
||||
import YAML from 'yaml';
|
||||
|
||||
import { SegmentEvent, trackEvent, trackSegmentEvent, vcsSegmentEventProperties } from '../../../common/analytics';
|
||||
import { SegmentEvent, trackSegmentEvent, vcsSegmentEventProperties } from '../../../common/analytics';
|
||||
import { database as db } from '../../../common/database';
|
||||
import { strings } from '../../../common/strings';
|
||||
import * as models from '../../../models';
|
||||
@ -164,7 +164,6 @@ export const cloneGitRepository = ({ createFsClient }: {
|
||||
dispatch(loadStart());
|
||||
repoSettingsPatch.needsFullClone = true;
|
||||
repoSettingsPatch.uri = translateSSHtoHTTP(repoSettingsPatch.uri);
|
||||
trackEvent('Git', 'Clone');
|
||||
let fsClient = createFsClient();
|
||||
|
||||
try {
|
||||
|
@ -6,7 +6,7 @@ import React, { Fragment } from 'react';
|
||||
import { combineReducers, Dispatch } from 'redux';
|
||||
import { unreachableCase } from 'ts-assert-unreachable';
|
||||
|
||||
import { trackEvent } from '../../../common/analytics';
|
||||
import { trackPageView } from '../../../common/analytics';
|
||||
import type { DashboardSortOrder, GlobalActivity } from '../../../common/constants';
|
||||
import {
|
||||
ACTIVITY_DEBUG,
|
||||
@ -319,7 +319,7 @@ export const loadRequestStop = (requestId: string) => ({
|
||||
export const setActiveActivity = (activity: GlobalActivity) => {
|
||||
activity = _normalizeActivity(activity);
|
||||
window.localStorage.setItem(`${LOCALSTORAGE_PREFIX}::activity`, JSON.stringify(activity));
|
||||
trackEvent('Activity', 'Change', activity);
|
||||
trackPageView(activity);
|
||||
return {
|
||||
type: SET_ACTIVE_ACTIVITY,
|
||||
activity,
|
||||
@ -690,7 +690,6 @@ export const initActiveActivity = () => (dispatch, getState) => {
|
||||
} else {
|
||||
// Always check if user has been prompted to migrate or onboard
|
||||
if (!settings.hasPromptedToMigrateFromDesigner && fs.existsSync(getDesignerDataDir())) {
|
||||
trackEvent('Data', 'Migration', 'Auto');
|
||||
overrideActivity = ACTIVITY_MIGRATION;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { SegmentEvent, trackEvent, trackSegmentEvent } from '../../../common/analytics';
|
||||
import { SegmentEvent, trackSegmentEvent } from '../../../common/analytics';
|
||||
import { ACTIVITY_HOME } from '../../../common/constants';
|
||||
import { strings } from '../../../common/strings';
|
||||
import * as models from '../../../models';
|
||||
@ -18,7 +18,6 @@ export const createProject = () => dispatch => {
|
||||
selectText: true,
|
||||
onComplete: async name => {
|
||||
const project = await models.project.create({ name });
|
||||
trackEvent('Project', 'Create');
|
||||
dispatch(setActiveProject(project._id));
|
||||
dispatch(setActiveActivity(ACTIVITY_HOME));
|
||||
trackSegmentEvent(SegmentEvent.projectLocalCreate);
|
||||
@ -39,7 +38,6 @@ export const removeProject = (project: Project) => dispatch => {
|
||||
onConfirm: async () => {
|
||||
await models.stats.incrementDeletedRequestsForDescendents(project);
|
||||
await models.project.remove(project);
|
||||
trackEvent('Project', 'Delete');
|
||||
// Show default project
|
||||
dispatch(setActiveProject(DEFAULT_PROJECT_ID));
|
||||
// Show home in case not already on home
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Dispatch } from 'redux';
|
||||
import { RequireExactlyOne } from 'type-fest';
|
||||
|
||||
import { SegmentEvent, trackEvent, trackSegmentEvent } from '../../../common/analytics';
|
||||
import { SegmentEvent, trackSegmentEvent } from '../../../common/analytics';
|
||||
import { ACTIVITY_DEBUG, ACTIVITY_SPEC, GlobalActivity, isCollectionActivity, isDesignActivity } from '../../../common/constants';
|
||||
import { database } from '../../../common/database';
|
||||
import * as models from '../../../models';
|
||||
@ -31,7 +31,8 @@ const actuallyCreate = (patch: Partial<Workspace>, onCreate?: OnWorkspaceCreateC
|
||||
await onCreate(workspace);
|
||||
}
|
||||
|
||||
trackEvent('Workspace', 'Create');
|
||||
trackSegmentEvent(SegmentEvent.collectionCreate);
|
||||
|
||||
await dispatch(activateWorkspace({ workspace }));
|
||||
};
|
||||
};
|
||||
|
13
packages/insomnia-inso/package-lock.json
generated
13
packages/insomnia-inso/package-lock.json
generated
@ -2382,6 +2382,14 @@
|
||||
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
|
||||
"dev": true
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.21.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.0"
|
||||
}
|
||||
},
|
||||
"babel-jest": {
|
||||
"version": "26.6.3",
|
||||
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz",
|
||||
@ -4299,6 +4307,11 @@
|
||||
"readable-stream": "^2.3.6"
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.7",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
|
||||
"integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ=="
|
||||
},
|
||||
"for-in": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
|
||||
|
@ -69,6 +69,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@stoplight/spectral": "^5.9.0",
|
||||
"axios": "^0.21.2",
|
||||
"commander": "^5.1.0",
|
||||
"consola": "^2.15.0",
|
||||
"cosmiconfig": "^6.0.0",
|
||||
|
@ -13,7 +13,7 @@ export const documentActions = [
|
||||
spec={spec}
|
||||
store={context.store}
|
||||
axios={context.__private.axios}
|
||||
trackEvent={context.__private.analytics.trackEvent}
|
||||
trackSegmentEvent={context.__private.analytics.trackSegmentEvent}
|
||||
/>,
|
||||
root,
|
||||
);
|
||||
|
@ -12,7 +12,7 @@ type Props = {
|
||||
data: Object,
|
||||
status: number,
|
||||
}>,
|
||||
trackEvent: (category: string, action: string, label: ?string, value: ?string) => any,
|
||||
trackSegmentEvent: (event: string, properties?: Record<string, any>) => any,
|
||||
store: {
|
||||
hasItem: (key: string) => Promise<boolean>,
|
||||
setItem: (key: string, value: string) => Promise<void>,
|
||||
@ -90,7 +90,7 @@ class DeployToPortal extends React.Component<Props, State> {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
const { spec, axios, trackEvent } = this.props;
|
||||
const { spec, axios, trackSegmentEvent } = this.props;
|
||||
|
||||
const {
|
||||
kongSpecFileName,
|
||||
@ -145,12 +145,14 @@ class DeployToPortal extends React.Component<Props, State> {
|
||||
});
|
||||
if (response.statusText === 'Created' || response.statusText === 'OK') {
|
||||
this.setState({ kongPortalDeployView: 'success' });
|
||||
trackEvent('Portal', 'Upload', overwrite ? 'Replace' : 'Create');
|
||||
const action = overwrite ? 'replace_portal' : 'create_portal'
|
||||
trackSegmentEvent('Kong Synced', { type: 'deploy', action })
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.response && err.response.status === 409) {
|
||||
this.setState({ kongPortalDeployView: 'overwrite' });
|
||||
trackEvent('Portal', 'Upload Error', overwrite ? 'Replace' : 'Create');
|
||||
const action = overwrite ? 'replace_portal' : 'create_portal'
|
||||
trackSegmentEvent('Kong Synced', { type: 'deploy', action, error: err.response.status + ': ' + err.response.statusText })
|
||||
} else {
|
||||
console.log('Failed to upload to dev portal', err.response);
|
||||
if (err.response && err.response.data && err.response.data.message) {
|
||||
@ -164,7 +166,7 @@ class DeployToPortal extends React.Component<Props, State> {
|
||||
async _handleConnectKong(e: SyntheticEvent<HTMLFormElement>) {
|
||||
e.preventDefault();
|
||||
|
||||
const { axios, trackEvent } = this.props;
|
||||
const { axios, trackSegmentEvent } = this.props;
|
||||
|
||||
const { kongPortalUserWorkspace, kongPortalApiUrl, kongPortalRbacToken } = this.state;
|
||||
|
||||
@ -182,7 +184,8 @@ class DeployToPortal extends React.Component<Props, State> {
|
||||
},
|
||||
});
|
||||
if (response.status === 200 || response.status === 201) {
|
||||
trackEvent('Portal', 'Connection');
|
||||
trackSegmentEvent('Kong Connected', { type: 'token', action: 'portal_deploy' })
|
||||
|
||||
// Set legacy mode for post upload formatting, suppress loader, set monitor portal URL, move to upload view
|
||||
const guiHost = response.data.configuration.portal_gui_host;
|
||||
this.setState({
|
||||
@ -195,7 +198,8 @@ class DeployToPortal extends React.Component<Props, State> {
|
||||
this._handleLoadingToggle(false);
|
||||
}
|
||||
} catch (error) {
|
||||
trackEvent('Portal', 'Connection Error');
|
||||
trackSegmentEvent('Kong Connected', { type: 'token', action: 'portal_deploy', error: error.message })
|
||||
|
||||
console.log('Connection error', error);
|
||||
this._handleLoadingToggle(false);
|
||||
this.setState({ connectionError: error });
|
||||
|
Loading…
Reference in New Issue
Block a user