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:
Ahsan Virani
2021-10-19 05:57:49 +02:00
committed by GitHub
parent 4b857b19ac
commit 421dd72224
100 changed files with 2223 additions and 550 deletions

View File

@@ -0,0 +1,30 @@
import N8nHeading from './Heading.vue';
export default {
title: 'Atoms/Heading',
component: N8nHeading,
argTypes: {
size: {
control: {
type: 'select',
options: ['2xlarge', 'xlarge', 'large', 'medium', 'small'],
},
},
color: {
control: {
type: 'select',
options: ['primary', 'text-dark', 'text-base', 'text-light'],
},
},
},
};
const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: {
N8nHeading,
},
template: '<n8n-heading v-bind="$props">hello world</n8n-heading>',
});
export const Heading = Template.bind({});

View File

@@ -0,0 +1,128 @@
<template functional>
<component :is="props.tag" :class="$style[$options.methods.getClass(props)]" :style="$options.methods.getStyles(props)">
<slot></slot>
</component>
</template>
<script lang="ts">
export default {
name: 'n8n-heading',
props: {
tag: {
type: String,
default: 'span',
},
bold: {
type: Boolean,
default: false,
},
size: {
type: String,
default: 'medium',
validator: (value: string): boolean => ['2xlarge', 'xlarge', 'large', 'medium', 'small'].includes(value),
},
color: {
type: String,
validator: (value: string): boolean => ['primary', 'text-dark', 'text-base', 'text-light'].includes(value),
},
},
methods: {
getClass(props: {size: string, bold: boolean}) {
return `heading-${props.size}${props.bold ? '-bold' : '-regular'}`;
},
getStyles(props: {color: string}) {
const styles = {} as any;
if (props.color) {
styles.color = `var(--color-${props.color})`;
}
return styles;
},
},
};
</script>
<style lang="scss" module>
.bold {
font-weight: var(--font-weight-bold);
}
.regular {
font-weight: var(--font-weight-regular);
}
.heading-2xlarge {
font-size: var(--font-size-2xl);
line-height: var(--font-line-height-compact);
}
.heading-2xlarge-regular {
composes: regular;
composes: heading-2xlarge;
}
.heading-2xlarge-bold {
composes: bold;
composes: heading-2xlarge;
}
.heading-xlarge {
font-size: var(--font-size-xl);
line-height: var(--font-line-height-compact);
}
.heading-xlarge-regular {
composes: regular;
composes: heading-xlarge;
}
.heading-xlarge-bold {
composes: bold;
composes: heading-xlarge;
}
.heading-large {
font-size: var(--font-size-l);
line-height: var(--font-line-height-loose);
}
.heading-large-regular {
composes: regular;
composes: heading-large;
}
.heading-large-bold {
composes: bold;
composes: heading-large;
}
.heading-medium {
font-size: var(--font-size-m);
line-height: var(--font-line-height-loose);
}
.heading-medium-regular {
composes: regular;
composes: heading-medium;
}
.heading-medium-bold {
composes: bold;
composes: heading-medium;
}
.heading-small {
font-size: var(--font-size-s);
line-height: var(--font-line-height-regular);
}
.heading-small-regular {
composes: regular;
composes: heading-small;
}
.heading-small-bold {
composes: bold;
composes: heading-small;
}
</style>

View File

@@ -0,0 +1,3 @@
import N8nHeading from './Heading.vue';
export default N8nHeading;

View File

@@ -1,5 +1,5 @@
<template functional>
<n8n-button
<component :is="$options.components.N8nButton"
:type="props.type"
:disabled="props.disabled"
:size="props.size === 'xlarge' ? 'large' : props.size"
@@ -14,7 +14,6 @@
</template>
<script lang="ts">
import Vue from 'vue';
import N8nButton from '../N8nButton';
const iconSizeMap = {
@@ -22,10 +21,11 @@ const iconSizeMap = {
xlarge: 'large',
};
Vue.component('N8nButton', N8nButton);
export default {
name: 'n8n-icon-button',
components: {
N8nButton,
},
props: {
type: {
type: String,

View File

@@ -1,19 +1,16 @@
<template functional>
<div :class="$style.infotip">
<n8n-icon icon="info-circle" /> <span><slot></slot></span>
<component :is="$options.components.N8nIcon" icon="info-circle" /> <span><slot></slot></span>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import N8nIcon from '../N8nIcon';
Vue.component('N8nIcon', N8nIcon);
export default {
name: 'n8n-info-tip',
props: {
components: {
N8nIcon,
},
};
</script>

View File

@@ -1,15 +1,15 @@
<template functional>
<div :class="$style.inputLabel">
<div :class="$style.label">
<span>
{{ $options.methods.addTargetBlank(props.label) }}
<span v-if="props.required" :class="$style.required">*</span>
</span>
<div :class="props.label ? $style.label: ''">
<component v-if="props.label" :is="$options.components.N8nText" :bold="true">
{{ props.label }}
<component :is="$options.components.N8nText" color="primary" :bold="true" v-if="props.required">*</component>
</component>
<span :class="$style.infoIcon" v-if="props.tooltipText">
<n8n-tooltip placement="top" :popper-class="$style.tooltipPopper">
<n8n-icon icon="question-circle" />
<div slot="content" v-html="props.tooltipText"></div>
</n8n-tooltip>
<component :is="$options.components.N8nTooltip" placement="top" :popper-class="$style.tooltipPopper">
<component :is="$options.components.N8nIcon" icon="question-circle" />
<div slot="content" v-html="$options.methods.addTargetBlank(props.tooltipText)"></div>
</component>
</span>
</div>
<slot></slot>
@@ -17,22 +17,22 @@
</template>
<script lang="ts">
import Vue from 'vue';
import N8nText from '../N8nText';
import N8nTooltip from '../N8nTooltip';
import N8nIcon from '../N8nIcon';
import { addTargetBlank } from '../utils/helpers';
Vue.component('N8nIcon', N8nIcon);
Vue.component('N8nTooltip', N8nTooltip);
export default {
name: 'n8n-input-label',
components: {
N8nText,
N8nIcon,
N8nTooltip,
},
props: {
label: {
type: String,
required: true,
},
tooltipText: {
type: String,
@@ -55,8 +55,6 @@ export default {
}
.label {
font-weight: var(--font-weight-bold);
font-size: var(--font-size-s);
margin-bottom: var(--spacing-2xs);
* {
@@ -69,10 +67,6 @@ export default {
display: var(--info-icon-display, none);
}
.required {
color: var(--color-primary);
}
.tooltipPopper {
max-width: 400px;
}

View File

@@ -1,5 +1,6 @@
import N8nSelect from './Select.vue';
import N8nOption from '../N8nOption';
import N8nIcon from '../N8nIcon';
import { action } from '@storybook/addon-actions';
export default {
@@ -48,6 +49,7 @@ const Template = (args, { argTypes }) => ({
components: {
N8nSelect,
N8nOption,
N8nIcon,
},
template: '<n8n-select v-bind="$props" v-model="val" @input="onInput" @change="onChange"><n8n-option value="1">op1</n8n-option><n8n-option value="2">op2</n8n-option></n8n-select>',
data() {
@@ -73,6 +75,7 @@ const ManyTemplate = (args, { argTypes }) => ({
components: {
N8nSelect,
N8nOption,
N8nIcon,
},
template: `<div class="multi-container">${selects}</div>`,
methods,
@@ -97,6 +100,7 @@ const ManyTemplateWithIcon = (args, { argTypes }) => ({
components: {
N8nSelect,
N8nOption,
N8nIcon,
},
template: `<div class="multi-container">${selectsWithIcon}</div>`,
methods,
@@ -120,6 +124,7 @@ const LimitedWidthTemplate = (args, { argTypes }) => ({
components: {
N8nSelect,
N8nOption,
N8nIcon,
},
template: '<div style="width:100px;"><n8n-select v-bind="$props" v-model="val" @input="onInput" @change="onChange"><n8n-option value="1" label="opt1 11 1111" /><n8n-option value="2" label="opt2 test very long ipsum"/></n8n-select></div>',
data() {

View File

@@ -0,0 +1,30 @@
import N8nText from './Text.vue';
export default {
title: 'Atoms/Text',
component: N8nText,
argTypes: {
size: {
control: {
type: 'select',
options: ['small', 'medium', 'large'],
},
},
color: {
control: {
type: 'select',
options: ['primary', 'text-dark', 'text-base', 'text-light'],
},
},
},
};
const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: {
N8nText,
},
template: '<n8n-text v-bind="$props">hello world</n8n-text>',
});
export const Text = Template.bind({});

View File

@@ -0,0 +1,102 @@
<template functional>
<span :class="$style[$options.methods.getClass(props)]" :style="$options.methods.getStyles(props)">
<slot></slot>
</span>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: 'n8n-text',
props: {
bold: {
type: Boolean,
default: false,
},
size: {
type: String,
default: 'medium',
validator: (value: string): boolean => ['large', 'medium', 'small'].includes(value),
},
color: {
type: String,
validator: (value: string): boolean => ['primary', 'text-dark', 'text-base', 'text-light'].includes(value),
},
align: {
type: String,
validator: (value: string): boolean => ['right', 'left', 'center'].includes(value),
},
},
methods: {
getClass(props: {size: string, bold: boolean}) {
return `body-${props.size}${props.bold ? '-bold' : '-regular'}`;
},
getStyles(props: {color: string, align: string}) {
const styles = {} as any;
if (props.color) {
styles.color = `var(--color-${props.color})`;
}
if (props.align) {
styles['text-align'] = props.align;
}
return styles;
},
},
});
</script>
<style lang="scss" module>
.bold {
font-weight: var(--font-weight-bold);
}
.regular {
font-weight: var(--font-weight-regular);
}
.body-large {
font-size: var(--font-size-m);
line-height: var(--font-line-height-xloose);
}
.body-large-regular {
composes: regular;
composes: body-large;
}
.body-large-bold {
composes: bold;
composes: body-large;
}
.body-medium {
font-size: var(--font-size-s);
line-height: var(--font-line-height-loose);
}
.body-medium-regular {
composes: regular;
composes: body-medium;
}
.body-medium-bold {
composes: bold;
composes: body-medium;
}
.body-small {
font-size: var(--font-size-2xs);
line-height: var(--font-line-height-loose);
}
.body-small-regular {
composes: regular;
composes: body-small;
}
.body-small-bold {
composes: bold;
composes: body-small;
}
</style>

View File

@@ -0,0 +1,3 @@
import N8nText from './Text.vue';
export default N8nText;

View File

@@ -5,10 +5,12 @@ import N8nInput from './N8nInput';
import N8nInfoTip from './N8nInfoTip';
import N8nInputNumber from './N8nInputNumber';
import N8nInputLabel from './N8nInputLabel';
import N8nHeading from './N8nHeading';
import N8nMenu from './N8nMenu';
import N8nMenuItem from './N8nMenuItem';
import N8nSelect from './N8nSelect';
import N8nSpinner from './N8nSpinner';
import N8nText from './N8nText';
import N8nTooltip from './N8nTooltip';
import N8nOption from './N8nOption';
@@ -20,10 +22,12 @@ export {
N8nInput,
N8nInputLabel,
N8nInputNumber,
N8nHeading,
N8nMenu,
N8nMenuItem,
N8nSelect,
N8nSpinner,
N8nText,
N8nTooltip,
N8nOption,
};

View File

@@ -1,49 +0,0 @@
<template>
<table :class="$style.table">
<tr v-for="c in classes" :key="c">
<td>.{{ c }}{{ postfix ? postfix : '' }}</td>
<td :class="$style[`${c}${postfix ? postfix : ''}`]">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse in
luctus sapien, a suscipit neque.
</td>
</tr>
</table>
</template>
<script lang="ts">
export default {
name: 'text-classes',
data(): { observer: null | MutationObserver; classes: string[] } {
return {
observer: null as null | MutationObserver,
classes: [
'heading1',
'heading2',
'heading3',
'heading4',
'body-large',
'body-medium',
'body-small',
],
};
},
props: {
postfix: {
type: String,
},
},
};
</script>
<style lang="scss" module>
@use "~/theme/src/common/typography.scss";
.table {
text-align: center;
color: var(--color-text-dark);
* {
padding-bottom: 1em;
}
}
</style>

View File

@@ -1,6 +1,5 @@
import { Meta, Story, Canvas } from '@storybook/addon-docs';
import Sizes from './Sizes.vue';
import TextClasses from './TextClasses.vue';
<Meta
title="Styleguide/Spacing"

View File

@@ -1,38 +0,0 @@
import { Meta, Story, Canvas } from '@storybook/addon-docs';
import TextClasses from './TextClasses.vue';
<Meta
title="Styleguide/Text"
parameters={{
design: {
type: 'figma',
url: 'https://www.figma.com/file/DxLbnIyMK8X0uLkUguFV4n/n8n-design-system_v1?node-id=79%3A6898',
},
}}
/>
# Regular
<Canvas>
<Story name="regular">
{{
template: `<text-classes />`,
components: {
TextClasses,
},
}}
</Story>
</Canvas>
# Bold
<Canvas>
<Story name="bold">
{{
template: `<text-classes postfix="-bold" />`,
components: {
TextClasses,
},
}}
</Story>
</Canvas>

View File

@@ -259,6 +259,7 @@
var(--color-background-xlight-l)
);
--border-radius-large: 8px;
--border-radius-base: 4px;
--border-radius-small: 2px;
--border-color-base: var(--color-foreground-base);

View File

@@ -29,7 +29,7 @@
@include mixins.e(arrow) {
margin: 0 8px 0 auto;
transition: transform 0.3s;
font-weight: 300;
font-weight: 400;
@include mixins.when(active) {
transform: rotate(90deg);
}

View File

@@ -1,66 +0,0 @@
%bold {
font-weight: var(--font-weight-bold);
}
.heading1 {
font-size: var(--font-size-2xl);
line-height: var(--font-line-height-compact);
}
.heading1-bold {
@extend %bold, .heading1;
}
.heading2 {
font-size: var(--font-size-xl);
line-height: var(--font-line-height-loose);
}
.heading2-bold {
@extend %bold, .heading2;
}
.heading3 {
font-size: var(--font-size-m);
line-height: var(--font-line-height-loose);
}
.heading3-bold {
@extend %bold, .heading3;
}
.heading4 {
font-size: var(--font-size-s);
line-height: var(--font-line-height-regular);
}
.heading4-bold {
@extend %bold, .heading4;
}
.body-large {
font-size: var(--font-size-m);
line-height: var(--font-line-height-xloose);
}
.body-large-bold {
@extend %bold, .body-large;
}
.body-medium {
font-size: var(--font-size-s);
line-height: var(--font-line-height-loose);
}
.body-medium-bold {
@extend %bold, .body-medium;
}
.body-small {
font-size: var(--font-size-2xs);
line-height: var(--font-line-height-loose);
}
.body-small-bold {
@extend %bold, .body-small;
}

View File

@@ -753,11 +753,7 @@ $switch-button-size: 16px;
$dialog-background-color: $color-white;
$dialog-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
/// fontSize||Font|1
$dialog-title-font-size: $font-size-large;
/// fontSize||Font|1
$dialog-content-font-size: 14px;
/// fontLineHeight||LineHeight|2
$dialog-font-line-height: $font-line-height-primary;
/// padding||Spacing|3
$dialog-padding-primary: var(--spacing-l);
$dialog-close-top: var(--dialog-close-top, var(--spacing-l));

View File

@@ -59,9 +59,10 @@
}
@include mixins.e(title) {
line-height: var.$dialog-font-line-height;
font-size: var.$dialog-title-font-size;
line-height: var(--font-line-height-compact);
font-size: var(--font-size-xl);
color: var(--color-text-dark);
font-weight: var(--font-weight-regular);
}
@include mixins.e(body) {

View File

@@ -48,6 +48,7 @@
font-size: var.$messagebox-font-size;
line-height: 1;
color: var.$messagebox-title-color;
font-weight: var(--font-weight-regular);
}
@include mixins.e(headerbtn) {
@@ -129,6 +130,7 @@
@include mixins.e(message) {
margin: 0;
font-weight: var(--font-weight-regular);
& p {
margin: 0;

View File

@@ -11,7 +11,7 @@ body {
overscroll-behavior-x: none;
line-height: 1;
font-size: var(--font-size-m);
font-weight: 300;
font-weight: var(--font-weight-regular);
color: var(--color-text-dark);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;