mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) Add welcomeQuestionsSubmitted telemetry event
Summary: The new event captures responses to the welcome questionnaire. Responses are also still sent to the special Grist document configured with the DOC_ID_NEW_USER_INFO variable. Test Plan: Tested manually. Reviewers: jarek Reviewed By: jarek Differential Revision: https://phab.getgrist.com/D4034
This commit is contained in:
parent
f659f3655d
commit
76e822eb23
@ -27,9 +27,8 @@ export function showWelcomeQuestions(userPrefsObs: Observable<UserPrefs>) {
|
|||||||
const showQuestions = getUserPrefObs(userPrefsObs, 'showNewUserQuestions');
|
const showQuestions = getUserPrefObs(userPrefsObs, 'showNewUserQuestions');
|
||||||
|
|
||||||
async function onConfirm() {
|
async function onConfirm() {
|
||||||
const selected = choices.filter((c, i) => selection[i].get()).map(c => c.textKey);
|
const use_cases = choices.filter((c, i) => selection[i].get()).map(c => c.textKey);
|
||||||
const use_cases = ['L', ...selected]; // Format to populate a ChoiceList column
|
const use_other = use_cases.includes("Other") ? otherText.get() : '';
|
||||||
const use_other = selected.includes("Other") ? otherText.get() : '';
|
|
||||||
|
|
||||||
const submitUrl = new URL(window.location.href);
|
const submitUrl = new URL(window.location.href);
|
||||||
submitUrl.pathname = '/welcome/info';
|
submitUrl.pathname = '/welcome/info';
|
||||||
|
@ -862,6 +862,25 @@ export const TelemetryContracts: TelemetryContracts = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
welcomeQuestionsSubmitted: {
|
||||||
|
description: 'Triggered when the welcome questionnaire is submitted.',
|
||||||
|
minimumTelemetryLevel: Level.full,
|
||||||
|
retentionPeriod: 'indefinitely',
|
||||||
|
metadataContracts: {
|
||||||
|
useCases: {
|
||||||
|
description: 'The selected use cases.',
|
||||||
|
dataType: 'string[]',
|
||||||
|
},
|
||||||
|
useOther: {
|
||||||
|
description: 'The value of the Other use case.',
|
||||||
|
dataType: 'string',
|
||||||
|
},
|
||||||
|
userId: {
|
||||||
|
description: 'The id of the user that triggered this event.',
|
||||||
|
dataType: 'number',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
type TelemetryContracts = Record<TelemetryEvent, TelemetryEventContract>;
|
type TelemetryContracts = Record<TelemetryEvent, TelemetryEventContract>;
|
||||||
@ -891,6 +910,7 @@ export const TelemetryEvents = StringUnion(
|
|||||||
'tutorialProgressChanged',
|
'tutorialProgressChanged',
|
||||||
'tutorialRestarted',
|
'tutorialRestarted',
|
||||||
'watchedVideoTour',
|
'watchedVideoTour',
|
||||||
|
'welcomeQuestionsSubmitted',
|
||||||
);
|
);
|
||||||
export type TelemetryEvent = typeof TelemetryEvents.type;
|
export type TelemetryEvent = typeof TelemetryEvents.type;
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ import {addPluginEndpoints, limitToPlugins} from 'app/server/lib/PluginEndpoint'
|
|||||||
import {PluginManager} from 'app/server/lib/PluginManager';
|
import {PluginManager} from 'app/server/lib/PluginManager';
|
||||||
import * as ProcessMonitor from 'app/server/lib/ProcessMonitor';
|
import * as ProcessMonitor from 'app/server/lib/ProcessMonitor';
|
||||||
import {adaptServerUrl, getOrgUrl, getOriginUrl, getScope, isDefaultUser, optStringParam,
|
import {adaptServerUrl, getOrgUrl, getOriginUrl, getScope, isDefaultUser, optStringParam,
|
||||||
RequestWithGristInfo, sendOkReply, stringParam, TEST_HTTPS_OFFSET,
|
RequestWithGristInfo, sendOkReply, stringArrayParam, stringParam, TEST_HTTPS_OFFSET,
|
||||||
trustOrigin} from 'app/server/lib/requestUtils';
|
trustOrigin} from 'app/server/lib/requestUtils';
|
||||||
import {ISendAppPageOptions, makeGristConfig, makeMessagePage, makeSendAppPage} from 'app/server/lib/sendAppPage';
|
import {ISendAppPageOptions, makeGristConfig, makeMessagePage, makeSendAppPage} from 'app/server/lib/sendAppPage';
|
||||||
import {getDatabaseUrl, listenPromise} from 'app/server/lib/serverUtils';
|
import {getDatabaseUrl, listenPromise} from 'app/server/lib/serverUtils';
|
||||||
@ -1304,12 +1304,28 @@ export class FlexServer implements GristServer {
|
|||||||
this.app.post('/welcome/info', ...middleware, expressWrap(async (req, resp, next) => {
|
this.app.post('/welcome/info', ...middleware, expressWrap(async (req, resp, next) => {
|
||||||
const userId = getUserId(req);
|
const userId = getUserId(req);
|
||||||
const user = getUser(req);
|
const user = getUser(req);
|
||||||
const row = {...req.body, UserID: userId, Name: user.name, Email: user.loginEmail};
|
const useCases = stringArrayParam(req.body.use_cases, 'use_cases');
|
||||||
|
const useOther = stringParam(req.body.use_other, 'use_other');
|
||||||
|
const row = {
|
||||||
|
UserID: userId,
|
||||||
|
Name: user.name,
|
||||||
|
Email: user.loginEmail,
|
||||||
|
use_cases: ['L', ...useCases],
|
||||||
|
use_other: useOther,
|
||||||
|
};
|
||||||
this._recordNewUserInfo(row)
|
this._recordNewUserInfo(row)
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
// If we failed to record, at least log the data, so we could potentially recover it.
|
// If we failed to record, at least log the data, so we could potentially recover it.
|
||||||
log.rawWarn(`Failed to record new user info: ${e.message}`, {newUserQuestions: row});
|
log.rawWarn(`Failed to record new user info: ${e.message}`, {newUserQuestions: row});
|
||||||
});
|
});
|
||||||
|
this.getTelemetry().logEvent('welcomeQuestionsSubmitted', {
|
||||||
|
full: {
|
||||||
|
userId,
|
||||||
|
useCases,
|
||||||
|
useOther,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch(e => log.error('failed to log telemetry event welcomeQuestionsSubmitted', e));
|
||||||
|
|
||||||
resp.status(200).send();
|
resp.status(200).send();
|
||||||
}), jsonErrorHandler); // Add a final error handler that reports errors as JSON.
|
}), jsonErrorHandler); // Add a final error handler that reports errors as JSON.
|
||||||
|
@ -282,6 +282,17 @@ export function stringParam(p: any, name: string, options: StringParamOptions =
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function stringArrayParam(p: any, name: string): string[] {
|
||||||
|
if (!Array.isArray(p)) {
|
||||||
|
throw new ApiError(`${name} parameter should be an array: ${p}`, 400);
|
||||||
|
}
|
||||||
|
if (p.some(el => typeof el !== 'string')) {
|
||||||
|
throw new ApiError(`${name} parameter should be a string array: ${p}`, 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
export function optIntegerParam(p: any, name: string): number|undefined {
|
export function optIntegerParam(p: any, name: string): number|undefined {
|
||||||
if (p === undefined) { return p; }
|
if (p === undefined) { return p; }
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user