Merge branch 'release/2020.5.2' into develop

This commit is contained in:
David Marby 2020-12-09 19:40:16 +01:00
commit cad2ebc932
14 changed files with 119 additions and 26 deletions

View File

@ -90,6 +90,21 @@ export function trackPageView(path: string) {
}); });
} }
export async function getDeviceId(): Promise<string> {
const settings = await models.settings.getOrCreate();
let { deviceId } = settings;
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 });
}
return deviceId;
}
// ~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~ //
// Private Functions // // Private Functions //
// ~~~~~~~~~~~~~~~~~ // // ~~~~~~~~~~~~~~~~~ //
@ -129,15 +144,7 @@ export async function _trackPageView(location: string) {
} }
async function _getDefaultParams(): Promise<Array<RequestParameter>> { async function _getDefaultParams(): Promise<Array<RequestParameter>> {
const settings = await models.settings.getOrCreate(); const deviceId = await getDeviceId();
// Migrate old GA ID into settings model
let { deviceId } = settings;
if (!deviceId) {
const oldId = (window && window.localStorage.gaClientId) || null;
deviceId = oldId || uuid.v4();
await models.settings.update(settings, { deviceId });
}
// Prepping user agent string prior to sending to GA due to Electron base UA not being GA friendly. // Prepping user agent string prior to sending to GA due to Electron base UA not being GA friendly.
const ua = String(window?.navigator?.userAgent) const ua = String(window?.navigator?.userAgent)

View File

@ -1,5 +1,5 @@
import * as db from './database'; import * as db from './database';
import { types as modelTypes } from '../models'; import { types as modelTypes, stats } from '../models';
import { send } from '../network/network'; import { send } from '../network/network';
import { getBodyBuffer } from '../models/response'; import { getBodyBuffer } from '../models/response';
@ -24,6 +24,7 @@ export async function getSendRequestCallbackMemDb(environmentId, memDB) {
export function getSendRequestCallback(environmentId) { export function getSendRequestCallback(environmentId) {
return async function sendRequest(requestId) { return async function sendRequest(requestId) {
stats.incrementExecutedRequests();
return sendAndTransform(requestId, environmentId); return sendAndTransform(requestId, environmentId);
}; };
} }

View File

@ -1,6 +1,9 @@
// @flow // @flow
import * as db from '../common/database'; import * as db from '../common/database';
import type { BaseModel } from './index'; import type { BaseModel } from './index';
import type { Workspace } from './workspace';
import type { RequestGroup } from './request-group';
import { isRequest, isGrpcRequest } from './helpers/is-model';
export const name = 'Stats'; export const name = 'Stats';
export const type = 'Stats'; export const type = 'Stats';
@ -14,6 +17,9 @@ type BaseStats = {
currentVersion: string | null, currentVersion: string | null,
lastVersion: string | null, lastVersion: string | null,
launches: number, launches: number,
createdRequests: number,
deletedRequests: number,
executedRequests: number,
}; };
export type Stats = BaseModel & BaseStats; export type Stats = BaseModel & BaseStats;
@ -25,6 +31,9 @@ export function init(): BaseStats {
currentVersion: null, currentVersion: null,
lastVersion: null, lastVersion: null,
launches: 0, launches: 0,
createdRequests: 0,
deletedRequests: 0,
executedRequests: 0,
}; };
} }
@ -49,3 +58,40 @@ export async function get(): Promise<Stats> {
return results[0]; return results[0];
} }
} }
export async function incrementRequestStats({
createdRequests,
deletedRequests,
executedRequests,
}: $Shape<Stats>) {
const stats = await get();
await update({
...(createdRequests && { createdRequests: stats.createdRequests + createdRequests }),
...(deletedRequests && { deletedRequests: stats.deletedRequests + deletedRequests }),
...(executedRequests && { executedRequests: stats.executedRequests + executedRequests }),
});
}
export async function incrementCreatedRequests() {
await incrementRequestStats({ createdRequests: 1 });
}
export async function incrementDeletedRequests() {
await incrementRequestStats({ deletedRequests: 1 });
}
export async function incrementExecutedRequests() {
await incrementRequestStats({ executedRequests: 1 });
}
export async function incrementCreatedRequestsForDescendents(doc: Workspace | RequestGroup) {
const docs = await db.withDescendants(doc);
const requests = docs.filter(doc => isRequest(doc) || isGrpcRequest(doc));
await incrementRequestStats({ createdRequests: requests.length });
}
export async function incrementDeletedRequestsForDescendents(doc: Workspace | RequestGroup) {
const docs = await db.withDescendants(doc);
const requests = docs.filter(doc => isRequest(doc) || isGrpcRequest(doc));
await incrementRequestStats({ deletedRequests: requests.length });
}

View File

@ -50,6 +50,9 @@ export const sendUnary = async (requestId: string, respond: ResponseCallbacks):
// Create callback // Create callback
const callback = _createUnaryCallback(requestId, respond); const callback = _createUnaryCallback(requestId, respond);
// Update request stats
models.stats.incrementExecutedRequests();
// Make call // Make call
const call = client.makeUnaryRequest( const call = client.makeUnaryRequest(
selectedMethod.path, selectedMethod.path,
@ -89,6 +92,9 @@ export const startClientStreaming = async (
// Create callback // Create callback
const callback = _createUnaryCallback(requestId, respond); const callback = _createUnaryCallback(requestId, respond);
// Update request stats
models.stats.incrementExecutedRequests();
// Make call // Make call
const call = client.makeClientStreamRequest( const call = client.makeClientStreamRequest(
selectedMethod.path, selectedMethod.path,
@ -131,6 +137,9 @@ export const startServerStreaming = async (
return; return;
} }
// Update request stats
models.stats.incrementExecutedRequests();
// Make call // Make call
const call = client.makeServerStreamRequest( const call = client.makeServerStreamRequest(
selectedMethod.path, selectedMethod.path,
@ -170,6 +179,9 @@ export const startBidiStreaming = async (
return; return;
} }
// Update request stats
models.stats.incrementExecutedRequests();
// Make call // Make call
const call = client.makeBidiStreamRequest( const call = client.makeBidiStreamRequest(
selectedMethod.path, selectedMethod.path,

View File

@ -51,6 +51,8 @@ class DocumentCardDropdown extends React.PureComponent<Props, State> {
const newWorkspace = await db.duplicate(workspace, { name: newName }); const newWorkspace = await db.duplicate(workspace, { name: newName });
await models.apiSpec.updateOrCreateForParentId(newWorkspace._id, { fileName: newName }); await models.apiSpec.updateOrCreateForParentId(newWorkspace._id, { fileName: newName });
models.stats.incrementCreatedRequestsForDescendents(newWorkspace);
handleSetActiveWorkspace(newWorkspace._id); handleSetActiveWorkspace(newWorkspace._id);
}, },
}); });
@ -94,6 +96,9 @@ class DocumentCardDropdown extends React.PureComponent<Props, State> {
if (isLastWorkspace) { if (isLastWorkspace) {
await models.workspace.create({ name: getAppName(), scope: 'spec' }); await models.workspace.create({ name: getAppName(), scope: 'spec' });
} }
await models.stats.incrementDeletedRequestsForDescendents(workspace);
await models.workspace.remove(workspace); await models.workspace.remove(workspace);
}, },
}); });

View File

@ -13,6 +13,7 @@ import { hotKeyRefs } from '../../../common/hotkeys';
import * as misc from '../../../common/misc'; import * as misc from '../../../common/misc';
import { isRequest } from '../../../models/helpers/is-model'; import { isRequest } from '../../../models/helpers/is-model';
import * as requestOperations from '../../../models/helpers/request-operations'; import * as requestOperations from '../../../models/helpers/request-operations';
import { incrementDeletedRequests } from '../../../models/stats';
@autobind @autobind
class RequestActionsDropdown extends PureComponent { class RequestActionsDropdown extends PureComponent {
@ -44,6 +45,7 @@ class RequestActionsDropdown extends PureComponent {
_handleRemove() { _handleRemove() {
const { request } = this.props; const { request } = this.props;
incrementDeletedRequests();
return requestOperations.remove(request); return requestOperations.remove(request);
} }

View File

@ -80,7 +80,9 @@ class RequestGroupActionsDropdown extends React.PureComponent<Props, State> {
this.props.handleCreateRequestGroup(this.props.requestGroup._id); this.props.handleCreateRequestGroup(this.props.requestGroup._id);
} }
_handleDeleteFolder() { async _handleDeleteFolder() {
await models.stats.incrementDeletedRequestsForDescendents(this.props.requestGroup);
models.requestGroup.remove(this.props.requestGroup); models.requestGroup.remove(this.props.requestGroup);
} }

View File

@ -183,6 +183,8 @@ class RequestSettingsModal extends React.PureComponent<Props, State> {
setTimeout(() => { setTimeout(() => {
this.setState({ justCopied: false }); this.setState({ justCopied: false });
}, 2000); }, 2000);
models.stats.incrementCreatedRequests();
} }
async show({ request, forceEditMode }: RequestSettingsModalOptions) { async show({ request, forceEditMode }: RequestSettingsModalOptions) {

View File

@ -20,6 +20,7 @@ import * as fetch from '../../account/fetch';
import imgSrcDesigner from '../images/insomnia-designer-logo.png'; import imgSrcDesigner from '../images/insomnia-designer-logo.png';
import imgSrcCore from '../images/insomnia-core-logo.png'; import imgSrcCore from '../images/insomnia-core-logo.png';
import { APP_ID_INSOMNIA } from '../../../config'; import { APP_ID_INSOMNIA } from '../../../config';
import { getDeviceId } from '../../common/analytics';
const LOCALSTORAGE_KEY = 'insomnia::notifications::seen'; const LOCALSTORAGE_KEY = 'insomnia::notifications::seen';
@ -127,6 +128,10 @@ class Toast extends React.PureComponent<Props, State> {
autoUpdatesDisabled: !settings.updateAutomatically, autoUpdatesDisabled: !settings.updateAutomatically,
disableUpdateNotification: settings.disableUpdateNotification, disableUpdateNotification: settings.disableUpdateNotification,
updateChannel: settings.updateChannel, updateChannel: settings.updateChannel,
deviceId: await getDeviceId(),
createdRequests: stats.createdRequests,
deletedRequests: stats.deletedRequests,
executedRequests: stats.executedRequests,
}; };
notification = await fetch.post('/notification', data, session.getCurrentSessionId()); notification = await fetch.post('/notification', data, session.getCurrentSessionId());

View File

@ -431,11 +431,15 @@ class Wrapper extends React.PureComponent<WrapperProps, State> {
title: 'Deleting Last Workspace', title: 'Deleting Last Workspace',
message: 'Since you deleted your only workspace, a new one has been created for you.', message: 'Since you deleted your only workspace, a new one has been created for you.',
onConfirm: async () => { onConfirm: async () => {
await models.stats.incrementDeletedRequestsForDescendents(activeWorkspace);
await models.workspace.create({ name: getAppName() }); await models.workspace.create({ name: getAppName() });
await models.workspace.remove(activeWorkspace); await models.workspace.remove(activeWorkspace);
}, },
}); });
} else { } else {
await models.stats.incrementDeletedRequestsForDescendents(activeWorkspace);
await models.workspace.remove(activeWorkspace); await models.workspace.remove(activeWorkspace);
} }
} }

View File

@ -210,6 +210,7 @@ class App extends PureComponent {
const parentId = activeRequest ? activeRequest.parentId : activeWorkspace._id; const parentId = activeRequest ? activeRequest.parentId : activeWorkspace._id;
const request = await models.request.create({ parentId, name: 'New Request' }); const request = await models.request.create({ parentId, name: 'New Request' });
await this._handleSetActiveRequest(request._id); await this._handleSetActiveRequest(request._id);
models.stats.incrementCreatedRequests();
}, },
], ],
[ [
@ -237,6 +238,7 @@ class App extends PureComponent {
return; return;
} }
await requestOperations.remove(activeRequest); await requestOperations.remove(activeRequest);
models.stats.incrementDeletedRequests();
}, },
}); });
}, },
@ -339,6 +341,7 @@ class App extends PureComponent {
parentId, parentId,
onComplete: requestId => { onComplete: requestId => {
this._handleSetActiveRequest(requestId); this._handleSetActiveRequest(requestId);
models.stats.incrementCreatedRequests();
}, },
}); });
} }
@ -381,7 +384,9 @@ class App extends PureComponent {
label: 'New Name', label: 'New Name',
selectText: true, selectText: true,
onComplete: async name => { onComplete: async name => {
await models.requestGroup.duplicate(requestGroup, { name }); const newRequestGroup = await models.requestGroup.duplicate(requestGroup, { name });
models.stats.incrementCreatedRequestsForDescendents(newRequestGroup);
}, },
}); });
} }
@ -404,6 +409,7 @@ class App extends PureComponent {
onComplete: async name => { onComplete: async name => {
const newRequest = await requestOperations.duplicate(request, { name }); const newRequest = await requestOperations.duplicate(request, { name });
await this._handleSetActiveRequest(newRequest._id); await this._handleSetActiveRequest(newRequest._id);
models.stats.incrementCreatedRequests();
}, },
}); });
} }
@ -435,6 +441,9 @@ class App extends PureComponent {
if (!isYes) { if (!isYes) {
return; return;
} }
await models.stats.incrementDeletedRequestsForDescendents(workspace);
await models.workspace.remove(workspace); await models.workspace.remove(workspace);
}, },
}); });
@ -453,6 +462,8 @@ class App extends PureComponent {
const newWorkspace = await db.duplicate(workspace, { name }); const newWorkspace = await db.duplicate(workspace, { name });
await this.props.handleSetActiveWorkspace(newWorkspace._id); await this.props.handleSetActiveWorkspace(newWorkspace._id);
callback(); callback();
models.stats.incrementCreatedRequestsForDescendents(newWorkspace);
}, },
}); });
} }
@ -681,12 +692,8 @@ class App extends PureComponent {
return; return;
} }
// NOTE: Since request is by far the most popular event, we will throttle // Update request stats
// it so that we only track it if the request has changed since the last one models.stats.incrementExecutedRequests();
const key = request._id;
if (this._sendRequestTrackingKey !== key) {
this._sendRequestTrackingKey = key;
}
// Start loading // Start loading
handleStartLoading(requestId); handleStartLoading(requestId);
@ -769,12 +776,8 @@ class App extends PureComponent {
return; return;
} }
// NOTE: Since request is by far the most popular event, we will throttle // Update request stats
// it so that we only track it if the request has changed since the last noe models.stats.incrementExecutedRequests();
const key = `${request._id}::${request.modified}`;
if (this._sendRequestTrackingKey !== key) {
this._sendRequestTrackingKey = key;
}
handleStartLoading(requestId); handleStartLoading(requestId);

View File

@ -313,6 +313,10 @@ function handleImportResult(result: ImportResult, errorMessage: string): Array<W
return []; return [];
} }
const createdRequests =
summary[models.request.type].length + summary[models.grpcRequest.type].length;
models.stats.incrementRequestStats({ createdRequests: createdRequests });
return summary[models.workspace.type] || []; return summary[models.workspace.type] || [];
} }

View File

@ -1,5 +1,5 @@
{ {
"version": "2020.5.1", "version": "2020.5.2",
"name": "insomnia", "name": "insomnia",
"executableName": "insomnia", "executableName": "insomnia",
"appId": "com.insomnia.app", "appId": "com.insomnia.app",

View File

@ -1,5 +1,5 @@
{ {
"version": "2020.5.1", "version": "2020.5.2",
"name": "insomnia-designer", "name": "insomnia-designer",
"executableName": "insomnia-designer", "executableName": "insomnia-designer",
"appId": "com.insomnia.designer", "appId": "com.insomnia.designer",