✨ Introduce telemetry (#2099)
* introduce analytics * add user survey backend * add user survey backend * set answers on survey submit Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com> * change name to personalization * lint Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com> * N8n 2495 add personalization modal (#2280) * update modals * add onboarding modal * implement questions * introduce analytics * simplify impl * implement survey handling * add personalized cateogry * update modal behavior * add thank you view * handle empty cases * rename modal * standarize modal names * update image, add tags to headings * remove unused file * remove unused interfaces * clean up footer spacing * introduce analytics * refactor to fix bug * update endpoint * set min height * update stories * update naming from questions to survey * remove spacing after core categories * fix bug in logic * sort nodes * rename types * merge with be * rename userSurvey * clean up rest api * use constants for keys * use survey keys * clean up types * move personalization to its own file Co-authored-by: ahsan-virani <ahsan.virani@gmail.com> * Survey new options (#2300) * split up options * fix quotes * remove unused import * add user created workflow event (#2301) * simplify env vars * fix versionCli on FE * update personalization env * fix event User opened Credentials panel * fix select modal spacing * fix nodes panel event * fix workflow id in workflow execute event * improve telemetry error logging * fix config and stop process events * add flush call on n8n stop * ready for release * improve telemetry process exit * fix merge * improve n8n stop events Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com> Co-authored-by: Mutasem <mutdmour@gmail.com> Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
This commit is contained in:
82
packages/editor-ui/src/modules/helper.ts
Normal file
82
packages/editor-ui/src/modules/helper.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
|
||||
import { AUTOMATION_CONSULTING_WORK_AREA, CALENDLY_TRIGGER_NODE_TYPE, CLEARBIT_NODE_TYPE, COMPANY_SIZE_1000_OR_MORE, COMPANY_SIZE_500_999, CRON_NODE_TYPE, ELASTIC_SECURITY_NODE_TYPE, EMAIL_SEND_NODE_TYPE, EXECUTE_COMMAND_NODE_TYPE, FINANCE_WORK_AREA, FUNCTION_NODE_TYPE, GITHUB_TRIGGER_NODE_TYPE, HTTP_REQUEST_NODE_TYPE, IF_NODE_TYPE, ITEM_LISTS_NODE_TYPE, IT_ENGINEERING_WORK_AREA, JIRA_TRIGGER_NODE_TYPE, MICROSOFT_EXCEL_NODE_TYPE, MICROSOFT_TEAMS_NODE_TYPE, PERSONALIZATION_MODAL_KEY, PAGERDUTY_NODE_TYPE, PRODUCT_WORK_AREA, QUICKBOOKS_NODE_TYPE, SALESFORCE_NODE_TYPE, SALES_BUSINESSDEV_WORK_AREA, SECURITY_WORK_AREA, SEGMENT_NODE_TYPE, SET_NODE_TYPE, SLACK_NODE_TYPE, SPREADSHEET_FILE_NODE_TYPE, SWITCH_NODE_TYPE, WEBHOOK_NODE_TYPE, XERO_NODE_TYPE, COMPANY_SIZE_KEY, WORK_AREA_KEY, CODING_SKILL_KEY } from '@/constants';
|
||||
import { IPersonalizationSurveyAnswers } from '@/Interface';
|
||||
|
||||
export function getPersonalizedNodeTypes(answers: IPersonalizationSurveyAnswers) {
|
||||
const companySize = answers[COMPANY_SIZE_KEY];
|
||||
const workArea = answers[WORK_AREA_KEY];
|
||||
|
||||
if (companySize === null && workArea === null && answers[CODING_SKILL_KEY] === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let codingSkill = null;
|
||||
if (answers[CODING_SKILL_KEY]) {
|
||||
codingSkill = parseInt(answers[CODING_SKILL_KEY] as string, 10);
|
||||
codingSkill = isNaN(codingSkill)? 0 : codingSkill;
|
||||
}
|
||||
|
||||
let nodeTypes = [] as string[];
|
||||
if (workArea === IT_ENGINEERING_WORK_AREA || workArea === AUTOMATION_CONSULTING_WORK_AREA) {
|
||||
nodeTypes = nodeTypes.concat(WEBHOOK_NODE_TYPE);
|
||||
}
|
||||
else {
|
||||
nodeTypes = nodeTypes.concat(CRON_NODE_TYPE);
|
||||
}
|
||||
|
||||
if (codingSkill !== null && codingSkill >= 4) {
|
||||
nodeTypes = nodeTypes.concat(FUNCTION_NODE_TYPE);
|
||||
}
|
||||
else {
|
||||
nodeTypes = nodeTypes.concat(ITEM_LISTS_NODE_TYPE);
|
||||
}
|
||||
|
||||
if (codingSkill !== null && codingSkill < 3) {
|
||||
nodeTypes = nodeTypes.concat(IF_NODE_TYPE);
|
||||
}
|
||||
else {
|
||||
nodeTypes = nodeTypes.concat(SWITCH_NODE_TYPE);
|
||||
}
|
||||
|
||||
if (companySize === COMPANY_SIZE_500_999 || companySize === COMPANY_SIZE_1000_OR_MORE) {
|
||||
if (workArea === SALES_BUSINESSDEV_WORK_AREA) {
|
||||
nodeTypes = nodeTypes.concat(SALESFORCE_NODE_TYPE);
|
||||
}
|
||||
else if (workArea === SECURITY_WORK_AREA) {
|
||||
nodeTypes = nodeTypes.concat([ELASTIC_SECURITY_NODE_TYPE, HTTP_REQUEST_NODE_TYPE]);
|
||||
}
|
||||
else if (workArea === PRODUCT_WORK_AREA) {
|
||||
nodeTypes = nodeTypes.concat([JIRA_TRIGGER_NODE_TYPE, SEGMENT_NODE_TYPE]);
|
||||
}
|
||||
else if (workArea === IT_ENGINEERING_WORK_AREA) {
|
||||
nodeTypes = nodeTypes.concat([GITHUB_TRIGGER_NODE_TYPE, HTTP_REQUEST_NODE_TYPE]);
|
||||
}
|
||||
else {
|
||||
nodeTypes = nodeTypes.concat([MICROSOFT_EXCEL_NODE_TYPE, MICROSOFT_TEAMS_NODE_TYPE]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (workArea === SALES_BUSINESSDEV_WORK_AREA) {
|
||||
nodeTypes = nodeTypes.concat(CLEARBIT_NODE_TYPE);
|
||||
}
|
||||
else if (workArea === SECURITY_WORK_AREA) {
|
||||
nodeTypes = nodeTypes.concat([PAGERDUTY_NODE_TYPE, HTTP_REQUEST_NODE_TYPE]);
|
||||
}
|
||||
else if (workArea === PRODUCT_WORK_AREA) {
|
||||
nodeTypes = nodeTypes.concat([JIRA_TRIGGER_NODE_TYPE, CALENDLY_TRIGGER_NODE_TYPE]);
|
||||
}
|
||||
else if (workArea === IT_ENGINEERING_WORK_AREA) {
|
||||
nodeTypes = nodeTypes.concat([EXECUTE_COMMAND_NODE_TYPE, HTTP_REQUEST_NODE_TYPE]);
|
||||
}
|
||||
else if (workArea === FINANCE_WORK_AREA) {
|
||||
nodeTypes = nodeTypes.concat([XERO_NODE_TYPE, QUICKBOOKS_NODE_TYPE, SPREADSHEET_FILE_NODE_TYPE]);
|
||||
}
|
||||
else {
|
||||
nodeTypes = nodeTypes.concat([EMAIL_SEND_NODE_TYPE, SLACK_NODE_TYPE]);
|
||||
}
|
||||
}
|
||||
|
||||
nodeTypes = nodeTypes.concat(SET_NODE_TYPE);
|
||||
|
||||
return nodeTypes;
|
||||
}
|
||||
75
packages/editor-ui/src/modules/settings.ts
Normal file
75
packages/editor-ui/src/modules/settings.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { ActionContext, Module } from 'vuex';
|
||||
import {
|
||||
IN8nUISettings,
|
||||
IPersonalizationSurveyAnswers,
|
||||
IRootState,
|
||||
ISettingsState,
|
||||
} from '../Interface';
|
||||
import { getSettings, submitPersonalizationSurvey } from '../api/settings';
|
||||
import Vue from 'vue';
|
||||
import { getPersonalizedNodeTypes } from './helper';
|
||||
import { PERSONALIZATION_MODAL_KEY } from '@/constants';
|
||||
|
||||
const module: Module<ISettingsState, IRootState> = {
|
||||
namespaced: true,
|
||||
state: {
|
||||
settings: {} as IN8nUISettings,
|
||||
},
|
||||
getters: {
|
||||
personalizedNodeTypes(state: ISettingsState): string[] {
|
||||
const answers = state.settings.personalizationSurvey && state.settings.personalizationSurvey.answers;
|
||||
if (!answers) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return getPersonalizedNodeTypes(answers);
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
setSettings(state: ISettingsState, settings: IN8nUISettings) {
|
||||
state.settings = settings;
|
||||
},
|
||||
setPersonalizationAnswers(state: ISettingsState, answers: IPersonalizationSurveyAnswers) {
|
||||
Vue.set(state.settings, 'personalizationSurvey', {
|
||||
answers,
|
||||
shouldShow: false,
|
||||
});
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async getSettings(context: ActionContext<ISettingsState, IRootState>) {
|
||||
const settings = await getSettings(context.rootGetters.getRestApiContext);
|
||||
context.commit('setSettings', settings);
|
||||
|
||||
// todo refactor to this store
|
||||
context.commit('setUrlBaseWebhook', settings.urlBaseWebhook, {root: true});
|
||||
context.commit('setEndpointWebhook', settings.endpointWebhook, {root: true});
|
||||
context.commit('setEndpointWebhookTest', settings.endpointWebhookTest, {root: true});
|
||||
context.commit('setSaveDataErrorExecution', settings.saveDataErrorExecution, {root: true});
|
||||
context.commit('setSaveDataSuccessExecution', settings.saveDataSuccessExecution, {root: true});
|
||||
context.commit('setSaveManualExecutions', settings.saveManualExecutions, {root: true});
|
||||
context.commit('setTimezone', settings.timezone, {root: true});
|
||||
context.commit('setExecutionTimeout', settings.executionTimeout, {root: true});
|
||||
context.commit('setMaxExecutionTimeout', settings.maxExecutionTimeout, {root: true});
|
||||
context.commit('setVersionCli', settings.versionCli, {root: true});
|
||||
context.commit('setInstanceId', settings.instanceId, {root: true});
|
||||
context.commit('setOauthCallbackUrls', settings.oauthCallbackUrls, {root: true});
|
||||
context.commit('setN8nMetadata', settings.n8nMetadata || {}, {root: true});
|
||||
context.commit('versions/setVersionNotificationSettings', settings.versionNotifications, {root: true});
|
||||
context.commit('setTelemetry', settings.telemetry, {root: true});
|
||||
|
||||
const showPersonalizationsModal = settings.personalizationSurvey && settings.personalizationSurvey.shouldShow && !settings.personalizationSurvey.answers;
|
||||
if (showPersonalizationsModal) {
|
||||
context.commit('ui/openModal', PERSONALIZATION_MODAL_KEY, {root: true});
|
||||
}
|
||||
return settings;
|
||||
},
|
||||
async submitPersonalizationSurvey(context: ActionContext<ISettingsState, IRootState>, results: IPersonalizationSurveyAnswers) {
|
||||
await submitPersonalizationSurvey(context.rootGetters.getRestApiContext, results);
|
||||
|
||||
context.commit('setPersonalizationAnswers', results);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default module;
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CREDENTIAL_EDIT_MODAL_KEY, DUPLICATE_MODAL_KEY, TAGS_MANAGER_MODAL_KEY, VERSIONS_MODAL_KEY, WORKLOW_OPEN_MODAL_KEY, CREDENTIAL_SELECT_MODAL_KEY, WORKFLOW_SETTINGS_MODAL_KEY } from '@/constants';
|
||||
import { CREDENTIAL_EDIT_MODAL_KEY, DUPLICATE_MODAL_KEY, PERSONALIZATION_MODAL_KEY, TAGS_MANAGER_MODAL_KEY, VERSIONS_MODAL_KEY, WORKFLOW_OPEN_MODAL_KEY, CREDENTIAL_SELECT_MODAL_KEY, WORKFLOW_SETTINGS_MODAL_KEY, CREDENTIAL_LIST_MODAL_KEY } from '@/constants';
|
||||
import Vue from 'vue';
|
||||
import { ActionContext, Module } from 'vuex';
|
||||
import {
|
||||
@@ -15,13 +15,22 @@ const module: Module<IUiState, IRootState> = {
|
||||
mode: '',
|
||||
activeId: null,
|
||||
},
|
||||
[CREDENTIAL_LIST_MODAL_KEY]: {
|
||||
open: false,
|
||||
},
|
||||
[CREDENTIAL_SELECT_MODAL_KEY]: {
|
||||
open: false,
|
||||
},
|
||||
[DUPLICATE_MODAL_KEY]: {
|
||||
open: false,
|
||||
},
|
||||
[PERSONALIZATION_MODAL_KEY]: {
|
||||
open: false,
|
||||
},
|
||||
[TAGS_MANAGER_MODAL_KEY]: {
|
||||
open: false,
|
||||
},
|
||||
[WORKLOW_OPEN_MODAL_KEY]: {
|
||||
[WORKFLOW_OPEN_MODAL_KEY]: {
|
||||
open: false,
|
||||
},
|
||||
[VERSIONS_MODAL_KEY]: {
|
||||
@@ -30,9 +39,6 @@ const module: Module<IUiState, IRootState> = {
|
||||
[WORKFLOW_SETTINGS_MODAL_KEY]: {
|
||||
open: false,
|
||||
},
|
||||
[CREDENTIAL_SELECT_MODAL_KEY]: {
|
||||
open: false,
|
||||
},
|
||||
},
|
||||
modalStack: [],
|
||||
sidebarMenuCollapsed: true,
|
||||
@@ -86,20 +92,8 @@ const module: Module<IUiState, IRootState> = {
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
openTagsManagerModal: async (context: ActionContext<IUiState, IRootState>) => {
|
||||
context.commit('openModal', TAGS_MANAGER_MODAL_KEY);
|
||||
},
|
||||
openWorklfowOpenModal: async (context: ActionContext<IUiState, IRootState>) => {
|
||||
context.commit('openModal', WORKLOW_OPEN_MODAL_KEY);
|
||||
},
|
||||
openDuplicateModal: async (context: ActionContext<IUiState, IRootState>) => {
|
||||
context.commit('openModal', DUPLICATE_MODAL_KEY);
|
||||
},
|
||||
openUpdatesPanel: async (context: ActionContext<IUiState, IRootState>) => {
|
||||
context.commit('openModal', VERSIONS_MODAL_KEY);
|
||||
},
|
||||
openWorkflowSettingsModal: async (context: ActionContext<IUiState, IRootState>) => {
|
||||
context.commit('openModal', WORKFLOW_SETTINGS_MODAL_KEY);
|
||||
openModal: async (context: ActionContext<IUiState, IRootState>, modalKey: string) => {
|
||||
context.commit('openModal', modalKey);
|
||||
},
|
||||
openExisitngCredential: async (context: ActionContext<IUiState, IRootState>, { id }: {id: string}) => {
|
||||
context.commit('setActiveId', {name: CREDENTIAL_EDIT_MODAL_KEY, id});
|
||||
@@ -111,9 +105,6 @@ const module: Module<IUiState, IRootState> = {
|
||||
context.commit('setMode', {name: CREDENTIAL_EDIT_MODAL_KEY, mode: 'new'});
|
||||
context.commit('openModal', CREDENTIAL_EDIT_MODAL_KEY);
|
||||
},
|
||||
openCredentialsSelectModal: async (context: ActionContext<IUiState, IRootState>) => {
|
||||
context.commit('openModal', CREDENTIAL_SELECT_MODAL_KEY);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user