mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2026-08-30 07:10:37 +02:00
* 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>
133 lines
3.5 KiB
Vue
133 lines
3.5 KiB
Vue
<template>
|
|
<div>
|
|
<SlideTransition>
|
|
<div class="node-creator" v-if="active" v-click-outside="onClickOutside">
|
|
<MainPanel @nodeTypeSelected="nodeTypeSelected" :categorizedItems="categorizedItems" :categoriesWithNodes="categoriesWithNodes" :searchItems="searchItems"></MainPanel>
|
|
</div>
|
|
</SlideTransition>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
|
|
import Vue from 'vue';
|
|
|
|
import { ICategoriesWithNodes, INodeCreateElement } from '@/Interface';
|
|
import { INodeTypeDescription } from 'n8n-workflow';
|
|
import SlideTransition from '../transitions/SlideTransition.vue';
|
|
import { HIDDEN_NODES } from '@/constants';
|
|
|
|
import MainPanel from './MainPanel.vue';
|
|
import { getCategoriesWithNodes, getCategorizedList } from './helpers';
|
|
import { mapGetters } from 'vuex';
|
|
|
|
export default Vue.extend({
|
|
name: 'NodeCreator',
|
|
components: {
|
|
MainPanel,
|
|
SlideTransition,
|
|
},
|
|
props: [
|
|
'active',
|
|
],
|
|
data() {
|
|
return {
|
|
allNodeTypes: [],
|
|
};
|
|
},
|
|
computed: {
|
|
...mapGetters('settings', ['personalizedNodeTypes']),
|
|
nodeTypes(): INodeTypeDescription[] {
|
|
return this.$store.getters.allNodeTypes;
|
|
},
|
|
visibleNodeTypes(): INodeTypeDescription[] {
|
|
return this.allNodeTypes
|
|
.filter((nodeType: INodeTypeDescription) => {
|
|
return !HIDDEN_NODES.includes(nodeType.name);
|
|
}).reduce((accumulator: INodeTypeDescription[], currentValue: INodeTypeDescription) => {
|
|
// keep only latest version of the nodes
|
|
// accumulator starts as an empty array.
|
|
const exists = accumulator.findIndex(nodes => nodes.name === currentValue.name);
|
|
if (exists >= 0 && accumulator[exists].version < currentValue.version) {
|
|
// This must be a versioned node and we've found a newer version.
|
|
// Replace the previous one with this one.
|
|
accumulator[exists] = currentValue;
|
|
} else {
|
|
accumulator.push(currentValue);
|
|
}
|
|
return accumulator;
|
|
}, []);
|
|
},
|
|
categoriesWithNodes(): ICategoriesWithNodes {
|
|
return getCategoriesWithNodes(this.visibleNodeTypes, this.personalizedNodeTypes as string[]);
|
|
},
|
|
categorizedItems(): INodeCreateElement[] {
|
|
return getCategorizedList(this.categoriesWithNodes);
|
|
},
|
|
searchItems(): INodeCreateElement[] {
|
|
const sorted = [...this.visibleNodeTypes];
|
|
sorted.sort((a, b) => {
|
|
const textA = a.displayName.toLowerCase();
|
|
const textB = b.displayName.toLowerCase();
|
|
return textA < textB ? -1 : textA > textB ? 1 : 0;
|
|
});
|
|
|
|
return sorted.map((nodeType) => ({
|
|
type: 'node',
|
|
category: '',
|
|
key: `${nodeType.name}`,
|
|
properties: {
|
|
nodeType,
|
|
subcategory: '',
|
|
},
|
|
includedByTrigger: nodeType.group.includes('trigger'),
|
|
includedByRegular: !nodeType.group.includes('trigger'),
|
|
}));
|
|
},
|
|
},
|
|
methods: {
|
|
onClickOutside (e: Event) {
|
|
if (e.type === 'click') {
|
|
this.$emit('closeNodeCreator');
|
|
}
|
|
},
|
|
nodeTypeSelected (nodeTypeName: string) {
|
|
this.$emit('nodeTypeSelected', nodeTypeName);
|
|
},
|
|
},
|
|
watch: {
|
|
nodeTypes(newList, prevList) {
|
|
if (prevList.length === 0) {
|
|
this.allNodeTypes = newList;
|
|
}
|
|
},
|
|
},
|
|
});
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
::v-deep *, *:before, *:after {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.node-creator {
|
|
position: fixed;
|
|
top: $--header-height;
|
|
right: 0;
|
|
width: $--node-creator-width;
|
|
height: 100%;
|
|
background-color: $--node-creator-background-color;
|
|
z-index: 200;
|
|
color: $--node-creator-text-color;
|
|
|
|
&:before {
|
|
box-sizing: border-box;
|
|
content: ' ';
|
|
border-left: 1px solid $--node-creator-border-color;
|
|
width: 1px;
|
|
position: absolute;
|
|
height: 100%;
|
|
}
|
|
}
|
|
</style>
|